From 6d33dca2f9f673376f967d60351575bbd8a912f5 Mon Sep 17 00:00:00 2001 From: Dimitris Lampridis <dimitris.lampridis@cern.ch> Date: Fri, 3 Aug 2018 10:12:43 +0200 Subject: [PATCH] hdl: introduce generic dual rst async fifo --- modules/genrams/common/Manifest.py | 9 +- .../common/inferred_async_fifo_dual_rst.vhd | 310 ++++++++++++++++++ modules/genrams/generic/Manifest.py | 7 +- .../generic/generic_async_fifo_dual_rst.vhd | 120 +++++++ modules/genrams/genram_pkg.vhd | 38 +++ .../wb_clock_crossing/xwb_clock_crossing.vhd | 62 ++-- 6 files changed, 522 insertions(+), 24 deletions(-) create mode 100644 modules/genrams/common/inferred_async_fifo_dual_rst.vhd create mode 100644 modules/genrams/generic/generic_async_fifo_dual_rst.vhd diff --git a/modules/genrams/common/Manifest.py b/modules/genrams/common/Manifest.py index cbc586b..a479e14 100644 --- a/modules/genrams/common/Manifest.py +++ b/modules/genrams/common/Manifest.py @@ -1,3 +1,6 @@ -files = ["inferred_sync_fifo.vhd", - "inferred_async_fifo.vhd", - "generic_shiftreg_fifo.vhd"] +files = [ + "inferred_sync_fifo.vhd", + "inferred_async_fifo_dual_rst.vhd", + "inferred_async_fifo.vhd", + "generic_shiftreg_fifo.vhd", +] diff --git a/modules/genrams/common/inferred_async_fifo_dual_rst.vhd b/modules/genrams/common/inferred_async_fifo_dual_rst.vhd new file mode 100644 index 0000000..ff8bddc --- /dev/null +++ b/modules/genrams/common/inferred_async_fifo_dual_rst.vhd @@ -0,0 +1,310 @@ +-------------------------------------------------------------------------------- +-- CERN BE-CO-HT +-- General Cores Library +-- https://www.ohwr.org/projects/general-cores +-------------------------------------------------------------------------------- +-- +-- unit name: inferred_async_fifo_dual_rst +-- +-- description: Parametrizable asynchronous FIFO (Generic version). +-- Dual-clock asynchronous FIFO. +-- - configurable data width and size +-- - configurable full/empty/almost full/almost empty/word count signals +-- - dual sunchronous reset +-- +-------------------------------------------------------------------------------- +-- Copyright CERN 2011-2018 +-------------------------------------------------------------------------------- +-- Copyright and related rights are licensed under the Solderpad Hardware +-- License, Version 2.0 (the "License"); you may not use this file except +-- in compliance with the License. You may obtain a copy of the License at +-- http://solderpad.org/licenses/SHL-2.0. +-- Unless required by applicable law or agreed to in writing, software, +-- hardware and materials distributed under this License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +-- or implied. See the License for the specific language governing permissions +-- and limitations under the License. +-------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.genram_pkg.all; +use work.gencores_pkg.all; + +entity inferred_async_fifo_dual_rst is + + generic ( + g_data_width : natural; + g_size : natural; + g_show_ahead : boolean := FALSE; + g_with_rd_empty : boolean := TRUE; + g_with_rd_full : boolean := FALSE; + g_with_rd_almost_empty : boolean := FALSE; + g_with_rd_almost_full : boolean := FALSE; + g_with_rd_count : boolean := FALSE; + g_with_wr_empty : boolean := FALSE; + g_with_wr_full : boolean := TRUE; + g_with_wr_almost_empty : boolean := FALSE; + g_with_wr_almost_full : boolean := FALSE; + g_with_wr_count : boolean := FALSE; + g_almost_empty_threshold : integer; + g_almost_full_threshold : integer); + port ( + -- write port + rst_wr_n_i : in std_logic := '1'; + clk_wr_i : in std_logic; + d_i : in std_logic_vector(g_data_width-1 downto 0); + we_i : in std_logic; + wr_empty_o : out std_logic; + wr_full_o : out std_logic; + wr_almost_empty_o : out std_logic; + wr_almost_full_o : out std_logic; + wr_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0); + -- read port + rst_rd_n_i : in std_logic := '1'; + clk_rd_i : in std_logic; + q_o : out std_logic_vector(g_data_width-1 downto 0); + rd_i : in std_logic; + rd_empty_o : out std_logic; + rd_full_o : out std_logic; + rd_almost_empty_o : out std_logic; + rd_almost_full_o : out std_logic; + rd_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0) + ); + +end inferred_async_fifo_dual_rst; + + +architecture syn of inferred_async_fifo_dual_rst is + + constant c_counter_bits : integer := f_log2_size(g_size) + 1; + subtype t_counter is std_logic_vector(c_counter_bits-1 downto 0); + + type t_counter_block is record + bin, bin_next, gray, gray_next : t_counter; + bin_x, gray_x, gray_xm : t_counter; + end record; + + type t_mem_type is array (0 to g_size-1) of std_logic_vector(g_data_width-1 downto 0); + signal mem : t_mem_type; + + signal rcb, wcb : t_counter_block; + + + signal full_int, empty_int : std_logic; + signal almost_full_int, almost_empty_int : std_logic; + signal going_full : std_logic; + + signal wr_count, rd_count : t_counter; + signal rd_int, we_int : std_logic; + + signal wr_empty_xm, wr_empty_x : std_logic; + signal rd_full_xm, rd_full_x : std_logic; + + signal almost_full_x, almost_full_xm : std_logic; + signal almost_empty_x, almost_empty_xm : std_logic; + + signal q_int : std_logic_vector(g_data_width-1 downto 0) := (others => '0'); + +begin -- syn + + rd_int <= rd_i and not empty_int; + we_int <= we_i and not full_int; + + p_mem_write : process(clk_wr_i) + begin + if rising_edge(clk_wr_i) then + if we_int = '1' then + mem(to_integer(unsigned(wcb.bin(wcb.bin'LEFT-1 downto 0)))) <= d_i; + end if; + end if; + end process p_mem_write; + + p_mem_read : process(clk_rd_i) + begin + if rising_edge(clk_rd_i) then + if rd_int = '1' then + q_int <= mem(to_integer(unsigned(rcb.bin(rcb.bin'LEFT-1 downto 0)))); + end if; + end if; + end process p_mem_read; + + q_o <= q_int; + + wcb.bin_next <= std_logic_vector(unsigned(wcb.bin) + 1); + wcb.gray_next <= f_gray_encode(wcb.bin_next); + + p_write_ptr : process(clk_wr_i) + begin + if rising_edge(clk_wr_i) then + if rst_wr_n_i = '0' then + wcb.bin <= (others => '0'); + wcb.gray <= (others => '0'); + elsif we_int = '1' then + wcb.bin <= wcb.bin_next; + wcb.gray <= wcb.gray_next; + end if; + end if; + end process p_write_ptr; + + rcb.bin_next <= std_logic_vector(unsigned(rcb.bin) + 1); + rcb.gray_next <= f_gray_encode(rcb.bin_next); + + p_read_ptr : process(clk_rd_i) + begin + if rising_edge(clk_rd_i) then + if rst_rd_n_i = '0' then + rcb.bin <= (others => '0'); + rcb.gray <= (others => '0'); + elsif rd_int = '1' then + rcb.bin <= rcb.bin_next; + rcb.gray <= rcb.gray_next; + end if; + end if; + end process p_read_ptr; + + U_Sync1 : gc_sync_register + generic map ( + g_width => c_counter_bits) + port map ( + clk_i => clk_wr_i, + rst_n_a_i => '1', + d_i => rcb.gray, + q_o => rcb.gray_x); + + U_Sync2 : gc_sync_register + generic map ( + g_width => c_counter_bits) + port map ( + clk_i => clk_rd_i, + rst_n_a_i => '1', + d_i => wcb.gray, + q_o => wcb.gray_x); + + wcb.bin_x <= f_gray_decode(wcb.gray_x, 1); + rcb.bin_x <= f_gray_decode(rcb.gray_x, 1); + + p_gen_empty : process(clk_rd_i) + begin + if rising_edge (clk_rd_i) then + if rst_rd_n_i = '0' then + empty_int <= '1'; + elsif rcb.gray = wcb.gray_x or (rd_int = '1' and (wcb.gray_x = rcb.gray_next)) then + empty_int <= '1'; + else + empty_int <= '0'; + end if; + end if; + end process p_gen_empty; + + U_Sync_Empty : gc_sync_ffs + generic map ( + g_sync_edge => "positive") + port map ( + clk_i => clk_wr_i, + rst_n_i => '1', + data_i => empty_int, + synced_o => wr_empty_x); + + U_Sync_Full : gc_sync_ffs + generic map ( + g_sync_edge => "positive") + port map ( + clk_i => clk_rd_i, + rst_n_i => '1', + data_i => full_int, + synced_o => rd_full_x); + + rd_empty_o <= empty_int; + wr_empty_o <= wr_empty_x; + + p_gen_going_full : process(rcb, wcb, we_int) + begin + if ((wcb.bin (wcb.bin'LEFT-1 downto 0) = rcb.bin_x(rcb.bin_x'LEFT-1 downto 0)) + and (wcb.bin(wcb.bin'LEFT) /= rcb.bin_x(wcb.bin_x'LEFT))) then + going_full <= '1'; + elsif (we_int = '1' + and (wcb.bin_next(wcb.bin'LEFT-1 downto 0) = rcb.bin_x(rcb.bin_x'LEFT-1 downto 0)) + and (wcb.bin_next(wcb.bin'LEFT) /= rcb.bin_x(rcb.bin_x'LEFT))) then + going_full <= '1'; + else + going_full <= '0'; + end if; + end process p_gen_going_full; + + p_register_full : process(clk_wr_i) + begin + if rising_edge (clk_wr_i) then + if rst_wr_n_i = '0' then + full_int <= '0'; + else + full_int <= going_full; + end if; + end if; + end process p_register_full; + + wr_full_o <= full_int; + rd_full_o <= rd_full_x; + + p_reg_almost_full : process(clk_wr_i) + begin + if rising_edge(clk_wr_i) then + if rst_wr_n_i = '0' then + almost_full_int <= '0'; + else + wr_count <= std_logic_vector(unsigned(wcb.bin) - unsigned(rcb.bin_x)); + if (unsigned(wr_count) < g_almost_full_threshold) then + almost_full_int <= '0'; + else + almost_full_int <= '1'; + end if; + end if; + end if; + end process p_reg_almost_full; + + U_Sync_AlmostFull : gc_sync_ffs + generic map ( + g_sync_edge => "positive") + port map ( + clk_i => clk_rd_i, + rst_n_i => '1', + data_i => almost_full_int, + synced_o => almost_full_x); + + wr_almost_full_o <= almost_full_int; + rd_almost_full_o <= almost_full_x; + + p_reg_almost_empty : process(clk_rd_i) + begin + if rising_edge(clk_rd_i) then + if rst_rd_n_i = '0' then + almost_empty_int <= '1'; + else + rd_count <= std_logic_vector(unsigned(wcb.bin_x) - unsigned(rcb.bin)); + if (unsigned(rd_count) > g_almost_empty_threshold) then + almost_empty_int <= '0'; + else + almost_empty_int <= '1'; + end if; + end if; + end if; + end process p_reg_almost_empty; + + U_Sync_AlmostEmpty : gc_sync_ffs + generic map ( + g_sync_edge => "positive") + port map ( + clk_i => clk_wr_i, + rst_n_i => '1', + data_i => almost_empty_int, + synced_o => almost_empty_x); + + rd_almost_empty_o <= almost_empty_int; + wr_almost_empty_o <= almost_empty_x; + + wr_count_o <= std_logic_vector(wr_count(f_log2_size(g_size)-1 downto 0)); + rd_count_o <= std_logic_vector(rd_count(f_log2_size(g_size)-1 downto 0)); + +end syn; diff --git a/modules/genrams/generic/Manifest.py b/modules/genrams/generic/Manifest.py index 112edc0..e49cf4d 100644 --- a/modules/genrams/generic/Manifest.py +++ b/modules/genrams/generic/Manifest.py @@ -1,2 +1,5 @@ -files = ["generic_async_fifo.vhd", - "generic_sync_fifo.vhd"] +files = [ + "generic_async_fifo_dual_rst.vhd", + "generic_async_fifo.vhd", + "generic_sync_fifo.vhd", +] diff --git a/modules/genrams/generic/generic_async_fifo_dual_rst.vhd b/modules/genrams/generic/generic_async_fifo_dual_rst.vhd new file mode 100644 index 0000000..5984e8e --- /dev/null +++ b/modules/genrams/generic/generic_async_fifo_dual_rst.vhd @@ -0,0 +1,120 @@ + +-------------------------------------------------------------------------------- +-- CERN BE-CO-HT +-- General Cores Library +-- https://www.ohwr.org/projects/general-cores +-------------------------------------------------------------------------------- +-- +-- unit name: generic_async_fifo_dual_rst +-- +-- description: Parametrizable asynchronous FIFO (Generic version). +-- Dual-clock asynchronous FIFO. +-- - configurable data width and size +-- - configurable full/empty/almost full/almost empty/word count signals +-- - dual sunchronous reset +-- +-------------------------------------------------------------------------------- +-- Copyright CERN 2011-2018 +-------------------------------------------------------------------------------- +-- Copyright and related rights are licensed under the Solderpad Hardware +-- License, Version 2.0 (the "License"); you may not use this file except +-- in compliance with the License. You may obtain a copy of the License at +-- http://solderpad.org/licenses/SHL-2.0. +-- Unless required by applicable law or agreed to in writing, software, +-- hardware and materials distributed under this License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +-- or implied. See the License for the specific language governing permissions +-- and limitations under the License. +-------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.genram_pkg.all; + +entity generic_async_fifo_dual_rst is + + generic ( + g_data_width : natural; + g_size : natural; + g_show_ahead : boolean := FALSE; + g_with_rd_empty : boolean := TRUE; + g_with_rd_full : boolean := FALSE; + g_with_rd_almost_empty : boolean := FALSE; + g_with_rd_almost_full : boolean := FALSE; + g_with_rd_count : boolean := FALSE; + g_with_wr_empty : boolean := FALSE; + g_with_wr_full : boolean := TRUE; + g_with_wr_almost_empty : boolean := FALSE; + g_with_wr_almost_full : boolean := FALSE; + g_with_wr_count : boolean := FALSE; + g_almost_empty_threshold : integer := 0; + g_almost_full_threshold : integer := 0); + port ( + -- write port + rst_wr_n_i : in std_logic := '1'; + clk_wr_i : in std_logic; + d_i : in std_logic_vector(g_data_width-1 downto 0); + we_i : in std_logic; + wr_empty_o : out std_logic; + wr_full_o : out std_logic; + wr_almost_empty_o : out std_logic; + wr_almost_full_o : out std_logic; + wr_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0); + -- read port + rst_rd_n_i : in std_logic := '1'; + clk_rd_i : in std_logic; + q_o : out std_logic_vector(g_data_width-1 downto 0); + rd_i : in std_logic; + rd_empty_o : out std_logic; + rd_full_o : out std_logic; + rd_almost_empty_o : out std_logic; + rd_almost_full_o : out std_logic; + rd_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0)); + +end generic_async_fifo_dual_rst; + + +architecture arch of generic_async_fifo_dual_rst is + +begin -- arch + + U_Inferred_FIFO : entity work.inferred_async_fifo_dual_rst + generic map ( + g_data_width => g_data_width, + g_size => g_size, + g_show_ahead => g_show_ahead, + g_with_rd_empty => g_with_rd_empty, + g_with_rd_full => g_with_rd_full, + g_with_rd_almost_empty => g_with_rd_almost_empty, + g_with_rd_almost_full => g_with_rd_almost_full, + g_with_rd_count => g_with_rd_count, + g_with_wr_empty => g_with_wr_empty, + g_with_wr_full => g_with_wr_full, + g_with_wr_almost_empty => g_with_wr_almost_empty, + g_with_wr_almost_full => g_with_wr_almost_full, + g_with_wr_count => g_with_wr_count, + g_almost_empty_threshold => g_almost_empty_threshold, + g_almost_full_threshold => g_almost_full_threshold) + port map ( + rst_wr_n_i => rst_wr_n_i, + clk_wr_i => clk_wr_i, + d_i => d_i, + we_i => we_i, + wr_empty_o => wr_empty_o, + wr_full_o => wr_full_o, + wr_almost_empty_o => wr_almost_empty_o, + wr_almost_full_o => wr_almost_full_o, + wr_count_o => wr_count_o, + rst_rd_n_i => rst_rd_n_i, + clk_rd_i => clk_rd_i, + q_o => q_o, + rd_i => rd_i, + rd_empty_o => rd_empty_o, + rd_full_o => rd_full_o, + rd_almost_empty_o => rd_almost_empty_o, + rd_almost_full_o => rd_almost_full_o, + rd_count_o => rd_count_o); + +end arch; diff --git a/modules/genrams/genram_pkg.vhd b/modules/genrams/genram_pkg.vhd index 3c74975..1f978a3 100644 --- a/modules/genrams/genram_pkg.vhd +++ b/modules/genrams/genram_pkg.vhd @@ -124,6 +124,44 @@ package genram_pkg is qb_o : out std_logic_vector(g_data_b_width-1 downto 0)); end component; + component generic_async_fifo_dual_rst is + generic ( + g_data_width : natural; + g_size : natural; + g_show_ahead : boolean := false; + g_with_rd_empty : boolean := true; + g_with_rd_full : boolean := false; + g_with_rd_almost_empty : boolean := false; + g_with_rd_almost_full : boolean := false; + g_with_rd_count : boolean := false; + g_with_wr_empty : boolean := false; + g_with_wr_full : boolean := true; + g_with_wr_almost_empty : boolean := false; + g_with_wr_almost_full : boolean := false; + g_with_wr_count : boolean := false; + g_almost_empty_threshold : integer := 0; + g_almost_full_threshold : integer := 0); + port ( + rst_wr_n_i : in std_logic := '1'; + clk_wr_i : in std_logic; + d_i : in std_logic_vector(g_data_width-1 downto 0); + we_i : in std_logic; + wr_empty_o : out std_logic; + wr_full_o : out std_logic; + wr_almost_empty_o : out std_logic; + wr_almost_full_o : out std_logic; + wr_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0); + rst_rd_n_i : in std_logic := '1'; + clk_rd_i : in std_logic; + q_o : out std_logic_vector(g_data_width-1 downto 0); + rd_i : in std_logic; + rd_empty_o : out std_logic; + rd_full_o : out std_logic; + rd_almost_empty_o : out std_logic; + rd_almost_full_o : out std_logic; + rd_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0)); + end component generic_async_fifo_dual_rst; + component generic_async_fifo generic ( g_data_width : natural; diff --git a/modules/wishbone/wb_clock_crossing/xwb_clock_crossing.vhd b/modules/wishbone/wb_clock_crossing/xwb_clock_crossing.vhd index 67ea4a0..5ea06f8 100644 --- a/modules/wishbone/wb_clock_crossing/xwb_clock_crossing.vhd +++ b/modules/wishbone/wb_clock_crossing/xwb_clock_crossing.vhd @@ -1,7 +1,25 @@ -------------------------------------------------------------------------------- --- Modifications: --- 2016-08-24: by Jan Pospisil (j.pospisil@cern.ch) --- * added assignments to (new) unspecified WB signals +-- CERN BE-CO-HT +-- General Cores Library +-- https://www.ohwr.org/projects/general-cores +-------------------------------------------------------------------------------- +-- +-- unit name: xwb_clock_crossing +-- +-- description: Cross clock-domain wishbone adapter +-- +-------------------------------------------------------------------------------- +-- Copyright CERN 2012-2018 +-------------------------------------------------------------------------------- +-- Copyright and related rights are licensed under the Solderpad Hardware +-- License, Version 2.0 (the "License"); you may not use this file except +-- in compliance with the License. You may obtain a copy of the License at +-- http://solderpad.org/licenses/SHL-2.0. +-- Unless required by applicable law or agreed to in writing, software, +-- hardware and materials distributed under this License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +-- or implied. See the License for the specific language governing permissions +-- and limitations under the License. -------------------------------------------------------------------------------- library ieee; @@ -97,12 +115,12 @@ begin end if; end process; - mfifo : generic_async_fifo + mfifo : generic_async_fifo_dual_rst generic map( g_data_width => mlen, g_size => g_size) port map( - rst_n_i => slave_rst_n_i, + rst_wr_n_i => slave_rst_n_i, clk_wr_i => slave_clk_i, d_i => msend_vect, we_i => mw_en, @@ -111,6 +129,7 @@ begin wr_almost_empty_o => open, wr_almost_full_o => open, wr_count_o => open, + rst_rd_n_i => master_rst_n_i, clk_rd_i => master_clk_i, q_o => mrecv_vect, rd_i => mr_en, @@ -132,12 +151,12 @@ begin mrecv.DAT <= mrecv_vect(mDAT_end downto mDAT_start); mrecv.SEL <= mrecv_vect(mSEL_end downto mSEL_start); - sfifo : generic_async_fifo + sfifo : generic_async_fifo_dual_rst generic map( g_data_width => slen, g_size => g_size) port map( - rst_n_i => master_rst_n_i, + rst_wr_n_i => master_rst_n_i, clk_wr_i => master_clk_i, d_i => ssend_vect, we_i => sw_en, @@ -146,6 +165,7 @@ begin wr_almost_empty_o => open, wr_almost_full_o => open, wr_count_o => open, + rst_rd_n_i => slave_rst_n_i, clk_rd_i => slave_clk_i, q_o => srecv_vect, rd_i => sr_en, @@ -184,14 +204,16 @@ begin master_o.SEL <= mrecv.SEL; master_o.DAT <= mrecv.DAT; - drive_master_port : process(master_clk_i, master_rst_n_i) + drive_master_port : process(master_clk_i) begin + if rising_edge(master_clk_i) then if master_rst_n_i = '0' then - master_o_STB <= '0'; - elsif rising_edge(master_clk_i) then - master_o_STB <= mr_en or (mrecv.CYC and master_o_STB and master_i.STALL); + master_o_STB <= '0'; + else + master_o_STB <= mr_en or (mrecv.CYC and master_o_STB and master_i.STALL); end if; - end process; + end if; + end process drive_master_port; -- Master clock domain: master -> sFIFO sw_en <= master_i.ACK or master_i.ERR or master_i.RTY; @@ -208,15 +230,17 @@ begin slave_o.RTY <= srecv.RTY and slave_o_PUSH; slave_o.ERR <= srecv.ERR and slave_o_PUSH; - drive_slave_port : process(slave_clk_i, slave_rst_n_i) + drive_slave_port : process(slave_clk_i) begin - if slave_rst_n_i = '0' then + if rising_edge(slave_clk_i) then + if slave_rst_n_i = '0' then slave_o_PUSH <= '0'; - slave_CYC <= '0'; - elsif rising_edge(slave_clk_i) then + slave_CYC <= '0'; + else slave_o_PUSH <= sr_en; - slave_CYC <= slave_i.CYC; - end if; - end process; + slave_CYC <= slave_i.CYC; + end if; + end if; + end process drive_slave_port; end rtl; -- GitLab