From 0a87b94da1043cd65d1c736bcc43470bdeb7e773 Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Fri, 8 Dec 2023 07:53:41 +0100 Subject: [PATCH 1/4] [docs] update description of CPU sleep signal --- docs/datasheet/cpu.adoc | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc index 828ff6062..bd4da6932 100644 --- a/docs/datasheet/cpu.adoc +++ b/docs/datasheet/cpu.adoc @@ -197,17 +197,18 @@ includes the <<_control_and_status_registers_csrs>> as well as the trap controll ==== Sleep Mode The NEORV32 CPU provides a single sleep mode that can be entered to power-down the core reducing dynamic -power consumption. Sleep mode in entered by executing the `wfi` instruction. When in sleep mode, all CPU-internal -operations are stopped (execution, instruction fetch, counter increments, ...). However, this does not affect the -operation of any peripheral/IO modules like interfaces and timers. Furthermore, the CPU will continue to buffer/enqueue -incoming interrupt requests. The CPU will leave sleep mode as soon as any _enabled_ interrupt source becomes _pending_. - -[IMPORTANT] -If sleep mode is entered without at least one enabled interrupt source the CPU will be _permanently_ halted. +power consumption. Sleep mode is entered by executing the `wfi` ("wait for interrupt") instruction. [NOTE] -The CPU automatically wakes up from sleep mode if a debug session is started via the on-chip debugger. `wfi` behaves as -a simple `nop` when the CPU is _in_ debug-mode or during single-stepping. +The `wfi` instruction will raise an illegal instruction exception when executed in user-mode +and `TW` in <<_mstatus>> is set. When executed in debug-mode or during single-stepping `wfi` will behave as +simple `nop`. + +In sleep mode all CPU-internal operations are stopped (execution, instruction fetch, counter increments, etc.). +CPU-external modules like memories, timers and peripheral interfaces are not affected by this. Furthermore, the CPU will +continue to buffer/enqueue incoming interrupt requests. The CPU will leave sleep mode as soon as any _enabled (via <<_mie>>) +interrupt source becomes _pending_ or if a debug session is started. As soon as the CPU has halted **all** internal +operations the `sleep_o` signal becomes high (see <<_cpu_top_entity_signals>>). ==== Full Virtualization @@ -340,8 +341,8 @@ direction as seen from the CPU. 4+^| **Global Signals** | `clk_i` | 1 | in | Global clock line, all registers triggering on rising edge | `rstn_i` | 1 | in | Global reset, low-active -| `sleep_o` | 1 | out | CPU is in sleep mode when set -| `debug_o` | 1 | out | CPU is in debug mode when set +| `sleep_o` | 1 | out | CPU is in <<_sleep_mode>> when set +| `debug_o` | 1 | out | CPU is in <<_cpu_debug_mode,debug mode>> when set | `ifence_o` | 1 | out | instruction fence (`fence.i` instruction ) | `dfence_o` | 1 | out | data fence (`fence` instruction ) 4+^| **Interrupts (<<_traps_exceptions_and_interrupts>>)** From e2931c757beb42f643b55b50c5ffca0368968306 Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sat, 9 Dec 2023 09:36:29 +0100 Subject: [PATCH 2/4] [rtl] refine beviour of sleep signal --- rtl/core/neorv32_cpu_control.vhd | 33 +++++++++++++++++++------------- rtl/core/neorv32_package.vhd | 2 +- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/rtl/core/neorv32_cpu_control.vhd b/rtl/core/neorv32_cpu_control.vhd index f18b05f2b..8008f48ac 100644 --- a/rtl/core/neorv32_cpu_control.vhd +++ b/rtl/core/neorv32_cpu_control.vhd @@ -132,14 +132,14 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is constant hpm_cnt_hi_width_c : natural := natural(cond_sel_int_f(boolean(HPM_CNT_WIDTH > 32), HPM_CNT_WIDTH-32, 0)); -- width high word -- instruction fetch engine -- - type fetch_engine_state_t is (IF_RESTART, IF_REQUEST, IF_PENDING); + type fetch_engine_state_t is (IF_RESTART, IF_REQUEST, IF_PENDING, IF_PARKED); type fetch_engine_t is record state : fetch_engine_state_t; state_prev : fetch_engine_state_t; - restart : std_ulogic; - unaligned : std_ulogic; + restart : std_ulogic; -- buffered restart request (after branch) + unaligned : std_ulogic; -- fetching from non-32-bit address pc : std_ulogic_vector(XLEN-1 downto 0); - reset : std_ulogic; + reset : std_ulogic; -- restart request (after branch) resp : std_ulogic; -- bus response end record; signal fetch_engine : fetch_engine_t; @@ -391,6 +391,8 @@ begin -- ------------------------------------------------------------ if (ipb.free = "11") then -- wait for free IPB space fetch_engine.state <= IF_PENDING; + elsif (execute_engine.state = SLEEP) then -- halt request (sleep)? + fetch_engine.state <= IF_PARKED; end if; when IF_PENDING => -- wait for bus response and write instruction data to prefetch buffer @@ -405,6 +407,12 @@ begin end if; end if; + when IF_PARKED => -- park position: instruction fetch is halted (CPU in sleep mode) + -- ------------------------------------------------------------ + if (execute_engine.state /= SLEEP) then + fetch_engine.state <= IF_REQUEST; + end if; + when others => -- undefined -- ------------------------------------------------------------ fetch_engine.state <= IF_RESTART; @@ -421,7 +429,6 @@ begin bus_req_o.stb <= '1' when (fetch_engine.state = IF_REQUEST) and (ipb.free = "11") else '0'; -- instruction bus response -- - -- [NOTE] PMP and alignment errors will keep pending until the triggered bus access request retires fetch_engine.resp <= '1' when (bus_rsp_i.ack = '1') or (bus_rsp_i.err = '1') else '0'; -- IPB instruction data and status -- @@ -653,6 +660,11 @@ begin execute_engine.pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; end if; + -- link PC: return address -- + if (execute_engine.state = BRANCH) then + execute_engine.link_pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; + end if; + -- next PC: address of next instruction -- case execute_engine.state is @@ -688,11 +700,6 @@ begin NULL; end case; - - -- link PC: return address -- - if (execute_engine.state = BRANCH) then - execute_engine.link_pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; - end if; end if; end process execute_engine_fsm_sync; @@ -1027,7 +1034,7 @@ begin ctrl_nxt.rf_wb_en <= execute_engine.ir(instr_opcode_lsb_c+2); -- save return address if link operation (will not happen if misaligned) if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (execute_engine.branch_taken = '1') then -- valid taken branch fetch_engine.reset <= '1'; -- reset instruction fetch to restart at modified PC - execute_engine.state_nxt <= BRANCHED; + execute_engine.state_nxt <= BRANCHED; -- shortcut (faster than going to RESTART) else execute_engine.state_nxt <= DISPATCH; end if; @@ -1131,7 +1138,7 @@ begin -- cpu status -- ctrl_o.cpu_priv <= csr.privilege_eff; - ctrl_o.cpu_sleep <= '1' when (execute_engine.state = SLEEP) else '0'; + ctrl_o.cpu_sleep <= '1' when (execute_engine.state = SLEEP) and (fetch_engine.state = IF_PARKED) else '0'; ctrl_o.cpu_trap <= trap_ctrl.env_enter; ctrl_o.cpu_debug <= debug_ctrl.running; @@ -1385,7 +1392,7 @@ begin -- ------------------------------------------------------------------------------------------- trap_ctrl.instr_il <= '1' when ((execute_engine.state = EXECUTE) or (execute_engine.state = ALU_WAIT)) and -- check in execution states only ( - (monitor.exc = '1') or -- execution monitor exception + (monitor.exc = '1') or -- execution monitor exception (multi-cycle instruction timeout) (illegal_cmd = '1') or -- illegal instruction? (execute_engine.ir(instr_opcode_lsb_c+1 downto instr_opcode_lsb_c) /= "11") -- illegal opcode LSBs? ) else '0'; diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 332a69668..dfcee5f22 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"01090202"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090203"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width, do not change! From ff7caa0a8f4376d6471b2917b9d1f85c4326da4e Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sat, 9 Dec 2023 09:39:56 +0100 Subject: [PATCH 3/4] [changelog] add v1.9.2.3 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89d6577e3..db7c0a33c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date | Version | Comment | Link | |:----:|:-------:|:--------|:----:| +| 09.12.2023 | 1.9.2.3 | refine behavior of CPU's sleep state & signal | [#746](https://github.com/stnolting/neorv32/pull/746) | | 05.12.2023 | 1.9.2.2 | reset `mstatus.mpp` to "machine-mode" | [#745](https://github.com/stnolting/neorv32/pull/745) | | 02.12.2023 | 1.9.2.1 | :sparkles: add RISC-V `Zicond` ISA extension (integer conditional operations) | [#743](https://github.com/stnolting/neorv32/pull/743) | | 01.12.2023 | [**:rocket:1.9.2**](https://github.com/stnolting/neorv32/releases/tag/v1.9.2) | **New release** | | From ab1aa4ad7bdbef9549363ce7abe61f77a24c9143 Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sat, 9 Dec 2023 09:41:30 +0100 Subject: [PATCH 4/4] [docs] minor edits --- docs/datasheet/cpu.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc index bd4da6932..607f8822a 100644 --- a/docs/datasheet/cpu.adoc +++ b/docs/datasheet/cpu.adoc @@ -207,8 +207,8 @@ simple `nop`. In sleep mode all CPU-internal operations are stopped (execution, instruction fetch, counter increments, etc.). CPU-external modules like memories, timers and peripheral interfaces are not affected by this. Furthermore, the CPU will continue to buffer/enqueue incoming interrupt requests. The CPU will leave sleep mode as soon as any _enabled (via <<_mie>>) -interrupt source becomes _pending_ or if a debug session is started. As soon as the CPU has halted **all** internal -operations the `sleep_o` signal becomes high (see <<_cpu_top_entity_signals>>). +interrupt source becomes _pending_ or if a debug session is started. As soon as the CPU has "parked" in a safe/resumable +state the `sleep_o` signal becomes high (see <<_cpu_top_entity_signals>>). ==== Full Virtualization