2026-05-01
You already know binary counting: 00, 01, 10, 11. Simple. But watch what happens at the transition from 01 to 10 — both bits change simultaneously. In real hardware, those two bits don't flip at the exact same picosecond. For a brief moment, the bus might read 00 or 11 — neither the old value nor the new one. You met this glitch window when we covered clock domain crossing and FIFO design. Gray code is the specific weapon hardware engineers deploy against it.
The Rule: In Gray code, exactly one bit changes between any two adjacent values. The 3-bit sequence goes: 000, 001, 011, 010, 110, 111, 101, 100. Looks random until you see the construction method.
Binary-to-Gray conversion is dead simple in hardware — it's a single row of XOR gates:
G[n] = B[n]G[i] = B[i+1] XOR B[i]For binary 0110: G[3]=0, G[2]=0 XOR 1=1, G[1]=1 XOR 1=0, G[0]=1 XOR 0=1. Result: 0101. That's it — three XOR gates for a 4-bit conversion. Zero clock cycles, pure combinational logic.
Gray-to-binary is slightly trickier — it's an XOR chain where each output depends on the one above it: B[i] = B[i+1] XOR G[i], starting from the MSB. This creates a ripple dependency, but for typical FIFO pointer widths (8–12 bits) the propagation delay is negligible.
The real-world application you've already seen: asynchronous FIFO pointers. When a write pointer crosses from the write clock domain into the read domain through a synchronizer, you need to guarantee that even if the synchronizer catches the pointer mid-transition, the captured value is at most one count behind — never a wild, corrupted value. Gray code guarantees this because only one bit is in flight at any moment. A binary pointer transitioning from 0111 to 1000 has four bits changing; the synchronizer could capture anything from 0000 to 1111.
Rule of thumb for FIFO designers: your pointer comparison (full/empty detection) should happen in the Gray domain, not after converting back to binary. Converting back introduces the same multi-bit-change problem you were trying to avoid. Compare Gray-coded pointers directly — "equal" still means empty, and "MSBs differ, rest equal" still means full, because Gray code preserves those relationships.
One subtlety: Gray codes only work for power-of-two counting ranges. If your FIFO depth isn't a power of two, you can't use standard Gray encoding — the wrap-around point would violate the single-bit-change property. This is why virtually every asynchronous FIFO you'll encounter in practice uses power-of-two depths.
