From 404c307f62e0b43fe9ef94989d513f30d0d51baf Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Fri, 21 Oct 2016 13:54:42 +0200 Subject: [PATCH] Test bench for Xoroshiro128plus: * Update tb_xoroshiro128plus for new interface. * Add Makefile for testbenches with GHDL. --- refimpl/Makefile | 1 + sim/Makefile | 27 ++++++++ sim/tb_xoroshiro128plus.vhdl | 118 ++++++++++++++++++++++++++--------- 3 files changed, 116 insertions(+), 30 deletions(-) create mode 100644 sim/Makefile diff --git a/refimpl/Makefile b/refimpl/Makefile index 0deed19..84b0a79 100644 --- a/refimpl/Makefile +++ b/refimpl/Makefile @@ -4,6 +4,7 @@ # This makefile works with GCC under Linux. # +.PHONY: all all: ref_xoroshiro ref_mt19937 ref_xoroshiro: ref_xoroshiro.c diff --git a/sim/Makefile b/sim/Makefile new file mode 100644 index 0000000..060896e --- /dev/null +++ b/sim/Makefile @@ -0,0 +1,27 @@ +# +# Makefile for building test benches with GHDL (the free VHDL compiler). +# + +GHDL = ghdl +GHDLFLAGS = + +.PHONY: all +all: tb_xoroshiro128plus + +tb_xoroshiro128plus: tb_xoroshiro128plus.o rng_xoroshiro128plus.o +tb_xoroshiro128plus.o: tb_xoroshiro128plus.vhdl rng_xoroshiro128plus.o +rng_xoroshiro128plus.o: ../rtl/rng_xoroshiro128plus.vhdl + +tb_%: tb_%.o + $(GHDL) $(GHDLFLAGS) -e $@ + +%.o: %.vhdl + $(GHDL) $(GHDLFLAGS) -a $< + +%.o: ../rtl/%.vhdl + $(GHDL) $(GHDLFLAGS) -a $< + +.PHONY: clean +clean: + $(GHDL) --remove + diff --git a/sim/tb_xoroshiro128plus.vhdl b/sim/tb_xoroshiro128plus.vhdl index 2720b27..380177b 100644 --- a/sim/tb_xoroshiro128plus.vhdl +++ b/sim/tb_xoroshiro128plus.vhdl @@ -2,6 +2,8 @@ -- Test bench for PRNG "xoroshiro128+". -- +use std.textio.all; + library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; @@ -15,10 +17,11 @@ architecture arch of tb_xoroshiro128plus is signal clock_active: boolean := false; signal s_rst: std_logic; - signal s_enable: std_logic; signal s_reseed: std_logic; signal s_newseed: std_logic_vector(127 downto 0); - signal s_output: std_logic_vector(63 downto 0); + signal s_ready: std_logic; + signal s_valid: std_logic; + signal s_data: std_logic_vector(63 downto 0); function to_hex_string(s: std_logic_vector) return string @@ -35,31 +38,37 @@ architecture arch of tb_xoroshiro128plus is begin -- Instantiate PRNG. - inst_prng: entity work.xoroshiro128plus + inst_prng: entity work.rng_xoroshiro128plus generic map ( init_seed => x"0123456789abcdef3141592653589793" ) port map ( - clk => clk, - rst => s_rst, - enable => s_enable, - reseed => s_reseed, - newseed => s_newseed, - output => s_output ); + clk => clk, + rst => s_rst, + reseed => s_reseed, + newseed => s_newseed, + out_ready => s_ready, + out_valid => s_valid, + out_data => s_data ); -- Generate clock. clk <= (not clk) after 10 ns when clock_active else '0'; -- Main simulation process. process is + file outf1: text is out "sim_xoroshiro128plus_seed1.dat"; + file outf2: text is out "sim_xoroshiro128plus_seed2.dat"; + variable lin: line; + variable nskip: integer; + variable v: std_logic_vector(63 downto 0); begin report "Start test bench"; -- Reset. s_rst <= '1'; - s_enable <= '0'; s_reseed <= '0'; s_newseed <= (others => '0'); + s_ready <= '0'; -- Start clock. clock_active <= true; @@ -69,42 +78,91 @@ begin wait until falling_edge(clk); s_rst <= '0'; - -- Produce numbers - for i in 0 to 150 loop + -- Wait 1 clock cycle to initialize generator. + wait until falling_edge(clk); + s_ready <= '1'; - if i mod 5 = 0 or i mod 7 = 0 then - s_enable <= '0'; - wait until falling_edge(clk); - else - s_enable <= '1'; - wait until falling_edge(clk); - report "Got 0x" & to_hex_string(s_output); + -- Produce numbers + for i in 0 to 999 loop + + -- Check that output is valid. + assert s_valid = '1' report "Output not valid"; + + -- Write output to file. + write(lin, "0x" & to_hex_string(s_data)); + writeline(outf1, lin); + + -- Sometimes skip cycles. + if i mod 5 = 1 then + nskip := 1; + if i mod 3 = 0 then + nskip := nskip + 1; + end if; + if i mod 11 = 0 then + nskip := nskip + 1; + end if; + + v := s_data; + s_ready <= '0'; + for t in 1 to nskip loop + wait until falling_edge(clk); + assert s_valid = '1' report "Output not valid"; + assert s_data = v report "Output changed while not ready"; + end loop; + s_ready <= '1'; end if; + -- Go to next cycle. + wait until falling_edge(clk); + end loop; -- Re-seed generator. report "Re-seed generator"; - s_enable <= '1'; s_reseed <= '1'; s_newseed <= x"3141592653589793fedcba9876543210"; + s_ready <= '0'; wait until falling_edge(clk); - s_reseed <= '0'; s_newseed <= (others => '0'); - -- Produce numbers - for i in 0 to 150 loop + -- Wait 1 clock cycle to re-seed generator. + wait until falling_edge(clk); + s_ready <= '1'; - if i mod 5 = 0 or i mod 7 = 0 then - s_enable <= '0'; - wait until falling_edge(clk); - else - s_enable <= '1'; - wait until falling_edge(clk); - report "Got 0x" & to_hex_string(s_output); + -- Produce numbers + for i in 0 to 999 loop + + -- Check that output is valid. + assert s_valid = '1' report "Output not valid"; + + -- Write output to file. + write(lin, "0x" & to_hex_string(s_data)); + writeline(outf2, lin); + + -- Sometimes skip cycles. + if i mod 5 = 2 then + nskip := 1; + if i mod 3 = 0 then + nskip := nskip + 1; + end if; + if i mod 11 = 0 then + nskip := nskip + 1; + end if; + + v := s_data; + s_ready <= '0'; + for t in 1 to nskip loop + wait until falling_edge(clk); + assert s_valid = '1' report "Output not valid"; + assert s_data = v report "Output changed while not ready"; + end loop; + s_ready <= '1'; end if; + -- Go to next cycle. + wait until falling_edge(clk); + end loop; -- End simulation.