You are on page 1of 13

SystemVerilog

Constrained Random Stimuli Generation


Ahmed Hemani

System Architecture and Methodology Group Department of Electronic and Computer Systems School of ICT, KTH

Constrained Stimuli Generation


Declarative Define the Stimuli space in an objected oriented way Specify the constraints: Spatial, Temporal Powerful constructs for specifying constraints Powerful constructs for checking the coverage Whats wrong with Directed Testbench ? Boundary conditions are not easily identified Too many boundary conditions Sweep across stimuli space is hardwired: Hard to reuse and hard to maintain The sweep is manually decided and can miss critical corner cases

A Simple Example
rand qualifies properties for which stimuli is to be generated randomly Bus class encapsulates the stimuli space
class Bus; rand bit[15:0] addr; rand bit[31:0] data; constraint word_align {addr[1:0] == 2b0;} endclass

constraint specifies that the constraint solver has to respect while generating random stimuli

Randomize is a built in function that

generates the random stimuli

Bus bus = new; repeat (50) begin if ( bus.randomize() == 1 ) $display ("addr = %16h data = %h\n", bus.addr, bus.data); else $display ("Randomization failed.\n"); end

Inheriting constraints
Often the memory map has holes. This can be captured with an additional constraint. The previous constraint is still valid and respected
typedef enum {devA, devB, devC} DevType; class MyBus extends Bus; rand DevType dev; constraint addr_range { (dev == devA) -> addr inside { [0 : 1023] }; (dev == devB) -> addr inside { [2048 : 4097]}; (dev == devC) -> addr inside {[8195 : 16655]};} endclass

If the derived class has a constraint of the same name as in the parent class, then the parent class constrained is overridden
class A; rand integer x; constraint c { x < 0; } endclass class B extends A; constraint c { x > 0; } endclass

With construct
Additional constraints can be applied with the with construct
task exercise_bus (MyBus bus); int res; // EXAMPLE 1: restrict to low addresses res = bus.randomize() with {dev == devA;}; // EXAMPLE 2: restrict to address between 10 and 20 res = bus.randomize() with {10 <= addr && addr <= 20;}; // EXAMPLE 3: restrict data values to powers-of-two res = bus.randomize() with {data & (data - 1) == 0;}; endtask

Random Variables
Class properties that are not qualified as rand are called state variables Class properties that needs to be randomized can be declared as rand or randc
rand properties have uniform probability distribution randc properties are random-cyclic variables that cycle through

all the values in a random permutation of their declared range

Disabling constraints
constraint_mode(1|0)

can turn ON and OFF named constraints Test benches should inject not just legal stimuli but also see how DUT behaves when illegal stimuli is injected into them.
task exercise_illegal(MyBus bus, int cycles); int res; // Disable word alignment constraint. bus.word_align.constraint_mode(0); repeat (cycles) begin // CASE 1: restrict to small addresses. res = bus.randomize() with {addr[0] || addr[1];}; ... end // Re-enable word alignment constraint bus.word_align.constraint_mode(1); endtask

rand_mode(0|1)

can turn off and on individual rand properties

In-line random variable control


The randomize() method can be used to temporarily control the set of random and state variables within a class instance or object. When the randomize method is called with no arguments, it assigns new values to all random variables that satisfies the constraints. When randomize is called with arguments, those arguments are the only variables that are randomized, rest are treated as state variables:
class CA; rand byte x, y; byte v, w; constraint c1 { x < v && y > w ); endclass CA a = new; a.randomize(); // random variables: x, y state variables: v, w a.Randomize (x); // random variables: x state variables: y, v, w a.Randomize (v, w); // random variables: v, w state variables: x, y a.Randomize (w, x); // random variables: w, x state variables: y, v

Randomizing Dynamic Arrays.


The size of a dynamic array declared as rand or randc can also be constrained. In that case, the array shall be resized according to the size constraint, and then all the array elements shall be randomized. The array size constraint is declared using the size method.
rand bit [7:0] len; rand integer data[]; constraint db {data.size == len; }

Pre and Post randomize


Often there is a need to do things before and after randomization These actions could be might be need to a) trigger golden model, response analysis, b) data logging, c) set state variables to certain values d) print debug statements, e) open and closing files etc.
class XYPair; rand integer x, y; endclass class MyXYPair extends XYPair function void pre_randomize(); super.pre_randomize(); $display("Before randomize x=%0d, y=%0d", x, y); endfunction function void post_randomize(); super.post_randomize(); $display("After randomize x=%0d, y=%0d", x, y); endfunction endclass

External constraint blocks


Constraint block bodies can be declared outside a class declaration, just like external task and function bodies:
// class declaration class XYPair; rand integer x, y; constraint c; endclass // external constraint body declaration constraint XYPair::c { x < y; }

Set Membership
Constraints can be expressed using set membership and its negation.
rand integer x, y, z; constraint c1 {x inside {3, 5, [9:15], [24:32], [y:2*y], z};} rand integer a, b, c; constraint c2 {a inside {b, c};} integer fives[0:3] = {5, 10, 15, 20}; rand integer v; constraint c3 {v inside fives;}

Memory maps Device Registers; their legal value ranges Test modes, states, instructions etc. Are some of the examples for whom constraints are elegantly expressed using sets

Distribution
Set membership construct implicitly expresses uniform distribution in set. In many cases non uniform distribution is required.
// x is equal to 100, 200, or 300 with weighted ratio of 1-2-5

x dist {100 := 1, 200 := 2, 300 := 5} x != 200; // x is equal to 100 or 300 with weighted ratio of 15. x dist {100 := 1, 200 := 2, 300 := 5}
//x is equal to 100, 101, 102, 200, or 300 with a weighted ratio of 1-1-1-2-5

x dist { [100:102] := 1, 200 := 2, 300 := 5} // means x is equal to one of 100, 101, 102, 200, or 300 // with a weighted ratio of 1/3- 1/3- 1/3- 25. x dist { [100:102] :/ 1, 200 := 2, 300 := 5

A dist operation cannot be used for randc variables.

Implication
Constraints can also be expressed using predicated relations. Two constructs: Implication and If Then Else
constraint impl { mode == small -> len < 10; mode == large -> len > 100;} rand bit [3:0] a, b; constraint c { (a == 0) -> (b == 1); }

Both a and b are 4 bits, so there are 256 combinations of a and b. Constraint c eliminates 15 combinations: {0,0}, {0,2}, {0,15}. Therefore, the probability that a == 0 is thus 1/(256-15) or 1/241.
if (mode == small) len < 10; else if (mode == large) len > 100;

Iterative Constraints
Iterative constraints allow arrayed variables to be constrained in a parameterized manner using loop variables and indexing expressions.
class C; rand byte A[] ; constraint C1 { foreach ( A [ i ] ) A[i] inside {2,4,8,16}; } constraint C2 { foreach ( A [ j ] ) A[j] > 2 * j; } endclass

class C; rand int A[] ; constraint c1 { A.size inside {[1:10]}; } constraint c2 { foreach (A[k]) (k < A.size-1) -> A[k+1] > A[k];} endclass

Variable Ordering
All legal combinations have an equal probablity to better explore the whole design space. Sometimes, however, it is desirable to force certain combinations to occur more frequently.
class B; rand bit s; rand bit [31:0] d; constraint c {s -> d == 0; endclass class B; rand bit s; rand bit [31:0] d; constraint c { s -> d == 0; } constraint order {solve s before d;} endclass

The constraint suggests that s determines d, i.e., s is first decided and then d is decided, but in reality s and d are determined together and the right combination retained if it meets the constraint. There are 233 possible combinations of {s, d}, but s is only true for {1,0}. Thus, the probability that s is true is 1/233, which is practically zero.

Functions in Constraints
Functions can make expression of constraints more compact.
constraint C1 { length == count_ones( v ) ; }
function int count_ones ( bit [9:0] w ); for( count_ones = 0; w != 0; w = w >> 1 ) count_ones += w & 1b1; endfunction constraint C2 {length == ((v>>9)&1) + ((v>>8)&1) + ((v>>7)&1) + ((v>>6)&1) + ((v>>5)&1) + ((v>>4)&1) + ((v>>3)&1) + ((v>>2)&1) + ((v>>1)&1) + ((v>>0)&1);}

Note that the two constraints above are not completely equivalent; C2 is bidirectional (length can constrain v and vice-versa), whereas C1 is not.

Constraint Guards
Constraint guards are predicate expressions that prevents the solver from evaluating expressions that could lead to fatal error like evaluation of non-existent object.
class SList; rand int n; rand Slist next; constraint sort { n < next.n; } endclass

constraint sort {if( next != null) n < next.n;}

Dynamic constraint modification


Stimuli Generation is random. Stimuli space can be very large. Functional coverage measures to what extent is the Stimuli Space covered. Based on output of DUT and results of functional coverage it may be desirable to change the constraints dynamically Implication and if...else style constraints allow declaration of predicated constraints. Constraint blocks can be made active or inactive using the constraint_mode() built-in method. Random variables can be made active or inactive using the rand_mode() built-in method. The weights in a dist constraint can be changed, affecting the probability that particular values in the set are chosen.

Randomization of scope variables


Constrained random stimuli generation techniques can also be applied to ordinary scope variables.
module stim; bit [15:0] addr; bit [31:0] data; function bit gen_stim(); bit success, rd_wr; success = randomize (addr, data, rd_wr); // call std::randomize return success; endfunction ... endmodule task stimulus (int length); int a, b, c, success; success = std::randomize (a, b, c) with {a < b ; a + b < length}; ... success = std::randomize (a, b) with {b - a > length}; ... endtask

10

Directly generating Random Nrs.


It is possible to directly invoke the random nr generators
$urandom generates 32 bit unsigned random nr $random generates 32 bit signed nr $urandom (int seed) can be seeded and the pseudo random sequence

will be repeated; helpful for debugging If seeded with time of the day, the sequence will be non deterministic
$urandom_range (<max_val>, <min_val>)

srandom()

sets the range in which random nr generation is to take place method allows manually seeding the Random Number Generator (RNG) of objects or threads

bit [64:1] addr; $urandom( 254 ); // Initialize the generator addr = {$urandom, $urandom }; // 64-bit random number number = $urandom & 15; // 4-bit random number

Random Stability
Random nr generator works independently for each object and thread. This property is called random stability. Test benches with this feature exhibit more stable RNG behavior in the face of small changes to the user code. Additionally, it enables more precise control over the generation of random values by manually seeding threads and objects. Thread Stability Object Stability Manual Seeding

11

randcase
Randcase is a way of randomizing spatial as well temporal properties of stimuli space
randcase randomly selects one of its branches. The randcase item expressions are non-negative integral expressions An items weight divided by the sum of all weights gives the probability of taking that branch.
randcase 3 : 1 : 4 : endcase // the x = 1; x = 2; x = 3; sum of // the // the // the all weights probability probability probability is is is is 8 3/8 or 0.375 1/8 or 0.125 4/8 or 0.5

The randcase weights can be arbitrary expressions, not just constants.


byte a, b; randcase a + b : x = 1; a - b : x = 2; a ^ ~b : x = 3; 12b800 : x = 4; endcase

Random Sequences
It is not enough to spatially sweep the stimuli space. Often individual instructions/IP operations like xmit, receive work But when tried in different sequences, DUTs fail Grammars are the universal ways of specifying languages Programming languages and protocols are specified using BNF notation BNF notation specifies production rules Each production rule is a sequence of tokens. Each token can be a terminal symbol or another production symbol, thus creating a hierarchy.

12

randsequence( main ) main : first second done; // first, second & done are nonterminals first: add | dec ; // randomly select add or dec second: pop | push ; // randomly select pop or push done : { $display("done");}; add : { $display("add");}; dec : { $display("dec");}; pop : { $display("pop");}; push : { $display("push");}; endsequence

add pop done add push done dec pop done dec push done

13

You might also like