Every FIFO pointer and every free-running counter that crosses into another clock domain faces the same hazard: the sampling edge can land while the value is changing. Binary code then tears, because each bit resolves independently to old or new. Gray code is ordered so that consecutive values differ in exactly one bit, which bounds the damage of a torn sample.
Each step of the counter flips exactly one Gray bit, including the wrap from the last value back to zero. If a destination flop samples the bus while that one bit is changing, the bit settles to the old or the new value, so the whole sample reads the old value or the new value. There is no third logic outcome; the per-bit synchroniser is still required because the one changing bit can itself go metastable.
Count | Binary | Gray | Bits changing (binary / Gray) |
|---|---|---|---|
0 | 000 | 000 | – |
1 | 001 | 001 | 1 / 1 |
2 | 010 | 011 | 2 / 1 |
3 | 011 | 010 | 1 / 1 |
4 | 100 | 110 | 3 / 1 |
At count 3 to 4 the binary value changes three bits at once while Gray changes one. That row is the whole argument.
Consecutive values only. The source must advance (or retreat) one step at a time. Loads, resets to arbitrary values, and skipped counts break the rule, because the jump changes several bits.
Sampled values may be stale but never wrong by more than the step. Synchroniser latency means the destination sees older values, typically two to three cycles behind. For a FIFO pointer that staleness is conservative (full early, empty early), never corrupt.
One changing bit at a time. The Gray value must come straight from source-domain flops. Combinational logic after the conversion can glitch several bits during the step and reintroduce tearing.
Check | Evidence |
|---|---|
The crossing carries a Gray-coded value | Conversion |
Single-bit steps hold on every transition | Exhaustive adjacency check, including the wrap (next lesson) |
No jumps on the crossed value | No load, reset-to-arbitrary, or skip on the Gray register |
Registered source, per-bit synchronisers | Gray flops in the source domain, one synchroniser chain per bit |
Two: the old value or the new value. Only one bit is in flight, so the sample resolves each bit to old or new and the two outcomes are exactly the two consecutive values.
No. Latency makes the sample stale, not wrong. The value observed is a genuine past value, one whole step, which conservative full and empty logic tolerates.