From 342b65f43eca19d8169829aa8d342d1424c6d323 Mon Sep 17 00:00:00 2001 From: Martin Meloun Date: Thu, 5 Sep 2013 18:04:56 +0200 Subject: [PATCH] Initial commit for MBLite+ Tumbl (used as coprocessor) This does not include memory interconnections (registers, instruction and data memory wiring is required). Signed-off-by: Martin Meloun --- hw/core_ctrl.vhd | 310 +++++++++++++++++++++++++++++ hw/decode.vhd | 358 ++++++++++++++++++++++++++++++++++ hw/exeq.vhd | 442 +++++++++++++++++++++++++++++++++++++++++ hw/fetch.vhd | 54 +++++ hw/mbl_Pkg.vhd | 498 +++++++++++++++++++++++++++++++++++++++++++++++ hw/mem.vhd | 141 ++++++++++++++ 6 files changed, 1803 insertions(+) create mode 100644 hw/core_ctrl.vhd create mode 100644 hw/decode.vhd create mode 100644 hw/exeq.vhd create mode 100644 hw/fetch.vhd create mode 100644 hw/mbl_Pkg.vhd create mode 100644 hw/mem.vhd diff --git a/hw/core_ctrl.vhd b/hw/core_ctrl.vhd new file mode 100644 index 0000000..95289fb --- /dev/null +++ b/hw/core_ctrl.vhd @@ -0,0 +1,310 @@ +--------------------------------------------------------------------------------- +-- +-- Entity: core_ctrl +-- Filename: core_ctrl.vhd +-- Description: the control unit for the TUD MB-Lite implementation +-- +-- Author: Huib Lincklaen Arriens +-- Delft University of Technology +-- Faculty EEMCS, Department ME&CE, Circuits and Systems +-- Date: December, 2010 +-- Modified: September, 2012: interrupt handling corrected to let +-- a pending branch be taken first +-- (with thanks to Matthis Meier, TU Dortmund, +-- for detecting this errror). +-- Remarks: +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; + +USE IEEE.std_logic_1164.all; +USE WORK.mbl_Pkg.all; + + +-------------------------------------------------------------------------------- +ENTITY core_ctrl IS +-------------------------------------------------------------------------------- + PORT ( + clk_i : IN STD_LOGIC; + rst_i : IN STD_LOGIC; +-- halt_i : IN STD_LOGIC; + int_i : IN STD_LOGIC; + -- specific fetch i/o + imem_addr_o : OUT STD_LOGIC_VECTOR (31 DOWNTO 0); + imem_clken_o : OUT STD_LOGIC; + pc_ctrl_o : OUT STD_LOGIC; + -- fetch to decode pipeline registers + IF2ID_REG_i : IN IF2ID_Type; + IF2ID_REG_o : OUT IF2ID_Type; + -- decode to exeq pipeline registers + ID2EX_REG_i : IN ID2EX_Type; + ID2EX_REG_o : OUT ID2EX_Type; + -- GPRF control + gprf_clken_o : OUT STD_LOGIC; + -- exeq to fetch feedback registers + EX2IF_REG_i : IN EX2IF_Type; + EX2IF_REG_o : OUT EX2IF_Type; + -- exeq to mem pipeline registers + EX2MEM_REG_i : IN EX2MEM_Type; + EX2MEM_REG_o : OUT EX2MEM_Type; + -- mem pipeline register + MEM_REG_i : IN MEM_REG_Type; + MEM_REG_o : OUT MEM_REG_Type; + -- FSL to mem data delay register(s) + FSL_S2MEM_REG_i : IN FSL_S2MEM_Type; + FSL_S2MEM_REG_o : OUT FSL_S2MEM_Type; + -- decode control i/o + ID2CTRL_i : IN ID2CTRL_Type; + INT_CTRL_o : OUT INT_CTRL_Type; + -- exeq control i/o + EX_WRB_i : IN WRB_Type; + EX_WRB_o : OUT WRB_Type; + -- data hazard i/o + HAZARD_WRB_i : IN HAZARD_WRB_Type; + HAZARD_WRB_o : OUT HAZARD_WRB_Type; + -- for handling the 'IMM' instruction + IMM_LOCK_i : IN IMM_LOCK_Type; + IMM_LOCK_o : OUT IMM_LOCK_Type; + -- for handling the Machine Status Register + MSR_i : IN MSR_Type; + MSR_o : OUT MSR_Type; + -- miscellaneous + MEM2CTRL_i : IN MEM2CTRL_Type; + FSL_nStall_i : IN STD_LOGIC; + done_o : OUT STD_LOGIC + ); +END ENTITY core_ctrl; + +-------------------------------------------------------------------------------- +ARCHITECTURE rtl OF core_ctrl IS +-------------------------------------------------------------------------------- + + SIGNAL rst_r : STD_LOGIC; + SIGNAL reset_s : STD_LOGIC; + + SIGNAL ID2EX_REG_r : ID2EX_Type; + SIGNAL EX2IF_REG_r : EX2IF_Type; + SIGNAL delayBit_r : STD_LOGIC; + SIGNAL delayBit_2r : STD_LOGIC; + SIGNAL IMM_LOCK_r : IMM_LOCK_Type; + SIGNAL HAZARD_WRB_r : HAZARD_WRB_Type; + + SIGNAL clken_s : STD_LOGIC; + SIGNAL clken_pipe_s : STD_LOGIC; + SIGNAL flush_ID2EX_s : STD_LOGIC; + SIGNAL flush_ID2EX_r : STD_LOGIC; + SIGNAL flush_EX2MEM_s : STD_LOGIC; + + SIGNAL setup_int_r : STD_LOGIC; + SIGNAL int_busy_r : STD_LOGIC; + + SIGNAL S_Data_r : STD_LOGIC_VECTOR (31 DOWNTO 0); + SIGNAL S_Data_2r : STD_LOGIC_VECTOR (31 DOWNTO 0); + + +BEGIN + + -- static connections + reset_s <= rst_i OR rst_r; + pc_ctrl_o <= NOT rst_r; + imem_addr_o <= IF2ID_REG_i.program_counter; + -- clock/wait control lines + clken_s <= (MEM2CTRL_i.clken AND FSL_nStall_i) OR rst_i; + clken_pipe_s <= clken_s AND (NOT HAZARD_WRB_i.hazard); + imem_clken_o <= clken_pipe_s; + gprf_clken_o <= clken_s; + -- signals for clearing the ID2EX and EX2MEM registers during branches + flush_ID2EX_s <= EX2IF_REG_r.take_branch; + flush_EX2MEM_s <= (flush_ID2EX_s AND (NOT delayBit_2r)) OR HAZARD_WRB_i.hazard; + -- outputs that need to be readable too, so needing shadowing signals + ID2EX_REG_o <= ID2EX_REG_r; + EX2IF_REG_o <= EX2IF_REG_r; + IMM_LOCK_o <= IMM_LOCK_r; + HAZARD_WRB_o <= HAZARD_WRB_r; + -- + INT_CTRL_o.setup_int <= setup_int_r; + INT_CTRL_o.rti_target <= ID2EX_REG_r.program_counter; + INT_CTRL_o.int_busy <= int_busy_r; + -- + FSL_S2MEM_REG_o.S_Data <= S_Data_2r; + +regd_proc: + PROCESS ( clk_i, rst_i, + -- complete sensitivity list for synthesizer + reset_s, MEM2CTRL_i, clken_pipe_s, IF2ID_REG_i, + flush_ID2EX_s, flush_EX2MEM_s, HAZARD_WRB_i, + MEM_REG_i, ID2CTRL_i, int_i, MSR_i, + int_busy_r, delayBit_r, IMM_LOCK_i, ID2EX_REG_i, ID2EX_REG_r, + EX2IF_REG_i, EX_WRB_i, S_Data_r, FSL_S2MEM_REG_i, EX2MEM_REG_i ) + + -- some local procedures + PROCEDURE lp_rst_IF2ID_REG IS + BEGIN + IF2ID_REG_o.program_counter <= (OTHERS => '0'); + END PROCEDURE; + + PROCEDURE lp_rst_ID2EX_REG IS + BEGIN + -- reset and handle ID2EX_REG_r.program_counter separately, + -- since it will be needed during interrupt setup + ID2EX_REG_r.rdix_rA <= (OTHERS => '0'); + ID2EX_REG_r.rdix_rB <= (OTHERS => '0'); + ID2EX_REG_r.curr_rD <= (OTHERS => '0'); + ID2EX_REG_r.alu_Action <= A_NOP; + ID2EX_REG_r.alu_Op1 <= ALU_IN_ZERO; + ID2EX_REG_r.alu_Op2 <= ALU_IN_IMM; + ID2EX_REG_r.alu_Cin <= CIN_ZERO; + ID2EX_REG_r.IMM16 <= (OTHERS => '0'); + ID2EX_REG_r.IMM_Lock <= '0'; + ID2EX_REG_r.msr_Action <= KEEP_CARRY; + ID2EX_REG_r.branch_Action <= NO_BR; + ID2EX_REG_r.mem_Action <= NO_MEM; + ID2EX_REG_r.transfer_Size <= WORD; + ID2EX_REG_r.wrb_Action <= NO_WRB; + ID2EX_REG_r.FSL_Test <= '1'; + ID2EX_REG_r.FSL_Non_blocking <= '1'; + ID2EX_REG_r.FSL_Control <= '0'; + ID2EX_REG_r.FSL_Atomic <= '0'; + END PROCEDURE; + + PROCEDURE lp_rst_EX2IF_REG IS + BEGIN + EX2IF_REG_r.take_branch <= '0'; + EX2IF_REG_r.branch_target <= (OTHERS => '0'); + END PROCEDURE; + + PROCEDURE lp_rst_EX2MEM_REG IS + BEGIN + EX2MEM_REG_o.mem_Action <= NO_MEM; + EX2MEM_REG_o.wrb_Action <= NO_WRB; + EX2MEM_REG_o.exeq_result <= (OTHERS => '0'); + EX2MEM_REG_o.data_rD <= (OTHERS => '0'); + EX2MEM_REG_o.byte_Enable <= (OTHERS => '0'); + EX2MEM_REG_o.wrix_rD <= (OTHERS => '0'); + END PROCEDURE; + + PROCEDURE lp_rst_FSL2MEM_REG IS + BEGIN + S_Data_r <= (OTHERS => '0'); + S_Data_2r <= (OTHERS => '0'); + END PROCEDURE; + + PROCEDURE lp_rst_IMM_LOCK IS + BEGIN + IMM_LOCK_r.locked <= '0'; + IMM_LOCK_r.IMM_hi16 <= (OTHERS => '0'); + END PROCEDURE; + + PROCEDURE lp_rst_MSR IS + BEGIN + MSR_o.IE <= '0'; + MSR_o.C <= '0'; + MSR_o.FSL <= '0'; + END PROCEDURE; + + PROCEDURE lp_rst_EX_WRB IS + BEGIN + EX_WRB_o.wrb_Action <= NO_WRB; + EX_WRB_o.wrix_rD <= (OTHERS => '0'); + EX_WRB_o.data_rD <= (OTHERS => '0'); + END PROCEDURE; + + PROCEDURE lp_rst_HAZARD_WRB IS + BEGIN + HAZARD_WRB_r.hazard <= '0'; + HAZARD_WRB_r.save_rX <= NO_SAVE; + HAZARD_WRB_r.data_rX <= (OTHERS => '0'); + HAZARD_WRB_r.data_rD <= (OTHERS => '0'); + END PROCEDURE; + + PROCEDURE lp_rst_MEM_REG IS + BEGIN + MEM_REG_o.wrb_Action <= NO_WRB; + MEM_REG_o.exeq_result <= (OTHERS => '0'); + MEM_REG_o.byte_Enable <= (OTHERS => '0'); + MEM_REG_o.wrix_rD <= (OTHERS => '0'); + END PROCEDURE; + + BEGIN + IF (RISING_EDGE (clk_i) AND (MEM2CTRL_i.clken = '1')) THEN + rst_r <= rst_i; + IF (reset_s = '1') THEN -- synchronous reset ... + lp_rst_IF2ID_REG; -- ... so lasts at least one clock_cycle + lp_rst_MSR; + lp_rst_HAZARD_WRB; + lp_rst_MEM_REG; + lp_rst_FSL2MEM_REG; + delayBit_r <= '0'; + flush_ID2EX_r <= '0'; + setup_int_r <= '0'; + int_busy_r <= '0'; + done_o <= '0'; + ID2EX_REG_r.program_counter <= (OTHERS => '0'); + ELSE + IF (clken_pipe_s = '1') THEN + IF2ID_REG_o <= IF2ID_REG_i; + END IF; + flush_ID2EX_r <= flush_ID2EX_s; + HAZARD_WRB_r <= HAZARD_WRB_i; + MEM_REG_o <= MEM_REG_i; + int_busy_r <= ID2CTRL_i.int_busy; + END IF; + -- decode-to-exeq unit registers + IF ((reset_s = '1') OR (flush_ID2EX_s = '1')) THEN + lp_rst_ID2EX_REG; + delayBit_r <= '0'; + -- check for the need and possibility to handle active interrupt requests + ELSIF (((int_i = '1') OR (MEM2CTRL_i.int = '1')) AND (MSR_i.IE = '1') AND + (ID2CTRL_i.int_busy = '0') AND (int_busy_r = '0') AND + -- pending branch should be taken before interrupt can be executed + -- dectected by Matthis Meier, TU Dortmund (Sept 2012) + (EX2IF_REG_i.take_branch = '0') AND + (delayBit_r = '0') AND + (IMM_LOCK_i.locked = '0') AND + (HAZARD_WRB_i.hazard = '0')) THEN + setup_int_r <= '1'; + ID2EX_REG_r.program_counter <= ID2EX_REG_i.program_counter; + lp_rst_ID2EX_REG; + ELSIF (clken_pipe_s = '1') THEN + setup_int_r <= '0'; + ID2EX_REG_r <= ID2EX_REG_i; + delayBit_r <= ID2CTRL_i.delayBit; + END IF; + -- exeq-to-mem unit registers + IF ((reset_s = '1') OR (flush_EX2MEM_s = '1')) THEN + lp_rst_EX2IF_REG; + lp_rst_EX2MEM_REG; + lp_rst_EX_WRB; + lp_rst_IMM_LOCK; + delayBit_2r <= '0'; + ELSE + IF (clken_pipe_s = '1') THEN + EX2IF_REG_r <= EX2IF_REG_i; + delayBit_2r <= delayBit_r; + EX_WRB_o <= EX_WRB_i; + S_Data_2r <= S_Data_r; + S_Data_r <= FSL_S2MEM_REG_i.S_Data; + END IF; + IF (clken_s = '1') THEN + -- next test to prevent a flush from disrupting + -- the write-back pipeline + IF (flush_ID2EX_r = '0') THEN + EX2MEM_REG_o <= EX2MEM_REG_i; + END IF; + IMM_LOCK_r <= IMM_LOCK_i; + MSR_o <= MSR_i; + END IF; + END IF; + -- check on End-Of-Program viz. "bri 0x00" + -- use delayBit to distinguish between "bri" and "rtsd/rtid" + IF ((ID2EX_REG_r.branch_Action = BR) AND + (ID2EX_REG_r.alu_Op2 = ALU_IN_IMM) AND + (ID2EX_REG_r.IMM16 = C_16_ZEROS) AND + (delayBit_r = '0') AND (flush_EX2MEM_s = '0')) THEN + done_o <= '1'; + END IF; + END IF; -- rising edge clk_i ... + END PROCESS regd_proc; + +END ARCHITECTURE rtl; diff --git a/hw/decode.vhd b/hw/decode.vhd new file mode 100644 index 0000000..bee212b --- /dev/null +++ b/hw/decode.vhd @@ -0,0 +1,358 @@ +--------------------------------------------------------------------------------- +-- +-- 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 +-- 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 := FALSE; + USE_BARREL_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 +-------------------------------------------------------------------------------- + + SIGNAL noLiteOpc_s : STD_LOGIC; + +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 FSL_Mode_v : STD_LOGIC_VECTOR ( 4 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 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; + + 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'; + 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; + FSL_Mode_v := "01010"; + -- 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; + -- for debugging purposes + noLiteOpc_s <= '0'; + + 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 / CMP + IF (opcIx_v(0) = '1') THEN -- RSUB / CMP + 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 ((opcIx_v(3 DOWNTO 0) = "0101") AND (IMM16_v(0)= '1')) THEN + -- special CMP(U) and not RSUB(I)K + 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 / FSL + CASE opcIx_v (2 DOWNTO 0) IS + WHEN "000" => -- MUL + IF (USE_HW_MUL_g = TRUE) THEN + alu_Action_v := A_MUL; + ELSE + noLiteOpc_s <= '1'; + END IF; + WHEN "001" => -- BS + IF (USE_BARREL_g = TRUE) THEN + IF (instruction_v(10) = '1') THEN + alu_Action_v := A_BSLL; + ELSE + IF (instruction_v(9) = '1') THEN + alu_Action_v := A_BSRA; + ELSE + alu_Action_v := A_BSRL; + END IF; + END IF; + ELSE + noLiteOpc_s <= '1'; + END IF; + WHEN "011" => -- FSL + IF (opcIx_v(3) = '0') THEN + FSL_Mode_v := instruction_v(10 DOWNTO 6); + ELSE + FSL_Mode_v := instruction_v(15 DOWNTO 11); + END IF; + IF (FSL_Mode_v(4) = '0') THEN + alu_Action_v := A_FSL_GET; + wrb_Action_v := WRB_FSL; + ELSE + alu_Action_v := A_FSL_PUT; + wrb_Action_v := NO_WRB; + END IF; + msr_Action_v := UPDATE_CARRY; + WHEN OTHERS => + noLiteOpc_s <= '1'; + END CASE; + + WHEN "10" => + IF (opcIx_v (3 DOWNTO 0) = "0100") THEN + CASE code_x26_v IS + 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 => + noLiteOpc_s <= '1'; + 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 => + noLiteOpc_s <= '1'; + 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 IS + WHEN "10001" => -- RTID + int_busy_v := '0'; + WHEN "10000" => -- RTSD +-- WHEN "10010" => -- RTBD +-- WHEN "10100" => -- RTED + WHEN OTHERS => + noLiteOpc_s <= '1'; + END CASE; + alu_Action_v := A_ADD; + branch_Action_v := BR; + wrb_Action_v := NO_WRB; + delayBit_v := '1'; + 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 => + noLiteOpc_s <= '1'; + 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) + IF (rA_v(2) = '1') THEN + branch_Action_v := BRL; + ELSE + branch_Action_v := BR; + wrb_Action_v := NO_WRB; + END IF; + IF (rA_v(3) = '1') THEN + alu_Op1_v := ALU_IN_ZERO; + ELSE + alu_Op1_v := ALU_IN_PC; + END IF; + IF (rA_v(4) = '1') THEN + delayBit_v := '1'; + END IF; + alu_Action_v := A_ADD; + WHEN "111" => + CASE rD_v(3 DOWNTO 0) IS + WHEN "0000" => -- BEQ + branch_Action_v := BEQ; + WHEN "0001" => -- BNE + branch_Action_v := BNE; + WHEN "0010" => -- BLT + branch_Action_v := BLT; + WHEN "0011" => -- BLE + branch_Action_v := BLE; + WHEN "0100" => -- BGT + branch_Action_v := BGT; + WHEN "0101" => -- BGE + branch_Action_v := BGE; + WHEN OTHERS => + noLiteOpc_s <= '1'; + END CASE; + 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 => + noLiteOpc_s <= '1'; + END CASE; + END IF; + + WHEN "11" => + 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 => + noLiteOpc_s <= '1'; + 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; + + WHEN OTHERS => + noLiteOpc_s <= '1'; + + 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.mem_Action <= mem_Action_v; + ID2EX_o.transfer_Size <= transfer_Size_v; + ID2EX_o.wrb_Action <= wrb_Action_v; + ID2EX_o.FSL_Non_blocking <= FSL_Mode_v(3); + ID2EX_o.FSL_Control <= FSL_Mode_v(2); + ID2EX_o.FSL_Test <= FSL_Mode_v(1); + ID2EX_o.FSL_Atomic <= FSL_Mode_v(0); + -- + ID2CTRL_o.delayBit <= delayBit_v; + ID2CTRL_o.int_busy <= int_busy_v; + + + + END PROCESS; + +END ARCHITECTURE rtl; + diff --git a/hw/exeq.vhd b/hw/exeq.vhd new file mode 100644 index 0000000..da14be3 --- /dev/null +++ b/hw/exeq.vhd @@ -0,0 +1,442 @@ +--------------------------------------------------------------------------------- +-- +-- 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: 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 := FALSE; + USE_BARREL_g : BOOLEAN := FALSE + ); + PORT ( + ID2EX_i : IN ID2EX_Type; + GPRF2EX_i : IN GPRF2EX_Type; + EX2IF_o : OUT EX2IF_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; + -- + exq_branch_i : IN STD_LOGIC; + -- + FSL_M2EX_i : IN FSL_M2EX_Type; + EX2FSL_M_o : OUT EX2FSL_M_Type; + -- + FSL_S2EX_i : IN FSL_S2EX_Type; + EX2FSL_S_o : OUT EX2FSL_S_Type; + -- + FSL_nStall_o : OUT STD_LOGIC + ); +END ENTITY exeq; + + +---------------------------------------------------------- +ARCHITECTURE rtl OF exeq IS +---------------------------------------------------------- + +BEGIN + +p_exeq: + PROCESS (ID2EX_i, GPRF2EX_i, EX_WRB_i, MEM_WRB_i, + IMM_LOCK_i, MSR_i, exq_branch_i, FSL_M2EX_i, FSL_S2EX_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_rA_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 FSLx_M_v : STD_LOGIC_VECTOR ( 3 DOWNTO 0); + VARIABLE FSLx_S_v : STD_LOGIC_VECTOR ( 3 DOWNTO 0); + VARIABLE FSL_Read_v : STD_LOGIC; + VARIABLE FSL_Write_v : STD_LOGIC; + VARIABLE FSL_nStall_v : STD_LOGIC; + VARIABLE FSL_Atomic_v : STD_LOGIC; + VARIABLE FSL_Error_v : STD_LOGIC; + VARIABLE tmp64_v : STD_LOGIC_VECTOR (63 DOWNTO 0); + VARIABLE padVec_v : STD_LOGIC_VECTOR (15 DOWNTO 0); + + 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 := "0000"; + FSLx_M_v := (OTHERS => '0'); + FSLx_S_v := (OTHERS => '0'); + FSL_Read_v := '0'; + FSL_Write_v := '0'; + FSL_nStall_v := '1'; + FSL_Atomic_v := '0'; + FSL_Error_v := MSR_i.FSL; + + -- 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'; +-- always?? IF (MEM_WRB_i.wrb_Action = WRB_MEM) THEN + -- handle situations in which both rA and rB needed + 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; + 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_rA_v := data_rA_v(31); + + 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; + + 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); + IF (id2ex_i.alu_Action = A_CMPU) THEN + IF (signBit_in1_v = signBit_in2_v) THEN + result_v(31) := NOT signBit_in1_v; + END IF; + ELSIF (id2ex_i.alu_Action = A_CMP) THEN + IF (signBit_in1_v = signBit_in2_v) THEN + result_v(31) := signBit_in1_v; + END IF; + END IF; + 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 => + result_v := MSR_i.C & C_24_ZEROS & "00" & MSR_i.FSL & '0' & MSR_i.C & MSR_i.IE & '0'; + WHEN A_MTS => + MSR_o.IE <= data_Ra_v(1); + MSR_o.C <= data_Ra_v(2); + MSR_o.FSL <= data_Ra_v(4); + 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_FSL_GET => + -- to be examined here, since FSL instruction treated differently than + -- e.g. memory read/writes, i.e. MSR-C and -FSL_E bit have to be set + -- depending on input values (exq_branch_i equals EX2IF_r.take_branch, i.e. + -- a one clock cycle delayed EX2IF_o.take_branch). + IF (exq_branch_i = '0') THEN + FSLx_S_v := in2_v(3 DOWNTO 0); + FSL_Read_v := FSL_S2EX_i.S_Exists AND (NOT hazard_v); + FSL_Atomic_v := ID2EX_i.FSL_Atomic; + IF (ID2EX_i.FSL_Non_blocking = '0') THEN + FSL_nStall_v := FSL_Read_v; + ELSE + carry_o_v := NOT FSL_Read_v; + IF ((FSL_Read_v = '1') AND + (ID2EX_i.FSL_Control /= FSL_S2EX_i.S_Control)) THEN + FSL_Error_v := '1'; + ELSE + FSL_Error_v := '0'; + END IF; + END IF; + END IF; + WHEN A_FSL_PUT => + FSLx_M_v := in2_v(3 DOWNTO 0); + FSL_Write_v := NOT (FSL_M2EX_i.M_Full OR hazard_v); + FSL_Atomic_v := ID2EX_i.FSL_Atomic; + IF (ID2EX_i.FSL_Non_blocking = '0') THEN + FSL_nStall_v := FSL_Write_v; + ELSE + carry_o_v := FSL_M2EX_i.M_Full; + END IF; + WHEN OTHERS => + NULL; + END CASE; + + IF (data_rA_v = C_32_ZEROS) THEN + isZero_v := '1'; + ELSE + isZero_v := '0'; + END IF; + CASE ID2EX_i.branch_Action IS + WHEN BR => do_branch_v := '1'; + WHEN BRL => do_branch_v := '1'; + WHEN BEQ => do_branch_v := isZero_v; + WHEN BNE => do_branch_v := NOT isZero_v; + WHEN BLT => do_branch_v := signBit_rA_v; + WHEN BLE => do_branch_v := signBit_rA_v OR isZero_v; + WHEN BGT => do_branch_v := NOT (signBit_rA_v OR isZero_v); + WHEN BGE => do_branch_v := NOT signBit_rA_v; + 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; + + -- 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; + EX2MEM_o.exeq_result <= ID2EX_i.program_counter; + EX2MEM_o.data_rD <= ID2EX_i.program_counter; + -- 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[IE], MSR[C] and/or MSR[FSL_Error] if needed + IF (ID2EX_i.alu_Action /= A_MTS) THEN + MSR_o.FSL <= FSL_Error_v; + MSR_o.IE <= MSR_i.IE AND (NOT FSL_Atomic_v); + IF (ID2EX_i.msr_Action = UPDATE_CARRY) THEN + MSR_o.C <= carry_o_v; + ELSE + MSR_o.C <= MSR_i.C; + END IF; + 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; + -- + EX2FSL_M_o.FSLx_M <= FSLx_M_v; + EX2FSL_M_o.M_Write <= FSL_Write_v; + EX2FSL_M_o.M_Data <= data_rA_v; + EX2FSL_M_o.M_Control <= ID2EX_i.FSL_Control; + -- + EX2FSL_S_o.FSLx_S <= FSLx_S_v; + EX2FSL_S_o.S_Read <= FSL_Read_v; + -- + FSL_nStall_o <= FSL_nStall_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; + diff --git a/hw/fetch.vhd b/hw/fetch.vhd new file mode 100644 index 0000000..0872293 --- /dev/null +++ b/hw/fetch.vhd @@ -0,0 +1,54 @@ +--------------------------------------------------------------------------------- +-- +-- Entity: fetch +-- Filename: fetch.vhd +-- Description: the Instruction Fetch (IF) 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: +-- Remarks: +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; +USE IEEE.std_logic_1164.all; +USE WORK.mbl_Pkg.all; + +-------------------------------------------------------------------------------- +ENTITY fetch IS +-------------------------------------------------------------------------------- + PORT ( + prog_cntr_i : IN STD_LOGIC_VECTOR (31 DOWNTO 0); + inc_pc_i : IN STD_LOGIC; + EX2IF_i : IN EX2IF_Type; + IF2ID_o : OUT IF2ID_Type + ); +END ENTITY fetch; + + +-------------------------------------------------------------------------------- +ARCHITECTURE rtl OF fetch IS +-------------------------------------------------------------------------------- + +BEGIN + +p_fetch: + PROCESS ( prog_cntr_i, inc_pc_i, EX2IF_i ) + VARIABLE next_pc_v : STD_LOGIC_VECTOR (31 DOWNTO 0); + VARIABLE incVal_v : STD_LOGIC_VECTOR (31 DOWNTO 0); + VARIABLE dummy_v : STD_LOGIC; + BEGIN + incVal_v := X"0000000" & '0' & inc_pc_i & "00"; + ep_add32 ( prog_cntr_i, incVal_v, '0', next_pc_v, dummy_v); + IF (EX2IF_i.take_branch = '0') THEN + IF2ID_o.program_counter <= next_pc_v; + ELSE + IF2ID_o.program_counter <= EX2IF_i.branch_target; + END IF; + END PROCESS; + +END ARCHITECTURE rtl; diff --git a/hw/mbl_Pkg.vhd b/hw/mbl_Pkg.vhd new file mode 100644 index 0000000..48e1162 --- /dev/null +++ b/hw/mbl_Pkg.vhd @@ -0,0 +1,498 @@ +--------------------------------------------------------------------------------- +-- +-- Package: mbl_Pkg +-- Filename: mbl_Pkg.vhd +-- Description: Package 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: June, 2011: ALU_ACTION_Type extended to incorporate +-- MUL and BS instructions (Huib) +-- Adapted to work with separate fsl_M- +-- and fsl_S selectors and automatic +-- tumbl<_jtag><_fsl>.vhd generation (Huib) +-- July, 2011: function ef_nbits added (Huib) +-- Remarks: +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; +USE IEEE.std_logic_1164.all; +USE IEEE.std_logic_unsigned.all; +USE IEEE.numeric_std.all; + + +-------------------------------------------------------------------------------- +PACKAGE mbl_Pkg IS +-------------------------------------------------------------------------------- + + CONSTANT C_8_ZEROS : STD_LOGIC_VECTOR ( 7 DOWNTO 0) := X"00"; + CONSTANT C_16_ZEROS : STD_LOGIC_VECTOR (15 DOWNTO 0) := X"0000"; + CONSTANT C_24_ZEROS : STD_LOGIC_VECTOR (23 DOWNTO 0) := X"000000"; + CONSTANT C_32_ZEROS : STD_LOGIC_VECTOR (31 DOWNTO 0) := X"00000000"; + + CONSTANT C_16_ONES : STD_LOGIC_VECTOR (15 DOWNTO 0) := X"FFFF"; + CONSTANT C_24_ONES : STD_LOGIC_VECTOR (23 DOWNTO 0) := X"FFFFFF"; + + +---------------------------------------------------------------------------------------------- +-- TYPE DEFINITIONS +---------------------------------------------------------------------------------------------- + + TYPE ALU_ACTION_Type IS (A_NOP, A_ADD, A_CMP, A_CMPU, A_OR, A_AND, A_XOR, + A_SHIFT, A_SEXT8, A_SEXT16, A_MFS, A_MTS, + A_MUL, A_BSLL, A_BSRL, A_BSRA, + A_FSL_GET, A_FSL_PUT); + TYPE ALU_IN1_Type IS (ALU_IN_REGA, ALU_IN_NOT_REGA, ALU_IN_PC, ALU_IN_ZERO); + TYPE ALU_IN2_Type IS (ALU_IN_REGB, ALU_IN_NOT_REGB, ALU_IN_IMM, ALU_IN_NOT_IMM); + TYPE ALU_CIN_Type IS (CIN_ZERO, CIN_ONE, FROM_MSR, FROM_IN1); + TYPE MSR_ACTION_Type IS (UPDATE_CARRY, KEEP_CARRY); + TYPE BRANCH_ACTION_Type IS (NO_BR, BR, BRL, BEQ, BNE, BLT, BLE, BGT, BGE); + TYPE WRB_ACTION_Type IS (NO_WRB, WRB_EX, WRB_MEM, WRB_FSL); + TYPE MEM_ACTION_Type IS (NO_MEM, WR_MEM, RD_MEM); + TYPE TRANSFER_SIZE_Type IS (WORD, HALFWORD, BYTE); + TYPE SAVE_REG_Type IS (NO_SAVE, SAVE_RA, SAVE_RB); + -- + TYPE IF2ID_Type IS RECORD + program_counter : STD_LOGIC_VECTOR (31 DOWNTO 0); + END RECORD; + + TYPE ID2EX_Type IS RECORD + program_counter : STD_LOGIC_VECTOR (31 DOWNTO 0); + rdix_rA : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + rdix_rB : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + curr_rD : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + alu_Action : ALU_ACTION_Type; + alu_Op1 : ALU_IN1_Type; + alu_Op2 : ALU_IN2_Type; + alu_Cin : ALU_CIN_Type; + IMM16 : STD_LOGIC_VECTOR (15 DOWNTO 0); + IMM_Lock : STD_LOGIC; + msr_Action : MSR_ACTION_Type; + branch_Action : BRANCH_ACTION_Type; + mem_Action : MEM_ACTION_Type; -- rd_mem implies writeback + transfer_Size : TRANSFER_SIZE_Type; + wrb_Action : WRB_ACTION_Type; + FSL_Non_blocking : STD_LOGIC; -- ncta + FSL_Control : STD_LOGIC; + FSL_Test : STD_LOGIC; + FSL_Atomic : STD_LOGIC; + END RECORD; + + TYPE ID2GPRF_Type IS RECORD + rdix_rA : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + rdix_rB : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + rdix_rD : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + END RECORD; + + TYPE INT_CTRL_Type IS RECORD + setup_int : STD_LOGIC; + rti_target : STD_LOGIC_VECTOR (31 DOWNTO 0); + int_busy : STD_LOGIC; + END RECORD; + + TYPE ID2CTRL_Type IS RECORD + delayBit : STD_LOGIC; + int_busy : STD_LOGIC; + END RECORD; + + TYPE GPRF2EX_Type IS RECORD + data_rA : STD_LOGIC_VECTOR (31 DOWNTO 0); + data_rB : STD_LOGIC_VECTOR (31 DOWNTO 0); + data_rD : STD_LOGIC_VECTOR (31 DOWNTO 0); + END RECORD; + + TYPE IMM_LOCK_Type IS RECORD + locked : STD_LOGIC; + IMM_hi16 : STD_LOGIC_VECTOR (15 DOWNTO 0); + END RECORD; + + TYPE MSR_Type IS RECORD + IE : STD_LOGIC; -- MSR[VHDL b1] = [MicroBlaze b30] + C : STD_LOGIC; -- MSR[VHDL b2 and b31] = [MicroBlaze b29 and b0] + FSL : STD_LOGIC; -- MSR[VHDL b4] = [MicroBlaze b27] + END RECORD; + + TYPE EX2IF_Type IS RECORD + take_branch : STD_LOGIC; + branch_target : STD_LOGIC_VECTOR (31 DOWNTO 0); + END RECORD; + + TYPE EX2MEM_Type IS RECORD + mem_Action : MEM_ACTION_Type; -- RD_MEM implies writeback + wrb_Action : WRB_ACTION_Type; + exeq_result : STD_LOGIC_VECTOR (31 DOWNTO 0); + data_rD : STD_LOGIC_VECTOR (31 DOWNTO 0); + byte_Enable : STD_LOGIC_VECTOR ( 3 DOWNTO 0); + wrix_rD : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + END RECORD; + + TYPE WRB_Type IS RECORD + wrb_Action : WRB_ACTION_Type; + wrix_rD : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + data_rD : STD_LOGIC_VECTOR (31 DOWNTO 0); + END RECORD; + + TYPE HAZARD_WRB_Type IS RECORD + hazard : STD_LOGIC; + save_rX : SAVE_REG_Type; + data_rX : STD_LOGIC_VECTOR (31 DOWNTO 0); + data_rD : STD_LOGIC_VECTOR (31 DOWNTO 0); + END RECORD; + + TYPE EX2FSL_M_Type IS RECORD + FSLx_M : STD_LOGIC_VECTOR ( 3 DOWNTO 0); + M_Write : STD_LOGIC; + M_Data : STD_LOGIC_VECTOR (31 DOWNTO 0); + M_Control : STD_LOGIC; + END RECORD; + + TYPE FSL_M2EX_Type IS RECORD + M_Full : STD_LOGIC; + END RECORD; + + TYPE EX2FSL_S_Type IS RECORD + FSLx_S : STD_LOGIC_VECTOR ( 3 DOWNTO 0); + S_Read : STD_LOGIC; + END RECORD; + + TYPE FSL_S2EX_Type IS RECORD + S_Control : STD_LOGIC; + S_Exists : STD_LOGIC; + END RECORD; + + TYPE FSL_S2MEM_Type IS RECORD + S_Data : STD_LOGIC_VECTOR (31 DOWNTO 0); + END RECORD; + + TYPE MEM_REG_Type IS RECORD + wrb_Action : WRB_ACTION_Type; + exeq_result : STD_LOGIC_VECTOR (31 DOWNTO 0); + byte_Enable : STD_LOGIC_VECTOR ( 3 DOWNTO 0); + wrix_rD : STD_LOGIC_VECTOR ( 4 DOWNTO 0); + END RECORD; + + TYPE MEM2CTRL_Type IS RECORD + clken : STD_LOGIC; + int : STD_LOGIC; + END RECORD; + + TYPE CORE2DMEMB_Type IS RECORD + ena : STD_LOGIC; + addr : STD_LOGIC_VECTOR (31 DOWNTO 0); + bSel : STD_LOGIC_VECTOR ( 3 DOWNTO 0); + wre : STD_LOGIC; + data : STD_LOGIC_VECTOR (31 DOWNTO 0); + END RECORD; + + TYPE DMEMB2CORE_Type IS RECORD + clken : STD_LOGIC; + data : STD_LOGIC_VECTOR (31 DOWNTO 0); + int : STD_LOGIC; + END RECORD; + + TYPE MEMORY_MAP_Type IS ARRAY(NATURAL RANGE <>) OF STD_LOGIC_VECTOR (31 DOWNTO 0); + -- NOTE: Use the named association format xxxx := ( 0 => X"A0010000" ); + -- in case the array has to contain only one element !! + + TYPE CORE2FSL_M_Type IS RECORD + -- connect M_Clk directly to highest level clock + M_Write : STD_LOGIC; + M_Data : STD_LOGIC_VECTOR (31 DOWNTO 0); + M_Control : STD_LOGIC; + END RECORD; + + TYPE FSL_M2CORE_Type IS RECORD + M_Full : STD_LOGIC; + END RECORD; + + TYPE CORE2FSL_S_Type IS RECORD + -- connect S_Clk directly to highest level clock + S_Read : STD_LOGIC; + END RECORD; + + TYPE FSL_S2CORE_Type IS RECORD + S_Exists : STD_LOGIC; + S_Data : STD_LOGIC_VECTOR (31 DOWNTO 0); + S_Control : STD_LOGIC; + END RECORD; + + TYPE CORE2FSL_M_ARRAY_Type IS ARRAY(NATURAL RANGE <>) OF CORE2FSL_M_Type; + TYPE FSL_M2CORE_ARRAY_Type IS ARRAY(NATURAL RANGE <>) OF FSL_M2CORE_Type; + TYPE CORE2FSL_S_ARRAY_Type IS ARRAY(NATURAL RANGE <>) OF CORE2FSL_S_Type; + TYPE FSL_S2CORE_ARRAY_Type IS ARRAY(NATURAL RANGE <>) OF FSL_S2CORE_Type; + + +---------------------------------------------------------------------------------------------- +-- COMPONENTS +---------------------------------------------------------------------------------------------- + + COMPONENT fetch IS + PORT ( + prog_cntr_i : IN STD_LOGIC_VECTOR (31 DOWNTO 0); + inc_pc_i : IN STD_LOGIC; + EX2IF_i : IN EX2IF_Type; + IF2ID_o : OUT IF2ID_Type + ); + END COMPONENT; + + COMPONENT decode IS + GENERIC ( + USE_HW_MUL_g : BOOLEAN := FALSE; + USE_BARREL_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 COMPONENT; + + COMPONENT adder IS + GENERIC ( + DW_g : POSITIVE := 32; + LW_g : POSITIVE := 15 + ); + PORT ( + in1 : IN STD_LOGIC_VECTOR (DW_g-1 DOWNTO 0); + in2 : IN STD_LOGIC_VECTOR (DW_g-1 DOWNTO 0); + cin : IN STD_LOGIC; + sum : OUT STD_LOGIC_VECTOR (DW_g-1 DOWNTO 0); + cout : OUT STD_LOGIC + ); + END COMPONENT; + + COMPONENT exeq IS + GENERIC ( + USE_HW_MUL_g : BOOLEAN := FALSE; + USE_BARREL_g : BOOLEAN := FALSE + ); + PORT ( + ID2EX_i : IN ID2EX_Type; + GPRF2EX_i : IN GPRF2EX_Type; + EX2IF_o : OUT EX2IF_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; + -- + exq_branch_i : IN STD_LOGIC; + -- + FSL_M2EX_i : IN FSL_M2EX_Type; + EX2FSL_M_o : OUT EX2FSL_M_Type; + -- + FSL_S2EX_i : IN FSL_S2EX_Type; + EX2FSL_S_o : OUT EX2FSL_S_Type; + -- + FSL_nStall_o : OUT STD_LOGIC + ); + END COMPONENT; + + COMPONENT mem IS + PORT ( + EX2MEM_i : IN EX2MEM_Type; + -- + DMEMB_i : IN DMEMB2CORE_Type; + DMEMB_o : OUT CORE2DMEMB_Type; + -- + FSL_S2MEM_i : IN FSL_S2MEM_Type; + -- + MEM_REG_i : IN MEM_REG_Type; + MEM_REG_o : OUT MEM_REG_Type; + -- + MEM_WRB_o : OUT WRB_Type; + MEM2CTRL_o : OUT MEM2CTRL_Type + ); + END COMPONENT; + + COMPONENT core_ctrl IS + PORT ( + clk_i : IN STD_LOGIC; + rst_i : IN STD_LOGIC; + -- halt_i : IN STD_LOGIC; + int_i : IN STD_LOGIC; + -- specific fetch i/o + imem_addr_o : OUT STD_LOGIC_VECTOR (31 DOWNTO 0); + imem_clken_o : OUT STD_LOGIC; + pc_ctrl_o : OUT STD_LOGIC; + -- fetch to decode pipeline registers + IF2ID_REG_i : IN IF2ID_Type; + IF2ID_REG_o : OUT IF2ID_Type; + -- decode to exeq pipeline registers + ID2EX_REG_i : IN ID2EX_Type; + ID2EX_REG_o : OUT ID2EX_Type; + -- GPRF control + gprf_clken_o : OUT STD_LOGIC; + -- exeq to fetch feedback registers + EX2IF_REG_i : IN EX2IF_Type; + EX2IF_REG_o : OUT EX2IF_Type; + -- exeq to mem pipeline registers + EX2MEM_REG_i : IN EX2MEM_Type; + EX2MEM_REG_o : OUT EX2MEM_Type; + -- mem pipeline register + MEM_REG_i : IN MEM_REG_Type; + MEM_REG_o : OUT MEM_REG_Type; + -- decode control i/o + ID2CTRL_i : IN ID2CTRL_Type; + INT_CTRL_o : OUT INT_CTRL_Type; + -- FSL to mem data delay register(s) + FSL_S2MEM_REG_i : IN FSL_S2MEM_Type; + FSL_S2MEM_REG_o : OUT FSL_S2MEM_Type; + -- exeq control i/o + EX_WRB_i : IN WRB_Type; + EX_WRB_o : OUT WRB_Type; + -- data hazard i/o + HAZARD_WRB_i : IN HAZARD_WRB_Type; + HAZARD_WRB_o : OUT HAZARD_WRB_Type; + -- for handling the 'IMM' instruction + IMM_LOCK_i : IN IMM_LOCK_Type; + IMM_LOCK_o : OUT IMM_LOCK_Type; + -- for handling the Machine Status Register + MSR_i : IN MSR_Type; + MSR_o : OUT MSR_Type; + -- miscellaneous + MEM2CTRL_i : IN MEM2CTRL_Type; + FSL_nStall_i : IN STD_LOGIC; + done_o : OUT STD_LOGIC + ); + END COMPONENT; + + COMPONENT fsl_M_selector IS + GENERIC ( + N_FSL_M_g : POSITIVE RANGE 1 TO 16 := 1 -- 1 upto 16 + ); + PORT ( + EX2FSL_M_i : IN EX2FSL_M_Type; + FSL_M2EX_o : OUT FSL_M2EX_Type; + -- + FSL_M_ARRAY_i : IN FSL_M2CORE_ARRAY_Type (0 TO N_FSL_M_g -1); + FSL_M_ARRAY_o : OUT CORE2FSL_M_ARRAY_Type (0 TO N_FSL_M_g -1) + ); + END COMPONENT; + + COMPONENT fsl_S_selector IS + GENERIC ( + N_FSL_S_g : POSITIVE RANGE 1 TO 16 := 1 -- 1 upto 16 + ); + PORT ( + EX2FSL_S_i : IN EX2FSL_S_Type; + FSL_S2EX_o : OUT FSL_S2EX_Type; + FSL_S2MEM_o : OUT FSL_S2MEM_Type; + -- + FSL_S_ARRAY_i : IN FSL_S2CORE_ARRAY_Type (0 TO N_FSL_S_g -1); + FSL_S_ARRAY_o : OUT CORE2FSL_S_ARRAY_Type (0 TO N_FSL_S_g -1) + ); + END COMPONENT; + +---------------------------------------------------------------------------------------------- +-- FUNCTION, PROCEDURE DECLARATIONS +---------------------------------------------------------------------------------------------- + + PROCEDURE ep_add32 ( a, b : IN STD_LOGIC_VECTOR (31 DOWNTO 0); + ci : IN STD_LOGIC; + VARIABLE s : OUT STD_LOGIC_VECTOR (31 DOWNTO 0); + VARIABLE co : OUT STD_LOGIC ); + +-- PROCEDURE ep_add32 ( a, b : IN STD_LOGIC_VECTOR; ci : IN STD_LOGIC; +-- VARIABLE s : OUT STD_LOGIC_VECTOR; +-- VARIABLE co : OUT STD_LOGIC ); + + FUNCTION ef_nbits ( value : NATURAL ) RETURN POSITIVE; + +END PACKAGE mbl_Pkg; + + +---------------------------------------------------------- +PACKAGE BODY mbl_Pkg IS +---------------------------------------------------------- + + PROCEDURE ep_add32 ( a, b : IN STD_LOGIC_VECTOR (31 DOWNTO 0); + ci : IN STD_LOGIC; + VARIABLE s : OUT STD_LOGIC_VECTOR (31 DOWNTO 0); + VARIABLE co : OUT STD_LOGIC ) IS + + CONSTANT NBITS_LO_c : POSITIVE := 17; + CONSTANT NBITS_HI_c : POSITIVE := 32 -NBITS_LO_c; + VARIABLE tmp_lo_v : STD_LOGIC_VECTOR (NBITS_LO_c +1 DOWNTO 0); + VARIABLE tmp_hi0_v : STD_LOGIC_VECTOR (NBITS_HI_c +1 DOWNTO 0); + VARIABLE tmp_hi1_v : STD_LOGIC_VECTOR (NBITS_HI_c +1 DOWNTO 0); + BEGIN + tmp_lo_v := STD_LOGIC_VECTOR( UNSIGNED( '0' & a(NBITS_LO_c -1 DOWNTO 0) & '1' ) + + UNSIGNED( '0' & b(NBITS_LO_c -1 DOWNTO 0) & ci )); + tmp_hi0_v := STD_LOGIC_VECTOR( UNSIGNED( '0' & a(31 DOWNTO (32 - NBITS_HI_c)) & '1') + + UNSIGNED( '0' & b(31 DOWNTO (32 - NBITS_HI_c)) & '0')); + tmp_hi1_v := STD_LOGIC_VECTOR( UNSIGNED( '0' & a(31 DOWNTO (32 - NBITS_HI_c)) & '1') + + UNSIGNED( '0' & b(31 DOWNTO (32 - NBITS_HI_c)) & '1')); + IF (tmp_lo_v(NBITS_LO_c +1) = '0') THEN + s := tmp_hi0_v(NBITS_HI_c DOWNTO 1) & tmp_lo_v(NBITS_LO_c DOWNTO 1); + co := tmp_hi0_v(NBITS_HI_c +1); + ELSE + s := tmp_hi1_v(NBITS_HI_c DOWNTO 1) & tmp_lo_v(NBITS_LO_c DOWNTO 1); + co := tmp_hi1_v(NBITS_HI_c +1); + END IF; + END PROCEDURE; + +-- PROCEDURE ep_add32 ( a, b : IN STD_LOGIC_VECTOR; ci : IN STD_LOGIC; +-- VARIABLE s : OUT STD_LOGIC_VECTOR; +-- VARIABLE co : OUT STD_LOGIC ) IS +-- VARIABLE tmp_lo_v : STD_LOGIC_VECTOR (a'LENGTH/2 +1 DOWNTO 0); +-- VARIABLE tmp_hi0_v : STD_LOGIC_VECTOR (a'LENGTH/2 +1 DOWNTO 0); +-- VARIABLE tmp_hi1_v : STD_LOGIC_VECTOR (a'LENGTH/2 +1 DOWNTO 0); +-- BEGIN +-- tmp_lo_v := STD_LOGIC_VECTOR( UNSIGNED( '0' & a(a'LENGTH/2 -1 DOWNTO 0) & '1' ) + +-- UNSIGNED( '0' & b(a'LENGTH/2 -1 DOWNTO 0) & ci )); +-- tmp_hi0_v := STD_LOGIC_VECTOR( UNSIGNED( '0' & a(a'LENGTH -1 DOWNTO a'LENGTH/2) & '1') + +-- UNSIGNED( '0' & b(a'LENGTH -1 DOWNTO a'LENGTH/2) & '0')); +-- tmp_hi1_v := STD_LOGIC_VECTOR( UNSIGNED( '0' & a(a'LENGTH -1 DOWNTO a'LENGTH/2) & '1') + +-- UNSIGNED( '0' & b(a'LENGTH -1 DOWNTO a'LENGTH/2) & '1')); +-- IF (tmp_lo_v(a'LENGTH/2 +1) = '0') THEN +-- s := tmp_hi0_v(a'LENGTH/2 DOWNTO 1) & tmp_lo_v(a'LENGTH/2 DOWNTO 1); +-- co := tmp_hi0_v(a'LENGTH/2 +1); +-- ELSE +-- s := tmp_hi1_v(a'LENGTH/2 DOWNTO 1) & tmp_lo_v(a'LENGTH/2 DOWNTO 1); +-- co := tmp_hi1_v(a'LENGTH/2 +1); +-- END IF; +-- END PROCEDURE; + +-- Function ef_nbits returns the minimum number of binary bits to represent +-- a value N with: +-- so N = 0,1 NBITS = 1 +-- N = 2,3 NBITS = 2 +-- N = 4,5,6,7 NBITS = 3 +-- N = 8..15 NBITS = 4 +-- N = 16..31 NBITS = 5 +-- etc. + + FUNCTION ef_nbits( value : NATURAL ) RETURN POSITIVE IS + VARIABLE temp_v : POSITIVE; + BEGIN + temp_v := 1; + FOR i IN 1 TO INTEGER'HIGH LOOP + temp_v := 2*temp_v; + IF (temp_v > value) THEN + RETURN i; + END IF; + END LOOP; + RETURN 32; + END FUNCTION; + +END PACKAGE BODY mbl_Pkg; \ No newline at end of file diff --git a/hw/mem.vhd b/hw/mem.vhd new file mode 100644 index 0000000..6ea137e --- /dev/null +++ b/hw/mem.vhd @@ -0,0 +1,141 @@ +--------------------------------------------------------------------------------- +-- +-- Entity: mem +-- Filename: mem.vhd +-- Description: the Memory (MEM) control unit for +-- the TUD MB-Lite implementation +-- +-- Author: Huib Lincklaen Arriens +-- Delft University of Technology +-- Faculty EEMCS, Department ME&CE, Circuits and Systems +-- Date: October, 2010 +-- +-- Modified: December, 2010: handle S_FSL Data Input (Huib) +-- Remarks: +-------------------------------------------------------------------------------- + + +LIBRARY IEEE; +USE IEEE.std_logic_1164.all; +USE work.mbl_Pkg.all; + + +-------------------------------------------------------------------------------- +ENTITY mem IS +-------------------------------------------------------------------------------- + PORT ( + EX2MEM_i : IN EX2MEM_Type; + -- + DMEMB_i : IN DMEMB2CORE_Type; + DMEMB_o : OUT CORE2DMEMB_Type; + -- + FSL_S2MEM_i : IN FSL_S2MEM_Type; + -- + MEM_REG_i : IN MEM_REG_Type; + MEM_REG_o : OUT MEM_REG_Type; + -- + MEM_WRB_o : OUT WRB_Type; + MEM2CTRL_o : OUT MEM2CTRL_Type + ); +END ENTITY mem; + + +-------------------------------------------------------------------------------- +ARCHITECTURE rtl OF mem IS +-------------------------------------------------------------------------------- + +BEGIN + + -- writeback in case of reads from the data memory bus: + -- delay wrb-ctrl signals (see core_ctrl) to stay in sync + -- with synchronous dmem data output + -- Following are only the unconditional pass-through signals. More are in the p_mem process. + MEM_REG_o.wrb_Action <= EX2MEM_i.wrb_Action; + MEM_REG_o.exeq_result <= EX2MEM_i.exeq_result; + MEM_REG_o.byte_Enable <= EX2MEM_i.byte_Enable; + MEM_REG_o.wrix_rD <= EX2MEM_i.wrix_rD; + -- + MEM_WRB_o.wrb_Action <= MEM_REG_i.wrb_Action; + MEM_WRB_o.wrix_rD <= MEM_REG_i.wrix_rD; + -- also signal 'slow memory decices' and interrupts from devices + MEM2CTRL_o.clken <= DMEMB_i.clken; + MEM2CTRL_o.int <= DMEMB_i.int; + -- pass byte_select signal (NOTE: BIG ENDIAN) + DMEMB_o.bSel <= EX2MEM_i.byte_Enable; + +p_mem: + PROCESS (EX2MEM_i, DMEMB_i, MEM_REG_i, FSL_S2MEM_i) + VARIABLE exeq_data_v : STD_LOGIC_VECTOR (31 DOWNTO 0); + VARIABLE dmem_data_v : STD_LOGIC_VECTOR (31 DOWNTO 0); + + BEGIN + + -- always align Big Endian input data from memory(-bus) + CASE MEM_REG_i.byte_Enable IS + WHEN "1000" => dmem_data_v := C_24_ZEROS & DMEMB_i.data(31 DOWNTO 24); + WHEN "0100" => dmem_data_v := C_24_ZEROS & DMEMB_i.data(23 DOWNTO 16); + WHEN "0010" => dmem_data_v := C_24_ZEROS & DMEMB_i.data(15 DOWNTO 8); + WHEN "0001" => dmem_data_v := C_24_ZEROS & DMEMB_i.data( 7 DOWNTO 0); + WHEN "1100" => dmem_data_v := C_16_ZEROS & DMEMB_i.data(31 DOWNTO 16); + WHEN "0011" => dmem_data_v := C_16_ZEROS & DMEMB_i.data(15 DOWNTO 0); + WHEN OTHERS => dmem_data_v := DMEMB_i.data; + END CASE; + + -- output to dmem-bus +-- DMEMB_o.addr <= EX2MEM_i.exeq_result; + CASE EX2MEM_i.mem_Action IS + WHEN WR_MEM => + -- write (or forward) to data memory bus + DMEMB_o.addr <= EX2MEM_i.exeq_result; + DMEMB_o.ena <= '1'; + DMEMB_o.wre <= '1'; + -- Note: use MEM_REG_i here, since MEM_WRB_o (output) cannot be read + IF ((MEM_REG_i.wrb_Action /= NO_WRB) AND + (EX2MEM_i.wrix_rD = MEM_REG_i.wrix_rD)) THEN + CASE MEM_REG_i.wrb_Action IS + WHEN WRB_EX => + -- forward exeq output, to handle e.g. add rD,rA,xx; sw rD,mem[y]; ... + exeq_data_v := MEM_REG_i.exeq_result; + WHEN WRB_FSL => + -- forward FSL_S input, to handle e.g. nget rD,rFSLx; swi rD,mem[x],xx; ... + exeq_data_v := FSL_S2MEM_i.S_Data; + WHEN OTHERS => + -- forward mem_data just read, to handle e.g. lhu rD,mem[x]; sh rD,mem[y]; ... + exeq_data_v := dmem_data_v; + END CASE; + ELSE + exeq_data_v := EX2MEM_i.data_rD; + END IF; + -- output data will be in Big Endian format + CASE EX2MEM_i.byte_Enable IS + WHEN "1000" => DMEMB_o.data <= exeq_data_v( 7 DOWNTO 0) & C_24_ZEROS; + WHEN "0100" => DMEMB_o.data <= C_8_ZEROS & exeq_data_v( 7 DOWNTO 0) & C_16_ZEROS; + WHEN "0010" => DMEMB_o.data <= C_16_ZEROS & exeq_data_v( 7 DOWNTO 0) & C_8_ZEROS; + WHEN "0001" => DMEMB_o.data <= C_24_ZEROS & exeq_data_v( 7 DOWNTO 0); + WHEN "1100" => DMEMB_o.data <= exeq_data_v(15 DOWNTO 0) & C_16_ZEROS; + WHEN "0011" => DMEMB_o.data <= C_16_ZEROS & exeq_data_v(15 DOWNTO 0); + WHEN OTHERS => DMEMB_o.data <= exeq_data_v; + END CASE; + WHEN RD_MEM => + -- read from data memory bus + DMEMB_o.addr <= EX2MEM_i.exeq_result; + DMEMB_o.ena <= '1'; + DMEMB_o.wre <= '0'; + DMEMB_o.data <= EX2MEM_i.data_rD; -- (OTHERS => 'Z'); + WHEN OTHERS => -- NO_MEM + DMEMB_o.addr <= C_32_ZEROS; + DMEMB_o.ena <= '0'; + DMEMB_o.wre <= '0'; + DMEMB_o.data <= EX2MEM_i.data_rD; -- (OTHERS => 'Z'); + END CASE; + + -- additional wrb signals + CASE MEM_REG_i.wrb_Action IS + WHEN WRB_MEM => MEM_WRB_o.data_rD <= dmem_data_v; + WHEN WRB_FSL => MEM_WRB_o.data_rD <= FSL_S2MEM_i.S_Data; + WHEN OTHERS => MEM_WRB_o.data_rD <= MEM_REG_i.exeq_result; + END CASE; + + END PROCESS; + +END ARCHITECTURE rtl; -- 2.39.2