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

  • Start Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
    • Testbench Anatomy & Layering
    • Stimulus: Generators, Transactions & Drivers
      • Transaction Design for Stimulus
      • Layered Constraint Architecture
      • Shaping Stimulus with Knobs and Policies
      • Protocol Legality and Error Injection
      • Randomizing Scenarios, Not Just Items
      • Generator Patterns
      • Driver Design
      • Mixing Directed and Random Stimulus
    • Monitors, Scoreboards & Reference Models
    • Self-Checking Tests & Regression
    • From Hand-Built TB to UVM
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Stimulus: Generators, Transactions & Drivers
  1. Topics
  2. SystemVerilog
  3. Testbench Architecture in SystemVerilog
  4. Stimulus: Generators, Transactions & Drivers
  5. Generator Patterns

Part 6 · Testbench Architecture · Intermediate

Generator Patterns

Blueprint generators, scenario tasks, mix controls, and stop conditions.

On this page

    The blueprint loop

    The simplest correct generator randomizes a blueprint object in a loop and puts a clone into the mailbox. Tests retarget the stream by swapping the blueprint for a derived object, with zero generator edits. This relies on clone() being virtual: a derived blueprint that adds fields overrides it, so every queued copy keeps the derived type.

    Piece

    Role

    Rule

    Blueprint

    Template transaction

    Tests may replace it with a derived type

    Clone on put

    Handle safety

    Every queued item is a fresh object

    Solve check

    Robustness

    Every call checks its return and stops loudly

    Mix knob

    Scenario share

    One dist over scenario kinds

    Scenario tasks and stop conditions

    The next listing is not run in this course's checks. It is a fragment that uses bus_txn from the transaction lesson.

    design.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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    // not-run: fragment: bus_txn is defined in the transaction-design listing, no top module
    class generator;
      mailbox #(bus_txn) out;
      int unsigned n;
      bus_txn blueprint;
      event done;
      function new(mailbox #(bus_txn) out, int unsigned n);
        this.out = out; this.n = n;
        blueprint = new();
      endfunction
      virtual task run();
        repeat (n) begin
          if (!blueprint.randomize())
            $fatal(1, "GEN: randomize failed");
          out.put(blueprint.clone());
        end
        -> done;
      endtask
    endclass
    
    class scenario_gen extends generator;
      typedef enum {SINGLE, WR_RD_BACK, BURST4} scen_e;
      rand scen_e scen;
      constraint c_mix { scen dist {SINGLE :/ 50, WR_RD_BACK :/ 30, BURST4 :/ 20}; }
      virtual task run();
        int unsigned sent = 0;
        int unsigned got = 0;
        while (sent < n) begin
          if (!this.randomize()) $fatal(1, "GEN: scen pick failed");
          case (scen)
            SINGLE: begin do_single(got); sent += got; end
            WR_RD_BACK: begin do_wr_rd_back(got); sent += got; end
            BURST4: begin do_burst4(got); sent += got; end
          endcase
        end
        -> done;
      endtask
      task automatic do_single(output int unsigned added);
        bus_txn c;
        if (!blueprint.randomize()) $fatal(1, "GEN: single failed");
        c = blueprint.clone();
        out.put(c);
        added = 1;
      endtask
      task automatic do_wr_rd_back(output int unsigned added);
        bus_txn wr, rd;
        if (!blueprint.randomize() with { kind == WRITE; })
          $fatal(1, "GEN: wr failed");
        wr = blueprint.clone();
        rd = wr.clone();
        rd.kind = READ;
        out.put(wr); out.put(rd);
        added = 2;
      endtask
      task automatic do_burst4(output int unsigned added);
        int unsigned k;
        if (!blueprint.randomize() with { kind == WRITE; addr[3:0] == 0; })
          $fatal(1, "GEN: burst failed");
        for (k = 0; k < 4; k++) begin
          bus_txn b = blueprint.clone();
          b.addr = blueprint.addr + 4 * k;
          b.gap = 0;
          out.put(b);
        end
        added = 4;
      endtask
    endclass

    Scenario helpers are tasks because mailbox put blocks, and functions cannot block. Each path checks its solve result like the baseline. Solver-side correlation across items belongs to scenario classes, covered in the previous lesson; these tasks build procedural patterns item by item.

    • Write-readback shares the address by clone-and-edit, so the pair checks something by construction.

    • Bursts force intra-scenario gap to zero while the driver still obeys the protocol.

    • Stopping uses count, coverage through $get_coverage, or an event, with a max-count safety cap.

    Common mistakes

    Common pitfall

    Putting the blueprint itself instead of a clone queues one handle many times. Every queued entry then mutates on the next solve.

    Interview

    Likely question: how does the generator know when to stop?

    Count, coverage, or event, combined with a safety cap. Coverage-driven stopping without a max-count cap spins forever on an unreachable bin.

    Check yourself Why must scenario helpers be tasks and not functions?

    They call mailbox put, which blocks. Functions cannot call tasks or block, so the helpers take task form with an output count.

    Check yourself A test needs only low addresses. What changes?

    Nothing in the generator: the test swaps in a derived blueprint with the extra constraint. That swap is the hand-rolled factory override.

    Testbench

    A deterministic mix model plus a testbench that checks the 190-item composition. The stand-in fixes the 50/30/20 split exactly; a real dist only approaches it.

    design.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
    module tb_mix;
      localparam int N_PICK = 100;
      // Scenario kind for pick slot 0..9 (a fixed 50/30/20 split), and
      // the number of items each kind puts into the mailbox.
      function automatic int kind_of(int slot);
        if (slot < 5) return 0;        // SINGLE
        else if (slot < 8) return 1;   // WR_RD_BACK
        else return 2;                 // BURST4
      endfunction
      function automatic int items_of(int kind);
        case (kind)
          0: return 1;
          1: return 2;
          default: return 4;
        endcase
      endfunction
      integer i;
      integer k;
      integer singles;
      integer pairs;
      integer bursts;
      integer sent;
      integer problems;
      initial begin
        singles = 0; pairs = 0; bursts = 0; sent = 0; problems = 0;
        for (i = 0; i < N_PICK; i = i + 1) begin
          k = kind_of(i % 10);
          sent = sent + items_of(k);
          if (k == 0) singles = singles + 1;
          else if (k == 1) pairs = pairs + 1;
          else bursts = bursts + 1;
        end
        if (singles != 50) problems = problems + 1;
        if (pairs != 30) problems = problems + 1;
        if (bursts != 20) problems = problems + 1;
        if (sent != 190) problems = problems + 1;
        if (problems == 0) $display("PASS: 190 items from 50 singles, 30 pairs, 20 bursts");
        else $fatal(1, "FAIL: found %0d composition problems", problems);
        $finish;
      end
    endmodule

    Related topics

    • Randomizing Scenarios, Not Just Items

    • Driver Design

    Previous

    172 / 259

    Next: Driver Design

    Up next

    Up nextDriver Design

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Transaction Design for Stimulus
    • Layered Constraint Architecture
    • Shaping Stimulus with Knobs and Policies