Subject: RE: [sv-ec] Comments on event changes CH17.html
From: Jay Lawrence (lawrence@cadence.com)
Date: Thu Jan 09 2003 - 18:50:39 PST
We could document the creation of sub-process but other undocumented
things make it a bit of a waste of energy. For instance, sequential
statements aren't guaranteed to not be interupted.
reg [31:0] a,b,c;
fork
begin
c = 1;
b = c;
end
begin
c = 2;
end
join
What is the value of b?
It could be either 1 or 2. Sequential code is not guaranteed to not be
interleaved. I don't know of a simulator that wouldn't get a 1, but is
legal to say 2.
A similar example:
wire [31:0] c;
reg [31:0] a, b;
assign c = a;
initial
begin
a = 1;
#1 a = 2;
$display("%d", c);
end
What is the value of printed? 1 or 2 is legal depending on whether the
continuous assignment fires immediately on assignment to 'a' or after
the sequential code ends. This is known to execute differently in
different simulators (and even in the same simulator with different
optimization levels.)
The last sick one off hand is:
wire [31:0] a = b;
wire [31:0] c;
assign c = b;
initial
begin
b = 0;
#1 b = 1;
$display("%d", a, c);
end
With the right set of switches XL will give you different values for a
and c.
So specifying the order of execution of fork/join would really only tell
you the order that the first statement executes.
Jay "Have fun with Verilog corner cases" Lawrence
-----Original Message-----
From: Arturo Salz [mailto:Arturo.Salz@synopsys.com]
Sent: Thursday, January 09, 2003 9:01 PM
To: Jay Lawrence; sv-ec@eda.org
Subject: Re: [sv-ec] Comments on event changes CH17.html
jay,
I agree with both your points:
1) Timing controls would alter the scheduling order.
2) I'm opposed to any reliance on execution of sub-processes.
However, I do believe that the creation of fork..join subprocesses
should be documented.
This is the sort of thing that vendors spend a lot time doing black box
testing in order to
match each others semantics, so it might as well be documented. That
will only ensure
a higher degree of inter-tool determinism, which is different from
encouraging users to rely
on the schedule ordering. For that purpose users should use any of the
synchronization
mechanisms available.
Arturo
----- Original Message -----
From: Jay <mailto:lawrence@cadence.com> Lawrence
To: Arturo Salz <mailto:Arturo.Salz@synopsys.COM> ; sv-ec@eda.org
Sent: Thursday, January 09, 2003 5:52 PM
Subject: RE: [sv-ec] Comments on event changes CH17.html
Just reread your reply ... On the concept of source order of fork/join,
yes in this trivival example everyone would get same answer, but if the
sub-processes created contained any sort of delay or event controls,
all bets are off on the order in which embedded events would be seen.
I would be opposed to any reliance on "source order" execution of
fork/join sub-processes.
Jay
-----Original Message-----
From: Arturo Salz [mailto:Arturo.Salz@synopsys.com]
Sent: Thursday, January 09, 2003 5:00 PM
To: Jay Lawrence; sv-ec@eda.org
Subject: Re: [sv-ec] Comments on event changes CH17.html
Jay,
You are correct to state that the LRM needs to specify the point in
the Verilog simulation cycle in which persistent events change back
to the "off" state. However, I do not believe that we need to add yet
another item to the stratified event queue. It's perfectly OK to reset
events during read-only-synchronize (at the same time as monitor
events). This is because only the positive edge (off -> on transition)
is visible outside the simulation kernel. A process can't be sensitive
to the "off" transition so the reset is akin to the monitor list update.
I assumed that this was implied from the language "until simulation
time advances", but it would be good to state it explicitly.
I appreciate what you are trying to do with the "non-blocking event
trigger".
Your proposal is in fact similar to the original Vera functionality in
which
the "persistency" of an event was a function of the trigger function.
That
functionality was changed to facilitate event management in Verilog by
making the persistency an explicit part of the event.
Unfortunately, your proposal doesn't solve the problem, it merely
reduces
the likelihood of its occurrence when the expects (@) execute at the
same
time as blocking assignments. This precludes deterministic operation of
processes that are both sensitive to as well as trigger events, since
that
might lead to multiple NBA times. Your message acknowledges this fact,
and states that it very rarely is a problem. But, events are used
primarily
for verification, and verification code executes during the
"verification phase",
which takes place after all non-blocking assignments, thus, your
proposal
might simply exacerbate the existing non-determinism problem by adding
the scheduling or processing order of non-blocking events to the
equation.
The bottom line is that if the triggered state of an event does not
persist
throughout the time step, the problem reappears.
For example, consider the following example:
event E1, E2;
fork
T1: begin @ E1 ; @ E2; end
T2: ->> E2;
T3: ->> E1;
join
Depending on the scheduling order of event triggering, the first
process, T1,
will either unblock or block forever. If this is rewritten with
persistent events
then regardless of the scheduling order, T1 always unblocks. Many other
simple examples will work deterministically with persistent events but
will
exhibit scheduling order dependencies using non-blocking event triggers.
Finally, I'd like to clarify something about your example. The example
does
capture the gist of the problem (the lack of determinism due to
scheduling
order) that motivates persistent events, and it is strictly correct
since the V2K
LRM does not explicitly specify the execution order of processes within
a
fork..join. However, all Verilog implementations of which I'm aware do
execute
the processes in source-order (T1, T2, T3 in the example). As a result,
the
outcome will always be to display "T1". I simply wanted to clarify this
in case
someone tries the example and deems this not to be a problem due to the
inherent determinism of existing implementations. I added a paragraph
to
this effect in the 3.1 LRM (see section 9.7) since I believe that
specifying the
order provides for better cross-tool determinism (and this is the
de-facto way
in which all vendors implement fork..join).
Arturo
----- Original Message -----
From: "Jay Lawrence" < <mailto:lawrence@cadence.com>
lawrence@cadence.com>
To: < <mailto:sv-ec@eda.org> sv-ec@eda.org>
Sent: Monday, January 06, 2003 3:47 AM
Subject: [sv-ec] Comments on event changes CH17.html
I assume we are going to begin today where we left off on the event
debate. I believe the debate now focuses more around the contents of
<http://www.eda.org/sv-ec/CH17.html> http://www.eda.org/sv-ec/CH17.html
than what is in the Draft 1 LRM so my
comments refer to that document.
Syntax nits
----------
- It currently says:
> The syntax to declare a non-persistent event is:
> event event_dentifier;
I believe this should be 'event_identifier' this occurs a bunch of times
in the changes document.
- last example is:
> fork
> T1: while(1) @ E2;
> T2: while(1) @ E1;
> T3: begin
> E2 = E1;
> while(1) -> E2);
> end
>join
The line "while(1) -> E2);" has a syntax error, the last ')' is not
needed.
This would also send NC into an infinite loop forever triggering E2. It
think the entire line should just be '-> E2;' and remove the while
altogether (maybe it needs a begin/end).
Persistent Event Clarification Needed
-------------------------------------
If we are going to accept this concept of an event that "persists
throughout the time-step, that is, until simulation time advances". We
are going to need to propose a change in the simulation cycle (1364 -
Chapter 5) to add a portion of the stratified event queue where these
things change state back to "off" after the monitor events have
executed.
Alternative Proposal for "Persistent Event" - "Non-blocking Event
Trigger"
------------------------------------------------------------------------
--Note: this is different than what Adam K. previously proposed (and was rejected)in IEEE 1364, that was events with transport delays, but had the same title.
The big value added by the persistent event is the reduced non-determinism created by allowing the event to remain triggered in order to avoid race conditions which occur from 0-delay simulation semantics. This is exactly like the race-conditions that are created by using blocking assignments.
I propose the we introduce a new operator ->> which we will call the non-blocking trigger operator. The operator takes a single event as an argument: event E;
->> E;
The effect of this operator is that the event E will be triggered in the non-blocking assignment phase of the simulation cycle. In 1364, this would be defined as adding a "non-blocking assign update event" to the current simulation time. The effect of this update event would be to trigger the referenced event.
The procedural code context in which the non-blocking trigger occurs continues to execute sequentially (does not block). This is also true of the regular trigger '->' operator, so the name non-blocking event trigger refers to when the event is scheduled rather than what happens in the sequential context.
This delaying of the event trigger until NBA-time disambiguates the triggering of events in exactly the same way that non-blocking assignments disambiguated assignment many years ago, and requires no changes to the simulation cycle.
It also has the advantage that events do not have to take on the characteristic of having a persistent value over time. They are still just instantaneously triggered (like the (posedge clk) in the CH17 proposal), so a new declaration for events (event bit) is not necessary. All events could be triggered in this way. Note, I actually like the promotion of events to first class objects that can be assigned to one another and passed to tasks. I would even allow them to occur in 'struct' and 'union' objects to embed an event with data.
The following example is ambiguous.
event E1; fork T1: begin @ E1 $display("T1"); end; T2: -> E1 T3: begin @ E1 $display("T3"); end; join
Depending on the simulator (or even simulation cycle) Either T1 or T3, or both will display and the fork/join may or may not ever unblock. If you replace the trigger with a non-blocking trigger.
event E1; fork T1: begin @ E1 $display("T1"); end; T2: ->> E1 T3: begin @ E1 $display("T3"); end; join
The order of execution becomes unimportant. T1 and T3 would both block and the trigger would be scheduled for NBA-time. When NBA-time arrives, both processes would always see the event.
There of course remain multiple NBA times possible in a given simulation cycle, but that very, very rarely causes issues with blocking vs. non-blocking assignment ambiguity. This solves the race condition problem triggering events with no more and no less ambiguity than non-block assignments did without introducing a new class of object or changing the simulation cycle.
Note, a logical extension of this proposal would also be to allow a delay control after the operator: ->> #5 E1; I bring it up here just because someone will. I think it makes sense but wouldn't protest too hard if only the immediate case was allowed. This is closer to Adam's proposal on adding transport delays to event triggering.
Jay
This archive was generated by hypermail 2b28 : Thu Jan 09 2003 - 18:51:23 PST