diff --git a/applications/rdma_demo/libraries/eth_tester_200g/hdllib.cfg b/applications/rdma_demo/libraries/eth_tester_200g/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..fe2717bbb8790ed0e4ee240566958d0b2d636693
--- /dev/null
+++ b/applications/rdma_demo/libraries/eth_tester_200g/hdllib.cfg
@@ -0,0 +1,20 @@
+hdl_lib_name = eth_tester_200g
+hdl_library_clause_name = eth_tester_200g_lib
+hdl_lib_uses_synth = common dp eth
+hdl_lib_uses_sim = diag technology tech_tse
+hdl_lib_technology = 
+
+synth_files =
+    src/vhdl/eth_tester_200g_pkg.vhd
+    src/vhdl/eth_tester_200g.vhd
+
+test_bench_files = 
+    tb/vhdl/tb_eth_tester_200g.vhd
+
+regression_test_vhdl = 
+
+
+[modelsim_project_file]
+
+[quartus_project_file]
+
diff --git a/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g.vhd b/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..9c83af4c58457be7465f5226897c41d57e9a33a0
--- /dev/null
+++ b/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g.vhd
@@ -0,0 +1,379 @@
+-------------------------------------------------------------------------------
+--
+-- 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. van der Walle
+-- 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 rdma_generator_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
+--   by the Vivado IP creator (only supports VHDL-93).
+-- Remark
+-- . 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, 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 axi4_lib.axi4_stream_pkg.all;
+use eth_lib.eth_pkg.all;
+use eth_lib.eth_tester_pkg.all;
+use work.rdma_generator_pkg.all;
+
+entity rdma_generator_eth_tester_wrapper is
+  port (
+    -- Clocks and reset
+    mm_clk             : in  std_logic;
+    st_clk             : in  std_logic;
+    st_pps             : in  std_logic;
+    aresetn            : in  std_logic;
+    -- UDP transmit interface
+    eth_src_mac        : in  std_logic_vector(6 * 8 - 1 downto 0);
+    ip_src_addr        : in  std_logic_vector(4 * 8 - 1 downto 0);
+    udp_src_port       : in  std_logic_vector(2 * 8 - 1 downto 0);
+
+    tx_fifo_rd_emp_arr : out std_logic_vector(0 downto 0);
+
+    -- tx_udp
+    -- Source In and Sink Out
+    tx_udp_tready    : in std_logic;
+
+    -- Source Out and Sink In
+    tx_udp_tvalid    : out std_logic;
+    tx_udp_tdata     : out std_logic_vector(512 - 1 downto 0);
+    tx_udp_tstrb     : out std_logic_vector(512 / 8 - 1 downto 0);
+    tx_udp_tkeep     : out std_logic_vector(512 / 8 - 1 downto 0);
+    tx_udp_tlast     : out std_logic;
+    tx_udp_tid       : out std_logic_vector(4 - 1 downto 0);
+    tx_udp_tdest     : out std_logic_vector(32 - 1 downto 0);
+    tx_udp_tuser     : out std_logic_vector(70 - 1 downto 0);
+
+    -- rx_udp
+    -- Source In and Sink Out
+    rx_udp_tready    : out std_logic;
+
+    -- Source Out and Sink In
+    rx_udp_tvalid    : in std_logic;
+    rx_udp_tdata     : in std_logic_vector(512 - 1 downto 0);
+    rx_udp_tstrb     : in std_logic_vector(512 / 8 - 1 downto 0);
+    rx_udp_tkeep     : in std_logic_vector(512 / 8 - 1 downto 0);
+    rx_udp_tlast     : in std_logic;
+    rx_udp_tid       : in std_logic_vector(4 - 1 downto 0);
+    rx_udp_tdest     : in std_logic_vector(32 - 1 downto 0);
+    rx_udp_tuser     : in std_logic_vector(70 - 1 downto 0);
+
+    -- reg_bg_ctrl
+    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_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_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_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_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_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 rdma_generator_eth_tester_wrapper;
+
+architecture str of rdma_generator_eth_tester_wrapper is
+  constant c_nof_byte                   : natural := c_rdma_generator_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);
+  signal tx_udp_siso_arr                : t_dp_siso_arr(0 downto 0) := (others => c_dp_siso_rdy);
+
+  signal rx_udp_axi4_sosi               : t_axi4_sosi := c_axi4_sosi_rst;
+  signal rx_udp_axi4_siso               : t_axi4_siso := c_axi4_siso_rst;
+  signal tx_udp_axi4_sosi               : t_axi4_sosi := c_axi4_sosi_rst;
+  signal tx_udp_axi4_siso               : t_axi4_siso := c_axi4_siso_rst;
+
+  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;
+
+  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;
+
+  signal mm_rst : std_logic := '0';
+  signal st_rst : std_logic := '0';
+begin
+  u_eth_tester : entity eth_lib.eth_tester
+  generic map (
+    g_nof_octet_generate => c_rdma_generator_nof_octet_generate_100gbe,
+    g_nof_octet_output   => c_rdma_generator_nof_octet_output_100gbe,
+    g_use_eth_header     => false,
+    g_use_ip_udp_header  => false,
+    g_use_dp_header      => true,
+    g_hdr_field_arr      => c_rdma_generator_dp_hdr_field_arr,
+    g_hdr_field_sel      => c_rdma_generator_dp_hdr_field_sel,
+    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        => eth_src_mac,
+    ip_src_addr        => ip_src_addr,
+    udp_src_port       => 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)
+    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,
+
+    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
+  );
+
+  -- DP to AXI4
+  u_axi4_tx_udp : entity axi4_lib.axi4_stream_dp_bridge
+  generic map (
+    g_axi4_rl => 0,
+    g_dp_rl   => 1,
+    g_active_low_rst => true
+  )
+  port map (
+    in_clk => st_clk,
+    in_rst => aresetn,
+
+    dp_rst => st_rst,
+
+    dp_in_sosi => tx_udp_sosi_arr(0),
+    dp_in_siso => tx_udp_siso_arr(0),
+
+    axi4_out_sosi => tx_udp_axi4_sosi,
+    axi4_out_siso => tx_udp_axi4_siso
+  );
+
+  u_axi4_rx_udp : entity axi4_lib.axi4_stream_dp_bridge
+  generic map (
+    g_axi4_rl => 0,
+    g_dp_rl   => 1,
+    g_active_low_rst => true
+  )
+  port map (
+    in_clk => st_clk,
+    in_rst => aresetn,
+
+    axi4_in_sosi => rx_udp_axi4_sosi,
+    axi4_in_siso => rx_udp_axi4_siso,
+
+    dp_out_sosi => rx_udp_sosi_arr(0),
+    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_tstrb  <= tx_udp_axi4_sosi.tstrb;
+  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.tstrb  <= rx_udp_tstrb;
+  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_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_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_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_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_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_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_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_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_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_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_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_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/libraries/eth_tester_200g/src/vhdl/eth_tester_200g_pkg.vhd b/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..bdc161635035a5ff5f76920b983c9c15c2505db1
--- /dev/null
+++ b/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g_pkg.vhd
@@ -0,0 +1,120 @@
+-------------------------------------------------------------------------------
+--
+-- 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_generator 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 eth_tester_200g_pkg is
+  constant c_rdma_generator_nof_octet_generate_100gbe : natural := 64;
+  constant c_rdma_generator_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_generator_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_generator_dp_nof_hdr_fields : natural := 4;
+  constant c_rdma_generator_dp_hdr_field_sel  : std_logic_vector(c_rdma_generator_dp_nof_hdr_fields - 1 downto 0) := "0100";
+
+  constant c_rdma_generator_dp_hdr_field_arr : t_common_field_arr(c_rdma_generator_dp_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_generator_dp_reg_hdr_dat_addr_w    : natural := ceil_log2(field_nof_words(c_rdma_generator_dp_hdr_field_arr, c_word_w));
+  constant c_rdma_generator_dp_reg_hdr_dat_addr_span : natural := 2**c_rdma_generator_dp_reg_hdr_dat_addr_w;
+
+  constant c_rdma_generator_dp_app_hdr_len  : natural :=  12;  -- octets
+
+  -- RoCEv2 header for RDMA write operation (excluding ETH, IP, UDP)
+  -- Base Transport Header (BTH) + RDMA Extended Transport Header (RETH) + Immediate Data
+  constant c_rdma_generator_roce_nof_hdr_fields : natural := 12 + 4 + 13 + 3 + 1;
+  constant c_rdma_generator_roce_hdr_field_sel  : std_logic_vector(c_rdma_generator_roce_nof_hdr_fields - 1 downto 0) :=  "111011111001" & "0100" & "1111111111111" & "111" & "1";
+
+  constant c_rdma_generator_roce_hdr_field_arr : t_common_field_arr(c_rdma_generator_roce_nof_hdr_fields - 1 downto 0) := (
+      ( field_name_pad("ip_version"          ), "RW",  4, field_default(4) ),
+      ( field_name_pad("ip_header_length"    ), "RW",  4, field_default(5) ),
+      ( field_name_pad("ip_services"         ), "RW",  8, field_default(0) ),
+      ( field_name_pad("ip_total_length"     ), "RW", 16, field_default(0) ),  -- depends on BG block size, so set by data path
+      ( field_name_pad("ip_identification"   ), "RW", 16, field_default(0) ),
+      ( field_name_pad("ip_flags"            ), "RW",  3, field_default(2) ),
+      ( field_name_pad("ip_fragment_offset"  ), "RW", 13, field_default(0) ),
+      ( field_name_pad("ip_time_to_live"     ), "RW",  8, field_default(127) ),
+      ( field_name_pad("ip_protocol"         ), "RW",  8, field_default(17) ),
+      ( field_name_pad("ip_header_checksum"  ), "RW", 16, field_default(0) ),
+      ( field_name_pad("ip_src_addr"         ), "RW", 32, field_default(0) ),
+      ( field_name_pad("ip_dst_addr"         ), "RW", 32, field_default(0) ),  -- c_eth_tester_ip_dst_addr
+
+      ( field_name_pad("udp_src_port"        ), "RW", 16, field_default(0) ),
+      ( field_name_pad("udp_dst_port"        ), "RW", 16, field_default(0) ),  -- c_eth_tester_udp_dst_port
+      ( field_name_pad("udp_total_length"    ), "RW", 16, field_default(0) ),  -- depends on BG block size, so set by data path
+      ( field_name_pad("udp_checksum"        ), "RW", 16, field_default(0) ),
+
+      ( field_name_pad("bth_opcode"          ), "RW",  8, field_default(0) ),
+      ( field_name_pad("bth_se"              ), "RW",  1, field_default(0) ),
+      ( field_name_pad("bth_m"               ), "RW",  1, field_default(0) ),
+      ( field_name_pad("bth_pad"             ), "RW",  2, field_default(0) ),
+      ( field_name_pad("bth_tver"            ), "RW",  4, field_default(0) ),
+      ( field_name_pad("bth_partition_key"   ), "RW", 16, field_default(0) ),
+      ( field_name_pad("bth_fres"            ), "RW",  1, field_default(0) ),
+      ( field_name_pad("bth_bres"            ), "RW",  1, field_default(0) ),
+      ( field_name_pad("bth_reserved_a"      ), "RW",  6, field_default(0) ),
+      ( field_name_pad("bth_dest_qp"         ), "RW", 16, field_default(0) ),
+      ( field_name_pad("bth_ack_req"         ), "RW",  1, field_default(0) ),
+      ( field_name_pad("bth_reserved_b"      ), "RW",  7, field_default(0) ),
+      ( field_name_pad("bth_psn"             ), "RW", 32, field_default(0) ),
+
+      ( field_name_pad("reth_virtual_address"), "RW", 64, field_default(0) ),
+      ( field_name_pad("reth_r_key"          ), "RW", 32, field_default(0) ),
+      ( field_name_pad("reth_dma_length"     ), "RW", 32, field_default(0) ),
+
+      ( field_name_pad("immediate_data"      ), "RW", 32, field_default(0) )
+  );
+  constant c_rdma_generator_roce_reg_hdr_dat_addr_w    : natural := ceil_log2(field_nof_words(c_rdma_generator_roce_hdr_field_arr, c_word_w));
+  constant c_rdma_generator_roce_reg_hdr_dat_addr_span : natural := 2**c_rdma_generator_roce_reg_hdr_dat_addr_w;
+
+  constant c_rdma_generator_roce_hdr_len  : natural :=  32;  -- octets
+  constant c_rdma_generator_roce_icrc_len : natural :=  4;   -- octets
+end eth_tester_200g_pkg;
+
+package body eth_tester_200g_pkg is
+end eth_tester_200g_pkg;
diff --git a/applications/rdma_demo/libraries/eth_tester_200g/tb/vhdl/tb_eth_tester_200g.vhd b/applications/rdma_demo/libraries/eth_tester_200g/tb/vhdl/tb_eth_tester_200g.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..eae40bfd2f37ef56750f74de571b0c95608e60f3
--- /dev/null
+++ b/applications/rdma_demo/libraries/eth_tester_200g/tb/vhdl/tb_eth_tester_200g.vhd
@@ -0,0 +1,524 @@
+-------------------------------------------------------------------------------
+--
+-- 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 rdma_generator_roce_tester using high bandwidth generic
+-- configuration, e.g. g_nof_octet_output = 64 and g_nof_octet_generate = 64.
+-- 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, eth_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 eth_lib.eth_pkg.all;
+use eth_lib.eth_tester_pkg.all;
+use eth_lib.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_rdma_generator 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 := 64;  -- maximum = 96 bytes as max dp.data field = 768 bits.
+    g_nof_octet_generate : natural := 64;
+
+    -- 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
+
+    -- for first stream
+    g_bg_ctrl_first      : t_diag_block_gen_integer := ('1', '1', 500, 3, 200, 0, c_diag_bg_mem_max_adr, 0);
+    -- for other streams
+    g_bg_ctrl_others     : t_diag_block_gen_integer := ('1', '1', 300, 3, 10, 0, c_diag_bg_mem_max_adr, 0)
+  );
+  port (
+    tb_end : out std_logic
+  );
+end tb_rdma_generator;
+
+architecture tb of tb_rdma_generator is
+  -- use to distinguish logging from tb instances in tb_tb
+  constant c_tb_str                : string := "tb-" & natural'image(g_tb_index) & " : ";
+
+  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);
+      -- use signed to fit 32 b in INTEGER
+      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);
+      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);
+      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));
+
+      -- 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)));
+
+      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 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;
+        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 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;
+        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.rdma_generator_roce_tester
+  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;