Working version

This commit is contained in:
shylie 2026-05-26 05:59:38 -04:00
parent f28aba370b
commit 394794cce0
Signed by: shylie
GPG Key ID: 20C8D70580687D9D
11 changed files with 365 additions and 14 deletions

View File

@ -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_FILE:${TARGET_NAME}> $<TARGET_FILE_DIR:${TARGET_NAME}>/${TARGET_NAME}.bin
COMMENT "Generating raw .bin file for ${TARGET_NAME}"
)
endfunction()
add_subdirectory(examples)

3
examples/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 4.0)
add_subdirectory(first)

View File

@ -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)

13
examples/first/first.c Normal file
View File

@ -0,0 +1,13 @@
#include <card-os.h>
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;
}

22
include/ring-buffer.h Normal file
View File

@ -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

View File

@ -3,12 +3,27 @@
#include <stdint.h>
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

39
src/card-os-link-user.ld Normal file
View File

@ -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__ = .;
}
}

View File

@ -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
__oscall_end = .;
} > OSCALL
. = 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")

View File

@ -1,7 +1,48 @@
#include <card-os.h>
#include <stddef.h>
#include <stdio.h>
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());
}

View File

@ -2,9 +2,12 @@
#include "card-os.h"
#include "display.h"
#include "ring-buffer.h"
#include <hardware/spi.h>
#include <hardware/sync.h>
#include <pico/bootrom.h>
#include <pico/multicore.h>
#include <pico/stdlib.h>
#include <tusb.h>
@ -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;
}

23
src/ring-buffer.c Normal file
View File

@ -0,0 +1,23 @@
#include "ring-buffer.h"
#include <sys/cdefs.h>
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;
}