Working version
This commit is contained in:
parent
f28aba370b
commit
394794cce0
@ -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
3
examples/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 4.0)
|
||||
|
||||
add_subdirectory(first)
|
||||
8
examples/first/CMakeLists.txt
Normal file
8
examples/first/CMakeLists.txt
Normal 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
13
examples/first/first.c
Normal 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
22
include/ring-buffer.h
Normal 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
|
||||
@ -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
39
src/card-os-link-user.ld
Normal 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__ = .;
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
178
src/card-os.c
178
src/card-os.c
@ -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
23
src/ring-buffer.c
Normal 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;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user