diff --git a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_I/unb2c_test_1GbE_I.vhd b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_I/unb2c_test_1GbE_I.vhd
index 5df27443699abb821c26211f077555e86edcc8fd..8fe2c8d809f201a13c179274d48bc3b081a745cf 100644
--- a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_I/unb2c_test_1GbE_I.vhd
+++ b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_I/unb2c_test_1GbE_I.vhd
@@ -1,6 +1,6 @@
 -------------------------------------------------------------------------------
 --
--- Copyright (C) 2015
+-- Copyright (C) 2022
 -- 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
@@ -20,6 +20,10 @@
 --
 -------------------------------------------------------------------------------
 
+-- Author: Eric Kooistra
+-- Purpose: Test 1GbE-I port using eth_tester
+-- Description:
+
 LIBRARY IEEE, common_lib, unb2c_board_lib, unb2c_test_lib, technology_lib;
 USE IEEE.STD_LOGIC_1164.ALL;
 USE IEEE.NUMERIC_STD.ALL;
diff --git a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/hdllib.cfg b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..93f2cfd2d1fcbb058726abb1094786100b447788
--- /dev/null
+++ b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/hdllib.cfg
@@ -0,0 +1,111 @@
+hdl_lib_name = unb2c_test_1GbE_II
+hdl_library_clause_name = unb2c_test_1GbE_II_lib
+hdl_lib_uses_synth = common mm technology unb2c_board unb2c_test
+hdl_lib_uses_sim = 
+hdl_lib_technology = ip_arria10_e2sg
+hdl_lib_include_ip = 
+
+synth_files =
+    unb2c_test_1GbE_II.vhd
+
+test_bench_files = 
+    tb_unb2c_test_1GbE_II.vhd
+
+regression_test_vhdl =
+
+
+[modelsim_project_file]
+modelsim_copy_files =
+
+
+[quartus_project_file]
+synth_top_level_entity =
+
+quartus_copy_files =
+    quartus .
+    ../../quartus .
+
+quartus_qsf_files =
+    $RADIOHDL_WORK/boards/uniboard2c/libraries/unb2c_board/quartus/unb2c_board.qsf
+
+quartus_sdc_pre_files =
+    $RADIOHDL_WORK/boards/uniboard2c/libraries/unb2c_board/quartus/unb2c_board_pre.sdc
+
+quartus_sdc_files =
+    $RADIOHDL_WORK/boards/uniboard2c/libraries/unb2c_board/quartus/unb2c_board.sdc
+
+quartus_tcl_files =
+    quartus/unb2c_test_1GbE_II_pins.tcl
+
+quartus_vhdl_files = 
+
+quartus_qip_files =
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/qsys_unb2c_test/qsys_unb2c_test.qip
+
+quartus_ip_files =
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_avs2_eth_coe_0.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_avs2_eth_coe_1.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_clk_0.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_jesd204b.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_jtag_uart_0.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_nios2_gen2_0.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_onchip_memory2_0.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_pio_jesd_ctrl.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_pio_pps.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_pio_system_info.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_pio_wdi.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_ram_diag_bg_10gbe.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_ram_diag_data_buffer_10gbe.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_ram_diag_data_buffer_bsn.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_ram_diag_data_buffer_ddr_MB_II.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_ram_diag_data_buffer_ddr_MB_I.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_ram_scrap.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_bsn_monitor_10GbE.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_bsn_monitor_input.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_bsn_scheduler.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_bsn_source.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_bg_10gbe.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_data_buffer_10gbe.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_data_buffer_bsn.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_data_buffer_ddr_MB_II.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_data_buffer_ddr_MB_I.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_rx_seq_10gbe.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_rx_seq_ddr_MB_II.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_rx_seq_ddr_MB_I.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_tx_seq_10gbe.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_tx_seq_ddr_MB_II.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_diag_tx_seq_ddr_MB_I.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_dpmm_ctrl.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_dpmm_data.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_epcs.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth10g_back0.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth10g_back1.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth10g_qsfp_ring.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_fpga_temp_sens.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_fpga_voltage_sens.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_heater.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_io_ddr_MB_II.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_io_ddr_MB_I.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_mmdp_ctrl.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_mmdp_data.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_remu.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_tr_10GbE_back0.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_tr_10GbE_back1.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_tr_10GbE_qsfp_ring.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_wdi.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_rom_system_info.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_timer_0.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_I_bg_ctrl.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_I_hdr_dat.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_I_bsn_monitor_v2_tx.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_I_strobe_total_count_tx.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_I_bsn_monitor_v2_rx.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_I_strobe_total_count_rx.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_II_bg_ctrl.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_II_hdr_dat.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_II_bsn_monitor_v2_tx.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_II_bsn_monitor_v2_rx.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_II_strobe_total_count_tx.ip
+    $RADIOHDL_BUILD_DIR/unb2c/quartus/unb2c_test_1GbE_II/ip/qsys_unb2c_test/qsys_unb2c_test_reg_eth1g_II_strobe_total_count_rx.ip
+
+nios2_app_userflags = -DCOMPILE_FOR_GEN2_UNB2
diff --git a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/quartus/unb2c_test_1GbE_II_pins.tcl b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/quartus/unb2c_test_1GbE_II_pins.tcl
new file mode 100644
index 0000000000000000000000000000000000000000..ae417258f888c910d593c6ab6e5117615ebbd36f
--- /dev/null
+++ b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/quartus/unb2c_test_1GbE_II_pins.tcl
@@ -0,0 +1,22 @@
+###############################################################################
+#
+# Copyright (C) 2014
+# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.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/>.
+#
+###############################################################################
+
+source $::env(RADIOHDL_WORK)/boards/uniboard2c/libraries/unb2c_board/quartus/pinning/unb2c_minimal_pins.tcl
diff --git a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/tb_unb2c_test_1GbE_II.vhd b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/tb_unb2c_test_1GbE_II.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..fc35af7ba0e294874eb7bd5a57ba6e401401a871
--- /dev/null
+++ b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/tb_unb2c_test_1GbE_II.vhd
@@ -0,0 +1,83 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2022
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- Author: E. Kooistra
+-- Purpose: Tb to try loading design in simulator
+-- Description:
+-- Usage:
+-- > run 1 us.
+
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+
+
+ENTITY tb_unb2c_test_1GbE_II IS
+END tb_unb2c_test_1GbE_II;
+
+
+ARCHITECTURE tb OF tb_unb2c_test_1GbE_II IS
+
+  SIGNAL clk  : STD_LOGIC := '0';
+  SIGNAL pps  : STD_LOGIC := '0';
+  SIGNAL wdi  : STD_LOGIC := '0';
+
+  SIGNAL eth_clk   : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00";
+  SIGNAL eth_sgin  : STD_LOGIC_VECTOR(1 DOWNTO 0);
+  SIGNAL eth_sgout : STD_LOGIC_VECTOR(1 DOWNTO 0);
+
+BEGIN
+
+  clk <= NOT clk AFTER 5 ns;
+  eth_clk(0) <= NOT eth_clk(0) AFTER 8 ns;
+  eth_clk(1) <= NOT eth_clk(1) AFTER 8 ns;
+
+  eth_sgin <= eth_sgout;  -- loopback eth0 and eth1
+
+  u_unb2c_test_1GbE_II : ENTITY work.unb2c_test_1GbE_II
+  GENERIC MAP (
+    g_sim        => TRUE
+  )
+  PORT MAP (
+    -- GENERAL
+    CLK          => clk,
+    PPS          => pps,
+    WDI          => wdi,
+    INTA         => OPEN,
+    INTB         => OPEN,
+
+    -- Others
+    VERSION      => "00",
+    ID           => "00000000",
+    TESTIO       => OPEN,
+
+
+    -- 1GbE Control Interface
+    ETH_CLK      => eth_clk,
+    ETH_SGIN     => eth_sgin,
+    ETH_SGOUT    => eth_sgout,
+
+    QSFP_LED     => OPEN
+  );
+
+END tb;
+
diff --git a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/unb2c_test_1GbE_II.vhd b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/unb2c_test_1GbE_II.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..8448d4f3167e3be5b38525bddd746b87345a191d
--- /dev/null
+++ b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_1GbE_II/unb2c_test_1GbE_II.vhd
@@ -0,0 +1,105 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2022
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Author: Eric Kooistra
+-- Purpose: Test both 1GbE-I and 1GbE-II ports using eth_tester
+-- Description:
+
+LIBRARY IEEE, common_lib, unb2c_board_lib, unb2c_test_lib, technology_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+USE unb2c_board_lib.unb2c_board_pkg.ALL;
+USE technology_lib.technology_pkg.ALL;
+
+
+ENTITY unb2c_test_1GbE_II IS
+  GENERIC (
+    g_design_name      : STRING  := "unb2c_test_1GbE_II";
+    g_design_note      : STRING  := "Use Eth0 and Eth1";
+    g_sim              : BOOLEAN := FALSE; --Overridden by TB
+    g_sim_unb_nr       : NATURAL := 0;
+    g_sim_node_nr      : NATURAL := 0;
+    g_stamp_date       : NATURAL := 0;  -- Date (YYYYMMDD) -- set by QSF
+    g_stamp_time       : NATURAL := 0;  -- Time (HHMMSS)   -- set by QSF
+    g_revision_id      : STRING  := ""  -- revision ID     -- set by QSF
+  );
+  PORT (
+    -- GENERAL
+    CLK          : IN    STD_LOGIC; -- System Clock
+    PPS          : IN    STD_LOGIC; -- System Sync
+    WDI          : OUT   STD_LOGIC; -- Watchdog Clear
+    INTA         : INOUT STD_LOGIC; -- FPGA interconnect line
+    INTB         : INOUT STD_LOGIC; -- FPGA interconnect line
+
+    -- Others
+    VERSION      : IN    STD_LOGIC_VECTOR(c_unb2c_board_aux.version_w-1 DOWNTO 0);
+    ID           : IN    STD_LOGIC_VECTOR(c_unb2c_board_aux.id_w-1 DOWNTO 0);
+    TESTIO       : INOUT STD_LOGIC_VECTOR(c_unb2c_board_aux.testio_w-1 DOWNTO 0);
+    
+  
+    -- 1GbE Control Interface
+    ETH_CLK      : IN    STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 DOWNTO 0);
+    ETH_SGIN     : IN    STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 DOWNTO 0);
+    ETH_SGOUT    : OUT   STD_LOGIC_VECTOR(c_unb2c_board_nof_eth-1 DOWNTO 0);
+
+    QSFP_LED     : OUT   STD_LOGIC_VECTOR(c_unb2c_board_tr_qsfp_nof_leds-1 DOWNTO 0)
+  );
+END unb2c_test_1GbE_II;
+
+
+ARCHITECTURE str OF unb2c_test_1GbE_II IS
+
+BEGIN
+  u_revision : ENTITY unb2c_test_lib.unb2c_test
+  GENERIC MAP (
+    g_design_name => g_design_name,
+    g_design_note => g_design_note,
+    g_sim         => g_sim,
+    g_sim_unb_nr  => g_sim_unb_nr,
+    g_sim_node_nr => g_sim_node_nr,
+    g_stamp_date  => g_stamp_date,
+    g_stamp_time  => g_stamp_time,
+    g_revision_id => g_revision_id
+  )
+  PORT MAP (
+    -- GENERAL
+    CLK          => CLK,
+    PPS          => PPS,
+    WDI          => WDI,
+    INTA         => INTA,
+    INTB         => INTB,
+
+    -- Others
+    VERSION      => VERSION,
+    ID           => ID,
+    TESTIO       => TESTIO,
+
+
+    -- 1GbE Control Interface
+    ETH_clk      => ETH_clk,
+    ETH_SGIN     => ETH_SGIN,
+    ETH_SGOUT    => ETH_SGOUT,
+
+    QSFP_LED     => QSFP_LED
+  );
+END str;
diff --git a/boards/uniboard2c/designs/unb2c_test/src/vhdl/mmm_unb2c_test.vhd b/boards/uniboard2c/designs/unb2c_test/src/vhdl/mmm_unb2c_test.vhd
index cb6ec2cfe0e446e3715c51d3fca55246da38d3f8..2b921773c05e099b2ddf736cbe505fdef765e7e1 100644
--- a/boards/uniboard2c/designs/unb2c_test/src/vhdl/mmm_unb2c_test.vhd
+++ b/boards/uniboard2c/designs/unb2c_test/src/vhdl/mmm_unb2c_test.vhd
@@ -344,11 +344,17 @@ BEGIN
                                                            PORT MAP(mm_rst, mm_clk, ram_diag_data_buf_ddr_MB_II_mosi, ram_diag_data_buf_ddr_MB_II_miso);
                                                            
     -- Note: the eth1g RAM and TSE buses are only required by unb_osy on the NIOS as they provide the ethernet<->MM gateway.
-    u_mm_file_reg_eth0            : mm_file GENERIC MAP(mmf_unb_file_prefix(g_sim_unb_nr, c_sim_node_nr, c_sim_node_type) & "AVS_ETH_0_MMS_REG")
+    -- . 1GbE_I with TSE setup by NiosII
+    u_mm_file_reg_eth0_tse        : mm_file GENERIC MAP(mmf_unb_file_prefix(g_sim_unb_nr, c_sim_node_nr, c_sim_node_type) & "AVS_ETH_0_TSE")
+                                               PORT MAP(mm_rst, mm_clk, eth1g_eth0_tse_mosi, eth1g_eth0_tse_miso);
+    u_mm_file_reg_eth0_reg        : mm_file GENERIC MAP(mmf_unb_file_prefix(g_sim_unb_nr, c_sim_node_nr, c_sim_node_type) & "AVS_ETH_0_REG")
                                                PORT MAP(mm_rst, mm_clk, i_eth1g_eth0_reg_mosi, eth1g_eth0_reg_miso);
-    u_mm_file_reg_eth1            : mm_file GENERIC MAP(mmf_unb_file_prefix(g_sim_unb_nr, c_sim_node_nr, c_sim_node_type) & "AVS_ETH_1_MMS_REG")
-                                               PORT MAP(mm_rst, mm_clk, i_eth1g_eth1_reg_mosi, eth1g_eth1_reg_miso);
-    
+    u_mm_file_reg_eth0_ram        : mm_file GENERIC MAP(mmf_unb_file_prefix(g_sim_unb_nr, c_sim_node_nr, c_sim_node_type) & "AVS_ETH_0_RAM")
+                                               PORT MAP(mm_rst, mm_clk, eth1g_eth0_ram_mosi, eth1g_eth0_ram_miso);
+    -- . 1GbE_II with TSE setup in VHDL
+    u_mm_file_reg_eth1_tse        : mm_file GENERIC MAP(mmf_unb_file_prefix(g_sim_unb_nr, c_sim_node_nr, c_sim_node_type) & "AVS_ETH_1_TSE")
+                                               PORT MAP(mm_rst, mm_clk, eth1g_eth1_tse_mosi, eth1g_eth1_tse_miso);
+
     u_mm_file_reg_tr_10GbE_qsfp_ring : mm_file GENERIC MAP(mmf_unb_file_prefix(g_sim_unb_nr, c_sim_node_nr, c_sim_node_type) & "REG_TR_10GBE_QSFP_RING")
                                                   PORT MAP(mm_rst, mm_clk, reg_tr_10GbE_qsfp_ring_mosi, reg_tr_10GbE_qsfp_ring_miso);
     u_mm_file_reg_tr_10GbE_back0     : mm_file GENERIC MAP(mmf_unb_file_prefix(g_sim_unb_nr, c_sim_node_nr, c_sim_node_type) & "REG_TR_10GBE_BACK0")
diff --git a/boards/uniboard2c/designs/unb2c_test/src/vhdl/unb2c_test.vhd b/boards/uniboard2c/designs/unb2c_test/src/vhdl/unb2c_test.vhd
index 8f3ed66cbfd0bba15b5484e037cc4c131816f49e..69aecc3a18e148fd872483a5f087393aa203955c 100644
--- a/boards/uniboard2c/designs/unb2c_test/src/vhdl/unb2c_test.vhd
+++ b/boards/uniboard2c/designs/unb2c_test/src/vhdl/unb2c_test.vhd
@@ -268,15 +268,10 @@ ARCHITECTURE str OF unb2c_test IS
   SIGNAL eth1g_eth0_ram_mosi        : t_mem_mosi;  -- ETH rx frame and tx frame memory
   SIGNAL eth1g_eth0_ram_miso        : t_mem_miso;
 
-  -- eth1g ch1
+  -- eth1g ch1 (eth_stream only has MM for TSE MAC)
   SIGNAL eth1g_eth1_mm_rst          : STD_LOGIC;
   SIGNAL eth1g_eth1_tse_mosi        : t_mem_mosi;  -- ETH TSE MAC registers
   SIGNAL eth1g_eth1_tse_miso        : t_mem_miso;
-  SIGNAL eth1g_eth1_reg_mosi        : t_mem_mosi;  -- ETH control and status registers
-  SIGNAL eth1g_eth1_reg_miso        : t_mem_miso;
-  SIGNAL eth1g_eth1_reg_interrupt   : STD_LOGIC;   -- Interrupt
-  SIGNAL eth1g_eth1_ram_mosi        : t_mem_mosi;  -- ETH rx frame and tx frame memory
-  SIGNAL eth1g_eth1_ram_miso        : t_mem_miso;
 
   -- EPCS read
   SIGNAL reg_dpmm_data_mosi         : t_mem_mosi;
@@ -648,7 +643,7 @@ BEGIN
     reg_ppsh_mosi            => reg_ppsh_mosi,
     reg_ppsh_miso            => reg_ppsh_miso, 
   
-    -- eth1g ch0
+    -- eth1g ch0 = 1GbE_I
     eth1g_eth0_mm_rst        => eth1g_eth0_mm_rst,
     eth1g_eth0_tse_mosi      => eth1g_eth0_tse_mosi,
     eth1g_eth0_tse_miso      => eth1g_eth0_tse_miso,
@@ -672,15 +667,15 @@ BEGIN
     reg_eth1g_I_strobe_total_count_rx_copi  => reg_eth1g_I_strobe_total_count_rx_copi,
     reg_eth1g_I_strobe_total_count_rx_cipo  => reg_eth1g_I_strobe_total_count_rx_cipo,
 
-    -- eth1g ch1
+    -- eth1g ch1 = 1GbE_II
     eth1g_eth1_mm_rst        => eth1g_eth1_mm_rst,
     eth1g_eth1_tse_mosi      => eth1g_eth1_tse_mosi,
     eth1g_eth1_tse_miso      => eth1g_eth1_tse_miso,
-    eth1g_eth1_reg_mosi      => eth1g_eth1_reg_mosi,
-    eth1g_eth1_reg_miso      => eth1g_eth1_reg_miso,
-    eth1g_eth1_reg_interrupt => eth1g_eth1_reg_interrupt,
-    eth1g_eth1_ram_mosi      => eth1g_eth1_ram_mosi,
-    eth1g_eth1_ram_miso      => eth1g_eth1_ram_miso,
+    eth1g_eth1_reg_mosi      => OPEN,
+    eth1g_eth1_reg_miso      => c_mem_cipo_rst,
+    eth1g_eth1_reg_interrupt => '0',
+    eth1g_eth1_ram_mosi      => OPEN,
+    eth1g_eth1_ram_miso      => c_mem_cipo_rst,
 
     reg_eth1g_II_bg_ctrl_copi                => reg_eth1g_II_bg_ctrl_copi,
     reg_eth1g_II_bg_ctrl_cipo                => reg_eth1g_II_bg_ctrl_cipo,
@@ -805,10 +800,12 @@ BEGIN
 
 
   gen_udp_stream_1GbE : IF c_use_1GbE_I_UDP = TRUE GENERATE
+    -- Derive MAC/IP/UDP from gn_index
     gn_eth_src_mac_I     <= c_base_mac & func_eth_tester_gn_index_to_mac_15_0(gn_index, 0);
     gn_ip_src_addr_I     <= c_base_ip & func_eth_tester_gn_index_to_ip_15_0(gn_index, 0);
     gn_udp_src_port_I    <= c_base_udp & func_eth_tester_gn_index_to_udp_7_0(gn_index, 0);
 
+    -- Generate UDP Tx and monitor UDP Rx
     u_eth_tester_I : ENTITY eth_lib.eth_tester
     GENERIC MAP (
       g_nof_streams     => c_nof_udp_streams_1GbE_I,
@@ -852,58 +849,21 @@ BEGIN
       reg_strobe_total_count_rx_copi => reg_eth1g_I_strobe_total_count_rx_copi,
       reg_strobe_total_count_rx_cipo => reg_eth1g_I_strobe_total_count_rx_cipo
     );
+
+    -- Uses eth.vhd with ETH/TSE interface with UDP streams in ctrl_unb2c_board
+    -- to stream UDP data via eth0 = 1GbE-I.
   END GENERATE;
 
 
-  -- Instantiate a second 1GbE to check pinning
+  -- Instantiate a second 1GbE-II to check pinning and to test UDP data via a
+  -- dedicated 1GbE port, instead of multiplexed with M&C
   gen_eth_II: IF c_use_1GbE_II = TRUE GENERATE
-
-    u_eth : ENTITY eth_lib.eth
-    GENERIC MAP (
-      g_technology         => g_technology,
-      g_init_ip_address    => c_base_ip & X"0000", -- Last two bytes set by board/FPGA ID.
-      g_cross_clock_domain => TRUE,
-      g_frm_discard_en     => TRUE
-    )
-    PORT MAP (
-      -- Clocks and reset
-      mm_rst            => mm_rst, -- use reset from QSYS
-      mm_clk            => mm_clk,     -- use mm_clk direct
-      --eth_clk           => xo_ethclk,    -- 125 MHz clock
-      eth_clk           => ETH_CLK(1),
-      st_rst            => dp_rst,
-      st_clk            => dp_clk,
-    
-      -- UDP transmit interface
-      udp_tx_snk_in_arr  => (others => c_dp_sosi_rst), 
-      udp_tx_snk_out_arr => open,
-      -- UDP receive interface
-      udp_rx_src_in_arr  => (others => c_dp_siso_rdy),
-      udp_rx_src_out_arr => open,
- 
-      -- Memory Mapped Slaves
-      tse_sla_in        => c_mem_mosi_rst,
-      tse_sla_out       => open,
-      reg_sla_in        => c_mem_mosi_rst,
-      reg_sla_out       => open,
-      reg_sla_interrupt => open,
-      ram_sla_in        => c_mem_mosi_rst,
-      ram_sla_out       => open,
-  
-      -- PHY interface
-      eth_txp           => ETH_SGOUT(1),
-      eth_rxp           => ETH_SGIN(1),
-  
-      -- LED interface
-      tse_led           => open
-    );
-
-    -- TODO: Add control and connect for second 1GbE
-
+    -- Derive eth1 MAC/IP/UDP from eth0
     gn_eth_src_mac_II    <= c_base_mac & func_eth_tester_gn_index_to_mac_15_0(gn_index, 1);
     gn_ip_src_addr_II    <= c_base_ip & func_eth_tester_gn_index_to_ip_15_0(gn_index, 1);
     gn_udp_src_port_II   <= c_base_udp & func_eth_tester_gn_index_to_udp_7_0(gn_index, 1);
 
+    -- Generate UDP Tx and monitor UDP Rx
     u_eth_tester_II : ENTITY eth_lib.eth_tester
     GENERIC MAP (
       g_nof_streams     => c_nof_udp_streams_1GbE_II,
@@ -947,6 +907,48 @@ BEGIN
       reg_strobe_total_count_rx_copi => reg_eth1g_II_strobe_total_count_rx_copi,
       reg_strobe_total_count_rx_cipo => reg_eth1g_II_strobe_total_count_rx_cipo
     );
+
+    -- Use eth_stream with ETH/TSE interface for UDP port g_rx_udp_port to
+    -- stream UDP data via eth1 = 1GbE-II
+    u_eth_stream : ENTITY eth_lib.eth_stream
+    GENERIC MAP (
+      g_technology   => g_technology,
+      g_rx_udp_port  => TO_UINT(c_eth_rx_udp_port),  -- = 0x1771 = 6001
+      g_jumbo_en     => FALSE,
+      g_sim          => g_sim,
+      g_sim_level    => 1   -- 0 = use IP model (equivalent to g_sim = FALSE); 1 = use fast serdes model;
+    )
+    PORT MAP (
+      -- Clocks and reset
+      mm_rst             => mm_rst,  -- eth1g_eth1_mm_rst
+      mm_clk             => mm_clk,
+      eth_clk            => ETH_CLK(1),
+      st_rst             => dp_rst,
+      st_clk             => dp_clk,
+
+      -- TSE setup
+      src_mac            => gn_eth_src_mac_II,
+      setup_done         => OPEN,
+
+      -- UDP transmit interface
+      udp_tx_snk_in      => eth1g_II_udp_tx_sosi_arr(0),
+      udp_tx_snk_out     => eth1g_II_udp_tx_siso_arr(0),
+
+      -- UDP receive interface
+      udp_rx_src_in      => c_dp_siso_rdy,
+      udp_rx_src_out     => eth1g_II_udp_rx_sosi_arr(0),
+
+      -- Memory Mapped Slaves
+      tse_ctlr_copi      => eth1g_eth1_tse_mosi,
+      tse_ctlr_cipo      => eth1g_eth1_tse_miso,
+
+      -- PHY interface
+      eth_txp            => ETH_SGOUT(1),
+      eth_rxp            => ETH_SGIN(1),
+
+      -- LED interface
+      tse_led            => OPEN
+    );
   END GENERATE;
 
 
diff --git a/boards/uniboard2c/designs/unb2c_test/src/vhdl/unb2c_test_pkg.vhd b/boards/uniboard2c/designs/unb2c_test/src/vhdl/unb2c_test_pkg.vhd
index 59c3a9e1cad55c33614bd63587ede07a56104089..af5abbd581802a09607b7494b929966e3713a403 100644
--- a/boards/uniboard2c/designs/unb2c_test/src/vhdl/unb2c_test_pkg.vhd
+++ b/boards/uniboard2c/designs/unb2c_test/src/vhdl/unb2c_test_pkg.vhd
@@ -76,18 +76,20 @@ PACKAGE unb2c_test_pkg IS
     type_MB_I           : t_c_tech_ddr;
     type_MB_II          : t_c_tech_ddr;
   END RECORD;
+
   --                                                     loop  1GbE  1GbE  qsfp  ring  bk0   jesd  DDR4  DDR4 heatr
-  CONSTANT c_test_minimal     : t_unb2c_test_config := (FALSE, TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
-  CONSTANT c_test_10GbE       : t_unb2c_test_config := (FALSE, TRUE, TRUE, TRUE, TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
-  CONSTANT c_test_10GbE_qb    : t_unb2c_test_config := (FALSE, TRUE, TRUE, TRUE,FALSE, TRUE,FALSE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
-  CONSTANT c_test_ddr         : t_unb2c_test_config := (FALSE, TRUE, TRUE,FALSE,FALSE,FALSE,FALSE, TRUE, TRUE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
-  CONSTANT c_test_heater      : t_unb2c_test_config := (FALSE, TRUE, TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, TRUE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
-  CONSTANT c_test_jesd204b    : t_unb2c_test_config := (FALSE, TRUE, TRUE,FALSE,FALSE,FALSE, TRUE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
+  CONSTANT c_test_minimal     : t_unb2c_test_config := (FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
+  CONSTANT c_test_1GbE_I_UDP  : t_unb2c_test_config := (FALSE, TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
+  CONSTANT c_test_1GbE_II_UDP : t_unb2c_test_config := (FALSE, TRUE, TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
+  CONSTANT c_test_10GbE       : t_unb2c_test_config := (FALSE,FALSE,FALSE, TRUE, TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
+  CONSTANT c_test_10GbE_qb    : t_unb2c_test_config := (FALSE,FALSE,FALSE, TRUE,FALSE, TRUE,FALSE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
+  CONSTANT c_test_ddr         : t_unb2c_test_config := (FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, TRUE, TRUE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
+  CONSTANT c_test_heater      : t_unb2c_test_config := (FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, TRUE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
+  CONSTANT c_test_jesd204b    : t_unb2c_test_config := (FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, TRUE,FALSE,FALSE,FALSE,c_tech_ddr4_8g_1600m, c_tech_ddr4_8g_1600m);
 
   -- Function to select the revision configuration. 
   FUNCTION func_sel_revision_rec(g_design_name : STRING) RETURN t_unb2c_test_config;
 
-
 END unb2c_test_pkg;
 
 
@@ -95,10 +97,12 @@ PACKAGE BODY unb2c_test_pkg IS
 
   FUNCTION func_sel_revision_rec(g_design_name : STRING) RETURN t_unb2c_test_config IS
   BEGIN
-    IF    g_design_name = "unb2c_test_10GbE"                    THEN RETURN c_test_10GbE;
-    ELSIF g_design_name = "unb2c_test_ddr"                      THEN RETURN c_test_ddr;
-    ELSIF g_design_name = "unb2c_test_heater"                   THEN RETURN c_test_heater;
-    ELSIF g_design_name = "unb2c_test_jesd204b"                 THEN RETURN c_test_jesd204b;
+    IF    g_design_name = "unb2c_test_10GbE"            THEN RETURN c_test_10GbE;
+    ELSIF g_design_name = "unb2c_test_ddr"              THEN RETURN c_test_ddr;
+    ELSIF g_design_name = "unb2c_test_heater"           THEN RETURN c_test_heater;
+    ELSIF g_design_name = "unb2c_test_jesd204b"         THEN RETURN c_test_jesd204b;
+    ELSIF g_design_name = "unb2c_test_1GbE_I"           THEN RETURN c_test_1GbE_I_UDP;
+    ELSIF g_design_name = "unb2c_test_1GbE_II"          THEN RETURN c_test_1GbE_II_UDP;
     ELSE  RETURN c_test_minimal;
     END IF;
   END;
diff --git a/boards/uniboard2c/designs/unb2c_test/unb2c_test.fpga.yaml b/boards/uniboard2c/designs/unb2c_test/unb2c_test.fpga.yaml
index 0b33ed4c02331e284be62af8c60356aebc66870d..0b9e4ee9e907f520e4536c7349178049645881b4 100644
--- a/boards/uniboard2c/designs/unb2c_test/unb2c_test.fpga.yaml
+++ b/boards/uniboard2c/designs/unb2c_test/unb2c_test.fpga.yaml
@@ -6,9 +6,8 @@ hdl_library_name: unb2c_test
 fpga_name       : unb2c_test
 fpga_description: "FPGA design unb2c_test"
 parameters:
-  - { name: c_nof_streams_1GbE_UDP,             value: 2 }  
-  - { name: c_def_1GbE_block_size,              value: 20 }  
-  - { name: c_nof_streams_10GbE_UDP,            value: 72 }  
+  - { name: c_nof_streams_eth0_UDP,             value: 4 }
+  - { name: c_nof_streams_10GbE_UDP,            value: 72 }
   - { name: c_def_10GbE_block_size,             value: 900 }  
   - { name: c_nof_streams_qsfp,                 value: 24 }  
   - { name: c_nof_streams_ring,                 value: 24 }  
@@ -39,6 +38,7 @@ peripherals:
       - RAM_SCRAP
 
   - peripheral_name: eth/eth
+    peripheral_group: eth0
     mm_port_names:
       - AVS_ETH_0_TSE
       - AVS_ETH_0_REG
@@ -71,47 +71,106 @@ peripherals:
     mm_port_names:
       - REG_HEATER
 
-  # 1GbE
+  # 1GbE-I
   - peripheral_name: diag/diag_block_gen
-    peripheral_group: eth_1gbe
+    peripheral_group: eth0_tx
     parameter_overrides:
-      - { name: g_nof_streams, value: c_nof_streams_1GbE_UDP }
-      - { name: g_buf_dat_w, value: 32 }
-      - { name: g_buf_addr_w, value: ceil_log2(c_def_1GbE_block_size) }
+      - { name: g_nof_streams, value: c_nof_streams_eth0_UDP }
+      - { name: g_nof_reg, value: c_nof_streams_eth0_UDP }
+      - { name: g_buf_addr_w, value: 8 }
     mm_port_names:
-      - REG_DIAG_BG_1GBE
-      - RAM_DIAG_BG_1GBE
+      - REG_ETH1G_I_BG_CTRL
+      - RAM_ETH1G_I_BG_CTRL  # not used in eth_tester_tx
 
-  - peripheral_name: diag/diag_tx_seq
-    peripheral_group: eth_1gbe
+  - peripheral_name: eth_tester_offload_hdr_dat
+    peripheral_group: eth0_tx
+    number_of_peripherals: c_nof_streams_eth0_UDP
+    peripheral_span: ceil_pow2(c_nof_streams_eth0_UDP) * 32 * MM_BUS_SIZE  # number_of_ports = 4, mm_port_span = 32 words
+    mm_port_names:
+      - REG_ETH1G_I_HDR_DAT
+
+  - peripheral_name: dp/dp_bsn_monitor_v2
+    peripheral_group: eth0_tx
     parameter_overrides:
-      - { name: g_nof_streams, value: c_nof_streams_1GbE_UDP }
+      - { name: g_nof_streams, value: c_nof_streams_eth0_UDP }
     mm_port_names:
-      - REG_DIAG_TX_SEQ_1GBE
+      - REG_ETH1G_I_BSN_MONITOR_V2_TX
 
-  - peripheral_name: dp/dp_bsn_monitor
-    peripheral_group: eth_1gbe
+  - peripheral_name: dp/dp_strobe_total_count
+    peripheral_group: eth0_tx
+    number_of_peripherals: c_nof_streams_eth0_UDP
+    peripheral_span: ceil_pow2(c_nof_streams_eth0_UDP) * 32 * MM_BUS_SIZE  # number_of_ports = 4, mm_port_span = 32 words
     parameter_overrides:
-      - { name: g_nof_streams, value: c_nof_streams_1GbE_UDP }
+      - { name: g_nof_counts, value: 1 }  # actual nof counts, <= g_nof_counts_max = 15
+                                          # 0 = nof_sop
     mm_port_names:
-      - REG_BSN_MONITOR_1GBE
+      - REG_ETH1G_I_STROBE_TOTAL_COUNT_TX
 
-  - peripheral_name: diag/diag_data_buffer
-    peripheral_group: eth_1gbe
+  - peripheral_name: dp/dp_bsn_monitor_v2
+    peripheral_group: eth0_rx
     parameter_overrides:
-      - { name: g_nof_streams, value: c_nof_streams_1GbE_UDP }
-      - { name: g_data_w, value: 32 }
-      - { name: g_nof_data, value: c_def_1GbE_block_size }
+      - { name: g_nof_streams, value: c_nof_streams_eth0_UDP }
     mm_port_names:
-      - REG_DIAG_DATA_BUFFER_1GBE
-      - RAM_DIAG_DATA_BUFFER_1GBE
+      - REG_ETH1G_I_BSN_MONITOR_V2_RX
 
-  - peripheral_name: diag/diag_rx_seq
-    peripheral_group: eth_1gbe
+  - peripheral_name: dp/dp_strobe_total_count
+    peripheral_group: eth0_rx
+    number_of_peripherals: c_nof_streams_eth0_UDP
+    peripheral_span: ceil_pow2(c_nof_streams_eth0_UDP) * 32 * MM_BUS_SIZE  # number_of_ports = 4, mm_port_span = 32 words
+    parameter_overrides:
+      - { name: g_nof_counts, value: 3 }  # actual nof counts, <= g_nof_counts_max = 15
+                                          # 0 = nof_sop, 1 = nof_valid, 2 = nof_crc_corrupt
+    mm_port_names:
+      - REG_ETH1G_I_STROBE_TOTAL_COUNT_RX
+
+  # 1GbE-II
+  - peripheral_name: eth/eth  # eth_stream
+    peripheral_group: eth1
+    mm_port_names:
+      - AVS_ETH_1_TSE
+      - AVS_ETH_1_REG  # not used for eth_stream
+      - AVS_ETH_1_RAM  # not used for eth_stream
+
+  - peripheral_name: diag/diag_block_gen
+    peripheral_group: eth1_tx
+    parameter_overrides:
+      - { name: g_nof_streams, value: 1 }
+      - { name: g_nof_reg, value: 1 }
+      - { name: g_buf_addr_w, value: 8 }
+    mm_port_names:
+      - REG_ETH1G_I_BG_CTRL
+      - RAM_ETH1G_I_BG_CTRL  # not used in eth_tester_tx
+
+  - peripheral_name: eth_tester_offload_hdr_dat
+    peripheral_group: eth1_tx
+    mm_port_names:
+      - REG_ETH1G_I_HDR_DAT
+
+  - peripheral_name: dp/dp_bsn_monitor_v2
+    peripheral_group: eth1_tx
+    mm_port_names:
+      - REG_ETH1G_I_BSN_MONITOR_V2_TX
+
+  - peripheral_name: dp/dp_strobe_total_count
+    peripheral_group: eth1_tx
+    parameter_overrides:
+      - { name: g_nof_counts, value: 1 }  # actual nof counts, <= g_nof_counts_max = 15
+                                          # 0 = nof_sop
+    mm_port_names:
+      - REG_ETH1G_I_STROBE_TOTAL_COUNT_TX
+
+  - peripheral_name: dp/dp_bsn_monitor_v2
+    peripheral_group: eth1_rx
+    mm_port_names:
+      - REG_ETH1G_I_BSN_MONITOR_V2_RX
+
+  - peripheral_name: dp/dp_strobe_total_count
+    peripheral_group: eth1_rx
     parameter_overrides:
-      - { name: g_nof_streams, value: c_nof_streams_1GbE_UDP }
+      - { name: g_nof_counts, value: 3 }  # actual nof counts, <= g_nof_counts_max = 15
+                                          # 0 = nof_sop, 1 = nof_valid, 2 = nof_crc_corrupt
     mm_port_names:
-      - REG_DIAG_TX_SEQ_1GBE
+      - REG_ETH1G_I_STROBE_TOTAL_COUNT_RX
 
   # 10GbE
   - peripheral_name: diag/diag_block_gen
diff --git a/doc/erko_howto_tools.txt b/doc/erko_howto_tools.txt
index 429197e7d13e277f1e30b4d0081f425d09625b9e..c71e6e5067699dfe22e55fe6a16e28c286d721f5 100755
--- a/doc/erko_howto_tools.txt
+++ b/doc/erko_howto_tools.txt
@@ -128,14 +128,27 @@ during tb simulation load --> fixed by "sudo chmod a+w -R modelsim_altera_libs/1
   revision build quartus dir, so all revisions use the same qsys.
 
 
+# Run command line synthesis for unb2c_test revision
+quartus_config unb2c
+run_qsys_pro unb2c unb2c_test_1GbE_I;
+gen_rom_mmap.py --avalon -d unb2c_test -r unb2c_test_1GbE_I
+run_reg unb2c unb2c_test_1GbE_I
+run_qcomp unb2c unb2c_test_1GbE_I --clk=CLK
+run_rbf unb2c unb2c_test_1GbE_I
 
+quartus_config unb2c
+run_qsys_pro unb2c unb2c_test_1GbE_II;
+gen_rom_mmap.py --avalon -d unb2c_test -r unb2c_test_1GbE_II
+run_reg unb2c unb2c_test_1GbE_II
+run_qcomp unb2c unb2c_test_1GbE_II --clk=CLK
+run_rbf unb2c unb2c_test_1GbE_II
 
 # Run command line synthesis for dts
 quartus_config unb2c
 run_qsys_pro unb2c lofar2_unb2c_sdp_station_full;
 gen_rom_mmap.py --avalon -d lofar2_unb2c_sdp_station -r lofar2_unb2c_sdp_station_full;
 run_reg unb2c lofar2_unb2c_sdp_station_full;
-run_qcomp unb2c lofar2_unb2c_sdp_station_full --clk=CLK;
+run_qcomp unb2c lofar2_unb2c_sdp_station_full --clk=CLK
 run_rbf unb2c lofar2_unb2c_sdp_station_full
 
 # Run command line synthesis for sdp-arts
diff --git a/libraries/base/common/src/vhdl/common_mem_pkg.vhd b/libraries/base/common/src/vhdl/common_mem_pkg.vhd
index 27fcd79466c332fc6ece560e5c5cc34b616407ca..dd26500d83613818ffad93645f699eaf5a229ff3 100644
--- a/libraries/base/common/src/vhdl/common_mem_pkg.vhd
+++ b/libraries/base/common/src/vhdl/common_mem_pkg.vhd
@@ -109,7 +109,27 @@ PACKAGE common_mem_pkg IS
   FUNCTION RESIZE_MEM_UDATA(  vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- unsigned
   FUNCTION RESIZE_MEM_SDATA(  vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- sign extended
   FUNCTION RESIZE_MEM_XDATA(  vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- set unused MSBits to 'X'
-  
+
+  ------------------------------------------------------------------------------
+  -- Procedures to access MM bus
+  -- . no mm_clk, combinatoral inputs only, to allow use in a state machine
+  -- . similar proc_mem_mm_bus_*() procs in tb_common_mem_pkg.vhd do have
+  --   mm_clk inputs
+  -- . if mm_copi.waitrequest is used, then issue the MM access and externaly
+  --   check and wait for mm_copi.waitrequest = '0' before removing the MM
+  --   access.
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_mem_bus_wr(CONSTANT wr_addr : IN  NATURAL;
+                            CONSTANT wr_data : IN  INTEGER;
+                            SIGNAL   mm_copi : OUT t_mem_copi);
+
+  PROCEDURE proc_mem_bus_wr(CONSTANT wr_addr : IN  NATURAL;
+                            CONSTANT wr_data : IN  STD_LOGIC_VECTOR;
+                            SIGNAL   mm_copi : OUT t_mem_copi);
+
+  PROCEDURE proc_mem_bus_rd(CONSTANT wr_addr : IN  NATURAL;
+                            SIGNAL   mm_copi : OUT t_mem_copi);
+
   ------------------------------------------------------------------------------
   -- Burst memory access (for DDR access interface)
   ------------------------------------------------------------------------------
@@ -279,7 +299,32 @@ PACKAGE BODY common_mem_pkg IS
     v_vec(vec'LENGTH-1 DOWNTO 0) := vec;
     RETURN v_vec;
   END RESIZE_MEM_XDATA;
-  
+
+  -- Procedures to access MM bus
+  PROCEDURE proc_mem_bus_wr(CONSTANT wr_addr : IN  NATURAL;
+                            CONSTANT wr_data : IN  INTEGER;
+                            SIGNAL   mm_copi : OUT t_mem_copi) IS
+  BEGIN
+    mm_copi.address <= TO_MEM_ADDRESS(wr_addr);
+    mm_copi.wrdata  <= TO_MEM_DATA(wr_data);
+    mm_copi.wr      <= '1';
+  END proc_mem_bus_wr;
+
+  PROCEDURE proc_mem_bus_wr(CONSTANT wr_addr : IN  NATURAL;
+                            CONSTANT wr_data : IN  STD_LOGIC_VECTOR;
+                            SIGNAL   mm_copi : OUT t_mem_copi) IS
+  BEGIN
+    mm_copi.address <= TO_MEM_ADDRESS(wr_addr);
+    mm_copi.wrdata  <= RESIZE_MEM_DATA(wr_data);
+    mm_copi.wr      <= '1';
+  END proc_mem_bus_wr;
+
+  PROCEDURE proc_mem_bus_rd(CONSTANT wr_addr : IN  NATURAL;
+                            SIGNAL   mm_copi : OUT t_mem_copi) IS
+  BEGIN
+    mm_copi.address <= TO_MEM_ADDRESS(wr_addr);
+    mm_copi.rd      <= '1';
+  END proc_mem_bus_rd;
 
   -- Resize functions to fit an integer or an SLV in the corresponding t_mem_miso or t_mem_mosi field width
   FUNCTION TO_MEM_CTLR_ADDRESS(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
diff --git a/libraries/base/diag/diag.peripheral.yaml b/libraries/base/diag/diag.peripheral.yaml
index ec4f28671473375570d764b2d7df883483f142e3..5b7932ea9733695a5b0d3ad31e965bfdcfc836d0 100644
--- a/libraries/base/diag/diag.peripheral.yaml
+++ b/libraries/base/diag/diag.peripheral.yaml
@@ -100,10 +100,11 @@ peripherals:
               user_width: g_data_w
     
   - peripheral_name: diag_block_gen    # pi_diag_block_gen.py
-    peripheral_description: "Block generator (BG)"
+    peripheral_description: "Block generator (BG) with g_nof_reg = 1 reg shared by all streams or g_nof_reg = g_nof_streams to have one reg per stream"
     parameters:
       # Parameters of mms_diag_block_gen.vhd
       - { name: g_nof_streams, value: 1 }
+      - { name: g_nof_reg, value: 1 }
       - { name: g_buf_dat_w, value: 16 }
       - { name: g_buf_addr_w, value: 7 }
     mm_ports:
@@ -112,7 +113,7 @@ peripherals:
         mm_port_type: REG
         mm_port_span: 8 * MM_BUS_SIZE
         mm_port_description: "Block generator control."
-        number_of_mm_ports: 1
+        number_of_mm_ports: g_nof_reg
         fields:
           - - field_name: enable
               field_description: "Starts the block generator."
diff --git a/libraries/base/dp/dp.peripheral.yaml b/libraries/base/dp/dp.peripheral.yaml
index 6d38ee172529145bc9e302121ef92abc0b6b0f41..23ed67a9ea89b4d4af72a7c355e6e2ecb07e24b6 100644
--- a/libraries/base/dp/dp.peripheral.yaml
+++ b/libraries/base/dp/dp.peripheral.yaml
@@ -451,7 +451,7 @@ peripherals:
       # MM port for dp_strobe_total_count.vhd
       - mm_port_name: REG_DP_STROBE_TOTAL_COUNT
         mm_port_type: REG
-        mm_port_span: ceil_pow2(g_nof_counts_max*2 + 1) * MM_BUS_SIZE
+        mm_port_span: ceil_pow2(g_nof_counts_max*2 + 1) * MM_BUS_SIZE  # = 32 * MM_BUS_SIZE
         mm_port_description: ""
         fields:
           - - field_name: counts
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_core.vhd b/libraries/base/dp/src/vhdl/dp_fifo_core.vhd
index 083fd11c107e8efa6570a5e4b7ad7c09839be0eb..c8f9cb39db358df72a7a0fbd4ab161343a341e54 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_core.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_core.vhd
@@ -111,7 +111,7 @@ ARCHITECTURE str OF dp_fifo_core IS
   SIGNAL fifo_wr_dat   : STD_LOGIC_VECTOR(c_fifo_dat_w-1 DOWNTO 0);
   SIGNAL fifo_wr_req   : STD_LOGIC;
   SIGNAL fifo_wr_ful   : STD_LOGIC;
-  SIGNAL wr_init       : STD_LOGIC                                 := '0';
+  SIGNAL wr_init       : STD_LOGIC := '0';
   SIGNAL fifo_wr_usedw : STD_LOGIC_VECTOR(wr_usedw'RANGE);
   
   SIGNAL fifo_rd_dat   : STD_LOGIC_VECTOR(c_fifo_dat_w-1 DOWNTO 0) := (OTHERS=>'0');
@@ -191,6 +191,7 @@ BEGIN
       usedw    => fifo_rd_usedw
     );
     
+    wr_init <= '0';  -- to avoid no driver warning in synthesis
     fifo_wr_usedw <= fifo_rd_usedw;
   END GENERATE;
   
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd
index 62ddba22104d5a5ff2ba355a63bbe5150b39a20e..9d904f89e2cf577428a406bc5ee0fb2b1530b9f6 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd
@@ -224,8 +224,7 @@ BEGIN
     
   -- No need to transfer eop counter across clock domains for single clock
   gen_rd_eop_cnt_sc : IF g_use_dual_clock=FALSE GENERATE
-    wr_fifo_usedw  <= rd_fifo_usedw;
-    rd_eop_new     <= '1';
+    rd_eop_new <= '1';
   END GENERATE;
 
   -- Set rd_eop_cnt outside generate statements to avoid Modelsim warning "Nonresolved signal 'rd_eop_cnt' may have multiple sources".
diff --git a/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd b/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
index 537d5871db8aab4bd9035a22f9567097feff51de..ecd2e6b6fea23856b16269dfba6fa2203f4f6eb3 100644
--- a/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
+++ b/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
@@ -272,6 +272,12 @@ PACKAGE dp_stream_pkg Is
 
   FUNCTION TO_DP_SOSI_UNSIGNED(sync, valid, sop, eop : STD_LOGIC; bsn, data, re, im, empty, channel, err : UNSIGNED) RETURN t_dp_sosi_unsigned;
 
+  -- Map between array and single element
+  FUNCTION TO_DP_ARR(sosi : t_dp_sosi) RETURN t_dp_sosi_arr;
+  FUNCTION TO_DP_ARR(siso : t_dp_siso) RETURN t_dp_siso_arr;
+  FUNCTION TO_DP_ONE(sosi_arr : t_dp_sosi_arr) RETURN t_dp_sosi;
+  FUNCTION TO_DP_ONE(siso_arr : t_dp_siso_arr) RETURN t_dp_siso;
+
   -- Keep part of head data and combine part of tail data, use the other sosi from head_sosi
   FUNCTION func_dp_data_shift_first(head_sosi, tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail              : NATURAL) RETURN t_dp_sosi;
   -- Shift and combine part of previous data and this data, use the other sosi from prev_sosi
@@ -638,6 +644,30 @@ PACKAGE BODY dp_stream_pkg IS
     RETURN v_sosi_unsigned;
   END TO_DP_SOSI_UNSIGNED;
 
+  -- Map between array and single element
+  FUNCTION TO_DP_ARR(sosi : t_dp_sosi) RETURN t_dp_sosi_arr IS
+    VARIABLE v_sosi_arr : t_dp_sosi_arr(0 DOWNTO 0) := (OTHERS => sosi);
+  BEGIN
+    RETURN v_sosi_arr;
+  END TO_DP_ARR;
+
+  FUNCTION TO_DP_ARR(siso : t_dp_siso) RETURN t_dp_siso_arr IS
+    VARIABLE v_siso_arr : t_dp_siso_arr(0 DOWNTO 0) := (OTHERS => siso);
+  BEGIN
+    RETURN v_siso_arr;
+  END TO_DP_ARR;
+
+  FUNCTION TO_DP_ONE(sosi_arr : t_dp_sosi_arr) RETURN t_dp_sosi IS
+  BEGIN
+    RETURN sosi_arr(0);
+  END TO_DP_ONE;
+
+  FUNCTION TO_DP_ONE(siso_arr : t_dp_siso_arr) RETURN t_dp_siso IS
+  BEGIN
+    RETURN siso_arr(0);
+  END TO_DP_ONE;
+
+
   -- Keep part of head data and combine part of tail data
   FUNCTION func_dp_data_shift_first(head_sosi, tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail : NATURAL) RETURN t_dp_sosi IS
     VARIABLE vN     : NATURAL := nof_symbols_per_data;
diff --git a/libraries/io/eth/hdllib.cfg b/libraries/io/eth/hdllib.cfg
index 11d97855c2d2c66fc69d0db9120c34e4d56095d3..39fcfc924d6665a6a0352057d1689ac17fb4937a 100644
--- a/libraries/io/eth/hdllib.cfg
+++ b/libraries/io/eth/hdllib.cfg
@@ -22,6 +22,8 @@ synth_files =
     src/vhdl/eth_control.vhd
     src/vhdl/eth_ihl_to_20.vhd
     src/vhdl/eth.vhd
+    src/vhdl/eth_stream_udp.vhd
+    src/vhdl/eth_stream.vhd
     src/vhdl/eth_tester_pkg.vhd
     src/vhdl/eth_tester_tx.vhd
     src/vhdl/eth_tester_rx.vhd
@@ -35,8 +37,10 @@ test_bench_files =
     tb/vhdl/tb_eth.vhd
     tb/vhdl/tb_eth_tester_pkg.vhd
     tb/vhdl/tb_eth_tester.vhd
+    tb/vhdl/tb_eth_stream_udp.vhd
     tb/vhdl/tb_tb_eth.vhd
     tb/vhdl/tb_tb_eth_tester.vhd
+    tb/vhdl/tb_tb_eth_stream_udp.vhd
     tb/vhdl/tb_eth_udp_offload.vhd
     tb/vhdl/tb_eth_ihl_to_20.vhd
     tb/vhdl/tb_tb_tb_eth_regression.vhd
@@ -49,6 +53,7 @@ regression_test_vhdl =
     tb/vhdl/tb_eth_ihl_to_20.vhd
     tb/vhdl/tb_tb_eth.vhd
     tb/vhdl/tb_tb_eth_tester.vhd
+    tb/vhdl/tb_tb_eth_stream_udp.vhd
 
 
 [modelsim_project_file]
diff --git a/libraries/io/eth/src/vhdl/eth_pkg.vhd b/libraries/io/eth/src/vhdl/eth_pkg.vhd
index eb4f556c1b29f3bd5bc7cb8f949bda396653bc28..632bbb7af95e91fa12763f67831023472e48846d 100644
--- a/libraries/io/eth/src/vhdl/eth_pkg.vhd
+++ b/libraries/io/eth/src/vhdl/eth_pkg.vhd
@@ -86,6 +86,9 @@ PACKAGE eth_pkg IS
   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;
     
+  -- Default Rx UDP port for UDP onload
+  CONSTANT c_eth_rx_udp_port : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(6001, 16);  -- 0x1771 = 6001
+
   ------------------------------------------------------------------------------
   -- MM register map
   ------------------------------------------------------------------------------
diff --git a/libraries/io/eth/src/vhdl/eth_stream.vhd b/libraries/io/eth/src/vhdl/eth_stream.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..ea47c91393a4503900bef921d609bd7a13e26283
--- /dev/null
+++ b/libraries/io/eth/src/vhdl/eth_stream.vhd
@@ -0,0 +1,179 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2022
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Author: Eric Kooistra
+-- Purpose:
+--   Provide Ethernet access to a node for one UDP stream via TSE.
+-- Description:
+-- * This eth_stream.vhd is a stripped down version of eth.vhd to offload and
+--   onload one UDP stream.
+--   . see eth_stream_udp.vhd for UDP offload/onload stream details
+--   . contains the TSE
+--   . sets up TSE in state machnine and then switch to external mm_ctlr,
+--     when setup_done = '1', to allow external monitoring of the TSE
+--   . use g_jumbo_en = FALSE to support 1500 octet frames 1518 like in
+--     unb_osy/unbos_eth.h, or use g_jumbo_en = TRUE to support 9000 octet
+--     frames. With g_jumbo_en = FALSE a 9000 octet packet is received
+--     properly, but has rx_src_out.err = 3 indicating invalid length.
+--     Use c_jumbo_en = TRUE to avoid invalid length.
+--
+-- References:
+-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE
+
+LIBRARY IEEE, common_lib, dp_lib, technology_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;
+USE technology_lib.technology_select_pkg.ALL;
+
+ENTITY eth_stream IS
+  GENERIC (
+    g_technology   : NATURAL := c_tech_select_default;
+    g_ETH_PHY      : STRING  := "LVDS"; -- "LVDS" (default): uses LVDS IOs for ctrl_unb_common, "XCVR": uses tranceiver PHY
+    g_rx_udp_port  : NATURAL := TO_UINT(c_eth_rx_udp_port);
+    g_jumbo_en     : BOOLEAN := FALSE;
+    g_sim          : BOOLEAN := FALSE;
+    g_sim_level    : NATURAL := 0   -- 0 = use IP model (equivalent to g_sim = FALSE); 1 = use fast serdes model;
+  );
+  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
+
+    -- TSE setup
+    src_mac            : IN STD_LOGIC_VECTOR(c_48-1 DOWNTO 0);
+    setup_done         : OUT STD_LOGIC;
+
+    -- UDP transmit interface
+    udp_tx_snk_in      : IN  t_dp_sosi := c_dp_sosi_rst;
+    udp_tx_snk_out     : OUT t_dp_siso;
+
+    -- UDP receive interface
+    udp_rx_src_in      : IN  t_dp_siso := c_dp_siso_rdy;
+    udp_rx_src_out     : OUT t_dp_sosi;
+
+    -- Memory Mapped Slaves
+    tse_ctlr_copi      : IN  t_mem_mosi;  -- ETH TSE MAC registers
+    tse_ctlr_cipo      : OUT t_mem_miso;
+
+    -- PHY interface
+    eth_txp            : OUT STD_LOGIC;
+    eth_rxp            : IN  STD_LOGIC;
+
+    -- LED interface
+    tse_led            : OUT t_tech_tse_led
+  );
+END eth_stream;
+
+
+ARCHITECTURE str OF eth_stream IS
+
+  -- Tx UDP offload stream to TSE
+  SIGNAL tse_tx_sosi   : t_dp_sosi;
+  SIGNAL tse_tx_siso   : t_dp_siso;
+
+  -- Rx stream from TSE (contains the UDP onload packets and possibly other
+  -- network packets)
+  SIGNAL tse_rx_sosi   : t_dp_sosi;
+  SIGNAL tse_rx_siso   : t_dp_siso;
+
+BEGIN
+
+  u_eth_stream_udp : ENTITY work.eth_stream_udp
+  GENERIC MAP (
+    g_rx_udp_port => g_rx_udp_port
+  )
+  PORT MAP (
+    -- Clocks and reset
+    st_rst        => st_rst,
+    st_clk        => st_clk,
+
+    -- User UDP interface
+    -- . Tx
+    udp_tx_sosi   => udp_tx_snk_in,
+    udp_tx_siso   => udp_tx_snk_out,
+    -- . Rx
+    udp_rx_sosi   => udp_rx_src_out,
+    udp_rx_siso   => udp_rx_src_in,
+
+    -- PHY interface
+    -- . Tx
+    tse_tx_sosi   => tse_tx_sosi,
+    tse_tx_siso   => tse_tx_siso,
+    -- . Rx
+    tse_rx_sosi   => tse_rx_sosi,
+    tse_rx_siso   => tse_rx_siso
+  );
+
+  u_tech_tse_with_setup : ENTITY tech_tse_lib.tech_tse_with_setup
+  GENERIC MAP (
+    g_technology   => g_technology,
+    g_ETH_PHY      => g_ETH_PHY,
+    g_jumbo_en     => g_jumbo_en,
+    g_sim          => g_sim,
+    g_sim_level    => g_sim_level
+  )
+  PORT MAP (
+    -- Clocks and reset
+    mm_rst         => mm_rst,
+    mm_clk         => mm_clk,   -- MM
+    eth_clk        => eth_clk,  -- 125 MHz
+    tx_snk_clk     => st_rst,   -- DP
+    rx_src_clk     => st_clk,   -- DP
+
+    -- TSE setup
+    src_mac        => src_mac,
+    setup_done     => setup_done,
+
+    -- Calibration & reconfig clock
+    cal_rec_clk    => cal_rec_clk,
+
+    -- Memory Mapped Peripheral
+    mm_ctlr_copi   => tse_ctlr_copi,
+    mm_ctlr_cipo   => tse_ctlr_cipo,
+
+    -- MAC transmit interface
+    -- . ST sink
+    tx_snk_in      => tse_tx_sosi,
+    tx_snk_out     => tse_tx_siso,
+
+    -- MAC receive interface
+    -- . ST Source
+    rx_src_in      => tse_rx_siso,
+    rx_src_out     => tse_rx_sosi,
+
+    -- PHY interface
+    eth_txp        => eth_txp,
+    eth_rxp        => eth_rxp,
+
+    tse_led        => tse_led
+  );
+
+END str;
diff --git a/libraries/io/eth/src/vhdl/eth_stream_udp.vhd b/libraries/io/eth/src/vhdl/eth_stream_udp.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..a11b6a23e2ad5f6ec34d32d2b5b43bde787e7c69
--- /dev/null
+++ b/libraries/io/eth/src/vhdl/eth_stream_udp.vhd
@@ -0,0 +1,188 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2022
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Author: Eric Kooistra
+-- Purpose:
+--   Provide Ethernet access to a node for one UDP stream.
+-- Description:
+-- * This eth_stream_udp.vhd contains the IP/UDP related components of eth.vhd
+--   that are needed to send or receive an UDP stream via 1GbE.
+--   . support only only UDP offload/onload stream.
+--   . the IP checksum is filled in for Tx and checked or Rx.
+--   . the Tx only contains UDP stream data, so no need for a dp_mux.
+--   . the Rx may contain other packet types, because the 1GbE connects to
+--     a network. All Rx packets that are not UDP for g_rx_udp_port are
+--     discarded.
+-- * Use eth_stream.vhd to have eth_stream_udp in combination with the TSE.
+--
+-- References:
+-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE work.eth_pkg.ALL;
+
+ENTITY eth_stream_udp IS
+  GENERIC (
+    g_rx_udp_port : NATURAL
+  );
+  PORT (
+    -- Clocks and reset
+    st_rst        : IN  STD_LOGIC;
+    st_clk        : IN  STD_LOGIC;
+    
+    -- User UDP interface
+    -- . Tx
+    udp_tx_sosi   : IN  t_dp_sosi;
+    udp_tx_siso   : OUT t_dp_siso;
+    -- . Rx
+    udp_rx_sosi   : OUT t_dp_sosi;
+    udp_rx_siso   : IN  t_dp_siso := c_dp_siso_rdy;
+
+    -- PHY interface
+    -- . Tx
+    tse_tx_sosi   : OUT t_dp_sosi;
+    tse_tx_siso   : IN  t_dp_siso;
+    -- . Rx
+    tse_rx_sosi   : IN  t_dp_sosi;
+    tse_rx_siso   : OUT t_dp_siso
+  );
+END eth_stream_udp;
+
+
+ARCHITECTURE str OF eth_stream_udp IS
+
+  -- ETH Tx
+  SIGNAL eth_tx_siso            : t_dp_siso;
+  SIGNAL eth_tx_sosi            : t_dp_sosi;
+
+  -- ETH Rx
+  SIGNAL rx_adapt_siso          : t_dp_siso;
+  SIGNAL rx_adapt_sosi          : t_dp_sosi;
+  
+  SIGNAL rx_hdr_status          : t_eth_hdr_status;
+  SIGNAL rx_hdr_status_complete : STD_LOGIC;
+
+  SIGNAL rx_eth_discard         : STD_LOGIC;
+  SIGNAL rx_eth_discard_val     : STD_LOGIC;
+
+BEGIN
+
+  ------------------------------------------------------------------------------
+  -- TX
+  ------------------------------------------------------------------------------
+
+  -- Insert IP header checksum
+  u_tx_ip : 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          => udp_tx_sosi,
+    snk_out         => udp_tx_siso,
+
+    -- Streaming Source
+    src_in          => tse_tx_siso,
+    src_out         => tse_tx_sosi   -- with err field value 0 for OK
+  );
+
+  ------------------------------------------------------------------------------
+  -- 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
+  );
+  
+  -- Pass on UDP stream for g_rx_udp_port
+  -- . Verify IP header checksum for IP
+  u_rx_udp : 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_adapt_sosi,
+    snk_out         => rx_adapt_siso,
+    
+    -- Streaming Source
+    src_in          => udp_rx_siso,
+    src_out         => udp_rx_sosi,
+
+    -- Frame control
+    frm_discard     => rx_eth_discard,
+    frm_discard_val => rx_eth_discard_val,
+    
+    -- Header info
+    hdr_status          => rx_hdr_status,
+    hdr_status_complete => rx_hdr_status_complete
+  );
+
+  -- Discard all Rx data that is not UDP for g_rx_udp_port
+  p_rx_discard : PROCESS(st_rst, st_clk)
+  BEGIN
+    IF st_rst = '1' THEN
+      rx_eth_discard <= '1';  -- default discard
+      rx_eth_discard_val <= '0';
+    ELSIF rising_edge(st_clk) THEN
+      -- Default keep rx_eth_discard status (instead of '1'), to more clearly
+      -- see when a change occurs
+      IF rx_hdr_status_complete = '1' THEN
+        rx_eth_discard <= '1';  -- default discard
+        IF rx_hdr_status.is_ip = '1' AND
+           rx_hdr_status.is_udp = '1' AND
+           TO_UINT(rx_hdr_status.udp_port) = g_rx_udp_port THEN
+          rx_eth_discard <= '0';  -- pass on IP/UDP stream for g_rx_udp_port
+        END IF;
+      END IF;
+
+      rx_eth_discard_val <= rx_hdr_status_complete;
+    END IF;
+  END PROCESS;
+
+END str;
diff --git a/libraries/io/eth/src/vhdl/eth_tester_pkg.vhd b/libraries/io/eth/src/vhdl/eth_tester_pkg.vhd
index 207728be0545d8f11f45451d303960e31546ab05..defeba8d5c5541a777b972d1a5e296eccf172b61 100644
--- a/libraries/io/eth/src/vhdl/eth_tester_pkg.vhd
+++ b/libraries/io/eth/src/vhdl/eth_tester_pkg.vhd
@@ -107,6 +107,9 @@ PACKAGE eth_tester_pkg is
   CONSTANT c_eth_tester_ip_src_addr_31_16 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"0A63";
   CONSTANT c_eth_tester_udp_src_port_15_8 : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"E0";
 
+  -- Default eth_tester Rx UDP port for single stream via 1GbE-II
+  CONSTANT c_eth_tester_eth1g_II_rx_udp_port : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(6001, 16);  -- 0x1771 = 6001
+
   TYPE t_eth_tester_app_header IS RECORD
     dp_length   : STD_LOGIC_VECTOR(15 DOWNTO 0);
     dp_reserved : STD_LOGIC_VECTOR(14 DOWNTO 0);
diff --git a/libraries/io/eth/src/vhdl/eth_tester_tx.vhd b/libraries/io/eth/src/vhdl/eth_tester_tx.vhd
index d1051404ea32694f5633b233db53fafb86f8e364..0ee2539d169bee295d7e9053d505170e88493e00 100644
--- a/libraries/io/eth/src/vhdl/eth_tester_tx.vhd
+++ b/libraries/io/eth/src/vhdl/eth_tester_tx.vhd
@@ -82,6 +82,7 @@ ARCHITECTURE str OF eth_tester_tx IS
   CONSTANT c_packet_sz_max        : NATURAL := ceil_div(c_eth_tester_bg_block_len_max, c_word_sz);
   CONSTANT c_fifo_fill            : NATURAL := c_packet_sz_max * 11 / 10;
   CONSTANT c_fifo_size            : NATURAL := true_log_pow2(c_fifo_fill + c_packet_sz_max);  -- = 8192
+  CONSTANT c_fifo_size_w          : NATURAL := ceil_log2(c_fifo_size);
 
   CONSTANT c_nof_total_counts     : NATURAL := 1;  -- one to count Tx packets
 
@@ -101,8 +102,10 @@ ARCHITECTURE str OF eth_tester_tx IS
   SIGNAL tx_fifo_data             : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
   SIGNAL tx_fifo_siso             : t_dp_siso;
   SIGNAL tx_fifo_wr_ful           : STD_LOGIC;
-  SIGNAL tx_fifo_wr_usedw         : STD_LOGIC_VECTOR(ceil_log2(c_fifo_size)-1 DOWNTO 0);
+  SIGNAL tx_fifo_wr_usedw         : STD_LOGIC_VECTOR(c_fifo_size_w-1 DOWNTO 0);
   SIGNAL i_tx_fifo_rd_emp         : STD_LOGIC;
+  SIGNAL tx_offload_siso          : t_dp_siso;
+  SIGNAL tx_offload_sosi          : t_dp_sosi;
 
   SIGNAL i_ref_sync               : STD_LOGIC := '0';
   SIGNAL in_strobe_arr            : STD_LOGIC_VECTOR(c_nof_total_counts-1 DOWNTO 0);
@@ -159,9 +162,11 @@ BEGIN
 
   -- BG block level flow control, needed in case BG settings result in eth bit
   -- rate > 1 Gbps, to avoid u_tx_fifo overflow.
-  p_bg_siso_xon : PROCESS(st_clk)
+  p_bg_siso_xon : PROCESS(st_rst, st_clk)
   BEGIN
-    IF rising_edge(st_clk) THEN
+    IF st_rst = '1' THEN
+      bg_siso.xon <= '1';
+    ELSIF rising_edge(st_clk) THEN
       bg_siso.xon <= '1';
       IF TO_UINT(tx_fifo_wr_usedw) > c_fifo_fill THEN
         bg_siso.xon <= '0';
@@ -198,19 +203,19 @@ BEGIN
     g_fifo_size      => c_fifo_size
   )
   PORT MAP (
-    wr_rst      => st_rst,
-    wr_clk      => st_clk,
-    rd_rst      => st_rst,
-    rd_clk      => st_clk,
+    wr_rst       => st_rst,
+    wr_clk       => st_clk,
+    rd_rst       => st_rst,
+    rd_clk       => st_clk,
     -- Monitor FIFO filling
-    wr_ful      => tx_fifo_wr_ful,
-    wr_usedw    => tx_fifo_wr_usedw,
-    rd_emp      => i_tx_fifo_rd_emp,
+    wr_ful       => tx_fifo_wr_ful,
+    wr_usedw     => tx_fifo_wr_usedw,
+    rd_emp       => i_tx_fifo_rd_emp,
     -- ST sink
-    snk_in      => tx_packed_sosi,
+    snk_in       => tx_packed_sosi,
     -- ST source
-    src_in      => tx_fifo_siso,
-    src_out     => tx_fifo_sosi
+    src_in       => tx_fifo_siso,
+    src_out      => tx_fifo_sosi
   );
 
   -------------------------------------------------------------------------------
@@ -295,8 +300,8 @@ BEGIN
     snk_in_arr(0)         => tx_fifo_sosi,
     snk_out_arr(0)        => tx_fifo_siso,
 
-    src_out_arr(0)        => i_tx_udp_sosi,
-    src_in_arr(0)         => tx_udp_siso,
+    src_out_arr(0)        => tx_offload_sosi,
+    src_in_arr(0)         => tx_offload_siso,
 
     hdr_fields_in_arr(0)  => hdr_fields_slv_in,  -- hdr_fields_slv_in_arr(i) is considered valid @ snk_in_arr(i).sop
     hdr_fields_out_arr(0) => hdr_fields_slv_tx
@@ -306,6 +311,22 @@ BEGIN
   hdr_fields_rec_in <= func_eth_tester_map_header(hdr_fields_slv_in);
   hdr_fields_rec_tx <= func_eth_tester_map_header(hdr_fields_slv_tx);
 
+
+  -------------------------------------------------------------------------------
+  -- dp_pipeline_ready to ease timing closure
+  -------------------------------------------------------------------------------
+  u_dp_pipeline_ready : ENTITY dp_lib.dp_pipeline_ready
+  PORT MAP(
+    rst     => st_rst,
+    clk     => st_clk,
+
+    snk_out => tx_offload_siso,
+    snk_in  => tx_offload_sosi,
+    src_in  => tx_udp_siso,
+    src_out => i_tx_udp_sosi
+  );
+
+
   -------------------------------------------------------------------------------
   -- Tx packet monitors
   -------------------------------------------------------------------------------
diff --git a/libraries/io/eth/tb/vhdl/tb_eth_stream_udp.vhd b/libraries/io/eth/tb/vhdl/tb_eth_stream_udp.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..95bf74ff0c3a07509b35aaf3ab293d9afefea1e5
--- /dev/null
+++ b/libraries/io/eth/tb/vhdl/tb_eth_stream_udp.vhd
@@ -0,0 +1,436 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2022
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+-- AUthor: E. Kooistra
+-- Purpose: Test bench for eth_stream_udp using eth_tester
+-- Description:
+--   Similar as tb_eth_tester.vhd, but for only one stream and using streaming
+--   interface loop back.
+--
+-- Usage:
+-- > as 8
+-- > run -a
+--
+-- References:
+-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE
+
+LIBRARY IEEE, common_lib, dp_lib, diag_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.common_str_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL;
+USE common_lib.common_network_layers_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE diag_lib.diag_pkg.ALL;
+USE work.eth_pkg.ALL;
+USE work.eth_tester_pkg.ALL;
+USE work.tb_eth_tester_pkg.ALL;
+
+ENTITY tb_eth_stream_udp IS
+  GENERIC (
+    g_tb_index         : NATURAL := 0;  -- use to incremental delay logging from tb instances in tb_tb
+    g_nof_sync         : NATURAL := 2;  -- number of BG sync intervals to set c_run_time
+    g_udp_port_match   : BOOLEAN := TRUE;
+
+    -- t_diag_block_gen_integer =
+    --   sl:  enable
+    --   sl:  enable_sync
+    --   nat: samples_per_packet
+    --   nat: blocks_per_sync
+    --   nat: gapsize
+    --   nat: mem_low_adrs
+    --   nat: mem_high_adrs
+    --   nat: bsn_init
+    g_bg_ctrl    : t_diag_block_gen_integer := ('1', '1', 50, 3, 200, 0, c_diag_bg_mem_max_adr, 0)  -- for first stream
+  );
+END tb_eth_stream_udp;
+
+
+ARCHITECTURE tb OF tb_eth_stream_udp IS
+
+  CONSTANT c_tb_str                : STRING := "tb-" & NATURAL'IMAGE(g_tb_index) & " : ";  -- use to distinguish logging from tb instances in tb_tb
+  CONSTANT mm_clk_period           : TIME := 10 ns;  -- 100 MHz
+  CONSTANT c_nof_st_clk_per_s      : NATURAL := 200 * 10**6;
+  CONSTANT st_clk_period           : TIME :=  (10**9 / c_nof_st_clk_per_s) * 1 ns;  -- 5 ns, 200 MHz
+
+  CONSTANT c_bg_block_len    : NATURAL := g_bg_ctrl.samples_per_packet;
+  CONSTANT c_bg_slot_len     : NATURAL := c_bg_block_len + g_bg_ctrl.gapsize;
+  CONSTANT c_eth_packet_len  : NATURAL := func_eth_tester_eth_packet_length(c_bg_block_len);
+
+  -- Use REAL to avoid NATURAL overflow in bps calculation
+  CONSTANT c_bg_nof_bps      : REAL := REAL(c_bg_block_len * c_octet_w) * REAL(c_nof_st_clk_per_s) / REAL(c_bg_slot_len);
+  CONSTANT c_bg_sync_period  : NATURAL := c_bg_slot_len * g_bg_ctrl.blocks_per_sync;
+
+  CONSTANT c_run_time        : NATURAL := g_nof_sync * c_bg_sync_period;
+  CONSTANT c_nof_sync        : NATURAL := c_run_time / c_bg_sync_period;
+
+  -- Destination UDP port
+  CONSTANT c_rx_udp_port     : NATURAL := TO_UINT(c_eth_tester_udp_dst_port);
+  CONSTANT c_dst_udp_port    : NATURAL := sel_a_b(g_udp_port_match, c_rx_udp_port, 17);
+
+  -- Expected Tx --> Rx latency values obtained from a tb run
+  CONSTANT c_tx_exp_latency          : NATURAL := 0;
+  CONSTANT c_rx_exp_latency_en       : BOOLEAN := c_bg_block_len >= 50;
+  CONSTANT c_rx_exp_latency_st       : NATURAL := sel_a_b(g_udp_port_match, 58, 0);
+
+  CONSTANT c_nof_valid_per_packet    : NATURAL := c_bg_block_len;
+
+  CONSTANT c_total_count_nof_valid_per_sync  : NATURAL := g_bg_ctrl.blocks_per_sync * c_nof_valid_per_packet;
+
+  CONSTANT c_mon_nof_sop_tx    : NATURAL := g_bg_ctrl.blocks_per_sync;
+  CONSTANT c_mon_nof_sop_rx    : NATURAL := sel_a_b(g_udp_port_match, c_mon_nof_sop_tx, 0);
+  CONSTANT c_mon_nof_valid_tx  : NATURAL := c_mon_nof_sop_tx * ceil_div(c_bg_block_len * c_octet_w, c_word_w);
+  CONSTANT c_mon_nof_valid_rx  : NATURAL := c_mon_nof_sop_rx * c_nof_valid_per_packet;
+
+  -- Use sim default src MAC, IP, UDP port from eth_tester_pkg.vhd and based on c_gn_index
+  CONSTANT c_gn_index           : NATURAL := 17;  -- global node index
+  CONSTANT c_gn_eth_src_mac     : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0) := c_eth_tester_eth_src_mac_47_16 & func_eth_tester_gn_index_to_mac_15_0(c_gn_index);
+  CONSTANT c_gn_ip_src_addr     : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := c_eth_tester_ip_src_addr_31_16 & func_eth_tester_gn_index_to_ip_15_0(c_gn_index);
+  CONSTANT c_gn_udp_src_port    : STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0) := c_eth_tester_udp_src_port_15_8 & TO_UVEC(c_gn_index, 8);
+
+  -- Clocks and reset
+  SIGNAL mm_rst              : STD_LOGIC := '1';
+  SIGNAL mm_clk              : STD_LOGIC := '1';
+  SIGNAL st_rst              : STD_LOGIC := '1';
+  SIGNAL st_clk              : STD_LOGIC := '1';
+  SIGNAL st_pps              : STD_LOGIC := '0';
+  SIGNAL stimuli_end         : STD_LOGIC := '0';
+  SIGNAL tb_end              : STD_LOGIC := '0';
+
+  SIGNAL tx_fifo_rd_emp      : STD_LOGIC;
+
+  -- ETH UDP data path interface
+  SIGNAL tx_udp_sosi         : t_dp_sosi;
+  SIGNAL tx_udp_siso         : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL rx_udp_sosi         : t_dp_sosi;
+
+  -- MM interface
+  -- . Tx
+  SIGNAL reg_bg_ctrl_copi                : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_bg_ctrl_cipo                : t_mem_cipo;
+  SIGNAL reg_hdr_dat_copi                : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_hdr_dat_cipo                : t_mem_cipo;
+  SIGNAL reg_bsn_monitor_v2_tx_copi      : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_bsn_monitor_v2_tx_cipo      : t_mem_cipo;
+  SIGNAL reg_strobe_total_count_tx_copi  : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_strobe_total_count_tx_cipo  : t_mem_cipo;
+  -- . Rx
+  SIGNAL reg_bsn_monitor_v2_rx_copi      : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_bsn_monitor_v2_rx_cipo      : t_mem_cipo;
+  SIGNAL reg_strobe_total_count_rx_copi  : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_strobe_total_count_rx_cipo  : t_mem_cipo;
+
+  -- . reg_strobe_total_count
+  SIGNAL tx_total_count_nof_packet       : NATURAL;
+  SIGNAL rx_total_count_nof_packet       : NATURAL;
+  SIGNAL tx_exp_total_count_nof_packet   : NATURAL;
+  SIGNAL rx_exp_total_count_nof_packet   : NATURAL;
+
+  SIGNAL rx_total_count_nof_valid        : NATURAL;
+  SIGNAL rx_exp_total_count_nof_valid    : NATURAL;
+
+  -- . reg_bsn_monitor_v2
+  SIGNAL tx_mon_nof_sop      : NATURAL;
+  SIGNAL tx_mon_nof_valid    : NATURAL;
+  SIGNAL tx_mon_latency      : NATURAL;
+  SIGNAL rx_mon_nof_sop      : NATURAL;
+  SIGNAL rx_mon_nof_valid    : NATURAL;
+  SIGNAL rx_mon_latency      : NATURAL;
+
+  -- ETH stream
+  SIGNAL tse_tx_sosi         : t_dp_sosi;
+  SIGNAL tse_tx_siso         : t_dp_siso;
+  SIGNAL tse_rx_sosi         : t_dp_sosi;
+  SIGNAL tse_rx_siso         : t_dp_siso;
+
+  -- View in Wave window
+  SIGNAL dbg_g_bg_ctrl            : t_diag_block_gen_integer := g_bg_ctrl;
+  SIGNAL dbg_c_run_time           : NATURAL := c_run_time;
+  SIGNAL dbg_c_mon_nof_sop_tx     : NATURAL := c_mon_nof_sop_tx;
+  SIGNAL dbg_c_mon_nof_sop_rx     : NATURAL := c_mon_nof_sop_rx;
+  SIGNAL dbg_c_mon_nof_valid_tx   : NATURAL := c_mon_nof_valid_tx;
+  SIGNAL dbg_c_mon_nof_valid_rx   : NATURAL := c_mon_nof_valid_rx;
+
+BEGIN
+
+  mm_clk <= (NOT mm_clk) OR tb_end AFTER mm_clk_period/2;
+  st_clk <= (NOT st_clk) OR tb_end AFTER st_clk_period/2;
+  mm_rst <= '1', '0' AFTER mm_clk_period*5;
+  st_rst <= '1', '0' AFTER st_clk_period*5;
+
+  tx_exp_total_count_nof_packet <= c_nof_sync * g_bg_ctrl.blocks_per_sync;
+  rx_exp_total_count_nof_packet <= sel_a_b(g_udp_port_match, tx_exp_total_count_nof_packet, 0);
+
+  rx_exp_total_count_nof_valid <= sel_a_b(g_udp_port_match, c_nof_sync * c_total_count_nof_valid_per_sync, 0);
+
+  -----------------------------------------------------------------------------
+  -- MM control and monitoring
+  -----------------------------------------------------------------------------
+  p_mm : PROCESS
+  BEGIN
+    tb_end <= '0';
+
+    proc_common_wait_until_low(mm_clk, mm_rst);
+    proc_common_wait_some_cycles(mm_clk, 10);
+
+    ---------------------------------------------------------------------------
+    -- Rx UDP offload port
+    ---------------------------------------------------------------------------
+    -- Set destination MAC/IP/UDP port in tx header
+    -- The MM addresses follow from byte address_offset // 4 in eth.peripheral.yaml
+    proc_mem_mm_bus_wr(16#7#, c_dst_udp_port, mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);
+    proc_mem_mm_bus_wr(16#10#, TO_SINT(c_eth_tester_ip_dst_addr), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);  -- use signed to fit 32 b in INTEGER
+    proc_mem_mm_bus_wr(16#18#, TO_SINT(c_eth_tester_eth_dst_mac(31 DOWNTO 0)), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);  -- use signed to fit 32 b in INTEGER
+    proc_mem_mm_bus_wr(16#19#, TO_UINT(c_eth_tester_eth_dst_mac(47 DOWNTO 32)), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);
+
+    ---------------------------------------------------------------------------
+    -- Stimuli
+    ---------------------------------------------------------------------------
+    -- Prepare the BG
+    proc_mem_mm_bus_wr(1, g_bg_ctrl.samples_per_packet, mm_clk, reg_bg_ctrl_copi);
+    proc_mem_mm_bus_wr(2, g_bg_ctrl.blocks_per_sync,    mm_clk, reg_bg_ctrl_copi);
+    proc_mem_mm_bus_wr(3, g_bg_ctrl.gapsize,            mm_clk, reg_bg_ctrl_copi);
+    proc_mem_mm_bus_wr(4, g_bg_ctrl.mem_low_adrs,       mm_clk, reg_bg_ctrl_copi);
+    proc_mem_mm_bus_wr(5, g_bg_ctrl.mem_high_adrs,      mm_clk, reg_bg_ctrl_copi);
+    proc_mem_mm_bus_wr(6, g_bg_ctrl.bsn_init,           mm_clk, reg_bg_ctrl_copi);  -- low part
+    proc_mem_mm_bus_wr(7, 0,                            mm_clk, reg_bg_ctrl_copi);  -- high part
+    -- Enable the BG at st_pps pulse.
+    proc_mem_mm_bus_wr(0, 3, mm_clk, reg_bg_ctrl_copi);
+    proc_common_wait_some_cycles(mm_clk, 10);
+    -- Issue an st_pps pulse to start the enabled BG
+    proc_common_gen_pulse(st_clk, st_pps);
+
+    -- Run test
+    proc_common_wait_some_cycles(st_clk, c_run_time);
+
+    -- Disable the BG
+    proc_mem_mm_bus_wr(0, 0, mm_clk, reg_bg_ctrl_copi);
+
+    -- Wait until Tx FIFO has emptied for the stream
+    WHILE tx_fifo_rd_emp /= '1' LOOP
+      proc_common_wait_some_cycles(st_clk, 1);
+    END LOOP;
+    proc_common_wait_some_cycles(st_clk, c_bg_sync_period);
+    stimuli_end <= '1';
+
+    -- Delay logging between different tb instances
+    proc_common_wait_some_cycles(st_clk, g_tb_index * 100);
+
+    -- Print logging
+    print_str("");   -- log empty line between tb results
+    print_str(c_tb_str &
+        "ETH bit rate :" &
+        " c_bg_nof_bps = " & REAL'IMAGE(c_bg_nof_bps) & " bps");
+    ASSERT c_bg_nof_bps < 10.0**9 REPORT "Tx flow control will keep ETH bitrate < 1Gbps." SEVERITY NOTE;
+
+    -------------------------------------------------------------------------
+    -- Verification: Total counts
+    -------------------------------------------------------------------------
+    -- . read low part, ignore high part (= 0) of two word total counts
+    -- Tx total nof packets
+    proc_mem_mm_bus_rd(0, mm_clk, reg_strobe_total_count_tx_cipo, reg_strobe_total_count_tx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    tx_total_count_nof_packet <= TO_UINT(reg_strobe_total_count_tx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    -- Rx total nof packets
+    proc_mem_mm_bus_rd(0, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    rx_total_count_nof_packet <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    -- Rx total nof valids
+    proc_mem_mm_bus_rd(2, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    rx_total_count_nof_valid <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    proc_common_wait_some_cycles(mm_clk, 1);
+
+    -- Print logging
+    print_str(c_tb_str &
+        "Tx total counts monitor :" &
+        " nof_packet = " & NATURAL'IMAGE(tx_total_count_nof_packet));
+
+    print_str(c_tb_str &
+        "Rx total counts monitor :" &
+        " nof_packet = " & NATURAL'IMAGE(rx_total_count_nof_packet) &
+        ", nof_valid  = " & NATURAL'IMAGE(rx_total_count_nof_valid));
+
+    -- Verify, only log when wrong
+    IF c_bg_nof_bps < 10.0**9 THEN
+      ASSERT tx_total_count_nof_packet = tx_exp_total_count_nof_packet REPORT c_tb_str &
+          "Wrong Tx total nof packets count, Tx count = " & NATURAL'IMAGE(tx_total_count_nof_packet) &
+          " /= " & NATURAL'IMAGE(tx_exp_total_count_nof_packet) &
+          " = Expected count" SEVERITY ERROR;
+
+      ASSERT rx_total_count_nof_packet = rx_exp_total_count_nof_packet REPORT c_tb_str &
+          "Wrong Rx total nof packets count, Rx count = " & NATURAL'IMAGE(rx_total_count_nof_packet) &
+          " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_packet) &
+          " = Expected count" SEVERITY ERROR;
+
+      ASSERT rx_total_count_nof_valid = rx_exp_total_count_nof_valid REPORT c_tb_str &
+          "Wrong Rx total nof valids count, Rx count = " & NATURAL'IMAGE(rx_total_count_nof_valid) &
+          " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_valid) &
+          " = Expected count" SEVERITY ERROR;
+    END IF;
+
+    -------------------------------------------------------------------------
+    -- Verification: BSN monitors (yield same values in every sync interval)
+    -------------------------------------------------------------------------
+    -- 3 = nof_sop
+    -- 4 = nof_valid
+    -- 6 = latency
+    -- . Tx
+    proc_mem_mm_bus_rd(3, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    tx_mon_nof_sop <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    proc_mem_mm_bus_rd(4, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    tx_mon_nof_valid <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    proc_mem_mm_bus_rd(6, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    tx_mon_latency <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    -- . Rx
+    proc_mem_mm_bus_rd(3, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    rx_mon_nof_sop <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    proc_mem_mm_bus_rd(4, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    rx_mon_nof_valid <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    proc_mem_mm_bus_rd(6, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    rx_mon_latency <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+    proc_common_wait_some_cycles(mm_clk, 1);
+
+    -- Print logging
+    print_str(c_tb_str &
+        "Tx BSN monitor :" &
+        " nof_sop = " & NATURAL'IMAGE(tx_mon_nof_sop) &
+        ", nof_valid = " & NATURAL'IMAGE(tx_mon_nof_valid) &
+        ", latency = " & NATURAL'IMAGE(tx_mon_latency));
+
+    print_str(c_tb_str &
+        "Rx BSN monitor :" &
+        " nof_sop = " & NATURAL'IMAGE(rx_mon_nof_sop) &
+        ", nof_valid = " & NATURAL'IMAGE(rx_mon_nof_valid) &
+        ", latency = " & NATURAL'IMAGE(rx_mon_latency));
+
+    IF c_bg_nof_bps < 10.0**9 THEN
+      -- Verify BSN monitors only when the BG sync interval is stable, so
+      -- the ETH data rate < 1 Gbps and no BG block flow control.
+      -- Verify, only log when wrong
+      ASSERT tx_mon_nof_sop = c_mon_nof_sop_tx REPORT c_tb_str & "Wrong tx nof_sop" SEVERITY ERROR;
+      ASSERT rx_mon_nof_sop = c_mon_nof_sop_rx REPORT c_tb_str & "Wrong rx nof_sop" SEVERITY ERROR;
+      ASSERT tx_mon_nof_valid = c_mon_nof_valid_tx REPORT c_tb_str & "Wrong tx nof_valid" SEVERITY ERROR;
+      ASSERT rx_mon_nof_valid = c_mon_nof_valid_rx REPORT c_tb_str & "Wrong rx nof_valid" SEVERITY ERROR;
+      ASSERT tx_mon_latency = c_tx_exp_latency REPORT c_tb_str & "Wrong tx latency" SEVERITY ERROR;
+
+      -- For short block lengths the Rx latency appears to become less, the
+      -- exact Rx latency is therefore hard to predetermine. The actual
+      -- latency is not critical, therefore it is sufficient to only very
+      -- the latency when it is more or less fixed.
+      IF c_rx_exp_latency_en THEN
+        ASSERT almost_equal(rx_mon_latency, c_rx_exp_latency_st, 0) REPORT
+            c_tb_str & "Wrong rx latency using st interface" SEVERITY ERROR;
+      END IF;
+    END IF;
+
+    -------------------------------------------------------------------------
+    -- End of test
+    -------------------------------------------------------------------------
+    proc_common_wait_some_cycles(mm_clk, 100);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+
+  u_eth_tester : ENTITY work.eth_tester
+  GENERIC MAP (
+    g_nof_streams      => 1,
+    g_bg_sync_timeout  => c_eth_tester_sync_timeout,
+    g_remove_crc       => FALSE  -- no CRC with streaming loopback
+  )
+  PORT MAP (
+    -- Clocks and reset
+    mm_rst             => mm_rst,
+    mm_clk             => mm_clk,
+    st_rst             => st_rst,
+    st_clk             => st_clk,
+    st_pps             => st_pps,
+
+    -- UDP transmit interface
+    eth_src_mac        => c_gn_eth_src_mac,
+    ip_src_addr        => c_gn_ip_src_addr,
+    udp_src_port       => c_gn_udp_src_port,
+
+    sl(tx_fifo_rd_emp_arr) => tx_fifo_rd_emp,
+
+    TO_DP_ONE(tx_udp_sosi_arr) => tx_udp_sosi,
+    tx_udp_siso_arr    => TO_DP_ARR(tx_udp_siso),
+
+    -- UDP receive interface
+    rx_udp_sosi_arr    => TO_DP_ARR(rx_udp_sosi),
+
+    -- Memory Mapped Slaves (one per stream)
+    -- . Tx
+    reg_bg_ctrl_copi               => reg_bg_ctrl_copi,
+    reg_bg_ctrl_cipo               => reg_bg_ctrl_cipo,
+    reg_hdr_dat_copi               => reg_hdr_dat_copi,
+    reg_hdr_dat_cipo               => reg_hdr_dat_cipo,
+    reg_bsn_monitor_v2_tx_copi     => reg_bsn_monitor_v2_tx_copi,
+    reg_bsn_monitor_v2_tx_cipo     => reg_bsn_monitor_v2_tx_cipo,
+    reg_strobe_total_count_tx_copi => reg_strobe_total_count_tx_copi,
+    reg_strobe_total_count_tx_cipo => reg_strobe_total_count_tx_cipo,
+    -- . Rx
+    reg_bsn_monitor_v2_rx_copi     => reg_bsn_monitor_v2_rx_copi,
+    reg_bsn_monitor_v2_rx_cipo     => reg_bsn_monitor_v2_rx_cipo,
+    reg_strobe_total_count_rx_copi => reg_strobe_total_count_rx_copi,
+    reg_strobe_total_count_rx_cipo => reg_strobe_total_count_rx_cipo
+  );
+  
+
+  -- ETH stream
+  u_dut : ENTITY work.eth_stream_udp
+  GENERIC MAP (
+    g_rx_udp_port => c_rx_udp_port
+  )
+  PORT MAP (
+    -- Clocks and reset
+    st_rst        => st_rst,
+    st_clk        => st_clk,
+
+    -- User UDP interface
+    -- . Tx
+    udp_tx_sosi   => tx_udp_sosi,
+    udp_tx_siso   => tx_udp_siso,
+    -- . Rx
+    udp_rx_sosi   => rx_udp_sosi,
+    udp_rx_siso   => c_dp_siso_rdy,
+
+    -- PHY interface
+    -- . Tx
+    tse_tx_sosi   => tse_tx_sosi,
+    tse_tx_siso   => tse_tx_siso,
+    -- . Rx
+    tse_rx_sosi   => tse_rx_sosi,
+    tse_rx_siso   => tse_rx_siso
+  );
+
+  -- Loopback wire Tx to Rx, register to increasy ready latency from 1 to 2
+  tse_rx_sosi <= tse_tx_sosi WHEN rising_edge(st_clk);
+  tse_tx_siso <= tse_rx_siso;
+
+END tb;
diff --git a/libraries/io/eth/tb/vhdl/tb_eth_tester_pkg.vhd b/libraries/io/eth/tb/vhdl/tb_eth_tester_pkg.vhd
index 4705b6f018f3b1f657ee08fd7ee846a909855ef8..93ca1f7791404443c6bcde867d3aada200646a1c 100644
--- a/libraries/io/eth/tb/vhdl/tb_eth_tester_pkg.vhd
+++ b/libraries/io/eth/tb/vhdl/tb_eth_tester_pkg.vhd
@@ -37,7 +37,7 @@ PACKAGE tb_eth_tester_pkg is
 
   CONSTANT c_eth_tester_eth_dst_mac       : STD_LOGIC_VECTOR(47 DOWNTO 0) := x"001B217176B9";  -- 001B217176B9 = DOP36-enp2s0
   CONSTANT c_eth_tester_ip_dst_addr       : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"0A6300FE";  -- 0A6300FE = '10.99.0.254' = DOP36-enp2s0
-  CONSTANT c_eth_tester_udp_dst_port      : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(6001, 16);  -- 0x1771 = 6001
+  CONSTANT c_eth_tester_udp_dst_port      : STD_LOGIC_VECTOR(15 DOWNTO 0) := c_eth_tester_eth1g_II_rx_udp_port;
 
   -- Ethernet packet length in octets inclduing eth header and CRC
   FUNCTION func_eth_tester_eth_packet_length(block_len : NATURAL) RETURN NATURAL;
diff --git a/libraries/io/eth/tb/vhdl/tb_tb_eth_stream_udp.vhd b/libraries/io/eth/tb/vhdl/tb_tb_eth_stream_udp.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..82b1b5710af83a767611c835c6d6c34005ab299d
--- /dev/null
+++ b/libraries/io/eth/tb/vhdl/tb_tb_eth_stream_udp.vhd
@@ -0,0 +1,80 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2022
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+-- Author: E. Kooistra
+-- Purpose: Multi test bench for eth_stream_udp
+-- Description:
+--
+-- Usage:
+--   > as 8
+--   > run -all
+
+LIBRARY IEEE, diag_lib;
+USE IEEE.std_logic_1164.ALL;
+USE diag_lib.diag_pkg.ALL;
+USE work.tb_eth_tester_pkg.ALL;
+
+ENTITY tb_tb_eth_stream_udp IS
+END tb_tb_eth_stream_udp;
+
+ARCHITECTURE tb OF tb_tb_eth_stream_udp IS
+
+  -- Tb
+  CONSTANT c_eth_clk_MHz   : NATURAL := 125;
+  CONSTANT c_st_clk_MHz    : NATURAL := 200;
+  CONSTANT c_nof_sync      : NATURAL := 2;
+  CONSTANT c_nof_blk       : NATURAL := 3;   -- nof_blk per sync
+
+  -- Tx packet size and gap size in octets
+  CONSTANT c_block_len     : NATURAL := 50;
+  CONSTANT c_link_len      : NATURAL := func_eth_tester_eth_packet_on_link_length(c_block_len);
+
+  -- For near maximum 1Gbps link rate the c_block_len + c_gap_len_min time
+  -- in the st_clk domain equals c_link_len time in eth_clk domain.
+  CONSTANT c_gap_len_min   : NATURAL := c_link_len * c_st_clk_MHz / c_eth_clk_MHz - c_block_len;
+
+  -- Choose c_gap_len somewhat larger to have packet link rate < 1 Gbps
+  CONSTANT c_gap_len       : NATURAL := c_gap_len_min * 2;   -- for g_nof_streams = 1
+
+  -- BG ctrl
+  CONSTANT c_high          : NATURAL := c_diag_bg_mem_max_adr;  -- = 2**24
+
+  CONSTANT c_bg_ctrl       : t_diag_block_gen_integer := ('1', '1', c_block_len,  c_nof_blk, c_gap_len, 0, c_high, 0);  -- for first stream
+
+BEGIN
+
+--  g_tb_index         : NATURAL := 0;  -- use to incremental delay logging from tb instances in tb_tb
+--  g_nof_sync         : NATURAL := 2;  -- number of BG sync intervals to set c_run_time
+--  g_udp_port_match   : BOOLEAN := TRUE;
+--
+--  -- t_diag_block_gen_integer =
+--  --   sl:  enable
+--  --   sl:  enable_sync
+--  --   nat: samples_per_packet
+--  --   nat: blocks_per_sync
+--  --   nat: gapsize
+--  --   nat: mem_low_adrs
+--  --   nat: mem_high_adrs
+--  --   nat: bsn_init
+--  g_bg_ctrl    : t_diag_block_gen_integer := ('1', '1', 50, 3, 200, 0, c_diag_bg_mem_max_adr, 0)  -- for first stream
+
+  u_udp          : ENTITY work.tb_eth_stream_udp GENERIC MAP (0, c_nof_sync,  TRUE, c_bg_ctrl);
+  u_udp_mismatch : ENTITY work.tb_eth_stream_udp GENERIC MAP (1, c_nof_sync, FALSE, c_bg_ctrl);
+
+END tb;
diff --git a/libraries/technology/tse/hdllib.cfg b/libraries/technology/tse/hdllib.cfg
index 5b71fe5191e51bac29016fed57641fab7f0cfcc8..86bd3ec8218f5f562c477a4dde02f407d2a573b8 100644
--- a/libraries/technology/tse/hdllib.cfg
+++ b/libraries/technology/tse/hdllib.cfg
@@ -29,16 +29,20 @@ synth_files =
     tech_tse_arria10_e1sg.vhd
     tech_tse_arria10_e2sg.vhd
     tech_tse.vhd
+    tech_tse_setup.vhd
+    tech_tse_with_setup.vhd
     tb_tech_tse_pkg.vhd
 
 test_bench_files =
     sim_tse.vhd
     tb_tech_tse_pkg.vhd
     tb_tech_tse.vhd
+    tb_tech_tse_with_setup.vhd
     tb_tb_tech_tse.vhd
 
 regression_test_vhdl = 
     tb_tb_tech_tse.vhd
+    tb_tech_tse_with_setup.vhd
 
 
 [modelsim_project_file]
diff --git a/libraries/technology/tse/tb_tech_tse.vhd b/libraries/technology/tse/tb_tech_tse.vhd
index ce074ce5673c8b798bdc26a7f934adb1e5cebddd..5c43594f5cb322abd32f0a8a382cdfd934214401 100644
--- a/libraries/technology/tse/tb_tech_tse.vhd
+++ b/libraries/technology/tse/tb_tech_tse.vhd
@@ -50,7 +50,7 @@ ENTITY tb_tech_tse IS
     --   g_data_type = c_tb_tech_tse_data_type_counter  = 1
     g_data_type  : NATURAL := c_tb_tech_tse_data_type_symbols;
     g_sim        : BOOLEAN := TRUE;
-    g_sim_level  : NATURAL := 1;    -- 0 = use IP; 1 = use fast serdes model;
+    g_sim_level  : NATURAL := 0;    -- 0 = use IP; 1 = use fast serdes model;
     g_tb_end     : BOOLEAN := TRUE  -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
   );
   PORT (
@@ -100,7 +100,9 @@ ARCHITECTURE tb OF tb_tech_tse IS
   SIGNAL mm_init           : STD_LOGIC := '1';
   SIGNAL mm_miso           : t_mem_miso;
   SIGNAL mm_mosi           : t_mem_mosi;
-  
+  SIGNAL mm_wrdata         : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for view in Wave window
+  SIGNAL mm_rddata         : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for view in Wave window
+
   SIGNAL mm_psc_access     : STD_LOGIC;
 
   -- TSE MAC transmit interface
@@ -116,6 +118,7 @@ ARCHITECTURE tb OF tb_tech_tse IS
   -- . The tb is the ST sink
   SIGNAL rx_sosi           : t_dp_sosi;
   SIGNAL rx_siso           : t_dp_siso;
+  SIGNAL rx_data           : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for view in Wave window
   -- . MAC specific
   SIGNAL rx_mac_out        : t_tech_tse_rx_mac;
 
@@ -143,6 +146,10 @@ BEGIN
   total_header_loopback.eth <= c_eth_header_loopback;
   total_header_etherlen.eth <= c_eth_header_etherlen;
 
+  mm_wrdata <= mm_mosi.wrdata(c_word_w-1 DOWNTO 0);
+  mm_rddata <= mm_miso.rddata(c_word_w-1 DOWNTO 0);
+  rx_data <= rx_sosi.data(c_word_w-1 DOWNTO 0);
+
   p_mm_setup : PROCESS
   BEGIN
     mm_init  <= '1';
diff --git a/libraries/technology/tse/tb_tech_tse_with_setup.vhd b/libraries/technology/tse/tb_tech_tse_with_setup.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..988214e6568cbbce51a166b5b883b624f09c93ae
--- /dev/null
+++ b/libraries/technology/tse/tb_tech_tse_with_setup.vhd
@@ -0,0 +1,308 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2009
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.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: Testbench for tech_tse for the Tripple Speed Ethernet IP technology
+--          wrapper, with setup.
+-- Description:
+--   Same tb as tb_tech_tse.vhd, but instead:
+--   . fixed use TSE IP (c_sim_level = 0)
+--   . using TSE setup in DUT
+--   . verify external MM access to TSE after setup in p_mm_setup.
+--   . use c_jumbo_en = FALSE for maximum 1500 packet size as with unb_osy, a
+--     9000 octet packet is received properly, but has rx_src_out.err = 3
+--     indicating invalid length. Use c_jumbo_en = TRUE to avoid invalid
+--     length.
+-- Usage:
+--   > as 10
+--   > run -all
+
+LIBRARY IEEE, technology_lib, common_lib, dp_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.common_network_layers_pkg.ALL;
+USE common_lib.common_network_total_header_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE technology_lib.technology_pkg.ALL;
+USE technology_lib.technology_select_pkg.ALL;
+USE WORK.tech_tse_pkg.ALL;
+USE WORK.tb_tech_tse_pkg.ALL;
+
+
+ENTITY tb_tech_tse_with_setup IS
+  -- Test bench control parameters
+  GENERIC (
+    g_technology : NATURAL := c_tech_select_default;
+    --   g_data_type = c_tb_tech_tse_data_type_symbols  = 0
+    --   g_data_type = c_tb_tech_tse_data_type_counter  = 1
+    g_data_type  : NATURAL := c_tb_tech_tse_data_type_symbols;
+    g_tb_end     : BOOLEAN := TRUE  -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
+  );
+  PORT (
+    tb_end : OUT STD_LOGIC
+  );
+END tb_tech_tse_with_setup;
+
+
+ARCHITECTURE tb OF tb_tech_tse_with_setup IS
+
+  CONSTANT c_sim                : BOOLEAN := TRUE;
+  CONSTANT c_sim_level          : NATURAL := 0;    -- 0 = use IP; 1 = use fast serdes model;
+  CONSTANT c_jumbo_en           : BOOLEAN := TRUE;
+
+  CONSTANT sys_clk_period       : TIME := 10 ns;  -- 100 MHz
+  CONSTANT eth_clk_period       : TIME :=  8 ns;  -- 125 MHz
+  CONSTANT cable_delay          : TIME := sel_a_b(c_sim_level=0, 12 ns, 0 ns);
+
+  CONSTANT c_promis_en          : BOOLEAN := FALSE;
+  CONSTANT c_tx_ready_latency   : NATURAL := c_tech_tse_tx_ready_latency;  -- 0, 1 are supported, must match TSE MAC c_tech_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
+
+  --CONSTANT c_pkt_length_arr     : t_nat_natural_arr := (0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1472, 1473, 9000);
+  CONSTANT c_pkt_length_arr     : t_nat_natural_arr := array_init(0, 80, 1) & array_init(1499, 2, 1) & 9000;
+  CONSTANT c_nof_pkt            : NATURAL := c_pkt_length_arr'LENGTH;
+  
+  CONSTANT c_dst_mac            : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"10FA01020300";
+  CONSTANT c_src_mac            : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"123456789ABC";  -- = 12-34-56-78-9A-BC
+  CONSTANT c_ethertype          : STD_LOGIC_VECTOR(c_network_eth_type_slv'RANGE) := X"10FA";
+  CONSTANT c_etherlen           : STD_LOGIC_VECTOR(c_network_eth_type_slv'RANGE) := "0000000000010000";
+
+  -- Packet headers
+  CONSTANT c_eth_header_loopback : t_network_eth_header := (c_src_mac, c_src_mac, c_ethertype);
+  CONSTANT c_eth_header_etherlen : t_network_eth_header := (c_src_mac, c_src_mac, c_etherlen);
+  
+  SIGNAL total_header_loopback   : t_network_total_header;
+  SIGNAL total_header_etherlen   : t_network_total_header;
+  
+  -- Clocks and reset
+  SIGNAL rx_end            : STD_LOGIC := '0';
+  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 mm_clk            : STD_LOGIC;         -- memory-mapped bus clock
+  SIGNAL mm_rst            : STD_LOGIC;         -- reset synchronous with mm_clk
+
+  -- TSE MAC control interface
+  SIGNAL tse_setup_done    : STD_LOGIC;
+
+  SIGNAL mm_init           : STD_LOGIC := '1';
+  SIGNAL mm_copi           : t_mem_copi;
+  SIGNAL mm_cipo           : t_mem_cipo;
+  SIGNAL mm_rddata         : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for view in Wave window
+
+  -- TSE MAC transmit interface
+  -- . The tb is the ST source
+  SIGNAL tx_en             : STD_LOGIC := '1';
+  SIGNAL tx_siso           : t_dp_siso;
+  SIGNAL tx_sosi           : t_dp_sosi;
+  -- . MAC specific
+  SIGNAL tx_mac_in         : t_tech_tse_tx_mac;
+  SIGNAL tx_mac_out        : t_tech_tse_tx_mac;
+
+  -- TSE MAC receive interface
+  -- . The tb is the ST sink
+  SIGNAL rx_sosi           : t_dp_sosi;
+  SIGNAL rx_siso           : t_dp_siso;
+  SIGNAL rx_data           : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for view in Wave window
+  -- . MAC specific
+  SIGNAL rx_mac_out        : t_tech_tse_rx_mac;
+
+  -- TSE PHY interface
+  SIGNAL eth_txp           : STD_LOGIC;
+  SIGNAL eth_rxp           : STD_LOGIC;
+
+  SIGNAL tse_led           : t_tech_tse_led;
+
+  -- Verification
+  SIGNAL tx_pkt_cnt     : NATURAL := 0;
+  SIGNAL rx_pkt_cnt     : NATURAL := 0;
+  
+BEGIN
+
+  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;
+  
+  -- Use signal to leave unused fields 'X'
+  total_header_loopback.eth <= c_eth_header_loopback;
+  total_header_etherlen.eth <= c_eth_header_etherlen;
+
+  mm_rddata <= mm_cipo.rddata(c_word_w-1 DOWNTO 0);
+  rx_data <= rx_sosi.data(c_word_w-1 DOWNTO 0);
+
+  p_mm_setup : PROCESS
+  BEGIN
+    mm_init <= '1';
+    mm_copi.wr <= '0';
+    mm_copi.rd <= '0';
+
+    -- reset release
+    mm_rst <= '1';
+    FOR I IN 0 TO 9 LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
+    mm_rst <= '0';
+    FOR I IN 0 TO 9 LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
+
+    -- Wait for tech_tse_with_setup to finish MM access to TSE
+    proc_common_wait_until_high(mm_clk, tse_setup_done);
+    proc_common_wait_some_cycles(mm_clk, 10);
+
+    -- Verify external MM access to TSE
+    proc_mem_mm_bus_rd(16#000#, mm_clk, mm_cipo, mm_copi);  -- REV --> CUST_VERSION & 0x0901, 0x1304
+    ASSERT UNSIGNED(mm_rddata(c_16-1 DOWNTO 0)) = X"1304" REPORT "Wrong external MM read access result." SEVERITY ERROR;
+
+    -- Wait for link synchronisation
+    proc_common_wait_until_high(mm_clk, tse_led.link);
+    proc_common_wait_some_cycles(mm_clk, 10);
+
+    mm_init <= '0';
+    WAIT;
+  END PROCESS;
+
+  
+  p_ff_transmitter : PROCESS
+  BEGIN
+    -- . Avalon ST
+    tx_sosi.data  <= (OTHERS=>'0');
+    tx_sosi.valid <= '0';
+    tx_sosi.sop   <= '0';
+    tx_sosi.eop   <= '0';
+    tx_sosi.empty <= (OTHERS=>'0');
+    tx_sosi.err   <= (OTHERS=>'0');
+    -- . MAC specific
+    tx_mac_in.crc_fwd <= '0';  -- when '0' then TSE MAC generates the TX CRC field
+
+    WHILE mm_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;
+
+    -- Loopback txp->rxp so DST_MAC = c_src_mac to send to itself
+    
+    -- TX frame:
+    -- . I=0 is empty payload, so only 4 words of the ETH header with 46 padding zeros, so empty = 2
+    -- . For I=1 to 46 the payload length remains 46 with padding zeros, so empty = 2
+    -- . For I>46 the payload length is I and empty = 4 - (I mod 4)
+    
+    FOR I IN 0 TO c_nof_pkt-1 LOOP
+      proc_tech_tse_tx_packet(total_header_loopback, c_pkt_length_arr(I), g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, tx_en, tx_siso, tx_sosi);
+    END LOOP;
+
+    FOR I IN 0 TO 1500 * 2 LOOP WAIT UNTIL rising_edge(st_clk); END LOOP;
+    rx_end <= '1';
+    WAIT;
+  END PROCESS;
+
+  
+  p_ff_receiver : PROCESS
+  BEGIN
+    -- . Avalon ST
+    rx_siso.ready <= '0';
+
+    WHILE mm_init/='0' LOOP
+      WAIT UNTIL rising_edge(st_clk);
+    END LOOP;
+
+    -- Receive forever
+    WHILE TRUE LOOP
+      proc_tech_tse_rx_packet(total_header_loopback, g_data_type, st_clk, rx_sosi, rx_siso);
+    END LOOP;
+
+    WAIT;
+  END PROCESS;
+
+  
+  dut : ENTITY work.tech_tse_with_setup
+  GENERIC MAP (
+    g_technology => g_technology,
+    g_ETH_PHY    => "LVDS",  -- "LVDS" (default): uses LVDS IOs for ctrl_unb_common, "XCVR": uses tranceiver PHY
+    g_jumbo_en   => c_jumbo_en,
+    g_sim        => c_sim,
+    g_sim_level  => c_sim_level     -- 0 = use IP; 1 = use fast serdes model;
+  )
+  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,
+
+    -- TSE setup
+    src_mac        => c_src_mac,
+    setup_done     => tse_setup_done,
+    
+    -- Memory Mapped Slave
+    mm_ctlr_copi   => mm_copi,
+    mm_ctlr_cipo   => mm_cipo,
+    
+    -- MAC transmit interface
+    -- . ST sink
+    tx_snk_in      => tx_sosi,
+    tx_snk_out     => tx_siso,
+    
+    -- MAC receive interface
+    -- . ST Source
+    rx_src_in      => rx_siso,
+    rx_src_out     => rx_sosi,
+
+    -- PHY interface
+    eth_txp        => eth_txp,
+    eth_rxp        => eth_rxp,
+
+    tse_led        => tse_led
+  );
+
+  -- Loopback
+  eth_rxp <= TRANSPORT eth_txp AFTER cable_delay;
+
+  -- Verification
+  tx_pkt_cnt <= tx_pkt_cnt + 1 WHEN tx_sosi.sop='1' AND rising_edge(st_clk);
+  rx_pkt_cnt <= rx_pkt_cnt + 1 WHEN rx_sosi.eop='1' AND rising_edge(st_clk);
+  
+  p_verify : PROCESS
+  BEGIN
+    tb_end <= '0';
+    WAIT UNTIL rx_end='1';
+    -- Verify that all transmitted packets have been received
+    IF tx_pkt_cnt=0 THEN
+      REPORT "No packets were transmitted." SEVERITY ERROR;
+    ELSIF rx_pkt_cnt=0 THEN
+      REPORT "No packets were received." SEVERITY ERROR;
+    ELSIF tx_pkt_cnt/=rx_pkt_cnt THEN
+      REPORT "Not all transmitted packets were received." SEVERITY ERROR;
+    END IF;
+    tb_end <= '1';
+    
+    WAIT FOR 1 ns;
+    IF g_tb_end=FALSE THEN
+      REPORT "Tb simulation finished." SEVERITY NOTE;
+    ELSE
+      REPORT "Tb simulation finished." SEVERITY FAILURE;
+    END IF;
+    WAIT;
+  END PROCESS;
+  
+END tb;
diff --git a/libraries/technology/tse/tech_tse_setup.vhd b/libraries/technology/tse/tech_tse_setup.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..fc02da2dc47117ca8647e27f75e60cd68577433b
--- /dev/null
+++ b/libraries/technology/tse/tech_tse_setup.vhd
@@ -0,0 +1,259 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2022
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+-- AUthor: E. Kooistra
+-- Purpose: Set up TSE via MM
+-- Description:
+-- . TSE set up as in tb_tech_tse_pkg, unb_osy/unbos_eth.c and
+--   eth1g_master.vhd. Cannot use proc_mem_mm_bus_*() because a synthesis
+--   process can only have one rising_edge(mm_clk) statement
+-- . After tse_init is done, then connect to external MM controller, to allow
+--   external  monitoring of the TSE.
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE work.tech_tse_pkg.ALL;
+
+ENTITY tech_tse_setup IS
+  GENERIC (
+    g_sim : BOOLEAN;
+    -- Nios 1GbE-I uses ETH_FRAME_LENGTH = 1518 in inbos_eth.h. Use g_jumbo_en
+    -- = FALSE for frame_len <= 1500 octets. If frame is longer then this
+    -- yields invalid length flag in rx_sosi.err, but data is still received.
+    -- Use g_jumbo_en = TRUE for frame_len <= 9000 octets (jumbo frames).
+    g_jumbo_en : BOOLEAN := FALSE
+  );
+  PORT (
+    -- Clocks and reset
+    mm_rst         : IN  STD_LOGIC;
+    mm_clk         : IN  STD_LOGIC;
+    
+    -- TSE setup
+    src_mac        : IN STD_LOGIC_VECTOR(c_48-1 DOWNTO 0);
+    setup_done     : OUT STD_LOGIC;
+
+    -- Memory Mapped Peripheral
+    -- . Controller side
+    mm_ctlr_copi   : IN  t_mem_copi;
+    mm_ctlr_cipo   : OUT t_mem_cipo;
+    -- . Peripheral side
+    mm_peri_copi   : OUT t_mem_copi;
+    mm_peri_cipo   : IN  t_mem_cipo
+  );
+END tech_tse_setup;
+
+ARCHITECTURE rtl OF tech_tse_setup IS
+
+  -- FALSE receive only frames for this src_mac and broadcast, TRUE receive all
+  CONSTANT c_promis_en  : BOOLEAN := FALSE;
+
+  -- Access the MM bus
+  TYPE t_state IS (s_rd_pcs_rev, s_wr_if_mode, s_rd_control, s_rd_status, s_wr_control,
+                   s_rd_mac_rev, s_wr_promis_en, s_wr_mac_0, s_wr_mac_1, s_wr_tx_ipg_len, s_wr_frm_len,
+                   s_wr_rx_section_empty, s_wr_rx_section_full, s_wr_tx_section_empty, s_wr_tx_section_full,
+                   s_wr_rx_almost_empty, s_wr_rx_almost_full, s_wr_tx_almost_empty, s_wr_tx_almost_full,
+                   s_rd_tx_cmd_stat, s_rd_rx_cmd_stat,
+                   s_done);
+
+  SIGNAL state           : t_state;
+  SIGNAL next_state      : t_state;
+  SIGNAL psc_access      : STD_LOGIC;  -- active during PCS registers access, for view in Wave window
+  SIGNAL fifo_access     : STD_LOGIC;  -- active during FIFO registers access, for view in Wave window
+
+  -- Memory Mapped Slave
+  SIGNAL tse_init        : STD_LOGIC := '1';
+  SIGNAL tse_ctlr_copi   : t_mem_copi;
+  SIGNAL tse_ctlr_cipo   : t_mem_cipo;
+  SIGNAL tse_waitrequest : STD_LOGIC;
+  SIGNAL tse_wrdata      : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for view in Wave window
+  SIGNAL tse_rddata      : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for view in Wave window
+
+  SIGNAL src_mac_0       : STD_LOGIC_VECTOR(c_32-1 DOWNTO 0);
+  SIGNAL src_mac_1       : STD_LOGIC_VECTOR(c_16-1 DOWNTO 0);
+
+BEGIN
+
+  setup_done <= NOT tse_init;
+
+  src_mac_0 <= hton(src_mac(c_48-1 DOWNTO c_16), 4);
+  src_mac_1 <= hton(src_mac(c_16-1 DOWNTO  0), 2);
+
+  -- Select MM interface controller
+  --               ___
+  --              |   |
+  --  mm_ctlr ----| 0 |
+  --              |   |---- mm_peri
+  -- tse_ctlr ----| 1 |
+  --              |___|
+  --                |
+  -- tse_init ------/
+  --
+  mm_peri_copi <= tse_ctlr_copi  WHEN tse_init = '1' ELSE mm_ctlr_copi;
+  mm_ctlr_cipo <= c_mem_cipo_rst WHEN tse_init = '1' ELSE mm_peri_cipo;
+  tse_ctlr_cipo <= mm_peri_cipo;
+  tse_waitrequest <= tse_ctlr_cipo.waitrequest;
+  tse_wrdata <= tse_ctlr_copi.wrdata(c_word_w-1 DOWNTO 0);
+  tse_rddata <= tse_ctlr_cipo.rddata(c_word_w-1 DOWNTO 0);
+
+  p_state : PROCESS(mm_rst, mm_clk)
+  BEGIN
+    IF mm_rst = '1' THEN
+      state <= s_rd_pcs_rev;
+      next_state <= s_rd_pcs_rev;
+      tse_init <= '1';
+      tse_ctlr_copi <= c_mem_copi_rst;
+      psc_access <= '0';
+      fifo_access <= '0';
+    ELSIF rising_edge(mm_clk) THEN
+      tse_init <= '1';
+      psc_access <= '0';
+      fifo_access <= '0';
+
+      -- Issue MM access
+      CASE state IS
+        -- PSC control
+        WHEN s_rd_pcs_rev =>
+          psc_access <= '1';
+          proc_mem_bus_rd(func_tech_tse_map_pcs_addr(16#22#), tse_ctlr_copi);  -- REV --> 0x0901, 0x1304
+          next_state <= s_wr_if_mode;
+
+        WHEN s_wr_if_mode =>
+          psc_access <= '1';
+          proc_mem_bus_wr(func_tech_tse_map_pcs_addr(16#28#), 16#0008#, tse_ctlr_copi);  -- IF_MODE <-- Force 1GbE,
+          next_state <= s_rd_control;
+
+        WHEN s_rd_control =>
+          psc_access <= '1';
+          proc_mem_bus_rd(func_tech_tse_map_pcs_addr(16#00#), tse_ctlr_copi);  -- CONTROL --> 0x1140
+          next_state <= s_rd_status;
+
+        WHEN s_rd_status =>
+          psc_access <= '1';
+          proc_mem_bus_rd(func_tech_tse_map_pcs_addr(16#02#), tse_ctlr_copi);  -- STATUS --> 0x000D
+          next_state <= s_wr_control;
+
+        WHEN s_wr_control =>
+          psc_access <= '1';
+          IF g_sim = FALSE THEN
+            proc_mem_bus_wr(func_tech_tse_map_pcs_addr(16#00#), 16#1140#, tse_ctlr_copi);  -- CONTROL <-- Keep auto negotiate enabled (is reset default)
+          ELSE
+            proc_mem_bus_wr(func_tech_tse_map_pcs_addr(16#00#), 16#0140#, tse_ctlr_copi);  -- CONTROL <-- In simulation disable auto negotiate
+          END IF;
+          next_state <= s_rd_mac_rev;
+
+        -- MAC control
+        WHEN s_rd_mac_rev =>
+          proc_mem_bus_rd(16#000#, tse_ctlr_copi);  -- REV --> CUST_VERSION & 0x0901
+          next_state <= s_wr_promis_en;
+
+        WHEN s_wr_promis_en =>
+          IF c_promis_en = FALSE THEN
+            proc_mem_bus_wr(16#008#, 16#0100004B#, tse_ctlr_copi);  -- COMMAND_CONFIG
+          ELSE
+            proc_mem_bus_wr(16#008#, 16#0100005B#, tse_ctlr_copi);
+          END IF;
+          next_state <= s_wr_mac_0;
+
+        WHEN s_wr_mac_0 =>
+          proc_mem_bus_wr(16#00C#, src_mac_0, tse_ctlr_copi);  -- MAC_0
+          next_state <= s_wr_mac_1;
+
+        WHEN s_wr_mac_1 =>
+          proc_mem_bus_wr(16#010#, src_mac_1, tse_ctlr_copi);  -- MAC_1 <-- SRC_MAC
+          next_state <= s_wr_tx_ipg_len;
+
+        WHEN s_wr_tx_ipg_len =>
+          proc_mem_bus_wr(16#05C#, 16#0000000C#, tse_ctlr_copi);  -- TX_IPG_LENGTH <-- interpacket gap = 12
+          next_state <= s_wr_frm_len;
+
+        WHEN s_wr_frm_len =>
+          IF g_jumbo_en = FALSE THEN
+            proc_mem_bus_wr(16#014#, 16#000005EE#, tse_ctlr_copi);  -- FRM_LENGTH <-- receive max frame length = 1518
+          ELSE
+            proc_mem_bus_wr(16#014#, 16#0000233A#, tse_ctlr_copi);  -- FRM_LENGTH <-- receive max frame length = 9018
+          END IF;
+          next_state <= s_wr_rx_section_empty;
+
+        -- MAC FIFO
+        WHEN s_wr_rx_section_empty =>
+          fifo_access <= '1';
+          proc_mem_bus_wr(16#01C#, c_tech_tse_rx_fifo_depth-16, tse_ctlr_copi);  -- RX_SECTION_EMPTY <-- default FIFO depth - 16, >3
+          next_state <= s_wr_rx_section_full;
+
+        WHEN s_wr_rx_section_full =>
+          fifo_access <= '1';
+          proc_mem_bus_wr(16#020#, 16, tse_ctlr_copi);  -- RX_SECTION_FULL <-- default 16
+          next_state <= s_wr_tx_section_empty;
+
+        WHEN s_wr_tx_section_empty =>
+          fifo_access <= '1';
+          proc_mem_bus_wr(16#024#, c_tech_tse_tx_fifo_depth-16, tse_ctlr_copi);  -- TX_SECTION_EMPTY <-- default FIFO depth - 16, >3
+          next_state <= s_wr_tx_section_full;
+
+        WHEN s_wr_tx_section_full =>
+          fifo_access <= '1';
+          proc_mem_bus_wr(16#028#, 16, tse_ctlr_copi);  -- TX_SECTION_FULL <-- default 16, >~ 8 otherwise no tx
+          next_state <= s_wr_rx_almost_empty;
+
+        WHEN s_wr_rx_almost_empty =>
+          fifo_access <= '1';
+          proc_mem_bus_wr(16#02C#, 8, tse_ctlr_copi);  -- RX_ALMOST_EMPTY <-- default 8
+          next_state <= s_wr_rx_almost_full;
+
+        WHEN s_wr_rx_almost_full =>
+          fifo_access <= '1';
+          proc_mem_bus_wr(16#030#, 8, tse_ctlr_copi);  -- RX_ALMOST_FULL <-- default 8
+          next_state <= s_wr_tx_almost_empty;
+
+        WHEN s_wr_tx_almost_empty =>
+          fifo_access <= '1';
+          proc_mem_bus_wr(16#034#, 8, tse_ctlr_copi);  -- TX_ALMOST_EMPTY  <-- default 8
+          next_state <= s_wr_tx_almost_full;
+
+        WHEN s_wr_tx_almost_full =>
+          fifo_access <= '1';
+          proc_mem_bus_wr(16#038#, c_tech_tse_tx_ready_latency + 3, tse_ctlr_copi);   -- TX_ALMOST_FULL   <-- default 3
+          next_state <= s_rd_tx_cmd_stat;
+
+        -- MAC status
+        WHEN s_rd_tx_cmd_stat =>
+          proc_mem_bus_rd(16#0E8#, tse_ctlr_copi);   -- TX_CMD_STAT --> 0x00040000 : [18]=1 TX_SHIFT16, [17]=0 OMIT_CRC
+          next_state <= s_rd_rx_cmd_stat;
+
+        WHEN s_rd_rx_cmd_stat =>
+          proc_mem_bus_rd(16#0EC#, tse_ctlr_copi);   -- RX_CMD_STAT --> 0x02000000 : [25]=1 RX_SHIFT16
+          next_state <= s_done;
+
+        WHEN OTHERS =>  -- s_done
+          tse_init <= '0';
+      END CASE;
+
+      -- Go to next state when MM access was accepted
+      IF state /= next_state AND tse_waitrequest = '0' THEN
+        tse_ctlr_copi.wr <= '0';
+        tse_ctlr_copi.rd <= '0';
+        state <= next_state;
+      END IF;
+
+    END IF;
+  END PROCESS;
+
+END ARCHITECTURE;
diff --git a/libraries/technology/tse/tech_tse_with_setup.vhd b/libraries/technology/tse/tech_tse_with_setup.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..41173fa0a9df5c51c9e9a618d751bfb88fed9e2b
--- /dev/null
+++ b/libraries/technology/tse/tech_tse_with_setup.vhd
@@ -0,0 +1,173 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2022
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+-- AUthor: E. Kooistra
+-- Purpose: Instantiate and setup TSE via MM
+-- Description:
+-- . Based on tech_tse instance in eth.vhd
+-- . Set up TSE in state machnine and then switch to external mm_ctlr, to
+--   allow external monitoring of the TSE.
+
+LIBRARY IEEE, technology_lib, common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE technology_lib.technology_pkg.ALL;
+USE technology_lib.technology_select_pkg.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE work.tech_tse_pkg.ALL;
+
+ENTITY tech_tse_with_setup IS
+  GENERIC (
+    g_technology   : NATURAL := c_tech_select_default;
+    g_ETH_PHY      : STRING  := "LVDS"; -- "LVDS" (default): uses LVDS IOs for ctrl_unb_common, "XCVR": uses tranceiver PHY
+    g_jumbo_en     : BOOLEAN := FALSE;
+    g_sim          : BOOLEAN := FALSE;
+    g_sim_level    : NATURAL := 0;     -- 0 = use IP model (equivalent to g_sim = FALSE); 1 = use fast serdes model;
+    g_sim_tx       : BOOLEAN := TRUE;
+    g_sim_rx       : BOOLEAN := TRUE
+  );
+  PORT (
+    -- Clocks and reset
+    mm_rst         : IN  STD_LOGIC;
+    mm_clk         : IN  STD_LOGIC;  -- MM
+    eth_clk        : IN  STD_LOGIC;  -- 125 MHz
+    tx_snk_clk     : IN  STD_LOGIC;  -- DP
+    rx_src_clk     : IN  STD_LOGIC;  -- DP
+
+    -- TSE setup
+    src_mac        : IN STD_LOGIC_VECTOR(c_48-1 DOWNTO 0);
+    setup_done     : OUT STD_LOGIC;
+
+    -- Calibration & reconfig clock
+    cal_rec_clk    : IN  STD_LOGIC := '0';
+    
+    -- Memory Mapped Peripheral
+    mm_ctlr_copi   : IN  t_mem_copi;
+    mm_ctlr_cipo   : OUT t_mem_cipo;
+
+    -- MAC transmit interface
+    -- . ST sink
+    tx_snk_in      : IN  t_dp_sosi;
+    tx_snk_out     : OUT t_dp_siso;
+
+    -- MAC receive interface
+    -- . ST Source
+    rx_src_in      : IN  t_dp_siso;
+    rx_src_out     : OUT t_dp_sosi;
+
+    -- PHY interface
+    eth_txp        : OUT STD_LOGIC;
+    eth_rxp        : IN  STD_LOGIC;
+
+    tse_led        : OUT t_tech_tse_led
+  );
+END tech_tse_with_setup;
+
+ARCHITECTURE str OF tech_tse_with_setup IS
+
+  -- Peripheral side
+  SIGNAL mm_peri_copi    : t_mem_copi;
+  SIGNAL mm_peri_cipo    : t_mem_cipo;
+
+  -- MAC specific
+  SIGNAL tx_mac_in       : t_tech_tse_tx_mac;
+  SIGNAL tx_mac_out      : t_tech_tse_tx_mac;
+  SIGNAL rx_mac_out      : t_tech_tse_rx_mac;
+
+  SIGNAL tx_sosi         : t_dp_sosi;
+
+BEGIN
+
+  -- Set up TSE as in unb_osy/unbos_eth.c
+  u_tech_tse_setup : ENTITY work.tech_tse_setup
+  GENERIC MAP (
+    g_sim      => g_sim,
+    g_jumbo_en => g_jumbo_en
+  )
+  PORT MAP (
+    -- Clocks and reset
+    mm_rst         => mm_rst,
+    mm_clk         => mm_clk,
+
+    -- TSE setup
+    src_mac        => src_mac,
+    setup_done     => setup_done,
+
+    -- Memory Mapped Peripheral
+    -- . Controller side
+    mm_ctlr_copi    => mm_ctlr_copi,
+    mm_ctlr_cipo    => mm_ctlr_cipo,
+    -- . Peripheral side
+    mm_peri_copi    => mm_peri_copi,
+    mm_peri_cipo    => mm_peri_cipo
+  );
+
+  -- Force defaults as in eth.vhd
+  tx_sosi <= func_dp_stream_error_set(tx_snk_in, 0);   -- force err field (value 0 for OK)
+
+  tx_mac_in.crc_fwd <= '0';  -- when '0' then TSE MAC generates the TX CRC field
+
+  u_tech_tse : ENTITY work.tech_tse
+  GENERIC MAP (
+    g_technology  => g_technology,
+    g_ETH_PHY     => g_ETH_PHY,
+    g_sim         => g_sim,
+    g_sim_level   => g_sim_level,
+    g_sim_tx      => g_sim_tx,
+    g_sim_rx      => g_sim_rx
+  )
+  PORT MAP (
+    -- Clocks and reset
+    mm_rst        => mm_rst,
+    mm_clk        => mm_clk,
+    eth_clk       => eth_clk,
+    tx_snk_clk    => tx_snk_clk,
+    rx_src_clk    => rx_src_clk,
+
+    -- Calibration & reconfig clock
+    cal_rec_clk   => cal_rec_clk,
+
+    -- Memory Mapped Peripheral
+    mm_sla_in     => mm_peri_copi,
+    mm_sla_out    => mm_peri_cipo,
+
+    -- MAC transmit interface
+    -- . ST sink
+    tx_snk_in     => tx_sosi,
+    tx_snk_out    => tx_snk_out,
+    -- . MAC specific
+    tx_mac_in     => tx_mac_in,
+    tx_mac_out    => tx_mac_out,
+
+    -- MAC receive interface
+    -- . ST Source
+    rx_src_in     => rx_src_in,
+    rx_src_out    => rx_src_out,
+    -- . MAC specific
+    rx_mac_out    => rx_mac_out,
+
+    -- PHY interface
+    eth_txp       => eth_txp,
+    eth_rxp       => eth_rxp,
+
+    tse_led       => tse_led
+  );
+
+END ARCHITECTURE;