Sign in on the Premium hub to save lesson progress. This lesson is open to read so the page is a complete article, not an empty login wall.
Lesson 3.2

Gray code, bin2gray, gray2bin

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.

1

4-bit table (memorize the pattern)

DecBinaryGray = bin ^ (bin>>1)Bits flipped from previous Gray
000000000โ€”
1000100011
2001000111
3001100101
4010001101
5010101111
6011001011
7011101001
8100011001

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.

2

bin2gray โ€” one XOR

bin2gray
// 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.

3

gray2bin โ€” chain from MSB

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).

gray2bin
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.

4

SVA โ€” unit distance

gray_sva
// 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.
5

Why bin ^ (bin>>1) is unit-distance

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.

6

Occupancy math is not done in Gray

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.

Q

Frequently asked questions

What is the bin2gray formula?

gray = bin ^ (bin >> 1). The MSB of Gray equals the MSB of binary.

How do you convert Gray back to 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).

Do Cummings-style full/empty need gray2bin?

No. They compare Gray words directly (inverting two MSBs for full). Convert to binary only for occupancy watermarks.

Does Gray wrap stay unit-distance?

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.

Key takeaways

  • gray = bin ^ (bin >> 1).
  • gray2bin is a prefix XOR from the MSB.
  • Flag logic can stay in Gray; occupancy math needs binary.