If you sample a binary counter with another clock, several bits can be in transition at once. The captured vector can be a value the counter never held. That illegal pointer is the convergence / multi-bit CDC problem β and it is why async FIFOs use Gray code.
A 4-bit binary count going from 7 to 8:
0111 β 1000 β all four bits flip.
The destination flop bank samples during that transition. Because of skew on the bus and metastability per bit, you might capture:
| Captured | Decimal | Legal count? |
|---|---|---|
| 0111 | 7 | old, OK |
| 1000 | 8 | new, OK |
| 1111 | 15 | never a neighbor of 7 or 8 |
| 0000 | 0 | illegal jump |
| 1100 | 12 | illegal |
An illegal pointer compared for full/empty can assert empty when the FIFO still has data (underflow next) or deassert full when there is no space (overflow). That is a silicon bug, not a βrare glitchβ.
Each bit is a separate CDC. After 2FF sync, each bit is βcleanβ digitally β but they were sampled at slightly different times. When you recombine them into one vector and decode it (compare pointers, compute occupancy), the bits have converged from different sample instants. The vector is coherent only if at most one bit was allowed to change.
Four independent synchronizers + one compare = reconvergent CDC. Forbidden for binary counters.
Gray(7)=0100, Gray(8)=1100. One bit. A 2FF synchronizer on that bus captures either 0100 or 1100 β both legal pointer encodings. Occupancy interpreted from a stale Gray is conservative (you might think the FIFO is a little more full or more empty than it is), never wildly wrong.
βWhy Gray for pointers but not for FIFO data?β β Data is not a unit-distance code; any bit pattern is legal payload. You keep data in dual-port RAM and only synchronize the address/count. Gray is for monotone pointers.
People mix two failures. Metastability is an analog linger on one flop; 2FF makes the downstream digital world binary again with high MTBF. An illegal vector is a perfectly digital 4-bit number that was never a valid count. Two-flopping each binary bit does not fix illegal vectors. Gray reduces the CDC to one bit so the only uncertainty is old vs new.
If two Gray bits ever toggle together because you XORβd combinationally (lesson 3.3), you re-introduce illegal vectors. Unit-distance is a property of the net you sample, not of a comment in the spec.
A single event (interrupt, packet-done) should use a pulse stretcher or handshake, not a 512-deep FIFO. A software-visible register that rarely changes can use a handshake + captured data (req/ack) rather than Gray. The async FIFO is for a stream of beats with backpressure. Using a FIFO for one flag wastes RAM and still needs you to size almost-empty correctly.
Several bits may toggle on one count. Destination flops sample at slightly different times and recombine into a count the source never held. Full/empty decoded from that chimera can overflow or underflow.
0111 to 1000 flips every bit. Gray 0100 to 1100 flips only the MSB. The Gray 2FF captures old or new, both legal.
It is late, not wild. Occupancy looks a little more full or empty than reality. Formulas must be written so late information is pessimistic, never optimistic about free space or available data.
Payload bits are not a unit-distance sequence. Any pattern is legal data. Store data in dual-port RAM; synchronize only the monotone pointer.