Files
rebbarb/gc_bba_test
Roflin abc61f3e66 gc_bba_test: add header->data idle gap; device replies 22 bit-times late
First on-console run: the Identity suite failed with the device ID reading
00 00 00 10 instead of 04 02 02 00.  Bit analysis shows that is an EXACT
match for the correct stream delayed by 22 bits -- the device answers
correctly, just too late for a 32-clock window to catch more than its first
set bit.  Not corruption, and not a broken link: response latency.

At EXI index 5 (~27 MHz) 22 bit-times is ~815 ns, which is about what the CDC
chain costs (rx AsyncFIFO capture->exi, register-file decode, tx AsyncFIFO
exi->capture, SPI engine) at a 24 MHz exi clock.  The design expects the GC to
hold the clock idle between the header write and the data read so the register
file can prefetch the response; libogc's inter-call overhead alone is not
enough at full speed.

Adds bba_gap_us (default 16 us, busy-waited with CS asserted since we hold the
EXI lock) and a Gap sweep test that reports the minimum clean gap at the
current speed -- which measures the latency rather than guessing at it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-03 11:37:00 +02:00
..

re-bba-rb — on-console test suite (GameCube)

A .dol you run from Swiss that drives the adapter in Serial Port 1 and reports pass/fail per test on the TV.

Build

Needs devkitPro's gamecube-dev group (devkitPPC + libogc). The devcontainer installs it — if DEVKITPPC is unset, rebuild the container, since the toolchain is added in .devcontainer/Dockerfile.

make            # -> gc_bba_test.dol

Copy the .dol to your SD card (SD Gecko / SD2SP2) and launch it from Swiss.

Controls

Button
D-pad up/down move
A open a suite / rerun the selected test
X run the selected suite
START run everything
Y clear all results
B back

What it tests

Suite Proves
Identity device enumerates: 04 02 02 00, HIPR, NWAYS
Registers PAR0–5, IMR writable and read back; IR is write-1-clear
Reset/control NCRA RESET self-clears, SR holds
EXI integrity 200 reads with no bit errors; which EXI clock indices work
Ethernet MAC readback, 60-byte ARP transmit (TI), frame receive (RWP/RI)
SPRAM/DMA ring descriptor is well-formed; reads ≥ 0x100 stream until CS

Things that will bite you

The device ID is a ONE-SHOT. Address 0 returns 04 02 02 00 only until the first NCRA reset clears id_phase in the gateware; after that it reads back NCRA. That is correct — it matches the GC's own init order — but it means the Identity test can only pass once per console power cycle. Run it before the Reset suite. On a re-run the app reports SKIP with an explanation rather than a misleading failure.

TI is not proof of transmission. It only means TXFrameDrain handed the frame to the W5100. A frame can set TI and never reach the wire. The TX test says so; to confirm the wire, capture on a PC or watch the RX test pick up a reply.

The RX test needs traffic. It waits ~2 s for any frame. On an isolated link with nothing talking it will fail legitimately — give the PC an address on the same subnet (the ARP the TX test sends is aimed at 10.0.0.50, so sudo ip addr add 10.0.0.50/24 dev <nic> makes the PC answer it and both tests pass together).

Never over-clock a register read. Asking for N bytes and clocking more leaves stale prefetched bytes queued and desynchronises the next transaction — a deterministic every-Nth-read corruption that looks like a signal-integrity fault. bba_read() clocks exactly len; don't "round up" for convenience.

TXDATA takes one byte per transaction. The register file's effective address auto-increments per data byte, so a 4-byte write to 0x48 would spill into 0x49–0x4B. bba_tx_bytes() does it correctly.

Build status

Builds clean (no warnings) with devkitPPC 16.1.0 / GCC 16 in the devcontainer: gc_bba_test.dol, ~172 KB, entry 0x80003100.

.gitignore excludes the build products — run make to produce the .dol.