不枉初心,砥砺前行

皮皮祥的博客

欢迎留言,评论

导航

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

还有什么使用方法和问题欢迎评论区补充。

posted on 2022-04-12 16:27  皮皮祥  阅读(845)  评论(0)    收藏  举报