diff --git a/libraries/io/eth/hdllib.cfg b/libraries/io/eth/hdllib.cfg new file mode 100644 index 0000000000000000000000000000000000000000..445b27d5158cf1b8159b91d1e4ef6ddf36af65ff --- /dev/null +++ b/libraries/io/eth/hdllib.cfg @@ -0,0 +1,35 @@ +hdl_lib_name = eth +hdl_library_clause_name = eth_lib +hdl_lib_uses = dp common tech_tse + +build_sim_dir = $HDL_BUILD_DIR +build_synth_dir = + +synth_files = + src/vhdl/eth_pkg.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_checksum.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_hdr_store.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_hdr_status.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_hdr_ctrl.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_hdr.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_crc_ctrl.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_crc_word.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_mm_registers.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_mm_reg_frame.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_udp_channel.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_buffer.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_control.vhd + $UNB/Firmware/modules/tse/src/vhdl/eth_ihl_to_20.vhd + src/vhdl/eth.vhd + + src/vhdl/avs_eth.vhd + src/vhdl/avs_eth_coe.vhd + +test_bench_files = + $UNB/Firmware/modules/tse/tb/vhdl/tb_eth_checksum.vhd + $UNB/Firmware/modules/tse/tb/vhdl/tb_eth_crc_ctrl.vhd + $UNB/Firmware/modules/tse/tb/vhdl/tb_eth_hdr.vhd + tb/vhdl/tb_eth.vhd + tb/vhdl/tb_tb_eth.vhd + tb/vhdl/tb_eth_udp_offload.vhd + $UNB/Firmware/modules/tse/tb/vhdl/tb_eth_ihl_to_20.vhd diff --git a/libraries/io/eth/src/vhdl/avs_eth.vhd b/libraries/io/eth/src/vhdl/avs_eth.vhd new file mode 100644 index 0000000000000000000000000000000000000000..98c8d722e0f90c9741ee7ce6815c6a0419ddd52e --- /dev/null +++ b/libraries/io/eth/src/vhdl/avs_eth.vhd @@ -0,0 +1,190 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, tech_tse_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; +USE work.eth_pkg.ALL; + + +ENTITY avs_eth IS + PORT ( + --------------------------------------------------------------------------- + -- Clock interface + --------------------------------------------------------------------------- + csi_mm_reset : IN STD_LOGIC; + csi_mm_clk : IN STD_LOGIC; + + --------------------------------------------------------------------------- + -- Memory Mapped Slave interface + --------------------------------------------------------------------------- + -- TSE MAC + -- . MOSI + mms_tse_address : IN STD_LOGIC_VECTOR(c_tse_byte_addr_w-1 DOWNTO 0); + mms_tse_write : IN STD_LOGIC; + mms_tse_read : IN STD_LOGIC; + mms_tse_writedata : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + -- . MISO + mms_tse_readdata : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + mms_tse_waitrequest : OUT STD_LOGIC; + + -- ETH registers + -- . MOSI + mms_reg_address : IN STD_LOGIC_VECTOR(c_eth_reg_addr_w-1 DOWNTO 0); + mms_reg_write : IN STD_LOGIC; + mms_reg_read : IN STD_LOGIC; + mms_reg_writedata : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + -- . MISO + mms_reg_readdata : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + -- ETH packet RAM + -- . MOSI + mms_ram_address : IN STD_LOGIC_VECTOR(c_eth_ram_addr_w-1 DOWNTO 0); + mms_ram_write : IN STD_LOGIC; + mms_ram_read : IN STD_LOGIC; + mms_ram_writedata : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + -- . MISO + mms_ram_readdata : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + --------------------------------------------------------------------------- + -- Avalon Interrupt Sender interface: ins_* + --------------------------------------------------------------------------- + ins_interrupt_irq : OUT STD_LOGIC; + + --------------------------------------------------------------------------- + -- Avalon Conduit interfaces: coe_*_export + --------------------------------------------------------------------------- + -- PHY interface + coe_eth_clk_export : IN STD_LOGIC; + coe_eth_txp_export : OUT STD_LOGIC; + coe_eth_rxp_export : IN STD_LOGIC; + + -- LED + coe_led_an_export : OUT STD_LOGIC; + coe_led_link_export : OUT STD_LOGIC; + coe_led_disp_err_export : OUT STD_LOGIC; + coe_led_char_err_export : OUT STD_LOGIC; + coe_led_crs_export : OUT STD_LOGIC; + coe_led_col_export : OUT STD_LOGIC + ); +END avs_eth; + + +ARCHITECTURE wrap OF avs_eth IS + + -- Wrap all records to STD_LOGIC + + -- ST UDP interface + SIGNAL udp_tx_snk_in_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + SIGNAL udp_rx_src_in_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + + -- MM interface + SIGNAL tse_sla_in : t_mem_mosi; -- ETH TSE MAC registers + SIGNAL tse_sla_out : t_mem_miso; + SIGNAL reg_sla_in : t_mem_mosi; -- ETH control and status registers + SIGNAL reg_sla_out : t_mem_miso; + SIGNAL ram_sla_in : t_mem_mosi; -- ETH rx frame and tx frame memory + SIGNAL ram_sla_out : t_mem_miso; + + -- LED interface + SIGNAL tse_led : t_tse_led; + +BEGIN + + -- Run internal ST at MM clock + -- Disable UDP off-load interface + udp_tx_snk_in_arr <= (OTHERS=>c_dp_sosi_rst); -- default not valid if not used + udp_rx_src_in_arr <= (OTHERS=>c_dp_siso_rdy); -- default ready if not used + + -- TSE MAC + -- . MOSI + tse_sla_in.address <= RESIZE_MEM_ADDRESS(mms_tse_address); + tse_sla_in.wr <= mms_tse_write; + tse_sla_in.rd <= mms_tse_read; + tse_sla_in.wrdata <= RESIZE_MEM_DATA(mms_tse_writedata); + -- . MISO + mms_tse_readdata <= tse_sla_out.rddata(c_word_w-1 DOWNTO 0); + mms_tse_waitrequest <= tse_sla_out.waitrequest; + + -- ETH registers + -- . MOSI + reg_sla_in.address <= RESIZE_MEM_ADDRESS(mms_reg_address); + reg_sla_in.wr <= mms_reg_write; + reg_sla_in.rd <= mms_reg_read; + reg_sla_in.wrdata <= RESIZE_MEM_DATA(mms_reg_writedata); + -- . MISO + mms_reg_readdata <= reg_sla_out.rddata(c_word_w-1 DOWNTO 0); + + -- ETH packet RAM + -- . MOSI + ram_sla_in.address <= RESIZE_MEM_ADDRESS(mms_ram_address); + ram_sla_in.wr <= mms_ram_write; + ram_sla_in.rd <= mms_ram_read; + ram_sla_in.wrdata <= RESIZE_MEM_DATA(mms_ram_writedata); + -- . MISO + mms_ram_readdata <= ram_sla_out.rddata(c_word_w-1 DOWNTO 0); + + -- LEDs + coe_led_an_export <= tse_led.an; + coe_led_link_export <= tse_led.link; + coe_led_disp_err_export <= tse_led.disp_err; + coe_led_char_err_export <= tse_led.char_err; + coe_led_crs_export <= tse_led.crs; + coe_led_col_export <= tse_led.col; + + u_eth : ENTITY work.eth + PORT MAP ( + -- Clocks and reset + mm_rst => csi_mm_reset, -- reset synchronous with mm_clk + mm_clk => csi_mm_clk, -- memory-mapped bus clock + eth_clk => coe_eth_clk_export, -- ethernet phy reference clock + st_rst => csi_mm_reset, -- reset synchronous with st_clk + st_clk => csi_mm_clk, -- packet stream clock + + -- UDP transmit interface + udp_tx_snk_in_arr => udp_tx_snk_in_arr, + udp_tx_snk_out_arr => OPEN, + -- UDP receive interface + udp_rx_src_in_arr => udp_rx_src_in_arr, + udp_rx_src_out_arr => OPEN, + + -- Memory Mapped Slaves + tse_sla_in => tse_sla_in, -- ETH TSE MAC registers + tse_sla_out => tse_sla_out, + reg_sla_in => reg_sla_in, -- ETH control and status registers + reg_sla_out => reg_sla_out, + reg_sla_interrupt => ins_interrupt_irq, -- ETH interrupt + ram_sla_in => ram_sla_in, -- ETH rx frame and tx frame memory + ram_sla_out => ram_sla_out, + + -- PHY interface + eth_txp => coe_eth_txp_export, + eth_rxp => coe_eth_rxp_export, + + -- LED interface + tse_led => tse_led + ); + +END wrap; diff --git a/libraries/io/eth/src/vhdl/avs_eth_coe.vhd b/libraries/io/eth/src/vhdl/avs_eth_coe.vhd new file mode 100644 index 0000000000000000000000000000000000000000..6a52b0d78c0cc76bbd202c6f2332fc620660ff8f --- /dev/null +++ b/libraries/io/eth/src/vhdl/avs_eth_coe.vhd @@ -0,0 +1,139 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Purpose: AVS wrapper to make a MM slave ports for ETH available as conduit +-- Description: +-- Remark: +-- . The avs_eth_coe_hw.tcl determines the read latency per port + +LIBRARY IEEE, common_lib, tech_tse_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; +USE work.eth_pkg.ALL; + + +ENTITY avs_eth_coe IS + PORT ( + ---------------------------------------------------------------------------- + -- MM side + + -- Clock interface + csi_mm_reset : IN STD_LOGIC; + csi_mm_clk : IN STD_LOGIC; + + -- TSE MAC + mms_tse_address : IN STD_LOGIC_VECTOR(c_tse_byte_addr_w-1 DOWNTO 0); + mms_tse_write : IN STD_LOGIC; + mms_tse_read : IN STD_LOGIC; + mms_tse_writedata : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + mms_tse_readdata : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -- read latency is 0 + mms_tse_waitrequest : OUT STD_LOGIC; -- necessary because read latency is 0 + + -- ETH registers + mms_reg_address : IN STD_LOGIC_VECTOR(c_eth_reg_addr_w-1 DOWNTO 0); + mms_reg_write : IN STD_LOGIC; + mms_reg_read : IN STD_LOGIC; + mms_reg_writedata : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + mms_reg_readdata : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -- read latency is 1 + + -- ETH packet RAM + mms_ram_address : IN STD_LOGIC_VECTOR(c_eth_ram_addr_w-1 DOWNTO 0); + mms_ram_write : IN STD_LOGIC; + mms_ram_read : IN STD_LOGIC; + mms_ram_writedata : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + mms_ram_readdata : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -- read latency is 2 + + -- Interrupt Sender interface + ins_interrupt_irq : OUT STD_LOGIC; -- relates to the ETH registers port + + ---------------------------------------------------------------------------- + -- User side + + -- Clock interface + coe_reset_export : OUT STD_LOGIC; + coe_clk_export : OUT STD_LOGIC; + + -- TSE MAC + coe_tse_address_export : OUT STD_LOGIC_VECTOR(c_tse_byte_addr_w-1 DOWNTO 0); + coe_tse_write_export : OUT STD_LOGIC; + coe_tse_read_export : OUT STD_LOGIC; + coe_tse_writedata_export : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + coe_tse_readdata_export : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + coe_tse_waitrequest_export : IN STD_LOGIC; + + -- ETH registers + coe_reg_address_export : OUT STD_LOGIC_VECTOR(c_eth_reg_addr_w-1 DOWNTO 0); + coe_reg_write_export : OUT STD_LOGIC; + coe_reg_read_export : OUT STD_LOGIC; + coe_reg_writedata_export : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + coe_reg_readdata_export : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + -- ETH packet RAM + coe_ram_address_export : OUT STD_LOGIC_VECTOR(c_eth_ram_addr_w-1 DOWNTO 0); + coe_ram_write_export : OUT STD_LOGIC; + coe_ram_read_export : OUT STD_LOGIC; + coe_ram_writedata_export : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + coe_ram_readdata_export : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + -- Interrupt Sender interface + coe_irq_export : IN STD_LOGIC + ); +END avs_eth_coe; + + +ARCHITECTURE wrap OF avs_eth_coe IS +BEGIN + + ------------------------------------------------------------------------------ + -- Wires + + -- Clock interface + coe_reset_export <= csi_mm_reset; + coe_clk_export <= csi_mm_clk; + + -- TSE MAC + coe_tse_address_export <= mms_tse_address; + coe_tse_write_export <= mms_tse_write; + coe_tse_read_export <= mms_tse_read; + coe_tse_writedata_export <= mms_tse_writedata; + mms_tse_readdata <= coe_tse_readdata_export; + mms_tse_waitrequest <= coe_tse_waitrequest_export; + + -- ETH registers + coe_reg_address_export <= mms_reg_address; + coe_reg_write_export <= mms_reg_write; + coe_reg_read_export <= mms_reg_read; + coe_reg_writedata_export <= mms_reg_writedata; + mms_reg_readdata <= coe_reg_readdata_export; + + -- ETH packet RAM + coe_ram_address_export <= mms_ram_address; + coe_ram_write_export <= mms_ram_write; + coe_ram_read_export <= mms_ram_read; + coe_ram_writedata_export <= mms_ram_writedata; + mms_ram_readdata <= coe_ram_readdata_export; + + -- Interrupt Sender interface + ins_interrupt_irq <= coe_irq_export; + +END wrap; diff --git a/libraries/io/eth/src/vhdl/eth.vhd b/libraries/io/eth/src/vhdl/eth.vhd new file mode 100644 index 0000000000000000000000000000000000000000..a43247081470ced371d75046778a8f5aca41d503 --- /dev/null +++ b/libraries/io/eth/src/vhdl/eth.vhd @@ -0,0 +1,613 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, tech_tse_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE common_lib.eth_layers_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; +USE work.eth_pkg.ALL; + +-- Purpose: +-- Provide Ethernet control access to a node and some UDP ports for streaming +-- data. +-- Description: +-- Connect the 1GbE TSE to the microprocessor and to streaming UDP ports. The +-- packets for the streaming channels are directed based on the UDP port +-- number and all other packets are transfered to the default control channel. + +ENTITY eth IS + GENERIC ( + g_cross_clock_domain : BOOLEAN := TRUE; -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain + g_ETH_PHY : STRING := "LVDS"; -- "LVDS" (default): uses LVDS IOs for ctrl_unb_common, "XCVR": uses tranceiver PHY + g_ihl20 : BOOLEAN := FALSE + ); + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; -- reset synchronous with mm_clk + mm_clk : IN STD_LOGIC; -- memory-mapped bus clock + eth_clk : IN STD_LOGIC; -- ethernet phy reference clock + st_rst : IN STD_LOGIC; -- reset synchronous with st_clk + st_clk : IN STD_LOGIC; -- packet stream clock + + cal_rec_clk : IN STD_LOGIC := '0'; -- Calibration & reconfig clock when using XCVR + + -- UDP transmit interface + udp_tx_snk_in_arr : IN t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0) := (OTHERS=> c_dp_sosi_rst); -- ST sinks, default not valid if not used + udp_tx_snk_out_arr : OUT t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + -- UDP receive interface + udp_rx_src_in_arr : IN t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0) := (OTHERS=> c_dp_siso_rdy); -- ST sources, default ready if not used + udp_rx_src_out_arr : OUT t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + + -- Memory Mapped Slaves + tse_sla_in : IN t_mem_mosi; -- ETH TSE MAC registers + tse_sla_out : OUT t_mem_miso; + reg_sla_in : IN t_mem_mosi; -- ETH control and status registers + reg_sla_out : OUT t_mem_miso; + reg_sla_interrupt : OUT STD_LOGIC; -- Interrupt + ram_sla_in : IN t_mem_mosi; -- ETH rx frame and tx frame memory + ram_sla_out : OUT t_mem_miso; + + -- PHY interface + eth_txp : OUT STD_LOGIC; + eth_rxp : IN STD_LOGIC; + + -- LED interface + tse_led : OUT t_tse_led + ); +END eth; + + +ARCHITECTURE str OF eth IS + + ------------------------------------------------------------------------------ + -- ETH Rx packet buffer and Tx packet buffer + ------------------------------------------------------------------------------ + + -- Use MM bus data width = c_word_w = 32 + CONSTANT c_mm_ram : t_c_mem := (latency => c_mem_ram_rd_latency, + adr_w => c_eth_ram_addr_w, + dat_w => c_word_w, + nof_dat => c_eth_ram_nof_words, + init_sl => '0'); + + SIGNAL mem_in : t_mem_mosi; -- big endian on ST and TSE MAC network side + SIGNAL mem_out : t_mem_miso; -- big endian on ST and TSE MAC network side + SIGNAL mem_in_endian : t_mem_mosi; -- keep big endian on MM side + SIGNAL mem_out_endian : t_mem_miso; -- keep big endian on MM side + + ------------------------------------------------------------------------------ + -- ETH stream + ------------------------------------------------------------------------------ + + -- Multiplex - demultiplex + CONSTANT c_mux_nof_ports : NATURAL := 1 + c_eth_nof_udp_ports; -- One for control + nof UDP ports + CONSTANT c_demux_nof_ports : NATURAL := c_mux_nof_ports; + CONSTANT c_demux_combined : BOOLEAN := FALSE; -- when TRUE then all downstream sinks must be ready, when FALSE then only the + -- selected sink needs to be ready (see dp_demux for more explanation). + -- All Rx (so UDP off-load and other ETH traffic) + SIGNAL rx_adapt_siso : t_dp_siso; + SIGNAL rx_adapt_sosi : t_dp_sosi; + + SIGNAL rx_crc_siso : t_dp_siso; + SIGNAL rx_crc_sosi : t_dp_sosi; + + SIGNAL rx_ihl20_siso : t_dp_siso; + SIGNAL rx_ihl20_sosi : t_dp_sosi; + + SIGNAL rx_hdr_siso : t_dp_siso; + SIGNAL rx_hdr_sosi : t_dp_sosi; + SIGNAL rx_hdr_status : t_eth_hdr_status; + + -- Rx demux + SIGNAL rx_channel_siso : t_dp_siso; + SIGNAL rx_channel_sosi : t_dp_sosi; + + SIGNAL demux_siso_arr : t_dp_siso_arr(0 TO c_mux_nof_ports-1); + SIGNAL demux_sosi_arr : t_dp_sosi_arr(0 TO c_mux_nof_ports-1); + + -- ETH Rx + SIGNAL eth_rx_siso : t_dp_siso; + SIGNAL eth_rx_sosi : t_dp_sosi; + + SIGNAL rx_frame_rd : STD_LOGIC; + SIGNAL rx_frame_ack : STD_LOGIC; + SIGNAL rx_frame_done : STD_LOGIC; + SIGNAL rx_frame_sosi : t_dp_sosi; + SIGNAL rx_frame_hdr_words : t_eth_total_header_arr; + SIGNAL rx_frame_hdr_fields : t_eth_total_header; + SIGNAL rx_frame_hdr_status : t_eth_hdr_status; + SIGNAL rx_frame_crc_word : STD_LOGIC_VECTOR(c_eth_data_w-1 DOWNTO 0); + + -- ETH Tx + SIGNAL eth_tx_siso : t_dp_siso; + SIGNAL eth_tx_sosi : t_dp_sosi; + + -- Tx mux + SIGNAL mux_siso_arr : t_dp_siso_arr(0 TO c_mux_nof_ports-1); + SIGNAL mux_sosi_arr : t_dp_sosi_arr(0 TO c_mux_nof_ports-1); + + -- All Tx (so UDP off-load and other ETH traffic) + SIGNAL tx_mux_siso : t_dp_siso; + SIGNAL tx_mux_sosi : t_dp_sosi; + + SIGNAL tx_hdr_siso : t_dp_siso; + SIGNAL tx_hdr_sosi : t_dp_sosi; + + ------------------------------------------------------------------------------ + -- MM registers (in st_clk domain) + ------------------------------------------------------------------------------ + + -- . write/read back + SIGNAL reg_demux : t_eth_mm_reg_demux; + SIGNAL reg_config : t_eth_mm_reg_config; + SIGNAL reg_control : t_eth_mm_reg_control; + SIGNAL reg_continue_wr : STD_LOGIC; + -- . read only + SIGNAL reg_frame : t_eth_mm_reg_frame; + SIGNAL reg_status : t_eth_mm_reg_status; + SIGNAL reg_status_wr : STD_LOGIC; + + ------------------------------------------------------------------------------ + -- TSE MAC + ------------------------------------------------------------------------------ + -- . MAC Transmit Stream + SIGNAL tse_tx_siso : t_dp_siso; + SIGNAL tse_tx_sosi : t_dp_sosi; + -- . MAC specific + SIGNAL tse_tx_mac_in : t_tse_tx_mac; + SIGNAL tse_tx_mac_out : t_tse_tx_mac; + -- . MAC Receive Stream + SIGNAL tse_rx_sosi : t_dp_sosi; + SIGNAL tse_rx_siso : t_dp_siso; + -- . MAC specific + SIGNAL tse_rx_mac_out : t_tse_rx_mac; + +BEGIN + + ------------------------------------------------------------------------------ + -- MM registers + ------------------------------------------------------------------------------ + + u_mm_registers : ENTITY work.eth_mm_registers + GENERIC MAP ( + g_cross_clock_domain => g_cross_clock_domain + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => st_rst, + st_clk => st_clk, + -- Memory Mapped Slave + sla_in => reg_sla_in, + sla_out => reg_sla_out, + sla_interrupt => reg_sla_interrupt, + -- MM registers in st_clk domain + -- . write/read back + st_reg_demux => reg_demux, + st_reg_config => reg_config, + st_reg_control => reg_control, + st_reg_continue_wr => reg_continue_wr, + -- . read only + st_reg_frame => reg_frame, + st_reg_status => reg_status, + st_reg_status_wr => reg_status_wr + ); + + -- Packet buffer + u_mm_ram : ENTITY common_lib.common_ram_crw_crw + GENERIC MAP ( + g_ram => c_mm_ram + ) + PORT MAP ( + rst_a => mm_rst, + clk_a => mm_clk, + wr_en_a => ram_sla_in.wr, + adr_a => ram_sla_in.address(c_mm_ram.adr_w-1 DOWNTO 0), + wr_dat_a => ram_sla_in.wrdata(c_mm_ram.dat_w-1 DOWNTO 0), + rd_en_a => ram_sla_in.rd, + rd_dat_a => ram_sla_out.rddata(c_mm_ram.dat_w-1 DOWNTO 0), + rd_val_a => ram_sla_out.rdval, + rst_b => st_rst, + clk_b => st_clk, + wr_en_b => mem_in_endian.wr, + adr_b => mem_in_endian.address(c_mm_ram.adr_w-1 DOWNTO 0), + wr_dat_b => mem_in_endian.wrdata(c_mm_ram.dat_w-1 DOWNTO 0), + rd_en_b => mem_in_endian.rd, + rd_dat_b => mem_out_endian.rddata(c_mm_ram.dat_w-1 DOWNTO 0), + rd_val_b => mem_out_endian.rdval + ); + + -- The Rx, Tx packet buffer is big-endian + mem_in_endian <= func_mem_swap_endianess(mem_in, c_word_sz); + mem_out <= func_mem_swap_endianess(mem_out_endian, c_word_sz); + + + ------------------------------------------------------------------------------ + -- RX : Adapt the TSE RX source ready latency from 2 to 1 + ------------------------------------------------------------------------------ + + u_adapt : ENTITY dp_lib.dp_latency_adapter + GENERIC MAP ( + g_in_latency => c_eth_rx_ready_latency, -- = 2 + g_out_latency => c_eth_ready_latency -- = 1 + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + -- ST sink + snk_out => tse_rx_siso, + snk_in => tse_rx_sosi, + -- ST source + src_in => rx_adapt_siso, + src_out => rx_adapt_sosi + ); + + ------------------------------------------------------------------------------ + -- RX : Replace the CRC word with the stream error field from the TSE MAC + ------------------------------------------------------------------------------ + + u_crc_ctrl : ENTITY work.eth_crc_ctrl + PORT MAP ( + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in_err => rx_adapt_sosi.err(c_tse_error_w-1 DOWNTO 0), -- preserve error field from TSE MAC stream + snk_in => rx_adapt_sosi, + snk_out => rx_adapt_siso, + + -- Streaming Source + src_in => rx_crc_siso, + src_out => rx_crc_sosi, -- replaced CRC word by snk_in_err, so CRC word /=0 indicates any TSE error + src_out_err => OPEN -- flag snk_in_err/=0 at src_out.eop + ); + + ------------------------------------------------------------------------------ + -- RX : Strip the option words from the IPv4 header + ------------------------------------------------------------------------------ + gen_ihl20: IF g_ihl20 GENERATE + u_ihl20 : ENTITY work.eth_ihl_to_20 + PORT MAP ( + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => rx_crc_sosi, + snk_out => rx_crc_siso, + + -- Streaming Source + src_in => rx_ihl20_siso, + src_out => rx_ihl20_sosi + ); + END GENERATE; + + no_ihl20: IF not g_ihl20 GENERATE + rx_ihl20_sosi <= rx_crc_sosi; + rx_crc_siso <= rx_ihl20_siso; + END GENERATE; + + + ------------------------------------------------------------------------------ + -- RX : For IP verify IP header checksum + ------------------------------------------------------------------------------ + + u_rx_frame : ENTITY work.eth_hdr + GENERIC MAP ( + g_header_store_and_forward => TRUE, + g_ip_header_checksum_calculate => TRUE + ) + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => rx_ihl20_sosi, + snk_out => rx_ihl20_siso, + + -- Streaming Source + src_in => rx_hdr_siso, + src_out => rx_hdr_sosi, + + -- Header info + hdr_status => rx_hdr_status + ); + + + ------------------------------------------------------------------------------ + -- Demux the UDP off-load traffic and the keep the other ETH traffic + ------------------------------------------------------------------------------ + + -- Put UDP off-load traffic on channel > 0 + -- Put other ETH traffic on channel = 0 for further internal processing + u_udp_channel : ENTITY work.eth_udp_channel + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => rx_hdr_sosi, + snk_out => rx_hdr_siso, + + -- Streaming Source with channel field + src_in => rx_channel_siso, + src_out => rx_channel_sosi, + + -- Demux control + reg_demux => reg_demux, + hdr_status => rx_hdr_status + ); + + -- Demultiplex channel 0 for internal handling and the other channels > 0 for external UDP off-load. + u_rx_demux : ENTITY dp_lib.dp_demux + GENERIC MAP ( + g_nof_output => c_demux_nof_ports, + g_combined => c_demux_combined + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + -- ST sinks + snk_out => rx_channel_siso, + snk_in => rx_channel_sosi, + -- ST source + src_in_arr => demux_siso_arr, + src_out_arr => demux_sosi_arr + ); + + -- Fixed local ETH port + eth_rx_sosi <= demux_sosi_arr(0); + demux_siso_arr(0) <= eth_rx_siso; + + -- UDP offload ports + gen_udp_rx_demux : FOR i IN 1 TO c_eth_nof_udp_ports GENERATE + udp_rx_src_out_arr(i-1) <= demux_sosi_arr(i); + demux_siso_arr(i) <= udp_rx_src_in_arr(i-1); + END GENERATE; + + + ------------------------------------------------------------------------------ + -- ETH RX frame buffer + ------------------------------------------------------------------------------ + + u_rx_buffer : ENTITY work.eth_buffer + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => eth_rx_sosi, + snk_out => eth_rx_siso, + + -- Streaming Source + -- . The src_rd, src_ack and src_done act instead of src_in.ready to have src_in ready per frame instead of per data word + src_rd => rx_frame_rd, -- request frame pulse + src_ack => rx_frame_ack, -- acknowledge request + src_done => rx_frame_done, -- signal frame received + src_out => rx_frame_sosi + ); + + + ------------------------------------------------------------------------------ + -- ETH RX frame monitor + ------------------------------------------------------------------------------ + + -- Extract total header + u_rx_hdr_info : ENTITY work.eth_hdr + GENERIC MAP ( + g_header_store_and_forward => FALSE, + g_ip_header_checksum_calculate => FALSE + ) + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => rx_frame_sosi, + + -- Header info + hdr_words => rx_frame_hdr_words, + hdr_fields => rx_frame_hdr_fields, + hdr_status => rx_frame_hdr_status + ); + + -- Extract CRC word (enumerate: 0=OK, >0 AND odd = Error) + u_rx_crc_word : ENTITY work.eth_crc_word + PORT MAP ( + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => rx_frame_sosi, + + -- CRC word + crc_word => rx_frame_crc_word, + crc_word_val => OPEN + ); + + u_mm_reg_frame : ENTITY work.eth_mm_reg_frame + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Inputs need for the frame register + hdr_fields => rx_frame_hdr_fields, + hdr_status => rx_frame_hdr_status, + erc_word => rx_frame_crc_word, + reg_config => reg_config, + + -- Frame register + reg_frame => reg_frame + ); + + + ------------------------------------------------------------------------------ + -- ETH Control + ------------------------------------------------------------------------------ + + u_control : ENTITY work.eth_control + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Control register + reg_config => reg_config, + reg_control => reg_control, + reg_continue_wr => reg_continue_wr, + reg_status => reg_status, + reg_status_wr => reg_status_wr, + + -- Streaming sink Rx frame + rcv_rd => rx_frame_rd, + rcv_ack => rx_frame_ack, + rcv_done => rx_frame_done, + rcv_in => rx_frame_sosi, + rcv_hdr_words => rx_frame_hdr_words, + rcv_hdr_status => rx_frame_hdr_status, + + -- Streaming source Tx frame + xmt_in => eth_tx_siso, + xmt_out => eth_tx_sosi, + + -- MM frame memory + mem_in => mem_in, + mem_out => mem_out + ); + + + ------------------------------------------------------------------------------ + -- TX : Mux UDP + ------------------------------------------------------------------------------ + + -- Fixed local ETH + eth_tx_siso <= mux_siso_arr(0); + mux_sosi_arr(0) <= eth_tx_sosi; + + -- UDP offload ports + gen_udp_tx_mux : FOR i IN 1 TO c_eth_nof_udp_ports GENERATE + udp_tx_snk_out_arr(i-1) <= mux_siso_arr(i); + mux_sosi_arr(i) <= udp_tx_snk_in_arr(i-1); + END GENERATE; + + -- Multiplex the two input streams on to the single ETH stream + u_tx_mux : ENTITY dp_lib.dp_mux + GENERIC MAP ( + g_data_w => c_eth_data_w, + g_empty_w => c_eth_empty_w, + g_in_channel_w => 1, + g_error_w => 1, + g_use_empty => TRUE, + g_use_in_channel => FALSE, + g_use_error => FALSE, + g_nof_input => c_mux_nof_ports, + g_use_fifo => FALSE, + g_fifo_size => array_init(1024, c_mux_nof_ports), -- input FIFOs are not used, but generic must match g_nof_input + g_fifo_fill => array_init( 0, c_mux_nof_ports) -- input FIFOs are not used, but generic must match g_nof_input + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + -- ST sinks + snk_out_arr => mux_siso_arr, -- OUT = request to upstream ST source + snk_in_arr => mux_sosi_arr, + -- ST source + src_in => tx_mux_siso, -- IN = request from downstream ST sink + src_out => tx_mux_sosi + ); + + ------------------------------------------------------------------------------ + -- TX : For IP insert IP header checksum + ------------------------------------------------------------------------------ + + u_tx_frame : ENTITY work.eth_hdr + GENERIC MAP ( + g_header_store_and_forward => TRUE, + g_ip_header_checksum_calculate => TRUE + ) + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => tx_mux_sosi, + snk_out => tx_mux_siso, + + -- Streaming Source + src_in => tx_hdr_siso, + src_out => tx_hdr_sosi + ); + + + ------------------------------------------------------------------------------ + -- TSE MAC + ------------------------------------------------------------------------------ + tx_hdr_siso <= tse_tx_siso; + tse_tx_sosi <= func_dp_stream_error_set(tx_hdr_sosi, 0); -- set err field (value 0 for OK) + + tse_tx_mac_in.crc_fwd <= '0'; -- when '0' then TSE MAC generates the TX CRC field + + u_tse : ENTITY work.tse + GENERIC MAP ( + g_ETH_PHY => g_ETH_PHY + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + eth_clk => eth_clk, + tx_snk_clk => st_clk, + rx_src_clk => st_clk, + cal_rec_clk => cal_rec_clk, + -- Memory Mapped Slave + mm_sla_in => tse_sla_in, + mm_sla_out => tse_sla_out, + -- MAC transmit interface + -- . ST sink + tx_snk_in => tse_tx_sosi, + tx_snk_out => tse_tx_siso, + -- . MAC specific + tx_mac_in => tse_tx_mac_in, + tx_mac_out => tse_tx_mac_out, -- OPEN + -- MAC receive interface + -- . ST Source + rx_src_in => tse_rx_siso, + rx_src_out => tse_rx_sosi, + -- . MAC specific + rx_mac_out => tse_rx_mac_out, + -- PHY interface + eth_txp => eth_txp, + eth_rxp => eth_rxp, + -- LED interface + tse_led => tse_led + ); + +END str; diff --git a/libraries/io/eth/src/vhdl/eth_pkg.vhd b/libraries/io/eth/src/vhdl/eth_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..a9a45752bb2fdcc83509d683e634237e43084bc4 --- /dev/null +++ b/libraries/io/eth/src/vhdl/eth_pkg.vhd @@ -0,0 +1,353 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, tech_tse_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE common_lib.eth_layers_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; + + +PACKAGE eth_pkg IS + + CONSTANT c_eth_data_w : NATURAL := c_tse_data_w; -- = c_word_w + CONSTANT c_eth_empty_w : NATURAL := c_tse_empty_w; -- = ceil_log2(c_word_sz) = 2; + CONSTANT c_eth_error_w : NATURAL := c_tse_error_w; -- = 6, but no error field, pass error info on via checksum or CRC /= 0 in packet word + + CONSTANT c_eth_rx_ready_latency : NATURAL := c_tse_rx_ready_latency; -- = 2 = default when FIFO is used + CONSTANT c_eth_tx_ready_latency : NATURAL := c_tse_tx_ready_latency; -- = 0, c_tse_tx_ready_latency + 3 = TX_ALMOST_FULL + CONSTANT c_eth_ready_latency : NATURAL := 1; -- = 1, fixed ETH module internal RL + + -- Maximum feasible frame size + CONSTANT c_eth_max_frame_sz : NATURAL := 1024*9; -- 9 kByte fits 9020 = word align (2) + eth header (14) + maximum jumbo payload (9000) + CRC (4) + CONSTANT c_eth_max_frame_nof_words : NATURAL := c_eth_max_frame_sz/c_word_sz; + CONSTANT c_eth_max_frame_nof_words_w : NATURAL := ceil_log2(c_eth_max_frame_nof_words); -- = 12 bit + + -- Actual frame space in RAM <= c_eth_max_frame_sz, default >= 1520, <= 9020 for jumbo + --CONSTANT c_eth_frame_sz : NATURAL := 1024*3/2; -- Use 1536 = 3/2 M9K, to benefit from Rx and Tx in single buffer of 2*1.5=3 M9K, but does + -- yield simulation warning: Address pointed at port A is out of bound! + --CONSTANT c_eth_frame_sz : NATURAL := 1024*8; -- Use 8192 = 8 M9K for jumbo frame support with payload size <= 8172 + --CONSTANT c_eth_frame_sz : NATURAL := 1024*9; -- Use 9216 = 9 M9K for jumbo frame support with payload size <= 9000 + CONSTANT c_eth_frame_sz : NATURAL := 1024*2; -- Use 2048 = 2 M9K to avoid simulation warning: Address pointed at port A is out of bound! + -- when the module is used in an Nios II SOPC system + -- The FIFOs seem to require nof words to be a power of 2, but that is taken care of locally if necessary + CONSTANT c_eth_frame_nof_words : NATURAL := c_eth_frame_sz/c_word_sz; + CONSTANT c_eth_frame_nof_words_w : NATURAL := ceil_log2(c_eth_frame_nof_words); -- >= 9 bit, <= 12 bit + + TYPE t_eth_data_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_eth_data_w-1 DOWNTO 0); + + + ------------------------------------------------------------------------------ + -- Definitions for eth header status + ------------------------------------------------------------------------------ + + TYPE t_eth_hdr_status IS RECORD + is_arp : STD_LOGIC; + is_ip : STD_LOGIC; + is_icmp : STD_LOGIC; + is_udp : STD_LOGIC; + ip_checksum : STD_LOGIC_VECTOR(c_halfword_w-1 DOWNTO 0); + ip_checksum_val : STD_LOGIC; + ip_checksum_is_ok : STD_LOGIC; + udp_port : STD_LOGIC_VECTOR(c_udp_port_slv'RANGE); + is_dhcp : STD_LOGIC; + END RECORD; + + CONSTANT c_eth_hdr_status_rst : t_eth_hdr_status := ('0', '0', '0', '0', + (OTHERS=>'0'), '0', '0', + (OTHERS=>'0'), '0'); + + ------------------------------------------------------------------------------ + -- Definitions for eth demux udp + ------------------------------------------------------------------------------ + + CONSTANT c_eth_nof_udp_ports : NATURAL := 4; -- support 2, 4, 8, ... UDP off-load ports + CONSTANT c_eth_channel_w : NATURAL := ceil_log2(c_eth_nof_udp_ports + 1); -- + 1 for all other packets that go to the default port + CONSTANT c_eth_nof_channels : NATURAL := 2**c_eth_channel_w; + + ------------------------------------------------------------------------------ + -- MM register map + ------------------------------------------------------------------------------ + + CONSTANT c_eth_reg_demux_nof_words : NATURAL := c_eth_nof_udp_ports; + CONSTANT c_eth_reg_config_nof_words : NATURAL := 4; + CONSTANT c_eth_reg_control_nof_words : NATURAL := 1; + CONSTANT c_eth_reg_frame_nof_words : NATURAL := 1; + CONSTANT c_eth_reg_status_nof_words : NATURAL := 1; + + CONSTANT c_eth_reg_demux_wi : NATURAL := 0; + CONSTANT c_eth_reg_config_wi : NATURAL := c_eth_reg_demux_wi + c_eth_reg_demux_nof_words; + CONSTANT c_eth_reg_control_wi : NATURAL := c_eth_reg_config_wi + c_eth_reg_config_nof_words; + CONSTANT c_eth_reg_frame_wi : NATURAL := c_eth_reg_control_wi + c_eth_reg_control_nof_words; + CONSTANT c_eth_reg_status_wi : NATURAL := c_eth_reg_frame_wi + c_eth_reg_frame_nof_words; + CONSTANT c_eth_reg_continue_wi : NATURAL := c_eth_reg_status_wi + c_eth_reg_status_nof_words; + + -- . write/read back registers + TYPE t_eth_demux_ports_arr IS ARRAY(1 TO c_eth_nof_udp_ports) OF STD_LOGIC_VECTOR(c_udp_port_w-1 DOWNTO 0); + TYPE t_eth_mm_reg_demux IS RECORD + udp_ports_en : STD_LOGIC_VECTOR(1 TO c_eth_nof_udp_ports); -- [16] + udp_ports : t_eth_demux_ports_arr; -- [15:0] + END RECORD; + + TYPE t_eth_mm_reg_config IS RECORD + udp_port : STD_LOGIC_VECTOR(c_udp_port_w-1 DOWNTO 0); -- [15:0] + ip_address : STD_LOGIC_VECTOR(c_ip_addr_w-1 DOWNTO 0); -- [31:0] + mac_address : STD_LOGIC_VECTOR(c_eth_mac_addr_w-1 DOWNTO 0); -- [15:0], [31:0] + END RECORD; + + TYPE t_eth_mm_reg_control IS RECORD + tx_nof_words : STD_LOGIC_VECTOR(c_eth_max_frame_nof_words_w-1 DOWNTO 0); -- 12 bit + tx_empty : STD_LOGIC_VECTOR(c_eth_empty_w-1 DOWNTO 0); -- 2 bit + tx_request : STD_LOGIC; -- 1 bit + tx_en : STD_LOGIC; -- 1 bit + rx_en : STD_LOGIC; -- 1 bit + END RECORD; + + TYPE t_eth_mm_reg_control_bi IS RECORD -- bit indices + tx_nof_words : NATURAL; -- [26:18] + tx_empty : NATURAL; -- [17:16] + tx_request : NATURAL; -- [2] + tx_en : NATURAL; -- [1] + rx_en : NATURAL; -- [0] + END RECORD; + + CONSTANT c_eth_mm_reg_control_bi : t_eth_mm_reg_control_bi := (18, 16, 2, 1, 0); + CONSTANT c_eth_mm_reg_control_rst : t_eth_mm_reg_control := ((OTHERS=>'0'), (OTHERS=>'0'), '0', '0', '0'); + + -- . read only registers + TYPE t_eth_mm_reg_frame IS RECORD + is_dhcp : STD_LOGIC; + is_udp_ctrl_port : STD_LOGIC; + is_udp : STD_LOGIC; + is_icmp : STD_LOGIC; + ip_address_match : STD_LOGIC; + ip_checksum_is_ok : STD_LOGIC; + is_ip : STD_LOGIC; + is_arp : STD_LOGIC; + mac_address_match : STD_LOGIC; + eth_mac_error : STD_LOGIC_VECTOR(c_eth_error_w-1 DOWNTO 0); + END RECORD; + + TYPE t_eth_mm_reg_frame_bi IS RECORD -- bit indices + is_dhcp : NATURAL; -- [15] + is_udp_ctrl_port : NATURAL; -- [14] + is_udp : NATURAL; -- [13] + is_icmp : NATURAL; -- [12] + ip_address_match : NATURAL; -- [11] + ip_checksum_is_ok : NATURAL; -- [10] + is_ip : NATURAL; -- [9] + is_arp : NATURAL; -- [8] + mac_address_match : NATURAL; -- [7] + eth_mac_error : NATURAL; -- [6] not used, [5:0] = TSE MAC error + END RECORD; + + CONSTANT c_eth_mm_reg_frame_bi : t_eth_mm_reg_frame_bi := (15, 14, 13, 12, 11, 10, 9, 8, 7, 0); + CONSTANT c_eth_mm_reg_frame_rst : t_eth_mm_reg_frame := ('0', '0', '0', '0', '0', '0', '0', '0', '0', (OTHERS=>'0')); + + TYPE t_eth_mm_reg_status IS RECORD + rx_nof_words : STD_LOGIC_VECTOR(c_eth_max_frame_nof_words_w-1 DOWNTO 0); -- 12 bit + rx_empty : STD_LOGIC_VECTOR(c_eth_empty_w-1 DOWNTO 0); -- 2 bit + tx_avail : STD_LOGIC; -- 1 bit + tx_done : STD_LOGIC; -- 1 bit + rx_avail : STD_LOGIC; -- 1 bit + END RECORD; + + TYPE t_eth_mm_reg_status_bi IS RECORD -- bit indices + rx_nof_words : NATURAL; -- [26:18] + rx_empty : NATURAL; -- [17:16] + tx_avail : NATURAL; -- [2] + tx_done : NATURAL; -- [1] + rx_avail : NATURAL; -- [0] + END RECORD; + + CONSTANT c_eth_mm_reg_status_bi : t_eth_mm_reg_status_bi := (18, 16, 2, 1, 0); + CONSTANT c_eth_mm_reg_status_rst : t_eth_mm_reg_status := ((OTHERS=>'0'), (OTHERS=>'0'), '0', '0', '0'); + + -- Register mapping functions + FUNCTION func_eth_mm_reg_demux( mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_demux; + FUNCTION func_eth_mm_reg_demux( mm_reg : t_eth_mm_reg_demux) RETURN STD_LOGIC_VECTOR; + FUNCTION func_eth_mm_reg_config( mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_config; + FUNCTION func_eth_mm_reg_config( mm_reg : t_eth_mm_reg_config) RETURN STD_LOGIC_VECTOR; + FUNCTION func_eth_mm_reg_control(mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_control; + FUNCTION func_eth_mm_reg_control(mm_reg : t_eth_mm_reg_control) RETURN STD_LOGIC_VECTOR; + FUNCTION func_eth_mm_reg_frame( mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_frame; + FUNCTION func_eth_mm_reg_frame( mm_reg : t_eth_mm_reg_frame) RETURN STD_LOGIC_VECTOR; + FUNCTION func_eth_mm_reg_status( mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_status; + FUNCTION func_eth_mm_reg_status( mm_reg : t_eth_mm_reg_status) RETURN STD_LOGIC_VECTOR; + + ------------------------------------------------------------------------------ + -- Definitions for eth_mm_registers + ------------------------------------------------------------------------------ + + CONSTANT c_eth_reg_nof_words : NATURAL := c_eth_reg_demux_nof_words + + c_eth_reg_config_nof_words + + c_eth_reg_control_nof_words + + c_eth_reg_frame_nof_words + + c_eth_reg_status_nof_words; + CONSTANT c_eth_reg_addr_w : NATURAL := ceil_log2(c_eth_reg_nof_words + 1); -- + 1 for c_eth_continue_wi + + ------------------------------------------------------------------------------ + -- Definitions for ETH Rx packet buffer and Tx packet buffer + ------------------------------------------------------------------------------ + + -- Use MM bus data width = c_word_w = 32 + CONSTANT c_eth_ram_rx_offset : NATURAL := 0; + CONSTANT c_eth_ram_tx_offset : NATURAL := c_eth_frame_nof_words; + CONSTANT c_eth_ram_nof_words : NATURAL := c_eth_frame_nof_words*2; + CONSTANT c_eth_ram_addr_w : NATURAL := ceil_log2(c_eth_ram_nof_words); + +END eth_pkg; + + +PACKAGE BODY eth_pkg IS + + -- Register mapping functions + FUNCTION func_eth_mm_reg_demux(mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_demux IS + VARIABLE v_reg : t_eth_mm_reg_demux; + BEGIN + -- Demux UDP MM registers + FOR I IN 1 TO c_eth_nof_udp_ports LOOP + v_reg.udp_ports_en(I) := mm_reg(c_udp_port_w + (I-1)*c_word_w); -- [16] = UDP port enable + v_reg.udp_ports(I) := mm_reg(c_udp_port_w-1 + (I-1)*c_word_w DOWNTO (I-1)*c_word_w); -- [15:0] = UDP port number + END LOOP; + RETURN v_reg; + END func_eth_mm_reg_demux; + + FUNCTION func_eth_mm_reg_demux(mm_reg : t_eth_mm_reg_demux) RETURN STD_LOGIC_VECTOR IS + VARIABLE v_reg : STD_LOGIC_VECTOR(c_eth_reg_demux_nof_words*c_word_w-1 DOWNTO 0); + BEGIN + v_reg := (OTHERS=>'0'); -- rsvd + FOR I IN 1 TO c_eth_nof_udp_ports LOOP + v_reg(c_udp_port_w + (I-1)*c_word_w) := mm_reg.udp_ports_en(I); -- [16] = UDP port enable + v_reg(c_udp_port_w-1 + (I-1)*c_word_w DOWNTO (I-1)*c_word_w) := mm_reg.udp_ports(I); -- [15:0] = UDP port number + END LOOP; + RETURN v_reg; + END func_eth_mm_reg_demux; + + -- MM config register + FUNCTION func_eth_mm_reg_config(mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_config IS + VARIABLE v_reg : t_eth_mm_reg_config; + BEGIN + v_reg.udp_port := mm_reg(c_udp_port_w+3*c_word_w-1 DOWNTO 3*c_word_w); -- [15:0] = control UDP port number + v_reg.ip_address := mm_reg( 3*c_word_w-1 DOWNTO 2*c_word_w); -- [31:0] = this node IP address + v_reg.mac_address(47 DOWNTO 32) := mm_reg( c_halfword_w+c_word_w-1 DOWNTO c_word_w); -- [47:32] = this node MAC address + v_reg.mac_address(31 DOWNTO 0) := mm_reg( c_word_w-1 DOWNTO 0); -- [31:0] = this node MAC address + RETURN v_reg; + END func_eth_mm_reg_config; + + FUNCTION func_eth_mm_reg_config(mm_reg : t_eth_mm_reg_config) RETURN STD_LOGIC_VECTOR IS + VARIABLE v_reg : STD_LOGIC_VECTOR(c_eth_reg_config_nof_words*c_word_w-1 DOWNTO 0); + BEGIN + v_reg := (OTHERS=>'0'); -- rsvd + v_reg(c_udp_port_w+3*c_word_w-1 DOWNTO 3*c_word_w) := mm_reg.udp_port; -- [15:0] = control UDP port number + v_reg( 3*c_word_w-1 DOWNTO 2*c_word_w) := mm_reg.ip_address; -- [31:0] = this node IP address + v_reg( c_halfword_w+c_word_w-1 DOWNTO c_word_w) := mm_reg.mac_address(47 DOWNTO 32); -- [47:32] = this node MAC address + v_reg( c_word_w-1 DOWNTO 0) := mm_reg.mac_address(31 DOWNTO 0); -- [31:0] = this node MAC address + RETURN v_reg; + END func_eth_mm_reg_config; + + -- MM control register + FUNCTION func_eth_mm_reg_control(mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_control IS + VARIABLE v_reg : t_eth_mm_reg_control; + BEGIN + v_reg.tx_nof_words := mm_reg(c_eth_max_frame_nof_words_w+c_eth_empty_w+16-1 DOWNTO c_eth_empty_w+16); -- [29:18] + v_reg.tx_empty := mm_reg( c_eth_empty_w+16-1 DOWNTO 16); -- [17:16] + v_reg.tx_request := mm_reg( 2); -- [2] + v_reg.tx_en := mm_reg( 1); -- [1] + v_reg.rx_en := mm_reg( 0); -- [0] + RETURN v_reg; + END func_eth_mm_reg_control; + + FUNCTION func_eth_mm_reg_control(mm_reg : t_eth_mm_reg_control) RETURN STD_LOGIC_VECTOR IS + VARIABLE v_reg : STD_LOGIC_VECTOR(c_eth_reg_control_nof_words*c_word_w-1 DOWNTO 0); + BEGIN + v_reg := (OTHERS=>'0'); -- rsvd + v_reg(c_eth_max_frame_nof_words_w+c_eth_empty_w+16-1 DOWNTO c_eth_empty_w+16) := mm_reg.tx_nof_words; -- [29:18] + v_reg( c_eth_empty_w+16-1 DOWNTO 16) := mm_reg.tx_empty; -- [17:16] + v_reg( 2) := mm_reg.tx_request; -- [2] + v_reg( 1) := mm_reg.tx_en; -- [1] + v_reg( 0) := mm_reg.rx_en; -- [0] + RETURN v_reg; + END func_eth_mm_reg_control; + + -- MM frame register + FUNCTION func_eth_mm_reg_frame(mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_frame IS + VARIABLE v_reg : t_eth_mm_reg_frame; + BEGIN + v_reg.is_dhcp := mm_reg( c_byte_w+7); -- [15] + v_reg.is_udp_ctrl_port := mm_reg( c_byte_w+6); -- [14] + v_reg.is_udp := mm_reg( c_byte_w+5); -- [13] + v_reg.is_icmp := mm_reg( c_byte_w+4); -- [12] + v_reg.ip_address_match := mm_reg( c_byte_w+3); -- [11] + v_reg.ip_checksum_is_ok := mm_reg( c_byte_w+2); -- [10] + v_reg.is_ip := mm_reg( c_byte_w+1); -- [9] + v_reg.is_arp := mm_reg( c_byte_w+0); -- [8] + v_reg.mac_address_match := mm_reg( c_byte_w-1); -- [7] + v_reg.eth_mac_error := mm_reg(c_eth_error_w-1 DOWNTO 0); -- [7] not used, [5:0] = TSE MAC error + RETURN v_reg; + END func_eth_mm_reg_frame; + + FUNCTION func_eth_mm_reg_frame(mm_reg : t_eth_mm_reg_frame) RETURN STD_LOGIC_VECTOR IS + VARIABLE v_reg : STD_LOGIC_VECTOR(c_eth_reg_frame_nof_words*c_word_w-1 DOWNTO 0); + BEGIN + v_reg := (OTHERS=>'0'); -- rsvd + v_reg( c_byte_w+7) := mm_reg.is_dhcp; -- [15] + v_reg( c_byte_w+6) := mm_reg.is_udp_ctrl_port; -- [14] + v_reg( c_byte_w+5) := mm_reg.is_udp; -- [13] + v_reg( c_byte_w+4) := mm_reg.is_icmp; -- [12] + v_reg( c_byte_w+3) := mm_reg.ip_address_match; -- [11] + v_reg( c_byte_w+2) := mm_reg.ip_checksum_is_ok; -- [10] + v_reg( c_byte_w+1) := mm_reg.is_ip; -- [9] + v_reg( c_byte_w+0) := mm_reg.is_arp; -- [8] + v_reg( c_byte_w-1) := mm_reg.mac_address_match; -- [7] + v_reg(c_eth_error_w-1 DOWNTO 0) := mm_reg.eth_mac_error; -- [6] not used, [5:0] = TSE MAC error + RETURN v_reg; + END func_eth_mm_reg_frame; + + -- MM status register + FUNCTION func_eth_mm_reg_status(mm_reg : STD_LOGIC_VECTOR) RETURN t_eth_mm_reg_status IS + VARIABLE v_reg : t_eth_mm_reg_status; + BEGIN + v_reg.rx_nof_words := mm_reg(c_eth_max_frame_nof_words_w+c_eth_empty_w+16-1 DOWNTO c_eth_empty_w+16); -- [29:18] + v_reg.rx_empty := mm_reg( c_eth_empty_w+16-1 DOWNTO 16); -- [17:16] + v_reg.tx_avail := mm_reg( 2); -- [2] + v_reg.tx_done := mm_reg( 1); -- [1] + v_reg.rx_avail := mm_reg( 0); -- [0] + RETURN v_reg; + END func_eth_mm_reg_status; + + FUNCTION func_eth_mm_reg_status(mm_reg : t_eth_mm_reg_status) RETURN STD_LOGIC_VECTOR IS + VARIABLE v_reg : STD_LOGIC_VECTOR(c_eth_reg_status_nof_words*c_word_w-1 DOWNTO 0); + BEGIN + v_reg := (OTHERS=>'0'); -- rsvd + v_reg(c_eth_max_frame_nof_words_w+c_eth_empty_w+16-1 DOWNTO c_eth_empty_w+16) := mm_reg.rx_nof_words; -- [29:18] + v_reg( c_eth_empty_w+16-1 DOWNTO 16) := mm_reg.rx_empty; -- [17:16] + v_reg( 2) := mm_reg.tx_avail; -- [2] + v_reg( 1) := mm_reg.tx_done; -- [1] + v_reg( 0) := mm_reg.rx_avail; -- [0] + RETURN v_reg; + END func_eth_mm_reg_status; + +END eth_pkg; + diff --git a/libraries/io/eth/tb/vhdl/tb_eth.vhd b/libraries/io/eth/tb/vhdl/tb_eth.vhd new file mode 100644 index 0000000000000000000000000000000000000000..058afe95d11c089a72246f976554fdbf974cfd9e --- /dev/null +++ b/libraries/io/eth/tb/vhdl/tb_eth.vhd @@ -0,0 +1,531 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, tech_tse_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE common_lib.eth_layers_pkg.ALL; +USE WORK.eth_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; +USE tech_tse_lib.tb_tech_tse_pkg.ALL; + + +ENTITY tb_eth IS + -- Test bench control parameters + GENERIC ( + -- g_data_type = c_tb_tse_data_type_symbols = 0 + -- g_data_type = c_tb_tse_data_type_counter = 1 + -- g_data_type = c_tb_tse_data_type_arp = 2 + -- g_data_type = c_tb_tse_data_type_ping = 3 + -- g_data_type = c_tb_tse_data_type_udp = 4 + g_data_type : NATURAL := c_tb_tse_data_type_udp + ); +END tb_eth; + + +ARCHITECTURE tb OF tb_eth IS + + -- as 10 + -- run 100 us + + CONSTANT sys_clk_period : TIME := 10 ns; -- 100 MHz + CONSTANT eth_clk_period : TIME := 8 ns; -- 125 MHz + CONSTANT cable_delay : TIME := 12 ns; + + CONSTANT c_cross_clock_domain : BOOLEAN := TRUE; -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain + + -- TSE constants + CONSTANT c_promis_en : BOOLEAN := FALSE; + + CONSTANT c_tx_ready_latency : NATURAL := c_tse_tx_ready_latency; -- 0, 1 are supported, must match TSE MAC c_tse_tx_ready_latency + CONSTANT c_nof_tx_not_valid : NATURAL := 0; -- when > 0 then pull tx valid low for c_nof_tx_not_valid beats during tx + + -- Payload user data + CONSTANT c_tb_nof_data : NATURAL := 0; -- nof UDP user data, nof ping padding data + CONSTANT c_tb_ip_nof_data : NATURAL := c_udp_header_len + c_tb_nof_data; -- nof IP data, + -- also suits ICMP, because c_icmp_header_len = c_udp_header_len + CONSTANT c_tb_reply_payload : BOOLEAN := TRUE; -- TRUE copy rx payload into response payload, else header only (e.g. for ARP) + + -- Packet headers + -- . Ethernet header + CONSTANT c_word_align : STD_LOGIC_VECTOR(c_eth_word_align_w-1 DOWNTO 0) := TO_UVEC(c_eth_word_align, c_eth_word_align_w); + CONSTANT c_lcu_src_mac : STD_LOGIC_VECTOR(c_eth_mac_slv'RANGE) := X"10FA01020300"; + CONSTANT c_dut_src_mac : STD_LOGIC_VECTOR(c_eth_mac_slv'RANGE) := X"123456789ABC"; -- = 12-34-56-78-9A-BC + CONSTANT c_dut_src_mac_hi : NATURAL := TO_UINT(c_dut_src_mac(c_eth_mac_addr_w-1 DOWNTO c_word_w)); + CONSTANT c_dut_src_mac_lo : NATURAL := TO_UINT(c_dut_src_mac( c_word_w-1 DOWNTO 0)); + -- support only ARP and IPv4 over ETH + CONSTANT c_dut_ethertype : NATURAL := sel_a_b(g_data_type-c_tb_tse_data_type_arp, c_eth_type_ip, c_eth_type_arp); + CONSTANT c_tx_eth_header : t_eth_header := (word_align => c_word_align, + dst_mac => c_dut_src_mac, + src_mac => c_lcu_src_mac, + eth_type => TO_UVEC(c_dut_ethertype, c_eth_type_w)); + CONSTANT c_exp_eth_header : t_eth_header := (word_align => c_tx_eth_header.word_align, -- = + dst_mac => c_tx_eth_header.src_mac, -- \/ + src_mac => c_tx_eth_header.dst_mac, -- /\ + eth_type => c_tx_eth_header.eth_type); -- = + + -- . IP header + CONSTANT c_lcu_ip_addr : NATURAL := 16#05060708#; -- = 05:06:07:08 + CONSTANT c_dut_ip_addr : NATURAL := 16#01020304#; + CONSTANT c_tb_ip_total_length : NATURAL := c_ip_total_length + c_tb_ip_nof_data; + -- support only ping protocol or UDP protocol over IP + CONSTANT c_tb_ip_protocol : NATURAL := sel_a_b(g_data_type-c_tb_tse_data_type_ping, c_ip_protocol_udp, c_ip_protocol_icmp); + + CONSTANT c_tx_ip_header : t_ip_header := (version => TO_UVEC(c_ip_version, c_ip_version_w), + header_length => TO_UVEC(c_ip_header_length, c_ip_header_length_w), + services => TO_UVEC(c_ip_services, c_ip_services_w), + total_length => TO_UVEC(c_tb_ip_total_length, c_ip_total_length_w), + identification => TO_UVEC(c_ip_identification, c_ip_identification_w), + flags => TO_UVEC(c_ip_flags, c_ip_flags_w), + fragment_offset => TO_UVEC(c_ip_fragment_offset, c_ip_fragment_offset_w), + time_to_live => TO_UVEC(c_ip_time_to_live, c_ip_time_to_live_w), + protocol => TO_UVEC(c_tb_ip_protocol, c_ip_protocol_w), + header_checksum => TO_UVEC(c_ip_header_checksum, c_ip_header_checksum_w), -- init value (or try 0xEBBD = 60349) + src_ip_addr => TO_UVEC(c_lcu_ip_addr, c_ip_addr_w), + dst_ip_addr => TO_UVEC(c_dut_ip_addr, c_ip_addr_w)); + + CONSTANT c_exp_ip_header : t_ip_header := (version => c_tx_ip_header.version, -- = + header_length => c_tx_ip_header.header_length, -- = + services => c_tx_ip_header.services, -- = + total_length => c_tx_ip_header.total_length, -- = + identification => c_tx_ip_header.identification, -- = + flags => c_tx_ip_header.flags, -- = + fragment_offset => c_tx_ip_header.fragment_offset, -- = + time_to_live => c_tx_ip_header.time_to_live, -- = + protocol => c_tx_ip_header.protocol, -- = + header_checksum => c_tx_ip_header.header_checksum, -- init value + src_ip_addr => c_tx_ip_header.dst_ip_addr, -- \/ + dst_ip_addr => c_tx_ip_header.src_ip_addr); -- /\ + + -- . ARP packet + CONSTANT c_tx_arp_packet : t_arp_packet := (htype => TO_UVEC(c_arp_htype, c_arp_htype_w), + ptype => TO_UVEC(c_arp_ptype, c_arp_ptype_w), + hlen => TO_UVEC(c_arp_hlen, c_arp_hlen_w), + plen => TO_UVEC(c_arp_plen, c_arp_plen_w), + oper => TO_UVEC(c_arp_oper_request, c_arp_oper_w), + sha => c_lcu_src_mac, + spa => TO_UVEC(c_lcu_ip_addr, c_ip_addr_w), + tha => c_dut_src_mac, + tpa => TO_UVEC(c_dut_ip_addr, c_ip_addr_w)); + + CONSTANT c_exp_arp_packet : t_arp_packet := (htype => c_tx_arp_packet.htype, + ptype => c_tx_arp_packet.ptype, + hlen => c_tx_arp_packet.hlen, + plen => c_tx_arp_packet.plen, + oper => TO_UVEC(c_arp_oper_reply, c_arp_oper_w), -- reply + sha => c_tx_arp_packet.tha, -- \/ + spa => c_tx_arp_packet.tpa, -- /\ \/ + tha => c_tx_arp_packet.sha, -- / \ /\ + tpa => c_tx_arp_packet.spa); -- / \ + + CONSTANT c_arp_htype : NATURAL := 1; -- Hardware type, 1=ethernet + CONSTANT c_arp_ptype : NATURAL := c_eth_type_ip; -- Protocol type, do ARP for IPv4 + CONSTANT c_arp_hlen : NATURAL := c_eth_mac_addr_len; -- Hardware length = 6 + CONSTANT c_arp_plen : NATURAL := c_ip_addr_len; -- Protocol length = 4 + CONSTANT c_arp_oper : NATURAL := 1; -- Operator, 1=request, (2=reply) + + -- . ICMP header + CONSTANT c_tx_icmp_header : t_icmp_header := (msg_type => TO_UVEC(c_icmp_msg_type_request, c_icmp_msg_type_w), -- ping request + code => TO_UVEC(c_icmp_code, c_icmp_code_w), + checksum => TO_UVEC(c_icmp_checksum, c_icmp_checksum_w), -- init value + id => TO_UVEC(c_icmp_id, c_icmp_id_w), + sequence => TO_UVEC(c_icmp_sequence, c_icmp_sequence_w)); + CONSTANT c_exp_icmp_header : t_icmp_header := (msg_type => TO_UVEC(c_icmp_msg_type_reply, c_icmp_msg_type_w), -- ping reply + code => c_tx_icmp_header.code, + checksum => c_tx_icmp_header.checksum, -- init value + id => c_tx_icmp_header.id, + sequence => c_tx_icmp_header.sequence); + + -- . UDP header + CONSTANT c_dut_udp_port_ctrl : NATURAL := 11; -- ETH demux UDP for control + CONSTANT c_dut_udp_port_st0 : NATURAL := 57; -- ETH demux UDP port 0 + CONSTANT c_dut_udp_port_st1 : NATURAL := 58; -- ETH demux UDP port 1 + CONSTANT c_dut_udp_port_st2 : NATURAL := 59; -- ETH demux UDP port 2 + CONSTANT c_dut_udp_port_en : NATURAL := 16#10000#; -- ETH demux UDP port enable bit 16 + CONSTANT c_lcu_udp_port : NATURAL := 10; -- UDP port used for src_port + CONSTANT c_dut_udp_port_st : NATURAL := c_dut_udp_port_st0; -- UDP port used for dst_port + CONSTANT c_tb_udp_total_length : NATURAL := c_udp_total_length + c_tb_nof_data; + CONSTANT c_tx_udp_header : t_udp_header := (src_port => TO_UVEC(c_lcu_udp_port, c_udp_port_w), + dst_port => TO_UVEC(c_dut_udp_port_ctrl, c_udp_port_w), -- or use c_dut_udp_port_st# + total_length => TO_UVEC(c_tb_udp_total_length, c_udp_total_length_w), + checksum => TO_UVEC(c_udp_checksum, c_udp_checksum_w)); -- init value + + CONSTANT c_exp_udp_header : t_udp_header := (src_port => c_tx_udp_header.dst_port, -- \/ + dst_port => c_tx_udp_header.src_port, -- /\ + total_length => c_tx_udp_header.total_length, -- = + checksum => c_tx_udp_header.checksum); -- init value + + SIGNAL tx_total_header : t_eth_total_header; -- transmitted packet header + SIGNAL exp_total_header : t_eth_total_header; -- expected received packet header + + -- ETH control + CONSTANT c_dut_control_rx_en : NATURAL := 2**c_eth_mm_reg_control_bi.rx_en; + CONSTANT c_dut_control_tx_en : NATURAL := 2**c_eth_mm_reg_control_bi.tx_en; + + -- Clocks and reset + SIGNAL eth_clk : STD_LOGIC := '0'; -- tse reference clock + SIGNAL sys_clk : STD_LOGIC := '0'; -- system clock + SIGNAL st_clk : STD_LOGIC; -- stream clock + SIGNAL st_rst : STD_LOGIC := '1'; -- reset synchronous with st_clk + SIGNAL mm_clk : STD_LOGIC; -- memory-mapped bus clock + SIGNAL mm_rst : STD_LOGIC := '1'; -- reset synchronous with mm_clk + + -- ETH TSE interface + SIGNAL dut_tse_init : STD_LOGIC := '1'; + SIGNAL dut_eth_init : STD_LOGIC := '1'; + SIGNAL eth_tse_miso : t_mem_miso; + SIGNAL eth_tse_mosi : t_mem_mosi; + SIGNAL eth_psc_access : STD_LOGIC; + SIGNAL eth_txp : STD_LOGIC; + SIGNAL eth_rxp : STD_LOGIC; + SIGNAL eth_led : t_tse_led; + + -- ETH MM registers interface + SIGNAL eth_reg_miso : t_mem_miso; + SIGNAL eth_reg_mosi : t_mem_mosi; + SIGNAL eth_reg_interrupt : STD_LOGIC; + + SIGNAL eth_mm_reg_control : t_eth_mm_reg_control; + SIGNAL eth_mm_reg_status : t_eth_mm_reg_status; + + SIGNAL eth_ram_miso : t_mem_miso; + SIGNAL eth_ram_mosi : t_mem_mosi; + + -- ETH UDP data path interface + SIGNAL udp_tx_sosi_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + SIGNAL udp_tx_siso_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + SIGNAL udp_rx_siso_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + SIGNAL udp_rx_sosi_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + + + -- LCU TSE interface + SIGNAL lcu_init : STD_LOGIC := '1'; + SIGNAL lcu_tse_miso : t_mem_miso; + SIGNAL lcu_tse_mosi : t_mem_mosi; + SIGNAL lcu_psc_access : STD_LOGIC; + SIGNAL lcu_tx_en : STD_LOGIC := '1'; + SIGNAL lcu_tx_siso : t_dp_siso; + SIGNAL lcu_tx_sosi : t_dp_sosi; + SIGNAL lcu_tx_mac_in : t_tse_tx_mac; + SIGNAL lcu_tx_mac_out : t_tse_tx_mac; + SIGNAL lcu_rx_sosi : t_dp_sosi; + SIGNAL lcu_rx_siso : t_dp_siso; + SIGNAL lcu_rx_mac_out : t_tse_rx_mac; + SIGNAL lcu_txp : STD_LOGIC; + SIGNAL lcu_rxp : STD_LOGIC; + SIGNAL lcu_led : t_tse_led; + +BEGIN + + -- run 50 us + + eth_clk <= NOT eth_clk AFTER eth_clk_period/2; -- TSE reference clock + sys_clk <= NOT sys_clk AFTER sys_clk_period/2; -- System clock + + mm_clk <= sys_clk; + st_clk <= sys_clk; + + p_reset : PROCESS + BEGIN + -- reset release + st_rst <= '1'; + mm_rst <= '1'; + FOR I IN 0 TO 9 LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + mm_rst <= '0'; + WAIT UNTIL rising_edge(st_clk); + st_rst <= '0'; + FOR I IN 0 TO 9 LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + WAIT; + END PROCESS; + + -- Use signal to leave unused fields 'X' + tx_total_header.eth <= c_tx_eth_header; + tx_total_header.arp <= c_tx_arp_packet; + tx_total_header.ip <= c_tx_ip_header; + tx_total_header.icmp <= c_tx_icmp_header; + tx_total_header.udp <= c_tx_udp_header; + + exp_total_header.eth <= c_exp_eth_header; + exp_total_header.arp <= c_exp_arp_packet; + exp_total_header.ip <= c_exp_ip_header; + exp_total_header.icmp <= c_exp_icmp_header; + exp_total_header.udp <= c_exp_udp_header; + + ------------------------------------------------------------------------------ + -- DUT + ------------------------------------------------------------------------------ + p_tse_setup : PROCESS + BEGIN + dut_tse_init <= '1'; + eth_tse_mosi.wr <= '0'; + eth_tse_mosi.rd <= '0'; + -- Wait for ETH init + WHILE dut_eth_init='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + -- Setup the TSE MAC + proc_tse_setup(c_promis_en, c_tse_tx_fifo_depth, c_tse_rx_fifo_depth, c_tx_ready_latency, + c_dut_src_mac, eth_psc_access, + mm_clk, eth_tse_miso, eth_tse_mosi); + dut_tse_init <= '0'; + WAIT; + END PROCESS; + + + p_eth_control : PROCESS + VARIABLE v_eth_control_word : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + BEGIN + -- ETH setup + dut_eth_init <= '1'; + eth_reg_mosi.wr <= '0'; + eth_reg_mosi.rd <= '0'; + eth_ram_mosi.address <= (OTHERS=>'0'); + eth_ram_mosi.wr <= '0'; + eth_ram_mosi.rd <= '0'; + + -- Wait for reset release + WHILE mm_rst='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + + -- Setup the DEMUX UDP + proc_mem_mm_bus_wr(c_eth_reg_demux_wi+0, c_dut_udp_port_en+c_dut_udp_port_st0, mm_clk, eth_reg_miso, eth_reg_mosi); -- UDP port stream 0 + proc_mem_mm_bus_wr(c_eth_reg_demux_wi+1, c_dut_udp_port_en+c_dut_udp_port_st1, mm_clk, eth_reg_miso, eth_reg_mosi); -- UDP port stream 1 + proc_mem_mm_bus_wr(c_eth_reg_demux_wi+2, c_dut_udp_port_en+c_dut_udp_port_st2, mm_clk, eth_reg_miso, eth_reg_mosi); -- UDP port stream 2 + proc_mem_mm_bus_rd(c_eth_reg_demux_wi+0, mm_clk, eth_reg_miso, eth_reg_mosi); + proc_mem_mm_bus_rd(c_eth_reg_demux_wi+1, mm_clk, eth_reg_miso, eth_reg_mosi); + proc_mem_mm_bus_rd(c_eth_reg_demux_wi+2, mm_clk, eth_reg_miso, eth_reg_mosi); + + -- Setup the RX config + proc_mem_mm_bus_wr(c_eth_reg_config_wi+0, c_dut_src_mac_lo, mm_clk, eth_reg_miso, eth_reg_mosi); -- control MAC address lo word + proc_mem_mm_bus_wr(c_eth_reg_config_wi+1, c_dut_src_mac_hi, mm_clk, eth_reg_miso, eth_reg_mosi); -- control MAC address hi halfword + proc_mem_mm_bus_wr(c_eth_reg_config_wi+2, c_dut_ip_addr, mm_clk, eth_reg_miso, eth_reg_mosi); -- control IP address + proc_mem_mm_bus_wr(c_eth_reg_config_wi+3, c_dut_udp_port_ctrl, mm_clk, eth_reg_miso, eth_reg_mosi); -- control UDP port + -- Enable RX + proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, c_dut_control_rx_en, mm_clk, eth_reg_miso, eth_reg_mosi); -- control rx en + dut_eth_init <= '0'; + + -- Wait for TSE init + WHILE dut_tse_init='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + + -- Response control + WHILE TRUE LOOP + eth_mm_reg_status <= c_eth_mm_reg_status_rst; + eth_mm_reg_control <= c_eth_mm_reg_control_rst; + -- wait for rx_avail interrupt + IF eth_reg_interrupt='1' THEN + -- read status register to read the status + proc_mem_mm_bus_rd(c_eth_reg_status_wi+0, mm_clk, eth_reg_miso, eth_reg_mosi); -- read result available in eth_mm_reg_status + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); + eth_mm_reg_status <= func_eth_mm_reg_status(eth_reg_miso.rddata); + WAIT UNTIL rising_edge(mm_clk); + -- write status register to acknowledge the interrupt + proc_mem_mm_bus_wr(c_eth_reg_status_wi+0, 0, mm_clk, eth_reg_miso, eth_reg_mosi); -- void value + -- prepare control register for response + IF c_tb_reply_payload=TRUE THEN + eth_mm_reg_control.tx_nof_words <= INCR_UVEC(eth_mm_reg_status.rx_nof_words, -1); -- -1 to skip the CRC word for the response + eth_mm_reg_control.tx_empty <= eth_mm_reg_status.rx_empty; + ELSE + eth_mm_reg_control.tx_nof_words <= TO_UVEC(c_eth_total_header_nof_words, c_eth_max_frame_nof_words_w); + eth_mm_reg_control.tx_empty <= TO_UVEC(0, c_eth_empty_w); + END IF; + eth_mm_reg_control.tx_en <= '1'; + eth_mm_reg_control.rx_en <= '1'; + WAIT UNTIL rising_edge(mm_clk); + -- wait for interrupt removal due to status register read access + WHILE eth_reg_interrupt='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + -- write control register to enable tx + IF c_tb_reply_payload=TRUE THEN + -- . copy the received payload to the response payload (overwrite part of the default response header in case of raw ETH) + FOR I IN func_tb_tse_header_size(g_data_type) TO TO_UINT(eth_mm_reg_control.tx_nof_words)-1 LOOP + proc_mem_mm_bus_rd(c_eth_ram_rx_offset+I, mm_clk, eth_ram_miso, eth_ram_mosi); + proc_mem_mm_bus_rd_latency(c_mem_ram_rd_latency, mm_clk); + proc_mem_mm_bus_wr(c_eth_ram_tx_offset+I, TO_SINT(eth_ram_miso.rddata(c_word_w-1 DOWNTO 0)), mm_clk, eth_ram_miso, eth_ram_mosi); + END LOOP; + --ELSE + -- . only reply header + END IF; + v_eth_control_word := func_eth_mm_reg_control(eth_mm_reg_control); + proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, TO_UINT(v_eth_control_word), mm_clk, eth_reg_miso, eth_reg_mosi); + -- write continue register to make the ETH module continue + proc_mem_mm_bus_wr(c_eth_reg_continue_wi, 0, mm_clk, eth_reg_miso, eth_reg_mosi); -- void value + END IF; + WAIT UNTIL rising_edge(mm_clk); + END LOOP; + + WAIT; + END PROCESS; + + ------------------------------------------------------------------------------ + -- LCU + ------------------------------------------------------------------------------ + p_lcu_setup : PROCESS + BEGIN + lcu_init <= '1'; + lcu_tse_mosi.wr <= '0'; + lcu_tse_mosi.rd <= '0'; + -- Wait for reset release + WHILE mm_rst='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + -- Setup the LCU TSE MAC + proc_tse_setup(c_promis_en, c_tse_tx_fifo_depth, c_tse_rx_fifo_depth, c_tx_ready_latency, + c_lcu_src_mac, lcu_psc_access, + mm_clk, lcu_tse_miso, lcu_tse_mosi); + -- Wait for DUT init done + WHILE dut_tse_init/='0' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + lcu_init <= '0'; + WAIT; + END PROCESS; + + p_lcu_transmitter : PROCESS + BEGIN + -- . Avalon ST + lcu_tx_sosi.data <= (OTHERS=>'0'); + lcu_tx_sosi.valid <= '0'; + lcu_tx_sosi.sop <= '0'; + lcu_tx_sosi.eop <= '0'; + lcu_tx_sosi.empty <= (OTHERS=>'0'); + lcu_tx_sosi.err <= (OTHERS=>'0'); + -- . MAC specific + lcu_tx_mac_in.crc_fwd <= '0'; -- when '0' then TSE MAC generates the TX CRC field + + WHILE lcu_init/='0' LOOP WAIT UNTIL rising_edge(st_clk); END LOOP; + FOR I IN 0 TO 9 LOOP WAIT UNTIL rising_edge(st_clk); END LOOP; + +-- proc_tse_tx_packet(tx_total_header, 100, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); + FOR I IN 0 TO 40 LOOP + proc_tse_tx_packet(tx_total_header, I, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); + --FOR J IN 0 TO 9 LOOP WAIT UNTIL rising_edge(st_clk); END LOOP; + END LOOP; +-- proc_tse_tx_packet(tx_total_header, 104, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 105, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 1472, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 101, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 1000, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 102, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 1000, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 103, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 104, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); +-- proc_tse_tx_packet(tx_total_header, 105, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi); + + WAIT; + END PROCESS; + + + p_lcu_receiver : PROCESS + BEGIN + -- . Avalon ST + lcu_rx_siso <= c_dp_siso_hold; + + WHILE lcu_init/='0' LOOP WAIT UNTIL rising_edge(st_clk); END LOOP; + + -- Verification of multiple rx packets is only supported when all packets + -- are of the same g_data_type, because the rx process can only support + -- one expected result. The proc_tse_rx_packet does not (yet) interpret the + -- actually received packet, it relies on the preset expected total_header. + + -- Receive forever + WHILE TRUE LOOP + proc_tse_rx_packet(exp_total_header, g_data_type, st_clk, lcu_rx_sosi, lcu_rx_siso); + END LOOP; + + WAIT; + END PROCESS; + + -- Wire ethernet cable between lcu and dut + eth_rxp <= TRANSPORT lcu_txp AFTER cable_delay; + lcu_rxp <= TRANSPORT eth_txp AFTER cable_delay; + + gen_udp_rx_siso_rdy: FOR i IN 0 TO c_eth_nof_udp_ports-1 GENERATE + udp_rx_siso_arr(i).ready <= '1'; + END GENERATE; + + dut : ENTITY work.eth + GENERIC MAP ( + g_cross_clock_domain => c_cross_clock_domain + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + eth_clk => eth_clk, + st_rst => st_rst, + st_clk => st_clk, + -- UDP transmit interface + -- . ST sink + udp_tx_snk_in_arr => udp_tx_sosi_arr, + udp_tx_snk_out_arr => udp_tx_siso_arr, + -- UDP receive interface + -- . ST source + udp_rx_src_in_arr => udp_rx_siso_arr, + udp_rx_src_out_arr => udp_rx_sosi_arr, + -- Control Memory Mapped Slaves + tse_sla_in => eth_tse_mosi, + tse_sla_out => eth_tse_miso, + reg_sla_in => eth_reg_mosi, + reg_sla_out => eth_reg_miso, + reg_sla_interrupt => eth_reg_interrupt, + ram_sla_in => eth_ram_mosi, + ram_sla_out => eth_ram_miso, + -- PHY interface + eth_txp => eth_txp, + eth_rxp => eth_rxp, + -- LED interface + tse_led => eth_led + ); + + lcu : ENTITY work.tse + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + eth_clk => eth_clk, + tx_snk_clk => st_clk, + rx_src_clk => st_clk, + + -- Memory Mapped Slave + mm_sla_in => lcu_tse_mosi, + mm_sla_out => lcu_tse_miso, + + -- MAC transmit interface + -- . ST sink + tx_snk_in => lcu_tx_sosi, + tx_snk_out => lcu_tx_siso, + -- . MAC specific + tx_mac_in => lcu_tx_mac_in, + tx_mac_out => lcu_tx_mac_out, + + -- MAC receive interface + -- . ST Source + rx_src_in => lcu_rx_siso, + rx_src_out => lcu_rx_sosi, + -- . MAC specific + rx_mac_out => lcu_rx_mac_out, + + -- PHY interface + eth_txp => lcu_txp, + eth_rxp => lcu_rxp, + + tse_led => lcu_led + ); + +END tb; diff --git a/libraries/io/eth/tb/vhdl/tb_eth_udp_offload.vhd b/libraries/io/eth/tb/vhdl/tb_eth_udp_offload.vhd new file mode 100644 index 0000000000000000000000000000000000000000..a4067eb15d17a857304b0ea4080fdfb340519cb4 --- /dev/null +++ b/libraries/io/eth/tb/vhdl/tb_eth_udp_offload.vhd @@ -0,0 +1,486 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, tech_tse_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE common_lib.common_str_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; +USE tech_tse_lib.tb_tech_tse_pkg.ALL; +USE WORK.eth_layers_pkg.ALL; +USE WORK.eth_pkg.ALL; + +ENTITY tb_eth_udp_offload IS + GENERIC ( + g_data_w : NATURAL := c_word_w; + g_symbol_w : NATURAL := 8; + g_in_en : t_dp_flow_control_enum := e_random + ); +END tb_eth_udp_offload; + + +ARCHITECTURE tb OF tb_eth_udp_offload IS + + -- tb default + CONSTANT c_rl : NATURAL := 1; + CONSTANT c_pulse_active : NATURAL := 1; + CONSTANT c_pulse_period : NATURAL := 7; + + -- tb specific + CONSTANT c_nof_repeat : NATURAL := 10; + CONSTANT c_bsn_w : NATURAL := 16; + CONSTANT c_symbol_init : NATURAL := 0; + CONSTANT c_symbol_mod : INTEGER := 2**g_symbol_w; -- used to avoid TO_UVEC warning for smaller g_symbol_w : "NUMERIC_STD.TO_UNSIGNED: vector truncated" + CONSTANT c_err_init : NATURAL := 0; + CONSTANT c_sync_period : NATURAL := 7; + CONSTANT c_sync_offset : NATURAL := 2; + + -- clock and reset + CONSTANT c_mm_clk_period : TIME := 20 ns; + CONSTANT c_st_clk_period : TIME := 5 ns; + CONSTANT c_eth_clk_period : TIME := 8 ns; -- 125 MHz + + -- ETH CONSTANTS + -- =========================================================================================================================================================== + + -- Payload user data + CONSTANT c_tb_nof_data : NATURAL := 1440; -- nof UDP user data, nof ping padding data. NOTE: non-multiples of g_data_w/g_symbol_w not supported as dp_packet_enc/dec do not support encoding/decoding empty + CONSTANT c_tb_ip_nof_data : NATURAL := c_udp_header_len + c_tb_nof_data; -- nof IP data, + + -- Headers + -- . Ethernet header + CONSTANT c_word_align : STD_LOGIC_VECTOR(c_eth_word_align_w-1 DOWNTO 0) := TO_UVEC(c_eth_word_align, c_eth_word_align_w); + CONSTANT c_lcu_src_mac : STD_LOGIC_VECTOR(c_eth_mac_slv'RANGE) := X"10FA01020300"; + CONSTANT c_dut_src_mac : STD_LOGIC_VECTOR(c_eth_mac_slv'RANGE) := X"123456789ABC"; -- = 12-34-56-78-9A-BC + CONSTANT c_dut_src_mac_hi : NATURAL := TO_UINT(c_dut_src_mac(c_eth_mac_addr_w-1 DOWNTO c_word_w)); + CONSTANT c_dut_src_mac_lo : NATURAL := TO_UINT(c_dut_src_mac( c_word_w-1 DOWNTO 0)); + + CONSTANT c_tx_eth_header : t_eth_header := (word_align => c_word_align, + dst_mac => c_dut_src_mac, + src_mac => c_lcu_src_mac, + eth_type => TO_UVEC(c_eth_type_ip, c_eth_type_w)); --TO_UVEC(c_dut_ethertype, c_eth_type_w)); + -- . IP header + CONSTANT c_lcu_ip_addr : NATURAL := 16#05060708#; -- = 05:06:07:08 + CONSTANT c_dut_ip_addr : NATURAL := 16#01020304#; + CONSTANT c_tb_ip_total_length : NATURAL := c_ip_total_length + c_tb_ip_nof_data; + -- support only ping protocol or UDP protocol over IP + CONSTANT c_tb_ip_protocol : NATURAL := c_ip_protocol_udp; --sel_a_b(g_data_type-c_tb_tse_data_type_ping, c_ip_protocol_udp, c_ip_protocol_icmp); + + CONSTANT c_tx_ip_header : t_ip_header := (version => TO_UVEC(c_ip_version, c_ip_version_w), + header_length => TO_UVEC(c_ip_header_length, c_ip_header_length_w), + services => TO_UVEC(c_ip_services, c_ip_services_w), + total_length => TO_UVEC(c_tb_ip_total_length, c_ip_total_length_w), + identification => TO_UVEC(c_ip_identification, c_ip_identification_w), + flags => TO_UVEC(c_ip_flags, c_ip_flags_w), + fragment_offset => TO_UVEC(c_ip_fragment_offset, c_ip_fragment_offset_w), + time_to_live => TO_UVEC(c_ip_time_to_live, c_ip_time_to_live_w), + protocol => TO_UVEC(c_tb_ip_protocol, c_ip_protocol_w), + header_checksum => TO_UVEC(c_ip_header_checksum, c_ip_header_checksum_w), -- init value (or try 0xEBBD = 60349) + src_ip_addr => TO_UVEC(c_lcu_ip_addr, c_ip_addr_w), + dst_ip_addr => TO_UVEC(c_dut_ip_addr, c_ip_addr_w)); + + -- . UDP header + CONSTANT c_dut_udp_port_ctrl : NATURAL := 11; -- ETH demux UDP for control + CONSTANT c_dut_udp_port_st0 : NATURAL := 57; -- ETH demux UDP port 0 + CONSTANT c_dut_udp_port_st1 : NATURAL := 58; -- ETH demux UDP port 1 + CONSTANT c_dut_udp_port_st2 : NATURAL := 59; -- ETH demux UDP port 2 + CONSTANT c_dut_udp_port_en : NATURAL := 16#10000#; -- ETH demux UDP port enable bit 16 + CONSTANT c_lcu_udp_port : NATURAL := 10; -- UDP port used for src_port + CONSTANT c_dut_udp_port_st : NATURAL := c_dut_udp_port_st0; -- UDP port used for dst_port + CONSTANT c_tb_udp_total_length : NATURAL := c_udp_total_length + c_tb_nof_data; + CONSTANT c_tx_udp_header : t_udp_header := (src_port => TO_UVEC(c_lcu_udp_port, c_udp_port_w), + dst_port => TO_UVEC(c_dut_udp_port_st, c_udp_port_w), -- or use c_dut_udp_port_ctrl + total_length => TO_UVEC(c_tb_udp_total_length, c_udp_total_length_w), + checksum => TO_UVEC(c_udp_checksum, c_udp_checksum_w)); -- init value + + CONSTANT c_total_hdr_slv : STD_LOGIC_VECTOR(c_eth_total_header_nof_words*c_word_w-1 DOWNTO 0) := c_tx_eth_header.word_align & + c_tx_eth_header.dst_mac & + c_tx_eth_header.src_mac & + c_tx_eth_header.eth_type & + c_tx_ip_header.version & + c_tx_ip_header.header_length & + c_tx_ip_header.services & + c_tx_ip_header.total_length & + c_tx_ip_header.identification & + c_tx_ip_header.flags & + c_tx_ip_header.fragment_offset & + c_tx_ip_header.time_to_live & + c_tx_ip_header.protocol & + c_tx_ip_header.header_checksum & + c_tx_ip_header.src_ip_addr & + c_tx_ip_header.dst_ip_addr & + c_tx_udp_header.src_port & + c_tx_udp_header.dst_port & + c_tx_udp_header.total_length & + c_tx_udp_header.checksum; + + -- =========================================================================================================================================================== + + -- TSE constants + CONSTANT c_promis_en : BOOLEAN := FALSE; + CONSTANT c_tx_ready_latency : NATURAL := c_tse_tx_ready_latency; -- 0, 1 are supported, must match TSE MAC c_tse_tx_ready_latency + + -- ETH control + CONSTANT c_dut_control_rx_en : NATURAL := 2**c_eth_mm_reg_control_bi.rx_en; + + -- ETH TSE interface + SIGNAL eth_psc_access : STD_LOGIC; + + SIGNAL tb_eth_hdr : t_eth_header := c_tx_eth_header; + SIGNAL tb_ip_hdr : t_ip_header := c_tx_ip_header; + SIGNAL tb_udp_hdr : t_udp_header := c_tx_udp_header; + + SIGNAL eth_clk : STD_LOGIC := '0'; -- tse reference clock + SIGNAL mm_clk : STD_LOGIC := '0'; + SIGNAL mm_rst : STD_LOGIC; + SIGNAL st_rst : STD_LOGIC; + SIGNAL st_clk : STD_LOGIC := '0'; + + SIGNAL tb_end : STD_LOGIC := '0'; + + SIGNAL random_0 : STD_LOGIC_VECTOR(14 DOWNTO 0) := (OTHERS=>'0'); -- use different lengths to have different random sequences + SIGNAL random_1 : STD_LOGIC_VECTOR(15 DOWNTO 0) := (OTHERS=>'0'); -- use different lengths to have different random sequences + SIGNAL pulse_0 : STD_LOGIC; + SIGNAL pulse_1 : STD_LOGIC; + SIGNAL pulse_en : STD_LOGIC := '1'; + + SIGNAL in_en : STD_LOGIC := '1'; + + -- tb verify + SIGNAL verify_en : STD_LOGIC := '0'; + SIGNAL verify_done : STD_LOGIC := '0'; + + SIGNAL prev_udp_rx_ready : STD_LOGIC_VECTOR(0 TO c_rl); + SIGNAL prev_udp_rx_data : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0); + + SIGNAL out_gap : STD_LOGIC := '1'; + + -- dp_hdr_insert/remove signals + SIGNAL reg_hdr_mosi : t_mem_mosi; + SIGNAL ram_hdr_mosi : t_mem_mosi; + SIGNAL ram_hdr_miso : t_mem_miso; + + -- ETH TSE interface + SIGNAL eth_tse_miso : t_mem_miso; + SIGNAL eth_tse_mosi : t_mem_mosi; + SIGNAL eth_serial_loopback : STD_LOGIC; + + -- ETH UDP data path from tx generation to rx verification + SIGNAL udp_tx_sosi : t_dp_sosi; + SIGNAL udp_tx_siso : t_dp_siso; + + SIGNAL udp_tx_pkt_sosi : t_dp_sosi; + SIGNAL udp_tx_pkt_siso : t_dp_siso; + + SIGNAL udp_tx_hdr_pkt_sosi_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + SIGNAL udp_tx_hdr_pkt_siso_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + + SIGNAL udp_rx_frame_pkt_siso_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + SIGNAL udp_rx_frame_pkt_sosi_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0); + + SIGNAL udp_rx_pkt_siso : t_dp_siso; + SIGNAL udp_rx_pkt_sosi : t_dp_sosi; + + SIGNAL udp_rx_siso : t_dp_siso; + SIGNAL udp_rx_sosi : t_dp_sosi; + + -- ETH MM registers interface + SIGNAL eth_reg_miso : t_mem_miso; + SIGNAL eth_reg_mosi : t_mem_mosi; + SIGNAL eth_reg_interrupt : STD_LOGIC; + + SIGNAL eth_ram_miso : t_mem_miso; + SIGNAL eth_ram_mosi : t_mem_mosi; + + SIGNAL dut_eth_init : STD_LOGIC := '1'; + SIGNAL dut_tse_init : STD_LOGIC := '1'; + +BEGIN + + mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2; + mm_rst <= '1', '0' AFTER c_mm_clk_period*20; + + st_clk <= (NOT st_clk) OR tb_end AFTER c_st_clk_period/2; + st_rst <= '1', '0' AFTER c_st_clk_period*7; + + eth_clk <= NOT eth_clk OR tb_end AFTER c_eth_clk_period/2; -- TSE reference clock + + random_0 <= func_common_random(random_0) WHEN rising_edge(st_clk); + random_1 <= func_common_random(random_1) WHEN rising_edge(st_clk); + + proc_common_gen_duty_pulse(c_pulse_active, c_pulse_period, '1', st_rst, st_clk, pulse_en, pulse_0); + proc_common_gen_duty_pulse(c_pulse_active, c_pulse_period+1, '1', st_rst, st_clk, pulse_en, pulse_1); + + ------------------------------------------------------------------------------ + -- STREAM CONTROL + ------------------------------------------------------------------------------ + + in_en <= '1' WHEN g_in_en=e_active ELSE + random_0(random_0'HIGH) WHEN g_in_en=e_random ELSE + pulse_0 WHEN g_in_en=e_pulse; + + udp_rx_siso.ready <= '1'; + udp_rx_siso.xon <= '1'; + + ------------------------------------------------------------------------------ + -- TSE SETUP + ------------------------------------------------------------------------------ + p_tse_setup : PROCESS + BEGIN + dut_tse_init <= '1'; + eth_tse_mosi.wr <= '0'; + eth_tse_mosi.rd <= '0'; + -- Wait for ETH init + WHILE dut_eth_init='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + -- Setup the TSE MAC + proc_tse_setup(c_promis_en, c_tse_tx_fifo_depth, c_tse_rx_fifo_depth, c_tx_ready_latency, + c_dut_src_mac, eth_psc_access, + mm_clk, eth_tse_miso, eth_tse_mosi); + dut_tse_init <= '0'; + WAIT; + END PROCESS; + + + ------------------------------------------------------------------------------ + -- DATA GENERATION + ------------------------------------------------------------------------------ + + -- Generate data path input data + p_stimuli : PROCESS + VARIABLE v_sync : STD_LOGIC := '0'; + VARIABLE v_bsn : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); + VARIABLE v_symbol : NATURAL := c_symbol_init; + VARIABLE v_channel : NATURAL := 1; + VARIABLE v_err : NATURAL := c_err_init; + + VARIABLE v_mm_wr_addr : NATURAL := 0; + VARIABLE v_mm_wr_hdr : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + BEGIN + udp_tx_sosi <= c_dp_sosi_rst; + reg_hdr_mosi <= c_mem_mosi_rst; + ram_hdr_mosi <= c_mem_mosi_rst; + eth_reg_mosi <= c_mem_mosi_rst; + + dut_eth_init <= '1'; + + proc_common_wait_until_low(mm_clk, mm_rst); + proc_common_wait_some_cycles(mm_clk, 5); + + -- Set up the UDP demux + proc_mem_mm_bus_wr(c_eth_reg_demux_wi+0, c_dut_udp_port_en+c_dut_udp_port_st0, mm_clk, eth_reg_miso, eth_reg_mosi); -- UDP port stream 0 + proc_common_wait_some_cycles(mm_clk, 5); + + -- Setup the RX config + proc_mem_mm_bus_wr(c_eth_reg_config_wi+0, c_dut_src_mac_lo, mm_clk, eth_reg_miso, eth_reg_mosi); -- control MAC address lo word + proc_mem_mm_bus_wr(c_eth_reg_config_wi+1, c_dut_src_mac_hi, mm_clk, eth_reg_miso, eth_reg_mosi); -- control MAC address hi halfword + proc_mem_mm_bus_wr(c_eth_reg_config_wi+2, c_dut_ip_addr, mm_clk, eth_reg_miso, eth_reg_mosi); -- control IP address + proc_mem_mm_bus_wr(c_eth_reg_config_wi+3, c_dut_udp_port_ctrl, mm_clk, eth_reg_miso, eth_reg_mosi); -- control UDP port + -- Enable RX + proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, c_dut_control_rx_en, mm_clk, eth_reg_miso, eth_reg_mosi); -- control rx en + dut_eth_init <= '0'; + + -- MM Stimuli: write HEADER to RAM + FOR i IN c_eth_total_header_nof_words DOWNTO 1 LOOP + -- Extract words from SLV from left to right + v_mm_wr_hdr := c_total_hdr_slv(i*c_word_w-1 DOWNTO i*c_word_w - c_word_w); + proc_mem_mm_bus_wr(v_mm_wr_addr, v_mm_wr_hdr, mm_clk, ram_hdr_mosi); + proc_common_wait_some_cycles(mm_clk, 5); + + IF v_mm_wr_addr<c_eth_total_header_nof_words-1 THEN + v_mm_wr_addr := v_mm_wr_addr + 1; + END IF; + END LOOP; + + -- Release the header onto the DP + proc_mem_mm_bus_wr(0, 1, mm_clk, reg_hdr_mosi); + + -- Begin of ST stimuli + proc_common_wait_until_low(st_clk, st_rst); + proc_common_wait_some_cycles(st_clk, 50); + + FOR R IN 0 TO c_nof_repeat-1 LOOP + v_sync := sel_a_b(R MOD c_sync_period = c_sync_offset, '1', '0'); -- v_bsn = R + proc_dp_gen_block_data(c_rl, TRUE, g_data_w, g_symbol_w, v_symbol, 0, 0, c_tb_nof_data, v_channel, v_err, v_sync, TO_DP_BSN(R), st_clk, in_en, udp_tx_siso, udp_tx_sosi); + v_bsn := INCR_UVEC(v_bsn, 1); + v_symbol := (v_symbol + c_tb_nof_data) MOD c_symbol_mod; + v_err := v_err + 1; + --proc_common_wait_some_cycles(st_clk, 10); -- create gap between frames + END LOOP; + + -- End of stimuli + proc_common_wait_some_cycles(st_clk, 50); -- depends on stream control + verify_done <= '1'; + proc_common_wait_some_cycles(st_clk, 1); + verify_done <= '0'; + + -- Resync to MM clk + proc_common_wait_some_cycles(mm_clk, 5); + + -- Read the stripped header via MM bus and print it in the transcript window + print_str("Reading stripped header from RAM:"); + FOR i IN 0 TO c_eth_total_header_nof_words-1 LOOP + proc_mem_mm_bus_rd(i, mm_clk, ram_hdr_mosi); + proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); + print_str("[" & time_to_str(now) & "] 0x" & slv_to_hex(ram_hdr_miso.rddata(c_word_w-1 DOWNTO 0))); + END LOOP; + + proc_common_wait_some_cycles(st_clk, 10); + tb_end <= '1'; + WAIT; + END PROCESS; + + ------------------------------------------------------------------------------ + -- DATA VERIFICATION + ------------------------------------------------------------------------------ + + verify_en <= '1' WHEN rising_edge(st_clk) AND udp_rx_sosi.sop='1'; -- verify enable after first output sop + + -- SOSI control + proc_dp_verify_valid(c_rl, st_clk, verify_en, udp_rx_siso.ready, prev_udp_rx_ready, udp_rx_sosi.valid); -- Verify that the output valid fits with the output ready latency + proc_dp_verify_gap_invalid(st_clk, udp_rx_sosi.valid, udp_rx_sosi.sop, udp_rx_sosi.eop, out_gap); -- Verify that the output valid is low between blocks from eop to sop + + -- SOSI data + -- . verify that the output is incrementing symbols, like the input stimuli + proc_dp_verify_symbols(c_rl, g_data_w, g_symbol_w, st_clk, verify_en, udp_rx_siso.ready, udp_rx_sosi.valid, udp_rx_sosi.eop, udp_rx_sosi.data(g_data_w-1 DOWNTO 0), udp_rx_sosi.empty, prev_udp_rx_data); + + ------------------------------------------------------------------------------ + -- DUT + ------------------------------------------------------------------------------ + dut : ENTITY work.eth + GENERIC MAP ( + g_cross_clock_domain => TRUE + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + eth_clk => eth_clk, + st_rst => st_rst, + st_clk => st_clk, + -- UDP transmit interface + -- . ST sink + udp_tx_snk_in_arr => udp_tx_hdr_pkt_sosi_arr, + udp_tx_snk_out_arr => udp_tx_hdr_pkt_siso_arr, + -- UDP receive interface + -- . ST source + udp_rx_src_in_arr => udp_rx_frame_pkt_siso_arr, + udp_rx_src_out_arr => udp_rx_frame_pkt_sosi_arr, + -- Control Memory Mapped Slaves + tse_sla_in => eth_tse_mosi, + tse_sla_out => eth_tse_miso, + reg_sla_in => eth_reg_mosi, + reg_sla_out => eth_reg_miso, + reg_sla_interrupt => eth_reg_interrupt, + ram_sla_in => eth_ram_mosi, + ram_sla_out => eth_ram_miso, + -- PHY interface + eth_txp => eth_serial_loopback, + eth_rxp => eth_serial_loopback, + -- LED interface + tse_led => OPEN + ); + + u_hdr_insert : ENTITY dp_lib.dp_hdr_insert + GENERIC MAP ( + g_data_w => g_data_w, + g_symbol_w => g_symbol_w, + g_hdr_nof_words => c_eth_total_header_nof_words + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + st_rst => st_rst, + st_clk => st_clk, + + reg_mosi => reg_hdr_mosi, + ram_mosi => ram_hdr_mosi, + + snk_out => udp_tx_pkt_siso, + snk_in => udp_tx_pkt_sosi, + + src_in => udp_tx_hdr_pkt_siso_arr(0), + src_out => udp_tx_hdr_pkt_sosi_arr(0) + ); + + u_dp_packet_enc : ENTITY dp_lib.dp_packet_enc + GENERIC MAP ( + g_data_w => g_data_w + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + + snk_out => udp_tx_siso, + snk_in => udp_tx_sosi, + + src_in => udp_tx_pkt_siso, + src_out => udp_tx_pkt_sosi + ); + + u_frame_remove : ENTITY dp_lib.dp_frame_remove + GENERIC MAP ( + g_data_w => g_data_w, + g_symbol_w => g_symbol_w, + g_hdr_nof_words => c_eth_total_header_nof_words, + g_tail_nof_words=> (c_eth_crc_len * g_symbol_w) / c_word_w + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + st_rst => st_rst, + st_clk => st_clk, + + snk_out => udp_rx_frame_pkt_siso_arr(0), + snk_in => udp_rx_frame_pkt_sosi_arr(0), + + sla_in => ram_hdr_mosi, + sla_out => ram_hdr_miso, + + src_in => udp_rx_pkt_siso, + src_out => udp_rx_pkt_sosi + ); + + u_dp_packet_dec : ENTITY dp_lib.dp_packet_dec + GENERIC MAP ( + g_data_w => g_data_w + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + + snk_out => udp_rx_pkt_siso, + snk_in => udp_rx_pkt_sosi, + + src_in => udp_rx_siso, + src_out => udp_rx_sosi + ); + +END tb; diff --git a/libraries/io/eth/tb/vhdl/tb_tb_eth.vhd b/libraries/io/eth/tb/vhdl/tb_tb_eth.vhd new file mode 100644 index 0000000000000000000000000000000000000000..38fd02194b65992d4aaf760ca267c80860b37082 --- /dev/null +++ b/libraries/io/eth/tb/vhdl/tb_tb_eth.vhd @@ -0,0 +1,44 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, tech_tse_lib; +USE IEEE.std_logic_1164.ALL; +USE tech_tse_lib.tb_tech_tse_pkg.ALL; + + +ENTITY tb_tb_eth IS +END tb_tb_eth; + + +ARCHITECTURE tb OF tb_tb_eth IS + +BEGIN + + -- Try ETH settings : GENERIC MAP (g_data_type => ) + + u_use_symbols : ENTITY work.tb_eth GENERIC MAP (c_tb_tse_data_type_symbols); + u_use_counter : ENTITY work.tb_eth GENERIC MAP (c_tb_tse_data_type_counter); + u_use_arp : ENTITY work.tb_eth GENERIC MAP (c_tb_tse_data_type_arp ); + u_use_ping : ENTITY work.tb_eth GENERIC MAP (c_tb_tse_data_type_ping ); + u_use_udp : ENTITY work.tb_eth GENERIC MAP (c_tb_tse_data_type_udp ); + +END tb;