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:

RuleExplanation
No Duplicate ConstraintsYou cannot declare two constraints with the same name.
External Constraint ConflictsConflicting constraints will cause errors unless resolved.
Constraint Block for the Same VariableA 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.

Scroll to Top