diff --git a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_beamformer.vhd b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_beamformer.vhd
index 523a0b955f37161dd6a2424b990487cb245f0b60..0a66af3bc3b589b791cdd0e3b246c29854f393cb 100644
--- a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_beamformer.vhd
+++ b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_beamformer.vhd
@@ -267,7 +267,7 @@ BEGIN
 
     in_sosi            => bf_out_sosi,       
     out_sosi           => mon_bf_udp_sosi,       
-    src_in             => bf_udp_siso,       
+    out_siso           => bf_udp_siso,
     
     beamlet_scale      => beamlet_scale,                          
     sdp_info           => sdp_info,       
diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd
index 610fc3db5b45c859d261ee019103f79d7b85c28e..f3f0b5b2b634da7e65917eec9d798850089c5787 100644
--- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd
+++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd
@@ -58,7 +58,7 @@ ENTITY sdp_beamformer_output IS
 
     in_sosi  : IN  t_dp_sosi; 
     out_sosi : OUT t_dp_sosi;
-    src_in   : IN t_dp_siso;
+    out_siso : IN t_dp_siso;
 
     sdp_info      : IN t_sdp_info;
     beamlet_scale : IN STD_LOGIC_VECTOR(c_sdp_W_beamlet_scale-1 DOWNTO 0);
@@ -164,7 +164,8 @@ BEGIN
   -- . Also, we need a fill FIFO here because 16b->64b will introduce gaps in our
   --   TX stream (not allowed by 10G TX MAC).
   -- . The fill fifo waits until c_fifo_fill words are received before enabling the
-  --   output. The total number of words in the fifo is determained by the backpressure.
+  --   output. The total number of words in the fifo is determined by the
+  --   backpressure.
   -------------------------------------------------------------------------------
   u_dp_fifo_fill_sc : ENTITY dp_lib.dp_fifo_fill_sc
   GENERIC MAP (
@@ -373,7 +374,7 @@ BEGIN
     snk_out_arr(0) => dp_pipeline_ready_src_in,  
     snk_in_arr(0)  => dp_pipeline_ready_src_out, 
     -- ST source
-    src_in_arr(0)  => src_in, 
+    src_in_arr(0)  => out_siso,
     src_out_arr(0) => out_sosi
   );
 
diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_station.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_station.vhd
index af106cdfccf8f2f92daaab665100dc543cc4f0f9..deb8fb8b7938855d96c6bbc1bf81dd3d4fe9baa3 100644
--- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_station.vhd
+++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_station.vhd
@@ -369,7 +369,7 @@ ENTITY sdp_station IS
     reg_nw_10GbE_eth10g_cipo   : OUT t_mem_cipo := c_mem_cipo_rst;
 
     ----------------------------------------------
-    -- QSFP for beamlet output and for ring cable
+    -- QSFP[1] quad for beamlet output and QSFP[0] quad for ring cable
     ----------------------------------------------
 
     -- QSFP serial (6 QSFP ports per FPGA)
@@ -444,12 +444,16 @@ ARCHITECTURE str OF sdp_station IS
   CONSTANT c_fifo_tx_size_ring         : NATURAL := true_log_pow2(c_lane_packet_nof_longwords_max + c_fifo_tx_fill_margin);  -- = 552 + 6 --> 1024
   CONSTANT c_fifo_tx_fill_ring         : NATURAL := c_fifo_tx_size_ring - c_fifo_tx_fill_margin;  -- = maximum fill level, so rely on eop
 
-  CONSTANT c_nof_lane                  : NATURAL := 3; -- 0 = XST, 1 = BF_0, 2 = BF_1.
-  CONSTANT c_nof_if                    : NATURAL := 3; -- 3 different interfaces, QSFP, RING_0 and RING_1
-  CONSTANT c_qsfp_if_offset            : NATURAL := 0; -- QSFP signals are indexed at c_nof_if * I.
-  CONSTANT c_ring_0_if_offset          : NATURAL := 1; -- RING_0 signals are indexed at c_nof_if * I + 1. 
-  CONSTANT c_ring_1_if_offset          : NATURAL := 2; -- RING_1 signals are indexed at c_nof_if * I + 2.
-  CONSTANT c_ring_nof_mac              : NATURAL := 12; -- Using 9 out of 12 (this is NOT optimized away during synthesis), must match one of the MAC IP variations, e.g. 1, 3, 4, 12, 24, 48
+  CONSTANT c_nof_even_lanes            : NATURAL := 3; -- 0 = XST, 1 = BF_0, 2 = BF_1.
+  CONSTANT c_lane_nof_if               : NATURAL := 3; -- 3 different 10GbE interfaces per pair of lanes: QSFP cable, RING_0 pcb and RING_1 pcb
+  CONSTANT c_ring_qsfp_if_offset       : NATURAL := 0; -- QSFP cable signals are indexed at c_lane_nof_if * I.
+  CONSTANT c_ring_0_if_offset          : NATURAL := 1; -- RING_0 pcb signals are indexed at c_lane_nof_if * I + 1.
+  CONSTANT c_ring_1_if_offset          : NATURAL := 2; -- RING_1 pcb signals are indexed at c_lane_nof_if * I + 2.
+  CONSTANT c_ring_nof_mac              : NATURAL := c_nof_even_lanes * c_lane_nof_if;
+
+  -- Using c_ring_nof_mac out of 12 (this is NOT optimized away during synthesis), must
+  -- match one of the MAC IP variations, e.g. 1, 3, 4, 12, 24, 48
+  CONSTANT c_ring_nof_mac_ip           : NATURAL := 12;  -- >= c_ring_nof_mac
 
   TYPE t_dp_sosi_2arr_pfb IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(c_sdp_P_pfb - 1 DOWNTO 0);
 
@@ -549,10 +553,10 @@ ARCHITECTURE str OF sdp_station IS
   SIGNAL xst_to_ri_sosi                    : t_dp_sosi := c_dp_sosi_rst;     
   SIGNAL bf_from_ri_sosi_arr               : t_dp_sosi_arr(c_sdp_N_beamsets-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);        
   SIGNAL bf_to_ri_sosi_arr                 : t_dp_sosi_arr(c_sdp_N_beamsets-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);    
-  SIGNAL lane_rx_cable_sosi_arr            : t_dp_sosi_arr(c_nof_lane-1 DOWNTO 0);  
-  SIGNAL lane_tx_cable_sosi_arr            : t_dp_sosi_arr(c_nof_lane-1 DOWNTO 0);        
-  SIGNAL lane_rx_board_sosi_arr            : t_dp_sosi_arr(c_nof_lane-1 DOWNTO 0);        
-  SIGNAL lane_tx_board_sosi_arr            : t_dp_sosi_arr(c_nof_lane-1 DOWNTO 0);        
+  SIGNAL lane_rx_cable_sosi_arr            : t_dp_sosi_arr(c_nof_even_lanes-1 DOWNTO 0);
+  SIGNAL lane_tx_cable_sosi_arr            : t_dp_sosi_arr(c_nof_even_lanes-1 DOWNTO 0);
+  SIGNAL lane_rx_board_sosi_arr            : t_dp_sosi_arr(c_nof_even_lanes-1 DOWNTO 0);
+  SIGNAL lane_tx_board_sosi_arr            : t_dp_sosi_arr(c_nof_even_lanes-1 DOWNTO 0);
  
   SIGNAL dp_bsn_source_restart             : STD_LOGIC;  -- used to restart WPFB sync interval timing
   SIGNAL dp_bsn_source_new_interval        : STD_LOGIC;  -- used to mask out first sync interval for SST and BST offload
@@ -567,13 +571,13 @@ ARCHITECTURE str OF sdp_station IS
   SIGNAL tr_ref_rst_156                    : STD_LOGIC;
 
   -- 10GbE ring
-  SIGNAL tr_10gbe_ring_serial_tx_arr       : STD_LOGIC_VECTOR(c_ring_nof_mac-1 DOWNTO 0) := (OTHERS => '0');
-  SIGNAL tr_10gbe_ring_serial_rx_arr       : STD_LOGIC_VECTOR(c_ring_nof_mac-1 DOWNTO 0) := (OTHERS => '0');
+  SIGNAL tr_10gbe_ring_serial_tx_arr       : STD_LOGIC_VECTOR(c_ring_nof_mac_ip-1 DOWNTO 0) := (OTHERS => '0');
+  SIGNAL tr_10gbe_ring_serial_rx_arr       : STD_LOGIC_VECTOR(c_ring_nof_mac_ip-1 DOWNTO 0) := (OTHERS => '0');
 
-  SIGNAL tr_10gbe_ring_snk_in_arr          : t_dp_sosi_arr(c_ring_nof_mac-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);
-  SIGNAL tr_10gbe_ring_snk_out_arr         : t_dp_siso_arr(c_ring_nof_mac-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy);
-  SIGNAL tr_10gbe_ring_src_out_arr         : t_dp_sosi_arr(c_ring_nof_mac-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);
-  SIGNAL tr_10gbe_ring_src_in_arr          : t_dp_siso_arr(c_ring_nof_mac-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy);
+  SIGNAL tr_10gbe_ring_snk_in_arr          : t_dp_sosi_arr(c_ring_nof_mac_ip-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);
+  SIGNAL tr_10gbe_ring_snk_out_arr         : t_dp_siso_arr(c_ring_nof_mac_ip-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy);
+  SIGNAL tr_10gbe_ring_src_out_arr         : t_dp_sosi_arr(c_ring_nof_mac_ip-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);
+  SIGNAL tr_10gbe_ring_src_in_arr          : t_dp_siso_arr(c_ring_nof_mac_ip-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy);
 
   -- 10GbE beamlet output
   SIGNAL nw_10gbe_beamlet_output_snk_in_arr  : t_dp_sosi_arr(c_nof_10GbE_beamlet_output-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst);
@@ -1160,7 +1164,7 @@ BEGIN
     );
 
     ---------------
-    -- nw_10GbE beamlet output
+    -- nw_10GbE beamlet output via front_io QSFP[1]
     ---------------
     u_nw_10GbE_beamlet_output: ENTITY nw_10GbE_lib.nw_10GbE
     GENERIC MAP (
@@ -1373,31 +1377,32 @@ BEGIN
         miso_arr => reg_dp_block_validate_bsn_at_sync_bf_cipo_arr
       );
     END GENERATE;
+
     -----------------------------------------------------------------------------
     -- Combine seperate signals into array for tr_10GbE
     -----------------------------------------------------------------------------  
-    gen_lane_wires : FOR I IN 0 TO c_nof_lane-1 GENERATE 
+    gen_lane_wires : FOR I IN 0 TO c_nof_even_lanes-1 GENERATE
       -- QSFP_RX, use_cable_to_previous_rn=1 -> even lanes receive from cable
-      lane_rx_cable_sosi_arr(I) <= tr_10gbe_ring_src_out_arr(c_nof_if * I + c_qsfp_if_offset) WHEN ring_info.use_cable_to_previous_rn = '1' ELSE c_dp_sosi_rst;
+      lane_rx_cable_sosi_arr(I) <= tr_10gbe_ring_src_out_arr(c_lane_nof_if * I + c_ring_qsfp_if_offset) WHEN ring_info.use_cable_to_previous_rn = '1' ELSE c_dp_sosi_rst;
 
       -- QSFP_TX, use_cable_to_next_rn=1 -> even lanes transmit to cable
-      tr_10gbe_ring_snk_in_arr(c_nof_if * I + c_qsfp_if_offset) <= lane_tx_cable_sosi_arr(I) WHEN ring_info.use_cable_to_next_rn = '1'      ELSE c_dp_sosi_rst;
+      tr_10gbe_ring_snk_in_arr(c_lane_nof_if * I + c_ring_qsfp_if_offset) <= lane_tx_cable_sosi_arr(I) WHEN ring_info.use_cable_to_next_rn = '1' ELSE c_dp_sosi_rst;
   
       -- RING_0_RX even lanes receive from RING_0 (from the left)
-      lane_rx_board_sosi_arr(I) <= tr_10gbe_ring_src_out_arr(c_nof_if * I + c_ring_0_if_offset);
+      lane_rx_board_sosi_arr(I) <= tr_10gbe_ring_src_out_arr(c_lane_nof_if * I + c_ring_0_if_offset);
   
       -- RING_1_TX even lanes transmit to RING_1 (to the right)
-      tr_10gbe_ring_snk_in_arr(c_nof_if * I + c_ring_1_if_offset) <= lane_tx_board_sosi_arr(I);
+      tr_10gbe_ring_snk_in_arr(c_lane_nof_if * I + c_ring_1_if_offset) <= lane_tx_board_sosi_arr(I);
     END GENERATE;
 
     -----------------------------------------------------------------------------
-    -- tr_10GbE ring
+    -- tr_10GbE ring via front_io QSFP[0]
     -----------------------------------------------------------------------------
     u_tr_10GbE_ring: ENTITY tr_10GbE_lib.tr_10GbE
     GENERIC MAP (
       g_sim           => g_sim,
       g_sim_level     => 1,
-      g_nof_macs      => c_ring_nof_mac,
+      g_nof_macs      => c_ring_nof_mac_ip,
       g_direction     => "TX_RX",
       g_tx_fifo_fill  => c_fifo_tx_fill_ring,
       g_tx_fifo_size  => c_fifo_tx_size_ring
@@ -1437,23 +1442,23 @@ BEGIN
     -----------------------------------------------------------------------------
     -- Seperate serial tx/rx array 
     -----------------------------------------------------------------------------  
-    -- Seperating the one large serial tx/rx array from tr_10GbE to the 3 port arrays:
-    -- QSFP port, RING_0 port and RING_1 port.
-    gen_serial_wires : FOR I IN 0 TO c_nof_lane-1 GENERATE 
+    -- Seperating the one large serial tx/rx array from tr_10GbE to the c_lane_nof_if = 3
+    -- port arrays: QSFP cable port, RING_0 pcb port and RING_1 pcb port.
+    gen_ring_serial_wires : FOR I IN 0 TO c_nof_even_lanes-1 GENERATE
       -- QSFP_TX
-      unb2_board_front_io_serial_tx_arr(I) <= tr_10gbe_ring_serial_tx_arr(c_nof_if * I + c_qsfp_if_offset);
+      unb2_board_front_io_serial_tx_arr(I) <= tr_10gbe_ring_serial_tx_arr(c_lane_nof_if * I + c_ring_qsfp_if_offset);
       -- QSFP_RX
-      tr_10gbe_ring_serial_rx_arr(c_nof_if * I + c_qsfp_if_offset) <= unb2_board_front_io_serial_rx_arr(I);
+      tr_10gbe_ring_serial_rx_arr(c_lane_nof_if * I + c_ring_qsfp_if_offset) <= unb2_board_front_io_serial_rx_arr(I);
     
       -- RING_0_TX 
-      RING_0_TX(I) <= tr_10gbe_ring_serial_tx_arr(c_nof_if * I + c_ring_0_if_offset);
+      RING_0_TX(I) <= tr_10gbe_ring_serial_tx_arr(c_lane_nof_if * I + c_ring_0_if_offset);
       -- RING_0_RX
-      tr_10gbe_ring_serial_rx_arr(c_nof_if * I + c_ring_0_if_offset) <= RING_0_RX(I);
+      tr_10gbe_ring_serial_rx_arr(c_lane_nof_if * I + c_ring_0_if_offset) <= RING_0_RX(I);
     
       -- RING_1_TX
-      RING_1_TX(I) <= tr_10gbe_ring_serial_tx_arr(c_nof_if * I + c_ring_1_if_offset);
+      RING_1_TX(I) <= tr_10gbe_ring_serial_tx_arr(c_lane_nof_if * I + c_ring_1_if_offset);
       -- RING_1_RX
-      tr_10gbe_ring_serial_rx_arr(c_nof_if * I + c_ring_1_if_offset) <= RING_1_RX(I);
+      tr_10gbe_ring_serial_rx_arr(c_lane_nof_if * I + c_ring_1_if_offset) <= RING_1_RX(I);
     END GENERATE;
   END GENERATE;
 
diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg
index 12f9c56edd7f921d5751fab385dcaca33cfa8365..8d500138501b9273d8bad9a735033150efd979c9 100644
--- a/libraries/base/dp/hdllib.cfg
+++ b/libraries/base/dp/hdllib.cfg
@@ -59,6 +59,7 @@ synth_files =
     src/vhdl/dp_fifo_fill.vhd
     src/vhdl/dp_fifo_fill_reg.vhd
     src/vhdl/dp_fifo_fill_eop.vhd
+    src/vhdl/dp_fifo_fill_eop_sc.vhd
     src/vhdl/dp_fifo_to_mm.vhd
     src/vhdl/dp_fifo_to_mm_reg.vhd
     src/vhdl/dp_fifo_from_mm.vhd
@@ -251,6 +252,7 @@ test_bench_files =
     tb/vhdl/tb_dp_fifo_dc_mixed_widths.vhd
     tb/vhdl/tb_dp_fifo_sc.vhd
     tb/vhdl/tb_dp_fifo_to_mm.vhd
+    tb/vhdl/tb_dp_fifo_xonoff.vhd
     tb/vhdl/tb_dp_flush.vhd
     tb/vhdl/tb_dp_gap.vhd
     tb/vhdl/tb_dp_hdr_insert_remove.vhd
@@ -368,6 +370,7 @@ test_bench_files =
 
 regression_test_vhdl = 
     tb/vhdl/tb_dp_fifo_to_mm.vhd
+    tb/vhdl/tb_dp_fifo_xonoff.vhd
     tb/vhdl/tb_dp_latency_adapter.vhd
     tb/vhdl/tb_dp_shiftreg.vhd
     tb/vhdl/tb_dp_bsn_source.vhd
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_core.vhd b/libraries/base/dp/src/vhdl/dp_fifo_core.vhd
index c8f9cb39db358df72a7a0fbd4ab161343a341e54..63085ac767e85f9dc04689ea1038483e9d5e58e1 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_core.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_core.vhd
@@ -66,7 +66,8 @@ ENTITY dp_fifo_core IS
     g_use_ctrl       : BOOLEAN := TRUE;  -- sop & eop
     g_use_complex    : BOOLEAN := FALSE; -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_size      : NATURAL := 512;   -- (16+2) * 512 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1
   );
   PORT (
@@ -96,7 +97,8 @@ ARCHITECTURE str OF dp_fifo_core IS
 
   CONSTANT c_complex_w        : NATURAL := smallest(c_dp_stream_dsp_data_w, g_data_w/2);  -- needed to cope with g_data_w > 2*c_dp_stream_dsp_data_w
    
-  CONSTANT c_fifo_almost_full : NATURAL := g_fifo_size-g_fifo_af_margin;  -- FIFO almost full level for snk_out.ready
+  CONSTANT c_fifo_almost_full : NATURAL := g_fifo_size - g_fifo_af_margin;  -- FIFO almost full level for snk_out.ready
+  CONSTANT c_fifo_almost_xon  : NATURAL := g_fifo_size - g_fifo_af_xon;     -- FIFO almost full level for snk_out.xon
   CONSTANT c_fifo_dat_w       : NATURAL := func_slv_concat_w(c_use_data, g_use_bsn, g_use_empty, g_use_channel, g_use_error, g_use_sync, g_use_ctrl,
                                                              g_data_w,   g_bsn_w,   g_empty_w,   g_channel_w,   g_error_w,   1,          c_ctrl_w);  -- concat via FIFO
   
@@ -163,11 +165,12 @@ BEGIN
                                  wr_sync,
                                  wr_ctrl);
   
-  -- pass on frame level flow control
-  nxt_snk_out.xon <= src_in.xon;
+  -- pass on frame level flow control from src_in.xon to upstream snk_out.xon, and
+  -- add flow contol dependent on whether the fifo can fit another block
+  nxt_snk_out.xon <= src_in.xon WHEN UNSIGNED(fifo_wr_usedw) <= c_fifo_almost_xon ELSE '0';
 
   -- up stream use fifo almost full to control snk_out.ready
-  nxt_snk_out.ready <= NOT wr_init WHEN UNSIGNED(fifo_wr_usedw)<c_fifo_almost_full ELSE '0';    
+  nxt_snk_out.ready <= NOT wr_init WHEN UNSIGNED(fifo_wr_usedw) < c_fifo_almost_full ELSE '0';
     
   gen_common_fifo_sc : IF g_use_dual_clock=FALSE GENERATE
     u_common_fifo_sc : ENTITY common_lib.common_fifo_sc
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_core_arr.vhd b/libraries/base/dp/src/vhdl/dp_fifo_core_arr.vhd
index 83964e22b64cf0a3cdc95ad955082f8752e7d713..d74579e00f221eeaf386a55abde1a43f0ae4629d 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_core_arr.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_core_arr.vhd
@@ -73,7 +73,8 @@ ENTITY dp_fifo_core_arr IS
     g_use_ctrl       : BOOLEAN := TRUE;  -- sop & eop
     g_use_complex    : BOOLEAN := FALSE; -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_size      : NATURAL := 512;   -- (16+2) * 512 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1
   );
   PORT (
@@ -106,7 +107,8 @@ ARCHITECTURE str OF dp_fifo_core_arr IS
 
   CONSTANT c_complex_w        : NATURAL := smallest(c_dp_stream_dsp_data_w, g_data_w/2);  -- needed to cope with g_data_w > 2*c_dp_stream_dsp_data_w
    
-  CONSTANT c_fifo_almost_full : NATURAL := g_fifo_size-g_fifo_af_margin;  -- FIFO almost full level for snk_out.ready
+  CONSTANT c_fifo_almost_full : NATURAL := g_fifo_size - g_fifo_af_margin;  -- FIFO almost full level for snk_out.ready
+  CONSTANT c_fifo_almost_xon  : NATURAL := g_fifo_size - g_fifo_af_xon;     -- FIFO almost full level for snk_out.xon
   CONSTANT c_fifo_dat_w       : NATURAL := func_slv_concat_w(c_use_data,     g_use_bsn, g_use_empty, g_use_channel, g_use_error, g_use_sync, g_use_ctrl, g_use_aux,
                                                              c_total_data_w, g_bsn_w,   g_empty_w,   g_channel_w,   g_error_w,   1,          c_ctrl_w,   g_aux_w);  -- concat via FIFO
   
@@ -185,11 +187,12 @@ BEGIN
                                  wr_ctrl,
                                  wr_aux);
   
-  -- pass on frame level flow control
-  nxt_snk_out.xon <= src_in_arr(0).xon;
+  -- pass on frame level flow control from src_in.xon to upstream snk_out.xon, and
+  -- add flow contol dependent on whether the fifo can fit another block
+  nxt_snk_out.xon <= src_in_arr(0).xon WHEN UNSIGNED(fifo_wr_usedw) <= c_fifo_almost_xon ELSE '0';
 
-  -- up stream use fifo almost full to control snk_out.ready
-  nxt_snk_out.ready <= '1' WHEN UNSIGNED(fifo_wr_usedw)<c_fifo_almost_full ELSE '0';    
+  -- use fifo almost full to control up stream snk_out.ready
+  nxt_snk_out.ready <= '1' WHEN UNSIGNED(fifo_wr_usedw) < c_fifo_almost_full ELSE '0';
     
   gen_common_fifo_sc : IF g_use_dual_clock=FALSE GENERATE
     u_common_fifo_sc : ENTITY common_lib.common_fifo_sc
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_dc.vhd b/libraries/base/dp/src/vhdl/dp_fifo_dc.vhd
index f5638052d7af7f99ebf06a4c0482791d13ac3639..211b97800f7e6bea6b800c3bbef87afe6374e13f 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_dc.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_dc.vhd
@@ -46,7 +46,8 @@ ENTITY dp_fifo_dc IS
     g_use_ctrl       : BOOLEAN := TRUE;  -- sop & eop
     g_use_complex    : BOOLEAN := FALSE; -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_size      : NATURAL := 512;   -- (16+2) * 512 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1
   );
   PORT (
@@ -91,6 +92,7 @@ BEGIN
     g_use_complex    => g_use_complex,
     g_fifo_size      => g_fifo_size,
     g_fifo_af_margin => g_fifo_af_margin,
+    g_fifo_af_xon    => g_fifo_af_xon,
     g_fifo_rl        => g_fifo_rl
   )
   PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_dc_arr.vhd b/libraries/base/dp/src/vhdl/dp_fifo_dc_arr.vhd
index 45d65e14cda439a068b419d049d6bc5db4ae507e..dcfd02e39c891d8211aadc39a74297d9410ac21c 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_dc_arr.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_dc_arr.vhd
@@ -51,7 +51,8 @@ ENTITY dp_fifo_dc_arr IS
     g_use_ctrl       : BOOLEAN := TRUE;  -- sop & eop
     g_use_complex    : BOOLEAN := FALSE; -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_size      : NATURAL := 512;   -- (16+2) * 512 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1
   );
   PORT (
@@ -101,6 +102,7 @@ BEGIN
     g_use_complex    => g_use_complex,
     g_fifo_size      => g_fifo_size,
     g_fifo_af_margin => g_fifo_af_margin,
+    g_fifo_af_xon    => g_fifo_af_xon,
     g_fifo_rl        => g_fifo_rl
   )
   PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_dc_mixed_widths.vhd b/libraries/base/dp/src/vhdl/dp_fifo_dc_mixed_widths.vhd
index 5b809003534f71183cafea90a0795368cd517104..996f267d282d660faa82c1291f34a371b47edf2a 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_dc_mixed_widths.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_dc_mixed_widths.vhd
@@ -114,7 +114,8 @@ ENTITY dp_fifo_dc_mixed_widths IS
     g_rd_data_w         : NATURAL := 9;
     g_use_ctrl          : BOOLEAN := TRUE;
     g_wr_fifo_size      : NATURAL := 512;   -- FIFO size in nof wr_data words
-    g_wr_fifo_af_margin : NATURAL := 4;     --  >=4, Nof words below max (full) at which fifo is considered almost full
+    g_wr_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_wr_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_rd_fifo_rl        : NATURAL := 1
   );
   PORT (
@@ -150,8 +151,9 @@ ARCHITECTURE str OF dp_fifo_dc_mixed_widths IS
   CONSTANT c_ctrl_w              : NATURAL := sel_a_b(g_use_ctrl, 2, 0);  -- sop and eop, or no ctrl
   CONSTANT c_empty_w             : NATURAL := ceil_log2(c_nof_narrow);
   
-  CONSTANT c_fifo_wr_almost_full : NATURAL := g_wr_fifo_size-g_wr_fifo_af_margin;  -- FIFO almost full level for snk_out.ready
-  
+  CONSTANT c_fifo_wr_almost_full : NATURAL := g_wr_fifo_size - g_wr_fifo_af_margin;  -- FIFO almost full level for snk_out.ready
+  CONSTANT c_fifo_wr_almost_xon  : NATURAL := g_wr_fifo_size - g_wr_fifo_af_xon;     -- FIFO almost full level for snk_out.xon
+
   CONSTANT c_fifo_narrow_data_w  : NATURAL := c_narrow_data_w + c_ctrl_w;           -- if used concat control via FIFO
   CONSTANT c_fifo_wide_data_w    : NATURAL := c_nof_narrow * c_fifo_narrow_data_w;  -- all through one FIFO
   
@@ -185,7 +187,8 @@ ARCHITECTURE str OF dp_fifo_dc_mixed_widths IS
   SIGNAL rd_sosi        : t_dp_sosi := c_dp_sosi_rst;  -- initialize default values for unused sosi fields
   
   SIGNAL i_snk_out      : t_dp_siso := c_dp_siso_rst;
-  
+  SIGNAL nxt_snk_out    : t_dp_siso := c_dp_siso_rst;
+
 BEGIN
 
   -- Use i_snk_out with defaults to force unused snk_out bits and fields to '0'
@@ -239,21 +242,24 @@ BEGIN
     wr_ful   <= fifo_wr_ful;
     wr_usedw <= i_wr_usedw;
     
-    nxt_fifo_aful <= '0' WHEN (UNSIGNED(i_wr_usedw)<c_fifo_wr_almost_full) ELSE '1';
-    
+    nxt_fifo_aful <= '0' WHEN (UNSIGNED(i_wr_usedw) < c_fifo_wr_almost_full) ELSE '1';
+
     p_wr_clk: PROCESS(wr_clk, wr_rst)
     BEGIN
       IF wr_rst='1' THEN
-        fifo_aful <= '0';
+        fifo_aful     <= '0';
+        i_snk_out.xon <= '0';
       ELSIF rising_edge(wr_clk) THEN
-        fifo_aful <= nxt_fifo_aful;
+        fifo_aful     <= nxt_fifo_aful;
+        i_snk_out.xon <= nxt_snk_out.xon;
       END IF;
     END PROCESS;
     
     -- Padding is only needed for the narrow write with frame control, in all other cases the padding control defaults to the redundant initialisation values
     
-    -- pass on frame level flow control
-    i_snk_out.xon <= src_in.xon;
+    -- pass on frame level flow control from src_in.xon to upstream snk_out.xon, and
+    -- add flow contol dependent on whether the fifo can fit another block
+    nxt_snk_out.xon <= src_in.xon WHEN UNSIGNED(i_wr_usedw) <= c_fifo_wr_almost_xon ELSE '0';
 
     -- use FIFO almost full and no padding going on to control output ready to up stream
     i_snk_out.ready <= (NOT fifo_aful) AND wr_pad_ready;
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill.vhd
index c77ea4adc285984c028092bb8ce1c843d3350eba..f3e379027b34679f52b21af52e81db2a1b9334dc 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_fill.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_fill.vhd
@@ -48,7 +48,8 @@ ENTITY dp_fifo_fill IS
     g_use_complex    : BOOLEAN := FALSE;  -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_fill      : NATURAL := 0;
     g_fifo_size      : NATURAL := 256;    -- (32+2) * 256 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;      -- Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;      -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;      -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1       -- use RL=0 for internal show ahead FIFO, default use RL=1 for internal normal FIFO
   );
   PORT (
@@ -95,6 +96,7 @@ BEGIN
     g_fifo_fill      => g_fifo_fill,
     g_fifo_size      => g_fifo_size,
     g_fifo_af_margin => g_fifo_af_margin,
+    g_fifo_af_xon    => g_fifo_af_xon,
     g_fifo_rl        => g_fifo_rl
   )
   PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_core.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_core.vhd
index ef89bbe4222771651c94497ecb019d0dd2280efb..cf1157ef538a3629b752ae022ae492e0c710bf72 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_fill_core.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_core.vhd
@@ -81,7 +81,8 @@ ENTITY dp_fifo_fill_core IS
     g_use_complex    : BOOLEAN := FALSE;  -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_fill      : NATURAL := 0;
     g_fifo_size      : NATURAL := 256;    -- (32+2) * 256 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;      -- Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1       -- use RL=0 for internal show ahead FIFO, default use RL=1 for internal normal FIFO
   );
   PORT (
@@ -176,6 +177,7 @@ BEGIN
       g_use_complex    => g_use_complex,
       g_fifo_size      => c_fifo_size,
       g_fifo_af_margin => g_fifo_af_margin,
+      g_fifo_af_xon    => g_fifo_af_xon,
       g_fifo_rl        => c_fifo_rl
     )
     PORT MAP (
@@ -215,6 +217,7 @@ BEGIN
       --g_use_complex    => g_use_complex,
       g_fifo_size      => c_fifo_size,
       g_fifo_af_margin => g_fifo_af_margin,
+      g_fifo_af_xon    => g_fifo_af_xon,
       g_fifo_rl        => c_fifo_rl
     )
     PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd
index 9d904f89e2cf577428a406bc5ee0fb2b1530b9f6..709af7d621a57d40fea76c96079df3820cb80717 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd
@@ -76,7 +76,8 @@ ENTITY dp_fifo_fill_eop IS
     g_use_complex    : BOOLEAN := FALSE;  -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_fill      : NATURAL := 0;
     g_fifo_size      : NATURAL := 256;    -- (32+2) * 256 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;      -- Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1       -- use RL=0 for internal show ahead FIFO, default use RL=1 for internal normal FIFO
   );
   PORT (
@@ -185,6 +186,7 @@ BEGIN
     g_use_complex    => g_use_complex,
     g_fifo_size      => c_fifo_size,
     g_fifo_af_margin => g_fifo_af_margin,
+    g_fifo_af_xon    => g_fifo_af_xon,
     g_fifo_rl        => c_fifo_rl
   )
   PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop_sc.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop_sc.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..90d16481a7bfa060cc27912b8a6628f4f1e115f3
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop_sc.vhd
@@ -0,0 +1,124 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2020
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+-- 
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+-- 
+--     http://www.apache.org/licenses/LICENSE-2.0
+-- 
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- Author: R. van der Walle, E. Kooistra
+-- Purpose: Single clk wrapper for dp_fifo_fill_eop.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib, technology_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+USE technology_lib.technology_select_pkg.ALL;
+
+ENTITY dp_fifo_fill_eop_sc IS
+  GENERIC (
+    g_technology     : NATURAL := c_tech_select_default;
+    g_note_is_ful    : BOOLEAN := TRUE;
+    g_data_w         : NATURAL := 16; -- Should be 2 times the c_complex_w if g_use_complex = TRUE
+    g_data_signed    : BOOLEAN := FALSE; -- TRUE extends g_data_w bits with the sign bit, FALSE pads g_data_w bits with zeros.
+    g_bsn_w          : NATURAL := 1;
+    g_empty_w        : NATURAL := 1;
+    g_channel_w      : NATURAL := 1;
+    g_error_w        : NATURAL := 1;
+    g_use_bsn        : BOOLEAN := FALSE;
+    g_use_empty      : BOOLEAN := FALSE;
+    g_use_channel    : BOOLEAN := FALSE;
+    g_use_error      : BOOLEAN := FALSE;
+    g_use_sync       : BOOLEAN := FALSE;
+    g_use_complex    : BOOLEAN := FALSE;  -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
+    g_fifo_fill      : NATURAL := 0;
+    g_fifo_size      : NATURAL := 256;    -- (32+2) * 256 = 1 M9K, g_data_w+2 for sop and eop
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
+    g_fifo_rl        : NATURAL := 1       -- use RL=0 for internal show ahead FIFO, default use RL=1 for internal normal FIFO
+  );
+  PORT (
+    rst          : IN  STD_LOGIC;
+    clk          : IN  STD_LOGIC;
+    -- Monitor FIFO filling
+    wr_ful       : OUT STD_LOGIC;  -- corresponds to the carry bit of wr_usedw when FIFO is full
+    usedw        : OUT STD_LOGIC_VECTOR(ceil_log2(largest(g_fifo_size, g_fifo_fill + g_fifo_af_margin + 2))-1 DOWNTO 0);  -- = ceil_log2(c_fifo_size)-1 DOWNTO 0
+    rd_emp       : OUT STD_LOGIC;
+    -- MM control FIFO filling (assume 32 bit MM interface)
+    wr_usedw_32b : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- = wr_usedw
+    rd_usedw_32b : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- = rd_usedw
+    rd_fill_32b  : IN  STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := TO_UVEC(g_fifo_fill, c_word_w);
+    -- ST sink
+    snk_out      : OUT t_dp_siso;
+    snk_in       : IN  t_dp_sosi;
+    -- ST source
+    src_in       : IN  t_dp_siso := c_dp_siso_rdy;
+    src_out      : OUT t_dp_sosi
+  );
+END dp_fifo_fill_eop_sc;
+
+ARCHITECTURE wrap OF dp_fifo_fill_eop_sc IS
+BEGIN
+
+  u_dp_fifo_fill_eop : ENTITY work.dp_fifo_fill_eop
+  GENERIC MAP (
+    g_technology     => g_technology,
+    g_note_is_ful    => g_note_is_ful,
+    g_use_dual_clock => FALSE,  -- single clock
+    g_data_w         => g_data_w,
+    g_data_signed    => g_data_signed,
+    g_bsn_w          => g_bsn_w,
+    g_empty_w        => g_empty_w,
+    g_channel_w      => g_channel_w,
+    g_error_w        => g_error_w,
+    g_use_bsn        => g_use_bsn,
+    g_use_empty      => g_use_empty,
+    g_use_channel    => g_use_channel,
+    g_use_error      => g_use_error,
+    g_use_sync       => g_use_sync,
+    g_use_complex    => g_use_complex,
+    g_fifo_fill      => g_fifo_fill,
+    g_fifo_size      => g_fifo_size,
+    g_fifo_af_margin => g_fifo_af_margin,
+    g_fifo_af_xon    => g_fifo_af_xon,
+    g_fifo_rl        => g_fifo_rl
+  )
+  PORT MAP (
+    wr_rst      => rst,
+    wr_clk      => clk,
+    rd_rst      => rst,
+    rd_clk      => clk,
+    -- Monitor FIFO filling
+    wr_ful      => wr_ful,
+    wr_usedw    => OPEN,
+    rd_usedw    => usedw,  -- use rd_usedw, similar as in dp_fifo_sc, dp_fifo_fill_sc
+    rd_emp      => rd_emp,
+    -- MM control FIFO filling (assume 32 bit MM interface)
+    wr_usedw_32b => wr_usedw_32b,
+    rd_usedw_32b => rd_usedw_32b,
+    rd_fill_32b  => rd_fill_32b,
+    -- ST sink
+    snk_out      => snk_out,
+    snk_in       => snk_in,
+    -- ST source
+    src_in       => src_in,
+    src_out      => src_out
+  );
+
+END wrap;
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_sc.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_sc.vhd
index db85d766fdeb1160ec49358fa622ac9e23bb66c8..dd7fa79f5910ad055dfbc994559513489ccda944 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_fill_sc.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_sc.vhd
@@ -47,7 +47,8 @@ ENTITY dp_fifo_fill_sc IS
     g_use_complex    : BOOLEAN := FALSE;  -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_fill      : NATURAL := 0;
     g_fifo_size      : NATURAL := 256;    -- (32+2) * 256 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;      -- Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1       -- use RL=0 for internal show ahead FIFO, default use RL=1 for internal normal FIFO
   );
   PORT (
@@ -96,6 +97,7 @@ BEGIN
     g_fifo_fill      => g_fifo_fill,
     g_fifo_size      => g_fifo_size,
     g_fifo_af_margin => g_fifo_af_margin,
+    g_fifo_af_xon    => g_fifo_af_xon,
     g_fifo_rl        => g_fifo_rl       
   )
   PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_fifo_sc.vhd b/libraries/base/dp/src/vhdl/dp_fifo_sc.vhd
index fb9570775d09d98e39f905748c21ad9ea61c5feb..3f261029443d6ad6de693bd149033c1fcf749052 100644
--- a/libraries/base/dp/src/vhdl/dp_fifo_sc.vhd
+++ b/libraries/base/dp/src/vhdl/dp_fifo_sc.vhd
@@ -48,7 +48,8 @@ ENTITY dp_fifo_sc IS
     g_use_ctrl       : BOOLEAN := TRUE;  -- sop & eop
     g_use_complex    : BOOLEAN := FALSE; -- TRUE feeds the concatenated complex fields (im & re) through the FIFO instead of the data field.
     g_fifo_size      : NATURAL := 512;   -- (16+2) * 512 = 1 M9K, g_data_w+2 for sop and eop
-    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin : NATURAL := 4;     -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon    : NATURAL := 0;     -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_rl        : NATURAL := 1
   );
   PORT (
@@ -92,6 +93,7 @@ BEGIN
     g_use_complex    => g_use_complex,
     g_fifo_size      => g_fifo_size,
     g_fifo_af_margin => g_fifo_af_margin,
+    g_fifo_af_xon    => g_fifo_af_xon,
     g_fifo_rl        => g_fifo_rl
   )
   PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_mux.vhd b/libraries/base/dp/src/vhdl/dp_mux.vhd
index 56e06ffb4f682760bedad923f5d4bbb8c5ba2490..4326157fa81910389a417ff5fea880ad9f1f43d5 100644
--- a/libraries/base/dp/src/vhdl/dp_mux.vhd
+++ b/libraries/base/dp/src/vhdl/dp_mux.vhd
@@ -105,7 +105,8 @@ ENTITY dp_mux IS
     g_use_in_channel    : BOOLEAN := FALSE;
     g_use_error         : BOOLEAN := FALSE;
     g_use_sync          : BOOLEAN := FALSE;
-    g_fifo_af_margin    : NATURAL := 4;  -- Nof words below max (full) at which fifo is considered almost full
+    g_fifo_af_margin    : NATURAL := 4;  -- >=4, Nof words below max (full) at which fifo is considered almost full for snk_out.ready
+    g_fifo_af_xon       : NATURAL := 0;  -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_size         : t_natural_arr := array_init(1024, 2);  -- must match g_nof_input, even when g_use_fifo=FALSE
     g_fifo_fill         : t_natural_arr := array_init(   0, 2)   -- must match g_nof_input, even when g_use_fifo=FALSE
   ); 
@@ -229,6 +230,7 @@ BEGIN
         g_fifo_fill      => c_fifo_fill(I),
         g_fifo_size      => c_fifo_size(I),
         g_fifo_af_margin => g_fifo_af_margin,
+        g_fifo_af_xon    => g_fifo_af_xon,
         g_fifo_rl        => 1
       )
       PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_xonoff.vhd b/libraries/base/dp/src/vhdl/dp_xonoff.vhd
index 9f7f9eccfdc6897f89b926d84bb6730526042d41..cfdcf122f6c0eabb05a8242cc765a47bfa046645 100644
--- a/libraries/base/dp/src/vhdl/dp_xonoff.vhd
+++ b/libraries/base/dp/src/vhdl/dp_xonoff.vhd
@@ -21,11 +21,58 @@
 
 -- Purpose: Add flow XON-XOFF control by flushing frames
 -- Description:
--- . The in_siso.ready = out_siso.ready so passed on unchanged, to support
+--   The siso.xon signal provides flow control per block of data, so at
+--   sop/eop boundaries. A source that listens to siso.xon can stop streaming
+--   blocks when siso.xon = '0' and resume streaming blocks when siso.xon =
+--   '1'. The siso.ready signal provides flow control per clock cycle. Hence
+--   the siso.ready can also cause a source to stop streaming.
+--
+--   If a source keeps on streaming blocks of data, becaue it does not listen
+--   to siso.xon and also not to siso.ready, then the dp_xonoff can be applied
+--   to drop the blocks when siso.xon = '0'. The purpose of dp_xonoff.vhd is
+--   then to avoid downstream overflow, when the downstream signals
+--   out_siso.xon = '0' to indicate that it cannot accept more blocks.
+--   Therefore the dp_xonoff listens to the out_siso.xon and flushes
+--   (discards) blocks when out_siso.xon = '0' and resumes letting blocks
+--   through when siso.xon = '1' again.
+--
+--   The dp_xonoff operates per block, so it takes care that complete blocks
+--   are flushed when out_siso.xon = '0', or passed on when out_siso.xon =
+--   '1'. Discarding blocks is acceptable to avoid overflow. Discarding data
+--   in a block is not acceptable, because that would corrupt the block
+--   format (e.g. its length, or cause missing sop or eop). Therefore the
+--   dp_xonoff uses siso.xon and does not listen to siso.ready.
+--
+--   The dp_xonoff in_siso.xon = '1' always, because the dp_xonoff will
+--   discard incoming blocks if they cannot be passed on. When out_siso.xon
+--   = '1', then in_siso.ready <= in_sosi.ready, so passed on. When
+--   out_siso.xon = '0', then in_siso.xon = '1' and in_siso.ready <= '1'
+--   (so in_siso = c_dp_sosi.rdy), because dp_xonoff can flush incoming
+--   blocks at maximum rate, until out_siso.xon = '1' again.
+--
+--   A dp_fifo will keep on outputing blocks when its out_siso.xon = '0',
+--   because it only passes in_siso.xon <= out_siso.xon, so it relies on its
+--   upsteam input to listen to the out_siso.xon. If there are still multiple
+--   blocks in the FIFO then these will be output. Typicaaly it is not
+--   necessary to have a dp_xonoff at the output of the dp_fifo to discard
+--   these blocks, because the dp_fifo does listen to out_siso.ready = '0',
+--   so the flow control per sample will then stop the dp_fifo from causing
+--   downstream overflow.
+--
+--   When a dp_fifo runs almost full within g_fifo_af_margin, then the
+--   in_siso.ready is made '0'. New addition is g_fifo_af_xon that defines a
+--   dp_fifo fill margin for making in_sosi.xon = '0'. If the upstream does
+--   not listen to ready flow control and xon flow control (e.g. like input
+--   from an ADC or a WG), then there may be need for an dp_xonoff at the
+--   input of the FIFO to discard input blocks.
+--
+--   The in_siso.ready = out_siso.ready so passed on unchanged, to support
 --   detailed output to input flow control per cycle. The in_siso.xon is
 --   always '1', because the out_siso.xon is taken care of in this
 --   dp_xonoff.vhd by flushing any in_sosi data when out_siso.xon = '0'.
 --
+-- . Use tb_dp_fifo_xonoff.vhd to verify dp_xonoff to avoid dp_fifo overflow.
+--
 -- . When g_bypass=TRUE then the in and out are wired and the component is void.
 -- . When g_bypass=FALSE then:
 --     The output is ON when flush='0'.
@@ -61,6 +108,7 @@ ENTITY dp_xonoff IS
     -- Frame out
     out_siso      : IN  t_dp_siso;  -- flush control via out_siso.xon
     out_sosi      : OUT t_dp_sosi;
+    out_en        : OUT STD_LOGIC;  -- for monitoring purposes in tb
     -- Optional override to force XOFF ('1' = enable override)
     force_xoff    : IN  STD_LOGIC := '0'
   );
@@ -75,18 +123,20 @@ ARCHITECTURE rtl OF dp_xonoff IS
   SIGNAL flush      : STD_LOGIC;
   SIGNAL nxt_flush  : STD_LOGIC;
   
-  SIGNAL out_en     : STD_LOGIC;
+  SIGNAL i_out_en   : STD_LOGIC;
   SIGNAL nxt_out_en : STD_LOGIC;
   
 BEGIN
 
+  out_en <= i_out_en;
+
   gen_bypass : IF g_bypass=TRUE GENERATE
     in_siso  <= out_siso;
     out_sosi <= in_sosi;
   END GENERATE;
   
   no_bypass : IF g_bypass=FALSE GENERATE
-    in_siso.ready <= out_siso.ready OR (NOT out_en);  -- pass on ready for detailed flow control per cycle only when output is enabled, otherwise ready = 1
+    in_siso.ready <= out_siso.ready OR (NOT i_out_en);  -- pass on ready for detailed flow control per cycle only when output is enabled, otherwise ready = 1
     in_siso.xon <= '1';               -- upstream can remain on, because flush will handle out_siso.xon
     nxt_flush <= NOT out_siso.xon OR force_xoff; -- use xon for flow control at frame level
   
@@ -95,11 +145,11 @@ BEGIN
       IF rst='1' THEN
         frm_busy_reg <= '0';
         flush        <= '0';
-        out_en       <= '1';
+        i_out_en     <= '1';
       ELSIF rising_edge(clk) THEN
         frm_busy_reg <= frm_busy;
         flush        <= nxt_flush;     -- pipeline register flush to ease timing closure
-        out_en       <= nxt_out_en;    -- state register out_en because it can only change between frames
+        i_out_en     <= nxt_out_en;    -- state register out_en because it can only change between frames
       END IF;
     END PROCESS;
 
@@ -114,9 +164,9 @@ BEGIN
       END IF;
     END PROCESS;
 
-    p_out_en : PROCESS(flush, out_en, frm_busy)
+    p_out_en : PROCESS(flush, i_out_en, frm_busy)
     BEGIN
-      nxt_out_en <= out_en;
+      nxt_out_en <= i_out_en;
       IF frm_busy='0' THEN
         IF flush='1' THEN
           nxt_out_en <= '0';
@@ -126,16 +176,16 @@ BEGIN
       END IF;    
     END PROCESS;
     
-    p_out_sosi : PROCESS(in_sosi, out_en)
+    p_out_sosi : PROCESS(in_sosi, i_out_en)
     BEGIN
       -- Pass on sosi data via wires
       out_sosi       <= in_sosi;
       
       -- XON/XOFF flow control via sosi control
-      out_sosi.sync  <= in_sosi.sync  AND out_en;
-      out_sosi.valid <= in_sosi.valid AND out_en;
-      out_sosi.sop   <= in_sosi.sop   AND out_en;
-      out_sosi.eop   <= in_sosi.eop   AND out_en;
+      out_sosi.sync  <= in_sosi.sync  AND i_out_en;
+      out_sosi.valid <= in_sosi.valid AND i_out_en;
+      out_sosi.sop   <= in_sosi.sop   AND i_out_en;
+      out_sosi.eop   <= in_sosi.eop   AND i_out_en;
     END PROCESS;
   END GENERATE;
   
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_fifo_xonoff.vhd b/libraries/base/dp/tb/vhdl/tb_dp_fifo_xonoff.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..7188c3417fcb214de2b283319bbcc4f23c8c2f84
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_dp_fifo_xonoff.vhd
@@ -0,0 +1,319 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-- Author: Eric Kooistra
+-- Date: 26 Apr 2023
+-- Purpose:
+-- . Test bench for dp_fifos to verify xon flow control when FIFO runs full.
+--   The dp_xonoff will discard blocks when its out_siso.xon = '0', to avoid
+--   downstream overflow. The dp_xonoff needs to be applied when the updstream
+--   source does not listen to flow control by siso.ready or by sisi.xon.
+-- Description:
+--   Verify that the dp_mux will not cause input FIFO overflow when the input
+--   load is too large for the output capacity.
+--
+--             g_use_in_xonoff                g_use_out_xonoff
+--   proc          |                              |
+--   dp_gen --> xonoff --> fifo_sc --> mux --> xonoff --> fifo <-- out_siso
+--   frame   |          |  arr      |       |          |  fill
+--           |          |           |       |          |  sc
+--           |          |           |       |          |
+--       bg_sosi_arr    |           |       |          |
+--             fifo_in_sosi_arr     |   mux_out_sosi   |
+--             fifo_in_siso_arr     |   mux_in_siso    |
+--                            mux_in_sosi_arr      fifo_fill_in_sosi
+--                            mux_in_siso_arr      fifo_fill_in_siso
+--
+--   Tb stimuli:
+--   . Enable input in_en after reset for 4*c_tb_nof_clk_cycles and disable it
+--     before tb_end, to read FIFOs empty in c_tb_nof_clk_cycles until tb_end.
+--   . Make external siso.xon = '0' for c_tb_nof_clk_cycles, to check xon flow
+--     control.
+--                    ______________________________________
+--   in_en        ___|                                      |_________
+--                _____________________            ___________________
+--   out_siso.xon                      |__________|
+--
+--   tb_end       ___________________________________________________|
+--
+-- Remark:
+-- . If g_gap_size is too small to fit g_nof_inputs on a multiplexed output,
+--   then g_use_in_xonoff needs to be TRUE to avoid u_in_fifo overflow.
+-- . It appears that the dp_xonoff at the mux output is not needed
+--   (g_use_out_xonoff = FALSE), because siso.ready or siso.xon at dp_xonoff
+--   of BG outputs can provide sufficient flow control to avoid u_out_fifo
+--   overflow.
+-- Usage:
+-- . as 12
+-- . run -all
+-- Observe in Wave Window:
+-- . near BG inputs:
+--   - fifo_in_siso_arr
+--   - dp_out_en_arr, to view dp_xonoff flushing
+--   - in_fifo_usedw_arr in analogue format
+-- . at MUX output:
+--   - fifo_fill_in_siso
+--   - dp_out_en, to view dp_xonoff flushing
+--   - out_fifo_usedw in analogue format
+-- Self test result is OK when there is no FAILURE due to FIFO overflow.
+
+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_str_pkg.ALL;
+USE common_lib.common_lfsr_sequences_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+USE work.tb_dp_pkg.ALL;
+
+ENTITY tb_dp_fifo_xonoff IS
+  GENERIC (
+    g_nof_inputs     : NATURAL := 2;
+    g_nof_blocks     : NATURAL := 500;
+    g_block_size     : NATURAL := 10;
+    g_gap_size       : NATURAL := 0;
+    g_use_in_xonoff  : BOOLEAN := TRUE;
+    g_use_out_xonoff : BOOLEAN := FALSE
+  );
+END tb_dp_fifo_xonoff;
+
+
+ARCHITECTURE tb OF tb_dp_fifo_xonoff IS
+
+  CONSTANT c_clk_period         : TIME := 5 ns;
+
+  CONSTANT c_tb_nof_clk_cycles  : NATURAL := g_nof_blocks * g_block_size;
+
+  -- Use extrnal FIFO for per input of dp_mux
+  -- c_fifo_af_ready >= 4, nof words below max (full) at which fifo is considered almost full for snk_out.ready
+  -- c_fifo_af_xon   >= 0, nof words below max (full) at which fifo is considered almost full for snk_out.xon
+  CONSTANT c_fifo_af_ready      : NATURAL := 4;
+  CONSTANT c_fifo_af_xon        : NATURAL := g_block_size + 50;
+
+  CONSTANT c_in_fifo_size       : NATURAL := g_block_size * 20;
+
+  CONSTANT c_out_fifo_size      : NATURAL := g_block_size * 20;
+  CONSTANT c_out_fifo_fill      : NATURAL := g_block_size;
+
+  CONSTANT c_ready_latency      : NATURAL := 1;
+  CONSTANT c_data_w             : NATURAL := 16;
+  CONSTANT c_symbol_w           : NATURAL := c_data_w;
+  CONSTANT c_symbol_init        : NATURAL := 0;
+  CONSTANT c_nof_symbols        : NATURAL := g_block_size;
+  CONSTANT c_bsn                : NATURAL := 0;
+  CONSTANT c_sync               : STD_LOGIC := '0';
+
+  CONSTANT c_nof_input_w        : NATURAL := ceil_log2(g_nof_inputs);
+
+  SIGNAL clk               : STD_LOGIC := '1';
+  SIGNAL rst               : STD_LOGIC := '1';
+  SIGNAL in_en             : STD_LOGIC := '0';
+  SIGNAL tb_end            : STD_LOGIC := '0';
+  
+  SIGNAL bg_siso           : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL bg_sosi_arr       : t_dp_sosi_arr(0 TO g_nof_inputs-1);
+  SIGNAL dp_out_en_arr     : STD_LOGIC_VECTOR(0 TO g_nof_inputs-1);
+  SIGNAL fifo_in_siso_arr  : t_dp_siso_arr(0 TO g_nof_inputs-1);
+  SIGNAL fifo_in_sosi_arr  : t_dp_sosi_arr(0 TO g_nof_inputs-1);
+  SIGNAL mux_in_siso_arr   : t_dp_siso_arr(0 TO g_nof_inputs-1);
+  SIGNAL mux_in_sosi_arr   : t_dp_sosi_arr(0 TO g_nof_inputs-1);
+
+  SIGNAL mux_out_siso      : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL mux_out_sosi      : t_dp_sosi;
+  SIGNAL dp_out_en         : STD_LOGIC;
+  SIGNAL fifo_fill_in_siso : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL fifo_fill_in_sosi : t_dp_sosi;
+  SIGNAL out_siso          : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL out_sosi          : t_dp_sosi;
+
+  -- Monitor FIFO filling
+  TYPE t_in_fifo_usedw_slv_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(ceil_log2(c_out_fifo_size)-1 DOWNTO 0);
+
+  SIGNAL in_fifo_wr_ful_arr  : STD_LOGIC_VECTOR(0 TO g_nof_inputs-1);
+  SIGNAL in_fifo_usedw_arr   : t_in_fifo_usedw_slv_arr(0 TO g_nof_inputs-1);
+  SIGNAL in_fifo_rd_emp_arr  : STD_LOGIC_VECTOR(0 TO g_nof_inputs-1);
+  SIGNAL out_fifo_wr_ful     : STD_LOGIC;
+  SIGNAL out_fifo_usedw      : STD_LOGIC_VECTOR(ceil_log2(c_out_fifo_size)-1 DOWNTO 0);
+  SIGNAL out_fifo_rd_emp     : STD_LOGIC;
+
+BEGIN
+  
+  ------------------------------------------------------------------------------
+  -- Clock & reset
+  ------------------------------------------------------------------------------
+  clk <= (NOT clk) OR tb_end AFTER c_clk_period/2;
+  rst <= '1', '0' AFTER c_clk_period*7;
+
+  ------------------------------------------------------------------------------
+  -- Stimuli: 
+  ------------------------------------------------------------------------------
+  gen_bg_arr : FOR I IN 0 TO g_nof_inputs-1 GENERATE
+    p_bg_arr : PROCESS
+    BEGIN
+      WHILE TRUE LOOP
+        proc_dp_gen_frame(c_ready_latency,
+                          c_data_w,
+                          c_symbol_w,
+                          c_symbol_init,
+                          c_nof_symbols,
+                          c_bsn + I,  -- use bsn to identify the inputs
+                          c_sync,
+                          clk,
+                          in_en,
+                          bg_siso,
+                          bg_sosi_arr(I));
+        WAIT FOR g_gap_size * c_clk_period;
+      END LOOP;
+      -- Use WHILE LOOP and WAIT to avoid warning (vcom-1090) Possible infinite loop:
+      -- Process contains no WAIT statement.
+      WAIT;
+    END PROCESS;
+
+    gen_dp_xonoff : IF g_use_in_xonoff GENERATE
+      u_dp_xonoff : ENTITY work.dp_xonoff
+      PORT MAP (
+        rst         => rst,
+        clk         => clk,
+        -- Frame in
+        in_siso     => OPEN,
+        in_sosi     => bg_sosi_arr(I),
+        -- Frame out
+        out_siso    => fifo_in_siso_arr(I),
+        out_sosi    => fifo_in_sosi_arr(I),
+        out_en      => dp_out_en_arr(I)
+      );
+    END GENERATE;
+    no_dp_xonoff : IF NOT g_use_in_xonoff GENERATE
+      fifo_in_sosi_arr <= bg_sosi_arr;
+      dp_out_en_arr <= (OTHERS => '1');
+    END GENERATE;
+
+    u_in_fifo : ENTITY work.dp_fifo_sc
+    GENERIC MAP (
+      g_data_w         => c_data_w,
+      g_bsn_w          => c_nof_input_w,
+      g_use_bsn        => TRUE,  -- use bsn to identify the inputs
+      g_use_ctrl       => TRUE,  -- sop & eop
+      g_fifo_size      => c_in_fifo_size,
+      g_fifo_af_margin => c_fifo_af_ready,
+      g_fifo_af_xon    => c_fifo_af_xon,
+      g_fifo_rl        => c_ready_latency
+    )
+    PORT MAP (
+      rst         => rst,
+      clk         => clk,
+      -- Monitor FIFO filling
+      wr_ful      => in_fifo_wr_ful_arr(I),
+      usedw       => in_fifo_usedw_arr(I),
+      rd_emp      => in_fifo_rd_emp_arr(I),
+      -- ST sink
+      snk_out     => fifo_in_siso_arr(I),  -- flush control via out_siso.xon
+      snk_in      => fifo_in_sosi_arr(I),
+      -- ST source
+      src_in      => mux_in_siso_arr(I),
+      src_out     => mux_in_sosi_arr(I)
+    );
+  END GENERATE;
+
+  -- Enable input after reset and disable it before tb_end, to read FIFOs empty
+  in_en <= '0', '1' AFTER c_clk_period*17,
+                '0' AFTER 4 * c_tb_nof_clk_cycles * c_clk_period;
+
+  -- Also verify toggling external siso.xon flow control
+  out_siso.xon <= '1',
+                  '0' AFTER 2 * c_tb_nof_clk_cycles * c_clk_period,
+                  '1' AFTER 3 * c_tb_nof_clk_cycles * c_clk_period;
+
+  -- End test
+  tb_end <= '0', '1' AFTER 5 * c_tb_nof_clk_cycles * c_clk_period;
+
+  ------------------------------------------------------------------------------
+  -- Multiplexer
+  ------------------------------------------------------------------------------
+  u_dp_mux : ENTITY work.dp_mux
+  GENERIC MAP (
+    g_nof_input   => g_nof_inputs,
+    g_fifo_size   => array_init(1024, g_nof_inputs),  -- must match g_nof_input, even when g_use_fifo=FALSE
+    g_fifo_fill   => array_init(   0, g_nof_inputs)   -- must match g_nof_input, even when g_use_fifo=FALSE
+  )
+  PORT MAP (
+    rst         => rst,
+    clk         => clk,
+    -- ST sinks
+    snk_out_arr => mux_in_siso_arr,
+    snk_in_arr  => mux_in_sosi_arr,
+    -- ST source
+    src_in      => mux_out_siso,
+    src_out     => mux_out_sosi
+  );
+
+  ------------------------------------------------------------------------------
+  -- Output
+  ------------------------------------------------------------------------------
+
+  gen_dp_xonoff : IF g_use_out_xonoff GENERATE
+    u_dp_xonoff : ENTITY work.dp_xonoff
+    PORT MAP (
+      rst         => rst,
+      clk         => clk,
+      -- Frame in
+      in_siso     => mux_out_siso,
+      in_sosi     => mux_out_sosi,
+      -- Frame out
+      out_siso    => fifo_fill_in_siso,
+      out_sosi    => fifo_fill_in_sosi,
+      out_en      => dp_out_en
+    );
+  END GENERATE;
+  no_dp_xonoff : IF NOT g_use_out_xonoff GENERATE
+    fifo_fill_in_sosi <= mux_out_sosi;
+    mux_out_siso <= fifo_fill_in_siso;
+    dp_out_en <= '1';
+  END GENERATE;
+
+  u_out_fifo : ENTITY work.dp_fifo_fill_sc
+  --u_out_fifo : ENTITY work.dp_fifo_fill_eop_sc
+  GENERIC MAP (
+    g_data_w         => c_data_w,
+    g_bsn_w          => c_nof_input_w,
+    g_use_bsn        => TRUE,  -- use bsn to identify the inputs
+    g_fifo_fill      => c_out_fifo_fill,
+    g_fifo_size      => c_out_fifo_size,
+    g_fifo_af_margin => c_fifo_af_ready,
+    g_fifo_af_xon    => c_fifo_af_xon,
+    g_fifo_rl        => c_ready_latency
+  )
+  PORT MAP (
+    rst         => rst,
+    clk         => clk,
+    -- Monitor FIFO filling
+    wr_ful      => out_fifo_wr_ful,
+    usedw       => out_fifo_usedw,
+    rd_emp      => out_fifo_rd_emp,
+    -- ST sink
+    snk_out     => fifo_fill_in_siso,
+    snk_in      => fifo_fill_in_sosi,
+    -- ST source
+    src_in      => out_siso,
+    src_out     => out_sosi
+  );
+
+END tb;
diff --git a/libraries/base/ring/src/vhdl/ring_mux.vhd b/libraries/base/ring/src/vhdl/ring_mux.vhd
index 0c6977776aefb653d5dcd4e726acd8ab3f515316..b907a921bbb4d8b808f620680f5b5476a282417a 100644
--- a/libraries/base/ring/src/vhdl/ring_mux.vhd
+++ b/libraries/base/ring/src/vhdl/ring_mux.vhd
@@ -46,6 +46,7 @@ ENTITY ring_mux IS
     g_use_empty         : BOOLEAN := TRUE;
     g_use_error         : BOOLEAN := TRUE;
     g_use_sync          : BOOLEAN := TRUE;
+    g_fifo_af_xon       : NATURAL := 0;  -- >=0, Nof words below max (full) at which fifo is considered almost full for snk_out.xon
     g_fifo_size         : t_natural_arr := array_init(1024, 2)  -- must match c_nof_input
   );
   PORT (
@@ -94,8 +95,8 @@ BEGIN
     g_use_in_channel    => TRUE,
     g_use_error         => g_use_error,
     g_use_sync          => g_use_sync,
+    g_fifo_af_xon       => g_fifo_af_xon,
     g_fifo_size         => g_fifo_size
-    
   )
   PORT MAP (
     rst => dp_rst,
diff --git a/libraries/io/ddr/src/vhdl/io_ddr.vhd b/libraries/io/ddr/src/vhdl/io_ddr.vhd
index 78c7bd3c0780d789b4f968750c8ebb0f09cbcecd..9157289e2e4fab3607d1972a8d9173296a4b759e 100644
--- a/libraries/io/ddr/src/vhdl/io_ddr.vhd
+++ b/libraries/io/ddr/src/vhdl/io_ddr.vhd
@@ -234,7 +234,8 @@ ARCHITECTURE str OF io_ddr IS
   CONSTANT c_wr_use_ctrl       : BOOLEAN := sel_a_b(g_wr_flush_mode="SOP", TRUE, FALSE);
   CONSTANT c_wr_fifo_use_ctrl  : BOOLEAN := c_wr_use_sync OR c_wr_use_ctrl;
   
-  CONSTANT c_ddr_gigabytes           : NATURAL := func_tech_ddr_module_size(g_tech_ddr);  -- units GiByte
+  CONSTANT c_ddr_nofbytes_w          : NATURAL := func_tech_ddr_module_nofbytes_w(g_tech_ddr);  -- log2(number of bytes)
+  CONSTANT c_ddr_gigabytes           : INTEGER := func_tech_ddr_module_gigabytes(g_tech_ddr);  -- units value GiByte when value > 1 or 2**value GiByte when value < 0
   CONSTANT c_ctlr_nof_bytes_per_word : NATURAL := func_tech_ddr_ctlr_ip_data_w(g_tech_ddr) / c_byte_w;  -- unit byte
 
   CONSTANT c_ctlr_address_w    : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr);
@@ -523,7 +524,7 @@ BEGIN
   mm_reg_io_ddr <= RESIZE_UVEC(rd_fifo_full_reg & wr_fifo_full_reg, c_mem_reg_dat_w) & 
                    RESIZE_UVEC(ctlr_wr_fifo_usedw, c_mem_reg_dat_w) & 
                    RESIZE_UVEC(ctlr_rd_fifo_usedw, c_mem_reg_dat_w) & 
-                   RESIZE_UVEC(TO_UVEC(c_ddr_gigabytes, 8) &
+                   RESIZE_UVEC(TO_SVEC(c_ddr_gigabytes, 8) &
                                TO_UVEC(c_ctlr_nof_bytes_per_word, 8) &
                                ctlr_tech_mosi.wr & ctlr_tech_miso.rdval & ctlr_tech_miso.cal_fail      & ctlr_tech_miso.cal_ok &
                                ctlr_rst_out_i    & ctlr_wr_flush_en     & ctlr_tech_miso.waitrequest_n & ctlr_tech_miso.done, c_mem_reg_dat_w);   
diff --git a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
index eac49482da7a7b38127631a97b3feea871207b58..1576dda24fcb93998266da1e458863f3d1c9d031 100644
--- a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
+++ b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
@@ -69,10 +69,13 @@ ARCHITECTURE str of tb_io_ddr IS
 
   -- Select DDR3 or DDR4 dependent on the technology and sim model
   CONSTANT c_mem_ddr                  : t_c_tech_ddr := func_tech_sel_ddr(g_technology, g_tech_ddr3, g_tech_ddr4);
+
+  -- Need to use >= c_tech_ddr4_sim_16k for g_block_len = 2500 in tb_tb_io_ddr
   CONSTANT c_sim_ddr                  : t_c_tech_ddr := func_tech_sel_ddr(g_technology, c_tech_ddr3_sim_16k, c_tech_ddr4_sim_16k);
   CONSTANT c_tech_ddr                 : t_c_tech_ddr := func_tech_sel_ddr(g_sim_model, c_sim_ddr, c_mem_ddr);
   
-  CONSTANT c_exp_gigabytes            : NATURAL := func_tech_ddr_module_size(c_tech_ddr);
+  CONSTANT c_exp_gigabytes            : INTEGER := func_tech_ddr_module_gigabytes(c_tech_ddr);
+  CONSTANT c_exp_nofbytes_w           : NATURAL := func_tech_ddr_module_nofbytes_w(c_tech_ddr);
   CONSTANT c_exp_nof_bytes_per_word   : NATURAL := func_tech_ddr_ctlr_ip_data_w(c_tech_ddr) / c_byte_w;
 
   CONSTANT c_dp_clk_period            : TIME := 5 ns;   -- 200 MHz
@@ -166,8 +169,9 @@ ARCHITECTURE str of tb_io_ddr IS
   SIGNAL dbg_c_ctlr_wr_not_rd_arr     : STD_LOGIC_VECTOR(0 TO c_nof_access-1)  := c_ctlr_wr_not_rd_arr;
   
   SIGNAL dbg_c_tech_ddr               : t_c_tech_ddr := c_tech_ddr;
-  SIGNAL dbg_c_exp_gigabytes          : NATURAL := c_exp_gigabytes;  -- = 0 for sim model, else nof GB
-  SIGNAL ddr_gigabytes                : NATURAL;
+  SIGNAL dbg_c_exp_gigabytes          : INTEGER := c_exp_gigabytes;  -- = 0 for sim model, else nof GB
+  SIGNAL dbg_c_exp_nofbytes_w         : NATURAL := c_exp_nofbytes_w;
+  SIGNAL ddr_gigabytes                : INTEGER;
   SIGNAL dbg_c_exp_nof_bytes_per_word : NATURAL := c_exp_nof_bytes_per_word;
   SIGNAL ctlr_nof_bytes_per_word      : NATURAL;
   SIGNAL dbg_c_dp_data_w              : NATURAL := c_dp_data_w;
@@ -274,7 +278,7 @@ BEGIN
     proc_mem_mm_bus_rd(0, mm_clk, reg_io_ddr_miso, reg_io_ddr_mosi);
     proc_mem_mm_bus_rd_latency(1, mm_clk);
     -- . verify ddr_gigabytes
-    ddr_gigabytes <= TO_UINT(reg_io_ddr_miso.rddata(23 DOWNTO 16));
+    ddr_gigabytes <= TO_SINT(reg_io_ddr_miso.rddata(23 DOWNTO 16));
     proc_common_wait_some_cycles(mm_clk, 1);
     ASSERT ddr_gigabytes = c_exp_gigabytes REPORT "Wrong read ddr_gigabytes" SEVERITY ERROR;
     -- . verify ctlr_nof_bytes_per_word
diff --git a/libraries/technology/ddr/tech_ddr_arria10.vhd b/libraries/technology/ddr/tech_ddr_arria10.vhd
index d706440e088df27496efa16f606d261b71ac2141..012b57882e8c25c26255a886863df1931ff395f0 100644
--- a/libraries/technology/ddr/tech_ddr_arria10.vhd
+++ b/libraries/technology/ddr/tech_ddr_arria10.vhd
@@ -71,7 +71,7 @@ END tech_ddr_arria10;
 
 ARCHITECTURE str OF tech_ddr_arria10 IS
 
-  CONSTANT c_gigabytes             : NATURAL := func_tech_ddr_module_size(g_tech_ddr);
+  CONSTANT c_gigabytes             : INTEGER := func_tech_ddr_module_gigabytes(g_tech_ddr);
 
   CONSTANT c_ctlr_address_w        : NATURAL := 26; --func_tech_ddr_ctlr_address_w(g_tech_ddr);
   CONSTANT c_ctlr_data_w           : NATURAL := 576;--func_tech_ddr_ctlr_data_w(   g_tech_ddr);
diff --git a/libraries/technology/ddr/tech_ddr_arria10_e1sg.vhd b/libraries/technology/ddr/tech_ddr_arria10_e1sg.vhd
index c59f216e78c90925321dee6602f3f561add69899..ff65a1506508cea6098fc36c1e9242997d438b12 100644
--- a/libraries/technology/ddr/tech_ddr_arria10_e1sg.vhd
+++ b/libraries/technology/ddr/tech_ddr_arria10_e1sg.vhd
@@ -74,7 +74,7 @@ END tech_ddr_arria10_e1sg;
 
 ARCHITECTURE str OF tech_ddr_arria10_e1sg IS
 
-  CONSTANT c_gigabytes             : NATURAL := func_tech_ddr_module_size(g_tech_ddr);
+  CONSTANT c_gigabytes             : INTEGER := func_tech_ddr_module_gigabytes(g_tech_ddr);
 
   CONSTANT c_ctlr_address_w        : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr);
   CONSTANT c_ctlr_data_w           : NATURAL := 576;--func_tech_ddr_ctlr_data_w(   g_tech_ddr);
diff --git a/libraries/technology/ddr/tech_ddr_arria10_e2sg.vhd b/libraries/technology/ddr/tech_ddr_arria10_e2sg.vhd
index 5b6f28915746718af3d4a3c20121f74b7c86d320..33876ba09e857050232506109614ffee6ef299d5 100644
--- a/libraries/technology/ddr/tech_ddr_arria10_e2sg.vhd
+++ b/libraries/technology/ddr/tech_ddr_arria10_e2sg.vhd
@@ -73,7 +73,7 @@ END tech_ddr_arria10_e2sg;
 
 ARCHITECTURE str OF tech_ddr_arria10_e2sg IS
 
-  CONSTANT c_gigabytes             : NATURAL := func_tech_ddr_module_size(g_tech_ddr);
+  CONSTANT c_gigabytes             : INTEGER := func_tech_ddr_module_gigabytes(g_tech_ddr);
 
   CONSTANT c_ctlr_address_w        : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr);
   CONSTANT c_ctlr_ip_data_w        : NATURAL := func_tech_ddr_ctlr_ip_data_w(g_tech_ddr);
diff --git a/libraries/technology/ddr/tech_ddr_arria10_e3sge3.vhd b/libraries/technology/ddr/tech_ddr_arria10_e3sge3.vhd
index 2a95f000aad9136b9345c1898c400622c569568a..075c74830130f3c61842093ed5831a2ad9eb706c 100644
--- a/libraries/technology/ddr/tech_ddr_arria10_e3sge3.vhd
+++ b/libraries/technology/ddr/tech_ddr_arria10_e3sge3.vhd
@@ -73,7 +73,7 @@ END tech_ddr_arria10_e3sge3;
 
 ARCHITECTURE str OF tech_ddr_arria10_e3sge3 IS
 
-  CONSTANT c_gigabytes             : NATURAL := func_tech_ddr_module_size(g_tech_ddr);
+  CONSTANT c_gigabytes             : INTEGER := func_tech_ddr_module_gigabytes(g_tech_ddr);
 
   CONSTANT c_ctlr_address_w        : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr);
   CONSTANT c_ctlr_data_w           : NATURAL := 576;--func_tech_ddr_ctlr_data_w(   g_tech_ddr);
diff --git a/libraries/technology/ddr/tech_ddr_mem_model.vhd b/libraries/technology/ddr/tech_ddr_mem_model.vhd
index c814d05884e16fafa9b6d371d21fb0b606015102..a301052eb7f072407ba160948bbb845e939ed961 100644
--- a/libraries/technology/ddr/tech_ddr_mem_model.vhd
+++ b/libraries/technology/ddr/tech_ddr_mem_model.vhd
@@ -59,10 +59,10 @@ END tech_ddr_memory_model;
 
 ARCHITECTURE str OF tech_ddr_memory_model IS
 
-  CONSTANT c_gigabytes    : NATURAL := func_tech_ddr_module_size(g_tech_ddr);
+  CONSTANT c_gigabytes    : INTEGER := func_tech_ddr_module_gigabytes(g_tech_ddr);
 
   SIGNAL dbg_g_tech_ddr   : t_c_tech_ddr := g_tech_ddr;
-  SIGNAL dbg_c_gigabytes  : NATURAL := c_gigabytes;
+  SIGNAL dbg_c_gigabytes  : INTEGER := c_gigabytes;
   
 BEGIN
 
diff --git a/libraries/technology/ddr/tech_ddr_pkg.vhd b/libraries/technology/ddr/tech_ddr_pkg.vhd
index 894e988782ebaf62ed5d9017343291b3f72a6366..fb3400258c6ba7e8620ebc0b21273abb67e44c5c 100644
--- a/libraries/technology/ddr/tech_ddr_pkg.vhd
+++ b/libraries/technology/ddr/tech_ddr_pkg.vhd
@@ -67,7 +67,12 @@ PACKAGE tech_ddr_pkg IS
   FUNCTION func_tech_ddr_ctlr_address_w(c_ddr : t_c_tech_ddr) RETURN NATURAL;  -- return DDR address width for the controller data at the by rsl=4 reduced rate
   FUNCTION func_tech_ddr_ctlr_data_w(   c_ddr : t_c_tech_ddr) RETURN NATURAL;  -- return DDR    data width for the controller data at the by rsl=4 reduced rate
   FUNCTION func_tech_ddr_ctlr_ip_data_w(c_ddr : t_c_tech_ddr) RETURN NATURAL;  -- return DDR    data width for the controller data at the by rsl=4 reduced rate
-  FUNCTION func_tech_ddr_module_size(   c_ddr : t_c_tech_ddr) RETURN NATURAL;  -- return DDR module size in GByte
+
+  -- return DDR module size in log2(number of bytes), because 2**nofbytes_w may not fit in 31 bit NATURAL
+  FUNCTION func_tech_ddr_module_nofbytes_w(c_ddr : t_c_tech_ddr) RETURN NATURAL;
+  -- return DDR module size in GiBytes when >= 1 GByte which is typical on HW, else
+  -- return size as negative value to indicate 2**value fraction of 1GByte which is typical in simulation
+  FUNCTION func_tech_ddr_module_gigabytes(c_ddr : t_c_tech_ddr) RETURN INTEGER;
 
   FUNCTION func_tech_ddr_sim_size(c_ddr : t_c_tech_ddr; sim_ctrl_addr_w : NATURAL) RETURN t_c_tech_ddr; -- derive sim_ddr from c_ddr (or alternatively use predefined c_tech_ddr*_sim)
   FUNCTION func_tech_ddr_rewire_64b_to_72b(c_ddr : t_c_tech_ddr; vec_64b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
@@ -252,20 +257,28 @@ PACKAGE BODY tech_ddr_pkg IS
     RETURN v_ddr;
   END;
   
-  FUNCTION func_tech_ddr_module_size(c_ddr : t_c_tech_ddr) RETURN NATURAL IS
+  FUNCTION func_tech_ddr_module_nofbytes_w(c_ddr : t_c_tech_ddr) RETURN NATURAL IS
     CONSTANT c_dq_address_w       : NATURAL := func_tech_ddr_dq_address_w(c_ddr);
     CONSTANT c_dq_nof_bytes       : NATURAL := 8;  -- both dw_q = 64 and 72 are regarded as having 8 bytes (either with 8 or 9 bits per byte)
     CONSTANT c_dq_nof_bytes_w     : NATURAL := ceil_log2(c_dq_nof_bytes);
     CONSTANT c_module_nof_bytes_w : NATURAL := c_dq_address_w + c_dq_nof_bytes_w;
+  BEGIN
+    RETURN c_module_nof_bytes_w;
+  END;
+  
+  FUNCTION func_tech_ddr_module_gigabytes(c_ddr : t_c_tech_ddr) RETURN INTEGER IS
+    CONSTANT c_module_nof_bytes_w : NATURAL := func_tech_ddr_module_nofbytes_w(c_ddr);
     CONSTANT c_1GB_w              : NATURAL := 30;
   BEGIN
     IF c_module_nof_bytes_w < c_1GB_w THEN
-      RETURN 0;
+      -- Return <= -1 to indicate fraction of 1GByte, so e.g. -1 implies 2**-1 = 0.5 GByte
+      RETURN c_module_nof_bytes_w - c_1GB_w;
     ELSE
-      RETURN 2**(c_module_nof_bytes_w-c_1GB_w);
+      -- Return >= 1 to indicate multiple of 1GByte = number of GByte
+      RETURN 2**(c_module_nof_bytes_w - c_1GB_w);
     END IF;
   END;
-  
+
   FUNCTION func_tech_ddr_rewire_64b_to_72b(c_ddr : t_c_tech_ddr; vec_64b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
     VARIABLE vec_72b : STD_LOGIC_VECTOR(func_tech_ddr_ctlr_ip_data_w(c_ddr) - 1 DOWNTO 0) := (OTHERS => '0');
   BEGIN
diff --git a/libraries/technology/ddr/tech_ddr_stratixiv.vhd b/libraries/technology/ddr/tech_ddr_stratixiv.vhd
index 7e9563ee5667fcd30c7d31c0a9822f999b9e5f6c..2830195512e35b15ac6b8cbb3e3ae8446e0f955e 100644
--- a/libraries/technology/ddr/tech_ddr_stratixiv.vhd
+++ b/libraries/technology/ddr/tech_ddr_stratixiv.vhd
@@ -75,12 +75,12 @@ END tech_ddr_stratixiv;
 
 ARCHITECTURE str OF tech_ddr_stratixiv IS
 
-  CONSTANT c_gigabytes             : NATURAL := func_tech_ddr_module_size(g_tech_ddr);
+  CONSTANT c_gigabytes             : INTEGER := func_tech_ddr_module_gigabytes(g_tech_ddr);
 
   CONSTANT c_ctlr_address_w        : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr);
   CONSTANT c_ctlr_data_w           : NATURAL := func_tech_ddr_ctlr_data_w(   g_tech_ddr);
   
-  SIGNAL dbg_c_gigabytes           : NATURAL := c_gigabytes;
+  SIGNAL dbg_c_gigabytes           : INTEGER := c_gigabytes;
   
   SIGNAL ref_rst_n                 : STD_LOGIC;
   SIGNAL ctlr_gen_rst_n            : STD_LOGIC;