------------------------------------------------------------------------------- -- Title : Standard VITAL TIMING Package -- : $Revision: 95.1 $ -- Library : VITAL -- : -- Developers : IEEE DASC Timing Working Group (TWG), PAR 1076.4 -- : -- Purpose : This packages defines standard types, attributes, constants, -- : functions and procedures for use in developing ASIC models. -- : This file contains the Package Body. -- ---------------------------------------------------------------------------- -- -- ---------------------------------------------------------------------------- -- Modification History : -- ---------------------------------------------------------------------------- -- Version No:|Auth:| Mod.Date:| Changes Made: -- v95.0 A | | 06/08/95 | Initial ballot draft 1995 -- v95.1 | | 08/31/95 | #203 - Timing violations at time 0 -- #204 - Output mapping prior to glitch detection -- ---------------------------------------------------------------------------- LIBRARY STD; USE STD.TEXTIO.ALL; PACKAGE BODY VITAL_Timing IS -- -------------------------------------------------------------------- -- Package Local Declarations -- -------------------------------------------------------------------- TYPE CheckType IS ( SetupCheck, HoldCheck, RecoveryCheck, RemovalCheck, PulseWidCheck, PeriodCheck ); TYPE CheckInfoType IS RECORD Violation : BOOLEAN; CheckKind : CheckType; ObsTime : TIME; ExpTime : TIME; DetTime : TIME; State : X01; END RECORD; TYPE LogicCvtTableType IS ARRAY (std_ulogic) OF CHARACTER; TYPE HiLoStrType IS ARRAY (std_ulogic RANGE 'X' TO '1') OF STRING(1 TO 4); CONSTANT LogicCvtTable : LogicCvtTableType := ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'); CONSTANT HiLoStr : HiLoStrType := (" X ", " Low", "High" ); TYPE EdgeSymbolMatchType IS ARRAY (X01,X01,VitalEdgeSymbolType) OF BOOLEAN; -- last value, present value, edge symbol CONSTANT EdgeSymbolMatch : EdgeSymbolMatchType := ( 'X'=>('X'=>( OTHERS => FALSE), '0'=>('N'|'F'|'v'|'E'|'D'|'*' => TRUE, OTHERS => FALSE ), '1'=>('P'|'R'|'^'|'E'|'A'|'*' => TRUE, OTHERS => FALSE ) ), '0'=>('X'=>( 'r'|'p'|'R'|'A'|'*' => TRUE, OTHERS => FALSE ), '0'=>( OTHERS => FALSE ), '1'=>( '/'|'P'|'p'|'R'|'*' => TRUE, OTHERS => FALSE ) ), '1'=>('X'=>( 'f'|'n'|'F'|'D'|'*' => TRUE, OTHERS => FALSE ), '0'=>( '\'|'N'|'n'|'F'|'*' => TRUE, OTHERS => FALSE ), '1'=>( OTHERS => FALSE ) ) ); --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- Misc Utilities Local Utilities --------------------------------------------------------------------------- ----------------------------------------------------------------------- FUNCTION Minimum ( CONSTANT t1,t2 : IN TIME ) RETURN TIME IS BEGIN IF ( t1 < t2 ) THEN RETURN (t1); ELSE RETURN (t2); END IF; END Minimum; ----------------------------------------------------------------------- FUNCTION Maximum ( CONSTANT t1,t2 : IN TIME ) RETURN TIME IS BEGIN IF ( t1 > t2 ) THEN RETURN (t1); ELSE RETURN (t2); END IF; END Maximum; -------------------------------------------------------------------- -- Error Message Types and Tables -------------------------------------------------------------------- TYPE VitalErrorType IS ( ErrVctLng , ErrNoPath , ErrNegPath , ErrNegDel ); TYPE VitalErrorSeverityType IS ARRAY (VitalErrorType) OF SEVERITY_LEVEL; CONSTANT VitalErrorSeverity : VitalErrorSeverityType := ( ErrVctLng => ERROR, ErrNoPath => WARNING, ErrNegPath => WARNING, ErrNegDel => WARNING ); CONSTANT MsgNoPath : STRING := "No Delay Path Condition TRUE. 0-delay used. Output signal is: "; CONSTANT MsgNegPath : STRING := "Path Delay less than time since input. 0 delay used. Output signal is: "; CONSTANT MsgNegDel : STRING := "Negative delay. New output value not scheduled. Output signal is: "; CONSTANT MsgVctLng : STRING := "Vector (array) lengths not equal. "; CONSTANT MsgUnknown : STRING := "Unknown error message."; FUNCTION VitalMessage ( CONSTANT ErrorId : IN VitalErrorType ) RETURN STRING IS BEGIN CASE ErrorId IS WHEN ErrVctLng => RETURN MsgVctLng; WHEN ErrNoPath => RETURN MsgNoPath; WHEN ErrNegPath => RETURN MsgNegPath; WHEN ErrNegDel => RETURN MsgNegDel; WHEN OTHERS => RETURN MsgUnknown; END CASE; END; PROCEDURE VitalError ( CONSTANT Routine : IN STRING; CONSTANT ErrorId : IN VitalErrorType ) IS BEGIN ASSERT FALSE REPORT Routine & ": " & VitalMessage(ErrorId) SEVERITY VitalErrorSeverity(ErrorId); END; PROCEDURE VitalError ( CONSTANT Routine : IN STRING; CONSTANT ErrorId : IN VitalErrorType; CONSTANT Info : IN STRING ) IS BEGIN ASSERT FALSE REPORT Routine & ": " & VitalMessage(ErrorId) & Info SEVERITY VitalErrorSeverity(ErrorId); END; PROCEDURE VitalError ( CONSTANT Routine : IN STRING; CONSTANT ErrorId : IN VitalErrorType; CONSTANT Info : IN CHARACTER ) IS BEGIN ASSERT FALSE REPORT Routine & ": " & VitalMessage(ErrorId) & Info SEVERITY VitalErrorSeverity(ErrorId); END; --------------------------------------------------------------------------- -- Time Delay Assignment Subprograms --------------------------------------------------------------------------- FUNCTION VitalExtendToFillDelay ( CONSTANT Delay : IN VitalDelayType ) RETURN VitalDelayType01Z IS BEGIN RETURN (OTHERS => Delay); END VitalExtendToFillDelay; FUNCTION VitalExtendToFillDelay ( CONSTANT Delay : IN VitalDelayType01 ) RETURN VitalDelayType01Z IS VARIABLE Delay01Z : VitalDelayType01Z; BEGIN Delay01Z(tr01) := Delay(tr01); Delay01Z(tr0z) := Delay(tr01); Delay01Z(trz1) := Delay(tr01); Delay01Z(tr10) := Delay(tr10); Delay01Z(tr1z) := Delay(tr10); Delay01Z(trz0) := Delay(tr10); RETURN (Delay01Z); END VitalExtendToFillDelay; FUNCTION VitalExtendToFillDelay ( CONSTANT Delay : IN VitalDelayType01Z ) RETURN VitalDelayType01Z IS BEGIN RETURN Delay; END VitalExtendToFillDelay; --------------------------------------------------------------------------- FUNCTION VitalCalcDelay ( CONSTANT NewVal : IN std_ulogic := 'X'; CONSTANT OldVal : IN std_ulogic := 'X'; CONSTANT Delay : IN VitalDelayType ) RETURN TIME IS BEGIN RETURN delay; END VitalCalcDelay; FUNCTION VitalCalcDelay ( CONSTANT NewVal : IN std_ulogic := 'X'; CONSTANT OldVal : IN std_ulogic := 'X'; CONSTANT Delay : IN VitalDelayType01 ) RETURN TIME IS VARIABLE Result : TIME; BEGIN CASE Newval IS WHEN '0' | 'L' => Result := Delay(tr10); WHEN '1' | 'H' => Result := Delay(tr01); WHEN 'Z' => CASE Oldval IS WHEN '0' | 'L' => Result := Delay(tr01); WHEN '1' | 'H' => Result := Delay(tr10); WHEN OTHERS => Result := MAXIMUM(Delay(tr10), Delay(tr01)); END CASE; WHEN OTHERS => CASE Oldval IS WHEN '0' | 'L' => Result := Delay(tr01); WHEN '1' | 'H' => Result := Delay(tr10); WHEN 'Z' => Result := MINIMUM(Delay(tr10), Delay(tr01)); WHEN OTHERS => Result := MAXIMUM(Delay(tr10), Delay(tr01)); END CASE; END CASE; RETURN Result; END VitalCalcDelay; FUNCTION VitalCalcDelay ( CONSTANT NewVal : IN std_ulogic := 'X'; CONSTANT OldVal : IN std_ulogic := 'X'; CONSTANT Delay : IN VitalDelayType01Z ) RETURN TIME IS VARIABLE Result : TIME; BEGIN CASE Oldval IS WHEN '0' | 'L' => CASE Newval IS WHEN '0' | 'L' => Result := Delay(tr10); WHEN '1' | 'H' => Result := Delay(tr01); WHEN 'Z' => Result := Delay(tr0z); WHEN OTHERS => Result := MINIMUM(Delay(tr01), Delay(tr0z)); END CASE; WHEN '1' | 'H' => CASE Newval IS WHEN '0' | 'L' => Result := Delay(tr10); WHEN '1' | 'H' => Result := Delay(tr01); WHEN 'Z' => Result := Delay(tr1z); WHEN OTHERS => Result := MINIMUM(Delay(tr10), Delay(tr1z)); END CASE; WHEN 'Z' => CASE Newval IS WHEN '0' | 'L' => Result := Delay(trz0); WHEN '1' | 'H' => Result := Delay(trz1); WHEN 'Z' => Result := MAXIMUM (Delay(tr0z), Delay(tr1z)); WHEN OTHERS => Result := MINIMUM (Delay(trz1), Delay(trz0)); END CASE; WHEN 'U' | 'X' | 'W' | '-' => CASE Newval IS WHEN '0' | 'L' => Result := MAXIMUM(Delay(tr10), Delay(trz0)); WHEN '1' | 'H' => Result := MAXIMUM(Delay(tr01), Delay(trz1)); WHEN 'Z' => Result := MAXIMUM(Delay(tr1z), Delay(tr0z)); WHEN OTHERS => Result := MAXIMUM(Delay(tr10), Delay(tr01)); END CASE; END CASE; RETURN Result; END VitalCalcDelay; --------------------------------------------------------------------------- FUNCTION VitalSelectPathDelay ( CONSTANT NewValue : IN std_logic; CONSTANT OldValue : IN std_logic; CONSTANT OutSignalName : IN string; CONSTANT Paths : IN VitalPathArrayType; CONSTANT DefaultDelay : IN VitalDelayType ) RETURN TIME IS VARIABLE TmpDelay : TIME; VARIABLE InputAge : TIME := TIME'HIGH; VARIABLE PropDelay : TIME := TIME'HIGH; BEGIN -- for each delay path FOR i IN Paths'RANGE LOOP -- ignore the delay path if it is not enabled NEXT WHEN NOT Paths(i).PathCondition; -- ignore the delay path if a more recent input event has been seen NEXT WHEN Paths(i).InputChangeTime > InputAge; -- This is the most recent input change (so far) -- Get the transition dependent delay TmpDelay := VitalCalcDelay(NewValue, OldValue, Paths(i).PathDelay); -- If other inputs changed at the same time, -- then use the minimum of their propagation delays, -- else use the propagation delay from this input. IF Paths(i).InputChangeTime < InputAge THEN PropDelay := TmpDelay; ELSE -- Simultaneous inputs change IF TmpDelay < PropDelay THEN PropDelay := TmpDelay; END IF; end if; InputAge := Paths(i).InputChangeTime; END LOOP; -- If there were no paths (with an enabled condition), -- use the default the delay IF (PropDelay = TIME'HIGH ) THEN PropDelay := VitalCalcDelay(NewValue, OldValue, DefaultDelay); -- If the time since the most recent input event is greater than the -- propagation delay from that input then -- use the default the delay ELSIF (InputAge > PropDelay) THEN PropDelay := VitalCalcDelay(NewValue, OldValue, DefaultDelay); -- Adjust the propagation delay by the time since the -- the input event occurred (Usually 0 ns). ELSE PropDelay := PropDelay - InputAge; END IF; RETURN PropDelay; END; FUNCTION VitalSelectPathDelay ( CONSTANT NewValue : IN std_logic; CONSTANT OldValue : IN std_logic; CONSTANT OutSignalName : IN string; CONSTANT Paths : IN VitalPathArray01Type; CONSTANT DefaultDelay : IN VitalDelayType01 ) RETURN TIME IS VARIABLE TmpDelay : TIME; VARIABLE InputAge : TIME := TIME'HIGH; VARIABLE PropDelay : TIME := TIME'HIGH; BEGIN -- for each delay path FOR i IN Paths'RANGE LOOP -- ignore the delay path if it is not enabled NEXT WHEN NOT Paths(i).PathCondition; -- ignore the delay path if a more recent input event has been seen NEXT WHEN Paths(i).InputChangeTime > InputAge; -- This is the most recent input change (so far) -- Get the transition dependent delay TmpDelay := VitalCalcDelay(NewValue, OldValue, Paths(i).PathDelay); -- If other inputs changed at the same time, -- then use the minimum of their propagation delays, -- else use the propagation delay from this input. IF Paths(i).InputChangeTime < InputAge THEN PropDelay := TmpDelay; ELSE -- Simultaneous inputs change IF TmpDelay < PropDelay THEN PropDelay := TmpDelay; END IF; end if; InputAge := Paths(i).InputChangeTime; END LOOP; -- If there were no paths (with an enabled condition), -- use the default the delay IF (PropDelay = TIME'HIGH ) THEN PropDelay := VitalCalcDelay(NewValue, OldValue, DefaultDelay); -- If the time since the most recent input event is greater than the -- propagation delay from that input then -- use the default the delay ELSIF (InputAge > PropDelay) THEN PropDelay := VitalCalcDelay(NewValue, OldValue, DefaultDelay); -- Adjust the propagation delay by the time since the -- the input event occurred (Usually 0 ns). ELSE PropDelay := PropDelay - InputAge; END IF; RETURN PropDelay; END; FUNCTION VitalSelectPathDelay ( CONSTANT NewValue : IN std_logic; CONSTANT OldValue : IN std_logic; CONSTANT OutSignalName : IN string; CONSTANT Paths : IN VitalPathArray01ZType; CONSTANT DefaultDelay : IN VitalDelayType01Z ) RETURN TIME IS VARIABLE TmpDelay : TIME; VARIABLE InputAge : TIME := TIME'HIGH; VARIABLE PropDelay : TIME := TIME'HIGH; BEGIN -- for each delay path FOR i IN Paths'RANGE LOOP -- ignore the delay path if it is not enabled NEXT WHEN NOT Paths(i).PathCondition; -- ignore the delay path if a more recent input event has been seen NEXT WHEN Paths(i).InputChangeTime > InputAge; -- This is the most recent input change (so far) -- Get the transition dependent delay TmpDelay := VitalCalcDelay(NewValue, OldValue, Paths(i).PathDelay); -- If other inputs changed at the same time, -- then use the minimum of their propagation delays, -- else use the propagation delay from this input. IF Paths(i).InputChangeTime < InputAge THEN PropDelay := TmpDelay; ELSE -- Simultaneous inputs change IF TmpDelay < PropDelay THEN PropDelay := TmpDelay; END IF; end if; InputAge := Paths(i).InputChangeTime; END LOOP; -- If there were no paths (with an enabled condition), -- use the default the delay IF (PropDelay = TIME'HIGH ) THEN PropDelay := VitalCalcDelay(NewValue, OldValue, DefaultDelay); -- If the time since the most recent input event is greater than the -- propagation delay from that input then -- use the default the delay ELSIF (InputAge > PropDelay) THEN PropDelay := VitalCalcDelay(NewValue, OldValue, DefaultDelay); -- Adjust the propagation delay by the time since the -- the input event occurred (Usually 0 ns). ELSE PropDelay := PropDelay - InputAge; END IF; RETURN PropDelay; END; --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- Glitch Handlers --------------------------------------------------------------------------- --------------------------------------------------------------------------- PROCEDURE ReportGlitch ( CONSTANT GlitchRoutine : IN STRING; CONSTANT OutSignalName : IN STRING; CONSTANT PreemptedTime : IN TIME; CONSTANT PreemptedValue : IN std_ulogic; CONSTANT NewTime : IN TIME; CONSTANT NewValue : IN std_ulogic; CONSTANT Index : IN INTEGER := 0; CONSTANT IsArraySignal : IN BOOLEAN := FALSE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS VARIABLE StrPtr1, StrPtr2, StrPtr3, StrPtr4, StrPtr5 : LINE; BEGIN Write (StrPtr1, PreemptedTime ); Write (StrPtr2, NewTime); Write (StrPtr3, LogicCvtTable(PreemptedValue)); Write (StrPtr4, LogicCvtTable(NewValue)); IF IsArraySignal THEN Write (StrPtr5, STRING'( "(" ) ); Write (StrPtr5, Index); Write (StrPtr5, STRING'( ")" ) ); ELSE Write (StrPtr5, STRING'( " " ) ); END IF; -- Issue Report only if Preempted value has not been -- removed from event queue ASSERT PreemptedTime > NewTime REPORT GlitchRoutine & ": GLITCH Detected on port " & OutSignalName & StrPtr5.ALL & "; Preempted Future Value := " & StrPtr3.ALL & " @ " & StrPtr1.ALL & "; Newly Scheduled Value := " & StrPtr4.ALL & " @ " & StrPtr2.ALL & ";" SEVERITY MsgSeverity; DEALLOCATE(StrPtr1); DEALLOCATE(StrPtr2); DEALLOCATE(StrPtr3); DEALLOCATE(StrPtr4); DEALLOCATE(StrPtr5); RETURN; END ReportGlitch; --------------------------------------------------------------------------- PROCEDURE VitalGlitch ( SIGNAL OutSignal : OUT std_logic; VARIABLE GlitchData : INOUT VitalGlitchDataType; CONSTANT OutSignalName : IN string; CONSTANT NewValue : IN std_logic; CONSTANT NewDelay : IN TIME := 0 ns; CONSTANT Mode : IN VitalGlitchKindType := OnEvent; CONSTANT XOn : IN BOOLEAN := TRUE; CONSTANT MsgOn : IN BOOLEAN := FALSE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS --------------------------------------------------------------------------- VARIABLE NewGlitch : BOOLEAN := TRUE; VARIABLE dly : TIME := NewDelay; BEGIN -- If nothing to schedule, just return IF NewDelay < 0 ns THEN IF (NewValue /= GlitchData.SchedValue) THEN VitalError ( "VitalGlitch", ErrNegDel, OutSignalName ); END IF; RETURN; END IF; -- If simple signal assignment -- perform the signal assignment IF ( Mode = VitalInertial) THEN OutSignal <= NewValue AFTER dly; ELSIF ( Mode = VitalTransport ) THEN OutSignal <= TRANSPORT NewValue AFTER dly; ELSE -- Glitch Processing --- -- If nothing currently scheduled IF GlitchData.SchedTime <= NOW THEN -- Note: NewValue is always /= OldValue when called from VPPD IF (NewValue = GlitchData.SchedValue) THEN RETURN; END IF; -- No new glitch, save time for possable future glitch NewGlitch := FALSE; GlitchData.GlitchTime := NOW+dly; -- New value earlier than the earliest previous value scheduled ELSIF (NOW+dly <= GlitchData.GlitchTime) AND (NOW+dly <= GlitchData.SchedTime) THEN -- No new glitch, save time for possible future glitch NewGlitch := FALSE; GlitchData.GlitchTime := NOW+dly; -- Transaction currently scheduled - if glitch already happened ELSIF GlitchData.GlitchTime <= NOW THEN IF (GlitchData.SchedValue = NewValue) THEN dly := Minimum( GlitchData.SchedTime-NOW, NewDelay ); END IF; NewGlitch := FALSE; -- Transaction currently scheduled (no glitch if same value) ELSIF (GlitchData.SchedValue = NewValue) AND (GlitchData.SchedTime = GlitchData.GlitchTime) THEN -- revise scheduled output time if new delay is sooner dly := Minimum( GlitchData.SchedTime-NOW, NewDelay ); -- No new glitch, save time for possable future glitch NewGlitch := FALSE; GlitchData.GlitchTime := NOW+dly; -- Transaction currently scheduled represents a glitch ELSE -- A new glitch has been detected NewGlitch := TRUE; END IF; IF NewGlitch THEN -- If messages requested, report the glitch IF MsgOn THEN ReportGlitch ("VitalGlitch", OutSignalName, GlitchData.GlitchTime, GlitchData.SchedValue, (dly + NOW), NewValue, MsgSeverity=>MsgSeverity ); END IF; -- Force immediate glitch for "OnDetect" mode. IF (Mode = OnDetect) THEN GlitchData.GlitchTime := NOW; END IF; -- If 'X' generation is requested, schedule the new value -- preceeded by a glitch pulse. -- Otherwise just schedule the new value (inertial mode). IF XOn THEN OutSignal <= 'X' AFTER GlitchData.GlitchTime-NOW; OutSignal <= TRANSPORT NewValue AFTER dly; ELSE OutSignal <= NewValue AFTER dly; END IF; -- If there no new glitch was detected, just schedule the new value. ELSE OutSignal <= NewValue AFTER dly; END IF; END IF; -- Record the new value and time just scheduled. GlitchData.SchedValue := NewValue; GlitchData.SchedTime := NOW+dly; RETURN; END; --------------------------------------------------------------------------- PROCEDURE VitalPathDelay ( SIGNAL OutSignal : OUT std_logic; VARIABLE GlitchData : INOUT VitalGlitchDataType; CONSTANT OutSignalName : IN string; CONSTANT OutTemp : IN std_logic; CONSTANT Paths : IN VitalPathArrayType; CONSTANT DefaultDelay : IN VitalDelayType := VitalZeroDelay; CONSTANT Mode : IN VitalGlitchKindType := OnEvent; CONSTANT XOn : IN BOOLEAN := TRUE; CONSTANT MsgOn : IN BOOLEAN := TRUE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS VARIABLE PropDelay : TIME; BEGIN -- Check if the new value to be scheduled is different than the -- previously scheduled value IF (GlitchData.SchedTime <= NOW) AND (GlitchData.SchedValue = OutTemp) THEN RETURN; END IF; -- Evaluate propagation delay paths PropDelay := VitalSelectPathDelay (OutTemp, GlitchData.LastValue, OutSignalName, Paths, DefaultDelay); GlitchData.LastValue := OutTemp; -- Schedule the output transactions - including glitch handling VitalGlitch (OutSignal, GlitchData, OutSignalName, OutTemp, PropDelay, Mode, XOn, MsgOn, MsgSeverity ); END VitalPathDelay; PROCEDURE VitalPathDelay01 ( SIGNAL OutSignal : OUT std_logic; VARIABLE GlitchData : INOUT VitalGlitchDataType; CONSTANT OutSignalName : IN string; CONSTANT OutTemp : IN std_logic; CONSTANT Paths : IN VitalPathArray01Type; CONSTANT DefaultDelay : IN VitalDelayType01 := VitalZeroDelay01; CONSTANT Mode : IN VitalGlitchKindType := OnEvent; CONSTANT XOn : IN BOOLEAN := TRUE; CONSTANT MsgOn : IN BOOLEAN := TRUE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS VARIABLE PropDelay : TIME; BEGIN -- Check if the new value to be scheduled is different than the -- previously scheduled value IF (GlitchData.SchedTime <= NOW) AND (GlitchData.SchedValue = OutTemp) THEN RETURN; END IF; -- Evaluate propagation delay paths PropDelay := VitalSelectPathDelay (OutTemp, GlitchData.LastValue, OutSignalName, Paths, DefaultDelay); GlitchData.LastValue := OutTemp; -- Schedule the output transactions - including glitch handling VitalGlitch (OutSignal, GlitchData, OutSignalName, OutTemp, PropDelay, Mode, XOn, MsgOn, MsgSeverity ); END VitalPathDelay01; PROCEDURE VitalPathDelay01Z ( SIGNAL OutSignal : OUT std_logic; VARIABLE GlitchData : INOUT VitalGlitchDataType; CONSTANT OutSignalName : IN string; CONSTANT OutTemp : IN std_logic; CONSTANT Paths : IN VitalPathArray01ZType; CONSTANT DefaultDelay : IN VitalDelayType01Z := VitalZeroDelay01Z; CONSTANT Mode : IN VitalGlitchKindType := OnEvent; CONSTANT XOn : IN BOOLEAN := TRUE; CONSTANT MsgOn : IN BOOLEAN := TRUE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING; CONSTANT OutputMap : IN VitalOutputMapType := VitalDefaultOutputMap ) IS VARIABLE PropDelay : TIME; BEGIN -- Check if the new value to be scheduled is different than the -- previously scheduled value IF (GlitchData.SchedTime <= NOW) AND (GlitchData.SchedValue = OutputMap(OutTemp) ) THEN RETURN; END IF; -- Evaluate propagation delay paths PropDelay := VitalSelectPathDelay (OutTemp, GlitchData.LastValue, OutSignalName, Paths, DefaultDelay); GlitchData.LastValue := OutTemp; -- Schedule the output transactions - including glitch handling VitalGlitch (OutSignal, GlitchData, OutSignalName, OutputMap(OutTemp), PropDelay, Mode, XOn, MsgOn, MsgSeverity ); END VitalPathDelay01Z; ---------------------------------------------------------------------------- PROCEDURE VitalWireDelay ( SIGNAL OutSig : OUT std_ulogic; SIGNAL InSig : IN std_ulogic; CONSTANT twire : IN VitalDelayType ) IS BEGIN OutSig <= TRANSPORT InSig AFTER twire; END VitalWireDelay; PROCEDURE VitalWireDelay ( SIGNAL OutSig : OUT std_ulogic; SIGNAL InSig : IN std_ulogic; CONSTANT twire : IN VitalDelayType01 ) IS VARIABLE Delay : TIME; BEGIN Delay := VitalCalcDelay( InSig, InSig'LAST_VALUE, twire ); OutSig <= TRANSPORT InSig AFTER Delay; END VitalWireDelay; PROCEDURE VitalWireDelay ( SIGNAL OutSig : OUT std_ulogic; SIGNAL InSig : IN std_ulogic; CONSTANT twire : IN VitalDelayType01Z ) IS VARIABLE Delay : TIME; BEGIN Delay := VitalCalcDelay( InSig, InSig'LAST_VALUE, twire ); OutSig <= TRANSPORT InSig AFTER Delay; END VitalWireDelay; ---------------------------------------------------------------------------- PROCEDURE VitalSignalDelay ( SIGNAL OutSig : OUT std_ulogic; SIGNAL InSig : IN std_ulogic; CONSTANT dly : IN TIME ) IS BEGIN OutSig <= TRANSPORT InSig AFTER dly; END; --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- Setup and Hold Time Check Routine --------------------------------------------------------------------------- --------------------------------------------------------------------------- PROCEDURE ReportViolation ( CONSTANT TestSignalName : IN STRING := ""; CONSTANT RefSignalName : IN STRING := ""; CONSTANT HeaderMsg : IN STRING := " "; CONSTANT CheckInfo : IN CheckInfoType; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS VARIABLE Message : LINE; BEGIN IF NOT CheckInfo.Violation THEN RETURN; END IF; Write ( Message, HeaderMsg ); Case CheckInfo.CheckKind IS WHEN SetupCheck => Write ( Message, STRING'(" SETUP ") ); WHEN HoldCheck => Write ( Message, STRING'(" HOLD ") ); WHEN RecoveryCheck => Write ( Message, STRING'(" RECOVERY ") ); WHEN RemovalCheck => Write ( Message, STRING'(" REMOVAL ") ); WHEN PulseWidCheck => Write ( Message, STRING'(" PULSE WIDTH ")); WHEN PeriodCheck => Write ( Message, STRING'(" PERIOD ") ); END CASE; Write ( Message, HiLoStr(CheckInfo.State) ); Write ( Message, STRING'(" VIOLATION ON ") ); Write ( Message, TestSignalName ); IF (RefSignalName'LENGTH > 0) THEN Write ( Message, STRING'(" WITH RESPECT TO ") ); Write ( Message, RefSignalName ); END IF; Write ( Message, ';' & LF ); Write ( Message, STRING'(" Expected := ") ); Write ( Message, CheckInfo.ExpTime); Write ( Message, STRING'("; Observed := ") ); Write ( Message, CheckInfo.ObsTime); Write ( Message, STRING'("; At : ") ); Write ( Message, CheckInfo.DetTime); ASSERT FALSE REPORT Message.ALL SEVERITY MsgSeverity; DEALLOCATE (Message); END ReportViolation; --------------------------------------------------------------------------- -- Procedure : InternalTimingCheck --------------------------------------------------------------------------- PROCEDURE InternalTimingCheck ( CONSTANT TestSignal : IN std_ulogic; CONSTANT RefSignal : IN std_ulogic; CONSTANT TestDelay : IN TIME := 0 ns; CONSTANT RefDelay : IN TIME := 0 ns; CONSTANT SetupHigh : IN TIME := 0 ns; CONSTANT SetupLow : IN TIME := 0 ns; CONSTANT HoldHigh : IN TIME := 0 ns; CONSTANT HoldLow : IN TIME := 0 ns; VARIABLE RefTime : IN TIME; VARIABLE RefEdge : IN BOOLEAN; VARIABLE TestTime : IN TIME; VARIABLE TestEvent : IN BOOLEAN; VARIABLE SetupEn : INOUT BOOLEAN; VARIABLE HoldEn : INOUT BOOLEAN; VARIABLE CheckInfo : INOUT CheckInfoType; CONSTANT MsgOn : IN BOOLEAN ) IS VARIABLE bias, b2 : TIME; BEGIN -- Check SETUP constraint IF RefEdge THEN IF SetupEn THEN CheckInfo.ObsTime := RefTime - TestTime; CheckInfo.State := To_X01(TestSignal); CASE CheckInfo.State IS WHEN '0' => CheckInfo.ExpTime := SetupLow; WHEN '1' => CheckInfo.ExpTime := SetupHigh; WHEN 'X' => CheckInfo.ExpTime := Maximum(SetupHigh,SetupLow); END CASE; CheckInfo.Violation := CheckInfo.ObsTime < CheckInfo.ExpTime; SetupEn := FALSE; ELSE CheckInfo.Violation := FALSE; END IF; -- Check HOLD constraint ELSIF TestEvent THEN IF HoldEn THEN CheckInfo.ObsTime := TestTime - RefTime; CheckInfo.State := To_X01(TestSignal); CASE CheckInfo.State IS WHEN '0' => CheckInfo.ExpTime := HoldHigh; WHEN '1' => CheckInfo.ExpTime := HoldLow; WHEN 'X' => CheckInfo.ExpTime := Maximum(HoldHigh,HoldLow); END CASE; CheckInfo.Violation := CheckInfo.ObsTime < CheckInfo.ExpTime; HoldEn := NOT CheckInfo.Violation; ELSE CheckInfo.Violation := FALSE; END IF; ELSE CheckInfo.Violation := FALSE; END IF; -- Adjust report values to account for internal model delays -- Note: TestDelay, RefDelay, TestTime, RefTime and bias are non-negative IF MsgOn AND CheckInfo.Violation THEN bias := TestDelay - RefDelay; IF TestTime - RefTime <= bias THEN CheckInfo.CheckKind := SetupCheck; b2 := TIME'HIGH - bias; IF (CheckInfo.ObsTime <= b2) THEN CheckInfo.ObsTime := CheckInfo.ObsTime + bias; ELSE CheckInfo.ObsTime := Time'HIGH; END IF; IF (CheckInfo.ExpTime <= b2) THEN CheckInfo.ExpTime := CheckInfo.ExpTime + bias; ELSE CheckInfo.ExpTime := Time'HIGH; END IF; CheckInfo.DetTime := RefTime - RefDelay; ELSE CheckInfo.CheckKind := HoldCheck; CheckInfo.ObsTime := CheckInfo.ObsTime - bias; IF (CheckInfo.ExpTime >= 0 ns) THEN CheckInfo.ExpTime := CheckInfo.ExpTime - bias; END IF; CheckInfo.DetTime := TestTime - TestDelay; END IF; END IF; END InternalTimingCheck; --------------------------------------------------------------------------- --------------------------------------------------------------------------- FUNCTION VitalTimingDataInit RETURN VitalTimingDataType IS BEGIN RETURN (FALSE,'X', 0 ns, FALSE, 'X', 0 ns, FALSE, NULL, NULL, NULL, NULL); END; --------------------------------------------------------------------------- -- Procedure : VitalSetupHoldCheck --------------------------------------------------------------------------- PROCEDURE VitalSetupHoldCheck ( VARIABLE Violation : OUT X01; VARIABLE TimingData : INOUT VitalTimingDataType; SIGNAL TestSignal : IN std_ulogic; CONSTANT TestSignalName: IN STRING := ""; CONSTANT TestDelay : IN TIME := 0 ns; SIGNAL RefSignal : IN std_ulogic; CONSTANT RefSignalName : IN STRING := ""; CONSTANT RefDelay : IN TIME := 0 ns; CONSTANT SetupHigh : IN TIME := 0 ns; CONSTANT SetupLow : IN TIME := 0 ns; CONSTANT HoldHigh : IN TIME := 0 ns; CONSTANT HoldLow : IN TIME := 0 ns; CONSTANT CheckEnabled : IN BOOLEAN := TRUE; CONSTANT RefTransition : IN VitalEdgeSymbolType; CONSTANT HeaderMsg : IN STRING := " "; CONSTANT XOn : IN BOOLEAN := TRUE; CONSTANT MsgOn : IN BOOLEAN := TRUE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS VARIABLE CheckInfo : CheckInfoType; VARIABLE RefEdge, TestEvent : BOOLEAN; VARIABLE TestDly : TIME := Maximum(0 ns, TestDelay); VARIABLE RefDly : TIME := Maximum(0 ns, RefDelay); VARIABLE bias : TIME; BEGIN IF (TimingData.NotFirstFlag = FALSE) THEN TimingData.TestLast := To_X01(TestSignal); TimingData.RefLast := To_X01(RefSignal); TimingData.NotFirstFlag := TRUE; END IF; -- Detect reference edges and record the time of the last edge RefEdge := EdgeSymbolMatch(TimingData.RefLast, To_X01(RefSignal), RefTransition); TimingData.RefLast := To_X01(RefSignal); IF RefEdge THEN TimingData.RefTime := NOW; TimingData.HoldEn := TRUE; END IF; -- Detect test (data) changes and record the time of the last change TestEvent := TimingData.TestLast /= To_X01Z(TestSignal); TimingData.TestLast := To_X01Z(TestSignal); IF TestEvent THEN TimingData.TestTime := NOW; TimingData.SetupEn := TRUE; END IF; -- Perform timing checks (if enabled) Violation := '0'; IF (CheckEnabled) THEN InternalTimingCheck ( TestSignal => TestSignal, RefSignal => RefSignal, TestDelay => TestDly, RefDelay => RefDly, SetupHigh => SetupHigh, SetupLow => SetupLow, HoldHigh => HoldHigh, HoldLow => HoldLow, RefTime => TimingData.RefTime, RefEdge => RefEdge, TestTime => TimingData.TestTime, TestEvent => TestEvent, SetupEn => TimingData.SetupEn, HoldEn => TimingData.HoldEn, CheckInfo => CheckInfo, MsgOn => MsgOn ); -- Report any detected violations and set return violation flag IF CheckInfo.Violation THEN IF (MsgOn) THEN ReportViolation (TestSignalName, RefSignalName, HeaderMsg, CheckInfo, MsgSeverity ); END IF; IF (XOn) THEN Violation := 'X'; END IF; END IF; END IF; END VitalSetupHoldCheck; --------------------------------------------------------------------------- PROCEDURE VitalSetupHoldCheck ( VARIABLE Violation : OUT X01; VARIABLE TimingData : INOUT VitalTimingDataType; SIGNAL TestSignal : IN std_logic_vector; CONSTANT TestSignalName: IN STRING := ""; CONSTANT TestDelay : IN TIME := 0 ns; SIGNAL RefSignal : IN std_ulogic; CONSTANT RefSignalName : IN STRING := ""; CONSTANT RefDelay : IN TIME := 0 ns; CONSTANT SetupHigh : IN TIME := 0 ns; CONSTANT SetupLow : IN TIME := 0 ns; CONSTANT HoldHigh : IN TIME := 0 ns; CONSTANT HoldLow : IN TIME := 0 ns; CONSTANT CheckEnabled : IN BOOLEAN := TRUE; CONSTANT RefTransition : IN VitalEdgeSymbolType; CONSTANT HeaderMsg : IN STRING := " "; CONSTANT XOn : IN BOOLEAN := TRUE; CONSTANT MsgOn : IN BOOLEAN := TRUE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS VARIABLE CheckInfo : CheckInfoType; VARIABLE RefEdge : BOOLEAN; VARIABLE TestEvent : VitalBoolArrayT(TestSignal'RANGE); VARIABLE TestDly : TIME := Maximum(0 ns, TestDelay); VARIABLE RefDly : TIME := Maximum(0 ns, RefDelay); VARIABLE bias : TIME; VARIABLE ChangedAllAtOnce : BOOLEAN := TRUE; VARIABLE StrPtr1 : LINE; BEGIN -- Initialization of working area. IF (TimingData.NotFirstFlag = FALSE) THEN TimingData.TestLastA := NEW std_logic_vector(TestSignal'RANGE); TimingData.TestTimeA := NEW VitalTimeArrayT(TestSignal'RANGE); TimingData.HoldEnA := NEW VitalBoolArrayT(TestSignal'RANGE); TimingData.SetupEnA := NEW VitalBoolArrayT(TestSignal'RANGE); FOR i IN TestSignal'RANGE LOOP TimingData.TestLastA(i) := To_X01(TestSignal(i)); END LOOP; TimingData.RefLast := To_X01(RefSignal); TimingData.NotFirstFlag := TRUE; END IF; -- Detect reference edges and record the time of the last edge RefEdge := EdgeSymbolMatch(TimingData.RefLast, To_X01(RefSignal), RefTransition); TimingData.RefLast := To_X01(RefSignal); IF RefEdge THEN TimingData.RefTime := NOW; TimingData.HoldEnA.all := (TestSignal'RANGE=>TRUE); END IF; -- Detect test (data) changes and record the time of the last change FOR i IN TestSignal'RANGE LOOP TestEvent(i) := TimingData.TestLastA(i) /= To_X01Z(TestSignal(i)); TimingData.TestLastA(i) := To_X01Z(TestSignal(i)); IF TestEvent(i) THEN TimingData.TestTimeA(i) := NOW; TimingData.SetupEnA(i) := TRUE; TimingData.TestTime := NOW; END IF; END LOOP; -- Check to see if the Bus subelements changed all at the same time. -- If so, then we can reduce the volume of error messages since we no -- longer have to report every subelement individually FOR i IN TestSignal'RANGE LOOP IF TimingData.TestTimeA(i) /= TimingData.TestTime THEN ChangedAllAtOnce := FALSE; EXIT; END IF; END LOOP; -- Perform timing checks (if enabled) Violation := '0'; IF (CheckEnabled) THEN FOR i IN TestSignal'RANGE LOOP InternalTimingCheck ( TestSignal => TestSignal(i), RefSignal => RefSignal, TestDelay => TestDly, RefDelay => RefDly, SetupHigh => SetupHigh, SetupLow => SetupLow, HoldHigh => HoldHigh, HoldLow => HoldLow, RefTime => TimingData.RefTime, RefEdge => RefEdge, TestTime => TimingData.TestTimeA(i), TestEvent => TestEvent(i), SetupEn => TimingData.SetupEnA(i), HoldEn => TimingData.HoldEnA(i), CheckInfo => CheckInfo, MsgOn => MsgOn ); -- Report any detected violations and set return violation flag IF CheckInfo.Violation THEN IF (MsgOn) THEN IF ( ChangedAllAtOnce AND (i = TestSignal'LEFT) ) THEN ReportViolation (TestSignalName&"(...)", RefSignalName, HeaderMsg, CheckInfo, MsgSeverity ); ELSIF (NOT ChangedAllAtOnce) THEN Write (StrPtr1, i); ReportViolation (TestSignalName & "(" & StrPtr1.ALL & ")", RefSignalName, HeaderMsg, CheckInfo, MsgSeverity ); DEALLOCATE (StrPtr1); END IF; END IF; IF (XOn) THEN Violation := 'X'; END IF; END IF; END LOOP; END IF; DEALLOCATE (StrPtr1); END VitalSetupHoldCheck; --------------------------------------------------------------------------- -- Function : VitalRecoveryRemovalCheck --------------------------------------------------------------------------- PROCEDURE VitalRecoveryRemovalCheck ( VARIABLE Violation : OUT X01; VARIABLE TimingData : INOUT VitalTimingDataType; SIGNAL TestSignal : IN std_ulogic; CONSTANT TestSignalName: IN STRING := ""; CONSTANT TestDelay : IN TIME := 0 ns; SIGNAL RefSignal : IN std_ulogic; CONSTANT RefSignalName : IN STRING := ""; CONSTANT RefDelay : IN TIME := 0 ns; CONSTANT Recovery : IN TIME := 0 ns; CONSTANT Removal : IN TIME := 0 ns; CONSTANT ActiveLow : IN BOOLEAN := TRUE; CONSTANT CheckEnabled : IN BOOLEAN := TRUE; CONSTANT RefTransition : IN VitalEdgeSymbolType; CONSTANT HeaderMsg : IN STRING := " "; CONSTANT XOn : IN BOOLEAN := TRUE; CONSTANT MsgOn : IN BOOLEAN := TRUE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS VARIABLE CheckInfo : CheckInfoType; VARIABLE RefEdge, TestEvent : BOOLEAN; VARIABLE TestDly : TIME := Maximum(0 ns, TestDelay); VARIABLE RefDly : TIME := Maximum(0 ns, RefDelay); VARIABLE bias : TIME; BEGIN IF (TimingData.NotFirstFlag = FALSE) THEN TimingData.TestLast := To_X01(TestSignal); TimingData.RefLast := To_X01(RefSignal); TimingData.NotFirstFlag := TRUE; END IF; -- Detect reference edges and record the time of the last edge RefEdge := EdgeSymbolMatch(TimingData.RefLast, To_X01(RefSignal), RefTransition); TimingData.RefLast := To_X01(RefSignal); IF RefEdge THEN TimingData.RefTime := NOW; TimingData.HoldEn := TRUE; END IF; -- Detect test (data) changes and record the time of the last change TestEvent := TimingData.TestLast /= To_X01Z(TestSignal); TimingData.TestLast := To_X01Z(TestSignal); IF TestEvent THEN TimingData.TestTime := NOW; TimingData.SetupEn := TRUE; END IF; -- Perform timing checks (if enabled) Violation := '0'; IF (CheckEnabled) THEN IF ActiveLow THEN InternalTimingCheck ( TestSignal, RefSignal, TestDly, RefDly, Recovery, 0 ns, 0 ns, Removal, TimingData.RefTime, RefEdge, TimingData.TestTime, TestEvent, TimingData.SetupEn, TimingData.HoldEn, CheckInfo, MsgOn ); ELSE InternalTimingCheck ( TestSignal, RefSignal, TestDly, RefDly, 0 ns, Recovery, Removal, 0 ns, TimingData.RefTime, RefEdge, TimingData.TestTime, TestEvent, TimingData.SetupEn, TimingData.HoldEn, CheckInfo, MsgOn ); END IF; -- Report any detected violations and set return violation flag IF CheckInfo.Violation THEN IF CheckInfo.CheckKind = SetupCheck THEN CheckInfo.CheckKind := RecoveryCheck; ELSE CheckInfo.CheckKind := RemovalCheck; END IF; IF (MsgOn) THEN ReportViolation (TestSignalName, RefSignalName, HeaderMsg, CheckInfo, MsgSeverity ); END IF; IF (XOn) THEN Violation := 'X'; END IF; END IF; END IF; END VitalRecoveryRemovalCheck; --------------------------------------------------------------------------- PROCEDURE VitalPeriodPulseCheck ( VARIABLE Violation : OUT X01; VARIABLE PeriodData : INOUT VitalPeriodDataType; SIGNAL TestSignal : IN std_ulogic; CONSTANT TestSignalName : IN STRING := ""; CONSTANT TestDelay : IN TIME := 0 ns; CONSTANT Period : IN TIME := 0 ns; CONSTANT PulseWidthHigh : IN TIME := 0 ns; CONSTANT PulseWidthLow : IN TIME := 0 ns; CONSTANT CheckEnabled : IN BOOLEAN := TRUE; CONSTANT HeaderMsg : IN STRING := " "; CONSTANT XOn : IN BOOLEAN := TRUE; CONSTANT MsgOn : IN BOOLEAN := TRUE; CONSTANT MsgSeverity : IN SEVERITY_LEVEL := WARNING ) IS VARIABLE TestDly : TIME := Maximum(0 ns, TestDelay); VARIABLE CheckInfo : CheckInfoType; VARIABLE PeriodObs : TIME; VARIABLE PulseTest, PeriodTest : BOOLEAN; VARIABLE TestValue : X01 := To_X01(TestSignal); BEGIN IF (PeriodData.NotFirstFlag = FALSE) THEN PeriodData.Rise := -maximum(Period, maximum(PulseWidthHigh, PulseWidthLow)); PeriodData.Fall := -maximum(Period, maximum(PulseWidthHigh, PulseWidthLow)); PeriodData.Last := To_X01(TestSignal); PeriodData.NotFirstFlag := TRUE; END IF; -- Initialize for no violation -- No violation possible if no test signal change Violation := '0'; IF (PeriodData.Last = TestValue) THEN RETURN; END IF; -- record starting pulse times IF EdgeSymbolMatch(PeriodData.Last, TestValue, 'P') THEN -- Compute period times, then record the High Rise Time PeriodObs := NOW - PeriodData.Rise; PeriodData.Rise := NOW; PeriodTest := TRUE; ELSIF EdgeSymbolMatch(PeriodData.Last, TestValue, 'N') THEN -- Compute period times, then record the Low Fall Time PeriodObs := NOW - PeriodData.Fall; PeriodData.Fall := NOW; PeriodTest := TRUE; ELSE PeriodTest := FALSE; END IF; -- do checks on pulse ends IF EdgeSymbolMatch(PeriodData.Last, TestValue, 'p') THEN -- Compute pulse times CheckInfo.ObsTime := NOW - PeriodData.Fall; CheckInfo.ExpTime := PulseWidthLow; PulseTest := TRUE; ELSIF EdgeSymbolMatch(PeriodData.Last, TestValue, 'n') THEN -- Compute pulse times CheckInfo.ObsTime := NOW - PeriodData.Rise; CheckInfo.ExpTime := PulseWidthHigh; PulseTest := TRUE; ELSE PulseTest := FALSE; END IF; IF PulseTest AND CheckEnabled THEN -- Verify Pulse Width [ignore 1st edge] IF ( CheckInfo.ObsTime < CheckInfo.ExpTime ) THEN IF (XOn) THEN Violation := 'X'; END IF; IF (MsgOn) THEN CheckInfo.Violation := TRUE; CheckInfo.CheckKind := PulseWidCheck; CheckInfo.DetTime := NOW - TestDly; CheckInfo.State := PeriodData.Last; ReportViolation (TestSignalName, "", HeaderMsg, CheckInfo, MsgSeverity ); END IF; -- MsgOn END IF; END IF; IF PeriodTest AND CheckEnabled THEN -- Verify the Period [ignore 1st edge] CheckInfo.ObsTime := PeriodObs; CheckInfo.ExpTime := Period; IF ( CheckInfo.ObsTime < CheckInfo.ExpTime ) THEN IF (XOn) THEN Violation := 'X'; END IF; IF (MsgOn) THEN CheckInfo.Violation := TRUE; CheckInfo.CheckKind := PeriodCheck; CheckInfo.DetTime := NOW - TestDly; CheckInfo.State := TestValue; ReportViolation (TestSignalName, "", HeaderMsg, CheckInfo, MsgSeverity ); END IF; -- MsgOn END IF; END IF; PeriodData.Last := TestValue; END VitalPeriodPulseCheck; END VITAL_Timing;