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