From b623e5cf0a5f07fe26c4788343bb613d3bd9cafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20H=C3=B6ppner?= Date: Wed, 12 Aug 2026 01:22:09 +0200 Subject: [PATCH] Refactor WASM runner and logging functionality; add heartbeat task and improve initialization process --- core/CMakeLists.txt | 4 +- core/include/FreeRTOSConfig.h | 1 + core/include/nova64_api.h | 2 +- core/include/wasm_runner.h | 5 +- core/src/nova64_api.c | 28 +++++-- core/src/nova64_core.c | 145 ++++++++++++++++++++++++---------- core/src/wasm_runner.c | 130 ++++++++++++++++++++++++------ simulator/Program.cs | 4 +- simulator/sd/slot0/init.wasm | Bin 103 -> 139 bytes software/init.go | 17 ---- software/init.zig | 5 +- software/nova64.zig | 10 +++ software/tmp.zig | 5 ++ 13 files changed, 261 insertions(+), 95 deletions(-) delete mode 100644 software/init.go create mode 100644 software/nova64.zig create mode 100644 software/tmp.zig diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index bd83ae2..4bb0cb6 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -84,10 +84,11 @@ else() # WAMR Desktop-Konfiguration set(WAMR_BUILD_INTERP 1 CACHE BOOL "" FORCE) set(WAMR_BUILD_FAST_INTERP 1 CACHE BOOL "" FORCE) + # set(WAMR_BUILD_INTERP_TICKS 1 CACHE BOOL "" FORCE) + set(WAMR_BUILD_JIT 0 CACHE BOOL "" FORCE) set(WAMR_BUILD_AOT 0 CACHE BOOL "" FORCE) set(WAMR_BUILD_LIBC_BUILTIN 1 CACHE BOOL "" FORCE) - # Disable WASI set(WAMR_BUILD_LIBC_WASI 0 CACHE BOOL "" FORCE) @@ -99,7 +100,6 @@ else() set(WAMR_BUILD_PLATFORM "linux" CACHE STRING "" FORCE) endif() - # define Target 'freertos_kernel' FetchContent_MakeAvailable(FreeRTOS_Kernel wamr_runtime) # -------------------------------------------------------------------------- diff --git a/core/include/FreeRTOSConfig.h b/core/include/FreeRTOSConfig.h index 8594e51..2581c2c 100644 --- a/core/include/FreeRTOSConfig.h +++ b/core/include/FreeRTOSConfig.h @@ -3,6 +3,7 @@ /* Desktop Simulator Settings */ #define configUSE_PREEMPTION 1 +#define configUSE_TIME_SLICING 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 #define configUSE_IDLE_HOOK 1 #define configUSE_TICK_HOOK 0 diff --git a/core/include/nova64_api.h b/core/include/nova64_api.h index 1c84685..f462136 100644 --- a/core/include/nova64_api.h +++ b/core/include/nova64_api.h @@ -1,6 +1,6 @@ #ifndef NOVA64_API_H #define NOVA64_API_H -void register_nova64_imports(void); +void nova64_register_imports(void); #endif // NOVA64_API_H diff --git a/core/include/wasm_runner.h b/core/include/wasm_runner.h index e6dc3a2..6648c8c 100644 --- a/core/include/wasm_runner.h +++ b/core/include/wasm_runner.h @@ -28,7 +28,8 @@ bool wasm_runner_initialize(void); */ bool wasm_runner_start_program( const char *module_path, - const wasm_runner_framebuffer_config_t *framebuffer_config, - wasm_runner_instance_t **out_instance); + const wasm_runner_framebuffer_config_t *framebuffer_config); + +void wasm_runner_terminate(void); #endif // WASM_RUNNER_H diff --git a/core/src/nova64_api.c b/core/src/nova64_api.c index 95050b2..ca53ea6 100644 --- a/core/src/nova64_api.c +++ b/core/src/nova64_api.c @@ -1,24 +1,42 @@ #include "FreeRTOS.h" +#include "nova64_internal.h" +#include "projdefs.h" #include "task.h" #include "wasm_export.h" -#include "projdefs.h" +#include + static void native_yield(wasm_exec_env_t exec_env, uint32_t timeout_ms) { if (timeout_ms == 0) { - // Gibt die Rest-Quantenzeit ab, blockiert aber nicht künstlich taskYIELD(); } else { - // Blockiert den Task für x Millisekunden vTaskDelay(pdMS_TO_TICKS(timeout_ms)); } } +static void native_log(wasm_exec_env_t exec_env, const char *message) { + (void)exec_env; + + nova64_log("[WASM LOG] "); + + const char *text = message ? message : ""; + size_t len = strlen(text); + bool has_newline = len > 0 && text[len - 1] == '\n'; + + if (has_newline) { + nova64_log("%s", text); + } else { + nova64_log("%s\n", text); + } +} + static NativeSymbol native_symbols[] = { - {"yield", (void *)native_yield, "(i)", NULL}, + {"nova64_yield", (void *)native_yield, "(i)", NULL}, + {"nova64_log", (void *)native_log, "($)", NULL}, // { "flush_framebuffer", (void*)native_flush_framebuffer, "()", NULL } }; -void register_nova64_imports(void) { +void nova64_register_imports(void) { wasm_runtime_register_natives("nova64", native_symbols, sizeof(native_symbols) / sizeof(NativeSymbol)); } \ No newline at end of file diff --git a/core/src/nova64_core.c b/core/src/nova64_core.c index 708b1fd..07adb2b 100644 --- a/core/src/nova64_core.c +++ b/core/src/nova64_core.c @@ -24,14 +24,48 @@ static nova64_io_interface_t g_io_interface_storage; static const nova64_io_interface_t *g_io_interface = NULL; static QueueHandle_t event_queue = NULL; static TaskHandle_t boot_task_handle = NULL; -static TaskHandle_t launcher_task_handle = NULL; +static TaskHandle_t init_task_handle = NULL; +static TaskHandle_t heartbeat_task_handle = NULL; #if defined(NOVA64_SHUTDOWN_AVAILABLE) static TaskHandle_t shutdown_task_handle = NULL; -static volatile bool shutdown_requested = false; +volatile bool shutdown_requested = false; #endif -static const char *const kInternalLauncherPath = "SYS:/launcher.wasm"; +static const char *const kInternalInitPath = "SYS:/init.wasm"; +#if defined(_WIN32) +#include +static SRWLOCK g_log_lock = SRWLOCK_INIT; + +static inline void log_lock(void) { AcquireSRWLockExclusive(&g_log_lock); } +static inline void log_unlock(void) { ReleaseSRWLockExclusive(&g_log_lock); } + +#elif defined(__unix__) || defined(__APPLE__) +#include +static pthread_mutex_t g_log_lock = PTHREAD_MUTEX_INITIALIZER; + +static inline void log_lock(void) { pthread_mutex_lock(&g_log_lock); } +static inline void log_unlock(void) { pthread_mutex_unlock(&g_log_lock); } + +#else + +#include "semphr.h" +static SemaphoreHandle_t g_log_lock = NULL; + +static inline void log_lock(void) { + if (!g_log_lock) { + g_log_lock = xSemaphoreCreateMutex(); + } + if (g_log_lock && xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + xSemaphoreTake(g_log_lock, portMAX_DELAY); + } +} +static inline void log_unlock(void) { + if (g_log_lock && xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + xSemaphoreGive(g_log_lock); + } +} +#endif void nova64_log(const char *format, ...) { char buffer[512]; @@ -40,48 +74,41 @@ void nova64_log(const char *format, ...) { vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); + log_lock(); + if (g_io_interface && g_io_interface->log_message) { g_io_interface->log_message(buffer); } else { fputs(buffer, stdout); + fflush(stdout); } + + log_unlock(); } static bool initialize_wasm_runtime(void) { nova64_log("Initializing WASM runtime...\n"); wasm_runner_initialize(); - // TODO: Replace this stub with real WAMR initialization. return true; } -static bool load_launcher_from_internal_storage(void) { - nova64_log("Loading launcher from internal storage (%s)...\n", - kInternalLauncherPath); - // TODO: Implement the actual internal storage filesystem and launcher load. - return true; -} - -static void nova64_wasm_launcher_task(void *params) { +static void start_init_from_internal_storage(void *params) { (void)params; - nova64_log("WASM launcher task started.\n"); - - // TODO: Execute the loaded WASM launcher module here with the WAMR engine. - for (;;) { - vTaskDelay(pdMS_TO_TICKS(1000)); - } + wasm_runner_start_program(kInternalInitPath, NULL); } -static bool start_launcher_task(void) { - BaseType_t result = xTaskCreate(nova64_wasm_launcher_task, "Nova64Launcher", - 4096 / sizeof(StackType_t), NULL, - tskIDLE_PRIORITY + 1, &launcher_task_handle); +static bool start_init_task(void) { + BaseType_t result = + xTaskCreate(start_init_from_internal_storage, "Nova64Init", + 4096 / sizeof(StackType_t), NULL, tskIDLE_PRIORITY + 1, + &init_task_handle); if (result != pdPASS) { - nova64_log("Failed to create launcher task.\n"); + nova64_log("Failed to create init task.\n"); return false; } - nova64_log("Launcher task created successfully.\n"); + nova64_log("Init task created successfully.\n"); return true; } @@ -90,14 +117,34 @@ static void nova64_shutdown_task(void *params) { (void)params; nova64_log("Shutdown task started.\n"); + shutdown_requested = false; for (;;) { + ulTaskNotifyTake(pdTRUE, + pdMS_TO_TICKS(50)); // Wait for notification or timeout if (shutdown_requested) { - nova64_log("Shutdown requested; ending scheduler.\n"); - vTaskEndScheduler(); - return; + break; } - vTaskDelay(pdMS_TO_TICKS(100)); } + + nova64_log("Shutdown requested; terminating WASM runtime.\n"); + + wasm_runner_terminate(); + + if (heartbeat_task_handle != NULL) { + vTaskDelete(heartbeat_task_handle); + heartbeat_task_handle = NULL; + } + + vTaskDelay(pdMS_TO_TICKS(100)); // Allow time for tasks to clean up + + shutdown_task_handle = NULL; +#if defined(_WIN32) + ExitThread(0); +#elif defined(__unix__) || defined(__APPLE__) + pthread_exit(NULL); +#else + vTaskDelete(NULL); +#endif } static bool start_shutdown_task(void) { @@ -115,6 +162,27 @@ static bool start_shutdown_task(void) { } #endif +void heartbeat_task(void *pvParameters) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = pdMS_TO_TICKS(1000); + + uint32_t seconds = 0; + + for (;;) { + vTaskDelayUntil(&xLastWakeTime, xFrequency); + + seconds++; + + nova64_log("[Heartbeat] System running for %lu s | FreeRTOS Tick: %lu\n", + (unsigned long)seconds, (unsigned long)xTaskGetTickCount()); + } +} + +void start_heartbeat_task(void) { + xTaskCreate(heartbeat_task, "heartbeat", 2048, NULL, 1, + &heartbeat_task_handle); +} + static void nova64_boot_task(void *params) { (void)params; nova64_log("Boot task started.\n"); @@ -125,17 +193,12 @@ static void nova64_boot_task(void *params) { return; } - if (!load_launcher_from_internal_storage()) { - nova64_log("Launcher loading failed.\n"); - vTaskDelete(NULL); - return; - } - - if (!start_launcher_task()) { - nova64_log("Launcher startup failed.\n"); + if (!start_init_task()) { + nova64_log("Init startup failed.\n"); vTaskDelete(NULL); return; } + start_heartbeat_task(); nova64_log("Boot process completed.\n"); vTaskDelete(NULL); @@ -153,10 +216,6 @@ NOVA64_API bool nova64_init(const nova64_io_interface_t *io_interface) { g_io_interface_storage = *io_interface; g_io_interface = &g_io_interface_storage; -#if defined(NOVA64_SHUTDOWN_AVAILABLE) - shutdown_requested = false; -#endif - nova64_log("System Initializing...\n"); event_queue = xQueueCreate(10, sizeof(uint32_t)); @@ -206,7 +265,13 @@ NOVA64_API bool nova64_shutdown(void) { } nova64_log("Scheduler shutdown requested from host.\n"); + shutdown_requested = true; + if (shutdown_task_handle != NULL) { + xTaskNotifyGive(shutdown_task_handle); + return true; + } + return true; } #endif diff --git a/core/src/wasm_runner.c b/core/src/wasm_runner.c index 0683460..34177a4 100644 --- a/core/src/wasm_runner.c +++ b/core/src/wasm_runner.c @@ -1,28 +1,75 @@ #include "wasm_runner.h" +#include "FreeRTOS.h" +#include "nova64_api.h" #include "nova64_fs.h" #include "nova64_internal.h" -#include "nova64_api.h" +#include "task.h" #include "wasm_export.h" #include -struct wasm_runner_instance { - void *native_instance; - char *module_path; - wasm_runner_framebuffer_config_t framebuffer_config; - wasm_runner_instance_t *next; -}; +#define MAX_WASM_TASKS 4 + +typedef enum { SLOT_FREE = 0, SLOT_RUNNING, SLOT_STOPPING } slot_state_t; + +typedef struct { + int id; + slot_state_t state; + // TaskHandle_t freertos_handle; + wasm_module_inst_t module_inst; + wasm_exec_env_t exec_env; +} wasm_task_slot_t; + +static wasm_task_slot_t g_wasm_slots[MAX_WASM_TASKS]; char error_buf[128]; uint32_t stack_size = 8092, heap_size = 8092; bool wasm_runner_initialize(void) { + for (int i = 0; i < MAX_WASM_TASKS; i++) { + g_wasm_slots[i].id = i; + g_wasm_slots[i].state = SLOT_FREE; + // g_wasm_slots[i].freertos_handle = NULL; + g_wasm_slots[i].module_inst = NULL; + } + wasm_runtime_init(); - register_nova64_imports(); + nova64_register_imports(); nova64_log("WASM runtime initialized successfully.\n"); - const char *module_file = "SYS:/init.wasm"; - int32_t file_size = nova64_get_file_size(module_file); + return true; +} + +bool wasm_runner_destroy(void) { + wasm_runtime_destroy(); + return true; +} + +bool wasm_runner_start_program( + const char *module_path, + const wasm_runner_framebuffer_config_t *framebuffer_config) { + + nova64_log("Running WASM module: %s\n", module_path); + + wasm_task_slot_t *slot = NULL; + for (int i = 0; i < MAX_WASM_TASKS; i++) { + if (g_wasm_slots[i].state == SLOT_FREE) { + slot = &g_wasm_slots[i]; + break; + } + } + + if (!slot) { + nova64_log("Maximum number of WASM tasks (%d) reached!\n", MAX_WASM_TASKS); + return false; + } + + if (!wasm_runtime_init_thread_env()) { + nova64_log("Failed to initialize WASM runtime thread environment.\n"); + return false; + } + + int32_t file_size = nova64_get_file_size(module_path); if (file_size <= 0) { nova64_log("Failed to determine WASM module size.\n"); return false; @@ -34,7 +81,7 @@ bool wasm_runner_initialize(void) { return false; } - if (!nova64_read_file_to_buffer(module_file, buffer, (size_t)file_size)) { + if (!nova64_read_file_to_buffer(module_path, buffer, (size_t)file_size)) { nova64_log("Failed to read WASM module into buffer.\n"); free(buffer); return false; @@ -43,36 +90,73 @@ bool wasm_runner_initialize(void) { wasm_module_t module = wasm_runtime_load(buffer, (uint32_t)file_size, error_buf, sizeof(error_buf)); - wasm_module_inst_t module_inst = wasm_runtime_instantiate( - module, stack_size, heap_size, error_buf, sizeof(error_buf)); + slot->module_inst = wasm_runtime_instantiate(module, stack_size, heap_size, + error_buf, sizeof(error_buf)); wasm_function_inst_t start_func = - wasm_runtime_lookup_function(module_inst, "_start"); + wasm_runtime_lookup_function(slot->module_inst, "_start"); if (start_func == NULL) { nova64_log("Failed to find '_start' function in WASM module: %s\n", - wasm_runtime_get_exception(module_inst)); + wasm_runtime_get_exception(slot->module_inst)); free(buffer); return false; } - wasm_exec_env_t exec_env = - wasm_runtime_create_exec_env(module_inst, stack_size); + slot->exec_env = wasm_runtime_create_exec_env(slot->module_inst, stack_size); + + nova64_log("WASM module execution environment created successfully.\n"); uint32_t argv[2] = {5, 3}; // Example arguments for the "add" function - if (wasm_runtime_call_wasm(exec_env, start_func, 2, argv)) { - nova64_log("WASM module executed successfully. Sum: %d\n", argv[0]); + slot->state = SLOT_RUNNING; + + if (wasm_runtime_call_wasm(slot->exec_env, start_func, 0, NULL)) { + nova64_log("WASM module executed successfully.\n"); } else { nova64_log("Failed to execute WASM module: %s\n", - wasm_runtime_get_exception(module_inst)); + wasm_runtime_get_exception(slot->module_inst)); } - wasm_runtime_destroy_exec_env(exec_env); - wasm_runtime_deinstantiate(module_inst); + slot->state = SLOT_STOPPING; + + wasm_runtime_destroy_exec_env(slot->exec_env); + wasm_runtime_deinstantiate(slot->module_inst); wasm_runtime_unload(module); free(buffer); - wasm_runtime_destroy(); + wasm_runtime_destroy_thread_env(); + + slot->module_inst = NULL; + slot->exec_env = NULL; + slot->state = SLOT_FREE; + vTaskDelete(NULL); return true; } + +void wasm_runner_terminate(void) { + nova64_log("Stopping all WASM tasks...\n"); + + for (int i = 0; i < MAX_WASM_TASKS; i++) { + if (g_wasm_slots[i].state == SLOT_RUNNING && g_wasm_slots[i].module_inst) { + g_wasm_slots[i].state = SLOT_STOPPING; + wasm_runtime_terminate(g_wasm_slots[i].module_inst); + } + } + + bool any_running = true; + while (any_running) { + any_running = false; + for (int i = 0; i < MAX_WASM_TASKS; i++) { + if (g_wasm_slots[i].state != SLOT_FREE) { + any_running = true; + break; + } + } + if (any_running) { + vTaskDelay(pdMS_TO_TICKS(10)); + } + } + + nova64_log("All WASM tasks successfully stopped.\n"); +} \ No newline at end of file diff --git a/simulator/Program.cs b/simulator/Program.cs index 58bbd1c..a42bb8c 100644 --- a/simulator/Program.cs +++ b/simulator/Program.cs @@ -1,7 +1,4 @@ -using System; -using System.IO; using System.Runtime.InteropServices; -using System.Threading; using Zio; using Zio.FileSystems; @@ -76,6 +73,7 @@ internal static class Program private static readonly Nova64Core.LogMessageDelegate LogMessage = (message) => { Console.Write($"[Core] {message}"); + Console.Out.Flush(); }; private static GCHandle? _ioHandle; diff --git a/simulator/sd/slot0/init.wasm b/simulator/sd/slot0/init.wasm index dd9f70de56eb57ccffe9aacdbb29602dac20aa38..aa6716760102ebfe7c3047074d7ec456d6eccd49 100644 GIT binary patch delta 114 zcmYfAX0&8TEY4+QU|?Y6U`k-DXGmaRU=n3y%gZlIG&A9XQ1LnW=?o0aOpJ^ytc(SW zjEt