Tutorials

Learn More

The generate statement in Verilog is a very useful construct that generates synthesizable code during elaboration time dynamically. The simulator provides an elaborated code of the ‘generate’ block. It provides the below facilities:

  1. To generate multiple module instances or code repetition.
  2. Conditionally instantiate a block of code based on the Verilog parameter, however, the parameter is not permitted in the generate statement.

 It basically provides control on variables, functions, tasks, and instantiation declarations. A generate block has been written within generate and endgenerate keywords.

Types of generate instantiation

  1. Modules
  2. Verilog gate primitives
  3. Continuous assignments
  4. Initial and always blocks
  5. User-defined primitives

Let’s see what is allowed within the scope of a generate block.

       A. Data types

    1. integer, real
    2. net, reg
    3. time, realtime
    4. event

           B. Function and task

    Note: Function and task are not allowed within a generate loop, but they are allowed in generate block.

    Below module items/declarations are not allowed within the scope of a generate block

    1. Port declarations like input, output, and inout 
    2. specify blocks
    3. parameters and local parameters

    Methods to write generate statements

    1. Generate loop
    2. Generate conditional (includes generate if-else and generate case)

    Generate loop

    The generate loop is similar to the for loop statement, but it uses genvar keyword as a loop variable. 

    • The genvar keyword is only used during the evaluation of generate block and does not exist during the simulation of the design. It needs to be used by a generate loop.
    • Generate loop provides flexibility to reduce code lines by replacing repetitive statements to a single statement like for loop.
    • Similar to a for loop, generate loops also can be nested with different genvar as an index variable.

    Example: Using always block inside generate block

    genvar k;
    generate 
      for (k = 0; k < 4; k++) begin
        always@(posedge clk) begin
          val[k] = a[k] & b[k];
        end
      end
    endgenerate

    This code expands to

    always@(posedge clk) begin
       val[0] = a[0] & b[0];
       val[1] = a[1] & b[1];
       val[2] = a[2] & b[2];
       val[3] = a[3] & b[3];
    end

    Example: Ripple Carry Adder

    module full_adder(
      input a, b, cin,
      output sum, cout
    );
      
      assign {sum, cout} = {a^b^cin, ((a & b) | (b & cin) | (a & cin))};
      //or
      //assign sum = a^b^cin;
      //assign cout = (a & b) | (b & cin) | (a & cin);
    endmodule
    
    module ripple_carry_adder #(parameter SIZE = 4) (
      input [SIZE-1:0] A, B, 
      input Cin,
      output [SIZE-1:0] S, Cout);
      
      genvar g;
      
      full_adder fa0(A[0], B[0], Cin, S[0], Cout[0]);
      generate  // This will instantial full_adder SIZE-1 times
        for(g = 1; g<SIZE; g++) begin
          full_adder fa(A[g], B[g], Cout[g-1], S[g], Cout[g]);
        end
      endgenerate
    endmodule

    Output:

    A = 0001: B = 0000, Cin = 0 --> S = 0001, Cout[3] = 0, Addition = 1
    A = 0010: B = 0100, Cin = 1 --> S = 0111, Cout[3] = 0, Addition = 7
    A = 1011: B = 0110, Cin = 0 --> S = 0001, Cout[3] = 1, Addition = 17
    A = 0101: B = 0011, Cin = 1 --> S = 1001, Cout[3] = 0, Addition = 9
    Simulation complete via $finish(1) at time 12 NS + 0

    Generate conditional

    A generate block allows conditionally instantiated using if-else-if construct and case keyword.

    Example: generate If-else

    In the below example, based on parameter sel full adder or half-adder design is instantiated. By default, parameter sel = 0 means half adder will be instantiated. But from the testbench code, parameter sel = 1 is passed to instantiate full adder. $display can not be used within generate block without initial block, otherwise, it throws an error '$display' is an invalid generate scope construct.

    module half_adder(
      input a, b,
      output sum, cout
    );
      
      assign {sum, cout} = {a^b, (a & b)};
      //or
      //assign sum = a^b;
      //assign cout = a & b;
    endmodule
    
    module full_adder(
      input a, b, cin,
      output sum, cout
    );
      
      assign {sum, cout} = {a^b^cin, ((a & b) | (b & cin) | (a & cin))};
      //or
      //assign sum = a^b^cin;
      //assign cout = (a & b) | (b & cin) | (a & cin);
    endmodule
    
    module gen_if_ex #(parameter sel = 0)(
      input A, B, Cin,
      output S, Cout);
       
      generate
        if(sel) begin
          initial $display("Full Adder is selected");
          full_adder fa(A, B, Cin, S, Cout);
        end
        else begin
          initial $display("Half Adder is selected");
          half_adder ha(A, B, S, Cout);
        end
      endgenerate
    endmodule
    

    Output:

    Full Adder is selected
    A = 0: B = 1, Cin = 1 --> S = 0, Cout = 1
    A = 1: B = 1, Cin = 1 --> S = 1, Cout = 1
    A = 1: B = 0, Cin = 1 --> S = 0, Cout = 1
    xmsim: *W,RNQUIE: Simulation is complete.

    Example: generate case

    Similarly, the above example if-else generate block can alternatively use case statement as specified in the below example.

    module half_adder(
      input a, b,
      output sum, cout
    );
      
      assign {sum, cout} = {a^b, (a & b)};
      //or
      //assign sum = a^b;
      //assign cout = a & b;
    endmodule
    
    module full_adder(
      input a, b, cin,
      output sum, cout
    );
      
      assign {sum, cout} = {a^b^cin, ((a & b) | (b & cin) | (a & cin))};
      //or
      //assign sum = a^b^cin;
      //assign cout = (a & b) | (b & cin) | (a & cin);
    endmodule
    
    module gen_if_ex #(parameter sel = 0)(
      input A, B, Cin,
      output S, Cout);
       
      generate
        case(sel)
          0: begin 
               initial $display("Full Adder is selected");
               half_adder ha(A, B, S, Cout);
             end
          1: begin 
               initial $display("Full Adder is selected");
               full_adder fa(A, B, Cin, S, Cout);
             end
        endcase
      endgenerate
    endmodule
    

    Output:

    Full Adder is selected
    A = 0: B = 1, Cin = 1 --> S = 0, Cout = 1
    A = 1: B = 1, Cin = 1 --> S = 1, Cout = 1
    A = 1: B = 0, Cin = 1 --> S = 0, Cout = 1
    xmsim: *W,RNQUIE: Simulation is complete.