Part 3 · Constraint Randomization · Intermediate
soft Constraints
Priority rules, overridable defaults without constraint_mode, soft + dist, and soft discard ordering.
Defaults that yield instead of fight
A soft constraint holds whenever it can, and is silently discarded when it contradicts any hard constraint. That makes it the natural tool for defaults : the base transaction ships with sensible soft values, and any test can override them with a plain inline constraint — no subclassing, no constraint_mode() bookkeeping, no knowledge of which block to disable. Hard constraints, by contrast, only ever intersect; two contradictory hard constraints make randomize() fail.
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
module t;
initial begin
eth_pkt p = new();
void'(p.randomize()); // len in 64..1500 (soft holds)
void'(p.randomize() with { len == 9000; }); // SUCCEEDS — soft discarded
// Had len_default been hard, this call would FAIL (64..1500 ∩ {9000} = ∅)
end
endmoduleNote the soft constraint is not “weakly weighted” — while active it is a full constraint, shaping the set exactly like a hard one. Discarding is all-or-nothing per soft constraint, triggered only by genuine contradiction.
Priority and discard ordering
When several soft constraints conflict with hard constraints (or with each other), the LRM defines a deterministic discard order: soft constraints have priorities based on declaration order , and later-declared soft constraints win over earlier ones. The solver discards the lowest-priority (earliest) soft constraints first, one at a time, until the remaining set is satisfiable. Inline soft constraints in randomize() with are treated as declared last — so they outrank every class-level soft constraint.
SOFT DISCARD ORDER (lowest priority discarded first)
priority LOW ──────────────────────────────► priority HIGH
earliest declaration ........... latest declaration ... inline 'with'
class c; conflict resolution:
constraint a { soft x < 10; } ① 1. try ALL constraints
constraint b { soft x > 5; } ② 2. unsat? drop ① (earliest soft)
endclass 3. still unsat? drop ②
randomize() with { soft x==20; }③ 4. hard constraints NEVER dropped
x == 20 case: ① (x<10) conflicts → ① dropped, ② and ③ hold → x = 20class 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
// randomize(): both cannot hold; the EARLIER soft (x==1) is discarded.
// Result: x == 2, deterministically — later soft constraints win.In practice you rarely lean on subtle priority interactions — treat the rule as “inline soft beats class soft, later beats earlier,” and keep soft constraints sparse enough that the ordering never surprises anyone.
soft + dist, and what soft cannot do
Soft applies to dist too: a soft dist provides a default traffic shape that any hard constraint overrides cleanly. This is a popular pattern for base sequences — default mostly-normal traffic, with error tests free to pin values.
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
// error test:
// void'(tx.randomize() with { resp == 3; });
// → hard inline wins; soft dist (which gives resp==3 little weight,
// and conflicts as a SET only if it excluded 3 — here it must yield
// as a distribution) is discarded; resp is exactly 3.Limits worth knowing: soft cannot rescue a contradiction between two hard constraints; soft constraints are still constraints, so they participate in bidirectional solving while active; and soft on randc is illegal for the same reason dist is. If you find yourself stacking many interacting soft constraints, that is usually a sign the defaults belong in a policy/knob structure instead.
Interview angle
What interviewers ask
“How do you give a transaction a default that tests can override without disabling constraint blocks?” — soft constraint in the class; hard inline with at the call site overrides it.
“Two soft constraints conflict — which survives?” — the later-declared one; soft priority increases with declaration order, and inline soft ranks above class soft.
“What happens when soft conflicts with hard?” — the soft constraint is discarded entirely; randomize() succeeds.
“Is soft a weighting mechanism?” — no; while satisfiable it constrains fully like a hard constraint. Weighting is dist.
“soft vs constraint_mode(0)?” — soft is automatic and per-conflict; constraint_mode is an explicit procedural toggle of a whole named block.
Key takeaways
soft constraints are discarded automatically when they contradict hard constraints — perfect for defaults.
While satisfiable, a soft constraint shapes the solution set exactly like a hard one.
Priority follows declaration order: later soft beats earlier soft; inline soft beats class soft.
Hard constraints are never discarded — hard-vs-hard contradiction still fails randomize().
soft dist gives an overridable default traffic shape without any constraint_mode calls.
Common pitfalls
Believing soft means “low weight” — it is full-strength until contradicted, then gone entirely.
Expecting soft to save a hard-vs-hard contradiction — randomize() still fails.
Relying on intricate soft priority chains — legal but unreadable; keep one soft default per field.
Marking everything soft “to be safe” — tests silently discard your protocol-legality constraints.
Forgetting inline soft outranks class soft — a sequence-level soft default overrides the class default.