journal 2026-05-05

P83 TCC RV32 on chip

P83 tried the actual RV32 TinyCC path. Upstream TinyCC in Nix only had a riscv64 backend, but TinyCC’s own USES file pointed at sellicott/tcc-riscv32. That fork has riscv32-gen.c, riscv32-link.c, and riscv32-asm.c, so we pinned commit de6f179e17d804541d6984bb9f3237c7ec9a6b78.

The userspace build packages a static RV32 /bin/tcc into the BusyBox initramfs. The first generated program hung because GCC-style register variables did not actually load the Linux syscall registers before ecall. Disassembly showed stack stores followed by ecall, then the final spin loop. Switching the sample source to explicit RISC-V inline assembly fixed it.

Passing guest commands:

tcc -static -nostdlib -o /tmp/p83_tcc_hello /usr/share/p83/tcc_hello.c
chmod +x /tmp/p83_tcc_hello
/tmp/p83_tcc_hello

The generated executable printed:

P83-TCC-COMPILED-ON-CHIP

Verification:

make -C projects/83_tcc_riscv32_on_chip/userspace
cd /mnt/MediaVolume/home/jadams/src/linux-rv32-build/linux-6.12.85
./scripts/config --set-str INITRAMFS_SOURCE /mnt/MediaVolume/home/jadams/src/gitlab.daringbit.com/josh/librelane-playground/projects/83_tcc_riscv32_on_chip/userspace/initramfs.cpio
make ARCH=riscv olddefconfig
make ARCH=riscv -j$(nproc) Image
cd /mnt/MediaVolume/home/jadams/src/gitlab.daringbit.com/josh/librelane-playground
make -C projects/83_tcc_riscv32_on_chip/test tty-smoke KERNEL_IMAGE=/mnt/MediaVolume/home/jadams/src/linux-rv32-build/linux-6.12.85/arch/riscv/boot/Image

Honest status: tty-smoke is PASS. Normal main plus libc headers is NOT RUN. LibreLane hardening is NOT RUN.

Next project should be profiling. We now have a real workload worth explaining with cycle markers, PC samples, and a flamegraph-style view.