From c873aa5c8d6baf0f250f06587a283f33c109e27a Mon Sep 17 00:00:00 2001
From: Erik Kooistra <kooistra@astron.nl>
Date: Tue, 6 Jan 2015 13:41:41 +0000
Subject: [PATCH] Use ctlr slv address instead of record address. Separate
 p_burst_size into wr and rd process and define burstsize as positive. Assign
 ctlr_mosi.burstsize directly using wr/rd_burst_size, no need for
 ctlr_mosi_burstsize.

---
 libraries/io/ddr/src/vhdl/io_ddr_driver.vhd | 142 ++++++++++----------
 1 file changed, 68 insertions(+), 74 deletions(-)

diff --git a/libraries/io/ddr/src/vhdl/io_ddr_driver.vhd b/libraries/io/ddr/src/vhdl/io_ddr_driver.vhd
index a72a4caf1f..9ec26e0e02 100644
--- a/libraries/io/ddr/src/vhdl/io_ddr_driver.vhd
+++ b/libraries/io/ddr/src/vhdl/io_ddr_driver.vhd
@@ -22,9 +22,17 @@
 
 -- Purpose: Provide streaming interface to DDR memory
 -- Description:
---   Write or read a block of data to or from DDR memory. The block of data is
---   located from dvr_start_addr to dvr_end_addr. The io_ddr_driver takes care
---   that the access is done in a number of bursts.
+--   Write or read a block of data to or from DDR memory. The data width is set
+--   by the DDR controller data width given by RESIZE_DDR_CTLR_DATA() and eg.
+--   256 bits for DDR3 with 64 bit DQ data. The block of data is located from
+--   dvr_start_addr to dvr_end_addr.
+--   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.
+-- Remarks:
+-- . 
 
 LIBRARY IEEE, tech_ddr_lib, common_lib, dp_lib;
 USE IEEE.STD_LOGIC_1164.ALL;
@@ -43,8 +51,8 @@ ENTITY io_ddr_driver IS
 
     dvr_en             : IN  STD_LOGIC := '1';
     dvr_wr_not_rd      : IN  STD_LOGIC;       
-    dvr_start_addr     : IN  t_tech_ddr_addr;
-    dvr_end_addr       : IN  t_tech_ddr_addr;
+    dvr_start_address  : IN  STD_LOGIC_VECTOR;
+    dvr_end_address    : IN  STD_LOGIC_VECTOR;
     dvr_done           : OUT STD_LOGIC;         -- Requested wr or rd sequence is done.
    
     wr_fifo_usedw      : IN  STD_LOGIC_VECTOR;
@@ -63,7 +71,7 @@ END io_ddr_driver;
 
 ARCHITECTURE str OF io_ddr_driver IS
 
-  CONSTANT c_address_w          : NATURAL := func_tech_ddr_dq_address_w(g_tech_ddr) + 1;  -- 1 bit added to detect overflow
+  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 
@@ -85,27 +93,21 @@ ARCHITECTURE str OF io_ddr_driver IS
   SIGNAL nxt_wr_burst_size      : NATURAL;
   SIGNAL nxt_rd_burst_size      : NATURAL;
 
-  SIGNAL ctlr_mosi_burstsize    : STD_LOGIC_VECTOR(c_tech_ddr_ctlr_burstsize_w-1 DOWNTO 0);
-
   SIGNAL i_dvr_done             : STD_LOGIC;
   SIGNAL nxt_dvr_done           : STD_LOGIC;
 
-  SIGNAL start_address          : STD_LOGIC_VECTOR(c_address_w-1 DOWNTO 0);
-  SIGNAL end_address            : STD_LOGIC_VECTOR(c_address_w-1 DOWNTO 0);
- 
-  SIGNAL cur_addr               : t_tech_ddr_addr; 
-  SIGNAL cur_address            : STD_LOGIC_VECTOR(c_address_w-1 DOWNTO 0);
-  SIGNAL nxt_cur_address        : STD_LOGIC_VECTOR(c_address_w-1 DOWNTO 0);   
-  SIGNAL diff_address           : STD_LOGIC_VECTOR(c_address_w-1 DOWNTO 0);
+  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 diff_address           : STD_LOGIC_VECTOR(c_ctlr_address_w-1 DOWNTO 0);
 
-  SIGNAL addresses_rem          : STD_LOGIC_VECTOR(31 DOWNTO 0); -- nof words (on the user side interface) to rd/wr until end addr is reached
-  SIGNAL reg_addresses_rem      : STD_LOGIC_VECTOR(31 DOWNTO 0); -- nof words (on the user side interface) to rd/wr until end addr is reached
+  SIGNAL addresses_rem          : STD_LOGIC_VECTOR(c_ctlr_address_w-1 DOWNTO 0); -- nof words (on the user side interface) to rd/wr until end addr is reached
+  SIGNAL reg_addresses_rem      : STD_LOGIC_VECTOR(c_ctlr_address_w-1 DOWNTO 0); -- nof words (on the user side interface) to rd/wr until end addr is reached
 
   SIGNAL reg_wr_fifo_usedw      : STD_LOGIC_VECTOR(wr_fifo_usedw'RANGE);  -- read side depth of the write FIFO
 
 BEGIN
 
-  dvr_done        <= i_dvr_done; 
+  dvr_done <= i_dvr_done; 
 
   p_clk : PROCESS(rst, clk)
   BEGIN
@@ -132,59 +134,58 @@ BEGIN
     END IF;
   END PROCESS;
 
-  -- Record address --> slv address
-  start_address <= func_tech_ddr_dq_address(dvr_start_addr, g_tech_ddr, c_address_w);
-  end_address   <= func_tech_ddr_dq_address(dvr_end_addr,   g_tech_ddr, c_address_w);
-  
-  -- Add 1 address (accounting for address resulotion) to diff_address: we also want to write the last address. Shift the result right to provide the correct resolution.
-  addresses_rem <= RESIZE_UVEC( SHIFT_UVEC( INCR_UVEC(diff_address, g_tech_ddr.rsl), g_tech_ddr.rsl_w), addresses_rem'LENGTH); 
-  
   -- End address - current address
-  diff_address  <= SUB_UVEC(end_address, cur_address, c_address_w);
+  diff_address  <= SUB_UVEC(dvr_end_address, cur_address);
 
-  p_burst_size : PROCESS (reg_addresses_rem, reg_wr_fifo_usedw)
-    VARIABLE v_burst_size : NATURAL;
+  -- Add 1 to diff_address to also write the last address
+  addresses_rem <= INCR_UVEC(diff_address, 1); 
+  
+  p_wr_burst_size : PROCESS (reg_addresses_rem, reg_wr_fifo_usedw)
+    VARIABLE v_burst_size : POSITIVE;
   BEGIN 
-    -- Write burst size is smallest of g_tech_ddr.maxburstsize, addresses_rem and wr_fifo_usedw
-    v_burst_size := g_tech_ddr.maxburstsize+c_margin;
-    IF UNSIGNED(reg_wr_fifo_usedw)>=c_margin AND UNSIGNED(reg_addresses_rem)>=c_margin THEN 
-      IF v_burst_size > SIGNED('0' & reg_addresses_rem) THEN v_burst_size := TO_UINT(reg_addresses_rem); END IF;
-      IF v_burst_size > SIGNED('0' & reg_wr_fifo_usedw) THEN v_burst_size := TO_UINT(reg_wr_fifo_usedw); END IF;
+    -- Write burst size at least 1 and if more then set to the smallest of g_tech_ddr.maxburstsize, addresses_rem and wr_fifo_usedw
+    IF UNSIGNED(reg_wr_fifo_usedw)>c_margin AND UNSIGNED(reg_addresses_rem)>c_margin THEN 
+      v_burst_size := g_tech_ddr.maxburstsize+c_margin;
+      IF v_burst_size > UNSIGNED(reg_addresses_rem) THEN v_burst_size := TO_UINT(reg_addresses_rem); 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 := 0;
+      v_burst_size := 1;
     END IF;
     nxt_wr_burst_size <= v_burst_size;
+  END PROCESS;
 
-    -- Read burst size is smallest of g_tech_ddr.maxburstsize and addresses_rem
-    v_burst_size := g_tech_ddr.maxburstsize;
-    IF UNSIGNED(reg_addresses_rem)>=1 THEN -- prevent assigning <0 value to natural
-      IF v_burst_size > SIGNED('0' & reg_addresses_rem) THEN v_burst_size := TO_UINT(reg_addresses_rem); END IF;
+  p_rd_burst_size : PROCESS (reg_addresses_rem)
+    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 addresses_rem
+    IF UNSIGNED(reg_addresses_rem)>0 THEN
+      v_burst_size := g_tech_ddr.maxburstsize;
+      IF v_burst_size > UNSIGNED(reg_addresses_rem) THEN v_burst_size := TO_UINT(reg_addresses_rem); END IF;
     ELSE
-      v_burst_size := 0;
+      v_burst_size := 1;
     END IF;
     nxt_rd_burst_size <= v_burst_size;
   END PROCESS;
-
-  cur_addr <= func_tech_ddr_dq_address(cur_address, g_tech_ddr);
-
-  ctlr_mosi.address <= func_tech_ddr_ctlr_address(cur_addr, g_tech_ddr, c_tech_ddr_ctlr_address_w);
-  ctlr_mosi.wrdata <= RESIZE_DDR_CTLR_DATA(wr_snk_in.data);
-  ctlr_mosi.burstsize <= ctlr_mosi_burstsize;
-
+  
   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_mosi_burstsize, ctlr_miso, req_burst_cycles, wr_snk_in, rd_src_in, 
-                    wr_fifo_usedw, wr_burst_size, rd_burst_size, reg_addresses_rem, start_address, cur_address)
+  p_state : PROCESS(prev_state, state, ctlr_init_done,
+                    dvr_en, dvr_wr_not_rd, i_dvr_done, ctlr_miso, req_burst_cycles, wr_snk_in, rd_src_in, 
+                    wr_fifo_usedw, wr_burst_size, rd_burst_size, reg_addresses_rem, dvr_start_address, cur_address)
   BEGIN  
-    nxt_state              <= state;   
+    nxt_state              <= state;
+    
+    ctlr_mosi.address      <= RESIZE_DDR_CTLR_ADDRESS(cur_address);
+    ctlr_mosi.wrdata       <= RESIZE_DDR_CTLR_DATA(wr_snk_in.data);
     ctlr_mosi.wr           <= '0';
     ctlr_mosi.rd           <= '0';
     ctlr_mosi.burstbegin   <= '0'; 
-    ctlr_mosi_burstsize    <= (OTHERS => '0');
-    nxt_req_burst_cycles   <= req_burst_cycles;
+    ctlr_mosi.burstsize    <= (OTHERS => '0');
+    
     wr_snk_out.ready       <= '0';
+    nxt_req_burst_cycles   <= req_burst_cycles;    
     nxt_dvr_done           <= i_dvr_done;
     nxt_cur_address        <= cur_address;
 
@@ -192,11 +193,11 @@ BEGIN
      
       WHEN s_wr_burst => -- Performs the burst portion (word 2+)        
         ctlr_mosi.wr <= '1';        
-        IF ctlr_miso.waitrequest_n = '1' THEN -- when local_ready goes low, that cycle does not count as a burst cycle          
-          nxt_req_burst_cycles <= INCR_UVEC(req_burst_cycles, -1);
-          wr_snk_out.ready     <= '1'; -- wr side uses latency of 0, so wr_snk_out.ready<='1' acknowledges a successful write request.
+        IF ctlr_miso.waitrequest_n = '1' THEN
+          nxt_req_burst_cycles  <= INCR_UVEC(req_burst_cycles, -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(req_burst_cycles) = 1 THEN -- Then we're in the last cycle of this burst sequence
-            nxt_state <= s_wr_request; -- We can only initiate a burst through the wr_request state
+            nxt_state <= s_wr_request; -- We can only initiate a new burst through the wr_request state
           END IF;
         END IF;            
 
@@ -210,22 +211,18 @@ BEGIN
             -- Always perform 1st write here             
             wr_snk_out.ready     <= '1';
             ctlr_mosi.wr         <= '1';
-            ctlr_mosi.burstbegin <= '1'; -- assert burst begin: strictly this is a burst of 1. 
-            ctlr_mosi_burstsize  <= TO_DDR_CTLR_BURSTSIZE(1); -- Set ctlr_mosi_burstsize to 1 by default
+            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
               nxt_state            <= s_wr_burst;
-              nxt_req_burst_cycles <= TO_DDR_CTLR_BURSTSIZE(wr_burst_size-1); -- Forward the required nof burst cycles (-1 as we've done the 1st in this state already) to burst state
-              ctlr_mosi_burstsize  <= TO_DDR_CTLR_BURSTSIZE(wr_burst_size  );
+              nxt_req_burst_cycles <= 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, UNSIGNED(ctlr_mosi_burstsize)*g_tech_ddr.rsl);
---            IF UNSIGNED(ctlr_mosi_burstsize) = 1 THEN -- Prevents FSM from going into this state again too soon (reg_addresses_rem invalid)
---            nxt_state <= s_wait3; 
---            END IF;
+            nxt_cur_address   <= INCR_UVEC(cur_address, wr_burst_size);
           END IF;
         END IF;        
 
-      WHEN s_rd_request => -- Posts a read request for a burst (0...g_tech_ddr.maxburstsize)      
+      WHEN s_rd_request =>  -- Posts a read request for a burst (1...g_tech_ddr.maxburstsize)      
         nxt_state <= s_wait3;   
         IF UNSIGNED(reg_addresses_rem) = 0 THEN -- end address reached
           nxt_dvr_done  <= '1';              
@@ -234,13 +231,9 @@ BEGIN
           IF rd_src_in.ready = '1' THEN -- Fifo uses its internal almost_full signal to toggle its snk_out.rdy     
             IF ctlr_miso.waitrequest_n = '1' THEN    
               ctlr_mosi.rd         <= '1';                   
-              ctlr_mosi.burstbegin <= '1'; -- assert burst begin: strictly this is a burst of 1.                  
-              ctlr_mosi_burstsize  <= TO_DDR_CTLR_BURSTSIZE(rd_burst_size);
-              IF rd_burst_size = 0 THEN ctlr_mosi_burstsize <= TO_DDR_CTLR_BURSTSIZE(1); END IF;
-              nxt_cur_address   <= INCR_UVEC(cur_address, UNSIGNED(ctlr_mosi_burstsize)*g_tech_ddr.rsl);  
---              IF UNSIGNED(ctlr_mosi_burstsize) = 1 THEN -- Prevents FSM from going into this state again too soon (reg_addresses_rem invalid)
---              nxt_state <= s_wait3; 
---              END IF;
+              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);  
             END IF;           
           END IF;
         END IF; 
@@ -265,16 +258,17 @@ BEGIN
         nxt_state <= s_wait2;
 
       WHEN s_idle =>
-        nxt_dvr_done <= '1';
+        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 <= start_address; 
+          nxt_cur_address <= dvr_start_address; 
           nxt_dvr_done    <= '0';
           nxt_state       <= s_wait1;
         END IF;
      
       WHEN OTHERS => -- s_init
+        nxt_dvr_done <= '0';
         IF ctlr_init_done = '1' THEN
-          nxt_state <= s_idle;  -- and assert dvr_done when in s_idle
+          nxt_state <= s_idle;  -- and assert dvr_done when in s_idle to indicate ctlr_init_done
         END IF;
       
     END CASE;
-- 
GitLab