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

  • How to Use This Course
  • Reading Paths
  • Quick Start: Your First Green Build
  • Part 1: How Chips Get Made6
  • Part 2: Your Workstation5
  • Part 3: Specify and Architect3
  • Part 4: The Design Loop6
  • Part 5: The Verification Ladder6
    • Tests That Can Fail
    • Self-Checking and Golden Model
    • Random Stimulus and Seeds
    • Assertions
    • Coverage
    • Formal in One Lesson
  • Part 6: Automation and Reproducibility5
  • Part 7: Hand-Off to the Back-End3
  • Part 8: When Things Go Wrong3
  • Part 9: Project and Next Steps3
  • Reference4
Loading lesson

‹Part 5: The Verification Ladder
  1. Topics
  2. Start Here: RTL and Verification
  3. Part 5: The Verification Ladder
  4. Random Stimulus and Seeds

Part 5 · The Verification Ladder · Working (W)

Random Stimulus and Seeds

Directed steps cover the cases you imagined. Random stimulus from a seed covers the rest, and the seed makes every run replayable, including the failures.

On this page

    Note

    Level: Working (W) · Answers: How do you test the cases you did not think of, and how do you reproduce a failure that came from chance?

    Before this: Self-Checking and Golden Model

    How do you test the cases you did not think of, and how do you reproduce a failure that came from chance?

    Every directed step in the last lesson covers a case somebody imagined. The bugs that survive directed testing live in the cases nobody imagined, and nobody imagines 400 cycles of inputs by hand. Random stimulus drives those cycles for you, and a seed makes the randomness replayable: the same seed always gives the same run, so a failure that came from chance can be reproduced exactly.

    A seed is chance you can replay

    The testbench draws its inputs from a pseudo-random number generator (PRNG): a deterministic sequence of numbers that starts from a chosen starting value. That starting value is the seed. The simulator's $random updates its working copy in place, so reseeding with the same number replays the identical sequence of inputs, cycle for cycle.

    A failing seed is therefore a reproducer, not a rumor. Seed 7 with 60 cycles fails at cycle 43 on the saturating design, and it fails there every time it is replayed through unchanged code. Debugging starts from the seed, not from a description of what the waveform looked like once.

    The seed comes as the first line of output, before anything else. Keep that number in the log, including the continuous integration (CI) log, which is the automatic test run that checks every shared change. A random run whose seed was never recorded cannot be replayed, and a failure that cannot be replayed cannot be fixed with confidence.

    Rare inputs need rare weights

    Uniform random stimulus would reset the counter about every other cycle, and the count would never climb anywhere near 15. The wrap from 15 to 0, the deepest behavior in the spec, needs a long undisturbed climb, so the testbench weights its dice: reset and clear each land about 1 cycle in 32, while a valid event lands about every other cycle. Those odds let the count climb high enough to wrap, yet still visit reset and clear regularly.

    Weights come from the shape of the design, not from habit. A deeper counter would need even rarer resets to reach its wrap, and a design with no deep states would need none of this. When random testing misses a corner, the first question is whether the weights ever let the run reach that corner at all.

    One seed in, one run out

    The figure below shows the whole idea in two rows. In the top row the same seed enters the generator twice and the same stimulus and the same failure come out both times. In the bottom row a different seed gives a different stimulus and a different result. Look at the arrows: replaying means feeding the identical seed through identical code.

    Seed in, run out: the same seed replayed gives the same 60-cycle stimulus and the same failure at cycle 43, while seed 13 gives a different stimulus that fails at cycle 25.

    Four hundred cycles from one number

    mini_controller.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    `timescale 1ns/1ps
    // Counts accepted events, 4 bits, wraps 15 -> 0.
    // Priority: reset > clear > count > hold. Reset is synchronous, active low.
    module mini_controller (
        input  logic       clk,
        input  logic       rst_n,
        input  logic       event_valid,
        input  logic       clear_count,
        output logic [3:0] count
    );
        always_ff @(posedge clk) begin
            if (!rst_n)
                count <= 4'd0;
            else if (clear_count)
                count <= 4'd0;
            else if (event_valid)
                count <= count + 4'd1;
        end
    endmodule
    
    `timescale 1ns/1ps

    This listing is the random testbench next to the design it checks: the same spec model as the strong test, a cycle task with the same before-edge and after-edge checks, and stimulus drawn from $random with weights that let the count climb.

    Diagram
    # captured terminal output
    $ iverilog -g2012 -s tb_random -o build/ok.vvp rtl/mini_controller.sv tb/tb_random.sv && vvp build/ok.vvp +seed=1 | grep -E '^(seed|PASS)'
    seed=1
    PASS: seed=1, 401 cycles

    This output was measured on macOS, Icarus Verilog 13.0. The seed comes first so every log entry carries its own reproducer, and the last line is the verdict: one reset edge plus 400 random cycles, all matching the model. Unlike the strong testbench, this one stops at the first mismatch, because the seed replays the exact run and the failure will still be there on the second look.

    Predict first Fourteen seeds, sixty cycles each, run against the mutant that sticks at 15 instead of wrapping. How many seeds catch it: all fourteen, none, or only some?

    Only some. Most 60-cycle runs never climb from 0 to 15 without a reset or clear landing first, so the missing wrap never meets exposing stimulus. A single passing seed means that walk got lucky, not that the design wraps.

    Most passing seeds prove nothing

    The sweep below runs the first fourteen seeds against the saturating mutant, and it confirms the prediction above. Read the middle column first: eleven seeds pass on broken code.

    Diagram
    # captured terminal output
    $ iverilog -g2012 -s tb_random -o build/bug.vvp saturates.sv tb/tb_random.sv && for s in 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do printf 'seed %-3s ' $s; vvp build/bug.vvp +seed=$s +cycles=60 | grep -E '^(PASS|FATAL)' | cut -c1-100; done
    seed 1   PASS: seed=1, 61 cycles
    seed 2   PASS: seed=2, 61 cycles
    seed 3   PASS: seed=3, 61 cycles
    seed 4   PASS: seed=4, 61 cycles
    seed 5   PASS: seed=5, 61 cycles
    seed 6   PASS: seed=6, 61 cycles
    seed 7   FATAL: tb/tb_random.sv:41: FAIL: seed=7 cycle=43: rst_n=1 clear=0 valid=1 expected 0 got 15
    seed 8   PASS: seed=8, 61 cycles
    seed 9   PASS: seed=9, 61 cycles
    seed 10  PASS: seed=10, 61 cycles
    seed 11  PASS: seed=11, 61 cycles
    seed 12  PASS: seed=12, 61 cycles
    seed 13  FATAL: tb/tb_random.sv:41: FAIL: seed=13 cycle=25: rst_n=1 clear=0 valid=1 expected 0 got 15
    seed 14  FATAL: tb/tb_random.sv:41: FAIL: seed=14 cycle=41: rst_n=1 clear=0 valid=1 expected 0 got 15

    Only seeds 7, 13 and 14 catch the bug, measured on macOS, Icarus Verilog 13.0. Eleven green seeds on a broken design are the lesson of this page in one table: run many seeds, keep every seed in the log, and prefer longer runs, because a longer climb reaches the wrap more often.

    Replay the failure, then fix the design

    A failing seed earns its keep when it replays bit-identically. The two runs below use the same seed against the same mutant, and every character matches including the cycle number.

    Diagram
    # captured terminal output
    $ vvp build/bug.vvp +seed=7 +cycles=60 | grep -E '^(seed|FATAL)'; vvp build/bug.vvp +seed=7 +cycles=60 | grep -E '^(seed|FATAL)'
    seed=7
    FATAL: tb/tb_random.sv:41: FAIL: seed=7 cycle=43: rst_n=1 clear=0 valid=1 expected 0 got 15
    seed=7
    FATAL: tb/tb_random.sv:41: FAIL: seed=7 cycle=43: rst_n=1 clear=0 valid=1 expected 0 got 15

    Repeat the experiment yourself on the saturating mutant, then put the design back:

    1. Copy mutants/saturates.sv over rtl/mini_controller.sv, keeping a copy of the original elsewhere.

    2. Run the fourteen-seed sweep and confirm that only seeds 7, 13 and 14 report the wrap failure.

    3. Replay +seed=7 +cycles=60 twice and confirm the identical failure at cycle 43 on both runs.

    4. Restore the original design file and run seed 1 once more to confirm the run is green before you continue.

    A reproducer is four things, not one

    A seed alone does not replay a failure. The same seed on a different design revision, a different testbench, or a different simulator version can take a different path. When you report or save a failing run, write down all four: the seed, the source revision (the Git commit that holds the design and the testbench), the tool versions (the record from the versions file), and the exact command line. Together they let anyone else, or you next month, replay the failure.

    Diagram
    # a complete reproducer, as a template (values differ per run)
    seed       : 7
    cycles     : 60
    revision   : <output of: git rev-parse --short HEAD>
    tools      : Icarus Verilog 13.0 (from tools/versions.md)
    command    : vvp build/bug.vvp +seed=7 +cycles=60

    Put that block in the bug report or in the commit message of the fix, so the failing seed becomes a permanent regression test.

    Three ways random testing wastes your time

    • A run that never records its seed. A failure without its seed is a story, not a reproducer. Record the seed first, keep it in every log, and treat a seedless random run as a run that never happened.

    • Replaying an old seed through a changed testbench. The seed only replays through identical code: editing the testbench changes the stimulus the same seed produces. After any testbench edit, old failing seeds are history and the sweep starts over.

    • Expecting random to hit rare corners quickly. Short or wrongly weighted runs never reach deep states like the wrap, and each green seed then proves only its own walk. Match the weights to the depth of the design, run many seeds, and make runs long enough to climb.

    Rule: no seed in the log means the run never happened.

    Check yourself Replay the failing run from this lesson.

    Build the mutant simulation and run it with +seed=7 +cycles=60: the run reports the identical failure at cycle 43, counting with the counter at 15 and expecting the wrap to 0. Any replay of seed 7 through unchanged code gives the same line, which is what makes the seed a reproducer.

    Check yourself What goes wrong if reset is as likely as counting, about 1 cycle in 2?

    The count rarely climbs past a few before a reset returns it to 0, so the wrap at 15 is almost never reached and the saturating mutant survives sweep after sweep. The weights must fit the depth of the design, or random stimulus exercises only the shallow states.

    Check yourself Seed 1 passes on the good design. What have you proven?

    That one 401-cycle walk matched the model, and nothing more. Other walks may still fail, as the sweep against the mutant shows. One green seed is a start; confidence comes from many seeds, longer runs, and the directed steps beside them.

    Interview

    Asked: "A random test failed once in CI. How do you debug it?"

    Weak answer: Rerun the test until it fails again, then look at the waveform around the failure.

    Strong answer: Take the seed and the cycle count from the CI log and rerun that exact combination locally, which replays the identical failure instead of hoping it appears again. Debug from the replayed run, fix the design or the testbench, then keep the seed as a regression so that exact walk stays green. If the seed no longer replays, the testbench changed since the failure and the sweep must be re-established.

    Follow-ups: (1) The seed replays on your machine but passed in CI. What differs? (2) How many seeds are enough for this design?

    Key takeaways

    • Random stimulus covers the cases you did not think to write, and the seed makes every run replayable.

    • Weight rare inputs so the design can reach deep states; uniform random rarely climbs to the wrap.

    • One green seed proves little: run many seeds, keep each seed in the log, and prefer longer runs.

    Keep going

    Next: Lesson 5.4, Assertions. Random stimulus still checks values against a model. The next lesson states each spec row as a rule the simulator checks on every cycle of every test.

    Related topics

    • SystemVerilog course

    • Lesson 5.2, Self-Checking and Golden Model

    Previous

    26 / 47

    Next: Assertions

    Up next

    Up nextAssertions

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Tests That Can Fail
    • Coverage
    • Formal in One Lesson