arp: Implement ARP replies

This commit is contained in:
Markus Koch 2022-05-15 14:44:37 +02:00
parent 7bb82a9acf
commit 5f389b0c7b
3 changed files with 236 additions and 2 deletions

View File

@ -183,9 +183,12 @@ architecture eth of top_hwitl is
constant F_CLK : integer := 50000000;
constant F_CLK_PHY : integer := 140000000;
constant ETH_CONFIG : configuration_t := (
constant ETH_CONFIG : configuration_t := (
mac_address => (x"00", x"ff", x"ff", x"11", x"22", x"33")
);
constant IP_CONFIG : ip_configuration_t := (
ip_address => (x"C0", x"A8", x"02", x"02")
);
signal rst : std_logic;
signal clk_phy : std_logic;
@ -199,12 +202,30 @@ architecture eth of top_hwitl is
constant PROT_ARP : integer := 0;
constant PROT_IP : integer := 1;
constant ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := (PROT_ARP => ETHERNET_II_PROTOCOL_ARP, PROT_IP => ETHERNET_II_PROTOCOL_IP);
constant ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := (
PROT_ARP => ETHERNET_II_PROTOCOL_ARP,
PROT_IP => ETHERNET_II_PROTOCOL_IP
);
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;
begin
trashernet_arp_inst : entity trashernet.trashernet_arp
port map(
clk => clk,
rst => rst,
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)
);
trashernet_eth_inst : entity trashernet.trashernet_eth
generic map(
ETHERNET_II_PROTOCOLS => ETHERNET_II_PROTOCOLS

View File

@ -0,0 +1,210 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_arp.vhd : Address Resolution Protocol
-- Implements simple single-entry cache ARP.
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- 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_pkg.all;
entity trashernet_arp is
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- Configuration
mac_config : in configuration_t; -- Trashernet MAC configuration
ip_config : in ip_configuration_t; -- Trashernet IP configuration
-- ARP application interface
arp_out : out arp_out_t; -- ARP IF (out from ARP)
arp_in : in arp_in_t; -- ARP IF (into ARP)
-- Ethernet II application interface
ethernet_ii_out : in ethernet_ii_out_t; -- Ethernet II IF (out from MAC)
ethernet_ii_in : out ethernet_ii_in_t -- Ethernet II IF (into MAC)
);
end entity trashernet_arp;
architecture rtl of trashernet_arp is
constant HTYPE : byte_vector := (x"00", x"01");
constant PTYPE : byte_vector := (x"08", x"00");
constant HLEN : byte := x"06";
constant PLEN : byte := x"04";
constant OPER_REQUEST : byte_vector := (x"00", x"01");
constant OPER_REPLY : byte_vector := (x"00", x"02");
signal arp_reply_rq : std_logic; -- Request to transmit an ARP reply
signal arp_reply_tha : mac_addr_t; -- Target MAC to use in reply (SHA in received packet)
signal arp_reply_tpa : ip_addr_t; -- Target IP to use in reply (SPA in received packet)
signal arp_reply_ack : std_logic; -- ARP reply has been latched and is being sent
begin
rx : block
constant BYTECOUNT_HEAD : integer := 8; -- HTYPE -> OPER
constant BYTECOUNT_ADDRESSES : integer := 20; -- SHA -> TPA
signal sr : byte_vector(0 to BYTECOUNT_ADDRESSES - 1);
constant SR_HEAD_OFFSET : integer := BYTECOUNT_ADDRESSES - BYTECOUNT_HEAD;
alias sr_head_htype is sr(SR_HEAD_OFFSET + 0 to SR_HEAD_OFFSET + 1);
alias sr_head_ptype is sr(SR_HEAD_OFFSET + 2 to SR_HEAD_OFFSET + 3);
alias sr_head_hlen is sr(SR_HEAD_OFFSET + 4);
alias sr_head_plen is sr(SR_HEAD_OFFSET + 5);
alias sr_head_oper is sr(SR_HEAD_OFFSET + 6 to SR_HEAD_OFFSET + 7);
constant SR_ADDRESSES_OFFSET : integer := -8;
alias sr_addresses_sha is sr(8 + SR_ADDRESSES_OFFSET to 13 + SR_ADDRESSES_OFFSET);
alias sr_addresses_spa is sr(14 + SR_ADDRESSES_OFFSET to 17 + SR_ADDRESSES_OFFSET);
alias sr_addresses_tha is sr(18 + SR_ADDRESSES_OFFSET to 23 + SR_ADDRESSES_OFFSET);
alias sr_addresses_tpa is sr(24 + SR_ADDRESSES_OFFSET to 27 + SR_ADDRESSES_OFFSET);
type state_t is (HEAD, ADDRESSES, WAITCRC, SENDREPLY, IGNORE);
signal state : state_t;
signal bytecount : integer range 0 to BYTECOUNT_ADDRESSES;
signal shifted : std_logic;
signal block_done : std_logic;
signal header_ok : std_logic;
signal we_are_asked : std_logic;
signal is_request : std_logic;
begin
block_done <= '1' when shifted = '1' and bytecount = 0 else '0';
header_ok <= '1' when --
sr_head_htype = HTYPE and --
sr_head_ptype = PTYPE and --
sr_head_hlen = HLEN and sr_head_plen = PLEN --
else
'0';
we_are_asked <= '1' when --
sr_addresses_tpa = ip_config.ip_address else
'0';
rx_fsm : process(clk, rst) is
begin
if rst then
state <= HEAD;
shifted <= '0';
bytecount <= BYTECOUNT_HEAD;
elsif rising_edge(clk) then
if (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
state <= HEAD; -- Safe return from any state, may be overridden below
bytecount <= BYTECOUNT_HEAD;
end if;
shifted <= ethernet_ii_out.rx_data_valid;
if (ethernet_ii_out.rx_data_valid = '1') and (bytecount > 0) then
sr <= sr(sr'low + 1 to sr'high) & ethernet_ii_out.rx_data;
bytecount <= bytecount - 1;
end if;
case state is
when HEAD =>
if block_done then
if header_ok then
bytecount <= BYTECOUNT_ADDRESSES;
state <= ADDRESSES;
is_request <= '1' when (sr_head_oper = OPER_REQUEST) else '0';
else
state <= IGNORE;
end if;
end if;
when ADDRESSES =>
if block_done then
if (we_are_asked) then
state <= WAITCRC;
else
state <= IGNORE;
end if;
end if;
when WAITCRC =>
if ethernet_ii_out.rx_crc_ok then
if is_request then
state <= SENDREPLY;
else
report "reply";
null; -- TODO: process response
end if;
end if;
when SENDREPLY =>
if arp_reply_ack then
bytecount <= BYTECOUNT_HEAD;
state <= HEAD;
end if;
when IGNORE =>
null;
end case;
end if;
end process rx_fsm;
arp_reply_rq <= '1' when state = SENDREPLY else '0';
arp_reply_tha <= sr_addresses_sha;
arp_reply_tpa <= sr_addresses_spa;
end block rx;
tx : block
signal sr : byte_vector(0 to 27);
signal arp_reply_preload : byte_vector(sr'range);
constant BYTECOUNT_MAX : integer := sr'length + 1;
signal bytecount : integer range 0 to BYTECOUNT_MAX;
type state_t is (IDLE, TRANSMIT);
signal state : state_t;
begin
arp_reply_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REPLY & -- Header
mac_config.mac_address & ip_config.ip_address & -- Sender
arp_reply_tha & arp_reply_tpa; -- Target
tx_fsm : process(clk, rst) is
begin
if rst then
arp_reply_ack <= '0';
elsif rising_edge(clk) then
arp_reply_ack <= '0';
if (ethernet_ii_out.tx_data_ack = '1') and (bytecount > 0) then
sr <= sr(sr'low + 1 to sr'high) & x"00";
bytecount <= bytecount - 1;
end if;
case state is
when IDLE =>
if arp_reply_rq then
state <= TRANSMIT;
arp_reply_ack <= '1';
sr <= arp_reply_preload;
end if;
bytecount <= BYTECOUNT_MAX;
when TRANSMIT =>
if bytecount = 0 then
state <= IDLE;
end if;
end case;
end if;
end process tx_fsm;
ethernet_ii_in.tx_mac_address <= arp_reply_tha;
ethernet_ii_in.tx_en <= '1' when state = TRANSMIT else '0';
ethernet_ii_in.tx_data <= sr(0);
end block tx;
end architecture rtl;

View File

@ -34,6 +34,9 @@ package trashernet_pkg is
type configuration_t is record
mac_address : mac_addr_t; -- MAC address of this node
end record configuration_t;
type ip_configuration_t is record
ip_address : ip_addr_t; -- IP address of this node
end record ip_configuration_t;
-- PHY interface
type phy_in_t is record