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