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>
This commit is contained in:
+19
-7
@@ -148,14 +148,26 @@ class ExiCapture(Elaboratable):
|
||||
# clock for DMA reads, so when CS deasserts mid-stream a few unsent
|
||||
# bytes remain. On CS-fall (frame_start) drain tx_fifo to empty before
|
||||
# the new transaction's data phase, so stale bytes never reach MISO.
|
||||
flushing = Signal()
|
||||
m.d.comb += tx_fifo.r_en.eq(
|
||||
(spi.tx_load & (txld_cnt >= 2)) | (flushing & tx_fifo.r_rdy)
|
||||
)
|
||||
# The flush must NOT read `tx_fifo.r_rdy`. r_rdy is derived from the
|
||||
# gray-coded FIFO pointers that `r_en` advances, so any r_rdy → r_en
|
||||
# dependence (either gating the drain with `& r_rdy`, or deasserting a
|
||||
# `flushing` flag on `~r_rdy`) closes a long capture-domain loop
|
||||
# (consume_ptr → gray → r_rdy → flush → r_en → consume_ptr) — the
|
||||
# measured critical path capping capture_clk. Instead, drain for a
|
||||
# FIXED number of cycles: the FIFO is only `tx_depth` deep, so pulsing
|
||||
# r_en for `tx_depth + 1` cycles empties it regardless of occupancy
|
||||
# (the FIFO advances its read pointer only on r_en & r_rdy internally,
|
||||
# so pulses past empty are harmless). This removes the pointer
|
||||
# feedback from r_en entirely; the only remaining r_en source is the
|
||||
# legitimate data-byte pop.
|
||||
drain = Signal(range(self._tx_depth + 2))
|
||||
with m.If(spi.frame_start):
|
||||
m.d.capture += flushing.eq(1)
|
||||
with m.Elif(~tx_fifo.r_rdy):
|
||||
m.d.capture += flushing.eq(0)
|
||||
m.d.capture += drain.eq(self._tx_depth + 1)
|
||||
with m.Elif(drain != 0):
|
||||
m.d.capture += drain.eq(drain - 1)
|
||||
m.d.comb += tx_fifo.r_en.eq(
|
||||
(spi.tx_load & (txld_cnt >= 2)) | (drain != 0)
|
||||
)
|
||||
|
||||
with m.If(spi.frame_start):
|
||||
m.d.capture += txld_cnt.eq(0)
|
||||
|
||||
Reference in New Issue
Block a user