-- EMACS settings: -*- tab-width: 2; indent-tabs-mode: t -*- -- vim: tabstop=2:shiftwidth=2:noexpandtab -- kate: tab-width 2; replace-tabs off; indent-width 2; -- -- ============================================================================= -- Authors: Patrick Lehmann -- Thomas B. Preusser -- -- Package: Simulation constants, functions and utilities. -- -- Description: -- ------------------------------------ -- TODO -- -- License: -- ============================================================================= -- Copyright 2007-2016 Technische Universitaet Dresden - Germany -- Chair for VLSI-Design, Diagnostics and Architecture -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- ============================================================================= library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use IEEE.math_real.all; library PoC; use PoC.utils.all; -- use PoC.strings.all; use PoC.vectors.all; use PoC.physical.all; use PoC.sim_global.all; use PoC.sim_types.all; use PoC.sim_protected.all; package simulation is -- Legacy interface for pre VHDL-2002 -- =========================================================================== procedure simInitialize; procedure simFinalize; impure function simCreateTest(Name : STRING) return T_SIM_TEST_ID; impure function simRegisterProcess(Name : STRING) return T_SIM_PROCESS_ID; procedure simDeactivateProcess(ProcID : T_SIM_PROCESS_ID); impure function simIsStopped return BOOLEAN; procedure simWriteMessage(Message : in STRING := ""); -- The testbench is marked as failed. If a message is provided, it is -- reported as an error. procedure simFail(Message : in STRING := ""); -- If the passed condition has evaluated false, the testbench is marked -- as failed. In this case, the optional message will be reported as an -- error if one was provided. procedure simAssertion(cond : in BOOLEAN; Message : in STRING := ""); -- Random Numbers -- =========================================================================== type T_SIM_SEED is record Seed1 : INTEGER; Seed2 : INTEGER; end record; procedure initializeSeed(Seed : inout T_SIM_SEED); procedure getUniformDistibutedRandomValue(Seed : inout T_SIM_SEED; Value : inout REAL; Minimum : in REAL; Maximum : in REAL); procedure getNormalDistibutedRandomValue(Seed : inout T_SIM_SEED; Value : inout REAL; StandardDeviation : in REAL := 1.0; Mean : in REAL := 0.0); procedure getNormalDistibutedRandomValue(Seed : inout T_SIM_SEED; Value : inout REAL; StandardDeviation : in REAL; Mean : in REAL; Minimum : in REAL; Maximum : in REAL); -- clock generation -- =========================================================================== procedure simGenerateClock(signal Clock : out STD_LOGIC; constant Frequency : in FREQ; constant Phase : in T_PHASE := 0 deg; constant DutyCycle : in T_DutyCycle := 50 percent; constant Wander : in T_WANDER := 0 permil); procedure simGenerateClock(signal Clock : out STD_LOGIC; constant Period : in TIME; constant Phase : in T_PHASE := 0 deg; constant DutyCycle : in T_DutyCycle := 50 percent; constant Wander : in T_WANDER := 0 permil); procedure simWaitUntilRisingEdge(signal Clock : in STD_LOGIC; constant Times : in POSITIVE); procedure simWaitUntilFallingEdge(signal Clock : in STD_LOGIC; constant Times : in POSITIVE); procedure simGenerateClock2(signal Clock : out STD_LOGIC; signal Debug : out INTEGER; constant Period : in TIME); -- waveform generation -- =========================================================================== procedure simGenerateWaveform(signal Wave : out BOOLEAN; Waveform: T_TIMEVEC; InitialValue : BOOLEAN); procedure simGenerateWaveform(signal Wave : out STD_LOGIC; Waveform: T_TIMEVEC; InitialValue : STD_LOGIC := '0'); procedure simGenerateWaveform(signal Wave : out STD_LOGIC; Waveform: T_SIM_WAVEFORM_SL; InitialValue : STD_LOGIC := '0'); procedure simGenerateWaveform(signal Wave : out T_SLV_8; Waveform: T_SIM_WAVEFORM_SLV_8; InitialValue : T_SLV_8); procedure simGenerateWaveform(signal Wave : out T_SLV_16; Waveform: T_SIM_WAVEFORM_SLV_16; InitialValue : T_SLV_16); procedure simGenerateWaveform(signal Wave : out T_SLV_24; Waveform: T_SIM_WAVEFORM_SLV_24; InitialValue : T_SLV_24); procedure simGenerateWaveform(signal Wave : out T_SLV_32; Waveform: T_SIM_WAVEFORM_SLV_32; InitialValue : T_SLV_32); procedure simGenerateWaveform(signal Wave : out T_SLV_48; Waveform: T_SIM_WAVEFORM_SLV_48; InitialValue : T_SLV_48); procedure simGenerateWaveform(signal Wave : out T_SLV_64; Waveform: T_SIM_WAVEFORM_SLV_64; InitialValue : T_SLV_64); function simGenerateWaveform_Reset(constant Pause : TIME := 0 ns; ResetPulse : TIME := 10 ns) return T_TIMEVEC; -- TODO: integrate VCD simulation functions and procedures from sim_value_change_dump.vhdl here -- checksum functions -- =========================================================================== -- TODO: move checksum functions here end package; package body simulation is -- legacy procedures -- =========================================================================== -- TODO: undocumented group procedure simInitialize is begin globalSimulationStatus.initialize; end procedure; procedure simFinalize is begin globalSimulationStatus.finalize; end procedure; impure function simCreateTest(Name : STRING) return T_SIM_TEST_ID is begin return globalSimulationStatus.createTest(Name); end function; impure function simRegisterProcess(Name : STRING) return T_SIM_PROCESS_ID is begin return globalSimulationStatus.registerProcess(Name); end function; procedure simDeactivateProcess(ProcID : T_SIM_PROCESS_ID) is begin globalSimulationStatus.deactivateProcess(ProcID); end procedure; impure function simIsStopped return BOOLEAN is begin return globalSimulationStatus.isStopped; end function; -- TODO: undocumented group procedure simWriteMessage(Message : in STRING := "") is begin globalSimulationStatus.writeMessage(Message); end procedure; procedure simFail(Message : in STRING := "") is begin globalSimulationStatus.fail(Message); end procedure; procedure simAssertion(cond : in BOOLEAN; Message : in STRING := "") is begin globalSimulationStatus.assertion(cond, Message); end procedure; -- =========================================================================== -- Random Numbers -- =========================================================================== procedure initializeSeed(Seed : inout T_SIM_SEED) is begin Seed.Seed1 := 5; Seed.Seed2 := 3423; end procedure; procedure getUniformDistibutedRandomValue(Seed : inout T_SIM_SEED; Value : inout REAL; Minimum : in REAL; Maximum : in REAL) is variable rand : REAL; begin if (Maximum < Minimum) then report "getUniformDistibutedRandomValue: Maximum must be greater than Minimum." severity FAILURE; end if; ieee.math_real.Uniform(Seed.Seed1, Seed.Seed2, rand); Value := scale(rand, Minimum, Maximum); end procedure ; procedure getNormalDistibutedRandomValue(Seed : inout T_SIM_SEED; Value : inout REAL; StandardDeviation : in REAL := 1.0; Mean : in REAL := 0.0) is variable rand1 : REAL; variable rand2 : REAL; begin if StandardDeviation < 0.0 then report "getNormalDistibutedRandomValue: Standard deviation must be >= 0.0" severity FAILURE; end if; -- Box Muller transformation ieee.math_real.Uniform(Seed.Seed1, Seed.Seed2, rand1); ieee.math_real.Uniform(Seed.Seed1, Seed.Seed2, rand2); -- standard normal distribution: mean 0, variance 1 Value := StandardDeviation * (sqrt(-2.0 * log(rand1)) * cos(MATH_2_PI * rand2)) + Mean; end procedure; procedure getNormalDistibutedRandomValue(Seed : inout T_SIM_SEED; Value : inout REAL; StandardDeviation : in REAL; Mean : in REAL; Minimum : in REAL; Maximum : in REAL) is variable rand : REAL; begin if (Maximum < Minimum) then report "getUniformDistibutedRandomValue: Maximum must be greater than Minimum." severity FAILURE; end if; if StandardDeviation < 0.0 then report "getNormalDistibutedRandomValue: Standard deviation must be >= 0.0" severity FAILURE; end if; while (TRUE) loop getNormalDistibutedRandomValue(Seed, rand, StandardDeviation, Mean); exit when ((Minimum <= rand) and (rand <= Maximum)); end loop; Value := rand; end procedure; -- clock generation -- =========================================================================== procedure simGenerateClock(signal Clock : out STD_LOGIC; constant Frequency : in FREQ; constant Phase : in T_PHASE := 0 deg; constant DutyCycle : in T_DUTYCYCLE := 50 percent; constant Wander : in T_WANDER := 0 permil) is constant Period : TIME := to_time(Frequency); begin simGenerateClock(Clock, Period, Phase, DutyCycle, Wander); end procedure; procedure simGenerateClock( signal Clock : out STD_LOGIC; constant Period : in TIME; constant Phase : in T_PHASE := 0 deg; constant DutyCycle : in T_DUTYCYCLE := 50 percent; constant Wander : in T_WANDER := 0 permil ) is constant NormalizedPhase : T_PHASE := ite((Phase >= 0 deg), Phase, Phase + 360 deg); -- move Phase into the range of 0° to 360° constant PhaseAsFactor : REAL := real(NormalizedPhase / 1 second) / 1296000.0; -- 1,296,000 = 3,600 seconds * 360 degree per cycle constant WanderAsFactor : REAL := real(Wander / 1 ppb) / 1.0e9; constant DutyCycleAsFactor : REAL := real(DutyCycle / 1 permil) / 1000.0; constant Delay : TIME := Period * PhaseAsFactor; constant TimeHigh : TIME := Period * DutyCycleAsFactor + (Period * (WanderAsFactor / 2.0)); -- add 50% wander to the high level constant TimeLow : TIME := Period - TimeHigh + (Period * WanderAsFactor); -- and 50% to the low level constant ClockAfterRun_cy : POSITIVE := 1; begin report "simGenerateClock: (Instance: '" & Clock'instance_name & "')" & CR & "Period: " & TIME'image(Period) & CR & "Phase: " & T_PHASE'image(Phase) & CR & "DutyCycle: " & T_DUTYCYCLE'image(DutyCycle) & CR & "PhaseAsFactor: " & REAL'image(PhaseAsFactor) & CR & "WanderAsFactor: " & REAL'image(WanderAsFactor) & CR & "DutyCycleAsFactor: " & REAL'image(DutyCycleAsFactor) & CR & "Delay: " & TIME'image(Delay) & CR & "TimeHigh: " & TIME'image(TimeHigh) & CR & "TimeLow: " & TIME'image(TimeLow) severity NOTE; if (Delay = 0 ns) then null; elsif (Delay <= TimeLow) then Clock <= '0'; wait for Delay; else Clock <= '1'; wait for Delay - TimeLow; Clock <= '0'; wait for TimeLow; end if; Clock <= '1'; while (not globalSimulationStatus.isStopped) loop wait for TimeHigh; Clock <= '0'; wait for TimeLow; Clock <= '1'; end loop; -- create N more cycles to allow other processes to recognize the stop condition (clock after run) for i in 1 to ClockAfterRun_cy loop wait for TimeHigh; Clock <= '0'; wait for TimeLow; Clock <= '1'; end loop; Clock <= '0'; end procedure; type T_SIM_NORMAL_DIST_PARAMETER is record StandardDeviation : REAL; Mean : REAL; end record; type T_JITTER_DISTRIBUTION is array (NATURAL range <>) of T_SIM_NORMAL_DIST_PARAMETER; procedure simGenerateClock2(signal Clock : out STD_LOGIC; signal Debug : out INTEGER; constant Period : in TIME) is constant TimeHigh : TIME := Period * 0.5; constant TimeLow : TIME := Period - TimeHigh; constant JitterPeakPeak : REAL := 0.1; -- UI constant JitterAsFactor : REAL := JitterPeakPeak / 4.0; -- Maximum jitter per edge constant JitterDistribution : T_JITTER_DISTRIBUTION := (0 => (0.6, 0.0)); --((0.2, -0.3), (0.3, -0.1), (0.5, 0.0), (0.3, 0.1), (0.2, 0.3)); variable Seed : T_SIM_SEED; variable rand : REAL; variable sum : REAL; variable Jitter : REAL; begin Clock <= '1'; initializeSeed(Seed); while (not globalSimulationStatus.isStopped) loop sum := 0.0; for i in JitterDistribution'range loop getNormalDistibutedRandomValue(Seed, rand, JitterDistribution(i).StandardDeviation, JitterDistribution(i).Mean, -1.0, 1.0); sum := sum + rand; end loop; Debug <= integer(sum * 1000.0); Jitter := JitterAsFactor * sum; -- Debug <= integer(rand * 256.0 + 256.0); wait for TimeHigh + (Period * Jitter); Clock <= '0'; wait for TimeLow + (Period * Jitter); Clock <= '1'; end loop; Clock <= '0'; end procedure; procedure simWaitUntilRisingEdge(signal Clock : in STD_LOGIC; constant Times : in POSITIVE) is begin for i in 1 to Times loop wait until rising_edge(Clock); exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simWaitUntilFallingEdge(signal Clock : in STD_LOGIC; constant Times : in POSITIVE) is begin for i in 1 to Times loop wait until falling_edge(Clock); exit when globalSimulationStatus.isStopped; end loop; end procedure; -- waveform generation -- =========================================================================== procedure simGenerateWaveform(signal Wave : out BOOLEAN; Waveform : T_TIMEVEC; InitialValue : BOOLEAN) is variable State : BOOLEAN := InitialValue; begin Wave <= State; for i in Waveform'range loop wait for Waveform(i); State := not State; Wave <= State; exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simGenerateWaveform(signal Wave : out STD_LOGIC; Waveform: T_TIMEVEC; InitialValue : STD_LOGIC := '0') is variable State : STD_LOGIC := InitialValue; begin Wave <= State; for i in Waveform'range loop wait for Waveform(i); State := not State; Wave <= State; exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simGenerateWaveform(signal Wave : out STD_LOGIC; Waveform: T_SIM_WAVEFORM_SL; InitialValue : STD_LOGIC := '0') is begin Wave <= InitialValue; for i in Waveform'range loop wait for Waveform(i).Delay; Wave <= Waveform(i).Value; exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simGenerateWaveform(signal Wave : out T_SLV_8; Waveform: T_SIM_WAVEFORM_SLV_8; InitialValue : T_SLV_8) is begin Wave <= InitialValue; for i in Waveform'range loop wait for Waveform(i).Delay; Wave <= Waveform(i).Value; exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simGenerateWaveform(signal Wave : out T_SLV_16; Waveform: T_SIM_WAVEFORM_SLV_16; InitialValue : T_SLV_16) is begin Wave <= InitialValue; for i in Waveform'range loop wait for Waveform(i).Delay; Wave <= Waveform(i).Value; exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simGenerateWaveform(signal Wave : out T_SLV_24; Waveform: T_SIM_WAVEFORM_SLV_24; InitialValue : T_SLV_24) is begin Wave <= InitialValue; for i in Waveform'range loop wait for Waveform(i).Delay; Wave <= Waveform(i).Value; exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simGenerateWaveform(signal Wave : out T_SLV_32; Waveform: T_SIM_WAVEFORM_SLV_32; InitialValue : T_SLV_32) is begin Wave <= InitialValue; for i in Waveform'range loop wait for Waveform(i).Delay; Wave <= Waveform(i).Value; exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simGenerateWaveform(signal Wave : out T_SLV_48; Waveform: T_SIM_WAVEFORM_SLV_48; InitialValue : T_SLV_48) is begin Wave <= InitialValue; for i in Waveform'range loop wait for Waveform(i).Delay; Wave <= Waveform(i).Value; exit when globalSimulationStatus.isStopped; end loop; end procedure; procedure simGenerateWaveform(signal Wave : out T_SLV_64; Waveform: T_SIM_WAVEFORM_SLV_64; InitialValue : T_SLV_64) is begin Wave <= InitialValue; for i in Waveform'range loop wait for Waveform(i).Delay; Wave <= Waveform(i).Value; exit when globalSimulationStatus.isStopped; end loop; end procedure; function simGenerateWaveform_Reset(constant Pause : TIME := 0 ns; ResetPulse : TIME := 10 ns) return T_TIMEVEC is variable p : TIME; variable rp : TIME; begin -- WORKAROUND: for QuestaSim/ModelSim -- Version: 10.4c -- Issue: -- return (0 => Pause, 1 => ResetPulse); always evaluates to (0 ns, 10 ns), -- regardless of the passed function parameters p := Pause; rp := ResetPulse; return (0 => p, 1 => rp); end function; -- checksum functions -- =========================================================================== -- TODO: move checksum functions here end package body;