Part 3 · Constraint Randomization · Intermediate
rand_mode(): Freezing Fields
Per-field and per-object rand_mode, frozen fields as state in constraints, set-then-freeze pattern, and querying.
What rand_mode(0) actually does
field.rand_mode(0) removes a field from the set of variables the solver assigns. Crucially, the field does not vanish from the constraint system — it becomes a state variable : its current value is read at solve time and every constraint mentioning it still must hold. This is the half people miss. Freezing a field does not disable the constraints on it; it converts those constraints into conditions on the frozen value, and if the frozen value contradicts them, randomize() fails.
class pkt;
rand bit [7:0] len;
rand bit [7:0] payload_kind;
constraint c { len > 10; payload_kind < len; }
endclass
module t;
initial begin
pkt p = new();
p.len.rand_mode(0); // freeze len at its CURRENT value (0!)
if (!p.randomize())
$display("FAILS: frozen len==0 violates len > 10");
p.len = 50; // set a legal value, then solve
void'(p.randomize()); // OK: payload_kind solved in [0:49]
end
endmoduleTwo lessons in one example: a frozen field keeps participating (payload_kind's range follows the frozen len), and freezing without first assigning a legal value is a randomize() failure waiting to happen — fields construct to zero.
Per-field vs per-object, and querying
Called on a single field, p.len.rand_mode(0) affects just that field. Called on the object, p.rand_mode(0) disables randomization of every rand/randc field in it (including, recursively, the mode of nested rand object handles being randomized — though each nested object also has its own rand_mode). Called with no argument as a function, it queries the current mode of a single variable and returns 0 or 1.
pkt p = new();
p.rand_mode(0); // freeze EVERY rand field in p
p.len.rand_mode(1); // re-enable just len
if (p.len.rand_mode()) // query — function form, single variable only
$display("len is randomized");
if (!p.payload_kind.rand_mode())
$display("payload_kind is frozen");
// NOTE: query form is per-variable; p.rand_mode() as a query is illegal —
// objects do not have a single mode to return.Mode state lives on the object instance and is sticky: it persists across randomize() calls until changed. A sequence that freezes a field for one call must remember to thaw it, or every later randomize() of that object inherits the freeze.
The set-then-freeze pattern
The standard production use: a test or sequence pins one field to a directed value while the rest of the transaction stays random — directed-random stimulus. Compare the mechanisms: an inline with { addr == X } also pins the value, but rand_mode(0) keeps the pin across many randomize() calls without repeating the constraint, which is exactly what loops want.
class axi_txn;
rand bit [31:0] addr;
rand bit [7:0] len;
rand bit write;
constraint legal_c { len inside {[1:16]}; addr[1:0] == 0; }
endclass
task hammer_one_address(axi_txn t, bit [31:0] target, int n);
t.addr = target; // 1. set the directed value
t.addr.rand_mode(0); // 2. freeze it (it must satisfy addr[1:0]==0!)
repeat (n)
if (!t.randomize()) // 3. len/write re-randomized each iteration
$fatal(1, "frozen addr violates legal_c");
t.addr.rand_mode(1); // 4. ALWAYS restore for the next user
endtaskrand_mode(0) — WHAT CHANGES AT SOLVE TIME
rand fields: addr len write
│ │ │
rand_mode: 0 1 1
│ │ │
▼ ▼ ▼
read as SOLVED SOLVED
STATE ▲ ▲
(=0xA000) │ │
│ constraints still connect them all:
└────► len inside {[1:16]}; addr[1:0]==0;
addr participates as the constant 0xA000
→ addr[1:0]==0 must HOLD or randomize()==0Interview angle
What interviewers ask
“After x.rand_mode(0), do constraints on x still apply?” — yes; x becomes a state variable and constraints on it become checks against its frozen value. The screening question for this feature.
“Why did randomize() start failing after I froze a field?” — the frozen (often default-zero) value violates an active constraint; set a legal value before freezing.
“rand_mode(0) vs inline with { x == k }?” — both pin x for a call; rand_mode persists across calls and needs no constraint repetition, but is sticky state you must restore.
“How do you check whether a field is currently randomized?” — the function form x.rand_mode() returns the mode; only valid per variable.
“Does object-level rand_mode(0) disable constraints?” — no; it freezes variables. Disabling constraints is constraint_mode's job — a deliberately confusable pair.
Key takeaways
rand_mode(0) converts a rand field into a state variable — constraints on it still apply.
Set a legal value before freezing; fields default to zero and zero often violates constraints.
Per-field and per-object forms exist; the query form is per-variable only.
Mode is sticky instance state — restore rand_mode(1) after directed phases.
Use rand_mode for multi-call pins; use inline with for one-call pins.
Common pitfalls
Freezing a field at its default 0 and hitting mysterious randomize() failures.
Assuming rand_mode(0) disables constraints on the field — it does not; constraint_mode does that.
Forgetting to restore rand_mode(1), silently freezing the field for all later tests sharing the object.
Calling p.rand_mode() as an object-level query — illegal; query is per variable.
Using rand_mode on a randc field then expecting the cycle to resume where it left off — the cycle state interaction is tool-dependent; re-check after thawing.