library ieee;
use ieee.std_logic_1164.all;
-- this fifo is meant to be used
-- as a
entity dfifo is
generic (
SIZE_2LOG : natural;
WIDTH : natural := 32);
port (
rst_in : in std_logic;
wr_clk_i : in std_logic;
wr_en_i : in std_logic;
wr_data_i : in std_logic_vector(WIDTH - 1 downto 0);
rd_clk_i : in std_logic;
rd_en_i : in std_logic;
rd_data_o : out std_logic_vector(WIDTH - 1 downto 0);
empty_o : out std_logic; -- valid on rd_clk?
full_o : out std_logic); -- valid on wr_clk?
end entity dfifo;
architecture a1 of dfifo is
constant SIZE : natural := 2**SIZE_2LOG;
signal wr_pos : std_logic_vector(SIZE_2LOG - 1 downto 0);
-- signal wr_pos_gray : std_logic_vector(SIZE_2LOG - 1 downto 0);
signal wr_next_pos_gray : std_logic_vector(SIZE_2LOG - 1 downto 0);
-- register of wr_pos and wr_next_pos sampled at rd_clock
-- signal wr_pos_gray_rsync : std_logic_vector(SIZE_2LOG - 1 downto 0);
signal wr_next_pos_gray_rsync : std_logic_vector(SIZE_2LOG - 1 downto 0);
signal rd_pos : std_logic_vector(SIZE_2LOG - 1 downto 0);
signal rd_pos_gray : std_logic_vector(SIZE_2LOG - 1 downto 0);
-- register of rd_pos_gray sampled at wr_clock
signal rd_pos_gray_wsync : std_logic_vector(SIZE_2LOG - 1 downto 0);
signal wr_en : std_logic;
signal rd_en : std_logic;
signal empty : std_logic;
signal full : std_logic;
begin -- architecture a1
write_counter_gray : entity work.bin2gray
generic map (
WIDTH => SIZE_2LOG)
port map (
bin_i => std_logic_vector(unsigned(wr_pos) + 1),
gray_o => wr_next_pos_gray);
write_counter : entity work.counter
generic map (
WIDTH => SIZE_2LOG,
MAX => SIZE)
port map (
clk_i => wr_clk_i,
rst_in => rst_in,
increment_i => wr_en,
count_o => wr_pos);
read_counter_gray : entity work.bin2gray
generic map (
WIDTH => SIZE_2LOG)
port map (
bin_i => rd_pos,
gray_o => rd_pos_gray);
read_counter : entity work.counter
generic map (
WIDTH => SIZE_2LOG,
MAX => SIZE)
port map (
clk_i => rd_clk_i,
rst_in => rst_in,
increment_i => rd_en,
count_o => rd_pos);
ram : entity work.dual_port_ram
generic map (
SIZE => SIZE,
SIZE_2LOG => SIZE_2LOG,
WIDTH => WIDTH)
port map (
wr_clk_i => wr_clk_i,
wr_addr_i => wr_pos,
wr_en_i => wr_en,
wr_data_i => wr_data_i,
rd_clk_i => rd_clk_i,
rd_addr_i => rd_pos,
rd_data => rd_data_o);
-- resynchronizer_wr_pos_gray_rsync: entity work.resynchronizer
-- port map (
-- orig_clk_i => wr_clk_i,
-- target_clk_i => rd_clk_i,
-- sig_i => wr_pos_gray,
-- sig_o => wr_pos_gray_rsync);
resynchronizer_wr_pos_next_gray_rsync: entity work.resynchronizer
port map (
orig_clk_i => wr_clk_i,
target_clk_i => rd_clk_i,
sig_i => wr_next_pos_gray,
sig_o => wr_next_pos_gray_rsync);
resynchronizer_rd_pos_gray_wsync: entity work.resynchronizer
port map (
orig_clk_i => wr_clk_i,
target_clk_i => rd_clk_i,
sig_i => rd_pos_gray,
sig_o => rd_pos_gray_wsync);
-- NOTE: this is meant to be used in write domain
full <= '1' when rd_pos_gray_wsync = wr_next_pos_gray else '0';
-- NOTE: this is meant to be used in read domain
empty <= '1' when rd_pos_gray = wr_pos_gray_rsync else '0';
rd_en <= rd_en_i and not empty;
wr_en <= wr_en_i and not full;
empty_o <= empty;
full_o <= empty;
end architecture a1;