for语句的用法
Verilog 中重复的内容可以使用for循环来完成,目前总结的注意点如下:
1、always 内部用for循环,需要定义interger类型变量,否则有些仿真工具会报错
2、异步复位时序逻辑always@下面第一行必须是异步复位,不能有for循环,否则综合工具会报错
3、for语句在always 外部,或者使用for循环例化模块,需要定义genvar变量,否则有些仿真工具会报错。
Verilog设计中该不该用for循环?
先说结论,可以用,但是分时候,不会用的时候别乱用。
你老师说的计数器xx,可能是让你写计数器的时候别用for循环,软硬件编程思维的不同。写一个计数器表示一段延时,软件编程的思维肯定的是用for循环,软件的执行是顺序执行,也就是一直处于这个循环中,直到不满足循环计数条件而跳出循环。
而硬件中的计数器实现直接就是一组D触发器,根据计数器的使能,加上在时钟边沿触发变化,再加上一个清零端(还可以加置位端)。软件和硬件这两个可以说,完全不是一个东西。
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 3'd0;
else if(cnt_clear)
cnt <= 3'd0;
else if(cnt_en)
cnt <= cnt + 1'd1;
end
如果我想实现软件思维的delay一段时间怎么做,直接用上面的计数器做一个flag
assign flag = cnt == 3'd3;
当cnt == 3‘d3时,我输出一个flag,表示我这段延时的标志。
i的变化不跟时钟走吗?
在Verilog中使用for循环的功能就是,把同一块电路复制多份,完全起不到计数的作用,所以这个i的意思是复制多少份你这段代码实现的电路,和时钟没有任何关系。主要是为了提高编码效率。
这个配图的功能就是把这块电路,复制stages_num份,然后每个clk下,执行的内容操作是相同的。所以能实现在复位时刻,把整个寄存器都赋值为0,然后复位释放执行其他操作。(这个图为题主提供)
题主提供图
什么时候用
可以用,那么什么时候用,代码设计有规律的时候,可以配合generate for,合理使用generate+for循环可以提高编码效率,同样的赋值语句需要赋值多次。这个generate语句里面可以是任何有运算。
generate
genvar i;
for(i = 0;i < 16;i = i + 1)
begin: neg_data
assign neg_data_out[i*DATA_WIDTH +:DATA_WIDTH] =
-data_in[i*DATA_WIDTH +:DATA_WIDTH]
end
endgenerate
同一个模块需要实例化多次也可以,比如这里有一个运算需要调用16个乘法器,如果把乘法器IP模块实例化16份,那岂不是要写很长的代码,所以用generate+for可以极大的提高编码效率。
generate
genvar i;
for(i = 0;i < 16;i = i + 1)
begin: mult_12x12
DW02_mult #(
.A_WIDTH(12),
.B_WIDTH(12)
) u_DW02_mult0(
.A(mult_a[i*12 +:12]),
.B(mult_b[i*12 +:12]),
.TC(1’b0),
.PRODUCT(product[i*24 +:24])
);
end
endgenerate
当然这样写debug会有一些困扰,不容易找到信号对应位宽数据。不过Verdi会显示每一个generate块,选中对应的块,加进去的波形就会是对应的bit信号。
最后就是做一个RAM/Regfile
reg [DATA_WIDTH-1:0] register[2**ADDR_WIDTH-1:0];
always @(posedge clk)begin
if(!wren_n && !csen_n)
register[addr] <= data_i;
end
always @(posedge clk)begin
if(wren_n && !csen_n)
data_o <= register[addr];
end
还有什么使用方法和问题欢迎评论区补充。
浙公网安备 33010602011771号