bench: hw_itl: Use UDPprot

This commit is contained in:
Markus Koch 2025-09-19 10:13:49 +02:00
parent e7db2df389
commit ba0cbed9bf
4 changed files with 199 additions and 41 deletions

View File

@ -228,7 +228,24 @@ architecture eth of top_hwitl is
signal udp_out : udp_out_t;
signal udp_in : udp_in_t;
signal udpprot_rx_out : udpprot_rx_out_vector(0 to 0);
signal udpprot_rx_in : udpprot_rx_in_vector(0 to 0);
signal udpprot_tx_out : udpprot_tx_out_vector(0 to 0);
signal udpprot_tx_in : udpprot_tx_in_vector(0 to 0);
begin
trashernet_udpprot_inst : entity trashernet.trashernet_udpprot
port map(
clk => clk,
rst => rst,
udp_out => udp_out,
udp_in => udp_in,
udpprot_rx_out => udpprot_rx_out,
udpprot_rx_in => udpprot_rx_in,
udpprot_tx_out => udpprot_tx_out,
udpprot_tx_in => udpprot_tx_in
);
trashernet_udp_inst : entity trashernet.trashernet_udp
port map(
clk => clk,
@ -398,12 +415,12 @@ begin
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);
udpprot_tx_in(0).tx_ip_address <= (x"C0", x"A8", x"02", x"01");
udpprot_tx_in(0).tx_destination_port <= x"00FF";
udpprot_tx_in(0).tx_source_port <= x"ABCD";
udpprot_tx_in(0).tx_length <= to_unsigned(sr'length, 16);
udpprot_tx_in(0).tx_data <= sr(0);
udpprot_tx_in(0).tx_en <= '1' when state = TX else '0';
tx_udp : process(clk, rst) is
begin
@ -417,12 +434,12 @@ begin
state <= TX;
sr <= PACKET;
cnt <= sr'length - 1;
report "UDP: Start TX";
report "UDP(0): Start TX";
end if;
when TX =>
if udp_out.tx_data_ack then
report "UDP: byte ack";
if udpprot_tx_out(0).tx_data_ack then
report "UDP(0): byte ack";
sr <= sr(sr'low + 1 to sr'high) & x"00";
if cnt = 0 then
state <= DONE;
@ -430,12 +447,12 @@ begin
cnt <= cnt - 1;
end if;
end if;
if udp_out.tx_err_stb then
report "UDP: TX ERROR";
if udpprot_tx_out(0).tx_err_stb then
report "UDP(0): TX ERROR";
state <= DONE;
end if;
if udp_out.tx_ok_stb then
report "UDP: TX OK stb in TX state -- that shouldn't happen, right?";
if udpprot_tx_out(0).tx_ok_stb then
report "UDP(0): TX OK stb in TX state -- that shouldn't happen, right?";
end if;
when DONE =>
@ -446,6 +463,8 @@ begin
end process tx_udp;
end block tx_udp_p;
udpprot_rx_in(0).port_bind <= x"0400";
rx_udp_p : block
begin
rx_udp : process(clk, rst) is
@ -453,13 +472,13 @@ 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_header.destination_port)) & " from port " & --
to_string(to_integer(udp_out.rx_header.source_port));
if udpprot_rx_out(0).rx_header_rcv then
report "UDP(0): RX on port " & --
to_string(to_integer(udpprot_rx_out(0).rx_header.destination_port)) & " from port " & --
to_string(to_integer(udpprot_rx_out(0).rx_header.source_port));
end if;
if udp_out.rx_data_valid then
report "UDP: RX: " & to_hstring(udp_out.rx_data);
if udpprot_rx_out(0).rx_data_valid then
report "UDP(0): RX: " & to_hstring(udpprot_rx_out(0).rx_data);
end if;
end if;
end process rx_udp;

View File

@ -261,20 +261,37 @@ package trashernet_pkg is
tx_data : byte;
end record udp_in_t;
type udpprot_rx_out_t is record
temp : std_logic;
type udpprot_rx_out_t is record
rx_data : byte; -- RX Data
rx_data_valid : std_logic; -- RX data valid strobe
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
end record udpprot_rx_out_t;
type udpprot_rx_in_t is record
temp : std_logic;
type udpprot_rx_in_t is record
port_bind : udp_port_t;
end record udpprot_rx_in_t;
type udpprot_tx_out_t is record
temp : std_logic;
type udpprot_tx_out_t is record
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 udpprot_tx_out_t;
type udpprot_tx_in_t is record
temp : std_logic;
type udpprot_tx_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 udpprot_tx_in_t;
subtype portnum is integer range 0 to 65535;
type udp_port_vector is array (natural range <>) of portnum;
type udpprot_tx_out_vector is array (natural range <>) of udpprot_tx_out_t;
type udpprot_tx_in_vector is array (natural range <>) of udpprot_tx_in_t;
type udpprot_rx_out_vector is array (natural range <>) of udpprot_rx_out_t;
type udpprot_rx_in_vector is array (natural range <>) of udpprot_rx_in_t;
-- ------------------------
-- General helper functions

View File

@ -1,8 +1,8 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_ipv4.vhd : Ethernet OSI Layer 3, Network (IPv4)
-- Implements packet handling and IP-Layer en-/decoding.
-- trashernet_udp.vhd : Ethernet OSI Layer 4, Transport (UDP)
-- Implements UDP frame encoding and decoding.
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
@ -16,10 +16,6 @@ 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
@ -30,12 +26,8 @@ entity trashernet_udp is
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)
udp_out : out udp_out_t; -- UDP application IF (out from UDP)
udp_in : in udp_in_t -- UDP application IF (into UDP)
);
end entity trashernet_udp;

View File

@ -0,0 +1,130 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_udpprot.vhd : Ethernet OSI Layer 4, Transport (UDP)
-- Provides a convenient port-based muxed interface for UDP connections.
-- -------------------------------------------------------------------------- --
-- 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_udpprot is
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- UDP application interface
udp_out : in udp_out_t; -- UDP application IF (out from UDP)
udp_in : out udp_in_t; -- UDP application IF (into UDP)
-- UDP protocols interface
udpprot_rx_out : out udpprot_rx_out_vector; -- UDP Application IF for receiving data (out from UDP)
udpprot_rx_in : in udpprot_rx_in_vector; -- UDP Application IF for receiving data (into UDP)
udpprot_tx_out : out udpprot_tx_out_vector; -- UDP Application IF for transmitting data (out from UDP)
udpprot_tx_in : in udpprot_tx_in_vector -- UDP Application IF for transmitting data (in from UDP)
);
end entity trashernet_udpprot;
architecture rtl of trashernet_udpprot is
constant RX_SEL_PROTOCOL_NONE : integer := udpprot_rx_out'low - 1;
signal rx_sel : integer range RX_SEL_PROTOCOL_NONE to udpprot_rx_out'high;
signal tx_sel : integer range udpprot_tx_out'low to udpprot_tx_out'high;
begin
assert udpprot_tx_out'length = udpprot_tx_in'length report "UDP in and out ports must have the same length" severity FAILURE;
assert udpprot_rx_out'length = udpprot_rx_in'length report "UDP in and out ports must have the same length" severity FAILURE;
rx : block
signal rx_header_rcv_delayed : std_logic;
begin
arb : process(clk, rst) is
begin
if rst then
rx_sel <= RX_SEL_PROTOCOL_NONE;
rx_header_rcv_delayed <= '0';
elsif rising_edge(clk) then
rx_header_rcv_delayed <= udp_out.rx_header_rcv;
if udp_out.rx_header_rcv then
rx_sel <= RX_SEL_PROTOCOL_NONE;
for i in udpprot_rx_out'range loop
if (udp_out.rx_header.destination_port = udpprot_rx_in(i).port_bind) then
rx_sel <= i;
end if;
end loop;
end if;
end if;
end process arb;
mux : for i in udpprot_rx_out'range generate
udpprot_rx_out(i).rx_data <= udp_out.rx_data;
udpprot_rx_out(i).rx_header <= udp_out.rx_header;
udpprot_rx_out(i).rx_data_valid <= udp_out.rx_data_valid when rx_sel = i else '0';
udpprot_rx_out(i).rx_error_stb <= udp_out.rx_error_stb when rx_sel = i else '0';
udpprot_rx_out(i).rx_ok_stb <= udp_out.rx_ok_stb when rx_sel = i else '0';
udpprot_rx_out(i).rx_header_rcv <= rx_header_rcv_delayed when rx_sel = i else '0';
end generate mux;
tx_mux : for i in udpprot_tx_out'range generate
udpprot_tx_out(i).tx_data_ack <= udp_out.tx_data_ack when tx_sel = i else '0';
udpprot_tx_out(i).tx_err_stb <= udp_out.tx_err_stb when tx_sel = i else '0';
udpprot_tx_out(i).tx_ok_stb <= udp_out.tx_ok_stb when tx_sel = i else '0';
end generate;
end block rx;
tx : block
type state_t is (IDLE, TXD, WAITDONE);
signal state : state_t;
begin
arb : process(clk, rst) is
begin
if rst then
state <= IDLE;
tx_sel <= udpprot_tx_in'left;
elsif rising_edge(clk) then
case state is
when IDLE =>
for i in udpprot_tx_in'range loop
if udpprot_tx_in(i).tx_en then
tx_sel <= i;
state <= TXD;
exit; -- Prioritize according to vector
end if;
end loop;
when TXD =>
state <= WAITDONE when (not udp_in.tx_en);
when WAITDONE =>
if udp_out.tx_err_stb or udp_out.tx_ok_stb or udp_out.tx_data_ack then
state <= IDLE;
tx_sel <= udpprot_tx_in'left; -- To avoid arbitration errors, always select the highest priority one by default
end if;
end case;
end if;
end process arb;
demux : block
begin
udp_in.tx_data <= udpprot_tx_in(tx_sel).tx_data;
udp_in.tx_en <= udpprot_tx_in(tx_sel).tx_en;
udp_in.tx_ip_address <= udpprot_tx_in(tx_sel).tx_ip_address;
udp_in.tx_length <= udpprot_tx_in(tx_sel).tx_length;
udp_in.tx_source_port <= udpprot_tx_in(tx_sel).tx_source_port;
udp_in.tx_destination_port <= udpprot_tx_in(tx_sel).tx_destination_port;
end block demux;
end block tx;
end architecture rtl;