Cut dead signals and the unused W5100 debug peek

An audit for signals that are written but never read turned up three things no
longer connected to anything.  All verified unreferenced across every module,
testbench and script before removal.

  exi_capture      cs_n_prev          registered on sync, read by nothing.
  w5100            udp_rx_sof         driven in the UDP rx stream mux; no
                                      consumer uses it.  uart_shell needs only
                                      data/valid/eof, because the request
                                      frames the transfer.  The MACRAW rx
                                      interface keeps its sof -- the frame
                                      assembler does need it.
  w5100            the debug peek      4 ports, 2 FSM states (DBG_RD/DBG_RD_W)
                                      and a branch in the IDLE arbiter's
                                      priority chain.  dbg_rd_req was driven by
                                      nothing -- not even its own testbench --
                                      so this was untested logic sitting in the
                                      path that decides what the bus master
                                      does next.

Kept deliberately, against the audit: the unused register-address constants in
both ethernet masters (_IR, _TMSR, _S0_SR, _S0_TX_FSR, _S0_TX_RD and the three
W5500 buffer ones).  They cost no logic and they document the chip's register
map in one place; that map was the source of three hardware bugs, and a partial
map invites re-guessing the missing half.  Same for status_panel's eth_rst_n,
which is a documented panel feature synth.py has not wired yet -- a gap, not
dead weight.  And rx_frame_assembler's geom_honoured, which is one comb line
asserting a property the tests otherwise could not observe.

Also fixed the register file's opening docstring, which claimed the module did
"three jobs" and invited splitting it into three.  It does not: the interrupt
level is IR & IMR, a frame arriving is a register side effect, and the read mux
feeds the TX stream combinationally in the cycle the FSM pushes it.  Those are
facets of one job that share the register bank, not separable parts.  _read_mux
now records why that path must stay unregistered -- one pipeline register there
is 42 ns against a 296 ns byte budget, which is the tx FIFO underrun that the
+1 descriptor hunt ended in.

Full suite passes; bba_top T9 6/6 at EXI_HALF=1, 2 and 8; W5100 elaborates with
enable_udp_test both ways.  Sweep: 8/8 seeds PASS, best seed 3 at clk 29.08 MHz
(1.21x the 24 MHz target), and area down again:

    ICESTORM_LC   4350 original -> 4328 after the rx_rptr cut -> 4305 now

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 19:42:02 +02:00
parent dac9c0c065
commit 41d487e1a7
3 changed files with 18 additions and 34 deletions
-25
View File
@@ -203,7 +203,6 @@ class W5100ParallelMaster(Elaboratable):
self.udp_rx_none = Signal()
self.udp_rx_data = Signal(8)
self.udp_rx_valid = Signal()
self.udp_rx_sof = Signal()
self.udp_rx_eof = Signal()
self.udp_rx_ready = Signal()
@@ -222,13 +221,6 @@ class W5100ParallelMaster(Elaboratable):
self.init_req = Signal()
self.init_done = Signal()
# Debug register peek (bring-up diagnostics): pulse dbg_rd_req with
# dbg_rd_addr set; dbg_rd_data is valid when dbg_rd_done pulses. Reads
# one byte over the indirect bus, reusing the fixed-length read path.
self.dbg_rd_req = Signal()
self.dbg_rd_addr = Signal(16)
self.dbg_rd_data = Signal(8)
self.dbg_rd_done = Signal()
self.par = Signal(48) # MAC address (PAR0..5 packed)
# NCRB.PR from the GC. Low (the normal case) means MACRAW filters to
# own-MAC + broadcast, which is what the real BBA does -- see the
@@ -353,7 +345,6 @@ class W5100ParallelMaster(Elaboratable):
with m.If(udp_rx_streaming):
m.d.comb += [self.udp_rx_data.eq(r_data),
self.udp_rx_valid.eq(r_valid),
self.udp_rx_sof.eq(r_first),
self.udp_rx_eof.eq(r_last),
r_ready.eq(self.udp_rx_ready)]
with m.Else():
@@ -563,7 +554,6 @@ class W5100ParallelMaster(Elaboratable):
# ── Main control FSM (Phase 1: init only) ────────────────────────────
if self._enable_udp:
m.d.sync += self.udp_rx_none.eq(0) # pulse: default low
m.d.sync += self.dbg_rd_done.eq(0) # pulse: default low
with m.FSM(domain="sync", name="main_fsm"):
with m.State("IDLE"):
m.d.sync += self.init_done.eq(0)
@@ -581,21 +571,6 @@ class W5100ParallelMaster(Elaboratable):
m.next = "UDP_DIPR"
with m.Elif(self.udp_rx_req):
m.next = "UDP_RX_RSR"
with m.Elif(self.dbg_rd_req):
m.next = "DBG_RD"
# Debug peek: read one byte from dbg_rd_addr over the indirect bus.
with m.State("DBG_RD"):
m.d.sync += [xfer_addr.eq(self.dbg_rd_addr), xfer_rw.eq(0),
xfer_stream.eq(0), xfer_sread.eq(0), xfer_wrap.eq(0),
xfer_direct.eq(0), xfer_len.eq(1), xfer_start.eq(1)]
m.next = "DBG_RD_W"
with m.State("DBG_RD_W"):
m.d.sync += xfer_start.eq(0)
with m.If(xfer_done):
m.d.sync += [self.dbg_rd_data.eq(rbuf[0]),
self.dbg_rd_done.eq(1)]
m.next = "IDLE"
# Pulse the W5100's RSTn pin, then let it boot, BEFORE touching the
# bus. This used to be missing entirely: w5100_rst_n was declared