diff --git a/libraries/io/ddr/src/vhdl/io_ddr.vhd b/libraries/io/ddr/src/vhdl/io_ddr.vhd
index cd42192996de6c6cc89c81caed63e498d2ce169c..182a004ccd3352fed738ac661da9b45afb6072b1 100644
--- a/libraries/io/ddr/src/vhdl/io_ddr.vhd
+++ b/libraries/io/ddr/src/vhdl/io_ddr.vhd
@@ -41,12 +41,12 @@
 --   DDR write access can start on the next valid, sop or sync dependent on
 --   g_wr_flush_mode.
 --
---   The g_rd_fifo_af_margin needs to be large enough to fit a number of read
+--   The c_rd_fifo_af_margin needs to be large enough to fit a number of read
 --   bursts that may be pending in the DDR controller command queue depth. 
 --   A new rd access can start when ctlr_rd_src_in.ready indicates that there
 --   is sufficient space in the read FIFO to store g_tech_ddr.maxburstsize
 --   words. Due to the DDR controller command queue there can be more rd
---   bursts already be pending. Therefore the g_rd_fifo_af_margin needs to be
+--   bursts already be pending. Therefore the c_rd_fifo_af_margin needs to be
 --   large enough to fit a number of read bursts.
 
 -- Usage:
@@ -159,9 +159,8 @@ ENTITY io_ddr IS
     g_tech_ddr                : t_c_tech_ddr;
     g_cross_domain_dvr_ctlr   : BOOLEAN := TRUE;    -- use TRUE when MM clock is used for the access control, use FALSE when ctlr_clk_in=ctlr_clk_out is used to avoid extra latency
     g_wr_data_w               : NATURAL := 32;  
-    g_wr_fifo_depth           : NATURAL := 256;     -- >=16                             , defined at DDR side of the FIFO, default 256 because 32b*256 fits in 1 M9K
-    g_rd_fifo_depth           : NATURAL := 256;     -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO, default 256 because 32b*256 fits in 1 M9K 
-    g_rd_fifo_af_margin       : NATURAL := 4 + 1*64;  -- < g_rd_fifo_depth and sufficient to fit one or more rd burst accesses of g_tech_ddr.maxburstsize each
+    g_wr_fifo_depth           : NATURAL := 256;   -- defined at DDR side of the FIFO, >=16 and independent of wr burst size, default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K
+    g_rd_fifo_depth           : NATURAL := 256;   -- defined at DDR side of the FIFO, >=16 AND > max number of rd burst sizes (so > c_rd_fifo_af_margin), default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K
     g_rd_data_w               : NATURAL := 32;
     g_wr_flush_mode           : STRING := "VAL";  -- "VAL", "SOP", "SYN"
     g_wr_flush_use_channel    : BOOLEAN := FALSE;
@@ -237,8 +236,11 @@ ARCHITECTURE str OF io_ddr IS
   CONSTANT c_ctlr_data_w       : NATURAL := func_tech_ddr_ctlr_data_w(g_tech_ddr);
   CONSTANT c_wr_fifo_depth     : NATURAL := g_wr_fifo_depth * (c_ctlr_data_w/g_wr_data_w);  -- get FIFO depth at write side
   
-  CONSTANT c_wr_fifo_af_margin : NATURAL := 4 + 1;                        -- use +1 to compensate for latency introduced by registering wr_siso.ready due to RL=0
+  CONSTANT c_wr_fifo_af_margin : NATURAL := 8 + 1;      -- use 8 (>= 4 default) to be safe and use +1 to compensate for latency introduced by registering wr_siso.ready due to RL=0
  
+  CONSTANT c_nof_rd_bursts_max : NATURAL := sel_a_b(g_tech_ddr.name="DDR3", 1, 3);            -- max number of rd bursts in queue, derived empirically from simulation, seems fixed 1 for DDR3 and seems to match (g_tech_ddr.command_queue_depth-1)/2 for DDR4
+  CONSTANT c_rd_fifo_af_margin : NATURAL := 8 + c_nof_rd_bursts_max*g_tech_ddr.maxburstsize;  -- use 8 (>= 4 default) to be safe and use sufficient extra margin to fit one or more rd burst accesses of g_tech_ddr.maxburstsize each
+  
   CONSTANT c_mem_reg_adr_w     : NATURAL := 2;
   CONSTANT c_mem_reg_dat_w     : NATURAL := 32;
   CONSTANT c_mem_reg_nof_data  : NATURAL := 3;
@@ -392,13 +394,15 @@ BEGIN
     ctlr_wr_flush_en => ctlr_wr_flush_en
   );
 
+  ASSERT g_rd_fifo_depth>c_rd_fifo_af_margin REPORT "io_ddr: rd FIFO depth must be > almost full margin." SEVERITY FAILURE;
+  
   u_rd_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths
   GENERIC MAP (
     g_wr_data_w         => c_ctlr_data_w,
     g_rd_data_w         => g_rd_data_w,
     g_use_ctrl          => FALSE,
     g_wr_fifo_size      => g_rd_fifo_depth,
-    g_wr_fifo_af_margin => g_rd_fifo_af_margin, -- >=4 (required by dp_fifo)
+    g_wr_fifo_af_margin => c_rd_fifo_af_margin, -- >=4 (required by dp_fifo)
     g_rd_fifo_rl        => 1
   )
   PORT MAP (
diff --git a/libraries/io/ddr/src/vhdl/mms_io_ddr.vhd b/libraries/io/ddr/src/vhdl/mms_io_ddr.vhd
index 57cb972d1d04438b61f42d01203589d5e41283ee..f07142b4f47634ce894dab58737cc096f6ab9170 100644
--- a/libraries/io/ddr/src/vhdl/mms_io_ddr.vhd
+++ b/libraries/io/ddr/src/vhdl/mms_io_ddr.vhd
@@ -35,9 +35,8 @@ ENTITY mms_io_ddr IS
     g_technology              : NATURAL := c_tech_select_default;
     g_tech_ddr                : t_c_tech_ddr;
     g_wr_data_w               : NATURAL := 32;  
-    g_wr_fifo_depth           : NATURAL := 256;     -- >=16                             , defined at DDR side of the FIFO, default 256 because 32b*256 fits in 1 M9K
-    g_rd_fifo_depth           : NATURAL := 256;     -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO, default 256 because 32b*256 fits in 1 M9K 
-    g_rd_fifo_af_margin       : NATURAL := 4 + 1*64;  -- < g_rd_fifo_depth and sufficient to fit one or more rd burst accesses of g_tech_ddr.maxburstsize each
+    g_wr_fifo_depth           : NATURAL := 256;   -- defined at DDR side of the FIFO, >=16 and independent of wr burst size, default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K
+    g_rd_fifo_depth           : NATURAL := 256;   -- defined at DDR side of the FIFO, >=16 AND > max number of rd burst sizes (so > c_rd_fifo_af_margin), default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K
     g_rd_data_w               : NATURAL := 32;
     g_wr_flush_mode           : STRING := "VAL";  -- "VAL", "SOP", "SYN"
     g_wr_flush_use_channel    : BOOLEAN := FALSE;
diff --git a/libraries/io/ddr/src/vhdl/mms_io_ddr_diag.vhd b/libraries/io/ddr/src/vhdl/mms_io_ddr_diag.vhd
index 69b7ad05253d1199faffcb4768c68277b78d1c48..ec39b0cd88d1875380faf3e41d73171239f005db 100644
--- a/libraries/io/ddr/src/vhdl/mms_io_ddr_diag.vhd
+++ b/libraries/io/ddr/src/vhdl/mms_io_ddr_diag.vhd
@@ -61,7 +61,7 @@ ENTITY mms_io_ddr_diag IS
     
     g_dp_data_w       : NATURAL := 32;  -- DP data width, func_tech_ddr_ctlr_data_w(g_io_tech_ddr)/g_dp_data_w must be a power of 2 due to the mixed width FIFO
     g_dp_seq_dat_w    : NATURAL := 32;  -- >= 1, test sequence data width. Choose g_dp_seq_dat_w <= g_dp_data_w. The seq data gets replicated to fill g_dp_data_w.
-    g_dp_fifo_depth   : NATURAL := 2048;  -- >= 2048, write FIFO depth and read FIFO depth at DP side of the FIFOs
+    g_dp_fifo_depth   : NATURAL := 2048;  -- defined at DP side of the FIFOs, write FIFO depth and read FIFO depth
     
     -- IO_DDR
     g_io_tech_ddr     : t_c_tech_ddr;
@@ -140,9 +140,8 @@ END mms_io_ddr_diag;
 
 ARCHITECTURE str OF mms_io_ddr_diag IS
 
-  CONSTANT c_io_wr_fifo_depth      : NATURAL := (g_dp_fifo_depth * g_dp_data_w) / func_tech_ddr_ctlr_data_w(g_io_tech_ddr);     -- >=16                             , defined at DDR side of the FIFO
-  CONSTANT c_io_rd_fifo_depth      : NATURAL := (g_dp_fifo_depth * g_dp_data_w) / func_tech_ddr_ctlr_data_w(g_io_tech_ddr);     -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO, default 256 because 32b*256 fits in 1 M9K
-  CONSTANT c_io_rd_fifo_af_margin  : NATURAL := 4 + 1*64;  -- < c_io_rd_fifo_depth and sufficient to fit one or more rd burst accesses of g_io_tech_ddr.maxburstsize each
+  CONSTANT c_io_wr_fifo_depth      : NATURAL := (g_dp_fifo_depth * g_dp_data_w) / func_tech_ddr_ctlr_data_w(g_io_tech_ddr);  -- defined at DDR side of the FIFO, >=16 and independent of wr burst size, default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K
+  CONSTANT c_io_rd_fifo_depth      : NATURAL := (g_dp_fifo_depth * g_dp_data_w) / func_tech_ddr_ctlr_data_w(g_io_tech_ddr);  -- defined at DDR side of the FIFO, >=16 AND > max number of rd burst sizes (so > c_rd_fifo_af_margin), default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K
     
   SIGNAL bg_siso_arr     : t_dp_siso_arr(0 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy);  -- Default xon='1'
   SIGNAL bg_sosi_arr     : t_dp_sosi_arr(0 DOWNTO 0);                             -- Output SOSI that contains the waveform data
@@ -163,7 +162,6 @@ BEGIN
     g_wr_data_w               => g_dp_data_w,
     g_wr_fifo_depth           => c_io_wr_fifo_depth,
     g_rd_fifo_depth           => c_io_rd_fifo_depth,
-    g_rd_fifo_af_margin       => c_io_rd_fifo_af_margin,
     g_rd_data_w               => g_dp_data_w,
     g_wr_flush_mode           => "VAL",
     g_wr_flush_use_channel    => FALSE,
diff --git a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
index 77b604d5903d71f5b1b2d8ee00d5c32341c2fa6f..fcad1d1261b442289236e341d8284f4a1cf3da09 100644
--- a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
+++ b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
@@ -82,11 +82,8 @@ ARCHITECTURE str of tb_io_ddr IS
   
   CONSTANT c_dp_data_w                : NATURAL := c_ctlr_data_w/g_dp_factor;
   
-  CONSTANT c_queue_nof_rd             : NATURAL := sel_a_b(c_tech_ddr.name="DDR3", 1, 3);   -- derived empirically from simulation, seems to match (c_tech_ddr.command_queue_depth-1)/2
-  
-  CONSTANT c_wr_fifo_depth            : NATURAL := 256;
-  CONSTANT c_rd_fifo_depth            : NATURAL := g_rd_fifo_depth;
-  CONSTANT c_rd_fifo_af_margin        : NATURAL := 4 + c_queue_nof_rd*c_tech_ddr.maxburstsize;  -- sufficient to fit one or more rd burst accesses of g_tech_ddr.maxburstsize each
+  CONSTANT c_wr_fifo_depth            : NATURAL := 256;              -- defined at DDR side of the FIFO 
+  CONSTANT c_rd_fifo_depth            : NATURAL := g_rd_fifo_depth;  -- defined at DDR side of the FIFO 
   
   -- Frame size for sop/eop
   CONSTANT c_wr_frame_size            : NATURAL := 32;
@@ -167,7 +164,6 @@ ARCHITECTURE str of tb_io_ddr IS
   SIGNAL dbg_c_dp_data_w              : NATURAL := c_dp_data_w;
   SIGNAL dbg_c_wr_fifo_depth          : NATURAL := c_wr_fifo_depth;
   SIGNAL dbg_c_rd_fifo_depth          : NATURAL := c_rd_fifo_depth;
-  SIGNAL dbg_c_rd_fifo_af_margin      : NATURAL := c_rd_fifo_af_margin;
   
   SIGNAL i_tb_end             : STD_LOGIC := '0';
   SIGNAL ctlr_ref_clk         : STD_LOGIC := '0';
@@ -409,9 +405,8 @@ BEGIN
     g_tech_ddr               => c_tech_ddr,
     g_cross_domain_dvr_ctlr  => c_cross_domain_dvr_ctlr,
     g_wr_data_w              => c_dp_data_w,
-    g_wr_fifo_depth          => c_wr_fifo_depth,  -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO.
-    g_rd_fifo_depth          => c_rd_fifo_depth,  -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. 
-    g_rd_fifo_af_margin      => c_rd_fifo_af_margin,
+    g_wr_fifo_depth          => c_wr_fifo_depth,  -- defined at DDR side of the FIFO.
+    g_rd_fifo_depth          => c_rd_fifo_depth,  -- defined at DDR side of the FIFO. 
     g_rd_data_w              => c_dp_data_w,
     g_wr_flush_mode          => g_wr_flush_mode,
     g_wr_flush_use_channel   => FALSE,