From 80ac83afd8e1deb1e5ffa074472202f209e126b1 Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Tue, 12 Sep 2023 10:57:51 +0200
Subject: [PATCH] Add flow control.

---
 .../base/dp/src/vhdl/dp_packet_unmerge.vhd    | 117 +++++++++++++++---
 .../dp/tb/vhdl/tb_dp_packet_merge_unmerge.vhd |  19 +--
 .../tb/vhdl/tb_tb_dp_packet_merge_unmerge.vhd |  40 +++---
 3 files changed, 128 insertions(+), 48 deletions(-)

diff --git a/libraries/base/dp/src/vhdl/dp_packet_unmerge.vhd b/libraries/base/dp/src/vhdl/dp_packet_unmerge.vhd
index d7f294f821..2a7d978adb 100644
--- a/libraries/base/dp/src/vhdl/dp_packet_unmerge.vhd
+++ b/libraries/base/dp/src/vhdl/dp_packet_unmerge.vhd
@@ -39,15 +39,34 @@
 --   and remain valid until the snk_in.eop. Hence these signals are then valid
 --   when snk_in.valid = '1'. Use same snk_in.err and snk_in.empty value for
 --   all unmerged packets.
+--                      _                       _                       _
+--   snk_in.sop   _____| |_____________________| |_____________________| |_
+--                                            _                       _
+--   snk_in.eop   ___________________________| |_____________________| |___
+--                      _       _       _       _       _       _       _
+--   src_out.sop  _____|0|_____|1|_____|2|_____|0|_____|1|_____|2|_____|0|_
+--                            _       _       _       _       _       _
+--   src_out.eop  ___________|0|_____|1|_____|2|_____|0|_____|1|_____|2|___
 --
---                    _                             _                             _
--- snk_in.sop   _____| |___________________________| |___________________________| |_
---                                                _                             _
--- snk_in.eop   _________________________________| |___________________________| |___
---                    _         _         _         _         _         _         _
--- src_out.sop  _____|0|_______|1|_______|2|_______|0|_______|1|_______|2|_______|0|_
---                            _         _         _         _         _         _
--- src_out.eop  _____________|0|_______|1|_______|2|_______|0|_______|1|_______|2|___
+-- . Flow control.
+--   . The component does not add additional snk_out.ready flow control itself,
+--     but it can listen to external src_in.ready flow control.
+--   - If g_use_src_in_ready = false, then src_in is ignored, so no flow
+--     control, else do use flow control by src_in.ready.
+--   - If g_use_src_in_ready = true, then g_use_dp_latency_adapter = false
+--     determines that the src_in.ready is used combinatorially else the
+--     src_in.ready is used registered.
+--   . The p_reg increases the ready latency (RL) by 1, because p_comb does
+--     not use src_in.ready, instead p_comb drives d.src_out based on the
+--     snk_in.sop, eop, valid. Therefore c_use_dp_latency_adapter = true is
+--     needed to restore the RL from 2 to 1 for the src_out the output. The
+--     alternative is to use a dp_pipeline to register d.src_out in
+--     combination with src_in.ready at the input, to keep RL at 1.
+--     The p_reg keeps the internal state of the component. With dp_pipeline
+--     a separate output register is needed to store src_out. With the
+--     dp_latency_adapter a feq register stages are needed to store src_out,
+--     but the adantage of dp_latency_adapter is that it also registers the
+--     src_in.ready so that may ease timing closure.
 
 library IEEE,common_lib;
 use IEEE.std_logic_1164.all;
@@ -57,9 +76,11 @@ use work.dp_stream_pkg.all;
 
 entity dp_packet_unmerge is
   generic (
-    g_nof_pkt_max   : natural := 1;  -- Maximum nof packets to unmerge each incoming packet to
-    g_pkt_len       : natural := 1;  -- Length of the unmerged packets
-    g_bsn_increment : natural := 0
+    g_use_src_in_ready         : boolean := false;
+    g_use_dp_latency_adapter   : boolean := true;
+    g_nof_pkt_max              : natural := 1;  -- Maximum nof packets to unmerge each incoming packet to
+    g_pkt_len                  : natural := 1;  -- Length of the unmerged packets
+    g_bsn_increment            : natural := 0
   );
   port (
     rst         : in  std_logic;
@@ -68,7 +89,7 @@ entity dp_packet_unmerge is
     snk_out     : out t_dp_siso;
     snk_in      : in  t_dp_sosi;
 
-    src_in      : in  t_dp_siso;
+    src_in      : in  t_dp_siso := c_dp_siso_rst;
     src_out     : out t_dp_sosi
   );
 end dp_packet_unmerge;
@@ -82,13 +103,64 @@ architecture rtl of dp_packet_unmerge is
 
   constant c_reg_rst : t_reg := (0, 0, c_dp_sosi_rst);
 
+  constant c_use_dp_latency_adapter : boolean := false;
+
   signal r : t_reg;
   signal d : t_reg;
 
+  -- Signals for c_use_dp_latency_adapter = false
+
+  -- Signals for c_use_dp_latency_adapter = true
+  signal dp_latency_adapter_snk_out : t_dp_siso;
+  signal dp_latency_adapter_snk_in  : t_dp_sosi;
+  signal dp_latency_adapter_src_in  : t_dp_siso;
+  signal dp_latency_adapter_src_out : t_dp_sosi;
 begin
   -- Map t_reg outputs to entity outputs
-  snk_out <= src_in;
-  src_out <= r.src_out;
+  no_flow_control : if g_use_src_in_ready = false generate
+    snk_out <= c_dp_siso_rdy;
+    src_out <= r.src_out;
+  end generate;
+
+  gen_use_src_in_ready : if g_use_src_in_ready = true generate
+    gen_dp_pipeline : if c_use_dp_latency_adapter = false generate
+      u_dp_pipeline : entity work.dp_pipeline
+      port map (
+        rst          => rst,
+        clk          => clk,
+        -- ST sink
+        snk_out      => snk_out,
+        snk_in       => d.src_out,
+        -- ST source
+        src_in       => src_in,
+        src_out      => src_out
+      );
+    end generate;
+
+    gen_dp_latency_adapter : if c_use_dp_latency_adapter = true generate
+      snk_out <= dp_latency_adapter_snk_out;
+      dp_latency_adapter_snk_in <= r.src_out;
+
+      u_dp_latency_adapter : entity work.dp_latency_adapter
+      generic map (
+        g_in_latency  => 2,
+        g_out_latency => 1
+      )
+      port map (
+        rst          => rst,
+        clk          => clk,
+        -- ST sink
+        snk_out      => dp_latency_adapter_snk_out,
+        snk_in       => dp_latency_adapter_snk_in,
+        -- ST source
+        src_in       => dp_latency_adapter_src_in,
+        src_out      => dp_latency_adapter_src_out
+      );
+
+      dp_latency_adapter_src_in <= src_in;
+      src_out <= dp_latency_adapter_src_out;
+    end generate;
+  end generate;
 
   -- p_reg
   r <= d when rising_edge(clk);
@@ -100,12 +172,12 @@ begin
     v := r;
 
     -- Function
-    --                    _                 _                 _
-    --   snk_in.sop    __| |_______________| |_______________| |_______________|
-    --                                   _                 _                 _
-    --   snk_in.eop    _________________| |_______________| |_______________| |_
-    --                    _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _
-    --   snk_in.valid  __|
+    --                   _                 _                 _
+    --   snk_in.sop   __| |_______________| |_______________| |_______________|
+    --                                  _                 _                 _
+    --   snk_in.eop   _________________| |_______________| |_______________| |_
+    --                   _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _
+    --   snk_in.valid __|
     --   v.val_cnt        0  1  0  1  0  1  0  1  0  1  0  1  0  1  0  1  0  1
     --   v.pkt_cnt        0     1     2     0     1     2     0     1     2
     --                    ______________   _______________   _______________   _
@@ -134,6 +206,11 @@ begin
     end if;
 
     -- output packet bsn, sync, sop and eop
+    -- . Default passes on snk_in.sync, valid, data, re, im
+    -- . The sync, valid can be passed on from snk_in, without checking
+    --   src_in.ready, because the fact that snk_in.valid is '1' is
+    --   sufficient for src_out.valid to be '1' too. The RL is taken care
+    --   of by gen_use_src_in_ready.
     v.src_out         := snk_in;  -- passes on snk_in.sync, data, re, im
     v.src_out.bsn     := r.src_out.bsn;
     v.src_out.channel := r.src_out.channel;
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_packet_merge_unmerge.vhd b/libraries/base/dp/tb/vhdl/tb_dp_packet_merge_unmerge.vhd
index f94f237442..cc2fa6efa0 100644
--- a/libraries/base/dp/tb/vhdl/tb_dp_packet_merge_unmerge.vhd
+++ b/libraries/base/dp/tb/vhdl/tb_dp_packet_merge_unmerge.vhd
@@ -43,20 +43,23 @@ use work.tb_dp_pkg.all;
 entity tb_dp_packet_merge_unmerge is
   generic (
     -- general
-    g_flow_control_stimuli   : t_dp_flow_control_enum := e_active;  -- always active, random or pulse flow control
-    g_flow_control_verify    : t_dp_flow_control_enum := e_active;  -- always active, random or pulse flow control
+    -- . always active, random or pulse flow control
+    g_flow_control_stimuli   : t_dp_flow_control_enum := e_random;
+    g_flow_control_verify    : t_dp_flow_control_enum := e_random;
     -- specific
+    g_use_dp_latency_adapter : boolean := true;
     g_data_w                 : natural := 16;
     g_nof_repeat             : natural := 24;
     g_nof_pkt                : natural := 3;
-    g_pkt_len                : natural := 10;
+    g_pkt_len                : natural := 29;
     g_pkt_gap                : natural := 0;
-    g_bsn_increment          : natural := 1
+    g_bsn_increment          : natural := 0
   );
 end tb_dp_packet_merge_unmerge;
 
 architecture tb of tb_dp_packet_merge_unmerge is
   constant c_rl                       : natural := 1;
+  constant c_use_src_in_ready         : boolean := g_flow_control_verify /= e_active;
 
   constant c_pulse_active             : natural := 1;
   constant c_pulse_period             : natural := 7;
@@ -307,9 +310,11 @@ begin
   ------------------------------------------------------------------------------
   u_dp_packet_unmerge : entity work.dp_packet_unmerge
   generic map (
-    g_nof_pkt_max   => g_nof_pkt,
-    g_pkt_len       => g_pkt_len,
-    g_bsn_increment => g_bsn_increment
+    g_use_src_in_ready       => c_use_src_in_ready,
+    g_use_dp_latency_adapter => g_use_dp_latency_adapter,
+    g_nof_pkt_max            => g_nof_pkt,
+    g_pkt_len                => g_pkt_len,
+    g_bsn_increment          => g_bsn_increment
   )
   port map (
     rst       => rst,
diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge_unmerge.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge_unmerge.vhd
index f0859b884a..76246a0f14 100644
--- a/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge_unmerge.vhd
+++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge_unmerge.vhd
@@ -39,6 +39,7 @@ begin
   --     g_flow_control_stimuli   : t_dp_flow_control_enum := e_active;  -- always active, random or pulse flow control
   --     g_flow_control_verify    : t_dp_flow_control_enum := e_active;  -- always active, random or pulse flow control
   --     -- specific
+  --     g_use_dp_latency_adapter : boolean := true;
   --     g_data_w                 : natural := 4;
   --     g_nof_repeat             : natural := 20;
   --     g_nof_pkt                : natural := 3;
@@ -46,27 +47,24 @@ begin
   --     g_pkt_gap                : natural := 0;
   --     g_bsn_increment          : natural := 0;
 
-  u_act_act_8_nof_0      : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 0, 29, 0, 1);
-  u_act_act_8_nof_1      : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 1, 29, 0, 1);
-  u_act_act_8_nof_2      : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 2, 29, 0, 1);
-  u_act_act_8_nof_3      : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, 1);
-  u_act_act_8_nof_4      : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 4, 29, 0, 1);
-  u_act_act_8_nof_5      : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 5, 29, 0, 1);
-  u_act_act_8_nof_6      : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 6, 29, 0, 1);
-  u_act_act_8_nof_7      : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 7, 29, 0, 1);
+  u_act_act_8_nof_0       : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 0, 29, 0, 1);
+  u_act_act_8_nof_1       : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 1, 29, 0, 1);
+  u_act_act_8_nof_2       : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 2, 29, 0, 1);
+  u_act_act_8_nof_3       : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 3, 29, 0, 1);
+  u_act_act_8_nof_4       : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 4, 29, 0, 1);
+  u_act_act_8_nof_4_bsn_0 : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 4, 29, 0, 0);
+  --u_act_act_8_nof_4_bsn_2 : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 4, 29, 0, 2);
+  u_act_act_8_nof_5       : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 5, 29, 0, 1);
+  u_act_act_8_nof_6       : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 6, 29, 0, 1);
+  u_act_act_8_nof_7       : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active,  true, 8, c_nof_repeat, 7, 29, 0, 1);
 
-  u_rnd_act_8_nof_3      : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_active, 8, c_nof_repeat, 3, 29, 0, 2);
-  u_rnd_rnd_8_nof_3      : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_random, 8, c_nof_repeat, 3, 29, 0, 3);
-  u_pls_act_8_nof_3      : entity work.tb_dp_packet_merge_unmerge generic map ( e_pulse,  e_active, 8, c_nof_repeat, 3, 29, 0, 4);
-  u_pls_rnd_8_nof_3      : entity work.tb_dp_packet_merge_unmerge generic map ( e_pulse,  e_random, 8, c_nof_repeat, 3, 29, 0, 5);
-  u_pls_pls_8_nof_3      : entity work.tb_dp_packet_merge_unmerge generic map ( e_pulse,  e_pulse,  8, c_nof_repeat, 3, 29, 0, 6);
+  u_rnd_act_8_nof_3       : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_active,  true, 8, c_nof_repeat, 3, 29, 0, 1);
+  u_rnd_rnd_8_nof_3_pipe  : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_random, false, 8, c_nof_repeat, 3, 29, 0, 1);
+  u_rnd_rnd_8_nof_3_adapt : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_random,  true, 8, c_nof_repeat, 3, 29, 0, 1);
+  u_pls_act_8_nof_3       : entity work.tb_dp_packet_merge_unmerge generic map ( e_pulse,  e_active,  true, 8, c_nof_repeat, 3, 29, 0, 1);
+  u_pls_rnd_8_nof_3       : entity work.tb_dp_packet_merge_unmerge generic map ( e_pulse,  e_random,  true, 8, c_nof_repeat, 3, 29, 0, 1);
+  u_pls_pls_8_nof_3       : entity work.tb_dp_packet_merge_unmerge generic map ( e_pulse,  e_pulse,   true, 8, c_nof_repeat, 3, 29, 0, 1);
 
-  u_rnd_act_8_nof_1      : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_active, 8, c_nof_repeat, 1, 29,  0, 1);
-  u_rnd_act_8_nof_3_gap  : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_active, 8, c_nof_repeat, 3, 29, 17, 1);
-
-  u_act_act_8_nof_3_no_err : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, 0);
-  u_act_act_8_nof_3_err_10 : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, 1);
-  u_act_act_8_nof_3_err_11 : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, 1);
-  u_act_act_8_nof_3_err_12 : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, 1);
-  u_act_act_8_nof_3_err_13 : entity work.tb_dp_packet_merge_unmerge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, 1);
+  u_rnd_act_8_nof_1       : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_active,  true, 8, c_nof_repeat, 1, 29,  0, 1);
+  u_rnd_act_8_nof_3_gap   : entity work.tb_dp_packet_merge_unmerge generic map ( e_random, e_active,  true, 8, c_nof_repeat, 3, 29, 17, 1);
 end tb;
-- 
GitLab