diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_one/lofar2_unb2c_sdp_station_tbuf_one_pins.tcl b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_one/lofar2_unb2c_sdp_station_tbuf_one_pins.tcl
index 74212380009a0fd332a68ef3a8cfedb08825778c..067487f8e0318c90114e5c03a2d285821449ef32 100644
--- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_one/lofar2_unb2c_sdp_station_tbuf_one_pins.tcl
+++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_one/lofar2_unb2c_sdp_station_tbuf_one_pins.tcl
@@ -19,6 +19,7 @@
 ###############################################################################
 source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_pins.tcl
 source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_jesd_pins.tcl
+source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_beamlets_pins.tcl
 source $::env(HDL_WORK)/boards/uniboard2c/libraries/unb2c_board/quartus/pinning/unb2c_ddr_16G_64b_I_pins.tcl
 
 
diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/hdllib.cfg b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..0a6640453eb6f515a9909b3bbeeeedb036dc7a07
--- /dev/null
+++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/hdllib.cfg
@@ -0,0 +1,48 @@
+hdl_lib_name = lofar2_unb2c_sdp_station_tbuf_ring
+hdl_library_clause_name = lofar2_unb2c_sdp_station_tbuf_ring_lib
+hdl_lib_uses_synth = common dp mm unb2c_board tech_ddr lofar2_unb2c_sdp_station
+hdl_lib_uses_sim =
+hdl_lib_technology = ip_arria10_e2sg
+hdl_lib_include_ip =
+
+synth_files =
+    lofar2_unb2c_sdp_station_tbuf_ring.vhd
+
+test_bench_files =
+    tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd
+    tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd
+
+regression_test_vhdl =
+    tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd
+
+[modelsim_project_file]
+modelsim_copy_files =
+    ../../src/data data
+
+modelsim_compile_ip_files =
+    # Unb2c 16GB-64b DDR4 driver
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_16g_1600/ddr4_16g_1600_64b/copy_hex_files.tcl
+
+[quartus_project_file]
+synth_top_level_entity =
+
+quartus_copy_files =
+    ../../quartus .
+    ../../src/data data
+
+quartus_qsf_files =
+    $HDL_WORK/boards/uniboard2c/libraries/unb2c_board/quartus/unb2c_board.qsf
+
+quartus_sdc_files =
+    ../../quartus/lofar2_unb2c_sdp_station.sdc
+
+quartus_tcl_files =
+    lofar2_unb2c_sdp_station_tbuf_ring_pins.tcl
+    ../../quartus/lofar2_unb2c_sdp_station_ip.tcl
+
+quartus_vhdl_files =
+
+quartus_qip_files =
+    $HDL_BUILD_DIR/unb2c/quartus/lofar2_unb2c_sdp_station_tbuf_ring/qsys_lofar2_unb2c_sdp_station/qsys_lofar2_unb2c_sdp_station.qip
+
+nios2_app_userflags = -DCOMPILE_FOR_GEN2_UNB2
diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..539414d25ab17dd6867e89c32a44458d39dc67da
--- /dev/null
+++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring.vhd
@@ -0,0 +1,176 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2024
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-- Author : E. Kooistra
+-- Purpose:
+--   Wrapper for synthesis of Lofar2 SDP Station tbuf_ring design. The wrapper
+--   maps the unb2c BCK pin names to the JESD204B signal names.
+-- Description:
+--   Contains SDPFW for unb2c with complete AIT input stage with 12 ADC
+--   streams and TBuf for 16GB DDR4 with 64 DQ in slot I.
+
+library IEEE, common_lib, dp_lib, unb2c_board_lib, tech_ddr_lib, lofar2_unb2c_sdp_station_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 unb2c_board_lib.unb2c_board_pkg.all;
+  use tech_ddr_lib.tech_ddr_pkg.all;
+  use dp_lib.dp_stream_pkg.all;
+
+entity lofar2_unb2c_sdp_station_tbuf_ring is
+  generic (
+    g_stamp_date  : natural := 0;  -- Date (YYYYMMDD) -- set by QSF
+    g_stamp_time  : natural := 0;  -- Time (HHMMSS)   -- set by QSF
+    g_revision_id : string := ""   -- revision ID     -- set by QSF
+  );
+  port (
+    -- GENERAL
+    CLK          : in    std_logic;  -- System Clock
+    PPS          : in    std_logic;  -- System Sync
+    WDI          : out   std_logic;  -- Watchdog Clear
+    INTA         : inout std_logic;  -- FPGA interconnect line
+    INTB         : inout std_logic;  -- FPGA interconnect line
+
+    -- Others
+    VERSION      : in    std_logic_vector(c_unb2c_board_aux.version_w - 1 downto 0);
+    ID           : in    std_logic_vector(c_unb2c_board_aux.id_w - 1 downto 0);
+    TESTIO       : inout std_logic_vector(c_unb2c_board_aux.testio_w - 1 downto 0);
+
+    -- 1GbE Control Interface
+    ETH_CLK      : in  std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0);
+    ETH_SGIN     : in  std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0);
+    ETH_SGOUT    : out std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0);
+
+    -- Transceiver clocks
+    SA_CLK       : in    std_logic := '0';  -- Clock 10GbE front (qsfp) and ring lines
+
+    -- front transceivers QSFP0 for Ring.
+    QSFP_0_RX    : in  std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0) := (others => '0');
+    QSFP_0_TX    : out std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0);
+
+    -- front transceivers QSFP1 for 10GbE output to CEP.
+    QSFP_1_RX    : in    std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0) := (others => '0');
+    QSFP_1_TX    : out   std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0);
+
+    -- LEDs
+    QSFP_LED     : out std_logic_vector(c_unb2c_board_tr_qsfp_nof_leds - 1 downto 0);
+
+    -- ring transceivers
+    -- . Using qsfp bus width also for ring interfaces
+    RING_0_RX    : in  std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0) := (others => '0');
+    RING_0_TX    : out std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0);
+    RING_1_RX    : in  std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0) := (others => '0');
+    RING_1_TX    : out std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0);
+
+    -- back transceivers (note only 12 are used in unb2c)
+    -- . c_unb2c_board_nof_tr_jesd204b = c_sdp_S_pn = 12
+    BCK_RX       : in  std_logic_vector(c_unb2c_board_nof_tr_jesd204b - 1 downto 0);
+    BCK_REF_CLK  : in  std_logic;  -- Use as JESD204B_REFCLK
+
+    -- jesd204b syncronization signals (4 syncs)
+    -- . c_unb2c_board_nof_sync_jesd204b = c_sdp_N_sync_jesd = 4
+    JESD204B_SYSREF : in  std_logic;
+    JESD204B_SYNC_N : out std_logic_vector(c_unb2c_board_nof_sync_jesd204b - 1 downto 0);
+
+    -- DDR4 MB_I memory interface
+    MB_I_REF_CLK : in std_logic;  -- Reference clock for MB_I
+    MB_I_IN      : in    t_tech_ddr4_phy_in;
+    MB_I_IO      : inout t_tech_ddr4_phy_io;
+    MB_I_OU      : out   t_tech_ddr4_phy_ou
+  );
+end lofar2_unb2c_sdp_station_tbuf_ring;
+
+architecture str of lofar2_unb2c_sdp_station_tbuf_ring is
+  constant c_design_name      : string  := "lofar2_unb2c_sdp_station_tbuf_ring";
+  constant c_design_note      : string  := "AIT + TBuf + Ring for dump from multiple nodes";
+
+  signal JESD204B_SERIAL_DATA : std_logic_vector(
+                                    (c_unb2c_board_tr_jesd204b.bus_w * c_unb2c_board_tr_jesd204b.nof_bus) - 1 downto 0);
+  signal jesd204b_sync_n_arr  : std_logic_vector(c_unb2c_board_nof_sync_jesd204b - 1 downto 0);
+  signal JESD204B_REFCLK      : std_logic;
+begin
+  -- Mapping between JESD signal names and UNB2C pin/schematic names
+  JESD204B_REFCLK      <= BCK_REF_CLK;
+  JESD204B_SERIAL_DATA <= BCK_RX;
+  JESD204B_SYNC_N(c_unb2c_board_nof_sync_jesd204b - 1 downto 0) <=
+                                                      jesd204b_sync_n_arr(c_unb2c_board_nof_sync_jesd204b - 1 downto 0);
+
+  u_revision : entity lofar2_unb2c_sdp_station_lib.lofar2_unb2c_sdp_station
+  generic map (
+    g_design_name => c_design_name,
+    g_design_note => c_design_note,
+    g_stamp_date  => g_stamp_date,
+    g_stamp_time  => g_stamp_time,
+    g_revision_id => g_revision_id
+  )
+  port map (
+    -- GENERAL
+    CLK          => CLK,
+    PPS          => PPS,
+    WDI          => WDI,
+    INTA         => INTA,
+    INTB         => INTB,
+
+    -- Others
+    VERSION      => VERSION,
+    ID           => ID,
+    TESTIO       => TESTIO,
+
+    -- 1GbE Control Interface
+    ETH_CLK      => ETH_CLK,
+    ETH_SGIN     => ETH_SGIN,
+    ETH_SGOUT    => ETH_SGOUT,
+
+    -- Transceiver clocks
+    SA_CLK       => SA_CLK,
+
+    -- front transceivers QSFP0 for Ring.
+    QSFP_0_RX    => QSFP_0_RX,
+    QSFP_0_TX    => QSFP_0_TX,
+
+    -- front transceivers QSFP1 for 10GbE output to CEP.
+    QSFP_1_RX    => QSFP_1_RX,
+    QSFP_1_TX    => QSFP_1_TX,
+
+    -- LEDs
+    QSFP_LED     => QSFP_LED,
+
+    -- ring transceivers
+    RING_0_RX    => RING_0_RX,
+    RING_0_TX    => RING_0_TX,
+    RING_1_RX    => RING_1_RX,
+    RING_1_TX    => RING_1_TX,
+
+    -- back transceivers
+    JESD204B_SERIAL_DATA => JESD204B_SERIAL_DATA,
+    JESD204B_REFCLK      => JESD204B_REFCLK,
+
+    -- jesd204b syncronization signals
+    JESD204B_SYSREF      => JESD204B_SYSREF,
+    JESD204B_SYNC_N      => jesd204b_sync_n_arr,
+
+    -- DDR4 MB_I memory interface
+    MB_I_REF_CLK => MB_I_REF_CLK,
+    MB_I_IN      => MB_I_IN,
+    MB_I_IO      => MB_I_IO,
+    MB_I_OU      => MB_I_OU
+  );
+end str;
diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring_pins.tcl b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring_pins.tcl
new file mode 100644
index 0000000000000000000000000000000000000000..982ad9f2cf99d1182e3e2e4a2e84554b3df3cf1f
--- /dev/null
+++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring_pins.tcl
@@ -0,0 +1,24 @@
+###############################################################################
+#
+# Copyright 2024
+# 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.
+#
+###############################################################################
+source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_pins.tcl
+source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_jesd_pins.tcl
+source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_beamlets_pins.tcl
+source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_ring_pins.tcl
+source $::env(HDL_WORK)/boards/uniboard2c/libraries/unb2c_board/quartus/pinning/unb2c_ddr_16G_64b_I_pins.tcl
diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..43237d9eac9bb89abaa23e5f12beffe81889c79c
--- /dev/null
+++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd
@@ -0,0 +1,1289 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2024
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--
+-- Author: E. Kooistra
+-- Purpose: Self-checking testbench for lofar2_unb2c_sdp_station_tbuf_ring
+--   using WG data.
+--
+-- Description:
+--   MM control actions:
+--
+--   A) Set up WG and verify sp_power_sum as in tb_lofar2_unb2c_sdp_station_adc / bf.vhd
+--      . use DC level (= sp index) signal at the signal inputs, so all SP carry DC.
+--   B) Record, freeze and dump TBuf [2]: TODO
+--      . g_rs_block_size, g_ddr_buffer_size to verify recording beyond buffer full.
+--      . g_dump_page_offset, g_dump_nof_pages to verify dumping across begin and end of buffer
+--      . g_dump_enables to verify dumping one or more antenna inputs
+--      . g_dump_inter_packet_gap to vary dump rate.
+--      . log, verify: state, total counts
+--
+--   . g_ddr_buffer_size:
+--     Use Use g_ddr_buffer_size with e.g. 256 words to have smaller circular buffer independend of fixed
+--     c_tech_ddr4_sim_4k_64 with size 4096 words, to speed up simulation of wrap around of circular buffer full.
+--
+-- References:
+-- [1] https://support.astron.nl/confluence/pages/viewpage.action?spaceKey=L2M&title=L5+SDPFW+Design+Document%3A+Transient+buffer+raw+data
+-- [2] https://support.astron.nl/confluence/display/L2M/L2+STAT+Decision%3A+SC+-+SDP+OPC-UA+interface with dynamic
+--     behaviour recipe for record, freeze, dump
+--
+-- Usage:
+--   > as 12   # for detailed debugging
+--   > run -a
+--   . view:
+--     . rx_beamlets_header.app for beamlet packet header
+--     . rx_dump_header.app for dump packet header
+--     . rx_ant_sosi and rx_ant_data_arr (to show SP with corresponding DC level) for dump packet data
+--   . copy usedw of tx FIFOs in Wave Window in analog format and as bits to see and compare their fill levels and
+--     spare space when g_rs_block_size, for tx FIFOs in:
+--     . nw_10GbE
+--     . sdp_beamformer_output of bf[0]
+--     . sdp_beamformer_output of bf[1]
+--     . sdp_tbuf_output tx FIFO
+--   . Use "cat transcript| grep Error:" in git/hdl directory to ease spotting simulation ERRORs
+--
+-------------------------------------------------------------------------------
+library IEEE, common_lib, mm_lib, dp_lib, diag_lib, i2c_lib, wpfb_lib;
+library tech_pll_lib, tr_10GbE_lib, unb2c_board_lib;
+library lofar2_sdp_lib, lofar2_unb2c_sdp_station_lib;
+  use IEEE.std_logic_1164.all;
+  use IEEE.numeric_std.all;
+  use IEEE.math_real.all;
+  use common_lib.common_pkg.all;
+  use common_lib.tb_common_pkg.all;
+  use common_lib.common_mem_pkg.all;
+  use common_lib.common_str_pkg.all;
+  use dp_lib.dp_stream_pkg.all;
+  use mm_lib.mm_file_pkg.all;
+  use mm_lib.mm_file_unb_pkg.all;
+  use diag_lib.diag_pkg.all;
+  use wpfb_lib.wpfb_pkg.all;
+  use tech_pll_lib.tech_pll_component_pkg.all;
+  use unb2c_board_lib.unb2c_board_pkg.all;
+  use lofar2_sdp_lib.sdp_pkg.all;
+  use lofar2_sdp_lib.tb_sdp_pkg.all;
+  use lofar2_sdp_lib.sdp_tbuf_pkg.all;
+  use lofar2_sdp_lib.tb_sdp_tbuf_pkg.all;
+
+entity tb_lofar2_unb2c_sdp_station_tbuf_ring is
+  generic (
+    g_tb_end                   : boolean := true;  -- when true then tb_end ends this simulation, else a higher
+                                                   -- multi-testbench will end the simulation
+    g_tb_index                 : natural := 0;
+    g_ddr_buffer_size          : natural := 256;  -- <= 4096, because c_tech_ddr4_sim_4k_64 has 4k = 4096 words of
+                                                   -- c_sdp_tbuf_W_word = 512b
+    g_rs_block_size            : natural := 100;  -- c_sdp_tbuf_rs_block_size = 2000, must be even see sdp_tbuf_output
+    g_rs_record_nof_block      : natural := 3;  -- choose > c_rs_nof_block_per_sync to have at least on sync interval
+                                                -- for the RSN monitor
+    g_dump_inter_packet_gap    : natural := 0;  -- use 1708 for 3 Gbps and g_rs_block_size = 2000
+    g_dump_page_offset         : natural := 0;  -- offset relative to recorded_first_page
+    g_dump_nof_pages           : natural := 3;  -- g_dump_page_offset + g_dump_nof_pages <= g_rs_record_nof_block, else
+                                                -- there will occur read RSN errors for pages that are not available
+    g_dump_enables             : std_logic_vector(c_sdp_A_pn - 1 downto 0) := "100001"
+  );
+  port (
+    tb_end : out std_logic
+  );
+end tb_lofar2_unb2c_sdp_station_tbuf_ring;
+
+architecture tb of tb_lofar2_unb2c_sdp_station_tbuf_ring is
+  constant c_sim             : boolean := true;  -- use true for sim_ddr, use false to simulate IP and external DDR4
+  constant c_unb_nr          : natural := 1;
+  constant c_node_nr         : natural := 2;
+  constant c_tb_str          : string := "TB-" & int_to_str(g_tb_index) & ": ";
+  constant c_mmf_prefix      : string := mmf_unb2_file_prefix(g_tb_index, c_unb_nr, c_node_nr);
+  constant c_Gbps            : real := 10.0**9;
+
+  constant c_design_name     : string := "lofar2_unb2c_sdp_station_tbuf_ring";
+  constant c_nof_dump        : natural := 1;  -- number of dumps, > 1 to repeat same dump
+
+  constant c_gn_index            : natural := c_unb_nr * 4 + c_node_nr;  -- this node GN
+  constant c_ai_offset           : natural := c_gn_index * c_sdp_A_pn;
+  constant c_id                  : std_logic_vector(7 downto 0) := TO_UVEC(c_gn_index, 8);
+  constant c_version             : std_logic_vector(1 downto 0) := "00";
+  constant c_fw_version          : t_unb2c_board_fw_version := (1, 0);
+
+  constant c_eth_clk_period      : time := 8 ns;  -- 125 MHz XO on UniBoard
+  constant c_ext_clk_period      : time := 5 ns;
+  constant c_mm_clk_period       : time := 10 ns;  -- 100 MHz internal mm_clk
+  constant c_bck_ref_clk_period  : time := 5 ns;
+  constant c_sa_clk_period       : time := tech_pll_clk_644_period;  -- 644MHz
+  constant c_tb_clk_period       : time := 100 ps;  -- use fast tb_clk to speed up M&C
+  constant c_1ns                 : time := 1 ns;
+
+  -- BSN
+  constant c_bs_block_size          : natural := true_log_pow2(g_rs_block_size);  -- power of 2 >= g_rs_block_size
+  constant c_bs_nof_block_per_sync  : natural := 2;
+  constant c_bs_nof_clk_per_sync    : natural := c_bs_nof_block_per_sync * c_bs_block_size;  -- For SP power in AIT
+  constant c_pps_period             : natural := c_bs_nof_clk_per_sync;
+  constant c_T_bs_period            : time    := c_bs_block_size * c_sdp_T_adc;
+  constant c_T_rd_interval          : time    := 200 ns;
+  constant c_init_bsn               : natural := 17;  -- some recognizable value >= 0
+
+  -- RSN
+  constant c_rs_nof_block_per_sync  : natural := 2;
+  constant c_rs_nof_clk_per_sync    : natural := c_rs_nof_block_per_sync * g_rs_block_size;
+
+  -- Buffer size
+  constant c_ddr_access_rate_pct    : natural := 100;  -- full rate is 100 %
+  constant c_ddr_buffer_size        : natural := sel_a_b(g_rs_block_size > g_ddr_buffer_size, 4096, g_ddr_buffer_size);
+  constant c_sim_sdp_tbuf           : t_sdp_tbuf_sim := (c_rs_nof_clk_per_sync,
+                                                         c_bs_block_size,
+                                                         g_rs_block_size,
+                                                         c_ddr_buffer_size,
+                                                         c_ddr_access_rate_pct);
+
+  -- Page size, and number of pages
+  constant c_page_data_size         : natural := func_sdp_tbuf_calculate_page_data_size(g_rs_block_size);
+  constant c_page_meta_size         : natural := func_sdp_tbuf_calculate_page_meta_size(g_rs_block_size);
+  constant c_page_size              : natural := c_page_data_size + c_page_meta_size;
+  constant c_nof_pages_in_buffer    : natural := func_sdp_tbuf_calculate_nof_pages(c_ddr_buffer_size, c_page_size);
+  constant c_dump_nof_pages_rw      : natural := g_dump_nof_pages;
+  constant c_dump_nof_pages_actual  : natural := smallest(g_dump_nof_pages, c_nof_pages_in_buffer);
+  constant c_bs_start_latency       : natural := c_bs_block_size * 2;
+  constant c_record_min_nof_pages   : natural := g_dump_page_offset + c_dump_nof_pages_rw;
+  constant c_record_min_nof_clk     : natural := c_bs_start_latency + g_rs_block_size * c_record_min_nof_pages;
+
+  constant c_exp_read_rate_bps      : real := func_sdp_tbuf_calculate_dump_rate_bps(g_rs_block_size,
+                                                                                    g_dump_inter_packet_gap);
+  constant c_exp_dump_rate_bps      : real := c_exp_read_rate_bps;
+  constant c_dump_rate_delta        : real := 0.05;  -- = 5 %
+
+  constant c_dump_nof_ai               : natural := vector_sum(g_dump_enables);
+  constant c_dump_ai_indices           : t_nat_integer_arr(g_dump_enables'range) := vector_one_indices(g_dump_enables);
+  constant c_read_nof_packets_per_ai   : natural := c_dump_nof_pages_actual;
+  constant c_read_total_nof_packets    : natural := c_dump_nof_ai * c_dump_nof_pages_actual;
+  constant c_read_nof_crc_errors       : natural := 0;
+  constant c_read_nof_rsn_errors       : natural := 0;
+  constant c_dump_nof_packets_per_ai   : natural := c_read_nof_packets_per_ai;
+  constant c_dump_nof_packets_per_loop : natural := c_dump_nof_ai * c_dump_nof_packets_per_ai;
+  constant c_dump_total_nof_packets    : natural := c_read_total_nof_packets;
+
+  -- SDP info
+  constant c_exp_sdp_info        : t_sdp_info := (
+                                     TO_UVEC(3, 6),  -- antenna_field_index
+                                     TO_UVEC(601, 10),  -- station_id
+                                     '0',  -- antenna_band_index
+                                     x"7FFFFFFF",  -- 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"1400"  -- block_period = 5120
+                                   );
+
+  -- TBuf dump header fields
+  constant c_cep_eth_src_mac     : std_logic_vector(47 downto 0) :=
+                                                c_sdp_cep_eth_src_mac_47_16 & func_sdp_gn_index_to_mac_15_0(c_gn_index);
+  constant c_cep_ip_src_addr     : std_logic_vector(31 downto 0) :=
+                                                 c_sdp_cep_ip_src_addr_31_16 & func_sdp_gn_index_to_ip_15_0(c_gn_index);
+  constant c_cep_udp_src_port    : std_logic_vector(15 downto 0) := c_sdp_cep_udp_src_port_15_8 & c_id;
+
+  -- Determine expected ip_header_checksum for c_unb_nr = 1, c_node_nr = 2, and g_rs_block_size. Value obtained from
+  -- rx_dump_header.ip.header_checksum in wave window
+  function func_exp_ip_header_checksum(g_rs_block_size : natural) return natural is
+  begin
+    if g_rs_block_size = 100 then
+      return 16#7806#;
+    elsif g_rs_block_size = 102 then
+      return 16#77FF#;
+    elsif g_rs_block_size = 2000 then
+      return 16#5E0C#;
+    else
+      return 0;
+    end if;
+  end func_exp_ip_header_checksum;
+
+  constant c_exp_ip_header_checksum : natural := func_exp_ip_header_checksum(g_rs_block_size);
+
+  constant c_packed_empty_w      : natural := 3;  -- = ceil_log2(c_longword_sz - 1)
+  constant c_rx_fifo_size        : natural := g_rs_block_size;
+
+  -- DDR4
+  constant c_exp_ddr_ctlr_nof_bytes_per_word : natural := c_sdp_tbuf_W_word / c_byte_w;
+
+  -- WG
+  -- . Observe WG using rs_sosi.sop and rs_data_arr() in decimal format in Wave Window.
+  constant c_bsn_start_wg        : natural := c_init_bsn + 2;  -- start WG at this BSN instead of some BSN, to avoid
+                                                               -- mismatches in exact expected data values
+
+  -- MM
+  constant c_addr_w_reg_diag_wg           : natural := 2;
+  constant c_mm_span_reg_diag_wg          : natural := 2**c_addr_w_reg_diag_wg;
+  constant c_addr_w_reg_dp_xonoff         : natural := 1;
+  constant c_mm_span_reg_dp_xonoff        : natural := 2**c_addr_w_reg_dp_xonoff;
+
+  constant c_mm_file_reg_bsn_source_v2    : string := c_mmf_prefix & "REG_BSN_SOURCE_V2";
+  constant c_mm_file_reg_bsn_scheduler_wg : string := c_mmf_prefix & "REG_BSN_SCHEDULER";
+  constant c_mm_file_reg_diag_wg          : string := c_mmf_prefix & "REG_WG";
+  constant c_mm_file_reg_sdp_info         : string := c_mmf_prefix & "REG_SDP_INFO";
+  constant c_mm_file_reg_io_ddr_mb_i      : string := c_mmf_prefix & "REG_IO_DDR_MB_I";
+  constant c_mm_file_reg_tbuf             : string := c_mmf_prefix & "REG_TBUF";
+  constant c_mm_file_reg_bsn_monitor_v2_tbuf     : string := c_mmf_prefix & "REG_BSN_MONITOR_V2_TBUF";
+  constant c_mm_file_reg_strobe_total_count_tbuf : string := c_mmf_prefix & "REG_STROBE_TOTAL_COUNT_TBUF";
+  constant c_mm_file_reg_hdr_dat          : string := c_mmf_prefix & "REG_HDR_DAT";  -- BF beamlets header
+  constant c_mm_file_reg_hdr_dat_tbuf     : string := c_mmf_prefix & "REG_HDR_DAT_TBUF";  -- TBuf dump header
+  constant c_mm_file_reg_dp_xonoff        : string := c_mmf_prefix & "REG_DP_XONOFF";  -- BF beamlet output enable
+  constant c_mm_file_reg_dp_xonoff_tbuf   : string := c_mmf_prefix & "REG_DP_XONOFF_TBUF";  -- TBuf dump output enable
+  constant c_mm_file_reg_nw_10gbe_mac     : string := c_mmf_prefix & "REG_NW_10GBE_MAC";
+
+  signal wg_started           : std_logic := '0';
+  signal rx_done              : std_logic := '0';
+  signal tb_almost_end        : std_logic := '0';
+  signal i_tb_end             : std_logic := '0';
+  signal tb_clk               : std_logic := '0';
+  signal rd_data_setup        : std_logic_vector(c_32 - 1 downto 0);
+  signal rd_data_state        : std_logic_vector(c_32 - 1 downto 0);
+  signal rd_data_control      : std_logic_vector(c_32 - 1 downto 0);
+  signal rd_data_monitor      : std_logic_vector(c_32 - 1 downto 0);
+  signal rd_data_bsn          : std_logic_vector(c_32 - 1 downto 0);
+  signal rd_data_record_busy  : std_logic_vector(c_32 - 1 downto 0);
+  signal rd_data_dump_done    : std_logic_vector(c_32 - 1 downto 0);
+  signal rd_data_strobe       : std_logic_vector(c_32 - 1 downto 0);
+  signal rd_data_nw_10gbe_mac : std_logic_vector(c_32 - 1 downto 0);
+
+  signal dest_rst            : std_logic := '1';  -- use separate destination rst for Rx 10GbE in tb
+  signal pps_rst             : std_logic := '1';  -- use separate reset to release the PPS generator
+  signal gen_pps             : std_logic := '0';
+
+  -- MM
+  signal rd_cep_eth_src_mac  : std_logic_vector(47 downto 0);
+  signal rd_cep_eth_dst_mac  : std_logic_vector(47 downto 0);
+  signal rd_cep_ip_src_addr  : std_logic_vector(31 downto 0);
+  signal rd_cep_ip_dst_addr  : std_logic_vector(31 downto 0);
+  signal rd_cep_udp_src_port : std_logic_vector(15 downto 0);
+  signal rd_cep_udp_dst_port : std_logic_vector(15 downto 0);
+
+  signal ddr_status                  : std_logic_vector(31 downto 0);
+  signal ddr_wr_fifo_used            : natural;
+  signal ddr_rd_fifo_used            : natural;
+  signal ddr_wr_fifo_full            : std_logic;
+  signal ddr_rd_fifo_full            : std_logic;
+  signal ddr_dvr_done                : std_logic := '0';
+  signal ddr_ctlr_nof_bytes_per_word : natural;
+
+  -- WG
+  signal current_bsn_wg         : std_logic_vector(c_dp_stream_bsn_w - 1 downto 0);
+
+  -- TBuf
+  signal tbuf_registers_wr          : t_sdp_tbuf_registers_rw;
+  signal tbuf_registers_rd          : t_sdp_tbuf_registers_rw;  -- read (rd) of write (wr)
+  signal tbuf_registers_ro          : t_sdp_tbuf_registers_ro;  -- read only (ro)
+  signal tbuf_strobe_total_counts   : t_sdp_tbuf_strobe_total_counts_ro;
+  signal recording_rsn_at_sync      : natural;
+  signal recording_nof_sop_per_sync : natural;
+  signal dump_index                 : natural;
+  signal time_index                 : natural;
+  signal read_busy                  : std_logic := '0';
+  signal dump_rate_bps              : real := 0.0;
+
+  signal dbg_c_exp_read_rate_bps         : real := c_exp_read_rate_bps;
+  signal dbg_c_exp_dump_rate_bps         : real := c_exp_dump_rate_bps;
+  signal dbg_c_dump_nof_ai               : natural := c_dump_nof_ai;
+  signal dbg_c_dump_ai_indices           : t_nat_integer_arr(g_dump_enables'range) := c_dump_ai_indices;
+  signal dbg_c_read_nof_packets_per_ai   : natural := c_read_nof_packets_per_ai;
+  signal dbg_c_read_total_nof_packets    : natural := c_read_total_nof_packets;
+  signal dbg_c_read_nof_crc_errors       : natural := c_read_nof_crc_errors;
+  signal dbg_c_read_nof_rsn_errors       : natural := c_read_nof_rsn_errors;
+  signal dbg_c_dump_nof_packets_per_ai   : natural := c_dump_nof_packets_per_ai;
+  signal dbg_c_dump_nof_packets_per_loop : natural := c_dump_nof_packets_per_loop;
+  signal dbg_c_dump_total_nof_packets    : natural := c_dump_total_nof_packets;
+
+  -- CEP model
+  -- . 10GbE
+  signal tr_10GbE_src_out          : t_dp_sosi;
+  signal tr_10GbE_src_in           : t_dp_siso;
+  signal tr_ref_clk_312            : std_logic := '0';
+  signal tr_ref_clk_156            : std_logic := '0';
+  signal tr_ref_rst_156            : std_logic := '0';
+
+  -- . dp_offload_rx
+  signal rx_dump_hdr_fields_raw     : std_logic_vector(1023 downto 0) := (others => '0');
+  signal rx_dump_sosi               : t_dp_sosi := c_dp_sosi_rst;
+
+  -- Dump packets header
+  signal tb_dump_cnt             : natural := 0;
+  signal rx_dump_header          : t_sdp_tbuf_cep_header;
+  signal exp_dump_header         : t_sdp_tbuf_cep_header;
+  signal rx_dump_marker          : natural;
+  signal rx_dump_station_info    : t_sdp_station_info;
+  signal exp_dump_station_info   : t_sdp_station_info;
+  signal exp_dump_ai             : natural;
+  signal exp_dp_rsn              : natural;
+
+  -- Dump packets data
+  signal rx_dump_packet_cnt      : natural := 0;
+  signal rx_stats_etherstatspkts : natural;
+  signal rx_fifo_siso            : t_dp_siso;
+  signal rx_fifo_sosi            : t_dp_sosi;
+  signal rx_ant_sosi             : t_dp_sosi := c_dp_sosi_rst;
+  signal rx_ant_sosi_prev_eop    : std_logic;
+  signal rx_ant_data_arr         : t_sdp_sp_data_arr(1 downto 0);  -- 14 bit, dual pol, X = 0, Y = 1
+  signal rx_ant_dc_data_err      : std_logic;
+  signal rx_ant_sinus_data_err   : std_logic;
+  signal rx_ant_index            : natural;
+  signal rx_dump_length_cnt      : natural;
+  signal rx_dump_length          : natural;
+  signal rx_wg_data              : integer := 0;
+  signal exp_wg_data             : integer := 0;
+  signal diff_wg_data            : integer := 0;
+  signal diff_wg_max             : integer := 0;
+
+  -- DUT
+  signal ext_clk             : std_logic := '0';
+  signal ext_pps             : std_logic := '0';
+
+  signal WDI                 : std_logic;
+  signal INTA                : std_logic;
+  signal INTB                : std_logic;
+
+  signal eth_clk             : std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0) := (others => '0');
+  signal eth_txp             : std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0);
+  signal eth_rxp             : std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0);
+
+  signal SA_CLK              : std_logic := '1';
+  signal si_lpbk_0           : std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0);
+
+  -- back transceivers
+  signal JESD204B_SERIAL_DATA : std_logic_vector(c_sdp_S_pn - 1 downto 0);
+  signal JESD204B_REFCLK      : std_logic := '1';
+
+  -- jesd204b syncronization signals
+  signal jesd204b_sysref     : std_logic;
+  signal jesd204b_sync_n     : std_logic_vector(c_sdp_N_sync_jesd - 1 downto 0);
+
+  -- DDR4 reference clock
+  signal MB_I_REF_CLK        : std_logic;
+begin
+  tb_end <= i_tb_end;
+
+  ----------------------------------------------------------------------------
+  -- System setup
+  ----------------------------------------------------------------------------
+  tb_clk  <= not tb_clk and not i_tb_end after c_tb_clk_period / 2;  -- Testbench MM clock
+  ext_clk <= not ext_clk and not i_tb_end after c_ext_clk_period / 2;  -- External clock (200 MHz)
+  eth_clk(0) <= not eth_clk(0) and not i_tb_end after c_eth_clk_period / 2;  -- Ethernet ref clock (125 MHz)
+  JESD204B_REFCLK <= not JESD204B_REFCLK and not i_tb_end after c_bck_ref_clk_period / 2;  -- JESD sample clock (200MHz)
+  SA_CLK <= not SA_CLK and not i_tb_end after c_sa_clk_period / 2;  -- Serial Gigabit IO sa clock (644 MHz)
+  MB_I_REF_CLK <= ext_clk;  -- DDR4 reference clock, same source as ext_clk (200 MHz)
+  dest_rst <= '0' after c_ext_clk_period * 10;
+
+  INTA <= 'H';  -- pull up
+  INTB <= 'H';  -- pull up
+
+  ------------------------------------------------------------------------------
+  -- External PPS
+  ------------------------------------------------------------------------------
+  proc_common_gen_pulse(5, c_pps_period, '1', pps_rst, ext_clk, gen_pps);
+  jesd204b_sysref <= gen_pps;
+  ext_pps <= gen_pps;
+
+  ------------------------------------------------------------------------------
+  -- DUT
+  -- . Uses lofar2_unb2c_sdp_station instead of synthesis wrapper lofar2_unb2c_sdp_station_tbuf_ring, to be able to
+  --   use the JESD204B signal names instead of the unb2c pin names and to have access to all generics.
+  ------------------------------------------------------------------------------
+  u_lofar_unb2c_sdp_station_tbuf_ring : entity lofar2_unb2c_sdp_station_lib.lofar2_unb2c_sdp_station
+  generic map (
+    g_design_name          => c_design_name,
+    g_design_note          => "AIT + TBuf + Ring for dump from multiple nodes",
+    g_sim                  => c_sim,
+    g_sim_tb_index         => g_tb_index,
+    g_sim_unb_nr           => c_unb_nr,
+    g_sim_node_nr          => c_node_nr,
+    g_sim_sdp_tbuf         => c_sim_sdp_tbuf,
+    g_bsn_nof_clk_per_sync => c_bs_nof_clk_per_sync,
+    g_bs_block_size        => c_bs_block_size
+  )
+  port map (
+    -- GENERAL
+    CLK          => ext_clk,
+    PPS          => ext_pps,
+    WDI          => WDI,
+    INTA         => INTA,
+    INTB         => INTB,
+
+    -- Others
+    VERSION      => c_version,
+    ID           => c_id,
+    TESTIO       => open,
+
+    -- 1GbE Control Interface
+    ETH_CLK      => eth_clk,
+    ETH_SGIN     => eth_rxp,
+    ETH_SGOUT    => eth_txp,
+
+    -- Transceiver clocks
+    SA_CLK       => SA_CLK,
+
+    -- front transceivers
+    QSFP_1_RX    => si_lpbk_0,
+    QSFP_1_TX    => si_lpbk_0,
+
+    -- LEDs
+    QSFP_LED     => open,
+
+    -- back transceivers
+    JESD204B_SERIAL_DATA => JESD204B_SERIAL_DATA,
+    JESD204B_REFCLK      => JESD204B_REFCLK,
+
+    -- jesd204b syncronization signals
+    JESD204B_SYSREF => jesd204b_sysref,
+    JESD204B_SYNC_N => jesd204b_sync_n,
+
+    -- DDR4 reference clock
+    MB_I_REF_CLK => MB_I_REF_CLK
+    -- DDR4 SO-DIMM Memory Bank I --> simulation use internal sim_ddr model in io_ddr
+  );
+
+  ------------------------------------------------------------------------------
+  -- CEP model
+  ------------------------------------------------------------------------------
+  u_unb2_board_clk644_pll : entity tech_pll_lib.tech_pll_xgmii_mac_clocks
+  port map (
+    refclk_644 => SA_CLK,
+    rst_in     => dest_rst,
+    clk_156    => tr_ref_clk_156,
+    clk_312    => tr_ref_clk_312,
+    rst_156    => tr_ref_rst_156,
+    rst_312    => open
+  );
+
+  u_tr_10GbE: entity tr_10GbE_lib.tr_10GbE
+  generic map (
+    g_sim           => true,
+    g_sim_level     => 1,
+    g_nof_macs      => 1,
+    g_use_mdio      => false
+  )
+  port map (
+    -- Transceiver PLL reference clock
+    tr_ref_clk_644      => SA_CLK,
+    tr_ref_clk_312      => tr_ref_clk_312,  -- 312.5      MHz for 10GBASE-R
+    tr_ref_clk_156      => tr_ref_clk_156,  -- 156.25     MHz for 10GBASE-R or for XAUI
+    tr_ref_rst_156      => tr_ref_rst_156,  -- for 10GBASE-R or for XAUI
+
+    -- MM interface
+    mm_rst              => dest_rst,
+    mm_clk              => tb_clk,
+
+    -- DP interface
+    dp_rst              => dest_rst,
+    dp_clk              => ext_clk,
+
+    serial_rx_arr(0)    => si_lpbk_0(0),
+
+    src_out_arr(0)      => tr_10GbE_src_out,
+    src_in_arr(0)       => tr_10GbE_src_in
+  );
+
+  u_dp_offload_rx : entity dp_lib.dp_offload_rx
+  generic map (
+    g_nof_streams         => 1,
+    g_data_w              => c_longword_w,
+    g_symbol_w            => c_octet_w,
+    g_hdr_field_arr       => c_sdp_tbuf_hdr_field_arr,
+    g_remove_crc          => false,
+    g_crc_nof_words       => 0
+  )
+  port map (
+    mm_rst                => dest_rst,
+    mm_clk                => tb_clk,
+
+    dp_rst                => dest_rst,
+    dp_clk                => ext_clk,
+
+    reg_hdr_dat_mosi      => c_mem_copi_rst,
+    reg_hdr_dat_miso      => open,
+
+    snk_in_arr(0)         => tr_10GbE_src_out,
+    snk_out_arr(0)        => tr_10GbE_src_in,
+
+    src_out_arr(0)        => rx_dump_sosi,
+
+    hdr_fields_out_arr    => open,
+    hdr_fields_raw_arr(0) => rx_dump_hdr_fields_raw
+  );
+
+  -- All rx_dump_sosi frames are rx dump packets
+  rx_dump_header <= func_sdp_tbuf_map_cep_header(rx_dump_hdr_fields_raw);
+
+  -- FIFO to fit backpressure for u_dp_repack_data_word
+  u_dp_fifo_sc : entity dp_lib.dp_fifo_sc
+  generic map (
+    g_data_w     => c_longword_w,
+    g_empty_w    => c_packed_empty_w,
+    g_use_empty  => true,
+    g_use_ctrl   => true,
+    g_fifo_size  => c_rx_fifo_size
+  )
+  port map (
+    rst     => dest_rst,
+    clk     => ext_clk,
+
+    snk_in  => rx_dump_sosi,
+    src_in  => rx_fifo_siso,
+    src_out => rx_fifo_sosi
+  );
+
+  -- 64 * 7 = 28 * 16 = 448
+  u_dp_repack_data_word : entity dp_lib.dp_repack_data
+  generic map (
+    g_in_dat_w       => c_longword_w,  -- = 64
+    g_in_nof_words   => 7,
+    g_in_symbol_w    => c_octet_w,
+    g_out_dat_w      => c_sdp_W_ant,  -- = 28
+    g_out_nof_words  => 16,
+    g_out_symbol_w   => 1,
+    g_pipeline_ready => false  -- true to pipeline ready from src_in to snk_out.
+  )
+  port map (
+    rst        => dest_rst,
+    clk        => ext_clk,
+    snk_in     => rx_fifo_sosi,
+    snk_out    => rx_fifo_siso,
+    src_out    => rx_ant_sosi
+  );
+
+  rx_ant_sosi_prev_eop <= rx_ant_sosi.eop when rising_edge(ext_clk);
+
+  p_rx_ant : process(rx_ant_sosi, rx_ant_sosi_prev_eop, rx_dump_header)
+  begin
+    for I in 0 to c_sdp_N_pol - 1 loop
+      rx_ant_data_arr(I) <= rx_ant_sosi.data((I + 1) * c_sdp_W_adc - 1 downto I * c_sdp_W_adc);
+    end loop;
+    if rx_ant_sosi.valid = '0' or rx_ant_sosi_prev_eop = '1' then
+      -- Check valid to ensure that rx_ant_index is updated after previous packet was finished
+      rx_ant_index <= to_uint(rx_dump_header.app.sdp_antenna_input_index) mod c_sdp_A_pn;
+    end if;
+  end process;
+
+  ------------------------------------------------------------------------------
+  -- MM slave accesses via file IO
+  ------------------------------------------------------------------------------
+  p_mm_setup : process
+    variable v_offset        : natural;
+    variable v_addr          : natural;
+    variable v_norm_ampl     : real;
+    variable v_bsn           : natural;
+    variable v_sp_power_sum  : real;
+  begin
+    -- Wait for DUT power up after reset
+    wait for 200 ns;
+
+    ----------------------------------------------------------------------------
+    -- Set SDP info
+    ----------------------------------------------------------------------------
+    --     TYPE t_sdp_info IS RECORD
+    --   8   antenna_field_index     : STD_LOGIC_VECTOR(5 DOWNTO 0);
+    --   7   station_id              : STD_LOGIC_VECTOR(9 DOWNTO 0);
+    --   6   antenna_band_index      : STD_LOGIC;
+    --   5   observation_id          : STD_LOGIC_VECTOR(31 DOWNTO 0);
+    --   4   nyquist_zone_index      : STD_LOGIC_VECTOR(1 DOWNTO 0);
+    --   3   f_adc                   : STD_LOGIC;
+    --   2   fsub_type               : STD_LOGIC;
+    --   1   beam_repositioning_flag : STD_LOGIC;
+    --   0   block_period            : STD_LOGIC_VECTOR(15 DOWNTO 0);
+    --     END RECORD;
+    -- . Write
+    mmf_mm_bus_wr(c_mm_file_reg_sdp_info,  8, TO_UINT(c_exp_sdp_info.antenna_field_index), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_sdp_info,  7, TO_UINT(c_exp_sdp_info.station_id), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_sdp_info,  6, TO_UINT(slv(c_exp_sdp_info.antenna_band_index)), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_sdp_info,  5, TO_UINT(c_exp_sdp_info.observation_id), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_sdp_info,  4, TO_UINT(c_exp_sdp_info.nyquist_zone_index), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_sdp_info,  1, TO_UINT(slv(c_exp_sdp_info.beam_repositioning_flag)), tb_clk);
+
+    ----------------------------------------------------------------------------
+    -- Set TBuf dump output MAC,IP,UDP port
+    ----------------------------------------------------------------------------
+    -- TBuf dump header
+    -- c_sdp_tbuf_hdr_field_arr : t_common_field_arr(c_sdp_tbuf_nof_hdr_fields - 1 downto 0) := (
+    --  33 field_name_pad("eth_dst_mac"                    ), "RW", 48, field_default(0) ),  -- c_sdp_cep_eth_dst_mac
+    --  31 field_name_pad("eth_src_mac"                    ), "RW", 48, field_default(0) ),
+    --  30 field_name_pad("eth_type"                       ), "RW", 16, field_default(x"0800") ),
+    --
+    --  29 field_name_pad("ip_version"                     ), "RW",  4, field_default(4) ),
+    --  28 field_name_pad("ip_header_length"               ), "RW",  4, field_default(5) ),
+    --  27 field_name_pad("ip_services"                    ), "RW",  8, field_default(0) ),
+    --  26 field_name_pad("ip_total_length"                ), "RW", 16, field_default(c_sdp_tbuf_ip_total_length) ),
+    --  25 field_name_pad("ip_identification"              ), "RW", 16, field_default(0) ),
+    --  24 field_name_pad("ip_flags"                       ), "RW",  3, field_default(2) ),
+    --  23 field_name_pad("ip_fragment_offset"             ), "RW", 13, field_default(0) ),
+    --  22 field_name_pad("ip_time_to_live"                ), "RW",  8, field_default(127) ),
+    --  21 field_name_pad("ip_protocol"                    ), "RW",  8, field_default(17) ),
+    --  20 field_name_pad("ip_header_checksum"             ), "RW", 16, field_default(0) ),
+    --  19 field_name_pad("ip_src_addr"                    ), "RW", 32, field_default(0) ),
+    --  18 field_name_pad("ip_dst_addr"                    ), "RW", 32, field_default(0) ),  -- c_sdp_cep_ip_dst_addr
+    --
+    --  17 field_name_pad("udp_src_port"                   ), "RW", 16, field_default(0) ),
+    --  16 field_name_pad("udp_dst_port"                   ), "RW", 16, field_default(0) ),  -- c_sdp_cep_udp_dst_port
+    --  15 field_name_pad("udp_total_length"               ), "RW", 16, field_default(c_sdp_tbuf_udp_total_length) ),
+    --  14 field_name_pad("udp_checksum"                   ), "RW", 16, field_default(0) ),
+    --
+    --  13 field_name_pad("sdp_marker"                     ), "RW",  8, field_default(c_sdp_tbuf_marker) ),
+    --  12 field_name_pad("sdp_version_id"                 ), "RW",  8, field_default(c_sdp_tbuf_version_id) ),
+    --  11 field_name_pad("sdp_observation_id"             ), "RW", 32, field_default(0) ),
+    --  10 field_name_pad("sdp_station_info"               ), "RW", 16, field_default(0) ),
+    --
+    --   9 field_name_pad("sdp_source_info_antenna_band_id"), "RW",  1, field_default(0) ),
+    --   8 field_name_pad("sdp_source_info_nyquist_zone_id"), "RW",  2, field_default(0) ),
+    --   7 field_name_pad("sdp_source_info_f_adc"          ), "RW",  1, field_default(0) ),
+    --   6 field_name_pad("sdp_source_info_sample_width"   ), "RW",  4, field_default(c_sdp_W_adc) ),
+    --   5 field_name_pad("sdp_source_info_gn_id"          ), "RW",  8, field_default(0) ),
+    --
+    --   4 field_name_pad("sdp_reserved"                   ), "RW", 24, field_default(0) ),
+    --   3 field_name_pad("sdp_antenna_input_index"        ), "RW",  8, field_default(0) ),
+    --   2 field_name_pad("sdp_nof_raw_data_per_packet"    ), "RW", 16, field_default(c_sdp_tbuf_rs_blk_size) ),
+    --
+    --   0 field_name_pad("dp_rsn"                         ), "RW", 64, field_default(0) )
+    --
+    -- Write tb defaults
+    -- . Use sim default dst and src MAC, IP, UDP port from sdp_pkg.vhd and based on c_gn_index
+    -- . Use signed to fit 32 b in INTEGER
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 32, TO_UINT(c_cep_eth_src_mac(47 downto 32)), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 31, TO_SINT(c_cep_eth_src_mac(31 downto 0)), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 19, TO_SINT(c_cep_ip_src_addr), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 17, TO_UINT(c_cep_udp_src_port), tb_clk);
+    -- . Set destination MAC/IP/UDP via c_mm_file_reg_hdr_dat_tbuf
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 34, TO_UINT(c_sdp_cep_eth_dst_mac(47 downto 32)), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 33, TO_SINT(c_sdp_cep_eth_dst_mac(31 downto 0)), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 18, TO_SINT(c_sdp_cep_ip_dst_addr), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 16, TO_UINT(c_sdp_cep_udp_dst_port), tb_clk);
+    -- . Use same src MAC, src IP and dst IP for ARP/ping via BF header MM register of beamset 0
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat, 39, TO_UINT(c_cep_eth_src_mac(47 downto 32)), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat, 38, TO_SINT(c_cep_eth_src_mac(31 downto 0)), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat, 26, TO_SINT(c_cep_ip_src_addr), tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_hdr_dat, 25, TO_SINT(c_sdp_cep_ip_dst_addr), tb_clk);
+    proc_common_wait_cross_clock_domain_latency(
+        c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2);
+    -- . Read back
+    mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 32, rd_data_setup, tb_clk);
+    rd_cep_eth_src_mac(47 downto 32) <= rd_data_setup(15 downto 0);
+    mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 31, rd_data_setup, tb_clk);
+    rd_cep_eth_src_mac(31 downto 0) <= rd_data_setup;
+    mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 19, rd_data_setup, tb_clk);
+    rd_cep_ip_src_addr <= rd_data_setup;
+    mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 17, rd_data_setup, tb_clk);
+    rd_cep_udp_src_port <= rd_data_setup(15 downto 0);
+    -- . Read back destination MAC/IP/UDP via c_mm_file_reg_hdr_dat_tbuf
+    mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 34, rd_data_setup, tb_clk);
+    rd_cep_eth_dst_mac(47 downto 32) <= rd_data_setup(15 downto 0);
+    mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 33, rd_data_setup, tb_clk);
+    rd_cep_eth_dst_mac(31 downto 0) <= rd_data_setup;
+    mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 18, rd_data_setup, tb_clk);
+    rd_cep_ip_dst_addr <= rd_data_setup;
+    mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 16, rd_data_setup, tb_clk);
+    rd_cep_udp_dst_port <= rd_data_setup(15 downto 0);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    -- . verify read back source MAC/IP/UDP
+    assert rd_cep_eth_src_mac = c_cep_eth_src_mac
+      report c_tb_str & "Wrong MM read rd_cep_eth_src_mac for dump"
+      severity ERROR;
+    assert rd_cep_ip_src_addr = c_cep_ip_src_addr
+      report c_tb_str & "Wrong MM read rd_cep_ip_src_addr for dump"
+      severity ERROR;
+    assert rd_cep_udp_src_port = c_cep_udp_src_port
+      report c_tb_str & "Wrong MM read rd_cep_udp_src_port for dump"
+      severity ERROR;
+    -- . verify read back destination MAC/IP/UDP
+    assert rd_cep_eth_dst_mac = c_sdp_cep_eth_dst_mac
+      report c_tb_str & "Wrong MM read rd_cep_eth_dst_mac for dump"
+      severity ERROR;
+    assert rd_cep_ip_dst_addr = c_sdp_cep_ip_dst_addr
+      report c_tb_str & "Wrong MM read rd_cep_ip_dst_addr for dump"
+      severity ERROR;
+    assert rd_cep_udp_dst_port = c_sdp_cep_udp_dst_port
+      report c_tb_str & "Wrong MM read rd_cep_udp_dst_port for dump"
+      severity ERROR;
+
+    ----------------------------------------------------------------------------
+    -- Read DDR4 memory status
+    ----------------------------------------------------------------------------
+    mmf_mm_bus_rd(c_mm_file_reg_io_ddr_mb_i, 0, rd_data_setup, tb_clk);
+    ddr_status <= rd_data_setup;
+    proc_common_wait_some_cycles(tb_clk, 1);
+
+    -- . verify dvr_done for calibration ok
+    ddr_dvr_done <= ddr_status(0);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    assert ddr_dvr_done = '1'
+      report c_tb_str & "Wrong no DDR MB_I"
+      severity ERROR;
+
+    -- . verify ddr_ctlr_nof_bytes_per_word
+    ddr_ctlr_nof_bytes_per_word <= TO_UINT(ddr_status(15 downto 8));
+    proc_common_wait_some_cycles(tb_clk, 1);
+    assert ddr_ctlr_nof_bytes_per_word = c_exp_ddr_ctlr_nof_bytes_per_word
+      report c_tb_str & "Wrong read ddr_ctlr_nof_bytes_per_word"
+      severity ERROR;
+
+    ----------------------------------------------------------------------------
+    -- Enable BS
+    ----------------------------------------------------------------------------
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 2, c_init_bsn, tb_clk);  -- Init BSN
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 3, 0, tb_clk);  -- Write high part activates the init BSN
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 1, c_bs_nof_clk_per_sync, tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 0, 16#00000003#, tb_clk);  -- Enable BS at PPS
+
+    -- Release PPS pulser, to get first PPS now and to start BSN source
+    wait for 100 ns;
+    pps_rst <= '0';
+
+    ----------------------------------------------------------------------------
+    -- Enable WG
+    ----------------------------------------------------------------------------
+    --   0 : mode[7:0]           --> off=0, calc=1, repeat=2, single=3)
+    --       nof_samples[31:16]  --> <= c_ram_wg_size=1024
+    --   1 : phase[15:0]
+    --   2 : freq[30:0]
+    --   3 : ampl[16:0]
+    -- Put DC signal on all SP
+    for S in 0 to c_sdp_S_pn - 1 loop
+      v_offset := S * c_mm_span_reg_diag_wg;
+      -- use WG ampl = sp index, phase = 90 and freq = 0 to have DC level = sp index
+      v_norm_ampl := real(S) / real(c_sdp_FS_adc);
+      mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 0, 1024 * 2**16 + 1, tb_clk);  -- nof_samples, mode calc
+      mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, integer(90.0 * c_diag_wg_phase_unit), tb_clk);
+      mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 2, 0, tb_clk);
+      mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, integer(v_norm_ampl * c_diag_wg_ampl_unit), tb_clk);
+    end loop;
+
+    -- Read current BSN
+    mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 0, current_bsn_wg(31 downto  0), tb_clk);
+    mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 1, current_bsn_wg(63 downto 32), tb_clk);
+    proc_common_wait_some_cycles(tb_clk, 1);
+
+    -- Write scheduler BSN to trigger start of WG at next block
+    v_bsn := TO_UINT(current_bsn_wg) + 2;
+    assert v_bsn <= c_bsn_start_wg
+      report c_tb_str & "Too late to start WG: " & int_to_str(v_bsn) & " > " & int_to_str(c_bsn_start_wg)
+      severity ERROR;
+    v_bsn := c_bsn_start_wg;
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_scheduler_wg, 0, v_bsn, tb_clk);  -- first write low then high part
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_scheduler_wg, 1,     0, tb_clk);  -- assume v_bsn < 2**31-1
+
+    ----------------------------------------------------------------------------
+    -- Wait until WG has started
+    ----------------------------------------------------------------------------
+    mmf_mm_wait_until_value(
+        c_mm_file_reg_bsn_scheduler_wg, 0,  -- read BSN low part
+        "UNSIGNED", rd_data_bsn, ">=", c_bsn_start_wg,  -- this is the wait until condition
+        c_T_bs_period, ext_clk);
+
+    -- WG started
+    wg_started <= '1';
+
+    ----------------------------------------------------------------------------
+    -- Wait for enough WG data
+    ----------------------------------------------------------------------------
+    proc_common_wait_until_high(ext_clk, tb_almost_end);
+
+    ---------------------------------------------------------------------------
+    -- End simulation
+    ---------------------------------------------------------------------------
+    proc_common_wait_some_cycles(ext_clk, 100);  -- delay for ease of view in Wave window
+    proc_common_stop_simulation(g_tb_end, g_tb_index, 0, ext_clk, tb_almost_end, i_tb_end);
+    wait;
+  end process;
+
+  p_mm_tbuf_control : process
+    variable v_bool               : boolean;
+    variable v_offset             : natural;
+    variable v_recorded_nof_pages : natural;
+    variable v_Begin              : natural;
+    variable v_End                : natural;
+    variable v_Period             : real := 0.0;
+    variable v_dump_rate_bps      : real := 0.0;
+    variable v_dump_start_page    : natural;
+    variable v_dump_start_rsn     : std_logic_vector(c_sdp_W_rsn - 1 downto 0);
+  begin
+    -- Init tbuf_registers_wr record
+    tbuf_registers_wr.record_all            <= '1';                      -- 2
+    tbuf_registers_wr.record_enable         <= '1';                      -- 3
+    tbuf_registers_wr.dump_inter_packet_gap <= g_dump_inter_packet_gap;  -- 11
+    tbuf_registers_wr.dump_start_page       <= 0;                        -- 12
+    tbuf_registers_wr.dump_nof_pages        <= c_dump_nof_pages_rw;      -- 13
+    tbuf_registers_wr.dump_start_rsn        <= (others => 'X');          -- 14
+    tbuf_registers_wr.dump_enables          <= (others => '0');          -- 16
+
+    -- Wait for DUT power up after reset
+    wait for 200 ns;
+    --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(461603339, 32));
+    --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(461602827, 32));
+    --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(515, 32));
+    --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(741, 32));
+    --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(3, 32));
+
+    ----------------------------------------------------------------------------
+    -- Record all antennas
+    ----------------------------------------------------------------------------
+    mmf_mm_bus_wr(c_mm_file_reg_tbuf, 2, to_int(tbuf_registers_wr.record_all), tb_clk);
+
+    ----------------------------------------------------------------------------
+    -- Enable packet dump output
+    ----------------------------------------------------------------------------
+    mmf_mm_bus_wr(c_mm_file_reg_dp_xonoff_tbuf, 0, 1, tb_clk);
+    mmf_mm_bus_wr(c_mm_file_reg_tbuf, 11, tbuf_registers_wr.dump_inter_packet_gap, tb_clk);
+
+    ----------------------------------------------------------------------------
+    -- Report and verify sizes
+    ----------------------------------------------------------------------------
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 0, rd_data_control, tb_clk);
+    tbuf_registers_ro.nof_samples_per_block <= to_uint(rd_data_control);
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 1, rd_data_control, tb_clk);
+    tbuf_registers_ro.nof_pages_in_buffer <= to_uint(rd_data_control);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    assert tbuf_registers_ro.nof_samples_per_block = g_rs_block_size
+      report c_tb_str & "Wrong tbuf_registers_ro.nof_samples_per_block "
+      severity ERROR;
+    assert tbuf_registers_ro.nof_pages_in_buffer = c_nof_pages_in_buffer
+      report c_tb_str & "Wrong tbuf_registers_ro.nof_pages_in_buffer "
+      severity ERROR;
+    print_str(c_tb_str & "tbuf_registers_ro.nof_samples_per_block = " &
+                                                                   int_to_str(tbuf_registers_ro.nof_samples_per_block));
+    print_str(c_tb_str & "tbuf_registers_ro.nof_pages_in_buffer   = " &
+                                                                     int_to_str(tbuf_registers_ro.nof_pages_in_buffer));
+
+    ----------------------------------------------------------------------------
+    -- RECORD
+    ----------------------------------------------------------------------------
+    print_str(c_tb_str & "--------------------------------------------");
+    print_str(c_tb_str & "-- RECORD");
+    print_str(c_tb_str & "--------------------------------------------");
+    -- Enable recording
+    proc_common_wait_until_high(ext_clk, wg_started);
+    mmf_mm_bus_wr(c_mm_file_reg_tbuf, 3, to_int(tbuf_registers_wr.record_enable), tb_clk);
+    proc_common_wait_cross_clock_domain_latency(
+        c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2);
+    -- Read back record_enable
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 3, rd_data_control, tb_clk);
+    tbuf_registers_rd.record_enable <= rd_data_control(0);
+    -- Read record_busy, wait one rs_block for record_enable to take effect
+    proc_common_wait_some_cycles(ext_clk, g_rs_block_size);
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 18, rd_data_record_busy, tb_clk);
+    tbuf_registers_ro.record_busy <= rd_data_record_busy(0);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    assert tbuf_registers_rd.record_enable = '1'
+      report c_tb_str & "Wrong tbuf_registers_rd.record_enable /= '1'"
+      severity ERROR;
+    assert tbuf_registers_ro.record_busy = '1'
+      report c_tb_str & "Wrong tbuf_registers_ro.record_busy /= '1'"
+      severity ERROR;
+    print_str(c_tb_str & "tbuf_registers_rd.record_enable = " & sl_to_str(tbuf_registers_rd.record_enable));
+    print_str(c_tb_str & "tbuf_registers_ro.record_busy = " & sl_to_str(tbuf_registers_ro.record_busy));
+
+    -- Read TBuf state
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 19, rd_data_state, tb_clk);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    v_bool := func_sdp_tbuf_print_state(c_tb_str, rd_data_state);
+
+    -- Recording
+    proc_common_wait_some_cycles(ext_clk, g_rs_block_size * g_rs_record_nof_block);
+
+    -- Read BSN monitor for recording data
+    mmf_mm_bus_rd(c_mm_file_reg_bsn_monitor_v2_tbuf, 1, rd_data_monitor, tb_clk);  -- bsn at sync
+    recording_rsn_at_sync <= to_uint(rd_data_monitor);
+    mmf_mm_bus_rd(c_mm_file_reg_bsn_monitor_v2_tbuf, 3, rd_data_monitor, tb_clk);  -- nof_sop
+    recording_nof_sop_per_sync <= to_uint(rd_data_monitor);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    assert recording_nof_sop_per_sync = c_rs_nof_block_per_sync
+      report c_tb_str & "Wrong RSN monitor nof blocks per sync"
+      severity ERROR;
+    print_str(c_tb_str & "recording_rsn_at_sync = " & int_to_str(recording_rsn_at_sync));
+    print_str(c_tb_str & "recording_nof_sop_per_sync = " & int_to_str(recording_nof_sop_per_sync));
+
+    ----------------------------------------------------------------------------
+    -- FREEZE
+    ----------------------------------------------------------------------------
+    print_str(c_tb_str & "--------------------------------------------");
+    print_str(c_tb_str & "-- FREEZE ");
+    print_str(c_tb_str & "--------------------------------------------");
+    -- Disable recording
+    tbuf_registers_wr.record_enable <= '0';
+    proc_common_wait_some_cycles(tb_clk, 1);
+    mmf_mm_bus_wr(c_mm_file_reg_tbuf, 3, to_int(tbuf_registers_wr.record_enable), tb_clk);
+    proc_common_wait_cross_clock_domain_latency(
+        c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2);
+    -- Read disabled recording
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 3, rd_data_control, tb_clk);
+    tbuf_registers_rd.record_enable <= rd_data_control(0);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    assert tbuf_registers_rd.record_enable = '0'
+      report c_tb_str & "Wrong tbuf_registers_rd.record_enable /= '0'"
+      severity ERROR;
+    -- Wait until recording has finished, read record_busy to account for latency in record_enable disabled
+    mmf_mm_wait_until_value(
+        c_mm_file_reg_tbuf, 18,  -- read record_busy
+        "UNSIGNED", rd_data_record_busy, "=", 0,  -- this is the wait until condition
+        c_T_rd_interval, ext_clk);
+    tbuf_registers_ro.record_busy <= rd_data_record_busy(0);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    print_str(c_tb_str & "tbuf_registers_rd.record_enable = " & sl_to_str(tbuf_registers_rd.record_enable));
+    print_str(c_tb_str & "tbuf_registers_ro.record_busy = " & sl_to_str(tbuf_registers_ro.record_busy));
+
+    -- Read number of recorded pages
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 4, rd_data_control, tb_clk);
+    tbuf_registers_ro.recorded_nof_pages <= to_uint(rd_data_control);
+
+    -- Read indices of first and last recorded page
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 5, rd_data_control, tb_clk);
+    tbuf_registers_ro.recorded_first_page <= to_uint(rd_data_control);
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 6, rd_data_control, tb_clk);
+    tbuf_registers_ro.recorded_last_page <= to_uint(rd_data_control);
+    proc_common_wait_some_cycles(tb_clk, 1);
+
+    v_recorded_nof_pages := tbuf_registers_ro.recorded_last_page - tbuf_registers_ro.recorded_first_page;
+    if v_recorded_nof_pages <= 0 then
+        v_recorded_nof_pages := v_recorded_nof_pages + tbuf_registers_ro.nof_pages_in_buffer;
+    end if;
+    assert tbuf_registers_ro.recorded_nof_pages > 0
+      report c_tb_str & "Wrong tbuf_registers_ro.recorded_nof_pages = 0"
+      severity ERROR;
+    assert tbuf_registers_ro.recorded_nof_pages = v_recorded_nof_pages
+      report c_tb_str &
+             "Wrong tbuf_registers_ro.recorded_nof_pages does not match recorded_first_page and recorded_last_page"
+      severity ERROR;
+
+    -- Read timestamps of first and last recorded page
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 7, rd_data_control, tb_clk);  -- read low part
+    tbuf_registers_ro.recorded_first_rsn(31 downto 0) <= rd_data_control;
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 8, rd_data_control, tb_clk);  -- read high part
+    tbuf_registers_ro.recorded_first_rsn(63 downto 32) <= rd_data_control;
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 9, rd_data_control, tb_clk);  -- read low part
+    tbuf_registers_ro.recorded_last_rsn(31 downto 0) <= rd_data_control;
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 10, rd_data_control, tb_clk);  -- read high part
+    tbuf_registers_ro.recorded_last_rsn(63 downto 32) <= rd_data_control;
+    proc_common_wait_some_cycles(tb_clk, 1);
+    assert to_uint(tbuf_registers_ro.recorded_last_rsn) - to_uint(tbuf_registers_ro.recorded_first_rsn) =
+           v_recorded_nof_pages * g_rs_block_size
+      report c_tb_str & "Wrong tbuf_registers_ro.recorded_last_rsn - tbuf_registers_ro.recorded_first_rsn"
+      severity ERROR;
+
+    -- Check that record_all = '1'
+    mmf_mm_bus_rd(c_mm_file_reg_tbuf, 2, rd_data_control, tb_clk);
+    tbuf_registers_rd.record_all <= rd_data_control(0);
+    proc_common_wait_some_cycles(tb_clk, 1);
+    assert tbuf_registers_rd.record_all = '1'
+      report c_tb_str & "Wrong tbuf_registers_rd.record_all /= 1"
+      severity ERROR;
+    print_str(c_tb_str & "tbuf_registers_rd.record_all            = " & sl_to_str(tbuf_registers_rd.record_all));
+    print_str(c_tb_str & "tbuf_registers_ro.nof_samples_per_block = " &
+                                                                   int_to_str(tbuf_registers_ro.nof_samples_per_block));
+    print_str(c_tb_str & "tbuf_registers_ro.nof_pages_in_buffer   = " &
+                                                                     int_to_str(tbuf_registers_ro.nof_pages_in_buffer));
+    print_str(c_tb_str & "tbuf_registers_ro.recorded_nof_pages    = " &
+                                                                      int_to_str(tbuf_registers_ro.recorded_nof_pages));
+    print_str(c_tb_str & "tbuf_registers_ro.recorded_first_page   = " &
+                                                                     int_to_str(tbuf_registers_ro.recorded_first_page));
+    print_str(c_tb_str & "tbuf_registers_ro.recorded_last_page    = " &
+                                                                      int_to_str(tbuf_registers_ro.recorded_last_page));
+    print_str(c_tb_str & "tbuf_registers_ro.recorded_first_rsn    = " &
+                                                             int_to_str(to_uint(tbuf_registers_ro.recorded_first_rsn)));
+    print_str(c_tb_str & "tbuf_registers_ro.recorded_last_rsn     = " &
+                                                              int_to_str(to_uint(tbuf_registers_ro.recorded_last_rsn)));
+
+    ----------------------------------------------------------------------------
+    -- DUMP
+    ----------------------------------------------------------------------------
+    -- Wait until nw_10GbE xon = '1'
+    while NOW < 11 us loop
+      wait for 100 ns;
+    end loop;
+
+    for DUMP in 0 to c_nof_dump - 1 loop
+      tb_dump_cnt <= tb_dump_cnt + 1;
+      proc_common_wait_some_cycles(tb_clk, 1);
+      print_str(c_tb_str & "--------------------------------------------");
+      print_str(c_tb_str & "-- DUMP : " & int_to_str(tb_dump_cnt));
+      print_str(c_tb_str & "--------------------------------------------");
+
+      -- Clear dump strobe_total_counts
+      mmf_mm_bus_wr(c_mm_file_reg_strobe_total_count_tbuf, c_sdp_tbuf_nof_strobe_total_counts_clear_id, 1, tb_clk);
+      proc_common_wait_cross_clock_domain_latency(
+          c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2);
+
+      -- Set dump interval and antenna inputs
+      v_dump_start_page := tbuf_registers_ro.recorded_first_page + g_dump_page_offset;
+      if v_dump_start_page >= c_nof_pages_in_buffer then
+        -- Wrap from begin of buffer when v_dump_start_page is just beyond the end of buffer. Do not use modulo
+        -- c_nof_pages_in_buffer to be able to simulate effect of a much too large v_dump_start_page due to
+        -- g_dump_page_offset >= c_nof_pages_in_buffer
+        v_dump_start_page := v_dump_start_page - c_nof_pages_in_buffer;
+      end if;
+      tbuf_registers_wr.dump_start_page <= v_dump_start_page;
+      v_dump_start_rsn := incr_uvec(tbuf_registers_ro.recorded_first_rsn, g_dump_page_offset * g_rs_block_size);
+      tbuf_registers_wr.dump_start_rsn <= v_dump_start_rsn;
+      tbuf_registers_wr.dump_enables <= g_dump_enables;
+      proc_common_wait_some_cycles(tb_clk, 1);
+      mmf_mm_bus_wr(c_mm_file_reg_tbuf, 12, tbuf_registers_wr.dump_start_page, tb_clk);
+      mmf_mm_bus_wr(c_mm_file_reg_tbuf, 13, tbuf_registers_wr.dump_nof_pages, tb_clk);
+      mmf_mm_bus_wr(c_mm_file_reg_tbuf, 14, to_uint(tbuf_registers_wr.dump_start_rsn), tb_clk);
+      mmf_mm_bus_wr(c_mm_file_reg_tbuf, 16, to_uint(tbuf_registers_wr.dump_enables), tb_clk);
+      proc_common_wait_cross_clock_domain_latency(
+          c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2);
+
+      if g_dump_nof_pages > 0 then
+        -- Time dump begin
+        read_busy <= '1';
+        v_Begin := NOW / c_1ns;
+        proc_common_wait_some_cycles(tb_clk, 1);
+
+        -- Read back enabled dump
+        mmf_mm_bus_rd(c_mm_file_reg_tbuf, 16, rd_data_control, tb_clk);
+        tbuf_registers_rd.dump_enables <= rd_data_control(c_sdp_A_pn - 1 downto 0);
+        proc_common_wait_some_cycles(tb_clk, 1);
+        assert to_uint(tbuf_registers_rd.dump_enables) = to_uint(tbuf_registers_wr.dump_enables)
+          report c_tb_str & "Wrong tbuf_registers_rd.dump_enables enabled"
+          severity ERROR;
+        print_str(c_tb_str & "tbuf_registers_rd.dump_enables = " & slv_to_str(tbuf_registers_rd.dump_enables));
+
+        ----------------------------------------------------------------------------
+        -- Wait until dump is done
+        ----------------------------------------------------------------------------
+        mmf_mm_wait_until_value(
+            c_mm_file_reg_tbuf, 17,  -- read dump_done
+            "UNSIGNED", rd_data_dump_done, "=", 1,  -- this is the wait until condition
+            c_T_rd_interval, ext_clk);
+        tbuf_registers_ro.dump_done <= rd_data_dump_done(0);
+        proc_common_wait_some_cycles(tb_clk, 1);
+
+        -- Time dump end
+        read_busy <= '0';
+        v_End := NOW / c_1ns;
+        v_Period := real(v_End - v_Begin) * 1.0e-9;  -- dump time in s
+        v_dump_rate_bps := real(c_dump_total_nof_packets * c_sdp_W_ant * g_rs_block_size) / v_Period;
+        dump_rate_bps <= v_dump_rate_bps;
+
+        -- Verify dump rate over sufficient number of packets
+        if c_dump_total_nof_packets > 5 then
+          -- . use almost_equal(a/b, 1.0, max_ratio) to verify that a and b differ less than max_ratio/100 percent
+          assert almost_equal(v_dump_rate_bps / c_exp_dump_rate_bps, 1.0, c_dump_rate_delta)
+            report c_tb_str & "Wrong dump rate"
+            severity ERROR;
+        end if;
+        print_str(c_tb_str & "Dump rate = " & real_to_str(v_dump_rate_bps / c_Gbps, 4, 2) & " Gbps" &
+                  " (Expected " & real_to_str(c_exp_dump_rate_bps / c_Gbps, 4, 2) & " Gbps)");
+      end if;
+
+      -- Wait some time for latency in sdp_tbuf_output and 10GbE Tx - Rx network
+      proc_common_wait_some_cycles(ext_clk, g_rs_block_size * 4);
+      rx_done <= '1';
+
+      -- Read strobe_total_counts
+      mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 0, rd_data_strobe, tb_clk);
+      tbuf_strobe_total_counts.memory_read_nof_packets <= to_uint(rd_data_strobe);
+      mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 2, rd_data_strobe, tb_clk);
+      tbuf_strobe_total_counts.memory_read_nof_crc_errors <= to_uint(rd_data_strobe);
+      mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 4, rd_data_strobe, tb_clk);
+      tbuf_strobe_total_counts.memory_read_nof_rsn_errors <= to_uint(rd_data_strobe);
+      mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 6, rd_data_strobe, tb_clk);
+      tbuf_strobe_total_counts.memory_read_dumped_nof_packets <= to_uint(rd_data_strobe);
+      mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 8, rd_data_strobe, tb_clk);
+      tbuf_strobe_total_counts.memory_ring_rx_nof_packets <= to_uint(rd_data_strobe);
+      mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 10, rd_data_strobe, tb_clk);
+      tbuf_strobe_total_counts.memory_ring_tx_nof_packets <= to_uint(rd_data_strobe);
+      mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 12, rd_data_strobe, tb_clk);
+      tbuf_strobe_total_counts.memory_output_nof_packets <= to_uint(rd_data_strobe);
+      proc_common_wait_some_cycles(tb_clk, 1);
+      assert tbuf_strobe_total_counts.memory_read_nof_packets = c_read_total_nof_packets
+        report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_read_nof_packets"
+        severity ERROR;
+      assert tbuf_strobe_total_counts.memory_read_nof_crc_errors = c_read_nof_crc_errors
+        report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_read_nof_crc_errors"
+        severity ERROR;
+      assert tbuf_strobe_total_counts.memory_read_nof_rsn_errors = c_read_nof_rsn_errors
+        report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_read_nof_rsn_errors"
+        severity ERROR;
+      assert tbuf_strobe_total_counts.memory_read_dumped_nof_packets = c_dump_total_nof_packets
+        report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_read_dumped_nof_packets"
+        severity ERROR;
+      assert tbuf_strobe_total_counts.memory_ring_rx_nof_packets = 0
+        report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_ring_rx_nof_packets"
+        severity ERROR;
+      assert tbuf_strobe_total_counts.memory_ring_tx_nof_packets = c_dump_total_nof_packets
+        report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_ring_tx_nof_packets"
+        severity ERROR;
+      assert tbuf_strobe_total_counts.memory_output_nof_packets = c_dump_total_nof_packets
+        report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_output_nof_packets"
+        severity ERROR;
+      print_str(c_tb_str & "tbuf_strobe_total_counts.memory_read_nof_packets = " &
+                                                            int_to_str(tbuf_strobe_total_counts.memory_read_nof_packets));
+      print_str(c_tb_str & "tbuf_strobe_total_counts.memory_read_nof_crc_errors = " &
+                                                         int_to_str(tbuf_strobe_total_counts.memory_read_nof_crc_errors));
+      print_str(c_tb_str & "tbuf_strobe_total_counts.memory_read_nof_rsn_errors = " &
+                                                         int_to_str(tbuf_strobe_total_counts.memory_read_nof_rsn_errors));
+      print_str(c_tb_str & "tbuf_strobe_total_counts.memory_read_dumped_nof_packets = " &
+                                                     int_to_str(tbuf_strobe_total_counts.memory_read_dumped_nof_packets));
+      print_str(c_tb_str & "tbuf_strobe_total_counts.memory_ring_rx_nof_packets = " &
+                                                         int_to_str(tbuf_strobe_total_counts.memory_ring_rx_nof_packets));
+      print_str(c_tb_str & "tbuf_strobe_total_counts.memory_ring_tx_nof_packets = " &
+                                                         int_to_str(tbuf_strobe_total_counts.memory_ring_tx_nof_packets));
+      print_str(c_tb_str & "tbuf_strobe_total_counts.memory_output_nof_packets = " &
+                                                          int_to_str(tbuf_strobe_total_counts.memory_output_nof_packets));
+
+      -- Read REG_NW_10GBE_MAC counts
+      -- . In sim via si_lpbk_0 loopback on own port, on HW using another node on unb2c as dump destination
+      -- . Only need to read low word part of rx_stats_etherstatspkts[35:0]
+      -- . Expect at least tbuf_strobe_total_counts.memory_output_nof_packets, there can be more when the nw_10gbe
+      --   does an ARP.
+      mmf_mm_bus_rd(c_mm_file_reg_nw_10gbe_mac, 16#C1C#, rd_data_nw_10gbe_mac, tb_clk);
+      rx_stats_etherstatspkts <= TO_UINT(rd_data_nw_10gbe_mac);
+      proc_common_wait_some_cycles(tb_clk, 1);
+      assert rx_stats_etherstatspkts >= tbuf_strobe_total_counts.memory_output_nof_packets
+        report c_tb_str & "Wrong rx_stats_etherstatspkts"
+        severity ERROR;
+      print_str(c_tb_str & "rx_stats_etherstatspkts = " & int_to_str(rx_stats_etherstatspkts));
+
+      -- Disable dump
+      proc_common_wait_some_cycles(ext_clk, 100);  -- delay for ease of view in Wave window
+      tbuf_registers_wr.dump_enables <= (others => '0');
+      proc_common_wait_some_cycles(tb_clk, 1);
+      mmf_mm_bus_wr(c_mm_file_reg_tbuf, 16, to_uint(tbuf_registers_wr.dump_enables), tb_clk);
+      proc_common_wait_cross_clock_domain_latency(
+          c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2);
+      -- Read back disabled dump
+      mmf_mm_bus_rd(c_mm_file_reg_tbuf, 16, rd_data_control, tb_clk);
+      tbuf_registers_rd.dump_enables <= rd_data_control(c_sdp_A_pn - 1 downto 0);
+      proc_common_wait_some_cycles(tb_clk, 1);
+      assert to_uint(tbuf_registers_rd.dump_enables) = to_uint(tbuf_registers_wr.dump_enables)
+        report c_tb_str & "Wrong tbuf_registers_rd.dump_enables disabled"
+        severity ERROR;
+      -- Read dump_done to check that it is '0'
+      mmf_mm_bus_rd(c_mm_file_reg_tbuf, 17, rd_data_dump_done, tb_clk);
+      tbuf_registers_ro.dump_done <= rd_data_dump_done(0);
+      proc_common_wait_some_cycles(tb_clk, 1);
+      assert tbuf_registers_ro.dump_done = '0'
+        report c_tb_str & "Wrong tbuf_registers_ro.dump_done"
+        severity ERROR;
+      print_str(c_tb_str & "tbuf_registers_rd.dump_enables = " & slv_to_str(tbuf_registers_rd.dump_enables));
+      print_str(c_tb_str & "tbuf_registers_ro.dump_done = " & sl_to_str(tbuf_registers_ro.dump_done));
+    end loop;
+
+    ---------------------------------------------------------------------------
+    -- Almost end simulation
+    ---------------------------------------------------------------------------
+    tb_almost_end <= '1';
+    wait;
+  end process;
+
+  -----------------------------------------------------------------------------
+  -- Verify TBuf dump packet header
+  -----------------------------------------------------------------------------
+  -- Prepare exp_dump_header before rx_dump_sosi.eop.
+  exp_dump_header <= func_sdp_tbuf_compose_cep_header(c_cep_ip_src_addr,
+                                                      c_exp_ip_header_checksum,
+                                                      c_exp_sdp_info,
+                                                      c_gn_index,
+                                                      c_sdp_W_adc,
+                                                      exp_dump_ai,
+                                                      g_rs_block_size,
+                                                      exp_dp_rsn);
+  exp_dump_station_info <= func_sdp_map_station_info(exp_dump_header.app.sdp_station_info);
+  rx_dump_station_info <= func_sdp_map_station_info(rx_dump_header.app.sdp_station_info);
+
+  p_verify_rx_dump_header : process
+    variable v_dump_index : natural;
+    variable v_time_index : natural;
+    variable v_ai_local   : natural;
+    variable v_cnt        : natural;
+    variable v_bool       : boolean;
+  begin
+    wait until rising_edge(ext_clk);
+    if c_dump_nof_packets_per_ai > 0 then
+      -- Count rx_dump_sosi packets at sop
+      if rx_dump_sosi.sop = '1' then
+        -- Determine expected antenna_input_index assuming c_dump_nof_packets_per_ai per ai. Use modulo
+        -- c_dump_nof_packets_per_loop to account for c_nof_dump > 1
+        v_cnt := rx_dump_packet_cnt mod c_dump_nof_packets_per_loop;
+        v_dump_index := v_cnt / c_dump_nof_packets_per_ai;
+        v_ai_local := c_dump_ai_indices(v_dump_index);
+        exp_dump_ai <= c_ai_offset + v_ai_local;
+
+        -- Determine expected RSN assuming c_dump_nof_packets_per_ai per ai
+        v_time_index := v_cnt mod c_dump_nof_packets_per_ai;
+        exp_dp_rsn <= to_uint(tbuf_registers_wr.dump_start_rsn) + v_time_index * g_rs_block_size;
+
+        -- Increment rx_dump_packet_cnt signal
+        rx_dump_packet_cnt <= rx_dump_packet_cnt + 1;
+      end if;
+      -- Verify header at eop
+      if rx_dump_sosi.eop = '1' then
+        v_bool := func_sdp_tbuf_verify_cep_header(rx_dump_header, exp_dump_header);
+      end if;
+      -- View variables in Wave Window
+      dump_index <= v_dump_index;
+      time_index <= v_time_index;
+    else
+      -- Expect no dump packets when g_dump_nof_pages = 0
+      assert rx_dump_sosi.sop = '0'
+        report c_tb_str & "Wrong unexpected rx_dump_sosi packet for g_dump_nof_pages = 0"
+        severity ERROR;
+    end if;
+  end process;
+
+  -----------------------------------------------------------------------------
+  -- Verify TBuf dump packet data
+  -----------------------------------------------------------------------------
+  p_verify_rx_dump_block_length : process
+    variable v_cnt : natural;
+  begin
+    wait until rising_edge(ext_clk);
+    -- Count received data per rs_block
+    if rx_ant_sosi.sop = '1' then
+      v_cnt := 1;
+    elsif rx_ant_sosi.valid = '1' then
+      v_cnt := v_cnt + 1;
+    end if;
+    if rx_ant_sosi.eop = '1' then
+      rx_dump_length <= v_cnt;
+    end if;
+    rx_dump_length_cnt <= v_cnt;
+    -- Verify received g_rs_block_size
+    if rx_ant_sosi.valid = '1' then
+      assert v_cnt <= g_rs_block_size
+        report c_tb_str & "Wrong rx_ant_sosi block length too long"
+        severity ERROR;
+    end if;
+    if rx_ant_sosi.eop = '1' then
+      assert v_cnt = g_rs_block_size
+        report c_tb_str & "Wrong rx_ant_sosi block length"
+        severity ERROR;
+    end if;
+  end process;
+
+  -- Verify the SP that have their WG set to DC data equal to their sp index value
+  p_verify_rx_dump_block_dc_data : process
+    variable v_sp : natural;
+  begin
+    wait until rising_edge(ext_clk);
+    rx_ant_dc_data_err <= '0';
+    if rx_ant_sosi.valid = '1' then
+      for I in 0 to c_sdp_N_pol - 1 loop
+        v_sp := rx_ant_index * c_sdp_N_pol + I;
+        if to_uint(rx_ant_data_arr(I)) /= v_sp then
+          rx_ant_dc_data_err <= '1';
+           report c_tb_str & "Wrong rx_ant_sosi block DC data for SP " & int_to_str(v_sp)
+            severity ERROR;
+        end if;
+      end loop;
+    end if;
+  end process;
+end tb;
diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..4ed2e49f14a508d8fab43a4fda322be35025d615
--- /dev/null
+++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd
@@ -0,0 +1,64 @@
+-- --------------------------------------------------------------------------
+-- Copyright 2025
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+-- --------------------------------------------------------------------------
+--
+-- Author: E. Kooistra, 28 may 2025
+-- Purpose: Regression multi tb for tb_lofar2_unb2c_sdp_station_tbuf_ring
+-- Description:
+--   The multi tb only has one instance, so the tb_tb is more a wrapper to
+--   ensure that always the same tb generics are used in the regression test.
+--   This allows modifying the generics in the tb.
+-- Usage:
+-- . Modelsim:
+--   > as 4
+--   > as 8  # debug to view tbuf states
+--   > run -all
+-- . Terminal:
+--   > cat transcript | grep Error:
+
+library IEEE, common_lib;
+use IEEE.std_logic_1164.all;
+use common_lib.tb_common_pkg.all;
+
+entity tb_tb_lofar2_unb2c_sdp_station_tbuf_ring is
+end tb_tb_lofar2_unb2c_sdp_station_tbuf_ring;
+
+architecture tb of tb_tb_lofar2_unb2c_sdp_station_tbuf_ring is
+  -- Multi tb
+  -- . Use tb index offset c_tbi to avoid file IO conflict during modelsim_regression_test_vhdl.py with other tb, like
+  --   tb_lofar2_unb2c_sdp_station_bf_ring, in shared HDL_IOFILE_SIM_DIR = build/sim directory set by init_hdl.sh.
+  constant c_tbi        : natural := 30;
+  constant c_tb_end_vec : std_logic_vector(c_tbi to c_tbi) := (others => '1');
+
+  signal tb_end_vec   : std_logic_vector(c_tb_end_vec'range) := c_tb_end_vec;  -- best view as hex in Wave Window
+  signal tb_end       : std_logic := '0';
+begin
+  u_tbuf_ring : entity work.tb_lofar2_unb2c_sdp_station_tbuf_ring
+  generic map (
+    g_tb_index              => c_tbi,
+    g_ddr_buffer_size       => 256,  -- <= 4096, because c_tech_ddr4_sim_4k_64 has 4k = 4096 words of
+                                     -- c_sdp_tbuf_W_word = 512b
+    g_rs_block_size         => 100,  -- c_sdp_tbuf_rs_block_size = 2000, must be even see sdp_tbuf_output
+    g_rs_record_nof_block   => 3,  -- choose > c_rs_nof_block_per_sync to have at least on sync interval
+                                   -- for the RSN monitor
+    g_dump_inter_packet_gap => 0,  -- use 1708 for 3 Gbps and g_rs_block_size = 2000
+    g_dump_page_offset      => 0,  -- offset relative to recorded_first_page
+    g_dump_nof_pages        => 3,  -- g_dump_page_offset + g_dump_nof_pages <= g_rs_record_nof_block, else
+                                   -- there will occur read RSN errors for pages that are not available
+    g_dump_enables          => "111111"
+  );
+end tb;
diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd
index 677d29d58643c2b9f09c4984cd62aa313f7d8783..c348d4b8377e449150ecf98a4d8e9bc579db003e 100644
--- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd
+++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd
@@ -60,6 +60,8 @@ package lofar2_unb2c_sdp_station_pkg is
                                                          (false, true,  false, false, false, 1, true,  false, true,  9);
   constant c_tbuf_one   : t_lofar2_unb2c_sdp_station_config :=
                                                          (false, false, false, false, false, 1, false, true,  false, 0);
+  constant c_tbuf_ring  : t_lofar2_unb2c_sdp_station_config :=
+                                                         (false, false, false, false, false, 1, false, true,  true,  0);
   constant c_full_wg    : t_lofar2_unb2c_sdp_station_config :=
                                                          (true,  true,  false, true,  true,  1, true,  false, true,  9);
   constant c_full       : t_lofar2_unb2c_sdp_station_config :=
@@ -86,6 +88,7 @@ package body lofar2_unb2c_sdp_station_pkg is
     elsif g_design_name = "lofar2_unb2c_sdp_station_xsub_one"  then return c_xsub_one;
     elsif g_design_name = "lofar2_unb2c_sdp_station_xsub_ring" then return c_xsub_ring;
     elsif g_design_name = "lofar2_unb2c_sdp_station_tbuf_one"  then return c_tbuf_one;
+    elsif g_design_name = "lofar2_unb2c_sdp_station_tbuf_ring" then return c_tbuf_ring;
     elsif g_design_name = "lofar2_unb2c_sdp_station_full_wg"   then return c_full_wg;  -- = baseline
     elsif g_design_name = "lofar2_unb2c_sdp_station_full"      then return c_full;  -- = baseline
     elsif g_design_name = "disturb2_unb2c_sdp_station_full_wg" then return c_full_wg_os;