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:
@@ -751,10 +751,23 @@ class W5100ParallelMaster(Elaboratable):
|
||||
m.next = "RX_RSR_CHK"
|
||||
with m.State("RX_RSR_CHK"):
|
||||
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():
|
||||
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)
|
||||
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),
|
||||
|
||||
Reference in New Issue
Block a user