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

entity EXStage is
port(

-- from OFStage
	pc: in std_logic_vector(15 downto 0);
	instructions: in std_logic_vector(20 downto 0);
	s2, ds: in std_logic_vector(3 downto 0);
	displ: in std_logic_vector(15 downto 0);
	
	A, B, C: in std_logic_vector(15 downto 0);	
	
-- from WBStage
	SP: in std_logic_vector(15 downto 0);
	
-- control	
	clk, stall, clr: in std_logic;

-- to WBStage and from RAM memory

	RES_out: out std_logic_vector(15 downto 0);
	C_out: out std_logic_vector(15 downto 0);
	ds_out: out std_logic_vector(3 downto 0);
	STACK_data: out std_logic_vector(15 downto 0);
	displ_out: out std_logic_vector(15 downto 0);
	
-- control for WBStage
    jmp_cond_out, reg_wr_out, ret_out, load_out, store_out, jsr_out, push_out: out std_logic;
    loadn_out, str_out, rts_out, pop_out, hlt_out: out std_logic
);
end entity EXStage;


architecture struct of EXStage is
     
	--instructions
	signal temp: std_logic_vector(20 downto 0);
	
	signal load_o, store_o, movr_o, add_o, sub_o, andi_o, ori_o, xori_o, noti_o, bgt_o: std_logic;
	signal blo_o, beq_o, jsr_o, ret_o, push_o, pop_o, rts_o, str_o, hlt_o, loadn_o: std_logic;
	signal reg_ds_wr: std_logic;

	--register outputs
	signal rot, ds_ex :std_logic_vector(3 downto 0);
	signal B_ex, A_ex, C_ex, displ_ex, pc_ex:std_logic_vector(15 downto 0);
	--alu
	signal sub_alu: std_logic;
	signal add_alu: std_logic;
	signal inc_alu: std_logic;
	signal sel_b_alu: std_logic;
	signal n_alu, z_alu, c_alu, v_alu: std_logic;
	signal RES_EX: std_logic_vector(15 downto 0); 
	
	--mux a
	signal sel_a: std_logic; 
	signal mux_a_ex: std_logic_vector(15 downto 0); 
	
	--mux b
	signal sel_b: std_logic;
	signal mux_b_ex: std_logic_vector(15 downto 0);
	   
	--jmp logic and control
	signal jmp_cond: std_logic;
	signal reg_wr: std_logic; 
	
begin

-- PC saved for nex stage ----------------------------------------------------------
	pc_of: entity work.reg(arch)
             generic map (16)
			 port map(input => pc, output => pc_ex, clk => clk, clr => clr );
	
-- INSTUCTIONS Registre ----------------------------------------------------------
	instruction_reg: entity work.reg(arch)
             generic map (21)
			 port map(input =>instructions, output => temp, clk => clk, clr => clr );
			 
	reg_ds_wr <= temp(20);		 
	load_o <= temp(19);
	store_o <= temp(18);
	movr_o <= temp(17);
	add_o <= temp(16);
	sub_o <= temp(15);
	andi_o <= temp(14);
	ori_o <= temp(13);
	xori_o <= temp(12);
	noti_o <= temp(11);
	bgt_o <= temp(10);
	blo_o <= temp(9);
	beq_o <= temp(8);
	jsr_o <= temp(7);
	ret_o <= temp(6);
	push_o <= temp(5);
	pop_o <= temp(4);
	rts_o <= temp(3);
	str_o <= temp(2);
	hlt_o <= temp(1);
	loadn_o <= temp(0);
			 		  			  
-- ADR REG s2 ------------------------------------------------------------------------			  
	adr_reg_s2: entity work.reg(arch)
             generic map (4)
			 port map(input => s2, output => rot, clk =>clk, clr =>clr);
			 
-- Operand A register-----------------------------------------------------------------
	operand_A: entity work.reg(arch)
             generic map (16)
			 port map(input => A, output => A_ex, clk =>clk, clr =>clr);
			 		 
-- Operand B register-----------------------------------------------------------------
	operand_B: entity work.reg(arch)
             generic map (16)
			 port map(input => B, output => B_ex, clk =>clk, clr =>clr);
			 			 
-- Operand C register-----------------------------------------------------------------
	jmp_adr_C: entity work.reg(arch)
             generic map (16)
			 port map(input => C, output => C_ex, clk =>clk, clr =>clr);
    C_out <= C_ex;
-- ADR REG ds ------------------------------------------------------------------------			  
	adr_reg_ds: entity work.reg(arch)
             generic map (4)
			 port map(input => ds, output => ds_ex, clk =>clk, clr =>clr);
	ds_out <= ds_ex;
			 
-- DISPL REG  ------------------------------------------------------------------------			  
	disp_reg: entity work.reg(arch)
             generic map (16)
			 port map(input => displ, output => displ_ex, clk =>clk, clr =>clr);
	displ_out <= displ_ex;
			 
-- MUX A  -----------------------------------------------------------------------------
	sel_a <= rts_o or str_o;
	mux_A: entity work.mux_2(arch)
			 port map(input1 => A_ex, input2 => displ_ex, output => mux_a_ex, sel => sel_a);
			 	
-- MUX B  -----------------------------------------------------------------------------
	sel_b <= rts_o or str_o or push_o or pop_o or jsr_o or ret_o;
	mux_B: entity work.mux_2(arch)
			 port map( input1 => B_ex, input2 => SP, output => mux_b_ex, sel => sel_b);
			 

-- MUX Stack  -----------------------------------------------------------------------------

	mux_stack: entity work.mux_2(arch)
			 port map( input1 => C_ex, input2 => PC_ex, output => STACK_data, sel => jsr_o);
			 
			 
-- ALU UNIT  -----------------------------------------------------------------------------
	sub_alu <= sub_o or bgt_o or blo_o or beq_o;
	add_alu <= add_o or rts_o or str_o;
	inc_alu <= push_o or jsr_o;
	sel_b_alu <= pop_o or ret_o;
	
	alu_unit: entity work.alu(arch)
			 port map(input_a => mux_a_ex, input_b => mux_b_ex, output => RES_out,
					add => add_alu, sub => sub_alu, inc => inc_alu, andi => andi_o, ori => ori_o, xori => xori_o,
					noti => noti_o, rot => movr_o, sel_b => sel_b_alu, rot_value => rot, n => n_alu, z => z_alu);
						 
-- jmp logic --------------------------------------------------------------------------------
	jmp_cond <= (beq_o and z_alu) or (blo_o and n_alu) or ( bgt_o and (not n_alu) and (not z_alu)) or jsr_o or ret_o;
	jmp_cond_out <= jmp_cond;
	 
-- reg wr, load, str, pop for of stage -------------------------------------------------------- 
    reg_wr_out <= reg_ds_wr;
    ret_out <= ret_o;
    load_out <= load_o;
    store_out <= store_o;
    jsr_out <= jsr_o;
    push_out <= push_o;
    str_out <= str_o;
    rts_out <= rts_o;
    pop_out <= pop_o;
    loadn_out <= loadn_o;
    hlt_out <= hlt_o;
end architecture struct;