SystemVerilog constraint defined with the keyword unique is called as a unique constraint. On randomization, unique values to set of variables or unique elements to an array can be generated by using unique constraints.
Unique constraint allows us to,
Generate unique values across the variables
Generate unique elements in an array (Fixed Size Array, Dynamic Array, Associative array and Queue)
constraint c_name { unique {variable's/array}; }
Below example shows,
Generation of random unique values to the variables var_1, var_2 and var_3
Generation of random unique elements to an array array
Unique constraint example
Unique elements
In the below example,
On randomization unique values to a variable var_1, var_2, var_3 can be obtained by writing unique constraints. Also, a unique constraint is written to an array to get unique array elements.
class unique_elements;
rand bit [3:0] var_1,var_2,var_3;
rand bit [7:0] array[6];
constraint varis_c {unique {var_1,var_2,var_3};}
constraint array_c {unique {array};}
function void display();
$display("var_1 = %p",var_1);
$display("var_2 = %p",var_2);
$display("var_3 = %p",var_3);
$display("array = %p",array);
endfunction
endclass
program unique_elements_randomization;
unique_elements pkt;
initial begin
pkt = new();
pkt.randomize();
pkt.display();
end
endprogram
SystemVerilog constraints declared with the keyword soft is called as soft constraints. any conflict between class constraint and inline constraint leads to a randomization failure, from this it is clear that it is not possible to override the class constraint by inline constraint. Some test scenarios demand to override the constraints, this can be done by writing a soft keyword in class constraint.
A soft constraint is a constraint on a random variable, which allows overriding the constraint.
This is one of the situations where soft constraints are useful. Lets Consider, In a verification testbench transaction class constraint is written to generate normal stimulus. For error stimulus generation, error testcase need to have an inline constraint that may conflict with the constraint defined inside the class. In this situation, we have only the option to change the constraint defined inside the transaction class, but changing the constraint in the transaction class will reflect in all other test cases. so this kind of problem can be avoided using soft constraints.
soft constraint examples
Conflict between constraints
In the example below, In the class packet, the addr variable is constrained to greater than 6 and the same addr variable is constrained to less than 6 in the inline constraint. that means expecting the value of addr to be less than and greater than 6, this is not possible and leads to a randomization failure. this problem is resolved in the next example using soft constraint.
class packet;
rand bit [3:0] addr;
constraint addr_range { addr > 6; }
endclass
module soft_constr;
initial begin
packet pkt;
pkt = new();
repeat(2) begin
pkt.randomize() with { addr < 6;};
$display("\taddr = %0d",pkt.addr);
end
end
endmodule
Simulator Output
Constraints inconsistency failure Constraints are inconsistent and cannot be solved. Please check the inconsistent constraints being printed above and rewritethem. addr = 0
In the example below, a previous example problem is solved using soft constraints, Constraint declared inside the class will get suppressed by inline constraints.
class packet;
rand bit [3:0] addr;
constraint addr_range { soft addr > 6; }
endclass
module soft_constr;
initial begin
packet pkt;
pkt = new();
repeat(2) begin
pkt.randomize() with { addr < 6;};
$display("\taddr = %0d",pkt.addr);
end
end
endmodule
SystemVerilog static constraints are similar to static class properties. A constraint block can be defined as static by including the static keyword in its definition. constraint block with the static keyword followed by constraint keyword is called as a static constraint. the static constraint is shared across all the class instances.
only the mode change of static constraint will get affected in all the instances of a class
mode change is enable or disable of a constraint by constrain_mode() method
a static class can be enabled or disabled by any object handle of its class, mode change with one object handle will reflect all other objects of same class type
Static constraint syntax
static constraint constraint_name { ....; }
Static constraint examples
turn off non-static constraint
In the below example,
The class packet has two instances pkt1 and pkt2. constraint addr_range is defined to control the value of random variable addr.
On randomization, pkt1.addr and pkt2.addr will take value based on the constraint.
The constraint is disabled using a pkt2 handle. As constraint is non-static only for pkt2 constraint will get disabled. On randomization, pkt1.addr will get value based on the constraint.
The example below is the same as the above example, the only change is the constraint is made as static.
The constraint is disabled by using one of the object handles. as the constraint is static in nature, the constraint will get disabled for both the objects.
As per the English dictionary, Callback definition is ‘a return call‘
What is SystemVerilog Callback?
SystemVerilog callback specifies the rules to define the methods and placing method calls to achieve ‘a return call to methods’.
In simple words,
Callbacks are empty methods with a call to them.
or
A method of the class is implemented with calls to dummy methods. On a need basis, the user can extend the class and implement the dummy methods.
Where,
Dummy methods are callback methods
Calls to dummy methods are callback hooks
Note:
There won’t be any impact for not implementing the Callback methods.
How callback works?
In the above diagram,
temp() is the method call to invoke a method temp
method temp has few statements (logic) also calls to callback_1 and callback_2
callback_1 and callback_2 are dummy methods without any logic in it.
On calling callback_1() and callback_2() there won’t be any impact to regular logic
On a need basis, the user can extend the class and add required logic to callback_1 and callback_2 without modifying the method temp
“randomize” is one of the SystemVerilog builtin methods which has the callback features implemented in it.
randomize method is implemented with the callback features to enable the execution of pre_randomize() and post_randomize() methods before and after the randomize() method execution respectively.
This is done by placing the callback hooks to pre_randomize() and post_randomize() methods in it.
Methods will get executed in the order mentioned below,
pre_randomize();
randomize();
pre_randomize();
If required user can implement the pre_randomize() and post_randomize() methods.
How to implement callback?
Below is one of the ways to implement the SystemVerilog callback.
Write a method which has calls (callback hooks) to dummy methods
Write dummy callback methods
How to use callback?
Extend the class and implement the callback method
Override the existing class by extended class
Callback example
Let’s consider an example of a Slave Driver (Slave Driver: drives response to the master).
For simplicity, one callback hook is implemented and only response generation logic is captured in the code.
Components of slave_driver example are,
slave_driver – Normal driver to drive response
response types are OKAY, EXOKAY, SLVERR, DECERR
slave_driver is constrained to send OKAY response always to see to the callback usage difference
slave_env – Environment which has a slave driver created in it
basic_test – Which sends the normal response
error_test – Testcase with callback method used to generate an error response
err_inject – extended driver class to implement the callback method
By using a callback, will implement the testcase to drive SLVERR response.
Will see though the below steps,
Adding Callback Support
Implementing Callback Method
Using Callback
Adding Callback Support
In this step, will write the driver with a dummy method and callback hooks to it.
Writing slave_driver class with enum variable resp
Placing hook for callback. In this example, as it is required to change the response once it is generated, so it is good to place callback hook after calling the randomize method
For error response generation scenario, it is required to corrupt the response generated.
This can be achieved by adding the logic in update_resp() callback to overwrite the response generated.
Which involves below steps.
extend the slave_driver and write new driver err_inject
program error_test;
slave_env env;
initial begin
//Create env
env = new();
//Calling run of env
env.run();
end
endprogram
Declare and create an err_inject driver
program error_test;
slave_env env;
err_inject err_driver;
initial begin
//Create env
env = new();
err_driver = new();
//Calling run of env
env.run();
end
endprogram
Override the slave_driver by the new err_inject driver
program error_test;
slave_env env;
err_inject err_driver;
initial begin
//Create env
env = new();
err_driver = new();
//Overriding slave_driver by error_driver
env.slv_driver = err_driver;
//Calling run of env
env.run();
end
endprogram
Simulator Output of basic_test
Slave generated response is OKAY
Slave generated response is OKAY
Simulator of error_test
Injecting SLVERR
Slave generated response is SLVERR
Injecting SLVERR
Slave generated response is SLVERR
By looking into the above slave_driver examples we could say that without modifying the existing environment it is possible to achieve error injection.
Easy to add additional functionality to existing logic
Placing hook for a callback. In this example, as it is required to change the response once it is generated, so it is good to place callback hook after calling the randomize method
For the error response generation scenario, it is required to corrupt the response generated.
This can be achieved by adding the logic in update_resp() callback to overwrite the response generated.
Which involves below steps.
extend the slave_driver and write new driver err_inject
program error_test;
slave_env env;
initial begin
//Create env
env = new();
//Calling run of env
env.run();
end
endprogram
Declare and create an err_inject driver
program error_test;
slave_env env;
err_inject err_driver;
initial begin
//Create env
env = new();
err_driver = new();
//Calling run of env
env.run();
end
endprogram
Override the slave_driver by the new err_inject driver
program error_test;
slave_env env;
err_inject err_driver;
initial begin
//Create env
env = new();
err_driver = new();
//Overriding slave_driver by error_driver
env.slv_driver = err_driver;
//Calling run of env
env.run();
end
endprogram
Simulator Output of basic_test
Slave generated response is OKAY
Slave generated response is OKAY
Simulator of error_test
Injecting SLVERR
Slave generated response is SLVERR
Injecting SLVERR
Slave generated response is SLVERR
Constraints in a class can be disabled using the constraint_mode method call. By default all the constraints will be enabled, during the randomization constraint solver will not consider the disabled constraints. the constraint disables method is similar to rand_mode() method.
constraint_mode() method
The constraint_mode() method can be used to disable any particular constraint block.
constraint_mode(1) means constraint block is enabled
constraint_mode(0) means constraint block is disabled
default value of constraint_mode is 1, i.e enabled
once the constraint block is disabled, it is required to make constraint_mode(1) enable back the constraint block
constraint_mode can be called as like SystemVerilog method, which returns the enable/disable status of a constraint block
In the below example,
The constraint is enabled by default, so on randomization constraint solver will consider the constraint and assigns the random value to variable addr as per the constraint is written.
class packet;
rand bit [3:0] addr;
constraint addr_range { addr inside {5,10}; }
endclass
module static_constr;
initial begin
packet pkt;
pkt = new();
pkt.randomize();
$display("\taddr = %0d",pkt.addr);
end
endmodule
Implication constraints and if else constraints in SystemVerilog
Implication constraints
The implication operator can be used to declaring conditional relations between two variables. implication operator is denoted by the symbol ->. The implication operator is placed between the expression and constraint.
expression -> constraint
If the expression on the LHS of implication operator (->) is true, then the only constraint on the RHS will be considered.
Implication constraint example
In the example below,
If addr_range == small, then addr will get a value less than 8.
i.e implication operator is used to mention condition between the two variables addr_range and addr.
class packet;
rand bit [3:0] addr;
string addr_range;
constraint address_range { (addr_range == "small") -> (addr < 8);}
endclass
module constr_implication;
initial begin
packet pkt;
pkt = new();
pkt.addr_range = "small";
$display("------------------------------------");
repeat(4) begin
pkt.randomize();
$display("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
end
$display("------------------------------------");
end
endmodule
Simulator Output
------------------------------------
addr_range = small addr = 6
addr_range = small addr = 2
addr_range = small addr = 1
addr_range = small addr = 4
------------------------------------
if else block allows conditional executions of constraints. If the expression is true, all the constraints in the first constraint/constraint-block must be satisfied, otherwise all the constraints in the optional else constraint/constraint-block must be satisfied.
if else constraints example
Above an example of implication operator usage is written with if else condition.
In the example below,
If addr_range == small, then addr will get a value less than 8.
class packet;
rand bit [3:0] addr;
string addr_range;
constraint address_range { if(addr_range == "small")
addr < 8;
else
addr > 8;
}
endclass
module constr_if_else;
initial begin
packet pkt;
pkt = new();
pkt.addr_range = "small";
$display("------------------------------------");
repeat(3) begin
pkt.randomize();
$display("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
end
$display("------------------------------------");
pkt.addr_range = "high";
$display("------------------------------------");
repeat(3) begin
pkt.randomize();
$display("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
end
$display("------------------------------------");
end
endmodule
Simulator Output
------------------------------------
addr_range = small addr = 1
addr_range = small addr = 4
addr_range = small addr = 6
------------------------------------
------------------------------------
addr_range = high addr = 12
addr_range = high addr = 15
addr_range = high addr = 9
------------------------------------
SystemVerilog supports using the foreach loop inside a constraint block. using the foreach loop within the constraint block will make easy to constrain an array. The foreach loop iterates over the elements of an array, so constraints with the foreach loop are called Iterative constraints.
the foreach constraint will be applicable to an array with one or more than one element. so it’s required to specify or constrain the size of the dynamic array.
In the below example,
addr and data are the two dynamic arrays, the first size of the arrays is constrained and then the values for each array element are constrained using a foreach loop.
Constraint provides control on randomization, from which the user can control the values on randomization. it would be good if it’s possible to control the occurrence or repetition of the same value on randomization.yes its possible, with dist operator, some values can be allocated more often to a random variable. this is called a weighted distribution. dist is an operator, it takes a list of values and weights, separated by := or :/ operator.
weighted distribution
As the name says, in weighted distribution weight will be specified to the values inside the constraint block. Value with the more weight will get allocated more often to a random variable.
syntax
value := weight or
value :/ weight
Value – desired value to a random variable
weight – indicates how often the value needs to be considered on randomization
The values and weights can be constants or variables,
value can be single or a range
the default weight of an unspecified value is := 1
the sum of weights need not be a 100
The := operator assigns the specified weight to the item, or if the item is a range, specified weight to every value in the range.
The :/ operator assigns the specified weight to the item, or if the item is a range, specified weight/n to every value in the range. where n is the number of values in the range.
In the example below,
On randomization, the possibility of ‘addr’ is getting the value of 10 is more than 7 and 2. this is because of weight specified to get value 10 is more than the other two values.
class packet;
rand bit [3:0] addr;
constraint addr_range { addr dist { 2 := 5, 7 := 8, 10 := 12 }; }
endclass
module constr_dist;
initial begin
packet pkt;
pkt = new();
$display("------------------------------------");
repeat(10) begin
pkt.randomize();
$display("\taddr = %0d",pkt.addr);
end
$display("------------------------------------");
end
endmodule
In the below example,
addr_1=2 weight=5, and addr_1=10 weight=8, addr_1=11 weight=8, addr_1=12 weight=8
addr_1=2 weight=5, and addr_1=10 weight=8/3=2.66, addr_1=11 weight=2.66, addr_1=12 weight=2.66
class packet;
rand bit [3:0] addr_1;
rand bit [3:0] addr_2;
constraint addr_1_range { addr_1 dist { 2 := 5, [10:12] := 8 }; }
constraint addr_2_range { addr_2 dist { 2 :/ 5, [10:12] :/ 8 }; }
endclass
module constr_dist;
initial begin
packet pkt;
pkt = new();
$display("------------------------------------");
repeat(10) begin
pkt.randomize();
$display("\taddr_1 = %0d",pkt.addr_1);
end
$display("------------------------------------");
$display("------------------------------------");
repeat(10) begin
pkt.randomize();
$display("\taddr_2 = %0d",pkt.addr_2);
end
$display("------------------------------------");
end
endmodule
During randomization, it might require to randomize the variable within a range of values or with inset of values or other than a range of values. this can be achieved by using constraint inside operator.With SystemVerilog inside operator, random variables will get values specified within the inside block.
values within the inside block can be variable, constant or range
the inside block is written with an inside keyword followed by curly braces {}
We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.Ok