Compare commits
No commits in common. "1c08d488610796795972eef988192da244d8ad64" and "7bb82a9acf9e0fd51d0ed8d99c38309d1ac24e1f" have entirely different histories.
1c08d48861
...
7bb82a9acf
@ -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`, `trashernet_arp`
|
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth`
|
||||||
|
|
||||||
When writing it, the following were the main design philosophies:
|
When writing it, the following were the main design philosophies:
|
||||||
|
|
||||||
|
@ -72,19 +72,6 @@ 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;
|
||||||
|
@ -17,11 +17,9 @@ import zlib
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
# Set up virtual device using
|
# Set up virtual device using
|
||||||
sudo ip link add dev veth1 type veth peer name veth2
|
sudo ip link add virt0 type dummy
|
||||||
sudo ip link set up veth1
|
sudo ip link set up virt0
|
||||||
sudo ip link set up veth2
|
sudo ip addr add 192.168.2.10/24 dev virt0
|
||||||
sudo ip addr add 192.168.2.1/24 dev veth1
|
|
||||||
sudo ip link set promisc on dev veth1
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
class MacDevReceiver():
|
class MacDevReceiver():
|
||||||
@ -32,6 +30,9 @@ 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))
|
||||||
@ -82,7 +83,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, "veth2")
|
macdev_receiver = MacDevReceiver(dut, eth_tx, eth_rx, "virt0")
|
||||||
|
|
||||||
# Wait for VHDL part to be ready
|
# Wait for VHDL part to be ready
|
||||||
await Edge(dut.bench_ready)
|
await Edge(dut.bench_ready)
|
||||||
|
@ -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); -- @suppress: Used in different architectures
|
led_n : out std_logic_vector(7 downto 0);
|
||||||
button_n : in std_logic_vector(3 downto 0); -- @suppress: Used in different architectures
|
button_n : in std_logic_vector(3 downto 0);
|
||||||
debug_data : out std_logic_vector(7 downto 0) -- @suppress: Used in different architectures
|
debug_data : out std_logic_vector(7 downto 0)
|
||||||
);
|
);
|
||||||
end entity top_hwitl;
|
end entity top_hwitl;
|
||||||
|
|
||||||
@ -50,6 +50,7 @@ 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;
|
||||||
@ -79,7 +80,7 @@ begin
|
|||||||
port map(
|
port map(
|
||||||
CLK => clk,
|
CLK => clk,
|
||||||
CLKOP => clk_phy,
|
CLKOP => clk_phy,
|
||||||
LOCK => open
|
LOCK => phy_pll_lock
|
||||||
);
|
);
|
||||||
|
|
||||||
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
|
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
|
||||||
@ -185,12 +186,10 @@ 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;
|
||||||
@ -200,41 +199,12 @@ 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 := (
|
constant ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := (PROT_ARP => ETHERNET_II_PROTOCOL_ARP, PROT_IP => ETHERNET_II_PROTOCOL_IP);
|
||||||
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
|
||||||
@ -265,7 +235,7 @@ begin
|
|||||||
port map(
|
port map(
|
||||||
CLK => clk,
|
CLK => clk,
|
||||||
CLKOP => clk_phy,
|
CLKOP => clk_phy,
|
||||||
LOCK => open
|
LOCK => phy_pll_lock
|
||||||
);
|
);
|
||||||
|
|
||||||
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
|
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
|
||||||
@ -310,22 +280,4 @@ 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;
|
||||||
|
@ -1,317 +0,0 @@
|
|||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- 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;
|
|
@ -54,7 +54,7 @@ begin
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
mac_destination_matches <= '1' when --
|
mac_destination_matches <= '1' when --
|
||||||
((mac_out.rx_header.mac_destination = MAC_ADDR_BROADCAST) or --
|
((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 = config.mac_address)) else
|
(mac_out.rx_header.mac_destination = config.mac_address)) else
|
||||||
'0';
|
'0';
|
||||||
|
|
||||||
|
@ -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 => -- @suppress "Dead state 'PAYLOAD'": Outgoing transition provided outside of case statement (RX disabled or error)
|
when PAYLOAD =>
|
||||||
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
|
||||||
|
@ -47,8 +47,6 @@ 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
|
||||||
-- -------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------
|
||||||
|
@ -19,8 +19,6 @@ 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
|
||||||
@ -31,15 +29,11 @@ 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
|
||||||
@ -82,7 +76,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"))); -- @suppress "Null range": We want a NULL vector here to remove the logic
|
constant ETHERNET_II_PROTOCOLS_NONE : ethernet_ii_protocol_vector(0 to -1) := (others => (ethertype => (x"00", x"00"))); -- NULL range
|
||||||
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"));
|
||||||
|
|
||||||
@ -122,38 +116,8 @@ 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;
|
||||||
|
Loading…
Reference in New Issue
Block a user