Fix the RX ring descriptor to the format libogc actually parses
The assembler wrote 00 00 len[11:8] len[7:0] with bytes 0 and 1 zero. The real format, read out of libogc's own BBA driver, is a PACKED 32-BIT LITTLE-ENDIAN word: next_packet_ptr in bits 0-11, packet_len in bits 12-23, status in bits 24-31. Under that driver our descriptor for a 342-byte frame decoded as a 12-byte frame with a next-pointer of 0 into the reserved page, so Swiss and anything else built on libogc would have initialised perfectly and then misparsed every received frame. Found by disassembling /opt/devkitpro/libogc/lib/cube/libbba.a (gcif.o, bba_interrupt) rather than by guessing: lwbrx r9,0,r9 # 4 bytes as a little-endian word rlwinm r4,r9,20,20,31 # packet_len = (word >> 12) & 0xFFF addi r4,r4,-4 # payload = packet_len - 4 cmpwi r4,1540 srwi r9,r9,24 # status = word >> 24 and. r9,r9,r18 # r18 = 0x..84 -> errors are 0x80 | 0x04 and the low 12 bits are written straight back to RRP (0x0018/0x0019), which is why next_packet_ptr has to be there at all -- it is the driver's read pointer. The length semantics and addressing were already correct (descriptor at page<<8, body at +4, length including the descriptor); only the packing was wrong and next_packet_ptr was never written. RXFrameAssembler now computes the next page BEFORE writing the descriptor (CALC_NEXT, formerly ADVANCE_RWP, moved ahead of the backfill) and writes bytes 0-3 as WRITE_D0..WRITE_D3. WRITE_D3 fixes a latent bug this exposed: WRITE_PLACEHOLDER issues four writes but the first lands twice, so desc_base+3 was NEVER written. That was harmless while the length write covered byte 3. As the status byte it would have been whatever the previous frame left in that cell, and a stale 0x80 or 0x04 makes the driver discard the frame. Readers updated to decode identically: netboot (which also now takes RRP from the descriptor's own next_packet_ptr, as libogc does, instead of recomputing the page span) and t_dma, including its page map. netboot's +0/+1 offset probe is removed -- the underrun that shifted descriptors is fixed and confirmed on console, and under a packed format a +1 read is not a shifted descriptor but garbage. The assembler's testbench now decodes with libogc_decode(), reproducing the instruction sequence above, so the tests check the DRIVER'S algorithm rather than our own packing. Every module testbench and bba_top at EXI_HALF=1/2/8 pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+6
-1
@@ -626,8 +626,13 @@ if __name__ == "__main__":
|
||||
|
||||
rwp = await exi_read(ctx, 0x16, 1) # RX write pointer (page)
|
||||
total_len = len(RX_FRAME) + 4
|
||||
RX_NEXT_PAGE = 2 # one-page frame written at page 1
|
||||
got = await exi_read(ctx, 0x0100, total_len) # descriptor + frame
|
||||
want = [0x00, 0x00, (total_len >> 8) & 0xFF, total_len & 0xFF] + RX_FRAME
|
||||
# The descriptor is a packed little-endian word, as libogc's driver
|
||||
# reads it: next_packet_ptr[11:0] | packet_len[23:12] | status[31:24].
|
||||
# See the format note in rx_frame_assembler.py.
|
||||
_desc_word = ((total_len & 0xFFF) << 12) | (RX_NEXT_PAGE & 0xFFF)
|
||||
want = [(_desc_word >> (8 * i)) & 0xFF for i in range(4)] + RX_FRAME
|
||||
print(f"T6 RWP=0x{rwp[0]:02X} (want 0x02)")
|
||||
print(f"T6 SPRAM[0x100]: {[f'0x{b:02X}' for b in got]}")
|
||||
print(f"T6 expected : {[f'0x{b:02X}' for b in want]}")
|
||||
|
||||
Reference in New Issue
Block a user