Gray Code Converter
Convert between binary and Gray code, generate the full sequence table for small widths, and grab Verilog/VHDL bin2gray and gray2bin functions - the safe way to cross counters between clock domains.
Results
- Binary in
- 10 (0b1010)
- Gray out
- 15 (0b1111)
Full 4-bit table
| Decimal | Binary | Gray | Gray (dec) |
|---|---|---|---|
| 0 | 0000 | 0000 | 0 |
| 1 | 0001 | 0001 | 1 |
| 2 | 0010 | 0011 | 3 |
| 3 | 0011 | 0010 | 2 |
| 4 | 0100 | 0110 | 6 |
| 5 | 0101 | 0111 | 7 |
| 6 | 0110 | 0101 | 5 |
| 7 | 0111 | 0100 | 4 |
| 8 | 1000 | 1100 | 12 |
| 9 | 1001 | 1101 | 13 |
| 10 | 1010 | 1111 | 15 |
| 11 | 1011 | 1110 | 14 |
| 12 | 1100 | 1010 | 10 |
| 13 | 1101 | 1011 | 11 |
| 14 | 1110 | 1001 | 9 |
| 15 | 1111 | 1000 | 8 |
Notes
- Adjacent Gray codes differ in exactly one bit, so a Gray-coded counter sampled in another clock domain is never off by more than one count - the trick behind async FIFO pointers.
- Gray order only survives CDC if the counter increments by 1: don't Gray-code a value that can jump.
// Gray code conversion functions
// Generated by libfpga.com/tools/gray-code
function [W-1:0] bin2gray(input [W-1:0] b);
bin2gray = b ^ (b >> 1);
endfunction
function [W-1:0] gray2bin(input [W-1:0] g);
integer i;
begin
gray2bin[W-1] = g[W-1];
for (i = W-2; i >= 0; i = i - 1)
gray2bin[i] = gray2bin[i+1] ^ g[i];
end
endfunction
-- Gray code conversion functions
-- Generated by libfpga.com/tools/gray-code
function bin2gray(b : std_logic_vector) return std_logic_vector is
begin
return b xor ('0' & b(b'high downto b'low + 1));
end function;
function gray2bin(g : std_logic_vector) return std_logic_vector is
variable b : std_logic_vector(g'range);
begin
b(g'high) := g(g'high);
for i in g'high - 1 downto g'low loop
b(i) := b(i + 1) xor g(i);
end loop;
return b;
end function;
About this tool
When a multi-bit counter crosses a clock domain, sampling it mid-transition can capture a mix of old and new bits — a binary counter going 7→8 flips four bits and can be read as anything. In Gray code, consecutive values differ in exactly one bit, so a mid-transition sample is at worst off by one count, never garbage. That property is the backbone of async FIFO pointers. This tool converts values both directions, prints the full sequence table for small widths, and provides the standard conversion functions (binary→Gray is one XOR; Gray→binary is a prefix XOR chain). Only counters that increment by one keep the property — don't Gray-code a value that jumps.