-------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: testbench for system test using Xilinx ML-402

-- 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.numeric_std.ALL;
USE work.package_utility.all;   

Library UNISIM;
use UNISIM.vcomponents.all;

ENTITY tb_ssram_frontend_wb IS
END tb_ssram_frontend_wb;

ARCHITECTURE behavior OF tb_ssram_frontend_wb IS 

	constant CLK_PERIOD : time := 10 ns;
	signal CLK_O	: std_logic := '1';
	signal RST_O	: std_logic := '1';
	signal CYC_O	: std_logic := '0';
	signal STB_O	: std_logic := '0';
	signal WE_O		: std_logic := '0';
	signal SEL_O	: unsigned(3 downto 0) := (others => '1');
	signal ACK_I	: std_logic;
	signal MRDY_O	: std_logic := '1';
	signal SRDY_I	: std_logic;
	signal ADDR_O	: unsigned(31 downto 0) := (others => '-');
	signal DAT_I	: unsigned(31 downto 0);
	signal DAT_O	: unsigned(31 downto 0) := (others => '-');

    SIGNAL ssram_d		: unsigned (32 - 1 DOWNTO 0) := (OTHERS => 'Z');
    SIGNAL ssram_dp		: unsigned (4 - 1 DOWNTO 0) := (OTHERS => 'Z');
    SIGNAL ssram_a		: unsigned (20 - 1 DOWNTO 0) := (OTHERS => '0');
    SIGNAL ssram_clk	: STD_LOGIC := '0';
    SIGNAL ssram_cke_n	: STD_LOGIC;
    SIGNAL ssram_adv	: STD_LOGIC;
    SIGNAL ssram_mode	: STD_LOGIC;
    SIGNAL ssram_bw_n	: unsigned(3 downto 0);
    SIGNAL ssram_we_n	: STD_LOGIC;
    SIGNAL ssram_oe_n	: STD_LOGIC;
    SIGNAL ssram_ce_n	: STD_LOGIC;
    SIGNAL ssram_zz		: STD_LOGIC;

    SIGNAL ssram_clk_fb	: STD_LOGIC;

	signal dout_rst		: std_logic := '0';
	signal dout_reg		: unsigned(31 downto 0);
	signal dout_cnt		: natural range 0 to 255;

BEGIN

	ssram_clk_fb	<= ssram_clk after 0.5 ns;

inst_ssram_frontend_wb : entity work.ssram_frontend_wb
	GENERIC MAP
	(
		addr_width		=> 20,
		data_width		=> 32,
		parity_width	=> 4
	)
	PORT MAP
	(
		-- J-Bus domain
		RST_I		=> RST_O,
		CLK_I		=> CLK_O,
		CYC_I		=> CYC_O,
		STB_I		=> STB_O,
		SEL_I		=> SEL_O,
		WE_I		=> WE_O,
		ACK_O		=> ACK_I,
		SRDY_O		=> SRDY_I,
		MRDY_I		=> MRDY_O,
		ADDR_I		=> ADDR_O,
		DAT_I		=> DAT_O,
		DAT_O		=> DAT_I,
		
		-- Sync SRAM domain
		ssram_clk_o		=> ssram_clk,
		ssram_clk_fb	=> ssram_clk_fb,
		ssram_cke_n		=> ssram_cke_n,
		ssram_ce_n		=> ssram_ce_n,
		ssram_oe_n		=> ssram_oe_n,
		ssram_we_n		=> ssram_we_n,
		ssram_adv		=> ssram_adv,
		ssram_mode		=> ssram_mode,
		ssram_zz		=> ssram_zz,
		ssram_a			=> ssram_a,
		ssram_d			=> ssram_d,
		ssram_dp		=> ssram_dp,
		ssram_bw_n		=> ssram_bw_n
	);
	
inst_ssram : entity work.cy7c1354
    -- PORT MAP Declarations
    PORT MAP 
    (
		Dq		=> STD_LOGIC_VECTOR(ssram_d),   	-- Data I/O
		Dpq		=> STD_LOGIC_VECTOR(ssram_dp),   	-- Data I/O
		Addr	=> STD_LOGIC_VECTOR(ssram_a(19 downto 2)),   	-- Address
		Mode	=> ssram_mode, 	-- Burst Mode
		Clk		=> ssram_clk,      -- Clk
		CEN_n	=> ssram_cke_n,                                   -- CEN#
		AdvLd_n	=> ssram_adv,                                   -- Adv/Ld#
		Bwa_n	=> ssram_bw_n(0),                                   -- Bwa#
		Bwb_n	=> ssram_bw_n(1),                                   -- BWb#
		Bwc_n	=> ssram_bw_n(2),                                   -- Bwc#
		Bwd_n	=> ssram_bw_n(3),                                   -- BWd#
		Rw_n	=> ssram_we_n,                                   -- RW#
		Oe_n	=> ssram_oe_n,                                   -- OE#
		Ce1_n	=> ssram_ce_n,                                   -- CE1#
		Ce2		=> '1',                                   -- CE2
		Ce3_n	=> '0',                                   -- CE3#
		Zz		=> ssram_zz
    );

read_register:
	process(CLK_O)
	begin
		if rising_edge(CLK_O) then
			if dout_rst = '1' then
				dout_cnt <= 0;
			elsif ACK_I = '1' and WE_O = '0' then
				dout_reg	<= DAT_I;
				dout_cnt 	<= dout_cnt + 1;
			end if;
		end if;
	end process;

CLK_GEN: process
	begin
		wait for CLK_PERIOD/2;
		CLK_O <= not CLK_O;
	end process;

STIMULUS: process

	begin

		wait for 5*CLK_PERIOD;
		RST_O <= '0';
		
		wait until rising_edge(CLK_O);
		-- 8 single cycles
		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '1';
		DAT_O	<= X"1234_0000";
		ADDR_O	<= X"0000_0000";
		
		for i in 0 to 31 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			DAT_O	<= DAT_O + 1;
			ADDR_O	<= ADDR_O + 4;
		end loop;
	
		STB_O	<= '0';
		wait until rising_edge(CLK_O);
		CYC_O	<= '0';

		------------------------------------------------------------
		wait for 3*CLK_PERIOD;
		------------------------------------------------------------

		-- 8-word burst cycle
		dout_rst	<= '1';
		wait until rising_edge(CLK_O);
		dout_rst	<= '0';
		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0000";

		for i in 0 to 31 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;
		
		STB_O	<= '0';
		wait until rising_edge(CLK_O) and dout_cnt = 31;
		CYC_O	<= '0';

		------------------------------------------------------------
		wait for 3*CLK_PERIOD;
		------------------------------------------------------------

		wait until rising_edge(CLK_O);
		-- 1-word burst cycle
		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SEL_O	<= "0011";
		ADDR_O	<= X"0000_0010";
		DAT_O	<= X"DEADBEEF";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';
		wait until rising_edge(CLK_O);
		CYC_O	<= '0';

		------------------------------------------------------------
		wait for 3*CLK_PERIOD;
		------------------------------------------------------------

		wait until rising_edge(CLK_O);
		-- 1-word burst cycle
		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0010";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';
		wait until rising_edge(CLK_O) and ACK_I = '1';
		CYC_O	<= '0';

		------------------------------------------------------------
		wait for 3*CLK_PERIOD;
		------------------------------------------------------------

		-- 8-word burst cycle
		dout_rst	<= '1';
		wait until rising_edge(CLK_O);
		dout_rst	<= '0';

		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0000";

		for i in 0 to 31 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;
		
		STB_O	<= '0';
		wait until rising_edge(CLK_O) and dout_cnt = 31;
		CYC_O	<= '0';

		------------------------------------------------------------
		wait for 10*CLK_PERIOD;
		------------------------------------------------------------


		-- 8-word burst cycle
		dout_rst	<= '1';
		wait until rising_edge(CLK_O);
		dout_rst	<= '0';

		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0000";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;

		STB_O	<= '0';
		wait until rising_edge(CLK_O) and dout_cnt = 7;
		CYC_O	<= '0';


		------------------------------------------------------------
		wait for 10*CLK_PERIOD;
		------------------------------------------------------------

		-- 8-word burst cycle
		dout_rst	<= '1';
		wait until rising_edge(CLK_O);
		dout_rst	<= '0';

		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SEL_O	<= "1111";
		DAT_O	<= X"1111_0000";
		ADDR_O	<= X"0000_0000";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			DAT_O	<= DAT_O + 1;
			ADDR_O	<= ADDR_O + 4;
		end loop;

		WE_O	<= '0';
		ADDR_O	<= X"0000_0000";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;

		STB_O	<= '0';
		wait until rising_edge(CLK_O) and dout_cnt = 7;
		CYC_O	<= '0';

		-- 8-word burst cycle
		dout_rst	<= '1';
		wait until rising_edge(CLK_O);
		dout_rst	<= '0';

		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SEL_O	<= "1111";
		DAT_O	<= X"2222_0000";
		ADDR_O	<= X"0000_0400";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			DAT_O	<= DAT_O + 1;
			ADDR_O	<= ADDR_O + 4;
		end loop;

		WE_O	<= '0';
		ADDR_O	<= X"0000_0400";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;

		STB_O	<= '0';
		wait until rising_edge(CLK_O) and dout_cnt = 7;
		CYC_O	<= '0';

		-- 8-word burst cycle
		dout_rst	<= '1';
		wait until rising_edge(CLK_O);
		dout_rst	<= '0';

		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SEL_O	<= "1111";
		DAT_O	<= X"3333_0000";
		ADDR_O	<= X"0000_0800";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			DAT_O	<= DAT_O + 1;
			ADDR_O	<= ADDR_O + 4;
		end loop;

		WE_O	<= '0';
		ADDR_O	<= X"0000_0800";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;

		STB_O	<= '0';
		wait until rising_edge(CLK_O) and dout_cnt = 7;
		CYC_O	<= '0';

		-- 8-word burst cycle
		dout_rst	<= '1';
		wait until rising_edge(CLK_O);
		dout_rst	<= '0';

		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SEL_O	<= "1111";
		DAT_O	<= X"4444_0000";
		ADDR_O	<= X"0000_0C00";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			DAT_O	<= DAT_O + 1;
			ADDR_O	<= ADDR_O + 4;
		end loop;

		WE_O	<= '0';
		ADDR_O	<= X"0000_0C00";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;

		STB_O	<= '0';
		wait until rising_edge(CLK_O) and dout_cnt = 7;
		CYC_O	<= '0';

		------------------------------------------------------------
		wait for 10*CLK_PERIOD;
		------------------------------------------------------------
		
		-- 8-word burst cycle
		dout_rst	<= '1';
		wait until rising_edge(CLK_O);
		dout_rst	<= '0';

		CYC_O	<= '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0000";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;

		ADDR_O	<= X"0000_0400";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;


		ADDR_O	<= X"0000_0800";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;


		ADDR_O	<= X"0000_0C00";

		for i in 0 to 7 loop
			wait until rising_edge(CLK_O) and SRDY_I = '1';
			ADDR_O	<= ADDR_O + 4;
		end loop;

		STB_O	<= '0';
		wait until rising_edge(CLK_O) and dout_cnt = 31;
		CYC_O	<= '0';
		
		wait; 
	
	end process;
	
END;
