commit 2f48b3efc891a4f8c78315ee8a6a2ca2e04ee8aa Author: Lukas Höppner Date: Sun Aug 9 15:02:21 2026 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5b79a54 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +.cache/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a15e8d5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "cmake.generator": "Ninja", + "cmake.buildDirectory": "${workspaceFolder}/build", + "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 diff --git a/CARTRIDGE_PINOUT.md b/CARTRIDGE_PINOUT.md new file mode 100644 index 0000000..f996151 --- /dev/null +++ b/CARTRIDGE_PINOUT.md @@ -0,0 +1,107 @@ +# Nova64 Cartridge Pinout Overview + +This document provides a compact, high-level technical view of the Nova64 cartridge connector from the cartridge developer perspective. + +## Purpose + +A concise 32-pin cartridge interface for expansion modules, storage, I/O, and optional power delivery. + +## Connector Goals + +- single edge connector for compact form factor +- separate power, data, and control signals +- support for smart cartridges and passive media +- keep SDMMC always available for cartridge-level storage access +- leave space for future expansion without extra pins +- describe pin numbering and signal roles from the cartridge edge view + +## 32-Pin Layout + +| Pin | Signal | Role | Default idle state | +| --: | ------------- | --------------------------------------- | ------------------ | +| 1 | GND | ground | grounded | +| 2 | VCC_3V3 | supply | N/A | +| 3 | CARTRIDGE_DET | cartridge presence detect | pull-up | +| 4 | POWER_CTRL | power direction control | pull-down | +| 5 | USB_FLAG | USB-capable flag | pull-up | +| 6 | USB_DP | USB D+ | pull-down | +| 7 | USB_DM | USB D- | pull-down | +| 8 | USB_ID | USB host/device mode | pull-up | +| 9 | USB_VBUS | VBUS sense / optional power | pull-down | +| 10 | SD_CMD | SDMMC command / host->cartridge control | pull-up | +| 11 | SD_CLK | SDMMC clock / host->cartridge | pull-down | +| 12 | SD_D0 | SDMMC data0 (bi-directional) | pull-up | +| 13 | SD_D1 | SDMMC data1 (bi-directional) | pull-up | +| 14 | SD_D2 | SDMMC data2 (bi-directional) | pull-up | +| 15 | SD_D3 | SDMMC data3 (bi-directional) | pull-up | +| 16 | I2C_SCL | I2C clock | pull-up | +| 17 | I2C_SDA | I2C data | pull-up | +| 18 | I2S_SCLK | I2S bit clock | pull-down | +| 19 | I2S_WS | I2S word select / frame clock | pull-down | +| 20 | I2S_SDOUT | I2S data out (cartridge->host) | pull-down | +| 21 | I2S_SDIN | I2S data in (host->cartridge) | pull-down | +| 22 | I2S_MCLK | I2S master clock | pull-down | +| 23 | SPI_MOSI | SPI MOSI (host->cartridge) | pull-down | +| 24 | SPI_MISO | SPI MISO (cartridge->host) | pull-down | +| 25 | SPI_SCLK | SPI clock (host->cartridge) | pull-down | +| 26 | SPI_CS0 | SPI chip select (host->cartridge) | pull-down | +| 27 | CAN_H | CAN high | recessive bias | +| 28 | CAN_L | CAN low | recessive bias | +| 29 | UART_RX | UART RX (host->cartridge) | pull-up | +| 30 | UART_TX | UART TX (cartridge->host) | pull-up | +| 31 | VCC_5V | supply | N/A | +| 32 | GND | ground | grounded | + +## Signal Groups + +- Ground: pins 1, 32 +- 3.3V supply: pin 2 +- Cartridge detection: pin 3 +- Power direction: pin 4 +- USB flag: pin 5 +- USB: pins 6-9 +- SDMMC: pins 10-15 +- I2C: pins 16-17 +- I2S audio: pins 18-22 +- SPI: pins 23-26 +- CAN: pins 27-28 +- UART: pins 29-30 +- 5V supply: pin 31 + +## Design Rationale + +- Keep storage and interface signals separate from power. +- Reserve the SDMMC channel so cartridges can provide their own software/data layer. +- Include USB and serial buses for smart module support. +- Use a dedicated ID input for simple cartridge recognition. +- Provide optional audio and GPIO for versatile cartridge types. + +## Notes + +- This is a high-level connector map, not a full electrical specification. +- Exact pin assignments may be refined later during hardware design. +- Preferred placement for pull-ups / pull-downs is the main device, with cartridge-side resistors only used for optional or cartridge-specific functions. +- Cartridge presence should be detected via a dedicated `CARTRIDGE_DET` pin, not by ORing multiple ID signals. +- Cartridge features such as SD/storage, I2C, SPI, CAN, UART and audio should be discovered dynamically at runtime after insertion. +- For bidirectional power delivery, the system should use a dedicated power-path controller and a clear source priority scheme. + - Monitor main device and cartridge voltage presence before enabling any power path. + - Use POWER_CTRL as a control input for a power-path switch or enable pin, not as a current-carrying line. + - If the main device is powered and the cartridge is not actively supplying power, keep cartridge supply disabled. + - If the main device is unpowered and a powered cartridge is inserted, allow the cartridge to supply the system after voltage stability is confirmed. + - Prevent backfeed by using ideal diodes or bidirectional power-path ICs that only conduct from the active source. + +Suggested cartridge categories: + +| Category | Meaning | +| ----------------: | ------------------------------------------------------------- | +| software only | cartridge provides software/application data only | +| special hardware | cartridge includes additional hardware functions | +| dynamic detection | actual capabilities are determined at runtime after insertion | + +USB_FLAG = 1 indicates the cartridge can present USB functionality in addition to its category. + +POWER_CTRL = 1 indicates the cartridge provides power to the main device + +--- + +A short technical reference for the Nova64 cartridge connector, intended for initial design discussion. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bf45427 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,105 @@ +file(GLOB_RECURSE CORE_SOURCES CONFIGURE_DEPENDS "src/*.c") + + + +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) + # -------------------------------------------------------------------------- + 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 "") + 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/README.md b/README.md new file mode 100644 index 0000000..3662044 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# Nova64 Cyberdeck Platform - High-Level System Specification + +## 1. System Overview & Core Concept +* **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). +* **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. + +--- + +## 2. Physical Cartridge & Expansion Slot Architecture +* **Mechanical Interface:** Uses a 32-pin edge-connector format (Game Boy style form factor, required PCB thickness: 1.2 mm). +* **Poka-Yoke Protection:** Custom mechanical keying (notches/grooves) to physically prevent legacy/original Game Boy cartridges from being inserted and damaging the 3.3V logic lines. +* **Bus Protocols & Interfaces:** + * **SD Card Interface (SDMMC):** Dedicated high-speed lines. *Rule: SD pins must remain allocated and accessible across all slot modes. This allows loading custom cartridge software for specialized cartridges.* + * **USB:** Native USB Host / Device capability for smart cartridges or peripherals. + * **I2C, SPI & CAN-Bus:** Serial buses for sensors, co-processors, and expanders. + * **Cartridge pinout reference:** Detailed connector numbering, signal roles, and idle states are defined in [CARTRIDGE_PINOUT.md](./CARTRIDGE_PINOUT.md) to keep this document as the single high-level system spec. + * **Power Bus:** Supports dual-directional power delivery (supplying power to cartridges or receiving alternative system power/charging from external battery cartridges). + +--- + +## 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. +* **Audio Use:** the same 10BASE-T1L connector is also intended to carry analog audio signals in some modes, requiring dedicated isolation and protection circuitry to separate audio from data and to protect the network interface. + +--- + +## 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. +* **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. + +--- + +## 5. Software HAL & FreeRTOS Architecture +* **Hardware Abstraction (I/O Callbacks):** + * Core engine defines function pointer contracts: `display_flush`, `audio_output`, `sd_read_sector`, and `cartridge_status` (with `slot_idx` support for multi-slot setups). + * System initialized via `nova64_init_io()`. + +--- + +## 6. Display, Framebuffer & Core Allocation Strategy +* **Dual-Core Processor Allocation (ESP32-P4):** + * **Core 0 (System & I/O Core):** Handles background FreeRTOS tasks, hardware drivers, 10BASE-T1L networking stack, audio generation, and system status bar overlays. + * **Core 1 (Execution Core):** Exclusively dedicated to running the WAMR WebAssembly engine and application code, guaranteeing deterministic performance and preventing OS tasks from causing frame drops. +* **Framebuffer Architecture:** + * Uses double-buffering (RGB565 format) to prevent screen tearing during active rendering. + * Framebuffers are explicitly allocated in **External PSRAM via the AXI bus**, enabling direct DMA (Direct Memory Access) streaming to the MIPI-DSI controller without CPU overhead. + * Application output and system UI are composited into the target buffer before triggering the host-injected `display_flush` callback (or VSYNC pointer swap). +* **Persistent System Status Bar:** + * A reserved hardware/system UI region at the top of the display rendered independently by Core 0. + * Displays active cartridge ID, 10BASE-T1L link status, battery levels, and system health metrics without interfering with running WASM applications. \ No newline at end of file diff --git a/include/FreeRTOSConfig.h b/include/FreeRTOSConfig.h new file mode 100644 index 0000000..8594e51 --- /dev/null +++ b/include/FreeRTOSConfig.h @@ -0,0 +1,37 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/* Desktop Simulator Settings */ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 64 * 1024 ) ) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 + +/* Synchronisation Objects */ +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_QUEUE_SETS 1 + +/* Memory Management */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 0 + +/* Disable API Functions */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 + +#endif /* FREERTOS_CONFIG_H */ \ No newline at end of file diff --git a/include/nova64_core.h b/include/nova64_core.h new file mode 100644 index 0000000..58bf598 --- /dev/null +++ b/include/nova64_core.h @@ -0,0 +1,106 @@ +#ifndef NOVA64_CORE_H +#define NOVA64_CORE_H + +#include +#include + +// Cross-platform DLL export/import visibility macros +#if defined(_WIN32) || defined(__CYGWIN__) +#ifdef NOVA64_EXPORTS +#define NOVA64_API __declspec(dllexport) +#else +#define NOVA64_API __declspec(dllimport) +#endif +#else +#if __GNUC__ >= 4 +#define NOVA64_API __attribute__((visibility("default"))) +#else +#define NOVA64_API +#endif +#endif + +/* ========================================================================== */ +/* I/O Callback Typedefs */ +/* ========================================================================== */ + +/** + * @brief Callback to flush a frame buffer to the display. + * @param buffer Pointer to raw pixel data (e.g., RGB565 / RGBA8888). + * @param width Frame width in pixels. + * @param height Frame height in pixels. + */ +typedef void (*nova64_display_flush_cb_t)(const uint16_t *buffer, + uint16_t width, uint16_t height); + +/** + * @brief Callback to output audio samples. + * @param samples Pointer to PCM audio sample buffer. + * @param count Number of samples in the buffer. + */ +typedef void (*nova64_audio_output_cb_t)(const int16_t *samples, + uint32_t count); + +/** + * @brief Callback to read sectors from the SD card. + * @param sector_idx The zero-based sector index to read. + * @param destination_buffer Pointer to memory where sector data should be + * copied. + * @param sector_count Number of 512-byte sectors to read. + * @return True on success, false on read error. + */ +typedef bool (*nova64_sd_read_sector_cb_t)(uint32_t sector_idx, + uint8_t *destination_buffer, + uint32_t sector_count); + +/** + * @brief Callback triggered when a cartridge state change occurs (e.g. + * inserted/removed). + * @param slot_idx Zero-based cartridge slot index. + * @param is_inserted True if a cartridge is detected, false if ejected. + */ +typedef void (*nova64_cartridge_status_cb_t)(uint32_t slot_idx, + bool is_inserted); + +/* ========================================================================== */ +/* I/O Interface Configuration Struct */ +/* ========================================================================== */ + +/** + * @brief Struct containing all I/O hardware abstraction callbacks. + * Pass NULL for any unneeded callback. + */ +typedef struct { + nova64_display_flush_cb_t display_flush; + nova64_audio_output_cb_t audio_output; + nova64_sd_read_sector_cb_t sd_read_sector; + nova64_cartridge_status_cb_t cartridge_status; +} nova64_io_interface_t; + +/* ========================================================================== */ +/* Engine Core API */ +/* ========================================================================== */ + +/** + * @brief Initializes the core engine and registers host I/O interface + * callbacks. + * @param io_interface Pointer to filled struct containing I/O function + * pointers. + * @return True if initialized successfully, false if already initialized or + * invalid. + */ +NOVA64_API bool nova64_init_io(const nova64_io_interface_t *io_interface); + +/** + * @brief Executes one engine processing tick. + * @param delta_ms Elapsed time in milliseconds since the last tick. + * @return 0 on success, negative error code on failure. + */ +NOVA64_API int32_t nova64_process_tick(uint32_t delta_ms); + +/** + * @brief Retrieves the engine version integer. + * @return 24-bit packed version number (0xMMmmPP -> Major, Minor, Patch). + */ +NOVA64_API uint32_t nova64_get_version(void); + +#endif // NOVA64_CORE_H \ No newline at end of file diff --git a/src/nova64_core.c b/src/nova64_core.c new file mode 100644 index 0000000..4e56401 --- /dev/null +++ b/src/nova64_core.c @@ -0,0 +1,76 @@ +#include "nova64_core.h" +#include "FreeRTOS.h" +#include "queue.h" +#include "task.h" +#include + +#if defined(ESP_PLATFORM) +/* ESP32-spezifische Header für Low-Power & Watchdog */ +#include "esp_pm.h" +#include "esp_rom_sys.h" +#include "esp_task_wdt.h" +#elif defined(_WIN32) +/* Windows API für Schlafen im Desktop-Thread */ +#include +#else +/* POSIX / Linux / macOS Sleep */ +#define _POSIX_C_SOURCE 199309L +#include +#endif + +static bool is_initialized = false; +static QueueHandle_t event_queue = NULL; + + +NOVA64_API bool nova64_init_io(const nova64_io_interface_t *io_interface) { + printf("[Nova64 Core] System Initializing...\n"); + + event_queue = xQueueCreate(10, sizeof(uint32_t)); + + is_initialized = true; + return true; +} + +NOVA64_API int32_t nova64_process_tick(uint32_t delta_ms) { + if (!is_initialized) + return -1; + // Core Game-Logic & State Machine Ticks + return 0; // OK +} + +NOVA64_API uint32_t nova64_get_version(void) { + return 0x010000; // v1.0.0 +} + +/* FreeRTOS hook: called by the kernel when the idle task runs. + * Required because configUSE_IDLE_HOOK is enabled in FreeRTOSConfig.h + */ +void vApplicationIdleHook(void) { +#if defined(ESP_PLATFORM) + + // ------------------------------------------------------------------------- + // ESP32-specific idle hook code + // ------------------------------------------------------------------------- +#if CONFIG_ESP_TASK_WDT + // Feed the watchdog to prevent reset + esp_task_wdt_reset(); +#endif + asm volatile("wfi"); // Wait for interrupt to save power + +#elif defined(_WIN32) + + // ------------------------------------------------------------------------- + // Windows-specific idle hook code + // ------------------------------------------------------------------------- + Sleep(1); // Sleep for 1 millisecond to yield CPU + +#else + + // ------------------------------------------------------------------------- + // POSIX-specific idle hook code + // ------------------------------------------------------------------------- + struct timespec ts = {0, 1000000}; // 1 millisecond + nanosleep(&ts, NULL); + +#endif +} \ No newline at end of file diff --git a/src/wasm_runner.c b/src/wasm_runner.c new file mode 100644 index 0000000..e69de29