Add on-console GameCube test suite + devkitPPC in the devcontainer

gc_bba_test/ builds a .dol that drives the adapter over raw EXI from the
console and reports pass/fail per test on the TV, navigable with the pad.

Uses libogc's EXI API against EXI0:2 (Serial Port 1) rather than its bba
network driver: driving the register file directly gives each check its own
verdict, so a failure points at a specific register instead of at
'networking'.  Six suites - identity, registers, reset/control, EXI link
integrity (including an EXI clock-index sweep), ethernet TX/RX, SPRAM/DMA
streaming.

Encodes the hardware lessons from bring-up so the app cannot mislead:
  * the device ID is a one-shot cleared by the first NCRA reset, so it is
    reported SKIP on a re-run rather than FAIL
  * TI means the frame reached the W5100, NOT the wire - the TX test says so
  * register reads clock exactly the requested length (over-clocking
    desynchronises the next transaction)
  * TXDATA is written one byte per transaction (eff_addr auto-increments)

.devcontainer/Dockerfile gains the devkitPro gamecube-dev group.  devkitPro
publishes no .deb on GitHub, so this uses their installer script against
apt.devkitpro.org -- which is 403 from inside the running container's egress
but reachable from a host-side docker build.  Rebuild the container to get it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 10:59:37 +02:00
parent f2a721cb1f
commit ccf4eb4996
8 changed files with 934 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
#ifndef TESTS_H
#define TESTS_H
#include <gccore.h>
#include <stddef.h>
typedef enum { T_PENDING = 0, T_PASS, T_FAIL, T_SKIP } tstatus_t;
#define TMSG_LEN 72
typedef struct {
const char *name;
const char *what; /* one line: what this proves */
int (*run)(char *msg, size_t n); /* 0 = pass, 1 = fail, 2 = skip */
tstatus_t status;
char msg[TMSG_LEN];
} test_t;
typedef struct {
const char *name;
const char *what;
test_t *tests;
int ntests;
} suite_t;
extern suite_t g_suites[];
extern const int g_nsuites;
/* Set once an NCRA reset has been issued this session. The device ID is a
* ONE-SHOT: reads of address 0 return it only until the first NCRA reset
* clears id_phase in the gateware, after which address 0 reads back NCRA.
* That is correct behaviour (it matches the GC's own init order), but it
* means the ID test can only pass once per console power cycle. */
extern int g_ncra_reset_done;
void tests_run_test(test_t *t);
void tests_run_suite(suite_t *s);
void tests_run_all(void);
void tests_reset_status(void);
void tests_tally(int *pass, int *fail, int *skip, int *pending);
#endif