Section 8.2

LRM-113

Change Syntax 8-2 (change in red and blue):

statement_item ::=

  blocking_assignment ;

|  nonblocking_assignment ;

|  procedural_continuous_assignments ;

|  case_statement

|  conditional_statement

|  inc_or_dec_expression ;

|  function_call ;

| function_call_statement

|  disable_statement

|  event_trigger

|  loop_statement

|  jump_statement

|  par_block

|  procedural_timing_control_statement

|  seq_block

|  system_task_enable task_enable_statement

|  task_enable

|  wait_statement

|  procedural_assertion_item

|  clocking_drive

| void ’ ( function_call )

| randsequence

| scope_randomize

| randcase_statement

| expect ( property_spec ) [ action_block ]

| expect ( property_instance ) [ action_block ]

| expect_property_statement

Section 8.3

LRM-117

Change Syntax 8-2 (change in red and blue):

blocking_assignment ::=

  variable_lvalue = delay_or_event_control expression

| hierarchical_variable_identifier = new [ constant_expression ] [ ( variable_identifier ) ]

| hierarchical_dynamic_array_variable_identifier [ ]  = dynamic_array_new

| class_variable_identifier  = new [ ( list_of_arguments ) ] class_new

| class_variable_identifier . randomize [ ( ) ] with constraint_block ;

| operator_assignment

Section 8.4

LRM-122

Change Syntax 8-3 (change in red and blue):

conditional_statement ::=                                                                                   // from Annex A.6.6

  if ( expression cond_predicate ) statement_or_null [ else statement_or_null ]

| unique_priority_if_statement

 

unique_priority_if_statement ::=

[ unique_priority ] if (expression cond_predicate) statement_or_null

{ else if (expression cond_predicate) statement_or_null }

[ else statement_or_null ]

 

unique_priority ::= unique | priority

 

cond_predicate ::=

expression_or_cond pattern { && expression_or_cond_pattern }

 

expression_or_cond_pattern ::=

expression | cond_pattern

 

cond_pattern ::= expression matches pattern

 

case_statement ::=                                                                                               // from Annex A.6.7

  [ unique_priority ] case ( expression ) case_item { case_item } endcase

| [ unique_priority ] casez ( expression ) case_item { case_item } endcase

| [ unique_priority ] casex ( expression ) case_item { case_item } endcase

  [ unique_priority ] case_keyword ( expression ) case_item { case_item } endcase

| [ unique_priority ] case_keyword ( expression ) matches case_pattern_item { case_pattern_item } endcase

 

case_keyword ::= case | casez | casex

 

case_item ::=

  expression { , expression } : statement_or_null

| default [ : ] statement_or_null

 

case_pattern_item ::=

  pattern [ && expression ] : statement_or_null

| default [ : ] statement_or_null

Section 8.4.1 (New)

LRM-122

Add new section (change in red and blue):

8.4.1 Pattern matching

 

Pattern matching provides a visual and succinct notation to compare a value against structures, tagged unions and constants, and to access their members. SystemVerilog adds pattern matching capability to case and if statements, and to conditional expressions. Before describing pattern matching in those contexts, we first describe the general concepts.

 

A pattern is a nesting of tagged union and structure expressions with identifiers, constant expressions, and the wildcard pattern “.*” at the leaves. For tagged union patterns, the identifier following the tagged keyword is a union member name. For void members the nested member pattern is omitted.

 

pattern ::=                                                                                                                              // from Annex A.6.7.1

  variable_identifier

| .*

| . constant_expression

| tagged member_identifier [ pattern ]

| { pattern , ... , pattern }

| { member_identifier : pattern , ... , member_identifier : pattern }

 

Syntax 8-4—Pattern syntax (excerpt from Annex A)

 

A pattern always occurs in a context of known type because it is matched against an expression of known type. Recursively, its nested patterns also have known type. A constant expression pattern must be of integral type. Thus a pattern can always be statically type-checked.

 

Each pattern introduces a new scope; the extent of this scope is described separately below for case statements, if statements and conditional expressions. Each pattern identifier is implicitly declared as a new variable within the pattern's scope, with the unique type that it must have based on its position in the pattern. Pattern identifiers must be unique in the pattern, i.e., the same identifier cannot be used in more than one position in a single pattern.

 

In pattern-matching, we always match the value V of an expression against a pattern. Note that static type-checking ensures that V and the pattern have the same type. The result of a pattern match is:

 

      A 1-bit determined value: 0 (false, or fail) or 1 (true, or succeed). The result cannot be x or z even if the value and pattern contain such bits.

 

      If the match succeeds, the pattern identifiers are bound to the corresponding members from V, using ordinary procedural assignment.

 

Each pattern is matched using the following simple recursive rule:

 

      An identifier pattern always succeeds (matches any value), and the identifier is bound to that value (using ordinary procedural assignment).

 

      The wildcard pattern “.*” always succeeds.

 

      A constant expression pattern succeeds if V is equal to its value.

 

      A tagged union pattern succeeds if the value has the same tag and, recursively, if the nested pattern matches the member value of the tagged union.

 

      A structure pattern succeeds if, recursively, each of the nested member patterns matches the corresponding member values in V. In structure patterns with named members, the textual order of members does not matter, and members may be omitted. Omitted members are ignored.

 

Conceptually, if the value V is seen as a flattened vector of bits, the pattern specifies which bits to match, with what values they should be matched and, if the match is successful, which bits to extract and bind to the pattern identifiers. Matching can be insensitive to x and z values, as described in the individual constructs below.

Section 8.4.1.1 (New)

LRM-122

Add new section (change in red and blue):

8.4.1.1 Pattern matching in case statements

 

In a pattern-matching case statement, the expression in parentheses is followed by the keyword matches, and the statement contains a series of “case_pattern_items”. The left-hand side of a case item, before the “:”, consists of a pattern and, optionally, the operator && followed by a boolean “filter” expression. The right-hand side of a case item is a statement. Each pattern introduces a new scope, in which its pattern identifiers are implicitly declared; this scope extends to the optional filter expression and the statement in the right-hand side of the same case item. Thus different case items can reuse pattern identifiers.

 

All the patterns are completely statically type-checked. The expression being tested in the pattern-matching case statement must have a known type, which is the same as the type of the pattern in each case item.

 

The expression in parentheses in a pattern-matching case statement shall be evaluated exactly once. Its value V shall be matched against the left-hand sides of the case items, one at a time, in the exact order given, ignoring the default case item if any. During this linear search, if a case item is selected, its statement is executed and the linear search is terminated. If no case item is selected, and a default case item is given, then its statement is executed. If no case item is selected and no default case item is given, no statement is executed.

 

For a case item to be selected, the value V must match the pattern (and the pattern identifiers are assigned the corresponding member values in V ) and then the boolean filter expression must evaluate to true (a determined value other than 0).

 

Example:

 

typedef union tagged {

void Invalid;

int Valid;

} VInt;

...

VInt v;

...

case (v) matches

tagged Invalid : $display ("v is Invalid");

tagged Valid n : $display ("v is Valid with value %d", n);

endcase

 

In the case statement, if v currently has the Invalid tag, the first pattern is matched. Otherwise, it must have the Valid tag, and the second pattern is matched. The identifier n is bound to the value of the Valid member, and this value is displayed. It is impossible to access the integer member value (n) when the tag is Invalid.

 

Example:

 

typedef union tagged {

struct {

bit [4:0] reg1, reg2, regd;

} Add;

union tagged {

bit [9:0] JmpU;

struct {

bit [1:0] cc,

bit [9:0] addr;

} JmpC;

} Jmp;

} Instr;

...

Instr instr;

...

case (instr) matches

tagged Add {r1,r2,rd} && (rd != 0): rf[rd] = rf[r1] + rf[r2];

tagged Jmp j : case (j) matches

tagged JmpU a : pc = pc + a;

tagged JmpC {c,a}: if (rf[c]) pc = a;

 endcase

endcase

 

If instr holds an Add instruction, the first pattern is matched, and the identifiers r1, r2 and rd are bound to the three register fields in the nested structure value. The right-hand side statement executes the instruction on the register file rf. It is impossible to access these register fields if the tag is Jmp. If instr holds a Jmp instruction, the second pattern is matched, and the identifier j is bound to the nested tagged union value. The inner case statement, in turn, matches this value against JmpU and JmpC patterns, and so on.

 

Example (same as previous example, but using wildcard and constant patterns to eliminate the rd = 0 case; in some processors, register 0 is a special “discard” register):

 

case (instr) matches

tagged Add {.*,.*, . 0}: ; // no op

tagged Add {r1,r2, rd} : rf[rd] = rf[r1] + rf[r2];

tagged Jmp j          : case (j) matches

tagged JmpU a : pc = pc + a;

tagged JmpC {c,a}: if (rf[c]) pc = a;

            endcase

endcase

 

Example (same as previous example, but note that the first inner case statement involves only structures and constants but no tagged unions):

 

case (instr) matches

tagged Add s: case (s) matches

{.*,.*, . 0}: ; // no op

{r1,r2, rd}: rf[rd] = rf[r1] + rf[r2];

endcase

tagged Jmp j: case (j) matches

tagged JmpU a : pc = pc + a;

tagged JmpC {c,a}: if (rf[c]) pc = a;

endcase

endcase

 

Example (same as previous example, but using nested tagged union patterns):

 

case (instr) matches

tagged Add {r1,r2,rd} && (rd != 0) : rf[rd] = rf[r1] + rf[r2];

tagged Jmp (tagged JmpU a)        : pc = pc + a;

tagged Jmp (tagged JmpC {c,a})    : if (rf[c]) pc = a;

endcase

 

Example (same as previous example, with named structure components):

 

case (instr) matches

tagged Add {reg2:r2,regd:rd,reg1:r1} && (rd != 0): rf[rd] = rf[r1] + rf[r2];

tagged Jmp (tagged JmpU a)                      : pc = pc + a;

tagged Jmp (tagged JmpC {addr:a,cc:c})          : if (rf[c]) pc = a;

endcase

 

As usual, the casez and casex keywords can be used instead of case, with the same semantics. In other words, during pattern matching, wherever two bits are compared (whether they are tag bits or members), the casez form ignores z bits, and the casex form ignores both z and x bits.

 

The priority and unique qualifiers play their usual role. priority implies that some case item must be selected. unique also implies that exactly one case item will be selected, so that they may be evaluated in parallel.

Section 8.4.1.2 (New)

LRM-122

Add new section (change in red and blue):

8.4.1.2 Pattern matching in if statements

 

The predicate in an if statement can be a series of clauses separated with the && operator. Each clause is either an expression (used as a boolean filter), or has the form expression matches pattern. The clauses represent a sequential conjunction from left to right, i.e., if any clause fails the remaining clauses are not evaluated, and all of them must succeed for the predicate to be true. Boolean expression clauses are evaluated as usual. Each pattern introduces a new scope, in which its pattern identifiers are implicitly declared; this scope extends to the remaining clauses in the predicate and to the corresponding “true” arm of the if statement.

 

In each e matches p clause, e and p must have the same known statically known type. The value of e is matched against the pattern p as described above.

 

Even though the pattern matching clauses always return a defined 1-bit result, the overall result may be ambiguous because of the boolean filter expressions in the predicate. The standard semantics of if statements hold, i.e., the first statement is executed if and only if the result is a determined value other than 0.

 

Example:

 

if (e matches (tagged Jmp (tagged JmpC {cc:c,addr:a})))

... // c and a can be used here

else

...

 

Example (same as previous example, illustrating a sequence of two pattern-matches with identifiers bound in the first pattern used in the second pattern).

 

if (e matches (tagged Jmp j),

    j matches (tagged JmpC {cc:c,addr:a}))

... // c and a can be used here

else

...

 

Example (same as first example, but adding a boolean expression to the sequence of clauses). The idea expressed is: “if e is a conditional jump instruction and the condition register is not equal to zero ...”.

 

if (e matches (tagged Jmp (tagged JmpC {cc:c,addr:a}))

&& (rf[c] != 0))

... // c and a can be used here

else

...

 

The priority and unique qualifiers play their usual role for if statements even if they use pattern matching.

Section 8.4.1.3 (New)

LRM-122

Add new section (change in red and blue):

8.4.1.3 Pattern matching in conditional expressions

 

A conditional expression (e1 ? e2 : e3) can also use pattern matching, i.e., the predicate e1 can be a sequence of expressions and “expression matches pattern” clauses separated with the && operator, just like the predicate of an if statement. The clauses represent a sequential conjunction from left to right, i.e., if any clause fails the remaining clauses are not evaluated, and all of them must succeed for the predicate to be true. Boolean expression clauses are evaluated as usual. Each pattern introduces a new scope, in which its pattern identifiers are implicitly declared; this scope extends to the remaining clauses in the predicate and to the consequent expression e2.

 

As described in the previous section, e1 may evaluate to true, false or an ambiguous value. The semantics of the overall conditional expression are described in Section 7.18, based on these three possible outcomes for e1.

Section 8.10

LRM-137

Changes (change in red and blue):

If the expression denotes a clocking- domain block input or inout (see Section 15), the event control operator uses the synchronous values, that is, the values sampled by the clocking event. The expression can also denote a clocking-domain block name (with no edge qualifier) to be triggered by the clocking event.

LRM-112

Changes (change in red and blue):

A variable used with the event control can be any one of the integral data types (see Section 3.3.1) or string. The variable can be either a simple variable or a ref argument (variable passed by reference); it can be a member of an array, associative-array, or object (class instance) of the aforementioned types. Objects (handles) and aggregate types are not allowed.

 

Event control variables can include object data members, in which case the object handle is evaluated only once when the event control statement is executed. Likewise, an object data member in an event control shall block until that particular data member changes value, not when the handle to the object is modified. For example:

 

Event expressions must return singular values. Aggregate types may be used in an expression provided the expression reduces to a singular value. The object members or aggregate elements may be any type as long as the result of the expression is a singular value.

If the event expression is a reference to a simple object handle or chandle variable, an event is created when a write to that variable is not equal to its previous value.


Non-virtual methods of an object and built-in methods or system functions for an aggregate type are allowed in event control expressions as long as the type of the return value is singular and the method is defined as a function, not a task.

Changing the value of object data members, aggregate elements, or the size of a dynamically sized array referenced by a method or function shall cause the event expression to be re-evaluated. An implementation may cause the event expression to be re-evaluated when changing the value or size even if the members are not referenced by the method or function.

 

real AOR[]; // dynamic array of reals

byte stream[$]; // queue of  bytes

initial wait(AOR.size() > 0) ....; // waits for array to be allocated.

initial wait($bits(stream) > 60)...; // waits for total number of bits in stream greater than 60

 

Packer Packet p = new; // Packet 1

Packet q = new; // Packet 2

initial fork

@(p.status);  // Wait for status in Packet 1 to change

@ q;        // Wait for a change to handle q

# 10 q = p; // triggers @q.

p = q; // Has no effect on the wait in Process 1

// @(p.status) now waits for status in Packet 2 to change, if not already different from Packet 1

join_none join

// @(p.status) continues to wait for status of Packet 1 to change