场景还是前面那个场景,这次主要针对for循环做一些总结;
【Verilog】generate和for循环的一些使用总结(1)
在编译和综合阶段,编译器会将for循环展开,因此for循环的起点和终点都必须是常数才能够综合,否则会报错;
对于for循环,直接看几个常见的使用场景;
always @(*)begin: gain_data
integer i;
data = 0;
for(i=0; i
通过for循环得到当拍最后一路有效数据,该代码等效于:
if(in_vld[0]) data = in_data[0 +:DATA_WD];
if(in_vld[1]) data = in_data[DATA_WD +:DATA_WD];
if(in_vld[2]) data = in_data[DATA_WD*2 +:DATA_WD];
...
进而等效于:
if(in_vld[2]) data = in_data[DATA_WD*2 +:DATA_WD];
else if(in_vld[1]) data = in_data[DATA_WD +:DATA_WD];
else if(in_vld[0]) data = in_data[0 +:DATA_WD];
...
最终会综合成有优先级的选择电路;
always @(*)begin: gain_data
integer i;
cnt = 0;
for(i=0; i
等价于:
cnt = 0 + vld[0] + vld[1] +...+ vld[PORT_NUM-1]
需要注意的是,计数器要给初值,否则会综合出latch;
在时序逻辑中使用for循环时必须千万注意,例如还是实现信号选择功能,那么这样写:
always @(posedge clk)begin
integer i;
for(i=0; i
其中那句else也是可以被省略的,但是一旦写成了:
always @(posedge clk)begin
integer i;
for(i=0; i
那就出问题了,此时相当于如下代码:
always @(posedge clk)begin
if(in_vld[PORT_NUM-1])
data <= in_data[DATA_WD*(PORT_NUM-1) +:DATA_WD];
else
data <= data;
end
只判断了最后最后一个端口的信息,具体波形如下,data1采用第一种方式写的,data2采用第二种方式,可以看出data2不是预期的结果:
for循环中极易出现掩盖行为,其实哪怕在组合逻辑中如果编码不当也会出现这一问题,例如下面这个编码,目的是统计MM个端口,每个端口有NN个信号,任何端口上NN个信号中只要有一个有效,就将flag[m]置高:
always @* begin
integer m,n;
for(m=0; m
这样写的本意是避免出现latch,可是实现效果还是一样,只检测了每个通道的最后一位了,只要最后一位无效,那么flag[m]就无效了,与设计预期不符,因此应该改成如下写法:
always @* begin
integer m,n;
flag = 0;
for(m=0; m
如果for循环在时序逻辑里做累加,那基本是废了,比如下面这段代码:
always @(posedge clk)begin
integer i;
for(i=0; i
这个代码等价于这样:
always @(posedge clk)begin
cnt <= cnt + in_vld[0];
cnt <= cnt + in_vld[1];
...
cnt <= cnt + in_vld[PORT_NUM-1];
end
实际效果就是加了最后一bit:
cnt <= cnt + in_vld[PORT_NUM-1];
1. 时序逻辑中尽量避免for循环,如使用一定注意避免掩盖问题;
2. verilog文件中for循环不能外露,需要有generate块或always块,system verilog中for可以外露,会默认处理为generate for;
3. for循环必须加begin-end,哪怕只有一行执行代码;
4. for begin后面必须有块名,建议大写,避免和信号名重复;
5. 单纯的for循环不支持data[3i+8 : 3i]的取值方式,只支持data[3i +: 8]写法;