udp: Add UDP decoder

This commit is contained in:
Markus Koch 2025-09-02 09:35:14 +02:00
parent 02a00e875d
commit 154604aacd
3 changed files with 249 additions and 13 deletions

View File

@ -225,7 +225,20 @@ architecture eth of top_hwitl is
);
signal ipv4_protocol_out : ipv4_protocol_out_vector(IPV4_PROTOCOLS'range);
signal ipv4_protocol_in : ipv4_protocol_in_vector(IPV4_PROTOCOLS'range);
signal udp_out : udp_out_t;
signal udp_in : udp_in_t;
begin
trashernet_udp_inst : entity trashernet.trashernet_udp
port map(
clk => clk,
rst => rst,
ipv4_protocol_in => ipv4_protocol_in(IPROT_UDP),
ipv4_protocol_out => ipv4_protocol_out(IPROT_UDP),
udp_out => udp_out,
udp_in => udp_in
);
trashernet_icmp_inst : entity trashernet.trashernet_icmp
port map(
clk => clk,
@ -375,20 +388,23 @@ begin
end process udp;
tx_udp_p : block
type state_t is (IDLE, TX, DONE);
signal state : state_t;
type state_t is (IDLE, TX, DONE);
signal state : state_t;
constant PACKET : byte_vector := (
x"10", x"00", -- Source port
x"04", x"00", -- Destination port
x"00", x"15", -- Length
x"00", x"00", -- Checksum (not used)
x"48", x"65", x"6C", x"6C", x"6F", x"20", x"57", x"6F", x"72", x"6C", x"64", x"21", x"0a" -- Payload
);
signal sr : byte_vector(PACKET'range);
signal cnt : integer range 0 to sr'length - 1;
begin
udp_in.tx_en <= '1' when state = TX else '0';
udp_in.tx_ip_address <= (x"C0", x"A8", x"02", x"01");
udp_in.tx_source_port <= x"ABCD";
udp_in.tx_destination_port <= x"00FF";
udp_in.tx_length <= to_unsigned(sr'length, 16);
udp_in.tx_data <= sr(0);
tx_udp : process(clk, rst) is
begin
if rst then
@ -405,7 +421,8 @@ begin
end if;
when TX =>
if ipv4_protocol_out(IPROT_UDP).tx_data_ack then
if udp_out.tx_data_ack then
report "UDP: byte ack";
sr <= sr(sr'low + 1 to sr'high) & x"00";
if cnt = 0 then
state <= DONE;
@ -413,11 +430,11 @@ begin
cnt <= cnt - 1;
end if;
end if;
if ipv4_protocol_out(IPROT_UDP).tx_err_stb then
if udp_out.tx_err_stb then
report "UDP: TX ERROR";
state <= DONE;
end if;
if ipv4_protocol_out(IPROT_UDP).tx_ok_stb then
if udp_out.tx_ok_stb then
report "UDP: TX OK stb in TX state -- that shouldn't happen, right?";
end if;
@ -427,12 +444,27 @@ begin
end case;
end if;
end process tx_udp;
ipv4_protocol_in(IPROT_UDP).tx_en <= '1' when state = TX else '0';
ipv4_protocol_in(IPROT_UDP).tx_ip_address <= (x"C0", x"A8", x"02", x"01");
ipv4_protocol_in(IPROT_UDP).tx_length <= to_unsigned(sr'length, 16);
ipv4_protocol_in(IPROT_UDP).tx_data <= sr(0);
end block tx_udp_p;
rx_udp_p : block
begin
rx_udp : process(clk, rst) is
begin
if rst then
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));
end if;
if udp_out.rx_data_valid then
report "UDP: RX: " & to_hstring(udp_out.rx_data);
end if;
end if;
end process rx_udp;
end block rx_udp_p;
icmp : process(clk) is
begin
if rising_edge(clk) then

View File

@ -191,6 +191,50 @@ package trashernet_pkg is
type ipv4_protocol_out_vector is array (natural range <>) of ipv4_protocol_out_t;
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
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_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
end record udp_out_t;
type udp_in_t is record
tx_ip_address : ip_addr_t; -- Destination IP address
tx_source_port : udp_port_t; -- UDP source port
tx_destination_port : udp_port_t; -- UDP destination port
tx_length : udp_length_t; -- UDP length
tx_en : std_logic; -- Start and continue transmitting
tx_data : byte;
end record udp_in_t;
type udpprot_rx_out_t is record
temp : std_logic;
end record udpprot_rx_out_t;
type udpprot_rx_in_t is record
temp : std_logic;
end record udpprot_rx_in_t;
type udpprot_tx_out_t is record
temp : std_logic;
end record udpprot_tx_out_t;
type udpprot_tx_in_t is record
temp : std_logic;
end record udpprot_tx_in_t;
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;

View File

@ -0,0 +1,160 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_ipv4.vhd : Ethernet OSI Layer 3, Network (IPv4)
-- Implements packet handling and IP-Layer en-/decoding.
-- -------------------------------------------------------------------------- --
-- 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_udp is
-- generic(
-- UDP_PORTS_RX : udp_port_vector; -- Ports to receive on
-- UDP_PORTS_TX : udp_port_vector -- Ports to transmit on
-- );
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- IPv4 application interface
ipv4_protocol_in : out ipv4_protocol_in_t; -- IPv4 IF (out from IP Protocol)
ipv4_protocol_out : in ipv4_protocol_out_t; -- IPv4 IF (into IP Protocol)
-- UDP application interface
udp_out : out udp_out_t;
udp_in : in udp_in_t
-- udpprot_rx_out : out udpprot_rx_out_t; -- UDP Application IF for receiving data (out from UDP)
-- udpprot_rx_in : in udpprot_rx_in_t; -- UDP Application IF for receiving data (into UDP)
-- udpprot_tx_out : out udpprot_tx_out_t; -- UDP Application IF for transmitting data (out from UDP)
-- udpprot_tx_in : in udpprot_tx_in_t -- UDP Application IF for transmitting data (in from UDP)
);
end entity trashernet_udp;
architecture rtl of trashernet_udp is
begin
receiver : block
constant BYTECOUNT_HEADER : integer := 8; -- Mandatory header fields
signal sr : byte_vector(0 to BYTECOUNT_HEADER - 1) := (others => x"00"); -- Init to zero to squelch metavalue warnings
alias sr_source_port is sr(0 to 1);
alias sr_destination_port is sr(2 to 3);
alias sr_length is sr(4 to 5);
alias sr_source_checksum is sr(6 to 7);
signal bytecount : integer range 0 to BYTECOUNT_HEADER - 1;
type state_t is (HEADER, PAYLOAD);
signal state : state_t;
begin
rxp : process(rst, clk) is
begin
if rst then
state <= HEADER;
udp_out.rx_header_rcv <= '0';
udp_out.rx_error_stb <= '0';
udp_out.rx_ok_stb <= '0';
elsif rising_edge(clk) then
udp_out.rx_header_rcv <= '0';
udp_out.rx_error_stb <= ipv4_protocol_out.rx_error_stb;
udp_out.rx_ok_stb <= ipv4_protocol_out.rx_ok_stb;
case state is
when HEADER =>
if ipv4_protocol_out.rx_data_valid then
sr <= sr(sr'low + 1 to sr'high) & ipv4_protocol_out.rx_data;
if bytecount = BYTECOUNT_HEADER - 1 then
state <= PAYLOAD;
udp_out.rx_header_rcv <= '1';
else
bytecount <= bytecount + 1;
end if;
end if;
when PAYLOAD =>
udp_out.rx_data <= ipv4_protocol_out.rx_data;
udp_out.rx_data_valid <= ipv4_protocol_out.rx_data_valid;
end case;
if ipv4_protocol_out.rx_header_rcv or ipv4_protocol_out.rx_error_stb or ipv4_protocol_out.rx_ok_stb then
state <= HEADER;
bytecount <= 0;
end if;
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)));
end block receiver;
transmitter : block
constant BYTECOUNT_HEADER : integer := 8; -- Mandatory header fields
signal sr : byte_vector(0 to BYTECOUNT_HEADER - 1) := (others => x"00"); -- Init to zero to squelch metavalue warnings
signal byte_cnt : integer range 0 to sr'length - 1;
type state_t is (IDLE, HEADER, PAYLOAD);
signal state : state_t;
begin
txp : process(rst, clk) is
variable full_length : udp_length_t;
begin
if rst then
udp_out.tx_data_ack <= '0';
udp_out.tx_err_stb <= '0';
udp_out.tx_ok_stb <= '0';
elsif rising_edge(clk) then
udp_out.tx_data_ack <= '0';
udp_out.tx_err_stb <= ipv4_protocol_out.tx_err_stb;
udp_out.tx_ok_stb <= ipv4_protocol_out.tx_ok_stb;
if ipv4_protocol_out.tx_data_ack = '1' then
if byte_cnt > 0 then
byte_cnt <= byte_cnt - 1;
end if;
sr <= sr(sr'low + 1 to sr'high) & x"00";
end if;
case state is
when IDLE =>
if udp_in.tx_en then
full_length := udp_in.tx_length + BYTECOUNT_HEADER;
sr <= byte_vector'(byte(udp_in.tx_source_port(15 downto 8)), byte(udp_in.tx_source_port(7 downto 0)), --
byte(udp_in.tx_destination_port(15 downto 8)), byte(udp_in.tx_destination_port(7 downto 0)), --
byte(full_length(15 downto 8)), byte(full_length(7 downto 0)), --
x"00", x"00");
byte_cnt <= sr'length - 1;
ipv4_protocol_in.tx_length <= full_length;
ipv4_protocol_in.tx_ip_address <= udp_in.tx_ip_address;
state <= HEADER;
end if;
when HEADER =>
if byte_cnt = 0 then
state <= PAYLOAD;
end if;
when PAYLOAD =>
if ipv4_protocol_out.tx_data_ack then
sr(sr'low) <= udp_in.tx_data;
udp_out.tx_data_ack <= '1';
if not udp_in.tx_en then
state <= IDLE;
end if;
end if;
end case;
end if;
end process txp;
ipv4_protocol_in.tx_data <= sr(sr'low);
ipv4_protocol_in.tx_en <= '1' when (state /= IDLE) else '0';
end block transmitter;
end architecture rtl;