diff --git a/CMakeLists.txt b/CMakeLists.txt index 10814e6c..79b6b92b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,6 @@ set(BUILD_LF_TESTS OFF CACHE BOOL "Build lf tests") set(BUILD_UNIT_TESTS OFF CACHE BOOL "Build unit tests") set(TEST_COVERAGE OFF CACHE BOOL "Compute test coverage") set(ASAN OFF CACHE BOOL "Compile with AddressSanitizer") -set(PLATFORM "POSIX" CACHE STRING "Platform to target") set(EVENT_QUEUE_SIZE 10 CACHE STRING "Static size of the event queue") set(REACTION_QUEUE_SIZE 10 CACHE STRING "Static size of the reaction queue") @@ -52,6 +51,10 @@ if (PLATFORM STREQUAL "POSIX") if(BUILD_EXAMPLES) add_subdirectory(examples/posix) endif () +elseif (PLATFORM STREQUAL "FLEXPRET") + add_library(reactor-uc STATIC ${SOURCES}) + add_subdirectory($ENV{FP_SDK_PATH} BINARY_DIR) + target_link_libraries(reactor-uc PUBLIC fp-sdk) elseif (PLATFORM STREQUAL "ZEPHYR") zephyr_library_named(reactor-uc) zephyr_library_sources(${SOURCES}) diff --git a/examples/flexpret/CMakeLists.txt b/examples/flexpret/CMakeLists.txt new file mode 100644 index 00000000..31ae88f9 --- /dev/null +++ b/examples/flexpret/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.22) + +if(DEFINED ENV{FP_SDK_PATH}) + # Set toolchain to RISC-V; must be done before call to project() + include($ENV{FP_SDK_PATH}/cmake/riscv-toolchain.cmake) +else() + message(FATAL_ERROR "FP_SDK_PATH environment variable not set!") +endif() + +project(fp-timer + LANGUAGES C + DESCRIPTION "LF on FlexPRET using uC runtime running a simple timer" + VERSION 1.0.0 +) + +set(DEBUG true) +set(SUPPORT_LONG_LONG true) # printf + +add_executable(fp-timer timer.c) + +set(PLATFORM "FLEXPRET" CACHE STRING "Platform to target") +set(BUILD_EXAMPLES OFF CAHCHE BOOL) + +add_subdirectory(../.. reactor-uc) +#add_subdirectory($ENV{FP_SDK_PATH} BINARY_DIR) +#target_link_libraries(fp-lf-uc PRIVATE +# ${CMAKE_CURRENT_LIST_DIR}/../src-gen/FlexPRET_uC/build/libFlexPRET_uC.a +# ${CMAKE_CURRENT_LIST_DIR}/../src-gen/FlexPRET_uC/build/reactor-uc/libreactor-uc.a +#) + + +target_link_libraries(fp-timer PRIVATE fp-sdk reactor-uc) + +include($ENV{FP_SDK_PATH}/cmake/fp-app.cmake) + +fp_add_outputs(fp-timer) + + + +# cmake_minimum_required(VERSION 3.20.0) +# set(PLATFORM "PICO" CACHE STRING "Platform to target") +# set(BUILD_EXAMPLES OFF CAHCHE BOOL) + +# if (DEFINED ENV{PICO_SDK_PATH}) +# include("$ENV{PICO_SDK_PATH}/pico_sdk_init.cmake") +# else() +# message(FATAL_ERROR "PICO_SDK_PATH environment variable not set") +# endif() + +# project(reactor-uc-pico) +# pico_sdk_init() +# add_subdirectory(../../ reactor-uc) + +# add_executable(hello_world +# timer_ex.c +# ) + +# target_link_libraries(hello_world PRIVATE reactor-uc) \ No newline at end of file diff --git a/examples/flexpret/timer.c b/examples/flexpret/timer.c new file mode 100644 index 00000000..143c6243 --- /dev/null +++ b/examples/flexpret/timer.c @@ -0,0 +1,47 @@ +#include "reactor-uc/reactor-uc.h" + +typedef struct { + Timer super; + Reaction *effects[0]; +} MyTimer; + +typedef struct { + Reaction super; +} MyReaction; + +struct MyReactor { + Reactor super; + MyReaction my_reaction; + MyTimer timer; + Reaction *_reactions[1]; + Trigger *_triggers[1]; +}; + +void timer_handler(Reaction *_self) { + struct MyReactor *self = (struct MyReactor *)_self->parent; + printf("Hello World @ %lld\n", self->super.env->get_logical_time(self->super.env)); +} + +void MyReaction_ctor(MyReaction *self, Reactor *parent) { + Reaction_ctor(&self->super, parent, timer_handler, NULL, 0, 0); +} + +void MyReactor_ctor(struct MyReactor *self, Environment *env) { + self->_reactions[0] = (Reaction *)&self->my_reaction; + self->_triggers[0] = (Trigger *)&self->timer; + Reactor_ctor(&self->super, "MyReactor", env, NULL, NULL, 0, self->_reactions, 1, self->_triggers, 1); + MyReaction_ctor(&self->my_reaction, &self->super); + Timer_ctor(&self->timer.super, &self->super, MSEC(0), USEC(100), self->timer.effects, 1); + TIMER_REGISTER_EFFECT(self->timer, self->my_reaction); +} + +struct MyReactor my_reactor; +Environment env; +int main() { + Environment_ctor(&env, (Reactor *)&my_reactor); + env.scheduler.set_timeout(&env.scheduler, SEC(1)); + MyReactor_ctor(&my_reactor, &env); + env.assemble(&env); + env.start(&env); + return 0; +} diff --git a/include/reactor-uc/platform/flexpret/flexpret.h b/include/reactor-uc/platform/flexpret/flexpret.h new file mode 100644 index 00000000..ab3e8a4b --- /dev/null +++ b/include/reactor-uc/platform/flexpret/flexpret.h @@ -0,0 +1,15 @@ +#ifndef REACTOR_UC_PLATFORM_FLEXPRET_H +#define REACTOR_UC_PLATFORM_FLEXPRET_H + +#include "reactor-uc/platform.h" +#include + +typedef struct { + Platform super; + volatile bool async_event_occurred; + bool in_critical_section; + fp_lock_t lock; +} PlatformFlexpret; + +void PlatformFlexpret_ctor(Platform *self); +#endif diff --git a/src/platform.c b/src/platform.c index 4fd45271..dd3eb2b2 100644 --- a/src/platform.c +++ b/src/platform.c @@ -5,6 +5,8 @@ #include "platform/riot/riot.c" #elif defined(PLATFORM_ZEPHYR) #include "platform/zephyr/zephyr.c" +#elif defined(PLATFORM_FLEXPRET) +#include "platform/flexpret/flexpret.c" #elif defined(PLATFORM_PICO) #include "platform/pico/pico.c" #else diff --git a/src/platform/flexpret/flexpret.c b/src/platform/flexpret/flexpret.c new file mode 100644 index 00000000..2fe7d900 --- /dev/null +++ b/src/platform/flexpret/flexpret.c @@ -0,0 +1,96 @@ +#include "reactor-uc/platform/flexpret/flexpret.h" +#include "reactor-uc/error.h" + +static PlatformFlexpret platform; + +lf_ret_t PlatformFlexpret_initialize(Platform *self) { + PlatformFlexpret *p = (PlatformFlexpret *) self; + p->async_event_occurred = false; + p->in_critical_section = false; + p->lock = (fp_lock_t) FP_LOCK_INITIALIZER; + return LF_OK; +} + +instant_t PlatformFlexpret_get_physical_time(Platform *self) { + (void)self; + return (instant_t) rdtime64(); +} + +lf_ret_t PlatformFlexpret_wait_until_interruptible(Platform *self, instant_t wakeup_time) { + PlatformFlexpret *p = (PlatformFlexpret *) self; + + p->async_event_occurred = false; + self->leave_critical_section(self); + // For FlexPRET specifically this functionality is directly available as + // an instruction + // It cannot fail - if it does, there is a bug in the processor and not much + // software can do about it + fp_wait_until(wakeup_time); + self->enter_critical_section(self); + + if (p->async_event_occurred) { + return LF_SLEEP_INTERRUPTED; + } else { + return LF_OK; + } +} + +lf_ret_t PlatformFlexpret_wait_until(Platform *self, instant_t wakeup_time) { + (void)self; + + // Interrupts should be disabled here so it does not matter whether we + // use wait until or delay until, but delay until is more accurate here + fp_delay_until(wakeup_time); + return LF_OK; +} + +// Note: Code is directly copied from FlexPRET's reactor-c implementation; +// beware of code duplication +void PlatformFlexpret_leave_critical_section(Platform *self) { + PlatformFlexpret *p = (PlatformFlexpret *) self; + + // In the special case where this function is called during an interrupt + // subroutine (isr) it should have no effect + if ((read_csr(CSR_STATUS) & 0x04) == 0x04) + return; + + validate(p->in_critical_section == true); + + fp_interrupt_enable(); + fp_lock_release(&p->lock); + p->in_critical_section = false; +} + +// Note: Code is directly copied from FlexPRET's reactor-c implementation; +// beware of code duplication +void PlatformFlexpret_enter_critical_section(Platform *self) { + PlatformFlexpret *p = (PlatformFlexpret *) self; + + // In the special case where this function is called during an interrupt + // subroutine (isr) it should have no effect + if ((read_csr(CSR_STATUS) & 0x04) == 0x04) + return; + + validate(p->in_critical_section == false); + + fp_interrupt_disable(); + fp_lock_acquire(&p->lock); + p->in_critical_section = true; +} + +void PlatformFlexpret_new_async_event(Platform *self) { + PlatformFlexpret *p = (PlatformFlexpret *) self; + p->async_event_occurred = true; +} + +void Platform_ctor(Platform *self) { + self->enter_critical_section = PlatformFlexpret_enter_critical_section; + self->leave_critical_section = PlatformFlexpret_leave_critical_section; + self->get_physical_time = PlatformFlexpret_get_physical_time; + self->wait_until = PlatformFlexpret_wait_until; + self->initialize = PlatformFlexpret_initialize; + self->wait_until_interruptible = PlatformFlexpret_wait_until_interruptible; + self->new_async_event = PlatformFlexpret_new_async_event; +} + +Platform *Platform_new(void) { return (Platform *)&platform; }