fix(tx): queue the frame length at TWD_HI so the drain runs concurrently

TXFrameDrain sat in IDLE until it had a length, and the length only reached
tx_ctrl when the NCRA ST bits were written -- after the GC had streamed the
whole frame.  So the entire frame had to fit in the 16-deep tx_bytes FIFO, and
BBARegisterFile silently drops bytes when w_rdy is low (SPI cannot
back-pressure).  On hardware this truncated frames at exactly 16 bytes: a
captured ARP had 16 correct bytes followed by the frame restarting over itself.

The length is now handed to the drain one cycle after the TWD_HI (0x35) write,
which the GC issues BEFORE streaming data.  The drain starts early and blocks
on tx_bytes_r_rdy, consuming bytes as they arrive, so tx_bytes becomes a
rate-matching buffer instead of whole-frame storage.  The ST write remains a
fallback trigger for software that skips TWD, guarded by tx_queued so one frame
is never queued twice.

Adds BBATop T8: streams a 34-byte frame (> the 16-deep FIFO) over EXI and
checks the W5100 model received it byte-for-byte.  Verified to FAIL without the
fix with exactly the hardware symptom -- 16/34 bytes, first bad byte at index
16.  The gap that let this ship: TXFrameDrain's own tests drive the FIFO
signals directly, and the BBATop test only covered the RX loop.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 18:49:04 +00:00
parent d669917cfe
commit 80957f35db
3 changed files with 75 additions and 2 deletions
+8 -1
View File
@@ -6,7 +6,14 @@ to notify the GC that the transmit is complete.
Flow
----
1. Wait for tx_len FIFO to have a length word (signals a complete frame queued).
1. Wait for tx_len FIFO to have a length word.
NOTE the length arrives when the GC writes TWD_HI (0x35), i.e. BEFORE it
streams the frame bytes -- not at the NCRA ST trigger. So this FSM starts
early and blocks in DRAIN on tx_bytes_r_rdy, consuming bytes as the GC
writes them. That is deliberate: tx_bytes is only 16 deep, so waiting for
ST (after the whole frame had been written) silently dropped everything past
byte 16 -- observed on hardware as frames truncating at exactly 16 bytes.
2. Pop the length from tx_len FIFO.
3. Assert tx_sof on first byte, tx_eof on last byte, consuming tx_bytes FIFO.
4. When W5500SPIMaster accepts the final byte: pulse tx_irq.