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

Redefined write flush modes. Now the flush is still under control by...

Redefined write flush modes. Now the flush is still under control by dvr_flush_en, and disabled when kept tied to '0'.
parent 13071b9e
No related branches found
No related tags found
No related merge requests found
...@@ -33,15 +33,14 @@ ENTITY io_ddr IS ...@@ -33,15 +33,14 @@ ENTITY io_ddr IS
g_technology : NATURAL := c_tech_select_default; g_technology : NATURAL := c_tech_select_default;
g_tech_ddr : t_c_tech_ddr; g_tech_ddr : t_c_tech_ddr;
g_wr_data_w : NATURAL := 32; g_wr_data_w : NATURAL := 32;
g_wr_use_ctrl : BOOLEAN := FALSE; -- TRUE to allow filling the WR FIFO (by disabling flush) after an EOP g_wr_use_ctrl : BOOLEAN := FALSE; -- TRUE to allow filling the write FIFO by disabling flush after an EOP
g_wr_fifo_depth : NATURAL := 128; -- >=16 AND >g_tech_ddr.maxburstsize , defined at read side of write FIFO. g_wr_fifo_depth : NATURAL := 128; -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO.
g_rd_fifo_depth : NATURAL := 256; -- >=16 AND >g_tech_ddr.maxburstsize > c_ddr_ctlr_nof_latent_reads, defined at write side of read FIFO. g_rd_fifo_depth : NATURAL := 256; -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO.
g_rd_data_w : NATURAL := 32; g_rd_data_w : NATURAL := 32;
g_flush_wr_fifo : BOOLEAN := FALSE; -- TRUE instantiates a dp_flush + controller to flush the write fifo when the driver is not ready to write g_flush_mode : STRING := "VALID"; -- "VALID", "SOP", "SYNC"
g_flush_sop : BOOLEAN := FALSE; g_flush_use_channel : BOOLEAN := FALSE;
g_flush_sop_channel : BOOLEAN := FALSE; g_flush_start_channel : NATURAL := 0;
g_flush_sop_start_channel : NATURAL := 0; g_flush_nof_channels : POSITIVE := 1
g_flush_nof_channels : NATURAL := 0
); );
PORT ( PORT (
-- DDR reference clock -- DDR reference clock
...@@ -63,6 +62,7 @@ ENTITY io_ddr IS ...@@ -63,6 +62,7 @@ ENTITY io_ddr IS
dvr_start_addr : IN t_tech_ddr_addr; dvr_start_addr : IN t_tech_ddr_addr;
dvr_end_addr : IN t_tech_ddr_addr; dvr_end_addr : IN t_tech_ddr_addr;
dvr_done : OUT STD_LOGIC; dvr_done : OUT STD_LOGIC;
dvr_flush_en : IN STD_LOGIC := '0';
-- Write FIFO clock domain -- Write FIFO clock domain
wr_clk : IN STD_LOGIC; wr_clk : IN STD_LOGIC;
...@@ -90,22 +90,20 @@ END io_ddr; ...@@ -90,22 +90,20 @@ END io_ddr;
ARCHITECTURE str OF io_ddr IS ARCHITECTURE str OF io_ddr IS
CONSTANT c_ctlr_data_w : NATURAL := func_tech_ddr_ctlr_data_w( g_tech_ddr); CONSTANT c_ctlr_data_w : NATURAL := func_tech_ddr_ctlr_data_w(g_tech_ddr);
CONSTANT c_wr_fifo_depth : NATURAL := g_wr_fifo_depth * (c_ctlr_data_w/g_wr_data_w); -- Multiply fifo depth by the fifo's rd/wr width ratio to get write side depth CONSTANT c_wr_fifo_depth : NATURAL := g_wr_fifo_depth * (c_ctlr_data_w/g_wr_data_w); -- get FIFO depth at write side
CONSTANT c_ddr_ctlr_nof_latent_reads : NATURAL := 100; -- Due to having a command cue, even after de-asserting read requests, the PHY keeps processing the cued read requests.
-- This makes sure 100 words are still available in the read FIFO after it de-asserted its siso.ready signal towards the ddr3 read side.
CONSTANT c_latency : NATURAL := 1;
CONSTANT c_wr_fifo_af_margin : NATURAL := 4 + 1; -- use +1 to compensate for latency introduced by registering wr_siso.ready due to RL=0
CONSTANT c_rd_fifo_af_margin : NATURAL := 4 + g_tech_ddr.maxburstsize; -- use ctlr_rd_src_in.ready to only start new rd access when there is sufficient space in the read FIFO
SIGNAL i_ctlr_init_done : STD_LOGIC; SIGNAL i_ctlr_init_done : STD_LOGIC;
SIGNAL i_dvr_done : STD_LOGIC; SIGNAL i_dvr_done : STD_LOGIC;
SIGNAL ctlr_mosi : t_tech_ddr_mosi := c_tech_ddr_mosi_rst; SIGNAL ctlr_mosi : t_tech_ddr_mosi := c_tech_ddr_mosi_rst;
SIGNAL ctlr_miso : t_tech_ddr_miso := c_tech_ddr_miso_rst; SIGNAL ctlr_miso : t_tech_ddr_miso := c_tech_ddr_miso_rst;
SIGNAL dvr_flush : STD_LOGIC := '0'; SIGNAL wr_flush : STD_LOGIC := '0';
SIGNAL ctlr_wr_snk_out : t_dp_siso := c_dp_siso_rdy; -- default xon='1' SIGNAL ctlr_wr_snk_out : t_dp_siso := c_dp_siso_rdy; -- default xon='1'
SIGNAL ctlr_wr_snk_in : t_dp_sosi := c_dp_sosi_rst; SIGNAL ctlr_wr_snk_in : t_dp_sosi := c_dp_sosi_rst;
...@@ -130,7 +128,7 @@ BEGIN ...@@ -130,7 +128,7 @@ BEGIN
g_rd_data_w => c_ctlr_data_w, g_rd_data_w => c_ctlr_data_w,
g_use_ctrl => g_wr_use_ctrl, g_use_ctrl => g_wr_use_ctrl,
g_wr_fifo_size => c_wr_fifo_depth, g_wr_fifo_size => c_wr_fifo_depth,
g_wr_fifo_af_margin => 4 + c_latency, --default (4) + c_latency to compensate for latency introduced by registering wr_siso.ready g_wr_fifo_af_margin => c_wr_fifo_af_margin,
g_rd_fifo_rl => 0 g_rd_fifo_rl => 0
) )
PORT MAP ( PORT MAP (
...@@ -150,11 +148,11 @@ BEGIN ...@@ -150,11 +148,11 @@ BEGIN
src_out => flush_wr_sosi src_out => flush_wr_sosi
); );
u_dp_flush : ENTITY dp_lib.dp_flush -- Always instantiate the flusher as it also contains a RL adapter u_dp_flush : ENTITY dp_lib.dp_flush
GENERIC MAP ( GENERIC MAP (
g_ready_latency => 0, g_ready_latency => 0,
g_framed_xon => g_wr_use_ctrl, -- stop flushing when dvr_flush is low and a sop has arrived g_framed_xon => g_wr_use_ctrl, -- stop flushing when wr_flush is low and a sop has arrived
g_framed_xoff => FALSE -- immediately start flushing when dvr_flush goes high g_framed_xoff => FALSE -- immediately start flushing when wr_flush goes high
) )
PORT MAP ( PORT MAP (
rst => ctlr_rst_in, rst => ctlr_rst_in,
...@@ -166,30 +164,29 @@ BEGIN ...@@ -166,30 +164,29 @@ BEGIN
src_out => ctlr_wr_snk_in, src_out => ctlr_wr_snk_in,
src_in => ctlr_wr_snk_out, src_in => ctlr_wr_snk_out,
flush_en => dvr_flush flush_en => wr_flush
); );
gen_io_ddr_driver_flush_ctrl : IF g_flush_wr_fifo = TRUE GENERATE u_io_ddr_driver_flush_ctrl : ENTITY work.io_ddr_driver_flush_ctrl
u_io_ddr_driver_flush_ctrl : ENTITY work.io_ddr_driver_flush_ctrl GENERIC MAP (
GENERIC MAP ( g_mode => g_flush_mode,
g_sop => g_flush_sop, g_use_channel => g_flush_use_channel,
g_sop_channel => g_flush_sop_channel, g_start_channel => g_flush_start_channel,
g_sop_start_channel => g_flush_sop_start_channel, g_nof_channels => g_flush_nof_channels
g_nof_channels => g_flush_nof_channels )
) PORT MAP (
PORT MAP ( rst => wr_rst,
rst => wr_rst, clk => wr_clk,
clk => wr_clk,
dvr_flush_en => dvr_flush_en,
dvr_en => dvr_en, dvr_en => dvr_en,
dvr_wr_not_rd => dvr_wr_not_rd, dvr_wr_not_rd => dvr_wr_not_rd,
dvr_done => i_dvr_done, dvr_done => i_dvr_done,
wr_sosi => wr_sosi, wr_sosi => wr_sosi,
dvr_flush => dvr_flush wr_flush => wr_flush
); );
END GENERATE;
u_rd_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths u_rd_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths
GENERIC MAP ( GENERIC MAP (
...@@ -197,7 +194,7 @@ BEGIN ...@@ -197,7 +194,7 @@ BEGIN
g_rd_data_w => g_rd_data_w, g_rd_data_w => g_rd_data_w,
g_use_ctrl => FALSE, g_use_ctrl => FALSE,
g_wr_fifo_size => g_rd_fifo_depth, g_wr_fifo_size => g_rd_fifo_depth,
g_wr_fifo_af_margin => c_ddr_ctlr_nof_latent_reads, -- >=4 (required by dp_fifo) g_wr_fifo_af_margin => c_rd_fifo_af_margin, -- >=4 (required by dp_fifo)
g_rd_fifo_rl => 1 g_rd_fifo_rl => 1
) )
PORT MAP ( PORT MAP (
......
...@@ -18,7 +18,20 @@ ...@@ -18,7 +18,20 @@
-- You should have received a copy of the GNU General Public License -- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>. -- along with this program. If not, see <http://www.gnu.org/licenses/>.
-- --
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Purpose: Flush the write input FIFO in io_ddr when not doing a write access.
-- Description:
-- The write input FIFO is flushed by when the io_ddr is not doing a write
-- access, so when idle or also when doing a read access.
-- When the io_ddr is starting a new write access, then the write input FIFO
-- gets filled. The filling starts dependent on:
--
-- . g_mode = "VALID" : immediately start filling on next valid data
-- . g_mode = "SOP" : start filling on next sop
-- . g_mode = "SYNC" : start filling on next sync
--
-- . g_use_channel = TRUE : start filling when channel matches g_start_channel
LIBRARY IEEE, common_lib, dp_lib; LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_1164.ALL;
...@@ -28,23 +41,23 @@ USE dp_lib.dp_stream_pkg.ALL; ...@@ -28,23 +41,23 @@ USE dp_lib.dp_stream_pkg.ALL;
ENTITY io_ddr_driver_flush_ctrl IS ENTITY io_ddr_driver_flush_ctrl IS
GENERIC ( GENERIC (
g_sop : BOOLEAN := FALSE; -- Stop flushing on SOP, otherwise stop flushing on valid data g_mode : STRING := "VALID"; -- "VALID", "SOP", "SYNC"
g_sop_channel : BOOLEAN := FALSE; -- When g_sop=TRUE, also check if the channel matches g_sop_start_channel g_use_channel : BOOLEAN := FALSE;
g_sop_start_channel : NATURAL := 0; g_start_channel : NATURAL := 0;
g_nof_channels : NATURAL := 0 g_nof_channels : POSITIVE := 1
); );
PORT ( PORT (
clk : IN STD_LOGIC; clk : IN STD_LOGIC;
rst : IN STD_LOGIC; rst : IN STD_LOGIC;
dvr_flush_en : IN STD_LOGIC := '1';
dvr_en : IN STD_LOGIC := '1'; dvr_en : IN STD_LOGIC := '1';
dvr_wr_not_rd : IN STD_LOGIC; dvr_wr_not_rd : IN STD_LOGIC;
dvr_done : IN STD_LOGIC; dvr_done : IN STD_LOGIC;
wr_sosi : IN t_dp_sosi; wr_sosi : IN t_dp_sosi;
dvr_flush : OUT STD_LOGIC wr_flush : OUT STD_LOGIC
); );
END io_ddr_driver_flush_ctrl; END io_ddr_driver_flush_ctrl;
...@@ -58,27 +71,25 @@ ARCHITECTURE str OF io_ddr_driver_flush_ctrl IS ...@@ -58,27 +71,25 @@ ARCHITECTURE str OF io_ddr_driver_flush_ctrl IS
SIGNAL state : t_state; SIGNAL state : t_state;
SIGNAL nxt_state : t_state; SIGNAL nxt_state : t_state;
SIGNAL channel : NATURAL RANGE 0 TO g_nof_channels-1;
SIGNAL flush_dis : STD_LOGIC; SIGNAL flush_dis : STD_LOGIC;
BEGIN BEGIN
-- Flush ddr3 module's FIFO (keep sinking the stream but simply discard the -- Flush disable control
-- data) after reset to prevent ddr3 write fifo from filling up - which would no_channel: IF g_use_channel=FALSE GENERATE
-- cause problems downstream (dp_mux uses two fifos that cannot be gen_valid : IF g_mode="VALID" GENERATE flush_dis <= wr_sosi.valid; END GENERATE;
-- allowed to fill up too much). gen_sop : IF g_mode="SOP" GENERATE flush_dis <= wr_sosi.sop ; END GENERATE;
-- Also flush the ddr3 module's FIFO when it is reading. gen_sync : IF g_mode="SYNC" GENERATE flush_dis <= wr_sosi.sync ; END GENERATE;
gen_sop : IF g_sop = TRUE GENERATE -- Disable flushing on arrival of SOP
gen_sop_only: IF g_sop_channel = FALSE GENERATE
flush_dis <= '1' WHEN wr_sosi.sop='1' ELSE '0';
END GENERATE;
gen_channel : IF g_sop_channel = TRUE GENERATE -- Only disable flushing on arrival of specific channel SOP
flush_dis <= '1' WHEN wr_sosi.sop='1' AND UNSIGNED(wr_sosi.channel(c_channel_w-1 DOWNTO 0))=g_sop_start_channel ELSE '0';
END GENERATE;
END GENERATE; END GENERATE;
gen_val : IF g_sop = FALSE GENERATE -- Disable flushing on arrival of 1st valid data use_channel: IF g_use_channel=TRUE GENERATE
flush_dis <= wr_sosi.valid; channel <= TO_UINT(wr_sosi.channel(c_channel_w-1 DOWNTO 0));
gen_valid : IF g_mode="VALID" GENERATE flush_dis <= '1' WHEN wr_sosi.valid='1' AND channel=g_start_channel ELSE '0'; END GENERATE;
gen_sop : IF g_mode="SOP" GENERATE flush_dis <= '1' WHEN wr_sosi.sop ='1' AND channel=g_start_channel ELSE '0'; END GENERATE;
gen_sync : IF g_mode="SYNC" GENERATE flush_dis <= '1' WHEN wr_sosi.sync ='1' AND channel=g_start_channel ELSE '0'; END GENERATE;
END GENERATE; END GENERATE;
p_reg : PROCESS(rst, clk) p_reg : PROCESS(rst, clk)
...@@ -90,23 +101,23 @@ BEGIN ...@@ -90,23 +101,23 @@ BEGIN
END IF; END IF;
END PROCESS; END PROCESS;
p_state : PROCESS(state, dvr_done, dvr_en, dvr_wr_not_rd, flush_dis) p_state : PROCESS(state, dvr_flush_en, dvr_done, dvr_en, dvr_wr_not_rd, flush_dis)
BEGIN BEGIN
nxt_state <= state; nxt_state <= state;
dvr_flush <= '0'; wr_flush <= '0';
CASE state IS CASE state IS
WHEN s_idle => WHEN s_idle =>
IF dvr_done='1' THEN IF dvr_flush_en='1' AND dvr_done='1' THEN
dvr_flush <= '1'; wr_flush <= '1';
nxt_state <= s_flush; nxt_state <= s_flush;
END IF; END IF;
WHEN s_flush => WHEN s_flush =>
dvr_flush <= '1'; wr_flush <= '1';
IF dvr_en='1' AND dvr_wr_not_rd='1' THEN IF dvr_en='1' AND dvr_wr_not_rd='1' THEN
nxt_state <= s_stop; nxt_state <= s_stop;
END IF; END IF;
WHEN OTHERS => -- s_stop WHEN OTHERS => -- s_stop
dvr_flush <= '1'; wr_flush <= '1';
IF flush_dis = '1' THEN IF flush_dis = '1' THEN
nxt_state <= s_idle; nxt_state <= s_idle;
END IF; END IF;
......
...@@ -89,7 +89,8 @@ ARCHITECTURE str of tb_io_ddr IS ...@@ -89,7 +89,8 @@ ARCHITECTURE str of tb_io_ddr IS
SIGNAL dvr_en : STD_LOGIC; SIGNAL dvr_en : STD_LOGIC;
SIGNAL dvr_wr_not_rd : STD_LOGIC; SIGNAL dvr_wr_not_rd : STD_LOGIC;
SIGNAL dvr_done : STD_LOGIC; SIGNAL dvr_done : STD_LOGIC;
SIGNAL dvr_flush_en : STD_LOGIC := '0';
SIGNAL wr_siso : t_dp_siso; SIGNAL wr_siso : t_dp_siso;
SIGNAL wr_sosi : t_dp_sosi; SIGNAL wr_sosi : t_dp_sosi;
...@@ -135,6 +136,9 @@ BEGIN ...@@ -135,6 +136,9 @@ BEGIN
src_diag_en <= '1'; src_diag_en <= '1';
snk_diag_en <= '1'; snk_diag_en <= '1';
-- When dvr_flush_en='0' then the write FIFO is flushed until the first write access is started
proc_common_wait_some_cycles(ctlr_clk, 100);
FOR I IN c_address_lo_arr'RANGE LOOP FOR I IN c_address_lo_arr'RANGE LOOP
v_addr_lo := func_tech_ddr_dq_address(TO_DDR_CTLR_ADDRESS(4*c_address_lo_arr(I)) , c_tech_ddr); v_addr_lo := func_tech_ddr_dq_address(TO_DDR_CTLR_ADDRESS(4*c_address_lo_arr(I)) , c_tech_ddr);
v_addr_hi := func_tech_ddr_dq_address(TO_DDR_CTLR_ADDRESS(4*c_address_lo_arr(I)+4*c_nof_address_arr(I)-1), c_tech_ddr); v_addr_hi := func_tech_ddr_dq_address(TO_DDR_CTLR_ADDRESS(4*c_address_lo_arr(I)+4*c_nof_address_arr(I)-1), c_tech_ddr);
...@@ -217,7 +221,8 @@ BEGIN ...@@ -217,7 +221,8 @@ BEGIN
dvr_done => dvr_done, dvr_done => dvr_done,
dvr_start_addr => dvr_start_addr, dvr_start_addr => dvr_start_addr,
dvr_end_addr => dvr_end_addr, dvr_end_addr => dvr_end_addr,
dvr_flush_en => dvr_flush_en,
wr_clk => dp_clk, wr_clk => dp_clk,
wr_rst => dp_rst, wr_rst => dp_rst,
......
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