-------------------------------------------------------------------------
-- 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.vga_types.all;

ENTITY tb_vga_frontend IS
END tb_vga_frontend;

ARCHITECTURE behavior OF tb_vga_frontend IS 

	constant tsvga			: vga_timespec_t := ts_vga_testbench;
	constant CLK_PERIOD		: time := 10 ns;
	constant VGA_CLK_PERIOD	: time := (integer(1E9) / tsvga.f_pxl_clk) * 1 ns;
	signal CLK_O			: std_logic := '1';
	signal RST_O			: std_logic := '1';

	-- Master
	signal CYC_O			: std_logic;
	signal STB_O			: std_logic;
	signal WE_O				: std_logic;
	signal SEL_O			: unsigned(3 downto 0) := (others => '1');
	signal ACK_I			: std_logic := '0';
	signal MRDY_O			: std_logic := '1';
	signal SRDY_I			: std_logic := '0';
	signal ADDR_O			: unsigned(31 downto 0) := (others => '-');
	signal MDAT_I			: unsigned(31 downto 0) := (others => '-');
	signal MDAT_O			: unsigned(31 downto 0) := (others => '-');

	-- Slave
	signal CYC_I			: std_logic := '0';
	signal STB_I			: std_logic := '0';
	signal WE_I				: std_logic := '0';
	signal SEL_I			: unsigned(3 downto 0);
	signal ACK_O			: std_logic;
	signal MRDY_I			: std_logic;
	signal SRDY_O			: std_logic;
	signal ADDR_I			: unsigned(31 downto 0) := (others => '-');
	signal SDAT_I			: unsigned(31 downto 0) := (others => '-');
	signal SDAT_O			: unsigned(31 downto 0) := (others => '-');

	-- VGA signals
	signal vga_clk			: std_logic := '1';
	signal vga_red			: unsigned(7 downto 0);
	signal vga_green		: unsigned(7 downto 0);
	signal vga_blue			: unsigned(7 downto 0);
	signal vga_blank_n		: std_logic;
	signal vga_sync_n		: std_logic;
	signal vga_hsync		: std_logic;
	signal vga_vsync		: std_logic;
	signal vga_en			: std_logic;


BEGIN

inst_vga_frontend : entity work.vga_frontend
	GENERIC MAP
	(
		fifo_depth					=> 256,
		fifo_almost_full_thresh		=> 240,
		fifo_almost_empty_thresh	=> 16,
		tsvga						=> tsvga
	)
	PORT MAP
	(
		-- System signals
		RST_I			=> RST_O,
		CLK_I			=> CLK_O,

		-- JBUS Master signals
		CYC_O			=> CYC_I,
		STB_O			=> STB_I,
		WE_O			=> WE_I,
		SEL_O			=> SEL_I,
		ACK_I			=> ACK_O,
		SRDY_I			=> SRDY_O,
		MRDY_O			=> MRDY_I,
		ADDR_O			=> ADDR_I,
		MDAT_I			=> MDAT_O,
		MDAT_O			=> MDAT_I,

		-- JBUS Slave signals
		CYC_I			=> CYC_O,
		STB_I			=> STB_O,
		WE_I			=> WE_O,
		SEL_I			=> SEL_O,
		ACK_O			=> ACK_I,
		SRDY_O			=> SRDY_I,
		MRDY_I			=> MRDY_O,
		ADDR_I			=> ADDR_O,
		SDAT_I			=> SDAT_O,
		SDAT_O			=> SDAT_I,
		
		-- VGA signals
		vga_clk_in		=> vga_clk,
		vga_clk_ce		=> vga_en,
		vga_red			=> vga_red,
		vga_green		=> vga_green,
		vga_blue		=> vga_blue,
		vga_blank_n		=> vga_blank_n,
		vga_sync_n		=> vga_sync_n,
		vga_hsync		=> vga_hsync,
		vga_vsync		=> vga_vsync
	);

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

VGA_CLK_GEN: process
	begin
		wait for VGA_CLK_PERIOD/2;
		vga_clk <= not vga_clk after 3 ns;
	end process;

-- Slave
	SRDY_O	<= CYC_I;
	
	process(CLK_O)
	begin
		if rising_edge(CLK_O) then
			if RST_O = '1' then
				MDAT_O	<= X"00000000";
			elsif (CYC_I and STB_I) = '1' then
				MDAT_O	<= MDAT_O + 1;
				ACK_O	<= '1';
			else
				ACK_O	<= '0';
			end if;
		end if;
	end process;

-- Master
STIMULUS: process

	begin

		wait for 6*CLK_PERIOD;
		RST_O <= '0';
		wait for 60*CLK_PERIOD;

		-- Enable master
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SDAT_O	<= X"0000_0002";
		ADDR_O	<= X"0000_0000";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Read status
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0000";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Read resolution X
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0018";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Read resolution Y
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_001C";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Read Cursor X
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0008";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Read Cursor Y
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_000C";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Write char 1
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SDAT_O	<= X"0000_0035";
		ADDR_O	<= X"0000_0004";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';
		
		-- Read char 1
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0004";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';
		
		-- Write char 2
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SDAT_O	<= X"0000_0045";
		ADDR_O	<= X"0000_0004";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Read char 2
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0004";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';
		
		-- Read Cursor X
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0008";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Read Cursor Y
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_000C";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Set Cursor X
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SDAT_O	<= X"0000_0012";
		ADDR_O	<= X"0000_0008";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';
		
		-- Set Cursor Y
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '1';
		SDAT_O	<= X"0000_0014";
		ADDR_O	<= X"0000_000C";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';
		
		-- Read Cursor X
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_0008";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		-- Read Cursor Y
		CYC_O	<= '1';
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '1';
		WE_O	<= '0';
		ADDR_O	<= X"0000_000C";
		wait until rising_edge(CLK_O) and SRDY_I = '1';
		STB_O	<= '0';

		wait until rising_edge(CLK_O);
		CYC_O	<= '0';

		

		wait; 
	
	end process;
	
END;
