Just like static variables in a class, constraints can be declared static. A static constraint is shared across every instance of the class — but only in one specific sense: how it responds to being turned on or off.
Constraints are affected by the static keyword only through constraint_mode(). When a non-static constraint is turned off, it's turned off only for the specific instance that made the call. When a static constraint is turned off, it's turned off for every instance of the class at once.
13 min read | Intermediate Level
What You'll Learn
- What makes a static constraint different from the default (non-static) kind
- Why
constraint_mode()only affects one instance for a non-static constraint, but every instance for a static one - How to verify the difference concretely, using one class with both a static and a non-static constraint side by side
Syntax
A constraint block is declared static by including the static keyword in its definition:
class [class_name];
...
static constraint [constraint_name] [definition]
endclass
Non-static Constraints
Constraints are non-static by default, so a separate copy exists for each class instance. Here, both constraints on a are ordinary, non-static blocks:
class ABC;
rand bit [3:0] a;
// Both are non-static constraints
constraint c1 { a > 5; }
constraint c2 { a < 12; }
endclass
module tb;
initial begin
ABC obj1 = new;
ABC obj2 = new;
for (int i = 0; i < 5; i++) begin
obj1.randomize();
obj2.randomize();
$display ("obj1.a = %0d, obj2.a = %0d", obj1.a, obj2.a);
end
end
endmodule
Both constraints are active in both instances, so both consistently land in the range (5, 12):
ncsim> run obj1.a = 9, obj2.a = 6 obj1.a = 7, obj2.a = 11 obj1.a = 6, obj2.a = 6 obj1.a = 9, obj2.a = 11 obj1.a = 6, obj2.a = 9 ncsim: *W,RNQUIE: Simulation is complete.
Static Constraints
Now let's turn off a non-static constraint and compare it against turning off a static one, using the exact same class with one of each.
Turn Off a Non-static Constraint
Here, c1 stays non-static, but c2 is declared static. Only obj1's copy of c1 is disabled:
class ABC;
rand bit [3:0] a;
// "c1" is non-static, but "c2" is static
constraint c1 { a > 5; }
static constraint c2 { a < 12; }
endclass
module tb;
initial begin
ABC obj1 = new;
ABC obj2 = new;
// Turn off non-static constraint
obj1.c1.constraint_mode(0);
for (int i = 0; i < 5; i++) begin
obj1.randomize();
obj2.randomize();
$display ("obj1.a = %0d, obj2.a = %0d", obj1.a, obj2.a);
end
end
endmodule
Output
ncsim> run obj1.a = 3, obj2.a = 6 obj1.a = 7, obj2.a = 11 obj1.a = 6, obj2.a = 6 obj1.a = 9, obj2.a = 11 obj1.a = 6, obj2.a = 9 ncsim: *W,RNQUIE: Simulation is complete.
obj1 produces a value (3) outside c1's a > 5 range — confirming c1 is genuinely off for that instance. obj2's values all stay within (5, 12) throughout, showing its own copy of c1 was never touched.
Quick Check
Q: If obj2.c1.constraint_mode(0) were also called, would that affect obj1 in any way?
Show Answer
No. c1 is non-static, so each instance has a completely independent copy of it — disabling obj2's copy has no effect on obj1's, whether obj1's copy is currently enabled or already disabled.
Turn Off a Static Constraint
This time, the static constraint c2 is disabled — through obj1's handle, but since c2 is static, both instances should be affected:
class ABC;
rand bit [3:0] a;
// "c1" is non-static, but "c2" is static
constraint c1 { a > 5; }
static constraint c2 { a < 12; }
endclass
module tb;
initial begin
ABC obj1 = new;
ABC obj2 = new;
// Turn off static constraint
obj1.c2.constraint_mode(0);
for (int i = 0; i < 5; i++) begin
obj1.randomize();
obj2.randomize();
$display ("obj1.a = %0d, obj2.a = %0d", obj1.a, obj2.a);
end
end
endmodule
Output
ncsim> run obj1.a = 15, obj2.a = 12 obj1.a = 9, obj2.a = 15 obj1.a = 14, obj2.a = 6 obj1.a = 11, obj2.a = 11 obj1.a = 12, obj2.a = 11 ncsim: *W,RNQUIE: Simulation is complete.
Both objects show values exceeding 11 (15, 14, 12 on obj1; 12, 15 on obj2), confirming c2 is genuinely off for both — even though the call was made through obj1's handle alone. c1 (still active, still non-static) continues to keep every value above 5 on both sides.
Quick Check
Q: If a third object, obj3, were constructed after obj1.c2.constraint_mode(0) was called, would obj3's copy of c2 be active or disabled?
Show Answer
Disabled. A static constraint's mode is shared across the entire class, not tied to which instances existed at the time the mode was changed — any instance, including ones created afterward, shares that same static state.
Where Is This Used?
A static constraint fits a rule that should never be selectively bypassed on a per-instance basis — a hard protocol-wide legality boundary, for instance — while still allowing that rule to be switched off entirely for a specific debug scenario or formal setup with a single constraint_mode() call, rather than looping through every existing object individually.
Common Beginner Mistakes
Mistake #1: Assuming static changes how the constraint itself behaves
The static keyword doesn't change the constraint's own logic during randomization at all — both examples still enforce a < 12 identically while c2 is enabled. Why? What static actually changes is purely how constraint_mode() propagates when the constraint is toggled on or off, nothing about the constraint expression itself.
Mistake #2: Assuming disabling a non-static constraint affects other instances
As the first Quick Check shows, it doesn't — each instance has a fully independent copy. Why? Non-static is the default specifically because most constraints are meant to apply per-object, not shared class-wide.
Mistake #3: Forgetting a static constraint's mode change reaches every instance
As the second Quick Check shows, this includes instances created after the mode change, not just ones that already existed. Why? There's only one shared enable/disable state for a static constraint, regardless of how many objects of the class exist or when they were constructed.
Mistake #4: Confusing a static constraint with a static class property
A static class property shares one actual value across every instance; a static constraint shares its enable/disable state, not any value. Why? Constraints don't hold values the way properties do — the only thing static actually shares here is whether the constraint is currently active.
Practice Exercise
Challenge: Disable Through a Different Instance
Given a class with static constraint c_range { val inside {[10:20]}; } and three instances, obj_a, obj_b, and obj_c, predict what happens to obj_a and obj_c after calling obj_b.c_range.constraint_mode(0);.
Hint
It doesn't matter which specific instance's handle is used to call constraint_mode() on a static constraint — only that some instance made the call.
Solution
Both obj_a and obj_c lose the [10:20] restriction too. Since c_range is static, its enable/disable state is shared across the entire class — disabling it through obj_b's handle disables it everywhere, exactly as if it had been called through obj_a or obj_c instead.
Summary
In this tutorial, you learned:
- Constraints are non-static by default, with each class instance holding its own independent copy
- A constraint declared
staticshares its enable/disable state across every instance of the class - Disabling a non-static constraint through one instance's handle has no effect on any other instance
- Disabling a static constraint through any single instance's handle disables it for every instance, including ones created afterward
staticonly changes howconstraint_mode()propagates — it has no effect on the constraint's own logic while active