Skip to content

SystemVerilog · Module 10

Constraint Modes — constraint_mode()

Per-object, per-block enable bitmap; surgical block-level disable vs whole-object disable; save/restore discipline; inheritance-aware access; TLM-port leak gotchas.

Module 10 · Page 10.6

What constraint_mode() Does

Every named constraint block in a class has a runtime mode flag — either ON (1) or OFF (0). All constraints start ON by default. constraint_mode() lets you flip this flag for a specific constraint, or for all constraints on an object at once, without changing the class source code.

A constraint that is OFF is completely invisible to the solver — as if it were never written. The moment you turn it back ON, it participates in every subsequent randomize() call on that object.

SystemVerilog — constraint_mode() syntax overview
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class Packet;
    rand bit [7:0]  src;
    rand bit [15:0] len;
 
    constraint no_broadcast  { src != 8'hFF; }
    constraint valid_length  { len inside {[64:1518]}; }
endclass
 
Packet p = new();
 
// ── Turn OFF one constraint ────────────────────────────────────
p.no_broadcast.constraint_mode(0);    // src is now free (0–255)
assert(p.randomize());                   // only valid_length active
 
// ── Turn it back ON ───────────────────────────────────────────
p.no_broadcast.constraint_mode(1);    // src excluded from 0xFF again
assert(p.randomize());
 
// ── Turn OFF ALL constraints on the object ────────────────────
p.constraint_mode(0);                  // every block is OFF
assert(p.randomize());                   // fully unconstrained
 
// ── Turn ALL constraints back ON ──────────────────────────────
p.constraint_mode(1);                  // all blocks ON again

Querying the Current Mode

Called with no argument, constraint_mode() returns the current mode as an int: 1 if ON, 0 if OFF. Use this to write conditional logic or to save and restore state around a test sequence.

SystemVerilog — querying and saving constraint mode
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Packet p = new();
 
// ── Query a single constraint's mode ──────────────────────────
int mode = p.no_broadcast.constraint_mode();
$display("no_broadcast is %s", mode ? "ON" : "OFF");
 
// ── Save, modify, restore pattern ────────────────────────────
int saved = p.valid_length.constraint_mode();  // save current state
 
p.valid_length.constraint_mode(0);             // disable temporarily
assert(p.randomize() with { len > 1518; });    // test oversized packet
 
p.valid_length.constraint_mode(saved);         // restore to original state

Object-Level constraint_mode()

Calling constraint_mode() on the object handle (not on a specific constraint) operates on every constraint block in the class and all parent classes in one call. It is the fastest way to strip all restrictions off an object for an unconstrained stress test or to restore them all afterwards.

SystemVerilog — object-level constraint_mode()
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class BusTxn;
    rand bit [31:0] addr;
    rand bit         write;
    rand bit [2:0]  burst;
 
    constraint aligned    { addr[1:0] == 2'b00; }
    constraint in_range   { addr inside {[32'h4000_0000:32'h4FFF_FFFF]}; }
    constraint max_burst  { burst <= 3'h4; }
endclass
 
BusTxn t = new();
 
// Phase 1 — normal constrained traffic
repeat (50) begin assert(t.randomize()); end
 
// Phase 2 — turn off EVERYTHING for raw stress test
t.constraint_mode(0);
repeat (50) begin assert(t.randomize()); end  // any addr, any burst
 
// Phase 3 — restore all, resume constrained traffic
t.constraint_mode(1);
repeat (50) begin assert(t.randomize()); end

constraint_mode() Across Inheritance

A derived class object carries constraint blocks from both the parent and the child. constraint_mode() at the object level affects all of them. Per-constraint calls can target both parent and child constraints by name — through the same handle.

SystemVerilog — constraint_mode() with inherited constraints
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class Base;
    rand bit [7:0] x;
    constraint base_limit { x < 128; }     // parent constraint
endclass
 
class Derived extends Base;
    rand bit [7:0] y;
    constraint child_limit { y > 10; }     // child constraint
endclass
 
Derived d = new();
 
// Disable only the parent's constraint through the derived handle
d.base_limit.constraint_mode(0);       // x is now free (0–255)
assert(d.randomize());                   // child_limit still active
 
// Object-level call disables both base_limit AND child_limit
d.constraint_mode(0);
assert(d.randomize());                   // x and y fully unconstrained
 
// Restore all
d.constraint_mode(1);

Combining OFF Constraints With the with Clause

Turning a class constraint OFF does not prevent you from adding an inline with constraint that covers the same field. This pattern is extremely useful: disable the class's version of a rule, then provide a tighter or looser version inline for one call.

SystemVerilog — disable class constraint, add inline replacement
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Packet p = new();
 
// Normal class constraint: valid_length forces len in 64–1518
// Test goal: generate an oversized packet (len > 1518)
 
// Step 1 — lift the class restriction
p.valid_length.constraint_mode(0);
 
// Step 2 — provide the test-specific range inline
assert(p.randomize() with { len inside {[1519:9000]}; });
 
// Step 3 — restore for subsequent calls
p.valid_length.constraint_mode(1);
assert(p.randomize());  // back to 64–1518

Practical Patterns

Pattern 1 — Multi-phase test with escalating freedom

SystemVerilog — three-phase test structure
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
BusTxn t = new();
 
// Phase 1 — fully constrained normal traffic
repeat (100) begin assert(t.randomize()); drive(t); end
 
// Phase 2 — relax alignment only (out-of-alignment accesses)
t.aligned.constraint_mode(0);
repeat (20) begin assert(t.randomize()); drive(t); end
t.aligned.constraint_mode(1);
 
// Phase 3 — relax range (out-of-region accesses, expect error responses)
t.in_range.constraint_mode(0);
repeat (20) begin assert(t.randomize()); drive(t); end
t.in_range.constraint_mode(1);

Pattern 2 — One base class, multiple test personalities

A single class can serve normal tests, stress tests, and error-injection tests — all from the same object — by toggling constraint modes between scenarios. No subclasses required.

SystemVerilog — configurable test personality via modes
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
typedef enum { NORMAL, STRESS, ERROR_INJECT } test_mode_e;
 
task automatic configure(BusTxn t, test_mode_e mode);
    case (mode)
        NORMAL: begin
            t.constraint_mode(1);           // all ON
        end
        STRESS: begin
            t.constraint_mode(0);           // all OFF — fully random
        end
        ERROR_INJECT: begin
            t.constraint_mode(1);           // start from all ON
            t.in_range.constraint_mode(0);  // allow out-of-range addresses
            t.aligned.constraint_mode(0);  // allow misaligned accesses
        end
    endcase
endtask

constraint_mode() vs the Alternatives

ToolWhen to use itPersists after call?
constraint_mode(0)Disable a rule for multiple consecutive callsYes — stays OFF until you turn it ON
with { } inlineOverride or narrow for exactly one callNo — discarded after the call
Child class override (same name)Permanently replace a rule for a whole test classPermanent — part of the class definition
rand_mode(0)Fix a field to its current value across callsYes — field stays non-random until re-enabled
Soft constraints (page 10.7)Hint a preference but allow the solver to override itAlways active — solver decides whether to apply

Common Pitfalls

Forgetting to restore after a test phase

If you call constraint_mode(0) in one test and never restore, the next test using the same object runs without that constraint. Always restore, or create a fresh object per test phase.

Object-level ON overwrites per-constraint state

t.constraint_mode(1) turns every constraint ON, including ones you had individually disabled. There is no "restore to previous per-constraint state" — save individual modes before calling the object-level form.

Disabling a constraint that another depends on

If constraint B uses the same field as constraint A, and A is disabled, the solver may still satisfy B with values A would have excluded. Think through the interaction before disabling.

Confusing constraint_mode with rand_mode

rand_mode(0) freezes a field's value. constraint_mode(0) removes a rule but the field is still randomised freely. They are completely independent switches.

Quick Reference

SystemVerilog — constraint_mode() cheat sheet
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── Per-constraint control ────────────────────────────────────
obj.c_name.constraint_mode(0);   // OFF — invisible to solver
obj.c_name.constraint_mode(1);   // ON  — active again
int m = obj.c_name.constraint_mode(); // query: 0=OFF, 1=ON
 
// ── Object-level control ──────────────────────────────────────
obj.constraint_mode(0);            // ALL constraints OFF (incl. inherited)
obj.constraint_mode(1);            // ALL constraints ON
 
// ── Save / restore pattern ────────────────────────────────────
int saved = obj.c_name.constraint_mode();
obj.c_name.constraint_mode(0);
// ... do special randomize calls ...
obj.c_name.constraint_mode(saved);
 
// ── Disable + replace inline ──────────────────────────────────
obj.c_name.constraint_mode(0);
assert(obj.randomize() with { /* replacement rule */ });
obj.c_name.constraint_mode(1);

Verification Usage — Where constraint_mode() Lives in Real Testbenches

Production environments use constraint_mode() in three predictable places. Outside those three, every other use is usually a refactor signal — most often "the inline with clause would be cleaner here."

Error-injection test relaxing one specific protocol rule

The canonical use: a test that deliberately drives stimulus that violates one specific protocol rule (e.g., unaligned addresses) while keeping every other rule intact. The relevant constraint block is disabled before randomize and re-enabled after.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class error_align_test extends uvm_test;
  task run_phase(uvm_phase phase);
    apb_xact tx = apb_xact::type_id::create("tx");
    int saved = tx.c_addr_align.constraint_mode();
    tx.c_addr_align.constraint_mode(0);   // off only for this scenario
 
    if (!tx.randomize() with { addr[1:0] != 2'b00; })
      `uvm_fatal("ERR", "couldn't generate unaligned addr")
    drive(tx);
 
    tx.c_addr_align.constraint_mode(saved); // restore — defensive
  endtask
endclass</code>

Sequence-level scenario shaping for performance modes

A test scenario might want to switch between performance modes (high-throughput, low-power, error-stress) where each mode has a different set of active constraints. A small helper method set_mode(int mode) on the sequence flips the right combinations of constraint blocks on each transaction it generates.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>function void apb_seq::set_mode(perf_mode_e mode);
  case (mode)
    HIGH_THROUGHPUT: begin
      req.c_back2back_disable.constraint_mode(0);  // allow back-to-back
      req.c_burst_max.constraint_mode(1);           // limit burst length
    end
    LOW_POWER: begin
      req.c_idle_gap.constraint_mode(1);            // require idle gap
      req.c_burst_max.constraint_mode(0);
    end
  endcase
endfunction</code>

Coverage-driven post-hoc constraint disabling

Late in a regression cycle, certain coverage bins remain unhit because the always-on constraints exclude their values. The test layer disables specific blocks temporarily to drive stimulus that closes those bins, with a one-line comment justifying the disable.

Simulation Behavior — How the Solver Honours constraint_mode()

Per-object bitmap

Each object carries one bit per named constraint block — initialised to 1 (enabled) at new(). constraint_mode(0/1) writes the bit; constraint_mode() with no argument reads it. The state is per-instance, not per-class — two objects of the same class can have entirely different blocks enabled.

Solver consultation at every randomize call

At each randomize() call, the solver iterates over every constraint block visible in the object's class hierarchy and, for each, checks the per-object enabled bit. Disabled blocks contribute nothing to the constraint set; enabled blocks contribute their expressions. The check is O(number of blocks), negligible against the cost of the actual solve.

Object-level vs constraint-level disable

obj.constraint_mode(0) (without a constraint name) disables every constraint block on the object. obj.block_name.constraint_mode(0) disables only the named block. The two address different needs: the object-level form is for "I want unrestricted randomisation for this transaction"; the block-level form is for "I want one specific relaxation."

Inheritance chain

Constraint blocks from the parent class are part of every child object — and each inherits its own per-object enabled bit. Disabling child.parent_c_block.constraint_mode(0) is legal; the parent's block is accessed by name on the child handle.

✅ Per-block disable — surgical
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>tx.c_addr_align.constraint_mode(0);
// Only the alignment constraint is off.
// Address map, byte strobes, length —
// all still apply.
if (!tx.randomize()) `uvm_fatal("","");
tx.c_addr_align.constraint_mode(1);</code>
❌ Object-level disable — too coarse
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>tx.constraint_mode(0);
// Every constraint is off.
// Addresses can be anywhere — even
// outside the legal map.
// Byte strobes can be illegal too.
// DUT will NAK most generated stimulus.
if (!tx.randomize()) `uvm_fatal("","");</code>

Waveform Analysis — Tracing Which Constraints Were Active at Solve Time

Disabled constraints are invisible from the outside — the resulting stimulus might violate a class constraint, but you can't tell whether (a) the constraint was disabled or (b) the constraint has a bug. The way to make the disable state visible is to log it explicitly at the call site.

The instrumentation pattern

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>function void apb_xact::post_randomize();
  `uvm_info("RAND",
    $sformatf("paddr=0x%08h  c_align=%s  c_legal_map=%s",
              paddr,
              this.c_align.constraint_mode() ? "ON" : "OFF",
              this.c_legal_map.constraint_mode() ? "ON" : "OFF"),
    UVM_HIGH)
endfunction</code>

ASCII view — disabled blocks visible in the log

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>  100ns  RAND  paddr=0x4000_0010  c_align=ON   c_legal_map=ON
  200ns  RAND  paddr=0x4000_0011  c_align=OFF  c_legal_map=ONdeliberately unaligned
  300ns  RAND  paddr=0x4000_0044  c_align=ON   c_legal_map=ON
  400ns  RAND  paddr=0x4000_0013  c_align=OFF  c_legal_map=ONdeliberately unaligned

                          tells you the disable
                          was intentional, not a bug</code>

Diagnosing "the DUT got an illegal transaction" failures

When a DUT failure log shows "received illegal transaction," the first question is: was the constraint that should have prevented this disabled? With constraint_mode logging in post_randomize, the answer is immediate. Without it, the diagnosis requires re-reading every constraint_mode call upstream — across sequences, tests, and config objects.

Industry Insights — Hard-Won Lessons About constraint_mode()

Debugging Academy — Five Real Bugs From constraint_mode() Misuse

1

"Constraint stays disabled after the scenario ends"

DEBUG
Symptom

A test disables c_align for an error-injection scenario, then resumes the main loop. The main loop's transactions also generate unaligned addresses, even though it never intended to.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>task error_scenario();
  tx.c_align.constraint_mode(0);   // disable
  if (!tx.randomize() with { addr[1:0] != 2'b00; }) `uvm_fatal("","");
  drive(tx);
  // BUG: forgot to re-enable c_align
endtask
 
task main_loop();
  error_scenario();
  repeat (100) begin               // expects aligned addresses
    if (!tx.randomize()) `uvm_fatal("","");
    drive(tx);
    // Many of these are unaligned — DUT NAKs them
  end
endtask</code>
Root Cause

constraint_mode changes persist on the object until explicitly changed again. The error scenario leaks its disable into the main loop.

Fix

Use the save/disable/restore pattern: int saved = tx.c_align.constraint_mode(); tx.c_align.constraint_mode(0); ... ; tx.c_align.constraint_mode(saved);. The restore makes the function self-contained — the main loop sees no side effects from error_scenario.

2

"Disabling once on the class doesn't affect new instances"

DEBUG
Symptom

A test disables c_align on a transaction handle at setup; new transactions constructed later generate aligned addresses again.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>function void test::run_phase(uvm_phase phase);
  apb_xact tx = apb_xact::type_id::create("tx");
  tx.c_align.constraint_mode(0);   // disable on this instance
 
  repeat (10) begin
    tx = apb_xact::type_id::create("tx");   // BUG: new instance every loop
    if (!tx.randomize()) `uvm_fatal("","");
    drive(tx);
    // Every iteration sees aligned addresses again
  end
endfunction</code>
Root Cause

constraint_mode state is per-object. Constructing a new tx resets every block to enabled. The initial disable applied to a transaction that was discarded at the first loop iteration.

Fix

Either (a) construct once outside the loop and reuse: apb_xact tx = apb_xact::type_id::create("tx"); tx.c_align.constraint_mode(0); repeat (10) begin if (!tx.randomize()) ... end, or (b) re-apply the disable inside the loop after each new(). Option (a) is cleaner when the goal is consistent constraint state across iterations.

3

"obj.constraint_mode(0) disabled too much"

DEBUG
Symptom

A test wanted to relax just alignment but called obj.constraint_mode(0) (no block name); resulting stimulus violates the legal address map, byte-strobe legality, and burst-length bounds.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>tx.constraint_mode(0);   // BUG: object-level disable, not per-block
if (!tx.randomize() with { addr[1:0] != 2'b00; }) `uvm_fatal("","");
// Generated addr is outside the legal map AND unaligned</code>
Root Cause

The form obj.constraint_mode(0) with no block name disables every constraint block on the object. The author wanted block-level disable: obj.block_name.constraint_mode(0).

Fix

Always name the specific block: tx.c_align.constraint_mode(0);. The other blocks (legal map, strobes, burst length) remain in effect, and only alignment is relaxed. Reserve the object-level form for the rare case where you genuinely want unrestricted randomisation (debug scaffolding, perhaps — never in test code).

4

"Disabled constraint state leaks across UVM components"

DEBUG
Symptom

A sequence disables c_align on a transaction handle before sending it to the driver. The driver re-randomises the transaction (which the sequence didn't expect), and the re-randomisation honours the disable, producing unaligned drives.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>task my_seq::body();
  `uvm_create(req)
  req.c_align.constraint_mode(0);
  start_item(req);
  finish_item(req);     // hand off to driver
  // Sequence assumed driver only drives, not re-randomises
endtask
 
task my_drv::run_phase(uvm_phase phase);
  forever begin
    seq_item_port.get_next_item(req);
    if (!req.randomize()) `uvm_fatal("","");   // BUG: driver re-randomises
    drive_bus(req);
    seq_item_port.item_done();
  end
endtask</code>
Root Cause

The driver is re-randomising the transaction (which is unusual but not illegal), and the disable state set by the sequence travels with the handle. The driver's randomize call honours the disable.

Fix

Drivers should not re-randomise transactions handed to them by sequences — they should drive what they receive. Remove the driver's randomize call. If the driver legitimately needs to randomise additional fields (e.g., local delay), use the named-argument form on a separate rand field: req.randomize(local_delay). Either way, the disable's leak is a symptom of architectural confusion about responsibility.

5

"Inherited constraint disabled on parent but still firing on child"

DEBUG
Symptom

A child class inherits c_align from the parent. The test disables it via the parent class name; the child class's transactions still generate aligned addresses.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class parent_xact;
  rand bit [31:0] addr;
  constraint c_align { addr[1:0] == 2'b00; }
endclass
 
class child_xact extends parent_xact;
  // inherits c_align
endclass
 
child_xact c = new();
// BUG: trying to disable via parent's type doesn't work
parent_xact::c_align.constraint_mode(0);  // illegal syntax
c.c_align.constraint_mode(0);   // CORRECT: through the instance handle</code>
Root Cause

constraint_mode is a per-instance method. You must call it on an instance handle, not on a class type or via scope resolution. The inherited block is accessed by its name through the child handle — c.c_align.constraint_mode(0) — and the disable applies to that specific instance.

Fix

Always call through the instance handle: c.c_align.constraint_mode(0);. The inheritance chain is transparent — the parent's block is accessible by its declared name on the child handle. No type-scoped disable mechanism exists; everything is per-object.

Interview Q&A — Twelve Questions You Will Be Asked

It enables or disables a named constraint block on a specific class instance. constraint_mode(0) disables; constraint_mode(1) enables; calling with no argument reads the current state. The change is per-instance and persists until explicitly changed again. The class definition is never modified — only the per-object enable bitmap.

Best Practices — Ten Rules for Disciplined constraint_mode() Usage

  1. Always save the current mode before disabling. int saved = c.constraint_mode(); c.constraint_mode(0); ... ; c.constraint_mode(saved); — four lines, future-proof.
  2. Prefer per-block disable over per-object disable. Surgical relaxation preserves every other constraint; whole-object disable opens the floodgates.
  3. Pair every disable with a comment explaining why. Future readers should understand the scenario from the source, not from a code-archaeology session.
  4. Remember the state is per-object. Constructing a new instance resets every block to enabled. Apply your disable after every new() or reuse the same handle.
  5. Log constraint_mode state in post_randomize during bring-up. The log line makes "which constraint was off?" diagnosable in seconds instead of hours.
  6. Don't leak disable state across function boundaries. A function that disables should restore before returning, so callers see no side effects.
  7. Don't leak disable state across TLM ports. Either restore before sending or clone the transaction so downstream code gets a fresh-state copy.
  8. Choose constraint_mode over soft constraints when the relaxation is scenario-driven. Soft is for graceful in-class conflict resolution; constraint_mode is for explicit test-layer control.
  9. For complex scenarios, use a helper class. A "mode manager" with set_scenario_X(tx) methods centralises policy and keeps test code readable.
  10. Use the inheritance-aware syntax. child_obj.parent_block_name.constraint_mode(0) works exactly as expected; there is no separate "disable parent's block" mechanism.