gc_bba_test: add raw slot dumps to locate the response
Reading one byte and getting 0x00 cannot distinguish 'decode is wrong' from 'reply is late' -- a one-byte window has nowhere for a late answer to show up. These two probes clock EIGHT data bytes and print every slot, so the position of 0x17 (NWAYS) or 0x04 (device ID) gives the latency directly, the same way bit-shift analysis turned 00 00 00 10 into 'correct, 22 bits late'. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,9 @@
|
|||||||
#include <ogc/lwp_watchdog.h>
|
#include <ogc/lwp_watchdog.h>
|
||||||
|
|
||||||
u32 bba_speed = EXI_SPEED32MHZ; /* nominal name; ~27 MHz in reality */
|
u32 bba_speed = EXI_SPEED32MHZ; /* nominal name; ~27 MHz in reality */
|
||||||
|
static int begin(void);
|
||||||
|
static void end(void);
|
||||||
|
|
||||||
u32 bba_gap_us = 16; /* see bba.h -- 0 reproduces the raw failure */
|
u32 bba_gap_us = 16; /* see bba.h -- 0 reproduces the raw failure */
|
||||||
|
|
||||||
/* Busy-wait, not usleep(): we are holding the EXI lock with CS asserted, so
|
/* Busy-wait, not usleep(): we are holding the EXI lock with CS asserted, so
|
||||||
@@ -23,6 +26,9 @@ static void gap(void)
|
|||||||
* write [0xC0, addr>>8, addr&0xFF, 0x00] + N bytes
|
* write [0xC0, addr>>8, addr&0xFF, 0x00] + N bytes
|
||||||
* The trailing 0x00 is the device's prefetch window: the address completes a
|
* The trailing 0x00 is the device's prefetch window: the address completes a
|
||||||
* whole byte before the data phase so the register file can fetch in time. */
|
* whole byte before the data phase so the register file can fetch in time. */
|
||||||
|
int begin_raw(void) { return begin(); }
|
||||||
|
void end_raw(void) { end(); }
|
||||||
|
|
||||||
static int begin(void)
|
static int begin(void)
|
||||||
{
|
{
|
||||||
int tries;
|
int tries;
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ int bba_write(u16 addr, const void *buf, u32 len);
|
|||||||
* which is a ONE-SHOT -- the first NCRA reset clears it until power cycle. */
|
* which is a ONE-SHOT -- the first NCRA reset clears it until power cycle. */
|
||||||
int bba_devid(u8 id[4]);
|
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);
|
||||||
|
|
||||||
/* Convenience single-byte helpers. bba_r8 returns the byte, or <0 on error. */
|
/* Convenience single-byte helpers. bba_r8 returns the byte, or <0 on error. */
|
||||||
int bba_r8(u16 addr);
|
int bba_r8(u16 addr);
|
||||||
int bba_w8(u16 addr, u8 val);
|
int bba_w8(u16 addr, u8 val);
|
||||||
|
|||||||
@@ -186,6 +186,41 @@ static int t_gap_sweep(char *m, size_t n)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int t_raw_reg(char *m, size_t n)
|
||||||
|
{
|
||||||
|
/* Clock EIGHT data bytes for a one-byte register read and show them all.
|
||||||
|
* A correct device puts NWAYS (0x17) in slot 0. If it shows up later the
|
||||||
|
* reply is merely LATE and the slot index gives the latency directly; if
|
||||||
|
* it never appears the decode is wrong, not slow. */
|
||||||
|
u8 b[8];
|
||||||
|
int i, at = -1;
|
||||||
|
if (bba_read(REG_NWAYS, b, sizeof(b)) < 0) { snprintf(m, n, "EXI error"); return 1; }
|
||||||
|
for (i = 0; i < 8; i++) if (b[i] == NWAYS_LINKUP) { at = i; break; }
|
||||||
|
snprintf(m, n, "%02X %02X %02X %02X %02X %02X %02X %02X | 0x17 %s%d",
|
||||||
|
b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],
|
||||||
|
at < 0 ? "absent" : "at slot ", at < 0 ? 0 : at);
|
||||||
|
return at == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int t_raw_id(char *m, size_t n)
|
||||||
|
{
|
||||||
|
/* Same for the device ID: 2-byte header, then clock 8 instead of 4. */
|
||||||
|
u8 b[8];
|
||||||
|
int i, at = -1, rc;
|
||||||
|
u16 h = 0x0000;
|
||||||
|
if ((rc = begin_raw()) < 0) { snprintf(m, n, "EXI error %d", rc); return 1; }
|
||||||
|
EXI_Imm(BBA_EXI_CHAN, &h, 2, EXI_WRITE, NULL);
|
||||||
|
EXI_Sync(BBA_EXI_CHAN);
|
||||||
|
memset(b, 0, sizeof(b));
|
||||||
|
EXI_ImmEx(BBA_EXI_CHAN, b, sizeof(b), EXI_READ);
|
||||||
|
end_raw();
|
||||||
|
for (i = 0; i < 8; i++) if (b[i] == 0x04) { at = i; break; }
|
||||||
|
snprintf(m, n, "%02X %02X %02X %02X %02X %02X %02X %02X | 0x04 %s%d",
|
||||||
|
b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],
|
||||||
|
at < 0 ? "absent" : "at slot ", at < 0 ? 0 : at);
|
||||||
|
return at == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* ───────────────────────── suite 5: ethernet ───────────────────────── */
|
/* ───────────────────────── suite 5: ethernet ───────────────────────── */
|
||||||
|
|
||||||
static u8 g_mac[6] = {0x00,0x09,0xBF,0x00,0x00,0x01};
|
static u8 g_mac[6] = {0x00,0x09,0xBF,0x00,0x00,0x01};
|
||||||
@@ -324,6 +359,8 @@ static test_t s_exi[] = {
|
|||||||
{"200x read", "no bit errors over 200 register reads", t_repeat, T_PENDING, {0}},
|
{"200x read", "no bit errors over 200 register reads", t_repeat, T_PENDING, {0}},
|
||||||
{"Speed sweep", "which EXI clock indices are reliable (0..5)", t_speed_sweep, T_PENDING, {0}},
|
{"Speed sweep", "which EXI clock indices are reliable (0..5)", t_speed_sweep, T_PENDING, {0}},
|
||||||
{"Gap sweep", "min header->data idle gap the device needs", t_gap_sweep, T_PENDING, {0}},
|
{"Gap sweep", "min header->data idle gap the device needs", t_gap_sweep, T_PENDING, {0}},
|
||||||
|
{"Raw reg dump", "8 slots of a NWAYS read - WHERE does 0x17 land?", t_raw_reg, T_PENDING, {0}},
|
||||||
|
{"Raw ID dump", "8 slots of the device-ID query - where is 0x04?", t_raw_id, T_PENDING, {0}},
|
||||||
};
|
};
|
||||||
static test_t s_eth[] = {
|
static test_t s_eth[] = {
|
||||||
{"MAC readback", "PAR0-5 hold a Nintendo-OUI MAC", t_mac_read, T_PENDING, {0}},
|
{"MAC readback", "PAR0-5 hold a Nintendo-OUI MAC", t_mac_read, T_PENDING, {0}},
|
||||||
@@ -339,7 +376,7 @@ suite_t g_suites[] = {
|
|||||||
{"Identity", "device enumerates and reports itself", s_identity, 3},
|
{"Identity", "device enumerates and reports itself", s_identity, 3},
|
||||||
{"Registers", "register file is readable and writable", s_regs, 4},
|
{"Registers", "register file is readable and writable", s_regs, 4},
|
||||||
{"Reset/control", "NCRA reset and control bits behave", s_reset, 2},
|
{"Reset/control", "NCRA reset and control bits behave", s_reset, 2},
|
||||||
{"EXI integrity", "the EXI link is error-free, and how fast", s_exi, 3},
|
{"EXI integrity", "the EXI link is error-free, and how fast", s_exi, 5},
|
||||||
{"Ethernet", "frames get to and from the W5100", s_eth, 3},
|
{"Ethernet", "frames get to and from the W5100", s_eth, 3},
|
||||||
{"SPRAM/DMA", "bulk reads stream correctly from the ring", s_spram, 2},
|
{"SPRAM/DMA", "bulk reads stream correctly from the ring", s_spram, 2},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user