diff --git a/libraries/io/eth/tb/vhdl/tb_eth_tester.vhd b/libraries/io/eth/tb/vhdl/tb_eth_tester.vhd
index cc0ba0bfd548a94b7b6fa3cab5ded54b40fe7209..be8f3a05e8011bb471241862c661e8967943221a 100644
--- a/libraries/io/eth/tb/vhdl/tb_eth_tester.vhd
+++ b/libraries/io/eth/tb/vhdl/tb_eth_tester.vhd
@@ -22,13 +22,16 @@
 -- Description: See detailed design in [1]
 --   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
 -- > run -a
+--
 -- References:
 -- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE
+-- [2] https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Application+header+size+in+Ethernet+packets
 
-LIBRARY IEEE, common_lib, dp_lib, diag_lib;
+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;
@@ -43,13 +46,18 @@ 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_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 IS
   GENERIC (
     g_tb_index         : NATURAL := 0;  -- use to incremental delay logging from tb instances in tb_tb
-    g_tb_str           : STRING := "";  -- use to distinguish logging from tb instances in tb_tb
-    g_nof_streams      : NATURAL := 2;  -- <= c_eth_nof_udp_ports = 4 when g_loopback_tx_rx = 1
-    g_loopback_eth     : BOOLEAN := TRUE;  -- FALSE = sosi loopback, TRUE = eth loopback
+    g_nof_sync         : NATURAL := 93;  -- number of BG sync intervals to set c_run_time
+    g_nof_streams      : NATURAL := 1;  -- <= c_eth_nof_udp_ports = 4 when g_loopback_tx_rx = 1
+    g_loopback_eth     : BOOLEAN := FALSE;  -- FALSE = sosi loopback, TRUE = eth loopback
+    g_eth_sim_level    : NATURAL := 1;  -- when g_loopback_eth = TRUE, then 0 = use tech_tse IP; 1 = use fast sim_tse model
 
     -- t_diag_block_gen_integer =
     --   sl:  enable
@@ -60,47 +68,66 @@ ENTITY tb_eth_tester IS
     --   nat: mem_low_adrs
     --   nat: mem_high_adrs
     --   nat: bsn_init
-    g_bg_ctrl_first    : t_diag_block_gen_integer := ('1', '1', 50, 8, 100, 0, c_diag_bg_mem_max_adr, 0);  -- for first stream
+    --g_bg_ctrl_first    : t_diag_block_gen_integer := ('1', '1', 50, 8, 100, 0, c_diag_bg_mem_max_adr, 0);  -- for first stream
+    --g_bg_ctrl_others   : t_diag_block_gen_integer := ('1', '1', 30, 8, 10, 0, c_diag_bg_mem_max_adr, 0)   -- for other streams
+    g_bg_ctrl_first    : t_diag_block_gen_integer := ('1', '1', 50, 8, 660, 0, c_diag_bg_mem_max_adr, 0);  -- for first stream
     g_bg_ctrl_others   : t_diag_block_gen_integer := ('1', '1', 30, 8, 10, 0, c_diag_bg_mem_max_adr, 0)   -- for other streams
   );
+  PORT (
+    tb_end : OUT STD_LOGIC
+  );
 END tb_eth_tester;
 
 
 ARCHITECTURE tb OF tb_eth_tester IS
-    
+
+  CONSTANT c_tb_str                : STRING := "tb-" & NATURAL'IMAGE(g_tb_index) & " : ";  -- use to distinguish logging from tb instances in tb_tb
   CONSTANT eth_clk_period          : TIME :=  8 ns;  -- 125 MHz
   CONSTANT mm_clk_period           : TIME := 10 ns;  -- 100 MHz
-  CONSTANT st_clk_period           : TIME :=  5 ns;  -- 200 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 := g_bg_ctrl_first.samples_per_packet;
+  CONSTANT c_bg_block_len_others   : NATURAL := g_bg_ctrl_others.samples_per_packet;
+
+  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_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);
 
-  CONSTANT c_bg_slot_len_first     : NATURAL := g_bg_ctrl_first.samples_per_packet + g_bg_ctrl_first.gapsize;
-  CONSTANT c_bg_slot_len_others    : NATURAL := g_bg_ctrl_others.samples_per_packet + g_bg_ctrl_others.gapsize;
+  -- Use REAL to avoid NATURAL overflow in bps calculation
+  CONSTANT c_eth_nof_bps_first     : REAL := REAL(c_eth_packet_len_first * c_octet_w) * REAL(c_nof_st_clk_per_s) / REAL(c_bg_slot_len_first);
+  CONSTANT c_eth_nof_bps_others    : REAL := REAL(c_eth_packet_len_others * c_octet_w) * REAL(c_nof_st_clk_per_s) / REAL(c_bg_slot_len_others);
+  CONSTANT c_eth_nof_bps_total     : REAL := c_eth_nof_bps_first + REAL(g_nof_streams - 1) * c_eth_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_nof_sync              : NATURAL := 3;
-  CONSTANT c_run_time              : NATURAL := c_nof_sync * c_bg_sync_period_max;
+  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        : NATURAL := sel_a_b(g_loopback_eth, 450, 27);
+  CONSTANT c_tx_exp_latency          : NATURAL := 0;
+  CONSTANT c_rx_exp_latency_st       : NATURAL := 27;
+  CONSTANT c_rx_exp_latency_sim_tse  : NATURAL := 165;
+  CONSTANT c_rx_exp_latency_tech_tse : NATURAL := 375;
 
   -- CRC is added by ETH IP. Therefore Tx packet has no CRC yet and Rx
   -- packet length depends on g_loopback_eth = TRUE
-  CONSTANT c_nof_valid_per_packet_first   : NATURAL := g_bg_ctrl_first.samples_per_packet + sel_a_b(g_loopback_eth, 4, 0);
-  CONSTANT c_nof_valid_per_packet_others  : NATURAL := g_bg_ctrl_others.samples_per_packet + sel_a_b(g_loopback_eth, 4, 0);
+  CONSTANT c_nof_valid_per_packet_first   : NATURAL := c_bg_block_len_first + sel_a_b(g_loopback_eth, 4, 0);
+  CONSTANT c_nof_valid_per_packet_others  : NATURAL := c_bg_block_len_others + sel_a_b(g_loopback_eth, 4, 0);
 
   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(g_bg_ctrl_first.samples_per_packet * c_octet_w, c_word_w);
+  CONSTANT c_mon_nof_valid_first_tx  : NATURAL := c_mon_nof_sop_first * ceil_div(c_bg_block_len_first * c_octet_w, c_word_w);
   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(g_bg_ctrl_others.samples_per_packet* c_octet_w, c_word_w);
+  CONSTANT c_mon_nof_valid_others_tx : NATURAL := c_mon_nof_sop_others * ceil_div(c_bg_block_len_others* c_octet_w, c_word_w);
   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
@@ -116,7 +143,7 @@ ARCHITECTURE tb OF tb_eth_tester IS
   SIGNAL st_clk              : STD_LOGIC := '1';
   SIGNAL st_pps              : STD_LOGIC := '0';
   SIGNAL stimuli_end         : STD_LOGIC := '0';
-  SIGNAL tb_end              : STD_LOGIC := '0';
+  SIGNAL i_tb_end            : STD_LOGIC := '0';
 
   SIGNAL eth_clk             : STD_LOGIC := '1';
   SIGNAL eth_txp             : STD_LOGIC;
@@ -125,6 +152,8 @@ ARCHITECTURE tb OF tb_eth_tester IS
   -- Use same bg_ctrl for all 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);
@@ -174,6 +203,12 @@ ARCHITECTURE tb OF tb_eth_tester IS
   SIGNAL reg_eth_copi            : t_mem_copi := c_mem_copi_rst;
   SIGNAL reg_eth_cipo            : t_mem_cipo;
 
+  -- . set up eth when g_eth_sim_level = 0
+  SIGNAL tse_init                : STD_LOGIC := '1';
+  SIGNAL tse_copi                : t_mem_copi := c_mem_copi_rst;
+  SIGNAL tse_cipo                : t_mem_cipo;
+  SIGNAL tse_psc_access          : STD_LOGIC;
+
   -- View in Wave window
   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;
@@ -184,16 +219,18 @@ ARCHITECTURE tb OF tb_eth_tester IS
 
 BEGIN
 
-  eth_clk <= (NOT eth_clk) OR tb_end AFTER eth_clk_period/2;
-  mm_clk <= (NOT mm_clk) OR tb_end AFTER mm_clk_period/2;
-  st_clk <= (NOT st_clk) OR tb_end AFTER st_clk_period/2;
+  tb_end <= i_tb_end;
+
+  eth_clk <= (NOT eth_clk) OR i_tb_end AFTER eth_clk_period/2;
+  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 => c_nof_sync * g_bg_ctrl_others.blocks_per_sync,
-  --                                                 0 => c_nof_sync * g_bg_ctrl_first.blocks_per_sync);
+  --                         (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
@@ -215,21 +252,26 @@ BEGIN
   -- MM control and monitoring
   -----------------------------------------------------------------------------
   p_mm : PROCESS
-    VARIABLE v_offset  : NATURAL;
-    VARIABLE v_port    : NATURAL;
-    VARIABLE v_value   : NATURAL;
+    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);
 
+    proc_common_wait_until_low(mm_clk, tse_init);
+    proc_common_wait_some_cycles(mm_clk, 10);
+
     ---------------------------------------------------------------------------
     -- Rx UDP offload port
     ---------------------------------------------------------------------------
-    v_port := TO_UINT(c_eth_tester_udp_dst_port);
+    v_udp_dst_port := TO_UINT(c_eth_tester_udp_dst_port);
 
     IF g_loopback_eth = TRUE THEN
       -- Set up demux in eth Rx based on destination UDP port
-      v_value := 2**16 + v_port;   -- enable bit 16, udp port number [15:0]
+      v_value := 2**16 + v_udp_dst_port;   -- enable bit 16, udp port number [15:0]
       FOR I IN g_nof_streams-1 DOWNTO 0 LOOP
         proc_mem_mm_bus_wr(0 + I, v_value + I, mm_clk, reg_eth_copi);   -- increment udp_dst_port per stream
       END LOOP;
@@ -239,7 +281,7 @@ BEGIN
       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#6#, v_port + I, mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);
+      proc_mem_mm_bus_wr(v_offset + 16#6#, v_udp_dst_port + I, mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);
       proc_mem_mm_bus_wr(v_offset + 16#9#, 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#17#, 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#18#, TO_UINT(c_eth_tester_eth_dst_mac(47 DOWNTO 32)), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi);
@@ -274,12 +316,36 @@ BEGIN
       -- Disable the other BG
       proc_mem_mm_bus_wr(v_offset + 0, 0, mm_clk, reg_bg_ctrl_copi);
     END LOOP;
-    proc_common_wait_some_cycles(st_clk, sel_a_b(g_loopback_eth, 20, 1) * c_bg_sync_period_max);
+
+    -- 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';
 
-    -- Dealy logging between different tb instances
+    -- 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_eth_nof_bps_first = " & REAL'IMAGE(c_eth_nof_bps_first) & " bps");
+      ELSE
+        print_str(c_tb_str &
+            "ETH bit rate (" & NATURAL'IMAGE(I) & ") :" &
+            " c_eth_nof_bps_others = " & REAL'IMAGE(c_eth_nof_bps_others) & " bps");
+      END IF;
+    END LOOP;
+    IF g_nof_streams > 1 THEN
+        print_str(c_tb_str &
+            "ETH bit rate total :" &
+            " c_eth_nof_bps_total = " & REAL'IMAGE(c_eth_nof_bps_total) & " bps");
+    END IF;
+    ASSERT c_eth_nof_bps_total < 10.0**9 REPORT "Total ETH bitrate must be < 1Gbps." SEVERITY WARNING;
 
     -------------------------------------------------------------------------
     -- Verification: Total counts
@@ -306,40 +372,51 @@ BEGIN
       proc_common_wait_some_cycles(mm_clk, 1);
 
       -- Print logging
-      print_str(g_tb_str &
+      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(g_tb_str &
+      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
-      ASSERT tx_total_count_nof_packet_arr(I) = exp_total_count_nof_packet_arr(I) REPORT g_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 g_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 g_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 g_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;
+      IF c_eth_nof_bps_total < 10.0**9 THEN
+        -- Verify, only log when wrong
+        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 total nof packets count(" & NATURAL'IMAGE(I) &
+            "), Tx count = " & NATURAL'IMAGE(tx_total_count_nof_packet_arr(I)) &
+            " /= " & NATURAL'IMAGE(tx_total_count_nof_packet_arr(I)) &
+            " = Rx count" SEVERITY ERROR;
+       END IF;
     END LOOP;
 
     -------------------------------------------------------------------------
@@ -373,39 +450,61 @@ BEGIN
       proc_common_wait_some_cycles(mm_clk, 1);
 
       -- Print logging
-      print_str(g_tb_str &
+      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(g_tb_str &
+      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)));
 
-      -- Verify, only log when wrong
-      IF I = 0 THEN
-        ASSERT tx_mon_nof_sop_arr(I) = c_mon_nof_sop_first REPORT g_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 g_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 g_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 g_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 g_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 g_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 g_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 g_tb_str & "Wrong rx nof_valid for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+      IF c_eth_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;
+        -- The rx_exp_latency is fixed when:
+        -- . g_loopback_eth = FALSE: the streams operate in parallel.
+        -- . g_loopback_eth = TRUE and g_nof_streams = 1, because for
+        --   g_nof_streams > 1 the streams are mulitplexed, so then the Rx
+        --   latency will vary.
+        IF g_loopback_eth = TRUE THEN
+          IF g_nof_streams = 1 THEN
+            IF g_eth_sim_level = 0 THEN
+              ASSERT almost_equal(rx_mon_latency_arr(I), c_rx_exp_latency_tech_tse, 1) REPORT
+                  c_tb_str & "Wrong rx latency using tech_tse interface" SEVERITY ERROR;
+            ELSIF g_eth_sim_level = 1 THEN
+              ASSERT almost_equal(rx_mon_latency_arr(I), c_rx_exp_latency_sim_tse, 1) REPORT
+                  c_tb_str & "Wrong rx latency using sim_tse interface" SEVERITY ERROR;
+            END IF;
+          END IF;
+        ELSE
+          ASSERT rx_mon_latency_arr(I) = c_rx_exp_latency_st REPORT
+              c_tb_str & "Wrong rx latency using st interface (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
+        END IF;
       END IF;
-      ASSERT tx_mon_latency_arr(I) = c_tx_exp_latency REPORT g_tb_str & "Wrong tx latency for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
-      ASSERT rx_mon_latency_arr(I) = c_rx_exp_latency REPORT g_tb_str & "Wrong rx latency for stream (" & NATURAL'IMAGE(I) & ")" SEVERITY ERROR;
     END LOOP;
 
     -------------------------------------------------------------------------
     -- End of test
     -------------------------------------------------------------------------
     proc_common_wait_some_cycles(mm_clk, 100);
-    tb_end <= '1';
+    i_tb_end <= '1';
     WAIT;
   END PROCESS;
 
@@ -426,6 +525,8 @@ BEGIN
     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,
 
@@ -450,12 +551,15 @@ BEGIN
   );
   
   -- Wire Tx to Rx
-  gen_loopback_sosi : IF g_loopback_eth = FALSE GENERATE
+  gen_loopback_st : IF g_loopback_eth = FALSE GENERATE
+    -- Loop back at streaming sosi level
+
     rx_udp_sosi_arr <= tx_udp_sosi_arr;
+    tse_init <= '0';
   END GENERATE;
 
   gen_loopback_eth : IF g_loopback_eth = TRUE GENERATE
-    eth_rxp <= eth_txp;
+    -- Loop back at ethernet 1Gbps line level
 
     eth_tx_udp_sosi_arr(g_nof_streams-1 DOWNTO 0) <= tx_udp_sosi_arr;
     tx_udp_siso_arr <= eth_tx_udp_siso_arr(g_nof_streams-1 DOWNTO 0);
@@ -463,12 +567,46 @@ BEGIN
     rx_udp_sosi_arr <= eth_rx_udp_sosi_arr(g_nof_streams-1 DOWNTO 0);
     eth_rx_udp_siso_arr(g_nof_streams-1 DOWNTO 0) <= (OTHERS => c_dp_siso_rdy);
 
+    -- Copied from tb_tech_tse.vhd
+    use_sim_tse : IF g_eth_sim_level > 0 GENERATE
+      eth_rxp <= eth_txp;
+      tse_init <= '0';
+    END GENERATE;
+    use_tech_tse : IF g_eth_sim_level = 0 GENERATE
+      eth_rxp <= TRANSPORT eth_txp AFTER 12 ns;  -- apply cable delay
+
+      p_tech_tse_setup : PROCESS
+        -- When c_promis_en = FALSE then only accept broadcast and packets with
+        -- dst_mac for this src_mac, else accept packets for any dst MAC
+        -- Therefore when c_promis_en = FALSE the TSE c_src_mac must be equal
+        -- to the Tx packet dst_mac to be able to receive the Tx packets via
+        -- the tx-rx loopback.
+        CONSTANT c_promis_en : BOOLEAN := FALSE;
+        CONSTANT c_src_mac   : STD_LOGIC_VECTOR(47 DOWNTO 0) := sel_a_b(c_promis_en, c_gn_eth_src_mac, c_eth_tester_eth_dst_mac);
+      BEGIN
+        tse_init <= '1';
+        tse_copi.wr <= '0';
+        tse_copi.rd <= '0';
+
+        proc_common_wait_until_low(mm_clk, mm_rst);
+        proc_common_wait_some_cycles(mm_clk, 10);
+
+        proc_tech_tse_setup(c_tech_select_default,
+                            c_promis_en, c_tech_tse_tx_fifo_depth, c_tech_tse_rx_fifo_depth, c_tech_tse_tx_ready_latency,
+                            c_src_mac, tse_psc_access,
+                            mm_clk, tse_cipo, tse_copi);
+        tse_init <= '0';
+        WAIT;
+      END PROCESS;
+    END GENERATE;
+
+    -- ETH module, see [1]
     u_eth : ENTITY work.eth
     GENERIC MAP (
       g_init_ip_address    => X"0A630000",
       g_cross_clock_domain => TRUE,
       g_sim                => TRUE,
-      g_sim_level          => 1  -- when g_sim = TRUE, then 0 = use IP; 1 = use fast serdes model
+      g_sim_level          => g_eth_sim_level
     )
     PORT MAP (
       -- Clocks and reset
@@ -486,8 +624,8 @@ BEGIN
       udp_rx_src_out_arr => eth_rx_udp_sosi_arr,
 
       -- Memory Mapped Slaves
-      tse_sla_in         => c_mem_copi_rst,  -- ETH TSE MAC registers
-      tse_sla_out        => OPEN,
+      tse_sla_in         => tse_copi,  -- ETH TSE MAC registers
+      tse_sla_out        => tse_cipo,
       reg_sla_in         => reg_eth_copi,  -- ETH control and status registers
       reg_sla_out        => reg_eth_cipo,
       reg_sla_interrupt  => OPEN,            -- Interrupt