Spent a session reading AtomVM’s source tree and build docs to answer: what would it take to run the latest AtomVM main branch on this chip? Project page lives at /projects/68_atomvm_port. This is the working notes.
The thing I expected to be a problem wasn’t
Going in I assumed AtomVM was an ARM/Xtensa project and the RV32 port would be the bulk of the work. It’s not. The build docs explicitly list the Pico 2 RISC-V target:
cmake .. -G Ninja -DPICO_BOARD=pico2 -DPICO_PLATFORM=rp2350-riscv
The RP2350’s Hazard3 is RV32IMAC + Zba + Zbb + Zbs + Zicsr + Zifencei. Our chip is RV32IMA + Zba + Zbb-essentials + Zbb rotates + Zicsr + Zifencei + Zicntr. The deltas:
- they have C (compressed). We don’t. Not required at runtime — Pico’s RISC-V build doesn’t even use it (Hazard3 supports Zcb/Zcmp instead).
- they have Zbs (single-bit). We don’t. AtomVM doesn’t require it.
- both have F/D off in the default Pico build, and AtomVM
exposes
AVM_DISABLE_FP=ONas a first-class option.
So the ISA story is “build with FP off, accept slower codegen without C, ship.” No CPU work.
The thing I expected to be easy was easy
src/platforms/rp2/src/main.c is short. Banner print, two
fixed flash addresses for LIB_AVM and MAIN_AVM, AVMPack
discovery, globalcontext_run(). The pattern maps 1:1 onto
how P43 loads FreeRTOS — fixed addresses, no filesystem.
sys.c calls into the Pico SDK for time
(get_absolute_time/to_us_since_boot), atomics, mutexes,
condvars, queues. Single-hart with AVM_DISABLE_SMP=ON
collapses most of that to no-ops. The remaining real
dependency is “read mtime, sleep until X, putc to UART” —
all of which we already have in P43’s port adapter.
The thing I didn’t think about that’s now the actual blocker
Heap. The AtomVM runtime mallocs. P43’s FreeRTOS port uses
FreeRTOS heap_4 for application allocs, but AtomVM doesn’t
ship with its own allocator AFAICT — it uses libc malloc /
free, which means newlib’s _sbrk has to be wired to a
linker-defined free-RAM region. We’ve done that pattern before
but it’ll need its own pass.
Also unknown: the full set of newlib syscalls AtomVM exercises.
_write and _sbrk are the obvious ones. _gettimeofday is
called from sys.c. Beyond that I’d want to actually link
against newlib and watch what comes up undefined. Not a
surprise just an item.
Two paths considered, recommended the cheap one
- A. Bare-metal AtomVM port modeled on
rp2/— replace Pico SDK shims with our MMIO. ~3 days end-to-end. - B. Build AtomVM as a Linux userspace
.elfand run it through P59’s Linux boot path. Correct in the long run. Blocked on us not having a real RV32 Linux userspace toolchain set up (glibc/musl, real initramfs). That’s a separate scoped project.
Recommended A.
Benchmark hookup
The other agent is doing the benchmark JSON ingestion in parallel. Tried not to step on that — proposed three workloads (fib(35), ping-pong, ETS r/w) and a UART shape compatible with the cycle-count fields P63 already emits. Specifics on the project page; the JSON keys are placeholders pending whatever the benchmark agent actually ships.
The interesting data point isn’t going to be raw speed (BEAM will eat C alive on cycles per useful work). It’s going to be “two-process message-passing throughput on a chip with no FPU, no JIT, no SMP, single-issue” — a metric that has no equivalent in the FreeRTOS-or-C world.
Decision items for the user
Listed at the bottom of the project page:
- Do we want this at all? Demo, not architectural progress.
- Path A or B? Recommendation: A.
- Where in the roadmap? Probably after P67 (synthesis baseline) so it lands on a chip with measured fmax.
Handing off here — no code, no commit, just the plan.