-- -------------------------------------------------------------------------- -- -- TRASHERNET - A Trashy Ethernet Stack for FPGAs -- -- -------------------------------------------------------------------------- -- -- trashernet_phy_cdc.vhd : Dual clock wrapper for the trashernet_phy -- Implements CDC between the PHY and DATA clock domains. -- -------------------------------------------------------------------------- -- -- Author : Markus Koch -- Contributors : None -- License : Mozilla Public License (MPL) Version 2 -- -------------------------------------------------------------------------- -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.trashernet_types.all; entity trashernet_phy_cdc is generic( F_CLK : in integer; -- Clock frequency of design IF F_CLK_PHY : in integer -- PHY clock (expected to be faster than F_CLK) ); port( -- Global clk : in std_logic; -- Clock for internal interface phy_clk : in std_logic; -- Clock for PHY (rx_p, tx_p) rst : in std_logic; -- Asynchronous reset -- System interface rx_data : out byte; -- RX Data rx_data_valid : out std_logic; -- RX Data valid rx_active : out std_logic; -- RX of packet in progress tx_data : in byte; -- TX Data tx_data_en : in std_logic; -- Transmitter enable tx_data_ack : out std_logic; -- Latched data_tx tx_active : out std_logic; -- Transmission in progress carrier_detect : out std_logic; -- Carrier detected rx_error : out std_logic; -- Receive error -- Ethernet physical signals rx_p : in std_logic; tx_p : out std_logic; tx_n : out std_logic ); end entity trashernet_phy_cdc; architecture RTL of trashernet_phy_cdc is -- PHY signals signal phy_rst : std_logic; signal phy_rx_data : std_logic_vector(7 downto 0); signal phy_rx_data_valid : std_logic; signal phy_rx_active : std_logic; signal phy_tx_data : std_logic_vector(7 downto 0); signal phy_tx_data_en : std_logic; signal phy_tx_data_ack : std_logic; signal phy_carrier_detect : std_logic; signal phy_rx_error : std_logic; signal phy_tx_active : std_logic; -- Helper signals signal rx_data_valid_i : std_logic; begin -- ------------------------------------------------------------------------- -- Drives: PHY clock domain -- ------------------------------------------------------------------------- rstsync : process(phy_clk, rst) is begin if rst then phy_rst <= '1'; elsif rising_edge(phy_clk) then phy_rst <= '0'; end if; end process rstsync; trashernet_phy_inst : entity work.trashernet_phy generic map( F_CLK => F_CLK_PHY ) port map( clk => phy_clk, rst => phy_rst, rx_data => phy_rx_data, rx_data_valid => phy_rx_data_valid, rx_active => phy_rx_active, tx_data => phy_tx_data, tx_data_en => phy_tx_data_en, tx_data_ack => phy_tx_data_ack, tx_active => phy_tx_active, carrier_detect => phy_carrier_detect, rx_error => phy_rx_error, rx_p => rx_p, tx_p => tx_p, tx_n => tx_n ); synchronizer_txen_inst : entity work.synchronizer generic map( SIZE => 5 ) port map( clk => phy_clk, rst => phy_rst, data_in => tx_data_en, data_out => phy_tx_data_en ); phy_tx_data <= tx_data; -- When tx_data_en is through the synchronizer, this should be stable (and in the other direction, it should only change when we don't read it anyways) -- ------------------------------------------------------------------------- -- Drives: System clock domain -- ------------------------------------------------------------------------- cdc_strobe_rxdv_inst : entity work.cdc_strobe port map( a_clk => phy_clk, a_rst => phy_rst, a_in => phy_rx_data_valid, b_clk => clk, b_rst => rst, b_out => rx_data_valid_i ); rxdvff : process(clk, rst) is begin if rst then rx_data_valid <= '0'; elsif rising_edge(clk) then rx_data_valid <= rx_data_valid_i; rx_data <= phy_rx_data; -- Data should be stable after the time it takes the _valid signal to go through the synchronizer end if; end process rxdvff; cdc_strobe_rxer_inst : entity work.cdc_strobe port map( a_clk => phy_clk, a_rst => phy_rst, a_in => phy_rx_error, b_clk => clk, b_rst => rst, b_out => rx_error ); synchronizer_rxa_inst : entity work.synchronizer port map( clk => clk, rst => rst, data_in => phy_rx_active, data_out => rx_active ); cdc_strobe_txack_inst : entity work.cdc_strobe port map( a_clk => phy_clk, a_rst => phy_rst, a_in => phy_tx_data_ack, b_clk => clk, b_rst => rst, b_out => tx_data_ack ); synchronizer_crs_inst : entity work.synchronizer port map( clk => clk, rst => rst, data_in => phy_carrier_detect, data_out => carrier_detect ); synchronizer_txa_inst : entity work.synchronizer port map( clk => clk, rst => rst, data_in => phy_tx_active, data_out => tx_active ); end architecture RTL;