--------------------------------------------------------------------------------
--
-- 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: DDR3 memory access component for Stratix IV.
-- Description:
-- Remarks:
-- . The local_init_done goes high some time after power up. It could have been
--   AND-ed with ctlr_miso.waitrequest_n. However the timing closure for
--   ctlr_miso.waitrequest_n can be critical, so therefore it is better not
--   to combinatorially load it with the AND local_init_done. Instead a
--   ctlr_miso.done field was added and used to pass on local_init_done.

-- Declare IP libraries to ensure default binding in simulation. The IP library clause is ignored by synthesis.
library ip_stratixiv_ddr3_uphy_4g_800_master_lib;
library ip_stratixiv_ddr3_uphy_4g_800_slave_lib;
library ip_stratixiv_ddr3_uphy_4g_single_rank_800_master_lib;
library ip_stratixiv_ddr3_uphy_4g_single_rank_800_slave_lib;
library ip_stratixiv_ddr3_uphy_16g_dual_rank_800_lib;

library IEEE, technology_lib, common_lib;
use IEEE.std_logic_1164.all;
use common_lib.common_mem_pkg.all;
use technology_lib.technology_pkg.all;
use work.tech_ddr_pkg.all;
use work.tech_ddr_component_pkg.all;

entity tech_ddr_stratixiv is
  generic (
    g_tech_ddr   : t_c_tech_ddr
  );
  port (
    -- PLL reference clock
    ref_clk           : in    std_logic;
    ref_rst           : in    std_logic;

    -- Controller user interface
    ctlr_gen_clk      : out   std_logic;
    ctlr_gen_rst      : out   std_logic;
    ctlr_gen_clk_2x   : out   std_logic;
    ctlr_gen_rst_2x   : out   std_logic;

    ctlr_mosi         : in    t_mem_ctlr_mosi;
    ctlr_miso         : out   t_mem_ctlr_miso;

    term_ctrl_out     : out   t_tech_ddr3_phy_terminationcontrol;
    term_ctrl_in      : in    t_tech_ddr3_phy_terminationcontrol := c_tech_ddr3_phy_terminationcontrol_rst;

    -- PHY interface
    phy_in            : in    t_tech_ddr3_phy_in;
    phy_io            : inout t_tech_ddr3_phy_io;
    phy_ou            : out   t_tech_ddr3_phy_ou
  );
end tech_ddr_stratixiv;

architecture str of tech_ddr_stratixiv is
  constant c_gigabytes             : integer := func_tech_ddr_module_gigabytes(g_tech_ddr);

  constant c_ctlr_address_w        : natural := func_tech_ddr_ctlr_address_w(g_tech_ddr);
  constant c_ctlr_data_w           : natural := func_tech_ddr_ctlr_data_w(   g_tech_ddr);

  signal dbg_c_gigabytes           : integer := c_gigabytes;

  signal ref_rst_n                 : std_logic;
  signal ctlr_gen_rst_n            : std_logic;
  signal i_ctlr_gen_rst            : std_logic;
  signal i_ctlr_gen_clk_2x         : std_logic;

  signal i_mem_cke                 : std_logic;
  signal i_mem_cs_n                : std_logic;
  signal i_mem_odt                 : std_logic;
begin
  ref_rst_n <= not ref_rst;

  gen_ip_stratixiv_ddr3_uphy_4g_800_master : if g_tech_ddr.name = "DDR3" and c_gigabytes = 4 and g_tech_ddr.mts = 800 and g_tech_ddr.master = true and g_tech_ddr.rank = "DUAL  " generate
    u_ip_stratixiv_ddr3_uphy_4g_800_master : ip_stratixiv_ddr3_uphy_4g_800_master
    port map (
      pll_ref_clk                => ref_clk,  -- pll_ref_clk.clk
      global_reset_n             => ref_rst_n,  -- global_reset.reset_n
      soft_reset_n               => '1',  -- soft_reset.reset_n
      afi_clk                    => ctlr_gen_clk,  -- afi_clk.clk
      afi_half_clk               => OPEN,  -- afi_half_clk.clk
      afi_reset_n                => ctlr_gen_rst_n,  -- afi_reset.reset_n
      mem_a                      => phy_ou.a(g_tech_ddr.a_w - 1 downto 0),  -- memory.mem_a
      mem_ba                     => phy_ou.ba(g_tech_ddr.ba_w - 1 downto 0),  -- .mem_ba
      mem_ck                     => phy_ou.ck(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck
      mem_ck_n                   => phy_ou.ck_n(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck_n
      mem_cke                    => phy_ou.cke(g_tech_ddr.cke_w - 1 downto 0),  -- .mem_cke
      mem_cs_n                   => phy_ou.cs_n(g_tech_ddr.cs_w - 1 downto 0),  -- .mem_cs_n
      mem_dm                     => phy_ou.dm(g_tech_ddr.dm_w - 1 downto 0),  -- .mem_dm
      mem_ras_n                  => phy_ou.ras_n,  -- .mem_ras_n
      mem_cas_n                  => phy_ou.cas_n,  -- .mem_cas_n
      mem_we_n                   => phy_ou.we_n,  -- .mem_we_n
      mem_reset_n                => phy_ou.reset_n,  -- .mem_reset_n
      mem_dq                     => phy_io.dq(g_tech_ddr.dq_w - 1 downto 0),  -- .mem_dq
      mem_dqs                    => phy_io.dqs(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs
      mem_dqs_n                  => phy_io.dqs_n(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs_n
      mem_odt                    => phy_ou.odt(g_tech_ddr.odt_w - 1 downto 0),  -- .mem_odt
      avl_ready                  => ctlr_miso.waitrequest_n,  -- avl.waitrequest_n
      avl_burstbegin             => ctlr_mosi.burstbegin,  -- .beginbursttransfer
      avl_addr                   => ctlr_mosi.address(c_ctlr_address_w - 1 downto 0),  -- .address
      avl_rdata_valid            => ctlr_miso.rdval,  -- .readdatavalid
      avl_rdata                  => ctlr_miso.rddata(c_ctlr_data_w - 1 downto 0),  -- .readdata
      avl_wdata                  => ctlr_mosi.wrdata(c_ctlr_data_w - 1 downto 0),  -- .writedata
      avl_be                     => (others => '1'),  -- .byteenable
      avl_read_req               => ctlr_mosi.rd,  -- .read
      avl_write_req              => ctlr_mosi.wr,  -- .write
      avl_size                   => ctlr_mosi.burstsize(g_tech_ddr.maxburstsize_w - 1 downto 0),  -- .burstcount
      local_init_done            => ctlr_miso.done,  -- status.local_init_done
      local_cal_success          => ctlr_miso.cal_ok,  -- .local_cal_success
      local_cal_fail             => ctlr_miso.cal_fail,  -- .local_cal_fail
      oct_rdn                    => phy_in.oct_rdn,  -- oct.rdn
      oct_rup                    => phy_in.oct_rup,  -- .rup
      seriesterminationcontrol   => term_ctrl_out.seriesterminationcontrol,  -- oct_sharing.seriesterminationcontrol
      parallelterminationcontrol => term_ctrl_out.parallelterminationcontrol,  -- .parallelterminationcontrol
      pll_mem_clk                => i_ctlr_gen_clk_2x,  -- pll_sharing.pll_mem_clk
      pll_write_clk              => OPEN,  -- .pll_write_clk
      pll_write_clk_pre_phy_clk  => OPEN,  -- .pll_write_clk_pre_phy_clk
      pll_addr_cmd_clk           => OPEN,  -- .pll_addr_cmd_clk
      pll_locked                 => OPEN,  -- .pll_locked
      pll_avl_clk                => OPEN,  -- .pll_avl_clk
      pll_config_clk             => OPEN,  -- .pll_config_clk
      dll_delayctrl              => open  -- dll_sharing.dll_delayctrl
    );
  end generate;

  gen_ip_stratixiv_ddr3_uphy_4g_800_slave : if g_tech_ddr.name = "DDR3" and c_gigabytes = 4 and g_tech_ddr.mts = 800 and g_tech_ddr.master = false and g_tech_ddr.rank = "DUAL  " generate
    u_ip_stratixiv_ddr3_uphy_4g_800_slave : ip_stratixiv_ddr3_uphy_4g_800_slave
    port map (
      pll_ref_clk                => ref_clk,  -- pll_ref_clk.clk
      global_reset_n             => ref_rst_n,  -- global_reset.reset_n
      soft_reset_n               => '1',  -- soft_reset.reset_n
      afi_clk                    => ctlr_gen_clk,  -- afi_clk.clk
      afi_half_clk               => OPEN,  -- afi_half_clk.clk
      afi_reset_n                => ctlr_gen_rst_n,  -- afi_reset.reset_n
      mem_a                      => phy_ou.a(g_tech_ddr.a_w - 1 downto 0),  -- memory.mem_a
      mem_ba                     => phy_ou.ba(g_tech_ddr.ba_w - 1 downto 0),  -- .mem_ba
      mem_ck                     => phy_ou.ck(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck
      mem_ck_n                   => phy_ou.ck_n(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck_n
      mem_cke                    => phy_ou.cke(g_tech_ddr.cke_w - 1 downto 0),  -- .mem_cke
      mem_cs_n                   => phy_ou.cs_n(g_tech_ddr.cs_w - 1 downto 0),  -- .mem_cs_n
      mem_dm                     => phy_ou.dm(g_tech_ddr.dm_w - 1 downto 0),  -- .mem_dm
      mem_ras_n                  => phy_ou.ras_n,  -- .mem_ras_n
      mem_cas_n                  => phy_ou.cas_n,  -- .mem_cas_n
      mem_we_n                   => phy_ou.we_n,  -- .mem_we_n
      mem_reset_n                => phy_ou.reset_n,  -- .mem_reset_n
      mem_dq                     => phy_io.dq(g_tech_ddr.dq_w - 1 downto 0),  -- .mem_dq
      mem_dqs                    => phy_io.dqs(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs
      mem_dqs_n                  => phy_io.dqs_n(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs_n
      mem_odt                    => phy_ou.odt(g_tech_ddr.odt_w - 1 downto 0),  -- .mem_odt
      avl_ready                  => ctlr_miso.waitrequest_n,  -- avl.waitrequest_n
      avl_burstbegin             => ctlr_mosi.burstbegin,  -- .beginbursttransfer
      avl_addr                   => ctlr_mosi.address(c_ctlr_address_w - 1 downto 0),  -- .address
      avl_rdata_valid            => ctlr_miso.rdval,  -- .readdatavalid
      avl_rdata                  => ctlr_miso.rddata(c_ctlr_data_w - 1 downto 0),  -- .readdata
      avl_wdata                  => ctlr_mosi.wrdata(c_ctlr_data_w - 1 downto 0),  -- .writedata
      avl_be                     => (others => '1'),  -- .byteenable
      avl_read_req               => ctlr_mosi.rd,  -- .read
      avl_write_req              => ctlr_mosi.wr,  -- .write
      avl_size                   => ctlr_mosi.burstsize(g_tech_ddr.maxburstsize_w - 1 downto 0),  -- .burstcount
      local_init_done            => ctlr_miso.done,  -- status.local_init_done
      local_cal_success          => OPEN,  -- .local_cal_success
      local_cal_fail             => OPEN,  -- .local_cal_fail
      seriesterminationcontrol   => term_ctrl_in.seriesterminationcontrol,  -- oct_sharing.seriesterminationcontrol
      parallelterminationcontrol => term_ctrl_in.parallelterminationcontrol,  -- .parallelterminationcontrol
      pll_mem_clk                => i_ctlr_gen_clk_2x,  -- pll_sharing.pll_mem_clk
      pll_write_clk              => OPEN,  -- .pll_write_clk
      pll_write_clk_pre_phy_clk  => OPEN,  -- .pll_write_clk_pre_phy_clk
      pll_addr_cmd_clk           => OPEN,  -- .pll_addr_cmd_clk
      pll_locked                 => OPEN,  -- .pll_locked
      pll_avl_clk                => OPEN,  -- .pll_avl_clk
      pll_config_clk             => OPEN,  -- .pll_config_clk
      dll_delayctrl              => open  -- dll_sharing.dll_delayctrl
    );
  end generate;

  gen_ip_stratixiv_ddr3_uphy_4g_single_rank_800_master : if g_tech_ddr.name = "DDR3" and c_gigabytes = 4 and g_tech_ddr.mts = 800 and g_tech_ddr.master = true and g_tech_ddr.rank = "SINGLE" generate
    u_ip_stratixiv_ddr3_uphy_4g_single_rank_800_master : ip_stratixiv_ddr3_uphy_4g_single_rank_800_master
    port map (
      pll_ref_clk                => ref_clk,  -- pll_ref_clk.clk
      global_reset_n             => ref_rst_n,  -- global_reset.reset_n
      soft_reset_n               => '1',  -- soft_reset.reset_n
      afi_clk                    => ctlr_gen_clk,  -- afi_clk.clk
      afi_half_clk               => OPEN,  -- afi_half_clk.clk
      afi_reset_n                => ctlr_gen_rst_n,  -- afi_reset.reset_n
      mem_a                      => phy_ou.a(g_tech_ddr.a_w - 1 downto 0),  -- memory.mem_a
      mem_ba                     => phy_ou.ba(g_tech_ddr.ba_w - 1 downto 0),  -- .mem_ba
      mem_ck                     => phy_ou.ck(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck
      mem_ck_n                   => phy_ou.ck_n(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck_n
      mem_cke                    => i_mem_cke,  -- .mem_cke
      mem_cs_n                   => i_mem_cs_n,  -- .mem_cs_n
      mem_dm                     => phy_ou.dm(g_tech_ddr.dm_w - 1 downto 0),  -- .mem_dm
      mem_ras_n                  => phy_ou.ras_n,  -- .mem_ras_n
      mem_cas_n                  => phy_ou.cas_n,  -- .mem_cas_n
      mem_we_n                   => phy_ou.we_n,  -- .mem_we_n
      mem_reset_n                => phy_ou.reset_n,  -- .mem_reset_n
      mem_dq                     => phy_io.dq(g_tech_ddr.dq_w - 1 downto 0),  -- .mem_dq
      mem_dqs                    => phy_io.dqs(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs
      mem_dqs_n                  => phy_io.dqs_n(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs_n
      mem_odt                    => i_mem_odt,  -- .mem_odt
      avl_ready                  => ctlr_miso.waitrequest_n,  -- avl.waitrequest_n
      avl_burstbegin             => ctlr_mosi.burstbegin,  -- .beginbursttransfer
      avl_addr                   => ctlr_mosi.address(c_ctlr_address_w - 1 downto 0),  -- .address
      avl_rdata_valid            => ctlr_miso.rdval,  -- .readdatavalid
      avl_rdata                  => ctlr_miso.rddata(c_ctlr_data_w - 1 downto 0),  -- .readdata
      avl_wdata                  => ctlr_mosi.wrdata(c_ctlr_data_w - 1 downto 0),  -- .writedata
      avl_be                     => (others => '1'),  -- .byteenable
      avl_read_req               => ctlr_mosi.rd,  -- .read
      avl_write_req              => ctlr_mosi.wr,  -- .write
      avl_size                   => ctlr_mosi.burstsize(g_tech_ddr.maxburstsize_w - 1 downto 0),  -- .burstcount
      local_init_done            => ctlr_miso.done,  -- status.local_init_done
      local_cal_success          => ctlr_miso.cal_ok,  -- .local_cal_success
      local_cal_fail             => ctlr_miso.cal_fail,  -- .local_cal_fail
      oct_rdn                    => phy_in.oct_rdn,  -- oct.rdn
      oct_rup                    => phy_in.oct_rup,  -- .rup
      seriesterminationcontrol   => term_ctrl_out.seriesterminationcontrol,  -- oct_sharing.seriesterminationcontrol
      parallelterminationcontrol => term_ctrl_out.parallelterminationcontrol,  -- .parallelterminationcontrol
      pll_mem_clk                => i_ctlr_gen_clk_2x,  -- pll_sharing.pll_mem_clk
      pll_write_clk              => OPEN,  -- .pll_write_clk
      pll_write_clk_pre_phy_clk  => OPEN,  -- .pll_write_clk_pre_phy_clk
      pll_addr_cmd_clk           => OPEN,  -- .pll_addr_cmd_clk
      pll_locked                 => OPEN,  -- .pll_locked
      pll_avl_clk                => OPEN,  -- .pll_avl_clk
      pll_config_clk             => OPEN,  -- .pll_config_clk
      dll_delayctrl              => open  -- dll_sharing.dll_delayctrl
    );

  phy_ou.cke(0)  <= i_mem_cke;
  phy_ou.cs_n(0) <= i_mem_cs_n;
  phy_ou.odt(0)  <= i_mem_odt;
  end generate;

  gen_ip_stratixiv_ddr3_uphy_4g_single_rank_800_slave : if g_tech_ddr.name = "DDR3" and c_gigabytes = 4 and g_tech_ddr.mts = 800 and g_tech_ddr.master = false and g_tech_ddr.rank = "SINGLE" generate
    u_ip_stratixiv_ddr3_uphy_4g_single_rank_800_slave : ip_stratixiv_ddr3_uphy_4g_single_rank_800_slave
    port map (
      pll_ref_clk                => ref_clk,  -- pll_ref_clk.clk
      global_reset_n             => ref_rst_n,  -- global_reset.reset_n
      soft_reset_n               => '1',  -- soft_reset.reset_n
      afi_clk                    => ctlr_gen_clk,  -- afi_clk.clk
      afi_half_clk               => OPEN,  -- afi_half_clk.clk
      afi_reset_n                => ctlr_gen_rst_n,  -- afi_reset.reset_n
      mem_a                      => phy_ou.a(g_tech_ddr.a_w - 1 downto 0),  -- memory.mem_a
      mem_ba                     => phy_ou.ba(g_tech_ddr.ba_w - 1 downto 0),  -- .mem_ba
      mem_ck                     => phy_ou.ck(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck
      mem_ck_n                   => phy_ou.ck_n(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck_n
      mem_cke                    => i_mem_cke,  -- .mem_cke
      mem_cs_n                   => i_mem_cs_n,  -- .mem_cs_n
      mem_dm                     => phy_ou.dm(g_tech_ddr.dm_w - 1 downto 0),  -- .mem_dm
      mem_ras_n                  => phy_ou.ras_n,  -- .mem_ras_n
      mem_cas_n                  => phy_ou.cas_n,  -- .mem_cas_n
      mem_we_n                   => phy_ou.we_n,  -- .mem_we_n
      mem_reset_n                => phy_ou.reset_n,  -- .mem_reset_n
      mem_dq                     => phy_io.dq(g_tech_ddr.dq_w - 1 downto 0),  -- .mem_dq
      mem_dqs                    => phy_io.dqs(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs
      mem_dqs_n                  => phy_io.dqs_n(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs_n
      mem_odt                    => i_mem_odt,  -- .mem_odt
      avl_ready                  => ctlr_miso.waitrequest_n,  -- avl.waitrequest_n
      avl_burstbegin             => ctlr_mosi.burstbegin,  -- .beginbursttransfer
      avl_addr                   => ctlr_mosi.address(c_ctlr_address_w - 1 downto 0),  -- .address
      avl_rdata_valid            => ctlr_miso.rdval,  -- .readdatavalid
      avl_rdata                  => ctlr_miso.rddata(c_ctlr_data_w - 1 downto 0),  -- .readdata
      avl_wdata                  => ctlr_mosi.wrdata(c_ctlr_data_w - 1 downto 0),  -- .writedata
      avl_be                     => (others => '1'),  -- .byteenable
      avl_read_req               => ctlr_mosi.rd,  -- .read
      avl_write_req              => ctlr_mosi.wr,  -- .write
      avl_size                   => ctlr_mosi.burstsize(g_tech_ddr.maxburstsize_w - 1 downto 0),  -- .burstcount
      local_init_done            => ctlr_miso.done,  -- status.local_init_done
      local_cal_success          => OPEN,  -- .local_cal_success
      local_cal_fail             => OPEN,  -- .local_cal_fail
      seriesterminationcontrol   => term_ctrl_in.seriesterminationcontrol,  -- oct_sharing.seriesterminationcontrol
      parallelterminationcontrol => term_ctrl_in.parallelterminationcontrol,  -- .parallelterminationcontrol
      pll_mem_clk                => i_ctlr_gen_clk_2x,  -- pll_sharing.pll_mem_clk
      pll_write_clk              => OPEN,  -- .pll_write_clk
      pll_write_clk_pre_phy_clk  => OPEN,  -- .pll_write_clk_pre_phy_clk
      pll_addr_cmd_clk           => OPEN,  -- .pll_addr_cmd_clk
      pll_locked                 => OPEN,  -- .pll_locked
      pll_avl_clk                => OPEN,  -- .pll_avl_clk
      pll_config_clk             => OPEN,  -- .pll_config_clk
      dll_delayctrl              => open  -- dll_sharing.dll_delayctrl
    );

  phy_ou.cke(0)  <= i_mem_cke;
  phy_ou.cs_n(0) <= i_mem_cs_n;
  phy_ou.odt(0)  <= i_mem_odt;
  end generate;

  gen_ip_stratixiv_ddr3_uphy_16g_dual_rank_800 : if g_tech_ddr.name = "DDR3" and c_gigabytes = 16 and g_tech_ddr.mts = 800 and g_tech_ddr.master = true and g_tech_ddr.rank = "DUAL  " generate
    u_ip_stratixiv_ddr3_uphy_16g_dual_rank_800 : ip_stratixiv_ddr3_uphy_16g_dual_rank_800
    port map (
      pll_ref_clk                => ref_clk,  -- pll_ref_clk.clk
      global_reset_n             => ref_rst_n,  -- global_reset.reset_n
      soft_reset_n               => '1',  -- soft_reset.reset_n
      afi_clk                    => ctlr_gen_clk,  -- afi_clk.clk
      afi_half_clk               => OPEN,  -- afi_half_clk.clk
      afi_reset_n                => ctlr_gen_rst_n,  -- afi_reset.reset_n
      mem_a                      => phy_ou.a(g_tech_ddr.a_w - 1 downto 0),  -- memory.mem_a
      mem_ba                     => phy_ou.ba(g_tech_ddr.ba_w - 1 downto 0),  -- .mem_ba
      mem_ck                     => phy_ou.ck(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck
      mem_ck_n                   => phy_ou.ck_n(g_tech_ddr.ck_w - 1 downto 0),  -- .mem_ck_n
      mem_cke                    => phy_ou.cke(g_tech_ddr.cke_w - 1 downto 0),  -- .mem_cke
      mem_cs_n                   => phy_ou.cs_n(g_tech_ddr.cs_w - 1 downto 0),  -- .mem_cs_n
      mem_dm                     => phy_ou.dm(g_tech_ddr.dm_w - 1 downto 0),  -- .mem_dm
      mem_ras_n                  => phy_ou.ras_n,  -- .mem_ras_n
      mem_cas_n                  => phy_ou.cas_n,  -- .mem_cas_n
      mem_we_n                   => phy_ou.we_n,  -- .mem_we_n
      mem_reset_n                => phy_ou.reset_n,  -- .mem_reset_n
      mem_dq                     => phy_io.dq(g_tech_ddr.dq_w - 1 downto 0),  -- .mem_dq
      mem_dqs                    => phy_io.dqs(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs
      mem_dqs_n                  => phy_io.dqs_n(g_tech_ddr.dqs_w - 1 downto 0),  -- .mem_dqs_n
      mem_odt                    => phy_ou.odt(g_tech_ddr.odt_w - 1 downto 0),  -- .mem_odt
      avl_ready                  => ctlr_miso.waitrequest_n,  -- avl.waitrequest_n
      avl_burstbegin             => ctlr_mosi.burstbegin,  -- .beginbursttransfer
      avl_addr                   => ctlr_mosi.address(c_ctlr_address_w - 1 downto 0),  -- .address
      avl_rdata_valid            => ctlr_miso.rdval,  -- .readdatavalid
      avl_rdata                  => ctlr_miso.rddata(c_ctlr_data_w - 1 downto 0),  -- .readdata
      avl_wdata                  => ctlr_mosi.wrdata(c_ctlr_data_w - 1 downto 0),  -- .writedata
      avl_be                     => (others => '1'),  -- .byteenable
      avl_read_req               => ctlr_mosi.rd,  -- .read
      avl_write_req              => ctlr_mosi.wr,  -- .write
      avl_size                   => ctlr_mosi.burstsize(g_tech_ddr.maxburstsize_w - 1 downto 0),  -- .burstcount
      local_init_done            => ctlr_miso.done,  -- status.local_init_done
      local_cal_success          => ctlr_miso.cal_ok,  -- .local_cal_success
      local_cal_fail             => ctlr_miso.cal_fail,  -- .local_cal_fail
      oct_rdn                    => phy_in.oct_rdn,  -- oct.rdn
      oct_rup                    => phy_in.oct_rup,  -- .rup
      seriesterminationcontrol   => term_ctrl_out.seriesterminationcontrol,  -- oct_sharing.seriesterminationcontrol
      parallelterminationcontrol => term_ctrl_out.parallelterminationcontrol,  -- .parallelterminationcontrol
      pll_mem_clk                => i_ctlr_gen_clk_2x,  -- pll_sharing.pll_mem_clk
      pll_write_clk              => OPEN,  -- .pll_write_clk
      pll_write_clk_pre_phy_clk  => OPEN,  -- .pll_write_clk_pre_phy_clk
      pll_addr_cmd_clk           => OPEN,  -- .pll_addr_cmd_clk
      pll_locked                 => OPEN,  -- .pll_locked
      pll_avl_clk                => OPEN,  -- .pll_avl_clk
      pll_config_clk             => OPEN,  -- .pll_config_clk
      dll_delayctrl              => open  -- dll_sharing.dll_delayctrl
    );
  end generate;

  i_ctlr_gen_rst <= not ctlr_gen_rst_n;

  u_async_ctlr_gen_rst_2x: entity common_lib.common_async
  generic map(
    g_rst_level => '0'
  )
  port map(
    rst  => ref_rst,
    clk  => i_ctlr_gen_clk_2x,
    din  => i_ctlr_gen_rst,
    dout => ctlr_gen_rst_2x
  );

  ctlr_gen_rst    <= i_ctlr_gen_rst;
  ctlr_gen_clk_2x <= i_ctlr_gen_clk_2x;
end str;