Verilog基础语法(7)之generate块

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

仿真文件:

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,选择了半加器:

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
  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值