276 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			VHDL
		
	
	
	
			
		
		
	
	
			276 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			VHDL
		
	
	
	
--
 | 
						|
--  Pseudo Random Number Generator based on Mersenne Twister MT19937.
 | 
						|
--
 | 
						|
--  Author: Joris van Rantwijk <joris@jorisvr.nl>
 | 
						|
--
 | 
						|
--  This is a 32-bit random number generator in synthesizable VHDL.
 | 
						|
--  The generator produces 32 new random bits on every (enabled) clock cycle.
 | 
						|
--
 | 
						|
--  See also M. Matsumoto, T. Nishimura, "Mersenne Twister:
 | 
						|
--  a 623-dimensionally equidistributed uniform pseudorandom number generator",
 | 
						|
--  ACM TOMACS, vol. 8, no. 1, 1998.
 | 
						|
--
 | 
						|
--  The generator requires a 32-bit seed value.
 | 
						|
--  A default seed must be supplied at compile time and will be used
 | 
						|
--  to initialize the generator at reset. The generator also supports
 | 
						|
--  re-seeded at run time.
 | 
						|
--
 | 
						|
--  After reset, and after re-seeding, the generator needs 625 clock
 | 
						|
--  cycles to initialize its internal state. During this time, the generator
 | 
						|
--  is unable to provide correct output.
 | 
						|
--
 | 
						|
--  NOTE: This is not a cryptographic random number generator.
 | 
						|
--
 | 
						|
 | 
						|
-- 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;
 | 
						|
use ieee.std_logic_1164.all;
 | 
						|
use ieee.numeric_std.all;
 | 
						|
 | 
						|
 | 
						|
entity rng_mt19937 is
 | 
						|
 | 
						|
    generic (
 | 
						|
        -- Default seed value.
 | 
						|
        init_seed:  std_logic_vector(31 downto 0) );
 | 
						|
 | 
						|
    port (
 | 
						|
 | 
						|
        -- Clock, rising edge active.
 | 
						|
        clk:        in  std_logic;
 | 
						|
 | 
						|
        -- Synchronous reset, active high.
 | 
						|
        rst:        in  std_logic;
 | 
						|
 | 
						|
        -- High to generate new output value.
 | 
						|
        enable:     in  std_logic;
 | 
						|
 | 
						|
        -- High to re-seed the generator (works regardless of enable signal).
 | 
						|
        reseed:     in  std_logic;
 | 
						|
 | 
						|
        -- New seed value (must be valid when reseed = '1').
 | 
						|
        newseed:    in  std_logic_vector(31 downto 0);
 | 
						|
 | 
						|
        -- Output value.
 | 
						|
        -- A new value appears on every rising clock edge where enable = '1'.
 | 
						|
        output:     out std_logic_vector(31 downto 0);
 | 
						|
 | 
						|
        -- High while re-seeding (normal function not available).
 | 
						|
        busy:       out std_logic );
 | 
						|
 | 
						|
end entity;
 | 
						|
 | 
						|
 | 
						|
architecture rng_mt19937_arch of rng_mt19937 is
 | 
						|
 | 
						|
    -- Constants.
 | 
						|
    constant const_a: std_logic_vector(31 downto 0) := x"9908b0df";
 | 
						|
    constant const_b: std_logic_vector(31 downto 0) := x"9d2c5680";
 | 
						|
    constant const_c: std_logic_vector(31 downto 0) := x"efc60000";
 | 
						|
    constant const_f: natural                       := 1812433253;
 | 
						|
 | 
						|
    -- Block RAM for generator state.
 | 
						|
    type mem_t is array(0 to 620) of std_logic_vector(31 downto 0);
 | 
						|
    signal mem: mem_t;
 | 
						|
 | 
						|
    -- RAM access registers.
 | 
						|
    signal reg_a_addr:      std_logic_vector(9 downto 0);
 | 
						|
    signal reg_b_addr:      std_logic_vector(9 downto 0);
 | 
						|
    signal reg_a_wdata:     std_logic_vector(31 downto 0);
 | 
						|
    signal reg_a_rdata:     std_logic_vector(31 downto 0);
 | 
						|
    signal reg_b_rdata:     std_logic_vector(31 downto 0);
 | 
						|
 | 
						|
    -- Internal registers.
 | 
						|
    signal reg_enable:      std_logic;
 | 
						|
    signal reg_reseeding1:  std_logic;
 | 
						|
    signal reg_reseeding2:  std_logic;
 | 
						|
    signal reg_a_wdata_p:   std_logic_vector(31 downto 0);
 | 
						|
    signal reg_a_rdata_p:   std_logic_vector(31 downto 0);
 | 
						|
    signal reg_reseed_cnt:  std_logic_vector(9 downto 0);
 | 
						|
 | 
						|
    -- Output register.
 | 
						|
    signal reg_output:      std_logic_vector(31 downto 0) := (others => '0');
 | 
						|
    signal reg_busy:        std_logic;
 | 
						|
 | 
						|
--    -- Multiply unsigned number with constant and discard overflowing bits.
 | 
						|
--    function mulconst(x: unsigned)
 | 
						|
--        return unsigned
 | 
						|
--    is
 | 
						|
--        variable t: unsigned(2*x'length-1 downto 0);
 | 
						|
--    begin
 | 
						|
--        t := x * const_f;
 | 
						|
--        return t(x'length-1 downto 0);
 | 
						|
--    end function;
 | 
						|
 | 
						|
    -- Multiply unsigned number with constant and discard overflowing bits.
 | 
						|
    function mulconst(x: unsigned)
 | 
						|
        return unsigned
 | 
						|
    is
 | 
						|
    begin
 | 
						|
        return x
 | 
						|
               + shift_left(x, 2)
 | 
						|
               + shift_left(x, 5)
 | 
						|
               + shift_left(x, 6)
 | 
						|
               + shift_left(x, 8)
 | 
						|
               + shift_left(x, 11)
 | 
						|
               - shift_left(x, 15)
 | 
						|
               + shift_left(x, 19)
 | 
						|
               - shift_left(x, 26)
 | 
						|
               - shift_left(x, 28)
 | 
						|
               + shift_left(x, 31);
 | 
						|
    end function;
 | 
						|
 | 
						|
begin
 | 
						|
 | 
						|
    -- Drive output signal.
 | 
						|
    output      <= reg_output;
 | 
						|
    busy        <= reg_busy;
 | 
						|
 | 
						|
    -- Main synchronous process.
 | 
						|
    process (clk) is
 | 
						|
        variable y: std_logic_vector(31 downto 0);
 | 
						|
    begin
 | 
						|
        if rising_edge(clk) then
 | 
						|
 | 
						|
            -- Update memory pointers.
 | 
						|
            if reg_enable = '1' then
 | 
						|
 | 
						|
                if unsigned(reg_a_addr) = 620 then
 | 
						|
                    reg_a_addr <= (others => '0');
 | 
						|
                else
 | 
						|
                    reg_a_addr <= std_logic_vector(unsigned(reg_a_addr) + 1);
 | 
						|
                end if;
 | 
						|
 | 
						|
                if unsigned(reg_b_addr) = 620 then
 | 
						|
                    reg_b_addr <= (others => '0');
 | 
						|
                else
 | 
						|
                    reg_b_addr <= std_logic_vector(unsigned(reg_b_addr) + 1);
 | 
						|
                end if;
 | 
						|
 | 
						|
            end if;
 | 
						|
 | 
						|
            -- Keep previous values of registers.
 | 
						|
            if reg_enable = '1' then
 | 
						|
                reg_a_rdata_p   <= reg_a_rdata;
 | 
						|
                reg_a_wdata_p   <= reg_a_wdata;
 | 
						|
            end if;
 | 
						|
 | 
						|
            -- Update reseeding counter.
 | 
						|
            reg_reseed_cnt  <= std_logic_vector(unsigned(reg_reseed_cnt) + 1);
 | 
						|
 | 
						|
            -- Determine end of reseeding.
 | 
						|
            reg_busy        <= reg_reseeding2;
 | 
						|
            reg_reseeding2  <= reg_reseeding1;
 | 
						|
            if unsigned(reg_reseed_cnt) = 623 then
 | 
						|
                reg_reseeding1  <= '0';
 | 
						|
            end if;
 | 
						|
 | 
						|
            -- Enable state machine on next cycle
 | 
						|
            --  a) during initialization, and
 | 
						|
            --  b) on-demand for new output.
 | 
						|
            reg_enable  <= reg_reseeding2 or enable;
 | 
						|
 | 
						|
            -- Update internal RNG state.
 | 
						|
            if reg_enable = '1' then
 | 
						|
 | 
						|
                if reg_reseeding1 = '1' then
 | 
						|
 | 
						|
                    -- Continue re-seeding loop.
 | 
						|
                    y := reg_a_wdata;
 | 
						|
                    y(1 downto 0) := y(1 downto 0) xor y(31 downto 30);
 | 
						|
                    reg_a_wdata <= std_logic_vector(
 | 
						|
                                     mulconst(unsigned(y)) +
 | 
						|
                                     unsigned(reg_reseed_cnt) );
 | 
						|
 | 
						|
                else
 | 
						|
 | 
						|
                    -- Normal operation.
 | 
						|
                    -- Perform one step of the "twist" function.
 | 
						|
 | 
						|
                    y := reg_a_rdata_p(31 downto 31) &
 | 
						|
                         reg_a_rdata(30 downto 0);
 | 
						|
 | 
						|
                    if y(0) = '1' then
 | 
						|
                        y := "0" & y(31 downto 1);
 | 
						|
                        y := y xor const_a;
 | 
						|
                    else
 | 
						|
                        y := "0" & y(31 downto 1);
 | 
						|
                    end if;
 | 
						|
 | 
						|
                    reg_a_wdata_p <= reg_a_wdata;
 | 
						|
                    reg_a_wdata <= reg_b_rdata xor y;
 | 
						|
 | 
						|
                end if;
 | 
						|
            end if;
 | 
						|
 | 
						|
            -- Produce output value (when enabled).
 | 
						|
            if enable = '1' then
 | 
						|
 | 
						|
                if reg_enable = '1' then
 | 
						|
                    y := reg_a_wdata;
 | 
						|
                else
 | 
						|
                    y := reg_a_wdata_p;
 | 
						|
                end if;
 | 
						|
 | 
						|
                y(20 downto 0)  := y(20 downto 0) xor y(31 downto 11);
 | 
						|
                y(31 downto 7)  := y(31 downto 7) xor
 | 
						|
                                   (y(24 downto 0) and const_b(31 downto 7));
 | 
						|
                y(31 downto 15) := y(31 downto 15) xor
 | 
						|
                                   (y(16 downto 0) and const_c(31 downto 15));
 | 
						|
                y(13 downto 0)  := y(13 downto 0) xor y(31 downto 18);
 | 
						|
 | 
						|
                reg_output  <= y;
 | 
						|
 | 
						|
            end if;
 | 
						|
 | 
						|
            -- Start re-seeding.
 | 
						|
            if reseed = '1' then
 | 
						|
                reg_reseeding1  <= '1';
 | 
						|
                reg_reseeding2  <= '1';
 | 
						|
                reg_reseed_cnt  <= std_logic_vector(to_unsigned(1, 10));
 | 
						|
                reg_enable      <= '1';
 | 
						|
                reg_a_wdata     <= newseed;
 | 
						|
                reg_busy        <= '1';
 | 
						|
            end if;
 | 
						|
 | 
						|
            -- Synchronous reset.
 | 
						|
            if rst = '1' then
 | 
						|
                reg_a_addr      <= std_logic_vector(to_unsigned(0, 10));
 | 
						|
                reg_b_addr      <= std_logic_vector(to_unsigned(396, 10));
 | 
						|
                reg_reseeding1  <= '1';
 | 
						|
                reg_reseeding2  <= '1';
 | 
						|
                reg_reseed_cnt  <= std_logic_vector(to_unsigned(1, 10));
 | 
						|
                reg_enable      <= '1';
 | 
						|
                reg_a_wdata     <= init_seed;
 | 
						|
                reg_output      <= (others => '0');
 | 
						|
                reg_busy        <= '1';
 | 
						|
            end if;
 | 
						|
 | 
						|
        end if;
 | 
						|
    end process;
 | 
						|
 | 
						|
    -- Synchronous process for block RAM.
 | 
						|
    process (clk) is
 | 
						|
    begin
 | 
						|
        if rising_edge(clk) then
 | 
						|
            if reg_enable = '1' then
 | 
						|
 | 
						|
                -- Read from port A.
 | 
						|
                reg_a_rdata <= mem(to_integer(unsigned(reg_a_addr)));
 | 
						|
 | 
						|
                -- Read from port B.
 | 
						|
                reg_b_rdata <= mem(to_integer(unsigned(reg_b_addr)));
 | 
						|
 | 
						|
                -- Write to port A.
 | 
						|
                mem(to_integer(unsigned(reg_a_addr))) <= reg_a_wdata;
 | 
						|
 | 
						|
            end if;
 | 
						|
        end if;
 | 
						|
    end process;
 | 
						|
 | 
						|
end architecture;
 | 
						|
 |