Skip to content

AMBA AXI · Module 14

AXI Across Clock Domains

The clock-domain-crossing (CDC) problem for AXI — metastability, why multi-bit buses can't be naively synchronized, why per-signal synchronizers fail for a handshaked bus, and why async FIFOs are the safe crossing for each AXI channel.

Real SoCs have multiple clock domains — a CPU at one frequency, peripherals at another, memory at a third — and AXI interfaces frequently cross between them. Crossing a clock-domain boundary safely is the CDC (clock-domain-crossing) problem, and AXI makes it harder than a single signal because it's a multi-signal, handshaked bus: VALID, READY, ADDR, DATA, and more must cross coherently. This chapter explains the underlying hazard (metastability), why multi-bit buses can't be naively synchronized, why synchronizing each AXI signal independently is wrong, and why the safe answer is an async FIFO per channel — the foundation for the async bridges of Chapter 14.2.

1. The Hazard — Metastability

When a signal generated in one clock domain is sampled by a flip-flop in another, the source signal can change arbitrarily close to the destination clock edge — violating the flop's setup/hold window. The flop can then enter a metastable state: its output hovers between 0 and 1 for an unpredictable time before resolving randomly. If that metastable value propagates into logic, it causes unpredictable, intermittent failures.

For a single-bit signal, the standard fix is a synchronizer — two (or more) back-to-back flops in the destination domain. The first flop may go metastable, but it has a full clock period to resolve before the second flop samples it, making the probability of metastability propagating vanishingly small (quantified by MTBF). This handles control bits safely. But a synchronizer only works for one bit at a time — and that's exactly where a multi-bit bus breaks.

Source signal sampled near destination clock edge goes metastable; a two-flop synchronizer resolves it for single-bit signals.Source-domain signalchanges near dst edgeMetastablesetup/hold violated →undefined2-FF synchronizerresolves single bit (MTBF)12
Figure 1 — the metastability hazard. A signal from the source domain can change near the destination clock edge, violating setup/hold and driving the sampling flop metastable (output undefined for a time). A single-bit synchronizer (2 flops) gives the metastable value a cycle to resolve, making failure vanishingly rare — but it only protects one bit.

2. Multi-Bit Buses Can't Be Naively Synchronized

The critical problem: you cannot safely synchronize a multi-bit bus (ADDR, DATA) by putting a synchronizer on each bit independently. The reason is bit skew — when the bus transitions, the bits don't all change at exactly the same instant (routing/timing differences), and each bit's synchronizer resolves its metastability independently and randomly. So on the destination side, some bits may resolve to the new value while others resolve to the old value in the same cycle — producing a garbage value that was never actually on the bus.

For example, a bus going from 0x0F to 0x10 (multiple bits changing) sampled mid-transition could resolve to 0x1F, 0x00, or any mix — a value the source never drove. Per-bit synchronizers make each bit metastability-safe but do nothing to keep the bits coherent as a word. So multi-bit data needs a fundamentally different crossing technique than control bits.

cdc-problem — multi-bit bus sampled mid-transition resolves to garbage

6 cycles
A multi-bit DATA bus transitions from 0x0F to 0x10 near the destination clock edge; the destination samples a garbage mix because bits resolve independently.bits resolve independently → never-driven valuebits resolve independe…src_clkdst_clkdata_src0F0F10101010data_dst0F0F??101010t0t1t2t3t4t5
Figure 2 — cdc-problem: a multi-bit bus sampled mid-transition. As DATA changes from old to new near the destination edge, the bits resolve independently — some to old, some to new — yielding a garbage word (here neither the old 0x0F nor the new 0x10, but a mix) that was never on the bus. Per-bit synchronizers don't keep the word coherent; multi-bit data needs a different crossing.

3. Why Per-Signal AXI Synchronizers Fail

AXI compounds the problem because it's a handshaked, multi-signal protocol. Even setting aside multi-bit data skew, synchronizing each AXI signal (VALID, READY, ADDR, DATA) independently is wrong, because the synchronizers have different, independent latencies:

  • VALID might cross in 2 cycles while DATA (if it could even cross — it can't naively) crosses in a different number — so the receiver could see VALID asserted before the corresponding DATA is stable, latching the wrong data.
  • The VALID/READY handshake timing is destroyed — the carefully-coupled relationship (data stable while VALID held until READY) is broken if VALID and the payload cross with different, uncorrelated delays.

So the AXI signals must cross together, coherently — the payload (ADDR/DATA) must be guaranteed stable and associated with its VALID on the destination side. Independent per-signal synchronization gives no such guarantee. This is why a proper AXI CDC isn't "synchronize the signals" — it's a structured mechanism that crosses the data and its control as a coherent unit.

Independent synchronizers on VALID, DATA, READY have different latencies, breaking data-VALID association and handshake timing.Per-signal syncVALID, DATA, READY separatelyDifferent latenciesVALID before DATA stableHandshake brokenVALID/READY timing lostNeed coherent crossingpayload + VALID together12
Figure 3 — why per-signal synchronization fails for AXI. Synchronizing VALID, READY, ADDR, DATA independently gives them different, uncorrelated latencies, so the receiver may see VALID before DATA is stable (wrong data latched) and the VALID/READY handshake timing is destroyed. AXI signals must cross together, coherently — payload associated with its VALID — which independent synchronizers can't guarantee.

4. The Safe Crossing — Async FIFO per Channel

The standard, safe AXI CDC is an asynchronous FIFO on each channel. An async FIFO has a write port in the source domain and a read port in the destination domain, with a dual-clock memory between them:

  • Data rides through memory. The payload (ADDR/DATA/etc.) is written into the FIFO in the source domain and read out in the destination domain — it's only read when the FIFO indicates it's present and stable, so the destination never samples mid-transition. The multi-bit data never needs per-bit synchronizing because it's stored, not sampled-in-flight.
  • Pointers cross safely via Gray code. The FIFO's write and read pointers must cross domains (to compute full/empty), and they're Gray-coded — only one bit changes per increment — so a pointer can be synchronized bit-by-bit safely (a single-bit change can't produce a garbage multi-bit value; at worst the synchronized pointer lags by a cycle, which is safe/conservative for full/empty).

So the principle is: cross the control (pointers) as single-bit-safe Gray code through synchronizers, and let the data ride through the FIFO memory, read only when safe. Each AXI channel (AW, W, B, AR, R) gets its own async FIFO, preserving the per-channel handshake across the boundary. This is exactly what the interconnect's clock converter (Chapter 12.7) implements, and it's the structure the async bridges of Chapter 14.2 detail.

Async FIFO: data written in source domain rides through memory read in destination domain; Gray-coded pointers cross safely via synchronizers.full/emptyWrite payload(source clock)Dual-clock FIFOmemoryRead payload(dest clock) —only whenpresentGray-coded pointerscross (1-bit-safesync)
Figure 4 — the async FIFO crossing. Payload data is written in the source domain and read in the destination domain through dual-clock memory — read only when present, so never sampled mid-transition (no per-bit sync needed). The write/read pointers cross via Gray code (one bit changes per increment) through synchronizers — single-bit-safe. Control crosses as Gray-coded pointers; data rides through memory. One async FIFO per AXI channel.

5. Common Misconceptions

6. Debugging Insight

7. Verification Insight

8. Interview Questions

9. Summary

Crossing an AXI interface between clock domains is the CDC problem, rooted in metastability: a signal sampled near the destination edge can hover undefined and cause intermittent failures. Single-bit control signals are crossed with synchronizers (2-FF, high MTBF), but multi-bit buses cannot be naively synchronized — per-bit synchronizers resolve independently, so bit skew produces garbage words never on the bus. AXI compounds this: synchronizing its signals independently breaks the VALID/payload association (wrong data latched) and the handshake timing (uncorrelated latencies), so the signals must cross coherently.

The safe crossing is an async FIFO per channel: the payload rides through dual-clock memory (written in the source domain, read in the destination domain only when present — never sampled mid-transition), while the Gray-coded pointers cross through synchronizers (one bit changes per increment → single-bit-safe, conservative full/empty). Control crosses as Gray pointers; data rides through memory. Each AXI channel gets its own FIFO, preserving the handshake — the interconnect's clock converter (12.7) and the async bridges (14.2). Critically, CDC needs static CDC analysis (functional sim doesn't model metastability), complemented by metastability injection — a structural proof that every crossing is safe. Next: the async bridge structure that implements this per-channel.

10. What Comes Next

You've got the CDC problem and principle; next, the bridge that implements it:

Previous: 13.6 — Identifying Performance Bottlenecks. Related: 12.7 — Clock & Reset in Interconnect for where clock converters sit in the fabric. For the broader protocol catalog, see the AMBA family overview doc.