From 3e1a53abafaeaee2e9e2489802fd743787eef92c Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Thu, 11 Sep 2025 13:00:09 +0200 Subject: [PATCH] Move header fields into records --- design/top_hwitl.vhd | 8 +- trashernet/trashernet_eth.vhd | 26 ++--- trashernet/trashernet_icmp.vhd | 4 +- trashernet/trashernet_ipv4.vhd | 11 +- trashernet/trashernet_ipv4prot.vhd | 5 +- trashernet/trashernet_pkg.vhd | 164 ++++++++++++++++++----------- trashernet/trashernet_udp.vhd | 7 +- 7 files changed, 134 insertions(+), 91 deletions(-) diff --git a/design/top_hwitl.vhd b/design/top_hwitl.vhd index 23f38b5..4c6fe15 100644 --- a/design/top_hwitl.vhd +++ b/design/top_hwitl.vhd @@ -360,7 +360,7 @@ begin elsif rising_edge(clk) then if ethernet_i_out.rx_header_rcv then - report "RX ETH-I: " & to_string(to_integer(ethernet_i_out.rx_length)); + report "RX ETH-I: " & to_string(to_integer(ethernet_i_out.rx_header.length)); end if; if (ethernet_ii_out(PROT_ARP).rx_header_rcv) then report "RX ARP"; @@ -373,7 +373,7 @@ begin report "RX IP error"; end if; if ipv4_out.rx_header_rcv then - report "RX IP start. PROT=" & to_hstring(ipv4_out.rx_protocol) & ", FROM=" & ip_to_string(ipv4_out.rx_ip_address); + report "RX IP start. PROT=" & to_hstring(ipv4_out.rx_header.protocol) & ", FROM=" & ip_to_string(ipv4_out.rx_header.ip_address); end if; end if; end process receiver; @@ -455,8 +455,8 @@ begin elsif rising_edge(clk) then if udp_out.rx_header_rcv then report "UDP: RX on port " & -- - to_string(to_integer(udp_out.rx_destination_port)) & " from port " & -- - to_string(to_integer(udp_out.rx_source_port)); + to_string(to_integer(udp_out.rx_header.destination_port)) & " from port " & -- + to_string(to_integer(udp_out.rx_header.source_port)); end if; if udp_out.rx_data_valid then report "UDP: RX: " & to_hstring(udp_out.rx_data); diff --git a/trashernet/trashernet_eth.vhd b/trashernet/trashernet_eth.vhd index 539cae9..cf90d57 100644 --- a/trashernet/trashernet_eth.vhd +++ b/trashernet/trashernet_eth.vhd @@ -87,22 +87,22 @@ begin -- Shared fields in the Ethernet II application interface shared_fields : for i in ethernet_ii_out'range generate - ethernet_ii_out(i).rx_mac_address <= mac_out.rx_header.mac_source; - ethernet_ii_out(i).rx_data <= mac_out.rx_mac_data; - ethernet_ii_out(i).rx_data_valid <= mac_out.rx_mac_valid when sel = i else '0'; - ethernet_ii_out(i).rx_crc_error <= mac_out.rx_mac_crc_error when sel = i else '0'; - ethernet_ii_out(i).rx_crc_ok <= mac_out.rx_mac_crc_ok when sel = i else '0'; - ethernet_ii_out(i).rx_header_rcv <= rx_mac_header_rcv_delayed when sel = i else '0'; + ethernet_ii_out(i).rx_header.mac_header <= mac_out.rx_header; + ethernet_ii_out(i).rx_data <= mac_out.rx_mac_data; + ethernet_ii_out(i).rx_data_valid <= mac_out.rx_mac_valid when sel = i else '0'; + ethernet_ii_out(i).rx_crc_error <= mac_out.rx_mac_crc_error when sel = i else '0'; + ethernet_ii_out(i).rx_crc_ok <= mac_out.rx_mac_crc_ok when sel = i else '0'; + ethernet_ii_out(i).rx_header_rcv <= rx_mac_header_rcv_delayed when sel = i else '0'; end generate shared_fields; -- Shared fields in the Ethernet application interface - ethernet_i_out.rx_data <= mac_out.rx_mac_data; - ethernet_i_out.rx_data_valid <= mac_out.rx_mac_valid when sel = SEL_ETH_I; - ethernet_i_out.rx_crc_error <= mac_out.rx_mac_crc_error when sel = SEL_ETH_I else '0'; - ethernet_i_out.rx_crc_ok <= mac_out.rx_mac_crc_ok when sel = SEL_ETH_I else '0'; - ethernet_i_out.rx_header_rcv <= rx_mac_header_rcv_delayed when sel = SEL_ETH_I else '0'; - ethernet_i_out.rx_mac_address <= mac_out.rx_header.mac_source; - ethernet_i_out.rx_length <= unsigned(mac_out.rx_header.mac_ethertype(0)) & unsigned(mac_out.rx_header.mac_ethertype(1)); + ethernet_i_out.rx_data <= mac_out.rx_mac_data; + ethernet_i_out.rx_data_valid <= mac_out.rx_mac_valid when sel = SEL_ETH_I; + ethernet_i_out.rx_crc_error <= mac_out.rx_mac_crc_error when sel = SEL_ETH_I else '0'; + ethernet_i_out.rx_crc_ok <= mac_out.rx_mac_crc_ok when sel = SEL_ETH_I else '0'; + ethernet_i_out.rx_header_rcv <= rx_mac_header_rcv_delayed when sel = SEL_ETH_I else '0'; + ethernet_i_out.rx_header.mac_header <= mac_out.rx_header; + ethernet_i_out.rx_header.length <= unsigned(mac_out.rx_header.mac_ethertype(0)) & unsigned(mac_out.rx_header.mac_ethertype(1)); -- TX fields (need to be driven here to avoid multiple drivers (blocks drive ALL signals of a record)) tx_fields : for i in ethernet_ii_out'range generate diff --git a/trashernet/trashernet_icmp.vhd b/trashernet/trashernet_icmp.vhd index be883d4..4e98e99 100644 --- a/trashernet/trashernet_icmp.vhd +++ b/trashernet/trashernet_icmp.vhd @@ -140,8 +140,8 @@ begin case state is when IDLE => if tx_response then - ipv4_protocol_in.tx_ip_address <= ipv4_protocol_out.rx_ip_address; -- TODO: This is technically too late, but ¯\_(ツ)_/¯ - ipv4_protocol_in.tx_length <= ipv4_protocol_out.rx_length; + ipv4_protocol_in.tx_ip_address <= ipv4_protocol_out.rx_header.ip_address; -- TODO: This is technically too late, but ¯\_(ツ)_/¯ + ipv4_protocol_in.tx_length <= ipv4_protocol_out.rx_header.length; sr <= byte_vector'( x"00", x"00", diff --git a/trashernet/trashernet_ipv4.vhd b/trashernet/trashernet_ipv4.vhd index 291df5c..6e2b584 100644 --- a/trashernet/trashernet_ipv4.vhd +++ b/trashernet/trashernet_ipv4.vhd @@ -129,11 +129,12 @@ begin end if; end process rx_fsm; - ipv4_out.rx_data <= ethernet_ii_out.rx_data; - ipv4_out.rx_data_valid <= ethernet_ii_out.rx_data_valid when state = PAYLOAD else '0'; - ipv4_out.rx_ip_address <= sr_source_ip; - ipv4_out.rx_protocol <= sr_protocol; - ipv4_out.rx_length <= unsigned(std_logic_vector'(sr_total_length(2) & sr_total_length(3))) - to_integer(unsigned(sr_ihl)) * 4; + ipv4_out.rx_data <= ethernet_ii_out.rx_data; + ipv4_out.rx_data_valid <= ethernet_ii_out.rx_data_valid when state = PAYLOAD else '0'; + ipv4_out.rx_header.eth_header <= ethernet_ii_out.rx_header; + ipv4_out.rx_header.ip_address <= sr_source_ip; + ipv4_out.rx_header.protocol <= sr_protocol; + ipv4_out.rx_header.length <= unsigned(std_logic_vector'(sr_total_length(2) & sr_total_length(3))) - to_integer(unsigned(sr_ihl)) * 4; end block rx; diff --git a/trashernet/trashernet_ipv4prot.vhd b/trashernet/trashernet_ipv4prot.vhd index adf2b8a..25d4005 100644 --- a/trashernet/trashernet_ipv4prot.vhd +++ b/trashernet/trashernet_ipv4prot.vhd @@ -57,7 +57,7 @@ begin if ipv4_out.rx_header_rcv then rx_sel <= SEL_PROTOCOL_NONE; for i in IPV4_PROTOCOLS'range loop - if (ipv4_out.rx_protocol = IPV4_PROTOCOLS(i)) then + if (ipv4_out.rx_header.protocol = IPV4_PROTOCOLS(i)) then rx_sel <= i; end if; end loop; @@ -67,8 +67,7 @@ begin mux : for i in ipv4_protocol_out'range generate ipv4_protocol_out(i).rx_data <= ipv4_out.rx_data; - ipv4_protocol_out(i).rx_ip_address <= ipv4_out.rx_ip_address; - ipv4_protocol_out(i).rx_length <= ipv4_out.rx_length; + ipv4_protocol_out(i).rx_header <= ipv4_out.rx_header; ipv4_protocol_out(i).rx_data_valid <= ipv4_out.rx_data_valid when rx_sel = i else '0'; ipv4_protocol_out(i).rx_error_stb <= ipv4_out.rx_error_stb when rx_sel = i else '0'; ipv4_protocol_out(i).rx_ok_stb <= ipv4_out.rx_ok_stb when rx_sel = i else '0'; diff --git a/trashernet/trashernet_pkg.vhd b/trashernet/trashernet_pkg.vhd index f2d1d0f..5b037a1 100644 --- a/trashernet/trashernet_pkg.vhd +++ b/trashernet/trashernet_pkg.vhd @@ -13,6 +13,10 @@ use ieee.std_logic_1164.all; use ieee.numeric_std.all; package trashernet_pkg is + -- ---------------- + -- Type definitions + -- ---------------- + -- General types subtype byte is std_logic_vector(7 downto 0); type byte_vector is array (natural range <>) of byte; @@ -23,18 +27,56 @@ package trashernet_pkg is function mac_to_string(constant mac_address : in mac_addr_t) return string; subtype ethertype_t is byte_vector(0 to 1); - type mac_header_fields is record + type mac_header_t is record mac_destination : mac_addr_t; -- Destination MAC address mac_source : mac_addr_t; -- Source MAC address mac_ethertype : ethertype_t; -- Ethertype or length - end record mac_header_fields; + end record mac_header_t; + + -- Ethernet specific types + type ethernet_i_header_t is record + mac_header : mac_header_t; -- MAC layer header + length : unsigned(15 downto 0); -- RX payload length in bytes + end record; + + type ethernet_ii_header_t is record + mac_header : mac_header_t; -- MAC layer header + end record; -- IP specific types subtype ip_addr_t is byte_vector(0 to 3); function ip_to_string(constant ip_address : in ip_addr_t) return string; function to_std_logic_vector(ip_address : ip_addr_t) return std_logic_vector; - -- Configuration interface + subtype ipv4_protocol is byte; + type ipv4_protocol_vector is array (natural range <>) of ipv4_protocol; + constant IPV4_PROTOCOL_ICMP : ipv4_protocol := x"01"; + constant IPV4_PROTOCOL_TCP : ipv4_protocol := x"06"; + constant IPV4_PROTOCOL_UDP : ipv4_protocol := x"11"; + subtype ipv4_length is unsigned(15 downto 0); + + type ipv4_header_t is record + ip_address : ip_addr_t; -- Source IP address + protocol : ipv4_protocol; -- Transport Protocol + length : ipv4_length; -- Telegram length (excluding header) + eth_header : ethernet_ii_header_t; -- Eth II header + end record ipv4_header_t; + + -- UDP specific types + subtype udp_port_t is unsigned(15 downto 0); + subtype udp_length_t is unsigned(15 downto 0); + type udp_header_t is record + source_port : udp_port_t; -- UDP source port + destination_port : udp_port_t; -- UDP destination port + length : udp_length_t; -- UDP length + ipv4_header : ipv4_header_t; -- IPv4 header + end record; + + -- ------------------------ + -- Configuration interfaces + -- ------------------------ + + -- System configuration type configuration_t is record mac_address : mac_addr_t; -- MAC address of this node end record configuration_t; @@ -44,6 +86,19 @@ package trashernet_pkg is subnet_mask : ip_addr_t; -- Subnet mask of this node end record ipv4_configuration_t; + -- MAC ETH interface + type ethernet_ii_protocol_t is record + ethertype : ethertype_t; + end record; + 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_PROTOCOL_IPV4 : ethernet_ii_protocol_t := (ethertype => (x"08", x"00")); + constant ETHERNET_II_PROTOCOL_ARP : ethernet_ii_protocol_t := (ethertype => (x"08", x"06")); + + -- ---------------------- + -- Application interfaces + -- ---------------------- + -- PHY interface type phy_in_t is record tx_data : byte; -- TX Data @@ -63,12 +118,12 @@ package trashernet_pkg is -- MAC interface type mac_in_t is record - tx_header : mac_header_fields; -- TX MAC Header Data + tx_header : mac_header_t; -- TX MAC Header Data tx_mac_data : byte; -- Payload tx_mac_data_en : std_logic; -- Start (and keep) transmitting a frame end record mac_in_t; type mac_out_t is record - rx_header : mac_header_fields; -- RX MAC Header Data + rx_header : mac_header_t; -- RX MAC Header Data rx_mac_header_rcv : std_logic; -- `rx_mac` header have been received and are valid rx_mac_data : byte; -- Ethernet data (after Ethertype) @@ -80,25 +135,18 @@ package trashernet_pkg is rx_mac_crc_error : std_logic; -- End of packet, CRC invalid end record mac_out_t; - -- MAC ETH interface - type ethernet_ii_protocol_t is record - ethertype : ethertype_t; - end record; - 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_PROTOCOL_IPV4 : ethernet_ii_protocol_t := (ethertype => (x"08", x"00")); - constant ETHERNET_II_PROTOCOL_ARP : ethernet_ii_protocol_t := (ethertype => (x"08", x"06")); - + -- Ethernet I interface type ethernet_i_out_t is record - rx_mac_address : mac_addr_t; -- Source MAC address - rx_crc_ok : std_logic; -- End of packet, CRC OK - rx_crc_error : std_logic; -- End of packet, CRC invalid + rx_crc_ok : std_logic; -- End of packet, CRC OK + rx_crc_error : std_logic; -- End of packet, CRC invalid - rx_data : byte; -- RX data - rx_data_valid : std_logic; -- RX data valid strobe - rx_length : unsigned(15 downto 0); -- RX payload length in bytes - rx_header_rcv : std_logic; -- Start of reception, `rx_length` is valid - tx_data_ack : std_logic; -- Give next data byte or disable `tx_en` + rx_header : ethernet_i_header_t; + rx_header_rcv : std_logic; -- Start of reception, `header` is valid + + rx_data : byte; -- RX data + rx_data_valid : std_logic; -- RX data valid strobe + + tx_data_ack : std_logic; -- Give next data byte or disable `tx_en` end record; type ethernet_i_in_t is record tx_mac_address : mac_addr_t; -- Destination MAC address @@ -108,14 +156,18 @@ package trashernet_pkg is end record; constant ETHERNET_I_IN_UNUSED : ethernet_i_in_t := (tx_mac_address => (others => x"00"), tx_data => x"00", tx_length => x"0000", others => '0'); -- TODO + -- Ethernet II interface type ethernet_ii_out_t is record - rx_mac_address : mac_addr_t; -- Source MAC address - rx_data : byte; -- RX data - rx_data_valid : std_logic; -- RX data valid strobe - rx_crc_ok : std_logic; -- End of packet, CRC OK - rx_crc_error : std_logic; -- End of packet, CRC invalid - rx_header_rcv : std_logic; -- Start of reception - tx_data_ack : std_logic; -- Give next data byte or disable `tx_en` + rx_header : ethernet_ii_header_t; + rx_header_rcv : std_logic; -- Start of reception + + rx_crc_ok : std_logic; -- End of packet, CRC OK + rx_crc_error : std_logic; -- End of packet, CRC invalid + + rx_data : byte; -- RX data + rx_data_valid : std_logic; -- RX data valid strobe + + tx_data_ack : std_logic; -- Give next data byte or disable `tx_en` end record; type ethernet_ii_in_t is record tx_mac_address : mac_addr_t; -- Destination MAC address @@ -138,23 +190,15 @@ package trashernet_pkg is end record arp_in_t; -- IPv4 interface - subtype ipv4_protocol is byte; - type ipv4_protocol_vector is array (natural range <>) of ipv4_protocol; - constant IPV4_PROTOCOL_ICMP : ipv4_protocol := x"01"; - constant IPV4_PROTOCOL_TCP : ipv4_protocol := x"06"; - constant IPV4_PROTOCOL_UDP : ipv4_protocol := x"11"; - subtype ipv4_length is unsigned(15 downto 0); - type ipv4_out_t is record - rx_ip_address : ip_addr_t; -- Source IP address - rx_protocol : ipv4_protocol; -- Transport Protocol - rx_length : ipv4_length; -- Telegram length (excluding header) + rx_header : ipv4_header_t; + rx_header_rcv : std_logic; -- Start of reception (`rx_ip_address` and `rx_protocol` are valid) + + rx_ok_stb : std_logic; -- End of packet, checksum OK + rx_error_stb : std_logic; -- End of packet, checksum invalid rx_data : byte; -- RX data rx_data_valid : std_logic; -- RX data valid strobe - rx_ok_stb : std_logic; -- End of packet, checksum OK - rx_error_stb : std_logic; -- End of packet, checksum invalid - rx_header_rcv : std_logic; -- Start of reception (`rx_ip_address` and `rx_protocol` are valid) tx_data_ack : std_logic; -- Give next data byte of disable `tx_en` tx_ok_stb : std_logic; -- Transmission successful @@ -169,14 +213,14 @@ package trashernet_pkg is end record ipv4_in_t; type ipv4_protocol_out_t is record - rx_ip_address : ip_addr_t; -- Source IP address - rx_length : ipv4_length; -- Telegram length (excluding header) + rx_header : ipv4_header_t; + rx_header_rcv : std_logic; -- Start of reception + + rx_ok_stb : std_logic; -- End of packet, checksum OK + rx_error_stb : std_logic; -- End of packet, checksum invalid rx_data : byte; -- RX data rx_data_valid : std_logic; -- RX data valid strobe - rx_ok_stb : std_logic; -- End of packet, checksum OK - rx_error_stb : std_logic; -- End of packet, checksum invalid - rx_header_rcv : std_logic; -- Start of reception tx_data_ack : std_logic; -- Give next data byte of disable `tx_en` tx_ok_stb : std_logic; -- Transmission successful @@ -193,23 +237,19 @@ package trashernet_pkg is type ipv4_protocol_in_vector is array (natural range <>) of ipv4_protocol_in_t; -- UDP interface - subtype udp_port_t is unsigned(15 downto 0); - subtype udp_length_t is unsigned(15 downto 0); - type udp_out_t is record - rx_data : byte; -- RX Data - rx_data_valid : std_logic; -- RX data valid strobe + type udp_out_t is record + rx_data : byte; -- RX Data + rx_data_valid : std_logic; -- RX data valid strobe - rx_header_rcv : std_logic; -- Start of reception - rx_source_port : udp_port_t; -- UDP source port - rx_destination_port : udp_port_t; -- UDP destination port - rx_length : udp_length_t; -- UDP length + rx_header : udp_header_t; -- UDP header + rx_header_rcv : std_logic; -- Start of reception, `rx_header` valid - rx_ok_stb : std_logic; -- End of packet, checksum OK - rx_error_stb : std_logic; -- End of packet, checksum invalid + rx_ok_stb : std_logic; -- End of packet, checksum OK + rx_error_stb : std_logic; -- End of packet, checksum invalid - tx_data_ack : std_logic; -- Give next data byte or disable `tx_en` - tx_ok_stb : std_logic; -- Transmission successful - tx_err_stb : std_logic; -- Transmission failed + tx_data_ack : std_logic; -- Give next data byte or disable `tx_en` + tx_ok_stb : std_logic; -- Transmission successful + tx_err_stb : std_logic; -- Transmission failed end record udp_out_t; type udp_in_t is record tx_ip_address : ip_addr_t; -- Destination IP address @@ -236,7 +276,9 @@ package trashernet_pkg is subtype portnum is integer range 0 to 65535; type udp_port_vector is array (natural range <>) of portnum; + -- ------------------------ -- General helper functions + -- ------------------------ function to_std_logic(constant bool : boolean) return std_logic; end package trashernet_pkg; diff --git a/trashernet/trashernet_udp.vhd b/trashernet/trashernet_udp.vhd index f5e7cc1..4633749 100644 --- a/trashernet/trashernet_udp.vhd +++ b/trashernet/trashernet_udp.vhd @@ -90,9 +90,10 @@ begin end if; end process rxp; - udp_out.rx_source_port <= unsigned(std_logic_vector'(sr_source_port(0) & sr_source_port(1))); - udp_out.rx_destination_port <= unsigned(std_logic_vector'(sr_destination_port(2) & sr_destination_port(3))); - udp_out.rx_length <= unsigned(std_logic_vector'(sr_length(4) & sr_length(5))); + udp_out.rx_header.source_port <= unsigned(std_logic_vector'(sr_source_port(0) & sr_source_port(1))); + udp_out.rx_header.destination_port <= unsigned(std_logic_vector'(sr_destination_port(2) & sr_destination_port(3))); + udp_out.rx_header.length <= unsigned(std_logic_vector'(sr_length(4) & sr_length(5))); + udp_out.rx_header.ipv4_header <= ipv4_protocol_out.rx_header; end block receiver; transmitter : block