-------------------------------------------------------------------------
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
-- This file: Testbench for JCPU
--            also writes 'opc.lst' for JASM-assembler
--
-- Copyright (C) 2007 J. Ahrensfeld
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program 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 General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-- 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;

library work;
use work.mips_types.all;
use work.mips_instr.all;
use work.async_types.all;
use work.async_defs.all;

ENTITY mips_sys IS
	GENERIC 
	(
		ICACHE_SIZE			: natural := 512;	-- words
		DCACHE_SIZE			: natural := 512;	-- words
		SRAM_ADDR_WIDTH		: integer := 14;
		FLASH_ADDR_WIDTH	: integer := 14
	);
	PORT
	(
		eb				: in  std_logic;
		nmi				: in  std_logic;
		rst				: in  std_logic;
		clk				: in  std_logic;
		flash_cs_n		: out std_logic;
		flash_oe_n		: out std_logic;
		flash_we_n		: out std_logic;
		flash_be_n		: out unsigned(3 downto 0);
		sram_cs_n		: out std_logic;
		sram_we_n		: out std_logic;
		sram_oe_n		: out std_logic;
		sram_be_n		: out unsigned(3 downto 0);
		sram_a			: out unsigned(SRAM_ADDR_WIDTH-1 downto 0);
		sram_d			: inout unsigned(31 downto 0);
		flash_a			: out unsigned(FLASH_ADDR_WIDTH-1 downto 0);
		flash_d			: inout unsigned(31 downto 0);
		
		gpo0			: out unsigned(31 downto 0);
		gpo1			: out unsigned(31 downto 0);
		gpi0			: in  unsigned(31 downto 0);
		gpi1			: in  unsigned(31 downto 0);

		rx				: in std_logic;
		tx				: out std_logic;

		debug			: out unsigned(1 downto 0)
	);
END mips_sys;

ARCHITECTURE behavior OF mips_sys IS 

	-- Master 
	signal ACK_I		: STD_LOGIC := '0';
	signal SRDY_I		: STD_LOGIC := '0';
	signal ADDR_O		: unsigned(31 downto 0);
	signal DAT_I		: unsigned(31 downto 0) := (others => '0');
	signal DAT_O		: unsigned(31 downto 0);
	signal WE_O			: STD_LOGIC;
	signal SEL_O		: unsigned(3 downto 0);
	signal CYC_O		: STD_LOGIC;
	signal STB_O		: STD_LOGIC;
	signal MRDY_O		: STD_LOGIC;
	signal INT			: unsigned (5 downto 0) := (others => '0');
	
	-- Slaves
	signal CYC_I_rom	: std_logic;
	signal ACK_O_rom	: std_logic;
	signal SRDY_O_rom	: std_logic;
	signal DAT_O_rom	: unsigned(31 downto 0);

	signal CYC_I_flash	: std_logic;
	signal ACK_O_flash	: std_logic;
	signal SRDY_O_flash	: std_logic;
	signal DAT_O_flash	: unsigned(31 downto 0);

	signal CYC_I_sram	: std_logic;
	signal ACK_O_sram	: std_logic;
	signal SRDY_O_sram	: std_logic;
	signal DAT_O_sram	: unsigned(31 downto 0);

	signal CYC_I_gpio	: std_logic;
	signal ACK_O_gpio	: std_logic;
	signal SRDY_O_gpio	: std_logic;
	signal DAT_O_gpio	: unsigned(31 downto 0);

	signal CYC_I_uart	: std_logic;
	signal ACK_O_uart	: std_logic;
	signal SRDY_O_uart	: std_logic;
	signal DAT_O_uart	: unsigned(31 downto 0);

	signal int_timer	: std_logic;
	signal int_uart		: std_logic;

	type mem_area_t is (mem_dead, mem_flash, mem_sram, mem_rom, mem_gpio, mem_uart);
	signal mem_area : mem_area_t;

BEGIN

------------------------------------------------------------------
-- Memory mux
------------------------------------------------------------------
mem_mux:
	process(ADDR_O)
	begin
		mem_area	<= mem_dead;
		if ADDR_O(31 downto 28) = X"0" then
			mem_area	<= mem_flash;
		elsif ADDR_O(31 downto 28) = X"A" then
			if ADDR_O(27 downto 26) = "00" then
				if ADDR_O(18 downto 16) = "000" then
					mem_area	<= mem_gpio;
				elsif ADDR_O(18 downto 16) = "001" then
					mem_area	<= mem_uart;
				end if;	
			elsif ADDR_O(27 downto 26) = "01" then
				mem_area	<= mem_flash;
			end if;	
		elsif (ADDR_O(31 downto 28) = X"B" and ADDR_O(15) = '0') then
			mem_area	<= mem_rom;
		elsif (ADDR_O(31 downto 28) = X"8" or ADDR_O(30) = '1') then
			mem_area	<= mem_sram;
		end if;
	end process;	

signal_mux:
	process(mem_area, CYC_O)
	begin
	
		CYC_I_uart		<= '0';
		CYC_I_gpio		<= '0';
		CYC_I_flash		<= '0';
		CYC_I_rom		<= '0';
		CYC_I_sram		<= '0';
		
		case mem_area is

		when mem_gpio =>
			CYC_I_gpio		<= CYC_O;

		when mem_uart =>
			CYC_I_uart		<= CYC_O;

		when mem_flash =>
			CYC_I_flash		<= CYC_O;

		when mem_rom =>
			CYC_I_rom		<= CYC_O;

		when mem_sram =>
			CYC_I_sram		<= CYC_O;
		
		when others => null;
		
		end case;
		
	end process;

 	SRDY_I		<=	SRDY_O_flash or SRDY_O_sram or SRDY_O_rom or SRDY_O_uart or SRDY_O_gpio;
 	ACK_I		<=	ACK_O_flash or ACK_O_sram or ACK_O_rom or ACK_O_uart or ACK_O_gpio;
 	DAT_I		<=	DAT_O_sram when CYC_I_sram = '1' else
					DAT_O_rom when CYC_I_rom = '1' else
					DAT_O_flash when CYC_I_flash = '1' else
					DAT_O_uart when CYC_I_uart = '1' else
					DAT_O_gpio when CYC_I_gpio = '1' else X"DEADBEEF";


------------------------------------------------------------------
inst_mips_top: entity work.mips_top
	GENERIC MAP
	(
		icache_size	=> ICACHE_SIZE,		-- words
		dcache_size	=> DCACHE_SIZE		-- words
	)
	PORT MAP
	(
		debug	=> debug,
		nmi		=> nmi,
		eb		=> eb,
		cpu_clk	=> clk,
		RST_I	=> rst,
		CLK_I	=> clk,
		ACK_I	=> ACK_I,
		SRDY_I	=> SRDY_I,
		ADDR_O	=> ADDR_O,
		DAT_I	=> DAT_I,
		DAT_O	=> DAT_O,
		WE_O	=> WE_O,
		SEL_O	=> SEL_O,
		CYC_O	=> CYC_O,
		STB_O	=> STB_O,
		MRDY_O	=> MRDY_O,
		INT		=> INT
	);
	INT(1)	<= int_uart;
	INT(5)	<= int_timer;
	
inst_rom : entity work.rom_wb
	PORT MAP
	(
		CLK_I	=> clk,
		RST_I	=> rst,
		CYC_I	=> CYC_I_rom,
		STB_I	=> STB_O,
		ACK_O	=> ACK_O_rom,
		MRDY_I	=> MRDY_O,
		SRDY_O	=> SRDY_O_rom,
		ADDR_I	=> ADDR_O,
		DAT_O	=> DAT_O_rom
	);

inst_gpio : entity work.gpio_wb
	PORT MAP
	(
		CLK_I		=> clk,
		RST_I		=> rst,
		CYC_I		=> CYC_I_gpio,
		STB_I		=> STB_O,
		SEL_I		=> SEL_O,
		WE_I		=> WE_O,
		ACK_O		=> ACK_O_gpio,
		SRDY_O		=> SRDY_O_gpio,
		MRDY_I		=> MRDY_O,
		ADDR_I		=> ADDR_O,
		DAT_I		=> DAT_O,
		DAT_O		=> DAT_O_gpio,
		INT_TIM_O	=> int_timer,
		sys_gpo0	=> gpo0,
		sys_gpo1	=> gpo1,
		sys_gpi0	=> gpi0,
		sys_gpi1	=> gpi1
	);

inst_flash_port : entity work.async_port_wb
	GENERIC MAP
	(
		addr_width		=> FLASH_ADDR_WIDTH,
		data_width		=> 32,
		byte_sel_width	=> 4,
		async_timespec	=> ts_flash
	)
	PORT MAP
	(
		CLK_I		=> clk,
		RST_I		=> rst,
		CYC_I		=> CYC_I_flash,
		STB_I		=> STB_O,
		WE_I		=> WE_O,
		ACK_O		=> ACK_O_flash,
		SRDY_O		=> SRDY_O_flash,
		MRDY_I		=> MRDY_O,
		SEL_I		=> SEL_O,
		ADDR_I		=> ADDR_O,
		DAT_I		=> DAT_O,
		DAT_O		=> DAT_O_flash,
		page_mode_en	=> '0',
		async_a		=> flash_a,
		async_d		=> flash_d,
		async_cs	=> flash_cs_n,
		async_wr	=> flash_we_n,
		async_rd	=> flash_oe_n,
		async_be	=> flash_be_n,
		async_rst	=> open
	);

inst_sram_port : entity work.async_port_wb
	GENERIC MAP
	(
		addr_width		=> SRAM_ADDR_WIDTH,
		data_width		=> 32,
		byte_sel_width	=> 4,
		async_timespec	=> ts_sram
	)
	PORT MAP
	(
		CLK_I		=> clk,
		RST_I		=> rst,
		CYC_I		=> CYC_I_sram,
		STB_I		=> STB_O,
		WE_I		=> WE_O,
		ACK_O		=> ACK_O_sram,
		SRDY_O		=> SRDY_O_sram,
		MRDY_I		=> MRDY_O,
		SEL_I		=> SEL_O,
		ADDR_I		=> ADDR_O,
		DAT_I		=> DAT_O,
		DAT_O		=> DAT_O_sram,
		page_mode_en	=> '0',
		async_a		=> sram_a,
		async_d		=> sram_d,
		async_cs	=> sram_cs_n,
		async_wr	=> sram_we_n,
		async_rd	=> sram_oe_n,
		async_be	=> sram_be_n,
		async_rst	=> open
	);

inst_uart : entity work.uart_wb
	PORT MAP
	(
		CLK_I		=> clk,
		RST_I		=> rst,
		CYC_I		=> CYC_I_uart,
		STB_I		=> STB_O,
		SEL_I		=> SEL_O,
		WE_I		=> WE_O,
		ACK_O		=> ACK_O_uart,
		SRDY_O		=> SRDY_O_uart,
		MRDY_I		=> MRDY_O,
		ADDR_I		=> ADDR_O,
		DAT_I		=> DAT_O,
		DAT_O		=> DAT_O_uart,
		INT_O		=> int_uart,
		ser_rx		=> rx,
		ser_tx		=> tx
	);
	
END;
