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
    • Randomization Basics: rand, randc & randomize()
    • Constraint Operators & Expressions
    • Dynamic Constraint Control
      • rand_mode(): Freezing Fields
      • constraint_mode(): Toggling Blocks
      • Inline Constraints: randomize() with
      • Constraint Override via Inheritance
      • State Variables and Cross-Object
    • Randomizing Arrays and Queues
    • How the Constraint Solver Works
    • Debugging Randomization Failures
    • Interview Drills — Constraints and Randomization Q&A
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Dynamic Constraint Control
  1. Topics
  2. SystemVerilog
  3. Constraint Randomization — Interview-Critical Deep Dive
  4. Dynamic Constraint Control
  5. Inline Constraints: randomize() with

Part 3 · Constraint Randomization · Intermediate

Inline Constraints: randomize() with

Call-site tightening, contradiction failures, local scope resolution, and inline or subclass.

On this page

    Why this matters

    A directed address sweep produced completely random addresses. The sequence wrote addr == addr inside with, both names meant the transaction's own field, and the rule was always true.

    After this lesson you can: tighten one call with inline constraints, predict a contradiction, and bind the caller's variables with local::.

    Inline constraints only tighten

    obj.randomize() with { ... } adds expressions for one call only. The solver ANDs them with the active class blocks, so inline code can only shrink the solution space.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class bus_txn;
      rand bit [31:0] addr;
      rand bit [7:0]  len;
      constraint legal_c { len inside {[1:16]}; addr < 32'h1_0000; }
    endclass
    module tb_tighten_only;
      initial begin
        automatic bus_txn t = new();
        // Tighten: legal AND call-site, so len in [4:16], addr in [0x8000:0xFFFF]
        if (!t.randomize() with { len >= 4; addr >= 32'h8000; })
          $fatal(1, "FAIL: the tightened solve failed");
        if (t.len < 4 || t.len > 16 || t.addr < 32'h8000 || t.addr > 32'hFFFF)
          $fatal(1, "FAIL: len=%0d addr=%h outside the intersection", t.len, t.addr);
        // Contradiction: len==32 meets len in [1:16] nowhere
        if (!t.randomize() with { len == 32; })
          $display("empty intersection: no value satisfies both rules");
        else $fatal(1, "FAIL: len == 32 should contradict legal_c");
        $display("PASS: inline with only tightened the class rules");
        $finish;
      end
    endmodule
    Terminal
    %Warning-UNSATCONSTR: /var/folders/41/dgs80y1569b4x8pwflv_w9jr0000gn/T/rtbtb-K1WcxI/t20.sv:4: Unsatisfied constraint: 'constraint legal_c { len inside {[1:16]}; addr < 32'h1_0000; }'
    %Warning-UNSATCONSTR: /var/folders/41/dgs80y1569b4x8pwflv_w9jr0000gn/T/rtbtb-K1WcxI/t20.sv:15: Unsatisfied constraint: 'if (!t.randomize() with { len == 32; })'
    empty intersection: no value satisfies both rules
    PASS: inline with only tightened the class rules

    A failed randomize() returns 0 and leaves every rand field holding its prior value (IEEE 1800 18.6.3). Driving the stale object is the follow-on bug, so always check the return.

    Name lookup and local

    Names inside with resolve against the randomized object first, then the enclosing scope. A sequence variable that shadows a field therefore binds to the field on both sides.

    Predict first A sequence has its own addr = 32'h4000 and calls t.randomize() with { addr == addr; }. What value does t.addr get?

    Any legal value. Both names bind to t.addr, so the rule is t.addr == t.addr, always true. local::addr is the fix.

    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
    class bus_txn;
      rand bit [31:0] addr;
      rand bit [7:0]  len;
      constraint legal_c { len inside {[1:16]}; addr < 32'h1_0000; }
    endclass
    class my_seq;
      bit [31:0] addr;   // the sequence's own addr shadows the field
      task body(bus_txn t);
        addr = 32'h4000;
        // Bug: both names bind to t.addr, so the rule is t.addr == t.addr
        void'(t.randomize() with { addr == addr; });
        // Fix: local:: skips the object and binds the calling scope
        void'(t.randomize() with { addr == local::addr; });
        if (t.addr != 32'h4000)
          $fatal(1, "FAIL: local::addr did not bind, addr=%h", t.addr);
      endtask
    endclass
    module tb_scope;
      initial begin
        automatic my_seq s = new();
        automatic bus_txn t = new();
        s.body(t);
        $display("PASS: local::addr pinned t.addr to 4000");
        $finish;
      end
    endmodule
    Terminal
    PASS: local::addr pinned t.addr to 4000

    Written in the with block

    Binds to

    Result

    addr

    The object's own field t.addr (looked up first)

    t.addr == t.addr: always true, so addr stays fully random

    local::addr

    The calling scope's my_seq.addr, here 32'h4000

    t.addr == 32'h4000: the intended pin

    The tautology never fails, so nothing points at it. The symptom arrives late as coverage holes or scoreboard noise.

    Inline or subclass

    Inline wins for one-off call-local intent: this loop wants short lengths, this call pins one address. Reusable personalities belong in subclasses, and relaxation is impossible inline.

    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
    class bus_txn;
      rand bit [31:0] addr;
      rand bit [7:0]  len;
      constraint legal_c { len inside {[1:16]}; addr < 32'h1_0000; }
    endclass
    class short_bus_txn extends bus_txn;
      constraint short_c { len inside {[1:4]}; }   // still ANDs with legal_c
    endclass
    module tb_one_off;
      bit [31:0] targets[];   // directed sweep values, sized by the test
      initial begin
        automatic bus_txn t = new();
        targets = new[4];
        foreach (targets[i]) begin
          // Inline: a directed sweep inside one sequence
          void'(t.randomize() with { addr == local::targets[i]; len == 1; });
          if (t.addr != targets[i] || t.len != 1)
            $fatal(1, "FAIL: sweep %0d gave addr=%h len=%0d", i, t.addr, t.len);
        end
        // Inline CANNOT ask for len > 16: that contradicts legal_c,
        // so relaxation needs constraint_mode or a subclass.
        $display("PASS: 4 directed sweep calls hit their targets");
        $finish;
      end
    endmodule
    Terminal
    PASS: 4 directed sweep calls hit their targets

    Common mistakes

    Common pitfall

    Trying to relax a class constraint inline always ends in contradiction. Shadowed names are worse: addr == addr is a silent tautology that randomizes freely, so qualify call-side values with local:: whenever names overlap.

    Interview

    Likely questions: whether inline replaces class constraints (no, it ANDs), what contradiction does (returns 0, fields keep prior values, soft constraints excepted), and what local:: is for (binding the calling scope past a shadowed field).

    Check yourself Do inline constraints replace class constraints?

    No. They intersect with every active class constraint for exactly one call. The space can only shrink, apart from hard inline expressions displacing class-level soft constraints.

    Check yourself An inline rule contradicts the class block. What does randomize() do?

    It returns 0 and leaves all rand fields at their prior values. Treat the 0 as a coding fault, not a retry, or the bench will drive a stale transaction.

    In the layer map, inline with answers what extra rules apply to one call. Use it for call-local intent, never for relaxation or reusable policy.

    Remember

    • Inline rules are ANDed with the class rules: they can only shrink the space.

    • A contradiction returns 0 and leaves every field unchanged.

    • Inside with, names find the object first; local:: reaches the caller.

    Rule of thumb: when a name exists on both sides, write local::.

    How this was checked

    Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown. Verilator prints a harmless WIDTHTRUNC warning for if (!obj.randomize()), because randomize() returns an int, and an UNSATCONSTR warning when a solve fails on purpose. Icarus 13 does not support constraints.

    Related topics

    • Next: Constraint Override via Inheritance

    Previous

    75 / 259

    Next: Constraint Override via Inheritance

    Up next

    Up nextConstraint Override via Inheritance

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • rand_mode(): Freezing Fields
    • State Variables and Cross-Object