A plain pipeline assumes the output is always ready. When a downstream block can stall, waiting data must not be overwritten.
valid from the sender: the data on this link is real.
ready from the receiver: it can accept data this cycle.
A transfer happens on a clock edge where both are high.
Rule | Why |
|---|---|
Once | Otherwise the receiver may see an offer that vanishes. |
Data and control stay stable while | The receiver must be able to take the same item later. |
The sender must not wait for | Two blocks each waiting for the other would deadlock. |
| Avoids combinational loops. |
One stage rides through a two-cycle stall: a1 waits while a2 is held, then each item moves on.
Cycle 0: a1 is accepted; the stage starts empty.
Cycle 1: the consumer stalls, so a1 waits and in_ready falls; a2 is offered and held stable.
Cycle 2: the stall continues; a2 stays stable.
Cycle 3: ready returns; a1 leaves and a2 enters in the same cycle.
Cycle 4: a2 leaves and a3 enters in the same cycle.
Cycle 5: a3 leaves; the source is quiet, so nothing enters.
Cycle 6: the stage is empty and valid is low.
Cycles 7–8: idle.
in_ready = !out_valid || out_ready: a new item enters when the stage is empty or its item leaves this cycle.
Emptying while accepting keeps one item per cycle with no bubbles.
out_valid follows in_valid whenever the stage is ready, so it also clears with nothing to offer.
The data register changes only on a real transfer, so it holds steady through a stall.
a2 is offered in cycles 1 and 2 but only transferred in cycle 3. What guarantees the receiver sees the same data each time?The protocol rule that data and valid stay stable while valid && !ready, plus the stage's data register that changes only on a transfer. The sender keeps driving a2 until ready arrives.
Three stages in a chain under random stalls, scored for loss, duplication, or reorder. Stability monitors check all four links. A directed shutdown fills the pipeline, stops the source while an offer is blocked, checks that the offer remains stable, then drains with the sink continuously ready.
module pipe_stage #(parameter int W = 8) (
input logic clk, rst_n,
input logic in_valid, output logic in_ready, input logic [W-1:0] in_data,
output logic out_valid, input logic out_ready, output logic [W-1:0] out_data
);
// Accept a new item whenever the stage is empty OR is being emptied this very cycle.
assign in_ready = !out_valid || out_ready;
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) out_valid <= 1'b0;
else if (in_ready) out_valid <= in_valid; // take the offer, or become empty
always_ff @(posedge clk)
if (in_ready && in_valid) out_data <= in_data; // capture data only on a real transfer
endmodule