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
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.
Suppose that we wanted to construct a shift register, like the one shown below.
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.
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 = count ; // 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 <= p ; preg <= p ; preg <= p ; preg <= p ; preg <= p ; preg <= p ; preg <= p ; end assign p[7:1] = preg[7:1]; // assign the p wire the value of the p register assign q = p; // output the MSB of the shift register endmodule
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 = count ; // 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 ; // output the MSB of the shift register endmodule