feat(mii): store-and-forward TX path on a single packet FIFO + HW-validated deadlock fixes - #1
Merged
Merged
Conversation
Replace the TX length FIFO + accumulator with a single 9-bit packet FIFO
carrying {EOF, byte}, gated by a gray-coded committed-frame counter. This is
the same store-and-forward scheme mii_if and gmii_cdc's own RX path already
use, so both PHY adapters share one boundary mechanism.
The paced drain FSM is preserved byte-for-byte (start_delay prefetch intact);
the frame now ends on the EOF bit. Resource-neutral: BRAM unchanged (EOF uses
the spare 9th bit).
Lint clean; full sim regression green incl. GMII-CDC 1G/100M/10M. Not HW-tested
(Arty is MII-only).
New self-contained MII transmit path: one async frame FIFO carrying
{tlast, data} feeds a media-side framer (preamble/SFD/CRC/pad/FCS/IFG + nibble
output). It starts only once a whole frame is committed, so it cannot underrun:
the AXIS input may bubble freely with no wire underrun and no gmii_tx_er,
unlike cut-through eth_mac_tx.
Validated by tb_mii_tx_saf (MII-TX-SAF): byte-exact framing and recomputed FCS
under gaps and a mid-frame stall. Regression green.
The MII path now transmits through mii_tx_saf (single frame FIFO + media-clk framer) instead of the cut-through eth_mac_tx, so a bubbling TX AXIS source can no longer underrun the wire. eth_mac_tx is kept on the RGMII path. TX framing moves per-PHY into the generate branches; eth_stats byte/frame counts, STATUS.tx_active, the TX-done IRQ, and inbound-PAUSE TX gating are preserved (wire-byte semantics unchanged) via muxed tx_byte_ev/tx_frame_done_ev and mii_tx_saf.tx_start_ok. The csum TB reconstructs the frame from the MII nibbles. Full regression + both lint phases green.
IP_ADDR CSR (0x40) exposes the demo L3 IPv4 over AXI (default 192.168.137.200), so the host retargets the demo IP at runtime with no rebuild. The FCAPZ_DEBUG build adds an fpgacapZero EJTAG-AXI bridge (JTAG USER4) behind a verified 2:1 AXI-Lite arbiter (axil_arb2) for live CSR read/write over JTAG; the ELA now also probes the MII TX/RX pins. Used this to validate mii_tx_saf store-and-forward TX on Arty A7 end to end (ARP/ICMP/UDP replies, RX_ERR=0). Adds axil_arb2 and IP_ADDR tests; docs updated.
The 4-bit committed-frame counter wrapped once 16 frames backed up in the 4 KB FIFO, so frame_pending read 0 and the framer deadlocked with a full FIFO and TX frozen. Widen the counter and gray CDC to FIFO_ADDR_WIDTH+1 bits so it cannot wrap before the FIFO backpressures. New regression tb_mii_tx_saf_burst_stall (4/20 -> 20/20). A separate load-dependent FIFO-desync wedge remains; see docs/missing_features.md.
The write side committed only on tlast, with no bound on the uncommitted run. A no-tlast run reaching the FIFO depth (an oversized frame, or frames merged by a dropped tlast) filled the FIFO with uncommitted data: frame_pending never rose, the framer parked in idle, and TX deadlocked permanently. Cap the in-flight run at MAX_FRAME (force a synthetic EOF, drop the runaway tail); MAX_FRAME < FIFO depth so the framer always progresses. Add regression tb_mii_tx_saf_oversize and a read-only SAF_DBG CSR (0x94) mirroring framer/FIFO state for on-hardware diagnosis.
On the MII branch mii_tx_saf drives the TX pins and mii_if is used only for RX, but its TX data FIFO was still instantiated and Vivado kept the XPM FIFO's RAMB36 even with the write side tied off. Add a TX_ENABLE parameter (default 1, so eth_mac.v and the MII TX testbenches are unchanged) guarding only the u_tx_fifo instantiation, and set TX_ENABLE=0 in eth_mac_sys's MII branch. The framer, IOB and debug taps stay at module level and self-drive to idle. Reclaims one RAMB36 (6.5 to 5.5 tiles), timing still met (WNS +0.360 ns).
SAF_DBG (0x94) was undocumented and the C header was missing both IP_ADDR (0x40) and SAF_DBG. Add both to registers.md, README, and emaczero.h, with the SAF_DBG bit layout. CHANGELOG: drop the stale note claiming the mii_if TX FIFO is only tied off (it is now compiled out via TX_ENABLE=0, reclaiming the BRAM), and record the two mii_tx_saf TX-deadlock fixes plus the IP_ADDR/SAF_DBG CSRs and axil_arb2.
TX path now shows eth_mac_tx (RGMII) / mii_tx_saf (MII); the PHY interface block shows MII: mii_tx_saf + mii_if vs RGMII: gmii_cdc + rgmii_if, reflecting mii_if now being RX-only on MII. Regenerated the SVG from the JSON spec via the hdldiagzero renderer.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks the MII transmit path onto a store-and-forward, single packet FIFO
(
mii_tx_saf), replacing the old cut-throughmii_ifTX. The framer only startsa frame once the whole frame is committed to the FIFO, so it can never underrun
and the AXIS input may bubble (deassert
tvalidmid-frame) with no wire error.Along the way this adds the on-hardware debug path used to root-cause two TX
deadlocks on an Arty A7-100T, fixes both, and reclaims the now-dead
mii_ifTXFIFO BRAM.
gmii_cdc(RGMII path) is likewise unified onto an EOF-sidebandpacket FIFO with the separate length FIFO removed.
What's included
New RTL
rtl/mii_tx_saf.v— store-and-forward MII TX core: one async frame FIFO(
{tlast,data}) + media-clock framer (preamble / SFD / CRC-32 / pad / FCS /IFG). Gray-coded committed-frame counter gates frame start → no underrun,
tolerates AXIS bubbles.
rtl/axil_arb2.v— 2:1 AXI-Lite arbiter for the JTAG debug path.gmii_cdc— unified TX on an EOF-sideband packet FIFO; dropped the lengthFIFO.
Bug fixes (both found and reproduced on hardware)
d79d1d0). A 4-bit counter aliased to afalse "equal" once 16 frames backed up in the 4 KB FIFO, parking the framer
in idle. Fixed by widening it to
FIFO_ADDR_WIDTH+1bits. Regressiontb_mii_tx_saf_burst_stall.e6d8a95). The write side committedonly on
tlastwith no bound on the uncommitted run. A no-tlastrunreaching the FIFO depth (an oversized frame, or frames merged by a dropped
tlastupstream) filled the FIFO with uncommitted data:frame_pendingneverrose, the framer parked in idle,
wr_fullstuck, and the whole TX pathdeadlocked permanently. Fixed by capping the in-flight run at
MAX_FRAME(force a synthetic EOF, drop the runaway tail) — since
MAX_FRAME< FIFOdepth, a permanent wedge is now structurally impossible. Regression
tb_mii_tx_saf_oversize.Debug infrastructure (
dc1b307)IP_ADDRCSR (0x40) — demo L3 IPv4 made AXI-writable (retarget the board'sIP over JTAG without a rebuild).
SAF_DBGCSR (0x94, RO) — mirrors themii_tx_safframer/FIFO state intothe sys domain (committed/drained frame counts,
rd_empty, framer state) foron-hardware diagnosis. This is what pinned down bug verify: cocotb datapath suite + 13 RTL fixes across gmii_cdc / eth_mac_rx / mii_tx_saf #2.
axil_arb2— CSR access over JTAG (USER4) alongside theELA/EIO.
Resource cleanup (
67b71d1)mii_ifgains aTX_ENABLEparameter (default 1). The MII branch ineth_mac_syssetsTX_ENABLE=0(theremii_tx_safdrives the pins), so thedead
mii_ifTX FIFO is no longer instantiated. Block RAM 6.5 → 5.5 tiles;the TX path now has exactly one physical FIFO.
Testing
iverilog -WallandVerilator lint clean. New TBs:
tb_mii_tx_saf,tb_mii_tx_saf_burst_stall,tb_mii_tx_saf_oversize,tb_axil_arb2.(echo loss ~99%, TX frozen) now sustains 300–400 Mbps at <1% loss, with
SAF_DBGreturning to clean idle after every burst andRX_ERR=0.Scope / notes
TX_ENABLE=1keeps the legacyeth_mac.vwrapper and all MII TXtestbenches unchanged.
unified internally.
docs/registers.md(new CSRs),docs/missing_features.md(Known Issues → resolved),
README.md,fpga/arty_a7/README.md,CHANGELOG.md.