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

前言 之前使用generate和for时候一直糊里糊涂的使用,所以今天静下心来总结一下,顺便看看有哪些坑。
做一个模块,输入为多路data通过bit map型vld信号作为标记,输出为单路data,取多路信息中port num值最大的那一路数据,同时输出这一拍共多少路有数据;

信号 端口 位宽 含义
in_vld input PORT_NUM bitmap型vld信号,每一bit标志一路数据有效
in_data input PORT_NUM * DATA_WD 共PORT_NUM路数据,每路数据位宽为DATA_WD
out_vld output 1 输出数据有效
out_data output DATA_WD 输出数据
out_cnt output PORT_WD 共多少路输入vld有效计数
参数 含义
FLOP_FLAG 输出数据是否打拍
PORT_NUM 输入vld位宽
DATA_WD 单路数据位宽
OK,下面的归纳与实验都是基于这个场景。
generate归纳 generate使用 generate的主要用法就是两种,第一是构造循环结构,例如多次实例化某个模块,或者是进行连线;第二种是通过if-generate或者case-generate来在多个代码块之间最多选择一个作为综合的rtl代码。
通过循环结构来例化多个模块,一般的语法结构就是:
genvar j; generate for(i=0; i<3; i=i+1)begin: inst_rtl flow_proc U_PROC(clk, rst_n, data_vld, in_data); end endgenerate

注意,generate for begin后面的名字是必须要有的,之后仿真器会通过这个标识来生成结构:
【Verilog】generate和for循环的一些使用总结(1)
文章图片


通过循环结构来简化wire连接,写法也是类似,例如我要把若干[DATA_WD -1:0]的数据拼成总线数据:
bit [DATA_WD -1:0]data_arr [PORT_NUM]; bit [PORT_NUM*DATA_WD -1:0] data_in; genvar i; generate for(i=0; i

当然了,以上都是可以综合的语法。

通过generate来选择代码块,例如在本次场景中,FLOP_FLAG决定输出是否要打拍,那么FLOP_FLAG为0和为1就是完全不同的电路,那么使用generate实现如下:
generate if(FLOP_FLAG)begin always @(posedge clk)begin: FLOP_OUT if(~rst_n)begin out_vld<= 0; out_data <= 0; out_cnt<= 0; end else begin out_vld <= vld; out_data <= data; out_cnt <= cnt; end end end else begin always @(*) begin: NO_FLOP_OUT out_vld = vld; out_data = https://www.it610.com/article/data; out_cnt = cnt; end end endgenerate

当FLOP_FLAG==1时,综合出的电路如下图:
【Verilog】generate和for循环的一些使用总结(1)
文章图片

当FLOP_FLAG==0时,综合出的电路如下图:
【Verilog】generate和for循环的一些使用总结(1)
文章图片

generate注意事项 1. 同一个文件中,generate for循环每次的循环变量名称不能重复,否则lint检查会报错,这也意味着generate不是一个完整的命名空间域吧;
generate genvar i; for(i=0; i<10; i=i+1)begin: RTL1 ... end endgenerategenerate genvar i; for(i=0; i<10; i=i+1)begin: RTL2 ... end endgenerate

2. generate 后跟begin end可以避免这一报错,但是verilog2005标准中已经明确禁止这种写法(generate begin-end),所以就乖乖的为每一个generate for定义一个genvar变量吧;
3. 把genvar定义在generate之外的话,两个generate都使用了这个变量,那么编译/lint/nlint都不会报错,甚至warning都不会报出,但是却可能引起仿真陷入死循环,也是不推荐,就乖乖定义genvar好了;
genvar i; generate for(i=0; i

4. genvar定义的变量不要用在always中循环使用,这种场景下乖乖在always里定义integer;
genvar i; // fail always @(*)begin: gain_data //integer i; //yes vld= 0; data = https://www.it610.com/article/0; cnt= 0; for(i=0; i

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

5. if-generate(或case-generate)的每一个if-else块也建议有一个名字,而不只是always块有名字。尽管在编译和lint检查时不会报错,但是可能会引发后续的formal报错,这是听一位大佬说的,不过说实话,我平时也不加这个名字;
6. generate中的代码块名字不要与文件中定义的信号名重复;
reg inst_rtl; genvar j; generate for(i=0; i<3; i=i+1)begin:inst_rtl flow_proc U_PROC(clk, rst_n, data_vld, in_data); end endgenerate

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

7. generate for里的参数必须直接调用,例如for(i=0; i 8. generate for中支持data[3i+8 : 3i]的取值方式,但是单纯的for循环不支持,只支持data[3i +: 8]写法;

    推荐阅读