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

简介: 【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代码。

通过循环结构来例化多个模块,一般的语法结构就是:

1. genvar j;
2. generate
3.     for(i=0; i<3; i=i+1)begin: inst_rtl
4.         flow_proc U_PROC(clk, rst_n, data_vld, in_data);
5.     end
6. endgenerate

注意,generate for begin后面的名字是必须要有的,之后仿真器会通过这个标识来生成结构:

通过循环结构来简化wire连接,写法也是类似,例如我要把若干[DATA_WD -1:0]的数据拼成总线数据:

1. bit [DATA_WD -1:0]  data_arr [PORT_NUM];
2. bit [PORT_NUM*DATA_WD -1:0] data_in;
3. 
4. genvar i;
5. generate
6.     for(i=0; i<PORT_NUM; i=i+1)begin:gen_data
7.         assign data_in[i*DATA_WD +:DATA_WD] = data_arr[i];
8.     end
9. endgenerate

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

通过generate来选择代码块,例如在本次场景中,FLOP_FLAG决定输出是否要打拍,那么FLOP_FLAG为0和为1就是完全不同的电路,那么使用generate实现如下:

1. generate
2.     if(FLOP_FLAG)begin
3.         always @(posedge clk)begin: FLOP_OUT
4.             if(~rst_n)begin
5.                 out_vld  <= 0;
6.                 out_data <= 0;
7.                 out_cnt  <= 0;
8.             end
9.             else begin
10.                 out_vld <= vld;
11.                 out_data <= data;
12.                 out_cnt <= cnt;
13.             end
14.         end
15.     end
16.     else begin
17.         always @(*) begin: NO_FLOP_OUT
18.             out_vld = vld;
19.             out_data = data;
20.             out_cnt = cnt;
21.         end
22.     end
23. endgenerate

当FLOP_FLAG==1时,综合出的电路如下图:

当FLOP_FLAG==0时,综合出的电路如下图:

generate注意事项

1. 同一个文件中,generate for循环每次的循环变量名称不能重复,否则lint检查会报错,这也意味着generate不是一个完整的命名空间域吧;

1. generate
2.     genvar i;
3.     for(i=0; i<10; i=i+1)begin: RTL1
4.         ...
5.     end
6. endgenerate
7. 
8. generate
9.     genvar i;
10.     for(i=0; i<10; i=i+1)begin: RTL2
11.         ...
12.     end
13. endgenerate

2. generate 后跟begin end可以避免这一报错,但是verilog2005标准中已经明确禁止这种写法(generate begin-end),所以就乖乖的为每一个generate for定义一个genvar变量吧;

3. 把genvar定义在generate之外的话,两个generate都使用了这个变量,那么编译/lint/nlint都不会报错,甚至warning都不会报出,但是却可能引起仿真陷入死循环,也是不推荐,就乖乖定义genvar好了;

1. genvar i;
2. generate
3.     for(i=0; i<PORT_NUM; i=i+1)begin:gen_data
4.         assign data_in[i*DATA_WD +:DATA_WD] = data_arr[i];
5.     end
6. endgenerate
7. generate
8.     for(i=0; i<PORT_NUM; i=i+1)begin:gen_data_tmp
9.         assign data_in_tmp[i*DATA_WD +:DATA_WD] = data_arr[i];
10.     end
11. endgenerate

4. genvar定义的变量不要用在always中循环使用,这种场景下乖乖在always里定义integer;

1.     genvar i; // fail
2.     always @(*)begin: gain_data
3.         //integer i;  //yes
4.         vld  = 0;
5.         data = 0;
6.         cnt  = 0;        
7.         for(i=0; i<PORT_NUM; i=i+1)begin
8.             if(in_vld[i])begin
9.                 vld  = 1'b1;
10.                 cnt  = cnt + {DATA_WD{1'b1}};
11.                 data = in_data[DATA_WD*i +:DATA_WD];
12.             end
13.         end
14.     end

5. if-generate(或case-generate)的每一个if-else块也建议有一个名字,而不只是always块有名字。尽管在编译和lint检查时不会报错,但是可能会引发后续的formal报错,这是听一位大佬说的,不过说实话,我平时也不加这个名字;

6. generate中的代码块名字不要与文件中定义的信号名重复;

1. reg inst_rtl;
2. genvar j;
3. generate
4.  for(i=0; i<3; i=i+1)begin:inst_rtl
5.    flow_proc U_PROC(clk, rst_n, data_vld, in_data);
6.  end
7. endgenerate

7. generate for里的参数必须直接调用,例如for(i=0; i<DEPTH; i=i+1),不能够出现运算例如for(i=0; i<DEPTH*5; i=i+1),如果一定需要这样做,那么要将参数提前处理好再拿来用;

8. generate for中支持data[3i+8 : 3i]的取值方式,但是单纯的for循环不支持,只支持data[3i +: 8]写法;


相关文章
|
C语言
Verilog中generate的用法
Verilog中generate的用法
3707 1
|
编译器 索引
Verilog generate
Verilog generate
|
网络性能优化
【AXI】解读AXI协议的额外信号(QOS信号,REGION信号,与USER信号)
【AXI】解读AXI协议的额外信号(QOS信号,REGION信号,与USER信号)
【AXI】解读AXI协议的额外信号(QOS信号,REGION信号,与USER信号)
|
机器学习/深度学习 编译器
【Verilog】generate和for循环的一些使用总结(2)
【Verilog】generate和for循环的一些使用总结(2)
1853 0
【Verilog】generate和for循环的一些使用总结(2)
|
前端开发 芯片
【芯片前端】关于set_input_delay/set_output_delay慢信号约束到快时钟的思考
【芯片前端】关于set_input_delay/set_output_delay慢信号约束到快时钟的思考
924 0
灭霸打个响指的功夫,看懂Verilog多维数组【Verilog高级教程】
灭霸打个响指的功夫,看懂Verilog多维数组【Verilog高级教程】
灭霸打个响指的功夫,看懂Verilog多维数组【Verilog高级教程】
【AXI】解读AXI协议中的burst突发传输机制
【AXI】解读AXI协议中的burst突发传输机制
【AXI】解读AXI协议中的burst突发传输机制
|
vr&ar SoC 内存技术
深入理解AMBA总线(十二)AXI突发传输和AXI控制信号
深入理解AMBA总线(十二)AXI突发传输和AXI控制信号
3396 0
|
芯片 索引 内存技术
玩转parameter与localparameter,这篇文章就够了【Verilog高级教程】
玩转parameter与localparameter,这篇文章就够了【Verilog高级教程】
玩转parameter与localparameter,这篇文章就够了【Verilog高级教程】