Day 80: The async FIFO: full/empty generation across domains
Async FIFO: full/empty across domains
With gray pointers crossing safely, each side computes its flag against the *synchronized* copy of the other pointer. Empty is generated in the read domain (read pointer == synchronized write pointer). Full is generated in the write domain (write pointer about to catch the synchronized read pointer, detected via the gray MSBs). Because the synchronized pointer is slightly *stale*, these flags are conservative — occasionally pessimistic, never wrong.
Pessimistic is safe; optimistic is a bug
The synchronized pointer lags reality by a couple of cycles, so full may assert a touch early and empty may de-assert a touch late — the FIFO looks slightly *more* full/empty than it really is. That's fine: you never overflow or underflow. The cardinal rule is that a CDC flag must err toward *safe* (stall) rather than *permissive* (corrupt).
Verify it hard: drive the write and read sides at *different, unrelated* clock rates in the testbench, push thousands of items through, and check data integrity and that full/empty never allow overflow/underflow. This async FIFO becomes the safe data path across any CDC in ChipX (and a favorite interview design).
Ship for Day 80
Because the opposite pointer is synchronized (and thus slightly stale), the async FIFO’s full/empty flags are: