diff --git a/CLAUDE.md b/CLAUDE.md index 6d5bb35..0f2bb26 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1086,6 +1086,24 @@ Sources, so this can be re-checked rather than re-guessed: - stock libogc — the same, read out of `libbba.a` (`gcif.o`, `__bba_init`): `EXI_Imm(len=2)` of `42 00`, then `EXI_ImmEx(len=1)` of the data. +**They are NOT two protocols — only two amounts of padding.** This is worth +stating plainly, because "the menu and a game speak different protocols to the +same chip" is rightly suspicious and is not what happens. Both send the +*identical* 2-byte header `[0x40|reg, 0x00]`. They differ only in how many +bytes follow, and the device is length-agnostic — the data phase runs until CS, +exactly as in register space. Swiss's 4-byte version is an **EXI efficiency +choice**, not a different protocol: one `exi_imm_read_write(…, 4)` is a single +EXI immediate operation (two register pokes), where libogc2 spends two separate +`EXI_ImmEx` calls. For code injected into a running game, halving the EXI +operations per register access is worth a padding byte. The real BBA tolerates +both because it never cared about the length in the first place. + +Menu vs game is therefore not a protocol split, it is just which library is +linked: `cube/swiss/source/bba.c` contains **no BBA register access at all** +(its header exposes only network config, detection and display, over +``), so the menu is 100% libogc2; the patch driver is Swiss's own +code and spends fewer EXI operations. + **How one decoder serves both:** they share bytes 0 and 1, and differ only in how many bytes follow. So the device takes the **LAST data byte before CS rise** as the write value (Swiss sends `[00, val]`, libogc sends `[val]` — @@ -1132,8 +1150,17 @@ data phase has two meanings that cannot be told apart on the wire: 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: +for those, and auto-increment is wrong for Swiss, so **no single rule satisfies +both** and the real device's behaviour here cannot be deduced from the drivers. + +⚠️ **It is also unobservable in them**, which is why it has never mattered: +`priv->devid` is the hardcoded constant `0xD107`, is never read back from the +device, and `bba_cmd_out8(0x05, priv->acstart)` on the very next line writes +`0x05` separately anyway — so under auto-increment half of that write is +immediately overwritten. Neither driver ever reads `0x04`/`0x05`. Do not try to +settle this from source; it would need a real BBA on a logic analyser. + +It does not matter for us 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