A soft constraint holds whenever it can, and it is dropped when a hard constraint contradicts it. That makes it the natural tool for defaults in reusable transactions.
While active, a soft constraint is full strength, shaping the set exactly like a hard one. Discarding is all-or-nothing per soft constraint, and only genuine contradiction triggers it.
// snippet: also in the bench below
class eth_pkt;
rand bit [13:0] len;
// Default: ordinary frame sizes, but only a preference
constraint len_default { soft len inside {[64:1500]}; }
endclassA plain call keeps the default range. A hard inline constraint such as len == 9000 discards the soft one and succeeds, where a hard default would fail on the empty intersection.
Priority | Where the soft constraint is written |
|---|---|
Lowest | Declared earlier in the class |
Higher | Declared later in the class, or in a derived class |
Highest | In an inline |
Hard constraints always hold. Softs are kept from the highest priority down, and one is discarded only if it cannot hold together with every higher-priority soft already kept. Example: class softs x < 10 then x > 5, and an inline soft x == 20: the inline one holds, x > 5 fits with it, and x < 10 is dropped.
IEEE 1800 18.5.14.1 defines the priority: a later soft in the same class outranks an earlier one, a derived class outranks its base, and an inline with outranks the class. Keep one soft default per field anyway, so the result stays easy to read.
// snippet: also in the bench below
class prio_demo;
rand int x;
constraint c_low { soft x == 1; } // declared first: lower priority
constraint c_high { soft x == 2; } // declared second: higher priority
endclass
// Both cannot hold, so the lower-priority (earlier) soft x==1 is discarded.
// LRM result (18.5.14.1): x == 2. Keep such chains rare.// snippet: also in the bench below
class axi_txn;
rand bit [1:0] resp; // 0=OKAY 1=EXOKAY 2=SLVERR 3=DECERR
// Default shape: overwhelmingly OKAY, but only a default
constraint resp_default { soft resp dist { 0 :/ 95, [2:3] :/ 5 }; }
endclass
// An error test with a hard inline resp == 3 discards the soft dist.
// Soft cannot rescue hard-versus-hard clashes, and soft on randc is illegal.Situation | Outcome |
|---|---|
Soft default alone | Holds fully, exactly like a hard constraint. |
Soft against hard | Soft is discarded and |
Two soft defaults in tension | The lower-priority (earlier) soft is discarded, per IEEE 1800 18.5.14.1. |
Hard against hard | Nothing is dropped and |
The soft constraint is discarded and randomize succeeds with the inline value. Only a hard-versus-hard clash fails.
randomize() fail?No. The earlier-declared soft is discarded and the later one holds; a soft constraint never makes the call fail.
eth_pkt has soft len inside {[64:1500]}. A test calls randomize() with { len == 9000; }. Does the call succeed, and what is len?It succeeds with len == 9000. The hard inline rule contradicts the soft default, so the soft one is discarded instead of the call failing.
The classes from this lesson: the soft default, a hard override, two softs in conflict, and a soft dist.
class eth_pkt;
rand bit [13:0] len;
// Default: ordinary frame sizes, but only a preference
constraint len_default { soft len inside {[64:1500]}; }
endclass
class prio_demo;
rand int x;
constraint c_low { soft x == 1; } // declared first: lower priority
constraint c_high { soft x == 2; } // declared second: higher priority
endclass
class axi_txn;
rand bit [1:0] resp; // 0=OKAY 1=EXOKAY 2=SLVERR 3=DECERR
constraint resp_default { soft resp dist { 0 :/ 95, [2:3] :/ 5 }; }
endclass
inline len == 9000: returned 1, len = 9000
two softs in conflict: x = 2 (the later one wins)
soft dist: OKAY in 946 of 1000 (weight 95 of 100)
PASS: the soft default held until a hard rule contradicted it, and the later soft won the tieThe standard also discards a soft dist when a hard rule contradicts it. One of the simulators used here does not: a hard resp == 3 made the call fail, so the bench checks only the soft weights.
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 5.048 did not discard a soft dist when a hard inline rule contradicted it: randomize() returned 0. The bench checks only the soft weights.