A transfer is valid && ready sampled at a clock edge. The relationship is asymmetric: the source offers valid (with a stable payload) without waiting for ready, while the sink may wait for valid before raising ready. The beat moves on the first edge where both are high.
Ownership is fixed. The source drives valid and the payload, and the sink drives ready.
Rule | What it says |
|---|---|
Transfer | One beat moves per clock edge with |
Valid ownership | The source drives |
Ready ownership | The sink drives |
Asymmetry | The source never waits for |
Each slot is one clock cycle. The xfer lane is high exactly when valid and ready are both high, so it marks the edges where a beat moves.
Slots 0 to 2 hold beat 0xA1 with ready low. Valid and data stay stable and xfer stays low, so nothing moves.
Slot 3 raises ready. Both signals are high, so the one transfer of 0xA1 happens at the edge ending the slot.
Slot 4 holds ready high with valid low. Xfer stays low: ready alone moves nothing.
Slot 5 offers beat 0xB2 with ready already high, so it transfers at the edge ending the slot.
Independence. valid must not depend combinationally on ready. A source that waits for ready before raising valid, facing a sink that waits for valid before raising ready, deadlocks. Register the source state and let ready only complete transfers.
Stability. While valid is high and ready is low, both valid and the payload stay stable. The sink may sample the payload on any cycle of the stall.
Counting. Throughput is transfer events, not levels. A valid held for ten cycles with one ready pulse is one beat, so monitors and scoreboards count valid && ready edges.
One beat, in the cycle where both are high. The sink broke no rule: it may raise ready before valid, and ready without valid moves nothing.
Whenever a beat stalls. One transfer can hold valid high for many cycles, so the monitor must count valid && ready edges instead.
Nothing. valid and the payload stay stable until the edge where ready joins them; the newer word waits its turn.
The testbench sends 64 words under deterministic pseudo-random backpressure. It samples at each rising edge before nonblocking updates, then waits until after those updates before ending the iteration. Counts therefore describe actual transfer edges, including the final beat. The bounded run checks order and stalled-offer stability.
module vr_source #(
parameter int DW = 8,
parameter int N = 64 // words to send; N <= 2**DW
) (
input logic clk,
input logic rst_n,
output logic valid,
output logic [DW-1:0] data,
input logic ready
);
logic [DW:0] count; // next word index (one extra bit so N = 2**DW is safe)
logic [15:0] lfsr; // fixed-seed offer pattern
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
valid <= 1'b0;
data <= '0;
count <= '0;
lfsr <= 16'hACE1;
end else begin
lfsr <= {lfsr[14:0], lfsr[15] ^ lfsr[13] ^ lfsr[12] ^ lfsr[10]};
if (!valid) begin
valid <= (count < N) && lfsr[0]; // random offer; valid never reads ready
data <= count[DW-1:0];
end else if (ready) begin
count <= count + 1'b1; // transfer done: move to the next word
valid <= (count + 1'b1 < N) && lfsr[0];
data <= count[DW-1:0] + 1'b1;
end
// valid && !ready: hold both stable
end
end
endmodule
// Sink: answers with a pseudo-random ready pattern. The testbench keeps the scoreboard.
module vr_sink (
input logic clk,
output logic ready
);
logic [15:0] lfsr = 16'h1D0F; // fixed seed: the run is deterministic
always_ff @(posedge clk) begin
lfsr <= {lfsr[14:0], lfsr[15] ^ lfsr[13] ^ lfsr[12] ^ lfsr[10]};
ready <= lfsr[0] ^ lfsr[7];
end
endmodule
Source checker, run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It sends 64 words under deterministic pseudo-random backpressure, samples at each rising edge before nonblocking updates, and checks order and stalled-offer stability in a bounded run. It is not a proof for every traffic pattern.