From fadf06530e31a517c277b5f5488ce2fb432c76b4 Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Wed, 4 Aug 2021 16:06:16 +0200
Subject: [PATCH] Fixed out_sosi.sync now starts with long fractional interval.
 Added fast forward of next output_sync_bsn in case of lost blocks.

---
 .../base/dp/src/vhdl/dp_bsn_sync_interval.vhd | 84 +++++++++++++------
 1 file changed, 59 insertions(+), 25 deletions(-)

diff --git a/libraries/base/dp/src/vhdl/dp_bsn_sync_interval.vhd b/libraries/base/dp/src/vhdl/dp_bsn_sync_interval.vhd
index 84ab7eb94b..a3bb5f9c11 100644
--- a/libraries/base/dp/src/vhdl/dp_bsn_sync_interval.vhd
+++ b/libraries/base/dp/src/vhdl/dp_bsn_sync_interval.vhd
@@ -126,16 +126,19 @@ ARCHITECTURE rtl OF dp_bsn_sync_interval IS
     blk_cnt           : NATURAL;
     interval_size     : NATURAL;
     start_bsn         : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);
+    input_bsn         : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);
     nof_blk_min       : NATURAL;
     nof_blk_max       : NATURAL;
-    fraction_size     : INTEGER RANGE -g_block_size TO g_block_size;
+    nof_blk           : NATURAL;
+    extra             : INTEGER;-- RANGE -g_block_size TO g_block_size;
+    accumulate        : INTEGER;-- RANGE -g_block_size TO g_block_size;
     hold_eop          : STD_LOGIC;
     update_bsn        : STD_LOGIC;
     output_enable     : STD_LOGIC;
     output_sync_bsn   : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);
   END RECORD;
 
-  CONSTANT c_reg_rst  : t_reg := ('0', '0', 0, 0, (OTHERS=>'0'), 0, 0, 0, '1', '0', '0', (OTHERS=>'0'));
+  CONSTANT c_reg_rst  : t_reg := ('0', '0', 0, 0, (OTHERS=>'0'), (OTHERS=>'0'), 0, 0, 0, 0, 0, '1', '0', '0', (OTHERS=>'0'));
 
   -- Local registers
   SIGNAL r            : t_reg;
@@ -177,25 +180,33 @@ BEGIN
 
     -- Initialization: calculate number of blocks per output sync interval
     IF r.enable_init = '1' THEN
-      -- Assume ctrl_start_bsn more than nof_blk block periods is after the
-      -- ctrl_enable_evt, so there is sufficient time until v.output_enable =
-      -- '1', to perform the calculation of nof_blk_min and nof_blk_max
-      -- sequentially. This avoids using division to calculate
-      -- ctrl_interval_size / g_block_size.
+      -- Assume ctrl_start_bsn is scheduled more than nof_blk block clk cycles
+      -- after the ctrl_enable_evt, so there is sufficient time until
+      -- v.output_enable = '1', to perform the calculation of nof_blk_min and
+      -- nof_blk_max sequentially. This avoids using division in logic to
+      -- calculate ctrl_interval_size / g_block_size.
       v_size := r.blk_cnt * g_block_size;
       IF v_size = ctrl_interval_size THEN
+        -- Support integer number of blocks per output sync interval
         v.interval_size := ctrl_interval_size;  -- hold ctrl_interval_size
         v.start_bsn := ctrl_start_bsn;          -- hold ctrl_start_bsn
-        v.nof_blk_min := r.blk_cnt;             -- support integer number of blocks per output sync interval
+        -- Fixed sync interval control, effectively disable fractional sync interval control:
+        v.nof_blk_min := r.blk_cnt;
         v.nof_blk_max := r.blk_cnt;
-        v.fraction_size := 0;                   -- = nof_blk_max - nof_blk_min
+        v.nof_blk := r.blk_cnt;                 -- nof_blk = nof_blk_max = nof_blk_min
+        v.extra := 0;
+        v.accumulate := 0;
         v.enable_init := '0';                   -- enable initialization is done
       ELSIF v_size > ctrl_interval_size THEN
+        -- Support fractional number of blocks per output sync interval
         v.interval_size := ctrl_interval_size;  -- hold ctrl_interval_size
         v.start_bsn := ctrl_start_bsn;          -- hold ctrl_start_bsn
-        v.nof_blk_min := r.blk_cnt - 1;         -- support fractional number of blocks per output sync interval
+        -- Fractional sync interval control:
+        v.nof_blk_min := r.blk_cnt - 1;
         v.nof_blk_max := r.blk_cnt;
-        v.fraction_size := v_size - ctrl_interval_size;  -- number of extra samples in nof_blk_max
+        v.nof_blk := r.blk_cnt;                 -- start with nof_blk_max sync interval
+        v.extra := v_size - ctrl_interval_size; -- number of extra samples in nof_blk_max compared to ctrl_interval_size
+        v.accumulate := v.extra;                -- start with nof_blk_max sync interval
         v.enable_init := '0';                   -- enable initialization is done
       ELSE
         v.blk_cnt := r.blk_cnt + 1;
@@ -211,8 +222,8 @@ BEGIN
       v.enable := '1';
     END IF;
 
-    -- Hold eop to detect when input has finished a block and to detect gaps
-    -- between in_sosi.eop and in_sosi.sop
+    -- Hold input eop to detect when input has finished a block and to detect
+    -- gaps between in_sosi.eop and in_sosi.sop
     IF in_sosi.sop = '1' THEN
       v.hold_eop := '0';
     END IF;
@@ -220,16 +231,17 @@ BEGIN
       v.hold_eop := '1';
     END IF;
 
-    -- Output enable at sync and disable after in_sosi.eop
     IF r.enable = '1' THEN
+      -- Output enable at in_sosi.sop start_bsn
       IF in_sosi.sop = '1' THEN
         IF UNSIGNED(in_sosi.bsn) = UNSIGNED(r.start_bsn) THEN
           v.output_enable := '1';
           output_start <= '1';  -- Pulse at start of output enable at start BSN of output sync intervals
-          v.output_sync_bsn := r.start_bsn;
+          v.output_sync_bsn := r.start_bsn;  -- Initialize output sync at start BSN of output sync intervals
         END IF;
       END IF;
     ELSE
+      -- Output disable after in_sosi.eop
       IF r.hold_eop = '1' THEN
         v.output_enable := '0';
       END IF;
@@ -252,19 +264,41 @@ BEGIN
 
     -- Determine BSN for next output sync
     IF r.update_bsn = '1' THEN
-      IF r.fraction_size > 0 THEN
-        v.output_sync_bsn := ADD_UVEC(r.output_sync_bsn, TO_UVEC(r.nof_blk_min, c_natural_w));  -- next BSN
-        v_size := r.nof_blk_min * g_block_size;    -- next interval size
-      ELSE
-        v.output_sync_bsn := ADD_UVEC(r.output_sync_bsn, TO_UVEC(r.nof_blk_max, c_natural_w));  -- next BSN
-        v_size := r.nof_blk_max * g_block_size;    -- next interval size
+      -- Similar code as in proc_dp_verify_sync(), the difference is that:
+      -- . Here r.extra is number of extra samples in nof_blk_max compared to
+      --   ctrl_interval_size,
+      -- . in proc_dp_verify_sync() r.extra is number of extra samples in
+      --   ctrl_interval_size compared to nof_blk_min.
+      -- Both schemes are valid, by using different schemes here and in tb the
+      -- verification coverage improves.
+      v.output_sync_bsn := ADD_UVEC(r.output_sync_bsn, TO_UVEC(r.nof_blk, c_natural_w));  -- next BSN
+
+      v.nof_blk := r.nof_blk_max;
+      v.accumulate := r.accumulate + r.extra;  -- account for nof_blk_max
+      IF v.accumulate >= g_block_size THEN
+        v.nof_blk := r.nof_blk_min;
+        v.accumulate := v.accumulate - g_block_size;  -- adjust for nof_blk_min
       END IF;
-      v.fraction_size := r.fraction_size + v_size - ctrl_interval_size;  -- next fraction
 
-      -- Assume output_sync_bsn is in future, else next in_sosi.sop will
-      -- result in a new update_bsn reqest, to catch up for lost input
-      -- blocks.
+      -- Assume output_sync_bsn is in future
       v.update_bsn := '0';
+
+      -- else last r.input_bsn will be used to keep update_bsn active for
+      -- more clk cycles to catch up for lost input blocks.
+    END IF;
+
+    -- Hold input bsn
+    IF in_sosi.sop = '1' THEN
+      v.input_bsn := in_sosi.bsn(g_bsn_w-1 DOWNTO 0);
+    END IF;
+
+    -- Catch up with output_sync_bsn in case of lost input blocks
+    IF v.output_enable = '1' THEN
+      IF UNSIGNED(r.input_bsn) > UNSIGNED(v.output_sync_bsn) THEN
+        -- Missed one or more input blocks, fast forward to look for next
+        -- output_sync_bsn
+        v.update_bsn := '1';
+      END IF;
     END IF;
 
     nxt_r <= v;
-- 
GitLab