generate为verilog中的生成语句,当对矢量中的多个位进行重复操作时,或者当进行多个模块的实例引用的重复操作时,或者根据参数的定义来确定程序中是否应该包含某段Verilog代码的时候,使用生成语句能大大简化程序的编写过程。
Verilog-2001添加了generate循环,允许产生module和primitive的多个实例化,generate语句的最主要功能就是对module、reg、assign、always、task等语句或者模块进行复制。
在generate语句中可以引入if-else和case语句,根据条件不同产生不同的实例化。
在设计中,很多情况下需要编写很多结构相同但是参数不同的赋值语句或者逻辑语句,如果在参数量很大的的情况下,原本的列举就会显得心有余而力不足。c语言中常用for语句来解决此类问题,verilog则为我们提供了generate语句。
一 、用法
1. generate语句有generate_for、generate_if、generate_case三种语句。
2. generate for语句必须有genvar关键字定义for的变量
3. for 的内容必须加begin和end
4. 必须给for语段起个名字
二、生成语句生成的实例范围
关键字generate-endgenerate用来指定该范围。生成实例可以是以下的一个或多个类型:
(1)模块;(2)用户定义原语;(3)门级语句;(4)连续赋值语句;(5)initial和always块。
三、三种语句的区别
3.1 generate-for语句
(1) 必须有genvar关键字定义for语句的变量。
(2)for语句的内容必须加begin和end(即使就一句)。
(3)for语句必须有个名字。
例1:利用generate_for来复制assign语句
module test(bin,gray);
parameter SIZE=8;
output [SIZE-1:0] bin;
input [SIZE-1:0] gray;
genvar i; //genvar i;也可以定义到generate语句里面
generate
for(i=0;i<SIZE;i=i+1)
begin:bit
assign bin[i]=^gray[SIZE-1:i];
end
endgenerate
endmodule
等同于下面语句
module test(bin,gray);
parameter SIZE=8;
output [SIZE-1:0] bin;
input [SIZE-1:0] gray;
assign bin[0]=^gray[SIZE-1:0];
assign bin[1]=^gray[SIZE-1:1];
assign bin[2]=^gray[SIZE-1:2];
assign bin[3]=^gray[SIZE-1:3];
assign bin[4]=^gray[SIZE-1:4];
assign bin[5]=^gray[SIZE-1:5];
assign bin[6]=^gray[SIZE-1:6];
assign bin[7]=^gray[SIZE-1:7];
endmodule
例2:利用generate_for来复制时序赋值语句
generate
genvar i;
for(i=0;i<SIZE;i=i+1)
begin:shifter
always@(posedge clk)
shifter[i]<=(i==0)?din:shifter[i-1];
end
endgenerate
相当于
always@(posedge clk)
begin
shifter[0]<=din;
shifter[1]<=shifter[0];
shifter[2]<=shifter[1];
... ...
shifter[SIZE]<=shifter[SIZE-1];
end
3.2 generate-if语句
例子:generate_for用于复制模块,而generate_if则是根据模块的参数(必须是常量)作为条件判断,来产生满足条件的电路。相当于判断语句。
module generate_if(
input t0,
input t1,
input t2,
output d
);
localparam S = 6; //定义模块所需参数,用于判断产生电路
generate
if(S < 7)
assign d = t0 | t1 | t2;
else
assign d = t0 & t1 & t2;
endgenerate
endmodule
3、generate_case语句
generate_case其实跟generate_if一样,都是根据参数(都必须为常量)作为判断条件,来产生满足条件的电路,不同于使用了case语法而已。
例子:
module generate_case(
input t0,
input t1,
input t2,
output d
);
localparam S = 8; //定义模块所需参数,用于判断产生电路
generate
case(S)
0:
assign d = t0 | t1 | t2;
1:
assign d = t0 & t1 & t2;
default:
assign d = t0 & t1 | t2;
endcase
endgenerate
endmodule
四、总结
之前一直在排斥对generate的使用,认为这种类似于c语言中for的循环语法并不适用于FPGA设计,因为FPGA实际上还是硬件,循环N次,就会映射N个同样的模块到FPGA,也就是多消耗的N倍的资源,为了节约资源,经常选择复用的方式来处理类循环数据。
但是殊不知在处理循环数据的时候,还是会消耗一定的资源以及逻辑调试的时间成本,最终可能也节约不了多少资源,而且相比于处理逻辑,循环语句要简洁明了,便于代码的阅读和维护。
随着工艺水平的提升,资源貌似也并不是项目考虑的首要因素了,大家都会留出充足的余量,所以开始正视这种generate“非主流”verilog语法。