Support BOTH command-space forms: Swiss's 4-byte and libogc's 2-byte
Reading Swiss's own driver (cube/patches/bba/bba.c) shows the previous commit
fixed libogc and BROKE Swiss. The two disagree, and both are real:
Swiss bba_cmd_out8: exi_imm_read_write(0x40<<24 | reg<<24 | val, 4)
-> ONE 4-byte transfer [0x40|reg, 00, 00, val], and bba_cmd_in8
returns the LOW byte, so a read response must be in BYTE 3.
libogc2 bba_cmd_outsnosel: req = (reg<<8)|0x4000;
EXI_ImmEx(&req, 2, WRITE); EXI_ImmEx(val, len, WRITE)
-> THREE bytes, value in byte 2, and a read takes byte 2.
stock libogc: identical to libogc2 (read out of libbba.a).
They share bytes 0 and 1 and differ only in how many bytes follow, so one
decoder serves both: take the LAST data byte before CS rise as the write value
(Swiss sends [00, val], libogc sends [val] -- last is val either way), and push
a read response TWICE so bytes 2 and 3 both carry it. Swiss clocks 4 bytes and
pops both; libogc clocks 3 and leaves one, which the next transaction's header
pops drain -- a 2-byte header gives exactly one drain slot, so the leftover is
bounded at one and cannot accumulate.
Critically this means NO auto-increment of cmd_reg across the data phase: that
applied Swiss's padding 00 to the register and val to reg+1, which is precisely
how the libogc-only version broke Swiss.
T12 covers the Swiss form and asserts bytes 2 AND 3; T10 keeps the libogc form.
Both mutation-tested: re-adding the auto-increment fails T12 with 0x00 in both
slots, and pushing the response once fails T12's byte 3. gc_bba_test gains
"cmd-space Swiss" alongside "cmd-space write", with bba_cmd_write4/read4.
Also corrects two things in CLAUDE.md now checkable against three drivers:
- NO driver writes TWD -- not Swiss, not libogc, not libogc2. The "GC sets
TWD before streaming" note was self-confirming: t_tx writes TWD because we
wrote t_tx. The counted TXDATA length is the primary path, not a fallback.
- Swiss's exi_dma_write rounds the length UP to 32 bytes (OSRoundUp32B), so
TXDATA gets up to 31 trailing bytes past the frame and a counted length sends
that much extra. Real hardware must do the same since Swiss works on it;
trailing padding past the IP total length is ignored. A 1514-byte frame
rounds to 1536 though, over the 1518 maximum.
Both drivers trigger TX with NCRA ST1, which the existing any-ST test accepts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -139,6 +139,35 @@ int bba_cmd_read(u8 creg)
|
||||
return (int)v;
|
||||
}
|
||||
|
||||
/* SWISS's command-space form: ONE 4-byte transfer, value in byte 3, and a
|
||||
* read takes byte 3 (the low byte of the 32-bit result). Swiss's
|
||||
* bba_cmd_out8/in8 use exi_imm_read_write(..., 4).
|
||||
*
|
||||
* This DIFFERS from bba_cmd_write/bba_cmd_read above, which use libogc's
|
||||
* 2-byte-header form. Both are real drivers and the device must serve both,
|
||||
* so both shapes are exercised. */
|
||||
int bba_cmd_write4(u8 creg, u8 val)
|
||||
{
|
||||
int rc;
|
||||
u32 w = ((u32)(0x40 | (creg & 0x3F)) << 24) | val;
|
||||
if ((rc = begin_raw()) < 0) return rc;
|
||||
if (EXI_Imm(BBA_EXI_CHAN, &w, 4, EXI_WRITE, NULL) <= 0) { end_raw(); return -3; }
|
||||
if (EXI_Sync(BBA_EXI_CHAN) <= 0) { end_raw(); return -4; }
|
||||
end_raw();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bba_cmd_read4(u8 creg)
|
||||
{
|
||||
int rc;
|
||||
u32 w = ((u32)(creg & 0x3F) << 24);
|
||||
if ((rc = begin_raw()) < 0) return rc;
|
||||
if (EXI_Imm(BBA_EXI_CHAN, &w, 4, EXI_READWRITE, NULL) <= 0) { end_raw(); return -3; }
|
||||
if (EXI_Sync(BBA_EXI_CHAN) <= 0) { end_raw(); return -4; }
|
||||
end_raw();
|
||||
return (int)(w & 0xFF); /* Swiss reads the LOW byte = byte 3 */
|
||||
}
|
||||
|
||||
int bba_r8(u16 addr)
|
||||
{
|
||||
u8 v;
|
||||
|
||||
Reference in New Issue
Block a user