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
  • Concept Map
  • Meet DCRouter
  • Glossary
  • Part 0: What Verification Is8
  • Part 1: What Can Go Wrong11
  • Part 2: Specifications as Checkable Rules8
  • Part 3: Observability and Controllability7
  • Part 4: Stimulus11
    • Directed Tests
    • Why Random Works
    • Constrained Random
    • Distributions and Bias
    • The Long Tail
    • Scenarios and Layered Stimulus
    • Error Injection
    • Timing and Back-Pressure
    • Seeds and Regressions
    • Hunting the Zoo with Random
    • Drills: Stimulus
  • Part 5: Checking11
  • Part 6: Coverage10
  • Part 7: Formal and Simulation10
  • Part 8: Verification Levels and Reuse8
  • Part 9: Planning and Risk9
  • Part 10: Emulation and Prototyping8
  • Part 11: Post-Silicon Validation8
  • Part 12: Bug Economics8
  • Part 13: Debug7
  • Part 14: Sign-Off7
  • Part 15: Verification in Context8
  • Part 16: Case Studies5
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 4: Stimulus
  1. Topics
  2. First Principles of Verification Strategy
  3. Part 4: Stimulus
  4. Constrained Random

Part 4 · Stimulus · Working (W)

Constrained Random

Pure random stimulus is mostly illegal input, which tests the design's reaction to impossible traffic instead of its function. Constraints put the randomness inside the legal space, and are best read as a model of what the design's real neighbours may do. A runnable DCRouter packet class with legality, modes, shaping and inline constraints, and the two ways constraints go wrong.

On this page

    Note

    Level: Working (W) · Answers: How do we drive the design into the states that matter?

    Before this: Why Random Works

    Drive DCRouter with fully random bits on every input and almost nothing useful happens. One header in sixteen has length 0, which is an error case; the tail's CRC is random, so 255 packets in 256 have a bad CRC; valid toggles at random in the middle of packets. The router spends the whole test reporting errors, and its normal forwarding logic, the part that carries real traffic, is barely exercised.

    How do you keep the benefits of random stimulus without drowning in illegal input?

    The obvious answer, and why it breaks

    The obvious fix is to write a generator that builds legal packets by hand: pick a length from 1 to 15, compute the CRC, and so on. That works until the rules multiply: error modes, priorities tied to destinations, lengths limited in some configurations, a test that needs only port 2. Hand-written generators become tangles of special cases, and each new test needs a new generator. Constraints separate what is legal from how values are picked.

    The idea: constraints are a model of the environment

    SystemVerilog lets a class declare rand fields and constraints; randomize() picks values that satisfy every constraint (fact V1). The constraints are best written and reviewed as a model of the environment: what the design's real neighbours may legally send, in each mode.

    Kind of constraint

    Models

    DCRouter example

    Legality

    What a correct source can send

    In normal mode, length 1 to 15 and a good CRC

    Mode

    Deliberately illegal input, switched on for error tests

    In fault mode, length 0 and bad CRCs are allowed

    Relations between fields

    Rules that tie fields together

    At most one fault per packet

    Shape

    How often each legal value appears

    Boundary lengths 1 and 15 weighted up

    Inline (with)

    A test's focus, on top of the model

    Only destination 2, high priority

    Build it: a DCRouter packet class

    The class below generates 2,000 packets in each mode and checks every constraint on every packet, then pins two fields with an inline constraint. Two details of SystemVerilog matter here (fact V6): in a dist, := gives a weight to each value of a range while :/ shares the weight across the range; and the shape is written separately for each mode so that no weighted bucket conflicts with a hard constraint.

    tb.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
    // Lesson 4.3: constraints as a model of the environment. A packet's fields are random, but
    // only inside what a legal source can send: in normal mode every length is 1-15 and the CRC is
    // good; fault mode (for error injection) also allows length 0 and makes 20% of the other
    // packets carry a bad CRC. The length is shaped toward the boundaries with dist. An inline `with` pins a field for one test.
    // 2,000 packets per mode are generated and every constraint is checked on every packet.
    module tb;
      class packet;
        rand bit [1:0] dst;
        rand bit       prio;
        rand bit [3:0] len;
        rand bit       bad;
        bit            err_mode = 0;
        constraint legal { !err_mode -> (len != 0 && !bad); }
        constraint one   { len == 0 -> !bad; }                       // one fault per packet
        constraint shape {                                           // := weight per value, :/ shared by a range
          if (err_mode) len dist {0 := 3, 1 := 20, [2:14] :/ 57, 15 := 20};
          else          len dist {1 := 20, [2:14] :/ 60, 15 := 20};
        }
        constraint fault { err_mode && len != 0 -> bad dist {0 := 80, 1 := 20}; }
      endclass
    
      initial begin
        packet p = new();
        int len_hist [16], n_bad, n_len0, n_dst2, errors;
        errors = 0;
        for (int mode = 0; mode < 2; mode++) begin
          p.err_mode = mode;
          len_hist = '{default: 0}; n_bad = 0; n_len0 = 0;
          for (int k = 0; k < 2000; k++) begin
            if (!p.randomize()) errors++;
            len_hist[p.len]++;
            n_bad += p.bad; n_len0 += (p.len == 0);
            if (!mode && (p.len == 0 || p.bad)) errors++;            // illegal in normal mode
            if (p.len == 0 && p.bad) errors++;                       // two faults in one packet
          end
          $display("%s mode: len 0: %0d  len 1: %0d  len 2-14: %0d  len 15: %0d  bad CRC: %0d",
                   mode ? "fault " : "normal", n_len0, len_hist[1], 2000 - n_len0 - len_hist[1] - len_hist[15], len_hist[15], n_bad);
        end
        p.err_mode = 0;
        n_dst2 = 0;
        for (int k = 0; k < 500; k++) begin
          if (!p.randomize() with { dst == 2; prio == 1; }) errors++;
          n_dst2 += (p.dst == 2 && p.prio == 1);
        end
        $display("inline constraint dst == 2, prio == 1: %0d of 500 packets", n_dst2);
        if (errors == 0 && n_dst2 == 500)
          $display("PASS: every packet obeyed its mode's constraints; dist shaped the lengths; the inline constraint held 500 times");
        else $display("FAIL: %0d constraint violations", errors);
        $finish;
      end
    endmodule

    It prints (Verilator):

    Diagram
    normal mode: len 0: 0  len 1: 401  len 2-14: 1186  len 15: 413  bad CRC: 0
    fault  mode: len 0: 56  len 1: 403  len 2-14: 1140  len 15: 401  bad CRC: 398
    inline constraint dst == 2, prio == 1: 500 of 500 packets
    PASS: every packet obeyed its mode's constraints; dist shaped the lengths; the inline constraint held 500 times

    How to read it: in normal mode no packet has length 0 or a bad CRC, and lengths 1 and 15 each appear about 20% of the time, as their weights of 20 out of 100 ask. In fault mode about 3% of packets have length 0 (56 of 2,000) and about 20% of the rest carry a bad CRC (398 of 1,944), and no packet has both faults. The inline constraint held on all 500 packets without changing the class.

    Two ways constraints go wrong

    Failure

    What happens

    Example

    Over-constrained

    Legal behaviour the real environment can produce is never generated, so its bugs are never reached

    Sending each input's packets in runs to one destination (a "realistic" stream) hides BUG_24, which needs back-to-back packets to different outputs

    Under-constrained

    Illegal input floods the test, producing false failures or burying function under error handling

    Unconstrained CRCs make almost every packet an error

    • Review constraints against the specification of the neighbours, not against the design: constraints describe what may arrive, not what the design handles well.

    • Keep illegal input as an explicit mode: error injection is a test of its own (lesson 4.7), not leakage from loose constraints.

    • Cover what the constraints produce (Part 6): a constraint that silently excludes a legal case shows as a coverage hole.

    How real teams use constraints

    Practice

    Purpose

    Base transaction classes with legality constraints

    Every test starts from a correct model of the environment

    Tests extend or add inline constraints

    Focus without rewriting the generator

    Error modes as switchable constraint sets

    Illegal input on purpose, never by accident

    Constraint reviews with the owners of neighbouring blocks

    The model matches what neighbours really send

    What breaks

    A team (illustrative) constrained their bus transactions so that a new request never targeted the address of an outstanding one, because that case "never happens in our system". A later system did it constantly. The read-after-write hazard logic for overlapping addresses had never been exercised, and its bug was found in the lab. The constraint described one neighbour's habit, not the interface's rules.

    Why this matters

    Senior lens. Read every constraint as a claim about the environment and ask who guarantees it. If the interface specification guarantees it, keep it; if it is one neighbour's habit, drop it or make it a mode. Over-constraint is the quiet failure: nothing breaks, the bugs simply live in the inputs the generator will never produce.

    Interview

    Asked: "Why constrain random stimulus?"

    Weak answer: To make the tests pass.

    Strong answer: To keep the randomness inside the legal input space, so the test exercises the design's function instead of its reaction to impossible traffic. I treat constraints as a model of the environment: legality from the interface spec, explicit modes for deliberate errors, relations between fields, and shaping toward boundaries; tests add inline constraints for focus. The two failure modes are under-constraining, which floods the test with illegal input, and over-constraining, which silently excludes legal cases where bugs live, so I review constraints against the neighbours' spec and cover what they generate.

    Follow-ups: (1) What is the difference between := and :/ in dist? (2) How would you notice an over-constrained generator?

    Check yourself A dist constraint reads len dist {1 := 20, [2:14] := 60, 15 := 20}. What fraction of packets get length 1?

    20 / (20 + 13·60 + 20) = 20/820, about 2.4%: := gives weight 60 to each of the 13 middle values. Writing [2:14] :/ 60 gives the intended 20%.

    Check yourself Why is "consecutive packets from one input go to the same destination" a dangerous constraint for DCRouter?

    It is not an interface rule, and it removes back-to-back packets to different outputs, the exact case where BUG_24 (reusing the previous destination) shows.

    Key takeaways

    • Constraints keep random stimulus inside the legal space; write them as a model of the environment.

    • Separate legality, error modes, field relations, shape and per-test inline constraints.

    • Over-constraining hides legal cases; under-constraining floods the test; review constraints against the neighbours' specification.

    Keep going

    Next: Lesson 4.4, Distributions and Bias. Shaping distributions toward corners without losing breadth.

    Related topics

    • Part 4 overview: Stimulus

    • SystemVerilog course: Randomization

    Previous

    42 / 160

    Next: Distributions and Bias

    Up next

    Up nextDistributions and Bias

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Directed Tests
    • The Long Tail
    • Scenarios and Layered Stimulus