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

Added io_ddr_cross_domain.vhd to handle dvr_clk and ctlr_clk domains in case...

Added io_ddr_cross_domain.vhd to handle dvr_clk and ctlr_clk domains in case they are different clock domains.
parent 53a97fb1
Branches
No related tags found
No related merge requests found
...@@ -12,6 +12,7 @@ modelsim_compile_ip_files = ...@@ -12,6 +12,7 @@ modelsim_compile_ip_files =
synth_files = synth_files =
src/vhdl/io_ddr_driver_flush_ctrl.vhd src/vhdl/io_ddr_driver_flush_ctrl.vhd
src/vhdl/io_ddr_driver.vhd src/vhdl/io_ddr_driver.vhd
src/vhdl/io_ddr_cross_domain.vhd
src/vhdl/io_ddr.vhd src/vhdl/io_ddr.vhd
test_bench_files = test_bench_files =
......
...@@ -18,46 +18,80 @@ ...@@ -18,46 +18,80 @@
-- 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: Provide streaming interface to DDR memory -- Purpose: Provide streaming interface to DDR memory
-- Description: -- Description:
-- --
-- dvr_wr_fifo_usedw <----------------\ -- The write FIFO and read FIFO take care of the clock domain crossing that
-- is needed if the ctlr_clk is not used for the data path. Furthermore the
-- FIFO takes care of repacking the user write and read data into the
-- typically wider data width c_ctlr_data_w = 256 for DDR3.
--
-- The DDR access starts after a dvr_en pulse. The access can be write or
-- read as defined by dvr_wr_not_rd. The size of the access depends the
-- address range given by dvr_start_addr and dvr_end_addr. The dvr_done goes
-- high when the access has finished and it goes low when a new access
-- starts.
--
-- The dvr_wr_flush_en pulse is recognized only between DDR accesses so when
-- the dvr_done is active, otherwise the dvr_wr_flush_en is ignored. The
-- dvr_wr_flush_en pulse can be used to flush the write FIFO to avoid that is
-- runs full in case a next write access will not happen soon enough. A next
-- DDR write access can start on the next valid, sop or sync dependent on
-- g_wr_flush_mode.
--
-- Block diagram:
--
-- dvr_wr_fifo_usedw <-*-------------------\
-- | -- |
-- wr_sosi wr_fifo_src | ctlr_wr_snk ctlr_mosi -- ctlr_wr_fifo_src | ctlr_wr_snk ctlr_mosi
-- . . | . . -- . | . .
-- . ________ . | . _______ . ______ -- ________ . | . _______ . ______
-- . | |--.-------+------->| | . | | -- | |-----.------+------.->| | . | |
-- . | | . ______ . | | . | | -- | | . ______ . | | . | |
-- . |dp_fifo | . | | . | | . | | -- |dp_fifo | . | | . | | . | |
-- ----->|dc_mixed|-+--->|dp |---->| io | . | tech | -- wr_sosi --------->|dc_mixed|-+----->|dp |----->| io | . | tech |
-- |widths | | |flush | | ddr | . | ddr | -- wr_clk --------->|widths | | |flush | | ddr | . | ddr |
-- |________| | |______|<-\ | driver| . | | -- |________| | |______|<--\ | driver| . | |
-- | | | | . | | -- | | | | . | |
-- | wr_flush_en| | | . | | -- | ctlr_wr_flush_en| | | . | |
-- | ______ | | | . | | -- | ______ | | | . | |
-- \--->|io_ddr|--/ | | . | | -- \----->|io_ddr|---/ | | . | |
-- |driver| | | . | | -- dvr_clk ------------> |driver| | | . | |<--- phy_in
-- /--->|flush | | | . | | -- dvr_wr_flush_en ----*-------------->|flush | | |---->| |---> phy_ou
-- |/-->|ctrl |<-\ | | . | | -- /---->|ctrl |<--\ | |<----| |<--> phy_io
-- ||/->|______| | | | . | | -- |/--->|______| | | | . | |
-- ||| | | | . | |<--- phy_in -- || | | | . | |
-- dvr_flush_en -----------+||------------|->| |---->| |---> phy_out -- dvr_en ----*---------+|---------------|->| | . | |
-- dvr_en ------------+|------------|->| |<----| |<--> phy_io -- dvr_wr_not_rd ----*----------+---------------|->| | . | |
-- dvr_wr_not_rd -------------+------------|->| | . | | -- dvr_done <---*--------------------------+--| | . | |
-- dvr_done <-------------------------+--| | . | | -- dvr_start_addr ----*---------------------------->| | . | |
-- dvr_start_addr ---------------------------->| | . | | -- dvr_end_addr ----*---------------------------->| | . | |
-- dvr_end_addr ---------------------------->| | . | |
-- ________ | | . | | -- ________ | | . | |
-- |dp_fifo | | | . | | -- rd_clk --------->|dp_fifo | | | . | |
-- <-----|dc_mixed|<------------------| | . | | -- rd_sosi <---------|dc_mixed|<---------------------| | . | |
-- . |widths | . |_______| . |______| -- rd_fifo_usedw |widths | . |_______| . |______|---\
-- . |________| . . -- |________| . . |
-- rd_sosi ctlr_rd_src ctlr_miso -- ctlr_rd_src ctlr_miso |
-- rd_fifo_usedw ctlr_init_done -- ctlr_init_done |
-- |
-- ctlr_clk /------ctlr_clk_in -------> |
-- \------ctlr_clk_out-----------------------------------------------/
-- --
-- * = clock domain crossing between dvr_clk and ctlr_clk clock domains.
-- --
-- Remarks:
-- . If the dvr_clk=ctlr_clk then the clock domain crossing logic defaults
-- to wires. However dvr_clk could also be the dp_clk or the mm_clk and then
-- the clock domain crossing logic is needed.
-- No need to cross dvr_start_addr, because the address is stable when the
-- dvr_en is stable. No need to cross dvr_wr_fifo_usedw, because it is only
-- used for monitoring purposes.
-- . Externally connect ctlr_clk = ctlr_clk_in = ctlr_clk_out
-- . Typically wr_clk = rd_clk = dp_clk.
-- . The main PHY signals are carried by phy_ou and phy_io. The phy_in signals
-- are typically not needed.
LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib; LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_1164.ALL;
...@@ -71,6 +105,7 @@ ENTITY io_ddr IS ...@@ -71,6 +105,7 @@ ENTITY io_ddr IS
GENERIC( GENERIC(
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_cross_domain_dvr_ctlr : BOOLEAN := TRUE;
g_wr_data_w : NATURAL := 32; g_wr_data_w : NATURAL := 32;
g_wr_fifo_depth : NATURAL := 128; -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the 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, defined at DDR side of the FIFO. g_rd_fifo_depth : NATURAL := 256; -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO.
...@@ -95,12 +130,15 @@ ENTITY io_ddr IS ...@@ -95,12 +130,15 @@ ENTITY io_ddr IS
ctlr_init_done : OUT STD_LOGIC; ctlr_init_done : OUT STD_LOGIC;
ctlr_rdy : OUT STD_LOGIC; ctlr_rdy : OUT STD_LOGIC;
-- Driver clock domain
dvr_clk : IN STD_LOGIC;
dvr_rst : IN STD_LOGIC;
dvr_en : IN STD_LOGIC; dvr_en : IN STD_LOGIC;
dvr_done : OUT STD_LOGIC;
dvr_wr_not_rd : IN STD_LOGIC; dvr_wr_not_rd : IN STD_LOGIC;
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_wr_flush_en : IN STD_LOGIC := '0';
dvr_flush_en : IN STD_LOGIC := '0';
dvr_wr_fifo_usedw : OUT STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth * (func_tech_ddr_ctlr_data_w(g_tech_ddr)/g_wr_data_w) )-1 DOWNTO 0); -- for monitoring purposes dvr_wr_fifo_usedw : OUT STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth * (func_tech_ddr_ctlr_data_w(g_tech_ddr)/g_wr_data_w) )-1 DOWNTO 0); -- for monitoring purposes
-- Write FIFO clock domain -- Write FIFO clock domain
...@@ -134,26 +172,31 @@ ARCHITECTURE str OF io_ddr IS ...@@ -134,26 +172,31 @@ ARCHITECTURE str OF io_ddr IS
CONSTANT c_wr_fifo_use_ctrl : BOOLEAN := c_wr_use_sync OR c_wr_use_ctrl; CONSTANT c_wr_fifo_use_ctrl : BOOLEAN := c_wr_use_sync OR c_wr_use_ctrl;
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); -- get FIFO depth at write side 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_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_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 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 ctlr_dvr_en : STD_LOGIC;
SIGNAL ctlr_dvr_done : STD_LOGIC;
SIGNAL ctlr_dvr_wr_not_rd : STD_LOGIC;
SIGNAL ctlr_dvr_start_addr : t_tech_ddr_addr;
SIGNAL ctlr_dvr_end_addr : t_tech_ddr_addr;
SIGNAL ctlr_dvr_wr_flush_en : STD_LOGIC := '0';
SIGNAL i_ctlr_init_done : STD_LOGIC; SIGNAL i_ctlr_init_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 wr_flush_en : STD_LOGIC := '0'; SIGNAL ctlr_wr_flush_en : STD_LOGIC := '0';
SIGNAL wr_fifo_snk_in : t_dp_sosi; SIGNAL wr_fifo_snk_in : t_dp_sosi;
SIGNAL wr_fifo_src_in : t_dp_siso; SIGNAL ctlr_wr_fifo_src_in : t_dp_siso;
SIGNAL wr_fifo_src_out : t_dp_sosi := c_dp_sosi_rst; SIGNAL ctlr_wr_fifo_src_out : t_dp_sosi := c_dp_sosi_rst;
SIGNAL wr_flush_snk_in : t_dp_sosi := c_dp_sosi_rst; SIGNAL ctlr_wr_flush_snk_in : t_dp_sosi := c_dp_sosi_rst;
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;
...@@ -161,14 +204,42 @@ ARCHITECTURE str OF io_ddr IS ...@@ -161,14 +204,42 @@ ARCHITECTURE str OF io_ddr IS
SIGNAL ctlr_rd_src_in : t_dp_siso; SIGNAL ctlr_rd_src_in : t_dp_siso;
SIGNAL ctlr_rd_src_out : t_dp_sosi := c_dp_sosi_rst; SIGNAL ctlr_rd_src_out : t_dp_sosi := c_dp_sosi_rst;
SIGNAL wr_fifo_usedw : STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth)-1 DOWNTO 0); -- read side depth of the write FIFO SIGNAL ctlr_wr_fifo_usedw : STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth)-1 DOWNTO 0); -- read side depth of the write FIFO
BEGIN BEGIN
ctlr_init_done <= i_ctlr_init_done; ctlr_init_done <= i_ctlr_init_done;
ctlr_rdy <= ctlr_miso.waitrequest_n; ctlr_rdy <= ctlr_miso.waitrequest_n;
dvr_done <= i_dvr_done;
dvr_wr_fifo_usedw <= wr_fifo_usedw; u_io_ddr_cross_domain : ENTITY work.io_ddr_cross_domain
GENERIC MAP (
g_cross_domain => g_cross_domain_dvr_ctlr
)
PORT MAP(
-- Driver clock domain
dvr_clk => dvr_clk,
dvr_rst => dvr_rst,
dvr_en => dvr_en,
dvr_done => dvr_done,
dvr_wr_not_rd => dvr_wr_not_rd,
dvr_start_addr => dvr_start_addr,
dvr_end_addr => dvr_end_addr,
dvr_wr_flush_en => dvr_wr_flush_en,
dvr_wr_fifo_usedw => dvr_wr_fifo_usedw,
-- DDR controller clock domain
ctlr_clk => ctlr_clk_in,
ctlr_rst => ctlr_rst_in,
ctlr_dvr_en => ctlr_dvr_en,
ctlr_dvr_done => ctlr_dvr_done,
ctlr_dvr_wr_not_rd => ctlr_dvr_wr_not_rd,
ctlr_dvr_start_addr => ctlr_dvr_start_addr,
ctlr_dvr_end_addr => ctlr_dvr_end_addr,
ctlr_dvr_wr_flush_en => ctlr_dvr_wr_flush_en,
ctlr_dvr_wr_fifo_usedw => ctlr_wr_fifo_usedw
);
p_wr_fifo_snk_in : PROCESS (wr_sosi) p_wr_fifo_snk_in : PROCESS (wr_sosi)
BEGIN BEGIN
...@@ -199,39 +270,39 @@ BEGIN ...@@ -199,39 +270,39 @@ BEGIN
snk_in => wr_fifo_snk_in, snk_in => wr_fifo_snk_in,
wr_usedw => OPEN, wr_usedw => OPEN,
rd_usedw => wr_fifo_usedw, rd_usedw => ctlr_wr_fifo_usedw,
rd_emp => OPEN, rd_emp => OPEN,
src_in => wr_fifo_src_in, src_in => ctlr_wr_fifo_src_in,
src_out => wr_fifo_src_out src_out => ctlr_wr_fifo_src_out
); );
u_dp_flush : ENTITY dp_lib.dp_flush u_dp_flush : ENTITY dp_lib.dp_flush
GENERIC MAP ( GENERIC MAP (
g_ready_latency => 0, g_ready_latency => 0,
g_framed_xon => c_wr_fifo_use_ctrl, -- stop flushing when wr_flush_en is low and a sop (or sync via sop) has arrived g_framed_xon => c_wr_fifo_use_ctrl, -- stop flushing when flush_en is low and a sop (or sync via sop) has arrived
g_framed_xoff => FALSE -- immediately start flushing when wr_flush_en goes high g_framed_xoff => FALSE -- immediately start flushing when flush_en goes high
) )
PORT MAP ( PORT MAP (
rst => ctlr_rst_in, rst => ctlr_rst_in,
clk => ctlr_clk_in, clk => ctlr_clk_in,
snk_in => wr_fifo_src_out, snk_in => ctlr_wr_fifo_src_out,
snk_out => wr_fifo_src_in, snk_out => ctlr_wr_fifo_src_in,
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 => wr_flush_en flush_en => ctlr_wr_flush_en
); );
p_wr_flush_snk_in : PROCESS (wr_fifo_src_out) p_ctlr_wr_flush_snk_in : PROCESS (ctlr_wr_fifo_src_out)
BEGIN BEGIN
wr_flush_snk_in <= wr_fifo_src_out; ctlr_wr_flush_snk_in <= ctlr_wr_fifo_src_out;
IF c_wr_use_sync=TRUE THEN IF c_wr_use_sync=TRUE THEN
-- Work around : Transport sync via sop through the dp_fifo_dc_mixed_widths -- Work around : Transport sync via sop through the dp_fifo_dc_mixed_widths
wr_flush_snk_in.sync <= wr_fifo_src_out.sop; ctlr_wr_flush_snk_in.sync <= ctlr_wr_fifo_src_out.sop;
wr_flush_snk_in.sop <= '0'; ctlr_wr_flush_snk_in.sop <= '0';
END IF; END IF;
END PROCESS; END PROCESS;
...@@ -246,14 +317,14 @@ BEGIN ...@@ -246,14 +317,14 @@ BEGIN
rst => ctlr_rst_in, rst => ctlr_rst_in,
clk => ctlr_clk_in, clk => ctlr_clk_in,
dvr_flush_en => dvr_flush_en, dvr_en => ctlr_dvr_en,
dvr_en => dvr_en, dvr_done => ctlr_dvr_done,
dvr_wr_not_rd => dvr_wr_not_rd, dvr_wr_not_rd => ctlr_dvr_wr_not_rd,
dvr_done => i_dvr_done, dvr_wr_flush_en => ctlr_dvr_wr_flush_en,
wr_sosi => wr_flush_snk_in, wr_sosi => ctlr_wr_flush_snk_in,
wr_flush_en => wr_flush_en ctlr_wr_flush_en => ctlr_wr_flush_en
); );
u_rd_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths u_rd_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths
...@@ -290,13 +361,13 @@ BEGIN ...@@ -290,13 +361,13 @@ BEGIN
rst => ctlr_rst_in, rst => ctlr_rst_in,
clk => ctlr_clk_in, clk => ctlr_clk_in,
dvr_en => dvr_en, dvr_en => ctlr_dvr_en,
dvr_wr_not_rd => dvr_wr_not_rd, dvr_wr_not_rd => ctlr_dvr_wr_not_rd,
dvr_start_addr => dvr_start_addr, dvr_start_addr => ctlr_dvr_start_addr,
dvr_end_addr => dvr_end_addr, dvr_end_addr => ctlr_dvr_end_addr,
dvr_done => i_dvr_done, dvr_done => ctlr_dvr_done,
wr_fifo_usedw => wr_fifo_usedw, wr_fifo_usedw => ctlr_wr_fifo_usedw,
wr_snk_in => ctlr_wr_snk_in, wr_snk_in => ctlr_wr_snk_in,
wr_snk_out => ctlr_wr_snk_out, wr_snk_out => ctlr_wr_snk_out,
......
--------------------------------------------------------------------------------
--
-- Copyright (C) 2014
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
-- Purpose: Cross clock domain between dvr_clk and ctlr_clk
-- Description:
--
-- Remarks:
-- . If the dvr_clk=ctlr_clk then the clock domain crossing logic defaults
-- to wires. However dvr_clk could also be the dp_clk or the mm_clk and then
-- the clock domain crossing logic is needed.
-- No need to cross dvr_start_addr, because the address is stable when the
-- dvr_en is stable. No need to cross dvr_wr_fifo_usedw, because it is only
-- used for monitoring purposes.
LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE common_lib.common_pkg.ALL;
USE technology_lib.technology_select_pkg.ALL;
USE technology_lib.technology_pkg.ALL;
USE tech_ddr_lib.tech_ddr_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
ENTITY io_ddr_cross_domain IS
GENERIC (
g_cross_domain : BOOLEAN := TRUE
);
PORT (
-- Driver clock domain
dvr_clk : IN STD_LOGIC;
dvr_rst : IN STD_LOGIC;
dvr_en : IN STD_LOGIC;
dvr_done : OUT STD_LOGIC;
dvr_wr_not_rd : IN STD_LOGIC;
dvr_start_addr : IN t_tech_ddr_addr;
dvr_end_addr : IN t_tech_ddr_addr;
dvr_wr_flush_en : IN STD_LOGIC := '0';
dvr_wr_fifo_usedw : OUT STD_LOGIC_VECTOR;
-- DDR controller clock domain
ctlr_clk : IN STD_LOGIC;
ctlr_rst : IN STD_LOGIC;
ctlr_dvr_en : OUT STD_LOGIC;
ctlr_dvr_done : IN STD_LOGIC;
ctlr_dvr_wr_not_rd : OUT STD_LOGIC;
ctlr_dvr_start_addr : OUT t_tech_ddr_addr;
ctlr_dvr_end_addr : OUT t_tech_ddr_addr;
ctlr_dvr_wr_flush_en : OUT STD_LOGIC := '0';
ctlr_dvr_wr_fifo_usedw : IN STD_LOGIC_VECTOR
);
END io_ddr_cross_domain;
ARCHITECTURE str OF io_ddr_cross_domain IS
SIGNAL dvr_en_busy : STD_LOGIC;
SIGNAL new_dvr_done : STD_LOGIC;
BEGIN
no_cross : IF g_cross_domain=FALSE GENERATE
-- dvr_clk --> ctlr_clk
ctlr_dvr_en <= dvr_en;
ctlr_dvr_wr_not_rd <= dvr_wr_not_rd;
ctlr_dvr_start_addr <= dvr_start_addr;
ctlr_dvr_end_addr <= dvr_end_addr;
ctlr_dvr_wr_flush_en <= dvr_wr_flush_en;
-- ctlr_clk --> dvr_clk
dvr_done <= ctlr_dvr_done;
dvr_wr_fifo_usedw <= ctlr_dvr_wr_fifo_usedw;
END GENERATE;
gen_cross : IF g_cross_domain=TRUE GENERATE
-- dvr_clk --> ctlr_clk
u_common_spulse_ctlr_dvr_en : ENTITY common_lib.common_spulse
GENERIC MAP (
g_delay_len => c_meta_delay_len
)
PORT MAP (
in_rst => dvr_rst,
in_clk => dvr_clk,
in_pulse => dvr_en,
in_busy => dvr_en_busy,
out_rst => ctlr_rst,
out_clk => ctlr_clk,
out_pulse => ctlr_dvr_en
);
-- Only register into the other clock domain
ctlr_dvr_wr_not_rd <= dvr_wr_not_rd WHEN rising_edge(ctlr_clk);
ctlr_dvr_start_addr <= dvr_start_addr WHEN rising_edge(ctlr_clk);
ctlr_dvr_end_addr <= dvr_end_addr WHEN rising_edge(ctlr_clk);
u_common_spulse_ctlr_dvr_wr_flush_en : ENTITY common_lib.common_spulse
GENERIC MAP (
g_delay_len => c_meta_delay_len
)
PORT MAP (
in_rst => dvr_rst,
in_clk => dvr_clk,
in_pulse => dvr_wr_flush_en,
out_rst => ctlr_rst,
out_clk => ctlr_clk,
out_pulse => ctlr_dvr_wr_flush_en
);
-- ctlr_clk --> dvr_clk
u_common_async_dvr_done : ENTITY common_lib.common_async
GENERIC MAP (
g_rst_level => '0',
g_delay_len => c_meta_delay_len
)
PORT MAP (
rst => dvr_rst,
clk => dvr_clk,
din => ctlr_dvr_done,
dout => new_dvr_done
);
-- Ensure previous dvr_done goes low after new dvr_en
dvr_done <= new_dvr_done AND NOT dvr_en_busy;
-- Only register the word in the other clock domai
dvr_wr_fifo_usedw <= ctlr_dvr_wr_fifo_usedw WHEN rising_edge(ctlr_clk);
END GENERATE;
END str;
...@@ -47,6 +47,9 @@ USE tech_ddr_lib.tech_ddr_pkg.ALL; ...@@ -47,6 +47,9 @@ USE tech_ddr_lib.tech_ddr_pkg.ALL;
ENTITY tb_io_ddr IS ENTITY tb_io_ddr IS
GENERIC ( GENERIC (
g_technology : NATURAL := c_tech_select_default; g_technology : NATURAL := c_tech_select_default;
g_ctlr_ref_clk_period : TIME := 5 ns; -- 200 MHz
g_dvr_clk_period : TIME := 5 ns; -- 50 ns
g_dp_clk_period : TIME := 5000 ps; -- 200 MHz
g_nof_repeat : NATURAL := 2; g_nof_repeat : NATURAL := 2;
g_wr_flush_mode : STRING := "SYN" -- "VAL", "SOP", "SYN" g_wr_flush_mode : STRING := "SYN" -- "VAL", "SOP", "SYN"
); );
...@@ -54,9 +57,7 @@ END ENTITY tb_io_ddr; ...@@ -54,9 +57,7 @@ END ENTITY tb_io_ddr;
ARCHITECTURE str of tb_io_ddr IS ARCHITECTURE str of tb_io_ddr IS
CONSTANT c_cross_domain_dvr_ctlr : BOOLEAN := g_ctlr_ref_clk_period/=g_dvr_clk_period;
CONSTANT c_ctlr_ref_clk_period : TIME := 5 ns; -- 200 MHz
CONSTANT c_dp_clk_period : TIME := 5000 ps; -- 200 MHz
CONSTANT c_tech_ddr : t_c_tech_ddr := c_tech_ddr3_4g_800m_master; CONSTANT c_tech_ddr : t_c_tech_ddr := c_tech_ddr3_4g_800m_master;
...@@ -91,6 +92,8 @@ ARCHITECTURE str of tb_io_ddr IS ...@@ -91,6 +92,8 @@ ARCHITECTURE str of tb_io_ddr IS
SIGNAL ctlr_ref_rst : STD_LOGIC; SIGNAL ctlr_ref_rst : STD_LOGIC;
SIGNAL ctlr_clk : STD_LOGIC; SIGNAL ctlr_clk : STD_LOGIC;
SIGNAL ctlr_rst : STD_LOGIC; SIGNAL ctlr_rst : STD_LOGIC;
SIGNAL dvr_clk : STD_LOGIC := '0';
SIGNAL dvr_rst : STD_LOGIC;
SIGNAL dp_clk : STD_LOGIC := '0'; SIGNAL dp_clk : STD_LOGIC := '0';
SIGNAL dp_rst : STD_LOGIC; SIGNAL dp_rst : STD_LOGIC;
...@@ -101,9 +104,9 @@ ARCHITECTURE str of tb_io_ddr IS ...@@ -101,9 +104,9 @@ ARCHITECTURE str of tb_io_ddr IS
SIGNAL dvr_end_addr : t_tech_ddr_addr; SIGNAL dvr_end_addr : t_tech_ddr_addr;
SIGNAL dvr_en : STD_LOGIC; SIGNAL dvr_en : 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; SIGNAL dvr_wr_not_rd : STD_LOGIC;
SIGNAL dvr_wr_flush_en : STD_LOGIC;
SIGNAL dvr_wr_fifo_usedw : STD_LOGIC_VECTOR(ceil_log2(c_wr_fifo_depth * c_dp_factor)-1 DOWNTO 0); SIGNAL dvr_wr_fifo_usedw : STD_LOGIC_VECTOR(ceil_log2(c_wr_fifo_depth * c_dp_factor)-1 DOWNTO 0);
SIGNAL diag_wr_src_in : t_dp_siso; SIGNAL diag_wr_src_in : t_dp_siso;
...@@ -130,10 +133,13 @@ ARCHITECTURE str of tb_io_ddr IS ...@@ -130,10 +133,13 @@ ARCHITECTURE str of tb_io_ddr IS
BEGIN BEGIN
ctlr_ref_clk <= NOT ctlr_ref_clk OR tb_end AFTER c_ctlr_ref_clk_period/2; ctlr_ref_clk <= NOT ctlr_ref_clk OR tb_end AFTER g_ctlr_ref_clk_period/2;
ctlr_ref_rst <= '1', '0' AFTER 100 ns; ctlr_ref_rst <= '1', '0' AFTER 100 ns;
dp_clk <= NOT dp_clk OR tb_end AFTER c_dp_clk_period/2; dvr_clk <= NOT dvr_clk OR tb_end AFTER g_dvr_clk_period/2;
dvr_rst <= '1', '0' AFTER 100 ns;
dp_clk <= NOT dp_clk OR tb_end AFTER g_dp_clk_period/2;
dp_rst <= '1', '0' AFTER 100 ns; dp_rst <= '1', '0' AFTER 100 ns;
p_stimuli : PROCESS p_stimuli : PROCESS
...@@ -141,10 +147,10 @@ BEGIN ...@@ -141,10 +147,10 @@ BEGIN
VARIABLE v_addr_hi : t_tech_ddr_addr; VARIABLE v_addr_hi : t_tech_ddr_addr;
BEGIN BEGIN
tb_end <= '0'; tb_end <= '0';
dvr_flush_en <= '0';
dvr_en <= '0'; dvr_en <= '0';
src_diag_en <= '0'; dvr_wr_flush_en <= '0';
dvr_wr_not_rd <= '0'; dvr_wr_not_rd <= '0';
src_diag_en <= '0';
snk_diag_en <= '0'; snk_diag_en <= '0';
expected_cnt <= 0; expected_cnt <= 0;
...@@ -155,7 +161,7 @@ BEGIN ...@@ -155,7 +161,7 @@ BEGIN
src_diag_en <= '1'; src_diag_en <= '1';
snk_diag_en <= '1'; snk_diag_en <= '1';
-- After reset even when dvr_flush_en='0' then the write FIFO is flushed until the first write access is started -- After reset even when dvr_wr_flush_en='0' then the write FIFO is flushed until the first write access is started
proc_common_wait_some_cycles(ctlr_clk, 100); proc_common_wait_some_cycles(ctlr_clk, 100);
FOR R IN 0 TO g_nof_repeat-1 LOOP FOR R IN 0 TO g_nof_repeat-1 LOOP
...@@ -169,11 +175,11 @@ BEGIN ...@@ -169,11 +175,11 @@ BEGIN
-- START ACCESS -- START ACCESS
dvr_wr_not_rd <= c_wr_not_rd_arr(I); dvr_wr_not_rd <= c_wr_not_rd_arr(I);
dvr_en <= '1'; dvr_en <= '1';
proc_common_wait_some_cycles(ctlr_clk, 1); proc_common_wait_some_cycles(dvr_clk, 1);
dvr_en <= '0'; dvr_en <= '0';
-- ACCESS DONE -- ACCESS DONE
proc_common_wait_until_lo_hi(ctlr_clk, dvr_done); proc_common_wait_until_lo_hi(dvr_clk, dvr_done);
IF c_wr_not_rd_arr(I)='0' THEN IF c_wr_not_rd_arr(I)='0' THEN
expected_cnt <= expected_cnt + c_nof_address_arr(I)*c_dp_factor; expected_cnt <= expected_cnt + c_nof_address_arr(I)*c_dp_factor;
...@@ -188,9 +194,9 @@ BEGIN ...@@ -188,9 +194,9 @@ BEGIN
snk_diag_en <= '0'; snk_diag_en <= '0';
-- Flush the wr fifo -- Flush the wr fifo
dvr_flush_en <= '1'; dvr_wr_flush_en <= '1';
proc_common_wait_some_cycles(ctlr_clk, 1); proc_common_wait_some_cycles(dvr_clk, 1);
dvr_flush_en <= '0'; dvr_wr_flush_en <= '0';
proc_common_wait_some_cycles(ctlr_clk, 500); proc_common_wait_some_cycles(ctlr_clk, 500);
ASSERT UNSIGNED(dvr_wr_fifo_usedw) = 0 REPORT "[ERROR] Write FIFO is flushed but not empty!" SEVERITY FAILURE; ASSERT UNSIGNED(dvr_wr_fifo_usedw) = 0 REPORT "[ERROR] Write FIFO is flushed but not empty!" SEVERITY FAILURE;
...@@ -260,6 +266,7 @@ BEGIN ...@@ -260,6 +266,7 @@ BEGIN
GENERIC MAP( GENERIC MAP(
g_technology => g_technology, g_technology => g_technology,
g_tech_ddr => c_tech_ddr, g_tech_ddr => c_tech_ddr,
g_cross_domain_dvr_ctlr => c_cross_domain_dvr_ctlr,
g_wr_data_w => c_dp_data_w, g_wr_data_w => c_dp_data_w,
g_wr_fifo_depth => c_wr_fifo_depth, -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. g_wr_fifo_depth => c_wr_fifo_depth, -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO.
g_rd_fifo_depth => c_rd_fifo_depth, -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. g_rd_fifo_depth => c_rd_fifo_depth, -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO.
...@@ -284,12 +291,15 @@ BEGIN ...@@ -284,12 +291,15 @@ BEGIN
ctlr_init_done => ctlr_init_done, ctlr_init_done => ctlr_init_done,
ctlr_rdy => ctlr_rdy, ctlr_rdy => ctlr_rdy,
-- Driver clock domain
dvr_clk => dvr_clk,
dvr_rst => dvr_rst,
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 => 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, dvr_wr_flush_en => dvr_wr_flush_en,
dvr_wr_fifo_usedw => dvr_wr_fifo_usedw, dvr_wr_fifo_usedw => dvr_wr_fifo_usedw,
-- Write FIFO clock domain -- Write FIFO clock domain
......
...@@ -40,11 +40,17 @@ ARCHITECTURE tb OF tb_tb_io_ddr IS ...@@ -40,11 +40,17 @@ ARCHITECTURE tb OF tb_tb_io_ddr IS
BEGIN BEGIN
-- g_technology : NATURAL := c_tech_select_default; -- g_technology : NATURAL := c_tech_select_default;
-- g_ctlr_ref_clk_period : TIME := 5 ns; -- 200 MHz
-- g_dvr_clk_period : TIME := 20 ns; -- 50 ns
-- g_dp_clk_period : TIME := 5000 ps; -- 200 MHz
-- g_nof_repeat : NATURAL := 2; -- g_nof_repeat : NATURAL := 2;
-- g_wr_flush_mode : STRING := "SYN" -- "VAL", "SOP", "SYN" -- g_wr_flush_mode : STRING := "SYN" -- "VAL", "SOP", "SYN"
u_fill_wrfifo_on_next_valid : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 2, "VAL"); u_fill_wrfifo_on_next_valid : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 5 ns, 5 ns, 5 ns, 2, "VAL");
u_fill_wrfifo_on_next_sop : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 2, "SOP"); u_fill_wrfifo_on_next_sop : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 5 ns, 5 ns, 5 ns, 2, "SOP");
u_fill_wrfifo_on_next_sync : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 2, "SYN"); u_fill_wrfifo_on_next_sync : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 5 ns, 5 ns, 5 ns, 2, "SYN");
u_cross_dvr_to_faster_ctlr : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 5 ns, 20 ns, 5 ns, 1, "VAL");
u_cross_dvr_to_slower_ctlr : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 5 ns, 1 ns, 5 ns, 1, "VAL");
END tb; END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment