Line 560... |
Line 560... |
next_pc_o <= next_pc_tmp(data_width_c-1 downto 1) & '0';
|
next_pc_o <= next_pc_tmp(data_width_c-1 downto 1) & '0';
|
|
|
|
|
-- CPU Control Bus Output -----------------------------------------------------------------
|
-- CPU Control Bus Output -----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
ctrl_output: process(ctrl, execute_engine, fetch_engine, trap_ctrl, csr, bus_fast_ir)
|
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, csr, bus_fast_ir)
|
begin
|
begin
|
ctrl_o <= ctrl;
|
ctrl_o <= ctrl;
|
-- direct output of register addresses --
|
|
ctrl_o(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c);
|
|
ctrl_o(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c);
|
|
ctrl_o(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= execute_engine.i_reg(instr_rs2_msb_c downto instr_rs2_lsb_c);
|
|
-- fast bus access requests --
|
-- fast bus access requests --
|
ctrl_o(ctrl_bus_if_c) <= ctrl(ctrl_bus_if_c) or bus_fast_ir;
|
ctrl_o(ctrl_bus_if_c) <= ctrl(ctrl_bus_if_c) or bus_fast_ir;
|
-- bus error control --
|
-- bus error control --
|
ctrl_o(ctrl_bus_ierr_ack_c) <= fetch_engine.bus_err_ack;
|
ctrl_o(ctrl_bus_ierr_ack_c) <= fetch_engine.bus_err_ack;
|
ctrl_o(ctrl_bus_derr_ack_c) <= trap_ctrl.env_start_ack;
|
ctrl_o(ctrl_bus_derr_ack_c) <= trap_ctrl.env_start_ack;
|
Line 580... |
Line 576... |
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
execute_engine_fsm_comb: process(execute_engine, fetch_engine, ipb, trap_ctrl, csr, ctrl, csr_acc_valid,
|
execute_engine_fsm_comb: process(execute_engine, fetch_engine, ipb, trap_ctrl, csr, ctrl, csr_acc_valid,
|
alu_add_i, alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i)
|
alu_add_i, alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i)
|
variable alu_immediate_v : std_ulogic;
|
variable alu_immediate_v : std_ulogic;
|
variable alu_operation_v : std_ulogic_vector(2 downto 0);
|
|
variable rs1_is_r0_v : std_ulogic;
|
variable rs1_is_r0_v : std_ulogic;
|
begin
|
begin
|
-- arbiter defaults --
|
-- arbiter defaults --
|
execute_engine.state_nxt <= execute_engine.state;
|
execute_engine.state_nxt <= execute_engine.state;
|
execute_engine.i_reg_nxt <= execute_engine.i_reg;
|
execute_engine.i_reg_nxt <= execute_engine.i_reg;
|
Line 625... |
Line 620... |
ctrl_nxt(ctrl_alu_shift_ar_c) <= execute_engine.i_reg(30); -- is arithmetic shift
|
ctrl_nxt(ctrl_alu_shift_ar_c) <= execute_engine.i_reg(30); -- is arithmetic shift
|
ctrl_nxt(ctrl_bus_size_lsb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- transfer size lsb (00=byte, 01=half-word)
|
ctrl_nxt(ctrl_bus_size_lsb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- transfer size lsb (00=byte, 01=half-word)
|
ctrl_nxt(ctrl_bus_size_msb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- transfer size msb (10=word, 11=?)
|
ctrl_nxt(ctrl_bus_size_msb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- transfer size msb (10=word, 11=?)
|
ctrl_nxt(ctrl_cp_cmd2_c downto ctrl_cp_cmd0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c); -- CP operation
|
ctrl_nxt(ctrl_cp_cmd2_c downto ctrl_cp_cmd0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c); -- CP operation
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- only CP0 (MULDIV) implemented yet
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- only CP0 (MULDIV) implemented yet
|
|
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= ctrl(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c); -- keep rd addr
|
|
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= ctrl(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- keep rs1 addr
|
|
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ctrl(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c); -- keep rs2 addr
|
|
|
-- is immediate operation? --
|
-- is immediate operation? --
|
alu_immediate_v := '0';
|
alu_immediate_v := '0';
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') then
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') then
|
alu_immediate_v := '1';
|
alu_immediate_v := '1';
|
end if;
|
end if;
|
|
|
-- alu operation re-coding --
|
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
|
|
when funct3_subadd_c => -- SUB / ADD(I)
|
|
if (alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1') then -- not immediate and funct7 = SUB
|
|
alu_operation_v := alu_cmd_sub_c;
|
|
else
|
|
alu_operation_v := alu_cmd_add_c;
|
|
end if;
|
|
when funct3_sll_c => alu_operation_v := alu_cmd_shift_c; -- SLL(I)
|
|
when funct3_slt_c => alu_operation_v := alu_cmd_slt_c; -- SLT(I)
|
|
when funct3_sltu_c => alu_operation_v := alu_cmd_slt_c; -- SLTU(I)
|
|
when funct3_xor_c => alu_operation_v := alu_cmd_xor_c; -- XOR(I)
|
|
when funct3_sr_c => alu_operation_v := alu_cmd_shift_c; -- SRL(I) / SRA(I)
|
|
when funct3_or_c => alu_operation_v := alu_cmd_or_c; -- OR(I)
|
|
when funct3_and_c => alu_operation_v := alu_cmd_and_c; -- AND(I)
|
|
when others => alu_operation_v := (others => '0'); -- undefined
|
|
end case;
|
|
|
|
-- is rs1 = r0? --
|
-- is rs1 = r0? --
|
rs1_is_r0_v := '0';
|
rs1_is_r0_v := '0';
|
if (execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then
|
if (execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then
|
rs1_is_r0_v := '1';
|
rs1_is_r0_v := '1';
|
end if;
|
end if;
|
|
|
-- state machine --
|
-- state machine --
|
case execute_engine.state is
|
case execute_engine.state is
|
|
|
when SYS_WAIT => -- Delay cycle (used to wait for side effects to kick in)
|
when SYS_WAIT => -- System delay cycle (used to wait for side effects to kick in) ((and to init r0 with zero if it is a physical register))
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
|
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero?
|
|
-- set reg_file.r0 to zero
|
|
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= (others => '0'); -- rd addr = r0
|
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output (results zero since there is no valid CSR_read request)
|
|
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- allow write access to r0
|
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
|
end if;
|
|
--
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
|
|
when DISPATCH => -- Get new command from instruction prefetch buffer (IPB)
|
when DISPATCH => -- Get new command from instruction prefetch buffer (IPB)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (ipb.avail = '1') then -- instruction available?
|
if (ipb.avail = '1') then -- instruction available?
|
ipb.re <= '1';
|
ipb.re <= '1';
|
|
--
|
trap_ctrl.instr_ma <= ipb.rdata(33); -- misaligned instruction fetch address
|
trap_ctrl.instr_ma <= ipb.rdata(33); -- misaligned instruction fetch address
|
trap_ctrl.instr_be <= ipb.rdata(34); -- bus access fault during instrucion fetch
|
trap_ctrl.instr_be <= ipb.rdata(34); -- bus access fault during instrucion fetch
|
illegal_compressed <= ipb.rdata(35); -- invalid decompressed instruction
|
illegal_compressed <= ipb.rdata(35); -- invalid decompressed instruction
|
|
--
|
|
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= ipb.rdata(instr_rd_msb_c downto instr_rd_lsb_c); -- rd addr
|
|
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= ipb.rdata(instr_rs1_msb_c downto instr_rs1_lsb_c); -- rs1 addr
|
|
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ipb.rdata(instr_rs2_msb_c downto instr_rs2_lsb_c); -- rs2 addr
|
|
--
|
execute_engine.is_ci_nxt <= ipb.rdata(32); -- flag to indicate this is a compressed instruction beeing executed
|
execute_engine.is_ci_nxt <= ipb.rdata(32); -- flag to indicate this is a compressed instruction beeing executed
|
execute_engine.i_reg_nxt <= ipb.rdata(31 downto 0);
|
execute_engine.i_reg_nxt <= ipb.rdata(31 downto 0);
|
execute_engine.if_rst_nxt <= '0';
|
execute_engine.if_rst_nxt <= '0';
|
|
--
|
if (execute_engine.if_rst = '0') then -- if there was no non-linear PC modification
|
if (execute_engine.if_rst = '0') then -- if there was no non-linear PC modification
|
execute_engine.pc_nxt <= execute_engine.next_pc;
|
execute_engine.pc_nxt <= execute_engine.next_pc;
|
end if;
|
end if;
|
--
|
--
|
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or ((ipb.rdata(33) or ipb.rdata(34)) = '1') then
|
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or ((ipb.rdata(33) or ipb.rdata(34)) = '1') then
|
Line 699... |
Line 694... |
|
|
when EXECUTE => -- Decode and execute instruction
|
when EXECUTE => -- Decode and execute instruction
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
case execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) is
|
case execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) is
|
|
|
when opcode_alu_c | opcode_alui_c => -- ALU operation
|
when opcode_alu_c | opcode_alui_c => -- (immediate) ALU operation
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations
|
ctrl_nxt(ctrl_alu_opc_mux_c) <= not alu_immediate_v;
|
ctrl_nxt(ctrl_alu_opc_mux_c) <= not alu_immediate_v;
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_operation_v; -- actual ALU operation
|
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
-- multi cycle alu operation? --
|
|
if (alu_operation_v = alu_cmd_shift_c) or -- shift operation?
|
-- actual ALU operation (re-coding) --
|
((CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
|
(execute_engine.i_reg(instr_funct7_lsb_c) = '1')) then -- MULDIV?
|
when funct3_subadd_c => -- ADD(I) / SUB
|
execute_engine.state_nxt <= ALU_WAIT;
|
if (alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1') then -- not immediate and funct7 => SUB
|
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_sub_c; -- SUB
|
else
|
else
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- ADD(I)
|
execute_engine.state_nxt <= DISPATCH;
|
|
end if;
|
end if;
|
|
when funct3_sll_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SLL(I)
|
|
when funct3_slt_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLT(I)
|
|
when funct3_sltu_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLTU(I)
|
|
when funct3_xor_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_xor_c; -- XOR(I)
|
|
when funct3_sr_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SRL(I) / SRA(I)
|
|
when funct3_or_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- OR(I)
|
|
when funct3_and_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_and_c; -- AND(I)
|
|
when others => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= (others => '0'); -- undefined
|
|
end case;
|
|
|
-- cp access? --
|
-- cp access? --
|
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
|
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
|
(execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
|
(execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
|
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP
|
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP
|
end if;
|
end if;
|
|
|
when opcode_lui_c | opcode_auipc_c => -- load upper immediate (add to PC)
|
-- multi cycle alu operation? --
|
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) or -- SLL shift operation?
|
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) or -- SR shift operation?
|
|
((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and (execute_engine.i_reg(instr_funct7_lsb_c) = '1')) then -- MULDIV?
|
|
execute_engine.state_nxt <= ALU_WAIT;
|
|
else
|
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
|
execute_engine.state_nxt <= DISPATCH;
|
|
end if;
|
|
|
|
when opcode_lui_c | opcode_auipc_c => -- load upper immediate / add upper immediate to PC
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_rf_clear_rs1_c) <= '1'; -- force RS1 = r0 (only relevant for LUI)
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- ALU.OPA = PC (for AUIPC only)
|
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_auipc_c(5)) then -- AUIPC
|
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_lui_c(5)) then -- LUI
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- ALU.OPA = CSR = 0 (hacky: csr.result is 0 since there was no csr_read_request)
|
else -- LUI
|
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA ( = 0)
|
|
end if;
|
end if;
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation = ADD
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
|
|
when opcode_load_c | opcode_store_c => -- load/store
|
when opcode_load_c | opcode_store_c => -- load/store
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation = ADD
|
ctrl_nxt(ctrl_bus_mar_we_c) <= '1'; -- write to MAR
|
ctrl_nxt(ctrl_bus_mar_we_c) <= '1'; -- write to MAR
|
ctrl_nxt(ctrl_bus_mdo_we_c) <= '1'; -- write to MDO (only relevant for stores)
|
ctrl_nxt(ctrl_bus_mdo_we_c) <= '1'; -- write to MDO (only relevant for stores)
|
execute_engine.state_nxt <= LOADSTORE_0;
|
execute_engine.state_nxt <= LOADSTORE_0;
|
|
|
when opcode_branch_c => -- branch instruction
|
when opcode_branch_c => -- branch instruction
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
|
ctrl_nxt(ctrl_alu_opc_mux_c) <= '1'; -- use RS2 as ALU.OPC
|
ctrl_nxt(ctrl_alu_opc_mux_c) <= '1'; -- use RS2 as ALU.OPC
|
execute_engine.state_nxt <= BRANCH;
|
execute_engine.state_nxt <= BRANCH;
|
|
|
when opcode_jal_c | opcode_jalr_c => -- jump and link (with register)
|
when opcode_jal_c | opcode_jalr_c => -- jump and link (with register)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
Line 759... |
Line 771... |
if (execute_engine.i_reg(instr_opcode_lsb_c+3) = opcode_jal_c(3)) then -- JAL
|
if (execute_engine.i_reg(instr_opcode_lsb_c+3) = opcode_jal_c(3)) then -- JAL
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
|
else -- JALR
|
else -- JALR
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
|
end if;
|
end if;
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
|
-- save return address --
|
-- save return address --
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "10"; -- RF input = next PC (save return address)
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "10"; -- RF input = next PC (save return address)
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
--
|
--
|
execute_engine.is_jump_nxt <= '1'; -- this is a jump operation
|
execute_engine.is_jump_nxt <= '1'; -- this is a jump operation
|
Line 783... |
Line 795... |
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
|
|
when opcode_syscsr_c => -- system/csr access
|
when opcode_syscsr_c => -- system/csr access
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
csr.re_nxt <= csr_acc_valid; -- always read CSR if valid access
|
csr.re_nxt <= csr_acc_valid; -- always read CSR if valid access
|
|
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= (others => '0'); -- set rs1_addr to r0 (zero)
|
|
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ctrl(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- copy rs1_addr to rs2_addr (for CSR mod)
|
|
--
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system
|
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
|
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
|
when funct12_ecall_c => -- ECALL
|
when funct12_ecall_c => -- ECALL
|
trap_ctrl.env_call <= '1';
|
trap_ctrl.env_call <= '1';
|
when funct12_ebreak_c => -- EBREAK
|
when funct12_ebreak_c => -- EBREAK
|
Line 794... |
Line 809... |
when funct12_mret_c => -- MRET
|
when funct12_mret_c => -- MRET
|
trap_ctrl.env_end <= '1';
|
trap_ctrl.env_end <= '1';
|
execute_engine.pc_nxt <= csr.mepc;
|
execute_engine.pc_nxt <= csr.mepc;
|
fetch_engine.reset <= '1';
|
fetch_engine.reset <= '1';
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
when funct12_wfi_c => -- WFI = "CPU sleep"
|
when funct12_wfi_c => -- WFI (CPU sleep)
|
execute_engine.sleep_nxt <= '1'; -- good night
|
execute_engine.sleep_nxt <= '1'; -- sleep well
|
when others => -- undefined
|
when others => -- undefined
|
NULL;
|
NULL;
|
end case;
|
end case;
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
else -- CSR access
|
else -- CSR access
|
Line 812... |
Line 827... |
|
|
end case;
|
end case;
|
|
|
when CSR_ACCESS => -- write CSR data to RF, write ALU.res to CSR
|
when CSR_ACCESS => -- write CSR data to RF, write ALU.res to CSR
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '0'; -- default
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- OPB = rs2 (which is rs1 here) / immediate
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- default
|
|
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '0'; -- default
|
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '0'; -- default
|
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- default ALU operation = OR
|
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
|
-- register operations --
|
when funct3_csrrw_c | funct3_csrrwi_c => -- CSRRW(I)
|
when funct3_csrrw_c => -- CSRRW
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "00"; -- OPA = rs1 (which is zero here)
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- OPA = rs1
|
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = rs1
|
|
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1
|
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
|
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
|
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
|
when funct3_csrrs_c => -- CSRRS
|
when funct3_csrrs_c | funct3_csrrsi_c => -- CSRRS(I)
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "10"; -- OPA = CSR
|
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1
|
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
|
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
|
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
|
when funct3_csrrc_c => -- CSRRC
|
when others => -- CSRRC(I)
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "10"; -- OPA = CSR
|
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1
|
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_bclr_c; -- actual ALU operation = bit clear
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_bclr_c; -- actual ALU operation = bit clear
|
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
|
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
|
-- immediate operations --
|
|
when funct3_csrrwi_c => -- CSRRWI
|
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- OPA = rs1
|
|
ctrl_nxt(ctrl_rf_clear_rs1_c) <= '1'; -- rs1 = 0
|
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
|
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
|
|
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
|
|
when funct3_csrrsi_c => -- CSRRSI
|
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
|
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
|
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
|
|
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if UIMM5 is not zero (bits from rs1 filed) and if valid access
|
|
when funct3_csrrci_c => -- CSRRCI
|
|
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
|
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
|
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_bclr_c; -- actual ALU operation = bit clear
|
|
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if UIMM5 is not zero (bits from rs1 filed) and if valid access
|
|
when others => -- undefined
|
|
NULL;
|
|
end case;
|
end case;
|
-- RF write back --
|
-- RF write back --
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
execute_engine.state_nxt <= DISPATCH; -- FIXME should be SYS_WAIT? have another cycle to let side-effects kick in
|
execute_engine.state_nxt <= DISPATCH; -- FIXME? should be SYS_WAIT? have another cycle to let side-effects kick in
|
|
|
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish
|
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c;
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c;
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
Line 927... |
Line 914... |
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
|
|
-- Illegal CSR Access Check ---------------------------------------------------------------
|
-- Illegal CSR Access Check ---------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
invalid_csr_access_check: process(execute_engine, csr)
|
invalid_csr_access_check: process(execute_engine, csr.privilege)
|
variable is_m_mode_v : std_ulogic;
|
variable is_m_mode_v : std_ulogic;
|
begin
|
begin
|
-- are we in machine mode? --
|
-- are we in machine mode? --
|
is_m_mode_v := '0';
|
is_m_mode_v := '0';
|
if (csr.privilege = m_priv_mode_c) then
|
if (csr.privilege = m_priv_mode_c) then
|