--------------------------------------------------------------------------------
--
-- 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/>.
--
--------------------------------------------------------------------------------

-- 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 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
    ctlr_ref_clk      : IN    STD_LOGIC;
    ctlr_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_init_done    : OUT   STD_LOGIC;

    ctlr_mosi         : IN    t_mem_ctlr_mosi;
    ctlr_miso         : OUT   t_mem_ctlr_miso;

    -- PHY interface
    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 tech_ddr_stratixiv;


ARCHITECTURE str OF tech_ddr_stratixiv IS

  CONSTANT c_gigabytes             : NATURAL := func_tech_ddr_module_size(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           : NATURAL := c_gigabytes;
  
  SIGNAL ctlr_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;

BEGIN

  ctlr_ref_rst_n <= NOT ctlr_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 GENERATE
    u_ip_stratixiv_ddr3_uphy_4g_800_master : ip_stratixiv_ddr3_uphy_4g_800_master
    PORT MAP (
      pll_ref_clk                => ctlr_ref_clk,                                                                   --  pll_ref_clk.clk
      global_reset_n             => ctlr_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_init_done,                                                                 --       status.local_init_done
      local_cal_success          => OPEN,                                                                           --             .local_cal_success
      local_cal_fail             => OPEN,                                                                           --             .local_cal_fail
      oct_rdn                    => phy_in.oct_rdn,                                                                 --          oct.rdn
      oct_rup                    => phy_in.oct_rup,                                                                 --             .rup
      seriesterminationcontrol   => phy_ou.seriesterminationcontrol(g_tech_ddr.terminationcontrol_w-1 DOWNTO 0),    --  oct_sharing.seriesterminationcontrol
      parallelterminationcontrol => phy_ou.parallelterminationcontrol(g_tech_ddr.terminationcontrol_w-1 DOWNTO 0),  --             .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 GENERATE
    u_ip_stratixiv_ddr3_uphy_4g_800_slave : ip_stratixiv_ddr3_uphy_4g_800_slave
    PORT MAP (
      pll_ref_clk                => ctlr_ref_clk,                                                                   --  pll_ref_clk.clk
      global_reset_n             => ctlr_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_init_done,                                                                 --       status.local_init_done
      local_cal_success          => OPEN,                                                                           --             .local_cal_success
      local_cal_fail             => OPEN,                                                                           --             .local_cal_fail
      seriesterminationcontrol   => phy_in.seriesterminationcontrol(g_tech_ddr.terminationcontrol_w-1 DOWNTO 0),    --  oct_sharing.seriesterminationcontrol
      parallelterminationcontrol => phy_in.parallelterminationcontrol(g_tech_ddr.terminationcontrol_w-1 DOWNTO 0),  --             .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  => ctlr_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;