------------------------------------------------------------ -- Copyright: 2011 Integrated Sytems Laboratory, ETH Zurich -- http://www.iis.ee.ethz.ch/~sha3 ------------------------------------------------------------ ------------------------------------------------------------------------------- -- Title : Testbench for design "Sha256 -- Project : ------------------------------------------------------------------------------- -- File : ethz_sha2_tb.vhd -- Author : Christoph Keller -- Company : Integrated Systems Laboratory, ETH Zurich -- Created : 2011-08-12 -- Last update: 2011-09-10 -- Platform : ModelSim (simulation), Synopsys (synthesis) -- Standard : VHDL'87 ------------------------------------------------------------------------------- -- Description: ------------------------------------------------------------------------------- -- Copyright (c) 2011 Integrated Systems Laboratory, ETH Zurich ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2011-08-12 1.0 chrikell Created -- 2011-08-25 1.01 kgf Changed entity name -- 2011-09-10 1.02 kgf Changed name of the Reset to RstxRBI ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use work.shapkg.all; use work.simulstuff.all; use std.textio.all; ------------------------------------------------------------------------------- entity ethz_sha2_tb is end ethz_sha2_tb; ------------------------------------------------------------------------------- architecture test of ethz_sha2_tb is component ethz_sha2 port ( ClkxCI : in std_logic; RstxRBI : in std_logic; FinBlockxSI : in std_logic; InWrEnxSI : in std_logic; PenUltCyclexSO : out std_logic; OutWrEnxSO : out std_logic; TextInxDI : in std_logic_vector(511 downto 0); HOutxDO : 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(HWIDTH-1 downto 0); signal ExpRespxD : std_logic_vector(255 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; 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 : 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', 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.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_sha2 port map ( CLKxCI => CLKxC, RstxRBI => RstxRB, FinBlockxSI => FinBlockxS, InWrEnxSI => InWrEnxS, PenUltCyclexSO => PenUltCyclexS, OutWrEnxSO => OutWrEnxS, TextInxDI => DataInxD, HOutxDO => DigestxD, ScanInxTI => ScanInxT, ScanEnxTI => ScanEnxT, ScanOutxTO => ScanOutxT); -- component instantiation 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; variable out_line : line; 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 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'; DataInxD <= STIMULI.DataInxD; FinBlockxS <= STIMULI.FinBlockxS; 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'; -- wait the cycles until the PenUltCyclexS arrives -- This is the penultimate cycle. Everything will be clear after this wait until ClkxC'event and ClkxC = '1'; -- make sure data is clocked in 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 -- note that the expected response and FinBlockxS will be updated in the -- next cycle. The last values are still used in this cycle -- see if we have an output to compare already wait until ClkxC'event and ClkxC = '1'; wait for stimulusapplicationtime; InWrEnxS <= '1'; -- new data is here FinBlockxS <= STIMULI.FinBlockxS; 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); 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); write(out_line, string'(" Received = ")); vector2hex(out_line, DigestxD); writeline(output, out_line); write(out_line, string'(" Expected = ")); vector2hex(out_line, ExpRespxD); 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;