Firmware: RIOv4_2_patched_31250.bin — wedge fix + SCI retuned to 31250 baud

make_patch.py gains --baud31250: one byte beyond the wedge patch — the SCI
init operand at $D62B ($30 -> $02). BAUD $30 = /13 prescale, /1 divider
(2MHz E / 208 = 9615); $02 = /1, /4 -> 31250 exactly, 3.3x faster. The
init write also confirms the 8MHz crystal, which is why 19200/38400 are
unreachable and why 62500/125k are left alone pending an ISR cycle count.

- 24 bytes changed vs original (sha256 9f866cf3...); re-disassembly diff
  vs the classic patched image shows exactly the one operand line, and
  the classic build still reproduces 3fc8170c... (script regression-safe).
- PC side: SerialPortTransport takes an optional baudRate (default 9600,
  runtime untouched); RioSerialMonitor + --mash accept --baud 31250.
- Caveats documented in README/ANALYSIS: non-standard rate (FTDI-class
  adapters only, no 16550s); native games still speak 9600 so this chip
  is bench/RIOJoy-only; validate the wedge patch at 9600 first.

275 tests green; mash --selftest regression unchanged (FAIL/exit-1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-17 20:25:00 -05:00
co-authored by Claude Fable 5
parent 1fecd7e274
commit df5804e835
5 changed files with 13228 additions and 2 deletions
+22 -2
View File
@@ -8,13 +8,25 @@ EVERY reply teardown, not just the $2522-gated success path.
that clears $2521/$2522 then continues to $DA2F.
2. Success path: make $DA00's clear of $2521/$2522 unconditional.
With --baud31250, additionally retune the SCI from 9600 to 31250 baud
(-> RIOv4_2_patched_31250.bin): the init at $D62A loads BAUD ($102B) with
$30 (prescale /13, divider /1 -> 2MHz E / (16*13) = 9615). $02 selects
prescale /1, divider /4 -> 2MHz / (16*4) = 31250 exactly. One operand
byte at $D62B. NOTE: 31250 is a non-standard rate — FTDI-class USB
adapters produce it exactly; classic 16550 UARTs cannot. The native
games still expect 9600, so a 31250 chip is bench/RIOJoy-only until the
games are patched.
Each edit asserts the exact original bytes first, so a wrong assumption
aborts instead of corrupting the image. Address == file offset.
"""
import sys, hashlib
SRC = sys.argv[1] if len(sys.argv) > 1 else "RIOv4_2.bin"
DST = sys.argv[2] if len(sys.argv) > 2 else "RIOv4_2_patched.bin"
BAUD31250 = "--baud31250" in sys.argv
args = [a for a in sys.argv[1:] if not a.startswith("--")]
SRC = args[0] if len(args) > 0 else "RIOv4_2.bin"
DST = args[1] if len(args) > 1 else (
"RIOv4_2_patched_31250.bin" if BAUD31250 else "RIOv4_2_patched.bin")
d = bytearray(open(SRC, "rb").read())
assert len(d) == 0x10000, f"expected 64KB image, got {len(d)}"
@@ -52,6 +64,14 @@ patch(0xDA21,
[0x7F,0x25,0x21, 0x7F,0x25,0x22, 0x01,0x01,0x01,0x01,0x01,0x01,0x01])
assert d[0xDA2E] == 0x39, "RTS at $DA2E must be intact"
# --- edit 3 (--baud31250 only): SCI 9600 -> 31250 --------------------------
# $D62A 86 30 LDAA #$30 (SCP=/13, SCR=/1) -> 86 02 (SCP=/1, SCR=/4)
# then STAA $102B (BAUD). 2MHz E-clock: 2e6/(16*13)=9615 -> 2e6/(16*4)=31250.
if BAUD31250:
assert d[0xD62A] == 0x86 and bytes(d[0xD62C:0xD62F]) == bytes([0xB7,0x10,0x2B]), \
"expected LDAA #imm ; STAA $102B at $D62A"
patch(0xD62B, [0x30], [0x02])
open(DST, "wb").write(d)
new_sha = hashlib.sha256(d).hexdigest()
# byte-diff report