--------------------------------------------------------------------------------- -- -- Entity: exeq -- Filename: exeq.vhd -- Description: the Execution (EX) unit for the TUD MB-Lite implementation -- -- Author: Huib Lincklaen Arriens -- Delft University of Technology -- Faculty EEMCS, Department ME&CE, Circuits and Systems -- Date: September, 2010 -- -- Modified: Septemper, 2013: FSL scratched, core customized (Meloun) -- December, 2010: FSL added (Huib) -- June, 2011: added code for MUL and BARREL (Huib) -- Adapted to work with separate fsl_M- -- and fsl_S selectors and automatic -- tumbl<_jtag><_fsl>.vhd generation (Huib) -- Remarks: -- -------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE IEEE.numeric_std.all; USE WORK.mbl_pkg.all; ---------------------------------------------------------- ENTITY exeq IS ---------------------------------------------------------- GENERIC ( USE_HW_MUL_g : BOOLEAN := TRUE; USE_BARREL_g : BOOLEAN := TRUE; COMPATIBILITY_MODE_g : BOOLEAN := FALSE ); PORT ( IF2ID_i : IN IF2ID_Type; -- ID2EX_i : IN ID2EX_Type; delayBit_i : IN STD_LOGIC; GPRF2EX_i : IN GPRF2EX_Type; EX2IF_o : OUT EX2IF_Type; EX2CTRL_o : OUT EX2CTRL_Type; HALT_o : OUT HALT_Type; -- EX_WRB_i : IN WRB_Type; EX_WRB_o : OUT WRB_Type; MEM_WRB_i : IN WRB_Type; -- HAZARD_WRB_i : IN HAZARD_WRB_Type; HAZARD_WRB_o : OUT HAZARD_WRB_Type; -- IMM_LOCK_i : IN IMM_LOCK_Type; IMM_LOCK_o : OUT IMM_LOCK_Type; -- MSR_i : IN MSR_Type; MSR_o : OUT MSR_Type; -- EX2MEM_o : OUT EX2MEM_Type ); END ENTITY exeq; ---------------------------------------------------------- ARCHITECTURE rtl OF exeq IS ---------------------------------------------------------- BEGIN p_exeq: PROCESS (ID2EX_i, GPRF2EX_i, EX_WRB_i, MEM_WRB_i, IF2ID_i, delayBit_i, IMM_LOCK_i, MSR_i, HAZARD_WRB_i) -- function needed by BSLL (only if USE_BARREL_g = TRUE) FUNCTION reverse_bits ( word32 : STD_LOGIC_VECTOR (31 DOWNTO 0) ) RETURN STD_LOGIC_VECTOR IS VARIABLE reversed_v : STD_LOGIC_VECTOR (31 DOWNTO 0); BEGIN f_rev: FOR i IN 0 TO 31 LOOP reversed_v(31-i) := word32(i); END LOOP; RETURN reversed_v; END; VARIABLE data_rA_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE data_rB_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE data_rD_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE in1_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE in2_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE hi16_v : STD_LOGIC_VECTOR (15 DOWNTO 0); VARIABLE IMM32_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE carry_i_v : STD_LOGIC; VARIABLE result_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE carry_o_v : STD_LOGIC; VARIABLE isZero_v : STD_LOGIC; VARIABLE signBit_in1_v : STD_LOGIC; VARIABLE signBit_in2_v : STD_LOGIC; VARIABLE signBit_r_v : STD_LOGIC; VARIABLE rA_eq_ex_rD_v : STD_LOGIC; VARIABLE rB_eq_ex_rD_v : STD_LOGIC; VARIABLE hazard_v : STD_LOGIC; VARIABLE save_rX_v : SAVE_REG_Type; VARIABLE data_rX_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE do_branch_v : STD_LOGIC; VARIABLE byte_Enable_v : STD_LOGIC_VECTOR ( 3 DOWNTO 0); VARIABLE tmp64_v : STD_LOGIC_VECTOR (63 DOWNTO 0); VARIABLE padVec_v : STD_LOGIC_VECTOR (15 DOWNTO 0); VARIABLE do_cond_v : STD_LOGIC; BEGIN rA_eq_ex_rD_v := '0'; rB_eq_ex_rD_v := '0'; hazard_v := '0'; save_rX_v := NO_SAVE; data_rX_v := data_rB_v; -- default value for data_rX_v result_v := (OTHERS => '0'); carry_o_v := '0'; do_branch_v := '0'; byte_Enable_v := (OTHERS => '0'); do_cond_v := '0'; -- MSR_o <= MSR_i; -- pass MSR by default -- create some helper variables IF (ID2EX_i.rdix_rA = EX_WRB_i.wrix_rD) THEN rA_eq_ex_rD_v := '1'; END IF; IF (ID2EX_i.rdix_rB = EX_WRB_i.wrix_rD) THEN rB_eq_ex_rD_v := '1'; END IF; -- test where to obtain data_rA from IF ((EX_WRB_i.wrb_Action = WRB_EX) AND (rA_eq_ex_rD_v = '1')) THEN data_rA_v := EX_WRB_i.data_rD; ELSIF ((MEM_WRB_i.wrb_Action /= NO_WRB) AND (ID2EX_i.rdix_rA = MEM_WRB_i.wrix_rD)) THEN data_rA_v := MEM_WRB_i.data_rD; ELSIF ((HAZARD_WRB_i.hazard = '1') AND (HAZARD_WRB_i.save_rX = SAVE_RA)) THEN data_rA_v := HAZARD_WRB_i.data_rX; ELSE data_rA_v := GPRF2EX_i.data_rA; END IF; -- test where to obtain data_rB from IF ((EX_WRB_i.wrb_Action = WRB_EX) AND (rB_eq_ex_rD_v = '1')) THEN data_rB_v := EX_WRB_i.data_rD; ELSIF ((MEM_WRB_i.wrb_Action /= NO_WRB) AND (ID2EX_i.rdix_rB = MEM_WRB_i.wrix_rD)) THEN data_rB_v := MEM_WRB_i.data_rD; ELSIF ((HAZARD_WRB_i.hazard = '1') AND (HAZARD_WRB_i.save_rX = SAVE_RB)) THEN data_rB_v := HAZARD_WRB_i.data_rX; ELSE data_rB_v := GPRF2EX_i.data_rB; END IF; -- .... or, isn't all necessary data available yet being still in the pipeline ? data_rX_v := data_rB_v; -- default value for data_rX_v IF (EX_WRB_i.wrb_Action = WRB_MEM) THEN IF ((rA_eq_ex_rD_v = '1') OR (rB_eq_ex_rD_v = '1')) THEN hazard_v := '1'; IF (rA_eq_ex_rD_v = '1') THEN save_rX_v := SAVE_RB; -- already by default data_rX_v = data_rB_v ELSE save_rX_v := SAVE_RA; data_rX_v := data_rA_v; END IF; END IF; END IF; IF (IMM_LOCK_i.locked = '1') THEN hi16_v := IMM_LOCK_i.IMM_hi16; ELSIF (ID2EX_i.IMM16(15) = '0') THEN hi16_v := C_16_ZEROS; ELSE hi16_v := C_16_ONES; END IF; IMM32_v := hi16_v & ID2EX_i.IMM16; CASE ID2EX_i.alu_Op1 IS WHEN ALU_IN_REGA => in1_v := data_rA_v; WHEN ALU_IN_NOT_REGA => in1_v := NOT data_rA_v; WHEN ALU_IN_PC => in1_v := ID2EX_i.program_counter; WHEN ALU_IN_ZERO => in1_v := C_32_ZEROS; WHEN OTHERS => NULL; END CASE; CASE ID2EX_i.alu_Op2 IS WHEN ALU_IN_REGB => in2_v := data_rB_v; WHEN ALU_IN_NOT_REGB => in2_v := NOT data_rB_v; WHEN ALU_IN_IMM => in2_v := IMM32_v; WHEN ALU_IN_NOT_IMM => in2_v := NOT IMM32_v; WHEN OTHERS => NULL; END CASE; signBit_in1_v := in1_v(31); signBit_in2_v := in2_v(31); signBit_r_v := data_rA_v(31); -- Init with Op1, then possibly override CASE ID2EX_i.alu_Cin IS WHEN CIN_ZERO => carry_i_v := '0'; WHEN CIN_ONE => carry_i_v := '1'; WHEN FROM_MSR => carry_i_v := MSR_i.C; WHEN FROM_IN1 => carry_i_v := in1_v(31); WHEN OTHERS => carry_i_v := '0'; END CASE; IF (data_rA_v = C_32_ZEROS) THEN isZero_v := '1'; ELSE isZero_v := '0'; END IF; CASE ID2EX_i.alu_Action IS WHEN A_ADD | A_CMP | A_CMPU => ep_add32 ( in1_v, in2_v, carry_i_v, result_v, carry_o_v); CASE ID2EX_i.alu_Action IS WHEN A_CMPU => IF (signBit_in1_v = signBit_in2_v) THEN result_v(31) := NOT signBit_in1_v; END IF; signBit_r_v := result_v(31); IF (COMPATIBILITY_MODE_g = FALSE) AND (ID2EX_i.it_Action /= NO_IT) THEN -- have to update zero flag with current result IF (result_v = C_32_ZEROS) THEN isZero_v := '1'; ELSE isZero_v := '0'; END IF; END IF; WHEN A_CMP => IF (signBit_in1_v = signBit_in2_v) THEN result_v(31) := signBit_in1_v; END IF; signBit_r_v := result_v(31); IF (COMPATIBILITY_MODE_g = FALSE) AND (ID2EX_i.it_Action /= NO_IT) THEN -- have to update zero flag with current result IF (result_v = C_32_ZEROS) THEN isZero_v := '1'; ELSE isZero_v := '0'; END IF; END IF; WHEN OTHERS => NULL; END CASE; WHEN A_OR => result_v := in1_v OR in2_v; WHEN A_AND => result_v := in1_v AND in2_v; WHEN A_XOR => result_v := in1_v XOR in2_v; WHEN A_SHIFT => result_v := carry_i_v & in1_v(31 DOWNTO 1); carry_o_v := in1_v(0); WHEN A_SEXT8 => IF (in1_v(7) = '0') THEN result_v := C_24_ZEROS & in1_v( 7 DOWNTO 0); ELSE result_v := C_24_ONES & in1_v( 7 DOWNTO 0); END IF; WHEN A_SEXT16 => IF (in1_v(15) = '0') THEN result_v := C_16_ZEROS & in1_v(15 DOWNTO 0); ELSE result_v := C_16_ONES & in1_v(15 DOWNTO 0); END IF; WHEN A_MFS => if (COMPATIBILITY_MODE_g = FALSE) THEN result_v := C_24_ZEROS & "00000" & MSR_i.C & MSR_i.IE & '0'; ELSE result_v := MSR_i.C & C_24_ZEROS & "0000" & MSR_i.C & MSR_i.IE & '0'; END IF; WHEN A_MTS => MSR_o.IE <= data_Ra_v(1); MSR_o.C <= data_Ra_v(2); WHEN A_MUL => IF (USE_HW_MUL_g = TRUE) THEN tmp64_v := STD_LOGIC_VECTOR( UNSIGNED(in1_v) * UNSIGNED(in2_v) ); result_v := tmp64_v(31 DOWNTO 0); END IF; WHEN A_BSLL | A_BSRL | A_BSRA => IF (USE_BARREL_g = TRUE) THEN IF (ID2EX_i.alu_Action = A_BSLL) THEN result_v := reverse_bits (in1_v); ELSE result_v := in1_v; END IF; IF (ID2EX_i.alu_Action = A_BSRA) THEN padVec_v := (OTHERS => in1_v(31)); ELSE padVec_v := (OTHERS => '0'); END IF; IF (in2_v(4) = '1') THEN result_v := padVec_v (15 DOWNTO 0) & result_v (31 DOWNTO 16); END IF; IF (in2_v(3) = '1') THEN result_v := padVec_v ( 7 DOWNTO 0) & result_v (31 DOWNTO 8); END IF; IF (in2_v(2) = '1') THEN result_v := padVec_v ( 3 DOWNTO 0) & result_v (31 DOWNTO 4); END IF; IF (in2_v(1) = '1') THEN result_v := padVec_v ( 1 DOWNTO 0) & result_v (31 DOWNTO 2); END IF; IF (in2_v(0) = '1') THEN result_v := padVec_v ( 0 DOWNTO 0) & result_v (31 DOWNTO 1); END IF; IF (ID2EX_i.alu_Action = A_BSLL) THEN result_v := reverse_bits (result_v); END IF; END IF; -- (USE_BARREL_g = TRUE) WHEN A_CLZ => tmp64_v := (OTHERS => '0'); leading_zeroes32 ( in1_v, UNSIGNED(tmp64_v(31 DOWNTO 0)), result_v ); WHEN OTHERS => NULL; END CASE; CASE ID2EX_i.condition IS WHEN COND_EQ => do_cond_v := isZero_v; WHEN COND_NE => do_cond_v := NOT isZero_v; WHEN COND_LT => do_cond_v := signBit_r_v; WHEN COND_LE => do_cond_v := signBit_r_v OR isZero_v; WHEN COND_GT => do_cond_v := NOT (signBit_r_v OR isZero_v); WHEN COND_GE => do_cond_v := NOT signBit_r_v; WHEN COND_ALL => do_cond_v := '1'; WHEN OTHERS => NULL; END CASE; CASE ID2EX_i.branch_Action IS WHEN BR => do_branch_v := do_cond_v; WHEN BRL => do_branch_v := '1'; WHEN OTHERS => NULL; END CASE; IF (do_branch_v = '1') THEN EX2IF_o.take_branch <= '1'; EX2IF_o.branch_target <= result_v; ELSE EX2IF_o.take_branch <= '0'; EX2IF_o.branch_target <= C_32_ZEROS; END IF; -- IT / ITE / ITT conditioning IF (COMPATIBILITY_MODE_g = FALSE) THEN CASE ID2EX_i.it_Action IS WHEN IT => EX2CTRL_o.flush_first <= not do_cond_v; EX2CTRL_o.flush_second <= '0'; EX2CTRL_o.ignore_state <= '1'; WHEN ITT => EX2CTRL_o.flush_first <= not do_cond_v; EX2CTRL_o.flush_second <= not do_cond_v; EX2CTRL_o.ignore_state <= '1'; WHEN ITE => EX2CTRL_o.flush_first <= not do_cond_v; EX2CTRL_o.flush_second <= do_cond_v; EX2CTRL_o.ignore_state <= '1'; WHEN OTHERS => EX2CTRL_o.flush_first <= '0'; EX2CTRL_o.flush_second <= '0'; EX2CTRL_o.ignore_state <= '0'; END CASE; END IF; -- Halting, the instruction parsing is separate HALT_o.halt <= ID2EX_i.halt; IF (ID2EX_i.halt = '1') THEN HALT_o.halt_code <= ID2EX_i.IMM16(4 DOWNTO 0); ELSE HALT_o.halt_code <= (others => '0'); END IF; -- WR_MEM/RD_MEM: result_v --> exeq_result --> mem_address, -- WR_MEM: data_rD --> data_out_to_mem -- BRL: prog_counter --> exeq_result -- else result_v --> exeq_result (data_rD not used) EX2MEM_o.wrix_rD <= ID2EX_i.curr_rD; IF (ID2EX_i.branch_Action = BRL) THEN EX2MEM_o.wrb_Action <= WRB_EX; IF (COMPATIBILITY_MODE_g = TRUE) OR (delayBit_i = '0') THEN EX2MEM_o.exeq_result <= ID2EX_i.program_counter; EX2MEM_o.data_rD <= ID2EX_i.program_counter; ELSE EX2MEM_o.exeq_result <= IF2ID_i.program_counter; EX2MEM_o.data_rD <= IF2ID_i.program_counter; END IF; -- set data_rD_v, although unused, to prevent an inferred latch data_rD_v := GPRF2EX_i.data_rD; ELSE EX2MEM_o.wrb_Action <= ID2EX_i.wrb_Action; EX2MEM_o.exeq_result <= result_v; -- test where to obtain data_rD from IF (HAZARD_WRB_i.hazard = '1') THEN data_rD_v := HAZARD_WRB_i.data_rD; ELSIF ((EX_WRB_i.wrb_Action = WRB_EX) AND (ID2EX_i.curr_rD = EX_WRB_i.wrix_rD)) THEN -- forward rD_data just calculated, to handle e.g. addi rD,rA,Imm; sw rD,mem[y]; ... data_rD_v := EX_WRB_i.data_rD; ELSIF ((MEM_WRB_i.wrb_Action /= NO_WRB) AND (ID2EX_i.curr_rD = MEM_WRB_i.wrix_rD)) THEN data_rD_v := MEM_WRB_i.data_rD; ELSE data_rD_v := GPRF2EX_i.data_rD; END IF; END IF; IF (ID2EX_i.mem_Action /= NO_MEM) THEN CASE ID2EX_i.transfer_Size IS WHEN BYTE => CASE result_v( 1 DOWNTO 0) IS WHEN "00" => byte_Enable_v := "1000"; WHEN "01" => byte_Enable_v := "0100"; WHEN "10" => byte_Enable_v := "0010"; WHEN "11" => byte_Enable_v := "0001"; WHEN OTHERS => NULL; END CASE; WHEN HALFWORD => CASE result_v( 1 DOWNTO 0) IS WHEN "00" => byte_Enable_v := "1100"; WHEN "10" => byte_Enable_v := "0011"; WHEN OTHERS => NULL; END CASE; WHEN OTHERS => byte_Enable_v := "1111"; END CASE; END IF; -- update MSR[C] if needed IF (ID2EX_i.msr_Action = UPDATE_CARRY) THEN MSR_o.C <= carry_o_v; END IF; -- pass remaining data to mem EX2MEM_o.mem_Action <= ID2EX_i.mem_Action; EX2MEM_o.data_rD <= data_rD_v; EX2MEM_o.byte_Enable <= byte_Enable_v; EX2MEM_o.wrix_rD <= ID2EX_i.curr_rD; -- IMM_LOCK_o.locked <= ID2EX_i.IMM_Lock; IMM_LOCK_o.IMM_hi16 <= ID2EX_i.IMM16; -- EX_WRB_o.wrb_Action <= ID2EX_i.wrb_Action; EX_WRB_o.wrix_rD <= ID2EX_i.curr_rD; EX_WRB_o.data_rD <= result_v; -- HAZARD_WRB_o.hazard <= hazard_v; HAZARD_WRB_o.save_rX <= save_rX_v; HAZARD_WRB_o.data_rX <= data_rX_v; HAZARD_WRB_o.data_rD <= data_rD_v; END PROCESS; END ARCHITECTURE rtl;