]> git.the-white-hart.net Git - vhdl/commitdiff
Add SRL-based clock sync FIFO
authorrs <>
Thu, 8 Jan 2026 04:11:12 +0000 (22:11 -0600)
committerrs <>
Thu, 8 Jan 2026 04:11:12 +0000 (22:11 -0600)
libraries/utility/sync_fifo_16.vhd [new file with mode: 0644]

diff --git a/libraries/utility/sync_fifo_16.vhd b/libraries/utility/sync_fifo_16.vhd
new file mode 100644 (file)
index 0000000..877992f
--- /dev/null
@@ -0,0 +1,163 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library work;
+
+
+entity sync_fifo_16 is
+       generic (
+               SYNC_STAGES: positive := 2;
+               WIDTH:       positive := 16
+       );
+       port (
+               head_rst_i: in  std_logic;
+               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(WIDTH-1 downto 0);
+
+               tail_rst_i: in  std_logic;
+               tail_clk_i: in  std_logic;
+               tail_stb_o: out std_logic;
+               tail_rdy_i: in  std_logic;
+               tail_dat_o: out std_logic_vector(WIDTH-1 downto 0)
+       );
+end sync_fifo_16;
+
+
+architecture behavioral of sync_fifo_16 is
+
+       signal head_rst_wait: std_logic;
+       signal tail_adr_sync: std_logic_vector(3 downto 0);
+       signal head_adr_reg:  std_logic_vector(3 downto 0) := (others => '0');
+       signal head_adr_next: std_logic_vector(3 downto 0);
+       signal head_rdy:      std_logic;
+       signal head_step:     std_logic;
+       signal is_full:       std_logic;
+
+       signal tail_rst_wait: std_logic;
+       signal head_adr_sync: std_logic_vector(3 downto 0);
+       signal tail_adr_reg:  std_logic_vector(3 downto 0) := (others => '0');
+       signal tail_adr_inc:  std_logic_vector(3 downto 0);
+       signal tail_adr_next: std_logic_vector(3 downto 0);
+       signal tail_stb:      std_logic;
+       signal tail_step:     std_logic;
+       signal tail_dat:      std_logic_vector(WIDTH-1 downto 0);
+       signal tail_dat_reg:  std_logic_vector(WIDTH-1 downto 0);
+       signal is_empty:      std_logic;
+
+begin
+
+       -- Head logic
+
+       e_sync_tail_rst: entity work.sync_sig
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => head_clk_i,
+                       sig_i => tail_rst_i,
+                       sig_o => head_rst_wait
+               );
+
+       e_sync_tail: entity work.sync_vec
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => head_clk_i,
+                       sig_i => std_logic_vector(tail_adr_reg),
+                       sig_o => tail_adr_sync
+               );
+
+       is_full <= '1' when std_logic_vector(head_adr_next) = tail_adr_sync or
+                           head_rst_i = '1' or head_rst_wait = '1'
+                      else '0';
+
+       head_rdy <= not is_full;
+       head_rdy_o <= head_rdy;
+
+       head_step <= head_stb_i and head_rdy;
+
+       e_head_adr: entity work.gray_counter
+               generic map (N => 4)
+               port map (
+                       rst_i => head_rst_i,
+                       clk_i => head_clk_i,
+                       ena_i => head_step,
+                       gray  => head_adr_reg,
+                       inc   => head_adr_next
+               );
+
+
+       -- Tail logic
+
+       e_sync_head_rst: entity work.sync_sig
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => tail_clk_i,
+                       sig_i => head_rst_i,
+                       sig_o => tail_rst_wait
+               );
+
+       e_sync_head: entity work.sync_vec
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => tail_clk_i,
+                       sig_i => std_logic_vector(head_adr_reg),
+                       sig_o => head_adr_sync
+               );
+
+       is_empty <= '1' when std_logic_vector(tail_adr_reg) = head_adr_sync or
+                            tail_rst_i = '1' or tail_rst_wait = '1'
+                       else '0';
+
+       tail_stb <= not is_empty;
+       tail_stb_o <= tail_stb;
+
+       tail_step <= tail_stb and tail_rdy_i;
+       tail_adr_next <= tail_adr_inc when tail_step = '1' else tail_adr_reg;
+
+       e_tail_adr: entity work.gray_counter
+               generic map (N => 4)
+               port map (
+                       rst_i => tail_rst_i,
+                       clk_i => tail_clk_i,
+                       ena_i => tail_step,
+                       gray  => tail_adr_reg,
+                       inc   => tail_adr_inc
+               );
+
+
+       -- FIFO memory
+
+       g_ram: for i in WIDTH-1 downto 0 generate
+               e_ram: ram16x1d
+                       port map (
+                               WE    => head_step,
+                               D     => head_dat_i(i),
+                               WCLK  => head_clk_i,
+                               A0    => head_adr_reg(0),
+                               A1    => head_adr_reg(1),
+                               A2    => head_adr_reg(2),
+                               A3    => head_adr_reg(3),
+                               SPO   => open,
+
+                               DPRA0 => tail_adr_next(0),
+                               DPRA1 => tail_adr_next(1),
+                               DPRA2 => tail_adr_next(2),
+                               DPRA3 => tail_adr_next(3),
+                               DPO   => tail_dat(i)
+                       );
+       end generate;
+
+       process (tail_clk_i, tail_dat)
+       begin
+               if rising_edge(tail_clk_i) then
+                       tail_dat_reg <= tail_dat;
+               end if;
+       end process;
+
+       tail_dat_o <= tail_dat_reg;
+
+end behavioral;