Skip to content
Snippets Groups Projects
io_ddr.vhd 9.06 KiB
Newer Older
--------------------------------------------------------------------------------
--
-- 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_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 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_flush_mode              : STRING := "VAL";    -- "VAL", "SOP", "SYN"
    g_flush_use_channel       : BOOLEAN := FALSE;
    g_flush_start_channel     : NATURAL := 0;
    g_flush_nof_channels      : POSITIVE := 1
    ctlr_ref_clk       : IN    STD_LOGIC;
    ctlr_ref_rst       : IN    STD_LOGIC;

    -- DDR controller clock domain
    ctlr_clk_out       : OUT   STD_LOGIC;
    ctlr_rst_out       : OUT   STD_LOGIC;
    
    ctlr_clk_in        : IN    STD_LOGIC;  -- connect ctlr_clk_out to ctlr_clk_in at top level to avoid potential delta-cycle differences between the same clock
    ctlr_rst_in        : IN    STD_LOGIC;  -- connect ctlr_rst_out to ctlr_rst_in at top level
    
    ctlr_init_done     : OUT   STD_LOGIC;
    ctlr_rdy           : OUT   STD_LOGIC;

    dvr_en             : IN    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_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
    wr_clk             : IN    STD_LOGIC;
    wr_rst             : IN    STD_LOGIC;

    wr_sosi            : IN    t_dp_sosi;
    wr_siso            : OUT   t_dp_siso;
  
    -- Read FIFO clock domain
    rd_clk             : IN    STD_LOGIC;
    rd_rst             : IN    STD_LOGIC;
    
    rd_sosi            : OUT   t_dp_sosi;
    rd_siso            : IN    t_dp_siso;
    
    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);  -- 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_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          : STD_LOGIC := '0';
  SIGNAL wr_fifo_src_in    : t_dp_siso;
  SIGNAL wr_fifo_src_out   : 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 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;
  u_wr_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths
  GENERIC MAP (
    g_wr_data_w         => g_wr_data_w,
    g_use_ctrl          => g_wr_use_ctrl,
    g_wr_fifo_size      => c_wr_fifo_depth,
    g_wr_fifo_af_margin => c_wr_fifo_af_margin,
    g_rd_fifo_rl        => 0
  )
  PORT MAP (
    wr_rst         => wr_rst,
    wr_clk         => wr_clk,
    rd_rst         => ctlr_rst_in,
    rd_clk         => ctlr_clk_in,

    snk_out        => wr_siso,
    snk_in         => wr_sosi,
  
    wr_usedw       => OPEN,
    rd_usedw       => wr_fifo_usedw,
    rd_emp         => OPEN,

  u_dp_flush : ENTITY dp_lib.dp_flush
    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 wr_flush goes high
    src_out  => ctlr_wr_snk_in,
    src_in   => ctlr_wr_snk_out,
  u_io_ddr_driver_flush_ctrl : ENTITY work.io_ddr_driver_flush_ctrl
  GENERIC MAP (
    g_mode          => g_flush_mode,
    g_use_channel   => g_flush_use_channel,
    g_start_channel => g_flush_start_channel,
    g_nof_channels  => g_flush_nof_channels
  )
  PORT MAP (

    dvr_flush_en  => dvr_flush_en,
    dvr_en        => dvr_en,
    dvr_wr_not_rd => dvr_wr_not_rd,
    dvr_done      => i_dvr_done,


  u_rd_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths
  GENERIC MAP (
    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_rd_fifo_af_margin, -- >=4 (required by dp_fifo)
    wr_rst   => ctlr_rst_in,
    wr_clk   => ctlr_clk_in,
    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 (
    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_in       => ctlr_wr_snk_in, 
    rd_src_in       => ctlr_rd_src_in,

    ctlr_init_done  => i_ctlr_init_done,
    ctlr_miso       => ctlr_miso,
    ctlr_mosi       => ctlr_mosi
  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_clk_out,
    ctlr_gen_rst      => ctlr_rst_out,
    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
  );