diff options
author | Tristan Gingold <tgingold@free.fr> | 2017-05-18 08:01:02 +0200 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2017-05-18 08:01:02 +0200 |
commit | cff9d9a80bc14e81684fd5e02a361c171737022d (patch) | |
tree | cc40a1f680ae5a8ecd1db3e6f27c6a0cbfb30741 /testsuite/gna/issue317/PoC/src/sim | |
parent | 2e3634206b04775398f712a4da735d70a32020f2 (diff) | |
download | ghdl-cff9d9a80bc14e81684fd5e02a361c171737022d.tar.gz ghdl-cff9d9a80bc14e81684fd5e02a361c171737022d.tar.bz2 ghdl-cff9d9a80bc14e81684fd5e02a361c171737022d.zip |
Add testcase for #317
Diffstat (limited to 'testsuite/gna/issue317/PoC/src/sim')
-rw-r--r-- | testsuite/gna/issue317/PoC/src/sim/sim_global.v08.vhdl | 42 | ||||
-rw-r--r-- | testsuite/gna/issue317/PoC/src/sim/sim_protected.v08.vhdl | 489 | ||||
-rw-r--r-- | testsuite/gna/issue317/PoC/src/sim/sim_simulation.v08.vhdl | 173 | ||||
-rw-r--r-- | testsuite/gna/issue317/PoC/src/sim/sim_types.vhdl | 376 | ||||
-rw-r--r-- | testsuite/gna/issue317/PoC/src/sim/sim_waveform.vhdl | 981 |
5 files changed, 2061 insertions, 0 deletions
diff --git a/testsuite/gna/issue317/PoC/src/sim/sim_global.v08.vhdl b/testsuite/gna/issue317/PoC/src/sim/sim_global.v08.vhdl new file mode 100644 index 000000000..02ebe003e --- /dev/null +++ b/testsuite/gna/issue317/PoC/src/sim/sim_global.v08.vhdl @@ -0,0 +1,42 @@ +-- 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 +-- +-- Package: Global simulation constants and shared varibales. +-- +-- Description: +-- ------------------------------------- +-- .. TODO:: No documentation available. +-- +-- License: +-- ============================================================================= +-- Copyright 2007-2016 Technische Universitaet Dresden - Germany +-- Chair of 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 PoC; +use PoC.FileIO.all; +use PoC.sim_protected.all; + + +package sim_global is + -- The default global status objects. + -- =========================================================================== + shared variable globalSimulationStatus : T_SIM_STATUS; + shared variable globalLogFile : T_LOGFILE; + shared variable globalStdOut : T_STDOUT; +end package; diff --git a/testsuite/gna/issue317/PoC/src/sim/sim_protected.v08.vhdl b/testsuite/gna/issue317/PoC/src/sim/sim_protected.v08.vhdl new file mode 100644 index 000000000..64b9568bb --- /dev/null +++ b/testsuite/gna/issue317/PoC/src/sim/sim_protected.v08.vhdl @@ -0,0 +1,489 @@ +-- 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:: No documentation available. +-- +-- License: +-- ============================================================================= +-- Copyright 2007-2016 Technische Universitaet Dresden - Germany +-- Chair of 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. +-- ============================================================================= + +use STD.TextIO.all; + +library IEEE; +use IEEE.STD_LOGIC_1164.all; + +library PoC; +use PoC.utils.all; +use PoC.strings.all; +use PoC.vectors.all; +use PoC.physical.all; + +use PoC.sim_types.all; + + +package sim_protected is + -- Simulation Task and Status Management + -- =========================================================================== + type T_SIM_STATUS is protected + -- Initializer and Finalizer + procedure initialize(MaxAssertFailures : natural := natural'high; MaxSimulationRuntime : TIME := TIME'high); + procedure finalize; + + -- Assertions + procedure fail(Message : string := ""); + procedure assertion(Condition : boolean; Message : string := ""); + procedure writeMessage(Message : string); + procedure writeReport; + + -- Process Management + impure function registerProcess(Name : string; IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID; + impure function registerProcess(TestID : T_SIM_TEST_ID; Name : string; IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID; + procedure deactivateProcess(procID : T_SIM_PROCESS_ID; SkipLowPriority : boolean := FALSE); + procedure stopAllProcesses; + procedure stopProcesses(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID); + + -- Test Management + procedure createDefaultTest; + impure function createTest(Name : string) return T_SIM_TEST_ID; + procedure activateDefaultTest; + procedure finalizeTest; + procedure finalizeTest(TestID : T_SIM_TEST_ID); + + -- Run Management + procedure stopAllClocks; + procedure stopClocks(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID); + + impure function isStopped(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean; + impure function isFinalized(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean; + impure function isAllFinalized return boolean; + end protected; +end package; + + +package body sim_protected is + -- Simulation process and Status Management + -- =========================================================================== + type T_SIM_STATUS_STATE is record + IsInitialized : boolean; + IsFinalized : boolean; + end record; + + type T_SIM_STATUS is protected body + -- status + variable State : T_SIM_STATUS_STATE := (FALSE, FALSE); + + variable Max_AssertFailures : natural := natural'high; + variable Max_SimulationRuntime : time := time'high; + + -- Internal state variable to log a failure condition for final reporting. + -- Once de-asserted, this variable will never return to a value of true. + variable Passed : boolean := TRUE; + variable AssertCount : natural := 0; + variable FailedAssertCount : natural := 0; + + -- Clock Management + variable MainProcessEnables : T_SIM_BOOLVEC(T_SIM_TEST_ID) := (others => TRUE); + variable MainClockEnables : T_SIM_BOOLVEC(T_SIM_TEST_ID) := (others => TRUE); + + -- Process Management + variable ProcessCount : natural := 0; + variable ActiveProcessCount : natural := 0; + variable Processes : T_SIM_PROCESS_VECTOR(T_SIM_PROCESS_ID); + + -- Test Management + variable TestCount : natural := 0; + variable ActiveTestCount : natural := 0; + variable Tests : T_SIM_TEST_VECTOR(T_SIM_TEST_ID); + + -- Initializer + procedure init is + begin + if (State.IsInitialized = FALSE) then + if C_SIM_VERBOSE then report "init:" severity NOTE; end if; + State.IsInitialized := TRUE; + createDefaultTest; + end if; + end procedure; + + procedure initialize(MaxAssertFailures : natural := natural'high; MaxSimulationRuntime : TIME := TIME'high) is + begin + if C_SIM_VERBOSE then report "initialize:" severity NOTE; end if; + init; + Max_AssertFailures := MaxAssertFailures; + Max_SimulationRuntime := MaxSimulationRuntime; + end procedure; + + procedure finalize is + begin + if (State.IsFinalized = FALSE) then + if C_SIM_VERBOSE then report "finalize: " severity NOTE; end if; + State.IsFinalized := TRUE; + for i in C_SIM_DEFAULT_TEST_ID to TestCount - 1 loop + finalizeTest(i); + end loop; + writeReport; + end if; + end procedure; + + procedure writeReport_Header is + variable LineBuffer : LINE; + begin + write(LineBuffer, ( string'("========================================"))); + write(LineBuffer, (LF & string'("POC TESTBENCH REPORT"))); + write(LineBuffer, (LF & string'("========================================"))); + writeline(output, LineBuffer); + end procedure; + + procedure writeReport_TestReport(Prefix : string := "") is + variable LineBuffer : LINE; + begin + if (Tests(C_SIM_DEFAULT_TEST_ID).Status /= SIM_TEST_STATUS_CREATED) then + write(LineBuffer, Prefix & "Tests " & integer'image(TestCount + 1)); + write(LineBuffer, LF & Prefix & " " & str_ralign("-1", log10ceilnz(TestCount + 1) + 1) & ": " & C_SIM_DEFAULT_TEST_NAME); + else + write(LineBuffer, Prefix & "Tests " & integer'image(TestCount)); + end if; + for i in 0 to TestCount - 1 loop + write(LineBuffer, LF & Prefix & " " & str_ralign(integer'image(i), log10ceilnz(TestCount)) & ": " & str_trim(Tests(i).Name)); + end loop; + writeline(output, LineBuffer); + end procedure; + + procedure writeReport_AssertReport(Prefix : string := "") is + variable LineBuffer : LINE; + begin + write(LineBuffer, Prefix & "Assertions " & integer'image(AssertCount)); + write(LineBuffer, LF & Prefix & " failed " & integer'image(FailedAssertCount) & ite((FailedAssertCount >= Max_AssertFailures), " Too many failed asserts!", "")); + writeline(output, LineBuffer); + end procedure; + + procedure writeReport_ProcessReport(Prefix : string := "") is + variable LineBuffer : LINE; + begin + write(LineBuffer, Prefix & "Processes " & integer'image(ProcessCount)); + write(LineBuffer, LF & Prefix & " active " & integer'image(ActiveProcessCount)); + -- report killed processes + for i in 0 to ProcessCount - 1 loop + if ((Processes(i).Status = SIM_PROCESS_STATUS_ACTIVE) and (Processes(i).IsLowPriority = FALSE)) then + write(LineBuffer, LF & Prefix & " " & str_ralign(integer'image(i), log10ceilnz(ProcessCount)) & ": " & str_trim(Processes(i).Name)); + end if; + end loop; + writeline(output, LineBuffer); + end procedure; + + procedure writeReport_RuntimeReport(Prefix : string := "") is + variable LineBuffer : LINE; + begin + write(LineBuffer, Prefix & "Runtime " & to_string(now, 1)); + writeline(output, LineBuffer); + end procedure; + + procedure writeReport_SimulationResult is + variable LineBuffer : LINE; + begin + write(LineBuffer, ( string'("========================================"))); + if not Passed then write(LineBuffer, (LF & string'("SIMULATION RESULT = FAILED"))); + elsif AssertCount = 0 then write(LineBuffer, (LF & string'("SIMULATION RESULT = NO ASSERTS"))); + elsif Passed then write(LineBuffer, (LF & string'("SIMULATION RESULT = PASSED"))); + end if; + write(LineBuffer, (LF & string'("========================================"))); + writeline(output, LineBuffer); + end procedure; + + procedure writeReport is + variable LineBuffer : LINE; + begin + writeReport_Header; + writeReport_TestReport(""); + write(LineBuffer, LF & "Overall"); + writeline(output, LineBuffer); + writeReport_AssertReport(" "); + writeReport_ProcessReport(" "); + writeReport_RuntimeReport(" "); + writeReport_SimulationResult; + end procedure; + + procedure assertion(condition : boolean; Message : string := "") is + begin + AssertCount := AssertCount + 1; + if not condition then + fail(Message); + FailedAssertCount := FailedAssertCount + 1; + if (FailedAssertCount >= Max_AssertFailures) then + stopAllProcesses; + end if; + end if; + end procedure; + + procedure fail(Message : string := "") is + begin + if (Message'length > 0) then + report Message severity ERROR; + end if; + Passed := FALSE; + end procedure; + + procedure writeMessage(Message : string) is + variable LineBuffer : LINE; + begin + write(LineBuffer, Message); + writeline(output, LineBuffer); + end procedure; + + procedure createDefaultTest is + variable Test : T_SIM_TEST; + begin + if (State.IsInitialized = FALSE) then + init; + end if; + if C_SIM_VERBOSE then report "createDefaultTest(" & C_SIM_DEFAULT_TEST_NAME & "):" severity NOTE; end if; + Test.ID := C_SIM_DEFAULT_TEST_ID; + Test.Name := resize(C_SIM_DEFAULT_TEST_NAME, T_SIM_TEST_NAME'length); + Test.Status := SIM_TEST_STATUS_CREATED; + Test.ProcessIDs := (others => 0); + Test.ProcessCount := 0; + Test.ActiveProcessCount := 0; + -- add to the internal structure + Tests(Test.ID) := Test; + end procedure; + + impure function createTest(Name : string) return T_SIM_TEST_ID is + variable Test : T_SIM_TEST; + begin + if (State.IsInitialized = FALSE) then + init; + end if; + if C_SIM_VERBOSE then report "createTest(" & Name & "): => " & T_SIM_TEST_ID'image(TestCount) severity NOTE; end if; + Test.ID := TestCount; + Test.Name := resize(Name, T_SIM_TEST_NAME'length); + Test.Status := SIM_TEST_STATUS_ACTIVE; + Test.ProcessIDs := (others => 0); + Test.ProcessCount := 0; + Test.ActiveProcessCount := 0; + -- add to the internal structure + Tests(Test.ID) := Test; + TestCount := TestCount + 1; + ActiveTestCount := ActiveTestCount + 1; + -- return TestID for finalizeTest + return Test.ID; + end function; + + procedure activateDefaultTest is + begin + if (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_CREATED) then + Tests(C_SIM_DEFAULT_TEST_ID).Status := SIM_TEST_STATUS_ACTIVE; + ActiveTestCount := ActiveTestCount + 1; + end if; + end procedure; + + procedure finalizeTest is + begin + finalizeTest(C_SIM_DEFAULT_TEST_ID); + end procedure; + + procedure finalizeTest(TestID : T_SIM_TEST_ID) is + begin + if (TestID >= TestCount) then + report "TestID (" & T_SIM_TEST_ID'image(TestID) & ") is unknown." severity FAILURE; + return; + end if; + + if TestID = C_SIM_DEFAULT_TEST_ID then + if (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_CREATED) then + if C_SIM_VERBOSE then report "finalizeTest(" & integer'image(C_SIM_DEFAULT_TEST_ID) & "): inactive" severity NOTE; end if; + Tests(C_SIM_DEFAULT_TEST_ID).Status := SIM_TEST_STATUS_ENDED; + stopProcesses(C_SIM_DEFAULT_TEST_ID); + return; + elsif (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_ACTIVE) then + if ActiveTestCount > 1 then + for ProcIdx in 0 to Tests(C_SIM_DEFAULT_TEST_ID).ProcessCount - 1 loop + deactivateProcess(Tests(C_SIM_DEFAULT_TEST_ID).ProcessIDs(ProcIdx), TRUE); + end loop; + Tests(C_SIM_DEFAULT_TEST_ID).Status := SIM_TEST_STATUS_ZOMBI; + return; + else + if C_SIM_VERBOSE then report "finalizeTest(" & integer'image(C_SIM_DEFAULT_TEST_ID) & "): active" severity NOTE; end if; + Tests(C_SIM_DEFAULT_TEST_ID).Status := SIM_TEST_STATUS_ENDED; + ActiveTestCount := ActiveTestCount - 1; + stopProcesses(C_SIM_DEFAULT_TEST_ID); + end if; + end if; + elsif (Tests(TestID).Status /= SIM_TEST_STATUS_ENDED) then + if C_SIM_VERBOSE then report "finalizeTest(TestID=" & T_SIM_TEST_ID'image(TestID) & "): " severity NOTE; end if; + Tests(TestID).Status := SIM_TEST_STATUS_ENDED; + ActiveTestCount := ActiveTestCount - 1; + + if (Tests(TestID).ActiveProcessCount > 0) then + fail("Test " & integer'image(TestID) & " '" & str_trim(Tests(TestID).Name) & "' has still active process while finalizing:"); + for ProcIdx in 0 to Tests(TestID).ProcessCount - 1 loop + if (Processes(Tests(TestID).ProcessIDs(ProcIdx)).Status = SIM_PROCESS_STATUS_ACTIVE) then + report " " & Processes(Tests(TestID).ProcessIDs(ProcIdx)).Name severity WARNING; + end if; + end loop; + end if; + stopProcesses(TestID); + end if; + + if ActiveTestCount = 0 then + finalize; + elsif ActiveTestCount = 1 then + if (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_ACTIVE) then + finalizeTest(C_SIM_DEFAULT_TEST_ID); + elsif (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_ZOMBI) then + stopProcesses(C_SIM_DEFAULT_TEST_ID); + else + return; + end if; + finalize; + end if; + end procedure; + + impure function registerProcess(Name : string; IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID is + begin + return registerProcess(C_SIM_DEFAULT_TEST_ID, Name, IsLowPriority); + end function; + + impure function registerProcess(TestID : T_SIM_TEST_ID; Name : string; IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID is + variable Proc : T_SIM_PROCESS; + variable TestProcID : T_SIM_TEST_ID; + begin + if (State.IsInitialized = FALSE) then + init; + end if; + if TestID = C_SIM_DEFAULT_TEST_ID then + activateDefaultTest; + end if; + + if (TestID >= TestCount) then + report "TestID (" & T_SIM_TEST_ID'image(TestID) & ") is unknown." severity FAILURE; + return T_SIM_PROCESS_ID'high; + end if; + + if C_SIM_VERBOSE then report "registerProcess(TestID=" & T_SIM_TEST_ID'image(TestID) & ", " & Name & "): => " & T_SIM_PROCESS_ID'image(ProcessCount) severity NOTE; end if; + Proc.ID := ProcessCount; + Proc.TestID := TestID; + Proc.Name := resize(Name, T_SIM_PROCESS_NAME'length); + Proc.Status := SIM_PROCESS_STATUS_ACTIVE; + Proc.IsLowPriority := IsLowPriority; + + -- add process to list + Processes(Proc.ID) := Proc; + ProcessCount := ProcessCount + 1; + ActiveProcessCount := inc_if(not IsLowPriority, ActiveProcessCount); + -- add process to test + TestProcID := Tests(TestID).ProcessCount; + Tests(TestID).ProcessIDs(TestProcID) := Proc.ID; + Tests(TestID).ProcessCount := TestProcID + 1; + Tests(TestID).ActiveProcessCount := inc_if(not IsLowPriority, Tests(TestID).ActiveProcessCount); + -- return the process ID + return Proc.ID; + end function; + + procedure deactivateProcess(ProcID : T_SIM_PROCESS_ID; SkipLowPriority : boolean := FALSE) is + variable TestID : T_SIM_TEST_ID; + begin + if (ProcID >= ProcessCount) then + report "ProcID (" & T_SIM_PROCESS_ID'image(ProcID) & ") is unknown." severity FAILURE; + return; + elsif (Processes(ProcID).IsLowPriority and SkipLowPriority) then + return; + end if; + + TestID := Processes(ProcID).TestID; + -- deactivate process + if (Processes(ProcID).Status = SIM_PROCESS_STATUS_ACTIVE) then + if C_SIM_VERBOSE then report "deactivateProcess(ProcID=" & T_SIM_PROCESS_ID'image(ProcID) & "): TestID=" & T_SIM_TEST_ID'image(TestID) & " Name=" & str_trim(Processes(ProcID).Name) severity NOTE; end if; + Processes(ProcID).Status := SIM_PROCESS_STATUS_ENDED; + ActiveProcessCount := dec_if(not Processes(ProcID).IsLowPriority, ActiveProcessCount); + Tests(TestID).ActiveProcessCount := dec_if(not Processes(ProcID).IsLowPriority, Tests(TestID).ActiveProcessCount); + if (Tests(TestID).ActiveProcessCount = 0) then + finalizeTest(TestID); + end if; + end if; + end procedure; + + procedure stopAllProcesses is + begin + if C_SIM_VERBOSE then report "stopAllProcesses:" severity NOTE; end if; + for i in C_SIM_DEFAULT_TEST_ID to TestCount - 1 loop + stopProcesses(i); + end loop; + end procedure; + + procedure stopProcesses(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) is + begin + if (TestID >= TestCount) then + report "TestID (" & T_SIM_TEST_ID'image(TestID) & ") is unknown." severity FAILURE; + return; + end if; + + if C_SIM_VERBOSE then report "stopProcesses(TestID=" & T_SIM_TEST_ID'image(TestID) & "): Name=" & str_trim(Tests(TestID).Name) severity NOTE; end if; + MainProcessEnables(TestID) := FALSE; + stopClocks(TestID); + end procedure; + + procedure stopAllClocks is + begin + if C_SIM_VERBOSE then report "stopAllClocks:" severity NOTE; end if; + for i in C_SIM_DEFAULT_TEST_ID to TestCount - 1 loop + stopClocks(i); + end loop; + end procedure; + + procedure stopClocks(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) is + begin + if (TestID >= TestCount) then + report "TestID (" & T_SIM_TEST_ID'image(TestID) & ") is unknown." severity FAILURE; + return; + end if; + + if C_SIM_VERBOSE then report "stopClocks(TestID=" & T_SIM_TEST_ID'image(TestID) & "): Name=" & str_trim(Tests(TestID).Name) severity NOTE; end if; + MainClockEnables(TestID) := FALSE; + end procedure; + + impure function isStopped(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean is + begin + return not MainClockEnables(TestID); + end function; + + impure function isFinalized(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean is + begin + return (Tests(TestID).Status = SIM_TEST_STATUS_ENDED); + end function; + + impure function isAllFinalized return boolean is + begin + if (State.IsFinalized = TRUE) then + if ActiveTestCount = 0 then + return TRUE; + end if; + report "isAllFinalized: " severity ERROR; + return FALSE; + else + return FALSE; + end if; + end function; + end protected body; +end package body; diff --git a/testsuite/gna/issue317/PoC/src/sim/sim_simulation.v08.vhdl b/testsuite/gna/issue317/PoC/src/sim/sim_simulation.v08.vhdl new file mode 100644 index 000000000..81a964b95 --- /dev/null +++ b/testsuite/gna/issue317/PoC/src/sim/sim_simulation.v08.vhdl @@ -0,0 +1,173 @@ +-- 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:: No documentation available. +-- +-- License: +-- ============================================================================= +-- Copyright 2007-2016 Technische Universitaet Dresden - Germany +-- Chair of 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 + -- =========================================================================== + -- prepared aliases, if GHDL gets the aliases fixed. Reported on 08.02.2015 as Issue #38 + -- alias simmInitialize is globalSimulationStatus.initialize[NATURAL, TIME]; + -- alias simmFinalize is globalSimulationStatus.finalize[]; + + -- alias simmCreateTest is globalSimulationStatus.createTest[STRING return T_SIM_TEST_ID]; + -- alias simmFinalizeTest is globalSimulationStatus.finalizeTest[T_SIM_TEST_ID]; + -- alias simmRegisterProcess is globalSimulationStatus.registerProcess[T_SIM_TEST_ID, STRING, BOOLEAN return T_SIM_PROCESS_ID]; + -- alias simmRegisterProcess is globalSimulationStatus.registerProcess[STRING, BOOLEAN return T_SIM_PROCESS_ID]; + -- alias simmDeactivateProcess is globalSimulationStatus.deactivateProcess[T_SIM_PROCESS_ID]; + + -- alias simmIsStopped is globalSimulationStatus.isStopped[T_SIM_TEST_ID return BOOLEAN]; + -- alias simmIsFinalized is globalSimulationStatus.isFinalized[T_SIM_TEST_ID return BOOLEAN]; + -- alias simmIsAllFinalized is globalSimulationStatus.isAllFinalized [return BOOLEAN]; + + -- alias simmAssertion is globalSimulationStatus.assertion[BOOLEAN, STRING]; + -- alias simmFail is globalSimulationStatus.fail[STRING]; + -- alias simmWriteMessage is globalSimulationStatus.writeMessage[STRING]; + + procedure simInitialize(MaxAssertFailures : natural := natural'high; MaxSimulationRuntime : TIME := TIME'high); + procedure simFinalize; + + impure function simCreateTest(Name : string) return T_SIM_TEST_ID; + procedure simFinalizeTest(constant TestID : T_SIM_TEST_ID); + impure function simRegisterProcess(Name : string; constant IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID; + impure function simRegisterProcess(constant TestID : T_SIM_TEST_ID; Name : string; constant IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID; + procedure simDeactivateProcess(ProcID : T_SIM_PROCESS_ID); + + impure function simIsStopped(constant TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean; + impure function simIsFinalized(constant TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean; + impure function simIsAllFinalized return boolean; + + procedure simAssertion(cond : in boolean; Message : in string := ""); + procedure simFail(Message : in string := ""); + procedure simWriteMessage(Message : in string := ""); + + -- 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(MaxAssertFailures : natural := natural'high; MaxSimulationRuntime : TIME := TIME'high) is + begin + globalSimulationStatus.initialize(MaxAssertFailures, MaxSimulationRuntime); + if C_SIM_VERBOSE then report "simInitialize:" severity NOTE; end if; + if (MaxSimulationRuntime /= time'high) then + wait for MaxSimulationRuntime; + report "simInitialize: TIMEOUT" severity ERROR; + globalSimulationStatus.finalize; + end if; + 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; + + procedure simFinalizeTest(constant TestID : T_SIM_TEST_ID) is + begin + globalSimulationStatus.finalizeTest(TestID); + end procedure; + + impure function simRegisterProcess(Name : string; constant IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID is + begin + return globalSimulationStatus.registerProcess(Name, IsLowPriority); + end function; + + impure function simRegisterProcess(constant TestID : T_SIM_TEST_ID; Name : string; constant IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID is + begin + return globalSimulationStatus.registerProcess(TestID, Name, IsLowPriority); + end function; + + procedure simDeactivateProcess(ProcID : T_SIM_PROCESS_ID) is + begin + globalSimulationStatus.deactivateProcess(ProcID); + end procedure; + + impure function simIsStopped(constant TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean is + begin + return globalSimulationStatus.isStopped(TestID); + end function; + + impure function simIsFinalized(constant TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean is + begin + return globalSimulationStatus.isFinalized(TestID); + end function; + + impure function simIsAllFinalized return boolean is + begin + return globalSimulationStatus.isAllFinalized; + 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; + + -- checksum functions + -- =========================================================================== + -- TODO: move checksum functions here +end package body; diff --git a/testsuite/gna/issue317/PoC/src/sim/sim_types.vhdl b/testsuite/gna/issue317/PoC/src/sim/sim_types.vhdl new file mode 100644 index 000000000..332cd4e16 --- /dev/null +++ b/testsuite/gna/issue317/PoC/src/sim/sim_types.vhdl @@ -0,0 +1,376 @@ +-- 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:: No documentation available. +-- +-- License: +-- ============================================================================= +-- Copyright 2007-2016 Technische Universitaet Dresden - Germany +-- Chair of 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; + + +package sim_types is + + constant C_SIM_VERBOSE : boolean := FALSE; -- POC_VERBOSE + + -- =========================================================================== + -- Simulation Task and Status Management + -- =========================================================================== + type T_SIM_BOOLVEC is array(integer range <>) of boolean; + + subtype T_SIM_TEST_ID is integer range -1 to 1023; + subtype T_SIM_TEST_NAME is string(1 to 256); + subtype T_SIM_PROCESS_ID is natural range 0 to 1023; + subtype T_SIM_PROCESS_NAME is string(1 to 64); + subtype T_SIM_PROCESS_INSTNAME is string(1 to 256); + type T_SIM_PROCESS_ID_VECTOR is array(natural range <>) of T_SIM_PROCESS_ID; + + type T_SIM_TEST_STATUS is ( + SIM_TEST_STATUS_CREATED, + SIM_TEST_STATUS_ACTIVE, + SIM_TEST_STATUS_ENDED, + SIM_TEST_STATUS_ZOMBI + ); + + type T_SIM_PROCESS_STATUS is ( + SIM_PROCESS_STATUS_ACTIVE, + SIM_PROCESS_STATUS_ENDED + ); + + type T_SIM_TEST is record + ID : T_SIM_TEST_ID; + Name : T_SIM_TEST_NAME; + Status : T_SIM_TEST_STATUS; + ProcessIDs : T_SIM_PROCESS_ID_VECTOR(T_SIM_PROCESS_ID); + ProcessCount : T_SIM_PROCESS_ID; + ActiveProcessCount : T_SIM_PROCESS_ID; + end record; + type T_SIM_TEST_VECTOR is array(integer range <>) of T_SIM_TEST; + + type T_SIM_PROCESS is record + ID : T_SIM_PROCESS_ID; + TestID : T_SIM_TEST_ID; + Name : T_SIM_PROCESS_NAME; + Status : T_SIM_PROCESS_STATUS; + IsLowPriority : boolean; + end record; + type T_SIM_PROCESS_VECTOR is array(natural range <>) of T_SIM_PROCESS; + + constant C_SIM_DEFAULT_TEST_ID : T_SIM_TEST_ID := -1; + constant C_SIM_DEFAULT_TEST_NAME : string := "Default test"; + + -- =========================================================================== + -- Random Numbers + -- =========================================================================== + type T_SIM_RAND_SEED is record + Seed1 : integer; + Seed2 : integer; + end record; + + procedure randInitializeSeed(Seed : inout T_SIM_RAND_SEED); + procedure randInitializeSeed(Seed : inout T_SIM_RAND_SEED; SeedValue : in T_SIM_RAND_SEED); + procedure randInitializeSeed(Seed : inout T_SIM_RAND_SEED; SeedVector : in T_INTVEC); + procedure randInitializeSeed(Seed : inout T_SIM_RAND_SEED; SeedVector : in string); + function randInitializeSeed return T_SIM_RAND_SEED; + function randInitializeSeed(SeedValue : T_SIM_RAND_SEED) return T_SIM_RAND_SEED; + function randInitializeSeed(SeedVector : T_INTVEC) return T_SIM_RAND_SEED; + function randInitializeSeed(SeedVector : string) return T_SIM_RAND_SEED; + + + -- Uniform distributed random values + -- =========================================================================== + procedure randUniformDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL); + procedure randUniformDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out integer; Minimum : integer; Maximum : integer); + procedure randUniformDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; Minimum : REAL; Maximum : REAL); + + -- Normal / Gaussian distributed random values + -- =========================================================================== + procedure randNormalDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; StandardDeviation : REAL := 1.0; Mean : REAL := 0.0); + procedure randNormalDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out integer; StandardDeviation : in REAL; Mean : in REAL; Minimum : in integer; Maximum : in integer); + procedure randNormalDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; StandardDeviation : in REAL; Mean : in REAL; Minimum : in REAL; Maximum : in REAL); + + -- Poisson distributed random values + -- =========================================================================== + procedure randPoissonDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; Mean : in REAL); + procedure randPoissonDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out integer; Mean : in REAL; Minimum : in integer; Maximum : in integer); + procedure randPoissonDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; Mean : in REAL; Minimum : in REAL; Maximum : in REAL); + + -- =========================================================================== + -- Clock Generation + -- =========================================================================== + -- type T_PERCENT is INTEGER'range units + type T_PERCENT is range integer'low to INTEGER'high units + ppb; + ppm = 1000 ppb; + permil = 1000 ppm; + percent = 10 permil; + one = 100 percent; + end units; + subtype T_WANDER is T_PERCENT range -1 one to 1 one; + subtype T_DUTYCYCLE is T_PERCENT range 0 ppb to 1 one; + + type T_DEGREE is range integer'low to INTEGER'high units + second; + minute = 60 second; + deg = 60 minute; + end units; + subtype T_PHASE is T_DEGREE range -360 deg to 360 deg; + + function ite(cond : boolean; value1 : T_DEGREE; value2 : T_DEGREE) return T_DEGREE; +end package; + + +package body sim_types is + function ite(cond : boolean; value1 : T_DEGREE; value2 : T_DEGREE) return T_DEGREE is + begin + if cond then + return value1; + else + return value2; + end if; + end function; + + -- =========================================================================== + -- Random Numbers + -- =========================================================================== + constant MAX_SEED1_VALUE : positive := 2147483562; + constant MAX_SEED2_VALUE : positive := 2147483398; + + function randGenerateInitialSeed return T_SIM_RAND_SEED is + begin + return ( + Seed1 => 5, + Seed2 => 3423 + ); + end function; + + function randBoundSeed(SeedValue : in T_SIM_RAND_SEED) return T_SIM_RAND_SEED is + begin + return ( + Seed1 => (SeedValue.Seed1 - 1 mod MAX_SEED1_VALUE) + 1, + Seed2 => (SeedValue.Seed2 - 1 mod MAX_SEED2_VALUE) + 1 + ); + end function; + + procedure randInitializeSeed(Seed : inout T_SIM_RAND_SEED) is + begin + Seed := randGenerateInitialSeed; + end procedure; + + procedure randInitializeSeed(Seed : inout T_SIM_RAND_SEED; SeedValue : in T_SIM_RAND_SEED) is + begin + Seed := randBoundSeed(SeedValue); + end procedure; + + procedure randInitializeSeed(Seed : inout T_SIM_RAND_SEED; SeedVector : in T_INTVEC) is + begin + if (SeedVector'length = 0) then + Seed := randGenerateInitialSeed; + elsif (SeedVector'length = 1) then + Seed := randBoundSeed(T_SIM_RAND_SEED'( + Seed1 => SeedVector(0), + Seed2 => 92346 + )); + elsif (SeedVector'length = 2) then + Seed := randBoundSeed(T_SIM_RAND_SEED'( + Seed1 => SeedVector(0), + Seed2 => SeedVector(1) + )); + else + -- FIXME: + -- Seed.Seed1 := SeedVector(0); + -- Seed.Seed2 := SeedVector(1); + end if; + end procedure; + + procedure randInitializeSeed(Seed : inout T_SIM_RAND_SEED; SeedVector : in string) is + begin + if (SeedVector'length = 0) then + Seed := randGenerateInitialSeed; + elsif (SeedVector'length = 1) then + Seed := T_SIM_RAND_SEED'( + Seed1 => character'pos(SeedVector(1)), + Seed2 => 39834 + ); + elsif (SeedVector'length = 2) then + Seed := T_SIM_RAND_SEED'( + Seed1 => character'pos(SeedVector(1)), + Seed2 => character'pos(SeedVector(2)) + ); + else + -- FIXME: + -- Seed.Seed1 := CHARACTER'pos(SeedVector(0)); + -- Seed.Seed2 := CHARACTER'pos(SeedVector(1)); + end if; + end procedure; + + function randInitializeSeed return T_SIM_RAND_SEED is + begin + return randGenerateInitialSeed; + end function; + + function randInitializeSeed(SeedValue : T_SIM_RAND_SEED) return T_SIM_RAND_SEED is + begin + return randBoundSeed(SeedValue); + end function; + + function randInitializeSeed(SeedVector : T_INTVEC) return T_SIM_RAND_SEED is + variable Result : T_SIM_RAND_SEED; + begin + randInitializeSeed(Result, SeedVector); + return Result; + end function; + + function randInitializeSeed(SeedVector : string) return T_SIM_RAND_SEED is + variable Result : T_SIM_RAND_SEED; + begin + randInitializeSeed(Result, SeedVector); + return Result; + end function; + + -- =========================================================================== + -- Uniform distributed random values + -- =========================================================================== + procedure randUniformDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL) is + begin + ieee.math_real.Uniform(Seed.Seed1, Seed.Seed2, Value); + end procedure; + + procedure randUniformDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out integer; Minimum : integer; Maximum : integer) is + variable rand : REAL; + begin + if Maximum < Minimum then report "randUniformDistributedValue: 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 randUniformDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; Minimum : REAL; Maximum : REAL) is + variable rand : REAL; + begin + if Maximum < Minimum then report "randUniformDistributedValue: 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; + + -- =========================================================================== + -- Normal / Gaussian distributed random values + -- =========================================================================== + procedure randNormalDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; StandardDeviation : REAL := 1.0; Mean : REAL := 0.0) is + variable rand1 : REAL; + variable rand2 : REAL; + begin + if StandardDeviation < 0.0 then report "randNormalDistributedValue: 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 randNormalDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out integer; StandardDeviation : in REAL; Mean : in REAL; Minimum : in integer; Maximum : in integer) is + variable rand_real : REAL; + variable rand_int : integer; + begin + if Maximum < Minimum then report "randNormalDistributedValue: Maximum must be greater than Minimum." severity FAILURE; end if; + if StandardDeviation < 0.0 then report "randNormalDistributedValue: Standard deviation must be >= 0.0" severity FAILURE; end if; + while TRUE loop + randNormalDistributedValue(Seed, rand_real, StandardDeviation, Mean); + rand_int := integer(round(rand_real)); + exit when ((Minimum <= rand_int) and (rand_int <= Maximum)); + end loop; + Value := rand_int; + end procedure; + + procedure randNormalDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; StandardDeviation : in REAL; Mean : in REAL; Minimum : in REAL; Maximum : in REAL) is + variable rand : REAL; + begin + if Maximum < Minimum then report "randNormalDistributedValue: Maximum must be greater than Minimum." severity FAILURE; end if; + if StandardDeviation < 0.0 then report "randNormalDistributedValue: Standard deviation must be >= 0.0" severity FAILURE; end if; + while TRUE loop + randNormalDistributedValue(Seed, rand, StandardDeviation, Mean); + exit when ((Minimum <= rand) and (rand <= Maximum)); + end loop; + Value := rand; + end procedure; + + -- =========================================================================== + -- Poisson distributed random values + -- =========================================================================== + procedure randPoissonDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; Mean : in REAL) is + variable Product : Real; + variable Bound : Real; + variable rand : Real; + variable Result : Real; + begin + Product := 1.0; + Result := 0.0; + Bound := exp(-1.0 * Mean); + if ((Mean <= 0.0) or (Bound <= 0.0)) then + report "randPoissonDistributedValue: Mean must be greater than 0.0." severity FAILURE; + return; + end if; + + while (Product >= Bound) loop + ieee.math_real.Uniform(Seed.Seed1, Seed.Seed2, rand); + Product := Product * rand; + Result := Result + 1.0; + end loop; + Value := Result; + end procedure; + + procedure randPoissonDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out integer; Mean : in REAL; Minimum : in integer; Maximum : in integer) is + variable rand_real : REAL; + variable rand_int : integer; + begin + if Maximum < Minimum then report "randPoissonDistributedValue: Maximum must be greater than Minimum." severity FAILURE; end if; + while TRUE loop + randPoissonDistributedValue(Seed, rand_real, Mean); + rand_int := integer(round(rand_real)); + exit when ((Minimum <= rand_int) and (rand_int <= Maximum)); + end loop; + Value := rand_int; + end procedure; + + procedure randPoissonDistributedValue(Seed : inout T_SIM_RAND_SEED; Value : out REAL; Mean : in REAL; Minimum : in REAL; Maximum : in REAL) is + variable rand : REAL; + begin + if Maximum < Minimum then report "randPoissonDistributedValue: Maximum must be greater than Minimum." severity FAILURE; end if; + while TRUE loop + randPoissonDistributedValue(Seed, rand, Mean); + exit when ((Minimum <= rand) and (rand <= Maximum)); + end loop; + Value := rand; + end procedure; +end package body; diff --git a/testsuite/gna/issue317/PoC/src/sim/sim_waveform.vhdl b/testsuite/gna/issue317/PoC/src/sim/sim_waveform.vhdl new file mode 100644 index 000000000..3c70eeac1 --- /dev/null +++ b/testsuite/gna/issue317/PoC/src/sim/sim_waveform.vhdl @@ -0,0 +1,981 @@ +-- 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 +-- Martin Zabel +-- +-- Package: Simulation constants, functions and utilities. +-- +-- Description: +-- ------------------------------------- +-- .. TODO:: No documentation available. +-- +-- License: +-- ============================================================================= +-- Copyright 2007-2016 Technische Universitaet Dresden - Germany +-- Chair of 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_types.all; +-- use PoC.sim_random.all; +use PoC.simulation.all; + + +package waveform is + -- 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( + constant TestID : in T_SIM_TEST_ID; + 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 simGenerateClock( + constant TestID : in T_SIM_TEST_ID; + 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 simWaitUntilRisingEdge(constant TestID : in T_SIM_TEST_ID; signal Clock : in std_logic; constant Times : in positive); + procedure simWaitUntilFallingEdge(signal Clock : in std_logic; constant Times : in positive); + procedure simWaitUntilFallingEdge(constant TestID : in T_SIM_TEST_ID; signal Clock : in std_logic; constant Times : in positive); + + procedure simGenerateClock2(constant TestID : in T_SIM_TEST_ID; signal Clock : out std_logic; signal Debug : out REAL; constant Period : in time); + + -- waveform description + -- =========================================================================== + type T_SIM_WAVEFORM_TUPLE_SL is record + Delay : time; + Value : std_logic; + end record; + + type T_SIM_WAVEFORM_TUPLE_SLV_8 is record + Delay : time; + Value : T_SLV_8; + end record; + + type T_SIM_WAVEFORM_TUPLE_SLV_16 is record + Delay : time; + Value : T_SLV_16; + end record; + + type T_SIM_WAVEFORM_TUPLE_SLV_24 is record + Delay : time; + Value : T_SLV_24; + end record; + + type T_SIM_WAVEFORM_TUPLE_SLV_32 is record + Delay : time; + Value : T_SLV_32; + end record; + + type T_SIM_WAVEFORM_TUPLE_SLV_48 is record + Delay : time; + Value : T_SLV_48; + end record; + + type T_SIM_WAVEFORM_TUPLE_SLV_64 is record + Delay : time; + Value : T_SLV_64; + end record; + + subtype T_SIM_WAVEFORM is TIME_VECTOR; -- use predefined physical type TIME here + type T_SIM_WAVEFORM_SL is array(natural range <>) of T_SIM_WAVEFORM_TUPLE_SL; + type T_SIM_WAVEFORM_SLV_8 is array(natural range <>) of T_SIM_WAVEFORM_TUPLE_SLV_8; + type T_SIM_WAVEFORM_SLV_16 is array(natural range <>) of T_SIM_WAVEFORM_TUPLE_SLV_16; + type T_SIM_WAVEFORM_SLV_24 is array(natural range <>) of T_SIM_WAVEFORM_TUPLE_SLV_24; + type T_SIM_WAVEFORM_SLV_32 is array(natural range <>) of T_SIM_WAVEFORM_TUPLE_SLV_32; + type T_SIM_WAVEFORM_SLV_48 is array(natural range <>) of T_SIM_WAVEFORM_TUPLE_SLV_48; + type T_SIM_WAVEFORM_SLV_64 is array(natural range <>) of T_SIM_WAVEFORM_TUPLE_SLV_64; + + -- waveform generation procedures + -- =========================================================================== + -- TODO: get initial value from Waveform(0) if .Delay = o fs, otherwise use (others => 'U') ? + procedure simGenerateWaveform( + signal Wave : out boolean; + constant Waveform : in T_SIM_WAVEFORM; + constant InitialValue : in boolean := FALSE + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out boolean; + constant Waveform : in T_SIM_WAVEFORM; + constant InitialValue : in boolean := FALSE + ); + procedure simGenerateWaveform( + signal Wave : out std_logic; + constant Waveform : in T_SIM_WAVEFORM; + constant InitialValue : in std_logic := '0' + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out std_logic; + constant Waveform : in T_SIM_WAVEFORM; + constant InitialValue : in std_logic := '0' + ); + procedure simGenerateWaveform( + signal Wave : out std_logic; + constant Waveform : in T_SIM_WAVEFORM_SL; + constant InitialValue : in std_logic := '0' + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out std_logic; + constant Waveform : in T_SIM_WAVEFORM_SL; + constant InitialValue : in std_logic := '0' + ); + procedure simGenerateWaveform( + signal Wave : out T_SLV_8; + constant Waveform : in T_SIM_WAVEFORM_SLV_8; + constant InitialValue : in T_SLV_8 := (others => '0') + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_8; + constant Waveform : in T_SIM_WAVEFORM_SLV_8; + constant InitialValue : in T_SLV_8 := (others => '0') + ); + procedure simGenerateWaveform( + signal Wave : out T_SLV_16; + constant Waveform : in T_SIM_WAVEFORM_SLV_16; + constant InitialValue : in T_SLV_16 := (others => '0') + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_16; + constant Waveform : in T_SIM_WAVEFORM_SLV_16; + constant InitialValue : in T_SLV_16 := (others => '0') + ); + procedure simGenerateWaveform( + signal Wave : out T_SLV_24; + constant Waveform : in T_SIM_WAVEFORM_SLV_24; + constant InitialValue : in T_SLV_24 := (others => '0') + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_24; + constant Waveform : in T_SIM_WAVEFORM_SLV_24; + constant InitialValue : in T_SLV_24 := (others => '0') + ); + procedure simGenerateWaveform( + signal Wave : out T_SLV_32; + constant Waveform : in T_SIM_WAVEFORM_SLV_32; + constant InitialValue : in T_SLV_32 := (others => '0') + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_32; + constant Waveform : in T_SIM_WAVEFORM_SLV_32; + constant InitialValue : in T_SLV_32 := (others => '0') + ); + procedure simGenerateWaveform( + signal Wave : out T_SLV_48; + constant Waveform : in T_SIM_WAVEFORM_SLV_48; + constant InitialValue : in T_SLV_48 := (others => '0') + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_48; + constant Waveform : in T_SIM_WAVEFORM_SLV_48; + constant InitialValue : in T_SLV_48 := (others => '0') + ); + procedure simGenerateWaveform( + signal Wave : out T_SLV_64; + constant Waveform : in T_SIM_WAVEFORM_SLV_64; + constant InitialValue : in T_SLV_64 := (others => '0') + ); + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_64; + constant Waveform : in T_SIM_WAVEFORM_SLV_64; + constant InitialValue : in T_SLV_64 := (others => '0') + ); + + function "*" (Wave : T_SIM_WAVEFORM; Times : natural) return T_SIM_WAVEFORM; + function ">" (Wave : T_SIM_WAVEFORM; Offset : time) return T_SIM_WAVEFORM; + function "<" (Wave : T_SIM_WAVEFORM; Offset : time) return T_SIM_WAVEFORM; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_8; Times : natural) return T_SIM_WAVEFORM_SLV_8; + function ">" (Wave : T_SIM_WAVEFORM_SLV_8; Offset : time) return T_SIM_WAVEFORM_SLV_8; + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_8; Offset : TIME) return T_SIM_WAVEFORM_SLV_8; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_16; Times : natural) return T_SIM_WAVEFORM_SLV_16; + function ">" (Wave : T_SIM_WAVEFORM_SLV_16; Offset : time) return T_SIM_WAVEFORM_SLV_16; + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_16; Offset : TIME) return T_SIM_WAVEFORM_SLV_16; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_24; Times : natural) return T_SIM_WAVEFORM_SLV_24; + function ">" (Wave : T_SIM_WAVEFORM_SLV_24; Offset : time) return T_SIM_WAVEFORM_SLV_24; + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_24; Offset : TIME) return T_SIM_WAVEFORM_SLV_24; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_32; Times : natural) return T_SIM_WAVEFORM_SLV_32; + function ">" (Wave : T_SIM_WAVEFORM_SLV_32; Offset : time) return T_SIM_WAVEFORM_SLV_32; + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_32; Offset : TIME) return T_SIM_WAVEFORM_SLV_32; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_48; Times : natural) return T_SIM_WAVEFORM_SLV_48; + function ">" (Wave : T_SIM_WAVEFORM_SLV_48; Offset : time) return T_SIM_WAVEFORM_SLV_48; + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_48; Offset : TIME) return T_SIM_WAVEFORM_SLV_48; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_64; Times : natural) return T_SIM_WAVEFORM_SLV_64; + function ">" (Wave : T_SIM_WAVEFORM_SLV_64; Offset : time) return T_SIM_WAVEFORM_SLV_64; + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_64; Offset : TIME) return T_SIM_WAVEFORM_SLV_64; + + -- convert arrays to waveforms + -- TODO: optimize waveform if input data doesn't change + -- TODO: write single bit variant + function to_waveform(bv : bit_vector; Delay : time) return T_SIM_WAVEFORM; + function to_waveform(slv : std_logic_vector; Delay : time) return T_SIM_WAVEFORM_SL; + function to_waveform(slvv : T_SLVV_8; Delay : time) return T_SIM_WAVEFORM_SLV_8; + function to_waveform(slvv : T_SLVV_16; Delay : time) return T_SIM_WAVEFORM_SLV_16; + function to_waveform(slvv : T_SLVV_24; Delay : time) return T_SIM_WAVEFORM_SLV_24; + function to_waveform(slvv : T_SLVV_32; Delay : time) return T_SIM_WAVEFORM_SLV_32; + function to_waveform(slvv : T_SLVV_48; Delay : time) return T_SIM_WAVEFORM_SLV_48; + function to_waveform(slvv : T_SLVV_64; Delay : time) return T_SIM_WAVEFORM_SLV_64; + + -- predefined common waveforms + function simGenerateWaveform_Reset(constant Pause : time := 0 ns; ResetPulse : time := 10 ns) return T_SIM_WAVEFORM; + + -- TODO: integrate VCD simulation functions and procedures from sim_value_change_dump.vhdl here + end package; + + +package body waveform is + -- 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(C_SIM_DEFAULT_TEST_ID, Clock, Period, Phase, DutyCycle, Wander); + end procedure; + + procedure simGenerateClock( + constant TestID : in T_SIM_TEST_ID; + 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(TestID, 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 + begin + simGenerateClock(C_SIM_DEFAULT_TEST_ID, Clock, Period, Phase, DutyCycle, Wander); + end procedure; + + procedure simGenerateClock( + constant TestID : in T_SIM_TEST_ID; + 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 := 5; + + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateClock(period=" & to_string(Period, 2) & ")", IsLowPriority => TRUE); + begin + -- report "simGenerateClock: (Instance: '" & Clock'instance_name & "')" & LF & + -- "Period: " & TIME'image(Period) & LF & + -- "Phase: " & T_PHASE'image(Phase) & LF & + -- "DutyCycle: " & T_DUTYCYCLE'image(DutyCycle) & LF & + -- "PhaseAsFactor: " & REAL'image(PhaseAsFactor) & LF & + -- "WanderAsFactor: " & REAL'image(WanderAsFactor) & LF & + -- "DutyCycleAsFactor: " & REAL'image(DutyCycleAsFactor) & LF & + -- "Delay: " & TIME'image(Delay) & LF & + -- "TimeHigh: " & TIME'image(TimeHigh) & LF & + -- "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 simIsStopped(TestID) loop + wait for TimeHigh; + Clock <= '0'; + wait for TimeLow; + Clock <= '1'; + end loop; + simDeactivateProcess(PROCESS_ID); + -- 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( + constant TestID : in T_SIM_TEST_ID; + signal Clock : out std_logic; + signal Debug : out REAL; + 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 => (StandardDeviation => 0.2, Mean => -0.4), + -- 1 => (StandardDeviation => 0.2, Mean => 0.4) + + -- 0 => (StandardDeviation => 0.2, Mean => -0.4), + -- 1 => (StandardDeviation => 0.3, Mean => -0.1), + -- 2 => (StandardDeviation => 0.5, Mean => 0.0), + -- 3 => (StandardDeviation => 0.3, Mean => 0.1), + -- 4 => (StandardDeviation => 0.2, Mean => 0.4) + + 0 => (StandardDeviation => 0.15, Mean => -0.6), + 1 => (StandardDeviation => 0.2, Mean => -0.3), + 2 => (StandardDeviation => 0.25, Mean => -0.2), + 3 => (StandardDeviation => 0.3, Mean => 0.0), + 4 => (StandardDeviation => 0.25, Mean => 0.2), + 5 => (StandardDeviation => 0.2, Mean => 0.3), + 6 => (StandardDeviation => 0.15, Mean => 0.6) + ); + variable Seed : T_SIM_RAND_SEED; + variable rand : REAL; + variable Jitter : REAL; + variable Index : natural; + + constant ClockAfterRun_cy : positive := 5; + begin + Clock <= '1'; + randInitializeSeed(Seed); + + while not simIsStopped(TestID) loop + ieee.math_real.Uniform(Seed.Seed1, Seed.Seed2, rand); + Index := scale(rand, 0, JitterDistribution'length * 10) mod JitterDistribution'length; + randNormalDistributedValue(Seed, rand, JitterDistribution(Index).StandardDeviation, JitterDistribution(Index).Mean, -1.0, 1.0); + + Jitter := JitterAsFactor * rand; + Debug <= rand; + + -- Debug <= integer(rand * 256.0 + 256.0); + wait for TimeHigh + (Period * Jitter); + Clock <= '0'; + wait for TimeLow + (Period * Jitter); + 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; + + + procedure simWaitUntilRisingEdge(signal Clock : in std_logic; constant Times : in positive) is + begin + simWaitUntilRisingEdge(C_SIM_DEFAULT_TEST_ID, Clock, Times); + end procedure; + + procedure simWaitUntilRisingEdge(constant TestID : in T_SIM_TEST_ID; 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 simIsStopped(TestID); + end loop; + end procedure; + + procedure simWaitUntilFallingEdge(signal Clock : in std_logic; constant Times : in positive) is + begin + simWaitUntilFallingEdge(C_SIM_DEFAULT_TEST_ID, Clock, Times); + end procedure; + + procedure simWaitUntilFallingEdge(constant TestID : in T_SIM_TEST_ID; 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 simIsStopped(TestID); + end loop; + end procedure; + + -- waveform generation + -- =========================================================================== + procedure simGenerateWaveform( + signal Wave : out boolean; + constant Waveform : in T_SIM_WAVEFORM; + constant InitialValue : in boolean := FALSE + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out boolean; + constant Waveform : in T_SIM_WAVEFORM; + constant InitialValue : in boolean := FALSE + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + variable State : boolean; + begin + State := InitialValue; + Wave <= State; + for i in Waveform'range loop + wait for Waveform(i); + State := not State; + Wave <= State; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + procedure simGenerateWaveform( + signal Wave : out std_logic; + constant Waveform : in T_SIM_WAVEFORM; + constant InitialValue : in std_logic := '0' + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out std_logic; + constant Waveform : in T_SIM_WAVEFORM; + constant InitialValue : in std_logic := '0' + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + variable State : std_logic; + begin + State := InitialValue; + Wave <= State; + for i in Waveform'range loop + wait for Waveform(i); + State := not State; + Wave <= State; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + procedure simGenerateWaveform( + signal Wave : out std_logic; + constant Waveform : in T_SIM_WAVEFORM_SL; + constant InitialValue : in std_logic := '0' + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out std_logic; + constant Waveform : in T_SIM_WAVEFORM_SL; + constant InitialValue : in std_logic := '0' + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + begin + Wave <= InitialValue; + for i in Waveform'range loop + wait for Waveform(i).Delay; + Wave <= Waveform(i).Value; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + procedure simGenerateWaveform( + signal Wave : out T_SLV_8; + constant Waveform : in T_SIM_WAVEFORM_SLV_8; + constant InitialValue : in T_SLV_8 := (others => '0') + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_8; + constant Waveform : in T_SIM_WAVEFORM_SLV_8; + constant InitialValue : in T_SLV_8 := (others => '0') + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + begin + Wave <= InitialValue; + for i in Waveform'range loop + wait for Waveform(i).Delay; + Wave <= Waveform(i).Value; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + procedure simGenerateWaveform( + signal Wave : out T_SLV_16; + constant Waveform : in T_SIM_WAVEFORM_SLV_16; + constant InitialValue : in T_SLV_16 := (others => '0') + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_16; + constant Waveform : in T_SIM_WAVEFORM_SLV_16; + constant InitialValue : in T_SLV_16 := (others => '0') + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + begin + Wave <= InitialValue; + for i in Waveform'range loop + wait for Waveform(i).Delay; + Wave <= Waveform(i).Value; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + procedure simGenerateWaveform( + signal Wave : out T_SLV_24; + constant Waveform : in T_SIM_WAVEFORM_SLV_24; + constant InitialValue : in T_SLV_24 := (others => '0') + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_24; + constant Waveform : in T_SIM_WAVEFORM_SLV_24; + constant InitialValue : in T_SLV_24 := (others => '0') + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + begin + Wave <= InitialValue; + for i in Waveform'range loop + wait for Waveform(i).Delay; + Wave <= Waveform(i).Value; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + procedure simGenerateWaveform( + signal Wave : out T_SLV_32; + constant Waveform : in T_SIM_WAVEFORM_SLV_32; + constant InitialValue : in T_SLV_32 := (others => '0') + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_32; + constant Waveform : in T_SIM_WAVEFORM_SLV_32; + constant InitialValue : in T_SLV_32 := (others => '0') + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + begin + Wave <= InitialValue; + for i in Waveform'range loop + wait for Waveform(i).Delay; + Wave <= Waveform(i).Value; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + procedure simGenerateWaveform( + signal Wave : out T_SLV_48; + constant Waveform : in T_SIM_WAVEFORM_SLV_48; + constant InitialValue : in T_SLV_48 := (others => '0') + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_48; + constant Waveform : in T_SIM_WAVEFORM_SLV_48; + constant InitialValue : in T_SLV_48 := (others => '0') + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + begin + Wave <= InitialValue; + for i in Waveform'range loop + wait for Waveform(i).Delay; + Wave <= Waveform(i).Value; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + procedure simGenerateWaveform( + signal Wave : out T_SLV_64; + constant Waveform : in T_SIM_WAVEFORM_SLV_64; + constant InitialValue : in T_SLV_64 := (others => '0') + ) is + begin + simGenerateWaveform(C_SIM_DEFAULT_TEST_ID, Wave, Waveform, InitialValue); + end procedure; + + procedure simGenerateWaveform( + constant TestID : in T_SIM_TEST_ID; + signal Wave : out T_SLV_64; + constant Waveform : in T_SIM_WAVEFORM_SLV_64; + constant InitialValue : in T_SLV_64 := (others => '0') + ) is + constant PROCESS_ID : T_SIM_PROCESS_ID := simRegisterProcess(TestID, "simGenerateWaveform"); + begin + Wave <= InitialValue; + for i in Waveform'range loop + wait for Waveform(i).Delay; + Wave <= Waveform(i).Value; + exit when simIsStopped(TestID); + end loop; + simDeactivateProcess(PROCESS_ID); + end procedure; + + -- Waveform arithmetic + function "*" (Wave : T_SIM_WAVEFORM; Times : natural) return T_SIM_WAVEFORM is + variable Result : T_SIM_WAVEFORM(0 to Wave'length * Times - 1); + begin + for i in 0 to Times - 1 loop + Result(i * Wave'length to (i + 1) * Wave'length - 1) := Wave; + end loop; + return Result; + end function; + + function ">" (Wave : T_SIM_WAVEFORM; Offset : time) return T_SIM_WAVEFORM is + begin + return (Wave(Wave'low) + Offset) & Wave(Wave'low + 1 to Wave'high); + end function; + + function "<" (Wave : T_SIM_WAVEFORM; Offset : time) return T_SIM_WAVEFORM is + variable Result : T_SIM_WAVEFORM(Wave'range); + variable TimePos : time; + begin + report "Has bugs" severity ERROR; + TimePos := 0 fs; + for i in Wave'range loop + TimePos := TimePos + Wave(i); + if TimePos > Offset then + return (TimePos - Offset) & Wave(i + 1 to Wave'high); + end if; + end loop; + return (0 => 0 fs); + end function; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_8; Times : natural) return T_SIM_WAVEFORM_SLV_8 is + variable Result : T_SIM_WAVEFORM_SLV_8(0 to Wave'length * Times - 1); + begin + for i in 0 to Times - 1 loop + Result(i * Wave'length to (i + 1) * Wave'length - 1) := Wave; + end loop; + return Result; + end function; + + function ">" (Wave : T_SIM_WAVEFORM_SLV_8; Offset : time) return T_SIM_WAVEFORM_SLV_8 is + begin + return T_SIM_WAVEFORM_TUPLE_SLV_8'( + Delay => Wave(Wave'low).Delay + Offset, + Value => Wave(Wave'low).Value + ) & Wave(Wave'low + 1 to Wave'high); + end function; + + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_8; Offset : TIME) return T_SIM_WAVEFORM_SLV_8 is + -- begin + -- report "Not implemented" severity FAILURE; + -- end function; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_16; Times : natural) return T_SIM_WAVEFORM_SLV_16 is + variable Result : T_SIM_WAVEFORM_SLV_16(0 to Wave'length * Times - 1); + begin + for i in 0 to Times - 1 loop + Result(i * Wave'length to (i + 1) * Wave'length - 1) := Wave; + end loop; + return Result; + end function; + + function ">" (Wave : T_SIM_WAVEFORM_SLV_16; Offset : time) return T_SIM_WAVEFORM_SLV_16 is + begin + return T_SIM_WAVEFORM_TUPLE_SLV_16'( + Delay => Wave(Wave'low).Delay + Offset, + Value => Wave(Wave'low).Value + ) & Wave(Wave'low + 1 to Wave'high); + end function; + + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_16; Offset : TIME) return T_SIM_WAVEFORM_SLV_16 is + -- begin + -- report "Not implemented" severity FAILURE; + -- end function; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_24; Times : natural) return T_SIM_WAVEFORM_SLV_24 is + variable Result : T_SIM_WAVEFORM_SLV_24(0 to Wave'length * Times - 1); + begin + for i in 0 to Times - 1 loop + Result(i * Wave'length to (i + 1) * Wave'length - 1) := Wave; + end loop; + return Result; + end function; + + function ">" (Wave : T_SIM_WAVEFORM_SLV_24; Offset : time) return T_SIM_WAVEFORM_SLV_24 is + begin + return T_SIM_WAVEFORM_TUPLE_SLV_24'( + Delay => Wave(Wave'low).Delay + Offset, + Value => Wave(Wave'low).Value + ) & Wave(Wave'low + 1 to Wave'high); + end function; + + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_24; Offset : TIME) return T_SIM_WAVEFORM_SLV_24 is + -- begin + -- report "Not implemented" severity FAILURE; + -- end function; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_32; Times : natural) return T_SIM_WAVEFORM_SLV_32 is + variable Result : T_SIM_WAVEFORM_SLV_32(0 to Wave'length * Times - 1); + begin + for i in 0 to Times - 1 loop + Result(i * Wave'length to (i + 1) * Wave'length - 1) := Wave; + end loop; + return Result; + end function; + + function ">" (Wave : T_SIM_WAVEFORM_SLV_32; Offset : time) return T_SIM_WAVEFORM_SLV_32 is + begin + return T_SIM_WAVEFORM_TUPLE_SLV_32'( + Delay => Wave(Wave'low).Delay + Offset, + Value => Wave(Wave'low).Value + ) & Wave(Wave'low + 1 to Wave'high); + end function; + + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_32; Offset : TIME) return T_SIM_WAVEFORM_SLV_32 is + -- begin + -- report "Not implemented" severity FAILURE; + -- end function; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_48; Times : natural) return T_SIM_WAVEFORM_SLV_48 is + variable Result : T_SIM_WAVEFORM_SLV_48(0 to Wave'length * Times - 1); + begin + for i in 0 to Times - 1 loop + Result(i * Wave'length to (i + 1) * Wave'length - 1) := Wave; + end loop; + return Result; + end function; + + function ">" (Wave : T_SIM_WAVEFORM_SLV_48; Offset : time) return T_SIM_WAVEFORM_SLV_48 is + begin + return T_SIM_WAVEFORM_TUPLE_SLV_48'( + Delay => Wave(Wave'low).Delay + Offset, + Value => Wave(Wave'low).Value + ) & Wave(Wave'low + 1 to Wave'high); + end function; + + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_48; Offset : TIME) return T_SIM_WAVEFORM_SLV_48 is + -- begin + -- report "Not implemented" severity FAILURE; + -- end function; + + function "*" (Wave : T_SIM_WAVEFORM_SLV_64; Times : natural) return T_SIM_WAVEFORM_SLV_64 is + variable Result : T_SIM_WAVEFORM_SLV_64(0 to Wave'length * Times - 1); + begin + for i in 0 to Times - 1 loop + Result(i * Wave'length to (i + 1) * Wave'length - 1) := Wave; + end loop; + return Result; + end function; + + function ">" (Wave : T_SIM_WAVEFORM_SLV_64; Offset : time) return T_SIM_WAVEFORM_SLV_64 is + begin + return T_SIM_WAVEFORM_TUPLE_SLV_64'( + Delay => Wave(Wave'low).Delay + Offset, + Value => Wave(Wave'low).Value + ) & Wave(Wave'low + 1 to Wave'high); + end function; + + -- function "<" (Wave : T_SIM_WAVEFORM_SLV_64; Offset : TIME) return T_SIM_WAVEFORM_SLV_64 is + -- begin + -- report "Not implemented" severity FAILURE; + -- end function; + + + function to_waveform(bv : bit_vector; Delay : time) return T_SIM_WAVEFORM is + variable Result : T_SIM_WAVEFORM(0 to bv'length - 1); + begin + report "Has bugs" severity ERROR; + for i in 0 to bv'length - 1 loop + Result(i) := Delay; + end loop; + return Result; + end function; + + function to_waveform(slv : std_logic_vector; Delay : time) return T_SIM_WAVEFORM_SL is + variable Result : T_SIM_WAVEFORM_SL(0 to slv'length - 1); + begin + for i in 0 to slv'length - 1 loop + Result(i).Delay := Delay; + Result(i).Value := slv(i); + end loop; + return Result; + end function; + + function to_waveform(slvv : T_SLVV_8; Delay : time) return T_SIM_WAVEFORM_SLV_8 is + variable Result : T_SIM_WAVEFORM_SLV_8(0 to slvv'length - 1); + begin + for i in 0 to slvv'length - 1 loop + Result(i).Delay := Delay; + Result(i).Value := slvv(i); + end loop; + return Result; + end function; + + function to_waveform(slvv : T_SLVV_16; Delay : time) return T_SIM_WAVEFORM_SLV_16 is + variable Result : T_SIM_WAVEFORM_SLV_16(0 to slvv'length - 1); + begin + for i in 0 to slvv'length - 1 loop + Result(i).Delay := Delay; + Result(i).Value := slvv(i); + end loop; + return Result; + end function; + + function to_waveform(slvv : T_SLVV_24; Delay : time) return T_SIM_WAVEFORM_SLV_24 is + variable Result : T_SIM_WAVEFORM_SLV_24(0 to slvv'length - 1); + begin + for i in 0 to slvv'length - 1 loop + Result(i).Delay := Delay; + Result(i).Value := slvv(i); + end loop; + return Result; + end function; + + function to_waveform(slvv : T_SLVV_32; Delay : time) return T_SIM_WAVEFORM_SLV_32 is + variable Result : T_SIM_WAVEFORM_SLV_32(0 to slvv'length - 1); + begin + for i in 0 to slvv'length - 1 loop + Result(i).Delay := Delay; + Result(i).Value := slvv(i); + end loop; + return Result; + end function; + + function to_waveform(slvv : T_SLVV_48; Delay : time) return T_SIM_WAVEFORM_SLV_48 is + variable Result : T_SIM_WAVEFORM_SLV_48(0 to slvv'length - 1); + begin + for i in 0 to slvv'length - 1 loop + Result(i).Delay := Delay; + Result(i).Value := slvv(i); + end loop; + return Result; + end function; + + function to_waveform(slvv : T_SLVV_64; Delay : time) return T_SIM_WAVEFORM_SLV_64 is + variable Result : T_SIM_WAVEFORM_SLV_64(0 to slvv'length - 1); + begin + for i in 0 to slvv'length - 1 loop + Result(i).Delay := Delay; + Result(i).Value := slvv(i); + end loop; + return Result; + end function; + + -- predefined common waveforms + function simGenerateWaveform_Reset(constant Pause : time := 0 ns; ResetPulse : time := 10 ns) return T_SIM_WAVEFORM is + variable p : time; + variable rp : time; + begin + -- WORKAROUND: for Mentor QuestaSim/ModelSim + -- Version: 10.4c + -- Issue: + -- return (0 => Pause, 1 => ResetPulse); always evaluates to (0 ns, 10 ns), + -- regardless of the passed function parameters + -- Bugfix: + -- The bugfix will be included in 10.5a, but this workaround must be + -- present until Altera updates the embedded ModelSim Altera Edition. + p := Pause; + rp := ResetPulse; + return (0 => p, 1 => rp); + end function; +end package body; |