From 5f389b0c7bbffdb39a1f7a7469e417c4bdb90c09 Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Sun, 15 May 2022 14:44:37 +0200 Subject: [PATCH] arp: Implement ARP replies --- design/top_hwitl.vhd | 25 +++- trashernet/trashernet_arp.vhd | 210 ++++++++++++++++++++++++++++++++++ trashernet/trashernet_pkg.vhd | 3 + 3 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 trashernet/trashernet_arp.vhd diff --git a/design/top_hwitl.vhd b/design/top_hwitl.vhd index 6ec6adb..bfb2d16 100644 --- a/design/top_hwitl.vhd +++ b/design/top_hwitl.vhd @@ -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 diff --git a/trashernet/trashernet_arp.vhd b/trashernet/trashernet_arp.vhd new file mode 100644 index 0000000..4d0da19 --- /dev/null +++ b/trashernet/trashernet_arp.vhd @@ -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 +-- 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; diff --git a/trashernet/trashernet_pkg.vhd b/trashernet/trashernet_pkg.vhd index fd3a04b..b04b885 100644 --- a/trashernet/trashernet_pkg.vhd +++ b/trashernet/trashernet_pkg.vhd @@ -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