Each VHDL signal consists of several components. A reader which stores the current value of the signal and one or more driver which include a list of projected transactions for the signal created by a source. A transaction consists of a value and a time stamp. The time stamp determines the simulated point in time when the value shall be copied to the reader of the signal. Each driver is a list of transactions sorted in increasing time stamp order. Each process which includes at least one signal assignment statement for a specific signal is associated a separate driver for that signal. All signal assignment statements of this process will operate on this driver. If a new transaction TRnew=(vnew,tnew) - where value(TRnew)=vnew is the value of the transaction and time(TRnew)=tnew its time stamp - is created by a process, it is inserted into the appropriate driver transaction list as follows:
Let TRm be a transaction on the list with
and
.
If
such a transaction exists then all transactions TRi with
are deleted.
treject is the pulse reject limit
specified in the signal assignment statement.
To implement this mechanisms in the C++ process code each process
which includes at least one signal assignment statement that targets a
specific signal is assigned (at least) one driver_info class
object for that signal during elaboration. Hence, each signal
assignment operation initiated by a process targets a corresponding
driver_info instance. Each instance points to one or several
transaction lists which store the projected transactions for this
signal. This lists are called local transaction lists in the
following.
If a process includes assignment statements which target a composite
signal then it may instantiate more than one driver_info
instance for that signal. Each assignment operation which addresses
the same set of scalar elements of a composite signal are done via a
common driver_info instance. Note, not the actual element(s)
which are addressed by a specific assignment operation are taken to
determine the set but the longest static signal prefix of the
assignment target expression.
Example:
SIGNAL sig : bit_vector(0 TO 10);
...
p: PROCESS
BEGIN
FOR i IN 4 TO 4 LOOP
sig(i) <= '1'; -- Signal assignment 1
END LOOP;
...
sig <= (OTHERS => '0'); -- Signal assignment 2
...
END PROCESS;
The longest static prefix of both assignment statements is the entire
signal ``sig''. Hence, both assignment operations are handled by the
same driver_info instance.
In some cases the compiler can determine whether the sets addressed by two different assignment (of the same process) operations are equal. In other cases this decision may depend on code executed during elaboration.
Example:
ENTITY test GENERIC (gen1, gen2 : INTEGER); END test; ... p: PROCESS BEGIN sig(gen1) <= ...; -- Signal assignment 1 ... sig(gen2) <= ...; -- Signal assignment 2 END PROCESS;
Depending on the actual value of the generic parameter ``gen1'' and
``gen2'' both assignment operations may address the same or different
signal elements. To solve this problem the driver_info
instances are accessed via pointers which are initialised during
elaboration. During elaboration ``gen1'' as well as ``gen2'' are
known and therefore both pointers will reference the same
driver_info instance if ``gen1'' is equal to ``gen2''.
Finally, the driver_info instance is used by the process code
to assign transactions to a signal (see Figure 6.1) as shown in the following example.
Example:
SIGNAL sig1 : INTEGER; ... p1: PROCESS BEGIN sig1 <= sig1 + 1 AFTER 20 ns; ... END PROCESS;is translated to
// Elaboration code
L7testlib_E8myentity_A6behave_P2p1::
L7testlib_E8myentity_A6behave_P2p1(L7testlib_E8myentity_A6behave
*architecture, name_stack &iname) : process_base(iname) {
arch = architecture;
R4int1 = &arch->S4int1->reader();
// Get the driver instance
D4sig1 = kernel.get_driver(this, S4sig1);
...
}
// Process execution code
bool
L7testlib_E8myentity_A6behave_P2p1::execute() {
// Add a new transaction to the transaction list of the signal
D4sig1->inertial_assign((*R4int1 + integer(1)), time(20, 2));
...
}
Besides this local lists each transaction is additionally sorted into a global transaction list. There is only a single global list in the simulator which is sorted in increasing time stamp order similar to the local lists. While the global list is used to determine the sequence in which the transactions are assigned to the corresponding readers the local lists are used to implement the transport and inertial delay mechanisms.
The actual structure of the driver_info class is defined by the
kernel and therefore only parts which are relevant to the code
generator are described here.