HDLbits
Start Practicing

RTL Design Patterns/Handshaking

Backpressure-Aware FIFO-Fed Pipeline

hard
handshakingvalid-readybackpressurefifopipeline

Why this ties the whole category together

Every problem earlier in this category proved one elastic element correct in isolation. Real pipelines chain many of them together, and the property that actually matters for a working chip is end-to-end: if the very last consumer stops accepting data, that backpressure has to ripple all the way back to the very first producer, with nothing lost or corrupted along the way, no matter how many elastic stages sit in between.

This module chains three elastic elements — a small FIFO (from the FIFOs category pattern) and two single-register pipeline stages (from the Ready/Valid Pipeline Stage problem) — and wires their ready/accept signals so that each stage’s readiness genuinely depends on the next one’s.

Structure and the backpressure chain

in_valid/in_data --> [ FIFO, depth=DEPTH ] --> [ stage 1 ] --> [ stage 2 ] --> out_valid/out_data
in_ready         <--   (fifo_full)         <-- s1_accept  <-- s2_accept  <-- out_ready
  • s2_accept = out_ready || !s2_valid — stage 2 behaves exactly like the Ready/Valid Pipeline Stage problem, decoupled from anything upstream of stage 1.
  • s1_accept = s2_accept || !s1_valid — stage 1’s readiness depends on stage 2’s, one link in the chain.
  • fifo_rd = fifo_rd_valid && s1_accept — the FIFO only drains into stage 1 when stage 1 can accept.
  • in_ready = !fifo_full — the FIFO’s fill level is the only thing upstream ever sees; as long as the FIFO isn’t full, bursts are absorbed without stalling the producer at all.

When out_ready is held low: stage 2 fills and stops accepting -> stage 1 fills (since s2_accept is now false) and stops accepting -> the FIFO stops draining (fifo_rd false) -> the FIFO fills up over DEPTH more cycles -> fifo_full -> in_ready finally drops. This is exactly the graded latency of backpressure through a real multi-stage pipeline: it takes time proportional to the buffering in between for backpressure to reach the front.

Correctness constraints

  • No data may ever be lost, duplicated, or reordered, regardless of how in_valid/out_ready toggle.
  • in_ready must eventually deassert under sustained out_ready == 0, once the FIFO plus both pipeline registers are full (that’s DEPTH + 2 items of total buffering in this design).
  • Each individual stage must still obey its own local correctness rules (the FIFO’s full/empty rules; each pipeline stage’s accept/stall rules) — this composition is correct precisely because each stage was already proven correct in isolation and the composition only wires valid/ready/accept signals between adjacent, individually-correct elastic elements.
  • The design must recover cleanly once out_ready returns high: all buffered data drains out, in order, with no re-initialization needed.