Firmware: RIOv4_2_patched_125000.bin — max-speed science build (13x)

make_patch.py generalized: baud flags 31250/62500/125000, each holding
the byte-clocked ACK-wait at ~12.8ms wall time (40/80/160 ticks; the
widen is implied for 62500/125000 since stock 4 ticks would be 0.6/0.3ms
there). All historical hashes reproduce unchanged; the 125000 image
(sha256 d22c8d85..., 25 bytes) diffs from 31250v2 by exactly the BAUD
and CMPA operands.

Predictions on record for the bench run: FTDI side exact (3M/24); the
MAX232-class level shifter is AT its 120kbps rating so edge-rounding
may surface as noise flags; and the 2MHz HC11 has ~160 E-cycles/byte -
back-to-back inbound bytes likely outrun the RX ISR (the firmware sets
its overrun flag $3186 but never reads it), so expect dropped bytes ->
NAK/retry churn and a dirtier profile than v2's. Wedges should stay 0.
62500 is one flag away as the fallback sweet spot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-18 11:20:30 -05:00
co-authored by Claude Fable 5
parent 61778ec3f1
commit d7535f2a43
3 changed files with 13205 additions and 15 deletions
+34 -15
View File
@@ -22,15 +22,34 @@ aborts instead of corrupting the image. Address == file offset.
"""
import sys, hashlib
BAUD31250 = "--baud31250" in sys.argv
WIDEN_ACKWAIT = "--widen-ackwait" in sys.argv
assert not WIDEN_ACKWAIT or BAUD31250, \
"--widen-ackwait only makes sense with --baud31250 (the wait is byte-scaled)"
# Baud retunes: flag -> (BAUD register value, ACK-wait ticks for ~12.8ms, name).
# The ACK-wait loop self-clocks in byte times (see edit 4), so each rate needs
# its own tick count to hold the same ~12.8ms wall-clock ACK grace window.
BAUD_OPTS = {
"--baud31250": (0x02, 0x28, "31250"), # /1 /4 -> 31250 (40 ticks)
"--baud62500": (0x01, 0x50, "62500"), # /1 /2 -> 62500 (80 ticks)
"--baud125000": (0x00, 0xA0, "125000"), # /1 /1 -> 125000 (160 ticks)
}
selected = [f for f in BAUD_OPTS if f in sys.argv]
assert len(selected) <= 1, f"pick one baud flag, got {selected}"
BAUD_VAL, ACKWAIT_VAL, BAUD_NAME = BAUD_OPTS[selected[0]] if selected else (None, None, None)
# --widen-ackwait: required semantics for 62500/125000 (implied there); optional
# for 31250 to keep the historical v1 image reproducible.
WIDEN_ACKWAIT = "--widen-ackwait" in sys.argv or BAUD_NAME in ("62500", "125000")
assert not ("--widen-ackwait" in sys.argv) or selected, \
"--widen-ackwait only makes sense with a baud retune (the wait is byte-scaled)"
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_31250v2.bin" if WIDEN_ACKWAIT else
"RIOv4_2_patched_31250.bin" if BAUD31250 else "RIOv4_2_patched.bin")
if len(args) > 1:
DST = args[1]
elif BAUD_NAME == "31250":
DST = "RIOv4_2_patched_31250v2.bin" if WIDEN_ACKWAIT else "RIOv4_2_patched_31250.bin"
elif BAUD_NAME:
DST = f"RIOv4_2_patched_{BAUD_NAME}.bin"
else:
DST = "RIOv4_2_patched.bin"
d = bytearray(open(SRC, "rb").read())
assert len(d) == 0x10000, f"expected 64KB image, got {len(d)}"
@@ -71,22 +90,22 @@ 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:
if BAUD_VAL is not None:
assert d[0xD62A] == 0x86 and bytes(d[0xD62C:0xD62F]) == bytes([0xB7,0x10,0x2B]), \
"expected LDAA #imm ; STAA $102B at $D62A"
patch(0xD62B, [0x30], [0x02])
patch(0xD62B, [0x30], [BAUD_VAL])
# --- edit 4 (--widen-ackwait, 31250 only): reply ACK-wait 4 -> 40 ticks -----
# --- edit 4 (--widen-ackwait; implied for 62500/125000): scale the ACK-wait --
# The no-ACK wait loop at $D9E0 self-clocks in BYTE TIMES: each tick transmits
# an IDLE ($FF) keep-alive and re-enters on that byte's TX-complete interrupt.
# 4 ticks = ~5.2ms at 9600 (USB ACK wins) but ~1.6ms at 31250 (USB loses ->
# retry storm; bench 2026-07-18: framing 5655, Abandon 65). $28 = 40 ticks
# = ~12.8ms at 31250, clearing FTDI worst-case turnaround with margin.
# $D9E6 81 04 CMPA #$04 -> 81 28 CMPA #$28
# The stock limit (4 ticks) = ~5.2ms at 9600 (USB ACK wins) but shrinks with
# baud (retry storm at 31250; bench 2026-07-18: framing 5655, Abandon 65).
# Each retune holds the window at ~12.8ms wall clock: 40/80/160 ticks.
# $D9E6 81 04 CMPA #$04 -> 81 <ticks>
if WIDEN_ACKWAIT:
assert d[0xD9E6] == 0x81 and bytes(d[0xD9E3:0xD9E6]) == bytes([0xB6,0x31,0x7B]), \
"expected LDAA $317B ; CMPA #imm at $D9E3"
patch(0xD9E7, [0x04], [0x28])
patch(0xD9E7, [0x04], [ACKWAIT_VAL])
open(DST, "wb").write(d)
new_sha = hashlib.sha256(d).hexdigest()