------------------------------------------------------------
-- Copyright: 2010 Integrated Sytems Laboratory, ETH Zurich
--            http://www.iis.ee.ethz.ch/~sha3
------------------------------------------------------------
-------------------------------------------------------------------------------
-- File:         simulstuff.vhd
-- Authors:      H.Kaeslin, M.Stadler, P.Luethi, F.Camarero, Th.Kuch, M.Braendli
-- Copyright:	 1995 - 2007 Microelectronics Design Center, ETH Zurich
-- Platform:     ModelSim 6.3
-- Last changes: 23.4.2008
-------------------------------------------------------------------------------
-- Mission:     Take care of all those lower-level issues of testbench
--              writing that make this activity slow and boring when starting
--              from scratch.
-- Description: A collection of universal types and subprograms that are
--              helpful for simulation purposes, not intended for synthesis.
--              By universal we mean independent of the model under test (MUT).
-------------------------------------------------------------------------------
-- Modification history:
--  7.7.98: source code established.
-- 16.7.98: new subprograms added for response evaluation and reporting.
--  4.9.98: failure annotation modified.
-- 31.5.00: generator for random vectors added.
--  7.6.00: CheckResponse overloaded for std_logic as suggested by M.Braendli.
-- 22.6.00: extraction of file entries (read) included for brevity of testb.
-- 07.5.03: added GenerateRandomBit where probability can be controlled.
-- 06.6.03: changed GenerateRandomVector for random numbers in open interval.
-- 18.7.05: new global signal "EndOfSimxS".
-- 25.7.05: new entry "mne" in (enumeration)type "respmatchtype".
-- 26.7.05: procedure PutSimulationReportSummary changed.
-- 09.8.05: CheckResponse renamed to CheckValue.
-- 20.9.05: function AnnotateFailureMessage removed.
-- 21.9.05: various changes and extensions by P.Luethi added:
--          - extensions to stimuli/expresp file input:
--            GetFileEntryXXX for signed/unsigned integer to
--            signed/unsigned/std_logic_vector conversion
--          - CheckValue and write() overload methods for signed & unsigned
-- 23.4.08: some general cleanup
-------------------------------------------------------------------------------
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
   
   -- signal to broadcast the end of simulation
   signal EndOfSimxS : boolean := false;
   -- clock generator     
   procedure ClockGenerator (
      signal ClkxC          : out std_logic;
      constant clkphaselow  : in  time;
      constant clkphasehigh : in  time);  

   -- support for file handling
   function FileOpenMessage (
      filename : string; status : file_open_status)
      return string;
   function FileReadMessage (
      filename : string; read_ok : boolean; lineread : string)
      return string;

   -- purpose: get one entry from the stimuli or expected responses file
   -- binary character => std_logic
   procedure GetFileEntry (
      fileentry            : inout std_logic;
      in_line, in_line_tmp : inout line; filename : string);
   -- binary string => std_logic_vector
   procedure GetFileEntry (
      fileentry            : inout std_logic_vector;
      in_line, in_line_tmp : inout line; filename : string);
   -- binary string => unsigned
   procedure GetFileEntry (
      val                  : inout unsigned;
      in_line, in_line_tmp : inout line; filename : string);
   -- binary string => signed
   procedure GetFileEntry (
      val                  : inout signed;
      in_line, in_line_tmp : inout line; filename : string);
   -- unsigned integer string => unsigned
   procedure GetFileEntryInt2x (
      val                  : inout unsigned;
      in_line, in_line_tmp : inout line; filename : string);
   -- signed/unsigned integer string => signed
   procedure GetFileEntryInt2x (
      val                  : inout signed;
      in_line, in_line_tmp : inout line; filename : string);
   -- signed/unsigned integer string => (signed =>) std_logic_vector
   procedure GetFileEntryInt2x (
      val                  : inout std_logic_vector;
      in_line, in_line_tmp : inout line; filename : string);
   -- unsigned integer string => (unsigned =>) std_logic_vector
   procedure GetFileEntryUInt2x (
      val                  : inout std_logic_vector;
      in_line, in_line_tmp : inout line; filename : string);

   -- support for evaluating responses from the MUT
   type respmatchtype is (
      mne,   -- not evaluated = expected response has the value "don't care"
      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 := (
      --     ---------------------------------------
      --     | mne  mok  mlf  msf  mil       |     |   
      --     ---------------------------------------
             ( mne, mok, mlf, msf, mil ), -- | mne |
             ( mok, mok, mlf, msf, mil ), -- | mok |
             ( mlf, mlf, mlf, mlf, mil ), -- | mlf |
             ( msf, msf, mlf, msf, mil ), -- | msf |
             ( mil, mil, mil, mil, mil )  -- | mil |
             );   -- symmetric, dimensions may be interchanged
   
   type respaccounttype is record
      numberof_mch,  -- number of responses checked so far
      numberof_mne,  -- see above for this and all other fields  
      numberof_mok,
      numberof_mlf,
      numberof_msf,
      numberof_mil : natural;
   end record;

   -- checks if actual and expected response are equal
   procedure CheckValue (
      actresp, expresp : in    std_logic_vector;
      respmatch        : out   respmatchtype;
      respaccount      : inout respaccounttype);
   procedure CheckValue (
      actresp, expresp : in    std_logic;
      respmatch        : out   respmatchtype;
      respaccount      : inout respaccounttype);
   procedure CheckValue (
      actresp, expresp : in    unsigned;
      respmatch        : out   respmatchtype;
      respaccount      : inout respaccounttype);
   procedure CheckValue (
      actresp, expresp : in    signed;
      respmatch        : out   respmatchtype;
      respaccount      : inout respaccounttype);

   -- purpose: summarize simulation report and write it to report file
   procedure PutSimulationReportSummary
      (file simreptfile : text; respaccount : in respaccounttype);

   -- purpose: overload write for signed and unsigned
   procedure write (outline : inout line; val : in unsigned);
   procedure write (outline : inout line; val : in signed);

   -- support for generation of random test patterns
   procedure GenerateRandomVector (
      randvectwidth        : in    natural;
      statevar1, statevar2 : inout integer;
      randvect             : out   std_logic_vector);  -- unconstrained array type
   procedure GenerateRandomBit (
      probability_of_1     : in    real;
      statevar1, statevar2 : inout integer;
      randbit              : out   std_logic);
   procedure GenerateRandomInteger (
      min, max             : in    integer;
      statevar1, statevar2 : inout integer;
      randinteger          : out   integer);

   
end package simulstuff;
--=============================================================================

-- package body
package body simulstuff is
   
   -- purpose: generate a periodic but stoppable clock signal,
   -- generator to be instantiated as a concurrent procedure.
   procedure ClockGenerator
      (signal ClkxC          : out std_logic;
       constant clkphaselow  : in  time;
       constant clkphasehigh : in  time)
   is
   begin
      ClkGen : loop
         ClkxC <= '1';
         wait for clkphasehigh;
         ClkxC <= '0';
         wait for clkphaselow;
         exit ClkGen when EndOfSimxS = true;
      end loop ClkGen;
      wait;                             -- forever
   end procedure ClockGenerator;
-------------------------------------------------------------------------------

   -- 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: 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;
-------------------------------------------------------------------------------
   
   -- ### binary character => std_logic
   -- purpose: get one entry from the stimuli or expected responses file
   -- source (file entry) : binary
   -- target (VHDL signal): std_logic
   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);  -- binary read
      if not read_ok then
         report FileReadMessage(filename, read_ok, in_line_tmp.all) severity error;
      end if;
   end GetFileEntry;

   -- ### binary string => std_logic_vector
   -- purpose: get one entry from the stimuli or expected responses file
   -- source (file entry) : binary
   -- target (VHDL signal): std_logic_vector
   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);      -- binary read
      if not read_ok then
         hread(in_line, fileentry, read_ok);  -- try hex-read
         if not read_ok then
            report FileReadMessage(filename, read_ok, in_line_tmp.all) severity error;
         end if;
      end if;
   end GetFileEntry;

   -- ### binary string => unsigned
   -- purpose: get one entry from the stimuli or expected responses file
   -- source (file entry) : binary
   -- target (VHDL signal): unsigned
   procedure GetFileEntry (
      val                  : inout unsigned;
      in_line, in_line_tmp : inout line;
      filename             :       string)
   is
      variable read_ok   : boolean;
      variable fileentry : std_logic_vector(val'high downto val'low);
   begin
      -- extract next entry to obtain the value of formal variable fileentry
      read(in_line, fileentry, read_ok);      -- binary read
      if not read_ok then
         hread(in_line, fileentry, read_ok);  -- try hex-read
         if not read_ok then
            report FileReadMessage(filename, read_ok, in_line_tmp.all) severity error;
         end if;
      end if;
      val := unsigned(fileentry);
   end GetFileEntry;

   -- ### binary string => signed
   -- purpose: get one entry from the stimuli or expected responses file
   -- source (file entry) : binary
   -- target (VHDL signal): signed
   procedure GetFileEntry (
      val                  : inout signed;
      in_line, in_line_tmp : inout line;
      filename             :       string)
   is
      variable read_ok   : boolean;
      variable fileentry : std_logic_vector(val'high downto val'low);
   begin
      -- extract next entry to obtain the value of formal variable fileentry
      read(in_line, fileentry, read_ok);      -- binary read
      if not read_ok then
         hread(in_line, fileentry, read_ok);  -- try hex-read
         if not read_ok then
            report FileReadMessage(filename, read_ok, in_line_tmp.all) severity error;
         end if;
      end if;
      val := signed(fileentry);
   end GetFileEntry;
   
   -- ### unsigned integer string => unsigned
   -- purpose: get one entry from the stimuli or expected responses file
   -- source (file entry) : unsigned integer
   -- target (VHDL signal): unsigned
   procedure GetFileEntryInt2x (
      val                  : inout unsigned;
      in_line, in_line_tmp : inout line;
      filename             :       string)
   is
      variable read_ok   : boolean;
      variable fileentry : integer;
   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;
      val := to_unsigned(fileentry, val'length);
   end GetFileEntryInt2x;

   -- ### signed/unsigned integer string => signed
   -- purpose: get one entry from the stimuli or expected responses file
   -- source (file entry) : signed/unsigned integer
   -- target (VHDL signal): signed
   procedure GetFileEntryInt2x (
      val                  : inout signed;
      in_line, in_line_tmp : inout line;
      filename             :       string)
   is
      variable read_ok   : boolean;
      variable fileentry : integer;
   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;
      val := to_signed(fileentry, val'length);
   end GetFileEntryInt2x;

   -- ### signed/unsigned integer string => (signed =>) std_logic_vector
   -- purpose: get one entry from the stimuli or expected responses file
   -- source (file entry) : signed/unsigned integer
   -- target (VHDL signal): (signed) std_logic_vector
   procedure GetFileEntryInt2x (
      val                  : inout std_logic_vector;
      in_line, in_line_tmp : inout line;
      filename             :       string)
   is
      variable tmp_signed : signed(1 to val'length);
   begin
      -- use overloaded procedure
      GetFileEntryInt2x(tmp_signed, in_line, in_line_tmp, filename);
      val := std_logic_vector(tmp_signed);
   end GetFileEntryInt2x;

   -- ### unsigned integer string => (unsigned =>) std_logic_vector
   -- purpose: get one entry from the stimuli or expected responses file
   -- source (file entry) : unsigned integer
   -- target (VHDL signal): (unsigned) std_logic_vector
   procedure GetFileEntryUInt2x (
      val                  : inout std_logic_vector;
      in_line, in_line_tmp : inout line;
      filename             :       string)
   is
      variable tmp_unsigned : unsigned(1 to val'length);
   begin
      -- use overloaded procedure
      GetFileEntryInt2x(tmp_unsigned, in_line, in_line_tmp, filename);
      val := std_logic_vector(tmp_unsigned);
   end GetFileEntryUInt2x;
-------------------------------------------------------------------------------

   -- purpose: check to what extent actual and expected responses match,
   --    return a grade and update failure account record accordingly.
   procedure CheckValue (
      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, mne ), -- | U |
             ( mlf, mok, mlf, mlf, mlf, msf, mlf, mlf, mne ), -- | X |
             ( mlf, mlf, mok, mlf, mlf, mlf, msf, mlf, mne ), -- | 0 |
             ( mlf, mlf, mlf, mok, mlf, mlf, mlf, msf, mne ), -- | 1 |
             ( mlf, mlf, mlf, mlf, mok, mlf, mlf, mlf, mne ), -- | Z |
             ( mlf, msf, mlf, mlf, mlf, mok, mlf, mlf, mne ), -- | W |
             ( mlf, mlf, msf, mlf, mlf, mlf, mok, mlf, mne ), -- | L |
             ( mlf, mlf, mlf, msf, mlf, mlf, mlf, mok, mne ), -- | 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 := mne;
   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 mne => respaccount.numberof_mne := respaccount.numberof_mne + 1;
         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 CheckValue;
   
   -- purpose: above procedure overloaded for scalars rather than vectors.
   procedure CheckValue (
      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;
      CheckValue(actrespvector, exprespvector, respmatch, respaccount);
   end CheckValue;

   -- purpose: above procedure overloaded for unsigned rather than std_logic_vector
   procedure CheckValue (
      actresp, expresp : in    unsigned;
      respmatch        : out   respmatchtype;
      respaccount      : inout respaccounttype)
   is
      variable actrespvector, exprespvector : std_logic_vector(actresp'high downto actresp'low);
   begin
      actrespvector := std_logic_vector(actresp);
      exprespvector := std_logic_vector(expresp);
      CheckValue(actrespvector, exprespvector, respmatch, respaccount);
   end CheckValue;

   -- purpose: above procedure overloaded for signed rather than std_logic_vector
   procedure CheckValue (
      actresp, expresp : in    signed;
      respmatch        : out   respmatchtype;
      respaccount      : inout respaccounttype)
   is
      variable actrespvector, exprespvector : std_logic_vector(actresp'high downto actresp'low);
   begin
      actrespvector := std_logic_vector(actresp);
      exprespvector := std_logic_vector(expresp);
      CheckValue(actrespvector, exprespvector, respmatch, respaccount);
   end CheckValue;
-------------------------------------------------------------------------------

   -- purpose: summarize simulation report and write it to report file.
   procedure PutSimulationReportSummary
      (file simreptfile : text; respaccount : in respaccounttype)
   is
      variable out_line : line;
   begin
      write(out_line, string'(" "));
      writeline(simreptfile, out_line);
      write(out_line, string'("====== Simulation Report Summary ==============================="));
      writeline(simreptfile, out_line);
      write(out_line, string'(" Total of responses: "));
      write(out_line, respaccount.numberof_mch);
      writeline(simreptfile, out_line);
      write(out_line, string'(" "));
      writeline(simreptfile, out_line);
      write(out_line, string'(" "));
 
      write(out_line, string'(" TOTAL VECTORS TESTED: "));
      write(out_line, respaccount.numberof_mch - respaccount.numberof_mne);
      writeline(simreptfile, out_line);

      write(out_line, string'("  ---------------------------------"));
      writeline(simreptfile, out_line);
      
      write(out_line, string'("   "));
      write(out_line, string'(" CORRECT RESPONSES:  "));
      write(out_line, respaccount.numberof_mok);
      writeline(simreptfile, out_line);
      
      write(out_line, string'("   "));
      write(out_line, string'(" FALSE   RESPONSES:  "));
      write(out_line, respaccount.numberof_mlf + respaccount.numberof_msf + respaccount.numberof_mil);
      writeline(simreptfile, out_line);

      writeline(simreptfile, out_line);
      
      write(out_line, string'("      "));
      write(out_line, respaccount.numberof_mlf);
      write(out_line, string'(" responses failed logically (those with a 'l')"));
      writeline(simreptfile, out_line);
      write(out_line, string'("      "));
      write(out_line, respaccount.numberof_msf);
      write(out_line, string'(" failed in drive strength (those with a 's')"));
      writeline(simreptfile, out_line);
      write(out_line, string'("      "));
      write(out_line, respaccount.numberof_mil);
      write(out_line, string'(" had an illegal logic value (those with a 'i')"));
      writeline(simreptfile, out_line);
      write(out_line, string'(" "));
      writeline(simreptfile, out_line);
      write(out_line, string'(" "));
      write(out_line, respaccount.numberof_mne);
      write(out_line, string'(" responses haven't been checked (those with a '-'), because"));
      writeline(simreptfile, out_line);
      write(out_line, string'(" "));
      write(out_line, string'("expected responses are unavailable or given as "&'"'&"don't care"&'"'&"."));
      writeline(simreptfile, out_line);
   end PutSimulationReportSummary;
-------------------------------------------------------------------------------

   -- purpose: overload write method for unsigned
   procedure write (outline : inout line; val : in unsigned) is
   begin
      write(outline, std_logic_vector(val));
   end write;

   -- purpose: overload write method for signed
   procedure write (outline : inout line; val : in signed) is
   begin
      write(outline, std_logic_vector(val));
   end write;
-------------------------------------------------------------------------------

   -- 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
      -- upperbound is (2.0**randvectwidth)-1.0, spreadbound is 1.0 more
      constant spreadbound            : real    := 2.0**randvectwidth;
      variable randreal01             : real    := 0.0;
      variable randscaled, randtruncd : real    := 0.0;
      variable randinteger            : integer := 0;
   begin
      -- obtain a random real in the open interval ]0,1[
      Uniform(statevar1, statevar2, randreal01);
      -- scale open interval ]0,1[ to open interval ]0,spreadbound[
      randscaled  := randreal01*spreadbound;
      -- truncate to next smaller integer (still of type real, though)
      -- in the closed interval [0,upperbound]
      randtruncd  := Trunc(randscaled);
      -- convert to a binary vector
      randinteger := integer(randtruncd);
      randvect    := std_logic_vector(to_unsigned(randinteger, randvectwidth));
   end GenerateRandomVector;

   -- purpose: generate a random bit with some given probability of being '1'.
   -- 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 GenerateRandomBit (
      probability_of_1     : in    real;
      statevar1, statevar2 : inout integer;
      randbit              : out   std_logic) 
   is
      variable randreal01 : real := 0.0;
   begin
      -- obtain a random real in the open interval ]0,1[
      Uniform(statevar1, statevar2, randreal01);
      -- set randbit according to threshold
      if (probability_of_1 > randreal01) then
         randbit := '1';
      else
         randbit := '0';
      end if;
   end GenerateRandomBit;

   -- purpose: generate random integer in the range [min, max], both included.
   -- 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 GenerateRandomInteger (
      min, max             : in    integer;
      statevar1, statevar2 : inout integer;
      randinteger          : out   integer)  
   is
      variable randreal01  : real := 0.0;
      constant spreadbound : real := real(max-min+1);
      variable randscaled  : real := 0.0;
   begin
      -- obtain a random real in the open interval ]0,1[
      Uniform(statevar1, statevar2, randreal01);
      -- scale open interval ]0,1[ to open interval ]0,spreadbound[
      randscaled  := randreal01*spreadbound;
      -- truncate to next smaller integer in the closed interval [0,max-min] and
      -- add the mininum value to get an integer in the closed interval [min,max]
      randinteger := integer(Trunc(randscaled)) + min;
   end GenerateRandomInteger;


end package body simulstuff;

Generated on Fri Sep 24 10:39:12 CEST 2010
Home