Verilog generate
generate用法
关键字generate
和endgenerate
作为使用语法的起点,有三种衍生结构:
generate-for
语句结构generate-if
语句结构generate-case
语句结构
使用generate的情况主要如下:
- 使用for循环对模块进行多次相似实例化
- 使用参数更改模块的结构或者设计
- 使用带有断言语句进行功能和形式验证
generate在综合过程中重复构造相似电路。
generate-for
使用generate-for之前,需要先声明一个genvar
变量,用于for循环语句进行判断。
genvar i; generate for( i=0;i<15;i=i+1) begin: loop always @ (posedge clk or negedge rst_n ) begin if( !rst_n ) begin dout[i] <= 1'b0; end else begin dout[i] <= din_a[i] ^ din_b[i]; end end end endgenerate // 如果for结构中没有使用always,注意要使用assign
genvar i; generate for(i=0;i<15;i=i+1) begin : loop xor xor_inst( .dout (dout[i]) , .din_a(din_a[i]), .din_b(din_b[i]) ); end endgenerate
第一个例子是对always块进行了循环,第二个则是对实例化时的模块进行了循环。
begin
后面的内容为标签名,是generate语句模块名,目的是通过它对循环语句进行层次化引用。第n
个模块相对层次名为loop[n].xor_inst
。
只有当for
循环在generate
中时,才能将always
放在for循环中。
generate-if
generate-if
语句结构比较宽松,不需要对generate
语句进行命名( generate-for
主要是对循环语句进行层次化引用),也不需要genvar变量。
由于generate-if
语句结构是通过判断语句执行代码块,也就决定了每次最多执行一个代码块,这种情况下,对各个代码块使用相同命名是合法的,并且有助于保持对代码的层次化引用。
注意点:在generate
块中的判断条件必须是常量。
parameter DIV = 4; generate if( DIV == 4 ) begin : u1 div4 div4_inst(xxxx); end else if( DIV == 8 ) begin: u1 // 命名可以相同 div8 div8_inst(xxxx); end endgenerate
generate-case
generate-case
语句和generate-if
语句核心思想都是进行条件判断,用法基本一致。
和generate-if
语句一样,case判断条件必须是常量。
parameter SEL = 1; generate case( SEL ) 1: begin //xxx end 2: begin // xxx end default: begin // xxx end endcase endgenerate
应用分析
1. 循环生成构造
循环生成构造提供了一种简单而简洁的方法来创建模块项的多个实例,例如模块实例、分配语句、断言、接口实例等。
本质上,它是一种特殊类型的for循环,其循环索引变量为 datatype genvar。
genvar
它是一个整数数据类型,仅在综合时存在并在运行时消失。
可以嵌套generate-for
循环,只需确保genvar将外部循环和内部循环分开使用,并在嵌套的 for 循环中引用这些变量时要小心。
2. 条件生成构造
条件生成构造允许根据在模块实例化期间传递的参数值更改设计结构。
这在为设计创建参数化通用 RTL 模块时非常有用。
通过使用generate而不是简单的多路复用器,可以节省一堆门电路和触发器。
3. 分层访问生成块
访问位于生成块内的模块项。
生成块有一个名字。
如果不为其命名,编译器将自动分配一个通用名称,例如genblk01、genblk02等,通常必须转储 wave 并用Visualizer工具以查看分配了哪些名称。
要访问生成块中的模块项,必须分层访问<generate_blk_name>.<module_item_name>
。
注意点
- Verilog 中没有
i++
的写法,要写成i=i+1
。 - generate-for中可以用
always
块或者assign
赋值
例子
hdlbits的练习题:BCD加法
module top_module( input [399:0] a , input [399:0] b , input cin , output cout , output [399:0] sum ); wire [99:0] cin_reg; bcd_fadd bcd_fadd_inst_0( .a (a[3:0] ), .b (b[3:0] ), .cin (cin ), .cout(cin_reg[0]), .sum (sum[3:0] ) ); genvar gv_i; generate for(gv_i=1;gv_i<100;gv_i= gv_i+1)begin :loop bcd_fadd bcd_fadd_inst( .a (a[(gv_i+1)*4-1:gv_i*4] ), .b (b[(gv_i+1)*4-1:gv_i*4] ), .cin (cin_reg[gv_i-1] ), .cout(cin_reg[gv_i] ), .sum (sum[(gv_i+1)*4-1:gv_i*4]) ); end endgenerate assign cout = cin_reg[99]; endmodule