Roflin 86cd5d1abd Fix two dropped-write bugs in RXFrameAssembler's SPRAM handshake
Both from one mistake: eth_wr_valid is scheduled with m.d.sync and so is LOW
for the whole first cycle in a state, while eth_wr_ready was tested
immediately -- and `ready` is usually already high on entry.  Both
valid.eq(1) and valid.eq(0) then fired in the same cycle, the later won, the
write was never issued, and it was dropped SILENTLY.

1. WRITE_LEN_HI dropped the descriptor's HIGH length byte, leaving it at its
   placeholder 0x00.  Hardware read a descriptor of 00 00 00 01 -- a 1-byte
   frame length, impossible for ethernet -- and rejected the ring.

2. WRITE_PLACEHOLDER counted a phantom first write, advancing wr_addr without
   issuing one.  Only THREE placeholder bytes were written and wr_addr ended
   at desc_base+3, so the frame body started at descriptor byte 3 and EVERY
   RECEIVED FRAME WAS SHIFTED ONE BYTE EARLY.  The GC's ethertype test then
   read the wrong offset and silently dropped every frame: the host saw "no
   ACK" while the ring filled and RWP advanced normally.

Both now advance on `valid & ready`, and the body offset is set explicitly
(desc_base + 4) rather than relying on an incremented pointer, so it cannot
drift with the handshake again.

WHY NO TEST CAUGHT THIS, which is the more important half:

  - The testbench drove the RX stream OPEN-LOOP -- one byte per tick, never
    checking rx_ready, which is low through IDLE and the whole placeholder
    write.  It silently lost bytes, including the SOF byte.  A real master
    must hold each byte until accepted.
  - It only ever asserted on rwp and rx_irq.  It declared a spram_writes list
    and never filled it, so NOTHING had ever checked what was written.
  - Every frame it sent was short, and a short frame's high length byte is
    legitimately zero -- so a dropped high byte was indistinguishable from a
    correct one.

The testbench now respects back-pressure, records every write, and checks the
descriptor bytes and the body offset.  T2 sends a 300-byte frame specifically
so the high length byte is non-zero.  Mutation-tested: restoring either bug
fails T2 with got [0,0,0,48] want [0,0,1,48] -- the same shape as the
hardware's 00 00 00 01 -- while T1 (short frame) still passes, which is
exactly the blind spot that let this ship.

Bring-up's 342-byte DHCP frame read a correct 00 00 01 5A only because the
arbiter happened to hold `ready` low on that entry cycle; the domain merge
and the SPRAM response-FIFO removal changed that timing.

--seeds 8: clk 27.8-32.2 MHz, EXI 54.9-64.5 MHz, 8/8 PASS.  Best seed 8
(clk 32.22, EXI 62.25), flashed.  Gateware only -- the .dol is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 12:04:00 +02:00
2026-06-13 19:02:58 +02:00
2026-08-28 10:29:41 +02:00
2026-06-16 14:59:18 +02:00
2026-08-28 10:29:41 +02:00
S
Description
No description provided
60 MiB
Languages
Python 84.9%
C 12.4%
Shell 1.1%
Dockerfile 0.7%
Makefile 0.4%
Other 0.5%