30 / 37 · Concept
Ready/valid and a one-entry elastic buffer
Design lossless, duplicate-free transfers and simultaneous input/output in a datapath that can stall.
Lessons are free to read. Enroll to save your learning progress.
A transfer occurs when valid and ready are 1 at the same edge
The sender asserts valid when presenting valid data, and the receiver asserts ready when it can accept data. Sampling both signals together at the clock edge determines whether a transfer occurs.
While valid=1 and ready=0, the sender must hold valid and the data. Waiting to assert valid until ready is high can cause deadlock, depending on the other side's rules. Here all signals are assumed to share one clock domain. 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. itself does not solve CDC.
Transfer waiting data exactly once
The columns below represent sampling cycles 0 through 5 in order. Read each signal as its value just before that 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. In cycles 1 and 2, A is waiting with valid=1 and ready=0, so valid and data are held. A is accepted at edge 3 and B at edge 4. The alignment of the clock and signal traces illustrates the contract; it does not model setupSetup The minimum time that input data must be stable before the capturing clock edge. If it is violated, the stored result is not guaranteed. Learn more/hold delays.
View waveform data
| Signal | Wave | Bus values |
|---|---|---|
| clk | p..... | |
| valid | 01...0 | |
| ready | 10.1.. | |
| transfer | 0..1.0 | |
| data | x3..4x | A → B |
A valid signal held high for several cycles does not imply only one transfer. Every edge at which ready is also high performs a separate transfer.
Build a buffer that stores one item
There is room for new data if the buffer is empty or its current data can be delivered at this edge.
module elastic_buffer (
input logic clk,
input logic 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 [7:0] out_data
);
assign in_ready = !out_valid || out_ready;
always_ff @(posedge clk) begin
if (rst) begin
out_valid <= 1'b0;
end else if (in_ready) begin
out_valid <= in_valid;
if (in_valid) out_data <= in_data;
end
end
endmoduleWhen an empty buffer accepts input, out_valid and out_data update after the edge. There is no combinational bypass, so the new value is not counted as an output transfer at the same edge. Transfers are not counted during reset, and out_data is meaningless when out_valid=0. Thus the data registerRegister A circuit that stores multiple bits of state. The synchronous registers in this course store their specified inputs at a clock edge. Learn more itself does not necessarily need resetReset A control that returns state to a specified initial value. Define whether it is synchronous or asynchronous and whether it has priority over other controls. Learn more.
A full buffer can replace its contents
| State just before the edge | out_ready | in_valid | Action at the edge |
|---|---|---|---|
| Empty | 0 or 1 | 1 | Store input and set valid=1 |
| Full | 0 | 0 or 1 | Hold current data and valid |
| Full | 1 | 0 | Deliver output and become empty |
| Full | 1 | 1 | Deliver old output and store new input simultaneously |
The last row allows one item per cycle after the buffer has first been filled. Having latency does not mean throughputThroughput The number of operations accepted or completed per unit time. A pipeline can increase throughput without reducing the latency of an individual operation. Learn more is halved.
A model to verify data order
Use a queue of maximum length 1 for the reference model. Determine output transfer and input acceptance from the previous values at each edge. If an output transfers, compare it with the queue's front item, then append the new input. Dequeue and enqueue can both occur at the same edge, so make their order explicit.
This invariant holds within a tracking interval restarted by reset. Also check that data stays stable during stalls, delivery order is preserved, and no item is delivered twice. The count invariant alone does not verify data-value correctness.
Chaining many buffers through combinational ready signals can create a long backward timing path. When connecting the structures, also check for combinational loops.
Further reading: AMD UG934 — READY/VALID Handshake
Try it yourself
The buffer is full with A, and a new input B has in_valid=1. Suppose out_ready=0 at the first edge and out_ready=1 at the next. What happens to A and B at each edge, and how long must the sender hold B?
Read the explanation
At the first edge, in_ready=0, so A is held and B is not accepted. The sender holds B and in_valid=1. At the next edge, in_ready=1, so A is delivered while B is stored simultaneously. After that edge, the buffer output is B, but B has not yet been delivered. Its output transfer occurs at a later edge where out_valid and out_ready are both 1.