Skip to content
Snippets Groups Projects
Commit 1cace676 authored by Eric Kooistra's avatar Eric Kooistra
Browse files

No need to use wr_fifo_usedw, because snk_in.valid does not need to remain active during the burst.

parent cb55bd71
No related branches found
No related tags found
No related merge requests found
......@@ -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,
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment