61 / 63 · Concept
Stallable pipelines and backpressure
Compute ready for each stage to prevent data loss, duplication, and recomputation during stalls and simultaneous movement.
Lessons are free to read. Enroll to save your learning progress.
When the receiver cannot always accept data
Prerequisites: a one-entry ready/validHandshake A contract that accepts a transfer when the sender's valid and the receiver's ready are both 1 at the same edge. It also defines how data must be held while waiting. Learn more buffer and data alignment in pipelinesPipeline A structure that divides computation into register-separated stages and overlaps processing of multiple inputs. Data, valid and control signals must be aligned by stage. Learn more.
Simply adding out_ready to a fixed-rate pipeline and blocking its output is insufficient. If the final stage is full and stalls, earlier stages must not overwrite their data either. Design backpressureBackpressure A way for a receiver to tell a sender that it temporarily cannot accept data, stopping the flow. Undelivered data must be preserved while stalled. Learn more to propagate the stop request toward the input.
Represent each of two stages with one data item and one valid bit. Stage 2 can accept a new value if it is empty or can deliver its current output. Apply the same rule to stage 1.
The external in_ready is r1. Even when r2=0, an empty first stage can accept one new input. This uses storage more effectively than rejecting all input whenever the output stops.
Update each stage only when movement is allowed
The following example computes y=2(x+1) for an unsignedUnsigned A rule for interpreting a bit pattern as a nonnegative integer. The n-bit range is 0 through 2^n−1 and may differ from the signed interpretation of the same bits. Learn more 8-bit x. Stage 1 stores x+1 in 9 bits; stage 2 shifts it left by one bit into 10 bits. This represents even the maximum-input result, 512 for x=255, exactly.
module stallable_pipeline (
input logic clk, rst,
input logic in_valid,
output logic in_ready,
input logic [7:0] in_data,
output logic out_valid,
input logic out_ready,
output logic [9:0] out_data
);
logic v1, v2, r1, r2;
logic [8:0] d1;
logic [9:0] d2;
assign r2 = !v2 || out_ready;
assign r1 = !v1 || r2;
assign in_ready = r1;
assign out_valid = v2;
assign out_data = d2;
always_ff @(posedge clk) begin
if (rst) begin
v1 <= 1'b0;
v2 <= 1'b0;
end else begin
if (r2) begin
v2 <= v1;
if (v1) d2 <= {d1, 1'b0};
end
if (r1) begin
v1 <= in_valid;
if (in_valid) d1 <= {1'b0, in_data} + 9'd1;
end
end
end
endmoduleBecause these are nonblockingNonblocking assignment An assignment written as <= in sequential RTL. It evaluates the right-hand side and schedules the update, allowing registers at the same edge to compute from the previous state. Learn more assignments, stage 2 receives the previous d1, not the d1 newly calculated at the same edge. With r1=0, v1 and d1 hold; with r2=0, v2 and d2 hold. Holding valid while continuously updating data is incorrect.
Trace both stages when full
Initially, suppose v2 holds A's result, v1 holds B's intermediate value, and input C is waiting.
| out_ready | in_ready | Action at the edge |
|---|---|---|
| 0 | 0 | Hold A and B; do not accept C |
| 0 | 0 | Hold A and B; do not accept C |
| 1 | 1 | Deliver A, move B to stage 2, accept C |
The sender holds C and in_valid until C is accepted. If it assumes that C was sent at the first stalled edge and presents the next item, C is lost.
Each column shows values just before a rising edgeRising edge The instant at which the clock changes from 0 to 1. Distinguish it from a level, which refers to the entire interval during which CLK=1. Learn more. Initially, the last stage contains A, the first stage contains B, and C is waiting at the input. After E2 delivers A and accepts C, the output before E3 has changed to B.
View waveform data
| Signal | Wave | Bus values |
|---|---|---|
| edge | 2345 | E0 → E1 → E2 → E3 |
| out_ready | 0.1. | |
| out_valid | 1... | |
| out_data | 2..3 | A → B |
| in_valid | 1... | |
| in_ready | 0.1. | |
| in_data | 2..3 | C → D |
Conservation laws to verify
Let Nin count accepted inputs and Nout count delivered outputs since reset, excluding transfers at a reset edge. The number of stored items is
Correct counts alone could miss a fault that outputs A twice and drops B, so check values and order against a reference queue as well. Vary input valid and output ready independently, including long stalls, continuous processing, and flushing during reset.
The ready path is also a timing path
Connecting many stages lengthens backward combinational paths such as r2→r1. Delaying ready by one register may require extra storage for inputs already promised during that delay. Adding a flip-flop to ready without considering storage and the protocol is not a safe timing optimization.
Try it yourself
With v1=0, v2=1, and out_ready=0, can an input with in_valid=1 be accepted? If out_ready remains 0 in the following cycle, can more inputs continue to be accepted?
Read the explanation
Initially r2=0 but r1=1, so one item can be accepted to fill stage 1. After the edge, v1=v2=1 gives r1=r2=0, preventing further acceptance. This distinction is what allows both storage slots to be used.