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.
// 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; }
endclassTo 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.
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.
// 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 framesThe 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.
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. |
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.
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
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 againNo. Inline expressions only add constraints for one call. They neither disable nor enable blocks, so the disabled block stays silent.
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.
One way to write it:
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
endmodulefault 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 packetsRun 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.