Verilog循环语句、always块与assign不能共存的原因、以及generate语句的介绍及用法

目录

一、verilog循环语句:

(1)while循环

(2)for循环

(3)repeat循环

(4)forever循环

二、always块与assign不能共存

三、generate语句

generate_for语句

generate_if语句

generate_case语句


一、verilog循环语句:

(1)while循环

格式:

while (condition) begin
    …
end
while 循环中止条件为 condition 为假。如果开始执行到 while 循环时 condition 已经为假,那么循环语句一次也不会执行。当然,执行语句只有一条时,关键字 begin 与 end 可以省略。

下面代码执行时,counter 执行了 11 次。

`timescale 1ns/1ns
 
module test ;
 
    reg [3:0]    counter ;
    initial begin
        counter = 'b0 ;
        while (counter<=10) begin
            #10 ;
            counter = counter + 1'b1 ;
        end
    end
 
   //stop the simulation
    always begin
        #10 ;  if ($time >= 1000) $finish ;
    end
 
endmodule

注意:

当我使用while作为循环编程时,有时会弹出:

“Error (10119): Verilog HDL Loop Statement error at top_module.v(16): loop with non-constant loop condition must terminate within 250 iterations File: /home/h/work/hdlbits.7268514/top_module.v Line: 16”

意思是:“非常量循环条件的循环必须在250次迭代内终止”

这里的话有两个解决方法:

方法一:修改编译器默认循环上限。

在英特尔官网上有给出该错误的解决方案,即在工程的.qsf文件中添加
set_global_assignment -name VERILOG_NON_CONSTANT_LOOP_LIMIT 300。

此时循环次数上限修改为 300,实测最大循环上限为 5000,这是很多Verilog教材中没有提到的。
方法二:当然就是换一个循环语句了,用for之类的循环不香么。

(2)for循环

格式:

for(initial_assignment; condition ; step_assignment)  begin
    …
end
initial_assignment 为初始条件。condition 为终止条件,condition 为假时,立即跳出循环。

step_assignment 为改变控制变量的过程赋值语句,通常为增加或减少循环变量计数。

一般来说,因为初始条件和自加操作等过程都已经包含在 for 循环中,所以 for 循环写法比 while 更为紧凑,但也不是所有的情况下都能使用 for 循环来代替 while 循环。

下面 for 循环的例子,实现了与 while 循环中例子一样的效果。需要注意的是,i = i + 1 不能像 C 语言那样写成 i++ 的形式,i = i -1 也不能写成 i -- 的形式。

// for 循环语句
integer      i ;
reg [3:0]    counter2 ;
initial begin
    counter2 = 'b0 ;
    for (i=0; i<=10; i=i+1) begin
        #10 ;
        counter2 = counter2 + 1'b1 ;
    end
end

(3)repeat循环

格式:

repeat (loop_times) begin
    …
end
repeat 的功能是执行固定次数的循环,它不能像 while 循环那样用一个逻辑表达式来确定循环是否继续执行。repeat 循环的次数必须是一个常量、变量或信号。如果循环次数是变量信号,则循环次数是开始执行 repeat 循环时变量信号的值。即便执行期间,循环次数代表的变量信号值发生了变化,repeat 执行次数也不会改变。

下面 repeat 循环例子,实现了与 while 循环中的例子一样的效果。

// repeat 循环语句
reg [3:0]    counter3 ;
initial begin
    counter3 = 'b0 ;
    repeat (11) begin  //重复11次
        #10 ;
        counter3 = counter3 + 1'b1 ;
    end
end

(4)forever循环

格式:

forever begin
    …
end
forever 语句表示永久循环,不包含任何条件表达式,一旦执行便无限的执行下去,系统函数 $finish 可退出 forever。

forever 相当于 while(1) 。

通常,forever 循环是和时序控制结构配合使用的。

例如,使用 forever 语句产生一个时钟:

reg          clk ;
initial begin
    clk       = 0 ;
    forever begin
        clk = ~clk ;
        #5 ;
    end
end
例如,使用 forever 语句实现一个时钟边沿控制的寄存器间数据传输功能:

reg    clk ;
reg    data_in, data_temp ;
initial begin
    forever @(posedge clk)      data_temp = data_in ;
end

二、always块与assign不能共存

是因为:

1、被assign赋值的信号定义为wire型;被always(*)结构块的信号定义为reg型。类型不同不能共用。

2、另外一个区别则是更细微的差别:举个例子,

    wire a;

      reg b;

   assign a = 1'b0;

   always@(*)

       b = 1'b0;

    在这种情况下,做仿真时a将会正常为0, 但是b却是不定态。这是为什么?verilog规定,always@(*)中的*是指该always块内的所有输入信号的变化为敏感列表,也就是仿真时只有当always@(*)块内的输入信号产生变化,该块内描述的信号才会产生变化,而像always@(*) b = 1'b0;

    这种写法由于1'b0一直没有变化,所以b的信号状态一直没有改变,由于b是组合逻辑输出,所以复位时没有明确的值(不定态),而又因为always@(*)块内没有敏感信号变化,因此b的信号状态一直保持为不定态。事实上该语句的综合结果有可能跟assign一样(本人没有去尝试),但是在功能仿真时就差之千里了。

三、generate语句

1、介绍

generate生成语句可以动态的生成verilog代码,当对矢量中的多个位进行重复操作 时,或者当进行多个模块的实例引用的重复操作时,或者根据参数的定义来确定程序中是否应该包含某段Verilog代码的时候,使用生成语句能大大简化程序的编写过程。生成语句生成的实例范围,关键字generate-endgenerate用来指定该范围。生成实例可以是以下的一个或多个类型:模块、用户定义原语、门级语句、连续赋值语句、initial和always块。

2、用法

generate_for语句

(1)、必须使用genvar声明一个正整数变量,用作for循环的判断。(genvar是generate语句中的一种变量类型,用在generate_for中声明正整数变量,放在generate内外都可以。)
(2)、需要复制的语句必须写到begin_end语句里面。就算只有一句!!!!!!
(3)、begin_end需要有一个类似于模块名的名字。

例1:assign语句实现

module test(bin,gray);
       parameter SIZE=8;
       output [SIZE-1:0] bin;
       input [SIZE-1:0] gray;
       genvar i; //genvar i;也可以定义到generate语句里面
       generate
              for(i=0;i               begin:bit
                     assign bin[i]=^gray[SIZE-1:i];
              end
       endgenerate
endmodule

等同于下面语句

assign bin[0]=^gray[SIZE-1:0];
assign bin[1]=^gray[SIZE-1:1];
assign bin[2]=^gray[SIZE-1:2];
assign bin[3]=^gray[SIZE-1:3];
assign bin[4]=^gray[SIZE-1:4];
assign bin[5]=^gray[SIZE-1:5];
assign bin[6]=^gray[SIZE-1:6];
assign bin[7]=^gray[SIZE-1:7];

generate_if语句

generate_for用于复制模块,而generate_if则是根据模块的参数(必须是常量)作为条件判断,来产生满足条件的电路。相当于判断语句。

module    generate_if(
    input                     t0                    ,
    input                     t1                    ,
    input                     t2                    ,
    output                      d            
);

localparam    S = 6;                //定义模块所需参数,用于判断产生电路

generate 
    if(S < 7)        
        assign d = t0 | t1 | t2;
    else
        assign d = t0 & t1 & t2;
endgenerate

endmodule

generate_case语句

generate_case其实跟generate_if一样,都是根据参数(都必须为常量)作为判断条件,来产生满足条件的电路,不同于使用了case语法而已。

module    generate_case(
    input                     t0                    ,
    input                     t1                    ,
    input                     t2                    ,
    output                      d            
);

localparam    S = 8;                //定义模块所需参数,用于判断产生电路

generate 
    case(S)
    0:assign d = t0 | t1 | t2;
    1:assign d = t0 & t1 & t2;
    default:
        assign d = t0 & t1 | t2;
    endcase
endgenerate

endmodule

你可能感兴趣的:(verilog,fpga开发)