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.

systemverilog
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
endmodule

Note 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.

diagram
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 = 20
systemverilog
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
// 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.

systemverilog
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.