-- -- Copyright 2019 Ettus Research, A National Instruments brand -- -- SPDX-License-Identifier: LGPL-3.0 -- -- Module: arp_responder -- Description: Processing IP to send replies for ARP frames (for IPv4) -- arp_responder checks the incoming ARP frame against the input port ip_addr, -- and if the frame is a request for this module's ip_addr, the module will -- format an ARP reply and send it on the outgoing AXI-S interface. -- -- mac_addr and ip_addr must be kept stable for this module to function. They -- are not registered within the IP. -- -- s_axis_tuser indicates there is an error in the packet, and it should be discarded library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity arp_responder is port ( aclk : in std_logic; aresetn : in std_logic; mac_addr : in std_logic_vector(47 downto 0); ip_addr : in std_logic_vector(31 downto 0); s_axis_tdata : in std_logic_vector(63 downto 0); s_axis_tvalid : in std_logic; s_axis_tready : out std_logic; s_axis_tkeep : in std_logic_vector(7 downto 0); s_axis_tlast : in std_logic; s_axis_tuser : in std_logic; m_axis_tdata : out std_logic_vector(63 downto 0); m_axis_tvalid : out std_logic; m_axis_tready : in std_logic; m_axis_tkeep : out std_logic_vector(7 downto 0); m_axis_tlast : out std_logic; m_axis_tuser : out std_logic ); end arp_responder; architecture arch of arp_responder is type pkt_state_t is (PKT_IDLE, PKT_RECV, PKT_SEND, PKT_DROP); signal pkt_state : pkt_state_t; signal pkt_recv_count : unsigned(3 downto 0); signal pkt_send_count : unsigned(3 downto 0); --All of these are LSB-0 for bits, but first byte transmitted is byte 0 -- In ChipScope, bytes will appear swapped versus typical diagrams signal src_mac_be : std_logic_vector(47 downto 0); signal sender_hw_addr_be : std_logic_vector(47 downto 0); signal sender_protocol_addr_be : std_logic_vector(31 downto 0); signal target_protocol_addr_be : std_logic_vector(31 downto 0); signal ip_addr_be : std_logic_vector(31 downto 0); begin m_axis_tuser <= '0'; m_axis_tvalid <= '1' when (pkt_state = PKT_SEND) else '0'; ip_addr_be <= ip_addr(7 downto 0) & ip_addr(15 downto 8) & ip_addr(23 downto 16) & ip_addr(31 downto 24); s_axis_tready <= '1' when (pkt_state = PKT_IDLE) or (pkt_state = PKT_RECV) or (pkt_state = PKT_DROP) else '0'; tx_reply : process (src_mac_be, mac_addr, ip_addr, sender_hw_addr_be, sender_protocol_addr_be, pkt_send_count) begin m_axis_tdata <= (others => 'X'); m_axis_tkeep <= (others => '1'); m_axis_tlast <= '0'; case (to_integer(pkt_send_count)) is when 0 => m_axis_tdata(47 downto 0) <= src_mac_be; m_axis_tdata(63 downto 48) <= mac_addr(39 downto 32) & mac_addr(47 downto 40); m_axis_tkeep <= X"FF"; m_axis_tlast <= '0'; when 1 => m_axis_tdata(31 downto 0) <= mac_addr(7 downto 0) & mac_addr(15 downto 8) & mac_addr(23 downto 16) & mac_addr(31 downto 24); m_axis_tdata(47 downto 32) <= X"0608"; m_axis_tdata(63 downto 48) <= X"0100"; m_axis_tkeep <= X"FF"; m_axis_tlast <= '0'; when 2 => m_axis_tdata(15 downto 0) <= X"0008"; --PTYPE m_axis_tdata(23 downto 16) <= X"06"; --HLEN m_axis_tdata(31 downto 24) <= X"04"; --PLEN m_axis_tdata(47 downto 32) <= X"0200"; --OPER m_axis_tdata(63 downto 48) <= mac_addr(39 downto 32) & mac_addr(47 downto 40); --SHA m_axis_tkeep <= X"FF"; m_axis_tlast <= '0'; when 3 => m_axis_tdata(31 downto 0) <= mac_addr(7 downto 0) & mac_addr(15 downto 8) & mac_addr(23 downto 16) & mac_addr(31 downto 24); --SHA m_axis_tdata(63 downto 32) <= ip_addr(7 downto 0) & ip_addr(15 downto 8) & ip_addr(23 downto 16) & ip_addr(31 downto 24); --SPA m_axis_tkeep <= X"FF"; m_axis_tlast <= '0'; when 4 => m_axis_tdata(47 downto 0) <= sender_hw_addr_be; --THA m_axis_tdata(63 downto 48) <= sender_protocol_addr_be(15 downto 0); --TPA m_axis_tkeep <= X"FF"; m_axis_tlast <= '0'; when 5 => m_axis_tdata(15 downto 0) <= sender_protocol_addr_be(31 downto 16); --TPA m_axis_tdata(63 downto 16) <= (others => '0'); m_axis_tkeep <= X"03"; m_axis_tlast <= '1'; when others => null; end case; end process; process (aclk) variable pkt_nonmatch : boolean := false; begin if rising_edge(aclk) then case (pkt_state) is when PKT_IDLE => if (s_axis_tvalid = '1') and (s_axis_tlast = '0') and (s_axis_tuser = '0') then pkt_state <= PKT_RECV; pkt_recv_count <= to_unsigned(1, pkt_recv_count'length); src_mac_be(15 downto 0) <= s_axis_tdata(63 downto 48); end if; when PKT_RECV => pkt_nonmatch := false; pkt_send_count <= to_unsigned(0, pkt_send_count'length); if (s_axis_tvalid = '1') and (s_axis_tuser = '1') then pkt_nonmatch := true; elsif (s_axis_tvalid = '1') and (s_axis_tuser = '0') then if (to_integer(pkt_recv_count) < 7) then pkt_recv_count <= pkt_recv_count + 1; end if; case (to_integer(pkt_recv_count)) is when 1 => src_mac_be(47 downto 16) <= s_axis_tdata(31 downto 0); if (s_axis_tdata(47 downto 32) /= X"0608") or --eth_type (s_axis_tdata(63 downto 48) /= X"0100") or --HTYPE (s_axis_tlast = '1') then pkt_nonmatch := true; end if; when 2 => sender_hw_addr_be(15 downto 0) <= s_axis_tdata(63 downto 48); if (s_axis_tdata(15 downto 0) /= X"0008") or --PTYPE (s_axis_tdata(23 downto 16) /= X"06") or --HLEN (s_axis_tdata(31 downto 24) /= X"04") or --PLEN (s_axis_tdata(47 downto 32) /= X"0100") or --OPER (s_axis_tlast = '1') then pkt_nonmatch := true; end if; when 3 => sender_hw_addr_be(47 downto 16) <= s_axis_tdata(31 downto 0); sender_protocol_addr_be <= s_axis_tdata(63 downto 32); if (s_axis_tlast = '1') then pkt_nonmatch := true; end if; when 4 => --THA = s_axis_tdata(47 downto 0) target_protocol_addr_be(15 downto 0) <= s_axis_tdata(63 downto 48); if (s_axis_tdata(63 downto 48) /= ip_addr_be(15 downto 0)) or (s_axis_tlast = '1') then pkt_nonmatch := true; end if; when 5 => target_protocol_addr_be(31 downto 16) <= s_axis_tdata(15 downto 0); if (s_axis_tdata(15 downto 0) /= ip_addr_be(31 downto 16)) then pkt_nonmatch := true; end if; when others => null; end case; end if; if (pkt_nonmatch) then if (s_axis_tlast = '1') then pkt_state <= PKT_IDLE; else pkt_state <= PKT_DROP; end if; elsif (s_axis_tlast = '1') then pkt_state <= PKT_SEND; end if; when PKT_SEND => if (m_axis_tready = '1') then pkt_send_count <= pkt_send_count + 1; if (pkt_send_count = 5) then pkt_state <= PKT_IDLE; end if; end if; when PKT_DROP => if (s_axis_tvalid = '1') and (s_axis_tlast = '1') then pkt_state <= PKT_IDLE; end if; end case; if aresetn = '0' then pkt_state <= PKT_IDLE; end if; end if; end process; end arch;