Skip to content

Commit

Permalink
Merge pull request #344 from lf-lang/rp2040-multicore
Browse files Browse the repository at this point in the history
Rp2040 multithreaded target support
  • Loading branch information
sberkun authored May 27, 2024
2 parents c30161c + b58a3a5 commit d9f86a0
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 8 deletions.
3 changes: 3 additions & 0 deletions low_level_platform/api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr")
target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_ZEPHYR)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")
target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_RP2040)
target_link_libraries(lf-low-level-platform-api INTERFACE pico_stdlib)
target_link_libraries(lf-low-level-platform-api INTERFACE pico_multicore)
target_link_libraries(lf-low-level-platform-api INTERFACE pico_sync)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET")
target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET)
target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk)
Expand Down
12 changes: 12 additions & 0 deletions low_level_platform/api/platform/lf_rp2040_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,16 @@
#define LF_TIME_BUFFER_LENGTH 80
#define _LF_TIMEOUT 1

#ifndef LF_SINGLE_THREADED
#warning "Threaded support on rp2040 is still experimental"

typedef recursive_mutex_t lf_mutex_t;
typedef struct {
semaphore_t notifs[NUM_CORES];
lf_mutex_t* mutex;
} lf_cond_t;
typedef int lf_thread_t;

#endif // LF_SINGLE_THREADED

#endif // LF_PICO_SUPPORT_H
6 changes: 6 additions & 0 deletions low_level_platform/impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr")
zephyr_library_named(lf-low-level-platform-impl)
zephyr_library_sources(${LF_LOW_LEVEL_PLATFORM_FILES})
zephyr_library_link_libraries(kernel)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")
add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES})
if (DEFINED NUMBER_OF_WORKERS AND ${NUMBER_OF_WORKERS} GREATER 2)
message(FATAL_ERROR "RP2040 can have at most 2 workers (one per core).\
Number of requested workers is ${NUMBER_OF_WORKERS}.")
endif()
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET")
add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES})
target_link_libraries(lf-low-level-platform-impl PRIVATE fp-sdk)
Expand Down
124 changes: 116 additions & 8 deletions low_level_platform/impl/src/lf_rp2040_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @author{Abhi Gundrala <[email protected]>}
*/

#if !defined(LF_SINGLE_THREADED)
#error "Only the single-threaded runtime has support for RP2040"
#endif

#include "platform/lf_rp2040_support.h"
#include "low_level_platform.h"
#include "utils/util.h"
#include "tag.h"

#include <pico/stdlib.h>
Expand Down Expand Up @@ -67,6 +62,8 @@ static uint32_t _lf_num_nested_crit_sec = 0;
*/
void _lf_initialize_clock(void) {
// init stdio lib
// may fail, but failure may be ok/expected if printing is not needed
// (i.e. if neither USB nor UART are enabled)
stdio_init_all();
// init sync structs
critical_section_init(&_lf_crit_sec);
Expand Down Expand Up @@ -161,7 +158,7 @@ int lf_disable_interrupts_nested() {
return 1;
}
// check crit sec count
// enter non-rentrant state by disabling interrupts
// enter non-reentrant state by disabling interrupts
// lock second core execution
if (_lf_num_nested_crit_sec == 0) {
// block if associated spin lock in use
Expand Down Expand Up @@ -202,9 +199,120 @@ int lf_enable_interrupts_nested() {
*/
int _lf_single_threaded_notify_of_event() {
// notify main sleep loop of event
sem_release(&_lf_sem_irq_event);
if (sem_release(&_lf_sem_irq_event)) {
return 0;
}
return 1;
}

#else // LF_SINGLE_THREADED

#warning "Threaded runtime on RP2040 is still experimental"

/**
* @brief Get the number of cores on the host machine.
*/
int lf_available_cores() { return 2; }

static void* (*thread_1)(void*);
static void* thread_1_args;
static int num_create_threads_called = 0;
static semaphore_t thread_1_done;
static void* thread_1_return;

#define MAGIC_THREAD1_ID 314159

void core1_entry() {
thread_1_return = thread_1(thread_1_args);
sem_reset(&thread_1_done, 1);
}

int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) {
// make sure this fn is only called once
if (num_create_threads_called != 0) {
return 1;
}
thread_1 = lf_thread;
thread_1_args = arguments;
num_create_threads_called += 1;
sem_init(&thread_1_done, 0, 1);
multicore_launch_core1(core1_entry);
*thread = MAGIC_THREAD1_ID;
return 0;
}

int lf_thread_join(lf_thread_t thread, void** thread_return) {
if (thread != MAGIC_THREAD1_ID) {
return 1;
}
sem_acquire_blocking(&thread_1_done);
// release in case join is called again
if (!sem_release(&thread_1_done)) {
// shouldn't be possible; lf_thread_join is only called from main thread
return 1;
}
if (thread_return) {
*thread_return = thread_1_return;
}
return 0;
}

int lf_mutex_init(lf_mutex_t* mutex) {
recursive_mutex_init(mutex);
return 0;
}

int lf_mutex_lock(lf_mutex_t* mutex) {
recursive_mutex_enter_blocking(mutex);
return 0;
}

int lf_mutex_unlock(lf_mutex_t* mutex) {
recursive_mutex_exit(mutex);
return 0;
}
#endif // LF_SINGLE_THREADED

// condition variables "notify" threads using a semaphore per core.
// although there are only two cores, may not use just a single semaphore
// as a cond_broadcast may be called from within an interrupt
int lf_cond_init(lf_cond_t* cond, lf_mutex_t* mutex) {
for (int i = 0; i < NUM_CORES; i++) {
sem_init(&(cond->notifs[i]), 0, 1);
}
cond->mutex = mutex;
return 0;
}

int lf_cond_broadcast(lf_cond_t* cond) {
for (int i = 0; i < NUM_CORES; i++) {
sem_reset(&(cond->notifs[i]), 1);
}
return 0;
}

int lf_cond_signal(lf_cond_t* cond) {
return lf_cond_broadcast(cond); // spurious wakeups, but that's ok
}

int lf_cond_wait(lf_cond_t* cond) {
semaphore_t* mailbox = &(cond->notifs[get_core_num()]);
lf_mutex_unlock(cond->mutex);
sem_acquire_blocking(mailbox);
lf_mutex_lock(cond->mutex);
return 0;
}

int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) {
semaphore_t* mailbox = &(cond->notifs[get_core_num()]);
absolute_time_t a = from_us_since_boot(absolute_time_ns / 1000);
bool acquired_permit = sem_acquire_block_until(mailbox, a);
return acquired_permit ? 0 : LF_TIMEOUT;
}

void initialize_lf_thread_id() {}

int lf_thread_id() { return get_core_num(); }

#endif // !LF_SINGLE_THREADED

#endif // PLATFORM_RP2040

0 comments on commit d9f86a0

Please sign in to comment.