fix(w5100): unlock NETLCKR before writing GWR/SUBR/SHAR/SIPR (W5100S)

Second W5100S-vs-W5100 gotcha found at bring-up: the W5100S has a Network Lock
Register (NETLCKR, 0x0071) the original W5100 lacks. It defaults to 0x00 (locked),
and while locked, ALL writes to GWR/SUBR/SHAR/SIPR are silently dropped -- so the
chip has no source IP/MAC and the UDP/MACRAW send builds nothing (chip reports
SEND_OK but transmits nothing; socket registers aren't locked, which is why an
indirect write/readback of Sn_PORT succeeded). Fix: write the unlock value 0x3A
to NETLCKR right after MR enables indirect mode, before the network-config writes.
On the bench this flipped the board from silent to actually keying frames onto
the wire (magjack activity LED now blinks).

Also:
- bba_top.py test model: RX buffer base 0x6000 -> 0xC000 to match the W5100S
  buffer-base fix (the model hardcoded the old W5100 address).
- w5100_selftest.py: added an indirect-mode (IDM) write/readback probe of a
  socket register + IND= field in the UART report, to isolate direct-vs-indirect
  access (confirmed indirect works on the real chip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-20 14:51:33 +00:00
parent 59948812f3
commit 9c4bc7a61c
3 changed files with 101 additions and 31 deletions
+13 -1
View File
@@ -49,6 +49,8 @@ _GAR0 = 0x0001 # Gateway IP, 4 bytes
_SUBR0 = 0x0005 # Subnet mask, 4 bytes
_SHAR0 = 0x0009 # Source MAC, 6 bytes
_SIPR0 = 0x000F # Source IP, 4 bytes
_NETLCKR = 0x0071 # W5100S Network Lock Register (WO) — GWR/SUBR/SHAR/SIPR are
_NETLCK_UNLOCK = 0x3A # writable ONLY while NETLCKR==0x3A (default 0x00 = locked)
_IR = 0x0015 # Interrupt register
_IMR = 0x0016 # Interrupt mask
_RMSR = 0x001A # RX memory size (2 bits/socket)
@@ -565,7 +567,16 @@ class W5100ParallelMaster(Elaboratable):
m.d.sync += wait_ctr.eq(wait_ctr + 1)
# MR = indirect + auto-increment (direct A=00).
write_reg("MR_MODE", _MR, [_MR_IND | _MR_AI], "SHAR", direct=True)
write_reg("MR_MODE", _MR, [_MR_IND | _MR_AI], "NETLCK", direct=True)
# W5100S-only: GWR/SUBR/SHAR/SIPR are LOCKED until NETLCKR (0x0071)
# is written 0x3A (default 0x00 = locked). Without this, every
# SHAR/SIPR/GAR/SUBR write below is silently DROPPED -> no source
# MAC/IP -> the UDP/MACRAW send builds nothing and the chip transmits
# nothing on the wire despite reporting SEND_OK (bench-confirmed
# 2026-09-20; the original W5100 had no such lock). Indirect mode is
# already on from MR_MODE, so this reaches 0x0071.
write_reg("NETLCK", _NETLCKR, [_NETLCK_UNLOCK], "SHAR")
# SHAR = source MAC (6-byte auto-increment burst).
with m.State("SHAR"):
@@ -911,6 +922,7 @@ if __name__ == "__main__":
EXPECTED = [
("MR", _MR_RST),
("MR", _MR_IND | _MR_AI),
(_NETLCKR, _NETLCK_UNLOCK), # W5100S: unlock GWR/SUBR/SHAR/SIPR
(_SHAR0 + 0, MAC[0]), (_SHAR0 + 1, MAC[1]), (_SHAR0 + 2, MAC[2]),
(_SHAR0 + 3, MAC[3]), (_SHAR0 + 4, MAC[4]), (_SHAR0 + 5, MAC[5]),
(_RMSR + 0, 0x55), (_RMSR + 1, 0x55),