diff --git a/CHANGELOG.md b/CHANGELOG.md
index d21581ac1..9036701d5 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 |
|:----:|:-------:|:--------|:----:|
+| 24.01.2024 | 1.9.3.4 | :sparkles: add optional CPU clock gating (via new generic `CLOCK_GATING_EN`): shut down the CPU clock during sleep mode; :warning: add new HDL design file for the clock gate (`neorv32_clockgate.vhd`) | [#775](https://github.com/stnolting/neorv32/pull/775) |
| 23.01.2024 | 1.9.3.3 | :bug: remove compressed floating point load/store operations as they are **not** supported by `Zfinx` | [#](https://github.com/stnolting/neorv32/pull/771) |
| 20.01.2024 | 1.9.3.2 | optimize bus switch; minor RTL and comment edits | [#769](https://github.com/stnolting/neorv32/pull/769) |
| 14.01.2024 | 1.9.3.1 | minor rtl cleanups and optimizations | [#764](https://github.com/stnolting/neorv32/pull/764) |
diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc
index a4db38626..fb49e5060 100644
--- a/docs/datasheet/cpu.adoc
+++ b/docs/datasheet/cpu.adoc
@@ -196,19 +196,31 @@ 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 is entered by executing the `wfi` ("wait for interrupt") instruction.
+The NEORV32 CPU provides a single sleep mode that can be entered to power-down the core reducing
+dynamic power consumption. Sleep mode is entered by executing the `wfi` ("wait for interrupt") instruction.
[NOTE]
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`.
+if `TW` in <<_mstatus>> is set. When executed in debug-mode or during single-stepping `wfi` will behave as
+simple `nop` without entering sleep mode.
+
+After executing the `wfi` instruction the CPU's `sleep_o` signal (<<_cpu_top_entity_signals>>) will become set
+as soon as the CPU has fully halted ("CPU is sleeping"):
+
+[start=1]
+.The front-end (instruction fetch) is stopped. There is no pending instruction fetch bus access.
+.The back-end (instruction execution) is stopped. There is no pending data bus access.
+.There is not enabled interrupt pending.
-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>>).
+continue to buffer/enqueue incoming interrupt. The CPU will leave sleep mode as soon as any _enabled (via <<_mie>>)
+interrupt source becomes _pending_ or if a debug session is started.
+
+===== Power-Down Mode
+
+Optionally, the sleep mode can also be used to shut down the CPU's main clock to further reduce power consumption
+by halting the core's clock tree. This clock gating mode is enabled by the `CLOCK_GATING_EN` generic
+(<<_processor_top_entity_generics>>). See section <<_processor_clocking>> for more information.
==== Full Virtualization
@@ -339,7 +351,8 @@ direction as seen from the CPU.
|=======================
| Signal | Width/Type | Dir | Description
4+^| **Global Signals**
-| `clk_i` | 1 | in | Global clock line, all registers triggering on rising edge
+| `clk_i` | 1 | in | Global clock line, all registers triggering on rising edge, this clock can be switched off during <<_sleep_mode>>
+| `clk_aux_i` | 1 | in | Always-on clock, used to keep the the sleep control active when `clk_i` is switched off
| `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 <<_cpu_debug_mode,debug mode>> when set
diff --git a/docs/datasheet/overview.adoc b/docs/datasheet/overview.adoc
index cf505bb0a..3f1725500 100644
--- a/docs/datasheet/overview.adoc
+++ b/docs/datasheet/overview.adoc
@@ -174,7 +174,7 @@ of the entire processor including all the required configuration generics is `ne
.Compile Order
[IMPORTANT]
Most of the RTL sources use **entity instantiation**. Hence, the RTL compile order might be relevant.
-The list below shows the hierarchical compile order srarting at the top.
+The list below shows the hierarchical compile order starting at the top.
.VHDL Library
[IMPORTANT]
@@ -182,6 +182,7 @@ All core VHDL files from the list below have to be assigned to a **new library**
...................................
┌-neorv32_package.vhd - Processor/CPU main VHDL package file
+├-neorv32_clockgate.vhd - Generic clock gating switch
├-neorv32_fifo.vhd - Generic FIFO component
│
│ ┌-neorv32_cpu_cp_bitmanip.vhd - Bit-manipulation co-processor (B ext.)
diff --git a/docs/datasheet/soc.adoc b/docs/datasheet/soc.adoc
index 22c2f4c81..0454b5581 100644
--- a/docs/datasheet/soc.adoc
+++ b/docs/datasheet/soc.adoc
@@ -199,9 +199,10 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
| Name | Type | Default | Description
4+^| **General**
| `CLOCK_FREQUENCY` | natural | - | The clock frequency of the processor's `clk_i` input port in Hertz (Hz).
+| `CLOCK_GATING_EN` | boolean | false | Enable clock gating when CPU is in sleep mode (see sections <<_sleep_mode>> and <<_processor_clocking>>).
| `INT_BOOTLOADER_EN` | boolean | false | Implement the processor-internal <<_bootloader_rom_bootrom>>, pre-initialized with the default <<_bootloader>> image.
-| `HART_ID` | suv(31:0) | 0x00000000 | The hart thread ID of the CPU (passed to <<_mhartid>> CSRs).
-| `VENDOR_ID` | suv(31:0) | 0x00000000 | JEDEC ID (passed to <<_mvendorid>> CSRs).
+| `HART_ID` | suv(31:0) | 0x00000000 | The hart thread ID of the CPU (passed to <<_mhartid>> CSR).
+| `VENDOR_ID` | suv(31:0) | 0x00000000 | JEDEC ID (passed to <<_mvendorid>> CSR).
4+^| **<<_on_chip_debugger_ocd>>**
| `ON_CHIP_DEBUGGER_EN` | boolean | false | Implement the on-chip debugger and the CPU debug mode.
| `DM_LEGACY_MODE` | boolean | false | Debug module spec. version: `false` = v1.0, `true` = v0.13 (legacy mode).
@@ -298,19 +299,39 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
The processor is implemented as fully-synchronous logic design using a single clock domain that is driven entirely by the
top's `clk_i` signal. This clock signal is used by all internal registers and memories, which trigger on the rising edge of
-this clock signal. External "clocks" like the OCD's JTAG clock or the TWI's serial clock are synchronized into the
-processor's clock domain before being further processed.
+this clock signal - except for the <<_processor_reset>> and the clock switching gate that trigger on a falling edge.
+External "clocks" like the OCD's JTAG clock or the SDI's serial clock are synchronized into the processor's clock domain
+before being further processed.
+==== Clock Gating
+
+The single clock domain of the processor can be split into an always-on clock domain and a switchable clock domain.
+The switchable clock domain is used to clock the CPU core. This domain can be deactivated at runtime to reduce power
+consumption. The always-on clock domain is used to clock all other processor modules like peripherals, memories and IO
+devices. Hence, these modules can continue operation (e.g. a timer keeps running) even if the CPU is shut down.
+
+The splitting into two clock domain is enabled by the `CLOCK_GATING_EN` generic (<<_processor_top_entity_generics>>).
+When enabled, a generic clock switching gate is added to decouple the switchable clock from the always-on clock domain
+(VHDL file `neorv32_clockgate.vhd`). Whenever the CPU enters <<_sleep_mode>> the CPU clock domain ist shut down.
+
+.Clock Switch Hardware
[NOTE]
-Only the registers of the <<_processor_reset>> system trigger on a _falling_ clock edge.
+By default, a generic clock gate is used (`rtl/core/neorv32_clockgate.vhd`) to shut down the CPU clock.
+Especially for FPGA setups it is highly recommended to replace this default version by a technology-specific primitive
+or macro wrapper to improve efficiency (clock skew, global clock tree usage, etc.).
+
-Many processor modules like the UARTs or the timers require a programmable time base for operations. In order to simplify
-the hardware, the processor implements a global "clock generator" that provides _clock enables_ for certain frequencies.
-These clock enable signals are synchronous to the system's main clock and will be high for only a single cycle. Hence,
-processor modules can use these enables for sub-main-clock operations while still having a single clock domain only.
+
+==== Peripheral Clocks
+
+Many processor modules like the UARTs or the timers provide a programmable time base for operations. In order to simplify
+the hardware, the processor implements a global "clock generator" that provides _clock enables_ for certain frequencies that
+are derived from the man clock. Hence, these clock enable signals are synchronous to the system's main clock and will be high
+for only a single cycle. The processor modules can use these enables for sub-main-clock operations while still providing a single
+clock domain only.
In total, 8 sub-main-clock signals are available. All processor modules, which feature a time-based configuration, provide a
-programmable three-bit prescaler select in their according control register to select one of the 8 available clocks. The
+programmable three-bit prescaler select in their control register to select one of the 8 available clocks. The
mapping of the prescaler select bits to the according clock source is shown in the table below. Here, _f_ represents the
processor main clock from the top entity's `clk_i` signal.
@@ -321,28 +342,11 @@ processor main clock from the top entity's `clk_i` signal.
| Resulting clock: | _f/2_ | _f/4_ | _f/8_ | _f/64_ | _f/128_ | _f/1024_| _f/2048_| _f/4096_
|=======================
-The software framework provides pre-defined aliases for the prescaler select bits:
-
-.Prescaler Aliases from `neorv32.h`
-[source,c]
---------------------------
-enum NEORV32_CLOCK_PRSC_enum {
- CLK_PRSC_2 = 0, /**< CPU_CLK (from clk_i top signal) / 2 */
- CLK_PRSC_4 = 1, /**< CPU_CLK (from clk_i top signal) / 4 */
- CLK_PRSC_8 = 2, /**< CPU_CLK (from clk_i top signal) / 8 */
- CLK_PRSC_64 = 3, /**< CPU_CLK (from clk_i top signal) / 64 */
- CLK_PRSC_128 = 4, /**< CPU_CLK (from clk_i top signal) / 128 */
- CLK_PRSC_1024 = 5, /**< CPU_CLK (from clk_i top signal) / 1024 */
- CLK_PRSC_2048 = 6, /**< CPU_CLK (from clk_i top signal) / 2048 */
- CLK_PRSC_4096 = 7 /**< CPU_CLK (from clk_i top signal) / 4096 */
-};
---------------------------
-
-.Power-Down Mode
+.Power Saving
[TIP]
-If no peripheral modules requires a clock signal from the internal generator (all available modules disabled by clearing the
-enable bit in the according module's control register) the generator is automatically deactivated to reduce dynamic power consumption.
-
+If no peripheral modules requires a clock signal from the internal clock generator (all according modules are disabled by
+clearing the enable bit in the according module's control register) the generator is automatically deactivated to reduce
+dynamic power consumption.
<<<
diff --git a/docs/datasheet/soc_sysinfo.adoc b/docs/datasheet/soc_sysinfo.adoc
index 342a9e40a..fcdce0158 100644
--- a/docs/datasheet/soc_sysinfo.adoc
+++ b/docs/datasheet/soc_sysinfo.adoc
@@ -19,7 +19,7 @@ The SYSINFO allows the application software to determine the setting of most of
that are related to processor/SoC configuration. All registers of this unit are read-only.
This device is always implemented - regardless of the actual hardware configuration. The bootloader as well
as the NEORV32 software runtime environment require information from this device (like memory layout
-and default clock speed) for correct operation.
+and default clock frequency) for correct operation.
**Register Map**
@@ -29,7 +29,7 @@ and default clock speed) for correct operation.
[options="header",grid="all"]
|=======================
| Address | Name [C] | Function
-| `0xfffffe00` | `CLK` | clock speed in Hz (via top's `CLOCK_FREQUENCY` generic)
+| `0xfffffe00` | `CLK` | clock frequency in Hz (via top's `CLOCK_FREQUENCY` generic)
| `0xfffffe04` | `MEM[4]` | internal memory configuration (see <<_sysinfo_memory_configuration>>)
| `0xfffffe08` | `SOC` | specific SoC configuration (see <<_sysinfo_soc_configuration>>)
| `0xfffffe0c` | `CACHE` | cache configuration information (see <<_sysinfo_cache_configuration>>)
@@ -67,7 +67,8 @@ Bit fields in this register are set to all-zero if the according cache is not im
| `4` | `SYSINFO_SOC_MEM_EXT_ENDIAN` | set if external bus interface uses BIG-endian byte-order (via top's `MEM_EXT_BIG_ENDIAN` generic)
| `5` | `SYSINFO_SOC_ICACHE` | set if processor-internal instruction cache is implemented (via top's `ICACHE_EN` generic)
| `6` | `SYSINFO_SOC_DCACHE` | set if processor-internal data cache is implemented (via top's `DCACHE_EN` generic)
-| `11:7` | - | _reserved_, read as zero
+| `7` | `SYSINFO_SOC_CLOCK_GATING` | set if CPU clock gating is implemented (via top's `CLOCK_GATING_EN` generic)
+| `11:8` | - | _reserved_, read as zero
| `12` | `SYSINFO_SOC_IO_CRC` | set if cyclic redundancy check unit is implemented (via top's `IO_CRC_EN` generic)
| `13` | `SYSINFO_SOC_IO_SLINK` | set if stream link interface is implemented (via top's `IO_SLINK_EN` generic)
| `14` | `SYSINFO_SOC_IO_DMA` | set if direct memory access controller is implemented (via top's `IO_DMA_EN` generic)
diff --git a/rtl/core/neorv32_clockgate.vhd b/rtl/core/neorv32_clockgate.vhd
new file mode 100644
index 000000000..e6c20cb0a
--- /dev/null
+++ b/rtl/core/neorv32_clockgate.vhd
@@ -0,0 +1,79 @@
+-- #################################################################################################
+-- # << NEORV32 - Generic Clock Gating Switch >> #
+-- # ********************************************************************************************* #
+-- # This is a generic clock switch that allows to shut down the clock of certain processor #
+-- # modules in order to reduce power consumption. #
+-- # #
+-- # [NOTE] Especially for FPGA setups, it is highly recommended to replace this default module #
+-- # by a technology-/platform-specific macro or primitive (e.g. a clock mux) wrapper. #
+-- # ********************************************************************************************* #
+-- # BSD 3-Clause License #
+-- # #
+-- # Copyright (c) 2024, Stephan Nolting. All rights reserved. #
+-- # #
+-- # Redistribution and use in source and binary forms, with or without modification, are #
+-- # permitted provided that the following conditions are met: #
+-- # #
+-- # 1. Redistributions of source code must retain the above copyright notice, this list of #
+-- # conditions and the following disclaimer. #
+-- # #
+-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
+-- # conditions and the following disclaimer in the documentation and/or other materials #
+-- # provided with the distribution. #
+-- # #
+-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
+-- # endorse or promote products derived from this software without specific prior written #
+-- # permission. #
+-- # #
+-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
+-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
+-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
+-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
+-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
+-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
+-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
+-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
+-- # OF THE POSSIBILITY OF SUCH DAMAGE. #
+-- # ********************************************************************************************* #
+-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
+-- #################################################################################################
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity neorv32_clockgate is
+ port (
+ clk_i : in std_ulogic; -- global clock line, always-on
+ rstn_i : in std_ulogic; -- global reset line, low-active, async
+ halt_i : in std_ulogic; -- shut down clock output when set
+ clk_o : out std_ulogic -- switched clock output
+ );
+end neorv32_clockgate;
+
+architecture neorv32_clockgate_rtl of neorv32_clockgate is
+
+ signal enable : std_ulogic;
+
+begin
+
+ -- Warn about Clock Gating ----------------------------------------------------------------
+ -- -------------------------------------------------------------------------------------------
+ assert false report "[NEORV32] Clock gating enabled (using generic clock switch)." severity warning;
+
+
+ -- Clock Switch ---------------------------------------------------------------------------
+ -- -------------------------------------------------------------------------------------------
+ clock_switch: process(rstn_i, clk_i)
+ begin
+ if (rstn_i = '0') then
+ enable <= '1';
+ elsif falling_edge(clk_i) then -- update on falling edge to avoid glitches on 'clk_o'
+ enable <= not halt_i;
+ end if;
+ end process clock_switch;
+
+ -- for FPGA designs better replace this by a technology-specific primitive or macro --
+ clk_o <= clk_i when (enable = '1') else '0';
+
+
+end neorv32_clockgate_rtl;
diff --git a/rtl/core/neorv32_cpu.vhd b/rtl/core/neorv32_cpu.vhd
index a3760502d..7f1ec3bc0 100644
--- a/rtl/core/neorv32_cpu.vhd
+++ b/rtl/core/neorv32_cpu.vhd
@@ -75,7 +75,8 @@ entity neorv32_cpu is
);
port (
-- global control --
- clk_i : in std_ulogic; -- global clock, rising edge
+ clk_i : in std_ulogic; -- switchable global clock, rising edge
+ clk_aux_i : in std_ulogic; -- always-on clock, rising edge
rstn_i : in std_ulogic; -- global reset, low-active, async
sleep_o : out std_ulogic; -- cpu is in sleep mode when set
debug_o : out std_ulogic; -- cpu is in debug mode when set
@@ -162,8 +163,8 @@ begin
-- CPU tuning options --
assert false report "[NEORV32] CPU tuning options: " &
cond_sel_string_f(FAST_MUL_EN, "fast_mul ", "") &
- cond_sel_string_f(FAST_SHIFT_EN, "fast_shift ", "" ) &
- cond_sel_string_f(REGFILE_HW_RST, "rf_hw_rst", "" )
+ cond_sel_string_f(FAST_SHIFT_EN, "fast_shift ", "") &
+ cond_sel_string_f(REGFILE_HW_RST, "rf_hw_rst ", "")
severity note;
-- simulation notifier --
@@ -207,6 +208,7 @@ begin
port map (
-- global control --
clk_i => clk_i, -- global clock, rising edge
+ clk_aux_i => clk_aux_i, -- always-on clock, rising edge
rstn_i => rstn_i, -- global reset, low-active, async
ctrl_o => ctrl, -- main control bus
-- instruction fetch interface --
diff --git a/rtl/core/neorv32_cpu_control.vhd b/rtl/core/neorv32_cpu_control.vhd
index 458e2dca0..94822f608 100644
--- a/rtl/core/neorv32_cpu_control.vhd
+++ b/rtl/core/neorv32_cpu_control.vhd
@@ -85,6 +85,7 @@ entity neorv32_cpu_control is
port (
-- global control --
clk_i : in std_ulogic; -- global clock, rising edge
+ clk_aux_i : in std_ulogic; -- always-on clock, rising edge
rstn_i : in std_ulogic; -- global reset, low-active, async
ctrl_o : out ctrl_bus_t; -- main control bus
-- instruction fetch interface --
@@ -132,7 +133,7 @@ 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, IF_PARKED);
+ type fetch_engine_state_t is (IF_RESTART, IF_REQUEST, IF_PENDING);
type fetch_engine_t is record
state : fetch_engine_state_t;
state_prev : fetch_engine_state_t;
@@ -214,6 +215,9 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
end record;
signal monitor : monitor_t;
+ -- CPU sleep-mode --
+ signal sleep_mode : std_ulogic;
+
-- trap controller --
type trap_ctrl_t is record
exc_buf : std_ulogic_vector(exc_width_c-1 downto 0); -- synchronous exception buffer (one bit per exception)
@@ -324,12 +328,11 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
-- debug mode controller --
type debug_ctrl_t is record
- running : std_ulogic; -- CPU is in debug mode
- trig_hw : std_ulogic; -- hardware trigger
- trig_break : std_ulogic; -- ebreak instruction trigger
- trig_halt : std_ulogic; -- external request trigger
- trig_step : std_ulogic; -- single-stepping mode trigger
- ext_halt_req : std_ulogic; -- external halt request buffer
+ running : std_ulogic; -- CPU is in debug mode
+ trig_hw : std_ulogic; -- hardware trigger
+ trig_break : std_ulogic; -- ebreak instruction trigger
+ trig_halt : std_ulogic; -- external request trigger
+ trig_step : std_ulogic; -- single-stepping mode trigger
end record;
signal debug_ctrl : debug_ctrl_t;
@@ -380,8 +383,6 @@ 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
@@ -396,12 +397,6 @@ begin
end if;
end if;
- when IF_PARKED => -- park position: instruction fetch is halted for sleep mode
- -- ------------------------------------------------------------
- if (execute_engine.state /= SLEEP) then
- fetch_engine.state <= IF_REQUEST;
- end if;
-
when others => -- IF_RESTART: set new start address
-- ------------------------------------------------------------
fetch_engine.pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; -- initialize from PC incl. 16-bit-alignment bit
@@ -1053,9 +1048,9 @@ begin
execute_engine.state_nxt <= DISPATCH;
end if;
- when SLEEP => -- sleep mode; no sleep during debugging; wakeup on pending IRQ
+ when SLEEP => -- sleep mode
-- ------------------------------------------------------------
- if (debug_ctrl.running = '1') or (csr.dcsr_step = '1') or (trap_ctrl.wakeup = '1') then
+ if (trap_ctrl.wakeup = '1') then
execute_engine.state_nxt <= DISPATCH;
end if;
@@ -1084,6 +1079,24 @@ begin
end process execute_engine_fsm_comb;
+ -- CPU Sleep Mode Control -----------------------------------------------------------------
+ -- -------------------------------------------------------------------------------------------
+ sleep_control: process(rstn_i, clk_aux_i) -- always-on clock domain
+ begin
+ if (rstn_i = '0') then
+ sleep_mode <= '0';
+ elsif rising_edge(clk_aux_i) then
+ if (execute_engine.state = SLEEP) and -- instruction execution has halted
+ (ipb.free /= "11") and -- instruction fetch has halted
+ (trap_ctrl.wakeup = '0') then -- no wake-up request
+ sleep_mode <= '1';
+ else
+ sleep_mode <= '0';
+ end if;
+ end if;
+ end process sleep_control;
+
+
-- CPU Control Bus Output -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
@@ -1121,7 +1134,7 @@ begin
-- cpu status --
ctrl_o.cpu_priv <= csr.privilege_eff;
- ctrl_o.cpu_sleep <= '1' when (execute_engine.state = SLEEP) and (fetch_engine.state = IF_PARKED) else '0'; -- set only if fully halted
+ ctrl_o.cpu_sleep <= '0';-- sleep_mode;
ctrl_o.cpu_trap <= trap_ctrl.env_enter;
ctrl_o.cpu_debug <= debug_ctrl.running;
@@ -1383,14 +1396,12 @@ begin
-- Trap Controller
-- ****************************************************************************************************************************
- -- Trap Buffer ----------------------------------------------------------------------------
+ -- Exception Buffer -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
- trap_buffer: process(rstn_i, clk_i)
+ exception_buffer: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
trap_ctrl.exc_buf <= (others => '0');
- trap_ctrl.irq_pnd <= (others => '0');
- trap_ctrl.irq_buf <= (others => '0');
elsif rising_edge(clk_i) then
-- Exception Buffer -----------------------------------------------------
@@ -1432,6 +1443,18 @@ begin
trap_ctrl.exc_buf(exc_db_break_c) <= '0';
trap_ctrl.exc_buf(exc_db_hw_c) <= '0';
end if;
+ end if;
+ end process exception_buffer;
+
+
+ -- Interrupt Buffer -----------------------------------------------------------------------
+ -- -------------------------------------------------------------------------------------------
+ interrupt_buffer: process(rstn_i, clk_aux_i) -- always-on clock domain
+ begin
+ if (rstn_i = '0') then
+ trap_ctrl.irq_pnd <= (others => '0');
+ trap_ctrl.irq_buf <= (others => '0');
+ elsif rising_edge(clk_aux_i) then
-- Interrupt-Pending Buffer ---------------------------------------------
-- Once triggered the fast interrupt requests stay active until
@@ -1477,9 +1500,8 @@ begin
trap_ctrl.irq_buf(irq_db_halt_c) <= '0';
trap_ctrl.irq_buf(irq_db_step_c) <= '0';
end if;
-
end if;
- end process trap_buffer;
+ end process interrupt_buffer;
-- Trap Priority Logic --------------------------------------------------------------------
@@ -1535,10 +1557,8 @@ begin
trap_controller: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
- trap_ctrl.wakeup <= '0';
trap_ctrl.env_pending <= '0';
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 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
@@ -1550,6 +1570,9 @@ begin
end if;
end process trap_controller;
+ -- wake-up from / do not enter sleep mode: during debugging or on pending IRQ --
+ trap_ctrl.wakeup <= or_reduce_f(trap_ctrl.irq_buf) or debug_ctrl.running or csr.dcsr_step;
+
-- any exception? --
trap_ctrl.exc_fire <= '1' when (or_reduce_f(trap_ctrl.exc_buf) = '1') else '0'; -- sync. exceptions CANNOT be masked
@@ -2366,10 +2389,8 @@ begin
debug_control: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
- debug_ctrl.ext_halt_req <= '0';
- debug_ctrl.running <= '0';
+ debug_ctrl.running <= '0';
elsif rising_edge(clk_i) then
- debug_ctrl.ext_halt_req <= db_halt_req_i; -- external halt request (from Debug Module)
if (debug_ctrl.running = '0') then -- debug mode OFFLINE
if (trap_ctrl.env_enter = '1') and (trap_ctrl.cause(5) = '1') then -- waiting for entry event
debug_ctrl.running <= '1';
@@ -2387,7 +2408,7 @@ begin
debug_ctrl.trig_break <= trap_ctrl.ebreak and (debug_ctrl.running or -- re-enter debug mode
(( csr.privilege) and csr.dcsr_ebreakm) or -- enabled goto-debug-mode in machine mode on "ebreak"
((not csr.privilege) and csr.dcsr_ebreaku)); -- enabled goto-debug-mode in user mode on "ebreak"
- debug_ctrl.trig_halt <= debug_ctrl.ext_halt_req and (not debug_ctrl.running); -- external halt request (if not halted already)
+ debug_ctrl.trig_halt <= db_halt_req_i and (not debug_ctrl.running); -- external halt request (if not halted already)
debug_ctrl.trig_step <= csr.dcsr_step and (not debug_ctrl.running); -- single-step mode (trigger when NOT CURRENTLY in debug mode)
end generate;
@@ -2395,12 +2416,11 @@ begin
-- Sdext ISA extension not enabled --
debug_mode_disable:
if not CPU_EXTENSION_RISCV_Sdext generate
- debug_ctrl.ext_halt_req <= '0';
- debug_ctrl.running <= '0';
- debug_ctrl.trig_hw <= '0';
- debug_ctrl.trig_break <= '0';
- debug_ctrl.trig_halt <= '0';
- debug_ctrl.trig_step <= '0';
+ debug_ctrl.running <= '0';
+ debug_ctrl.trig_hw <= '0';
+ debug_ctrl.trig_break <= '0';
+ debug_ctrl.trig_halt <= '0';
+ debug_ctrl.trig_step <= '0';
end generate;
diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd
index 8ab2003bc..d81e9a7fc 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"01090303"; -- hardware version
+ constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090304"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width
@@ -744,6 +744,7 @@ package neorv32_package is
generic (
-- General --
CLOCK_FREQUENCY : natural;
+ CLOCK_GATING_EN : boolean := false;
HART_ID : std_ulogic_vector(31 downto 0) := x"00000000";
VENDOR_ID : std_ulogic_vector(31 downto 0) := x"00000000";
INT_BOOTLOADER_EN : boolean := false;
diff --git a/rtl/core/neorv32_sysinfo.vhd b/rtl/core/neorv32_sysinfo.vhd
index 1b2ffa3bf..5cc3d06fc 100644
--- a/rtl/core/neorv32_sysinfo.vhd
+++ b/rtl/core/neorv32_sysinfo.vhd
@@ -6,7 +6,7 @@
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
--- # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
+-- # Copyright (c) 2024, Stephan Nolting. All rights reserved. #
-- # #
-- # Redistribution and use in source and binary forms, with or without modification, are #
-- # permitted provided that the following conditions are met: #
@@ -46,6 +46,7 @@ entity neorv32_sysinfo is
generic (
-- General --
CLOCK_FREQUENCY : natural; -- clock frequency of clk_i in Hz
+ CLOCK_GATING_EN : boolean; -- enable clock gating when in sleep mode
INT_BOOTLOADER_EN : boolean; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Internal instruction memory --
MEM_INT_IMEM_EN : boolean; -- implement processor-internal instruction memory
@@ -112,7 +113,7 @@ begin
-- Construct Info ROM ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
- -- SYSINFO(0): Processor Clock Frequency --
+ -- SYSINFO(0): Processor Clock Frequency in Hz --
sysinfo(0) <= std_ulogic_vector(to_unsigned(CLOCK_FREQUENCY, 32));
-- SYSINFO(1): Internal Memory Configuration (sizes)
@@ -122,50 +123,47 @@ begin
sysinfo(1)(31 downto 24) <= std_ulogic_vector(to_unsigned(index_size_f(AMO_RVS_GRANULARITY), 8)); -- log2(reservation set granularity)
-- SYSINFO(2): SoC Configuration --
- -- Memory System --
- sysinfo(2)(00) <= bool_to_ulogic_f(INT_BOOTLOADER_EN); -- processor-internal bootloader implemented?
- sysinfo(2)(01) <= bool_to_ulogic_f(MEM_EXT_EN); -- external memory bus interface implemented?
- sysinfo(2)(02) <= bool_to_ulogic_f(int_imem_en_c); -- processor-internal instruction memory implemented?
- sysinfo(2)(03) <= bool_to_ulogic_f(int_dmem_en_c); -- processor-internal data memory implemented?
- sysinfo(2)(04) <= bool_to_ulogic_f(MEM_EXT_BIG_ENDIAN); -- is external memory bus interface using BIG-endian byte-order?
- sysinfo(2)(05) <= bool_to_ulogic_f(ICACHE_EN); -- processor-internal instruction cache implemented?
- sysinfo(2)(06) <= bool_to_ulogic_f(DCACHE_EN); -- processor-internal data cache implemented?
- -- reserved --
- sysinfo(2)(07) <= '0';
- sysinfo(2)(08) <= '0';
- sysinfo(2)(09) <= '0';
- sysinfo(2)(10) <= '0';
- sysinfo(2)(11) <= '0';
- -- Peripherals/IO --
- sysinfo(2)(12) <= bool_to_ulogic_f(IO_CRC_EN); -- cyclic redundancy check unit (CRC) implemented?
- sysinfo(2)(13) <= bool_to_ulogic_f(IO_SLINK_EN); -- stream link interface (SLINK) implemented?
- sysinfo(2)(14) <= bool_to_ulogic_f(IO_DMA_EN); -- direct memory access controller (DMA) implemented?
- sysinfo(2)(15) <= bool_to_ulogic_f(IO_GPIO_EN); -- general purpose input/output port unit (GPIO) implemented?
- sysinfo(2)(16) <= bool_to_ulogic_f(IO_MTIME_EN); -- machine system timer (MTIME) implemented?
- sysinfo(2)(17) <= bool_to_ulogic_f(IO_UART0_EN); -- primary universal asynchronous receiver/transmitter (UART0) implemented?
- sysinfo(2)(18) <= bool_to_ulogic_f(IO_SPI_EN); -- serial peripheral interface (SPI) implemented?
- sysinfo(2)(19) <= bool_to_ulogic_f(IO_TWI_EN); -- two-wire interface (TWI) implemented?
- sysinfo(2)(20) <= bool_to_ulogic_f(IO_PWM_EN); -- pulse-width modulation unit (PWM) implemented?
- sysinfo(2)(21) <= bool_to_ulogic_f(IO_WDT_EN); -- watch dog timer (WDT) implemented?
- sysinfo(2)(22) <= bool_to_ulogic_f(IO_CFS_EN); -- custom functions subsystem (CFS) implemented?
- sysinfo(2)(23) <= bool_to_ulogic_f(IO_TRNG_EN); -- true random number generator (TRNG) implemented?
- sysinfo(2)(24) <= bool_to_ulogic_f(IO_SDI_EN); -- serial data interface (SDI) implemented?
- sysinfo(2)(25) <= bool_to_ulogic_f(IO_UART1_EN); -- secondary universal asynchronous receiver/transmitter (UART1) implemented?
- sysinfo(2)(26) <= bool_to_ulogic_f(IO_NEOLED_EN); -- NeoPixel-compatible smart LED interface (NEOLED) implemented?
- sysinfo(2)(27) <= bool_to_ulogic_f(IO_XIRQ_EN); -- external interrupt controller (XIRQ) implemented?
- sysinfo(2)(28) <= bool_to_ulogic_f(IO_GPTMR_EN); -- general purpose timer (GPTMR) implemented?
- sysinfo(2)(29) <= bool_to_ulogic_f(IO_XIP_EN); -- execute in place module (XIP) implemented?
- sysinfo(2)(30) <= bool_to_ulogic_f(IO_ONEWIRE_EN); -- 1-wire interface (ONEWIRE) implemented?
- sysinfo(2)(31) <= bool_to_ulogic_f(ON_CHIP_DEBUGGER_EN); -- on-chip debugger implemented?
+ sysinfo(2)(00) <= '1' when INT_BOOTLOADER_EN else '0'; -- processor-internal bootloader implemented?
+ sysinfo(2)(01) <= '1' when MEM_EXT_EN else '0'; -- external memory bus interface implemented?
+ sysinfo(2)(02) <= '1' when int_imem_en_c else '0'; -- processor-internal instruction memory implemented?
+ sysinfo(2)(03) <= '1' when int_dmem_en_c else '0'; -- processor-internal data memory implemented?
+ sysinfo(2)(04) <= '1' when MEM_EXT_BIG_ENDIAN else '0'; -- is external memory bus interface using BIG-endian byte-order?
+ sysinfo(2)(05) <= '1' when ICACHE_EN else '0'; -- processor-internal instruction cache implemented?
+ sysinfo(2)(06) <= '1' when DCACHE_EN else '0'; -- processor-internal data cache implemented?
+ sysinfo(2)(07) <= '1' when CLOCK_GATING_EN else '0'; -- enable clock gating when in sleep mode
+ sysinfo(2)(08) <= '0'; -- reserved
+ sysinfo(2)(09) <= '0'; -- reserved
+ sysinfo(2)(10) <= '0'; -- reserved
+ sysinfo(2)(11) <= '0'; -- reserved
+ sysinfo(2)(12) <= '1' when IO_CRC_EN else '0'; -- cyclic redundancy check unit (CRC) implemented?
+ sysinfo(2)(13) <= '1' when IO_SLINK_EN else '0'; -- stream link interface (SLINK) implemented?
+ sysinfo(2)(14) <= '1' when IO_DMA_EN else '0'; -- direct memory access controller (DMA) implemented?
+ sysinfo(2)(15) <= '1' when IO_GPIO_EN else '0'; -- general purpose input/output port unit (GPIO) implemented?
+ sysinfo(2)(16) <= '1' when IO_MTIME_EN else '0'; -- machine system timer (MTIME) implemented?
+ sysinfo(2)(17) <= '1' when IO_UART0_EN else '0'; -- primary universal asynchronous receiver/transmitter (UART0) implemented?
+ sysinfo(2)(18) <= '1' when IO_SPI_EN else '0'; -- serial peripheral interface (SPI) implemented?
+ sysinfo(2)(19) <= '1' when IO_TWI_EN else '0'; -- two-wire interface (TWI) implemented?
+ sysinfo(2)(20) <= '1' when IO_PWM_EN else '0'; -- pulse-width modulation unit (PWM) implemented?
+ sysinfo(2)(21) <= '1' when IO_WDT_EN else '0'; -- watch dog timer (WDT) implemented?
+ sysinfo(2)(22) <= '1' when IO_CFS_EN else '0'; -- custom functions subsystem (CFS) implemented?
+ sysinfo(2)(23) <= '1' when IO_TRNG_EN else '0'; -- true random number generator (TRNG) implemented?
+ sysinfo(2)(24) <= '1' when IO_SDI_EN else '0'; -- serial data interface (SDI) implemented?
+ sysinfo(2)(25) <= '1' when IO_UART1_EN else '0'; -- secondary universal asynchronous receiver/transmitter (UART1) implemented?
+ sysinfo(2)(26) <= '1' when IO_NEOLED_EN else '0'; -- NeoPixel-compatible smart LED interface (NEOLED) implemented?
+ sysinfo(2)(27) <= '1' when IO_XIRQ_EN else '0'; -- external interrupt controller (XIRQ) implemented?
+ sysinfo(2)(28) <= '1' when IO_GPTMR_EN else '0'; -- general purpose timer (GPTMR) implemented?
+ sysinfo(2)(29) <= '1' when IO_XIP_EN else '0'; -- execute in place module (XIP) implemented?
+ sysinfo(2)(30) <= '1' when IO_ONEWIRE_EN else '0'; -- 1-wire interface (ONEWIRE) implemented?
+ sysinfo(2)(31) <= '1' when ON_CHIP_DEBUGGER_EN else '0'; -- on-chip debugger implemented?
-- SYSINFO(3): Cache Configuration --
- sysinfo(3)(03 downto 00) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_BLOCK_SIZE), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(block_size_in_bytes)
- sysinfo(3)(07 downto 04) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_NUM_BLOCKS), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(number_of_block)
- sysinfo(3)(11 downto 08) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_ASSOCIATIVITY), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(associativity)
- sysinfo(3)(15 downto 12) <= "0001" when (ICACHE_ASSOCIATIVITY > 1) and (ICACHE_EN = true) else (others => '0'); -- i-cache: replacement strategy (LRU only (yet))
+ sysinfo(3)(03 downto 00) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_BLOCK_SIZE), 4)) when ICACHE_EN else (others => '0'); -- i-cache: log2(block_size_in_bytes)
+ sysinfo(3)(07 downto 04) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_NUM_BLOCKS), 4)) when ICACHE_EN else (others => '0'); -- i-cache: log2(number_of_block)
+ sysinfo(3)(11 downto 08) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_ASSOCIATIVITY), 4)) when ICACHE_EN else (others => '0'); -- i-cache: log2(associativity)
+ sysinfo(3)(15 downto 12) <= "0001" when (ICACHE_ASSOCIATIVITY > 1) and ICACHE_EN else (others => '0'); -- i-cache: replacement strategy (LRU only (yet))
--
- sysinfo(3)(19 downto 16) <= std_ulogic_vector(to_unsigned(index_size_f(DCACHE_BLOCK_SIZE), 4)) when (DCACHE_EN = true) else (others => '0'); -- d-cache: log2(block_size)
- sysinfo(3)(23 downto 20) <= std_ulogic_vector(to_unsigned(index_size_f(DCACHE_NUM_BLOCKS), 4)) when (DCACHE_EN = true) else (others => '0'); -- d-cache: log2(num_blocks)
+ sysinfo(3)(19 downto 16) <= std_ulogic_vector(to_unsigned(index_size_f(DCACHE_BLOCK_SIZE), 4)) when DCACHE_EN else (others => '0'); -- d-cache: log2(block_size)
+ sysinfo(3)(23 downto 20) <= std_ulogic_vector(to_unsigned(index_size_f(DCACHE_NUM_BLOCKS), 4)) when DCACHE_EN else (others => '0'); -- d-cache: log2(num_blocks)
sysinfo(3)(27 downto 24) <= (others => '0'); -- d-cache: log2(associativity)
sysinfo(3)(31 downto 28) <= (others => '0'); -- d-cache: replacement strategy
diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd
index 98cf87744..18dfa190d 100644
--- a/rtl/core/neorv32_top.vhd
+++ b/rtl/core/neorv32_top.vhd
@@ -48,6 +48,7 @@ entity neorv32_top is
generic (
-- General --
CLOCK_FREQUENCY : natural; -- clock frequency of clk_i in Hz
+ CLOCK_GATING_EN : boolean := false; -- enable clock gating when in sleep mode
HART_ID : std_ulogic_vector(31 downto 0) := x"00000000"; -- hardware thread ID
VENDOR_ID : std_ulogic_vector(31 downto 0) := x"00000000"; -- vendor's JEDEC ID
INT_BOOTLOADER_EN : boolean := false; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
@@ -282,6 +283,7 @@ architecture neorv32_top_rtl of neorv32_top is
signal rst_cause : std_ulogic_vector(1 downto 0);
-- clock generator --
+ signal clk_cpu : std_ulogic; -- CPU core clock, can be switched off
signal clk_div, clk_div_ff : std_ulogic_vector(11 downto 0);
signal clk_gen : std_ulogic_vector(07 downto 0);
signal clk_gen_en, clk_gen_en_ff : std_ulogic;
@@ -352,11 +354,11 @@ begin
-- say hello --
assert false report
- "The NEORV32 RISC-V Processor by Stephan Nolting, " &
+ "The NEORV32 RISC-V Processor, " &
"version 0x" & to_hstring32_f(hw_version_c) & ", " &
"github.com/stnolting/neorv32" severity note;
- -- show module configuration --
+ -- show main SoC configuration --
assert false report
"[NEORV32] Processor Configuration: " &
cond_sel_string_f(MEM_INT_IMEM_EN, "IMEM ", "") &
@@ -479,6 +481,25 @@ begin
clk_gen_en <= cg_en.wdt or cg_en.uart0 or cg_en.uart1 or cg_en.spi or cg_en.twi or cg_en.pwm or
cg_en.cfs or cg_en.neoled or cg_en.gptmr or cg_en.xip or cg_en.onewire;
+
+ -- Clock Gating ---------------------------------------------------------------------------
+ -- -------------------------------------------------------------------------------------------
+ neorv32_clockgate_inst_true:
+ if (CLOCK_GATING_EN = true) generate
+ neorv32_clockgate_inst: entity neorv32.neorv32_clockgate
+ port map (
+ clk_i => clk_i,
+ rstn_i => rstn_sys,
+ halt_i => cpu_sleep,
+ clk_o => clk_cpu
+ );
+ end generate;
+
+ neorv32_clockgate_inst_false:
+ if (CLOCK_GATING_EN = false) generate
+ clk_cpu <= clk_i;
+ end generate;
+
end generate; -- /generators
@@ -526,7 +547,8 @@ begin
)
port map (
-- global control --
- clk_i => clk_i,
+ clk_i => clk_cpu,
+ clk_aux_i => clk_i,
rstn_i => rstn_sys,
sleep_o => cpu_sleep,
debug_o => cpu_debug,
@@ -1502,8 +1524,9 @@ begin
generic map (
-- General --
CLOCK_FREQUENCY => CLOCK_FREQUENCY,
+ CLOCK_GATING_EN => CLOCK_GATING_EN,
INT_BOOTLOADER_EN => INT_BOOTLOADER_EN,
- -- internal Instruction memory --
+ -- Internal Instruction memory --
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN,
MEM_INT_IMEM_SIZE => imem_size_c,
-- Internal Data memory --
diff --git a/sim/neorv32_tb.vhd b/sim/neorv32_tb.vhd
index b9b7338c1..dada56c3d 100644
--- a/sim/neorv32_tb.vhd
+++ b/sim/neorv32_tb.vhd
@@ -219,6 +219,7 @@ begin
generic map (
-- General --
CLOCK_FREQUENCY => f_clock_c, -- clock frequency of clk_i in Hz
+ CLOCK_GATING_EN => true, -- enable clock gating when in sleep mode
HART_ID => x"00000000", -- hardware thread ID
VENDOR_ID => x"00000000", -- vendor's JEDEC ID
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
diff --git a/sim/simple/neorv32_tb.simple.vhd b/sim/simple/neorv32_tb.simple.vhd
index 024bcd297..7dd8e31d5 100644
--- a/sim/simple/neorv32_tb.simple.vhd
+++ b/sim/simple/neorv32_tb.simple.vhd
@@ -162,6 +162,7 @@ begin
generic map (
-- General --
CLOCK_FREQUENCY => f_clock_c, -- clock frequency of clk_i in Hz
+ CLOCK_GATING_EN => true, -- enable clock gating when in sleep mode
HART_ID => x"00000000", -- hardware thread ID
VENDOR_ID => x"00000000", -- vendor's JEDEC ID
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
diff --git a/sw/lib/include/neorv32_sysinfo.h b/sw/lib/include/neorv32_sysinfo.h
index b55afed2a..e7160705b 100644
--- a/sw/lib/include/neorv32_sysinfo.h
+++ b/sw/lib/include/neorv32_sysinfo.h
@@ -3,7 +3,7 @@
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
-// # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
+// # Copyright (c) 2024, Stephan Nolting. All rights reserved. #
// # #
// # Redistribution and use in source and binary forms, with or without modification, are #
// # permitted provided that the following conditions are met: #
@@ -72,9 +72,10 @@ enum NEORV32_SYSINFO_SOC_enum {
SYSINFO_SOC_MEM_INT_DMEM = 3, /**< SYSINFO_SOC (3) (r/-): Processor-internal data memory implemented when 1 (via MEM_INT_DMEM_EN generic) */
SYSINFO_SOC_MEM_EXT_ENDIAN = 4, /**< SYSINFO_SOC (4) (r/-): External bus interface uses BIG-endian byte-order when 1 (via MEM_EXT_BIG_ENDIAN generic) */
SYSINFO_SOC_ICACHE = 5, /**< SYSINFO_SOC (5) (r/-): Processor-internal instruction cache implemented when 1 (via ICACHE_EN generic) */
- SYSINFO_SOC_DCACHE = 6, /**< SYSINFO_SOC (6) (r/-): Processor-internal instruction cache implemented when 1 (via ICACHE_EN generic) */
+ SYSINFO_SOC_DCACHE = 6, /**< SYSINFO_SOC (6) (r/-): Processor-internal instruction cache implemented when 1 (via DCACHE_EN generic) */
+ SYSINFO_SOC_CLOCK_GATING = 7, /**< SYSINFO_SOC (7) (r/-): Clock gating enabled when 1 (via CLOCK_GATING_EN generic) */
- SYSINFO_SOC_IO_CRC = 12, /**< SYSINFO_SOC (12) (r/-):Cyclic redundancy check unit implemented when 1 (via IO_CRC_EN generic) */
+ SYSINFO_SOC_IO_CRC = 12, /**< SYSINFO_SOC (12) (r/-): Cyclic redundancy check unit implemented when 1 (via IO_CRC_EN generic) */
SYSINFO_SOC_IO_SLINK = 13, /**< SYSINFO_SOC (13) (r/-): Stream link interface implemented when 1 (via IO_SLINK_EN generic) */
SYSINFO_SOC_IO_DMA = 14, /**< SYSINFO_SOC (14) (r/-): Direct memory access controller implemented when 1 (via IO_DMA_EN generic) */
SYSINFO_SOC_IO_GPIO = 15, /**< SYSINFO_SOC (15) (r/-): General purpose input/output port unit implemented when 1 (via IO_GPIO_EN generic) */
diff --git a/sw/lib/source/neorv32_rte.c b/sw/lib/source/neorv32_rte.c
index 902c30db6..c46af72ad 100644
--- a/sw/lib/source/neorv32_rte.c
+++ b/sw/lib/source/neorv32_rte.c
@@ -56,7 +56,6 @@ static uint32_t __neorv32_rte_vector_lut[NEORV32_RTE_NUM_TRAPS] __attribute__((u
// private functions
static void __attribute__((__naked__,aligned(4))) __neorv32_rte_core(void);
static void __neorv32_rte_debug_handler(void);
-static void __neorv32_rte_print_true_false(int state);
static void __neorv32_rte_print_hex_word(uint32_t num);
@@ -518,9 +517,19 @@ void neorv32_rte_print_hw_config(void) {
neorv32_uart0_printf("\n\n<< NEORV32 Processor Configuration >>\n\n");
// general
- neorv32_uart0_printf("Is simulation: "); __neorv32_rte_print_true_false(neorv32_cpu_csr_read(CSR_MXISA) & (1 << CSR_MXISA_IS_SIM));
+ neorv32_uart0_printf("Is simulation: ");
+ if (neorv32_cpu_csr_read(CSR_MXISA) & (1 << CSR_MXISA_IS_SIM)) { neorv32_uart0_printf("yes\n"); }
+ else { neorv32_uart0_printf("no\n"); }
+
neorv32_uart0_printf("Clock speed: %u Hz\n", NEORV32_SYSINFO->CLK);
- neorv32_uart0_printf("On-chip debugger: "); __neorv32_rte_print_true_false(NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_OCD));
+
+ neorv32_uart0_printf("Clock gating: ");
+ if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_CLOCK_GATING)) { neorv32_uart0_printf("enabled\n"); }
+ else { neorv32_uart0_printf("disabled\n"); }
+
+ neorv32_uart0_printf("On-chip debugger: ");
+ if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_OCD)) { neorv32_uart0_printf("enabled\n"); }
+ else { neorv32_uart0_printf("disabled\n"); }
// IDs
neorv32_uart0_printf("Hart ID: 0x%x\n"
@@ -719,23 +728,6 @@ void neorv32_rte_print_hw_config(void) {
}
-/**********************************************************************//**
- * NEORV32 runtime environment (RTE):
- * Private function to print true or false via UART0.
- *
- * @param[in] state Print 'true' when !=0, print 'false' when 0
- **************************************************************************/
-static void __neorv32_rte_print_true_false(int state) {
-
- if (state) {
- neorv32_uart0_puts("true\n");
- }
- else {
- neorv32_uart0_puts("false\n");
- }
-}
-
-
/**********************************************************************//**
* NEORV32 runtime environment (RTE):
* Private function to print 32-bit number as 8-digit hexadecimal value (with "0x" suffix).
diff --git a/sw/svd/neorv32.svd b/sw/svd/neorv32.svd
index 4bc3ed16d..46e8f6547 100644
--- a/sw/svd/neorv32.svd
+++ b/sw/svd/neorv32.svd
@@ -1591,6 +1591,7 @@
SYSINFO_SOC_MEM_EXT_ENDIAN[4:4]External bus interface uses BIG-endian byte-order
SYSINFO_SOC_ICACHE[5:5]Processor-internal instruction cache implemented
SYSINFO_SOC_DCACHE[6:6]Processor-internal data cache implemented
+ SYSINFO_SOC_CLOCK_GATING[7:7]Clock gating implemented
SYSINFO_SOC_IO_CRC[12:12]Cyclic redundancy check unit implemented
SYSINFO_SOC_IO_SLINK[13:13]Stream link interface implemented
SYSINFO_SOC_IO_DMA[14:14]Direct memory access controller implemented