diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_crosslets_remote.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_crosslets_remote.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..b154eaaaba4b7aef6c98ff41ab964c12b3b51159
--- /dev/null
+++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_crosslets_remote.vhd
@@ -0,0 +1,257 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2021
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--
+-- Author: R. van der Walle, E. Kooistra
+-- Purpose:
+-- . Implements the functionality for remote crosslets IO and aligning the
+--   local and remote crosslets in the node_sdp_correlator of the LOFAR2
+--   SDPFW design.
+-- Description:
+-------------------------------------------------------------------------------
+
+library IEEE, common_lib, dp_lib, reorder_lib, st_lib, mm_lib, ring_lib;
+use IEEE.std_logic_1164.all;
+use common_lib.common_pkg.all;
+use common_lib.common_mem_pkg.all;
+use common_lib.common_network_layers_pkg.all;
+use dp_lib.dp_stream_pkg.all;
+use ring_lib.ring_pkg.all;
+use work.sdp_pkg.all;
+
+entity sdp_crosslets_remote is
+  generic (
+    g_P_sq             : natural := c_sdp_P_sq
+  );
+  port (
+    dp_clk             : in  std_logic;
+    dp_rst             : in  std_logic;
+
+    xsel_sosi          : in  t_dp_sosi;
+    from_ri_sosi       : in  t_dp_sosi := c_dp_sosi_rst;
+    to_ri_sosi         : out t_dp_sosi;
+
+    crosslets_sosi     : out t_dp_sosi;
+    crosslets_copi     : in  t_mem_copi := c_mem_copi_rst;
+    crosslets_cipo_arr : out t_mem_cipo_arr(g_P_sq - 1 downto 0);
+
+    mm_rst             : in  std_logic;
+    mm_clk             : in  std_logic;
+
+    reg_bsn_align_copi                       : in  t_mem_copi := c_mem_copi_rst;
+    reg_bsn_align_cipo                       : out t_mem_cipo;
+    reg_bsn_monitor_v2_bsn_align_input_copi  : in  t_mem_copi := c_mem_copi_rst;
+    reg_bsn_monitor_v2_bsn_align_input_cipo  : out t_mem_cipo;
+    reg_bsn_monitor_v2_bsn_align_output_copi : in  t_mem_copi := c_mem_copi_rst;
+    reg_bsn_monitor_v2_bsn_align_output_cipo : out t_mem_cipo
+  );
+end sdp_crosslets_remote;
+
+architecture str of sdp_crosslets_remote is
+  constant c_block_size           : natural  := c_sdp_N_crosslets_max * c_sdp_S_pn;
+  constant c_block_size_longwords : natural  := ceil_div(c_block_size, 2);  -- 32b -> 64b
+  constant c_data_w               : natural  := c_sdp_W_crosslet * c_nof_complex;
+
+  -- The size for 1 block is probably already enough as the number of blocks received
+  -- on the remote input of the mux probably have enough gap time in between. Just
+  -- to be sure to not run into issues in the future, the fifo size is increased to
+  -- buffer the maximum nof blocks per block period.
+  constant c_mux_fifo_size   : natural  := 2**ceil_log2(g_P_sq * c_block_size_longwords);
+  -- c_fifo_fill_size should be at least 2 * c_block_size_longwords as dp_repack_data
+  -- repacks from 64bit to 32bit. Chosing 3x to have some room.
+  constant c_fifo_fill_size  : natural  := 2**ceil_log2(3 * c_block_size_longwords);
+
+  signal xsel_data_sosi                : t_dp_sosi := c_dp_sosi_rst;
+  signal local_sosi                    : t_dp_sosi := c_dp_sosi_rst;
+
+  signal ring_mux_sosi                 : t_dp_sosi := c_dp_sosi_rst;
+  signal ring_mux_siso                 : t_dp_siso := c_dp_siso_rdy;
+  signal dp_fifo_fill_sosi             : t_dp_sosi := c_dp_sosi_rst;
+  signal dp_fifo_fill_siso             : t_dp_siso := c_dp_siso_rdy;
+  signal rx_sosi                       : t_dp_sosi := c_dp_sosi_rst;
+  signal dispatch_invert_sosi_arr      : t_dp_sosi_arr(0 to g_P_sq - 1) := (others => c_dp_sosi_rst);
+  signal dispatch_sosi_arr             : t_dp_sosi_arr(g_P_sq - 1 downto 0) := (others => c_dp_sosi_rst);
+begin
+  ---------------------------------------------------------------
+  -- Repack 32b to 64b
+  ---------------------------------------------------------------
+  -- repacking xsel re/im to data field.
+  p_wire_xsel_sosi : process(xsel_sosi)
+  begin
+    xsel_data_sosi <= xsel_sosi;
+    xsel_data_sosi.data(                c_sdp_W_crosslet - 1 downto 0)                <= xsel_sosi.re(c_sdp_W_crosslet - 1 downto 0);
+    xsel_data_sosi.data(c_nof_complex * c_sdp_W_crosslet - 1 downto c_sdp_W_crosslet) <= xsel_sosi.im(c_sdp_W_crosslet - 1 downto 0);
+  end process;
+
+  u_dp_repack_data_local : entity dp_lib.dp_repack_data
+  generic map (
+    g_in_dat_w       => c_data_w,
+    g_in_nof_words   => c_longword_w / c_data_w,
+    g_out_dat_w      => c_longword_w,
+    g_out_nof_words  => 1,
+    g_pipeline_ready => true  -- Needed for src_in.ready to snk_out.ready.
+  )
+  port map (
+    rst => dp_rst,
+    clk => dp_clk,
+
+    snk_in  => xsel_data_sosi,
+    src_out => local_sosi
+  );
+
+  ---------------------------------------------------------------
+  -- ring_mux
+  ---------------------------------------------------------------
+  u_ring_mux : entity ring_lib.ring_mux
+  generic map (
+    g_bsn_w        => c_dp_stream_bsn_w,
+    g_data_w       => c_longword_w,
+    g_channel_w    => c_word_w,
+    g_use_error    => false,
+    g_fifo_size    => array_init(c_mux_fifo_size, 2)
+  )
+  port map (
+    dp_clk => dp_clk,
+    dp_rst => dp_rst,
+
+    remote_sosi => from_ri_sosi,
+    local_sosi  => local_sosi,
+    mux_sosi    => ring_mux_sosi,
+    mux_siso    => ring_mux_siso
+  );
+
+  to_ri_sosi <= ring_mux_sosi;
+
+  -- fill fifo to remove gaps
+  u_dp_fifo_fill_eop : entity dp_lib.dp_fifo_fill_eop
+  generic map (
+    g_data_w         => c_longword_w,
+    g_bsn_w          => c_dp_stream_bsn_w,
+    g_empty_w        => c_dp_stream_empty_w,
+    g_channel_w      => c_dp_stream_channel_w,
+    g_error_w        => c_dp_stream_error_w,
+    g_use_bsn        => true,
+    g_use_empty      => true,
+    g_use_channel    => true,
+    g_use_error      => true,
+    g_use_sync       => true,
+    g_fifo_fill      => c_block_size_longwords,
+    g_fifo_size      => c_fifo_fill_size
+  )
+  port map (
+    wr_rst      => dp_rst,
+    wr_clk      => dp_clk,
+    rd_rst      => dp_rst,
+    rd_clk      => dp_clk,
+
+    snk_out     => ring_mux_siso,
+    snk_in      => ring_mux_sosi,
+
+    src_in      => dp_fifo_fill_siso,
+    src_out     => dp_fifo_fill_sosi
+  );
+
+  ---------------------------------------------------------------
+  -- Repack 64b to 32b
+  ---------------------------------------------------------------
+  u_dp_repack_data_rx : entity dp_lib.dp_repack_data
+  generic map (
+    g_in_dat_w       => c_longword_w,
+    g_in_nof_words   => 1,
+    g_out_dat_w      => c_data_w,
+    g_out_nof_words  => c_longword_w / c_data_w,
+    g_pipeline_ready => true  -- Needed for src_in.ready to snk_out.ready.
+  )
+  port map (
+    rst => dp_rst,
+    clk => dp_clk,
+
+    snk_in  => dp_fifo_fill_sosi,
+    snk_out => dp_fifo_fill_siso,
+    src_out => rx_sosi
+  );
+
+  ---------------------------------------------------------------
+  -- dp_demux
+  ---------------------------------------------------------------
+  u_dp_demux : entity dp_lib.dp_demux
+  generic map (
+    g_mode              => 0,
+    g_nof_output        => g_P_sq,
+    g_remove_channel_lo => false,
+    g_sel_ctrl_invert   => true  -- TRUE when indexed (g_nof_input-1 DOWNTO 0)
+  )
+  port map (
+    rst => dp_rst,
+    clk => dp_clk,
+
+    snk_in      => rx_sosi,
+    src_out_arr => dispatch_invert_sosi_arr
+  );
+
+  dispatch_sosi_arr <= func_dp_stream_arr_reverse_range(dispatch_invert_sosi_arr);
+
+  ---------------------------------------------------------------
+  -- dp_bsn_aligner_v2
+  ---------------------------------------------------------------
+  u_mmp_dp_bsn_align_v2 : entity dp_lib.mmp_dp_bsn_align_v2
+  generic map(
+    -- for dp_bsn_align_v2
+    g_nof_streams             => g_P_sq,
+    g_bsn_latency_max         => 2,
+    g_nof_aligners_max        => 1,  -- 1 for Access scheme 3.
+    g_block_size              => c_block_size,
+    g_data_w                  => c_data_w,
+    g_use_mm_output           => true,
+    g_rd_latency              => 1,  -- Required for st_xst
+    -- for mms_dp_bsn_monitor_v2
+    -- Using c_sdp_N_clk_sync_timeout_xsub as g_nof_clk_per_sync is used for BSN monitor timeout.
+    g_nof_clk_per_sync        => c_sdp_N_clk_sync_timeout_xsub,
+    g_nof_input_bsn_monitors  => g_P_sq,
+    g_use_bsn_output_monitor  => true
+    )
+  port map (
+    -- Memory-mapped clock domain
+    mm_rst                  => mm_rst,
+    mm_clk                  => mm_clk,
+
+    reg_bsn_align_copi      => reg_bsn_align_copi,
+    reg_bsn_align_cipo      => reg_bsn_align_cipo,
+
+    reg_input_monitor_copi  => reg_bsn_monitor_v2_bsn_align_input_copi,
+    reg_input_monitor_cipo  => reg_bsn_monitor_v2_bsn_align_input_cipo,
+
+    reg_output_monitor_copi => reg_bsn_monitor_v2_bsn_align_output_copi,
+    reg_output_monitor_cipo => reg_bsn_monitor_v2_bsn_align_output_cipo,
+
+    -- Streaming clock domain
+    dp_rst     => dp_rst,
+    dp_clk     => dp_clk,
+
+    -- Streaming input
+    in_sosi_arr => dispatch_sosi_arr,
+
+    -- Output via local MM interface in dp_clk domain, when g_use_mm_output = TRUE.
+    mm_sosi     => crosslets_sosi,
+    mm_copi     => crosslets_copi,
+    mm_cipo_arr => crosslets_cipo_arr
+  );
+end str;
diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_crosslets_remote_ring.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_crosslets_remote_ring.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..20aee6dfde39bbd7279f2fe9232ef0196017570b
--- /dev/null
+++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_crosslets_remote_ring.vhd
@@ -0,0 +1,737 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+--
+-- Author: E. Kooistra
+-- Purpose:
+-- . Test bench for multiple sdp_crosslets_remote.vhd + ring_lane.vhd +
+--   tr_10GbE in a ring
+-- Description:
+-- . https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Subband+Correlator
+--
+-- . Block diagram:
+--   * tb can use one instance of tr_10Gbe to model Rx from ring and Tx to ring.
+--   * Ring lane serial links for ring nodes RN = 0 to c_last_rn:
+--
+--     tr_10gbe_ring_serial_tx_arr --> tr_10gbe_ring_serial_rx_arr after c_cable_delay
+--
+--         /<-------------------------------------------------------------\
+--         \---> 0 ---> RN - 1  --->  RN  --->  RN + 1 ---> c_last_rn --->/
+--                                    |^
+--    tr_10gbe_ring_serial_tx_arr(RN) || tr_10gbe_ring_serial_tx_arr(RN)
+--                                    v|
+--                                  tr_10Gbe
+--                                    |^
+--      tr_10gbe_ring_rx_sosi_arr(RN) || tr_10gbe_ring_tx_sosi_arr(RN)
+--                                    v|
+--                                 ring_lane
+--                                    |^
+--               from_ri_sosi_arr(RN) || to_ri_sosi_arr(RN)
+--                                    v|
+--        local_crosslets_sosi --> sdp_crosslets_remote --> x_sosi_arr(RN)(P_sq)
+--                                                          x_sosi
+--
+--   * BSN monitors:
+--                                            RN
+--                                            |^
+--         ring_lane/ring_rx                  || ring_lane/ring_tx
+--         FPGA_xst_ring_rx_latency_R(RN)(RN) || FPGA_xst_ring_tx_latency_R(RN)(RN)
+--                                            ||
+--      dp_bsn_align_v2 P_sq inputs           ||
+--      FPGA_xst_rx_align_latency_R(RN)(P_sq) ||
+--                                            ||
+--             dp_bsn_align_v2 aligned output ||
+--             FPGA_xst_aligned_latency_R(RN) v|
+--
+-- . XST ring latency results from SDP-ARTS HW:
+--   - xst_ring_rx_latency:
+--     node 64:  -1   -1   -1   -1   -1   -1   -1   -1   1774 1569 1363 1112 906  677  472  266
+--     node 65:  249  -1   -1   -1   -1   -1   -1   -1   -1   1776 1579 1352 1113 890  692  472
+--     node 66:  466  267  -1   -1   -1   -1   -1   -1   -1   -1   1787 1566 1340 1105 905  685
+--     node 67:  688  487  266  -1   -1   -1   -1   -1   -1   -1   -1   1793 1566 1346 1128 905
+--     node 68:  904  699  493  264  -1   -1   -1   -1   -1   -1   -1   -1   1788 1567 1355 1133
+--     node 69:  1114 913  717  473  252  -1   -1   -1   -1   -1   -1   -1   -1   1776 1576 1357
+--     node 70:  1341 1122 945  681  460  259  -1   -1   -1   -1   -1   -1   -1   -1   1783 1566
+--     node 71:  1551 1348 1156 890  667  471  250  -1   -1   -1   -1   -1   -1   -1   -1   1773
+--     node 72:  1785 1596 1397 1122 894  711  482  277  -1   -1   -1   -1   -1   -1   -1   -1
+--     node 73:  -1   1819 1618 1350 1114 936  693  497  254  -1   -1   -1   -1   -1   -1   -1
+--     node 74:  -1   -1   1828 1563 1342 1146 901  704  461  260  -1   -1   -1   -1   -1   -1
+--     node 75:  -1   -1   -1   1784 1564 1366 1121 920  677  480  257  -1   -1   -1   -1   -1
+--     node 76:  -1   -1   -1   -1   1804 1597 1362 1164 913  707  500  273  -1   -1   -1   -1
+--     node 77:  -1   -1   -1   -1   -1   1810 1587 1390 1125 924  723  480  261  -1   -1   -1
+--     node 78:  -1   -1   -1   -1   -1   -1   1800 1599 1351 1137 938  693  472  253  -1   -1
+--     node 79:  -1   -1   -1   -1   -1   -1   -1   1809 1566 1344 1143 899  681  460  259  -1
+--
+--   - xst_ring_tx_latency:
+--     node 64:  12   -1   -1   -1   -1   -1   -1   -1   -1   1611 1361 1155 926  698  470  264
+--     node 65:  256  12   -1   -1   -1   -1   -1   -1   -1   -1   1583 1363 1143 920  676  476
+--     node 66:  470  272  12   -1   -1   -1   -1   -1   -1   -1   -1   1575 1353 1131 892  692
+--     node 67:  694  496  274  12   -1   -1   -1   -1   -1   -1   -1   -1   1577 1357 1119 914
+--     node 68:  922  714  486  258  12   -1   -1   -1   -1   -1   -1   -1   -1   1585 1347 1125
+--     node 69:  1145 926  704  482  260  12   -1   -1   -1   -1   -1   -1   -1   -1   1567 1345
+--     node 70:  1371 1147 924  704  484  264  12   -1   -1   -1   -1   -1   -1   -1   -1   1567
+--     node 71:  1579 1359 1139 916  696  476  256  12   -1   -1   -1   -1   -1   -1   -1   -1
+--     node 72:  -1   1597 1369 1141 934  706  500  274  12   -1   -1   -1   -1   -1   -1   -1
+--     node 73:  -1   -1   1593 1347 1149 930  706  484  262  12   -1   -1   -1   -1   -1   -1
+--     node 74:  -1   -1   -1   1571 1373 1151 928  708  488  264  12   -1   -1   -1   -1   -1
+--     node 75:  -1   -1   -1   -1   1595 1373 1151 928  708  488  264  12   -1   -1   -1   -1
+--     node 76:  -1   -1   -1   -1   -1   1619 1391 1163 934  728  500  294  12   -1   -1   -1
+--     node 77:  -1   -1   -1   -1   -1   -1   1611 1369 1145 946  706  508  264  12   -1   -1
+--     node 78:  -1   -1   -1   -1   -1   -1   -1   1593 1371 1171 928  732  488  268  12   -1
+--     node 79:  -1   -1   -1   -1   -1   -1   -1   -1   1587 1387 1143 948  702  480  262  12
+--
+--   - xst_rx_align_latency:
+--     node 64:  1    204  434  638  868  1109 1318 1546 1774
+--     node 65:  1    214  412  652  852  1109 1315 1532 1756
+--     node 66:  1    202  422  622  866  1109 1326 1529 1750
+--     node 67:  1    204  426  648  846  1109 1324 1548 1751
+--     node 68:  1    210  416  644  874  1109 1322 1528 1758
+--     node 69:  1    204  426  626  848  1109 1328 1546 1746
+--     node 70:  1    208  428  648  848  1109 1330 1550 1753
+--     node 71:  1    210  430  648  870  1109 1328 1552 1770
+--     node 72:  1    230  436  666  892  1109 1342 1570 1776
+--     node 73:  1    202  444  640  884  1109 1327 1566 1788
+--     node 74:  1    222  422  664  860  1109 1323 1543 1784
+--     node 75:  1    214  432  634  878  1109 1319 1541 1763
+--     node 76:  1    232  438  668  872  1125 1346 1559 1789
+--     node 77:  1    216  436  654  876  1109 1337 1554 1777
+--     node 78:  1    206  430  648  868  1109 1332 1559 1772
+--     node 79:  1    208  430  650  870  1109 1328 1550 1775
+--
+--   - xst_aligned_latency:
+--     node 64:  2051
+--     node 65:  2051
+--     node 66:  2051
+--     node 67:  2051
+--     node 68:  2051
+--     node 69:  2051
+--     node 70:  2051
+--     node 71:  2051
+--     node 72:  2051
+--     node 73:  2051
+--     node 74:  2051
+--     node 75:  2051
+--     node 76:  2051
+--     node 77:  2051
+--     node 78:  2051
+--     node 79:  2051
+--
+-- Usage:
+-- > as 3 or more
+-- > run -a
+-------------------------------------------------------------------------------
+
+library IEEE, common_lib, dp_lib, st_lib, ring_lib, tr_10GbE_lib, tech_pll_lib;
+use IEEE.std_logic_1164.all;
+use common_lib.common_pkg.all;
+use common_lib.common_mem_pkg.all;
+use common_lib.tb_common_pkg.all;
+use common_lib.tb_common_mem_pkg.all;
+use common_lib.common_str_pkg.all;
+use dp_lib.dp_stream_pkg.all;
+use ring_lib.ring_pkg.all;
+use tech_pll_lib.tech_pll_component_pkg.all;
+use work.sdp_pkg.all;
+use work.tb_sdp_pkg.all;
+
+entity tb_sdp_crosslets_remote_ring is
+  generic (
+    g_nof_rn    : natural := 4;  -- number of nodes in the ring
+    g_nof_sync  : natural := 2
+  );
+end tb_sdp_crosslets_remote_ring;
+
+architecture tb of tb_sdp_crosslets_remote_ring is
+  constant c_dp_clk_period : time := 5 ns;  -- 200 MHz
+  constant c_mm_clk_period : time := 1 ns;  -- fast MM clk to speed up simulation
+  constant c_sa_clk_period : time := tech_pll_clk_644_period;  -- 644MHz
+
+  -- Apply cable delay in tech_pll_clk_156_period units, to remain aligned with tr_10GbE sim model
+  -- . Choose c_cable_delay = 30 * 6.4 ~= 192 ns ~= 38 dp_clk of 5 ns, to match delay seen on HW
+  -- . Maximum c_cable_delay <= ??? * 6.4 =
+  constant c_clk_156_period  : time := tech_pll_clk_156_period;  -- 6.400020 ns ~= 156.25 MHz
+  constant c_cable_delay     : time := c_clk_156_period * 188;
+
+  -- XST data
+  constant c_P_sq                      : natural := g_nof_rn / 2 + 1;  -- nof square correlator cells
+  constant c_nof_transport_hops        : natural := c_P_sq - 1;
+  constant c_block_period              : natural := c_sdp_N_fft;
+  constant c_block_size                : natural := c_sdp_N_crosslets_max * c_sdp_S_pn;
+  constant c_gap_size                  : natural := c_block_period - c_block_size;
+  constant c_nof_blocks_per_sync       : natural := 10;
+  constant g_nof_sync                  : natural := 2;
+  constant c_local_crosslet_re         : integer := 1;
+  constant c_local_crosslet_im         : integer := 2;
+
+  constant c_last_rn                   : natural := g_nof_rn - 1;  -- first ring node has index RN = 0 by definition.
+
+  type t_ring_integer_2arr is array (integer range <>) of t_integer_arr(c_last_rn downto 0);
+
+  type t_crosslets_cipo_2arr is array (integer range <>) of t_mem_cipo_arr(c_P_sq - 1 downto 0);
+  type t_crosslets_sosi_2arr is array (integer range <>) of t_dp_sosi_arr(c_P_sq - 1 downto 0);
+  type t_crosslets_integer_2arr is array (integer range <>) of t_integer_arr(c_P_sq - 1 downto 0);
+
+  -- Ring lane packets
+  constant c_use_cable                 : std_logic := '1';  -- '0' ring via PCB traces, '1' ring via QSFP cables
+
+  -- = crosslet subband select block size divided by 2 as it is repacked from 32b to 64b. = 42 longwords
+  constant c_lane_payload_nof_longwords_xst : natural := c_sdp_N_crosslets_max * c_sdp_S_pn / 2;
+  constant c_lane_packet_nof_longwords_max  : natural := c_lane_payload_nof_longwords_xst + c_ring_dp_hdr_field_size;
+                                                         -- = 549 + 3 = 552
+  constant c_fifo_tx_fill_margin       : natural := 10;  -- >= c_fifo_fill_margin = 6 that is used in dp_fifo_fill_eop
+  constant c_fifo_tx_size_ring : natural := true_log_pow2(c_lane_packet_nof_longwords_max + c_fifo_tx_fill_margin);
+                                            -- = 552 + 6 --> 1024
+  constant c_fifo_tx_fill_ring : natural := c_fifo_tx_size_ring - c_fifo_tx_fill_margin;
+                                            -- = maximum fill level, so rely on eop
+  constant c_err_bi                    : natural := 0;
+  constant c_nof_err_counts            : natural := 8;
+  constant c_bsn_at_sync_check_channel : natural := 1;
+  constant c_validate_channel          : boolean := true;
+  constant c_validate_channel_mode     : string  := "=";
+  constant c_sync_timeout              : natural := c_block_period * (c_nof_blocks_per_sync + 1);
+
+  -- Timeout tb if there is no output x_sosi
+  constant c_tb_timeout                : time := (g_nof_sync + 1) * c_sync_timeout * c_dp_clk_period;
+
+  -- Address widths of a single MM instance
+  constant c_addr_w_reg_ring_lane_info_xst          : natural := 1;
+
+  signal mm_init                : std_logic := '1';
+  signal tb_end                 : std_logic := '0';
+  signal dp_clk                 : std_logic := '1';
+  signal dp_rst                 : std_logic;
+  signal mm_clk                 : std_logic := '1';
+  signal mm_rst                 : std_logic;
+  signal SA_CLK                 : std_logic := '1';
+  signal tr_ref_clk_312         : std_logic := '0';
+  signal tr_ref_clk_156         : std_logic := '0';
+  signal tr_ref_rst_156         : std_logic := '0';
+
+  signal stimuli_rst              : std_logic;
+  signal stimuli_end              : std_logic;
+
+  signal stimuli_sosi             : t_dp_sosi;
+  signal local_crosslets_sosi_arr : t_dp_sosi_arr(c_last_rn downto 0);
+  signal xst_bs_sosi              : t_dp_sosi;
+  signal from_ri_sosi_arr         : t_dp_sosi_arr(c_last_rn downto 0);
+  signal to_ri_sosi_arr           : t_dp_sosi_arr(c_last_rn downto 0);
+  signal crosslets_sosi_arr       : t_dp_sosi_arr(c_last_rn downto 0);
+  signal crosslets_copi_arr       : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst);
+  signal crosslets_cipo_2arr      : t_crosslets_cipo_2arr(c_last_rn downto 0);
+  signal x_sosi_2arr              : t_crosslets_sosi_2arr(c_last_rn downto 0);
+  signal x_sosi                   : t_dp_sosi;
+
+  -- 10GbE ring
+  signal tr_10gbe_ring_rx_sosi_arr    : t_dp_sosi_arr(c_last_rn downto 0) := (others => c_dp_sosi_rst);
+  signal tr_10gbe_ring_tx_sosi_arr    : t_dp_sosi_arr(c_last_rn downto 0) := (others => c_dp_sosi_rst);
+  signal tr_10gbe_ring_serial_rx_arr  : std_logic_vector(c_last_rn downto 0) := (others => '0');
+  signal tr_10gbe_ring_serial_tx_arr  : std_logic_vector(c_last_rn downto 0) := (others => '0');
+
+  -- Crosslets ring MM registers
+  signal reg_ring_lane_info_xst_copi_arr         : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst);
+  signal reg_ring_lane_info_xst_cipo_arr         : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst);
+  signal reg_ring_lane_info_xst_copi             : t_mem_copi := c_mem_copi_rst;
+  signal reg_ring_lane_info_xst_cipo             : t_mem_cipo := c_mem_cipo_rst;
+  signal reg_bsn_monitor_v2_ring_rx_xst_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst);
+  signal reg_bsn_monitor_v2_ring_rx_xst_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst);
+  signal reg_bsn_monitor_v2_ring_rx_xst_copi     : t_mem_copi := c_mem_copi_rst;
+  signal reg_bsn_monitor_v2_ring_rx_xst_cipo     : t_mem_cipo := c_mem_cipo_rst;
+  signal reg_bsn_monitor_v2_ring_tx_xst_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst);
+  signal reg_bsn_monitor_v2_ring_tx_xst_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst);
+  signal reg_bsn_monitor_v2_ring_tx_xst_copi     : t_mem_copi := c_mem_copi_rst;
+  signal reg_bsn_monitor_v2_ring_tx_xst_cipo     : t_mem_cipo := c_mem_cipo_rst;
+  signal reg_dp_block_validate_err_xst_copi_arr  : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst);
+  signal reg_dp_block_validate_err_xst_cipo_arr  : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst);
+  signal reg_dp_block_validate_err_xst_copi      : t_mem_copi := c_mem_copi_rst;
+  signal reg_dp_block_validate_err_xst_cipo      : t_mem_cipo := c_mem_cipo_rst;
+  signal reg_dp_block_validate_bsn_at_sync_xst_copi_arr : t_mem_copi_arr(c_last_rn downto 0) :=
+                                                         (others => c_mem_copi_rst);
+  signal reg_dp_block_validate_bsn_at_sync_xst_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) :=
+                                                         (others => c_mem_cipo_rst);
+  signal reg_dp_block_validate_bsn_at_sync_xst_copi     : t_mem_copi := c_mem_copi_rst;
+  signal reg_dp_block_validate_bsn_at_sync_xst_cipo     : t_mem_cipo := c_mem_cipo_rst;
+  -- Crosslets ring MM points
+  signal FPGA_xst_ring_nof_transport_hops_R       : t_natural_arr(c_last_rn downto 0);
+  signal FPGA_xst_ring_rx_latency_R               : t_ring_integer_2arr(c_last_rn downto 0);
+  signal FPGA_xst_ring_tx_latency_R               : t_ring_integer_2arr(c_last_rn downto 0);
+
+  -- BSN aligner MM registers
+  signal reg_bsn_align_v2_xst_copi_arr            : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst);
+  signal reg_bsn_align_v2_xst_cipo_arr            : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst);
+  signal reg_bsn_align_v2_xst_copi                : t_mem_copi := c_mem_copi_rst;
+  signal reg_bsn_align_v2_xst_cipo                : t_mem_cipo := c_mem_cipo_rst;
+  signal reg_bsn_monitor_v2_xst_rx_align_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst);
+  signal reg_bsn_monitor_v2_xst_rx_align_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst);
+  signal reg_bsn_monitor_v2_xst_rx_align_copi     : t_mem_copi := c_mem_copi_rst;
+  signal reg_bsn_monitor_v2_xst_rx_align_cipo     : t_mem_cipo := c_mem_cipo_rst;
+  signal reg_bsn_monitor_v2_xst_aligned_copi_arr  : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst);
+  signal reg_bsn_monitor_v2_xst_aligned_cipo_arr  : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst);
+  signal reg_bsn_monitor_v2_xst_aligned_copi      : t_mem_copi := c_mem_copi_rst;
+  signal reg_bsn_monitor_v2_xst_aligned_cipo      : t_mem_cipo := c_mem_cipo_rst;
+  -- BSN aligner Monitor Points
+  signal FPGA_xst_rx_align_latency_R              : t_crosslets_integer_2arr(c_last_rn downto 0);
+  signal FPGA_xst_aligned_latency_R               : t_integer_arr(c_last_rn downto 0);
+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;
+
+  mm_rst <= '1', '0' after c_mm_clk_period * 7;
+  mm_clk <= (not mm_clk) or tb_end after c_mm_clk_period / 2;
+
+  -- Wait for tr_10GbE to be active
+  stimuli_rst <= '1', '0' after 15 us;
+
+  SA_CLK <= not SA_CLK after c_sa_clk_period / 2;  -- Serial Gigabit IO sa clock (644 MHz)
+
+  -- Generate local crosslets stream, use same for all nodes
+  u_stimuli : entity dp_lib.dp_stream_stimuli
+  generic map (
+    g_sync_period => c_nof_blocks_per_sync,
+    g_nof_repeat  => c_nof_blocks_per_sync * g_nof_sync,
+    g_pkt_len     => c_block_size,
+    g_pkt_gap     => c_gap_size
+  )
+  port map (
+    rst               => stimuli_rst,
+    clk               => dp_clk,
+    -- Generate stimuli
+    src_out           => stimuli_sosi,
+    -- End of stimuli
+    tb_end            => stimuli_end
+  );
+
+  -- Use constant crosslet data to ease verification of aligned crosslet data at each node
+  p_local_crosslets_sosi : process(stimuli_sosi)
+  begin
+    for RN in 0 to c_last_rn loop
+      local_crosslets_sosi_arr(RN) <= stimuli_sosi;
+      local_crosslets_sosi_arr(RN).data <= TO_DP_SDATA(0);
+      -- different crosslets value (and /= 0) per node
+      local_crosslets_sosi_arr(RN).re <= TO_DP_DSP_DATA(RN + c_local_crosslet_re);
+      local_crosslets_sosi_arr(RN).im <= TO_DP_DSP_DATA(RN + c_local_crosslet_im);
+      local_crosslets_sosi_arr(RN).channel <= TO_DP_CHANNEL(0);
+      local_crosslets_sosi_arr(RN).err <= TO_DP_ERROR(0);
+    end loop;
+  end process;
+
+  xst_bs_sosi <= local_crosslets_sosi_arr(0);
+
+  p_mm : process
+    -- MM access
+    variable v_span          : natural;
+    variable v_span_node     : natural;
+    variable v_offset        : natural;
+    -- print_str()
+    constant c_nof_col       : natural := 1 + g_nof_rn;
+    constant c_col_w         : natural := 5;
+    constant c_extra_w       : natural := 10;
+    constant c_line_w        : natural := c_extra_w + c_nof_col * c_col_w;
+    variable v_line          : string(1 to c_line_w);
+  begin
+    proc_common_wait_until_low(dp_clk, mm_rst);
+    proc_common_wait_some_cycles(mm_clk, 10);
+
+    proc_common_wait_cross_clock_domain_latency(c_mm_clk_period, c_dp_clk_period,
+                                                c_common_cross_clock_domain_latency * 2);
+    ---------------------------------------------------------------------------
+    -- Setup transport nof hops for each RN to c_nof_transport_hops
+    ---------------------------------------------------------------------------
+    -- Write FPGA_xst_ring_nof_transport_hops_RW = ring_lane_info.transport_nof_hops
+    v_span := 2**c_addr_w_reg_ring_lane_info_xst;
+    for RN in 0 to c_last_rn loop
+      v_offset := 1 + RN * v_span;
+      proc_mem_mm_bus_wr(v_offset, c_nof_transport_hops, mm_clk,
+                         reg_ring_lane_info_xst_cipo, reg_ring_lane_info_xst_copi);
+    end loop;
+    proc_common_wait_cross_clock_domain_latency(c_mm_clk_period, c_dp_clk_period,
+                                                c_common_cross_clock_domain_latency * 2);
+    -- Readback FPGA_xst_ring_nof_transport_hops_R
+    for RN in 0 to c_last_rn loop
+      v_offset := 1 + RN * v_span;
+      proc_mem_mm_bus_rd(v_offset, mm_clk, reg_ring_lane_info_xst_cipo, reg_ring_lane_info_xst_copi);
+      proc_mem_mm_bus_rd_latency(1, mm_clk);
+      FPGA_xst_ring_nof_transport_hops_R(RN) <= TO_UINT(reg_ring_lane_info_xst_cipo.rddata(c_word_w - 1 downto 0));
+    end loop;
+
+    ---------------------------------------------------------------------------
+    -- Wait until second x_sosi.sync
+    ---------------------------------------------------------------------------
+    proc_common_wait_until_hi_lo(dp_clk, x_sosi.sync);
+    proc_common_wait_until_hi_lo(dp_clk, x_sosi.sync);
+
+    ---------------------------------------------------------------------------
+    -- Read BSN monitors
+    ---------------------------------------------------------------------------
+    v_span := 2**c_sdp_reg_bsn_monitor_v2_addr_w;
+    -- Read FPGA_xst_ring_rx_latency_R
+    v_span_node := true_log_pow2(g_nof_rn) * v_span;
+    for RN in 0 to c_last_rn loop
+      for U in 0 to c_last_rn loop
+        v_offset := 6 + RN * v_span_node + U * v_span;
+        proc_mem_mm_bus_rd(v_offset, mm_clk, reg_bsn_monitor_v2_ring_rx_xst_cipo, reg_bsn_monitor_v2_ring_rx_xst_copi);
+        proc_mem_mm_bus_rd_latency(1, mm_clk);
+        FPGA_xst_ring_rx_latency_R(RN)(U) <= TO_SINT(reg_bsn_monitor_v2_ring_rx_xst_cipo.rddata(c_word_w - 1 downto 0));
+      end loop;
+    end loop;
+    -- Read FPGA_xst_rx_align_latency_R, for c_P_sq inputs per RN
+    v_span_node := true_log_pow2(c_P_sq) * v_span;
+    for RN in 0 to c_last_rn loop
+      for P in 0 to c_P_sq - 1 loop
+        v_offset := 6 + RN * v_span_node + P * v_span;
+        proc_mem_mm_bus_rd(v_offset, mm_clk, reg_bsn_monitor_v2_xst_rx_align_cipo, reg_bsn_monitor_v2_xst_rx_align_copi);
+        proc_mem_mm_bus_rd_latency(1, mm_clk);
+        FPGA_xst_rx_align_latency_R(RN)(P) <= TO_SINT(reg_bsn_monitor_v2_xst_rx_align_cipo.rddata(c_word_w - 1 downto 0));
+      end loop;
+    end loop;
+    -- Read FPGA_xst_aligned_latency_R
+    for RN in 0 to c_last_rn loop
+      v_offset := 6 + RN * v_span;
+      proc_mem_mm_bus_rd(v_offset, mm_clk, reg_bsn_monitor_v2_xst_aligned_cipo, reg_bsn_monitor_v2_xst_aligned_copi);
+      proc_mem_mm_bus_rd_latency(1, mm_clk);
+      FPGA_xst_aligned_latency_R(RN) <= TO_SINT(reg_bsn_monitor_v2_xst_aligned_cipo.rddata(c_word_w - 1 downto 0));
+    end loop;
+    -- Read FPGA_xst_ring_tx_latency_R
+    v_span_node := true_log_pow2(g_nof_rn) * v_span;
+    for RN in 0 to c_last_rn loop
+      for U in 0 to c_last_rn loop
+        v_offset := 6 + RN * v_span_node + U * v_span;
+        proc_mem_mm_bus_rd(v_offset, mm_clk, reg_bsn_monitor_v2_ring_tx_xst_cipo, reg_bsn_monitor_v2_ring_tx_xst_copi);
+        proc_mem_mm_bus_rd_latency(1, mm_clk);
+        FPGA_xst_ring_tx_latency_R(RN)(U) <= TO_SINT(reg_bsn_monitor_v2_ring_tx_xst_cipo.rddata(c_word_w - 1 downto 0));
+      end loop;
+    end loop;
+
+    ---------------------------------------------------------------------------
+    -- Wait until end of simulation
+    ---------------------------------------------------------------------------
+    mm_init <= '0';
+
+    proc_common_wait_until_high(dp_clk, stimuli_end);
+    proc_common_wait_some_cycles(dp_clk, 1000);
+
+    ---------------------------------------------------------------------------
+    -- Print latency results
+    ---------------------------------------------------------------------------
+    print_str("FPGA_xst_ring_rx_latency_R:");
+    for RN in 0 to c_last_rn loop
+      -- latency values
+      v_line := (others => ' ');
+      for U in 0 to c_last_rn loop
+         v_line(c_line_w - c_col_w * (U + 1) + 1 to c_line_w - c_col_w * U) :=
+                int_to_str(FPGA_xst_ring_rx_latency_R(RN)(U), c_col_w);
+      end loop;
+      -- ring node index
+      v_line(c_line_w - c_col_w * (c_last_rn + 1) + 1 to c_line_w - c_col_w * c_last_rn) := int_to_str(RN, c_col_w);
+      print_str(v_line);
+    end Loop;
+    print_str("");
+
+    print_str("FPGA_xst_ring_tx_latency_R:");
+    for RN in 0 to c_last_rn loop
+      -- latency values
+      v_line := (others => ' ');
+      for U in 0 to c_last_rn loop
+         v_line(c_line_w - c_col_w * (U + 1) + 1 to c_line_w - c_col_w * U) :=
+                int_to_str(FPGA_xst_ring_tx_latency_R(RN)(U), c_col_w);
+      end loop;
+      -- ring node index
+      v_line(c_line_w - c_col_w * (c_last_rn + 1) + 1 to c_line_w - c_col_w * c_last_rn) := int_to_str(RN, c_col_w);
+      print_str(v_line);
+    end Loop;
+    print_str("");
+
+    print_str("FPGA_xst_rx_align_latency_R:");
+    for RN in 0 to c_last_rn loop
+      -- latency values
+      v_line := (others => ' ');
+      for U in 0 to c_P_sq - 1 loop
+         v_line(c_line_w - c_col_w * (U + 1) + 1 to c_line_w - c_col_w * U) :=
+                int_to_str(FPGA_xst_rx_align_latency_R(RN)(U), c_col_w);
+      end loop;
+      -- ring node index
+      v_line(c_line_w - c_col_w * (c_P_sq + 1) + 1 to c_line_w - c_col_w * c_P_sq) := int_to_str(RN, c_col_w);
+      print_str(v_line);
+    end Loop;
+    print_str("");
+
+    print_str("FPGA_xst_aligned_latency_R:");
+    for RN in 0 to c_last_rn loop
+      print_str(int_to_str(RN) & ": " & int_to_str(FPGA_xst_aligned_latency_R(RN)));
+    end Loop;
+    print_str("");
+
+    tb_end <= '1';
+    wait;
+  end process;
+
+  -- End the tb simulation
+  proc_common_timeout_failure(c_tb_timeout, tb_end);  -- ERROR: end simulation if it fails to end in time
+  proc_common_stop_simulation(tb_end);  -- OK: end simulation
+
+  ------------------------------------------------------------------------------
+  -- DUT
+  ------------------------------------------------------------------------------
+  gen_dut : for RN in 0 to c_last_rn generate
+    -- Connect ring wires between the nodes
+    wire_ring : if RN > 0 generate
+      tr_10gbe_ring_serial_rx_arr(RN) <= transport tr_10gbe_ring_serial_tx_arr(RN - 1) after c_cable_delay;
+    end generate;
+    close_ring : if RN = 0 generate
+      tr_10gbe_ring_serial_rx_arr(0) <= transport tr_10gbe_ring_serial_tx_arr(c_last_rn) after c_cable_delay;
+    end generate;
+
+    -- tr_10GbE access at each node, all via front_io QSFP[0]
+    u_tr_10GbE_ring: entity tr_10GbE_lib.tr_10GbE
+    generic map (
+      g_sim           => true,
+      g_sim_level     => 1,
+      g_nof_macs      => 1,
+      g_direction     => "TX_RX",
+      g_tx_fifo_fill  => c_fifo_tx_fill_ring,
+      g_tx_fifo_size  => c_fifo_tx_size_ring
+    )
+    port map (
+      -- Transceiver PLL reference clock
+      tr_ref_clk_644        => SA_CLK,
+      tr_ref_clk_312        => tr_ref_clk_312,
+      tr_ref_clk_156        => tr_ref_clk_156,
+      tr_ref_rst_156        => tr_ref_rst_156,
+
+      -- MM interface
+      mm_rst                => mm_rst,
+      mm_clk                => mm_clk,
+
+      reg_mac_mosi          => c_mem_copi_rst,
+      reg_mac_miso          => open,
+      reg_eth10g_mosi       => c_mem_copi_rst,
+      reg_eth10g_miso       => open,
+
+      -- DP interface
+      dp_rst                => dp_rst,
+      dp_clk                => dp_clk,
+
+      src_out_arr           => tr_10gbe_ring_rx_sosi_arr(RN downto RN),
+      snk_in_arr            => tr_10gbe_ring_tx_sosi_arr(RN downto RN),
+
+      -- Serial IO
+      serial_tx_arr         => tr_10gbe_ring_serial_tx_arr(RN downto RN),
+      serial_rx_arr         => tr_10gbe_ring_serial_rx_arr(RN downto RN)
+    );
+
+    -- Ring lane access at each node
+    u_ring_lane_xst : entity ring_lib.ring_lane
+      generic map (
+        g_lane_direction            => 1,  -- transport in positive RN direction.
+        g_lane_data_w               => c_longword_w,
+        g_lane_packet_length        => c_lane_payload_nof_longwords_xst,
+        g_lane_total_nof_packets_w  => 32,
+        g_use_dp_layer              => true,
+        g_nof_rx_monitors           => g_nof_rn,
+        g_nof_tx_monitors           => g_nof_rn,
+        g_err_bi                    => c_err_bi,
+        g_nof_err_counts            => c_nof_err_counts,
+        g_bsn_at_sync_check_channel => c_bsn_at_sync_check_channel,
+        g_validate_channel          => c_validate_channel,
+        g_validate_channel_mode     => c_validate_channel_mode,
+        g_sync_timeout              => c_sync_timeout
+      )
+      port map (
+        mm_rst => mm_rst,
+        mm_clk => mm_clk,
+        dp_clk => dp_clk,
+        dp_rst => dp_rst,
+
+        from_lane_sosi     => from_ri_sosi_arr(RN),
+        to_lane_sosi       => to_ri_sosi_arr(RN),
+        lane_rx_cable_sosi => tr_10gbe_ring_rx_sosi_arr(RN),
+        lane_rx_board_sosi => c_dp_sosi_rst,
+        lane_tx_cable_sosi => tr_10gbe_ring_tx_sosi_arr(RN),
+        lane_tx_board_sosi => open,
+        bs_sosi            => xst_bs_sosi,  -- used for bsn and sync
+
+        reg_ring_lane_info_copi                => reg_ring_lane_info_xst_copi_arr(RN),
+        reg_ring_lane_info_cipo                => reg_ring_lane_info_xst_cipo_arr(RN),
+        reg_bsn_monitor_v2_ring_rx_copi        => reg_bsn_monitor_v2_ring_rx_xst_copi_arr(RN),
+        reg_bsn_monitor_v2_ring_rx_cipo        => reg_bsn_monitor_v2_ring_rx_xst_cipo_arr(RN),
+        reg_bsn_monitor_v2_ring_tx_copi        => reg_bsn_monitor_v2_ring_tx_xst_copi_arr(RN),
+        reg_bsn_monitor_v2_ring_tx_cipo        => reg_bsn_monitor_v2_ring_tx_xst_cipo_arr(RN),
+        reg_dp_block_validate_err_copi         => reg_dp_block_validate_err_xst_copi_arr(RN),
+        reg_dp_block_validate_err_cipo         => reg_dp_block_validate_err_xst_cipo_arr(RN),
+        reg_dp_block_validate_bsn_at_sync_copi => reg_dp_block_validate_bsn_at_sync_xst_copi_arr(RN),
+        reg_dp_block_validate_bsn_at_sync_cipo => reg_dp_block_validate_bsn_at_sync_xst_cipo_arr(RN),
+
+        this_rn   => to_uvec(RN, c_byte_w),
+        N_rn      => to_uvec(g_nof_rn, c_byte_w),
+        rx_select => c_use_cable,
+        tx_select => c_use_cable
+      );
+
+    -- Intermediate crosslets alignment at each node
+    u_sdp_crosslets_remote : entity work.sdp_crosslets_remote
+      generic map (
+        g_P_sq  => c_P_sq
+      )
+      port map (
+        dp_clk        => dp_clk,
+        dp_rst        => dp_rst,
+
+        xsel_sosi     => local_crosslets_sosi_arr(RN),
+        from_ri_sosi  => from_ri_sosi_arr(RN),
+        to_ri_sosi    => to_ri_sosi_arr(RN),
+
+        crosslets_sosi     => crosslets_sosi_arr(RN),
+        crosslets_copi     => crosslets_copi_arr(RN),
+        crosslets_cipo_arr => crosslets_cipo_2arr(RN),
+
+        mm_rst        => mm_rst,
+        mm_clk        => mm_clk,
+
+        reg_bsn_align_copi                       => reg_bsn_align_v2_xst_copi_arr(RN),
+        reg_bsn_align_cipo                       => reg_bsn_align_v2_xst_cipo_arr(RN),
+        reg_bsn_monitor_v2_bsn_align_input_copi  => reg_bsn_monitor_v2_xst_rx_align_copi_arr(RN),
+        reg_bsn_monitor_v2_bsn_align_input_cipo  => reg_bsn_monitor_v2_xst_rx_align_cipo_arr(RN),
+        reg_bsn_monitor_v2_bsn_align_output_copi => reg_bsn_monitor_v2_xst_aligned_copi_arr(RN),
+        reg_bsn_monitor_v2_bsn_align_output_cipo => reg_bsn_monitor_v2_xst_aligned_cipo_arr(RN)
+      );
+
+    -- MM -> DP
+    u_st_xsq_mm_to_dp : entity st_lib.st_xsq_mm_to_dp
+    generic map(
+      g_nof_streams       => c_P_sq,
+      g_nof_crosslets     => c_sdp_N_crosslets_max,
+      g_nof_signal_inputs => c_sdp_S_pn,
+      g_dsp_data_w        => c_sdp_W_crosslet
+    )
+    port map(
+      rst          => dp_rst,
+      clk          => dp_clk,
+      in_sosi      => crosslets_sosi_arr(RN),
+      mm_mosi      => crosslets_copi_arr(RN),
+      mm_miso_arr  => crosslets_cipo_2arr(RN),
+      out_sosi_arr => x_sosi_2arr(RN)
+    );
+  end generate;  -- gen_dut
+
+  x_sosi <= x_sosi_2arr(0)(0);
+
+  ------------------------------------------------------------------------------
+  -- Verify crosslets at every node, to check that no packets were lost
+  ------------------------------------------------------------------------------
+  p_verify_crosslets : process(dp_clk)
+  begin
+    for RN in 0 to c_last_rn Loop
+      for P in 0 to c_P_sq - 1 loop
+        if x_sosi_2arr(RN)(P).valid = '1' then
+          assert TO_SINT(x_sosi_2arr(RN)(P).re) /= 0 report "Wrong crosslet re at node " & int_to_str(RN) severity error;
+          assert TO_SINT(x_sosi_2arr(RN)(P).im) /= 0 report "Wrong crosslet im at node " & int_to_str(RN) severity error;
+        end if;
+      end loop;
+    end loop;
+  end process;
+
+  ------------------------------------------------------------------------------
+  -- 10GbE clocks
+  ------------------------------------------------------------------------------
+  u_tech_pll_xgmii_mac_clocks : entity tech_pll_lib.tech_pll_xgmii_mac_clocks
+  port map (
+    refclk_644 => SA_CLK,
+    rst_in     => mm_rst,
+    clk_156    => tr_ref_clk_156,
+    clk_312    => tr_ref_clk_312,
+    rst_156    => tr_ref_rst_156,
+    rst_312    => open
+  );
+
+  ------------------------------------------------------------------------------
+  -- MM bus multiplexers
+  ------------------------------------------------------------------------------
+  -- Use common_mem_mux to avoid (vcom-1450) Actual (indexed name) for formal "mm_miso" is not a static signal name.
+  -- Use downto range for _arr, to match downto range of mosi_arr.
+  u_mem_mux_reg_ring_lane_info_xst : entity common_lib.common_mem_mux
+  generic map (
+    g_nof_mosi    => g_nof_rn,
+    g_mult_addr_w => c_addr_w_reg_ring_lane_info_xst
+  )
+  port map (
+    mosi     => reg_ring_lane_info_xst_copi,
+    miso     => reg_ring_lane_info_xst_cipo,
+    mosi_arr => reg_ring_lane_info_xst_copi_arr,
+    miso_arr => reg_ring_lane_info_xst_cipo_arr
+  );
+
+  u_mem_mux_reg_bsn_monitor_v2_ring_rx_xst : entity common_lib.common_mem_mux
+  generic map (
+    g_nof_mosi    => g_nof_rn,
+    g_mult_addr_w => c_sdp_reg_bsn_monitor_v2_addr_w + ceil_log2(g_nof_rn)
+  )
+  port map (
+    mosi     => reg_bsn_monitor_v2_ring_rx_xst_copi,
+    miso     => reg_bsn_monitor_v2_ring_rx_xst_cipo,
+    mosi_arr => reg_bsn_monitor_v2_ring_rx_xst_copi_arr,
+    miso_arr => reg_bsn_monitor_v2_ring_rx_xst_cipo_arr
+  );
+
+  u_mem_mux_reg_bsn_monitor_v2_ring_tx_xst : entity common_lib.common_mem_mux
+  generic map (
+    g_nof_mosi    => g_nof_rn,
+    g_mult_addr_w => c_sdp_reg_bsn_monitor_v2_addr_w + ceil_log2(g_nof_rn)
+  )
+  port map (
+    mosi     => reg_bsn_monitor_v2_ring_tx_xst_copi,
+    miso     => reg_bsn_monitor_v2_ring_tx_xst_cipo,
+    mosi_arr => reg_bsn_monitor_v2_ring_tx_xst_copi_arr,
+    miso_arr => reg_bsn_monitor_v2_ring_tx_xst_cipo_arr
+  );
+
+  u_mem_mux_reg_bsn_monitor_v2_xst_rx_align : entity common_lib.common_mem_mux
+  generic map (
+    g_nof_mosi    => g_nof_rn,
+    g_mult_addr_w => c_sdp_reg_bsn_monitor_v2_addr_w + ceil_log2(c_P_sq)
+  )
+  port map (
+    mosi     => reg_bsn_monitor_v2_xst_rx_align_copi,
+    miso     => reg_bsn_monitor_v2_xst_rx_align_cipo,
+    mosi_arr => reg_bsn_monitor_v2_xst_rx_align_copi_arr,
+    miso_arr => reg_bsn_monitor_v2_xst_rx_align_cipo_arr
+  );
+
+  u_mem_mux_reg_bsn_monitor_v2_xst_aligned : entity common_lib.common_mem_mux
+  generic map (
+    g_nof_mosi    => g_nof_rn,
+    g_mult_addr_w => c_sdp_reg_bsn_monitor_v2_addr_w
+  )
+  port map (
+    mosi     => reg_bsn_monitor_v2_xst_aligned_copi,
+    miso     => reg_bsn_monitor_v2_xst_aligned_cipo,
+    mosi_arr => reg_bsn_monitor_v2_xst_aligned_copi_arr,
+    miso_arr => reg_bsn_monitor_v2_xst_aligned_cipo_arr
+  );
+
+  u_mem_mux_reg_bsn_align_v2_xst : entity common_lib.common_mem_mux
+  generic map (
+    g_nof_mosi    => g_nof_rn,
+    g_mult_addr_w => c_sdp_reg_bsn_align_v2_addr_w
+  )
+  port map (
+    mosi     => reg_bsn_align_v2_xst_copi,
+    miso     => reg_bsn_align_v2_xst_cipo,
+    mosi_arr => reg_bsn_align_v2_xst_copi_arr,
+    miso_arr => reg_bsn_align_v2_xst_cipo_arr
+  );
+end tb;