From 7ea52cb96a34573474ca00bb7db57efc41120c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20H=C3=B6ppner?= Date: Sun, 9 Aug 2026 16:29:38 +0200 Subject: [PATCH] Create Simulator target scaffold --- .gitignore | 6 +- .vscode/launch.json | 15 +++ .vscode/settings.json | 7 +- .vscode/tasks.json | 19 +++ CMakeLists.txt | 129 ++++++--------------- README.md | 20 +++- core/CMakeLists.txt | 108 +++++++++++++++++ {include => core/include}/FreeRTOSConfig.h | 0 {include => core/include}/nova64_core.h | 0 {src => core/src}/nova64_core.c | 0 {src => core/src}/wasm_runner.c | 0 esp32/.gitkeep | 0 simulator/Nova64Simulator.csproj | 30 +++++ simulator/Program.cs | 42 +++++++ 14 files changed, 275 insertions(+), 101 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 core/CMakeLists.txt rename {include => core/include}/FreeRTOSConfig.h (100%) rename {include => core/include}/nova64_core.h (100%) rename {src => core/src}/nova64_core.c (100%) rename {src => core/src}/wasm_runner.c (100%) create mode 100644 esp32/.gitkeep create mode 100644 simulator/Nova64Simulator.csproj create mode 100644 simulator/Program.cs diff --git a/.gitignore b/.gitignore index 5b79a54..56b016c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -build/ -.cache/ \ No newline at end of file +build**/ +.cache/ +bin/ +obj/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..30dcfa8 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Nova64 Simulator", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "CMake: build", + "program": "${workspaceFolder}/simulator/bin/Debug/net8.0/Nova64Simulator.dll", + "args": [], + "cwd": "${workspaceFolder}/simulator", + "console": "integratedTerminal" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index a15e8d5..8c3b338 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,8 @@ "cmake.configureOnOpen": true, "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", - "cmake.cmakePath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\IDE\\CommonExtensions\\Microsoft\\CMake\\CMake\\bin\\cmake.exe" -} \ No newline at end of file + "cmake.cmakePath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\IDE\\CommonExtensions\\Microsoft\\CMake\\CMake\\bin\\cmake.exe", + "cmake.configureSettings": { + "BUILD_SIMULATOR": "ON" + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..6fc89f3 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,19 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "CMake: configure", + "type": "cmake", + "command": "configure", + "group": "build" + }, + { + "label": "CMake: build", + "type": "cmake", + "command": "build", + "dependsOn": "CMake: configure", + "dependsOrder": "sequence", + "group": "build" + } + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt index bf45427..f8b2837 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,105 +1,44 @@ -file(GLOB_RECURSE CORE_SOURCES CONFIGURE_DEPENDS "src/*.c") +cmake_minimum_required(VERSION 3.16) +project(Nova64 VERSION 1.0.0 LANGUAGES C) +option(BUILD_CORE "Build the Nova64 native core library" ON) +option(BUILD_ESP32 "Build the ESP32 firmware project" OFF) +option(BUILD_SIMULATOR "Build the C# simulator project" OFF) +set(SIMULATOR_PROJECT "simulator/Nova64Simulator.csproj" CACHE PATH "Path to the C# simulator .csproj or .sln relative to repository root") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -if(ESP_PLATFORM) - # -------------------------------------------------------------------------- - # 1. ESP-IDF BUILD MODE (Target: ESP32-P4) - # -------------------------------------------------------------------------- - message(STATUS "[Nova64] Building as ESP-IDF Component for ESP32...") +if(BUILD_CORE) + add_subdirectory(core) +endif() - idf_component_register( - SRCS - ${CORE_SOURCES} - INCLUDE_DIRS - "include" - REQUIRES - freertos - wamr - ) - -else() - # -------------------------------------------------------------------------- - # 2. DESKTOP BUILD MODE (Target: Windows .dll / Linux .so / macOS .dylib) - # -------------------------------------------------------------------------- - cmake_minimum_required(VERSION 3.16) - project(nova64_core VERSION 1.0.0 LANGUAGES C) - - message(STATUS "[Nova64] Building Desktop Shared Library...") - - set(CMAKE_C_STANDARD 11) - set(CMAKE_C_STANDARD_REQUIRED ON) - - # -------------------------------------------------------------------------- - # FreeRTOS Configuration - # -------------------------------------------------------------------------- - add_library(freertos_config INTERFACE) - - target_include_directories(freertos_config SYSTEM - INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR}/include - ) - - target_compile_definitions(freertos_config - INTERFACE - projCOVERAGE_TEST=0 - ) - - # -------------------------------------------------------------------------- - # FreeRTOS Kernel via FetchContent - # -------------------------------------------------------------------------- - include(FetchContent) - - # Download FreeRTOS-Kernel Repository - FetchContent_Declare( - FreeRTOS_Kernel - GIT_REPOSITORY https://github.com/FreeRTOS/FreeRTOS-Kernel.git - GIT_TAG V11.3.0 - ) - - if(WIN32) - set(FREERTOS_PORT "MSVC_MINGW" CACHE STRING "") +if(BUILD_ESP32) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/esp32/CMakeLists.txt") + add_subdirectory(esp32) else() - set(FREERTOS_PORT "GCC/POSIX" CACHE STRING "") + message(WARNING "BUILD_ESP32=ON but esp32/CMakeLists.txt is missing.") endif() - # Select FreeRTOS heap implementation (provides pvPortMalloc/vPortFree) - set(FREERTOS_HEAP 4 CACHE STRING "FreeRTOS Heap Implementation") - # Disable FreeRTOS Demos/Tests - set(BUILD_TESTING OFF CACHE BOOL "" FORCE) +endif() - # define Target 'freertos_kernel' - FetchContent_MakeAvailable(FreeRTOS_Kernel) - - # -------------------------------------------------------------------------- - # Nova64 Core Target - # -------------------------------------------------------------------------- - - # Shared Library (.dll / .so / .dylib) - add_library(nova64_core SHARED ${CORE_SOURCES}) - - target_include_directories(nova64_core PUBLIC - $ - ) - - # Link FreeRTOS Kernel to the nova64_core library - target_link_libraries(nova64_core PRIVATE freertos_kernel freertos_config) - - target_compile_definitions(nova64_core PRIVATE NOVA64_EXPORTS) - - if (WIN32) - set_target_properties(nova64_core PROPERTIES - C_VISIBILITY_PRESET hidden - VISIBILITY_INLINES_HIDDEN YES - PREFIX "" - ) - else() - set_target_properties(nova64_core PROPERTIES - C_VISIBILITY_PRESET hidden - VISIBILITY_INLINES_HIDDEN YES - ) +if(BUILD_SIMULATOR) + find_program(DOTNET_EXECUTABLE dotnet) + if(NOT DOTNET_EXECUTABLE) + message(FATAL_ERROR "BUILD_SIMULATOR requires the .NET SDK. Install dotnet or disable BUILD_SIMULATOR.") endif() - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + if(NOT SIMULATOR_PROJECT) + message(FATAL_ERROR "BUILD_SIMULATOR=ON requires SIMULATOR_PROJECT to point to the simulator .csproj or .sln relative to the repository root.") + endif() -endif() \ No newline at end of file + add_custom_target(simulator ALL + COMMAND "${DOTNET_EXECUTABLE}" build "${CMAKE_CURRENT_SOURCE_DIR}/${SIMULATOR_PROJECT}" /p:NativeLibDir="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/simulator" + COMMENT "Building C# simulator project" + ) + + if(BUILD_CORE) + add_dependencies(simulator nova64_core) + endif() +endif() diff --git a/README.md b/README.md index 3662044..0afc7b4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ * **Project Name:** Nova64 * **Architecture Model:** Dual-target modular system featuring a native execution core (`nova64_core`) running on top of **FreeRTOS**. * **Target Microcontroller:** **ESP32-P4** (RISC-V architecture) driving local display output, audio generation, custom expansion bus, and network interfaces. -* **Desktop Simulator / Tooling:** Native C core compiled as a shared library (`.dll` / `.so`) and driven by a **C# Host Application** via P/Invoke. Hardware dependencies are injected at runtime via function pointer callbacks (Dependency Injection pattern). +* **Desktop Simulator / Tooling:** Native C core compiled as a shared library (`.dll` / `.so`) and driven by a **Desktop Host Application** via FFI. Hardware dependencies are injected at runtime via function pointer callbacks (Dependency Injection pattern). * **Central Unit Input Constraint:** The base display unit **contains no (or only limited) built-in physical input controls** (no onboard buttons or D-pad). Control inputs are provided externally via connected cartridges, expansion modules, network interfaces, or desktop simulator inputs. --- @@ -21,6 +21,22 @@ --- +## 2.1 Storage & Volume Model +* **Internal System Store:** A dedicated internal non-removable storage volume holds the app launcher, system UI assets, status bar content, and core system resources. + * The launcher and persistent status bar always load from internal storage so they remain available even when no cartridge is present. + * This internal store is the trusted root for firmware updates, system apps, and a shared application bundle repository. +* **External Cartridge Volumes:** Each cartridge slot can expose storage as a removable volume, such as SDMMC media, flash-backed smart cartridge storage, or USB mass-storage from an attached peripheral. + * Cartridge insertion is detected dynamically; the runtime exposes each detected volume through the storage manager. + * Volumes are treated as detachable devices separate from the internal system store. +* **Namespace:** A custom volume namespace is preferred for clarity and platform identity. + * Example mapping: `SYS:` = internal system store, `EXA:` = cartridge slot 0, `EXB:` = cartridge slot 1, etc. +* **Access Semantics:** + * The app launcher and status overlay use the internal volume as their primary source. + * WASM applications may access external cartridge volumes via the exposed volume API, with explicit slot or volume identifier selection. + * Cartridges may support read-only system assets, writable data partitions, or secure application storage depending on their hardware capabilities. + +--- + ## 3. Networking Interface (10BASE-T1L) * **Protocol:** **10BASE-T1L** (Single-Pair Ethernet) for long-distance, industrial-grade point-to-point and networked communication between decks/modules. * **Physical Cabling:** routed through **audio-style connectors/cables** (e.g., 3.5mm/6.3mm jacks) to fit the cyberpunk aesthetic while maintaining robust single-pair data transmission. @@ -31,7 +47,7 @@ ## 4. WASM Application Runtime (WAMR) * **Runtime Engine:** **WAMR (WebAssembly Micro Runtime)** embedded directly into `nova64_core`. * **Execution Model:** Sandboxed application layer for dynamic software, games, and cartridge binaries. -* **Cross-Platform Parity:** Uncompiled WASM bytecode runs identically on both the physical ESP32-P4 hardware and the C# Desktop Simulator. +* **Cross-Platform Parity:** Uncompiled WASM bytecode runs identically on both the physical ESP32-P4 hardware and the Desktop Simulator. * **Host Bindings:** WAMR exports host functions bound to the internal `nova64_core` APIs, allowing sandboxed WASM applications to draw to the framebuffer, play audio, and read cartridge storage safely. --- diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt new file mode 100644 index 0000000..00dc88d --- /dev/null +++ b/core/CMakeLists.txt @@ -0,0 +1,108 @@ +file(GLOB_RECURSE CORE_SOURCES CONFIGURE_DEPENDS "src/*.c") + +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + cmake_minimum_required(VERSION 3.16) + project(nova64_core VERSION 1.0.0 LANGUAGES C) + + set(CMAKE_C_STANDARD 11) + set(CMAKE_C_STANDARD_REQUIRED ON) +endif() + + + +if(ESP_PLATFORM) + # -------------------------------------------------------------------------- + # 1. ESP-IDF BUILD MODE (Target: ESP32-P4) + # -------------------------------------------------------------------------- + message(STATUS "[Nova64] Building as ESP-IDF Component for ESP32...") + + idf_component_register( + SRCS + ${CORE_SOURCES} + INCLUDE_DIRS + "include" + REQUIRES + freertos + wamr + ) + +else() + # -------------------------------------------------------------------------- + # 2. DESKTOP BUILD MODE (Target: Windows .dll / Linux .so / macOS .dylib) + # -------------------------------------------------------------------------- + + message(STATUS "[Nova64] Building as Desktop Shared Library...") + + # -------------------------------------------------------------------------- + # FreeRTOS Configuration + # -------------------------------------------------------------------------- + add_library(freertos_config INTERFACE) + + target_include_directories(freertos_config SYSTEM + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/include + ) + + target_compile_definitions(freertos_config + INTERFACE + projCOVERAGE_TEST=0 + ) + + # -------------------------------------------------------------------------- + # FreeRTOS Kernel via FetchContent + # -------------------------------------------------------------------------- + include(FetchContent) + + # Download FreeRTOS-Kernel Repository + FetchContent_Declare( + FreeRTOS_Kernel + GIT_REPOSITORY https://github.com/FreeRTOS/FreeRTOS-Kernel.git + GIT_TAG V11.3.0 + ) + + if(WIN32) + set(FREERTOS_PORT "MSVC_MINGW" CACHE STRING "") + else() + set(FREERTOS_PORT "GCC/POSIX" CACHE STRING "") + endif() + # Select FreeRTOS heap implementation (provides pvPortMalloc/vPortFree) + set(FREERTOS_HEAP 4 CACHE STRING "FreeRTOS Heap Implementation") + # Disable FreeRTOS Demos/Tests + set(BUILD_TESTING OFF CACHE BOOL "" FORCE) + + # define Target 'freertos_kernel' + FetchContent_MakeAvailable(FreeRTOS_Kernel) + + # -------------------------------------------------------------------------- + # Nova64 Core Target + # -------------------------------------------------------------------------- + + # Shared Library (.dll / .so / .dylib) + add_library(nova64_core SHARED ${CORE_SOURCES}) + + target_include_directories(nova64_core PUBLIC + $ + ) + + # Link FreeRTOS Kernel to the nova64_core library + target_link_libraries(nova64_core PRIVATE freertos_kernel freertos_config) + + target_compile_definitions(nova64_core PRIVATE NOVA64_EXPORTS) + + if (WIN32) + set_target_properties(nova64_core PROPERTIES + C_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN YES + PREFIX "" + ) + else() + set_target_properties(nova64_core PROPERTIES + C_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN YES + ) + endif() + + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +endif() \ No newline at end of file diff --git a/include/FreeRTOSConfig.h b/core/include/FreeRTOSConfig.h similarity index 100% rename from include/FreeRTOSConfig.h rename to core/include/FreeRTOSConfig.h diff --git a/include/nova64_core.h b/core/include/nova64_core.h similarity index 100% rename from include/nova64_core.h rename to core/include/nova64_core.h diff --git a/src/nova64_core.c b/core/src/nova64_core.c similarity index 100% rename from src/nova64_core.c rename to core/src/nova64_core.c diff --git a/src/wasm_runner.c b/core/src/wasm_runner.c similarity index 100% rename from src/wasm_runner.c rename to core/src/wasm_runner.c diff --git a/esp32/.gitkeep b/esp32/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/simulator/Nova64Simulator.csproj b/simulator/Nova64Simulator.csproj new file mode 100644 index 0000000..146ae56 --- /dev/null +++ b/simulator/Nova64Simulator.csproj @@ -0,0 +1,30 @@ + + + + Exe + net8.0 + enable + enable + true + + + + $(NativeLibDir) + + + + + + + + + + + + + + + + + + diff --git a/simulator/Program.cs b/simulator/Program.cs new file mode 100644 index 0000000..662da8b --- /dev/null +++ b/simulator/Program.cs @@ -0,0 +1,42 @@ +using System; +using System.Runtime.InteropServices; + +internal static class Nova64Core +{ + private const string LibName = "nova64_core"; + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + public static extern bool nova64_init_io(IntPtr io_interface); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + public static extern int nova64_process_tick(uint delta_ms); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + public static extern uint nova64_get_version(); +} + +internal static class Program +{ + private static void Main() + { + Console.WriteLine("Nova64 simulator starting..."); + + try + { + var version = Nova64Core.nova64_get_version(); + Console.WriteLine($"Loaded nova64_core native library. Version: 0x{version:X}"); + } + catch (DllNotFoundException ex) + { + Console.WriteLine($"Native library not found: {ex.Message}"); + } + catch (EntryPointNotFoundException ex) + { + Console.WriteLine($"Native entry point missing: {ex.Message}"); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to initialize native library: {ex.Message}"); + } + } +}