netboot: hold the screen on failure, dump the descriptor, shrink the block
Two separate problems, one of which was hiding the other. 1. The diagnostics were unreadable. do_netboot() printed them and returned, and the caller's draw_main() redrew immediately and wiped the screen -- so two consecutive failures were reported only as "a short flash" with no detail, and the error code alone was not enough to act on. nb_pause() now holds the screen until a button is pressed, on every failure path. This cost two blind round trips, each of which needs a hand copy of the .dol to the SD card. Printing a diagnosis and then erasing it is worse than not printing one. 2. The default block was 1024 bytes, making ~1050-byte frames that span FIVE of the SPRAM ring's 15 pages. The only multi-page frame ever proven on this hardware is the 342-byte DHCP broadcast from bring-up, which spans two. Five-page frames are untested territory, and a transfer is the wrong place to discover a wrap bug. Default is now 256 bytes -> ~296-byte frame -> two pages, deliberately close to the proven case. --block raises it once small blocks work; the GC still caps at NB_BLOCK_MAX = 1024. ring_next() also keeps the four raw descriptor bytes and the page it read them from, and the error path prints them. When a length is rejected those bytes ARE the diagnosis: 00 00 xx xx tells us the assembler wrote a descriptor and the length is simply unexpected, whereas garbage tells us we are reading the wrong page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+14
-3
@@ -25,7 +25,13 @@ import time
|
||||
ETHERTYPE = 0x88B5
|
||||
MAGIC = b"GCUP"
|
||||
OP_DATA, OP_ACK, OP_DONE = 1, 2, 3
|
||||
BLOCK = 1024
|
||||
# Default payload 256 bytes -> a ~296-byte frame, which with the 4-byte
|
||||
# descriptor occupies TWO of the SPRAM ring's 15 pages. That is deliberately
|
||||
# close to the only multi-page frame ever proven on this hardware (a 342-byte
|
||||
# DHCP broadcast). 1024-byte payloads make ~1050-byte frames spanning FIVE
|
||||
# pages, which has never been exercised -- raise --block once small blocks are
|
||||
# known to work, not before.
|
||||
BLOCK_DEFAULT = 256
|
||||
HDR = 26
|
||||
# The GC's MAC comes from PAR0-5, which the gateware pre-populates with a
|
||||
# Nintendo OUI. Discovered from the first ACK, so this is only the initial
|
||||
@@ -54,10 +60,15 @@ def main():
|
||||
ap.add_argument("--dest", default="/gc_bba_test.dol",
|
||||
help="where to write it on the SD card "
|
||||
"(default /gc_bba_test.dol)")
|
||||
ap.add_argument("--block", type=int, default=BLOCK_DEFAULT,
|
||||
help=f"payload bytes per frame (default {BLOCK_DEFAULT}; "
|
||||
"the GC caps it at 1024)")
|
||||
args = ap.parse_args()
|
||||
|
||||
if not 1 <= args.block <= 1024:
|
||||
sys.exit("--block must be 1..1024 (the GC's NB_BLOCK_MAX)")
|
||||
img = open(args.dol, "rb").read()
|
||||
blocks = [img[i:i + BLOCK] for i in range(0, len(img), BLOCK)]
|
||||
blocks = [img[i:i + args.block] for i in range(0, len(img), args.block)]
|
||||
if not blocks:
|
||||
sys.exit("empty image")
|
||||
if len(blocks) > 0xFFFF:
|
||||
@@ -68,7 +79,7 @@ def main():
|
||||
src = s.getsockname()[4]
|
||||
s.settimeout(args.timeout)
|
||||
|
||||
print(f"{args.dol}: {len(img)} bytes, {len(blocks)} blocks of {BLOCK}")
|
||||
print(f"{args.dol}: {len(img)} bytes, {len(blocks)} blocks of {args.block}")
|
||||
print(f"sending from {src.hex(':')} on {args.iface}")
|
||||
|
||||
dst = BROADCAST
|
||||
|
||||
Reference in New Issue
Block a user