Section 12.2

LRM-71

Changes (change in red):

typedef enum {low, mid, high} AddrType;

 

class MyBus extends Bus;

rand AddrType atype;

constraint addr_range

{

(atype == low ) => -> addr inside { [0 : 15] };

(atype == mid ) => -> addr inside { [16 : 127]};

(atype == high) => -> addr inside {[128 : 255]};

}

endclass

LRM-71

Changes (change in red):

      Constraints interact bidirectionally. In this example, the value chosen for addr depends on atype and how it is constrained, and the value chosen for atype depends on addr and how it is constrained. All expression operators are treated bidirectionally, including the implication operator (=> ->).

LRM-54

Changes (change in red):

Occasionally, it is desirable to perform operations immediately before or after randomization. That is accomplished via two built-in methods, pre_randomize() and post_randomize(), which are automatically called before and after randomization. These methods can be overridden overloaded with the desired functionality:

LRM-54

Changes (change in red):

By default, pre_randomize() and post_randomize() call their overridden overloaded parent class methods. When pre_randomize() or post_randomize() are overridden overloaded, care must be taken to invoke the parent class’ methods, unless the class is a base class (has no parent class), otherwise the base class methods shall not be called.

Section 12.4

LRM-63 LRM-70 LRM-71

Changes in Syntax 12-2 (change in red):

constraint_declaration ::=

[ static ] constraint constraint_identifier { { constraint_block } }

 

constraint_block ::=

  solve [ priority ]  identifier_list before identifier_list ;

| expression dist { dist_list } ;

| constraint_expression

 

constraint_expression ::=

  expression ;

| expression => -> constraint_set

| if ( expression ) constraint_set [ else constraint_set ]

| expression dist { dist_list } ;

| foreach ( array_identifier [ loop_variables ] ) constraint_set

 

constraint_set ::=

  constraint_expression

| { { constraint_expression } }

 

dist_list ::= dist_item { , dist_item }

 

dist_item ::=

  value_range := expression

| value_range :/ expression

 

constraint_prototype ::= [ static ] constraint constraint_identifier

 

extern_constraint_declaration ::=

[ static ] constraint class_identifier :: constraint_identifier { { constraint_block } }

 

identifier_list ::= identifier { , identifier }

 

loop_variables ::= [ index_identifier ] { ,  [ index_identifier ] }                                     // from Annex A.6.8

LRM-71

Changes (change in red):

constraint_block is a list of expression statements that restrict the range of a variable or define relations between variables. A constraint_expression is any SystemVerilog expression, or one of the constraint-specific operators: => -> and dist (see Sections 12.4.4 and 12.4.5).

LRM-63

Changes (change in red):

The declarative nature of constraints imposes the following restrictions on constraint expressions:

 

Calling tasks or functions is not allowed. Functions are allowed with certain limitations (see Section 12.4.11).

 

— Operators with side effects, such as ++ and -- are not allowed.

 

randc variables cannot be specified in ordering constraints (see solve...before in Section 12.4.8).

 

dist expressions cannot appear in other expressions (unlike inside); they can only be top-level expressions.

Section 12.4.4

LRM-63

Changes (change in red):

Limitations:

— A dist operation shall not be applied to randc variables.

— A dist expression requires that expression contain at least one rand variable.

— A dist expression can only be a top-level constraint (not a predicated constraint).

Section 12.4.5

LRM-71

Changes (change in red):

The implication operator ( => -> ) can be used to declare an expression that implies a constraint.

 

The syntax to define an implication constraint is:

 

constraint_expression ::=                                   // from Annex A.1.9

   ...

| expression => -> constraint_set

 

Syntax 12-5—Constraint implication syntax (excerpt from Annex A)

 

The expression can be any integral SystemVerilog expression.

 

The boolean equivalent of the implication operator a => -> b is (!a || b). This states that if the expression is true, then random numbers generated are constrained by the constraint (or constraint block). Otherwise the random numbers generated are unconstrained.

 

The constraint_set represents any valid constraint or an unnamed constraint block. If the expression is true, all of the constraints in the constraint block must also be satisfied.

 

For example:

 

mode == small => -> len < 10;

mode == large => -> len > 100;

 

In this example, the value of mode implies that the value of len shall be constrained to less than 10 (mode == small), greater than 100 (mode == large), or unconstrained (mode != small and mode != large).

 

In the following example:

 

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 says that a == 0 implies that b == 1, thereby eliminating 15 combinations: {0,0}, {0,2}, … {0,15}. Therefore, the probability that a == 0 is thus 1/(256-15) or 1/241.

Section 12.4.6

LRM-71

Changes (change in red):

mode == small => -> len < 10 ;

mode == large => -> len > 100 ;

Section 12.4.7 (New)

LRM-63

Add new Section and renumber succeeding (change in red):

12.4.7 Iterative Constraints

 

Iterative constraints allow arrayed variables to be constrained in a parameterized manner using loop variables and indexing expressions.

 

The syntax to define an iterative constraint is:

 

constraint_expression ::=                                                                    // from Annex A.1.9

|  foreach (array_identifier [ loop_variables ] )  constraint_set

 

loop_variables ::= [ index_identifier ]{ ,  [ index_identifier ] }                                                                                                                                     // from Annex A.6.8

 

The foreach construct specifies iteration over the elements of an array. Its argument is an identifier that designates any type of array (fixed-size, dynamic, associative, or queue) followed by a list of loop variables enclosed in square brackets. Each loop variable corresponds to one of the dimensions of the array.

 

For example:

 

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

 

C1 constrains each element of the array A to be in the set [2,4,8,16]. C2 constrains each element of the array A to be greater than twice its index.

 

The number of loop variables must not exceed the number of dimensions of the array variable. The scope of each loop variable is the foreach constraint construct, including its constraint_set. The type of each loop variable is implicitly declared to be consistent with the type of array index. An empty loop variable indicates no iteration over that dimension of the array. As with default arguments, a list of commas at the end can be omitted, thus, foreach( arr [ j ] ) is a shorthand for foreach( arr [ j, , , , ] ). It shall be an error for any loop variable to have the same identifier as the array.

 

The mapping of loop variables to array indexes is determined by the dimension cardinality, as described in Section 22.4.

 

//     1  2  3            3    4       1   2    -> Dimension numbers

int A [2][3][4];    bit [3:0][2:1] B [5:1][4];

 

foreach( A [ i, j, k ] ) …

foreach( B [ q, r, , s ] ) …

 

The first foreach causes i to iterate from 0 to 1, j from 0 to 2, and k from 0 to 3. The second foreach causes q to iterate from 5 to 1, r from 0 to 3, and s from 2 to 1.

 

Iterative constraints can include predicates. For example:

 

class C;

rand int A[] ;

 

constraint c1 { arr.size inside {[1:10]}; }

constraint c2 { foreach ( A[ k ] ) (k < A.size – 1) =>  A[k + 1] > A[k]; }

 endclass

 

The first constraint, c1, constrains the size of the array A to be between 1 and 10. The second constraint, c2, constrains each array value to be greater than the preceding one, i.e., an array sorted in ascending order.

 

Within a foreach, predicate expressions involving only constants, state variables, object handle comparisons, loop variables, or the size of the array being iterated behave as guards against the creation of constraints, and not as logical relations. For example, the implication in constraint c2 above involves only a loop variable and the size of the array being iterated, thus, it allows the creation of a constraint only when k < A.size() – 1, which in this case prevents an out-of-bounds access in the constraint. Guards are described in more detail in Section 12.4.12

 

Index expressions can include loop variables, constants, and state variables. Invalid or out or bound array indexes are not automatically eliminated; users must explicitly exclude these indexes using predicates.

 

The size method of a dynamic or associative array can be used to constrain the size of the array (see constraint c1 above). If an array is constrained by both size constraints and iterative constraints, the size constraints are solved first, and the iterative constraints next. As a result of this implicit ordering between size constraints and iterative constraints, the size method shall be treated as a state variable within the foreach block of the corresponding array. For example, the expression A.size is treated as a random variable in constraint c1, and as a state variable in constraint c2. This implicit ordering can cause the solver to fail in some situations.

Section 12.4.8

LRM-71

Changes (change in red):

class B;

rand bit s;

rand bit [31:0] d;

 

constraint c { s => -> d == 0; }

endclass

LRM-71

Changes (change in red):

class B;

rand bit s;

rand bit [31:0] d;

constraint c { s => -> d == 0; }

constraint order { solve s before d; }

endclass

Section 12.4.11 (New)

LRM-63

Add (change in red):

12.4.11 Functions in Constraints

 

Some properties are unwieldy or impossible to express in a single expression. For example, the natural way to compute the number of 1’s in a packed array uses a loop:

 

function int count_ones ( bit [9:0] w );

   for( count_ones = 0; w != 0; w = w >> 1 )

                     count_ones += w & 1’b1;

 endfunction

 

Such a function could be used to constrain other random variables to the number of 1 bits:

 

                constraint C1  {  length == count_ones( v ) };

 

Without the ability to call a function, this constraint requires the loop to be unrolled and expressed as a sum of the individual bits:

 

constraint C2

{

    length == ((w>>9)&1) + ((w>>8)&1) + ((w>>7)&1) + ((w>>6)&1) + ((w>>5)&1) +

  ((w>>4)&1) + ((w>>3)&1) + ((w>>2)&1) + ((w>>1)&1) + ((w>>0)&1);

}

 

Unlike the count_ones function, more complex properties, which require temporary state or unbounded loops, may be impossible to convert into a single expression. The ability to call functions, thus, enhances the expressive power of the constraint language and reduces the likelihood of errors. Note that the two constraints above are not completely equivalent; C2 is bidirectional (length can constrain w and vice-versa), whereas C1 is not.

 

To handle these common cases, SystemVerilog allows constraint expressions to include function calls, but it imposes certain semantic restrictions.

 

¾      Functions that appear in constraint expressions cannot contain output or ref arguments (const ref are allowed).

 

¾      Functions that appear in constraint expressions should be automatic (or preserve no state information) and have no side effects.

 

¾      Functions that appear in constraints cannot modify the constraints, for example, calling rand_mode or constraint_mode methods.

 

¾      Functions shall be called before constraints are solved, and their return values shall be treated as state variables.

 

¾      Random variables used as function arguments shall establish an implicit variable ordering or priority. Constraints that include only variables with higher priority are solved before other, lower priority, constraints. Random variables solved as part of a higher priority set of constraints become state variables to the remaining set of constraints. For example:

 

class B;

rand int x, y;

constraint C { x <= F(y); };

constraint D { y inside { 2, 4, 8 } };

              endclass

 

Forces y to be solved before x. Thus, constraint D is solved separately before constraint C, which uses the values of y and F(y) as state variables.

Within each prioritized set of constraints, cyclical (randc) variables are solved first.

 

¾      Circular dependencies created by the implicit variable ordering shall result in an error.

 

¾      Function calls in active constraints are executed an unspecified number of times (at least once), in an unspecified order.

Section 12.4.12 (New)

LRM-63

Add (change in red):

12.4.12 Constraint guards

 

Constraint guards are predicate expressions that function as guards against the creation of constraints, and not as logical relations to be satisfied by the solver. These predicate expressions are evaluated before the constraints are solved, and are characterized by involving only the following items:

¾      constants

¾      state variables

¾      object handle comparisons (comparisons between two handles or a handle and the constant null)

In addition to the above, iterative constraints (see Section 12.4.7) also consider loop variables and the size of the array being iterated as state variables.

 

Treating these predicate expressions as constraint guards prevents the solver from generating evaluation errors, thereby failing on some seemingly correct constraints. This enables users to write constraints that avoid errors due to nonexistent object handles or array indices out of bounds. For example, the sort constraint of the singly-linked list, SList, shown below is intended to assign a random sequence of numbers that is sorted in ascending order. However, the constraint expression will fail on the last element when next.n results in an evaluation error due to a non-existent handle.

 

       class SList;

              rand int n;

              rand Slist next;

 

              constraint sort  {  n < next.n; }

       endclass

 

The error condition above can be avoided by writing a predicate expression to guard against that condition:

 

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

 

In the sort constraint above, the if prevents the creation of a constraint when next == null, which in this case avoids accessing a non-existent object. Both implication (->) and if…else can be used as guards.

 

Guard expressions can themselves include sub-expressions that result in evaluation errors (e.g., null references), and they are also guarded from generating errors. This logical sifting is accomplished by evaluating predicate sub-expressions using the following 4-state representation:

 

¾      0            TRUE                     Sub-expression evaluates to TRUE

¾      1            FALSE                   Sub-expression evaluates to FALSE

¾      E            ERROR                 Sub-expression causes an evaluation error

¾      R           RANDOM             Expression includes random variables and cannot be evaluated

 

Every sub-expression within a predicate expression is evaluated to yield one of the above four values. The sub-expressions are evaluated in an arbitrary order, and the result of that evaluation plus the logical operation define the outcome in the alternate 4-state representation. A conjunction (&&), disjunction (||), or negation (!) of sub-expressions can include some (perhaps all) guard sub-expressions. The following rules specify the resulting value for the guard:

 

¾      Conjunction (&&): If any one of the sub-expressions evaluates to FALSE then the guard evaluates to FALSE. Otherwise, if any one sub-expression evaluates to ERROR then the guard evaluates to ERROR, else the guard evaluates to TRUE.

¾      If the guard evaluates to FALSE then the constraint is eliminated.

¾      If the guard evaluates to TRUE then a (possibly conditional) constraint is generated.

¾      If the guard evaluates to ERROR then an error is generated and randomize fails.

 

¾      Disjunction (||): If any one of the sub-expressions evaluates to TRUE then the guard evaluates to TRUE. Otherwise, if any one sub-expression evaluates to ERROR then the guard evaluates to ERROR, else the guard evaluates to FALSE.

¾      If the guard evaluates to FALSE then a (possibly conditional) constraint is generated.

¾      If the guard evaluates to TRUE then an unconditional constraint is generated.

¾      If the guard evaluates to ERROR then an error is generated and randomize fails.

¾       

¾      Negation (!): If the sub-expression evaluates ERROR then the guard evaluates to ERROR. Otherwise, if the sub-expression evaluates to TRUE or FALSE then the guard evaluates to FALSE or TRUE, respectively.

 

These rules are codified by the following truth tables:

 

&&

0

1

E

R

 

||

0

1

E