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

entity WBStage is
port(

-- from ex stage
	RES: in std_logic_vector(15 downto 0);
	C: in std_logic_vector(15 downto 0);
	ds: in std_logic_vector(3 downto 0);
	STACK_data: in std_logic_vector(15 downto 0);
	displ: in std_logic_vector(15 downto 0);
	
    jmp_cond, reg_wr, ret, load, store, jsr, push, loadn, str, rts, pop, hlt: in std_logic;
    
-- from DATA memory
    RAM_data : in std_logic_vector(15 downto 0);
      
-- control	
	clk, stall, clr, clr_sp: in std_logic;

-- outputs for other stages
    sp_out: out std_logic_vector(15 downto 0);
    SPreset: out std_logic;
    reg_data_out: out std_logic_vector(15 downto 0);
    ds_out: out std_logic_vector(3 downto 0); 
    jmp_cond_out, reg_wr_out: out std_logic;
    jmp_adr_out: out std_logic_vector(15 downto 0);
    hlt_out: out std_logic
);
end entity WBStage;


architecture struct of WBStage is   
    
--instructions
	signal temp: std_logic_vector(7 downto 0);
	signal temp_wb: std_logic_vector(7 downto 0);	
	signal jmp_cond_wb, reg_wb, ret_wb, load_wb, loadn_wb, str_wb, pop_wb: std_logic;
	
--Stack
    signal stack_data_wb: std_logic_vector(15 downto 0);
    signal stack_wr, reset, reset1: std_logic;
    signal address, rest: std_logic_vector(7 downto 0);
    
-- RES registre
    signal RES_wb: std_logic_vector(15 downto 0);

-- DISPL registre
    signal displ_wb: std_logic_vector(15 downto 0);
    
-- DS adr reg 
    signal ds_wb: std_logic_vector(3 downto 0);
    
-- C register
    signal C_wb: std_logic_vector(15 downto 0);
    
-- SP register
    signal sp_wb: std_logic_vector(7 downto 0);
    signal extend_wb: std_logic_vector(7 downto 0);
    signal sp_inc_wb: std_logic;
    signal sp_dec_wb: std_logic;

-- DATA from memory
    signal RAM_data_WB: std_logic_vector(15 downto 0);
   
-- Address jump mux
    signal sel1: std_logic;
    signal sel0: std_logic;
    signal sel: std_logic_vector(1 downto 0);
    
begin   
-- Control signals from ex stage ----------------------------------------------------------

    temp(7) <= jmp_cond;
    temp(6) <= reg_wr;
    temp(5) <= ret;
    temp(4) <= load;
    temp(3) <= loadn;
    temp(2) <= str;
    temp(1) <= pop;
    temp(0) <= hlt;


-- CONTROL REGISTER-------------------------------------------------------------------------
	control_register: entity work.reg(arch)
             generic map (8)
			 port map(input => temp, output => temp_wb, clk => clk, clr => clr );

-- Control signals used in wb stage --------------------------------------------------------


    jmp_cond_out <= temp_wb(7);
    reg_wr_out <= temp_wb(6);
    ret_wb <= temp_wb(5);
    load_wb <= temp_wb(4);
    loadn_wb <= temp_wb(3);
    str_wb <= temp_wb(2);
    pop_wb <= temp_wb(1);
    hlt_out <= temp_wb(0);

-- STACK -----------------------------------------------------------------------------------
    stack_wr <= push or rts or jsr;
    address <= RES(7 downto 0);
    rest <= RES(15 downto 8);
    
    stack: entity work.stack(arch) 
            port map(Data_in => STACK_data, Data_out => stack_data_wb, address => address, clk => clk,
                      wr => stack_wr);
                      
    -- SPreset-- 
    reset1 <= '0' when rest = B"00000000" else '1';
    reset <= reset1 and (jsr or push or ret or pop or str or rts);
                       
  	SP_reset: entity work.d_ff(arch)
             port map(input => reset, output => SPreset, clk => clk, clr => clr );

                            
-- RES registre -----------------------------------------------------------------------------
    RES_register: entity work.reg(arch)
             generic map (16)
			 port map(input => RES, output => RES_wb, clk => clk, clr => clr);
					
-- DISPL registre ------------------------------------------------------------------------------
    displ_register: entity work.reg(arch)
             generic map (16)
			 port map(input => displ, output => displ_wb, clk => clk, clr => clr);
			 
-- DS address reg ----------------------------------------------------------------------------------- 
	adr_reg_ds: entity work.reg(arch)
             generic map (4)
			 port map(input => ds, output => ds_wb, clk => clk, clr => clr);
			 ds_out <= ds_wb;
-- C register ------------------------------------------------------------------------------------
	jmp_adr_C: entity work.reg(arch)
             generic map (16)
			 port map(input => C, output => C_wb, clk => clk, clr => clr);

-- SP register -----------------------------------------------------------------------------------
               sp_inc_wb <= jsr or push;
               sp_dec_wb <= ret or pop;
    SP_reg: entity work.sp(arch)
             port map(output => sp_wb, clk => clk, clr => clr_sp,
              inc => sp_inc_wb, dec => sp_dec_wb);
              
    extend_wb <= "00000000";
    sp_out <=  extend_wb & sp_wb;  
           
-- Data out mux -------------------------------------------------------------------------------
    sel1 <= str_wb or pop_wb or loadn_wb;
    sel0 <= load_wb or loadn_wb;
    sel <= sel1 & sel0;
    RAM_data_WB <= RAM_data when (load_wb = '1') else "ZZZZZZZZZZZZZZZZ";
    data_out_mux: entity work.mux_4(arch)
			 port map(       
                      input1 => RES_wb,
                      input2 => RAM_data_WB,
                      input3 => stack_data_wb,
                      input4 => displ_wb,
                      output => reg_data_out,
                      sel => sel
                     );
-- JMP address mux ----------------------------------------------------------------------------
    jmp_address_mux: entity work.mux_2(arch)
              port map(
                       input1 => C_wb,
                       input2 => stack_data_wb,
                       output => jmp_adr_out,
                       sel => ret_wb
                      );

end architecture struct;