New IO-ARCHITECTURE.md, derived from the v4.2 image, the U7 GAL decode and schematic sheets 1/3: - $A010 control-latch bit map (CCK / D_OUT / WR_SB / RD_SB / SEL0-2) - the 50-byte script format the firmware replays, and the ROM table map - full port/address population: 9 buttons boards + 2 keypads across all 8 ports; the 0x00-0x6F logical map and its 0x48-0x4F gap - the keypad engine ($CC53/$CC7E): 4-row matrix scan, row-patched RAM scripts, the $DC14 key-code table, message type $8B - lamp readback ($21C2) and the 72-byte lamp-fault mask at $DFA8 -- fault reports are type $03 with the lamp index in $2519 - scan cycle budget: 1.91 ms/pass, 17.3 ms/scan, ~58 Hz; demux is 60% - expansion: one spare buttons board, and nothing further without a protocol revision Corrections to existing docs: - $CC53 was cited as the encoder sweep; it is the keypad-1 scanner. The sweep is $C8CC-$C9A7, driven from $C0CB. - U31 is on sheet 3, not sheet 1, and is completely uncommitted: no address, data, strobe or pod-bus signal reaches it. Not an expansion hook -- populating it does nothing without new wiring. - No spare HCTL-2016 footprints exist. The decode has 3 free selects on U9, but the PCB carries exactly 5 positions and sheet 1 draws 5. More analog axes need hardware, not firmware. Also carries the previously-uncommitted standard-rate (16550) feasibility analysis and baudscan.py, plus a note that the FastRIO "FTDI-class adapter" rule really means arbitrary-rate generation: CP2102N qualifies, classic CP2102 snaps 31250 to 38400. Bench-measured 2026-07-26; on-cockpit latency check still pending. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
155 lines
8.0 KiB
Markdown
155 lines
8.0 KiB
Markdown
# RIO board firmware
|
|
|
|
> **Pod owner, not an engineer?** Read
|
|
> [wedge-explained.md](wedge-explained.md) — a plain-language account of
|
|
> the "stick died mid-battle" bug that RIO 4.3 fixes.
|
|
|
|
> **How the board moves buttons and lamps:**
|
|
> [IO-ARCHITECTURE.md](IO-ARCHITECTURE.md) — the pod-bus control latch,
|
|
> the 50-byte script format, the full port/address population of a pod
|
|
> (9 buttons boards + 2 keypads), the scan cycle budget, and what
|
|
> expansion headroom is left.
|
|
|
|
- **`RIOv4_2.bin`** — RIO cockpit I/O board firmware **v4.2**, dumped
|
|
2026-07-04 from one of our own boards' EPROM: an **AMD AM27C512-150**
|
|
(64K x 8 UV EPROM, 150ns — the image fills it exactly).
|
|
sha256 `60a88718835c654b6135dbec7721c40ef99dca07df2ad4b57eedeb24037a5f73`.
|
|
For the eventual patched burn: a pin-compatible Winbond W27C512
|
|
(electrically erasable, TL866-friendly) drops straight into the socket;
|
|
the original AMD chip gets labeled and preserved unmodified.
|
|
|
|
## First-look analysis (from the image alone, confirmed on hardware)
|
|
|
|
- MCU: **Toshiba TMP68HC11** (read off the chip; the code fingerprint
|
|
agrees — 6800-family opcodes with writes into the 68HC11 internal
|
|
register block at `$10xx`).
|
|
- Memory map: image is FF up to **0xC000**; 16KB of code occupies
|
|
`$C000-$FFFF` (EPROM mapped at the top of the HC11 address space).
|
|
- Startup at `$C000`: `SEI; LDS #$8000; STAA $1024 (TMSK2);
|
|
STAA $1022 (TMSK1); ...` then a long `JSR` init chain — textbook HC11
|
|
bring-up.
|
|
- Vector table (`$FFD6-$FFFF`, big-endian):
|
|
- `$FFFE` RESET → `$C000`
|
|
- **`$FFD6` SCI (serial) → `$D630`** — the entry point of the board's
|
|
receive/protocol interrupt handler. The suspected board-side
|
|
DISABLE_AND_DIE-style wedge (see RIO-NOTES.md: the board mirrors the
|
|
game's PCSPAK state machine, and mash-stress leaves the reply path
|
|
dead while the button/event path stays alive) is reachable from here.
|
|
- `$FFE4` → `$C1B2`, `$FFE6` → `$C18E` (timer output-compares); most
|
|
other vectors → `$DB07..$DB3D` stubs.
|
|
|
|
## Why this exists
|
|
|
|
The remaining RIO reliability issue is board-side: under button-mash
|
|
stress the board's reply/analog state machine wedges (RX dead, TX alive;
|
|
a button press or power cycle revives it), reproduced identically on two
|
|
different USB serial adapters. The game-side half of the protocol was
|
|
binary-patched for tolerance (BTL4OPT patches v2-v4); the board firmware
|
|
is the other half. Plan (RIO-NOTES.md "Board firmware patch plan"):
|
|
disassemble as 68HC11 from `$C000` with the vector entries as roots, find
|
|
the SCI state machine (protocol constants FC=ACK FD=NAK FE=RESTART
|
|
FF=IDLE, idle-reload-4 patterns), patch the early-ACK/error wedge path or
|
|
widen its window, burn a new EPROM, keep this original safe.
|
|
|
|
## RIO 4.3 — `RIOv4_3.bin` (current production firmware)
|
|
|
|
**Christened 2026-07-19** after full on-hardware certification. Built
|
|
by `make_patch.py --e0thresh=5 --checkrepaint --reportversion=4.3
|
|
RIOv4_2.bin RIOv4_3.bin`; sha256
|
|
`6d67a2fc77130b601fdb0ac02042dd4d0a98ac7e29a8077d588987a81073939c`
|
|
(69 bytes changed vs stock). 9600 baud, native-game compatible. On the
|
|
stock v4.2 base it carries:
|
|
|
|
1. **Reply-latch wedge fix** (edits 1-2) — bench-certified.
|
|
2. **E0-display threshold, N=5** (edit 5) — certified: display holds
|
|
`F0000000` through sub-threshold error events, flips to the live
|
|
`E0` readout at the 5th teardown (`E0000105` on the bench).
|
|
3. **Check self-test display repaint** (edit 6) — certified both ways:
|
|
version+check leaves `F0000000` when healthy, and re-renders the E0
|
|
readout when counters are over threshold (`E0000305` on the bench)
|
|
instead of stock's stale `04000000`.
|
|
4. **Version bump** (edit 7, `--reportversion=4.3`) — the VersionReply
|
|
now announces **4.3** (one operand byte at `$C6FF`). Nothing
|
|
host-side validates the value (native games verified not to check
|
|
it). The certification runs below were made on the pre-edit-7 bytes;
|
|
the only delta is the version literal. Chips burned before this edit
|
|
report 4.2 — re-burn to announce 4.3.
|
|
|
|
Certification runs (all in `testlogs/` + RIOv4_2-ANALYSIS.md): two
|
|
`--e0test` acceptance passes (display verified by eye at each step) and
|
|
a 120 s mash at **549 presses/min sustained** — zero wedges, board
|
|
counters flat, zero NAK, 247 resends all healed
|
|
(`riomash-rio43rc1-9600-20260719-164901.log`).
|
|
|
|
## FastRIO 4.3 — `RIOv4_3_fastrio.bin`
|
|
|
|
Same generation for the RIOJoy-only cockpits: `make_patch.py
|
|
--baud31250 --widen-ackwait --e0thresh=5 --checkrepaint
|
|
--reportversion=4.3 RIOv4_2.bin RIOv4_3_fastrio.bin`; sha256
|
|
`ee807831fe0df9dc147eb5cdc3302672ae21f6ff349da30babea27fc863234b9`
|
|
(71 bytes vs stock — differs from `RIOv4_3.bin` in exactly two bytes:
|
|
`$D62B` baud `30→02` and `$D9E7` ACK-wait `04→28`). 31250 baud,
|
|
FTDI-class adapter required, **not** native-game compatible.
|
|
Disassembly-verified; run the acceptance ladder on the FastRIO cockpit
|
|
before deploying (`--e0test COM1` auto-probes 31250, then a mash
|
|
spot-check at `--baud 31250`).
|
|
|
|
### "FTDI-class" is really "arbitrary-rate" — CP2102N qualifies
|
|
|
|
Bench-measured 2026-07-26 on a **Silicon Labs CP2102N** (`VID_10C4`/
|
|
`PID_EA60`; identify by the bus-reported string "CP2102N USB to UART
|
|
Bridge Controller" — the `REV_0100` hardware ID is *not* diagnostic).
|
|
It generates the whole HC11 ladder — 20833 / 31250 / 41667 / 62500 —
|
|
each tracking its request within measurement noise, so the adapter
|
|
requirement is about **arbitrary-rate generation**, not the FTDI brand.
|
|
|
|
**Classic CP2101/2102/2103 do NOT qualify**: they quantise to the AN205
|
|
table, where a 31250 request snaps silently to **38400**. The part on
|
|
test was verified not to snap — 31250 and 38400 measure as distinct
|
|
wire rates.
|
|
|
|
**UNVERIFIED**: absolute rate against an independent clock, and
|
|
round-trip latency against the FastRIO ACK window (`$D9E7 = $28`,
|
|
40 ticks ≈ 12.8 ms at 31250). The certification rig used an FTDI with
|
|
its latency timer at 1 ms; **CP210x exposes no latency-timer setting**
|
|
— though it also has no FTDI-style 16 ms coalescing default to defeat.
|
|
Confirm on-cockpit before deploying a CP2102N in a FastRIO seat.
|
|
|
|
> **Measurement trap.** On Silabs driver **6.7.0.0**,
|
|
> `SerialPort.BytesToWrite` reaches 0 while ~640 bytes (the CP2102N TX
|
|
> FIFO) are still in flight; driver **6.7.6.2130** waited for a true
|
|
> drain. Timing a bulk write to `BytesToWrite == 0` therefore
|
|
> *over-reads* the baud rate — at 31250/3 s it reported a bogus
|
|
> **+7.15%**, which looks exactly like a rate fault but is pure
|
|
> bookkeeping. Measure instead by the **slope** of elapsed-vs-bytes
|
|
> across several transfer sizes; a fixed buffer only moves the
|
|
> intercept.
|
|
|
|
## Standard-rate (16550) future — the oscillator-swap path
|
|
|
|
FastRIO's 31250 is FTDI-only by arithmetic: from the stock 8 MHz
|
|
oscillator every SCI rate above 9615 sits +8.5% off the nearest
|
|
16550-standard rate (exhaustive proof: [`baudscan.py`](baudscan.py)).
|
|
Swapping the board's 4-pin oscillator can (8.000 MHz, by U4) for a
|
|
**7.3728 MHz** part makes the entire standard ladder exact — 9600
|
|
(still native-game compatible) through 115200 — at the cost of a
|
|
mandatory one-byte BAUD retune per rate. Recommended target: **28800
|
|
"FastRIO-Std"**, which keeps the exact per-byte CPU margin of the
|
|
certified 31250 v2 while being reachable by *any* UART, including the
|
|
period pods' 16550s. Full analysis (the closed-form impossibility, can
|
|
options, margins, required edits, and the why-8-MHz design hypothesis):
|
|
RIOv4_2-ANALYSIS.md "Standard-rate (16550) feasibility". Unbuilt as of
|
|
2026-07-24 — needs the can, new `BAUD_OPTS`/ACK-wait entries in
|
|
`make_patch.py`, and the acceptance ladder.
|
|
|
|
## Archive
|
|
|
|
All prior generations live in [`archive/`](archive/) with their
|
|
disassemblies: `RIOv4_2_patched` (wedge fix only), `_31250`/`_31250v2`
|
|
(FastRIO speed builds), `_62500`/`_125000` (speed-ladder science runs),
|
|
and the `_e0t5` pair (threshold without check-repaint). Bench verdicts
|
|
and per-edit history: RIOv4_2-ANALYSIS.md. The pristine dump
|
|
`RIOv4_2.bin` stays at top level — it is the source every patch builds
|
|
from. RIO 4.3 is in the cockpit socket as of 2026-07-19; the original
|
|
AMD chip and the retired e0t5 burn are labeled and preserved.
|