Document that the command decoder is one mechanism, and its real limit
Records why supporting both command-space forms is a single decoder rather than two paths, and where that abstraction genuinely stops. The unification: 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) instead of 1 (val). Command space was the last place still assuming a fixed transfer length, which register space already avoids. Both rules are length-agnostic -- last data byte wins, fill the first two data slots -- so there is no driver detection, no mode flag, and with comments stripped the words "Swiss" and "libogc" do not appear in the RTL. The limit, which is real but inert: a 2-byte data phase means "pad + value" (Swiss) or "two consecutive registers" (libogc2), and those cannot be told apart on the wire. libogc2 does do multi-byte command writes -- bba_cmd_outs(0x04, &priv->devid, 2) runs unconditionally in its init -- so 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), which both drivers access one byte at a time, while libogc2's multi-byte accesses target 0x04/0x05 and 0x08/0x09, none of which are decoded. If 0x04/0x05 are ever implemented the fix is per-register width knowledge, not a driver mode -- noted so nobody resolves it by sniffing transfer length. Also records that the challenge/response handshake must NOT be implemented: libogc2 reads a 4-byte challenge from command reg 0x08 and writes the response 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 cannot be entered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1110,6 +1110,48 @@ a fast path independent of this FSM.
|
|||||||
Tests: `bba_register_file` **T10** (libogc form) and **T12** (Swiss form,
|
Tests: `bba_register_file` **T10** (libogc form) and **T12** (Swiss form,
|
||||||
asserting bytes 2 AND 3), both mutation-tested — re-adding the auto-increment
|
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.
|
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
|
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
|
(`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.
|
short header — the single case where the two formats coincide.
|
||||||
|
|||||||
Reference in New Issue
Block a user