HDLbits
Start Practicing

RTL Design Patterns/Handshaking

Skid Buffer

hard
handshakingvalid-readyskid-buffertiming-closure

Why the simple pipeline stage isn’t enough

The Ready/Valid Pipeline Stage problem computes in_ready = out_ready || !data_valid — a direct combinational path from out_ready to in_ready. Chain a dozen of those stages back-to-back in a deep pipeline and you get a dozen-gate-deep ripple of ready signals every cycle, which is exactly the kind of long combinational path that fails timing closure in a real chip. A skid buffer exists specifically to cut that chain: its in_ready output comes straight from a flip-flop-derived condition, with zero combinational dependency on this cycle’s out_ready.

But if in_ready was already high last cycle (a promise made before this cycle’s out_ready was even known), and the upstream source takes you up on it while out_ready just happens to be low this cycle, that incoming beat has nowhere to go except… a second storage slot. That’s the “skid” — the extra beat that arrives just as the brakes are applied.

The key realization: a skid buffer is a depth-2 FIFO

Reusing the pointer-based full-flag idiom from the FIFOs category solves this cleanly: full (and hence in_ready = !full) is computed purely from the registered write/read pointers, never from out_ready directly. With two storage slots (slot0, slot1) instead of one, the buffer can always accept one more beat than it is currently presenting downstream — exactly the “skid” capacity needed.

Interface

Same valid/ready interface as the other handshaking problems in this track — clk/rst, in_data/in_valid/in_ready, out_data/out_valid/out_ready.

Correctness constraints

  • in_ready must be derived only from registered state (wr_ptr, rd_ptr) — never combinationally from out_ready.
  • No data may be lost or reordered even when out_ready deasserts on the very cycle after a beat was accepted on the strength of a previously-registered in_ready.
  • The buffer must hold at most 2 in-flight beats and must correctly report full/in_ready low once both slots are occupied.
  • out_valid/out_data must present the oldest buffered beat first (FIFO order), with fall-through (combinational) read semantics — no extra latency beyond what’s needed to physically decouple the two sides.