From 88903bf6cb6bd5c54395ebaed32f28acb4b924b0 Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Mon, 6 Sep 2021 16:52:36 +0200
Subject: [PATCH] Prepared dp_bsn_align_v2.vhd (still empty) and mmp_, tb_ and
 tb_mmp_ files, that compile but have no functionality yet.

---
 libraries/base/dp/hdllib.cfg                  |  19 +-
 .../base/dp/src/vhdl/dp_bsn_align_v2.vhd      | 106 +++++
 .../base/dp/src/vhdl/mmp_dp_bsn_align_v2.vhd  | 224 +++++++++
 .../base/dp/tb/vhdl/tb_dp_bsn_align_v2.vhd    | 425 ++++++++++++++++++
 .../dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd     | 191 ++++++++
 5 files changed, 959 insertions(+), 6 deletions(-)
 create mode 100644 libraries/base/dp/src/vhdl/dp_bsn_align_v2.vhd
 create mode 100644 libraries/base/dp/src/vhdl/mmp_dp_bsn_align_v2.vhd
 create mode 100644 libraries/base/dp/tb/vhdl/tb_dp_bsn_align_v2.vhd
 create mode 100644 libraries/base/dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd

diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg
index 9cc984efdd..feea37ef59 100644
--- a/libraries/base/dp/hdllib.cfg
+++ b/libraries/base/dp/hdllib.cfg
@@ -82,6 +82,12 @@ synth_files =
     src/vhdl/dp_block_from_mm.vhd
     src/vhdl/dp_block_from_mm_dc.vhd
     src/vhdl/dp_block_to_mm.vhd
+    src/vhdl/dp_bsn_monitor.vhd
+    src/vhdl/dp_bsn_monitor_reg.vhd
+    src/vhdl/mms_dp_bsn_monitor.vhd
+    src/vhdl/dp_bsn_monitor_v2.vhd
+    src/vhdl/dp_bsn_monitor_reg_v2.vhd
+    src/vhdl/mms_dp_bsn_monitor_v2.vhd
     src/vhdl/dp_bsn_source.vhd
     src/vhdl/dp_bsn_source_v2.vhd
     src/vhdl/dp_bsn_source_reg.vhd
@@ -97,6 +103,8 @@ synth_files =
     src/vhdl/dp_bsn_align.vhd
     src/vhdl/dp_bsn_align_reg.vhd
     src/vhdl/mms_dp_bsn_align.vhd
+    src/vhdl/dp_bsn_align_v2.vhd
+    src/vhdl/mmp_dp_bsn_align_v2.vhd
     src/vhdl/dp_frame_rd.vhd
     src/vhdl/dp_frame_fsn.vhd
     src/vhdl/dp_frame_tx.vhd
@@ -114,12 +122,6 @@ synth_files =
     src/vhdl/dp_packet_dec_channel_lo.vhd
     src/vhdl/dp_gap.vhd
     src/vhdl/dp_mon.vhd
-    src/vhdl/dp_bsn_monitor.vhd
-    src/vhdl/dp_bsn_monitor_reg.vhd
-    src/vhdl/mms_dp_bsn_monitor.vhd
-    src/vhdl/dp_bsn_monitor_v2.vhd
-    src/vhdl/dp_bsn_monitor_reg_v2.vhd
-    src/vhdl/mms_dp_bsn_monitor_v2.vhd
     src/vhdl/dp_distribute.vhd
     src/vhdl/dp_ram_from_mm.vhd
     src/vhdl/dp_ram_from_mm_reg.vhd
@@ -210,6 +212,8 @@ test_bench_files =
     tb/vhdl/tb_dp_block_validate_channel.vhd
     tb/vhdl/tb_dp_bsn_align.vhd
     tb/vhdl/tb_mms_dp_bsn_align.vhd
+    tb/vhdl/tb_dp_bsn_align_v2.vhd
+    tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd
     tb/vhdl/tb_dp_bsn_monitor.vhd
     tb/vhdl/tb_dp_bsn_monitor_v2.vhd
     tb/vhdl/tb_dp_bsn_source.vhd
@@ -294,6 +298,7 @@ test_bench_files =
     tb/vhdl/tb_tb_dp_block_from_mm.vhd
     tb/vhdl/tb_tb_dp_block_validate_channel.vhd
     tb/vhdl/tb_tb_dp_bsn_align.vhd
+    #src/vhdl/tb_tb_dp_bsn_align_v2.vhd
     tb/vhdl/tb_tb_dp_bsn_source_v2.vhd
     tb/vhdl/tb_tb_dp_bsn_sync_scheduler.vhd
     tb/vhdl/tb_tb_dp_concat.vhd
@@ -364,6 +369,8 @@ regression_test_vhdl =
     tb/vhdl/tb_tb_dp_block_from_mm.vhd
     tb/vhdl/tb_tb_dp_block_validate_channel.vhd
     tb/vhdl/tb_tb_dp_bsn_align.vhd
+    #tb/vhdl/tb_tb_dp_bsn_align_v2.vhd
+    tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd
     tb/vhdl/tb_tb_dp_bsn_source_v2.vhd
     tb/vhdl/tb_tb_dp_bsn_sync_scheduler.vhd
     tb/vhdl/tb_tb_dp_concat.vhd
diff --git a/libraries/base/dp/src/vhdl/dp_bsn_align_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_align_v2.vhd
new file mode 100644
index 0000000000..b3ea7dc99f
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/dp_bsn_align_v2.vhd
@@ -0,0 +1,106 @@
+-- --------------------------------------------------------------------------
+-- 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: Eric Kooistra, 3 Sept 2021
+-- Purpose :
+--   Align frames from multiple input streams
+-- Description:
+--   The aligner uses a circular buffer to capture the blocks that arrive at
+--   the input streams. The blocks have a block sequence number (BSN) that
+--   is used to align the inputs. The input stream 0 is treated as local
+--   input stream that is ahead of the other remote input streams. After a
+--   certain number of blocks on input 0, the same block on all remote
+--   inputs should also have arrived. If not then they are replaced by
+--   filler data. The output streams are paced by the block rate of input 0.
+--
+--   For more detailed description see:
+--   https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+BSN+aligner+v2
+--
+-- Remarks:
+-- . This dp_bsn_align_v2.vhd replaces the dp_bsn_align.vhd that was used in
+--   APERTIF. Mian differences are that the old component uses FIFO buffers,
+--   timeouts and states, and v2 does not, which makes v2 simpler and more
+--   robust.
+
+LIBRARY IEEE,common_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 work.dp_stream_pkg.ALL;
+
+
+ENTITY dp_bsn_align_v2 IS
+  GENERIC (
+    g_nof_streams                : NATURAL;           -- number of input and output streams
+    g_bsn_latency_max            : NATURAL;           -- Maximum travel latency of a remote block in number of block periods T_blk
+    g_bsn_latency_use_node_index : BOOLEAN := FALSE;  -- FALSE for align at end node, TRUE for align at every intermediate node
+    g_block_size                 : NATURAL := 32;     -- > 1, g_block_size=1 is not supported
+    g_buffer_nof_blocks          : NATURAL;           -- circular buffer size per input, choose ceil_pow2(1 + g_bsn_latency_max)
+    g_bsn_w                      : NATURAL := c_dp_stream_bsn_w;  -- number of bits in sosi BSN
+    g_data_w                     : NATURAL;           -- number of bits in sosi data
+    g_filler_value               : INTEGER := 0       -- output sosi data value for missing input blocks
+  );
+  PORT (
+    dp_rst         : IN  STD_LOGIC;
+    dp_clk         : IN  STD_LOGIC;
+
+    node_index     : IN  NATURAL := 0;  -- only used when g_bsn_latency_use_node_index is TRUE
+
+    -- MM control
+    in_en_arr      : IN  STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+
+    -- Streaming input
+    in_sosi_arr    : IN  t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+
+    -- Output via local MM interface in dp_clk domain
+    mm_copi        : IN  t_mem_copi;  -- read access to output block, all output streams share same mm_copi
+    mm_cipo_arr    : OUT t_mem_copi_arr(g_nof_streams-1 DOWNTO 0);
+    mm_sosi        : OUT t_dp_sosi   -- streaming information that signals that an output block can be read
+  );
+END dp_bsn_align_v2;
+
+
+ARCHITECTURE rtl OF dp_bsn_align_v2 IS
+
+  TYPE t_reg IS RECORD
+    a           : STD_LOGIC;
+    b           : NATURAL;
+  END RECORD;
+
+  CONSTANT c_reg_rst  : t_reg := ('0', 0);
+
+  -- Local registers
+  SIGNAL r            : t_reg;
+  SIGNAL nxt_r        : t_reg;
+
+BEGIN
+
+  p_clk: PROCESS(dp_clk, dp_rst)
+  BEGIN
+    IF dp_rst='1' THEN
+      r <= c_reg_rst;
+    ELSIF rising_edge(dp_clk) THEN
+      r <= nxt_r;
+    END IF;
+  END PROCESS;
+  
+
+
+
+END rtl;
diff --git a/libraries/base/dp/src/vhdl/mmp_dp_bsn_align_v2.vhd b/libraries/base/dp/src/vhdl/mmp_dp_bsn_align_v2.vhd
new file mode 100644
index 0000000000..69c94300e6
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/mmp_dp_bsn_align_v2.vhd
@@ -0,0 +1,224 @@
+-- --------------------------------------------------------------------------
+-- 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: Eric Kooistra, 6 Sept 2021
+-- Purpose: MMP for dp_bsn_align_v2
+-- Description:
+--   Add MM interfaces to dp_bsn_align_v2:
+--
+--   * Instantiates input BSN monitors when g_nof_input_bsn_monitors > 0
+--   * Instantiates output BSN monitor g_use_bsn_output_monitor = TRUE
+--   * Define MM reg for input enable/disable control for input i:
+--
+--      wi    Bits  Access     Type   Name
+--       i     [0]      RW  boolean   input_enable
+--
+--      where i = 0:g_nof_streams-1 and input_enable '1' is on, '0' is off
+--
+--   For more description see dp_bsn_align_v2 and
+--   https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+BSN+aligner+v2
+
+LIBRARY IEEE, common_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 work.dp_stream_pkg.ALL;
+
+
+ENTITY mmp_dp_bsn_align_v2 IS
+  GENERIC (
+    g_nof_streams                : NATURAL;           -- number of input and output streams
+    g_bsn_latency_max            : NATURAL;           -- Maximum travel latency of a remote block in number of block periods T_blk
+    g_bsn_latency_use_node_index : BOOLEAN := FALSE;  -- FALSE for align at end node, TRUE for align at every intermediate node
+    g_block_size                 : NATURAL := 32;     -- > 1, g_block_size=1 is not supported
+    g_buffer_nof_blocks          : NATURAL;           -- circular buffer size per input, choose ceil_pow2(1 + g_bsn_latency_max)
+    g_bsn_w                      : NATURAL := c_dp_stream_bsn_w;  -- number of bits in sosi BSN
+    g_data_w                     : NATURAL;           -- number of bits in sosi data
+    g_filler_value               : INTEGER := 0;      -- output sosi data value for missing input blocks
+    g_nof_clk_per_sync           : NATURAL := 200*10**6;
+    g_nof_input_bsn_monitors     : NATURAL := 0;
+    g_use_bsn_output_monitor     : BOOLEAN := FALSE
+  );
+  PORT (
+    -- Memory-mapped clock domain
+    mm_rst                  : IN  STD_LOGIC;
+    mm_clk                  : IN  STD_LOGIC;
+
+    reg_copi                : IN  t_mem_copi;
+    reg_cipo                : OUT t_mem_cipo;
+
+    reg_input_monitor_copi  : IN  t_mem_copi;
+    reg_input_monitor_cipo  : OUT t_mem_cipo;
+
+    reg_output_monitor_copi : IN  t_mem_copi;
+    reg_output_monitor_cipo : OUT t_mem_cipo;
+
+    -- Streaming clock domain
+    dp_rst         : IN  STD_LOGIC;
+    dp_clk         : IN  STD_LOGIC;
+
+    node_index     : IN  NATURAL := 0;  -- only used when g_bsn_latency_use_node_index is TRUE
+
+    -- Streaming input
+    in_sosi_arr    : IN  t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+
+    -- Output via local MM in dp_clk domain
+    mm_copi        : IN  t_mem_copi;  -- read access to output block, all output streams share same mm_copi
+    mm_cipo_arr    : OUT t_mem_copi_arr(g_nof_streams-1 DOWNTO 0);
+    mm_sosi        : OUT t_dp_sosi   -- streaming information that signals that an output block can be read
+  );
+END mmp_dp_bsn_align_v2;
+
+
+ARCHITECTURE str OF mmp_dp_bsn_align_v2 IS
+
+  -- Use one MM word (bit 0) per input_enable bit, similar as in dp_bsn_align_reg.vhd.
+
+  -- TYPE t_c_mem IS RECORD
+  --   latency   : NATURAL;    -- read latency
+  --   adr_w     : NATURAL;
+  --   dat_w     : NATURAL;
+  --   nof_dat   : NATURAL;    -- optional, nof dat words <= 2**adr_w
+  --   init_sl   : STD_LOGIC;  -- optional, init all dat words to std_logic '0', '1' or 'X'
+  CONSTANT c_mm_reg     : t_c_mem := (1, ceil_log2(g_nof_streams), 1, g_nof_streams, '0');
+
+  SIGNAL reg_wr         : STD_LOGIC_VECTOR(c_mm_reg.nof_dat*c_mm_reg.dat_w-1 DOWNTO 0);
+  SIGNAL in_en_arr      : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+
+  SIGNAL mm_sosi_arr    : t_dp_sosi_arr(0 DOWNTO 0);
+
+BEGIN
+
+  u_reg : ENTITY common_lib.common_reg_r_w_dc
+  GENERIC MAP (
+    g_cross_clock_domain   => TRUE,
+    g_readback             => FALSE,
+    g_reg                  => c_mm_reg
+  )
+  PORT MAP (
+    -- Clocks and reset
+    mm_rst         => mm_rst,
+    mm_clk         => mm_clk,
+    st_rst         => dp_rst,
+    st_clk         => dp_clk,
+
+    -- Memory Mapped Slave in mm_clk domain
+    sla_in         => reg_copi,
+    sla_out        => reg_cipo,
+
+    -- MM registers in st_clk domain
+    reg_wr_arr     => OPEN,
+    reg_rd_arr     => OPEN,
+    out_reg        => reg_wr,   -- readback via ST clock domain
+    in_reg         => reg_wr
+  );
+
+  in_en_arr <= reg_wr;
+
+  -- Use input BSN monitors for the first g_nof_input_bsn_monitors input
+  -- streams, e.g. to support:
+  -- . only one input stream (g_nof_input_bsn_monitors = 1), or
+  -- . all input streams (g_nof_input_bsn_monitors = g_nof_streams).
+  gen_bsn_mon_input : IF g_nof_input_bsn_monitors > 0 GENERATE
+    u_bsn_mon_input : ENTITY work.mms_dp_bsn_monitor_v2
+    GENERIC MAP (
+      g_nof_streams        => g_nof_input_bsn_monitors,
+      g_cross_clock_domain => TRUE,
+      g_sync_timeout       => g_nof_clk_per_sync,
+      g_bsn_w              => g_bsn_w,
+      g_error_bi           => 0,
+      g_cnt_sop_w          => c_word_w,
+      g_cnt_valid_w        => c_word_w,
+      g_cnt_latency_w      => c_word_w
+    )
+    PORT MAP (
+      -- Memory-mapped clock domain
+      mm_rst         => mm_rst,
+      mm_clk         => mm_clk,
+      reg_mosi       => reg_input_monitor_copi,
+      reg_miso       => reg_input_monitor_cipo,
+
+      -- Streaming clock domain
+      dp_rst         => dp_rst,
+      dp_clk         => dp_clk,
+      ref_sync       => in_sosi_arr(0).sync,  -- local reference sync input
+
+      in_siso_arr    => (OTHERS=>c_dp_siso_rdy),
+      in_sosi_arr    => in_sosi_arr(g_nof_input_bsn_monitors-1 DOWNTO 0)
+    );
+  END GENERATE;
+
+  gen_bsn_mon_output : IF g_use_bsn_output_monitor GENERATE
+    u_bsn_mon_output : ENTITY work.mms_dp_bsn_monitor_v2
+    GENERIC MAP (
+      g_nof_streams        => 1,  -- all outputs have same BSN monitor information
+      g_cross_clock_domain => TRUE,
+      g_sync_timeout       => g_nof_clk_per_sync,
+      g_bsn_w              => g_bsn_w,
+      g_error_bi           => 0,
+      g_cnt_sop_w          => c_word_w,
+      g_cnt_valid_w        => c_word_w,
+      g_cnt_latency_w      => c_word_w
+    )
+    PORT MAP (
+      -- Memory-mapped clock domain
+      mm_rst         => mm_rst,
+      mm_clk         => mm_clk,
+      reg_mosi       => reg_output_monitor_copi,
+      reg_miso       => reg_output_monitor_cipo,
+
+      -- Streaming clock domain
+      dp_rst         => dp_rst,
+      dp_clk         => dp_clk,
+      ref_sync       => in_sosi_arr(0).sync,  -- local reference sync input
+
+      in_siso_arr    => (OTHERS=>c_dp_siso_rdy),
+      in_sosi_arr    => mm_sosi_arr
+    );
+  END GENERATE;
+
+  u_bsn_align : ENTITY work.dp_bsn_align_v2
+  GENERIC MAP (
+    g_nof_streams                => g_nof_streams,
+    g_bsn_latency_max            => g_bsn_latency_max,
+    g_bsn_latency_use_node_index => g_bsn_latency_use_node_index,
+    g_block_size                 => g_block_size,
+    g_buffer_nof_blocks          => g_buffer_nof_blocks,
+    g_bsn_w                      => g_bsn_w,
+    g_data_w                     => g_data_w,
+    g_filler_value               => g_filler_value
+  )
+  PORT MAP (
+    dp_rst         => dp_rst,
+    dp_clk         => dp_clk,
+    node_index     => node_index,
+    -- MM control
+    in_en_arr      => in_en_arr,
+    -- Streaming input
+    in_sosi_arr    => in_sosi_arr,
+    -- Output via local MM in dp_clk domain
+    mm_copi        => mm_copi,
+    mm_cipo_arr    => mm_cipo_arr,
+    mm_sosi        => mm_sosi
+  );
+
+  mm_sosi <= mm_sosi_arr(0);
+
+END str;
+
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_bsn_align_v2.vhd b/libraries/base/dp/tb/vhdl/tb_dp_bsn_align_v2.vhd
new file mode 100644
index 0000000000..1fcccb9e61
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_dp_bsn_align_v2.vhd
@@ -0,0 +1,425 @@
+-- --------------------------------------------------------------------------
+-- 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: Eric Kooistra, 3 Sept 2021
+-- Purpose: Verify dp_bsn_align_v2
+-- Description:
+-- Usage:
+-- > as 10
+-- > run -all
+  
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.common_lfsr_sequences_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE dp_lib.tb_dp_pkg.ALL;
+
+
+ENTITY tb_dp_bsn_align_v2 IS
+  GENERIC (
+    -- DUT
+    g_nof_streams                : NATURAL := 2;      -- number of input and output streams
+    g_bsn_latency_max            : NATURAL := 1;      -- Maximum travel latency of a remote block in number of block periods T_blk
+    g_bsn_latency_use_node_index : BOOLEAN := FALSE;  -- FALSE for align at end node, TRUE for align at every intermediate node
+    g_block_size                 : NATURAL := 17;     -- > 1, g_block_size=1 is not supported
+    g_bsn_w                      : NATURAL := c_dp_stream_bsn_w;  -- number of bits in sosi BSN
+    g_data_w                     : NATURAL;           -- number of bits in sosi data
+    g_filler_value               : INTEGER := 0;      -- output sosi data value for missing input blocks
+
+    -- TB
+    g_diff_delay           : NATURAL := 20;
+    g_diff_bsn             : NATURAL := 3;      -- g_diff_bsn = g_bsn_latency_max can just be aligned
+    g_nof_repeat           : NATURAL := 100     -- for constant active stream control using 1 is sufficient, use > 1 to verify longer with random stimuli
+  );
+END tb_dp_bsn_align_v2;
+
+
+ARCHITECTURE tb OF tb_dp_bsn_align_v2 IS
+
+  CONSTANT c_rl                       : NATURAL := 1;
+  CONSTANT c_pulse_active             : NATURAL := 1;
+  CONSTANT c_pulse_period             : NATURAL := 7;
+  
+  CONSTANT c_data_w                   : NATURAL := 16;
+  CONSTANT c_data_init                : INTEGER := 0;
+  CONSTANT c_bsn_w                    : NATURAL := 16;
+  CONSTANT c_bsn_init                 : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := TO_UVEC(3, c_bsn_w);
+  CONSTANT c_channel_init             : INTEGER := 0;
+  CONSTANT c_err_init                 : NATURAL := 247;
+  CONSTANT c_sync_period              : NATURAL := 7;
+  CONSTANT c_sync_offset              : NATURAL := 2;
+  
+  CONSTANT c_gap_size                 : NATURAL := 10;
+  CONSTANT c_block_period             : NATURAL := g_block_size + c_gap_size;
+  CONSTANT c_xoff_timeout             : NATURAL := c_block_period * g_bsn_latency_max * 2;  -- xoff timeout to recover for next alignment attempt
+  CONSTANT c_sop_timeout              : NATURAL := c_block_period * g_bsn_latency_max;      -- sop timeout to end current aligment attempt
+  
+  CONSTANT c_event_input              : NATURAL := smallest(1, g_nof_streams-1);    -- select special event input at which the event will apply, use >= g_nof_streams to disable the special events
+
+  CONSTANT c_buffer_nof_blocks        : NATURAL := ceil_pow2(1 + g_bsn_latency_max);  -- circular buffer size per input
+
+  TYPE t_data_arr    IS ARRAY (g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
+  TYPE t_bsn_arr     IS ARRAY (g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0);
+  TYPE t_err_arr     IS ARRAY (g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(c_dp_stream_error_w-1 DOWNTO 0);
+  TYPE t_channel_arr IS ARRAY (g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(c_dp_stream_channel_w-1 DOWNTO 0);
+  TYPE t_rl_vec_arr  IS ARRAY (g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(0 TO c_rl);
+
+  TYPE t_tb_state IS (s_idle, s_bsn_mis_aligned, s_bsn_aligned, s_small_bsn_diff, s_large_bsn_diff, s_restore_bsn, s_disable_one_input, s_enable_inputs);
+  
+  SIGNAL tb_end            : STD_LOGIC := '0';
+  SIGNAL clk               : STD_LOGIC := '1';
+  SIGNAL rst               : STD_LOGIC := '1';
+  SIGNAL sl1               : STD_LOGIC := '1';
+
+  SIGNAL random            : STD_LOGIC_VECTOR(15 DOWNTO 0) := (OTHERS=>'0');  -- use different lengths to have different random sequences
+  SIGNAL pulse             : STD_LOGIC;
+  SIGNAL pulse_en          : STD_LOGIC := '1';
+  
+  SIGNAL node_index        : NATURAL := 0;
+
+  SIGNAL in_siso_arr       : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy);
+  SIGNAL in_sosi_arr       : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL in_bsn            : t_bsn_arr;
+  SIGNAL in_data           : t_data_arr;
+  SIGNAL in_val            : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL in_sync           : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL in_sop            : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL in_eop            : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL in_err            : t_err_arr;
+  SIGNAL in_channel        : t_channel_arr;
+  
+  SIGNAL mm_copi           : t_mem_copi;   -- read access to output block, all output streams share same mm_copi
+  SIGNAL mm_cipo_arr       : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL mm_sosi           : t_dp_sosi;   -- streaming information that signals that an output block can be read
+
+  SIGNAL out_siso_arr      : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy);
+  SIGNAL out_sosi_arr      : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL out_bsn           : t_bsn_arr;
+  SIGNAL out_data          : t_data_arr;
+  SIGNAL out_val           : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL out_sync          : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL out_sop           : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL out_eop           : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL out_gap           : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS=>'1');
+  SIGNAL out_err           : t_err_arr;
+  SIGNAL out_channel       : t_channel_arr;
+
+  SIGNAL tb_state          : t_tb_state;
+  
+  SIGNAL verify_done_arr   : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL default_end_arr   : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL default_end       : STD_LOGIC;
+  SIGNAL verify_dis_arr    : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL verify_en_arr     : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS=>'0');
+  
+  SIGNAL hold_out_sop      : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+  SIGNAL prev_out_ready    : t_rl_vec_arr;
+  SIGNAL prev_out_bsn      : t_bsn_arr;
+  SIGNAL expected_out_bsn  : t_bsn_arr;
+  SIGNAL prev_out_data     : t_data_arr;
+  SIGNAL expected_out_data : t_data_arr;
+  
+  SIGNAL verify_extra_end  : STD_LOGIC := '0';
+  SIGNAL bsn_diff          : INTEGER;
+  SIGNAL bsn_offset        : INTEGER;
+  SIGNAL bsn_event         : STD_LOGIC := '0';                                           -- pulse '1' triggers a BSN offset for an input
+  SIGNAL bsn_event_ack_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL bsn_event_ack     : STD_LOGIC;
+  SIGNAL in_en_event       : STD_LOGIC := '0';                                           -- pulse '1' indicates that the input enables in in_en_arr have been updated
+  SIGNAL in_en_arr         : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS=>'1');  -- default all inputs are enabled
+    
+BEGIN
+
+  clk <= (NOT clk) OR tb_end AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*7;
+  
+  random <= func_common_random(random) WHEN rising_edge(clk);
+  
+  proc_common_gen_duty_pulse(c_pulse_active, c_pulse_period+1, '1', rst, clk, pulse_en, pulse);
+
+  ------------------------------------------------------------------------------
+  -- DATA GENERATION
+  ------------------------------------------------------------------------------
+  
+  -- Generate data path input data
+  gen_input : FOR I IN g_nof_streams-1 DOWNTO 0 GENERATE
+    p_stimuli : PROCESS
+      VARIABLE v_sync      : STD_LOGIC := '0';
+      VARIABLE v_bsn       : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := c_bsn_init;
+      VARIABLE v_data      : NATURAL := c_data_init;
+      VARIABLE v_channel   : NATURAL := c_channel_init;
+      VARIABLE v_err       : NATURAL := c_err_init;
+      VARIABLE v_diff_bsn  : NATURAL := 0;
+    BEGIN
+      -- Create BSN misalignment between the input streams
+      v_diff_bsn := I MOD (g_diff_bsn+1);
+      
+      v_data := v_data + I;
+      v_bsn  := INCR_UVEC(v_bsn, v_diff_bsn);
+      in_sosi_arr(I) <= c_dp_sosi_rst;
+      proc_common_wait_until_low(clk, rst);
+      proc_common_wait_some_cycles(clk, c_xoff_timeout*2);
+      
+      -- Create latency misalignment between the input streams
+      proc_common_wait_some_cycles(clk, I*g_diff_delay/g_nof_streams);
+      
+      -- Begin of stimuli
+      FOR R IN 0 TO g_nof_repeat-v_diff_bsn-1 LOOP
+        v_sync := sel_a_b(TO_UINT(v_bsn) MOD c_sync_period = c_sync_offset, '1', '0');
+        proc_dp_gen_block_data(c_rl, TRUE, c_data_w, c_data_w, v_data, 0, 0, g_block_size, v_channel, v_err, v_sync, v_bsn, clk, in_en_arr(I), in_siso_arr(I), in_sosi_arr(I));
+        v_bsn  := INCR_UVEC(v_bsn, 1);
+        v_data := v_data + g_block_size;
+        proc_common_wait_some_cycles(clk, c_gap_size);               -- create gap between frames
+      END LOOP;
+      
+      -- End of default stimuli
+      expected_out_bsn(I)  <= INCR_UVEC(v_bsn, -1);
+      expected_out_data(I) <= TO_UVEC(v_data-1, c_data_w);
+      
+      proc_common_wait_some_cycles(clk, 100);  -- depends on stream control
+      default_end_arr(I) <= '1';
+      verify_done_arr(I) <= '1';
+      proc_common_wait_some_cycles(clk, 1);
+      verify_done_arr(I) <= '0';
+      
+      --------------------------------------------------------------------------
+      -- Extra
+      --------------------------------------------------------------------------
+      
+      proc_common_wait_some_cycles(clk, 500);
+      WHILE verify_extra_end /= '1' LOOP
+        v_sync := sel_a_b(TO_UINT(v_bsn) MOD c_sync_period = c_sync_offset, '1', '0');
+        proc_dp_gen_block_data(c_rl, TRUE, c_data_w, c_data_w, v_data, 0, 0, g_block_size, v_channel, v_err, v_sync, v_bsn, clk, in_en_arr(I), in_siso_arr(I), in_sosi_arr(I));
+        v_bsn := INCR_UVEC(v_bsn, 1);
+        bsn_event_ack_arr(I) <= '0';
+        IF I=c_event_input AND bsn_event='1' THEN
+          v_bsn := INCR_UVEC(v_bsn, bsn_offset);
+          bsn_event_ack_arr(I) <= '1';
+        END IF;
+        v_data := v_data + g_block_size;
+        proc_common_wait_some_cycles(clk, c_gap_size);               -- create gap between frames
+      END LOOP;
+      
+      -- End of extra stimuli
+      expected_out_bsn(I)  <= INCR_UVEC(v_bsn, -1);
+      expected_out_data(I) <= TO_UVEC(v_data-1, c_data_w);
+      
+      verify_done_arr(I) <= '1';
+      proc_common_wait_some_cycles(clk, 1);
+      verify_done_arr(I) <= '0';
+      WAIT;
+    END PROCESS;
+  END GENERATE;
+  
+  default_end   <= vector_and(default_end_arr);
+  bsn_event_ack <= vector_or(bsn_event_ack_arr);
+  
+  p_special_stimuli : PROCESS
+  BEGIN
+    verify_dis_arr <= (OTHERS=>'0');
+    
+    tb_state <= s_bsn_mis_aligned;  
+    in_en_event    <= '0';
+    in_en_arr      <= (OTHERS=>'1');
+
+    ----------------------------------------------------------------------------
+    -- Wait until default verify test is done
+    ----------------------------------------------------------------------------
+    
+    proc_common_wait_until_high(clk, default_end);
+    
+    verify_dis_arr <= (OTHERS=>'1');
+    proc_common_wait_some_cycles(clk, 100);
+    verify_dis_arr <= (OTHERS=>'0');
+    
+    tb_state <= s_bsn_aligned;
+    proc_common_wait_some_cycles(clk, 1000);
+    
+    ----------------------------------------------------------------------------
+    -- Verify change in input BSN offset
+    ----------------------------------------------------------------------------
+
+    -- . enforce small BSN misalignment
+    tb_state <= s_small_bsn_diff;
+    verify_dis_arr <= (OTHERS=>'1');
+    bsn_offset <= -1;
+    bsn_event <= '1';
+    proc_common_wait_until_high(clk, bsn_event_ack);
+    bsn_event <= '0';
+    proc_common_wait_some_cycles(clk, 100);
+    
+    verify_dis_arr <= (OTHERS=>'0');
+    proc_common_wait_some_cycles(clk, 1000);
+    verify_dis_arr <= (OTHERS=>'1');
+    
+    -- . restore original BSN sequence
+    tb_state <= s_restore_bsn;
+    bsn_offset <= +1;
+    bsn_event <= '1';
+    proc_common_wait_until_high(clk, bsn_event_ack);
+    bsn_event <= '0';
+    proc_common_wait_some_cycles(clk, 100);
+    
+    verify_dis_arr <= (OTHERS=>'0');
+    proc_common_wait_some_cycles(clk, 1000);
+--     verify_dis_arr <= (OTHERS=>'1');
+    
+    -- . enforce large BSN misalignment
+    tb_state <= s_large_bsn_diff;
+    bsn_offset <= -g_bsn_latency_max-1;
+    bsn_event <= '1';
+    proc_common_wait_until_high(clk, bsn_event_ack);
+    bsn_event <= '0';
+    -- expect no output, because difference remains too large, so do not restart verify_en here and leave it commented:
+--     proc_common_wait_some_cycles(clk, 100);
+--     verify_dis_arr <= (OTHERS=>'0');
+    proc_common_wait_some_cycles(clk, 1000);
+    verify_dis_arr <= (OTHERS=>'1');
+    
+    -- . restore original BSN sequence
+    tb_state <= s_restore_bsn;
+    bsn_offset <= g_bsn_latency_max+1;
+    bsn_event <= '1';
+    proc_common_wait_until_high(clk, bsn_event_ack);
+    bsn_event <= '0';
+    proc_common_wait_some_cycles(clk, 100);
+    verify_dis_arr <= (OTHERS=>'0');
+    proc_common_wait_some_cycles(clk, 1000);
+    
+    ----------------------------------------------------------------------------
+    -- Verify change in input enables
+    ----------------------------------------------------------------------------
+    
+    tb_state <= s_disable_one_input;
+    verify_dis_arr <= (OTHERS=>'1');
+    in_en_event <= '1';
+    in_en_arr(c_event_input) <= '0';            -- switch an input off
+    proc_common_wait_some_cycles(clk, 1);
+    in_en_event <= '0';
+    proc_common_wait_some_cycles(clk, 100);
+    verify_dis_arr <= (OTHERS=>'0');
+    proc_common_wait_some_cycles(clk, 2000);    -- keep this input off for a while
+    
+    tb_state <= s_enable_inputs;
+    verify_dis_arr <= (OTHERS=>'1');
+    in_en_event <= '1';
+    in_en_arr(c_event_input) <= '1';            -- switch this input on
+    proc_common_wait_some_cycles(clk, 1);
+    in_en_event <= '0';
+    proc_common_wait_some_cycles(clk, 100);
+    verify_dis_arr <= (OTHERS=>'0');
+    proc_common_wait_some_cycles(clk, 500);
+    
+    tb_state <= s_restore_bsn;
+    verify_dis_arr <= (OTHERS=>'1');
+    bsn_offset <= bsn_diff;  -- use input 0 to restore original BSN sequence for input c_event_input, that got lost due to input disable 
+    bsn_event <= '1';
+    proc_common_wait_until_high(clk, bsn_event_ack);
+    bsn_event <= '0';
+    proc_common_wait_some_cycles(clk, 100);
+    verify_dis_arr <= (OTHERS=>'0');
+    proc_common_wait_some_cycles(clk, 2000);
+    
+    tb_state <= s_idle;
+    verify_extra_end <= '1';
+    proc_common_wait_some_cycles(clk, 500);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+  
+  bsn_diff <= TO_UINT(in_sosi_arr(0).bsn) - TO_UINT(in_sosi_arr(c_event_input).bsn) WHEN rising_edge(clk) AND in_sosi_arr(0).sop='1';
+  
+  ------------------------------------------------------------------------------
+  -- DATA VERIFICATION
+  ------------------------------------------------------------------------------
+  
+  gen_verify : FOR I IN g_nof_streams-1 DOWNTO 0 GENERATE
+    -- Verification logistics
+    verify_en_arr(I) <= '1' WHEN rising_edge(clk) AND verify_dis_arr(I)='0' AND in_en_arr(I)='1' AND out_sosi_arr(I).sop='1' ELSE
+                        '0' WHEN rising_edge(clk) AND verify_dis_arr(I)='1';    -- verify enable after first output sop
+    
+    -- Ease in_sosi_arr monitoring
+    in_data(I)    <= in_sosi_arr(I).data(c_data_w-1 DOWNTO 0);
+    in_val(I)     <= in_sosi_arr(I).valid;
+    in_sop(I)     <= in_sosi_arr(I).sop;
+    in_eop(I)     <= in_sosi_arr(I).eop;
+    in_err(I)     <= in_sosi_arr(I).err;
+    in_channel(I) <= in_sosi_arr(I).channel;
+    in_sync(I)    <= in_sosi_arr(I).sync;
+    in_bsn(I)     <= in_sosi_arr(I).bsn(c_bsn_w-1 DOWNTO 0);
+
+    -- Ease out_sosi_arr monitoring and verification
+    out_data(I)    <= out_sosi_arr(I).data(c_data_w-1 DOWNTO 0);
+    out_val(I)     <= out_sosi_arr(I).valid;
+    out_sop(I)     <= out_sosi_arr(I).sop;
+    out_eop(I)     <= out_sosi_arr(I).eop;
+    out_err(I)     <= out_sosi_arr(I).err;
+    out_channel(I) <= out_sosi_arr(I).channel;
+    out_sync(I)    <= out_sosi_arr(I).sync;
+    out_bsn(I)     <= out_sosi_arr(I).bsn(c_bsn_w-1 DOWNTO 0);
+    
+    -- Actual verification of the output streams
+    -- . Verify that the output valid fits with the output ready latency
+    proc_dp_verify_valid(c_rl, clk, verify_en_arr(I), out_siso_arr(I).ready, prev_out_ready(I), out_val(I));
+    -- . Verify that sop and eop come in pairs
+    proc_dp_verify_sop_and_eop(clk, out_val(I), out_sop(I), out_eop(I), hold_out_sop(I));
+    
+    -- . Verify that the output is incrementing, like the input stimuli
+    proc_dp_verify_data("out_sosi.data", c_rl, clk, verify_en_arr(I), out_siso_arr(I).ready, out_val(I), out_data(I), prev_out_data(I));
+    proc_dp_verify_data("out_sosi.bsn", c_rl, clk, verify_en_arr(I), out_siso_arr(I).ready, out_sop(I), out_bsn(I), prev_out_bsn(I));
+    
+    -- . Verify that the stimuli have been applied at all
+    proc_dp_verify_value(e_equal, clk, verify_done_arr(I), expected_out_data(I), prev_out_data(I));
+    proc_dp_verify_value(e_equal, clk, verify_done_arr(I), expected_out_bsn(I),  prev_out_bsn(I));
+  END GENERATE;
+  
+  
+  ------------------------------------------------------------------------------
+  -- DUT 
+  ------------------------------------------------------------------------------
+  
+  u_bsn_align : ENTITY work.dp_bsn_align_v2
+  GENERIC MAP (
+    g_nof_streams                => g_nof_streams,
+    g_bsn_latency_max            => g_bsn_latency_max,
+    g_bsn_latency_use_node_index => g_bsn_latency_use_node_index,
+    g_block_size                 => g_block_size,
+    g_buffer_nof_blocks          => c_buffer_nof_blocks,
+    g_bsn_w                      => g_bsn_w,
+    g_data_w                     => g_data_w,
+    g_filler_value               => g_filler_value
+  )
+  PORT MAP (
+    dp_rst         => rst,
+    dp_clk         => clk,
+    -- Control
+    node_index     => node_index,
+    in_en_arr      => in_en_arr,
+    -- Streaming input
+    in_sosi_arr    => in_sosi_arr,
+    -- Output via local MM in dp_clk domain
+    mm_copi        => mm_copi,
+    mm_cipo_arr    => mm_cipo_arr,
+    mm_sosi        => mm_sosi
+  );
+  
+END tb;
diff --git a/libraries/base/dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd b/libraries/base/dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd
new file mode 100644
index 0000000000..e9003e6c0d
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd
@@ -0,0 +1,191 @@
+-- --------------------------------------------------------------------------
+-- 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: E. Kooistra, 6 sept 2021
+-- Purpose: Verify MM part of mmp_dp_bsn_align_v2
+-- Description:
+--    The functional part is already verified by tb_tb_dp_bsn_align_v2.vhd.
+-- Usage:
+-- > as 5
+-- > run -all
+  
+LIBRARY IEEE, common_lib, technology_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL; 
+USE common_lib.common_str_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+USE work.tb_dp_pkg.ALL;
+
+ENTITY tb_mmp_dp_bsn_align_v2 IS
+END tb_mmp_dp_bsn_align_v2;
+
+
+ARCHITECTURE tb OF tb_mmp_dp_bsn_align_v2 IS
+
+  CONSTANT c_mm_clk_period              : TIME := 40 ns;
+  CONSTANT c_dp_clk_period              : TIME := 10 ns;
+  CONSTANT c_cross_clock_domain_latency : NATURAL := 20;
+
+  CONSTANT c_report_note                : BOOLEAN := FALSE;  -- Use TRUE for tb debugging, else FALSE to keep Transcript window more empty
+
+  CONSTANT c_nof_input_sync             : NATURAL := 10;
+  CONSTANT c_nof_block_per_sync         : NATURAL := 32;
+  CONSTANT c_block_size                 : NATURAL := 10;
+  CONSTANT c_input_gap_size             : NATURAL := 3;
+  CONSTANT c_sim_nof_blocks             : NATURAL := c_nof_block_per_sync * c_nof_input_sync;
+
+  CONSTANT c_nof_streams                : NATURAL := 2;
+  CONSTANT c_bsn_latency_max            : NATURAL := 2;
+  CONSTANT c_bsn_latency_use_node_index : BOOLEAN := FALSE;
+  CONSTANT c_buffer_nof_blocks          : NATURAL := ceil_pow2(1 + c_bsn_latency_max);
+  CONSTANT c_bsn_w                      : NATURAL := c_dp_stream_bsn_w;
+  CONSTANT c_data_w                     : NATURAL := 16;
+  CONSTANT c_filler_value               : INTEGER := 0;
+  CONSTANT c_nof_clk_per_sync           : NATURAL := 200*10**6;
+  CONSTANT c_nof_input_bsn_monitors     : NATURAL := 0;
+  CONSTANT c_use_bsn_output_monitor     : BOOLEAN := FALSE;
+
+  SIGNAL tb_end                   : STD_LOGIC := '0';
+  SIGNAL stimuli_end              : STD_LOGIC := '0';
+
+  -- MM clock domain
+  SIGNAL mm_clk                   : STD_LOGIC := '1';
+  SIGNAL mm_rst                   : STD_LOGIC := '1';
+
+  SIGNAL reg_copi                 : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_cipo                 : t_mem_cipo;
+  SIGNAL reg_input_monitor_copi   : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_input_monitor_cipo   : t_mem_cipo;
+  SIGNAL reg_output_monitor_copi  : t_mem_copi := c_mem_copi_rst;
+  SIGNAL reg_output_monitor_cipo  : t_mem_cipo;
+
+  -- DP clock domain
+  SIGNAL dp_clk                   : STD_LOGIC := '1';
+  SIGNAL dp_rst                   : STD_LOGIC := '1';
+
+  SIGNAL node_index               : NATURAL := 0;  -- only used when g_bsn_latency_use_node_index is TRUE
+  SIGNAL stimuli_sosi             : t_dp_sosi;
+  SIGNAL in_sosi_arr              : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0);
+  SIGNAL mm_copi                  : t_mem_copi;   -- read access to output block, all output streams share same mm_copi
+  SIGNAL mm_cipo_arr              : t_mem_copi_arr(c_nof_streams-1 DOWNTO 0);
+  SIGNAL mm_sosi                  : t_dp_sosi;   -- streaming information that signals that an output block can be read
+
+BEGIN
+
+  dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2;
+  mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2;
+  dp_rst <= '1', '0' AFTER c_dp_clk_period*7;    
+  mm_rst <= '1', '0' AFTER c_mm_clk_period*7;
+  
+  ------------------------------------------------------------------------------
+  -- MM stimuli and verification
+  ------------------------------------------------------------------------------
+
+  p_stimuli_and_verify_mm : PROCESS
+    VARIABLE v_bsn : NATURAL;
+  BEGIN              
+    proc_common_wait_until_low(dp_clk, mm_rst);
+    proc_common_wait_until_low(dp_clk, dp_rst);
+    proc_common_wait_some_cycles(mm_clk, 5);
+
+
+    ---------------------------------------------------------------------------
+    -- End of test
+    ---------------------------------------------------------------------------
+    proc_common_wait_until_high(dp_clk, stimuli_end);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+
+  ------------------------------------------------------------------------------
+  -- Streaming stimuli
+  ------------------------------------------------------------------------------
+
+  -- Generate data blocks with input sync
+  u_stimuli : ENTITY work.dp_stream_stimuli
+  GENERIC MAP (
+    g_sync_period  => c_nof_block_per_sync,
+    g_err_init     => 0,
+    g_err_incr     => 0,  -- do not increment, to not distract from viewing of BSN in Wave window
+    g_channel_init => 0,
+    g_channel_incr => 0,  -- do not increment, to not distract from viewing of BSN in Wave window
+    g_nof_repeat   => c_sim_nof_blocks,
+    g_pkt_len      => c_block_size,
+    g_pkt_gap      => c_input_gap_size
+  )
+  PORT MAP (
+    rst               => dp_rst,
+    clk               => dp_clk,
+
+    -- Generate stimuli
+    src_out           => stimuli_sosi,
+
+    -- End of stimuli
+    tb_end            => stimuli_end
+  );
+
+  in_sosi_arr <= (OTHERS => stimuli_sosi);
+
+  ------------------------------------------------------------------------------
+  -- DUT
+  ------------------------------------------------------------------------------
+
+  u_bsn_align : ENTITY work.mmp_dp_bsn_align_v2
+  GENERIC MAP (
+    g_nof_streams                => c_nof_streams,
+    g_bsn_latency_max            => c_bsn_latency_max,
+    g_bsn_latency_use_node_index => c_bsn_latency_use_node_index,
+    g_block_size                 => c_block_size,
+    g_buffer_nof_blocks          => c_buffer_nof_blocks,
+    g_bsn_w                      => c_bsn_w,
+    g_data_w                     => c_data_w,
+    g_filler_value               => c_filler_value,
+    g_nof_clk_per_sync           => c_nof_clk_per_sync,
+    g_nof_input_bsn_monitors     => c_nof_input_bsn_monitors,
+    g_use_bsn_output_monitor     => c_use_bsn_output_monitor
+  )
+  PORT MAP (
+    mm_rst                  => mm_rst,
+    mm_clk                  => mm_clk,
+
+    reg_copi                => reg_copi,
+    reg_cipo                => reg_cipo,
+
+    reg_input_monitor_copi  => reg_input_monitor_copi,
+    reg_input_monitor_cipo  => reg_input_monitor_cipo,
+
+    reg_output_monitor_copi => reg_output_monitor_copi,
+    reg_output_monitor_cipo => reg_output_monitor_cipo,
+
+    dp_rst                  => dp_rst,
+    dp_clk                  => dp_clk,
+
+    node_index              => node_index,
+    -- Streaming input
+    in_sosi_arr             => in_sosi_arr,
+    -- Output via local MM in dp_clk domain
+    mm_copi                 => mm_copi,
+    mm_cipo_arr             => mm_cipo_arr,
+    mm_sosi                 => mm_sosi
+  );
+
+END tb;
-- 
GitLab