Skip to content

Instantly share code, notes, and snippets.

@ikwzm
Last active March 25, 2016 05:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ikwzm/2176977 to your computer and use it in GitHub Desktop.
Save ikwzm/2176977 to your computer and use it in GitHub Desktop.
Tiny Mersenne Twister 32bit (TinyMT32) Pseudo Random Number Generator VHDL Package and RTL.

Tiny Mersenne Twister 32bit (TinyMT32) Pseudo Random Number Generator VHDL Package and RTL.

###概要### Tiny Mersenne Twister(TinyMT)法による擬似乱数生成パッケージと論理合成可能なサンプル回路です。

こちらを参考に書いてみました。 Tiny Mersenne Twister(TinyMT) Home Page (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index-jp.html)

tinymt32 を元にしています。

単精度の浮動小数点はサポートしていません。32ビット整数か実数のみです。

tinymt32.vhd は擬似乱数生成パッケージです。

tinimt32_gen.vhd は論理合成可能なサンプルの擬似乱数生成回路です。

###シミュレーション###

シミュレーションには GHDL (http://ghdl.free.fr/) を使いました。
Makefile を用意したので、make コマンド一発でシミュレーションが走ります。もしかしたら他のシミュレーションでは走らないかもしれません。その際はご一報ください。

###論理合成###

tinimt32_gen.vhd は論理合成可能な擬似乱数生成回路です。

テーブルはリセット時にデフォルトの値がセットされます。

また、外部からの書き込みによるテーブルの初期化も可能です。

論理合成は Xilinx 社 ISE13.1 使いました。

###ライセンス###

二条項BSDライセンス (2-clause BSD license) で公開しています。

###謝辞###

このような貴重なアルゴリズムを惜しげもなく公開してくださった方々にはひたすら感謝です。

GHDL=ghdl
GHDLFLAGS=--mb-comments
WORK=work
TEST_BENCH = test_bench \
$(END_LIST)
all: $(TEST_BENCH)
clean:
rm -f *.o *.cf $(TEST_BENCH)
test_bench: tinymt32.o tinymt32_gen.o test_bench.o
$(GHDL) -e $(GHDLFLAGS) $@
-$(GHDL) -r $(GHDLRUNFLAGS) $@
test_bench.o: ./test_bench.vhd
$(GHDL) -a $(GHDLFLAGS) --work=work $<
tinymt32.o: ./tinymt32.vhd
$(GHDL) -a $(GHDLFLAGS) --work=$(WORK) $<
tinymt32_gen.o: ./tinymt32_gen.vhd
$(GHDL) -a $(GHDLFLAGS) --work=$(WORK) $<
-----------------------------------------------------------------------------------
--! @file test_bench.vhd
--! @brief Test Bench for tinymt32_gen
--! @version 1.0.0
--! @date 2012/8/1
--! @author Ichiro Kawazome <ichiro_k@ca2.so-net.ne.jp>
-----------------------------------------------------------------------------------
--
-- Copyright (C) 2012 Ichiro Kawazome
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
--
-- 1. Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
--
-- 2. Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in
-- the documentation and/or other materials provided with the
-- distribution.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use work.TINYMT32.all;
entity TEST_BENCH is
end TEST_BENCH;
architecture MODEL of TEST_BENCH is
component TINYMT32_GEN
port (
CLK : in std_logic;
RST : in std_logic;
INIT : in std_logic;
INIT_PARAM : in PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
RND_RUN : in std_logic;
RND_VAL : out std_logic;
RND_NUM : out RANDOM_NUMBER_TYPE
);
end component;
constant PERIOD : time := 10 ns;
constant DELAY : time := 1 ns;
signal CLK : std_logic;
signal RST : std_logic;
signal INIT : std_logic;
signal INIT_PARAM: PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
signal RND_RUN : std_logic;
signal RND_VAL : std_logic;
signal RND_NUM : RANDOM_NUMBER_TYPE;
begin
U: TINYMT32_GEN
port map(
CLK => CLK,
RST => RST,
INIT => INIT,
INIT_PARAM => INIT_PARAM,
RND_RUN => RND_RUN,
RND_VAL => RND_VAL,
RND_NUM => RND_NUM
);
process begin
CLK <= '1'; wait for PERIOD/2;
CLK <= '0'; wait for PERIOD/2;
end process;
process
---------------------------------------------------------------------------
-- unsigned to hex string.
---------------------------------------------------------------------------
function TO_HEX_STRING(arg:unsigned;len:integer;space:character) return STRING is
variable str : STRING(len downto 1);
variable value : unsigned(arg'length-1 downto 0);
begin
value := arg;
for i in str'right to str'left loop
if (value > 0) then
case (to_integer(value mod 16)) is
when 0 => str(i) := '0';
when 1 => str(i) := '1';
when 2 => str(i) := '2';
when 3 => str(i) := '3';
when 4 => str(i) := '4';
when 5 => str(i) := '5';
when 6 => str(i) := '6';
when 7 => str(i) := '7';
when 8 => str(i) := '8';
when 9 => str(i) := '9';
when 10 => str(i) := 'a';
when 11 => str(i) := 'b';
when 12 => str(i) := 'c';
when 13 => str(i) := 'd';
when 14 => str(i) := 'e';
when 15 => str(i) := 'f';
when others => str(i) := 'X';
end case;
else
if (i = str'right) then
str(i) := '0';
else
str(i) := space;
end if;
end if;
value := value / 16;
end loop;
return str;
end function;
---------------------------------------------------------------------------
-- unsigned to decimal string.
---------------------------------------------------------------------------
function TO_DEC_STRING(arg:unsigned;len:integer;space:character) return STRING is
variable str : STRING(len downto 1);
variable value : unsigned(arg'length-1 downto 0);
begin
value := arg;
for i in str'right to str'left loop
if (value > 0) then
case (to_integer(value mod 10)) is
when 0 => str(i) := '0';
when 1 => str(i) := '1';
when 2 => str(i) := '2';
when 3 => str(i) := '3';
when 4 => str(i) := '4';
when 5 => str(i) := '5';
when 6 => str(i) := '6';
when 7 => str(i) := '7';
when 8 => str(i) := '8';
when 9 => str(i) := '9';
when others => str(i) := 'X';
end case;
else
if (i = str'right) then
str(i) := '0';
else
str(i) := space;
end if;
end if;
value := value / 10;
end loop;
return str;
end function;
---------------------------------------------------------------------------
-- unsigned to decimal string
---------------------------------------------------------------------------
function TO_DEC_STRING(arg:unsigned;len:integer) return STRING is
begin
return TO_DEC_STRING(arg,len,' ');
end function;
---------------------------------------------------------------------------
-- unsigned to decimal string
---------------------------------------------------------------------------
function TO_HEX_STRING(arg:unsigned;len:integer) return STRING is
begin
return TO_HEX_STRING(arg,len,'0');
end function;
---------------------------------------------------------------------------
-- real number to decimal string.
---------------------------------------------------------------------------
function TO_DEC_STRING(arg:real;len1,len2:integer) return STRING is
variable str : STRING(len2-1 downto 0);
variable i,n,p : integer;
begin
i := integer(arg);
if real(i) = arg then
n := i;
elsif i > 0 and real(i) > arg then
n := i-1;
elsif i < 0 and real(i) < arg then
n := i+1;
else
n := i;
end if;
p := integer((arg-real(n))*(10.0**len2));
return TO_DEC_STRING(to_unsigned(n,len1-len2-1),len1-len2-1,' ') & "." &
TO_DEC_STRING(to_unsigned(p,32),len2,'0');
end function;
---------------------------------------------------------------------------
-- convert Random Number to real.
---------------------------------------------------------------------------
function TO_REAL(arg:RANDOM_NUMBER_TYPE) return real is
variable result: real := 0.0;
begin
for i in arg'range loop
result := result + result;
if (arg(i) = '1') then
result := result + 1.0;
end if;
end loop;
return result;
end function;
---------------------------------------------------------------------------
-- Pseudo Random Number Generator Initalize Parameters.
---------------------------------------------------------------------------
constant seed : SEED_TYPE := X"00000001";
constant mat1 : SEED_TYPE := X"8f7011ee";
constant mat2 : SEED_TYPE := X"fc78ff1f";
constant tmat : RANDOM_NUMBER_TYPE := X"3793fdff";
constant init_key : SEED_VECTOR(0 to 0) := (0 => seed);
variable param : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE :=
NEW_PSEUDO_RANDOM_NUMBER_GENERATOR(mat1,mat2,tmat,seed);
---------------------------------------------------------------------------
-- Random number
---------------------------------------------------------------------------
variable num : real;
---------------------------------------------------------------------------
-- for display
---------------------------------------------------------------------------
constant TAG : STRING(1 to 1) := " ";
constant SPACE : STRING(1 to 1) := " ";
variable text_line : LINE;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
procedure WAIT_CLK(CNT:integer) is
begin
for i in 1 to CNT loop
wait until (CLK'event and CLK = '1');
end loop;
wait for DELAY;
end WAIT_CLK;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
variable count_run : integer;
variable count_val : integer;
variable count_max : integer;
constant RUN_WAIT : integer := 1;
begin
RST <= '1';
INIT <= '0';
RND_RUN <= '0';
WAIT_CLK(10);
RST <= '0';
WAIT_CLK(10);
-- WRITE(text_line, TO_HEX_STRING(unsigned(TO_01(param.status(0))),10) & SPACE);
-- WRITE(text_line, TO_HEX_STRING(unsigned(TO_01(param.status(1))),10) & SPACE);
-- WRITE(text_line, TO_HEX_STRING(unsigned(TO_01(param.status(2))),10) & SPACE);
-- WRITE(text_line, TO_HEX_STRING(unsigned(TO_01(param.status(3))),10));
-- WRITELINE(OUTPUT, text_line);
INIT_PSEUDO_RANDOM_NUMBER_GENERATOR(param,mat1,mat2,tmat,seed);
WRITE(text_line, "tinymt32 0x" & TO_HEX_STRING(unsigned(param.mat1),8) & SPACE);
WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.mat2),8) & SPACE);
WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.tmat),8) & SPACE);
WRITE(text_line, "seed = " & TO_DEC_STRING(unsigned(seed ),1));
WRITELINE(OUTPUT, text_line);
WRITE(text_line, "32-bit unsigned integers r, where 0 <= r < 2^32" & SPACE);
WRITELINE(OUTPUT, text_line);
INIT <= '1';
INIT_PARAM<= param;
WAIT_CLK(1);
INIT <= '0';
WAIT_CLK(1);
RND_RUN <= '1';
count_run := 0;
count_val := 0;
count_max := 50;
for i in 0 to RUN_WAIT*(count_max+10) loop
wait until (CLK'event and CLK = '1');
if (count_run >= count_max or i mod RUN_WAIT /= 0) then
RND_RUN <= '0' after DELAY;
else
RND_RUN <= '1' after DELAY;
count_run := count_run + 1;
end if;
if (RND_VAL = '1') then
count_val := count_val + 1;
WRITE(text_line, TO_DEC_STRING(unsigned(TO_01(RND_NUM)),10) & SPACE);
if (count_val mod 5 = 0) then
WRITELINE(OUTPUT, text_line);
end if;
if (count_val >= count_max) then
exit;
end if;
end if;
end loop;
WRITELINE(OUTPUT, text_line);
RND_RUN <= '0' after DELAY;
INIT_PSEUDO_RANDOM_NUMBER_GENERATOR(param,mat1,mat2,tmat,init_key);
-- WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.status(0)),8) & SPACE);
-- WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.status(1)),8) & SPACE);
-- WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.status(2)),8) & SPACE);
-- WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.status(3)),8) & SPACE);
-- WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.mat1 ),8) & SPACE);
-- WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.mat2 ),8) & SPACE);
-- WRITE(text_line, "0x" & TO_HEX_STRING(unsigned(param.tmat ),8) & SPACE);
-- WRITELINE(OUTPUT, text_line);
WRITE(text_line, "init_by_array {" & TO_DEC_STRING(unsigned(init_key(0)),1) & "}");
WRITELINE(OUTPUT, text_line);
WRITE(text_line, "float numbers r, where 0.0 <= r < 1.0" & SPACE);
WRITELINE(OUTPUT, text_line);
INIT <= '1';
INIT_PARAM<= param;
WAIT_CLK(1);
INIT <= '0';
WAIT_CLK(1);
RND_RUN <= '1';
count_run := 0;
count_val := 0;
count_max := 50;
for i in 0 to RUN_WAIT*(count_max+10) loop
wait until (CLK'event and CLK = '1');
if (count_run >= count_max or i mod RUN_WAIT /= 0) then
RND_RUN <= '0' after DELAY;
else
RND_RUN <= '1' after DELAY;
count_run := count_run + 1;
end if;
if (RND_VAL = '1') then
count_val := count_val + 1;
num := (1.0/4294967296.0)*TO_REAL(RND_NUM);
WRITE(text_line, TO_DEC_STRING(num,9,7) & SPACE);
if (count_val mod 5 = 0) then
WRITELINE(OUTPUT, text_line);
end if;
if (count_val >= count_max) then
exit;
end if;
end if;
end loop;
WRITELINE(OUTPUT, text_line);
RND_RUN <= '0' after DELAY;
assert(false) report TAG & " Run complete..." severity FAILURE;
wait;
end process;
end MODEL;
-----------------------------------------------------------------------------------
--! @file tinymt32.vhd
--! @brief Pseudo Random Number Generator Package(TinyMT32).
--! @version 1.0.0
--! @date 2012/8/1
--! @author Ichiro Kawazome <ichiro_k@ca2.so-net.ne.jp>
-----------------------------------------------------------------------------------
--
-- Copyright (C) 2012 Ichiro Kawazome
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
--
-- 1. Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
--
-- 2. Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in
-- the documentation and/or other materials provided with the
-- distribution.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-----------------------------------------------------------------------------------
--! @brief Pseudo Random Number Generator Package(TinyMT32).
-----------------------------------------------------------------------------------
package TINYMT32 is
-------------------------------------------------------------------------------
--! @brief Type of Random Number.
-------------------------------------------------------------------------------
subtype RANDOM_NUMBER_TYPE is unsigned(31 downto 0);
-------------------------------------------------------------------------------
--! @brief Vector of Random Number.
-------------------------------------------------------------------------------
type RANDOM_NUMBER_VECTOR is array(integer range <>) of RANDOM_NUMBER_TYPE;
-------------------------------------------------------------------------------
--! @brief Convert Integer to RANDOM_NUMBER_TYPE
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param arg Integer.
--! @return Generated random number.
-------------------------------------------------------------------------------
function TO_RANDOM_NUMBER_TYPE(arg:integer) return RANDOM_NUMBER_TYPE;
-------------------------------------------------------------------------------
--! @brief Type of Seed Number for Pseudo Random Number Generator.
-------------------------------------------------------------------------------
subtype SEED_TYPE is unsigned(31 downto 0);
-------------------------------------------------------------------------------
--! @brief Vector of Seed Number for Pseudo Random Number Generator.
-------------------------------------------------------------------------------
type SEED_VECTOR is array(integer range <>) of SEED_TYPE;
-------------------------------------------------------------------------------
--! @brief Convert Integer to SEED_TYPE
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param arg Integer.
--! @return Generated seed number.
-------------------------------------------------------------------------------
function TO_SEED_TYPE(arg:integer) return SEED_TYPE;
-------------------------------------------------------------------------------
--! @brief Type of Record for Pseudo Random Number Generator.
-------------------------------------------------------------------------------
type PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE is record
status : RANDOM_NUMBER_VECTOR(0 to 3);
mat1 : SEED_TYPE;
mat2 : SEED_TYPE;
tmat : RANDOM_NUMBER_TYPE;
end record;
-------------------------------------------------------------------------------
--! @brief Generate instance for Pseudo Random Number Generator.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param mat1 Parameter for Pseudo Random Number Generator.
--! @param mat2 Parameter for Pseudo Random Number Generator.
--! @param tmat Parameter for Pseudo Random Number Generator.
--! @param seed Seed Number for Pseudo Random Number Generator.
--! @return Pseudo Random Number Generator.
-------------------------------------------------------------------------------
function NEW_PSEUDO_RANDOM_NUMBER_GENERATOR(
mat1 : SEED_TYPE;
mat2 : SEED_TYPE;
tmat : RANDOM_NUMBER_TYPE;
seed : SEED_TYPE
) return PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
-------------------------------------------------------------------------------
--! @brief Generate instance for Pseudo Random Number Generator.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param mat1 Parameter for Pseudo Random Number Generator.
--! @param mat2 Parameter for Pseudo Random Number Generator.
--! @param tmat Parameter for Pseudo Random Number Generator.
--! @param seed Seed Number Vector for Pseudo Random Number Generator.
--! @return Pseudo Random Number Generator.
-------------------------------------------------------------------------------
function NEW_PSEUDO_RANDOM_NUMBER_GENERATOR(
mat1 : SEED_TYPE;
mat2 : SEED_TYPE;
tmat : RANDOM_NUMBER_TYPE;
seed : SEED_VECTOR
) return PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
-------------------------------------------------------------------------------
--! @brief Initialize Pseudo Random Number Generator.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param mat1 Parameter for Pseudo Random Number Generator.
--! @param mat2 Parameter for Pseudo Random Number Generator.
--! @param tmat Parameter for Pseudo Random Number Generator.
--! @param seed Seed Number for Pseudo Random Number Generator.
-------------------------------------------------------------------------------
procedure INIT_PSEUDO_RANDOM_NUMBER_GENERATOR(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
mat1 : in SEED_TYPE;
mat2 : in SEED_TYPE;
tmat : in RANDOM_NUMBER_TYPE;
seed : in SEED_TYPE
);
-------------------------------------------------------------------------------
--! @brief Initialize Pseudo Random Number Generator.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param mat1 Parameter for Pseudo Random Number Generator.
--! @param mat2 Parameter for Pseudo Random Number Generator.
--! @param tmat Parameter for Pseudo Random Number Generator.
--! @param seed Seed Number Vector for Pseudo Random Number Generator.
-------------------------------------------------------------------------------
procedure INIT_PSEUDO_RANDOM_NUMBER_GENERATOR(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
mat1 : in SEED_TYPE;
mat2 : in SEED_TYPE;
tmat : in RANDOM_NUMBER_TYPE;
seed : in SEED_VECTOR
);
-------------------------------------------------------------------------------
--! @brief This function changes internal state of tinymt32.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! * Users should not call this function directly.
--! @param generator Pseudo Random Number Generator.
-------------------------------------------------------------------------------
procedure NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE
);
-------------------------------------------------------------------------------
--! @brief This function outputs 32-bit unsigned integer from internal state.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! * Users should not call this function directly.
--! @param generator Pseudo Random Number Generator.
--! @return Generated temper number.
-------------------------------------------------------------------------------
function GENERATE_TEMPER(
generator : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE
) return RANDOM_NUMBER_TYPE;
-------------------------------------------------------------------------------
--! @brief Generates a random number
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_NUMBER(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out RANDOM_NUMBER_TYPE
);
-------------------------------------------------------------------------------
--! @brief Generates a random number on (std_logic_vector).
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_STD_LOGIC_VECTOR(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out std_logic_vector
);
-------------------------------------------------------------------------------
--! @brief Generates a random number on [0,0x7fffffff]-interval.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_INT31(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out integer
);
-------------------------------------------------------------------------------
--! @brief Generates a random number on [0,1]-real-interval.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_REAL1(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out real
);
-------------------------------------------------------------------------------
--! @brief Generates a random number on [0,1)-real-interval.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_REAL2(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out real
);
-------------------------------------------------------------------------------
--! @brief Generates a random number on (0,1)-real-interval.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_REAL3(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out real
);
end TINYMT32;
-----------------------------------------------------------------------------------
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package body TINYMT32 is
-------------------------------------------------------------------------------
-- Period parameters
-------------------------------------------------------------------------------
constant MEXP : integer := 127;
constant SH0 : integer := 1;
constant SH1 : integer := 10;
constant SH8 : integer := 8;
constant MASK : RANDOM_NUMBER_TYPE := (RANDOM_NUMBER_TYPE'high => '0', others => '1');
constant LINEARITY_CHECK : boolean := FALSE;
constant MIN_LOOP : integer := 8;
constant PRE_LOOP : integer := 8;
-------------------------------------------------------------------------------
--! @brief Convert Integer to SEED_TYPE
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param arg Integer.
--! @return Generated seed number.
-------------------------------------------------------------------------------
function TO_SEED_TYPE(arg:integer) return SEED_TYPE is
begin
return to_unsigned(arg,SEED_TYPE'length);
end function;
-------------------------------------------------------------------------------
--! @brief Convert Integer to RANDOM_NUMBER_TYPE
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param arg Integer.
--! @return Generated random number.
-------------------------------------------------------------------------------
function TO_RANDOM_NUMBER_TYPE(arg:integer) return RANDOM_NUMBER_TYPE is
begin
return to_unsigned(arg,RANDOM_NUMBER_TYPE'length);
end function;
-------------------------------------------------------------------------------
--! @brief Convert from Random Number to real.
---------------------------------------------------------------------------
function TO_REAL(arg:RANDOM_NUMBER_TYPE) return real is
variable result: real := 0.0;
begin
for i in arg'range loop
result := result + result;
if (arg(i) = '1') then
result := result + 1.0;
end if;
end loop;
return result;
end function;
-------------------------------------------------------------------------------
--! @brief RANDOM_NUMBER_TYPE multiplied by integer.
-------------------------------------------------------------------------------
function MUL_K(k:integer;arg:RANDOM_NUMBER_TYPE) return RANDOM_NUMBER_TYPE is
variable tmp : unsigned(2*RANDOM_NUMBER_TYPE'length-1 downto 0);
begin
tmp := arg * TO_RANDOM_NUMBER_TYPE(k);
return tmp(RANDOM_NUMBER_TYPE'range);
end function;
-------------------------------------------------------------------------------
--! @brief Generate instance for Pseudo Random Number Generator.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param mat1 Parameter for Pseudo Random Number Generator.
--! @param mat2 Parameter for Pseudo Random Number Generator.
--! @param tmat Parameter for Pseudo Random Number Generator.
--! @param seed Seed Number for Pseudo Random Number Generator.
--! @return Pseudo Random Number Generator.
-------------------------------------------------------------------------------
function NEW_PSEUDO_RANDOM_NUMBER_GENERATOR(
mat1 : SEED_TYPE;
mat2 : SEED_TYPE;
tmat : RANDOM_NUMBER_TYPE;
seed : SEED_TYPE
) return PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE
is
variable generator : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
begin
INIT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator,mat1,mat2,tmat,seed);
return generator;
end function;
-------------------------------------------------------------------------------
--! @brief Generate instance for Pseudo Random Number Generator.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param mat1 Parameter for Pseudo Random Number Generator.
--! @param mat2 Parameter for Pseudo Random Number Generator.
--! @param tmat Parameter for Pseudo Random Number Generator.
--! @param seed Seed Number Vector for Pseudo Random Number Generator.
--! @return Pseudo Random Number Generator.
-------------------------------------------------------------------------------
function NEW_PSEUDO_RANDOM_NUMBER_GENERATOR(
mat1 : SEED_TYPE;
mat2 : SEED_TYPE;
tmat : RANDOM_NUMBER_TYPE;
seed : SEED_VECTOR
) return PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE
is
variable generator : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
begin
INIT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator,mat1,mat2,tmat,seed);
return generator;
end function;
-------------------------------------------------------------------------------
--! @brief This function certificate the period of 2^127-1.
-------------------------------------------------------------------------------
procedure period_certification(generator:inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE) is
begin
if ((generator.status(0) and MASK) = 0) and
(generator.status(1) = 0) and
(generator.status(2) = 0) and
(generator.status(3) = 0) then
generator.status(0) := TO_RANDOM_NUMBER_TYPE(84); -- 'T'
generator.status(1) := TO_RANDOM_NUMBER_TYPE(57); -- 'I';
generator.status(2) := TO_RANDOM_NUMBER_TYPE(78); -- 'N';
generator.status(3) := TO_RANDOM_NUMBER_TYPE(89); -- 'Y';
end if;
end procedure;
-------------------------------------------------------------------------------
--! @brief Initialize Pseudo Random Number Generator.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param mat1 Parameter for Pseudo Random Number Generator.
--! @param mat2 Parameter for Pseudo Random Number Generator.
--! @param tmat Parameter for Pseudo Random Number Generator.
--! @param seed Seed Number for Pseudo Random Number Generator.
-------------------------------------------------------------------------------
procedure INIT_PSEUDO_RANDOM_NUMBER_GENERATOR(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
mat1 : in SEED_TYPE;
mat2 : in SEED_TYPE;
tmat : in RANDOM_NUMBER_TYPE;
seed : in SEED_TYPE
) is
begin
generator.mat1 := mat1;
generator.mat2 := mat2;
generator.tmat := tmat;
generator.status(0) := seed;
generator.status(1) := mat1;
generator.status(2) := mat2;
generator.status(3) := tmat;
for i in 1 to MIN_LOOP-1 loop
generator.status(i mod 4) := generator.status(i mod 4) xor
(MUL_K(1812433253,
((generator.status((i-1) mod 4)) xor
(generator.status((i-1) mod 4) srl 30))) + i);
end loop;
period_certification(generator);
for i in 0 to PRE_LOOP-1 loop
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator);
end loop;
end procedure;
-------------------------------------------------------------------------------
--! @brief Initialize Pseudo Random Number Generator.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param mat1 Parameter for Pseudo Random Number Generator.
--! @param mat2 Parameter for Pseudo Random Number Generator.
--! @param tmat Parameter for Pseudo Random Number Generator.
--! @param seed Seed Number Vector for Pseudo Random Number Generator.
-------------------------------------------------------------------------------
procedure INIT_PSEUDO_RANDOM_NUMBER_GENERATOR(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
mat1 : in SEED_TYPE;
mat2 : in SEED_TYPE;
tmat : in RANDOM_NUMBER_TYPE;
seed : in SEED_VECTOR
) is
constant lag : integer := 1;
constant mid : integer := 1;
constant size : integer := 4;
variable i,j : integer;
variable count : integer;
variable r : RANDOM_NUMBER_TYPE;
alias init_key : SEED_VECTOR(1 to seed'length) is seed;
function ini_func1(x:RANDOM_NUMBER_TYPE) return RANDOM_NUMBER_TYPE is
begin
return MUL_K(1664525 ,(x xor (x srl 27)));
end function;
function ini_func2(x:RANDOM_NUMBER_TYPE) return RANDOM_NUMBER_TYPE is
begin
return MUL_K(1566083941,(x xor (x srl 27)));
end function;
begin
generator.mat1 := mat1;
generator.mat2 := mat2;
generator.tmat := tmat;
generator.status(0) := TO_RANDOM_NUMBER_TYPE(0);
generator.status(1) := mat1;
generator.status(2) := mat2;
generator.status(3) := tmat;
if (init_key'length + 1 > MIN_LOOP) then
count := init_key'length + 1;
else
count := MIN_LOOP;
end if;
i := 0;
for j in 0 to count-1 loop
r := ini_func1(generator.status(i) xor
generator.status((i+mid) mod size) xor
generator.status((i+size-1) mod size));
generator.status((i+mid ) mod size) := generator.status((i+mid ) mod size) + r;
if (j = 0) then
r := r + init_key'length;
elsif (init_key'low <= j and j <= init_key'high) then
r := r + init_key(j) + i;
else
r := r + i;
end if;
generator.status((i+mid+lag) mod size) := generator.status((i+mid+lag) mod size) + r;
generator.status(i) := r;
i := (i + 1) mod size;
end loop;
for j in 0 to size-1 loop
r := ini_func2(generator.status(i) +
generator.status((i+mid ) mod size) +
generator.status((i+size-1) mod size));
generator.status((i+mid ) mod size) := generator.status((i+mid ) mod size) xor r;
r := r - i;
generator.status((i+mid+lag) mod size) := generator.status((i+mid+lag) mod size) xor r;
generator.status(i) := r;
i := (i + 1) mod size;
end loop;
period_certification(generator);
for i in 0 to PRE_LOOP-1 loop
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator);
end loop;
end procedure;
-------------------------------------------------------------------------------
--! @brief This function changes internal state of tinymt32.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! * Users should not call this function directly.
--! @param generator Pseudo Random Number Generator.
-------------------------------------------------------------------------------
procedure NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE
) is
variable x : RANDOM_NUMBER_TYPE;
variable y : RANDOM_NUMBER_TYPE;
begin
x := (generator.status(0) and MASK) xor generator.status(1) xor generator.status(2);
y := generator.status(3);
x := x xor (x sll SH0);
y := y xor (y srl SH0) xor x;
generator.status(0) := generator.status(1);
generator.status(1) := generator.status(2);
generator.status(2) := x xor (y sll SH1);
generator.status(3) := y;
if (y(0) = '1') then
generator.status(1) := generator.status(1) xor generator.mat1;
generator.status(2) := generator.status(2) xor generator.mat2;
end if;
end procedure;
-------------------------------------------------------------------------------
--! @brief This function outputs 32-bit unsigned integer from internal state.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! * Users should not call this function directly.
--! @param generator Pseudo Random Number Generator.
--! @return Generated temper number.
-------------------------------------------------------------------------------
function GENERATE_TEMPER(
generator : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE
) return RANDOM_NUMBER_TYPE
is
variable t0 : RANDOM_NUMBER_TYPE;
variable t1 : RANDOM_NUMBER_TYPE;
begin
t0 := generator.status(3);
if (LINEARITY_CHECK) then
t1 := generator.status(0) xor (generator.status(2) srl SH8);
else
t1 := generator.status(0) + (generator.status(2) srl SH8);
end if;
t0 := t0 xor t1;
if (t1(0) = '1') then
t0 := t0 xor generator.tmat;
end if;
return t0;
end function;
-------------------------------------------------------------------------------
--! @brief Generates a random number
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_NUMBER(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out RANDOM_NUMBER_TYPE
) is
begin
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator);
number := GENERATE_TEMPER(generator);
end procedure;
-------------------------------------------------------------------------------
--! @brief Generates a random number on (std_logic_vector).
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_STD_LOGIC_VECTOR(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out std_logic_vector
) is
variable word : RANDOM_NUMBER_TYPE;
variable number_t : std_logic_vector(number'length-1 downto 0);
begin
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator);
word := GENERATE_TEMPER(generator);
for i in number_t'range loop
if (word(i) = '1') then
number_t(i) := '1';
else
number_t(i) := '0';
end if;
end loop;
number := number_t;
end procedure;
-------------------------------------------------------------------------------
--! @brief Generates a random number on [0,0x7fffffff]-interval.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_INT31(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out integer
) is
variable word : RANDOM_NUMBER_TYPE;
begin
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator);
word := GENERATE_TEMPER(generator);
number := to_integer(word(31 downto 1));
end procedure;
-------------------------------------------------------------------------------
--! @brief Generates a random number on [0,1]-real-interval.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_REAL1(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out real
) is
variable word : RANDOM_NUMBER_TYPE;
begin
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator);
word := GENERATE_TEMPER(generator);
number := (1.0/4294967295.0)*TO_REAL(word);
end procedure;
-------------------------------------------------------------------------------
--! @brief Generates a random number on [0,1)-real-interval.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_REAL2(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out real
) is
variable word : RANDOM_NUMBER_TYPE;
begin
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator);
word := GENERATE_TEMPER(generator);
number := (1.0/4294967296.0)*TO_REAL(word);
end procedure;
-------------------------------------------------------------------------------
--! @brief Generates a random number on (0,1)-real-interval.
--! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--! @param generator Pseudo Random Number Generator.
--! @param number Generated random number.
-------------------------------------------------------------------------------
procedure GENERATE_RANDOM_REAL3(
variable generator : inout PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
variable number : out real
) is
variable word : RANDOM_NUMBER_TYPE;
begin
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(generator);
word := GENERATE_TEMPER(generator);
number := (1.0/4294967296.0)*(0.5+TO_REAL(word));
end procedure;
end TINYMT32;
-----------------------------------------------------------------------------------
--! @file tinymt32_gen.vhd
--! @brief Pseudo Random Number Generator (TinyMT32).
--! @version 1.0.0
--! @date 2012/8/1
--! @author Ichiro Kawazome <ichiro_k@ca2.so-net.ne.jp>
-----------------------------------------------------------------------------------
--
-- Copyright (C) 2012 Ichiro Kawazome
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
--
-- 1. Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
--
-- 2. Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in
-- the documentation and/or other materials provided with the
-- distribution.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.TINYMT32.RANDOM_NUMBER_TYPE;
use work.TINYMT32.PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
entity TINYMT32_GEN is
port (
CLK : in std_logic;
RST : in std_logic;
INIT : in std_logic;
INIT_PARAM : in PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
RND_RUN : in std_logic;
RND_VAL : out std_logic;
RND_NUM : out RANDOM_NUMBER_TYPE
);
end TINYMT32_GEN;
-----------------------------------------------------------------------------------
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.TINYMT32.all;
architecture RTL of TINYMT32_GEN is
constant DEFAULT_PARAM : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE :=
NEW_PSEUDO_RANDOM_NUMBER_GENERATOR(
X"8f7011ee",
X"fc78ff1f",
X"3793fdff",
TO_SEED_TYPE(1)
);
signal curr_status : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
signal status_valid : std_logic;
begin
process(CLK, RST)
variable next_status : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
begin
if (RST = '1') then
curr_status <= DEFAULT_PARAM;
status_valid <= '0';
RND_VAL <= '0';
RND_NUM <= (others => '0');
elsif (CLK'event and CLK = '1') then
if (INIT = '1') then
curr_status <= INIT_PARAM;
status_valid <= '0';
RND_VAL <= '0';
RND_NUM <= (others => '0');
else
if (RND_RUN = '1') then
next_status := curr_status;
NEXT_PSEUDO_RANDOM_NUMBER_GENERATOR(next_status);
curr_status <= next_status;
status_valid <= '1';
else
status_valid <= '0';
end if;
if (status_valid = '1') then
RND_NUM <= GENERATE_TEMPER(curr_status);
RND_VAL <= '1';
else
RND_VAL <= '0';
end if;
end if;
end if;
end process;
end RTL;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment