journal 2026-05-04

AtomVM research — can our chip run BEAM bytecode?

p68atomvmbeamerlangelixirresearchplanning

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:

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.

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:

  1. Do we want this at all? Demo, not architectural progress.
  2. Path A or B? Recommendation: A.
  3. 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.