rand len field instead of using a dynamic array?len solves together with the elements, and an i < len guard limits the rules to the used slots. A dynamic array's size is solved first, and Verilator 5.048 could not combine size() with sum() on one.
m[4][4] in a constraint?foreach (m[i, j]), the standard's comma form. m[i][j] in the loop header is not standard syntax, and Verilator rejects it.
arr.sum() with (int'(item)) == 100 and the pairwise rule if (i < j) arr[i] != arr[j]. Ten different bytes reach at least 0 + 1 + ... + 9 = 45, so 100 is feasible.
Construct | Rule | Trap it avoids |
|---|---|---|
|
| Sizing first, then filling by hand |
Dynamic | Solved first, then the element rules | A size range with no legal elements |
Comma form | One loop over both dimensions |
|
Guarded element rule | Rules apply only below | Constraining garbage past |
A null child handle is never built by the solver: the constructor owns allocation. Sums widen first, and uniqueness that must work on every tool is written pairwise.
The bench checks the length guard and the 2D loop over 200 frames, and ten different bytes totalling 100 over 200 calls.
class frame;
rand bit [7:0] len;
rand bit [7:0] pay[16];
rand bit [7:0] m[4][4];
constraint c_size { len inside {[1:16]}; }
constraint c_pay { foreach (pay[i]) if (i < len) pay[i] inside {[1:50]}; else pay[i] == 0; }
constraint c_2d { foreach (m[i, j]) m[i][j] inside {[0:15]}; } // comma form for 2D
endclass
class pkt_sum;
rand bit [7:0] arr[10];
constraint c_sum { arr.sum() with (int'(item)) == 100; } // widened
constraint c_pair { foreach (arr[i]) foreach (arr[j]) if (i < j) arr[i] != arr[j]; }
endclass
frame: len 7, guarded payload and 4x4 matrix legal over 200 calls
pkt_sum: ten different bytes totalling 100, e.g. '{'h6, 'h7, 'h2e, 'h11, 'hc, 'h2, 'h5, 'h0, 'h4, 'h1}
PASS: guarded rules, the 2D comma loop, the widened sum and pairwise uniqueness all heldRun 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.