Verilog有4种循环语句,如下所示。

  1. forever:持续不断地执行,就是死循环。
  2. repeat:执行括号内表达式指定的循环次数,如果表达式是x或z,就不执行。
  3. while:与C语言的while循环一样,当括号内表达式为true时就执行,否则不进入循环或跳出循环。
  4. for:与C语言的for循环一样,括号内分三个部分。

通常按如下方式使用它们。

  1. forver:用在需要死循环的地方,例如生成时钟的地方。
  2. repeat:可以不用定义循环变量,直接使用,更加清晰。
  3. while:循环中的判断条件可以很简单,也可以很复杂。
  4. foe:常用于固定次数或可变次数的循环,要定义一个循环变量。

使用for循环可以减少代码的书写量,使得代码更加紧凑,不易出错,而且可以做到随意配置。
例子:ISN是一个parameter,是在实例化时从顶层传递过来的,其值不是固定值。最好的办法是用for循环,否则一条一条地书写,根本就不好维护。

reg [ISN-1:0]       SelY;
reg [ISN*2-1:0]     TransY;
reg [ISN*3-1:0]     BurstY;
reg [ISN-1:0]       WriteY;
always @(*)
 begin
  for (i = 0; i < ISN; i = i + 1)
   begin
     SelY[i*1 +: 1]    = (SelX[i*1 +: 1]   & {1{os_access_bits[i]}});
     TransY[i*2 +: 2]  = (TransX[i*2 +: 2]   & {2{os_access_bits[i]}});
     BurstY[i*3 +: 3]  = (BurstX[i*3 +: 3]   & {3{os_access_bits[i]}});
     WriteY[i*1 +: 1]  = (WriteX[i*1 +: 1]   & {1{os_access_bits[i]}});
   end
end

例子:使用for循环实现优先级解码器。这里NUMBER怎么变化都没关系,代码也不需要像用casez一样需要修改。

parameter NUMBER = 8;
localparam WIDTH=$clog2(NUMBER);
reg [NUMBER-1:0] intc_src;
reg [WIDTH:0]    intc_number;
reg              flag;
always @(*)
  begin
    intc_number = (1'b1 << WIDTH);
    flag = 1;
    for (i = 0; flag && (i < NUMBER); i = i + 1)
      begin: intc_number_block
        if (intc_src[i] == 1) begin
          intc_number = i;
          flag = 0;
        end
      end
    end

现在的综合工具很强大,当循环个数是常量的时候,这样书写的for循环是可以综合的,例如上面的两个for循环。但是如果循环个数是变量的时候,那么任何综合工具都综合不出来,这是因为硬件规模必须是有限的、固定的。当综合工具遇到循环语句时,就把它们展开成若干条顺序执行的语句,然后再综合成电路。若循环个数是常数,则展开的语句数是确定的,所以可以综合;而若循环个数是变量,则展开的语句数是不确定的,对应的硬件电路数量也不能确定,所以无法综合。