SystemVerilog randomize with {}: Inline Constraints
randomize() picks legal random values for the rand fields of a class, but the rules it obeys do not have to live inside the class. The SystemVerilog randomize with construct lets you attach extra constraints at the exact call site, so one object can be shaped differently every time you randomize it. This page walks through the inline with {} block, soft constraints, constraint_mode() and rand_mode(), with examples you can run in the browser.
Every example uses a top module named tb and a class with rand members. Use the Simulation log tab on the runnable blocks to see the actual randomized values your simulator produces.
The inline with {} block
Writing obj.randomize() with { ... } adds the listed constraints to whatever the class already declares, only for that single call. The expressions inside the braces are ordinary constraint expressions: equalities, inequalities, inside ranges, implications and so on. Member names such as len refer to the object being randomized, so you do not prefix them with the handle.
class Packet;
rand bit [7:0] len;
rand bit [1:0] prio;
endclass
module tb;
Packet p = new();
int ok;
initial begin
for (int i = 0; i < 4; i++) begin
ok = p.randomize() with { len inside {[8:16]}; prio == 2'b11; };
if (ok == 0)
$display("trial %0d: randomize failed", i);
else
$display("trial %0d: len=%0d prio=%0d", i, p.len, p.prio);
end
$finish;
end
endmoduletrial 0: len=10 prio=3 trial 1: len=9 prio=3 trial 2: len=14 prio=3 trial 3: len=8 prio=3
In the run above, prio is pinned to 3 and len always lands between 8 and 16, call after call. The constraints in the with block are combined with the class constraints using logical AND; if the two sets contradict each other the solver fails and randomize() returns 0.
What can go inside the braces
The inline block accepts the same operators you would use in a named constraint. The most common building blocks are:
a inside {[lo:hi], v1, v2}restricts a value to a set or range.cond -> expris implication: whencondholds,exprmust also hold.a == b * 4expresses a relational tie between fields, solved together, not in order.x dist { ... }gives a weighted distribution that biases some values over others.
Because all constraints are solved simultaneously, the position of an expression in the block does not matter. You are describing a set of legal solutions, not a sequence of assignments that run top to bottom. An inline block can also reference variables from the surrounding testbench: a name that is not a class member is read from the enclosing scope, and the local:: prefix forces the testbench value when a member would otherwise shadow it. That lets a test compute a bound at runtime and feed it straight into the constraint.
Soft constraints: defaults that bend
A plain constraint is hard: break it and randomization fails. A soft constraint states a preference instead. The solver honours it only when nothing else conflicts; a hard constraint, including one added through with {}, overrides it without error. Soft constraints are the clean way to give a class a sensible default that any test can replace without editing the class.
class Transfer;
rand bit [3:0] burst;
constraint c_default { soft burst == 1; }
endclass
module tb;
Transfer t = new();
int ok;
initial begin
ok = t.randomize();
$display("default : burst=%0d", t.burst);
ok = t.randomize() with { burst inside {[4:8]}; };
$display("overridden : burst=%0d", t.burst);
ok = t.randomize() with { burst == 2; };
$display("hard set : burst=%0d", t.burst);
$finish;
end
endmoduleWith only the soft default active, burst comes out as 1. The second call adds a hard inside range, so the solver drops the soft preference and picks a value from 4 to 8. The third call forces burst == 2. Simulator support for soft varies, so this block is shown for syntax only; if your tool reports an unsatisfied-constraint warning, model the default with a normal constraint plus constraint_mode() instead.
constraint_mode(): switching rules off
Every named constraint block can be turned off and on at runtime with constraint_mode(). Call it on a single constraint handle to disable just that rule, or on the object itself to disable all of them at once. A disabled constraint is ignored by the next randomize() until you switch it back on.
class Addr;
rand bit [7:0] addr;
constraint c_align { addr % 4 == 0; }
constraint c_low { addr < 16; }
endclass
module tb;
Addr a = new();
int ok;
initial begin
ok = a.randomize();
$display("both on : addr=%0d (multiple of 4 and < 16)", a.addr);
a.c_low.constraint_mode(0); // switch off only the "addr < 16" rule
ok = a.randomize();
$display("low off : addr=%0d (still a multiple of 4)", a.addr);
a.constraint_mode(0); // switch off every constraint in the object
ok = a.randomize() with { addr == 77; };
$display("all off : addr=%0d (only the inline rule is left)", a.addr);
$finish;
end
endmoduleboth on : addr=0 (multiple of 4 and < 16) low off : addr=20 (still a multiple of 4) all off : addr=77 (only the inline rule is left)
After c_low.constraint_mode(0) the alignment rule still applies but the upper bound is gone, so values can climb past 16. After a.constraint_mode(0) both class rules are off and only the inline addr == 77 decides the result. This is how a directed test reuses a random class while suppressing selected rules.
rand_mode(): controlling randomization per call
Where constraint_mode() enables or disables rules, rand_mode() controls whether a variable is randomized at all. Setting field.rand_mode(0) makes the solver treat that field as a fixed constant: it keeps its current value and the solver works around it. Setting it back to 1 returns the field to the random pool.
class Frame;
rand bit [7:0] id;
rand bit [7:0] data;
endclass
module tb;
Frame f = new();
int ok;
initial begin
// Randomize both fields, tying data to id for this call only.
ok = f.randomize() with { id inside {[1:4]}; data == id * 16; };
$display("call 1 : id=%0d data=%0d", f.id, f.data);
// Freeze id: rand_mode(0) makes the solver treat it as a constant.
f.id.rand_mode(0);
ok = f.randomize() with { data inside {[200:255]}; };
$display("call 2 : id=%0d data=%0d (id frozen)", f.id, f.data);
// Thaw id again and randomize both fields together.
f.id.rand_mode(1);
ok = f.randomize() with { id > 100; data < 16; };
$display("call 3 : id=%0d data=%0d (id active again)", f.id, f.data);
$finish;
end
endmodulecall 1 : id=1 data=16 call 2 : id=1 data=234 (id frozen) call 3 : id=169 data=15 (id active again)
In call 2 the frozen id holds its value while data is randomized around it. In call 3 both fields are active again. Combined with inline with {} constraints, rand_mode() gives you fine control over which fields move on each call without touching the class definition.
constraint_mode() vs rand_mode()
These two controls are easy to confuse because both relax randomization, but they act on different things. constraint_mode() acts on a rule: the variables stay random, but one relationship between them stops being enforced. rand_mode() acts on a variable: the rules that mention it still exist, but the field itself no longer varies. Reach for constraint_mode() when you want to loosen a restriction and still get fresh values, and rand_mode() when you want a specific field to stand still while the rest of the object is randomized.
Always test the return value
randomize() returns 1 on success and 0 when the constraints cannot be satisfied. Each example captures it in an int and checks it; ignoring the result means a failed solve passes unnoticed and stale values leak into your stimulus. A failed randomize does not stop the simulation on its own, so the check is yours to write.
Quick reference
| Construct | Scope | Effect |
|---|---|---|
randomize() with {} | one call | adds constraints for that call only |
soft constraint | class default | a preference; any hard constraint overrides it |
constraint_mode(0/1) | named constraint or object | turns a rule off or on |
rand_mode(0/1) | a rand variable | freezes or thaws that variable |
Quick check
What happens when an inline with {} constraint contradicts a hard class constraint?
Both sets are hard and are ANDed together. No value satisfies both, so randomize() returns 0 and the fields keep their previous contents.
How is a soft constraint different from a normal one?
It is only a preference. The solver drops a soft constraint whenever a hard constraint, in the class or in a with {} block, conflicts with it, instead of failing the call.
You want a rand field to keep its current value for a single randomize() call. Which control do you use?
Call field.rand_mode(0) to freeze the variable; the solver treats it as a constant until you call rand_mode(1) again.
Does the order of expressions inside a with {} block matter?
No. Every constraint is solved simultaneously as one set of relations, not executed from top to bottom.
Share your question in comments or talk to our mentor team for batch guidance.
Compile and simulate this in the browser — no install. Edit the code and re-run instantly.
Learn Verilog with mentors, labs and placement support
This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.
Explore VLSI Courses