Line 46... |
Line 46... |
use neorv32.neorv32_package.all;
|
use neorv32.neorv32_package.all;
|
|
|
entity neorv32_cpu_control is
|
entity neorv32_cpu_control is
|
generic (
|
generic (
|
-- General --
|
-- General --
|
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
|
HW_THREAD_ID : natural; -- hardware thread id (32-bit)
|
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0) := x"00000000"; -- cpu boot address
|
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0); -- cpu boot address
|
CPU_DEBUG_ADDR : std_ulogic_vector(31 downto 0) := x"00000000"; -- cpu debug mode start address
|
CPU_DEBUG_ADDR : std_ulogic_vector(31 downto 0); -- cpu debug mode start address
|
-- RISC-V CPU Extensions --
|
-- RISC-V CPU Extensions --
|
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
|
CPU_EXTENSION_RISCV_A : boolean; -- implement atomic extension?
|
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
|
CPU_EXTENSION_RISCV_C : boolean; -- implement compressed extension?
|
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
CPU_EXTENSION_RISCV_E : boolean; -- implement embedded RF extension?
|
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
|
CPU_EXTENSION_RISCV_M : boolean; -- implement muld/div extension?
|
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
CPU_EXTENSION_RISCV_U : boolean; -- implement user mode extension?
|
CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT reg!)
|
CPU_EXTENSION_RISCV_Zfinx : boolean; -- implement 32-bit floating-point extension (using INT reg!)
|
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
CPU_EXTENSION_RISCV_Zicsr : boolean; -- implement CSR system?
|
CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.?
|
CPU_EXTENSION_RISCV_Zifencei : boolean; -- implement instruction stream sync.?
|
CPU_EXTENSION_RISCV_Zmmul : boolean := false; -- implement multiply-only M sub-extension?
|
CPU_EXTENSION_RISCV_Zmmul : boolean; -- implement multiply-only M sub-extension?
|
CPU_EXTENSION_RISCV_DEBUG : boolean := false; -- implement CPU debug mode?
|
CPU_EXTENSION_RISCV_DEBUG : boolean; -- implement CPU debug mode?
|
-- Extension Options --
|
-- Extension Options --
|
CPU_CNT_WIDTH : natural := 64; -- total width of CPU cycle and instret counters (0..64)
|
CPU_CNT_WIDTH : natural; -- total width of CPU cycle and instret counters (0..64)
|
|
CPU_IPB_ENTRIES : natural; -- entries is instruction prefetch buffer, has to be a power of 2
|
-- Physical memory protection (PMP) --
|
-- Physical memory protection (PMP) --
|
PMP_NUM_REGIONS : natural := 0; -- number of regions (0..64)
|
PMP_NUM_REGIONS : natural; -- number of regions (0..64)
|
PMP_MIN_GRANULARITY : natural := 64*1024; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
PMP_MIN_GRANULARITY : natural; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
-- Hardware Performance Monitors (HPM) --
|
-- Hardware Performance Monitors (HPM) --
|
HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29)
|
HPM_NUM_CNTS : natural; -- number of implemented HPM counters (0..29)
|
HPM_CNT_WIDTH : natural := 40 -- total size of HPM counters (0..64)
|
HPM_CNT_WIDTH : natural -- total size of HPM counters (0..64)
|
);
|
);
|
port (
|
port (
|
-- global control --
|
-- global control --
|
clk_i : in std_ulogic; -- global clock, rising edge
|
clk_i : in std_ulogic; -- global clock, rising edge
|
rstn_i : in std_ulogic; -- global reset, low-active, async
|
rstn_i : in std_ulogic; -- global reset, low-active, async
|
Line 272... |
Line 273... |
re : std_ulogic; -- csr read enable
|
re : std_ulogic; -- csr read enable
|
re_nxt : std_ulogic;
|
re_nxt : std_ulogic;
|
wdata : std_ulogic_vector(data_width_c-1 downto 0); -- csr write data
|
wdata : std_ulogic_vector(data_width_c-1 downto 0); -- csr write data
|
rdata : std_ulogic_vector(data_width_c-1 downto 0); -- csr read data
|
rdata : std_ulogic_vector(data_width_c-1 downto 0); -- csr read data
|
--
|
--
|
|
mstatus_fs : std_ulogic; -- mstatus.FS: FPU status (single-bit, only OFF and DIRTY states)
|
mstatus_mie : std_ulogic; -- mstatus.MIE: global IRQ enable (R/W)
|
mstatus_mie : std_ulogic; -- mstatus.MIE: global IRQ enable (R/W)
|
mstatus_mpie : std_ulogic; -- mstatus.MPIE: previous global IRQ enable (R/W)
|
mstatus_mpie : std_ulogic; -- mstatus.MPIE: previous global IRQ enable (R/W)
|
mstatus_mpp : std_ulogic_vector(1 downto 0); -- mstatus.MPP: machine previous privilege mode
|
mstatus_mpp : std_ulogic_vector(1 downto 0); -- mstatus.MPP: machine previous privilege mode
|
|
mstatus_tw : std_ulogic; -- mstatus:TW trigger illegal instruction exception if WFI is executed outside of M-mode
|
--
|
--
|
mie_msie : std_ulogic; -- mie.MSIE: machine software interrupt enable (R/W)
|
mie_msie : std_ulogic; -- mie.MSIE: machine software interrupt enable (R/W)
|
mie_meie : std_ulogic; -- mie.MEIE: machine external interrupt enable (R/W)
|
mie_meie : std_ulogic; -- mie.MEIE: machine external interrupt enable (R/W)
|
mie_mtie : std_ulogic; -- mie.MEIE: machine timer interrupt enable (R/W)
|
mie_mtie : std_ulogic; -- mie.MEIE: machine timer interrupt enable (R/W)
|
mie_firqe : std_ulogic_vector(15 downto 0); -- mie.firq*e: fast interrupt enabled (R/W)
|
mie_firqe : std_ulogic_vector(15 downto 0); -- mie.firq*e: fast interrupt enabled (R/W)
|
Line 456... |
Line 459... |
|
|
-- Instruction Prefetch Buffer (FIFO) -----------------------------------------------------
|
-- Instruction Prefetch Buffer (FIFO) -----------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
instr_prefetch_buffer: neorv32_fifo
|
instr_prefetch_buffer: neorv32_fifo
|
generic map (
|
generic map (
|
FIFO_DEPTH => ipb_entries_c, -- number of fifo entries; has to be a power of two; min 1
|
FIFO_DEPTH => CPU_IPB_ENTRIES, -- number of fifo entries; has to be a power of two; min 1
|
FIFO_WIDTH => ipb.wdata'length, -- size of data elements in fifo
|
FIFO_WIDTH => ipb.wdata'length, -- size of data elements in fifo
|
FIFO_RSYNC => false, -- we NEED to read data asynchronously
|
FIFO_RSYNC => false, -- we NEED to read data asynchronously
|
FIFO_SAFE => false -- no safe access required (ensured by FIFO-external control)
|
FIFO_SAFE => false -- no safe access required (ensured by FIFO-external control)
|
)
|
)
|
port map (
|
port map (
|
Line 612... |
Line 615... |
-- Instruction Execution
|
-- Instruction Execution
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
-- Immediate Generator --------------------------------------------------------------------
|
-- Immediate Generator --------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
imm_gen: process(execute_engine.i_reg, rstn_i, clk_i)
|
imm_gen: process(rstn_i, clk_i)
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
begin
|
begin
|
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
|
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
imm_o <= (others => def_rst_val_c);
|
imm_o <= (others => def_rst_val_c);
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
if (execute_engine.state = BRANCH) then -- next_PC as immediate for jump-and-link operations (=return address) via ALU.MOV_B
|
if (execute_engine.state = BRANCH) then -- next_PC as immediate for jump-and-link operations (=return address) via ALU.MOV_B
|
imm_o <= execute_engine.next_pc;
|
imm_o <= execute_engine.next_pc;
|
else -- "normal" immediate from instruction word
|
else -- "normal" immediate from instruction word
|
|
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
|
case opcode_v is -- save some bits here, the two LSBs are always "11" for rv32
|
case opcode_v is -- save some bits here, the two LSBs are always "11" for rv32
|
when opcode_store_c => -- S-immediate
|
when opcode_store_c => -- S-immediate
|
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
|
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
|
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
|
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
|
imm_o(04 downto 01) <= execute_engine.i_reg(11 downto 08);
|
imm_o(04 downto 01) <= execute_engine.i_reg(11 downto 08);
|
Line 688... |
Line 691... |
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
|
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
|
execute_engine.state <= SYS_WAIT;
|
execute_engine.state <= SYS_WAIT;
|
execute_engine.sleep <= '0';
|
execute_engine.sleep <= '0';
|
execute_engine.branched <= '1'; -- reset is a branch from "somewhere"
|
execute_engine.branched <= '1'; -- reset is a branch from "somewhere"
|
-- no dedicated RESET required --
|
-- no dedicated RESET required --
|
execute_engine.state_prev <= SYS_WAIT;
|
execute_engine.state_prev <= SYS_WAIT; -- actual reset value is not relevant
|
execute_engine.i_reg <= (others => def_rst_val_c);
|
execute_engine.i_reg <= (others => def_rst_val_c);
|
execute_engine.is_ci <= def_rst_val_c;
|
execute_engine.is_ci <= def_rst_val_c;
|
execute_engine.last_pc <= (others => def_rst_val_c);
|
execute_engine.last_pc <= (others => def_rst_val_c);
|
execute_engine.i_reg_last <= (others => def_rst_val_c);
|
execute_engine.i_reg_last <= (others => def_rst_val_c);
|
execute_engine.next_pc <= (others => def_rst_val_c);
|
execute_engine.next_pc <= (others => def_rst_val_c);
|
Line 915... |
Line 918... |
|
|
|
|
-- 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 (to let side effects kick in)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
-- 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?
|
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_csrr_c; -- hacky! CSR read-access without a valid CSR-read -> results zero
|
|
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- force RF write access and force rd=r0
|
|
end if;
|
|
--
|
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
|
|
|
|
when DISPATCH => -- Get new command from instruction issue engine
|
when DISPATCH => -- Get new command from instruction issue engine
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
Line 1101... |
Line 1098... |
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
end if;
|
end if;
|
|
|
when opcode_fop_c => -- floating-point operations
|
when opcode_fop_c => -- floating-point operations
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (CPU_EXTENSION_RISCV_Zfinx = true) and (decode_aux.is_float_op = '1') then
|
if (CPU_EXTENSION_RISCV_Zfinx = true) and (decode_aux.is_float_op = '1') and (csr.mstatus_fs = '1') then
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_fpu_c; -- trigger FPU CP
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_fpu_c; -- trigger FPU CP
|
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;
|
execute_engine.state_nxt <= ALU_WAIT;
|
execute_engine.state_nxt <= ALU_WAIT;
|
else
|
else
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
Line 1118... |
Line 1115... |
end case;
|
end case;
|
|
|
|
|
when SYS_ENV => -- system environment operation - execution
|
when SYS_ENV => -- system environment operation - execution
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT; -- default
|
case decode_aux.sys_env_cmd is -- use a simplified input here (with permanent zeros)
|
case decode_aux.sys_env_cmd is -- use a simplified input here (with permanent zeros)
|
when funct12_ecall_c => trap_ctrl.env_call <= '1'; -- ECALL
|
when funct12_ecall_c => trap_ctrl.env_call <= '1'; -- ECALL
|
when funct12_ebreak_c => trap_ctrl.break_point <= '1'; -- EBREAK
|
when funct12_ebreak_c => trap_ctrl.break_point <= '1'; -- EBREAK
|
when funct12_mret_c => execute_engine.state_nxt <= TRAP_EXIT; -- MRET
|
|
when funct12_wfi_c => execute_engine.sleep_nxt <= '1'; -- WFI
|
when funct12_wfi_c => execute_engine.sleep_nxt <= '1'; -- WFI
|
|
when funct12_mret_c => -- MRET
|
|
if (CPU_EXTENSION_RISCV_U = true) and (csr.priv_m_mode = '1') then -- only allowed in M-mode
|
|
execute_engine.state_nxt <= TRAP_EXIT;
|
|
else
|
|
NULL;
|
|
end if;
|
when funct12_dret_c => -- DRET
|
when funct12_dret_c => -- DRET
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
if (CPU_EXTENSION_RISCV_DEBUG = true) and (debug_ctrl.running = '1') then -- only allowed in debug-mode
|
execute_engine.state_nxt <= TRAP_EXIT;
|
execute_engine.state_nxt <= TRAP_EXIT;
|
debug_ctrl.dret <= '1';
|
debug_ctrl.dret <= '1';
|
else
|
else
|
NULL;
|
NULL;
|
end if;
|
end if;
|
Line 1189... |
Line 1191... |
when FENCE_OP => -- fence operations - execution
|
when FENCE_OP => -- fence operations - execution
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
-- FENCE.I --
|
-- FENCE.I --
|
if (CPU_EXTENSION_RISCV_Zifencei = true) then
|
if (CPU_EXTENSION_RISCV_Zifencei = true) then
|
execute_engine.pc_mux_sel <= '0'; -- linear next PC = start *new* instruction fetch with next instruction (only relevant for fence.i)
|
execute_engine.pc_mux_sel <= '0'; -- linear next PC = start *new* instruction fetch with next instruction
|
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) then
|
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) then
|
execute_engine.pc_we <= '1'; -- update PC
|
execute_engine.pc_we <= '1'; -- update PC
|
execute_engine.branched_nxt <= '1'; -- this is an actual branch
|
execute_engine.branched_nxt <= '1'; -- this is an actual branch
|
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
|
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
|
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
|
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
|
Line 1231... |
Line 1233... |
when LOADSTORE_2 => -- wait for bus transaction to finish
|
when LOADSTORE_2 => -- wait for bus transaction to finish
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for load (and SC.W) operations)
|
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for load (and SC.W) operations)
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
|
-- wait for memory response / exception --
|
-- wait for memory response / exception --
|
if (trap_ctrl.env_start = '1') then -- abort if exception
|
if (trap_ctrl.env_start = '1') and -- only abort if BUS EXCEPTION
|
|
((trap_ctrl.cause = trap_lma_c) or (trap_ctrl.cause = trap_lbe_c) or (trap_ctrl.cause = trap_sma_c) or (trap_ctrl.cause = trap_sbe_c)) then
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
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
|
-- data write-back --
|
-- data write-back --
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or -- normal load
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or -- normal load
|
(decode_aux.is_atomic_lr = '1') or -- atomic load-reservate
|
(decode_aux.is_atomic_lr = '1') or -- atomic load-reservate
|
Line 1279... |
Line 1282... |
csr_acc_valid <= '0'; -- default = invalid access
|
csr_acc_valid <= '0'; -- default = invalid access
|
case csr.addr is
|
case csr.addr is
|
|
|
-- floating-point CSRs --
|
-- floating-point CSRs --
|
when csr_fflags_c | csr_frm_c | csr_fcsr_c =>
|
when csr_fflags_c | csr_frm_c | csr_fcsr_c =>
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then
|
if (CPU_EXTENSION_RISCV_Zfinx = true) and (csr.mstatus_fs = '1') then -- FPU implemented and enabled?
|
csr_acc_valid <= '1'; -- full access for everyone if Zfinx extension is implemented
|
csr_acc_valid <= '1'; -- full access for everyone
|
else
|
else
|
NULL;
|
NULL;
|
end if;
|
end if;
|
|
|
-- machine trap setup & handling --
|
-- machine trap setup & handling --
|
when csr_mstatus_c | csr_misa_c | csr_mie_c | csr_mtvec_c | csr_mcounteren_c | csr_mscratch_c | csr_mepc_c | csr_mcause_c =>
|
when csr_mstatus_c | csr_mstatush_c | csr_misa_c | csr_mie_c | csr_mtvec_c | csr_mcounteren_c | csr_mscratch_c | csr_mepc_c | csr_mcause_c =>
|
csr_acc_valid <= csr.priv_m_mode; -- M-mode only, NOTE: MISA is read-only in the NEORV32 but we do not cause an exception here for compatibility
|
csr_acc_valid <= csr.priv_m_mode; -- M-mode only, NOTE: MISA is read-only in the NEORV32 but we do not cause an exception here for compatibility
|
when csr_mip_c | csr_mtval_c => -- NOTE: MIP and MTVAL are read-only in the NEORV32!
|
when csr_mip_c | csr_mtval_c => -- NOTE: MIP and MTVAL are read-only in the NEORV32!
|
csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
|
|
-- physical memory protection (PMP) - address & configuration --
|
-- physical memory protection (PMP) - address & configuration --
|
Line 1353... |
Line 1356... |
when csr_mcountinhibit_c =>
|
when csr_mcountinhibit_c =>
|
csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
|
|
|
|
-- machine information registers & custom (NEORV32-specific) read-only CSRs --
|
-- machine information registers & custom (NEORV32-specific) read-only CSRs --
|
when csr_mvendorid_c | csr_marchid_c | csr_mimpid_c | csr_mhartid_c | csr_mzext_c =>
|
when csr_mvendorid_c | csr_marchid_c | csr_mimpid_c | csr_mhartid_c | csr_mconfigptr_c | csr_mzext_c =>
|
csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
|
|
-- debug mode CSRs --
|
-- debug mode CSRs --
|
when csr_dcsr_c | csr_dpc_c | csr_dscratch0_c =>
|
when csr_dcsr_c | csr_dpc_c | csr_dscratch0_c =>
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
Line 1373... |
Line 1376... |
end process csr_access_check;
|
end process csr_access_check;
|
|
|
|
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
illegal_instruction_check: process(execute_engine, decode_aux, csr_acc_valid, debug_ctrl)
|
illegal_instruction_check: process(execute_engine, decode_aux, csr, csr_acc_valid, debug_ctrl)
|
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 1539... |
Line 1542... |
-- ecall, ebreak, mret, wfi, dret --
|
-- ecall, ebreak, mret, wfi, dret --
|
elsif (execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c) = "00000") and
|
elsif (execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c) = "00000") and
|
(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then
|
(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then
|
if (execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_ecall_c) or -- ECALL
|
if (execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_ecall_c) or -- ECALL
|
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_ebreak_c) or -- EBREAK
|
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_ebreak_c) or -- EBREAK
|
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_mret_c) or -- MRET
|
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_mret_c)and (CPU_EXTENSION_RISCV_U = true) and (csr.priv_m_mode = '1')) or -- MRET (only allowed in M-mode)
|
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = (funct12_dret_c)) and (CPU_EXTENSION_RISCV_DEBUG = true) and (debug_ctrl.running = '1')) or -- DRET
|
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = (funct12_dret_c)) and (CPU_EXTENSION_RISCV_DEBUG = true) and (debug_ctrl.running = '1')) or -- DRET
|
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_wfi_c) then -- WFI
|
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_wfi_c) and ((csr.priv_m_mode = '1') or (csr.mstatus_tw = '0'))) then -- WFI allowed in M-mode or if mstatus.TW=0
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
else
|
else
|
illegal_instruction <= '1';
|
illegal_instruction <= '1';
|
end if;
|
end if;
|
else
|
else
|
Line 1562... |
Line 1565... |
illegal_instruction <= '1';
|
illegal_instruction <= '1';
|
end if;
|
end if;
|
|
|
when opcode_fop_c => -- floating point operations - single/dual operands
|
when opcode_fop_c => -- floating point operations - single/dual operands
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (CPU_EXTENSION_RISCV_Zfinx = true) and -- F extension enabled
|
if (CPU_EXTENSION_RISCV_Zfinx = true) and (csr.mstatus_fs = '1') and -- F extension implemented and enabled
|
(execute_engine.i_reg(instr_funct7_lsb_c+1 downto instr_funct7_lsb_c) = float_single_c) and -- single-precision operations only
|
(execute_engine.i_reg(instr_funct7_lsb_c+1 downto instr_funct7_lsb_c) = float_single_c) and -- single-precision operations only
|
(decode_aux.is_float_op = '1') then -- is correct/supported floating-point instruction
|
(decode_aux.is_float_op = '1') then -- is correct/supported floating-point instruction
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
else
|
else
|
illegal_instruction <= '1';
|
illegal_instruction <= '1';
|
Line 1917... |
Line 1920... |
-- see: https://forums.xilinx.com/t5/General-Technical-Discussion/quot-Don-t-care-quot-reset-value/td-p/412845
|
-- see: https://forums.xilinx.com/t5/General-Technical-Discussion/quot-Don-t-care-quot-reset-value/td-p/412845
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
csr.we <= '0';
|
csr.we <= '0';
|
--
|
--
|
csr.mstatus_mie <= '0';
|
csr.mstatus_mie <= '0';
|
|
csr.mstatus_fs <= '0';
|
csr.mstatus_mpie <= '0';
|
csr.mstatus_mpie <= '0';
|
csr.mstatus_mpp <= (others => '0');
|
csr.mstatus_mpp <= (others => '0');
|
|
csr.mstatus_tw <= '0';
|
csr.privilege <= priv_mode_m_c; -- start in MACHINE mode
|
csr.privilege <= priv_mode_m_c; -- start in MACHINE mode
|
csr.mie_msie <= def_rst_val_c;
|
csr.mie_msie <= def_rst_val_c;
|
csr.mie_meie <= def_rst_val_c;
|
csr.mie_meie <= def_rst_val_c;
|
csr.mie_mtie <= def_rst_val_c;
|
csr.mie_mtie <= def_rst_val_c;
|
csr.mie_firqe <= (others => def_rst_val_c);
|
csr.mie_firqe <= (others => def_rst_val_c);
|
Line 1991... |
Line 1996... |
csr.mstatus_mie <= csr.wdata(03);
|
csr.mstatus_mie <= csr.wdata(03);
|
csr.mstatus_mpie <= csr.wdata(07);
|
csr.mstatus_mpie <= csr.wdata(07);
|
if (CPU_EXTENSION_RISCV_U = true) then -- user mode implemented
|
if (CPU_EXTENSION_RISCV_U = true) then -- user mode implemented
|
csr.mstatus_mpp(0) <= csr.wdata(11) or csr.wdata(12);
|
csr.mstatus_mpp(0) <= csr.wdata(11) or csr.wdata(12);
|
csr.mstatus_mpp(1) <= csr.wdata(11) or csr.wdata(12);
|
csr.mstatus_mpp(1) <= csr.wdata(11) or csr.wdata(12);
|
else -- only machine mode is available
|
csr.mstatus_tw <= csr.wdata(21);
|
csr.mstatus_mpp <= priv_mode_m_c;
|
end if;
|
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then -- FPU implemented
|
|
csr.mstatus_fs <= csr.wdata(14) or csr.wdata(13);
|
end if;
|
end if;
|
end if;
|
end if;
|
-- R/W: mie - machine interrupt enable register --
|
-- R/W: mie - machine interrupt enable register --
|
if (csr.addr(3 downto 0) = csr_mie_c(3 downto 0)) then
|
if (csr.addr(3 downto 0) = csr_mie_c(3 downto 0)) then
|
csr.mie_msie <= csr.wdata(03); -- machine SW IRQ enable
|
csr.mie_msie <= csr.wdata(03); -- machine SW IRQ enable
|
Line 2080... |
Line 2087... |
if (csr.addr(4 downto 0) = csr_mcountinhibit_c(4 downto 0)) then
|
if (csr.addr(4 downto 0) = csr_mcountinhibit_c(4 downto 0)) then
|
csr.mcountinhibit_cy <= csr.wdata(0); -- enable auto-increment of [m]cycle[h] counter
|
csr.mcountinhibit_cy <= csr.wdata(0); -- enable auto-increment of [m]cycle[h] counter
|
csr.mcountinhibit_ir <= csr.wdata(2); -- enable auto-increment of [m]instret[h] counter
|
csr.mcountinhibit_ir <= csr.wdata(2); -- enable auto-increment of [m]instret[h] counter
|
csr.mcountinhibit_hpm <= csr.wdata(csr.mcountinhibit_hpm'left+3 downto 3); -- enable auto-increment of [m]hpmcounter*[h] counter
|
csr.mcountinhibit_hpm <= csr.wdata(csr.mcountinhibit_hpm'left+3 downto 3); -- enable auto-increment of [m]hpmcounter*[h] counter
|
end if;
|
end if;
|
-- machine performance-monitoring event selector --
|
-- machine performance-monitors event selector --
|
if (HPM_NUM_CNTS > 0) then
|
if (HPM_NUM_CNTS > 0) then
|
for i in 0 to HPM_NUM_CNTS-1 loop
|
for i in 0 to HPM_NUM_CNTS-1 loop
|
if (csr.addr(4 downto 0) = std_ulogic_vector(to_unsigned(i+3, 5))) then
|
if (csr.addr(4 downto 0) = std_ulogic_vector(to_unsigned(i+3, 5))) then
|
csr.mhpmevent(i) <= csr.wdata(csr.mhpmevent(i)'left downto 0);
|
csr.mhpmevent(i) <= csr.wdata(csr.mhpmevent(i)'left downto 0);
|
end if;
|
end if;
|
Line 2224... |
Line 2231... |
|
|
-- user mode disabled --
|
-- user mode disabled --
|
if (CPU_EXTENSION_RISCV_U = false) then
|
if (CPU_EXTENSION_RISCV_U = false) then
|
csr.privilege <= priv_mode_m_c;
|
csr.privilege <= priv_mode_m_c;
|
csr.mstatus_mpp <= priv_mode_m_c;
|
csr.mstatus_mpp <= priv_mode_m_c;
|
|
csr.mstatus_tw <= '0';
|
csr.mcounteren_cy <= '0';
|
csr.mcounteren_cy <= '0';
|
csr.mcounteren_tm <= '0';
|
csr.mcounteren_tm <= '0';
|
csr.mcounteren_ir <= '0';
|
csr.mcounteren_ir <= '0';
|
csr.dcsr_ebreaku <= '0';
|
csr.dcsr_ebreaku <= '0';
|
csr.dcsr_prv <= priv_mode_m_c;
|
csr.dcsr_prv <= priv_mode_m_c;
|
Line 2253... |
Line 2261... |
csr.mcountinhibit_ir <= '0';
|
csr.mcountinhibit_ir <= '0';
|
end if;
|
end if;
|
|
|
-- floating-point extension disabled --
|
-- floating-point extension disabled --
|
if (CPU_EXTENSION_RISCV_Zfinx = false) then
|
if (CPU_EXTENSION_RISCV_Zfinx = false) then
|
|
csr.mstatus_fs <= '0';
|
csr.fflags <= (others => '0');
|
csr.fflags <= (others => '0');
|
csr.frm <= (others => '0');
|
csr.frm <= (others => '0');
|
end if;
|
end if;
|
|
|
-- debug mode disabled --
|
-- debug mode disabled --
|
Line 2500... |
Line 2509... |
when csr_mstatus_c => -- mstatus (r/w): machine status register
|
when csr_mstatus_c => -- mstatus (r/w): machine status register
|
csr.rdata(03) <= csr.mstatus_mie; -- MIE
|
csr.rdata(03) <= csr.mstatus_mie; -- MIE
|
csr.rdata(07) <= csr.mstatus_mpie; -- MPIE
|
csr.rdata(07) <= csr.mstatus_mpie; -- MPIE
|
csr.rdata(11) <= csr.mstatus_mpp(0); -- MPP: machine previous privilege mode low
|
csr.rdata(11) <= csr.mstatus_mpp(0); -- MPP: machine previous privilege mode low
|
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
|
|
csr.rdata(13) <= csr.mstatus_fs; -- FS(0): FPU status - OFF or DIRTY
|
|
csr.rdata(14) <= csr.mstatus_fs; -- FS(1): FPU status - OFF or DIRTY
|
|
csr.rdata(21) <= csr.mstatus_tw; -- TW: WFI timeout wait
|
|
csr.rdata(31) <= csr.mstatus_fs; -- SD: state dirty (only FPU yet)
|
when csr_misa_c => -- misa (r/-): ISA and extensions
|
when csr_misa_c => -- misa (r/-): 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(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)
|
Line 2537... |
Line 2550... |
when csr_mepc_c => -- mepc (r/w): machine exception program counter
|
when csr_mepc_c => -- mepc (r/w): machine exception program counter
|
csr.rdata <= csr.mepc(data_width_c-1 downto 1) & '0';
|
csr.rdata <= csr.mepc(data_width_c-1 downto 1) & '0';
|
when csr_mcause_c => -- mcause (r/w): machine trap cause
|
when csr_mcause_c => -- mcause (r/w): machine trap cause
|
csr.rdata(31) <= csr.mcause(csr.mcause'left);
|
csr.rdata(31) <= csr.mcause(csr.mcause'left);
|
csr.rdata(csr.mcause'left-1 downto 0) <= csr.mcause(csr.mcause'left-1 downto 0);
|
csr.rdata(csr.mcause'left-1 downto 0) <= csr.mcause(csr.mcause'left-1 downto 0);
|
when csr_mtval_c => -- mtval (r/w): machine bad address or instruction
|
when csr_mtval_c => -- mtval (r/-): machine bad address or instruction
|
csr.rdata <= csr.mtval;
|
csr.rdata <= csr.mtval;
|
when csr_mip_c => -- mip (r/-): machine interrupt pending
|
when csr_mip_c => -- mip (r/-): machine interrupt pending
|
csr.rdata(03) <= trap_ctrl.irq_buf(interrupt_msw_irq_c);
|
csr.rdata(03) <= trap_ctrl.irq_buf(interrupt_msw_irq_c);
|
csr.rdata(07) <= trap_ctrl.irq_buf(interrupt_mtime_irq_c);
|
csr.rdata(07) <= trap_ctrl.irq_buf(interrupt_mtime_irq_c);
|
csr.rdata(11) <= trap_ctrl.irq_buf(interrupt_mext_irq_c);
|
csr.rdata(11) <= trap_ctrl.irq_buf(interrupt_mext_irq_c);
|
Line 2755... |
Line 2768... |
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
-- when csr_mvendorid_c => csr.rdata <= (others => '0'); -- mvendorid (r/-): vendor ID, implemented but always zero
|
-- when csr_mvendorid_c => csr.rdata <= (others => '0'); -- mvendorid (r/-): vendor ID, implemented but always zero
|
when csr_marchid_c => csr.rdata(4 downto 0) <= "10011"; -- marchid (r/-): arch ID - official RISC-V open-source arch ID
|
when csr_marchid_c => csr.rdata(4 downto 0) <= "10011"; -- marchid (r/-): arch ID - official RISC-V open-source arch ID
|
when csr_mimpid_c => csr.rdata <= hw_version_c; -- mimpid (r/-): implementation ID -- NEORV32 hardware version
|
when csr_mimpid_c => csr.rdata <= hw_version_c; -- mimpid (r/-): implementation ID -- NEORV32 hardware version
|
when csr_mhartid_c => csr.rdata <= std_ulogic_vector(to_unsigned(HW_THREAD_ID, 32)); -- mhartid (r/-): hardware thread ID
|
when csr_mhartid_c => csr.rdata <= std_ulogic_vector(to_unsigned(HW_THREAD_ID, 32)); -- mhartid (r/-): hardware thread ID
|
|
-- when csr_mconfigptr_c => csr.rdata <= (others => '0'); -- mconfigptr (r/-): machine configuration pointer register, implemented but not assigned yet
|
|
|
-- custom machine read-only CSRs --
|
-- custom machine read-only CSRs --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_mzext_c => -- mzext (r/-): available RISC-V Z* sub-extensions
|
when csr_mzext_c => -- mzext (r/-): available RISC-V Z* sub-extensions
|
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- Zicsr
|
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- Zicsr
|