[sw/lib] add SMP HAL

This commit is contained in:
stnolting 2025-01-04 22:06:11 +01:00
parent c13a0f5909
commit e3cc802d7d
4 changed files with 152 additions and 1 deletions

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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 <neorv32.h>
/**********************************************************************//**
* 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++;
}
}