Why a registered stage is different from a passthrough
The Valid/Ready Interface Basics problem wires in_ready straight from out_ready with zero registers. That’s fine for glue logic, but real pipelines need actual flip-flops between stages to break long combinational paths and to let each stage operate somewhat independently. Once you add a register, the ready/valid logic has to account for what’s already sitting in that register: a transfer arriving this cycle isn’t necessarily the one this stage will present next cycle.
Interface
Identical to the combinational passthrough, plus clk/rst:
| Signal | Direction | Description |
|---|---|---|
clk/rst |
input | Clock and synchronous, active-high reset. |
in_data, in_valid, in_ready |
— | Upstream side. |
out_data, out_valid, out_ready |
— | Downstream side. |
The core logic
The stage holds one item in data_reg/data_valid. The key insight is the readiness equation:
in_ready = out_ready || !data_valid
- If the stage is empty (
!data_valid, a “bubble”), it can always accept new input — there’s nowhere for it to be blocked. - If the stage is full (
data_valid), it can only accept new input if the downstream sink is also taking the current item this same cycle (out_ready) — because that guarantees the register will be free at the next clock edge, letting the stage refill and drain in the same cycle for full one-item-per-cycle throughput. - If the stage is full and
out_readyis low,in_readyis correctly low: the stage must hold its data and stall upstream.
Cycle-by-cycle example
| Cycle | in_valid |
in_ready |
out_valid |
out_ready |
Note |
|---|---|---|---|---|---|
| 0 | 1 | 1 | 0 | – | Stage empty, accepts A. |
| 1 | 1 | 1 | 1 (A) |
1 | A drained, B accepted same cycle. |
| 2 | 1 | 0 | 1 (B) |
0 | Downstream stalls; stage full, in_ready drops. C must wait. |
| 3 | 1 | 0 | 1 (B) |
0 | Still stalled — B held, C still waiting. |
| 4 | 1 | 1 | 1 (B) |
1 | Downstream resumes; B drains, C accepted. |
Correctness constraints
- No data may be lost or duplicated: an item transferred in (
in_valid && in_ready) must eventually appear exactly once onout_datawithout_valid. - While
data_validis high andout_readyis low,in_readymust be low (no silent overwrite of buffered data). - A “bubble” cycle (
in_validlow) must propagate asout_validlow exactly one cycle later — it must not be confused with a stall. - This stage’s
in_readydepends combinationally onout_ready(via the|| !data_validterm) — that’s acceptable for a single stage, but chaining many of these back-to-back creates a long combinational ready path across the whole pipeline. The Skid Buffer problem in this category shows how to break that chain.