Skip to content

ADR 0016 — v1.13.0 (in progress): 65816 ABORT interrupt

  • Status: Proposed
  • Release: v1.13.0 (unreleased; in progress)
  • Theme: The post-v1.12.0 tail. Opened by the first decision of the cycle; per-release decisions fold in here.

D1 — 65816 ABORT interrupt, boundary-recognized (#518)

  • Context: the 65816 hardware-interrupt model (ADR 0014 D1, ADR 0015 D3) covered IRQ/NMI but not ABORT ($FFF8 emulation / $FFE8 native), the memory-management interrupt. ABORT was parked because chippy has no abort source (no MMU), and true ABORT is asserted mid-instruction — the real chip finishes the instruction's cycles with its register/memory writes inhibited, then vectors while pushing the aborted instruction's PC so RTI re-runs it. Modeling that faithfully needs cycle-accurate rollback and a peripheral that drives the abort line mid-op.

  • Decision: land ABORT with a boundary-recognized model that matches how chippy already services IRQ/NMI. Step services interrupts at the instruction boundary, so an asserted ABORT aborts the upcoming instruction before it executes: serviceInterrupt816(0xFFF8, 0xFFE8) pushes the current PC (the aborted instruction's own address), so RTI re-runs it — no rollback needed because the instruction never started. New abortPending + AssertAbort() (edge-triggered like TriggerNMI, a no-op on the 8-bit cores). ABORT is serviced first in Step (priority over NMI/IRQ) and ignores the I flag. Driver: a :abort TUI command.

  • Consequences: the 65816 interrupt model is complete (IRQ/NMI/ABORT, all per-cycle bus-trace validated). abortPending is only ever set for the 65816, so the 8-bit cores take a cheap false branch each Step. True mid-instruction abort (cycle-accurate rollback driven by an MMU asserting mid-op) remains out of scope and is documented on the field — it needs a consumer that doesn't exist in-tree. Reuses serviceInterrupt816, so ABORT inherits the correct native/emulation push order + $FFF8/$FFE8 vectors with no new dispatch. This closes epic #517 (65816 accuracy + playground polish).

D2 — Catppuccin default theme + true-color demo GIFs

  • Context: the TUI's demo GIFs (the vhs smoke tapes) never reflected a chosen palette — the tapes set no VHS terminal theme, so chippy's ANSI-256 colors rendered against VHS's default scheme. chippy also had no Catppuccin palette, the requested default.

  • Decision: ship four Catppuccin flavors — Mocha, Macchiato, Frappe, Latte — as first-class themes using the official hex colors (via lipgloss, true-color rather than ANSI-256 approximation), and make Catppuccin Mocha the shipped default (ThemeDefault). The original high-saturation palette is preserved as neon; mono/protan/tritan are unchanged. A single catppuccinPalette(flavor) maps chippy's semantic slots (mauve headings, blue registers, green flags, mauve status bar) so the four flavors share one mapping and differ only in hex. The VHS tapes now Set Theme "Catppuccin Mocha" and export COLORTERM=truecolor before launch, so the GIFs render the exact Catppuccin colors instead of a 256-color approximation.

  • Consequences: the default look changes for everyone (opt back with --theme neon). Themes carry hex now, not just ANSI-256 — true-color terminals get exact colors; 256-color terminals downsample via lipgloss. The persisted :theme choice and --theme flag are unaffected (still a name); AvailableThemes() drives the flag help, :theme list, and completion.

D3 — 6551 ACIA wired into the binary (#535)

  • Context: the peripheral.ACIA core + tests landed in #531 but nothing constructed one — a serial ROM loaded into chippy got no input and its TX was invisible. The Apple-1 devices ($F001 TextOutput / $F004 KeyboardInput) are hard-wired in main; the ACIA needed the same treatment plus a chosen base.

  • Decision: add a -acia $BASE flag (default off) that registers a peripheral.ACIA on the MMIO bus and SetIRQ(c)s it so receiver interrupts reach the CPU. It coexists with the $F001/$F004 devices rather than replacing them (distinct addresses; $5000 is the Ben Eater convention). The TUI gains a Model.ACIA field + WithACIA builder mirroring WithKeyboard: input mode (i) routes keystrokes into the ACIA RX queue (alongside the keyboard if both are wired), and the Output pane sources its text from the ACIA TX sink when no TextOutput is present (titled "Serial"), with TextOutput winning when both exist. The ACIA joins the reverse-step peripheral snapshot map keyed by its base address. A hand-assembled example/serial_echo.bin (source serial_echo.s, generator gen_serial_echo.go) demos it end-to-end and self-verifies on chippy's own core.

  • Consequences: serial ROMs (Ben-Eater-style) are now runnable and interactive. The output pane is no longer TextOutput-only — hasOutput() / outputText() abstract the source, so a future third sink slots in the same way. Peripherals still don't persist to the state file (only the rewind snapshot ring); the ACIA follows that existing contract. TX-interrupt emulation remains out of scope (TDRE is always set — polled TX), as documented on the core.