randc bit [1:0] c promise that rand bit [1:0] r does not?Every value once per cycle of four calls, with no repeat inside a cycle. rand draws independently each call, so repeats are normal.
randomize() returns 0. What do the rand fields hold, and what must the caller do?Their previous values: a failed call assigns nothing. The caller checks the return value and stops, or every later transaction re-sends stale stimulus.
rand handle inside the object is null. What does randomize() do with it?The standard skips it and still returns 1; the solver never builds objects. Verilator 5.048 skipped it only when the handle's class had no constraints of its own, and otherwise stopped with a null-pointer error. Build every handle in new().
rand | randc | |
|---|---|---|
Repeats across calls | Allowed | None until the cycle ends |
State | None | Per field, per object |
Mixes with dist | Yes | No: weighting contradicts cycling |
Widths | Any | Tools may cap it; the cap is at least 8 bits |
randomize() returns 1 when the solver found a solution and 0 when the set was empty. One call solves every rand field of the object and its parents whose mode is on, plus every non-null rand child, in one problem; plain fields are read as constants.
The bench checks each answer above on Verilator: 100 calls of the rand and randc pair, a null child then a built one, and a call that cannot succeed.
class demo;
rand bit [1:0] r; // any of 0..3 each call: repeats allowed
randc bit [1:0] c; // a permutation of 0..3, then a new one
endclass
class header; // no constraints of its own: Verilator stops on a null handle whose class has some
rand bit [3:0] ver;
endclass
class packet;
rand bit [7:0] payload_len;
bit [7:0] max_len = 40; // state: read by the solver, never written
rand header hdr; // nested: solved only if it exists
constraint c { payload_len <= max_len; }
endclass
100 calls: rand repeated its previous value 23 times; randc never repeated inside a cycle
hdr null: randomize() returned 1, hdr is still null
hdr built: ver 3, payload_len 9 (max_len 40)
%Warning-UNSATCONSTR: /var/folders/41/dgs80y1569b4x8pwflv_w9jr0000gn/T/rtbtb-K1WcxI/t63.sv:14: Unsatisfied constraint: 'constraint c { payload_len <= max_len; }'
%Warning-UNSATCONSTR: /var/folders/41/dgs80y1569b4x8pwflv_w9jr0000gn/T/rtbtb-K1WcxI/t63.sv:45: Unsatisfied constraint: 'ok = p.randomize() with { payload_len > 200; };'
payload_len > 200 against max_len 40: returned 0, payload_len still 9
PASS: randc cycled, the null handle was skipped and then solved once built, and the failed call kept stale valuesrandomize() legitimately return 0?On a contradiction: class rules against an inline with, parent against child, state bounds squeezed empty, or a wrap with no solution. Each is a design signal, not noise.
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 skipped a null rand handle only when its class had no constraints; otherwise the run stopped with a null-pointer error.