From c2e071853d498452d98e65cc401ef8e24259595d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" <w.terpstra@gsi.de> Date: Thu, 25 Apr 2013 12:02:54 +0200 Subject: [PATCH] remove gc_wfifo in favour of generic_async_fifo --- modules/common/Manifest.py | 3 +- modules/common/gc_wfifo.vhd | 182 ------------------ modules/common/gencores_pkg.vhd | 31 --- .../wb_clock_crossing/xwb_clock_crossing.vhd | 132 +++++++++---- modules/wishbone/wishbone_pkg.vhd | 3 +- 5 files changed, 101 insertions(+), 250 deletions(-) delete mode 100644 modules/common/gc_wfifo.vhd diff --git a/modules/common/Manifest.py b/modules/common/Manifest.py index 2e185e10..b1f63397 100644 --- a/modules/common/Manifest.py +++ b/modules/common/Manifest.py @@ -9,5 +9,4 @@ files = [ "gencores_pkg.vhd", "gc_sync_ffs.vhd", "gc_arbitrated_mux.vhd", "gc_pulse_synchronizer.vhd", - "gc_frequency_meter.vhd", - "gc_wfifo.vhd"]; + "gc_frequency_meter.vhd"]; diff --git a/modules/common/gc_wfifo.vhd b/modules/common/gc_wfifo.vhd deleted file mode 100644 index 60b2673f..00000000 --- a/modules/common/gc_wfifo.vhd +++ /dev/null @@ -1,182 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library work; -use work.gencores_pkg.all; -use work.genram_pkg.all; - -entity gc_wfifo is - generic( - sync_depth : natural := 3; - gray_code : boolean := true; - addr_width : natural := 4; - data_width : natural := 32); - port( - -- write port, only set w_en when w_rdy - w_clk_i : in std_logic; - w_rst_n_i: in std_logic; - w_rdy_o : out std_logic; - w_en_i : in std_logic; - w_data_i : in std_logic_vector(data_width-1 downto 0); - -- (pre)alloc port, can be unused - a_clk_i : in std_logic; - a_rst_n_i: in std_logic; - a_rdy_o : out std_logic; - a_en_i : in std_logic; - -- read port, only set r_en when r_rdy - -- data is valid the cycle after r_en raised - r_clk_i : in std_logic; - r_rst_n_i: in std_logic; - r_rdy_o : out std_logic; - r_en_i : in std_logic; - r_data_o : out std_logic_vector(data_width-1 downto 0)); -end gc_wfifo; - -architecture rtl of gc_wfifo is - -- Quartus 11 sometimes goes crazy and infers an altshift_taps! Stop it. - attribute altera_attribute : string; - attribute altera_attribute of rtl : architecture is "-name AUTO_SHIFT_REGISTER_RECOGNITION OFF"; - - subtype counter is unsigned(addr_width downto 0); - type counter_shift is array(sync_depth downto 0) of counter; - - signal r_idx_bnry : counter; - signal r_idx_gray : counter; - signal w_idx_bnry : counter; - signal w_idx_gray : counter; - signal a_idx_bnry : counter; - signal a_idx_gray : counter; - - signal r_idx_shift_w : counter_shift; -- r_idx_gray in w_clk - signal r_idx_shift_a : counter_shift; -- r_idx_gray in a_clk - signal w_idx_shift_r : counter_shift; -- w_idx_gray in r_clk - - signal qb : std_logic_vector(data_width-1 downto 0); - - function bin2gray(a : unsigned) return unsigned is - variable o : unsigned(a'length downto 0); - begin - if gray_code then - o := (a & '0') xor ('0' & a); - else - o := (a & '0'); - end if; - return o(a'length downto 1); - end bin2gray; - - function index(a : counter) return std_logic_vector is - begin - return std_logic_vector(a(addr_width-1 downto 0)); - end index; - - function empty(a, b : counter) return std_logic is - begin - if a = b then - return '1'; - else - return '0'; - end if; - end empty; - - function full(a, b : counter) return std_logic is - variable mask : counter := (others => '0'); - begin - -- In binary a full FIFO has indexes (a XOR 1000...00) = b - -- bin2gray is a linear function, thus: - -- a XOR 1000..00 = b iff - -- bin2gray(a XOR 1000...00) = bin2gray(b) iff - -- bin2gray(a) XOR bin2gray(1000...00) = bin2gray(b) iif - -- bin2gray(a) XOR 1100..00 = bin2gray(b) - mask(addr_width) := '1'; - mask := bin2gray(mask); - if (a xor mask) = b then - return '1'; - else - return '0'; - end if; - end full; -begin - - ram : generic_simple_dpram - generic map( - g_data_width => data_width, - g_size => 2**addr_width, - g_addr_conflict_resolution => "dont_care", - g_dual_clock => gray_code) - port map( - clka_i => w_clk_i, - wea_i => w_en_i, - aa_i => index(w_idx_bnry), - da_i => w_data_i, - clkb_i => r_clk_i, - ab_i => index(r_idx_bnry), - qb_o => qb); - - read : process(r_clk_i) - variable idx : counter; - begin - if rising_edge(r_clk_i) then - if r_rst_n_i = '0' then - idx := (others => '0'); - r_data_o <= qb; - elsif r_en_i = '1' then - idx := r_idx_bnry + 1; - r_data_o <= qb; - else - idx := r_idx_bnry; - --r_data_o <= r_data_o; --implied - end if; - r_idx_bnry <= idx; - r_idx_gray <= bin2gray(idx); - if sync_depth > 0 then - w_idx_shift_r(sync_depth downto 1) <= w_idx_shift_r(sync_depth-1 downto 0); - end if; - end if; - end process; - w_idx_shift_r(0) <= w_idx_gray; - r_rdy_o <= not empty(r_idx_gray, w_idx_shift_r(sync_depth)); - - write : process(w_clk_i) - variable idx : counter; - begin - if rising_edge(w_clk_i) then - if w_rst_n_i = '0' then - idx := (others => '0'); - elsif w_en_i = '1' then - idx := w_idx_bnry + 1; - else - idx := w_idx_bnry; - end if; - w_idx_bnry <= idx; - w_idx_gray <= bin2gray(idx); - if sync_depth > 0 then - r_idx_shift_w(sync_depth downto 1) <= r_idx_shift_w(sync_depth-1 downto 0); - end if; - end if; - end process; - r_idx_shift_w(0) <= r_idx_gray; - w_rdy_o <= not full(w_idx_gray, r_idx_shift_w(sync_depth)); - - alloc : process(a_clk_i) - variable idx : counter; - begin - if rising_edge(a_clk_i) then - if a_rst_n_i = '0' then - idx := (others => '0'); - elsif a_en_i = '1' then - idx := a_idx_bnry + 1; - else - idx := a_idx_bnry; - end if; - a_idx_bnry <= idx; - a_idx_gray <= bin2gray(idx); - if sync_depth > 0 then - r_idx_shift_a(sync_depth downto 1) <= r_idx_shift_a(sync_depth-1 downto 0); - end if; - end if; - end process; - r_idx_shift_a(0) <= r_idx_gray; - a_rdy_o <= not full(a_idx_gray, r_idx_shift_a(sync_depth)); - -end rtl; diff --git a/modules/common/gencores_pkg.vhd b/modules/common/gencores_pkg.vhd index 91f65568..930a4392 100644 --- a/modules/common/gencores_pkg.vhd +++ b/modules/common/gencores_pkg.vhd @@ -189,37 +189,6 @@ package gencores_pkg is q_input_id_o : out std_logic_vector(f_log2_size(g_num_inputs)-1 downto 0)); end component; - -- A 'Wes' FIFO. Generic FIFO using inferred memory. - -- Supports clock domain crossing - -- Should be safe from fast->slow or reversed - -- Set sync_depth := 0 and gray_code := false if only one clock - component gc_wfifo is - generic( - sync_depth : natural := 3; - gray_code : boolean := true; - addr_width : natural := 4; - data_width : natural := 32); - port( - -- write port, only set w_en when w_rdy - w_clk_i : in std_logic; - w_rst_n_i: in std_logic; - w_rdy_o : out std_logic; - w_en_i : in std_logic; - w_data_i : in std_logic_vector(data_width-1 downto 0); - -- (pre)alloc port, can be unused - a_clk_i : in std_logic; - a_rst_n_i: in std_logic; - a_rdy_o : out std_logic; - a_en_i : in std_logic; - -- read port, only set r_en when r_rdy - -- data is valid the cycle after r_en raised - r_clk_i : in std_logic; - r_rst_n_i: in std_logic; - r_rdy_o : out std_logic; - r_en_i : in std_logic; - r_data_o : out std_logic_vector(data_width-1 downto 0)); - end component; - -- Power-On reset generation component gc_reset is generic( diff --git a/modules/wishbone/wb_clock_crossing/xwb_clock_crossing.vhd b/modules/wishbone/wb_clock_crossing/xwb_clock_crossing.vhd index a068f63b..c04a628d 100644 --- a/modules/wishbone/wb_clock_crossing/xwb_clock_crossing.vhd +++ b/modules/wishbone/wb_clock_crossing/xwb_clock_crossing.vhd @@ -2,14 +2,13 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.wishbone_pkg.all; -use work.gencores_pkg.all; +use work.genram_pkg.all; -- If you reset one clock domain, you must reset BOTH! -- Release of the reset lines may be arbitrarily out-of-phase entity xwb_clock_crossing is generic( - sync_depth : natural := 3; - log2fifo : natural := 4); + g_size : natural := 16); port( -- Slave control port slave_clk_i : in std_logic; @@ -35,11 +34,11 @@ architecture rtl of xwb_clock_crossing is constant mSEL_start : natural := mDAT_end + 1; constant mSEL_end : natural := mSEL_start + (c_wishbone_data_width/8) - 1; constant mlen : natural := mSEL_end + 1; - + signal msend, mrecv : t_wishbone_master_out; signal msend_vect, mrecv_vect : std_logic_vector(mlen-1 downto 0); - signal mw_rdy, mw_en, mr_rdy, mr_en : std_logic; - + signal mw_en, mr_empty, mr_en : std_logic; + constant sACK_start : natural := 0; constant sACK_end : natural := sACK_start; constant sRTY_start : natural := sACK_end + 1; @@ -49,69 +48,135 @@ architecture rtl of xwb_clock_crossing is constant sDAT_start : natural := sERR_end + 1; constant sDAT_end : natural := sDAT_start + c_wishbone_data_width - 1; constant slen : natural := sDAT_end + 1; - + signal ssend, srecv : t_wishbone_slave_out; signal ssend_vect, srecv_vect : std_logic_vector(slen-1 downto 0); - signal sw_rdy, sw_en, sr_rdy, sr_en, sa_rdy, sa_en : std_logic; - + signal sw_en, sr_empty, sr_en : std_logic; + signal slave_CYC : std_logic; signal master_o_STB : std_logic; signal slave_o_PUSH : std_logic; + + -- We need to limit the total number of incomplete Wishbone requests. + -- Consider a slow master and fast slave. + -- The master slowly pushes a lot of requests. + -- The slave pops them immediately from the mfifo and queues them itself. + -- Suddenly, the slave can do work and answers all pending requests. + -- The slow master is unable to read the sfifo fast enough and it overflows. + + subtype t_count is unsigned(f_ceil_log2(g_size+1)-1 downto 0); + + signal mpushed : t_count; + signal mpopped : t_count; + signal full : std_logic; + begin - mfifo : gc_wfifo - generic map(addr_width => log2fifo, data_width => mlen, sync_depth => sync_depth, gray_code => true) - port map(w_clk_i => slave_clk_i, w_rst_n_i => slave_rst_n_i, w_rdy_o => mw_rdy, w_en_i => mw_en, w_data_i => msend_vect, - r_clk_i => master_clk_i, r_rst_n_i => master_rst_n_i, r_rdy_o => mr_rdy, r_en_i => mr_en, r_data_o => mrecv_vect, - a_clk_i => '0', a_rst_n_i => '0', a_rdy_o => open, a_en_i => '0'); + + full <= '1' when mpushed = mpopped else '0'; + count : process(slave_clk_i) is + begin + if rising_edge(slave_clk_i) then + if slave_rst_n_i = '0' then + mpushed <= (others => '0'); + mpopped <= to_unsigned(g_size, t_count'length); + else + if (not full and slave_i.CYC and slave_i.STB) = '1' then + mpushed <= mpushed + 1; + end if; + if slave_o_PUSH = '1' then + mpopped <= mpopped + 1; + end if; + end if; + end if; + end process; + + mfifo : generic_async_fifo + generic map( + g_data_width => mlen, + g_size => g_size) + port map( + rst_n_i => slave_rst_n_i, + clk_wr_i => slave_clk_i, + d_i => msend_vect, + we_i => mw_en, + wr_empty_o => open, + wr_full_o => open, + wr_almost_empty_o => open, + wr_almost_full_o => open, + wr_count_o => open, + clk_rd_i => master_clk_i, + q_o => mrecv_vect, + rd_i => mr_en, + rd_empty_o => mr_empty, + rd_full_o => open, + rd_almost_empty_o => open, + rd_almost_full_o => open, + rd_count_o => open); msend_vect(mCYC_start) <= msend.CYC; msend_vect(mWE_start) <= msend.WE; msend_vect(mADR_end downto mADR_start) <= msend.ADR; msend_vect(mDAT_end downto mDAT_start) <= msend.DAT; msend_vect(mSEL_end downto mSEL_start) <= msend.SEL; - + mrecv.CYC <= mrecv_vect(mCYC_start); mrecv.WE <= mrecv_vect(mWE_start); mrecv.ADR <= mrecv_vect(mADR_end downto mADR_start); mrecv.DAT <= mrecv_vect(mDAT_end downto mDAT_start); mrecv.SEL <= mrecv_vect(mSEL_end downto mSEL_start); - - sfifo : gc_wfifo - generic map(addr_width => log2fifo, data_width => slen, sync_depth => sync_depth, gray_code => true) - port map(w_clk_i => master_clk_i, w_rst_n_i => master_rst_n_i, w_rdy_o => open, w_en_i => sw_en, w_data_i => ssend_vect, - r_clk_i => slave_clk_i, r_rst_n_i => slave_rst_n_i, r_rdy_o => sr_rdy, r_en_i => sr_en, r_data_o => srecv_vect, - a_clk_i => slave_clk_i, a_rst_n_i => slave_rst_n_i, a_rdy_o => sa_rdy, a_en_i => sa_en); - + + sfifo : generic_async_fifo + generic map( + g_data_width => slen, + g_size => g_size) + port map( + rst_n_i => master_rst_n_i, + clk_wr_i => master_clk_i, + d_i => ssend_vect, + we_i => sw_en, + wr_empty_o => open, + wr_full_o => open, + wr_almost_empty_o => open, + wr_almost_full_o => open, + wr_count_o => open, + clk_rd_i => slave_clk_i, + q_o => srecv_vect, + rd_i => sr_en, + rd_empty_o => sr_empty, + rd_full_o => open, + rd_almost_empty_o => open, + rd_almost_full_o => open, + rd_count_o => open); + ssend_vect(sACK_start) <= ssend.ACK; ssend_vect(sRTY_start) <= ssend.RTY; ssend_vect(sERR_start) <= ssend.ERR; ssend_vect(sDAT_end downto sDAT_start) <= ssend.DAT; - + srecv.ACK <= srecv_vect(sACK_start); srecv.RTY <= srecv_vect(sRTY_start); srecv.ERR <= srecv_vect(sERR_start); srecv.DAT <= srecv_vect(sDAT_end downto sDAT_start); -- Slave clock domain: slave -> mFIFO - mw_en <= (mw_rdy and sa_rdy and slave_i.CYC and slave_i.STB) or + mw_en <= (not full and slave_i.CYC and slave_i.STB) or (not slave_i.CYC and slave_CYC); -- Masters may only drop cycle if FIFOs are empty - sa_en <= mw_rdy and sa_rdy and slave_i.CYC and slave_i.STB; - slave_o.STALL <= not mw_rdy or not sa_rdy; + slave_o.STALL <= full; msend.CYC <= slave_i.CYC; msend.ADR <= slave_i.ADR; msend.WE <= slave_i.WE; msend.SEL <= slave_i.SEL; msend.DAT <= slave_i.DAT; - + -- Master clock domain: mFIFO -> master - mr_en <= mr_rdy and (not mrecv.CYC or not master_o_STB or not master_i.STALL); + mr_en <= not mr_empty and (not mrecv.CYC or not master_o_STB or not master_i.STALL); master_o.CYC <= mrecv.CYC; master_o.STB <= master_o_STB; -- is high outside of CYC. that's ok; it should be ignored. master_o.ADR <= mrecv.ADR; master_o.WE <= mrecv.WE; master_o.SEL <= mrecv.SEL; master_o.DAT <= mrecv.DAT; - + drive_master_port : process(master_clk_i) begin if rising_edge(master_clk_i) then @@ -122,21 +187,21 @@ begin end if; end if; end process; - + -- Master clock domain: master -> sFIFO sw_en <= mrecv.CYC and (master_i.ACK or master_i.ERR or master_i.RTY); ssend.ACK <= master_i.ACK; ssend.ERR <= master_i.ERR; ssend.RTY <= master_i.RTY; ssend.DAT <= master_i.DAT; - + -- Slave clock domain: sFIFO -> slave - sr_en <= sr_rdy; + sr_en <= not sr_empty; slave_o.DAT <= srecv.DAT; slave_o.ACK <= srecv.ACK and slave_o_PUSH; 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) begin if rising_edge(slave_clk_i) then @@ -149,4 +214,5 @@ begin end if; end if; end process; + end rtl; diff --git a/modules/wishbone/wishbone_pkg.vhd b/modules/wishbone/wishbone_pkg.vhd index ad10e1ee..f195267d 100644 --- a/modules/wishbone/wishbone_pkg.vhd +++ b/modules/wishbone/wishbone_pkg.vhd @@ -334,8 +334,7 @@ package wishbone_pkg is -- Release of the reset lines may be arbitrarily out-of-phase component xwb_clock_crossing is generic( - sync_depth : natural := 3; - log2fifo : natural := 4); + g_size : natural := 16); port( -- Slave control port slave_clk_i : in std_logic; -- GitLab