------------------------------------------------------------ -- Copyright: 2011 Integrated Sytems Laboratory, ETH Zurich -- http://www.iis.ee.ethz.ch/~sha3 ------------------------------------------------------------ ------------------------------------------------------------------------------- -- Title : Testbench for design "skein" -- Project : ------------------------------------------------------------------------------- -- File : skein_tb.vhd -- Author : Christoph Keller -- Company : Integrated Systems Laboratory, ETH Zurich -- Created : 2011-08-15 -- Last update: 2011-09-01 -- Platform : ModelSim (simulation), Synopsys (synthesis) -- Standard : VHDL'87 ------------------------------------------------------------------------------- -- Description: ------------------------------------------------------------------------------- -- Copyright (c) 2011 Integrated Systems Laboratory, ETH Zurich ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2011-08-15 1.0 chrikell Created ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use work.simulstuff.all; use std.textio.all; ------------------------------------------------------------------------------- entity ethz_skein_tb is end ethz_skein_tb; ------------------------------------------------------------------------------- architecture test of ethz_skein_tb is component ethz_skein port ( ClkxCI : in std_logic; RstxRBI : in std_logic; FinBlockxSI : in std_logic; InWrEnxSI : in std_logic; OutWrEnxSO : out std_logic; PenUltCyclexSO : out std_logic; BlockxDI : in std_logic_vector(511 downto 0); MsgLenxDI : in std_logic_vector(63 downto 0); HashxDO : out std_logic_vector(255 downto 0); ScanInxTI : in std_logic; ScanEnxTI : in std_logic; ScanOutxTO : out std_logic); end component; -- component ports signal ClkxC : std_logic; signal RstxRB : std_logic; signal FinBlockxS : std_logic; signal InWrEnxS : std_logic; signal OutWrEnxS : std_logic; signal PenUltCyclexS : std_logic; signal DataInxD : std_logic_vector(511 downto 0); signal DigestxD : std_logic_vector(255 downto 0); signal ExpRespxD : std_logic_vector(255 downto 0); signal MsgLenxD : std_logic_vector(63 downto 0); signal ScanInxT : std_logic := '0'; -- No scan for this version signal ScanEnxT : std_logic := '0'; -- No scan for this version signal ScanOutxT : std_logic; -- clock signal Clk : std_logic := '1'; type stimulirecordtype is record DataInxD : std_logic_vector(511 downto 0); FinBlockxS : std_logic; MsgLenxD : std_logic_vector(63 downto 0); DigestxD : std_logic_vector(255 downto 0); end record; signal STIMULI : stimulirecordtype; -- record of stimuli -- declarations of signals that do help coordinate testbench processes signal SIMPROGRESS : ResolveTrafficLight trafficlight := orange; -- timing of clock and simulation events constant clkphasehigh : time := 10 ns; constant clkphaselow : time := 10 ns; constant responseacquisitiontime : time := 15 ns; constant stimulusapplicationtime : time := 5 ns; constant resetactivetime : time := 5 ns; -- declaration of stimuli, expected responses, and simulation report files file stimulifile, simreptfile : text; constant stimulifilename : string := "../simvectors/testvectors.txt"; ---- declaration of non-universal i.e. MUT-dependent subprograms -- purpose: get one record worth of stimuli from file. impure function GetStimuliRecord (file stimulifile : text) return stimulirecordtype is variable read_ok : boolean; variable in_line, in_line_tmp : line; -- stimuli to default to unknown in case no value is obtained from file variable stimulirecord : stimulirecordtype := (DataInxD => (others => '0'), FinBlockxS => '0', MsgLenxD => (others => '0'), DigestxD => (others => '-') ); begin -- read a line from the stimuli file -- skipping any empty and comment lines encountered loop readline(stimulifile, in_line); -- copy line read to enable meaningful error messages later in_line_tmp := new string'(in_line(in_line'low to in_line'high)); if in_line_tmp'length >= 1 then exit when in_line_tmp(1) /= '%'; end if; deallocate(in_line_tmp); end loop; -- extract all values of a record of stimuli GetFileEntry (stimulirecord.DataInxD, in_line, in_line_tmp, stimulifilename); GetFileEntry (stimulirecord.FinBlockxS, in_line, in_line_tmp, stimulifilename); GetFileEntry (stimulirecord.MsgLenxD, in_line, in_line_tmp, stimulifilename); GetFileEntry (stimulirecord.DigestxD, in_line, in_line_tmp, stimulifilename); -- deallocate line copy now that all entries have been read deallocate(in_line_tmp); return stimulirecord; end GetStimuliRecord; -- purpose: compose a failure message line and write it to the report file. procedure PutSimulationReportFailure (ActualDigestxD : in std_logic_vector(255 downto 0); ExpectedDigestxD : in std_logic_vector(255 downto 0); respmatch : in respmatchtype) is variable out_line : line; begin report "Error Encountered " severity warning; write(out_line, string'("ERROR at ")); write(out_line, now); writeline(output, out_line); -- add expected responses write(out_line, string'(" Received = ")); vector2hex(out_line, ActualDigestxD); writeline(output, out_line); write(out_line, string'(" Expected = ")); vector2hex(out_line, ExpectedDigestxD); writeline(output, out_line); end PutSimulationReportFailure; begin -- test -- component instantiation DUT : ethz_skein port map ( ClkxCI => ClkxC, RstxRBI => RstxRB, FinBlockxSI => FinBlockxS, InWrEnxSI => InWrEnxS, OutWrEnxSO => OutWrEnxS, PenUltCyclexSO => PenUltCyclexS, BlockxDI => DataInxD, MsgLenxDI => MsgLenxD, HashxDO => DigestxD, ScanInxTI => ScanInxT, ScanEnxTI => ScanEnxT, ScanOutxTO => ScanOutxT ); ScanInxT <= '0'; ScanEnxT <= '0'; -- clock generation Tb_clkgen : process begin case SIMPROGRESS is -- if orange then wait for start sign when orange => wait until SIMPROGRESS = green; -- if green then proceed with yet another clock period when green => null; when green2 => null; -- if yellow (neither red nor any other color should occur here) -- then terminate when others => SIMPROGRESS <= red; wait; -- forever end case; CLKxC <= '1'; wait for clkphasehigh; CLKxC <= '0'; wait for clkphaselow; end process Tb_clkgen; -- launch and terminate simulation run ---------------------------------------------------------------------------- Tb_launchterm : process variable status : file_open_status; begin -- open files for stimuli, config, and simulation report file_open(status, stimulifile, stimulifilename, read_mode); assert status = open_ok report FileOpenMessage(stimulifilename, status) severity failure; -- give start sign to other processes SIMPROGRESS <= green; -- suspend until clock generator shuts down wait until SIMPROGRESS = red; report "Simulation run completed, all stimuli processed." severity note; -- close files file_close(stimulifile); wait; -- forever to starve event queue end process Tb_launchterm; -- obtain stimulus and apply it to MUT ---------------------------------------------------------------------------- Tb_stimappli : process -- variables for accounting of mismatching responses variable respmatch : respmatchtype; variable respaccount : respaccounttype := (0, 0, 0, 0, 0); variable exprespavail : boolean := true; begin -- wait for start sign wait until SIMPROGRESS = green; -- default values RstxRB <= '0'; -- Resets Active FinBlockxS <= '0'; InWrEnxS <= '0'; -- No enbable yet DataInxD <= (others => '0'); -- all zeroes per default -- ExpRespxD others => '-'); -- initially no expectation MsgLenxD <= (others => '0'); wait for resetactivetime; -- Wait until reset is over RstxRB <= '1'; -- take reset back -- initial vector wait until CLKxC'event and CLKxC = '1'; STIMULI <= GetStimuliRecord(stimulifile); wait for stimulusapplicationtime; -- wait until the right time InWrEnxS <= '1'; FinBlockxS <= STIMULI.FinBlockxS; -- we need a slight delay here MsgLenxD <= STIMULI.MsgLenxD; DataInxD <= STIMULI.DataInxD; -- ExpRespxD DigestxD; -- initial value wait until ClkxC'event and ClkxC = '1'; -- make sure data is clocked in -- process until we run out of stimuli appli_loop : while not (endfile(stimulifile)) loop wait for stimulusapplicationtime; InWrEnxS <= '0'; -- no longer needed FinBlockxS <= '0'; --n set back to zero -- wait the cycles until the PenUltCyclexS arrives -- This is the penultimate cycle. Everything will be clear after this done_loop : while PenUltCyclexS = '0' loop wait until ClkxC'event and ClkxC = '1'; wait for responseacquisitiontime; end loop done_loop; -- now we have donexS STIMULI <= GetStimuliRecord(stimulifile); -- read a new value wait until ClkxC'event and ClkxC = '1'; wait for stimulusapplicationtime; InWrEnxS <= '1'; -- new data is here FinBlockxS <= STIMULI.FinBlockxS; -- we need a slight delay here MsgLenxD <= STIMULI.MsgLenxD; DataInxD <= STIMULI.DataInxD; -- apply new data; wait until CLKxC'event and CLKxC = '1'; -- loop until all stimuli have been processed end loop appli_loop; ------------------------------------------------------------------------------- -- Final Vector We applied the last vector, let us wait for the result ------------------------------------------------------------------------------- -- read the last one as well wait for stimulusapplicationtime; InWrEnxS <= '0'; -- no longer needed FinBlockxS <= '0'; -- should be sampled -- wait the cycles until the PenUltCyclexS arrives -- This is the penultimate cycle. Everything will be clear after this last_loop : while PenUltCyclexS = '0' loop wait until ClkxC'event and ClkxC = '1'; wait for responseacquisitiontime; end loop last_loop; wait until CLKxC'event and CLKxC = '1'; wait until CLKxC'event and CLKxC = '1'; SIMPROGRESS <= red; wait; end process Tb_stimappli; ------------------------------------------------------------------------------- -- Check for output responses only ------------------------------------------------------------------------------- tb_respcheck : process -- variables for accounting of mismatching responses variable respmatch : respmatchtype; variable respaccount : respaccounttype := (0, 0, 0, 0, 0); variable out_line : line; begin -- process tb_respcheck -- wait for start sign wait until SIMPROGRESS = green; wait until CLKxC'event and CLKxC = '1'; wait until CLKxC'event and CLKxC = '1'; wait for stimulusapplicationtime; ExpRespxD <= STIMULI.DigestxD; -- initial value while SIMPROGRESS = green loop wait until CLKxC'event and CLKxC = '1'; wait for responseacquisitiontime; if PenUltCyclexS = '1' then ExpRespxD <= STIMULI.DigestxD; -- also for this guy end if; if OutWrEnxS = '1' then -- we have a comparison value CheckResponse(DigestxD, ExpRespxD, respmatch, respaccount); write(out_line, string'(" Expected = ")); vector2hex(out_line, ExpRespxD); writeline(output, out_line); if respmatch /= mok then -- is there a mismatch ?? PutSimulationReportFailure(DigestxD, ExpRespxD, respmatch); else write(out_line, string'(" -> Matching result at ")); write(out_line, now); writeline(output, out_line); end if; -- change the expresp after the out wren, -- assumes that InwrEn is already there end if; end loop; -- sim green PutSimulationReportSummary(respaccount); wait; -- kill the queue end process tb_respcheck; end test;