From 3eb3a187fe4e42698470a2011c4f9c4e15431bb1 Mon Sep 17 00:00:00 2001 From: rs <> Date: Tue, 11 Nov 2025 15:01:29 -0600 Subject: [PATCH] Add clock domain crossers This is an initial commit, but there are some problems here. The FIFO should be using Gray code for the pointers to prevent data races between bits when sending the pointers across clock domains. Both the FIFO and synchronizers need reset logic as well. --- libraries/utility/fifo_xclk.vhd | 128 ++++++++++++++++++++++++++++++++ libraries/utility/xclk_sig.vhd | 34 +++++++++ libraries/utility/xclk_vec.vhd | 31 ++++++++ 3 files changed, 193 insertions(+) create mode 100644 libraries/utility/fifo_xclk.vhd create mode 100644 libraries/utility/xclk_sig.vhd create mode 100644 libraries/utility/xclk_vec.vhd diff --git a/libraries/utility/fifo_xclk.vhd b/libraries/utility/fifo_xclk.vhd new file mode 100644 index 0000000..a21ef0c --- /dev/null +++ b/libraries/utility/fifo_xclk.vhd @@ -0,0 +1,128 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library unisim; +use unisim.vcomponents.all; + +library utility; + + +entity fifo_xclk is + port ( + head_clk_i: in std_logic; + head_stb_i: in std_logic; + head_rdy_o: out std_logic; + head_dat_i: in std_logic_vector(7 downto 0); + + tail_clk_i: in std_logic; + tail_stb_o: out std_logic; + tail_ack_i: in std_logic; + tail_dat_o: out std_logic_vector(7 downto 0) + ); +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_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_stb: std_logic; + signal tail_step: std_logic; + signal is_empty: std_logic; + +begin + + -- Head logic + + e_xclk_tail: entity utility.xclk_vec + port map ( + a_sig_i => std_logic_vector(tail_adr_reg), + b_clk_i => head_clk_i, + b_sig_o => tail_adr_xclk + ); + + is_full <= '1' when std_logic_vector(head_adr_next) = tail_adr_xclk else '0'; + + head_rdy <= not is_full; + 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; + + + -- Tail logic + + e_xclk_head: entity utility.xclk_vec + port map ( + a_sig_i => std_logic_vector(head_adr_reg), + b_clk_i => tail_clk_i, + b_sig_o => head_adr_xclk + ); + + is_empty <= '1' when std_logic_vector(tail_adr_reg) = head_adr_xclk else '0'; + + tail_stb <= not is_empty; + 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; + + + -- FIFO memory + + e_fifo: ramb16_s9_s9 + generic map ( + SIM_COLLISION_CHECK => "GENERATE_X_ONLY" + ) + port map ( + -- Port A is the FIFO head + wea => head_step, + ena => '1', + ssra => '0', + clka => head_clk_i, + addra => std_logic_vector(head_adr_reg), + dia => head_dat_i, + dipa => "0", + doa => open, + dopa => open, + + -- Port B is the FIFO tail + web => '0', + enb => '1', + ssrb => '0', + clkb => tail_clk_i, + addrb => std_logic_vector(tail_adr_next), + dib => x"00", + dipb => "0", + dob => tail_dat_o, + dopb => open + ); + +end behavioral; diff --git a/libraries/utility/xclk_sig.vhd b/libraries/utility/xclk_sig.vhd new file mode 100644 index 0000000..aec6e8c --- /dev/null +++ b/libraries/utility/xclk_sig.vhd @@ -0,0 +1,34 @@ +library ieee; +use ieee.std_logic_1164.all; + + +entity xclk_sig is + generic ( + INIT: std_logic := '0' + ); + port ( + a_sig_i: in std_logic; + + b_clk_i: in std_logic; + b_sig_o: out std_logic + ); +end xclk_sig; + + +architecture behavioral of xclk_sig is + + signal b_0_reg: std_logic := INIT; + signal b_1_reg: std_logic := INIT; + +begin + + process (b_clk_i, a_sig_i, b_0_reg) + begin + if rising_edge(b_clk_i) then + b_0_reg <= a_sig_i; + b_1_reg <= b_0_reg; + end if; + end process; + b_sig_o <= b_1_reg; + +end behavioral; diff --git a/libraries/utility/xclk_vec.vhd b/libraries/utility/xclk_vec.vhd new file mode 100644 index 0000000..cd50daa --- /dev/null +++ b/libraries/utility/xclk_vec.vhd @@ -0,0 +1,31 @@ +library ieee; +use ieee.std_logic_1164.all; + + +entity xclk_vec is + port ( + a_sig_i: in std_logic_vector; + + b_clk_i: in std_logic; + b_sig_o: out std_logic_vector + ); +end xclk_vec; + + +architecture behavioral of xclk_vec is + + signal b_0_reg: std_logic_vector(b_sig_o'high downto 0) := (others => '0'); + signal b_1_reg: std_logic_vector(b_sig_o'high downto 0) := (others => '0'); + +begin + + process (b_clk_i, a_sig_i, b_0_reg) + begin + if rising_edge(b_clk_i) then + b_0_reg <= a_sig_i; + b_1_reg <= b_0_reg; + end if; + end process; + b_sig_o <= b_1_reg; + +end behavioral; -- 2.43.0