The FIFO reset sequencer¶
If you modify reset logic, read this first — the failure it prevents is silent, permanent, and looks like dead hardware.
The failure¶
Every FIFO ahead of DDR3 is clocked by a recovered clock, and
mandec stalls that clock when it sees no valid Manchester symbols.
fifo_ddr3_in and fifo2_ddr3_in are fifo_generator cores with an
asynchronous reset and the safety circuit enabled. Such a core needs both
of its clocks running to complete a reset. So, without the sequencer:
Pulse
fifo_resetwhile channel 2 is idle, andfifo2_ddr3_innever starts accepting writes. Nothing ever reaches DDR3, sofifo2_ddr3_outstays empty,prog_emptystays asserted,ep_readynever rises,ReadFromBlockPipeOut(0xA1, ...)blocks forever — and it does not recover when data arrives later.
On the host that looks like:
[mio.streamDaq.fpga_recv] Starting capture from pipe 0xA1
[mio.okDev] Read failed: -1
StreamReadError: Read failed: -1
Channel 1 has the same exposure through fifo_ddr3_in.
Why DDR3 did not remove it¶
DDR3 fixed capacity, and it put the FIFO the host reads (fifo*_ddr3_out) on
the free-running ui_clk, so a quiet transmitter can no longer freeze a pipe's
readiness. It did not change the input side: fifo_ddr3_in and fifo2_ddr3_in
are still written on the recovered clocks, so the sequencer is still required.
The fix¶
Each channel has its own reset sequencer; the host's reset does not reach these FIFOs directly:
- A free-running toggle in each recovered-clock domain,
- synchronised into
okClkthrough anASYNC_REGchain and edge-detected, - the channel's FIFO reset is held until eight recovered-clock edges have actually been observed, then released.
The FIFOs are therefore always reset with their write clock running, and held
across many of its cycles, which is what fifo_generator requires.
reg dec_fifo_reset = 1'b1;
reg dec2_fifo_reset = 1'b1;
// ... held until RST_TICKS edges of dec_tick / dec2_tick are seen
Toggle-and-synchronise rather than sampling the clock directly, because nothing should assume the recovered clock is periodic — a half-locked decoder's is not.
What takes which reset¶
| FIFO | Reset | Why |
|---|---|---|
fifo_chain0/1, fifo_ddr3_in |
dec_fifo_reset |
written on dec_clk |
fifo2_chain0/1, fifo2_ddr3_in |
dec2_fifo_reset |
written on dec2_clk |
fifo_ddr3_out, fifo2_ddr3_out |
plain fifo_reset |
both their clocks free-run; gating them would make them depend on a transmitter they do not need |
The two sequencers are fully independent. Channel 1 does not wait on a channel-2 transmitter, so running one channel alone is fine.
Verification¶
In simulation, channel 2 through pipe 0xa1:
| scenario | without sequencer | with sequencer |
|---|---|---|
ch2 idle during fifo_reset |
NO DATA (blocked on ep_ready) |
error rate 0.0 |
ch2 active during fifo_reset |
error rate 0.0 | error rate 0.0 |
The default testbench run keeps channel 2 active during the reset. The idle
case — the one hardware actually hits — needs CH2_RESET_PULSES=0; see
Running the testbench.
On hardware, starting the capture before the channel-2 transmitter streams cleanly with 0 dropped buffers (confirmed 2026-09-18).
A channel without a transmitter stays in reset
A channel stays held in reset until its transmitter appears. With no
channel-2 transmitter connected, pipe2_ready on J2-26 sits low and pipe
0xA1 returns nothing. That is correct, not a fault.