P76 made host input practical by batching the MMIO FIFO drain. P77 adds the missing low-level interrupt proof: the FIFO can now raise the core’s machine external interrupt line, the bare-metal runtime can take the trap, ack the source, and return to AtomVM without crashing.
P77 AtomVM input IRQ bridge starting
rendered frames: 1
input events: 6
input batches: 1
input max batch: 6
input irq count: 1
input irq seen: true
input fifo status: 0
P77 AtomVM input IRQ bridge PASS
What changed
The input FIFO gained a control register at 0x10001010. Software
writes bit 0 to enable the source. The trap handler writes bit 1 to ack
and disable it. That makes the interrupt edge useful without letting a
nonempty FIFO retrap forever while AtomVM is still running ordinary C
and Erlang code.
| layer | new piece |
|---|---|
| RTL | FIFO-not-empty pending bit and IRQ enable/ack register |
| top-level | FIFO IRQ ORed with the existing external IRQ input |
| runtime | M-mode external IRQ handler with scratch register save/restore |
| C platform | p77_input_irq_init() enables mie.MEIE, mstatus.MIE, and the MMIO source |
| NIFs | chip:input_irq_count/0 and chip:input_irq_seen/0 expose the trap result |
| game | smoke log reports IRQ count next to FIFO/batch counters |
The scripted smoke queued six events. The harness delivered all six,
the input IRQ fired once, the game drained the events as one batch, the
FIFO status returned to 0, and the run halted PASS after 14,774,406
post-load cycles.
Still not the final shape
This is interrupt delivery into the runtime, not yet an AtomVM-native
event source. The IRQ handler intentionally does almost nothing: count,
ack/disable, restore registers, and mret. The Erlang Tetris server
still calls chip:input_events/0 from the game tick, and that NIF
re-enables the source after draining the FIFO.
The next AtomVM step is to connect this IRQ to scheduler wakeup or a real port/listener path so a running Erlang process can receive input messages without being polled from render code.
Verification
cd projects/77_atomvm_input_irq/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/p77-input-irq-smoke-frame.png
Honest Status
| check | status |
|---|---|
| AtomVM input IRQ bridge starts | PASS |
| Host FIFO input reaches harness | PASS |
| RTL MMIO input FIFO buffers events | PASS |
| FIFO-not-empty input IRQ reaches M-mode trap handler | PASS |
| IRQ ack/disable prevents trap storm | PASS |
chip:input_events/0 drains batched host events | PASS |
chip:input_irq_count/0 reports nonzero IRQ count | PASS |
| Tetris framebuffer renders | PASS |
| Scripted quit via input batch | PASS |
| AtomVM scheduler wakeup from input IRQ | NOT RUN |
| F/D architectural compliance | NOT RUN |
| LibreLane hardening | NOT RUN |
What just happened?
The chip can now take an input interrupt while AtomVM is running and come back alive. That is the low-level bridge P76 was missing. The remaining work is making the interrupt wake an Erlang-side event path instead of merely making the next polling NIF safe and observable.