------------------------------------------------------------------------- -- Project: FIFO, generic FIFOs written in VHDL -- Release 1 -- -- Copyright (C) 2007 J. Ahrensfeld -- -- This library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- This library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with this library; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- -- For questions and ideas, please contact the author at jens@jayfield.org -- ----------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.ALL; LIBRARY WORK; USE WORK.FIFO_CTRL_PKG.ALL; entity fifo_async_ctrl is Generic ( addr_width : integer := 3; almost_full_thresh : integer := 6; almost_empty_thresh : integer := 2 ); Port ( rst : in STD_LOGIC; clk_w : in STD_LOGIC; clk_r : in STD_LOGIC; winc : in STD_LOGIC; rinc : in STD_LOGIC; ptr_w : out unsigned (addr_width-1 downto 0); ptr_r : out unsigned (addr_width-1 downto 0); fifo_pre_full : out STD_LOGIC; fifo_pre_empty : out STD_LOGIC; fifo_full : out STD_LOGIC; fifo_empty : out STD_LOGIC; fifo_afull : out STD_LOGIC; fifo_aempty : out STD_LOGIC ); end fifo_async_ctrl; architecture Behavioral of fifo_async_ctrl is signal gcnt_w : unsigned (addr_width downto 0); signal gcnt2_w : unsigned (addr_width downto 0); signal bcnt2_aw : unsigned (addr_width downto 0); signal bcnt_w : unsigned (addr_width downto 0); signal gnxt_w : unsigned (addr_width downto 0); signal bnxt_w : unsigned (addr_width downto 0); signal gcnt_r : unsigned (addr_width downto 0); signal gcnt2_r : unsigned (addr_width downto 0); signal bcnt2_ar : unsigned (addr_width downto 0); signal bcnt_r : unsigned (addr_width downto 0); signal gnxt_r : unsigned (addr_width downto 0); signal bnxt_r : unsigned (addr_width downto 0); signal pre_empty, pre_full : std_logic; signal full, empty : std_logic; -- synthesis translate_off signal diffw : signed (addr_width downto 0); signal diffr : signed (addr_width downto 0); -- synthesis translate_on begin ptr_w <= bcnt_w(addr_width-1 downto 0); ptr_r <= bnxt_r(addr_width-1 downto 0); fifo_full <= full; fifo_empty <= empty; fifo_pre_full <= pre_full; fifo_pre_empty <= pre_empty; proc_write_inhibit: process(rst, clk_w) begin if rst = '1' then full <= '0'; elsif rising_edge(clk_w) then full <= pre_full; end if; end process; proc_read_inhibit: process(rst, clk_r) begin if rst = '1' then empty <= '1'; elsif rising_edge(clk_r) then empty <= pre_empty; end if; end process; proc_sync_grptr: process(clk_w) variable p1, p2 : unsigned (addr_width downto 0); begin if rising_edge(clk_w) then gcnt2_r <= p2; p2 := p1; p1 := gcnt_r; end if; end process; proc_ptr_gwptr: process(clk_r) variable p1, p2 : unsigned (addr_width downto 0); begin if rising_edge(clk_r) then gcnt2_w <= p2; p2 := p1; p1 := gcnt_w; end if; end process; proc_status_full: process(gnxt_w, gcnt2_r) begin if (gnxt_w = (not gcnt2_r(gcnt2_r'left downto gcnt2_r'left-1) & gcnt2_r(gcnt2_r'left-2 downto 0))) then pre_full <= '1'; else pre_full <= '0'; end if; end process; proc_status_empty: process(gnxt_r, gcnt2_w) begin if (gnxt_r = gcnt2_w) then pre_empty <= '1'; else pre_empty <= '0'; end if; end process; proc_sync_arptr: process(clk_w) variable p1, p2 : unsigned (addr_width downto 0); begin if rising_edge(clk_w) then bcnt2_ar <= p2; p2 := p1; p1 := bcnt_r; end if; end process; proc_ptr_awptr: process(clk_r) variable p1, p2 : unsigned (addr_width downto 0); begin if rising_edge(clk_r) then bcnt2_aw <= p2; p2 := p1; p1 := bcnt_w; end if; end process; proc_status_almost_full: process(rst, clk_w) variable diff : unsigned (addr_width downto 0); begin -- synthesis translate_off diffw <= signed(diff); -- synthesis translate_on if rst = '1' then fifo_afull <= '0'; diff := (others => '0'); elsif rising_edge(clk_w) then if diff >= almost_full_thresh-1 then fifo_afull <= '1'; else fifo_afull <= '0'; end if; diff := unsigned(abs(signed(bnxt_w) - signed(bcnt2_ar))); end if; end process; proc_status_almost_empty: process(rst, clk_r) variable diff : unsigned (addr_width downto 0); begin -- synthesis translate_off diffr <= signed(diff); -- synthesis translate_on if rst = '1' then fifo_aempty <= '1'; diff := (others => '0'); elsif rising_edge(clk_r) then if diff <= almost_empty_thresh+1 then fifo_aempty <= '1'; else fifo_aempty <= '0'; end if; diff := unsigned(abs(signed(bcnt2_aw) - signed(bnxt_r))); end if; end process; inst_gray_counter_w : entity work.gray_counter generic map ( width => addr_width+1, init_value => 0 ) port map ( rst => rst, clk => clk_w, ce => winc, bcnt => bcnt_w, bnxt => bnxt_w, gcnt => gcnt_w, gnxt => gnxt_w ); inst_gray_counter_r : entity work.gray_counter generic map ( width => addr_width+1, init_value => 0 ) port map ( rst => rst, clk => clk_r, ce => rinc, bcnt => bcnt_r, bnxt => bnxt_r, gcnt => gcnt_r, gnxt => gnxt_r ); end Behavioral;