Skip to content

SystemVerilog · Module 10

Soft Constraints

Overridable defaults the solver drops when contradicted, per-expression granularity, distinct from constraint_mode and inline with, and the danger of marking protocol legality soft.

Module 10 · Page 10.7

Hard vs Soft — The Core Difference

Every constraint you have seen so far is a hard constraint — the solver must satisfy it or fail. A soft constraint is written with the soft keyword and behaves differently: the solver tries its best to satisfy it, but if it conflicts with any hard constraint, the soft constraint is silently dropped and the solver continues without it. randomize() still returns 1.

SystemVerilog — hard vs soft constraint behaviour
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class Packet;
    rand bit [7:0] len;
 
    // Hard constraint — solver MUST satisfy this or return 0
    constraint min_len  { len >= 64; }
 
    // Soft constraint — solver TRIES to satisfy this
    // If it conflicts with a hard constraint, it is dropped silently
    constraint prefer_short { soft len <= 128; }
endclass
 
Packet p = new();
 
// No conflict — both satisfied: len in 64–128
assert(p.randomize());
 
// Hard inline constraint contradicts the soft one:
// soft prefer_short is dropped, hard inline wins
assert(p.randomize() with { len > 500; });  // len in 501–255? No—
                                              // len in 501..65535 for wider type
                                              // For 8-bit: len in 132–255
 
// randomize() returns 1 in both cases — no failure

Syntax — Where soft Goes

The soft keyword appears inside a constraint block, directly before the expression it applies to. Each expression in a block is independently hard or soft — you can mix them freely.

SystemVerilog — soft constraint syntax forms
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class BusTxn;
    rand bit [31:0] addr;
    rand bit [7:0]  data;
    rand bit         write;
 
    // ── A block where every expression is soft ────────────────────
    constraint defaults {
        soft addr  == 32'h4000_0000;  // prefer this address
        soft write == 1;               // prefer write transactions
    }
 
    // ── Mixed block — one hard, one soft ─────────────────────────
    constraint mixed {
        addr[1:0] == 2'b00;            // HARD — alignment always enforced
        soft data  != 8'h00;           // SOFT — prefer non-zero, can drop
    }
 
    // ── Soft inside a named block — the block name still applies ──
    constraint prefer_range {
        soft addr inside {[32'h4000_0000:32'h4000_FFFF]};
    }
endclass

The soft keyword can also appear inside a with inline constraint:

SystemVerilog — soft inside a with clause
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
BusTxn t = new();
 
// Add a soft preference inline — only for this call
assert(t.randomize() with {
    soft addr == 32'h4000_0100;   // prefer this address, but not required
});

Overriding Soft Constraints

The primary purpose of soft constraints is to define sensible defaults in a base class that subclasses and tests can override with hard constraints — without triggering a constraint contradiction. This is the design pattern that makes them powerful.

Override with a hard inline constraint

SystemVerilog — hard inline overrides soft class constraint
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class Pkt;
    rand bit [1:0] prio;
    constraint default_prio { soft prio == 0; }  // prefer low priority
endclass
 
Pkt p = new();
 
// Normal call — soft satisfied, prio = 0
assert(p.randomize());
$display("prio = %0d", p.prio);   // prio = 0
 
// Hard inline contradicts soft — soft is dropped, hard wins
assert(p.randomize() with { prio == 3; });
$display("prio = %0d", p.prio);   // prio = 3  (no error, no failure)
 
// Next normal call — soft is active again, prio = 0
assert(p.randomize());
$display("prio = %0d", p.prio);   // prio = 0

Override in a child class with a hard constraint

SystemVerilog — child class hard constraint overrides parent soft
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Base class defines a soft default
class BasePkt;
    rand bit [1:0] prio;
    constraint default_prio { soft prio == 0; }
endclass
 
// Child class ALWAYS uses high priority — hard constraint wins over soft
class HighPriPkt extends BasePkt;
    constraint force_hi { prio == 3; }   // hard — overrides parent's soft
endclass
 
// No contradiction error — the soft is silently dropped in HighPriPkt
HighPriPkt h = new();
assert(h.randomize());   // prio = 3, always

Multiple Soft Constraints — Priority

When multiple soft constraints are active and some of them conflict with each other or with hard constraints, the solver drops as few as possible to find a valid solution. The LRM does not mandate a specific priority ordering between soft constraints — the solver is free to choose which soft constraints to keep.

SystemVerilog — multiple soft constraints, partial satisfaction
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class Config;
    rand bit [3:0] x;
 
    // Three soft preferences — may not all be satisfiable together
    constraint s1 { soft x >  8;  }   // prefer x in 9–15
    constraint s2 { soft x <  5;  }   // prefer x in 0–4
    constraint s3 { soft x == 7;  }   // prefer x = 7
    // s1 and s2 contradict each other — solver drops one of them
    // s3 is compatible with neither s1 nor s2 — may also be dropped
    // Result is tool-dependent: could be 9–15, 0–4, or 7
endclass

Practical Patterns

Pattern 1 — Reusable base class with overridable defaults

Write a single transaction class that works for both the default test scenario and specialised edge-case tests — without subclassing or constraint_mode() calls.

SystemVerilog — base class with soft defaults, tests override inline
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class AhbTxn;
    rand bit [31:0] addr;
    rand bit [2:0]  size;    // 0=byte, 1=half, 2=word, 3=dword...
    rand bit [2:0]  burst;
 
    // Hard rules — always enforced
    constraint aligned {
        (size == 0) || (addr[0]   == 0);
        (size == 1) || (addr[1:0] == 0);
    }
 
    // Soft defaults — typical traffic pattern, tests can override
    constraint typical {
        soft size  == 3'h2;            // prefer word transfers
        soft burst == 3'h0;            // prefer single burst
    }
endclass
 
AhbTxn t = new();
 
// Normal test — typical traffic (size=word, burst=single)
assert(t.randomize());
 
// Burst test — override size and burst inline, no class change
assert(t.randomize() with {
    size  == 3'h3;    // hard: force dword — soft size is dropped
    burst == 3'h4;    // hard: force INCR16 — soft burst is dropped
});

Pattern 2 — Steering coverage without closing doors

Use a soft constraint to bias randomisation towards an under-covered region while still letting the solver occasionally pick other values. Unlike constraint_mode(0/1), no switching is needed — the solver naturally includes values outside the hint when the combined constraint set requires it.

SystemVerilog — soft bias towards an uncovered region
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class OpGen;
    rand bit [3:0] opcode;
 
    // Bias towards rarely-hit opcodes 12–15
    constraint coverage_push {
        soft opcode inside {[12:15]};
    }
endclass
 
OpGen g = new();
 
// Most calls: opcode in 12–15 (soft satisfied)
// If an inline or inherited hard constraint forces opcode < 12,
// the soft is dropped and that value is used instead — no failure
assert(g.randomize());
assert(g.randomize() with { opcode == 4'h5; });  // 5, soft dropped
assert(g.randomize());                               // 12–15 again

soft vs the Alternatives

ToolWhat it guaranteesBest for
Hard constraintValue always satisfies the rule or solver failsProtocol-level invariants (alignment, range, legality)
soft constraintValue satisfies rule when possible; dropped silently if conflictedDefault values in base classes, typical traffic bias
dist (page 10.8)Weighted probability across values — some always possibleStatistical bias: "70% reads, 30% writes"
constraint_mode(0/1)Rule is explicitly on or off — you control it in codeSwitching between test phases programmatically
with { } inlineExtra rule active for exactly one callPer-call steering, corner-case injection

Common Pitfalls

Expecting soft to be probabilistic

soft x == 0 does not mean "x is 0 most of the time." It means "x is 0 whenever nothing forces it elsewhere." For weighted probabilities use dist.

Debugging disappeared soft constraints

If a soft constraint is being silently dropped and you don't know why, temporarily make it hard to see which other constraint is causing the conflict. Revert to soft once you understand the interaction.

Two conflicting softs with no hard tie-breaker

When two soft constraints cannot both be satisfied and there is no hard constraint to break the tie, the solver's choice is tool-defined. Never rely on which of two conflicting softs wins.

Using soft to avoid writing hard constraints

If a rule must always hold — alignment, legality, protocol compliance — it must be a hard constraint. Soft is not a "gentler" version of hard; it genuinely means the rule can be ignored.

Quick Reference

SystemVerilog — soft constraint cheat sheet
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── Declare soft inside a constraint block ────────────────────
constraint name { soft <expr>; }
 
// ── Mix hard and soft in one block ───────────────────────────
constraint name {
    hard_expr;            // hard — must be satisfied
    soft soft_expr;       // soft — satisfied if possible
}
 
// ── Soft inside a with clause ─────────────────────────────────
assert(obj.randomize() with { soft field == value; });
 
// ── Override soft with a hard inline ─────────────────────────
// Hard always wins over soft — no contradiction error
assert(obj.randomize() with { field == other_value; });  // soft dropped
 
// ── Override soft in a child class ───────────────────────────
class Child extends Parent;
    constraint force_it { field == specific_value; }  // hard wins
endclass
 
// ── What soft does NOT do ─────────────────────────────────────
// ✗ Not probabilistic — use dist for weighted probability
// ✗ Not "sometimes" — it's satisfied fully or dropped entirely
// ✗ Not a replacement for hard constraints on protocol rules

Verification Usage — Where soft Pays Off in Real VIP

Production VIPs use soft in three distinct architectural roles. Each is a clean expression of "default that may be overridden"; mixing the roles or applying soft outside them produces unmaintainable behaviour.

Overridable defaults on protocol-shaped fields

The canonical use: a transaction class wants to declare "the typical address range," "the preferred burst length," "the default transaction kind" — values that real tests almost always accept, but that scenario tests may override.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class apb_xact extends uvm_sequence_item;
  rand bit [31:0] paddr;
  rand bit [3:0]  burst_len;
  rand pwrite_e   pwrite;
 
  constraint c_defaults {
    soft paddr inside {[32'h4000_0000 : 32'h4000_FFFF]};   // default range
    soft burst_len inside {[0:7]};                          // default short
    soft pwrite == PWRITE_WRITE;                            // default write
  }
endclass
 
// Default test gets the soft defaults
if (!tx.randomize()) `uvm_fatal("","");
 
// Scenario test overrides one without disabling others
if (!tx.randomize() with { paddr inside {[32'h5000_0000:32'h5FFF_FFFF]}; })
  `uvm_fatal("","");
// burst_len and pwrite still use their soft defaults</code>

Reusable VIP base classes with customer-overridable preferences

Vendor-shipped VIPs use soft extensively on the base transaction class. The vendor's defaults work out-of-the-box; customers override the specific defaults their project needs without forking the source.

Configurable error-injection scenarios

Soft constraints simplify error-injection: the class ships with the legal-stimulus defaults marked soft; error tests just add inline constraints that contradict the defaults, and the solver drops the conflicting softs automatically — no constraint_mode bookkeeping required.

Simulation Behavior — How the Solver Resolves Soft Conflicts

Constraint set assembly with soft expressions

At randomize() call time, the solver collects every constraint expression — hard and soft — from every active class block plus the inline with clause. Each expression is tagged with its priority (hard = required, soft = preferred).

Conflict detection and resolution

The solver first attempts to satisfy every expression simultaneously. If that's satisfiable, it picks an assignment and returns. If not, it identifies the minimal set of soft expressions that, when dropped, makes the remaining set satisfiable — and tries again. The drop is granular: only soft expressions that actually participate in a contradiction are dropped; soft expressions on unrelated fields are preserved.

No partial-priority levels

Soft expressions don't have a numeric priority — every soft is equally "droppable." If two soft expressions are in mutual conflict (rare), the solver chooses one to drop based on implementation-defined criteria. For most production code, this doesn't matter: real soft conflicts come from "inline with contradicts class default," not from "two class defaults contradict each other."

Cost characteristics

Soft constraints add a small cost over hard constraints: the solver must attempt the full set first, detect any conflict, identify the drop candidates, and re-solve. For a class with many softs and no conflicting inline with, the cost is identical to hard constraints. For a class with frequent inline conflicts, the cost is modestly higher.

✅ Soft yields gracefully
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class xact;
  rand bit [31:0] addr;
  constraint c {
    soft addr inside {[0:'hFFFF]};   // soft default
    addr[1:0] == 2'b00;               // hard alignment
  }
endclass
 
// Inline asks for a high address;
// soft drops, hard still applies.
tx.randomize() with { addr inside {[32'h1_0000:32'hFFFF_FFFF]}; };
// Result: addr in [0x10000:0xFFFFFFFC],
//         still aligned (hard preserved).</code>
❌ Hard wins, inline loses
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class xact;
  rand bit [31:0] addr;
  constraint c {
    addr inside {[0:'hFFFF]};        // hard — no escape
    addr[1:0] == 2'b00;
  }
endclass
 
// Inline asks for high address; hard
// blocks → randomize() returns 0.
tx.randomize() with { addr inside {[32'h1_0000:32'hFFFF_FFFF]}; };
// → solve fails. Need constraint_mode(0)
//   or refactor the class.</code>

Waveform Analysis — Verifying Soft Behaviour Is What You Intended

Soft drops are silent — the resulting transaction looks identical to one where the soft constraint was never present. The way to verify softs are behaving correctly is to instrument post_randomize with the field values and the expected vs actual relationships.

The instrumentation pattern

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class apb_xact extends uvm_sequence_item;
  rand bit [31:0] paddr;
  rand bit [3:0]  burst_len;
 
  constraint c_defaults {
    soft paddr inside {[32'h4000_0000 : 32'h4000_FFFF]};
    soft burst_len inside {[0:7]};
  }
 
  function void post_randomize();
    bit addr_in_default = (paddr inside {[32'h4000_0000:32'h4000_FFFF]});
    bit blen_in_default = (burst_len inside {[0:7]});
    `uvm_info("SOFT",
      $sformatf("paddr=0x%08h (default=%0d)  burst_len=%0d (default=%0d)",
                paddr, addr_in_default, burst_len, blen_in_default),
      UVM_HIGH)
  endfunction
endclass</code>

ASCII view — soft defaults respected vs dropped

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>  100ns  SOFT  paddr=0x4000_0010 (default=1)  burst_len=3 (default=1)
  200ns  SOFT  paddr=0x4000_0044 (default=1)  burst_len=5 (default=1)
  300ns  SOFT  paddr=0x5000_1234 (default=0)  burst_len=4 (default=1)   ← softs split
  400ns  SOFT  paddr=0x5000_5678 (default=0)  burst_len=12 (default=0)  ← both dropped
              ↑                                ↑
       inline overrode paddr's soft       error test also overrode
       (burst_len's soft still applied)    burst_len's soft</code>

Diagnosing "the test didn't generate what I expected"

When a test fails to produce stimulus in the expected range, the question is: was a soft default dropped? With per-field "in default range" booleans in the log, the answer is one line. Without it, you re-read every inline with and every constraint block to figure out which override fired.

Industry Insights — Hard-Won Lessons About Soft Constraints

Debugging Academy — Five Real Bugs From soft Misuse

1

"Soft protocol-alignment dropped silently, DUT NAKs everything"

DEBUG
Symptom

A test runs cleanly with no randomize() failures, but the DUT NAKs every transaction with "alignment violation." Coverage of legal stimulus is 0%.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class apb_xact;
  rand bit [31:0] paddr;
  constraint c {
    soft paddr[1:0] == 2'b00;   // BUG: alignment is hard protocol, not preference
  }
endclass
 
// Some upstream code does inline override:
tx.randomize() with { paddr == 32'h4000_0001; }   // unaligned
// Soft drops silently; DUT rejects all transactions</code>
Root Cause

Alignment is a hard protocol rule but was marked soft. The inline override drops it silently; the DUT enforces the rule downstream and rejects the result. The test infrastructure can't see the bug because both randomize and the driver report success.

Fix

Remove the soft keyword: constraint c { paddr[1:0] == 2'b00; }. Now any inline override that produces an unaligned address makes randomize return 0 — the failure surfaces immediately with the actionable "constraint infeasible" diagnostic instead of silently downstream.

2

"Soft expression never overridden — same as hard"

DEBUG
Symptom

A constraint is marked soft "for future override flexibility" but no test ever overrides it. After six months of regression, the soft never yielded.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class xact;
  rand bit [31:0] paddr;
  // Soft "for flexibility" but no one ever overrides
  constraint c { soft paddr inside {[0:'hFFFF]}; }
endclass</code>
Root Cause

Speculative softness costs nothing in solver behaviour (no override = same as hard), but it costs in code clarity — the next maintainer wonders why soft is there and whether it's load-bearing. If nothing overrides it, the marker is noise.

Fix

Remove soft unless and until you have an actual override scenario. Mark a constraint soft when a derived class or test scenario actually needs to override it — not as a "just in case." YAGNI applies to constraint blocks too.

3

"Soft yields when I expected it to stay"

DEBUG
Symptom

A test sets up an inline with clause expecting the class's soft default to also apply. The resulting transaction shows the soft default was dropped.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class xact;
  rand bit [31:0] paddr;
  rand bit [31:0] pwdata;
  constraint c {
    soft paddr inside {[32'h0:32'hFFFF]};
    soft pwdata inside {[32'h0:32'h00FF]};
  }
endclass
 
// Inline only mentions paddr:
tx.randomize() with { paddr inside {[32'h10000:32'h1FFFF]}; };
// User expects: paddr overridden, pwdata still in [0:0xFF]
// Actual: paddr in [0x10000:0x1FFFF], pwdata...?
// Depends on whether pwdata's soft was dropped (it shouldn't be)</code>
Root Cause

Actually this works correctly: only paddr's soft conflicts with the inline, so only that soft is dropped. pwdata's soft is independent and stays in effect. If the user observes pwdata outside [0:0xFF], the cause is elsewhere — usually another inline clause they forgot, or a derived class that also relaxed pwdata.

Fix

Verify with the diagnostic from §11 (log soft-respect flags) before changing code. Soft drops are surgical — they touch only the conflicting expression. If you see broader-than-expected behaviour, look for other overrides in the call chain.

4

"Conflicting soft defaults in parent and child — child's wins?"

DEBUG
Symptom

A child class redeclares a soft default with a different value than the parent's. The developer expected the child's soft to "override" the parent's; actually both are present and the joint constraint set is unsatisfiable.

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class parent_xact;
  rand bit [31:0] paddr;
  constraint c { soft paddr inside {[0:'hFFFF]}; }
endclass
 
class child_xact extends parent_xact;
  constraint c_child { soft paddr inside {[32'h1_0000:32'h1_FFFF]}; }
endclass
 
child_xact c = new();
c.randomize();   // Both softs are active; they don't overlap
// Solver drops one (implementation-defined which)
// Result: arbitrary which range the addr lands in</code>
Root Cause

Inheritance doesn't override constraint blocks — it adds them. Both softs are in the active set; their satisfying sets don't intersect; the solver drops one. Which one gets dropped is implementation-defined, so the resulting behaviour is non-portable.

Fix

Two options. (a) If the child wants a different default range, mark the parent's constraint soft and let the child add a hard constraint that overrides: constraint c_child { paddr inside {[32'h1_0000:32'h1_FFFF]}; } — the hard child wins, the soft parent yields. (b) If both ranges should genuinely apply alternately, restructure with explicit modes via constraint_mode. Two softs on the same field is almost always a design smell.

5

"Inline with uses a value that should have triggered soft drop — but the soft is still active"

DEBUG
Symptom

A test's inline with picks a value within the soft default's range; the developer expects the soft to remain active. Actually, the inline doesn't contradict the soft, so the soft is preserved (correctly).

Buggy Code
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<code>class xact;
  rand bit [31:0] paddr;
  constraint c { soft paddr inside {[0:'hFFFF]}; }
endclass
 
// Inline picks a value INSIDE the soft default's range
tx.randomize() with { paddr == 32'h1234; };
// User expected: soft "yields to inline" because inline mentioned paddr
// Reality: 0x1234 is inside [0:0xFFFF], so soft is satisfied — no yield needed</code>
Root Cause

The soft only yields when there is an actual contradiction. paddr == 0x1234 is consistent with paddr inside {[0:'hFFFF]}, so no conflict exists, and the soft stays active (and happens to also be satisfied). This is correct behaviour, not a bug.

Fix

Understand the model: soft is a "preference unless contradicted." A value inside the soft range doesn't contradict it; only a value outside does. If you wanted to force the soft to yield even on consistent values, the right tool is constraint_mode(0), not inline with.

Interview Q&A — Twelve Questions You Will Be Asked

A constraint expression marked with the soft keyword inside a constraint block. Soft expressions act as preferences: the solver tries to satisfy them along with every other constraint, but if a hard constraint or an inline with contradicts the soft, the solver drops the conflicting soft and re-solves. Soft constraints exist to support overridable defaults.

Best Practices — Ten Rules for soft Discipline

  1. Mark something soft only when an override scenario actually exists. Speculative softness is just noise.
  2. Never mark protocol legality as soft. Alignment, byte-strobe consistency, address-map containment — these are hard contracts the DUT will enforce. Use soft for preferences, never for rules.
  3. Comment every soft default with the rationale. Future readers need to understand whether the default reflects a measured typical case, a coverage convenience, or arbitrary choice.
  4. Use soft instead of constraint_mode when the scenario is "default unless overridden." Saves bookkeeping, eliminates leak risk.
  5. Per-expression granularity matters. Mark each expression individually; mix soft and hard within the same block as needed.
  6. Don't put two conflicting softs on the same field across a parent/child chain. Implementation-defined behaviour is non-portable. Make the parent soft and the child hard.
  7. Log soft-respect flags in post_randomize during bring-up. One bit per soft-constrained field; the log line tells you which softs dropped on which calls.
  8. Use simulator's "report soft drops" mode during initial class design. Verifies your softs yield only when you intend.
  9. Don't confuse soft with dist. Soft is "preferred default, yields on contradiction." Dist is "probabilistic shaping with weights." They serve different needs.
  10. If you find yourself adding many softs to "make a class flexible," reconsider. Excessive softness produces a class whose behaviour depends entirely on call-site inline clauses — at which point a clear inline-only approach may be cleaner.