------------------------------
--
-- sram_regbased_tb.vhdl
--
-- created: 4/10/18
-- by: johnsontimoj
-- rev: 0
--
-- testbench for reg based SRAM example
-- of sram_regbased.vhdl
--
-------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
--use work.my_local_math.all;

entity sram_controller_tb is
	generic(
				ROW_ADDR_WIDTH_tb:	positive := 4;
				COL_ADDR_WIDTH_tb:	positive := 4;
				DATA_WIDTH_tb:			positive := 8
			);
	-- no port entry - testbench
end entity;

architecture testbench of sram_controller_tb is

	signal	CLK					:	std_logic;
	signal	RSTB					:	std_logic;
	signal	ADDR					:	std_logic_vector(((ROW_ADDR_WIDTH_tb + COL_ADDR_WIDTH_tb) - 1) downto 0);
	signal	DATA_IN				:	std_logic_vector((DATA_WIDTH_tb - 1) downto 0);
	signal	RD						:	std_logic;
	signal	WR						:	std_logic;
	signal	BUSY					:	std_logic;
	signal	DONE					:	std_logic;
	
	signal	RAS_N					:	std_logic;
	signal	CAS_N					:	std_logic;
	signal	WE_N					:	std_logic;
	signal	ADDR_OUT				:	std_logic_vector((ROW_ADDR_WIDTH_tb - 1) downto 0);
	signal	DATA_TO_SRAM		:	std_logic_vector((DATA_WIDTH_tb - 1) downto 0);
	signal	DATA_OUT				:	std_logic_vector((DATA_WIDTH_tb - 1) downto 0);
	signal	ROW_ACTIVE			:	std_logic;
	
	constant PER	:	time	:= 20 ns;
		
	--------------------------------
	-- Component prototype
	---------------------------------
component sram_controller is
	generic(
			-- ROW_ADDRESS_WIDTH MUST BE > COL_ADDR_WIDTH
			ROW_ADDR_WIDTH:	positive := 6;
			COL_ADDR_WIDTH:	positive := 4;
			DATA_WIDTH:			positive := 16
			);
	port(
			i_clk:		in std_logic;
			i_rstb: 		in std_logic;

			i_address:	in std_logic_vector(((ROW_ADDR_WIDTH + COL_ADDR_WIDTH) - 1) downto 0);
			i_data_in:	in std_logic_vector((DATA_WIDTH - 1) downto 0);
			i_read:		in std_logic;
			i_write:		in std_logic;

			o_busy:		out std_logic;
			o_done:		out std_logic;

			-- SRAM interface
			o_ras_n:		out std_logic;
			o_cas_n:		out std_logic;
			o_we_n:		out std_logic;
			o_address:	out std_logic_vector((ROW_ADDR_WIDTH - 1) downto 0);
			o_data_to_sram:	out std_logic_vector((DATA_WIDTH - 1) downto 0)
		);
end component;

component sram_memory is
	generic(
				ROW_ADDR_WIDTH:	positive := 6;
				COL_ADDR_WIDTH:	positive := 4;
				DATA_WIDTH:			positive := 16
			);
	port(
			i_clk:				in std_logic;
			i_rstb:				in std_logic;
			i_ras_n:				in std_logic;
			i_cas_n:				in std_logic;
			i_we_n:				in std_logic;
			i_addr_in:			in std_logic_vector((ROW_ADDR_WIDTH - 1) downto 0);
			i_data_in:			in std_logic_vector((DATA_WIDTH - 1) downto 0);
			o_data_out:			out std_logic_vector((DATA_WIDTH - 1) downto 0);
			o_row_active:		out std_logic
			);
end component;
	-----------------------------------
	
	begin
	
	------------------------------------
	-- Device under test (DUT)
	------------------------------------

	ctlr: sram_controller
		generic map(
						ROW_ADDR_WIDTH => ROW_ADDR_WIDTH_tb,
						COL_ADDR_WIDTH => COL_ADDR_WIDTH_tb,
						DATA_WIDTH		=> DATA_WIDTH_tb
					)
		port map(
			i_clk				=>	CLK,		
			i_rstb			=> RSTB,
 
			i_address		=> ADDR,		
			i_data_in		=> DATA_IN,		
			i_read			=> RD,		
			i_write			=> WR,	
 
			o_busy			=> BUSY, 
			o_done			=> DONE,

			o_ras_n			=> RAS_N,
			o_cas_n			=> CAS_N,
			o_we_n			=> WE_N,
			o_address		=> ADDR_OUT,
			o_data_to_sram	=> DATA_TO_SRAM
		);

	mem: sram_memory
		generic map(
						ROW_ADDR_WIDTH => ROW_ADDR_WIDTH_tb,
						COL_ADDR_WIDTH => COL_ADDR_WIDTH_tb,
						DATA_WIDTH		=> DATA_WIDTH_tb
					)
		port map(
			i_clk					=>	CLK,		
			i_rstb				=> RSTB,
			i_ras_n				=> RAS_N,		
			i_cas_n				=> CAS_N,		
			i_we_n				=> WE_N,		
			i_addr_in			=> ADDR_OUT,		
			i_data_in			=> DATA_TO_SRAM,	
			o_data_out			=> DATA_OUT,
			o_row_active 		=> ROW_ACTIVE
		);                   	


	-------------------------------------
	-- Test processes
	-------------------------------------
	
   -- Clock process
	clock: process		-- note - no sensitivity list allowed
   begin
		CLK <= '0';
		wait for PER/2;
		infinite: loop
			CLK <= not CLK; wait for PER/2;
		end loop;				
	end process;
	
	-- Reset process
	reset: process		-- note - no sensitivity list allowed
   begin
		RSTB <= '0';
		wait for PER * 2;
		RSTB <= '1';
		wait;
	end process;
	
	-- Run Process
	run: Process		-- note - no sensitivity list allowed
	begin
		-- Initalize values
		ADDR <= (others => '0');
		DATA_IN <= (others => '0');
		WR <= '0';
		RD <= '0';

		wait for PER * 4;
			
		-- write to all addresses
		for i in 0 to (2**(ROW_ADDR_WIDTH_tb + COL_ADDR_WIDTH_tb)) loop
			ADDR <= std_logic_vector(to_unsigned(i,(ROW_ADDR_WIDTH_tb + COL_ADDR_WIDTH_tb)));
			DATA_IN <= std_logic_vector(to_unsigned(i,DATA_WIDTH_tb));
			WR <= '1';
			wait for PER * 2;
		
			assert ROW_ACTIVE = '1'
			report "ERROR: Row Active error " & 
					" measured " & std_logic'image(ROW_ACTIVE) & 
					" expected " & integer'image(1)
			severity error;

			wait for PER * 2;
			WR <= '0';
			wait for PER * 2;
		end loop;
		
		for i in 0 to (2**(ROW_ADDR_WIDTH_tb + COL_ADDR_WIDTH_tb)) loop
			ADDR <= std_logic_vector(to_unsigned(i,(ROW_ADDR_WIDTH_tb + COL_ADDR_WIDTH_tb)));
			DATA_IN <= (others => '0');
			RD <= '1';
			wait for PER * 2;
		
			assert ROW_ACTIVE = '1'
			report "ERROR: Row Active error " & 
					" measured " & std_logic'image(ROW_ACTIVE) & 
					" expected " & integer'image(1)
			severity error;

			wait for PER * 2;
			RD <= '0';
			wait for PER * 2;
			
		assert DATA_OUT = std_logic_vector(to_unsigned(i,DATA_WIDTH_tb))
			report "ERROR: Data r/w error: " & 
					" measured " & integer'image(to_integer(unsigned(DATA_OUT))) & 
					" expected " & integer'image(i)
			severity error;
			
		assert ROW_ACTIVE = '0'
			report "ERROR: Row Active error " & 
					" measured " & std_logic'image(ROW_ACTIVE) & 
					" expected " & integer'image(0)
			severity error;	
			
		end loop;
		
		report "========================================";
		report "ALL SRAM CONTROLLER TESTS COMPLETED";
		report "========================================";
		
		
		-- Wait a a few clocks and terminate the sim (independent of tool settings)
		
		wait for PER * 4;
		
		assert false
			report "SRAM CONTROLLER TESTBENCH COMPLETE."
			severity failure;

	end process;
	
	------------------------------------------
	-- End test processes
	------------------------------------------
	
end architecture;