verilog中的generate块可以称为生成块,所谓生成,可以理解为复制。如果不太好理解,下面我们继续使用generate块。
generate块应用的场合通常是对模块进行批量例化,或者有条件的例化,使用参数进行控制对哪些模块进行例化,或者例化多少。
不仅限于模块例化,当同一个操作或模块实例需要多次重复,或者某些代码需要根据给定的Verilog参数有条件地包含时,这些语句特别方便。
generate块可以分为generate for和generate if或者generate case。
generate for
介绍generate for 之前,先介绍for循环:
for循环,必须在always块里使用。对应的,always块内的变量要声明成reg类型。
for(表达式1;表达式2;表达式3),执行时对表达式1、2、3和C语言中一样:
(1)执行表达式1,一般是循环变量赋初值;
(2)执行表达式2,若结果为真则执行for里面的内容,否则结束for语句;
(3)执行完for里面的语句,执行表达式3,一般是循环变量自增、自减、移位等操作,回到(2);
verilog的for和C语言的for的不同点;
C语言的for里面的语句是串行顺序执行,而verilog的for内的语句实际是并行的,只是为了写代码方便才用for对多个同样的结构赋值。
比如:实现移位寄存器:
integer i;
always @ (posedge clk)
begin
data_reg[0] <= data_in;
for(i = 0; i < 4; i = i+1) begin
data_reg[i+1] <= data_reg[i];
end
end
等效于:
always @ (posedge clk)
begin
data_reg[0] <= data_in;
data_reg[1] <= data_reg[0];
data_reg[2] <= data_reg[1];
data_reg[3] <= data_reg[2];
data_reg[4] <= data_reg[3];
end
当相同结构的赋值语句较多时,使用for语句能够简化代码,并不会影响实际综合后的电路结构。
generate for 用于批量处理某些赋值等行为。例如:
半加器模块:
module add(
input a,
input b,
output sum
output cout
);
assign sum = a ^ b;
assign cout = a & b;
endmodule
当需要多次进行加法运算时,设置一个可控制加发次数的模块
module exam
#
(
parameter N = 2
)
(
input [N-1:0]a,
input [N-1:0]b,
output [N-1:0]sum,
output [N-1:0]cout
);
genvar i;
generate
for(i = 0; i < N; i = i + 1)begin:addN
add u0(.a(a[i]), .b(b[i]), .sum(sum[i]), .cout(cout[i]));
end
endgenerate
作用上:和for是一样的;
区别:
(1)generate for的循环变量必须用genvar声明,for的变量可以用reg、integer整数等多种类型声明;
(2)for只能用在always块里面,generate for可以做assign赋值,用always块话,always写在generate for里;
(3)generate for后面必须给这个循环起一个名字,for不需要;
(4)generate for还可以用于例化模块;
generate if
generate if中的条件必须是参数,这是很重要的一点,初学者容易误用,例如将generate if(),括号内给一个变量,根据其值选择执行哪一块语句。
例子:
先给出两个待选择模块:
module mux_assign ( input a, b, sel,
output out);
assign out = sel ? a : b;
initial
$display ("mux_assign is instantiated");
endmodule
module mux_case (input a, b, sel,
output reg out);
always @ (a or b or sel) begin
case (sel)
0 : out = a;
1 : out = b;
endcase
end
initial
$display ("mux_case is instantiated");
endmodule
使用generate if语句来选择例化上述哪一个模块:
module my_design ( input a, b, sel,
output out);
parameter USE_CASE = 0;
generate
if (USE_CASE)
mux_case mc (.a(a), .b(b), .sel(sel), .out(out));
else
mux_assign ma (.a(a), .b(b), .sel(sel), .out(out));
endgenerate
endmodule
USE_CASE就是一个参数,根据参数的值来选择例化哪一个模块。
仿真文件:
module tb;
reg a, b, sel;
wire out;
integer i;
my_design #(.USE_CASE(1)) u0 ( .a(a), .b(b), .sel(sel), .out(out));
initial begin
a <= 0;
b <= 0;
sel <= 0;
for (i = 0; i < 5; i = i + 1) begin
#10 a <= $random;
b <= $random;
sel <= $random;
$display ("i=%0d a=0x%0h b=0x%0h sel=0x%0h out=0x%0h", i, a, b, sel, out);
end
end
endmodule
结果:
USE_CASE代入参数为1,因此,应该例化的是mux_case 被执行。
// When USE_CASE = 1
mux_case is instantiated
i=0 a=0x0 b=0x0 sel=0x0 out=0x0
i=1 a=0x0 b=0x1 sel=0x1 out=0x1
i=2 a=0x1 b=0x1 sel=0x1 out=0x1
i=3 a=0x1 b=0x0 sel=0x1 out=0x0
i=4 a=0x1 b=0x0 sel=0x1 out=0x0
generate case
generate case语句和generate if语句用法无异,和普通的if与case一致,if具有优先级,case没有优先级。
例子:
给出半加器和全加器设计:
半加器:
module halfadd (input a, b,
output reg sum, cout);
always @ (a or b)
{cout, sum} = a + b;
initial
$display ("Half adder instantiation");
endmodule
全加器:
module falladd (input a, b, cin,
output reg sum, cout);
always @ (a or b or cin)
{cout, sum} = a + b + cin;
initial
$display ("Full adder instantiation");
endmodule
顶层使用generate case来选调用半加器和全加器,通过参数为ADDER_TYPE 值进行区分:
module my_adder (input a, b, cin,
output sum, cout);
parameter ADDER_TYPE = 1;
generate
case(ADDER_TYPE)
0 : halfadd u0 (.a(a), .b(b), .sum(sum), .cout(cout));
1 : falladd u1 (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
endcase
endgenerate
endmodule
仿真文件:文章来源:https://www.toymoban.com/news/detail-639980.html
module tb;
reg a, b, cin;
wire sum, cout;
my_adder #(.ADDER_TYPE(0)) u0 (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
initial begin
a <= 0;
b <= 0;
cin <= 0;
$monitor("a=0x%0h b=0x%0h cin=0x%0h cout=0%0h sum=0x%0h",
a, b, cin, cout, sum);
for (int i = 0; i < 5; i = i + 1) begin
#10 a <= $random;
b <= $random;
cin <= $random;
end
end
endmodule
仿真结果:
仿真中ADDER_TYPE = 0,选择了半加器:文章来源地址https://www.toymoban.com/news/detail-639980.html
Half adder instantiation
a=0x0 b=0x0 cin=0x0 cout=00 sum=0x0
a=0x0 b=0x1 cin=0x1 cout=00 sum=0x1
a=0x1 b=0x1 cin=0x1 cout=01 sum=0x0
a=0x1 b=0x0 cin=0x1 cout=00 sum=0x1
到了这里,关于Verilog基础语法(7)之generate块的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!