-------------------------------------------------------------------------
-- Project: FIFO, generic FIFOs written in VHDL
-- Release 1
--
-- Copyright (C) 2007 J. Ahrensfeld
--
-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.
--
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public
-- License along with this library; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
--
-- For questions and ideas, please contact the author at jens@jayfield.org
--
-----------------------------------------------------------------------

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.MATH_REAL.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE STD.TEXTIO.ALL;

-- LIBRARY WORK;
-- USE.YOURLIB.WHATELSE

ENTITY tb_fifo_async IS
END tb_fifo_async;

ARCHITECTURE behavior OF tb_fifo_async IS 

	--Constants
	constant PERIOD_W 	: time := 10 ns;
	constant PERIOD_R 	: time := 7.5 ns;
	constant ADDR_WIDTH : integer := 3;
	constant DATA_WIDTH : integer := 8;

	--Inputs
	signal rst					: STD_LOGIC := '1';
	signal clk_w				: STD_LOGIC := '0';
	signal clk_r				: STD_LOGIC := '0';
	signal we					: STD_LOGIC := '0';
	signal re					: STD_LOGIC := '0';
	signal din					: unsigned (7 downto 0);
	--Outputs

	signal dout					: unsigned (7 downto 0);
	signal fifo_full			: STD_LOGIC;
	signal fifo_empty			: STD_LOGIC;
	signal fifo_almost_full		: STD_LOGIC;
	signal fifo_almost_empty	: STD_LOGIC;

	signal write_en				: STD_LOGIC := '0';
	signal read_en				: STD_LOGIC := '0';

	signal ref_r				: unsigned (7 downto 0);

BEGIN

	-- Instantiate the Unit Under Test (UUT)
	uut: entity work.fifo_async
	GENERIC MAP
	(
		addr_width					=> ADDR_WIDTH,
		data_width					=> DATA_WIDTH,
		almost_full_thresh			=> 6,
		almost_empty_thresh			=> 2,
		allow_full_writes			=> false,
		allow_empty_reads			=> false,
		do_last_read_update			=> false
	)
	PORT MAP
	(
		rst			=>	rst,
		clk_w		=>	clk_w,
		clk_r		=>	clk_r,
		we			=>	we,
		re			=>	re,
		data_w		=>	din,
		data_r		=>	dout,
		fifo_full	=>	fifo_full,
		fifo_empty	=>	fifo_empty,
		fifo_afull	=>	fifo_almost_full,
		fifo_aempty	=>	fifo_almost_empty

	);

 	tb_clk_w : PROCESS
	BEGIN
		clk_w <= not clk_w;
		wait for PERIOD_W/2;
	END PROCESS;

 	tb_clk_r : PROCESS
	BEGIN
		clk_r <= not clk_r;
		wait for PERIOD_R/2;
	END PROCESS;

 	tb_write : PROCESS
	BEGIN

		-- Wait 100 ns for global reset to finish
		wait for 5*PERIOD_W;
		rst			<= '0';
		wait for 7*PERIOD_W;
		write_en <= '1';
		wait for 25*PERIOD_W;
		write_en <= '0';
		wait for 7*PERIOD_W;
		write_en <= '1';
		wait for 25*PERIOD_W;
		write_en <= '0';
		wait for 7*PERIOD_W;
		write_en <= '1';
		wait for 1*PERIOD_W;
		write_en <= '0';
		wait for 1*PERIOD_W;
		write_en <= '1';
		wait for 1*PERIOD_W;
		write_en <= '0';
		wait for 3*PERIOD_W;
		write_en <= '1';
		wait for 4*PERIOD_W;
		write_en <= '0';
		wait for 17*PERIOD_W;
		write_en <= '1';
		wait for 55*PERIOD_W;
		write_en <= '0';
		wait for 1*PERIOD_W;
		write_en <= '1';
		wait for 1*PERIOD_W;
		write_en <= '0';
		wait for 3*PERIOD_W;
		write_en <= '1';
		wait for 44*PERIOD_W;
		write_en <= '0';
		
		wait; 
		
	END PROCESS;

 	tb_read : PROCESS
	BEGIN

		-- Wait 100 ns for global reset to finish
		wait for 25*PERIOD_R;
		read_en <= '1';
		wait for 25*PERIOD_R;
		read_en <= '0';
		wait for 25*PERIOD_R;
		read_en <= '1';
		wait for 1*PERIOD_R;
		read_en <= '0';
		wait for 5*PERIOD_R;
		read_en <= '1';
		wait for 1*PERIOD_R;
		read_en <= '0';
		wait for 5*PERIOD_R;
		read_en <= '1';
		wait for 1*PERIOD_R;
		read_en <= '0';
		wait for 5*PERIOD_R;
		read_en <= '1';
		wait for 1*PERIOD_R;
		read_en <= '0';
		wait for 5*PERIOD_R;
		read_en <= '1';
		wait for 1*PERIOD_R;
		read_en <= '0';
		wait for 5*PERIOD_R;
		read_en <= '1';
		wait for 1*PERIOD_R;
		read_en <= '0';
		wait for 5*PERIOD_R;
		read_en <= '1';
		wait for 1*PERIOD_R;
		read_en <= '0';
		wait for 7*PERIOD_R;
		read_en <= '1';
		wait for 15*PERIOD_R;
		read_en <= '0';
		wait; 
		
	END PROCESS;
	
	we <= write_en;
	
 	tb_w : PROCESS(rst, clk_w)
	BEGIN

		if rst = '1' then
			din <= (others => '0');
		elsif rising_edge(clk_w) then
			if we = '1' and fifo_full = '0' then
				din <= din + 1;
			end if;				
		end if;	

	END PROCESS;
	
	re	<= read_en;
	
 	tb_r : PROCESS(rst, clk_r)
	BEGIN

		if rst = '1' then
			ref_r <= (others => '0');
		elsif rising_edge(clk_r) then
			if re = '1' and fifo_empty = '0' then
				assert ref_r = dout report "FIFO read error!" severity failure;
				ref_r <= ref_r + 1;
			end if;				
		end if;	
		
	END PROCESS;

END behavior;