Line 232... |
Line 232... |
|
|
-- RISC-V control and status registers (CSRs) --
|
-- RISC-V control and status registers (CSRs) --
|
type pmp_ctrl_t is array (0 to pmp_max_r_c-1) of std_ulogic_vector(7 downto 0);
|
type pmp_ctrl_t is array (0 to pmp_max_r_c-1) of std_ulogic_vector(7 downto 0);
|
type pmp_addr_t is array (0 to pmp_max_r_c-1) of std_ulogic_vector(data_width_c-1 downto 0);
|
type pmp_addr_t is array (0 to pmp_max_r_c-1) of std_ulogic_vector(data_width_c-1 downto 0);
|
type csr_t is record
|
type csr_t is record
|
|
addr : std_ulogic_vector(11 downto 0); -- csr address
|
we : std_ulogic; -- csr write enable
|
we : std_ulogic; -- csr write enable
|
we_nxt : std_ulogic;
|
we_nxt : std_ulogic;
|
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
|
Line 248... |
Line 249... |
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(3 downto 0); -- mie.firq*e: fast interrupt enabled (R/W)
|
mie_firqe : std_ulogic_vector(3 downto 0); -- mie.firq*e: fast interrupt enabled (R/W)
|
--
|
--
|
|
mcounteren_cy : std_ulogic; -- mcounteren.cy: allow cycle[h] access from user-mode
|
|
mcounteren_tm : std_ulogic; -- mcounteren.tm: allow time[h] access from user-mode
|
|
mcounteren_ir : std_ulogic; -- mcounteren.ir: allow instret[h] access from user-mode
|
|
--
|
|
mcountinhibit_cy : std_ulogic; -- mcounterinhibit.cy: enable auto-increment
|
|
mcountinhibit_ir : std_ulogic; -- mcounterinhibit.ir: enable auto-increment
|
|
--
|
mip_status : std_ulogic_vector(interrupt_width_c-1 downto 0); -- current buffered IRQs
|
mip_status : std_ulogic_vector(interrupt_width_c-1 downto 0); -- current buffered IRQs
|
mip_clear : std_ulogic_vector(interrupt_width_c-1 downto 0); -- set bits clear the according buffered IRQ
|
mip_clear : std_ulogic_vector(interrupt_width_c-1 downto 0); -- set bits clear the according buffered IRQ
|
--
|
--
|
privilege : std_ulogic_vector(1 downto 0); -- hart's current privilege mode
|
privilege : std_ulogic_vector(1 downto 0); -- hart's current privilege mode
|
priv_m_mode : std_ulogic; -- CPU in M-mode
|
priv_m_mode : std_ulogic; -- CPU in M-mode
|
Line 342... |
Line 350... |
fetch_engine.state_nxt <= IFETCH_ISSUE;
|
fetch_engine.state_nxt <= IFETCH_ISSUE;
|
end if;
|
end if;
|
|
|
when IFETCH_ISSUE => -- store instruction data to prefetch buffer
|
when IFETCH_ISSUE => -- store instruction data to prefetch buffer
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
|
fetch_engine.bus_err_ack <= be_instr_i or ma_instr_i; -- ACK bus/alignment errors
|
if (bus_i_wait_i = '0') or (be_instr_i = '1') or (ma_instr_i = '1') then -- wait for bus response
|
if (bus_i_wait_i = '0') or (be_instr_i = '1') or (ma_instr_i = '1') then -- wait for bus response
|
fetch_engine.pc_nxt <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4);
|
fetch_engine.pc_nxt <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4);
|
ipb.we <= '1';
|
ipb.we <= '1';
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
end if;
|
end if;
|
Line 456... |
Line 465... |
when ISSUE_ACTIVE => -- issue instruction if available
|
when ISSUE_ACTIVE => -- issue instruction if available
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (ipb.avail = '1') then -- instructions available?
|
if (ipb.avail = '1') then -- instructions available?
|
|
|
if (issue_engine.align = '0') or (CPU_EXTENSION_RISCV_C = false) then -- begin check in LOW instruction half-word
|
if (issue_engine.align = '0') or (CPU_EXTENSION_RISCV_C = false) then -- begin check in LOW instruction half-word
|
if (execute_engine.state = DISPATCH) then
|
if (execute_engine.state = DISPATCH) then -- ready to issue new command?
|
cmd_issue.valid <= '1';
|
cmd_issue.valid <= '1';
|
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction
|
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction
|
if (ipb.rdata(1 downto 0) = "11") or (CPU_EXTENSION_RISCV_C = false) then -- uncompressed and "aligned"
|
if (ipb.rdata(1 downto 0) = "11") or (CPU_EXTENSION_RISCV_C = false) then -- uncompressed and "aligned"
|
ipb.re <= '1';
|
ipb.re <= '1';
|
cmd_issue.data <= '0' & ipb.rdata(33 downto 32) & '0' & ipb.rdata(31 downto 0);
|
cmd_issue.data <= '0' & ipb.rdata(33 downto 32) & '0' & ipb.rdata(31 downto 0);
|
Line 470... |
Line 479... |
issue_engine.align_nxt <= '1';
|
issue_engine.align_nxt <= '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
else -- begin check in HIGH instruction half-word
|
else -- begin check in HIGH instruction half-word
|
if (execute_engine.state = DISPATCH) then
|
if (execute_engine.state = DISPATCH) then -- ready to issue new command?
|
cmd_issue.valid <= '1';
|
cmd_issue.valid <= '1';
|
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction
|
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction
|
if (issue_engine.buf(1 downto 0) = "11") then -- uncompressed and "unaligned"
|
if (issue_engine.buf(1 downto 0) = "11") then -- uncompressed and "unaligned"
|
ipb.re <= '1';
|
ipb.re <= '1';
|
cmd_issue.data <= '0' & issue_engine.buf(17 downto 16) & '0' & (ipb.rdata(15 downto 0) & issue_engine.buf(15 downto 0));
|
cmd_issue.data <= '0' & issue_engine.buf(17 downto 16) & '0' & (ipb.rdata(15 downto 0) & issue_engine.buf(15 downto 0));
|
Line 500... |
Line 509... |
issue_engine.state_nxt <= ISSUE_ACTIVE;
|
issue_engine.state_nxt <= ISSUE_ACTIVE;
|
|
|
end case;
|
end case;
|
end process issue_engine_fsm_comb;
|
end process issue_engine_fsm_comb;
|
|
|
-- 16-bit instruction: half-word select --
|
-- 16-bit instructions: half-word select --
|
ci_instr16 <= ipb.rdata(15 downto 0) when (issue_engine.align = '0') else issue_engine.buf(15 downto 0);
|
ci_instr16 <= ipb.rdata(15 downto 0) when (issue_engine.align = '0') else issue_engine.buf(15 downto 0);
|
|
|
|
|
-- Compressed Instructions Recoding -------------------------------------------------------
|
-- Compressed Instructions Recoding -------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 610... |
Line 619... |
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
-- PC update --
|
-- PC update --
|
if (execute_engine.pc_we = '1') then
|
if (execute_engine.pc_we = '1') then
|
case execute_engine.pc_mux_sel is
|
case execute_engine.pc_mux_sel is
|
when "00" => execute_engine.pc <= execute_engine.next_pc(data_width_c-1 downto 1) & '0'; -- normal (linear) increment
|
when "00" => execute_engine.pc <= execute_engine.next_pc(data_width_c-1 downto 1) & '0'; -- normal (linear) increment
|
when "01" => execute_engine.pc <= alu_add_i(data_width_c-1 downto 1) & '0'; -- jump/branch
|
when "01" => execute_engine.pc <= alu_add_i(data_width_c-1 downto 1) & '0'; -- jump/taken_branch
|
when "10" => execute_engine.pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
|
when "10" => execute_engine.pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
|
when others => execute_engine.pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap return
|
when others => execute_engine.pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap exit
|
end case;
|
end case;
|
end if;
|
end if;
|
--
|
--
|
execute_engine.state <= execute_engine.state_nxt;
|
execute_engine.state <= execute_engine.state_nxt;
|
execute_engine.sleep <= execute_engine.sleep_nxt;
|
execute_engine.sleep <= execute_engine.sleep_nxt;
|
Line 648... |
Line 657... |
-- 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;
|
|
|
|
-- CSR access address --
|
|
csr.addr <= execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c);
|
|
|
-- PC output --
|
-- PC output --
|
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- PC for ALU ops
|
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- PC for ALU ops
|
|
|
|
|
-- CPU Control Bus Output -----------------------------------------------------------------
|
-- CPU Control Bus Output -----------------------------------------------------------------
|
Line 841... |
Line 853... |
when funct3_xor_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_xor_c; -- XOR(I)
|
when funct3_xor_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_xor_c; -- XOR(I)
|
when funct3_or_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_or_c; -- OR(I)
|
when funct3_or_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_or_c; -- OR(I)
|
when others => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_and_c; -- AND(I)
|
when others => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_and_c; -- AND(I)
|
end case;
|
end case;
|
|
|
-- cp access? --
|
-- co-processor (cp) access? --
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- just in case a mul/div operation
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- just in case a mul/div operation
|
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and (execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV CP op?
|
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and (execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV CP op?
|
execute_engine.is_cp_op_nxt <= '1'; -- this is a CP operation
|
execute_engine.is_cp_op_nxt <= '1'; -- this is a CP operation
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
-- ALU operation - function select --
|
-- ALU operation - function select --
|
Line 1100... |
Line 1112... |
csr_wacc_v := or_all_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c)); -- write allowed if rs1/uimm5 != 0
|
csr_wacc_v := or_all_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c)); -- write allowed if rs1/uimm5 != 0
|
-- csr_racc_v := '1'; -- always read CSR
|
-- csr_racc_v := '1'; -- always read CSR
|
end if;
|
end if;
|
|
|
-- check CSR access --
|
-- check CSR access --
|
case execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) is
|
case csr.addr is
|
|
-- standard read/write CSRs --
|
when csr_mstatus_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mstatus_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mstatush_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mstatush_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_misa_c => csr_acc_valid <= csr.priv_m_mode;-- and (not csr_wacc_v); -- M-mode only, MISA is read-only in the NEORV32 but we don't cause an exception here for compatibility
|
when csr_misa_c => csr_acc_valid <= csr.priv_m_mode;-- and (not csr_wacc_v); -- M-mode only, MISA is read-only in the NEORV32 but we do not cause an exception here for compatibility
|
when csr_mie_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mie_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mtvec_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mtvec_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mscratch_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mscratch_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mepc_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mepc_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mcause_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mcause_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
|
when csr_mcounteren_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mtval_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mtval_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mip_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mip_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
--
|
--
|
when csr_pmpcfg0_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 1)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpcfg0_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 1)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpcfg1_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 5)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpcfg1_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 5)) and csr.priv_m_mode; -- M-mode only
|
Line 1124... |
Line 1138... |
when csr_pmpaddr4_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 5)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpaddr4_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 5)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpaddr5_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 6)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpaddr5_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 6)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpaddr6_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 7)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpaddr6_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 7)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpaddr7_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 8)) and csr.priv_m_mode; -- M-mode only
|
when csr_pmpaddr7_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(pmp_num_regions_c >= 8)) and csr.priv_m_mode; -- M-mode only
|
--
|
--
|
when csr_mcycle_c => csr_acc_valid <= csr.priv_m_mode and bool_to_ulogic_f(zicnt_en_c); -- M-mode only and "Zicnt" = true
|
when csr_mcountinhibit_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_minstret_c => csr_acc_valid <= csr.priv_m_mode and bool_to_ulogic_f(zicnt_en_c); -- M-mode only and "Zicnt" = true
|
|
--
|
|
when csr_mcycleh_c => csr_acc_valid <= csr.priv_m_mode and bool_to_ulogic_f(zicnt_en_c); -- M-mode only and "Zicnt" = true
|
|
when csr_minstreth_c => csr_acc_valid <= csr.priv_m_mode and bool_to_ulogic_f(zicnt_en_c); -- M-mode only and "Zicnt" = true
|
|
--
|
|
when csr_cycle_c => csr_acc_valid <= (not csr_wacc_v) and bool_to_ulogic_f(zicnt_en_c); -- all modes, read-only and "Zicnt" = true
|
|
when csr_time_c => csr_acc_valid <= (not csr_wacc_v); -- all modes, read-only
|
|
when csr_instret_c => csr_acc_valid <= (not csr_wacc_v) and bool_to_ulogic_f(zicnt_en_c); -- all modes, read-only and "Zicnt" = true
|
|
--
|
--
|
when csr_cycleh_c => csr_acc_valid <= (not csr_wacc_v) and bool_to_ulogic_f(zicnt_en_c); -- all modes, read-only and "Zicnt" = true
|
when csr_mcycle_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_timeh_c => csr_acc_valid <= (not csr_wacc_v); -- all modes, read-only
|
when csr_minstret_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_instreth_c => csr_acc_valid <= (not csr_wacc_v) and bool_to_ulogic_f(zicnt_en_c); -- all modes, read-only and "Zicnt" = true
|
|
--
|
--
|
when csr_mvendorid_c => csr_acc_valid <= csr.priv_m_mode and (not csr_wacc_v); -- M-mode only, read-only
|
when csr_mcycleh_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_marchid_c => csr_acc_valid <= csr.priv_m_mode and (not csr_wacc_v); -- M-mode only, read-only
|
when csr_minstreth_c => csr_acc_valid <= csr.priv_m_mode; -- M-mode only
|
when csr_mimpid_c => csr_acc_valid <= csr.priv_m_mode and (not csr_wacc_v); -- M-mode only, read-only
|
-- standard read-only CSRs --
|
when csr_mhartid_c => csr_acc_valid <= csr.priv_m_mode and (not csr_wacc_v); -- M-mode only, read-only
|
when csr_cycle_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_cy); -- M-mode, U-mode if authorized, read-only
|
|
when csr_time_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_tm); -- M-mode, U-mode if authorized, read-only
|
|
when csr_instret_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_ir); -- M-mode, U-mode if authorized, read-only
|
|
--
|
|
when csr_cycleh_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_cy); -- M-mode, U-mode if authorized, read-only
|
|
when csr_timeh_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_tm); -- M-mode, U-mode if authorized, read-only
|
|
when csr_instreth_c => csr_acc_valid <= (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_ir); -- M-mode, U-mode if authorized, read-only
|
|
--
|
|
when csr_mvendorid_c => csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
|
when csr_marchid_c => csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
|
when csr_mimpid_c => csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
|
when csr_mhartid_c => csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
|
-- custom read-only CSRs --
|
|
when csr_mzext_c => csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
--
|
--
|
when csr_mzext_c => csr_acc_valid <= csr.priv_m_mode and (not csr_wacc_v); -- M-mode only, read-only
|
when others => csr_acc_valid <= '0'; -- invalid access
|
--
|
|
when others => csr_acc_valid <= '0'; -- undefined, invalid access
|
|
end case;
|
end case;
|
end process invalid_csr_access_check;
|
end process invalid_csr_access_check;
|
|
|
|
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- Illegal Instruction Check --------------------------------------------------------------
|
Line 1590... |
Line 1606... |
csr.mtval <= (others => '0');
|
csr.mtval <= (others => '0');
|
csr.mip_clear <= (others => '0');
|
csr.mip_clear <= (others => '0');
|
csr.pmpcfg <= (others => (others => '0'));
|
csr.pmpcfg <= (others => (others => '0'));
|
csr.pmpaddr <= (others => (others => '1'));
|
csr.pmpaddr <= (others => (others => '1'));
|
--
|
--
|
|
csr.mcounteren_cy <= '0';
|
|
csr.mcounteren_tm <= '0';
|
|
csr.mcounteren_ir <= '0';
|
|
csr.mcountinhibit_cy <= '0';
|
|
csr.mcountinhibit_ir <= '0';
|
|
--
|
csr.mcycle <= (others => '0');
|
csr.mcycle <= (others => '0');
|
csr.minstret <= (others => '0');
|
csr.minstret <= (others => '0');
|
csr.mcycleh <= (others => '0');
|
csr.mcycleh <= (others => '0');
|
csr.minstreth <= (others => '0');
|
csr.minstreth <= (others => '0');
|
mcycle_msb <= '0';
|
mcycle_msb <= '0';
|
Line 1608... |
Line 1630... |
|
|
-- --------------------------------------------------------------------------------
|
-- --------------------------------------------------------------------------------
|
-- CSR access by application software
|
-- CSR access by application software
|
-- --------------------------------------------------------------------------------
|
-- --------------------------------------------------------------------------------
|
if (csr.we = '1') then -- manual update
|
if (csr.we = '1') then -- manual update
|
case execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) is
|
case csr.addr is
|
|
|
-- machine trap setup --
|
-- machine trap setup --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_mstatus_c => -- R/W: mstatus - machine status register
|
when csr_mstatus_c => -- R/W: mstatus - machine status register
|
csr.mstatus_mie <= csr.wdata(03);
|
csr.mstatus_mie <= csr.wdata(03);
|
Line 1621... |
Line 1643... |
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
|
else -- only machine mode is available
|
csr.mstatus_mpp <= priv_mode_m_c;
|
csr.mstatus_mpp <= priv_mode_m_c;
|
end if;
|
end if;
|
when csr_mie_c => -- R/W: mie - machine interrupt-enable register
|
when csr_mie_c => -- R/W: mie - machine interrupt enable register
|
csr.mie_msie <= csr.wdata(03); -- machine SW IRQ enable
|
csr.mie_msie <= csr.wdata(03); -- machine SW IRQ enable
|
csr.mie_mtie <= csr.wdata(07); -- machine TIMER IRQ enable
|
csr.mie_mtie <= csr.wdata(07); -- machine TIMER IRQ enable
|
csr.mie_meie <= csr.wdata(11); -- machine EXT IRQ enable
|
csr.mie_meie <= csr.wdata(11); -- machine EXT IRQ enable
|
--
|
--
|
csr.mie_firqe(0) <= csr.wdata(16); -- fast interrupt channel 0
|
csr.mie_firqe(0) <= csr.wdata(16); -- fast interrupt channel 0
|
csr.mie_firqe(1) <= csr.wdata(17); -- fast interrupt channel 1
|
csr.mie_firqe(1) <= csr.wdata(17); -- fast interrupt channel 1
|
csr.mie_firqe(2) <= csr.wdata(18); -- fast interrupt channel 2
|
csr.mie_firqe(2) <= csr.wdata(18); -- fast interrupt channel 2
|
csr.mie_firqe(3) <= csr.wdata(19); -- fast interrupt channel 3
|
csr.mie_firqe(3) <= csr.wdata(19); -- fast interrupt channel 3
|
when csr_mtvec_c => -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
|
when csr_mtvec_c => -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
|
csr.mtvec <= csr.wdata(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
|
csr.mtvec <= csr.wdata(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
|
|
when csr_mcounteren_c => -- R/W: machine counter enable register
|
|
csr.mcounteren_cy <= csr.wdata(0); -- enable user-level access to cycle[h]
|
|
csr.mcounteren_tm <= csr.wdata(1); -- enable user-level access to time[h]
|
|
csr.mcounteren_ir <= csr.wdata(2); -- enable user-level access to instret[h]
|
|
|
-- machine trap handling --
|
-- machine trap handling --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
|
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
|
csr.mscratch <= csr.wdata;
|
csr.mscratch <= csr.wdata;
|
Line 1698... |
Line 1724... |
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_pmpaddr0_c | csr_pmpaddr1_c | csr_pmpaddr2_c | csr_pmpaddr3_c |
|
when csr_pmpaddr0_c | csr_pmpaddr1_c | csr_pmpaddr2_c | csr_pmpaddr3_c |
|
csr_pmpaddr4_c | csr_pmpaddr5_c | csr_pmpaddr6_c | csr_pmpaddr7_c => -- R/W: pmpaddr0..7 - PMP address register 0..7
|
csr_pmpaddr4_c | csr_pmpaddr5_c | csr_pmpaddr6_c | csr_pmpaddr7_c => -- R/W: pmpaddr0..7 - PMP address register 0..7
|
if (PMP_USE = true) then
|
if (PMP_USE = true) then
|
for i in 0 to pmp_num_regions_c-1 loop
|
for i in 0 to pmp_num_regions_c-1 loop
|
if (execute_engine.i_reg(23 downto 20) = std_ulogic_vector(to_unsigned(i, 4))) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
|
if (csr.addr(2 downto 0) = std_ulogic_vector(to_unsigned(i, 3))) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
|
csr.pmpaddr(i) <= csr.wdata;
|
csr.pmpaddr(i) <= csr.wdata;
|
csr.pmpaddr(i)(index_size_f(pmp_min_granularity_c)-4 downto 0) <= (others => '1');
|
csr.pmpaddr(i)(index_size_f(pmp_min_granularity_c)-4 downto 0) <= (others => '1');
|
end if;
|
end if;
|
end loop; -- i (CSRs)
|
end loop; -- i (CSRs)
|
end if;
|
end if;
|
|
|
|
-- machine counter setup --
|
|
-- --------------------------------------------------------------------
|
|
when csr_mcountinhibit_c => -- R/W: mcountinhibit - machine counter-inhibit register
|
|
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
|
|
|
-- undefined --
|
-- undefined --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when others =>
|
when others =>
|
NULL;
|
NULL;
|
|
|
Line 1771... |
Line 1803... |
end if;
|
end if;
|
|
|
end if; -- hardware csr access
|
end if; -- hardware csr access
|
|
|
-- --------------------------------------------------------------------------------
|
-- --------------------------------------------------------------------------------
|
-- Counter CSRs (each counter is split in 2 32-bit counters)
|
-- Counter CSRs (each counter is split in two 32-bit counters)
|
-- --------------------------------------------------------------------------------
|
-- --------------------------------------------------------------------------------
|
if (zicnt_en_c = true) then -- implement standard RISC-V performance counters?
|
|
-- [m]cycle --
|
-- [m]cycle --
|
if (csr.we = '1') and (execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) = csr_mcycle_c) then -- write access
|
if (csr.we = '1') and (csr.addr = csr_mcycle_c) then -- write access
|
csr.mcycle <= '0' & csr.wdata;
|
csr.mcycle <= '0' & csr.wdata;
|
mcycle_msb <= '0';
|
mcycle_msb <= '0';
|
elsif (execute_engine.sleep = '0') then -- automatic update (if CPU is not in sleep mode)
|
elsif (csr.mcountinhibit_cy = '0') and (execute_engine.sleep = '0') then -- non-inhibited automatic update (if CPU is not in sleep mode)
|
csr.mcycle <= std_ulogic_vector(unsigned(csr.mcycle) + 1);
|
csr.mcycle <= std_ulogic_vector(unsigned(csr.mcycle) + 1);
|
mcycle_msb <= csr.mcycle(csr.mcycle'left);
|
mcycle_msb <= csr.mcycle(csr.mcycle'left);
|
end if;
|
end if;
|
|
|
-- [m]cycleh --
|
-- [m]cycleh --
|
if (csr.we = '1') and (execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) = csr_mcycleh_c) then -- write access
|
if (csr.we = '1') and (csr.addr = csr_mcycleh_c) then -- write access
|
csr.mcycleh <= csr.wdata(csr.mcycleh'left downto 0);
|
csr.mcycleh <= csr.wdata;
|
elsif ((mcycle_msb xor csr.mcycle(csr.mcycle'left)) = '1') then -- automatic update
|
elsif ((mcycle_msb xor csr.mcycle(csr.mcycle'left)) = '1') then -- automatic update (continued)
|
csr.mcycleh <= std_ulogic_vector(unsigned(csr.mcycleh) + 1);
|
csr.mcycleh <= std_ulogic_vector(unsigned(csr.mcycleh) + 1);
|
end if;
|
end if;
|
|
|
-- [m]instret --
|
-- [m]instret --
|
if (csr.we = '1') and (execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) = csr_minstret_c) then -- write access
|
if (csr.we = '1') and (csr.addr = csr_minstret_c) then -- write access
|
csr.minstret <= '0' & csr.wdata;
|
csr.minstret <= '0' & csr.wdata;
|
minstret_msb <= '0';
|
minstret_msb <= '0';
|
elsif (execute_engine.state = EXECUTE) then -- automatic update (if CPU actually executes an instruction)
|
elsif (csr.mcountinhibit_ir = '0') and (execute_engine.state = EXECUTE) then -- non-inhibited automatic update (if CPU actually executes an instruction)
|
csr.minstret <= std_ulogic_vector(unsigned(csr.minstret) + 1);
|
csr.minstret <= std_ulogic_vector(unsigned(csr.minstret) + 1);
|
minstret_msb <= csr.minstret(csr.minstret'left);
|
minstret_msb <= csr.minstret(csr.minstret'left);
|
end if;
|
end if;
|
|
|
-- [m]instreth --
|
-- [m]instreth --
|
if (csr.we = '1') and (execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) = csr_minstreth_c) then -- write access
|
if (csr.we = '1') and (csr.addr = csr_minstreth_c) then -- write access
|
csr.minstreth <= csr.wdata(csr.minstreth'left downto 0);
|
csr.minstreth <= csr.wdata;
|
elsif ((minstret_msb xor csr.minstret(csr.minstret'left)) = '1') then -- automatic update
|
elsif ((minstret_msb xor csr.minstret(csr.minstret'left)) = '1') then -- automatic update (continued)
|
csr.minstreth <= std_ulogic_vector(unsigned(csr.minstreth) + 1);
|
csr.minstreth <= std_ulogic_vector(unsigned(csr.minstreth) + 1);
|
end if;
|
end if;
|
else -- performance counters NOT implemented (not RISC-V-compliant!)
|
|
csr.mcycle <= (others => '0');
|
|
csr.minstret <= (others => '0');
|
|
csr.mcycleh <= (others => '0');
|
|
csr.minstreth <= (others => '0');
|
|
mcycle_msb <= '0';
|
|
minstret_msb <= '0';
|
|
end if;
|
|
|
|
end if;
|
end if;
|
end if;
|
end if;
|
end process csr_write_access;
|
end process csr_write_access;
|
|
|
Line 1845... |
Line 1868... |
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
csr.re <= csr.re_nxt; -- read access?
|
csr.re <= csr.re_nxt; -- read access?
|
csr.rdata <= (others => '0'); -- default output
|
csr.rdata <= (others => '0'); -- default output
|
if (CPU_EXTENSION_RISCV_Zicsr = true) and (csr.re = '1') then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) and (csr.re = '1') then
|
case execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) is
|
case csr.addr is
|
|
|
-- machine trap setup --
|
-- machine trap setup --
|
when csr_mstatus_c => -- R/W: mstatus - machine status register
|
when csr_mstatus_c => -- R/W: mstatus - 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(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 => -- R/-: mstatush - machine status register - high part
|
csr.rdata(05) <= '1'; -- MBE: CPU/Processor is BIG-ENDIAN
|
csr.rdata(05) <= '1'; -- MBE: CPU/Processor is BIG-ENDIAN (in machine-mode)
|
when csr_misa_c => -- R/-: misa - ISA and extensions
|
when csr_misa_c => -- R/-: misa - ISA and extensions
|
csr.rdata(00) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_A); -- A CPU extension
|
csr.rdata(00) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_A); -- A CPU extension
|
csr.rdata(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 1876... |
Line 1900... |
csr.rdata(17) <= csr.mie_firqe(1); -- fast interrupt channel 1
|
csr.rdata(17) <= csr.mie_firqe(1); -- fast interrupt channel 1
|
csr.rdata(18) <= csr.mie_firqe(2); -- fast interrupt channel 2
|
csr.rdata(18) <= csr.mie_firqe(2); -- fast interrupt channel 2
|
csr.rdata(19) <= csr.mie_firqe(3); -- fast interrupt channel 3
|
csr.rdata(19) <= csr.mie_firqe(3); -- fast interrupt channel 3
|
when csr_mtvec_c => -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
|
when csr_mtvec_c => -- R/W: mtvec - 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
|
|
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(2) <= csr.mcounteren_ir; -- enable user-level access to instret[h]
|
|
|
-- machine trap handling --
|
-- machine trap handling --
|
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
|
when csr_mscratch_c => -- R/W: mscratch - 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 => -- R/W: mepc - machine exception program counter
|
Line 1986... |
Line 2014... |
if (csr.pmpcfg(7)(4 downto 3) = "00") then -- mode = off
|
if (csr.pmpcfg(7)(4 downto 3) = "00") then -- mode = off
|
csr.rdata(index_size_f(pmp_min_granularity_c)-3 downto 0) <= (others => '0'); -- required for granularity check by SW
|
csr.rdata(index_size_f(pmp_min_granularity_c)-3 downto 0) <= (others => '0'); -- required for granularity check by SW
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
|
-- machine counter setup --
|
|
-- --------------------------------------------------------------------
|
|
when csr_mcountinhibit_c => -- R/W: mcountinhibit - machine counter-inhibit register
|
|
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
|
|
|
-- 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 => -- R/(W): [m]cycle: Cycle counter LOW
|
csr.rdata <= csr.mcycle(31 downto 0);
|
csr.rdata <= csr.mcycle(31 downto 0);
|
when csr_time_c => -- R/-: time: System time LOW (from MTIME unit)
|
when csr_time_c => -- R/-: time: System time LOW (from MTIME unit)
|
csr.rdata <= time_i(31 downto 0);
|
csr.rdata <= time_i(31 downto 0);
|
Line 2015... |
Line 2049... |
-- custom machine read-only CSRs --
|
-- custom machine read-only CSRs --
|
when csr_mzext_c => -- R/-: mzext - available Z* extensions
|
when csr_mzext_c => -- R/-: mzext - available Z* extensions
|
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- RISC-V.Zicsr CPU extension
|
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- RISC-V.Zicsr CPU extension
|
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- RISC-V.Zifencei CPU extension
|
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- RISC-V.Zifencei CPU extension
|
csr.rdata(2) <= bool_to_ulogic_f(PMP_USE); -- RISC-V physical memory protection
|
csr.rdata(2) <= bool_to_ulogic_f(PMP_USE); -- RISC-V physical memory protection
|
csr.rdata(3) <= bool_to_ulogic_f(zicnt_en_c); -- RISC-V performance counters ([m]cycle[h] & [m]instret[h]) implemented
|
|
|
|
-- undefined/unavailable --
|
-- undefined/unavailable --
|
when others =>
|
when others =>
|
csr.rdata <= (others => '0'); -- not implemented
|
csr.rdata <= (others => '0'); -- not implemented
|
|
|