From 1cace6765e95dfa19bfafc2fc785dbd827f4541f Mon Sep 17 00:00:00 2001
From: Erik Kooistra <kooistra@astron.nl>
Date: Thu, 8 Jan 2015 06:43:14 +0000
Subject: [PATCH] No need to use wr_fifo_usedw, because snk_in.valid does not
 need to remain active during the burst.

---
 libraries/io/ddr/src/vhdl/io_ddr.vhd        |  22 ++-
 libraries/io/ddr/src/vhdl/io_ddr_driver.vhd | 164 ++++++++------------
 2 files changed, 71 insertions(+), 115 deletions(-)

diff --git a/libraries/io/ddr/src/vhdl/io_ddr.vhd b/libraries/io/ddr/src/vhdl/io_ddr.vhd
index d8369af334..c64eb757a9 100644
--- a/libraries/io/ddr/src/vhdl/io_ddr.vhd
+++ b/libraries/io/ddr/src/vhdl/io_ddr.vhd
@@ -44,14 +44,11 @@
 -- Block diagram:
 --
 --
---                        ctlr_wr_fifo_src        ctlr_wr_snk   ctlr_mosi
---                                    .             .             .
---                      ________      .             .   _______   .   ______
---                     |        |-----.-------------.->|       |  .  |      |
---                     |        |     .   ______    .  |       |  .  |      |
---   wr_fifo_usedw <---|dp_fifo |     .  |      |   .  |       |  .  |      |
---   wr_sosi --------->|dc_mixed|-+----->|dp    |----->| io    |  .  | tech |
---   wr_clk  --------->|widths  | |      |flush |      | ddr   |  .  | ddr  |
+--                          ctlr_wr_fifo_src      ctlr_wr_snk   ctlr_mosi
+--                      ________      .   ______    .   _______   .   ______
+--   wr_fifo_usedw <---|dp_fifo |     .  |dp    |   .  |       |  .  |      |
+--   wr_sosi --------->|dc_mixed|-+----->|flush |----->| io    |  .  | tech |
+--   wr_clk  --------->|widths  | |      |      |      | ddr   |  .  | ddr  |
 --                     |________| |      |______|<--\  | driver|  .  |      |
 --                                |                 |  |       |  .  |      |
 --                                | ctlr_wr_flush_en|  |       |  .  |      |
@@ -199,7 +196,9 @@ ARCHITECTURE str OF io_ddr IS
   SIGNAL ctlr_rd_src_in        : t_dp_siso;
   SIGNAL ctlr_rd_src_out       : t_dp_sosi := c_dp_sosi_rst;
   
-  SIGNAL ctlr_wr_fifo_usedw    : STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth)-1 DOWNTO 0);  -- read side depth of the write FIFO
+  -- Monitor only
+  SIGNAL ctlr_wr_fifo_usedw    : STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth)-1 DOWNTO 0);  -- read  side depth of the write FIFO
+  SIGNAL ctlr_rd_fifo_usedw    : STD_LOGIC_VECTOR(ceil_log2(g_rd_fifo_depth)-1 DOWNTO 0);  -- write side depth of the read  FIFO
   
 BEGIN 
 
@@ -312,7 +311,7 @@ BEGIN
     dvr_wr_not_rd    => ctlr_dvr_wr_not_rd,
     dvr_wr_flush_en  => ctlr_dvr_wr_flush_en,
 
-    wr_sosi          => ctlr_wr_flush_snk_in,
+    ctlr_wr_sosi     => ctlr_wr_flush_snk_in,
 
     ctlr_wr_flush_en => ctlr_wr_flush_en
   );
@@ -335,7 +334,7 @@ BEGIN
     snk_out  => ctlr_rd_src_in,
     snk_in   => ctlr_rd_src_out,
   
-    wr_usedw => OPEN,
+    wr_usedw => ctlr_rd_fifo_usedw,
     rd_usedw => rd_fifo_usedw,
     rd_emp   => OPEN,
 
@@ -357,7 +356,6 @@ BEGIN
     dvr_nof_data       => ctlr_dvr_nof_data, 
     dvr_done           => ctlr_dvr_done,
     
-    wr_fifo_usedw      => ctlr_wr_fifo_usedw,
     wr_snk_in          => ctlr_wr_snk_in, 
     wr_snk_out         => ctlr_wr_snk_out,
     
diff --git a/libraries/io/ddr/src/vhdl/io_ddr_driver.vhd b/libraries/io/ddr/src/vhdl/io_ddr_driver.vhd
index 93523dd8ad..cdb8f9d912 100644
--- a/libraries/io/ddr/src/vhdl/io_ddr_driver.vhd
+++ b/libraries/io/ddr/src/vhdl/io_ddr_driver.vhd
@@ -27,10 +27,8 @@
 --   256 bits for DDR3 with 64 bit DQ data. The block of data is located from
 --   dvr_start_address to dvr_nof_data.
 --   The io_ddr_driver takes care that the access is done in a number of bursts.
---   The write burst size depends on the maximum burst size, the remaining
---   block size and on the number of words available in the (external) FIFO as
---   indicated by wr_fifo_usedw. The read burst size depends on the maximum
---   burst size and the remaining block size.
+--   The burst size for both write and read depends on the maximum burst size
+--   and the remaining block size.
 -- Remarks:
 -- . 
 
@@ -53,9 +51,8 @@ ENTITY io_ddr_driver IS
     dvr_wr_not_rd      : IN  STD_LOGIC;       
     dvr_start_address  : IN  STD_LOGIC_VECTOR;
     dvr_nof_data       : IN  STD_LOGIC_VECTOR;
-    dvr_done           : OUT STD_LOGIC;         -- Requested wr or rd sequence is done.
+    dvr_done           : OUT STD_LOGIC;         -- Requested wr or rd sequence is done
    
-    wr_fifo_usedw      : IN  STD_LOGIC_VECTOR;
     wr_snk_in          : IN  t_dp_sosi;
     wr_snk_out         : OUT t_dp_siso;
     
@@ -73,101 +70,65 @@ ARCHITECTURE str OF io_ddr_driver IS
 
   CONSTANT c_ctlr_address_w     : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr);
  
-  CONSTANT c_margin             : NATURAL := 2; -- wr_burst_size is updated one cycle after reading actual nof available words.
-                                                -- Subtract two (wr_fifo_usedw and wr_burst_size are both registered) so we cannot 
-                                                -- post a request for a too large burst size, which could cause the wr_burst state 
-                                                -- to be two valid words short.
-
-  TYPE t_state_enum IS (s_init, s_idle, s_wait1, s_wait2, s_wait3, s_rd_request, s_wr_request, s_wr_burst);
+  TYPE t_state_enum IS (s_init, s_idle, s_wait, s_rd_request, s_wr_request, s_wr_burst);
 
   SIGNAL state                  : t_state_enum;
   SIGNAL nxt_state              : t_state_enum; 
   SIGNAL prev_state             : t_state_enum; 
 
-  SIGNAL wr_burst_size          : NATURAL RANGE 0 TO 2**g_tech_ddr.maxburstsize_w-1;
-  SIGNAL rd_burst_size          : NATURAL RANGE 0 TO 2**g_tech_ddr.maxburstsize_w-1;
-
-  SIGNAL nxt_wr_burst_size      : NATURAL;
-  SIGNAL nxt_rd_burst_size      : NATURAL;
-
-  SIGNAL burst_wr_cnt           : STD_LOGIC_VECTOR(g_tech_ddr.maxburstsize_w-1 DOWNTO 0);  -- count down from wr_burst_size to 0
+  SIGNAL burst_size             : POSITIVE RANGE 1 TO 2**g_tech_ddr.maxburstsize_w-1;      -- burst size >= 1
+  SIGNAL nxt_burst_size         : POSITIVE;
+  SIGNAL burst_wr_cnt           : STD_LOGIC_VECTOR(g_tech_ddr.maxburstsize_w-1 DOWNTO 0);  -- count down from burst_size to 0
   SIGNAL nxt_burst_wr_cnt       : STD_LOGIC_VECTOR(g_tech_ddr.maxburstsize_w-1 DOWNTO 0);
 
-  SIGNAL i_dvr_done             : STD_LOGIC;
   SIGNAL nxt_dvr_done           : STD_LOGIC;
 
   SIGNAL cur_address            : STD_LOGIC_VECTOR(c_ctlr_address_w-1 DOWNTO 0);
   SIGNAL nxt_cur_address        : STD_LOGIC_VECTOR(c_ctlr_address_w-1 DOWNTO 0);   
   SIGNAL address_cnt            : STD_LOGIC_VECTOR(c_ctlr_address_w-1 DOWNTO 0);  -- count down nof addresses = nof ctlr data words
   SIGNAL nxt_address_cnt        : STD_LOGIC_VECTOR(c_ctlr_address_w-1 DOWNTO 0);   
-  SIGNAL reg_address_cnt        : STD_LOGIC_VECTOR(c_ctlr_address_w-1 DOWNTO 0);   
-  SIGNAL reg_wr_fifo_usedw      : STD_LOGIC_VECTOR(wr_fifo_usedw'RANGE);          -- available nof ctlr data words for a burst in at read side the write FIFO
 
 BEGIN
 
-  dvr_done <= i_dvr_done; 
-
   p_clk : PROCESS(rst, clk)
   BEGIN
     IF rst='1' THEN
       state                <= s_init;
       burst_wr_cnt         <= (OTHERS => '0');
-      i_dvr_done           <= '0';
+      dvr_done             <= '0';
       cur_address          <= (OTHERS=>'0');
       address_cnt          <= (OTHERS=>'0');
-      wr_burst_size        <= 0;
-      rd_burst_size        <= 0;
-      reg_address_cnt      <= (OTHERS=>'0');
-      reg_wr_fifo_usedw    <= (OTHERS=>'0');
+      burst_size           <= 1;
       prev_state           <= s_idle;
     ELSIF rising_edge(clk) THEN
       state                <= nxt_state;
       burst_wr_cnt         <= nxt_burst_wr_cnt;
-      i_dvr_done           <= nxt_dvr_done;
+      dvr_done             <= nxt_dvr_done;
       cur_address          <= nxt_cur_address;
       address_cnt          <= nxt_address_cnt;
-      wr_burst_size        <= nxt_wr_burst_size;
-      rd_burst_size        <= nxt_rd_burst_size;
-      reg_address_cnt      <= address_cnt;
-      reg_wr_fifo_usedw    <= wr_fifo_usedw;
+      burst_size           <= nxt_burst_size;
       prev_state           <= state;
     END IF;
   END PROCESS;
 
-  p_wr_burst_size : PROCESS (reg_address_cnt, reg_wr_fifo_usedw)
-    VARIABLE v_burst_size : POSITIVE;
+  p_burst_size : PROCESS (address_cnt)
   BEGIN 
-    -- Write burst size is at least 1 and if more then set to the smallest of g_tech_ddr.maxburstsize, address_cnt and wr_fifo_usedw
-    IF UNSIGNED(reg_wr_fifo_usedw)>c_margin AND UNSIGNED(reg_address_cnt)>c_margin THEN 
-      v_burst_size := g_tech_ddr.maxburstsize+c_margin;
-      IF v_burst_size > UNSIGNED(reg_address_cnt) THEN v_burst_size := TO_UINT(reg_address_cnt); END IF;
-      IF v_burst_size > UNSIGNED(reg_wr_fifo_usedw) THEN v_burst_size := TO_UINT(reg_wr_fifo_usedw); END IF;
-      v_burst_size := v_burst_size - c_margin;
-    ELSE
-      v_burst_size := 1;
+    -- Access burst size is at least 1 and if more then set to the smallest of g_tech_ddr.maxburstsize and address_cnt
+    nxt_burst_size <= 1;
+    IF UNSIGNED(address_cnt) > 0 THEN
+      nxt_burst_size <= g_tech_ddr.maxburstsize;
+      IF UNSIGNED(address_cnt) < g_tech_ddr.maxburstsize THEN
+        nxt_burst_size <= TO_UINT(address_cnt);
+      END IF;
     END IF;
-    nxt_wr_burst_size <= v_burst_size;
-  END PROCESS;
-
-  p_rd_burst_size : PROCESS (reg_address_cnt)
-    VARIABLE v_burst_size : POSITIVE;
-  BEGIN 
-    -- Read burst size is at least 1 and if more then set to the smallest of g_tech_ddr.maxburstsize and address_cnt
-    IF UNSIGNED(reg_address_cnt)>0 THEN
-      v_burst_size := g_tech_ddr.maxburstsize;
-      IF v_burst_size > UNSIGNED(reg_address_cnt) THEN v_burst_size := TO_UINT(reg_address_cnt); END IF;
-    ELSE
-      v_burst_size := 1;
-    END IF;
-    nxt_rd_burst_size <= v_burst_size;
   END PROCESS;
   
   rd_src_out.valid <= ctlr_miso.rdval;
   rd_src_out.data <= RESIZE_DP_DATA(ctlr_miso.rddata);
   
   p_state : PROCESS(prev_state, state, ctlr_init_done,
-                    dvr_en, dvr_wr_not_rd, i_dvr_done, ctlr_miso, burst_wr_cnt, wr_snk_in, rd_src_in, 
-                    wr_fifo_usedw, wr_burst_size, rd_burst_size, reg_address_cnt, dvr_start_address, cur_address, address_cnt)
+                    dvr_en, dvr_wr_not_rd, ctlr_miso, wr_snk_in, rd_src_in, 
+                    burst_size, burst_wr_cnt, dvr_start_address, cur_address, address_cnt)
   BEGIN  
     nxt_state              <= state;
     
@@ -180,25 +141,26 @@ BEGIN
     
     wr_snk_out.ready       <= '0';
     nxt_burst_wr_cnt       <= burst_wr_cnt;    
-    nxt_dvr_done           <= i_dvr_done;
+    nxt_dvr_done           <= '0';
     nxt_cur_address        <= cur_address;
     nxt_address_cnt        <= address_cnt;
 
     CASE state IS
      
       WHEN s_wr_burst => -- Performs the burst portion (word 2+)        
-        ctlr_mosi.wr <= '1';        
         IF ctlr_miso.waitrequest_n = '1' THEN
-          nxt_burst_wr_cnt  <= INCR_UVEC(burst_wr_cnt, -1);
-          wr_snk_out.ready  <= '1';           -- wr side uses latency of 0, so wr_snk_out.ready<='1' acknowledges a successful write request.
-          IF UNSIGNED(burst_wr_cnt) = 1 THEN  -- check for the last cycle of this burst sequence
-            nxt_state <= s_wr_request;        -- initiate a new wr burst or goto idle via the wr_request state
+          IF wr_snk_in.valid = '1' THEN         -- it is allowed that valid is not always active during a burst
+            wr_snk_out.ready <= '1';            -- wr side uses latency of 0, so wr_snk_out.ready<='1' acknowledges a successful write request.
+            ctlr_mosi.wr     <= '1';
+            nxt_burst_wr_cnt <= INCR_UVEC(burst_wr_cnt, -1);
+            IF UNSIGNED(burst_wr_cnt) = 1 THEN  -- check for the last cycle of this burst sequence
+              nxt_state <= s_wr_request;        -- initiate a new wr burst or goto idle via the wr_request state
+            END IF;
           END IF;
         END IF;            
 
       WHEN s_wr_request =>  -- Performs 1 write access and goes into s_wr_burst when requested write words >1       
-        nxt_state <= s_wait3; 
-        IF UNSIGNED(reg_address_cnt) = 0 THEN -- end address reached
+        IF UNSIGNED(address_cnt) = 0 THEN -- end address reached
           nxt_dvr_done  <= '1';              
           nxt_state     <= s_idle;          
         ELSIF ctlr_miso.waitrequest_n = '1' THEN 
@@ -206,61 +168,57 @@ BEGIN
             -- Always perform 1st write here             
             wr_snk_out.ready     <= '1';
             ctlr_mosi.wr         <= '1';
-            ctlr_mosi.burstbegin <= '1';                                   -- assert burstbegin,
-            ctlr_mosi.burstsize  <= TO_DDR_CTLR_BURSTSIZE(wr_burst_size);  -- burstsize >= 1
-            IF wr_burst_size > 1 THEN
-              -- Perform any remaining writes in a burst
+            ctlr_mosi.burstbegin <= '1';                                -- assert burstbegin,
+            ctlr_mosi.burstsize  <= TO_DDR_CTLR_BURSTSIZE(burst_size);  -- burstsize >= 1
+            nxt_cur_address      <= INCR_UVEC(cur_address, burst_size);
+            nxt_address_cnt      <= INCR_UVEC(address_cnt, -burst_size);
+            -- Return for next wr request or perform any remaining writes in this burst
+            nxt_state <= s_wait; 
+            IF burst_size > 1 THEN
               nxt_state        <= s_wr_burst;
-              nxt_burst_wr_cnt <= TO_DDR_CTLR_BURSTSIZE(wr_burst_size-1); -- first burst wr cycle is done here, the rest are done in s_wr_burst
-            END IF; -- ELSE: there is only 1 word, so no need for remaining burst   
-            nxt_cur_address   <= INCR_UVEC(cur_address, wr_burst_size);
-            nxt_address_cnt   <= INCR_UVEC(address_cnt, -wr_burst_size);
+              nxt_burst_wr_cnt <= TO_DDR_CTLR_BURSTSIZE(burst_size-1);  -- first burst wr cycle is done here, the rest are done in s_wr_burst
+            END IF;
           END IF;
         END IF;        
 
       WHEN s_rd_request =>  -- Posts a read request for a burst (1...g_tech_ddr.maxburstsize)      
-        nxt_state <= s_wait3;   
-        IF UNSIGNED(reg_address_cnt) = 0 THEN -- end address reached
+        IF UNSIGNED(address_cnt) = 0 THEN -- end address reached
           nxt_dvr_done  <= '1';              
           nxt_state     <= s_idle;
         ELSE 
-          IF rd_src_in.ready = '1' THEN -- Fifo uses its internal almost_full signal to toggle its snk_out.rdy     
+          IF rd_src_in.ready = '1' THEN  -- the external FIFO uses almost full level assert its snk_out.ready and can then still accept the maximum rd burst of words
             IF ctlr_miso.waitrequest_n = '1' THEN    
               ctlr_mosi.rd         <= '1';                   
-              ctlr_mosi.burstbegin <= '1';                                   -- assert burstbegin,
-              ctlr_mosi.burstsize  <= TO_DDR_CTLR_BURSTSIZE(rd_burst_size);  -- burstsize >= 1
-              nxt_cur_address   <= INCR_UVEC(cur_address, rd_burst_size);  
-              nxt_address_cnt   <= INCR_UVEC(address_cnt, -rd_burst_size);
+              ctlr_mosi.burstbegin <= '1';                                -- assert burstbegin,
+              ctlr_mosi.burstsize  <= TO_DDR_CTLR_BURSTSIZE(burst_size);  -- burstsize >= 1
+              nxt_cur_address      <= INCR_UVEC(cur_address, burst_size);  
+              nxt_address_cnt      <= INCR_UVEC(address_cnt, -burst_size);
+              -- Return for next rd request
+              nxt_state <= s_wait;
             END IF;           
           END IF;
         END IF; 
 
-      -- This wait state is inserted between two requests when necessary, e.g. when FSM enters wr_request
-      -- from the state wr_request, an extra cycle is needed for reg_address_cnt to be valid.
-      WHEN s_wait3 =>
-        IF prev_state = s_wr_request THEN nxt_state <= s_wr_request; END IF;
-        IF prev_state = s_rd_request THEN nxt_state <= s_rd_request; END IF;
-   
-     -- In this cycle reg_address_cnt is valid. This cycle is added so wr_burst_size and rd_burst_size
-     -- (derived from reg_address_cnt) are valid the next cycle.
-     WHEN s_wait2 =>
-       IF dvr_wr_not_rd = '1' THEN
-         nxt_state <= s_wr_request; 
-       ELSE
-         nxt_state <= s_rd_request;             
-       END IF;
-      
-      -- Wait a cycle so reg_address_cnt is valid the next cyle.
-      WHEN s_wait1 =>
-        nxt_state <= s_wait2;
-
+      -- In this state address_cnt is valid and in the next state burst_size (that depends on address_cnt) will be valid.
+      -- Therefore this wait state is inserted between any requests.
+      WHEN s_wait =>
+        IF prev_state = s_wr_request THEN nxt_state <= s_wr_request; END IF;  -- between wr-wr burst requests
+        IF prev_state = s_rd_request THEN nxt_state <= s_rd_request; END IF;  -- between rd-rd burst requests
+        IF prev_state = s_idle THEN                                           -- between wr and rd accesses
+          IF dvr_wr_not_rd = '1' THEN
+            nxt_state <= s_wr_request;
+          ELSE
+            nxt_state <= s_rd_request;
+          END IF;
+        END IF;
+         
       WHEN s_idle =>
         nxt_dvr_done <= '1';    -- assert dvr_done after s_init or keep it asserted after a finished access
         IF dvr_en = '1' THEN  
           nxt_cur_address <= dvr_start_address; 
           nxt_address_cnt <= dvr_nof_data;
           nxt_dvr_done    <= '0';
-          nxt_state       <= s_wait1;
+          nxt_state       <= s_wait;
         END IF;
      
       WHEN OTHERS => -- s_init
-- 
GitLab