131 lines
4.7 KiB
VHDL
131 lines
4.7 KiB
VHDL
-- -------------------------------------------------------------------------- --
|
|
-- 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;
|