SystemVerilog Unique Constraint

Unique Constraint

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

Simulator Output

var_1 =  8 
var_2 = 14
var_3 = 11
array = '{'h81, 'h7b, 'h4, 'h47, 'he1, 'h17}

Click to execute on   

unique array of elements example

In below example,
Unique elements for an array is generated by using a unique keyword. Also considered that the value of elements is less than 10.

class unique_elements;
  rand bit [31:0] array[10];
  
  constraint array_c {unique {array};
                      foreach(array[i]) array[i] < 10;}
  
  function void display();
    $display("array = %p",array);
  endfunction
endclass

program unique_elements_randomization;
  unique_elements pkt;

  initial begin
    pkt = new();
    pkt.randomize();
    pkt.display();   
  end
  
endprogram

Simulator Output

array = '{'h5, 'h7, 'h8, 'h1, 'h6, 'h9, 'h2, 'h3, 'h4, 'h0}

Click to execute on   

TODO:
To see the difference, remove “unique {array};” and execute.
Below is the result on removing the “unique {array};” from constraint.

array = '{'h8, 'h4, 'h3, 'h2, 'h3, 'h0, 'h4, 'h8, 'h6, 'h2}

without unique, we can see the repeated values.

❮ Previous Next ❯

SystemVerilog Soft Constraints

Soft Constraints

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.

constraint c_name { soft variable { condition }; }

real-time use of soft 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

Click to execute on   

Using soft constraint

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

Simulator Output

addr = 1
addr = 3

Click to execute on   

❮ Previous Next ❯

SystemVerilog Static Constraints

Static Constraints in SystemVerilog

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.

class packet;
  rand  bit [7:0] addr;
  
  constraint addr_range { addr == 5; }
endclass

module static_constr;
  initial begin
    packet pkt1;
    packet pkt2;
    pkt1 = new();
    pkt2 = new();
    
    $display("Before disabling constraint");    
    pkt1.randomize();
    $display("\tpkt1.addr = %0d",pkt1.addr);
    pkt2.randomize();
    $display("\tpkt2.addr = %0d",pkt2.addr);  
    
    pkt2.addr_range.constraint_mode(0);
    
    $display("After disabling constraint");
    pkt1.randomize();
    $display("\tpkt1.addr = %0d",pkt1.addr);
    pkt2.randomize();
    $display("\tpkt2.addr = %0d",pkt2.addr);      
  end

Simulator Output

Before disabling constraint
pkt1.addr = 5
pkt2.addr = 5
After disabling constraint
pkt1.addr = 5
pkt2.addr = 134

Click to execute on   

turn off static 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.

class packet;
  rand  bit [7:0] addr;
  
  static constraint addr_range { addr == 5; }
endclass

module static_constr;
  initial begin
    packet pkt1;
    packet pkt2;
    pkt1 = new();
    pkt2 = new();

    $display("Before disabling constraint");
    pkt1.randomize();
    $display("\tpkt1.addr = %0d",pkt1.addr);
    pkt2.randomize();
    $display("\tpkt2.addr = %0d",pkt2.addr);    
    
    pkt2.addr_range.constraint_mode(0);
    
    $display("After disabling constraint");
    pkt1.randomize();
    $display("\tpkt1.addr = %0d",pkt1.addr);
    pkt2.randomize();
    $display("\tpkt2.addr = %0d",pkt2.addr);     
  end
endmodule

Simulator Output

Before disabling constraint
pkt1.addr = 5
pkt2.addr = 5
After disabling constraint
pkt1.addr = 22
pkt2.addr = 134

Click to execute on   

❮ Previous Next ❯

SystemVerilog Callback

Callback

What is Callback?

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?

SystemVerilog Callback
SystemVerilog Callback

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
SystemVerilog Callback TestBench Example
SystemVerilog Callback TestBench Example

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
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

class slave_driver;  
  resp_type resp;
endclass
  • Adding response driving task send_response with response randomize logic
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

class slave_driver;
  resp_type resp;
   
  //send response task
  task send_response;
    std::randomize(resp) with { resp == OKAY;};
  endtask
endclass
  • Defining the callback method by declaring the virtual task update_resp
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

class slave_driver;
  resp_type resp;
  
  //callback hook
  virtual task update_resp; endtask
  
  //send response task
  task send_response;
    std::randomize(resp) with { resp == OKAY;};
  endtask
endclass
  • 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
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

class slave_driver;
  resp_type resp;
  
  //callback hook
  virtual task update_resp; endtask
  
  //send response task
  task send_response;
    std::randomize(resp) with { resp == OKAY;};
    update_resp();
  endtask
endclass

Implementing Callback 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
class err_inject extends slave_driver;

endclass
  • Implement the callback method update_resp
class err_inject extends slave_driver;
  virtual task update_resp;
    $display("Injecting SLVERR");
    resp = SLVERR;
  endtask
endclass

Using Callback

A callback can be used by,

  • Writing new error response testcase
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

Click to execute on   

 Note: 

  • To execute basic_test comment error_test.sv
  • To execute error_test comment basic_test.sv

Benefits of callback?

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
  • Makes component reusable

❮ Previous Next ❯

SystemVerilog Callback example

Callbacks in SystemVerilog

For a detailed description of Callback refer to SystemVerilog Callback.

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 the SLVERR response.

Will see through 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
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

class slave_driver;  
  resp_type resp;
endclass
  • Adding response driving task send_response with response randomize logic
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

class slave_driver;
  resp_type resp;
   
  //send response task
  task send_response;
    std::randomize(resp) with { resp == OKAY;};
  endtask
endclass
  • Defining the callback method by declaring the virtual task update_resp
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

class slave_driver;
  resp_type resp;
  
  //callback hook
  virtual task update_resp; endtask
  
  //send response task
  task send_response;
    std::randomize(resp) with { resp == OKAY;};
  endtask
endclass
  • 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
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

class slave_driver;
  resp_type resp;
  
  //callback hook
  virtual task update_resp; endtask
  
  //send response task
  task send_response;
    std::randomize(resp) with { resp == OKAY;};
    update_resp();
  endtask
endclass

Implementing Callback 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
class err_inject extends slave_driver;

endclass
  • Implement the callback method update_resp
class err_inject extends slave_driver;
  virtual task update_resp;
    $display("Injecting SLVERR");
    resp = SLVERR;
  endtask
endclass

Using Callback

A callback can be used by,

  • Writing new error response testcase
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

Click to execute on

 Note: 

  • To execute basic_test comment error_test.sv
  • To execute error_test comment basic_test.sv

❮ Previous Next ❯

SystemVerilog Disable Constraints

Disable Constraints

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

constraint_mode syntax

<object_hanlde>.<constraint_block_name>.constraint_mode(enable);
//enable == 1, constraint block enable
//enable == 0, constraint block disable

constraint disable  examples

without constraint disable

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

Simulator Output

addr = 5

Click to execute on   

with constraint disabled

The constraint is disabled by using the constraint_mode method, so on randomization constraint solver will not consider the constraint.

class packet;
  rand  bit [3:0] addr;
  
  constraint addr_range { addr inside {5,10,15}; }
endclass

module static_constr;
  initial begin
    packet pkt;
    pkt = new();
    
    
    $display("Before Constraint disable");
    repeat(2) begin //{
      pkt.randomize();
      $display("\taddr = %0d",pkt.addr);
    end //}
    
    //disabling constraint
    pkt.addr_range.constraint_mode(0);
    
    $display("After Constraint disable");
    repeat(2) begin //{
      pkt.randomize();
      $display("\taddr = %0d",pkt.addr);
    end //}
  end
endmodule

Simulator Output

Before Constraint disable
addr = 15
addr = 5
After Constraint disable
addr = 9
addr = 14

Click to execute on   

calling constraint_mode method

In the below example,
Constrain_mode is called as method to see to the enable/disable status of constraint.

class packet;
  rand  bit [3:0] addr;
  
  constraint addr_range { addr inside {5,10,15}; }
endclass

module static_constr;
  initial begin
    packet pkt;
    pkt = new();
    
    
    $display("Before Constraint disable");
    $display("Value of constraint mode = %0d",pkt.addr_range.constraint_mode());    
    pkt.randomize();
    $display("\taddr = %0d",pkt.addr);
    
    //disabling constraint
    pkt.addr_range.constraint_mode(0);
    
    $display("After Constraint disable");
    $display("Value of constraint mode = %0d",pkt.addr_range.constraint_mode());    
    pkt.randomize();
    $display("\taddr = %0d",pkt.addr);
    
  end
endmodule

Simulator Output

Before Constraint disable
Value of constraint mode = 1
addr = 15
After Constraint disable
Value of constraint mode = 0
addr = 1

Click to execute on   

❮ Previous Next ❯

SystemVerilog implication if else Constraints

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

Click to execute on   

if else constraints

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

Click to execute on   

❮ Previous Next ❯

SystemVerilog foreach loop Constraint Blocks

foreach constraint

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.

constraint constraint_name { foreach ( variable[iterator] )  variable[iterator] <..conditions..>  }

foreach loop constraint example

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.

Constraining array sizes,
constraint asize     { addr.size < 4; }
constraint dsize     { data.size == addr.size; }

Constraining array elements,
constraint avalues { foreach ( addr[i] ) addr[i] inside {4,8,12,16}; }
constraint dvalues { foreach ( data[j] ) data[j] > 4 * j; }

class packet;
  rand byte addr [];
  rand byte data [];

  constraint avalues { foreach( addr[i] ) addr[i] inside {4,8,12,16}; }
  constraint dvalues { foreach( data[j] ) data[j] > 4 * j; }
  constraint asize   { addr.size < 4; }
  constraint dsize   { data.size == addr.size; }
endclass

module constr_iteration;
  initial begin
    packet pkt;
    pkt = new();

    $display("------------------------------------");
    repeat(2) begin
      pkt.randomize();
      $display("\taddr-size = %0d data-size = %0d",pkt.addr.size(),pkt.data.size());
      foreach(pkt.addr[i]) $display("\taddr = %0d data = %0d",pkt.addr[i],pkt.data[i]);
      $display("------------------------------------");
    end
  end
endmodule

Simulator Output

------------------------------------
addr-size = 2 data-size = 2
addr = 4 data = 101
addr = 16 data = 21
------------------------------------
addr-size = 3 data-size = 3
addr = 16 data = 89
addr = 4 data = 19
addr = 16 data = 13
------------------------------------

Click to execute on   

❮ Previous Next ❯

SystemVerilog distribution Constraint

dist Constraint in SystemVerilog

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.

addr dist { 2 := 5, [10:12] := 8 };

for addr == 2 , weight 5
    addr == 10, weight 8
    addr == 11, weight 8
    addr == 12, weight 8

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.

addr dist { 2 :/ 5, [10:12] :/ 8 };

for addr == 2 , weight 5
    addr == 10, weight 8/3
    addr == 11, weight 8/3
    addr == 12, weight 8/3

weighted distribution constraint examples

randomization with dist operator

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

Simulator Output

------------------------------------
addr = 10
addr = 7
addr = 10
addr = 10
addr = 10
addr = 7
addr = 7
addr = 2
addr = 10
addr = 10
------------------------------------

Click to execute on   

difference between := and :/ dist operator

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

Simulator Output

------------------------------------
addr_1 = 2
addr_1 = 12
addr_1 = 12
addr_1 = 12
addr_1 = 11
addr_1 = 10
addr_1 = 11
addr_1 = 2
addr_1 = 11
addr_1 = 12
------------------------------------
------------------------------------
addr_2 = 10
addr_2 = 12
addr_2 = 2
addr_2 = 2
addr_2 = 10
addr_2 = 10
addr_2 = 2
addr_2 = 11
addr_2 = 11
addr_2 = 12
------------------------------------

Click to execute on   

❮ Previous Next ❯

SystemVerilog Constraint inside

Constraint inside SystemVerilog

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 {}
    constraint addr_range { addr inside { ... }; }
  • the range is specified by [ ]
    constraint addr_range { addr inside { [5:10]}; }
  • set of values are specified by ‘comma’,
    constraint addr_range { addr inside { 1,3,5,7,9}; }
  • it is allowed to mix range and set of values
    constraint addr_range { addr inside {1,3,[5:10],12,[13:15]}; }
  • if the value needs to be outside the range, then it can be specified as inverse (!) of inside
    constraint addr_range { addr !(inside {[5:10]}); }
  • Other random variables can be used in inside block
          rand bit [3:0] start_addr;
          rand bit [3:0] end_addr;
          rand bit [3:0] addr;
          constraint addr_range { addr inside {[start_addr:end_addr]}; }

constraint inside example

In the example below,
addr_1 will get random value within the range start_addr and end_addr,

class packet;
  rand bit [3:0] addr;
  rand bit [3:0] start_addr;
  rand bit [3:0] end_addr;
  
  constraint addr_1_range { addr inside {[start_addr:end_addr]}; }
endclass

module constr_inside;
  initial begin
    packet pkt;
    pkt = new();
    $display("------------------------------------");
    repeat(3) begin
      pkt.randomize();
      $display("\tstart_addr = %0d,end_addr = %0d",pkt.start_addr,pkt.end_addr);
      $display("\taddr = %0d",pkt.addr);
      $display("------------------------------------");
    end
  end
endmodule

Simulator Output

------------------------------------
start_addr = 12,end_addr = 13
addr = 12
------------------------------------
start_addr = 3,end_addr = 7
addr = 7
------------------------------------
start_addr = 5,end_addr = 11
addr = 9
------------------------------------

Click to execute on   

inverted inside example

In the example below,
addr will get the random value outside the range start_addr and end_addr. this is done by using negation or invert operator (!)

class packet;
  rand bit [3:0] addr;
  rand bit [3:0] start_addr;
  rand bit [3:0] end_addr;
  
  constraint addr_1_range { !(addr inside {[start_addr:end_addr]}); }
endclass

module constr_inside;
  initial begin
    packet pkt;
    pkt = new();
    $display("------------------------------------");
    repeat(3) begin
      pkt.randomize();
      $display("\tstart_addr = %0d,end_addr = %0d",pkt.start_addr,pkt.end_addr);
      $display("\taddr = %0d",pkt.addr);
      $display("------------------------------------");
    end
  end
endmodule

Simulator Output

------------------------------------
start_addr = 12,end_addr = 4
addr = 0
------------------------------------
start_addr = 6,end_addr = 7
addr = 13
------------------------------------
start_addr = 5,end_addr = 9
addr = 11
------------------------------------

Click to execute on   

❮ Previous Next ❯