]> git.the-white-hart.net Git - vhdl/commitdiff
Use Gray counters in clock domain crossing FIFO
authorrs <>
Wed, 12 Nov 2025 00:41:25 +0000 (18:41 -0600)
committerrs <>
Wed, 12 Nov 2025 00:41:25 +0000 (18:41 -0600)
libraries/utility/fifo_xclk.vhd
libraries/utility/gray_counter.vhd [new file with mode: 0644]
libraries/utility/tests/test_graycounter.vhd [new file with mode: 0644]

index a21ef0c2910088f5a67c0ad104db2e02017c1db7..d2e55ceaa1266cde25933a64aa97672fb9761ae2 100644 (file)
@@ -26,15 +26,16 @@ end fifo_xclk;
 architecture behavioral of fifo_xclk is
 
        signal tail_adr_xclk: std_logic_vector(10 downto 0);
-       signal head_adr_reg:  unsigned(10 downto 0) := (others => '0');
-       signal head_adr_next: unsigned(10 downto 0);
+       signal head_adr_reg:  std_logic_vector(10 downto 0) := (others => '0');
+       signal head_adr_next: std_logic_vector(10 downto 0);
        signal head_rdy:      std_logic;
        signal head_step:     std_logic;
        signal is_full:       std_logic;
 
        signal head_adr_xclk: std_logic_vector(10 downto 0);
-       signal tail_adr_reg:  unsigned(10 downto 0) := (others => '0');
-       signal tail_adr_next: unsigned(10 downto 0);
+       signal tail_adr_reg:  std_logic_vector(10 downto 0) := (others => '0');
+       signal tail_adr_inc:  std_logic_vector(10 downto 0);
+       signal tail_adr_next: std_logic_vector(10 downto 0);
        signal tail_stb:      std_logic;
        signal tail_step:     std_logic;
        signal is_empty:      std_logic;
@@ -56,16 +57,16 @@ begin
        head_rdy_o <= head_rdy;
 
        head_step <= head_stb_i and head_rdy;
-       head_adr_next <= head_adr_reg + 1;
 
-       process (head_clk_i)
-       begin
-               if rising_edge(head_clk_i) then
-                       if head_step = '1' then
-                               head_adr_reg <= head_adr_next;
-                       end if;
-               end if;
-       end process;
+       e_head_adr: entity utility.gray_counter
+               generic map (N => 11)
+               port map (
+                       rst_i => '0',
+                       clk_i => head_clk_i,
+                       ena_i => head_step,
+                       gray  => head_adr_reg,
+                       inc   => head_adr_next
+               );
 
 
        -- Tail logic
@@ -83,16 +84,17 @@ begin
        tail_stb_o <= tail_stb;
 
        tail_step <= tail_stb and tail_ack_i;
-       tail_adr_next <= tail_adr_reg + 1 when tail_step = '1' else tail_adr_reg;
-
-       process (tail_clk_i)
-       begin
-               if rising_edge(tail_clk_i) then
-                       if tail_step = '1' then
-                               tail_adr_reg <= tail_adr_next;
-                       end if;
-               end if;
-       end process;
+       tail_adr_next <= tail_adr_inc when tail_step = '1' else tail_adr_reg;
+
+       e_tail_adr: entity utility.gray_counter
+               generic map (N => 11)
+               port map (
+                       rst_i => '0',
+                       clk_i => tail_clk_i,
+                       ena_i => tail_step,
+                       gray  => tail_adr_reg,
+                       inc   => tail_adr_inc
+               );
 
 
        -- FIFO memory
diff --git a/libraries/utility/gray_counter.vhd b/libraries/utility/gray_counter.vhd
new file mode 100644 (file)
index 0000000..c14020f
--- /dev/null
@@ -0,0 +1,48 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+
+entity gray_counter is
+       generic (N: positive := 8);
+       port (
+               rst_i: in  std_logic;
+               clk_i: in  std_logic;
+               ena_i: in  std_logic;
+
+               gray:  out std_logic_vector(N-1 downto 0);
+               inc:   out std_logic_vector(N-1 downto 0)
+       );
+end gray_counter;
+
+
+architecture behavioral of gray_counter is
+
+       signal count_reg:  unsigned(N-1 downto 0) := (others => '0');
+       signal count_next: unsigned(N-1 downto 0);
+
+       signal gray_reg:   std_logic_vector(N-1 downto 0) := (others => '0');
+       signal gray_next:  std_logic_vector(N-1 downto 0);
+
+begin
+
+       gray <= gray_reg;
+       inc  <= gray_next;
+
+       count_next <= count_reg + 1;
+       gray_next  <= std_logic_vector(count_next xor ('0' & count_next(N-1 downto 1)));
+
+       process (rst_i, clk_i)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               gray_reg  <= (others => '0');
+                               count_reg <= (others => '0');
+                       elsif ena_i = '1' then
+                               gray_reg  <= gray_next;
+                               count_reg <= count_next;
+                       end if;
+               end if;
+       end process;
+
+end behavioral;
diff --git a/libraries/utility/tests/test_graycounter.vhd b/libraries/utility/tests/test_graycounter.vhd
new file mode 100644 (file)
index 0000000..0b241b7
--- /dev/null
@@ -0,0 +1,47 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_graycounter is
+end test_graycounter;
+
+
+architecture behavior of test_graycounter is
+
+       signal rst: std_logic;
+       signal clk: std_logic;
+       signal ena: std_logic;
+       signal gray: std_logic_vector(7 downto 0);
+
+begin
+
+       p_test: process
+       begin
+               ena <= '0';
+               rst <= '1';
+               wait until rising_edge(clk);
+               rst <= '0';
+               ena <= '1';
+               wait;
+       end process;
+
+       e_gray: entity work.gray_counter
+               generic map (N => 8)
+               port map (
+                       rst_i => rst,
+                       clk_i => clk,
+                       ena_i => ena,
+                       gray  => gray
+               );
+
+       p_clk: process
+       begin
+               clk <= '0';
+               wait for 10 ns;
+               clk <= '1';
+               wait for 10 ns;
+       end process;
+
+end;