// EXAMPLE 1: restrict to small low addresses
res = bus.randomize()with
{atype == small low;};
class MyYXPair MyXYPair extends XYPair ;
constraint_declaration ::= [ static ] constraint
constraint_identifier { { constraint_block } } // from Annex
A.1.9
constraint_block ::= { { constraint_block_item } }
constraint_block_item ::=
solve identifier_list before identifier_list ;
| constraint_expression
constraint_expression ::=
expression_or_dist ;
| expression –> constraint_set
| if ( expression
) constraint_set [ else constraint_set ]
| expression dist { dist_list } ;
| foreach ( array_identifier [ loop_variables ] ) constraint_set
dist_item ::=
value_range :=
expression
| value_range :/ expression
dist_item ::= value_range [ dist_weight ]
dist_weight ::=
:= expression
| :/ expression
constraint_prototype ::= [ static ] constraint constraint_identifier ;
extern_constraint_declaration ::=
[ static ] constraint
class_identifier :: class_scope constraint_identifier { { constraint_block } }
identifier_list ::= identifier { , identifier
}
expression_or_dist ::= expression [ dist { dist_list } ] // from
Annex A.1.9
constraint_block ::= //
from Annex A.1.9
...
| expression dist { dist_list } ;
dist_list ::= dist_item { , dist_item } // from
Annex A.1.9
dist_item ::= value_range [ dist_weight
]
dist_weight ::=
:= expression
| :/ expression
expression_or_dist ::=
expression [ dist { dist_list } ] //
from Annex A.1.9
Constraints provide two constructs for declaring conditional
(predicated) relations: implication implication and if...else.
constraint_block_item ::=
solve identifier_list before identifier_list ;
| constraint_expression
The constraint c says “s implies d equals
zero”. Although this reads as if s determines
d, in fact s and
d are determined together. There are 232 233 valid possible combinations of {s,d}, but s is only true for {1,0}. Thus, the probability that s is true is 1/232 1/233, which is
practically zero.
constraint_declaration ::= // from Annex
A.1.9
[ static ] constraint
constraint_identifier { { constraint_block } }
constraint C1 { length
== count_ones( v ) ;
};
constraint C2
{
length == ((wv>>9)&1)
+ ((wv>>8)&1) + ((wv>>7)&1)
+ ((wv>>6)&1) + ((wv>>5)&1)
+
((wv>>4)&1) + ((wv>>3)&1) +
((wv>>2)&1) + ((wv>>1)&1)
+ ((wv>>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 length can constrain wv and vice-versa),
whereas C1 is not.
class B;
rand
int x, y;
constraint C { x <=
F(y); };
constraint D { y inside { 2, 4, 8 }; };
endclass
inline_constraint _declaration ::= //
not in Annex A
class_variable_identifier . randomize
[ ( [ variable_identifier_list | null ] ) ]
with { { constraint_block } }
scope_randomize
::=
// not in Annex A
[ std::
] randomize ( [ variable_identifier_list ] ) [ with { {
constraint_block } } ]