From a9d26c9dbc01f125ec70416d75b7cfe04bea1544 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 21:54:48 +0100 Subject: [PATCH 01/21] =?UTF-8?q?=E2=9C=A8=20[rtl]=20add=20inter-core-comm?= =?UTF-8?q?unication=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/datasheet/overview.adoc | 1 + rtl/core/neorv32_cpu_icc.vhd | 139 +++++++++++++++++++++++++++++++++++ rtl/file_list_cpu.f | 1 + rtl/file_list_soc.f | 1 + 4 files changed, 142 insertions(+) create mode 100644 rtl/core/neorv32_cpu_icc.vhd diff --git a/docs/datasheet/overview.adoc b/docs/datasheet/overview.adoc index b17477bbb..c58f69a3b 100644 --- a/docs/datasheet/overview.adoc +++ b/docs/datasheet/overview.adoc @@ -194,6 +194,7 @@ neorv32_top.vhd - NEORV32 PROCESSOR/SOC TOP ENTITY ││└neorv32_cpu_cp_shifter.vhd - Bit-shift co-processor (base ISA) │├neorv32_cpu_control.vhd - CPU control, exception system and CSRs ││└neorv32_cpu_decompressor.vhd - Compressed instructions decoder (C ext.) +│├neorv32_cpu_icc.vhd - Inter-core communication unit │├neorv32_cpu_lsu.vhd - Load/store unit │├neorv32_cpu_pmp.vhd - Physical memory protection unit (Smpmp ext.) │└neorv32_cpu_regfile.vhd - Data register file diff --git a/rtl/core/neorv32_cpu_icc.vhd b/rtl/core/neorv32_cpu_icc.vhd new file mode 100644 index 000000000..dfac5deb4 --- /dev/null +++ b/rtl/core/neorv32_cpu_icc.vhd @@ -0,0 +1,139 @@ +-- ================================================================================ -- +-- NEORV32 CPU - Inter-Core Communication Unit (ICC) -- +-- -------------------------------------------------------------------------------- -- +-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- +-- Copyright (c) NEORV32 contributors. -- +-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. -- +-- Licensed under the BSD-3-Clause license, see LICENSE for details. -- +-- SPDX-License-Identifier: BSD-3-Clause -- +-- ================================================================================ -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library neorv32; +use neorv32.neorv32_package.all; + +entity neorv32_cpu_icc is + generic ( + HART_ID : natural range 0 to 3; -- ID of this core + NUM_HARTS : natural range 1 to 4 -- number of cores, has to be a power of two + ); + port ( + -- global control -- + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + -- CSR interface -- + csr_we_i : in std_ulogic; -- global write enable + csr_re_i : in std_ulogic; -- global read enable + csr_addr_i : in std_ulogic_vector(11 downto 0); -- address + csr_wdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- write data + csr_rdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- read data + -- ICC TX links -- + icc_tx_rdy_o : out std_ulogic_vector(NUM_HARTS-1 downto 0); -- data available + icc_tx_ack_i : in std_ulogic_vector(NUM_HARTS-1 downto 0); -- read-enable + icc_tx_dat_o : out std_ulogic_vector((NUM_HARTS*XLEN)-1 downto 0); -- data word + -- ICC RX links -- + icc_rx_rdy_i : in std_ulogic_vector(NUM_HARTS-1 downto 0); -- data available + icc_rx_ack_o : out std_ulogic_vector(NUM_HARTS-1 downto 0); -- read-enable + icc_rx_dat_i : in std_ulogic_vector((NUM_HARTS*XLEN)-1 downto 0) -- data word + ); +end neorv32_cpu_icc; + +architecture neorv32_cpu_icc_rtl of neorv32_cpu_icc is + + -- link select -- + constant id_width_c : natural := index_size_f(NUM_HARTS); + signal link_id : std_ulogic_vector(id_width_c-1 downto 0); + + -- link control -- + signal link_sel, tx_fifo_we, tx_fifo_free : std_ulogic_vector(NUM_HARTS-1 downto 0); + + -- incoming data as array -- + type rx_data_t is array (0 to NUM_HARTS-1) of std_ulogic_vector(XLEN-1 downto 0); + signal rx_data : rx_data_t; + +begin + + -- CSR Access ----------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + csr_write: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + link_id <= (others => '0'); + elsif rising_edge(clk_i) then + if (csr_we_i = '1') and (csr_addr_i(11 downto 1) = csr_mxiccsr0_c(11 downto 1)) then + link_id <= csr_wdata_i(id_width_c-1 downto 0); + end if; + end if; + end process csr_write; + + csr_read: process(csr_addr_i, link_id, icc_rx_rdy_i, tx_fifo_free, rx_data) + begin + csr_rdata_o <= (others => '0'); -- default + if (csr_addr_i(11 downto 2) = csr_mxiccrxd_c(11 downto 2)) then -- ICC CSRs base address + if (csr_addr_i(1) = '0') then -- data register(s) + csr_rdata_o <= rx_data(to_integer(unsigned(link_id))); + else -- control and status register(s) + csr_rdata_o(XLEN-1) <= icc_rx_rdy_i(to_integer(unsigned(link_id))); + csr_rdata_o(XLEN-2) <= tx_fifo_free(to_integer(unsigned(link_id))); + csr_rdata_o(id_width_c-1 downto 0) <= link_id; + end if; + end if; + end process csr_read; + + + -- Communication Links -------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + link_gen: + for i in 0 to NUM_HARTS-1 generate + + -- TX FIFOs for outgoing links -- + queue_gen: + if i /= HART_ID generate + queue_inst: entity neorv32.neorv32_fifo + generic map ( + FIFO_DEPTH => 4, -- yes, this is fixed + FIFO_WIDTH => XLEN, + FIFO_RSYNC => true, + FIFO_SAFE => true, + FULL_RESET => true + ) + port map ( + -- control -- + clk_i => clk_i, + rstn_i => rstn_i, + clear_i => '0', + half_o => open, + -- write port -- + wdata_i => csr_wdata_i, + we_i => tx_fifo_we(i), + free_o => tx_fifo_free(i), + -- read port -- + re_i => icc_tx_ack_i(i), + rdata_o => icc_tx_dat_o(i*XLEN+(XLEN-1) downto i*XLEN), + avail_o => icc_tx_rdy_o(i) + ); + end generate; + + -- no FIFO/link for *this* core -- + queue_terminate: + if i = HART_ID generate + tx_fifo_free(i) <= '0'; + icc_tx_dat_o(i*XLEN+(XLEN-1) downto i*XLEN) <= (others => '0'); + icc_tx_rdy_o(i) <= '0'; + end generate; + + -- reorganize incoming links as 2d-array -- + rx_data(i) <= icc_rx_dat_i(i*XLEN+(XLEN-1) downto i*XLEN); + + -- link control -- + link_sel(i) <= '1' when (unsigned(link_id) = to_unsigned(i, id_width_c)) else '0'; + icc_rx_ack_o(i) <= '1' when (csr_re_i = '1') and (csr_addr_i = csr_mxiccrxd_c) and (link_sel(i) = '1') else '0'; + tx_fifo_we(i) <= '1' when (csr_we_i = '1') and (csr_addr_i = csr_mxicctxd_c) and (link_sel(i) = '1') else '0'; + + end generate; + + +end neorv32_cpu_icc_rtl; diff --git a/rtl/file_list_cpu.f b/rtl/file_list_cpu.f index 2df0a0b67..60e4609de 100644 --- a/rtl/file_list_cpu.f +++ b/rtl/file_list_cpu.f @@ -14,4 +14,5 @@ NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_alu.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_lsu.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_pmp.vhd +NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_icc.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu.vhd diff --git a/rtl/file_list_soc.f b/rtl/file_list_soc.f index b495e38f7..76da9d04d 100644 --- a/rtl/file_list_soc.f +++ b/rtl/file_list_soc.f @@ -15,6 +15,7 @@ NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_alu.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_lsu.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_pmp.vhd +NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_icc.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_bus.vhd NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cache.vhd From dc43074f109801b1e5b6201ce1984550664cfa10 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 21:59:29 +0100 Subject: [PATCH 02/21] [csr] add ICC CSRs --- docs/datasheet/cpu_csr.adoc | 120 +++++++++++++++++++++++-------- rtl/core/neorv32_cpu_control.vhd | 15 ++-- rtl/core/neorv32_package.vhd | 12 ++-- sw/lib/include/neorv32_cpu_csr.h | 24 ++++++- 4 files changed, 129 insertions(+), 42 deletions(-) diff --git a/docs/datasheet/cpu_csr.adoc b/docs/datasheet/cpu_csr.adoc index de64b19e6..249ec1071 100644 --- a/docs/datasheet/cpu_csr.adoc +++ b/docs/datasheet/cpu_csr.adoc @@ -57,8 +57,6 @@ to check if the targeted bits can actually be modified. | 0x7b0 | <<_dcsr>> | - | DRW | Debug control and status register | 0x7b1 | <<_dpc>> | - | DRW | Debug program counter | 0x7b2 | <<_dscratch0>> | - | DRW | Debug scratch register 0 -5+^| **<<_custom_functions_unit_cfu_csrs>>** -| 0x800 .. 0x803 | <<_cfureg, `cfureg0`>> .. <<_cfureg, `cfureg3`>> | `CSR_CFUCREG0` .. `CSR_CFUCREG3` | URW | Custom CFU registers 0 to 3 5+^| **<<_machine_counter_and_timer_csrs>>** | 0xb00 | <<_mcycleh, `mcycle`>> | `CSR_MCYCLE` | MRW | Machine cycle counter low word | 0xb02 | <<_minstreth, `minstret`>> | `CSR_MINSTRET` | MRW | Machine instruction-retired counter low word @@ -79,7 +77,11 @@ to check if the targeted bits can actually be modified. | 0xf14 | <<_mhartid>> | `CSR_MHARTID` | MRO | Machine hardware thread ID | 0xf15 | <<_mconfigptr>> | `CSR_MCONFIGPTR` | MRO | Machine configuration pointer register 5+^| **<<_neorv32_specific_csrs>>** -| 0xfc0 | <<_mxisa>> | `CSR_MXISA` | MRO | NEORV32-specific "eXtended" machine CPU ISA and extensions +| 0xbc0 | <<_mxiccrxd>> | `CSR_MXICCRXD` | MRW | ICC RX data +| 0xbc1 | <<_mxicctxd>> | `CSR_MXICCTXD` | MRW | ICC TX data +| 0xbc2 .. 0xbc3 | <<_mxiccsr, `mxiccsr0`>> .. <<_mxiccsr, `mxiccsr0`>> | `CSR_MXICCSR0` .. `CSR_MXICCSR3` | MRW | ICC control and status +| 0x800 .. 0x803 | <<_cfureg, `cfureg0`>> .. <<_cfureg, `cfureg3`>> | `CSR_CFUCREG0` .. `CSR_CFUCREG3` | URW | Custom CFU registers 0 to 3 +| 0xfc0 | <<_mxisa>> | `CSR_MXISA` | MRO | Extended machine CPU ISA and extensions |======================= @@ -595,28 +597,6 @@ implementation of the according modes. |======================= -<<< -// #################################################################################################################### -:sectnums: -==== Custom Functions Unit (CFU) CSRs - -[discrete] -===== **`cfureg`** - -[cols="<1,<8"] -[frame="topbot",grid="none"] -|======================= -| Name | Custom (user-defined) CFU CSRs -| Address | `0x800` (`cfureg0`) -| | `0x801` (`cfureg1`) -| | `0x802` (`cfureg2`) -| | `0x803` (`cfureg3`) -| Reset value | `0x00000000` -| ISA | `Zicsr` & `Zxcfu` -| Description | User-defined CSRs to be used within the <<_custom_functions_unit_cfu>>. -|======================= - - <<< // #################################################################################################################### :sectnums: @@ -929,12 +909,92 @@ core's hart ID is unique starting at 0 for the first core. :sectnums: ==== NEORV32-Specific CSRs +.RISC-V-Compliant Mapping [NOTE] -All NEORV32-specific CSRs are mapped to addresses that are explicitly reserved for custom **Machine-Mode, read-only** CSRs -(assured by the RISC-V privileged specifications). Hence, these CSRs can only be accessed when in machine-mode. Any access -outside of machine-mode will raise an illegal instruction exception. +All NEORV32-specific CSRs are mapped to addresses that are explicitly reserved for +custom/implementation-specific use (assured by the RISC-V privileged specifications). + + +[discrete] +===== **`cfureg`** + +[cols="<1,<8"] +[frame="topbot",grid="none"] +|======================= +| Name | Custom (user-defined) CFU CSRs +| Address | `0x800` (`cfureg0`) +| | `0x801` (`cfureg1`) +| | `0x802` (`cfureg2`) +| | `0x803` (`cfureg3`) +| Reset value | `0x00000000` +| ISA | `Zicsr` & `Zxcfu` +| Description | User-defined CSRs to be used within the <<_custom_functions_unit_cfu>>. +|======================= + + +{empty} + +[discrete] +===== **`mxiccrxd`** + +[cols="<1,<8"] +[frame="topbot",grid="none"] +|======================= +| Name | <<_inter_core_communication_icc>> RX data +| Address | `0xbc0` +| Reset value | `0x00000000` +| ISA | `Zicsr` & `X` +| Description | RX data from selected link. Buffered by a 4-entries-deep and 32-bit wide FIFO. +This CSR is hardwired to all-zero if there is just a single CPU core in the system. +|======================= + + +{empty} + +[discrete] +===== **`mxicctxd`** + +[cols="<1,<8"] +[frame="topbot",grid="none"] +|======================= +| Name | <<_inter_core_communication_icc>> TX data +| Address | `0xbc1` +| Reset value | `0x00000000` +| ISA | `Zicsr` & `X` +| Description | TX data for selected link. Buffered by a 4-entries-deep and 32-bit wide FIFO. +This CSR is hardwired to all-zero if there is just a single CPU core in the system. +|======================= +{empty} + +[discrete] +===== **`mxiccsr`** +[cols="<1,<8"] +[frame="topbot",grid="none"] +|======================= +| Name | <<_inter_core_communication_icc>> control and status +| Address | `0xbc2` (`mxiccsr0`) +| | `0xbc3` (`mxiccsr1`) +| Reset value | `0x40000000` +| ISA | `Zicsr` & `X` +| Description | Link selection and status. Note that `mxiccsr1` is just a mirrored copy of `mxiccsr0`. +This CSR is hardwired to all-zero if there is just a single CPU core in the system. +|======================= + +.`mxiccsr` CSR Bits +[cols="^1,^2,^1,<5"] +[options="header",grid="rows"] +|======================= +| Bit | Name [C] | R/W | Description +| 1:0 | `CSR_MXICCSR_LINK_MSB : CSR_MXICCSR_LINK_LSB` | r/w | Link select. The value in this memory corresponds +to the ID of the core to which a connection is to be established via a link. The ICC data registers <<_mxiccrxd>> +and <<_mxicctxd>> will only access the queue FIFOs of the selected link. Not that only bit 0 is writable. Bit 1 +is hardwaired to zero. +| 29:2 | - | r/- | Reserved; hardwired to zero. +| 30 | `CSR_MXICCSR_TX_FREE` | r/- | Set if there is free space for TX data for the selected link. +| 31 | `CSR_MXICCSR_RX_AVAIL` | r/- | Set if RX data from the selected link is available. +|======================= + + +{empty} + [discrete] ===== **`mxisa`** @@ -946,7 +1006,7 @@ outside of machine-mode will raise an illegal instruction exception. | Reset value | `DEFINED` | ISA | `Zicsr` & `X` | Description | The `mxisa` CSRs is a NEORV32-specific read-only CSR that helps machine-mode software to -discover ISA sub-extensions and CPU configuration options +discover additional ISA (sub-)extensions and CPU configuration options. |======================= .`mxisa` CSR Bits @@ -985,5 +1045,5 @@ discover ISA sub-extensions and CPU configuration options | 28 | `CSR_MXISA_RFHWRST` | r/- | full hardware reset of register file available when set (`CPU_RF_HW_RST_EN`), see <<_cpu_tuning_options>> | 29 | `CSR_MXISA_FASTMUL` | r/- | fast multiplication available when set (`CPU_FAST_MUL_EN`), see <<_cpu_tuning_options>> | 30 | `CSR_MXISA_FASTSHIFT` | r/- | fast shifts available when set (`CPU_FAST_SHIFT_EN`), see <<_cpu_tuning_options>> -| 31 | `CSR_MXISA_IS_SIM` | r/- | set if CPU is being **simulated** (⚠️ not guaranteed) +| 31 | `CSR_MXISA_IS_SIM` | r/- | set if CPU is being **simulated** |======================= diff --git a/rtl/core/neorv32_cpu_control.vhd b/rtl/core/neorv32_cpu_control.vhd index 24058d89c..0f182e612 100644 --- a/rtl/core/neorv32_cpu_control.vhd +++ b/rtl/core/neorv32_cpu_control.vhd @@ -29,7 +29,7 @@ use neorv32.neorv32_package.all; entity neorv32_cpu_control is generic ( -- General -- - HART_ID : natural; -- hardware thread ID + HART_ID : natural range 0 to 3; -- hardware thread ID VENDOR_ID : std_ulogic_vector(31 downto 0); -- vendor's JEDEC ID BOOT_ADDR : std_ulogic_vector(31 downto 0); -- cpu boot address DEBUG_PARK_ADDR : std_ulogic_vector(31 downto 0); -- cpu debug-mode parking loop entry address, 4-byte aligned @@ -923,9 +923,10 @@ begin csr_valid(2) <= bool_to_ulogic_f(RISCV_ISA_Zfinx); -- available if FPU implemented -- machine trap setup/handling, environment/information registers, etc. -- - when csr_mstatus_c | csr_mstatush_c | csr_misa_c | csr_mie_c | csr_mtvec_c | csr_mscratch_c | - csr_mepc_c | csr_mcause_c | csr_mip_c | csr_mtval_c | csr_mtinst_c | csr_mcountinhibit_c | - csr_mvendorid_c | csr_marchid_c | csr_mimpid_c | csr_mhartid_c | csr_mconfigptr_c | csr_mxisa_c => + when csr_mstatus_c | csr_mstatush_c | csr_misa_c | csr_mie_c | csr_mtvec_c | csr_mscratch_c | + csr_mepc_c | csr_mcause_c | csr_mip_c | csr_mtval_c | csr_mtinst_c | csr_mcountinhibit_c | + csr_mvendorid_c | csr_marchid_c | csr_mimpid_c | csr_mhartid_c | csr_mconfigptr_c | csr_mxisa_c | + csr_mxiccrxd_c | csr_mxicctxd_c | csr_mxiccsr0_c | csr_mxiccsr1_c => csr_valid(2) <= '1'; -- always implemented -- machine-controlled user-mode CSRs -- @@ -1658,6 +1659,12 @@ begin csr.rdata <= xcsr_rdata_i; -- implemented externally end if; + -- -------------------------------------------------------------------- + -- inter-core communication + -- -------------------------------------------------------------------- + when csr_mxiccrxd_c | csr_mxicctxd_c | csr_mxiccsr0_c | csr_mxiccsr1_c => + csr.rdata <= xcsr_rdata_i; -- implemented externally + -- -------------------------------------------------------------------- -- machine trap setup -- -------------------------------------------------------------------- diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index f957a7820..3f254eef0 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -29,7 +29,7 @@ package neorv32_package is -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100807"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100808"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width @@ -436,7 +436,7 @@ package neorv32_package is constant csr_dcsr_c : std_ulogic_vector(11 downto 0) := x"7b0"; constant csr_dpc_c : std_ulogic_vector(11 downto 0) := x"7b1"; constant csr_dscratch0_c : std_ulogic_vector(11 downto 0) := x"7b2"; - -- NEORV32-specific user registers -- + -- NEORV32-specific read/write user registers -- constant csr_cfureg0_c : std_ulogic_vector(11 downto 0) := x"800"; constant csr_cfureg1_c : std_ulogic_vector(11 downto 0) := x"801"; constant csr_cfureg2_c : std_ulogic_vector(11 downto 0) := x"802"; @@ -475,8 +475,11 @@ package neorv32_package is constant csr_mhpmcounter13h_c : std_ulogic_vector(11 downto 0) := x"b8d"; constant csr_mhpmcounter14h_c : std_ulogic_vector(11 downto 0) := x"b8e"; constant csr_mhpmcounter15h_c : std_ulogic_vector(11 downto 0) := x"b8f"; - -- NEORV32-specific read-write machine registers -- ---constant csr_mxstatus_c : std_ulogic_vector(11 downto 0) := x"bc0"; -- to-be-implemented + -- NEORV32-specific read/write machine registers -- + constant csr_mxiccrxd_c : std_ulogic_vector(11 downto 0) := x"bc0"; + constant csr_mxicctxd_c : std_ulogic_vector(11 downto 0) := x"bc1"; + constant csr_mxiccsr0_c : std_ulogic_vector(11 downto 0) := x"bc2"; + constant csr_mxiccsr1_c : std_ulogic_vector(11 downto 0) := x"bc3"; -- user counters/timers -- constant csr_cycle_c : std_ulogic_vector(11 downto 0) := x"c00"; --constant csr_time_c : std_ulogic_vector(11 downto 0) := x"c01"; @@ -493,7 +496,6 @@ package neorv32_package is constant csr_mconfigptr_c : std_ulogic_vector(11 downto 0) := x"f15"; -- NEORV32-specific read-only machine registers -- constant csr_mxisa_c : std_ulogic_vector(11 downto 0) := x"fc0"; ---constant csr_mxisah_c : std_ulogic_vector(11 downto 0) := x"fc1"; -- to-be-implemented -- ********************************************************************************************************** -- CPU Control diff --git a/sw/lib/include/neorv32_cpu_csr.h b/sw/lib/include/neorv32_cpu_csr.h index de650d4a7..d6432c31e 100644 --- a/sw/lib/include/neorv32_cpu_csr.h +++ b/sw/lib/include/neorv32_cpu_csr.h @@ -1,7 +1,7 @@ // ================================================================================ // // The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // // Copyright (c) NEORV32 contributors. // -// Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. // +// Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. // // Licensed under the BSD-3-Clause license, see LICENSE for details. // // SPDX-License-Identifier: BSD-3-Clause // // ================================================================================ // @@ -137,6 +137,12 @@ enum NEORV32_CSR_enum { CSR_MHPMCOUNTER14H = 0xb8e, /**< 0xb8e - mhpmcounter14h: Machine hardware performance monitor 14 counter high word */ CSR_MHPMCOUNTER15H = 0xb8f, /**< 0xb8f - mhpmcounter15h: Machine hardware performance monitor 15 counter high word */ + /* inter-core communication */ + CSR_MXICCRXD = 0xbc0, /**< 0xbc0 - mxiccrxd: Machine ICC link RX data */ + CSR_MXICCTXD = 0xbc1, /**< 0xbc1 - mxicctxd: Machine ICC link TX data */ + CSR_MXICCSR0 = 0xbc2, /**< 0xbc1 - mxiccsr0: Machine ICC link status register 0 (#NEORV32_CSR_MXICCSR_enum) */ + CSR_MXICCSR1 = 0xbc3, /**< 0xbc1 - mxiccsr1: Machine ICC link status register 1 (#NEORV32_CSR_MXICCSR_enum) */ + /* user counters and timers */ CSR_CYCLE = 0xc00, /**< 0xc00 - cycle: User cycle counter low word */ CSR_INSTRET = 0xc02, /**< 0xc02 - instret: User instructions-retired counter low word */ @@ -150,7 +156,7 @@ enum NEORV32_CSR_enum { CSR_MIMPID = 0xf13, /**< 0xf13 - mimpid: Machine implementation ID */ CSR_MHARTID = 0xf14, /**< 0xf14 - mhartid: Machine hardware thread ID */ CSR_MCONFIGPTR = 0xf15, /**< 0xf15 - mconfigptr: Machine configuration pointer register */ - CSR_MXISA = 0xfc0 /**< 0xfc0 - mxisa: Machine extended ISA and extensions (#NEORV32_CSR_XISA_enum) */ + CSR_MXISA = 0xfc0 /**< 0xfc0 - mxisa: Machine extended ISA and extensions (#NEORV32_CSR_MXISA_enum) */ }; @@ -302,7 +308,7 @@ enum NEORV32_CSR_MISA_enum { /**********************************************************************//** * CPU mxisa CSR (r/-): Machine extended instruction set extensions (NEORV32-specific) **************************************************************************/ -enum NEORV32_CSR_XISA_enum { +enum NEORV32_CSR_MXISA_enum { // ISA (sub-)extensions CSR_MXISA_ZICSR = 0, /**< CPU mxisa CSR (0): privileged architecture (r/-)*/ CSR_MXISA_ZIFENCEI = 1, /**< CPU mxisa CSR (1): instruction stream sync (r/-)*/ @@ -340,6 +346,18 @@ enum NEORV32_CSR_XISA_enum { }; +/**********************************************************************//** + * CPU mxiccsr CSR (r/w): Inter-core communication control and status (NEORV32-specific) + **************************************************************************/ +enum NEORV32_CSR_MXICCSR_enum { + CSR_MXICCSR_LINK_LSB = 0, /**< CPU mxiccsr CSR (0): link/hart select LSB (r/w)*/ + CSR_MXICCSR_LINK_MSB = 1, /**< CPU mxiccsr CSR (1): link/hart select MSB (r/w)*/ + + CSR_MXICCSR_TX_FREE = 30, /**< CPU mxiccsr CSR (30): Free space in selected link's TX FIFO (r/-)*/ + CSR_MXICCSR_RX_AVAIL = 31 /**< CPU mxiccsr CSR (31): Data available in selected link's RX FIFO (r/-)*/ +}; + + /**********************************************************************//** * CPU mhpmevent hardware performance monitor events **************************************************************************/ From 3f81f54dbb559eca0fedfc89c542a8baaf1332c6 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 21:59:56 +0100 Subject: [PATCH 03/21] [cpu] add inter-core communication links --- docs/datasheet/cpu.adoc | 37 ++++++++++------ rtl/core/neorv32_cpu.vhd | 95 ++++++++++++++++++++++++++++++---------- 2 files changed, 96 insertions(+), 36 deletions(-) diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc index ded6effe6..780c7fafd 100644 --- a/docs/datasheet/cpu.adoc +++ b/docs/datasheet/cpu.adoc @@ -62,25 +62,33 @@ type of all signals is _std_ulogic_ or _std_ulogic_vector_, respectively. The "D direction as seen from the CPU. .NEORV32 CPU Signal List -[cols="<3,^3,^1,<5"] +[cols="^2,^2,^1,<8"] [options="header", grid="rows"] |======================= | Signal | Width/Type | Dir | Description 4+^| **Global Signals** -| `clk_i` | 1 | in | Global clock line, all registers triggering on rising edge. -| `rstn_i` | 1 | in | Global reset, low-active. +| `clk_i` | 1 | in | Global clock line, all registers triggering on rising edge. +| `rstn_i` | 1 | in | Global reset, low-active. 4+^| **Interrupts (<<_traps_exceptions_and_interrupts>>)** -| `msi_i` | 1 | in | RISC-V machine software interrupt. -| `mei_i` | 1 | in | RISC-V machine external interrupt. -| `mti_i` | 1 | in | RISC-V machine timer interrupt. -| `firq_i` | 16 | in | Custom fast interrupt request signals. -| `dbi_i` | 1 | in | Request CPU to halt and enter debug mode (RISC-V <<_on_chip_debugger_ocd>>). +| `msi_i` | 1 | in | RISC-V machine software interrupt. +| `mei_i` | 1 | in | RISC-V machine external interrupt. +| `mti_i` | 1 | in | RISC-V machine timer interrupt. +| `firq_i` | 16 | in | Custom fast interrupt request signals. +| `dbi_i` | 1 | in | Request CPU to halt and enter debug mode (RISC-V <<_on_chip_debugger_ocd>>). 4+^| **Instruction <<_bus_interface>>** -| `ibus_req_o` | `bus_req_t` | out | Instruction fetch bus request. -| `ibus_rsp_i` | `bus_rsp_t` | in | Instruction fetch bus response. +| `ibus_req_o` | `bus_req_t` | out | Instruction fetch bus request. +| `ibus_rsp_i` | `bus_rsp_t` | in | Instruction fetch bus response. 4+^| **Data <<_bus_interface>>** -| `dbus_req_o` | `bus_req_t` | out | Data access (load/store) bus request. -| `dbus_rsp_i` | `bus_rsp_t` | in | Data access (load/store) bus response. +| `dbus_req_o` | `bus_req_t` | out | Data access (load/store) bus request. +| `dbus_rsp_i` | `bus_rsp_t` | in | Data access (load/store) bus response. +4+^| **<<_inter_core_communication_icc>> TX links** +| `icc_tx_rdy_o` | 2 | out | Data available for cores `0..1`. +| `icc_tx_ack_i` | 2 | in | Read-enable from cores `0..1`. +| `icc_tx_dat_o` | 2*32 | out | Data for cores `0..1`. +4+^| **<<_inter_core_communication_icc>> RX links** +| `icc_rx_rdy_i` | 2 | in | Data available from cores `0..1`. +| `icc_rx_ack_o` | 2 | out | Read-enable for cores `0..1`. +| `icc_rx_dat_i` | 2*32 | in | Data from cores `0..1`. |======================= .Bus Interface Protocol @@ -109,8 +117,9 @@ The generic type "suv(x:y)" represents a `std_ulogic_vector(x downto y)`. [options="header",grid="rows"] |======================= | Name | Type | Description -| `HART_ID` | natural | Value for the <<_mhartid>> CSR. -| `VENDOR_ID` | suv(31:0) | Value for the <<_mvendorid>> CSR. +| `HART_ID` | natural | ID of the core (for <<_mhartid>> CSR). +| `NUM_HARTS` | natural | Total number of cores in the system. +| `VENDOR_ID` | suv(31:0) | Vendor identification (for <<_mvendorid>> CSR). | `BOOT_ADDR` | suv(31:0) | CPU reset address. See section <<_address_space>>. | `DEBUG_PARK_ADDR` | suv(31:0) | "Park loop" entry address for the <<_on_chip_debugger_ocd>>, has to be 4-byte aligned. | `DEBUG_EXC_ADDR` | suv(31:0) | "Exception" entry address for the <<_on_chip_debugger_ocd>>, has to be 4-byte aligned. diff --git a/rtl/core/neorv32_cpu.vhd b/rtl/core/neorv32_cpu.vhd index 37c216a0d..60fbe5127 100644 --- a/rtl/core/neorv32_cpu.vhd +++ b/rtl/core/neorv32_cpu.vhd @@ -22,7 +22,8 @@ use neorv32.neorv32_package.all; entity neorv32_cpu is generic ( -- General -- - HART_ID : natural; -- hardware thread ID + HART_ID : natural range 0 to 3; -- hardware thread ID + NUM_HARTS : natural range 1 to 4; -- total number of harts in the system, has to be a power of 2 VENDOR_ID : std_ulogic_vector(31 downto 0); -- vendor's JEDEC ID BOOT_ADDR : std_ulogic_vector(31 downto 0); -- cpu boot address DEBUG_PARK_ADDR : std_ulogic_vector(31 downto 0); -- cpu debug mode parking loop entry address @@ -69,20 +70,28 @@ entity neorv32_cpu is ); port ( -- global control -- - clk_i : in std_ulogic; -- switchable global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async + clk_i : in std_ulogic; -- switchable global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async -- interrupts -- - msi_i : in std_ulogic; -- risc-v machine software interrupt - mei_i : in std_ulogic; -- risc-v machine external interrupt - mti_i : in std_ulogic; -- risc-v machine timer interrupt - firq_i : in std_ulogic_vector(15 downto 0); -- custom fast interrupts - dbi_i : in std_ulogic; -- risc-v debug halt request interrupt + msi_i : in std_ulogic; -- risc-v machine software interrupt + mei_i : in std_ulogic; -- risc-v machine external interrupt + mti_i : in std_ulogic; -- risc-v machine timer interrupt + firq_i : in std_ulogic_vector(15 downto 0); -- custom fast interrupts + dbi_i : in std_ulogic; -- risc-v debug halt request interrupt -- instruction bus interface -- - ibus_req_o : out bus_req_t; -- request bus - ibus_rsp_i : in bus_rsp_t; -- response bus + ibus_req_o : out bus_req_t; -- request bus + ibus_rsp_i : in bus_rsp_t; -- response bus -- data bus interface -- - dbus_req_o : out bus_req_t; -- request bus - dbus_rsp_i : in bus_rsp_t -- response bus + dbus_req_o : out bus_req_t; -- request bus + dbus_rsp_i : in bus_rsp_t; -- response bus + -- ICC TX links -- + icc_tx_rdy_o : out std_ulogic_vector(NUM_HARTS-1 downto 0); -- data available + icc_tx_ack_i : in std_ulogic_vector(NUM_HARTS-1 downto 0); -- read-enable + icc_tx_dat_o : out std_ulogic_vector((NUM_HARTS*XLEN)-1 downto 0); -- data word + -- ICC RX links -- + icc_rx_rdy_i : in std_ulogic_vector(NUM_HARTS-1 downto 0); -- data available + icc_rx_ack_o : out std_ulogic_vector(NUM_HARTS-1 downto 0); -- read-enable + icc_rx_dat_i : in std_ulogic_vector((NUM_HARTS*XLEN)-1 downto 0) -- data word ); end neorv32_cpu; @@ -98,12 +107,14 @@ architecture neorv32_cpu_rtl of neorv32_cpu is RISCV_ISA_Zksh and RISCV_ISA_Zksed; -- Zks: ShangMi suite -- external CSR interface -- + signal xcsr_re : std_ulogic; signal xcsr_we : std_ulogic; signal xcsr_addr : std_ulogic_vector(11 downto 0); signal xcsr_wdata : std_ulogic_vector(XLEN-1 downto 0); signal xcsr_rdata_pmp : std_ulogic_vector(XLEN-1 downto 0); signal xcsr_rdata_alu : std_ulogic_vector(XLEN-1 downto 0); signal xcsr_rdata_res : std_ulogic_vector(XLEN-1 downto 0); + signal xcsr_rdata_icc : std_ulogic_vector(XLEN-1 downto 0); -- local signals -- signal clk_gated : std_ulogic; -- switchable clock (clock gating) @@ -128,7 +139,7 @@ architecture neorv32_cpu_rtl of neorv32_cpu is begin - -- Sanity Checks -------------------------------------------------------------------------- + -- Configuration Info and Sanity Checks --------------------------------------------------- -- ------------------------------------------------------------------------------------------- -- CPU ISA configuration (in alphabetical order - not in canonical order!) -- assert false report "[NEORV32] CPU ISA: rv32" & @@ -177,6 +188,10 @@ begin -- simulation notifier -- assert not is_simulation_c report "[NEORV32] Assuming this is a simulation." severity warning; + -- ID checks -- + assert is_power_of_two_f(NUM_HARTS) report "[NEORV32] NUM_HARTS has to be a power of two." severity error; + assert (HART_ID < NUM_HARTS) report "[NEORV32] HART_ID out of range." severity error; + -- Clock Gating --------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -197,7 +212,7 @@ begin end generate; - -- Control Unit --------------------------------------------------------------------------- + -- Control Unit (CTRL) -------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_cpu_control_inst: entity neorv32.neorv32_cpu_control generic map ( @@ -269,7 +284,7 @@ begin csr_rdata_o => csr_rdata, -- CSR read data -- external CSR interface -- xcsr_we_o => xcsr_we, -- global write enable - xcsr_re_o => open, -- global read enable + xcsr_re_o => xcsr_re, -- global read enable xcsr_addr_o => xcsr_addr, -- address xcsr_wdata_o => xcsr_wdata, -- write data xcsr_rdata_i => xcsr_rdata_res, -- read data @@ -287,10 +302,10 @@ begin irq_machine <= mti_i & mei_i & msi_i; -- external CSR read-back -- - xcsr_rdata_res <= xcsr_rdata_pmp or xcsr_rdata_alu; + xcsr_rdata_res <= xcsr_rdata_alu or xcsr_rdata_pmp or xcsr_rdata_icc; - -- Register File -------------------------------------------------------------------------- + -- Register File (RF) --------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_cpu_regfile_inst: entity neorv32.neorv32_cpu_regfile generic map ( @@ -314,7 +329,7 @@ begin rf_wdata <= alu_res or lsu_rdata or csr_rdata or pc_ret; - -- ALU (Arithmetic/Logic Unit) and ALU Co-Processors -------------------------------------- + -- Arithmetic/Logic Unit (ALU) and ALU Co-Processors -------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_cpu_alu_inst: entity neorv32.neorv32_cpu_alu generic map ( @@ -364,7 +379,7 @@ begin ); - -- Load/Store Unit ------------------------------------------------------------------------ + -- Load/Store Unit (LSU) ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- neorv32_cpu_lsu_inst: entity neorv32.neorv32_cpu_lsu generic map ( @@ -389,9 +404,9 @@ begin ); - -- Physical Memory Protection ------------------------------------------------------------- + -- Physical Memory Protection (PMP) ------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - pmp_inst_true: + pmp_enabled: if RISCV_ISA_Smpmp generate neorv32_cpu_pmp_inst: entity neorv32.neorv32_cpu_pmp generic map ( @@ -418,11 +433,47 @@ begin ); end generate; - pmp_inst_false: + pmp_disabled: if not RISCV_ISA_Smpmp generate xcsr_rdata_pmp <= (others => '0'); pmp_fault <= '0'; end generate; + -- Inter-Core Communication (ICC) --------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + icc_enabled: + if NUM_HARTS > 1 generate + neorv32_cpu_icc_inst: entity neorv32.neorv32_cpu_icc + generic map ( + HART_ID => HART_ID, -- ID of this core + NUM_HARTS => NUM_HARTS -- number of cores, has to be a power of two + ) + port map ( + -- global control -- + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + -- CSR interface -- + csr_we_i => xcsr_we, -- global write enable + csr_re_i => xcsr_re, -- global read enable + csr_addr_i => xcsr_addr, -- address + csr_wdata_i => xcsr_wdata, -- write data + csr_rdata_o => xcsr_rdata_icc, -- read data + -- ICC TX links -- + icc_tx_rdy_o => icc_tx_rdy_o, -- data available + icc_tx_ack_i => icc_tx_ack_i, -- read-enable + icc_tx_dat_o => icc_tx_dat_o, -- data word + -- ICC RX links -- + icc_rx_rdy_i => icc_rx_rdy_i, -- data available + icc_rx_ack_o => icc_rx_ack_o, -- read-enable + icc_rx_dat_i => icc_rx_dat_i -- data word + ); + end generate; + + icc_disabled: + if NUM_HARTS = 1 generate + xcsr_rdata_icc <= (others => '0'); + end generate; + + end neorv32_cpu_rtl; From 271ff4a734478c75d0c57facff95187db4ac100d Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:04:09 +0100 Subject: [PATCH 04/21] [changelog] add v1.10.8.8 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f1fc9094..22db89141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date | Version | Comment | Ticket | |:----:|:-------:|:--------|:------:| +| 04.01.2025 | 1.10.8.8 | :sparkles: add inter-core communication (ICC) for the SMP dual-core setup | [#1142](https://github.com/stnolting/neorv32/pull/1142) | | 03.01.2025 | 1.10.8.7 | :warning: :sparkles: replace `Zalrsc` ISA extensions (reservation-set operations) by `Zaamo` ISA extension (atomic read-modify-write operations) | [#1141](https://github.com/stnolting/neorv32/pull/1141) | | 01.01.2025 | 1.10.8.6 | :sparkles: :test_tube: add smp dual-core option | [#1135](https://github.com/stnolting/neorv32/pull/1135) | | 29.12.2024 | 1.10.8.5 | :test_tube: add multi-hart support to debug module | [#1132](https://github.com/stnolting/neorv32/pull/1132) | From 1002ab6230794d19e6a8ceee5305d6461621de2c Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:04:34 +0100 Subject: [PATCH 05/21] [top] add inter-core com wiring --- rtl/core/neorv32_top.vhd | 191 +++++++++++++++++++++++---------------- 1 file changed, 114 insertions(+), 77 deletions(-) diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd index c53bf89ae..55a1c55a5 100644 --- a/rtl/core/neorv32_top.vhd +++ b/rtl/core/neorv32_top.vhd @@ -310,6 +310,14 @@ architecture neorv32_top_rtl of neorv32_top is signal dci_ndmrstn : std_ulogic; signal dci_haltreq : std_ulogic_vector(num_cores_c-1 downto 0); + -- CPU ICC links -- + type icc_rdy_t is array (0 to num_cores_c-1) of std_ulogic_vector(num_cores_c-1 downto 0); + type icc_ack_t is array (0 to num_cores_c-1) of std_ulogic_vector(num_cores_c-1 downto 0); + type icc_dat_t is array (0 to num_cores_c-1) of std_ulogic_vector(num_cores_c*32-1 downto 0); + signal icc_tx_rdy, icc_rx_rdy : icc_rdy_t; + signal icc_tx_ack, icc_rx_ack : icc_ack_t; + signal icc_tx_dat, icc_rx_dat : icc_dat_t; + -- bus: CPU core(s) + L1 caches -- type multicore_req_t is array (0 to num_cores_c-1) of bus_req_t; type multicore_rsp_t is array (0 to num_cores_c-1) of bus_rsp_t; @@ -499,6 +507,7 @@ begin generic map ( -- General -- HART_ID => i, + NUM_HARTS => num_cores_c, VENDOR_ID => vendorid_c, BOOT_ADDR => cpu_boot_addr_c, DEBUG_PARK_ADDR => dm_park_entry_c, @@ -545,26 +554,54 @@ begin ) port map ( -- global control -- - clk_i => clk_i, - rstn_i => rstn_sys, + clk_i => clk_i, + rstn_i => rstn_sys, -- interrupts -- - msi_i => msw_irq(i), - mei_i => mext_irq_i, - mti_i => mtime_irq(i), - firq_i => cpu_firq, - dbi_i => dci_haltreq(i), + msi_i => msw_irq(i), + mei_i => mext_irq_i, + mti_i => mtime_irq(i), + firq_i => cpu_firq, + dbi_i => dci_haltreq(i), -- instruction bus interface -- - ibus_req_o => cpu_i_req(i), - ibus_rsp_i => cpu_i_rsp(i), + ibus_req_o => cpu_i_req(i), + ibus_rsp_i => cpu_i_rsp(i), -- data bus interface -- - dbus_req_o => cpu_d_req(i), - dbus_rsp_i => cpu_d_rsp(i) + dbus_req_o => cpu_d_req(i), + dbus_rsp_i => cpu_d_rsp(i), + -- ICC TX links -- + icc_tx_rdy_o => icc_tx_rdy(i), + icc_tx_ack_i => icc_tx_ack(i), + icc_tx_dat_o => icc_tx_dat(i), + -- ICC RX links -- + icc_rx_rdy_i => icc_rx_rdy(i), + icc_rx_ack_o => icc_rx_ack(i), + icc_rx_dat_i => icc_rx_dat(i) ); + -- inter-core communication (ICC) links (connect every core with every other) -- + icc_gen: + for j in 0 to num_cores_c-1 generate + + icc_gen_terminate: -- do not connect a core's link to itself + if i = j generate + icc_rx_rdy(i)(j) <= '0'; + icc_tx_ack(i)(j) <= '0'; + icc_rx_dat(i)(j*32+31 downto j*32) <= (others => '0'); + end generate; + + ip_gen_connect: + if i /= j generate + icc_rx_rdy(i)(j) <= icc_tx_rdy(j)(i); + icc_tx_ack(i)(j) <= icc_rx_ack(j)(i); + icc_rx_dat(i)(j*32+31 downto j*32) <= icc_tx_dat(j)(i*32+31 downto i*32); + end generate; + + end generate; + -- CPU L1 Instruction Cache (I-Cache) ----------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_icache_inst_true: + neorv32_icache_enabled: if ICACHE_EN generate neorv32_icache_inst: entity neorv32.neorv32_cache generic map ( @@ -584,7 +621,7 @@ begin ); end generate; - neorv32_icache_inst_false: + neorv32_icache_disabled: if not ICACHE_EN generate icache_req(i) <= cpu_i_req(i); cpu_i_rsp(i) <= icache_rsp(i); @@ -593,7 +630,7 @@ begin -- CPU L1 Data Cache (D-Cache) ------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - neorv32_dcache_inst_true: + neorv32_dcache_enabled: if DCACHE_EN generate neorv32_dcache_inst: entity neorv32.neorv32_cache generic map ( @@ -613,7 +650,7 @@ begin ); end generate; - neorv32_dcache_inst_false: + neorv32_dcache_disabled: if not DCACHE_EN generate dcache_req(i) <= cpu_d_req(i); cpu_d_rsp(i) <= dcache_rsp(i); @@ -677,7 +714,7 @@ begin -- Direct Memory Access Controller (DMA) Complex -- ************************************************************************************************************************** - neorv32_dma_complex_true: + neorv32_dma_complex_enabled: if IO_DMA_EN generate -- DMA Controller ------------------------------------------------------------------------- @@ -715,9 +752,9 @@ begin x_rsp_i => main_rsp ); - end generate; -- /neorv32_dma_complex_true + end generate; -- /neorv32_dma_complex_enabled - neorv32_dma_complex_false: + neorv32_dma_complex_disabled: if not IO_DMA_EN generate iodev_rsp(IODEV_DMA) <= rsp_terminate_c; main_req <= complex_req; @@ -730,7 +767,7 @@ begin -- Read-Modify-Write Controller for Atomic Memory Operations -- ************************************************************************************************************************** - neorv32_bus_amo_ctrl_true: + neorv32_bus_amo_ctrl_enabled: if RISCV_ISA_Zaamo generate neorv32_bus_amo_ctrl_inst: entity neorv32.neorv32_bus_amo_ctrl port map ( @@ -743,7 +780,7 @@ begin ); end generate; - neorv32_bus_amo_ctrl_false: + neorv32_bus_amo_ctrl_disabled: if not RISCV_ISA_Zaamo generate main2_req <= main_req; main_rsp <= main2_rsp; @@ -811,7 +848,7 @@ begin -- Processor-Internal Instruction Memory (IMEM) ------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_int_imem_inst_true: + neorv32_int_imem_enabled: if MEM_INT_IMEM_EN generate neorv32_int_imem_inst: entity neorv32.neorv32_imem generic map ( @@ -826,7 +863,7 @@ begin ); end generate; - neorv32_int_imem_inst_false: + neorv32_int_imem_disabled: if not MEM_INT_IMEM_EN generate imem_rsp <= rsp_terminate_c; end generate; @@ -834,7 +871,7 @@ begin -- Processor-Internal Data Memory (DMEM) -------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_int_dmem_inst_true: + neorv32_int_dmem_enabled: if MEM_INT_DMEM_EN generate neorv32_int_dmem_inst: entity neorv32.neorv32_dmem generic map ( @@ -848,7 +885,7 @@ begin ); end generate; - neorv32_int_dmem_inst_false: + neorv32_int_dmem_disabled: if not MEM_INT_DMEM_EN generate dmem_rsp <= rsp_terminate_c; end generate; @@ -856,7 +893,7 @@ begin -- Execute In-Place Module (XIP) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_xip_inst_true: + neorv32_xip_enabled: if XIP_EN generate -- XIP interface -- @@ -880,7 +917,7 @@ begin ); -- XIP cache (XIP-CACHE) -- - neorv32_xipcache_inst_true: + neorv32_xipcache_enabled: if XIP_CACHE_EN generate neorv32_xcache_inst: entity neorv32.neorv32_cache generic map ( @@ -900,15 +937,15 @@ begin ); end generate; - neorv32_xipcache_inst_false: + neorv32_xipcache_disabled: if not XIP_CACHE_EN generate xipcache_req <= xip_req; xip_rsp <= xipcache_rsp; end generate; - end generate; -- /neorv32_xip_inst_true + end generate; -- /neorv32_xip_enabled - neorv32_xip_inst_false: + neorv32_xip_disabled: if not XIP_EN generate iodev_rsp(IODEV_XIP) <= rsp_terminate_c; xip_rsp <= rsp_terminate_c; @@ -921,7 +958,7 @@ begin -- External Bus Interface (XBUS) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_xbus_inst_true: + neorv32_xbus_enabled: if XBUS_EN generate -- external bus gateway (XBUS) -- @@ -949,7 +986,7 @@ begin ); -- external bus cache (X-CACHE) -- - neorv32_xcache_inst_true: + neorv32_xcache_enabled: if XBUS_CACHE_EN generate neorv32_xcache_inst: entity neorv32.neorv32_cache generic map ( @@ -969,15 +1006,15 @@ begin ); end generate; - neorv32_xcache_inst_false: + neorv32_xcache_disabled: if not XBUS_CACHE_EN generate xcache_req <= xbus_req; xbus_rsp <= xcache_rsp; end generate; - end generate; -- /neorv32_xbus_inst_true + end generate; -- /neorv32_xbus_enabled - neorv32_xbus_inst_false: + neorv32_xbus_disabled: if not XBUS_EN generate xbus_rsp <= rsp_terminate_c; xbus_adr_o <= (others => '0'); @@ -1081,7 +1118,7 @@ begin -- Processor-Internal Bootloader ROM (BOOTROM) -------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_boot_rom_inst_true: + neorv32_boot_rom_enabled: if bootrom_en_c generate neorv32_boot_rom_inst: entity neorv32.neorv32_boot_rom port map ( @@ -1092,7 +1129,7 @@ begin ); end generate; - neorv32_boot_rom_inst_false: + neorv32_boot_rom_disabled: if not bootrom_en_c generate iodev_rsp(IODEV_BOOTROM) <= rsp_terminate_c; end generate; @@ -1100,7 +1137,7 @@ begin -- Custom Functions Subsystem (CFS) ------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_cfs_inst_true: + neorv32_cfs_enabled: if IO_CFS_EN generate neorv32_cfs_inst: entity neorv32.neorv32_cfs generic map ( @@ -1121,7 +1158,7 @@ begin ); end generate; - neorv32_cfs_inst_false: + neorv32_cfs_disabled: if not IO_CFS_EN generate iodev_rsp(IODEV_CFS) <= rsp_terminate_c; clk_gen_en(CG_CFS) <= '0'; @@ -1132,7 +1169,7 @@ begin -- Serial Data Interface (SDI) ------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - neorv32_sdi_inst_true: + neorv32_sdi_enabled: if IO_SDI_EN generate neorv32_sdi_inst: entity neorv32.neorv32_sdi generic map ( @@ -1151,7 +1188,7 @@ begin ); end generate; - neorv32_sdi_inst_false: + neorv32_sdi_disabled: if not IO_SDI_EN generate iodev_rsp(IODEV_SDI) <= rsp_terminate_c; sdi_dat_o <= '0'; @@ -1161,7 +1198,7 @@ begin -- General Purpose Input/Output Port (GPIO) ----------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_gpio_inst_true: + neorv32_gpio_enabled: if io_gpio_en_c generate neorv32_gpio_inst: entity neorv32.neorv32_gpio generic map ( @@ -1177,7 +1214,7 @@ begin ); end generate; - neorv32_gpio_inst_false: + neorv32_gpio_disabled: if not io_gpio_en_c generate iodev_rsp(IODEV_GPIO) <= rsp_terminate_c; gpio_o <= (others => '0'); @@ -1186,7 +1223,7 @@ begin -- Watch Dog Timer (WDT) ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - neorv32_wdt_inst_true: + neorv32_wdt_enabled: if IO_WDT_EN generate neorv32_wdt_inst: entity neorv32.neorv32_wdt port map ( @@ -1202,7 +1239,7 @@ begin ); end generate; - neorv32_wdt_inst_false: + neorv32_wdt_disabled: if not IO_WDT_EN generate iodev_rsp(IODEV_WDT) <= rsp_terminate_c; clk_gen_en(CG_WDT) <= '0'; @@ -1212,7 +1249,7 @@ begin -- Core Local Interruptor (CLINT) --------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_clint_inst_true: + neorv32_clint_enabled: if IO_CLINT_EN generate neorv32_clint_inst: entity neorv32.neorv32_clint generic map ( @@ -1229,7 +1266,7 @@ begin ); end generate; - neorv32_clint_inst_false: + neorv32_clint_disabled: if not IO_CLINT_EN generate iodev_rsp(IODEV_CLINT) <= rsp_terminate_c; mtime_time_o <= (others => '0'); @@ -1240,7 +1277,7 @@ begin -- Primary Universal Asynchronous Receiver/Transmitter (UART0) ---------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_uart0_inst_true: + neorv32_uart0_enabled: if IO_UART0_EN generate neorv32_uart0_inst: entity neorv32.neorv32_uart generic map ( @@ -1265,7 +1302,7 @@ begin ); end generate; - neorv32_uart0_inst_false: + neorv32_uart0_disabled: if not IO_UART0_EN generate iodev_rsp(IODEV_UART0) <= rsp_terminate_c; uart0_txd_o <= '0'; @@ -1278,7 +1315,7 @@ begin -- Secondary Universal Asynchronous Receiver/Transmitter (UART1) -------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_uart1_inst_true: + neorv32_uart1_enabled: if IO_UART1_EN generate neorv32_uart1_inst: entity neorv32.neorv32_uart generic map ( @@ -1303,7 +1340,7 @@ begin ); end generate; - neorv32_uart1_inst_false: + neorv32_uart1_disabled: if not IO_UART1_EN generate iodev_rsp(IODEV_UART1) <= rsp_terminate_c; uart1_txd_o <= '0'; @@ -1316,7 +1353,7 @@ begin -- Serial Peripheral Interface (SPI) ------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - neorv32_spi_inst_true: + neorv32_spi_enabled: if IO_SPI_EN generate neorv32_spi_inst: entity neorv32.neorv32_spi generic map ( @@ -1337,7 +1374,7 @@ begin ); end generate; - neorv32_spi_inst_false: + neorv32_spi_disabled: if not IO_SPI_EN generate iodev_rsp(IODEV_SPI) <= rsp_terminate_c; spi_clk_o <= '0'; @@ -1350,7 +1387,7 @@ begin -- Two-Wire Interface (TWI) --------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_twi_inst_true: + neorv32_twi_enabled: if IO_TWI_EN generate neorv32_twi_inst: entity neorv32.neorv32_twi generic map ( @@ -1371,7 +1408,7 @@ begin ); end generate; - neorv32_twi_inst_false: + neorv32_twi_disabled: if not IO_TWI_EN generate iodev_rsp(IODEV_TWI) <= rsp_terminate_c; twi_sda_o <= '1'; @@ -1383,7 +1420,7 @@ begin -- Two-Wire Device (TWD) ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - neorv32_twd_inst_true: + neorv32_twd_enabled: if IO_TWD_EN generate neorv32_twd_inst: entity neorv32.neorv32_twd generic map ( @@ -1404,7 +1441,7 @@ begin ); end generate; - neorv32_twd_inst_false: + neorv32_twd_disabled: if not IO_TWD_EN generate iodev_rsp(IODEV_TWD) <= rsp_terminate_c; twd_sda_o <= '1'; @@ -1416,7 +1453,7 @@ begin -- Pulse-Width Modulation Controller (PWM) ------------------------------------------------ -- ------------------------------------------------------------------------------------------- - neorv32_pwm_inst_true: + neorv32_pwm_enabled: if io_pwm_en_c generate neorv32_pwm_inst: entity neorv32.neorv32_pwm generic map ( @@ -1433,7 +1470,7 @@ begin ); end generate; - neorv32_pwm_inst_false: + neorv32_pwm_disabled: if not io_pwm_en_c generate iodev_rsp(IODEV_PWM) <= rsp_terminate_c; clk_gen_en(CG_PWM) <= '0'; @@ -1443,7 +1480,7 @@ begin -- True Random Number Generator (TRNG) ---------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_trng_inst_true: + neorv32_trng_enabled: if IO_TRNG_EN generate neorv32_trng_inst: entity neorv32.neorv32_trng generic map ( @@ -1457,7 +1494,7 @@ begin ); end generate; - neorv32_trng_inst_false: + neorv32_trng_disabled: if not IO_TRNG_EN generate iodev_rsp(IODEV_TRNG) <= rsp_terminate_c; end generate; @@ -1465,7 +1502,7 @@ begin -- Smart LED (WS2811/WS2812) Interface (NEOLED) ------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_neoled_inst_true: + neorv32_neoled_enabled: if IO_NEOLED_EN generate neorv32_neoled_inst: entity neorv32.neorv32_neoled generic map ( @@ -1483,7 +1520,7 @@ begin ); end generate; - neorv32_neoled_inst_false: + neorv32_neoled_disabled: if not IO_NEOLED_EN generate iodev_rsp(IODEV_NEOLED) <= rsp_terminate_c; clk_gen_en(CG_NEOLED) <= '0'; @@ -1494,7 +1531,7 @@ begin -- External Interrupt Controller (XIRQ) --------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_xirq_inst_true: + neorv32_xirq_enabled: if io_xirq_en_c generate neorv32_xirq_inst: entity neorv32.neorv32_xirq generic map ( @@ -1510,7 +1547,7 @@ begin ); end generate; - neorv32_xirq_inst_false: + neorv32_xirq_disabled: if not io_xirq_en_c generate iodev_rsp(IODEV_XIRQ) <= rsp_terminate_c; firq(FIRQ_XIRQ) <= '0'; @@ -1519,7 +1556,7 @@ begin -- General Purpose Timer (GPTMR) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_gptmr_inst_true: + neorv32_gptmr_enabled: if IO_GPTMR_EN generate neorv32_gptmr_inst: entity neorv32.neorv32_gptmr port map ( @@ -1533,7 +1570,7 @@ begin ); end generate; - neorv32_gptmr_inst_false: + neorv32_gptmr_disabled: if not IO_GPTMR_EN generate iodev_rsp(IODEV_GPTMR) <= rsp_terminate_c; clk_gen_en(CG_GPTMR) <= '0'; @@ -1543,7 +1580,7 @@ begin -- 1-Wire Interface Controller (ONEWIRE) -------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_onewire_inst_true: + neorv32_onewire_enabled: if IO_ONEWIRE_EN generate neorv32_onewire_inst: entity neorv32.neorv32_onewire generic map ( @@ -1562,7 +1599,7 @@ begin ); end generate; - neorv32_onewire_inst_false: + neorv32_onewire_disabled: if not IO_ONEWIRE_EN generate iodev_rsp(IODEV_ONEWIRE) <= rsp_terminate_c; onewire_o <= '1'; @@ -1573,7 +1610,7 @@ begin -- Stream Link Interface (SLINK) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_slink_inst_true: + neorv32_slink_enabled: if IO_SLINK_EN generate neorv32_slink_inst: entity neorv32.neorv32_slink generic map ( @@ -1600,7 +1637,7 @@ begin ); end generate; - neorv32_slink_inst_false: + neorv32_slink_disabled: if not IO_SLINK_EN generate iodev_rsp(IODEV_SLINK) <= rsp_terminate_c; firq(FIRQ_SLINK_RX) <= '0'; @@ -1615,7 +1652,7 @@ begin -- Cyclic Redundancy Check Unit (CRC) ----------------------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_crc_inst_true: + neorv32_crc_enabled: if IO_CRC_EN generate neorv32_crc_inst: entity neorv32.neorv32_crc port map ( @@ -1626,7 +1663,7 @@ begin ); end generate; - neorv32_crc_inst_false: + neorv32_crc_disabled: if not IO_CRC_EN generate iodev_rsp(IODEV_CRC) <= rsp_terminate_c; end generate; @@ -1634,7 +1671,7 @@ begin -- System Configuration Information Memory (SYSINFO) -------------------------------------- -- ------------------------------------------------------------------------------------------- - neorv32_sysinfo_inst_true: + neorv32_sysinfo_enabled: if io_sysinfo_en_c generate neorv32_sysinfo_inst: entity neorv32.neorv32_sysinfo generic map ( @@ -1691,7 +1728,7 @@ begin ); end generate; - neorv32_sysinfo_inst_false: + neorv32_sysinfo_disabled: if not io_sysinfo_en_c generate iodev_rsp(IODEV_SYSINFO) <= rsp_terminate_c; end generate; @@ -1704,7 +1741,7 @@ begin -- On-Chip Debugger Complex -- ************************************************************************************************************************** - neorv32_ocd_inst_true: + neorv32_ocd_enabled: if OCD_EN generate -- On-Chip Debugger - Debug Transport Module (DTM) ---------------------------------------- @@ -1744,9 +1781,9 @@ begin halt_req_o => dci_haltreq ); - end generate; + end generate; -- /neorv32_ocd_enabled - neorv32_debug_ocd_inst_false: + neorv32_debug_ocd_disabled: if not OCD_EN generate iodev_rsp(IODEV_OCD) <= rsp_terminate_c; jtag_tdo_o <= jtag_tdi_i; -- JTAG pass-through From 97d00295ee21dd7f6bb91e90663d538d88b71068 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:04:49 +0100 Subject: [PATCH 06/21] [processor_checks] minor fixes --- sw/example/processor_check/main.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/sw/example/processor_check/main.c b/sw/example/processor_check/main.c index 5c7bf0295..cc3bc4c11 100644 --- a/sw/example/processor_check/main.c +++ b/sw/example/processor_check/main.c @@ -571,10 +571,10 @@ int main() { neorv32_cpu_csr_clr(CSR_MSTATUS, 1 << CSR_MSTATUS_MIE); tmp_a = trap_cnt; // current number of traps - // try executing some illegal instructions asm volatile (".word 0x58007053"); // unsupported fsqrt.s x0, x0 - asm volatile (".word 0x0e00202f"); // unsupported amoswap.w x0, x0, (x0) + asm volatile (".word 0x0e00302f"); // unsupported amoswap.D x0, x0, (x0) + asm volatile (".word 0x1000202f"); // unsupported lr.w x0, (x0) asm volatile (".word 0x34004073"); // illegal CSR access funct3 (using mscratch) asm volatile (".word 0x30200077"); // mret with illegal opcode asm volatile (".word 0x3020007f"); // mret with illegal opcode @@ -603,7 +603,7 @@ int main() { invalid_instr = 0x08812681; // mtinst: pre-decompressed; clear bit 1 if compressed instruction } else { // C extension disabled - tmp_a += 15; + tmp_a += 16; invalid_instr = 0xfe002fe3; } @@ -2146,22 +2146,17 @@ int main() { neorv32_cpu_csr_write(CSR_MCAUSE, mcause_never_c); PRINT_STANDARD("[%i] Dual-core ", cnt_test); - if ((neorv32_cpu_csr_read(CSR_MHARTID) == 0) && // we need to be core 0 - (NEORV32_SYSINFO->MISC[SYSINFO_MISC_HART] > 1) && // we need at least two cores + if ((NEORV32_SYSINFO->MISC[SYSINFO_MISC_HART] > 1) && // we need at least two cores (neorv32_clint_available() != 0)) { // we need the CLINT cnt_test++; // enable machine software interrupt neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MSIE); - // wait some time for the IRQ to arrive the CPU - asm volatile ("nop"); - asm volatile ("nop"); - - // launch core1 - tmp_a = (uint32_t)neorv32_rte_smp_launch(core1_main, (uint8_t*)core1_stack, sizeof(core1_stack)); + // launch core 1 + tmp_a = (uint32_t)neorv32_smp_launch(1, core1_main, (uint8_t*)core1_stack, sizeof(core1_stack)); - // wait for software interrupt in sleep mode + // wait for software interrupt (issued by core 1) in sleep mode neorv32_cpu_sleep(); // disable interrupts and clear software interrupt From c13a0f5909787b3fd6236621baf50d5f63a7ea86 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:05:09 +0100 Subject: [PATCH 07/21] [rte] cleanup --- sw/lib/include/neorv32_rte.h | 1 - sw/lib/source/neorv32_rte.c | 72 ++---------------------------------- 2 files changed, 4 insertions(+), 69 deletions(-) diff --git a/sw/lib/include/neorv32_rte.h b/sw/lib/include/neorv32_rte.h index 31ef18db3..50473d9df 100644 --- a/sw/lib/include/neorv32_rte.h +++ b/sw/lib/include/neorv32_rte.h @@ -67,7 +67,6 @@ int neorv32_rte_handler_uninstall(int id); void neorv32_rte_debug_handler(void); uint32_t neorv32_rte_context_get(int x); void neorv32_rte_context_put(int x, uint32_t data); -int neorv32_rte_smp_launch(void (*entry_point)(void), uint8_t* stack_memory, size_t stack_size_bytes); /**@}*/ #endif // neorv32_rte_h diff --git a/sw/lib/source/neorv32_rte.c b/sw/lib/source/neorv32_rte.c index 88be7d4c9..1b280078f 100644 --- a/sw/lib/source/neorv32_rte.c +++ b/sw/lib/source/neorv32_rte.c @@ -15,28 +15,20 @@ #include -// // ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ // RTE private variables and functions -// // ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ // the private trap vector look-up table for each CPU core static uint32_t __neorv32_rte_vector_lut[2][NEORV32_RTE_NUM_TRAPS]; -// SMP startup configuration -static volatile struct __attribute__((packed,aligned(4))) { - uint32_t magic_word; // to check for valid configuration - uint32_t stack_lower; // stack begin address (lowest valid address); 16-byte aligned! - uint32_t stack_upper; // stack end address (highest valid address); 16-byte aligned! - uint32_t entry_point; // main function entry address -} __neorv32_rte_smp_startup; - // private helper function static void __neorv32_rte_print_hex_word(uint32_t num); -// // ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ // RTE core functions -// // ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ /**********************************************************************//** * NEORV32 runtime environment (RTE): @@ -414,62 +406,6 @@ void neorv32_rte_debug_handler(void) { } -// ------------------------------------------------------------------------------------------------ -// Multi-core functions -// ------------------------------------------------------------------------------------------------ - -/**********************************************************************//** - * NEORV32 runtime environment (RTE): - * Configure and start secondary CPU (core 1). - * - * @warning This function can be called from core 0 only. - * - * @param[in] entry_point Core 1 main function (must be of type "void entry_point(void)"). - * @param[in] stack_memory Pointer to beginning of core 1 stack memory array. Should be at least 512 bytes. - * @param[in] stack_size_bytes Core 1 stack size in bytes. - * @return 0 if launching succeeded. -1 if hardware configuration error. -2 if core is not responding. - **************************************************************************/ -int neorv32_rte_smp_launch(void (*entry_point)(void), uint8_t* stack_memory, size_t stack_size_bytes) { - - // sanity checks - if ((neorv32_cpu_csr_read(CSR_MHARTID) != 0) || // not execute on core 0 - (neorv32_clint_available() == 0) || // CLINT not available - (NEORV32_SYSINFO->MISC[SYSINFO_MISC_HART] == 1)) { // there is only one CPU core - return -1; - } - - // align end of stack to 16-bytes according to the RISC-V ABI (#1021) - uint32_t stack_top = ((uint32_t)stack_memory + (uint32_t)(stack_size_bytes-1)) & 0xfffffff0u; - - // setup launch-configuration struct - __neorv32_rte_smp_startup.magic_word = 0x1337cafeu; - __neorv32_rte_smp_startup.stack_lower = (uint32_t)stack_memory; - __neorv32_rte_smp_startup.stack_upper = stack_top; - __neorv32_rte_smp_startup.entry_point = (uint32_t)entry_point; - - // flush data cache (containing configuration struct) to main memory - asm volatile ("fence"); - - // use CLINT.MTIMECMP[1].low_word to pass the address of the configuration struct - NEORV32_CLINT->MTIMECMP[1].uint32[0] = (uint32_t)&__neorv32_rte_smp_startup; - - // start core 1 by triggering its software interrupt - neorv32_clint_msi_set(1); - - // wait for core 1 to clear its software interrupt - int cnt = 0; - while (1) { - if (neorv32_clint_msi_get(1) == 0) { - return 0; // success! - } - if (cnt > 10000) { - return -2; // timeout; core did not respond - } - cnt++; - } -} - - // ------------------------------------------------------------------------------------------------ // Private helper functions // ------------------------------------------------------------------------------------------------ From e3cc802d7d3b39f2911861b845f1345ee64b51db Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:06:11 +0100 Subject: [PATCH 08/21] [sw/lib] add SMP HAL --- docs/datasheet/software.adoc | 1 + sw/lib/include/neorv32.h | 3 +- sw/lib/include/neorv32_smp.h | 79 ++++++++++++++++++++++++++++++++++++ sw/lib/source/neorv32_smp.c | 70 ++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 sw/lib/include/neorv32_smp.h create mode 100644 sw/lib/source/neorv32_smp.c diff --git a/docs/datasheet/software.adoc b/docs/datasheet/software.adoc index ad58c249a..8efccb943 100644 --- a/docs/datasheet/software.adoc +++ b/docs/datasheet/software.adoc @@ -80,6 +80,7 @@ The NEORV32 HAL consists of the following files. | `neorv32_rte.c` | `neorv32_rte.h` | <<_neorv32_runtime_environment>> | `neorv32_sdi.c` | `neorv32_sdi.h` | <<_serial_data_interface_controller_sdi>> HAL | `neorv32_slink.c` | `neorv32_slink.h` | <<_stream_link_interface_slink>> HAL +| `neorv32_smp.c` | `neorv32_smp.h` | HAL for the SMP <<_dual_core_configuration>> | `neorv32_spi.c` | `neorv32_spi.h` | <<_serial_peripheral_interface_controller_spi>> HAL | `neorv32_sysinfo.c` | `neorv32_sysinfo.h` | <<_system_configuration_information_memory_sysinfo>> HAL | `neorv32_trng.c` | `neorv32_trng.h` | <<_true_random_number_generator_trng>> HAL diff --git a/sw/lib/include/neorv32.h b/sw/lib/include/neorv32.h index 888a9db68..b78bfbb79 100644 --- a/sw/lib/include/neorv32.h +++ b/sw/lib/include/neorv32.h @@ -1,7 +1,7 @@ // ================================================================================ // // The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // // Copyright (c) NEORV32 contributors. // -// Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. // +// Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. // // Licensed under the BSD-3-Clause license, see LICENSE for details. // // SPDX-License-Identifier: BSD-3-Clause // // ================================================================================ // @@ -262,6 +262,7 @@ typedef union { // NEORV32 runtime environment #include "neorv32_rte.h" +#include "neorv32_smp.h" // IO/peripheral devices #include "neorv32_cfs.h" diff --git a/sw/lib/include/neorv32_smp.h b/sw/lib/include/neorv32_smp.h new file mode 100644 index 000000000..1ffd6d0db --- /dev/null +++ b/sw/lib/include/neorv32_smp.h @@ -0,0 +1,79 @@ +// ================================================================================ // +// The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // +// Copyright (c) NEORV32 contributors. // +// Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. // +// Licensed under the BSD-3-Clause license, see LICENSE for details. // +// SPDX-License-Identifier: BSD-3-Clause // +// ================================================================================ // + +/** + * @file neorv32_smp.h + * @brief SMP HW driver header file. + */ + +#ifndef neorv32_smp_h +#define neorv32_smp_h + + +/**********************************************************************//** + * @name Prototypes + **************************************************************************/ +/**@{*/ +int neorv32_smp_launch(int hart_id, void (*entry_point)(void), uint8_t* stack_memory, size_t stack_size_bytes); +/**@}*/ + + +/**********************************************************************//** + * Get data from core via ICC link. + * Check link status before #neorv32_smp_icc_avail(). + * + * @param[in] hart_sel Source core. + * @return Data word (32-bit) received from selected core. + **************************************************************************/ +inline uint32_t __attribute__ ((always_inline)) neorv32_smp_icc_get(int hart_sel) { + + neorv32_cpu_csr_write(CSR_MXICCSR0, (uint32_t)hart_sel); + return neorv32_cpu_csr_read(CSR_MXICCRXD); +} + + +/**********************************************************************//** + * Send data to core via ICC link. + * Check link status before #neorv32_smp_icc_free(). + * + * @param[in] hart_sel Destination core. + * @param[in] data Data word (32-bit) to be send to selected core. + **************************************************************************/ +inline void __attribute__ ((always_inline)) neorv32_smp_icc_put(int hart_sel, uint32_t data) { + + neorv32_cpu_csr_write(CSR_MXICCSR0, (uint32_t)hart_sel); + neorv32_cpu_csr_write(CSR_MXICCTXD, data); +} + + +/**********************************************************************//** + * Check if ICC link data is available. + * + * @param[in] hart_sel Source core. + * @return 0 = no data available, nonzero = data available. + **************************************************************************/ +inline int __attribute__ ((always_inline)) neorv32_smp_icc_avail(int hart_sel) { + + neorv32_cpu_csr_write(CSR_MXICCSR0, (uint32_t)hart_sel); + return neorv32_cpu_csr_read(CSR_MXICCSR0) & (1 << CSR_MXICCSR_RX_AVAIL); +} + + +/**********************************************************************//** + * Check if free space in ICC link. + * + * @param[in] hart_sel Destination core. + * @return 0 = no free space available, nonzero = free space available. + **************************************************************************/ +inline int __attribute__ ((always_inline)) neorv32_smp_icc_free(int hart_sel) { + + neorv32_cpu_csr_write(CSR_MXICCSR0, (uint32_t)hart_sel); + return neorv32_cpu_csr_read(CSR_MXICCSR0) & (1 << CSR_MXICCSR_TX_FREE); +} + +#endif // neorv32_smp_h diff --git a/sw/lib/source/neorv32_smp.c b/sw/lib/source/neorv32_smp.c new file mode 100644 index 000000000..da5797492 --- /dev/null +++ b/sw/lib/source/neorv32_smp.c @@ -0,0 +1,70 @@ +// ================================================================================ // +// The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // +// Copyright (c) NEORV32 contributors. // +// Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. // +// Licensed under the BSD-3-Clause license, see LICENSE for details. // +// SPDX-License-Identifier: BSD-3-Clause // +// ================================================================================ // + +/** + * @file neorv32_smp.c + * @brief SMP HW driver source file. + */ + +#include + + +/**********************************************************************//** + * Configure and start SMP core. + * + * @warning This function can be executed on core 0 only. + * + * @param[in] hart_id Hart/core select. + * @param[in] entry_point Core's main function (must be of type "void entry_point(void)"). + * @param[in] stack_memory Pointer to beginning of core's stack memory array. Should be at least 512 bytes. + * @param[in] stack_size_bytes Core's stack size in bytes. + * @return 0 if launching succeeded. -1 if invalid hart ID or CLINT not available. -2 if core is not responding. + **************************************************************************/ +int neorv32_smp_launch(int hart_id, void (*entry_point)(void), uint8_t* stack_memory, size_t stack_size_bytes) { + + const uint32_t signature = 0xffab4321u; + int num_cores = (int)NEORV32_SYSINFO->MISC[SYSINFO_MISC_HART]; + + // sanity checks + if ((neorv32_cpu_csr_read(CSR_MHARTID) != 0) || // this can be executed on core 0 only + (hart_id == 0) || // we cannot launch core 0 + (hart_id > (num_cores-1)) || // selected core not available + (neorv32_clint_available() == 0)) { // we need the CLINT + return -1; + } + + // drain input queue from selected core + while (neorv32_smp_icc_avail(hart_id)) { + neorv32_smp_icc_get(hart_id); + } + + // align end of stack to 16-bytes according to the RISC-V ABI (#1021) + uint32_t stack_top = ((uint32_t)stack_memory + (uint32_t)(stack_size_bytes-1)) & 0xfffffff0u; + + // send launch configuration + neorv32_smp_icc_put(hart_id, signature); // signature + neorv32_smp_icc_put(hart_id, stack_top); // top of core's stack + neorv32_smp_icc_put(hart_id, (uint32_t)entry_point); // entry point + + // start core by triggering its software interrupt + neorv32_clint_msi_set(hart_id); + + // wait for start acknowledge + int cnt = 0; + while (1) { + if (neorv32_smp_icc_avail(hart_id)) { + if (neorv32_smp_icc_get(hart_id) == signature) { + return 0; + } + } + if (cnt > 10000) { + return -2; // timeout; core did not respond + } + cnt++; + } +} From b71e8e2b2ce19c1976c2167d2a3d44f72d73c6b4 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:06:31 +0100 Subject: [PATCH 09/21] [demo_dual_core] update HAL --- sw/example/demo_dual_core/main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sw/example/demo_dual_core/main.c b/sw/example/demo_dual_core/main.c index 934d7a464..d172c78de 100644 --- a/sw/example/demo_dual_core/main.c +++ b/sw/example/demo_dual_core/main.c @@ -86,11 +86,12 @@ int main(void) { neorv32_uart0_printf("Launching core1...\n"); // Launch execution of core 1. Arguments: - // 1st:: "main_core1" is the entry point for the core and we provide a total of 2kB of stack for it. - // 2nd:: Pointer to the core's stack memory array. - // 3rd:: Size of the core's stack memory array. + // 1st: CHart ID of the core that we want to launch. + // 2nd: "main_core1" is the entry point for the core and we provide a total of 2kB of stack for it. + // 3rd: Pointer to the core's stack memory array. + // 4th: Size of the core's stack memory array. - int smp_launch_rc = neorv32_rte_smp_launch(main_core1, (uint8_t*)core1_stack, sizeof(core1_stack)); + int smp_launch_rc = neorv32_smp_launch(1, main_core1, (uint8_t*)core1_stack, sizeof(core1_stack)); // Here we are using a statically allocated array as stack memory. Alternatively, malloc // could be used (it is recommend to align the stack memory on a 16-byte boundary): From 06d5e3ac6ac8b474477f06a845ca030b9aa92a36 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:06:52 +0100 Subject: [PATCH 10/21] [docs] add inter-core communication --- README.md | 3 ++- docs/figures/smp_system.png | Bin 79469 -> 81615 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bcb79f35..046312da5 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,8 @@ setup according to your needs. Note that all of the following SoC modules are en **CPU Core** * [![RISCV-ARCHID](https://img.shields.io/badge/RISC--V%20Architecture%20ID-19-000000.svg?longCache=true&style=flat-square&logo=riscv&colorA=273274&colorB=fbb517)](https://github.com/riscv/riscv-isa-manual/blob/master/marchid.md) -* RISC-V 32-bit little-endian single- or SMP-dual-core pipelined/multi-cycle modified Harvard architecture +* RISC-V 32-bit little-endian pipelined/multi-cycle modified Harvard architecture +* Single-core or SMP dual-core configuration (including low-latency inter-core communication) * configurable [instruction sets and extensions](https://stnolting.github.io/neorv32/#_instruction_sets_and_extensions): \ `RV32` diff --git a/docs/figures/smp_system.png b/docs/figures/smp_system.png index a55182cd3b24380333c4e3d9eba7b360c1ef5db3..2c91c06366242caff68275c13e09cc3b400103a4 100644 GIT binary patch literal 81615 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

GHnXcvc$g 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 literal 79469 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�T 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 From febeb10b6a1d237187395eb3029f4049b0ce8514 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:19:29 +0100 Subject: [PATCH 11/21] [sw/example] cleanup --- sw/example/demo_dual_core/run_check.sh | 1 - 1 file changed, 1 deletion(-) delete mode 100644 sw/example/demo_dual_core/run_check.sh diff --git a/sw/example/demo_dual_core/run_check.sh b/sw/example/demo_dual_core/run_check.sh deleted file mode 100644 index 5f6a5c2a4..000000000 --- a/sw/example/demo_dual_core/run_check.sh +++ /dev/null @@ -1 +0,0 @@ -make USER_FLAGS+="-DUART0_SIM_MODE -DUART1_SIM_MODE" clean_all asm install sim From ac87c3a4494f36edfc811d55a6e4724b2bf5e59a Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:24:01 +0100 Subject: [PATCH 12/21] [rtl] update default application image --- rtl/core/neorv32_application_image.vhd | 49 ++++++++++++-------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/rtl/core/neorv32_application_image.vhd b/rtl/core/neorv32_application_image.vhd index df8c1862a..74b03df67 100644 --- a/rtl/core/neorv32_application_image.vhd +++ b/rtl/core/neorv32_application_image.vhd @@ -1,7 +1,7 @@ -- The NEORV32 RISC-V Processor - github.com/stnolting/neorv32 -- Auto-generated memory initialization image (for internal IMEM) -- Source: demo_blink_led/build/main.bin --- Built: 02.01.2025 14:38:10 +-- Built: 04.01.2025 22:17:35 library ieee; use ieee.std_logic_1164.all; @@ -11,7 +11,7 @@ use neorv32.neorv32_package.all; package neorv32_application_image is -constant application_init_size_c : natural := 1260; -- bytes +constant application_init_size_c : natural := 1248; -- bytes constant application_init_image_c : mem32_t := ( x"f14020f3", x"80002217", @@ -23,11 +23,11 @@ x"000022b7", x"80028293", x"30029073", x"00000317", -x"1b030313", +x"1a430313", x"30531073", x"30401073", x"00000397", -x"4b838393", +x"4ac38393", x"80000417", x"fc440413", x"80000497", @@ -37,7 +37,7 @@ x"fb450513", x"80000597", x"fac58593", x"00000617", -x"1b860613", +x"1ac60613", x"00000693", x"00000713", x"00000793", @@ -57,32 +57,31 @@ x"00000e13", x"00000e93", x"00000f13", x"00000f93", -x"06008463", +x"06008263", x"00000797", x"01878793", x"30579073", x"30446073", x"30046073", -x"1040006f", +x"0f80006f", +x"fff40737", +x"00209793", +x"00f70733", +x"00072023", x"34202773", x"800007b7", x"00378793", -x"00f70463", -x"30200073", -x"0ff0000f", -x"fff446b7", -x"0086a683", -x"1337d737", -x"afe70713", -x"0006a783", -x"00f70463", +x"02f71463", +x"bc201073", +x"bc0026f3", +x"ffab4737", +x"32170713", +x"00d71a63", +x"bc171073", +x"bc002173", +x"bc002673", +x"0580006f", x"30200073", -x"0086a103", -x"00c6a603", -x"0006a023", -x"fff40737", -x"00072223", -x"0540006f", x"00838e63", x"00945c63", x"0003a783", @@ -95,9 +94,9 @@ x"00052023", x"00450513", x"ff5ff06f", x"00000417", -x"3a840413", +x"3a040413", x"00000497", -x"3a048493", +x"39848493", x"00945a63", x"00042083", x"000080e7", @@ -106,8 +105,6 @@ x"ff1ff06f", x"0ff0000f", x"0000100f", x"30029073", -x"34201073", -x"34101073", x"00000513", x"00000593", x"000600e7", From 1c5bb786e32782f2e01b970ed1e4854b12bd448d Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:24:21 +0100 Subject: [PATCH 13/21] [rtl] update bootloader image --- rtl/core/neorv32_bootloader_image.vhd | 155 +++++++++++++------------- 1 file changed, 76 insertions(+), 79 deletions(-) diff --git a/rtl/core/neorv32_bootloader_image.vhd b/rtl/core/neorv32_bootloader_image.vhd index 165e72af4..6b5b52502 100644 --- a/rtl/core/neorv32_bootloader_image.vhd +++ b/rtl/core/neorv32_bootloader_image.vhd @@ -1,7 +1,7 @@ -- The NEORV32 RISC-V Processor - github.com/stnolting/neorv32 -- Auto-generated memory initialization image (for internal BOOTROM) -- Source: bootloader/build/main.bin --- Built: 02.01.2025 14:38:30 +-- Built: 04.01.2025 22:18:00 library ieee; use ieee.std_logic_1164.all; @@ -11,7 +11,7 @@ use neorv32.neorv32_package.all; package neorv32_bootloader_image is -constant bootloader_init_size_c : natural := 4072; -- bytes +constant bootloader_init_size_c : natural := 4060; -- bytes constant bootloader_init_image_c : mem32_t := ( x"f14020f3", x"80200217", @@ -23,11 +23,11 @@ x"000022b7", x"80028293", x"30029073", x"00000317", -x"12030313", +x"11430313", x"30531073", x"30401073", x"00001397", -x"fb438393", +x"fa838393", x"80200417", x"fc440413", x"80200497", @@ -37,36 +37,35 @@ x"fb450513", x"80200597", x"fb458593", x"00000617", -x"12860613", +x"11c60613", x"00000693", x"00000713", x"00000793", -x"06008463", +x"06008263", x"00000797", x"01878793", x"30579073", x"30446073", x"30046073", -x"0b40006f", +x"0a80006f", +x"fff40737", +x"00209793", +x"00f70733", +x"00072023", x"34202773", x"800007b7", x"00378793", -x"00f70463", -x"30200073", -x"0ff0000f", -x"fff446b7", -x"0086a683", -x"1337d737", -x"afe70713", -x"0006a783", -x"00f70463", +x"02f71463", +x"bc201073", +x"bc0026f3", +x"ffab4737", +x"32170713", +x"00d71a63", +x"bc171073", +x"bc002173", +x"bc002673", +x"0340006f", x"30200073", -x"0086a103", -x"00c6a603", -x"0006a023", -x"fff40737", -x"00072223", -x"0300006f", x"00838e63", x"00945c63", x"0003a783", @@ -81,8 +80,6 @@ x"ff5ff06f", x"0ff0000f", x"0000100f", x"30029073", -x"34201073", -x"34101073", x"00000513", x"00000593", x"000600e7", @@ -119,7 +116,7 @@ x"ffe017b7", x"00112823", x"00812623", x"00912423", -x"a5c78793", +x"a5078793", x"30579073", x"fffe07b7", x"0087a783", @@ -203,54 +200,54 @@ x"30479073", x"00800793", x"3007a073", x"ffe01537", -x"dd850513", +x"dcc50513", x"6b4000ef", x"f1302573", x"648000ef", x"ffe01537", -x"e1050513", +x"e0450513", x"6a0000ef", x"fffe0437", x"00042503", x"630000ef", x"ffe01537", -x"e1850513", +x"e0c50513", x"688000ef", x"30102573", x"61c000ef", x"ffe01537", -x"e2050513", +x"e1450513", x"674000ef", x"fc002573", x"608000ef", x"ffe01537", -x"e2850513", +x"e1c50513", x"660000ef", x"00842503", x"00100493", x"5f0000ef", x"ffe01537", -x"e3050513", +x"e2450513", x"648000ef", x"00444503", x"00a49533", x"ffc57513", x"5d4000ef", x"ffe01537", -x"e3850513", +x"e2c50513", x"62c000ef", x"00544783", x"00f49533", x"ffc57513", x"5b8000ef", x"ffe014b7", -x"dd448513", +x"dc848513", x"610000ef", x"00842783", x"00f79713", x"06075063", x"ffe01537", -x"e4050513", +x"e3450513", x"5f8000ef", x"2e0000ef", x"00042703", @@ -270,13 +267,13 @@ x"00f69613", x"0a065463", x"ffe01537", x"00472783", -x"e6c50513", +x"e6050513", x"5a8000ef", x"ffe017b7", -x"e7878513", +x"e6c78513", x"59c000ef", x"ffe01537", -x"ef850513", +x"eec50513", x"590000ef", x"fff507b7", x"0007a703", @@ -286,14 +283,14 @@ x"0047a403", x"0ff47413", x"00040513", x"4f4000ef", -x"dd448513", +x"dc848513", x"568000ef", x"f9b40413", x"0ff47413", x"01300793", x"2287e863", x"ffe017b7", -x"f7478793", +x"f6878793", x"00241413", x"00f40433", x"00042783", @@ -317,7 +314,7 @@ x"00b41463", x"f2f564e3", x"00100513", x"6f8000ef", -x"dd448513", +x"dc848513", x"4ec000ef", x"00000513", x"031000ef", @@ -330,20 +327,20 @@ x"800007b7", x"0047a403", x"00041863", x"ffe01537", -x"f0050513", +x"ef450513", x"f1dff06f", x"ffe01537", -x"f1c50513", +x"f1050513", x"4ac000ef", x"00040513", x"440000ef", x"ffe01537", -x"f2450513", +x"f1850513", x"498000ef", x"00400537", x"42c000ef", x"ffe01537", -x"f3c50513", +x"f3050513", x"484000ef", x"fff507b7", x"0007a703", @@ -361,7 +358,7 @@ x"00050663", x"00300513", x"498000ef", x"ffe01537", -x"f4850513", +x"f3c50513", x"43c000ef", x"01045793", x"00178793", @@ -399,7 +396,7 @@ x"00850513", x"40e005b3", x"2a8000ef", x"ffe01537", -x"dbc50513", +x"db050513", x"e09ff06f", x"00f12223", x"1ec000ef", @@ -425,14 +422,14 @@ x"800007b7", x"0047a783", x"e60790e3", x"ffe01537", -x"f5850513", +x"f4c50513", x"da1ff06f", x"fffe07b7", x"0087a783", x"2007f793", x"00079863", x"ffe01537", -x"f6850513", +x"f5c50513", x"d85ff06f", x"00100513", x"e35ff06f", @@ -621,7 +618,7 @@ x"01c00493", x"00945733", x"ffe017b7", x"00f77713", -x"fc478793", +x"fb878793", x"00e787b3", x"0007c503", x"ffc48493", @@ -657,13 +654,13 @@ x"ff810113", x"00812023", x"00050413", x"ffe01537", -x"d6450513", +x"d5850513", x"00112223", x"f99ff0ef", x"00241793", x"ffe01537", x"008787b3", -x"fd450513", +x"fc850513", x"00f50533", x"f81ff0ef", x"00800793", @@ -744,7 +741,7 @@ x"0087a783", x"00e79713", x"04075263", x"ffe01537", -x"d6c50513", +x"d6050513", x"e41ff0ef", x"00048513", x"dd5ff0ef", @@ -757,7 +754,7 @@ x"da5ff0ef", x"34302573", x"db5ff0ef", x"ffe01537", -x"dd450513", +x"dc850513", x"e0dff0ef", x"00440413", x"34141073", @@ -772,7 +769,7 @@ x"00a12023", x"00f4a023", x"02051863", x"ffe01537", -x"d7850513", +x"d6c50513", x"dd1ff0ef", x"00012503", x"004005b7", @@ -783,12 +780,12 @@ x"04f50863", x"00000513", x"0380006f", x"ffe01537", -x"d9850513", +x"d8c50513", x"da5ff0ef", x"00400537", x"d39ff0ef", x"ffe01537", -x"db450513", +x"da850513", x"d91ff0ef", x"fffe07b7", x"0087a783", @@ -820,7 +817,7 @@ x"00d787b3", x"00200513", x"fa0792e3", x"ffe01537", -x"dbc50513", +x"db050513", x"d11ff0ef", x"800007b7", x"0087a223", @@ -854,12 +851,12 @@ x"40a00533", x"e0400437", x"00a47433", x"ffe01537", -x"dc050513", +x"db450513", x"c89ff0ef", x"00040513", x"c1dff0ef", x"ffe01537", -x"dd050513", +x"dc450513", x"c75ff0ef", x"975ff0ef", x"00050863", @@ -909,7 +906,7 @@ x"0a3e3e20", x"444c420a", x"4a203a56", x"20206e61", -x"30322032", +x"30322034", x"480a3532", x"203a5657", x"00000020", @@ -1002,26 +999,26 @@ x"00002e65", x"61766e49", x"2064696c", x"00444d43", -x"ffe00660", -x"ffe00688", -x"ffe00688", -x"ffe0040c", -x"ffe00688", -x"ffe00688", -x"ffe00688", -x"ffe00658", -x"ffe00688", -x"ffe00688", -x"ffe00688", -x"ffe00688", -x"ffe00688", -x"ffe004d0", -x"ffe004e4", -x"ffe00688", +x"ffe00654", +x"ffe0067c", +x"ffe0067c", +x"ffe00400", +x"ffe0067c", +x"ffe0067c", +x"ffe0067c", +x"ffe0064c", +x"ffe0067c", +x"ffe0067c", +x"ffe0067c", +x"ffe0067c", +x"ffe0067c", +x"ffe004c4", x"ffe004d8", -x"ffe00688", -x"ffe00688", -x"ffe00678", +x"ffe0067c", +x"ffe004cc", +x"ffe0067c", +x"ffe0067c", +x"ffe0066c", x"33323130", x"37363534", x"62613938", From 7e6a57079a15a1ef22cc9d63414cac5cab8d50ff Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:24:46 +0100 Subject: [PATCH 14/21] [crt0] update core 1 boot code --- sw/common/crt0.S | 66 +++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/sw/common/crt0.S b/sw/common/crt0.S index 82586d08b..0f0a156a1 100644 --- a/sw/common/crt0.S +++ b/sw/common/crt0.S @@ -76,43 +76,39 @@ __crt0_entry: // ************************************************************************************************ #ifndef DISABLE_DUALCORE __crt0_dualcore_check: - beqz x1, __crt0_dualcore_primary // proceed with normal boot-up if we are core 0 + beqz x1, __crt0_dualcore_primary // proceed with normal boot-up if we are core 0 // setup machine software interrupt - la x15, __crt0_dualcore_mswi - csrw mtvec, x15 // install interrupt handler - csrsi mie, 1 << 3 // enable software interrupt source - csrsi mstatus, 1 << 3 // enable machine-level interrupts - j __crt0_sleep // wait for interrupt in sleep mode + la x15, __crt0_dualcore_wakeup + csrw mtvec, x15 // install interrupt handler + csrsi mie, 1 << 3 // enable software interrupt source + csrsi mstatus, 1 << 3 // enable machine-level interrupts + j __crt0_sleep // wait for interrupt in sleep mode // machine software interrupt handler -__crt0_dualcore_mswi: +__crt0_dualcore_wakeup: + li x14, 0xfff40000 // CLINT.MSWI base address + slli x15, x1, 2 // offset = hart_id * 4 + add x14, x14, x15 + sw zero, 0(x14) // CLINT.MSWI[hart_id] + csrr x14, mcause - li x15, 0x80000003 // is machine software interrupt? - beq x14, x15, __crt0_dualcore_init // start initialization - mret // go back to sleep if incorrect trap - - // get configuration struct address -__crt0_dualcore_init: - fence // reload data cache - li x13, 0xfff44000 // CLINT.MTIMCEMP base address - lw x13, 8(x13) // CLINT.MTIMCEMP[1].low = address of configuration struct - li x14, 0x1337cafe // expected magic word - lw x15, 0(x13) // __neorv32_rte_smp_startup.magic_word - beq x14, x15, __crt0_dualcore_valid - mret // go back to sleep if invalid configuration - -__crt0_dualcore_valid: - lw x2, 8(x13) // sp = __neorv32_rte_smp_startup.stack_upper - lw x12, 12(x13) // __neorv32_rte_smp_startup.entry_point - sw x0, 0(x13) // invalidate configuration struct - - // acknowledge startup by clearing software interrupt - li x14, 0xfff40000 // CLINT.MSWI base address - sw zero, 4(x14) // CLINT.MSWI[1] - - // start main function - j __crt0_main_entry + li x15, 0x80000003 // is machine software interrupt? + bne x14, x15, __crt0_dualcore_exit // go back to sleep if not + + // get launch configuration from core 0 + csrw 0xbc2, zero // ICC.SR: link select = 0 + csrr x13, 0xbc0 // ICC.RX: signature + li x14, 0xffab4321 // expected signature + bne x14, x13, __crt0_dualcore_exit // abort if incorrect signature + + csrw 0xbc1, x14 // ICC.TX: acknowledge start + csrr x2, 0xbc0 // ICC.RX: stack_top -> sp + csrr x12, 0xbc0 // ICC.RX: entry_point + j __crt0_main_entry // start main function + +__crt0_dualcore_exit: + mret // go back to sleep __crt0_dualcore_primary: #endif @@ -171,11 +167,7 @@ __crt0_main_entry: fence // reload instruction cache fence.i // reload instruction cache - // re-initialize trap CSRs - csrw mstatus, x5 - csrw mcause, zero - csrw mepc, zero - + csrw mstatus, x5 // re-initialize addi x10, zero, 0 // x10 = a0 = argc = 0 addi x11, zero, 0 // x11 = a1 = argv = 0 jalr x1, x12 // call actual main function; put return address in ra From 2c07c53ece8bc89534dc29186baa2a8ca8db3371 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:25:29 +0100 Subject: [PATCH 15/21] [docs] update dual-core section - add inter-core communication - update core 1 boot procedure --- docs/datasheet/cpu_dual_core.adoc | 69 ++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/docs/datasheet/cpu_dual_core.adoc b/docs/datasheet/cpu_dual_core.adoc index 1e6acec4a..a70e0ed0f 100644 --- a/docs/datasheet/cpu_dual_core.adoc +++ b/docs/datasheet/cpu_dual_core.adoc @@ -1,9 +1,9 @@ :sectnums: === Dual-Core Configuration -.Hardware Requirements -[IMPORTANT] -The SMP dual-core configuration requires the <<_core_local_interruptor_clint>> to be implemented. +.Dual-Core Example +[TIP] +A simple dual-core example program can be found in `sw/example/demo_dual_core`. Optionally, the CPU core can be implemented as **symmetric multiprocessing (SMP) dual-core** system. This dual-core configuration is enabled by the `DUAL_CORE_EN` <<_processor_top_entity_generics, top generic>>. @@ -14,10 +14,10 @@ of both core complexes are further switched into a single system bus using a rou image::smp_system.png[align=center] -Both CPU cores are fully identical and use the same configuration provided by the according -<<_processor_top_entity_generics, top generics>>. However, each core can be identified by the according -"hart ID" that can be retrieved from the <<_mhartid>> CSR. CPU core 0 (the _primary_ core) has `mhartid = 0` -while core 1 (the _secondary_ core) has `mhartid = 1`. +Both CPU cores are fully identical and use the same ISA, tuning and cache configurations provided by the +according <<_processor_top_entity_generics, top generics>>. However, each core can be identified by the +according "hart ID" that can be retrieved from the <<_mhartid>> CSR. CPU core 0 (the _primary_ core) has +`mhartid = 0` while core 1 (the _secondary_ core) has `mhartid = 1`. The following table summarizes the most important aspects when using the dual-core configuration. @@ -41,32 +41,63 @@ while the top of stack of core 1 has to be explicitly defined by core 0 (see <<_ cores share the same heap, `.data` and `.bss` sections. | **Constructors and destructors** | Constructors and destructors are executed on core 0 only. (see ) +| **Core communication** | See section <<_inter_core_communication_icc>>. | **Bootloader** | Only core 0 will boot and execute the bootloader while core 1 is held in standby. -| **Booting** | See next section <<_dual_core_boot>>. +| **Booting** | See section <<_dual_core_boot>>. |======================= -.Dual-Core Example + +==== Inter-Core Communication (ICC) + +Both cores can communicate with each other via a direct point-to-point connection based on FIFO-like message +queues. These direct communication links are faster (in terms of latency) compared to a memory-mapped or +shared-memory communication. Additionally, communication using these links is guaranteed to be atomic. + +The inter-core communication (ICC) module is implemented as dedicated hardware module within each CPU core +(VHDL file `rtl/core/neorv32_cpu_icc.vhd`). This module is automatically included if the dual-core option +is enabled. Each core provides a 32-bit wide and 4 entries deep FIFO for sending data to the other core. +Hence, there are two FIFOs: one for sending data from core 0 to core 1 and another one for sending data the +opposite way. + +The ICC communication links are accessed via NEORV32-specific CSRs. Hence, those FIFOs are accessible only +by the CPU core itself and cannot be accessed by the DMA or any other CPU core. In total, three CSRs are +provided to handle communications: + +The <<_mxiccsr>> is used to select the core with which to communicate. In the dual-core configuration core 1 +can only select core 0 and vice versa. The core selection in this register allows access to the according +message FIFOs via the two other CSRs. Additionally, the CSR provides status flags (TX FIFO data available; +RX FIFO free space) related to the selected communication link. + +The <<_mxiccrxd>> and <<_mxicctxd>> CSRs are used for the actual data read and write operations. Writing data +to <<<<_mxicctxd>>> will send to the message queue of the core selected by <<_mxiccsr>>. Conversely, reading +data from <<_mxiccrxd>> will return data received from the core selected by <<_mxiccsr>>. + +The ICC FIFOs do not provide any interrupt capabilities. Software is expected to use the machine-software +interrupt of the receiving core (provided by the <<_core_local_interruptor_clint>>) to inform it about +available messages. + +.ICC Software API [TIP] -A simple dual-core example setup / test program can be found in `sw/example/demo_dual_core`. +The NEORV32 software framework provides API wrappers to abstract inter-core communication: +`sw/lib/include/noevr32_smp.h` ==== Dual-Core Boot -After reset both cores start booting. However, core 1 will always (regardless of the boot configuration) enter -sleep mode inside the default <<_start_up_code_crt0>> that is linked with any compiled application. The primary -core (core 0) will continue booting executing either the <<_bootloader>> or the pre-installed image in the -internal instruction memory (depending on the <<_boot_configuration>>). +After reset, both cores start booting. However, core 1 will - regardless of the <<_boot_configuration>> - always +enter <<_sleep_mode>> right inside the default <<_start_up_code_crt0>> that is linked with any compiled +application. The primary core (core 0) will continue booting, executing either the <<_bootloader>> or the +pre-installed image from the internal instruction memory (depending on the boot configuration). -To boot-up core 1 the primary core has to use a special library function provided by the NEORV32 runtime -environment (RTE): +To boot-up core 1, the primary core has to use a special library function provided by the NEORV32 software framework: .CPU Core 1 launch function prototype (note that this function can only be executed on core 0) [source,c] ---- -int neorv32_rte_smp_launch(void (*entry_point)(void), uint8_t* stack_memory, size_t stack_size_bytes); +int neorv32_smp_launch(int hart_id, void (*entry_point)(void), uint8_t* stack_memory, size_t stack_size_bytes); ---- -When executed, core 0 will populate a configuration structure in main memory that contain the entry point +When executed, core 0 use the <<_inter_core_communication_icc>> to send launch data that includes the entry point for core 1 (via `entry_point`) and the actual stack configuration (via `stack_memory` and `stack_size_bytes`). .Core 1 Stack Memory @@ -78,5 +109,5 @@ boundary.´ After that, the primary core triggers the _machine software interrupt_ of core 1 using the <<_core_local_interruptor_clint>>. Core 1 wakes up from sleep mode, consumes the configuration structure and -finally starts executing at the provided entry point. When `neorv32_rte_smp_launch()` returns (with no error +finally starts executing at the provided entry point. When `neorv32_smp_launch()` returns (with no error code) the secondary core is online and running. From c8d23bb25a22d386dcc4ca773638a8154c9010b8 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:26:12 +0100 Subject: [PATCH 16/21] [vivado_ip] add dual-core option --- rtl/system_integration/neorv32_vivado_ip.tcl | 8 + rtl/system_integration/neorv32_vivado_ip.vhd | 190 ++++++++++--------- 2 files changed, 105 insertions(+), 93 deletions(-) diff --git a/rtl/system_integration/neorv32_vivado_ip.tcl b/rtl/system_integration/neorv32_vivado_ip.tcl index ac3894257..1d5b6e9c1 100644 --- a/rtl/system_integration/neorv32_vivado_ip.tcl +++ b/rtl/system_integration/neorv32_vivado_ip.tcl @@ -161,6 +161,14 @@ proc setup_ip_gui {} { { CLOCK_FREQUENCY {Clock Frequency (Hz)} {Frequency of the clk input signal in Hz} } } + set group [add_group $page {Core Complex}] + add_params $group { + { DUAL_CORE_EN {Number of CPU cores} {} } + } + set_property widget {comboBox} [ipgui::get_guiparamspec -name "DUAL_CORE_EN" -component [ipx::current_core] ] + set_property value_validation_type pairs [ipx::get_user_parameters DUAL_CORE_EN -of_objects [ipx::current_core]] + set_property value_validation_pairs {{Single-core} false {SMP dual-core} true} [ipx::get_user_parameters DUAL_CORE_EN -of_objects [ipx::current_core]] + set group [add_group $page {Boot Configuration}] add_params $group { { BOOT_MODE_SELECT {Boot mode select} {Processor boot configuration} } diff --git a/rtl/system_integration/neorv32_vivado_ip.vhd b/rtl/system_integration/neorv32_vivado_ip.vhd index a246ef951..f82177e18 100644 --- a/rtl/system_integration/neorv32_vivado_ip.vhd +++ b/rtl/system_integration/neorv32_vivado_ip.vhd @@ -26,116 +26,118 @@ entity neorv32_vivado_ip is -- Configuration Generics -- ------------------------------------------------------------ -- Clocking -- - CLOCK_FREQUENCY : natural := 100_000_000; + CLOCK_FREQUENCY : natural := 100_000_000; + -- Dual-Core Configuration -- + DUAL_CORE_EN : boolean := false; -- Identification -- - JEDEC_ID : std_logic_vector(10 downto 0) := "00000000000"; + JEDEC_ID : std_logic_vector(10 downto 0) := "00000000000"; -- Boot Configuration -- - BOOT_MODE_SELECT : natural range 0 to 2 := 0; + BOOT_MODE_SELECT : natural range 0 to 2 := 0; BOOT_ADDR_CUSTOM : std_ulogic_vector(31 downto 0) := x"00000000"; -- On-Chip Debugger (OCD) -- - OCD_EN : boolean := false; - OCD_AUTHENTICATION : boolean := false; + OCD_EN : boolean := false; + OCD_AUTHENTICATION : boolean := false; -- RISC-V CPU Extensions -- - RISCV_ISA_C : boolean := false; - RISCV_ISA_E : boolean := false; - RISCV_ISA_M : boolean := false; - RISCV_ISA_U : boolean := false; - RISCV_ISA_Zaamo : boolean := false; - RISCV_ISA_Zba : boolean := false; - RISCV_ISA_Zbb : boolean := false; - RISCV_ISA_Zbkb : boolean := false; - RISCV_ISA_Zbkc : boolean := false; - RISCV_ISA_Zbkx : boolean := false; - RISCV_ISA_Zbs : boolean := false; - RISCV_ISA_Zfinx : boolean := false; - RISCV_ISA_Zicntr : boolean := false; - RISCV_ISA_Zicond : boolean := false; - RISCV_ISA_Zihpm : boolean := false; - RISCV_ISA_Zmmul : boolean := false; - RISCV_ISA_Zknd : boolean := false; - RISCV_ISA_Zkne : boolean := false; - RISCV_ISA_Zknh : boolean := false; - RISCV_ISA_Zksed : boolean := false; - RISCV_ISA_Zksh : boolean := false; - RISCV_ISA_Zxcfu : boolean := false; + RISCV_ISA_C : boolean := false; + RISCV_ISA_E : boolean := false; + RISCV_ISA_M : boolean := false; + RISCV_ISA_U : boolean := false; + RISCV_ISA_Zaamo : boolean := false; + RISCV_ISA_Zba : boolean := false; + RISCV_ISA_Zbb : boolean := false; + RISCV_ISA_Zbkb : boolean := false; + RISCV_ISA_Zbkc : boolean := false; + RISCV_ISA_Zbkx : boolean := false; + RISCV_ISA_Zbs : boolean := false; + RISCV_ISA_Zfinx : boolean := false; + RISCV_ISA_Zicntr : boolean := false; + RISCV_ISA_Zicond : boolean := false; + RISCV_ISA_Zihpm : boolean := false; + RISCV_ISA_Zmmul : boolean := false; + RISCV_ISA_Zknd : boolean := false; + RISCV_ISA_Zkne : boolean := false; + RISCV_ISA_Zknh : boolean := false; + RISCV_ISA_Zksed : boolean := false; + RISCV_ISA_Zksh : boolean := false; + RISCV_ISA_Zxcfu : boolean := false; -- Tuning Options -- - CPU_FAST_MUL_EN : boolean := false; - CPU_FAST_SHIFT_EN : boolean := false; - CPU_RF_HW_RST_EN : boolean := false; + CPU_FAST_MUL_EN : boolean := false; + CPU_FAST_SHIFT_EN : boolean := false; + CPU_RF_HW_RST_EN : boolean := false; -- Physical Memory Protection (PMP) -- - PMP_NUM_REGIONS : natural range 0 to 16 := 0; - PMP_MIN_GRANULARITY : natural := 4; - PMP_TOR_MODE_EN : boolean := false; - PMP_NAP_MODE_EN : boolean := false; + PMP_NUM_REGIONS : natural range 0 to 16 := 0; + PMP_MIN_GRANULARITY : natural := 4; + PMP_TOR_MODE_EN : boolean := false; + PMP_NAP_MODE_EN : boolean := false; -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS : natural range 0 to 13 := 0; - HPM_CNT_WIDTH : natural range 0 to 64 := 40; + HPM_NUM_CNTS : natural range 0 to 13 := 0; + HPM_CNT_WIDTH : natural range 0 to 64 := 40; -- Internal Instruction memory -- - MEM_INT_IMEM_EN : boolean := false; - MEM_INT_IMEM_SIZE : natural := 16384; + MEM_INT_IMEM_EN : boolean := false; + MEM_INT_IMEM_SIZE : natural := 16384; -- Internal Data memory -- - MEM_INT_DMEM_EN : boolean := false; - MEM_INT_DMEM_SIZE : natural := 8192; + MEM_INT_DMEM_EN : boolean := false; + MEM_INT_DMEM_SIZE : natural := 8192; -- Internal Cache memory -- - ICACHE_EN : boolean := false; - ICACHE_NUM_BLOCKS : natural range 1 to 256 := 4; - ICACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; + ICACHE_EN : boolean := false; + ICACHE_NUM_BLOCKS : natural range 1 to 256 := 4; + ICACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; -- Internal Data Cache (dCACHE) -- - DCACHE_EN : boolean := false; - DCACHE_NUM_BLOCKS : natural range 1 to 256 := 4; - DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; + DCACHE_EN : boolean := false; + DCACHE_NUM_BLOCKS : natural range 1 to 256 := 4; + DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; -- External Bus Interface -- - XBUS_EN : boolean := true; - XBUS_TIMEOUT : natural range 8 to 65536 := 64; - XBUS_REGSTAGE_EN : boolean := false; - XBUS_CACHE_EN : boolean := false; - XBUS_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; - XBUS_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; + XBUS_EN : boolean := true; + XBUS_TIMEOUT : natural range 8 to 65536 := 64; + XBUS_REGSTAGE_EN : boolean := false; + XBUS_CACHE_EN : boolean := false; + XBUS_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; + XBUS_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; -- Execute in-place module (XIP) -- - XIP_EN : boolean := false; - XIP_CACHE_EN : boolean := false; - XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; - XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; + XIP_EN : boolean := false; + XIP_CACHE_EN : boolean := false; + XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; + XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; -- External Interrupts Controller (XIRQ) -- - XIRQ_EN : boolean := false; - XIRQ_NUM_CH : natural range 1 to 32 := 1; -- variable-sized ports must be at least 0 downto 0; #974 + XIRQ_EN : boolean := false; + XIRQ_NUM_CH : natural range 1 to 32 := 1; -- variable-sized ports must be at least 0 downto 0; #974 -- Processor peripherals -- - IO_GPIO_EN : boolean := false; - IO_GPIO_IN_NUM : natural range 1 to 64 := 1; -- variable-sized ports must be at least 0 downto 0; #974 - IO_GPIO_OUT_NUM : natural range 1 to 64 := 1; - IO_CLINT_EN : boolean := false; - IO_UART0_EN : boolean := false; - IO_UART0_RX_FIFO : natural range 1 to 2**15 := 1; - IO_UART0_TX_FIFO : natural range 1 to 2**15 := 1; - IO_UART1_EN : boolean := false; - IO_UART1_RX_FIFO : natural range 1 to 2**15 := 1; - IO_UART1_TX_FIFO : natural range 1 to 2**15 := 1; - IO_SPI_EN : boolean := false; - IO_SPI_FIFO : natural range 1 to 2**15 := 1; - IO_SDI_EN : boolean := false; - IO_SDI_FIFO : natural range 1 to 2**15 := 1; - IO_TWI_EN : boolean := false; - IO_TWI_FIFO : natural range 1 to 2**15 := 1; - IO_TWD_EN : boolean := false; - IO_TWD_FIFO : natural range 1 to 2**15 := 1; - IO_PWM_EN : boolean := false; - IO_PWM_NUM_CH : natural range 1 to 16 := 1; -- variable-sized ports must be at least 0 downto 0; #974 - IO_WDT_EN : boolean := false; - IO_TRNG_EN : boolean := false; - IO_TRNG_FIFO : natural range 1 to 2**15 := 1; - IO_CFS_EN : boolean := false; - IO_CFS_CONFIG : std_logic_vector(31 downto 0) := x"00000000"; - IO_CFS_IN_SIZE : natural range 1 to 4096 := 32; -- variable-sized ports must be at least 0 downto 0; #974 - IO_CFS_OUT_SIZE : natural range 1 to 4096 := 32; -- variable-sized ports must be at least 0 downto 0; #974 - IO_NEOLED_EN : boolean := false; - IO_NEOLED_TX_FIFO : natural range 1 to 2**15 := 1; - IO_GPTMR_EN : boolean := false; - IO_ONEWIRE_EN : boolean := false; - IO_DMA_EN : boolean := false; + IO_GPIO_EN : boolean := false; + IO_GPIO_IN_NUM : natural range 1 to 64 := 1; -- variable-sized ports must be at least 0 downto 0; #974 + IO_GPIO_OUT_NUM : natural range 1 to 64 := 1; + IO_CLINT_EN : boolean := false; + IO_UART0_EN : boolean := false; + IO_UART0_RX_FIFO : natural range 1 to 2**15 := 1; + IO_UART0_TX_FIFO : natural range 1 to 2**15 := 1; + IO_UART1_EN : boolean := false; + IO_UART1_RX_FIFO : natural range 1 to 2**15 := 1; + IO_UART1_TX_FIFO : natural range 1 to 2**15 := 1; + IO_SPI_EN : boolean := false; + IO_SPI_FIFO : natural range 1 to 2**15 := 1; + IO_SDI_EN : boolean := false; + IO_SDI_FIFO : natural range 1 to 2**15 := 1; + IO_TWI_EN : boolean := false; + IO_TWI_FIFO : natural range 1 to 2**15 := 1; + IO_TWD_EN : boolean := false; + IO_TWD_FIFO : natural range 1 to 2**15 := 1; + IO_PWM_EN : boolean := false; + IO_PWM_NUM_CH : natural range 1 to 16 := 1; -- variable-sized ports must be at least 0 downto 0; #974 + IO_WDT_EN : boolean := false; + IO_TRNG_EN : boolean := false; + IO_TRNG_FIFO : natural range 1 to 2**15 := 1; + IO_CFS_EN : boolean := false; + IO_CFS_CONFIG : std_logic_vector(31 downto 0) := x"00000000"; + IO_CFS_IN_SIZE : natural range 1 to 4096 := 32; -- variable-sized ports must be at least 0 downto 0; #974 + IO_CFS_OUT_SIZE : natural range 1 to 4096 := 32; -- variable-sized ports must be at least 0 downto 0; #974 + IO_NEOLED_EN : boolean := false; + IO_NEOLED_TX_FIFO : natural range 1 to 2**15 := 1; + IO_GPTMR_EN : boolean := false; + IO_ONEWIRE_EN : boolean := false; + IO_DMA_EN : boolean := false; IO_SLINK_EN : boolean := false; - IO_SLINK_RX_FIFO : natural range 1 to 2**15 := 1; - IO_SLINK_TX_FIFO : natural range 1 to 2**15 := 1; - IO_CRC_EN : boolean := false + IO_SLINK_RX_FIFO : natural range 1 to 2**15 := 1; + IO_SLINK_TX_FIFO : natural range 1 to 2**15 := 1; + IO_CRC_EN : boolean := false ); port ( -- ------------------------------------------------------------ @@ -353,6 +355,8 @@ begin generic map ( -- Clocking -- CLOCK_FREQUENCY => CLOCK_FREQUENCY, + -- Dual-Core Configuration -- + DUAL_CORE_EN => DUAL_CORE_EN, -- Identification -- JEDEC_ID => std_ulogic_vector(JEDEC_ID), -- Boot Configuration -- From 5fc3a48056401ca528206a6c39c142274e5fcbc4 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 23:05:02 +0100 Subject: [PATCH 17/21] [rtl] comment edits --- rtl/core/neorv32_bus.vhd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rtl/core/neorv32_bus.vhd b/rtl/core/neorv32_bus.vhd index 3a8b70a1d..d3f3c82d1 100644 --- a/rtl/core/neorv32_bus.vhd +++ b/rtl/core/neorv32_bus.vhd @@ -211,7 +211,7 @@ end neorv32_bus_switch_rtl; -- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- --- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. -- +-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. -- -- Licensed under the BSD-3-Clause license, see LICENSE for details. -- -- SPDX-License-Identifier: BSD-3-Clause -- -- ================================================================================ -- @@ -301,7 +301,7 @@ end neorv32_bus_reg_rtl; -- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- --- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. -- +-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. -- -- Licensed under the BSD-3-Clause license, see LICENSE for details. -- -- SPDX-License-Identifier: BSD-3-Clause -- -- ================================================================================ -- @@ -487,7 +487,7 @@ end neorv32_bus_gateway_rtl; -- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- --- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. -- +-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. -- -- Licensed under the BSD-3-Clause license, see LICENSE for details. -- -- SPDX-License-Identifier: BSD-3-Clause -- -- ================================================================================ -- @@ -747,7 +747,7 @@ end neorv32_bus_io_switch_rtl; -- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- --- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. -- +-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. -- -- Licensed under the BSD-3-Clause license, see LICENSE for details. -- -- SPDX-License-Identifier: BSD-3-Clause -- -- ================================================================================ -- @@ -863,7 +863,7 @@ begin sys_req_o.rw <= '1' when (arbiter.state = S_WRITE) or (arbiter.state = S_WRITE_WAIT) else core_req_i.rw; sys_req_o.src <= core_req_i.src; sys_req_o.priv <= core_req_i.priv; - sys_req_o.amo <= core_req_i.amo; + sys_req_o.amo <= core_req_i.amo; -- set during the entire read-modify-write operation sys_req_o.amoop <= (others => '0'); -- the specific AMO type should not matter after this point sys_req_o.fence <= core_req_i.fence; sys_req_o.sleep <= core_req_i.sleep; From 0245fdc4d319459c4ede7fb50643276fe15661be Mon Sep 17 00:00:00 2001 From: stnolting Date: Sun, 5 Jan 2025 09:26:26 +0100 Subject: [PATCH 18/21] Update sw/example/demo_dual_core/main.c Co-authored-by: NikLeberg <39563554+NikLeberg@users.noreply.github.com> Signed-off-by: stnolting --- sw/example/demo_dual_core/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sw/example/demo_dual_core/main.c b/sw/example/demo_dual_core/main.c index d172c78de..2336da3da 100644 --- a/sw/example/demo_dual_core/main.c +++ b/sw/example/demo_dual_core/main.c @@ -86,7 +86,7 @@ int main(void) { neorv32_uart0_printf("Launching core1...\n"); // Launch execution of core 1. Arguments: - // 1st: CHart ID of the core that we want to launch. + // 1st: Hart ID of the core that we want to launch. // 2nd: "main_core1" is the entry point for the core and we provide a total of 2kB of stack for it. // 3rd: Pointer to the core's stack memory array. // 4th: Size of the core's stack memory array. From 24bcf0669c55bdf0053ac1360bd9badbb737f8f4 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sun, 5 Jan 2025 09:26:44 +0100 Subject: [PATCH 19/21] Update docs/datasheet/cpu_csr.adoc Co-authored-by: NikLeberg <39563554+NikLeberg@users.noreply.github.com> Signed-off-by: stnolting --- docs/datasheet/cpu_csr.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/datasheet/cpu_csr.adoc b/docs/datasheet/cpu_csr.adoc index 249ec1071..48f137b4e 100644 --- a/docs/datasheet/cpu_csr.adoc +++ b/docs/datasheet/cpu_csr.adoc @@ -986,7 +986,7 @@ This CSR is hardwired to all-zero if there is just a single CPU core in the syst | Bit | Name [C] | R/W | Description | 1:0 | `CSR_MXICCSR_LINK_MSB : CSR_MXICCSR_LINK_LSB` | r/w | Link select. The value in this memory corresponds to the ID of the core to which a connection is to be established via a link. The ICC data registers <<_mxiccrxd>> -and <<_mxicctxd>> will only access the queue FIFOs of the selected link. Not that only bit 0 is writable. Bit 1 +and <<_mxicctxd>> will only access the queue FIFOs of the selected link. Note that only bit 0 is writable. Bit 1 is hardwaired to zero. | 29:2 | - | r/- | Reserved; hardwired to zero. | 30 | `CSR_MXICCSR_TX_FREE` | r/- | Set if there is free space for TX data for the selected link. From c2c790895721c46faed3d816ba039c1d786bb094 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sun, 5 Jan 2025 10:10:49 +0100 Subject: [PATCH 20/21] [sw] minor cleanups --- sw/common/crt0.S | 20 ++++++++++---------- sw/lib/source/neorv32_smp.c | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sw/common/crt0.S b/sw/common/crt0.S index 0f0a156a1..440338a33 100644 --- a/sw/common/crt0.S +++ b/sw/common/crt0.S @@ -72,21 +72,21 @@ __crt0_entry: // ************************************************************************************************ -// Dual-core setup - wait for configuration if we are not core 0. +// SMP multi-core setup - wait for configuration if we are not core 0. // ************************************************************************************************ -#ifndef DISABLE_DUALCORE -__crt0_dualcore_check: - beqz x1, __crt0_dualcore_primary // proceed with normal boot-up if we are core 0 +#ifndef DISABLE_MULTICORE +__crt0_multicore_check: + beqz x1, __crt0_multicore_primary // proceed with normal boot-up if we are core 0 // setup machine software interrupt - la x15, __crt0_dualcore_wakeup + la x15, __crt0_multicore_wakeup csrw mtvec, x15 // install interrupt handler csrsi mie, 1 << 3 // enable software interrupt source csrsi mstatus, 1 << 3 // enable machine-level interrupts j __crt0_sleep // wait for interrupt in sleep mode // machine software interrupt handler -__crt0_dualcore_wakeup: +__crt0_multicore_wakeup: li x14, 0xfff40000 // CLINT.MSWI base address slli x15, x1, 2 // offset = hart_id * 4 add x14, x14, x15 @@ -94,23 +94,23 @@ __crt0_dualcore_wakeup: csrr x14, mcause li x15, 0x80000003 // is machine software interrupt? - bne x14, x15, __crt0_dualcore_exit // go back to sleep if not + bne x14, x15, __crt0_multicore_exit // go back to sleep if not // get launch configuration from core 0 csrw 0xbc2, zero // ICC.SR: link select = 0 csrr x13, 0xbc0 // ICC.RX: signature li x14, 0xffab4321 // expected signature - bne x14, x13, __crt0_dualcore_exit // abort if incorrect signature + bne x14, x13, __crt0_multicore_exit // abort if incorrect signature csrw 0xbc1, x14 // ICC.TX: acknowledge start csrr x2, 0xbc0 // ICC.RX: stack_top -> sp csrr x12, 0xbc0 // ICC.RX: entry_point j __crt0_main_entry // start main function -__crt0_dualcore_exit: +__crt0_multicore_exit: mret // go back to sleep -__crt0_dualcore_primary: +__crt0_multicore_primary: #endif diff --git a/sw/lib/source/neorv32_smp.c b/sw/lib/source/neorv32_smp.c index da5797492..882a46d00 100644 --- a/sw/lib/source/neorv32_smp.c +++ b/sw/lib/source/neorv32_smp.c @@ -27,7 +27,7 @@ **************************************************************************/ int neorv32_smp_launch(int hart_id, void (*entry_point)(void), uint8_t* stack_memory, size_t stack_size_bytes) { - const uint32_t signature = 0xffab4321u; + const uint32_t magic_number = 0xffab4321u; int num_cores = (int)NEORV32_SYSINFO->MISC[SYSINFO_MISC_HART]; // sanity checks @@ -47,7 +47,7 @@ int neorv32_smp_launch(int hart_id, void (*entry_point)(void), uint8_t* stack_me uint32_t stack_top = ((uint32_t)stack_memory + (uint32_t)(stack_size_bytes-1)) & 0xfffffff0u; // send launch configuration - neorv32_smp_icc_put(hart_id, signature); // signature + neorv32_smp_icc_put(hart_id, magic_number); // identifies valid configuration neorv32_smp_icc_put(hart_id, stack_top); // top of core's stack neorv32_smp_icc_put(hart_id, (uint32_t)entry_point); // entry point @@ -58,11 +58,11 @@ int neorv32_smp_launch(int hart_id, void (*entry_point)(void), uint8_t* stack_me int cnt = 0; while (1) { if (neorv32_smp_icc_avail(hart_id)) { - if (neorv32_smp_icc_get(hart_id) == signature) { + if (neorv32_smp_icc_get(hart_id) == magic_number) { return 0; } } - if (cnt > 10000) { + if (cnt > 1000) { return -2; // timeout; core did not respond } cnt++; From f6ba1550419a71055d5b083104d6604ba4f73900 Mon Sep 17 00:00:00 2001 From: stnolting Date: Sun, 5 Jan 2025 10:11:03 +0100 Subject: [PATCH 21/21] [sw/lib] remove obsolete legacy layer --- sw/lib/include/neorv32.h | 3 --- sw/lib/include/neorv32_legacy.h | 42 --------------------------------- 2 files changed, 45 deletions(-) delete mode 100644 sw/lib/include/neorv32_legacy.h diff --git a/sw/lib/include/neorv32.h b/sw/lib/include/neorv32.h index b78bfbb79..24b8bcc57 100644 --- a/sw/lib/include/neorv32.h +++ b/sw/lib/include/neorv32.h @@ -252,9 +252,6 @@ typedef union { // helper functions #include "neorv32_aux.h" -// legacy compatibility layer -#include "neorv32_legacy.h" - // CPU core #include "neorv32_cpu.h" #include "neorv32_cpu_csr.h" diff --git a/sw/lib/include/neorv32_legacy.h b/sw/lib/include/neorv32_legacy.h deleted file mode 100644 index db5a0e1aa..000000000 --- a/sw/lib/include/neorv32_legacy.h +++ /dev/null @@ -1,42 +0,0 @@ -// ================================================================================ // -// The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 // -// Copyright (c) NEORV32 contributors. // -// Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. // -// Licensed under the BSD-3-Clause license, see LICENSE for details. // -// SPDX-License-Identifier: BSD-3-Clause // -// ================================================================================ // - -/** - * @file neorv32_legacy.h - * @brief Legacy compatibility layer. - * @warning Deprecated! Do not use for new designs! - * @see https://stnolting.github.io/neorv32/sw/files.html - */ - -#ifndef neorv32_legacy_h -#define neorv32_legacy_h - -#include - - -/**********************************************************************//** - * @name GPIO aliases - **************************************************************************/ -/**@{*/ -#define INPUT_LO INPUT[0] -#define INPUT_HI INPUT[1] -#define OUTPUT_LO OUTPUT[0] -#define OUTPUT_HI OUTPUT[1] -/**@}*/ - - -/**********************************************************************//** - * @name Atomic LR/SC instructions - **************************************************************************/ -/**@{*/ -#define neorv32_cpu_load_reservate_word(addr, wdata) neorv32_cpu_amolr(addr, wdata) -#define neorv32_cpu_store_conditional_word(addr, wdata) neorv32_cpu_amosc(addr, wdata) -/**@}*/ - - -#endif // neorv32_legacy_h