Nov 13, 2016

Verilog Binary to gray code conversion

About the Author

Welcome to my digital design blog! I share in-depth articles on RTL design, timing analysis, ASIC/FPGA concepts, and interview preparation.

Binary to Gray Code Conversion

Binary-to-Gray code conversion is commonly used in digital systems, especially in asynchronous FIFO designs, rotary encoders, and clock-domain crossing applications.

Gray code is a binary numbering system in which only one bit changes between two consecutive values. This property helps reduce errors during transitions.

Binary-to-Gray Code Conversion Formula

The most significant Gray-code bit is equal to the most significant binary bit. Each remaining Gray-code bit is obtained by XORing two adjacent binary bits.

Formula:
Gray = Binary ⊕ (Binary >> 1)

For a six-bit binary number:

G[5] = B[5]
G[4] = B[5] ⊕ B[4]
G[3] = B[4] ⊕ B[3]
G[2] = B[3] ⊕ B[2]
G[1] = B[2] ⊕ B[1]
G[0] = B[1] ⊕ B[0]

Example

Consider the six-bit binary number:

Binary = 101101

The corresponding Gray code is calculated as follows:

Gray = Binary ⊕ (Binary >> 1)

Binary     = 101101
Binary >> 1 = 010110
Gray      = 111011

Hardware for Binary-to-Gray Conversion

Verilog Code for Binary-to-Gray Conversion

The following Verilog module converts an N-bit binary input into its corresponding Gray-code output.

module binary_to_gray #(
    parameter WIDTH = 6
) (
    input  wire [WIDTH-1:0] binary_in,
    output wire [WIDTH-1:0] gray_out
);

    // Binary-to-Gray conversion
    assign gray_out = binary_in ^ (binary_in >> 1);

endmodule

Registered Binary-to-Gray Converter

If the output must be synchronized with a clock, a registered version can be used.

module binary_to_gray_registered #(
    parameter WIDTH = 6
) (
    input  wire                 clk,
    input  wire                 rst_n,
    input  wire [WIDTH-1:0]     binary_in,
    output reg  [WIDTH-1:0]     gray_out
);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            gray_out <= {WIDTH{1'b0}};
        else
            gray_out <= binary_in ^ (binary_in >> 1);
    end

endmodule

Binary Counter with Gray-Code Output

This example generates a binary counter and continuously converts its value into Gray code.

module binary_gray_counter #(
    parameter WIDTH = 6
) (
    input  wire             clk,
    input  wire             rst_n,
    output reg  [WIDTH-1:0] binary_count,
    output wire [WIDTH-1:0] gray_count
);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            binary_count <= {WIDTH{1'b0}};
        else
            binary_count <= binary_count + 1'b1;
    end

    assign gray_count = binary_count ^ (binary_count >> 1);

endmodule

Truth Table for a Three-Bit Converter

Decimal Binary Gray Code
0 000 000
1 001 001
2 010 011
3 011 010
4 100 110
5 101 111
6 110 101
7 111 100

Advantages of Gray Code

  • Only one bit changes between consecutive values.
  • Reduces errors during transitions.
  • Useful in asynchronous FIFO pointer synchronization.
  • Commonly used in rotary encoders.
  • Can reduce glitches in digital logic.

Conclusion

Binary-to-Gray conversion is simple to implement using XOR gates. In Verilog, the conversion can be written as:

gray_out = binary_in ^ (binary_in >> 1);

This expression works for any bus width and synthesizes into a simple XOR network.

Interview Questions and Answers

Q1. What is Gray code and why is it used?

Answer: Gray code is a binary numbering system in which two consecutive values differ by only one bit. It is used to avoid multi-bit transition errors in systems such as asynchronous FIFO pointers, rotary encoders, and analog-to-digital converters, because a single-bit change eliminates the possibility of intermediate false states during a transition.

Q2. Write the equation for binary-to-Gray conversion.

Answer: The conversion equation is:

Gray = Binary ⊕ (Binary >> 1)

The MSB of the Gray code equals the MSB of the binary value, and every other Gray bit is the XOR of two adjacent binary bits: G[i] = B[i+1] ⊕ B[i].

Q3. Write the equation for Gray-to-binary conversion.

Answer: The MSB is copied directly, and each binary bit is obtained by XORing the previous binary bit with the corresponding Gray bit:

B[MSB] = G[MSB]
B[i] = B[i+1] ⊕ G[i]   for all remaining bits

In Verilog, Gray-to-binary requires an iterative XOR-reduce (prefix XOR), for example: for (i=0; i<WIDTH-1; i=i+1) bin[i] = ^gray[WIDTH-1:i]; or a loop that accumulates: bin[i] = bin[i+1] ^ gray[i];

Q4. Why is Gray code used for FIFO pointers in asynchronous FIFOs?

Answer: When a multi-bit binary pointer crosses a clock domain through a synchronizer, multiple bits may change simultaneously and each bit may get sampled at a different time, producing a corrupted, invalid pointer value. Because a Gray-coded pointer changes only one bit at a time, even if the sample is metastable or delayed, the received value is either the old value or the new value — never an invalid intermediate value.

Q5. Is the FIFO depth required to be a power of 2 when using Gray-code pointers? Why?

Answer: Yes. Gray code wraps correctly (maintains the single-bit-change property between the last and first value) only when the counting sequence is a power of two, such as 8, 16, or 32 deep. For non-power-of-2 depths, the wrap from the last value back to zero would change multiple bits at once, breaking the CDC safety property.

Q6. What hardware is required to convert binary to Gray code?

Answer: Only a set of two-input XOR gates — one XOR gate per Gray output bit except the MSB, which is wired directly. An N-bit converter therefore needs N-1 XOR gates, and the logic depth is just one XOR gate, making the conversion very fast.

Q7. Convert binary 1011 to Gray code and Gray code 1011 back to binary.

Answer:

  • Binary 1011 → Gray: G3 = 1, G2 = 1⊕0 = 1, G1 = 0⊕1 = 1, G0 = 1⊕1 = 0 → Gray = 1110
  • Gray 1011 → Binary: B3 = 1, B2 = 1⊕0 = 1, B1 = 1⊕1 = 0, B0 = 0⊕1 = 1 → Binary = 1101

Q8. Write a synthesizable Verilog one-liner for binary-to-Gray conversion.

Answer:

assign gray = bin ^ (bin >> 1);

This works for any vector width and synthesizes to a single level of XOR gates.

Q9. Can Gray code be used for arithmetic operations directly?

Answer: No. Gray code is a reflected, non-weighted code — bit positions have no fixed weights, so addition, subtraction, and comparison cannot be performed directly. The value must be converted back to binary before arithmetic. This is why asynchronous FIFOs internally increment the binary pointer and convert to Gray only for the clock-domain-crossing stage.

Q10. What is the difference between binary code and Gray code?

Feature Binary Code Gray Code
Bit changes between consecutive values One or more bits Exactly one bit
Weighted code Yes (positional weights) No (non-weighted)
Arithmetic support Direct Not directly
Typical use General computation CDC, encoders, K-maps

Q11. Why is Gray code used in Karnaugh maps?

Answer: Karnaugh maps order their rows and columns in Gray-code sequence so that physically adjacent cells differ by exactly one input variable. This allows logically adjacent minterms to be visually identified and grouped into larger implicants for simplified Boolean expressions.

Q12. What happens if a multi-bit binary pointer is synchronized directly across clock domains?

Answer: Different bits can be sampled at different instants (due to skew and metastability), so the receiving domain may capture a value that never actually existed — for example, a transitioning pointer 0111 → 1000 could be seen as 1111, 0000, or 1100. Such a corrupted pointer can cause FIFO full/empty flags to be computed incorrectly, leading to data corruption or overflow/underflow. Gray coding eliminates this failure mode.

Q13. How would you write a Gray-code counter directly (without converting from binary)?

Answer: A Gray-code counter computes the next Gray value by finding the least significant set bit of the current Gray value, XORing it with the previous binary value, and converting back to Gray. A common approach:

// Convert Gray back to binary, increment, convert to Gray
wire [WIDTH-1:0] bin_next = bin + 1'b1;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        bin  <= {WIDTH{1'b0}};
        gray <= {WIDTH{1'b0}};
    end else begin
        bin  <= bin_next;
        gray <= bin_next ^ (bin_next >> 1);
    end
end

Q14. In which other applications is Gray code used?

Answer:

  • Rotary and linear position encoders (avoids false intermediate readings).
  • Asynchronous FIFO read/write pointers.
  • Karnaugh maps for Boolean simplification.
  • Error reduction in analog-to-digital converters (e.g., shaft-angle encoders).
  • Sequential logic state encoding where adjacent states must differ by one bit to reduce glitches.
  • Genetic algorithms and Gray-coded modulation (e.g., QAM constellation labeling) for improved error performance.

Q15. Is Gray code unique? How many N-bit Gray codes exist?

Answer: No. The standard reflected binary Gray code is just one member of a family of Hamiltonian cycles on an N-dimensional hypercube. Any cycle that visits all 2N vertices exactly once, with adjacent vertices differing in one bit, is a valid N-bit Gray code. The reflected binary form is the most widely used because of its simple conversion equations.

Quick Revision Tip: Remember two one-liners — Binary→Gray: gray = bin ^ (bin >> 1)  |  Gray→Binary: bin[i] = bin[i+1] ^ gray[i] (prefix XOR). Most interview follow-ups (FIFO, CDC, power-of-2 depth) come directly from the single-bit-change property.

📚 Related Reading

Prepare for your digital design interview with our comprehensive synthesis interview guide:

🔗 Synthesis Interview Questions & Answers

Cover topics: RTL coding styles, gate-level netlist, area vs. timing trade-offs, pipeline insertion, fanout, and more.

Table of Contents

SiteMap