Two coupled fixes, both exposed by batching TXDATA writes in the test app.
1. eff_addr advanced on EVERY data byte of a register-space write. But
TXDATA (0x48) is a FIFO PORT, not a register: a whole frame is written to
that one address. So an 8-byte write put byte 0 in TXDATA and bytes 1..7
into 0x49+, which the switch silently ignores. The frame was an eighth of
its declared length, TXFrameDrain blocked waiting for the rest, and TI
never set (hardware: txto=16, "no ACK after 20 tries").
SWISS WOULD HAVE HIT THIS. It writes an entire frame with bba_outs to
BBA_WRTXFIFOD -- one transaction, one address -- so its TX would have
delivered ONE BYTE per frame. The path was never exercised because the
test app wrote TXDATA one byte per EXI transaction, giving every byte a
fresh header at 0x48. Every other register must still advance, so that
bba_outs can write PAR0-5 or MAR0-7 as a block; the exception is TXDATA
only.
2. tx_bytes was 16 deep. SPI cannot back-pressure -- there is no way to tell
the GC to wait -- so BBARegisterFile silently drops bytes when w_rdy is
low, which makes the depth the only thing between a drain stall and a
corrupted frame, not a buffering preference. 16 bytes is ~4.7 us at the
EXI byte rate, and TXFrameDrain shares the W5100 bus arbiter with RX and
the socket-3 UDP test, so any longer stall truncated a frame mid-flight.
With (1) fixed, Swiss streams up to 1514 bytes in a single transaction, so
16 could never have held.
Now 2048: a whole maximum-size frame plus margin, so a frame cannot be
truncated even if the drain makes no progress for the entire transaction.
Costs 3 of 27 free BRAMs (ICESTORM_RAM 3/30 -> 6/30, LC 68% -> 70%).
Dennis spotted that the 8-byte workaround could not survive whole-frame
writes, which is what prompted fixing the depth rather than shipping it.
bba_tx_bytes() consequently streams 64-byte chunks (bba_write()'s buffer
limit), so a 60-byte ACK is ONE transaction instead of sixty.
T8 covers both and is mutation-tested: restoring the increment gives
"1/8 bytes MISMATCH -- got [17], want [17, 34, 51, ...]". It now writes 64
bytes so it exercises the deepened FIFO too.
--seeds 8: clk 27.6-29.4 MHz, EXI 51.2-64.7 MHz, 8/8 PASS. Best seed 1
(clk 29.35, EXI 60.80), flashed.
STILL NO FLOW CONTROL on the TX path: a frame larger than 2048 would drop
silently rather than error. Fine for ethernet's 1518 ceiling; revisit if the
multiworld socket work ever wants larger payloads.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>