Commit Graph

22 Commits

Author SHA1 Message Date
Roflin 2458884160 Rework the EXI decoder to the real GC<->BBA protocol
Replaces the invented 2-byte header (addr split across both bytes, 2-bit
length field) with the protocol libogc and Swiss actually speak:

  command  (bit7=0, 6-bit reg)   [reg, 00, 00, data]  one 4-byte transfer
  register (bit7=1, 16-bit reg)  [0x80|w<<6, ah, al, 00] + data until CS

This was not an optimisation: the old decoder read Swiss's NWAYS read
(80 00 31 00) as 'write 0x31 to NCRA', and bit 0 of 0x31 is RESET, so every
register read would have reset the device.

Changes:
  * 16-bit address; no length field -- register reads and writes now stream
    until CS, like the SPRAM path already did
  * RHDR_LO starts the SPRAM fetch as soon as the address completes, using
    the trailing header byte as the prefetch window the protocol provides
  * command space serves EXI regs 0x02/0x03 (interrupt mask/status), the only
    two Swiss uses
  * EXI_GetID gets its own path: it offers just ONE header byte of warning, so
    the first ID byte is pushed the instant byte 0 identifies the query

Two timing subtleties, both found by simulation and commented in place:
  * MISO is driven LIVE from the tx FIFO head, so a byte pushed while the pad
    byte is on the wire appears in the pad slot.  A filler byte is parked
    there (MISO is don't-care through the header) so the first real response
    lands in data slot 0.
  * the prefetch must be one-shot; re-firing while waiting for the pad byte
    consumed the register stream early and shifted reads by a byte.

All testbenches updated to the real format and passing: bba_register_file
(7), bba_top (8 incl. the full W5100->SPRAM->GC loop and TX), exi_j4,
exi_capture, spi_mode3_slave, tx_frame_drain, spram_arbiter,
rx_frame_assembler, w5100_parallel_master.  gc_bba_test rebuilt against the
new protocol.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-03 11:58:52 +02:00
Roflin 5f60c011cb 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>
2026-09-30 19:16:51 +00:00
Roflin e80b7485d5 fix(w5100): actually drive RSTn on init so a wedged chip can recover
w5100_rst_n was declared and never driven anywhere -- the pin sat at its init
value of 1 forever.  The only reset the chip ever got was the MR software
reset, which arrives over the very bus a wedged chip has stopped answering, so
a wedged W5100 could not be recovered at all: not by NCRA reset, not by
reflashing, not even by reconfiguring the FPGA (RSTn just floats to its R36
pull-up while unconfigured).  Only a 12 V power cycle worked.

Init now pulses RSTn low (1 ms, datasheet minimum is ~2 us) and waits the full
post-reset settle before touching the bus.  RSTn low time is clamped to
reset_cycles so the testbenches' small values stay reachable by wait_ctr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-30 19:09:25 +00:00
Roflin b42dc65796 fix(w5100): wait 83ms after software reset, not 1ms
The init does MR=0x80 (software reset) then waits reset_cycles before writing
NETLCKR/SHAR/SIPR/socket registers.  That wait was 24_000 cycles = 1 ms at
24 MHz, but the W5100S needs the datasheet's 60.3 ms -- our own bus self-test
needed ~85 ms before the chip answered at all.

1 ms is marginal rather than simply wrong, which is why this presented as
intermittent: an NCRA reset sometimes left the chip still resetting while the
init writes landed on it and were silently dropped, leaving it misconfigured
and the bus master blocked.  Symptom was a W5100 that wedged after an NCRA
reset -- TX never completing and the UART shell's own 'udp unicast' hanging --
recoverable only by a 12 V power cycle.  Note RST_N is never asserted by the
gateware; only the software reset is used, so this wait is the only settle
time the chip gets.

Default is now 2_000_000 = 83 ms.  Testbenches pass small values explicitly and
are unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-30 19:02:52 +00:00
Roflin 80957f35db fix(tx): queue the frame length at TWD_HI so the drain runs concurrently
TXFrameDrain sat in IDLE until it had a length, and the length only reached
tx_ctrl when the NCRA ST bits were written -- after the GC had streamed the
whole frame.  So the entire frame had to fit in the 16-deep tx_bytes FIFO, and
BBARegisterFile silently drops bytes when w_rdy is low (SPI cannot
back-pressure).  On hardware this truncated frames at exactly 16 bytes: a
captured ARP had 16 correct bytes followed by the frame restarting over itself.

The length is now handed to the drain one cycle after the TWD_HI (0x35) write,
which the GC issues BEFORE streaming data.  The drain starts early and blocks
on tx_bytes_r_rdy, consuming bytes as they arrive, so tx_bytes becomes a
rate-matching buffer instead of whole-frame storage.  The ST write remains a
fallback trigger for software that skips TWD, guarded by tx_queued so one frame
is never queued twice.

Adds BBATop T8: streams a 34-byte frame (> the 16-deep FIFO) over EXI and
checks the W5100 model received it byte-for-byte.  Verified to FAIL without the
fix with exactly the hardware symptom -- 16/34 bytes, first bad byte at index
16.  The gap that let this ship: TXFrameDrain's own tests drive the FIFO
signals directly, and the BBATop test only covered the RX loop.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-30 18:49:04 +00:00
Roflin 9a7eb54801 exi_j4: shared AND-merge helper + enumeration testbench
Factors the EXI_J4 pad merge out of synth.py so the synthesis path and the
test exercise the same code.  Verifies the device ID (04 02 02 00) enumerates
over SP1 with J4 idle, over J4 with SP1 idle, and over SP1 again afterwards,
plus a register read via J4 and the full cs_n truth table.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-30 18:12:26 +00:00
Roflin c0abd45518 synth: optional EXI mirror on the J4 debug header (EXI_J4=1)
Lets a bench host drive EXI without the SP1 edge connector, for bring-up.

Merges a second set of EXI pads onto the existing ones rather than repinning,
so the SP1 connector stays live and the default build is untouched.  The three
inputs are AND-merged, which is correct because every EXI input is inactive
HIGH (CPOL=1 clk, active-low cs_n, mosi only matters while cs_n is low): the
unplugged side idles at 1 through its SB_IO PULLUP and passes the other side
through, so no select signal is needed.  Outputs drive both pads.

All five J4 pads are on the same bottom die edge as the EXI pads (x=13..18 vs
x=5..9), so the capture domain keeps its anchor.  It still adds 3 LUTs ahead of
the input synchronisers, so EXI_J4 builds must sweep seeds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-30 17:54:24 +00:00
Roflin 3d37e4ba6d Hardware bring-up: first UDP packet transmitted and captured
The W5100S ethernet back-end now works end-to-end on real hardware: a complete,
correctly-checksummed UDP datagram (10.0.0.99:40000 -> 10.0.0.50:6464, 32-byte
payload) was transmitted by the FPGA-driven W5100S and captured on a PC, after a
full bidirectional ARP handshake.

Records the three W5100S-specific findings in CLAUDE.md (NETLCKR unlock, the
15-bit IDM address space putting the buffers at 0x4000/0x6000, and the 60.3 ms
reset-to-ready time), and notes that UDP unicast is the reliable bring-up path
while a 255.255.255.255 send sets SEND_OK without appearing on the wire.

w5100_udptest.py is the self-contained configure+send+readback probe that
isolated all of this.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 19:10:07 +00:00
Roflin 394b677c8f fix(w5100): revert buffer base to 0x4000/0x6000 — IDM decodes only 15 bits
Reverts the 0x8000/0xC000 change from 162dbf7, which was WRONG and actively
broke transmission. The W5100S datasheet pseudo-code quotes 0x8000 (TX) /
0xC000 (RX) for the memory blocks, but the PARALLEL/indirect (IDM) interface
only decodes a 15-bit offset. Bench-proven with an address-aliasing probe:
writing distinct values to each candidate base and reading them back showed
0xC000 and 0x4000 are the SAME cell (0xC000 & 0x7FFF == 0x4000) while 0x6000
holds its own value.

Consequence of the bad base: every payload byte written to 0x9800+i aliased
down onto 0x0000+i, landing on SHAR (0x09-0x0E) and SIPR (0x0F-0x12) and
overwriting them with the payload. The chip then transmitted frames with a
garbage source MAC/IP, which the peer NIC drops without counting -- the
"SEND_OK but rx_packets=0" symptom, and the bogus SIPR0 readback (0x50 was
literally payload byte 15, 'P').

The NETLCKR unlock from 9c4bc7a is a genuine W5100S requirement and stays.

Also:
- w5100_udptest.py: self-contained configure+send+readback probe (and the
  address-aliasing probe that found this), reports over UART.
- scripts/build-flash.sh: sweep N seeds and flash the best (capture timing is
  seed-dependent, so the sweep is mandatory).
- scripts/uart-console.py: interactive UART console, plus --send/--read
  one-shot modes for scripting.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 18:56:38 +00:00
Roflin 5d9880f9c5 Add W5100 read-only register-dump probe (bring-up)
Reads socket-3 / status registers over the indirect bus and streams them on the
UART, without resetting the chip, to inspect what a UDP send left behind. First
hardware run was inconclusive (socket regs read 0x00 but SIPR/PHYSR didn't match
either "state persisted" or "clean reset") -- the FPGA reflash appears to glitch
RST_N, so a self-contained configure+send+readback is the reliable next step.
Committed as a starting point for that.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-20 15:03:44 +00:00
Roflin 9c4bc7a61c 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>
2026-09-20 14:51:33 +00:00
Roflin 59948812f3 Bring-up: W5100 bus self-test, eFuse OVLO bug, Pi SPI EXI host
From the physical V2 bring-up session (2026-09-20):

- exi_bba/w5100_selftest.py (NEW): standalone FPGA<->W5100 bus diagnostic.
  Clock-independent data-bus walk (direct-mode GAR0 read-back, all 8 lines) +
  MR software-reset self-clear (needs the 25 MHz crystal). Reports 4 verdicts on
  D6/D7 LEDs AND over UART (115200): GOOD / data-line-N / clock-dead / no-response.
  Boot wait is 85 ms (> the W5100S 60.3 ms init). On this board: GOOD -- bus +
  all 8 data lines + 25 MHz clock all verified (unlike V1's broken D3).

- REVIEW.md / TODO.md: eFuse U13 OVLO is tied to GND, which on the TPS25961
  selects the internal FIXED ~6 V overvoltage cutoff -- so it blocks the 12 V
  rail entirely (bench-confirmed: 12V_EXI=0, GC_ON=0, W5100 unpowered). FAB-
  BLOCKER for V2.1: fix with an OVLO divider (~1.1M/100k -> trip ~15 V). Bench
  workaround: lift U13 pin 2 (OVLO) off GND. Also closed the eFuse-placement,
  GND-via/3V3-zone, and CC-ESD TODO items.

- hardware/re-bba-rb/exi_devid_spi.py (NEW): Pi hardware-SPI (~25 MHz) EXI
  device-ID host, companion to the bit-bang exi_devid_rpi.py.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-20 14:33:49 +00:00
Roflin 162dbf7d5f fix(w5100): W5100S TX/RX buffer base is 0x8000/0xC000, not 0x4000/0x6000
The W5100ParallelMaster used the original W5100's TX (0x4000) / RX (0x6000)
memory-block base addresses. This board's chip is a W5100S, whose TX/RX memory
blocks live at 0x8000 / 0xC000 (datasheet: TX 0x8000-0xBFFF, RX 0xC000-0xFFFF).

Consequence found at hardware bring-up (2026-09-20): every frame was written to
dead address space, so SEND transmitted the (empty) real TX buffer -- the chip
reported "sent" but nothing valid reached the wire (peer rx_packets stayed 0,
link up). The sim bus-model used these same constants, so it never caught it --
exactly the "register addresses are datasheet-from-memory, confirm at bring-up"
risk. All socket register offsets were verified correct against the W5100S
datasheet; only the two memory bases were wrong. Fixes both the socket-N UDP
test and the socket-0 MACRAW (GC) path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-20 14:33:37 +00:00
Roflin 009a643698 Moved all components to F.Cu 2026-08-28 10:29:41 +02:00
Roflin c16afb6eea Add integrated UART UDP bring-up shell (socket 3) + capture critical-path fix
An interactive UART command shell drives a UDP send/receive test on the
W5100's socket 3, running ALONGSIDE the live BBA (socket-0 MACRAW) with
EXI keeping bus priority. MACRAW+UDP coexistence is W5100S-datasheet
confirmed (S4.6 + "4 independent SOCKETs"). Now the default flash build
(--console selects the old event-log console).

New / changed gateware:
- uart_shell.py (new): rebbarb> shell over FT2232H channel B. Commands:
  help; udp unicast <ip> [msg]; udp broadcast [msg]. After each send it
  waits (bounded, else "timeout") for a reply and prints "rx <payload>".
  Line buffer + message ROM live in block RAM with a sequential parser
  (LC-efficient); 1-deep RX holding reg keeps pastes intact. 8 sim tests.
- w5100_parallel_master.py: configurable UDP socket (default 3) with UDP
  send AND receive (IP-stack init, runtime dest IP, WIZnet UDP RX header
  + payload). Gated by enable_udp_test so the MACRAW path is unchanged
  when off. Tests U1-U4 + MACRAW T1-T5.
- exi_capture.py: CAPTURE-DOMAIN CRITICAL-PATH FIX. The TX byte-FIFO
  read-enable was gated by its own gray-coded ready
  (r_en = ... | (flushing & r_rdy)), forming a consume_ptr -> gray ->
  r_rdy -> flush -> r_en -> consume_ptr loop that capped capture_clk.
  Replaced the r_rdy-based "drain until empty" flush with a fixed-length
  drain counter (FIFO is only tx_depth deep), removing the pointer
  feedback from r_en. Path 24.3 -> 19.6 ns; flush behavior preserved.
- bba_top.py: wire shell <-> W5100 UDP (send + rx); shell additive.
- synth.py: shell default build; env-var UDP network config; documents a
  reverted PNR-timing-priority experiment.

Timing (--seeds 8, default shell build, 67% LC): capture closes on 4/8
seeds (best seed 4 = 58.36 MHz, +8%), clk passes on all. This is BETTER
than the pre-shell 2/8 baseline because the flush fix improved the
capture domain intrinsically. Flash build/seed4/top.bin.

Bring-up caveats (unchanged): W5100 socket register addresses / UDP
header format are datasheet-derived (confirm on hardware); UDP_SRC_IP /
subnet / gateway must match the LAN for unicast ARP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-02 14:36:47 +00:00
Dennis Brentjes 7d7ab34bff Fixes review comments. 2026-07-31 22:06:21 +02:00
Dennis Brentjes 5828d6a388 Finished the board including the connector and mousebites 2026-07-24 14:04:04 +02:00
Dennis Brentjes 620ae5cd64 finalized pcb design, need to remeasure PCB outline. 2026-07-08 22:00:53 +02:00
Roflin 85f82c8740 Added Uart. 2026-06-14 09:37:59 +02:00
Roflin a7c88109a9 Started on component selection of the final PCB. 2026-06-13 22:09:05 +02:00
Dennis Brentjes 5b732a0b34 Adds diagrams. 2026-06-13 19:02:58 +02:00
Dennis Brentjes 8d0ab1d948 Added full design created with Claude 2026-06-13 18:35:38 +02:00