• verilog generate


    generate块允许乘以模块实例或执行任何模块的条件实例化。它提供了基于 Verilog 参数构建设计的能力。当需要多次重复相同的操作或模块实例,或者必须根据给定的 Verilog 参数有条件地包含某些代码时,这些语句特别方便。

    generate块不能包含端口、参数、声明specparamspecify块。但是,其他模块项目和其他生成块是允许的。所有生成的实例都在module关键字generate和之间进行编码endgenerate

    生成的实例化可以有模块、连续赋值alwaysinitial块和用户定义的原语。有两种类型的生成结构——循环和条件。

    生成for循环

    半加器将在另一个名为my_design的顶级设计模块中使用for 循环构造实例化N次。必须使用关键字声明循环变量,该关键字告诉工具该变量将在生成块的详细说明期间专门使用。generategenvar

    // Design for a half-adder
    module ha ( input   a, b,
                output  sum, cout);
    
      assign sum  = a ^ b;
      assign cout = a & b;
    endmodule
    
    // A top level design that contains N instances of half adder
    module my_design
    	#(parameter N=4)
    		(	input [N-1:0] a, b,
    			output [N-1:0] sum, cout);
    
    	// Declare a temporary loop variable to be used during
    	// generation and won't be available during simulation
    	genvar i;
    
    	// Generate for loop to instantiate N times
    	generate
    		for (i = 0; i < N; i = i + 1) begin
              ha u0 (a[i], b[i], sum[i], cout[i]);
    		end
    	endgenerate
    endmodule
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    试验台

    testbench 参数用于控制设计中半加器实例的数量。当N为 2 时,my_design将有两个半加器实例。

    module tb;
    	parameter N = 2;
      reg  [N-1:0] a, b;
      wire [N-1:0] sum, cout;
    
      // Instantiate top level design with N=2 so that it will have 2
      // separate instances of half adders and both are given two separate
      // inputs
      my_design #(.N(N)) md( .a(a), .b(b), .sum(sum), .cout(cout));
    
      initial begin
        a <= 0;
        b <= 0;
    
        $monitor ("a=0x%0h b=0x%0h sum=0x%0h cout=0x%0h", a, b, sum, cout);
    
        #10 a <= 'h2;
        		b <= 'h3;
        #20 b <= 'h4;
        #10 a <= 'h5;
      end
    endmodule
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    a[0]b[0]给出输出sum[0]cout[0]a[1]b[1]给出输出sum[1]cout[1]

    模拟日志
    ncsim > 运行
    a=0x0 b=0x0 sum=0x0 cout=0x0
    a=0x2 b=0x3 总和=0x1 cout=0x2
    a=0x2 b=0x0 sum=0x2 cout=0x0
    a=0x1 b=0x0 sum=0x1 cout=0x0
    ncsim: *W,RNQUIE:模拟完成。
    ncsim > 退出
    
    

    看到详细的 RTL 确实有两个由generate块生成的半加器实例。

    生成如果

    下面显示的是一个使用if else内部generate结构在两个不同的多路复用器实现之间进行选择的示例。第一个设计使用assign语句来实现多路复用器,而第二个设计使用case语句。在顶层设计模块中定义了一个名为USE_CASE的参数,用于在两个选项之间进行选择。

    // Design #1: Multiplexer design uses an "assign" statement to assign
    // out signal
    module mux_assign ( input a, b, sel,
                       output out);
      assign out = sel ? a : b;
    
      // The initial display statement is used so that
      // we know which design got instantiated from simulation
      // logs
      initial
      	$display ("mux_assign is instantiated");
    endmodule
    
    // Design #2: Multiplexer design uses a "case" statement to drive
    // out signal
    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
    
      // The initial display statement is used so that
      // we know which design got instantiated from simulation
      // logs
      initial
        $display ("mux_case is instantiated");
    endmodule
    
    // Top Level Design: Use a parameter to choose either one
    module my_design (	input a, b, sel,
             			output out);
      parameter USE_CASE = 0;
    
      // Use a "generate" block to instantiate either mux_case
      // or mux_assign using an if else construct with generate
      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
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    试验台

    Testbench 实例化顶层模块my_design并将参数USE_CASE设置为 1,以便实例化设计 usingcase语句。

    module tb;
    	// Declare testbench variables
      reg a, b, sel;
      wire out;
      integer i;
    
      // Instantiate top level design and set USE_CASE parameter to 1 so that
      // the design using case statement is instantiated
      my_design #(.USE_CASE(1)) u0 ( .a(a), .b(b), .sel(sel), .out(out));
    
      initial begin
      	// Initialize testbench variables
      	a <= 0;
        b <= 0;
        sel <= 0;
    
        // Assign random values to DUT inputs with some delay
        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
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    当参数USE_CASE为1时,从仿真日志可以看出,multiplexer design usingcase语句被实例化了。当USE_CASE为零时,多路复用器设计 usingassign语句被实例化。这可以从模拟日志中打印的显示语句中看出。

    模拟日志
    // 当 USE_CASE = 1 时
    ncsim > 运行
    mux_case 被实例化
    i=0 a=0x0 b=0x0 选择=0x0 输出=0x0
    i=1 a=0x0 b=0x1 选择=0x1 输出=0x1
    i=2 a=0x1 b=0x1 选择=0x1 输出=0x1
    i=3 a=0x1 b=0x0 选择=0x1 输出=0x0
    i=4 a=0x1 b=0x0 选择=0x1 输出=0x0
    ncsim: *W,RNQUIE:模拟完成。
    
    // 当 USE_CASE = 0 时
    ncsim > 运行
    mux_assign 被实例化
    i=0 a=0x0 b=0x0 选择=0x0 输出=0x0
    i=1 a=0x0 b=0x1 选择=0x1 输出=0x0
    i=2 a=0x1 b=0x1 选择=0x1 输出=0x1
    i=3 a=0x1 b=0x0 选择=0x1 输出=0x1
    i=4 a=0x1 b=0x0 选择=0x1 输出=0x1
    ncsim: *W,RNQUIE:模拟完成。
    
    

    生成案例

    generate case 允许模块、initial 和 always 块根据case表达式在另一个模块中实例化,以从多个选项中选择一个。

    // Design #1: Half adder
    module ha (input a, b,
               output reg sum, cout);
      always @ (a or b)
      {cout, sum} = a + b;
    
      initial
        $display ("Half adder instantiation");
    endmodule
    
    // Design #2: Full adder
    module fa (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
    
    // Top level design: Choose between half adder and full adder
    module my_adder (input a, b, cin,
                     output sum, cout);
      parameter ADDER_TYPE = 1;
    
      generate
        case(ADDER_TYPE)
          0 : ha u0 (.a(a), .b(b), .sum(sum), .cout(cout));
          1 : fa u1 (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
        endcase
      endgenerate
    endmodule
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    试验台

    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
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    请注意,由于实例化了半加器,因此cin对输出sumcout没有任何影响。

    模拟日志
    ncsim > 运行
    半加器实例化
    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
    ncsim: *W,RNQUIE:模拟完成。
    
    
  • 相关阅读:
    c++术语大总结
    再获认可!知道创宇入选“业务安全推进计划”首批成员单位
    IBM Qiskit量子机器学习速成(一)
    RHCE学习 --- 第一次作业
    【STM32】【HAL库】【实用制作】数控收音机(软件设计)
    R语言的简介和安装
    创作一款表情包生成微信小程序:功能详解与用户体验优化
    MySql---事务,索引,视图概述
    05 面向对象
    深入了解RTMP推流技术:视频汇聚EasyCVR低延迟与高稳定性分析
  • 原文地址:https://blog.csdn.net/luoganttcc/article/details/128024145