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. constraint_mode(): Toggling Blocks

Part 3 · Constraint Randomization · Intermediate

constraint_mode(): Toggling Blocks

Named constraint blocks as test handles, error injection, and the block state model.

On this page

    Why this matters

    An error test disabled the legality rule to send one bad packet and never turned it back on. Every later sequence that shared the object sent garbage, and the log blamed the DUT.

    After this lesson you can: turn named constraint blocks off and on, inject protocol errors deliberately, and read a block's state safely.

    Blocks are control handles

    constraint_mode(0) deactivates a named block so the solver ignores every expression inside it. The deeper point is block organization: intent-grouped blocks give tests one knob per concern.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // snippet: the class from the bench below
    class eth_pkt;
      rand bit [13:0] len;
      rand bit [47:0] dst;
      rand bit        bad_fcs;
      // Grouped by intent: each block is a test-facing knob
      constraint valid_c   { len inside {[64:1500]}; bad_fcs == 0; }
      constraint short_c   { soft len < 256; }
      constraint unicast_c { dst[40] == 0; }
    endclass

    To test whether a block is on, read p.valid_c.constraint_mode() into a variable first: one of the simulators used here rejects the query written directly as an if condition.

    Name blocks for the rule they enforce, with a _c suffix. Test writers can then disable a rule without reading its expressions.

    Error injection

    The canonical use: an error test drops the legality block, then steers toward an interesting illegal corner. Bare relaxation mostly produces dull garbage rather than near-legal corners.

    design.sv
    1
    2
    3
    4
    5
    // snippet: the error-injection steps, run in the bench below
    p.valid_c.constraint_mode(0);   // 1. drop legality
    if (!p.randomize() with { len inside {[1:63]}; bad_fcs == 1; })   // 2. steer at runts
      $fatal(1, "error-injection randomize hit an empty space");
    p.valid_c.constraint_mode(1);   // 3. restore: the next sequence wants legal frames

    The inline with succeeds only because valid_c is off: with it on, the two length ranges do not overlap and randomize() returns 0. Toggling relaxes while inline tightens, and error injection needs both in that order.

    State model and scope

    • Every named block starts enabled when the object is built.

    • p.valid_c.constraint_mode(0) disables one block; (1) enables it again.

    • p.constraint_mode(0) and (1) switch every block of the object at once.

    • p.valid_c.constraint_mode() returns 1 or 0 for that one block.

    • The state is sticky: it survives every later call and every sequence that shares the object, so restore what you disable.

    Modes belong to the object instance, not the class, so two objects of one class can disagree about which blocks are active. The exception is a block declared static constraint: its mode is shared, so toggling it affects every instance (IEEE 1800 18.5.11).

    Need

    Mechanism

    Why not the other

    Relax a rule temporarily

    constraint_mode

    Inline with only intersects, so it cannot remove a rule.

    Standing relaxed policy

    Subclass override

    A toggle is per-instance state that someone must restore.

    Adjust a default distribution

    Soft constraint

    A hard block needs an explicit procedural switch.

    Freeze one field

    rand_mode

    Disabling a block frees its fields instead of pinning them.

    Testbench

    Predict first The bench turns valid_c back on and then asks for len inside {[1:63]}. What does randomize() return?

    0. With valid_c on, lengths must be 64 to 1500, so no length satisfies both rules.

    Long frames with short_c off, runt frames with bad FCS while valid_c is off, and a runt request that fails once valid_c is restored.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class eth_pkt;
      rand bit [13:0] len;
      rand bit [47:0] dst;
      rand bit        bad_fcs;
      // Grouped by intent: each block is a test-facing knob
      constraint valid_c   { len inside {[64:1500]}; bad_fcs == 0; }
      constraint short_c   { soft len < 256; }
      constraint unicast_c { dst[40] == 0; }
    endclass
    
    Terminal
    valid_c still on; 496 of 500 frames were 256 bytes or longer
    %Warning-UNSATCONSTR: /var/folders/41/dgs80y1569b4x8pwflv_w9jr0000gn/T/rtbtb-K1WcxI/t18.sv:6: Unsatisfied constraint: 'constraint valid_c   { len inside {[64:1500]}; bad_fcs == 0; }'
    %Warning-UNSATCONSTR: /var/folders/41/dgs80y1569b4x8pwflv_w9jr0000gn/T/rtbtb-K1WcxI/t18.sv:30: Unsatisfied constraint: 'on = p.randomize() with { len inside {[1:63]}; };    '
    runts with bad FCS: 100 of 100; with valid_c restored, a runt request returns 0
    PASS: short_c off allowed long frames, valid_c off allowed runts, and restoring valid_c forbade them again

    Common mistakes

    Common pitfall

    One monolithic constraint block forces tests into all-or-nothing reuse. Split blocks by intent, and note that object-level constraint_mode(1) enables every block, clobbering any custom mix.

    Interview

    Likely questions: how to inject protocol errors (disable the legality block, steer inline, restore), and why blocks are named by intent (blocks are the unit that toggling and overriding act on).

    Check yourself Can an inline with block re-enable behavior from a disabled block?

    No. Inline expressions only add constraints for one call. They neither disable nor enable blocks, so the disabled block stays silent.

    Check yourself Is a disabled block shared across objects of the class?

    No, for an ordinary block: the mode is per-instance sticky state, so other objects are untouched. The exception is a static constraint block, whose mode is shared by every instance.

    In the layer map, constraint_mode answers which constraints are active. Use it to carve off legality for error phases, never as a standing policy.

    Project step

    Write PacketFIFO's first error test: add a bad_check bit to pkt_txn and put bad_check == 0 in legal_c with the length and port rules. The test drops legal_c, produces bad lengths and bad check bytes on purpose, then restores it.

    One way to write 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
    typedef enum bit [1:0] {DATA = 2'd0, CTRL = 2'd1, ERR = 2'd2} kind_e;
    
    class pkt_txn;
      rand kind_e    kind;
      rand bit [1:0] dest;
      rand bit [3:0] len;
      rand bit       bad_check;            // 1: the driver corrupts the check byte
      constraint legal_c { len inside {[1:8]}; dest inside {[0:2]}; bad_check == 0; }
    endclass
    
    module tb_pkt_err;
      pkt_txn p = new();
      int bad_len = 0, bad_chk = 0;
      initial begin
        repeat (100) if (!p.randomize()) $fatal(1, "FAIL: legal solve failed");   // legal traffic
        // Error phase: drop legality, then steer at the two faults PacketFIFO's checker must catch.
        p.legal_c.constraint_mode(0);
        repeat (50) begin
          if (!p.randomize() with { len == 0 || len > 8; }) $fatal(1, "FAIL: bad-length solve failed");
          if (p.len == 0 || p.len > 8) bad_len++;
          if (!p.randomize() with { len inside {[1:8]}; bad_check == 1; }) $fatal(1, "FAIL: bad-check solve failed");
          if (p.bad_check) bad_chk++;
        end
        p.legal_c.constraint_mode(1);                                  // restore for the next phase
        repeat (100) begin
          if (!p.randomize()) $fatal(1, "FAIL: legal solve failed after restore");
          if (p.len == 0 || p.len > 8 || p.bad_check) $fatal(1, "FAIL: an illegal packet after restore");
        end
        $display("fault phase: %0d bad lengths, %0d bad check bytes; legal again after restore", bad_len, bad_chk);
        $display("PASS: legal_c off produced the two planned faults, and legal_c back on produced only legal packets");
        $finish;
      end
    endmodule
    Terminal
    fault phase: 50 bad lengths, 50 bad check bytes; legal again after restore
    PASS: legal_c off produced the two planned faults, and legal_c back on produced only legal packets

    Remember

    • constraint_mode(0) removes a whole named block; inline with can never remove one.

    • Error injection: drop the rule, steer with inline with, restore.

    • Modes belong to one object and stay until changed.

    Rule of thumb: every constraint_mode(0) has a matching constraint_mode(1).

    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.

    Verilator 5.048 rejects if (p.valid_c.constraint_mode()); the bench reads the query into a variable first.

    Related topics

    • Next: Inline Constraints: randomize() with

    Previous

    74 / 259

    Next: Inline Constraints: randomize() with

    Up next

    Up nextInline Constraints: randomize() with

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Constraint Override via Inheritance
    • State Variables and Cross-Object