P40 made a clean foundation; P41 builds on it. FreeRTOS-Kernel V11.1.0 now links cleanly against our chip via a small port adapter.
The compile-only rung was deliberate: FreeRTOS bring-up has a chain of “did the port work?” questions and we want each rung to fail in exactly one place if it fails. P41 covers “does it build and link?”; P42 (next) covers “does scheduling actually work?”.
Three places the port had to deviate from the upstream RISC-V port:
-
32-bit mtime/mtimecmp. The upstream
vPortSetupTimerInterruptwrites a 64-bit*pullMachineTimerCompareRegister. Our DUT only has a 32-bitmtimecmpat0x10000004. A 64-bit store would step on a non-existent0x10000008. Disabled the upstream default viaconfigMTIMECMP_BASE_ADDRESS = 0and provided ours. -
freertos_risc_v_application_interrupt_handler. WithportasmHAS_MTIME = 0, the upstream port routes all interrupts through this user hook. Mine dispatches on mcause: machine timer updates the deadline and callsxTaskIncrementTick/vTaskSwitchContext; anything else halts loudly. -
Freestanding libc. The Arch
riscv64-elf-gccdoesn’t ship newlib - just freestanding headers. FreeRTOS uses<stdlib.h>(forsize_t) and<string.h>(memset/memcpy/etc). Header shims underport/freestanding-shims/plus byte-loop implementations inport/p41_libc.c.
ELF: 13 KiB text, 12 B data, 16 KiB bss (mostly the FreeRTOS heap). About 30 KiB total. Comfortable in our 256 KiB external memory.
The trap-frame work in P40 paid off here. FreeRTOS’s portContext.h
expects a 32-word context with mcause/mepc at the end - which is
exactly the shape P40 built. The IRQ save/restore primitives I wrote
for P40 satisfy what FreeRTOS’s portmacro.h wants. None of this is
coincidence - P40’s trap frame was designed reading FreeRTOS’s port,
so this part should drop in cleanly.
It does. P42 next will tell us whether the scheduler actually schedules.