The simulator currently provides some limited features for interacting with channels and environments at run-time. The channel features allow a user to connect arbitrary sources and sinks to channels, as well as perform assertion checks and value logging. For consistency, all channels commands are prefixed with channel-.
Registers a named channel (with constituents) in a separate namespace in the simulator, typically used to drive or log the environment. The name of the channel should match that of an instance (process or channel) in the source file.
For example, channel e:0 :0 d:4 is a conventional e1of4 channel with active-high data rails d[0..3], and an active-low acknowledge (enable) reset to 0, no bundles.
- name is the name of the new channel in the simulator's namespace
- type is a regular expression of the form [ae]?[nv]?:[01]?, where
- a means active-high acknowledge
- e means active-low acknowledge (a.k.a. enable)
- n means active-low validity (a.k.a. neutrality)
- v means active-high validity. These are also the names of the channel signals.
- [01] is the initial value of the acknowledge during reset, which is only relevant to channel sinks.
- bundle is the name of the data bundle (rail group) of the channel in the form [name]:size, where size is the number of rail bundles (M in Mx1ofN). If there are no bundles, then leave the name blank, i.e. just write :0 If there is only one bundle (1x1ofN), use size 0 to indicate that named bundle is not an array.
- rails ([~]rname:radix) is the name and size of each bundle's data rails, rname is the name of the data rail of the channel. radix is the number of data rails per bundle (N in Mx1ofN). Use radix 0 to indicate that rail is not an array (1of1). If rails is prefixed with a ~, then the data rails will be interpreted as active low.
The channel names used in the simulator must correspond to an actual channel (or process) in the input description. (The name used for registration actually resides in the simulator's own namespace, separate from the compiled circuits.) Upon registering a channel name, the simulator locates all relevant subnodes of the channel by appending .e or .a (or .v or .n) and .d[i] (or however the rails are named) to the end of the channel's name. The data rails' name may be prefixed with ~ to indicate that the rails are active-low. The following are examples of channel commands.
channel A e:0 :0 d:2 channel B e:1 :0 d:2 channel C e:1 :0 r:2 channel D e:1 :0 d:0 channel E a:1 :0 r:4 channel F e:1 d:4 r:4 channel G ev:0 :0 d:2 channel H : :0 d:2 channel J e:0 :0 ~d:2 channel H : :0 ~d:2
Respectively, the channel declarations are: (A) an e1of2 channel with .e initially low (if coming from the environment), (B) an e1of2 with .e initially high, (C) an e1of2 with array data rails named r, (D) an e1of2 with one non-array data rail r, (E) an a1of4 with .a initially high, (F) an e4x1of4 channel, (G) an ev1of2 (enable-valid protocol), (H) an acknowledgeless 1of2 channel (just data-rails), (J) an e1of2 with active-low data rails, and (K) an acknowledgeless, active-low dual-rail.
A channel can be declared without an acknowledge by omitting the a or e desginator and the initial value after the colon, as in examples H and K, above. Acknowledgeless channels cannot be used as sources or sinks, however, they can still be watched, logged, and checked against expected values. (Watching, logging, and checking values on channels does not use the acknowledge signal of channels.)
The shared-valid protocols use a additional validity (or neutrality) signal in the channel to perform the handshake. For example, the validity signal can be generated by the completion tree from the sender, and sent to the receiver so the receiver can reuse the completion signal without recomputing it. Shared-validity channels operate slightly differently than other channels. Data is considered valid when the validity is true, not necessarily when the data rails are in a valid state. (Of course, in the cases of properly constructed and connected completion trees, the data will be valid.) Thus, data is logged, printed, checked only when the validity signal becomes active, which is usually after the data rails are valid. (More on sourcing and sinking of shared-validity channels below.)
Another class of channels use level-encoded dual rail (LEDR). Such channels are declared using channel-ledr.
Registers a level-encoded dual-rail (LEDR) channel. LEDR channels do not follow a return-to-null protocol; there is exactly one transition per iteration on the forward path. Currently, LEDR channels only encode 1-bit of information per channel. The data rail represents the logic level, and the repeat rail is toggled to communicate another token with the same value. The channel acknowledge (if present) also fires onces per handshake. Together, they are used for 2-phase protocols. The name of the channel should match that of an instance (process or channel) in the source file.
The initial values of the three rails determines the “empty-parity” of the channel, the parity of the rails when the channel is in its empty state. The initial values are used when the channels are connected up to driving environments such as sources and sinks. For bundled channels, the initial values of data and repeat apply to all bundles.
- name is the name of the new channel in the simulator's namespace
- ack is a regular expression of the form id:[01], where
- if an identifier id is given before the :, it is interpreted as the name of an acknowledge signal.
- The value after the : (required) is interpreted as the initial state of the acknowledge wire. There is no need to express whether the acknowledge is active-high or active-low.
- : with no name represents a channel with no acknowledge.
- bundles is the name of the data-repeat bundle followed by : and the number of bundles. Pass just :0 to indicate that there is only one data-repeat pair.
- data is the name of the data rail, interpreted with active-high logic levels. The init value specifies the initial value of the data rail on an empty channel.
- repeat is the name of the repeat rail. init specifies the initial value of the repeat rail on an empty channel.
channel-ledr NAME e:0 :0 d:0 r:0 channel-ledr NAME e:1 :0 d:0 r:0
By default, bundled channels are interpreted as unsigned numbers. channel-signed indicates that chan should be interpreted and displayed as signed values. Signedness is only applicable to binary (radix-2) channels with more than one bit; non-radix-2 channels are always interpreted as unsigned, and single bit channels are always unsigned (0 or 1). It is generally recommended to declare the signedness of a channel immedately after declaring it, and before any values are interpreted.
Yet another class of channels captures bundled-data interfaces. Bundled-data channels contain one or more single-rail data wires (bus), and an acknowledge and request rail. Data is interpreted as valid during the active edge of the request rail. Two-phase and four-phase handshake variants exist for bundled-data.
Registers a bundled-data (BD) channel, which consists of a bus, request rail, and acknowledge rail. The request and acknowledge perform a two-phase handshake on every token; these signals toggle once per handshake. The name of the channel should match that of an instance (process or channel) in the source file.
- name is the name of the new channel in the simulator's namespace
- ack is a regular expression of the form id:[01], where
- id is the name of the acknowledge signal.
- The value after the : (required) is interpreted as the initial state of the acknowledge wire, if driven by sink.
- req is the name of the request signal. The value given is the initial value of the request signal, if driven by a source. Together the XOR of the initial values of the acknowledge and request defines the empty-parity.
- data is the name of the data rail(s), interpreted with active-high logic levels (prefix with ~ to make active-low). The num value specifies the number of wires (bus width). If the channel is data-less (handshake only), then omit the data rail name and just write :.
channel-bd-2p NAME e:1 v:1 d:0 -- this names the ack e and the request v, and data is a single-wire bundled-data channel. channel-bd-2p NAME a:1 r:0 d:8 -- this names the ack a and the request r, and data is a 8-bit bundled-data channel.
Registers a bundled-data (BD) channel, which consists of a bus, request rail, and acknowledge rail. The request and acknowledge perform a four-phase handshake on every token; these signals toggle twice per handshake. The name of the channel should match that of an instance (process or channel) in the source file.
- name is the name of the new channel in the simulator's namespace
- ack is a regular expression of the form id:[01], where
- id is the name of the acknowledge signal.
- The value after the : (required) is interpreted as the initial state of the acknowledge wire, if driven by sink.
- a denotes an active-high acknowledge, and e denotes an active-low acknowledge, (same as 1ofN channels).
- req is the name of the request signal. The value given is the initial value of the request signal, if driven by a source – THIS IS IGNORED FOR NOW, source channels will always drive this to inactive on reset.
- data is the name of the data rail(s), interpreted with active-high logic levels (prefix with ~ to make active-low). The num value specifies the number of wires (bus width). If the channel is data-less (handshake only), then omit the data rail name and just write :.
channel-bd-4p NAME e:0 v:1 d:0 -- this declares an active-low acknowledge, active-high request, single-wire bundled-data channel. channel-bd-4p NAME a:1 n:0 d:8 -- this declares an active-high acknowledge, active-low request, 8-bit bundled-data channel.
Data is guaranteed to be stable until an acknowledge is received.
Finally, there is support for synchnous clocked channels.
Registers a synchronous (clocked) channel, which consists of a data bus and a clock signal. The name of the channel should match that of an instance (process or channel) in the source file.
- name is the name of the new channel in the simulator's namespace
- clk is the name of the clock signal. The value given is the initial value of the clock on reset, if driven by a source. If the name is prefixed by ~ then clock is active low (negative-edge). If the name is prefixed by * then clock is double-edged. Otherwise, clock is considered positive-edge only. The init initial value is only relevant for double-edged clocks.
- data is the name of the data rail(s), interpreted with active-high logic levels (prefix with ~ to make active-low). The num value specifies the number of wires (bus width). If the channel is data-less (handshake only), then omit the data rail name and just write :.
channel-clocked NAME clk:0 d:0 -- this names the clock clk, and data d is a single-wire channel. clk is pos-edge triggered only. channel-clocked NAME ~clk:0 d:8 -- this names the clock clk, and data d is a 8-bit bundled-data channel. clk is neg-edge triggered only. channel-clocked NAME *clk:0 d:8 -- this names the clock clk, and data d is a 8-bit bundled-data channel. clk is double-edge triggered.Sources do not actually drive the clock, they only setup the data during clock edges.
When configured as a source, clocked-channels only set the data rails in response to the clock signal; it never drives the clock rail. This is by design, because the same clock may be referenced to any number of clocked channels. (The clock should be driven separately by clock-source.) For single-edged clocked channels, the data is set during the inactive clock phase, and held during the active clock phase, in other words, the data is set up on the opposite triggering clock edge. For double-edged clock channels, the data is set/evaluated on every edge.
Drives wire node with toggling values. If node is prefixed with ~, then clock is active low (negative edge). If node is prefixed with *, then clock is double-edged. The reset value, init, is only relevant to double-edged clocks. With no prefix, the clock is active-high (positive edge). N is the number of cycles, or * for infinite. For single=edged clocks, the clock always resets to its inactive value. For single-edged clocks, a rise and fall counts as one cycle. If named clock-source already exists, restart it using the new configuration and number of edges.
clock-source CLK:0 * -- clk is pos-edge, infinitely running clock. clock-source ~CLK:1 20 -- clk is a neg-edge clock running 20 cycles. clock-source *CLK:0 * -- clk is double-edge clock, reset to 0, running infinitely.
One can get information about channel configurations with the following commands:
Print the current configuration and state of channel chan. This also shows the sequence of values associated with sources and expectations with sequence position, if applicable. Looping values are indicated with *. This also shows the origin of the value sequence and the name of the current log file to which values are dumped, if enabled.
This prints the current handshake state of a channel, including the current value, if valid, and the expected activity (e.g., waiting for data from sender, or ack from receiver).
This asserts the current state of a channel. Legal values for arguments (in any order and combination):
The error-handling policy in the case of a failed assertion is controlled by channel-expect-fail.
- <int> the integer value of the data rails; passes only if data is valid and matches the expected value.
- valid (four-phase or two-phase) passes if the channel data rails are in the valid state, or the validity signal (if any) is active, or a two-phase channel is in the set-phase (full).
- neutral (four-phase or two-phase) passes if the channel data rails are all neutral/null.
- full is synonymous with valid
- empty is synonymous with neutral
- ack (four-phase only) passes if the acknowledge is in the active state, whether the signal is active-high or active-low.
- neg-ack (four-phase only) passes if the acknowledge is in the negative state.
- waiting-sender (four-phase or two-phase) passes if the channel is in a state of the handshake that expects the next action from the sender of the channel.
- waiting-receiver (four-phase or two-phase) passes if the channel is in a state of the handshake that expects the next action from the receiver of the channel.
To control which channels should report values to the console, the simulator provides basic watch commands.
Report value of data rails when channel chan has valid data. Data validity is only determined by the state of the data rails, and not the acknowledge signal. An unstable channel (that can transiently take valid states) will report every transient value. Channels in the stopped state will still be reported, make sure that they are resumed by channel-release.
Set this switch on to show simulation timestamps when watched channels are printed or logged channels are written to file. Default: off
Channel values can also be logged to a file or compared against expected values.
Record all valid data values on channel chan to output file. File stream automatically closes upon end of simulation, or with an explicit channel-close. Channels in the stopped state will NOT be reported, make sure that they are resumed by channel-release.
Close any output file streams associated with channel chan. This flush the current log file, closes the file, and stops logging. This does not affect source nor expect value sequences since those files are read in their entirety upon configuration.
Compare data values seen on channel chan against a sequence of values from file. Error out as soon as there is a value mismatch. In this variant, once value sequence is exhausted, no more comparisons are done, and channel values go unchecked. See also channel-expect-file-loop.
Like channel-expect-file but repeats value sequence infintely.
Tells a channel chan to expect values on data rails. Stops checking values after last value is used.
It is legal to log and expect values on the same channel.
The following commands can further control when channels log or check values. Ignoring can be useful for masking out atypical phases of behavior or turning off checking. Ignoring channels is independent of the stopped/released state of a channel.
Stop logging and checking expected values on channel chan. This can be useful for momentarily ignoring a sequence of values. An ignored channel will continue to respond to changes until it is stopped, by a stop command.
Value files: The files referenced by channel-expect and channel-source may contain # comments and blank lines, which are skipped. Only the first value on each line is used, so value sequences should be newline-separated. For now, the remained of each line is simply ignored, so you may use them for comments, but this may change in the future. The other legal value in the file is X, which is interpreted as don't care for expected values, and random for source values.
Channels can be configured to operate as environments when they are not already connected to inputs or outputs. The only conflicting (illegal) configuration combination is that a channel cannot act as source while expecting values. (Why would you want to do that anyways?) Channels configured as sources or sinks can be controlled through the following commands.
Configure channel chan to source values from the environment. Values are take from file and read into an internal array. Once values are exhausted, the channel stops sourcing. To repeat values, use channel-source-file-loop. A channel configured as a source should have the production rules drive the acknowledge signal and no other rules driving the data rails (otherwise the simulator will issue a warning).
Like channel-source-file except that value sequence is repeated infintely.
Source values on channel chan using the values passed on the command. Sourcing stops after last value is used. Legal values are integers and 'X' for random. If no values are given, then the channel will not source any values, but it will still reset the data rails to neutral state.
Configures a channel to source random data values. This is useful for tests that do not depend on data values.
Configure a channel to consume all data values (infinitely). A sink-configured channel should have data rails driven by the production rules and nothing else driving the acknowledge signal (simulator will issue warning otherwise). A sink-configured channel can also log and expect values. Mmmmm... tokens! Nom-nom-nom...
It is legal to source and sink on the same channel.
It is often useful to query the status of a channel that is sourcing or expecting values.
For channels that are sourcing or expecting values, assert the state of the channel value array being used. val is 1 to assert that values are still remaining, 0 to assert that values are empty (channel is finished). Looped sources and expects will never be empty. This is useful for checking that finite sequence tests have actually completed. Exits fatally if assertion fails.
Channel sources and sinks can be configured to respond with a different timing from the global policy.
With no additional arguments, report the timing mode of channel chan. Timing only applies to channels that are configured as a source or a sink. Modes:
- global : use the global simulation-wide timing policy.
- after [delay] : use a fixed delay.
- random [[min]:[max]] : if max is specified, use a uniform distribution delay bounded by max, otherwise return an exponential variate delay with a minimum of min. Unspecified min bounds defaults to 0. Unspecified max defaults to +INF.
- binary [min]:[max] prob : chooses either the min or the max value with prob probability of taking the min value.
Shared-validity environments: Shared-validity sources operate slightly differently from the other standard channels. Sources of such channels will drive both the data-rails and the validity signal. The validity-signal will automatically react when the data-rails enter a valid state, thus it is treated as both an input and output to the source. However, the validity signal should not be driven by any other circuit, i.e. it should have no fanin. Shared-validity sinks do not respond to data-rails at all, they only respond to the validity signal with the acknowledge. Thus it is the responsibility of the circuit under test to provide the validity signal.
After configuring channels as sourcing or sinking environments, there is one more additional step to enabling them. Channels startup in the stopped state, in which they do no respond to any changes in the circuit, data-rails or acknowledges. Resetting a channel forces a channel into its initial state. For sources, the data rails are always neutral. For sinks, the acknowledge is in the initial state that was specified when the channel was declared. A channel will begin to respond to the circuit only after it has been released. Channels may be individually stopped or released, and reset-all and release-all are also provided for convenience.
Force a environment-configured channel into its reset state, i.e. a source will reset its data rails to neutral (ignoring state of acknowledge), and a sink will set the acknowledge to the initial value (from configuration) regardless of the data rails (and validity). IMPORTANT: This command also freezes a channel in the stopped state, like channel-stop and will not respond to signal changes until resumed by channel-release.
Force all source- or sink- configured channels into their reset state, as done by channel-reset. This is typically done at the same time as global reset initalization.
Freeze a source- or sink-configured channel so that it stops responding to signal transitions from the circuit. Stopped channels will not log data nor assert expected values because they may be in a transient state. A channel can be unfrozen by channel-release.
For channels that are sinking and expecting values (non-loop), stop sinking as soon as expected values are exhausted. The default behavior for a sink is to continue sinking regardless of checking against expected values.
Releases a source- or sink-configured channel from the stopped state, so that it begins to respond to circuit signal transitions (and continue logging and expecting). Upon resuming, the channel evaluates its inputs and adds events to the event queue as deemed appropriate.
Applies channel-release to all channels. This is typically used at the end of a reset initialization sequence as the circuit is brought out of the reset state.
Timing: delays are given some default value, except in random timing mode, where delays are randomized. TODO: configure after delays on sources and sinks.
Re-initialization: The initialize and reset also affect the state of channels. initialize retains the configuration (source, sink, watch, expect) of all channels, however, the data rail tracking is reset to account for all nodes being set to X. All output log streams are closed. Value sequences for sourcing and expecting are retained, but the position index is reset to 0, the beginning. (Rationale: it is uncommon to start at different offsets in the value sequences.) reset will completely wipe all registered channels, as if the simulator had just started up.