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.