【Verilog】generate和for循环的一些使用总结(2)

前言

场景还是前面那个场景,这次主要针对for循环做一些总结;

【Verilog】generate和for循环的一些使用总结(1)

for循环归纳

在编译和综合阶段,编译器会将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]

【Verilog】generate和for循环的一些使用总结(2)_第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]写法;

 

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