From e3cc802d7d3b39f2911861b845f1345ee64b51db Mon Sep 17 00:00:00 2001 From: stnolting Date: Sat, 4 Jan 2025 22:06:11 +0100 Subject: [PATCH] [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 ad58c249..8efccb94 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 888a9db6..b78bfbb7 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 00000000..1ffd6d0d --- /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 00000000..da579749 --- /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++; + } +}