------------------------------------------------------------------------------- -- Title : ni_resync -- Project : Network Interface (NI) for the ALICE TRD TRAP2 ------------------------------------------------------------------------------- -- File : ni_resync.vhd -- Author : Rolf Schneider -- Company : University Heidelberg - KIP -- Last update: 2003-03-19 -- Platform : Synopsys - v2003.03 ------------------------------------------------------------------------------- -- Description: resynchronization unit from DDR input to sync. output ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2003/03/06 1.0 schneide Created ------------------------------------------------------------------------------- -- last modified: 18:09 / 26 May 2003 / V.Angelov -- additional output register stage for FPGA implementation only library IEEE; use IEEE.std_logic_1164.all; ---------------------------------------------------------------------------------------------------- -- ENTITY ---------------------------------------------------------------------------------------------------- entity ni_resync is generic( width : integer := 10); -- width of the external interface port( clk : in std_logic; -- internal clock reset_n : in std_logic; -- asynchronous reset strobe : in std_logic; -- incoming DDR strobe signal data_in : in std_logic_vector(width-1 downto 0); -- incoming DDR data sync. to strobe we_n : out std_logic; -- outgoing data valid signal data_out : out std_logic_vector((2*width)-1 downto 0)); -- data output, sync. to internal clk end ni_resync; ---------------------------------------------------------------------------------------------------- -- ARCHITECTURE ---------------------------------------------------------------------------------------------------- architecture v of ni_resync is component reg_clr is generic(Ndata : Integer := 32); port ( clk : in std_logic; ce : in std_logic; rst_n : in std_logic; d : in std_logic_vector(Ndata-1 downto 0); q : out std_logic_vector(Ndata-1 downto 0) ); end component; -- CONSTANTS ------------------------------------------------------------------------------------- constant gray0 : std_logic_vector(1 downto 0) := "00"; -- constant gray counter codes ... constant gray1 : std_logic_vector(1 downto 0) := "01"; constant gray2 : std_logic_vector(1 downto 0) := "11"; constant gray3 : std_logic_vector(1 downto 0) := "10"; -- SIGNALS --------------------------------------------------------------------------------------- signal data0pos, data1pos, data2pos, data3pos : std_logic_vector(width-1 downto 0); signal data0neg, data1neg, data2neg, data3neg : std_logic_vector(width-1 downto 0); signal gray_cnt, old_cnt, nxt_cnt, new_cnt : std_logic_vector(1 downto 0); signal gray_cnt_neg : std_logic_vector(1 downto 0); signal valid_i : std_logic; signal strobe_n : std_logic; signal we_pos : std_logic_vector(3 downto 0); signal we_neg : std_logic_vector(3 downto 0); signal sync_p : std_logic; signal sync_n : std_logic; signal LogH : std_logic; signal data_out_i : std_logic_vector(data_out'range); -- STRUCTURE ------------------------------------------------------------------------------------- begin -- fetch data on rising edge of strobe signal into one of four registers -- depending on the cray counter 'gray_cnt' and increment 'gray_cnt' process(strobe, reset_n) begin if reset_n = '0' then gray_cnt <= gray0; sync_p <= '0'; elsif rising_edge(strobe) then sync_p <= '0'; case gray_cnt is when gray0 => gray_cnt <= gray1; when gray1 => gray_cnt <= gray2; sync_p <= '1'; when gray2 => gray_cnt <= gray3; when gray3 => gray_cnt <= gray0; when others => null; end case; end if; end process; with gray_cnt select we_pos <= "1000" when gray3, "0100" when gray2, "0010" when gray1, "0001" when gray0, "XXXX" when others; LogH <= '1'; rg0pos: reg_clr generic map(Ndata => width) port map(clk => strobe, ce => we_pos(0), rst_n => LogH, d => data_in, q => data0pos ); rg1pos: reg_clr generic map(Ndata => width) port map(clk => strobe, ce => we_pos(1), rst_n => LogH, d => data_in, q => data1pos ); rg2pos: reg_clr generic map(Ndata => width) port map(clk => strobe, ce => we_pos(2), rst_n => LogH, d => data_in, q => data2pos ); rg3pos: reg_clr generic map(Ndata => width) port map(clk => strobe, ce => we_pos(3), rst_n => LogH, d => data_in, q => data3pos ); -- negative edge of strobe strobe_n <= not strobe; process(strobe_n, reset_n) begin if reset_n = '0' then gray_cnt_neg <= gray0; sync_n <= '0'; elsif rising_edge(strobe_n) then sync_n <= sync_p; if sync_n='1' then gray_cnt_neg <= gray0; else case gray_cnt_neg is when gray0 => gray_cnt_neg <= gray1; when gray1 => gray_cnt_neg <= gray2; when gray2 => gray_cnt_neg <= gray3; when gray3 => gray_cnt_neg <= gray0; when others => null; end case; end if; end if; end process; with gray_cnt_neg select we_neg <= "1000" when gray3, "0100" when gray2, "0010" when gray1, "0001" when gray0, "XXXX" when others; -- fetch data on falling edge of strobe signal into one of four registers -- depending on the gray counter 'gray_cnt rg0neg: reg_clr generic map(Ndata => width) port map(clk => strobe_n, ce => we_neg(0), rst_n => LogH, d => data_in, q => data0neg ); rg1neg: reg_clr generic map(Ndata => width) port map(clk => strobe_n, ce => we_neg(1), rst_n => LogH, d => data_in, q => data1neg ); rg2neg: reg_clr generic map(Ndata => width) port map(clk => strobe_n, ce => we_neg(2), rst_n => LogH, d => data_in, q => data2neg ); rg3neg: reg_clr generic map(Ndata => width) port map(clk => strobe_n, ce => we_neg(3), rst_n => LogH, d => data_in, q => data3neg ); -- prepare next value of old_cnt with old_cnt select nxt_cnt <= gray1 when gray0, gray2 when gray1, gray3 when gray2, gray0 when others; -- data is valid if new_cnt and old_cnt differs for more than one clock cycle valid_i <= '1' when new_cnt /= old_cnt else '0'; -- synchronize to the system clock process(clk, reset_n) begin if reset_n = '0' then new_cnt <= "00"; old_cnt <= "00"; elsif rising_edge(clk) then new_cnt <= gray_cnt; if valid_i = '1' then old_cnt <= nxt_cnt; end if; end if; end process; -- select the valid output register with old_cnt select data_out_i <= data0pos & data0neg when gray0, data1pos & data1neg when gray1, data2pos & data2neg when gray2, data3pos & data3neg when others; -- the we_n signal for the fifos correspond to the valid signal process(clk) begin if clk'event and clk='1' then data_out <= data_out_i; we_n <= not valid_i; end if; end process; end; ---------------------------------------------------------------------------------------------------- -- CONFIGURATION ---------------------------------------------------------------------------------------------------- -- pragma translate_off configuration ni_resync_CFG of ni_resync is for v end for; -- v end ni_resync_CFG; -- pragma translate_on