diff --git a/applications/rdma_demo/hdllib.cfg b/applications/rdma_demo/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..eecdcb43a3072f940e2b96c89e6045fa99ba1d2f
--- /dev/null
+++ b/applications/rdma_demo/hdllib.cfg
@@ -0,0 +1,19 @@
+hdl_lib_name = rdma_demo
+hdl_library_clause_name = rdma_demo_lib
+hdl_lib_uses_synth = common dp eth axi4
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files =
+    src/vhdl/rdma_demo_pkg.vhd
+    src/vhdl/rdma_demo_eth_tester_wrapper.vhd
+
+test_bench_files = 
+
+regression_test_vhdl = 
+
+
+[modelsim_project_file]
+
+[quartus_project_file]
+
diff --git a/libraries/io/eth/src/vhdl/eth_tester_vivado_ip_wrapper.vhd b/applications/rdma_demo/src/vhdl/rdma_demo_eth_tester_wrapper.vhd
similarity index 50%
rename from libraries/io/eth/src/vhdl/eth_tester_vivado_ip_wrapper.vhd
rename to applications/rdma_demo/src/vhdl/rdma_demo_eth_tester_wrapper.vhd
index 4df04597d9bf2abb3f495f6be34b743555a6a895..4f50982eaefbe88db5d32b4baff19f1491aa00c4 100644
--- a/libraries/io/eth/src/vhdl/eth_tester_vivado_ip_wrapper.vhd
+++ b/applications/rdma_demo/src/vhdl/rdma_demo_eth_tester_wrapper.vhd
@@ -21,7 +21,7 @@
 -- Purpose: Provide AXI-4-stream interfaces + standard avalon MM interfaces for 
 --          eth_tester.vhd such that it can be used to create a Vivado IP block.
 -- Description: 
--- . The eth_tester_vivado_ip_wrapper uses axi4_stream_dp_bridge to convert the dp
+-- . The rdma_demo_eth_tester_wrapper uses axi4_stream_dp_bridge to convert the dp
 --   sosi/siso interfaces of the eth_tester into AXI4-Stream interfaces.
 -- . In order for this component to be suitable as a Vivado IP, the ports are
 --   exclusively STD_LOGIC(_VECTOR) where the widths are hard-coded as demanded
@@ -30,19 +30,19 @@
 -- . Avalon is used for all MM interfaces, which can be bridged to AXI4-Lite in 
 --   vivado using the AXI AMM Bridge IP.
 
-LIBRARY IEEE, common_lib, dp_lib, diag_lib, axi4_lib;
+LIBRARY IEEE, common_lib, dp_lib, axi4_lib, eth_lib;
 USE IEEE.std_logic_1164.ALL;
 USE common_lib.common_pkg.ALL;
 USE common_lib.common_mem_pkg.ALL;
 USE common_lib.common_network_layers_pkg.ALL;
 USE dp_lib.dp_stream_pkg.ALL;
 USE dp_lib.dp_components_pkg.ALL;
-USE diag_lib.diag_pkg.ALL;
 USE axi4_lib.axi4_stream_pkg.ALL;
-USE work.eth_pkg.ALL;
-USE work.eth_tester_pkg.ALL;
+USE eth_lib.eth_pkg.ALL;
+USE eth_lib.eth_tester_pkg.ALL;
+USE work.rdma_demo_pkg.ALL;
 
-ENTITY eth_tester_vivado_ip_wrapper IS  
+ENTITY rdma_demo_eth_tester_wrapper IS  
   PORT (
     -- Clocks and reset
     mm_clk             : IN  STD_LOGIC;
@@ -85,64 +85,75 @@ ENTITY eth_tester_vivado_ip_wrapper IS
     rx_udp_tuser     : IN STD_LOGIC_VECTOR(70-1 DOWNTO 0);
 
     -- reg_bg_ctrl
-    reg_bg_ctrl_avm_address                     : IN  STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_bg_ctrl_avm_read                        : IN  STD_LOGIC;
-    reg_bg_ctrl_avm_readdata                    : OUT STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_bg_ctrl_avm_readdatavalid               : OUT STD_LOGIC; 
-    reg_bg_ctrl_avm_waitrequest                 : OUT STD_LOGIC; 
-    reg_bg_ctrl_avm_write                       : IN  STD_LOGIC;
-    reg_bg_ctrl_avm_writedata                   : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bg_ctrl_avs_address                     : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bg_ctrl_avs_read                        : IN  STD_LOGIC;
+    reg_bg_ctrl_avs_readdata                    : OUT STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bg_ctrl_avs_readdatavalid               : OUT STD_LOGIC; 
+    reg_bg_ctrl_avs_waitrequest                 : OUT STD_LOGIC; 
+    reg_bg_ctrl_avs_write                       : IN  STD_LOGIC;
+    reg_bg_ctrl_avs_writedata                   : IN  STD_LOGIC_VECTOR(32-1 downto 0);
 
     -- reg_hdr_dat
-    reg_hdr_dat_avm_address                     : IN  STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_hdr_dat_avm_read                        : IN  STD_LOGIC;
-    reg_hdr_dat_avm_readdata                    : OUT STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_hdr_dat_avm_readdatavalid               : OUT STD_LOGIC; 
-    reg_hdr_dat_avm_waitrequest                 : OUT STD_LOGIC; 
-    reg_hdr_dat_avm_write                       : IN  STD_LOGIC;
-    reg_hdr_dat_avm_writedata                   : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_hdr_dat_avs_address                     : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_hdr_dat_avs_read                        : IN  STD_LOGIC;
+    reg_hdr_dat_avs_readdata                    : OUT STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_hdr_dat_avs_readdatavalid               : OUT STD_LOGIC; 
+    reg_hdr_dat_avs_waitrequest                 : OUT STD_LOGIC; 
+    reg_hdr_dat_avs_write                       : IN  STD_LOGIC;
+    reg_hdr_dat_avs_writedata                   : IN  STD_LOGIC_VECTOR(32-1 downto 0);
 
     -- reg_bsn_monitor_v2_tx
-    reg_bsn_monitor_v2_tx_avm_address           : IN  STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_bsn_monitor_v2_tx_avm_read              : IN  STD_LOGIC;
-    reg_bsn_monitor_v2_tx_avm_readdata          : OUT STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_bsn_monitor_v2_tx_avm_readdatavalid     : OUT STD_LOGIC; 
-    reg_bsn_monitor_v2_tx_avm_waitrequest       : OUT STD_LOGIC; 
-    reg_bsn_monitor_v2_tx_avm_write             : IN  STD_LOGIC;
-    reg_bsn_monitor_v2_tx_avm_writedata         : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bsn_monitor_v2_tx_avs_address           : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bsn_monitor_v2_tx_avs_read              : IN  STD_LOGIC;
+    reg_bsn_monitor_v2_tx_avs_readdata          : OUT STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bsn_monitor_v2_tx_avs_readdatavalid     : OUT STD_LOGIC; 
+    reg_bsn_monitor_v2_tx_avs_waitrequest       : OUT STD_LOGIC; 
+    reg_bsn_monitor_v2_tx_avs_write             : IN  STD_LOGIC;
+    reg_bsn_monitor_v2_tx_avs_writedata         : IN  STD_LOGIC_VECTOR(32-1 downto 0);
 
     -- reg_strobe_total_count_tx
-    reg_strobe_total_count_tx_avm_address       : IN  STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_strobe_total_count_tx_avm_read          : IN  STD_LOGIC;
-    reg_strobe_total_count_tx_avm_readdata      : OUT STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_strobe_total_count_tx_avm_readdatavalid : OUT STD_LOGIC; 
-    reg_strobe_total_count_tx_avm_waitrequest   : OUT STD_LOGIC; 
-    reg_strobe_total_count_tx_avm_write         : IN  STD_LOGIC;
-    reg_strobe_total_count_tx_avm_writedata     : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_strobe_total_count_tx_avs_address       : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_strobe_total_count_tx_avs_read          : IN  STD_LOGIC;
+    reg_strobe_total_count_tx_avs_readdata      : OUT STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_strobe_total_count_tx_avs_readdatavalid : OUT STD_LOGIC; 
+    reg_strobe_total_count_tx_avs_waitrequest   : OUT STD_LOGIC; 
+    reg_strobe_total_count_tx_avs_write         : IN  STD_LOGIC;
+    reg_strobe_total_count_tx_avs_writedata     : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+
+    -- reg_dp_split
+    reg_dp_split_avs_address                    : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_dp_split_avs_read                       : IN  STD_LOGIC;
+    reg_dp_split_avs_readdata                   : OUT STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_dp_split_avs_readdatavalid              : OUT STD_LOGIC; 
+    reg_dp_split_avs_waitrequest                : OUT STD_LOGIC; 
+    reg_dp_split_avs_write                      : IN  STD_LOGIC;
+    reg_dp_split_avs_writedata                  : IN  STD_LOGIC_VECTOR(32-1 downto 0);
 
     -- reg_bsn_monitor_v2_rx
-    reg_bsn_monitor_v2_rx_avm_address           : IN  STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_bsn_monitor_v2_rx_avm_read              : IN  STD_LOGIC;
-    reg_bsn_monitor_v2_rx_avm_readdata          : OUT STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_bsn_monitor_v2_rx_avm_readdatavalid     : OUT STD_LOGIC; 
-    reg_bsn_monitor_v2_rx_avm_waitrequest       : OUT STD_LOGIC; 
-    reg_bsn_monitor_v2_rx_avm_write             : IN  STD_LOGIC;
-    reg_bsn_monitor_v2_rx_avm_writedata         : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bsn_monitor_v2_rx_avs_address           : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bsn_monitor_v2_rx_avs_read              : IN  STD_LOGIC;
+    reg_bsn_monitor_v2_rx_avs_readdata          : OUT STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_bsn_monitor_v2_rx_avs_readdatavalid     : OUT STD_LOGIC; 
+    reg_bsn_monitor_v2_rx_avs_waitrequest       : OUT STD_LOGIC; 
+    reg_bsn_monitor_v2_rx_avs_write             : IN  STD_LOGIC;
+    reg_bsn_monitor_v2_rx_avs_writedata         : IN  STD_LOGIC_VECTOR(32-1 downto 0);
 
     -- reg_strobe_total_count_rx
-    reg_strobe_total_count_rx_avm_address       : IN  STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_strobe_total_count_rx_avm_read          : IN  STD_LOGIC;
-    reg_strobe_total_count_rx_avm_readdata      : OUT STD_LOGIC_VECTOR(32-1 downto 0);
-    reg_strobe_total_count_rx_avm_readdatavalid : OUT STD_LOGIC; 
-    reg_strobe_total_count_rx_avm_waitrequest   : OUT STD_LOGIC; 
-    reg_strobe_total_count_rx_avm_write         : IN  STD_LOGIC;
-    reg_strobe_total_count_rx_avm_writedata     : IN  STD_LOGIC_VECTOR(32-1 downto 0)
+    reg_strobe_total_count_rx_avs_address       : IN  STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_strobe_total_count_rx_avs_read          : IN  STD_LOGIC;
+    reg_strobe_total_count_rx_avs_readdata      : OUT STD_LOGIC_VECTOR(32-1 downto 0);
+    reg_strobe_total_count_rx_avs_readdatavalid : OUT STD_LOGIC; 
+    reg_strobe_total_count_rx_avs_waitrequest   : OUT STD_LOGIC; 
+    reg_strobe_total_count_rx_avs_write         : IN  STD_LOGIC;
+    reg_strobe_total_count_rx_avs_writedata     : IN  STD_LOGIC_VECTOR(32-1 downto 0)
 
    );
-END eth_tester_vivado_ip_wrapper;
+END rdma_demo_eth_tester_wrapper;
 
 
-ARCHITECTURE str OF eth_tester_vivado_ip_wrapper IS
+ARCHITECTURE str OF rdma_demo_eth_tester_wrapper IS
+  CONSTANT c_nof_byte                   : NATURAL := c_rdma_demo_nof_octet_output_100gbe;
+
   SIGNAL rx_udp_sosi_arr                : t_dp_sosi_arr(0 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);
   SIGNAL rx_udp_siso_arr                : t_dp_siso_arr(0 DOWNTO 0) := (OTHERS => c_dp_siso_rdy);
   SIGNAL tx_udp_sosi_arr                : t_dp_sosi_arr(0 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);
@@ -161,6 +172,8 @@ ARCHITECTURE str OF eth_tester_vivado_ip_wrapper IS
   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;
+  SIGNAL reg_dp_split_copi              : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_dp_split_cipo              : t_mem_cipo;
 
   SIGNAL reg_bsn_monitor_v2_rx_copi     : t_mem_copi := c_mem_copi_rst;
   SIGNAL reg_bsn_monitor_v2_rx_cipo     : t_mem_cipo;
@@ -172,9 +185,15 @@ ARCHITECTURE str OF eth_tester_vivado_ip_wrapper IS
 
 BEGIN
 
-  u_eth_tester : ENTITY work.eth_tester
+  u_eth_tester : ENTITY eth_lib.eth_tester
   GENERIC MAP (
-    g_remove_crc => FALSE
+    g_nof_octet_generate => c_rdma_demo_nof_octet_generate_100gbe,
+    g_nof_octet_output   => c_rdma_demo_nof_octet_output_100gbe,
+    g_use_network_header => FALSE,
+    g_use_dp_header      => TRUE,
+    g_hdr_field_arr      => c_rdma_demo_hdr_field_arr,
+    g_hdr_field_sel      => c_rdma_demo_hdr_field_sel,
+    g_remove_crc         => FALSE
   )
   PORT MAP (
     -- Clocks and reset
@@ -206,6 +225,8 @@ BEGIN
     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,
+    reg_dp_split_copi              => reg_dp_split_copi,
+    reg_dp_split_cipo              => reg_dp_split_cipo,
 
     reg_bsn_monitor_v2_rx_copi     => reg_bsn_monitor_v2_rx_copi,
     reg_bsn_monitor_v2_rx_cipo     => reg_bsn_monitor_v2_rx_cipo,
@@ -250,96 +271,112 @@ BEGIN
     dp_out_siso => rx_udp_siso_arr(0)
   );
 
-
   -- Wire Records to IN/OUT ports.
   -- tx_udp
   tx_udp_axi4_siso.tready <= tx_udp_tready;
 
   tx_udp_tvalid <= tx_udp_axi4_sosi.tvalid;
-  tx_udp_tdata  <= tx_udp_axi4_sosi.tdata;
   tx_udp_tstrb  <= tx_udp_axi4_sosi.tstrb;
-  tx_udp_tkeep  <= tx_udp_axi4_sosi.tkeep;
   tx_udp_tlast  <= tx_udp_axi4_sosi.tlast;
   tx_udp_tid    <= tx_udp_axi4_sosi.tid;
   tx_udp_tdest  <= tx_udp_axi4_sosi.tdest;
   tx_udp_tuser  <= tx_udp_axi4_sosi.tuser;
+  -- reverse order of bytes
+  gen_tx_data : FOR I IN 0 TO c_nof_byte - 1 GENERATE
+    tx_udp_tdata( (I+1) * c_octet_w - 1 DOWNTO I * c_octet_w) <= tx_udp_axi4_sosi.tdata((c_nof_byte - I) * c_octet_w - 1 DOWNTO (c_nof_byte - 1 - I) * c_octet_w);
+    tx_udp_tkeep(I) <= tx_udp_axi4_sosi.tkeep(c_nof_byte - 1 - I);
+  END GENERATE;
 
   -- rx_udp
   rx_udp_tready <= rx_udp_axi4_siso.tready;
 
   rx_udp_axi4_sosi.tvalid <= rx_udp_tvalid;
-  rx_udp_axi4_sosi.tdata  <= rx_udp_tdata;
   rx_udp_axi4_sosi.tstrb  <= rx_udp_tstrb;
-  rx_udp_axi4_sosi.tkeep  <= rx_udp_tkeep;
   rx_udp_axi4_sosi.tlast  <= rx_udp_tlast;
   rx_udp_axi4_sosi.tid    <= rx_udp_tid;
   rx_udp_axi4_sosi.tdest  <= rx_udp_tdest;
   rx_udp_axi4_sosi.tuser  <= rx_udp_tuser;
+  -- reverse order of bytes
+  gen_rx_data : FOR I IN 0 TO c_nof_byte - 1 GENERATE
+    rx_udp_axi4_sosi.tdata( (I+1) * c_octet_w - 1 DOWNTO I * c_octet_w) <= rx_udp_tdata((c_nof_byte - I) * c_octet_w - 1 DOWNTO (c_nof_byte - 1 - I) * c_octet_w);
+    rx_udp_axi4_sosi.tkeep(I) <= rx_udp_tkeep(c_nof_byte - 1 - I);
+  END GENERATE;
 
   -- reg_bg_ctrl
   -- copi
-  reg_bg_ctrl_copi.address      <= reg_bg_ctrl_avm_address;
-  reg_bg_ctrl_copi.wrdata       <= RESIZE_UVEC(reg_bg_ctrl_avm_writedata, c_mem_data_w);
-  reg_bg_ctrl_copi.wr           <= reg_bg_ctrl_avm_write;
-  reg_bg_ctrl_copi.rd           <= reg_bg_ctrl_avm_read;
+  reg_bg_ctrl_copi.address                    <= reg_bg_ctrl_avs_address;
+  reg_bg_ctrl_copi.wrdata                     <= RESIZE_UVEC(reg_bg_ctrl_avs_writedata, c_mem_data_w);
+  reg_bg_ctrl_copi.wr                         <= reg_bg_ctrl_avs_write;
+  reg_bg_ctrl_copi.rd                         <= reg_bg_ctrl_avs_read;
   -- cipo
-  reg_bg_ctrl_avm_readdata      <= RESIZE_UVEC_32(reg_bg_ctrl_cipo.rddata);  
-  reg_bg_ctrl_avm_readdatavalid <= reg_bg_ctrl_cipo.rdval; 
-  reg_bg_ctrl_avm_waitrequest   <= reg_bg_ctrl_cipo.waitrequest;
+  reg_bg_ctrl_avs_readdata                    <= RESIZE_UVEC_32(reg_bg_ctrl_cipo.rddata);  
+  reg_bg_ctrl_avs_readdatavalid               <= reg_bg_ctrl_cipo.rdval; 
+  reg_bg_ctrl_avs_waitrequest                 <= reg_bg_ctrl_cipo.waitrequest;
 
   -- reg_hdr_dat
   -- copi
-  reg_hdr_dat_copi.address      <= reg_hdr_dat_avm_address;
-  reg_hdr_dat_copi.wrdata       <= RESIZE_UVEC(reg_hdr_dat_avm_writedata, c_mem_data_w);
-  reg_hdr_dat_copi.wr           <= reg_hdr_dat_avm_write;
-  reg_hdr_dat_copi.rd           <= reg_hdr_dat_avm_read;
+  reg_hdr_dat_copi.address                    <= reg_hdr_dat_avs_address;
+  reg_hdr_dat_copi.wrdata                     <= RESIZE_UVEC(reg_hdr_dat_avs_writedata, c_mem_data_w);
+  reg_hdr_dat_copi.wr                         <= reg_hdr_dat_avs_write;
+  reg_hdr_dat_copi.rd                         <= reg_hdr_dat_avs_read;
   -- cipo
-  reg_hdr_dat_avm_readdata      <= RESIZE_UVEC_32(reg_hdr_dat_cipo.rddata);  
-  reg_hdr_dat_avm_readdatavalid <= reg_hdr_dat_cipo.rdval; 
-  reg_hdr_dat_avm_waitrequest   <= reg_hdr_dat_cipo.waitrequest;
+  reg_hdr_dat_avs_readdata                    <= RESIZE_UVEC_32(reg_hdr_dat_cipo.rddata);  
+  reg_hdr_dat_avs_readdatavalid               <= reg_hdr_dat_cipo.rdval; 
+  reg_hdr_dat_avs_waitrequest                 <= reg_hdr_dat_cipo.waitrequest;
 
   -- reg_bsn_monitor_v2_tx
   -- copi
-  reg_bsn_monitor_v2_tx_copi.address      <= reg_bsn_monitor_v2_tx_avm_address;
-  reg_bsn_monitor_v2_tx_copi.wrdata       <= RESIZE_UVEC(reg_bsn_monitor_v2_tx_avm_writedata, c_mem_data_w);
-  reg_bsn_monitor_v2_tx_copi.wr           <= reg_bsn_monitor_v2_tx_avm_write;
-  reg_bsn_monitor_v2_tx_copi.rd           <= reg_bsn_monitor_v2_tx_avm_read;
+  reg_bsn_monitor_v2_tx_copi.address          <= reg_bsn_monitor_v2_tx_avs_address;
+  reg_bsn_monitor_v2_tx_copi.wrdata           <= RESIZE_UVEC(reg_bsn_monitor_v2_tx_avs_writedata, c_mem_data_w);
+  reg_bsn_monitor_v2_tx_copi.wr               <= reg_bsn_monitor_v2_tx_avs_write;
+  reg_bsn_monitor_v2_tx_copi.rd               <= reg_bsn_monitor_v2_tx_avs_read;
   -- cipo
-  reg_bsn_monitor_v2_tx_avm_readdata      <= RESIZE_UVEC_32(reg_bsn_monitor_v2_tx_cipo.rddata);  
-  reg_bsn_monitor_v2_tx_avm_readdatavalid <= reg_bsn_monitor_v2_tx_cipo.rdval; 
-  reg_bsn_monitor_v2_tx_avm_waitrequest   <= reg_bsn_monitor_v2_tx_cipo.waitrequest;
+  reg_bsn_monitor_v2_tx_avs_readdata          <= RESIZE_UVEC_32(reg_bsn_monitor_v2_tx_cipo.rddata);  
+  reg_bsn_monitor_v2_tx_avs_readdatavalid     <= reg_bsn_monitor_v2_tx_cipo.rdval; 
+  reg_bsn_monitor_v2_tx_avs_waitrequest       <= reg_bsn_monitor_v2_tx_cipo.waitrequest;
 
   -- reg_strobe_total_count_tx
   -- copi
-  reg_strobe_total_count_tx_copi.address      <= reg_strobe_total_count_tx_avm_address;
-  reg_strobe_total_count_tx_copi.wrdata       <= RESIZE_UVEC(reg_strobe_total_count_tx_avm_writedata, c_mem_data_w);
-  reg_strobe_total_count_tx_copi.wr           <= reg_strobe_total_count_tx_avm_write;
-  reg_strobe_total_count_tx_copi.rd           <= reg_strobe_total_count_tx_avm_read;
+  reg_strobe_total_count_tx_copi.address      <= reg_strobe_total_count_tx_avs_address;
+  reg_strobe_total_count_tx_copi.wrdata       <= RESIZE_UVEC(reg_strobe_total_count_tx_avs_writedata, c_mem_data_w);
+  reg_strobe_total_count_tx_copi.wr           <= reg_strobe_total_count_tx_avs_write;
+  reg_strobe_total_count_tx_copi.rd           <= reg_strobe_total_count_tx_avs_read;
+  -- cipo
+  reg_strobe_total_count_tx_avs_readdata      <= RESIZE_UVEC_32(reg_strobe_total_count_tx_cipo.rddata);  
+  reg_strobe_total_count_tx_avs_readdatavalid <= reg_strobe_total_count_tx_cipo.rdval; 
+  reg_strobe_total_count_tx_avs_waitrequest   <= reg_strobe_total_count_tx_cipo.waitrequest;
+
+  -- reg_dp_split
+  -- copi
+  reg_dp_split_copi.address                   <= reg_dp_split_avs_address;
+  reg_dp_split_copi.wrdata                    <= RESIZE_UVEC(reg_dp_split_avs_writedata, c_mem_data_w);
+  reg_dp_split_copi.wr                        <= reg_dp_split_avs_write;
+  reg_dp_split_copi.rd                        <= reg_dp_split_avs_read;
   -- cipo
-  reg_strobe_total_count_tx_avm_readdata      <= RESIZE_UVEC_32(reg_strobe_total_count_tx_cipo.rddata);  
-  reg_strobe_total_count_tx_avm_readdatavalid <= reg_strobe_total_count_tx_cipo.rdval; 
-  reg_strobe_total_count_tx_avm_waitrequest   <= reg_strobe_total_count_tx_cipo.waitrequest;
+  reg_dp_split_avs_readdata                   <= RESIZE_UVEC_32(reg_dp_split_cipo.rddata);  
+  reg_dp_split_avs_readdatavalid              <= reg_dp_split_cipo.rdval; 
+  reg_dp_split_avs_waitrequest                <= reg_dp_split_cipo.waitrequest;
 
   -- reg_bsn_monitor_v2_rx
   -- copi
-  reg_bsn_monitor_v2_rx_copi.address      <= reg_bsn_monitor_v2_rx_avm_address;
-  reg_bsn_monitor_v2_rx_copi.wrdata       <= RESIZE_UVEC(reg_bsn_monitor_v2_rx_avm_writedata, c_mem_data_w);
-  reg_bsn_monitor_v2_rx_copi.wr           <= reg_bsn_monitor_v2_rx_avm_write;
-  reg_bsn_monitor_v2_rx_copi.rd           <= reg_bsn_monitor_v2_rx_avm_read;
+  reg_bsn_monitor_v2_rx_copi.address          <= reg_bsn_monitor_v2_rx_avs_address;
+  reg_bsn_monitor_v2_rx_copi.wrdata           <= RESIZE_UVEC(reg_bsn_monitor_v2_rx_avs_writedata, c_mem_data_w);
+  reg_bsn_monitor_v2_rx_copi.wr               <= reg_bsn_monitor_v2_rx_avs_write;
+  reg_bsn_monitor_v2_rx_copi.rd               <= reg_bsn_monitor_v2_rx_avs_read;
   -- cipo
-  reg_bsn_monitor_v2_rx_avm_readdata      <= RESIZE_UVEC_32(reg_bsn_monitor_v2_rx_cipo.rddata);  
-  reg_bsn_monitor_v2_rx_avm_readdatavalid <= reg_bsn_monitor_v2_rx_cipo.rdval; 
-  reg_bsn_monitor_v2_rx_avm_waitrequest   <= reg_bsn_monitor_v2_rx_cipo.waitrequest;
+  reg_bsn_monitor_v2_rx_avs_readdata          <= RESIZE_UVEC_32(reg_bsn_monitor_v2_rx_cipo.rddata);  
+  reg_bsn_monitor_v2_rx_avs_readdatavalid     <= reg_bsn_monitor_v2_rx_cipo.rdval; 
+  reg_bsn_monitor_v2_rx_avs_waitrequest       <= reg_bsn_monitor_v2_rx_cipo.waitrequest;
 
   -- reg_strobe_total_count_rx
   -- copi
-  reg_strobe_total_count_rx_copi.address      <= reg_strobe_total_count_rx_avm_address;
-  reg_strobe_total_count_rx_copi.wrdata       <= RESIZE_UVEC(reg_strobe_total_count_rx_avm_writedata, c_mem_data_w);
-  reg_strobe_total_count_rx_copi.wr           <= reg_strobe_total_count_rx_avm_write;
-  reg_strobe_total_count_rx_copi.rd           <= reg_strobe_total_count_rx_avm_read;
+  reg_strobe_total_count_rx_copi.address      <= reg_strobe_total_count_rx_avs_address;
+  reg_strobe_total_count_rx_copi.wrdata       <= RESIZE_UVEC(reg_strobe_total_count_rx_avs_writedata, c_mem_data_w);
+  reg_strobe_total_count_rx_copi.wr           <= reg_strobe_total_count_rx_avs_write;
+  reg_strobe_total_count_rx_copi.rd           <= reg_strobe_total_count_rx_avs_read;
   -- cipo
-  reg_strobe_total_count_rx_avm_readdata      <= RESIZE_UVEC_32(reg_strobe_total_count_rx_cipo.rddata);  
-  reg_strobe_total_count_rx_avm_readdatavalid <= reg_strobe_total_count_rx_cipo.rdval; 
-  reg_strobe_total_count_rx_avm_waitrequest   <= reg_strobe_total_count_rx_cipo.waitrequest;
+  reg_strobe_total_count_rx_avs_readdata      <= RESIZE_UVEC_32(reg_strobe_total_count_rx_cipo.rddata);  
+  reg_strobe_total_count_rx_avs_readdatavalid <= reg_strobe_total_count_rx_cipo.rdval; 
+  reg_strobe_total_count_rx_avs_waitrequest   <= reg_strobe_total_count_rx_cipo.waitrequest;
 
 END str;
diff --git a/applications/rdma_demo/src/vhdl/rdma_demo_pkg.vhd b/applications/rdma_demo/src/vhdl/rdma_demo_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..8afd1a81d4ea92d9d0a730c984934fdfa7950348
--- /dev/null
+++ b/applications/rdma_demo/src/vhdl/rdma_demo_pkg.vhd
@@ -0,0 +1,75 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- 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: R. vd Walle
+-- Purpose: This package contains rdma_demo specific constants and/or functions
+-- Description:
+--
+LIBRARY IEEE, common_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.common_field_pkg.ALL;
+USE common_lib.common_network_layers_pkg.ALL;
+
+PACKAGE rdma_demo_pkg is
+
+  CONSTANT c_rdma_demo_nof_octet_generate_100gbe : NATURAL := 64;
+  CONSTANT c_rdma_demo_nof_octet_output_100gbe   : NATURAL := 64;
+
+
+  -- hdr_field_sel bit selects where the hdr_field value is set:
+  -- . 0 = data path controlled, value is set in data path, so field_default()
+  --       is not used.
+  -- . 1 = MM controlled, value is set via MM or by the field_default(), so any
+  --       data path setting in eth_tester.vhd is not used.
+  -- Remarks:
+  -- . For constant values it is convenient to use MM controlled, because then
+  --   the field_default() is used that can be set here in
+  --   c_rdma_demo_hdr_field_arr.
+  -- . For reserved values it is convenient to use MM controlled, because then
+  --   in future they could still be changed via MM without having to recompile
+  --   the FW.
+  -- . Typically only use data path controlled if the value has to be set
+  --   dynamically, so dependent on the state of the FW.
+  -- . If a data path controlled field is not set in the FW, then it defaults
+  --   to 0 by declaring hdr_fields_in_arr with all 0. Hence e.g. udp_checksum
+  --   = 0 can be achieve via data path and default hdr_fields_in_arr = 0 or
+  --   via MM controlled and field_default(0).
+  CONSTANT c_rdma_demo_nof_hdr_fields : NATURAL := 4;
+  CONSTANT c_rdma_demo_hdr_field_sel  : STD_LOGIC_VECTOR(c_rdma_demo_nof_hdr_fields-1 DOWNTO 0) := "0100";
+
+  CONSTANT c_rdma_demo_hdr_field_arr : t_common_field_arr(c_rdma_demo_nof_hdr_fields-1 DOWNTO 0) := (
+      ( field_name_pad("dp_length"                               ), "RW", 16, field_default(0) ),
+      ( field_name_pad("dp_reserved"                             ), "RW", 15, field_default(0) ),
+      ( field_name_pad("dp_sync"                                 ), "RW",  1, field_default(0) ),
+      ( field_name_pad("dp_bsn"                                  ), "RW", 64, field_default(0) )
+  );
+  CONSTANT c_rdma_demo_reg_hdr_dat_addr_w    : NATURAL := ceil_log2(field_nof_words(c_rdma_demo_hdr_field_arr, c_word_w));  -- = 5
+  CONSTANT c_rdma_demo_reg_hdr_dat_addr_span : NATURAL := 2**c_rdma_demo_reg_hdr_dat_addr_w;  -- = 32
+
+  CONSTANT c_rdma_demo_app_hdr_len  : NATURAL :=  12;  -- octets
+
+END rdma_demo_pkg;
+
+PACKAGE BODY rdma_demo_pkg IS
+
+END rdma_demo_pkg;
+
diff --git a/libraries/base/dp/src/vhdl/dp_field_blk.vhd b/libraries/base/dp/src/vhdl/dp_field_blk.vhd
index 477e36e314b1cf985d314f5d26f07ef7b4e1ec56..f778f6c181aef52db57f807726063f2959ae2dba 100644
--- a/libraries/base/dp/src/vhdl/dp_field_blk.vhd
+++ b/libraries/base/dp/src/vhdl/dp_field_blk.vhd
@@ -35,7 +35,16 @@ USE work.dp_stream_pkg.ALL;
 --   if override = '0' the field is taken from snk_in.data.
 -- . The initial (default) values of the override bits are passed via g_field_sel(one bit per field);
 -- . Both the SLV as the override (ovr) fields can be read back via MM;
-
+-- . g_mode can be used to select in which mode dp_field_blk should work. Most of the time, the
+--   default g_mode = 0 can be used. When using g_mode = 0, it is assumed that dp_field_blk must be
+--   used in source mode when g_snk_data_w > g_src_data_w, else in sink mode. This is a typical 
+--   application as it is often the case that the total width of the field block is larger than the
+--   serial data width as shown in the example below. There are cases where the width of the 
+--   field-block is smaller than the serial data words. Therefore it is possible to force either sink 
+--   or source mode.
+--   . g_mode = 0: auto select mode based on g_snk_data_w and g_src_data_w.
+--   . g_mode = 1: use dp_field_blk in source mode regardless of g_*_data_w.
+--   . g_mode = 2: use dp_field_blk in sink mode regardless of g_*_data_w.
 
 -- The diagrams below show dp_field_blk in source and sink configuration. For simplicity, the 5
 -- fields are defined as follows (fields do not need to respect word boundaries):
@@ -82,7 +91,8 @@ ENTITY dp_field_blk IS
     g_src_data_w     : NATURAL;
     g_in_symbol_w    : NATURAL := 1;
     g_out_symbol_w   : NATURAL := 1;
-    g_pipeline_ready : BOOLEAN := FALSE
+    g_pipeline_ready : BOOLEAN := FALSE;
+    g_mode           : NATURAL := 0 -- 0 = auto, 1 = source , 2 = sink
   );
   PORT (
     dp_rst          : IN  STD_LOGIC;
@@ -123,7 +133,7 @@ ARCHITECTURE str OF dp_field_blk IS
 
   -- Mode: fields to data block (c_field_to_block=True) or data block to fields (c_field_to_block=False)
   --  a.k.a. wire to narrow                             or narrow     to wide 
-  CONSTANT c_field_to_block : BOOLEAN := g_snk_data_w>g_src_data_w;
+  CONSTANT c_field_to_block : BOOLEAN := sel_a_b(g_mode = 0, g_snk_data_w>g_src_data_w, sel_a_b(g_mode = 1, TRUE, FALSE));
 
   -- Field to block: mm_fields only has SLV output, no input. Set input wirdt to zero.
   CONSTANT c_mm_fields_slv_in_w  : NATURAL := sel_a_b(c_field_to_block, 0, g_src_data_w);
diff --git a/libraries/base/dp/src/vhdl/dp_offload_rx.vhd b/libraries/base/dp/src/vhdl/dp_offload_rx.vhd
index 6ce2e23d4cda4d15e7d7ad80eabee1b0a9729282..9ec0038dbd96b145dd56065d4d7c7e14e22611bc 100644
--- a/libraries/base/dp/src/vhdl/dp_offload_rx.vhd
+++ b/libraries/base/dp/src/vhdl/dp_offload_rx.vhd
@@ -149,7 +149,8 @@ BEGIN
       g_snk_data_w   => c_dp_field_blk_snk_data_w,  --g_data_w,
       g_src_data_w   => c_dp_field_blk_src_data_w,  --field_slv_in_len(field_arr_set_mode(g_hdr_field_arr , "RO"))
       g_in_symbol_w  => c_symbol_w,
-      g_out_symbol_w => c_symbol_w
+      g_out_symbol_w => c_symbol_w,
+      g_mode         => 2 -- sink mode
     )
     PORT MAP (
       dp_rst       => dp_rst,
diff --git a/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd
index a7e72974601c0c47dd94097ae9cf90a7255a2f58..a27fc5a3e50be733febcd62b9de696f809ffb7a5 100644
--- a/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd
+++ b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd
@@ -184,7 +184,8 @@ BEGIN
       g_src_data_w     => c_dp_field_blk_src_data_w,
       g_in_symbol_w    => g_symbol_w,
       g_out_symbol_w   => g_symbol_w,
-      g_pipeline_ready => g_pipeline_ready
+      g_pipeline_ready => g_pipeline_ready,
+      g_mode           => 1 -- source mode
     )
     PORT MAP (
       dp_clk       => dp_clk,
diff --git a/libraries/base/dp/src/vhdl/dp_repack_data.vhd b/libraries/base/dp/src/vhdl/dp_repack_data.vhd
index d1c86bf258f14795eaa5ea49ddc9007a12fe1dc3..9469c48397784de9b3371c14caaf3505425b334e 100644
--- a/libraries/base/dp/src/vhdl/dp_repack_data.vhd
+++ b/libraries/base/dp/src/vhdl/dp_repack_data.vhd
@@ -139,6 +139,11 @@
 --   The src_out.empty will be 2, because:
 --     (g_out_dat_w*g_out_nof_words-g_in_dat_w*g_in_nof_words)/g_out_symbol_w
 --      = (32*11 - 42*8*1)/ 8 = 2 octet symbols
+-- . Instead of using dp_sosi.data for intermediate results in dp_repack_data, 
+--   a seperate std_logic_vector is used to carry the sosi data as the required 
+--   vector width can become larger than c_dp_stream_data_w. Note that for the
+--   in/out sosi of dp_repack_data, the dp_sosi.data field is still used such 
+--   that there is no added complexity for the user of dp_repack_data.
 --       
 -- Design steps:
 -- * In total the development took 5 days. On day 3 I was in distress because
@@ -189,7 +194,8 @@ ENTITY dp_repack_in IS
     snk_in           : IN  t_dp_sosi;
 
     src_in           : IN  t_dp_siso;
-    src_out          : OUT t_dp_sosi
+    src_out          : OUT t_dp_sosi;
+    src_out_data     : OUT STD_LOGIC_VECTOR(g_in_dat_w * g_in_nof_words - 1 DOWNTO 0)
   );
 END dp_repack_in;
 
@@ -203,12 +209,13 @@ ARCHITECTURE rtl OF dp_repack_in IS
   TYPE t_dat_arr  IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
 
   TYPE t_reg IS RECORD
-    dat_arr       : t_dat_arr(g_in_nof_words-1 DOWNTO 0);     -- internally use dat_arr[] to represent v.src_out.data
-    src_out       : t_dp_sosi;                                -- sosi output
-    hold_out      : t_dp_sosi;                                -- hold snk_in.sync/sop/eop until end of section and then hold valid src_out until src_in.ready
-    flush         : STD_LOGIC;                                -- shift when snk_in.valid or flush in case the last subsection has < g_in_nof_words
-    dat_bit_cnt   : NATURAL RANGE 0 TO c_bit_cnt_max;         -- actual nof bits in subsection
-    pack_bit_cnt  : NATURAL RANGE 0 TO c_bit_cnt_max;         -- count nof bits in subsection
+    dat_arr       : t_dat_arr(g_in_nof_words-1 DOWNTO 0);        -- internally use dat_arr[] to represent v.src_out.data
+    src_out       : t_dp_sosi;                                   -- sosi output
+    src_out_data  : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0); -- Use seperate STD_LOGIC_VECTOR to carry the sosi data as c_in_buf_dat_w can be larger than c_dp_stream_data_w.
+    hold_out      : t_dp_sosi;                                   -- hold snk_in.sync/sop/eop until end of section and then hold valid src_out until src_in.ready
+    flush         : STD_LOGIC;                                   -- shift when snk_in.valid or flush in case the last subsection has < g_in_nof_words
+    dat_bit_cnt   : NATURAL RANGE 0 TO c_bit_cnt_max;            -- actual nof bits in subsection
+    pack_bit_cnt  : NATURAL RANGE 0 TO c_bit_cnt_max;            -- count nof bits in subsection
   END RECORD;
 
   SIGNAL data_vec   : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
@@ -220,7 +227,6 @@ ARCHITECTURE rtl OF dp_repack_in IS
   -- Debug signals
   SIGNAL snk_in_data        : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
   SIGNAL i_src_out          : t_dp_sosi;
-  SIGNAL src_out_data       : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
 
   SIGNAL dbg_g_in_dat_w   : NATURAL := g_in_dat_w;
   SIGNAL dbg_in_nof_words : NATURAL := g_in_nof_words;
@@ -232,7 +238,6 @@ BEGIN
   snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
   
   src_out      <= i_src_out;
-  src_out_data <= i_src_out.data(c_in_buf_dat_w-1 DOWNTO 0);
   
   gen_bypass : IF g_bypass=TRUE GENERATE
     snk_out   <= src_in;
@@ -306,8 +311,9 @@ BEGIN
         END IF;
   
         -- pass on the v.dat_arr as data vector
+        v.src_out_data := data_vec;
         v.src_out.data := RESIZE_DP_DATA(data_vec);
-  
+
         -- pass on dat_bit_cnt via DP empty field
         v.src_out.empty := INCR_UVEC(v.hold_out.empty, c_in_buf_dat_w - v.dat_bit_cnt);
   
@@ -361,7 +367,7 @@ BEGIN
     --------------------------------------------------------------------------
     -- Wired output
     i_src_out <= r.src_out;
-  
+    src_out_data <= r.src_out_data;
     --------------------------------------------------------------------------
     -- Flow control
   
@@ -403,6 +409,7 @@ ENTITY dp_repack_out IS
 
     snk_out          : OUT t_dp_siso;
     snk_in           : IN  t_dp_sosi;
+    snk_in_data      : IN  STD_LOGIC_VECTOR(g_in_buf_dat_w-1 DOWNTO 0);
 
     src_in           : IN  t_dp_siso;
     src_out          : OUT t_dp_sosi
@@ -437,7 +444,7 @@ ARCHITECTURE rtl OF dp_repack_out IS
   SIGNAL nxt_r     : t_reg;
 
   -- Debug signals
-  SIGNAL snk_in_data        : STD_LOGIC_VECTOR(g_in_buf_dat_w-1 DOWNTO 0);
+  SIGNAL i_src_out_data     : STD_LOGIC_VECTOR(g_in_buf_dat_w-1 DOWNTO 0);
   SIGNAL i_src_out          : t_dp_sosi;
   SIGNAL src_out_data       : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
 
@@ -451,10 +458,8 @@ ARCHITECTURE rtl OF dp_repack_out IS
 
 BEGIN
 
-  snk_in_data <= snk_in.data(g_in_buf_dat_w-1 DOWNTO 0);
-  
   src_out      <= i_src_out;
-  src_out_data <= i_src_out.data(g_out_dat_w-1 DOWNTO 0);
+  src_out_data <= i_src_out_data(g_out_dat_w-1 DOWNTO 0);
   
   gen_bypass : IF g_bypass=TRUE GENERATE
     snk_out <= src_in;
@@ -463,11 +468,11 @@ BEGIN
     BEGIN
       i_src_out <= snk_in;
       IF c_snk_in_dat_lo>0 THEN
-        i_src_out.data  <= SHIFT_UVEC(snk_in.data,   c_snk_in_dat_lo);
+        i_src_out_data  <= SHIFT_UVEC(snk_in_data,   c_snk_in_dat_lo);
         i_src_out.empty <= INCR_UVEC( snk_in.empty, -c_snk_in_dat_lo);
       END IF;
       IF c_out_buf_dat_lo>0 THEN
-        i_src_out.data  <= SHIFT_UVEC(snk_in.data, -c_out_buf_dat_lo);
+        i_src_out_data  <= SHIFT_UVEC(snk_in_data, -c_out_buf_dat_lo);
         i_src_out.empty <= INCR_UVEC( snk_in.empty, c_out_buf_dat_lo);
       END IF;
     END PROCESS;
@@ -605,7 +610,7 @@ BEGIN
   
     --------------------------------------------------------------------------
     -- Wires
-    data_vec(c_out_buf_dat_w-1 DOWNTO c_out_buf_dat_lo) <= snk_in.data(g_in_buf_dat_w-1 DOWNTO c_snk_in_dat_lo);
+    data_vec(c_out_buf_dat_w-1 DOWNTO c_out_buf_dat_lo) <= snk_in_data(g_in_buf_dat_w-1 DOWNTO c_snk_in_dat_lo);
   
     --------------------------------------------------------------------------
     -- Wired output
@@ -707,12 +712,12 @@ BEGIN
   src_out <= i_src_out;
 
   snk_in_data    <= i_snk_in.data(g_in_dat_w-1 DOWNTO 0);
-  pack_sosi_data <= pack_sosi.data(c_in_buf_dat_w-1 DOWNTO 0);
   src_out_data   <= i_src_out.data(g_out_dat_w-1 DOWNTO 0);
 
   no_dp_repack_in : IF g_enable_repack_in=FALSE GENERATE
     i_snk_out <= pack_siso;
     pack_sosi <= i_snk_in;
+    pack_sosi_data <= RESIZE_UVEC(snk_in_data, c_in_buf_dat_w);
   END GENERATE;
 
   gen_dp_repack_in : IF g_enable_repack_in=TRUE GENERATE
@@ -731,7 +736,8 @@ BEGIN
       snk_in   => i_snk_in,
 
       src_in   => pack_siso,
-      src_out  => pack_sosi
+      src_out  => pack_sosi,
+      src_out_data => pack_sosi_data
     );
   END GENERATE;
 
@@ -755,6 +761,7 @@ BEGIN
 
       snk_out  => pack_siso,
       snk_in   => pack_sosi,
+      snk_in_data => pack_sosi_data,
 
       src_in   => src_in,
       src_out  => i_src_out
diff --git a/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd b/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
index ecd2e6b6fea23856b16269dfba6fa2203f4f6eb3..b57aeab0eddc8f2df392ea50b10793b4db089a45 100644
--- a/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
+++ b/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
@@ -49,12 +49,12 @@ PACKAGE dp_stream_pkg Is
   --   This grouping is useful for functions that operate on a t_dp_sosi signal.
   -- * The info fields are valid at the sop or at the eop, but typically they hold their last active value to avoid unnessary
   --   toggling and to ease viewing in the wave window.
-  CONSTANT c_dp_stream_bsn_w      : NATURAL :=  64;  -- 64 is sufficient to count blocks of data for years
-  CONSTANT c_dp_stream_data_w     : NATURAL := 768;  -- 72 is sufficient for max word 8 * 9-bit. 576 supports half rate DDR4 bus data width. The current 768 is enough for wide single clock SLVs (e.g. headers)
-  CONSTANT c_dp_stream_dsp_data_w : NATURAL :=  64;  -- 64 is sufficient for DSP data, including complex power accumulates
-  CONSTANT c_dp_stream_empty_w    : NATURAL :=  16;  --  8 is sufficient for max 256 symbols per data word, still use 16 bit to be able to count c_dp_stream_data_w in bits
-  CONSTANT c_dp_stream_channel_w  : NATURAL :=  32;  -- 32 is sufficient for several levels of hierarchy in mapping types of streams on to channels 
-  CONSTANT c_dp_stream_error_w    : NATURAL :=  32;  -- 32 is sufficient for several levels of hierarchy in mapping error numbers, e.g. 32 different one-hot encoded errors, bit [0] = 0 = OK
+  CONSTANT c_dp_stream_bsn_w      : NATURAL :=  64;   -- 64 is sufficient to count blocks of data for years
+  CONSTANT c_dp_stream_data_w     : NATURAL :=  1024; -- 72 is sufficient for max word 8 * 9-bit. 576 supports half rate DDR4 bus data width. The current 1024 is enough for wide single clock SLVs (e.g. headers)
+  CONSTANT c_dp_stream_dsp_data_w : NATURAL :=  64;   -- 64 is sufficient for DSP data, including complex power accumulates
+  CONSTANT c_dp_stream_empty_w    : NATURAL :=  16;   --  8 is sufficient for max 256 symbols per data word, still use 16 bit to be able to count c_dp_stream_data_w in bits
+  CONSTANT c_dp_stream_channel_w  : NATURAL :=  32;   -- 32 is sufficient for several levels of hierarchy in mapping types of streams on to channels 
+  CONSTANT c_dp_stream_error_w    : NATURAL :=  32;   -- 32 is sufficient for several levels of hierarchy in mapping error numbers, e.g. 32 different one-hot encoded errors, bit [0] = 0 = OK
   
   CONSTANT c_dp_stream_ok         : NATURAL := 0;  -- SOSI err field OK value
   CONSTANT c_dp_stream_err        : NATURAL := 1;  -- SOSI err field error value /= OK
diff --git a/libraries/base/dp/src/vhdl/mms_dp_split.vhd b/libraries/base/dp/src/vhdl/mms_dp_split.vhd
index 8dc4c80b0595d99e0df1dd2873828901e743c4b6..08e4fe056c0ed205e5d0cee7dee1efb26bbb83dc 100644
--- a/libraries/base/dp/src/vhdl/mms_dp_split.vhd
+++ b/libraries/base/dp/src/vhdl/mms_dp_split.vhd
@@ -50,7 +50,9 @@ ENTITY mms_dp_split IS
     snk_in_arr   : IN  t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
     -- ST source
     src_in_2arr  : IN  t_dp_siso_2arr_2(g_nof_streams-1 DOWNTO 0);
-    src_out_2arr : OUT t_dp_sosi_2arr_2(g_nof_streams-1 DOWNTO 0)
+    src_out_2arr : OUT t_dp_sosi_2arr_2(g_nof_streams-1 DOWNTO 0);
+
+    out_nof_symbols : OUT t_natural_arr(g_nof_streams-1 DOWNTO 0) 
   );
 END mms_dp_split;
 
@@ -82,6 +84,8 @@ BEGIN
 
   gen_stream : FOR i IN 0 TO g_nof_streams-1 GENERATE
       
+    out_nof_symbols(i) <= TO_UINT(nof_symbols(i));
+
     u_reg : ENTITY work.dp_split_reg
     GENERIC MAP (
       g_nof_symbols => g_nof_symbols_max
diff --git a/libraries/io/eth/hdllib.cfg b/libraries/io/eth/hdllib.cfg
index 7553f16f0752b47e1202d15547d9f7d39635ad0a..909d905bed2e804092d562c2646aefd752c37d4b 100644
--- a/libraries/io/eth/hdllib.cfg
+++ b/libraries/io/eth/hdllib.cfg
@@ -1,6 +1,6 @@
 hdl_lib_name = eth
 hdl_library_clause_name = eth_lib
-hdl_lib_uses_synth = dp common diag tech_tse axi4
+hdl_lib_uses_synth = dp common diag tech_tse
 hdl_lib_uses_sim = 
 hdl_lib_technology = 
 
@@ -28,7 +28,6 @@ synth_files =
     src/vhdl/eth_tester_tx.vhd
     src/vhdl/eth_tester_rx.vhd
     src/vhdl/eth_tester.vhd
-    src/vhdl/eth_tester_vivado_ip_wrapper.vhd
 
 test_bench_files = 
     src/vhdl/eth_statistics.vhd
@@ -38,9 +37,11 @@ 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_tester_high_bw.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_tester_high_bw.vhd
     tb/vhdl/tb_tb_eth_stream_udp.vhd
     tb/vhdl/tb_eth_udp_offload.vhd
     tb/vhdl/tb_eth_ihl_to_20.vhd
@@ -54,6 +55,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_tester_high_bw.vhd
     tb/vhdl/tb_tb_eth_stream_udp.vhd
 
 
diff --git a/libraries/io/eth/src/vhdl/eth_tester.vhd b/libraries/io/eth/src/vhdl/eth_tester.vhd
index e6253bb87bd4c786fa8ed39d676775e9d17cb485..4b3b4ce3448975529ce77e04482f867e7cd01777 100644
--- a/libraries/io/eth/src/vhdl/eth_tester.vhd
+++ b/libraries/io/eth/src/vhdl/eth_tester.vhd
@@ -28,6 +28,7 @@ LIBRARY IEEE, common_lib, dp_lib, diag_lib;
 USE IEEE.std_logic_1164.ALL;
 USE common_lib.common_pkg.ALL;
 USE common_lib.common_mem_pkg.ALL;
+USE common_lib.common_field_pkg.ALL;
 USE common_lib.common_network_layers_pkg.ALL;
 USE dp_lib.dp_stream_pkg.ALL;
 USE dp_lib.dp_components_pkg.ALL;
@@ -37,10 +38,16 @@ USE work.eth_tester_pkg.ALL;
 
 ENTITY eth_tester IS
   GENERIC (
-    g_nof_streams      : NATURAL := 1;
-    g_bg_sync_timeout  : NATURAL := c_eth_tester_sync_timeout;
-    g_remove_crc       : BOOLEAN := TRUE  -- use TRUE when using sim_tse and tech_tse link interface,
-                                          -- use FALSE when streaming link interface
+    g_nof_streams        : NATURAL := 1;
+    g_bg_sync_timeout    : NATURAL := c_eth_tester_sync_timeout;
+    g_nof_octet_generate : NATURAL := 1;
+    g_nof_octet_output   : NATURAL := 4; -- must be multiple of g_nof_octet_generate.
+    g_use_network_header : BOOLEAN  := TRUE;
+    g_use_dp_header      : BOOLEAN  := TRUE;
+    g_hdr_field_arr      : t_common_field_arr := c_eth_tester_hdr_field_arr;
+    g_hdr_field_sel      : STD_LOGIC_VECTOR   := c_eth_tester_hdr_field_sel;
+    g_remove_crc         : BOOLEAN := TRUE  -- use TRUE when using sim_tse and tech_tse link interface,
+                                            -- use FALSE when streaming link interface
   );
   PORT (
     -- Clocks and reset
@@ -73,6 +80,8 @@ ENTITY eth_tester IS
     reg_bsn_monitor_v2_tx_cipo     : OUT t_mem_cipo;
     reg_strobe_total_count_tx_copi : IN  t_mem_copi := c_mem_copi_rst;
     reg_strobe_total_count_tx_cipo : OUT t_mem_cipo;
+    reg_dp_split_copi              : IN  t_mem_copi := c_mem_copi_rst;
+    reg_dp_split_cipo              : OUT t_mem_cipo;
     -- . Rx
     reg_bsn_monitor_v2_rx_copi             : IN  t_mem_copi := c_mem_copi_rst;
     reg_bsn_monitor_v2_rx_cipo             : OUT t_mem_cipo;
@@ -84,6 +93,8 @@ END eth_tester;
 
 ARCHITECTURE str OF eth_tester IS
 
+  CONSTANT c_dp_split_reg_adr_w : NATURAL := 1; -- 1 for 1 stream in dp_split
+  
   SIGNAL ref_sync_arr  : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
 
   SIGNAL dp_length_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0);  -- tx block length
@@ -98,6 +109,8 @@ ARCHITECTURE str OF eth_tester IS
   SIGNAL reg_bsn_monitor_v2_tx_cipo_arr     : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst);
   SIGNAL reg_strobe_total_count_tx_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst);
   SIGNAL reg_strobe_total_count_tx_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst);
+  SIGNAL reg_dp_split_copi_arr              : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst);
+  SIGNAL reg_dp_split_cipo_arr              : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst);
   -- . Rx
   SIGNAL reg_bsn_monitor_v2_rx_copi_arr     : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_copi_rst);
   SIGNAL reg_bsn_monitor_v2_rx_cipo_arr     : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_cipo_rst);
@@ -109,7 +122,13 @@ BEGIN
   gen_streams : FOR I IN 0 TO g_nof_streams-1 GENERATE
     u_tx : ENTITY work.eth_tester_tx
     GENERIC MAP (
-      g_bg_sync_timeout  => g_bg_sync_timeout
+      g_bg_sync_timeout    => g_bg_sync_timeout,
+      g_nof_octet_generate => g_nof_octet_generate,
+      g_nof_octet_output   => g_nof_octet_output,
+      g_use_network_header => g_use_network_header, 
+      g_use_dp_header      => g_use_dp_header,
+      g_hdr_field_arr      => g_hdr_field_arr,
+      g_hdr_field_sel      => g_hdr_field_sel
     )
     PORT MAP (
       -- Clocks and reset
@@ -139,12 +158,18 @@ BEGIN
       reg_bsn_monitor_v2_tx_copi     => reg_bsn_monitor_v2_tx_copi_arr(I),
       reg_bsn_monitor_v2_tx_cipo     => reg_bsn_monitor_v2_tx_cipo_arr(I),
       reg_strobe_total_count_tx_copi => reg_strobe_total_count_tx_copi_arr(I),
-      reg_strobe_total_count_tx_cipo => reg_strobe_total_count_tx_cipo_arr(I)
+      reg_strobe_total_count_tx_cipo => reg_strobe_total_count_tx_cipo_arr(I),
+      reg_dp_split_copi              => reg_dp_split_copi_arr(I),
+      reg_dp_split_cipo              => reg_dp_split_cipo_arr(I)
     );
 
     u_rx : ENTITY work.eth_tester_rx
     GENERIC MAP (
       g_bg_sync_timeout  => g_bg_sync_timeout,
+      g_nof_octet_unpack => g_nof_octet_generate,
+      g_nof_octet_input  => g_nof_octet_output,
+      g_use_dp_header    => g_use_dp_header,
+      g_hdr_field_arr    => g_hdr_field_arr,
       g_remove_crc       => g_remove_crc
     )
     PORT MAP (
@@ -221,6 +246,18 @@ BEGIN
     miso_arr => reg_strobe_total_count_tx_cipo_arr
   );
 
+  u_common_mem_mux_dp_split : ENTITY common_lib.common_mem_mux
+  GENERIC MAP (
+    g_nof_mosi    => g_nof_streams,
+    g_mult_addr_w => c_dp_split_reg_adr_w
+  )
+  PORT MAP (
+    mosi     => reg_dp_split_copi,
+    miso     => reg_dp_split_cipo,
+    mosi_arr => reg_dp_split_copi_arr,
+    miso_arr => reg_dp_split_cipo_arr
+  );
+
   -- Rx
   u_common_mem_mux_bsn_monitor_v2_rx : ENTITY common_lib.common_mem_mux
   GENERIC MAP (
diff --git a/libraries/io/eth/src/vhdl/eth_tester_rx.vhd b/libraries/io/eth/src/vhdl/eth_tester_rx.vhd
index 982054836a1dd884878c733548be96fc41ee054e..acaf31d8d3eec327626ddee2fedd3bdedd3c5fe3 100644
--- a/libraries/io/eth/src/vhdl/eth_tester_rx.vhd
+++ b/libraries/io/eth/src/vhdl/eth_tester_rx.vhd
@@ -38,6 +38,10 @@ USE work.eth_tester_pkg.ALL;
 ENTITY eth_tester_rx IS
   GENERIC (
     g_bg_sync_timeout  : NATURAL := 220*10**6;  -- 10% margin for nominal 1 s with st_clk at 200MHz
+    g_nof_octet_unpack : NATURAL  := 1;
+    g_nof_octet_input  : NATURAL  := 4; -- must be multiple of g_nof_octet_generate
+    g_use_dp_header    : BOOLEAN  := TRUE;
+    g_hdr_field_arr    : t_common_field_arr := c_eth_tester_hdr_field_arr;
     g_remove_crc       : BOOLEAN := TRUE  -- use TRUE when using sim_tse and tech_tse link interface,
                                           -- use FALSE when streaming link interface
   );
@@ -67,14 +71,17 @@ ARCHITECTURE str OF eth_tester_rx IS
 
   CONSTANT c_nof_total_counts     : NATURAL := 3;  -- 0 = nof_sop, 1 = nof_valid, 2 = nof_crc_corrupt
 
-  CONSTANT c_empty_w              : NATURAL := 2;  -- for 0, 1, 2, 3 empty octets per word
+  CONSTANT c_empty_w              : NATURAL := ceil_log2(g_nof_octet_input);  
   CONSTANT c_error_w              : NATURAL := 1;
+  CONSTANT c_in_data_w            : NATURAL := g_nof_octet_input * c_octet_w;
+  CONSTANT c_repack_data_w        : NATURAL := g_nof_octet_unpack * c_octet_w;
+  CONSTANT c_nof_repack_words     : NATURAL := g_nof_octet_input / g_nof_octet_unpack;
 
   -- Rx FIFO size can be much less than rx_block_sz_max, because st_clk >
   -- eth_clk rate, but with st level tx-rx loopback the Rx FIFO does need
   -- rx_block_sz_max FIFO size.
-  CONSTANT rx_block_sz_max        : NATURAL := c_eth_tester_rx_block_len_max / c_word_sz;  -- = 9004 / 4 = 2251
-  CONSTANT c_fifo_size            : NATURAL := true_log_pow2(rx_block_sz_max);  -- = 4096 words
+  CONSTANT rx_block_sz_max   : NATURAL := ceil_div(c_eth_tester_rx_block_len_max, g_nof_octet_input);
+  CONSTANT c_fifo_size       : NATURAL := true_log_pow2(rx_block_sz_max);
 
   SIGNAL rx_udp_data         : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
   SIGNAL rx_offload_sosi     : t_dp_sosi;
@@ -114,9 +121,9 @@ BEGIN
   u_dp_offload_rx : ENTITY dp_lib.dp_offload_rx
   GENERIC MAP (
     g_nof_streams   => 1,
-    g_data_w        => c_word_w,
+    g_data_w        => c_in_data_w,
     g_symbol_w      => c_octet_w,
-    g_hdr_field_arr => c_eth_tester_hdr_field_arr,
+    g_hdr_field_arr => g_hdr_field_arr,
     g_remove_crc    => g_remove_crc,
     g_crc_nof_words => 1
   )
@@ -141,9 +148,11 @@ BEGIN
   p_set_meta: PROCESS(rx_offload_sosi, hdr_fields_out_slv, hdr_fields_raw_slv)
   BEGIN
     decoded_sosi      <= rx_offload_sosi;
-    decoded_length    <=       TO_UINT(hdr_fields_raw_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_length")));
-    decoded_sosi.sync <=            sl(hdr_fields_out_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_sync") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_sync")));
-    decoded_sosi.bsn  <= RESIZE_DP_BSN(hdr_fields_raw_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_bsn" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_bsn")));
+    IF g_use_dp_header THEN
+      decoded_length    <=       TO_UINT(hdr_fields_raw_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_length")));
+      decoded_sosi.sync <=            sl(hdr_fields_out_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_sync") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_sync")));
+      decoded_sosi.bsn  <= RESIZE_DP_BSN(hdr_fields_raw_slv(field_hi(c_eth_tester_hdr_field_arr, "dp_bsn" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_bsn")));
+    END IF;
     -- Map rx_offload_sosi.err c_tech_tse_error_w = 6 bit value on to c_error_w = 1 bit decoded_sosi.err value
     decoded_sosi.err <= TO_DP_ERROR(0);
     IF UNSIGNED(rx_offload_sosi.err(c_tech_tse_error_w-1 DOWNTO 0)) /= 0 THEN
@@ -155,7 +164,7 @@ BEGIN
   p_verify_length : PROCESS(st_clk)
   BEGIN
     IF rising_edge(st_clk) THEN
-      IF decoded_sosi.sop = '1' THEN
+      IF g_use_dp_header AND decoded_sosi.sop = '1' THEN
         ASSERT decoded_length = exp_length REPORT "Unexpected Rx length" & NATURAL'IMAGE(decoded_length) & " /= " & NATURAL'IMAGE(exp_length) & " expected length from Tx" SEVERITY ERROR;
       END IF;
     END IF;
@@ -164,7 +173,7 @@ BEGIN
 
   u_rx_fifo : ENTITY dp_lib.dp_fifo_sc
   GENERIC MAP (
-    g_data_w         => c_word_w,
+    g_data_w         => c_in_data_w,
     g_bsn_w          => c_diag_bg_bsn_init_w,  -- = 64 bit
     g_empty_w        => c_empty_w,
     g_error_w        => c_error_w,
@@ -187,13 +196,13 @@ BEGIN
     src_out     => rx_fifo_sosi
   );
 
-  u_unpack : ENTITY dp_lib.dp_repack_data  -- unpack 32b words into 8b octets
+  u_unpack : ENTITY dp_lib.dp_repack_data 
   GENERIC MAP (
-    g_in_dat_w       => c_word_w,  -- = 32
+    g_in_dat_w       => c_in_data_w, 
     g_in_nof_words   => 1,
     g_in_symbol_w    => c_octet_w,
-    g_out_dat_w      => c_octet_w,  -- = 8
-    g_out_nof_words  => c_word_sz,  -- = 4
+    g_out_dat_w      => c_repack_data_w,  
+    g_out_nof_words  => c_nof_repack_words,  
     g_out_symbol_w   => c_octet_w
   )
   PORT MAP (
@@ -240,7 +249,7 @@ BEGIN
   END PROCESS;
 
   in_strobe_arr(0) <= unpacked_sosi.sop;    -- count total nof Rx packets
-  in_strobe_arr(1) <= unpacked_sosi.valid;  -- count total nof Rx valid octets
+  in_strobe_arr(1) <= unpacked_sosi.valid;  -- count total nof Rx valid samples
   in_strobe_arr(2) <= crc_corrupt;          -- count total nof corrupted Rx packets
 
   u_dp_strobe_total_count : ENTITY dp_lib.dp_strobe_total_count
diff --git a/libraries/io/eth/src/vhdl/eth_tester_tx.vhd b/libraries/io/eth/src/vhdl/eth_tester_tx.vhd
index a110e63720b8dd841afff9b5af9d8c3fbd52d844..c63c25fccd12554350afdf08f252c76d6b436974 100644
--- a/libraries/io/eth/src/vhdl/eth_tester_tx.vhd
+++ b/libraries/io/eth/src/vhdl/eth_tester_tx.vhd
@@ -17,12 +17,21 @@
 -- limitations under the License.
 --
 -------------------------------------------------------------------------------
--- AUthor: E. Kooistra
+-- AUthor: E. Kooistra, R. vd Walle
 -- Purpose: Test the 1GbE interface by sending and counting received packets.
 -- Description: Tx part of eth_tester, see detailed design in [1]
 --
 -- References:
 -- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE
+-- 
+-- Remarks:
+-- . g_nof_octet_generate can be set to increase the amount of bytes generated
+--   per clock cycle by the BG. This is done by duplicating the one byte 
+--   g_nof_octet_generate times using a generate statement.
+-- . g_nof_octet_output determines the output data width, e.g. 
+--   when set to 4, the output sosi containis 4 * 8 = 32 bits of generated data.
+--   This should be the same or a multiple of g_nof_octet_generate such that
+--   it can be repacked.
 
 LIBRARY IEEE, common_lib, dp_lib, diag_lib;
 USE IEEE.std_logic_1164.ALL;
@@ -36,7 +45,14 @@ USE work.eth_tester_pkg.ALL;
 
 ENTITY eth_tester_tx IS
   GENERIC (
-    g_bg_sync_timeout  : NATURAL := 220*10**6  -- 10% margin for nominal 1 s with st_clk at 200MHz
+    g_bg_sync_timeout     : NATURAL  := 220*10**6;  -- 10% margin for nominal 1 s with st_clk at 200MHz
+    g_nof_octet_generate  : NATURAL  := 1;
+    g_nof_octet_output    : NATURAL  := 4; -- must be multiple of g_nof_octet_generate
+    g_use_network_header  : BOOLEAN  := TRUE;
+    g_use_dp_header       : BOOLEAN  := TRUE;
+    g_hdr_field_arr       : t_common_field_arr := c_eth_tester_hdr_field_arr;
+    g_hdr_field_sel       : STD_LOGIC_VECTOR   := c_eth_tester_hdr_field_sel
+
   );
   PORT (
     -- Clocks and reset
@@ -66,36 +82,48 @@ ENTITY eth_tester_tx IS
     reg_bsn_monitor_v2_tx_copi     : IN  t_mem_copi := c_mem_copi_rst;
     reg_bsn_monitor_v2_tx_cipo     : OUT t_mem_cipo;
     reg_strobe_total_count_tx_copi : IN  t_mem_copi := c_mem_copi_rst;
-    reg_strobe_total_count_tx_cipo : OUT t_mem_cipo
+    reg_strobe_total_count_tx_cipo : OUT t_mem_cipo;
+    reg_dp_split_copi              : IN  t_mem_copi := c_mem_copi_rst;
+    reg_dp_split_cipo              : OUT t_mem_cipo
   );
 END eth_tester_tx;
 
 
 ARCHITECTURE str OF eth_tester_tx IS
 
-  CONSTANT c_empty_w              : NATURAL := 2;  -- for 0, 1, 2, 3 empty octets per word
+  CONSTANT c_empty_w              : NATURAL := ceil_log2(g_nof_octet_output);
 
   -- Choose 10% extra margin for FIFO fill level that will result in BG block
   -- level flow control via  bg_siso.xon. The input eop will release blocks
   -- for FIFO output already before the FIFO is fill level is reached.
   -- Choose FIFO size to fit one more packet on top of FIFO fill level.
-  CONSTANT c_packet_sz_max        : NATURAL := ceil_div(c_eth_tester_bg_block_len_max, c_word_sz);
+  CONSTANT c_packet_sz_max        : NATURAL := ceil_div(c_eth_tester_bg_block_len_max, g_nof_octet_output);
   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            : NATURAL := true_log_pow2(c_fifo_fill + c_packet_sz_max); 
   CONSTANT c_fifo_size_w          : NATURAL := ceil_log2(c_fifo_size);
 
   CONSTANT c_nof_total_counts     : NATURAL := 1;  -- one to count Tx packets
 
+  CONSTANT c_nof_repack_words     : NATURAL := g_nof_octet_output / g_nof_octet_generate; -- yields integer as g_nof_octet_output is multiple of g_nof_octet_generate.
+  CONSTANT c_generate_data_w      : NATURAL := g_nof_octet_generate * c_octet_w;
+  CONSTANT c_out_data_w           : NATURAL := g_nof_octet_output * c_octet_w;
+  CONSTANT c_nof_symbols_max      : NATURAL := c_network_eth_payload_jumbo_max;
+  CONSTANT c_use_split            : BOOLEAN := sel_a_b(g_nof_octet_generate > 1, TRUE, FALSE); 
+
   SIGNAL ip_total_length          : NATURAL;
   SIGNAL udp_total_length         : NATURAL;
   SIGNAL app_total_length         : NATURAL;
 
   SIGNAL bg_siso                  : t_dp_siso := c_dp_siso_rdy;
   SIGNAL bg_sosi                  : t_dp_sosi;
+  SIGNAL in_split_sosi            : t_dp_sosi;
+  SIGNAL in_split_siso            : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL out_split_sosi_arr       : t_dp_sosi_arr(1 DOWNTO 0);
+  SIGNAL out_split_siso_arr       : t_dp_siso_arr(1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy);
+  SIGNAL split_nof_symbols        : NATURAL;
   SIGNAL bg_data                  : STD_LOGIC_VECTOR(c_octet_w-1 DOWNTO 0);
   SIGNAL bg_ctrl_hold             : t_diag_block_gen;
   SIGNAL bg_block_len             : NATURAL;
-  SIGNAL tx_packed_siso           : t_dp_siso;
   SIGNAL tx_packed_sosi           : t_dp_sosi;
   SIGNAL tx_packed_data           : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
   SIGNAL tx_fifo_sosi             : t_dp_sosi;
@@ -138,30 +166,40 @@ BEGIN
   GENERIC MAP (
     g_nof_streams        => 1,
     g_use_bg_buffer_ram  => FALSE,
-    g_buf_addr_w         => c_diag_bg_mem_adrs_w  -- = 24, use full range 2**24 for BG addr --> data values
+    g_buf_addr_w         => c_diag_bg_mem_adrs_w,  -- = 24, use full range 2**24 for BG addr --> data values
+    g_buf_dat_w          => c_octet_w
   )
   PORT MAP (
     -- System
-    mm_rst           => mm_rst,
-    mm_clk           => mm_clk,
-    dp_rst           => st_rst,
-    dp_clk           => st_clk,
-    en_sync          => st_pps,  -- block generator enable sync pulse in ST clock domain
+    mm_rst  => mm_rst,
+    mm_clk  => mm_clk,
+    dp_rst  => st_rst,
+    dp_clk  => st_clk,
+    en_sync => st_pps,  -- block generator enable sync pulse in ST clock domain
     -- MM interface
-    reg_bg_ctrl_mosi      => reg_bg_ctrl_copi,  -- BG control register (one for all streams)
-    reg_bg_ctrl_miso      => reg_bg_ctrl_cipo,
+    reg_bg_ctrl_mosi    => reg_bg_ctrl_copi,  -- BG control register (one for all streams)
+    reg_bg_ctrl_miso    => reg_bg_ctrl_cipo,
     -- ST interface
-    bg_ctrl_hold_arr(0)   => bg_ctrl_hold,
-    out_sosi_arr(0)       => bg_sosi,
-    out_siso_arr(0)       => bg_siso
+    bg_ctrl_hold_arr(0) => bg_ctrl_hold,
+    out_sosi_arr(0)     => bg_sosi,
+    out_siso_arr(0)     => bg_siso
   );
 
+  -- Duplicate bg_sosi.data g_nof_octets_generate times
+  p_duplicate : PROCESS(bg_sosi)
+  BEGIN
+    in_split_sosi <= bg_sosi;
+    FOR I IN 0 TO g_nof_octet_generate-1 LOOP
+      in_split_sosi.data((I+1) * c_octet_w-1 DOWNTO I * c_octet_w) <= bg_sosi.data(c_octet_w-1 DOWNTO 0);
+    END LOOP;
+  END PROCESS;
+
   -- BG clock level flow control, needed when the dp_repack_data has to insert
   -- empty octets into the last packed word.
-  bg_siso.ready <= tx_packed_siso.ready;
+  bg_siso.ready <= in_split_siso.ready;
 
   -- BG block level flow control, needed in case BG settings result in eth bit
-  -- rate > 1 Gbps, to avoid u_tx_fifo overflow.
+  -- rate larger than the rated ethernet output speed, to avoid u_tx_fifo overflow.
   p_bg_siso_xon : PROCESS(st_rst, st_clk)
   BEGIN
     IF st_rst = '1' THEN
@@ -174,26 +212,59 @@ BEGIN
     END IF;
   END PROCESS;
 
-  u_pack : ENTITY dp_lib.dp_repack_data  -- pack 8b octets into 32b words
+  -- Use dp_split to make fine packet length adjustment on octet level.
+  -- dp_split sets the empty field to indicate the unused bytes in the last word.
+  gen_split : IF c_use_split GENERATE
+    u_mms_dp_split : ENTITY dp_lib.mms_dp_split
+    GENERIC MAP (
+      g_data_w          => c_generate_data_w,
+      g_symbol_w        => c_octet_w,
+      g_nof_symbols_max => c_nof_symbols_max
+    )
+    PORT MAP (
+      mm_rst             => mm_rst,
+      mm_clk             => mm_clk,
+      dp_rst             => st_rst,
+      dp_clk             => st_clk,
+
+      reg_mosi           => reg_dp_split_copi,
+      reg_miso           => reg_dp_split_cipo,
+
+      snk_in_arr(0)      => in_split_sosi,
+      snk_out_arr(0)     => in_split_siso,
+
+      src_in_2arr(0)     => out_split_siso_arr,
+      src_out_2arr(0)    => out_split_sosi_arr,
+
+      out_nof_symbols(0) => split_nof_symbols
+    );
+  END GENERATE;
+
+  gen_no_split : IF NOT c_use_split GENERATE
+    out_split_sosi_arr(1) <= in_split_sosi;
+    in_split_siso <= out_split_siso_arr(1);
+  END GENERATE;
+
+  u_pack : ENTITY dp_lib.dp_repack_data  -- repack generated words to output width.
   GENERIC MAP (
-    g_in_dat_w       => c_octet_w,  -- = 8
-    g_in_nof_words   => c_word_sz,  -- = 4
+    g_in_dat_w       => c_generate_data_w,
+    g_in_nof_words   => c_nof_repack_words,  
     g_in_symbol_w    => c_octet_w,
-    g_out_dat_w      => c_word_w,  -- = 32
+    g_out_dat_w      => c_out_data_w,  
     g_out_nof_words  => 1,
     g_out_symbol_w   => c_octet_w
   )
   PORT MAP (
     rst              => st_rst,
     clk              => st_clk,
-    snk_out          => tx_packed_siso,
-    snk_in           => bg_sosi,
+    snk_out          => out_split_siso_arr(1), -- connect dp_split head part, tail is discarded.
+    snk_in           => out_split_sosi_arr(1),
     src_out          => tx_packed_sosi
   );
 
   u_tx_fifo : ENTITY dp_lib.dp_fifo_fill_eop
   GENERIC MAP (
-    g_data_w         => c_word_w,
+    g_data_w         => c_out_data_w,
     g_bsn_w          => c_diag_bg_bsn_init_w,  -- = 64 bit
     g_empty_w        => c_empty_w,
     g_use_bsn        => TRUE,
@@ -262,19 +333,24 @@ BEGIN
   -- The bg_block_len is still valid because bg_ctrl_hold holds the BG settings
   -- until it restarts, so no need to pass bg_block_len on via e.g. the channel
   -- field in u_fifo.
-  bg_block_len <= TO_UINT(bg_ctrl_hold.samples_per_packet(15 DOWNTO 0));  -- packet lenghts fit in 16b
+  bg_block_len <= split_nof_symbols WHEN c_use_split ELSE TO_UINT(bg_ctrl_hold.samples_per_packet(15 DOWNTO 0));  -- packet lenghts fit in 16b
   app_total_length <= c_eth_tester_app_hdr_len + bg_block_len WHEN rising_edge(st_clk);
   udp_total_length <= c_network_udp_header_len + app_total_length WHEN rising_edge(st_clk);
   ip_total_length <= c_network_ip_header_len + udp_total_length WHEN rising_edge(st_clk);
 
-  hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "eth_src_mac"     ) DOWNTO field_lo(c_eth_tester_hdr_field_arr,  "eth_src_mac"     )) <= eth_src_mac;
-  hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "ip_total_length" ) DOWNTO field_lo(c_eth_tester_hdr_field_arr,  "ip_total_length" )) <= TO_UVEC(ip_total_length, 16);
-  hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "ip_src_addr"     ) DOWNTO field_lo(c_eth_tester_hdr_field_arr,  "ip_src_addr"     )) <= ip_src_addr;
-  hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "udp_src_port"    ) DOWNTO field_lo(c_eth_tester_hdr_field_arr,  "udp_src_port"    )) <= udp_src_port;
-  hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "udp_total_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr,  "udp_total_length")) <= TO_UVEC(udp_total_length, 16);
-  hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "dp_length"       ) DOWNTO field_lo(c_eth_tester_hdr_field_arr,  "dp_length"       )) <= TO_UVEC(app_total_length, 16);
-  hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "dp_sync"         ) DOWNTO field_lo(c_eth_tester_hdr_field_arr,  "dp_sync"         )) <= slv(tx_fifo_sosi.sync);
-  hdr_fields_slv_in(field_hi(c_eth_tester_hdr_field_arr, "dp_bsn"          ) DOWNTO field_lo(c_eth_tester_hdr_field_arr,  "dp_bsn"          )) <= tx_fifo_sosi.bsn;
+  gen_network_header : IF g_use_network_header GENERATE
+    hdr_fields_slv_in(field_hi(g_hdr_field_arr, "eth_src_mac"     ) DOWNTO field_lo(g_hdr_field_arr,  "eth_src_mac"     )) <= eth_src_mac;
+    hdr_fields_slv_in(field_hi(g_hdr_field_arr, "ip_total_length" ) DOWNTO field_lo(g_hdr_field_arr,  "ip_total_length" )) <= TO_UVEC(ip_total_length, 16);
+    hdr_fields_slv_in(field_hi(g_hdr_field_arr, "ip_src_addr"     ) DOWNTO field_lo(g_hdr_field_arr,  "ip_src_addr"     )) <= ip_src_addr;
+    hdr_fields_slv_in(field_hi(g_hdr_field_arr, "udp_src_port"    ) DOWNTO field_lo(g_hdr_field_arr,  "udp_src_port"    )) <= udp_src_port;
+    hdr_fields_slv_in(field_hi(g_hdr_field_arr, "udp_total_length") DOWNTO field_lo(g_hdr_field_arr,  "udp_total_length")) <= TO_UVEC(udp_total_length, 16);
+  END GENERATE;
+
+  gen_dp_header : IF g_use_dp_header GENERATE
+    hdr_fields_slv_in(field_hi(g_hdr_field_arr, "dp_length"       ) DOWNTO field_lo(g_hdr_field_arr,  "dp_length"       )) <= TO_UVEC(app_total_length, 16);
+    hdr_fields_slv_in(field_hi(g_hdr_field_arr, "dp_sync"         ) DOWNTO field_lo(g_hdr_field_arr,  "dp_sync"         )) <= slv(tx_fifo_sosi.sync);
+    hdr_fields_slv_in(field_hi(g_hdr_field_arr, "dp_bsn"          ) DOWNTO field_lo(g_hdr_field_arr,  "dp_bsn"          )) <= tx_fifo_sosi.bsn;
+  END GENERATE;
 
   -------------------------------------------------------------------------------
   -- Tx ETH/UDP/IP packets with packed BG data
@@ -282,10 +358,10 @@ BEGIN
   u_dp_offload_tx : ENTITY dp_lib.dp_offload_tx_v3
   GENERIC MAP (
     g_nof_streams    => 1,
-    g_data_w         => c_word_w,
+    g_data_w         => c_out_data_w,
     g_symbol_w       => c_octet_w,
-    g_hdr_field_arr  => c_eth_tester_hdr_field_arr,
-    g_hdr_field_sel  => c_eth_tester_hdr_field_sel,
+    g_hdr_field_arr  => g_hdr_field_arr,
+    g_hdr_field_sel  => g_hdr_field_sel,
     g_pipeline_ready => TRUE
   )
   PORT MAP (
diff --git a/libraries/io/eth/tb/vhdl/tb_eth_tester_high_bw.vhd b/libraries/io/eth/tb/vhdl/tb_eth_tester_high_bw.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..0e0e07b7573188da65791687e9a4e6a567a1b270
--- /dev/null
+++ b/libraries/io/eth/tb/vhdl/tb_eth_tester_high_bw.vhd
@@ -0,0 +1,527 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- 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: R. vd Walle
+-- Purpose: Test bench for eth_tester using high bandwidth generic configuration
+-- Description: Similar to the 1GbE testbench [1] for the eth tester but using generic
+-- values for usage with high bandwidth, e.g. 10 / 100 GbE.
+--   The g_nof_streams >= 1 are tested independently, using g_bg_ctrl_first for
+--   BG in stream 0 and g_bg_ctrl_others for all other streams.
+--
+-- Usage:
+-- > as 8
+-- # * E.g. view sosi/data signals in dut/gen_streams/u_rx and u_tx
+-- > 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, technology_lib, tech_tse_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.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 dp_lib.dp_components_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;
+USE technology_lib.technology_select_pkg.ALL;
+USE tech_tse_lib.tech_tse_pkg.ALL;
+USE tech_tse_lib.tb_tech_tse_pkg.ALL;
+
+ENTITY tb_eth_tester_high_bw 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_nof_streams        : NATURAL := 1;  
+    g_nof_octet_output   : NATURAL := 96; -- maximum = 96 bytes as max dp.data field = 768 bits.
+    g_nof_octet_generate : NATURAL := 96;
+
+    -- 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_first      : t_diag_block_gen_integer := ('1', '1', 500, 3, 200, 0, c_diag_bg_mem_max_adr, 0);  -- for first stream
+    g_bg_ctrl_others     : t_diag_block_gen_integer := ('1', '1', 300, 3, 10, 0, c_diag_bg_mem_max_adr, 0)   -- for other streams
+  );
+  PORT (
+    tb_end : OUT STD_LOGIC
+  );
+END tb_eth_tester_high_bw;
+
+
+ARCHITECTURE tb OF tb_eth_tester_high_bw 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_first    : NATURAL := ceil_div(g_bg_ctrl_first.samples_per_packet, g_nof_octet_generate);
+  CONSTANT c_bg_block_len_others   : NATURAL := ceil_div(g_bg_ctrl_others.samples_per_packet, g_nof_octet_generate);
+  CONSTANT c_bg_block_len_max      : NATURAL := largest(c_bg_block_len_first, c_bg_block_len_others);
+
+  CONSTANT c_bg_slot_len_first     : NATURAL := c_bg_block_len_first + g_bg_ctrl_first.gapsize;
+  CONSTANT c_bg_slot_len_others    : NATURAL := c_bg_block_len_others + g_bg_ctrl_others.gapsize;
+  CONSTANT c_bg_slot_len_max       : NATURAL := largest(c_bg_slot_len_first, c_bg_slot_len_others);
+
+  CONSTANT c_eth_packet_len_first  : NATURAL := func_eth_tester_eth_packet_length(c_bg_block_len_first);
+  CONSTANT c_eth_packet_len_others : NATURAL := func_eth_tester_eth_packet_length(c_bg_block_len_others);
+
+  -- Use REAL to avoid NATURAL overflow in bps calculation
+  CONSTANT c_bg_nof_bps_first      : REAL := REAL(c_bg_block_len_first * c_octet_w) * REAL(c_nof_st_clk_per_s) / REAL(c_bg_slot_len_first);
+  CONSTANT c_bg_nof_bps_others     : REAL := REAL(c_bg_block_len_others * c_octet_w) * REAL(c_nof_st_clk_per_s) / REAL(c_bg_slot_len_others);
+  CONSTANT c_bg_nof_bps_total      : REAL := c_bg_nof_bps_first + REAL(g_nof_streams - 1) * c_bg_nof_bps_others;
+
+  CONSTANT c_bg_sync_period_first  : NATURAL := c_bg_slot_len_first * g_bg_ctrl_first.blocks_per_sync;
+  CONSTANT c_bg_sync_period_others : NATURAL := c_bg_slot_len_others * g_bg_ctrl_others.blocks_per_sync;
+  CONSTANT c_bg_sync_period_max    : NATURAL := largest(c_bg_sync_period_first, c_bg_sync_period_others);
+
+  CONSTANT c_run_time              : NATURAL := g_nof_sync * c_bg_sync_period_max;
+  CONSTANT c_nof_sync_first        : NATURAL := c_run_time / c_bg_sync_period_first;
+  CONSTANT c_nof_sync_others       : NATURAL := c_run_time / c_bg_sync_period_others;
+
+  -- 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_max >= 50;
+  CONSTANT c_rx_exp_latency_st       : NATURAL := 19;
+
+  -- CRC is added by Tx TSE IP and removed by dp_offload_rx when g_remove_crc =
+  -- g_loopback_eth = TRUE. Therefore internally only application payload
+  -- (= block_len) octets are counted.
+  CONSTANT c_nof_valid_per_packet_first   : NATURAL := c_bg_block_len_first;
+  CONSTANT c_nof_valid_per_packet_others  : NATURAL := c_bg_block_len_others;
+
+  CONSTANT c_total_count_nof_valid_per_sync_first  : NATURAL := g_bg_ctrl_first.blocks_per_sync * c_nof_valid_per_packet_first;
+  CONSTANT c_total_count_nof_valid_per_sync_others : NATURAL := g_bg_ctrl_others.blocks_per_sync * c_nof_valid_per_packet_others;
+
+  CONSTANT c_mon_nof_sop_first       : NATURAL := g_bg_ctrl_first.blocks_per_sync;
+  CONSTANT c_mon_nof_sop_others      : NATURAL := g_bg_ctrl_others.blocks_per_sync;
+  CONSTANT c_mon_nof_valid_first_tx  : NATURAL := c_mon_nof_sop_first * ceil_div(c_bg_block_len_first * g_nof_octet_generate, g_nof_octet_output);
+  CONSTANT c_mon_nof_valid_first_rx  : NATURAL := c_mon_nof_sop_first * c_nof_valid_per_packet_first;
+  CONSTANT c_mon_nof_valid_others_tx : NATURAL := c_mon_nof_sop_others * ceil_div(c_bg_block_len_others * g_nof_octet_generate, g_nof_octet_output);
+  CONSTANT c_mon_nof_valid_others_rx : NATURAL := c_mon_nof_sop_others * c_nof_valid_per_packet_others;
+
+  -- 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 i_tb_end            : STD_LOGIC := '0';
+
+  -- Use same bg_ctrl for all others streams, this provides sufficient test coverage
+  SIGNAL bg_ctrl_arr         : t_diag_block_gen_integer_arr(g_nof_streams-1 DOWNTO 0);
+
+  SIGNAL tx_fifo_rd_emp_arr  : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+
+  -- ETH UDP data path interface
+  SIGNAL tx_udp_sosi_arr     : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL tx_udp_siso_arr     : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy);
+  SIGNAL rx_udp_sosi_arr     : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+
+  -- 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;
+  SIGNAL reg_dp_split_copi               : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_dp_split_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_arr        : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL rx_total_count_nof_packet_arr        : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL exp_total_count_nof_packet_arr       : t_natural_arr(g_nof_streams-1 DOWNTO 0);  -- same for both tx and rx
+
+  SIGNAL rx_total_count_nof_valid_arr         : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL rx_exp_total_count_nof_valid_arr     : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+
+  SIGNAL rx_total_count_nof_corrupted_arr     : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL rx_exp_total_count_nof_corrupted_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+
+  -- . reg_bsn_monitor_v2
+  SIGNAL tx_mon_nof_sop_arr      : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL tx_mon_nof_valid_arr    : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL tx_mon_latency_arr      : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL rx_mon_nof_sop_arr      : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL rx_mon_nof_valid_arr    : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL rx_mon_latency_arr      : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+
+  -- View in Wave window
+  SIGNAL dbg_c_run_time                : NATURAL := c_run_time;
+  SIGNAL dbg_c_mon_nof_sop_first       : NATURAL := c_mon_nof_sop_first;
+  SIGNAL dbg_c_mon_nof_sop_others      : NATURAL := c_mon_nof_sop_others;
+  SIGNAL dbg_c_mon_nof_valid_first_tx  : NATURAL := c_mon_nof_valid_first_tx;
+  SIGNAL dbg_c_mon_nof_valid_first_rx  : NATURAL := c_mon_nof_valid_first_rx;
+  SIGNAL dbg_c_mon_nof_valid_others_tx : NATURAL := c_mon_nof_valid_others_tx;
+  SIGNAL dbg_c_mon_nof_valid_others_rx : NATURAL := c_mon_nof_valid_others_rx;
+
+BEGIN
+
+  tb_end <= i_tb_end;
+
+  mm_clk <= (NOT mm_clk) OR i_tb_end AFTER mm_clk_period/2;
+  st_clk <= (NOT st_clk) OR i_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;
+
+  -- Using
+  --SIGNAL exp_total_count_nof_packet_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0);
+  --                         (g_nof_streams-1 DOWNTO 1 => g_nof_sync * g_bg_ctrl_others.blocks_per_sync,
+  --                                                 0 => g_nof_sync * g_bg_ctrl_first.blocks_per_sync);
+  -- yields verror 1074, verror 1048, therefor use p_init instead, and
+  -- therefor use bg_ctrl_arr instead of c_bg_ctrl_arr.
+  p_init : PROCESS
+  BEGIN
+    bg_ctrl_arr    <= (OTHERS => g_bg_ctrl_others);
+    bg_ctrl_arr(0) <= g_bg_ctrl_first;
+
+    exp_total_count_nof_packet_arr    <= (OTHERS => c_nof_sync_others * g_bg_ctrl_others.blocks_per_sync);
+    exp_total_count_nof_packet_arr(0) <= c_nof_sync_first * g_bg_ctrl_first.blocks_per_sync;
+
+    rx_exp_total_count_nof_valid_arr    <= (OTHERS => c_nof_sync_others * c_total_count_nof_valid_per_sync_others);
+    rx_exp_total_count_nof_valid_arr(0) <= c_nof_sync_first * c_total_count_nof_valid_per_sync_first;
+
+    rx_exp_total_count_nof_corrupted_arr <= (OTHERS => 0);  -- default no Rx errors
+    WAIT;
+  END PROCESS;
+
+  -----------------------------------------------------------------------------
+  -- MM control and monitoring
+  -----------------------------------------------------------------------------
+  p_mm : PROCESS
+    VARIABLE v_value        : NATURAL;
+    VARIABLE v_offset       : NATURAL;
+    VARIABLE v_udp_dst_port : NATURAL;
+  BEGIN
+    i_tb_end <= '0';
+
+    proc_common_wait_until_low(mm_clk, mm_rst);
+    proc_common_wait_some_cycles(mm_clk, 10);
+
+    ---------------------------------------------------------------------------
+    -- Rx UDP offload port
+    ---------------------------------------------------------------------------
+    v_udp_dst_port := TO_UINT(c_eth_tester_udp_dst_port);
+
+
+
+    FOR I IN g_nof_streams-1 DOWNTO 0 LOOP
+      v_offset := I * c_eth_tester_reg_hdr_dat_addr_span;
+      -- Set destination MAC/IP/UDP port in tx header, increment udp_dst_port per stream
+      -- The MM addresses follow from byte address_offset // 4 in eth.peripheral.yaml
+      proc_mem_mm_bus_wr(v_offset + 16#7#, v_udp_dst_port + I, mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);
+      proc_mem_mm_bus_wr(v_offset + 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(v_offset + 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(v_offset + 16#19#, TO_UINT(c_eth_tester_eth_dst_mac(47 DOWNTO 32)), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);
+    END LOOP;
+
+    ---------------------------------------------------------------------------
+    -- Stimuli
+    ---------------------------------------------------------------------------
+    FOR I IN g_nof_streams-1 DOWNTO 0 LOOP
+      v_offset := I * c_diag_bg_reg_adr_span;
+      -- Set number of octets per packet for dp_split
+      proc_mem_mm_bus_wr(I*2, bg_ctrl_arr(I).samples_per_packet, mm_clk, reg_dp_split_copi);
+
+      -- Prepare the BG
+      proc_mem_mm_bus_wr(v_offset + 1, ceil_div(bg_ctrl_arr(I).samples_per_packet, g_nof_octet_generate) , mm_clk, reg_bg_ctrl_copi);
+      proc_mem_mm_bus_wr(v_offset + 2, bg_ctrl_arr(I).blocks_per_sync,    mm_clk, reg_bg_ctrl_copi);
+      proc_mem_mm_bus_wr(v_offset + 3, bg_ctrl_arr(I).gapsize,            mm_clk, reg_bg_ctrl_copi);
+      proc_mem_mm_bus_wr(v_offset + 4, bg_ctrl_arr(I).mem_low_adrs,       mm_clk, reg_bg_ctrl_copi);
+      proc_mem_mm_bus_wr(v_offset + 5, bg_ctrl_arr(I).mem_high_adrs,      mm_clk, reg_bg_ctrl_copi);
+      proc_mem_mm_bus_wr(v_offset + 6, bg_ctrl_arr(I).bsn_init,           mm_clk, reg_bg_ctrl_copi);  -- low part
+      proc_mem_mm_bus_wr(v_offset + 7, 0,                                 mm_clk, reg_bg_ctrl_copi);  -- high part
+      -- Enable the BG at st_pps pulse.
+      proc_mem_mm_bus_wr(v_offset + 0, 3, mm_clk, reg_bg_ctrl_copi);
+
+    END LOOP;
+    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
+    FOR I IN g_nof_streams-1 DOWNTO 0 LOOP
+      v_offset := I * c_diag_bg_reg_adr_span;
+      -- Disable the other BG
+      proc_mem_mm_bus_wr(v_offset + 0, 0, mm_clk, reg_bg_ctrl_copi);
+    END LOOP;
+
+    -- Wait until Tx FIFOs have emptied for all streams
+    WHILE UNSIGNED(tx_fifo_rd_emp_arr(g_nof_streams-1 DOWNTO 0)) /= 2**g_nof_streams - 1 LOOP
+      proc_common_wait_some_cycles(st_clk, 1);
+    END LOOP;
+    proc_common_wait_some_cycles(st_clk, c_bg_sync_period_max);
+    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
+    FOR I IN g_nof_streams-1 DOWNTO 0 LOOP
+      IF I = 0 THEN
+        print_str(c_tb_str &
+            "ETH bit rate (" & NATURAL'IMAGE(I) & ") :" &
+            " c_bg_nof_bps_first = " & REAL'IMAGE(c_bg_nof_bps_first) & " bps");
+      ELSE
+        print_str(c_tb_str &
+            "ETH bit rate (" & NATURAL'IMAGE(I) & ") :" &
+            " c_bg_nof_bps_others = " & REAL'IMAGE(c_bg_nof_bps_others) & " bps");
+      END IF;
+    END LOOP;
+    IF g_nof_streams > 1 THEN
+        print_str(c_tb_str &
+            "ETH bit rate total :" &
+            " c_bg_nof_bps_total = " & REAL'IMAGE(c_bg_nof_bps_total) & " bps");
+    END IF;
+
+    -------------------------------------------------------------------------
+    -- Verification: Total counts
+    -------------------------------------------------------------------------
+    FOR I IN g_nof_streams-1 DOWNTO 0 LOOP
+      -- . read low part, ignore high part (= 0) of two word total counts
+      v_offset := I * c_dp_strobe_total_count_reg_adr_span;
+      -- Tx total nof packets
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= TO_UINT(reg_strobe_total_count_tx_cipo.rddata(c_word_w-1 DOWNTO 0));
+      -- Rx total nof packets
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+      -- Rx total nof valids
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+      -- Rx total nof corrupted
+      proc_mem_mm_bus_rd(v_offset + 4, 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_corrupted_arr(I) <= 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(" & NATURAL'IMAGE(I) & ") :" &
+          " nof_packet = " & NATURAL'IMAGE(tx_total_count_nof_packet_arr(I)));
+
+      print_str(c_tb_str &
+          "Rx total counts monitor(" & NATURAL'IMAGE(I) & ") :" &
+          " nof_packet = " & NATURAL'IMAGE(rx_total_count_nof_packet_arr(I)) &
+          ", nof_valid = " & NATURAL'IMAGE(rx_total_count_nof_valid_arr(I)) &
+          ", nof_corrupted = " & NATURAL'IMAGE(rx_total_count_nof_corrupted_arr(I)));
+
+      -- Verify, only log when wrong
+      IF c_bg_nof_bps_total < 10.0**9 THEN
+        ASSERT tx_total_count_nof_packet_arr(I) = exp_total_count_nof_packet_arr(I) REPORT c_tb_str &
+            "Wrong Tx total nof packets count(" & NATURAL'IMAGE(I) &
+            "), Tx count = " & NATURAL'IMAGE(tx_total_count_nof_packet_arr(I)) &
+            " /= " & NATURAL'IMAGE(exp_total_count_nof_packet_arr(I)) &
+            " = Expected count" SEVERITY ERROR;
+
+        ASSERT rx_total_count_nof_packet_arr(I) = exp_total_count_nof_packet_arr(I) REPORT c_tb_str &
+            "Wrong Rx total nof packets count(" & NATURAL'IMAGE(I) &
+            "), Rx count = " & NATURAL'IMAGE(rx_total_count_nof_packet_arr(I)) &
+            " /= " & NATURAL'IMAGE(exp_total_count_nof_packet_arr(I)) &
+            " = Expected count" SEVERITY ERROR;
+
+        ASSERT rx_total_count_nof_valid_arr(I) = rx_exp_total_count_nof_valid_arr(I) REPORT c_tb_str &
+            "Wrong Rx total nof valids count(" & NATURAL'IMAGE(I) &
+            "), Rx count = " & NATURAL'IMAGE(rx_total_count_nof_valid_arr(I)) &
+            " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_valid_arr(I)) &
+            " = Expected count" SEVERITY ERROR;
+
+        ASSERT rx_total_count_nof_corrupted_arr(I) = rx_exp_total_count_nof_corrupted_arr(I) REPORT c_tb_str &
+            "Wrong Rx total nof corrupted count(" & NATURAL'IMAGE(I) &
+            "), Rx count = " & NATURAL'IMAGE(rx_total_count_nof_corrupted_arr(I)) &
+            " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_corrupted_arr(I)) &
+            " = Expected count" SEVERITY ERROR;
+      ELSE
+        -- Verify that Tx total nof packets = Rx total nof packets, also when
+        -- BG experiences siso.xon block level flow control, to stay below
+        -- 1 Gbps of the 1GbE link rate.
+        ASSERT tx_total_count_nof_packet_arr(I) = rx_total_count_nof_packet_arr(I) REPORT c_tb_str &
+            "Wrong Tx-Rx total nof packets count(" & NATURAL'IMAGE(I) &
+            "), Tx count = " & NATURAL'IMAGE(tx_total_count_nof_packet_arr(I)) &
+            " /= " & NATURAL'IMAGE(rx_total_count_nof_packet_arr(I)) &
+            " = Rx count" SEVERITY ERROR;
+      END IF;
+    END LOOP;
+
+    -------------------------------------------------------------------------
+    -- Verification: BSN monitors (yield same values in every sync interval)
+    -------------------------------------------------------------------------
+    FOR I IN g_nof_streams-1 DOWNTO 0 LOOP
+      v_offset := I * c_dp_bsn_monitor_v2_reg_adr_span;
+      -- 3 = nof_sop
+      -- 4 = nof_valid
+      -- 6 = latency
+      -- . Tx
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0));
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0));
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0));
+      -- . Rx
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0));
+      proc_mem_mm_bus_rd(v_offset + 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_arr(I) <= 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(" & NATURAL'IMAGE(I) & ") :" &
+          " nof_sop = " & NATURAL'IMAGE(tx_mon_nof_sop_arr(I)) &
+          ", nof_valid = " & NATURAL'IMAGE(tx_mon_nof_valid_arr(I)) &
+          ", latency = " & NATURAL'IMAGE(tx_mon_latency_arr(I)));
+
+      print_str(c_tb_str &
+          "Rx BSN monitor(" & NATURAL'IMAGE(I) & ") :" &
+          " nof_sop = " & NATURAL'IMAGE(rx_mon_nof_sop_arr(I)) &
+          ", nof_valid = " & NATURAL'IMAGE(rx_mon_nof_valid_arr(I)) &
+          ", latency = " & NATURAL'IMAGE(rx_mon_latency_arr(I)));
+
+      IF c_bg_nof_bps_total < 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
+        IF I = 0 THEN
+          ASSERT tx_mon_nof_sop_arr(I) = c_mon_nof_sop_first REPORT c_tb_str & "Wrong tx nof_sop for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+          ASSERT rx_mon_nof_sop_arr(I) = c_mon_nof_sop_first REPORT c_tb_str & "Wrong rx nof_sop for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+          ASSERT tx_mon_nof_valid_arr(I) = c_mon_nof_valid_first_tx REPORT c_tb_str & "Wrong tx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+          ASSERT rx_mon_nof_valid_arr(I) = c_mon_nof_valid_first_rx REPORT c_tb_str & "Wrong rx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+        ELSE
+          ASSERT tx_mon_nof_sop_arr(I) = c_mon_nof_sop_others REPORT c_tb_str & "Wrong tx nof_sop for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+          ASSERT rx_mon_nof_sop_arr(I) = c_mon_nof_sop_others REPORT c_tb_str & "Wrong rx nof_sop for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+          ASSERT tx_mon_nof_valid_arr(I) = c_mon_nof_valid_others_tx REPORT c_tb_str & "Wrong tx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+          ASSERT rx_mon_nof_valid_arr(I) = c_mon_nof_valid_others_rx REPORT c_tb_str & "Wrong rx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+        END IF;
+        ASSERT tx_mon_latency_arr(I) = c_tx_exp_latency REPORT c_tb_str & "Wrong tx latency for stream (" & NATURAL'IMAGE(I) & ")" 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_arr(I), c_rx_exp_latency_st, 10) REPORT
+              c_tb_str & "Wrong rx latency using st interface (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+        END IF;
+      END IF;
+    END LOOP;
+
+    -------------------------------------------------------------------------
+    -- End of test
+    -------------------------------------------------------------------------
+    proc_common_wait_some_cycles(mm_clk, 100);
+    i_tb_end <= '1';
+    WAIT;
+  END PROCESS;
+
+  dut : ENTITY work.eth_tester
+  GENERIC MAP (
+    g_nof_streams        => g_nof_streams,
+    g_bg_sync_timeout    => c_eth_tester_sync_timeout,
+    g_nof_octet_generate => g_nof_octet_generate,
+    g_nof_octet_output   => g_nof_octet_output,
+    g_remove_crc         => FALSE
+  )
+  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,
+
+    tx_fifo_rd_emp_arr => tx_fifo_rd_emp_arr,
+
+    tx_udp_sosi_arr    => tx_udp_sosi_arr,
+    tx_udp_siso_arr    => tx_udp_siso_arr,
+
+    -- UDP receive interface
+    rx_udp_sosi_arr    => rx_udp_sosi_arr,
+
+    -- 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,
+    reg_dp_split_copi              => reg_dp_split_copi,
+    reg_dp_split_cipo              => reg_dp_split_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
+  );
+  
+    -- Loop back at streaming sosi level
+    rx_udp_sosi_arr <= tx_udp_sosi_arr;
+END tb;
diff --git a/libraries/io/eth/tb/vhdl/tb_tb_eth_tester_high_bw.vhd b/libraries/io/eth/tb/vhdl/tb_tb_eth_tester_high_bw.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..036d1641b590e1182adf53fa195aacffd90d5461
--- /dev/null
+++ b/libraries/io/eth/tb/vhdl/tb_tb_eth_tester_high_bw.vhd
@@ -0,0 +1,177 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- 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: R. vd Walle
+-- Purpose: Multi test bench for eth_tester for high bandwidths.
+-- Description: Similar to the 1GbE TB as described in [1] but for 10 / 100 GbE.
+--
+-- References:
+-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE
+--
+-- Usage:
+--   > as 8
+--   > run -all
+--   Takes about 10 m
+
+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_tester_high_bw IS
+END tb_tb_eth_tester_high_bw;
+
+ARCHITECTURE tb OF tb_tb_eth_tester_high_bw IS
+
+  -- Multi tb
+  CONSTANT c_tb_w       : NATURAL := 100;  -- sufficiently long to fit all tb instances
+  CONSTANT c_tb_end_vec : STD_LOGIC_VECTOR(c_tb_w-1 DOWNTO 0) := (OTHERS=>'1');
+
+  SIGNAL tb_end_vec   : STD_LOGIC_VECTOR(c_tb_w-1 DOWNTO 0) := c_tb_end_vec;  -- best view as hex in Wave Window
+  SIGNAL tb_end       : STD_LOGIC := '0';
+
+  -- Tb
+  CONSTANT c_eth_clk_MHz   : NATURAL := 125;
+  CONSTANT c_st_clk_MHz    : NATURAL := 200;
+  CONSTANT c_nof_sync      : NATURAL := 2;
+  CONSTANT c_nof_sync_many : NATURAL := 50;  -- sufficient to achieve Tx FIFO fill level
+  CONSTANT c_nof_streams   : NATURAL := 3;
+  CONSTANT c_nof_blk       : NATURAL := 3;   -- nof_blk per sync
+
+  -- Tx packet size and gap size in octets
+  CONSTANT c_block_len       : NATURAL := 500;  -- BG block length of first stream [0]
+  CONSTANT c_block_len_jumbo : NATURAL := 9000;
+  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;
+  CONSTANT c_slot_len_min  : NATURAL := c_block_len + c_gap_len_min;
+
+  -- 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
+  CONSTANT c_long_gap      : NATURAL := c_gap_len_min * 10;
+  CONSTANT c_short_gap     : NATURAL := 10;   -- to cause BG xon/xoff flow control
+  CONSTANT c_zero_gap      : NATURAL := 0;    -- to verify BG ready flow control
+
+  -- Choose c_others_len > c_block_len, so same c_gap_len is suitable to
+  -- keep Ethernet link rate < 1 Gbps
+  CONSTANT c_others_len    : NATURAL := 65;  -- BG block length of other streams [c_nof_streams-1 : 1]
+
+  -- BG ctrl
+  CONSTANT c_high             : NATURAL := c_diag_bg_mem_max_adr;  -- = 2**24
+
+  CONSTANT c_bg_ctrl_rst      : t_diag_block_gen_integer := ('0', '0', 1, c_nof_blk, c_gap_len, 0, c_high, 0);  -- place holder for unused stream
+
+  CONSTANT c_bg_ctrl_one      : t_diag_block_gen_integer := ('1', '1', c_block_len,  c_nof_blk, c_gap_len, 0, c_high, 0);  -- for first stream
+  CONSTANT c_bg_ctrl_others   : t_diag_block_gen_integer := ('1', '1', c_others_len, c_nof_blk, c_gap_len, 0, c_high, 0);  -- for other streams
+
+  -- . BG with different block lengths and other payload values
+  --   The payload values are only verified manually using the Wave Window
+  CONSTANT c_bg_ctrl_len_0    : t_diag_block_gen_integer := ('1', '1', c_block_len+0, c_nof_blk, c_gap_len,      0,      0, 0);  -- nof octets
+  CONSTANT c_bg_ctrl_len_1    : t_diag_block_gen_integer := ('1', '1', c_block_len+1, c_nof_blk, c_gap_len,      1,      1, 0);  -- nof octets
+  CONSTANT c_bg_ctrl_len_2    : t_diag_block_gen_integer := ('1', '1', c_block_len+2, c_nof_blk, c_gap_len,      1,      7, 0);  -- nof octets
+  CONSTANT c_bg_ctrl_len_3    : t_diag_block_gen_integer := ('1', '1', c_block_len+3, c_nof_blk, c_gap_len, c_high-1, c_high-1, 0);  -- nof octets
+
+  CONSTANT c_bg_ctrl_multiple_first    : t_diag_block_gen_integer := ('1', '1', c_block_len,  c_nof_blk, c_nof_streams * c_gap_len, 0, c_high, 0);  -- for first stream
+  CONSTANT c_bg_ctrl_multiple_others   : t_diag_block_gen_integer := ('1', '1', c_others_len, c_nof_blk, c_nof_streams * c_gap_len, 0, c_high, 0);  -- for other streams
+
+BEGIN
+
+--  g_tb_index         : NATURAL := 0;  -- use to incremental delay logging from tb instances in tb_tb
+--  g_nof_sync         : NATURAL := 3;  -- number of BG sync intervals to set c_run_time
+--  g_nof_streams      : NATURAL := 2;
+--  g_nof_octet_output   : NATURAL := 96; -- maximum = 96 bytes as max dp.data field = 768 bits.
+--  g_nof_octet_generate : NATURAL := 96;
+--
+--  -- 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_first    : t_diag_block_gen_integer := ('1', '1', 50, c_nof_blk, 100, 0, 30, 0);  -- for first stream
+--  g_bg_ctrl_others   : t_diag_block_gen_integer := ('1', '1', 30, c_nof_blk, 10, 0, 30, 0)   -- for other streams
+
+  -- Tb instance prefix:
+  -- . u_st   : uses streaming Tx-Rx interface
+
+
+  -----------------------------------------------------------------------------
+  -- Single stream
+  -----------------------------------------------------------------------------
+  -- Try different loopback interfaces
+  u_st_10g      : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (0, c_nof_sync, 1, 8, 8, c_bg_ctrl_one, c_bg_ctrl_rst) PORT MAP (tb_end_vec(0)); -- 8 byte wide
+  u_st_100g     : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (1, c_nof_sync, 1, 64, 64, c_bg_ctrl_one, c_bg_ctrl_rst) PORT MAP (tb_end_vec(1)); -- 64 byte wide
+  u_st_max      : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (2, c_nof_sync, 1, 96, 96, c_bg_ctrl_one, c_bg_ctrl_rst) PORT MAP (tb_end_vec(2)); -- 96 byte wide as max dp.data width = 96*8=768 bits.
+
+  -- Try large block size and nof blocks_per_sync = 1
+  u_st_jumbo1   : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (10, c_nof_sync, 1, 96, 96,
+                                                         ('1', '1', c_block_len_jumbo, 1, c_zero_gap, 0, c_high, 0),
+                                                         c_bg_ctrl_rst)
+                                            PORT MAP (tb_end_vec(10));
+
+  -- Try large block sizes
+  u_st_jumbo2   : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (11, c_nof_sync, 1, 64, 64,
+                                                         ('1', '1', c_block_len_jumbo, 2, c_zero_gap, 0, c_high, 0),
+                                                         c_bg_ctrl_rst)
+                                            PORT MAP (tb_end_vec(11));
+
+
+
+  -- Try small block sizes at 64*8 = 512b bus size
+  -- . BG supports samples_per_packet >= 2, BG treats samples_per_packet = 1 as 2
+  -- . ETH MAC pads samples_per_packet <= 6 to 6, to have minimum packet length of 64 octets,
+  --   because hdr = 14 + 20 + 8 + 12 and crc = 4 have 58 octets.
+  u_st_len2 : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (20, c_nof_sync, 1, 64, 64,
+                                                     ('1', '1', 2, c_nof_blk, c_gap_len, 0, c_high, 0),
+                                                     c_bg_ctrl_rst)
+                                        PORT MAP (tb_end_vec(20));
+
+
+  -- Try different BG block lengths and data widths to verify sosi.empty nof octets in last word and repack.
+  u_st_bg_len_0 : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (30, c_nof_sync, 1, 64,  8, c_bg_ctrl_len_0, c_bg_ctrl_rst) PORT MAP (tb_end_vec(30));
+  u_st_bg_len_1 : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (31, c_nof_sync, 1, 8,   1, c_bg_ctrl_len_1, c_bg_ctrl_rst) PORT MAP (tb_end_vec(31));
+  u_st_bg_len_2 : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (32, c_nof_sync, 1, 8,   4, c_bg_ctrl_len_2, c_bg_ctrl_rst) PORT MAP (tb_end_vec(32));
+  u_st_bg_len_3 : ENTITY work.tb_eth_tester_high_bw GENERIC MAP (33, c_nof_sync, 1, 64, 64, c_bg_ctrl_len_3, c_bg_ctrl_rst) PORT MAP (tb_end_vec(33));
+
+  -----------------------------------------------------------------------------
+  -- Multiple streams
+  -----------------------------------------------------------------------------
+  u_st_multiple_streams : ENTITY work.tb_eth_tester_high_bw
+                          GENERIC MAP (80, c_nof_sync, c_nof_streams, 8, 8,
+                                       c_bg_ctrl_multiple_first,
+                                       c_bg_ctrl_multiple_others)
+                          PORT MAP (tb_end_vec(80));
+
+
+  tb_end <= '1' WHEN tb_end_vec = c_tb_end_vec ELSE '0';
+
+  p_tb_end : PROCESS
+  BEGIN
+    WAIT UNTIL tb_end='1';
+    WAIT FOR 1 ns;
+    REPORT "Multi tb simulation finished." SEVERITY FAILURE;
+    WAIT;
+  END PROCESS;
+
+END tb;