-- -------------------------------------------------------------------------- -- -- TRASHERNET - A Trashy Ethernet Stack for FPGAs -- -- -------------------------------------------------------------------------- -- -- top_hwitl.vhd: Top level design for hardware-in-the-loop tests -- -- Target: Simulation -- -------------------------------------------------------------------------- -- -- 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 ieee.math_real.all; library trashernet; use trashernet.trashernet_pkg.all; entity top_hwitl is port( clk : in std_logic; rst_n : in std_logic; rx_p : in std_logic; tx_p : out std_logic; tx_n : out std_logic; led_n : out std_logic_vector(7 downto 0); -- @suppress: Used in different architectures button_n : in std_logic_vector(3 downto 0); -- @suppress: Used in different architectures debug_data : out std_logic_vector(7 downto 0) -- @suppress: Used in different architectures ); end entity top_hwitl; architecture mac of top_hwitl is component pll0 port( CLK : in std_logic; CLKOP : out std_logic; LOCK : out std_logic ); end component pll0; constant F_CLK : integer := 50000000; constant F_CLK_PHY : integer := 140000000; constant ETH_CONFIG : configuration_t := ( mac_address => (x"00", x"ff", x"ff", x"11", x"22", x"33") ); signal rst : std_logic; signal clk_phy : std_logic; signal phy_out : phy_out_t; signal phy_in : phy_in_t; signal mac_out : mac_out_t; signal mac_in : mac_in_t; type status_t is (IDLE, TX); signal state : status_t; constant BYTE_CNT_MAX : integer := 100; signal byte_cnt : integer range 0 to BYTE_CNT_MAX; constant TMO_MAX : integer := integer(round((real(F_CLK) * 0.25))) - 1; signal tmo : integer range 0 to TMO_MAX; begin trashernet_mac_inst : entity trashernet.trashernet_mac port map( clk => clk, rst => rst, phy_out => phy_out, phy_in => phy_in, mac_out => mac_out, mac_in => mac_in ); pll0_inst : pll0 port map( CLK => clk, CLKOP => clk_phy, LOCK => open ); trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc generic map( F_CLK => F_CLK, F_CLK_PHY => F_CLK_PHY ) port map( clk => clk, phy_clk => clk_phy, rst => rst, phy_out => phy_out, phy_in => phy_in, rx_p => rx_p, tx_p => tx_p, tx_n => tx_n ); reset_sync : process(clk, rst_n) is begin if (rst_n = '0') then rst <= '1'; elsif (rising_edge(clk)) then rst <= '0'; end if; end process reset_sync; receiver : process(clk, rst) is begin if rst then state <= IDLE; mac_in.tx_mac_data_en <= '0'; tmo <= 0; elsif rising_edge(clk) then if (tmo /= 0) then tmo <= tmo - 1; end if; case state is when IDLE => if mac_out.rx_mac_crc_ok then if (mac_out.rx_header.mac_destination = ETH_CONFIG.mac_address) then -- Note: We won't respond to broadcasts! state <= TX; byte_cnt <= BYTE_CNT_MAX; mac_in.tx_header.mac_destination <= mac_out.rx_header.mac_source; end if; end if; if tmo = 0 then state <= TX; byte_cnt <= BYTE_CNT_MAX; mac_in.tx_header.mac_destination <= (others => x"FF"); end if; when TX => tmo <= TMO_MAX; mac_in.tx_header.mac_ethertype <= (x"00", std_logic_vector(to_unsigned(BYTE_CNT_MAX, 8))); mac_in.tx_mac_data_en <= '1'; mac_in.tx_mac_data <= std_logic_vector(to_unsigned(byte_cnt, 8)); if mac_out.tx_mac_data_ack then if byte_cnt = 1 then mac_in.tx_mac_data_en <= '0'; state <= IDLE; else byte_cnt <= byte_cnt - 1; end if; end if; end case; end if; end process receiver; mac_in.tx_header.mac_source <= ETH_CONFIG.mac_address; debug_data(0) <= tx_p; debug_data(1) <= tx_n; end architecture mac; -- -------------------------------------------------------------------------- -- -- top_hwitl (eth) -- -------------------------------------------------------------------------- -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; library trashernet; use trashernet.trashernet_pkg.all; architecture eth of top_hwitl is component pll0 port( CLK : in std_logic; CLKOP : out std_logic; LOCK : out std_logic ); end component pll0; constant F_CLK : integer := 50000000; constant F_CLK_PHY : integer := 140000000; constant ETH_CONFIG : configuration_t := ( mac_address => (x"00", x"FF", x"FF", x"11", x"22", x"33") ); constant IP_CONFIG : ipv4_configuration_t := ( ip_address => (x"C0", x"A8", x"02", x"02"), subnet_mask => (x"FF", x"FF", x"FF", x"00"), gateway => (x"C0", x"A8", x"02", x"01") ); signal rst : std_logic; signal clk_phy : std_logic; signal phy_out : phy_out_t; signal phy_in : phy_in_t; signal mac_out : mac_out_t; signal mac_in : mac_in_t; constant PROT_ARP : integer := 0; constant PROT_IPV4 : integer := 1; constant ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := ( PROT_ARP => ETHERNET_II_PROTOCOL_ARP, PROT_IPV4 => ETHERNET_II_PROTOCOL_IPV4 ); signal ethernet_i_out : ethernet_i_out_t; signal ethernet_i_in : ethernet_i_in_t; signal ethernet_ii_out : ethernet_ii_out_vector(ETHERNET_II_PROTOCOLS'range); signal ethernet_ii_in : ethernet_ii_in_vector(ETHERNET_II_PROTOCOLS'range); signal arp_out : arp_out_t; signal arp_in : arp_in_t; signal ipv4_out : ipv4_out_t; signal ipv4_in : ipv4_in_t; begin trashernet_ipv4_inst : entity trashernet.trashernet_ipv4 port map( clk => clk, rst => rst, ipv4_config => IP_CONFIG, arp_out => arp_out, arp_in => arp_in, ethernet_ii_out => ethernet_ii_out(PROT_IPV4), ethernet_ii_in => ethernet_ii_in(PROT_IPV4), ipv4_out => ipv4_out, ipv4_in => ipv4_in ); trashernet_arp_inst : entity trashernet.trashernet_arp generic map( SYSTICK_FREQ => F_CLK ) port map( clk => clk, rst => rst, systick => '1', mac_config => ETH_CONFIG, ip_config => IP_CONFIG, arp_out => arp_out, arp_in => arp_in, ethernet_ii_out => ethernet_ii_out(PROT_ARP), ethernet_ii_in => ethernet_ii_in(PROT_ARP) ); ethernet_i_in <= ethernet_i_in_t'( tx_mac_address => (others => (others => '-')), tx_data => (others => '-'), tx_en => '0', tx_length => (others => '-') ); trashernet_eth_inst : entity trashernet.trashernet_eth generic map( ETHERNET_II_PROTOCOLS => ETHERNET_II_PROTOCOLS ) port map( clk => clk, rst => rst, mac_out => mac_out, mac_in => mac_in, config => ETH_CONFIG, ethernet_i_out => ethernet_i_out, ethernet_i_in => ethernet_i_in, ethernet_ii_out => ethernet_ii_out, ethernet_ii_in => ethernet_ii_in ); trashernet_mac_inst : entity trashernet.trashernet_mac port map( clk => clk, rst => rst, phy_out => phy_out, phy_in => phy_in, mac_out => mac_out, mac_in => mac_in ); pll0_inst : pll0 port map( CLK => clk, CLKOP => clk_phy, LOCK => open ); trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc generic map( F_CLK => F_CLK, F_CLK_PHY => F_CLK_PHY ) port map( clk => clk, phy_clk => clk_phy, rst => rst, phy_out => phy_out, phy_in => phy_in, rx_p => rx_p, tx_p => tx_p, tx_n => tx_n ); reset_sync : process(clk, rst_n) is begin if (rst_n = '0') then rst <= '1'; elsif (rising_edge(clk)) then rst <= '0'; end if; end process reset_sync; receiver : process(clk, rst) is begin if rst then elsif rising_edge(clk) then if ethernet_i_out.rx_header_rcv then report "RX ETH-I: " & to_string(to_integer(ethernet_i_out.rx_length)); end if; if (ethernet_ii_out(PROT_ARP).rx_header_rcv) then report "RX ARP"; end if; if (ethernet_ii_out(PROT_IPV4).rx_header_rcv) then report "RX IP"; end if; if ipv4_out.rx_data_valid then report "RX IP data: " & to_hstring(ipv4_out.rx_data); end if; if ipv4_out.rx_ok_stb then report "RX IP OK"; end if; if ipv4_out.rx_error_stb then report "RX IP error"; end if; if ipv4_out.rx_header_rcv then report "RX IP start. PROT=" & to_hstring(ipv4_out.rx_protocol) & ", FROM=" & ip_to_string(ipv4_out.rx_ip_address); end if; end if; end process receiver; arp_request_test : process(clk, rst) is begin if rst then arp_in.arp_ip <= (x"C0", x"A8", x"02", x"01"); arp_in.arp_query_stb <= '0'; elsif rising_edge(clk) then arp_in.arp_query_stb <= not button_n(0); if arp_out.arp_ok_stb then report "Found MAC: " & mac_to_string(arp_out.arp_mac); end if; if arp_out.arp_fail_stb then report "ARP failed"; end if; end if; end process arp_request_test; end architecture eth;