From c29a9d5343e9ba2be23f5099b93b8babc1fd5aa3 Mon Sep 17 00:00:00 2001 From: Cyd Date: Sun, 19 Jul 2026 16:13:13 -0500 Subject: [PATCH] RIOv4_3rc1 candidate: wedge fix + E0 threshold + check-display repaint; archive prior images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New edit 6 (--checkrepaint, requires --e0thresh): hooks the CheckRequest handler's final notify ($C5E4) through a 10-byte cave at $E020 that repaints F0000000 after the self-test and re-renders the E0 readout only when a counter is at/over threshold — no more stale 04000000 after status checks. Candidate = 9600 native-game-compatible base + edits 1-2/5/6, 68 bytes vs stock, disassembly-verified, awaiting burn; on verification it will be christened RIO 4.3. All prior patched generations (wedge-only, 31250/31250v2, 62500/125000 science builds, e0t5 pair) moved to rio-firmware/archive/ with their disassemblies; RIOv4_2.bin stays at top level as the pristine patch source. Co-Authored-By: Claude Fable 5 --- README.md | 51 +- RIOv4_2-ANALYSIS.md | 13 +- RIOv4_3rc1.bin | 39 + RIOv4_3rc1.disasm.asm | 13109 ++++++++++++++++ .../RIOv4_2_patched.bin | 0 .../RIOv4_2_patched.disasm.asm | 0 .../RIOv4_2_patched_125000.bin | 0 .../RIOv4_2_patched_125000.disasm.asm | 0 .../RIOv4_2_patched_31250.bin | 0 .../RIOv4_2_patched_31250.disasm.asm | 0 .../RIOv4_2_patched_31250v2.bin | 0 .../RIOv4_2_patched_31250v2.disasm.asm | 0 .../RIOv4_2_patched_31250v2_e0t5.bin | 0 .../RIOv4_2_patched_31250v2_e0t5.disasm.asm | 0 .../RIOv4_2_patched_62500.bin | 0 .../RIOv4_2_patched_62500.disasm.asm | 0 .../RIOv4_2_patched_e0t5.bin | 0 .../RIOv4_2_patched_e0t5.disasm.asm | 0 make_patch.py | 24 + 19 files changed, 13214 insertions(+), 22 deletions(-) create mode 100644 RIOv4_3rc1.bin create mode 100644 RIOv4_3rc1.disasm.asm rename RIOv4_2_patched.bin => archive/RIOv4_2_patched.bin (100%) rename RIOv4_2_patched.disasm.asm => archive/RIOv4_2_patched.disasm.asm (100%) rename RIOv4_2_patched_125000.bin => archive/RIOv4_2_patched_125000.bin (100%) rename RIOv4_2_patched_125000.disasm.asm => archive/RIOv4_2_patched_125000.disasm.asm (100%) rename RIOv4_2_patched_31250.bin => archive/RIOv4_2_patched_31250.bin (100%) rename RIOv4_2_patched_31250.disasm.asm => archive/RIOv4_2_patched_31250.disasm.asm (100%) rename RIOv4_2_patched_31250v2.bin => archive/RIOv4_2_patched_31250v2.bin (100%) rename RIOv4_2_patched_31250v2.disasm.asm => archive/RIOv4_2_patched_31250v2.disasm.asm (100%) rename RIOv4_2_patched_31250v2_e0t5.bin => archive/RIOv4_2_patched_31250v2_e0t5.bin (100%) rename RIOv4_2_patched_31250v2_e0t5.disasm.asm => archive/RIOv4_2_patched_31250v2_e0t5.disasm.asm (100%) rename RIOv4_2_patched_62500.bin => archive/RIOv4_2_patched_62500.bin (100%) rename RIOv4_2_patched_62500.disasm.asm => archive/RIOv4_2_patched_62500.disasm.asm (100%) rename RIOv4_2_patched_e0t5.bin => archive/RIOv4_2_patched_e0t5.bin (100%) rename RIOv4_2_patched_e0t5.disasm.asm => archive/RIOv4_2_patched_e0t5.disasm.asm (100%) diff --git a/README.md b/README.md index 4b1d698a..1a11bdfb 100644 --- a/README.md +++ b/README.md @@ -41,22 +41,37 @@ 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. -## Patched images (built by make_patch.py; see RIOv4_2-ANALYSIS.md) +## Current work candidate — `RIOv4_3rc1.bin` -- **`RIOv4_2_patched.bin`** — the reply-latch wedge fix, 23 bytes changed. - sha256 `3fc8170caf60e2580641724ff995176c93c4f2e706f31487beded8233142493f`. -- **`RIOv4_2_patched_31250.bin`** (`make_patch.py --baud31250`) — wedge fix - + SCI retuned 9600 → 31250 baud (one more byte, `$D62B: 30→02`). - sha256 `9f866cf353d04906e1d3e3847b6375eaae251c987b656f68f093e61ba1bd545b`. - Bench/RIOJoy-only until the native games get baud patches; needs an - FTDI-class adapter (16550s can't make 31250). Test tools take `--baud 31250`. -- **Speed-ladder variants** (`_31250v2`, `_62500`, `_125000`) and bench - verdicts: see RIOv4_2-ANALYSIS.md — 31250v2 is the certified FastRIO - build; 62500/125000 were science runs (CPU is the wall). -- **`RIOv4_2_patched_e0t5.bin` / `RIOv4_2_patched_31250v2_e0t5.bin`** - (`--e0thresh=5`) — adds a threshold to the cockpit display's `E0` - serial-error readout, which stock firmware paints on the *first* - counter event (`E0000001` forever after one benign give-up). Display - stays `F0000000` until any error counter reaches 5; counters still - accumulate. 30-byte cave at `$E000`, disassembly-verified, **not yet - burned/bench-verified**. Details in RIOv4_2-ANALYSIS.md. +Built by `make_patch.py --e0thresh=5 --checkrepaint RIOv4_2.bin +RIOv4_3rc1.bin`; sha256 +`dc59bd51cae34781cf42f338e44a020b249a4030acc3c584af916aee9ca881e3` +(68 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) — bench-certified 2026-07-19 + (held `F0000000` sub-threshold, flipped to `E0000105` at the 5th + teardown; mash regression clean). +3. **Check self-test display repaint** (edit 6, NEW) — the CheckRequest + handler previously left a stale `04000000` frame on the display; a + 10-byte cave at `$E020` now repaints `F0000000` after every check, + then re-renders the `E0` readout only if a counter is at/over + threshold. **Needs on-hardware verification**: after a burn, any + version+check exchange (tray connect, monitor, mash start) must + leave the display reading `F0000000`, not `04000000`; then re-run + `--e0test` (expect the certified behavior unchanged) and a mash + spot-check. + +Once edit 6 is verified on the cockpit, this image is christened +**RIO 4.3**. + +## 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; the 9600 one is +in the socket as of 2026-07-19 until rc1 is burned). 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. diff --git a/RIOv4_2-ANALYSIS.md b/RIOv4_2-ANALYSIS.md index f8db959b..6ab2086b 100644 --- a/RIOv4_2-ANALYSIS.md +++ b/RIOv4_2-ANALYSIS.md @@ -516,7 +516,12 @@ last thing rendered), enqueues the fault reports, clears the flag (`$C5E1`), notifies `0x8C` again — and **returns without repainting the display**. Every status check therefore leaves a stale `04 00 ` snapshot (idle: `04000000`) on the digits. The -board is fully healthy afterwards; no reset is needed. Proper fix, if -the cosmetic bothers: a ~10-byte cave off `$C5E4` that repaints `F0` -(`JSR $CB7C`) and re-renders the E0 readout when over threshold -(`JSR $D5F2`) — candidate for the next burn, not yet built. +board is fully healthy afterwards; no reset is needed. Proper fix: +**edit 6** (`make_patch.py --checkrepaint`) — a 10-byte cave at `$E020` +hooked from the handler's final notify (`$C5E4`): `JSR $C70E` (original +notify), `JSR $CB7C` (repaint `F0000000`), `JSR $D5F2` (re-render the +E0 readout, which the edit-5 gate suppresses below threshold), `RTS`. +Built into **`RIOv4_3rc1.bin`** (with edits 1-2 and 5; sha256 +`dc59bd51cae3…`) — awaiting burn + on-hardware verification, after +which the image is christened RIO 4.3. Prior generations moved to +`archive/`. diff --git a/RIOv4_3rc1.bin b/RIOv4_3rc1.bin new file mode 100644 index 00000000..6f41e77a --- /dev/null +++ b/RIOv4_3rc1.bin @@ -0,0 +1,39 @@ +$"f qFLiÐÙƽôýâë,ʽ5ӽ$$ J K M 4 7  N$ɽ|$!$B$C$G$E$I$F$J$$K$$H$1111% %!%"Ty1y~y˽y~<<67̽4hɜ$F$E32889}$I'|$J$J&$!'м$J$I9̭#""9    =  =   @#""9 #""9^ q9oZ&J&9í$E#; @&    @ @#; $I#;%;<<76 %;% +&~8 & +&G ~8& +&6 &0~$') +&  &&~8$!˧A%523889~;&F(;'~O& ̽;'~^& ;'u~o& 4;'d~€ & h;'S~‘& ɜ;'B~¢&%ұB;'\~¹&ҽJ;'H~Ё&*p;'4~˧; '~A|,$!9&ν~;'~~%~ÐÙi M9 K~S J91Ԣ%9 P۰d< 1 18Z&9" + 32< 1 18Z&z 3&9`!b>9H#ν>9H!½>9$>9H$T>9H$>9$Ļ3U9%08 (9 >9 >9oZ&9   Π)Π!Π#Π%Π' 9 Π) 9 Π! 9 Π# 9 Π% 9 Π' 9 + '>9$"91D1X 9i&$"1''X' +''9~~ƿâë$$!J1Ѱ$ɽ1S~bNJǵ$! 99˽ 9~ƾi&1'~ƏLiÐÙƽôýâë,$$ J K M 4 7  N$ɽ|$!$B$C$G$E$I$F$J$$K$$H$1111% %!%"~ƾ&z~ƾ&Ċ~ƾ&Ě~ƾ&Ī~ƾ&ĺ9i&1$Gi&1$K$GH$?967<<-A-B;8832967<<-A-B$!;8832967<<-A-B%%;8832967<<-A-B%%;8832967<<-A-B1;8832967<<-A-B1;8832967<<-A-B1;8832967<<$!'0 '% +%-B -A<%%8z%&;88329$!'-A$ -B 7;9$!'#%-A$ -B% J;9$!'#%-A$ -B% K;99 LΠ( Π8 !ʗ #ʰ &   + 9 LΠ Π0 !ʗ #ʰ &    9 LΠ" Π2 !ʗ  #ʰ &     9 LΠ$ Π4 !ʗ  #ʰ &     9 LΠ& Π6 !ʗ  #ʰ &     9 ' L&#  H$ H~ʖ H~ʖ&#  H$ H~ʖ H~ʖ&#  H$ H~ʖ H~ʖ &#  H$ H~ʖ H~ʖ&  H$ H ~ʖ H 9  & ! %9< 89O_ % & #'|   ҽ9<6$!& 8  H  H 6I289<6$!& 8 % H & H 6I289 HDDDD9O L H 9 8962962962962962967<<  N P !̲8832967<<  N : P2: :!̲88329  4 4&~&O~&̀~ͱ "Z& 5 +< 1 18Z&z 5&z 4&9  + + 9 + +  9 + +   9 + + 9  6 5 NZ'D~&r~| z 5&z 6&967<< !:&7< 1 1 : N& J8~d K8$ Ȝ~l$ o8832967<< !:'@< 1 1 : N& J8~κ K8$ Ȝ~Ȇ$ J%o88329<6$!& 8 K H O L6I289 M& +$ ~$ # M& +$ +~0$ +967<< 7$B N$!P϶| NV!P϶| N܈!P϶ܺ!P϶| N!P϶!P϶P!P϶| N| N| N݂!P϶| Nݴ!P϶883299D967<<!R!PZ& 6 +< 1 18Z&z 6&8832967< 0 else "RIOv4_2.bin" if len(args) > 1: @@ -59,6 +64,8 @@ else: DST = "RIOv4_2_patched.bin" if E0T is not None and len(args) <= 1: DST = DST[:-4] + f"_e0t{E0T}.bin" +if CHECKREPAINT and len(args) <= 1: + DST = DST[:-4] + "_ckr.bin" d = bytearray(open(SRC, "rb").read()) assert len(d) == 0x10000, f"expected 64KB image, got {len(d)}" @@ -141,6 +148,23 @@ if E0T is not None: 0x7E, 0xD5, 0xF7] # $E01B JMP $D5F7 (resume render) patch(0xE000, [0xFF] * len(cave), cave) +# --- edit 6 (--checkrepaint): repaint the display after the check self-test -- +# The CheckRequest handler ($C5A6) renders its five-channel encoder sweep to +# the cockpit display (it sets the test-display flag $2421 for the duration) +# and returns without repainting, leaving a stale '04 00 ' frame +# (idle: 04000000) after every status check. Hook its final TestModeChange +# notify ($C5E4 JSR $C70E) through a cave that also repaints F0000000 +# ($CB7C) and then re-renders the E0 error readout via $D5F2 — which, with +# the edit-5 gate, paints only when a counter is at/over threshold. Display +# after any check: F0000000 when healthy, E0... when not. +if CHECKREPAINT: + patch(0xC5E4, [0xBD, 0xC7, 0x0E], [0xBD, 0xE0, 0x20]) # JSR $C70E -> JSR $E020 + cave6 = [0xBD, 0xC7, 0x0E, # $E020 JSR $C70E (original notify, kept) + 0xBD, 0xCB, 0x7C, # $E023 JSR $CB7C (repaint F0000000) + 0xBD, 0xD5, 0xF2, # $E026 JSR $D5F2 (E0 readout iff >= threshold) + 0x39] # $E029 RTS + patch(0xE020, [0xFF] * len(cave6), cave6) + open(DST, "wb").write(d) new_sha = hashlib.sha256(d).hexdigest() # byte-diff report