Firmware: --e0thresh patch — gate the E0 error display (default N=5)
Stock $D5F2 repaints the cockpit display to the E0 counter readout on the FIRST increment of $3187/$3184/$3185, so one benign give-up shows E0000001 forever. New opt-in make_patch.py edit 5 hijacks the render's LDX #$2038 into a 30-byte cave at $E000: all three counters below N -> exit via the routine's own epilogue (registers restored, display untouched); any >= N -> resume the render. Counters still accumulate. Built + disassembly-verified (not yet burned): RIOv4_2_patched_e0t5.bin (9600) and RIOv4_2_patched_31250v2_e0t5.bin (FastRIO). Docs updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,13 @@ 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)"
|
||||
|
||||
# --e0thresh[=N]: gate the E0 error display (see edit 5). Default N=5.
|
||||
E0T = None
|
||||
for a in sys.argv:
|
||||
if a.startswith("--e0thresh"):
|
||||
E0T = int(a.split("=", 1)[1]) if "=" in a else 5
|
||||
assert E0T is None or 1 <= E0T <= 255, f"--e0thresh out of range: {E0T}"
|
||||
|
||||
args = [a for a in sys.argv[1:] if not a.startswith("--")]
|
||||
SRC = args[0] if len(args) > 0 else "RIOv4_2.bin"
|
||||
if len(args) > 1:
|
||||
@@ -50,6 +57,8 @@ elif BAUD_NAME:
|
||||
DST = f"RIOv4_2_patched_{BAUD_NAME}.bin"
|
||||
else:
|
||||
DST = "RIOv4_2_patched.bin"
|
||||
if E0T is not None and len(args) <= 1:
|
||||
DST = DST[:-4] + f"_e0t{E0T}.bin"
|
||||
|
||||
d = bytearray(open(SRC, "rb").read())
|
||||
assert len(d) == 0x10000, f"expected 64KB image, got {len(d)}"
|
||||
@@ -107,6 +116,31 @@ if WIDEN_ACKWAIT:
|
||||
"expected LDAA $317B ; CMPA #imm at $D9E3"
|
||||
patch(0xD9E7, [0x04], [ACKWAIT_VAL])
|
||||
|
||||
# --- edit 5 (--e0thresh=N): threshold-gate the E0 error display -----------
|
||||
# Stock behavior: every increment of $3187 (TX-ring overflow), $3184 (reply
|
||||
# retransmit) or $3185 (reply teardown/give-up) immediately calls $D5F2,
|
||||
# which paints 'E0'+counters over the F0 banner — so ONE benign give-up
|
||||
# shows E0000001 forever. Gate the render: skip unless any counter >= N.
|
||||
# $D5F2 prologue (PSHX/PSHA) has already run when we take over its
|
||||
# LDX #$2038; the cave may clobber A/X because both exits restore them —
|
||||
# below-threshold leaves via the routine's own epilogue at $D61D
|
||||
# (PULA/PULX/RTS), at-or-above resumes the render at $D5F7.
|
||||
if E0T is not None:
|
||||
patch(0xD5F4, [0xCE, 0x20, 0x38], [0x7E, 0xE0, 0x00]) # LDX #$2038 -> JMP $E000
|
||||
cave = [0xB6, 0x31, 0x87, # $E000 LDAA $3187 (ring overflows)
|
||||
0x81, E0T, # $E003 CMPA #N
|
||||
0x24, 0x11, # $E005 BCC $E018 (>=N -> render)
|
||||
0xB6, 0x31, 0x84, # $E007 LDAA $3184 (reply retransmits)
|
||||
0x81, E0T, # $E00A CMPA #N
|
||||
0x24, 0x0A, # $E00C BCC $E018
|
||||
0xB6, 0x31, 0x85, # $E00E LDAA $3185 (teardowns/give-ups)
|
||||
0x81, E0T, # $E011 CMPA #N
|
||||
0x24, 0x03, # $E013 BCC $E018
|
||||
0x7E, 0xD6, 0x1D, # $E015 JMP $D61D (below threshold: epilogue)
|
||||
0xCE, 0x20, 0x38, # $E018 LDX #$2038 (displaced instruction)
|
||||
0x7E, 0xD5, 0xF7] # $E01B JMP $D5F7 (resume render)
|
||||
patch(0xE000, [0xFF] * len(cave), cave)
|
||||
|
||||
open(DST, "wb").write(d)
|
||||
new_sha = hashlib.sha256(d).hexdigest()
|
||||
# byte-diff report
|
||||
|
||||
Reference in New Issue
Block a user