From 394794cce0cf82e3cb7d70775e03c364d479ec09 Mon Sep 17 00:00:00 2001 From: shylie Date: Tue, 26 May 2026 05:59:38 -0400 Subject: [PATCH] Working version --- CMakeLists.txt | 16 ++- examples/CMakeLists.txt | 3 + examples/first/CMakeLists.txt | 8 ++ examples/first/first.c | 13 +++ include/ring-buffer.h | 22 +++++ include/user/card-os.h | 17 +++- src/card-os-link-user.ld | 39 ++++++++ src/card-os-link.ld | 13 ++- src/card-os-user.c | 47 ++++++++- src/card-os.c | 178 +++++++++++++++++++++++++++++++++- src/ring-buffer.c | 23 +++++ 11 files changed, 365 insertions(+), 14 deletions(-) create mode 100644 examples/CMakeLists.txt create mode 100644 examples/first/CMakeLists.txt create mode 100644 examples/first/first.c create mode 100644 include/ring-buffer.h create mode 100644 src/card-os-link-user.ld create mode 100644 src/ring-buffer.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d907035..fb9e069 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,13 +13,25 @@ add_executable(card-os src/card-os.c src/usb_descriptors.c src/display.c + src/ring-buffer.c ) target_include_directories(card-os PRIVATE include) -target_link_libraries(card-os PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_unique_id hardware_clocks hardware_spi) +target_link_libraries(card-os PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_unique_id hardware_clocks hardware_spi pico_multicore) pico_set_linker_script(card-os ${CMAKE_CURRENT_SOURCE_DIR}/src/card-os-link.ld) pico_add_extra_outputs(card-os) -add_library(card-os-user +add_library(card-os-user STATIC src/card-os-user.c ) target_include_directories(card-os-user PUBLIC include/user) +target_link_options(card-os-user PUBLIC -Wl,--script=${CMAKE_CURRENT_SOURCE_DIR}/src/card-os-link-user.ld -nostartfiles) + +function(card_os_finalize_user_program TARGET_NAME) + add_custom_command( + TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary $ $/${TARGET_NAME}.bin + COMMENT "Generating raw .bin file for ${TARGET_NAME}" + ) +endfunction() + +add_subdirectory(examples) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..7bd8ba8 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 4.0) + +add_subdirectory(first) diff --git a/examples/first/CMakeLists.txt b/examples/first/CMakeLists.txt new file mode 100644 index 0000000..ab575da --- /dev/null +++ b/examples/first/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 4.0) + +add_executable(first + first.c +) +target_link_libraries(first PUBLIC card-os-user) + +card_os_finalize_user_program(first) diff --git a/examples/first/first.c b/examples/first/first.c new file mode 100644 index 0000000..3fab595 --- /dev/null +++ b/examples/first/first.c @@ -0,0 +1,13 @@ +#include + +static volatile int value; + +int main(void) +{ + card_os_put_rect((card_os_rect){ + .r = 0, .g = 0, .b = 0, .x = 0, .y = 0, .w = 240, .h = 320 }); + card_os_put_rect((card_os_rect){ + .r = 0xFF, .g = 0xFF, .b = 0xFF, .x = 60, .y = 80, .w = 60, .h = 80 }); + + return 0; +} diff --git a/include/ring-buffer.h b/include/ring-buffer.h new file mode 100644 index 0000000..ba46c43 --- /dev/null +++ b/include/ring-buffer.h @@ -0,0 +1,22 @@ +#ifndef CARD_OS_RING_BUFFER +#define CARD_OS_RING_BUFFER + +#include "user/card-os.h" + +enum +{ + OS_RING_BUFFER_SIZE = 16 +}; + +typedef struct +{ + unsigned int write_index; + unsigned int read_index; + + os_message buffer[OS_RING_BUFFER_SIZE]; +} os_ring_buffer; + +int os_ring_buffer_write(volatile os_ring_buffer* ring_buffer, + const os_message* message); + +#endif // CARD_OS_RING_BUFFER diff --git a/include/user/card-os.h b/include/user/card-os.h index 88d187c..56bda63 100644 --- a/include/user/card-os.h +++ b/include/user/card-os.h @@ -3,12 +3,27 @@ #include +typedef enum +{ + OS_CMD_TERMINATE_PROGRAM, + OS_CMD_SBRK, + OS_CMD_DRAW_RECT +} os_command; + +typedef struct +{ + os_command command; + void* data; +} os_message; + +typedef void (*os_call_fn)(os_message*); + typedef struct { uint8_t r, g, b; uint16_t x, y, w, h; } card_os_rect; -void card_os_put_rect(const card_os_rect* rect); +void card_os_put_rect(card_os_rect rect); #endif // CARD_OS_USER diff --git a/src/card-os-link-user.ld b/src/card-os-link-user.ld new file mode 100644 index 0000000..af212f1 --- /dev/null +++ b/src/card-os-link-user.ld @@ -0,0 +1,39 @@ +ENTRY(_start) + +MEMORY +{ + RAM (rwx) : ORIGIN = 0x20000000 + 192k, LENGTH = 64k +} + +SECTIONS +{ + . = ORIGIN(RAM); + + .start : ALIGN(4) + { + KEEP(*(.start)) + } + + .text : ALIGN(4) + { + *(.text*) + } + + .rodata : ALIGN(4) + { + *(.rodata*) + } + + .data : ALIGN(4) + { + *(.data*) + } + + .bss (NOLOAD) : ALIGN(4) + { + __bss_start__ = .; + *(.bss*) + *(COMMON) + __bss_end__ = .; + } +} diff --git a/src/card-os-link.ld b/src/card-os-link.ld index 322d0f4..dd0b239 100644 --- a/src/card-os-link.ld +++ b/src/card-os-link.ld @@ -23,12 +23,16 @@ FLASH_SIZE = 8m; OSCALL_SIZE = 4k; +TOTAL_RAM_SIZE = 256k; +USER_RAM_SIZE = 64k; +KERNEL_RAM_SIZE = TOTAL_RAM_SIZE - USER_RAM_SIZE; MEMORY { FLASH(rx) : ORIGIN = 0x10000000, LENGTH = FLASH_SIZE - OSCALL_SIZE OSCALL(rx) : ORIGIN = 0x10000000 + FLASH_SIZE - OSCALL_SIZE, LENGTH = OSCALL_SIZE - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = KERNEL_RAM_SIZE + USER_RAM(rwx) : ORIGIN = 0x20000000 + KERNEL_RAM_SIZE, LENGTH = USER_RAM_SIZE SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k } @@ -145,12 +149,12 @@ SECTIONS . = ALIGN(4); . = ALIGN(4); - __oscall_start = .; .oscall : { + __oscall_start = .; KEEP(*(.oscall)) + __oscall_end = .; } > OSCALL - __oscall_end = .; . = ALIGN(4); .ram_vector_table (NOLOAD): { @@ -290,6 +294,9 @@ SECTIONS PROVIDE (_end = __end__); PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + PROVIDE(__user_ram_start = ORIGIN(USER_RAM)); + PROVIDE(__user_ram_end = ORIGIN(USER_RAM) + LENGTH(USER_RAM)); + /* Check if data + heap + stack exceeds RAM limit */ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") diff --git a/src/card-os-user.c b/src/card-os-user.c index 02745bd..046b34d 100644 --- a/src/card-os-user.c +++ b/src/card-os-user.c @@ -1,7 +1,48 @@ #include #include +#include -typedef void (*os_call_fn)(int call, const void* inptr, void* outptr); +const os_call_fn oscall + = (os_call_fn)(0x10000000 + 8 * 1024 * 1024 - 4096 + 1); -// address guaranteed by linker script for os -extern os_call_fn __oscall_start; +int _close(int file) { return -1; } + +off_t _lseek(int file, off_t ptr, int dir) { return 0; } + +ssize_t _read(int file, void* ptr, size_t len) { return 0; } + +ssize_t _write(int file, const void* ptr, size_t len) { return len; } + +void _exit(int status) +{ + oscall(&(os_message){ .command = OS_CMD_TERMINATE_PROGRAM, .data = NULL }); + while (1) + { + } +} + +void* _sbrk(ptrdiff_t incr) +{ + os_message msg = { .command = OS_CMD_SBRK, .data = &incr }; + oscall(&msg); + return msg.data; +} + +void card_os_put_rect(card_os_rect rect) +{ + oscall(&(os_message){ .command = OS_CMD_DRAW_RECT, .data = &rect }); +} + +extern uint8_t __bss_start__; +extern uint8_t __bss_end__; +int main(void); + +__attribute__((section(".start"))) void _start(void) +{ + for (uint8_t* p = &__bss_start__; p < &__bss_end__; p++) + { + *p = 0; + } + + _exit(main()); +} diff --git a/src/card-os.c b/src/card-os.c index 930040d..43bf21a 100644 --- a/src/card-os.c +++ b/src/card-os.c @@ -2,9 +2,12 @@ #include "card-os.h" #include "display.h" +#include "ring-buffer.h" #include +#include #include +#include #include #include @@ -14,6 +17,15 @@ const uint8_t DISPLAY_CS = 5; const uint8_t DISPLAY_DC = 4; spi_inst_t* const DISPLAY_SPI = spi0; +extern uint8_t __user_ram_start; + +typedef int (*user_program_fn)(void); +static volatile user_program_fn user_program; + +void core1_entry(void); +void os_task(void); +void os_handle_message(const os_message* msg, os_message* out); + int main(void) { gpio_set_function(DISPLAY_SCK, GPIO_FUNC_SPI); @@ -33,18 +45,146 @@ int main(void) tud_init(0); + user_program = NULL; + multicore_launch_core1(core1_entry); + while (true) { tud_task(); + os_task(); } } +static uint16_t program_length; +static uint16_t program_write_index; +static enum { + RECV_WAITING, + RECV_HIGH8_LENGTH, + RECV_LOW8_LENGTH, + RECV_PROGRAM +} recv_status = RECV_WAITING; void tud_vendor_rx_cb(uint8_t itf, const uint8_t* buffer, uint16_t bufsize) { - if (buffer[0] == 0x99) + if (buffer[0] == 0x99 && recv_status == RECV_WAITING) { rom_reset_usb_boot(0, 0); } + else + { + for (int bufidx = 0; bufidx < bufsize; bufidx++) + { + switch (recv_status) + { + case RECV_WAITING: + program_length = 0; + program_write_index = 0; + recv_status = RECV_HIGH8_LENGTH; + break; + + case RECV_HIGH8_LENGTH: + display_put_rect(0, 0, 0xFF, 0, 0, 240, 320); + program_length |= buffer[bufidx]; + program_length <<= 8; + recv_status = RECV_LOW8_LENGTH; + break; + + case RECV_LOW8_LENGTH: + display_put_rect(0xFF, 0, 0, 0, 0, 240, 320); + program_length |= buffer[bufidx]; + recv_status = RECV_PROGRAM; + break; + + case RECV_PROGRAM: + (&__user_ram_start)[program_write_index++] = buffer[bufidx]; + if (program_write_index == program_length) + { + display_put_rect(0, 0xFF, 0, 0, 0, 240, 320); + __dmb(); + user_program = (user_program_fn)((uintptr_t)&__user_ram_start | 1); + __sev(); + recv_status = RECV_WAITING; + } + break; + } + } + } +} + +static volatile os_ring_buffer core0_buffer + = { .read_index = 0, .write_index = 0 }; +static volatile os_ring_buffer core1_buffer + = { .read_index = 0, .write_index = 0 }; + +void core1_entry(void) +{ + display_put_rect(0xFF, 0, 0xFF, 0, 0, 240, 320); + + while (!user_program) + { + __wfe(); + } + + user_program(); + + // send message to terminate core 1 + int index = -1; + while (index < 0) + { + index = os_ring_buffer_write(&core1_buffer, + &(os_message){ .command = 1, .data = NULL }); + } + multicore_fifo_push_blocking(index); + + // stall until reset + while (true) + { + } +} + +// runs on core 0 +void os_task(void) +{ + if (multicore_fifo_rvalid()) + { + uint32_t index = multicore_fifo_pop_blocking(); + os_message msg = core1_buffer.buffer[index]; + core1_buffer.read_index + = (core1_buffer.read_index + 1) % OS_RING_BUFFER_SIZE; + os_message out; + os_handle_message(&msg, &out); + out.command = msg.command; + int wrote_index = -1; + while (wrote_index < 0) + { + wrote_index = os_ring_buffer_write(&core0_buffer, &out); + } + multicore_fifo_push_blocking(wrote_index); + } +} + +extern uint8_t __end__; +extern uint8_t __StackLimit; + +static uint8_t* heap_end; +void os_sbrk(const ptrdiff_t* incr, void** out) +{ + if (!heap_end) + { + heap_end = &__end__; + } + + uint8_t* prev = heap_end; + uint8_t* next = heap_end + *(ptrdiff_t*)incr; + + if (next >= &__StackLimit || next < &__end__) + { + *out = (void*)-1; + } + else + { + heap_end = next; + *out = prev; + } } void os_put_rect(const card_os_rect* rect) @@ -53,12 +193,40 @@ void os_put_rect(const card_os_rect* rect) rect->h); } -static __attribute__((section(".oscall"))) void -oscall(int call, const void* inptr, void* outptr) +void os_handle_message(const os_message* msg, os_message* out) { - switch (call) + switch (msg->command) { - case 0: + case OS_CMD_TERMINATE_PROGRAM: + multicore_fifo_drain(); + multicore_reset_core1(); + break; + case OS_CMD_SBRK: + os_sbrk(msg->data, &out->data); + break; + case OS_CMD_DRAW_RECT: + os_put_rect(msg->data); break; } } + +// this should run on core 1 +__attribute__((section(".oscall"), noinline, used)) void +oscall(os_message* message) +{ + os_message local_msg = *message; + + // send command + int index = -1; + while (index < 0) + { + index = os_ring_buffer_write(&core1_buffer, &local_msg); + } + multicore_fifo_push_blocking(index); + + // receive response + index = multicore_fifo_pop_blocking(); + *message = core0_buffer.buffer[index]; + core0_buffer.read_index + = (core0_buffer.read_index + 1) % OS_RING_BUFFER_SIZE; +} diff --git a/src/ring-buffer.c b/src/ring-buffer.c new file mode 100644 index 0000000..53d2af5 --- /dev/null +++ b/src/ring-buffer.c @@ -0,0 +1,23 @@ +#include "ring-buffer.h" + +#include + +int os_ring_buffer_write(volatile os_ring_buffer* ring_buffer, + const os_message* message) +{ + if ((ring_buffer->write_index + 1) % OS_RING_BUFFER_SIZE + == ring_buffer->read_index) + { + return -1; + } + + __compiler_membar(); + ring_buffer->buffer[ring_buffer->write_index] = *message; + + int index = ring_buffer->write_index; + + ring_buffer->write_index + = (ring_buffer->write_index + 1) % OS_RING_BUFFER_SIZE; + + return index; +}