2.2.7 Gray Counter

May 27, 2025 ยท View on GitHub

Gray Counter

A Gray code is a binary number system in which each successive code differs by a single bit. This property makes Gray codes useful for reducing switching noise, error detection, and rotary encoders. Although sequential examples in this section focus on examples with a single clock domain, Gray codes are also fundamental for safely transferring counters across multiple clock domains.

Here we implement a Gray code counter. It is done by using a binary counter and converting the value to a gray code.

Binary to Gray code conversion

To convert a binary number to Gray code:

  • The most significant bit remains unchanged
  • Each remaining bit is XORed with the bit to its left

Verilog

module gray_counter #(
  parameter N = 4
) (
  input clock, clear,
  output reg [N-1:0] q
);
  reg [N-1:0] count;

   always @(posedge clock) begin
     if (clear) begin
        count <= 0;
        q <= 0;
      end else begin
        count <= count + 1;
        q <= { count[N-1], count[N-1:1] ^ count[N-2:0] };
      end
   end

endmodule

VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity gray_counter is
  generic (
    N : integer := 4
  );
  port (
    clock, clear : in std_logic;
    q : out std_logic_vector(N-1 downto 0)
  );
end entity;

architecture rtl of gray_counter is 
  signal count : std_logic_vector(N-1 downto 0);
  signal q_int : std_logic_vector(N-1 downto 0);
begin

  q <= q_int;

  process (clock) begin
    if rising_edge(clock) then
      if clear = '1' then 
        count <= (others => '0');
        q_int <= (others => '0');
      else 
        count <= std_logic_vector(unsigned(count) + 1);
        q_int <= count(N-1) & (count(N-1 downto 1) xor count(N-2 downto 0));
      end if;
    end if;
  end process;

end architecture;

Hardcaml

Direct translation

  let gray_counter_1 ~n ~clock ~clear =
    let spec = Reg_spec.create ~clock ~clear () in
    let q = Always.Variable.reg spec ~width:n in
    let out = Always.Variable.reg spec ~width:n in
    Always.(
      compile
        [ q <-- q.value +:. 1
        ; out <-- q.value.:(n - 1) @: q.value.:[n - 1, 1] ^: q.value.:[n - 2, 0]
        ]);
    out.value
  ;;

Idiomatic Hardcaml

  let gray_counter_2 ~n ~clock ~clear =
    let spec = Reg_spec.create ~clock ~clear () in
    let q = reg_fb spec ~width:n ~f:(fun q -> q +:. 1) in
    reg spec (msb q @: msbs q ^: lsbs q)
  ;;