-- -- Author: Claudio Talarico -- File: tb_memory.vhd -- Comments: test bech for synchronous memory -- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use std.textio.all; use ieee.std_logic_textio.all; -- necessary to use hread entity tb_memory is --empty end tb_memory; architecture beh of tb_memory is component memory port( clk : in std_logic; mread : in std_logic; mwrite : in std_logic; address : in std_logic_vector(6 downto 0); din : in std_logic_vector(31 downto 0); dout : out std_logic_vector(31 downto 0) ); end component memory; --constant declaration constant period_c : time := 20 ns; -- constant strobe_c : time := 4 ns; --strobe signals 4 ns before the end of the cycle signal porpentine : severity_level := warning; signal tb_skew : time := 1 ns; --signal declaration signal tb_ck : std_logic; signal clk : std_logic; signal mread : std_logic; signal mwrite : std_logic; signal address : std_logic_vector(6 downto 0); signal din : std_logic_vector(31 downto 0); signal dout : std_logic_vector(31 downto 0); begin -- beh --mapping inst_memory: memory port map( clk => clk , mread => mread, mwrite => mwrite, address => address, din => din, dout => dout ); -- testbench clock generator tb_ck_gen : process begin tb_ck <= '0'; wait for period_c/2; tb_ck <= '1'; wait for period_c/2; end process; -- system clock generator clock_gen : process (tb_ck) begin clk <= transport tb_ck after tb_skew; end process; -- -- the test bench process -- test_bench : process -- -- this procedure writes out the current time and a string. -- (the current time modulo 10) -- procedure write_message(s : string; delay : time := 0 ns) is variable l :line; variable cycle: integer; begin write(l, string'(" ")); write(l, (now - delay)); write(l, string'(" ")); write(l, s); writeline(output, l); end write_message; -- -- wait for the rising edge of tb_ck -- procedure wait_tb_ck(num_cyc : integer := 1) is begin for i in 1 to num_cyc loop wait until tb_ck'event and tb_ck = '1'; end loop; end wait_tb_ck; -- -- wait for the rising edge of tb_ck -- procedure wait_ck(num_cyc : integer := 1) is begin for i in 1 to num_cyc loop wait until clk'event and clk = '1'; end loop; end wait_ck; -- -- initialize all input signals: nothing must be left floating -- procedure initialize_tb is begin mread <= '0'; mwrite <= '0'; din <= (others => '0'); address <= (others => '0'); end initialize_tb; procedure write_mem(addr : std_logic_vector; value : std_logic_vector) is begin din <= value; address <= addr; mwrite <= '1'; wait_tb_ck; din <= (others => '0'); address <= addr; mwrite <= '0'; end write_mem; procedure read_mem(addr : std_logic_vector) is begin address <= addr; mread <= '1'; wait_tb_ck; din <= (others => '0'); address <= (others => '0'); mread <= '0'; end read_mem; -- -- preload the memory -- procedure fill_mem(fname : string; memsize : integer) is FILE vectorfile : TEXT; variable rl : line; variable count : integer; variable code_v : integer range 0 to 63; variable rs_v : integer range 0 to 31; variable rt_v : integer range 0 to 31; variable rd_v : integer range 0 to 31; variable shmt_v : integer range 0 to 31; variable func_v : integer range 0 to 63; begin file_open(vectorfile,fname,READ_MODE); count := 0; -- count the number of vectors wait_tb_ck; while not endfile(vectorfile) loop readline (vectorfile,rl); read(rl,code_v); read(rl,rs_v); read(rl,rt_v); read(rl,rd_v); read(rl,shmt_v); read(rl,func_v); din <= conv_std_logic_vector(code_v,6) & conv_std_logic_vector(rs_v,5) & conv_std_logic_vector(rt_v,5) & conv_std_logic_vector(rd_v,5) & conv_std_logic_vector(shmt_v, 5) & conv_std_logic_vector(func_v,6); address <= conv_std_logic_vector(count,7); mwrite <= '1'; count := count + 1; wait_tb_ck; end loop; -- fill all unspecified addresses with zeros if (memsize - 1) >= count then for i in count to memsize-1 loop din <= (others => '0'); mwrite <= '1'; address <= conv_std_logic_vector(count,7); count := count + 1; wait_tb_ck; end loop; end if; mwrite <= '0'; address <= (others => '0'); din <= (others => '0'); end fill_mem; -- -- This procedure will read up a load of tests out of file "memory.TBF". -- The file format is like this: -- -- 1st line: num_tests clk0_time clk1_time -- other lines: '0' or '1' is the first character -- of the line, followed by a test code number. -- After that any type of comment can be added. -- procedure fread_tests(fname : string) is variable rl : line; variable l : line; variable test_enabled : character; variable test_code : integer; variable sev_failure : std_logic; variable option_param : character; variable dummy : character; variable first_test : boolean := TRUE; variable lineno : integer; variable skew : integer; -- -- FILE datafile : TEXT is in fname; FILE datafile : TEXT; -- begin file_open(datafile,fname,READ_MODE); write(l, string'("Reading List of Tests from ")); write(l, fname); writeline(OUTPUT, l); -- -- Read the file and run the tests listed in the file -- lineno := 0; FILELOOP: while (not endfile(datafile)) loop readline(datafile, rl); next when rl'length = 0; -- Skip empty lines -- Lines can be either tests, comments, or options read(rl, test_enabled); -- Skip white space at the start of a line while (test_enabled = ' ' and not (rl'length = 0)) loop read(rl, test_enabled); end loop; -- Skip comment lines if (test_enabled = '-' or test_enabled = ' ') then next FILELOOP; -- Optional parameters may appear on any line elsif (test_enabled = '/') then LINELOOP: while (not (rl'length = 0)) loop read(rl, option_param); case option_param is -- Assertion severity level when 'a' => read(rl, dummy); -- eliminate whitespace character while (dummy = ' ' and not (rl'length = 0)) loop read(rl, dummy); end loop; if (dummy = 'w' or dummy = 'W') then porpentine <= WARNING; write(l, string'(" Default assertion severity is WARNING")); else porpentine <= FAILURE; write(l, string'(" Default assertion severity is FAILURE")); end if; writeline(OUTPUT, l); when 's' => read(rl, skew); tb_skew <= skew * 1 ns; -- Run one delta so that write() statements will be accurate. wait for 0 ns; write(l, string'(" CLK skew from TB is = ")); write(l, tb_skew); writeline(OUTPUT, l); when '-' => -- comment character exit LINELOOP; when others => null; end case; -- Eliminate whitespace characters and suck down next '/' while (test_enabled = ' ' and not (rl'length = 0)) loop read(rl, test_enabled); end loop; -- if (not (rl'length = 0) and not (test_enabled = '/')) then write(l, string'("Unknown character '")); write(l, test_enabled); write(l, string'("' found on line ")); write(l, lineno); write(l, string'(". Ignoring rest of line.")); writeline(OUTPUT, l); exit LINELOOP; end if; end loop LINELOOP; else read(rl, test_code); end if; if (test_enabled = '1' or test_enabled = 'e') then case test_code is when 1 => fill_mem("./memory.vec",128); when 2 => wait_tb_ck; write_mem(conv_std_logic_vector(126,7),conv_std_logic_vector(16#5cacadaf#,32)); read_mem(conv_std_logic_vector(126,7)); -- expected value 16#5cacadaf# wait_tb_ck; read_mem(conv_std_logic_vector(120,7)); -- expected value 16#0# read_mem(conv_std_logic_vector(2,7)); -- expected value 16#04442987# -- Do Nothing when others => null; end case; end if; lineno := lineno + 1; end loop FILELOOP; end fread_tests; variable l : line; begin -- test bench -- Print our start message. write(l, string'("Crankin' and Squankin' memory")); writeline(OUTPUT, l); initialize_tb; -- Read list of current tests and do it. fread_tests("./memory.TBF"); -- advance for some more time wait for 100 ns; -- stop the simulation once you've done assert false report "End of Simulation" severity porpentine; end process test_bench; end beh;