Line 2... |
Line 2... |
-- # << NEORV32 - CPU Control >> #
|
-- # << NEORV32 - CPU Control >> #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # CPU operation is split into a fetch engine (responsible for fetching instruction data), an #
|
-- # CPU operation is split into a fetch engine (responsible for fetching instruction data), an #
|
-- # issue engine (for recoding compressed instructions and for constructing 32-bit instruction #
|
-- # issue engine (for recoding compressed instructions and for constructing 32-bit instruction #
|
-- # words) and an execute engine (responsible for actually executing the instructions), a trap #
|
-- # words) and an execute engine (responsible for actually executing the instructions), a trap #
|
-- # handling controller and the RISC-V status and control register set (CSRs). #
|
-- # handling controller and the RISC-V status and control register set (CSRs) including the #
|
|
-- # hardware performance monitor counters. #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # BSD 3-Clause License #
|
-- # BSD 3-Clause License #
|
-- # #
|
-- # #
|
-- # Copyright (c) 2021, Stephan Nolting. All rights reserved. #
|
-- # Copyright (c) 2021, Stephan Nolting. All rights reserved. #
|
-- # #
|
-- # #
|
Line 49... |
Line 50... |
-- General --
|
-- General --
|
HW_THREAD_ID : std_ulogic_vector(31 downto 0):= x"00000000"; -- hardware thread id
|
HW_THREAD_ID : std_ulogic_vector(31 downto 0):= x"00000000"; -- hardware thread id
|
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0):= x"00000000"; -- cpu boot address
|
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0):= x"00000000"; -- cpu boot address
|
-- RISC-V CPU Extensions --
|
-- RISC-V CPU Extensions --
|
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
|
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
|
|
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit manipulation extensions?
|
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
|
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
|
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
|
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
|
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
Line 163... |
Line 165... |
data : std_ulogic_vector(35 downto 0); -- 4-bit status + 32-bit instruction
|
data : std_ulogic_vector(35 downto 0); -- 4-bit status + 32-bit instruction
|
valid : std_ulogic; -- data word is valid when set
|
valid : std_ulogic; -- data word is valid when set
|
end record;
|
end record;
|
signal cmd_issue : cmd_issue_t;
|
signal cmd_issue : cmd_issue_t;
|
|
|
|
-- instruction decoding helper logic --
|
|
type decode_aux_t is record
|
|
alu_immediate : std_ulogic;
|
|
rs1_is_r0 : std_ulogic;
|
|
is_atomic_lr : std_ulogic;
|
|
is_atomic_sc : std_ulogic;
|
|
is_bitmanip_imm : std_ulogic;
|
|
is_bitmanip_reg : std_ulogic;
|
|
end record;
|
|
signal decode_aux : decode_aux_t;
|
|
|
-- instruction execution engine --
|
-- instruction execution engine --
|
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP, EXECUTE, ALU_WAIT, BRANCH, FENCE_OP, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, SYS_ENV, CSR_ACCESS);
|
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP, EXECUTE, ALU_WAIT, BRANCH, FENCE_OP, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, SYS_ENV, CSR_ACCESS);
|
type execute_engine_t is record
|
type execute_engine_t is record
|
state : execute_engine_state_t;
|
state : execute_engine_state_t;
|
state_nxt : execute_engine_state_t;
|
state_nxt : execute_engine_state_t;
|
Line 719... |
Line 732... |
ctrl_o(ctrl_bus_if_c) <= bus_fast_ir;
|
ctrl_o(ctrl_bus_if_c) <= 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;
|
-- instruction's function blocks (for co-processors) --
|
-- instruction's function blocks (for co-processors) --
|
|
ctrl_o(ctrl_ir_opcode7_6_c downto ctrl_ir_opcode7_0_c) <= execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c);
|
ctrl_o(ctrl_ir_funct12_11_c downto ctrl_ir_funct12_0_c) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c);
|
ctrl_o(ctrl_ir_funct12_11_c downto ctrl_ir_funct12_0_c) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c);
|
ctrl_o(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c);
|
ctrl_o(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c);
|
-- locked bus operation (for atomica memory operations) --
|
-- locked bus operation (for atomica memory operations) --
|
ctrl_o(ctrl_bus_lock_c) <= atomic_ctrl.lock; -- (bus) lock status
|
ctrl_o(ctrl_bus_lock_c) <= atomic_ctrl.lock; -- (bus) lock status
|
end process ctrl_output;
|
end process ctrl_output;
|
|
|
|
|
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
decode_helper: process(execute_engine)
|
|
begin
|
|
-- defaults --
|
|
decode_aux.alu_immediate <= '0';
|
|
decode_aux.rs1_is_r0 <= '0';
|
|
decode_aux.is_atomic_lr <= '0';
|
|
decode_aux.is_atomic_sc <= '0';
|
|
decode_aux.is_bitmanip_imm <= '0';
|
|
decode_aux.is_bitmanip_reg <= '0';
|
|
|
|
-- is immediate ALU operation? --
|
|
decode_aux.alu_immediate <= not execute_engine.i_reg(instr_opcode_msb_c-1);
|
|
|
|
-- is rs1 == r0? --
|
|
decode_aux.rs1_is_r0 <= not or_all_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c));
|
|
|
|
-- is atomic load-reservate/store-conditional? --
|
|
if (CPU_EXTENSION_RISCV_A = true) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') then -- valid atomic sub-opcode
|
|
decode_aux.is_atomic_lr <= not execute_engine.i_reg(instr_funct5_lsb_c);
|
|
decode_aux.is_atomic_sc <= execute_engine.i_reg(instr_funct5_lsb_c);
|
|
end if;
|
|
|
|
-- is BITMANIP.Zbb instruction? --
|
|
-- pretty complex as we have to extract this from the ALU/ALUI instruction space --
|
|
-- immediate operation --
|
|
if ((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0110000") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "001") and
|
|
(
|
|
(execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c) = "00000") or -- CLZ
|
|
(execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c) = "00001") or -- CTZ
|
|
(execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c) = "00010") or -- PCNT
|
|
(execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c) = "00100") or -- SEXT.B
|
|
(execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c) = "00101") -- SEXT.H
|
|
)
|
|
) or
|
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "01100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101")) or -- RORI
|
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "00101") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_imm12_lsb_c+6 downto instr_imm12_lsb_c) = "0000111")) or -- GORCI.b 7 (orc.b)
|
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "01101") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_imm12_lsb_c+6 downto instr_imm12_lsb_c) = "0011000")) then -- GREVI.-8 (rev8)
|
|
decode_aux.is_bitmanip_imm <= '1';
|
|
end if;
|
|
-- register operation --
|
|
if ((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0110000") and (execute_engine.i_reg(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) = "01")) or -- ROR / ROL
|
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000101") and (execute_engine.i_reg(instr_funct3_msb_c) = '1')) or -- MIN[U] / MAX[U]
|
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "100")) or -- PACK
|
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0100000") and
|
|
(
|
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "111") or -- ANDN
|
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "110") or -- ORN
|
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "100") -- XORN
|
|
)
|
|
) then
|
|
decode_aux.is_bitmanip_reg <= '1';
|
|
end if;
|
|
end process decode_helper;
|
|
|
|
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
execute_engine_fsm_comb: process(execute_engine, fetch_engine, cmd_issue, trap_ctrl, csr, ctrl, csr_acc_valid,
|
execute_engine_fsm_comb: process(execute_engine, decode_aux, fetch_engine, cmd_issue, trap_ctrl, csr, ctrl, csr_acc_valid,
|
alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_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 rs1_is_r0_v : std_ulogic;
|
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
variable is_atomic_lr_v : std_ulogic;
|
|
variable is_atomic_sc_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;
|
execute_engine.is_cp_op_nxt <= execute_engine.is_cp_op;
|
execute_engine.is_cp_op_nxt <= execute_engine.is_cp_op;
|
Line 788... |
Line 855... |
-- ALU main control --
|
-- ALU main control --
|
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
|
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- default ALU function select: arithmetic
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- default ALU function select: arithmetic
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c; -- default ALU arithmetic operation: ADDSUB
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c; -- default ALU arithmetic operation: ADDSUB
|
|
|
-- is immediate ALU operation? --
|
|
alu_immediate_v := not execute_engine.i_reg(instr_opcode_msb_c-1);
|
|
|
|
-- is rs1 == r0? --
|
|
rs1_is_r0_v := not or_all_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c));
|
|
|
|
-- is atomic load-reservate/store-conditional? --
|
|
if (CPU_EXTENSION_RISCV_A = true) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') then -- valid atomic sub-opcode
|
|
is_atomic_lr_v := not execute_engine.i_reg(instr_funct5_lsb_c);
|
|
is_atomic_sc_v := execute_engine.i_reg(instr_funct5_lsb_c);
|
|
else
|
|
is_atomic_lr_v := '0';
|
|
is_atomic_sc_v := '0';
|
|
end if;
|
|
|
|
|
|
-- state machine --
|
-- state machine --
|
case execute_engine.state is
|
case execute_engine.state is
|
|
|
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))
|
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]
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
-- set reg_file's r0 to zero --
|
-- set reg_file's r0 to zero --
|
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero?
|
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero?
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output (hacky! results zero since there is no valid CSR_read)
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output (hacky! results zero since there is no valid CSR-read)
|
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- force RF write access and force rd=r0
|
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- force RF write access and force rd=r0
|
end if;
|
end if;
|
--
|
--
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
|
|
Line 863... |
Line 915... |
case opcode_v is
|
case opcode_v is
|
|
|
when opcode_alu_c | opcode_alui_c => -- (immediate) ALU operation
|
when opcode_alu_c | opcode_alui_c => -- (immediate) ALU operation
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= decode_aux.alu_immediate; -- use IMM as ALU.OPB for immediate operations
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
|
|
|
-- ALU arithmetic operation type and ADD/SUB --
|
-- ALU arithmetic operation type and ADD/SUB --
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then
|
Line 875... |
Line 927... |
else
|
else
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c;
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c;
|
end if;
|
end if;
|
|
|
-- ADD/SUB --
|
-- ADD/SUB --
|
if ((alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1')) or -- not an immediate op and funct7.6 set => SUB
|
if ((decode_aux.alu_immediate = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1')) or -- not an immediate op and funct7.6 set => SUB
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or -- SLT operation
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or -- SLT operation
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then -- SLTU operation
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then -- SLTU operation
|
ctrl_nxt(ctrl_alu_addsub_c) <= '1'; -- SUB/SLT
|
ctrl_nxt(ctrl_alu_addsub_c) <= '1'; -- SUB/SLT
|
else
|
else
|
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
|
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
|
Line 890... |
Line 942... |
when funct3_xor_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_xor_c; -- XOR(I)
|
when funct3_xor_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_xor_c; -- XOR(I)
|
when funct3_or_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_or_c; -- OR(I)
|
when funct3_or_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_or_c; -- OR(I)
|
when others => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_and_c; -- AND(I)
|
when others => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_and_c; -- AND(I)
|
end case;
|
end case;
|
|
|
-- co-processor (cp) access? --
|
-- co-processor MULDIV operation? --
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- just in case a mul/div operation
|
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_msb_c downto instr_funct7_lsb_c) = "0000001") then -- MULDIV CP op?
|
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 CP op?
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- use MULDIV CP
|
execute_engine.is_cp_op_nxt <= '1'; -- this is a CP operation
|
execute_engine.is_cp_op_nxt <= '1'; -- this is a CP operation
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
-- ALU operation - function select --
|
-- co-processor bit manipulation operation? --
|
|
elsif (CPU_EXTENSION_RISCV_B = true) and
|
|
(((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and (decode_aux.is_bitmanip_reg = '1')) or -- register operation
|
|
((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alui_c(5)) and (decode_aux.is_bitmanip_imm = '1'))) then -- immediate operation
|
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_bitmanip_c; -- use BITMANIP CP
|
|
execute_engine.is_cp_op_nxt <= '1'; -- this is a CP operation
|
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
|
-- ALU operation, function select --
|
else
|
else
|
execute_engine.is_cp_op_nxt <= '0'; -- no CP operation
|
execute_engine.is_cp_op_nxt <= '0'; -- no CP operation
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is -- actual ALU.func operation (re-coding)
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is -- actual ALU.func operation (re-coding)
|
when funct3_xor_c | funct3_or_c | funct3_and_c => ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c;
|
when funct3_xor_c | funct3_or_c | funct3_and_c => ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c;
|
when funct3_sll_c | funct3_sr_c => ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_shift_c;
|
when funct3_sll_c | funct3_sr_c => ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_shift_c;
|
Line 908... |
Line 967... |
end if;
|
end if;
|
|
|
-- multi cycle alu operation? --
|
-- 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?
|
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_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) or -- SR shift operation?
|
((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 CP op?
|
((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')) or -- MULDIV CP op?
|
|
((CPU_EXTENSION_RISCV_B = true) and (
|
|
((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and (decode_aux.is_bitmanip_reg = '1')) or -- BITMANIP CP register operation?
|
|
((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alui_c(5)) and (decode_aux.is_bitmanip_imm = '1'))) ) then -- BITMANIP CP immediate operation?
|
execute_engine.state_nxt <= ALU_WAIT;
|
execute_engine.state_nxt <= ALU_WAIT;
|
else -- single cycle ALU operation
|
else -- single cycle ALU operation
|
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;
|
end if;
|
end if;
|
Line 1010... |
Line 1072... |
-- CSR write access --
|
-- CSR write access --
|
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
|
when funct3_csrrw_c | funct3_csrrwi_c => -- CSRRW(I)
|
when funct3_csrrw_c | funct3_csrrwi_c => -- CSRRW(I)
|
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 | funct3_csrrsi_c | funct3_csrrc_c | funct3_csrrci_c => -- CSRRS(I) / CSRRC(I)
|
when funct3_csrrs_c | funct3_csrrsi_c | funct3_csrrc_c | funct3_csrrci_c => -- CSRRS(I) / CSRRC(I)
|
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1/imm is not zero and if valid access
|
csr.we_nxt <= (not decode_aux.rs1_is_r0) and csr_acc_valid; -- write CSR if rs1/imm is not zero and if valid access
|
when others => -- invalid
|
when others => -- invalid
|
csr.we_nxt <= '0';
|
csr.we_nxt <= '0';
|
end case;
|
end case;
|
-- register file write back --
|
-- register file 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
|
Line 1024... |
Line 1086... |
|
|
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_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back (permanent write-back)
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back (permanent write-back)
|
-- cp access or alu shift? --
|
-- cp access or alu.shift? --
|
if (execute_engine.is_cp_op = '1') then
|
if (execute_engine.is_cp_op = '1') then
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
else
|
else
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_shift_c;
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_shift_c;
|
end if;
|
end if;
|
Line 1075... |
Line 1137... |
end if;
|
end if;
|
|
|
|
|
when LOADSTORE_0 => -- trigger memory request
|
when LOADSTORE_0 => -- trigger memory request
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or (is_atomic_lr_v = '1') then -- normal load or atomic load-reservate
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or (decode_aux.is_atomic_lr = '1') then -- normal load or atomic load-reservate
|
ctrl_nxt(ctrl_bus_rd_c) <= '1'; -- read request
|
ctrl_nxt(ctrl_bus_rd_c) <= '1'; -- read request
|
else -- store
|
else -- store
|
ctrl_nxt(ctrl_bus_wr_c) <= '1'; -- write request
|
ctrl_nxt(ctrl_bus_wr_c) <= '1'; -- write request
|
end if;
|
end if;
|
execute_engine.state_nxt <= LOADSTORE_1;
|
execute_engine.state_nxt <= LOADSTORE_1;
|
Line 1098... |
Line 1160... |
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_atomic_c; -- atomic.SC: result comes from "atomic co-processor"
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_atomic_c; -- atomic.SC: result comes from "atomic co-processor"
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
end if;
|
end if;
|
-- register file write-back --
|
-- register file write-back --
|
ctrl_nxt(ctrl_rf_in_mux_lsb_c) <= '0'; -- RF input = ALU.res or MEM
|
ctrl_nxt(ctrl_rf_in_mux_lsb_c) <= '0'; -- RF input = ALU.res or MEM
|
if (is_atomic_sc_v = '1') then
|
if (decode_aux.is_atomic_sc = '1') then
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU.res (only relevant for atomic.SC)
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU.res (only relevant for atomic.SC)
|
else
|
else
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
|
end if;
|
end if;
|
--
|
--
|
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for load operations)
|
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for load operations)
|
-- wait for memory response --
|
-- wait for memory response --
|
if ((ma_load_i or be_load_i or ma_store_i or be_store_i) = '1') then -- abort if exception
|
if ((ma_load_i or be_load_i or ma_store_i or be_store_i) = '1') then -- abort if exception
|
atomic_ctrl.env_abort <= '1'; -- LOCKED (atomic) memory access environment failed (forces SC result to be non-zero => failure)
|
atomic_ctrl.env_abort <= '1'; -- LOCKED (atomic) memory access environment failed (forces SC result to be non-zero => failure)
|
ctrl_nxt(ctrl_rf_wb_en_c) <= is_atomic_sc_v; -- SC failes: allow write back of non-zero result
|
ctrl_nxt(ctrl_rf_wb_en_c) <= decode_aux.is_atomic_sc; -- SC failes: allow write back of non-zero result
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction
|
elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or (is_atomic_lr_v = '1') or (is_atomic_sc_v = '1') then -- load / load-reservate / store conditional
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or (decode_aux.is_atomic_lr = '1') or (decode_aux.is_atomic_sc = '1') then -- load / load-reservate / store conditional
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
end if;
|
end if;
|
atomic_ctrl.env_end <= '1'; -- normal end of LOCKED (atomic) memory access environment
|
atomic_ctrl.env_end <= '1'; -- normal end of LOCKED (atomic) memory access environment
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
end if;
|
end if;
|
Line 1136... |
Line 1198... |
|
|
-- Illegal CSR Access Check ---------------------------------------------------------------
|
-- Illegal CSR Access Check ---------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
invalid_csr_access_check: process(execute_engine.i_reg, csr)
|
invalid_csr_access_check: process(execute_engine.i_reg, csr)
|
variable csr_wacc_v : std_ulogic; -- to check access to read-only CSRs
|
variable csr_wacc_v : std_ulogic; -- to check access to read-only CSRs
|
variable csr_mcounteren_hpm_v : std_ulogic_vector(28 downto 0); -- max 29 HPM counters
|
|
-- variable csr_racc_v : std_ulogic; -- to check access to write-only CSRs
|
-- variable csr_racc_v : std_ulogic; -- to check access to write-only CSRs
|
|
variable csr_mcounteren_hpm_v : std_ulogic_vector(28 downto 0); -- max 29 HPM counters
|
begin
|
begin
|
-- is this CSR instruction really going to write/read to/from a CSR? --
|
-- is this CSR instruction really going to write/read to/from a CSR? --
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrw_c) or
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrw_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) then
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) then
|
csr_wacc_v := '1'; -- always write CSR
|
csr_wacc_v := '1'; -- always write CSR
|
Line 1216... |
Line 1278... |
-- standard read-only CSRs --
|
-- standard read-only CSRs --
|
when csr_cycle_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_cy); -- M-mode, U-mode if authorized, read-only
|
when csr_cycle_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_cy); -- M-mode, U-mode if authorized, read-only
|
when csr_time_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_tm); -- M-mode, U-mode if authorized, read-only
|
when csr_time_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_tm); -- M-mode, U-mode if authorized, read-only
|
when csr_instret_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_ir); -- M-mode, U-mode if authorized, read-only
|
when csr_instret_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_ir); -- M-mode, U-mode if authorized, read-only
|
--
|
--
|
when csr_hpmcounter3_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(0)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter3_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(00)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter4_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(1)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter4_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(01)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter5_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(2)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter5_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(02)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter6_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(3)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter6_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(03)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter7_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(4)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter7_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(04)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter8_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(5)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter8_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(05)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter9_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(6)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter9_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(06)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter10_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(7)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter10_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(07)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter11_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(8)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter11_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(08)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter12_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(9)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter12_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(09)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter13_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(10)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter13_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(10)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter14_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(11)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter14_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(11)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter15_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(12)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter15_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(12)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter16_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(13)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter16_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(13)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter17_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(14)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter17_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(14)); -- M-mode, U-mode if authorized, read-only
|
Line 1250... |
Line 1312... |
--
|
--
|
when csr_cycleh_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_cy); -- M-mode, U-mode if authorized, read-only
|
when csr_cycleh_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_cy); -- M-mode, U-mode if authorized, read-only
|
when csr_timeh_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_tm); -- M-mode, U-mode if authorized, read-only
|
when csr_timeh_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_tm); -- M-mode, U-mode if authorized, read-only
|
when csr_instreth_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_ir); -- M-mode, U-mode if authorized, read-only
|
when csr_instreth_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_ir); -- M-mode, U-mode if authorized, read-only
|
--
|
--
|
when csr_hpmcounter3h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(0)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter3h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(00)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter4h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(1)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter4h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(01)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter5h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(2)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter5h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(02)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter6h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(3)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter6h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(03)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter7h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(4)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter7h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(04)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter8h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(5)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter8h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(05)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter9h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(6)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter9h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(06)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter10h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(7)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter10h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(07)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter11h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(8)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter11h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(08)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter12h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(9)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter12h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(09)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter13h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(10)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter13h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(10)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter14h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(11)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter14h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(11)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter15h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(12)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter15h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(12)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter16h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(13)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter16h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(13)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter17h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(14)); -- M-mode, U-mode if authorized, read-only
|
when csr_hpmcounter17h_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr_mcounteren_hpm_v(14)); -- M-mode, U-mode if authorized, read-only
|
Line 1294... |
Line 1356... |
end process invalid_csr_access_check;
|
end process invalid_csr_access_check;
|
|
|
|
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
illegal_instruction_check: process(execute_engine, csr_acc_valid)
|
illegal_instruction_check: process(execute_engine, decode_aux, csr_acc_valid)
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
begin
|
begin
|
-- illegal instructions are checked in the EXECUTE stage
|
-- illegal instructions are checked in the EXECUTE stage
|
-- the execute engine should not commit any illegal instruction
|
-- the execute engine should not commit any illegal instruction
|
if (execute_engine.state = EXECUTE) then
|
if (execute_engine.state = EXECUTE) then
|
Line 1315... |
Line 1377... |
|
|
-- check instructions --
|
-- check instructions --
|
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
|
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
|
case opcode_v is
|
case opcode_v is
|
|
|
-- OPCODE check sufficient: LUI, UIPC, JAL --
|
-- check sufficient LUI, UIPC, JAL (only check actual OPCODE) --
|
when opcode_lui_c | opcode_auipc_c | opcode_jal_c =>
|
when opcode_lui_c | opcode_auipc_c | opcode_jal_c =>
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
-- illegal E-CPU register? --
|
-- illegal E-CPU register? --
|
if (CPU_EXTENSION_RISCV_E = true) and (execute_engine.i_reg(instr_rd_msb_c) = '1') then
|
if (CPU_EXTENSION_RISCV_E = true) and (execute_engine.i_reg(instr_rd_msb_c) = '1') then
|
illegal_register <= '1';
|
illegal_register <= '1';
|
end if;
|
end if;
|
|
|
when opcode_alui_c => -- check ALUI funct7
|
when opcode_alu_c => -- check ALU.funct3 & ALU.funct7
|
if ((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) and
|
if (execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000001") then -- MULDIV
|
|
if (CPU_EXTENSION_RISCV_M = false) then -- not implemented
|
|
illegal_instruction <= '1';
|
|
end if;
|
|
elsif (decode_aux.is_bitmanip_reg = '1') then -- bit manipulation
|
|
if (CPU_EXTENSION_RISCV_B = false) then -- not implemented
|
|
illegal_instruction <= '1';
|
|
end if;
|
|
elsif ((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_subadd_c) or
|
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c)) and -- ADD/SUB or SRA/SRL check
|
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000") and
|
|
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0100000")) then -- ADD/SUB or SRA/SRL select
|
|
illegal_instruction <= '1';
|
|
else
|
|
illegal_instruction <= '0';
|
|
end if;
|
|
-- illegal E-CPU register? --
|
|
if (CPU_EXTENSION_RISCV_E = true) and
|
|
((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
|
|
illegal_register <= '1';
|
|
end if;
|
|
|
|
when opcode_alui_c => -- check ALUI.funct7
|
|
if (decode_aux.is_bitmanip_imm = '1') then -- bit manipulation
|
|
if (CPU_EXTENSION_RISCV_B = false) then -- not implemented
|
|
illegal_instruction <= '1';
|
|
end if;
|
|
elsif ((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) and
|
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000")) or -- shift logical left
|
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000")) or -- shift logical left
|
((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) and
|
((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) and
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000") and
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000") and
|
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0100000"))) then -- shift right
|
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0100000"))) then -- shift right
|
illegal_instruction <= '1';
|
illegal_instruction <= '1';
|
Line 1338... |
Line 1427... |
-- illegal E-CPU register? --
|
-- illegal E-CPU register? --
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
|
illegal_register <= '1';
|
illegal_register <= '1';
|
end if;
|
end if;
|
|
|
when opcode_load_c => -- check LOAD funct3
|
when opcode_load_c => -- check LOAD.funct3
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lb_c) or
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lb_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lh_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lh_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lw_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lw_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lbu_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lbu_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lhu_c) then
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_lhu_c) then
|
Line 1353... |
Line 1442... |
-- illegal E-CPU register? --
|
-- illegal E-CPU register? --
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
|
illegal_register <= '1';
|
illegal_register <= '1';
|
end if;
|
end if;
|
|
|
when opcode_store_c => -- check STORE funct3
|
when opcode_store_c => -- check STORE.funct3
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sb_c) or
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sb_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sh_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sh_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sw_c) then
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sw_c) then
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
else
|
else
|
Line 1366... |
Line 1455... |
-- illegal E-CPU register? --
|
-- illegal E-CPU register? --
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1')) then
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1')) then
|
illegal_register <= '1';
|
illegal_register <= '1';
|
end if;
|
end if;
|
|
|
when opcode_branch_c => -- check BRANCH funct3
|
when opcode_branch_c => -- check BRANCH.funct3
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_beq_c) or
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_beq_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_bne_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_bne_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_blt_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_blt_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_bge_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_bge_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_bltu_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_bltu_c) or
|
Line 1382... |
Line 1471... |
-- illegal E-CPU register? --
|
-- illegal E-CPU register? --
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1')) then
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1')) then
|
illegal_register <= '1';
|
illegal_register <= '1';
|
end if;
|
end if;
|
|
|
when opcode_jalr_c => -- check JALR funct3
|
when opcode_jalr_c => -- check JALR.funct3
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "000") then
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "000") then
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
else
|
else
|
illegal_instruction <= '1';
|
illegal_instruction <= '1';
|
end if;
|
end if;
|
-- illegal E-CPU register? --
|
-- illegal E-CPU register? --
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
|
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
|
illegal_register <= '1';
|
illegal_register <= '1';
|
end if;
|
end if;
|
|
|
when opcode_alu_c => -- check ALU funct3 & funct7
|
|
if (execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000001") then -- MULDIV
|
|
if (CPU_EXTENSION_RISCV_M = false) then -- not implemented
|
|
illegal_instruction <= '1';
|
|
end if;
|
|
elsif ((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_subadd_c) or
|
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c)) and -- ADD/SUB or SRA/SRL check
|
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000") and
|
|
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0100000")) then -- ADD/SUB or SRA/SRL select
|
|
illegal_instruction <= '1';
|
|
else
|
|
illegal_instruction <= '0';
|
|
end if;
|
|
-- illegal E-CPU register? --
|
|
if (CPU_EXTENSION_RISCV_E = true) and
|
|
((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
|
|
illegal_register <= '1';
|
|
end if;
|
|
|
|
when opcode_fence_c => -- fence instructions --
|
when opcode_fence_c => -- fence instructions --
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true) then -- FENCE.I
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true) then -- FENCE.I
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
elsif (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then -- FENCE
|
elsif (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then -- FENCE
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
Line 2048... |
Line 2118... |
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
cnt_event <= cnt_event_nxt;
|
cnt_event <= cnt_event_nxt;
|
hpmcnt_trigger <= (others => '0'); -- default
|
hpmcnt_trigger <= (others => '0'); -- default
|
for i in 0 to HPM_NUM_CNTS-1 loop
|
for i in 0 to HPM_NUM_CNTS-1 loop
|
-- enabled selected triggers by ANDing events and configuration bits --
|
-- enable selected triggers by ANDing events and configuration bits --
|
-- OR everything to see if counter should increment --
|
-- OR everything to see if counter should increment --
|
-- AND with inverted sleep flag to increment only when CPU is awake --
|
-- AND with inverted sleep flag to increment only when CPU is awake --
|
hpmcnt_trigger(i) <= (or_all_f(cnt_event and csr.mhpmevent(i)(cnt_event'left downto 0))) and (not execute_engine.sleep);
|
hpmcnt_trigger(i) <= (or_all_f(cnt_event and csr.mhpmevent(i)(cnt_event'left downto 0))) and (not execute_engine.sleep);
|
end loop; -- i
|
end loop; -- i
|
end if;
|
end if;
|
Line 2099... |
Line 2169... |
csr.rdata(12) <= csr.mstatus_mpp(1); -- MPP: machine previous privilege mode high
|
csr.rdata(12) <= csr.mstatus_mpp(1); -- MPP: machine previous privilege mode high
|
when csr_mstatush_c => -- R/-: mstatush - machine status register - high part
|
when csr_mstatush_c => -- R/-: mstatush - machine status register - high part
|
csr.rdata(05) <= '1'; -- MBE: CPU/Processor is BIG-ENDIAN (in machine-mode)
|
csr.rdata(05) <= '1'; -- MBE: CPU/Processor is BIG-ENDIAN (in machine-mode)
|
when csr_misa_c => -- R/-: misa - ISA and extensions
|
when csr_misa_c => -- R/-: misa - ISA and extensions
|
csr.rdata(00) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_A); -- A CPU extension
|
csr.rdata(00) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_A); -- A CPU extension
|
|
csr.rdata(01) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- B CPU extension
|
csr.rdata(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_C); -- C CPU extension
|
csr.rdata(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_C); -- C CPU extension
|
csr.rdata(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- E CPU extension
|
csr.rdata(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- E CPU extension
|
csr.rdata(08) <= not bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- I CPU extension (if not E)
|
csr.rdata(08) <= not bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- I CPU extension (if not E)
|
csr.rdata(12) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_M); -- M CPU extension
|
csr.rdata(12) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_M); -- M CPU extension
|
csr.rdata(20) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- U CPU extension
|
csr.rdata(20) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- U CPU extension
|
Line 2351... |
Line 2422... |
csr.rdata <= hw_version_c; -- NEORV32 hardware version
|
csr.rdata <= hw_version_c; -- NEORV32 hardware version
|
when csr_mhartid_c => -- R/-: mhartid - hardware thread ID
|
when csr_mhartid_c => -- R/-: mhartid - hardware thread ID
|
csr.rdata <= HW_THREAD_ID;
|
csr.rdata <= HW_THREAD_ID;
|
|
|
-- custom machine read-only CSRs --
|
-- custom machine read-only CSRs --
|
when csr_mzext_c => -- R/-: mzext - available Z* extensions
|
when csr_mzext_c => -- R/-: mzext - available RISC-V Z* extensions
|
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- RISC-V.Zicsr CPU extension
|
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- Zicsr
|
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- RISC-V.Zifencei CPU extension
|
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei
|
|
csr.rdata(2) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zbb
|
|
|
-- undefined/unavailable --
|
-- undefined/unavailable --
|
when others =>
|
when others =>
|
csr.rdata <= (others => '0'); -- not implemented
|
csr.rdata <= (others => '0'); -- not implemented
|
|
|