Update Event proposal to latest Accepted.
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.
Add non-blocking event trigger
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
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.
Add the following production after event_trigger as shown in red:
event_trigger ::=
-> hierarchical_event_identifier ;
->> [delay_or_event_control]
hierarchical_event_identifier ;
Update with approved Event description
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
example, 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 fork…join 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.
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.
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 example:
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” );
Add initial to examples of program block
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
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
Remove [] from cycle delay operator (##).
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
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
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
Add system include directive
Add new paragraph as shown in red:
Verilog
provides the `include file inclusion
compiler directive. SystemVerilog enhances the capabilities to support standard
include specification.
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.