fix(w5100): clear stale Sn_IR bits when INT_N asserts with no RX data

RX_RSR_CHK returned to IDLE when RSR==0 without clearing Sn_IR.  SEND_OK
(bit 4) fires after every successful transmit and the RX path only ever
cleared RECV (bit 2), so INT_N stayed asserted; because IDLE tests
~w5100_int_n BEFORE tx_valid, the FSM span IDLE->RX_CHECK->RX_RSR_CHK->IDLE
and TX was starved permanently.  Observed on hardware as the first frame
transmitting and every later one never setting TI while RX kept working.

Now clears every Sn_IR bit except RECV, so a frame arriving between the RSR
read and the write still raises INT_N and is served next pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 19:16:51 +00:00
parent e80b7485d5
commit 5f60c011cb
+14 -1
View File
@@ -751,10 +751,23 @@ class W5100ParallelMaster(Elaboratable):
m.next = "RX_RSR_CHK" m.next = "RX_RSR_CHK"
with m.State("RX_RSR_CHK"): with m.State("RX_RSR_CHK"):
with m.If(rx_rsr == 0): with m.If(rx_rsr == 0):
m.next = "IDLE" # nothing received # INT_N is asserted but there is no data. Something other
# than RECV set Sn_IR -- in practice SEND_OK (bit 4), which
# fires after every successful transmit. Returning to IDLE
# without clearing it leaves INT_N low forever, and since
# IDLE tests ~w5100_int_n BEFORE tx_valid, the FSM spins
# IDLE->RX_CHECK->here and TX is starved permanently. That
# showed up on hardware as: first frame transmits, every
# later one never sets TI, while RX keeps working.
m.next = "RX_IR_CLR"
with m.Else(): with m.Else():
m.next = "RX_RDPTR" m.next = "RX_RDPTR"
# Clear every Sn_IR bit EXCEPT RECV (0x04). Keeping RECV means a
# frame that lands between the RSR read and this write still raises
# INT_N and gets served on the next pass instead of being lost.
write_reg("RX_IR_CLR", _S0_IR, [0x1B], "IDLE")
with m.State("RX_RDPTR"): # read S0_RX_RD (2 bytes) with m.State("RX_RDPTR"): # read S0_RX_RD (2 bytes)
m.d.sync += [xfer_addr.eq(_S0_RX_RD), xfer_rw.eq(0), m.d.sync += [xfer_addr.eq(_S0_RX_RD), xfer_rw.eq(0),
xfer_stream.eq(0), xfer_sread.eq(0), xfer_wrap.eq(0), xfer_stream.eq(0), xfer_sread.eq(0), xfer_wrap.eq(0),