In SystemVerilog, constraint blocks are used to restrict the values that random variables can take. These blocks act as class members, similar to variables, functions, and tasks. They play an important role in controlling the randomization of variables to ensure that certain conditions are met.
What Are Constraint Blocks?
A constraint block is a special construct that allows you to define conditions that random variables must satisfy during randomization. These conditions are set using expressions within the constraint block. The syntax for a constraint block looks like this:
constraint [name_of_constraint] {
[expression 1];
[expression N];
}
The expressions inside the curly braces {}
define the rules for the randomization of variables. These constraints can be applied to multiple variables, and it is not mandatory to have separate constraint blocks for each variable. However, conflicting constraints across different blocks are not allowed, unless you disable them using the constraint_mode()
method.
Key Points:
- An empty constraint will not affect randomization.
- Constraints can be applied inside or outside the class body.
Example of Using Constraint Blocks
Here are a few examples of how constraint blocks work in practice.
Defining Constraints in a Class
Let’s create a simple class that defines random variables and constraints. The class Packet
contains a variable addr
that must satisfy certain conditions when randomized.
class Packet;
rand bit [31:0] addr;
rand bit [7:0] burst;
rand bit [7:0] len;
rand bit [7:0] size;
// Constraint block for valid address
constraint valid_addr {
addr >= 32'hf0000000;
addr <= 32'hfaceface;
}
// Constraint block for burst parameters
constraint fast_burst {
burst >= 3;
len >= 64;
size >= 128;
}
endclass
In this example, valid_addr
ensures that addr
falls within a specific range, while fast_burst
sets limits for the burst
, len
, and size
variables.
Error and Conflict Handling
It’s important to note that constraints can conflict. For example, if you try to declare two constraints that contradict each other, such as setting addr
to be greater than 32'hfaceffff
and less than 32'hf0000000
, this will lead to a runtime error.
// This will cause an error due to conflicting constraints
constraint valid {
addr >= 32'hfaceffff;
}
The solver will fail in this case because it cannot find an address that satisfies both conditions. However, constraints can be adjusted and managed, as we will discuss later.
In-Class Constraint Example
Let’s now look at an example where we define constraints inside a class body to control the range of a variable called mode
.
class ABC;
rand bit [3:0] mode;
// Constraint for mode variable to be between 2 and 6
constraint c_mode {
mode > 2;
mode <= 6;
}
endclass
module tb;
ABC abc;
initial begin
abc = new(); // Create a new object of class ABC
// Randomize the mode variable 5 times and display its value
for (int i = 0; i < 5; i++) begin
abc.randomize(); // Randomize the class object
$display("mode = 0x%0h", abc.mode);
end
end
endmodule
Expected Simulation Log
When you run the above code, the mode
variable will always fall between the values of 2 and 6. Here’s a sample log output:
ncsim> run
mode = 0x6
mode = 0x6
mode = 0x5
mode = 0x4
mode = 0x5
ncsim: *W,RNQUIE: Simulation is complete.
External Constraints
External constraints are constraints that are defined outside the class body. These constraints can either be implicit or explicit.
Implicit Constraints
An implicit constraint is one that is defined without the extern
keyword. In this case, the constraint is automatically associated with the class.
constraint c_implicit { mode > 2; };
Explicit Constraints
An explicit constraint requires the extern
keyword and is referenced using the scope resolution operator ::
.
constraint ABC::c_explicit { mode <= 6; };
Full Example with External Constraints
class ABC;
rand bit [3:0] mode;
constraint c_implicit; // Implicit constraint
extern constraint c_explicit; // Explicit external constraint
endclass
// Defining the external constraints outside the class
constraint ABC::c_implicit { mode > 2; };
constraint ABC::c_explicit { mode <= 6; };
module tb;
ABC abc;
initial begin
abc = new(); // Create a new object
// Randomize and display the value of mode
for (int i = 0; i < 5; i++) begin
abc.randomize();
$display("mode = 0x%0h", abc.mode);
end
end
endmodule
Expected Simulation Log
mode = 0x3
mode = 0x5
mode = 0x6
mode = 0x4
mode = 0x6
Important Rules for Constraints
Here are some rules to remember when using constraints in SystemVerilog:
Rule | Explanation |
---|---|
No Duplicate Constraints | You cannot declare two constraints with the same name. |
External Constraint Conflicts | Conflicting constraints will cause errors unless resolved. |
Constraint Block for the Same Variable | A variable cannot have multiple constraint blocks with the same name. |
Conclusion
SystemVerilog constraint blocks are powerful tools for controlling randomization. They allow you to impose conditions on random variables, making your simulations more realistic and controlled. Remember to handle potential conflicts and apply constraints appropriately, whether they are in-class or external.