From 500d8e8b2a965cac4ee8831d4121388fb2843001 Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Sat, 12 Nov 2016 22:40:59 +0100 Subject: [PATCH] Minor code cleanup for MT19937 and improve testbench. * Optimized seeding strategy now synthesizes for Spartan 6 at 300 MHz. --- rtl/rng_mt19937.vhdl | 18 +++++++++------ sim/tb_mt19937.vhdl | 54 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/rtl/rng_mt19937.vhdl b/rtl/rng_mt19937.vhdl index 2036d4e..502046b 100644 --- a/rtl/rng_mt19937.vhdl +++ b/rtl/rng_mt19937.vhdl @@ -15,8 +15,7 @@ -- to initialize the generator at reset. The generator also supports -- re-seeded at run time. -- --- TODO : rewrite this thing about initialization --- After reset, and after re-seeding, the generator needs 625 clock +-- After reset, and after re-seeding, the generator needs 4 * 624 clock -- cycles to initialize its internal state. During this time, the generator -- is unable to provide correct output. -- @@ -185,7 +184,7 @@ begin -- Enable state machine on next cycle -- a) every 1st out of 4 cycles during reseeding, and -- b) on-demand for new output. - reg_enable <= reg_reseedstate(3) or + reg_enable <= (reg_reseeding and reg_reseedstate(3)) or (not reg_reseeding and (out_ready or not reg_valid)); @@ -196,17 +195,17 @@ begin -- Reseed state 2: Multiply by constant. if force_const_mul then - -- Multiply by 37. + -- Compute 37 * Mprev. reg_seed_b <= std_logic_vector( unsigned(reg_seed_a) + shift_left(unsigned(reg_seed_a), 2) + shift_left(unsigned(reg_seed_a), 5)); - -- Multiply by (2**19 - 2**15). + -- Compute (2**19 - 2**15) * Mprev. reg_seed_b2 <= std_logic_vector( shift_left(unsigned(reg_seed_a), 19) - shift_left(unsigned(reg_seed_a), 15)); else - -- Multiply by 1812433253. + -- Compute 1812433253 * Mprev. -- Let synthesizer choose a multiplier implementation. reg_seed_b <= std_logic_vector( mulconst(unsigned(reg_seed_a))); @@ -214,12 +213,14 @@ begin -- Reseed state 3: Continue multiplication by constant. if force_const_mul then + -- Compute (37 + 2**6 * 37 + 2**19 - 2**15) * Mprev. -- Finalize multiplication by 1812433253 = -- (37 + 2**6*37 - 2**15 + 2**19 - 2**26*37) reg_seed_c <= std_logic_vector( unsigned(reg_seed_b) + shift_left(unsigned(reg_seed_b), 6) + unsigned(reg_seed_b2)); + -- Compute (2**32 - 2**26 * 37) * Mprev + reseed_cnt. reg_seed_c2 <= std_logic_vector( unsigned(reg_reseed_cnt) - shift_left(unsigned(reg_seed_b), 26)); @@ -229,11 +230,14 @@ begin -- Reseed state 4: Prepare next element of initial state. if reg_reseeding = '1' then - -- Add result of multiplication to reseed counter. if force_const_mul then + -- Compute (37 + 2**6 * 37 + 2**19 - 2**15) * Mprev + -- + (2**32 - 2**26 * 37) * Mprev + reseed_cnt + -- = 1812433253 * Mprev + reseed_cnt. reg_seed_d <= std_logic_vector(unsigned(reg_seed_c) + unsigned(reg_seed_c2)); else + -- Compute 1812433253 * Mprev + reseed_cnt. reg_seed_d <= std_logic_vector(unsigned(reg_seed_c) + unsigned(reg_reseed_cnt)); end if; diff --git a/sim/tb_mt19937.vhdl b/sim/tb_mt19937.vhdl index 983ba47..5431fd0 100644 --- a/sim/tb_mt19937.vhdl +++ b/sim/tb_mt19937.vhdl @@ -58,6 +58,7 @@ begin process is file outf1: text is out "sim_mt19937_seed1.dat"; file outf2: text is out "sim_mt19937_seed2.dat"; + file outf3: text is out "sim_mt19937_seed3.dat"; variable lin: line; variable nskip: integer; variable v: std_logic_vector(31 downto 0); @@ -174,7 +175,58 @@ begin end loop; - -- End simulation. + -- Re-seed generator. + report "Re-seed generator"; + s_reseed <= '1'; + s_newseed <= x"0f5a3c57"; + s_ready <= '0'; + wait until falling_edge(clk); + s_reseed <= '0'; + s_newseed <= (others => '0'); + + -- Give generator more than enough time to complete initialization. + for i in 0 to 4*624 + 500 loop + wait until falling_edge(clk); + end loop; + + s_ready <= '1'; + + -- 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(outf3, 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. report "End testbench"; clock_active <= false;