Generate blocks

V. Hunter Adams (vha3@cornell.edu)

Introduction

Generate blocks are a mechanism by which we can generate lots of Verilog. To quote the Sutherland HDL guide, "generate blocks provide control over the creation of many types of module items. A generate block must be defined within a module, and is used to generate code within that module."

Within these generate blocks, you can do things like declare variables, instantiate modules, wire modules together, etc. And furthermore, you can do these things conditionally. Usually, the conditions within a generate block will depend on the value of one or a number of genvars.

A genvar is "an integer variable which must be a positive value. They may only be used within a generate block. Genvar variables only have a value during elaboration, and do not exist during simulation. Genvar variables must be declared within the module where the genvar is used. They may be declared either inside or outside of a generate block." (Evans and Sutherland HDL guide).

Because generate blocks are only evaluated at elaboration, any conditionals within a generate block must have arguments which are constant expressions. Recall that the generate blocks are being used to build hardware. It therefore must be the case that all conditionals are evaluatable at compile time. If not, that would suggest we were building hardware at runtime, which doesn't make sense.

Video discussion of the content on this page





Example

Suppose that we wanted to construct a shift register, like the one shown below.

missing

We'll consider two ways of doing this. One using a generate block, and the other without using a generate block. Hopefully, by doing so, the utility of the generate block will be clear.

A shift register without using a generate block

Let us first construct this circuit without using a generate block.

Please note that I have implemented this shift register such that we can replace a section with the generate block. In practice, you may implement this a bit more concisely. This is optimized instead for clarity. The output of this module will be 8 0's, then 8 1's, then 8 0's, etc.

module shift (input  wire clock,     // clock input
              output wire q) ;       // output of shift register

    wire [7:0] p ;                   // the wire through which we will shift

    reg [3:0] count = 4'd_0 ;        // a register which will contain an incrementing value
    always @ (posedge clock) begin   // the always block which increments that value
        count <= (count + 4'd_1) ;
    end

    assign p[0] = count[3] ;         // assign the first bit of p the MSB of count 

    reg [7:0] preg ;                 // the shift register

    always @ (posedge clock) begin   // repetitive logic which implements the shift register
        preg[1] <= p[0] ;
        preg[2] <= p[1] ;
        preg[3] <= p[2] ;
        preg[4] <= p[3] ;
        preg[5] <= p[4] ;
        preg[6] <= p[5] ;
        preg[7] <= p[6] ;
    end

    assign p[7:1] = preg[7:1];        // assign the p wire the value of the p register

    assign q = p[7];                  // output the MSB of the shift register
endmodule

A shift register using a generate block

Instead of building all of the repetitive logic above, we could instead use a generate block. We would do so by creating a separate flip-flop module. This is the logic which we will use the generate block to create many copies of.

module dflop(input wire clock,      // clock input
             input wire d,          // data input (1 bit wide)
             output wire q) ;       // data output (1 bit wide)

    reg out ;                       // register that will contain the data for output
    always @ (posedge clock) begin  // at each rising clock edge, out gets the value of the input data
        out <= d ;
    end

    assign q = out ;                // the output is assigned the value of out
endmodule

We can then use a generate block to instantiate and connect a bunch of copies of this module.

module shift (input wire clock,                // clock input
              output wire q) ;                 // output of shift register

    wire [7:0] wire p ;                        // the wire through which we will shift

    reg [3:0] count = 4'd_0 ;                  // a register which will contain an incrementing value
    always @ (posedge clock) begin             // the always block which increments that value
        count <= (count + 4'd_1) ;
    end

    assign p[0] = count[3] ;                   // assign the first bit of p the MSB of count

    // The generate block below replaces the repetitive logic from above

    generate                                   // indicate start of generate block
        genvar n;                              // instantiate a genvar called n
        for (n=0; n<=6; n=n+1) begin: flopGen  // a for loop which increments n from 0 to 6 (named)
            dflop u(.clock(clock),             // each time, instantiate a dflop module, connect to p
                    .d(p[n]),
                    .q(p[n+1]));
        end
    endgenerate

    assign q = p[7] ;                          // output the MSB of the shift register
endmodule