Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ddr.vhd 32.16 KiB
--------------------------------------------------------------------------------
--
-- Copyright (C) 2011
-- 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, common_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE common_lib.common_pkg.ALL;
USE work.ddr3_pkg.ALL;
USE work.ddr_pkg.ALL; -- more general definitions for DDR3 and DDR4
USE dp_lib.dp_stream_pkg.ALL;

ENTITY ddr IS
  GENERIC(
    g_phy                     : NATURAL := 1;   -- 0: ALTMEMPHY  1: UNIPHY_MASTER 2: UNIPHY_SLAVE 3: ARRIA 10 EMIF
    g_ddr                     : t_c_ddr_phy;    -- contains the width information for the DDR interface records
    g_mts                     : NATURAL := 800; -- Megatransfers per second
    g_wr_data_w               : NATURAL := c_ddr3_ctlr_data_w;  
    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 >c_ddr3_ctlr_maxburstsize                               , defined at read  side of write FIFO.
    g_rd_fifo_depth           : NATURAL := 256;                -- >=16 AND >c_ddr3_ctlr_maxburstsize > c_ddr3_ctrl_nof_latent_reads, defined at write side of read  FIFO. 
    g_rd_data_w               : NATURAL := c_ddr3_ctlr_data_w;
    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_rst           : IN    STD_LOGIC; -- asynchronous reset input to controller

    ctlr_gen_clk       : OUT   STD_LOGIC; -- Controller generated clock
    ctlr_gen_rst       : OUT   STD_LOGIC;    
    ctlr_gen_clk_2x    : OUT   STD_LOGIC; -- Controller generated double frequency clock
    ctlr_gen_rst_2x    : OUT   STD_LOGIC; -- ctlr_gen_rst synchronized to ctlr_gen_clk_2x

    ctlr_init_done     : OUT   STD_LOGIC;
    ctlr_rdy           : OUT   STD_LOGIC;

    dvr_start_addr     : IN    t_ddr3_addr;
    dvr_end_addr       : IN    t_ddr3_addr;

    dvr_en             : IN    STD_LOGIC;
    dvr_wr_not_rd      : IN    STD_LOGIC;
    dvr_done           : OUT   STD_LOGIC;

    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 * (c_ddr3_ctlr_data_w/g_rd_data_w) )-1 DOWNTO 0);
    
    ser_term_ctrl_out  : OUT   STD_LOGIC_VECTOR(13 DOWNTO 0);
    par_term_ctrl_out  : OUT   STD_LOGIC_VECTOR(13 DOWNTO 0);

    ser_term_ctrl_in   : IN    STD_LOGIC_VECTOR(13 DOWNTO 0) := (OTHERS => '0');
    par_term_ctrl_in   : IN    STD_LOGIC_VECTOR(13 DOWNTO 0) := (OTHERS => '0');

    phy_in             : IN    t_ddr3_phy_in;
    phy_io             : INOUT t_ddr3_phy_io;
    phy_ou             : OUT   t_ddr3_phy_ou
   );
END ddr;


ARCHITECTURE str OF ddr IS  
 
  CONSTANT c_wr_fifo_depth : NATURAL := g_wr_fifo_depth * (c_ddr3_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_latency       : NATURAL := 1;

  SIGNAL ctlr_burst        : STD_LOGIC; 
  SIGNAL ctlr_burst_size   : STD_LOGIC_VECTOR(c_ddr3_ctlr_maxburstsize_w-1 DOWNTO 0);
  SIGNAL ctlr_address      : STD_LOGIC_VECTOR(ceil_log2(g_ddr.cs_w-1) + g_ddr.ba_w + g_ddr.bg_w + g_ddr.a_w + g_ddr.a_col_w - c_ddr3_ctlr_rsl_w-1 DOWNTO 0); -- ceil_log2(..-1) because the chip select lines are converted to a logical address
  SIGNAL ctlr_rd_req       : STD_LOGIC;
  SIGNAL ctlr_wr_req       : STD_LOGIC;

  SIGNAL ctlr_rst_n        : STD_LOGIC;
  SIGNAL ctlr_gen_rst_n    : STD_LOGIC;

  SIGNAL i_ctlr_gen_clk    : STD_LOGIC;
  SIGNAL i_ctlr_gen_rst    : STD_LOGIC;
  SIGNAL i_ctlr_gen_clk_2x : STD_LOGIC;
  SIGNAL i_ctlr_init_done  : STD_LOGIC;
  SIGNAL i_ctlr_rdy        : STD_LOGIC;
  SIGNAL i_dvr_done        : STD_LOGIC;

  SIGNAL dvr_cur_addr      : t_ddr3_addr;
  SIGNAL dvr_flush         : STD_LOGIC := '0';
 
  SIGNAL ctlr_wr_siso      : t_dp_siso := c_dp_siso_rdy;  -- default xon='1'
  SIGNAL ctlr_wr_sosi      : t_dp_sosi;

  SIGNAL flush_wr_siso     : t_dp_siso;
  SIGNAL flush_wr_sosi     : t_dp_sosi;

  SIGNAL ctlr_rd_siso      : t_dp_siso;
  SIGNAL ctlr_rd_sosi      : t_dp_sosi;
  
  SIGNAL wr_fifo_usedw     : STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth)-1 DOWNTO 0);  -- read side depth of the write FIFO
  
  -- signals for Arria 10 DDR4
  signal mb_a_internal     : std_logic_vector(g_ddr.a_w-1 DOWNTO 0);

BEGIN 

  dvr_done <= i_dvr_done;

  ctlr_rst_n      <= NOT(ctlr_rst);  
  i_ctlr_gen_rst  <= NOT(ctlr_gen_rst_n);

  ctlr_gen_clk    <= i_ctlr_gen_clk;
  ctlr_gen_rst    <= i_ctlr_gen_rst;
  ctlr_gen_clk_2x <= i_ctlr_gen_clk_2x;   
  ctlr_rdy        <= i_ctlr_rdy;  
  ctlr_init_done  <= i_ctlr_init_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_ddr_local_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         => i_ctlr_gen_rst,
    rd_clk         => i_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      => i_ctlr_gen_rst,
    clk      => i_ctlr_gen_clk,
   
    snk_in   => flush_wr_sosi,
    snk_out  => flush_wr_siso,

    src_out  => ctlr_wr_sosi,
    src_in   => ctlr_wr_siso,  -- fixed streaming xon='1'

    flush_en => dvr_flush      -- memory mapped xon/xoff control
  );

  gen_flush : IF g_flush_wr_fifo = TRUE GENERATE  
    u_flush_ctrl : ENTITY work.ddr3_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_ddr_local_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_ddr3_ctrl_nof_latent_reads, -- >=4 (required by dp_fifo)
    g_rd_fifo_rl        => 1
  )
  PORT MAP (
    wr_rst   => i_ctlr_gen_rst,
    wr_clk   => i_ctlr_gen_clk,
    rd_rst   => rd_rst,
    rd_clk   => rd_clk,

    snk_out  => ctlr_rd_siso,
    snk_in   => ctlr_rd_sosi,
  
    wr_usedw => OPEN,
    rd_usedw => rd_fifo_usedw,
    rd_emp   => OPEN,

    src_in   => rd_siso,
    src_out  => rd_sosi
  );

  u_ddr3_driver : ENTITY work.ddr3_driver
  GENERIC MAP (
    g_wr_fifo_depth => g_wr_fifo_depth,  
    g_ddr           => g_ddr
  )
  PORT MAP ( 
    rst             => i_ctlr_gen_rst,  
    clk             => i_ctlr_gen_clk,        

    ctlr_rdy        => i_ctlr_rdy,
    ctlr_init_done  => i_ctlr_init_done,
    ctlr_wr_req     => ctlr_wr_req,      
    ctlr_rd_req     => ctlr_rd_req,
    ctlr_burst      => ctlr_burst,
    ctlr_burst_size => ctlr_burst_size,

    wr_val          => ctlr_wr_sosi.valid, 
    wr_rdy          => ctlr_wr_siso.ready,
    rd_rdy          => ctlr_rd_siso.ready,

    cur_addr        => dvr_cur_addr,
    start_addr      => dvr_start_addr,
    end_addr        => dvr_end_addr, 

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

    wr_fifo_usedw   => wr_fifo_usedw
  );

  ctlr_address <= dvr_cur_addr.chip & dvr_cur_addr.bank & dvr_cur_addr.row(g_ddr.a_w-1 DOWNTO 0) & dvr_cur_addr.column(g_ddr.a_col_w -1 DOWNTO c_ddr3_ctlr_rsl_w);

  gen_aphy_4g_800 : IF g_mts = 800 AND g_phy = 0 GENERATE
    u_aphy_4g_800 : ENTITY work.aphy_4g_800
    PORT MAP(
      aux_full_rate_clk     => i_ctlr_gen_clk_2x,
      aux_half_rate_clk     => OPEN,
      aux_scan_clk          => OPEN,
      aux_scan_clk_reset_n  => OPEN,
      dll_reference_clk     => OPEN,
      dqs_delay_ctrl_export => OPEN,
      global_reset_n        => ctlr_rst_n,
      local_address         => ctlr_address,
      local_be              => (OTHERS => '1'),
      local_burstbegin      => ctlr_burst,
      local_init_done       => i_ctlr_init_done,
      local_rdata           => ctlr_rd_sosi.data(c_ddr_local_data_w-1 downto 0),
      local_rdata_valid     => ctlr_rd_sosi.valid,
      local_read_req        => ctlr_rd_req,
      local_ready           => i_ctlr_rdy,
      local_refresh_ack     => OPEN,
      local_size            => ctlr_burst_size,
      local_wdata           => ctlr_wr_sosi.data(c_ddr_local_data_w-1 downto 0),
      local_wdata_req       => OPEN,
      local_write_req       => ctlr_wr_req,
  
      mem_addr              => phy_ou.a(g_ddr.a_w-1 DOWNTO 0),
      mem_ba                => phy_ou.ba(g_ddr.ba_w-1 DOWNTO 0),
      mem_cas_n             => phy_ou.cas_n,
      mem_cke               => phy_ou.cke(g_ddr.clk_w-1 DOWNTO 0),
      mem_clk               => phy_io.clk(g_ddr.clk_w-1 DOWNTO 0),
      mem_clk_n             => phy_io.clk_n(g_ddr.clk_w-1 DOWNTO 0),
      mem_cs_n              => phy_ou.cs_n(g_ddr.cs_w-1 DOWNTO 0),
      mem_dm                => phy_ou.dm(g_ddr.dm_w-1 DOWNTO 0),
      mem_dq                => phy_io.dq(g_ddr.dq_w-1 DOWNTO 0),
      mem_dqs               => phy_io.dqs(g_ddr.dqs_w-1 DOWNTO 0),
      mem_dqsn              => phy_io.dqs_n(g_ddr.dqs_w-1 DOWNTO 0),
      mem_odt               => phy_ou.odt(g_ddr.cs_w-1 DOWNTO 0),
      mem_ras_n             => phy_ou.ras_n,
      mem_reset_n           => phy_ou.reset_n,
      mem_we_n              => phy_ou.we_n,
  
      oct_ctl_rs_value      => c_ddr3_phy_oct_rs,
      oct_ctl_rt_value      => c_ddr3_phy_oct_rt,
      phy_clk               => i_ctlr_gen_clk,
      pll_ref_clk           => ctlr_ref_clk,
      reset_phy_clk_n       => ctlr_gen_rst_n,
      reset_request_n       => OPEN,
      soft_reset_n          => '1'
    );   
  END GENERATE;
  
  gen_uphy_4g_800_master : IF g_mts = 800 AND g_phy = 1 GENERATE
    u_uphy_4g_800_master : COMPONENT uphy_4g_800_master 
	   PORT MAP (
	  	pll_ref_clk                => ctlr_ref_clk,                         
	  	global_reset_n             => ctlr_rst_n,                           
	  	soft_reset_n               => '1',                                  
	  	afi_clk                    => i_ctlr_gen_clk,                       
	  	afi_half_clk               => OPEN,                                 
	  	afi_reset_n                => ctlr_gen_rst_n,                       
	  	mem_a                      => phy_ou.a(g_ddr.a_w-1 DOWNTO 0),       
	  	mem_ba                     => phy_ou.ba(g_ddr.ba_w-1 DOWNTO 0),     
	  	mem_ck                     => phy_io.clk(g_ddr.clk_w-1 DOWNTO 0),   
	  	mem_ck_n                   => phy_io.clk_n(g_ddr.clk_w-1 DOWNTO 0), 
	  	mem_cke                    => phy_ou.cke(g_ddr.clk_w-1 DOWNTO 0),   
	  	mem_cs_n                   => phy_ou.cs_n(g_ddr.cs_w-1 DOWNTO 0),   
	  	mem_dm                     => phy_ou.dm(g_ddr.dm_w-1 DOWNTO 0),     
	  	mem_ras_n                  => phy_ou.ras_n,                         
	  	mem_cas_n                  => phy_ou.cas_n,                         
	  	mem_we_n                   => phy_ou.we_n,                          
	  	mem_reset_n                => phy_ou.reset_n,                       
	  	mem_dq                     => phy_io.dq(g_ddr.dq_w-1 DOWNTO 0),     
	  	mem_dqs                    => phy_io.dqs(g_ddr.dqs_w-1 DOWNTO 0),   
	  	mem_dqs_n                  => phy_io.dqs_n(g_ddr.dqs_w-1 DOWNTO 0), 
	  	mem_odt                    => phy_ou.odt(g_ddr.cs_w-1 DOWNTO 0),    
	  	avl_ready                  => i_ctlr_rdy,                           
	  	avl_burstbegin             => ctlr_burst,                           
	  	avl_addr                   => ctlr_address,                         
	  	avl_rdata_valid            => ctlr_rd_sosi.valid,                   
	  	avl_rdata                  => ctlr_rd_sosi.data(c_ddr_local_data_w-1 downto 0),
	  	avl_wdata                  => ctlr_wr_sosi.data(c_ddr_local_data_w-1 downto 0),
	  	avl_be                     => (OTHERS => '1'),                      
	  	avl_read_req               => ctlr_rd_req,                          
	  	avl_write_req              => ctlr_wr_req,                          
	  	avl_size                   => ctlr_burst_size,          
	  	local_init_done            => i_ctlr_init_done,                     
	  	local_cal_success          => OPEN,                                 
	  	local_cal_fail             => OPEN,                                 
	  	oct_rdn                    => phy_in.oct_rdn,                       
	  	oct_rup                    => phy_in.oct_rup,                       
  		seriesterminationcontrol   => ser_term_ctrl_out,                                 
	  	parallelterminationcontrol => par_term_ctrl_out,                                 
	  	pll_mem_clk                => i_ctlr_gen_clk_2x,
      pll_write_clk              => OPEN,
      pll_write_clk_pre_phy_clk  => OPEN,
      pll_addr_cmd_clk           => OPEN,
      pll_locked                 => OPEN,
      pll_avl_clk                => OPEN,
      pll_config_clk             => OPEN,
      dll_delayctrl              => OPEN
	  );    
  END GENERATE;  

  gen_uphy_4g_800_slave : IF g_mts = 800 AND g_phy = 2 GENERATE
    u_uphy_4g_800_slave : COMPONENT uphy_4g_800_slave 
	   PORT MAP (
	  	pll_ref_clk                => ctlr_ref_clk,                         
	  	global_reset_n             => ctlr_rst_n,                           
	  	soft_reset_n               => '1',                                  
	  	afi_clk                    => i_ctlr_gen_clk,                       
	  	afi_half_clk               => OPEN,                                 
	  	afi_reset_n                => ctlr_gen_rst_n,                       
	  	mem_a                      => phy_ou.a(g_ddr.a_w-1 DOWNTO 0),       
	  	mem_ba                     => phy_ou.ba(g_ddr.ba_w-1 DOWNTO 0),     
	  	mem_ck                     => phy_io.clk(g_ddr.clk_w-1 DOWNTO 0),   
	  	mem_ck_n                   => phy_io.clk_n(g_ddr.clk_w-1 DOWNTO 0), 
	  	mem_cke                    => phy_ou.cke(g_ddr.clk_w-1 DOWNTO 0),   
	  	mem_cs_n                   => phy_ou.cs_n(g_ddr.cs_w-1 DOWNTO 0),   
	  	mem_dm                     => phy_ou.dm(g_ddr.dm_w-1 DOWNTO 0),     
	  	mem_ras_n                  => phy_ou.ras_n,                         
	  	mem_cas_n                  => phy_ou.cas_n,                         
	  	mem_we_n                   => phy_ou.we_n,                          
	  	mem_reset_n                => phy_ou.reset_n,                       
	  	mem_dq                     => phy_io.dq(g_ddr.dq_w-1 DOWNTO 0),     
	  	mem_dqs                    => phy_io.dqs(g_ddr.dqs_w-1 DOWNTO 0),   
	  	mem_dqs_n                  => phy_io.dqs_n(g_ddr.dqs_w-1 DOWNTO 0), 
	  	mem_odt                    => phy_ou.odt(g_ddr.cs_w-1 DOWNTO 0),    
	  	avl_ready                  => i_ctlr_rdy,                           
	  	avl_burstbegin             => ctlr_burst,                           
	  	avl_addr                   => ctlr_address,                         
	  	avl_rdata_valid            => ctlr_rd_sosi.valid,                   
	  	avl_rdata                  => ctlr_rd_sosi.data(c_ddr_local_data_w-1 downto 0),
	  	avl_wdata                  => ctlr_wr_sosi.data(c_ddr_local_data_w-1 downto 0),
	  	avl_be                     => (OTHERS => '1'),                      
	  	avl_read_req               => ctlr_rd_req,                          
	  	avl_write_req              => ctlr_wr_req,                          
	  	avl_size                   => ctlr_burst_size,          
	  	local_init_done            => i_ctlr_init_done,                     
	  	local_cal_success          => OPEN,                                 
	  	local_cal_fail             => OPEN,                                 
  		seriesterminationcontrol   => ser_term_ctrl_in,                                 
	  	parallelterminationcontrol => par_term_ctrl_in,                                 
	  	pll_mem_clk                => i_ctlr_gen_clk_2x,
      pll_write_clk              => OPEN,
      pll_write_clk_pre_phy_clk  => OPEN,
      pll_addr_cmd_clk           => OPEN,
      pll_locked                 => OPEN,
      pll_avl_clk                => OPEN,
      pll_config_clk             => OPEN,
      dll_delayctrl              => OPEN
	  );    
  END GENERATE;  

  gen_aphy_4g_1066 : IF g_mts = 1066 AND g_phy = 0 GENERATE  
    u_aphy_4g_1066 : ENTITY work.aphy_4g_1066
    PORT MAP(
      aux_full_rate_clk     => i_ctlr_gen_clk_2x,
      aux_half_rate_clk     => OPEN,
      aux_scan_clk          => OPEN,
      aux_scan_clk_reset_n  => OPEN,
      dll_reference_clk     => OPEN,
      dqs_delay_ctrl_export => OPEN,
      global_reset_n        => ctlr_rst_n,
      local_address         => ctlr_address,
      local_be              => (OTHERS => '1'),
      local_burstbegin      => ctlr_burst,
      local_init_done       => i_ctlr_init_done,
      local_rdata           => ctlr_rd_sosi.data(c_ddr_local_data_w-1 downto 0),
      local_rdata_valid     => ctlr_rd_sosi.valid,
      local_read_req        => ctlr_rd_req,
      local_ready           => i_ctlr_rdy,
      local_refresh_ack     => OPEN,
      local_size            => ctlr_burst_size,
      local_wdata           => ctlr_wr_sosi.data(c_ddr_local_data_w-1 downto 0),
      local_wdata_req       => OPEN,
      local_write_req       => ctlr_wr_req,
  
      mem_addr              => phy_ou.a(g_ddr.a_w-1 DOWNTO 0),
      mem_ba                => phy_ou.ba(g_ddr.ba_w-1 DOWNTO 0),
      mem_cas_n             => phy_ou.cas_n,
      mem_cke               => phy_ou.cke(g_ddr.clk_w-1 DOWNTO 0),
      mem_clk               => phy_io.clk(g_ddr.clk_w-1 DOWNTO 0),
      mem_clk_n             => phy_io.clk_n(g_ddr.clk_w-1 DOWNTO 0),
      mem_cs_n              => phy_ou.cs_n(g_ddr.cs_w-1 DOWNTO 0),
      mem_dm                => phy_ou.dm(g_ddr.dm_w-1 DOWNTO 0),
      mem_dq                => phy_io.dq(g_ddr.dq_w-1 DOWNTO 0),
      mem_dqs               => phy_io.dqs(g_ddr.dqs_w-1 DOWNTO 0),
      mem_dqsn              => phy_io.dqs_n(g_ddr.dqs_w-1 DOWNTO 0),
      mem_odt               => phy_ou.odt(g_ddr.cs_w-1 DOWNTO 0),
      mem_ras_n             => phy_ou.ras_n,
      mem_reset_n           => phy_ou.reset_n,
      mem_we_n              => phy_ou.we_n,
  
      oct_ctl_rs_value      => c_ddr3_phy_oct_rs,
      oct_ctl_rt_value      => c_ddr3_phy_oct_rt,
      phy_clk               => i_ctlr_gen_clk,
      pll_ref_clk           => ctlr_ref_clk,
      reset_phy_clk_n       => ctlr_gen_rst_n,
      reset_request_n       => OPEN,
      soft_reset_n          => '1'
    );   
  END GENERATE;
  
  gen_uphy_4g_1066_master : IF g_mts = 1066 AND g_phy = 1 GENERATE
    u_uphy_4g_1066_master : COMPONENT uphy_4g_1066_master 
	   PORT MAP (
	  	pll_ref_clk                => ctlr_ref_clk,                         
	  	global_reset_n             => ctlr_rst_n,                           
	  	soft_reset_n               => '1',                                  
	  	afi_clk                    => i_ctlr_gen_clk,                       
	  	afi_half_clk               => OPEN,                                 
	  	afi_reset_n                => ctlr_gen_rst_n,                       
	  	mem_a                      => phy_ou.a(g_ddr.a_w-1 DOWNTO 0),       
	  	mem_ba                     => phy_ou.ba(g_ddr.ba_w-1 DOWNTO 0),     
	  	mem_ck                     => phy_io.clk(g_ddr.clk_w-1 DOWNTO 0),   
	  	mem_ck_n                   => phy_io.clk_n(g_ddr.clk_w-1 DOWNTO 0), 
	  	mem_cke                    => phy_ou.cke(g_ddr.clk_w-1 DOWNTO 0),   
	  	mem_cs_n                   => phy_ou.cs_n(g_ddr.cs_w-1 DOWNTO 0),   
	  	mem_dm                     => phy_ou.dm(g_ddr.dm_w-1 DOWNTO 0),     
	  	mem_ras_n                  => phy_ou.ras_n,                         
	  	mem_cas_n                  => phy_ou.cas_n,                         
	  	mem_we_n                   => phy_ou.we_n,                          
	  	mem_reset_n                => phy_ou.reset_n,                       
	  	mem_dq                     => phy_io.dq(g_ddr.dq_w-1 DOWNTO 0),     
	  	mem_dqs                    => phy_io.dqs(g_ddr.dqs_w-1 DOWNTO 0),   
	  	mem_dqs_n                  => phy_io.dqs_n(g_ddr.dqs_w-1 DOWNTO 0), 
	  	mem_odt                    => phy_ou.odt(g_ddr.cs_w-1 DOWNTO 0),    
	  	avl_ready                  => i_ctlr_rdy,                           
	  	avl_burstbegin             => ctlr_burst,                           
	  	avl_addr                   => ctlr_address,                         
	  	avl_rdata_valid            => ctlr_rd_sosi.valid,                   
	  	avl_rdata                  => ctlr_rd_sosi.data(c_ddr_local_data_w-1 downto 0),                                   avl_wdata                  => ctlr_wr_sosi.data(c_ddr_local_data_w-1 downto 0),                                   avl_be                     => (OTHERS => '1'),                      
	  	avl_read_req               => ctlr_rd_req,                          
	  	avl_write_req              => ctlr_wr_req,                          
	  	avl_size                   => ctlr_burst_size,          
	  	local_init_done            => i_ctlr_init_done,                     
	  	local_cal_success          => OPEN,                                 
	  	local_cal_fail             => OPEN,                                 
	  	oct_rdn                    => phy_in.oct_rdn,                       
	  	oct_rup                    => phy_in.oct_rup,                       
  		seriesterminationcontrol   => ser_term_ctrl_out,                                 
	  	parallelterminationcontrol => par_term_ctrl_out,                                 
	  	pll_mem_clk                => i_ctlr_gen_clk_2x,
      pll_write_clk              => OPEN,
      pll_write_clk_pre_phy_clk  => OPEN,
      pll_addr_cmd_clk           => OPEN,
      pll_locked                 => OPEN,
      pll_avl_clk                => OPEN,
      pll_config_clk             => OPEN,
      dll_delayctrl              => OPEN
	  );    
  END GENERATE;  
  
  gen_uphy_4g_1066_slave : IF g_mts = 1066 AND g_phy = 2 GENERATE
    u_uphy_4g_1066_slave : COMPONENT uphy_4g_1066_slave 
	   PORT MAP (
	  	pll_ref_clk                => ctlr_ref_clk,                         
	  	global_reset_n             => ctlr_rst_n,                           
	  	soft_reset_n               => '1',                                  
	  	afi_clk                    => i_ctlr_gen_clk,                       
	  	afi_half_clk               => OPEN,                                 
	  	afi_reset_n                => ctlr_gen_rst_n,                       
	  	mem_a                      => phy_ou.a(g_ddr.a_w-1 DOWNTO 0),       
	  	mem_ba                     => phy_ou.ba(g_ddr.ba_w-1 DOWNTO 0),     
	  	mem_ck                     => phy_io.clk(g_ddr.clk_w-1 DOWNTO 0),   
	  	mem_ck_n                   => phy_io.clk_n(g_ddr.clk_w-1 DOWNTO 0), 
	  	mem_cke                    => phy_ou.cke(g_ddr.clk_w-1 DOWNTO 0),   
	  	mem_cs_n                   => phy_ou.cs_n(g_ddr.cs_w-1 DOWNTO 0),   
	  	mem_dm                     => phy_ou.dm(g_ddr.dm_w-1 DOWNTO 0),     
	  	mem_ras_n                  => phy_ou.ras_n,                         
	  	mem_cas_n                  => phy_ou.cas_n,                         
	  	mem_we_n                   => phy_ou.we_n,                          
	  	mem_reset_n                => phy_ou.reset_n,                       
	  	mem_dq                     => phy_io.dq(g_ddr.dq_w-1 DOWNTO 0),     
	  	mem_dqs                    => phy_io.dqs(g_ddr.dqs_w-1 DOWNTO 0),   
	  	mem_dqs_n                  => phy_io.dqs_n(g_ddr.dqs_w-1 DOWNTO 0), 
	  	mem_odt                    => phy_ou.odt(g_ddr.cs_w-1 DOWNTO 0),    
	  	avl_ready                  => i_ctlr_rdy,                           
	  	avl_burstbegin             => ctlr_burst,                           
	  	avl_addr                   => ctlr_address,                         
	  	avl_rdata_valid            => ctlr_rd_sosi.valid,                   
	  	avl_rdata                  => ctlr_rd_sosi.data(c_ddr_local_data_w-1 downto 0),                   
	  	avl_wdata                  => ctlr_wr_sosi.data(c_ddr_local_data_w-1 downto 0),                    	  	avl_be                     => (OTHERS => '1'),                      
	  	avl_read_req               => ctlr_rd_req,                          
	  	avl_write_req              => ctlr_wr_req,                          
	  	avl_size                   => ctlr_burst_size,          
	  	local_init_done            => i_ctlr_init_done,                     
	  	local_cal_success          => OPEN,                                 
	  	local_cal_fail             => OPEN,                                 
  		seriesterminationcontrol   => ser_term_ctrl_in,                                 
	  	parallelterminationcontrol => par_term_ctrl_in,                                 
	  	pll_mem_clk                => i_ctlr_gen_clk_2x,
      pll_write_clk              => OPEN,
      pll_write_clk_pre_phy_clk  => OPEN,
      pll_addr_cmd_clk           => OPEN,
      pll_locked                 => OPEN,
      pll_avl_clk                => OPEN,
      pll_config_clk             => OPEN,
      dll_delayctrl              => OPEN
	  );    
  END GENERATE;  

  -- DDR4 for Arria 10 with hard EMIF controller
  -- This version uses all the IO pins as in the pinning design

  gen_emif_ddr4_all_1800 : IF g_mts = 1800 AND g_phy = 3 GENERATE

    phy_ou.a <= mb_a_internal(13 downto 0);
    phy_ou.we_a14 <= mb_a_internal(14);
    phy_ou.cas_a15 <= mb_a_internal(15);
    phy_ou.ras_a16 <= mb_a_internal(16);

    u_ddr4 : ddr4_all
    port map (
      global_reset_n      => ctlr_rst_n,   -- reset_n 
      pll_ref_clk         => ctlr_ref_clk, -- Must connect directly to MB_II_REF_CLK pin
      oct_rzqin           => MB_I_RZQ,     -- Direct connection to pin. No separate calibration module
      mem_ck              => phy_io.clk(g_ddr.clk_w-1 DOWNTO 0), -- 2
      mem_ck_n            => phy_io.clk_n(g_ddr.clk_w-1 DOWNTO 0), -- 2
      mem_a               => mb_a_internal, -- 17
      mem_act_n           => phy_ou.act_n(g_ddr.act_w-1 DOWNTO 0), -- 1
      mem_ba              => phy_ou.ba(g_ddr.ba_w-1 DOWNTO 0), -- 2
      mem_bg              => phy_ou.bg(g_ddr.bg_w-1 DOWNTO 0), --2
      mem_cke             => phy_ou.cke(g_ddr.clk_w-1 DOWNTO 0), -- 2
      mem_cs_n            => phy_ou.cs_n(g_ddr.cs_w-1 DOWNTO 0), -- 2
      mem_odt             => phy_ou.odt(g_ddr.odt_w-1 DOWNTO 0), -- 2
      mem_reset_n         => phy_ou.resetarr_n(g_ddr.resetarr_w-1 DOWNTO 0), -- 1
      mem_alert_n         => phy_in.alert_n(g_ddr.alert_w-1 DOWNTO 0), -- 1
      mem_par             => phy_ou.par(g_ddr.par_w-1 DOWNTO 0),
      mem_dqs             => phy_io.dqs(g_ddr.dqs_w-1 DOWNTO 0), -- 9
      mem_dqs_n           => phy_io.dqs_n(g_ddr.dqs_w-1 DOWNTO 0), -- 9
      mem_dq(63 downto 0) => phy_io.dq(g_ddr.dq_w-1 DOWNTO 0), -- 64
      mem_dq(71 downto 64)=> phy_io.cb(g_ddr.cb_w-1 DOWNTO 0), -- 8
      mem_dbi_n           => phy_ou.dm(g_ddr.dm_w-1 DOWNTO 0), -- 9
      local_cal_success   => open,
      local_cal_fail      => open,
      emif_usr_reset_n    => ctlr_gen_rst_n, --local_i_reset_n,
      emif_usr_clk        => i_ctlr_gen_clk, --local_i_clk,
      amm_ready_0         => i_ctlr_rdy, --local_i_ready,
      amm_read_0          => ctlr_rd_req, --local_i_read,
      amm_write_0         => ctlr_wr_req, --local_i_write,
      amm_address_0       => ctlr_address, --local_i_address, - 27
      amm_readdata_0      => ctlr_rd_sosi.data(c_ddr_local_data_w-1 downto 0), --local_i_readdata, -- 576
      amm_writedata_0     => ctlr_wr_sosi.data(c_ddr_local_data_w-1 downto 0), --local_i_writedata, -- 576
      amm_burstcount_0    => ctlr_burst_size, --local_i_burstcount,
      amm_byteenable_0    => (OTHERS => '1'), --local_i_be,
      amm_readdatavalid_0 => ctlr_rd_sosi.valid --local_i_read_data_valid
    );
  end generate;

  gen_emif_ddr4_4g_1600 : IF g_mts = 1600 AND g_phy = 3 GENERATE

    phy_ou.a <= mb_a_internal(13 downto 0);
    phy_ou.we_a14 <= mb_a_internal(14);
    phy_ou.cas_a15 <= mb_a_internal(15);
    phy_ou.ras_a16 <= mb_a_internal(16);

    u_ddr4 : ddr4_4g_1600
    port map (
      global_reset_n      => ctlr_rst_n,   -- reset_n 
      pll_ref_clk         => ctlr_ref_clk, -- Must connect directly to MB_II_REF_CLK pin
      oct_rzqin           => MB_I_RZQ,     -- Direct connection to pin. No separate calibration module
      mem_ck              => phy_io.clk(g_ddr.clk_w-1 DOWNTO 0), -- 2
      mem_ck_n            => phy_io.clk_n(g_ddr.clk_w-1 DOWNTO 0), -- 2
      mem_a               => mb_a_internal, -- 17
      mem_act_n           => phy_ou.act_n(g_ddr.act_w-1 DOWNTO 0), -- 1
      mem_ba              => phy_ou.ba(g_ddr.ba_w-1 DOWNTO 0), -- 2
      mem_bg              => phy_ou.bg(g_ddr.bg_w-1 DOWNTO 0), --2
      mem_cke             => phy_ou.cke(g_ddr.clk_w-1 DOWNTO 0), -- 2
      mem_cs_n            => phy_ou.cs_n(g_ddr.cs_w-1 DOWNTO 0), -- 2
      mem_odt             => phy_ou.odt(g_ddr.odt_w-1 DOWNTO 0), -- 2
      mem_reset_n         => phy_ou.resetarr_n(g_ddr.resetarr_w-1 DOWNTO 0), -- 1
      mem_alert_n         => phy_in.alert_n(g_ddr.alert_w-1 DOWNTO 0), -- 1
      mem_par             => phy_ou.par(g_ddr.par_w-1 DOWNTO 0),
      mem_dqs             => phy_io.dqs(g_ddr.dqs_w-1 DOWNTO 0), -- 9
      mem_dqs_n           => phy_io.dqs_n(g_ddr.dqs_w-1 DOWNTO 0), -- 9
      mem_dq(63 downto 0) => phy_io.dq(g_ddr.dq_w-1 DOWNTO 0), -- 64
      mem_dq(71 downto 64)=> phy_io.cb(g_ddr.cb_w-1 DOWNTO 0), -- 8
      mem_dbi_n           => phy_ou.dm(g_ddr.dm_w-1 DOWNTO 0), -- 9
      local_cal_success   => open,
      local_cal_fail      => open,
      emif_usr_reset_n    => ctlr_gen_rst_n, --local_i_reset_n,
      emif_usr_clk        => i_ctlr_gen_clk, --local_i_clk,
      amm_ready_0         => i_ctlr_rdy, --local_i_ready,
      amm_read_0          => ctlr_rd_req, --local_i_read,
      amm_write_0         => ctlr_wr_req, --local_i_write,
      amm_address_0       => ctlr_address, --local_i_address, - 27
      amm_readdata_0      => ctlr_rd_sosi.data(c_ddr_local_data_w-1 downto 0), --local_i_readdata, -- 576
      amm_writedata_0     => ctlr_wr_sosi.data(c_ddr_local_data_w-1 downto 0), --local_i_writedata, -- 576
      amm_burstcount_0    => ctlr_burst_size, --local_i_burstcount,
      amm_byteenable_0    => (OTHERS => '1'), --local_i_be,
      amm_readdatavalid_0 => ctlr_rd_sosi.valid --local_i_read_data_valid
    );
  end generate;
              
END str;