Files
TeslaRel410/restoration/rio-firmware/README.md
T
CydandClaude Opus 5 b615f319db RIO: decode the pod-bus I/O architecture end to end
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>
2026-07-26 22:05:29 -05:00

8.0 KiB

RIO board firmware

Pod owner, not an engineer? Read 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 — 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). 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/ 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.