Fix command-space writes, and replay libogc's real init sequence

Second protocol mismatch found the same way as the descriptor: by
disassembling libogc's own driver instead of trusting our notes.

COMMAND SPACE IS A 2-BYTE HEADER + DATA PHASE, not a single 4-byte transfer.
CLAUDE.md said [0x40|reg, 00, 00, data] and the decoder followed it, waiting
for a fourth byte and consuming the DATA byte as header byte 2 -- so every
command-space WRITE was silently dropped.  libogc's __bba_init writes command
register 2 (its interrupt mask) at both the start and the end of init, so none
of that took effect.  What it actually sends:

  EXI_Imm  (len=2, write) -> 42 00    the whole header, 0x4000 | (reg << 8)
  EXI_Sync
  EXI_ImmEx(len=1, write) -> 00       the data

Three bytes between CS fall and CS rise.  The device-ID read survived the wrong
decode only because SPIMode3Slave answers it on a fast path independent of this
FSM -- which is precisely why no test caught it: the only command-space traffic
under test bypassed the decoder being tested.

CHDR_2/CHDR_3 are replaced by CMD_WRITE, which takes the data byte straight
after header byte 1 and auto-increments the command register so a multi-byte
command write behaves like the register-space path.  cmd_wreg latches the
target because the write applies a cycle later, by which time cmd_reg has
moved on.  bba_register_file T10 writes command register 2 and reads it back,
and is mutation-tested: restoring the 4-byte decode fails it.

Also replaces the GUESSED init sequence in CLAUDE.md with the real transaction
list.  The old one was wrong in three ways that matter: libogc READS the MAC
out of PAR0-5 rather than writing one (so our reset value is what the console
uses), IMR is 0xDF not 0x86, and it writes RWP (0x0016/17) and RHBP (0x001A/1B)
which the register file does not accept.  The latter is harmless today -- RHBP
is 0x000F, matching our hardcoded 15-page ring -- but a driver configuring a
smaller ring would be ignored while the assembler kept writing outside it.

New gc_bba_test suite 7 "libogc init" replays the sequence on hardware:
cmd-space write (2-byte header, read back), MAC readable (one 6-byte PAR read,
Nintendo OUI), and init replay (all 30 writes in order, then NWAYS/HIPR/NCRA.SR
must still read correctly -- the old guessed header format turned a NWAYS read
into an NCRA reset, so a misdecoded write is a real risk).

bba.c gains bba_cmd_write/bba_cmd_read in libogc's shape.

Every module testbench and bba_top at EXI_HALF=1/2/8 pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 10:42:17 +02:00
parent d83f7beef8
commit 0aa1fa884a
5 changed files with 324 additions and 31 deletions
+6
View File
@@ -76,6 +76,12 @@ int bba_devid(u8 id[4]);
int begin_raw(void);
void end_raw(void);
/* COMMAND-space access: 2-byte header + data phase (3 bytes total for a
* single-byte write), the shape libogc uses. bba_cmd_read returns the byte
* or <0 on error. */
int bba_cmd_write(u8 creg, u8 val);
int bba_cmd_read(u8 creg);
/* Convenience single-byte helpers. bba_r8 returns the byte, or <0 on error. */
int bba_r8(u16 addr);
int bba_w8(u16 addr, u8 val);