Compare commits

..

10 Commits

Author SHA1 Message Date
1c08d48861 doc: Add ARP layer to README 2022-10-30 17:38:29 +01:00
ccb7d6c0da Fix linter warnings 2022-10-30 17:29:14 +01:00
8d9ca9e784 arp: Rename timeout_tick to systick 2022-10-30 17:27:43 +01:00
3240f363ba arp: Reformat code 2022-10-29 19:19:16 +02:00
a5d5ca280d arp: Add timeout 2022-10-29 19:18:51 +02:00
651b6bb11e bench: Test ARP requests in HWITL 2022-10-28 18:55:04 +02:00
4804674d8e arp: Implement ARP requests
This is still missing timeout in case of no reply.
This needs to be added!
2022-10-28 18:52:17 +02:00
1a41120afa bench: Clarify HWITL interface creation for local testing 2022-10-27 17:02:53 +02:00
5f7704cf63 pkg: Implement to_string functions for MAC and IP addresses 2022-05-15 14:51:52 +02:00
5f389b0c7b arp: Implement ARP replies 2022-05-15 14:51:49 +02:00
9 changed files with 440 additions and 25 deletions

View File

@ -5,7 +5,7 @@
Trashernet is a very trashy Ethernet stack for FPGAs written in VHDL aiming to cover all OSI layers: Trashernet is a very trashy Ethernet stack for FPGAs written in VHDL aiming to cover all OSI layers:
* Layer 1, Physical: `trashernet_phy` * Layer 1, Physical: `trashernet_phy`
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth` * Layer 2, Data link: `trashernet_mac`, `trashernet_eth`, `trashernet_arp`
When writing it, the following were the main design philosophies: When writing it, the following were the main design philosophies:

View File

@ -72,6 +72,19 @@ begin
tx_n => open tx_n => open
); );
test_seq : process is
begin
wait until bench_ready = '1';
button_n <= (others => '1'); button_n <= (others => '1');
wait for 1 us;
wait until rising_edge(clk);
button_n(0) <= '0';
wait until rising_edge(clk);
button_n(0) <= '1';
wait;
end process test_seq;
end architecture bench; end architecture bench;

View File

@ -17,9 +17,11 @@ import zlib
''' '''
# Set up virtual device using # Set up virtual device using
sudo ip link add virt0 type dummy sudo ip link add dev veth1 type veth peer name veth2
sudo ip link set up virt0 sudo ip link set up veth1
sudo ip addr add 192.168.2.10/24 dev virt0 sudo ip link set up veth2
sudo ip addr add 192.168.2.1/24 dev veth1
sudo ip link set promisc on dev veth1
''' '''
class MacDevReceiver(): class MacDevReceiver():
@ -30,9 +32,6 @@ class MacDevReceiver():
self.dev = dev self.dev = dev
self.mac_rx_ev = Event() self.mac_rx_ev = Event()
print("Setting IF to promisc mode...")
os.system("ip link set promisc on dev {}".format(dev))
ETH_P_ALL=3 ETH_P_ALL=3
self.macdev=socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL)) self.macdev=socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
self.macdev.bind((dev, 0)) self.macdev.bind((dev, 0))
@ -83,7 +82,7 @@ async def hwitl(dut):
await eth_rx.start() await eth_rx.start()
# Start local monitors # Start local monitors
macdev_receiver = MacDevReceiver(dut, eth_tx, eth_rx, "virt0") macdev_receiver = MacDevReceiver(dut, eth_tx, eth_rx, "veth2")
# Wait for VHDL part to be ready # Wait for VHDL part to be ready
await Edge(dut.bench_ready) await Edge(dut.bench_ready)

View File

@ -26,9 +26,9 @@ entity top_hwitl is
rx_p : in std_logic; rx_p : in std_logic;
tx_p : out std_logic; tx_p : out std_logic;
tx_n : out std_logic; tx_n : out std_logic;
led_n : out std_logic_vector(7 downto 0); led_n : out std_logic_vector(7 downto 0); -- @suppress: Used in different architectures
button_n : in std_logic_vector(3 downto 0); button_n : in std_logic_vector(3 downto 0); -- @suppress: Used in different architectures
debug_data : out std_logic_vector(7 downto 0) debug_data : out std_logic_vector(7 downto 0) -- @suppress: Used in different architectures
); );
end entity top_hwitl; end entity top_hwitl;
@ -50,7 +50,6 @@ architecture mac of top_hwitl is
signal rst : std_logic; signal rst : std_logic;
signal clk_phy : std_logic; signal clk_phy : std_logic;
signal phy_pll_lock : std_logic;
signal phy_out : phy_out_t; signal phy_out : phy_out_t;
signal phy_in : phy_in_t; signal phy_in : phy_in_t;
@ -80,7 +79,7 @@ begin
port map( port map(
CLK => clk, CLK => clk,
CLKOP => clk_phy, CLKOP => clk_phy,
LOCK => phy_pll_lock LOCK => open
); );
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
@ -186,10 +185,12 @@ architecture eth of top_hwitl is
constant ETH_CONFIG : configuration_t := ( constant ETH_CONFIG : configuration_t := (
mac_address => (x"00", x"ff", x"ff", x"11", x"22", x"33") 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 rst : std_logic;
signal clk_phy : std_logic; signal clk_phy : std_logic;
signal phy_pll_lock : std_logic;
signal phy_out : phy_out_t; signal phy_out : phy_out_t;
signal phy_in : phy_in_t; signal phy_in : phy_in_t;
@ -199,12 +200,41 @@ architecture eth of top_hwitl is
constant PROT_ARP : integer := 0; constant PROT_ARP : integer := 0;
constant PROT_IP : integer := 1; 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_out : ethernet_i_out_t;
signal ethernet_i_in : ethernet_i_in_t; signal ethernet_i_in : ethernet_i_in_t;
signal ethernet_ii_out : ethernet_ii_out_vector(ETHERNET_II_PROTOCOLS'range); 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 ethernet_ii_in : ethernet_ii_in_vector(ETHERNET_II_PROTOCOLS'range);
signal arp_out : arp_out_t;
signal arp_in : arp_in_t;
begin begin
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 trashernet_eth_inst : entity trashernet.trashernet_eth
generic map( generic map(
ETHERNET_II_PROTOCOLS => ETHERNET_II_PROTOCOLS ETHERNET_II_PROTOCOLS => ETHERNET_II_PROTOCOLS
@ -235,7 +265,7 @@ begin
port map( port map(
CLK => clk, CLK => clk,
CLKOP => clk_phy, CLKOP => clk_phy,
LOCK => phy_pll_lock LOCK => open
); );
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
@ -280,4 +310,22 @@ begin
end if; end if;
end process receiver; 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; end architecture eth;

View File

@ -0,0 +1,317 @@
-- -------------------------------------------------------------------------- --
-- 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
generic(
SYSTICK_FREQ : integer
);
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
systick : in std_logic; -- Global time reference for slow events (here: timeout)
-- 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");
constant ARP_TIMEOUT : time := 1 sec;
signal arp_tx_reply_rq : std_logic; -- Request to transmit an ARP reply
signal arp_tx_reply_tha : mac_addr_t; -- Target MAC to use in reply (SHA in received packet)
signal arp_tx_reply_tpa : ip_addr_t; -- Target IP to use in reply (SPA in received packet)
signal arp_tx_reply_ack : std_logic; -- ARP reply has been latched and is being sent
signal arp_tx_request_rq : std_logic; -- Request to transmit an ARP request
signal arp_tx_request_tpa : ip_addr_t; -- IP address that we want to know the MAC address of
signal arp_tx_request_ack : std_logic; -- ARP request has been latched and is being sent
signal arp_rx_reply_stb : std_logic; -- An ARP reply was received (strobe)
signal arp_rx_sha : mac_addr_t; -- The MAC address of the reply sender, valid with arp_rx_reply
signal arp_rx_spa : ip_addr_t; -- The IP address of the reply sender, valid with arp_rx_reply
begin
resolver : block
type resolver_state_t is (IDLE, QUERY_MAC);
signal state : resolver_state_t;
signal query_mac_found : std_logic;
signal query_timeout : std_logic := '0'; -- TODO: Implement
signal replied_ip : ip_addr_t;
signal replied_mac : mac_addr_t;
begin
arp_resolver_main : process(rst, clk) is
begin
if rst then
state <= IDLE;
replied_ip <= (others => x"00"); -- 0.0.0.0
arp_out.arp_ok_stb <= '0';
arp_out.arp_fail_stb <= '0';
arp_tx_request_rq <= '0';
elsif rising_edge(clk) then
arp_out.arp_ok_stb <= '0';
arp_out.arp_fail_stb <= '0';
if arp_rx_reply_stb then
if arp_tx_request_tpa = arp_rx_spa then -- If this reply is actually for our request
replied_mac <= arp_rx_sha;
replied_ip <= arp_rx_spa;
end if;
end if;
case state is
when IDLE =>
if arp_in.arp_query_stb then
if query_mac_found then
arp_out.arp_ok_stb <= '1';
else
arp_tx_request_rq <= '1';
state <= QUERY_MAC;
end if;
end if;
when QUERY_MAC =>
if arp_tx_request_ack then
arp_tx_request_rq <= '0';
end if;
if query_mac_found or query_timeout then
arp_out.arp_ok_stb <= query_mac_found;
arp_out.arp_fail_stb <= not query_mac_found;
state <= IDLE;
end if;
end case;
end if;
end process arp_resolver_main;
query_mac_found <= '1' when (arp_tx_request_tpa = replied_ip) else '0';
arp_out.arp_mac <= replied_mac;
arp_tx_request_tpa <= arp_in.arp_ip;
timeout_timer_inst : entity work.timer
generic map(
F_TICK => SYSTICK_FREQ,
DURATION => ARP_TIMEOUT,
AUTOSTART => false
)
port map(
clk => clk,
rst => rst,
tick => systick,
start => arp_tx_request_rq,
expired => query_timeout,
expired_stb => open
);
end block resolver;
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); -- @suppress "Unused declaration": We don't need to check this as this is already done by the MAC
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;
arp_rx_reply_stb <= '0';
elsif rising_edge(clk) then
arp_rx_reply_stb <= '0';
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
arp_rx_reply_stb <= '1';
end if;
end if;
when SENDREPLY =>
if arp_tx_reply_ack then
bytecount <= BYTECOUNT_HEAD;
state <= HEAD;
end if;
when IGNORE => -- @suppress "Dead state 'IGNORE'": Outgoing transition provided outside of case statement (on RX ok/err)
null;
end case;
end if;
end process rx_fsm;
arp_tx_reply_rq <= '1' when state = SENDREPLY else '0';
arp_tx_reply_tha <= sr_addresses_sha;
arp_tx_reply_tpa <= sr_addresses_spa;
arp_rx_sha <= sr_addresses_sha;
arp_rx_spa <= sr_addresses_spa;
end block rx;
tx : block
signal sr : byte_vector(0 to 27);
signal arp_reply_preload : byte_vector(sr'range);
signal arp_request_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_tx_reply_tha & arp_tx_reply_tpa; -- Target
arp_request_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REQUEST & -- Header
mac_config.mac_address & ip_config.ip_address & -- Sender
mac_addr_t'(x"00", x"00", x"00", x"00", x"00", x"00") & arp_tx_request_tpa; -- Target
tx_fsm : process(clk, rst) is
begin
if rst then
arp_tx_reply_ack <= '0';
arp_tx_request_ack <= '0';
elsif rising_edge(clk) then
arp_tx_reply_ack <= '0';
arp_tx_request_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_tx_reply_rq then
state <= TRANSMIT;
arp_tx_reply_ack <= '1';
sr <= arp_reply_preload;
ethernet_ii_in.tx_mac_address <= arp_tx_reply_tha;
elsif arp_tx_request_rq then
state <= TRANSMIT;
arp_tx_request_ack <= '1';
sr <= arp_request_preload;
ethernet_ii_in.tx_mac_address <= MAC_ADDR_BROADCAST;
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_en <= '1' when state = TRANSMIT else '0';
ethernet_ii_in.tx_data <= sr(0);
end block tx;
end architecture rtl;

View File

@ -54,7 +54,7 @@ begin
begin begin
mac_destination_matches <= '1' when -- mac_destination_matches <= '1' when --
((mac_out.rx_header.mac_destination = (x"FF", x"FF", x"FF", x"FF", x"FF", x"FF")) or -- ((mac_out.rx_header.mac_destination = MAC_ADDR_BROADCAST) or --
(mac_out.rx_header.mac_destination = config.mac_address)) else (mac_out.rx_header.mac_destination = config.mac_address)) else
'0'; '0';

View File

@ -102,7 +102,7 @@ begin
byte_count <= byte_count + 1; byte_count <= byte_count + 1;
end if; end if;
end if; end if;
when PAYLOAD => when PAYLOAD => -- @suppress "Dead state 'PAYLOAD'": Outgoing transition provided outside of case statement (RX disabled or error)
if phy_out.rx_data_valid then if phy_out.rx_data_valid then
sr_payload <= sr_payload(sr_payload'low + 1 to sr_payload'high) & phy_out.rx_data; sr_payload <= sr_payload(sr_payload'low + 1 to sr_payload'high) & phy_out.rx_data;
if byte_count = CRC_LENGTH then if byte_count = CRC_LENGTH then

View File

@ -47,6 +47,8 @@ architecture rtl of trashernet_phy_cdc is
signal rx_data_valid_i : std_logic; signal rx_data_valid_i : std_logic;
begin begin
assert F_CLK_PHY > 2 * F_CLK report "F_CLK_PHY must be at least 2x F_CLK" severity failure;
-- ------------------------------------------------------------------------- -- -------------------------------------------------------------------------
-- Drives: PHY clock domain -- Drives: PHY clock domain
-- ------------------------------------------------------------------------- -- -------------------------------------------------------------------------

View File

@ -19,6 +19,8 @@ package trashernet_pkg is
-- MAC specific types -- MAC specific types
subtype mac_addr_t is byte_vector(0 to 5); subtype mac_addr_t is byte_vector(0 to 5);
constant MAC_ADDR_BROADCAST : mac_addr_t := (others => x"FF");
function mac_to_string(constant mac_address : in mac_addr_t) return string;
subtype ethertype_t is byte_vector(0 to 1); subtype ethertype_t is byte_vector(0 to 1);
type mac_header_fields is record type mac_header_fields is record
@ -29,11 +31,15 @@ package trashernet_pkg is
-- IP specific types -- IP specific types
subtype ip_addr_t is byte_vector(0 to 3); subtype ip_addr_t is byte_vector(0 to 3);
function ip_to_string(constant ip_address : in ip_addr_t) return string;
-- Configuration interface -- Configuration interface
type configuration_t is record type configuration_t is record
mac_address : mac_addr_t; -- MAC address of this node mac_address : mac_addr_t; -- MAC address of this node
end record configuration_t; 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 -- PHY interface
type phy_in_t is record type phy_in_t is record
@ -76,7 +82,7 @@ package trashernet_pkg is
ethertype : ethertype_t; ethertype : ethertype_t;
end record; end record;
type ethernet_ii_protocol_vector is array (natural range <>) of ethernet_ii_protocol_t; type ethernet_ii_protocol_vector is array (natural range <>) of ethernet_ii_protocol_t;
constant ETHERNET_II_PROTOCOLS_NONE : ethernet_ii_protocol_vector(0 to -1) := (others => (ethertype => (x"00", x"00"))); -- NULL range constant ETHERNET_II_PROTOCOLS_NONE : ethernet_ii_protocol_vector(0 to -1) := (others => (ethertype => (x"00", x"00"))); -- @suppress "Null range": We want a NULL vector here to remove the logic
constant ETHERNET_II_PROTOCOL_IP : ethernet_ii_protocol_t := (ethertype => (x"08", x"00")); constant ETHERNET_II_PROTOCOL_IP : ethernet_ii_protocol_t := (ethertype => (x"08", x"00"));
constant ETHERNET_II_PROTOCOL_ARP : ethernet_ii_protocol_t := (ethertype => (x"08", x"06")); constant ETHERNET_II_PROTOCOL_ARP : ethernet_ii_protocol_t := (ethertype => (x"08", x"06"));
@ -116,8 +122,38 @@ package trashernet_pkg is
type ethernet_ii_out_vector is array (natural range <>) of ethernet_ii_out_t; type ethernet_ii_out_vector is array (natural range <>) of ethernet_ii_out_t;
type ethernet_ii_in_vector is array (natural range <>) of ethernet_ii_in_t; type ethernet_ii_in_vector is array (natural range <>) of ethernet_ii_in_t;
constant ETHERNET_II_IN_UNUSED : ethernet_ii_in_t := (tx_mac_address => (others => x"00"), tx_data => x"00", others => '0'); constant ETHERNET_II_IN_UNUSED : ethernet_ii_in_t := (tx_mac_address => (others => x"00"), tx_data => x"00", others => '0');
type arp_out_t is record
arp_mac : mac_addr_t; -- Resulting MAC address for query
arp_ok_stb : std_logic; -- ARP request successful, `arp_mac` valid
arp_fail_stb : std_logic; -- ARP request failed, `arp_mac` invalid
end record arp_out_t;
type arp_in_t is record
arp_ip : ip_addr_t; -- IP address to query
arp_query_stb : std_logic; -- Request MAC for IP
end record arp_in_t;
end package trashernet_pkg; end package trashernet_pkg;
package body trashernet_pkg is package body trashernet_pkg is
function mac_to_string(constant mac_address : in mac_addr_t) return string is
begin
return --
to_hstring(mac_address(0)) & ":" & --
to_hstring(mac_address(1)) & ":" & --
to_hstring(mac_address(2)) & ":" & --
to_hstring(mac_address(3)) & ":" & --
to_hstring(mac_address(4)) & ":" & --
to_hstring(mac_address(5)) --
;
end function mac_to_string;
function ip_to_string(constant ip_address : in ip_addr_t) return string is
begin
return --
to_string(to_integer(unsigned(ip_address(0)))) & "." & --
to_string(to_integer(unsigned(ip_address(1)))) & "." & --
to_string(to_integer(unsigned(ip_address(2)))) & "." & --
to_string(to_integer(unsigned(ip_address(3)))) --
;
end function ip_to_string;
end package body trashernet_pkg; end package body trashernet_pkg;