From a425b8494e08fe494a97ccfb76e1e32f7b861ea2 Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Wed, 6 Oct 2021 11:38:23 +0200
Subject: [PATCH] Verify lost stream data and lost data flag in channel bit 0,
 via g_lost_stream_id in tb.

---
 .../base/dp/src/vhdl/dp_bsn_align_v2.vhd      | 133 ++++++++++-------
 .../base/dp/tb/vhdl/tb_dp_bsn_align_v2.vhd    | 134 +++++++++++-------
 .../base/dp/tb/vhdl/tb_tb_dp_bsn_align_v2.vhd |  24 ++--
 3 files changed, 175 insertions(+), 116 deletions(-)

diff --git a/libraries/base/dp/src/vhdl/dp_bsn_align_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_align_v2.vhd
index 87dcb99739..2cf94b151e 100644
--- a/libraries/base/dp/src/vhdl/dp_bsn_align_v2.vhd
+++ b/libraries/base/dp/src/vhdl/dp_bsn_align_v2.vhd
@@ -26,13 +26,17 @@
 --   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
---   replacement data. The output streams are paced by the block rate of input 0.
---   The user has to read the block within the block period.
+--   replacement data. The output streams are paced by the block rate of
+--   input 0. The user has to read the block within the block period.
 --
 --   Features:
---   . uses lost_data flag and replacement data to replace lost input blocks
+--   . The g_block_size <= block period, so supports input blocks arriving
+--     with or without data valid gaps
+--   . uses replacement data to replace lost input blocks and channel bit 0 as
+--     lost_data flag
 --   . uses replacement data to replace disabled input streams
---   . output block can be read in arbitrary order
+--   . output block can be read in arbitrary order via g_use_mm_output = TRUE
+--   . output block can be streamed via g_use_mm_output = FALSE
 --
 --   For more detailed description see:
 --   https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+BSN+aligner+v2
@@ -53,13 +57,13 @@ 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_nof_streams                : NATURAL;           -- >= 2, 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_nof_aligners_max           : POSITIVE := 1;     -- 1 when only align at last node, > 1 when align at every intermediate node
     g_block_size                 : NATURAL := 32;     -- > 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_replacement_value          : INTEGER := 0;      -- output sosi data value for missing input blocks
+    g_data_replacement_value     : INTEGER := 0;      -- output sosi data value for missing input blocks
     g_use_mm_output              : BOOLEAN := FALSE;  -- output via MM or via streaming DP
     g_pipeline_input             : NATURAL := 0;      -- >= 0, choose 0 for wires, choose 1 to ease timing closure
     g_rd_latency                 : NATURAL := 1       -- 1 or 2, choose 2 to ease timing closure
@@ -107,10 +111,15 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
   -- avoid that synthesis may infer a too larger multiplier
   CONSTANT c_product_w      : NATURAL := c_blk_pointer_w + c_block_size_w;
 
+  -- Output on lost data flag via out_sosi_arr().channel bit 0
+  CONSTANT c_channel_w      : NATURAL := 1;
+
   TYPE t_bsn_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);
+  TYPE t_channel_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_channel_w-1 DOWNTO 0);
   TYPE t_adr_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_mem_ram.adr_w-1 DOWNTO 0);
   TYPE t_filled_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_buffer_nof_blocks-1 DOWNTO 0);
 
+  -- State
   TYPE t_reg IS RECORD
     -- p_write_arr
     wr_pointer           : NATURAL;
@@ -128,15 +137,21 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
     rd_offset            : STD_LOGIC_VECTOR(c_mem_ram.adr_w-1 DOWNTO 0);
     rd_copi              : t_mem_copi;
     fill_cipo_arr        : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0);  -- used combinatorial to contain rd_cipo_arr from buffer or replacement data
-    out_bsn              : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);  -- hold BSN for streaming output
+    out_bsn              : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);  -- hold BSN until next sop, for easy view in Wave window
+    out_channel_arr      : t_channel_arr(g_nof_streams-1 DOWNTO 0);  -- hold channel until next sop per stream, for easy view in Wave window
   END RECORD;
 
+  -- Wires and auxiliary variables in p_comb
+  -- . For unique representation as signal wire, the p_comb should assign each
+  --   field in t_comb only once to a variable. It is allowed to reasign a
+  --   t_comb variable in p_comb, but then only the last assignment value will
+  --   be visible via the signal dbg_wires in the Wave window.
   TYPE t_comb IS RECORD
-    ref_sosi          : t_dp_sosi;
-    pointer_slv       : STD_LOGIC_VECTOR(c_blk_pointer_w-1 DOWNTO 0);
-    product_slv       : STD_LOGIC_VECTOR(c_product_w-1 DOWNTO 0);
-    lost_data_flag    : STD_LOGIC;
-    out_sosi_arr      : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+    ref_sosi            : t_dp_sosi;
+    pointer_slv         : STD_LOGIC_VECTOR(c_blk_pointer_w-1 DOWNTO 0);
+    product_slv         : STD_LOGIC_VECTOR(c_product_w-1 DOWNTO 0);
+    lost_data_flags_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
+    out_sosi_arr        : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
   END RECORD;
 
   CONSTANT c_reg_rst  : t_reg := (0,
@@ -151,14 +166,15 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
                                   (OTHERS=>'0'),
                                   c_mem_copi_rst,
                                   (OTHERS=>c_mem_cipo_rst),
-                                  (OTHERS=>'0'));
+                                  (OTHERS=>'0'),
+                                  (OTHERS=>(OTHERS=>'0')));
 
   -- State registers for p_comb
   SIGNAL r             : t_reg;
   SIGNAL nxt_r         : t_reg;
 
-  -- Memoryless signals in p_comb (wires used as local auxiliary variables)
-  SIGNAL s             : t_comb;
+  -- Memoryless signals in p_comb (wires used as local variables)
+  SIGNAL dbg_wires     : t_comb;
 
   -- Structural signals (wires used to connect components and IO)
   SIGNAL dp_done       : STD_LOGIC;
@@ -174,18 +190,18 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
   SIGNAL rd_copi       : t_mem_copi;
 
   -- Debug signals
-  SIGNAL dbg_nof_streams         : NATURAL := g_nof_streams;
-  SIGNAL dbg_bsn_latency_max     : NATURAL := g_bsn_latency_max;
-  SIGNAL dbg_nof_aligners_max    : NATURAL := g_nof_aligners_max;
-  SIGNAL dbg_block_size          : NATURAL := g_block_size;
-  SIGNAL dbg_bsn_w               : NATURAL := g_bsn_w;
-  SIGNAL dbg_data_w              : NATURAL := g_data_w;
-  SIGNAL dbg_replacement_value   : INTEGER := g_replacement_value;
-  SIGNAL dbg_use_mm_output       : BOOLEAN := g_use_mm_output;
-  SIGNAL dbg_pipeline_input      : NATURAL := g_pipeline_input;
-  SIGNAL dbg_rd_latency          : NATURAL := g_rd_latency;
-  SIGNAL dbg_c_buffer_nof_blocks : NATURAL := c_buffer_nof_blocks;
-  SIGNAL dbg_c_product_w         : NATURAL := c_product_w;
+  SIGNAL dbg_nof_streams            : NATURAL := g_nof_streams;
+  SIGNAL dbg_bsn_latency_max        : NATURAL := g_bsn_latency_max;
+  SIGNAL dbg_nof_aligners_max       : NATURAL := g_nof_aligners_max;
+  SIGNAL dbg_block_size             : NATURAL := g_block_size;
+  SIGNAL dbg_bsn_w                  : NATURAL := g_bsn_w;
+  SIGNAL dbg_data_w                 : NATURAL := g_data_w;
+  SIGNAL dbg_data_replacement_value : INTEGER := g_data_replacement_value;
+  SIGNAL dbg_use_mm_output          : BOOLEAN := g_use_mm_output;
+  SIGNAL dbg_pipeline_input         : NATURAL := g_pipeline_input;
+  SIGNAL dbg_rd_latency             : NATURAL := g_rd_latency;
+  SIGNAL dbg_c_buffer_nof_blocks    : NATURAL := c_buffer_nof_blocks;
+  SIGNAL dbg_c_product_w            : NATURAL := c_product_w;
 
 BEGIN
 
@@ -202,7 +218,7 @@ BEGIN
   
   p_comb : PROCESS(r, in_sosi_arr_p, mm_copi, dp_copi, rd_cipo_arr, rd_sosi_arr)
     VARIABLE v : t_reg;   -- State variable
-    VARIABLE d : t_comb;  -- Memoryless auxiliary variables, local wires
+    VARIABLE w : t_comb;  -- Local wires = memoryless auxiliary variables
   BEGIN
     v := r;  -- state signals
     v.mm_sosi := func_dp_stream_reset_control(r.mm_sosi);
@@ -222,24 +238,24 @@ BEGIN
 
       IF in_sosi_arr_p(I).sop = '1' THEN
         -- . set address at start of block
-        d.pointer_slv := in_sosi_arr_p(I).bsn(c_blk_pointer_w-1 DOWNTO 0);
-        d.product_slv := MULT_UVEC(d.pointer_slv, c_block_size_slv);
-        v.wr_copi_arr(I).address := RESIZE_MEM_ADDRESS(d.product_slv);
+        w.pointer_slv := in_sosi_arr_p(I).bsn(c_blk_pointer_w-1 DOWNTO 0);
+        w.product_slv := MULT_UVEC(w.pointer_slv, c_block_size_slv);
+        v.wr_copi_arr(I).address := RESIZE_MEM_ADDRESS(w.product_slv);
 
         -- . set filled flag at sop, so assume rest of block will follow in time
-        v.filled_arr(I)(TO_UINT(d.pointer_slv)) := '1';
+        v.filled_arr(I)(TO_UINT(w.pointer_slv)) := '1';
       END IF;
     END LOOP;
 
     ----------------------------------------------------------------------------
     -- p_control, all at sop of local reference input 0
     ----------------------------------------------------------------------------
-    d.ref_sosi := in_sosi_arr_p(0);
-    IF d.ref_sosi.sop = '1' THEN
+    w.ref_sosi := in_sosi_arr_p(0);
+    IF w.ref_sosi.sop = '1' THEN
       -- . write sync & bsn buffer
-      v.wr_pointer := TO_UINT(d.ref_sosi.bsn(c_blk_pointer_w-1 DOWNTO 0));
-      v.sync_arr(v.wr_pointer) := d.ref_sosi.sync;
-      v.bsn_arr(v.wr_pointer) := d.ref_sosi.bsn(g_bsn_w-1 DOWNTO 0);
+      v.wr_pointer := TO_UINT(w.ref_sosi.bsn(c_blk_pointer_w-1 DOWNTO 0));
+      v.sync_arr(v.wr_pointer) := w.ref_sosi.sync;
+      v.bsn_arr(v.wr_pointer) := w.ref_sosi.bsn(g_bsn_w-1 DOWNTO 0);
 
       -- . update read block pointer at g_bsn_latency_max blocks behind the reference write pointer
       IF g_nof_aligners_max = 1 THEN
@@ -252,9 +268,9 @@ BEGIN
       END IF;
 
       -- . update read address of read block pointer
-      d.pointer_slv := TO_UVEC(v.rd_pointer, c_blk_pointer_w);
-      d.product_slv := MULT_UVEC(d.pointer_slv, c_block_size_slv);
-      v.rd_offset := RESIZE_UVEC(d.product_slv, c_mem_ram.adr_w);
+      w.pointer_slv := TO_UVEC(v.rd_pointer, c_blk_pointer_w);
+      w.product_slv := MULT_UVEC(w.pointer_slv, c_block_size_slv);
+      v.rd_offset := RESIZE_UVEC(w.product_slv, c_mem_ram.adr_w);
 
       -- . issue mm_sosi, if there is output ready to be read, indicated by filled reference block
       IF r.filled_arr(0)(v.rd_pointer) = '1' THEN
@@ -268,10 +284,10 @@ BEGIN
         --   determine whether the ouput has to insert replacement data
         v.mm_sosi.channel := (OTHERS=>'0');
         FOR I IN 0 TO g_nof_streams-1 LOOP
-          d.lost_data_flag := NOT v.filled_arr(I)(v.rd_pointer);
+          w.lost_data_flags_arr(I) := NOT v.filled_arr(I)(v.rd_pointer);
           IF stream_en_arr(I) = '1' THEN  -- use MM bit at sop
-            v.use_replacement_data(I) := d.lost_data_flag;  -- enabled stream, so replace the data if the data was lost
-            v.mm_sosi.channel(I) := d.lost_data_flag;  -- enabled stream, so flag the data if the data was lost
+            v.use_replacement_data(I) := w.lost_data_flags_arr(I);  -- enabled stream, so replace the data if the data was lost
+            v.mm_sosi.channel(I) := w.lost_data_flags_arr(I);  -- enabled stream, so flag the data if the data was lost
           ELSE
             v.use_replacement_data(I) := '1';  -- disabled stream, so replace the data, but do not flag the data as lost
           END IF;
@@ -294,7 +310,7 @@ BEGIN
     -- . if necessary, replace a stream by replacement data
     FOR I IN 0 TO g_nof_streams-1 LOOP
       IF r.use_replacement_data(I) = '1' THEN
-        v.fill_cipo_arr(I).rddata := TO_MEM_SDATA(g_replacement_value);
+        v.fill_cipo_arr(I).rddata := TO_MEM_SDATA(g_data_replacement_value);
       END IF;
     END LOOP;
 
@@ -327,26 +343,33 @@ BEGIN
       END IF;
 
       -- . pass on input data from the buffer
-      d.out_sosi_arr := rd_sosi_arr;  -- = v.fill_cipo_arr in streaming format, contains the
+      w.out_sosi_arr := rd_sosi_arr;  -- = v.fill_cipo_arr in streaming format, contains the
                                       -- input data from the buffer or replacement data
       IF rd_sosi_arr(0).sop = '1' THEN
         -- . at sop pass on input info from r.dp_sosi to all streams in out_sosi_arr
-        d.out_sosi_arr := func_dp_stream_arr_set(d.out_sosi_arr, r.dp_sosi.sync, "SYNC");
-        d.out_sosi_arr := func_dp_stream_arr_set(d.out_sosi_arr, r.dp_sosi.bsn, "BSN");
+        w.out_sosi_arr := func_dp_stream_arr_set(w.out_sosi_arr, r.dp_sosi.sync, "SYNC");
+        w.out_sosi_arr := func_dp_stream_arr_set(w.out_sosi_arr, r.dp_sosi.bsn, "BSN");
         FOR I IN 0 TO g_nof_streams-1 LOOP
           -- . pass on the lost flag per stream
-          d.out_sosi_arr(I).channel := RESIZE_DP_CHANNEL(slv(r.dp_sosi.channel(I)));
+          w.out_sosi_arr(I).channel := RESIZE_DP_CHANNEL(slv(r.dp_sosi.channel(I)));
         END LOOP;
 
-        -- . hold BSN until next sop, to ease view in wave window
+        -- . hold sop info fields until next sop, to ease view in wave window
         v.out_bsn := r.dp_sosi.bsn(g_bsn_w-1 DOWNTO 0);
+        FOR I IN 0 TO g_nof_streams-1 LOOP
+          v.out_channel_arr(I) := w.out_sosi_arr(I).channel(c_channel_w-1 DOWNTO 0);
+        END LOOP;
       ELSE
-        -- . until next sop pass on BSN, to ease view in wave window
-        d.out_sosi_arr := func_dp_stream_arr_set(d.out_sosi_arr, r.out_bsn, "BSN");
+        -- . until next sop pass on BSN to all streams, to ease view in wave window
+        w.out_sosi_arr := func_dp_stream_arr_set(w.out_sosi_arr, r.out_bsn, "BSN");
+        FOR I IN 0 TO g_nof_streams-1 LOOP
+           -- . until next sop pass on channel bit 0 per stream, to ease view in wave window
+           w.out_sosi_arr(I).channel := RESIZE_DP_CHANNEL(r.out_channel_arr(I));
+        END LOOP;
       END IF;
 
       -- . output via DP streaming interface
-      out_sosi_arr <= d.out_sosi_arr;
+      out_sosi_arr <= w.out_sosi_arr;
 
       -- . no output via MM interface
       mm_cipo_arr <= (OTHERS => c_mem_cipo_rst);
@@ -357,8 +380,8 @@ BEGIN
     ----------------------------------------------------------------------------
     nxt_r <= v;
 
-    -- memory less signals, only for view in wave window
-    s <= d;
+    -- local wires, only for view in wave window
+    dbg_wires <= w;
   END PROCESS;
 
   ------------------------------------------------------------------------------
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
index 5d735d6e82..fd514dee5c 100644
--- a/libraries/base/dp/tb/vhdl/tb_dp_bsn_align_v2.vhd
+++ b/libraries/base/dp/tb/vhdl/tb_dp_bsn_align_v2.vhd
@@ -25,7 +25,7 @@
 --   . gaps or no gaps between blocks via g_block_period >= g_block_size
 --   . g_bsn_latency_max in combination with g_tb_diff_delay
 --   . g_use_mm_output using DUT MM to DP or external MM to DP in tb
---   . g_replacement_value for a remote g_disable_stream (one is enough
+--   . g_data_replacement_value for a remote g_disable_stream_id (one is enough
 --     to verify), the local stream cannot be disabled.
 -- Usage:
 -- > as 10
@@ -45,24 +45,25 @@ 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_nof_aligners_max     : POSITIVE := 1;     -- 1 when only align at last node, > 1 when align at every intermediate node
-    g_block_size           : NATURAL := 11;     -- > 1, g_block_size=1 is not supported
-    g_block_period         : NATURAL := 20;     -- >= g_block_size, = g_block_size + c_gap_size
-    g_bsn_w                : NATURAL := c_dp_stream_bsn_w;  -- number of bits in sosi BSN
-    g_data_w               : NATURAL := 16;     -- number of bits in sosi data
-    g_replacement_value    : INTEGER := 17;      -- output sosi data replacement value for missing input blocks
-    g_disable_stream       : NATURAL := 0;      -- default 0 to enable all streams, > 0 selects stream that will be disabled
-    g_use_mm_output        : BOOLEAN := FALSE;   -- output via MM or via streaming DP
-    g_pipeline_input       : NATURAL := 0;      -- >= 0, choose 0 for wires, choose 1 to ease timing closure
-    g_rd_latency           : NATURAL := 1;      -- 1 or 2, choose 2 to ease timing closure
+    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_nof_aligners_max       : POSITIVE := 1;     -- 1 when only align at last node, > 1 when align at every intermediate node
+    g_block_size             : NATURAL := 11;     -- > 1, g_block_size=1 is not supported
+    g_block_period           : NATURAL := 20;     -- >= g_block_size, = g_block_size + c_gap_size
+    g_bsn_w                  : NATURAL := c_dp_stream_bsn_w;  -- number of bits in sosi BSN
+    g_data_w                 : NATURAL := 16;     -- number of bits in sosi data
+    g_data_replacement_value : INTEGER := 17;      -- output sosi data replacement value for missing input blocks
+    g_disable_stream_id      : NATURAL := 0;      -- default 0 to enable all streams, > 0 selects stream that will be disabled
+    g_lost_stream_id         : NATURAL := 1;      -- default 0 to have all streams, > 0 selects stream that will be lost
+    g_use_mm_output          : BOOLEAN := FALSE;   -- output via MM or via streaming DP
+    g_pipeline_input         : NATURAL := 0;      -- >= 0, choose 0 for wires, choose 1 to ease timing closure
+    g_rd_latency             : NATURAL := 1;      -- 1 or 2, choose 2 to ease timing closure
 
     -- TB
-    g_tb_diff_delay        : INTEGER := 0;       -- 0 = aligned inputs, -1 = max input delay for no loss,
-                                                 -- >~ g_bsn_latency_max * g_block_period will give loss
-    g_tb_nof_restart       : NATURAL := 2;       -- number of times to restart the input stimuli
-    g_tb_nof_blocks        : NATURAL := 20       -- number of input blocks per restart
+    g_tb_diff_delay          : INTEGER := 0;       -- 0 = aligned inputs, -1 = max input delay for no loss,
+                                                   -- >~ g_bsn_latency_max * g_block_period will give loss
+    g_tb_nof_restart         : NATURAL := 2;       -- number of times to restart the input stimuli
+    g_tb_nof_blocks          : NATURAL := 20       -- number of input blocks per restart
   );
 END tb_dp_bsn_align_v2;
 
@@ -123,6 +124,7 @@ ARCHITECTURE tb OF tb_dp_bsn_align_v2 IS
   SIGNAL node_index            : NATURAL := 0;
 
   SIGNAL stream_en_arr         : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS => '1');  -- default all streams are enabled
+  SIGNAL stream_lost_arr       : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS => '0');  -- default no streams are lost
 
   SIGNAL ref_siso_arr          : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy);
   SIGNAL ref_sosi_arr          : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);                               -- generated stimuli
@@ -160,11 +162,11 @@ ARCHITECTURE tb OF tb_dp_bsn_align_v2 IS
   SIGNAL out_data_arr          : t_data_arr;
   SIGNAL hold_data_arr         : t_data_arr;
   SIGNAL out_bsn_arr           : t_bsn_arr;
+  SIGNAL out_bsn               : INTEGER;
   SIGNAL out_channel_arr       : t_channel_arr;
   SIGNAL out_err_arr           : t_err_arr;
 
   SIGNAL tb_state              : t_tb_state;
-  SIGNAL tb_bsn                : INTEGER;
   SIGNAL restart_cnt_arr       : t_nat_integer_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => -1);
   SIGNAL restart_cnt           : INTEGER := 0;
   SIGNAL ref_sosi_arr_dly      : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);
@@ -173,9 +175,10 @@ ARCHITECTURE tb OF tb_dp_bsn_align_v2 IS
   SIGNAL verify_done_arr       : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS => '0');
   SIGNAL verify_sosi_en_arr    : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS => '0');
 
-  SIGNAL hold_out_sop_arr      : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS => '0');
-  SIGNAL expected_out_bsn_arr  : t_bsn_arr;
-  SIGNAL expected_out_data_arr : t_data_arr;
+  SIGNAL hold_out_sop_arr         : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS => '0');
+  SIGNAL expected_out_bsn_arr     : t_bsn_arr;
+  SIGNAL expected_out_data_arr    : t_data_arr;
+  SIGNAL expected_out_channel_arr : t_channel_arr;
 
   SIGNAL dbg_func_delay_max    : NATURAL := func_input_delay(g_nof_streams - 1);
 
@@ -213,16 +216,30 @@ BEGIN
           v_data := v_data + g_block_size;
           proc_common_wait_some_cycles(clk, c_gap_size);  -- create gap between frames
         END LOOP;
-        -- no gap between restarts, to ease verification by maintaining fixed latency of out_sosi_arr_exp
+        -- no gap between restarts, to ease verification by maintaining fixed
+        -- latency of out_sosi_arr_exp
         restart_cnt_arr(I) <= restart_cnt_arr(I) + 1;
       END LOOP;
 
-      -- End of stimuli, g_bsn_latency_max blocks remain in DUT buffer
+      -- End of stimuli
+      -- . default g_bsn_latency_max blocks remain in DUT buffer
       expected_out_bsn_arr(I) <= TO_UVEC(v_bsn-1 - c_align_latency_nof_blocks, c_bsn_w);
       expected_out_data_arr(I) <= TO_UVEC(v_data-1 - c_align_latency_nof_valid, c_data_w);
-      IF I > 0 AND I = g_disable_stream THEN
-        -- Expected stream disable replacement value
-        expected_out_data_arr(I) <= TO_UVEC(g_replacement_value, c_data_w);
+      -- . default no data is lost, so all channel(0) lost data flags are 0
+      expected_out_channel_arr(I) <= TO_DP_CHANNEL(0);
+
+      -- Account for disturbed remote input streams
+      IF I > 0 THEN
+        IF I = g_disable_stream_id THEN
+          -- Expected stream disable replacement data value
+          expected_out_data_arr(I) <= TO_UVEC(g_data_replacement_value, c_data_w);
+        END IF;
+        IF I = g_lost_stream_id THEN
+          -- Expected stream lost replacement data value and expected lost
+          -- flag channel(0) value
+          expected_out_data_arr(I) <= TO_UVEC(g_data_replacement_value, c_data_w);
+          expected_out_channel_arr(I) <= TO_DP_CHANNEL(1);
+        END IF;
       END IF;
 
       proc_common_wait_some_cycles(clk, 100);
@@ -235,8 +252,26 @@ BEGIN
     END PROCESS;
   END GENERATE;
 
-  -- Model remote input stream enable/disable
-  stream_en_arr(g_disable_stream) <= '0' WHEN g_disable_stream > 0;
+  tb_end <= vector_and(tb_end_arr);
+
+  -- Model misalignment latency between the input streams
+  gen_rx_sosi_arr : FOR I IN g_nof_streams-1 DOWNTO 0 GENERATE
+    rx_sosi_arr(I) <= TRANSPORT ref_sosi_arr(I) AFTER func_input_delay(I) * clk_period;
+  END GENERATE;
+
+  -- Model enable/disable remote input stream
+  stream_en_arr(g_disable_stream_id) <= '0' WHEN g_disable_stream_id > 0;
+
+  -- Model lost remote input stream
+  stream_lost_arr(g_lost_stream_id) <= '1' WHEN g_lost_stream_id > 0;
+
+  p_in_sosi_arr : PROCESS(rx_sosi_arr, stream_lost_arr)
+  BEGIN
+    in_sosi_arr <= rx_sosi_arr;
+    IF stream_lost_arr(g_lost_stream_id) = '1' THEN
+      in_sosi_arr(g_lost_stream_id) <= RESET_DP_SOSI_CTRL(rx_sosi_arr(g_lost_stream_id));
+    END IF;
+  END PROCESS;
 
   -- Use tb_state to view tb progress in Wave window
   restart_cnt <= restart_cnt_arr(0);
@@ -249,16 +284,6 @@ BEGIN
     IF restart_cnt > 1 THEN tb_state <= s_restart; END IF;
   END PROCESS;
 
-  -- Model misalignment latency between the input streams
-  gen_rx_sosi_arr : FOR I IN g_nof_streams-1 DOWNTO 0 GENERATE
-    rx_sosi_arr(I) <= TRANSPORT ref_sosi_arr(I) AFTER func_input_delay(I) * clk_period;
-  END GENERATE;
-
-  -- Model lost input
-  in_sosi_arr <= rx_sosi_arr;
-
-  tb_end <= vector_and(tb_end_arr);
-  
   mon_sosi : FOR I IN g_nof_streams-1 DOWNTO 0 GENERATE
     -- Ease in_sosi_arr monitoring
     in_sync_arr(I)    <= in_sosi_arr(I).sync;
@@ -283,14 +308,14 @@ BEGIN
 
   out_sosi <= out_sosi_arr(0);  -- take out_sosi control and info from out_sosi_arr(0)
 
+  out_bsn <= TO_UINT(out_sosi.bsn);  -- = out_bsn_arr().bsn = out_sosi_arr(I).bsn
+
   ------------------------------------------------------------------------------
   -- DATA VERIFICATION, use multiple ways to increase coverage
-  -- a) Use proc_dp_verify_*() to verify output compared to prev output
-  -- b) Use delayed in_sosi_arr as expected out_sosi_arr
+  -- a) Use proc_dp_verify_*() to verify output sosi format
+  -- b) Use delayed in_sosi_arr as expected out_sosi_arr to verify output sosi
   ------------------------------------------------------------------------------
 
-  tb_bsn <= TO_UINT(out_sosi.bsn);
-
   ref_sosi_arr_dly <= TRANSPORT ref_sosi_arr AFTER c_total_latency * clk_period;
   out_sosi_arr_exp <= ref_sosi_arr_dly WHEN rising_edge(clk);
   out_sosi_exp <= out_sosi_arr_exp(0);  -- take out_sosi_exp control and info from out_sosi_arr_exp(0)
@@ -303,9 +328,9 @@ BEGIN
 
     -- . Verify that the stimuli have been applied at all
     hold_data_arr(I) <= out_data_arr(I) WHEN out_val_arr(I) = '1';  -- hold last valid data
-
     proc_dp_verify_value("out_data_arr", e_equal, clk, verify_done_arr(I), expected_out_data_arr(I), hold_data_arr(I));
     proc_dp_verify_value("out_bsn_arr", e_equal, clk, verify_done_arr(I), expected_out_bsn_arr(I), out_bsn_arr(I));
+    proc_dp_verify_value("out_channel_arr", e_equal, clk, verify_done_arr(I), expected_out_channel_arr(I), out_channel_arr(I));
   END GENERATE;
   
   -- . Use delayed in_sosi_arr as expected out_sosi_arr, this is possible
@@ -329,14 +354,23 @@ BEGIN
            ASSERT out_sosi_arr(I).sop = out_sosi_arr_exp(I).sop REPORT "Wrong sop for output " & int_to_str(I) SEVERITY ERROR;
            ASSERT out_sosi_arr(I).eop = out_sosi_arr_exp(I).eop REPORT "Wrong eop for output " & int_to_str(I) SEVERITY ERROR;
            ASSERT out_sosi_arr(I).valid = out_sosi_arr_exp(I).valid REPORT "Wrong valid for output " & int_to_str(I) SEVERITY ERROR;
-           IF stream_en_arr(I) = '1' THEN
+           -- data field
+           IF stream_en_arr(I) = '1' AND stream_lost_arr(I) = '0' THEN
              ASSERT out_sosi_arr(I).data  = out_sosi_arr_exp(I).data REPORT "Wrong data for output " & int_to_str(I) & " : "
-                                                                            & int_to_str(TO_UINT(out_sosi_arr(I).data)) & " /= "
-                                                                            & int_to_str(TO_UINT(out_sosi_arr_exp(I).data)) SEVERITY ERROR;
+                                                                       & int_to_str(TO_UINT(out_sosi_arr(I).data)) & " /= "
+                                                                       & int_to_str(TO_UINT(out_sosi_arr_exp(I).data)) SEVERITY ERROR;
            ELSE
-             ASSERT TO_UINT(out_sosi_arr(I).data) = g_replacement_value REPORT "Wrong data for output " & int_to_str(I) & " : "
-                                                                               & int_to_str(TO_UINT(out_sosi_arr(I).data)) & " /= "
-                                                                               & int_to_str(g_replacement_value) SEVERITY ERROR;
+             ASSERT TO_UINT(out_sosi_arr(I).data) = g_data_replacement_value REPORT "Wrong replacement data for output " & int_to_str(I) & " : "
+                                                                       & int_to_str(TO_UINT(out_sosi_arr(I).data)) & " /= "
+                                                                       & int_to_str(g_data_replacement_value) SEVERITY ERROR;
+           END IF;
+           IF out_sosi_arr_exp(I).sop = '1' THEN
+             -- channel field with lost flag bit 0
+             IF stream_lost_arr(I) = '0' THEN
+               ASSERT out_sosi_arr(I).channel = out_sosi_arr_exp(I).channel REPORT "Wrong lost flag bit in channel /= 0 for output " & int_to_str(I) SEVERITY ERROR;
+             ELSE
+               ASSERT out_sosi_arr(I).channel = TO_DP_CHANNEL(1) REPORT "Wrong lost flag bit channel /= 1 for output " & int_to_str(I) SEVERITY ERROR;
+             END IF;
            END IF;
         END IF;
       END IF;
@@ -355,7 +389,7 @@ BEGIN
     g_block_size                 => g_block_size,
     g_bsn_w                      => g_bsn_w,
     g_data_w                     => g_data_w,
-    g_replacement_value          => g_replacement_value,
+    g_data_replacement_value     => g_data_replacement_value,
     g_use_mm_output              => g_use_mm_output,    -- output via MM or via streaming DP
     g_pipeline_input             => g_pipeline_input,   -- >= 0, choose 0 for wires, choose 1 to ease timing closure
     g_rd_latency                 => g_rd_latency        -- 1 or 2, choose 2 to ease timing closure
diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_align_v2.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_align_v2.vhd
index c0662c3aee..9bbae41339 100644
--- a/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_align_v2.vhd
+++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_align_v2.vhd
@@ -50,8 +50,9 @@ BEGIN
   -- g_block_period               : NATURAL := 20;     -- >= g_block_size, = g_block_size + c_gap_size
   -- g_bsn_w                      : NATURAL := c_dp_stream_bsn_w;  -- number of bits in sosi BSN
   -- g_data_w                     : NATURAL := 16;     -- number of bits in sosi data
-  -- c_replacement_value          : INTEGER := 0;      -- output sosi data replacement value for missing input blocks
-  -- g_disable_stream             : NATURAL := 0;      -- default 0 to enable all streams, > 0 selects stream that will be disabled
+  -- g_data_replacement_value     : INTEGER := 0;      -- output sosi data replacement value for missing input blocks
+  -- g_disable_stream_id          : NATURAL := 0;      -- default 0 to enable all streams, > 0 selects stream that will be disabled
+  -- g_lost_stream_id             : NATURAL := 0;      -- default 0 to have all streams, > 0 selects stream that will be lost
   -- g_use_mm_output              : BOOLEAN := FALSE;  -- output via MM or via streaming DP
   -- g_pipeline_input             : NATURAL := 1;      -- >= 0, choose 0 for wires, choose 1 to ease timing closure
   -- g_rd_latency                 : NATURAL := 2;      -- 1 or 2, choose 2 to ease timing closure
@@ -62,14 +63,15 @@ BEGIN
   -- g_tb_nof_restart       : NATURAL := 1;       -- number of times to restart the input stimuli
   -- g_tb_nof_blocks        : NATURAL := 10       -- number of input blocks per restart
 
-  u_mm_output           : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block, c_period, 32, 16, 17, 0,  TRUE, 0, 1,  0, 2, c_nof_blk);
-  u_dp_output           : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block, c_period, 32, 16, 17, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
-  u_dp_output_bsn_lat_2 : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 2, 1, c_block, c_period, 32, 16, 17, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
-  u_dp_output_bsn_lat_3 : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 3, 1, c_block, c_period, 32, 16, 17, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
-  u_dp_output_p1_rd2    : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block, c_period, 32, 16, 17, 0, FALSE, 1, 2,  0, 2, c_nof_blk);
-  u_dp_zero_gap         : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block,  c_block, 32, 16, 17, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
-  u_dp_disable_one      : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (4, 1, 1, c_block, c_period, 32, 16, 17, 2, FALSE, 0, 1,  0, 2, c_nof_blk);
-
-  u_diff_delay_no_loss  : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block, c_period, 32, 16, 17, 0, FALSE, 0, 1, -1, 2, c_nof_blk);
+  u_mm_output           : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block, c_period, 32, 16, 17, 0, 0,  TRUE, 0, 1,  0, 2, c_nof_blk);
+  u_dp_output           : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block, c_period, 32, 16, 17, 0, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
+  u_bsn_lat_max_2       : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 2, 1, c_block, c_period, 32, 16, 17, 0, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
+  u_bsn_lat_max_3       : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 3, 1, c_block, c_period, 32, 16, 17, 0, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
+  u_pipe1_rdlat2        : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block, c_period, 32, 16, 17, 0, 0, FALSE, 1, 2,  0, 2, c_nof_blk);
+  u_zero_gap            : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block,  c_block, 32, 16, 17, 0, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
+  u_stream_disable      : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (3, 1, 1, c_block, c_period, 32, 16, 17, 2, 0, FALSE, 0, 1,  0, 2, c_nof_blk);
+  u_stream_lost         : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (3, 1, 1, c_block, c_period, 32, 16, 17, 0, 2, FALSE, 0, 1,  0, 2, c_nof_blk);
+  u_stream_disable_lost : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (4, 1, 1, c_block, c_period, 32, 16, 17, 1, 2, FALSE, 0, 1,  0, 2, c_nof_blk);
+  u_diff_delay_no_loss  : ENTITY work.tb_dp_bsn_align_v2 GENERIC MAP (2, 1, 1, c_block, c_period, 32, 16, 17, 0, 0, FALSE, 0, 1, -1, 2, c_nof_blk);
 
 END tb;
-- 
GitLab