Reflected binary Gray code: adjacent integers differ by exactly one bit. Conversion is XOR. You must be able to write both directions on a whiteboard.
| Dec | Binary | Gray = bin ^ (bin>>1) | Bits flipped from previous Gray |
|---|---|---|---|
| 0 | 0000 | 0000 | โ |
| 1 | 0001 | 0001 | 1 |
| 2 | 0010 | 0011 | 1 |
| 3 | 0011 | 0010 | 1 |
| 4 | 0100 | 0110 | 1 |
| 5 | 0101 | 0111 | 1 |
| 6 | 0110 | 0101 | 1 |
| 7 | 0111 | 0100 | 1 |
| 8 | 1000 | 1100 | 1 |
At wrap from 15 โ 0, Gray 1000 โ 0000 also flips one bit. The extra pointer MSB in a FIFO is part of this Gray word, so wrap of the circular buffer stays unit-distance.
// Gray[i] = bin[i] ^ bin[i+1], with Gray[MSB] = bin[MSB]
function [PTR_W-1:0] bin2gray;
input [PTR_W-1:0] bin;
begin
bin2gray = bin ^ (bin >> 1);
end
endfunction
Example: bin=0111 (7). bin>>1 = 0011. XOR = 0100. Matches the table.
MSB of binary equals MSB of Gray. Each lower bit is XOR of all Gray bits above it (or iteratively XOR with the binary bit just recovered).
function [PTR_W-1:0] gray2bin;
input [PTR_W-1:0] gray;
integer i;
begin
gray2bin[PTR_W-1] = gray[PTR_W-1];
for (i = PTR_W-2; i >= 0; i = i-1)
gray2bin[i] = gray2bin[i+1] ^ gray[i];
end
endfunction
Classic Cummings async FIFO does not need gray2bin in the flag path. Full/empty compare Gray codes directly (with two MSBs inverted for full). You convert back to binary only if you want occupancy in the destination domain for almost-full watermarks.
// On the Gray pointer register in one clock domain: assert property (@(posedge clk) disable iff (!rst_n) $onehot0(gray ^ $past(gray))); // $onehot0: 0 or 1 bits set in the XOR โ 0 or 1 bits changed.
Reflected binary Gray is built so each increment flips the lowest bit that keeps the code a prefix reflection. The XOR-with-shift identity implements that map in hardware with no table. You can prove adjacent integers differ by one Gray bit by checking that exactly one bit of g(n) ^ g(n+1) is set. Interviews may ask you to derive Gray(7) and Gray(8) by hand: 0111 ^ 0011 = 0100, 1000 ^ 0100 = 1100.
Gray codes are not monotonic as unsigned integers. You cannot subtract two Gray words and get occupancy. Always convert the synchronized Gray back to binary, then subtract modulo 2^PTR_W. That is why almost-full lives in the write domain after gray2bin(wq2_rgray). Flag compares stay in Gray because equality and the two-MSB invert are cheap and match the extra-MSB full geometry.
gray = bin ^ (bin >> 1). The MSB of Gray equals the MSB of binary.
bin[MSB] = gray[MSB]; each lower bit is the XOR of the binary bit above it with the Gray bit at that position (prefix XOR from the MSB).
No. They compare Gray words directly (inverting two MSBs for full). Convert to binary only for occupancy watermarks.
For a binary counter that visits all 2^n states, including the wrap from 2^nโ1 to 0, adjacent Gray codes differ by one bit. That is why DEPTH must be a power of two in this style.
gray = bin ^ (bin >> 1).