//*****************************************************************************
// DISCLAIMER OF LIABILITY
//
// This file contains proprietary and confidential information of
// Xilinx, Inc. ("Xilinx"), that is distributed under a license
// from Xilinx, and may be used, copied and/or disclosed only
// pursuant to the terms of a valid license agreement with Xilinx.
//
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION
// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT
// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT,
// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx
// does not warrant that functions included in the Materials will
// meet the requirements of Licensee, or that the operation of the
// Materials will be uninterrupted or error-free, or that defects
// in the Materials will be corrected. Furthermore, Xilinx does
// not warrant or make any representations regarding use, or the
// results of the use, of the Materials in terms of correctness,
// accuracy, reliability or otherwise.
//
// 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.
//
// Copyright 2006, 2007, 2008 Xilinx, Inc.
// All rights reserved.
//
// This disclaimer and copyright notice must be retained as part
// of this file at all times.
//*****************************************************************************
//   ____  ____
//  /   /\/   /
// /___/  \  /    Vendor: Xilinx
// \   \   \/     Version: 3.4
//  \   \         Application: MIG
//  /   /         Filename: ddr2_ctrl.v
// /___/   /\     Date Last Modified: $Date: 2009/11/03 04:43:17 $
// \   \  /  \    Date Created: Wed Aug 30 2006
//  \___\/\___\
//
//
//Device: Virtex-5
//Design Name: DDR/DDR2
//Purpose:
//   This module is the main control logic of the memory interface. All
//   commands are issued from here according to the burst, CAS Latency and the
//   user commands.
//Reference:
//Revision History:
//   Rev 1.2 - Fixed auto refresh to activate bug. KP 11-19-2007
//   Rev 1.3 - For Dual Rank parts support CS logic modified. KP. 05/08/08
//   Rev 1.4 - AUTO_REFRESH_WAIT state modified for Auto Refresh flag asserted
//             immediately after calibration is completed. KP. 07/28/08
//   Rev 1.5 - Assignment of bank_valid_r is modified to fix a bug in 
//             Bank Management logic. PK. 10/29/08
//*****************************************************************************

`timescale 1ns/1ps

module ddr2_ctrl #
  (
   // Following parameters are for 72-bit RDIMM design (for ML561 Reference
   // board design). Actual values may be different. Actual parameters values
   // are passed from design top module mig_v3_4 module. Please refer to
   // the mig_v3_4 module for actual values.
   parameter BANK_WIDTH    = 2,
   parameter COL_WIDTH     = 10,
   parameter CS_BITS       = 0,
   parameter CS_NUM        = 1,
   parameter ROW_WIDTH     = 14,
   parameter ADDITIVE_LAT  = 0,
   parameter BURST_LEN     = 4,
   parameter CAS_LAT       = 5,
   parameter ECC_ENABLE    = 0,
   parameter REG_ENABLE    = 1,
   parameter TREFI_NS      = 7800,
   parameter TRAS          = 40000,
   parameter TRCD          = 15000,
   parameter TRRD          = 10000,
   parameter TRFC          = 105000,
   parameter TRP           = 15000,
   parameter TRTP          = 7500,
   parameter TWR           = 15000,
   parameter TWTR          = 10000,
   parameter CLK_PERIOD    = 3000,
   parameter MULTI_BANK_EN = 1,
   parameter TWO_T_TIME_EN = 0,
   parameter DDR_TYPE      = 1
   )
  (
   input                   clk,
   input                   rst,
   input [2:0]             af_cmd,
   input [30:0]            af_addr,
   input                   af_empty,
   input                   phy_init_done,
   output                  ctrl_ref_flag,
   output                  ctrl_af_rden,
   output reg              ctrl_wren,
   output reg              ctrl_rden,
   output [ROW_WIDTH-1:0]  ctrl_addr,
   output [BANK_WIDTH-1:0] ctrl_ba,
   output                  ctrl_ras_n,
   output                  ctrl_cas_n,
   output                  ctrl_we_n,
   output [CS_NUM-1:0]     ctrl_cs_n
   );

  // input address split into various ranges
  localparam ROW_RANGE_START     = COL_WIDTH;
  localparam ROW_RANGE_END       = ROW_WIDTH + ROW_RANGE_START - 1;
  localparam BANK_RANGE_START    = ROW_RANGE_END + 1;
  localparam BANK_RANGE_END      = BANK_WIDTH + BANK_RANGE_START - 1;
  localparam CS_RANGE_START      = BANK_RANGE_START + BANK_WIDTH;
  localparam CS_RANGE_END        = CS_BITS + CS_RANGE_START - 1;
  // compare address (for determining bank/row hits) split into various ranges
  // (compare address doesn't include column bits)
  localparam CMP_WIDTH            = CS_BITS + BANK_WIDTH + ROW_WIDTH;
  localparam CMP_ROW_RANGE_START  = 0;
  localparam CMP_ROW_RANGE_END    = ROW_WIDTH + CMP_ROW_RANGE_START - 1;
  localparam CMP_BANK_RANGE_START = CMP_ROW_RANGE_END + 1;
  localparam CMP_BANK_RANGE_END   = BANK_WIDTH + CMP_BANK_RANGE_START - 1;
  localparam CMP_CS_RANGE_START   = CMP_BANK_RANGE_END + 1;
  localparam CMP_CS_RANGE_END     = CS_BITS + CMP_CS_RANGE_START-1;

  localparam BURST_LEN_DIV2      = BURST_LEN / 2;
  localparam OPEN_BANK_NUM       = 4;
  localparam CS_BITS_FIX         = (CS_BITS == 0) ? 1 : CS_BITS;

  // calculation counters based on clock cycle and memory parameters
  // TRAS: ACTIVE->PRECHARGE interval - 2
  localparam integer TRAS_CYC = (TRAS + CLK_PERIOD)/CLK_PERIOD;
  // TRCD: ACTIVE->READ/WRITE interval - 3 (for DDR2 factor in ADD_LAT)
  localparam integer TRRD_CYC = (TRRD + CLK_PERIOD)/CLK_PERIOD;
  localparam integer TRCD_CYC = (((TRCD + CLK_PERIOD)/CLK_PERIOD) >
                                 ADDITIVE_LAT )?
             ((TRCD+CLK_PERIOD)/ CLK_PERIOD) - ADDITIVE_LAT : 0;
  // TRFC: REFRESH->REFRESH, REFRESH->ACTIVE interval - 2
  localparam integer TRFC_CYC = (TRFC + CLK_PERIOD)/CLK_PERIOD;
  // TRP: PRECHARGE->COMMAND interval - 2
   // for precharge all add 1 extra clock cycle
  localparam integer TRP_CYC =  ((TRP + CLK_PERIOD)/CLK_PERIOD) +1;
  // TRTP: READ->PRECHARGE interval - 2 (Al + BL/2 + (max (TRTP, 2tck))-2
  localparam integer TRTP_TMP_MIN = (((TRTP + CLK_PERIOD)/CLK_PERIOD) >= 2)?
                                     ((TRTP + CLK_PERIOD)/CLK_PERIOD) : 2;
  localparam integer TRTP_CYC = TRTP_TMP_MIN + ADDITIVE_LAT
                                + BURST_LEN_DIV2 - 2;
  // TWR: WRITE->PRECHARGE interval - 2
  localparam integer WR_LAT = (DDR_TYPE > 0) ? CAS_LAT + ADDITIVE_LAT - 1 : 1;
  localparam integer TWR_CYC = ((TWR + CLK_PERIOD)/CLK_PERIOD) +
             WR_LAT + BURST_LEN_DIV2 ;
  // TWTR: WRITE->READ interval - 3 (for DDR1, TWTR = 2 clks)
  // DDR2 = CL-1 + BL/2 +TWTR
  localparam integer TWTR_TMP_MIN = ((TWTR + CLK_PERIOD) % CLK_PERIOD)?((TWTR + CLK_PERIOD)/CLK_PERIOD) + 1:(TWTR + CLK_PERIOD)/CLK_PERIOD;
  localparam integer TWTR_CYC = (DDR_TYPE > 0) ? (TWTR_TMP_MIN + (CAS_LAT -1)
                                 + BURST_LEN_DIV2 ): 2;

  //  TRTW: READ->WRITE interval - 3
  //  DDR1: CL + (BL/2)
  //  DDR2: (BL/2) + 2. Two more clocks are added to
  //  the DDR2 counter to account for the delay in
  //  arrival of the DQS during reads (pcb trace + buffer
  //  delays + memory parameters).
  localparam TRTW_CYC = (DDR_TYPE > 0) ? BURST_LEN_DIV2 + 4 :
             (CAS_LAT == 25) ? 2 + BURST_LEN_DIV2 : CAS_LAT + BURST_LEN_DIV2;

  localparam integer CAS_LAT_RD = (CAS_LAT == 25) ? 2 : CAS_LAT;

  // Make sure all values >= 0 (some may be = 0)
  localparam TRAS_COUNT = (TRAS_CYC > 0) ? TRAS_CYC : 0;
  localparam TRCD_COUNT = (TRCD_CYC > 0) ? TRCD_CYC : 0;
  localparam TRRD_COUNT = (TRRD_CYC > 0) ? TRRD_CYC : 0;
  localparam TRFC_COUNT = (TRFC_CYC > 0) ? TRFC_CYC : 0;
  localparam TRP_COUNT  = (TRP_CYC > 0)  ? TRP_CYC  : 0;
  localparam TRTP_COUNT = (TRTP_CYC > 0) ? TRTP_CYC : 0;
  localparam TWR_COUNT  = (TWR_CYC > 0)  ? TWR_CYC  : 0;
  localparam TWTR_COUNT = (TWTR_CYC > 0) ? TWTR_CYC : 0;
  localparam TRTW_COUNT = (TRTW_CYC > 0) ? TRTW_CYC : 0;

  // Auto refresh interval
  localparam TREFI_COUNT = ((TREFI_NS * 1000)/CLK_PERIOD) - 1;

  // memory controller states
  localparam   CTRL_IDLE                =     5'h00;
  localparam   CTRL_PRECHARGE           =     5'h01;
  localparam   CTRL_PRECHARGE_WAIT      =     5'h02;
  localparam   CTRL_AUTO_REFRESH        =     5'h03;
  localparam   CTRL_AUTO_REFRESH_WAIT   =     5'h04;
  localparam   CTRL_ACTIVE              =     5'h05;
  localparam   CTRL_ACTIVE_WAIT         =     5'h06;
  localparam   CTRL_BURST_READ          =     5'h07;
  localparam   CTRL_READ_WAIT           =     5'h08;
  localparam   CTRL_BURST_WRITE         =     5'h09;
  localparam   CTRL_WRITE_WAIT          =     5'h0A;
  localparam   CTRL_PRECHARGE_WAIT1     =     5'h0B;


  reg [CMP_WIDTH-1:0]                      act_addr_r;
  wire [30:0]                              af_addr_r;
  reg [30:0]                               af_addr_r1;
  reg [30:0]                               af_addr_r2;
  reg [30:0]                               af_addr_r3;
  wire [2:0]                               af_cmd_r;
  reg [2:0]                                af_cmd_r1;
  reg [2:0]                                af_cmd_r2;
  reg                                      af_valid_r;
  reg                                      af_valid_r1;
  reg                                      af_valid_r2;
  reg [CS_BITS_FIX :0]                     auto_cnt_r;
  reg                                      auto_ref_r;
  reg [(OPEN_BANK_NUM*CMP_WIDTH)-1:0]      bank_cmp_addr_r;
  reg [OPEN_BANK_NUM-1:0]                  bank_hit;
  reg [OPEN_BANK_NUM-1:0]                  bank_hit_r;
  reg [OPEN_BANK_NUM-1:0]                  bank_hit_r1;
  reg [OPEN_BANK_NUM-1:0]                  bank_valid_r;
  reg                                      bank_conflict_r;
  reg                                      conflict_resolved_r;
  reg                                      ctrl_af_rden_r;
  reg                                      conflict_detect_r;
  wire                                     conflict_detect;
  reg                                      cs_change_r;
  reg                                      cs_change_sticky_r;
  reg [ROW_WIDTH-1:0]                      ddr_addr_r;
  wire [ROW_WIDTH-1:0]                     ddr_addr_col;
  wire [ROW_WIDTH-1:0]                     ddr_addr_row;
  reg [BANK_WIDTH-1:0]                     ddr_ba_r;
  reg                                      ddr_cas_n_r;
  reg [CS_NUM-1:0]                         ddr_cs_n_r;
  reg                                      ddr_ras_n_r;
  reg                                      ddr_we_n_r;
  reg [4:0]                                next_state;
  reg                                      no_precharge_wait_r;
  reg                                      no_precharge_r;
  reg                                      no_precharge_r1;
  reg                                      phy_init_done_r;
  reg [4:0]                                precharge_ok_cnt_r;
  reg                                      precharge_ok_r;
  reg [4:0]                                ras_cnt_r;
  reg [3:0]                                rcd_cnt_r;
  reg                                      rcd_cnt_ok_r;
  reg [2:0]                                rdburst_cnt_r;
  reg                                      rdburst_ok_r;
  reg                                      rdburst_rden_ok_r;
  reg                                      rd_af_flag_r;
  wire                                     rd_flag;
  reg                                      rd_flag_r;
  reg [4:0]                                rd_to_wr_cnt_r;
  reg                                      rd_to_wr_ok_r;
  reg                                      ref_flag_r;
  reg [11:0]                               refi_cnt_r;
  reg                                      refi_cnt_ok_r;
  reg                                      rst_r
                                           /* synthesis syn_preserve = 1 */;
  reg                                      rst_r1
                                           /* synthesis syn_maxfan = 10 */;
  reg [7:0]                                rfc_cnt_r;
  reg                                      rfc_ok_r;
  reg [3:0]                                row_miss;
  reg [3:0]                                row_conflict_r;
  reg [3:0]                                rp_cnt_r;
  reg                                      rp_cnt_ok_r;
  reg [CMP_WIDTH-1:0]                      sb_open_add_r;
  reg [4:0]                                state_r;
  reg [4:0]                                state_r1;
  wire                                     sm_rden;
  reg                                      sm_rden_r;
  reg [2:0]                                trrd_cnt_r;
  reg                                      trrd_cnt_ok_r;
  reg [2:0]                                two_t_enable_r;
  reg [CS_NUM-1:0]                         two_t_enable_r1;
  reg [2:0]                                wrburst_cnt_r;
  reg                                      wrburst_ok_r;
  reg                                      wrburst_wren_ok_r;
  wire                                     wr_flag;
  reg                                      wr_flag_r;
  reg [4:0]                                wr_to_rd_cnt_r;
  reg                                      wr_to_rd_ok_r;

  // XST attributes for local reset "tree"
  // synthesis attribute shreg_extract of rst_r is "no";
  // synthesis attribute shreg_extract of rst_r1 is "no";
  // synthesis attribute equivalent_register_removal of rst_r is "no"

  //***************************************************************************

  // sm_rden is used to assert read enable to the address FIFO
  assign sm_rden = ((state_r == CTRL_BURST_WRITE) ||
                    (state_r == CTRL_BURST_READ)) ;

  // assert read flag to the adress FIFO
  assign ctrl_af_rden = sm_rden || rd_af_flag_r;

  // local reset "tree" for controller logic only. Create this to ease timing
  // on reset path. Prohibit equivalent register removal on RST_R to prevent
  // "sharing" with other local reset trees (caution: make sure global fanout
  // limit is set to large enough value, otherwise SLICES may be used for
  // fanout control on RST_R.
  always @(posedge clk) begin
    rst_r  <= rst;
    rst_r1 <= rst_r;
  end

  //*****************************************************************
  // interpret commands from Command/Address FIFO
  //*****************************************************************

  assign wr_flag = (af_valid_r2) ? ((af_cmd_r2 == 3'b000) ? 1'b1 : 1'b0): 1'b0;
  assign rd_flag = (af_valid_r2) ? ((af_cmd_r2 == 3'b001) ? 1'b1 : 1'b0): 1'b0;

  always @(posedge clk) begin
    rd_flag_r <= rd_flag;
    wr_flag_r <= wr_flag;
  end

  //////////////////////////////////////////////////
  // The data from the address FIFO is fetched and
  // stored in two register stages. The data will be
  // pulled out of the second register stage whenever
  // the state machine can handle new data from the
  // address FIFO.

  // This flag is asserted when there is no
  // cmd & address in the pipe. When there is
  // valid cmd & addr from the address FIFO the
  // af_valid signals will be asserted. This flag will
  // be set the cycle af_valid_r is de-asserted.
  always @(posedge clk) begin
    // for simulation purposes - to force CTRL_AF_RDEN low during reset
    if (rst_r1)
      rd_af_flag_r <= 1'd0;
    else if((ctrl_af_rden_r) ||
            (rd_af_flag_r && (af_valid_r || af_valid_r1)))
         rd_af_flag_r <= 1'd0;
    else if (~af_valid_r1 || ~af_valid_r)
         rd_af_flag_r <= 1'd1;

  end

  // First register stage for the cmd & add from the FIFO.
  // The af_valid_r signal gives the status of the data
  // in this stage. The af_valid_r will be asserted when there
  // is valid data. This register stage will be updated
  // 1. read to the FIFO and the FIFO not empty
  // 2. After write and read states
  // 3. The valid signal is not asserted in the last stage.
  always @(posedge clk) begin
    if (rst_r1)begin
      af_valid_r <= 1'd0;
    end else begin
      if (ctrl_af_rden_r || sm_rden_r || ~af_valid_r1
          || ~af_valid_r2)begin
        af_valid_r <= ctrl_af_rden_r;
      end
    end
  end

  // The output register in the FIFO is used. The addr
  // and command are already registered in the FIFO.
  assign af_addr_r = af_addr;
  assign af_cmd_r = af_cmd;

  // Second register stage for the cmd & add from the FIFO.
  // The af_valid_r1 signal gives the status of the data
  // in this stage. The af_valid_r will be asserted when there
  // is valid data. This register stage will be updated
  // 1. read to the FIFO and the FIFO not empty and there
  // is no valid data on this stage
  // 2. After write and read states
  // 3. The valid signal is not asserted in the last stage.
  always@(posedge clk) begin
    if (rst_r1)begin
      af_valid_r1 <= 1'd0;
      af_addr_r1 <= {31{1'bx}};
      af_cmd_r1 <= {3{1'bx}};
    end else if (~af_valid_r1 || sm_rden_r ||
                  ~af_valid_r2) begin
      af_valid_r1 <= af_valid_r;
      af_addr_r1 <= af_addr_r;
      af_cmd_r1 <= af_cmd_r;
    end
  end

  // The state machine uses the address and command in this
  // register stage. The data is fetched from the second
  // register stage whenever the state machine can accept new
  // addr. The conflict flags are also generated based on the
  // second register stage and updated when the new address
  // is loaded for the state machine.
  always@(posedge clk) begin
    if (rst_r1)begin
      af_valid_r2 <= 1'd0;
      af_addr_r2 <= {31{1'bx}};
      af_cmd_r2 <= {3{1'bx}};
      bank_hit_r <= {OPEN_BANK_NUM{1'bx}};
      bank_conflict_r <= 1'bx;
      row_conflict_r <= 4'bx;
    end else if(sm_rden || ~af_valid_r2)begin
      af_valid_r2 <= af_valid_r1;
      af_addr_r2 <= af_addr_r1;
      af_cmd_r2 <= af_cmd_r1;
      if(MULTI_BANK_EN)begin
        bank_hit_r <= bank_hit;
        row_conflict_r <= row_miss;
        bank_conflict_r <= (~(|bank_hit));
      end else begin
        bank_hit_r <= {OPEN_BANK_NUM{1'b0}};
        bank_conflict_r <= 1'd0;
        row_conflict_r[0] <= (af_addr_r1[CS_RANGE_END:ROW_RANGE_START]
                              != sb_open_add_r[CMP_WIDTH-1:0]);
      end
    end
  end // always@ (posedge clk)

  //detecting cs change for multi chip select case
  generate
    if(CS_NUM > 1) begin: gen_cs_change
       always @(posedge clk) begin
          if(sm_rden || ~af_valid_r2)begin
            cs_change_r <= af_addr_r1[CS_RANGE_END:CS_RANGE_START] !=
                       af_addr_r2[CS_RANGE_END:CS_RANGE_START] ;
            cs_change_sticky_r <=
             af_addr_r1[CS_RANGE_END:CS_RANGE_START] !=
             af_addr_r2[CS_RANGE_END:CS_RANGE_START] ;
          end else
            cs_change_r <= 1'd0;
       end
    end // block: gen_cs_change
    else begin: gen_cs_0
       always @(posedge clk) begin
          cs_change_r <= 1'd0;
          cs_change_sticky_r <= 1'd0;
       end
    end
 endgenerate

  assign conflict_detect = (MULTI_BANK_EN) ?
                           ((|(row_conflict_r[3:0] & bank_hit_r[3:0]))
                            | bank_conflict_r) & af_valid_r2 :
                           row_conflict_r[0] & af_valid_r2;

  always @(posedge clk) begin
    conflict_detect_r <= conflict_detect;
    sm_rden_r <= sm_rden;
    af_addr_r3 <= af_addr_r2;
    ctrl_af_rden_r <= ctrl_af_rden & ~af_empty;
  end

  // conflict resolved signal. When this signal is asserted
  // the conflict is resolved. The address to be compared
  // for the conflict_resolved_r will be stored in act_add_r
  // when the bank is opened.
  always @(posedge clk) begin
   conflict_resolved_r <= (act_addr_r ==
                           af_addr_r2[CS_RANGE_END:ROW_RANGE_START]);
    if((state_r == CTRL_ACTIVE))
      act_addr_r <= af_addr_r2[CS_RANGE_END:ROW_RANGE_START];
  end

  //***************************************************************************
  // Bank management logic
  // Semi-hardcoded for now for 4 banks
  // will keep multiple banks open if MULTI_BANK_EN is true.
  //***************************************************************************

  genvar bank_i;
  generate // if multiple bank option chosen
    if(MULTI_BANK_EN) begin: gen_multi_bank_open

      for (bank_i = 0; bank_i < OPEN_BANK_NUM;
           bank_i = bank_i + 1) begin: gen_bank_hit1
        // asserted if bank address match + open bank entry is valid
        always @(*) begin
          bank_hit[bank_i]
            = ((bank_cmp_addr_r[(CMP_WIDTH*(bank_i+1))-1:
                                (CMP_WIDTH*bank_i)+ROW_WIDTH] ==
                af_addr_r1[CS_RANGE_END:BANK_RANGE_START]) &&
               bank_valid_r[bank_i]);
          // asserted if row address match (no check for bank entry valid, rely
          // on this term to be used in conjunction with BANK_HIT[])
          row_miss[bank_i]
            = (bank_cmp_addr_r[(CMP_WIDTH*bank_i)+ROW_WIDTH-1:
                               (CMP_WIDTH*bank_i)] !=
               af_addr_r1[ROW_RANGE_END:ROW_RANGE_START]);
        end
      end

      always @(posedge clk) begin
        no_precharge_wait_r  <= bank_valid_r[3] & bank_conflict_r;
        bank_hit_r1 <= bank_hit_r;
      end

      always@(*)
        no_precharge_r = ~bank_valid_r[3] & bank_conflict_r;

      always@(posedge clk)
        no_precharge_r1 <= no_precharge_r;


      always @(posedge clk) begin
        // Clear all bank valid bits during AR (i.e. since all banks get
        // precharged during auto-refresh)
        if ((state_r1 == CTRL_AUTO_REFRESH)) begin
          bank_valid_r    <= {OPEN_BANK_NUM{1'b0}};
          bank_cmp_addr_r <= {(OPEN_BANK_NUM*CMP_WIDTH-1){1'b0}};
        end else begin
          if (state_r1 == CTRL_ACTIVE) begin
            // 00 is always going to have the latest bank and row.
            bank_cmp_addr_r[CMP_WIDTH-1:0]
              <= af_addr_r3[CS_RANGE_END:ROW_RANGE_START];
            // This indicates the bank was activated
            bank_valid_r[0] <= 1'b1;

            case ({bank_hit_r1[2:0]})
              3'b001: begin
                bank_cmp_addr_r[CMP_WIDTH-1:0]
                  <= af_addr_r3[CS_RANGE_END:ROW_RANGE_START];
                // This indicates the bank was activated
                bank_valid_r[0] <= 1'b1;
              end
              3'b010: begin //(b0->b1)
                bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH]
                  <= bank_cmp_addr_r[CMP_WIDTH-1:0];
                bank_valid_r[1] <= bank_valid_r[0];
              end
              3'b100:begin //(b0->b1, b1->b2)
                bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH]
                  <= bank_cmp_addr_r[CMP_WIDTH-1:0];
                bank_cmp_addr_r[(3*CMP_WIDTH)-1:2*CMP_WIDTH]
                  <= bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH];
                bank_valid_r[1] <= bank_valid_r[0];
                bank_valid_r[2] <= bank_valid_r[1];
              end
              default: begin //(b0->b1, b1->b2, b2->b3)
                bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH]
                  <= bank_cmp_addr_r[CMP_WIDTH-1:0];
                bank_cmp_addr_r[(3*CMP_WIDTH)-1:2*CMP_WIDTH]
                  <= bank_cmp_addr_r[(2*CMP_WIDTH)-1:CMP_WIDTH];
                bank_cmp_addr_r[(4*CMP_WIDTH)-1:3*CMP_WIDTH]
                  <= bank_cmp_addr_r[(3*CMP_WIDTH)-1:2*CMP_WIDTH];
                bank_valid_r[1] <= bank_valid_r[0];
                bank_valid_r[2] <= bank_valid_r[1];
                bank_valid_r[3] <= bank_valid_r[2];
              end
            endcase
          end
        end
      end
    end else begin: gen_single_bank_open // single bank option
      always @(posedge clk) begin
        no_precharge_r       <= 1'd0;
        no_precharge_r1      <= 1'd0;
        no_precharge_wait_r  <= 1'd0;
        if (rst_r1)
          sb_open_add_r <= {CMP_WIDTH{1'b0}};
        else if (state_r == CTRL_ACTIVE)
          sb_open_add_r <= af_addr_r2[CS_RANGE_END:ROW_RANGE_START];
      end
    end
  endgenerate

  //***************************************************************************
  // Timing counters
  //***************************************************************************

  //*****************************************************************
  // Write and read enable generation for PHY
  //*****************************************************************

  // write burst count. Counts from (BL/2 to 1).
  // Also logic for controller write enable.
  always @(posedge clk) begin
    if (state_r == CTRL_BURST_WRITE) begin
      wrburst_cnt_r <= BURST_LEN_DIV2;
    end else if (wrburst_cnt_r >= 3'd1)
      wrburst_cnt_r <= wrburst_cnt_r - 1;
  end // always @ (posedge clk)


  always @(posedge clk) begin
    if (rst_r1) begin
      ctrl_wren   <= 1'b0;
    end else if (state_r == CTRL_BURST_WRITE) begin
      ctrl_wren   <= 1'b1;
    end else if (wrburst_wren_ok_r)
      ctrl_wren   <= 1'b0;
  end


  always @(posedge clk) begin
    if ((state_r == CTRL_BURST_WRITE)
        && (BURST_LEN_DIV2 > 2))
      wrburst_ok_r <= 1'd0;
    else if ((wrburst_cnt_r <= 3'd3) ||
             (BURST_LEN_DIV2 <= 2))
      wrburst_ok_r <= 1'b1;
  end

  // flag to check when wrburst count has reached
  // a value of 1. This flag is used in the ctrl_wren
  // logic
  always @(posedge clk) begin
     if(wrburst_cnt_r == 3'd2)
       wrburst_wren_ok_r <=1'b1;
     else
       wrburst_wren_ok_r <= 1'b0;
  end


  // read burst count. Counts from (BL/2 to 1)
  always @(posedge clk) begin
   if (state_r == CTRL_BURST_READ) begin
      rdburst_cnt_r <= BURST_LEN_DIV2;
    end else if (rdburst_cnt_r >= 3'd1)
      rdburst_cnt_r <= rdburst_cnt_r - 1;
  end // always @ (posedge clk)


   always @(posedge clk) begin
    if (rst_r1) begin
      ctrl_rden   <= 1'b0;
    end else if (state_r == CTRL_BURST_READ) begin
      ctrl_rden   <= 1'b1;
    end else if (rdburst_rden_ok_r)
      ctrl_rden   <= 1'b0;
   end

  // the rd_burst_ok_r signal will be asserted one cycle later
  // in multi chip select cases if the back to back read is to
  // different chip selects. The cs_changed_sticky_r signal will
  // be asserted only for multi chip select cases.
  always @(posedge clk) begin
    if ((state_r == CTRL_BURST_READ)
        && (BURST_LEN_DIV2 > 2))
      rdburst_ok_r <= 1'd0;
    else if ((rdburst_cnt_r <=( 3'd3 - cs_change_sticky_r)) ||
             (BURST_LEN_DIV2 <= 2))
      rdburst_ok_r <= 1'b1;
  end

  // flag to check when rdburst count has reached
  // a value of 1. This flag is used in the ctrl_rden
  // logic
  always @(posedge clk) begin
     if (rdburst_cnt_r == 3'd2)
       rdburst_rden_ok_r <= 1'b1;
     else
       rdburst_rden_ok_r <= 1'b0;
  end


  //*****************************************************************
  // Various delay counters
  // The counters are checked for value of <= 3 to determine the
  // if the count values are reached during different commands.
  // It is checked for 3 because
  // 1. The counters are loaded during the state when the command
  //    state is reached (+1)
  // 2. After the <= 3 condition is reached the sm takes two cycles
  //    to transition to the new command state (+2)
  //*****************************************************************

  // tRP count - precharge command period
  always @(posedge clk) begin
    if (state_r == CTRL_PRECHARGE)
      rp_cnt_r <= TRP_COUNT;
    else if (rp_cnt_r != 4'd0)
      rp_cnt_r <= rp_cnt_r - 1;
  end

  always @(posedge clk) begin
    if (state_r == CTRL_PRECHARGE)
      rp_cnt_ok_r <= 1'd0;
    else if (rp_cnt_r <= 4'd3)
      rp_cnt_ok_r <= 1'd1;
  end

  // tRFC count - refresh-refresh, refresh-active
  always @(posedge clk) begin
    if (state_r == CTRL_AUTO_REFRESH)
      rfc_cnt_r <= TRFC_COUNT;
    else if (rfc_cnt_r != 8'd0)
      rfc_cnt_r <= rfc_cnt_r - 1;
  end

  always @(posedge clk) begin
    if (state_r == CTRL_AUTO_REFRESH)
      rfc_ok_r <= 1'b0;
    else if(rfc_cnt_r <= 8'd3)
      rfc_ok_r <= 1'b1;
  end

  // tRCD count - active to read/write
  always @(posedge clk) begin
    if (state_r == CTRL_ACTIVE)
      rcd_cnt_r <= TRCD_COUNT;
    else if (rcd_cnt_r != 4'd0)
      rcd_cnt_r <= rcd_cnt_r - 1;
  end

  always @(posedge clk) begin
    if ((state_r == CTRL_ACTIVE)
        && (TRCD_COUNT > 2))
      rcd_cnt_ok_r <= 1'd0;
    else if (rcd_cnt_r <= 4'd3)
      rcd_cnt_ok_r <= 1;
  end

  // tRRD count - active to active
  always @(posedge clk) begin
    if (state_r == CTRL_ACTIVE)
      trrd_cnt_r <= TRRD_COUNT;
    else if (trrd_cnt_r != 3'd0)
      trrd_cnt_r <= trrd_cnt_r - 1;
  end

  always @(posedge clk) begin
    if (state_r == CTRL_ACTIVE)
      trrd_cnt_ok_r <= 1'd0;
    else if (trrd_cnt_r <= 3'd3)
      trrd_cnt_ok_r <= 1;
  end

  // tRAS count - active to precharge
  always @(posedge clk) begin
    if (state_r == CTRL_ACTIVE)
      ras_cnt_r <= TRAS_COUNT;
    else if (ras_cnt_r != 5'd0)
      ras_cnt_r <= ras_cnt_r - 1;
  end

  // counter for write to prcharge
  // read to precharge and
  // activate to precharge
  // precharge_ok_cnt_r is added with trtp count,
  // there can be cases where the sm can go from
  // activate to read and the act->pre count time
  // would not have been satisfied. The rd->pre
   // time is very less. wr->pre time is almost the
   // same as act-> pre
  always @(posedge clk) begin
    if (state_r == CTRL_BURST_READ) begin
      // assign only if the cnt is < TRTP_COUNT
      if (precharge_ok_cnt_r < TRTP_COUNT)
        precharge_ok_cnt_r <= TRTP_COUNT;
    end else if (state_r == CTRL_BURST_WRITE)
      precharge_ok_cnt_r <= TWR_COUNT;
    else if (state_r == CTRL_ACTIVE)
      if (precharge_ok_cnt_r <= TRAS_COUNT)
        precharge_ok_cnt_r <= TRAS_COUNT;
      else
        precharge_ok_cnt_r <= precharge_ok_cnt_r - 1;
    else if (precharge_ok_cnt_r != 5'd0)
      precharge_ok_cnt_r <= precharge_ok_cnt_r - 1;
  end

  always @(posedge clk) begin
    if ((state_r == CTRL_BURST_READ) ||
        (state_r == CTRL_BURST_WRITE)||
        (state_r == CTRL_ACTIVE))
      precharge_ok_r <= 1'd0;
    else if(precharge_ok_cnt_r <= 5'd3)
      precharge_ok_r <=1'd1;
  end

  // write to read counter
  // write to read includes : write latency + burst time + tWTR
  always @(posedge clk) begin
    if (rst_r1)
      wr_to_rd_cnt_r <= 5'd0;
    else if (state_r == CTRL_BURST_WRITE)
      wr_to_rd_cnt_r <= (TWTR_COUNT);
    else if (wr_to_rd_cnt_r != 5'd0)
      wr_to_rd_cnt_r <= wr_to_rd_cnt_r - 1;
  end

  always @(posedge clk) begin
    if (state_r == CTRL_BURST_WRITE)
      wr_to_rd_ok_r <= 1'd0;
    else if (wr_to_rd_cnt_r <= 5'd3)
      wr_to_rd_ok_r <= 1'd1;
  end

  // read to write counter
  always @(posedge clk) begin
    if (rst_r1)
      rd_to_wr_cnt_r <= 5'd0;
    else if (state_r == CTRL_BURST_READ)
      rd_to_wr_cnt_r <= (TRTW_COUNT);
    else if (rd_to_wr_cnt_r != 5'd0)
      rd_to_wr_cnt_r <= rd_to_wr_cnt_r - 1;
  end

  always @(posedge clk) begin
    if (state_r == CTRL_BURST_READ)
      rd_to_wr_ok_r <= 1'b0;
    else if (rd_to_wr_cnt_r <= 5'd3)
      rd_to_wr_ok_r <= 1'b1;
  end

  always @(posedge clk) begin
     if(refi_cnt_r == (TREFI_COUNT -1))
       refi_cnt_ok_r <= 1'b1;
     else
       refi_cnt_ok_r <= 1'b0;
  end

  // auto refresh interval counter in refresh_clk domain
  always @(posedge clk) begin
    if ((rst_r1) || (refi_cnt_ok_r))  begin
      refi_cnt_r <= 12'd0;
    end else begin
      refi_cnt_r <= refi_cnt_r + 1;
    end
  end // always @ (posedge clk)

  // auto refresh flag
  always @(posedge clk) begin
    if (refi_cnt_ok_r) begin
      ref_flag_r <= 1'b1;
    end else begin
      ref_flag_r <= 1'b0;
    end
  end // always @ (posedge clk)

  assign ctrl_ref_flag = ref_flag_r;

  //refresh flag detect
  //auto_ref high indicates auto_refresh requirement
  //auto_ref is held high until auto refresh command is issued.
  always @(posedge clk)begin
    if (rst_r1)
      auto_ref_r <= 1'b0;
    else if (ref_flag_r)
      auto_ref_r <= 1'b1;
    else if (state_r == CTRL_AUTO_REFRESH)
      auto_ref_r <= 1'b0;
  end


  // keep track of which chip selects got auto-refreshed (avoid auto-refreshing
  // all CS's at once to avoid current spike)
  always @(posedge clk)begin
    if (rst_r1 || (state_r1 == CTRL_PRECHARGE))
      auto_cnt_r <= 'd0;
    else if (state_r1 == CTRL_AUTO_REFRESH)
      auto_cnt_r <= auto_cnt_r + 1;
  end

  // register for timing purposes. Extra delay doesn't really matter
  always @(posedge clk)
    phy_init_done_r <= phy_init_done;

  always @(posedge clk)begin
    if (rst_r1) begin
      state_r    <= CTRL_IDLE;
      state_r1 <= CTRL_IDLE;
    end else begin
      state_r    <= next_state;
      state_r1 <= state_r;
    end
  end

  //***************************************************************************
  // main control state machine
  //***************************************************************************

  always @(*) begin
    next_state = state_r;
    (* full_case, parallel_case *) case (state_r)
      CTRL_IDLE: begin
        // perform auto refresh as soon as we are done with calibration.
        // The calibration logic does not do any refreshes.
        if (phy_init_done_r)
          next_state = CTRL_AUTO_REFRESH;
      end

      CTRL_PRECHARGE: begin
        if (auto_ref_r)
          next_state = CTRL_PRECHARGE_WAIT1;
        // when precharging an LRU bank, do not have to go to wait state
        // since we can't possibly be activating row in same bank next
        // disabled for 2t timing. There needs to be a gap between cmds
        // in 2t timing
        else if (no_precharge_wait_r && !TWO_T_TIME_EN)
          next_state = CTRL_ACTIVE;
        else
          next_state = CTRL_PRECHARGE_WAIT;
      end

      CTRL_PRECHARGE_WAIT:begin
        if (rp_cnt_ok_r)begin
          if (auto_ref_r)
            // precharge again to make sure we close all the banks
            next_state = CTRL_PRECHARGE;
          else
            next_state = CTRL_ACTIVE;
        end
      end

      CTRL_PRECHARGE_WAIT1:
        if (rp_cnt_ok_r)
          next_state = CTRL_AUTO_REFRESH;

      CTRL_AUTO_REFRESH:
        next_state = CTRL_AUTO_REFRESH_WAIT;

      CTRL_AUTO_REFRESH_WAIT:
      //staggering Auto refresh for multi
      // chip select designs. The SM waits
      // for the rfc time before issuing the
      // next auto refresh.
        if (auto_cnt_r < (CS_NUM))begin
           if (rfc_ok_r )
              next_state = CTRL_AUTO_REFRESH;
           end else if (rfc_ok_r)begin
              if(auto_ref_r)
                // MIG 2.3: For deep designs if Auto Refresh
                // flag asserted immediately after calibration is completed
                next_state = CTRL_PRECHARGE;
              else if  ( wr_flag || rd_flag)
                next_state = CTRL_ACTIVE;
            end

      CTRL_ACTIVE:
        next_state = CTRL_ACTIVE_WAIT;

      CTRL_ACTIVE_WAIT: begin
        if (rcd_cnt_ok_r) begin
          if ((conflict_detect_r && ~conflict_resolved_r) ||
              auto_ref_r) begin
            if (no_precharge_r1 && ~auto_ref_r && trrd_cnt_ok_r)
              next_state = CTRL_ACTIVE;
            else  if(precharge_ok_r)
              next_state = CTRL_PRECHARGE;
          end else if ((wr_flag_r) && (rd_to_wr_ok_r))
            next_state = CTRL_BURST_WRITE;
          else if ((rd_flag_r)&& (wr_to_rd_ok_r))
            next_state = CTRL_BURST_READ;
        end
      end

      // beginning of write burst
      CTRL_BURST_WRITE: begin
        if (BURST_LEN_DIV2 == 1) begin
          // special case if BL = 2 (i.e. burst lasts only one clk cycle)
          if (wr_flag)
            // if we have another non-conflict write command right after the
            // current write, then stay in this state
            next_state = CTRL_BURST_WRITE;
          else
            // otherwise, if we're done with this burst, and have no write
            // immediately scheduled after this one, wait until write-read
            // delay has passed
            next_state = CTRL_WRITE_WAIT;
        end else
          // otherwise BL > 2, and we  have at least one more write cycle for
          // current burst
          next_state = CTRL_WRITE_WAIT;
        // continuation of write burst (also covers waiting after write burst
        // has completed for write-read delay to pass)
      end

      CTRL_WRITE_WAIT: begin
        if ((conflict_detect) || auto_ref_r) begin
          if (no_precharge_r && ~auto_ref_r && wrburst_ok_r)
            next_state = CTRL_ACTIVE;
          else if (precharge_ok_r)
            next_state = CTRL_PRECHARGE;
        end else if (wrburst_ok_r && wr_flag)
          next_state = CTRL_BURST_WRITE;
        else if ((rd_flag) && (wr_to_rd_ok_r))
          next_state = CTRL_BURST_READ;
      end

      CTRL_BURST_READ: begin
        if (BURST_LEN_DIV2 == 1) begin
          // special case if BL = 2 (i.e. burst lasts only one clk cycle)
          if (rd_flag)
            next_state = CTRL_BURST_READ;
          else
            next_state = CTRL_READ_WAIT;
        end else
          next_state = CTRL_READ_WAIT;
      end

      CTRL_READ_WAIT: begin
        if ((conflict_detect) || auto_ref_r)begin
          if (no_precharge_r && ~auto_ref_r && rdburst_ok_r)
            next_state = CTRL_ACTIVE;
          else if (precharge_ok_r)
            next_state = CTRL_PRECHARGE;
        // for burst of 4 in multi chip select
        // if there is a change in cs wait one cycle before the
        // next read command. cs_change_r will be asserted.
        end else if (rdburst_ok_r  && rd_flag && ~cs_change_r)
          next_state = CTRL_BURST_READ;
        else if (wr_flag && (rd_to_wr_ok_r))
          next_state = CTRL_BURST_WRITE;
      end
    endcase
  end

  //***************************************************************************
  // control signals to memory
  //***************************************************************************

  always @(posedge clk) begin
     if ((state_r == CTRL_AUTO_REFRESH) ||
         (state_r == CTRL_ACTIVE) ||
         (state_r == CTRL_PRECHARGE)) begin
       ddr_ras_n_r <= 1'b0;
       two_t_enable_r[0] <= 1'b0;
     end else begin
       if (TWO_T_TIME_EN)
         ddr_ras_n_r <= two_t_enable_r[0] ;
       else
         ddr_ras_n_r <= 1'd1;
       two_t_enable_r[0] <= 1'b1;
     end
  end

  always @(posedge clk)begin
    if ((state_r == CTRL_BURST_WRITE) ||
        (state_r == CTRL_BURST_READ) ||
        (state_r == CTRL_AUTO_REFRESH)) begin
      ddr_cas_n_r <= 1'b0;
      two_t_enable_r[1] <= 1'b0;
    end else begin
      if (TWO_T_TIME_EN)
        ddr_cas_n_r <= two_t_enable_r[1];
      else
        ddr_cas_n_r <= 1'b1;
      two_t_enable_r[1] <= 1'b1;
    end
  end

  always @(posedge clk) begin
    if ((state_r == CTRL_BURST_WRITE) ||
        (state_r == CTRL_PRECHARGE)) begin
      ddr_we_n_r <= 1'b0;
      two_t_enable_r[2] <= 1'b0;
    end else begin
      if(TWO_T_TIME_EN)
        ddr_we_n_r <= two_t_enable_r[2];
      else
        ddr_we_n_r <= 1'b1;
      two_t_enable_r[2] <= 1'b1;
    end
  end

  // turn off auto-precharge when issuing commands (A10 = 0)
  // mapping the col add for linear addressing.
  generate
    if (TWO_T_TIME_EN) begin: gen_addr_col_two_t
      if (COL_WIDTH == ROW_WIDTH-1) begin: gen_ddr_addr_col_0
        assign ddr_addr_col = {af_addr_r3[COL_WIDTH-1:10], 1'b0,
                               af_addr_r3[9:0]};
      end else begin
        if (COL_WIDTH > 10) begin: gen_ddr_addr_col_1
          assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}},
                                 af_addr_r3[COL_WIDTH-1:10], 1'b0,
                                 af_addr_r3[9:0]};
        end else begin: gen_ddr_addr_col_2
          assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, 1'b0,
                               af_addr_r3[COL_WIDTH-1:0]};
        end
      end
    end else begin: gen_addr_col_one_t
      if (COL_WIDTH == ROW_WIDTH-1) begin: gen_ddr_addr_col_0_1
        assign ddr_addr_col = {af_addr_r2[COL_WIDTH-1:10], 1'b0,
                               af_addr_r2[9:0]};
      end else begin
        if (COL_WIDTH > 10) begin: gen_ddr_addr_col_1_1
          assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}},
                                 af_addr_r2[COL_WIDTH-1:10], 1'b0,
                                 af_addr_r2[9:0]};
        end else begin: gen_ddr_addr_col_2_1
          assign ddr_addr_col = {{(ROW_WIDTH-COL_WIDTH-1){1'b0}}, 1'b0,
                                 af_addr_r2[COL_WIDTH-1:0]};
        end
      end
    end
  endgenerate

  // Assign address during row activate
  generate
    if (TWO_T_TIME_EN)
      assign ddr_addr_row = af_addr_r3[ROW_RANGE_END:ROW_RANGE_START];
    else
      assign ddr_addr_row = af_addr_r2[ROW_RANGE_END:ROW_RANGE_START];
  endgenerate


  always @(posedge clk)begin
    if ((state_r == CTRL_ACTIVE) ||
        ((state_r1 == CTRL_ACTIVE) && TWO_T_TIME_EN))
      ddr_addr_r <= ddr_addr_row;
    else if ((state_r == CTRL_BURST_WRITE) ||
             (state_r == CTRL_BURST_READ)  ||
             (((state_r1 == CTRL_BURST_WRITE) ||
               (state_r1 == CTRL_BURST_READ)) &&
              TWO_T_TIME_EN))
      ddr_addr_r <= ddr_addr_col;
    else if (((state_r == CTRL_PRECHARGE)  ||
              ((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN))
             && auto_ref_r) begin
      // if we're precharging as a result of AUTO-REFRESH, precharge all banks
      ddr_addr_r <= {ROW_WIDTH{1'b0}};
      ddr_addr_r[10] <= 1'b1;
    end else if ((state_r == CTRL_PRECHARGE) ||
                 ((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN))
      // if we're precharging to close a specific bank/row, set A10=0
      ddr_addr_r <= {ROW_WIDTH{1'b0}};
    else
      ddr_addr_r <= {ROW_WIDTH{1'bx}};
  end

  always @(posedge clk)begin
    // whenever we're precharging, we're either: (1) precharging all banks (in
    // which case banks bits are don't care, (2) precharging the LRU bank,
    // b/c we've exceeded the limit of # of banks open (need to close the LRU
    // bank to make room for a new one), (3) we haven't exceed the maximum #
    // of banks open, but we trying to open a different row in a bank that's
    // already open
    if (((state_r == CTRL_PRECHARGE)  ||
         ((state_r1 == CTRL_PRECHARGE) && TWO_T_TIME_EN)) &&
        bank_conflict_r && MULTI_BANK_EN)
      // When LRU bank needs to be closed
      ddr_ba_r <= bank_cmp_addr_r[(3*CMP_WIDTH)+CMP_BANK_RANGE_END:
                                  (3*CMP_WIDTH)+CMP_BANK_RANGE_START];
    else begin
      // Either precharge due to refresh or bank hit case
      if (TWO_T_TIME_EN)
        ddr_ba_r <= af_addr_r3[BANK_RANGE_END:BANK_RANGE_START];
      else
        ddr_ba_r <= af_addr_r2[BANK_RANGE_END:BANK_RANGE_START];
    end
  end

  // chip enable generation logic
  generate
    // if only one chip select, always assert it after reset
    if (CS_BITS == 0) begin: gen_ddr_cs_0
      always @(posedge clk)
        if (rst_r1)
          ddr_cs_n_r[0] <= 1'b1;
        else
          ddr_cs_n_r[0] <= 1'b0;
    // otherwise if we have multiple chip selects
      end else begin: gen_ddr_cs_1
      if(TWO_T_TIME_EN) begin: gen_2t_cs
         always @(posedge clk)
           if (rst_r1)
             ddr_cs_n_r <= {CS_NUM{1'b1}};
           else if ((state_r1 == CTRL_AUTO_REFRESH)) begin
             // if auto-refreshing, only auto-refresh one CS at any time (avoid
             // beating on the ground plane by refreshing all CS's at same time)
             ddr_cs_n_r <= {CS_NUM{1'b1}};
             ddr_cs_n_r[auto_cnt_r] <= 1'b0;
           end else if (auto_ref_r && (state_r1 == CTRL_PRECHARGE)) begin
             ddr_cs_n_r <= {CS_NUM{1'b0}};
           end else if ((state_r1 == CTRL_PRECHARGE) && ( bank_conflict_r
                    && MULTI_BANK_EN))begin
                  // precharging the LRU bank
                  ddr_cs_n_r <= {CS_NUM{1'b1}};
                  ddr_cs_n_r[bank_cmp_addr_r[(3*CMP_WIDTH)+CMP_CS_RANGE_END:
                  (3*CMP_WIDTH)+CMP_CS_RANGE_START]] <= 1'b0;
           end else begin
          // otherwise, check the upper address bits to see which CS to assert
             ddr_cs_n_r <= {CS_NUM{1'b1}};
             ddr_cs_n_r[af_addr_r3[CS_RANGE_END:CS_RANGE_START]] <= 1'b0;
           end // else: !if(((state_r == CTRL_PRECHARGE)  ||...
        end else begin: gen_1t_cs // block: gen_2t_cs
         always @(posedge clk)
           if (rst_r1)
             ddr_cs_n_r <= {CS_NUM{1'b1}};
           else if ((state_r == CTRL_AUTO_REFRESH) ) begin
             // if auto-refreshing, only auto-refresh one CS at any time (avoid
             // beating on the ground plane by refreshing all CS's at same time)
             ddr_cs_n_r <= {CS_NUM{1'b1}};
             ddr_cs_n_r[auto_cnt_r] <= 1'b0;
           end else if (auto_ref_r && (state_r == CTRL_PRECHARGE) ) begin
             ddr_cs_n_r <= {CS_NUM{1'b0}};
           end else if ((state_r == CTRL_PRECHARGE)  &&
                 (bank_conflict_r && MULTI_BANK_EN))begin
                  // precharging the LRU bank
                  ddr_cs_n_r <= {CS_NUM{1'b1}};
                  ddr_cs_n_r[bank_cmp_addr_r[(3*CMP_WIDTH)+CMP_CS_RANGE_END:
                  (3*CMP_WIDTH)+CMP_CS_RANGE_START]] <= 1'b0;
           end else begin
          // otherwise, check the upper address bits to see which CS to assert
             ddr_cs_n_r <= {CS_NUM{1'b1}};
             ddr_cs_n_r[af_addr_r2[CS_RANGE_END:CS_RANGE_START]] <= 1'b0;
           end // else: !if(((state_r == CTRL_PRECHARGE)  ||...
        end // block: gen_1t_cs
    end
  endgenerate

  // registring the two_t timing enable signal.
  // This signal will be asserted (low) when the
  // chip select has to be asserted.
  always @(posedge clk)begin
     if(&two_t_enable_r)
        two_t_enable_r1 <= {CS_NUM{1'b1}};
     else
        two_t_enable_r1 <= {CS_NUM{1'b0}};
  end

  assign ctrl_addr  = ddr_addr_r;
  assign ctrl_ba    = ddr_ba_r;
  assign ctrl_ras_n = ddr_ras_n_r;
  assign ctrl_cas_n = ddr_cas_n_r;
  assign ctrl_we_n  = ddr_we_n_r;
  assign ctrl_cs_n  = (TWO_T_TIME_EN) ?
                      (ddr_cs_n_r | two_t_enable_r1) :
                      ddr_cs_n_r;

endmodule

