Verilog有4种循环语句,如下所示。
- forever:持续不断地执行,就是死循环。
- repeat:执行括号内表达式指定的循环次数,如果表达式是x或z,就不执行。
- while:与C语言的while循环一样,当括号内表达式为true时就执行,否则不进入循环或跳出循环。
- for:与C语言的for循环一样,括号内分三个部分。
通常按如下方式使用它们。
- forver:用在需要死循环的地方,例如生成时钟的地方。
- repeat:可以不用定义循环变量,直接使用,更加清晰。
- while:循环中的判断条件可以很简单,也可以很复杂。
- 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循环。但是如果循环个数是变量的时候,那么任何综合工具都综合不出来,这是因为硬件规模必须是有限的、固定的。当综合工具遇到循环语句时,就把它们展开成若干条顺序执行的语句,然后再综合成电路。若循环个数是常数,则展开的语句数是确定的,所以可以综合;而若循环个数是变量,则展开的语句数是不确定的,对应的硬件电路数量也不能确定,所以无法综合。