Skip to content

AMBA AXI · Module 3

Handshake Dependency & Deadlock Rules

The AXI dependency rules that prevent deadlock — VALID never waits for READY, and the cross-channel ordering (B after W, R after AR) that keeps the dependency graph acyclic.

Decoupled channels (2.4) and backpressure (3.3) give AXI its performance — and its capacity to deadlock, if the channels are allowed to wait on each other in a cycle. This chapter is the rule set that makes all that concurrency safe: the single-channel rule you met in 3.1 (VALID never waits for READY), now generalized to a cross-channel dependency graph. The whole trick is one idea — keep the dependency graph acyclic. AXI4's dependency rules are precisely the constraints that forbid a cycle, so a transaction can always make forward progress. Get a dependency direction wrong and you get a hang that no amount of waiting resolves. This is the Critical payoff of Module 3; grounded in AMBA AXI4 §A3.3.

1. Deadlock Is a Cycle of Waiting

Deadlock has one shape: a cycle of "I'll move after you move." If A waits for B and B waits for A, neither ever moves. On a handshake that's the cardinal-rule violation from 3.1 in its purest form — the source waits for READY and the destination waits for VALID, so neither signal ever asserts.

A circular wait: the source waits for READY before asserting VALID, and the destination waits for VALID before asserting READY, so neither ever asserts and the channel deadlocks.needs READY firstneeds VALID firstcircular waitSource waits forREADY beforeasserting VALIDDestination waitsfor VALID beforeasserting READYNeither everasserts →DEADLOCK
Figure 1 — deadlock is a dependency cycle. If the source won't assert VALID until it sees READY, and the destination won't assert READY until it sees VALID, each is waiting for the other to move first. The wait is circular, so neither ever fires — a permanent hang. Breaking the cycle (one side must not wait) is the whole game.

So the rule that prevents single-channel deadlock is exactly the cardinal rule: a source asserts VALID from its own data, never waiting for READY. That breaks the cycle — the source always moves first, so the destination's READY (which may wait for VALID) eventually fires. One non-waiting side is all it takes.

2. The Deadlock on a Waveform

A handshake deadlock has an unmistakable signature: both VALID and READY flat-low forever, with the transaction never completing.

Deadlock — VALID waits for READY (both flat low)

8 cycles
Both VALID and READY stay low for every cycle; the data is available but never transfers because each side waits for the other, so no transfer event ever occurs.data ready, but VALID waits for READYdata ready, but VALID waitsfor READYboth low forever → no transfer everboth low forever → notransfer everaclkvalidreadydataD0D0D0D0D0D0D0D0t0t1t2t3t4t5t6t7
Figure 2 — the deadlock-dependency waveform. The source has data to send but waits for READY, so VALID never rises; the destination waits for VALID, so READY never rises. Both stay low for all time and no beat ever transfers. Flat-low-forever on both control signals is the textbook VALID-waits-for-READY deadlock.

Contrast this with backpressure (3.3), where VALID is high and READY is low (a legitimate stall that resolves when the destination is ready). Deadlock is both low and never resolving. Telling these two apart on a capture is a core skill: high-VALID/low-READY is flow control; low-VALID/low-READY-forever is a dependency bug.

3. From One Channel to Many

The single-channel rule generalizes. AXI has five channels, and they're allowed to depend on each other in specific directions — a master may legitimately wait for one thing before doing another. The danger is that these cross-channel waits could form a cycle across channels even if each channel individually obeys the cardinal rule. AXI4's dependency rules (§A3.3) are exactly the set of allowed dependencies chosen so that no cycle can form.

The rules come in two flavors:

  • "may depend on" (optional): a READY may wait for the corresponding VALID (the destination may wait to see an offer). These are the slave/master conveniences.
  • "must not depend on" (forbidden): a VALID must never wait for its READY — on any channel. This is the cardinal rule applied five times.
  • "must follow" (required ordering): some events must happen after others — the write response after the write data, the read data after the read address. These are mandatory orderings, not just allowances.

Put together, every dependency arrow points "forward" (a VALID enabling a READY, or an earlier event enabling a later one) and never backward into a VALID from its own READY — so the graph is a DAG, and a DAG cannot deadlock.

4. The AXI4 Dependency Graph

Here is the write path's dependency graph — the legal arrows. Read an arrow X → Y as "Y may be asserted depending on X" (Y is allowed to wait for X). The read path is the same shape with AR and R.

AXI4 write dependency graph: AWREADY may depend on AWVALID, WREADY may depend on WVALID, BVALID must follow both the accepted write address and the accepted write data, and BREADY may depend on BVALID; no READY feeds back into its own VALID, so the graph is acyclic.AWVALIDmaster — independentAWREADYslave — may waitWVALIDmaster — independentWREADYslave — may waitBVALIDslave — after WLASTBREADYmaster — may waitmay wait formay wait forB MUST follow W…and AWmay wait for12
Figure 3 — the AXI4 write dependency graph (read is symmetric with AR/R). AWREADY may wait for AWVALID; WREADY may wait for WVALID; BVALID MUST follow BOTH the accepted write address (the AW handshake) and the accepted write data (through WLAST); BREADY may wait for BVALID. Crucially, no arrow ever points from a READY back into its own VALID — every VALID is an independent source — so the graph is acyclic and cannot deadlock.

The forbidden arrows are the ones you don't see: nothing points from AWREADY back to AWVALID, from WREADY to WVALID, from BREADY to BVALID, or (on the read side) from ARREADY/RREADY to their VALIDs. Each VALID is a graph source with no incoming dependency from its own READY. That's the acyclic guarantee, stated as a picture.

5. The Mandatory Orderings

Two arrows in that graph are not "may" but "must" — required orderings that hold every transaction together:

  • Write: B must follow W and AW. The slave must not assert BVALID until it has accepted the write data — the W-channel handshake of the last beat (WLAST) — and until it has accepted the write address, the AW handshake. Both are "must wait" dependencies in §A3.3.1, not just the data one. A response before either is a protocol violation, and a correctness disaster: the master believes the write landed when it did not.
  • Read: R must follow AR. The slave must not assert RVALID until the address has been accepted (the AR handshake completed). You can't return read data for an address you haven't taken.

These orderings are causal — the answer can't precede the question — and they're the "must follow" dependencies of the base protocol.

Mandatory orderings: write response BVALID only after both the write address is accepted and the write data is accepted through WLAST; read data RVALID only after the read address is accepted.B must follow bothR must follow ARWrite addressaccepted (AW)AND write dataaccepted (WLAST)BVALID allowedRead addressaccepted (ARhandshake)RVALID allowed
Figure 4 — the two mandatory orderings. A write's B response may be asserted only after both the write address is accepted (AW handshake) and the write data is accepted (through WLAST); a read's R data may be asserted only after the address is accepted (the AR handshake). The answer cannot precede the question — these causal orderings are required, not optional.

The dependency rules, as a set of guardrails:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Conceptual — the AXI4 dependency rules (AMBA AXI4 §A3.3), as guardrails:
//  1. A SOURCE asserts VALID from its own data — NEVER waits for READY.   (no self-cycle)
//  2. A DESTINATION may assert READY before or after VALID.               (either is legal)
//  3. Write response: BVALID only AFTER the AW handshake AND the accepted
//     final write-data beat (WLAST).                            (B follows AW and W)
//  4. Read data: RVALID only AFTER the AR handshake completes.             (R follows AR)
// Rule 1 broken on any channel, OR a dependency cycle across channels → DEADLOCK.

6. AXI3 vs AXI4 — A Relaxed Dependency

One historical note that's interview-relevant: AXI3 had a stricter write dependency — in effect, write data ordering was tied more tightly to the address. AXI4 relaxed it so the write data may arrive before, with, or after the write address (the decoupling from 2.4). This relaxation removed a dependency, which can only make the graph "more acyclic," never less — so it's safe. The lesson: AXI4's dependency set is the minimal one needed to prevent deadlock while maximizing decoupling; AXI3 was slightly more constrained. When bridging AXI3↔AXI4, this is one of the behaviours a converter must reconcile (Chapter 2.5).

7. How a Violation Deadlocks

Concretely, two ways to create a cycle and hang the bus:

  • Single-channel (the classic): a source codes VALID = f(READY)awvalid <= awready, say. Now AWVALID waits for AWREADY, and a slave that (legally) waits for AWVALID before AWREADY completes the cycle. Both flat-low forever (Figure 2).
  • Cross-channel (the subtle one): a master that refuses to accept read data (RREADY low) until it finishes a write, while the thing blocking the write is downstream of that same master's read traffic — a loop through the system, not one channel. Interconnects and bridges are where these arise, because they couple channels that the base rules kept independent. The defense is the same: never let a VALID (or an "accept") wait on something that ultimately waits on it.

The rules in §4–5 guarantee the base protocol is deadlock-free; system-level deadlocks come from logic layered on top (a master/bridge that adds its own cross-channel dependency). So "AXI can't deadlock" is true of the protocol and false of careless integration — which is exactly why this chapter is Critical.

8. Common Misconceptions

9. Debugging Insight

10. Verification Insight

11. The Rules as Executable Checks

The section above says "the dependency rules become a small, high-value assertion set." Here it is, written out. These four checks are the mandatory orderings of §A3.3.1 in SVA — and nothing else, because the single-channel VALID/READY mechanics already have their own executable proof in 3.1 — the VALID/READY handshake. This page's job is the cross-channel half.

The ordering rules are counting rules, so the checker counts. Each channel's completed handshakes are tallied, and a response is legal only if the transaction it answers has already been fully requested.

axi_dependency_checks.sv — the §A3.3.1 orderings, bound to a channel set
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
//  AXI4 cross-channel dependency checks (AMBA AXI4 §A3.3.1).
//  Bind to a master/slave/interconnect port:
//     bind axi_slave axi_dependency_checks u_dep (.*);
// ─────────────────────────────────────────────────────────────────────────
module axi_dependency_checks (
  input logic aclk, aresetn,
  input logic awvalid, awready,
  input logic wvalid,  wready, wlast,
  input logic bvalid,  bready,
  input logic arvalid, arready,
  input logic rvalid,  rready, rlast
);
 
  // ── Completed-handshake tallies, one per transaction-level event ───────
  int unsigned aw_seen, w_seen, b_seen, ar_seen, r_seen;
 
  always_ff @(posedge aclk or negedge aresetn) begin
    if (!aresetn) begin
      aw_seen <= 0;  w_seen <= 0;  b_seen <= 0;  ar_seen <= 0;  r_seen <= 0;
    end else begin
      if (awvalid && awready)            aw_seen <= aw_seen + 1;  // addresses taken
      if (wvalid  && wready && wlast)    w_seen  <= w_seen  + 1;  // writes fully delivered
      if (bvalid  && bready)             b_seen  <= b_seen  + 1;  // responses retired
      if (arvalid && arready)            ar_seen <= ar_seen + 1;  // read addrs taken
      if (rvalid  && rready && rlast)    r_seen  <= r_seen  + 1;  // reads retired
    end
  end
 
  // The registered counters are exactly the right reference, and it is worth
  // seeing why rather than reaching for a combinational "including this cycle"
  // total. A concurrent assertion samples in the Preponed region, so at the
  // edge where the slave accepts WLAST, `w_seen` is still the OLD count — the
  // increment lands after that edge. The earliest the slave can then drive
  // BVALID is the following cycle, which samples the incremented count and
  // passes. A response asserted any earlier samples the old count and fails.
  // So the registered form already permits the fastest legal response and
  // rejects everything ahead of it; adding current-cycle terms would only
  // widen the check into accepting a response that genuinely preceded its data.
 
  // ── Rule: B must follow the accepted final write-data beat ─────────────
  //  While BVALID is high the slave is offering response number b_seen
  //  (0-indexed). That write must already have delivered its WLAST, so the
  //  count of completed write payloads must exceed the responses retired.
  a_b_after_wlast:
  assert property (@(posedge aclk) disable iff (!aresetn)
      bvalid |-> (b_seen < w_seen))
    else $error("[%0t] BVALID asserted for a write whose WLAST has not been accepted (b_seen=%0d w_seen=%0d)",
                $time, b_seen, w_seen);
 
  // ── Rule: B must ALSO follow the accepted write address ────────────────
  //  The half of the rule that gets dropped. AXI4 decouples AW from W, so a
  //  slave can hold WLAST while AWVALID has never arrived; without this check
  //  it may respond to a transaction it cannot have identified.
  a_b_after_awaddr:
  assert property (@(posedge aclk) disable iff (!aresetn)
      bvalid |-> (b_seen < aw_seen))
    else $error("[%0t] BVALID asserted for a write whose address has not been accepted (b_seen=%0d aw_seen=%0d)",
                $time, b_seen, aw_seen);
 
  // ── Rule: R must follow the accepted read address ──────────────────────
  a_r_after_araddr:
  assert property (@(posedge aclk) disable iff (!aresetn)
      rvalid |-> (r_seen < ar_seen))
    else $error("[%0t] RVALID asserted for a read whose address has not been accepted (r_seen=%0d ar_seen=%0d)",
                $time, r_seen, ar_seen);
 
  // ── The covers that make the passes mean something ─────────────────────
  //  Each assertion above is an implication. On a quiet bus every attempt
  //  passes vacuously, so a clean run proves nothing without these.
  c_write_response_seen: cover property (@(posedge aclk) disable iff (!aresetn)
      bvalid && bready);
  c_read_data_seen:      cover property (@(posedge aclk) disable iff (!aresetn)
      rvalid && rready && rlast);
  c_wlast_before_awaddr: cover property (@(posedge aclk) disable iff (!aresetn)
      (w_seen > aw_seen));   // the AXI4 decoupling actually exercised
 
endmodule

What each check means, and what a failure means.

AssertionThe claimA failure tells you
a_b_after_wlastA write response is only offered for a write whose payload has been fully acceptedThe slave is acknowledging data it has not received. Any master treating BRESP as durability has been lied to.
a_b_after_awaddr…and whose address has been acceptedThe slave responded to a transaction it cannot have identified. Almost always a write-side FSM that keys off WLAST alone in a design where AW and W are decoupled.
a_r_after_araddrRead data is only offered for an address that was acceptedThe slave is sourcing data for a request it never took — a stale FIFO entry, or a read pipeline not flushed on reset.

The last cover, c_wlast_before_awaddr, is the one reviewers forget. It fires only when write data genuinely arrives ahead of its address, which is exactly the AXI4 relaxation described in §6. If it never fires, the regression has not exercised the decoupling, and a_b_after_awaddr has never been in a position to catch anything.

12. Safety, Liveness, and Performance — Three Different Claims

A deadlock is the absence of progress, and no assertion of the kind written above can detect it: every one of them is a safety property, and a hung bus never does anything wrong — it simply never does anything. Catching a hang needs a different kind of claim, and conflating the three is how pages like this one start stating things about AXI that AXI does not say.

The three claims, kept apart:

ClaimWhat it assertsWhere the bound comes from
Safety"this must never happen" — e.g. BVALID asserted before WLASTAMBA AXI4 §A3.3. Normative. A violation is a protocol bug.
Bounded liveness"this must happen within N cycles" — every VALID meets its READY inside the windowYour integration's latency budget. Not the spec. A violation is a hang, or a bound chosen too tight.
Performance"this should typically take about T" — 95% of reads return in under 40 cyclesYour architecture model. A violation is a performance bug, not a correctness one.

Encoded, they look different too: safety is unbounded SVA, bounded liveness is SVA with a finite ##[0:N] window, and performance is coverage and statistics rather than an assertion at all.

True liveness — "READY eventually asserts," with no bound — is unfalsifiable in a finite simulation: you can never observe "eventually." What simulation can do is bound it, and a bounded-liveness assertion is exactly a watchdog:

axi_liveness_watchdog.sv — a POLICY check, not a protocol check
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
//  Bounded-liveness watchdog. MAX_STALL is chosen from the SYSTEM's latency
//  budget — the deepest legitimate backpressure the integration can produce
//  under worst-case contention — with margin. It is NOT an AXI requirement,
//  and a firing watchdog is a finding to investigate, not a protocol verdict.
// ─────────────────────────────────────────────────────────────────────────
module axi_liveness_watchdog #(
  parameter int MAX_STALL = 1024
) (
  input logic aclk, aresetn,
  input logic awvalid, awready,
  input logic wvalid,  wready,
  input logic bvalid,  bready,
  input logic arvalid, arready,
  input logic rvalid,  rready
);
 
  // Once a source asserts VALID it must hold it until READY (the stability
  // rule from 3.1), so "the VALID that rose at cycle N is still waiting at
  // cycle N+k" is simply VALID still being high. The property therefore only
  // has to ask whether READY showed up inside the window.
  property p_no_indefinite_stall(logic valid, logic ready);
    @(posedge aclk) disable iff (!aresetn)
      $rose(valid) |-> ##[0:MAX_STALL] ready;
  endproperty
 
  // ##[0:MAX_STALL], not ##[1:MAX_STALL]: a destination may already be
  // asserting READY in the cycle VALID rises — a legal zero-stall transfer.
  // A window starting at 1 would demand a SECOND READY and fail every
  // full-throughput handshake on the bus.
 
  w_aw_progress: assert property (p_no_indefinite_stall(awvalid, awready))
    else $error("[%0t] AW stalled beyond %0d cycles — suspect a dependency cycle", $time, MAX_STALL);
  w_w_progress:  assert property (p_no_indefinite_stall(wvalid,  wready))
    else $error("[%0t] W stalled beyond %0d cycles — suspect a dependency cycle",  $time, MAX_STALL);
  w_b_progress:  assert property (p_no_indefinite_stall(bvalid,  bready))
    else $error("[%0t] B stalled beyond %0d cycles — suspect a dependency cycle",  $time, MAX_STALL);
  w_ar_progress: assert property (p_no_indefinite_stall(arvalid, arready))
    else $error("[%0t] AR stalled beyond %0d cycles — suspect a dependency cycle", $time, MAX_STALL);
  w_r_progress:  assert property (p_no_indefinite_stall(rvalid,  rready))
    else $error("[%0t] R stalled beyond %0d cycles — suspect a dependency cycle",  $time, MAX_STALL);
 
endmodule

Note what the watchdog does not claim. It does not say the stall was illegal; it says the stall exceeded the bound this system was designed to tolerate, which is a statement about your integration. That is still exactly what you want, because a genuine deadlock exceeds every bound — a true cycle of waiting never resolves, so any finite MAX_STALL catches it. The bound's only real job is to be large enough that legitimate contention never trips it.

13. Debugging Lab — A Cross-Channel Deadlock, End to End

1

Bus hangs under load; every channel individually obeys the cardinal rule

CROSS-CHANNEL-CYCLE
Observed Symptom

A DMA-to-DDR regression passes for weeks. A new test raises the DMA's outstanding-read depth from 4 to 16 and the simulation stops making progress at around 300 µs. No assertion fires for the first several minutes of wall-clock; eventually w_r_progress and w_aw_progress both report stalls past MAX_STALL. The simulation then runs to the regression's global timeout with no further activity of any kind.

Expected vs Actual

Expected. With 16 outstanding reads, the DMA issues reads, drains R beats as they return, and interleaves its write traffic; throughput rises, and every channel keeps moving.

Actual. ARVALID is high and ARREADY low, forever. RVALID is high and RREADY low, forever. AWVALID is high and AWREADY low, forever. Every VALID is behaving correctly — asserted from the source's own state, held stable, never waiting on its own READY. No ordering assertion fires. Nothing is wrong anywhere; nothing is moving anywhere.

Diagnostic

The first thing to establish is deadlock versus backpressure, and the signature settles it immediately: this is VALID high with READY low that never clears, which is neither of the two textbook pictures. It is not the flat-low-forever of a cardinal-rule violation (§2), and it is not the transient high-VALID/low-READY of ordinary backpressure — it has backpressure's shape and deadlock's permanence. That combination is the fingerprint of a cross-channel cycle: each party is legitimately stalling, and each party's stall is what the next party is waiting on.

So build the wait-for graph. For each stalled party, record the one thing it is blocked on:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  DMA         is not asserting RREADY   because its read-data buffer is full
  DMA buffer  is not draining           because the DMA drains it by writing to DDR
  DMA write   is not progressing        because AWVALID is not being accepted
  Interconnect is not asserting AWREADY because its write-issue slot is held
  write slot  is held                   because an earlier write is awaiting its B
  that B      is not returning          because the slave's response path is behind
  the slave   is behind                 because it is stalled on ... the DMA's reads

The last line closes the loop. Draw it and the cycle is visible: DMA reads → DMA buffer → DMA writes → interconnect write slot → slave response → DMA reads.

Root Cause

The DMA couples two channels that the base protocol deliberately keeps independent: it refuses RREADY until it can drain read data, and it drains read data by issuing writes. That makes read acceptance depend on write progress. The AXI dependency graph (§4) has no such arrow — the master added it.

At an outstanding depth of 4 the coupling was invisible, because the read buffer never filled before writes retired. At 16, reads outpace the write path, the buffer fills, RREADY drops, and the added back-edge closes a cycle that runs through the interconnect and the slave. Every individual channel remains fully compliant, which is precisely why no ordering assertion fired: the protocol was never violated. The system was.

Fix

Break the added back-edge — do not try to order around it. Read acceptance must not depend on write progress, so give the read-drain path a route that does not run through the write path:

  • Reserve buffer capacity per outstanding read. Issue a read only when the space to retire it already exists; then RREADY is never a function of anything downstream, and the back-edge disappears at the source. This is the structural fix and the one to prefer.
  • Failing that, bound the coupling. Cap outstanding reads at a depth the write path is provably able to retire, so the buffer cannot fill. This makes the cycle unreachable rather than absent — cheaper, and correspondingly more fragile, since it re-breaks the moment a downstream latency changes.

What is not a fix: raising MAX_STALL, adding an arbiter priority, or deepening the buffer. Each shifts the depth at which the cycle closes without removing it, which converts a reproducible hang into an intermittent one.

Prevention

Three things, in order of how much they pay back:

  1. Review every "wait" a master or bridge adds as a graph edge. The base protocol's graph is acyclic (§4); integration logic is where back-edges come from. Any RTL that gates one channel's READY on another channel's progress deserves the question "and what does that wait on?" until the answer bottoms out.
  2. Bind the bounded-liveness watchdog everywhere, permanently. It is what turned a silent hang into a timestamped finding here. Without it, this defect presents as "the regression got slower."
  3. Sweep outstanding depth in regression. This bug was latent at depth 4 and fatal at 16. Depth is the parameter that makes cross-channel cycles reachable, so it belongs in the constrained-random space, not pinned at whatever value the first test used.

14. Interview Questions

15. Summary

Deadlock is a cycle of waiting, and AXI prevents it by keeping the dependency graph acyclic. The foundation is the cardinal rule from 3.1 applied to every channel: a VALID must never wait for its READY — each VALID is an independent source, so some side always moves first. On top of that, AXI4 (§A3.3) defines which dependencies are allowed (a READY may wait for its VALID) and which are required (the mandatory orderings: B must follow the accepted write data, R must follow the accepted read address — the answer can't precede the question). Every arrow points forward; none feeds a READY back into its own VALID; the graph is a DAG and a DAG cannot deadlock.

Distinguish the failure from backpressure: backpressure is VALID high / READY low and resolves; deadlock is both low forever, or a cross-channel cycle, and never resolves. And remember the scope: the protocol is deadlock-free, but integration logic — masters, bridges, interconnects that couple channels — can add a back-edge and hang the system, which is why this is Critical. Debug a hang by finding the cycle in the wait-for graph and removing the illegal dependency; verify it with structural rule-assertions plus liveness timeouts. Next: the recurring handshake bugs that turn these rules into war stories.

17. Where This Is Specified

The dependency rules on this page are normative text in the Arm AMBA AXI Protocol Specification, §A3.3 — Dependencies between channel handshake signals — with the per-channel "must wait" / "may wait" list in §A3.3.1 and the handshake rules themselves in §A3.2. Arm publishes the specification on its AMBA AXI documentation page; it is the source to check before writing any dependency assertion, because §A3.3.1 is a short list in which the difference between must and may carries the entire deadlock-freedom argument — and it is the list from which "B follows W" is routinely quoted with the AW half missing.

One thing to confirm in the specification rather than take from any tutorial: there is no clause bounding how long a READY may remain low. Its absence is what makes every watchdog in §12 a policy rather than a protocol check, and searching for the rule and not finding it is a more durable way to learn that than being told.

The SVA used above is IEEE Std 1800 (SystemVerilog), clause 16 — see concurrent assertions for the sampling and implication semantics these checks rely on, and for why each one is paired with a cover.

Related lessons. The single-channel mechanics this page builds on are in 3.1 — VALID/READY handshake; the channel set in five channels and independent channels; the legitimate stall it must be distinguished from in backpressure and stalls. For the write-side ordering rule in detail see write ordering and WLAST; for the depth parameter that makes cross-channel cycles reachable, outstanding verification; and for the hands-on hunt, debugging deadlock and timeout debug.

16. What Comes Next

You have the rules that keep concurrency safe. Module 3 closes with the field guide to getting them wrong:

  • 3.6 — Common Handshake Bugs (coming next) — the recurring handshake mistakes (dropped VALID, combinational READY loops, ordering violations) and how to spot each.

Previous: 3.4 — Handshake Throughput. For the broader protocol catalog, see the AMBA family overview doc.