-------------------------------------------------------------------------------- -- -- 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/>. -- -------------------------------------------------------------------------------- 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 IS GENERIC( g_technology : NATURAL := c_tech_select_default; g_tech_ddr : t_c_tech_ddr; 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_fifo_depth : NATURAL := 128; -- >=16 AND >g_tech_ddr.maxburstsize , defined at read side of write 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_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_sop : BOOLEAN := FALSE; g_flush_sop_channel : BOOLEAN := FALSE; g_flush_sop_start_channel : NATURAL := 0; g_flush_nof_channels : NATURAL := 0 ); PORT ( ctlr_ref_clk : IN STD_LOGIC; ctlr_ref_rst : IN STD_LOGIC; ctlr_init_done : OUT STD_LOGIC; ctlr_rdy : OUT STD_LOGIC; dvr_en : IN STD_LOGIC; dvr_wr_not_rd : IN STD_LOGIC; dvr_done : OUT STD_LOGIC; dvr_start_addr : IN t_tech_ddr_addr; dvr_end_addr : IN t_tech_ddr_addr; wr_clk : IN STD_LOGIC; wr_rst : IN STD_LOGIC; wr_sosi : IN t_dp_sosi; wr_siso : OUT t_dp_siso; rd_sosi : OUT t_dp_sosi; rd_siso : IN t_dp_siso; rd_clk : IN STD_LOGIC; rd_rst : IN STD_LOGIC; rd_fifo_usedw : OUT STD_LOGIC_VECTOR(ceil_log2(g_rd_fifo_depth * (func_tech_ddr_ctlr_data_w(g_tech_ddr)/g_rd_data_w) )-1 DOWNTO 0); phy_in : IN t_tech_ddr_phy_in; phy_io : INOUT t_tech_ddr_phy_io; phy_ou : OUT t_tech_ddr_phy_ou ); END io_ddr; ARCHITECTURE str OF io_ddr IS 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_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; SIGNAL i_ctlr_init_done : STD_LOGIC; SIGNAL i_dvr_done : STD_LOGIC; SIGNAL ctlr_gen_clk : STD_LOGIC; SIGNAL ctlr_gen_rst : 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 dvr_flush : STD_LOGIC := '0'; 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 flush_wr_siso : t_dp_siso; SIGNAL flush_wr_sosi : 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 BEGIN ctlr_init_done <= i_ctlr_init_done; ctlr_rdy <= ctlr_miso.waitrequest_n; dvr_done <= i_dvr_done; u_wr_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths GENERIC MAP ( g_wr_data_w => g_wr_data_w, g_rd_data_w => c_ctlr_data_w, g_use_ctrl => g_wr_use_ctrl, 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_rd_fifo_rl => 0 ) PORT MAP ( wr_rst => wr_rst, wr_clk => wr_clk, rd_rst => ctlr_gen_rst, rd_clk => ctlr_gen_clk, snk_out => wr_siso, snk_in => wr_sosi, wr_usedw => OPEN, rd_usedw => wr_fifo_usedw, rd_emp => OPEN, src_in => flush_wr_siso, src_out => flush_wr_sosi ); u_dp_flush : ENTITY dp_lib.dp_flush -- Always instantiate the flusher as it also contains a RL adapter GENERIC MAP ( 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_xoff => FALSE -- immediately start flushing when dvr_flush goes high ) PORT MAP ( rst => ctlr_gen_rst, clk => ctlr_gen_clk, snk_in => flush_wr_sosi, snk_out => flush_wr_siso, src_out => ctlr_wr_snk_in, src_in => ctlr_wr_snk_out, flush_en => dvr_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 GENERIC MAP ( g_sop => g_flush_sop, g_sop_channel => g_flush_sop_channel, g_sop_start_channel => g_flush_sop_start_channel, g_nof_channels => g_flush_nof_channels ) PORT MAP ( rst => wr_rst, clk => wr_clk, dvr_en => dvr_en, dvr_wr_not_rd => dvr_wr_not_rd, dvr_done => i_dvr_done, wr_sosi => wr_sosi, dvr_flush => dvr_flush ); END GENERATE; u_rd_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths GENERIC MAP ( g_wr_data_w => c_ctlr_data_w, g_rd_data_w => g_rd_data_w, g_use_ctrl => FALSE, 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_rd_fifo_rl => 1 ) PORT MAP ( wr_rst => ctlr_gen_rst, wr_clk => ctlr_gen_clk, rd_rst => rd_rst, rd_clk => rd_clk, snk_out => ctlr_rd_src_in, snk_in => ctlr_rd_src_out, wr_usedw => OPEN, rd_usedw => rd_fifo_usedw, rd_emp => OPEN, src_in => rd_siso, src_out => rd_sosi ); u_io_ddr_driver : ENTITY work.io_ddr_driver GENERIC MAP ( g_tech_ddr => g_tech_ddr ) PORT MAP ( rst => ctlr_gen_rst, clk => ctlr_gen_clk, ctlr_init_done => i_ctlr_init_done, ctlr_mosi => ctlr_mosi, ctlr_miso => ctlr_miso, dvr_en => dvr_en, dvr_done => i_dvr_done, dvr_wr_not_rd => dvr_wr_not_rd, dvr_start_addr => dvr_start_addr, dvr_end_addr => dvr_end_addr, wr_fifo_usedw => wr_fifo_usedw, wr_snk_out => ctlr_wr_snk_out, wr_snk_in => ctlr_wr_snk_in, rd_src_in => ctlr_rd_src_in, rd_src_out => ctlr_rd_src_out ); u_tech_ddr : ENTITY tech_ddr_lib.tech_ddr GENERIC MAP ( g_technology => g_technology, g_tech_ddr => g_tech_ddr ) PORT MAP ( -- PLL reference clock ctlr_ref_clk => ctlr_ref_clk, ctlr_ref_rst => ctlr_ref_rst, -- Controller user interface ctlr_gen_clk => ctlr_gen_clk, ctlr_gen_rst => ctlr_gen_rst, ctlr_gen_clk_2x => OPEN, ctlr_gen_rst_2x => OPEN, ctlr_init_done => i_ctlr_init_done, ctrl_mosi => ctlr_mosi, ctrl_miso => ctlr_miso, -- PHY interface phy_in => phy_in, phy_io => phy_io, phy_ou => phy_ou ); END str;