1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
--
-- 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;
|