In discrete event systems, changes in system behavior are marked by discrete occurrences or events. Events consist of a token and a time stamp. A token can be a scalar value, a matrix, a data structure, and so forth. The time stamp might be a floating-point number (Spice or the Ptolemy Discrete-Event model of computation) or consist of an ordered pair (global clock tick, delta time tick) of integers (VHDL). In VHDL, the ordered pair of integers represents a global time index and a delta time index. The scheduler runs the simulation by maintaining a record of all of the events in the system sorted by time stamp, and advancing time to the earliest time stamp. Thus, there is a total ordering between all events. Given any two events, we can tell if they occur simultaneously or after one another. CAD tools implementing a discrete event model include
--------------------------------
| |
| --- |
----> | | --- |
--- | C | ---------> | | |
| A | ------> | | | D | ---
--- --- ---> | |
| ---
--- |
| B | -------------------
---
Figure 1: A Discrete Event Block Diagram
This block diagram has two source blocks, A and B, and two input/output blocks C and D. There are no sink blocks.
The Ptolemy Classic DE model of computation requires that all source blocks schedule themselves. A Ptolemy Classic DE scheduler for simulation goes through three steps:
DERepeatStar,
whose code is available at
$PTOLEMY/src/domains/de/kernel/DERepeatStar.cc.
The initialize method creates a hidden feedback arc from a hidden output
port to a hidden input port.
(The hidden feedback arc is also given a property of infinitesimal
delay, which will be covered in Case #3 below.)
Hidden means that the arc or port does not show up when the block is
graphically displayed.
In the begin phase of initialization, a source block would output an
initial token at the simulation start time (0.0 s) on the hidden feedback
arc.
When simulation execution begins, every source block will be fired
at the simulation start time.
If the source node would be refired at a future time, then the
go method of the source node would output on the hidden feedback arc
a token with a timestamp equal to the future time.
At the beginning of the simulation, the global queue has
| 0.0 sec | Block A |
| 0.0 sec | Block B |
| 1.0 sec | Block C |
| 1.5 sec | Block D |
| 1.5 sec | Block D |
| 2.0 sec | Block D |
| 2.0 sec | Block D |
| 2.5 sec | Block C |
| 2.5 sec | Block C |
| 3.0 sec | Block C |
Will the system come to a halt by itself?
Generally, it does not, and even if it did, the scheduler could not predict it in finite time for all possible systems. The particular system we are using as an example will repeat forever. So, in practice, the user specifies a stopping time.
DEClock block
DEClock block
DEClock blocks from the Ptolemy Classic
collection.
The DEClock source code is available at
$PTOLEMY/src/domains/de/stars/DEClock.pl.
DEClock is derived from DERepeatStar, whose
code is available at
$PTOLEMY/src/domains/de/kernel/DERepeatStar.cc.
For this second case, we will encounter simultaneous events. The proper handling of simultaneous events increases the difficulty of scheduling because the scheduler must obey the order of data dependencies in the graph.
Blocks A and B pass tokens along a hidden feedback arc to cause the repeated firings to occur. After the scheduler has been initialized, the global queue has the following events in it prior to executing the graph:
| 0.0 sec | Block A |
| 0.0 sec | Block B |
Let's examine what would happen during the execution at Time 0.0 sec before we arrive at a schedule. Block A would produce an output with time stamp of 0.0 sec, which feeds into Block C. Block C would produce an output with time stamp of 0.0 sec, which feeds into block D. Block B would produce an output with time stamp of 0.0 sec, which feeds into Block D.
How do we derive a schedule to resolve the simultaneous events at block D to ensure causality?
When handling simultaneous events, the scheduler must first determine the data dependencies before executing any blocks in order to enforce causality. We can determine the data dependencies by performing a topological sort, which will be discussed in the Introduction to Graph Theory lecture. A topological sort is not necessarily unique.
In this DE graph, D is a delay block, and A, B, and C are functional blocks. A and B have hidden feedback arcs with a property of infinitesimal delay (i.e., a second dimension of time). The infinitesimal delay indicates that any data produced on the hidden output arc will be at an infinitesimally later time. Since we are trying to resolve a schedule for the current time, the delay property enables the hidden feedback arc to be broken. In addition, D is a delay block, so that any data it produces will happen at a later time than the current time stamp. Here is the amended graph to schedule at a particular time stamp:
---
| | ---
--- | C | ---------> | |
| A | ------> | | | D |
--- --- ----> | |
| ---
--- |
| B | -------------------
---
Figure 2: The Discrete Event block diagram in Figure 1 used in
scheduling execution to resolve simultaneous events. Of the four blocks,
only D is a delay block. Since D is a delay block, the feedback arc from
D to C can be removed for the purposes on scheduling the execution for
the current time stamp.
For the DE system, only D is a delay block. Here all of the topological sorts:
In finding the topological sort, the scheduler has to know if each block will produce a delay or not. In the Ptolemy Classic DE domain, however, delays associated with blocks must always be positive. The delay attribute associated with a DE block is set in the block's constructor in Ptolemy Classic.
What happens if the delay is data-dependent?
It is okay in VHDL. Delays associated with operations in VHDL must be non-negative.
| 1.0 sec | Block A |
| 1.5 sec | Block B |
| 1.5 sec | Block B |
| 2.0 sec | Block C (upper port) |
| 2.0 sec | Block A |
| 2.0 sec | Block C (upper port) |
| 2.0 sec | Block A |
| 2.5 sec | Block C (upper port) |
| 3.0 sec | Block B |
| 2.5 sec | Block C (upper port) |
| 3.0 sec | Block C (upper port) |
| 3.0 sec | Block A |
| 3.0 sec | Block B |
| 3.0 sec | Block C (upper port) |
| 3.0 sec | Block A |
| 3.0 sec | Block B |
| 3.5 sec | Block C (upper port) |
Possible outcomes:
*, which would
appear as a diamond in Ptolemy Classic.
Although an infinitesimal delay takes 0 seconds, it specifies that C
can execute before D.
For simultaneous events, the DE scheduler can now find a firing
sequence, e.g. ACBD or BACD or ABCD, by using a
topological sort, which will be discussed in the
Introduction to Graph
Theory lecture.
---------------*----------------
| |
| --- |
----> | | --- |
--- | C | ---------> | | |
| A | ------> | | | D | ---
--- --- ---> | |
| ---
--- |
| B | -------------------
---
Figure 3: Adjusting the DE schematic to handle simultaneous events
by adding an infinitesimal delay *.
After scheduling has been initialized but before the simulation starts, here is the state of the global queue:
| 0.0 sec | Block A |
| 0.0 sec | Block B |
| 0.0 sec | Block C (lower port) |
| 0.0 sec | Block D (lower port) |
| 1.0 sec | Block A |
| 1.5 sec | Block B |
| 0.0 sec | Block D (lower port) |
| 0.0 sec | Block D (upper port) |
| 1.0 sec | Block A |
| 1.5 sec | Block B |
At Time = (0.0 + e) seconds, where e means
one unit of infinitesimal delay,
| (0.0 + e) sec | Block C (upper port) |
| 1.0 sec | Block A |
| 1.5 sec | Block B |
At Time = (0.0 + 2 e) seconds
| (0.0 + 2 e) sec | Block C (upper port) |
| 1.0 sec | Block A |
| 1.5 sec | Block B |
This firing pattern could be continued ad infinitum without the scheduler advancing global time beyond 0.0 seconds.
Slide 8 of the block diagram talk defines determinism:
Here is a review of the semantics of the discrete-event model:
The fundamental problem in DE systems is one of races, e.g. as would occur in reconvergence as in the following graph:
/----B-----\
A---+ D
\----C-----/
If the blocks in a DE system are well-behaved for some suitable definition of well-behaved, then this is not a problem. In general, if D is an event-sensitive object (e.g., an edge-sensitive latch), then the behavior would be nondeterministic.
Here is another example. This example concerns an undefined concurrent procedure execution order in Verilog:
always @(posedge clk) $write( a ) always @(posedge clk) $write( b )The first simulator moved procedures between two push-down stacks, which produced