Commit Graph
14 Commits
Author SHA1 Message Date
CydandClaude Fable 5 3c9455eb97 62500 SHELVED: chord-driven RX overrun is host-unfixable; 31250v2 is FastRIO
Slow chorded presses still glitch lamps at 62500 after three rounds of
host-side hardening (NAK-race resend -> stop-and-wait -> typed
resolution): a chord maximizes board ISR latency exactly when lamp
replies arrive, and a 2-byte RX buffer loses bytes no protocol can
recover. Full post-mortem in ANALYSIS.md; all bench evidence archived.
Final ladder: 9600 production / 31250v2 FastRIO / 62500 shelved /
125000 not viable. Stop-and-wait stays on everywhere as cheap delivery
insurance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 13:40:48 -05:00
CydandClaude Fable 5 bef1499152 RioSerialLink: type-aware resolution closes the straggler-reply hole
Bench round 3 (testlogs/riomash-patched-62500-sw): lamp glitches
persisted because reply-resolution was type-blind — an analog reply
still crossing USB from the previous poll could falsely confirm the
NEXT command (usually a lamp write) before the board judged it. Now a
reply resolves only its MATCHING pending request (analog/version/
check); ACK/NAK stay type-blind, which is safe because the board's TX
ISR prioritizes ACK/NAK ahead of reply data, so a command's ACK cannot
trail into its successor's window. Budget-exhausted drops settle 10ms
before releasing the gate so late stragglers land on an empty pending.

New test: a stray AnalogReply must not resolve a pending lamp command.
283 green; selftest regression unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 13:34:12 -05:00
CydandClaude Fable 5 c170f1535c RioSerialLink: stop-and-wait command delivery (supersedes NAK-race resend)
Bench falsified the v1 retransmit (testlogs/riomash-patched-62500-retx):
resends tracked NAKs 1:1 (321/321) yet lamps still stuck/missed — under
mash bursts the NAK arrives after a newer command is already "latest",
so the wrong packet was resent; and total shreds never NAK at all.

Now commands are stop-and-wait: ONE in flight (_commandGate), resolved
by ACK, NAK, or AckTimeout (50ms); NAK/timeout retransmits THE SAME
packet up to CommandRetransmitLimit (2), then drops (idempotent - the
next state update supersedes). Attribution is exact by construction and
timeouts catch silent shreds. Control-byte replies bypass the gate so
board traffic is never delayed; a request's own reply (analog/version/
check) also resolves the wait, so request/reply exchanges never burn
the timeout even if the board sends no explicit ACK.

7 tests (same-packet resend, timeout retry+drop, ACK completion,
serialization, reply-resolves-request, stray-NAK no-op, disable);
282 green. Mash summary now reports NAK/timeout resends.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 13:20:30 -05:00
CydandClaude Fable 5 03bd5830ff 62500 bench: analog clean, lamps lose ~6.5% — RIO speed ladder complete
NAK=69/~1060 lamp commands explains the observed stuck-bright/missed
lamps (fire-and-forget writes turn each corrupt 4-byte burst into a
visible state error) while 2-byte traffic is pristine (analog 88.1%,
counters flat, zero wedges, worst gap 0.14s). The HC11 RX ISR's worst
path sits right at ~320 E-cycles. Ladder: 9600 production, 31250v2
CLEAN (FastRIO), 62500 needs host NAK-retransmit, 125000 CPU-walled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 13:08:46 -05:00
CydandClaude Fable 5 e718ddebfd 125000 bench: RX overrun confirmed (NAK=1082, lamps dead) — CPU is the wall
Board->PC near-perfect at 125k (framing 5) while PC->board shredded by
packet length (2-byte polls 60% delivered, 4-byte lamp cmds ~2/3 NAKed
as checksum-corrupt): the 2MHz HC11 RX ISR can't drain back-to-back
bytes at 80us. MAX232 acquitted; zero wedges even at 40% inbound loss.
62500 image built as the sweet-spot candidate (RIOv4_2_patched_62500.bin).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:57:51 -05:00
CydandClaude Fable 5 4b283b976e 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>
2026-07-18 11:20:30 -05:00
CydandClaude Fable 5 f489bd340e FastRIO v2 bench: CLEAN — ACK-wait widening eliminates the retry storm
192s mash at 31250 with the $D9E7 wait fix: framing 5655 -> 54
(-99.4%), AbandonCount 65 -> +0, duplicate replies gone (215% -> 88.6%
of poll slots — identical to the healthy 9600 profile, the structural
$D758 drop-gate ratio), zero wedges, counters perfectly flat. The
byte-clocked ACK-wait theory is confirmed end to end: disassembly
predicted the mechanism, one operand byte fixed it, the wire went
quiet. Evidence log archived; results table in ANALYSIS.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:13:38 -05:00
CydandClaude Fable 5 dd41a3a411 Firmware 31250 v2: widen the byte-scaled reply ACK-wait ($D9E7: 04->28)
Disassembly confirmed the bench theory: the no-ACK wait loop at $D9E0
self-clocks in byte times (each tick transmits an IDLE keep-alive and
re-enters on its TX-complete interrupt), so raising the baud silently
shrank the ACK grace from ~5.2ms to ~1.6ms - under USB turnaround,
hence the v1 retry storm. --widen-ackwait (requires --baud31250) sets
the limit to 40 ticks (~12.8ms at 31250). v2 image: 25 bytes changed,
sha256 420d4cfc...; re-disasm diff vs v1 is exactly the CMPA operand.
v1/classic hashes reproduce unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:45:40 -05:00
CydandClaude Fable 5 27a592da53 31250 bench run: wedge patch holds under retry storm; window is byte-scaled
127s mash at 31250: zero wedges — but 5655 framing resyncs, duplicate
replies (215% of poll slots) and AbandonCount=65 reveal the board's
reply ACK-wait scales with byte time: ~5+ms at 9600 (USB beats it,
zero framing) vs ~1.6ms at 31250 (USB cannot). All 65 retry
exhaustions self-recovered through the patched give-up path — the
strongest field proof of the latch fix yet; unpatched firmware would
have wedged on the first. Verdict recorded in ANALYSIS.md: cabinets
run the 9600 patched chip; 31250 stays a bench branch until the retry
window is widened in firmware.

Tool: before-snapshot now retries once (can lose the post-DTR boot
race, as this run showed); evidence log archived.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:36:23 -05:00
CydandClaude Fable 5 d8cac8927a Archive the bench A/B evidence logs (force past the riomash ignore)
testlogs/ carries the raw records behind the CONFIRMED verdict:
baseline wedged at 0.62s and stayed dead 300s; patched ran clean
through 152s of heavier mash, worst gap 0.58s self-recovered.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:22:55 -05:00
CydandClaude Fable 5 85b351a4b2 Firmware wedge patch CONFIRMED on real hardware — bench A/B results
Baseline (original chip): reply path wedged 0.62s into the run — the
tool's own version/check exchange colliding with analog polling was
enough, no mash required — and stayed dead for all 300s despite 951
button presses (no button revival; power cycle only). Patched chip:
survived the same startup collision, 2419 analog replies at a steady
~16/s over 152s under heavier mash (peak 635/min), zero wedges, worst
gap 0.58s self-recovered — the $DFF0 latch-clear stub doing its job.

Results table + evidence logs committed (rio-firmware/testlogs/).
Remaining: cabinet soak + native-game session; 31250 variant A/B.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:21:38 -05:00
CydandClaude Fable 5 df5804e835 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>
2026-07-17 20:25:00 -05:00
CydandClaude Fable 5 1fecd7e274 Firmware validation harness: instrumented RIO_TAP mash test in RioSerialMonitor
New --mash mode (tools/RioSerialMonitor/MashTest.cs) mechanizes the
wedge-patch validation plan from RIOv4_2-ANALYSIS.md:
- Runs the live link with the app's >5s reset-recovery DISABLED so a
  board wedge stays observable, and echoes lamps on every press
  (lamp/reply collisions are the wedge trigger).
- Gap timing uses ANY AnalogReply packet (0xFE sentinels included -
  a sentinel still proves the reply path is alive); logs a gap
  histogram + top-10 longest gaps with timestamps.
- WEDGE detector: analog silent past the threshold (default 2s) ->
  beep + banner; on resume, classifies self-recovered (patched
  expectation) vs button-revived (button event within 300ms of resume,
  the unpatched signature) vs unresolved at run end.
- Board self-reported RestartCount/AbandonCount/FullBufferCount
  snapshotted before/after via CheckRequest, delta printed
  (7-bit wrap-aware).
- Fixed-layout summary teed to riomash-<label>-<stamp>.log so
  baseline-vs-patched runs diff directly. Exit 0 = no wedge, 1 = wedge.

--mash --selftest drives the whole instrument against a scripted
in-memory board (SelftestTransport) that goes silent at t=4.0s and
revives 200ms after a button at t=6.5s: verified end-to-end - alarm at
6.0s, wedge classified button-revived (2.75s), counter delta +4/+0/+1,
verdict FAIL, exit 1. Use it to sanity-check the alarm at the cabinet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 14:35:27 -05:00
CydandClaude Fable 5 7d2987a344 RIO firmware: v4.2 EPROM dump, 68HC11 disassembly, reply-latch wedge patch
- RIOv4_2.bin: 64K image dumped from the board's AM27C512 (code at
  $C000-$FFFF, TMP68HC11).
- disasm_6811.py + RIOv4_2.disasm.asm: vector-rooted 68HC11 disassembly;
  SCI ISR at $D630 traced to the $2521 reply-in-progress latch leak that
  wedges the analog reply path under button-mash stress.
- make_patch.py + RIOv4_2_patched.bin: two in-place edits (abort-path stub
  at $DFF0, unconditional latch clear at $DA21) statically verified by
  re-disassembly diff. Dynamic proof awaits a burned W27C512.
- Analysis + burn/validation plan in RIOv4_2-ANALYSIS.md and README.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 09:29:33 -05:00