写在前面的话
在设计中,很多情况下我们需要编写很多结构相同但参数不同的赋值语句或逻辑语句块,当参数量很大的情况下,原始的列举就会变得很笨拙甚至是不可行的。C语言处理这种问题通常情况下会使用如for循环语句来完成多次的相同操作。而verilog 语言呢?同样的为我们提供了generate语句块来帮助我们完成这些过程。接下来,梦翼师兄将和大家一起开始generate语句的学习。
基本概念
generate的主要功能就是对module,net,reg,parameter,assign,always,task,function进行复制,genvar是generate语句中的一种变量类型,用以在 generate-for 语句中声明一个正整数的索引变量 (如果将“X”或“Z”或者“负值”赋给genvar 变量将会出错)。genvar 变量可以声明在 generate 语句内,也可以声明在 generate 语句外。
generate 语句有 generate-for、generate-if 和 generate-case 三种语句,下面梦翼师兄和大家一起来学习这三种语句。
genrate-for
使用generate_for的时候,必须要注意以下几点要求:
a) 必须使用genvar申明一个正整数变量,用作for的判断变量;
b) for里面的内嵌语句,必须写在begin_end里面,哪怕只有一句;
c) begin_end需要一个名字。
例1:利用generate_for来复制assign语句
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * E_mail : zxopenwjf@126.com * The module function : generate_for_assign模块 *****************************************************/ 01 module for_test(indata, t0, t1, t2, t3); 02 03 input [7:0] indata; //输入8位位宽indata 04 output [1:0] t0, t1, t2, t3; //输出2位位宽t0,t1,t2,t3; 05 06 wire [1:0] temp [3:0]; //定义位宽为2,深度为4的temp 07 genvar i; 08 09 generate for(i=0; i<4; i=i+1 ) //generate for模块复制 10 begin : gfor_block 11 assign temp[i] = indata[2*i+1:2*i]; 12 end 13 endgenerate 14 15 assign t0 = temp[0]; //t0等于temp[0] 16 assign t1 = temp[1]; //t1等于temp[1] 17 assign t2 = temp[2]; //t2等于temp[2] 18 assign t3 = temp[3]; //t3等于temp[3] 19 20 endmodule |
编写的测试代码如下:
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function :for_test的测试模块 *****************************************************/ 01 `timescale 1ns/1ps 02 module tb; 03 04 reg [7:0] indata; //输入8位位宽indata 05 wire [1:0] t0, t1, t2, t3; //输出2位位宽t0,t1,t2,t3; 06 07//----------写入2组数据------------ 08 initial 09 begin 10 indata = 8'b1011_1011; 11 #100 indata = 8'b0101_1010; 12 end 13 14 //---------模块例化-------------- 15 for_test for_test( 16 .indata(indata), 17 .t0(t0), 18 .t1(t1), 19 .t2(t2), 20 .t3(t3) 21 ); 22 23 endmodule |
仿真波形如下:
观察波形可以得到:
temp[0] = indata[1:0];
temp[1] = indata[3:2];
temp[2] = indata[5:4];
temp[3] = indata[7:6];
由此得出for_test模块第9~13行可以这样展开:
assign temp[0] = indata[1:0];
assign temp[1] = indata[3:2];
assign temp[2] = indata[5:4];
assign temp[3] = indata[7:6];
我们发现,这段代码是通过i的增加来重复执行temp[i] = indata[2*i+1:2*i] 这条语句的,所以generate_for可以复制assign语句。
例2:利用generate_for来复制always语句
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function : generate_for_always模块 *****************************************************/ 01 module for_test1(indata, t0, t1, t2, t3); 02 03 input [7:0] indata; //输入8位位宽indata 04 output [1:0] t0, t1, t2, t3; //输出2位位宽t0,t1,t2,t3; 05 06 reg [1:0] temp [3:0]; //定义位宽为2,深度为4的temp 07 genvar i; 08 09 generate for(i=0; i<4; i=i+1 )//generate for模块复制 10 begin : gfor_block 11 always @ (*) 12 temp[i] = indata [2*i+1:2*i] 13 end 14 endgenerate 15 16 assign t0 = temp[0]; //t0等于temp[0] 17 assign t1 = temp[1]; //t1等于temp[1] 18 assign t2 = temp[2]; //t2等于temp[2] 19 assign t3 = temp[3]; //t3等于temp[3] 20 21 endmodule |
编写的测试代码如下:
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function :for_test1的测试模块 *****************************************************/ 01 `timescale 1ns/1ps 02 module tb; 03 04 reg [7:0] indata; //输入8位位宽indata 05 wire [1:0] t0, t1, t2, t3; //输出2位位宽t0,t1,t2,t3; 06 07//----------写入2组数据------------ 08 initial 09 begin 10 indata = 8'b1011_1011; 11 #100 indata = 8'b0101_1010; 12 end 13 14 //---------模块例化--------------- 15 for_test1 for_test1( 16 .indata(indata), 17 .t0(t0), 18 .t1(t1), 19 .t2(t2), 20 .t3(t3) 21 ); 22 23 endmodule |
仿真波形如下:
观察波形可以得到:
temp[0] = indata[1:0];
temp[1] = indata[3:2];
temp[2] = indata[5:4];
temp[3] = indata[7:6];
由此得到for_test1模块第9~14行我们可以这样展开:
always @ (*)
temp[0] = indata[1:0];
always @ (*)
temp[1] = indata[3:2];
always @ (*)
temp[2] = indata[5:4];
always @ (*)
temp[3] = indata[7:6];
我们发现,这段代码是通过i的增加来重复执行
always @ (*)
temp[i] = indata[2*i+1:2*i]
这条语句的,所以generate_for可以复制always语句。
例3:利用多个generate_for来实现模块复制
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function : generate_for_多个模块 *****************************************************/ 01 module for_test2(indata, t0, t1, t2, t3); 02 03 input [7:0] indata; //输入8位位宽indata 04 output [1:0] t0, t1, t2, t3; //输出2位位宽t0,t1,t2,t3; 05 06 wire [1:0] temp [3:0]; //定义位宽为2,深度为4的temp 07 genvar i, j; 08 09 generate for(i=0; i<4; i=i+1) //generate for模块复制 10 begin : gfor_block_a 11 for(j=0; j<2; j=j+1) 12 begin : gfor_block_b 13 assign temp[i][j] = indata[2*i+j]; 14 end 15 end 16 endgenerate 17 18 assign t0 = temp[0]; //t0等于temp[0] 19 assign t1 = temp[1]; //t1等于temp[1] 20 assign t2 = temp[2]; //t2等于temp[2] 21 assign t3 = temp[3]; //t3等于temp[3] 22 endmodule |
编写的测试代码如下:
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function :for_test2的测试模块 *****************************************************/ 01 `timescale 1ns/1ps 02 module tb; 03 04 reg [7:0] indata; //输入8位位宽indata 05 wire [1:0] t0, t1, t2, t3; //输出2位位宽t0,t1,t2,t3; 06 07//----------写入2组数据------------ 08 initial 09 begin 10 indata = 8'b1011_1011; 11 #100 indata = 8'b0101_1010; 12 end 13 14 //---------模块例化--------------- 15 for_test2 for_test2( 16 .indata(indata), 17 .t0(t0), 18 .t1(t1), 19 .t2(t2), 20 .t3(t3) 21 ); 22 23 endmodule |
仿真波形如下:
观察波形可以得到:
temp[0] [0] = indata[0];
temp[0] [1] = indata[1];
temp[1] [0] = indata[2];
temp[1] [0] = indata[3];
temp[2] [0] = indata[4];
temp[2] [1] = indata[5];
temp[3] [0] = indata[6];
temp[3] [1] = indata[7];
由此得到for_test2模块第9~16行可以这样展开:
assign temp[0] [0] = indata[0];
assign temp[0] [1] = indata[1];
assign temp[1] [0] = indata[2];
assign temp[1] [0] = indata[3];
assign temp[2] [0] = indata[4];
assign temp[2] [1] = indata[5];
assign temp[3] [0] = indata[6];
assign temp[3] [1] = indata[7];
我们发现,这段代码是通过i和j的增加来重复执行
temp[i][j] = indata[2*i+j]
这条语句的,所以generate_for可以实现模块的复制。
genrate-if
generate_for是用于复制模块,而generate_if则是根据模块的参数(必须是常量)作为条件判断,来产生满足条件的电路。如:
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function : generate_if模块 *****************************************************/ 01 module if_test(a, b, c, d); 02 03 input a, b, c; //输入信号a,b,c 04 output d; //输出信号d 05 06 localparam WIDE = 8; //参数模块,用于选择产生的电路 07 08 generate 09 if(WIDE <10) //当WIDE小于10,d等于abc相或 10 assign d = a | b | c; 11 else //当WIDE大于等于10,d等于abc相与 12 assign d = a & b & c; 13 endgenerate 14 15 endmodule |
该代码生成的RTL电路图如下:
当把WIDE改成等于12的时候,代码如下:
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function : generate_if模块 *****************************************************/ 01 module if_test(a, b, c, d); 02 03 input a, b, c; //输入信号a,b,c 04 output d; //输出信号d 05 06 localparam WIDE = 12; //参数模块,用于选择生产的电路 07 08 generate 09 if(WIDE <10) //当WIDE小于10,d等于abc相或 10 assign d = a | b | c; 11 else //当WIDE大于等于10,d等于abc相与 12 assign d = a & b & c; 13 endgenerate 14 15 endmodule |
该代码生成的RTL电路图如下:
从上面2个不同的WIDE值得出的RTL图可知,generate_if是根据模块的参数来作为判断条件,来产生满足条件的电路,当WIDE等于8时,d等于abc相或,对应于我们代码的第9~10行;当WIDE等于12时,d等于abc相与,对应于我们代码的第11~12行。
generate-case
generate_case其实跟generate_if一样的,都是根据模块的参数(必须是常量)作为条件判断,来生成满足条件的电路,不同的地方仅仅是改成使用case 的语法而已。如:
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function : generate_case模块 *****************************************************/ 01 module case_test(a, b, c, d); 02 03 input a, b, c; //输入信号a,b,c 04 output d; //输出信号d 05 06 localparam WIDE = 12; //参数模块,用于选择生产的电路 07 08 generate 09 case(WIDE) 10 0 : //当WIDE等于0,d等于abc相或 11 assign d = a | b | c; 12 13 1 : //当WIDE等于1,d等于abc相与 14 assign d = a & b & c; 15 16 default : //当WIDE不等于1或0,d等于a与b或c 17 assign d = a & b | c; 18 19 endcase 20 endgenerate 21 22 endmodule |
该代码生成的RTL电路图如下:
我们将参数WIDE设置位0,生成的RTL电路图如下:
将参数WIDE设置位1,生成的RTL电路图如下:
从上面3个不同的WIDE值得出的RTL图可知,generate_case也是根据模块的参数来作为条件判断,来产生满足条件的电路,当WIDE等于12时,d等于a与b或c,对应于我们代码的第16~17行;当WIDE等于0时,d等于abc相或,对应于我们代码的第10~11行;当WIDE等于1时,d等于abc相与,对应于我们代码的第13~14行。