You connect a block that produces words to a block that consumes them. Most of the time the consumer keeps up, but now and then it has to pause: its memory is busy, or its own output is blocked. In simulation the first thousand words arrive fine. Then a regression run shows one word missing and another delivered twice, only when a pause lands on a particular cycle.
The two blocks disagreed, for one cycle, about whether a word had moved. How can two blocks agree, every single cycle, on whether a word changed hands?
Answer one: the producer pulses "here is a word" and the consumer must take it. This works only while the consumer can always accept. The first time it pauses, the word on the wire is overwritten by the next one and lost. A one-way signal carries no news back from the consumer, so the producer cannot know.
Answer two: add a "stop" wire from the consumer. Now the producer can be held off, but the rule is still vague. If the consumer raises stop in the same cycle a word is on the wire, did that word count? If the producer decides it did and the consumer decides it did not, the word is lost. If both decide the opposite way, it is delivered twice. The bug in the opening story is exactly this: two sides applying slightly different rules to the same cycle.
What is missing is a rule that both sides compute from the same information, so they cannot reach different answers.
Give each side one signal that states only what that side knows:
valid, driven by the producer: "the data on the wire this cycle is real".
ready, driven by the consumer: "if there is data this cycle, I will take it".
Then fix one rule: a word moves on a rising clock edge where valid and ready are both high. Both sides see both signals, both compute the same AND, so they always agree whether a word moved. Neither side has to guess what the other decided.
Think of handing over a baton: the runner holds it out (valid), the next runner's hand is open (ready), and it changes hands only when both are true at the same moment. Neither runner lets go or grabs on their own.
valid | ready | What happens on the next edge | Who is waiting |
|---|---|---|---|
0 | 0 | Nothing. The link is idle. | Nobody |
0 | 1 | Nothing. The consumer could take a word, but none is offered. | The consumer |
1 | 0 | Nothing moves. The producer must keep the same word on the wire. This is a stall. | The producer |
1 | 1 | The word moves. Next cycle the producer may offer a new word or drop valid. | Nobody |
The third row carries the rule that makes the scheme safe: once the producer raises valid, it keeps valid high and the data unchanged until the word moves. The consumer may raise ready in any cycle, so the producer cannot take a word back. If it could, a consumer that raised ready in the same cycle would capture a word the producer believes it never sent. The full set of rules, and why each one exists, is the next lesson.
The listing below is the testbench that produced the waveform further down. The producer offers words 0 to 5. The consumer's ready follows a fixed pattern chosen so every combination appears, and the producer has nothing to offer in cycles 5 and 6. A checker confirms that each word arrives exactly once and in order, and that the producer never changes valid or data while stalled.
// valid/ready on one hop: a producer sends six words (0..5) to a consumer whose
// ready follows a fixed pattern, so every valid/ready combination appears.
// The checker confirms each word arrives exactly once, in order, and that the
// producer holds vld and data steady while it is stalled.
module tb;
reg clk = 0;
always #5 clk = ~clk;
reg rst_n = 0;
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, tb);
#12 rst_n = 1;
end
reg [4:0] cyc = 0; // cycle counter, drives the fixed patterns
always @(posedge clk) if (rst_n) cyc <= cyc + 1;
// Consumer: ready pattern, one bit per cycle (bit 0 = first cycle after reset).
localparam [31:0] RDY_PATTERN = 32'b0011_1010_1111_1000;
wire rdy = RDY_PATTERN[cyc];
// Producer: offers words 0..5. It has nothing to send in cycles 5 and 6.
reg vld = 0;
reg [7:0] data = 0;
reg [2:0] loaded = 0; // words loaded onto the wire so far
wire have = (loaded < 6) && !(cyc == 5 || cyc == 6);
wire xfer = vld & rdy; // a word moves on a rising edge where both are high
always @(posedge clk) begin
if (!rst_n) begin
vld <= 0;
end else if (!vld || xfer) begin // the wire is free: empty, or emptying this edge
vld <= have;
if (have) begin
data <= {5'd0, loaded};
loaded <= loaded + 1;
end
end // otherwise: stalled, hold vld and data
end
// Checker
reg [7:0] expect_d = 0;
reg was_stalled = 0;
reg [7:0] stalled_data = 0;
integer errors = 0, xfers = 0, cycles = 0;
always @(posedge clk) if (rst_n) begin
cycles = cycles + 1;
if (was_stalled && (!vld || data != stalled_data)) begin
$display("ERROR: producer changed vld/data while stalled at cycle %0d", cyc);
errors = errors + 1;
end
was_stalled <= vld && !rdy;
stalled_data <= data;
if (xfer) begin
if (data != expect_d) begin
$display("ERROR: got %0d, expected %0d", data, expect_d);
errors = errors + 1;
end
expect_d = expect_d + 1;
xfers = xfers + 1;
end
end
initial begin
#170;
if (errors == 0 && xfers == 6)
$display("PASS: 6 words moved in order in %0d cycles, none lost or repeated", cycles);
else
$display("FAIL: %0d errors, %0d transfers", errors, xfers);
$finish;
end
endmoduleThe whole handshake is the line wire xfer = vld & rdy; and the producer's if (!vld || xfer): the producer may load a new word only when the wire is empty or the current word is moving on this edge.
How to read it, slot by slot (slot 0 is the first column):
Slots 1–2: stall. Word 0 is on the wire with vld high, but rdy is low. The data stays 0 and vld stays high, as the rule demands.
Slots 3–5: full speed. rdy rises, and words 0, 1 and 2 move on three consecutive edges (xfer high). Back-to-back transfers need no idle cycle between them.
Slots 6–7: consumer waiting. rdy is high but the producer has nothing, so vld is low and nothing moves. The data lane still shows 2: data is meaningless while vld is low.
Slots 8–11: stall, move, stall, move. Word 3 waits one cycle (slot 8) and moves in slot 9; word 4 waits in slot 10 and moves in slot 11.
Slot 12: word 5 moves. From slot 13 the producer is done.
Count the sixteen slots by combination:
Combination | Slots | Count |
|---|---|---|
valid 1, ready 1 (transfer) | 3, 4, 5, 9, 11, 12 | 6 |
valid 1, ready 0 (producer stalled) | 1, 2, 8, 10 | 4 |
valid 0, ready 1 (consumer waiting) | 6, 7, 13 | 3 |
valid 0, ready 0 (idle) | 0, 14, 15 | 3 |
Throughput is transfers divided by cycles: 6 / 16 = 37.5% of one word per cycle. The other ten cycles are lost to one side or the other waiting, but no word is lost or repeated. That split is the point of a handshake: it guarantees agreement, and leaves rate to the two sides. When you are asked why a valid/ready link is slow, count these four combinations on the waveform: they tell you at once whether the producer or the consumer is the bottleneck.
Scheme | What it costs | When it wins |
|---|---|---|
Valid only (no ready) | Nothing extra, but the consumer must accept every word | The consumer is guaranteed to keep up, for example a fixed-rate stream into a FIFO sized for it |
Wait state (the target stretches one transfer) | One extra signal; the initiator is blocked during the stretch | Simple register buses, one transfer at a time |
valid/ready | Two signals; data held during stalls; ready paths need care in timing | Any on-chip hop where the far side answers within a cycle |
Request/acknowledge (four-phase) | Two full round trips of signalling per word | Crossing clock domains, where each signal needs a synchroniser |
Credits | A counter at the sender and a return path | Long or pipelined paths where ready would arrive many cycles late |
Protocol | Its constraint | Its choice |
|---|---|---|
AXI | Many independent streams of addresses, data and responses on chip, each with its own rate | A VALID/READY pair on every channel. The source may not wait for READY before asserting VALID, and holds the payload stable while VALID is high and READY is low. |
AXI-Stream | Address-free data streams between IP blocks | TVALID/TREADY with the same handshake rules as AXI, plus TLAST to mark packet ends |
PCI Express | A link between chips whose round trip is far longer than one cycle | No per-cycle ready from the far end. The sender spends credits that the receiver advertised and returns (Part 4). |
The pattern to notice: when the answer can come back within a cycle, a ready signal is the simplest agreement. When it cannot, the protocol moves to credits.
A team connects a new consumer that samples data whenever its own rdy is high, without looking at vld. In most tests the producer always has data, so nothing goes wrong. In a test where the producer pauses, the consumer captures the stale word in every waiting cycle (slots 6 and 7 in the waveform above) and delivers word 2 three times.
// bad-example: the consumer captures on its own ready, ignoring valid
always @(posedge clk)
if (rdy) fifo_push(data); // pushes stale data whenever vld is lowThe mirror-image bug is a producer that drives data from a free-running counter instead of a holding register. It changes the data during a stall, so the consumer receives a later value and the stalled word is silently skipped. Both bugs come from one side using a private rule instead of the shared one: a word moves only when valid and ready are both high, and nothing else counts. Fixing either one is a single gate; finding it takes a checker like the one in the listing.
No. The current word has not moved, and the consumer may raise ready in any cycle, including the next one. The producer must hold valid and the current data until an edge with both high; only then may it load the next word.
The consumer. In 50 cycles the producer was offering a word and the consumer was not ready; the producer was idle in only 10. Speeding up the producer would not help; the consumer needs to accept more often.
Both compute the same function of the same two signals at the same clock edge: valid AND ready. No side relies on information the other side cannot see.
A word moves on a rising edge where valid and ready are both high; both sides compute the same AND, so they always agree.
Once valid is high, the producer holds valid and data until the word moves; the consumer may drive ready whenever it likes.
The handshake guarantees agreement, not rate: count the four valid/ready combinations to see who is slowing the link.