AI-88

Update Event proposal to latest Accepted.

Section 3.9

Replace Section 3.9 with the following as shown in red:

 

3.9 Event data type

The event data type is an enhancement over Verilog named events. SystemVerilog events provide a handle to a synchronization object. Like Verilog, event variables can be explicitly triggered and waited for; furthermore, SystemVerilog events can also have a persistent triggered state that lasts for the duration of the entire time step. In addition, an event variable can be assigned another event variable or the special value null. When assigned another event variable, both event variables refer to the same synchronization object; when assigned null, the association between the synchronization object and the event variable is broken. Events can be passed as arguments to tasks.

 

The syntax to declare an event is:

 

event [ bit ] variable_name [= initial_value];

 

Where variable_name is a valid identifier and the optional initial_value can be another event variable or the special value null.

 

If an initial value is not specified then the variable is initialized to a new synchronization object.

 

The declaration event bit creates a persistent event (as described in section 12.6.2).

 

If the event is assigned null, the event becomes nonblocking, as if it were permanently triggered.

 

Examples:

 

event done;                // declare a new event called done

event done_too = done;     // declare done_too as alias to done

event bit blast; // persistent event

event bit empty = null;    // event variable with no synchronization object

 

Event operations and semantics are discussed in detail in section 12.6.

AI-88

Add non-blocking event trigger

Section 8.1

Add the following to the statement_item production in Syntax 8-1 and Annex A.6.4 (as shown in red):

 

statement_item ::=

{ attribute_instance } blocking_assignment ;

| { attribute_instance } nonblocking_assignment ;

| { attribute_instance } procedural_continuous_assignments ;

| { attribute_instance } case_statement

| { attribute_instance } conditional_statement

| { attribute_instance } transition_to_state statement_or_null

| { attribute_instance } inc_or_dec_expression

| { attribute_instance } function_call /* must be void function */

| { attribute_instance } disable_statement

| { attribute_instance } event_trigger

| { attribute_instance } loop_statement

| { attribute_instance } jump_statement

| { attribute_instance } par_block

| { attribute_instance } procedural_timing_control_statement

| { attribute_instance } seq_block

| { attribute_instance } system_task_enable

| { attribute_instance } task_enable

| { attribute_instance } wait_statement

| { attribute_instance } proc_assertion

| { attribute_instance } nonblocking_event_trigger

Section 8.10

Move the existing Section 8.10 to 8.11 and insert the following as Section 8.10 (as shown in red):

 

 

8.10 Nonblocking Event Trigger

 

nonblocking_event_trigger ::=       // from Annex A.6.5

            ->> [delay_or_event_control] hierarchical_event_identifier ;

 

Syntax 8-8 Nonblocking event trigger syntax (excerpt from Annex A)

 

The effect of the ->> operator is that the statement executes without blocking and it creates a non-blocking assign update event in the time when the delay control expires, or the event-control occurs. The effect of this update event would be to trigger the referenced event in the nonblocking assignment region of the simulation cycle.

Annex A.6.5

Add the following production after event_trigger as shown in red:

 

event_trigger ::=

-> hierarchical_event_identifier ;

 

nonblocking_event_trigger ::=

            ->> [delay_or_event_control] hierarchical_event_identifier ;

AI-88

            Update with approved Event description

 

Section 12.6

Make changes in red:

 

In Verilog, named events are static objects that can be triggered via the -> operator, and processes can wait for an event to be triggered via the @ operator. SystemVerilog events support the same basic operations, but enhance Verilog events in several ways. The most salient enhancement is that the triggered state of Verilog named events has no duration, whereas in SystemVerilog this state persists throughout the time-step on which the event is triggered. Also, SystemVerilog events act as handles to synchronization queues, thus, they can be passed as arguments to tasks, and they can be assigned to one another or compared.

 

Existing Verilog event operations (@ and ->) are backward compatible and continue to work the same way when used in the static Verilog context. The additional functionality described below works with all events in either the static or dynamic context.

 

A SystemVerilog event provides a handle to an underlying synchronization object. When a process waits for an event to be triggered, the process is put on a FIFO queue maintained within the synchronization object. Processes can wait for a SystemVerilog event to be triggered either via the @ operator, or by using the wait() construct to examine their triggered state. Events are always triggered using the -> or the ->> operator.

 

SystemVerilog provides for two different types of events: persistent events and non-persistent events. These two are described below.

 

The syntax to declare named events is discussed in section 3.9.

 

Section 12.6.1 through 12.6.4

Delete Sections 12.6.1 through 12.6.4 and replace with the following as shown in red:

 

12.6.1 Triggering an Event

 

Named events are triggered via the -> operator.

 

The syntax to trigger an event is:

 

-> event_identifier;

 

Triggering an event unblocks all processes currently waiting on that event. When triggered, named events behave like a one-shot, that is, the trigger state itself is not observable, only its effect. This is similar to the way in which an edge can trigger a flip-flop but the state of the edge can not be ascertained, i.e., if( posedge clock ) is illegal.

 

12.6.2 Waiting for an Event

 

The basic mechanism to wait for an event to be triggered is via the event control operator: @.

 

The syntax for this use of the @ operator is:

 

@ event_identifier;

 

The @ operator blocks the calling process until the given event is triggered.

 

For a trigger to unblock a process waiting on an event, the waiting process must execute the @ statement before the triggering process executes the trigger operator, ->. If the trigger executes first then the waiting process remains blocked.

 

12.6.3 Persistent Trigger: triggered property

 

SystemVerilog can distinguish the event trigger itself, which is instantaneous, from the event’s triggered state, which persists throughout the time-step (i.e., until simulation time advances). The triggered event property allows users to examine this state.

 

The syntax for invoking the triggered property uses a method-like syntax:

 

event_identifier.triggered

 

The triggered event property evaluates to true if the given event has been triggered in the current time-step and false otherwise. If event_identifier is NULL then the triggered event property evaluates to false.

 

The triggered event property is most useful when used in the context of a wait construct:

 

                wait ( event_identifier.triggered )

 

Using this mechanism, an event trigger will unblock the waiting process whether the wait executes before or at the same simulation time as the trigger operation. The triggered event property, thus, helps eliminate a common race condition that occurs when both the trigger and the wait happen at the same time. A process that blocks waiting for an event may or may not unblock depending on the execution order of the waiting and triggering processes. However, a process that waits on the triggered state always unblocks, regardless of the order of execution of the wait and trigger operations.

 

Example:

 

event done, blast;         // declare two new events

event done_too = done;           // declare done_too as alias to done

 

task trigger( event ev );

-> ev;

endtask

...

fork

@ done_too;       // wait for done through done_too

#1 trigger( done );     // trigger done through task trigger

join

 

fork

-> blast;

wait( blast.triggered );

join

 

The first fork in the example shows how two event identifiers done and done_too refer to the same synchronization object, and also how an event can be passed to a generic task that triggers the event. In the exam­ple, one process waits for the event via done_too, while the actual triggering is done via the trigger task that is passed done as an argument.

 

In the second fork, one process may trigger the event blast before the other process (if the processes in the forkjoin execute in source order) has a chance to execute, and wait for the event. Nonetheless, the second process unblocks and the fork terminates. This is because the process waits for the event’s triggered state, which remains in its triggered state for the duration of the time-step.

Section 12.7

Replace Section 12.7 as shown in red:

 

12.7 Event sequencing

 

12.7.1 wait_order()

 

The wait_order construct suspends the calling process until all the specified events are triggered in the given order (left to right), or any of the un-triggered events is triggered out of order and thus causes the operation to fail.

 

The syntax for the wait_order construct is:

 

wait_order( event_identifier[.triggered] {, event_identifier} )

[ statement_or_null ] [ else statement_or_null ]

 

For wait_order to succeed, at any point in the sequence, the subsequent events --- which must all be un-triggered at this point or the sequence would have already failed --- must be triggered in the prescribed order. Preceding events are not limited to occur only once, that is, once an event occurs in the prescribed order, it can be triggered again without causing the construct to fail.

 

Only the first event in the list can wait for the persistent triggered property.

 

The action taken when the construct fails depends on whether the phrase ‘else statement_or_null’ (the fail statement) is specified or not. If it is specified then the given statement is executed upon failure of the construct. If the fail statement is not specified, a failure generates a run-time error.

 

For example:

 

wait_order( a, b, c );

 

Suspends the current process until events a, b, and c trigger in the order a –> b –> c. If the events trigger out of order, a run-time error is generated.

 

wait_order( a, b, c ) else $display( “Error: events out of order” );

 

In this example, the fail statement specifies that upon failure of the construct, a user message be displayed, but without an error being generated.

 

bit success;

wait_order( a, b, c ) success = 1; else success = 0;

 

In this example, the completion status is stored in the variable success, without an error being generated.

Section 12.8

Change Section 12.8 as shown in red:

 

12.8 Event variables

 

An event is a unique data type with several important properties. Unlike Verilog, SystemVerilog events can be assigned to one another. When one event is assigned to another the synchronization queue of the source event is shared by both the source and the destination event. In this sense, events act as full-fledged variables and not merely as labels.

 

12.8.1 Merging Events

 

When one event variable is assigned to another, the two become merged. Thus, executing -> on either event variable affects processes waiting on either event variable.

 

For example:

 

event a, b, c;

a = b;

-> c;

-> a;   // also triggers b

-> b;   // also triggers a

a = c;

b = a;

-> a;   // also triggers b and c

-> b;   // also triggers a and c

-> c;   // also triggers a and b

 

When events are merged, the assignment only affects the execution of subsequent event control or wait operations. If a process is blocked waiting for event1 when another event is assigned to event1, the currently waiting process will never unblock. For exam­ple:

 

fork

T1: while(1) @ E2;

T2: while(1) @ E1;

T3: begin

E2 = E1;

while(1) -> E2;

end

join

 

This example forks off three concurrent processes. Each process starts at the same time. Thus, at the same time that process T1 and T2 are blocked, process T3 assigns event E1 to E2. This means that process T1 will never unblock, because the event E2 is now E1. To unblock both threads T1 and T2, the merger of E2 and E1 must take place before the fork.

 

12.8.2 Reclaiming Events

 

When an event variable is assigned the special null value, the association between the event variable and the underlying synchronization queue is broken. When no event variable is associated with an underlying synchronization queue, the resources of the queue itself become available for re-use.

 

Triggering a null event shall have no effect. The outcome of waiting on a null event is undefined, and implementations may issue a run-time warning.

 

event E1 = null;

@ E1;               // undefined: may block forever or not at all

wait( E1.triggered );     // undefined

-> E1;              // no effect

 

12.8.3 Events Comparison

 

Event variables can be compared against other event variables or the special value null.  Only the following operators are allowed for comparing event variables:

 

      Equality (==) with another event or with null.

      Inequality (!=) with another event or with null.

      Case equality (===) with another event or with null (same semantics as ==).

      Case inequality (!==) with another event or with null (same semantics as !=).

      Test for a Boolean value that will be 0 if the event is null and 1 otherwise.

 

Example:

 

event E1, E2;

 

if( E1 )               // same as if( E1 != null )

E1 = E2;

if( E1 == E2 )

   $display( “E1 and E2 are the same event” );

AI-88

Add initial to examples of program block

Section 13.7

Make changes in red:

 

program test( input phi1, input [15:0] data, output write,

input phi2, inout [8:1] cmd, input enable

);

 

clocking cd1 @(posedge phi1);

input data;

output write;

input state = top.cpu.state;

endclocking

 

clocking cd2 @(posedge phi2);

input #2 output #4ps cmd;

input enable;

endclocking

 

initial begin

// program begins here

...

// user can access cd1.data , cd2.cmd , etc…

end

endprogram

Section 13.8

Make changes in red:

 

program test( bus_A.test a, bus_B.test b );

 

clocking cd1 @(posedge a.clk);

input a.data;

output a.write;

inout state = top.cpu.state;

endclocking

 

clocking cd2 @(posedge b.clk);

input #2 output #4ps b.cmd;

input b.enable;

endclocking

 

initial begin

// program begins here

...

// user can access cd1.a.data , cd2.b.cmd , etc…

end

endprogram

AI-88

Remove [] from cycle delay operator (##).

Section 13.10

Make changes in red:

 

13.10 Cycle delay: ##

The ## operator can be used to delay execution by a specified number of clocking events, or clock cycles.

 

The syntax for the cycle delay statement is:

 

## [ expression ];

 

The expression can be any SystemVerilog expression that evaluates to a positive integer value.

 

What represents a cycle is determined by the default clocking in effect (see section 13.11). If no default clocking has been specified for the current module, interface, or program then the compiler will issue an error.

 

Example:

 

## [5];       // wait 5 cycles using the default clocking

## [j + 1];   // wait j+1 cycles using the default clocking

Section 13.11

Make changes in red:

 

Example 1. Declaring a clocking as the default:

 

program test( input bit clk, input reg [15:0] data )

default clocking bus @(posedge clk);

inout data;

endclocking

 

initial begin

## [5];

if ( bus.data == 10 )

## [1];

else

...

end

endprogram

 

Example 2. Assigning an existing clocking to be the default:

 

clocking busA @(posedge clk1); ... endclocking

clocking busB @(negedge clk2); ... endclocking

module processor ...

module cpu( interface y )

default clocking busA ;

initial begin

## [5]; // use busA => (posedge clk1)

...

end

endprogram endmodule

endmodule

Section 13.14

Make changes in red:

 

Examples:

 

bus.data[3:0] <= 4’h5; // drive in current cycle

##1 bus.data <= 8’hz; // wait 1 (bus) cycle and then drive

##[2]; bus.data <= 2; // wait 2 default clocking cycles, then drive

bus.data <= ##2 r; // sample r, wait 2 (bus) cycles, the drive

AI-88

Add system include directive

Section 23.1

Add new paragraph as shown in red:

 

Verilog provides the `include file inclusion compiler directive. SystemVerilog enhances the capabilities to support standard include specification.

 

Section 23.3

 

23.3 `include

The syntax of the `include compiler directive is:

 

      include_compiler_directive ::=

              `include "filename"

            | `include <filename>

 

When the filename is an absolute path, only that filename is included and only the double quote form of the `include can be used.

 

When the double quote ("filename") version is used, the behavior of `include is unchanged from IEEE Std. 1364-2001.

 

When the angle bracket ("<>") notation is used, then only the vendor defined location containing files defined by the language standard is searched. Relative pathnames given inside the <> are interpreted relative to the vendor-defined location in all cases.