library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_unsigned.all;

--******************************************************************************
--**** ENTITY exceptCU
--**** Deskripsi:
--****              Entity ini menguraiakan exception control unit. Unit ini
--****              digunakan untuk arithmetic overflow, undefined instruction,
--****              atau external IO devices untuk membuat suatu permintaan. 
--****              Jika unit ini dibolehkan kemudian setiap
--****              baris dicontohkan bekerja. Baris pertama akan benar
--****              kemudian dilayani. Stage yang sesuai dari pipeline
--****              dibersihkan dan exception unit tidak dibolehkan. Jika sebuah
--****              external IO device dilayani kemudian sebuah acknowledgment 
--****              dikirim keluar dan nilai program counter sekarang
--****              dikirim melalui TRAP register.
--******************************************************************************
ENTITY exceptCU IS
    PORT(Interrupt, enInterrupt              : IN STD_LOGIC_VECTOR(5 DOWNTO 0);
         pcSel                               : IN STD_LOGIC_VECTOR(1 DOWNTO 0);
         overflow, undfIns, enabled          : IN STD_LOGIC;
         pcenableIn                          : IN STD_LOGIC;
         IntAck                              : OUT STD_LOGIC_VECTOR(5 DOWNTO 0);
         ifid_flush, idex_flush, exmem_flush : OUT STD_LOGIC;
         pcSelect                            : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
         disableInt                          : OUT STD_LOGIC;
         trapPC                              : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
         pcenableOut                         : OUT STD_LOGIC);
END ENTITY exceptCU;

ARCHITECTURE except_behav OF exceptCU IS

BEGIN

    
    name : PROCESS(Interrupt, enInterrupt, enabled, overflow, undfIns, pcSel) IS
    BEGIN
        
        IF(enabled='1') THEN
            IF(overflow='1') THEN  --this means if the overflow line is sethigh
                pcSelect <= "0100";
                IntAck <= "000000";
                ifid_flush <= '1';
                exmem_flush <= '1';
                idex_flush <= '1';
                disableInt <= '1';
                trapPC <= "01"; -- save the PC address in ex stage so that we 
                                -- can jump back to it.
                pcenableOut <= '1';
                
            ELSIF(undfIns='1') THEN --this means if the undefined instruction 
                                    --line is high
                pcSelect <= "0101";
                IntAck <= "000000";
                ifid_flush <= '1';
                exmem_flush <= '0';
                idex_flush <= '0';
                disableInt <= '1';
                trapPC <= "10"; -- save the PC address in the id stage so we can 
                                -- jump back to it
                pcenableOut <= '1';
                
                
            -- if interrupt0 is high and it is also enabled do  
            ELSIF(Interrupt(0)='1' and enInterrupt(0)='1') THEN 
                pcSelect <= "0110";                             
                IntAck <= "000001";                             
                ifid_flush <= '1';
                exmem_flush <= '0';
                idex_flush <= '1';
                disableInt <= '1';
                trapPC <= "11";
                pcenableOut <= '1';
            
            -- if interrupt1 is high and it is also enabled do      
            ELSIF(Interrupt(1)='1' and enInterrupt(1)='1') THEN 
                pcSelect <= "0111";                             
                IntAck <= "000010";                             
                ifid_flush <= '1';
                exmem_flush <= '0';
                idex_flush <= '1';
                disableInt <= '1';
                trapPC <= "11";
                pcenableOut <= '1';
                
            -- if interrupt2 is high and it is also enabled do  
            ELSIF(Interrupt(2)='1' and enInterrupt(2)='1') THEN
                pcSelect <= "1000";
                IntAck <= "000100";
                ifid_flush <= '1';
                exmem_flush <= '0';
                idex_flush <= '1';
                disableInt <= '1';
                trapPC <= "11";
                pcenableOut <= '1';
            
            --if interrupt3 is high and it is also enabled do   
            ELSIF(Interrupt(3)='1' and enInterrupt(3)='1') THEN
                pcSelect <= "1001";
                IntAck <= "001000";
                ifid_flush <= '1';
                exmem_flush <= '0';
                idex_flush <= '1';
                disableInt <= '1';
                trapPC <= "11";
                pcenableOut <= '1';
            
            -- if interrupt4 is high and it is also enabled do
            ELSIF(Interrupt(4)='1' and enInterrupt(4)='1') THEN 
                pcSelect <= "1010";                                                         
                IntAck <= "010000";                             
                ifid_flush <= '1';
                exmem_flush <= '0';
                idex_flush <= '1';
                disableInt <= '1';
                trapPC <= "11";
                pcenableOut <= '1';
            
            -- if interrupt5 is high and it is also enabled do
            ELSIF(Interrupt(5)='1' and enInterrupt(5)='1') THEN
                pcSelect <= "1011";
                IntAck <= "100000";
                ifid_flush <= '1';
                exmem_flush <= '0';
                idex_flush <= '1';
                disableInt <= '1';
                trapPC <= "11";
                pcenableOut <= '1';
            
            -- no interrupts or exceptions have occured do nothing.
            ELSE            
                pcSelect <= "00"&pcSel;             
                IntAck <= "000000";                 
                ifid_flush <= '0';
                exmem_flush <= '0';
                idex_flush <= '0';
                disableInt <= '0';
                trapPC <= "00";
                pcenableOut <= pcenableIn;
            END IF;
        
        -- Interrupts and Exceptions are not enabled so do nothing.
        ELSE                        
            pcSelect <= "00"&pcSel;
            IntAck <= "000000";
            ifid_flush <= '0';
            exmem_flush <= '0';
            idex_flush <= '0';
            disableInt <= '1';
            trapPC <= "00"; -- no need to TRAP the PC
            pcenableOut <= pcenableIn;
        END IF;

    END PROCESS name;
END ARCHITECTURE except_behav;
