Same queue idea. Different physics. A sync FIFO has one clock: pointers are ordinary registers you can compare combinationally. An async FIFO has two clocks: you must not compare a live binary counter from the other domain.
| Sync FIFO | Async FIFO | |
|---|---|---|
| Clocks | One clk | wr_clk and rd_clk, unrelated |
| Memory | 1-port or simple dual-port RAM | True dual-port RAM (write on wr_clk, read on rd_clk) |
| Pointers | Binary, same domain | Binary locally, Gray across the CDC |
| Full flag | Write domain (same as read) | Generated in write domain from synced read pointer |
| Empty flag | Same clock | Generated in read domain from synced write pointer |
| Reset | One reset (sync or async-assert) | Per-domain reset; deassert synchronized on each clock |
Never sample a multi-bit binary counter with a foreign clock. That is the whole reason for Gray pointers.
An async FIFO does not use a divided copy of one clock. wr_clk and rd_clk come from different PLLs / pads. There is no common rising edge, no integer period ratio you may assume, and no legal combinational path between domains. The diagram below uses WaveDrom period and phase so the clocks are not the same grid β that is the picture you should keep in your head.
If two clocks look identical in a slide, treat it as a drawing bug β silicon will not line those edges up. Dual-port RAM is written on wr_clk and read on rd_clk. full is a write-domain signal; empty is a read-domain signal. Never AND them in one always block.
βCan I 2FF-synchronize an 8-bit data bus?β β No. Each bit can resolve to a different sample. Use a FIFO (or handshake + captured data, or Gray if the bus is a counter). Data in an async FIFO does not cross; only Gray pointers do.
When a Gray bit is sampled near its transition by rd_clk, the first synchronizer flop can sit at an illegal voltage for a while. The second flop is far less likely to see a mid-level. That is all the 2FF buys you: a clean bit, not a fresh pointer. The pointer is still one or two read clocks stale. Flags computed from it must stay conservative so a stale βnot fullβ never licenses a write into a truly full RAM.
Three-flop synchronizers appear in very high reliability flows. They add latency and reduce apparent FIFO depth further. This course uses 2FF as the industry default for internal chip CDC of Gray pointers with a constrained MTBF.
Write side: wr_clk, wr_rst_n, wr_en, wdata, full (and optional almost_full). Read side: rd_clk, rd_rst_n, rd_en, rdata, empty (and optional almost_empty, data_valid for FWFT). There is no shared clk. There is no combinational path from write-domain flops to read-domain flops except the intended Gray nets into synchronizer D-pins.
FPGA hard FIFO primitives (Xilinx FIFO Generator, Intel DCFIFO) implement this partition for you. You still need to know it: interviews and custom ASIC FIFOs will ask you to draw it from scratch.
A sync FIFO uses one clock; pointers are binary and compared in the same domain. An async FIFO uses two unrelated clocks, dual-port RAM for data, Gray-coded pointers through 2FF synchronizers, full in the write domain, and empty in the read domain.
No. They may come from different PLLs or pads. You must not assume a common edge or an integer period ratio. Waveforms that show identical clocks are a drawing error.
Each bit can resolve on a different sample. The captured word can be a value that was never driven. Keep payload in RAM and cross only a unit-distance Gray pointer.
In the write clock domain, from the local write Gray pointer compared with a 2FF-synchronized copy of the read Gray pointer. Empty is the mirror on the read clock.