library ieee;
library work;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.VITAL_Primitives.all;
use work.all;

entity stall_unit is
port(   
        clk: in std_logic;
        reset: in std_logic;
        SPreset: in std_logic;
        jmp_cond: in std_logic;
        hlt: in std_logic;
        
        reg_s1_rd_ID, reg_s2_rd_ID, reg_ds_rd_ID: in std_logic;
        ds_ID, s1_ID, s2_ID, ds_OF, ds_EX: in std_logic_vector(3 downto 0);
        reg_wr_OF, reg_wr_EX: in std_logic;
	
        stall_if: out std_logic;
        stall_id: out std_logic;
        stall_of: out std_logic;
        stall_ex: out std_logic;
        stall_wb: out std_logic;
        
        reset_if: out std_logic;
        reset_id: out std_logic;
        reset_of: out std_logic;
        reset_reg_and_sp: out std_logic;
        reset_ex: out std_logic;
        reset_wb: out std_logic
	);
end entity stall_unit;

architecture arch of stall_unit is

	signal halt_stall: std_logic;
	signal p1, p2, p3, p4, p5, p6: std_logic;
	signal reset_of_temp, jmp_cond_saved, stall_1, stall_2, temp, stall_saved: std_logic; 
	signal reset_jmp_cond_reg, reset_stall_reg: std_logic;
begin 
               
    halt_reg: entity work.d_ff(arch)
             port map(input => hlt, output => halt_stall, clk => clk, clr => reset);  
             
--resets       
        reset_if <= reset or SPreset;
        reset_id <= reset or SPreset or jmp_cond;
        
        reset_of_temp <= reset or temp or jmp_cond;
        reset_reg_and_sp <= reset or SPreset; 
        reset_stall_reg <= reset or SPreset or jmp_cond;
        reset_jmp_cond_reg <= reset or SPreset;  
        
        reset_ex <= reset or SPreset or jmp_cond;
        reset_wb <= reset or SPreset or jmp_cond;
        
        
        
        p1 <= '1' when ds_ID = ds_OF else '0';
        p2 <= '1' when ds_ID = ds_EX else '0';
        
        p3 <= '1' when s1_ID = ds_OF else '0';
        p4 <= '1' when s1_ID = ds_EX else '0';
        
        p5 <= '1' when s2_ID = ds_OF else '0';
        p6 <= '1' when s2_ID = ds_EX else '0';

 -- stall       
        stall_1 <= ((reg_ds_rd_ID and reg_wr_OF and p1) or
                     (reg_s1_rd_ID and reg_wr_OF and p3) or
                     (reg_s2_rd_ID and reg_wr_OF and p5)
                     );
                     
        stall_2 <= ((reg_ds_rd_ID and reg_wr_EX and p2) or    
                      (reg_s1_rd_ID and reg_wr_EX and p4) or
                      (reg_s2_rd_ID and reg_wr_EX and p6)
                     ); 
                     
        temp <= stall_1 or stall_2;
        
        -- Save stall OF_ stage for next clock and stall for id------------------------------------------ 
        stall_reg: entity work.d_ff(arch)
             port map(input => temp, output => stall_saved, clk => clk, clr => reset_stall_reg); 
        --------------------------------------------------------------------------------   
        
        
        -- Save reset OF_ stage for next clock ---------------------------------------------------------- 
        jmp_cond_reg: entity work.d_ff(arch)
             port map(input => jmp_cond, output => jmp_cond_saved, clk => clk, clr => reset_jmp_cond_reg); 
        -------------------------------------------------------------------------------------------------
        reset_of <= jmp_cond_saved or reset_of_temp;
            
        stall_if <= stall_saved and (not jmp_cond);
        stall_id <= stall_saved;         
        stall_of <= halt_stall;
        stall_ex <= halt_stall;
        stall_wb <= halt_stall;
               
end architecture arch;