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

entity IDStage is
port(
	
	pc : in std_logic_vector(15 downto 0);
	ROM_data: in std_logic_vector(15 downto 0);

	clk, stall, clr: in std_logic;
	
	load_o, store_o, movr_o, add_o, sub_o, andi_o, ori_o, xori_o, noti_o: out std_logic;
	bgt_o, blo_o, beq_o, jsr_o, ret_o, push_o, pop_o, rts_o, str_o, hlt_o, loadn_o : out std_logic;
	reg_s1_rd, reg_s2_rd, reg_ds_rd, reg_ds_wr: out std_logic;
	
	pc_out : out std_logic_vector(15 downto 0);
	displ: out std_logic_vector(15 downto 0);
	s1, s2, ds : out std_logic_vector(3 downto 0)

);
end entity IDStage;


architecture struct of IDStage is
    
--PC
    signal pc_ID, mux_pc_ID: std_logic_vector(15 downto 0);

--OPCODE
	signal opcode_ID: std_logic_vector(6 downto 0);
	
--INSTRUCTION 	
	signal instruction_ID, stalled_instr_ID, stalled_instr2_ID, mux_save_inst_ID: std_logic_vector(15 downto 0);
	
--STALL 
    signal stall_saved, both_stall, both_saved, sel_1, sel_0: std_logic;
    signal sel: std_logic_vector(1 downto 0); 
begin
	
-- MUX selectig insruction to save (from data mem or from instruction_stall) ---------------------------
    mux_pc: entity work.mux_2(arch)
             port map(input1 => pc,
                      input2 => pc_ID,
                      output => mux_pc_ID,
                      sel => stall); 	
                      
-- PC saved for nex stage ----------------------------------------------------------
	reg_pc_id: entity work.reg(arch)
             generic map(16)
			 port map(input => mux_pc_ID, output => pc_ID, clk => clk, clr => clr );
			 pc_out <= pc_ID;	
			 
			 
-- MUX selectig insruction to save (from data mem or from instruction_stall) ---------------------------
    mux_instr_to_save: entity work.mux_2(arch)
             port map(input1 => ROM_data,
                      input2 => stalled_instr_ID,
                      output => mux_save_inst_ID,
                      sel => stall_saved); 			 	 
			 
-- Catch instruction later used if stall -------------------------------------------			 
	instruction_stall: entity work.reg(arch)
            generic map(16)
			 port map(input => mux_save_inst_ID, output => stalled_instr_ID, clk => clk, clr => clr );
			 
	--if two stalls		 
	instruction_stall1: entity work.reg(arch)
            generic map(16)
			 port map(input => stalled_instr_ID, output => stalled_instr2_ID, clk => clk, clr => clr );
			 
---------- STALL LOGIC ID ----------------------------------------------------------

    -- Save stall
        stall_reg: entity work.d_ff(arch)
                port map(input => stall, output => stall_saved, clk => clk, clr => clr);
    -- Save both
        both_stall <= stall and stall_saved;
        both_reg: entity work.d_ff(arch)
                port map(input => both_stall, output => both_saved, clk => clk, clr => clr);   			 
	
        sel_1 <= stall_saved and (stall or both_saved);
        sel_0 <= ((stall_saved and (not sel_1)) or (stall and (not sel_1)));
        sel <= sel_1 & sel_0;
			  
-- MUX selectig stalled instructions or curent instraction---------------------------
    mux_instr: entity work.mux_4(arch)
             port map(input1 => ROM_data,
                      input2 => stalled_instr_ID,
                      input3 => stalled_instr2_ID,
                      input4 => stalled_instr2_ID,
                      output => instruction_ID,
                      sel => sel); 
  	
-- Opcode_dec ----------------------------------------------------------------------

	opcode_ID <= instruction_ID(15 downto 12) & instruction_ID(2 downto 0);
	op_decoder: entity work.opcode_dec(arch)
			 port map(op_code => opcode_ID, load_o => load_o, store_o => store_o,
					movr_o => movr_o, add_o => add_o, sub_o => sub_o, andi_o => andi_o,
					ori_o => ori_o,	xori_o => xori_o, noti_o => noti_o, bgt_o => bgt_o,
					blo_o => blo_o, beq_o => beq_o, jsr_o => jsr_o, ret_o => ret_o,
					push_o => push_o, pop_o => pop_o, rts_o => rts_o, str_o => str_o,
					hlt_o => hlt_o, loadn_o => loadn_o, reg_s1_rd => reg_s1_rd,
					reg_s2_rd => reg_s2_rd, reg_ds_rd => reg_ds_rd, reg_ds_wr => reg_ds_wr
				);
				
--	SIGN EXTENSION--------------------------------------------------------
	sign_extension: entity work.sign_ext(arch)
			 port map(s1 => instruction_ID(7 downto 4),s2 => instruction_ID(3 downto 0),output => displ);	

-- SOURCE and DESTINAION--------------------------------------------------
	
	ds <= instruction_ID(11 downto 8);
	s1 <= instruction_ID(7 downto 4);
	s2 <= instruction_ID(3 downto 0); 
	
end architecture struct;
	
