diff --git a/trashernet/cdc_strobe.vhd b/trashernet/cdc_strobe.vhd new file mode 100644 index 0000000..93ed74c --- /dev/null +++ b/trashernet/cdc_strobe.vhd @@ -0,0 +1,51 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity cdc_strobe is + generic( + SYNCHRONIZERS : integer := 3 + ); + port( + a_clk : in std_logic; + a_rst : in std_logic; + a_in : in std_logic; + b_clk : in std_logic; + b_rst : in std_logic; + b_out : out std_logic + ); +end entity cdc_strobe; + +architecture rtl of cdc_strobe is + signal a_toggle : std_logic; + signal b_toggle : std_logic; + signal b_toggle_last : std_logic; +begin + togglify : process(a_clk, a_rst) is + begin + if a_rst then + a_toggle <= '0'; + elsif rising_edge(a_clk) then + if (a_in) then + a_toggle <= not a_toggle; + end if; + end if; + end process togglify; + + synchronizer_inst : entity work.synchronizer + generic map( + SIZE => SYNCHRONIZERS + ) + port map( + clk => b_clk, + rst => b_rst, + data_in => a_toggle, + data_out => b_toggle + ); + + -- strobify + b_toggle_last <= '0' when b_rst + else b_toggle when rising_edge(b_clk) + ; + b_out <= (b_toggle ?/= b_toggle_last); +end architecture rtl; diff --git a/trashernet/trashernet_phy_cdc.vhd b/trashernet/trashernet_phy_cdc.vhd new file mode 100644 index 0000000..a544764 --- /dev/null +++ b/trashernet/trashernet_phy_cdc.vhd @@ -0,0 +1,153 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.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 std_logic_vector(7 downto 0); -- RX Data + rx_data_valid : out std_logic; -- RX Data valid + rx_active : out std_logic; -- RX of packet in progress + + tx_data : in std_logic_vector(7 downto 0); -- TX Data + tx_data_en : in std_logic; -- Transmitter enable + tx_data_ack : out std_logic; -- Latched data_tx + + 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 + ); +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; + + -- 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, + carrier_detect => phy_carrier_detect, + rx_error => phy_rx_error, + rx_p => rx_p, + tx_p => tx_p + ); + + 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 + ); + +end architecture RTL;