--------------------------------------------------------------------------
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
-- This file: JIPS top file 
--
-- Copyright (C) 2008 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;

entity mips_top is
	Generic
	(
		icache_size	: natural := 1024;	-- words
		icache_line	: natural := 8;		-- words
		dcache_size	: natural := 1024;	-- words
		dcache_line	: natural := 8		-- words
	);
	Port
	(
		debug		: out unsigned(1 downto 0);
		eb			: in  STD_LOGIC;
		nmi			: in  STD_LOGIC;
		cpu_clk		: in  STD_LOGIC;
		RST_I		: in  STD_LOGIC;
		CLK_I		: in  STD_LOGIC;
		ACK_I		: in  STD_LOGIC;
		SRDY_I		: in  STD_LOGIC;
		ADDR_O		: out unsigned(31 downto 0);
		DAT_I		: in  unsigned(31 downto 0);
		DAT_O		: out unsigned(31 downto 0);
		WE_O		: out STD_LOGIC;
		SEL_O		: out unsigned(3 downto 0);
		CYC_O		: out STD_LOGIC;
		STB_O		: out STD_LOGIC;
		MRDY_O		: out STD_LOGIC;
		INT			: in  unsigned (5 downto 0)
	);
	
end mips_top;

architecture rtl of mips_top is

--------------------------------------------------------------------------
-- Pipeline
--------------------------------------------------------------------------
	COMPONENT pipeline is
	Port 
	(
		rst			: in  STD_LOGIC;
		clk			: in  STD_LOGIC;
		ce			: in  STD_LOGIC;
		imem_rdy	: in  STD_LOGIC;
		imem_en		: out STD_LOGIC;
		imem_addr	: out word_t;
		imem_data	: in  word_t;
		dmem_rdy	: in  STD_LOGIC;
		dmem_en		: out STD_LOGIC;
		dmem_we		: out STD_LOGIC;
		dmem_be		: out unsigned(3 downto 0);
		dmem_addr	: out word_t;
		dmem_din	: in  word_t;
		dmem_dout	: out word_t;
		cop_ir		: out word_t;
		cop_ir_en	: out STD_LOGIC;
		cop_din		: in  word_t;
		cop_dout	: out word_t;
		c0_ctrl_out	: out cop0_ctrl_in_t;
		c0_ctrl_in	: in  cop0_ctrl_out_t
	);
	END COMPONENT;
	signal imem_err			: std_logic;
	signal imem_rdy			: std_logic;
	signal imem_en			: std_logic;
	signal imem_addr		: word_t;
	signal imem_din			: word_t;
	signal dmem_err			: std_logic;
	signal dmem_rdy			: std_logic;
	signal dmem_en			: std_logic;
	signal dmem_we			: std_logic;
	signal dmem_addr		: word_t;
	signal dmem_dout		: word_t;
	signal dmem_din			: word_t;
	signal dmem_be			: unsigned(3 downto 0);

	signal biu_rst			: STD_LOGIC;
	signal cpu_rst			: STD_LOGIC;
	signal cpu_run			: STD_LOGIC;

	signal pipe_cop_ir		: word_t;
	signal pipe_cop_ir_en	: STD_LOGIC;
	signal pipe_cop_din		: word_t;
	signal pipe_cop_dout	: word_t;
	signal pipe_c0_ctrl_out	: cop0_ctrl_in_t;
	signal pipe_c0_ctrl_in	: cop0_ctrl_out_t;
	
--------------------------------------------------------------------------
-- Coprocessor
--------------------------------------------------------------------------
	COMPONENT cop is
	GENERIC
	(
		icache_size	: natural;
		icache_line	: natural;
		dcache_size	: natural;
		dcache_line	: natural
	);
	Port 
	(
		rst			: in  STD_LOGIC;
		clk			: in  STD_LOGIC;
		nmi			: in  STD_LOGIC;
		eb			: in  STD_LOGIC;
		int			: in  unsigned (5 downto 0);
		ir_en		: in  STD_LOGIC;
		ir			: in  word_t;
		ctrl_in		: in  cop0_ctrl_in_t;
		ctrl_out	: out cop0_ctrl_out_t;
		din			: in  word_t;
		dout		: out word_t
	);
	END COMPONENT;
	
--------------------------------------------------------------------------
-- Bus Interface Unit
--------------------------------------------------------------------------
	COMPONENT biu
	GENERIC
	(
		icache_size	: natural;
		icache_line	: natural;
		dcache_size	: natural;
		dcache_line	: natural
	);
	PORT
	(
		RST_I			: in  STD_LOGIC;
		CLK_I			: in  STD_LOGIC;
		ACK_I			: in  STD_LOGIC;
		SRDY_I			: in  STD_LOGIC;
		ADDR_O			: out unsigned(31 downto 0);
		DAT_I			: in  unsigned(31 downto 0);
		DAT_O			: out unsigned(31 downto 0);
		WE_O			: out STD_LOGIC;
		SEL_O			: out unsigned(3 downto 0);
		CYC_O			: out STD_LOGIC;
		STB_O			: out STD_LOGIC;
		MRDY_O			: out STD_LOGIC;
		cop0_ctrl_in	: in cop0_ctrl_out_t;
		cpu_clk			: in  STD_LOGIC;
		cpu_imem_err	: out STD_LOGIC;
		cpu_imem_rdy	: out STD_LOGIC;
		cpu_imem_en		: in  STD_LOGIC;
		cpu_imem_addr	: in  word_t;
		cpu_imem_din	: out word_t;
		cpu_dmem_err	: out STD_LOGIC;
		cpu_dmem_rdy	: out STD_LOGIC;
		cpu_dmem_en		: in  STD_LOGIC;
		cpu_dmem_we		: in  STD_LOGIC;
		cpu_dmem_be		: in  unsigned(3 downto 0);
		cpu_dmem_dout	: in  word_t;
		cpu_dmem_din	: out word_t;
		cpu_dmem_addr	: in  word_t
	);
	END COMPONENT;

begin

-------------------------------------------------------------------
	debug(0)		<= imem_err;
	debug(1)		<= dmem_err;
	
	process(CLK_I)
	variable reset_delay : unsigned (31 downto 0);
	begin
		if rising_edge(CLK_I) then
			if RST_I = '1' then
				reset_delay := (others => '0');
				biu_rst	<= '1';
				cpu_rst <= '1';
				cpu_run	<= '0';
			else
				reset_delay := reset_delay(reset_delay'left-1 downto 0) & '1';
				if reset_delay(20) = '1' then
					biu_rst <= '0';
				end if;	
				if reset_delay(31) = '1' then
					cpu_rst <= '0';
				end if;	
				if reset_delay(16) = '1' then
					cpu_run	<= '1';
				end if;	
			end if;
		end if;
	end process;

inst_pipeline: pipeline
	PORT MAP
	(
		rst			=> cpu_rst,
		clk			=> cpu_clk,
		ce			=> cpu_run,
		imem_rdy	=> imem_rdy,
		imem_en		=> imem_en,
		imem_addr	=> imem_addr,
		imem_data	=> imem_din,
		dmem_rdy	=> dmem_rdy,
		dmem_en		=> dmem_en,
		dmem_we		=> dmem_we,
		dmem_be		=> dmem_be,
		dmem_addr	=> dmem_addr,
		dmem_din	=> dmem_din,
		dmem_dout	=> dmem_dout,
		cop_ir		=> pipe_cop_ir,
		cop_ir_en	=> pipe_cop_ir_en,
		cop_din		=> pipe_cop_din,
		cop_dout	=> pipe_cop_dout,
		c0_ctrl_out	=> pipe_c0_ctrl_out,
		c0_ctrl_in	=> pipe_c0_ctrl_in
	);

inst_cop: cop
	GENERIC MAP
	(
		icache_size	=> icache_size,	-- words
		icache_line	=> icache_line,	-- words
		dcache_size	=> dcache_size,	-- words
		dcache_line	=> dcache_line	-- words
	)
	PORT MAP
	(
		rst			=> cpu_rst,
		clk			=> cpu_clk,
		nmi			=> nmi,
		eb			=> eb,
		int			=> INT,
		ir_en		=> pipe_cop_ir_en,
		ir			=> pipe_cop_ir,
		ctrl_in		=> pipe_c0_ctrl_out,
		ctrl_out	=> pipe_c0_ctrl_in,
		dout		=> pipe_cop_din,
		din			=> pipe_cop_dout
	);
	
inst_biu: biu
	GENERIC MAP
	(
		icache_size	=> icache_size,	-- words
		icache_line	=> icache_line,	-- words
		dcache_size	=> dcache_size,	-- words
		dcache_line	=> dcache_line	-- words
	)
	PORT MAP
	(
		RST_I			=> biu_rst,
		CLK_I			=> CLK_I,
		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,
		cop0_ctrl_in	=> pipe_c0_ctrl_in,
		cpu_clk			=> cpu_clk,
		cpu_imem_err	=> imem_err,
		cpu_imem_rdy	=> imem_rdy,
		cpu_imem_en		=> imem_en,
		cpu_imem_addr	=> imem_addr,
		cpu_imem_din	=> imem_din,
		cpu_dmem_err	=> dmem_err,
		cpu_dmem_rdy	=> dmem_rdy,
		cpu_dmem_en		=> dmem_en,
		cpu_dmem_we		=> dmem_we,
		cpu_dmem_be		=> dmem_be,
		cpu_dmem_addr	=> dmem_addr,
		cpu_dmem_din	=> dmem_din,
		cpu_dmem_dout	=> dmem_dout
	);

end rtl;
