diff --git a/CLAUDE.md b/CLAUDE.md index 9152577..83da879 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1110,6 +1110,48 @@ a fast path independent of this FSM. Tests: `bba_register_file` **T10** (libogc form) and **T12** (Swiss form, asserting bytes 2 AND 3), both mutation-tested — re-adding the auto-increment fails T12, and pushing the response once fails T12's byte 3. + +**This is ONE decoder, not two.** There is no driver detection, no mode flag +and no conditional on which driver is talking — grep the RTL with comments +stripped and the words "Swiss" and "libogc" do not appear. The unification is +that **Swiss's "4-byte transfer" is not a second protocol**: from the device's +side it is the same 2-byte header followed by a data phase that happens to be +2 bytes (`00, val`) rather than 1 (`val`). Command space was simply the last +place that still assumed a fixed transfer length — the same mistake register +space already avoids ("no length field, the data phase runs until CS"). Both +rules are therefore length-agnostic: last data byte wins, fill the first two +data slots. + +⚠️ **The residual ambiguity, which is real but currently inert.** A 2-byte +data phase has two meanings that cannot be told apart on the wire: + +``` +[0x42, 0x00, 0x00, val] Swiss -> cmd reg 2 = val (pad + value) +[0x42, 0x00, b0, b1 ] libogc2 -> cmd reg 2 = b0, 3 = b1 (two registers) +``` + +libogc2 really does multi-byte command writes — `bba_cmd_outs(0x04, +&priv->devid, 2)` runs unconditionally in its init. "Last byte wins" is wrong +for those, and auto-increment is wrong for Swiss. It does not matter today +because: +- the only command registers implemented are **0x02** (IMR) and **0x03** (IR), + and BOTH drivers access those a single byte at a time; and +- libogc2's multi-byte command accesses target `0x04`/`0x05` and + `0x08`/`0x09`, none of which are decoded — they fall through the `Switch` + and are ignored. + +So the decoder is correct for every register it implements. **If `0x04`/`0x05` +are ever implemented, the fix is per-register width knowledge (single-byte +registers take the last byte; multi-byte registers auto-increment), NOT a +driver mode.** Do not "resolve" the ambiguity by sniffing the transfer length. + +⚠️ **Do NOT implement the challenge/response handshake.** libogc2 reads a +4-byte challenge from command reg `0x08`, computes `bba_calc_response()` and +writes it to `0x09` — but only when the DEVICE raises status bit `0x10` in +command reg `0x03`. It is device-initiated, we never set that bit, so the path +never runs. Likewise `bba_cmd_out8(0x05, priv->acstart)` and the `0x0B` status +read only appear inside those handlers. Emulating any of it would be work for +a path that cannot be entered. NCRA, IR, NWAYS, RWP, RRP, PAR… all live in the REGISTER space (`bba_in8`/`bba_out8`/`bba_ins`/`bba_outs`). Only the device-ID query uses a short header — the single case where the two formats coincide.