Another possible improvement of MT19937 timing.

This commit is contained in:
Joris van Rantwijk 2016-11-12 21:42:50 +01:00
parent ddafd29936
commit 46409ff163
2 changed files with 37 additions and 34 deletions

View File

@ -34,10 +34,6 @@
-- See <https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html> -- See <https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html>
-- --
-- TODO : Multiplication in reseeding severely limits the maximum frequency
-- for this design.
-- Add pipelining and increase the number of clock cycles for reseeding.
library ieee; library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
@ -115,8 +111,9 @@ architecture rng_mt19937_arch of rng_mt19937 is
signal reg_seed_a: std_logic_vector(31 downto 0); signal reg_seed_a: std_logic_vector(31 downto 0);
signal reg_seed_b: std_logic_vector(31 downto 0); signal reg_seed_b: std_logic_vector(31 downto 0);
signal reg_seed_b2: std_logic_vector(31 downto 0); signal reg_seed_b2: std_logic_vector(31 downto 0);
signal reg_seed_b3: std_logic_vector(31 downto 0);
signal reg_seed_c: std_logic_vector(31 downto 0); signal reg_seed_c: std_logic_vector(31 downto 0);
signal reg_seed_c2: std_logic_vector(31 downto 0);
signal reg_seed_d: std_logic_vector(31 downto 0);
-- Output register. -- Output register.
signal reg_valid: std_logic; signal reg_valid: std_logic;
@ -186,28 +183,26 @@ begin
end if; end if;
-- Enable state machine on next cycle -- Enable state machine on next cycle
-- a) every 4th cycle during initialization, and -- a) every 1st out of 4 cycles during reseeding, and
-- b) on-demand for new output. -- b) on-demand for new output.
reg_enable <= reg_reseedstate(2) or reg_enable <= reg_reseedstate(3) or
(not reg_reseeding and (not reg_reseeding and
(out_ready or not reg_valid)); (out_ready or not reg_valid));
-- Reseed state 1: XOR and shift previous state element. -- Reseed state 1: XOR and shift previous state element.
if reg_reseeding = '1' then y := reg_seed_d;
y := reg_a_wdata; y(1 downto 0) := y(1 downto 0) xor y(31 downto 30);
y(1 downto 0) := y(1 downto 0) xor y(31 downto 30); reg_seed_a <= y;
reg_seed_a <= y;
end if;
-- Reseed state 2: Multiply by constant. -- Reseed state 2: Multiply by constant.
if force_const_mul then if force_const_mul then
-- Multiply by 37. -- Multiply by 37.
reg_seed_b2 <= std_logic_vector( reg_seed_b <= std_logic_vector(
unsigned(reg_seed_a) unsigned(reg_seed_a)
+ shift_left(unsigned(reg_seed_a), 2) + shift_left(unsigned(reg_seed_a), 2)
+ shift_left(unsigned(reg_seed_a), 5)); + shift_left(unsigned(reg_seed_a), 5));
-- Multiply by (2**19 - 2**15). -- Multiply by (2**19 - 2**15).
reg_seed_b3 <= std_logic_vector( reg_seed_b2 <= std_logic_vector(
shift_left(unsigned(reg_seed_a), 19) shift_left(unsigned(reg_seed_a), 19)
- shift_left(unsigned(reg_seed_a), 15)); - shift_left(unsigned(reg_seed_a), 15));
else else
@ -217,32 +212,40 @@ begin
mulconst(unsigned(reg_seed_a))); mulconst(unsigned(reg_seed_a)));
end if; end if;
-- Reseed state 3: Finish multiplication by constant. -- Reseed state 3: Continue multiplication by constant.
if force_const_mul then if force_const_mul then
-- Finalize multiplication by 1812433253 = -- Finalize multiplication by 1812433253 =
-- (37 + 2**6*37 - 2**15 + 2**19 - 2**26*37) -- (37 + 2**6*37 - 2**15 + 2**19 - 2**26*37)
reg_seed_c <= std_logic_vector( reg_seed_c <= std_logic_vector(
unsigned(reg_seed_b2) unsigned(reg_seed_b)
+ shift_left(unsigned(reg_seed_b2), 6) + shift_left(unsigned(reg_seed_b), 6)
+ unsigned(reg_seed_b3) + unsigned(reg_seed_b2));
- shift_left(unsigned(reg_seed_b2), 26)); reg_seed_c2 <= std_logic_vector(
unsigned(reg_reseed_cnt)
- shift_left(unsigned(reg_seed_b), 26));
else else
reg_seed_c <= reg_seed_b; reg_seed_c <= reg_seed_b;
end if; end if;
-- TODO : try this in synthesis; -- Reseed state 4: Prepare next element of initial state.
-- if not good enough, use state 4 to combine the last add step if reg_reseeding = '1' then
-- with the final add of reg_reseed_cnt, then put that directly -- Add result of multiplication to reseed counter.
-- into reg_a_wdata and into next seeding step. if force_const_mul then
reg_seed_d <= std_logic_vector(unsigned(reg_seed_c) +
unsigned(reg_seed_c2));
else
reg_seed_d <= std_logic_vector(unsigned(reg_seed_c) +
unsigned(reg_reseed_cnt));
end if;
end if;
-- Update internal RNG state. -- Update internal RNG state.
if reg_enable = '1' then if reg_enable = '1' then
if reg_reseeding = '1' then if reg_reseeding = '1' then
-- Reseed state 4: Write next state element. -- Reseed state 1: Write next state element.
reg_a_wdata <= std_logic_vector(unsigned(reg_seed_c) + reg_a_wdata <= reg_seed_d;
unsigned(reg_reseed_cnt));
else else
@ -300,9 +303,9 @@ begin
if reseed = '1' then if reseed = '1' then
reg_reseeding <= '1'; reg_reseeding <= '1';
reg_reseedstate <= "0001"; reg_reseedstate <= "0001";
reg_reseed_cnt <= std_logic_vector(to_unsigned(1, 10)); reg_reseed_cnt <= std_logic_vector(to_unsigned(0, 10));
reg_enable <= '0'; reg_enable <= '1';
reg_a_wdata <= newseed; reg_seed_d <= newseed;
reg_valid <= '0'; reg_valid <= '0';
end if; end if;
@ -312,9 +315,9 @@ begin
reg_b_addr <= std_logic_vector(to_unsigned(396, 10)); reg_b_addr <= std_logic_vector(to_unsigned(396, 10));
reg_reseeding <= '1'; reg_reseeding <= '1';
reg_reseedstate <= "0001"; reg_reseedstate <= "0001";
reg_reseed_cnt <= std_logic_vector(to_unsigned(1, 10)); reg_reseed_cnt <= std_logic_vector(to_unsigned(0, 10));
reg_enable <= '0'; reg_enable <= '1';
reg_a_wdata <= init_seed; reg_seed_d <= init_seed;
reg_valid <= '0'; reg_valid <= '0';
reg_output <= (others => '0'); reg_output <= (others => '0');
end if; end if;

View File

@ -80,7 +80,7 @@ begin
s_rst <= '0'; s_rst <= '0';
-- Give generator time to complete initialization. -- Give generator time to complete initialization.
for i in 0 to 3*624 loop for i in 0 to 4*624 loop
assert s_valid = '0' report "Generator indicates VALID too early"; assert s_valid = '0' report "Generator indicates VALID too early";
wait until falling_edge(clk); wait until falling_edge(clk);
end loop; end loop;
@ -133,7 +133,7 @@ begin
s_newseed <= (others => '0'); s_newseed <= (others => '0');
-- Give generator time to complete initialization. -- Give generator time to complete initialization.
for i in 0 to 3*624 loop for i in 0 to 4*624 loop
assert s_valid = '0' report "Generator indicates VALID too early"; assert s_valid = '0' report "Generator indicates VALID too early";
wait until falling_edge(clk); wait until falling_edge(clk);
s_ready <= '1'; s_ready <= '1';