【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]写法;


相关文章
|
机器学习/深度学习 算法 异构计算
m基于FPGA的多通道FIR滤波器verilog实现,包含testbench测试文件
本文介绍了使用VIVADO 2019.2仿真的多通道FIR滤波器设计。展示了系统RTL结构图,并简述了FIR滤波器的基本理论,包括单通道和多通道的概念、常见结构及设计方法,如窗函数法、频率采样法、优化算法和机器学习方法。此外,还提供了Verilog核心程序代码,用于实现4通道滤波器模块,包含时钟、复位信号及输入输出接口的定义。
1007 7
|
存储 异构计算
Verilog RAM/ROM的数据初始化
Verilog RAM/ROM的数据初始化
|
C语言
Verilog中generate的用法
Verilog中generate的用法
4137 1
ZYNQ-AXI总线的信号接口要求以及时序关系
ZYNQ-AXI总线的信号接口要求以及时序关系
2773 0
ZYNQ-AXI总线的信号接口要求以及时序关系
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
算法 数据中心 云计算
Xilinx IP 10Gigabit Ethernet Subsystem IP接口的详细说明
总的来说,Xilinx的10Gigabit Ethernet Subsystem IP是一个强大的,灵活的和高效的解决方案,它使得设计者能够快速、准确、高效地实现10Gbps的以太网连接。
892 25
【verilog】同步复位,异步复位以及异步复位同步释放
该文讨论了数字电路设计中触发器复位机制的三种类型:同步复位、异步复位和异步复位同步释放。同步复位在时钟边沿确保稳定性,但对复位脉冲宽度有要求;异步复位响应快速,但可能受干扰且时序不确定;异步复位同步释放则结合两者的优点。设计时需根据需求权衡选择。文中还给出了Verilog代码示例。
一把王者的时间,学会generate语句【Verilog高级教程】
一把王者的时间,学会generate语句【Verilog高级教程】
一把王者的时间,学会generate语句【Verilog高级教程】
灭霸打个响指的功夫,看懂Verilog多维数组【Verilog高级教程】
灭霸打个响指的功夫,看懂Verilog多维数组【Verilog高级教程】
灭霸打个响指的功夫,看懂Verilog多维数组【Verilog高级教程】
|
机器学习/深度学习 编译器
【Verilog】generate和for循环的一些使用总结(2)
【Verilog】generate和for循环的一些使用总结(2)
2862 0
【Verilog】generate和for循环的一些使用总结(2)