ECL models apparently must fall into the category of models "that have unusual requirements not typically encountered by ASIC model writers". This paper will show why that is so, and will discuss several tricks and techniques for "moving the line" dividing models simple enough to write completely compliant to VITAL Level 1, and models too complex to do so farther towards the complex models. This greater adherence to the standard should prove beneficial in general since more models will be portable, readily readable to VITAL-knowledgable persons, and acceleratable by the simulators that take advantage of VITAL.
Specific areas investigated by this paper include: single-ended versus differential inputs and how to do them using VITAL, modeling ECL signal strengths, VITAL-compliant tables which effectively model ECL differential inputs and clocks, the case for a VitalSignalAssign primitive, and the use of VITAL processes in series - why series processes are the best way to do some ECL models and how to pass signals between processes.
In modeling ECL parts with differential signals, outputs represent a case that hardly needs discussion; the output signal is generated for one of the two opposite polarity pins, and the other is inverted.
With ECL differential inputs, the modeling is more complicated. There are two cases that we've isolated for our modeling at TRW, although more could be defined if greater accuracy were required. Both cases involve the treatment of input skew, or the delta time between the edge of one differential signal pair and the other during a logic transition. Skew can enter a simulation by backannotating PCB route delays onto the differential signal nets, for example. Both cases use the assignment of an internal signal or variable to represent as a scalar the result of an evaluation of the differential signal pair.
One case is defined for inputs where the value of the differential signal can be assigned std_logic value `X' during any skew time. This is close to the real-world expectation of an ECL part's behavior since, when both halfs of a differential signal pair are at the same logic value ( another way of defining skew ) the noise immunity of the input is practically nothing. While some hysteresis may prevent a logic transition given little or no noise or overshoot on the the signal line, unknown behavior is a prudent assumption. An example of this case is the "D" differential inputs of an ECL flip flop. Since the "D" input is only relevant at the clock edge, and need be stable only for the setup and hold times measured from the clock edge, the state of the "D" input as seen by the model (or the internal state) can be accurately assigned `X' during a skew interval when the logic value of "D" is changing.
Another case is defined for inputs where skew time between the positive and negative differential inputs is relatively short, but the value `X' cannot be assigned to the internal signal or variable representing the differential signal pair during the skew time because `X' should not propagate through the model. Instead, the model should wait until the lagging half of the differential signal pair "completes the transition", and make the change in logic value. In the real world, the circuit ought to have been designed so the skew time is minimal so that any noise-induced false transitions during skew time are less than the glitch sensitivity of the part (at this point, this paper cops a plea that the subject of high speed design is not the area of expertise of the writer and is not the subject of this paper). An ECL clock input is an example of this case; if during a rising edge event, the positive differential input transitions from logic `0' to `1' a few hundred picoseconds skew time before the negative differential input transitions from logic `1' to `0', the internal value of the clock input within the model should stay logic `0' until the negative differential input changes, then go to `1'.
VITAL primitives provide an input parameter called ResultMap, of type VitalResultMap, which performs the mapping onto the default VITAL primitive output values (`U', `X', `0', `1') of a user-defined set. To model ECL Wired-OR parts accurately, a ResultMap of the form (`U', `X', `L', `1') maps the weak low value `L' onto an output where `0' would normally occur. We do not use the five-valued form of the ResultMap to map a different value, such as `W', onto the default output value `Z' because we don't see a need for it, and we wish to reserve the use of `W' (as described in a subsequent section).
If an ECL part is being driven with a weak signal value, a VITAL-compliant model can do one of two things. Either it can accept that value without modification, and VITAL procedures and functions will treat it like a strong value of the same logic type; or the model can somehow test the value to determine the strength and proceed accordingly - most likely treating the `L' value on the input the same as a `Z' or `X' value.
Since calls to functions and procedures other than VITAL are not allowed in VITAL architectures, nor are control structures such as "IFs", "CASEs", or "LOOPs" allowed in VITAL processes, the model is somewhat limited in what it can do to test input strengths that are not tested in anything supplied by VITAL. Certainly the following is not allowed:
IF ( input_signal = `0' or input_signal = `1') THENFortunately, constants in VITAL architectures are not restricted, so a model can be constructed with static, constant lookup maps and tables to perform just about any conceivable function on std_logic values. (This paper uses the naming convention `map' for a one-dimensional array and table for a 2-dimensional array). The only limitation is that their use must be restricted to variable assignments within processes, since VITAL explicitly outlaws signal assignments except in VITAL concurrent procedure calls, or in the VitalPathDelay procedure within a process.
internal_input_variable := input_signal;
ELSE
internal_input_variable := `X';
END IF;
An example of a lookup map for doing the above assignment of internal_input_variable consists of two parts. First a type declaration and a constant declaration are put into the architecture declaration region of the model.
TYPE stdlogic_map IS ARRAY(std_ulogic) OF std_ulogic;The std_ulogic type inside the array guarantees that when the variable assignment from the table is performed, the variable will be of type std_ulogic which is required of VITAL process variables (types BOOLEAN or TIME are legal too but are not applicable here).
CONSTANT ECL_no_weak_inputs: stdlogic_map :=
------------------------------------------------
-- U .. X .. 0 .. 1 .. Z .. W .. L .. H .. - ...
------------------------------------------------
( `X', `X', `0', `1', `X', `X', `X', `X', `X' );
Then the variable assignment is performed in a process.
-- assume we're in a process ...The model uses internal_input_variable to determine the model behavior. If the input_signal has not been pulled-down, the model will propagate the `X' value.
internal_input_variable := ECL_no_weak_inputs(input_signal);
If we rule out the use of `W' and `H' in any user-defined ResultMap ( which is fine in the ECL Wired-OR environment - but might conceivably be a problem in an environment mixing, say, ECL Wired-OR parts and TTL open collector parts - but even there the two kinds of parts should never be wired directly together, should they?), and we take care not to drive a `W' from a test bench or a script, `W' can be used for other purposes without concern it might appear at the input to a model unintentionally.
We propose and use `W' to indicate that an input to an ECL model is connected to VBB. Also, VBB outputs from ECL models are driven to `W' by the model.
Then, techniques which build on the technique of using lookup maps and tables can be used within the model to determine whether the usage of the model is single-ended or differential, and process accordingly.
The type declaration and constant declaration for this lookup table are as follows.
TYPE stdlogic_table IS ARRAY(std_ulogic, std_ulogic) OF std_ulogic;In a VITAL model, the port signals D and D_N, the differential inputs, propagated through a VitalWireDelay procedure become D_ipd and D_N_ipd respectively. The internal variable Dint_zd is assigned in a process as shown in the statement below. Note that the order of the array subscripts is important: if D_ipd has value `W', the table inverts the value of D_N_ipd.
CONSTANT ECL_s_or_d_inputs_tab: stdlogic_table := (
-------------------------------------------------------
-- U .. X .. 0 .. 1 .. Z .. W .. L .. H .. -...--------
-------------------------------------------------------
( `U', `U', `U', `U', `U', `U', `U', `U', `U'), -- U --
( `U', `X', `X', `X', `X', `X', `X', `X', `X'), -- X --
( `U', `X', `X', `0', `X', `0', `X', `0', `X'), -- 0 --
( `U', `X', `1', `X', `X', `1', `1', `X', `X'), -- 1 --
( `U', `X', `X', `X', `X', `X', `X', `X', `X'), -- Z --
( `U', `X', `1', `0', `X', `X', `1', `0', `X'), -- W --
( `U', `X', `X', `0', `X', `0', `X', `0', `X'), -- L --
( `U', `X', `1', `X', `X', `1', `1', `X', `X'), -- H --
( `U', `X', `X', `X', `X', `X', `X', `X', `X') --- - --
);
Dint_zd := ECL_s_or_d_inputs_tab(D_ipd, D_N_ipd);
The variable Dint_zd is used like a single-ended input to determine the behavior of the D flip flop. If that functionality is in the same process, this table lookup must precede it since processes are executed sequentially and variables are assigned immediately in VHDL.The `X' values assigned to Dint_zd whenever skew in the transitions of D_ipd and D_N_ipd occur do not affect the model since Dint_zd should be stable when the clock edge occurs. The VITAL model ought to be written with Timing Checks for Setup and Hold if the data for these is available.
In the architecture delclaration region the following TYPE and two CONSTANTs are declared.
TYPE stdlogic_table IS ARRAY(std_ulogic, std_ulogic) OF std_ulogic;These lookup tables are used in a VITAL process by first declaring a variable Mode, of type X01, a subtype of std_logic. Mode is assigned by lookup from the ECL_diff_mode_tab table using the differential clock signals as indices. Mode has the value `1' if the differential clock input is single-ended, VBB on CLK, the value `0' if single-ended, VBB on CLK_N, or the value `X' if it the clock is diffenential, no VBB seen on either pin.
CONSTANT ECL_diff_mode_tab: stdlogic_table := (
-------------------------------------------------------
-- U .. X .. 0 .. 1 .. Z .. W .. L .. H .. -...--------
-------------------------------------------------------
( `X', `X', `X', `X', `X', `0', `X', `X', `X'), -- U --
( `X', `X', `X', `X', `X', `0', `X', `X', `X'), -- X --
( `X', `X', `X', `X', `X', `0', `X', `X', `X'), -- 0 --
( `X', `X', `X', `X', `X', `0', `X', `X', `X'), -- 1 --
( `X', `X', `X', `X', `X', `0', `X', `X', `X'), -- Z --
( `1', `1', `1', `1', `1', `X', `1', `1', `1'), -- W --
( `X', `X', `X', `X', `X', `0', `X', `X', `X'), -- L --
( `X', `X', `X', `X', `X', `0', `X', `X', `X'), -- H --
( `X', `X', `X', `X', `X', `0', `X', `X', `X'), -- - --
);
CONSTANT ECL_clk_tab : VitalStateTableType := (
-- --INPUTS-------|--PREV--|-OUTPUT----
-- CLK CLK_N Mode | CLKint | CLKint' --
---------------------------------------
-- Below are single-ended clock cases
( `-', `X', `1', `-', `X' ), -- single-ended, Vbb on CLK
( `-', `0', `1', `-', `1' ), -- single-ended, Vbb on CLK
( `-', `1', `1', `-', `0' ), -- single-ended, Vbb on CLK
( `X', `-', `0', `-', `X' ), -- single-ended, Vbb on CLK_N
( `0', `-', `0', `-', `0' ), -- single-ended, Vbb on CLK_N
( `1', `-', `0', `-', `1' ), -- single-ended, Vbb on CLK_N
-- Below are differential clock cases
( `X', `-', `X', `-', `X' ), -- CLK unknown
( `-', `X', `X', `-', `X' ), -- CLK unknown
( `1', `-', `X', `X', `1' ), -- Recover from `X'
( `0', `-', `X', `X', `0' ), -- Recover from `X'
( `/', `0', `X', `0', `1' ), -- valid ECL rising edge
( `1', `\', `X', `0', `1' ), -- valid ECL rising edge
( `\', `1', `X', `1', `0' ), -- valid ECL falling edge
( `0', `/', `X', `1', `0' ), -- valid ECL falling edge
( `-', `-', `-', `-', `S' ) --- default
); -- End of VitalStateTableType definition
With Mode detemined, the second table, a VitalStateTable, is used to assign an internal variable CLKint_zd to represent the logical state of the clock. The VitalStateTable has one state to keep track of the previous value of CLKint_zd which is important for distinguishing the various cases (the full line-by-line study of the table is left as an exercise for the reader !). The full process that we use over and over again in our ECL parts is shown below. Notice that the process assigns a signal, CLKint, so that other processes may utilize it to implement the functionality of the model. ECLclock just does ECL clocks.
-------------------------------------------------------------------------
-- ECL CLock Process
-------------------------------------------------------------------------
ECLclock: PROCESS (CLK_ipd, CLK_N_ipd)
-- Functionality Results Variables
VARIABLE Mode : X01 := `X';
VARIABLE CLKint_zd : std_ulogic := `X';
VARIABLE PrevData : std_logic_vector(1 to 3) := (OTHERS => `X');
-- Output Glitch Detection Variables
VARIABLE CLK_GlitchData : ValidGlitchDataType;
BEGIN
---------------------------------------------------------------------
-- Funtionality Section
---------------------------------------------------------------------
Mode := ECL_diff_mode_tab(CLK_ipd, CLK_N_ipd);
VitalStateTable (
StateTable => ECL_clk_tab,
DataIn => (CLK_ipd, CLK_N_ipd, Mode),
Result => CLKint_zd,
PreviousDataIn => PrevData );
---------------------------------------------------------------------
-- (Dummy) Path Delay Section
---------------------------------------------------------------------
VitalPathDelay (
OutSignal => CLKint,
OutSignalName => "CLKint",
OutTemp => CLKint_zd,
Paths => ( 0 => UseDefaultDelay),
GlitchData => CLK_GlitchData );
END PROCESS;
One consideration to take into account in "splitting" functionality into multiple processes is a speed-up of the model that occurs because of the narrowed sensitivities of the separate processes. If a single, large process has all the model's functionality, and an all-encompassing sensitivity list to boot, then it is activated from front to end every time any of those sensitivity list signals has an event. Smaller, separate processes have smaller sensitivity lists so that an event on a particular signal need not force the entire functionality of the model to be run. In this respect, the separate processes isolate and filter the activity of the model.
More about this "dummy" use of VitalPathDelay: one of the intended consequences of VITAL is to restrict the ways signals can be assigned within VHDL models, so that simulation vendors can have a very limited set of cases for event scheduling to deal with when they go about the task of accelerating their simulators. That is a layman's way of describing it, but I think it's close. To that end, in a process, VitalPathDelay is the ONLY legal way to assign a signal. Since VITAL3.0 explicitly allows multiple processes, it is inevitable that, for those models where processes " in series" are a natural, efficient, and/or readable way to describe a part, VitalPathDelay is going to be used as I've used it here: as a dummy signal assignment statement.
By the way, "UseDefaultDelay" is just a constant which passes a null VitalPathType into the procedure. That parameter and the GlitchData parameter have to be passed into dummy VitalPathDelay because there is no default value declared in the procedure.
CONSTANT UseDefaultDelay : VitalPathType ( InputChangeTime => 0 ps,It is my hope that the VITAL TAG will put a new procedure into VITAL which ought to be called VitalSignalAssign. This procedure would only be allowed in processes, only be allowed once per signal (all operations would be done on the variable, not the signal), and would not unduly burden the efforts of simulation vendors seeking the highest possible performance. They could even treat VitalSignalAssign as an alias for the VitalPathDelay procedure, but with the zero-delay parameters automatically passed. My wish is to not have to write code that declares a GlitchData variable, and passes a null VitialPathType when all I want to do is assign a zero-delayed signal. If implemented, the process signal assignment would look something like this.
PathDelay => VitalZeroDelay,
PathCondition => FALSE );
VitalSignalAssign (SignalOut => CLKint, VarIn => CLKint_zd);
Skew has been discussed with respect to inputs where skew time can be safely modeled as `X', and clocks where the model ought to wait until the other differential signal "completes the transition". Models for some ECL parts might need values for maximum skew time allowed. If extreme thoroughness in the model is desired, one of the Vital Timing Check procedures can be cleverly used to check for maximum skew time exceeded. If the violation occurs, the model can set a violation variable and the ECL_clk_tab VitalStateTable can be enhanced to have a column for the violation input.
In the Cadence environment, Leapfrog supplies the simula - TOR (i.e., the person simulating) with one of its better products.The VHDL models are moderately easy to integrate into a mixed simulation environment using Opensim - we do this all the time with existing RapidSim library parts. Users wishing to implement a simulation environment based on standards, easily portable to other vendors' tools, and guaranteed to be valid for a long time (no pun intended), might want to seriously consider writing models in VITAL.