The ready-valid interface is the most reused flow-control pattern in SoC design. A transfer occurs on any clock cycle where both valid and ready are high. The producer asserts valid when it has data and wants to transfer. The consumer asserts ready when it can accept.
For the AXI-style interface used here, Rule 1: outside reset, an asserted VALID and its payload must remain stable until an accepting rising edge with VALID && READY. Rule 2: a source must not wait for READY before presenting an available item. Rule 3: a destination may wait until it has observed VALID before asserting READY. Waiting permission does not permit an AXI combinational input-to-output path: implement the dependency through suitable state. Arm IHI 0022H A3.1–A3.2 specifies both the timing restriction and handshake rules.
VALID / READY EDGE TABLE (conceptual, outside reset)
Rising edge | VALID | READY | DATA | Accepted item
E1 | 1 | 0 | D0 | none
E2 | 1 | 0 | D0 | none
E3 | 1 | 1 | D0 | D0
E4 | 1 | 1 | D1 | D1
D0 remains offered through E3; D1 replaces it after E3.
Two consecutive accepting edges mean two transfers.The classic bug is gating a pending offer with READY: valid = ready & internal_valid. If the destination starts with READY=0 and waits to observe VALID, the producer never presents its item and the destination never sees a reason to become ready. This is a waiting deadlock even when the destination's decision is registered. A literal combinational loop is a separate circuit problem and is not necessary for this deadlock.
Do not rely on synthesis to repair an invalid dependency. Drive VALID from retained pending-item state, preserve the payload during a stall, and choose buffering that obeys the selected interface timing rules. Registering one signal without preserving the item and controlling acceptance is not a complete repair. A directed test with READY initially low exposes the waiting bug in simulation.
Never: valid = ready (direct or through combinational logic).
Retain pending VALID and payload until an accepting edge.
Review both dependency rules and actual buffering capacity.
A skid buffer retains an extra accepted item when registered backpressure takes time to reach the producer. Consider a design with an output register and one extra skid slot: two items total. If item A is stalled at the output while upstream still sees READY, accepted item B must be stored in the skid slot. Output VALID and A remain unchanged; the buffer does not withdraw the stalled offer.
Once both slots are occupied, upstream READY must stop further acceptance before item C can overflow storage. After A transfers, B can advance without being lost, duplicated or reordered. Exact latency and bypass behaviour depend on the design; buffering cannot make the downstream accept while its READY is low. Size storage for the number of additional items that can actually be accepted before backpressure takes effect.
TWO-ITEM BUFFER (one illustrative registered-READY policy)
Initially: output holds A; skid slot is empty.
Edge | Input acceptance | Output acceptance | After edge
E1 | B | none | output A, skid B
E2 | none | none | output A, skid B
E3 | none | A | output B, skid empty
E4 | C | B | output C, skid empty
Upstream READY is 0 at E2/E3, then 1 at E4.
Downstream READY is 0 at E1/E2, then 1 at E3/E4.
A stays offered until E3; B stays offered until E4.
This table describes a policy, not simulated RTL.When a downstream slave deasserts ready, pressure propagates upstream through FIFOs, arbiters, and credit counters. The master you see stalled may be three hops away from the actual bottleneck — a DRAM scheduler, a narrow bridge, or an exhausted PCIe completion credit pool.
Plot actual FIFO occupancy alongside its local full/empty flags and accepted input/output events. High occupancy can explain frequent input stalls. An apparently empty FIFO with a stalled upstream offer needs further investigation: reset, arbitration, registered flags or a downstream dependency can prevent acceptance. Occupancy alone does not identify the cause.
Measure stall cycles per channel: % cycles where valid=1 && ready=0.
Credit exhaustion: sender has data but credit count = 0.
Arbiter fairness: one master can monopolize if QoS absent.
Average handshake rate hides tail latency. A master stalled 40% of cycles on AR may still show 'active' waveforms. Measure stall percentage and p99 latency, not visual activity.
Size from the largest possible backlog of accepted writes minus completed reads, including any additional acceptances before backpressure takes effect. A burst's beat count already measures items; multiplying it by a clock ratio is not a general FIFO-depth formula. Average rate does not bound burst backlog or a paused consumer.
Credits are ready signals with memory — the receiver pre-announces capacity N, sender counts down. Debug is identical: find who ran out of capacity and why.
Never: valid = ready (direct or through combinational logic).
Retain pending VALID and payload until an accepting edge.
Review both dependency rules and actual buffering capacity.