--------------------------------------------------------------------------------- -- -- Entity: decode -- Filename: decode.vhd -- Description: the Instruction Decode (ID) 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 -- September, 2013: core customization, -- new instructions (Meloun) -- June, 2011: added code for MUL and BARREL (Huib) -- Modified: -- Remarks: -- -------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE WORK.mbl_pkg.all; -------------------------------------------------------------------------------- ENTITY decode IS -------------------------------------------------------------------------------- GENERIC ( USE_HW_MUL_g : BOOLEAN := TRUE; USE_BARREL_g : BOOLEAN := TRUE; COMPATIBILITY_MODE_g : BOOLEAN := FALSE ); PORT ( IF2ID_i : IN IF2ID_Type; imem_data_i : IN STD_LOGIC_VECTOR (31 DOWNTO 0); -- ID2GPRF_o : OUT ID2GPRF_Type; ID2EX_o : OUT ID2EX_Type; -- INT_CTRL_i : IN INT_CTRL_Type; ID2CTRL_o : OUT ID2CTRL_Type ); END ENTITY decode; -------------------------------------------------------------------------------- ARCHITECTURE rtl OF decode IS -------------------------------------------------------------------------------- BEGIN p_decode: PROCESS (IF2ID_i, imem_data_i, INT_CTRL_i) IS VARIABLE prog_counter_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE opcIx_v : STD_LOGIC_VECTOR ( 5 DOWNTO 0); VARIABLE instruction_v : STD_LOGIC_VECTOR (31 DOWNTO 0); VARIABLE rD_v : STD_LOGIC_VECTOR ( 4 DOWNTO 0); VARIABLE rA_v : STD_LOGIC_VECTOR ( 4 DOWNTO 0); VARIABLE rB_v : STD_LOGIC_VECTOR ( 4 DOWNTO 0); VARIABLE IMM16_v : STD_LOGIC_VECTOR (15 DOWNTO 0); VARIABLE code_x26_v : STD_LOGIC_VECTOR ( 2 DOWNTO 0); VARIABLE IMM_Lock_v : STD_LOGIC; VARIABLE alu_Action_v : ALU_ACTION_Type; VARIABLE alu_Op1_v : ALU_IN1_Type; VARIABLE alu_Op2_v : ALU_IN2_Type; VARIABLE alu_Cin_v : ALU_CIN_Type; VARIABLE msr_Action_v : MSR_ACTION_Type; VARIABLE branch_Action_v : BRANCH_ACTION_Type; VARIABLE it_Action_v : IT_ACTION_Type; VARIABLE delayBit_v : STD_LOGIC; VARIABLE mem_Action_v : MEM_ACTION_Type; VARIABLE transfer_Size_v : TRANSFER_SIZE_Type; VARIABLE wrb_Action_v : WRB_ACTION_Type; VARIABLE int_busy_v : STD_LOGIC; VARIABLE condition_raw_v : STD_LOGIC_VECTOR ( 2 DOWNTO 0); VARIABLE halt_v : STD_LOGIC; BEGIN prog_counter_v := IF2ID_i.program_counter; instruction_v := imem_data_i; opcIx_v := instruction_v (31 DOWNTO 26); rD_v := instruction_v (25 DOWNTO 21); rA_v := instruction_v (20 DOWNTO 16); rB_v := instruction_v (15 DOWNTO 11); IMM16_v := instruction_v (15 DOWNTO 0); IMM_Lock_v := '0'; delayBit_v := '0'; IF (COMPATIBILITY_MODE_g = FALSE) THEN it_Action_v := NO_IT; END IF; condition_raw_v := (others => '1'); alu_Cin_v := CIN_ZERO; alu_Action_v := A_NOP; msr_Action_v := KEEP_CARRY; branch_Action_v := NO_BR; mem_Action_v := NO_MEM; transfer_Size_v := WORD; wrb_Action_v := WRB_EX; halt_v := '0'; -- for decoding SEXT16, SEXT8, SRC, SRC or SRL code_x26_v := instruction_v(6) & instruction_v(5) & instruction_v(0); int_busy_v := INT_CTRL_i.int_busy; IF (INT_CTRL_i.setup_int = '1') THEN alu_Op1_v := ALU_IN_ZERO; alu_Op2_v := ALU_IN_IMM; IMM16_v := X"0010"; -- address of _interrupt_handler vector prog_counter_v := INT_CTRL_i.rti_target; -- delayed program counter alu_Action_v := A_ADD; rD_v := "01110"; -- r14 reserved for storing program_counter rA_v := (OTHERS => '0'); -- also set rA and rB to avoid possible ... rB_v := (OTHERS => '0'); -- ... erronuous hazard detection in exeq module int_busy_v := '1'; branch_Action_v := BRL; ELSE alu_Op1_v := ALU_IN_REGA; IF (opcIx_v(3) = '0') THEN alu_Op2_v := ALU_IN_REGB; ELSE alu_Op2_v := ALU_IN_IMM; END IF; CASE opcIx_v (5 DOWNTO 4) IS WHEN "00" => -- ADD / RSUB IF (opcIx_v(0) = '1') THEN -- RSUB alu_Op1_v := ALU_IN_NOT_REGA; END IF; IF (opcIx_v(1) = '0') THEN -- xxx IF (opcIx_v(0) = '0') THEN alu_Cin_v := CIN_ZERO; ELSE alu_Cin_v := CIN_ONE; END IF; ELSE -- xxxC alu_Cin_v := FROM_MSR; END IF; IF ((COMPATIBILITY_MODE_g = TRUE) AND (opcIx_v(3 DOWNTO 0) = "0101") AND (IMM16_v(0)= '1')) THEN -- special CMP(U) and not RSUB(I)K, supported only in compatibility mode IF (IMM16_v(1) = '1') THEN -- U-bit set, CMPU alu_Action_v := A_CMPU; ELSE alu_Action_v := A_CMP; END IF; ELSE alu_Action_v := A_ADD; IF (opcIx_v(2) = '0') THEN msr_Action_v := UPDATE_CARRY; END IF; END IF; WHEN "01" => -- MUL / BS CASE opcIx_v (2 DOWNTO 0) IS WHEN "000" => -- MUL IF (USE_HW_MUL_g = TRUE) THEN alu_Action_v := A_MUL; END IF; WHEN "001" => -- BS IF (USE_BARREL_g = TRUE) THEN IF (instruction_v(10) = '1') THEN alu_Action_v := A_BSLL; ELSIF (instruction_v(9) = '1') THEN alu_Action_v := A_BSRA; ELSE alu_Action_v := A_BSRL; END IF; END IF; WHEN "010" | "011" => -- CMP(U) IF (COMPATIBILITY_MODE_g = FALSE) THEN IF (opcIx_v(0) = '1') THEN alu_Action_v := A_CMPU; ELSE alu_Action_v := A_CMP; END IF; alu_Op1_v := ALU_IN_NOT_REGA; alu_Cin_v := CIN_ONE; END IF; WHEN "100" | "101" => -- IT(U) / ITT(U) / ITE(U) IF (COMPATIBILITY_MODE_g = FALSE) THEN IF (opcIx_v(0) = '1') THEN alu_Action_v := A_CMPU; ELSE alu_Action_v := A_CMP; END IF; CASE rD_v(4 downto 3) IS WHEN "00" => it_Action_v := IT; WHEN "01" => it_Action_v := ITT; WHEN "10" => it_Action_v := ITE; WHEN OTHERS => NULL; END CASE; condition_raw_v := rD_v(2 downto 0); -- IT instruction isn't writing to anything wrb_Action_v := NO_WRB; alu_Op1_v := ALU_IN_NOT_REGA; alu_Cin_v := CIN_ONE; END IF; WHEN OTHERS => NULL; END CASE; WHEN "10" => IF (opcIx_v (3 DOWNTO 0) = "0100") THEN CASE code_x26_v IS WHEN "000" => -- CLZ alu_Action_v := A_CLZ; WHEN "001" | "011" | "101" => CASE code_x26_v(2 DOWNTO 1) IS WHEN "00" => -- SRA alu_Cin_v := FROM_IN1; WHEN "01" => -- SRC alu_Cin_v := FROM_MSR; WHEN "10" => -- SRL alu_Cin_v := CIN_ZERO; WHEN OTHERS => NULL; END CASE; alu_Action_v := A_SHIFT; msr_Action_v := UPDATE_CARRY; WHEN "110" => -- SEXT8 alu_Action_v := A_SEXT8; WHEN "111" => -- SEXT16 alu_Action_v := A_SEXT16; WHEN OTHERS => NULL; END CASE; ELSIF (opcIx_v (3 DOWNTO 0) = "1100") THEN -- IMM IMM_Lock_v := '1'; -- always: IMM_LOCK_o.IMM16 <= IMM16_v; alu_Action_v := A_NOP; wrb_Action_v := NO_WRB; ELSIF (opcIx_v (3 DOWNTO 0) = "1101") THEN CASE rD_v (3 DOWNTO 0) IS WHEN "0001" => -- RTI(D) int_busy_v := '0'; WHEN OTHERS => -- RTS(D) NULL; END CASE; alu_Action_v := A_ADD; branch_Action_v := BR; wrb_Action_v := NO_WRB; delayBit_v := rD_v(4); ELSIF (opcIx_v (3 DOWNTO 0) = "0101") THEN CASE IMM16_v IS WHEN X"8001" => -- MFS (MSR only) alu_Action_v := A_MFS; WHEN X"C001" => -- MTS (MSR only) alu_Action_v := A_MTS; wrb_Action_v := NO_WRB; WHEN OTHERS => NULL; END CASE; rB_v := (OTHERS => '0'); -- in order to prevent occasional hazards (r16, r24) ELSE CASE opcIx_v (2 DOWNTO 0) IS WHEN "000" => alu_Action_v := A_OR; WHEN "001" => alu_Action_v := A_AND; WHEN "010" => alu_Action_v := A_XOR; WHEN "011" => alu_Action_v := A_AND; IF (opcIx_v(3) = '0') THEN alu_Op2_v := ALU_IN_NOT_REGB; ELSE alu_Op2_v := ALU_IN_NOT_IMM; END IF; WHEN "110" => -- BR(I)(D) IF (rA_v(3) = '1') THEN alu_Op1_v := ALU_IN_ZERO; ELSE alu_Op1_v := ALU_IN_PC; END IF; IF (rA_v(2) = '1') THEN branch_Action_v := BRL; ELSE branch_Action_v := BR; wrb_Action_v := NO_WRB; END IF; alu_Action_v := A_ADD; delayBit_v := rA_v(4); WHEN "111" => condition_raw_v := rD_v(2 downto 0); -- Conditional branching branch_Action_v := BR; alu_Action_v := A_ADD; alu_Op1_v := ALU_IN_PC; delayBit_v := rD_v(4); wrb_Action_v := NO_WRB; -- evaluate and update/overwrite in exeq WHEN OTHERS => NULL; END CASE; END IF; WHEN "11" => IF (opcIx_v (3 DOWNTO 0) = "1111") THEN -- HALT alu_Action_v := A_NOP; wrb_Action_v := NO_WRB; halt_v := '1'; ELSE alu_Action_v := A_ADD; CASE opcIx_v (1 DOWNTO 0) IS WHEN "00" => transfer_Size_v := BYTE; WHEN "01" => transfer_Size_v := HALFWORD; WHEN "10" => transfer_Size_v := WORD; WHEN OTHERS => NULL; END CASE; IF (opcIx_v(2) = '0') THEN mem_Action_v := RD_MEM; wrb_Action_v := WRB_MEM; ELSE mem_Action_v := WR_MEM; wrb_Action_v := NO_WRB; END IF; END IF; WHEN OTHERS => NULL; END CASE; END IF; -- interrupt test ID2GPRF_o.rdix_rA <= rA_v; ID2GPRF_o.rdix_rB <= rB_v; ID2GPRF_o.rdix_rD <= rD_v; ID2EX_o.program_counter <= prog_counter_v; ID2EX_o.rdix_rA <= rA_v; ID2EX_o.rdix_rB <= rB_v; ID2EX_o.curr_rD <= rD_v; ID2EX_o.alu_Action <= alu_Action_v; ID2EX_o.alu_Op1 <= alu_Op1_v; ID2EX_o.alu_Op2 <= alu_Op2_v; ID2EX_o.alu_Cin <= alu_Cin_v; ID2EX_o.IMM16 <= IMM16_v; ID2EX_o.IMM_Lock <= IMM_Lock_v; ID2EX_o.msr_Action <= msr_Action_v; ID2EX_o.branch_Action <= branch_Action_v; ID2EX_o.it_Action <= it_Action_v; ID2EX_o.mem_Action <= mem_Action_v; ID2EX_o.transfer_Size <= transfer_Size_v; ID2EX_o.wrb_Action <= wrb_Action_v; ID2EX_o.halt <= halt_v; -- CASE condition_raw_v IS WHEN "000" => ID2EX_o.condition <= COND_EQ; WHEN "001" => ID2EX_o.condition <= COND_NE; WHEN "010" => ID2EX_o.condition <= COND_LT; WHEN "011" => ID2EX_o.condition <= COND_LE; WHEN "100" => ID2EX_o.condition <= COND_GT; WHEN "101" => ID2EX_o.condition <= COND_GE; WHEN "111" => ID2EX_o.condition <= COND_ALL; WHEN OTHERS => ID2EX_o.condition <= COND_ALL; END CASE; -- ID2CTRL_o.delayBit <= delayBit_v; ID2CTRL_o.int_busy <= int_busy_v; END PROCESS; END ARCHITECTURE rtl;