From f52fc96d8b9ccac2d7023e13c6e4b225cac41c09 Mon Sep 17 00:00:00 2001 From: Erik Kooistra <kooistra@astron.nl> Date: Mon, 5 Jan 2015 14:22:44 +0000 Subject: [PATCH] Added io_ddr_cross_domain.vhd to handle dvr_clk and ctlr_clk domains in case they are different clock domains. --- libraries/io/ddr/hdllib.cfg | 1 + libraries/io/ddr/src/vhdl/io_ddr.vhd | 233 ++++++++++++------ .../io/ddr/src/vhdl/io_ddr_cross_domain.vhd | 149 +++++++++++ libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd | 58 +++-- libraries/io/ddr/tb/vhdl/tb_tb_io_ddr.vhd | 20 +- 5 files changed, 349 insertions(+), 112 deletions(-) create mode 100644 libraries/io/ddr/src/vhdl/io_ddr_cross_domain.vhd diff --git a/libraries/io/ddr/hdllib.cfg b/libraries/io/ddr/hdllib.cfg index a033ca3ac9..41a4c6ca9c 100644 --- a/libraries/io/ddr/hdllib.cfg +++ b/libraries/io/ddr/hdllib.cfg @@ -12,6 +12,7 @@ modelsim_compile_ip_files = synth_files = src/vhdl/io_ddr_driver_flush_ctrl.vhd src/vhdl/io_ddr_driver.vhd + src/vhdl/io_ddr_cross_domain.vhd src/vhdl/io_ddr.vhd test_bench_files = diff --git a/libraries/io/ddr/src/vhdl/io_ddr.vhd b/libraries/io/ddr/src/vhdl/io_ddr.vhd index bdf19a2b66..b804ce46e2 100644 --- a/libraries/io/ddr/src/vhdl/io_ddr.vhd +++ b/libraries/io/ddr/src/vhdl/io_ddr.vhd @@ -18,47 +18,81 @@ -- 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: Provide streaming interface to DDR memory -- Description: -- --- dvr_wr_fifo_usedw <----------------\ --- | --- wr_sosi wr_fifo_src | ctlr_wr_snk ctlr_mosi --- . . | . . --- . ________ . | . _______ . ______ --- . | |--.-------+------->| | . | | --- . | | . ______ . | | . | | --- . |dp_fifo | . | | . | | . | | --- ----->|dc_mixed|-+--->|dp |---->| io | . | tech | --- |widths | | |flush | | ddr | . | ddr | --- |________| | |______|<-\ | driver| . | | --- | | | | . | | --- | wr_flush_en| | | . | | --- | ______ | | | . | | --- \--->|io_ddr|--/ | | . | | --- |driver| | | . | | --- /--->|flush | | | . | | --- |/-->|ctrl |<-\ | | . | | --- ||/->|______| | | | . | | --- ||| | | | . | |<--- phy_in --- dvr_flush_en -----------+||------------|->| |---->| |---> phy_out --- dvr_en ------------+|------------|->| |<----| |<--> phy_io --- dvr_wr_not_rd -------------+------------|->| | . | | --- dvr_done <-------------------------+--| | . | | --- dvr_start_addr ---------------------------->| | . | | --- dvr_end_addr ---------------------------->| | . | | --- ________ | | . | | --- |dp_fifo | | | . | | --- <-----|dc_mixed|<------------------| | . | | --- . |widths | . |_______| . |______| --- . |________| . . --- rd_sosi ctlr_rd_src ctlr_miso --- rd_fifo_usedw ctlr_init_done --- +-- 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 <-*-------------------\ +-- | +-- ctlr_wr_fifo_src | ctlr_wr_snk ctlr_mosi +-- . | . . +-- ________ . | . _______ . ______ +-- | |-----.------+------.->| | . | | +-- | | . ______ . | | . | | +-- |dp_fifo | . | | . | | . | | +-- wr_sosi --------->|dc_mixed|-+----->|dp |----->| io | . | tech | +-- wr_clk --------->|widths | | |flush | | ddr | . | ddr | +-- |________| | |______|<--\ | driver| . | | +-- | | | | . | | +-- | ctlr_wr_flush_en| | | . | | +-- | ______ | | | . | | +-- \----->|io_ddr|---/ | | . | | +-- dvr_clk ------------> |driver| | | . | |<--- phy_in +-- dvr_wr_flush_en ----*-------------->|flush | | |---->| |---> phy_ou +-- /---->|ctrl |<--\ | |<----| |<--> phy_io +-- |/--->|______| | | | . | | +-- || | | | . | | +-- dvr_en ----*---------+|---------------|->| | . | | +-- dvr_wr_not_rd ----*----------+---------------|->| | . | | +-- dvr_done <---*--------------------------+--| | . | | +-- dvr_start_addr ----*---------------------------->| | . | | +-- dvr_end_addr ----*---------------------------->| | . | | +-- ________ | | . | | +-- rd_clk --------->|dp_fifo | | | . | | +-- rd_sosi <---------|dc_mixed|<---------------------| | . | | +-- rd_fifo_usedw |widths | . |_______| . |______|---\ +-- |________| . . | +-- ctlr_rd_src ctlr_miso | +-- 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; USE IEEE.STD_LOGIC_1164.ALL; USE common_lib.common_pkg.ALL; @@ -71,6 +105,7 @@ ENTITY io_ddr IS GENERIC( g_technology : NATURAL := c_tech_select_default; g_tech_ddr : t_c_tech_ddr; + g_cross_domain_dvr_ctlr : BOOLEAN := TRUE; 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_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 ctlr_init_done : 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_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_done : OUT STD_LOGIC; - dvr_flush_en : IN STD_LOGIC := '0'; + dvr_wr_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 -- Write FIFO clock domain @@ -134,42 +172,75 @@ ARCHITECTURE str OF io_ddr IS 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_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_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_dvr_done : STD_LOGIC; + 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 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_mosi : t_tech_ddr_mosi := c_tech_ddr_mosi_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 wr_fifo_src_out : t_dp_sosi := c_dp_sosi_rst; + SIGNAL ctlr_wr_fifo_src_in : t_dp_siso; + 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_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_in : t_dp_sosi := c_dp_sosi_rst; - SIGNAL ctlr_rd_src_in : t_dp_siso; - SIGNAL ctlr_rd_src_out : t_dp_sosi := c_dp_sosi_rst; + SIGNAL ctlr_rd_src_in : t_dp_siso; + 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 ctlr_init_done <= i_ctlr_init_done; 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) BEGIN wr_fifo_snk_in <= wr_sosi; @@ -199,39 +270,39 @@ BEGIN snk_in => wr_fifo_snk_in, wr_usedw => OPEN, - rd_usedw => wr_fifo_usedw, + rd_usedw => ctlr_wr_fifo_usedw, rd_emp => OPEN, - src_in => wr_fifo_src_in, - src_out => wr_fifo_src_out + src_in => ctlr_wr_fifo_src_in, + src_out => ctlr_wr_fifo_src_out ); u_dp_flush : ENTITY dp_lib.dp_flush GENERIC MAP ( 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_xoff => FALSE -- immediately start flushing when wr_flush_en goes high + 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 flush_en goes high ) PORT MAP ( rst => ctlr_rst_in, clk => ctlr_clk_in, - snk_in => wr_fifo_src_out, - snk_out => wr_fifo_src_in, + snk_in => ctlr_wr_fifo_src_out, + snk_out => ctlr_wr_fifo_src_in, src_out => ctlr_wr_snk_in, 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 - 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 -- Work around : Transport sync via sop through the dp_fifo_dc_mixed_widths - wr_flush_snk_in.sync <= wr_fifo_src_out.sop; - wr_flush_snk_in.sop <= '0'; + ctlr_wr_flush_snk_in.sync <= ctlr_wr_fifo_src_out.sop; + ctlr_wr_flush_snk_in.sop <= '0'; END IF; END PROCESS; @@ -243,17 +314,17 @@ BEGIN g_nof_channels => g_wr_flush_nof_channels ) PORT MAP ( - rst => ctlr_rst_in, - clk => ctlr_clk_in, + rst => ctlr_rst_in, + clk => ctlr_clk_in, - dvr_flush_en => dvr_flush_en, - dvr_en => dvr_en, - dvr_wr_not_rd => dvr_wr_not_rd, - dvr_done => i_dvr_done, + dvr_en => ctlr_dvr_en, + dvr_done => ctlr_dvr_done, + dvr_wr_not_rd => ctlr_dvr_wr_not_rd, + 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 @@ -290,13 +361,13 @@ BEGIN rst => ctlr_rst_in, clk => ctlr_clk_in, - dvr_en => dvr_en, - dvr_wr_not_rd => dvr_wr_not_rd, - dvr_start_addr => dvr_start_addr, - dvr_end_addr => dvr_end_addr, - dvr_done => i_dvr_done, + dvr_en => ctlr_dvr_en, + dvr_wr_not_rd => ctlr_dvr_wr_not_rd, + dvr_start_addr => ctlr_dvr_start_addr, + dvr_end_addr => ctlr_dvr_end_addr, + 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_out => ctlr_wr_snk_out, diff --git a/libraries/io/ddr/src/vhdl/io_ddr_cross_domain.vhd b/libraries/io/ddr/src/vhdl/io_ddr_cross_domain.vhd new file mode 100644 index 0000000000..a5420a39ed --- /dev/null +++ b/libraries/io/ddr/src/vhdl/io_ddr_cross_domain.vhd @@ -0,0 +1,149 @@ +-------------------------------------------------------------------------------- +-- +-- 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; diff --git a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd index b8fd498594..11ab25b024 100644 --- a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd +++ b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd @@ -46,17 +46,18 @@ USE tech_ddr_lib.tech_ddr_pkg.ALL; ENTITY tb_io_ddr IS GENERIC ( - g_technology : NATURAL := c_tech_select_default; - g_nof_repeat : NATURAL := 2; - g_wr_flush_mode : STRING := "SYN" -- "VAL", "SOP", "SYN" + 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_wr_flush_mode : STRING := "SYN" -- "VAL", "SOP", "SYN" ); END ENTITY tb_io_ddr; ARCHITECTURE str of tb_io_ddr IS - - CONSTANT c_ctlr_ref_clk_period : TIME := 5 ns; -- 200 MHz - CONSTANT c_dp_clk_period : TIME := 5000 ps; -- 200 MHz + CONSTANT c_cross_domain_dvr_ctlr : BOOLEAN := g_ctlr_ref_clk_period/=g_dvr_clk_period; 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 SIGNAL ctlr_ref_rst : STD_LOGIC; SIGNAL ctlr_clk : 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_rst : STD_LOGIC; @@ -101,9 +104,9 @@ ARCHITECTURE str of tb_io_ddr IS SIGNAL dvr_end_addr : t_tech_ddr_addr; SIGNAL dvr_en : STD_LOGIC; - SIGNAL dvr_wr_not_rd : 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 diag_wr_src_in : t_dp_siso; @@ -130,23 +133,26 @@ ARCHITECTURE str of tb_io_ddr IS 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; - 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; p_stimuli : PROCESS VARIABLE v_addr_lo : t_tech_ddr_addr; VARIABLE v_addr_hi : t_tech_ddr_addr; BEGIN - tb_end <= '0'; - dvr_flush_en <= '0'; - dvr_en <= '0'; - src_diag_en <= '0'; - dvr_wr_not_rd <= '0'; - snk_diag_en <= '0'; - expected_cnt <= 0; + tb_end <= '0'; + dvr_en <= '0'; + dvr_wr_flush_en <= '0'; + dvr_wr_not_rd <= '0'; + src_diag_en <= '0'; + snk_diag_en <= '0'; + expected_cnt <= 0; proc_common_wait_until_high(ctlr_clk, ctlr_init_done); proc_common_wait_some_cycles(ctlr_clk, 2); -- Give the driver FSM a cycle to go into idle mode @@ -155,7 +161,7 @@ BEGIN src_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); FOR R IN 0 TO g_nof_repeat-1 LOOP @@ -169,11 +175,11 @@ BEGIN -- START ACCESS dvr_wr_not_rd <= c_wr_not_rd_arr(I); dvr_en <= '1'; - proc_common_wait_some_cycles(ctlr_clk, 1); + proc_common_wait_some_cycles(dvr_clk, 1); dvr_en <= '0'; -- 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 expected_cnt <= expected_cnt + c_nof_address_arr(I)*c_dp_factor; @@ -188,9 +194,9 @@ BEGIN snk_diag_en <= '0'; -- Flush the wr fifo - dvr_flush_en <= '1'; - proc_common_wait_some_cycles(ctlr_clk, 1); - dvr_flush_en <= '0'; + dvr_wr_flush_en <= '1'; + proc_common_wait_some_cycles(dvr_clk, 1); + dvr_wr_flush_en <= '0'; 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; @@ -260,6 +266,7 @@ BEGIN GENERIC MAP( g_technology => g_technology, 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_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. @@ -284,12 +291,15 @@ BEGIN ctlr_init_done => ctlr_init_done, ctlr_rdy => ctlr_rdy, + -- Driver clock domain + dvr_clk => dvr_clk, + dvr_rst => dvr_rst, dvr_en => dvr_en, dvr_wr_not_rd => dvr_wr_not_rd, dvr_done => dvr_done, dvr_start_addr => dvr_start_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, -- Write FIFO clock domain diff --git a/libraries/io/ddr/tb/vhdl/tb_tb_io_ddr.vhd b/libraries/io/ddr/tb/vhdl/tb_tb_io_ddr.vhd index 080b876a5e..ac4f8ff367 100644 --- a/libraries/io/ddr/tb/vhdl/tb_tb_io_ddr.vhd +++ b/libraries/io/ddr/tb/vhdl/tb_tb_io_ddr.vhd @@ -39,12 +39,18 @@ ARCHITECTURE tb OF tb_tb_io_ddr IS BEGIN - -- g_technology : NATURAL := c_tech_select_default; - -- g_nof_repeat : NATURAL := 2; - -- 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_sop : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 2, "SOP"); - u_fill_wrfifo_on_next_sync : ENTITY work.tb_io_ddr GENERIC MAP (c_tech_select_default, 2, "SYN"); + -- 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_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, 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, 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, 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; -- GitLab