Correct the framing: the two command forms are padding, not protocols
My earlier note read as "Swiss's menu and a patched game speak different protocols to the same chip", which is both suspicious-sounding and wrong. Both send the IDENTICAL 2-byte header [0x40|reg, 0x00] and differ only in how many bytes follow, which the device never cared about -- the data phase runs until CS, exactly as in register space. Swiss's 4-byte form is an EXI efficiency choice: one exi_imm_read_write(..., 4) is a single EXI immediate operation, 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. Menu vs game is not a protocol split either, 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 <network.h> -- so the menu is entirely libogc2, and the patch driver is Swiss's own leaner code. Verified: the only menu-side device access is EXI_GetID for detection and MX98730EC_GetExiSpeed, which just returns EXI_SPEED32MHZ (confirming Swiss hardcodes speed index 5 for the real BBA), while bba_requires_init() returns id != EXI_MX98730EC_ID, i.e. the real BBA needs no Swiss-side init. Also sharpens the multi-byte caveat. No single rule satisfies both Swiss's padded single-byte write and libogc2's bba_cmd_outs(0x04, &devid, 2), so the real device's behaviour there cannot be deduced from the drivers -- and it is unobservable in them anyway: devid is the hardcoded constant 0xD107, is never read back, and bba_cmd_out8(0x05, acstart) on the next line overwrites half of it under auto-increment. Settling it would need a real BBA on a logic analyser, so the note now says not to try it from source. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
`<network.h>`), 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
|
||||
|
||||
Reference in New Issue
Block a user