--------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: Interrupt controller 
--
-- 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;

use work.cpu_pkg.all;

entity int_ctrl is
	Port (
		rst				: in  STD_LOGIC;
		clk				: in  STD_LOGIC;
		ctrl_in			: in  int_ctrl_in_t;
		int_in			: in  STD_LOGIC;
		int_exit		: in  STD_LOGIC;
		iphase_in		: in  iphase_t;
		pc_addr_out		: out inst_addr_t;
		int_ack_out		: out STD_LOGIC;
		stat_save_out	: out STD_LOGIC; 
		stat_rest_out	: out STD_LOGIC; 
		pc_load_out		: out STD_LOGIC;
		stk_push_out	: out STD_LOGIC;
		stk_pop_out		: out STD_LOGIC
	);
end int_ctrl;

architecture Behavioral of int_ctrl is

	type int_state_t is (int_idle, int_inject, int_active, int_release);
	
	signal int_state, int_state_next : int_state_t;
	signal pc_load, int_ack, stk_push, stk_pop : STD_LOGIC;
	signal int_request : std_logic;
	
	
begin

	int_ack_out		<= int_ack;
	pc_load_out		<= pc_load;
	stk_push_out	<= stk_push;
	stk_pop_out		<= stk_pop;
	
-----------------------------------------------------------------------
irg_ctrl_fsm:
	process (int_state, iphase_in, int_request, int_exit)
	begin

		pc_addr_out <= to_unsigned(1, inst_addr_t'length);
		int_state_next <= int_state;
		int_ack <= '0';
		pc_load <= '0';
		stk_push <= '0';
		stk_pop <= '0';
		case int_state is
		
		when int_idle =>
			if int_request = '1' and iphase_in = 1 then
				int_state_next <= int_inject;
			end if;
		when int_inject =>
			if iphase_in = 0 then
				int_ack <= '1';
				pc_load <= '1';
			elsif iphase_in = 1 then
				stk_push <= '1';
				int_state_next <= int_active;
			end if;
		when int_active =>
			if int_exit = '1' and iphase_in = 1 then
				int_state_next <= int_release;
			end if;
		when int_release =>
			if iphase_in = 0 then
				stk_pop <= '1';
				pc_load <= '1';
			elsif iphase_in = 1 then
				int_state_next <= int_idle;
			end if;	
		when others => 	
			int_state_next <= int_idle;
		end case;	
			
	end process;
	
irq_ctrl_states:
	process (rst, clk, int_state_next)
	begin
		if rst = '1' then
			int_state <= int_idle;
		elsif rising_edge(clk) then
			int_state <= int_state_next;
		end if;
	end process;

-----------------------------------------------------------------------
pin_sample:
	process (clk)
	begin
		if rising_edge(clk) then
			int_request <= '0';
			if ctrl_in.enable = '1' then
				int_request <= int_in;
			end if;	
		end if;
	end process;

-----------------------------------------------------------------------
stat_save_restore:
	process (clk, stk_push, stk_pop)
	begin
		if rising_edge(clk) then
			stat_save_out <= stk_push;
			stat_rest_out <= stk_pop;
		end if;
	end process;

end Behavioral;
