diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b6ee5743..bb867b20d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date (*dd.mm.yyyy*) | Version | Comment | |:-------------------:|:-------:|:--------| +| 01.09.2023 | 1.8.8.6 | minor rtl edits and cleanups; [#679](https://github.com/stnolting/neorv32/pull/679) | | 30.08.2023 | 1.8.8.5 | remove "branch prediction" logic - core is smaller and _even faster_ without it; [#678](https://github.com/stnolting/neorv32/pull/678) | | 25.08.2023 | 1.8.8.4 | add new generic to downgrade on-chip debugger's debug module back to spec. version 0.13 (`DM_LEGACY_MODE` generic); [#677](https://github.com/stnolting/neorv32/pull/677) | | 23.08.2023 | 1.8.8.3 | :test_tube: add experimental `Smcntrpmf` ISA extension (counter privilege mode filtering; spec. is frozen but not yet ratified); remove unused `menvcfg` CSRs; [#676](https://github.com/stnolting/neorv32/pull/676) | diff --git a/rtl/core/neorv32_cpu.vhd b/rtl/core/neorv32_cpu.vhd index e6f3f9f76..f5dadcf74 100644 --- a/rtl/core/neorv32_cpu.vhd +++ b/rtl/core/neorv32_cpu.vhd @@ -368,7 +368,7 @@ begin addr_i => alu_add, -- access address wdata_i => rs2, -- write data rdata_o => mem_rdata, -- read data - mar_o => mar, -- current memory address register + mar_o => mar, -- memory address register d_wait_o => bus_d_wait, -- wait for access to complete ma_load_o => ma_load, -- misaligned load data address ma_store_o => ma_store, -- misaligned store data address diff --git a/rtl/core/neorv32_cpu_alu.vhd b/rtl/core/neorv32_cpu_alu.vhd index 894047abe..3cfc7c9ea 100644 --- a/rtl/core/neorv32_cpu_alu.vhd +++ b/rtl/core/neorv32_cpu_alu.vhd @@ -100,6 +100,9 @@ architecture neorv32_cpu_cpu_rtl of neorv32_cpu_alu is signal cp_start : std_ulogic_vector(4 downto 0); -- co-processor trigger signal cp_valid : std_ulogic_vector(4 downto 0); -- co-processor done + -- CSR read-backs -- + signal csr_rdata_fpu : std_ulogic_vector(XLEN-1 downto 0); + begin -- Comparator Unit (for conditional branches) --------------------------------------------- @@ -117,12 +120,12 @@ begin opa <= pc_i when (ctrl_i.alu_opa_mux = '1') else rs1_i; opb <= imm_i when (ctrl_i.alu_opb_mux = '1') else rs2_i; - opa_x <= (opa(opa'left) and (not ctrl_i.alu_unsigned)) & opa; -- sign-extend - opb_x <= (opb(opb'left) and (not ctrl_i.alu_unsigned)) & opb; -- sign-extend - -- Adder/Subtracter Core ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- + opa_x <= (opa(opa'left) and (not ctrl_i.alu_unsigned)) & opa; -- sign-extend + opb_x <= (opb(opb'left) and (not ctrl_i.alu_unsigned)) & opb; -- sign-extend + addsub_res <= std_ulogic_vector(unsigned(opa_x) - unsigned(opb_x)) when (ctrl_i.alu_op(0) = '1') else std_ulogic_vector(unsigned(opa_x) + unsigned(opb_x)); @@ -163,6 +166,9 @@ begin -- > "cp_result" data has to be always zero unless the specific co-processor has been actually triggered cp_res <= cp_result(0) or cp_result(1) or cp_result(2) or cp_result(3) or cp_result(4); + -- co-processor CSR read-back -- + csr_rdata_o <= csr_rdata_fpu; + -- Co-Processor 0: Shifter Unit (Base ISA) ------------------------------------------------ -- ------------------------------------------------------------------------------------------- @@ -255,31 +261,31 @@ begin neorv32_cpu_cp_fpu_inst: entity neorv32.neorv32_cpu_cp_fpu port map ( -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_i, -- global reset, low-active, async - ctrl_i => ctrl_i, -- main control bus - start_i => cp_start(3), -- trigger operation + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + ctrl_i => ctrl_i, -- main control bus + start_i => cp_start(3), -- trigger operation -- CSR interface -- - csr_we_i => csr_we_i, -- global write enable - csr_addr_i => csr_addr_i, -- address - csr_wdata_i => csr_wdata_i, -- write data - csr_rdata_o => csr_rdata_o, -- read data + csr_we_i => csr_we_i, -- global write enable + csr_addr_i => csr_addr_i, -- address + csr_wdata_i => csr_wdata_i, -- write data + csr_rdata_o => csr_rdata_fpu, -- read data -- data input -- - cmp_i => cmp, -- comparator status - rs1_i => rs1_i, -- rf source 1 - rs2_i => rs2_i, -- rf source 2 - rs3_i => rs3_i, -- rf source 3 + cmp_i => cmp, -- comparator status + rs1_i => rs1_i, -- rf source 1 + rs2_i => rs2_i, -- rf source 2 + rs3_i => rs3_i, -- rf source 3 -- result and status -- - res_o => cp_result(3), -- operation result - valid_o => cp_valid(3) -- data output valid + res_o => cp_result(3), -- operation result + valid_o => cp_valid(3) -- data output valid ); end generate; neorv32_cpu_cp_fpu_inst_false: if (CPU_EXTENSION_RISCV_Zfinx = false) generate - csr_rdata_o <= (others => '0'); - cp_result(3) <= (others => '0'); - cp_valid(3) <= '0'; + csr_rdata_fpu <= (others => '0'); + cp_result(3) <= (others => '0'); + cp_valid(3) <= '0'; end generate; diff --git a/rtl/core/neorv32_cpu_control.vhd b/rtl/core/neorv32_cpu_control.vhd index e95950483..743386ec4 100644 --- a/rtl/core/neorv32_cpu_control.vhd +++ b/rtl/core/neorv32_cpu_control.vhd @@ -65,7 +65,7 @@ entity neorv32_cpu_control is CPU_EXTENSION_RISCV_E : boolean; -- implement embedded RF extension? CPU_EXTENSION_RISCV_M : boolean; -- implement mul/div extension? CPU_EXTENSION_RISCV_U : boolean; -- implement user mode extension? - CPU_EXTENSION_RISCV_Zfinx : boolean; -- implement 32-bit floating-point extension (using INT reg!) + CPU_EXTENSION_RISCV_Zfinx : boolean; -- implement 32-bit floating-point extension (using INT regs) CPU_EXTENSION_RISCV_Zicntr : boolean; -- implement base counters? CPU_EXTENSION_RISCV_Zihpm : boolean; -- implement hardware performance monitors? CPU_EXTENSION_RISCV_Zifencei : boolean; -- implement instruction stream sync.? @@ -166,8 +166,8 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is align_clr : std_ulogic; ci_i16 : std_ulogic_vector(15 downto 0); ci_i32 : std_ulogic_vector(31 downto 0); - data : std_ulogic_vector((3+32)-1 downto 0); -- 3-bit status & 32-bit instruction - valid : std_ulogic_vector(1 downto 0); -- data word is valid when != 0 + data : std_ulogic_vector((3+32)-1 downto 0); -- 3-bit status + 32-bit instruction + valid : std_ulogic_vector(1 downto 0); -- data word is valid ack : std_ulogic; end record; signal issue_engine : issue_engine_t; @@ -520,10 +520,9 @@ begin issue_engine.align_set <= ipb.avail(0); -- start of next instruction word is NOT 32-bit-aligned issue_engine.valid(0) <= ipb.avail(0); issue_engine.data <= ipb.rdata(0)(17 downto 16) & '1' & issue_engine.ci_i32; - else -- aligned uncompressed + else -- aligned uncompressed; use IPB(0) status flags only issue_engine.valid <= (others => (ipb.avail(0) and ipb.avail(1))); - issue_engine.data <= (ipb.rdata(1)(17 downto 16) or ipb.rdata(0)(17 downto 16)) & '0' & - (ipb.rdata(1)(15 downto 00) & ipb.rdata(0)(15 downto 00)); + issue_engine.data <= ipb.rdata(0)(17 downto 16) & '0' & ipb.rdata(1)(15 downto 0) & ipb.rdata(0)(15 downto 0); end if; -- start with HIGH half-word -- else @@ -531,25 +530,24 @@ begin issue_engine.align_clr <= ipb.avail(1); -- start of next instruction word is 32-bit-aligned again issue_engine.valid(1) <= ipb.avail(1); issue_engine.data <= ipb.rdata(1)(17 downto 16) & '1' & issue_engine.ci_i32; - else -- unaligned uncompressed + else -- unaligned uncompressed; use IPB(0) status flags only issue_engine.valid <= (others => (ipb.avail(0) and ipb.avail(1))); - issue_engine.data <= (ipb.rdata(0)(17 downto 16) or ipb.rdata(1)(17 downto 16)) & '0' & - (ipb.rdata(0)(15 downto 00) & ipb.rdata(1)(15 downto 00)); + issue_engine.data <= ipb.rdata(0)(17 downto 16) & '0' & ipb.rdata(0)(15 downto 0) & ipb.rdata(1)(15 downto 0); end if; end if; end process issue_engine_fsm_comb; end generate; -- /issue_engine_enabled - issue_engine_disabled: + issue_engine_disabled: -- use IPB(0) status flags only if (CPU_EXTENSION_RISCV_C = false) generate - issue_engine.valid <= (others => ipb.avail(0)); -- only use status flags from IPB[0] + issue_engine.valid <= (others => ipb.avail(0)); issue_engine.data <= ipb.rdata(0)(17 downto 16) & '0' & (ipb.rdata(1)(15 downto 0) & ipb.rdata(0)(15 downto 0)); end generate; -- /issue_engine_disabled - -- update IPB FIFOs (ready-for-next)? -- - ipb.re(0) <= '1' when (issue_engine.valid(0) = '1') and (issue_engine.ack = '1') else '0'; - ipb.re(1) <= '1' when (issue_engine.valid(1) = '1') and (issue_engine.ack = '1') else '0'; + -- update IPB FIFOs -- + ipb.re(0) <= issue_engine.valid(0) and issue_engine.ack; + ipb.re(1) <= issue_engine.valid(1) and issue_engine.ack; -- **************************************************************************************************************************** @@ -638,10 +636,10 @@ begin -- PC update -- if (execute_engine.pc_we = '1') then - if (execute_engine.pc_mux_sel = '0') then - execute_engine.pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; -- next instruction address - else - execute_engine.pc <= alu_add_i(XLEN-1 downto 1) & '0'; -- jump/taken-branch + if (execute_engine.pc_mux_sel = '0') then -- next (linear) instruction address + execute_engine.pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; + else -- jump/taken-branch + execute_engine.pc <= alu_add_i(XLEN-1 downto 1) & '0'; end if; end if; @@ -826,7 +824,8 @@ begin -- ALU operand B: is immediate? -- case decode_aux.opcode is - when opcode_alui_c | opcode_lui_c | opcode_auipc_c | opcode_load_c | opcode_store_c | opcode_amo_c | opcode_branch_c | opcode_jal_c | opcode_jalr_c => + when opcode_alui_c | opcode_lui_c | opcode_auipc_c | opcode_load_c | opcode_store_c | + opcode_amo_c | opcode_branch_c | opcode_jal_c | opcode_jalr_c => ctrl_nxt.alu_opb_mux <= '1'; when others => ctrl_nxt.alu_opb_mux <= '0'; @@ -836,7 +835,7 @@ begin -- state machine -- case execute_engine.state is - when DISPATCH => -- Wait for ISSUE engine to become ready + when DISPATCH => -- Wait for ISSUE ENGINE to emit valid instruction word -- ------------------------------------------------------------ if (issue_engine.valid(0) = '1') or (issue_engine.valid(1) = '1') then -- new instruction word available if (trap_ctrl.env_pending = '1') or (trap_ctrl.exc_fire = '1') then -- pending trap @@ -846,7 +845,7 @@ begin trap_ctrl.instr_be <= issue_engine.data(34); -- bus access fault during instruction fetch trap_ctrl.instr_ma <= issue_engine.data(33) and (not bool_to_ulogic_f(CPU_EXTENSION_RISCV_C)); -- misaligned instruction fetch (if C disabled) execute_engine.is_ci_nxt <= issue_engine.data(32); -- this is a de-compressed instruction - execute_engine.ir_nxt <= issue_engine.data(31 downto 0); + execute_engine.ir_nxt <= issue_engine.data(31 downto 0); -- instruction word execute_engine.pc_we <= not execute_engine.branched; -- update PC with next_pc if there was no actual branch execute_engine.state_nxt <= EXECUTE; end if; @@ -1001,7 +1000,7 @@ begin execute_engine.pc_we <= '1'; -- update PC with branch DST; will be overridden in DISPATCH if branch not taken end if; if (execute_engine.ir(instr_opcode_lsb_c+2) = '1') or (execute_engine.branch_taken = '1') then -- JAL[R] or taken branch - fetch_engine.reset <= '1'; -- reset instruction fetch starting at modified PC + fetch_engine.reset <= '1'; -- reset instruction fetch to restart at modified PC execute_engine.state_nxt <= BRANCHED; else execute_engine.state_nxt <= DISPATCH; @@ -1039,15 +1038,14 @@ begin if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.opcode(2) = opcode_amo_c(2)) then ctrl_nxt.lsu_rvso <= '1'; -- this is a reservation set operation end if; - ctrl_nxt.rf_mux <= rf_mux_mem_c; -- memory read data + ctrl_nxt.rf_mux <= rf_mux_mem_c; -- RF input = memory read data if (trap_ctrl.exc_buf(exc_laccess_c) = '1') or (trap_ctrl.exc_buf(exc_saccess_c) = '1') or -- bus access error (trap_ctrl.exc_buf(exc_lalign_c) = '1') or (trap_ctrl.exc_buf(exc_salign_c) = '1') then -- alignment error - execute_engine.state_nxt <= DISPATCH; -- abort! - elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction - if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.opcode(2) = opcode_amo_c(2)) then -- atomic operation - ctrl_nxt.rf_wb_en <= '1'; - else -- normal load/store - ctrl_nxt.rf_wb_en <= not execute_engine.ir(instr_opcode_msb_c-1); -- data write-back for load + execute_engine.state_nxt <= DISPATCH; -- abort + elsif (bus_d_wait_i = '0') then -- bus system has completed the transaction + if ((CPU_EXTENSION_RISCV_A = true) and (decode_aux.opcode(2) = opcode_amo_c(2))) or -- atomic operation + (execute_engine.ir(instr_opcode_msb_c-1) = '0') then -- normal load + ctrl_nxt.rf_wb_en <= '1'; -- allow write-back to register file end if; execute_engine.state_nxt <= DISPATCH; end if; @@ -1346,7 +1344,7 @@ begin illegal_cmd <= '0'; end if; - when opcode_fop_c => -- all Zfinx encodings valid if FPU enabled + when opcode_fop_c => -- all encodings valid if FPU enabled -- ------------------------------------------------------------ illegal_cmd <= (not bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zfinx)) or (not decode_aux.is_f_op); @@ -1486,7 +1484,7 @@ begin elsif rising_edge(clk_i) then trap_ctrl.wakeup <= or_reduce_f(trap_ctrl.irq_buf); -- wakeup from sleep on any (enabled! #583) pending IRQ (including debug IRQs) if (trap_ctrl.env_pending = '0') then -- no pending trap environment yet - -- trigger IRQ only in EXECUTE state to continue execution even on permanent IRQ + -- trigger IRQ only in EXECUTE states to *continue execution* even if there are permanent interrupt requests if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and (execute_engine.state = EXECUTE)) then trap_ctrl.env_pending <= '1'; -- now execute engine can start trap handling end if; @@ -1504,7 +1502,7 @@ begin ( (or_reduce_f(trap_ctrl.irq_buf(irq_firq_15_c downto irq_msi_irq_c)) = '1') and -- pending IRQ ((csr.mstatus_mie = '1') or (csr.privilege = priv_mode_u_c)) and -- take IRQ when in M-mode and MIE=1 OR when in U-mode - (debug_ctrl.running = '0') and (csr.dcsr_step = '0') -- no IRQs when in single-stepping mode or during single-stepping + (debug_ctrl.running = '0') and (csr.dcsr_step = '0') -- no IRQs when in debug-mode or during debug single-stepping ) or (trap_ctrl.irq_buf(irq_db_step_c) = '1') or -- debug-mode single-step IRQ (trap_ctrl.irq_buf(irq_db_halt_c) = '1') else '0'; -- debug-mode halt IRQ @@ -1528,7 +1526,7 @@ begin elsif (trap_ctrl.exc_buf(exc_lalign_c) = '1') then trap_ctrl.cause <= trap_lma_c; -- load address misaligned elsif (trap_ctrl.exc_buf(exc_saccess_c) = '1') then trap_ctrl.cause <= trap_saf_c; -- store access fault elsif (trap_ctrl.exc_buf(exc_laccess_c) = '1') then trap_ctrl.cause <= trap_laf_c; -- load access fault - -- debug mode exceptions and interrupts -- + -- standard RISC-V debug mode exceptions and interrupts -- elsif (trap_ctrl.irq_buf(irq_db_halt_c) = '1') then trap_ctrl.cause <= trap_db_halt_c; -- external halt request (async) elsif (trap_ctrl.exc_buf(exc_db_hw_c) = '1') then trap_ctrl.cause <= trap_db_trig_c; -- hardware trigger (sync) elsif (trap_ctrl.exc_buf(exc_db_break_c) = '1') then trap_ctrl.cause <= trap_db_break_c; -- break instruction (sync) @@ -1641,11 +1639,9 @@ begin csr.tdata2 <= (others => '0'); elsif rising_edge(clk_i) then - -- write access? -- - csr.we <= csr.we_nxt and (not trap_ctrl.exc_buf(exc_iillegal_c)); -- write if not an illegal instruction - -- defaults -- - csr.mip_firq_nclr <= (others => '1'); -- active low + csr.we <= csr.we_nxt and (not trap_ctrl.exc_buf(exc_iillegal_c)); -- write if not an illegal instruction + csr.mip_firq_nclr <= (others => '1'); -- inactive FIRQ clear (active low) -- ******************************************************************************** -- CSR access by application software @@ -1763,85 +1759,76 @@ begin end case; - -- ******************************************************************************** - -- Automatic CSR access by hardware + -- Hardware CSR access: TRAP ENTER -- ******************************************************************************** - else - - -- -------------------------------------------------------------------- - -- TRAP ENTER - -- -------------------------------------------------------------------- - if (trap_ctrl.env_enter = '1') then - - -- NORMAL trap entry - no CSR update when in debug-mode! -- - if (CPU_EXTENSION_RISCV_Sdext = false) or ((trap_ctrl.cause(5) = '0') and (debug_ctrl.running = '0')) then - csr.mcause <= trap_ctrl.cause(trap_ctrl.cause'left) & trap_ctrl.cause(4 downto 0); -- trap type & identifier - csr.mepc <= trap_ctrl.epc(XLEN-1 downto 1) & '0'; -- trap PC - -- trap value -- - if (trap_ctrl.cause(6) = '0') and (trap_ctrl.cause(4 downto 2) = trap_lma_c(4 downto 2)) then -- load/store misaligned/fault - csr.mtval <= mar_i; -- faulting data access address - else -- everything else including all interrupts - csr.mtval <= (others => '0'); - end if; - -- trap instruction -- - if (trap_ctrl.cause(6) = '0') then -- exception - csr.mtinst <= execute_engine.ir; - if (execute_engine.is_ci = '1') and (CPU_EXTENSION_RISCV_C = true) then - csr.mtinst(1) <= '0'; -- RISC-V priv. spec: clear bit 1 if compressed instruction - end if; - else -- interrupt - csr.mtinst <= (others => '0'); - end if; - -- update privilege level and interrupt-enable stack -- - csr.privilege <= priv_mode_m_c; -- execute trap in machine mode - csr.mstatus_mie <= '0'; -- disable interrupts - csr.mstatus_mpie <= csr.mstatus_mie; -- backup previous mie state - csr.mstatus_mpp <= csr.privilege; -- backup previous privilege mode + elsif (trap_ctrl.env_enter = '1') then + + -- NORMAL trap entry - no CSR update when in debug-mode! -- + if (CPU_EXTENSION_RISCV_Sdext = false) or ((trap_ctrl.cause(5) = '0') and (debug_ctrl.running = '0')) then + csr.mcause <= trap_ctrl.cause(trap_ctrl.cause'left) & trap_ctrl.cause(4 downto 0); -- trap type & identifier + csr.mepc <= trap_ctrl.epc(XLEN-1 downto 1) & '0'; -- trap PC + -- trap value -- + if (trap_ctrl.cause(6) = '0') and (trap_ctrl.cause(4 downto 2) = trap_lma_c(4 downto 2)) then -- load/store misaligned/fault + csr.mtval <= mar_i; -- faulting data access address + else -- everything else including all interrupts + csr.mtval <= (others => '0'); end if; - - -- DEBUG MODE entry - no CSR update when already in debug-mode! -- - if (CPU_EXTENSION_RISCV_Sdext = true) and (trap_ctrl.cause(5) = '1') and (debug_ctrl.running = '0') then - -- trap cause -- - 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 -- - csr.dpc <= trap_ctrl.epc(XLEN-1 downto 1) & '0'; + -- trap instruction -- + if (trap_ctrl.cause(6) = '0') then -- exception + csr.mtinst <= execute_engine.ir; + if (execute_engine.is_ci = '1') and (CPU_EXTENSION_RISCV_C = true) then + csr.mtinst(1) <= '0'; -- RISC-V priv. spec: clear bit 1 if compressed instruction + end if; + else -- interrupt + csr.mtinst <= (others => '0'); end if; + -- update privilege level and interrupt-enable stack -- + csr.privilege <= priv_mode_m_c; -- execute trap in machine mode + csr.mstatus_mie <= '0'; -- disable interrupts + csr.mstatus_mpie <= csr.mstatus_mie; -- backup previous mie state + csr.mstatus_mpp <= csr.privilege; -- backup previous privilege mode + end if; - -- -------------------------------------------------------------------- - -- TRAP EXIT - -- -------------------------------------------------------------------- - elsif (trap_ctrl.env_exit = '1') then + -- DEBUG MODE entry - no CSR update when already in debug-mode! -- + if (CPU_EXTENSION_RISCV_Sdext = true) and (trap_ctrl.cause(5) = '1') and (debug_ctrl.running = '0') then + -- trap cause -- + 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 -- + csr.dpc <= trap_ctrl.epc(XLEN-1 downto 1) & '0'; + end if; - -- return from debug mode trap -- - if (CPU_EXTENSION_RISCV_Sdext = true) and (debug_ctrl.running = '1') then - if (CPU_EXTENSION_RISCV_U = true) then - csr.privilege <= csr.dcsr_prv; - if (csr.dcsr_prv /= priv_mode_m_c) then - csr.mstatus_mprv <= '0'; -- clear if return to priv. mode less than M - end if; + -- ******************************************************************************** + -- Hardware CSR access: TRAP EXIT + -- ******************************************************************************** + elsif (trap_ctrl.env_exit = '1') then + + -- return from debug mode trap -- + if (CPU_EXTENSION_RISCV_Sdext = true) and (debug_ctrl.running = '1') then + if (CPU_EXTENSION_RISCV_U = true) then + csr.privilege <= csr.dcsr_prv; + if (csr.dcsr_prv /= priv_mode_m_c) then + csr.mstatus_mprv <= '0'; -- clear if return to priv. mode less than M end if; + end if; - -- return from normal trap -- - else - if (CPU_EXTENSION_RISCV_U = true) then - csr.privilege <= csr.mstatus_mpp; -- restore previous privilege mode - csr.mstatus_mpp <= priv_mode_u_c; -- set to least-privileged mode that is supported - if (csr.mstatus_mpp /= priv_mode_m_c) then - csr.mstatus_mprv <= '0'; -- clear if return to priv. mode less than M - end if; + -- return from normal trap -- + else + if (CPU_EXTENSION_RISCV_U = true) then + csr.privilege <= csr.mstatus_mpp; -- restore previous privilege mode + csr.mstatus_mpp <= priv_mode_u_c; -- set to least-privileged mode that is supported + if (csr.mstatus_mpp /= priv_mode_m_c) then + csr.mstatus_mprv <= '0'; -- clear if return to priv. mode less than M end if; - csr.mstatus_mie <= csr.mstatus_mpie; -- restore machine-mode IRQ enable flag - csr.mstatus_mpie <= '1'; end if; - + csr.mstatus_mie <= csr.mstatus_mpie; -- restore machine-mode IRQ enable flag + csr.mstatus_mpie <= '1'; end if; end if; - -- ******************************************************************************** -- Override - hardwire/terminate unimplemented registers/bits -- ******************************************************************************** @@ -1885,7 +1872,7 @@ begin csr.dscratch0 <= (others => '0'); end if; - -- no trigger module-- + -- no trigger module -- if (CPU_EXTENSION_RISCV_Sdtrig = false) then csr.tdata1_exe <= '0'; csr.tdata1_action <= '0'; @@ -2402,7 +2389,7 @@ begin csr.tdata1_rd(26 downto 21) <= "000000"; -- maskmax: only exact values csr.tdata1_rd(20) <= '0'; -- hit: feature not implemented csr.tdata1_rd(19) <= '0'; -- select: fire on address match - csr.tdata1_rd(18) <= '1'; -- timing: trigger AFTER executing the triggering instruction + csr.tdata1_rd(18) <= '1'; -- timing: trigger AFTER executing the programmed instruction address csr.tdata1_rd(17 downto 16) <= "00"; -- sizelo: match against an access of any size csr.tdata1_rd(15 downto 12) <= "000" & csr.tdata1_action; -- action = 1: enter debug mode on trigger, action = 0: ebreak exception on trigger csr.tdata1_rd(11) <= '0'; -- chain: chaining not supported - there is only one trigger diff --git a/rtl/core/neorv32_cpu_cp_bitmanip.vhd b/rtl/core/neorv32_cpu_cp_bitmanip.vhd index 38afc5386..be00521b6 100644 --- a/rtl/core/neorv32_cpu_cp_bitmanip.vhd +++ b/rtl/core/neorv32_cpu_cp_bitmanip.vhd @@ -171,13 +171,13 @@ begin -- Sub-Extension Configuration ------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- assert false report - "NEORV32 CPU: Implementing bit-manipulation (B) sub-extensions " & - cond_sel_string_f(zba_en_c, "Zba ", "") & - cond_sel_string_f(zbb_en_c, "Zbb ", "") & - cond_sel_string_f(zbc_en_c, "Zbc ", "") & - cond_sel_string_f(zbs_en_c, "Zbs ", "") & - "" - severity note; + "NEORV32 CPU: Implementing bit-manipulation (B) sub-extensions " & + cond_sel_string_f(zba_en_c, "Zba ", "") & + cond_sel_string_f(zbb_en_c, "Zbb ", "") & + cond_sel_string_f(zbc_en_c, "Zbc ", "") & + cond_sel_string_f(zbs_en_c, "Zbs ", "") & + "" + severity note; -- Instruction Decoding (One-Hot) --------------------------------------------------------- diff --git a/rtl/core/neorv32_cpu_cp_muldiv.vhd b/rtl/core/neorv32_cpu_cp_muldiv.vhd index c5f9a032c..27ed47e08 100644 --- a/rtl/core/neorv32_cpu_cp_muldiv.vhd +++ b/rtl/core/neorv32_cpu_cp_muldiv.vhd @@ -169,6 +169,7 @@ begin when others => -- undefined ctrl.state <= S_IDLE; + end case; end if; end process coprocessor_ctrl; diff --git a/rtl/core/neorv32_cpu_cp_shifter.vhd b/rtl/core/neorv32_cpu_cp_shifter.vhd index 650dc6081..b16fc2cba 100644 --- a/rtl/core/neorv32_cpu_cp_shifter.vhd +++ b/rtl/core/neorv32_cpu_cp_shifter.vhd @@ -66,8 +66,8 @@ architecture neorv32_cpu_cp_shifter_rtl of neorv32_cpu_cp_shifter is -- serial shifter -- type shifter_t is record busy : std_ulogic; - busy_ff : std_ulogic; done : std_ulogic; + done_ff : std_ulogic; cnt : std_ulogic_vector(index_size_f(XLEN)-1 downto 0); sreg : std_ulogic_vector(XLEN-1 downto 0); end record; @@ -89,13 +89,13 @@ begin serial_shifter_core: process(rstn_i, clk_i) begin if (rstn_i = '0') then - shifter.busy_ff <= '0'; shifter.busy <= '0'; + shifter.done_ff <= '0'; shifter.cnt <= (others => '0'); shifter.sreg <= (others => '0'); elsif rising_edge(clk_i) then -- arbitration -- - shifter.busy_ff <= shifter.busy; + shifter.done_ff <= shifter.busy and shifter.done; if (start_i = '1') then shifter.busy <= '1'; elsif (shifter.done = '1') or (ctrl_i.cpu_trap = '1') then -- abort on trap @@ -119,7 +119,7 @@ begin -- shift control/output -- shifter.done <= '1' when (or_reduce_f(shifter.cnt(shifter.cnt'left downto 1)) = '0') else '0'; valid_o <= shifter.busy and shifter.done; - res_o <= shifter.sreg when (shifter.busy = '0') and (shifter.busy_ff = '1') else (others => '0'); + res_o <= shifter.sreg when (shifter.done_ff = '1') else (others => '0'); end generate; -- /serial_shifter diff --git a/rtl/core/neorv32_cpu_pmp.vhd b/rtl/core/neorv32_cpu_pmp.vhd index a7470658b..239e419de 100644 --- a/rtl/core/neorv32_cpu_pmp.vhd +++ b/rtl/core/neorv32_cpu_pmp.vhd @@ -223,14 +223,14 @@ begin begin addr_rd(i) <= (others => '0'); addr_rd(i)(XLEN-1 downto pmp_lsb_c-2) <= csr.addr(i)(XLEN-1 downto pmp_lsb_c-2); - if (GRANULARITY = 8) then -- bit [G-1] reads as zero in TOR or OFF mode + if (GRANULARITY = 8) then -- bit G-1 reads as zero in TOR or OFF mode if (csr.cfg(i)(cfg_ah_c) = '0') then -- TOR/OFF mode addr_rd(i)(pmp_lsb_c) <= '0'; end if; elsif (GRANULARITY > 8) then - addr_rd(i)(pmp_lsb_c-2 downto 0) <= (others => '1'); -- in NAPOT mode bits [G-2:0] must read as one + addr_rd(i)(pmp_lsb_c-2 downto 0) <= (others => '1'); -- in NAPOT mode bits G-2:0 must read as one if (csr.cfg(i)(cfg_ah_c) = '0') then -- TOR/OFF mode - addr_rd(i)(pmp_lsb_c-1 downto 0) <= (others => '0'); -- in TOR or OFF mode bits [G-1:0] must read as zero + addr_rd(i)(pmp_lsb_c-1 downto 0) <= (others => '0'); -- in TOR or OFF mode bits G-1:0 must read as zero end if; end if; end process address_read_back; diff --git a/rtl/core/neorv32_cpu_regfile.vhd b/rtl/core/neorv32_cpu_regfile.vhd index ee52f0d79..2cec968c2 100644 --- a/rtl/core/neorv32_cpu_regfile.vhd +++ b/rtl/core/neorv32_cpu_regfile.vhd @@ -120,7 +120,7 @@ begin -- write enable -- rd_zero <= '1' when (ctrl_i.rf_rd = "00000") else '0'; - rf_we <= (ctrl_i.rf_wb_en and (not rd_zero)) or ctrl_i.rf_zero_we; -- do not write to x0 unless explicitly forced + rf_we <= (ctrl_i.rf_wb_en and (not rd_zero)) or ctrl_i.rf_zero_we; -- do not allow writes to x0 unless explicitly forced -- Register File -------------------------------------------------------------------------- diff --git a/rtl/core/neorv32_crc.vhd b/rtl/core/neorv32_crc.vhd index 2beee15c5..7837da9a7 100644 --- a/rtl/core/neorv32_crc.vhd +++ b/rtl/core/neorv32_crc.vhd @@ -153,14 +153,10 @@ begin end process crc_core; -- operation mode -- - mode_select: process(crc) - begin - case crc.mode is - when "00" => crc.msb <= crc.sreg(07); -- crc8 - when "01" => crc.msb <= crc.sreg(15); -- crc16 - when others => crc.msb <= crc.sreg(31); -- crc32 - end case; - end process mode_select; + with crc.mode select crc.msb <= + crc.sreg(07) when "00", -- crc8 + crc.sreg(15) when "01", -- crc16 + crc.sreg(31) when others; -- crc32 end neorv32_crc_rtl; diff --git a/rtl/core/neorv32_intercon.vhd b/rtl/core/neorv32_intercon.vhd index c01e469d8..d90768285 100644 --- a/rtl/core/neorv32_intercon.vhd +++ b/rtl/core/neorv32_intercon.vhd @@ -112,7 +112,6 @@ begin a_req_pending <= (a_rd_req_buf or a_wr_req_buf) when (PORT_A_READ_ONLY = false) else a_rd_req_buf; b_req_pending <= (b_rd_req_buf or b_wr_req_buf) when (PORT_B_READ_ONLY = false) else b_rd_req_buf; - -- FSM -- arbiter_comb: process(arbiter, a_req_current, b_req_current, a_req_pending, b_req_pending, a_rd_req_buf, a_wr_req_buf, b_rd_req_buf, b_wr_req_buf, x_rsp_i) @@ -399,7 +398,7 @@ begin response: process(imem_rsp_i, dmem_rsp_i, boot_rsp_i, xip_rsp_i, io_rsp_i, ext_rsp_i) variable tmp_v : bus_rsp_t; begin - tmp_v := rsp_terminate_c; -- start will all-zero + tmp_v := rsp_terminate_c; -- start with all-zero if (IMEM_ENABLE = true) then tmp_v.data := tmp_v.data or imem_rsp_i.data; tmp_v.ack := tmp_v.ack or imem_rsp_i.ack; @@ -451,7 +450,6 @@ begin elsif rising_edge(clk_i) then keeper.err <= '0'; -- default keeper.halt <= port_sel(port_xip_c) or port_sel(port_ext_c); -- no timeout if XIP or EXTERNAL access - -- fsm -- if (keeper.busy = '0') then -- bus idle keeper.cnt <= std_ulogic_vector(to_unsigned(TIMEOUT, keeper.cnt'length)); if (main_req_i.re = '1') or (main_req_i.we = '1') then @@ -548,8 +546,8 @@ entity neorv32_bus_io_switch is ); port ( -- host port -- - main_req_i : in bus_req_t; -- host request - main_rsp_o : out bus_rsp_t; -- host response + main_req_i : in bus_req_t; -- host request + main_rsp_o : out bus_rsp_t; -- host response -- device ports -- dev_00_req_o : out bus_req_t; dev_00_rsp_i : in bus_rsp_t; dev_01_req_o : out bus_req_t; dev_01_rsp_i : in bus_rsp_t; @@ -582,7 +580,7 @@ architecture neorv32_bus_io_switch_rtl of neorv32_bus_io_switch is -- ------------------------------------------------------------------------------------------- -- -- 1. Increment (must not exceed ). -- -- 2. Append another pair of "DEV_xx_EN" and "DEV_xx_BASE" generics. -- - -- 3. Append these two generics to the according and arrays. -- + -- 3. Append these two generics to the according and arrays. -- -- 4. Append another pair of "dev_xx_req_o" and "dev_xx_rsp_i" ports. -- -- 5. Append these two ports to the according and array assignments in -- -- the "Combine Device Ports" section. -- @@ -596,17 +594,6 @@ architecture neorv32_bus_io_switch_rtl of neorv32_bus_io_switch is constant abb_lo_c : natural := index_size_f(DEV_SIZE); -- low address boundary bit constant abb_hi_c : natural := (index_size_f(DEV_SIZE) + index_size_f(num_devs_logical_c)) - 1; -- high address boundary bit - -- list of device base addresses -- - type dev_base_list_t is array (0 to num_devs_physical_c-1) of std_ulogic_vector(31 downto 0); - constant dev_base_list_c : dev_base_list_t := ( - DEV_00_BASE, DEV_01_BASE, DEV_02_BASE, DEV_03_BASE, - DEV_04_BASE, DEV_05_BASE, DEV_06_BASE, DEV_07_BASE, - DEV_08_BASE, DEV_09_BASE, DEV_10_BASE, DEV_11_BASE, - DEV_12_BASE, DEV_13_BASE, DEV_14_BASE, DEV_15_BASE, - DEV_16_BASE, DEV_17_BASE, DEV_18_BASE, DEV_19_BASE, - DEV_20_BASE - ); - -- list of enabled device ports -- type dev_en_list_t is array (0 to num_devs_physical_c-1) of boolean; constant dev_en_list_c : dev_en_list_t := ( @@ -618,6 +605,17 @@ architecture neorv32_bus_io_switch_rtl of neorv32_bus_io_switch is DEV_20_EN ); + -- list of device base addresses -- + type dev_base_list_t is array (0 to num_devs_physical_c-1) of std_ulogic_vector(31 downto 0); + constant dev_base_list_c : dev_base_list_t := ( + DEV_00_BASE, DEV_01_BASE, DEV_02_BASE, DEV_03_BASE, + DEV_04_BASE, DEV_05_BASE, DEV_06_BASE, DEV_07_BASE, + DEV_08_BASE, DEV_09_BASE, DEV_10_BASE, DEV_11_BASE, + DEV_12_BASE, DEV_13_BASE, DEV_14_BASE, DEV_15_BASE, + DEV_16_BASE, DEV_17_BASE, DEV_18_BASE, DEV_19_BASE, + DEV_20_BASE + ); + -- device ports combined as arrays -- type dev_req_t is array (num_devs_physical_c-1 downto 0) of bus_req_t; type dev_rsp_t is array (num_devs_physical_c-1 downto 0) of bus_rsp_t; @@ -661,8 +659,7 @@ begin access_gen_enabled: if (dev_en_list_c(i) = true) generate - dev_sel(i) <= '1' when main_req_i.addr(abb_hi_c downto abb_lo_c) = dev_base_list_c(i)(abb_hi_c downto abb_lo_c) else '0'; - -- + dev_sel(i) <= '1' when main_req_i.addr(abb_hi_c downto abb_lo_c) = dev_base_list_c(i)(abb_hi_c downto abb_lo_c) else '0'; dev_req(i).addr <= main_req_i.addr; dev_req(i).data <= main_req_i.data; dev_req(i).ben <= main_req_i.ben; @@ -819,7 +816,7 @@ begin rsvs.state <= "00"; -- invalidate reservation elsif (core_req_i.we = '1') then -- write access - if (core_req_i.rvso = '1') then -- store-conditional instruction + if (core_req_i.rvso = '1') then -- store-conditional to reservated address if (rsvs.match = '1') then -- SC to reservated address rsvs.state <= "11"; -- execute SC instruction (reservation still valid) else -- SC to any other address (new reservation attempt while the current one is still valid) diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 7a07db110..5c57fd30a 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -56,7 +56,7 @@ package neorv32_package is -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080805"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080806"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width, do not change! @@ -609,15 +609,15 @@ package neorv32_package is -- MSB: 1 = interrupt, 0 = sync. exception -- MSB-1: 1 = entry to debug mode, 0 = normal trapping -- RISC-V compliant synchronous exceptions -- - constant trap_ima_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00000"; -- 0: instruction misaligned - constant trap_iaf_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00001"; -- 1: instruction access fault - constant trap_iil_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00010"; -- 2: illegal instruction - constant trap_brk_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00011"; -- 3: breakpoint - constant trap_lma_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00100"; -- 4: load address misaligned - constant trap_laf_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00101"; -- 5: load access fault - constant trap_sma_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00110"; -- 6: store address misaligned - constant trap_saf_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00111"; -- 7: store access fault - constant trap_env_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "010UU"; -- 8..11: environment call from u/s/h/m + constant trap_ima_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00000"; -- 0: instruction misaligned + constant trap_iaf_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00001"; -- 1: instruction access fault + constant trap_iil_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00010"; -- 2: illegal instruction + constant trap_brk_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00011"; -- 3: breakpoint + constant trap_lma_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00100"; -- 4: load address misaligned + constant trap_laf_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00101"; -- 5: load access fault + constant trap_sma_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00110"; -- 6: store address misaligned + constant trap_saf_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "00111"; -- 7: store access fault + constant trap_env_c : std_ulogic_vector(6 downto 0) := "0" & "0" & "010UU"; -- 8..11: environment call from u/s/h/m -- RISC-V compliant asynchronous exceptions (interrupts) -- constant trap_msi_c : std_ulogic_vector(6 downto 0) := "1" & "0" & "00011"; -- 3: machine software interrupt constant trap_mti_c : std_ulogic_vector(6 downto 0) := "1" & "0" & "00111"; -- 7: machine timer interrupt