Skip to content

ADR 0013 — v1.10.0: bank-aware 24-bit bus for the 65816

  • Status: Accepted
  • Release: v1.10.0 (2026-06-30)
  • Theme: The post-v1.9.0 tail. Opened by the first decision of the cycle; per-release decisions fold in here.

D1 — Bank-aware Banked24 (kill the bank-0 mirror, #505)

  • Context: the WDC 65C816 core (#456, ADR 0010) forms full 24-bit addresses — PBR:PC, long/[dp] addressing, MVN/MVP — but the production 24-bit bus was Bus24From16 (cpu/cpu816.go), which truncated every access to uint16(a). Every bank aliased bank 0: a program touching a bank ≠ 0 silently read/wrote the single 64 KiB RAM. The 8/16-bit chain (RAM/MMIO/WBus) and every inspection path (loader, DAP readMemory/ writeMemory, the TUI memory panel) were hard-capped at 64 KiB.

  • Decision: introduce cpu.Banked24, the real 24-bit bus, and thread bank-awareness through the four layers it touches:

  • CoreBanked24 routes bank 0 through the supplied 16-bit Bus (chippy's MMIO/WBus/RAM chain, so peripherals, watchpoints, and the TUI's bank-0 panels stay accurate) and backs banks 1-255 with a flat 16 MB store (make([]byte, 1<<24) — the bank-0 slice is unused). Wired at the sole production site (cmd/chippy/main.go, replacing the mirror) and in the DAP launch path (which never called SetBus24 for 65816 — a latent nil-bus panic).
  • Loader — Intel HEX type-04 (Extended Linear Address) records set the upper 16 bits of a 24-bit address; data past bank 0 loads through Options.Bus24. Bank 0 still loads into ram directly (bypassing MMIO, per the loader invariant). .bin/.prg/.o stay bank-0 — inherently 16-bit formats.
  • DAPpeekByte24/writeByte24 route bank 0 through the MMIO-aware path and banks 1-255 through Banked24; handleReadMemory/ handleWriteMemory lift the 0xFFFF/0x10000 clamps to memMax() (16 MB when a bank-aware bus is wired, else 64 KiB) and render addresses 6-digit vs 4-digit. AttachConfig gains Banked; Server.SetBanked lets the in-process LocalSource (attached in New, before the bus is known) reach banks afterward.
  • TUISource.ReadMemory widens to a uint32 address; the memory panel anchors its window at MemViewBank:MemViewAddr, :bank N selects the bank, and the header + row addresses show $BB:XXXX. Bank>0 edits write through Banked24; MemViewBank persists as an additive v1.x state field.

  • Consequences: a 65816 program reaches 16 MB of distinct storage; the memory panel inspects and edits any bank. The flat 16 MB is always resident — simplest indexing, acceptable on a modern host (a sparse map or lazy pages would trade memory for per-access cost / GC pressure). The bank-0-through-the- 16-bit-chain split keeps watchpoints and peripherals a bank-0-only concept (chippy's documented memory model — there is no cross-bank MMIO). Two scoped follow-ups: cross-bank disassembly (D2, since done) and remote 65816 over DAP (RemoteSource serves bank 0 from its 64 KiB mirror — no remote 65816 host exists). Bus24From16 is retained as the bank-0 mirror adapter for unit tests; production no longer uses it.

D2 — Cross-bank disassembly (PBR-relative, #507)

  • Context: D1 made the memory panel bank-aware, but the disassemble path stayed 16-bit (cpu.DisasmCPU/WalkBack read c.Bus, the DAP clamped the reference to 0xFFFF). A 65816 program executing in a bank ≠ 0 (PBR ≠ 0) disassembled bank 0 at the same offset — wrong bytes.

  • Decision: add bus-explicit disassembly. cpu.DisasmCPUAt/WalkBackAt are siblings of DisasmCPU/WalkBack that read instruction bytes through a supplied Bus rather than c.Bus — the decode (opcode table, M/X/E immediate widths) is bank-independent, so only the operand-byte source changes. The DAP introduces bankView, a 16-bit Bus reading the side-effect-free peekByte24 of a fixed bank; handleDisassemble parses a 24-bit reference, holds the bank constant across the window (the within-bank 16-bit offset carries the operand-fetch wrap), and emits bank-aware addresses. The TUI widens Source.Disassemble to a uint32 anchor and syncDisasm anchors at PBR:PC for the 65816; the panel renders $BB:XXXX rows and a (bank $NN) title.

  • Consequences: code in any bank disassembles correctly, following PBR live. Symbols, the source map, and data ranges remain a bank-0 concept (the .dbg source map addresses bank 0) — bank>0 lines decode without symbol / source annotation. The pinned-scroll anchor (' off) still uses the current PBR, so cross-bank scrolling isn't supported; remote 65816 over DAP is still out of scope (RemoteSource mirror is bank 0).