------------------------------------------------------------
-- Copyright: 2011 Integrated Sytems Laboratory, ETH Zurich
-- http://www.iis.ee.ethz.ch/~sha3
------------------------------------------------------------
-------------------------------------------------------------------------------
-- Title : Modified version of the simulstuff
-- Project : Shabziger
-------------------------------------------------------------------------------
-- File : simulstuff.vhd
-- Author : Frank K. Guerkaynak
-- Company : Integrated Systems Laboratory, ETH Zurich
-- Created : 2011-08-22
-- Last update: 2011-08-22
-- Platform : ModelSim (simulation), Synopsys (synthesis)
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: This is a branch from the original simulstuff by H. Kaeslin et
-- al. It was slightly modified for Acacia. In the Shabziger
-- project we have modified that it does not use an output file
-- A single file is used to read in the stimuli
-------------------------------------------------------------------------------
-- Copyright (c) 2011 Integrated Systems Laboratory, ETH Zurich
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2011-08-22 1.0 kgf Created
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
use std.textio.all;
library ieee;
use ieee.std_logic_textio.all; -- read and write overloaded for std_logic
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.Uniform; -- IEEE 1076.2 real math package
use ieee.math_real.Trunc;
-------------------------------------------------------------------------------
-- package declaration
package simulstuff is
-- kgf's silly vector 2 hex conversion.
procedure four2hex
(p_line: inout line;
value : in std_logic_vector( 3 downto 0));
procedure vector2hex
(p_line: inout line;
vector : in std_logic_vector);
-- support for file handling
function FileOpenMessage
(filename : string; status : file_open_status)
return string;
procedure GetFileEntry
(fileentry : inout std_logic_vector;
in_line, in_line_tmp : inout line; filename : string);
procedure GetFileEntry
(fileentry : inout std_logic;
in_line, in_line_tmp : inout line; filename : string);
function FileReadMessage
(filename : string; read_ok : boolean; lineread : string)
return string;
-- support for process coordination, patterned after a traffic light
type trafficlight is (
orange, -- simulation run is waiting to start
green, -- simulation run is under way
green2, -- idem but there are no expected responses left
yellow, -- simulation run has exhausted its stimuli
red ); -- simulation run has completed
type trafficlightvector is array (natural range <>) of trafficlight;
function ResolveTrafficLight
(argument : in trafficlightvector) return trafficlight;
-- support for evaluating responses from the MUT
type respmatchtype is (
mok, -- o.k. = both logic value and drive strength do match
mlf, -- logic fail = logic value or tristate status does not match
msf, -- strength fail = weak instead of strong drive or viceversa
mil ); -- illegal response = actual response has value "don't care"
type vectorwise_matchtable
is array (respmatchtype, respmatchtype) of respmatchtype;
constant check_vectorwise : vectorwise_matchtable := (
-- ----------------------------------
-- | mok mlf msf mil | |
-- ----------------------------------
( mok, mlf, msf, mil ), -- | mok |
( mlf, mlf, mlf, mil ), -- | mlf |
( msf, mlf, msf, mil ), -- | msf |
( mil, mlf, mil, mil ) -- | mil |
); -- symmetric, dimensions may be interchanged
type respaccounttype is record
numberof_mch, -- number of responses checked so far
numberof_mok, -- see above for this and all other fields
numberof_mlf,
numberof_msf,
numberof_mil : natural;
end record;
procedure CheckResponse
(actresp, expresp : in std_logic_vector;
respmatch : out respmatchtype;
respaccount : inout respaccounttype);
procedure CheckResponse
(actresp, expresp : in std_logic;
respmatch : out respmatchtype;
respaccount : inout respaccounttype);
function AnnotateFailureMessage
(respmatch : in respmatchtype) return string;
procedure PutSimulationReportSummary
(respaccount : in respaccounttype);
-- support for generation of random test patterns
procedure GenerateRandomVector
(randvectwidth : in natural;
statevar1, statevar2 : inout integer;
randvect : out std_logic_vector); -- unconstrained array type
end package simulstuff;
--=============================================================================
-- package body
package body simulstuff is
procedure four2hex
(p_line: inout line;
value : in std_logic_vector( 3 downto 0))
is
begin
case value is
when "0000" => write (p_line, string'("0"));
when "0001" => write (p_line, string'("1"));
when "0010" => write (p_line, string'("2"));
when "0011" => write (p_line, string'("3"));
when "0100" => write (p_line, string'("4"));
when "0101" => write (p_line, string'("5"));
when "0110" => write (p_line, string'("6"));
when "0111" => write (p_line, string'("7"));
when "1000" => write (p_line, string'("8"));
when "1001" => write (p_line, string'("9"));
when "1010" => write (p_line, string'("a"));
when "1011" => write (p_line, string'("b"));
when "1100" => write (p_line, string'("c"));
when "1101" => write (p_line, string'("d"));
when "1110" => write (p_line, string'("e"));
when "1111" => write (p_line, string'("f"));
when others => write (p_line, string'("X"));
end case;
end procedure four2hex;
procedure vector2hex
(p_line: inout line;
vector : in std_logic_vector)
is
variable a : std_logic_vector( vector'length-1 downto 0 ):= vector ;
variable i : natural;
variable steps : natural;
variable b : std_logic_vector( 3 downto 0);
variable extra_bits : boolean;
begin
extra_bits := true;
b := "0000";
i := a'length;
if (i mod 4 = 1) then
b := "000" & a (i-1);
i := i-1 ;
elsif (i mod 4 = 2) then
b := "00" & a(i-1 downto i-2);
i := i-2;
elsif (i mod 4 = 3) then
b := '0' & a(i-1 downto i-3);
i := i-3;
else
extra_bits := false;
end if;
if extra_bits then
four2hex(p_line,b);
end if;
steps := (i / 4) - 1;
for j in 0 to steps loop
b:= a ( (steps-j)*4+3 downto (steps-j)*4);
four2hex(p_line,b);
end loop;
end vector2hex;
-- purpose: translate file open status into a human-readable text string.
function FileOpenMessage (filename : string; status : file_open_status)
return string is
begin
case status is
when open_ok => return "File "& filename &" opened successfully.";
when status_error => return "File "& filename &" already opened.";
when name_error => return
"File "& filename &" does not exist or can not be created.";
when mode_error => return
"File "& filename &" can not be opened in write or append mode.";
end case;
end FileOpenMessage;
-- purpose: get one entry from the stimuli or expected responses file.
procedure GetFileEntry
(fileentry : inout std_logic_vector;
in_line, in_line_tmp : inout line;
filename : string)
is
variable read_ok : boolean;
begin
-- extract next entry to obtain the value of formal variable fileentry
read(in_line,fileentry,read_ok);
if not read_ok then
report FileReadMessage(filename,read_ok,in_line_tmp.all)
severity error;
end if;
end GetFileEntry;
-- purpose: above procedure overloaded for scalars rather than vectors.
procedure GetFileEntry
(fileentry : inout std_logic;
in_line, in_line_tmp : inout line; filename : string)
is
variable read_ok : boolean;
begin
-- extract next entry to obtain the value of formal variable fileentry
read(in_line,fileentry,read_ok);
if not read_ok then
report FileReadMessage(filename,read_ok,in_line_tmp.all)
severity error;
end if;
end GetFileEntry;
-- purpose: translate file read status into a human-readable text string.
function FileReadMessage
(filename : string;
read_ok : boolean; lineread : string)
return string is
begin
if read_ok=true then
return "Line `"& lineread &"' sucessfully read from file "
& filename &".";
else
return "Missing or unsuitable entry found while reading line `"
& lineread &"' from file "& filename &".";
end if;
end FileReadMessage;
-------------------------------------------------------------------------------
-- purpose: determine actual status of simulation run,
-- argument simply overwrites previous signal value
-- as simulation progress never moves back.
function ResolveTrafficLight
(argument : in trafficlightvector) return trafficlight
is
type trafficlighttable is array (trafficlight, trafficlight)
of trafficlight;
constant colortable : trafficlighttable := (
-- --------------------------------------------------
-- | orange green green2 yellow red | |
-- --------------------------------------------------
( orange, green, green2, yellow, red ), -- | orange |
( green, green, green2, yellow, red ), -- | green |
( green2, green2, green2, yellow, red ), -- | green2 |
( yellow, yellow, yellow, yellow, red ), -- | yellow |
( red, red, red, red, red ) -- | red |
); -- commutative, dimensions may be interchanged
variable result: trafficlight := orange;
begin
for i in argument'range loop
result := colortable(result,argument(i));
end loop;
return result;
end ResolveTrafficLight;
-------------------------------------------------------------------------------
-- purpose: check to what extent actual and expected responses match,
-- return a grade, and update failure account record accordingly.
procedure CheckResponse
(actresp, expresp : in std_logic_vector;
respmatch : out respmatchtype;
respaccount : inout respaccounttype)
is
type bitwise_matchtable is array (std_logic, std_logic) of respmatchtype;
constant check_bitwise : bitwise_matchtable := (
-- ---------------------------------------------------------
-- exp | U X 0 1 Z W L H - |act|
-- ---------------------------------------------------------
( mok, mlf, mlf, mlf, mlf, mlf, mlf, mlf, mok ), -- | U |
( mlf, mok, mlf, mlf, mlf, msf, mlf, mlf, mok ), -- | X |
( mlf, mlf, mok, mlf, mlf, mlf, msf, mlf, mok ), -- | 0 |
( mlf, mlf, mlf, mok, mlf, mlf, mlf, msf, mok ), -- | 1 |
( mlf, mlf, mlf, mlf, mok, mlf, mlf, mlf, mok ), -- | Z |
( mlf, msf, mlf, mlf, mlf, mok, mlf, mlf, mok ), -- | W |
( mlf, mlf, msf, mlf, mlf, mlf, mok, mlf, mok ), -- | L |
( mlf, mlf, mlf, msf, mlf, mlf, mlf, mok, mok ), -- | H |
( mil, mil, mil, mil, mil, mil, mil, mil, mil ) -- | - |
); -- act is the 1st and exp the 2nd dimension
variable bitwise_match, vectorwise_match : respmatchtype := mok;
begin
assert expresp'length=actresp'length and expresp'length>0
report " Cardinality of response does not match or is zero."
severity warning;
for i in expresp'range loop
bitwise_match := check_bitwise(actresp(i),expresp(i));
vectorwise_match := check_vectorwise(vectorwise_match,bitwise_match);
end loop;
respmatch := vectorwise_match;
case vectorwise_match is
when mok => respaccount.numberof_mok := respaccount.numberof_mok +1;
when mlf => respaccount.numberof_mlf := respaccount.numberof_mlf +1;
when msf => respaccount.numberof_msf := respaccount.numberof_msf +1;
when mil => respaccount.numberof_mil := respaccount.numberof_mil +1;
end case;
respaccount.numberof_mch := respaccount.numberof_mch +1;
end CheckResponse;
-- purpose: above procedure overloaded for scalars rather than vectors.
procedure CheckResponse
(actresp, expresp : in std_logic;
respmatch : out respmatchtype;
respaccount : inout respaccounttype)
is
variable actrespvector, exprespvector : std_logic_vector(0 to 0);
begin
actrespvector(0) := actresp; exprespvector(0) := expresp;
CheckResponse(actrespvector,exprespvector,respmatch,respaccount);
end CheckResponse;
-------------------------------------------------------------------------------
-- purpose: generate a text string that comments on how a response matches.
function AnnotateFailureMessage (respmatch : in respmatchtype)
return string is
begin
case respmatch is
when mok => return string' -- everything as expected
("^^ matched. ");
when mlf => return string' -- wrong logic state or yes/no drive
("^^ failed logically! ");
when msf => return string' -- wrong drive strength
("^^ failed in strength! ");
when others => return string' -- no legal logic value for simulation
("^^ failed illegally! ");
end case;
end AnnotateFailureMessage;
-------------------------------------------------------------------------------
-- purpose: summarize simulation report and write it to report file.
procedure PutSimulationReportSummary
(respaccount : in respaccounttype)
is
variable out_line : line;
begin
-- separator
write(out_line,string'("% ======== Simulation Report Summary ========"));
writeline(output,out_line);
-- 1st line
write(out_line,string'("% A total of "));
write(out_line,respaccount.numberof_mch);
write(out_line,string'(" responses have been checked, out of which "));
write(out_line,respaccount.numberof_mok);
write(out_line,string'(" matched expectations."));
writeline(output,out_line); -- to screen ??
-- 2nd line
assert respaccount.numberof_mch /= respaccount.numberof_mok
report "All Results Match! " severity note;
assert respaccount.numberof_mch = respaccount.numberof_mok
report "ERRORS in Simulation" severity warning;
end PutSimulationReportSummary;
-------------------------------------------------------------------------------
-- purpose: generate binary random vectors of parametrized word width that
-- should be uniformly distributed over interval [0,2**randvectwidth-1].
-- limitation: mantissa of VHDL type reals has 23bits, so randvectwidth
-- must not exceed this value as outcome is otherwise uncertain.
-- note: state variables of procedure Uniform must be kept within the
-- calling process because variables in a subprogram do not persist.
-- findings: repeated calls of procedure ieee.math_real.Uniform with
-- identical seeds indeed result in identical pseudo random numbers.
procedure GenerateRandomVector
(randvectwidth : in natural;
statevar1, statevar2 : inout integer;
randvect : out std_logic_vector) -- unconstrained array type
is
constant upperbound : real := (2.0**randvectwidth)-1.0;
variable randreal01 : real := 0.0;
variable randscaled, randtruncd : real := 0.0;
variable randinteger : integer := 0;
begin
-- obtain a random real in [0,1]
Uniform(statevar1,statevar2,randreal01);
-- rescale interval [0,1] to [0,upperbound]
randscaled := randreal01*(upperbound+1.0);
-- truncate to next smaller integer (still of type real, though)
if randscaled/=(upperbound+1.0) then -- almost always
randtruncd := Trunc(randscaled);
else -- avoid spillover when randreal01 was exactly 1.0
randtruncd := 0.0; -- 0.0 or upperbound is largely immaterial
end if;
-- convert to a binary vector
randinteger := integer(randtruncd);
randvect := std_logic_vector(
to_unsigned(randinteger,randvectwidth));
end GenerateRandomVector;
-------------------------------------------------------------------------------
end package body simulstuff;