AMBA AXI · Module 3
Common Handshake Bugs
A field guide to the recurring AXI handshake bugs — dropped VALID, mutated payload, VALID-waits-for-READY deadlock, ordering violations, and undrained responses — and how to spot each.
Every rule in this module has a failure mode, and the same handful of bugs show up on real AXI bring-ups again and again. This chapter is the field guide: the recurring handshake mistakes, what each looks like on a waveform, and the one-line guardrail that prevents it. They cluster into four families — stability, dependency, ordering, and drain — and once you can name the family from the signature on a capture, diagnosis is fast. This closes Module 3 by turning the contract (3.1), the transfer event (3.2), backpressure (3.3), throughput (3.4), and the dependency rules (3.5) into a debugging checklist you'll use on every AXI block.
1. Four Families of Handshake Bug
Almost every handshake bug is a violation of one rule from this module, so they sort into four families:
2. Stability Bugs
These break the stability rule (3.1): once VALID is asserted, the source must hold VALID and the payload stable until the transfer completes. Two variants dominate.
Dropped VALID — the source asserts VALID with a beat, the destination isn't ready yet (READY low), and the source illegally withdraws VALID before the transfer. The beat is silently lost.
Dropped VALID — a lost beat
8 cyclesMutated payload — the source holds VALID but changes the data while waiting. The destination captures whatever is present at the transfer edge, so it gets the wrong beat.
Mutated payload under held VALID — a corrupt beat
8 cycles3. Dependency Bugs
These break the cardinal rule (3.1/3.5): a VALID must never wait for its READY. The canonical mistake is coding valid = f(ready):
// ❌ Dependency bug — VALID waits for READY. If the slave (legally) waits for
// VALID before asserting READY, both stay low forever → DEADLOCK.
assign awvalid = awready; // never rises
// ✅ Fix — assert VALID from your own data; hold until the transfer.
assign awvalid = have_addr; // independent of READYA related, subtler form is a combinational loop: VALID is wired combinationally from READY and the destination wires READY combinationally from VALID, creating a zero-delay cycle (a simulation X/oscillation or an unsynthesizable loop). The signature on a capture is the deadlock from 3.5 — both control signals flat-low forever, no forward progress. The fix is always the same: drive VALID from internal state, and if a registered path is needed for timing, use a skid buffer (3.4), not a combinational dependency.
4. Ordering & Drain Bugs
Ordering bugs break the mandatory orderings (3.5). The dangerous one is B before W: a slave asserts BVALID before it has accepted the write data (WLAST). The master sees OKAY and believes the write landed — but the data was never taken, so memory is silently wrong. The read analogue is RVALID before the AR handshake. These don't hang the bus; they corrupt correctness while looking healthy.
Drain bugs break liveness on the response/data side: a master that never asserts BREADY (or RREADY). The slave correctly holds BVALID high until accepted, but it's never accepted, so the response channel jams and subsequent transactions back up behind it. The signature is a VALID (often bvalid/rvalid) high for a long time with its READY low — and unlike legitimate backpressure, it never clears because the master simply isn't draining. Many simple masters tie BREADY/RREADY high precisely to avoid this.
5. The Handshake Bug Catalogue
AXI handshake bugs — signature, cause, fix, and guardrail
Symptom: A beat goes missing; on the capture, VALID was high while READY was low, then went low before a transfer. The destination never saw it.
Cause: The source withdrew VALID (or moved on) during backpressure, violating the stability rule.
Fix: Once asserted, hold VALID and the payload until VALID && READY. Drive VALID from a registered "I have a beat" state, cleared only on transfer.
Guardrail: An assertion — while VALID && !READY, VALID must stay high next cycle.
Symptom: Data is wrong despite a clean-looking transfer; the payload changed while VALID was held.
Cause: The source updated the payload mid-offer; the destination captured the value present at the transfer edge.
Fix: Latch the payload when you assert VALID and hold it stable until transfer.
Guardrail: An assertion — while VALID && !READY, the payload must not change.
Symptom: The channel is hung; VALID and READY are both low forever; no transaction completes.
Cause: VALID was coded as a function of READY (e.g. awvalid = awready); the slave waits for VALID, so the cycle never breaks.
Fix: Assert VALID from internal data readiness only — never reference READY in the VALID equation.
Guardrail: Review every VALID assignment; if its right-hand side mentions the matching READY, it's wrong (AXI4 §A3.3).
Symptom: A write reports OKAY but memory is wrong; intermittent, surfaces far downstream. BVALID rose before WLAST was accepted.
Cause: The slave asserted the response before taking the write data, violating the B-after-W ordering.
Fix: Gate BVALID behind both address and last-data acceptance (aw_done && w_done); gate RVALID behind the AR handshake.
Guardrail: Assertions — BVALID must not assert before WVALID && WREADY && WLAST; RVALID not before ARVALID && ARREADY.
Symptom: BVALID (or RVALID) high for a very long time with READY low; transactions back up; throughput collapses then stalls.
Cause: The master never asserts BREADY/RREADY, so responses are never consumed and the channel can't make progress.
Fix: Ensure the master always (eventually) asserts BREADY/RREADY; simple masters tie them high.
Guardrail: A liveness/timeout assertion — an asserted BVALID/RVALID must be accepted within N cycles.
Symptom: Correct data, but the channel runs at ~50% — a beat every other cycle, a clean bubble pattern.
Cause: A single-register slice drops READY for a cycle to drain after each transfer (Chapter 3.4).
Fix: Replace with a skid buffer (2-deep register slice) that registers the path for timing without inserting bubbles.
Guardrail: A performance check on sustained utilization; investigate any channel stuck near 0.5.
6. Triage by Signature
The fastest way to use this guide is backwards — from the signature on a capture to the bug:
7. Debugging Insight
8. Verification Insight
9. Interview Questions
10. Summary
The recurring AXI handshake bugs sort into four families, each breaking one rule from this module. Stability bugs — dropped VALID (a lost beat) and mutated payload (a corrupt beat) — break "hold VALID and payload until transfer." Dependency bugs — VALID waits for READY, including combinational loops — break "VALID never waits for READY," with the signature of both signals flat-low forever (deadlock). Ordering bugs — B before W, R before AR — break the mandatory orderings and silently corrupt data while looking healthy. Drain bugs — a master that never asserts BREADY/RREADY — jam the response channel and back up transactions. (The ~50% naive registered handshake from 3.4 rounds out the catalogue.)
Diagnose by signature: both low forever → dependency; VALID dropped → lost beat; payload changes under VALID → corrupt beat; response before data → ordering; VALID high with READY never asserted → drain. Each family maps to a reusable assertion (stability, structural-no-VALID-from-READY plus timeout, ordering, liveness) and is only exposed by stressful stimulus — random per-channel backpressure with many outstanding transactions. Symptom → family → rule → fix is the whole method. That completes Module 3: you now own the handshake end-to-end — contract, timing, flow control, throughput, deadlock rules, and the bugs. Module 4 returns to the write path to detail its channels signal by signal.
11. What Comes Next
That closes Module 3 — the VALID/READY Handshake. Module 4 details the write transaction channel by channel, now that the handshake underneath them is fully understood:
- 4.1 — The Write Address (AW) Channel (coming next) — every AW signal and its role in launching a write.
Previous: 3.5 — Handshake Dependency & Deadlock Rules. For the broader protocol catalog, see the AMBA family overview doc.