/* bba.h — raw EXI transport to the re-bba-rb adapter in Serial Port 1. * * Deliberately NOT libogc's bba network driver: this talks to the register * file directly so every check gets its own pass/fail and a failure points at * a specific register rather than at "networking". */ #ifndef BBA_H #define BBA_H #include /* Serial Port 1 == EXI channel 0, device 2. */ #define BBA_EXI_CHAN EXI_CHANNEL_0 #define BBA_EXI_DEV EXI_DEVICE_2 /* Register map (see CLAUDE.md "Key Registers"). */ #define REG_NCRA 0x00 #define REG_IMR 0x08 #define REG_IR 0x09 #define REG_RWP_LO 0x16 #define REG_RWP_HI 0x17 #define REG_RRP_LO 0x18 #define REG_PAR0 0x20 #define REG_PAR4 0x24 #define REG_NWAYS 0x31 #define REG_TWD_LO 0x34 #define REG_TWD_HI 0x35 #define REG_HIPR 0x3A #define REG_TXDATA 0x48 #define SPRAM_BASE 0x0100 /* NCRA bits */ #define NCRA_RESET 0x01 #define NCRA_ST0 0x02 #define NCRA_SR 0x08 /* IR bits */ #define IR_RI 0x02 #define IR_TI 0x04 /* Expected constants */ #define NWAYS_LINKUP 0x17 #define HIPR_PRESENT 0x01 /* EXI clock index, EXI_SPEED1MHZ(0) .. EXI_SPEED32MHZ(5). The nominal 32 MHz * index is really ~27 MHz on hardware (see CLAUDE.md); the capture domain * oversamples it 2x at 54 MHz. Settable so the suite can sweep it. */ extern u32 bba_speed; /* Microseconds to hold the clock idle between the header write and the data * phase, with CS still asserted. The register file decodes the header and * PROACTIVELY pushes the response into its TX FIFO during this gap; until the * first byte reaches the FIFO head the device drives MISO low. Measured on * hardware 2026-10-03: at EXI index 5 the reply arrived 22 bit-times (~815 ns) * late with no explicit gap, so a 4-byte read returned 00 00 00 10 -- the * correct stream, just shifted out of the window. 0 = whatever gap libogc's * inter-call overhead happens to give. */ extern u32 bba_gap_us; /* All return 0 on success, negative on an EXI-layer failure. */ /* REGISTER-space read: 4-byte header [0x80, ah, al, 0x00] then `len` bytes. * The real protocol has NO length field -- the data phase runs until CS, so * `len` is unbounded. The trailing 0x00 header byte is the device's prefetch * window. See docs/exi_protocol_real.md. */ int bba_read(u16 addr, void *buf, u32 len); /* REGISTER-space write: 4-byte header [0xC0, ah, al, 0x00] then `len` bytes. */ int bba_write(u16 addr, const void *buf, u32 len); /* EXI_GetID: write 0x0000 (two bytes) then read 4. Returns the device ID, * which is a ONE-SHOT -- the first NCRA reset clears it until power cycle. */ int bba_devid(u8 id[4]); /* Raw transaction framing, for probes that build their own byte sequence. */ 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); /* SPRAM / DMA-style read: any address >= 0x0100 streams until CS deasserts, * so `len` may exceed 4 and the header's 2-bit length field is ignored. */ int bba_stream(u16 addr, void *buf, u32 len); /* Stream `len` bytes into the TXDATA port. One byte per EXI transaction: * the register file's effective address auto-increments per data byte, so a * multi-byte write to 0x48 would spill into 0x49+ instead of the FIFO. */ int bba_tx_bytes(const u8 *buf, u32 len); #endif