Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refine behaviour of CPU sleep signal #746

Merged
merged 4 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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