No. 78 / project of 147 on the ladder

AtomVM input IRQ mailbox bridge

introduces — IRQ-driven sys_poll_events FIFO drain; Erlang input mailbox messages; subscribed game process

harden statelast run2026-05-05
signoff
  • DRCNOT RUN
  • LVSNOT RUN
  • antennaNOT RUN

P77 proved that host input can raise machine external IRQ and return cleanly through the bare-metal trap handler. P78 moves the delivery point into AtomVM: the platform’s sys_poll_events notices the input IRQ counter, drains the FIFO, and sends each event to the subscribed Erlang process as {input, Event}.

P78 AtomVM input IRQ mailbox bridge starting
rendered frames: 1
input events: 6
input mailbox events: 6
input mailbox delivered: 6
input irq count: 2
input irq seen: true
input fifo status: 0
P78 AtomVM input IRQ mailbox bridge PASS

What changed

The game server calls chip:input_subscribe/0 from its own process. That records the process id in platform data. When sys_poll_events runs and sees the P77 trap counter change, it drains the MMIO FIFO and uses globalcontext_send_message to enqueue one {input, Event} tuple per host control.

layernew behavior
platform NIFchip:input_subscribe/0 picks the mailbox target
scheduler wait hooksys_poll_events treats the input IRQ count as a wake condition
platform deliveryFIFO words become Erlang {input, Event} messages
game loopTetris handles input in its receive loop instead of polling the FIFO
observabilitychip:input_mailbox_count/0 reports delivered messages

The scripted smoke queued six controls. The harness delivered all six, the trap handler saw input IRQ, sys_poll_events delivered six mailbox messages, the FIFO returned to 0, and the run halted PASS after 15,456,265 post-load cycles.

Limit

This is still a project-specific platform bridge. It is not the generic AtomVM listener/port-driver model, and it still busy-polls mtime for ordinary timeouts. The important proof is narrower but useful: host controls can become normal Erlang messages on the chip.

Verification

cd projects/78_atomvm_irq_mailbox/test
make all
make verilator-run-input-smoke
SDL_VIDEODRIVER=dummy uv run --with pygame --with pillow ../viewer.py \
  captured/frames/frame_0000.bin 128 96 --scale 4 \
  --png captured/p78-irq-mailbox-smoke-frame.png

Honest Status

checkstatus
AtomVM input IRQ mailbox bridge startsPASS
Host FIFO input reaches harnessPASS
FIFO-not-empty input IRQ reaches M-mode trap handlerPASS
sys_poll_events drains FIFO after input IRQPASS
Erlang game server receives {input, Event} messagesPASS
chip:input_mailbox_count/0 reports delivered messagesPASS
Tetris framebuffer rendersPASS
Scripted quit via mailbox inputPASS
Generic AtomVM listener/port-driver integrationNOT RUN
F/D architectural complianceNOT RUN
LibreLane hardeningNOT RUN

What just happened?

The viewer-to-chip control path now ends in the shape we wanted for the game: a running Erlang process receives input messages. That makes the interactive demo much less fake, while keeping the remaining AtomVM driver work clearly scoped.