Skip to content

Instantly share code, notes, and snippets.

@ikwzm
Created March 21, 2012 10:39
Show Gist options
  • Save ikwzm/2146081 to your computer and use it in GitHub Desktop.
Save ikwzm/2146081 to your computer and use it in GitHub Desktop.
Mersenne Twister Pseudo Random Number Generator VHDL RTL.

Mersenne Twister Pseudo Random Number Generator VHDL RTL.

###概要### Mersenne Twister法による擬似乱数生成回路です。

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

mt19937arを元にしています。

論理合成可能です。

1クロックで1、2、4、8、16ワード(1ワードは32bit)の乱数を生成できます。

###論理合成### Xilinx社のFPGAで合成を行うためには次のファイルが必要です。

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

Altera社のFPGAで合成を行う場合はこちらhttps://gist.github.com/2250826を参照してください.

###シミュレーション### シミュレーションをするためには次のファイルが必要です。

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

###その他### なおここにアップした回路は乱数生成のみで、テーブルの初期化は行っていません。 テーブルの初期化は、外部から書き込むか、FPGAベンダーのツールを使ってあらかじめRAMに書いておく必要があります。 テーブルの初期化のための回路を作ることも考えましたが、たかだか1回の初期化のために貴重なFPGA/ASICのリソースを使うのもなんだし、んなもんCPUでやればいいやってことで今回は見送りました。 もう少しパーシャルリコンフィグが使い易ければ、初期化のあとにリソースを開放して他の機能に置き換えることが出来るんですが。

###ライセンス### 二条項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: mt19937ar.o test_bench.o mt32_gen.o mt32_1w1r_ram.o sdpram.o sdpram_model.o
$(GHDL) -e $(GHDLFLAGS) $@
-$(GHDL) -r $(GHDLRUNFLAGS) $@
test_bench.o : ./test_bench.vhd
$(GHDL) -a $(GHDLFLAGS) --work=work $<
mt19937ar.o : ./mt19937ar.vhd
$(GHDL) -a $(GHDLFLAGS) --work=$(WORK) $<
mt32_gen.o : ./mt32_gen.vhd
$(GHDL) -a $(GHDLFLAGS) --work=$(WORK) $<
mt32_1w1r_ram.o: ./mt32_1w1r_ram.vhd
$(GHDL) -a $(GHDLFLAGS) --work=$(WORK) $<
sdpram.o : ./sdpram.vhd
$(GHDL) -a $(GHDLFLAGS) --work=$(WORK) $<
sdpram_model.o : ./sdpram_model.vhd
$(GHDL) -a $(GHDLFLAGS) --work=$(WORK) $<
-----------------------------------------------------------------------------------
-- --
-- Title : Synchronous Dual Port RAM for MT32_GEN --
-- Module Name : MT32_1W1R_RAM --
-- Version : 0.0.1 --
-- Created : 2012/3/21 --
-- File Name : mt32_1w1r_ram.vhd --
-- Author : Ichiro Kawazome <[email protected]> --
-- Description : Synchronous Dual Port RAM for MT32_GEN --
-- --
-- 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;
entity MT32_1W1R_RAM is
generic (
DEPTH : integer := 6;
ID : integer := 0
);
port (
CLK : in std_logic;
WE : in std_logic;
WADDR : in std_logic_vector(DEPTH-1 downto 0);
RADDR : in std_logic_vector(DEPTH-1 downto 0);
WDATA : in std_logic_vector( 31 downto 0);
RDATA : out std_logic_vector( 31 downto 0)
);
end MT32_1W1R_RAM;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture RTL of MT32_1W1R_RAM is
component SDPRAM
generic (
DEPTH : integer;
RWIDTH : integer;
WWIDTH : integer;
WEBIT : integer;
ID : integer
);
port (
WCLK : in std_logic;
WE : in std_logic_vector(2**WEBIT-1 downto 0);
WADDR : in std_logic_vector(DEPTH-1 downto WWIDTH);
RCLK : in std_logic;
RADDR : in std_logic_vector(DEPTH-1 downto RWIDTH);
WDATA : in std_logic_vector(2**WWIDTH-1 downto 0);
RDATA : out std_logic_vector(2**RWIDTH-1 downto 0)
);
end component;
signal wen : std_logic_vector(0 downto 0);
begin
wen <= (others => '1') when (WE = '1') else (others => '0');
RAM:SDPRAM
generic map(
DEPTH => DEPTH+5,
RWIDTH => 5,
WWIDTH => 5,
WEBIT => 0,
ID => ID
)
port map(
WCLK => CLK,
WE => wen,
WADDR => WADDR,
RCLK => CLK,
RADDR => RADDR,
WDATA => WDATA,
RDATA => RDATA
);
end RTL;
-----------------------------------------------------------------------------------
-- --
-- Title : Pseudo Random Number Generator (MT32) --
-- Module Name : MT32_GEN --
-- Version : 0.0.4 --
-- Created : 2012/3/22 --
-- File Name : mt32_gen.vhd --
-- Author : Ichiro Kawazome <[email protected]> --
-- Description : This is a Mersenne Twister pseudorandom number generator. --
-- --
-- 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;
entity MT32_GEN is
generic (
N : integer := 624;
M : integer := 397;
L : integer := 1
);
port (
CLK : in std_logic;
RST : in std_logic;
TBL_INIT : in std_logic;
TBL_WE : in std_logic_vector( L-1 downto 0);
TBL_WPTR : in std_logic_vector( 15 downto 0);
TBL_WDATA : in std_logic_vector(32*L-1 downto 0);
TBL_RPTR : in std_logic_vector( 15 downto 0);
TBL_RDATA : out std_logic_vector(32*L-1 downto 0);
RND_RUN : in std_logic;
RND_VAL : out std_logic;
RND_NUM : out std_logic_vector(32*L-1 downto 0)
);
end MT32_GEN;
-----------------------------------------------------------------------------------
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture RTL of MT32_GEN is
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
constant WIDTH : integer := 32;
subtype RANDOM_NUMBER_TYPE is std_logic_vector(WIDTH-1 downto 0);
type RANDOM_NUMBER_VECTOR is array(integer range <>) of RANDOM_NUMBER_TYPE;
constant UPPER : std_logic_vector(WIDTH-1 downto WIDTH-1) := (others => '1');
constant LOWER : std_logic_vector(WIDTH-2 downto 0) := (others => '1');
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
constant MATRIX_A : RANDOM_NUMBER_TYPE := X"9908B0DF";
constant TEMPERING_PARAM1 : RANDOM_NUMBER_TYPE := X"9d2c5680";
constant TEMPERING_PARAM2 : RANDOM_NUMBER_TYPE := X"efc60000";
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
function shift(arg: RANDOM_NUMBER_TYPE;num:integer) return RANDOM_NUMBER_TYPE is
variable retval : RANDOM_NUMBER_TYPE;
begin
for i in retval'range loop
if (i+num <= retval'high and i+num >= retval'low) then
retval(i) := arg(i+num);
else
retval(i) := '0';
end if;
end loop;
return retval;
end function;
function shift_right(arg: RANDOM_NUMBER_TYPE;num:positive) return RANDOM_NUMBER_TYPE is
begin
return shift(arg,num);
end function;
function shift_left (arg: RANDOM_NUMBER_TYPE;num:positive) return RANDOM_NUMBER_TYPE is
begin
return shift(arg,-num);
end function;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
function Tempering(arg: RANDOM_NUMBER_TYPE) return RANDOM_NUMBER_TYPE is
variable y : RANDOM_NUMBER_TYPE;
begin
y := arg;
y := y xor (shift_right(y, 11));
y := y xor (shift_left (y, 7) and TEMPERING_PARAM1);
y := y xor (shift_left (y, 15) and TEMPERING_PARAM2);
y := y xor (shift_right(y, 18));
return y;
end function;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
function CALC_MT_PTR_LOW return integer is
variable retval : integer;
begin
retval := 0;
while (2**retval < L) loop
retval := retval + 1;
end loop;
return retval;
end function;
function CALC_MT_PTR_HIGH return integer is
variable retval : integer;
begin
retval := 0;
while (2**retval <= N) loop
retval := retval + 1;
end loop;
return retval;
end function;
constant MT_PTR_LOW : integer := CALC_MT_PTR_LOW;
constant MT_PTR_HIGH : integer := CALC_MT_PTR_HIGH;
subtype MT_PTR_TYPE is std_logic_vector(MT_PTR_HIGH downto MT_PTR_LOW);
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
function TO_MT_PTR(arg:integer) return MT_PTR_TYPE is
variable u : unsigned(MT_PTR_HIGH downto 0);
begin
u := to_unsigned(arg,u'length);
return std_logic_vector(u(MT_PTR_TYPE'range));
end function;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
function INC_MT_PTR(ptr:MT_PTR_TYPE) return MT_PTR_TYPE is
variable retval : MT_PTR_TYPE;
begin
if (unsigned(ptr) >= unsigned(TO_MT_PTR(N-1))) then
retval := (others => '0');
else
retval := std_logic_vector(unsigned(ptr)+1);
end if;
return retval;
end function;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
signal random_number : RANDOM_NUMBER_VECTOR(0 to L-1);
signal random_valid : std_logic;
signal z_val : std_logic;
signal z : RANDOM_NUMBER_VECTOR(0 to L-1);
signal mt_xdata : RANDOM_NUMBER_VECTOR(0 to L-1);
signal mt_ydata : RANDOM_NUMBER_VECTOR(0 to L-1);
signal mt_wdata : RANDOM_NUMBER_VECTOR(0 to L-1);
signal mt_rdata : RANDOM_NUMBER_VECTOR(0 to L-1);
signal mt_waddr : MT_PTR_TYPE;
signal mt_write : std_logic_vector (0 to L-1);
signal mt_read : std_logic;
signal mt_curr_yaddr : MT_PTR_TYPE;
signal mt_next_yaddr : MT_PTR_TYPE;
signal mt_curr_xaddr : MT_PTR_TYPE;
signal mt_next_xaddr : MT_PTR_TYPE;
signal y_curr_index : MT_PTR_TYPE;
signal y_next_index : MT_PTR_TYPE;
signal x_curr_index : MT_PTR_TYPE;
signal x_next_index : MT_PTR_TYPE;
signal z_curr_index : MT_PTR_TYPE;
signal run : std_logic;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
component MT32_1W1R_RAM
generic(
DEPTH : integer;
ID : integer
);
port (
CLK : in std_logic;
WE : in std_logic;
WADDR : in std_logic_vector(DEPTH-1 downto 0);
WDATA : in std_logic_vector( 31 downto 0);
RADDR : in std_logic_vector(DEPTH-1 downto 0);
RDATA : out std_logic_vector( 31 downto 0)
);
end component;
begin
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
CTRL: process(CLK,RST) begin
if (RST = '1') then
y_curr_index <= TO_MT_PTR(0);
y_next_index <= TO_MT_PTR(0);
x_curr_index <= TO_MT_PTR(M);
x_next_index <= TO_MT_PTR(M);
z_curr_index <= TO_MT_PTR(0);
run <= '0';
mt_read <= '0';
z_val <= '0';
elsif (CLK'event and CLK = '1') then
if (TBL_INIT='1') then
y_curr_index <= TO_MT_PTR(0);
y_next_index <= TO_MT_PTR(0);
x_curr_index <= TO_MT_PTR(M);
x_next_index <= TO_MT_PTR(M);
z_curr_index <= TO_MT_PTR(0);
run <= '0';
mt_read <= '0';
z_val <= '0';
else
if (RND_RUN = '1') then
run <= '1';
else
run <= '0';
end if;
if (run = '1')then
y_curr_index <= y_next_index;
y_next_index <= INC_MT_PTR(y_next_index);
x_curr_index <= x_next_index;
x_next_index <= INC_MT_PTR(x_next_index);
mt_read <= '1';
else
mt_read <= '0';
end if;
if (mt_read = '1') then
z_curr_index <= y_curr_index;
z_val <= '1';
else
z_val <= '0';
end if;
end if;
end if;
end process;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
mt_waddr <= z_curr_index when (TBL_INIT='0') else TBL_WPTR(MT_PTR_TYPE'range);
mt_curr_yaddr <= y_curr_index when (TBL_INIT='0') else TBL_RPTR(MT_PTR_TYPE'range);
mt_next_yaddr <= y_next_index when (TBL_INIT='0') else TBL_RPTR(MT_PTR_TYPE'range);
mt_curr_xaddr <= x_curr_index when (TBL_INIT='0') else TBL_RPTR(MT_PTR_TYPE'range);
mt_next_xaddr <= x_next_index when (TBL_INIT='0') else TBL_RPTR(MT_PTR_TYPE'range);
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
GEN:for i in 0 to L-1 generate
signal mg : RANDOM_NUMBER_TYPE;
begin
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
mt_write(i) <= z_val when (TBL_INIT='0') else TBL_WE(i);
mt_wdata(i) <= z(i) when (TBL_INIT='0') else TBL_WDATA(WIDTH*(i+1)-1 downto WIDTH*i);
TBL_RDATA(WIDTH*(i+1)-1 downto WIDTH*i) <= mt_rdata(i);
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
MT_Y_U:if (i = 0) generate
signal mt_curr_upper : std_logic_vector(UPPER'range);
begin
U:MT32_1W1R_RAM
generic map(
DEPTH => MT_PTR_TYPE'length,
ID => i
)
port map (
CLK => CLK,
WE => mt_write(0),
WADDR => mt_waddr,
WDATA => mt_wdata(0),
RADDR => mt_next_yaddr,
RDATA => mt_rdata(0)
);
process (CLK, RST) begin
if (RST = '1') then
mt_curr_upper <= (others => '0');
elsif (CLK'event and CLK = '1') then
if (mt_read = '1') then
mt_curr_upper <= mt_rdata(i)(UPPER'range);
end if;
end if;
end process;
mt_ydata(0 )(UPPER'range) <= mt_curr_upper;
mt_ydata(L-1)(LOWER'range) <= mt_rdata(0)(LOWER'range);
end generate;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
MT_Y_M: if (i > 0) generate
U: MT32_1W1R_RAM
generic map(
DEPTH => MT_PTR_TYPE'length,
ID => i
)
port map (
CLK => CLK,
WE => mt_write(i),
WADDR => mt_waddr,
WDATA => mt_wdata(i),
RADDR => mt_curr_yaddr,
RDATA => mt_rdata(i)
);
mt_ydata(i )(UPPER'range) <= mt_rdata(i)(UPPER'range);
mt_ydata(i-1)(LOWER'range) <= mt_rdata(i)(LOWER'range);
end generate;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
MT_X:block
signal mt_xaddr : MT_PTR_TYPE;
begin
mt_xaddr <= mt_curr_xaddr when (i >= (M mod L)) else
mt_next_xaddr;
U: MT32_1W1R_RAM
generic map(
DEPTH => MT_PTR_TYPE'length,
ID => L+i
)
port map (
CLK => CLK,
WE => mt_write(i),
WADDR => mt_waddr,
RADDR => mt_xaddr,
WDATA => mt_wdata(i),
RDATA => mt_xdata((L+i-(M mod L)) mod L)
);
end block;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
mg <= MATRIX_A when (mt_ydata(i)(0) = '1') else (others => '0');
z(i) <= mt_xdata(i) xor shift_right(mt_ydata(i),1) xor mg;
random_number(i) <= Tempering(z(i));
end generate;
random_valid <= z_val;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
process(CLK,RST) begin
if (RST = '1') then
RND_VAL <= '0';
RND_NUM <= (others => '0');
elsif (CLK'event and CLK = '1') then
RND_VAL <= random_valid;
for i in 0 to L-1 loop
RND_NUM(WIDTH*(i+1)-1 downto WIDTH*i) <= random_number(i);
end loop;
end if;
end process;
end RTL;
-----------------------------------------------------------------------------------
-- --
-- Title : Test Bench for MT32_GEN --
-- Module Name : TEST_BENCH --
-- Version : 0.0.3 --
-- Created : 2012/3/28 --
-- File Name : TEST_BENCH.vhd --
-- Author : Ichiro Kawazome <[email protected]> --
-- --
-- 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.MT19937AR.SEED_VECTOR;
use work.MT19937AR.PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE;
use work.MT19937AR.NEW_PSEUDO_RANDOM_NUMBER_GENERATOR;
use work.MT19937AR.GENERATE_RANDOM_STD_LOGIC_VECTOR;
use work.MT19937AR.GENERATE_RANDOM_REAL2;
entity TEST_BENCH is
end TEST_BENCH;
architecture MODEL of TEST_BENCH is
component MT32_GEN
generic (
N : integer;
M : integer;
L : integer
);
port (
CLK : in std_logic;
RST : in std_logic;
TBL_INIT : in std_logic;
TBL_WE : in std_logic_vector( L-1 downto 0);
TBL_WPTR : in std_logic_vector( 15 downto 0);
TBL_WDATA : in std_logic_vector(32*L-1 downto 0);
TBL_RPTR : in std_logic_vector( 15 downto 0);
TBL_RDATA : out std_logic_vector(32*L-1 downto 0);
RND_RUN : in std_logic;
RND_VAL : out std_logic;
RND_NUM : out std_logic_vector(32*L-1 downto 0)
);
end component;
constant WIDTH : integer := 32;
constant LANE : integer := 1;
constant PERIOD : time := 10 ns;
constant DELAY : time := 1 ns;
constant N : integer := 624;
signal CLK : std_logic;
signal RST : std_logic;
signal TBL_INIT : std_logic;
signal TBL_WE : std_logic_vector( LANE-1 downto 0);
signal TBL_WPTR : std_logic_vector( 15 downto 0);
signal TBL_WDATA : std_logic_vector(WIDTH*LANE-1 downto 0);
signal TBL_RPTR : std_logic_vector( 15 downto 0);
signal TBL_RDATA : std_logic_vector(WIDTH*LANE-1 downto 0);
signal RND_RUN : std_logic;
signal RND_VAL : std_logic;
signal RND_NUM : std_logic_vector(WIDTH*LANE-1 downto 0);
begin
U: MT32_GEN
generic map(
N => N,
M => 397,
L => LANE
)
port map(
CLK => CLK,
RST => RST,
TBL_INIT => TBL_INIT,
TBL_WE => TBL_WE,
TBL_WPTR => TBL_WPTR,
TBL_WDATA => TBL_WDATA,
TBL_RPTR => TBL_RPTR,
TBL_RDATA => TBL_RDATA,
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 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;
---------------------------------------------------------------------------
-- Seed Numbers for Pseudo Random Number Generator.
---------------------------------------------------------------------------
variable seed : SEED_VECTOR(0 to 3) := (0 => X"00000123",
1 => X"00000234",
2 => X"00000345",
3 => X"00000456");
---------------------------------------------------------------------------
-- Pseudo Random Number Generator Instance.
---------------------------------------------------------------------------
variable prng : PSEUDO_RANDOM_NUMBER_GENERATOR_TYPE := NEW_PSEUDO_RANDOM_NUMBER_GENERATOR(seed);
---------------------------------------------------------------------------
-- Random number
---------------------------------------------------------------------------
variable vec : std_logic_vector(31 downto 0);
---------------------------------------------------------------------------
-- 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 wdata : std_logic_vector(WIDTH*LANE-1 downto 0);
variable rdata : std_logic_vector(WIDTH -1 downto 0);
variable count_run : integer;
variable count_val : integer;
variable count_max : integer;
constant RUN_WAIT : integer := 3;
begin
RST <= '1';
TBL_INIT <= '0';
TBL_WE <= (others => '0');
TBL_WPTR <= (others => '0');
TBL_WDATA <= (others => '0');
TBL_RPTR <= (others => '0');
RND_RUN <= '0';
WAIT_CLK(10);
RST <= '0';
WAIT_CLK(10);
TBL_INIT <= '1';
for i in 0 to N/LANE-1 loop
for l in 0 to LANE-1 loop
wdata(WIDTH*(l+1)-1 downto WIDTH*l) := std_logic_vector(prng.table(i*LANE+l));
end loop;
TBL_WDATA <= wdata;
TBL_WPTR <= std_logic_vector(to_unsigned(i*LANE,TBL_WPTR'length));
TBL_WE <= (others => '1');
WAIT_CLK(1);
end loop;
TBL_WE <= (others => '0');
WAIT_CLK(1);
for i in 0 to N/LANE-1 loop
TBL_RPTR <= std_logic_vector(to_unsigned(i*LANE,TBL_RPTR'length));
WAIT_CLK(2);
for l in 0 to LANE-1 loop
rdata := TBL_RDATA(WIDTH*(l+1)-1 downto WIDTH*l);
if (rdata /= std_logic_vector(prng.table(i*LANE+l))) then
WRITE(text_line, SPACE & "TBL_RDATA(");
WRITE(text_line, i*LANE+l);
WRITE(text_line, ")=" & TO_DEC_STRING(unsigned(rdata),10) & " prng.table=(");
WRITE(text_line, i*LANE+l);
WRITE(text_line, ")=" & TO_DEC_STRING(unsigned(prng.table(i*LANE+l)),10));
WRITELINE(OUTPUT, text_line);
assert (FALSE) report "Mismatch Initialzed table" severity FAILURE;
end if;
end loop;
-- WRITE(text_line, TO_DEC_STRING(unsigned(TBL_RPTR ), 6));
-- WRITE(text_line, SPACE);
-- WRITE(text_line, TO_DEC_STRING(unsigned(TBL_RDATA),10));
-- WRITELINE(OUTPUT, text_line);
end loop;
WAIT_CLK(10);
TBL_INIT <= '0';
WRITE(text_line, TAG & "1000 outputs of genrand_int32()");
WRITELINE(OUTPUT, text_line);
RND_RUN <= '1';
count_run := 0;
count_val := 0;
count_max := (1000/LANE)-1;
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
for l in 0 to LANE-1 loop
count_val := count_val + 1;
rdata := RND_NUM(32*(l+1)-1 downto 32*l);
WRITE(text_line, TO_DEC_STRING(unsigned(rdata),10));
WRITE(text_line, SPACE);
GENERATE_RANDOM_STD_LOGIC_VECTOR(prng,vec);
assert (rdata = vec)
report "Mismatch Random Number (" &
TO_DEC_STRING(to_unsigned(count_val,10),4,'0') & ") " &
TO_DEC_STRING(unsigned(rdata),10) & " /= " &
TO_DEC_STRING(unsigned( vec),10)
severity FAILURE;
if ((count_val*LANE+l) mod 5 = 0) then
WRITELINE(OUTPUT, text_line);
end if;
end loop;
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;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment