Line 48... |
Line 48... |
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 := 0; -- 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):= x"00000000"; -- cpu boot address
|
|
CPU_DEBUG_ADDR : std_ulogic_vector(31 downto 0) := x"00000000"; -- 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 := false; -- implement atomic extension?
|
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit manipulation extensions?
|
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_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT reg!)
|
CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT reg!)
|
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.?
|
CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.?
|
|
CPU_EXTENSION_RISCV_DEBUG : boolean := false; -- 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 := 64; -- total width of CPU cycle and instret counters (0..64)
|
-- Physical memory protection (PMP) --
|
-- Physical memory protection (PMP) --
|
PMP_NUM_REGIONS : natural := 0; -- number of regions (0..64)
|
PMP_NUM_REGIONS : natural := 0; -- 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 := 64*1024; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
Line 90... |
Line 92... |
curr_pc_o : out std_ulogic_vector(data_width_c-1 downto 0); -- current PC (corresponding to current instruction)
|
curr_pc_o : out std_ulogic_vector(data_width_c-1 downto 0); -- current PC (corresponding to current instruction)
|
csr_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
|
csr_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
|
-- FPU interface --
|
-- FPU interface --
|
fpu_rm_o : out std_ulogic_vector(02 downto 0); -- rounding mode
|
fpu_rm_o : out std_ulogic_vector(02 downto 0); -- rounding mode
|
fpu_flags_i : in std_ulogic_vector(04 downto 0); -- exception flags
|
fpu_flags_i : in std_ulogic_vector(04 downto 0); -- exception flags
|
|
-- debug mode (halt) request --
|
|
db_halt_req_i : in std_ulogic;
|
-- non-maskable interrupt --
|
-- non-maskable interrupt --
|
nm_irq_i : in std_ulogic;
|
nm_irq_i : in std_ulogic;
|
-- interrupts (risc-v compliant) --
|
-- interrupts (risc-v compliant) --
|
msw_irq_i : in std_ulogic; -- machine software interrupt
|
msw_irq_i : in std_ulogic; -- machine software interrupt
|
mext_irq_i : in std_ulogic; -- machine external interrupt
|
mext_irq_i : in std_ulogic; -- machine external interrupt
|
Line 240... |
Line 244... |
irq_buf : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
irq_buf : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
irq_fire : std_ulogic; -- set if there is a valid source in the interrupt buffer
|
irq_fire : std_ulogic; -- set if there is a valid source in the interrupt buffer
|
exc_ack : std_ulogic; -- acknowledge all exceptions
|
exc_ack : std_ulogic; -- acknowledge all exceptions
|
irq_ack : std_ulogic_vector(interrupt_width_c-1 downto 0); -- acknowledge specific interrupt
|
irq_ack : std_ulogic_vector(interrupt_width_c-1 downto 0); -- acknowledge specific interrupt
|
irq_ack_nxt : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
irq_ack_nxt : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
cause : std_ulogic_vector(5 downto 0); -- trap ID for mcause CSR
|
cause : std_ulogic_vector(6 downto 0); -- trap ID for mcause CSR
|
cause_nxt : std_ulogic_vector(5 downto 0);
|
cause_nxt : std_ulogic_vector(6 downto 0);
|
|
db_irq_fire : std_ulogic; -- set if there is a valid IRQ source in the "enter debug mode" trap buffer
|
|
db_irq_en : std_ulogic; -- set if IRQs are allowed in debu mode
|
--
|
--
|
env_start : std_ulogic; -- start trap handler env
|
env_start : std_ulogic; -- start trap handler env
|
env_start_ack : std_ulogic; -- start of trap handler acknowledged
|
env_start_ack : std_ulogic; -- start of trap handler acknowledged
|
env_end : std_ulogic; -- end trap handler env
|
env_end : std_ulogic; -- end trap handler env
|
--
|
--
|
Line 298... |
Line 304... |
mcountinhibit_cy : std_ulogic; -- mcounterinhibit.cy: enable auto-increment for [m]cycle[h]
|
mcountinhibit_cy : std_ulogic; -- mcounterinhibit.cy: enable auto-increment for [m]cycle[h]
|
mcountinhibit_ir : std_ulogic; -- mcounterinhibit.ir: enable auto-increment for [m]instret[h]
|
mcountinhibit_ir : std_ulogic; -- mcounterinhibit.ir: enable auto-increment for [m]instret[h]
|
mcountinhibit_hpm : std_ulogic_vector(HPM_NUM_CNTS-1 downto 0); -- mcounterinhibit.hpm3: enable auto-increment for mhpmcounterx[h]
|
mcountinhibit_hpm : std_ulogic_vector(HPM_NUM_CNTS-1 downto 0); -- mcounterinhibit.hpm3: enable auto-increment for mhpmcounterx[h]
|
--
|
--
|
privilege : std_ulogic_vector(1 downto 0); -- hart's current privilege mode
|
privilege : std_ulogic_vector(1 downto 0); -- hart's current privilege mode
|
|
privilege_rd : std_ulogic_vector(1 downto 0); -- hart's current privilege mode (effective)
|
priv_m_mode : std_ulogic; -- CPU in M-mode
|
priv_m_mode : std_ulogic; -- CPU in M-mode
|
priv_u_mode : std_ulogic; -- CPU in u-mode
|
priv_u_mode : std_ulogic; -- CPU in u-mode
|
--
|
--
|
mepc : std_ulogic_vector(data_width_c-1 downto 0); -- mepc: machine exception pc (R/W)
|
mepc : std_ulogic_vector(data_width_c-1 downto 0); -- mepc: machine exception pc (R/W)
|
mcause : std_ulogic_vector(5 downto 0); -- mcause: machine trap cause (R/W)
|
mcause : std_ulogic_vector(5 downto 0); -- mcause: machine trap cause (R/W)
|
Line 326... |
Line 333... |
pmpcfg_rd : pmp_ctrl_rd_t; -- physical memory protection - actual read data
|
pmpcfg_rd : pmp_ctrl_rd_t; -- physical memory protection - actual read data
|
pmpaddr : pmp_addr_t; -- physical memory protection - address registers
|
pmpaddr : pmp_addr_t; -- physical memory protection - address registers
|
--
|
--
|
frm : std_ulogic_vector(02 downto 0); -- frm (R/W): FPU rounding mode
|
frm : std_ulogic_vector(02 downto 0); -- frm (R/W): FPU rounding mode
|
fflags : std_ulogic_vector(04 downto 0); -- fflags (R/W): FPU exception flags
|
fflags : std_ulogic_vector(04 downto 0); -- fflags (R/W): FPU exception flags
|
|
--
|
|
dcsr_ebreakm : std_ulogic; -- dcsr.ebreakm (R/W): behavior of ebreak instruction on m-mode
|
|
dcsr_ebreaku : std_ulogic; -- dcsr.ebreaku (R/W): behavior of ebreak instruction on u-mode
|
|
dcsr_step : std_ulogic; -- dcsr.step (R/W): single-step mode
|
|
dcsr_stepie : std_ulogic; -- dcsr.stepie (R/W): enable IRQs in single-step mode
|
|
dcsr_prv : std_ulogic_vector(01 downto 0); -- dcsr.prv (R/W): current privilege level when entering debug mode
|
|
dcsr_cause : std_ulogic_vector(02 downto 0); -- dcsr.cause (R/-): why was debug mode entered
|
|
dcsr_rd : std_ulogic_vector(data_width_c-1 downto 0); -- dcsr (R/(W)): debug mode control and status register
|
|
dpc : std_ulogic_vector(data_width_c-1 downto 0); -- dpc (R/W): debug mode program counter
|
|
dscratch0 : std_ulogic_vector(data_width_c-1 downto 0); -- dscratch0 (R/W): debug mode scratch register 0
|
end record;
|
end record;
|
signal csr : csr_t;
|
signal csr : csr_t;
|
|
|
|
-- debug mode controller --
|
|
type debug_ctrl_state_t is (DEBUG_OFFLINE, DEBUG_PENDING, DEBUG_ONLINE, DEBUG_EXIT);
|
|
type debug_ctrl_t is record
|
|
state : debug_ctrl_state_t;
|
|
-- decoded state --
|
|
running : std_ulogic; -- debug mode active
|
|
pending : std_ulogic; -- waiting to start debug mode
|
|
-- entering triggers --
|
|
trig_break : std_ulogic; -- ebreak instruction
|
|
trig_halt : std_ulogic; -- external request
|
|
trig_step : std_ulogic; -- single-stepping mode
|
|
-- leave debug mode --
|
|
dret : std_ulogic; -- executed DRET instruction
|
|
-- misc --
|
|
ext_halt_req : std_ulogic_vector(1 downto 0); -- rising edge detector for external halt request
|
|
end record;
|
|
signal debug_ctrl : debug_ctrl_t;
|
|
|
-- counter low-to-high-word carry --
|
-- counter low-to-high-word carry --
|
signal mcycle_msb : std_ulogic;
|
signal mcycle_msb : std_ulogic;
|
signal minstret_msb : std_ulogic;
|
signal minstret_msb : std_ulogic;
|
signal mhpmcounter_msb : std_ulogic_vector(HPM_NUM_CNTS-1 downto 0);
|
signal mhpmcounter_msb : std_ulogic_vector(HPM_NUM_CNTS-1 downto 0);
|
|
|
Line 714... |
Line 749... |
--
|
--
|
execute_engine.state_prev <= execute_engine.state;
|
execute_engine.state_prev <= execute_engine.state;
|
execute_engine.i_reg <= execute_engine.i_reg_nxt;
|
execute_engine.i_reg <= execute_engine.i_reg_nxt;
|
execute_engine.is_ci <= execute_engine.is_ci_nxt;
|
execute_engine.is_ci <= execute_engine.is_ci_nxt;
|
execute_engine.is_cp_op <= execute_engine.is_cp_op_nxt;
|
execute_engine.is_cp_op <= execute_engine.is_cp_op_nxt;
|
|
|
-- PC & IR of "last executed" instruction --
|
-- PC & IR of "last executed" instruction --
|
if (execute_engine.state = EXECUTE) then
|
if (execute_engine.state = EXECUTE) then
|
execute_engine.last_pc <= execute_engine.pc;
|
execute_engine.last_pc <= execute_engine.pc;
|
execute_engine.i_reg_last <= execute_engine.i_reg;
|
execute_engine.i_reg_last <= execute_engine.i_reg;
|
end if;
|
end if;
|
|
|
-- next PC --
|
-- next PC --
|
case execute_engine.state is
|
case execute_engine.state is
|
when TRAP_ENTER => execute_engine.next_pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
|
when TRAP_ENTER =>
|
when TRAP_EXIT => execute_engine.next_pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap exit
|
if (CPU_EXTENSION_RISCV_DEBUG = false) then -- normal trapping
|
when EXECUTE => execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + unsigned(execute_engine.next_pc_inc)); -- next linear PC
|
execute_engine.next_pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
|
when others => NULL;
|
else -- DEBUG MODE enabled
|
|
if (trap_ctrl.cause(5) = '1') then -- trap cause: debug mode (re-)entry
|
|
execute_engine.next_pc <= CPU_DEBUG_ADDR; -- debug mode enter; start at "parking loop" <normal_entry>
|
|
elsif (debug_ctrl.running = '1') then -- any other exception INSIDE debug mode
|
|
execute_engine.next_pc <= std_ulogic_vector(unsigned(CPU_DEBUG_ADDR) + 4); -- execute at "parking loop" <exception_entry>
|
|
else -- normal trapping
|
|
execute_engine.next_pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
|
|
end if;
|
|
end if;
|
|
when TRAP_EXIT =>
|
|
if (CPU_EXTENSION_RISCV_DEBUG = false) or (debug_ctrl.running = '0') then -- normal end of trap
|
|
execute_engine.next_pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap exit
|
|
else -- DEBUG MODE exiting
|
|
execute_engine.next_pc <= csr.dpc(data_width_c-1 downto 1) & '0'; -- debug mode exit
|
|
end if;
|
|
when EXECUTE =>
|
|
execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + unsigned(execute_engine.next_pc_inc)); -- next linear PC
|
|
when others =>
|
|
NULL;
|
end case;
|
end case;
|
|
|
-- main control bus --
|
-- main control bus --
|
ctrl <= ctrl_nxt;
|
ctrl <= ctrl_nxt;
|
end if;
|
end if;
|
end process execute_engine_fsm_sync;
|
end process execute_engine_fsm_sync;
|
|
|
Line 749... |
Line 805... |
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, bus_fast_ir, execute_engine, csr)
|
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, bus_fast_ir, execute_engine, csr)
|
begin
|
begin
|
-- signals from execute engine --
|
-- signals from execute engine --
|
ctrl_o <= ctrl;
|
ctrl_o <= ctrl;
|
-- current privilege level --
|
-- current privilege level --
|
ctrl_o(ctrl_priv_lvl_msb_c downto ctrl_priv_lvl_lsb_c) <= csr.privilege;
|
ctrl_o(ctrl_priv_lvl_msb_c downto ctrl_priv_lvl_lsb_c) <= csr.privilege_rd;
|
-- register addresses --
|
-- register addresses --
|
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_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);
|
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);
|
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_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c);
|
-- fast bus access requests --
|
-- fast bus access requests --
|
Line 772... |
Line 828... |
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);
|
-- cpu status --
|
-- cpu status --
|
ctrl_o(ctrl_sleep_c) <= execute_engine.sleep; -- cpu is in sleep mode
|
ctrl_o(ctrl_sleep_c) <= execute_engine.sleep; -- cpu is in sleep mode
|
ctrl_o(ctrl_trap_c) <= trap_ctrl.env_start_ack; -- cpu is starting a trap handler
|
ctrl_o(ctrl_trap_c) <= trap_ctrl.env_start_ack; -- cpu is starting a trap handler
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
|
ctrl_o(ctrl_debug_running_c) <= debug_ctrl.running; -- cpu is currently in debug mode
|
|
else
|
|
ctrl_o(ctrl_debug_running_c) <= '0';
|
|
end if;
|
end process ctrl_output;
|
end process ctrl_output;
|
|
|
|
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 861... |
Line 922... |
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "11000") and (execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c+1) = "0000")) then -- FCVT.W*.S
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "11000") and (execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c+1) = "0000")) then -- FCVT.W*.S
|
decode_aux.is_float_op <= '1';
|
decode_aux.is_float_op <= '1';
|
end if;
|
end if;
|
|
|
-- system/environment instructions --
|
-- system/environment instructions --
|
sys_env_cmd_mask_v := funct12_ecall_c or funct12_ebreak_c or funct12_mret_c or funct12_wfi_c; -- sum-up set bits
|
sys_env_cmd_mask_v := funct12_ecall_c or funct12_ebreak_c or funct12_mret_c or funct12_wfi_c or funct12_dret_c; -- sum-up set bits
|
decode_aux.sys_env_cmd(11 downto 0) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) and sys_env_cmd_mask_v; -- set unsued bits to always-zero
|
decode_aux.sys_env_cmd(11 downto 0) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) and sys_env_cmd_mask_v; -- set unsued bits to always-zero
|
end process decode_helper;
|
end process decode_helper;
|
|
|
|
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
execute_engine_fsm_comb: process(execute_engine, decode_aux, fetch_engine, cmd_issue, trap_ctrl, csr, ctrl, csr_acc_valid,
|
execute_engine_fsm_comb: process(execute_engine, debug_ctrl, 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, excl_state_i)
|
alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i, excl_state_i)
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
begin
|
begin
|
-- arbiter defaults --
|
-- arbiter defaults --
|
execute_engine.state_nxt <= execute_engine.state;
|
execute_engine.state_nxt <= execute_engine.state;
|
Line 890... |
Line 951... |
|
|
-- trap environment control --
|
-- trap environment control --
|
trap_ctrl.env_start_ack <= '0';
|
trap_ctrl.env_start_ack <= '0';
|
trap_ctrl.env_end <= '0';
|
trap_ctrl.env_end <= '0';
|
|
|
|
-- leave debug mode --
|
|
debug_ctrl.dret <= '0';
|
|
|
-- exception trigger --
|
-- exception trigger --
|
trap_ctrl.instr_be <= '0';
|
trap_ctrl.instr_be <= '0';
|
trap_ctrl.instr_ma <= '0';
|
trap_ctrl.instr_ma <= '0';
|
trap_ctrl.env_call <= '0';
|
trap_ctrl.env_call <= '0';
|
trap_ctrl.break_point <= '0';
|
trap_ctrl.break_point <= '0';
|
Line 963... |
Line 1027... |
execute_engine.state_nxt <= EXECUTE;
|
execute_engine.state_nxt <= EXECUTE;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
|
|
when TRAP_ENTER => -- Start trap environment - get MTVEC, stay here for sleep mode
|
when TRAP_ENTER => -- Start trap environment - get TVEC, stay here for sleep mode
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (trap_ctrl.env_start = '1') then -- trap triggered?
|
if (trap_ctrl.env_start = '1') then -- trap triggered?
|
trap_ctrl.env_start_ack <= '1';
|
trap_ctrl.env_start_ack <= '1';
|
execute_engine.state_nxt <= TRAP_EXECUTE;
|
execute_engine.state_nxt <= TRAP_EXECUTE;
|
end if;
|
end if;
|
|
|
when TRAP_EXIT => -- Return from trap environment - get MEPC
|
when TRAP_EXIT => -- Return from trap environment - get EPC
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
trap_ctrl.env_end <= '1';
|
trap_ctrl.env_end <= '1';
|
execute_engine.state_nxt <= TRAP_EXECUTE;
|
execute_engine.state_nxt <= TRAP_EXECUTE;
|
|
|
when TRAP_EXECUTE => -- Start trap environment - jump to MTVEC / return from trap environment - jump to MEPC
|
when TRAP_EXECUTE => -- Start trap environment - jump to TVEC / return from trap environment - jump to EPC
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.pc_mux_sel <= '0'; -- next PC (csr.mtvec)
|
execute_engine.pc_mux_sel <= '0'; -- next PC (csr.mtvec)
|
fetch_engine.reset <= '1';
|
fetch_engine.reset <= '1';
|
execute_engine.pc_we <= '1';
|
execute_engine.pc_we <= '1';
|
execute_engine.sleep_nxt <= '0'; -- disable sleep mode
|
execute_engine.sleep_nxt <= '0'; -- disable sleep mode
|
Line 1041... |
Line 1105... |
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;
|
when others => ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c;
|
when others => ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c;
|
end case;
|
end case;
|
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')) or -- 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 (
|
((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_alu_c(5)) and (decode_aux.is_bitmanip_reg = '1')) or -- BITMANIP CP register operation?
|
Line 1142... |
Line 1206... |
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
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_mret_c => execute_engine.state_nxt <= TRAP_EXIT; -- MRET
|
when funct12_wfi_c => execute_engine.sleep_nxt <= '1'; -- WFI
|
when funct12_wfi_c =>
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) and (debug_ctrl.running = '1') then
|
|
NULL; -- just a NOP when in debug mode
|
|
else
|
|
execute_engine.sleep_nxt <= '1'; -- WFI (normal)
|
|
end if;
|
|
when funct12_dret_c => -- DRET
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
|
execute_engine.state_nxt <= TRAP_EXIT;
|
|
debug_ctrl.dret <= '1';
|
|
else
|
|
NULL;
|
|
end if;
|
when others => NULL;-- undefined
|
when others => NULL;-- undefined
|
end case;
|
end case;
|
|
|
|
|
when CSR_ACCESS => -- read & write status and control register (CSR)
|
when CSR_ACCESS => -- read & write status and control register (CSR)
|
Line 1279... |
Line 1355... |
-- Invalid Instruction / CSR access check
|
-- Invalid Instruction / CSR access check
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
-- CSR Access Check -----------------------------------------------------------------------
|
-- CSR Access Check -----------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
csr_access_check: process(execute_engine.i_reg, csr)
|
csr_access_check: process(execute_engine.i_reg, csr, debug_ctrl)
|
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(31 downto 0); -- max 29 HPM counters, plus 3 LSB-aligned dummy bits
|
variable csr_mcounteren_hpm_v : std_ulogic_vector(31 downto 0); -- max 29 HPM counters, plus 3 LSB-aligned dummy bits
|
begin
|
begin
|
-- is this CSR instruction really going to write to a CSR? --
|
-- is this CSR instruction really going to write to 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
|
Line 1415... |
Line 1491... |
|
|
-- 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_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 --
|
|
when csr_dcsr_c | csr_dpc_c | csr_dscratch0_c =>
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
|
csr_acc_valid <= debug_ctrl.running; -- DEBUG-mode only
|
|
else
|
|
NULL;
|
|
end if;
|
|
|
-- undefined / not implemented --
|
-- undefined / not implemented --
|
when others =>
|
when others =>
|
NULL; -- invalid access
|
NULL; -- invalid access
|
end case;
|
end case;
|
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)
|
illegal_instruction_check: process(execute_engine, decode_aux, 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 1445... |
Line 1529... |
|
|
-- 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
|
|
|
-- check sufficient LUI, UIPC, JAL (only check actual OPCODE) --
|
|
|
when opcode_lui_c | opcode_auipc_c | opcode_jal_c => -- check sufficient LUI, UIPC, JAL (only check actual OPCODE)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
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;
|
Line 1559... |
Line 1643... |
illegal_register <= '1';
|
illegal_register <= '1';
|
end if;
|
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) then -- FENCE.I -- NO trap if not implemented
|
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';
|
else
|
else
|
illegal_instruction <= '1';
|
illegal_instruction <= '1';
|
Line 1597... |
Line 1681... |
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) or -- MRET
|
|
((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
|
(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) then -- WFI
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
else
|
else
|
illegal_instruction <= '1';
|
illegal_instruction <= '1';
|
end if;
|
end if;
|
Line 1639... |
Line 1724... |
illegal_register <= '0';
|
illegal_register <= '0';
|
end if;
|
end if;
|
end process illegal_instruction_check;
|
end process illegal_instruction_check;
|
|
|
-- any illegal condition? --
|
-- any illegal condition? --
|
trap_ctrl.instr_il <= illegal_instruction or illegal_opcode_lsbs or illegal_register or illegal_compressed;
|
-- ignore illegal register condition in debug mode
|
|
trap_ctrl.instr_il <= illegal_instruction or illegal_opcode_lsbs or (illegal_register and (not debug_ctrl.running)) or illegal_compressed;
|
|
|
|
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
-- Exception and Interrupt (= Trap) Control
|
-- Exception and Interrupt (= Trap) Control
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
Line 1653... |
Line 1739... |
trap_controller: process(rstn_i, clk_i)
|
trap_controller: process(rstn_i, clk_i)
|
variable mode_m_v, mode_u_v : std_ulogic;
|
variable mode_m_v, mode_u_v : std_ulogic;
|
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
trap_ctrl.exc_buf <= (others => '0');
|
trap_ctrl.exc_buf <= (others => '0');
|
|
trap_ctrl.exc_buf(exception_db_break_c) <= '0'; -- enter debug mode
|
trap_ctrl.irq_buf <= (others => def_rst_val_c);
|
trap_ctrl.irq_buf <= (others => def_rst_val_c);
|
trap_ctrl.irq_buf(interrupt_nm_irq_c) <= '0'; -- NMI
|
trap_ctrl.irq_buf(interrupt_nm_irq_c) <= '0'; -- NMI
|
|
trap_ctrl.irq_buf(interrupt_db_halt_c) <= '0'; -- enter debug mode
|
|
trap_ctrl.irq_buf(interrupt_db_step_c) <= '0'; -- enter debug mode
|
trap_ctrl.exc_ack <= '0';
|
trap_ctrl.exc_ack <= '0';
|
trap_ctrl.irq_ack <= (others => '0');
|
trap_ctrl.irq_ack <= (others => '0');
|
trap_ctrl.env_start <= '0';
|
trap_ctrl.env_start <= '0';
|
trap_ctrl.cause <= (others => def_rst_val_c);
|
trap_ctrl.cause <= (others => def_rst_val_c);
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
|
|
-- exception buffer: misaligned load/store/instruction address
|
-- exception buffer: misaligned load/store/instruction address
|
trap_ctrl.exc_buf(exception_lalign_c) <= (trap_ctrl.exc_buf(exception_lalign_c) or ma_load_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_lalign_c) <= (trap_ctrl.exc_buf(exception_lalign_c) or ma_load_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_salign_c) <= (trap_ctrl.exc_buf(exception_salign_c) or ma_store_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_salign_c) <= (trap_ctrl.exc_buf(exception_salign_c) or ma_store_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_ialign_c) <= (trap_ctrl.exc_buf(exception_ialign_c) or trap_ctrl.instr_ma) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_ialign_c) <= (trap_ctrl.exc_buf(exception_ialign_c) or trap_ctrl.instr_ma) and (not trap_ctrl.exc_ack);
|
|
|
-- exception buffer: load/store/instruction bus access error
|
-- exception buffer: load/store/instruction bus access error
|
trap_ctrl.exc_buf(exception_laccess_c) <= (trap_ctrl.exc_buf(exception_laccess_c) or be_load_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_laccess_c) <= (trap_ctrl.exc_buf(exception_laccess_c) or be_load_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_saccess_c) <= (trap_ctrl.exc_buf(exception_saccess_c) or be_store_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_saccess_c) <= (trap_ctrl.exc_buf(exception_saccess_c) or be_store_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_iaccess_c) <= (trap_ctrl.exc_buf(exception_iaccess_c) or trap_ctrl.instr_be) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_iaccess_c) <= (trap_ctrl.exc_buf(exception_iaccess_c) or trap_ctrl.instr_be) and (not trap_ctrl.exc_ack);
|
|
|
-- exception buffer: illegal instruction / env call / break point
|
-- exception buffer: illegal instruction / env call / break point
|
trap_ctrl.exc_buf(exception_m_envcall_c) <= (trap_ctrl.exc_buf(exception_m_envcall_c) or (trap_ctrl.env_call and csr.priv_m_mode)) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_m_envcall_c) <= (trap_ctrl.exc_buf(exception_m_envcall_c) or (trap_ctrl.env_call and csr.priv_m_mode)) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_u_envcall_c) <= (trap_ctrl.exc_buf(exception_u_envcall_c) or (trap_ctrl.env_call and csr.priv_u_mode)) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_u_envcall_c) <= (trap_ctrl.exc_buf(exception_u_envcall_c) or (trap_ctrl.env_call and csr.priv_u_mode)) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_break_c) <= (trap_ctrl.exc_buf(exception_break_c) or trap_ctrl.break_point) and (not trap_ctrl.exc_ack);
|
|
trap_ctrl.exc_buf(exception_iillegal_c) <= (trap_ctrl.exc_buf(exception_iillegal_c) or trap_ctrl.instr_il) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_iillegal_c) <= (trap_ctrl.exc_buf(exception_iillegal_c) or trap_ctrl.instr_il) and (not trap_ctrl.exc_ack);
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
|
trap_ctrl.exc_buf(exception_break_c) <= (trap_ctrl.exc_buf(exception_break_c) or
|
|
(
|
|
(trap_ctrl.break_point and csr.priv_m_mode and (not csr.dcsr_ebreakm) and (not debug_ctrl.running)) or -- enable break to machine-trap-handler when in machine mode on "ebreak"
|
|
(trap_ctrl.break_point and csr.priv_u_mode and (not csr.dcsr_ebreaku) and (not debug_ctrl.running)) -- enable break to machine-trap-handler when in user mode on "ebreak"
|
|
)
|
|
) and (not trap_ctrl.exc_ack);
|
|
else
|
|
trap_ctrl.exc_buf(exception_break_c) <= (trap_ctrl.exc_buf(exception_break_c) or trap_ctrl.break_point) and (not trap_ctrl.exc_ack);
|
|
end if;
|
|
|
|
-- enter debug mode --
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
|
trap_ctrl.exc_buf(exception_db_break_c) <= (trap_ctrl.exc_buf(exception_db_break_c) or debug_ctrl.trig_break) and (not trap_ctrl.exc_ack);
|
|
trap_ctrl.irq_buf(interrupt_db_halt_c) <= (trap_ctrl.irq_buf(interrupt_db_halt_c) or debug_ctrl.trig_halt) and (not trap_ctrl.irq_ack(interrupt_db_halt_c));
|
|
trap_ctrl.irq_buf(interrupt_db_step_c) <= (trap_ctrl.irq_buf(interrupt_db_step_c) or debug_ctrl.trig_step) and (not trap_ctrl.irq_ack(interrupt_db_step_c));
|
|
else
|
|
trap_ctrl.exc_buf(exception_db_break_c) <= '0';
|
|
trap_ctrl.irq_buf(interrupt_db_halt_c) <= '0';
|
|
trap_ctrl.irq_buf(interrupt_db_step_c) <= '0';
|
|
end if;
|
|
|
-- interrupt buffer: non-maskable interrupt
|
-- interrupt buffer: non-maskable interrupt
|
trap_ctrl.irq_buf(interrupt_nm_irq_c) <= (trap_ctrl.irq_buf(interrupt_nm_irq_c) or nm_irq_i) and (not trap_ctrl.irq_ack(interrupt_nm_irq_c));
|
trap_ctrl.irq_buf(interrupt_nm_irq_c) <= (trap_ctrl.irq_buf(interrupt_nm_irq_c) or nm_irq_i) and (not trap_ctrl.irq_ack(interrupt_nm_irq_c));
|
-- interrupt buffer: machine software/external/timer interrupt
|
-- interrupt buffer: machine software/external/timer interrupt
|
trap_ctrl.irq_buf(interrupt_msw_irq_c) <= csr.mie_msie and (trap_ctrl.irq_buf(interrupt_msw_irq_c) or msw_irq_i) and (not trap_ctrl.irq_ack(interrupt_msw_irq_c));
|
trap_ctrl.irq_buf(interrupt_msw_irq_c) <= csr.mie_msie and (trap_ctrl.irq_buf(interrupt_msw_irq_c) or msw_irq_i) and (not trap_ctrl.irq_ack(interrupt_msw_irq_c));
|
trap_ctrl.irq_buf(interrupt_mext_irq_c) <= csr.mie_meie and (trap_ctrl.irq_buf(interrupt_mext_irq_c) or mext_irq_i) and (not trap_ctrl.irq_ack(interrupt_mext_irq_c));
|
trap_ctrl.irq_buf(interrupt_mext_irq_c) <= csr.mie_meie and (trap_ctrl.irq_buf(interrupt_mext_irq_c) or mext_irq_i) and (not trap_ctrl.irq_ack(interrupt_mext_irq_c));
|
trap_ctrl.irq_buf(interrupt_mtime_irq_c) <= csr.mie_mtie and (trap_ctrl.irq_buf(interrupt_mtime_irq_c) or mtime_irq_i) and (not trap_ctrl.irq_ack(interrupt_mtime_irq_c));
|
trap_ctrl.irq_buf(interrupt_mtime_irq_c) <= csr.mie_mtie and (trap_ctrl.irq_buf(interrupt_mtime_irq_c) or mtime_irq_i) and (not trap_ctrl.irq_ack(interrupt_mtime_irq_c));
|
-- interrupt buffer: NEORV32-specific fast interrupts
|
-- interrupt buffer: NEORV32-specific fast interrupts
|
for i in 0 to 15 loop
|
for i in 0 to 15 loop
|
trap_ctrl.irq_buf(interrupt_firq_0_c+i) <= csr.mie_firqe(i) and (trap_ctrl.irq_buf(interrupt_firq_0_c+i) or firq_i(i)) and (not trap_ctrl.irq_ack(interrupt_firq_0_c+i));
|
trap_ctrl.irq_buf(interrupt_firq_0_c+i) <= csr.mie_firqe(i) and (trap_ctrl.irq_buf(interrupt_firq_0_c+i) or firq_i(i)) and (not trap_ctrl.irq_ack(interrupt_firq_0_c+i));
|
end loop;
|
end loop;
|
|
|
-- trap control --
|
-- trap control --
|
if (trap_ctrl.env_start = '0') then -- no started trap handler
|
if (trap_ctrl.env_start = '0') then -- no started trap handler
|
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and -- trap triggered!
|
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and -- trap triggered!
|
((execute_engine.state = EXECUTE) or (execute_engine.state = TRAP_ENTER))) then -- fire IRQs in EXECUTE or TRAP state only to continue execution even on permanent IRQ
|
((execute_engine.state = EXECUTE) or (execute_engine.state = TRAP_ENTER))) then -- fire IRQs in EXECUTE or TRAP state only to continue execution even on permanent IRQ
|
trap_ctrl.cause <= trap_ctrl.cause_nxt; -- capture source ID for program (for mcause csr)
|
trap_ctrl.cause <= trap_ctrl.cause_nxt; -- capture source ID for program (for mcause csr)
|
Line 1706... |
Line 1820... |
end if;
|
end if;
|
end process trap_controller;
|
end process trap_controller;
|
|
|
-- any exception/interrupt? --
|
-- any exception/interrupt? --
|
trap_ctrl.exc_fire <= or_all_f(trap_ctrl.exc_buf); -- exceptions/faults CANNOT be masked
|
trap_ctrl.exc_fire <= or_all_f(trap_ctrl.exc_buf); -- exceptions/faults CANNOT be masked
|
trap_ctrl.irq_fire <= or_all_f(trap_ctrl.irq_buf) and csr.mstatus_mie; -- interrupts CAN be masked
|
trap_ctrl.irq_fire <= (or_all_f(trap_ctrl.irq_buf) and csr.mstatus_mie and trap_ctrl.db_irq_en) or trap_ctrl.db_irq_fire; -- interrupts CAN be masked
|
|
|
|
-- debug mode (entry) interrupts --
|
|
trap_ctrl.db_irq_en <= '1' when (CPU_EXTENSION_RISCV_DEBUG = false) else
|
|
'0' when (debug_ctrl.running = '1') else -- no interrupts when IN debug mode
|
|
csr.dcsr_stepie when (csr.dcsr_step = '1') else '1'; -- allow IRQ in single-step mode when dcsr.stepie is set
|
|
trap_ctrl.db_irq_fire <= (trap_ctrl.irq_buf(interrupt_db_step_c) or trap_ctrl.irq_buf(interrupt_db_halt_c)) when (CPU_EXTENSION_RISCV_DEBUG = true) else '0'; -- "NMI" for debug mode entry
|
|
|
-- acknowledge mask output --
|
-- acknowledge mask output --
|
firq_ack_o <= trap_ctrl.irq_ack(interrupt_firq_15_c downto interrupt_firq_0_c);
|
firq_ack_o <= trap_ctrl.irq_ack(interrupt_firq_15_c downto interrupt_firq_0_c);
|
|
|
|
|
-- Trap Priority Encoder ------------------------------------------------------------------
|
-- Trap Priority Encoder ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
trap_priority: process(trap_ctrl)
|
trap_priority: process(trap_ctrl)
|
begin
|
begin
|
-- defaults --
|
-- defaults --
|
trap_ctrl.cause_nxt <= (others => '-');
|
trap_ctrl.cause_nxt <= (others => '0');
|
trap_ctrl.irq_ack_nxt <= (others => '0');
|
trap_ctrl.irq_ack_nxt <= (others => '0');
|
|
|
-- ----------------------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------------------
|
|
-- enter debug mode requests; basically, these are standard interrupt that have some
|
|
-- special handling - they have the highest priority in order to go to debug when requested
|
|
-- even if other traps are pending right now; the <trap_ctrl.cause_nxt> value will be
|
|
-- written to csr.dcsr_cause instead of mcause
|
|
-- ----------------------------------------------------------------------------------------
|
|
|
|
-- break instruction --
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) and (trap_ctrl.exc_buf(exception_db_break_c) = '1') then
|
|
trap_ctrl.cause_nxt <= trap_db_break_c;
|
|
|
|
-- external halt request --
|
|
elsif (CPU_EXTENSION_RISCV_DEBUG = true) and (trap_ctrl.irq_buf(interrupt_db_halt_c) = '1') then
|
|
trap_ctrl.cause_nxt <= trap_db_halt_c;
|
|
trap_ctrl.irq_ack_nxt(interrupt_db_halt_c) <= '1';
|
|
|
|
|
|
-- ----------------------------------------------------------------------------------------
|
-- the following traps are caused by *asynchronous* exceptions (= interrupts)
|
-- the following traps are caused by *asynchronous* exceptions (= interrupts)
|
-- here we do need a specific acknowledge mask since several sources can trigger at once
|
-- here we do need a specific acknowledge mask since several sources can trigger at once
|
-- ----------------------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------------------
|
|
|
-- interrupt: 1.0 non-maskable interrupt --
|
-- interrupt: 1.0 non-maskable interrupt --
|
if (trap_ctrl.irq_buf(interrupt_nm_irq_c) = '1') then
|
elsif (trap_ctrl.irq_buf(interrupt_nm_irq_c) = '1') then
|
trap_ctrl.cause_nxt <= trap_nmi_c;
|
trap_ctrl.cause_nxt <= trap_nmi_c;
|
trap_ctrl.irq_ack_nxt(interrupt_nm_irq_c) <= '1';
|
trap_ctrl.irq_ack_nxt(interrupt_nm_irq_c) <= '1';
|
|
|
|
|
-- interrupt: 1.11 machine external interrupt --
|
-- interrupt: 1.11 machine external interrupt --
|
Line 1875... |
Line 2012... |
trap_ctrl.cause_nxt <= trap_sbe_c;
|
trap_ctrl.cause_nxt <= trap_sbe_c;
|
|
|
-- exception: 0.5 load access fault --
|
-- exception: 0.5 load access fault --
|
elsif (trap_ctrl.exc_buf(exception_laccess_c) = '1') then
|
elsif (trap_ctrl.exc_buf(exception_laccess_c) = '1') then
|
trap_ctrl.cause_nxt <= trap_lbe_c;
|
trap_ctrl.cause_nxt <= trap_lbe_c;
|
|
|
|
|
|
-- ----------------------------------------------------------------------------------------
|
|
-- re-enter debug mode during single-stepping; this debug mode entry trap has the lowest
|
|
-- priority to let "normal" traps kick in during single stepping
|
|
-- ----------------------------------------------------------------------------------------
|
|
|
|
-- single stepping --
|
|
elsif (CPU_EXTENSION_RISCV_DEBUG = true) and (trap_ctrl.irq_buf(interrupt_db_step_c) = '1') then
|
|
trap_ctrl.cause_nxt <= trap_db_step_c;
|
|
trap_ctrl.irq_ack_nxt(interrupt_db_step_c) <= '1';
|
end if;
|
end if;
|
end process trap_priority;
|
end process trap_priority;
|
|
|
|
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
Line 1908... |
Line 2056... |
|
|
-- Control and Status Registers - Write Access --------------------------------------------
|
-- Control and Status Registers - Write Access --------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
csr_write_access: process(rstn_i, clk_i)
|
csr_write_access: process(rstn_i, clk_i)
|
begin
|
begin
|
-- NOTE: Register that reset to "def_rst_val_c" do NOT actually have a real reset by default (def_rst_val_c = '-') and have to be
|
-- NOTE: If <dedicated_reset_c> = true then <def_rst_val_c> evaluates to '-'. Register that reset to <def_rst_val_c> do
|
-- explicitly initialized by software!
|
-- NOT actually have a real reset by default (def_rst_val_c = '-') and have to be explicitly initialized by software!
|
-- 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';
|
Line 1944... |
Line 2092... |
csr.mcountinhibit_ir <= def_rst_val_c;
|
csr.mcountinhibit_ir <= def_rst_val_c;
|
csr.mcountinhibit_hpm <= (others => def_rst_val_c);
|
csr.mcountinhibit_hpm <= (others => def_rst_val_c);
|
--
|
--
|
csr.fflags <= (others => def_rst_val_c);
|
csr.fflags <= (others => def_rst_val_c);
|
csr.frm <= (others => def_rst_val_c);
|
csr.frm <= (others => def_rst_val_c);
|
|
--
|
|
csr.dcsr_ebreakm <= '0';
|
|
csr.dcsr_ebreaku <= '0';
|
|
csr.dcsr_step <= '0';
|
|
csr.dcsr_stepie <= '0';
|
|
csr.dcsr_prv <= (others => def_rst_val_c);
|
|
csr.dcsr_cause <= (others => def_rst_val_c);
|
|
csr.dpc <= (others => def_rst_val_c);
|
|
csr.dscratch0 <= (others => def_rst_val_c);
|
|
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
-- write access? --
|
-- write access? --
|
csr.we <= csr.we_nxt;
|
csr.we <= csr.we_nxt;
|
|
|
Line 1974... |
Line 2131... |
end if;
|
end if;
|
end if;
|
end if;
|
|
|
-- machine trap setup --
|
-- machine trap setup --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
if (csr.addr(11 downto 4) = csr_class_setup_c) then -- ftrap setup CSR class
|
if (csr.addr(11 downto 4) = csr_class_setup_c) then -- trap setup CSR class
|
-- R/W: mstatus - machine status register --
|
-- R/W: mstatus - machine status register --
|
if (csr.addr(3 downto 0) = csr_mstatus_c(3 downto 0)) then
|
if (csr.addr(3 downto 0) = csr_mstatus_c(3 downto 0)) then
|
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
|
Line 2087... |
Line 2244... |
csr.mhpmevent(i)(hpmcnt_event_never_c) <= '0'; -- would be used for "TIME"
|
csr.mhpmevent(i)(hpmcnt_event_never_c) <= '0'; -- would be used for "TIME"
|
end loop; -- i (CSRs)
|
end loop; -- i (CSRs)
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
|
-- debug mode CSRs --
|
|
-- --------------------------------------------------------------------
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
|
if (csr.addr(11 downto 2) = csr_class_debug_c) then -- debug CSR class
|
|
-- R/W: dcsr - debug mode control and status register --
|
|
if (csr.addr(1 downto 0) = csr_dcsr_c(1 downto 0)) then
|
|
csr.dcsr_ebreakm <= csr.wdata(15);
|
|
csr.dcsr_stepie <= csr.wdata(2);
|
|
csr.dcsr_step <= csr.wdata(2);
|
|
if (CPU_EXTENSION_RISCV_U = true) then -- user mode implemented
|
|
csr.dcsr_ebreaku <= csr.wdata(12);
|
|
csr.dcsr_prv(0) <= csr.wdata(1) or csr.wdata(0);
|
|
csr.dcsr_prv(1) <= csr.wdata(1) or csr.wdata(0);
|
|
else -- only machine mode is available
|
|
csr.dcsr_prv <= priv_mode_m_c;
|
|
end if;
|
|
end if;
|
|
-- R/W: dpc - debug mode program counter --
|
|
if (csr.addr(1 downto 0) = csr_dpc_c(1 downto 0)) then
|
|
csr.dpc <= csr.wdata;
|
|
end if;
|
|
-- R/W: dscratch0 - debug mode scratch register 0 --
|
|
if (csr.addr(1 downto 0) = csr_dscratch0_c(1 downto 0)) then
|
|
csr.dscratch0 <= csr.wdata;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
|
-- --------------------------------------------------------------------------------
|
-- --------------------------------------------------------------------------------
|
-- CSR access by hardware
|
-- CSR access by hardware
|
-- --------------------------------------------------------------------------------
|
-- --------------------------------------------------------------------------------
|
else
|
else
|
Line 2099... |
Line 2284... |
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then
|
csr.fflags <= csr.fflags or fpu_flags_i; -- accumulate flags ("accrued exception flags")
|
csr.fflags <= csr.fflags or fpu_flags_i; -- accumulate flags ("accrued exception flags")
|
end if;
|
end if;
|
|
|
-- mcause, mepc, mtval: machine trap cause, PC and value register --
|
-- mcause, mepc, mtval: write machine trap cause, PC and trap value register --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
|
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
|
|
if (CPU_EXTENSION_RISCV_DEBUG = false) or ((trap_ctrl.cause(5) = '0') and -- update mtval/mepc/mcause only when NOT ENTRY debug mode exception
|
|
(debug_ctrl.running = '0')) then -- and NOT IN debug mode
|
|
|
-- trap cause ID code --
|
-- trap cause ID code --
|
csr.mcause(csr.mcause'left) <= trap_ctrl.cause(trap_ctrl.cause'left); -- 1: interrupt, 0: exception
|
csr.mcause(csr.mcause'left) <= trap_ctrl.cause(trap_ctrl.cause'left); -- 1: interrupt, 0: exception
|
csr.mcause(4 downto 0) <= trap_ctrl.cause(4 downto 0); -- identifier
|
csr.mcause(4 downto 0) <= trap_ctrl.cause(4 downto 0); -- identifier
|
|
|
-- trap PC --
|
-- trap PC --
|
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS
|
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS (async source)
|
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
|
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
|
else -- for sync. EXCEPTIONS
|
else -- for sync. EXCEPTIONS (sync source)
|
csr.mepc <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- this is the LAST pc = last executed instruction
|
csr.mepc <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- this is the LAST pc = last executed instruction
|
end if;
|
end if;
|
|
|
-- trap value --
|
-- trap value --
|
case trap_ctrl.cause is
|
case trap_ctrl.cause is
|
when trap_ima_c | trap_iba_c => -- misaligned instruction address OR instruction access error
|
when trap_ima_c | trap_iba_c => -- misaligned instruction address OR instruction access error
|
csr.mtval <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- address of faulting instruction
|
csr.mtval <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- address of faulting instruction
|
when trap_brk_c => -- breakpoint
|
when trap_brk_c => -- breakpoint
|
Line 2124... |
Line 2314... |
when trap_iil_c => -- illegal instruction
|
when trap_iil_c => -- illegal instruction
|
csr.mtval <= execute_engine.i_reg_last; -- faulting instruction itself
|
csr.mtval <= execute_engine.i_reg_last; -- faulting instruction itself
|
when others => -- everything else including all interrupts
|
when others => -- everything else including all interrupts
|
csr.mtval <= (others => '0');
|
csr.mtval <= (others => '0');
|
end case;
|
end case;
|
|
|
|
end if;
|
|
|
|
-- trap enter: write dpc and dcsr --
|
|
-- --------------------------------------------------------------------
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) and (trap_ctrl.cause(5) = '1') and (debug_ctrl.running = '0') then -- debug mode entry exception
|
|
|
|
-- trap cause ID code --
|
|
csr.dcsr_cause <= trap_ctrl.cause(2 downto 0); -- why did we enter debug mode?
|
|
-- current privilege mode when debug mode was entered --
|
|
csr.dcsr_prv <= csr.privilege;
|
|
|
|
-- trap PC --
|
|
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS (async source)
|
|
csr.dpc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
|
|
else -- for sync. EXCEPTIONS (sync source)
|
|
csr.dpc <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- this is the LAST pc = last executed instruction
|
|
end if;
|
|
|
|
end if;
|
|
|
end if;
|
end if;
|
|
|
-- mstatus: context switch --
|
-- mstatus: context switch --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
if (trap_ctrl.env_start_ack = '1') then -- ENTER: trap handler starting?
|
-- ENTER: trap handling starting?
|
|
if (trap_ctrl.env_start_ack = '1') then
|
|
if (CPU_EXTENSION_RISCV_DEBUG = false) or -- normal trapping (debug mode NOT implemented)
|
|
((debug_ctrl.running = '0') and (trap_ctrl.cause(5) = '0')) then -- not IN debug mode and not ENTERING debug mode
|
csr.mstatus_mie <= '0'; -- disable interrupts
|
csr.mstatus_mie <= '0'; -- disable interrupts
|
csr.mstatus_mpie <= csr.mstatus_mie; -- buffer previous mie state
|
csr.mstatus_mpie <= csr.mstatus_mie; -- buffer previous mie state
|
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
|
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
|
csr.privilege <= priv_mode_m_c; -- execute trap in machine mode
|
csr.privilege <= priv_mode_m_c; -- execute trap in machine mode
|
csr.mstatus_mpp <= csr.privilege; -- buffer previous privilege mode
|
csr.mstatus_mpp <= csr.privilege; -- buffer previous privilege mode
|
end if;
|
end if;
|
elsif (trap_ctrl.env_end = '1') then -- EXIT: return from exception
|
end if;
|
|
|
|
-- EXIT: return from exception
|
|
elsif (trap_ctrl.env_end = '1') then
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) and (debug_ctrl.running = '1') then -- return from debug mode
|
|
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
|
|
csr.privilege <= csr.dcsr_prv;
|
|
end if;
|
|
else -- return from "normal trap"
|
csr.mstatus_mie <= csr.mstatus_mpie; -- restore global IRQ enable flag
|
csr.mstatus_mie <= csr.mstatus_mpie; -- restore global IRQ enable flag
|
csr.mstatus_mpie <= '1';
|
csr.mstatus_mpie <= '1';
|
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
|
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
|
csr.privilege <= csr.mstatus_mpp; -- go back to previous privilege mode
|
csr.privilege <= csr.mstatus_mpp; -- go back to previous privilege mode
|
csr.mstatus_mpp <= priv_mode_m_c;
|
csr.mstatus_mpp <= priv_mode_m_c;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
end if;
|
|
|
-- user mode NOT implemented --
|
-- user mode NOT implemented --
|
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;
|
end if;
|
end if;
|
Line 2164... |
Line 2388... |
csr.mstatus_mpp <= priv_mode_m_c;
|
csr.mstatus_mpp <= priv_mode_m_c;
|
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.mcounteren_hpm <= (others => '0');
|
csr.mcounteren_hpm <= (others => '0');
|
|
csr.dcsr_ebreaku <= '0';
|
end if;
|
end if;
|
|
|
-- pmp disabled --
|
-- pmp disabled --
|
if (PMP_NUM_REGIONS = 0) then
|
if (PMP_NUM_REGIONS = 0) then
|
csr.pmpcfg <= (others => (others => '0'));
|
csr.pmpcfg <= (others => (others => '0'));
|
Line 2193... |
Line 2418... |
if (CPU_EXTENSION_RISCV_Zfinx = false) then
|
if (CPU_EXTENSION_RISCV_Zfinx = false) then
|
csr.fflags <= (others => '0');
|
csr.fflags <= (others => '0');
|
csr.frm <= (others => '0');
|
csr.frm <= (others => '0');
|
end if;
|
end if;
|
|
|
|
-- debug mode disabled --
|
|
if (CPU_EXTENSION_RISCV_DEBUG = false) then
|
|
csr.dcsr_ebreakm <= '0';
|
|
csr.dcsr_ebreaku <= '0';
|
|
csr.dcsr_step <= '0';
|
|
csr.dcsr_stepie <= '0';
|
|
csr.dcsr_prv <= (others => '0');
|
|
csr.dcsr_cause <= (others => '0');
|
|
csr.dpc <= (others => '0');
|
|
csr.dscratch0 <= (others => '0');
|
|
end if;
|
|
|
end if;
|
end if;
|
end process csr_write_access;
|
end process csr_write_access;
|
|
|
-- decode current privilege mode --
|
-- decode current privilege mode --
|
csr.priv_m_mode <= '1' when (csr.privilege = priv_mode_m_c) else '0';
|
csr.privilege_rd <= priv_mode_m_c when (CPU_EXTENSION_RISCV_E) and (debug_ctrl.running = '1') else csr.privilege; -- effective privilege mode ("machine" when in debug mode)
|
csr.priv_u_mode <= '1' when (csr.privilege = priv_mode_u_c) else '0';
|
csr.priv_m_mode <= '1' when (csr.privilege_rd = priv_mode_m_c) else '0';
|
|
csr.priv_u_mode <= '1' when (csr.privilege_rd = priv_mode_u_c) and (CPU_EXTENSION_RISCV_U = true) else '0';
|
|
|
-- PMP configuration output to bus unit --
|
-- PMP configuration output to bus unit --
|
pmp_output: process(csr)
|
pmp_output: process(csr)
|
begin
|
begin
|
pmp_addr_o <= (others => (others => '0'));
|
pmp_addr_o <= (others => (others => '0'));
|
Line 2402... |
Line 2640... |
if (CPU_EXTENSION_RISCV_Zicsr = true) and (csr.re = '1') then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) and (csr.re = '1') then
|
case csr.addr is
|
case csr.addr is
|
|
|
-- floating-point CSRs --
|
-- floating-point CSRs --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_fflags_c => -- R/W: fflags - floating-point (FPU) exception flags
|
when csr_fflags_c => -- fflags (r/w): floating-point (FPU) exception flags
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then -- FPU implemented
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then csr.rdata(4 downto 0) <= csr.fflags; else NULL; end if;
|
csr.rdata(4 downto 0) <= csr.fflags;
|
when csr_frm_c => -- frm (r/w): floating-point (FPU) rounding mode
|
else
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then csr.rdata(2 downto 0) <= csr.frm; else NULL; end if;
|
NULL;
|
when csr_fcsr_c => -- fcsr (r/w): floating-point (FPU) control/status (frm + fflags)
|
end if;
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then csr.rdata(7 downto 5) <= csr.frm; csr.rdata(4 downto 0) <= csr.fflags; else NULL; end if;
|
when csr_frm_c => -- R/W: frm - floating-point (FPU) rounding mode
|
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then -- FPU implemented
|
|
csr.rdata(2 downto 0) <= csr.frm;
|
|
else
|
|
NULL;
|
|
end if;
|
|
when csr_fcsr_c => -- R/W: fcsr - floating-point (FPU) control/status (frm + fflags)
|
|
if (CPU_EXTENSION_RISCV_Zfinx = true) then -- FPU implemented
|
|
csr.rdata(7 downto 5) <= csr.frm;
|
|
csr.rdata(4 downto 0) <= csr.fflags;
|
|
else
|
|
NULL;
|
|
end if;
|
|
|
|
-- machine trap setup --
|
-- machine trap setup --
|
when csr_mstatus_c => -- R/W: mstatus - 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(06) <= '1' and bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- UBE: CPU/Processor is BIG-ENDIAN (in user-mode)
|
csr.rdata(06) <= '1' and bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- UBE: CPU/Processor is BIG-ENDIAN (in user-mode)
|
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
|
when csr_mstatush_c => -- R/-: mstatush - machine status register - high part
|
when csr_mstatush_c => -- mstatush (r/-): 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 => -- 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(01) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- B 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
|
csr.rdata(23) <= '1'; -- X CPU extension (non-std extensions)
|
csr.rdata(23) <= '1'; -- X CPU extension (non-std extensions)
|
csr.rdata(30) <= '1'; -- 32-bit architecture (MXL lo)
|
csr.rdata(30) <= '1'; -- 32-bit architecture (MXL lo)
|
csr.rdata(31) <= '0'; -- 32-bit architecture (MXL hi)
|
csr.rdata(31) <= '0'; -- 32-bit architecture (MXL hi)
|
when csr_mie_c => -- R/W: mie - machine interrupt-enable register
|
when csr_mie_c => -- mie (r/w): machine interrupt-enable register
|
csr.rdata(03) <= csr.mie_msie; -- machine software IRQ enable
|
csr.rdata(03) <= csr.mie_msie; -- machine software IRQ enable
|
csr.rdata(07) <= csr.mie_mtie; -- machine timer IRQ enable
|
csr.rdata(07) <= csr.mie_mtie; -- machine timer IRQ enable
|
csr.rdata(11) <= csr.mie_meie; -- machine external IRQ enable
|
csr.rdata(11) <= csr.mie_meie; -- machine external IRQ enable
|
for i in 0 to 15 loop -- fast interrupt channels 0..15 enable
|
for i in 0 to 15 loop -- fast interrupt channels 0..15 enable
|
csr.rdata(16+i) <= csr.mie_firqe(i);
|
csr.rdata(16+i) <= csr.mie_firqe(i);
|
end loop; -- i
|
end loop; -- i
|
when csr_mtvec_c => -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
|
when csr_mtvec_c => -- mtvec (r/w): machine trap-handler base address (for ALL exceptions)
|
csr.rdata <= csr.mtvec(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
|
csr.rdata <= csr.mtvec(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
|
when csr_mcounteren_c => -- R/W: machine counter enable register
|
when csr_mcounteren_c => -- mcounteren (r/w): machine counter enable register
|
if (CPU_EXTENSION_RISCV_U = false) then -- this CSR is hardwired to zero if user mode is not implemented
|
if (CPU_EXTENSION_RISCV_U = false) then -- this CSR is hardwired to zero if user mode is not implemented
|
NULL;
|
NULL;
|
else
|
else
|
csr.rdata(0) <= csr.mcounteren_cy; -- enable user-level access to cycle[h]
|
csr.rdata(0) <= csr.mcounteren_cy; -- enable user-level access to cycle[h]
|
csr.rdata(1) <= csr.mcounteren_tm; -- enable user-level access to time[h]
|
csr.rdata(1) <= csr.mcounteren_tm; -- enable user-level access to time[h]
|
csr.rdata(2) <= csr.mcounteren_ir; -- enable user-level access to instret[h]
|
csr.rdata(2) <= csr.mcounteren_ir; -- enable user-level access to instret[h]
|
csr.rdata(csr.mcounteren_hpm'left+3 downto 3) <= csr.mcounteren_hpm; -- enable user-level access to hpmcounterx[h]
|
csr.rdata(csr.mcounteren_hpm'left+3 downto 3) <= csr.mcounteren_hpm; -- enable user-level access to hpmcounterx[h]
|
end if;
|
end if;
|
|
|
-- machine trap handling --
|
-- machine trap handling --
|
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
|
-- --------------------------------------------------------------------
|
|
when csr_mscratch_c => -- mscratch (r/w): machine scratch register
|
csr.rdata <= csr.mscratch;
|
csr.rdata <= csr.mscratch;
|
when csr_mepc_c => -- R/W: mepc - 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 => -- R/W: mcause - 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 => -- R/W: mtval - machine bad address or instruction
|
when csr_mtval_c => -- mtval (r/w): machine bad address or instruction
|
csr.rdata <= csr.mtval;
|
csr.rdata <= csr.mtval;
|
when csr_mip_c => -- R/-: mip - 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);
|
for i in 0 to 15 loop -- fast interrupt channels 0..15 pending
|
for i in 0 to 15 loop -- fast interrupt channels 0..15 pending
|
csr.rdata(16+i) <= trap_ctrl.irq_buf(interrupt_firq_0_c+i);
|
csr.rdata(16+i) <= trap_ctrl.irq_buf(interrupt_firq_0_c+i);
|
end loop; -- i
|
end loop; -- i
|
|
|
-- physical memory protection - configuration --
|
-- physical memory protection - configuration --
|
|
-- --------------------------------------------------------------------
|
when csr_pmpcfg0_c => if (PMP_NUM_REGIONS > 00) then csr.rdata <= csr.pmpcfg_rd(03) & csr.pmpcfg_rd(02) & csr.pmpcfg_rd(01) & csr.pmpcfg_rd(00); else NULL; end if; -- R/W: pmpcfg0
|
when csr_pmpcfg0_c => if (PMP_NUM_REGIONS > 00) then csr.rdata <= csr.pmpcfg_rd(03) & csr.pmpcfg_rd(02) & csr.pmpcfg_rd(01) & csr.pmpcfg_rd(00); else NULL; end if; -- R/W: pmpcfg0
|
when csr_pmpcfg1_c => if (PMP_NUM_REGIONS > 03) then csr.rdata <= csr.pmpcfg_rd(07) & csr.pmpcfg_rd(06) & csr.pmpcfg_rd(05) & csr.pmpcfg_rd(04); else NULL; end if; -- R/W: pmpcfg1
|
when csr_pmpcfg1_c => if (PMP_NUM_REGIONS > 03) then csr.rdata <= csr.pmpcfg_rd(07) & csr.pmpcfg_rd(06) & csr.pmpcfg_rd(05) & csr.pmpcfg_rd(04); else NULL; end if; -- R/W: pmpcfg1
|
when csr_pmpcfg2_c => if (PMP_NUM_REGIONS > 07) then csr.rdata <= csr.pmpcfg_rd(11) & csr.pmpcfg_rd(10) & csr.pmpcfg_rd(09) & csr.pmpcfg_rd(08); else NULL; end if; -- R/W: pmpcfg2
|
when csr_pmpcfg2_c => if (PMP_NUM_REGIONS > 07) then csr.rdata <= csr.pmpcfg_rd(11) & csr.pmpcfg_rd(10) & csr.pmpcfg_rd(09) & csr.pmpcfg_rd(08); else NULL; end if; -- R/W: pmpcfg2
|
when csr_pmpcfg3_c => if (PMP_NUM_REGIONS > 11) then csr.rdata <= csr.pmpcfg_rd(15) & csr.pmpcfg_rd(14) & csr.pmpcfg_rd(13) & csr.pmpcfg_rd(12); else NULL; end if; -- R/W: pmpcfg3
|
when csr_pmpcfg3_c => if (PMP_NUM_REGIONS > 11) then csr.rdata <= csr.pmpcfg_rd(15) & csr.pmpcfg_rd(14) & csr.pmpcfg_rd(13) & csr.pmpcfg_rd(12); else NULL; end if; -- R/W: pmpcfg3
|
when csr_pmpcfg4_c => if (PMP_NUM_REGIONS > 15) then csr.rdata <= csr.pmpcfg_rd(19) & csr.pmpcfg_rd(18) & csr.pmpcfg_rd(17) & csr.pmpcfg_rd(16); else NULL; end if; -- R/W: pmpcfg4
|
when csr_pmpcfg4_c => if (PMP_NUM_REGIONS > 15) then csr.rdata <= csr.pmpcfg_rd(19) & csr.pmpcfg_rd(18) & csr.pmpcfg_rd(17) & csr.pmpcfg_rd(16); else NULL; end if; -- R/W: pmpcfg4
|
Line 2498... |
Line 2726... |
when csr_pmpcfg13_c => if (PMP_NUM_REGIONS > 51) then csr.rdata <= csr.pmpcfg_rd(55) & csr.pmpcfg_rd(54) & csr.pmpcfg_rd(53) & csr.pmpcfg_rd(52); else NULL; end if; -- R/W: pmpcfg13
|
when csr_pmpcfg13_c => if (PMP_NUM_REGIONS > 51) then csr.rdata <= csr.pmpcfg_rd(55) & csr.pmpcfg_rd(54) & csr.pmpcfg_rd(53) & csr.pmpcfg_rd(52); else NULL; end if; -- R/W: pmpcfg13
|
when csr_pmpcfg14_c => if (PMP_NUM_REGIONS > 55) then csr.rdata <= csr.pmpcfg_rd(59) & csr.pmpcfg_rd(58) & csr.pmpcfg_rd(57) & csr.pmpcfg_rd(56); else NULL; end if; -- R/W: pmpcfg14
|
when csr_pmpcfg14_c => if (PMP_NUM_REGIONS > 55) then csr.rdata <= csr.pmpcfg_rd(59) & csr.pmpcfg_rd(58) & csr.pmpcfg_rd(57) & csr.pmpcfg_rd(56); else NULL; end if; -- R/W: pmpcfg14
|
when csr_pmpcfg15_c => if (PMP_NUM_REGIONS > 59) then csr.rdata <= csr.pmpcfg_rd(63) & csr.pmpcfg_rd(62) & csr.pmpcfg_rd(61) & csr.pmpcfg_rd(60); else NULL; end if; -- R/W: pmpcfg15
|
when csr_pmpcfg15_c => if (PMP_NUM_REGIONS > 59) then csr.rdata <= csr.pmpcfg_rd(63) & csr.pmpcfg_rd(62) & csr.pmpcfg_rd(61) & csr.pmpcfg_rd(60); else NULL; end if; -- R/W: pmpcfg15
|
|
|
-- physical memory protection - addresses --
|
-- physical memory protection - addresses --
|
|
-- --------------------------------------------------------------------
|
when csr_pmpaddr0_c => if (PMP_NUM_REGIONS > 00) then csr.rdata <= csr.pmpaddr(00); else NULL; end if; -- R/W: pmpaddr0
|
when csr_pmpaddr0_c => if (PMP_NUM_REGIONS > 00) then csr.rdata <= csr.pmpaddr(00); else NULL; end if; -- R/W: pmpaddr0
|
when csr_pmpaddr1_c => if (PMP_NUM_REGIONS > 01) then csr.rdata <= csr.pmpaddr(01); else NULL; end if; -- R/W: pmpaddr1
|
when csr_pmpaddr1_c => if (PMP_NUM_REGIONS > 01) then csr.rdata <= csr.pmpaddr(01); else NULL; end if; -- R/W: pmpaddr1
|
when csr_pmpaddr2_c => if (PMP_NUM_REGIONS > 02) then csr.rdata <= csr.pmpaddr(02); else NULL; end if; -- R/W: pmpaddr2
|
when csr_pmpaddr2_c => if (PMP_NUM_REGIONS > 02) then csr.rdata <= csr.pmpaddr(02); else NULL; end if; -- R/W: pmpaddr2
|
when csr_pmpaddr3_c => if (PMP_NUM_REGIONS > 03) then csr.rdata <= csr.pmpaddr(03); else NULL; end if; -- R/W: pmpaddr3
|
when csr_pmpaddr3_c => if (PMP_NUM_REGIONS > 03) then csr.rdata <= csr.pmpaddr(03); else NULL; end if; -- R/W: pmpaddr3
|
when csr_pmpaddr4_c => if (PMP_NUM_REGIONS > 04) then csr.rdata <= csr.pmpaddr(04); else NULL; end if; -- R/W: pmpaddr4
|
when csr_pmpaddr4_c => if (PMP_NUM_REGIONS > 04) then csr.rdata <= csr.pmpaddr(04); else NULL; end if; -- R/W: pmpaddr4
|
Line 2565... |
Line 2794... |
when csr_pmpaddr62_c => if (PMP_NUM_REGIONS > 62) then csr.rdata <= csr.pmpaddr(62); else NULL; end if; -- R/W: pmpaddr62
|
when csr_pmpaddr62_c => if (PMP_NUM_REGIONS > 62) then csr.rdata <= csr.pmpaddr(62); else NULL; end if; -- R/W: pmpaddr62
|
when csr_pmpaddr63_c => if (PMP_NUM_REGIONS > 63) then csr.rdata <= csr.pmpaddr(63); else NULL; end if; -- R/W: pmpaddr63
|
when csr_pmpaddr63_c => if (PMP_NUM_REGIONS > 63) then csr.rdata <= csr.pmpaddr(63); else NULL; end if; -- R/W: pmpaddr63
|
|
|
-- machine counter setup --
|
-- machine counter setup --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_mcountinhibit_c => -- R/W: mcountinhibit - machine counter-inhibit register
|
when csr_mcountinhibit_c => -- mcountinhibit (r/w): machine counter-inhibit register
|
csr.rdata(0) <= csr.mcountinhibit_cy; -- enable auto-increment of [m]cycle[h] counter
|
csr.rdata(0) <= csr.mcountinhibit_cy; -- enable auto-increment of [m]cycle[h] counter
|
csr.rdata(2) <= csr.mcountinhibit_ir; -- enable auto-increment of [m]instret[h] counter
|
csr.rdata(2) <= csr.mcountinhibit_ir; -- enable auto-increment of [m]instret[h] counter
|
csr.rdata(csr.mcountinhibit_hpm'left+3 downto 3) <= csr.mcountinhibit_hpm; -- enable auto-increment of [m]hpmcounterx[h] counter
|
csr.rdata(csr.mcountinhibit_hpm'left+3 downto 3) <= csr.mcountinhibit_hpm; -- enable auto-increment of [m]hpmcounterx[h] counter
|
|
|
-- machine performance-monitoring event selector --
|
-- machine performance-monitoring event selector --
|
|
-- --------------------------------------------------------------------
|
when csr_mhpmevent3_c => if (HPM_NUM_CNTS > 00) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(00); else NULL; end if; -- R/W: mhpmevent3
|
when csr_mhpmevent3_c => if (HPM_NUM_CNTS > 00) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(00); else NULL; end if; -- R/W: mhpmevent3
|
when csr_mhpmevent4_c => if (HPM_NUM_CNTS > 01) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(01); else NULL; end if; -- R/W: mhpmevent4
|
when csr_mhpmevent4_c => if (HPM_NUM_CNTS > 01) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(01); else NULL; end if; -- R/W: mhpmevent4
|
when csr_mhpmevent5_c => if (HPM_NUM_CNTS > 02) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(02); else NULL; end if; -- R/W: mhpmevent5
|
when csr_mhpmevent5_c => if (HPM_NUM_CNTS > 02) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(02); else NULL; end if; -- R/W: mhpmevent5
|
when csr_mhpmevent6_c => if (HPM_NUM_CNTS > 03) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(03); else NULL; end if; -- R/W: mhpmevent6
|
when csr_mhpmevent6_c => if (HPM_NUM_CNTS > 03) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(03); else NULL; end if; -- R/W: mhpmevent6
|
when csr_mhpmevent7_c => if (HPM_NUM_CNTS > 04) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(04); else NULL; end if; -- R/W: mhpmevent7
|
when csr_mhpmevent7_c => if (HPM_NUM_CNTS > 04) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(04); else NULL; end if; -- R/W: mhpmevent7
|
Line 2602... |
Line 2832... |
when csr_mhpmevent29_c => if (HPM_NUM_CNTS > 26) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(26); else NULL; end if; -- R/W: mhpmevent29
|
when csr_mhpmevent29_c => if (HPM_NUM_CNTS > 26) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(26); else NULL; end if; -- R/W: mhpmevent29
|
when csr_mhpmevent30_c => if (HPM_NUM_CNTS > 27) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(27); else NULL; end if; -- R/W: mhpmevent30
|
when csr_mhpmevent30_c => if (HPM_NUM_CNTS > 27) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(27); else NULL; end if; -- R/W: mhpmevent30
|
when csr_mhpmevent31_c => if (HPM_NUM_CNTS > 28) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(28); else NULL; end if; -- R/W: mhpmevent31
|
when csr_mhpmevent31_c => if (HPM_NUM_CNTS > 28) then csr.rdata(hpmcnt_event_size_c-1 downto 0) <= csr.mhpmevent(28); else NULL; end if; -- R/W: mhpmevent31
|
|
|
-- counters and timers --
|
-- counters and timers --
|
when csr_cycle_c | csr_mcycle_c => -- (R)/(W): [m]cycle: Cycle counter LOW
|
-- --------------------------------------------------------------------
|
|
when csr_cycle_c | csr_mcycle_c => -- [m]cycle (r/w): Cycle counter LOW
|
if (cpu_cnt_lo_width_c > 0) then csr.rdata(cpu_cnt_lo_width_c-1 downto 0) <= csr.mcycle(cpu_cnt_lo_width_c-1 downto 0); else NULL; end if;
|
if (cpu_cnt_lo_width_c > 0) then csr.rdata(cpu_cnt_lo_width_c-1 downto 0) <= csr.mcycle(cpu_cnt_lo_width_c-1 downto 0); else NULL; end if;
|
when csr_cycleh_c | csr_mcycleh_c => -- (R)/(W): [m]cycleh: Cycle counter HIGH
|
when csr_cycleh_c | csr_mcycleh_c => -- [m]cycleh (r/w): Cycle counter HIGH
|
if (cpu_cnt_hi_width_c > 0) then csr.rdata(cpu_cnt_hi_width_c-1 downto 0) <= csr.mcycleh(cpu_cnt_hi_width_c-1 downto 0); else NULL; end if;
|
if (cpu_cnt_hi_width_c > 0) then csr.rdata(cpu_cnt_hi_width_c-1 downto 0) <= csr.mcycleh(cpu_cnt_hi_width_c-1 downto 0); else NULL; end if;
|
|
|
when csr_instret_c | csr_minstret_c => -- (R)/(W): [m]instret: Instructions-retired counter LOW
|
when csr_instret_c | csr_minstret_c => -- [m]instret (r/w): Instructions-retired counter LOW
|
if (cpu_cnt_lo_width_c > 0) then csr.rdata(cpu_cnt_lo_width_c-1 downto 0) <= csr.minstret(cpu_cnt_lo_width_c-1 downto 0); else NULL; end if;
|
if (cpu_cnt_lo_width_c > 0) then csr.rdata(cpu_cnt_lo_width_c-1 downto 0) <= csr.minstret(cpu_cnt_lo_width_c-1 downto 0); else NULL; end if;
|
when csr_instreth_c | csr_minstreth_c => -- (R)/(W): [m]instreth: Instructions-retired counter HIGH
|
when csr_instreth_c | csr_minstreth_c => -- [m]instreth (r/w): Instructions-retired counter HIGH
|
if (cpu_cnt_hi_width_c > 0) then csr.rdata(cpu_cnt_hi_width_c-1 downto 0) <= csr.minstreth(cpu_cnt_hi_width_c-1 downto 0); else NULL; end if;
|
if (cpu_cnt_hi_width_c > 0) then csr.rdata(cpu_cnt_hi_width_c-1 downto 0) <= csr.minstreth(cpu_cnt_hi_width_c-1 downto 0); else NULL; end if;
|
|
|
when csr_time_c => -- (R)/-: time: System time LOW (from MTIME unit)
|
when csr_time_c => csr.rdata <= time_i(31 downto 0); -- time (r/-): System time LOW (from MTIME unit)
|
csr.rdata <= time_i(31 downto 0);
|
when csr_timeh_c => csr.rdata <= time_i(63 downto 32); -- timeh (r/-): System time HIGH (from MTIME unit)
|
when csr_timeh_c => -- (R)/-: timeh: System time HIGH (from MTIME unit)
|
|
csr.rdata <= time_i(63 downto 32);
|
|
|
|
-- hardware performance counters --
|
-- hardware performance counters --
|
|
-- --------------------------------------------------------------------
|
when csr_hpmcounter3_c | csr_mhpmcounter3_c => if (HPM_NUM_CNTS > 00) then csr.rdata <= csr.mhpmcounter_rd(00); else NULL; end if; -- (R)/(W): [m]hpmcounter3 - low
|
when csr_hpmcounter3_c | csr_mhpmcounter3_c => if (HPM_NUM_CNTS > 00) then csr.rdata <= csr.mhpmcounter_rd(00); else NULL; end if; -- (R)/(W): [m]hpmcounter3 - low
|
when csr_hpmcounter4_c | csr_mhpmcounter4_c => if (HPM_NUM_CNTS > 01) then csr.rdata <= csr.mhpmcounter_rd(01); else NULL; end if; -- (R)/(W): [m]hpmcounter4 - low
|
when csr_hpmcounter4_c | csr_mhpmcounter4_c => if (HPM_NUM_CNTS > 01) then csr.rdata <= csr.mhpmcounter_rd(01); else NULL; end if; -- (R)/(W): [m]hpmcounter4 - low
|
when csr_hpmcounter5_c | csr_mhpmcounter5_c => if (HPM_NUM_CNTS > 02) then csr.rdata <= csr.mhpmcounter_rd(02); else NULL; end if; -- (R)/(W): [m]hpmcounter5 - low
|
when csr_hpmcounter5_c | csr_mhpmcounter5_c => if (HPM_NUM_CNTS > 02) then csr.rdata <= csr.mhpmcounter_rd(02); else NULL; end if; -- (R)/(W): [m]hpmcounter5 - low
|
when csr_hpmcounter6_c | csr_mhpmcounter6_c => if (HPM_NUM_CNTS > 03) then csr.rdata <= csr.mhpmcounter_rd(03); else NULL; end if; -- (R)/(W): [m]hpmcounter6 - low
|
when csr_hpmcounter6_c | csr_mhpmcounter6_c => if (HPM_NUM_CNTS > 03) then csr.rdata <= csr.mhpmcounter_rd(03); else NULL; end if; -- (R)/(W): [m]hpmcounter6 - low
|
when csr_hpmcounter7_c | csr_mhpmcounter7_c => if (HPM_NUM_CNTS > 04) then csr.rdata <= csr.mhpmcounter_rd(04); else NULL; end if; -- (R)/(W): [m]hpmcounter7 - low
|
when csr_hpmcounter7_c | csr_mhpmcounter7_c => if (HPM_NUM_CNTS > 04) then csr.rdata <= csr.mhpmcounter_rd(04); else NULL; end if; -- (R)/(W): [m]hpmcounter7 - low
|
Line 2679... |
Line 2909... |
when csr_hpmcounter29h_c | csr_mhpmcounter29h_c => if (HPM_NUM_CNTS > 26) and (hpm_cnt_hi_width_c > 0) then csr.rdata <= csr.mhpmcounterh_rd(26); else NULL; end if; -- (R)/(W): [m]hpmcounter29h - high
|
when csr_hpmcounter29h_c | csr_mhpmcounter29h_c => if (HPM_NUM_CNTS > 26) and (hpm_cnt_hi_width_c > 0) then csr.rdata <= csr.mhpmcounterh_rd(26); else NULL; end if; -- (R)/(W): [m]hpmcounter29h - high
|
when csr_hpmcounter30h_c | csr_mhpmcounter30h_c => if (HPM_NUM_CNTS > 27) and (hpm_cnt_hi_width_c > 0) then csr.rdata <= csr.mhpmcounterh_rd(27); else NULL; end if; -- (R)/(W): [m]hpmcounter30h - high
|
when csr_hpmcounter30h_c | csr_mhpmcounter30h_c => if (HPM_NUM_CNTS > 27) and (hpm_cnt_hi_width_c > 0) then csr.rdata <= csr.mhpmcounterh_rd(27); else NULL; end if; -- (R)/(W): [m]hpmcounter30h - high
|
when csr_hpmcounter31h_c | csr_mhpmcounter31h_c => if (HPM_NUM_CNTS > 28) and (hpm_cnt_hi_width_c > 0) then csr.rdata <= csr.mhpmcounterh_rd(28); else NULL; end if; -- (R)/(W): [m]hpmcounter31h - high
|
when csr_hpmcounter31h_c | csr_mhpmcounter31h_c => if (HPM_NUM_CNTS > 28) and (hpm_cnt_hi_width_c > 0) then csr.rdata <= csr.mhpmcounterh_rd(28); else NULL; end if; -- (R)/(W): [m]hpmcounter31h - high
|
|
|
-- machine information registers --
|
-- machine information registers --
|
when csr_mvendorid_c => -- R/-: mvendorid - vendor ID
|
-- --------------------------------------------------------------------
|
csr.rdata <= (others => '0');
|
when csr_mvendorid_c => csr.rdata <= (others => '0'); -- mvendorid (r/-): vendor ID
|
when csr_marchid_c => -- R/-: marchid - arch ID
|
when csr_marchid_c => csr.rdata(4 downto 0) <= "10011"; -- marchid (r/-): arch ID - official RISC-V open-source arch ID
|
csr.rdata(4 downto 0) <= "10011"; -- 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 => -- R/-: mimpid - implementation ID
|
when csr_mhartid_c => csr.rdata <= std_ulogic_vector(to_unsigned(HW_THREAD_ID, 32)); -- mhartid (r/-): hardware thread ID
|
csr.rdata <= hw_version_c; -- NEORV32 hardware version
|
|
when csr_mhartid_c => -- R/-: mhartid - hardware thread ID
|
|
csr.rdata <= std_ulogic_vector(to_unsigned(HW_THREAD_ID, 32));
|
|
|
|
-- custom machine read-only CSRs --
|
-- custom machine read-only CSRs --
|
when csr_mzext_c => -- R/-: mzext - 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
|
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei
|
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei
|
csr.rdata(2) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zbb (B)
|
csr.rdata(2) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zbb (B)
|
csr.rdata(3) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zbs (B)
|
csr.rdata(3) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zbs (B)
|
csr.rdata(4) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zba (B)
|
csr.rdata(4) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zba (B)
|
Line 2708... |
Line 2936... |
csr.rdata(6) <= '1'; -- Zxscnt (custom)
|
csr.rdata(6) <= '1'; -- Zxscnt (custom)
|
csr.rdata(7) <= '0'; -- Zxnocnt (custom)
|
csr.rdata(7) <= '0'; -- Zxnocnt (custom)
|
end if;
|
end if;
|
csr.rdata(8) <= bool_to_ulogic_f(boolean(PMP_NUM_REGIONS > 0)); -- PMP (physical memory protection)
|
csr.rdata(8) <= bool_to_ulogic_f(boolean(PMP_NUM_REGIONS > 0)); -- PMP (physical memory protection)
|
csr.rdata(9) <= bool_to_ulogic_f(boolean(HPM_NUM_CNTS > 0)); -- HPM (hardware performance monitors)
|
csr.rdata(9) <= bool_to_ulogic_f(boolean(HPM_NUM_CNTS > 0)); -- HPM (hardware performance monitors)
|
|
csr.rdata(10) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_DEBUG); -- RISC-V debug mode
|
|
|
|
-- debug mode CSRs --
|
|
-- --------------------------------------------------------------------
|
|
when csr_dcsr_c => if (CPU_EXTENSION_RISCV_DEBUG = true) then csr.rdata <= csr.dcsr_rd; else NULL; end if; -- dcsr (r/w): debug mode control and status
|
|
when csr_dpc_c => if (CPU_EXTENSION_RISCV_DEBUG = true) then csr.rdata <= csr.dpc; else NULL; end if; -- dpc (r/w): debug mode program counter
|
|
when csr_dscratch0_c => if (CPU_EXTENSION_RISCV_DEBUG = true) then csr.rdata <= csr.dscratch0; else NULL; end if; -- dscratch0 (r/w): debug mode scratch register 0
|
|
|
-- undefined/unavailable --
|
-- undefined/unavailable --
|
|
-- --------------------------------------------------------------------
|
when others =>
|
when others =>
|
NULL; -- not implemented
|
NULL; -- not implemented
|
|
|
end case;
|
end case;
|
end if;
|
end if;
|
Line 2722... |
Line 2958... |
|
|
-- CSR read data output --
|
-- CSR read data output --
|
csr_rdata_o <= csr.rdata;
|
csr_rdata_o <= csr.rdata;
|
|
|
|
|
|
-- Debug Control --------------------------------------------------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
debug_control: process(rstn_i, clk_i)
|
|
begin
|
|
if (rstn_i = '0') then
|
|
debug_ctrl.state <= DEBUG_OFFLINE;
|
|
debug_ctrl.ext_halt_req <= "00";
|
|
elsif rising_edge(clk_i) then
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) then
|
|
|
|
-- rising edge detector --
|
|
debug_ctrl.ext_halt_req <= debug_ctrl.ext_halt_req(0) & db_halt_req_i;
|
|
|
|
-- state machine --
|
|
case debug_ctrl.state is
|
|
|
|
when DEBUG_OFFLINE => -- not in debug mode, waiting for entering request
|
|
if (debug_ctrl.trig_halt = '1') or -- external request (from DM)
|
|
(debug_ctrl.trig_break = '1') or -- ebreak instruction
|
|
(debug_ctrl.trig_step = '1') then -- single-stepping mode
|
|
debug_ctrl.state <= DEBUG_PENDING;
|
|
end if;
|
|
|
|
when DEBUG_PENDING => -- waiting to start debug mode
|
|
if (trap_ctrl.env_start_ack = '1') and (trap_ctrl.cause(5) = '1') then -- processing trap entry into debug mode
|
|
debug_ctrl.state <= DEBUG_ONLINE;
|
|
end if;
|
|
|
|
when DEBUG_ONLINE => -- we are in debug mode
|
|
if (debug_ctrl.dret = '1') then -- DRET instruction
|
|
debug_ctrl.state <= DEBUG_EXIT;
|
|
end if;
|
|
|
|
when DEBUG_EXIT => -- leaving debug mode
|
|
if (execute_engine.state = TRAP_EXECUTE) then -- processing trap exit
|
|
debug_ctrl.state <= DEBUG_OFFLINE;
|
|
end if;
|
|
|
|
when others => -- undefined
|
|
debug_ctrl.state <= DEBUG_OFFLINE;
|
|
|
|
end case;
|
|
else -- debug mode NOT implemented
|
|
debug_ctrl.state <= DEBUG_OFFLINE;
|
|
debug_ctrl.ext_halt_req <= "00";
|
|
end if;
|
|
end if;
|
|
end process debug_control;
|
|
|
|
-- state decoding --
|
|
debug_ctrl.pending <= '1' when (debug_ctrl.state = DEBUG_PENDING) and (CPU_EXTENSION_RISCV_DEBUG = true) else '0';
|
|
debug_ctrl.running <= '1' when ((debug_ctrl.state = DEBUG_ONLINE) or (debug_ctrl.state = DEBUG_EXIT)) and (CPU_EXTENSION_RISCV_DEBUG = true) else '0';
|
|
|
|
-- entry debug mode triggers --
|
|
debug_ctrl.trig_break <= trap_ctrl.break_point and (debug_ctrl.running or -- we are in debug mode: re-enter debug mode
|
|
(csr.priv_m_mode and csr.dcsr_ebreakm and (not debug_ctrl.running)) or -- enable goto-debug-mode in machine mode on "ebreak"
|
|
(csr.priv_u_mode and csr.dcsr_ebreaku and (not debug_ctrl.running))); -- enable goto-debug-mode in user mode on "ebreak"
|
|
debug_ctrl.trig_halt <= (not debug_ctrl.ext_halt_req(1)) and debug_ctrl.ext_halt_req(0) and (not debug_ctrl.running); -- rising edge detector from external halt request (if not halted already)
|
|
debug_ctrl.trig_step <= csr.dcsr_step and (not debug_ctrl.running); -- single-step mode (trigger when NOT CURRENTLY in debug mode)
|
|
|
|
|
|
-- Debug Control and Status Register (dcsr) - Read-Back -----------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
dcsr_readback_false:
|
|
if (CPU_EXTENSION_RISCV_DEBUG = false) generate
|
|
csr.dcsr_rd <= (others => '0');
|
|
end generate;
|
|
|
|
dcsr_readback_true:
|
|
if (CPU_EXTENSION_RISCV_DEBUG = true) generate
|
|
csr.dcsr_rd(31 downto 28) <= "0100"; -- xdebugver: external debug support compatible to spec
|
|
csr.dcsr_rd(27 downto 16) <= (others => '0'); -- reserved
|
|
csr.dcsr_rd(15) <= csr.dcsr_ebreakm; -- ebreakm: what happens on ebreak in m-mode? (normal trap OR debug-enter)
|
|
csr.dcsr_rd(14) <= '0'; -- ebreakh: not available
|
|
csr.dcsr_rd(13) <= '0'; -- ebreaks: not available
|
|
csr.dcsr_rd(12) <= csr.dcsr_ebreaku when (CPU_EXTENSION_RISCV_U = true) else '0'; -- ebreaku: what happens on ebreak in u-mode? (normal trap OR debug-enter)
|
|
csr.dcsr_rd(11) <= csr.dcsr_stepie; -- stepie: interrupts enabled during single-stepping?
|
|
csr.dcsr_rd(10) <= '0'; -- stopcount: counters increment as usual FIXME ???
|
|
csr.dcsr_rd(09) <= '0'; -- stoptime: timers increment as usual FIXME ???
|
|
csr.dcsr_rd(08 downto 06) <= csr.dcsr_cause; -- cause
|
|
csr.dcsr_rd(05) <= '0'; -- reserved
|
|
csr.dcsr_rd(04) <= '0'; -- mprven: mstatus.mprv is ignored in debug mode
|
|
csr.dcsr_rd(03) <= trap_ctrl.irq_buf(interrupt_nm_irq_c); -- nmip: pending non-maskable interrupt
|
|
csr.dcsr_rd(02) <= csr.dcsr_step; -- step: single-step mode
|
|
csr.dcsr_rd(01 downto 00) <= csr.dcsr_prv; -- prv: privilege mode when debug mode was entered
|
|
end generate;
|
|
|
|
|
end neorv32_cpu_control_rtl;
|
end neorv32_cpu_control_rtl;
|
|
|
No newline at end of file
|
No newline at end of file
|