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

entity OFStage is
port(

-- from IDStage

	pc: in std_logic_vector(15 downto 0);
	
	load_o, store_o, movr_o, add_o, sub_o, andi_o, ori_o, xori_o, noti_o: in std_logic;
	bgt_o, blo_o, beq_o, jsr_o, ret_o, push_o, pop_o, rts_o, str_o, hlt_o, loadn_o: in std_logic;
	reg_ds_wr: in std_logic;
	
	s1, s2, ds: in std_logic_vector(3 downto 0);
	
	displ: in std_logic_vector(15 downto 0);
	
-- from WBStage
	ds_wb: in std_logic_vector(3 downto 0);
	dat_wb: in std_logic_vector(15 downto 0);
	reg_wr_wb: in std_logic;

-- control	
	clk, stall, clr, reg_reset: in std_logic;

-- to EXStage	

	pc_out: out std_logic_vector(15 downto 0);
	instructions: out std_logic_vector(20 downto 0);
	s2_out, ds_out: out std_logic_vector(3 downto 0);
	displ_out: out std_logic_vector(15 downto 0);
	
	A_out, B_out, C_out: out std_logic_vector(15 downto 0)	

);
end entity OFStage;


architecture struct of OFStage is
     
    -- instructions
	signal temp: std_logic_vector(20 downto 0);
	
	-- FORWARD data from WB srage
	signal forw_val_OF: std_logic_vector(15 downto 0);
	signal forw_ds_OF: std_logic_vector(3 downto 0);
	signal forw_reg_wr_OF: std_logic;
	
	--operands
	signal A_OF: std_logic_vector(15 downto 0);
	signal B_OF: std_logic_vector(15 downto 0);
	signal C_OF: std_logic_vector(15 downto 0); 
	
	--source and destination	
    signal s1_OF, s2_OF, ds_OF: std_logic_vector(3 downto 0);
    
    -- FORWARDIG control
    signal sel_a_OF, sel_b_OF, sel_c_OF: std_logic; 
     
begin
		
-- INSTRUCTIONS -----------------------------------	

    temp(20) <= reg_ds_wr;
	temp(19) <= load_o;
	temp(18) <= store_o;
	temp(17) <= movr_o;
	temp(16) <= add_o;
	temp(15) <= sub_o;
	temp(14) <= andi_o;
	temp(13) <= ori_o;
	temp(12) <= xori_o;
	temp(11) <= noti_o;
	temp(10) <= bgt_o;
	temp(9) <= blo_o;
	temp(8) <= beq_o;
	temp(7) <= jsr_o;
	temp(6) <= ret_o;
	temp(5) <= push_o;
	temp(4) <= pop_o;
	temp(3) <= rts_o;
	temp(2) <= str_o;
	temp(1) <= hlt_o;
	temp(0) <= loadn_o;
	
	
-- PC saved for nex stage ----------------------------------------------------------
	pc_of: entity work.reg(arch)
			 port map(input => pc, output => pc_out, clk => clk, clr => clr );
	
-- INSTUCTIONS Registre ----------------------------------------------------------
	instruction_reg: entity work.reg(arch)
             generic map (21)
			 port map(input => temp, output => instructions, clk => clk, clr => clr );
			 		 
-- REG FILE ----------------------------------------------------------------------
	register_file: entity work.reg_file(arch)
			 port map(sel_s1 => s1, sel_s2 => s2, sel_s3 => ds, sel_dst => ds_wb, data_in => dat_wb,
			  s1_out => A_OF, s2_out => B_OF, s3_out => C_OF, clk => clk, clr => reg_reset, wr => reg_wr_wb);
			  
-- FORWARD data from WB srage ----------------------------------------------------------
	forward_data: entity work.reg(arch)
			 port map(input => dat_wb, output => forw_val_OF, clk => clk, clr => clr );
			 			 
	forward_ds: entity work.reg(arch)
             generic map (4)
			 port map(input => ds_wb, output => forw_ds_OF, clk => clk, clr => clr );
			 
	forward_wr: entity work.d_ff(arch)
             port map(input => reg_wr_wb, output => forw_reg_wr_OF, clk => clk, clr => clr );
			 
-- MUX A -------------------------------------------------------------------------
	mux_a: entity work.mux_2(arch)
             port map(input1 => A_OF, input2 => forw_val_OF, output => A_out, sel => sel_a_OF); 
             
-- MUX B -------------------------------------------------------------------------
	mux_b: entity work.mux_2(arch)
             port map(input1 => B_OF, input2 => forw_val_OF, output => B_out, sel => sel_b_OF); 
             
-- MUX C -------------------------------------------------------------------------
	mux_c: entity work.mux_2(arch)
             port map(input1 => C_OF, input2 => forw_val_OF, output => C_out, sel => sel_c_OF);
          				  			  
-- ADR REG s2 ------------------------------------------------------------------------			  
	adr_reg_s2: entity work.reg(arch)
             generic map (4)
			 port map(input => s2, output => s2_OF, clk =>clk, clr =>clr);
	s2_out <= s2_OF;
			 
-- ADR REG s1 ------------------------------------------------------------------------			  
	adr_reg_s1: entity work.reg(arch)
             generic map (4)
			 port map(input => s1, output => s1_OF, clk =>clk, clr =>clr);
			 
-- ADR REG ds ------------------------------------------------------------------------			  
	adr_reg_ds: entity work.reg(arch)
	         generic map (4)	
			 port map(input => ds, output => ds_OF, clk =>clk, clr =>clr);
			 
	ds_out <= ds_OF;
			 
-- FORWARDIG control -----------------------------------------------------------------
    forward_control: entity work.forward_logic(arch)
            port map(s1_of => s1_OF, s2_of => s2_OF, ds_of => ds_OF,
		             ds_wb => forw_ds_OF, reg_wr_wb => forw_reg_wr_OF,
		             sel_a => sel_a_OF, sel_b => sel_b_OF, sel_c => sel_c_OF);

-- DISPL REG  ------------------------------------------------------------------------			  
	disp_reg: entity work.reg(arch)
             generic map (16)
			 port map(input => displ, output => displ_out, clk =>clk, clr =>clr);
		
end architecture struct;