//*****************************************************************************
// (c) Copyright 2008 - 2012 Xilinx, Inc. All rights reserved.
//
// This file contains confidential and proprietary information
// of Xilinx, Inc. and is protected under U.S. and
// international copyright and other intellectual property
// laws.
//
// DISCLAIMER
// This disclaimer is not a license and does not grant any
// rights to the materials distributed herewith. Except as
// otherwise provided in a valid license issued to you by
// Xilinx, and to the maximum extent permitted by applicable
// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
// (2) Xilinx shall not be liable (whether in contract or tort,
// including negligence, or under any other theory of
// liability) for any loss or damage of any kind or nature
// related to, arising under or in connection with these
// materials, including for any direct, or any indirect,
// special, incidental, or consequential loss or damage
// (including loss of data, profits, goodwill, or any type of
// loss or damage suffered as a result of any action brought
// by a third party) even if such damage or loss was
// reasonably foreseeable or Xilinx had been advised of the
// possibility of the same.
//
// CRITICAL APPLICATIONS
// Xilinx products are not designed or intended to be fail-
// safe, or for use in any application requiring fail-safe
// performance, such as life-support or safety devices or
// systems, Class III medical devices, nuclear facilities,
// applications related to the deployment of airbags, or any
// other applications that could lead to death, personal
// injury, or severe property or environmental damage
// (individually and collectively, "Critical
// Applications"). Customer assumes the sole risk and
// liability of any use of Xilinx products in Critical
// Applications, subject only to applicable laws and
// regulations governing limitations on product liability.
//
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
// PART OF THIS FILE AT ALL TIMES.
//
//*****************************************************************************
//   ____  ____
//  /   /\/   /
// /___/  \  /    Vendor                : Xilinx
// \   \   \/     Version               : %version
//  \   \         Application           : MIG
//  /   /         Filename              : ddr_mc_phy_wrapper.v
// /___/   /\     Date Last Modified    : $date$
// \   \  /  \    Date Created          : Oct 10 2010
//  \___\/\___\
//
//Device            : 7 Series
//Design Name       : DDR3 SDRAM
//Purpose           : Wrapper file that encompasses the MC_PHY module
//                    instantiation and handles the vector remapping between
//                    the MC_PHY ports and the user's DDR3 ports. Vector
//                    remapping affects DDR3 control, address, and DQ/DQS/DM. 
//Reference         :
//Revision History  :
//*****************************************************************************

`timescale 1 ps / 1 ps

module mig_7series_v1_8_ddr_mc_phy_wrapper #
  (
   parameter TCQ              = 100,    // Register delay (simulation only)
   parameter tCK              = 2500,   // ps
   parameter BANK_TYPE        = "HP_IO", // # = "HP_IO", "HPL_IO", "HR_IO", "HRL_IO"
   parameter DATA_IO_PRIM_TYPE = "DEFAULT", // # = "HP_LP", "HR_LP", "DEFAULT"
   parameter DATA_IO_IDLE_PWRDWN = "ON",  // "ON" or "OFF"
   parameter IODELAY_GRP      = "IODELAY_MIG",
   parameter nCK_PER_CLK      = 4,      // Memory:Logic clock ratio
   parameter nCS_PER_RANK     = 1,      // # of unique CS outputs per rank
   parameter BANK_WIDTH       = 3,      // # of bank address
   parameter CKE_WIDTH        = 1,      // # of clock enable outputs 
   parameter CS_WIDTH         = 1,      // # of chip select
   parameter CK_WIDTH         = 1,      // # of CK
   parameter CWL              = 5,      // CAS Write latency
   parameter DDR2_DQSN_ENABLE = "YES",  // Enable differential DQS for DDR2
   parameter DM_WIDTH         = 8,      // # of data mask
   parameter DQ_WIDTH         = 16,     // # of data bits
   parameter DQS_CNT_WIDTH    = 3,      // ceil(log2(DQS_WIDTH))
   parameter DQS_WIDTH        = 8,      // # of strobe pairs
   parameter DRAM_TYPE        = "DDR3", // DRAM type (DDR2, DDR3)
   parameter RANKS            = 4,      // # of ranks
   parameter ODT_WIDTH        = 1,      // # of ODT outputs
   parameter REG_CTRL         = "OFF",  // "ON" for registered DIMM
   parameter ROW_WIDTH        = 16,     // # of row/column address
   parameter USE_CS_PORT      = 1,      // Support chip select output 
   parameter USE_DM_PORT      = 1,      // Support data mask output
   parameter USE_ODT_PORT     = 1,      // Support ODT output
   parameter IBUF_LPWR_MODE   = "OFF",  // input buffer low power option
   parameter LP_DDR_CK_WIDTH  = 2,

   // Hard PHY parameters
   parameter PHYCTL_CMD_FIFO = "FALSE",
   parameter DATA_CTL_B0     = 4'hc,
   parameter DATA_CTL_B1     = 4'hf,
   parameter DATA_CTL_B2     = 4'hf,
   parameter DATA_CTL_B3     = 4'hf,
   parameter DATA_CTL_B4     = 4'hf,
   parameter BYTE_LANES_B0   = 4'b1111,
   parameter BYTE_LANES_B1   = 4'b0000,
   parameter BYTE_LANES_B2   = 4'b0000,
   parameter BYTE_LANES_B3   = 4'b0000,
   parameter BYTE_LANES_B4   = 4'b0000,
   parameter PHY_0_BITLANES  = 48'h0000_0000_0000,
   parameter PHY_1_BITLANES  = 48'h0000_0000_0000,
   parameter PHY_2_BITLANES  = 48'h0000_0000_0000,
   // Parameters calculated outside of this block
   parameter HIGHEST_BANK    = 3,        // Highest I/O bank index
   parameter HIGHEST_LANE    = 12,       // Highest byte lane index
   // ** Pin mapping parameters
   // Parameters for mapping between hard PHY and physical DDR3 signals
   // There are 2 classes of parameters:
   //   - DQS_BYTE_MAP, CK_BYTE_MAP, CKE_ODT_BYTE_MAP: These consist of 
   //      8-bit elements. Each element indicates the bank and byte lane 
   //      location of that particular signal. The bit lane in this case 
   //      doesn't need to be specified, either because there's only one 
   //      pin pair in each byte lane that the DQS or CK pair can be 
   //      located at, or in the case of CKE_ODT_BYTE_MAP, only the byte
   //      lane needs to be specified in order to determine which byte
   //      lane generates the RCLK (Note that CKE, and ODT must be located
   //      in the same bank, thus only one element in CKE_ODT_BYTE_MAP)
   //        [7:4] = bank # (0-4)
   //        [3:0] = byte lane # (0-3)
   //   - All other MAP parameters: These consist of 12-bit elements. Each
   //      element indicates the bank, byte lane, and bit lane location of
   //      that particular signal:
   //        [11:8] = bank # (0-4)
   //        [7:4]  = byte lane # (0-3)
   //        [3:0]  = bit lane # (0-11)
   // Note that not all elements in all parameters will be used - it 
   // depends on the actual widths of the DDR3 buses. The parameters are 
   // structured to support a maximum of: 
   //   - DQS groups: 18
   //   - data mask bits: 18
   // In addition, the default parameter size of some of the parameters will
   // support a certain number of bits, however, this can be expanded at 
   // compile time by expanding the width of the vector passed into this 
   // parameter
   //   - chip selects: 10
   //   - bank bits: 3
   //   - address bits: 16
   parameter CK_BYTE_MAP
     = 144'h00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00,
   parameter ADDR_MAP    
     = 192'h000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000,
   parameter BANK_MAP   = 36'h000_000_000,
   parameter CAS_MAP    = 12'h000,
   parameter CKE_ODT_BYTE_MAP = 8'h00,
   parameter CKE_MAP    = 96'h000_000_000_000_000_000_000_000,
   parameter ODT_MAP    = 96'h000_000_000_000_000_000_000_000,
   parameter CKE_ODT_AUX = "FALSE",
   parameter CS_MAP     = 120'h000_000_000_000_000_000_000_000_000_000,
   parameter PARITY_MAP = 12'h000,
   parameter RAS_MAP    = 12'h000,
   parameter WE_MAP     = 12'h000,
   parameter DQS_BYTE_MAP         
     = 144'h00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00,
   // DATAx_MAP parameter is used for byte lane X in the design
   parameter DATA0_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA1_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA2_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA3_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA4_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA5_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA6_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA7_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA8_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA9_MAP  = 96'h000_000_000_000_000_000_000_000,
   parameter DATA10_MAP = 96'h000_000_000_000_000_000_000_000,
   parameter DATA11_MAP = 96'h000_000_000_000_000_000_000_000,
   parameter DATA12_MAP = 96'h000_000_000_000_000_000_000_000,
   parameter DATA13_MAP = 96'h000_000_000_000_000_000_000_000,
   parameter DATA14_MAP = 96'h000_000_000_000_000_000_000_000,
   parameter DATA15_MAP = 96'h000_000_000_000_000_000_000_000,
   parameter DATA16_MAP = 96'h000_000_000_000_000_000_000_000,
   parameter DATA17_MAP = 96'h000_000_000_000_000_000_000_000,
   // MASK0_MAP used for bytes [8:0], MASK1_MAP for bytes [17:9]
   parameter MASK0_MAP  = 108'h000_000_000_000_000_000_000_000_000,
   parameter MASK1_MAP  = 108'h000_000_000_000_000_000_000_000_000,
   // Simulation options
   parameter SIM_CAL_OPTION  = "NONE",

   // The PHY_CONTROL primitive in the bank where PLL exists is declared
   // as the Master PHY_CONTROL.
   parameter MASTER_PHY_CTL  = 1
  )
  (
   input                               rst,
   input                               clk,
   input                               freq_refclk,
   input                               mem_refclk,
   input                               pll_lock,
   input                               sync_pulse,
   input                               idelayctrl_refclk,
   input                               phy_cmd_wr_en,
   input                               phy_data_wr_en,
   input [31:0]                        phy_ctl_wd,
   input                               phy_ctl_wr,
   input                               phy_if_empty_def,
   input                               phy_if_reset,
   input [5:0]                         data_offset_1,
   input [5:0]                         data_offset_2,
   input [3:0]                         aux_in_1,
   input [3:0]                         aux_in_2,
   output [4:0]                        idelaye2_init_val,
   output [5:0]                        oclkdelay_init_val,
   output                              if_empty,
   output                              phy_ctl_full,
   output                              phy_cmd_full,
   output                              phy_data_full,
   output                              phy_pre_data_a_full,
   output [(CK_WIDTH * LP_DDR_CK_WIDTH)-1:0] ddr_clk,
   output                              phy_mc_go,          
   input                               phy_write_calib,
   input                               phy_read_calib,
   input                               calib_in_common,
   input [5:0]                         calib_sel,
   input [HIGHEST_BANK-1:0]            calib_zero_inputs,
   input [HIGHEST_BANK-1:0]            calib_zero_ctrl,
   input [2:0]                         po_fine_enable,
   input [2:0]                         po_coarse_enable,
   input [2:0]                         po_fine_inc,
   input [2:0]                         po_coarse_inc,
   input                               po_counter_load_en,
   input                               po_counter_read_en,
   input [2:0]                         po_sel_fine_oclk_delay,
   input [8:0]                         po_counter_load_val,
   output [8:0]                        po_counter_read_val,
   output [5:0]                        pi_counter_read_val,
   input [HIGHEST_BANK-1:0]            pi_rst_dqs_find,
   input                               pi_fine_enable,
   input                               pi_fine_inc,
   input                               pi_counter_load_en,
   input [5:0]                         pi_counter_load_val,
   input                               idelay_ce,
   input                               idelay_inc,
   input                               idelay_ld,
   input                               idle,
   output                              pi_phase_locked,
   output                              pi_phase_locked_all,
   output                              pi_dqs_found,
   output                              pi_dqs_found_all,
   output                              pi_dqs_out_of_range,
   // From/to calibration logic/soft PHY
   input                                         phy_init_data_sel,
   input [nCK_PER_CLK*ROW_WIDTH-1:0]             mux_address,
   input [nCK_PER_CLK*BANK_WIDTH-1:0]            mux_bank, 
   input [nCK_PER_CLK-1:0]                       mux_cas_n,
   input [CS_WIDTH*nCS_PER_RANK*nCK_PER_CLK-1:0] mux_cs_n,
   input [nCK_PER_CLK-1:0]                       mux_ras_n,
   input [1:0]                                   mux_odt,
   input [nCK_PER_CLK-1:0]                       mux_cke, 
   input [nCK_PER_CLK-1:0]                       mux_we_n,   
   input [nCK_PER_CLK-1:0]                       parity_in,
   input [2*nCK_PER_CLK*DQ_WIDTH-1:0]            mux_wrdata,
   input [2*nCK_PER_CLK*(DQ_WIDTH/8)-1:0]        mux_wrdata_mask,   
   input                                         mux_reset_n,
   output [2*nCK_PER_CLK*DQ_WIDTH-1:0]           rd_data,
   // Memory I/F
   output [ROW_WIDTH-1:0]                        ddr_addr,
   output [BANK_WIDTH-1:0]                       ddr_ba,
   output                                        ddr_cas_n,
   output [CKE_WIDTH-1:0]                        ddr_cke,
   output [CS_WIDTH*nCS_PER_RANK-1:0]            ddr_cs_n,
   output [DM_WIDTH-1:0]                         ddr_dm,
   output [ODT_WIDTH-1:0]                        ddr_odt,
   output                                        ddr_parity,
   output                                        ddr_ras_n,
   output                                        ddr_we_n,
   output                                        ddr_reset_n,
   inout [DQ_WIDTH-1:0]                          ddr_dq,
   inout [DQS_WIDTH-1:0]                         ddr_dqs,
   inout [DQS_WIDTH-1:0]                         ddr_dqs_n
   
   ,input                                        dbg_pi_counter_read_en
   ,output                                       ref_dll_lock
   ,input                                        rst_phaser_ref
   ,output [11:0]                                dbg_pi_phase_locked_phy4lanes
   ,output [11:0]                                dbg_pi_dqs_found_lanes_phy4lanes
   );
  
  function [71:0] generate_bytelanes_ddr_ck;
    input [143:0] ck_byte_map;
    integer v ;
    begin
      generate_bytelanes_ddr_ck = 'b0 ;
      for (v = 0; v < CK_WIDTH; v = v + 1) begin
        if ((CK_BYTE_MAP[((v*8)+4)+:4]) == 2)
          generate_bytelanes_ddr_ck[48+(4*v)+1*(CK_BYTE_MAP[(v*8)+:4])] = 1'b1;
        else if ((CK_BYTE_MAP[((v*8)+4)+:4]) == 1)
          generate_bytelanes_ddr_ck[24+(4*v)+1*(CK_BYTE_MAP[(v*8)+:4])] = 1'b1;
        else
          generate_bytelanes_ddr_ck[4*v+1*(CK_BYTE_MAP[(v*8)+:4])] = 1'b1;
      end
    end
  endfunction

  function [(2*CK_WIDTH*8)-1:0] generate_ddr_ck_map;
    input [143:0] ck_byte_map;
    integer g;
    begin
      generate_ddr_ck_map = 'b0 ;
      for(g = 0 ; g < CK_WIDTH ; g= g + 1) begin
        generate_ddr_ck_map[(g*2*8)+:8]  = (ck_byte_map[(g*8)+:4] == 4'd0) ? "A" :
                                           (ck_byte_map[(g*8)+:4] == 4'd1) ? "B" :  
                                           (ck_byte_map[(g*8)+:4] == 4'd2) ? "C" : "D" ;
        generate_ddr_ck_map[(((g*2)+1)*8)+:8] = (ck_byte_map[((g*8)+4)+:4] == 4'd0) ? "0" :
                                                (ck_byte_map[((g*8)+4)+:4] == 4'd1) ? "1" :  "2" ; //each STRING charater takes 0 location
      end
    end  
  endfunction



  // Enable low power mode for input buffer
  localparam IBUF_LOW_PWR
             = (IBUF_LPWR_MODE == "OFF") ? "FALSE" :
             ((IBUF_LPWR_MODE == "ON")  ? "TRUE" : "ILLEGAL");

  // Ratio of data to strobe
  localparam DQ_PER_DQS = DQ_WIDTH / DQS_WIDTH;
  // number of data phases per internal clock
  localparam PHASE_PER_CLK = 2*nCK_PER_CLK;
  // used to determine routing to OUT_FIFO for control/address for 2:1
  // vs. 4:1 memory:internal clock ratio modes
  localparam PHASE_DIV = 4 / nCK_PER_CLK;
  
  localparam CLK_PERIOD = tCK * nCK_PER_CLK;

  // Create an aggregate parameters for data mapping to reduce # of generate
  // statements required in remapping code. Need to account for the case
  // when the DQ:DQS ratio is not 8:1 - in this case, each DATAx_MAP 
  // parameter will have fewer than 8 elements used 
  localparam FULL_DATA_MAP = {DATA17_MAP[12*DQ_PER_DQS-1:0], 
                              DATA16_MAP[12*DQ_PER_DQS-1:0], 
                              DATA15_MAP[12*DQ_PER_DQS-1:0], 
                              DATA14_MAP[12*DQ_PER_DQS-1:0], 
                              DATA13_MAP[12*DQ_PER_DQS-1:0], 
                              DATA12_MAP[12*DQ_PER_DQS-1:0], 
                              DATA11_MAP[12*DQ_PER_DQS-1:0], 
                              DATA10_MAP[12*DQ_PER_DQS-1:0], 
                              DATA9_MAP[12*DQ_PER_DQS-1:0],  
                              DATA8_MAP[12*DQ_PER_DQS-1:0],  
                              DATA7_MAP[12*DQ_PER_DQS-1:0],  
                              DATA6_MAP[12*DQ_PER_DQS-1:0],
                              DATA5_MAP[12*DQ_PER_DQS-1:0],  
                              DATA4_MAP[12*DQ_PER_DQS-1:0],  
                              DATA3_MAP[12*DQ_PER_DQS-1:0],  
                              DATA2_MAP[12*DQ_PER_DQS-1:0],  
                              DATA1_MAP[12*DQ_PER_DQS-1:0],  
                              DATA0_MAP[12*DQ_PER_DQS-1:0]};
  // Same deal, but for data mask mapping
  localparam FULL_MASK_MAP = {MASK1_MAP, MASK0_MAP};
  localparam TMP_BYTELANES_DDR_CK  = generate_bytelanes_ddr_ck(CK_BYTE_MAP) ; 
  localparam TMP_GENERATE_DDR_CK_MAP = generate_ddr_ck_map(CK_BYTE_MAP) ;

  // Temporary parameters to determine which bank is outputting the CK/CK#
  // Eventually there will be support for multiple CK/CK# output
  //localparam TMP_DDR_CLK_SELECT_BANK = (CK_BYTE_MAP[7:4]);
  //// Temporary method to force MC_PHY to generate ODDR associated with
  //// CK/CK# output only for a single byte lane in the design. All banks
  //// that won't be generating the CK/CK# will have "UNUSED" as their
  //// PHY_GENERATE_DDR_CK parameter
  //localparam TMP_PHY_0_GENERATE_DDR_CK 
  //           = (TMP_DDR_CLK_SELECT_BANK != 0) ? "UNUSED" : 
  //              ((CK_BYTE_MAP[1:0] == 2'b00) ? "A" :
  //               ((CK_BYTE_MAP[1:0] == 2'b01) ? "B" :
  //                ((CK_BYTE_MAP[1:0] == 2'b10) ? "C" : "D")));
  //localparam TMP_PHY_1_GENERATE_DDR_CK 
  //           = (TMP_DDR_CLK_SELECT_BANK != 1) ? "UNUSED" : 
  //              ((CK_BYTE_MAP[1:0] == 2'b00) ? "A" :
  //               ((CK_BYTE_MAP[1:0] == 2'b01) ? "B" :
  //                ((CK_BYTE_MAP[1:0] == 2'b10) ? "C" : "D")));
  //localparam TMP_PHY_2_GENERATE_DDR_CK 
  //           = (TMP_DDR_CLK_SELECT_BANK != 2) ? "UNUSED" : 
  //              ((CK_BYTE_MAP[1:0] == 2'b00) ? "A" :
  //               ((CK_BYTE_MAP[1:0] == 2'b01) ? "B" :
  //                ((CK_BYTE_MAP[1:0] == 2'b10) ? "C" : "D")));

  // Function to generate MC_PHY parameters PHY_BITLANES_OUTONLYx
  // which indicates which bit lanes in data byte lanes are 
  // output-only bitlanes (e.g. used specifically for data mask outputs)
  function [143:0] calc_phy_bitlanes_outonly;
    input [215:0] data_mask_in;
    integer       z;
    begin
      calc_phy_bitlanes_outonly = 'b0;
      // Only enable BITLANES parameters for data masks if, well, if
      // the data masks are actually enabled
      if (USE_DM_PORT == 1)
        for (z = 0; z < DM_WIDTH; z = z + 1)
          calc_phy_bitlanes_outonly[48*data_mask_in[(12*z+8)+:3] + 
                                    12*data_mask_in[(12*z+4)+:2] + 
                                    data_mask_in[12*z+:4]] = 1'b1;
    end 
  endfunction

  localparam PHY_BITLANES_OUTONLY   = calc_phy_bitlanes_outonly(FULL_MASK_MAP);
  localparam PHY_0_BITLANES_OUTONLY = PHY_BITLANES_OUTONLY[47:0];
  localparam PHY_1_BITLANES_OUTONLY = PHY_BITLANES_OUTONLY[95:48];
  localparam PHY_2_BITLANES_OUTONLY = PHY_BITLANES_OUTONLY[143:96];

  // Determine which bank and byte lane generates the RCLK used to clock
  // out the auxilliary (ODT, CKE) outputs
  localparam CKE_ODT_RCLK_SELECT_BANK_AUX_ON 
             = (CKE_ODT_BYTE_MAP[7:4] == 4'h0) ? 0 :
                 ((CKE_ODT_BYTE_MAP[7:4] == 4'h1) ? 1 :
                  ((CKE_ODT_BYTE_MAP[7:4] == 4'h2) ? 2 :
                   ((CKE_ODT_BYTE_MAP[7:4] == 4'h3) ? 3 :
                    ((CKE_ODT_BYTE_MAP[7:4] == 4'h4) ? 4 : -1))));
  localparam CKE_ODT_RCLK_SELECT_LANE_AUX_ON
             = (CKE_ODT_BYTE_MAP[3:0] == 4'h0) ? "A" :
                 ((CKE_ODT_BYTE_MAP[3:0] == 4'h1) ? "B" :
                  ((CKE_ODT_BYTE_MAP[3:0] == 4'h2) ? "C" :
                   ((CKE_ODT_BYTE_MAP[3:0] == 4'h3) ? "D" : "ILLEGAL")));

  localparam CKE_ODT_RCLK_SELECT_BANK_AUX_OFF 
             = (CKE_MAP[11:8] == 4'h0) ? 0 :
                 ((CKE_MAP[11:8] == 4'h1) ? 1 :
                  ((CKE_MAP[11:8] == 4'h2) ? 2 :
                   ((CKE_MAP[11:8] == 4'h3) ? 3 :
                    ((CKE_MAP[11:8] == 4'h4) ? 4 : -1))));
  localparam CKE_ODT_RCLK_SELECT_LANE_AUX_OFF
             = (CKE_MAP[7:4] == 4'h0) ? "A" :
                 ((CKE_MAP[7:4] == 4'h1) ? "B" :
                  ((CKE_MAP[7:4] == 4'h2) ? "C" :
                   ((CKE_MAP[7:4] == 4'h3) ? "D" : "ILLEGAL")));


  localparam CKE_ODT_RCLK_SELECT_BANK = (CKE_ODT_AUX == "TRUE") ? CKE_ODT_RCLK_SELECT_BANK_AUX_ON : CKE_ODT_RCLK_SELECT_BANK_AUX_OFF ;
  localparam CKE_ODT_RCLK_SELECT_LANE = (CKE_ODT_AUX == "TRUE") ? CKE_ODT_RCLK_SELECT_LANE_AUX_ON : CKE_ODT_RCLK_SELECT_LANE_AUX_OFF ;

  
  //***************************************************************************
  // OCLKDELAYED tap setting calculation:
  // Parameters for calculating amount of phase shifting output clock to
  // achieve 90 degree offset between DQS and DQ on writes
  //***************************************************************************
  
  //90 deg equivalent to 0.25 for MEM_RefClk <= 300 MHz
  // and 1.25 for Mem_RefClk > 300 MHz
  localparam PO_OCLKDELAY_INV = (((SIM_CAL_OPTION == "NONE") && (tCK > 2500)) || (tCK >= 3333)) ?  "FALSE" : "TRUE";
  
  //DIV1: MemRefClk >= 400 MHz, DIV2: 200 <= MemRefClk < 400, 
  //DIV4: MemRefClk < 200 MHz
  localparam PHY_0_A_PI_FREQ_REF_DIV = tCK > 5000 ?  "DIV4" : 
                                       tCK > 2500 ? "DIV2": "NONE";

  localparam FREQ_REF_DIV = (PHY_0_A_PI_FREQ_REF_DIV == "DIV4" ? 4 : 
                             PHY_0_A_PI_FREQ_REF_DIV == "DIV2" ? 2 : 1);

  // Intrinsic delay between OCLK and OCLK_DELAYED Phaser Output
  localparam real INT_DELAY = 0.4392/FREQ_REF_DIV + 100.0/tCK;

  // Whether OCLK_DELAY output comes inverted or not
  localparam real HALF_CYCLE_DELAY = 0.5*(PO_OCLKDELAY_INV == "TRUE" ? 1 : 0);

  // Phaser-Out Stage3 Tap delay for 90 deg shift. 
  // Maximum tap delay is FreqRefClk period distributed over 64 taps
  // localparam real TAP_DELAY = MC_OCLK_DELAY/64/FREQ_REF_DIV;
  localparam real MC_OCLK_DELAY = ((PO_OCLKDELAY_INV == "TRUE" ? 1.25 : 0.25) - 
                                   (INT_DELAY + HALF_CYCLE_DELAY)) 
                                   * 63 * FREQ_REF_DIV;
  //localparam integer PHY_0_A_PO_OCLK_DELAY = MC_OCLK_DELAY;

  localparam integer PHY_0_A_PO_OCLK_DELAY_HW 
                     = (tCK <= 938)  ? 23 :
                       (tCK <= 1072) ? 24 :
                       (tCK <= 1250) ? 25 :
                       (tCK <= 1500) ? 26 : 27;
                       
  // Note that simulation requires a different value than in H/W because of the
  // difference in the way delays are modeled
  localparam integer PHY_0_A_PO_OCLK_DELAY = (SIM_CAL_OPTION == "NONE") ? 
                                             (tCK > 2500) ? 8 : 30 :
                                             MC_OCLK_DELAY;
                       
  // Initial DQ IDELAY value
  localparam PHY_0_A_IDELAYE2_IDELAY_VALUE = (SIM_CAL_OPTION != "FAST_CAL") ? 0 :
                  (tCK < 1000) ? 0 :
                  (tCK < 1330) ? 0 :
                  (tCK < 2300) ? 0 :
                  (tCK < 2500) ? 2 : 0;
  //localparam PHY_0_A_IDELAYE2_IDELAY_VALUE = 0;
  
  // Aux_out parameters RD_CMD_OFFSET = CL+2? and WR_CMD_OFFSET = CWL+3?
  localparam PHY_0_RD_CMD_OFFSET_0 = 10;
  localparam PHY_0_RD_CMD_OFFSET_1 = 10;
  localparam PHY_0_RD_CMD_OFFSET_2 = 10;
  localparam PHY_0_RD_CMD_OFFSET_3 = 10;
  // 4:1 and 2:1 have WR_CMD_OFFSET values for ODT timing
  localparam PHY_0_WR_CMD_OFFSET_0 = (nCK_PER_CLK == 4) ? 8 : 4;
  localparam PHY_0_WR_CMD_OFFSET_1 = (nCK_PER_CLK == 4) ? 8 : 4;
  localparam PHY_0_WR_CMD_OFFSET_2 = (nCK_PER_CLK == 4) ? 8 : 4;
  localparam PHY_0_WR_CMD_OFFSET_3 = (nCK_PER_CLK == 4) ? 8 : 4;
  // 4:1 and 2:1 have different values
  localparam PHY_0_WR_DURATION_0 = 7;
  localparam PHY_0_WR_DURATION_1 = 7;
  localparam PHY_0_WR_DURATION_2 = 7;
  localparam PHY_0_WR_DURATION_3 = 7;
  // Aux_out parameters for toggle mode (CKE)
  localparam CWL_M = (REG_CTRL == "ON") ? CWL + 1 : CWL;
  localparam PHY_0_CMD_OFFSET = (nCK_PER_CLK == 4) ?  (CWL_M % 2) ? 8 : 9 :
                                  (CWL < 7) ?
                                    4 + ((CWL_M % 2) ? 0 : 1) :
                                    5 + ((CWL_M % 2) ? 0 : 1);

  // temporary parameter to enable/disable PHY PC counters. In both 4:1 and 
  // 2:1 cases, this should be disabled. For now, enable for 4:1 mode to 
  // avoid making too many changes at once. 
  localparam PHY_COUNT_EN = (nCK_PER_CLK == 4) ? "TRUE" : "FALSE";

  
  wire [((HIGHEST_LANE+3)/4)*4-1:0] aux_out;
  wire [HIGHEST_LANE-1:0]           mem_dqs_in;
  wire [HIGHEST_LANE-1:0]           mem_dqs_out;
  wire [HIGHEST_LANE-1:0]           mem_dqs_ts;
  wire [HIGHEST_LANE*10-1:0]        mem_dq_in;
  wire [HIGHEST_LANE*12-1:0]        mem_dq_out;
  wire [HIGHEST_LANE*12-1:0]        mem_dq_ts;
  wire [DQ_WIDTH-1:0]               in_dq;
  wire [DQS_WIDTH-1:0]              in_dqs;
  wire [ROW_WIDTH-1:0]              out_addr;  
  wire [BANK_WIDTH-1:0]             out_ba;
  wire                              out_cas_n;
  wire [CS_WIDTH*nCS_PER_RANK-1:0]  out_cs_n;
  wire [DM_WIDTH-1:0]               out_dm;
  wire [ODT_WIDTH -1:0]             out_odt;
  wire [CKE_WIDTH -1 :0]            out_cke ;
  wire [DQ_WIDTH-1:0]               out_dq;
  wire [DQS_WIDTH-1:0]              out_dqs;
  wire                              out_parity;
  wire                              out_ras_n;
  wire                              out_we_n;
  wire [HIGHEST_LANE*80-1:0]        phy_din;
  wire [HIGHEST_LANE*80-1:0]        phy_dout;
  wire                              phy_rd_en;  
  wire [DM_WIDTH-1:0]               ts_dm;  
  wire [DQ_WIDTH-1:0]               ts_dq;  
  wire [DQS_WIDTH-1:0]              ts_dqs;

  reg [31:0]                        phy_ctl_wd_i1;
  reg [31:0]                        phy_ctl_wd_i2;
  reg                               phy_ctl_wr_i1;
  reg                               phy_ctl_wr_i2;
  reg [5:0]                         data_offset_1_i1;
  reg [5:0]                         data_offset_1_i2;
  reg [5:0]                         data_offset_2_i1;
  reg [5:0]                         data_offset_2_i2;
  wire [31:0]                       phy_ctl_wd_temp;
  wire                              phy_ctl_wr_temp;
  wire [5:0]                        data_offset_1_temp;
  wire [5:0]                        data_offset_2_temp;
  wire [5:0]                        data_offset_1_of;
  wire [5:0]                        data_offset_2_of;
  wire [31:0]                       phy_ctl_wd_of;
(* keep = "true", max_fanout = 1 *)  wire          phy_ctl_wr_of;
  wire                              phy_ctl_full_temp;
  
  wire                              data_io_idle_pwrdwn;

  // Always read from input data FIFOs when not empty
  assign phy_rd_en = !if_empty;
  
  // IDELAYE2 initial value
  assign idelaye2_init_val = PHY_0_A_IDELAYE2_IDELAY_VALUE;
  assign oclkdelay_init_val = PHY_0_A_PO_OCLK_DELAY;
  
  // Idle powerdown when there are no pending reads in the MC
  assign data_io_idle_pwrdwn = DATA_IO_IDLE_PWRDWN == "ON" ? idle : 1'b0;
  
  //***************************************************************************
  // Auxiliary output steering
  //***************************************************************************

  // For a 4 rank I/F the aux_out[3:0] from the addr/ctl bank will be 
  // mapped to ddr_odt and the aux_out[7:4] from one of the data banks
  // will map to ddr_cke. For I/Fs less than 4 the aux_out[3:0] from the
  // addr/ctl bank would bank would map to both ddr_odt and ddr_cke.
  generate
  if(CKE_ODT_AUX == "TRUE")begin:cke_thru_auxpins
    if (CKE_WIDTH == 1) begin : gen_cke
      // Explicitly instantiate OBUF to ensure that these are present
      // in the netlist. Typically this is not required since NGDBUILD
      // at the top-level knows to infer an I/O/IOBUF and therefore a
      // top-level LOC constraint can be attached to that pin. This does
      // not work when a hierarchical flow is used and the LOC is applied
      // at the individual core-level UCF
      OBUF u_cke_obuf
        (
         .I (aux_out[4*CKE_ODT_RCLK_SELECT_BANK]),
         .O (ddr_cke)
         );
    end else begin: gen_2rank_cke
      OBUF u_cke0_obuf
        (
         .I (aux_out[4*CKE_ODT_RCLK_SELECT_BANK]),
         .O (ddr_cke[0])
         );
      OBUF u_cke1_obuf
        (
         .I (aux_out[4*CKE_ODT_RCLK_SELECT_BANK+2]),
         .O (ddr_cke[1])
         );
    end
  end  
  endgenerate

  generate
  if(CKE_ODT_AUX == "TRUE")begin:odt_thru_auxpins
    if (USE_ODT_PORT == 1) begin : gen_use_odt
      // Explicitly instantiate OBUF to ensure that these are present
      // in the netlist. Typically this is not required since NGDBUILD
      // at the top-level knows to infer an I/O/IOBUF and therefore a
      // top-level LOC constraint can be attached to that pin. This does
      // not work when a hierarchical flow is used and the LOC is applied
      // at the individual core-level UCF
        OBUF u_odt_obuf
          (
           .I (aux_out[4*CKE_ODT_RCLK_SELECT_BANK+1]),
           .O (ddr_odt[0])
           );      
      if (ODT_WIDTH == 2 && RANKS == 1) begin: gen_2port_odt
        OBUF u_odt1_obuf
          (
           .I (aux_out[4*CKE_ODT_RCLK_SELECT_BANK+2]),
           .O (ddr_odt[1])
           );
      end else if (ODT_WIDTH == 2 && RANKS == 2) begin: gen_2rank_odt
        OBUF u_odt1_obuf
          (
           .I (aux_out[4*CKE_ODT_RCLK_SELECT_BANK+3]),
           .O (ddr_odt[1])
           );
      end else if (ODT_WIDTH == 3 && RANKS == 1) begin: gen_3port_odt
        OBUF u_odt1_obuf
          (
           .I (aux_out[4*CKE_ODT_RCLK_SELECT_BANK+2]),
           .O (ddr_odt[1])
           );
        OBUF u_odt2_obuf
          (
           .I (aux_out[4*CKE_ODT_RCLK_SELECT_BANK+3]),
           .O (ddr_odt[2])
           );
      end
    end else begin
        assign ddr_odt = 'b0; 
    end
  end
  endgenerate

  //***************************************************************************
  // Read data bit steering
  //***************************************************************************

  // Transpose elements of rd_data_map to form final read data output:
  // phy_din elements are grouped according to "physical bit" - e.g.
  // for nCK_PER_CLK = 4, there are 8 data phases transfered per physical
  // bit per clock cycle: 
  //   = {dq0_fall3, dq0_rise3, dq0_fall2, dq0_rise2, 
  //      dq0_fall1, dq0_rise1, dq0_fall0, dq0_rise0}
  // whereas rd_data is are grouped according to "phase" - e.g.
  //   = {dq7_rise0, dq6_rise0, dq5_rise0, dq4_rise0,
  //      dq3_rise0, dq2_rise0, dq1_rise0, dq0_rise0}
  // therefore rd_data is formed by transposing phy_din - e.g.
  //   for nCK_PER_CLK = 4, and DQ_WIDTH = 16, and assuming MC_PHY 
  //   bit_lane[0] maps to DQ[0], and bit_lane[1] maps to DQ[1], then 
  //   the assignments for bits of rd_data corresponding to DQ[1:0]
  //   would be:      
  //    {rd_data[112], rd_data[96], rd_data[80], rd_data[64],
  //     rd_data[48], rd_data[32], rd_data[16], rd_data[0]} = phy_din[7:0]
  //    {rd_data[113], rd_data[97], rd_data[81], rd_data[65],
  //     rd_data[49], rd_data[33], rd_data[17], rd_data[1]} = phy_din[15:8]   
  generate
    genvar i, j;  
    for (i = 0; i < DQ_WIDTH; i = i + 1) begin: gen_loop_rd_data_1
      for (j = 0; j < PHASE_PER_CLK; j = j + 1) begin: gen_loop_rd_data_2
        assign rd_data[DQ_WIDTH*j + i] 
                 = phy_din[(320*FULL_DATA_MAP[(12*i+8)+:3]+
                            80*FULL_DATA_MAP[(12*i+4)+:2] +
                            8*FULL_DATA_MAP[12*i+:4]) + j];
      end
    end
  endgenerate
  
  //***************************************************************************
  // Control/address
  //***************************************************************************

  assign out_cas_n
    = mem_dq_out[48*CAS_MAP[10:8] + 12*CAS_MAP[5:4] + CAS_MAP[3:0]];
  
  generate
    // if signal placed on bit lanes [0-9]    
    if (CAS_MAP[3:0] < 4'hA) begin: gen_cas_lt10
      // Determine routing based on clock ratio mode. If running in 4:1
      // mode, then all four bits from logic are used. If 2:1 mode, only
      // 2-bits are provided by logic, and each bit is repeated 2x to form
      // 4-bit input to IN_FIFO, e.g.
      //   4:1 mode: phy_dout[] = {in[3], in[2], in[1], in[0]}
      //   2:1 mode: phy_dout[] = {in[1], in[1], in[0], in[0]}
      assign phy_dout[(320*CAS_MAP[10:8] + 80*CAS_MAP[5:4] + 
                       8*CAS_MAP[3:0])+:4] 
               = {mux_cas_n[3/PHASE_DIV], mux_cas_n[2/PHASE_DIV],
                  mux_cas_n[1/PHASE_DIV], mux_cas_n[0]};
    end else begin: gen_cas_ge10
      // If signal is placed in bit lane [10] or [11], route to upper
      // nibble of phy_dout lane [5] or [6] respectively (in this case
      // phy_dout lane [5, 6] are multiplexed to take input for two
      // different SDR signals - this is how bits[10,11] need to be
      // provided to the OUT_FIFO
      assign phy_dout[(320*CAS_MAP[10:8] + 80*CAS_MAP[5:4] + 
                       8*(CAS_MAP[3:0]-5) + 4)+:4] 
               = {mux_cas_n[3/PHASE_DIV], mux_cas_n[2/PHASE_DIV],
                  mux_cas_n[1/PHASE_DIV], mux_cas_n[0]};
    end
  endgenerate

  assign out_ras_n
    = mem_dq_out[48*RAS_MAP[10:8] + 12*RAS_MAP[5:4] + RAS_MAP[3:0]];
  
  generate
    if (RAS_MAP[3:0] < 4'hA) begin: gen_ras_lt10
      assign phy_dout[(320*RAS_MAP[10:8] + 80*RAS_MAP[5:4] + 
                       8*RAS_MAP[3:0])+:4]
               = {mux_ras_n[3/PHASE_DIV], mux_ras_n[2/PHASE_DIV],
                  mux_ras_n[1/PHASE_DIV], mux_ras_n[0]};
    end else begin: gen_ras_ge10
      assign phy_dout[(320*RAS_MAP[10:8] + 80*RAS_MAP[5:4] + 
                       8*(RAS_MAP[3:0]-5) + 4)+:4] 
               = {mux_ras_n[3/PHASE_DIV], mux_ras_n[2/PHASE_DIV],
                  mux_ras_n[1/PHASE_DIV], mux_ras_n[0]};
    end
  endgenerate

  assign out_we_n
    = mem_dq_out[48*WE_MAP[10:8] + 12*WE_MAP[5:4] + WE_MAP[3:0]];
  
  generate
    if (WE_MAP[3:0] < 4'hA) begin: gen_we_lt10
      assign phy_dout[(320*WE_MAP[10:8] + 80*WE_MAP[5:4] + 
                       8*WE_MAP[3:0])+:4] 
               = {mux_we_n[3/PHASE_DIV], mux_we_n[2/PHASE_DIV],
                  mux_we_n[1/PHASE_DIV], mux_we_n[0]};
    end else begin: gen_we_ge10
      assign phy_dout[(320*WE_MAP[10:8] + 80*WE_MAP[5:4] + 
                       8*(WE_MAP[3:0]-5) + 4)+:4] 
               = {mux_we_n[3/PHASE_DIV], mux_we_n[2/PHASE_DIV],
                  mux_we_n[1/PHASE_DIV], mux_we_n[0]};
    end
  endgenerate
  
  generate
    if (REG_CTRL == "ON") begin: gen_parity_out
      // Generate addr/ctrl parity output only for DDR3 and DDR2 registered DIMMs
      assign out_parity
        = mem_dq_out[48*PARITY_MAP[10:8] + 12*PARITY_MAP[5:4] + 
                     PARITY_MAP[3:0]];
      if (PARITY_MAP[3:0] < 4'hA) begin: gen_lt10
        assign phy_dout[(320*PARITY_MAP[10:8] + 80*PARITY_MAP[5:4] + 
                         8*PARITY_MAP[3:0])+:4] 
                 = {parity_in[3/PHASE_DIV], parity_in[2/PHASE_DIV],
                    parity_in[1/PHASE_DIV], parity_in[0]};                 
      end else begin: gen_ge10
        assign phy_dout[(320*PARITY_MAP[10:8] + 80*PARITY_MAP[5:4] + 
                         8*(PARITY_MAP[3:0]-5) + 4)+:4] 
               = {parity_in[3/PHASE_DIV], parity_in[2/PHASE_DIV],
                  parity_in[1/PHASE_DIV], parity_in[0]};
      end
    end
  endgenerate
  
  //*****************************************************************  
  
  generate
    genvar m, n,x;  

    //*****************************************************************
    // Control/address (multi-bit) buses
    //*****************************************************************

    // Row/Column address
    for (m = 0; m < ROW_WIDTH; m = m + 1) begin: gen_addr_out
      assign out_addr[m]
               = mem_dq_out[48*ADDR_MAP[(12*m+8)+:3] + 
                            12*ADDR_MAP[(12*m+4)+:2] + 
                            ADDR_MAP[12*m+:4]];
      
      if (ADDR_MAP[12*m+:4] < 4'hA) begin: gen_lt10
        // For multi-bit buses, we also have to deal with transposition 
        // when going from the logic-side control bus to phy_dout
        for (n = 0; n < 4; n = n + 1) begin: loop_xpose
          assign phy_dout[320*ADDR_MAP[(12*m+8)+:3] + 
                          80*ADDR_MAP[(12*m+4)+:2] + 
                          8*ADDR_MAP[12*m+:4] + n]
                   = mux_address[ROW_WIDTH*(n/PHASE_DIV) + m];
        end
      end else begin: gen_ge10 
        for (n = 0; n < 4; n = n + 1) begin: loop_xpose
          assign phy_dout[320*ADDR_MAP[(12*m+8)+:3] + 
                          80*ADDR_MAP[(12*m+4)+:2] + 
                          8*(ADDR_MAP[12*m+:4]-5) + 4 + n]
                   = mux_address[ROW_WIDTH*(n/PHASE_DIV) + m];
        end
      end
    end

    // Bank address
    for (m = 0; m < BANK_WIDTH; m = m + 1) begin: gen_ba_out
        assign out_ba[m]
                 = mem_dq_out[48*BANK_MAP[(12*m+8)+:3] + 
                              12*BANK_MAP[(12*m+4)+:2] + 
                              BANK_MAP[12*m+:4]];

      if (BANK_MAP[12*m+:4] < 4'hA) begin: gen_lt10
        for (n = 0; n < 4; n = n + 1) begin: loop_xpose
          assign phy_dout[320*BANK_MAP[(12*m+8)+:3] + 
                          80*BANK_MAP[(12*m+4)+:2] + 
                          8*BANK_MAP[12*m+:4] + n]
                   = mux_bank[BANK_WIDTH*(n/PHASE_DIV) + m];
        end
      end else begin: gen_ge10 
        for (n = 0; n < 4; n = n + 1) begin: loop_xpose
          assign phy_dout[320*BANK_MAP[(12*m+8)+:3] + 
                          80*BANK_MAP[(12*m+4)+:2] + 
                          8*(BANK_MAP[12*m+:4]-5) + 4 + n]
                   = mux_bank[BANK_WIDTH*(n/PHASE_DIV) + m];
        end
      end
    end
    
    // Chip select     
    if (USE_CS_PORT == 1) begin: gen_cs_n_out
      for (m = 0; m < CS_WIDTH*nCS_PER_RANK; m = m + 1) begin: gen_cs_out
        assign out_cs_n[m]
                 = mem_dq_out[48*CS_MAP[(12*m+8)+:3] + 
                              12*CS_MAP[(12*m+4)+:2] + 
                              CS_MAP[12*m+:4]];
        if (CS_MAP[12*m+:4] < 4'hA) begin: gen_lt10
          for (n = 0; n < 4; n = n + 1) begin: loop_xpose
            assign phy_dout[320*CS_MAP[(12*m+8)+:3] + 
                            80*CS_MAP[(12*m+4)+:2] + 
                            8*CS_MAP[12*m+:4] + n]
                     = mux_cs_n[CS_WIDTH*nCS_PER_RANK*(n/PHASE_DIV) + m];
          end
        end else begin: gen_ge10 
          for (n = 0; n < 4; n = n + 1) begin: loop_xpose
            assign phy_dout[320*CS_MAP[(12*m+8)+:3] + 
                            80*CS_MAP[(12*m+4)+:2] + 
                            8*(CS_MAP[12*m+:4]-5) + 4 + n]
                     = mux_cs_n[CS_WIDTH*nCS_PER_RANK*(n/PHASE_DIV) + m];
          end
        end
      end
    end


   if(CKE_ODT_AUX == "FALSE") begin
     // ODT_ports     
     wire [ODT_WIDTH*nCK_PER_CLK -1 :0] mux_odt_remap  ;

     if(RANKS == 1) begin
        for(x =0 ; x < nCK_PER_CLK ; x = x+1) begin
          assign mux_odt_remap[(x*ODT_WIDTH)+:ODT_WIDTH] = {ODT_WIDTH{mux_odt[0]}} ;
        end 
     end else begin
        for(x =0 ; x < 2*nCK_PER_CLK ; x = x+2) begin
          assign mux_odt_remap[(x*ODT_WIDTH/RANKS)+:ODT_WIDTH/RANKS] = {ODT_WIDTH/RANKS{mux_odt[0]}} ;
          assign mux_odt_remap[((x*ODT_WIDTH/RANKS)+(ODT_WIDTH/RANKS))+:ODT_WIDTH/RANKS] = {ODT_WIDTH/RANKS{mux_odt[1]}} ;
        end 
     end

     if (USE_ODT_PORT == 1) begin: gen_odt_out
       for (m = 0; m < ODT_WIDTH; m = m + 1) begin: gen_odt_out_1
         assign out_odt[m]
                  = mem_dq_out[48*ODT_MAP[(12*m+8)+:3] + 
                               12*ODT_MAP[(12*m+4)+:2] + 
                               ODT_MAP[12*m+:4]];
         if (ODT_MAP[12*m+:4] < 4'hA) begin: gen_lt10
           for (n = 0; n < 4; n = n + 1) begin: loop_xpose
             assign phy_dout[320*ODT_MAP[(12*m+8)+:3] + 
                             80*ODT_MAP[(12*m+4)+:2] + 
                             8*ODT_MAP[12*m+:4] + n]
                      = mux_odt_remap[ODT_WIDTH*(n/PHASE_DIV) + m];
           end
         end else begin: gen_ge10 
           for (n = 0; n < 4; n = n + 1) begin: loop_xpose
             assign phy_dout[320*ODT_MAP[(12*m+8)+:3] + 
                             80*ODT_MAP[(12*m+4)+:2] + 
                             8*(ODT_MAP[12*m+:4]-5) + 4 + n]
                      = mux_odt_remap[ODT_WIDTH*(n/PHASE_DIV) + m];
           end
         end
       end
     end


     wire [CKE_WIDTH*nCK_PER_CLK -1:0] mux_cke_remap ;

     for(x = 0 ; x < nCK_PER_CLK ; x = x +1) begin
      assign  mux_cke_remap[(x*CKE_WIDTH)+:CKE_WIDTH] = {CKE_WIDTH{mux_cke[x]}} ;
     end 


 
     for (m = 0; m < CKE_WIDTH; m = m + 1) begin: gen_cke_out
       assign out_cke[m]
                = mem_dq_out[48*CKE_MAP[(12*m+8)+:3] + 
                             12*CKE_MAP[(12*m+4)+:2] + 
                             CKE_MAP[12*m+:4]];
       if (CKE_MAP[12*m+:4] < 4'hA) begin: gen_lt10
         for (n = 0; n < 4; n = n + 1) begin: loop_xpose
           assign phy_dout[320*CKE_MAP[(12*m+8)+:3] + 
                           80*CKE_MAP[(12*m+4)+:2] + 
                           8*CKE_MAP[12*m+:4] + n]
                    = mux_cke_remap[CKE_WIDTH*(n/PHASE_DIV) + m];
         end
       end else begin: gen_ge10 
         for (n = 0; n < 4; n = n + 1) begin: loop_xpose
           assign phy_dout[320*CKE_MAP[(12*m+8)+:3] + 
                           80*CKE_MAP[(12*m+4)+:2] + 
                           8*(CKE_MAP[12*m+:4]-5) + 4 + n]
                    = mux_cke_remap[CKE_WIDTH*(n/PHASE_DIV) + m];
         end
       end
     end
   end  
       
    //*****************************************************************
    // Data mask
    //*****************************************************************

    if (USE_DM_PORT == 1) begin: gen_dm_out
      for (m = 0; m < DM_WIDTH; m = m + 1) begin: gen_dm_out
        assign out_dm[m]
                 = mem_dq_out[48*FULL_MASK_MAP[(12*m+8)+:3] + 
                              12*FULL_MASK_MAP[(12*m+4)+:2] + 
                              FULL_MASK_MAP[12*m+:4]];
        assign ts_dm[m]
                 = mem_dq_ts[48*FULL_MASK_MAP[(12*m+8)+:3] + 
                             12*FULL_MASK_MAP[(12*m+4)+:2] + 
                             FULL_MASK_MAP[12*m+:4]];           
        for (n = 0; n < PHASE_PER_CLK; n = n + 1) begin: loop_xpose
          assign phy_dout[320*FULL_MASK_MAP[(12*m+8)+:3] + 
                          80*FULL_MASK_MAP[(12*m+4)+:2] + 
                          8*FULL_MASK_MAP[12*m+:4] + n]
                   = mux_wrdata_mask[DM_WIDTH*n + m];     
        end
      end
    end

    //*****************************************************************
    // Input and output DQ
    //*****************************************************************
  
    for (m = 0; m < DQ_WIDTH; m = m + 1) begin: gen_dq_inout
      // to MC_PHY
      assign mem_dq_in[40*FULL_DATA_MAP[(12*m+8)+:3] + 
                       10*FULL_DATA_MAP[(12*m+4)+:2] + 
                       FULL_DATA_MAP[12*m+:4]] 
               = in_dq[m];
      // to I/O buffers
      assign out_dq[m]
               = mem_dq_out[48*FULL_DATA_MAP[(12*m+8)+:3] + 
                            12*FULL_DATA_MAP[(12*m+4)+:2] + 
                            FULL_DATA_MAP[12*m+:4]];
      assign ts_dq[m]
               = mem_dq_ts[48*FULL_DATA_MAP[(12*m+8)+:3] + 
                           12*FULL_DATA_MAP[(12*m+4)+:2] + 
                           FULL_DATA_MAP[12*m+:4]];   
      for (n = 0; n < PHASE_PER_CLK; n = n + 1) begin: loop_xpose
        assign phy_dout[320*FULL_DATA_MAP[(12*m+8)+:3] + 
                        80*FULL_DATA_MAP[(12*m+4)+:2] + 
                        8*FULL_DATA_MAP[12*m+:4] + n]
                 = mux_wrdata[DQ_WIDTH*n + m];     
      end
    end

    //*****************************************************************
    // Input and output DQS
    //*****************************************************************

    for (m = 0; m < DQS_WIDTH; m = m + 1) begin: gen_dqs_inout
      // to MC_PHY
      assign mem_dqs_in[4*DQS_BYTE_MAP[(8*m+4)+:3] + DQS_BYTE_MAP[(8*m)+:2]]
        = in_dqs[m];
      // to I/O buffers
      assign out_dqs[m]
        = mem_dqs_out[4*DQS_BYTE_MAP[(8*m+4)+:3] + DQS_BYTE_MAP[(8*m)+:2]];
      assign ts_dqs[m]
        = mem_dqs_ts[4*DQS_BYTE_MAP[(8*m+4)+:3] + DQS_BYTE_MAP[(8*m)+:2]];
    end
  endgenerate
  
  //***************************************************************************
  // Memory I/F output and I/O buffer instantiation
  //***************************************************************************

  // Note on instantiation - generally at the minimum, it's not required to 
  // instantiate the output buffers - they can be inferred by the synthesis
  // tool, and there aren't any attributes that need to be associated with
  // them. Consider as a future option to take out the OBUF instantiations
  
  OBUF u_cas_n_obuf
    (
     .I (out_cas_n),
     .O (ddr_cas_n)
     );

  OBUF u_ras_n_obuf
    (
     .I (out_ras_n),
     .O (ddr_ras_n)
     );  

  OBUF u_we_n_obuf
    (
     .I (out_we_n),
     .O (ddr_we_n)
     );  
  
  generate
    genvar p;

    for (p = 0; p < ROW_WIDTH; p = p + 1) begin: gen_addr_obuf
      OBUF u_addr_obuf
        (
         .I (out_addr[p]),
         .O (ddr_addr[p])
         );      
    end

    for (p = 0; p < BANK_WIDTH; p = p + 1) begin: gen_bank_obuf
      OBUF u_bank_obuf
        (
         .I (out_ba[p]),
         .O (ddr_ba[p])
         );      
    end

    if (USE_CS_PORT == 1) begin: gen_cs_n_obuf
      for (p = 0; p < CS_WIDTH*nCS_PER_RANK; p = p + 1) begin: gen_cs_obuf
        OBUF u_cs_n_obuf
          (
           .I (out_cs_n[p]),
           .O (ddr_cs_n[p])
           );      
      end
    end
    if(CKE_ODT_AUX == "FALSE")begin:cke_odt_thru_outfifo
      if (USE_ODT_PORT== 1) begin: gen_odt_obuf
        for (p = 0; p < ODT_WIDTH; p = p + 1) begin: gen_odt_obuf
          OBUF u_cs_n_obuf
            (
             .I (out_odt[p]),
             .O (ddr_odt[p])
             );      
        end
      end
        for (p = 0; p < CKE_WIDTH; p = p + 1) begin: gen_cke_obuf
          OBUF u_cs_n_obuf
            (
             .I (out_cke[p]),
             .O (ddr_cke[p])
             );      
        end
    end  
      
    if (REG_CTRL == "ON") begin: gen_parity_obuf
      // Generate addr/ctrl parity output only for DDR3 registered DIMMs
      OBUF u_parity_obuf
        (
         .I (out_parity),
         .O (ddr_parity)
         );
    end else begin: gen_parity_tieoff
      assign ddr_parity = 1'b0;
    end

    if ((DRAM_TYPE == "DDR3") || (REG_CTRL == "ON")) begin: gen_reset_obuf
      // Generate reset output only for DDR3 and DDR2 RDIMMs
      OBUF u_reset_obuf
        (
         .I (mux_reset_n),
         .O (ddr_reset_n)
         );
    end else begin: gen_reset_tieoff
      assign ddr_reset_n = 1'b1;
    end
    
    if (USE_DM_PORT == 1) begin: gen_dm_obuf
      for (p = 0; p < DM_WIDTH; p = p + 1) begin: loop_dm
        OBUFT u_dm_obuf
          (
           .I (out_dm[p]),
           .T (ts_dm[p]),
           .O (ddr_dm[p])
           );      
      end      
    end else begin: gen_dm_tieoff
      assign ddr_dm = 'b0;
    end      

    if (DATA_IO_PRIM_TYPE == "HP_LP") begin: gen_dq_iobuf_HP
      for (p = 0; p < DQ_WIDTH; p = p + 1) begin: gen_dq_iobuf
        IOBUF_DCIEN #
          (
           .IBUF_LOW_PWR (IBUF_LOW_PWR)
           )
          u_iobuf_dq
            (
             .DCITERMDISABLE (data_io_idle_pwrdwn),
             .IBUFDISABLE    (data_io_idle_pwrdwn),
             .I              (out_dq[p]),
             .T              (ts_dq[p]),
             .O              (in_dq[p]),
             .IO             (ddr_dq[p])
             );
      end
    end else if (DATA_IO_PRIM_TYPE == "HR_LP") begin: gen_dq_iobuf_HR
      for (p = 0; p < DQ_WIDTH; p = p + 1) begin: gen_dq_iobuf
        IOBUF_INTERMDISABLE #
          (
           .IBUF_LOW_PWR (IBUF_LOW_PWR)
           )
          u_iobuf_dq
            (
             .INTERMDISABLE  (data_io_idle_pwrdwn),
             .IBUFDISABLE    (data_io_idle_pwrdwn),
             .I              (out_dq[p]),
             .T              (ts_dq[p]),
             .O              (in_dq[p]),
             .IO             (ddr_dq[p])
             );
      end
    end else begin: gen_dq_iobuf_default
      for (p = 0; p < DQ_WIDTH; p = p + 1) begin: gen_dq_iobuf
        IOBUF #
          (
           .IBUF_LOW_PWR (IBUF_LOW_PWR)
           )
          u_iobuf_dq
            (
             .I  (out_dq[p]),
             .T  (ts_dq[p]),
             .O  (in_dq[p]),
             .IO (ddr_dq[p])
             );
      end
    end

    if (DATA_IO_PRIM_TYPE == "HP_LP") begin: gen_dqs_iobuf_HP
      for (p = 0; p < DQS_WIDTH; p = p + 1) begin: gen_dqs_iobuf
        if ((DRAM_TYPE == "DDR2") &&
            (DDR2_DQSN_ENABLE != "YES")) begin: gen_ddr2_dqs_se
          IOBUF_DCIEN #
            (
             .IBUF_LOW_PWR (IBUF_LOW_PWR)
             )
            u_iobuf_dqs
              (
               .DCITERMDISABLE (data_io_idle_pwrdwn),
               .IBUFDISABLE    (data_io_idle_pwrdwn),
               .I              (out_dqs[p]),
               .T              (ts_dqs[p]),
               .O              (in_dqs[p]),
               .IO             (ddr_dqs[p])
               );
          assign ddr_dqs_n[p] = 1'b0;
        end else begin: gen_dqs_diff
          IOBUFDS_DCIEN #
            (
             .IBUF_LOW_PWR (IBUF_LOW_PWR),
             .DQS_BIAS     ("TRUE")
             )
            u_iobuf_dqs
              (
               .DCITERMDISABLE (data_io_idle_pwrdwn),
               .IBUFDISABLE    (data_io_idle_pwrdwn),
               .I              (out_dqs[p]),
               .T              (ts_dqs[p]),
               .O              (in_dqs[p]),
               .IO             (ddr_dqs[p]),
               .IOB            (ddr_dqs_n[p])
               );
        end
      end
    end else if (DATA_IO_PRIM_TYPE == "HR_LP") begin: gen_dqs_iobuf_HR
      for (p = 0; p < DQS_WIDTH; p = p + 1) begin: gen_dqs_iobuf
        if ((DRAM_TYPE == "DDR2") &&
            (DDR2_DQSN_ENABLE != "YES")) begin: gen_ddr2_dqs_se
          IOBUF_INTERMDISABLE #
            (
             .IBUF_LOW_PWR (IBUF_LOW_PWR)
             )
            u_iobuf_dqs
              (
               .INTERMDISABLE  (data_io_idle_pwrdwn),
               .IBUFDISABLE    (data_io_idle_pwrdwn),
               .I              (out_dqs[p]),
               .T              (ts_dqs[p]),
               .O              (in_dqs[p]),
               .IO             (ddr_dqs[p])
               );
          assign ddr_dqs_n[p] = 1'b0;
        end else begin: gen_dqs_diff
          IOBUFDS_INTERMDISABLE #
            (
             .IBUF_LOW_PWR (IBUF_LOW_PWR),
             .DQS_BIAS     ("TRUE")
             )
            u_iobuf_dqs
              (
               .INTERMDISABLE  (data_io_idle_pwrdwn),
               .IBUFDISABLE    (data_io_idle_pwrdwn),
               .I              (out_dqs[p]),
               .T              (ts_dqs[p]),
               .O              (in_dqs[p]),
               .IO             (ddr_dqs[p]),
               .IOB            (ddr_dqs_n[p])
               );
        end
      end
    end else begin: gen_dqs_iobuf_default
      for (p = 0; p < DQS_WIDTH; p = p + 1) begin: gen_dqs_iobuf
        if ((DRAM_TYPE == "DDR2") &&
            (DDR2_DQSN_ENABLE != "YES")) begin: gen_ddr2_dqs_se
          IOBUF #
            (
             .IBUF_LOW_PWR (IBUF_LOW_PWR)
             )
            u_iobuf_dqs
              (
               .I   (out_dqs[p]),
               .T   (ts_dqs[p]),
               .O   (in_dqs[p]),
               .IO  (ddr_dqs[p])
               );
          assign ddr_dqs_n[p] = 1'b0;
        end else begin: gen_dqs_diff
          IOBUFDS #
            (
             .IBUF_LOW_PWR (IBUF_LOW_PWR),
             .DQS_BIAS     ("TRUE")
             )
            u_iobuf_dqs
              (
               .I   (out_dqs[p]),
               .T   (ts_dqs[p]),
               .O   (in_dqs[p]),
               .IO  (ddr_dqs[p]),
               .IOB (ddr_dqs_n[p])
               );
        end
      end
    end

  endgenerate

  always @(posedge clk) begin
    phy_ctl_wd_i1 <= #TCQ phy_ctl_wd;
    phy_ctl_wr_i1 <= #TCQ phy_ctl_wr;
    phy_ctl_wd_i2 <= #TCQ phy_ctl_wd_i1;
    phy_ctl_wr_i2 <= #TCQ phy_ctl_wr_i1;
    data_offset_1_i1 <= #TCQ data_offset_1;
    data_offset_1_i2 <= #TCQ data_offset_1_i1;
    data_offset_2_i1 <= #TCQ data_offset_2;
    data_offset_2_i2 <= #TCQ data_offset_2_i1;
  end 


  // 2 cycles of command delay needed for 4;1 mode. 2:1 mode does not need it.
  // 2:1 mode the command goes through pre fifo 
  assign phy_ctl_wd_temp = (nCK_PER_CLK == 4) ? phy_ctl_wd_i2 : phy_ctl_wd_of;
  assign phy_ctl_wr_temp = (nCK_PER_CLK == 4) ? phy_ctl_wr_i2 : phy_ctl_wr_of;
  assign data_offset_1_temp = (nCK_PER_CLK == 4) ? data_offset_1_i2 : data_offset_1_of;
  assign data_offset_2_temp = (nCK_PER_CLK == 4) ? data_offset_2_i2 : data_offset_2_of;

  generate
    begin

      mig_7series_v1_8_ddr_of_pre_fifo #
      (
       .TCQ   (25),    
       .DEPTH (8),     
       .WIDTH (44)     
      )
     phy_ctl_pre_fifo
      (
       .clk       (clk),
       .rst       (rst),
       .full_in   (phy_ctl_full_temp),
       .wr_en_in  (phy_ctl_wr),
       .d_in      ({data_offset_2, data_offset_1, phy_ctl_wd}),
       .wr_en_out (phy_ctl_wr_of),
       .d_out     ({data_offset_2_of, data_offset_1_of, phy_ctl_wd_of})
       );
       
    end
  endgenerate 
    


  //***************************************************************************
  // Hard PHY instantiation
  //***************************************************************************

   assign phy_ctl_full = phy_ctl_full_temp;
  
  mig_7series_v1_8_ddr_mc_phy #
    (
     .BYTE_LANES_B0                 (BYTE_LANES_B0),
     .BYTE_LANES_B1                 (BYTE_LANES_B1),
     .BYTE_LANES_B2                 (BYTE_LANES_B2),
     .BYTE_LANES_B3                 (BYTE_LANES_B3),
     .BYTE_LANES_B4                 (BYTE_LANES_B4),
     .DATA_CTL_B0                   (DATA_CTL_B0),
     .DATA_CTL_B1                   (DATA_CTL_B1),
     .DATA_CTL_B2                   (DATA_CTL_B2),
     .DATA_CTL_B3                   (DATA_CTL_B3),
     .DATA_CTL_B4                   (DATA_CTL_B4),
     .PHY_0_BITLANES                (PHY_0_BITLANES),
     .PHY_1_BITLANES                (PHY_1_BITLANES),
     .PHY_2_BITLANES                (PHY_2_BITLANES),
     .PHY_0_BITLANES_OUTONLY        (PHY_0_BITLANES_OUTONLY),
     .PHY_1_BITLANES_OUTONLY        (PHY_1_BITLANES_OUTONLY),
     .PHY_2_BITLANES_OUTONLY        (PHY_2_BITLANES_OUTONLY),
     .RCLK_SELECT_BANK              (CKE_ODT_RCLK_SELECT_BANK),
     .RCLK_SELECT_LANE              (CKE_ODT_RCLK_SELECT_LANE),
     //.CKE_ODT_AUX                   (CKE_ODT_AUX),
     .GENERATE_DDR_CK_MAP           (TMP_GENERATE_DDR_CK_MAP),
     .BYTELANES_DDR_CK              (TMP_BYTELANES_DDR_CK),
     .NUM_DDR_CK                    (CK_WIDTH),
     .LP_DDR_CK_WIDTH               (LP_DDR_CK_WIDTH),
     .PO_CTL_COARSE_BYPASS          ("FALSE"),  
     .PHYCTL_CMD_FIFO               ("FALSE"),
     .PHY_CLK_RATIO                 (nCK_PER_CLK),
     .MASTER_PHY_CTL                (MASTER_PHY_CTL),
     .PHY_FOUR_WINDOW_CLOCKS        (63),
     .PHY_EVENTS_DELAY              (18),
     .PHY_COUNT_EN                  ("FALSE"), //PHY_COUNT_EN
     .PHY_SYNC_MODE                 ("FALSE"),
     .SYNTHESIS                     ((SIM_CAL_OPTION == "NONE") ? "TRUE" : "FALSE"),
     .PHY_DISABLE_SEQ_MATCH         ("TRUE"), //"TRUE"     
     .PHY_0_GENERATE_IDELAYCTRL     ("FALSE"),
     .PHY_0_A_PI_FREQ_REF_DIV       (PHY_0_A_PI_FREQ_REF_DIV),
     .PHY_0_CMD_OFFSET              (PHY_0_CMD_OFFSET),   //for CKE
     .PHY_0_RD_CMD_OFFSET_0         (PHY_0_RD_CMD_OFFSET_0),
     .PHY_0_RD_CMD_OFFSET_1         (PHY_0_RD_CMD_OFFSET_1),
     .PHY_0_RD_CMD_OFFSET_2         (PHY_0_RD_CMD_OFFSET_2),
     .PHY_0_RD_CMD_OFFSET_3         (PHY_0_RD_CMD_OFFSET_3),
     .PHY_0_RD_DURATION_0           (6),
     .PHY_0_RD_DURATION_1           (6),
     .PHY_0_RD_DURATION_2           (6),
     .PHY_0_RD_DURATION_3           (6),
     .PHY_0_WR_CMD_OFFSET_0         (PHY_0_WR_CMD_OFFSET_0),
     .PHY_0_WR_CMD_OFFSET_1         (PHY_0_WR_CMD_OFFSET_1),
     .PHY_0_WR_CMD_OFFSET_2         (PHY_0_WR_CMD_OFFSET_2),
     .PHY_0_WR_CMD_OFFSET_3         (PHY_0_WR_CMD_OFFSET_3),
     .PHY_0_WR_DURATION_0           (PHY_0_WR_DURATION_0),
     .PHY_0_WR_DURATION_1           (PHY_0_WR_DURATION_1),
     .PHY_0_WR_DURATION_2           (PHY_0_WR_DURATION_2),
     .PHY_0_WR_DURATION_3           (PHY_0_WR_DURATION_3), 
     .PHY_0_AO_TOGGLE               ((RANKS == 1) ? 4'b0001 : 4'b0101), 
     .PHY_0_A_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_0_B_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_0_C_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_0_D_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_0_A_PO_OCLKDELAY_INV      (PO_OCLKDELAY_INV),
     .PHY_0_A_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_0_B_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_0_C_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_0_D_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_1_GENERATE_IDELAYCTRL     ("FALSE"),
     //.PHY_1_GENERATE_DDR_CK         (TMP_PHY_1_GENERATE_DDR_CK),
     //.PHY_1_NUM_DDR_CK              (1),
     .PHY_1_A_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_1_B_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_1_C_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_1_D_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_1_A_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_1_B_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_1_C_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_1_D_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_2_GENERATE_IDELAYCTRL     ("FALSE"),
     //.PHY_2_GENERATE_DDR_CK         (TMP_PHY_2_GENERATE_DDR_CK),
     //.PHY_2_NUM_DDR_CK              (1),
     .PHY_2_A_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_2_B_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_2_C_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_2_D_PO_OCLK_DELAY         (PHY_0_A_PO_OCLK_DELAY),
     .PHY_2_A_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_2_B_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_2_C_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .PHY_2_D_IDELAYE2_IDELAY_VALUE (PHY_0_A_IDELAYE2_IDELAY_VALUE),
     .TCK                           (tCK),
     .PHY_0_IODELAY_GRP             (IODELAY_GRP)
     ,.PHY_1_IODELAY_GRP             (IODELAY_GRP)
     ,.PHY_2_IODELAY_GRP             (IODELAY_GRP)
     ,.BANK_TYPE                     (BANK_TYPE)
     ,.CKE_ODT_AUX                   (CKE_ODT_AUX)
     )
    u_ddr_mc_phy
      (
       .rst                    (rst),
       // Don't use MC_PHY to generate DDR_RESET_N output. Instead
       // generate this output outside of MC_PHY (and synchronous to CLK)
       .ddr_rst_in_n           (1'b1),
       .phy_clk                (clk),
       .freq_refclk            (freq_refclk),
       .mem_refclk             (mem_refclk),
       // Remove later - always same connection as phy_clk port
       .mem_refclk_div4        (clk),
       .pll_lock               (pll_lock),
       .auxout_clk             (),
       .sync_pulse             (sync_pulse),
       // IDELAYCTRL instantiated outside of mc_phy module
       .idelayctrl_refclk      (),
       .phy_dout               (phy_dout),
       .phy_cmd_wr_en          (phy_cmd_wr_en),
       .phy_data_wr_en         (phy_data_wr_en),
       .phy_rd_en              (phy_rd_en),
       .phy_ctl_wd             (phy_ctl_wd_temp),
       .phy_ctl_wr             (phy_ctl_wr_temp),
       .if_empty_def           (phy_if_empty_def),
       .if_rst                 (phy_if_reset),
       .phyGo                  ('b1),
       .aux_in_1               (aux_in_1),
       .aux_in_2               (aux_in_2),
       // No support yet for different data offsets for different I/O banks
       // (possible use in supporting wider range of skew among bytes)
       .data_offset_1          (data_offset_1_temp),
       .data_offset_2          (data_offset_2_temp),
       .cke_in                 (),
       .if_a_empty             (),
       .if_empty               (if_empty),
       .if_empty_or            (),
       .if_empty_and           (),
       .of_ctl_a_full          (),
      // .of_data_a_full         (phy_data_full),
       .of_ctl_full            (phy_cmd_full),
       .of_data_full           (),
       .pre_data_a_full        (phy_pre_data_a_full),
       .idelay_ld              (idelay_ld),
       .idelay_ce              (idelay_ce),
       .idelay_inc             (idelay_inc),
       .input_sink             (),
       .phy_din                (phy_din),
       .phy_ctl_a_full         (),
       .phy_ctl_full           (phy_ctl_full_temp),
       .mem_dq_out             (mem_dq_out),
       .mem_dq_ts              (mem_dq_ts),
       .mem_dq_in              (mem_dq_in),
       .mem_dqs_out            (mem_dqs_out),
       .mem_dqs_ts             (mem_dqs_ts),
       .mem_dqs_in             (mem_dqs_in),
       .aux_out                (aux_out),
       .phy_ctl_ready          (),
       .rst_out                (),
       .ddr_clk                (ddr_clk),
       //.rclk                   (),
       .mcGo                   (phy_mc_go),
       .phy_write_calib        (phy_write_calib),
       .phy_read_calib         (phy_read_calib),
       .calib_sel              (calib_sel),
       .calib_in_common        (calib_in_common),
       .calib_zero_inputs      (calib_zero_inputs),
       .calib_zero_ctrl        (calib_zero_ctrl),
       .calib_zero_lanes       ('b0),
       .po_fine_enable         (po_fine_enable),
       .po_coarse_enable       (po_coarse_enable),
       .po_fine_inc            (po_fine_inc),
       .po_coarse_inc          (po_coarse_inc),
       .po_counter_load_en     (po_counter_load_en),
       .po_sel_fine_oclk_delay (po_sel_fine_oclk_delay),
       .po_counter_load_val    (po_counter_load_val),
       .po_counter_read_en     (po_counter_read_en),
       .po_coarse_overflow     (),
       .po_fine_overflow       (),
       .po_counter_read_val    (po_counter_read_val),
       .pi_rst_dqs_find        (pi_rst_dqs_find),
       .pi_fine_enable         (pi_fine_enable),
       .pi_fine_inc            (pi_fine_inc),
       .pi_counter_load_en     (pi_counter_load_en),
       .pi_counter_read_en     (dbg_pi_counter_read_en),
       .pi_counter_load_val    (pi_counter_load_val),
       .pi_fine_overflow       (),
       .pi_counter_read_val    (pi_counter_read_val),
       .pi_phase_locked        (pi_phase_locked),
       .pi_phase_locked_all    (pi_phase_locked_all),
       .pi_dqs_found           (),
       .pi_dqs_found_any       (pi_dqs_found),
       .pi_dqs_found_all       (pi_dqs_found_all),
       .pi_dqs_found_lanes     (dbg_pi_dqs_found_lanes_phy4lanes),
       // Currently not being used. May be used in future if periodic
       // reads become a requirement. This output could be used to signal 
       // a catastrophic failure in read capture and the need for 
       // re-calibration.
       .pi_dqs_out_of_range    (pi_dqs_out_of_range)

       ,.ref_dll_lock          (ref_dll_lock)
       ,.pi_phase_locked_lanes (dbg_pi_phase_locked_phy4lanes)
//       ,.rst_phaser_ref        (rst_phaser_ref)
       );
      
endmodule
