Skip to content

VHDL · Chapter 18.2 · Advanced RTL Design

Handshaking Protocols

A bare pipeline assumes the consumer is always ready, but real systems need the two sides to agree on when data moves. The standard mechanism is valid and ready handshaking, the AXI-Stream style. The producer raises valid when it has data, the consumer raises ready when it can accept, and a transfer happens on the clock edge only when both are high. This gives backpressure for free, since the consumer simply drops ready to stall the producer. Two rules keep it correct and deadlock-free. The producer must hold its data and valid stable until the transfer completes and never drop an offered word, and valid must not depend on ready or you create a combinational loop. When the two sides need to run independently, a skid buffer or FIFO decouples them. This lesson covers the contract, backpressure, the stability and dependency rules, and decoupling.

Foundation15 min readVHDLRTLHandshakingvalid/readyBackpressureAXI-Stream

1. Engineering intuition — both sides must say yes

Moving data between two blocks is a negotiation, not a shove. The producer signals "I have a word" (valid); the consumer signals "I can take one" (ready); and the word actually moves only when both agree on the same clock edge. That single rule gives you flow control in both directions: if the consumer is busy it drops ready and the producer simply waits, holding its word — that is backpressure. The discipline that makes it work is honesty and stability: once the producer offers a word it must keep offering the same word until it is taken (no take-backs), and it must decide valid without peeking at ready (otherwise the two chase each other combinationally). Get those right and any two blocks can be wired together and will throttle each other correctly.

2. Formal explanation — the valid/ready contract

valid_ready.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- TRANSFER occurs on a clock edge when valid AND ready are BOTH high.
transfer <= valid and ready;       -- one word moves this cycle iff both are asserted
 
-- PRODUCER: assert valid with data; HOLD both stable until accepted; advance only on transfer.
process (clk) begin
  if rising_edge(clk) then
    if rst = '1' then valid <= '0';
    elsif (valid = '1' and ready = '1') then      -- accepted → produce next
      data  <= next_data;
      valid <= have_next;
    elsif valid = '0' and have_next = '1' then    -- start offering a word
      data  <= next_data;
      valid <= '1';
    end if;                                        -- if valid and NOT ready → HOLD (data/valid unchanged)
  end if;
end process;
 
-- RULES:
--   • valid must NOT depend (combinationally) on ready → ready may depend on valid (not both).
--   • producer must HOLD data+valid stable while valid='1' and ready='0' (never drop an offered word).

A transfer happens when valid and ready on a clock edge. The producer holds data and valid stable until accepted and advances only on transfer; the consumer asserts ready when able. valid must not depend on ready (avoids a combinational loop); ready may depend on valid.

3. Production usage — backpressure and decoupling

backpressure_and_skid.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- BACKPRESSURE: the consumer stalls the producer simply by deasserting ready.
ready <= can_accept;               -- low when the consumer is busy/full → producer holds
 
-- DECOUPLE producer and consumer (so neither's combinational timing affects the other):
--   a SKID BUFFER (1-2 entry) or a FIFO sits between them, presenting valid/ready on each side.
--   • absorbs a cycle of latency in ready, prevents the two sides' logic from forming long paths
--   • lets a producer keep streaming while the consumer occasionally stalls (FIFO smooths bursts)
 
-- Typical wiring: producer.valid → fifo.wr_valid ; fifo.wr_ready → producer.ready
--                  fifo.rd_valid → consumer.valid ; consumer.ready → fifo.rd_ready

What hardware does this become? A small amount of control logic per interface — a valid register on the producer, a ready from the consumer, and the valid and ready transfer condition — wrapping whatever data path flows between them. Backpressure is just the consumer's ready going low, which (because the producer holds) stalls the flow with no data loss. A skid buffer or FIFO in the middle decouples the two: it breaks long combinational ready paths (helping timing) and absorbs bursts so a producer can keep running through brief consumer stalls. This valid/ready pattern is the universal interface contract — AXI-Stream, internal block boundaries, pipeline plumbing — because any two compliant blocks compose correctly.

4. Structural interpretation — producer/consumer valid/ready

producer driving data and valid, consumer driving ready, transfer when both highvalid + datareadyproducerdrives data + valid (holdsuntil taken)transfer = valid ANDreadyon the clock edgeconsumerdrives ready (backpressure)12
Valid/ready handshaking lets a producer and consumer agree on data movement. The producer drives data and a valid signal; the consumer drives ready; a transfer occurs on the clock edge only when valid and ready are both high. The consumer applies backpressure by deasserting ready, which stalls the producer, so the producer must hold its data and valid stable until the transfer completes. Valid must not depend combinationally on ready (ready may depend on valid) to avoid a loop. A skid buffer or FIFO between the two decouples their timing and absorbs bursts. This is a flow-control structure; the waveform below shows a transfer and a stall with held data.

5. Simulation interpretation — transfer and stall

valid/ready: transfer when both high; stall holds data

8 cycles
valid/ready: transfer when both high; stall holds datavalid & ready both high → A transferredvalid & ready both hig…ready low: STALL — producer HOLDS data B and valid (no drop)ready low: STALL — pro…ready high again → B transferred, then Cready high again → B t…clkvalid11111000ready10011111dataABBBCCCCxfer10011000t0t1t2t3t4t5t6t7
A transfers when valid and ready are both high. When the consumer drops ready, the producer stalls and holds data B and valid unchanged across the stalled cycles — the word is not lost or duplicated. When ready returns, B transfers, then C. This hold-until-accepted behavior is the heart of the valid/ready contract and gives lossless backpressure between any two compliant blocks.

6. Debugging example — dropped data or a valid/ready loop

Expected: lossless flow with correct backpressure. Observed (a): words are lost or duplicated when the consumer stalls. Observed (b): the design has a combinational loop / unstable handshake, or deadlocks. Root cause (a): the producer changed or dropped data/valid while valid='1' and ready='0' — it did not hold the offered word until accepted, so a stalled word was lost. Root cause (b): valid was made to depend combinationally on ready (and ready on valid), forming a loop — or both sides waited on each other. Fix: hold data and valid stable until valid and ready (advance only on transfer), and ensure valid does not depend on ready (only ready may depend on valid); decouple with a skid buffer/FIFO to break long ready paths. Engineering takeaway: never drop an offered word and never let valid depend on ready — hold until accepted and keep the dependency one-way, or you get data loss or a handshake loop.

hold_until_accepted.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- BUG: producer advances/drops valid regardless of ready → stalled word lost.
-- if rising_edge(clk) then data <= next; valid <= have_next; end if;   -- ignores ready
-- FIX: advance only on transfer; hold otherwise.
if rising_edge(clk) then
  if valid='1' and ready='1' then data <= next; valid <= have_next; end if;  -- hold when not accepted
end if;

7. Common mistakes & what to watch for

  • Dropping an offered word. Hold data/valid stable until valid and ready; advance only on transfer, or data is lost.
  • valid depending on ready. That forms a combinational loop; keep the dependency one-way (ready may depend on valid).
  • No backpressure handling. If the consumer can stall, the producer must honor ready; otherwise it overruns.
  • Long combinational ready chains. Decouple with a skid buffer/FIFO to break timing-critical ready paths.
  • Deadlock from mutual waiting. Ensure progress is possible (one side can always eventually assert); avoid circular ready/valid dependencies across blocks.

8. Engineering insight & continuity

Valid/ready handshaking is the universal RTL flow-control contract: a transfer occurs only when valid and ready, the consumer applies backpressure by dropping ready, the producer holds its word until accepted, and valid never depends on ready — with skid buffers/FIFOs to decouple the two sides. Any two compliant blocks compose losslessly. The most important decoupling buffer is the FIFO itself — sized storage that smooths bursts and bridges rate mismatches — which is the next lesson, FIFO Design: the architecture, pointers, and full/empty logic of the queue at the heart of streaming RTL.