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

Use ctlr slv address instead of record address. Separate p_burst_size into wr...

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.
parent 19926973
No related branches found
No related tags found
No related merge requests found
......@@ -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;
......
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