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

entity PipelineCPU is
port(
		
	--control
	clk, reset: in std_logic;
	
	--ROM outputs and inputs
    ROM_rd: out std_logic;
    A_ROM_BUS: out std_logic_vector(15 downto 0);
    D_ROM_BUS: in std_logic_vector(15 downto 0);
    
    -- RAM outputs and inputs
    RAM_rd, RAM_wr: out std_logic;
    A_RAM_BUS: out std_logic_vector(15 downto 0);
    D_RAM_BUS: inout std_logic_vector(15 downto 0) 


	--------- testing ------------
-- IFStage
	  -- CPU_pc_IF :out std_logic_vector(15 downto 0);
	
--IDStage
	  -- CPU_pc_ID :out std_logic_vector(15 downto 0);	
      -- CPU_displ_ID: out std_logic_vector(15 downto 0);
	  -- CPU_s1_ID, CPU_s2_ID, CPU_ds_ID: out std_logic_vector(3 downto 0);
	  -- CPU_reg_s1_rd_ID, CPU_reg_s2_rd_ID, CPU_reg_ds_rd_ID, CPU_reg_ds_wr_ID: out std_logic;
			
--OFStage
	  -- CPU_pc_OF :out std_logic_vector(15 downto 0);
	  -- CPU_instructions_OF: out std_logic_vector(20 downto 0);
	  -- CPU_s2_OF, CPU_ds_OF: out std_logic_vector(3 downto 0);
	  -- CPU_displ_OF: out std_logic_vector(15 downto 0);
	  -- CPU_A_OF, CPU_B_OF, CPU_C_OF: out std_logic_vector(15 downto 0);
		
--EXStage

	  -- CPU_RES_EX:out std_logic_vector(15 downto 0);
	  -- CPU_C_EX:out std_logic_vector(15 downto 0);
	  -- CPU_ds_EX:out std_logic_vector(3 downto 0);
	  -- CPU_STACK_data_EX, CPU_displ_EX:out std_logic_vector(15 downto 0);
      -- CPU_jmp_cond_EX, CPU_reg_wr_EX, CPU_ret_EX, CPU_load_EX, CPU_store_EX, CPU_jsr_EX:out std_logic;
      -- CPU_push_EX, CPU_loadn_EX, CPU_str_EX, CPU_rts_EX, CPU_pop_EX, CPU_hlt_EX:out std_logic;
      
--WBStage 

      -- CPU_sp_WB:out std_logic_vector(15 downto 0);
      -- CPU_SPreset_WB:out std_logic;
      -- CPU_reg_data_WB:out std_logic_vector(15 downto 0);
      -- CPU_ds_WB:out std_logic_vector(3 downto 0); 
      -- CPU_jmp_cond_WB, CPU_reg_wr_WB:out std_logic;
      -- CPU_jmp_adr_WB:out std_logic_vector(15 downto 0);
      -- CPU_hlt_WB:out std_logic;
      
-- STALL unit
      -- CPU_stall_if: out std_logic;
      -- CPU_stall_id: out std_logic;
      -- CPU_stall_of: out std_logic;
      -- CPU_stall_ex: out std_logic;
      -- CPU_stall_wb: out std_logic;
        
      -- CPU_reset_if: out std_logic;
      -- CPU_reset_id: out std_logic;
      -- CPU_reset_of: out std_logic;
      -- CPU_reset_reg_and_sp: out std_logic;
      -- CPU_reset_ex: out std_logic;
      -- CPU_reset_wb: out std_logic
	
	);
end entity PipelineCPU;

architecture struct of PipelineCPU is
-- IFStage
	signal pc_IF :std_logic_vector(15 downto 0);
	signal instr_adr_IF: std_logic_vector(15 downto 0);
	signal instr_rd_IF: std_logic;
	
--IDStage
	signal pc_ID :std_logic_vector(15 downto 0);	
	signal load_ID, store_ID, movr_ID, add_ID, sub_ID, andi_ID, ori_ID, xori_ID, noti_ID: std_logic;
	signal bgt_ID, blo_ID, beq_ID, jsr_ID, ret_ID, push_ID, pop_ID, rts_ID, str_ID, hlt_ID, loadn_ID : std_logic;
	signal reg_s1_rd_ID, reg_s2_rd_ID, reg_ds_rd_ID, reg_ds_wr_ID: std_logic;
	signal displ_ID: std_logic_vector(15 downto 0);
	signal s1_ID, s2_ID, ds_ID: std_logic_vector(3 downto 0);
			
--OFStage
	signal pc_OF :std_logic_vector(15 downto 0);
	signal instructions_OF: std_logic_vector(20 downto 0);
	signal s1_OF, s2_OF, ds_OF: std_logic_vector(3 downto 0);
	signal displ_OF: std_logic_vector(15 downto 0);
	signal A_OF, B_OF, C_OF: std_logic_vector(15 downto 0);
	-- for stall
	signal reg_wr_OF: std_logic;
		
--EXStage

	signal RES_EX: std_logic_vector(15 downto 0);
	signal RAM_data_EX: std_logic_vector(15 downto 0);
	signal C_EX: std_logic_vector(15 downto 0);
	signal ds_EX: std_logic_vector(3 downto 0);
	signal STACK_data_EX, displ_EX: std_logic_vector(15 downto 0);
    signal jmp_cond_EX, reg_wr_EX, ret_EX, load_EX, store_EX, jsr_EX: std_logic;
    signal push_EX, loadn_EX, str_EX, rts_EX, pop_EX, hlt_EX: std_logic;
    signal ld_st, RAM_wr_temp: std_logic;
      
--WBStage 

    signal sp_WB: std_logic_vector(15 downto 0);
    signal SPreset_WB: std_logic;
    signal reg_data_WB: std_logic_vector(15 downto 0);
    signal ds_WB: std_logic_vector(3 downto 0); 
    signal jmp_cond_WB, reg_wr_WB: std_logic;
    signal jmp_adr_WB: std_logic_vector(15 downto 0);
    signal hlt_WB: std_logic;

-- STALL unit

    signal stall_if: std_logic;
    signal stall_id: std_logic;
    signal stall_of: std_logic;
    signal stall_ex: std_logic;
    signal stall_wb: std_logic;
        
    signal reset_if: std_logic;
    signal reset_id: std_logic;
    signal reset_of: std_logic;
    signal reset_reg_and_sp: std_logic;
    signal reset_ex: std_logic;
    signal reset_wb: std_logic;
    
begin

-- IFStage ----------------------------------------------------------
	if_stage: entity work.IFStage(struct)
			 port map(	pc => pc_IF, instr_a_bus => instr_adr_IF, instr_rd => instr_rd_IF,
						jmp_adr => jmp_adr_WB, clk => clk, stall => stall_if, jmp_cond => jmp_cond_WB, clr => reset_if);
						
    ROM_rd <= instr_rd_IF;
    A_ROM_BUS <= instr_adr_IF;				
			
						
--------------- testing -----------------
	  -- CPU_pc_IF <= pc_IF;						

-- IDStage ----------------------------------------------------------
	id_stage: entity work.IDStage(struct)
			 port map(	
				--inputs
				pc => pc_IF,
				ROM_data => D_ROM_BUS,
				clk => clk,  stall => stall_id, clr => reset_id,
				
				--outputs
				load_o => load_ID, store_o => store_ID, movr_o => movr_ID, add_o => add_ID, sub_o => sub_ID,
				andi_o => andi_ID, ori_o => ori_ID, xori_o => xori_ID, noti_o => noti_ID,
				bgt_o => bgt_ID, blo_o => blo_ID, beq_o => beq_ID, jsr_o => jsr_ID, ret_o => ret_ID, 
				push_o => push_ID, pop_o => pop_ID, rts_o => rts_ID, str_o => str_ID, hlt_o => hlt_ID,
				loadn_o => loadn_ID, reg_ds_wr => reg_ds_wr_ID,
				reg_s1_rd => reg_s1_rd_ID, reg_s2_rd => reg_s2_rd_ID, reg_ds_rd => reg_ds_rd_ID,	
				pc_out => pc_ID, displ => displ_ID, s1 => s1_ID, s2 => s2_ID, ds => ds_ID 				
			);
--------------- testing -----------------
	  -- CPU_pc_ID <= pc_ID;
      -- CPU_displ_ID <= displ_ID;
	  -- CPU_s1_ID <= s1_ID;
	  -- CPU_s2_ID <= s2_ID;
      -- CPU_ds_ID <= ds_ID;
      -- CPU_reg_s1_rd_ID <= reg_s1_rd_ID;
      -- CPU_reg_s2_rd_ID <= reg_s2_rd_ID;
      -- CPU_reg_ds_rd_ID <= reg_ds_rd_ID;
      -- CPU_reg_ds_wr_ID <= reg_ds_wr_ID;
	  

-- OFStage ----------------------------------------------------------
	of_stage: entity work.OFStage(struct)
			port map(
					--inputs
					pc => pc_ID,
					load_o => load_ID, store_o => store_ID, movr_o => movr_ID, add_o => add_ID,
					sub_o => sub_ID, andi_o => andi_ID, ori_o => ori_ID, xori_o => xori_ID,
					noti_o => noti_ID, bgt_o => bgt_ID, blo_o => blo_ID, beq_o => beq_ID, jsr_o => jsr_ID,
					ret_o => ret_ID, push_o => push_ID, pop_o => pop_ID, rts_o => rts_ID, str_o => str_ID,
					hlt_o => hlt_ID, loadn_o => loadn_ID, reg_ds_wr => reg_ds_wr_ID,
					s1 => s1_ID, s2 => s2_ID, ds => ds_ID, displ => displ_ID,
				    ds_wb => ds_WB,
					dat_wb => reg_data_WB, reg_wr_wb => reg_wr_WB,
					
					--control
					clk => clk, stall => stall_of, clr => reset_of, reg_reset => reset_reg_and_sp,
					
					--outputs
					pc_out => pc_OF,
					instructions => instructions_OF, s2_out => s2_OF,
					ds_out => ds_OF, 
					displ_out => displ_OF, A_out => A_OF, B_out => B_OF, C_out => C_OF);
				
					
--------------- testing -----------------
	  -- CPU_pc_OF <= pc_OF;
	  -- CPU_instructions_OF <= instructions_OF;
	  -- CPU_s2_OF <= s2_OF;
	  -- CPU_ds_OF <= ds_OF;
	  -- CPU_displ_OF <= displ_OF;
	  -- CPU_A_OF <= A_OF;
	  -- CPU_B_OF <= B_OF;
	  -- CPU_C_OF <= C_OF;			
		
-- EXStage ----------------------------------------------------------
	ex_stage: entity work.EXStage(struct)
 			port map(
					--inputs
                    pc => pc_OF, instructions => instructions_OF, s2 => s2_OF, ds => ds_OF,
                    displ => displ_OF, A => A_OF, B => B_OF, C => C_OF,	SP => SP_wb, 
	
                    -- control	
                    clk => clk, stall => stall_ex, clr => reset_ex,
                    
                    --outputs
                    RES_out => RES_EX, C_out => C_EX, ds_out => ds_EX,
                    STACK_data => STACK_data_EX, displ_out => displ_EX, jmp_cond_out => jmp_cond_EX,
                    reg_wr_out => reg_wr_EX, ret_out => ret_EX, load_out => load_EX,
                    store_out => store_EX, jsr_out => jsr_EX, push_out => push_EX, loadn_out => loadn_EX, 
                    str_out => str_EX, rts_out => rts_EX, pop_out => pop_EX, hlt_out => hlt_EX);
                    
      ld_st <= (load_EX or store_EX) and (not jmp_cond_WB);   
      RAM_rd <= load_EX and (not jmp_cond_WB);
      RAM_wr_temp <= store_EX and (not jmp_cond_WB);
      RAM_wr <= RAM_wr_temp;
      A_RAM_BUS <= RES_EX when ld_st = '1' else "ZZZZZZZZZZZZZZZZ";
      D_RAM_BUS <= C_EX when RAM_wr_temp = '1' else "ZZZZZZZZZZZZZZZZ";                 
                    
--------------- testing -----------------
	  -- CPU_RES_EX <=RES_EX;
	  -- CPU_C_EX <=C_EX;
	  -- CPU_ds_EX <=ds_EX;
	  -- CPU_STACK_data_EX <=STACK_data_EX;
	  -- CPU_displ_EX <=displ_EX;
      -- CPU_jmp_cond_EX <=jmp_cond_EX;
      -- CPU_reg_wr_EX <=reg_wr_EX;
      -- CPU_ret_EX <=ret_EX ;
      -- CPU_load_EX <=load_EX;
      -- CPU_store_EX <=store_EX;
      -- CPU_jsr_EX <=jsr_EX;
      -- CPU_push_EX <=push_EX;
      -- CPU_loadn_EX <=loadn_EX;
      -- CPU_str_EX <=str_EX;
      -- CPU_rts_EX <=rts_EX;
      -- CPU_pop_EX <=pop_EX;
      -- CPU_hlt_EX <=hlt_EX;


-- WBStage ----------------------------------------------------------
    wb_stage: entity work.WBStage(struct)
            port map(
                    --inputs
                    RES => RES_EX,
                    C => C_EX, ds => ds_EX, STACK_data => STACK_data_EX, displ => displ_EX,
                    jmp_cond => jmp_cond_EX, reg_wr => reg_wr_EX, ret => ret_EX, load => load_EX,
                    store => store_EX, jsr => jsr_EX, push => push_EX, loadn => loadn_ex, str => str_EX,
                    rts => rts_EX, pop => pop_EX, hlt => hlt_EX,
                    
                    RAM_data => D_RAM_BUS,
                    -- control	
                    clk => clk, stall => stall_wb, clr => reset_wb, clr_sp => reset_reg_and_sp,

                    -- outputs for other stages
                    sp_out => sp_WB, SPreset => SPreset_WB, reg_data_out => reg_data_WB, ds_out => ds_WB,
                    jmp_cond_out => jmp_cond_WB, reg_wr_out => reg_wr_WB, jmp_adr_out => jmp_adr_WB, hlt_out => hlt_WB);
                    
--------------- testing -----------------
      -- CPU_sp_WB <=sp_WB;
      -- CPU_SPreset_WB <=SPreset_WB;
      -- CPU_reg_data_WB <=reg_data_WB;
      -- CPU_ds_WB <=ds_WB; 
      -- CPU_jmp_cond_WB <=jmp_cond_WB;
      -- CPU_reg_wr_WB <=reg_wr_WB;
      -- CPU_jmp_adr_WB <=jmp_adr_WB;
      -- CPU_hlt_WB <=hlt_WB;
      
-- STALL unit ----------------------------------------------------------------------------
               reg_wr_OF <= instructions_OF(20);
    stall: entity work.stall_unit(arch)
            port map(
            -- inputs -------------
                clk => clk,
                reset => reset,
                SPreset => SPreset_WB,
                jmp_cond => jmp_cond_WB,
                hlt => hlt_WB,
                reg_s1_rd_ID => reg_s1_rd_ID, reg_s2_rd_ID => reg_s2_rd_ID, reg_ds_rd_ID => reg_ds_rd_ID,
                ds_ID => ds_ID, s1_ID => s1_ID, s2_ID => s2_ID, ds_OF => ds_OF, ds_EX => ds_EX,
                reg_wr_OF => reg_wr_OF, reg_wr_EX =>  reg_wr_EX,
            
            -- outputs -------------
                stall_if => stall_if,
                stall_id => stall_id,
                stall_of => stall_of,
                stall_ex => stall_ex,
                stall_wb => stall_wb,
        
                reset_if => reset_if,
                reset_id => reset_id,
                reset_of => reset_of,
                reset_reg_and_sp => reset_reg_and_sp,
                reset_ex => reset_ex,
                reset_wb => reset_wb
        );
        
   --------------- testing -----------------
     -- CPU_stall_if <= stall_if;
     -- CPU_stall_id <= stall_id;
     -- CPU_stall_of <= stall_of;
     -- CPU_stall_ex <= stall_ex;
     -- CPU_stall_wb <= stall_wb;
        
     -- CPU_reset_if <= reset_if;
     -- CPU_reset_id <= reset_id;
     -- CPU_reset_of <= reset_of;
     -- CPU_reset_reg_and_sp <= reset_reg_and_sp;
     -- CPU_reset_ex <= reset_ex;
     -- CPU_reset_wb <= reset_wb;
               
end architecture struct;