Skip to content

Commit

Permalink
refine behaviour of CPU sleep signal (#746)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting committed Dec 9, 2023
2 parents 273714b + ab1aa4a commit f63236c
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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** | |
Expand Down
23 changes: 12 additions & 11 deletions docs/datasheet/cpu.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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 "parked" in a safe/resumable
state the `sleep_o` signal becomes high (see <<_cpu_top_entity_signals>>).


==== Full Virtualization
Expand Down Expand Up @@ -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>>)**
Expand Down
33 changes: 20 additions & 13 deletions rtl/core/neorv32_cpu_control.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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 --
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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';
Expand Down
2 changes: 1 addition & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -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!

Expand Down

0 comments on commit f63236c

Please sign in to comment.