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):

Output
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

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

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 static shares 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
  • static only changes how constraint_mode() propagates — it has no effect on the constraint's own logic while active
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5