diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd
index 0031f7d1593008eadc92c9a16e8f6236321d4b56..9e02d441423fc2b0ee15eabc79ef19ea21c5f21c 100644
--- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd
+++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd
@@ -33,7 +33,7 @@
 -- .
 -------------------------------------------------------------------------------
 
-LIBRARY IEEE, common_lib, dp_lib;
+LIBRARY IEEE, common_lib, dp_lib, ring_lib;
 USE IEEE.STD_LOGIC_1164.ALL;
 USE common_lib.common_pkg.ALL;
 USE common_lib.common_mem_pkg.ALL;
@@ -43,6 +43,7 @@ USE common_lib.common_network_layers_pkg.ALL;
 USE common_lib.common_field_pkg.ALL;
 USE common_lib.common_str_pkg.ALL;
 USE dp_lib.dp_stream_pkg.ALL;
+USE ring_lib.ring_pkg.ALL;
 USE work.sdp_pkg.ALL;
 USE work.tb_sdp_pkg.ALL;
 
@@ -50,19 +51,27 @@ USE work.tb_sdp_pkg.ALL;
 ENTITY tb_sdp_statistics_offload IS
   GENERIC (
     g_statistics_type          : STRING := "XST";
-    g_offload_time             : NATURAL := 500;
-    g_beamset_id               : NATURAL := 0;
-    g_P_sq                     : NATURAL := 1 --c_sdp_P_sq
+    g_offload_time             : NATURAL := 50;
+    g_beamset_id               : NATURAL := 1;  -- < c_sdp_N_beamsets
+    g_gn_index                 : NATURAL := 5;  -- global node (GN) index, must be in range(O_rn, O_rn + N_rn), use > 0 to see effect of g_offload_time
+    g_O_rn                     : NATURAL := 4;  -- GN index of first ring node (RN)
+    g_N_rn                     : NATURAL := 8;  -- <= c_sdp_N_rn_max = 16, number of nodes in ring
+    g_P_sq                     : NATURAL := 9;  -- <= c_sdp_P_sq
+    g_nof_crosslets            : NATURAL := 1;  -- <= c_sdp_N_crosslets_max
+    g_crosslets_direction      : INTEGER := 1   -- +1 or -1
   );
 END tb_sdp_statistics_offload;
 
 ARCHITECTURE tb OF tb_sdp_statistics_offload IS
+
   CONSTANT c_dp_clk_period : TIME := 5 ns;     -- 200 MHz
-  CONSTANT c_mm_clk_period : TIME := 20 ns;    -- 50 MHz
+  CONSTANT c_mm_clk_period : TIME := 1 ns;     -- 1 GHz to speed up simulation
 
   CONSTANT c_cross_clock_domain_latency : NATURAL := 20;
 
-  -- In this tb simply use fixed src addresses
+  CONSTANT c_offload_time              : NATURAL := g_offload_time * g_gn_index;
+
+  -- In this tb simply use fixed network src addresses
   CONSTANT c_eth_src_mac  : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0) := x"123456789ABC";
   CONSTANT c_ip_src_addr  : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := x"0A090807";
   CONSTANT c_udp_src_port : STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0) := x"D001";
@@ -76,23 +85,26 @@ ARCHITECTURE tb OF tb_sdp_statistics_offload IS
   CONSTANT c_ip_total_length           : NATURAL := func_sdp_get_stat_ip_total_length(g_statistics_type);
   CONSTANT c_marker                    : NATURAL := func_sdp_get_stat_marker(g_statistics_type);
   CONSTANT c_nof_signal_inputs         : NATURAL := func_sdp_get_stat_nof_signal_inputs(g_statistics_type);
-  CONSTANT c_nof_packets               : NATURAL := func_sdp_get_stat_nof_packets(g_statistics_type, c_sdp_S_pn, g_P_sq);
+  CONSTANT c_nof_packets_max           : NATURAL := func_sdp_get_stat_nof_packets(g_statistics_type, c_sdp_S_pn, g_P_sq, c_sdp_N_crosslets_max);
 
-  CONSTANT c_beamlet_id                : NATURAL := g_beamset_id * c_sdp_S_sub_bf;
+  CONSTANT c_beamlet_index             : NATURAL := g_beamset_id * c_sdp_S_sub_bf;
+
+  CONSTANT c_crosslets_info_rec        : t_sdp_crosslets_info := (offset_arr => (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), step => 16);
+  CONSTANT c_crosslets_info_slv        : STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0) := func_construct_crosslets_info(c_crosslets_info_rec);
 
   -- payload data
-  CONSTANT c_data_size : NATURAL := 2;
+  CONSTANT c_data_size : NATURAL := c_sdp_W_statistic_sz;
   CONSTANT c_nof_data  : NATURAL := c_nof_statistics_per_packet;
 
-  -- Define SST RAM size for c_nof_packets.
-  CONSTANT c_ram_size  : NATURAL := c_nof_data * c_data_size * c_nof_packets;
+  -- Define SST RAM size for c_nof_packets_max.
+  CONSTANT c_ram_size  : NATURAL := c_nof_data * c_data_size * c_nof_packets_max;
   CONSTANT c_ram_w     : NATURAL := ceil_log2(c_ram_size);
   --CONSTANT c_ram_buf   : t_c_mem := (c_mem_ram_rd_latency, c_ram_w,  32, 2**c_ram_w, 'X');
   CONSTANT c_ram_buf   : t_c_mem := (1, c_ram_w,  32, 2**c_ram_w, 'X');
 
   -- Define block timing.
   CONSTANT c_bsn_init            : NATURAL := 0;
-  CONSTANT c_nof_block_per_sync  : NATURAL := 80;  -- Sufficient to fit more than c_nof_packets offload packets per sync interval.
+  CONSTANT c_nof_block_per_sync  : NATURAL := 3 + ceil_div(c_offload_time, c_nof_data) + c_nof_packets_max;  -- Sufficient to fit more than c_nof_packets_max offload packets per sync interval.
   CONSTANT c_nof_clk_per_block   : NATURAL := c_nof_data * c_data_size;
   CONSTANT c_nof_valid_per_block : NATURAL := c_nof_data * c_data_size;
   CONSTANT c_nof_sync            : NATURAL := 5;
@@ -118,52 +130,85 @@ ARCHITECTURE tb OF tb_sdp_statistics_offload IS
   SIGNAL offload_rx_hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst;
   SIGNAL offload_rx_hdr_dat_miso : t_mem_miso;
 
-  SIGNAL in_sosi             : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL in_sosi              : t_dp_sosi := c_dp_sosi_rst;
+
+  SIGNAL offload_data         : STD_LOGIC_VECTOR(31 DOWNTO 0);
+  SIGNAL offload_sosi         : t_dp_sosi;
+  SIGNAL offload_siso         : t_dp_siso := c_dp_siso_rst;
 
-  SIGNAL offload_data        : STD_LOGIC_VECTOR(31 DOWNTO 0);
-  SIGNAL offload_sosi        : t_dp_sosi;
-  SIGNAL offload_siso        : t_dp_siso := c_dp_siso_rst;
+  SIGNAL test_offload_sosi    : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL test_offload_en      : STD_LOGIC := '0';
+  SIGNAL test_offload_sop_cnt : NATURAL;
+  SIGNAL test_offload_eop_cnt : NATURAL;
 
-  SIGNAL test_offload_sosi   : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL rx_hdr_fields_out    : STD_LOGIC_VECTOR(1023 DOWNTO 0);
+  SIGNAL rx_hdr_fields_raw    : STD_LOGIC_VECTOR(1023 DOWNTO 0) := (OTHERS => '0');
+  SIGNAL rx_sdp_stat_header   : t_sdp_stat_header;
+  SIGNAL exp_sdp_stat_header  : t_sdp_stat_header;
 
-  SIGNAL rx_hdr_fields_out   : STD_LOGIC_VECTOR(1023 DOWNTO 0);
-  SIGNAL rx_hdr_fields_raw   : STD_LOGIC_VECTOR(1023 DOWNTO 0) := (OTHERS => '0');
-  SIGNAL rx_sdp_stat_header  : t_sdp_stat_header;
-  SIGNAL exp_sdp_stat_header : t_sdp_stat_header;
-  SIGNAL exp_bsn             : STD_LOGIC_VECTOR(63 DOWNTO 0);
+  SIGNAL exp_dp_bsn              : STD_LOGIC_VECTOR(63 DOWNTO 0);
+  SIGNAL exp_sst_signal_input     : NATURAL;
+  SIGNAL exp_bst_beamlet_index    : NATURAL;
+  SIGNAL cur_X_sq_cell        : NATURAL;
+  SIGNAL cur_crosslet         : NATURAL;
+  SIGNAL exp_subband_index    : NATURAL;
+  SIGNAL exp_xst_signal_input_A   : NATURAL;
+  SIGNAL exp_xst_signal_input_B   : NATURAL;
 
   -- Signals used to change settings of sdp_info. 
-  SIGNAL gn_index  : NATURAL := 1;  -- select > 0 to see effect of g_offload_time 
-  
   SIGNAL sdp_info  :  t_sdp_info := (
                         TO_UVEC(601, 16),   -- station_id
                         '0',                -- antenna_band_index
-                        x"00001111",        -- observation_id  
-                        b"01",              -- nyquist_zone_index
-                        '0',                -- f_adc  
-                        '1',                -- fsub_type
+                        x"FFFFFFFF",        -- observation_id
+                        b"01",              -- nyquist_zone_index, 0 = first, 1 = second, 2 = third
+                        '1',                -- f_adc, 0 = 160 MHz, 1 = 200 MHz
+                        '0',                -- fsub_type, 0 = critically sampled, 1 = oversampled
                         '0',                -- beam_repositioning_flag
-                        x"01",              -- O_si
-                        x"02",              -- N_si
-                        x"04",              -- O_rn
-                        x"08",              -- N_rn
+                        x"01",              -- O_si, not used
+                        x"02",              -- N_si, not used
+                        TO_UVEC(g_O_rn, 8), -- O_rn
+                        TO_UVEC(g_N_rn, 8), -- N_rn
                         x"1400"             -- block_period = 5120
                       );
 
+  SIGNAL gn_index  : NATURAL := g_gn_index;           -- this node GN
+  SIGNAL rn_index  : NATURAL := g_gn_index - g_O_rn;  -- this node RN
+  SIGNAL source_rn : NATURAL;  -- source node RN
+  SIGNAL source_gn : NATURAL;  -- source node GN
+
   SIGNAL subband_calibrated_flag : STD_LOGIC := '0';
+  SIGNAL nof_crosslets           : STD_LOGIC_VECTOR(c_sdp_nof_crosslets_reg_w-1 DOWNTO 0) := (OTHERS => '0');
+  SIGNAL nof_packets             : NATURAL;
 
   -- Signals used for starting processes.
-  SIGNAL ram_wr_data   : STD_LOGIC_VECTOR(c_ram_buf.dat_w-1 DOWNTO 0);
-  SIGNAL ram_wr_addr   : STD_LOGIC_VECTOR(c_ram_buf.adr_w-1 DOWNTO 0);
-  SIGNAL ram_wr_en     : STD_LOGIC;
-  SIGNAL init_ram_done : STD_LOGIC := '0';
+  SIGNAL ram_wr_data      : STD_LOGIC_VECTOR(c_ram_buf.dat_w-1 DOWNTO 0);
+  SIGNAL ram_wr_addr      : STD_LOGIC_VECTOR(c_ram_buf.adr_w-1 DOWNTO 0);
+  SIGNAL ram_wr_en        : STD_LOGIC;
+  SIGNAL init_ram_done    : STD_LOGIC := '0';
 
-  SIGNAL in_sync_cnt      : NATURAL := 0;
   SIGNAL in_sync_hold     : STD_LOGIC := '0';
-  SIGNAL rx_block_cnt     : NATURAL := 0;
-  SIGNAL rx_valid_clk_cnt : NATURAL := 0;
+  SIGNAL in_sync_cnt      : NATURAL := 0;
+  SIGNAL test_sync_cnt    : INTEGER;
+
+  SIGNAL rx_packet_cnt    : NATURAL := 0;
+  SIGNAL rx_valid_cnt     : NATURAL := 0;
+
+  -- Debug signals, to view in Wave window
+  SIGNAL dbg_c_nof_statistics_per_packet : NATURAL := c_nof_statistics_per_packet;
+  SIGNAL dbg_c_udp_total_length          : NATURAL := c_udp_total_length;
+  SIGNAL dbg_c_ip_total_length           : NATURAL := c_ip_total_length;
+  SIGNAL dbg_c_marker                    : NATURAL := c_marker;
+  SIGNAL dbg_c_nof_signal_inputs         : NATURAL := c_nof_signal_inputs;
+  SIGNAL dbg_c_nof_packets_max           : NATURAL := c_nof_packets_max;
+  SIGNAL dbg_c_beamlet_index             : NATURAL := c_beamlet_index;
+  SIGNAL dbg_c_data_size                 : NATURAL := c_data_size;
+  SIGNAL dbg_c_nof_data                  : NATURAL := c_nof_data;
+  SIGNAL dbg_c_ram_size                  : NATURAL := c_ram_size;
+  SIGNAL dbg_c_crosslets_info_rec        : t_sdp_crosslets_info := c_crosslets_info_rec;
+  SIGNAL dbg_c_crosslets_info_slv        : STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0) := c_crosslets_info_slv;
 
 BEGIN
+
   dp_rst <= '1', '0' AFTER c_dp_clk_period*7;
   dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2;
   
@@ -186,24 +231,15 @@ BEGIN
     END LOOP;
     ram_wr_en <= '0';
 
-    proc_common_wait_until_high(dp_clk, in_sosi.sync);
     init_ram_done <= '1';
     WAIT;
   END PROCESS;
 
-  p_enable_trigger : PROCESS
-  BEGIN
-    proc_common_wait_until_high(mm_clk, init_ram_done);
-    -- Enable common variabel delay.
-    proc_mem_mm_bus_wr(c_reg_enable_mm_addr_enable, 1, mm_clk, enable_miso, enable_mosi);
-    proc_common_wait_some_cycles(mm_clk, c_cross_clock_domain_latency);
-    WAIT;
-  END PROCESS;
-
+  -- Start the input
   p_in_sosi : PROCESS
   BEGIN
     proc_common_wait_until_low(dp_clk, dp_rst);
-    proc_common_wait_some_cycles(dp_clk, 12);
+    proc_common_wait_some_cycles(dp_clk, 10);
     in_sosi.bsn <= TO_DP_BSN(c_bsn_init);
     in_sosi.valid <= '1';
     WHILE TRUE LOOP
@@ -229,7 +265,79 @@ BEGIN
     WAIT;
   END PROCESS;
 
-  p_exp_sdp_stat_header : PROCESS(sdp_info, subband_calibrated_flag, gn_index, rx_block_cnt, exp_bsn)
+  -- Enable the statistics offload when input is running
+  p_enable_trigger : PROCESS
+  BEGIN
+    proc_common_wait_until_high(mm_clk, init_ram_done);
+    proc_common_wait_until_high(dp_clk, in_sosi.sync);
+    -- Enable common variabel delay.
+    proc_mem_mm_bus_wr(c_reg_enable_mm_addr_enable, 1, mm_clk, enable_miso, enable_mosi);
+    proc_common_wait_some_cycles(mm_clk, c_cross_clock_domain_latency);
+    proc_common_wait_some_cycles(dp_clk, 1);
+    test_offload_en <= '1';
+    WAIT;
+  END PROCESS;
+
+  -- Crosslets settings
+  nof_crosslets <= TO_UVEC(g_nof_crosslets, c_sdp_nof_crosslets_reg_w);
+  nof_packets   <= func_sdp_get_stat_nof_packets(g_statistics_type, c_sdp_S_pn, g_P_sq, g_nof_crosslets);
+
+  -- Counters to time expected exp_sdp_stat_header fields per offload packet
+  p_exp_counters : PROCESS(dp_clk)
+  BEGIN
+    IF rising_edge(dp_clk) THEN
+      -- Count sync intervals using in_sosi.sync, because there is no test_offload_sosi.sync
+      IF test_offload_en = '0' THEN
+        in_sync_cnt <= 0;
+        test_offload_sop_cnt <= 0;
+        test_offload_eop_cnt <= 0;
+      ELSE
+        -- Count test_offload_sosi sync integration intervals
+        IF in_sosi.sync = '1' THEN
+          in_sync_cnt <= in_sync_cnt + 1;
+        END IF;
+
+        -- Count test_offload_sosi packets
+        IF test_offload_sosi.sop = '1' THEN
+          test_offload_sop_cnt <= test_offload_sop_cnt + 1;  -- early count
+        END IF;
+        IF test_offload_sosi.eop = '1' THEN
+          test_offload_eop_cnt <= test_offload_eop_cnt + 1;  -- after count
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+  test_sync_cnt <= in_sync_cnt + 1;  -- optionally adjust to fit test_offload_sosi
+
+  -- derive current X_sq correlator cell index
+  cur_X_sq_cell <= (test_offload_eop_cnt / g_nof_crosslets) MOD g_P_sq;
+  -- derive current N_crosslets index index
+  cur_crosslet <= test_offload_eop_cnt MOD g_nof_crosslets;
+
+  -- derive source RN index
+  source_rn <= func_nof_hops_to_source_rn(cur_X_sq_cell, rn_index, g_N_rn, g_crosslets_direction);
+  source_gn <= g_O_rn + source_rn;
+
+  -- Prepare exp_sdp_stat_header before test_offload_sosi.eop, so that p_exp_sdp_stat_header can
+  -- verify it at test_offload_sosi.eop.
+
+  -- For all statistics
+  exp_dp_bsn <= TO_SVEC(c_bsn_init + 1 + test_sync_cnt * c_nof_block_per_sync, 64);
+  -- SST
+  exp_sst_signal_input <= rx_packet_cnt + c_sdp_S_pn * gn_index;
+  -- BST
+  exp_bst_beamlet_index <= c_beamlet_index;
+  -- XST
+  -- . prepare expected XST subband_index
+  exp_subband_index <= (c_crosslets_info_rec.offset_arr(cur_crosslet) + test_sync_cnt * c_crosslets_info_rec.step) MOD c_sdp_N_sub;
+
+  -- . prepare expected XST signal_input_A index
+  exp_xst_signal_input_A <= (gn_index MOD c_sdp_N_pn_max) * c_sdp_S_pn;
+
+  -- . prepare expected XST signal_input_B index, assume crosslet transport in positive direction
+  exp_xst_signal_input_B <= (source_gn MOD c_sdp_N_pn_max) * c_sdp_S_pn;
+
+  p_exp_sdp_stat_header : PROCESS(sdp_info, subband_calibrated_flag, gn_index, exp_dp_bsn, exp_sst_signal_input, exp_subband_index, exp_xst_signal_input_A, exp_xst_signal_input_B)
   BEGIN
     -- eth header
     exp_sdp_stat_header.eth.dst_mac        <= c_sdp_stat_eth_dst_mac;
@@ -275,23 +383,23 @@ BEGIN
     exp_sdp_stat_header.app.sdp_reserved                            <= TO_UVEC(                   0,  8);
     exp_sdp_stat_header.app.sdp_integration_interval                <= TO_UVEC(c_nof_block_per_sync, 24);
     IF g_statistics_type = "SST" THEN
-      exp_sdp_stat_header.app.sdp_data_id                           <= TO_UVEC(rx_block_cnt + c_sdp_S_pn * gn_index, 32);
-      exp_sdp_stat_header.app.sdp_data_id_sst_signal_input_index    <= TO_UVEC(rx_block_cnt + c_sdp_S_pn * gn_index,  8);
+      exp_sdp_stat_header.app.sdp_data_id                           <= TO_UVEC(exp_sst_signal_input, 32);
+      exp_sdp_stat_header.app.sdp_data_id_sst_signal_input_index    <= TO_UVEC(exp_sst_signal_input,  8);
     ELSIF g_statistics_type = "BST" THEN
-      exp_sdp_stat_header.app.sdp_data_id                           <= TO_UVEC(c_beamlet_id, 32);
-      exp_sdp_stat_header.app.sdp_data_id_bst_beamlet_index         <= TO_UVEC(c_beamlet_id, 16);
+      exp_sdp_stat_header.app.sdp_data_id                           <= TO_UVEC(c_beamlet_index, 32);
+      exp_sdp_stat_header.app.sdp_data_id_bst_beamlet_index         <= TO_UVEC(c_beamlet_index, 16);
     ELSIF g_statistics_type = "XST" THEN
-      exp_sdp_stat_header.app.sdp_data_id                           <= TO_UVEC(0, 7) & TO_UVEC(0, 9) & TO_UVEC(0, 8) & TO_UVEC(0, 8);  -- TODO
-      exp_sdp_stat_header.app.sdp_data_id_xst_subband_index         <= TO_UVEC(0, 9);  -- TODO
-      exp_sdp_stat_header.app.sdp_data_id_xst_signal_input_A_index  <= TO_UVEC(0, 8);  -- TODO
-      exp_sdp_stat_header.app.sdp_data_id_xst_signal_input_B_index  <= TO_UVEC(0, 8);  -- TODO
+      exp_sdp_stat_header.app.sdp_data_id                           <= TO_UVEC(0, 7) & TO_UVEC(exp_subband_index, 9) & TO_UVEC(exp_xst_signal_input_A, 8) & TO_UVEC(exp_xst_signal_input_B, 8);
+      exp_sdp_stat_header.app.sdp_data_id_xst_subband_index         <= TO_UVEC(exp_subband_index, 9);
+      exp_sdp_stat_header.app.sdp_data_id_xst_signal_input_A_index  <= TO_UVEC(exp_xst_signal_input_A, 8);
+      exp_sdp_stat_header.app.sdp_data_id_xst_signal_input_B_index  <= TO_UVEC(exp_xst_signal_input_B, 8);
     END IF;
-    exp_sdp_stat_header.app.sdp_nof_signal_inputs                   <= TO_UVEC(        c_nof_signal_inputs,  8);
-    exp_sdp_stat_header.app.sdp_nof_bytes_per_statistics            <= TO_UVEC(                          8,  8);
-    exp_sdp_stat_header.app.sdp_nof_statistics_per_packet           <= TO_UVEC(c_nof_statistics_per_packet, 16);
+    exp_sdp_stat_header.app.sdp_nof_signal_inputs                   <= TO_UVEC(          c_nof_signal_inputs,  8);
+    exp_sdp_stat_header.app.sdp_nof_bytes_per_statistic             <= TO_UVEC(c_sdp_nof_bytes_per_statistic,  8);
+    exp_sdp_stat_header.app.sdp_nof_statistics_per_packet           <= TO_UVEC(  c_nof_statistics_per_packet, 16);
     exp_sdp_stat_header.app.sdp_block_period                        <= sdp_info.block_period;
 
-    exp_sdp_stat_header.app.dp_bsn <= exp_bsn;
+    exp_sdp_stat_header.app.dp_bsn <= exp_dp_bsn;
   END PROCESS;
 
   rx_sdp_stat_header <= func_sdp_extract_stat_header(rx_hdr_fields_raw);
@@ -299,26 +407,24 @@ BEGIN
   p_verify_header : PROCESS(test_offload_sosi)
     VARIABLE v_bool : BOOLEAN;
   BEGIN
+    -- Prepare exp_sdp_stat_header before test_offload_sosi.eop, so that it can be verified at test_offload_sosi.eop
     IF test_offload_sosi.eop = '1' THEN
-      -- bsn is not fully received (bit 0-15 is missing) because 32 bit allignment not working in dp_offload_rx.vhd.
-
       v_bool := func_sdp_verify_stat_header(g_statistics_type, rx_sdp_stat_header, exp_sdp_stat_header, sdp_info);
-
     END IF;
   END PROCESS;
 
-  -- Count number of blocks in a sync interval.
+  -- Count number of packets in a sync interval.
   -- There is no active test_offload_sosi.sync to restart the count. Therefore capture the in_sosi.sync in in_sync_hold, and
-  -- use in_sync_hold with test_offload_sosi.sop to start counting blocks (packets) from 0, at the start of every sync interval.
-  p_rx_block_cnt : PROCESS(dp_clk)
+  -- use in_sync_hold with test_offload_sosi.sop to start counting packets from 0, at the start of every sync interval.
+  p_rx_packet_cnt : PROCESS(dp_clk)
   BEGIN
     IF rising_edge(dp_clk) THEN
       IF test_offload_sosi.sop = '1' THEN
         IF in_sync_hold = '1' THEN
-          rx_block_cnt <= 0;
           in_sync_hold <= '0';
+          rx_packet_cnt <= 0;
         ELSE
-          rx_block_cnt <= rx_block_cnt + 1;
+          rx_packet_cnt <= rx_packet_cnt + 1;
         END IF;
       END IF;
       IF in_sosi.sync = '1' THEN
@@ -327,40 +433,29 @@ BEGIN
     END IF;
   END PROCESS;
 
-  -- Count number of sync intervals, to determine expected statistics bsn
-  p_rx_sync_cnt : PROCESS(dp_clk)
-  BEGIN
-    IF rising_edge(dp_clk) THEN
-      IF in_sosi.sync = '1' THEN
-        in_sync_cnt <= in_sync_cnt + 1;
-      END IF;
-    END IF;
-  END PROCESS;
-  exp_bsn <= TO_SVEC(c_bsn_init + 1 + (in_sync_cnt - 1) * c_nof_block_per_sync, 64);
-
-  -- Verify number of blocks between 2 syncs and between 2 changed bsn numbers.
-  p_verify_nof_blocks : PROCESS(dp_clk)
+  -- Verify number of packets per sync interval
+  p_verify_nof_packets : PROCESS(dp_clk)
   BEGIN
     IF rising_edge(dp_clk) THEN
       IF init_ram_done = '1' THEN
 
-        IF in_sosi.sync = '1' AND rx_block_cnt > 0 THEN
-          ASSERT rx_block_cnt = c_nof_packets-1 REPORT "wrong number of blocks between 2 sync" SEVERITY ERROR;
+        IF in_sosi.sync = '1' AND rx_packet_cnt > 0 THEN
+          ASSERT rx_packet_cnt = nof_packets-1 REPORT "Wrong number of packets per sync interval" SEVERITY ERROR;
         END IF;
 
       END IF;
     END IF;
   END PROCESS;
 
-  p_verify_nof_valid : PROCESS(dp_clk)
+  p_verify_nof_valid_per_packet : PROCESS(dp_clk)
   BEGIN
     IF rising_edge(dp_clk) THEN
       IF test_offload_sosi.sop = '1' THEN
-        rx_valid_clk_cnt <= 1;
+        rx_valid_cnt <= 1;
       ELSIF test_offload_sosi.eop = '1' THEN
-        ASSERT rx_valid_clk_cnt+1 = c_nof_valid_per_block REPORT "wrong number of clock counts while valid" SEVERITY ERROR;
+        ASSERT rx_valid_cnt+1 = c_nof_valid_per_block REPORT "Wrong number of valid per packet" SEVERITY ERROR;
       ELSE
-        rx_valid_clk_cnt <= rx_valid_clk_cnt + 1;
+        rx_valid_cnt <= rx_valid_cnt + 1;  -- test_offload_sosi.valid has no gaps
       END IF;
     END IF;
   END PROCESS;
@@ -430,34 +525,43 @@ BEGIN
     g_P_sq            => g_P_sq
   )
   PORT MAP (
-    mm_clk    => mm_clk,
-    mm_rst    => mm_rst,
+    mm_clk => mm_clk,
+    mm_rst => mm_rst,
 
-    dp_clk    => dp_clk,
-    dp_rst    => dp_rst,
+    dp_clk => dp_clk,
+    dp_rst => dp_rst,
 
-    master_mosi => master_mosi,
-    master_miso => master_miso,
+    -- MM
+    master_mosi      => master_mosi,
+    master_miso      => master_miso,
 
     reg_enable_mosi  => enable_mosi,
     reg_enable_miso  => enable_miso,
 
-    reg_hdr_dat_mosi  => hdr_dat_mosi,
-    reg_hdr_dat_miso  => hdr_dat_miso,
+    reg_hdr_dat_mosi => hdr_dat_mosi,
+    reg_hdr_dat_miso => hdr_dat_miso,
 
-    sdp_info                => sdp_info,
-    subband_calibrated_flag => subband_calibrated_flag,
-    gn_index                => gn_index,
+    -- ST
+    in_sosi          => in_sosi,
+    out_sosi         => offload_sosi,
+    out_siso         => offload_siso,
+
+    -- Inputs from other blocks
+    eth_src_mac             => c_eth_src_mac,
+    udp_src_port            => c_udp_src_port,
+    ip_src_addr             => c_ip_src_addr,
 
-    in_sosi   => in_sosi,
-    out_sosi  => offload_sosi,
-    out_siso  => offload_siso,
+    gn_index                => gn_index,
 
-    eth_src_mac  => c_eth_src_mac,
-    udp_src_port => c_udp_src_port,
-    ip_src_addr  => c_ip_src_addr
+    sdp_info                => sdp_info,
+    subband_calibrated_flag => subband_calibrated_flag,
+    nof_crosslets           => nof_crosslets,
+    crosslets_info          => c_crosslets_info_slv
   );
 
+  -- Check crosslet_info functions
+  ASSERT c_crosslets_info_rec = func_extract_crosslets_info(c_crosslets_info_slv) REPORT "Error in func_extract_crosslets_info() or func_construct_crosslets_info()" SEVERITY FAILURE;
+
   -- To view the 32 bit 1GbE offload data more easily in the Wave window
   offload_data <= offload_sosi.data(31 DOWNTO 0);
 
diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_tb_sdp_statistics_offload.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_tb_sdp_statistics_offload.vhd
index e0506591d517a9df01f03904a3c1bec1c98a1c28..c7e03d9ef4b5972d91a444d63918abe5d3a675e3 100644
--- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_tb_sdp_statistics_offload.vhd
+++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_tb_sdp_statistics_offload.vhd
@@ -40,12 +40,19 @@ BEGIN
 --    g_statistics_type          : STRING := "SST";
 --    g_offload_time             : NATURAL := 500;
 --    g_beamset_id               : NATURAL := 0;
+--    g_gn_index                 : NATURAL := 1;  -- global node (GN) index, use > 0 to see effect of g_offload_time
+--    g_O_rn                     : NATURAL := 0;  -- GN index of first ring node (RN)
+--    g_N_rn                     : NATURAL := 16; -- <= c_sdp_N_rn_max = 16, number of nodes in ring
 --    g_P_sq                     : NATURAL := c_sdp_P_sq
+--    g_nof_crosslets            : NATURAL := 1;
+--    g_crosslets_direction      : INTEGER := 1;  -- +1 or -1
+
+  u_sst         : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("SST", 50);
+  u_bst_0       : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("BST", 50, 0);
+  u_bst_1       : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("BST", 50, 1);
+  u_xst_P1      : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("XST", 50, 0,  1, 0, 16,  1, 1, 1);
+  u_xst_P1_nof3 : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("XST", 50, 0,  1, 0, 16,  1, 3, 1);
+  u_xst_P9      : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("XST", 50, 0,  1, 0, 16,  9, 1, 1);
+  u_xst_P9_nof3 : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("XST", 50, 0,  1, 0, 16,  9, 3, 1);
 
-  u_sst      : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("SST");
-  u_bst_0    : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("BST");
-  u_bst_1    : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("BST", 500, 1);
-  u_xst_1    : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("XST", 500, 0, 1);
-  u_xst_P_sq : ENTITY work.tb_sdp_statistics_offload GENERIC MAP("XST");
-  
 END tb;