Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations57
  • Combinational Design58
  • Sequential Design61
  • FSM & Control66
  • Timing & Clocking64
  • Reset & CDC58
  • Memory & Buses94
  • Advanced RTL60
    • Parameterization and Generate Hub
      • Parameters vs localparams
      • Why parameterized RTL scales
      • Generate loops and conditionals
      • Avoid defparam overrides
      • Key takeaways
      • Common pitfalls
      • Worked Examples and Waveforms
      • Corner Cases and Stress Tests
      • Integration and Sign-off Notes
    • Top-Level Integration Hub
    • Synthesis Intent Hub
    • Style and Static Checks Hub
    • Assertions in RTL Hub
    • Formal Verification Basics Hub
    • Reusable SystemVerilog for RTL
  • Senior & Interview175
  • Glossary and Notation
Loading lesson

‹Parameterization and Generate Hub
  1. Topics
  2. RTL Design
  3. Advanced RTL
  4. Parameterization and Generate Hub
  5. Generate loops and conditionals

Part 8 · Advanced · Advanced

Generate loops and conditionals

Replicate logic with for generate and choose structure with if and case generate.

On this page

    Why this matters

    A generate condition that depends on a signal cannot work, and a count of zero elaborates nothing. Both mistakes show up late, as a missing instance or a netlist with no lane.

    After this lesson you can: choose between a generate loop, an if generate and a case generate, and explain how each differs from a procedural loop.

    For generate replicates hardware

    A for generate unrolls at elaboration time. Each iteration builds real logic under its own block name.

    Lane slicing uses it: iteration i owns bits [i*WIDTH +: WIDTH]. The block name (GEN_LANE) shows up in netlists and error messages.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // snippet: the generate body of gen_lanes (full module in the testbench below)
    genvar i;
    generate
      for (i = 0; i < LANES; i++) begin : GEN_LANE        // one named block per lane
        if (INVERT == 1) begin : G_INV                      // if-generate inside the loop
          assign stage[i*WIDTH +: WIDTH] = ~in_flat[i*WIDTH +: WIDTH];
        end else begin : G_PAS
          assign stage[i*WIDTH +: WIDTH] = in_flat[i*WIDTH +: WIDTH];
        end
      end
      if (PIPE == 1) begin : G_PIPE                         // registered output
        always_ff @(posedge clk) out_flat <= stage;
      end else begin : G_COMB                               // combinational output
        always_comb out_flat = stage;
      end
    endgenerate

    The loop builds LANES copies of a lane. Inside each copy, the INVERT flag picks one of two bodies. After the loop, PIPE picks a register or a wire for the whole output.

    If and case generate select structure

    An if generate picks between two structures with a constant condition. A case generate picks among many with a constant selector.

    Both decide at elaboration and cannot depend on a signal. A choice that depends on a signal is a mux, not a generate.

    Construct

    Decides on

    Use it for

    for generate

    A constant count

    Replicating lanes, banks, pipeline stages

    if generate

    A constant flag

    Including a register stage or a debug tap

    case generate

    A constant mode

    Selecting add versus subtract at build time

    tb_gen has two instances. u_comb with LANES 4, INVERT 0 and PIPE 0 contains GEN_LANE 0 to 3, each with a G_PAS block, and a G_COMB block. u_pipe with LANES 2, INVERT 1 and PIPE 1 contains GEN_LANE 0 and 1, each with a G_INV block, and a G_PIPE block.
    The elaborated hierarchy of the two gen_lanes instances in the testbench: each parameter set builds a different tree of named blocks, and the branches not chosen do not exist

    Read each branch as the hierarchy a simulator or netlist shows after elaboration. A path such as u_pipe.GEN_LANE[1].G_INV names one real block.

    • Same source, different trees. u_comb has four lanes and no register; u_pipe has two inverting lanes and a register.

    • Unchosen branches are gone. u_comb has no G_INV and no G_PIPE, so a probe of u_comb.G_PIPE fails to resolve.

    Common mistakes

    Common pitfall

    Driving a generate condition with a signal, or elaborating zero iterations by accident. Generate conditions must be elaboration constants; keep the count parameter strictly positive.

    Interview

    Likely question: how does a generate loop differ from a loop inside always_comb?

    • Generate builds N copies of hardware, named in the hierarchy.

    • Procedural loop describes one block that scans values; synthesis unrolls it into shared or repeated logic.

    • Rule of thumb: structure replication is generate, value computation is procedural.

    Check yourself PIPE is 0 in the lesson module. Which branch builds, and how does the output behave?

    The G_COMB branch builds and G_PIPE never exists. The output follows the input combinationally, with no clock delay.

    Check yourself MODE defaults to add, but the build subtracts. Where do you look first?

    The instantiation override at that site: MODE was set to 1 there. Generate follows the parameter it receives, not the default.

    Testbench

    Lane replication with polarity and pipeline options, an add/subtract pair, and a finite testbench over both widths. After a known pipeline capture, change inputs between rising edges: the combinational instance must respond before the next edge while the registered instance must hold, then update after NBA settlement.

    gen_lanes.sv
    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
    46
    47
    48
    49
    50
    module gen_lanes #(
      parameter int LANES = 4,
      parameter int WIDTH = 8,
      parameter int INVERT = 0,   // if-generate: per-lane polarity
      parameter int PIPE = 1      // if-generate: registered or combinational output
    ) (
      input  logic clk,
      input  logic [LANES*WIDTH-1:0] in_flat,
      output logic [LANES*WIDTH-1:0] out_flat
    );
      logic [LANES*WIDTH-1:0] stage;
      genvar i;
      generate
        for (i = 0; i < LANES; i++) begin : GEN_LANE
          if (INVERT == 1) begin : G_INV
            assign stage[i*WIDTH +: WIDTH] = ~in_flat[i*WIDTH +: WIDTH];
          end else begin : G_PAS
            assign stage[i*WIDTH +: WIDTH] = in_flat[i*WIDTH +: WIDTH];
          end
        end
        if (PIPE == 1) begin : G_PIPE
          always_ff @(posedge clk) out_flat <= stage;
        end else begin : G_COMB
          always_comb out_flat = stage;
        end
      endgenerate
    endmodule
    
    // case-generate: MODE picks the operation at elaboration time.
    module gen_op #(
      parameter int MODE = 0,   // 0 = add, 1 = subtract
      parameter int WIDTH = 8
    ) (
      input  logic [WIDTH-1:0] a, b,
      output logic [WIDTH-1:0] y
    );
      generate
        case (MODE)
          0: begin : G_ADD
            assign y = a + b;
          end
          1: begin : G_SUB
            assign y = a - b;
          end
          default: begin : G_DEF
            assign y = a + b;
          end
        endcase
      endgenerate
    endmodule
    

    Remember

    • A generate loop builds N copies of hardware, each under its own block name.

    • If and case generate pick a structure from an elaboration constant, never from a signal.

    • Keep the count parameter strictly positive.

    Rule of thumb: structure replication is generate; value computation is a procedural loop.

    How this was checked

    Testbench run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It covers both widths, and checks that the combinational instance responds before the next edge while the registered instance holds and then updates after NBA settlement. This sensitivity case is argued from the source; no replacement mutation was run. The checks are finite digital checks, not physical signoff.

    Keep going

    • Practice: Generate-for versus generate-if in a parameterised design

    • Code lab: Generate loop

    • Interview: run a mock interview on this topic

    Related topics

    • Parameters vs localparams

    • Avoid defparam overrides

    Previous

    461 / 694

    Next: Avoid defparam overrides

    Up next

    Up nextAvoid defparam overrides

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Parameters vs localparams
    • Key takeaways
    • Common pitfalls