OpenCores
URL https://opencores.org/ocsvn/genesys_ddr2/genesys_ddr2/trunk

Subversion Repositories genesys_ddr2

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /genesys_ddr2
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

trunk/bench/Xilinx_MIG_bench/sim Property changes : Deleted: bugtraq:number ## -1 +0,0 ## -true \ No newline at end of property Index: trunk/bench/Xilinx_MIG_bench =================================================================== --- trunk/bench/Xilinx_MIG_bench (revision 2) +++ trunk/bench/Xilinx_MIG_bench (nonexistent)
trunk/bench/Xilinx_MIG_bench Property changes : Deleted: bugtraq:number ## -1 +0,0 ## -true \ No newline at end of property Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_top.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_top.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_top.v (nonexistent) @@ -1,395 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_top.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// Top-level for memory physical layer (PHY) interface -//Reference: -//Revision History: -// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 -// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 -// Rev 1.3 - Parameter CS_BITS added. PK. 10/8/08 -// Rev 1.4 - Parameter IODELAY_GRP added. PK. 11/27/08 -//***************************************************************************** - -`timescale 1ns/1ps - -(* X_CORE_INFO = "mig_v3_61_ddr2_sdram_v5, Coregen 12.4" , CORE_GENERATION_INFO = "ddr2_sdram_v5,mig_v3_61,{component_name=ddr2_phy_top, BANK_WIDTH=2, CKE_WIDTH=1, CLK_WIDTH=2, COL_WIDTH=10, CS_NUM=1, CS_WIDTH=1, DM_WIDTH=8, DQ_WIDTH=64, DQ_PER_DQS=8, DQS_WIDTH=8, ODT_WIDTH=1, ROW_WIDTH=13, ADDITIVE_LAT=0, BURST_LEN=4, BURST_TYPE=0, CAS_LAT=3, ECC_ENABLE=0, MULTI_BANK_EN=1, TWO_T_TIME_EN=1, ODT_TYPE=1, REDUCE_DRV=0, REG_ENABLE=0, TREFI_NS=7800, TRAS=40000, TRCD=15000, TRFC=105000, TRP=15000, TRTP=7500, TWR=15000, TWTR=7500, CLK_PERIOD=8000, RST_ACT_LOW=1, INTERFACE_TYPE=DDR2_SDRAM, LANGUAGE=Verilog, SYNTHESIS_TOOL=ISE, NO_OF_CONTROLLERS=1}" *) -module ddr2_phy_top # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter CLK_WIDTH = 1, - parameter CKE_WIDTH = 1, - parameter COL_WIDTH = 10, - parameter CS_BITS = 0, - parameter CS_NUM = 1, - parameter CS_WIDTH = 1, - parameter USE_DM_PORT = 1, - parameter DM_WIDTH = 9, - parameter DQ_WIDTH = 72, - parameter DQ_BITS = 7, - parameter DQ_PER_DQS = 8, - parameter DQS_WIDTH = 9, - parameter DQS_BITS = 4, - parameter HIGH_PERFORMANCE_MODE = "TRUE", - parameter IODELAY_GRP = "IODELAY_MIG", - parameter ODT_WIDTH = 1, - parameter ROW_WIDTH = 14, - parameter ADDITIVE_LAT = 0, - parameter TWO_T_TIME_EN = 0, - parameter BURST_LEN = 4, - parameter BURST_TYPE = 0, - parameter CAS_LAT = 5, - parameter TWR = 15000, - parameter ECC_ENABLE = 0, - parameter ODT_TYPE = 1, - parameter DDR_TYPE = 1, - parameter REDUCE_DRV = 0, - parameter REG_ENABLE = 1, - parameter CLK_PERIOD = 3000, - parameter SIM_ONLY = 0, - parameter DEBUG_EN = 0, - parameter FPGA_SPEED_GRADE = 2 - ) - ( - input clk0, - input clk90, - input clkdiv0, - input rst0, - input rst90, - input rstdiv0, - input ctrl_wren, - input [ROW_WIDTH-1:0] ctrl_addr, - input [BANK_WIDTH-1:0] ctrl_ba, - input ctrl_ras_n, - input ctrl_cas_n, - input ctrl_we_n, - input [CS_NUM-1:0] ctrl_cs_n, - input ctrl_rden, - input ctrl_ref_flag, - input [(2*DQ_WIDTH)-1:0] wdf_data, - input [(2*DQ_WIDTH/8)-1:0] wdf_mask_data, - output wdf_rden, - output phy_init_done, - output [DQS_WIDTH-1:0] phy_calib_rden, - output [DQS_WIDTH-1:0] phy_calib_rden_sel, - output [DQ_WIDTH-1:0] rd_data_rise, - output [DQ_WIDTH-1:0] rd_data_fall, - output [CLK_WIDTH-1:0] ddr_ck, - output [CLK_WIDTH-1:0] ddr_ck_n, - output [ROW_WIDTH-1:0] ddr_addr, - output [BANK_WIDTH-1:0] ddr_ba, - output ddr_ras_n, - output ddr_cas_n, - output ddr_we_n, - output [CS_WIDTH-1:0] ddr_cs_n, - output [CKE_WIDTH-1:0] ddr_cke, - output [ODT_WIDTH-1:0] ddr_odt, - output [DM_WIDTH-1:0] ddr_dm, - inout [DQS_WIDTH-1:0] ddr_dqs, - inout [DQS_WIDTH-1:0] ddr_dqs_n, - inout [DQ_WIDTH-1:0] ddr_dq, - // Debug signals (optional use) - input dbg_idel_up_all, - input dbg_idel_down_all, - input dbg_idel_up_dq, - input dbg_idel_down_dq, - input dbg_idel_up_dqs, - input dbg_idel_down_dqs, - input dbg_idel_up_gate, - input dbg_idel_down_gate, - input [DQ_BITS-1:0] dbg_sel_idel_dq, - input dbg_sel_all_idel_dq, - input [DQS_BITS:0] dbg_sel_idel_dqs, - input dbg_sel_all_idel_dqs, - input [DQS_BITS:0] dbg_sel_idel_gate, - input dbg_sel_all_idel_gate, - output [3:0] dbg_calib_done, - output [3:0] dbg_calib_err, - output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, - output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, - output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, - output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly - ); - - wire [3:0] calib_done; - wire calib_ref_done; - wire calib_ref_req; - wire [3:0] calib_start; - wire dm_ce; - wire [1:0] dq_oe_n; - wire dqs_oe_n; - wire dqs_rst_n; - wire [(DQ_WIDTH/8)-1:0] mask_data_fall; - wire [(DQ_WIDTH/8)-1:0] mask_data_rise; - wire [CS_NUM-1:0] odt; - wire [ROW_WIDTH-1:0] phy_init_addr; - wire [BANK_WIDTH-1:0] phy_init_ba; - wire phy_init_cas_n; - wire [CKE_WIDTH-1:0] phy_init_cke; - wire [CS_NUM-1:0] phy_init_cs_n; - wire phy_init_data_sel; - wire phy_init_ras_n; - wire phy_init_rden; - wire phy_init_we_n; - wire phy_init_wren; - wire [DQ_WIDTH-1:0] wr_data_fall; - wire [DQ_WIDTH-1:0] wr_data_rise; - - //*************************************************************************** - - ddr2_phy_write # - ( - .DQ_WIDTH (DQ_WIDTH), - .CS_NUM (CS_NUM), - .ADDITIVE_LAT (ADDITIVE_LAT), - .CAS_LAT (CAS_LAT), - .ECC_ENABLE (ECC_ENABLE), - .ODT_TYPE (ODT_TYPE), - .REG_ENABLE (REG_ENABLE), - .DDR_TYPE (DDR_TYPE) - ) - u_phy_write - ( - .clk0 (clk0), - .clk90 (clk90), - .rst90 (rst90), - .wdf_data (wdf_data), - .wdf_mask_data (wdf_mask_data), - .ctrl_wren (ctrl_wren), - .phy_init_wren (phy_init_wren), - .phy_init_data_sel (phy_init_data_sel), - .dm_ce (dm_ce), - .dq_oe_n (dq_oe_n), - .dqs_oe_n (dqs_oe_n), - .dqs_rst_n (dqs_rst_n), - .wdf_rden (wdf_rden), - .odt (odt), - .wr_data_rise (wr_data_rise), - .wr_data_fall (wr_data_fall), - .mask_data_rise (mask_data_rise), - .mask_data_fall (mask_data_fall) - ); - - ddr2_phy_io # - ( - .CLK_WIDTH (CLK_WIDTH), - .USE_DM_PORT (USE_DM_PORT), - .DM_WIDTH (DM_WIDTH), - .DQ_WIDTH (DQ_WIDTH), - .DQ_BITS (DQ_BITS), - .DQ_PER_DQS (DQ_PER_DQS), - .DQS_BITS (DQS_BITS), - .DQS_WIDTH (DQS_WIDTH), - .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), - .IODELAY_GRP (IODELAY_GRP), - .ODT_WIDTH (ODT_WIDTH), - .ADDITIVE_LAT (ADDITIVE_LAT), - .CAS_LAT (CAS_LAT), - .REG_ENABLE (REG_ENABLE), - .CLK_PERIOD (CLK_PERIOD), - .DDR_TYPE (DDR_TYPE), - .SIM_ONLY (SIM_ONLY), - .DEBUG_EN (DEBUG_EN), - .FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) - ) - u_phy_io - ( - .clk0 (clk0), - .clk90 (clk90), - .clkdiv0 (clkdiv0), - .rst0 (rst0), - .rst90 (rst90), - .rstdiv0 (rstdiv0), - .dm_ce (dm_ce), - .dq_oe_n (dq_oe_n), - .dqs_oe_n (dqs_oe_n), - .dqs_rst_n (dqs_rst_n), - .calib_start (calib_start), - .ctrl_rden (ctrl_rden), - .phy_init_rden (phy_init_rden), - .calib_ref_done (calib_ref_done), - .calib_done (calib_done), - .calib_ref_req (calib_ref_req), - .calib_rden (phy_calib_rden), - .calib_rden_sel (phy_calib_rden_sel), - .wr_data_rise (wr_data_rise), - .wr_data_fall (wr_data_fall), - .mask_data_rise (mask_data_rise), - .mask_data_fall (mask_data_fall), - .rd_data_rise (rd_data_rise), - .rd_data_fall (rd_data_fall), - .ddr_ck (ddr_ck), - .ddr_ck_n (ddr_ck_n), - .ddr_dm (ddr_dm), - .ddr_dqs (ddr_dqs), - .ddr_dqs_n (ddr_dqs_n), - .ddr_dq (ddr_dq), - .dbg_idel_up_all (dbg_idel_up_all), - .dbg_idel_down_all (dbg_idel_down_all), - .dbg_idel_up_dq (dbg_idel_up_dq), - .dbg_idel_down_dq (dbg_idel_down_dq), - .dbg_idel_up_dqs (dbg_idel_up_dqs), - .dbg_idel_down_dqs (dbg_idel_down_dqs), - .dbg_idel_up_gate (dbg_idel_up_gate), - .dbg_idel_down_gate (dbg_idel_down_gate), - .dbg_sel_idel_dq (dbg_sel_idel_dq), - .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), - .dbg_sel_idel_dqs (dbg_sel_idel_dqs), - .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), - .dbg_sel_idel_gate (dbg_sel_idel_gate), - .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), - .dbg_calib_done (dbg_calib_done), - .dbg_calib_err (dbg_calib_err), - .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), - .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), - .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), - .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), - .dbg_calib_rden_dly (dbg_calib_rden_dly), - .dbg_calib_gate_dly (dbg_calib_gate_dly) - ); - - ddr2_phy_ctl_io # - ( - .BANK_WIDTH (BANK_WIDTH), - .CKE_WIDTH (CKE_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_NUM (CS_NUM), - .CS_WIDTH (CS_WIDTH), - .TWO_T_TIME_EN (TWO_T_TIME_EN), - .ODT_WIDTH (ODT_WIDTH), - .ROW_WIDTH (ROW_WIDTH), - .DDR_TYPE (DDR_TYPE) - ) - u_phy_ctl_io - ( - .clk0 (clk0), - .clk90 (clk90), - .rst0 (rst0), - .rst90 (rst90), - .ctrl_addr (ctrl_addr), - .ctrl_ba (ctrl_ba), - .ctrl_ras_n (ctrl_ras_n), - .ctrl_cas_n (ctrl_cas_n), - .ctrl_we_n (ctrl_we_n), - .ctrl_cs_n (ctrl_cs_n), - .phy_init_addr (phy_init_addr), - .phy_init_ba (phy_init_ba), - .phy_init_ras_n (phy_init_ras_n), - .phy_init_cas_n (phy_init_cas_n), - .phy_init_we_n (phy_init_we_n), - .phy_init_cs_n (phy_init_cs_n), - .phy_init_cke (phy_init_cke), - .phy_init_data_sel (phy_init_data_sel), - .odt (odt), - .ddr_addr (ddr_addr), - .ddr_ba (ddr_ba), - .ddr_ras_n (ddr_ras_n), - .ddr_cas_n (ddr_cas_n), - .ddr_we_n (ddr_we_n), - .ddr_cke (ddr_cke), - .ddr_cs_n (ddr_cs_n), - .ddr_odt (ddr_odt) - ); - - ddr2_phy_init # - ( - .BANK_WIDTH (BANK_WIDTH), - .CKE_WIDTH (CKE_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_BITS (CS_BITS), - .CS_NUM (CS_NUM), - .DQ_WIDTH (DQ_WIDTH), - .ODT_WIDTH (ODT_WIDTH), - .ROW_WIDTH (ROW_WIDTH), - .ADDITIVE_LAT (ADDITIVE_LAT), - .BURST_LEN (BURST_LEN), - .BURST_TYPE (BURST_TYPE), - .TWO_T_TIME_EN(TWO_T_TIME_EN), - .CAS_LAT (CAS_LAT), - .ODT_TYPE (ODT_TYPE), - .REDUCE_DRV (REDUCE_DRV), - .REG_ENABLE (REG_ENABLE), - .TWR (TWR), - .CLK_PERIOD (CLK_PERIOD), - .DDR_TYPE (DDR_TYPE), - .SIM_ONLY (SIM_ONLY) - ) - u_phy_init - ( - .clk0 (clk0), - .clkdiv0 (clkdiv0), - .rst0 (rst0), - .rstdiv0 (rstdiv0), - .calib_done (calib_done), - .ctrl_ref_flag (ctrl_ref_flag), - .calib_ref_req (calib_ref_req), - .calib_start (calib_start), - .calib_ref_done (calib_ref_done), - .phy_init_wren (phy_init_wren), - .phy_init_rden (phy_init_rden), - .phy_init_addr (phy_init_addr), - .phy_init_ba (phy_init_ba), - .phy_init_ras_n (phy_init_ras_n), - .phy_init_cas_n (phy_init_cas_n), - .phy_init_we_n (phy_init_we_n), - .phy_init_cs_n (phy_init_cs_n), - .phy_init_cke (phy_init_cke), - .phy_init_done (phy_init_done), - .phy_init_data_sel (phy_init_data_sel) - ); - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_init.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_init.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_init.v (nonexistent) @@ -1,1219 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_init.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Thu Aug 24 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -//Reference: -// This module is the intialization control logic of the memory interface. -// All commands are issued from here acoording to the burst, CAS Latency and -// the user commands. -//Revision History: -// Rev 1.1 - Localparam WR_RECOVERY added and mapped to -// load mode register. PK. 14/7/08 -// Rev 1.2 - To issue an Auto Refresh command to each chip during various -// calibration stages logic modified. PK. 08/10/08 -// Rev 1.3 - Retain current data pattern for stage 4 calibration, and create -// new pattern for stage 4. RC. 09/21/09. -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_phy_init # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter CKE_WIDTH = 1, - parameter COL_WIDTH = 10, - parameter CS_BITS = 0, - parameter CS_NUM = 1, - parameter DQ_WIDTH = 72, - parameter ODT_WIDTH = 1, - parameter ROW_WIDTH = 14, - parameter ADDITIVE_LAT = 0, - parameter BURST_LEN = 4, - parameter TWO_T_TIME_EN = 0, - parameter BURST_TYPE = 0, - parameter CAS_LAT = 5, - parameter ODT_TYPE = 1, - parameter REDUCE_DRV = 0, - parameter REG_ENABLE = 1, - parameter TWR = 15000, - parameter CLK_PERIOD = 3000, - parameter DDR_TYPE = 1, - parameter SIM_ONLY = 0 - ) - ( - input clk0, - input clkdiv0, - input rst0, - input rstdiv0, - input [3:0] calib_done, - input ctrl_ref_flag, - input calib_ref_req, - output reg [3:0] calib_start, - output reg calib_ref_done, - output reg phy_init_wren, - output reg phy_init_rden, - output [ROW_WIDTH-1:0] phy_init_addr, - output [BANK_WIDTH-1:0] phy_init_ba, - output phy_init_ras_n, - output phy_init_cas_n, - output phy_init_we_n, - output [CS_NUM-1:0] phy_init_cs_n, - output [CKE_WIDTH-1:0] phy_init_cke, - output reg phy_init_done, - output phy_init_data_sel - ); - - // time to wait between consecutive commands in PHY_INIT - this is a - // generic number, and must be large enough to account for worst case - // timing parameter (tRFC - refresh-to-active) across all memory speed - // grades and operating frequencies. Expressed in CLKDIV clock cycles. - localparam CNTNEXT_CMD = 7'b1111111; - // time to wait between read and read or precharge for stage 3 & 4 - // the larger CNTNEXT_CMD can also be used, use smaller number to - // speed up calibration - avoid tRAS violation, and speeds up simulation - localparam CNTNEXT_RD = 4'b1111; - - // Write recovery (WR) time - is defined by - // tWR (in nanoseconds) by tCK (in nanoseconds) and rounding up a - // noninteger value to the next integer - localparam integer WR_RECOVERY = ((TWR + CLK_PERIOD) - 1)/CLK_PERIOD; - localparam CS_BITS_FIX = (CS_BITS == 0) ? 1 : CS_BITS; - - localparam INIT_CAL1_READ = 5'h00; - localparam INIT_CAL2_READ = 5'h01; - localparam INIT_CAL3_READ = 5'h02; - localparam INIT_CAL4_READ = 5'h03; - localparam INIT_CAL1_WRITE = 5'h04; - localparam INIT_CAL2_WRITE = 5'h05; - localparam INIT_CAL3_WRITE = 5'h06; - localparam INIT_DUMMY_ACTIVE_WAIT = 5'h07; - localparam INIT_PRECHARGE = 5'h08; - localparam INIT_LOAD_MODE = 5'h09; - localparam INIT_AUTO_REFRESH = 5'h0A; - localparam INIT_IDLE = 5'h0B; - localparam INIT_CNT_200 = 5'h0C; - localparam INIT_CNT_200_WAIT = 5'h0D; - localparam INIT_PRECHARGE_WAIT = 5'h0E; - localparam INIT_MODE_REGISTER_WAIT = 5'h0F; - localparam INIT_AUTO_REFRESH_WAIT = 5'h10; - localparam INIT_DEEP_MEMORY_ST = 5'h11; - localparam INIT_DUMMY_ACTIVE = 5'h12; - localparam INIT_CAL1_WRITE_READ = 5'h13; - localparam INIT_CAL1_READ_WAIT = 5'h14; - localparam INIT_CAL2_WRITE_READ = 5'h15; - localparam INIT_CAL2_READ_WAIT = 5'h16; - localparam INIT_CAL3_WRITE_READ = 5'h17; - localparam INIT_CAL3_READ_WAIT = 5'h18; - localparam INIT_CAL4_READ_WAIT = 5'h19; - localparam INIT_CALIB_REF = 5'h1A; - localparam INIT_ZQCL = 5'h1B; - localparam INIT_WAIT_DLLK_ZQINIT = 5'h1C; - localparam INIT_CAL4_WRITE = 5'h1D; // MIG 3.3: New state - localparam INIT_CAL4_WRITE_READ = 5'h1E; // MIG 3.3: New state - - localparam INIT_CNTR_INIT = 4'h0; - localparam INIT_CNTR_PRECH_1 = 4'h1; - localparam INIT_CNTR_EMR2_INIT = 4'h2; - localparam INIT_CNTR_EMR3_INIT = 4'h3; - localparam INIT_CNTR_EMR_EN_DLL = 4'h4; - localparam INIT_CNTR_MR_RST_DLL = 4'h5; - localparam INIT_CNTR_CNT_200_WAIT = 4'h6; - localparam INIT_CNTR_PRECH_2 = 4'h7; - localparam INIT_CNTR_AR_1 = 4'h8; - localparam INIT_CNTR_AR_2 = 4'h9; - localparam INIT_CNTR_MR_ACT_DLL = 4'hA; - localparam INIT_CNTR_EMR_DEF_OCD = 4'hB; - localparam INIT_CNTR_EMR_EXIT_OCD = 4'hC; - localparam INIT_CNTR_DEEP_MEM = 4'hD; - // MIG 3.3: Remove extra precharge occurring at end of calibration -// localparam INIT_CNTR_PRECH_3 = 4'hE; -// localparam INIT_CNTR_DONE = 4'hF; - localparam INIT_CNTR_DONE = 4'hE; - - localparam DDR1 = 0; - localparam DDR2 = 1; - localparam DDR3 = 2; - - reg [CS_BITS_FIX :0] auto_cnt_r; - reg [1:0] burst_addr_r; - reg [1:0] burst_cnt_r; - wire [1:0] burst_val; - wire cal_read; - wire cal_write; - wire cal_write_read; - reg cal1_started_r; - reg cal2_started_r; - reg cal4_started_r; - reg [3:0] calib_done_r; - reg calib_ref_req_posedge; - reg calib_ref_req_r; - reg [15:0] calib_start_shift0_r; - reg [15:0] calib_start_shift1_r; - reg [15:0] calib_start_shift2_r; - reg [15:0] calib_start_shift3_r; - reg [1:0] chip_cnt_r; - reg [4:0] cke_200us_cnt_r; - reg cke_200us_cnt_en_r; - reg [7:0] cnt_200_cycle_r; - reg cnt_200_cycle_done_r; - reg [6:0] cnt_cmd_r; - reg cnt_cmd_ok_r; - reg [3:0] cnt_rd_r; - reg cnt_rd_ok_r; - reg ctrl_ref_flag_r; - reg done_200us_r; - reg [ROW_WIDTH-1:0] ddr_addr_r; - reg [ROW_WIDTH-1:0] ddr_addr_r1; - reg [BANK_WIDTH-1:0] ddr_ba_r; - reg [BANK_WIDTH-1:0] ddr_ba_r1; - reg ddr_cas_n_r; - reg ddr_cas_n_r1; - reg [CKE_WIDTH-1:0] ddr_cke_r; - reg [CS_NUM-1:0] ddr_cs_n_r; - reg [CS_NUM-1:0] ddr_cs_n_r1; - reg [CS_NUM-1:0] ddr_cs_disable_r; - reg ddr_ras_n_r; - reg ddr_ras_n_r1; - reg ddr_we_n_r; - reg ddr_we_n_r1; - wire [15:0] ext_mode_reg; - reg [3:0] init_cnt_r; - reg init_done_r; - reg [4:0] init_next_state; - reg [4:0] init_state_r; - reg [4:0] init_state_r1; - reg [4:0] init_state_r1_2t; - reg [4:0] init_state_r2; - wire [15:0] load_mode_reg; - wire [15:0] load_mode_reg0; - wire [15:0] load_mode_reg1; - wire [15:0] load_mode_reg2; - wire [15:0] load_mode_reg3; - reg phy_init_done_r; - reg phy_init_done_r1; - reg phy_init_done_r2; - reg phy_init_done_r3; - reg refresh_req; - wire [3:0] start_cal; - - //*************************************************************************** - - //***************************************************************** - // DDR1 and DDR2 Load mode register - // Mode Register (MR): - // [15:14] - unused - 00 - // [13] - reserved - 0 - // [12] - Power-down mode - 0 (normal) - // [11:9] - write recovery - for Auto Precharge (tWR/tCK) - // [8] - DLL reset - 0 or 1 - // [7] - Test Mode - 0 (normal) - // [6:4] - CAS latency - CAS_LAT - // [3] - Burst Type - BURST_TYPE - // [2:0] - Burst Length - BURST_LEN - //***************************************************************** - - generate - if (DDR_TYPE == DDR2) begin: gen_load_mode_reg_ddr2 - assign load_mode_reg[2:0] = (BURST_LEN == 8) ? 3'b011 : - ((BURST_LEN == 4) ? 3'b010 : 3'b111); - assign load_mode_reg[3] = BURST_TYPE; - assign load_mode_reg[6:4] = (CAS_LAT == 3) ? 3'b011 : - ((CAS_LAT == 4) ? 3'b100 : - ((CAS_LAT == 5) ? 3'b101 : 3'b111)); - assign load_mode_reg[7] = 1'b0; - assign load_mode_reg[8] = 1'b0; // init value only (DLL not reset) - assign load_mode_reg[11:9] = (WR_RECOVERY == 6) ? 3'b101 : - ((WR_RECOVERY == 5) ? 3'b100 : - ((WR_RECOVERY == 4) ? 3'b011 : - ((WR_RECOVERY == 3) ? 3'b010 : - 3'b001))); - assign load_mode_reg[15:12] = 4'b000; - end else if (DDR_TYPE == DDR1)begin: gen_load_mode_reg_ddr1 - assign load_mode_reg[2:0] = (BURST_LEN == 8) ? 3'b011 : - ((BURST_LEN == 4) ? 3'b010 : - ((BURST_LEN == 2) ? 3'b001 : 3'b111)); - assign load_mode_reg[3] = BURST_TYPE; - assign load_mode_reg[6:4] = (CAS_LAT == 2) ? 3'b010 : - ((CAS_LAT == 3) ? 3'b011 : - ((CAS_LAT == 25) ? 3'b110 : 3'b111)); - assign load_mode_reg[12:7] = 6'b000000; // init value only - assign load_mode_reg[15:13] = 3'b000; - end - endgenerate - - //***************************************************************** - // DDR1 and DDR2 ext mode register - // Extended Mode Register (MR): - // [15:14] - unused - 00 - // [13] - reserved - 0 - // [12] - output enable - 0 (enabled) - // [11] - RDQS enable - 0 (disabled) - // [10] - DQS# enable - 0 (enabled) - // [9:7] - OCD Program - 111 or 000 (first 111, then 000 during init) - // [6] - RTT[1] - RTT[1:0] = 0(no ODT), 1(75), 2(150), 3(50) - // [5:3] - Additive CAS - ADDITIVE_CAS - // [2] - RTT[0] - // [1] - Output drive - REDUCE_DRV (= 0(full), = 1 (reduced) - // [0] - DLL enable - 0 (normal) - //***************************************************************** - - generate - if (DDR_TYPE == DDR2) begin: gen_ext_mode_reg_ddr2 - assign ext_mode_reg[0] = 1'b0; - assign ext_mode_reg[1] = REDUCE_DRV; - assign ext_mode_reg[2] = ((ODT_TYPE == 1) || (ODT_TYPE == 3)) ? - 1'b1 : 1'b0; - assign ext_mode_reg[5:3] = (ADDITIVE_LAT == 0) ? 3'b000 : - ((ADDITIVE_LAT == 1) ? 3'b001 : - ((ADDITIVE_LAT == 2) ? 3'b010 : - ((ADDITIVE_LAT == 3) ? 3'b011 : - ((ADDITIVE_LAT == 4) ? 3'b100 : - 3'b111)))); - assign ext_mode_reg[6] = ((ODT_TYPE == 2) || (ODT_TYPE == 3)) ? - 1'b1 : 1'b0; - assign ext_mode_reg[9:7] = 3'b000; - assign ext_mode_reg[10] = 1'b0; - assign ext_mode_reg[15:10] = 6'b000000; - end else if (DDR_TYPE == DDR1) begin: gen_ext_mode_reg_ddr1 - assign ext_mode_reg[0] = 1'b0; - assign ext_mode_reg[1] = REDUCE_DRV; - assign ext_mode_reg[12:2] = 11'b00000000000; - assign ext_mode_reg[15:13] = 3'b000; - end - endgenerate - - //***************************************************************** - // DDR3 Load mode reg0 - // Mode Register (MR0): - // [15:13] - unused - 000 - // [12] - Precharge Power-down DLL usage - 0 (DLL frozen, slow-exit), - // 1 (DLL maintained) - // [11:9] - write recovery for Auto Precharge (tWR/tCK = 6) - // [8] - DLL reset - 0 or 1 - // [7] - Test Mode - 0 (normal) - // [6:4],[2] - CAS latency - CAS_LAT - // [3] - Burst Type - BURST_TYPE - // [1:0] - Burst Length - BURST_LEN - //***************************************************************** - - generate - if (DDR_TYPE == DDR3) begin: gen_load_mode_reg0_ddr3 - assign load_mode_reg0[1:0] = (BURST_LEN == 8) ? 2'b00 : - ((BURST_LEN == 4) ? 2'b10 : 2'b11); - // Part of CAS latency. This bit is '0' for all CAS latencies - assign load_mode_reg0[2] = 1'b0; - assign load_mode_reg0[3] = BURST_TYPE; - assign load_mode_reg0[6:4] = (CAS_LAT == 5) ? 3'b001 : - (CAS_LAT == 6) ? 3'b010 : 3'b111; - assign load_mode_reg0[7] = 1'b0; - // init value only (DLL reset) - assign load_mode_reg0[8] = 1'b1; - assign load_mode_reg0[11:9] = 3'b010; - // Precharge Power-Down DLL 'slow-exit' - assign load_mode_reg0[12] = 1'b0; - assign load_mode_reg0[15:13] = 3'b000; - end - endgenerate - - //***************************************************************** - // DDR3 Load mode reg1 - // Mode Register (MR1): - // [15:13] - unused - 00 - // [12] - output enable - 0 (enabled for DQ, DQS, DQS#) - // [11] - TDQS enable - 0 (TDQS disabled and DM enabled) - // [10] - reserved - 0 (must be '0') - // [9] - RTT[2] - 0 - // [8] - reserved - 0 (must be '0') - // [7] - write leveling - 0 (disabled), 1 (enabled) - // [6] - RTT[1] - RTT[1:0] = 0(no ODT), 1(75), 2(150), 3(50) - // [5] - Output driver impedance[1] - 0 (RZQ/6 and RZQ/7) - // [4:3] - Additive CAS - ADDITIVE_CAS - // [2] - RTT[0] - // [1] - Output driver impedance[0] - 0(RZQ/6), or 1 (RZQ/7) - // [0] - DLL enable - 0 (normal) - //***************************************************************** - - generate - if (DDR_TYPE == DDR3) begin: gen_ext_mode_reg1_ddr3 - // DLL enabled during Imitialization - assign load_mode_reg1[0] = 1'b0; - // RZQ/6 - assign load_mode_reg1[1] = REDUCE_DRV; - assign load_mode_reg1[2] = ((ODT_TYPE == 1) || (ODT_TYPE == 3)) ? - 1'b1 : 1'b0; - assign load_mode_reg1[4:3] = (ADDITIVE_LAT == 0) ? 2'b00 : - ((ADDITIVE_LAT == 1) ? 2'b01 : - ((ADDITIVE_LAT == 2) ? 2'b10 : - 3'b111)); - // RZQ/6 - assign load_mode_reg1[5] = 1'b0; - assign load_mode_reg1[6] = ((ODT_TYPE == 2) || (ODT_TYPE == 3)) ? - 1'b1 : 1'b0; - // Make zero WRITE_LEVEL - assign load_mode_reg1[7] = 0; - assign load_mode_reg1[8] = 1'b0; - assign load_mode_reg1[9] = 1'b0; - assign load_mode_reg1[10] = 1'b0; - assign load_mode_reg1[15:11] = 5'b00000; - end - endgenerate - - //***************************************************************** - // DDR3 Load mode reg2 - // Mode Register (MR2): - // [15:11] - unused - 00 - // [10:9] - RTT_WR - 00 (Dynamic ODT off) - // [8] - reserved - 0 (must be '0') - // [7] - self-refresh temperature range - - // 0 (normal), 1 (extended) - // [6] - Auto Self-Refresh - 0 (manual), 1(auto) - // [5:3] - CAS Write Latency (CWL) - - // 000 (5 for 400 MHz device), - // 001 (6 for 400 MHz to 533 MHz devices), - // 010 (7 for 533 MHz to 667 MHz devices), - // 011 (8 for 667 MHz to 800 MHz) - // [2:0] - Partial Array Self-Refresh (Optional) - - // 000 (full array) - //***************************************************************** - - generate - if (DDR_TYPE == DDR3) begin: gen_ext_mode_reg2_ddr3 - assign load_mode_reg2[2:0] = 3'b000; - assign load_mode_reg2[5:3] = (CAS_LAT == 5) ? 3'b000 : - (CAS_LAT == 6) ? 3'b001 : 3'b111; - assign load_mode_reg2[6] = 1'b0; // Manual Self-Refresh - assign load_mode_reg2[7] = 1'b0; - assign load_mode_reg2[8] = 1'b0; - assign load_mode_reg2[10:9] = 2'b00; - assign load_mode_reg2[15:11] = 5'b00000; - end - endgenerate - - //***************************************************************** - // DDR3 Load mode reg3 - // Mode Register (MR3): - // [15:3] - unused - All zeros - // [2] - MPR Operation - 0(normal operation), 1(data flow from MPR) - // [1:0] - MPR location - 00 (Predefined pattern) - //***************************************************************** - - generate - if (DDR_TYPE == DDR3)begin: gen_ext_mode_reg3_ddr3 - assign load_mode_reg3[1:0] = 2'b00; - assign load_mode_reg3[2] = 1'b0; - assign load_mode_reg3[15:3] = 13'b0000000000000; - end - endgenerate - - //*************************************************************************** - // Logic for calibration start, and for auto-refresh during cal request - // CALIB_REF_REQ is used by calibration logic to request auto-refresh - // durign calibration (used to avoid tRAS violation is certain calibration - // stages take a long time). Once the auto-refresh is complete and cal can - // be resumed, CALIB_REF_DONE is asserted by PHY_INIT. - //*************************************************************************** - - // generate pulse for each of calibration start controls - assign start_cal[0] = ((init_state_r1 == INIT_CAL1_READ) && - (init_state_r2 != INIT_CAL1_READ)); - assign start_cal[1] = ((init_state_r1 == INIT_CAL2_READ) && - (init_state_r2 != INIT_CAL2_READ)); - assign start_cal[2] = ((init_state_r1 == INIT_CAL3_READ) && - (init_state_r2 == INIT_CAL3_WRITE_READ)); - assign start_cal[3] = ((init_state_r1 == INIT_CAL4_READ) && - (init_state_r2 != INIT_CAL4_READ)); - // MIG 3.3: Change to accomodate FSM changes related to stage 4 calibration -// (init_state_r2 == INIT_CAL4_WRITE_READ)); - - // Generate positive-edge triggered, latched signal to force initialization - // to pause calibration, and to issue auto-refresh. Clear flag as soon as - // refresh initiated - always @(posedge clkdiv0) - if (rstdiv0) begin - calib_ref_req_r <= 1'b0; - calib_ref_req_posedge <= 1'b0; - refresh_req <= 1'b0; - end else begin - calib_ref_req_r <= calib_ref_req; - calib_ref_req_posedge <= calib_ref_req & ~calib_ref_req_r; - if (init_state_r1 == INIT_AUTO_REFRESH) - refresh_req <= 1'b0; - else if (calib_ref_req_posedge) - refresh_req <= 1'b1; - end - - // flag to tell cal1 calibration was started. - // This flag is used for cal1 auto refreshes - // some of these bits may not be needed - only needed for those stages that - // need refreshes within the stage (i.e. very long stages) - always @(posedge clkdiv0) - if (rstdiv0) begin - cal1_started_r <= 1'b0; - cal2_started_r <= 1'b0; - cal4_started_r <= 1'b0; - end else begin - if (calib_start[0]) - cal1_started_r <= 1'b1; - if (calib_start[1]) - cal2_started_r <= 1'b1; - if (calib_start[3]) - cal4_started_r <= 1'b1; - end - - // Delay start of each calibration by 16 clock cycles to - // ensure that when calibration logic begins, that read data is already - // appearing on the bus. Don't really need it, it's more for simulation - // purposes. Each circuit should synthesize using an SRL16. - // In first stage of calibration periodic auto refreshes - // will be issued to meet memory timing. calib_start_shift0_r[15] will be - // asserted more than once.calib_start[0] is anded with cal1_started_r so - // that it is asserted only once. cal1_refresh_done is anded with - // cal1_started_r so that it is asserted after the auto refreshes. - always @(posedge clkdiv0) begin - calib_start_shift0_r <= {calib_start_shift0_r[14:0], start_cal[0]}; - calib_start_shift1_r <= {calib_start_shift1_r[14:0], start_cal[1]}; - calib_start_shift2_r <= {calib_start_shift2_r[14:0], start_cal[2]}; - calib_start_shift3_r <= {calib_start_shift3_r[14:0], start_cal[3]}; - calib_start[0] <= calib_start_shift0_r[15] & ~cal1_started_r; - calib_start[1] <= calib_start_shift1_r[15] & ~cal2_started_r; - calib_start[2] <= calib_start_shift2_r[15]; - calib_start[3] <= calib_start_shift3_r[15] & ~cal4_started_r; - calib_ref_done <= calib_start_shift0_r[15] | - calib_start_shift1_r[15] | - calib_start_shift3_r[15]; - end - - // generate delay for various states that require it (no maximum delay - // requirement, make sure that terminal count is large enough to cover - // all cases) - always @(posedge clkdiv0) begin - case (init_state_r) - INIT_PRECHARGE_WAIT, - INIT_MODE_REGISTER_WAIT, - INIT_AUTO_REFRESH_WAIT, - INIT_DUMMY_ACTIVE_WAIT, - INIT_CAL1_WRITE_READ, - INIT_CAL1_READ_WAIT, - INIT_CAL2_WRITE_READ, - INIT_CAL2_READ_WAIT, - INIT_CAL3_WRITE_READ, - INIT_CAL4_WRITE_READ : - cnt_cmd_r <= cnt_cmd_r + 1; - default: - cnt_cmd_r <= 7'b0000000; - endcase - end - - // assert when count reaches the value - always @(posedge clkdiv0) begin - if(cnt_cmd_r == CNTNEXT_CMD) - cnt_cmd_ok_r <= 1'b1; - else - cnt_cmd_ok_r <= 1'b0; - end - - always @(posedge clkdiv0) begin - case (init_state_r) - INIT_CAL3_READ_WAIT, - INIT_CAL4_READ_WAIT: - cnt_rd_r <= cnt_rd_r + 1; - default: - cnt_rd_r <= 4'b0000; - endcase - end - - always @(posedge clkdiv0) begin - if(cnt_rd_r == CNTNEXT_RD) - cnt_rd_ok_r <= 1'b1; - else - cnt_rd_ok_r <= 1'b0; - end - - //*************************************************************************** - // Initial delay after power-on - //*************************************************************************** - - // register the refresh flag from the controller. - // The refresh flag is in full frequency domain - so a pulsed version must - // be generated for half freq domain using 2 consecutive full clk cycles - // The registered version is used for the 200us counter - always @(posedge clk0) - ctrl_ref_flag_r <= ctrl_ref_flag; - always @(posedge clkdiv0) - cke_200us_cnt_en_r <= ctrl_ref_flag || ctrl_ref_flag_r; - - // 200us counter for cke - always @(posedge clkdiv0) - if (rstdiv0) begin - // skip power-up count if only simulating - if (SIM_ONLY) - cke_200us_cnt_r <= 5'b00001; - else - cke_200us_cnt_r <= 5'd27; - end else if (cke_200us_cnt_en_r) - cke_200us_cnt_r <= cke_200us_cnt_r - 1; - - always @(posedge clkdiv0) - if (rstdiv0) - done_200us_r <= 1'b0; - else if (!done_200us_r) - done_200us_r <= (cke_200us_cnt_r == 5'b00000); - - // 200 clocks counter - count value : h'64 required for initialization - // Counts 100 divided by two clocks - always @(posedge clkdiv0) - if (rstdiv0 || (init_state_r == INIT_CNT_200)) - cnt_200_cycle_r <= 8'h64; - else if (init_state_r == INIT_ZQCL) // ddr3 - cnt_200_cycle_r <= 8'hC8; - else if (cnt_200_cycle_r != 8'h00) - cnt_200_cycle_r <= cnt_200_cycle_r - 1; - - always @(posedge clkdiv0) - if (rstdiv0 || (init_state_r == INIT_CNT_200) - || (init_state_r == INIT_ZQCL)) - cnt_200_cycle_done_r <= 1'b0; - else if (cnt_200_cycle_r == 8'h00) - cnt_200_cycle_done_r <= 1'b1; - - //***************************************************************** - // handle deep memory configuration: - // During initialization: Repeat initialization sequence once for each - // chip select. Note that we could perform initalization for all chip - // selects simulataneously. Probably fine - any potential SI issues with - // auto refreshing all chip selects at once? - // Once initialization complete, assert only CS[1] for calibration. - //***************************************************************** - - always @(posedge clkdiv0) - if (rstdiv0) begin - chip_cnt_r <= 2'b00; - end else if (init_state_r == INIT_DEEP_MEMORY_ST) begin - if (chip_cnt_r != CS_NUM) - chip_cnt_r <= chip_cnt_r + 1; - else - chip_cnt_r <= 2'b00; - // MIG 2.4: Modified to issue an Auto Refresh commmand - // to each chip select during various calibration stages - end else if (init_state_r == INIT_PRECHARGE && init_done_r) begin - chip_cnt_r <= 2'b00; - end else if (init_state_r1 == INIT_AUTO_REFRESH && init_done_r) begin - if (chip_cnt_r < (CS_NUM-1)) - chip_cnt_r <= chip_cnt_r + 1; - end - - // keep track of which chip selects got auto-refreshed (avoid auto-refreshing - // all CS's at once to avoid current spike) - always @(posedge clkdiv0)begin - if (rstdiv0 || init_state_r == INIT_PRECHARGE) - auto_cnt_r <= 'd0; - else if (init_state_r == INIT_AUTO_REFRESH && init_done_r) begin - if (auto_cnt_r < CS_NUM) - auto_cnt_r <= auto_cnt_r + 1; - end - end - - always @(posedge clkdiv0) - if (rstdiv0) begin - ddr_cs_n_r <= {CS_NUM{1'b1}}; - end else begin - ddr_cs_n_r <= {CS_NUM{1'b1}}; - if ((init_state_r == INIT_DUMMY_ACTIVE) || - ((init_state_r == INIT_PRECHARGE) && (~init_done_r))|| - (init_state_r == INIT_LOAD_MODE) || - (init_state_r == INIT_AUTO_REFRESH) || - (init_state_r == INIT_ZQCL ) || - (((init_state_r == INIT_CAL1_READ) || - (init_state_r == INIT_CAL2_READ) || - (init_state_r == INIT_CAL3_READ) || - (init_state_r == INIT_CAL4_READ) || - (init_state_r == INIT_CAL1_WRITE) || - (init_state_r == INIT_CAL2_WRITE) || - (init_state_r == INIT_CAL3_WRITE) || - (init_state_r == INIT_CAL4_WRITE)) && (burst_cnt_r == 2'b00))) - ddr_cs_n_r[chip_cnt_r] <= 1'b0; - else if (init_state_r == INIT_PRECHARGE) - ddr_cs_n_r <= {CS_NUM{1'b0}}; - else - ddr_cs_n_r[chip_cnt_r] <= 1'b1; - end - - //*************************************************************************** - // Write/read burst logic - //*************************************************************************** - - assign cal_write = ((init_state_r == INIT_CAL1_WRITE) || - (init_state_r == INIT_CAL2_WRITE) || - (init_state_r == INIT_CAL3_WRITE) || - (init_state_r == INIT_CAL4_WRITE)); - assign cal_read = ((init_state_r == INIT_CAL1_READ) || - (init_state_r == INIT_CAL2_READ) || - (init_state_r == INIT_CAL3_READ) || - (init_state_r == INIT_CAL4_READ)); - assign cal_write_read = ((init_state_r == INIT_CAL1_READ) || - (init_state_r == INIT_CAL2_READ) || - (init_state_r == INIT_CAL3_READ) || - (init_state_r == INIT_CAL4_READ) || - (init_state_r == INIT_CAL1_WRITE) || - (init_state_r == INIT_CAL2_WRITE) || - (init_state_r == INIT_CAL3_WRITE) || - (init_state_r == INIT_CAL4_WRITE)); - - assign burst_val = (BURST_LEN == 4) ? 2'b00 : - (BURST_LEN == 8) ? 2'b01 : 2'b00; - - // keep track of current address - need this if burst length < 8 for - // stage 2-4 calibration writes and reads. Make sure value always gets - // initialized to 0 before we enter write/read state. This is used to - // keep track of when another burst must be issued - always @(posedge clkdiv0) - if (cal_write_read) - burst_addr_r <= burst_addr_r + 2; - else - burst_addr_r <= 2'b00; - - // write/read burst count - always @(posedge clkdiv0) - if (cal_write_read) - if (burst_cnt_r == 2'b00) - burst_cnt_r <= burst_val; - else // SHOULD THIS BE -2 CHECK THIS LOGIC - burst_cnt_r <= burst_cnt_r - 1; - else - burst_cnt_r <= 2'b00; - - // indicate when a write is occurring - always @(posedge clkdiv0) - // MIG 2.1: Remove (burst_addr_r<4) term - not used - // phy_init_wren <= cal_write && (burst_addr_r < 3'd4); - phy_init_wren <= cal_write; - - // used for read enable calibration, pulse to indicate when read issued - always @(posedge clkdiv0) - // MIG 2.1: Remove (burst_addr_r<4) term - not used - // phy_init_rden <= cal_read && (burst_addr_r < 3'd4); - phy_init_rden <= cal_read; - - //*************************************************************************** - // Initialization state machine - //*************************************************************************** - - always @(posedge clkdiv0) - // every time we need to initialize another rank of memory, need to - // reset init count, and repeat the entire initialization (but not - // calibration) sequence - if (rstdiv0 || (init_state_r == INIT_DEEP_MEMORY_ST)) - init_cnt_r <= INIT_CNTR_INIT; - else if ((DDR_TYPE == DDR1) && (init_state_r == INIT_PRECHARGE) && - (init_cnt_r == INIT_CNTR_PRECH_1)) - // skip EMR(2) and EMR(3) register loads - init_cnt_r <= INIT_CNTR_EMR_EN_DLL; - else if ((DDR_TYPE == DDR1) && (init_state_r == INIT_LOAD_MODE) && - (init_cnt_r == INIT_CNTR_MR_ACT_DLL)) - // skip OCD calibration for DDR1 - init_cnt_r <= INIT_CNTR_DEEP_MEM; - else if ((DDR_TYPE == DDR3) && (init_state_r == INIT_ZQCL)) - // skip states for DDR3 - init_cnt_r <= INIT_CNTR_DEEP_MEM; - else if ((init_state_r == INIT_LOAD_MODE) || - ((init_state_r == INIT_PRECHARGE) && - (init_state_r1 != INIT_CALIB_REF)) || - ((init_state_r == INIT_AUTO_REFRESH) && (~init_done_r)) || - (init_state_r == INIT_CNT_200) || - // MIG 3.3: Added increment when starting calibration - ((init_state_r == INIT_DUMMY_ACTIVE) && - (init_state_r1 == INIT_IDLE))) - init_cnt_r <= init_cnt_r + 1; - - always @(posedge clkdiv0) begin - if ((init_state_r == INIT_IDLE) && (init_cnt_r == INIT_CNTR_DONE)) begin - phy_init_done_r <= 1'b1; - end else - phy_init_done_r <= 1'b0; - end - - // phy_init_done to the controller and the user interface. - // It is delayed by four clocks to account for the - // multi cycle path constraint to the (phy_init_data_sel) - // to the phy layer. - always @(posedge clkdiv0) begin - phy_init_done_r1 <= phy_init_done_r; - phy_init_done_r2 <= phy_init_done_r1; - phy_init_done_r3 <= phy_init_done_r2; - phy_init_done <= phy_init_done_r3; - end - - // Instantiate primitive to allow this flop to be attached to multicycle - // path constraint in UCF. This signal goes to PHY_WRITE and PHY_CTL_IO - // datapath logic only. Because it is a multi-cycle path, it can be - // clocked by either CLKDIV0 or CLK0. - FDRSE u_ff_phy_init_data_sel - ( - .Q (phy_init_data_sel), - .C (clkdiv0), - .CE (1'b1), - .D (phy_init_done_r1), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve=1 */ - /* synthesis syn_replicate = 0 */; - - //synthesis translate_off - always @(posedge calib_done[0]) - $display ("First Stage Calibration completed at time %t", $time); - - always @(posedge calib_done[1]) - $display ("Second Stage Calibration completed at time %t", $time); - - always @(posedge calib_done[2]) begin - $display ("Third Stage Calibration completed at time %t", $time); - end - - always @(posedge calib_done[3]) begin - $display ("Fourth Stage Calibration completed at time %t", $time); - $display ("Calibration completed at time %t", $time); - end - //synthesis translate_on - - always @(posedge clkdiv0) begin - if ((init_cnt_r >= INIT_CNTR_DEEP_MEM))begin - init_done_r <= 1'b1; - end else - init_done_r <= 1'b0; - end - - //***************************************************************** - - always @(posedge clkdiv0) - if (rstdiv0) begin - init_state_r <= INIT_IDLE; - init_state_r1 <= INIT_IDLE; - init_state_r2 <= INIT_IDLE; - calib_done_r <= 4'b0000; - end else begin - init_state_r <= init_next_state; - init_state_r1 <= init_state_r; - init_state_r2 <= init_state_r1; - calib_done_r <= calib_done; // register for timing - end - - always @(*) begin - init_next_state = init_state_r; - (* full_case, parallel_case *) case (init_state_r) - INIT_IDLE: begin - if (done_200us_r) begin - (* parallel_case *) case (init_cnt_r) - INIT_CNTR_INIT: - init_next_state = INIT_CNT_200; - INIT_CNTR_PRECH_1: - init_next_state = INIT_PRECHARGE; - INIT_CNTR_EMR2_INIT: - init_next_state = INIT_LOAD_MODE; // EMR(2) - INIT_CNTR_EMR3_INIT: - init_next_state = INIT_LOAD_MODE; // EMR(3); - INIT_CNTR_EMR_EN_DLL: - init_next_state = INIT_LOAD_MODE; // EMR, enable DLL - INIT_CNTR_MR_RST_DLL: - init_next_state = INIT_LOAD_MODE; // MR, reset DLL - INIT_CNTR_CNT_200_WAIT:begin - if(DDR_TYPE == DDR3) - init_next_state = INIT_ZQCL; // DDR3 - else - // Wait 200cc after reset DLL - init_next_state = INIT_CNT_200; - end - INIT_CNTR_PRECH_2: - init_next_state = INIT_PRECHARGE; - INIT_CNTR_AR_1: - init_next_state = INIT_AUTO_REFRESH; - INIT_CNTR_AR_2: - init_next_state = INIT_AUTO_REFRESH; - INIT_CNTR_MR_ACT_DLL: - init_next_state = INIT_LOAD_MODE; // MR, unreset DLL - INIT_CNTR_EMR_DEF_OCD: - init_next_state = INIT_LOAD_MODE; // EMR, OCD default - INIT_CNTR_EMR_EXIT_OCD: - init_next_state = INIT_LOAD_MODE; // EMR, enable OCD exit - INIT_CNTR_DEEP_MEM: begin - if ((chip_cnt_r < CS_NUM-1)) - init_next_state = INIT_DEEP_MEMORY_ST; - else if (cnt_200_cycle_done_r) - init_next_state = INIT_DUMMY_ACTIVE; - else - init_next_state = INIT_IDLE; - end - // MIG 3.3: Remove extra precharge occurring at end of calibration -// INIT_CNTR_PRECH_3: -// init_next_state = INIT_PRECHARGE; - INIT_CNTR_DONE: - init_next_state = INIT_IDLE; - default : - init_next_state = INIT_IDLE; - endcase - end - end - INIT_CNT_200: - init_next_state = INIT_CNT_200_WAIT; - INIT_CNT_200_WAIT: - if (cnt_200_cycle_done_r) - init_next_state = INIT_IDLE; - INIT_PRECHARGE: - init_next_state = INIT_PRECHARGE_WAIT; - INIT_PRECHARGE_WAIT: - if (cnt_cmd_ok_r)begin - if (init_done_r && (!(&calib_done_r))) - init_next_state = INIT_AUTO_REFRESH; - else - init_next_state = INIT_IDLE; - end - INIT_ZQCL: - init_next_state = INIT_WAIT_DLLK_ZQINIT; - INIT_WAIT_DLLK_ZQINIT: - if (cnt_200_cycle_done_r) - init_next_state = INIT_IDLE; - INIT_LOAD_MODE: - init_next_state = INIT_MODE_REGISTER_WAIT; - INIT_MODE_REGISTER_WAIT: - if (cnt_cmd_ok_r) - init_next_state = INIT_IDLE; - INIT_AUTO_REFRESH: - init_next_state = INIT_AUTO_REFRESH_WAIT; - INIT_AUTO_REFRESH_WAIT: - // MIG 2.4: Modified to issue an Auto Refresh commmand - // to each chip select during various calibration stages - if (auto_cnt_r < CS_NUM && init_done_r) begin - if (cnt_cmd_ok_r) - init_next_state = INIT_AUTO_REFRESH; - end else if (cnt_cmd_ok_r)begin - if (init_done_r) - init_next_state = INIT_DUMMY_ACTIVE; - else - init_next_state = INIT_IDLE; - end - INIT_DEEP_MEMORY_ST: - init_next_state = INIT_IDLE; - // single row activate. All subsequent calibration writes and - // read will take place in this row - INIT_DUMMY_ACTIVE: - init_next_state = INIT_DUMMY_ACTIVE_WAIT; - INIT_DUMMY_ACTIVE_WAIT: - if (cnt_cmd_ok_r)begin - if (~calib_done_r[0]) begin - // if returning to stg1 after refresh, don't need to write - if (cal1_started_r) - init_next_state = INIT_CAL1_READ; - // if first entering stg1, need to write training pattern - else - init_next_state = INIT_CAL1_WRITE; - end else if (~calib_done[1]) begin - if (cal2_started_r) - init_next_state = INIT_CAL2_READ; - else - init_next_state = INIT_CAL2_WRITE; - end else if (~calib_done_r[2]) - // Stage 3 only requires a refresh after the entire stage is - // finished - init_next_state = INIT_CAL3_WRITE; - else begin - // Stage 4 requires a refresh after every DQS group - if (cal4_started_r) - init_next_state = INIT_CAL4_READ; - else - init_next_state = INIT_CAL4_WRITE; - end - end - // Stage 1 calibration (write and continuous read) - INIT_CAL1_WRITE: - if (burst_addr_r == 2'b10) - init_next_state = INIT_CAL1_WRITE_READ; - INIT_CAL1_WRITE_READ: - if (cnt_cmd_ok_r) - init_next_state = INIT_CAL1_READ; - INIT_CAL1_READ: - // Stage 1 requires inter-stage auto-refresh - if (calib_done_r[0] || refresh_req) - init_next_state = INIT_CAL1_READ_WAIT; - INIT_CAL1_READ_WAIT: - if (cnt_cmd_ok_r) - init_next_state = INIT_CALIB_REF; - // Stage 2 calibration (write and continuous read) - INIT_CAL2_WRITE: - if (burst_addr_r == 2'b10) - init_next_state = INIT_CAL2_WRITE_READ; - INIT_CAL2_WRITE_READ: - if (cnt_cmd_ok_r) - init_next_state = INIT_CAL2_READ; - INIT_CAL2_READ: - // Stage 2 requires inter-stage auto-refresh - if (calib_done_r[1] || refresh_req) - init_next_state = INIT_CAL2_READ_WAIT; - INIT_CAL2_READ_WAIT: - if (cnt_cmd_ok_r) - init_next_state = INIT_CALIB_REF; - // Stage 3 calibration (write and continuous read) - INIT_CAL3_WRITE: - if (burst_addr_r == 2'b10) - init_next_state = INIT_CAL3_WRITE_READ; - INIT_CAL3_WRITE_READ: - if (cnt_cmd_ok_r) - init_next_state = INIT_CAL3_READ; - INIT_CAL3_READ: - if (burst_addr_r == 2'b10) - init_next_state = INIT_CAL3_READ_WAIT; - INIT_CAL3_READ_WAIT: begin - if (cnt_rd_ok_r) - if (calib_done_r[2]) begin - init_next_state = INIT_CALIB_REF; - end else - init_next_state = INIT_CAL3_READ; - end - // Stage 4 calibration - INIT_CAL4_WRITE: - if (burst_addr_r == 2'b10) - init_next_state = INIT_CAL4_WRITE_READ; - INIT_CAL4_WRITE_READ: - if (cnt_cmd_ok_r) - init_next_state = INIT_CAL4_READ; - INIT_CAL4_READ: - if (burst_addr_r == 2'b10) - init_next_state = INIT_CAL4_READ_WAIT; - INIT_CAL4_READ_WAIT: begin - if (cnt_rd_ok_r) - // Stage 4 requires inter-stage auto-refresh - if (calib_done_r[3] || refresh_req) - // MIG 3.3: With removal of extra precharge, proceed to - // state CALIB_REF first to avoid incrementing init_cntr -// init_next_state = INIT_PRECHARGE; - init_next_state = INIT_CALIB_REF; - else - init_next_state = INIT_CAL4_READ; - end - INIT_CALIB_REF: - init_next_state = INIT_PRECHARGE; - endcase - end - - //*************************************************************************** - // Memory control/address - //*************************************************************************** - - always @(posedge clkdiv0) - if ((init_state_r == INIT_DUMMY_ACTIVE) || - (init_state_r == INIT_PRECHARGE) || - (init_state_r == INIT_LOAD_MODE) || - (init_state_r == INIT_AUTO_REFRESH)) begin - ddr_ras_n_r <= 1'b0; - end else begin - ddr_ras_n_r <= 1'b1; - end - - always @(posedge clkdiv0) - if ((init_state_r == INIT_LOAD_MODE) || - (init_state_r == INIT_AUTO_REFRESH) || - (cal_write_read && (burst_cnt_r == 2'b00))) begin - ddr_cas_n_r <= 1'b0; - end else begin - ddr_cas_n_r <= 1'b1; - end - - always @(posedge clkdiv0) - if ((init_state_r == INIT_LOAD_MODE) || - (init_state_r == INIT_PRECHARGE) || - (init_state_r == INIT_ZQCL) || - (cal_write && (burst_cnt_r == 2'b00)))begin - ddr_we_n_r <= 1'b0; - end else begin - ddr_we_n_r <= 1'b1; - end - - //***************************************************************** - // memory address during init - //***************************************************************** - - always @(posedge clkdiv0) begin - if ((init_state_r == INIT_PRECHARGE) - || (init_state_r == INIT_ZQCL))begin - // Precharge all - set A10 = 1 - ddr_addr_r <= {ROW_WIDTH{1'b0}}; - ddr_addr_r[10] <= 1'b1; - ddr_ba_r <= {BANK_WIDTH{1'b0}}; - end else if (init_state_r == INIT_LOAD_MODE) begin - ddr_ba_r <= {BANK_WIDTH{1'b0}}; - ddr_addr_r <= {ROW_WIDTH{1'b0}}; - case (init_cnt_r) - // EMR (2) - INIT_CNTR_EMR2_INIT: begin - ddr_ba_r[1:0] <= 2'b10; - ddr_addr_r <= {ROW_WIDTH{1'b0}}; - end - // EMR (3) - INIT_CNTR_EMR3_INIT: begin - ddr_ba_r[1:0] <= 2'b11; - if(DDR_TYPE == DDR3) - ddr_addr_r <= load_mode_reg3[ROW_WIDTH-1:0]; - else - ddr_addr_r <= {ROW_WIDTH{1'b0}}; - end - // EMR write - A0 = 0 for DLL enable - INIT_CNTR_EMR_EN_DLL: begin - ddr_ba_r[1:0] <= 2'b01; - if(DDR_TYPE == DDR3) - ddr_addr_r <= load_mode_reg1[ROW_WIDTH-1:0]; - else - ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; - end - // MR write, reset DLL (A8=1) - INIT_CNTR_MR_RST_DLL: begin - if(DDR_TYPE == DDR3) - ddr_addr_r <= load_mode_reg0[ROW_WIDTH-1:0]; - else - ddr_addr_r <= load_mode_reg[ROW_WIDTH-1:0]; - ddr_ba_r[1:0] <= 2'b00; - ddr_addr_r[8] <= 1'b1; - end - // MR write, unreset DLL (A8=0) - INIT_CNTR_MR_ACT_DLL: begin - ddr_ba_r[1:0] <= 2'b00; - ddr_addr_r <= load_mode_reg[ROW_WIDTH-1:0]; - end - // EMR write, OCD default state - INIT_CNTR_EMR_DEF_OCD: begin - ddr_ba_r[1:0] <= 2'b01; - ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; - ddr_addr_r[9:7] <= 3'b111; - end - // EMR write - OCD exit - INIT_CNTR_EMR_EXIT_OCD: begin - ddr_ba_r[1:0] <= 2'b01; - ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; - end - default: begin - ddr_ba_r <= {BANK_WIDTH{1'bx}}; - ddr_addr_r <= {ROW_WIDTH{1'bx}}; - end - endcase - end else if (cal_write_read) begin - // when writing or reading for Stages 2-4, since training pattern is - // either 4 (stage 2) or 8 (stage 3-4) long, if BURST LEN < 8, then - // need to issue multiple bursts to read entire training pattern - ddr_addr_r[ROW_WIDTH-1:3] <= {ROW_WIDTH-4{1'b0}}; - ddr_addr_r[2:0] <= {burst_addr_r, 1'b0}; - ddr_ba_r <= {BANK_WIDTH-1{1'b0}}; - end else if (init_state_r == INIT_DUMMY_ACTIVE) begin - // all calibration writing read takes place in row 0x0 only - ddr_ba_r <= {BANK_WIDTH{1'b0}}; - ddr_addr_r <= {ROW_WIDTH{1'b0}}; - end else begin - // otherwise, cry me a river - ddr_ba_r <= {BANK_WIDTH{1'bx}}; - ddr_addr_r <= {ROW_WIDTH{1'bx}}; - end - end - - // Keep CKE asserted after initial power-on delay - always @(posedge clkdiv0) - ddr_cke_r <= {CKE_WIDTH{done_200us_r}}; - - // register commands to memory. Two clock cycle delay from state -> output - always @(posedge clk0) begin - ddr_addr_r1 <= ddr_addr_r; - ddr_ba_r1 <= ddr_ba_r; - ddr_cas_n_r1 <= ddr_cas_n_r; - ddr_ras_n_r1 <= ddr_ras_n_r; - ddr_we_n_r1 <= ddr_we_n_r; - ddr_cs_n_r1 <= ddr_cs_n_r; - end // always @ (posedge clk0) - - always @(posedge clk0) - init_state_r1_2t <= init_state_r1; - - // logic to toggle chip select. The chip_select is - // clocked of clkdiv0 and will be asserted for - // two clock cycles. - always @(posedge clk0) begin - if(rst0) - ddr_cs_disable_r <= {CS_NUM{1'b0}}; - else begin - if(| ddr_cs_disable_r) - ddr_cs_disable_r <= {CS_NUM{1'b0}}; - else begin - if (TWO_T_TIME_EN) begin - if (init_state_r1_2t == INIT_PRECHARGE && init_done_r) - ddr_cs_disable_r <= 'd3; - else - ddr_cs_disable_r[chip_cnt_r] <= ~ddr_cs_n_r1[chip_cnt_r]; - end - else begin - if (init_state_r1 == INIT_PRECHARGE && init_done_r) - ddr_cs_disable_r <= 'd3; - else - ddr_cs_disable_r[chip_cnt_r] <= ~ddr_cs_n_r[chip_cnt_r]; - end - end - end - end - - - assign phy_init_addr = ddr_addr_r; - assign phy_init_ba = ddr_ba_r; - assign phy_init_cas_n = ddr_cas_n_r; - assign phy_init_cke = ddr_cke_r; - assign phy_init_ras_n = ddr_ras_n_r; - assign phy_init_we_n = ddr_we_n_r; - assign phy_init_cs_n = (TWO_T_TIME_EN) ? - ddr_cs_n_r1 | ddr_cs_disable_r - : ddr_cs_n_r| ddr_cs_disable_r; - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_io.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_io.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_io.v (nonexistent) @@ -1,353 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_io.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module instantiates calibration logic, data, data strobe and the -// data mask iobs. -//Reference: -//Revision History: -// Rev 1.1 - DM_IOB instance made based on USE_DM_PORT value . PK. 25/6/08 -// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 -// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_phy_io # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter CLK_WIDTH = 1, - parameter USE_DM_PORT = 1, - parameter DM_WIDTH = 9, - parameter DQ_WIDTH = 72, - parameter DQ_BITS = 7, - parameter DQ_PER_DQS = 8, - parameter DQS_BITS = 4, - parameter DQS_WIDTH = 9, - parameter HIGH_PERFORMANCE_MODE = "TRUE", - parameter IODELAY_GRP = "IODELAY_MIG", - parameter ODT_WIDTH = 1, - parameter ADDITIVE_LAT = 0, - parameter CAS_LAT = 5, - parameter REG_ENABLE = 1, - parameter CLK_PERIOD = 3000, - parameter DDR_TYPE = 1, - parameter SIM_ONLY = 0, - parameter DEBUG_EN = 0, - parameter FPGA_SPEED_GRADE = 2 - ) - ( - input clk0, - input clk90, - input clkdiv0, - input rst0, - input rst90, - input rstdiv0, - input dm_ce, - input [1:0] dq_oe_n, - input dqs_oe_n, - input dqs_rst_n, - input [3:0] calib_start, - input ctrl_rden, - input phy_init_rden, - input calib_ref_done, - output [3:0] calib_done, - output calib_ref_req, - output [DQS_WIDTH-1:0] calib_rden, - output [DQS_WIDTH-1:0] calib_rden_sel, - input [DQ_WIDTH-1:0] wr_data_rise, - input [DQ_WIDTH-1:0] wr_data_fall, - input [(DQ_WIDTH/8)-1:0] mask_data_rise, - input [(DQ_WIDTH/8)-1:0] mask_data_fall, - output [(DQ_WIDTH)-1:0] rd_data_rise, - output [(DQ_WIDTH)-1:0] rd_data_fall, - output [CLK_WIDTH-1:0] ddr_ck, - output [CLK_WIDTH-1:0] ddr_ck_n, - output [DM_WIDTH-1:0] ddr_dm, - inout [DQS_WIDTH-1:0] ddr_dqs, - inout [DQS_WIDTH-1:0] ddr_dqs_n, - inout [DQ_WIDTH-1:0] ddr_dq, - // Debug signals (optional use) - input dbg_idel_up_all, - input dbg_idel_down_all, - input dbg_idel_up_dq, - input dbg_idel_down_dq, - input dbg_idel_up_dqs, - input dbg_idel_down_dqs, - input dbg_idel_up_gate, - input dbg_idel_down_gate, - input [DQ_BITS-1:0] dbg_sel_idel_dq, - input dbg_sel_all_idel_dq, - input [DQS_BITS:0] dbg_sel_idel_dqs, - input dbg_sel_all_idel_dqs, - input [DQS_BITS:0] dbg_sel_idel_gate, - input dbg_sel_all_idel_gate, - output [3:0] dbg_calib_done, - output [3:0] dbg_calib_err, - output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, - output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, - output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, - output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly - ); - - // ratio of # of physical DM outputs to bytes in data bus - // may be different - e.g. if using x4 components - localparam DM_TO_BYTE_RATIO = DM_WIDTH / (DQ_WIDTH/8); - - wire [CLK_WIDTH-1:0] ddr_ck_q; - wire [DQS_WIDTH-1:0] delayed_dqs; - wire [DQ_WIDTH-1:0] dlyce_dq; - wire [DQS_WIDTH-1:0] dlyce_dqs; - wire [DQS_WIDTH-1:0] dlyce_gate; - wire [DQ_WIDTH-1:0] dlyinc_dq; - wire [DQS_WIDTH-1:0] dlyinc_dqs; - wire [DQS_WIDTH-1:0] dlyinc_gate; - wire dlyrst_dq; - wire dlyrst_dqs; - wire [DQS_WIDTH-1:0] dlyrst_gate; - wire [DQS_WIDTH-1:0] dq_ce; - (* KEEP = "TRUE" *) wire [DQS_WIDTH-1:0] en_dqs /* synthesis syn_keep = 1 */; - wire [DQS_WIDTH-1:0] rd_data_sel; - - //*************************************************************************** - - ddr2_phy_calib # - ( - .DQ_WIDTH (DQ_WIDTH), - .DQ_BITS (DQ_BITS), - .DQ_PER_DQS (DQ_PER_DQS), - .DQS_BITS (DQS_BITS), - .DQS_WIDTH (DQS_WIDTH), - .ADDITIVE_LAT (ADDITIVE_LAT), - .CAS_LAT (CAS_LAT), - .REG_ENABLE (REG_ENABLE), - .CLK_PERIOD (CLK_PERIOD), - .SIM_ONLY (SIM_ONLY), - .DEBUG_EN (DEBUG_EN) - ) - u_phy_calib - ( - .clk (clk0), - .clkdiv (clkdiv0), - .rstdiv (rstdiv0), - .calib_start (calib_start), - .ctrl_rden (ctrl_rden), - .phy_init_rden (phy_init_rden), - .rd_data_rise (rd_data_rise), - .rd_data_fall (rd_data_fall), - .calib_ref_done (calib_ref_done), - .calib_done (calib_done), - .calib_ref_req (calib_ref_req), - .calib_rden (calib_rden), - .calib_rden_sel (calib_rden_sel), - .dlyrst_dq (dlyrst_dq), - .dlyce_dq (dlyce_dq), - .dlyinc_dq (dlyinc_dq), - .dlyrst_dqs (dlyrst_dqs), - .dlyce_dqs (dlyce_dqs), - .dlyinc_dqs (dlyinc_dqs), - .dlyrst_gate (dlyrst_gate), - .dlyce_gate (dlyce_gate), - .dlyinc_gate (dlyinc_gate), - .en_dqs (en_dqs), - .rd_data_sel (rd_data_sel), - .dbg_idel_up_all (dbg_idel_up_all), - .dbg_idel_down_all (dbg_idel_down_all), - .dbg_idel_up_dq (dbg_idel_up_dq), - .dbg_idel_down_dq (dbg_idel_down_dq), - .dbg_idel_up_dqs (dbg_idel_up_dqs), - .dbg_idel_down_dqs (dbg_idel_down_dqs), - .dbg_idel_up_gate (dbg_idel_up_gate), - .dbg_idel_down_gate (dbg_idel_down_gate), - .dbg_sel_idel_dq (dbg_sel_idel_dq), - .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), - .dbg_sel_idel_dqs (dbg_sel_idel_dqs), - .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), - .dbg_sel_idel_gate (dbg_sel_idel_gate), - .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), - .dbg_calib_done (dbg_calib_done), - .dbg_calib_err (dbg_calib_err), - .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), - .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), - .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), - .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), - .dbg_calib_rden_dly (dbg_calib_rden_dly), - .dbg_calib_gate_dly (dbg_calib_gate_dly) - ); - - //*************************************************************************** - // Memory clock generation - //*************************************************************************** - - genvar ck_i; - generate - for(ck_i = 0; ck_i < CLK_WIDTH; ck_i = ck_i+1) begin: gen_ck - ODDR # - ( - .SRTYPE ("SYNC"), - .DDR_CLK_EDGE ("OPPOSITE_EDGE") - ) - u_oddr_ck_i - ( - .Q (ddr_ck_q[ck_i]), - .C (clk0), - .CE (1'b1), - .D1 (1'b0), - .D2 (1'b1), - .R (1'b0), - .S (1'b0) - ); - // Can insert ODELAY here if required - OBUFDS u_obuf_ck_i - ( - .I (ddr_ck_q[ck_i]), - .O (ddr_ck[ck_i]), - .OB (ddr_ck_n[ck_i]) - ); - end - endgenerate - - //*************************************************************************** - // DQS instances - //*************************************************************************** - - genvar dqs_i; - generate - for(dqs_i = 0; dqs_i < DQS_WIDTH; dqs_i = dqs_i+1) begin: gen_dqs - ddr2_phy_dqs_iob # - ( - .DDR_TYPE (DDR_TYPE), - .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), - .IODELAY_GRP (IODELAY_GRP) - ) - u_iob_dqs - ( - .clk0 (clk0), - .clkdiv0 (clkdiv0), - .rst0 (rst0), - .dlyinc_dqs (dlyinc_dqs[dqs_i]), - .dlyce_dqs (dlyce_dqs[dqs_i]), - .dlyrst_dqs (dlyrst_dqs), - .dlyinc_gate (dlyinc_gate[dqs_i]), - .dlyce_gate (dlyce_gate[dqs_i]), - .dlyrst_gate (dlyrst_gate[dqs_i]), - .dqs_oe_n (dqs_oe_n), - .dqs_rst_n (dqs_rst_n), - .en_dqs (en_dqs[dqs_i]), - .ddr_dqs (ddr_dqs[dqs_i]), - .ddr_dqs_n (ddr_dqs_n[dqs_i]), - .dq_ce (dq_ce[dqs_i]), - .delayed_dqs (delayed_dqs[dqs_i]) - ); - end - endgenerate - - //*************************************************************************** - // DM instances - //*************************************************************************** - - genvar dm_i; - generate - if (USE_DM_PORT) begin: gen_dm_inst - for(dm_i = 0; dm_i < DM_WIDTH; dm_i = dm_i+1) begin: gen_dm - ddr2_phy_dm_iob u_iob_dm - ( - .clk90 (clk90), - .dm_ce (dm_ce), - .mask_data_rise (mask_data_rise[dm_i/DM_TO_BYTE_RATIO]), - .mask_data_fall (mask_data_fall[dm_i/DM_TO_BYTE_RATIO]), - .ddr_dm (ddr_dm[dm_i]) - ); - end - end - endgenerate - - //*************************************************************************** - // DQ IOB instances - //*************************************************************************** - - genvar dq_i; - generate - for(dq_i = 0; dq_i < DQ_WIDTH; dq_i = dq_i+1) begin: gen_dq - ddr2_phy_dq_iob # - ( - .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), - .IODELAY_GRP (IODELAY_GRP), - .FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) - ) - u_iob_dq - ( - .clk0 (clk0), - .clk90 (clk90), - .clkdiv0 (clkdiv0), - .rst90 (rst90), - .dlyinc (dlyinc_dq[dq_i]), - .dlyce (dlyce_dq[dq_i]), - .dlyrst (dlyrst_dq), - .dq_oe_n (dq_oe_n), - .dqs (delayed_dqs[dq_i/DQ_PER_DQS]), - .ce (dq_ce[dq_i/DQ_PER_DQS]), - .rd_data_sel (rd_data_sel[dq_i/DQ_PER_DQS]), - .wr_data_rise (wr_data_rise[dq_i]), - .wr_data_fall (wr_data_fall[dq_i]), - .rd_data_rise (rd_data_rise[dq_i]), - .rd_data_fall (rd_data_fall[dq_i]), - .ddr_dq (ddr_dq[dq_i]) - ); - end - endgenerate - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/MEMCtrl.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/MEMCtrl.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/MEMCtrl.v (nonexistent) @@ -1,605 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: MEMCtrl.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// Top-level module. Simple model for what the user might use -// Typically, the user will only instantiate MEM_INTERFACE_TOP in their -// code, and generate all backend logic (test bench) and all the other infrastructure logic -// separately. -// In addition to the memory controller, the module instantiates: -// 1. Reset logic based on user clocks -// 2. IDELAY control block -//Reference: -//Revision History: -// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 -// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 -// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 -//***************************************************************************** - -`timescale 1ns/1ps - -(* X_CORE_INFO = "mig_v3_61_ddr2_v5, Coregen 12.4" , CORE_GENERATION_INFO = "ddr2_v5,mig_v3_61,{component_name=MEMCtrl, BANK_WIDTH=2, CKE_WIDTH=1, CLK_WIDTH=2, COL_WIDTH=10, CS_NUM=1, CS_WIDTH=1, DM_WIDTH=8, DQ_WIDTH=64, DQ_PER_DQS=8, DQS_WIDTH=8, ODT_WIDTH=1, ROW_WIDTH=13, ADDITIVE_LAT=0, BURST_LEN=4, BURST_TYPE=0, CAS_LAT=3, ECC_ENABLE=0, MULTI_BANK_EN=1, TWO_T_TIME_EN=1, ODT_TYPE=1, REDUCE_DRV=0, REG_ENABLE=0, TREFI_NS=7800, TRAS=40000, TRCD=15000, TRFC=105000, TRP=15000, TRTP=7500, TWR=15000, TWTR=7500, CLK_PERIOD=8000, RST_ACT_LOW=1, INTERFACE_TYPE=DDR2_SDRAM, LANGUAGE=Verilog, SYNTHESIS_TOOL=ISE, NO_OF_CONTROLLERS=1}" *) -module MEMCtrl # - ( - parameter BANK_WIDTH = 2, - // # of memory bank addr bits. - parameter CKE_WIDTH = 1, - // # of memory clock enable outputs. - parameter CLK_WIDTH = 2, - // # of clock outputs. - parameter COL_WIDTH = 10, - // # of memory column bits. - parameter CS_NUM = 1, - // # of separate memory chip selects. - parameter CS_WIDTH = 1, - // # of total memory chip selects. - parameter CS_BITS = 0, - // set to log2(CS_NUM) (rounded up). - parameter DM_WIDTH = 8, - // # of data mask bits. - parameter DQ_WIDTH = 64, - // # of data width. - parameter DQ_PER_DQS = 8, - // # of DQ data bits per strobe. - parameter DQS_WIDTH = 8, - // # of DQS strobes. - parameter DQ_BITS = 6, - // set to log2(DQS_WIDTH*DQ_PER_DQS). - parameter DQS_BITS = 3, - // set to log2(DQS_WIDTH). - parameter ODT_WIDTH = 1, - // # of memory on-die term enables. - parameter ROW_WIDTH = 13, - // # of memory row and # of addr bits. - parameter ADDITIVE_LAT = 0, - // additive write latency. - parameter BURST_LEN = 4, - // burst length (in double words). - parameter BURST_TYPE = 0, - // burst type (=0 seq; =1 interleaved). - parameter CAS_LAT = 3, - // CAS latency. - parameter ECC_ENABLE = 0, - // enable ECC (=1 enable). - parameter APPDATA_WIDTH = 128, - // # of usr read/write data bus bits. - parameter MULTI_BANK_EN = 1, - // Keeps multiple banks open. (= 1 enable). - parameter TWO_T_TIME_EN = 1, - // 2t timing for unbuffered dimms. - parameter ODT_TYPE = 1, - // ODT (=0(none),=1(75),=2(150),=3(50)). - parameter REDUCE_DRV = 0, - // reduced strength mem I/O (=1 yes). - parameter REG_ENABLE = 0, - // registered addr/ctrl (=1 yes). - parameter TREFI_NS = 7800, - // auto refresh interval (ns). - parameter TRAS = 40000, - // active->precharge delay. - parameter TRCD = 15000, - // active->read/write delay. - parameter TRFC = 105000, - // refresh->refresh, refresh->active delay. - parameter TRP = 15000, - // precharge->command delay. - parameter TRTP = 7500, - // read->precharge delay. - parameter TWR = 15000, - // used to determine write->precharge. - parameter TWTR = 7500, - // write->read delay. - parameter HIGH_PERFORMANCE_MODE = "TRUE", - // # = TRUE, the IODELAY performance mode is set - // to high. - // # = FALSE, the IODELAY performance mode is set - // to low. - parameter SIM_ONLY = 0, - // = 1 to skip SDRAM power up delay. - parameter DEBUG_EN = 0, - // Enable debug signals/controls. - // When this parameter is changed from 0 to 1, - // make sure to uncomment the coregen commands - // in ise_flow.bat or create_ise.bat files in - // par folder. - parameter CLK_PERIOD = 8000, - // Core/Memory clock period (in ps). - parameter RST_ACT_LOW = 1 - // =1 for active low reset, =0 for active high. - ) - ( - inout [DQ_WIDTH-1:0] ddr2_dq, - output [ROW_WIDTH-1:0] ddr2_a, - output [BANK_WIDTH-1:0] ddr2_ba, - output ddr2_ras_n, - output ddr2_cas_n, - output ddr2_we_n, - output [CS_WIDTH-1:0] ddr2_cs_n, - output [ODT_WIDTH-1:0] ddr2_odt, - output [CKE_WIDTH-1:0] ddr2_cke, - output [DM_WIDTH-1:0] ddr2_dm, - input sys_rst_n, - output phy_init_done, - input locked, - output rst0_tb, - input clk0, - output clk0_tb, - input clk90, - input clkdiv0, - input clk200, - output app_wdf_afull, - output app_af_afull, - output rd_data_valid, - input app_wdf_wren, - input app_af_wren, - input [30:0] app_af_addr, - input [2:0] app_af_cmd, - output [(APPDATA_WIDTH)-1:0] rd_data_fifo_out, - input [(APPDATA_WIDTH)-1:0] app_wdf_data, - input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, - inout [DQS_WIDTH-1:0] ddr2_dqs, - inout [DQS_WIDTH-1:0] ddr2_dqs_n, - output [CLK_WIDTH-1:0] ddr2_ck, - output [CLK_WIDTH-1:0] ddr2_ck_n//, - //ADAUGAT PT LEDURI - //output error_o, error_cmp_o - ); - - //*************************************************************************** - // IODELAY Group Name: Replication and placement of IDELAYCTRLs will be - // handled automatically by software tools if IDELAYCTRLs have same refclk, - // reset and rdy nets. Designs with a unique RESET will commonly create a - // unique RDY. Constraint IODELAY_GROUP is associated to a set of IODELAYs - // with an IDELAYCTRL. The parameter IODELAY_GRP value can be any string. - //*************************************************************************** - - localparam IODELAY_GRP = "IODELAY_MIG"; - - - - - - wire rst0; - wire rst90; - wire rstdiv0; - wire rst200; - wire idelay_ctrl_rdy; - - wire error; - wire error_cmp; - wire [35:0] control; - wire [71:0] data; - wire [7:0] trig0; - - //Debug signals - - - wire [3:0] dbg_calib_done; - wire [3:0] dbg_calib_err; - wire [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt; - wire [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt; - wire [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt; - wire [DQS_WIDTH-1:0] dbg_calib_rd_data_sel; - wire [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly; - wire [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly; - wire dbg_idel_up_all; - wire dbg_idel_down_all; - wire dbg_idel_up_dq; - wire dbg_idel_down_dq; - wire dbg_idel_up_dqs; - wire dbg_idel_down_dqs; - wire dbg_idel_up_gate; - wire dbg_idel_down_gate; - wire [DQ_BITS-1:0] dbg_sel_idel_dq; - wire dbg_sel_all_idel_dq; - wire [DQS_BITS:0] dbg_sel_idel_dqs; - wire dbg_sel_all_idel_dqs; - wire [DQS_BITS:0] dbg_sel_idel_gate; - wire dbg_sel_all_idel_gate; - - - // Debug signals (optional use) - - //*********************************** - // PHY Debug Port demo - //*********************************** - wire [35:0] cs_control0; - wire [35:0] cs_control1; - wire [35:0] cs_control2; - wire [35:0] cs_control3; - wire [191:0] vio0_in; - wire [95:0] vio1_in; - wire [99:0] vio2_in; - wire [31:0] vio3_out; - - - - - //*************************************************************************** - - assign rst0_tb = rst0; - assign clk0_tb = clk0; - - -ddr2_idelay_ctrl # - ( - .IODELAY_GRP (IODELAY_GRP) - ) - u_ddr2_idelay_ctrl - ( - .rst200 (rst200), - .clk200 (clk200), - .idelay_ctrl_rdy (idelay_ctrl_rdy) - ); - - ddr2_infrastructure # - ( - .RST_ACT_LOW (RST_ACT_LOW) - ) -u_ddr2_infrastructure - ( - .sys_rst_n (sys_rst_n), - .locked (locked), - .rst0 (rst0), - .rst90 (rst90), - .rstdiv0 (rstdiv0), - .rst200 (rst200), - .clk0 (clk0), - .clk90 (clk90), - .clkdiv0 (clkdiv0), - .clk200 (clk200), - .idelay_ctrl_rdy (idelay_ctrl_rdy) - ); - - ddr2_top # - ( - .BANK_WIDTH (BANK_WIDTH), - .CKE_WIDTH (CKE_WIDTH), - .CLK_WIDTH (CLK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_NUM (CS_NUM), - .CS_WIDTH (CS_WIDTH), - .CS_BITS (CS_BITS), - .DM_WIDTH (DM_WIDTH), - .DQ_WIDTH (DQ_WIDTH), - .DQ_PER_DQS (DQ_PER_DQS), - .DQS_WIDTH (DQS_WIDTH), - .DQ_BITS (DQ_BITS), - .DQS_BITS (DQS_BITS), - .ODT_WIDTH (ODT_WIDTH), - .ROW_WIDTH (ROW_WIDTH), - .ADDITIVE_LAT (ADDITIVE_LAT), - .BURST_LEN (BURST_LEN), - .BURST_TYPE (BURST_TYPE), - .CAS_LAT (CAS_LAT), - .ECC_ENABLE (ECC_ENABLE), - .APPDATA_WIDTH (APPDATA_WIDTH), - .MULTI_BANK_EN (MULTI_BANK_EN), - .TWO_T_TIME_EN (TWO_T_TIME_EN), - .ODT_TYPE (ODT_TYPE), - .REDUCE_DRV (REDUCE_DRV), - .REG_ENABLE (REG_ENABLE), - .TREFI_NS (TREFI_NS), - .TRAS (TRAS), - .TRCD (TRCD), - .TRFC (TRFC), - .TRP (TRP), - .TRTP (TRTP), - .TWR (TWR), - .TWTR (TWTR), - .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), - .IODELAY_GRP (IODELAY_GRP), - .SIM_ONLY (SIM_ONLY), - .DEBUG_EN (DEBUG_EN), - .FPGA_SPEED_GRADE (3), - .USE_DM_PORT (1), - .CLK_PERIOD (CLK_PERIOD) - ) -u_ddr2_top_0 -( - .ddr2_dq (ddr2_dq), - .ddr2_a (ddr2_a), - .ddr2_ba (ddr2_ba), - .ddr2_ras_n (ddr2_ras_n), - .ddr2_cas_n (ddr2_cas_n), - .ddr2_we_n (ddr2_we_n), - .ddr2_cs_n (ddr2_cs_n), - .ddr2_odt (ddr2_odt), - .ddr2_cke (ddr2_cke), - .ddr2_dm (ddr2_dm), - .phy_init_done (phy_init_done), - .rst0 (rst0), - .rst90 (rst90), - .rstdiv0 (rstdiv0), - .clk0 (clk0), - .clk90 (clk90), - .clkdiv0 (clkdiv0), - .app_wdf_afull (app_wdf_afull), - .app_af_afull (app_af_afull), - .rd_data_valid (rd_data_valid), - .app_wdf_wren (app_wdf_wren), - .app_af_wren (app_af_wren), - .app_af_addr (app_af_addr), - .app_af_cmd (app_af_cmd), - .rd_data_fifo_out (rd_data_fifo_out), - .app_wdf_data (app_wdf_data), - .app_wdf_mask_data (app_wdf_mask_data), - .ddr2_dqs (ddr2_dqs), - .ddr2_dqs_n (ddr2_dqs_n), - .ddr2_ck (ddr2_ck), - .rd_ecc_error (), - .ddr2_ck_n (ddr2_ck_n), - - .dbg_calib_done (dbg_calib_done), - .dbg_calib_err (dbg_calib_err), - .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), - .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), - .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), - .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), - .dbg_calib_rden_dly (dbg_calib_rden_dly), - .dbg_calib_gate_dly (dbg_calib_gate_dly), - .dbg_idel_up_all (dbg_idel_up_all), - .dbg_idel_down_all (dbg_idel_down_all), - .dbg_idel_up_dq (dbg_idel_up_dq), - .dbg_idel_down_dq (dbg_idel_down_dq), - .dbg_idel_up_dqs (dbg_idel_up_dqs), - .dbg_idel_down_dqs (dbg_idel_down_dqs), - .dbg_idel_up_gate (dbg_idel_up_gate), - .dbg_idel_down_gate (dbg_idel_down_gate), - .dbg_sel_idel_dq (dbg_sel_idel_dq), - .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), - .dbg_sel_idel_dqs (dbg_sel_idel_dqs), - .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), - .dbg_sel_idel_gate (dbg_sel_idel_gate), - .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate) - ); - - - //***************************************************************** - // Hooks to prevent sim/syn compilation errors (mainly for VHDL - but - // keep it also in Verilog version of code) w/ floating inputs if - // DEBUG_EN = 0. - //***************************************************************** - - generate - if (DEBUG_EN == 0) begin: gen_dbg_tie_off - assign dbg_idel_up_all = 'b0; - assign dbg_idel_down_all = 'b0; - assign dbg_idel_up_dq = 'b0; - assign dbg_idel_down_dq = 'b0; - assign dbg_idel_up_dqs = 'b0; - assign dbg_idel_down_dqs = 'b0; - assign dbg_idel_up_gate = 'b0; - assign dbg_idel_down_gate = 'b0; - assign dbg_sel_idel_dq = 'b0; - assign dbg_sel_all_idel_dq = 'b0; - assign dbg_sel_idel_dqs = 'b0; - assign dbg_sel_all_idel_dqs = 'b0; - assign dbg_sel_idel_gate = 'b0; - assign dbg_sel_all_idel_gate = 'b0; - end else begin: gen_dbg_enable - - //***************************************************************** - // PHY Debug Port example - see MIG User's Guide, XAPP858 or - // Answer Record 29443 - // This logic supports up to 32 DQ and 8 DQS I/O - // NOTES: - // 1. PHY Debug Port demo connects to 4 VIO modules: - // - 3 VIO modules with only asynchronous inputs - // * Monitor IDELAY taps for DQ, DQS, DQS Gate - // * Calibration status - // - 1 VIO module with synchronous outputs - // * Allow dynamic adjustment o f IDELAY taps - // 2. User may need to modify this code to incorporate other - // chipscope-related modules in their larger design (e.g. - // if they have other ILA/VIO modules, they will need to - // for example instantiate a larger ICON module). In addition - // user may want to instantiate more VIO modules to control - // IDELAY for more DQ, DQS than is shown here - //***************************************************************** - - icon4 u_icon - ( - .control0 (cs_control0), - .control1 (cs_control1), - .control2 (cs_control2), - .control3 (cs_control3) - ); - - //***************************************************************** - // VIO ASYNC input: Display current IDELAY setting for up to 32 - // DQ taps (32x6) = 192 - //***************************************************************** - - vio_async_in192 u_vio0 - ( - .control (cs_control0), - .async_in (vio0_in) - ); - - //***************************************************************** - // VIO ASYNC input: Display current IDELAY setting for up to 8 DQS - // and DQS Gate taps (8x6x2) = 96 - //***************************************************************** - - vio_async_in96 u_vio1 - ( - .control (cs_control1), - .async_in (vio1_in) - ); - - //***************************************************************** - // VIO ASYNC input: Display other calibration results - //***************************************************************** - - vio_async_in100 u_vio2 - ( - .control (cs_control2), - .async_in (vio2_in) - ); - - //***************************************************************** - // VIO SYNC output: Dynamically change IDELAY taps - //***************************************************************** - - vio_sync_out32 u_vio3 - ( - .control (cs_control3), - .clk (clkdiv0), - .sync_out (vio3_out) - ); - - //***************************************************************** - // Bit assignments: - // NOTE: Not all VIO, ILA inputs/outputs may be used - these will - // be dependent on the user's particular bit width - //***************************************************************** - - if (DQ_WIDTH <= 32) begin: gen_dq_le_32 - assign vio0_in[(6*DQ_WIDTH)-1:0] - = dbg_calib_dq_tap_cnt[(6*DQ_WIDTH)-1:0]; - end else begin: gen_dq_gt_32 - assign vio0_in = dbg_calib_dq_tap_cnt[191:0]; - end - - if (DQS_WIDTH <= 8) begin: gen_dqs_le_8 - assign vio1_in[(6*DQS_WIDTH)-1:0] - = dbg_calib_dqs_tap_cnt[(6*DQS_WIDTH)-1:0]; - assign vio1_in[(12*DQS_WIDTH)-1:(6*DQS_WIDTH)] - = dbg_calib_gate_tap_cnt[(6*DQS_WIDTH)-1:0]; - end else begin: gen_dqs_gt_32 - assign vio1_in[47:0] = dbg_calib_dqs_tap_cnt[47:0]; - assign vio1_in[95:48] = dbg_calib_gate_tap_cnt[47:0]; - end - -//dbg_calib_rd_data_sel - - if (DQS_WIDTH <= 8) begin: gen_rdsel_le_8 - assign vio2_in[(DQS_WIDTH)+7:8] - = dbg_calib_rd_data_sel[(DQS_WIDTH)-1:0]; - end else begin: gen_rdsel_gt_32 - assign vio2_in[15:8] - = dbg_calib_rd_data_sel[7:0]; - end - -//dbg_calib_rden_dly - - if (DQS_WIDTH <= 8) begin: gen_calrd_le_8 - assign vio2_in[(5*DQS_WIDTH)+19:20] - = dbg_calib_rden_dly[(5*DQS_WIDTH)-1:0]; - end else begin: gen_calrd_gt_32 - assign vio2_in[59:20] - = dbg_calib_rden_dly[39:0]; - end - -//dbg_calib_gate_dly - - if (DQS_WIDTH <= 8) begin: gen_calgt_le_8 - assign vio2_in[(5*DQS_WIDTH)+59:60] - = dbg_calib_gate_dly[(5*DQS_WIDTH)-1:0]; - end else begin: gen_calgt_gt_32 - assign vio2_in[99:60] - = dbg_calib_gate_dly[39:0]; - end - -//dbg_sel_idel_dq - - if (DQ_BITS <= 5) begin: gen_selid_le_5 - assign dbg_sel_idel_dq[DQ_BITS-1:0] - = vio3_out[DQ_BITS+7:8]; - end else begin: gen_selid_gt_32 - assign dbg_sel_idel_dq[4:0] - = vio3_out[12:8]; - end - -//dbg_sel_idel_dqs - - if (DQS_BITS <= 3) begin: gen_seldqs_le_3 - assign dbg_sel_idel_dqs[DQS_BITS:0] - = vio3_out[(DQS_BITS+16):16]; - end else begin: gen_seldqs_gt_32 - assign dbg_sel_idel_dqs[3:0] - = vio3_out[19:16]; - end - -//dbg_sel_idel_gate - - if (DQS_BITS <= 3) begin: gen_gtdqs_le_3 - assign dbg_sel_idel_gate[DQS_BITS:0] - = vio3_out[(DQS_BITS+21):21]; - end else begin: gen_gtdqs_gt_32 - assign dbg_sel_idel_gate[3:0] - = vio3_out[24:21]; - end - - - assign vio2_in[3:0] = dbg_calib_done; - assign vio2_in[7:4] = dbg_calib_err; - - assign dbg_idel_up_all = vio3_out[0]; - assign dbg_idel_down_all = vio3_out[1]; - assign dbg_idel_up_dq = vio3_out[2]; - assign dbg_idel_down_dq = vio3_out[3]; - assign dbg_idel_up_dqs = vio3_out[4]; - assign dbg_idel_down_dqs = vio3_out[5]; - assign dbg_idel_up_gate = vio3_out[6]; - assign dbg_idel_down_gate = vio3_out[7]; - assign dbg_sel_all_idel_dq = vio3_out[15]; - assign dbg_sel_all_idel_dqs = vio3_out[20]; - assign dbg_sel_all_idel_gate = vio3_out[25]; - end - endgenerate - - -endmodule - - - Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_ctl_io.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_ctl_io.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_ctl_io.v (nonexistent) @@ -1,304 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_ctl_io.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Thu Aug 24 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module puts the memory control signals like address, bank address, -// row address strobe, column address strobe, write enable and clock enable -// in the IOBs. -//Reference: -//Revision History: -// Rev 1.1 - To fix CR 540201, S attribute is added for CS, CKE and ODT -// module (FDCPE) instances. PK. 01/08/10 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_phy_ctl_io # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter CKE_WIDTH = 1, - parameter COL_WIDTH = 10, - parameter CS_NUM = 1, - parameter TWO_T_TIME_EN = 0, - parameter CS_WIDTH = 1, - parameter ODT_WIDTH = 1, - parameter ROW_WIDTH = 14, - parameter DDR_TYPE = 1 - ) - ( - input clk0, - input clk90, - input rst0, - input rst90, - input [ROW_WIDTH-1:0] ctrl_addr, - input [BANK_WIDTH-1:0] ctrl_ba, - input ctrl_ras_n, - input ctrl_cas_n, - input ctrl_we_n, - input [CS_NUM-1:0] ctrl_cs_n, - input [ROW_WIDTH-1:0] phy_init_addr, - input [BANK_WIDTH-1:0] phy_init_ba, - input phy_init_ras_n, - input phy_init_cas_n, - input phy_init_we_n, - input [CS_NUM-1:0] phy_init_cs_n, - input [CKE_WIDTH-1:0] phy_init_cke, - input phy_init_data_sel, - input [CS_NUM-1:0] odt, - output [ROW_WIDTH-1:0] ddr_addr, - output [BANK_WIDTH-1:0] ddr_ba, - output ddr_ras_n, - output ddr_cas_n, - output ddr_we_n, - output [CKE_WIDTH-1:0] ddr_cke, - output [CS_WIDTH-1:0] ddr_cs_n, - output [ODT_WIDTH-1:0] ddr_odt - ); - - reg [ROW_WIDTH-1:0] addr_mux; - reg [BANK_WIDTH-1:0] ba_mux; - reg cas_n_mux; - reg [CS_NUM-1:0] cs_n_mux; - reg ras_n_mux; - reg we_n_mux; - - - - //*************************************************************************** - - - - - // MUX to choose from either PHY or controller for SDRAM control - - generate // in 2t timing mode the extra register stage cannot be used. - if(TWO_T_TIME_EN) begin // the control signals are asserted for two cycles - always @(*)begin - if (phy_init_data_sel) begin - addr_mux = ctrl_addr; - ba_mux = ctrl_ba; - cas_n_mux = ctrl_cas_n; - cs_n_mux = ctrl_cs_n; - ras_n_mux = ctrl_ras_n; - we_n_mux = ctrl_we_n; - end else begin - addr_mux = phy_init_addr; - ba_mux = phy_init_ba; - cas_n_mux = phy_init_cas_n; - cs_n_mux = phy_init_cs_n; - ras_n_mux = phy_init_ras_n; - we_n_mux = phy_init_we_n; - end - end - end else begin - always @(posedge clk0)begin // register the signals in non 2t mode - if (phy_init_data_sel) begin - addr_mux <= ctrl_addr; - ba_mux <= ctrl_ba; - cas_n_mux <= ctrl_cas_n; - cs_n_mux <= ctrl_cs_n; - ras_n_mux <= ctrl_ras_n; - we_n_mux <= ctrl_we_n; - end else begin - addr_mux <= phy_init_addr; - ba_mux <= phy_init_ba; - cas_n_mux <= phy_init_cas_n; - cs_n_mux <= phy_init_cs_n; - ras_n_mux <= phy_init_ras_n; - we_n_mux <= phy_init_we_n; - end - end - end - endgenerate - - //*************************************************************************** - // Output flop instantiation - // NOTE: Make sure all control/address flops are placed in IOBs - //*************************************************************************** - - // RAS: = 1 at reset - (* IOB = "FORCE" *) FDCPE u_ff_ras_n - ( - .Q (ddr_ras_n), - .C (clk0), - .CE (1'b1), - .CLR (1'b0), - .D (ras_n_mux), - .PRE (rst0) - ) /* synthesis syn_useioff = 1 */; - - // CAS: = 1 at reset - (* IOB = "FORCE" *) FDCPE u_ff_cas_n - ( - .Q (ddr_cas_n), - .C (clk0), - .CE (1'b1), - .CLR (1'b0), - .D (cas_n_mux), - .PRE (rst0) - ) /* synthesis syn_useioff = 1 */; - - // WE: = 1 at reset - (* IOB = "FORCE" *) FDCPE u_ff_we_n - ( - .Q (ddr_we_n), - .C (clk0), - .CE (1'b1), - .CLR (1'b0), - .D (we_n_mux), - .PRE (rst0) - ) /* synthesis syn_useioff = 1 */; - - // CKE: = 0 at reset - genvar cke_i; - generate - for (cke_i = 0; cke_i < CKE_WIDTH; cke_i = cke_i + 1) begin: gen_cke - (* IOB = "FORCE" *) (* S = "TRUE" *) FDCPE u_ff_cke - ( - .Q (ddr_cke[cke_i]), - .C (clk0), - .CE (1'b1), - .CLR (rst0), - .D (phy_init_cke[cke_i]), - .PRE (1'b0) - ) /* synthesis syn_useioff = 1 */; - end - endgenerate - - // chip select: = 1 at reset - // For unbuffered dimms the loading will be high. The chip select - // can be asserted early if the loading is very high. The - // code as is uses clock 0. If needed clock 270 can be used to - // toggle chip select 1/4 clock cycle early. The code has - // the clock 90 input for the early assertion of chip select. - - genvar cs_i; - generate - for(cs_i = 0; cs_i < CS_WIDTH; cs_i = cs_i + 1) begin: gen_cs_n - if(TWO_T_TIME_EN) begin - (* IOB = "FORCE" *) (* S = "TRUE" *) FDCPE u_ff_cs_n - ( - .Q (ddr_cs_n[cs_i]), - .C (clk0), - .CE (1'b1), - .CLR (1'b0), - .D (cs_n_mux[(cs_i*CS_NUM)/CS_WIDTH]), - .PRE (rst0) - ) /* synthesis syn_useioff = 1 */; - end else begin // if (TWO_T_TIME_EN) - (* IOB = "FORCE" *) (* S = "TRUE" *) FDCPE u_ff_cs_n - ( - .Q (ddr_cs_n[cs_i]), - .C (clk0), - .CE (1'b1), - .CLR (1'b0), - .D (cs_n_mux[(cs_i*CS_NUM)/CS_WIDTH]), - .PRE (rst0) - ) /* synthesis syn_useioff = 1 */; - end // else: !if(TWO_T_TIME_EN) - end - endgenerate - - // address: = X at reset - genvar addr_i; - generate - for (addr_i = 0; addr_i < ROW_WIDTH; addr_i = addr_i + 1) begin: gen_addr - (* IOB = "FORCE" *) FDCPE u_ff_addr - ( - .Q (ddr_addr[addr_i]), - .C (clk0), - .CE (1'b1), - .CLR (1'b0), - .D (addr_mux[addr_i]), - .PRE (1'b0) - ) /* synthesis syn_useioff = 1 */; - end - endgenerate - - // bank address = X at reset - genvar ba_i; - generate - for (ba_i = 0; ba_i < BANK_WIDTH; ba_i = ba_i + 1) begin: gen_ba - (* IOB = "FORCE" *) FDCPE u_ff_ba - ( - .Q (ddr_ba[ba_i]), - .C (clk0), - .CE (1'b1), - .CLR (1'b0), - .D (ba_mux[ba_i]), - .PRE (1'b0) - ) /* synthesis syn_useioff = 1 */; - end - endgenerate - - // ODT control = 0 at reset - genvar odt_i; - generate - if (DDR_TYPE > 0) begin: gen_odt_ddr2 - for (odt_i = 0; odt_i < ODT_WIDTH; odt_i = odt_i + 1) begin: gen_odt - (* IOB = "FORCE" *) (* S = "TRUE" *) FDCPE u_ff_odt - ( - .Q (ddr_odt[odt_i]), - .C (clk0), - .CE (1'b1), - .CLR (rst0), - .D (odt[(odt_i*CS_NUM)/ODT_WIDTH]), - .PRE (1'b0) - ) /* synthesis syn_useioff = 1 */; - end - end - endgenerate - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_calib.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_calib.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_calib.v (nonexistent) @@ -1,2428 +0,0 @@ -//***************************************************************************** -// (c) Copyright 2006-2009 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: 3.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_calib.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Thu Aug 10 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module handles calibration after memory initialization. -//Reference: -//Revision History: -// Rev 1.1 - Default statement is added for the CASE statement of -// rdd_mux_sel logic. PK. 03/23/09 -// Rev 1.2 - Change training pattern detected for stage 3 calibration. -// Use 2-bits per DQS group for stage 3 pattern detection. -// RC. 09/21/09 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_phy_calib # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter DQ_WIDTH = 72, - parameter DQ_BITS = 7, - parameter DQ_PER_DQS = 8, - parameter DQS_BITS = 4, - parameter DQS_WIDTH = 9, - parameter ADDITIVE_LAT = 0, - parameter CAS_LAT = 5, - parameter REG_ENABLE = 1, - parameter CLK_PERIOD = 3000, - parameter SIM_ONLY = 0, - parameter DEBUG_EN = 0 - ) - ( - input clk, - input clkdiv, - input rstdiv, - input [3:0] calib_start, - input ctrl_rden, - input phy_init_rden, - input [DQ_WIDTH-1:0] rd_data_rise, - input [DQ_WIDTH-1:0] rd_data_fall, - input calib_ref_done, - output reg [3:0] calib_done, - output reg calib_ref_req, - output [DQS_WIDTH-1:0] calib_rden, - output reg [DQS_WIDTH-1:0] calib_rden_sel, - output reg dlyrst_dq, - output reg [DQ_WIDTH-1:0] dlyce_dq, - output reg [DQ_WIDTH-1:0] dlyinc_dq, - output reg dlyrst_dqs, - output reg [DQS_WIDTH-1:0] dlyce_dqs, - output reg [DQS_WIDTH-1:0] dlyinc_dqs, - output reg [DQS_WIDTH-1:0] dlyrst_gate, - output reg [DQS_WIDTH-1:0] dlyce_gate, - output reg [DQS_WIDTH-1:0] dlyinc_gate, - //(* XIL_PAR_NO_REG_ORDER = "TRUE", XIL_PAR_PATH="Q->u_iodelay_dq_ce.DATAIN", syn_keep = "1", keep = "TRUE"*) - output [DQS_WIDTH-1:0] en_dqs, - output [DQS_WIDTH-1:0] rd_data_sel, - // Debug signals (optional use) - input dbg_idel_up_all, - input dbg_idel_down_all, - input dbg_idel_up_dq, - input dbg_idel_down_dq, - input dbg_idel_up_dqs, - input dbg_idel_down_dqs, - input dbg_idel_up_gate, - input dbg_idel_down_gate, - input [DQ_BITS-1:0] dbg_sel_idel_dq, - input dbg_sel_all_idel_dq, - input [DQS_BITS:0] dbg_sel_idel_dqs, - input dbg_sel_all_idel_dqs, - input [DQS_BITS:0] dbg_sel_idel_gate, - input dbg_sel_all_idel_gate, - output [3:0] dbg_calib_done, - output [3:0] dbg_calib_err, - output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, - output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, - output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, - output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly - ); - - // minimum time (in IDELAY taps) for which capture data must be stable for - // algorithm to consider - localparam MIN_WIN_SIZE = 5; - // IDEL_SET_VAL = (# of cycles - 1) to wait after changing IDELAY value - // we only have to wait enough for input with new IDELAY value to - // propagate through pipeline stages. - localparam IDEL_SET_VAL = 3'b111; - // # of clock cycles to delay read enable to determine if read data pattern - // is correct for stage 3/4 (RDEN, DQS gate) calibration - localparam CALIB_RDEN_PIPE_LEN = 31; - // translate CAS latency into number of clock cycles for read valid delay - // determination. Really only needed for CL = 2.5 (set to 2) - localparam CAS_LAT_RDEN = (CAS_LAT == 25) ? 2 : CAS_LAT; - // an SRL32 is used to delay CTRL_RDEN to generate read valid signal. This - // is min possible value delay through SRL32 can be - localparam RDEN_BASE_DELAY = CAS_LAT_RDEN + ADDITIVE_LAT + REG_ENABLE; - // an SRL32 is used to delay the CTRL_RDEN from the read postamble DQS - // gate. This is min possible value the SRL32 delay can be: - // - Delay from end of deassertion of CTRL_RDEN to last falling edge of - // read burst = 3.5 (CTRL_RDEN -> CAS delay) + 3 (min CAS latency) = 6.5 - // - Minimum time for DQS gate circuit to be generated: - // * 1 cyc to register CTRL_RDEN from controller - // * 1 cyc after RDEN_CTRL falling edge - // * 1 cyc min through SRL32 - // * 1 cyc through SRL32 output flop - // * 0 (<1) cyc of synchronization to DQS domain via IDELAY - // * 1 cyc of delay through IDDR to generate CE to DQ IDDR's - // Total = 5 cyc < 6.5 cycles - // The total should be less than 5.5 cycles to account prop delays - // adding one cycle to the synchronization time via the IDELAY. - // NOTE: Value differs because of optional pipeline register added - // for case of RDEN_BASE_DELAY > 3 to improve timing - localparam GATE_BASE_DELAY = RDEN_BASE_DELAY - 3; - localparam GATE_BASE_INIT = (GATE_BASE_DELAY <= 1) ? 0 : GATE_BASE_DELAY; - // used for RDEN calibration: difference between shift value used during - // calibration, and shift value for actual RDEN SRL. Only applies when - // RDEN edge is immediately captured by CLKDIV0. If not (depends on phase - // of CLK0 and CLKDIV0 when RDEN is asserted), then add 1 to this value. - localparam CAL3_RDEN_SRL_DLY_DELTA = 6; - // fix minimum value of DQS to be 1 to handle the case where's there's only - // one DQS group. We could also enforce that user always inputs minimum - // value of 1 for DQS_BITS (even when DQS_WIDTH=1). Leave this as safeguard - // Assume we don't have to do this for DQ, DQ_WIDTH always > 1 - localparam DQS_BITS_FIX = (DQS_BITS == 0) ? 1 : DQS_BITS; - // how many taps to "pre-delay" DQ before stg 1 calibration - not needed for - // current calibration, but leave for debug - localparam DQ_IDEL_INIT = 6'b000000; - // # IDELAY taps per bit time (i.e. half cycle). Limit to 63. - localparam integer BIT_TIME_TAPS = (CLK_PERIOD/150 < 64) ? - CLK_PERIOD/150 : 63; - - // used in various places during stage 4 cal: (1) determines maximum taps - // to increment when finding right edge, (2) amount to decrement after - // finding left edge, (3) amount to increment after finding right edge - localparam CAL4_IDEL_BIT_VAL = (BIT_TIME_TAPS >= 6'b100000) ? - 6'b100000 : BIT_TIME_TAPS; - - localparam CAL1_IDLE = 4'h0; - localparam CAL1_INIT = 4'h1; - localparam CAL1_INC_IDEL = 4'h2; - localparam CAL1_FIND_FIRST_EDGE = 4'h3; - localparam CAL1_FIRST_EDGE_IDEL_WAIT = 4'h4; - localparam CAL1_FOUND_FIRST_EDGE_WAIT = 4'h5; - localparam CAL1_FIND_SECOND_EDGE = 4'h6; - localparam CAL1_SECOND_EDGE_IDEL_WAIT = 4'h7; - localparam CAL1_CALC_IDEL = 4'h8; - localparam CAL1_DEC_IDEL = 4'h9; - localparam CAL1_DONE = 4'hA; - - localparam CAL2_IDLE = 4'h0; - localparam CAL2_INIT = 4'h1; - localparam CAL2_INIT_IDEL_WAIT = 4'h2; - localparam CAL2_FIND_EDGE_POS = 4'h3; - localparam CAL2_FIND_EDGE_IDEL_WAIT_POS = 4'h4; - localparam CAL2_FIND_EDGE_NEG = 4'h5; - localparam CAL2_FIND_EDGE_IDEL_WAIT_NEG = 4'h6; - localparam CAL2_DEC_IDEL = 4'h7; - localparam CAL2_DONE = 4'h8; - - localparam CAL3_IDLE = 3'h0; - localparam CAL3_INIT = 3'h1; - localparam CAL3_DETECT = 3'h2; - localparam CAL3_RDEN_PIPE_CLR_WAIT = 3'h3; - localparam CAL3_DONE = 3'h4; - - localparam CAL4_IDLE = 3'h0; - localparam CAL4_INIT = 3'h1; - localparam CAL4_FIND_WINDOW = 3'h2; - localparam CAL4_FIND_EDGE = 3'h3; - localparam CAL4_IDEL_WAIT = 3'h4; - localparam CAL4_RDEN_PIPE_CLR_WAIT = 3'h5; - localparam CAL4_ADJ_IDEL = 3'h6; - localparam CAL4_DONE = 3'h7; - - integer i, j; - - reg [5:0] cal1_bit_time_tap_cnt; - reg [1:0] cal1_data_chk_last; - reg cal1_data_chk_last_valid; - reg [1:0] cal1_data_chk_r; - reg cal1_dlyce_dq; - reg cal1_dlyinc_dq; - reg cal1_dqs_dq_init_phase; - reg cal1_detect_edge; - reg cal1_detect_stable; - reg cal1_found_second_edge; - reg cal1_found_rising; - reg cal1_found_window; - reg cal1_first_edge_done; - reg [5:0] cal1_first_edge_tap_cnt; - reg [6:0] cal1_idel_dec_cnt; - reg [5:0] cal1_idel_inc_cnt; - reg [5:0] cal1_idel_max_tap; - reg cal1_idel_max_tap_we; - reg [5:0] cal1_idel_tap_cnt; - reg cal1_idel_tap_limit_hit; - reg [6:0] cal1_low_freq_idel_dec; - reg cal1_ref_req; - wire cal1_refresh; - reg [3:0] cal1_state; - reg [3:0] cal1_window_cnt; - reg cal2_curr_sel; - wire cal2_detect_edge; - reg cal2_dlyce_dqs; - reg cal2_dlyinc_dqs; - reg [5:0] cal2_idel_dec_cnt; - reg [5:0] cal2_idel_tap_cnt; - reg [5:0] cal2_idel_tap_limit; - reg cal2_idel_tap_limit_hit; - reg cal2_rd_data_fall_last_neg; - reg cal2_rd_data_fall_last_pos; - reg cal2_rd_data_last_valid_neg; - reg cal2_rd_data_last_valid_pos; - reg cal2_rd_data_rise_last_neg; - reg cal2_rd_data_rise_last_pos; - reg [DQS_WIDTH-1:0] cal2_rd_data_sel; - wire cal2_rd_data_sel_edge; - reg [DQS_WIDTH-1:0] cal2_rd_data_sel_r; - reg cal2_ref_req; - reg [3:0] cal2_state; - reg cal3_data_match; - reg cal3_data_match_stgd; - wire cal3_data_valid; - wire cal3_match_found; - wire [4:0] cal3_rden_dly; - reg [4:0] cal3_rden_srl_a; - reg [2:0] cal3_state; - wire cal4_data_good; - reg cal4_data_match; - reg cal4_data_match_stgd; - wire cal4_data_valid; - reg cal4_dlyce_gate; - reg cal4_dlyinc_gate; - reg cal4_dlyrst_gate; - reg [4:0] cal4_gate_srl_a; - reg [5:0] cal4_idel_adj_cnt; - reg cal4_idel_adj_inc; - reg cal4_idel_bit_tap; - reg [5:0] cal4_idel_tap_cnt; - reg cal4_idel_max_tap; - reg [4:0] cal4_rden_srl_a; - reg cal4_ref_req; - reg cal4_seek_left; - reg cal4_stable_window; - reg [2:0] cal4_state; - reg [3:0] cal4_window_cnt; - reg [3:0] calib_done_tmp; // only for stg1/2/4 - reg calib_ctrl_gate_pulse_r; - reg calib_ctrl_rden; - reg calib_ctrl_rden_r; - wire calib_ctrl_rden_negedge; - reg calib_ctrl_rden_negedge_r; - reg [3:0] calib_done_r; - reg [3:0] calib_err; - reg [1:0] calib_err_2; - wire calib_init_gate_pulse; - reg calib_init_gate_pulse_r; - reg calib_init_gate_pulse_r1; - reg calib_init_rden; - reg calib_init_rden_r; - reg [4:0] calib_rden_srl_a; - wire [4:0] calib_rden_srl_a_r; - reg [(5*DQS_WIDTH)-1:0] calib_rden_dly; - reg calib_rden_edge_r; - reg [4:0] calib_rden_pipe_cnt; - wire calib_rden_srl_out; - wire calib_rden_srl_out_r; - reg calib_rden_srl_out_r1; - reg calib_rden_valid; - reg calib_rden_valid_stgd; - reg [DQ_BITS-1:0] count_dq; - reg [DQS_BITS_FIX-1:0] count_dqs; - reg [DQS_BITS_FIX-1:0] count_gate; - reg [DQS_BITS_FIX-1:0] count_rden; - reg ctrl_rden_r; - wire dlyce_or; - reg [(5*DQS_WIDTH)-1:0] gate_dly; - wire [(5*DQS_WIDTH)-1:0] gate_dly_r; - wire gate_srl_in; - wire [DQS_WIDTH-1:0] gate_srl_out; - wire [DQS_WIDTH-1:0] gate_srl_out_r; - reg [2:0] idel_set_cnt; - wire idel_set_wait; - reg [DQ_BITS-1:0] next_count_dq; - reg [DQS_BITS_FIX-1:0] next_count_dqs; - reg [DQS_BITS_FIX-1:0] next_count_gate; - reg phy_init_rden_r; - reg phy_init_rden_r1; - reg [DQS_WIDTH-1:0] rd_data_fall_1x_bit1_r1; - reg [DQ_WIDTH-1:0] rd_data_fall_1x_r; - reg [DQS_WIDTH-1:0] rd_data_fall_1x_r1; - reg [DQS_WIDTH-1:0] rd_data_fall_2x_bit1_r; - reg [DQS_WIDTH-1:0] rd_data_fall_2x_r; - wire [DQS_WIDTH-1:0] rd_data_fall_chk_q1; - wire [DQS_WIDTH-1:0] rd_data_fall_chk_q1_bit1; - wire [DQS_WIDTH-1:0] rd_data_fall_chk_q2; - wire [DQS_WIDTH-1:0] rd_data_fall_chk_q2_bit1; - reg [DQS_WIDTH-1:0] rd_data_rise_1x_bit1_r1; - reg [DQ_WIDTH-1:0] rd_data_rise_1x_r; - reg [DQS_WIDTH-1:0] rd_data_rise_1x_r1; - reg [DQS_WIDTH-1:0] rd_data_rise_2x_bit1_r; - reg [DQS_WIDTH-1:0] rd_data_rise_2x_r; - wire [DQS_WIDTH-1:0] rd_data_rise_chk_q1; - wire [DQS_WIDTH-1:0] rd_data_rise_chk_q1_bit1; - wire [DQS_WIDTH-1:0] rd_data_rise_chk_q2; - wire [DQS_WIDTH-1:0] rd_data_rise_chk_q2_bit1; - reg rdd_fall_q1; - reg rdd_fall_q1_bit1; - reg rdd_fall_q1_bit1_r; - reg rdd_fall_q1_bit1_r1; - reg rdd_fall_q1_r; - reg rdd_fall_q1_r1; - reg rdd_fall_q2; - reg rdd_fall_q2_bit1; - reg rdd_fall_q2_bit1_r; - reg rdd_fall_q2_r; - reg rdd_rise_q1; - reg rdd_rise_q1_bit1; - reg rdd_rise_q1_bit1_r; - reg rdd_rise_q1_bit1_r1; - reg rdd_rise_q1_r; - reg rdd_rise_q1_r1; - reg rdd_rise_q2; - reg rdd_rise_q2_bit1; - reg rdd_rise_q2_bit1_r; - reg rdd_rise_q2_r; - reg [DQS_BITS_FIX-1:0] rdd_mux_sel; - reg rden_dec; - reg [(5*DQS_WIDTH)-1:0] rden_dly; - wire [(5*DQS_WIDTH)-1:0] rden_dly_r; - reg [4:0] rden_dly_0; - reg rden_inc; - reg [DQS_WIDTH-1:0] rden_mux; - wire [DQS_WIDTH-1:0] rden_srl_out; - - // Debug - integer x; - reg [5:0] dbg_dq_tap_cnt [DQ_WIDTH-1:0]; - reg [5:0] dbg_dqs_tap_cnt [DQS_WIDTH-1:0]; - reg [5:0] dbg_gate_tap_cnt [DQS_WIDTH-1:0]; - - //*************************************************************************** - // Debug output ("dbg_phy_calib_*") - // NOTES: - // 1. All debug outputs coming out of PHY_CALIB are clocked off CLKDIV0, - // although they are also static after calibration is complete. This - // means the user can either connect them to a Chipscope ILA, or to - // either a sync/async VIO input block. Using an async VIO has the - // advantage of not requiring these paths to meet cycle-to-cycle timing. - // 2. The widths of most of these debug buses are dependent on the # of - // DQS/DQ bits (e.g. dq_tap_cnt width = 6 * (# of DQ bits) - // SIGNAL DESCRIPTION: - // 1. calib_done: 4 bits - each one asserted as each phase of calibration - // is completed. - // 2. calib_err: 4 bits - each one asserted when a calibration error - // encountered for that stage. Some of these bits may not - // be used (not all cal stages report an error). - // 3. dq_tap_cnt: final IDELAY tap counts for all DQ IDELAYs - // 4. dqs_tap_cnt: final IDELAY tap counts for all DQS IDELAYs - // 5. gate_tap_cnt: final IDELAY tap counts for all DQS gate - // synchronization IDELAYs - // 6. rd_data_sel: final read capture MUX (either "positive" or "negative" - // edge capture) settings for all DQS groups - // 7. rden_dly: related to # of cycles after issuing a read until when - // read data is valid - for all DQS groups - // 8. gate_dly: related to # of cycles after issuing a read until when - // clock enable for all DQ's is deasserted to prevent - // effect of DQS postamble glitch - for all DQS groups - //*************************************************************************** - - //***************************************************************** - // Record IDELAY tap values by "snooping" IDELAY control signals - //***************************************************************** - - // record DQ IDELAY tap values - genvar dbg_dq_tc_i; - generate - for (dbg_dq_tc_i = 0; dbg_dq_tc_i < DQ_WIDTH; - dbg_dq_tc_i = dbg_dq_tc_i + 1) begin: gen_dbg_dq_tap_cnt - assign dbg_calib_dq_tap_cnt[(6*dbg_dq_tc_i)+5:(6*dbg_dq_tc_i)] - = dbg_dq_tap_cnt[dbg_dq_tc_i]; - always @(posedge clkdiv) - if (rstdiv | dlyrst_dq) - dbg_dq_tap_cnt[dbg_dq_tc_i] <= 6'b000000; - else - if (dlyce_dq[dbg_dq_tc_i]) - if (dlyinc_dq[dbg_dq_tc_i]) - dbg_dq_tap_cnt[dbg_dq_tc_i] - <= dbg_dq_tap_cnt[dbg_dq_tc_i] + 1; - else - dbg_dq_tap_cnt[dbg_dq_tc_i] - <= dbg_dq_tap_cnt[dbg_dq_tc_i] - 1; - end - endgenerate - - // record DQS IDELAY tap values - genvar dbg_dqs_tc_i; - generate - for (dbg_dqs_tc_i = 0; dbg_dqs_tc_i < DQS_WIDTH; - dbg_dqs_tc_i = dbg_dqs_tc_i + 1) begin: gen_dbg_dqs_tap_cnt - assign dbg_calib_dqs_tap_cnt[(6*dbg_dqs_tc_i)+5:(6*dbg_dqs_tc_i)] - = dbg_dqs_tap_cnt[dbg_dqs_tc_i]; - always @(posedge clkdiv) - if (rstdiv | dlyrst_dqs) - dbg_dqs_tap_cnt[dbg_dqs_tc_i] <= 6'b000000; - else - if (dlyce_dqs[dbg_dqs_tc_i]) - if (dlyinc_dqs[dbg_dqs_tc_i]) - dbg_dqs_tap_cnt[dbg_dqs_tc_i] - <= dbg_dqs_tap_cnt[dbg_dqs_tc_i] + 1; - else - dbg_dqs_tap_cnt[dbg_dqs_tc_i] - <= dbg_dqs_tap_cnt[dbg_dqs_tc_i] - 1; - end - endgenerate - - // record DQS gate IDELAY tap values - genvar dbg_gate_tc_i; - generate - for (dbg_gate_tc_i = 0; dbg_gate_tc_i < DQS_WIDTH; - dbg_gate_tc_i = dbg_gate_tc_i + 1) begin: gen_dbg_gate_tap_cnt - assign dbg_calib_gate_tap_cnt[(6*dbg_gate_tc_i)+5:(6*dbg_gate_tc_i)] - = dbg_gate_tap_cnt[dbg_gate_tc_i]; - always @(posedge clkdiv) - if (rstdiv | dlyrst_gate[dbg_gate_tc_i]) - dbg_gate_tap_cnt[dbg_gate_tc_i] <= 6'b000000; - else - if (dlyce_gate[dbg_gate_tc_i]) - if (dlyinc_gate[dbg_gate_tc_i]) - dbg_gate_tap_cnt[dbg_gate_tc_i] - <= dbg_gate_tap_cnt[dbg_gate_tc_i] + 1; - else - dbg_gate_tap_cnt[dbg_gate_tc_i] - <= dbg_gate_tap_cnt[dbg_gate_tc_i] - 1; - end - endgenerate - - assign dbg_calib_done = calib_done; - assign dbg_calib_err = calib_err; - assign dbg_calib_rd_data_sel = cal2_rd_data_sel; - assign dbg_calib_rden_dly = rden_dly; - assign dbg_calib_gate_dly = gate_dly; - - //*************************************************************************** - // Read data pipelining, and read data "ISERDES" data width expansion - //*************************************************************************** - - // For all data bits, register incoming capture data to slow clock to improve - // timing. Adding single pipeline stage does not affect functionality (as - // long as we make sure to wait extra clock cycle after changing DQ IDELAY) - // Also note in this case that we're "missing" every other clock cycle's - // worth of data capture since we're sync'ing to the slow clock. This is - // fine for stage 1 and stage 2 cal, but not for stage 3 and 4 (see below - // for different circuit to handle those stages) - always @(posedge clkdiv) begin - rd_data_rise_1x_r <= rd_data_rise; - rd_data_fall_1x_r <= rd_data_fall; - end - - // For every DQ_PER_DQS bit, generate what is essentially a ISERDES-type - // data width expander. Will need this for stage 3 and 4 cal, where we need - // to compare data over consecutive clock cycles. We can also use this for - // stage 2 as well (stage 2 doesn't require every bit to be looked at, only - // one bit per DQS group) - // MIG 3.3: Expand to use lower two bits of each DQS group - use for stage - // 3 calibration for added robustness, since we will be checking for the - // training pattern from the memory even when the data bus is 3-stated. - // Theoretically it is possible for whatever garbage data is on the bus - // to be interpreted as the training sequence, although this can be made - // very unlikely by the choice of training sequence (bit sequence, length) - // and the number of bits compared for each DQS group. - genvar rdd_i; - generate - for (rdd_i = 0; rdd_i < DQS_WIDTH; rdd_i = rdd_i + 1) begin: gen_rdd - // first stage: keep data in fast clk domain. Store data over two - // consecutive clock cycles for rise/fall data for proper transfer - // to slow clock domain - always @(posedge clk) begin - rd_data_rise_2x_r[rdd_i] <= rd_data_rise[(rdd_i*DQ_PER_DQS)]; - rd_data_fall_2x_r[rdd_i] <= rd_data_fall[(rdd_i*DQ_PER_DQS)]; - rd_data_rise_2x_bit1_r[rdd_i] <= rd_data_rise[(rdd_i*DQ_PER_DQS)+1]; - rd_data_fall_2x_bit1_r[rdd_i] <= rd_data_fall[(rdd_i*DQ_PER_DQS)+1]; - end - // second stage, register first stage to slow clock domain, 2nd stage - // consists of both these flops, and the rd_data_rise_1x_r flops - always @(posedge clkdiv) begin - rd_data_rise_1x_r1[rdd_i] <= rd_data_rise_2x_r[rdd_i]; - rd_data_fall_1x_r1[rdd_i] <= rd_data_fall_2x_r[rdd_i]; - rd_data_rise_1x_bit1_r1[rdd_i] <= rd_data_rise_2x_bit1_r[rdd_i]; - rd_data_fall_1x_bit1_r1[rdd_i] <= rd_data_fall_2x_bit1_r[rdd_i]; - end - // now we have four outputs - representing rise/fall outputs over last - // 2 fast clock cycles. However, the ordering these represent can either - // be: (1) Q2 = data @ time = n, Q1 = data @ time = n+1, or (2) - // Q2 = data @ time = n - 1, Q1 = data @ time = n (and data at [Q1,Q2] - // is "staggered") - leave it up to the stage of calibration using this - // to figure out which is which, if they care at all (e.g. stage 2 cal - // doesn't care about the ordering) - assign rd_data_rise_chk_q1[rdd_i] - = rd_data_rise_1x_r[(rdd_i*DQ_PER_DQS)]; - assign rd_data_rise_chk_q2[rdd_i] - = rd_data_rise_1x_r1[rdd_i]; - assign rd_data_fall_chk_q1[rdd_i] - = rd_data_fall_1x_r[(rdd_i*DQ_PER_DQS)]; - assign rd_data_fall_chk_q2[rdd_i] - = rd_data_fall_1x_r1[rdd_i]; - // MIG 3.3: Added comparison for second bit in DQS group for stage 3 cal - assign rd_data_rise_chk_q1_bit1[rdd_i] - = rd_data_rise_1x_r[(rdd_i*DQ_PER_DQS)+1]; - assign rd_data_rise_chk_q2_bit1[rdd_i] - = rd_data_rise_1x_bit1_r1[rdd_i]; - assign rd_data_fall_chk_q1_bit1[rdd_i] - = rd_data_fall_1x_r[(rdd_i*DQ_PER_DQS)+1]; - assign rd_data_fall_chk_q2_bit1[rdd_i] - = rd_data_fall_1x_bit1_r1[rdd_i]; - end - endgenerate - - //***************************************************************** - // Outputs of these simplified ISERDES circuits then feed MUXes based on - // which DQ the current calibration algorithm needs to look at - //***************************************************************** - - // generate MUX control; assume that adding an extra pipeline stage isn't - // an issue - whatever stage cal logic is using output of MUX will wait - // enough time after changing it - always @(posedge clkdiv) begin - (* full_case, parallel_case *) case (calib_done[2:0]) - 3'b001: rdd_mux_sel <= next_count_dqs; - 3'b011: rdd_mux_sel <= count_rden; - 3'b111: rdd_mux_sel <= next_count_gate; - default: rdd_mux_sel <= {DQS_BITS_FIX{1'bx}}; - endcase - end - - always @(posedge clkdiv) begin - rdd_rise_q1 <= rd_data_rise_chk_q1[rdd_mux_sel]; - rdd_rise_q2 <= rd_data_rise_chk_q2[rdd_mux_sel]; - rdd_fall_q1 <= rd_data_fall_chk_q1[rdd_mux_sel]; - rdd_fall_q2 <= rd_data_fall_chk_q2[rdd_mux_sel]; - rdd_rise_q1_bit1 <= rd_data_rise_chk_q1_bit1[rdd_mux_sel]; - rdd_rise_q2_bit1 <= rd_data_rise_chk_q2_bit1[rdd_mux_sel]; - rdd_fall_q1_bit1 <= rd_data_fall_chk_q1_bit1[rdd_mux_sel]; - rdd_fall_q2_bit1 <= rd_data_fall_chk_q2_bit1[rdd_mux_sel]; - end - - //*************************************************************************** - // Demultiplexor to control (reset, increment, decrement) IDELAY tap values - // For DQ: - // STG1: for per-bit-deskew, only inc/dec the current DQ. For non-per - // deskew, increment all bits in the current DQS set - // STG2: inc/dec all DQ's in the current DQS set. - // NOTE: Nice to add some error checking logic here (or elsewhere in the - // code) to check if logic attempts to overflow tap value - //*************************************************************************** - - // don't use DLYRST to reset value of IDELAY after reset. Need to change this - // if we want to allow user to recalibrate after initial reset - always @(posedge clkdiv) - if (rstdiv) begin - dlyrst_dq <= 1'b1; - dlyrst_dqs <= 1'b1; - end else begin - dlyrst_dq <= 1'b0; - dlyrst_dqs <= 1'b0; - end - - always @(posedge clkdiv) begin - if (rstdiv) begin - dlyce_dq <= 'b0; - dlyinc_dq <= 'b0; - dlyce_dqs <= 'b0; - dlyinc_dqs <= 'b0; - end else begin - dlyce_dq <= 'b0; - dlyinc_dq <= 'b0; - dlyce_dqs <= 'b0; - dlyinc_dqs <= 'b0; - - // stage 1 cal: change only specified DQ - if (cal1_dlyce_dq) begin - if (SIM_ONLY == 0) begin - dlyce_dq[count_dq] <= 1'b1; - dlyinc_dq[count_dq] <= cal1_dlyinc_dq; - end else begin - // if simulation, then calibrate only first DQ, apply results - // to all DQs (i.e. assume delay on all DQs is the same) - for (i = 0; i < DQ_WIDTH; i = i + 1) begin: loop_sim_dq_dly - dlyce_dq[i] <= 1'b1; - dlyinc_dq[i] <= cal1_dlyinc_dq; - end - end - end else if (cal2_dlyce_dqs) begin - // stage 2 cal: change DQS and all corresponding DQ's - if (SIM_ONLY == 0) begin - dlyce_dqs[count_dqs] <= 1'b1; - dlyinc_dqs[count_dqs] <= cal2_dlyinc_dqs; - for (i = 0; i < DQ_PER_DQS; i = i + 1) begin: loop_dqs_dly - dlyce_dq[(DQ_PER_DQS*count_dqs)+i] <= 1'b1; - dlyinc_dq[(DQ_PER_DQS*count_dqs)+i] <= cal2_dlyinc_dqs; - end - end else begin - for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_dqs_dly - // if simulation, then calibrate only first DQS - dlyce_dqs[i] <= 1'b1; - dlyinc_dqs[i] <= cal2_dlyinc_dqs; - for (j = 0; j < DQ_PER_DQS; j = j + 1) begin: loop_sim_dq_dqs_dly - dlyce_dq[(DQ_PER_DQS*i)+j] <= 1'b1; - dlyinc_dq[(DQ_PER_DQS*i)+j] <= cal2_dlyinc_dqs; - end - end - end - end else if (DEBUG_EN != 0) begin - // DEBUG: allow user to vary IDELAY tap settings - // For DQ IDELAY taps - if (dbg_idel_up_all || dbg_idel_down_all || - dbg_sel_all_idel_dq) begin - for (x = 0; x < DQ_WIDTH; x = x + 1) begin: loop_dly_inc_dq - dlyce_dq[x] <= dbg_idel_up_all | dbg_idel_down_all | - dbg_idel_up_dq | dbg_idel_down_dq; - dlyinc_dq[x] <= dbg_idel_up_all | dbg_idel_up_dq; - end - end else begin - dlyce_dq <= 'b0; - dlyce_dq[dbg_sel_idel_dq] <= dbg_idel_up_dq | - dbg_idel_down_dq; - dlyinc_dq[dbg_sel_idel_dq] <= dbg_idel_up_dq; - end - // For DQS IDELAY taps - if (dbg_idel_up_all || dbg_idel_down_all || - dbg_sel_all_idel_dqs) begin - for (x = 0; x < DQS_WIDTH; x = x + 1) begin: loop_dly_inc_dqs - dlyce_dqs[x] <= dbg_idel_up_all | dbg_idel_down_all | - dbg_idel_up_dqs | dbg_idel_down_dqs; - dlyinc_dqs[x] <= dbg_idel_up_all | dbg_idel_up_dqs; - end - end else begin - dlyce_dqs <= 'b0; - dlyce_dqs[dbg_sel_idel_dqs] <= dbg_idel_up_dqs | - dbg_idel_down_dqs; - dlyinc_dqs[dbg_sel_idel_dqs] <= dbg_idel_up_dqs; - end - end - end - end - - // GATE synchronization is handled directly by Stage 4 calibration FSM - always @(posedge clkdiv) - if (rstdiv) begin - dlyrst_gate <= {DQS_WIDTH{1'b1}}; - dlyce_gate <= {DQS_WIDTH{1'b0}}; - dlyinc_gate <= {DQS_WIDTH{1'b0}}; - end else begin - dlyrst_gate <= {DQS_WIDTH{1'b0}}; - dlyce_gate <= {DQS_WIDTH{1'b0}}; - dlyinc_gate <= {DQS_WIDTH{1'b0}}; - - if (cal4_dlyrst_gate) begin - if (SIM_ONLY == 0) - dlyrst_gate[count_gate] <= 1'b1; - else - for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_gate_sim_dly_rst - dlyrst_gate[i] <= 1'b1; - end - end - - if (cal4_dlyce_gate) begin - if (SIM_ONLY == 0) begin - dlyce_gate[count_gate] <= 1'b1; - dlyinc_gate[count_gate] <= cal4_dlyinc_gate; - end else begin - // if simulation, then calibrate only first gate - for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_gate_sim_dly - dlyce_gate[i] <= 1'b1; - dlyinc_gate[i] <= cal4_dlyinc_gate; - end - end - end else if (DEBUG_EN != 0) begin - // DEBUG: allow user to vary IDELAY tap settings - if (dbg_idel_up_all || dbg_idel_down_all || - dbg_sel_all_idel_gate) begin - for (x = 0; x < DQS_WIDTH; x = x + 1) begin: loop_dly_inc_gate - dlyce_gate[x] <= dbg_idel_up_all | dbg_idel_down_all | - dbg_idel_up_gate | dbg_idel_down_gate; - dlyinc_gate[x] <= dbg_idel_up_all | dbg_idel_up_gate; - end - end else begin - dlyce_gate <= {DQS_WIDTH{1'b0}}; - dlyce_gate[dbg_sel_idel_gate] <= dbg_idel_up_gate | - dbg_idel_down_gate; - dlyinc_gate[dbg_sel_idel_gate] <= dbg_idel_up_gate; - end - end - end - - //*************************************************************************** - // signal to tell calibration state machines to wait and give IDELAY time to - // settle after it's value is changed (both time for IDELAY chain to settle, - // and for settled output to propagate through ISERDES). For general use: use - // for any calibration state machines that modify any IDELAY. - // Should give at least enough time for IDELAY output to settle (technically - // for V5, this should be "glitchless" when IDELAY taps are changed, so don't - // need any time here), and also time for new data to propagate through both - // ISERDES and the "RDD" MUX + associated pipelining - // For now, give very "generous" delay - doesn't really matter since only - // needed during calibration - //*************************************************************************** - - // determine if calibration polarity has changed - always @(posedge clkdiv) - cal2_rd_data_sel_r <= cal2_rd_data_sel; - - assign cal2_rd_data_sel_edge = |(cal2_rd_data_sel ^ cal2_rd_data_sel_r); - - // combine requests to modify any of the IDELAYs into one. Also when second - // stage capture "edge" polarity is changed (IDELAY isn't changed in this - // case, but use the same counter to stall cal logic) - assign dlyce_or = cal1_dlyce_dq | - cal2_dlyce_dqs | - cal2_rd_data_sel_edge | - cal4_dlyce_gate | - cal4_dlyrst_gate; - - // SYN_NOTE: Can later recode to avoid combinational path - assign idel_set_wait = dlyce_or || (idel_set_cnt != IDEL_SET_VAL); - - always @(posedge clkdiv) - if (rstdiv) - idel_set_cnt <= 4'b0000; - else if (dlyce_or) - idel_set_cnt <= 4'b0000; - else if (idel_set_cnt != IDEL_SET_VAL) - idel_set_cnt <= idel_set_cnt + 1; - - // generate request to PHY_INIT logic to issue auto-refresh - // used by certain states to force prech/auto-refresh part way through - // calibration to avoid a tRAS violation (which will happen if that - // stage of calibration lasts long enough). This signal must meet the - // following requirements: (1) only transition from 0->1 when the refresh - // request is needed, (2) stay at 1 and only transition 1->0 when - // CALIB_REF_DONE is asserted - always @(posedge clkdiv) - if (rstdiv) - calib_ref_req <= 1'b0; - else - calib_ref_req <= cal1_ref_req | cal2_ref_req | cal4_ref_req; - - // stage 1 calibration requests auto-refresh every 4 bits - generate - if (DQ_BITS < 2) begin: gen_cal1_refresh_dq_lte4 - assign cal1_refresh = 1'b0; - end else begin: gen_cal1_refresh_dq_gt4 - assign cal1_refresh = (next_count_dq[1:0] == 2'b00); - end - endgenerate - - //*************************************************************************** - // First stage calibration: DQ-DQS - // Definitions: - // edge: detected when varying IDELAY, and current capture data != prev - // capture data - // valid bit window: detected when current capture data == prev capture - // data for more than half the bit time - // starting conditions for DQS-DQ phase: - // case 1: when DQS starts somewhere in rising edge bit window, or - // on the right edge of the rising bit window. - // case 2: when DQS starts somewhere in falling edge bit window, or - // on the right edge of the falling bit window. - // Algorithm Description: - // 1. Increment DQ IDELAY until we find an edge. - // 2. While we're finding the first edge, note whether a valid bit window - // has been detected before we found an edge. If so, then figure out if - // this is the rising or falling bit window. If rising, then our starting - // DQS-DQ phase is case 1. If falling, then it's case 2. If don't detect - // a valid bit window, then we must have started on the edge of a window. - // Need to wait until later on to decide which case we are. - // - Store FIRST_EDGE IDELAY value - // 3. Now look for second edge. - // 4. While we're finding the second edge, note whether valid bit window - // is detected. If so, then use to, along with results from (2) to figure - // out what the starting case is. If in rising bit window, then we're in - // case 2. If falling, then case 1. - // - Store SECOND_EDGE IDELAY value - // NOTES: - // a. Finding two edges allows us to calculate the bit time (although - // not the "same" bit time polarity - need to investigate this - // more). - // b. If we run out of taps looking for the second edge, then the bit - // time must be too long (>= 2.5ns, and DQS-DQ starting phase must be - // case 1). - // 5. Calculate absolute amount to delay DQ as: - // If second edge found, and case 1: - // - DQ_IDELAY = FIRST_EDGE - 0.5*(SECOND_EDGE - FIRST_EDGE) - // If second edge found, and case 2: - // - DQ_IDELAY = SECOND_EDGE - 0.5*(SECOND_EDGE - FIRST_EDGE) - // If second edge not found, then need to make an approximation on - // how much to shift by (should be okay, because we have more timing - // margin): - // - DQ_IDELAY = FIRST_EDGE - 0.5 * (bit_time) - // NOTE: Does this account for either case 1 or case 2????? - // NOTE: It's also possible even when we find the second edge, that - // to instead just use half the bit time to subtract from either - // FIRST or SECOND_EDGE. Finding the actual bit time (which is - // what (SECOND_EDGE - FIRST_EDGE) is, is slightly more accurate, - // since it takes into account duty cycle distortion. - // 6. Repeat for each DQ in current DQS set. - //*************************************************************************** - - //***************************************************************** - // for first stage calibration - used for checking if DQS is aligned to the - // particular DQ, such that we're in the data valid window. Basically, this - // is one giant MUX. - // = [falling data, rising data] - // = [0, 1] = rising DQS aligned in proper (rising edge) bit window - // = [1, 0] = rising DQS aligned in wrong (falling edge) bit window - // = [0, 0], or [1,1] = in uncertain region between windows - //***************************************************************** - - // SYN_NOTE: May have to split this up into multiple levels - MUX can get - // very wide - as wide as the data bus width - always @(posedge clkdiv) - cal1_data_chk_r <= {rd_data_fall_1x_r[next_count_dq], - rd_data_rise_1x_r[next_count_dq]}; - - //***************************************************************** - // determine when an edge has occurred - when either the current value - // is different from the previous latched value or when the DATA_CHK - // outputs are the same (rare, but indicates that we're at an edge) - // This is only valid when the IDELAY output and propagation of the - // data through the capture flops has had a chance to settle out. - //***************************************************************** - - // write CAL1_DETECT_EDGE and CAL1_DETECT_STABLE in such a way that - // if X's are captured on the bus during functional simulation, that - // the logic will register this as an edge detected. Do this to allow - // use of this HDL with Denali memory models (Denali models drive DQ - // to X's on both edges of the data valid window to simulate jitter) - // This is only done for functional simulation purposes. **Should not** - // make the final synthesized logic more complicated, but it does make - // the HDL harder to understand b/c we have to "phrase" the logic - // slightly differently than when not worrying about X's - always @(*) begin - // no edge found if: (1) we have recorded prev edge, and rise - // data == fall data, (2) we haven't yet recorded prev edge, but - // rise/fall data is equal to either [0,1] or [1,0] (i.e. rise/fall - // data isn't either X's, or [0,0] or [1,1], which indicates we're - // in the middle of an edge, since normally rise != fall data for stg1) - if ((cal1_data_chk_last_valid && - (cal1_data_chk_r == cal1_data_chk_last)) || - (!cal1_data_chk_last_valid && - ((cal1_data_chk_r == 2'b01) || (cal1_data_chk_r == 2'b10)))) - cal1_detect_edge = 1'b0; - else - cal1_detect_edge = 1'b1; - end - - always @(*) begin - // assert if we've found a region where data valid window is stable - // over consecutive IDELAY taps, and either rise/fall = [1,0], or [0,1] - if ((cal1_data_chk_last_valid && - (cal1_data_chk_r == cal1_data_chk_last)) && - ((cal1_data_chk_r == 2'b01) || (cal1_data_chk_r == 2'b10))) - cal1_detect_stable = 1'b1; - else - cal1_detect_stable = 1'b0; - end - - //***************************************************************** - // Find valid window: keep track of how long we've been in the same data - // window. If it's been long enough, then declare that we've found a valid - // window. Also returns whether we found a rising or falling window (only - // valid when found_window is asserted) - //***************************************************************** - - always @(posedge clkdiv) begin - if (cal1_state == CAL1_INIT) begin - cal1_window_cnt <= 4'b0000; - cal1_found_window <= 1'b0; - cal1_found_rising <= 1'bx; - end else if (!cal1_data_chk_last_valid) begin - // if we haven't stored a previous value of CAL1_DATA_CHK (or it got - // invalidated because we detected an edge, and are now looking for the - // second edge), then make sure FOUND_WINDOW deasserted on following - // clock edge (to avoid finding a false window immediately after finding - // an edge). Note that because of jitter, it's possible to not find an - // edge at the end of the IDELAY increment settling time, but to find an - // edge on the next clock cycle (e.g. during CAL1_FIND_FIRST_EDGE) - cal1_window_cnt <= 4'b0000; - cal1_found_window <= 1'b0; - cal1_found_rising <= 1'bx; - end else if (((cal1_state == CAL1_FIRST_EDGE_IDEL_WAIT) || - (cal1_state == CAL1_SECOND_EDGE_IDEL_WAIT)) && - !idel_set_wait) begin - // while finding the first and second edges, see if we can detect a - // stable bit window (occurs over MIN_WIN_SIZE number of taps). If - // so, then we're away from an edge, and can conclusively determine the - // starting DQS-DQ phase. - if (cal1_detect_stable) begin - cal1_window_cnt <= cal1_window_cnt + 1; - if (cal1_window_cnt == MIN_WIN_SIZE-1) begin - cal1_found_window <= 1'b1; - if (cal1_data_chk_r == 2'b01) - cal1_found_rising <= 1'b1; - else - cal1_found_rising <= 1'b0; - end - end else begin - // otherwise, we're not in a data valid window, reset the window - // counter, and indicate we're not currently in window. This should - // happen by design at least once after finding the first edge. - cal1_window_cnt <= 4'b0000; - cal1_found_window <= 1'b0; - cal1_found_rising <= 1'bx; - end - end - end - - //***************************************************************** - // keep track of edge tap counts found, and whether we've - // incremented to the maximum number of taps allowed - //***************************************************************** - - always @(posedge clkdiv) - if (cal1_state == CAL1_INIT) begin - cal1_idel_tap_limit_hit <= 1'b0; - cal1_idel_tap_cnt <= 6'b000000; - end else if (cal1_dlyce_dq) begin - if (cal1_dlyinc_dq) begin - cal1_idel_tap_cnt <= cal1_idel_tap_cnt + 1; - cal1_idel_tap_limit_hit <= (cal1_idel_tap_cnt == 6'b111110); - end else begin - cal1_idel_tap_cnt <= cal1_idel_tap_cnt - 1; - cal1_idel_tap_limit_hit <= 1'b0; - end - end - - //***************************************************************** - // Pipeline for better timing - amount to decrement by if second - // edge not found - //***************************************************************** - // if only one edge found (possible for low frequencies), then: - // 1. Assume starting DQS-DQ phase has DQS in DQ window (aka "case 1") - // 2. We have to decrement by (63 - first_edge_tap_cnt) + (BIT_TIME_TAPS/2) - // (i.e. decrement by 63-first_edge_tap_cnt to get to right edge of - // DQ window. Then decrement again by (BIT_TIME_TAPS/2) to get to center - // of DQ window. - // 3. Clamp the above value at 63 to ensure we don't underflow IDELAY - // (note: clamping happens in the CAL1 state machine) - always @(posedge clkdiv) - cal1_low_freq_idel_dec - <= (7'b0111111 - {1'b0, cal1_first_edge_tap_cnt}) + - (BIT_TIME_TAPS/2); - - //***************************************************************** - // Keep track of max taps used during stage 1, use this to limit - // the number of taps that can be used in stage 2 - //***************************************************************** - - always @(posedge clkdiv) - if (rstdiv) begin - cal1_idel_max_tap <= 6'b000000; - cal1_idel_max_tap_we <= 1'b0; - end else begin - // pipeline latch enable for CAL1_IDEL_MAX_TAP - we have plenty - // of time, tap count gets updated, then dead cycles waiting for - // IDELAY output to settle - cal1_idel_max_tap_we <= (cal1_idel_max_tap < cal1_idel_tap_cnt); - // record maximum # of taps used for stg 1 cal - if ((cal1_state == CAL1_DONE) && cal1_idel_max_tap_we) - cal1_idel_max_tap <= cal1_idel_tap_cnt; - end - - //***************************************************************** - - always @(posedge clkdiv) - if (rstdiv) begin - calib_done[0] <= 1'b0; - calib_done_tmp[0] <= 1'bx; - calib_err[0] <= 1'b0; - count_dq <= {DQ_BITS{1'b0}}; - next_count_dq <= {DQ_BITS{1'b0}}; - cal1_bit_time_tap_cnt <= 6'bxxxxxx; - cal1_data_chk_last <= 2'bxx; - cal1_data_chk_last_valid <= 1'bx; - cal1_dlyce_dq <= 1'b0; - cal1_dlyinc_dq <= 1'b0; - cal1_dqs_dq_init_phase <= 1'bx; - cal1_first_edge_done <= 1'bx; - cal1_found_second_edge <= 1'bx; - cal1_first_edge_tap_cnt <= 6'bxxxxxx; - cal1_idel_dec_cnt <= 7'bxxxxxxx; - cal1_idel_inc_cnt <= 6'bxxxxxx; - cal1_ref_req <= 1'b0; - cal1_state <= CAL1_IDLE; - end else begin - // default values for all "pulse" outputs - cal1_ref_req <= 1'b0; - cal1_dlyce_dq <= 1'b0; - cal1_dlyinc_dq <= 1'b0; - - case (cal1_state) - CAL1_IDLE: begin - count_dq <= {DQ_BITS{1'b0}}; - next_count_dq <= {DQ_BITS{1'b0}}; - if (calib_start[0]) begin - calib_done[0] <= 1'b0; - calib_done_tmp[0] <= 1'b0; - cal1_state <= CAL1_INIT; - end - end - - CAL1_INIT: begin - cal1_data_chk_last_valid <= 1'b0; - cal1_found_second_edge <= 1'b0; - cal1_dqs_dq_init_phase <= 1'b0; - cal1_idel_inc_cnt <= 6'b000000; - cal1_state <= CAL1_INC_IDEL; - end - - // increment DQ IDELAY so that either: (1) DQS starts somewhere in - // first rising DQ window, or (2) DQS starts in first falling DQ - // window. The amount to shift is frequency dependent (and is either - // precalculated by MIG or possibly adjusted by the user) - CAL1_INC_IDEL: - if ((cal1_idel_inc_cnt == DQ_IDEL_INIT) && !idel_set_wait) begin - cal1_state <= CAL1_FIND_FIRST_EDGE; - end else if (cal1_idel_inc_cnt != DQ_IDEL_INIT) begin - cal1_idel_inc_cnt <= cal1_idel_inc_cnt + 1; - cal1_dlyce_dq <= 1'b1; - cal1_dlyinc_dq <= 1'b1; - end - - // look for first edge - CAL1_FIND_FIRST_EDGE: begin - // Determine DQS-DQ phase if we can detect enough of a valid window - if (cal1_found_window) - cal1_dqs_dq_init_phase <= ~cal1_found_rising; - // find first edge - if found then record position - if (cal1_detect_edge) begin - cal1_state <= CAL1_FOUND_FIRST_EDGE_WAIT; - cal1_first_edge_done <= 1'b0; - cal1_first_edge_tap_cnt <= cal1_idel_tap_cnt; - cal1_data_chk_last_valid <= 1'b0; - end else begin - // otherwise, store the current value of DATA_CHK, increment - // DQ IDELAY, and compare again - cal1_state <= CAL1_FIRST_EDGE_IDEL_WAIT; - cal1_data_chk_last <= cal1_data_chk_r; - // avoid comparing against DATA_CHK_LAST for previous iteration - cal1_data_chk_last_valid <= 1'b1; - cal1_dlyce_dq <= 1'b1; - cal1_dlyinc_dq <= 1'b1; - end - end - - // wait for DQ IDELAY to settle - CAL1_FIRST_EDGE_IDEL_WAIT: - if (!idel_set_wait) - cal1_state <= CAL1_FIND_FIRST_EDGE; - - // delay state between finding first edge and looking for second - // edge. Necessary in order to invalidate CAL1_FOUND_WINDOW before - // starting to look for second edge - CAL1_FOUND_FIRST_EDGE_WAIT: - cal1_state <= CAL1_FIND_SECOND_EDGE; - - // Try and find second edge - CAL1_FIND_SECOND_EDGE: begin - // When looking for 2nd edge, first make sure data stabilized (by - // detecting valid data window) - needed to avoid false edges - if (cal1_found_window) begin - cal1_first_edge_done <= 1'b1; - cal1_dqs_dq_init_phase <= cal1_found_rising; - end - // exit if run out of taps to increment - if (cal1_idel_tap_limit_hit) - cal1_state <= CAL1_CALC_IDEL; - else begin - // found second edge, record the current edge count - if (cal1_first_edge_done && cal1_detect_edge) begin - cal1_state <= CAL1_CALC_IDEL; - cal1_found_second_edge <= 1'b1; - cal1_bit_time_tap_cnt <= cal1_idel_tap_cnt - - cal1_first_edge_tap_cnt + 1; - end else begin - cal1_state <= CAL1_SECOND_EDGE_IDEL_WAIT; - cal1_data_chk_last <= cal1_data_chk_r; - cal1_data_chk_last_valid <= 1'b1; - cal1_dlyce_dq <= 1'b1; - cal1_dlyinc_dq <= 1'b1; - end - end - end - - // wait for DQ IDELAY to settle, then store ISERDES output - CAL1_SECOND_EDGE_IDEL_WAIT: - if (!idel_set_wait) - cal1_state <= CAL1_FIND_SECOND_EDGE; - - // pipeline delay state to calculate amount to decrement DQ IDELAY - // NOTE: We're calculating the amount to decrement by, not the - // absolute setting for DQ IDELAY - CAL1_CALC_IDEL: begin - // if two edges found - if (cal1_found_second_edge) - // case 1: DQS was in DQ window to start with. First edge found - // corresponds to left edge of DQ rising window. Backup by 1.5*BT - // NOTE: In this particular case, it is possible to decrement - // "below 0" in the case where DQS delay is less than 0.5*BT, - // need to limit decrement to prevent IDELAY tap underflow - if (!cal1_dqs_dq_init_phase) - cal1_idel_dec_cnt <= {1'b0, cal1_bit_time_tap_cnt} + - {1'b0, (cal1_bit_time_tap_cnt >> 1)}; - // case 2: DQS was in wrong DQ window (in DQ falling window). - // First edge found is right edge of DQ rising window. Second - // edge is left edge of DQ rising window. Backup by 0.5*BT - else - cal1_idel_dec_cnt <= {1'b0, (cal1_bit_time_tap_cnt >> 1)}; - // if only one edge found - assume will always be case 1 - DQS in - // DQS window. Case 2 only possible if path delay on DQS > 5ns - else - cal1_idel_dec_cnt <= cal1_low_freq_idel_dec; - cal1_state <= CAL1_DEC_IDEL; - end - - // decrement DQ IDELAY for final adjustment - CAL1_DEC_IDEL: - // once adjustment is complete, we're done with calibration for - // this DQ, now return to IDLE state and repeat for next DQ - // Add underflow protection for case of 2 edges found and DQS - // starting in DQ window (see comments for above state) - note we - // have to take into account delayed value of CAL1_IDEL_TAP_CNT - - // gets updated one clock cycle after CAL1_DLYCE/INC_DQ - if ((cal1_idel_dec_cnt == 7'b0000000) || - (cal1_dlyce_dq && (cal1_idel_tap_cnt == 6'b000001))) begin - cal1_state <= CAL1_DONE; - // stop when all DQ's calibrated, or DQ[0] cal'ed (for sim) - if ((count_dq == DQ_WIDTH-1) || (SIM_ONLY != 0)) - calib_done_tmp[0] <= 1'b1; - else - // need for VHDL simulation to prevent out-of-index error - next_count_dq <= count_dq + 1; - end else begin - // keep decrementing until final tap count reached - cal1_idel_dec_cnt <= cal1_idel_dec_cnt - 1; - cal1_dlyce_dq <= 1'b1; - cal1_dlyinc_dq <= 1'b0; - end - - // delay state to allow count_dq and DATA_CHK to point to the next - // DQ bit (allows us to potentially begin checking for an edge on - // next DQ right away). - CAL1_DONE: - if (!idel_set_wait) begin - count_dq <= next_count_dq; - if (calib_done_tmp[0]) begin - calib_done[0] <= 1'b1; - cal1_state <= CAL1_IDLE; - end else begin - // request auto-refresh after every 8-bits calibrated to - // avoid tRAS violation - if (cal1_refresh) begin - cal1_ref_req <= 1'b1; - if (calib_ref_done) - cal1_state <= CAL1_INIT; - end else - // if no need this time for refresh, proceed to next bit - cal1_state <= CAL1_INIT; - end - end - endcase - end - - //*************************************************************************** - // Second stage calibration: DQS-FPGA Clock - // Algorithm Description: - // 1. Assumes a training pattern that will produce a pattern oscillating at - // half the core clock frequency each on rise and fall outputs, and such - // that rise and fall outputs are 180 degrees out of phase from each - // other. Note that since the calibration logic runs at half the speed - // of the interface, expect that data sampled with the slow clock always - // to be constant (either always = 1, or = 0, and rise data != fall data) - // unless we cross the edge of the data valid window - // 2. Start by setting RD_DATA_SEL = 0. This selects the rising capture data - // sync'ed to rising edge of core clock, and falling edge data sync'ed - // to falling edge of core clock - // 3. Start looking for an edge. An edge is defined as either: (1) a - // change in capture value or (2) an invalid capture value (e.g. rising - // data != falling data for that same clock cycle). - // 4. If an edge is found, go to step (6). If edge hasn't been found, then - // set RD_DATA_SEL = 1, and try again. - // 5. If no edge is found, then increment IDELAY and return to step (3) - // 6. If an edge if found, then invert RD_DATA_SEL - this shifts the - // capture point 180 degrees from the edge of the window (minus duty - // cycle distortion, delay skew between rising/falling edge capture - // paths, etc.) - // 7. If no edge is found by CAL2_IDEL_TAP_LIMIT (= 63 - # taps used for - // stage 1 calibration), then decrement IDELAY (without reinverting - // RD_DATA_SEL) by CAL2_IDEL_TAP_LIMIT/2. This guarantees we at least - // have CAL2_IDEL_TAP_LIMIT/2 of slack both before and after the - // capture point (not optimal, but best we can do not having found an - // of the window). This happens only for very low frequencies. - // 8. Repeat for each DQS group. - // NOTE: Step 6 is not optimal. A better (and perhaps more complicated) - // algorithm might be to find both edges of the data valid window (using - // the same polarity of RD_DATA_SEL), and then decrement to the midpoint. - //*************************************************************************** - - // RD_DATA_SEL should be tagged with FROM-TO (multi-cycle) constraint in - // UCF file to relax timing. This net is "pseudo-static" (after value is - // changed, FSM waits number of cycles before using the output). - // Note that we are adding one clock cycle of delay (to isolate it from - // the other logic CAL2_RD_DATA_SEL feeds), make sure FSM waits long - // enough to compensate (by default it does, it waits a few cycles more - // than minimum # of clock cycles) - genvar rd_i; - generate - for (rd_i = 0; rd_i < DQS_WIDTH; rd_i = rd_i+1) begin: gen_rd_data_sel - FDRSE u_ff_rd_data_sel - ( - .Q (rd_data_sel[rd_i]), - .C (clkdiv), - .CE (1'b1), - .D (cal2_rd_data_sel[rd_i]), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - end - endgenerate - - //***************************************************************** - // Max number of taps used for stg2 cal dependent on number of taps - // used for stg1 (give priority to stg1 cal - let it use as many - // taps as it needs - the remainder of the IDELAY taps can be used - // by stg2) - //***************************************************************** - - always @(posedge clkdiv) - cal2_idel_tap_limit <= 6'b111111 - cal1_idel_max_tap; - - //***************************************************************** - // second stage calibration uses readback pattern of "1100" (i.e. - // 1st rising = 1, 1st falling = 1, 2nd rising = 0, 2nd falling = 0) - // only look at the first bit of each DQS group - //***************************************************************** - - // deasserted when captured data has changed since IDELAY was - // incremented, or when we're right on the edge (i.e. rise data = - // fall data). - assign cal2_detect_edge = - ((((rdd_rise_q1 != cal2_rd_data_rise_last_pos) || - (rdd_fall_q1 != cal2_rd_data_fall_last_pos)) && - cal2_rd_data_last_valid_pos && (!cal2_curr_sel)) || - (((rdd_rise_q1 != cal2_rd_data_rise_last_neg) || - (rdd_fall_q1 != cal2_rd_data_fall_last_neg)) && - cal2_rd_data_last_valid_neg && (cal2_curr_sel)) || - (rdd_rise_q1 != rdd_fall_q1)); - - //***************************************************************** - // keep track of edge tap counts found, and whether we've - // incremented to the maximum number of taps allowed - // NOTE: Assume stage 2 cal always increments the tap count (never - // decrements) when searching for edge of the data valid window - //***************************************************************** - - always @(posedge clkdiv) - if (cal2_state == CAL2_INIT) begin - cal2_idel_tap_limit_hit <= 1'b0; - cal2_idel_tap_cnt <= 6'b000000; - end else if (cal2_dlyce_dqs) begin - cal2_idel_tap_cnt <= cal2_idel_tap_cnt + 1; - cal2_idel_tap_limit_hit <= (cal2_idel_tap_cnt == - cal2_idel_tap_limit - 1); - end - - //***************************************************************** - - always @(posedge clkdiv) - if (rstdiv) begin - calib_done[1] <= 1'b0; - calib_done_tmp[1] <= 1'bx; - calib_err[1] <= 1'b0; - count_dqs <= 'b0; - next_count_dqs <= 'b0; - cal2_dlyce_dqs <= 1'b0; - cal2_dlyinc_dqs <= 1'b0; - cal2_idel_dec_cnt <= 6'bxxxxxx; - cal2_rd_data_last_valid_neg <= 1'bx; - cal2_rd_data_last_valid_pos <= 1'bx; - cal2_rd_data_sel <= 'b0; - cal2_ref_req <= 1'b0; - cal2_state <= CAL2_IDLE; - end else begin - cal2_ref_req <= 1'b0; - cal2_dlyce_dqs <= 1'b0; - cal2_dlyinc_dqs <= 1'b0; - - case (cal2_state) - CAL2_IDLE: begin - count_dqs <= 'b0; - next_count_dqs <= 'b0; - if (calib_start[1]) begin - cal2_rd_data_sel <= {DQS_WIDTH{1'b0}}; - calib_done[1] <= 1'b0; - calib_done_tmp[1] <= 1'b0; - cal2_state <= CAL2_INIT; - end - end - - // Pass through this state every time we calibrate a new DQS group - CAL2_INIT: begin - cal2_curr_sel <= 1'b0; - cal2_rd_data_last_valid_neg <= 1'b0; - cal2_rd_data_last_valid_pos <= 1'b0; - cal2_state <= CAL2_INIT_IDEL_WAIT; - end - - // Stall state only used if calibration run more than once. Can take - // this state out if design never runs calibration more than once. - // We need this state to give time for MUX'ed data to settle after - // resetting RD_DATA_SEL - CAL2_INIT_IDEL_WAIT: - if (!idel_set_wait) - cal2_state <= CAL2_FIND_EDGE_POS; - - // Look for an edge - first check "positive-edge" stage 2 capture - CAL2_FIND_EDGE_POS: begin - // if found an edge, then switch to the opposite edge stage 2 - // capture and we're done - no need to decrement the tap count, - // since switching to the opposite edge will shift the capture - // point by 180 degrees - if (cal2_detect_edge) begin - cal2_curr_sel <= 1'b1; - cal2_state <= CAL2_DONE; - // set all DQS groups to be the same for simulation - if (SIM_ONLY != 0) - cal2_rd_data_sel <= {DQS_WIDTH{1'b1}}; - else - cal2_rd_data_sel[count_dqs] <= 1'b1; - if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) - calib_done_tmp[1] <= 1'b1; - else - // MIG 2.1: Fix for simulation out-of-bounds error when - // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) - next_count_dqs <= count_dqs + 1; - end else begin - // otherwise, invert polarity of stage 2 capture and look for - // an edge with opposite capture clock polarity - cal2_curr_sel <= 1'b1; - cal2_rd_data_sel[count_dqs] <= 1'b1; - cal2_state <= CAL2_FIND_EDGE_IDEL_WAIT_POS; - cal2_rd_data_rise_last_pos <= rdd_rise_q1; - cal2_rd_data_fall_last_pos <= rdd_fall_q1; - cal2_rd_data_last_valid_pos <= 1'b1; - end - end - - // Give time to switch from positive-edge to negative-edge second - // stage capture (need time for data to filter though pipe stages) - CAL2_FIND_EDGE_IDEL_WAIT_POS: - if (!idel_set_wait) - cal2_state <= CAL2_FIND_EDGE_NEG; - - // Look for an edge - check "negative-edge" stage 2 capture - CAL2_FIND_EDGE_NEG: - if (cal2_detect_edge) begin - cal2_curr_sel <= 1'b0; - cal2_state <= CAL2_DONE; - // set all DQS groups to be the same for simulation - if (SIM_ONLY != 0) - cal2_rd_data_sel <= {DQS_WIDTH{1'b0}}; - else - cal2_rd_data_sel[count_dqs] <= 1'b0; - if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) - calib_done_tmp[1] <= 1'b1; - else - // MIG 2.1: Fix for simulation out-of-bounds error when - // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) - next_count_dqs <= count_dqs + 1; - end else if (cal2_idel_tap_limit_hit) begin - // otherwise, if we've run out of taps, then immediately - // backoff by half # of taps used - that's our best estimate - // for optimal calibration point. Doesn't matter whether which - // polarity we're using for capture (we don't know which one is - // best to use) - cal2_idel_dec_cnt <= {1'b0, cal2_idel_tap_limit[5:1]}; - cal2_state <= CAL2_DEC_IDEL; - if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) - calib_done_tmp[1] <= 1'b1; - else - // MIG 2.1: Fix for simulation out-of-bounds error when - // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) - next_count_dqs <= count_dqs + 1; - end else begin - // otherwise, increment IDELAY, and start looking for edge again - cal2_curr_sel <= 1'b0; - cal2_rd_data_sel[count_dqs] <= 1'b0; - cal2_state <= CAL2_FIND_EDGE_IDEL_WAIT_NEG; - cal2_rd_data_rise_last_neg <= rdd_rise_q1; - cal2_rd_data_fall_last_neg <= rdd_fall_q1; - cal2_rd_data_last_valid_neg <= 1'b1; - cal2_dlyce_dqs <= 1'b1; - cal2_dlyinc_dqs <= 1'b1; - end - - CAL2_FIND_EDGE_IDEL_WAIT_NEG: - if (!idel_set_wait) - cal2_state <= CAL2_FIND_EDGE_POS; - - // if no edge found, then decrement by half # of taps used - CAL2_DEC_IDEL: begin - if (cal2_idel_dec_cnt == 6'b000000) - cal2_state <= CAL2_DONE; - else begin - cal2_idel_dec_cnt <= cal2_idel_dec_cnt - 1; - cal2_dlyce_dqs <= 1'b1; - cal2_dlyinc_dqs <= 1'b0; - end - end - - // delay state to allow count_dqs and ISERDES data to point to next - // DQ bit (DQS group) before going to INIT - CAL2_DONE: - if (!idel_set_wait) begin - count_dqs <= next_count_dqs; - if (calib_done_tmp[1]) begin - calib_done[1] <= 1'b1; - cal2_state <= CAL2_IDLE; - end else begin - // request auto-refresh after every DQS group calibrated to - // avoid tRAS violation - cal2_ref_req <= 1'b1; - if (calib_ref_done) - cal2_state <= CAL2_INIT; - end - end - endcase - end - - //*************************************************************************** - // Stage 3 calibration: Read Enable - // Description: - // read enable calibration determines the "round-trip" time (in # of CLK0 - // cycles) between when a read command is issued by the controller, and - // when the corresponding read data is synchronized by into the CLK0 domain - // this is a long delay chain to delay read enable signal from controller/ - // initialization logic (i.e. this is used for both initialization and - // during normal controller operation). Stage 3 calibration logic decides - // which delayed version is appropriate to use (which is affected by the - // round trip delay of DQ/DQS) as a "valid" signal to tell rest of logic - // when the captured data output from ISERDES is valid. - //*************************************************************************** - - //***************************************************************** - // Delay chains: Use shift registers - // Two sets of delay chains are used: - // 1. One to delay RDEN from PHY_INIT module for calibration - // purposes (delay required for RDEN for calibration is different - // than during normal operation) - // 2. One per DQS group to delay RDEN from controller for normal - // operation - the value to delay for each DQS group can be different - // as is determined during calibration - //***************************************************************** - - //***************************************************************** - // First delay chain, use only for calibration - // input = asserted on rising edge of RDEN from PHY_INIT module - //***************************************************************** - - always @(posedge clk) begin - ctrl_rden_r <= ctrl_rden; - phy_init_rden_r <= phy_init_rden; - phy_init_rden_r1 <= phy_init_rden_r; - calib_rden_edge_r <= phy_init_rden_r & ~phy_init_rden_r1; - end - - // Calibration shift register used for both Stage 3 and Stage 4 cal - // (not strictly necessary for stage 4, but use as an additional check - // to make sure we're checking for correct data on the right clock cycle) - always @(posedge clkdiv) - if (!calib_done[2]) - calib_rden_srl_a <= cal3_rden_srl_a; - else - calib_rden_srl_a <= cal4_rden_srl_a; - - // Flops for targetting of multi-cycle path in UCF - genvar cal_rden_ff_i; - generate - for (cal_rden_ff_i = 0; cal_rden_ff_i < 5; - cal_rden_ff_i = cal_rden_ff_i+1) begin: gen_cal_rden_dly - FDRSE u_ff_cal_rden_dly - ( - .Q (calib_rden_srl_a_r[cal_rden_ff_i]), - .C (clkdiv), - .CE (1'b1), - .D (calib_rden_srl_a[cal_rden_ff_i]), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - end - endgenerate - - SRLC32E u_calib_rden_srl - ( - .Q (calib_rden_srl_out), - .Q31 (), - .A (calib_rden_srl_a_r), - .CE (1'b1), - .CLK (clk), - .D (calib_rden_edge_r) - ); - - FDRSE u_calib_rden_srl_out_r - ( - .Q (calib_rden_srl_out_r), - .C (clk), - .CE (1'b1), - .D (calib_rden_srl_out), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve = 1 */; - - // convert to CLKDIV domain. Two version are generated because we need - // to be able to tell exactly which fast (clk) clock cycle the read - // enable was asserted in. Only one of CALIB_DATA_VALID or - // CALIB_DATA_VALID_STGD will be asserted for any given shift value - always @(posedge clk) - calib_rden_srl_out_r1 <= calib_rden_srl_out_r; - - always @(posedge clkdiv) begin - calib_rden_valid <= calib_rden_srl_out_r; - calib_rden_valid_stgd <= calib_rden_srl_out_r1; - end - - //***************************************************************** - // Second set of delays chain, use for normal reads - // input = RDEN from controller - //***************************************************************** - - // Flops for targetting of multi-cycle path in UCF - genvar rden_ff_i; - generate - for (rden_ff_i = 0; rden_ff_i < 5*DQS_WIDTH; - rden_ff_i = rden_ff_i+1) begin: gen_rden_dly - FDRSE u_ff_rden_dly - ( - .Q (rden_dly_r[rden_ff_i]), - .C (clkdiv), - .CE (1'b1), - .D (rden_dly[rden_ff_i]), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - end - endgenerate - - // NOTE: Comment this section explaining purpose of SRL's - genvar rden_i; - generate - for (rden_i = 0; rden_i < DQS_WIDTH; rden_i = rden_i + 1) begin: gen_rden - SRLC32E u_rden_srl - ( - .Q (rden_srl_out[rden_i]), - .Q31 (), - .A ({rden_dly_r[(rden_i*5)+4], - rden_dly_r[(rden_i*5)+3], - rden_dly_r[(rden_i*5)+2], - rden_dly_r[(rden_i*5)+1], - rden_dly_r[(rden_i*5)]}), - .CE (1'b1), - .CLK (clk), - .D (ctrl_rden_r) - ); - FDRSE u_calib_rden_r - ( - .Q (calib_rden[rden_i]), - .C (clk), - .CE (1'b1), - .D (rden_srl_out[rden_i]), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve = 1 */; - end - endgenerate - - //***************************************************************** - // indicates that current received data is the correct pattern. Check both - // rising and falling data for first DQ in each DQS group. Note that - // we're checking using a pipelined version of read data, so need to take - // this inherent delay into account in determining final read valid delay - // Data is written to the memory in the following order (first -> last): - // 0x1, 0xE, 0xE, 0x1, 0x1, 0xE, 0x1, 0xE - // Looking at the two LSb bits, expect data in sequence (in binary): - // bit[0]: 1, 0, 0, 1, 0, 1, 0, 1 - // bit[1]: 0, 1, 1, 0, 1, 0, 1, 0 - // Check for the presence of the first 7 words, and compensate read valid - // delay accordingly. Don't check last falling edge data, it may be - // corrupted by the DQS tri-state glitch at end of read postamble - // (glitch protection not yet active until stage 4 cal) - //***************************************************************** - - always @(posedge clkdiv) begin - rdd_rise_q1_r <= rdd_rise_q1; - rdd_fall_q1_r <= rdd_fall_q1; - rdd_rise_q2_r <= rdd_rise_q2; - rdd_fall_q2_r <= rdd_fall_q2; - rdd_rise_q1_r1 <= rdd_rise_q1_r; - rdd_fall_q1_r1 <= rdd_fall_q1_r; - // MIG 3.3: Added comparison for second bit in DQS group for stage 3 cal - rdd_rise_q1_bit1_r <= rdd_rise_q1_bit1; - rdd_fall_q1_bit1_r <= rdd_fall_q1_bit1; - rdd_rise_q2_bit1_r <= rdd_rise_q2_bit1; - rdd_fall_q2_bit1_r <= rdd_fall_q2_bit1; - rdd_rise_q1_bit1_r1 <= rdd_rise_q1_bit1_r; - rdd_fall_q1_bit1_r1 <= rdd_fall_q1_bit1_r; - end - - always @(posedge clkdiv) begin - // For the following sequence from memory: - // rise[0], fall[0], rise[1], fall[1] - // if data is aligned out of fabric ISERDES: - // RDD_RISE_Q2 = rise[0] - // RDD_FALL_Q2 = fall[0] - // RDD_RISE_Q1 = rise[1] - // RDD_FALL_Q1 = fall[1] - cal3_data_match <= ((rdd_rise_q2_r == 1) && - (rdd_fall_q2_r == 0) && - (rdd_rise_q1_r == 0) && - (rdd_fall_q1_r == 1) && - (rdd_rise_q2 == 0) && - (rdd_fall_q2 == 1) && - (rdd_rise_q1 == 0) && - (rdd_rise_q2_bit1_r == 0) && - (rdd_fall_q2_bit1_r == 1) && - (rdd_rise_q1_bit1_r == 1) && - (rdd_fall_q1_bit1_r == 0) && - (rdd_rise_q2_bit1 == 1) && - (rdd_fall_q2_bit1 == 0) && - (rdd_rise_q1_bit1 == 1)); - - // if data is staggered out of fabric ISERDES: - // RDD_RISE_Q1_R = rise[0] - // RDD_FALL_Q1_R = fall[0] - // RDD_RISE_Q2 = rise[1] - // RDD_FALL_Q2 = fall[1] - cal3_data_match_stgd <= ((rdd_rise_q1_r1 == 1) && - (rdd_fall_q1_r1 == 0) && - (rdd_rise_q2_r == 0) && - (rdd_fall_q2_r == 1) && - (rdd_rise_q1_r == 0) && - (rdd_fall_q1_r == 1) && - (rdd_rise_q2 == 0) && - (rdd_rise_q1_bit1_r1 == 0) && - (rdd_fall_q1_bit1_r1 == 1) && - (rdd_rise_q2_bit1_r == 1) && - (rdd_fall_q2_bit1_r == 0) && - (rdd_rise_q1_bit1_r == 1) && - (rdd_fall_q1_bit1_r == 0) && - (rdd_rise_q2_bit1 == 1)); - end - - assign cal3_rden_dly = cal3_rden_srl_a - CAL3_RDEN_SRL_DLY_DELTA; - assign cal3_data_valid = (calib_rden_valid | calib_rden_valid_stgd); - assign cal3_match_found - = ((calib_rden_valid && cal3_data_match) || - (calib_rden_valid_stgd && cal3_data_match_stgd)); - - // when calibrating, check to see which clock cycle (after the read is - // issued) does the expected data pattern arrive. Record this result - // NOTE: Can add error checking here in case valid data not found on any - // of the available pipeline stages - always @(posedge clkdiv) begin - if (rstdiv) begin - cal3_rden_srl_a <= 5'bxxxxx; - cal3_state <= CAL3_IDLE; - calib_done[2] <= 1'b0; - calib_err_2[0] <= 1'b0; - count_rden <= {DQS_WIDTH{1'b0}}; - rden_dly <= {5*DQS_WIDTH{1'b0}}; - end else begin - - case (cal3_state) - CAL3_IDLE: begin - count_rden <= {DQS_WIDTH{1'b0}}; - if (calib_start[2]) begin - calib_done[2] <= 1'b0; - cal3_state <= CAL3_INIT; - end - end - - CAL3_INIT: begin - cal3_rden_srl_a <= RDEN_BASE_DELAY; - // let SRL pipe clear after loading initial shift value - cal3_state <= CAL3_RDEN_PIPE_CLR_WAIT; - end - - CAL3_DETECT: - if (cal3_data_valid) - // if match found at the correct clock cycle - if (cal3_match_found) begin - - // For simulation, load SRL addresses for all DQS with same value - if (SIM_ONLY != 0) begin - for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_rden_dly - rden_dly[(i*5)] <= cal3_rden_dly[0]; - rden_dly[(i*5)+1] <= cal3_rden_dly[1]; - rden_dly[(i*5)+2] <= cal3_rden_dly[2]; - rden_dly[(i*5)+3] <= cal3_rden_dly[3]; - rden_dly[(i*5)+4] <= cal3_rden_dly[4]; - end - end else begin - rden_dly[(count_rden*5)] <= cal3_rden_dly[0]; - rden_dly[(count_rden*5)+1] <= cal3_rden_dly[1]; - rden_dly[(count_rden*5)+2] <= cal3_rden_dly[2]; - rden_dly[(count_rden*5)+3] <= cal3_rden_dly[3]; - rden_dly[(count_rden*5)+4] <= cal3_rden_dly[4]; - end - - // Use for stage 4 calibration - calib_rden_dly[(count_rden*5)] <= cal3_rden_srl_a[0]; - calib_rden_dly[(count_rden*5)+1] <= cal3_rden_srl_a[1]; - calib_rden_dly[(count_rden*5)+2] <= cal3_rden_srl_a[2]; - calib_rden_dly[(count_rden*5)+3] <= cal3_rden_srl_a[3]; - calib_rden_dly[(count_rden*5)+4] <= cal3_rden_srl_a[4]; - cal3_state <= CAL3_DONE; - end else begin - // If we run out of stages to shift, without finding correct - // result, the stop and assert error - if (cal3_rden_srl_a == 5'b11111) begin - calib_err_2[0] <= 1'b1; - cal3_state <= CAL3_IDLE; - end else begin - // otherwise, increase the shift value and try again - cal3_rden_srl_a <= cal3_rden_srl_a + 1; - cal3_state <= CAL3_RDEN_PIPE_CLR_WAIT; - end - end - - // give additional time for RDEN_R pipe to clear from effects of - // previous pipeline or IDELAY tap change - CAL3_RDEN_PIPE_CLR_WAIT: - if (calib_rden_pipe_cnt == 5'b00000) - cal3_state <= CAL3_DETECT; - - CAL3_DONE: begin - if ((count_rden == DQS_WIDTH-1) || (SIM_ONLY != 0)) begin - calib_done[2] <= 1'b1; - cal3_state <= CAL3_IDLE; - end else begin - count_rden <= count_rden + 1; - cal3_state <= CAL3_INIT; - end - end - endcase - end - end - - //***************************************************************** - // Last part of stage 3 calibration - compensate for differences - // in delay between different DQS groups. Assume that in the worst - // case, DQS groups can only differ by one clock cycle. Data for - // certain DQS groups must be delayed by one clock cycle. - // NOTE: May need to increase allowable variation to greater than - // one clock cycle in certain customer designs. - // Algorithm is: - // 1. Record shift delay value for DQS[0] - // 2. Compare each DQS[x] delay value to that of DQS[0]: - // - If different, than record this fact (RDEN_MUX) - // - If greater than DQS[0], set RDEN_INC. Assume greater by - // one clock cycle only - this is a key assumption, assume no - // more than a one clock cycle variation. - // - If less than DQS[0], set RDEN_DEC - // 3. After calibration is complete, set control for DQS group - // delay (CALIB_RDEN_SEL): - // - If RDEN_DEC = 1, then assume that DQS[0] is the lowest - // delay (and at least one other DQS group has a higher - // delay). - // - If RDEN_INC = 1, then assume that DQS[0] is the highest - // delay (and that all other DQS groups have the same or - // lower delay). - // - If both RDEN_INC and RDEN_DEC = 1, then flag error - // (variation is too high for this algorithm to handle) - //***************************************************************** - - always @(posedge clkdiv) begin - if (rstdiv) begin - calib_err_2[1] <= 1'b0; - calib_rden_sel <= {DQS_WIDTH{1'bx}}; - rden_dec <= 1'b0; - rden_dly_0 <= 5'bxxxxx; - rden_inc <= 1'b0; - rden_mux <= {DQS_WIDTH{1'b0}}; - end else begin - // if a match if found, then store the value of rden_dly - if (!calib_done[2]) begin - if ((cal3_state == CAL3_DETECT) && cal3_match_found) begin - // store the value for DQS[0] as a reference - if (count_rden == 0) begin - // for simulation, RDEN calibration only happens for DQS[0] - // set RDEN_MUX for all DQS groups to be the same as DQS[0] - if (SIM_ONLY != 0) - rden_mux <= {DQS_WIDTH{1'b0}}; - else begin - // otherwise, load values for DQS[0] - rden_dly_0 <= cal3_rden_srl_a; - rden_mux[0] <= 1'b0; - end - end else if (SIM_ONLY == 0) begin - // for all other DQS groups, compare RDEN_DLY delay value with - // that of DQS[0] - if (rden_dly_0 != cal3_rden_srl_a) begin - // record that current DQS group has a different delay - // than DQS[0] (the "reference" DQS group) - rden_mux[count_rden] <= 1'b1; - if (rden_dly_0 > cal3_rden_srl_a) - rden_inc <= 1'b1; - else if (rden_dly_0 < cal3_rden_srl_a) - rden_dec <= 1'b1; - // otherwise, if current DQS group has same delay as DQS[0], - // then rden_mux[count_rden] remains at 0 (since rden_mux - // array contents initialized to 0) - end - end - end - end else begin - // Otherwise - if we're done w/ stage 2 calibration: - // set final value for RDEN data delay - // flag error if there's more than one cycle variation from DQS[0] - calib_err_2[1] <= (rden_inc && rden_dec); - if (rden_inc) - // if DQS[0] delay represents max delay - calib_rden_sel <= ~rden_mux; - else - // if DQS[0] delay represents min delay (or all the delays are - // the same between DQS groups) - calib_rden_sel <= rden_mux; - end - end - end - - // flag error for stage 3 if appropriate - always @(posedge clkdiv) - calib_err[2] <= calib_err_2[0] | calib_err_2[1]; - - //*************************************************************************** - // Stage 4 calibration: DQS gate - //*************************************************************************** - - //***************************************************************** - // indicates that current received data is the correct pattern. Same as - // for READ VALID calibration, except that the expected data sequence is - // different since DQS gate is asserted after the 6th word. - // Data sequence: - // Arrives from memory (at FPGA input) (R, F): 1 0 0 1 1 0 0 1 - // After gating the sequence looks like: 1 0 0 1 1 0 1 0 (7th word = - // 5th word, 8th word = 6th word) - // What is the gate timing is off? Need to make sure we can distinquish - // between the results of correct vs. incorrect gate timing. We also use - // the "read_valid" signal from stage 3 calibration to help us determine - // when to check for a valid sequence for stage 4 calibration (i.e. use - // CAL4_DATA_VALID in addition to CAL4_DATA_MATCH/CAL4_DATA_MATCH_STGD) - // Note that since the gate signal from the CLK0 domain is synchronized - // to the falling edge of DQS, that the effect of the gate will only be - // seen starting with a rising edge data (although it is possible - // the GATE IDDR output could go metastable and cause a unexpected result - // on the first rising and falling edges after the gate is enabled). - // Also note that the actual DQS glitch can come more than 0.5*tCK after - // the last falling edge of DQS and the constraint for this path is can - // be > 0.5*tCK; however, this means when calibrating, the output of the - // GATE IDDR may miss the setup time requirement of the rising edge flop - // and only meet it for the falling edge flop. Therefore the rising - // edge data immediately following the assertion of the gate can either - // be a 1 or 0 (can rely on either) - // As the timing on the gate is varied, we expect to see (sequence of - // captured read data shown below): - // - 1 0 0 1 1 0 0 1 (gate is really early, starts and ends before - // read burst even starts) - // - x 0 0 1 1 0 0 1 (gate pulse starts before the burst, and ends - // - x y 0 1 1 0 0 1 sometime during the burst; x,y = 0, or 1, but - // - x y x 1 1 0 0 1 all bits that show an x are the same value, - // - x y x y 1 0 0 1 and y are the same value) - // - x y x y x 0 0 1 - // - x y x y x y 0 1 (gate starts just before start of burst) - // - 1 0 x 0 x 0 x 0 (gate starts after 1st falling word. The "x" - // represents possiblity that gate may not disable - // clock for 2nd rising word in time) - // - 1 0 0 1 x 1 x 1 (gate starts after 2nd falling word) - // - 1 0 0 1 1 0 x 0 (gate starts after 3rd falling word - GOOD!!) - // - 1 0 0 1 1 0 0 1 (gate starts after burst is already done) - //***************************************************************** - - assign cal4_data_valid = calib_rden_valid | calib_rden_valid_stgd; - assign cal4_data_good = (calib_rden_valid & - cal4_data_match) | - (calib_rden_valid_stgd & - cal4_data_match_stgd); - - always @(posedge clkdiv) begin - // if data is aligned out of fabric ISERDES: - cal4_data_match <= ((rdd_rise_q2_r == 1) && - (rdd_fall_q2_r == 0) && - (rdd_rise_q1_r == 0) && - (rdd_fall_q1_r == 1) && - (rdd_rise_q2 == 1) && - (rdd_fall_q2 == 0) && - // MIG 2.1: Last rising edge data value not - // guaranteed to be certain value at higher - // frequencies - // (rdd_rise_q1 == 0) && - (rdd_fall_q1 == 0)); - // if data is staggered out of fabric ISERDES: - cal4_data_match_stgd <= ((rdd_rise_q1_r1 == 1) && - (rdd_fall_q1_r1 == 0) && - (rdd_rise_q2_r == 0) && - (rdd_fall_q2_r == 1) && - (rdd_rise_q1_r == 1) && - (rdd_fall_q1_r == 0) && - // MIG 2.1: Last rising edge data value not - // guaranteed to be certain value at higher - // frequencies - // (rdd_rise_q2 == 0) && - (rdd_fall_q2 == 0)); - end - - //***************************************************************** - // DQS gate enable generation: - // This signal gets synchronized to DQS domain, and drives IDDR - // register that in turn asserts/deasserts CE to all 4 or 8 DQ - // IDDR's in that DQS group. - // 1. During normal (post-cal) operation, this is only for 2 clock - // cycles following the end of a burst. Check for falling edge - // of RDEN. But must also make sure NOT assert for a read-idle- - // read (two non-consecutive reads, separated by exactly one - // idle cycle) - in this case, don't assert the gate because: - // (1) we don't have enough time to deassert the gate before the - // first rising edge of DQS for second burst (b/c of fact - // that DQS gate is generated in the fabric only off rising - // edge of CLK0 - if we somehow had an ODDR in fabric, we - // could pull this off, (2) assumption is that the DQS glitch - // will not rise enough to cause a glitch because the - // post-amble of the first burst is followed immediately by - // the pre-amble of the next burst - // 2. During stage 4 calibration, assert for 3 clock cycles - // (assert gate enable one clock cycle early), since we gate out - // the last two words (in addition to the crap on the DQ bus after - // the DQS read postamble). - // NOTE: PHY_INIT_RDEN and CTRL_RDEN have slightly different timing w/r - // to when they are asserted w/r to the start of the read burst - // (PHY_INIT_RDEN is one cycle earlier than CTRL_RDEN). - //***************************************************************** - - // register for timing purposes for fast clock path - currently only - // calib_done_r[2] used - always @(posedge clk) - calib_done_r <= calib_done; - - always @(*) begin - calib_ctrl_rden = ctrl_rden; - calib_init_rden = calib_done_r[2] & phy_init_rden; - end - - assign calib_ctrl_rden_negedge = ~calib_ctrl_rden & calib_ctrl_rden_r; - // check for read-idle-read before asserting DQS pulse at end of read - assign calib_ctrl_gate_pulse = calib_ctrl_rden_negedge_r & - ~calib_ctrl_rden; - always @(posedge clk) begin - calib_ctrl_rden_r <= calib_ctrl_rden; - calib_ctrl_rden_negedge_r <= calib_ctrl_rden_negedge; - calib_ctrl_gate_pulse_r <= calib_ctrl_gate_pulse; - end - - assign calib_init_gate_pulse = ~calib_init_rden & calib_init_rden_r; - always @(posedge clk) begin - calib_init_rden_r <= calib_init_rden; - calib_init_gate_pulse_r <= calib_init_gate_pulse; - calib_init_gate_pulse_r1 <= calib_init_gate_pulse_r; - end - - // Gate is asserted: (1) during cal, for 3 cycles, starting 1 cycle - // after falling edge of CTRL_RDEN, (2) during normal ops, for 2 - // cycles, starting 2 cycles after falling edge of CTRL_RDEN - assign gate_srl_in = ~((calib_ctrl_gate_pulse | - calib_ctrl_gate_pulse_r) | - (calib_init_gate_pulse | - calib_init_gate_pulse_r | - calib_init_gate_pulse_r1)); - - //***************************************************************** - // generate DQS enable signal for each DQS group - // There are differences between DQS gate signal for calibration vs. during - // normal operation: - // * calibration gates the second to last clock cycle of the burst, - // rather than after the last word (e.g. for a 8-word, 4-cycle burst, - // cycle 4 is gated for calibration; during normal operation, cycle - // 5 (i.e. cycle after the last word) is gated) - // enable for DQS is deasserted for two clock cycles, except when - // we have the preamble for the next read immediately following - // the postamble of the current read - assume DQS does not glitch - // during this time, that it stays low. Also if we did have to gate - // the DQS for this case, then we don't have enough time to deassert - // the gate in time for the first rising edge of DQS for the second - // read - //***************************************************************** - - // Flops for targetting of multi-cycle path in UCF - genvar gate_ff_i; - generate - for (gate_ff_i = 0; gate_ff_i < 5*DQS_WIDTH; - gate_ff_i = gate_ff_i+1) begin: gen_gate_dly - FDRSE u_ff_gate_dly - ( - .Q (gate_dly_r[gate_ff_i]), - .C (clkdiv), - .CE (1'b1), - .D (gate_dly[gate_ff_i]), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - end - endgenerate - - genvar gate_i; - generate - for (gate_i = 0; gate_i < DQS_WIDTH; gate_i = gate_i + 1) begin: gen_gate - SRLC32E u_gate_srl - ( - .Q (gate_srl_out[gate_i]), - .Q31 (), - .A ({gate_dly_r[(gate_i*5)+4], - gate_dly_r[(gate_i*5)+3], - gate_dly_r[(gate_i*5)+2], - gate_dly_r[(gate_i*5)+1], - gate_dly_r[(gate_i*5)]}), - .CE (1'b1), - .CLK (clk), - .D (gate_srl_in) - ); - - // For GATE_BASE_DELAY > 0, have one extra cycle to register outputs - // from controller before generating DQS gate pulse. In PAR, the - // location of the controller logic can be far from the DQS gate - // logic (DQS gate logic located near the DQS I/O's), contributing - // to large net delays. Registering the controller outputs for - // CL >= 4 (above 200MHz) adds a stage of pipelining to reduce net - // delays - if (GATE_BASE_DELAY > 0) begin: gen_gate_base_dly_gt3 - // add flop between SRL32 and EN_DQS flop (which is located near the - // DDR2 IOB's) - FDRSE u_gate_srl_ff - ( - .Q (gate_srl_out_r[gate_i]), - .C (clk), - .CE (1'b1), - .D (gate_srl_out[gate_i]), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve = 1 */; - end else begin: gen_gate_base_dly_le3 - assign gate_srl_out_r[gate_i] = gate_srl_out[gate_i]; - end - - FDRSE u_en_dqs_ff - ( - .Q (en_dqs[gate_i]), - .C (clk), - .CE (1'b1), - .D (gate_srl_out_r[gate_i]), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - end - endgenerate - - //***************************************************************** - // Find valid window: keep track of how long we've been in the same data - // window. If it's been long enough, then declare that we've found a stable - // valid window - in particular, that we're past any region of instability - // associated with the edge of the window. Use only when finding left edge - //***************************************************************** - - always @(posedge clkdiv) - // reset before we start to look for window - if (cal4_state == CAL4_INIT) begin - cal4_window_cnt <= 4'b0000; - cal4_stable_window <= 1'b0; - end else if ((cal4_state == CAL4_FIND_EDGE) && cal4_seek_left) begin - // if we're looking for left edge, and incrementing IDELAY, count - // consecutive taps over which we're in the window - if (cal4_data_valid) begin - if (cal4_data_good) - cal4_window_cnt <= cal4_window_cnt + 1; - else - cal4_window_cnt <= 4'b0000; - end - - if (cal4_window_cnt == MIN_WIN_SIZE-1) - cal4_stable_window <= 1'b1; - end - - //***************************************************************** - // keep track of edge tap counts found, and whether we've - // incremented to the maximum number of taps allowed - //***************************************************************** - - always @(posedge clkdiv) - if ((cal4_state == CAL4_INIT) || cal4_dlyrst_gate) begin - cal4_idel_max_tap <= 1'b0; - cal4_idel_bit_tap <= 1'b0; - cal4_idel_tap_cnt <= 6'b000000; - end else if (cal4_dlyce_gate) begin - if (cal4_dlyinc_gate) begin - cal4_idel_tap_cnt <= cal4_idel_tap_cnt + 1; - cal4_idel_bit_tap <= (cal4_idel_tap_cnt == CAL4_IDEL_BIT_VAL-2); - cal4_idel_max_tap <= (cal4_idel_tap_cnt == 6'b111110); - end else begin - cal4_idel_tap_cnt <= cal4_idel_tap_cnt - 1; - cal4_idel_bit_tap <= 1'b0; - cal4_idel_max_tap <= 1'b0; - end - end - - always @(posedge clkdiv) - if ((cal4_state != CAL4_RDEN_PIPE_CLR_WAIT) && - (cal3_state != CAL3_RDEN_PIPE_CLR_WAIT)) - calib_rden_pipe_cnt <= CALIB_RDEN_PIPE_LEN-1; - else - calib_rden_pipe_cnt <= calib_rden_pipe_cnt - 1; - - //***************************************************************** - // Stage 4 cal state machine - //***************************************************************** - - always @(posedge clkdiv) - if (rstdiv) begin - calib_done[3] <= 1'b0; - calib_done_tmp[3] <= 1'b0; - calib_err[3] <= 1'b0; - count_gate <= 'b0; - gate_dly <= 'b0; - next_count_gate <= 'b0; - cal4_idel_adj_cnt <= 6'bxxxxxx; - cal4_dlyce_gate <= 1'b0; - cal4_dlyinc_gate <= 1'b0; - cal4_dlyrst_gate <= 1'b0; // reset handled elsewhere in code - cal4_gate_srl_a <= 5'bxxxxx; - cal4_rden_srl_a <= 5'bxxxxx; - cal4_ref_req <= 1'b0; - cal4_seek_left <= 1'bx; - cal4_state <= CAL4_IDLE; - end else begin - cal4_ref_req <= 1'b0; - cal4_dlyce_gate <= 1'b0; - cal4_dlyinc_gate <= 1'b0; - cal4_dlyrst_gate <= 1'b0; - - case (cal4_state) - CAL4_IDLE: begin - count_gate <= 'b0; - next_count_gate <= 'b0; - if (calib_start[3]) begin - gate_dly <= 'b0; - calib_done[3] <= 1'b0; - cal4_state <= CAL4_INIT; - end - end - - CAL4_INIT: begin - // load: (1) initial value of gate delay SRL, (2) appropriate - // value of RDEN SRL (so that we get correct "data valid" timing) - cal4_gate_srl_a <= GATE_BASE_INIT; - cal4_rden_srl_a <= {calib_rden_dly[(count_gate*5)+4], - calib_rden_dly[(count_gate*5)+3], - calib_rden_dly[(count_gate*5)+2], - calib_rden_dly[(count_gate*5)+1], - calib_rden_dly[(count_gate*5)]}; - // let SRL pipe clear after loading initial shift value - cal4_state <= CAL4_RDEN_PIPE_CLR_WAIT; - end - - // sort of an initial state - start checking to see whether we're - // already in the window or not - CAL4_FIND_WINDOW: - // decide right away if we start in the proper window - this - // determines if we are then looking for the left (trailing) or - // right (leading) edge of the data valid window - if (cal4_data_valid) begin - // if we find a match - then we're already in window, now look - // for left edge. Otherwise, look for right edge of window - cal4_seek_left <= cal4_data_good; - cal4_state <= CAL4_FIND_EDGE; - end - - CAL4_FIND_EDGE: - // don't do anything until the exact clock cycle when to check that - // readback data is valid or not - if (cal4_data_valid) begin - // we're currently in the window, look for left edge of window - if (cal4_seek_left) begin - // make sure we've passed the right edge before trying to detect - // the left edge (i.e. avoid any edge "instability") - else, we - // may detect an "false" edge too soon. By design, if we start in - // the data valid window, always expect at least - // MIN(BIT_TIME_TAPS,32) (-/+ jitter, see below) taps of valid - // window before we hit the left edge (this is because when stage - // 4 calibration first begins (i.e., gate_dly = 00, and IDELAY = - // 00), we're guaranteed to NOT be in the window, and we always - // start searching for MIN(BIT_TIME_TAPS,32) for the right edge - // of window. If we don't find it, increment gate_dly, and if we - // now start in the window, we have at least approximately - // CLK_PERIOD-MIN(BIT_TIME_TAPS,32) = MIN(BIT_TIME_TAPS,32) taps. - // It's approximately because jitter, noise, etc. can bring this - // value down slightly. Because of this (although VERY UNLIKELY), - // we have to protect against not decrementing IDELAY below 0 - // during adjustment phase). - if (cal4_stable_window && !cal4_data_good) begin - // found left edge of window, dec by MIN(BIT_TIME_TAPS,32) - cal4_idel_adj_cnt <= CAL4_IDEL_BIT_VAL; - cal4_idel_adj_inc <= 1'b0; - cal4_state <= CAL4_ADJ_IDEL; - end else begin - // Otherwise, keep looking for left edge: - if (cal4_idel_max_tap) begin - // ran out of taps looking for left edge (max=63) - happens - // for low frequency case, decrement by 32 - cal4_idel_adj_cnt <= 6'b100000; - cal4_idel_adj_inc <= 1'b0; - cal4_state <= CAL4_ADJ_IDEL; - end else begin - cal4_dlyce_gate <= 1'b1; - cal4_dlyinc_gate <= 1'b1; - cal4_state <= CAL4_IDEL_WAIT; - end - end - end else begin - // looking for right edge of window: - // look for the first match - this means we've found the right - // (leading) edge of the data valid window, increment by - // MIN(BIT_TIME_TAPS,32) - if (cal4_data_good) begin - cal4_idel_adj_cnt <= CAL4_IDEL_BIT_VAL; - cal4_idel_adj_inc <= 1'b1; - cal4_state <= CAL4_ADJ_IDEL; - end else begin - // Otherwise, keep looking: - // only look for MIN(BIT_TIME_TAPS,32) taps for right edge, - // if we haven't found it, then inc gate delay, try again - if (cal4_idel_bit_tap) begin - // if we're already maxed out on gate delay, then error out - // (simulation only - calib_err isn't currently connected) - if (cal4_gate_srl_a == 5'b11111) begin - calib_err[3] <= 1'b1; - cal4_state <= CAL4_IDLE; - end else begin - // otherwise, increment gate delay count, and start - // over again - cal4_gate_srl_a <= cal4_gate_srl_a + 1; - cal4_dlyrst_gate <= 1'b1; - cal4_state <= CAL4_RDEN_PIPE_CLR_WAIT; - end - end else begin - // keep looking for right edge - cal4_dlyce_gate <= 1'b1; - cal4_dlyinc_gate <= 1'b1; - cal4_state <= CAL4_IDEL_WAIT; - end - end - end - end - - // wait for GATE IDELAY to settle, after reset or increment - CAL4_IDEL_WAIT: begin - // For simulation, load SRL addresses for all DQS with same value - if (SIM_ONLY != 0) begin - for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_gate_dly - gate_dly[(i*5)+4] <= cal4_gate_srl_a[4]; - gate_dly[(i*5)+3] <= cal4_gate_srl_a[3]; - gate_dly[(i*5)+2] <= cal4_gate_srl_a[2]; - gate_dly[(i*5)+1] <= cal4_gate_srl_a[1]; - gate_dly[(i*5)] <= cal4_gate_srl_a[0]; - end - end else begin - gate_dly[(count_gate*5)+4] <= cal4_gate_srl_a[4]; - gate_dly[(count_gate*5)+3] <= cal4_gate_srl_a[3]; - gate_dly[(count_gate*5)+2] <= cal4_gate_srl_a[2]; - gate_dly[(count_gate*5)+1] <= cal4_gate_srl_a[1]; - gate_dly[(count_gate*5)] <= cal4_gate_srl_a[0]; - end - // check to see if we've found edge of window - if (!idel_set_wait) - cal4_state <= CAL4_FIND_EDGE; - end - - // give additional time for RDEN_R pipe to clear from effects of - // previous pipeline (and IDELAY reset) - CAL4_RDEN_PIPE_CLR_WAIT: begin - // MIG 2.2: Bug fix - make sure to update GATE_DLY count, since - // possible for FIND_EDGE->RDEN_PIPE_CLR_WAIT->FIND_WINDOW - // transition (i.e. need to make sure the gate count updated in - // FIND_EDGE gets reflected in GATE_DLY by the time we reach - // state FIND_WINDOW) - previously GATE_DLY only being updated - // during state CAL4_IDEL_WAIT - if (SIM_ONLY != 0) begin - for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_gate_dly_pipe - gate_dly[(i*5)+4] <= cal4_gate_srl_a[4]; - gate_dly[(i*5)+3] <= cal4_gate_srl_a[3]; - gate_dly[(i*5)+2] <= cal4_gate_srl_a[2]; - gate_dly[(i*5)+1] <= cal4_gate_srl_a[1]; - gate_dly[(i*5)] <= cal4_gate_srl_a[0]; - end - end else begin - gate_dly[(count_gate*5)+4] <= cal4_gate_srl_a[4]; - gate_dly[(count_gate*5)+3] <= cal4_gate_srl_a[3]; - gate_dly[(count_gate*5)+2] <= cal4_gate_srl_a[2]; - gate_dly[(count_gate*5)+1] <= cal4_gate_srl_a[1]; - gate_dly[(count_gate*5)] <= cal4_gate_srl_a[0]; - end - // look for new window - if (calib_rden_pipe_cnt == 5'b00000) - cal4_state <= CAL4_FIND_WINDOW; - end - - // increment/decrement DQS/DQ IDELAY for final adjustment - CAL4_ADJ_IDEL: - // add underflow protection for corner case when left edge found - // using fewer than MIN(BIT_TIME_TAPS,32) taps - if ((cal4_idel_adj_cnt == 6'b000000) || - (cal4_dlyce_gate && !cal4_dlyinc_gate && - (cal4_idel_tap_cnt == 6'b000001))) begin - cal4_state <= CAL4_DONE; - // stop when all gates calibrated, or gate[0] cal'ed (for sim) - if ((count_gate == DQS_WIDTH-1) || (SIM_ONLY != 0)) - calib_done_tmp[3] <= 1'b1; - else - // need for VHDL simulation to prevent out-of-index error - next_count_gate <= count_gate + 1; - end else begin - cal4_idel_adj_cnt <= cal4_idel_adj_cnt - 1; - cal4_dlyce_gate <= 1'b1; - // whether inc or dec depends on whether left or right edge found - cal4_dlyinc_gate <= cal4_idel_adj_inc; - end - - // wait for IDELAY output to settle after decrement. Check current - // COUNT_GATE value and decide if we're done - CAL4_DONE: - if (!idel_set_wait) begin - count_gate <= next_count_gate; - if (calib_done_tmp[3]) begin - calib_done[3] <= 1'b1; - cal4_state <= CAL4_IDLE; - end else begin - // request auto-refresh after every DQS group calibrated to - // avoid tRAS violation - cal4_ref_req <= 1'b1; - if (calib_ref_done) - cal4_state <= CAL4_INIT; - end - end - endcase - end - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_idelay_ctrl.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_idelay_ctrl.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_idelay_ctrl.v (nonexistent) @@ -1,87 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_idelay_ctrl.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module instantiates the IDELAYCTRL primitive of the Virtex-5 device -// which continuously calibrates the IDELAY elements in the region in case of -// varying operating conditions. It takes a 200MHz clock as an input -//Reference: -//Revision History: -// Rev 1.1 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added -// on IOELAYCTRL primitive. Generate logic on IDELAYCTRL removed -// since tools will replicate idelactrl primitives.PK. 11/27/08 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_idelay_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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter IODELAY_GRP = "IODELAY_MIG" - ) - - ( - input clk200, - input rst200, - output idelay_ctrl_rdy - ); - - (* IODELAY_GROUP = IODELAY_GRP *) IDELAYCTRL u_idelayctrl - ( - .RDY(idelay_ctrl_rdy), - .REFCLK(clk200), - .RST(rst200) - ); - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_top.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_top.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_top.v (nonexistent) @@ -1,181 +0,0 @@ -//***************************************************************************** -// 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 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_usr_top.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Mon Aug 28 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module interfaces with the user. The user should provide the data -// and various commands. -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_usr_top # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter CS_BITS = 0, - parameter COL_WIDTH = 10, - parameter DQ_WIDTH = 72, - parameter DQ_PER_DQS = 8, - parameter APPDATA_WIDTH = 144, - parameter ECC_ENABLE = 0, - parameter DQS_WIDTH = 9, - parameter ROW_WIDTH = 14 - ) - ( - input clk0, - input clk90, - input rst0, - input [DQ_WIDTH-1:0] rd_data_in_rise, - input [DQ_WIDTH-1:0] rd_data_in_fall, - input [DQS_WIDTH-1:0] phy_calib_rden, - input [DQS_WIDTH-1:0] phy_calib_rden_sel, - output rd_data_valid, - output [APPDATA_WIDTH-1:0] rd_data_fifo_out, - input [2:0] app_af_cmd, - input [30:0] app_af_addr, - input app_af_wren, - input ctrl_af_rden, - output [2:0] af_cmd, - output [30:0] af_addr, - output af_empty, - output app_af_afull, - output [1:0] rd_ecc_error, - input app_wdf_wren, - input [APPDATA_WIDTH-1:0] app_wdf_data, - input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, - input wdf_rden, - output app_wdf_afull, - output [(2*DQ_WIDTH)-1:0] wdf_data, - output [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data - ); - - wire [(APPDATA_WIDTH/2)-1:0] i_rd_data_fifo_out_fall; - wire [(APPDATA_WIDTH/2)-1:0] i_rd_data_fifo_out_rise; - - //*************************************************************************** - - assign rd_data_fifo_out = {i_rd_data_fifo_out_fall, - i_rd_data_fifo_out_rise}; - - // read data de-skew and ECC calculation - ddr2_usr_rd # - ( - .DQ_PER_DQS (DQ_PER_DQS), - .ECC_ENABLE (ECC_ENABLE), - .APPDATA_WIDTH (APPDATA_WIDTH), - .DQS_WIDTH (DQS_WIDTH) - ) - u_usr_rd - ( - .clk0 (clk0), - .rst0 (rst0), - .rd_data_in_rise (rd_data_in_rise), - .rd_data_in_fall (rd_data_in_fall), - .rd_ecc_error (rd_ecc_error), - .ctrl_rden (phy_calib_rden), - .ctrl_rden_sel (phy_calib_rden_sel), - .rd_data_valid (rd_data_valid), - .rd_data_out_rise (i_rd_data_fifo_out_rise), - .rd_data_out_fall (i_rd_data_fifo_out_fall) - ); - - // Command/Addres FIFO - ddr2_usr_addr_fifo # - ( - .BANK_WIDTH (BANK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_BITS (CS_BITS), - .ROW_WIDTH (ROW_WIDTH) - ) - u_usr_addr_fifo - ( - .clk0 (clk0), - .rst0 (rst0), - .app_af_cmd (app_af_cmd), - .app_af_addr (app_af_addr), - .app_af_wren (app_af_wren), - .ctrl_af_rden (ctrl_af_rden), - .af_cmd (af_cmd), - .af_addr (af_addr), - .af_empty (af_empty), - .app_af_afull (app_af_afull) - ); - - ddr2_usr_wr # - ( - .BANK_WIDTH (BANK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_BITS (CS_BITS), - .DQ_WIDTH (DQ_WIDTH), - .APPDATA_WIDTH (APPDATA_WIDTH), - .ECC_ENABLE (ECC_ENABLE), - .ROW_WIDTH (ROW_WIDTH) - ) - u_usr_wr - ( - .clk0 (clk0), - .clk90 (clk90), - .rst0 (rst0), - .app_wdf_wren (app_wdf_wren), - .app_wdf_data (app_wdf_data), - .app_wdf_mask_data (app_wdf_mask_data), - .wdf_rden (wdf_rden), - .app_wdf_afull (app_wdf_afull), - .wdf_data (wdf_data), - .wdf_mask_data (wdf_mask_data) - ); - -endmodule \ No newline at end of file Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_rd.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_rd.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_rd.v (nonexistent) @@ -1,297 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_usr_rd.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Tue Aug 29 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// The delay between the read data with respect to the command issued is -// calculted in terms of no. of clocks. This data is then stored into the -// FIFOs and then read back and given as the ouput for comparison. -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_usr_rd # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter DQ_PER_DQS = 8, - parameter DQS_WIDTH = 9, - parameter APPDATA_WIDTH = 144, - parameter ECC_WIDTH = 72, - parameter ECC_ENABLE = 0 - ) - ( - input clk0, - input rst0, - input [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_rise, - input [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_fall, - input [DQS_WIDTH-1:0] ctrl_rden, - input [DQS_WIDTH-1:0] ctrl_rden_sel, - output reg [1:0] rd_ecc_error, - output rd_data_valid, - output reg [(APPDATA_WIDTH/2)-1:0] rd_data_out_rise, - output reg [(APPDATA_WIDTH/2)-1:0] rd_data_out_fall - ); - - // determine number of FIFO72's to use based on data width - localparam RDF_FIFO_NUM = ((APPDATA_WIDTH/2)+63)/64; - - reg [DQS_WIDTH-1:0] ctrl_rden_r; - wire [(DQS_WIDTH*DQ_PER_DQS)-1:0] fall_data; - reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_fall_r; - reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_rise_r; - wire rden; - reg [DQS_WIDTH-1:0] rden_sel_r - /* synthesis syn_preserve=1 */; - wire [DQS_WIDTH-1:0] rden_sel_mux; - wire [(DQS_WIDTH*DQ_PER_DQS)-1:0] rise_data; - - // ECC specific signals - wire [((RDF_FIFO_NUM -1) *2)+1:0] db_ecc_error; - reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] fall_data_r; - reg fifo_rden_r0; - reg fifo_rden_r1; - reg fifo_rden_r2; - reg fifo_rden_r3; - reg fifo_rden_r4; - reg fifo_rden_r5; - reg fifo_rden_r6; - wire [(APPDATA_WIDTH/2)-1:0] rd_data_out_fall_temp; - wire [(APPDATA_WIDTH/2)-1:0] rd_data_out_rise_temp; - reg rst_r; - reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rise_data_r; - wire [((RDF_FIFO_NUM -1) *2)+1:0] sb_ecc_error; - - - //*************************************************************************** - - always @(posedge clk0) begin - rden_sel_r <= ctrl_rden_sel; - ctrl_rden_r <= ctrl_rden; - rd_data_in_rise_r <= rd_data_in_rise; - rd_data_in_fall_r <= rd_data_in_fall; - end - - // Instantiate primitive to allow this flop to be attached to multicycle - // path constraint in UCF. Multicycle path allowed for data from read FIFO. - // This is the same signal as RDEN_SEL_R, but is only used to select data - // (does not affect control signals) - genvar rd_i; - generate - for (rd_i = 0; rd_i < DQS_WIDTH; rd_i = rd_i+1) begin: gen_rden_sel_mux - FDRSE u_ff_rden_sel_mux - ( - .Q (rden_sel_mux[rd_i]), - .C (clk0), - .CE (1'b1), - .D (ctrl_rden_sel[rd_i]), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve=1 */; - end - endgenerate - - // determine correct read data valid signal timing - assign rden = (rden_sel_r[0]) ? ctrl_rden[0] : ctrl_rden_r[0]; - - // assign data based on the skew - genvar data_i; - generate - for(data_i = 0; data_i < DQS_WIDTH; data_i = data_i+1) begin: gen_data - assign rise_data[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): - (data_i*DQ_PER_DQS)] - = (rden_sel_mux[data_i]) ? - rd_data_in_rise[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1) : - (data_i*DQ_PER_DQS)] : - rd_data_in_rise_r[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): - (data_i*DQ_PER_DQS)]; - assign fall_data[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): - (data_i*DQ_PER_DQS)] - = (rden_sel_mux[data_i]) ? - rd_data_in_fall[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): - (data_i*DQ_PER_DQS)] : - rd_data_in_fall_r[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): - (data_i*DQ_PER_DQS)]; - end - endgenerate - - // Generate RST for FIFO reset AND for read/write enable: - // ECC FIFO always being read from and written to - always @(posedge clk0) - rst_r <= rst0; - - genvar rdf_i; - generate - if (ECC_ENABLE) begin - always @(posedge clk0) begin - rd_ecc_error[0] <= (|sb_ecc_error) & fifo_rden_r5; - rd_ecc_error[1] <= (|db_ecc_error) & fifo_rden_r5; - rd_data_out_rise <= rd_data_out_rise_temp; - rd_data_out_fall <= rd_data_out_fall_temp; - rise_data_r <= rise_data; - fall_data_r <= fall_data; - end - - // can use any of the read valids, they're all delayed by same amount - assign rd_data_valid = fifo_rden_r6; - - // delay read valid to take into account max delay difference btw - // the read enable coming from the different DQS groups - always @(posedge clk0) begin - if (rst0) begin - fifo_rden_r0 <= 1'b0; - fifo_rden_r1 <= 1'b0; - fifo_rden_r2 <= 1'b0; - fifo_rden_r3 <= 1'b0; - fifo_rden_r4 <= 1'b0; - fifo_rden_r5 <= 1'b0; - fifo_rden_r6 <= 1'b0; - end else begin - fifo_rden_r0 <= rden; - fifo_rden_r1 <= fifo_rden_r0; - fifo_rden_r2 <= fifo_rden_r1; - fifo_rden_r3 <= fifo_rden_r2; - fifo_rden_r4 <= fifo_rden_r3; - fifo_rden_r5 <= fifo_rden_r4; - fifo_rden_r6 <= fifo_rden_r5; - end - end - - for (rdf_i = 0; rdf_i < RDF_FIFO_NUM; rdf_i = rdf_i + 1) begin: gen_rdf - - FIFO36_72 # // rise fifo - ( - .ALMOST_EMPTY_OFFSET (9'h007), - .ALMOST_FULL_OFFSET (9'h00F), - .DO_REG (1), // extra CC output delay - .EN_ECC_WRITE ("FALSE"), - .EN_ECC_READ ("TRUE"), - .EN_SYN ("FALSE"), - .FIRST_WORD_FALL_THROUGH ("FALSE") - ) - u_rdf - ( - .ALMOSTEMPTY (), - .ALMOSTFULL (), - .DBITERR (db_ecc_error[rdf_i + rdf_i]), - .DO (rd_data_out_rise_temp[(64*(rdf_i+1))-1: - (64 *rdf_i)]), - .DOP (), - .ECCPARITY (), - .EMPTY (), - .FULL (), - .RDCOUNT (), - .RDERR (), - .SBITERR (sb_ecc_error[rdf_i + rdf_i]), - .WRCOUNT (), - .WRERR (), - .DI (rise_data_r[((64*(rdf_i+1)) + (rdf_i*8))-1: - (64 *rdf_i)+(rdf_i*8)]), - .DIP (rise_data_r[(72*(rdf_i+1))-1: - (64*(rdf_i+1))+ (8*rdf_i)]), - .RDCLK (clk0), - .RDEN (~rst_r), - .RST (rst_r), - .WRCLK (clk0), - .WREN (~rst_r) - ); - - FIFO36_72 # // fall_fifo - ( - .ALMOST_EMPTY_OFFSET (9'h007), - .ALMOST_FULL_OFFSET (9'h00F), - .DO_REG (1), // extra CC output delay - .EN_ECC_WRITE ("FALSE"), - .EN_ECC_READ ("TRUE"), - .EN_SYN ("FALSE"), - .FIRST_WORD_FALL_THROUGH ("FALSE") - ) - u_rdf1 - ( - .ALMOSTEMPTY (), - .ALMOSTFULL (), - .DBITERR (db_ecc_error[(rdf_i+1) + rdf_i]), - .DO (rd_data_out_fall_temp[(64*(rdf_i+1))-1: - (64 *rdf_i)]), - .DOP (), - .ECCPARITY (), - .EMPTY (), - .FULL (), - .RDCOUNT (), - .RDERR (), - .SBITERR (sb_ecc_error[(rdf_i+1) + rdf_i]), - .WRCOUNT (), - .WRERR (), - .DI (fall_data_r[((64*(rdf_i+1)) + (rdf_i*8))-1: - (64*rdf_i)+(rdf_i*8)]), - .DIP (fall_data_r[(72*(rdf_i+1))-1: - (64*(rdf_i+1))+ (8*rdf_i)]), - .RDCLK (clk0), - .RDEN (~rst_r), - .RST (rst_r), // or can use rst0 - .WRCLK (clk0), - .WREN (~rst_r) - ); - end - end else begin - assign rd_data_valid = fifo_rden_r0; - always @(posedge clk0) begin - rd_data_out_rise <= rise_data; - rd_data_out_fall <= fall_data; - fifo_rden_r0 <= rden; - end - end - endgenerate - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dqs_iob.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dqs_iob.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dqs_iob.v (nonexistent) @@ -1,266 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_dqs_iob.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module places the data strobes in the IOBs. -//Reference: -//Revision History: -// Rev 1.1 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 -// Rev 1.2 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added -// on IODELAY primitives. PK. 11/27/08 -// Rev 1.3 - IDDR primitve (u_iddr_dq_ce) is replaced with a negative-edge -// triggered flip-flop. PK. 03/20/09 -// Rev 1.4 - To fix CR 540201, S and syn_preserve attributes are added -// for dqs_oe_n_r. PK. 01/08/10 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_phy_dqs_iob # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter DDR_TYPE = 1, - parameter HIGH_PERFORMANCE_MODE = "TRUE", - parameter IODELAY_GRP = "IODELAY_MIG" - ) - ( - input clk0, - input clkdiv0, - input rst0, - input dlyinc_dqs, - input dlyce_dqs, - input dlyrst_dqs, - input dlyinc_gate, - input dlyce_gate, - input dlyrst_gate, - input dqs_oe_n, - input dqs_rst_n, - input en_dqs, - inout ddr_dqs, - inout ddr_dqs_n, - output dq_ce, - output delayed_dqs - ); - - wire clk180; - wire dqs_bufio; - - wire dqs_ibuf; - wire dqs_idelay; - wire dqs_oe_n_delay; - (* S = "TRUE" *) wire dqs_oe_n_r /* synthesis syn_preserve = 1*/; - wire dqs_rst_n_delay; - reg dqs_rst_n_r /* synthesis syn_preserve = 1*/; - wire dqs_out; - wire en_dqs_sync /* synthesis syn_keep = 1 */; - - // for simulation only. Synthesis should ignore this delay - localparam DQS_NET_DELAY = 0.8; - - assign clk180 = ~clk0; - - // add delta delay to inputs clocked by clk180 to avoid delta-delay - // simulation issues - assign dqs_rst_n_delay = dqs_rst_n; - assign dqs_oe_n_delay = dqs_oe_n; - - //*************************************************************************** - // DQS input-side resources: - // - IODELAY (pad -> IDELAY) - // - BUFIO (IDELAY -> BUFIO) - //*************************************************************************** - - // Route DQS from PAD to IDELAY - (* IODELAY_GROUP = IODELAY_GRP *) IODELAY # - ( - .DELAY_SRC("I"), - .IDELAY_TYPE("VARIABLE"), - .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE), - .IDELAY_VALUE(0), - .ODELAY_VALUE(0) - ) - u_idelay_dqs - ( - .DATAOUT (dqs_idelay), - .C (clkdiv0), - .CE (dlyce_dqs), - .DATAIN (), - .IDATAIN (dqs_ibuf), - .INC (dlyinc_dqs), - .ODATAIN (), - .RST (dlyrst_dqs), - .T () - ); - - // From IDELAY to BUFIO - BUFIO u_bufio_dqs - ( - .I (dqs_idelay), - .O (dqs_bufio) - ); - - // To model additional delay of DQS BUFIO + gating network - // for behavioral simulation. Make sure to select a delay number smaller - // than half clock cycle (otherwise output will not track input changes - // because of inertial delay). Duplicate to avoid delta delay issues. - assign #(DQS_NET_DELAY) i_delayed_dqs = dqs_bufio; - assign #(DQS_NET_DELAY) delayed_dqs = dqs_bufio; - - //*************************************************************************** - // DQS gate circuit (not supported for all controllers) - //*************************************************************************** - - // Gate routing: - // en_dqs -> IDELAY -> en_dqs_sync -> IDDR.S -> dq_ce -> - // capture IDDR.CE - - // Delay CE control so that it's in phase with delayed DQS - (* IODELAY_GROUP = IODELAY_GRP *) IODELAY # - ( - .DELAY_SRC ("DATAIN"), - .IDELAY_TYPE ("VARIABLE"), - .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), - .IDELAY_VALUE (0), - .ODELAY_VALUE (0) - ) - u_iodelay_dq_ce - ( - .DATAOUT (en_dqs_sync), - .C (clkdiv0), - .CE (dlyce_gate), - .DATAIN (en_dqs), - .IDATAIN (), - .INC (dlyinc_gate), - .ODATAIN (), - .RST (dlyrst_gate), - .T () - ); - - // Generate sync'ed CE to DQ IDDR's using a negative-edge triggered flip-flop - // clocked by DQS. This flop should be locked to the IOB flip-flop at the same - // site as IODELAY u_idelay_dqs in order to use the dedicated route from - // the IODELAY to flip-flop (to keep this route as short as possible) - (* IOB = "FORCE" *) FDCPE_1 # - ( - .INIT(1'b0) - ) - u_iddr_dq_ce - ( - .Q (dq_ce), - .C (i_delayed_dqs), - .CE (1'b1), - .CLR (1'b0), - .D (en_dqs_sync), - .PRE (en_dqs_sync) - ) /* synthesis syn_useioff = 1 */ - /* synthesis syn_replicate = 0 */; - - //*************************************************************************** - // DQS output-side resources - //*************************************************************************** - - // synthesis attribute keep of dqs_rst_n_r is "true" - always @(posedge clk180) - dqs_rst_n_r <= dqs_rst_n_delay; - - ODDR # - ( - .SRTYPE("SYNC"), - .DDR_CLK_EDGE("OPPOSITE_EDGE") - ) - u_oddr_dqs - ( - .Q (dqs_out), - .C (clk180), - .CE (1'b1), - .D1 (dqs_rst_n_r), // keep output deasserted for write preamble - .D2 (1'b0), - .R (1'b0), - .S (1'b0) - ); - - (* IOB = "FORCE" *) FDP u_tri_state_dqs - ( - .D (dqs_oe_n_delay), - .Q (dqs_oe_n_r), - .C (clk180), - .PRE (rst0) - ) /* synthesis syn_useioff = 1 */; - - //*************************************************************************** - - // use either single-ended (for DDR1) or differential (for DDR2) DQS input - - generate - if (DDR_TYPE > 0) begin: gen_dqs_iob_ddr2 - IOBUFDS u_iobuf_dqs - ( - .O (dqs_ibuf), - .IO (ddr_dqs), - .IOB (ddr_dqs_n), - .I (dqs_out), - .T (dqs_oe_n_r) - ); - end else begin: gen_dqs_iob_ddr1 - IOBUF u_iobuf_dqs - ( - .O (dqs_ibuf), - .IO (ddr_dqs), - .I (dqs_out), - .T (dqs_oe_n_r) - ); - end - endgenerate - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_top.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_top.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_top.v (nonexistent) @@ -1,276 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_top.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// System level module. This level contains just the memory controller. -// This level will be intiantated when the user wants to remove the -// synthesizable test bench, IDELAY control block and the clock -// generation modules. -//Reference: -//Revision History: -// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 -// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 -// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_top # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, // # of memory bank addr bits - parameter CKE_WIDTH = 1, // # of memory clock enable outputs - parameter CLK_WIDTH = 1, // # of clock outputs - parameter COL_WIDTH = 10, // # of memory column bits - parameter CS_NUM = 1, // # of separate memory chip selects - parameter CS_BITS = 0, // set to log2(CS_NUM) (rounded up) - parameter CS_WIDTH = 1, // # of total memory chip selects - parameter USE_DM_PORT = 1, // enable Data Mask (=1 enable) - parameter DM_WIDTH = 9, // # of data mask bits - parameter DQ_WIDTH = 72, // # of data width - parameter DQ_BITS = 7, // set to log2(DQS_WIDTH*DQ_PER_DQS) - parameter DQ_PER_DQS = 8, // # of DQ data bits per strobe - parameter DQS_WIDTH = 9, // # of DQS strobes - parameter DQS_BITS = 4, // set to log2(DQS_WIDTH) - parameter HIGH_PERFORMANCE_MODE = "TRUE", // IODELAY Performance Mode - parameter IODELAY_GRP = "IODELAY_MIG", // IODELAY Group Name - parameter ODT_WIDTH = 1, // # of memory on-die term enables - parameter ROW_WIDTH = 14, // # of memory row & # of addr bits - parameter APPDATA_WIDTH = 144, // # of usr read/write data bus bits - parameter ADDITIVE_LAT = 0, // additive write latency - parameter BURST_LEN = 4, // burst length (in double words) - parameter BURST_TYPE = 0, // burst type (=0 seq; =1 interlved) - parameter CAS_LAT = 5, // CAS latency - parameter ECC_ENABLE = 0, // enable ECC (=1 enable) - parameter ODT_TYPE = 1, // ODT (=0(none),=1(75),=2(150),=3(50)) - parameter MULTI_BANK_EN = 1, // enable bank management - parameter TWO_T_TIME_EN = 0, // 2t timing for unbuffered dimms - parameter REDUCE_DRV = 0, // reduced strength mem I/O (=1 yes) - parameter REG_ENABLE = 1, // registered addr/ctrl (=1 yes) - parameter TREFI_NS = 7800, // auto refresh interval (ns) - parameter TRAS = 40000, // active->precharge delay - parameter TRCD = 15000, // active->read/write delay - parameter TRFC = 105000, // ref->ref, ref->active delay - parameter TRP = 15000, // precharge->command delay - parameter TRTP = 7500, // read->precharge delay - parameter TWR = 15000, // used to determine wr->prech - parameter TWTR = 10000, // write->read delay - parameter CLK_PERIOD = 3000, // Core/Mem clk period (in ps) - parameter SIM_ONLY = 0, // = 1 to skip power up delay - parameter DEBUG_EN = 0, // Enable debug signals/controls - parameter FPGA_SPEED_GRADE = 2 // FPGA Speed Grade - ) - ( - input clk0, - input clk90, - input clkdiv0, - input rst0, - input rst90, - input rstdiv0, - input [2:0] app_af_cmd, - input [30:0] app_af_addr, - input app_af_wren, - input app_wdf_wren, - input [APPDATA_WIDTH-1:0] app_wdf_data, - input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, - output app_af_afull, - output app_wdf_afull, - output rd_data_valid, - output [APPDATA_WIDTH-1:0] rd_data_fifo_out, - output [1:0] rd_ecc_error, - output phy_init_done, - output [CLK_WIDTH-1:0] ddr2_ck, - output [CLK_WIDTH-1:0] ddr2_ck_n, - output [ROW_WIDTH-1:0] ddr2_a, - output [BANK_WIDTH-1:0] ddr2_ba, - output ddr2_ras_n, - output ddr2_cas_n, - output ddr2_we_n, - output [CS_WIDTH-1:0] ddr2_cs_n, - output [CKE_WIDTH-1:0] ddr2_cke, - output [ODT_WIDTH-1:0] ddr2_odt, - output [DM_WIDTH-1:0] ddr2_dm, - inout [DQS_WIDTH-1:0] ddr2_dqs, - inout [DQS_WIDTH-1:0] ddr2_dqs_n, - inout [DQ_WIDTH-1:0] ddr2_dq, - // Debug signals (optional use) - input dbg_idel_up_all, - input dbg_idel_down_all, - input dbg_idel_up_dq, - input dbg_idel_down_dq, - input dbg_idel_up_dqs, - input dbg_idel_down_dqs, - input dbg_idel_up_gate, - input dbg_idel_down_gate, - input [DQ_BITS-1:0] dbg_sel_idel_dq, - input dbg_sel_all_idel_dq, - input [DQS_BITS:0] dbg_sel_idel_dqs, - input dbg_sel_all_idel_dqs, - input [DQS_BITS:0] dbg_sel_idel_gate, - input dbg_sel_all_idel_gate, - output [3:0] dbg_calib_done, - output [3:0] dbg_calib_err, - output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, - output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, - output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, - output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly - ); - - // memory initialization/control logic - ddr2_mem_if_top # - ( - .BANK_WIDTH (BANK_WIDTH), - .CKE_WIDTH (CKE_WIDTH), - .CLK_WIDTH (CLK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_BITS (CS_BITS), - .CS_NUM (CS_NUM), - .CS_WIDTH (CS_WIDTH), - .USE_DM_PORT (USE_DM_PORT), - .DM_WIDTH (DM_WIDTH), - .DQ_WIDTH (DQ_WIDTH), - .DQ_BITS (DQ_BITS), - .DQ_PER_DQS (DQ_PER_DQS), - .DQS_BITS (DQS_BITS), - .DQS_WIDTH (DQS_WIDTH), - .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), - .IODELAY_GRP (IODELAY_GRP), - .ODT_WIDTH (ODT_WIDTH), - .ROW_WIDTH (ROW_WIDTH), - .APPDATA_WIDTH (APPDATA_WIDTH), - .ADDITIVE_LAT (ADDITIVE_LAT), - .BURST_LEN (BURST_LEN), - .BURST_TYPE (BURST_TYPE), - .CAS_LAT (CAS_LAT), - .ECC_ENABLE (ECC_ENABLE), - .MULTI_BANK_EN (MULTI_BANK_EN), - .TWO_T_TIME_EN (TWO_T_TIME_EN), - .ODT_TYPE (ODT_TYPE), - .DDR_TYPE (1), - .REDUCE_DRV (REDUCE_DRV), - .REG_ENABLE (REG_ENABLE), - .TREFI_NS (TREFI_NS), - .TRAS (TRAS), - .TRCD (TRCD), - .TRFC (TRFC), - .TRP (TRP), - .TRTP (TRTP), - .TWR (TWR), - .TWTR (TWTR), - .CLK_PERIOD (CLK_PERIOD), - .SIM_ONLY (SIM_ONLY), - .DEBUG_EN (DEBUG_EN), - .FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) - ) - u_mem_if_top - ( - .clk0 (clk0), - .clk90 (clk90), - .clkdiv0 (clkdiv0), - .rst0 (rst0), - .rst90 (rst90), - .rstdiv0 (rstdiv0), - .app_af_cmd (app_af_cmd), - .app_af_addr (app_af_addr), - .app_af_wren (app_af_wren), - .app_wdf_wren (app_wdf_wren), - .app_wdf_data (app_wdf_data), - .app_wdf_mask_data (app_wdf_mask_data), - .app_af_afull (app_af_afull), - .app_wdf_afull (app_wdf_afull), - .rd_data_valid (rd_data_valid), - .rd_data_fifo_out (rd_data_fifo_out), - .rd_ecc_error (rd_ecc_error), - .phy_init_done (phy_init_done), - .ddr_ck (ddr2_ck), - .ddr_ck_n (ddr2_ck_n), - .ddr_addr (ddr2_a), - .ddr_ba (ddr2_ba), - .ddr_ras_n (ddr2_ras_n), - .ddr_cas_n (ddr2_cas_n), - .ddr_we_n (ddr2_we_n), - .ddr_cs_n (ddr2_cs_n), - .ddr_cke (ddr2_cke), - .ddr_odt (ddr2_odt), - .ddr_dm (ddr2_dm), - .ddr_dqs (ddr2_dqs), - .ddr_dqs_n (ddr2_dqs_n), - .ddr_dq (ddr2_dq), - .dbg_idel_up_all (dbg_idel_up_all), - .dbg_idel_down_all (dbg_idel_down_all), - .dbg_idel_up_dq (dbg_idel_up_dq), - .dbg_idel_down_dq (dbg_idel_down_dq), - .dbg_idel_up_dqs (dbg_idel_up_dqs), - .dbg_idel_down_dqs (dbg_idel_down_dqs), - .dbg_idel_up_gate (dbg_idel_up_gate), - .dbg_idel_down_gate (dbg_idel_down_gate), - .dbg_sel_idel_dq (dbg_sel_idel_dq), - .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), - .dbg_sel_idel_dqs (dbg_sel_idel_dqs), - .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), - .dbg_sel_idel_gate (dbg_sel_idel_gate), - .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), - .dbg_calib_done (dbg_calib_done), - .dbg_calib_err (dbg_calib_err), - .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), - .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), - .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), - .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), - .dbg_calib_rden_dly (dbg_calib_rden_dly), - .dbg_calib_gate_dly (dbg_calib_gate_dly) - ); - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_ctrl.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_ctrl.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_ctrl.v (nonexistent) @@ -1,1230 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_ctrl.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ 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 MEMCtrl module. Please refer to - // the MEMCtrl 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 (rst_r1) - precharge_ok_cnt_r <= 5'd0; - else 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 - Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_addr_fifo.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_addr_fifo.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_addr_fifo.v (nonexistent) @@ -1,131 +0,0 @@ -//***************************************************************************** -// 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 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_usr_addr_fifo.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Mon Aug 28 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module instantiates the block RAM based FIFO to store the user -// address and the command information. Also calculates potential bank/row -// conflicts by comparing the new address with last address issued. -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_usr_addr_fifo # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter COL_WIDTH = 10, - parameter CS_BITS = 0, - parameter ROW_WIDTH = 14 - ) - ( - input clk0, - input rst0, - input [2:0] app_af_cmd, - input [30:0] app_af_addr, - input app_af_wren, - input ctrl_af_rden, - output [2:0] af_cmd, - output [30:0] af_addr, - output af_empty, - output app_af_afull - ); - - wire [35:0] fifo_data_out; - reg rst_r; - - - always @(posedge clk0) - rst_r <= rst0; - - - //*************************************************************************** - - assign af_cmd = fifo_data_out[33:31]; - assign af_addr = fifo_data_out[30:0]; - - //*************************************************************************** - - FIFO36 # - ( - .ALMOST_EMPTY_OFFSET (13'h0007), - .ALMOST_FULL_OFFSET (13'h000F), - .DATA_WIDTH (36), - .DO_REG (1), - .EN_SYN ("TRUE"), - .FIRST_WORD_FALL_THROUGH ("FALSE") - ) - u_af - ( - .ALMOSTEMPTY (), - .ALMOSTFULL (app_af_afull), - .DO (fifo_data_out[31:0]), - .DOP (fifo_data_out[35:32]), - .EMPTY (af_empty), - .FULL (), - .RDCOUNT (), - .RDERR (), - .WRCOUNT (), - .WRERR (), - .DI ({app_af_cmd[0],app_af_addr}), - .DIP ({2'b00,app_af_cmd[2:1]}), - .RDCLK (clk0), - .RDEN (ctrl_af_rden), - .RST (rst_r), - .WRCLK (clk0), - .WREN (app_af_wren) - ); - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dm_iob.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dm_iob.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dm_iob.v (nonexistent) @@ -1,106 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_dm_iob.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module places the data mask signals into the IOBs. -//Reference: -//Revision History: -// Rev 1.1 - To fix timing issues with Synplicity 9.6.1, syn_preserve -// attribute added for the instance u_dm_ce. PK. 11/11/08 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_phy_dm_iob - ( - input clk90, - input dm_ce, - input mask_data_rise, - input mask_data_fall, - output ddr_dm - ); - - wire dm_out; - wire dm_ce_r; - - FDRSE_1 u_dm_ce - ( - .Q (dm_ce_r), - .C (clk90), - .CE (1'b1), - .D (dm_ce), - .R (1'b0), - .S (1'b0) - ) /* synthesis syn_preserve=1 */; - - ODDR # - ( - .SRTYPE("SYNC"), - .DDR_CLK_EDGE("SAME_EDGE") - ) - u_oddr_dm - ( - .Q (dm_out), - .C (clk90), - .CE (dm_ce_r), - .D1 (mask_data_rise), - .D2 (mask_data_fall), - .R (1'b0), - .S (1'b0) - ); - - OBUF u_obuf_dm - ( - .I (dm_out), - .O (ddr_dm) - ); - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_write.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_write.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_write.v (nonexistent) @@ -1,469 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_write.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Thu Aug 24 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -//Reference: -// Handles delaying various write control signals appropriately depending -// on CAS latency, additive latency, etc. Also splits the data and mask in -// rise and fall buses. -//Revision History: -// Rev 1.1 - For Dual Rank parts support ODT logic corrected. PK. 08/05/08 -// Rev 1.2 - Retain current data pattern for stage 4 calibration, and create -// new pattern for stage 4. RC. 09/21/09. -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_phy_write # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter DQ_WIDTH = 72, - parameter CS_NUM = 1, - parameter ADDITIVE_LAT = 0, - parameter CAS_LAT = 5, - parameter ECC_ENABLE = 0, - parameter ODT_TYPE = 1, - parameter REG_ENABLE = 1, - parameter DDR_TYPE = 1 - ) - ( - input clk0, - input clk90, - input rst90, - input [(2*DQ_WIDTH)-1:0] wdf_data, - input [(2*DQ_WIDTH/8)-1:0] wdf_mask_data, - input ctrl_wren, - input phy_init_wren, - input phy_init_data_sel, - output reg dm_ce, - output reg [1:0] dq_oe_n, - output reg dqs_oe_n , - output reg dqs_rst_n , - output wdf_rden, - output reg [CS_NUM-1:0] odt , - output [DQ_WIDTH-1:0] wr_data_rise, - output [DQ_WIDTH-1:0] wr_data_fall, - output [(DQ_WIDTH/8)-1:0] mask_data_rise, - output [(DQ_WIDTH/8)-1:0] mask_data_fall - ); - - localparam MASK_WIDTH = DQ_WIDTH/8; - localparam DDR1 = 0; - localparam DDR2 = 1; - localparam DDR3 = 2; - - // (MIN,MAX) value of WR_LATENCY for DDR1: - // REG_ENABLE = (0,1) - // ECC_ENABLE = (0,1) - // Write latency = 1 - // Total: (1,3) - // (MIN,MAX) value of WR_LATENCY for DDR2: - // REG_ENABLE = (0,1) - // ECC_ENABLE = (0,1) - // Write latency = ADDITIVE_CAS + CAS_LAT - 1 = (0,4) + (3,5) - 1 = (2,8) - // ADDITIVE_LAT = (0,4) (JEDEC79-2B) - // CAS_LAT = (3,5) (JEDEC79-2B) - // Total: (2,10) - localparam WR_LATENCY = (DDR_TYPE == DDR3) ? - (ADDITIVE_LAT + (CAS_LAT) + REG_ENABLE ) : - (DDR_TYPE == DDR2) ? - (ADDITIVE_LAT + (CAS_LAT-1) + REG_ENABLE ) : - (1 + REG_ENABLE ); - - // NOTE that ODT timing does not need to be delayed for registered - // DIMM case, since like other control/address signals, it gets - // delayed by one clock cycle at the DIMM - localparam ODT_WR_LATENCY = WR_LATENCY - REG_ENABLE; - - wire dm_ce_0; - reg dm_ce_r; - wire [1:0] dq_oe_0; - reg [1:0] dq_oe_n_90_r1; - reg [1:0] dq_oe_270; - wire dqs_oe_0; - reg dqs_oe_270; - reg dqs_oe_n_180_r1; - wire dqs_rst_0; - reg dqs_rst_n_180_r1; - reg dqs_rst_270; - reg ecc_dm_error_r; - reg ecc_dm_error_r1; - reg [(DQ_WIDTH-1):0] init_data_f; - reg [(DQ_WIDTH-1):0] init_data_r; - reg [3:0] init_wdf_cnt_r; - wire odt_0; - reg rst90_r /* synthesis syn_maxfan = 10 */; - reg [10:0] wr_stages ; - reg [(2*DQ_WIDTH)-1:0] wdf_data_r; - reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r; - wire [(2*DQ_WIDTH/8)-1:0] wdf_ecc_mask; - - reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r1; - wire wdf_rden_0; - reg calib_rden_90_r; - reg wdf_rden_90_r; - reg wdf_rden_90_r1; - reg wdf_rden_270; - - always @(posedge clk90) - rst90_r <= rst90; - - //*************************************************************************** - // Analysis of additional pipeline delays: - // 1. dq_oe (DQ 3-state): 1 CLK90 cyc in IOB 3-state FF - // 2. dqs_oe (DQS 3-state): 1 CLK180 cyc in IOB 3-state FF - // 3. dqs_rst (DQS output value reset): 1 CLK180 cyc in FF + 1 CLK180 cyc - // in IOB DDR - // 4. odt (ODT control): 1 CLK0 cyc in IOB FF - // 5. write data (output two cyc after wdf_rden - output of RAMB_FIFO w/ - // output register enabled): 2 CLK90 cyc in OSERDES - //*************************************************************************** - - // DQS 3-state must be asserted one extra clock cycle due b/c of write - // pre- and post-amble (extra half clock cycle for each) - assign dqs_oe_0 = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2]; - - // same goes for ODT, need to handle both pre- and post-amble (generate - // ODT only for DDR2) - // ODT generation for DDR2 based on write latency. The MIN write - // latency is 2. Based on the write latency ODT is asserted. - generate - if ((DDR_TYPE != DDR1) && (ODT_TYPE > 0))begin: gen_odt_ddr2 - if(ODT_WR_LATENCY > 3) - assign odt_0 = - wr_stages[ODT_WR_LATENCY-2] | - wr_stages[ODT_WR_LATENCY-3] | - wr_stages[ODT_WR_LATENCY-4] ; - else if ( ODT_WR_LATENCY == 3) - assign odt_0 = - wr_stages[ODT_WR_LATENCY-1] | - wr_stages[ODT_WR_LATENCY-2] | - wr_stages[ODT_WR_LATENCY-3] ; - else - assign odt_0 = - wr_stages[ODT_WR_LATENCY] | - wr_stages[ODT_WR_LATENCY-1] | - wr_stages[ODT_WR_LATENCY-2] ; - end else - assign odt_0 = 1'b0; - endgenerate - - assign dq_oe_0[0] = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY]; - assign dq_oe_0[1] = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2]; - assign dqs_rst_0 = ~wr_stages[WR_LATENCY-2]; - assign dm_ce_0 = wr_stages[WR_LATENCY] | wr_stages[WR_LATENCY-1] - | wr_stages[WR_LATENCY-2]; - - // write data fifo, read flag assertion - generate - if (DDR_TYPE != DDR1) begin: gen_wdf_ddr2 - if (WR_LATENCY > 2) - assign wdf_rden_0 = wr_stages[WR_LATENCY-3]; - else - assign wdf_rden_0 = wr_stages[WR_LATENCY-2]; - end else begin: gen_wdf_ddr1 - assign wdf_rden_0 = wr_stages[WR_LATENCY-2]; - end - endgenerate - - // first stage isn't registered - always @(*) - wr_stages[0] = (phy_init_data_sel) ? ctrl_wren : phy_init_wren; - - always @(posedge clk0) begin - wr_stages[1] <= wr_stages[0]; - wr_stages[2] <= wr_stages[1]; - wr_stages[3] <= wr_stages[2]; - wr_stages[4] <= wr_stages[3]; - wr_stages[5] <= wr_stages[4]; - wr_stages[6] <= wr_stages[5]; - wr_stages[7] <= wr_stages[6]; - wr_stages[8] <= wr_stages[7]; - wr_stages[9] <= wr_stages[8]; - wr_stages[10] <= wr_stages[9]; - end - - // intermediate synchronization to CLK270 - always @(negedge clk90) begin - dq_oe_270 <= dq_oe_0; - dqs_oe_270 <= dqs_oe_0; - dqs_rst_270 <= dqs_rst_0; - wdf_rden_270 <= wdf_rden_0; - end - - // synchronize DQS signals to CLK180 - always @(negedge clk0) begin - dqs_oe_n_180_r1 <= ~dqs_oe_270; - dqs_rst_n_180_r1 <= ~dqs_rst_270; - end - - // All write data-related signals synced to CLK90 - always @(posedge clk90) begin - dq_oe_n_90_r1 <= ~dq_oe_270; - wdf_rden_90_r <= wdf_rden_270; - end - - // generate for wdf_rden and calib rden. These signals - // are asserted based on write latency. For write - // latency of 2, the extra register stage is taken out. - generate - if (WR_LATENCY > 2) begin - always @(posedge clk90) begin - // assert wdf rden only for non calibration opertations - wdf_rden_90_r1 <= wdf_rden_90_r & - phy_init_data_sel; - // rden for calibration - calib_rden_90_r <= wdf_rden_90_r; - end - end else begin - always @(*) begin - wdf_rden_90_r1 = wdf_rden_90_r - & phy_init_data_sel; - calib_rden_90_r = wdf_rden_90_r; - end - end // else: !if(WR_LATENCY > 2) - endgenerate - - // dm CE signal to stop dm oscilation - always @(negedge clk90)begin - dm_ce_r <= dm_ce_0; - dm_ce <= dm_ce_r; - end - - // When in ECC mode the upper byte [71:64] will have the - // ECC parity. Mapping the bytes which have valid data - // to the upper byte in ecc mode. Also in ecc mode there - // is an extra register stage to account for timing. - - genvar mask_i; - generate - if(ECC_ENABLE) begin - for (mask_i = 0; mask_i < (2*DQ_WIDTH)/72; - mask_i = mask_i+1) begin: gen_mask - assign wdf_ecc_mask[((mask_i*9)+9)-1:(mask_i*9)] = - {&wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9], - wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9]}; - end - end - endgenerate - - generate - if (ECC_ENABLE) begin:gen_ecc_reg - always @(posedge clk90)begin - if(phy_init_data_sel) - wdf_mask_r <= wdf_ecc_mask; - else - wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}}; - end - end else begin - always@(posedge clk90) begin - if (phy_init_data_sel) - wdf_mask_r <= wdf_mask_data; - else - wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}}; - end - end - endgenerate - - always @(posedge clk90) begin - if(phy_init_data_sel) - wdf_data_r <= wdf_data; - else - wdf_data_r <={init_data_f,init_data_r}; - end - - // Error generation block during simulation. - // Error will be displayed when all the DM - // bits are not zero. The error will be - // displayed only during the start of the sequence - // for errors that are continous over many cycles. - generate - if (ECC_ENABLE) begin: gen_ecc_error - always @(posedge clk90) begin - //synthesis translate_off - wdf_mask_r1 <= wdf_mask_r; - if(DQ_WIDTH > 72) - ecc_dm_error_r - <= ( - (~wdf_mask_r1[35] && (|wdf_mask_r1[34:27])) || - (~wdf_mask_r1[26] && (|wdf_mask_r1[25:18])) || - (~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) || - (~wdf_mask_r1[8] && (|wdf_mask_r1[7:0]))) && phy_init_data_sel; - else - ecc_dm_error_r - <= ((~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) || - (~wdf_mask_r1[8] && (|wdf_mask_r1[7:0]))) && phy_init_data_sel; - ecc_dm_error_r1 <= ecc_dm_error_r ; - if (ecc_dm_error_r && ~ecc_dm_error_r1) // assert the error only once. - $display ("ECC DM ERROR. "); - //synthesis translate_on - end - end - endgenerate - - //*************************************************************************** - // State logic to write calibration training patterns - //*************************************************************************** - - always @(posedge clk90) begin - if (rst90_r) begin - init_wdf_cnt_r <= 4'd0; - init_data_r <= {64{1'bx}}; - init_data_f <= {64{1'bx}}; - end else begin - init_wdf_cnt_r <= init_wdf_cnt_r + calib_rden_90_r; - casex (init_wdf_cnt_r) - // First stage calibration. Pattern (rise/fall) = 1(r)->0(f) - // The rise data and fall data are already interleaved in the manner - // required for data into the WDF write FIFO - 4'b00xx: begin - init_data_r <= {DQ_WIDTH{1'b1}}; - init_data_f <= {DQ_WIDTH{1'b0}}; - end - // Second stage calibration. Pattern = 1(r)->1(f)->0(r)->0(f) - 4'b01x0: begin - init_data_r <= {DQ_WIDTH{1'b1}}; - init_data_f <= {DQ_WIDTH{1'b1}}; - end - 4'b01x1: begin - init_data_r <= {DQ_WIDTH{1'b0}}; - init_data_f <= {DQ_WIDTH{1'b0}}; - end - // MIG 3.2: Changed Stage 3/4 training pattern - // Third stage calibration patern = - // 11(r)->ee(f)->ee(r)->11(f)-ee(r)->11(f)->ee(r)->11(f) - 4'b1000: begin - init_data_r <= {DQ_WIDTH/4{4'h1}}; - init_data_f <= {DQ_WIDTH/4{4'hE}}; - end - 4'b1001: begin - init_data_r <= {DQ_WIDTH/4{4'hE}}; - init_data_f <= {DQ_WIDTH/4{4'h1}}; - end - 4'b1010: begin - init_data_r <= {(DQ_WIDTH/4){4'hE}}; - init_data_f <= {(DQ_WIDTH/4){4'h1}}; - end - 4'b1011: begin - init_data_r <= {(DQ_WIDTH/4){4'hE}}; - init_data_f <= {(DQ_WIDTH/4){4'h1}}; - end - // Fourth stage calibration patern = - // 11(r)->ee(f)->ee(r)->11(f)-11(r)->ee(f)->ee(r)->11(f) - 4'b1100: begin - init_data_r <= {DQ_WIDTH/4{4'h1}}; - init_data_f <= {DQ_WIDTH/4{4'hE}}; - end - 4'b1101: begin - init_data_r <= {DQ_WIDTH/4{4'hE}}; - init_data_f <= {DQ_WIDTH/4{4'h1}}; - end - 4'b1110: begin - init_data_r <= {(DQ_WIDTH/4){4'h1}}; - init_data_f <= {(DQ_WIDTH/4){4'hE}}; - end - 4'b1111: begin - // MIG 3.5: Corrected last two writes for stage 4 calibration - // training pattern. Previously MIG 3.3 and MIG 3.4 had the - // incorrect pattern. This can sometimes result in a calibration - // point with small timing margin. -// init_data_r <= {(DQ_WIDTH/4){4'h1}}; -// init_data_f <= {(DQ_WIDTH/4){4'hE}}; - init_data_r <= {(DQ_WIDTH/4){4'hE}}; - init_data_f <= {(DQ_WIDTH/4){4'h1}}; - end - endcase - end - end - - //*************************************************************************** - - always @(posedge clk90) - dq_oe_n <= dq_oe_n_90_r1; - - always @(negedge clk0) - dqs_oe_n <= dqs_oe_n_180_r1; - - always @(negedge clk0) - dqs_rst_n <= dqs_rst_n_180_r1; - - // generate for odt. odt is asserted based on - // write latency. For write latency of 2 - // the extra register stage is taken out. - generate - if (ODT_WR_LATENCY > 3) begin - always @(posedge clk0) begin - odt <= 'b0; - odt[0] <= odt_0; - end - end else begin - always @ (*) begin - odt = 'b0; - odt[0] = odt_0; - end - end - endgenerate - - assign wdf_rden = wdf_rden_90_r1; - - //*************************************************************************** - // Format write data/mask: Data is in format: {fall, rise} - //*************************************************************************** - - assign wr_data_rise = wdf_data_r[DQ_WIDTH-1:0]; - assign wr_data_fall = wdf_data_r[(2*DQ_WIDTH)-1:DQ_WIDTH]; - assign mask_data_rise = wdf_mask_r[MASK_WIDTH-1:0]; - assign mask_data_fall = wdf_mask_r[(2*MASK_WIDTH)-1:MASK_WIDTH]; - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_chipscope.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_chipscope.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_chipscope.v (nonexistent) @@ -1,114 +0,0 @@ -//***************************************************************************** -// 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 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_chipscope.v -// /___/ /\ Date Last Modified: $Data$ -// \ \ / \ Date Created: 9/14/06 -// \___\/\___\ -// -//Device: Virtex-5 -//Purpose: -// Skeleton Chipscope module declarations - for simulation only -//Reference: -//Revision History: -// -//***************************************************************************** - -`timescale 1ns/1ps - -module icon4 - ( - control0, - control1, - control2, - control3 - ) - /* synthesis syn_black_box syn_noprune = 1 */; - output [35:0] control0; - output [35:0] control1; - output [35:0] control2; - output [35:0] control3; -endmodule - -module vio_async_in192 - ( - control, - async_in - ) - /* synthesis syn_black_box syn_noprune = 1 */; - input [35:0] control; - input [191:0] async_in; -endmodule - -module vio_async_in96 - ( - control, - async_in - ) - /* synthesis syn_black_box syn_noprune = 1 */; - input [35:0] control; - input [95:0] async_in; -endmodule - -module vio_async_in100 - ( - control, - async_in - ) - /* synthesis syn_black_box syn_noprune = 1 */; - input [35:0] control; - input [99:0] async_in; -endmodule - -module vio_sync_out32 - ( - control, - clk, - sync_out - ) - /* synthesis syn_black_box syn_noprune = 1 */; - input [35:0] control; - input clk; - output [31:0] sync_out; -endmodule \ No newline at end of file Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dq_iob.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dq_iob.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_phy_dq_iob.v (nonexistent) @@ -1,592 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_phy_dq_iob.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module places the data in the IOBs. -//Reference: -//Revision History: -// Rev 1.1 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 -// Rev 1.2 - DIRT strings removed and modified the code. PK. 11/13/08 -// Rev 1.3 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added -// on IODELAY primitive. PK. 11/27/08 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_phy_dq_iob # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter HIGH_PERFORMANCE_MODE = "TRUE", - parameter IODELAY_GRP = "IODELAY_MIG", - parameter FPGA_SPEED_GRADE = 2 - ) - ( - input clk0, - input clk90, - input clkdiv0, - input rst90, - input dlyinc, - input dlyce, - input dlyrst, - input [1:0] dq_oe_n, - input dqs, - input ce, - input rd_data_sel, - input wr_data_rise, - input wr_data_fall, - output rd_data_rise, - output rd_data_fall, - inout ddr_dq - ); - - wire dq_iddr_clk; - wire dq_idelay; - wire dq_in; - wire dq_oe_n_r; - wire dq_out; - wire stg2a_out_fall; - wire stg2a_out_rise; - (* XIL_PAR_DELAY = "0 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) - wire stg2b_out_fall; - (* XIL_PAR_DELAY = "0 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) - wire stg2b_out_rise; - wire stg3a_out_fall; - wire stg3a_out_rise; - wire stg3b_out_fall; - wire stg3b_out_rise; - - //*************************************************************************** - // Directed routing constraints for route between IDDR and stage 2 capture - // in fabric. - // Only 2 out of the 12 wire declarations will be used for any given - // instantiation of this module. - // Varies according: - // (1) I/O column (left, center, right) used - // (2) Which I/O in I/O pair (master, slave) used - // Nomenclature: _Xy, X = column (0 = left, 1 = center, 2 = right), - // y = master or slave - //*************************************************************************** - - // MODIFIED, RC, 06/13/08: Remove all references to DIRT, master/slave - - (* XIL_PAR_DELAY = "515 ps", XIL_PAR_SKEW = "55 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) - wire stg1_out_rise_sg3; - (* XIL_PAR_DELAY = "515 ps", XIL_PAR_SKEW = "55 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) - wire stg1_out_fall_sg3; - (* XIL_PAR_DELAY = "575 ps", XIL_PAR_SKEW = "65 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) - wire stg1_out_rise_sg2; - (* XIL_PAR_DELAY = "575 ps", XIL_PAR_SKEW = "65 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) - wire stg1_out_fall_sg2; - (* XIL_PAR_DELAY = "650 ps", XIL_PAR_SKEW = "70 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) - wire stg1_out_rise_sg1; - (* XIL_PAR_DELAY = "650 ps", XIL_PAR_SKEW = "70 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) - wire stg1_out_fall_sg1; - - //*************************************************************************** - // Bidirectional I/O - //*************************************************************************** - - IOBUF u_iobuf_dq - ( - .I (dq_out), - .T (dq_oe_n_r), - .IO (ddr_dq), - .O (dq_in) - ); - - //*************************************************************************** - // Write (output) path - //*************************************************************************** - - // on a write, rising edge of DQS corresponds to rising edge of CLK180 - // (aka falling edge of CLK0 -> rising edge DQS). We also know: - // 1. data must be driven 1/4 clk cycle before corresponding DQS edge - // 2. first rising DQS edge driven on falling edge of CLK0 - // 3. rising data must be driven 1/4 cycle before falling edge of CLK0 - // 4. therefore, rising data driven on rising edge of CLK - ODDR # - ( - .SRTYPE("SYNC"), - .DDR_CLK_EDGE("SAME_EDGE") - ) - u_oddr_dq - ( - .Q (dq_out), - .C (clk90), - .CE (1'b1), - .D1 (wr_data_rise), - .D2 (wr_data_fall), - .R (1'b0), - .S (1'b0) - ); - - // make sure output is tri-state during reset (DQ_OE_N_R = 1) - ODDR # - ( - .SRTYPE("ASYNC"), - .DDR_CLK_EDGE("SAME_EDGE") - ) - u_tri_state_dq - ( - .Q (dq_oe_n_r), - .C (clk90), - .CE (1'b1), - .D1 (dq_oe_n[0]), - .D2 (dq_oe_n[1]), - .R (1'b0), - .S (rst90) - ); - - //*************************************************************************** - // Read data capture scheme description: - // Data capture consists of 3 ranks of flops, and a MUX - // 1. Rank 1 ("Stage 1"): IDDR captures delayed DDR DQ from memory using - // delayed DQS. - // - Data is split into 2 SDR streams, one each for rise and fall data. - // - BUFIO (DQS) input inverted to IDDR. IDDR configured in SAME_EDGE - // mode. This means that: (1) Q1 = fall data, Q2 = rise data, - // (2) Both rise and fall data are output on falling edge of DQS - - // rather than rise output being output on one edge of DQS, and fall - // data on the other edge if the IDDR were configured in OPPOSITE_EDGE - // mode. This simplifies Stage 2 capture (only one core clock edge - // used, removing effects of duty-cycle-distortion), and saves one - // fabric flop in Rank 3. - // 2. Rank 2 ("Stage 2"): Fabric flops are used to capture output of first - // rank into FPGA clock (CLK) domain. Each rising/falling SDR stream - // from IDDR is feed into two flops, one clocked off rising and one off - // falling edge of CLK. One of these flops is chosen, with the choice - // being the one that reduces # of DQ/DQS taps necessary to align Stage - // 1 and Stage 2. Same edge is used to capture both rise and fall SDR - // streams. - // 3. Rank 3 ("Stage 3"): Removes half-cycle paths in CLK domain from - // output of Rank 2. This stage, like Stage 2, is clocked by CLK. Note - // that Stage 3 can be expanded to also support SERDES functionality - // 4. Output MUX: Selects whether Stage 1 output is aligned to rising or - // falling edge of CLK (i.e. specifically this selects whether IDDR - // rise/fall output is transfered to rising or falling edge of CLK). - // Implementation: - // 1. Rank 1 is implemented using an IDDR primitive - // 2. Rank 2 is implemented using: - // - An RPM to fix the location of the capture flops near the DQ I/O. - // The exact RPM used depends on which I/O column (left, center, - // right) the DQ I/O is placed at - this affects the optimal location - // of the slice flops (or does it - can we always choose the two - // columns to slices to the immediate right of the I/O to use, no - // matter what the column?). The origin of the RPM must be set in the - // UCF file using the RLOC_ORIGIN constraint (where the original is - // based on the DQ I/O location). - // - Directed Routing Constraints ("DIRT strings") to fix the routing - // to the rank 2 fabric flops. This is done to minimize: (1) total - // route delay (and therefore minimize voltage/temperature-related - // variations), and (2) minimize skew both within each rising and - // falling data net, as well as between the rising and falling nets. - // The exact DIRT string used depends on: (1) which I/O column the - // DQ I/O is placed, and (2) whether the DQ I/O is placed on the - // "Master" or "Slave" I/O of a diff pair (DQ is not differential, but - // the routing will be affected by which of each I/O pair is used) - // 3. Rank 3 is implemented using fabric flops. No LOC or DIRT contraints - // are used, tools are expected to place these and meet PERIOD timing - // without constraints (constraints may be necessary for "full" designs, - // in this case, user may need to add LOC constraints - if this is the - // case, there are no constraints - other than meeting PERIOD timing - - // for rank 3 flops. - //*************************************************************************** - - //*************************************************************************** - // MIG 2.2: Define AREA_GROUP = "DDR_CAPTURE_FFS" contain all RPM flops in - // design. In UCF file, add constraint: - // AREA_GROUP "DDR_CAPTURE_FFS" GROUP = CLOSED; - // This is done to prevent MAP from packing unrelated logic into - // the slices used by the RPMs. Doing so may cause the DIRT strings - // that define the IDDR -> fabric flop routing to later become - // unroutable during PAR because the unrelated logic placed by MAP - // may use routing resources required by the DIRT strings. MAP - // does not currently take into account DIRT strings when placing - // logic - //*************************************************************************** - - // IDELAY to delay incoming data for synchronization purposes - (* IODELAY_GROUP = IODELAY_GRP *) IODELAY # - ( - .DELAY_SRC ("I"), - .IDELAY_TYPE ("VARIABLE"), - .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), - .IDELAY_VALUE (0), - .ODELAY_VALUE (0) - ) - u_idelay_dq - ( - .DATAOUT (dq_idelay), - .C (clkdiv0), - .CE (dlyce), - .DATAIN (), - .IDATAIN (dq_in), - .INC (dlyinc), - .ODATAIN (), - .RST (dlyrst), - .T () - ); - - //*************************************************************************** - // Rank 1 capture: Use IDDR to generate two SDR outputs - //*************************************************************************** - - // invert clock to IDDR in order to use SAME_EDGE mode (otherwise, we "run - // out of clocks" because DQS is not continuous - assign dq_iddr_clk = ~dqs; - - //*************************************************************************** - // Rank 2 capture: Use fabric flops to capture Rank 1 output. Use RPM and - // DIRT strings here. - // BEL ("Basic Element of Logic") and relative location constraints for - // second stage capture. C - // Varies according: - // (1) I/O column (left, center, right) used - // (2) Which I/O in I/O pair (master, slave) used - //*************************************************************************** - - // MODIFIED, RC, 06/13/08: Remove all references to DIRT, master/slave - // Take out generate statements - collapses to a single case - - generate - if (FPGA_SPEED_GRADE == 3) begin: gen_stg2_sg3 - IDDR # - ( - .DDR_CLK_EDGE ("SAME_EDGE") - ) - u_iddr_dq - ( - .Q1 (stg1_out_fall_sg3), - .Q2 (stg1_out_rise_sg3), - .C (dq_iddr_clk), - .CE (ce), - .D (dq_idelay), - .R (1'b0), - .S (1'b0) - ); - - //********************************************************* - // Slice #1 (posedge CLK): Used for: - // 1. IDDR transfer to CLK0 rising edge domain ("stg2a") - // 2. stg2 falling edge -> stg3 rising edge transfer - //********************************************************* - - // Stage 2 capture - FDRSE u_ff_stg2a_fall - ( - .Q (stg2a_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg1_out_fall_sg3), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - FDRSE u_ff_stg2a_rise - ( - .Q (stg2a_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg1_out_rise_sg3), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - // Stage 3 falling -> rising edge translation - FDRSE u_ff_stg3b_fall - ( - .Q (stg3b_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg2b_out_fall), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - FDRSE u_ff_stg3b_rise - ( - .Q (stg3b_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg2b_out_rise), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - - //********************************************************* - // Slice #2 (posedge CLK): Used for: - // 1. IDDR transfer to CLK0 falling edge domain ("stg2b") - //********************************************************* - - FDRSE_1 u_ff_stg2b_fall - ( - .Q (stg2b_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg1_out_fall_sg3), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - - FDRSE_1 u_ff_stg2b_rise - ( - .Q (stg2b_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg1_out_rise_sg3), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - end else if (FPGA_SPEED_GRADE == 2) begin: gen_stg2_sg2 - IDDR # - ( - .DDR_CLK_EDGE ("SAME_EDGE") - ) - u_iddr_dq - ( - .Q1 (stg1_out_fall_sg2), - .Q2 (stg1_out_rise_sg2), - .C (dq_iddr_clk), - .CE (ce), - .D (dq_idelay), - .R (1'b0), - .S (1'b0) - ); - - //********************************************************* - // Slice #1 (posedge CLK): Used for: - // 1. IDDR transfer to CLK0 rising edge domain ("stg2a") - // 2. stg2 falling edge -> stg3 rising edge transfer - //********************************************************* - - // Stage 2 capture - FDRSE u_ff_stg2a_fall - ( - .Q (stg2a_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg1_out_fall_sg2), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - FDRSE u_ff_stg2a_rise - ( - .Q (stg2a_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg1_out_rise_sg2), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - // Stage 3 falling -> rising edge translation - FDRSE u_ff_stg3b_fall - ( - .Q (stg3b_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg2b_out_fall), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - FDRSE u_ff_stg3b_rise - ( - .Q (stg3b_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg2b_out_rise), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - - //********************************************************* - // Slice #2 (posedge CLK): Used for: - // 1. IDDR transfer to CLK0 falling edge domain ("stg2b") - //********************************************************* - - FDRSE_1 u_ff_stg2b_fall - ( - .Q (stg2b_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg1_out_fall_sg2), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - - FDRSE_1 u_ff_stg2b_rise - ( - .Q (stg2b_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg1_out_rise_sg2), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - end else if (FPGA_SPEED_GRADE == 1) begin: gen_stg2_sg1 - IDDR # - ( - .DDR_CLK_EDGE ("SAME_EDGE") - ) - u_iddr_dq - ( - .Q1 (stg1_out_fall_sg1), - .Q2 (stg1_out_rise_sg1), - .C (dq_iddr_clk), - .CE (ce), - .D (dq_idelay), - .R (1'b0), - .S (1'b0) - ); - - //********************************************************* - // Slice #1 (posedge CLK): Used for: - // 1. IDDR transfer to CLK0 rising edge domain ("stg2a") - // 2. stg2 falling edge -> stg3 rising edge transfer - //********************************************************* - - // Stage 2 capture - FDRSE u_ff_stg2a_fall - ( - .Q (stg2a_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg1_out_fall_sg1), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - FDRSE u_ff_stg2a_rise - ( - .Q (stg2a_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg1_out_rise_sg1), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - // Stage 3 falling -> rising edge translation - FDRSE u_ff_stg3b_fall - ( - .Q (stg3b_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg2b_out_fall), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - FDRSE u_ff_stg3b_rise - ( - .Q (stg3b_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg2b_out_rise), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - - //********************************************************* - // Slice #2 (posedge CLK): Used for: - // 1. IDDR transfer to CLK0 falling edge domain ("stg2b") - //********************************************************* - - FDRSE_1 u_ff_stg2b_fall - ( - .Q (stg2b_out_fall), - .C (clk0), - .CE (1'b1), - .D (stg1_out_fall_sg1), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - - FDRSE_1 u_ff_stg2b_rise - ( - .Q (stg2b_out_rise), - .C (clk0), - .CE (1'b1), - .D (stg1_out_rise_sg1), - .R (1'b0), - .S (1'b0) - )/* synthesis syn_preserve = 1 */ - /* synthesis syn_replicate = 0 */; - end - endgenerate - - //*************************************************************************** - // Second stage flops clocked by posedge CLK0 don't need another layer of - // registering - //*************************************************************************** - - assign stg3a_out_rise = stg2a_out_rise; - assign stg3a_out_fall = stg2a_out_fall; - - //******************************************************************* - - assign rd_data_rise = (rd_data_sel) ? stg3a_out_rise : stg3b_out_rise; - assign rd_data_fall = (rd_data_sel) ? stg3a_out_fall : stg3b_out_fall; - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_mem_if_top.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_mem_if_top.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_mem_if_top.v (nonexistent) @@ -1,380 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_mem_if_top.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR/DDR2 -//Purpose: -// Top-level for parameterizable (DDR or DDR2) memory interface -//Reference: -//Revision History: -// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 -// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 -// Rev 1.3 - Parameter CS_BITS added. PK. 10/8/08 -// Rev 1.4 - Parameter IODELAY_GRP added. PK. 11/27/08 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_mem_if_top # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter CKE_WIDTH = 1, - parameter CLK_WIDTH = 1, - parameter COL_WIDTH = 10, - parameter CS_BITS = 0, - parameter CS_NUM = 1, - parameter CS_WIDTH = 1, - parameter USE_DM_PORT = 1, - parameter DM_WIDTH = 9, - parameter DQ_WIDTH = 72, - parameter DQ_BITS = 7, - parameter DQ_PER_DQS = 8, - parameter DQS_BITS = 4, - parameter DQS_WIDTH = 9, - parameter HIGH_PERFORMANCE_MODE = "TRUE", - parameter IODELAY_GRP = "IODELAY_MIG", - parameter ODT_WIDTH = 1, - parameter ROW_WIDTH = 14, - parameter APPDATA_WIDTH = 144, - parameter ADDITIVE_LAT = 0, - parameter BURST_LEN = 4, - parameter BURST_TYPE = 0, - parameter CAS_LAT = 5, - parameter ECC_ENABLE = 0, - parameter MULTI_BANK_EN = 1, - parameter TWO_T_TIME_EN = 0, - parameter ODT_TYPE = 1, - parameter DDR_TYPE = 1, - parameter REDUCE_DRV = 0, - parameter REG_ENABLE = 1, - parameter TREFI_NS = 7800, - parameter TRAS = 40000, - parameter TRCD = 15000, - parameter TRFC = 105000, - parameter TRP = 15000, - parameter TRTP = 7500, - parameter TWR = 15000, - parameter TWTR = 10000, - parameter CLK_PERIOD = 3000, - parameter SIM_ONLY = 0, - parameter DEBUG_EN = 0, - parameter FPGA_SPEED_GRADE = 2 - ) - ( - input clk0, - input clk90, - input clkdiv0, - input rst0, - input rst90, - input rstdiv0, - input [2:0] app_af_cmd, - input [30:0] app_af_addr, - input app_af_wren, - input app_wdf_wren, - input [APPDATA_WIDTH-1:0] app_wdf_data, - input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, - output [1:0] rd_ecc_error, - output app_af_afull, - output app_wdf_afull, - output rd_data_valid, - output [APPDATA_WIDTH-1:0] rd_data_fifo_out, - output phy_init_done, - output [CLK_WIDTH-1:0] ddr_ck, - output [CLK_WIDTH-1:0] ddr_ck_n, - output [ROW_WIDTH-1:0] ddr_addr, - output [BANK_WIDTH-1:0] ddr_ba, - output ddr_ras_n, - output ddr_cas_n, - output ddr_we_n, - output [CS_WIDTH-1:0] ddr_cs_n, - output [CKE_WIDTH-1:0] ddr_cke, - output [ODT_WIDTH-1:0] ddr_odt, - output [DM_WIDTH-1:0] ddr_dm, - inout [DQS_WIDTH-1:0] ddr_dqs, - inout [DQS_WIDTH-1:0] ddr_dqs_n, - inout [DQ_WIDTH-1:0] ddr_dq, - // Debug signals (optional use) - input dbg_idel_up_all, - input dbg_idel_down_all, - input dbg_idel_up_dq, - input dbg_idel_down_dq, - input dbg_idel_up_dqs, - input dbg_idel_down_dqs, - input dbg_idel_up_gate, - input dbg_idel_down_gate, - input [DQ_BITS-1:0] dbg_sel_idel_dq, - input dbg_sel_all_idel_dq, - input [DQS_BITS:0] dbg_sel_idel_dqs, - input dbg_sel_all_idel_dqs, - input [DQS_BITS:0] dbg_sel_idel_gate, - input dbg_sel_all_idel_gate, - output [3:0] dbg_calib_done, - output [3:0] dbg_calib_err, - output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, - output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, - output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, - output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, - output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly - ); - - wire [30:0] af_addr; - wire [2:0] af_cmd; - wire af_empty; - wire [ROW_WIDTH-1:0] ctrl_addr; - wire ctrl_af_rden; - wire [BANK_WIDTH-1:0] ctrl_ba; - wire ctrl_cas_n; - wire [CS_NUM-1:0] ctrl_cs_n; - wire ctrl_ras_n; - wire ctrl_rden; - wire ctrl_ref_flag; - wire ctrl_we_n; - wire ctrl_wren; - wire [DQS_WIDTH-1:0] phy_calib_rden; - wire [DQS_WIDTH-1:0] phy_calib_rden_sel; - wire [DQ_WIDTH-1:0] rd_data_fall; - wire [DQ_WIDTH-1:0] rd_data_rise; - wire [(2*DQ_WIDTH)-1:0] wdf_data; - wire [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data; - wire wdf_rden; - - //*************************************************************************** - - ddr2_phy_top # - ( - .BANK_WIDTH (BANK_WIDTH), - .CKE_WIDTH (CKE_WIDTH), - .CLK_WIDTH (CLK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_BITS (CS_BITS), - .CS_NUM (CS_NUM), - .CS_WIDTH (CS_WIDTH), - .USE_DM_PORT (USE_DM_PORT), - .DM_WIDTH (DM_WIDTH), - .DQ_WIDTH (DQ_WIDTH), - .DQ_BITS (DQ_BITS), - .DQ_PER_DQS (DQ_PER_DQS), - .DQS_BITS (DQS_BITS), - .DQS_WIDTH (DQS_WIDTH), - .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), - .IODELAY_GRP (IODELAY_GRP), - .ODT_WIDTH (ODT_WIDTH), - .ROW_WIDTH (ROW_WIDTH), - .TWO_T_TIME_EN (TWO_T_TIME_EN), - .ADDITIVE_LAT (ADDITIVE_LAT), - .BURST_LEN (BURST_LEN), - .BURST_TYPE (BURST_TYPE), - .CAS_LAT (CAS_LAT), - .ECC_ENABLE (ECC_ENABLE), - .ODT_TYPE (ODT_TYPE), - .DDR_TYPE (DDR_TYPE), - .REDUCE_DRV (REDUCE_DRV), - .REG_ENABLE (REG_ENABLE), - .TWR (TWR), - .CLK_PERIOD (CLK_PERIOD), - .SIM_ONLY (SIM_ONLY), - .DEBUG_EN (DEBUG_EN), - .FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) - ) - u_phy_top - ( - .clk0 (clk0), - .clk90 (clk90), - .clkdiv0 (clkdiv0), - .rst0 (rst0), - .rst90 (rst90), - .rstdiv0 (rstdiv0), - .ctrl_wren (ctrl_wren), - .ctrl_addr (ctrl_addr), - .ctrl_ba (ctrl_ba), - .ctrl_ras_n (ctrl_ras_n), - .ctrl_cas_n (ctrl_cas_n), - .ctrl_we_n (ctrl_we_n), - .ctrl_cs_n (ctrl_cs_n), - .ctrl_rden (ctrl_rden), - .ctrl_ref_flag (ctrl_ref_flag), - .wdf_data (wdf_data), - .wdf_mask_data (wdf_mask_data), - .wdf_rden (wdf_rden), - .phy_init_done (phy_init_done), - .phy_calib_rden (phy_calib_rden), - .phy_calib_rden_sel (phy_calib_rden_sel), - .rd_data_rise (rd_data_rise), - .rd_data_fall (rd_data_fall), - .ddr_ck (ddr_ck), - .ddr_ck_n (ddr_ck_n), - .ddr_addr (ddr_addr), - .ddr_ba (ddr_ba), - .ddr_ras_n (ddr_ras_n), - .ddr_cas_n (ddr_cas_n), - .ddr_we_n (ddr_we_n), - .ddr_cs_n (ddr_cs_n), - .ddr_cke (ddr_cke), - .ddr_odt (ddr_odt), - .ddr_dm (ddr_dm), - .ddr_dqs (ddr_dqs), - .ddr_dqs_n (ddr_dqs_n), - .ddr_dq (ddr_dq), - .dbg_idel_up_all (dbg_idel_up_all), - .dbg_idel_down_all (dbg_idel_down_all), - .dbg_idel_up_dq (dbg_idel_up_dq), - .dbg_idel_down_dq (dbg_idel_down_dq), - .dbg_idel_up_dqs (dbg_idel_up_dqs), - .dbg_idel_down_dqs (dbg_idel_down_dqs), - .dbg_idel_up_gate (dbg_idel_up_gate), - .dbg_idel_down_gate (dbg_idel_down_gate), - .dbg_sel_idel_dq (dbg_sel_idel_dq), - .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), - .dbg_sel_idel_dqs (dbg_sel_idel_dqs), - .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), - .dbg_sel_idel_gate (dbg_sel_idel_gate), - .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), - .dbg_calib_done (dbg_calib_done), - .dbg_calib_err (dbg_calib_err), - .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), - .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), - .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), - .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), - .dbg_calib_rden_dly (dbg_calib_rden_dly), - .dbg_calib_gate_dly (dbg_calib_gate_dly) - ); - - ddr2_usr_top # - ( - .BANK_WIDTH (BANK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_BITS (CS_BITS), - .DQ_WIDTH (DQ_WIDTH), - .DQ_PER_DQS (DQ_PER_DQS), - .DQS_WIDTH (DQS_WIDTH), - .APPDATA_WIDTH (APPDATA_WIDTH), - .ECC_ENABLE (ECC_ENABLE), - .ROW_WIDTH (ROW_WIDTH) - ) - u_usr_top - ( - .clk0 (clk0), - .clk90 (clk90), - .rst0 (rst0), - .rd_data_in_rise (rd_data_rise), - .rd_data_in_fall (rd_data_fall), - .phy_calib_rden (phy_calib_rden), - .phy_calib_rden_sel(phy_calib_rden_sel), - .rd_data_valid (rd_data_valid), - .rd_ecc_error (rd_ecc_error), - .rd_data_fifo_out (rd_data_fifo_out), - .app_af_cmd (app_af_cmd), - .app_af_addr (app_af_addr), - .app_af_wren (app_af_wren), - .ctrl_af_rden (ctrl_af_rden), - .af_cmd (af_cmd), - .af_addr (af_addr), - .af_empty (af_empty), - .app_af_afull (app_af_afull), - .app_wdf_wren (app_wdf_wren), - .app_wdf_data (app_wdf_data), - .app_wdf_mask_data (app_wdf_mask_data), - .wdf_rden (wdf_rden), - .app_wdf_afull (app_wdf_afull), - .wdf_data (wdf_data), - .wdf_mask_data (wdf_mask_data) - ); - - - ddr2_ctrl # - ( - .BANK_WIDTH (BANK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .CS_BITS (CS_BITS), - .CS_NUM (CS_NUM), - .ROW_WIDTH (ROW_WIDTH), - .ADDITIVE_LAT (ADDITIVE_LAT), - .BURST_LEN (BURST_LEN), - .CAS_LAT (CAS_LAT), - .ECC_ENABLE (ECC_ENABLE), - .REG_ENABLE (REG_ENABLE), - .MULTI_BANK_EN (MULTI_BANK_EN), - .TWO_T_TIME_EN (TWO_T_TIME_EN), - .TREFI_NS (TREFI_NS), - .TRAS (TRAS), - .TRCD (TRCD), - .TRFC (TRFC), - .TRP (TRP), - .TRTP (TRTP), - .TWR (TWR), - .TWTR (TWTR), - .CLK_PERIOD (CLK_PERIOD), - .DDR_TYPE (DDR_TYPE) - ) - u_ctrl - ( - .clk (clk0), - .rst (rst0), - .af_cmd (af_cmd), - .af_addr (af_addr), - .af_empty (af_empty), - .phy_init_done (phy_init_done), - .ctrl_ref_flag (ctrl_ref_flag), - .ctrl_af_rden (ctrl_af_rden), - .ctrl_wren (ctrl_wren), - .ctrl_rden (ctrl_rden), - .ctrl_addr (ctrl_addr), - .ctrl_ba (ctrl_ba), - .ctrl_ras_n (ctrl_ras_n), - .ctrl_cas_n (ctrl_cas_n), - .ctrl_we_n (ctrl_we_n), - .ctrl_cs_n (ctrl_cs_n) - ); - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_infrastructure.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_infrastructure.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_infrastructure.v (nonexistent) @@ -1,150 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_infrastructure.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Wed Aug 16 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// Clock distribution and reset synchronization -//Reference: -//Revision History: -// Rev 1.1 - Port name changed from dcm_lock to locked. PK. 10/14/08 -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_infrastructure # - ( - parameter RST_ACT_LOW = 1 - ) - ( - input clk0, - input clk90, - input clk200, - input clkdiv0, - input locked, - input sys_rst_n, - input idelay_ctrl_rdy, - output rst0, - output rst90, - output rst200, - output rstdiv0 - ); - - // # of clock cycles to delay deassertion of reset. Needs to be a fairly - // high number not so much for metastability protection, but to give time - // for reset (i.e. stable clock cycles) to propagate through all state - // machines and to all control signals (i.e. not all control signals have - // resets, instead they rely on base state logic being reset, and the effect - // of that reset propagating through the logic). Need this because we may not - // be getting stable clock cycles while reset asserted (i.e. since reset - // depends on DCM lock status) - localparam RST_SYNC_NUM = 25; - - reg [RST_SYNC_NUM-1:0] rst0_sync_r /* synthesis syn_maxfan = 10 */; - reg [RST_SYNC_NUM-1:0] rst200_sync_r /* synthesis syn_maxfan = 10 */; - reg [RST_SYNC_NUM-1:0] rst90_sync_r /* synthesis syn_maxfan = 10 */; - reg [(RST_SYNC_NUM/2)-1:0] rstdiv0_sync_r /* synthesis syn_maxfan = 10 */; - wire rst_tmp; - wire sys_clk_ibufg; - wire sys_rst; - - assign sys_rst = RST_ACT_LOW ? ~sys_rst_n: sys_rst_n; - - //*************************************************************************** - // Reset synchronization - // NOTES: - // 1. shut down the whole operation if the DCM hasn't yet locked (and by - // inference, this means that external SYS_RST_IN has been asserted - - // DCM deasserts LOCKED as soon as SYS_RST_IN asserted) - // 2. In the case of all resets except rst200, also assert reset if the - // IDELAY master controller is not yet ready - // 3. asynchronously assert reset. This was we can assert reset even if - // there is no clock (needed for things like 3-stating output buffers). - // reset deassertion is synchronous. - //*************************************************************************** - - assign rst_tmp = sys_rst | ~locked | ~idelay_ctrl_rdy; - - // synthesis attribute max_fanout of rst0_sync_r is 10 - always @(posedge clk0 or posedge rst_tmp) - if (rst_tmp) - rst0_sync_r <= {RST_SYNC_NUM{1'b1}}; - else - // logical left shift by one (pads with 0) - rst0_sync_r <= rst0_sync_r << 1; - - // synthesis attribute max_fanout of rstdiv0_sync_r is 10 - always @(posedge clkdiv0 or posedge rst_tmp) - if (rst_tmp) - rstdiv0_sync_r <= {(RST_SYNC_NUM/2){1'b1}}; - else - // logical left shift by one (pads with 0) - rstdiv0_sync_r <= rstdiv0_sync_r << 1; - - // synthesis attribute max_fanout of rst90_sync_r is 10 - always @(posedge clk90 or posedge rst_tmp) - if (rst_tmp) - rst90_sync_r <= {RST_SYNC_NUM{1'b1}}; - else - rst90_sync_r <= rst90_sync_r << 1; - - // make sure CLK200 doesn't depend on IDELAY_CTRL_RDY, else chicken n' egg - // synthesis attribute max_fanout of rst200_sync_r is 10 - always @(posedge clk200 or negedge locked) - if (!locked) - rst200_sync_r <= {RST_SYNC_NUM{1'b1}}; - else - rst200_sync_r <= rst200_sync_r << 1; - - assign rst0 = rst0_sync_r[RST_SYNC_NUM-1]; - assign rst90 = rst90_sync_r[RST_SYNC_NUM-1]; - assign rst200 = rst200_sync_r[RST_SYNC_NUM-1]; - assign rstdiv0 = rstdiv0_sync_r[(RST_SYNC_NUM/2)-1]; - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_wr.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_wr.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl/ddr2_usr_wr.v (nonexistent) @@ -1,334 +0,0 @@ -//***************************************************************************** -// 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 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_usr_wr.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Mon Aug 28 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR/DDR2 -//Purpose: -// This module instantiates the modules containing internal FIFOs -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_usr_wr # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter COL_WIDTH = 10, - parameter CS_BITS = 0, - parameter DQ_WIDTH = 72, - parameter APPDATA_WIDTH = 144, - parameter ECC_ENABLE = 0, - parameter ROW_WIDTH = 14 - ) - ( - input clk0, - input clk90, - input rst0, - // Write data FIFO interface - input app_wdf_wren, - input [APPDATA_WIDTH-1:0] app_wdf_data, - input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, - input wdf_rden, - output app_wdf_afull, - output [(2*DQ_WIDTH)-1:0] wdf_data, - output [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data - ); - - // determine number of FIFO72's to use based on data width - // round up to next integer value when determining WDF_FIFO_NUM - localparam WDF_FIFO_NUM = (ECC_ENABLE) ? (APPDATA_WIDTH+63)/64 : - ((2*DQ_WIDTH)+63)/64; - // MASK_WIDTH = number of bytes in data bus - localparam MASK_WIDTH = DQ_WIDTH/8; - - wire [WDF_FIFO_NUM-1:0] i_wdf_afull; - wire [DQ_WIDTH-1:0] i_wdf_data_fall_in; - wire [DQ_WIDTH-1:0] i_wdf_data_fall_out; - wire [(64*WDF_FIFO_NUM)-1:0] i_wdf_data_in; - wire [(64*WDF_FIFO_NUM)-1:0] i_wdf_data_out; - wire [DQ_WIDTH-1:0] i_wdf_data_rise_in; - wire [DQ_WIDTH-1:0] i_wdf_data_rise_out; - wire [MASK_WIDTH-1:0] i_wdf_mask_data_fall_in; - wire [MASK_WIDTH-1:0] i_wdf_mask_data_fall_out; - wire [(8*WDF_FIFO_NUM)-1:0] i_wdf_mask_data_in; - wire [(8*WDF_FIFO_NUM)-1:0] i_wdf_mask_data_out; - wire [MASK_WIDTH-1:0] i_wdf_mask_data_rise_in; - wire [MASK_WIDTH-1:0] i_wdf_mask_data_rise_out; - reg rst_r; - - // ECC signals - wire [(2*DQ_WIDTH)-1:0] i_wdf_data_out_ecc; - wire [((2*DQ_WIDTH)/8)-1:0] i_wdf_mask_data_out_ecc; - wire [63:0] i_wdf_mask_data_out_ecc_wire; - wire [((2*DQ_WIDTH)/8)-1:0] mask_data_in_ecc; - wire [63:0] mask_data_in_ecc_wire; - - //*************************************************************************** - - assign app_wdf_afull = i_wdf_afull[0]; - - always @(posedge clk0 ) - rst_r <= rst0; - - genvar wdf_di_i; - genvar wdf_do_i; - genvar mask_i; - genvar wdf_i; - generate - if(ECC_ENABLE) begin // ECC code - - assign wdf_data = i_wdf_data_out_ecc; - - // the byte 9 dm is always held to 0 - assign wdf_mask_data = i_wdf_mask_data_out_ecc; - - - - // generate for write data fifo . - for (wdf_i = 0; wdf_i < WDF_FIFO_NUM; wdf_i = wdf_i + 1) begin: gen_wdf - - FIFO36_72 # - ( - .ALMOST_EMPTY_OFFSET (9'h007), - .ALMOST_FULL_OFFSET (9'h00F), - .DO_REG (1), // extra CC output delay - .EN_ECC_WRITE ("TRUE"), - .EN_ECC_READ ("FALSE"), - .EN_SYN ("FALSE"), - .FIRST_WORD_FALL_THROUGH ("FALSE") - ) - u_wdf_ecc - ( - .ALMOSTEMPTY (), - .ALMOSTFULL (i_wdf_afull[wdf_i]), - .DBITERR (), - .DO (i_wdf_data_out_ecc[((64*(wdf_i+1))+(wdf_i *8))-1: - (64*wdf_i)+(wdf_i *8)]), - .DOP (i_wdf_data_out_ecc[(72*(wdf_i+1))-1: - (64*(wdf_i+1))+ (8*wdf_i) ]), - .ECCPARITY (), - .EMPTY (), - .FULL (), - .RDCOUNT (), - .RDERR (), - .SBITERR (), - .WRCOUNT (), - .WRERR (), - .DI (app_wdf_data[(64*(wdf_i+1))-1: - (64*wdf_i)]), - .DIP (), - .RDCLK (clk90), - .RDEN (wdf_rden), - .RST (rst_r), // or can use rst0 - .WRCLK (clk0), - .WREN (app_wdf_wren) - ); - end - - // remapping the mask data. The mask data from user i/f does not have - // the mask for the ECC byte. Assigning 0 to the ECC mask byte. - for (mask_i = 0; mask_i < (DQ_WIDTH)/36; - mask_i = mask_i +1) begin: gen_mask - assign mask_data_in_ecc[((8*(mask_i+1))+ mask_i)-1:((8*mask_i)+mask_i)] - = app_wdf_mask_data[(8*(mask_i+1))-1:8*(mask_i)] ; - assign mask_data_in_ecc[((8*(mask_i+1))+mask_i)] = 1'd0; - end - - // assign ecc bits to temp variables to avoid - // sim warnings. Not all the 64 bits of the fifo - // are used in ECC mode. - assign mask_data_in_ecc_wire[((2*DQ_WIDTH)/8)-1:0] = mask_data_in_ecc; - assign mask_data_in_ecc_wire[63:((2*DQ_WIDTH)/8)] = - {(64-((2*DQ_WIDTH)/8)){1'b0}}; - assign i_wdf_mask_data_out_ecc = - i_wdf_mask_data_out_ecc_wire[((2*DQ_WIDTH)/8)-1:0]; - - - FIFO36_72 # - ( - .ALMOST_EMPTY_OFFSET (9'h007), - .ALMOST_FULL_OFFSET (9'h00F), - .DO_REG (1), // extra CC output delay - .EN_ECC_WRITE ("TRUE"), - .EN_ECC_READ ("FALSE"), - .EN_SYN ("FALSE"), - .FIRST_WORD_FALL_THROUGH ("FALSE") - ) - u_wdf_ecc_mask - ( - .ALMOSTEMPTY (), - .ALMOSTFULL (), - .DBITERR (), - .DO (i_wdf_mask_data_out_ecc_wire), - .DOP (), - .ECCPARITY (), - .EMPTY (), - .FULL (), - .RDCOUNT (), - .RDERR (), - .SBITERR (), - .WRCOUNT (), - .WRERR (), - .DI (mask_data_in_ecc_wire), - .DIP (), - .RDCLK (clk90), - .RDEN (wdf_rden), - .RST (rst_r), // or can use rst0 - .WRCLK (clk0), - .WREN (app_wdf_wren) - ); - end else begin - - //*********************************************************************** - - // Define intermediate buses: - assign i_wdf_data_rise_in - = app_wdf_data[DQ_WIDTH-1:0]; - assign i_wdf_data_fall_in - = app_wdf_data[(2*DQ_WIDTH)-1:DQ_WIDTH]; - assign i_wdf_mask_data_rise_in - = app_wdf_mask_data[MASK_WIDTH-1:0]; - assign i_wdf_mask_data_fall_in - = app_wdf_mask_data[(2*MASK_WIDTH)-1:MASK_WIDTH]; - - //*********************************************************************** - // Write data FIFO Input: - // Arrange DQ's so that the rise data and fall data are interleaved. - // the data arrives at the input of the wdf fifo as {fall,rise}. - // It is remapped as: - // {...fall[15:8],rise[15:8],fall[7:0],rise[7:0]} - // This is done to avoid having separate fifo's for rise and fall data - // and to keep rise/fall data for the same DQ's on same FIFO - // Data masks are interleaved in a similar manner - // NOTE: Initialization data from PHY_INIT module does not need to be - // interleaved - it's already in the correct format - and the same - // initialization pattern from PHY_INIT is sent to all write FIFOs - //*********************************************************************** - - for (wdf_di_i = 0; wdf_di_i < MASK_WIDTH; - wdf_di_i = wdf_di_i + 1) begin: gen_wdf_data_in - assign i_wdf_data_in[(16*wdf_di_i)+15:(16*wdf_di_i)] - = {i_wdf_data_fall_in[(8*wdf_di_i)+7:(8*wdf_di_i)], - i_wdf_data_rise_in[(8*wdf_di_i)+7:(8*wdf_di_i)]}; - assign i_wdf_mask_data_in[(2*wdf_di_i)+1:(2*wdf_di_i)] - = {i_wdf_mask_data_fall_in[wdf_di_i], - i_wdf_mask_data_rise_in[wdf_di_i]}; - end - - //*********************************************************************** - // Write data FIFO Output: - // FIFO DQ and mask outputs must be untangled and put in the standard - // format of {fall,rise}. Same goes for mask output - //*********************************************************************** - - for (wdf_do_i = 0; wdf_do_i < MASK_WIDTH; - wdf_do_i = wdf_do_i + 1) begin: gen_wdf_data_out - assign i_wdf_data_rise_out[(8*wdf_do_i)+7:(8*wdf_do_i)] - = i_wdf_data_out[(16*wdf_do_i)+7:(16*wdf_do_i)]; - assign i_wdf_data_fall_out[(8*wdf_do_i)+7:(8*wdf_do_i)] - = i_wdf_data_out[(16*wdf_do_i)+15:(16*wdf_do_i)+8]; - assign i_wdf_mask_data_rise_out[wdf_do_i] - = i_wdf_mask_data_out[2*wdf_do_i]; - assign i_wdf_mask_data_fall_out[wdf_do_i] - = i_wdf_mask_data_out[(2*wdf_do_i)+1]; - end - - assign wdf_data = {i_wdf_data_fall_out, - i_wdf_data_rise_out}; - - assign wdf_mask_data = {i_wdf_mask_data_fall_out, - i_wdf_mask_data_rise_out}; - - //*********************************************************************** - - for (wdf_i = 0; wdf_i < WDF_FIFO_NUM; wdf_i = wdf_i + 1) begin: gen_wdf - - FIFO36_72 # - ( - .ALMOST_EMPTY_OFFSET (9'h007), - .ALMOST_FULL_OFFSET (9'h00F), - .DO_REG (1), // extra CC output delay - .EN_ECC_WRITE ("FALSE"), - .EN_ECC_READ ("FALSE"), - .EN_SYN ("FALSE"), - .FIRST_WORD_FALL_THROUGH ("FALSE") - ) - u_wdf - ( - .ALMOSTEMPTY (), - .ALMOSTFULL (i_wdf_afull[wdf_i]), - .DBITERR (), - .DO (i_wdf_data_out[(64*(wdf_i+1))-1:64*wdf_i]), - .DOP (i_wdf_mask_data_out[(8*(wdf_i+1))-1:8*wdf_i]), - .ECCPARITY (), - .EMPTY (), - .FULL (), - .RDCOUNT (), - .RDERR (), - .SBITERR (), - .WRCOUNT (), - .WRERR (), - .DI (i_wdf_data_in[(64*(wdf_i+1))-1:64*wdf_i]), - .DIP (i_wdf_mask_data_in[(8*(wdf_i+1))-1:8*wdf_i]), - .RDCLK (clk90), - .RDEN (wdf_rden), - .RST (rst_r), // or can use rst0 - .WRCLK (clk0), - .WREN (app_wdf_wren) - ); - end - end - endgenerate - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl (nonexistent)
trunk/rtl/XilinxMIG_MemCtrl/user_design/rtl Property changes : Deleted: bugtraq:number ## -1 +0,0 ## -true \ No newline at end of property Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_adr_data_gen.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_adr_data_gen.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_adr_data_gen.v (nonexistent) @@ -1,273 +0,0 @@ -//***************************************************************************** -// 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 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_tb_test_gen.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Fri Sep 01 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module instantiates the addr_gen and the data_gen modules. It takes -// the user data stored in internal FIFOs and gives the data that is to be -// compared with the read data -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_adr_data_gen # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter COL_WIDTH = 10, - parameter DM_WIDTH = 9, - parameter DQ_WIDTH = 72, - parameter APPDATA_WIDTH = 144, - parameter ECC_ENABLE = 0, - parameter ROW_WIDTH = 14 - ) - ( - input clk, - input rst, - input wr_addr_en, - input wr_data_en, - input rd_op, - input rd_data_valid, - input [30:0] bus_if_addr, - input [APPDATA_WIDTH-1:0] bus_if_wr_data, - input [(APPDATA_WIDTH/8)-1:0] bus_if_wr_mask_data, - output reg app_af_wren, - output [2:0] app_af_cmd, - output [30:0] app_af_addr, - output app_wdf_wren, - output [APPDATA_WIDTH-1:0] app_wdf_data, - output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data//, - //output [APPDATA_WIDTH-1:0] app_cmp_data - ); - - //data - localparam RD_IDLE_FIRST_DATA = 2'b00; - localparam RD_SECOND_DATA = 2'b01; - localparam RD_THIRD_DATA = 2'b10; - localparam RD_FOURTH_DATA = 2'b11; - - //address - reg wr_addr_en_r1; - reg [2:0] af_cmd_r;//, af_cmd_r0, af_cmd_r1; - reg af_wren_r; - reg rst_r - /* synthesis syn_preserve = 1 */; - reg rst_r1 - /* synthesis syn_maxfan = 10 */; - reg [5:0] wr_addr_r;//wr_addr_cnt; - reg wr_addr_en_r0; - - //data - reg [APPDATA_WIDTH-1:0] app_wdf_data_r; - reg [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data_r; - wire app_wdf_wren_r; - reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_fall; - reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_rise; - //wire rd_data_valid_r; - reg [1:0] rd_state; - wire [APPDATA_WIDTH-1:0] wr_data; - reg wr_data_en_r; - reg [(APPDATA_WIDTH/2)-1:0] wr_data_fall - /* synthesis syn_maxfan = 2 */; - reg [(APPDATA_WIDTH/2)-1:0] wr_data_rise - /* synthesis syn_maxfan = 2 */; - wire [(APPDATA_WIDTH/8)-1:0] wr_mask_data; - - //*************************************************************************** - - // 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 larger than fanout on RST_R, otherwise SLICES will be - // used for fanout control on RST_R. - always @(posedge clk) begin - rst_r <= rst; - rst_r1 <= rst_r; - end -// register backend enables / FIFO enables - // write enable for Command/Address FIFO is generated 1 CC after WR_ADDR_EN - always @(posedge clk) - if (rst_r1) begin - app_af_wren <= 1'b0; - end else begin - app_af_wren <= wr_addr_en; - end - - always @ (posedge clk) - if (rst_r1) - wr_addr_r <= 0; - else if (wr_addr_en && (rd_op == 1'b0)) - wr_addr_r <= bus_if_addr; - - assign app_af_addr = wr_addr_r; - assign app_af_cmd = af_cmd_r; - - always @ (posedge clk) - begin - af_cmd_r <= 0; - if (rd_op) - af_cmd_r <= 3'b001; - end - -// ddr2_tb_test_addr_gen # -// ( -// .BANK_WIDTH (BANK_WIDTH), -// .COL_WIDTH (COL_WIDTH), -// .ROW_WIDTH (ROW_WIDTH) -// ) -// u_addr_gen -// ( -// .clk (clk), -// .rst (rst), -// .wr_addr_en (wr_addr_en), -// .rd_op (rd_op), -// .bus_if_addr (bus_if_addr), -// .app_af_cmd (app_af_cmd), -// .app_af_addr (app_af_addr), -// .app_af_wren (app_af_wren) -// ); - - //data - assign app_wdf_data = wr_data; - assign app_wdf_mask_data = wr_mask_data; - // inst ff for timing - FDRSE ff_wdf_wren - ( - .Q (app_wdf_wren), - .C (clk), - .CE (1'b1), - .D (wr_data_en), //wr_data_en_r - .R (1'b0), - .S (1'b0) - ); -// FDRSE ff_rd_data_valid_r -// ( -// .Q (rd_data_valid_r), -// .C (clk), -// .CE (1'b1), -// .D (rd_data_valid), -// .R (1'b0), -// .S (1'b0) -// ); - - assign wr_data = {wr_data_fall, wr_data_rise}; - assign wr_mask_data = bus_if_wr_mask_data; - - //data latching - //synthesis attribute max_fanout of wr_data_fall is 2 - //synthesis attribute max_fanout of wr_data_rise is 2 - always @(posedge clk) - begin - if (rst_r1) - begin - wr_data_rise <= {(APPDATA_WIDTH/2){1'bx}}; - wr_data_fall <= {(APPDATA_WIDTH/2){1'bx}}; - end - else - if (wr_data_en) - begin - wr_data_rise <= bus_if_wr_data[(APPDATA_WIDTH/2)-1:0]; - wr_data_fall <= bus_if_wr_data[APPDATA_WIDTH-1:(APPDATA_WIDTH/2)]; - end - end - - //BO: needs to be commented out in the future - //***************************************************************** - // Read data logic - //***************************************************************** -// -// // read comparison data generation -// always @(posedge clk) -// if (rst_r1) begin -// rd_data_pat_rise <= {(APPDATA_WIDTH/2){1'bx}}; -// rd_data_pat_fall <= {(APPDATA_WIDTH/2){1'bx}}; -// rd_state <= RD_IDLE_FIRST_DATA; -// end else begin -// case (rd_state) -// RD_IDLE_FIRST_DATA: -// if (rd_data_valid_r) -// begin -// rd_data_pat_rise <= {(APPDATA_WIDTH/2){1'b1}}; // 0xF -// rd_data_pat_fall <= {(APPDATA_WIDTH/2){1'b0}}; // 0x0 -// rd_state <= RD_SECOND_DATA; -// end -// RD_SECOND_DATA: -// if (rd_data_valid_r) begin -// rd_data_pat_rise <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA -// rd_data_pat_fall <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 -// rd_state <= RD_THIRD_DATA; -// end -// RD_THIRD_DATA: -// if (rd_data_valid_r) begin -// rd_data_pat_rise <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 -// rd_data_pat_fall <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA -// rd_state <= RD_FOURTH_DATA; -// end -// RD_FOURTH_DATA: -// if (rd_data_valid_r) begin -// rd_data_pat_rise <= {(APPDATA_WIDTH/8){4'b1001}}; // 0x9 -// rd_data_pat_fall <= {(APPDATA_WIDTH/8){4'b0110}}; // 0x6 -// rd_state <= RD_IDLE_FIRST_DATA; -// end -// endcase -// end -// -// //data to the compare circuit during read -// assign app_cmp_data = {rd_data_pat_fall, rd_data_pat_rise}; - - - - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_gen.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_gen.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_gen.v (nonexistent) @@ -1,159 +0,0 @@ -//***************************************************************************** -// Company: UPT -// Engineer: Oana Boncalo & Alexandru Amaricai -// -// Create Date: 10:23:39 11/26/2012 -// Design Name: -// Module Name: DDR2 user IF address and data generation -// Project Name: -// Target Devices: -// Tool versions: -//Device: Virtex-5 -//Purpose: -// This module instantiates the addr_gen and the data_gen modules. It takes -// the user data stored in internal FIFOs and gives the data that is to be -// compared with the read data -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_adr_data_gen # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter COL_WIDTH = 10, - parameter DM_WIDTH = 9, - parameter DQ_WIDTH = 72, - parameter APPDATA_WIDTH = 144, - parameter ECC_ENABLE = 0, - parameter ROW_WIDTH = 14 - ) - ( - input clk, - input rst, - input wr_addr_en, - input wr_data_en, - input rd_op, - input rd_data_valid, - input [30:0] bus_if_addr, - input [APPDATA_WIDTH-1:0] bus_if_wr_data, - input [(APPDATA_WIDTH/8)-1:0] bus_if_wr_mask_data, - output reg app_af_wren, - output [2:0] app_af_cmd, - output [30:0] app_af_addr, - output app_wdf_wren, - output [APPDATA_WIDTH-1:0] app_wdf_data, - output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data - ); - - //data - localparam RD_IDLE_FIRST_DATA = 2'b00; - localparam RD_SECOND_DATA = 2'b01; - localparam RD_THIRD_DATA = 2'b10; - localparam RD_FOURTH_DATA = 2'b11; - - //address - reg wr_addr_en_r1; - reg [2:0] af_cmd_r;//, af_cmd_r0, af_cmd_r1; - reg af_wren_r; - reg rst_r - /* synthesis syn_preserve = 1 */; - reg rst_r1 - /* synthesis syn_maxfan = 10 */; - reg [5:0] wr_addr_r; - reg wr_addr_en_r0; - - //data - reg [APPDATA_WIDTH-1:0] app_wdf_data_r; - reg [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data_r; - wire app_wdf_wren_r; - reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_fall; - reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_rise; - reg [1:0] rd_state; - wire [APPDATA_WIDTH-1:0] wr_data; - reg wr_data_en_r; - reg [(APPDATA_WIDTH/2)-1:0] wr_data_fall - /* synthesis syn_maxfan = 2 */; - reg [(APPDATA_WIDTH/2)-1:0] wr_data_rise - /* synthesis syn_maxfan = 2 */; - wire [(APPDATA_WIDTH/8)-1:0] wr_mask_data; - - //*************************************************************************** - - // 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 larger than fanout on RST_R, otherwise SLICES will be - // used for fanout control on RST_R. - always @(posedge clk) begin - rst_r <= rst; - rst_r1 <= rst_r; - end -// register backend enables / FIFO enables - // write enable for Command/Address FIFO is generated 1 CC after WR_ADDR_EN - always @(posedge clk) - if (rst_r1) begin - app_af_wren <= 1'b0; - end else begin - app_af_wren <= wr_addr_en; - end - - always @ (posedge clk) - if (rst_r1) - wr_addr_r <= 0; - else if (wr_addr_en && (rd_op == 1'b0)) - wr_addr_r <= bus_if_addr; - - assign app_af_addr = wr_addr_r; - assign app_af_cmd = af_cmd_r; - - always @ (posedge clk) - begin - af_cmd_r <= 0; - if (rd_op) - af_cmd_r <= 3'b001; - end - - - //data - assign app_wdf_data = wr_data; - assign app_wdf_mask_data = wr_mask_data; - // inst ff for timing - FDRSE ff_wdf_wren - ( - .Q (app_wdf_wren), - .C (clk), - .CE (1'b1), - .D (wr_data_en), - .R (1'b0), - .S (1'b0) - ); - - assign wr_data = {wr_data_fall, wr_data_rise}; - assign wr_mask_data = bus_if_wr_mask_data; - - //data latching - //synthesis attribute max_fanout of wr_data_fall is 2 - //synthesis attribute max_fanout of wr_data_rise is 2 - always @(posedge clk) - begin - if (rst_r1) - begin - wr_data_rise <= {(APPDATA_WIDTH/2){1'bx}}; - wr_data_fall <= {(APPDATA_WIDTH/2){1'bx}}; - end - else - if (wr_data_en) - begin - wr_data_rise <= bus_if_wr_data[(APPDATA_WIDTH/2)-1:0]; - wr_data_fall <= bus_if_wr_data[APPDATA_WIDTH-1:(APPDATA_WIDTH/2)]; - end - end - - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_user_if_top.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_user_if_top.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_user_if_top.v (nonexistent) @@ -1,211 +0,0 @@ -//***************************************************************************** -// Company: UPT -// Engineer: Oana Boncalo & Alexandru Amaricai -// -// Create Date: 10:23:39 11/26/2012 -// Design Name: -// Module Name: DDR2 user IF for Genesys board -// Project Name: -// Target Devices: -// Tool versions: -//Device: Virtex-5 -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_user_if_top # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter COL_WIDTH = 10, - parameter DM_WIDTH = 9, - parameter DQ_WIDTH = 72, - parameter ROW_WIDTH = 14, - parameter APPDATA_WIDTH = 144, - parameter ECC_ENABLE = 0, - parameter BURST_LEN = 4 - ) - ( - input clk0, - input rst0, - input app_af_afull, - input app_wdf_afull, - input rd_data_valid, - input [APPDATA_WIDTH-1:0] rd_data_fifo_out, - input phy_init_done, - input rd_cmd, - input wr_cmd, - input [30:0] bus_if_addr, - input [APPDATA_WIDTH-1:0] bus_if_wr_data, - input [(APPDATA_WIDTH/8)-1:0] bus_if_wr_mask_data, - output end_op, - output req_wd, - output app_af_wren, - output [2:0] app_af_cmd, - output [30:0] app_af_addr, - output app_wdf_wren, - output [APPDATA_WIDTH-1:0] app_wdf_data, - output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, - output error, - output error_cmp - ); - - localparam BURST_LEN_DIV2 = BURST_LEN/2; - - localparam IDLE_CMD = 3'b000; - localparam WRITE_CMD = 3'b001; - localparam READ_CMD = 3'b010; - - reg app_af_not_afull_r; - wire [APPDATA_WIDTH-1:0] app_cmp_data; - reg app_wdf_not_afull_r ; - reg [2:0] burst_cnt; - reg phy_init_done_tb_r; - wire phy_init_done_r; - reg rst_r - /* synthesis syn_preserve = 1 */; - reg rst_r1 - /* synthesis syn_maxfan = 10 */; - reg [2:0] state; - reg [3:0] state_cnt; - reg wr_addr_en ; - reg wr_data_en ; - reg rd_op; - reg end_op_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" - - //***************************************************************** - - // 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 larger than fanout on RST_R, otherwise SLICES will be - // used for fanout control on RST_R. - always @(posedge clk0) begin - rst_r <= rst0; - rst_r1 <= rst_r; - end - - // Instantiate flops for timing. - FDRSE ff_phy_init_done - ( - .Q (phy_init_done_r), - .C (clk0), - .CE (1'b1), - .D (phy_init_done), - .R (1'b0), - .S (1'b0) - ); - - assign end_op = end_op_r; - //*************************************************************************** - // State Machine for writing to WRITE DATA & ADDRESS FIFOs - // state machine changed for low FIFO threshold values - //*************************************************************************** - - always @(posedge clk0) begin - if (rst_r1) begin - wr_data_en <= 1'bx; - wr_addr_en <= 1'bx; - state[2:0] <= IDLE_CMD; - state_cnt <= 4'bxxxx; - app_af_not_afull_r <= 1'bx; - app_wdf_not_afull_r <= 1'bx; - burst_cnt <= 3'bxxx; - phy_init_done_tb_r <= 1'bx; - rd_op <= 1'bx; - end_op_r <= 1'bx; - end else begin - wr_data_en <= 1'b0; - wr_addr_en <= 1'b0; - rd_op <= 1'b0; - end_op_r <= 1'b0; - app_af_not_afull_r <= ~app_af_afull; - app_wdf_not_afull_r <= ~app_wdf_afull; - phy_init_done_tb_r <= phy_init_done_r; - - case (state) - IDLE_CMD: begin - state_cnt <= 4'd0; - burst_cnt <= BURST_LEN_DIV2 - 1; - end_op_r <= 1'b0; - // only start writing when initialization done - if (app_wdf_not_afull_r && app_af_not_afull_r && phy_init_done_tb_r) - begin - if (rd_cmd) - state <= READ_CMD; - if (wr_cmd) - state <= WRITE_CMD; - end - end - - WRITE_CMD: - if (app_wdf_not_afull_r && app_af_not_afull_r) - begin - wr_data_en <= 1'b1; - // When we're done with the current burst... - if (burst_cnt == 3'd0) - begin - wr_addr_en <= 1'b1; - state <= IDLE_CMD; - end_op_r <= 1'b1; - end - else - burst_cnt <= burst_cnt - 1; - end - - READ_CMD: begin - burst_cnt <= BURST_LEN_DIV2 - 1; - if (app_af_not_afull_r) - begin - wr_addr_en <= 1'b1; - rd_op <= 1'b1; - state <= IDLE_CMD; - end_op_r <= 1'b1; - end - end - endcase - end - end - assign req_wd = (!wr_addr_en && wr_data_en)? 1'b1:1'b0; - - // Command/Address and Write Data generation - ddr2_adr_data_gen # - ( - .BANK_WIDTH (BANK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .DM_WIDTH (DM_WIDTH), - .DQ_WIDTH (DQ_WIDTH), - .APPDATA_WIDTH (APPDATA_WIDTH), - .ECC_ENABLE (ECC_ENABLE), - .ROW_WIDTH (ROW_WIDTH) - ) - u_adr_data_gen - ( - .clk (clk0), - .rst (rst0), - .wr_addr_en (wr_addr_en), - .wr_data_en (wr_data_en), - .rd_op (rd_op), - .rd_data_valid (rd_data_valid), - .bus_if_addr (bus_if_addr), - .app_af_wren (app_af_wren), - .bus_if_wr_mask_data(bus_if_wr_mask_data), - .bus_if_wr_data (bus_if_wr_data), - .app_af_cmd (app_af_cmd), - .app_af_addr (app_af_addr), - .app_wdf_wren (app_wdf_wren), - .app_wdf_data (app_wdf_data), - .app_wdf_mask_data (app_wdf_mask_data) - ); - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_cmp.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_cmp.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_cmp.v (nonexistent) @@ -1,266 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_tb_test_cmp.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Fri Sep 01 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module generates the error signal in case of bit errors. It compares -// the read data with expected data value. -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_tb_test_cmp # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter DQ_WIDTH = 72, - parameter APPDATA_WIDTH = 144, - parameter ECC_ENABLE = 0 - ) - ( - input clk, - input rst, - input phy_init_done, - input rd_data_valid, - input [APPDATA_WIDTH-1:0] app_cmp_data, - input [APPDATA_WIDTH-1:0] rd_data_fifo_in, - output reg error, - output reg error_cmp - ); - - wire [(APPDATA_WIDTH/16)-1:0] byte_err_fall; - reg [(APPDATA_WIDTH/16)-1:0] byte_err_fall_r; - wire [(APPDATA_WIDTH/16)-1:0] byte_err_rise; - reg [(APPDATA_WIDTH/16)-1:0] byte_err_rise_r; - wire [(APPDATA_WIDTH/2)-1:0] cmp_data_fall; - wire [(APPDATA_WIDTH/2)-1:0] cmp_data_rise; - wire [APPDATA_WIDTH-1:0] cmp_data_r; - reg [APPDATA_WIDTH-1:0] cmp_data_r1; - reg cmp_start; - wire [(APPDATA_WIDTH/2)-1:0] data_fall_r; - wire [(APPDATA_WIDTH/2)-1:0] data_rise_r; - reg err_fall; - reg err_rise; - reg error_tmp_r; - wire error_tmp_r1; - wire error_tmp_r2; - wire [APPDATA_WIDTH-1:0] rd_data_r; - wire [APPDATA_WIDTH-1:0] rd_data_r1; - reg [APPDATA_WIDTH-1:0] rd_data_r2; - wire rd_data_valid_r; - reg rd_data_valid_r1; - reg rd_data_valid_r2; - reg rst_r - /* synthesis syn_preserve = 1 */; - reg rst_r1 - /* synthesis syn_maxfan = 10 */; - - // 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" - - //*************************************************************************** - - // 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 larger than fanout on RST_R, otherwise SLICES will be - // used for fanout control on RST_R. - always @(posedge clk) begin - rst_r <= rst; - rst_r1 <= rst_r; - end - - // instantiate discrete flops for better timing - genvar rd_data_i; - generate - for (rd_data_i = 0; rd_data_i < APPDATA_WIDTH; - rd_data_i = rd_data_i + 1) begin: gen_rd_data - FDRSE ff_rd_data - ( - .Q (rd_data_r[rd_data_i]), - .C (clk), - .CE (1'b1), - .D (rd_data_fifo_in[rd_data_i]), - .R (1'b0), - .S (1'b0) - ); - - FDRSE ff_rd_data_r1 - ( - .Q (rd_data_r1[rd_data_i]), - .C (clk), - .CE (1'b1), - .D (rd_data_r[rd_data_i]), - .R (1'b0), - .S (1'b0) - ); - end - endgenerate - - genvar cmp_data_i; - generate - for (cmp_data_i = 0; cmp_data_i < APPDATA_WIDTH; - cmp_data_i = cmp_data_i + 1) begin: gen_cmp_data - FDRSE ff_cmp_data - ( - .Q (cmp_data_r[cmp_data_i]), - .C (clk), - .CE (1'b1), - .D (app_cmp_data[cmp_data_i]), - .R (1'b0), - .S (1'b0) - ); - end - endgenerate - - assign data_fall_r = rd_data_r2[APPDATA_WIDTH-1:(APPDATA_WIDTH/2)]; - assign data_rise_r = rd_data_r2[(APPDATA_WIDTH/2)-1:0]; - assign cmp_data_fall = cmp_data_r[APPDATA_WIDTH-1:(APPDATA_WIDTH/2)]; - assign cmp_data_rise = cmp_data_r[(APPDATA_WIDTH/2)-1:0]; - - // Instantiate ff for timing. - FDRSE ff_rd_data_valid_r - ( - .Q (rd_data_valid_r), - .C (clk), - .CE (1'b1), - .D (rd_data_valid), - .R (1'b0), - .S (1'b0) - ); - - always @(posedge clk) begin - if (rst_r1) begin - rd_data_valid_r1 <= 1'd0; - end else begin - rd_data_valid_r1 <= rd_data_valid_r & phy_init_done; - end - end - - always @(posedge clk)begin - rd_data_r2 <= rd_data_r1; - cmp_data_r1 <= cmp_data_r; - rd_data_valid_r2 <= rd_data_valid_r1; - end - - genvar cmp_i; - generate - for (cmp_i = 0; cmp_i < APPDATA_WIDTH/16; cmp_i = cmp_i + 1) begin: gen_cmp - assign byte_err_fall[cmp_i] - = (rd_data_valid_r2 && - (data_fall_r[8*(cmp_i+1)-1:8*cmp_i] != - cmp_data_fall[8*(cmp_i+1)-1:8*cmp_i])); - assign byte_err_rise[cmp_i] - = (rd_data_valid_r2 && - (data_rise_r[8*(cmp_i+1)-1:8*cmp_i] != - cmp_data_rise[8*(cmp_i+1)-1:8*cmp_i])); - end - endgenerate - - always @(posedge clk) begin - byte_err_rise_r <= byte_err_rise; - byte_err_fall_r <= byte_err_fall; - end - - always @(posedge clk) - if (rst_r1) begin - err_rise <= 1'bx; - err_fall <= 1'bx; - cmp_start <= 1'b0; - error_tmp_r <= 1'b0; - end else begin - err_rise <= | byte_err_rise_r; - err_fall <= | byte_err_fall_r; - // start comparing when initialization/calibration complete, and we - // get first valid readback - if (rd_data_valid_r2) - cmp_start <= 1'b1; - if (cmp_start && !error_tmp_r) - error_tmp_r <= err_rise | err_fall; - //synthesis translate_off - if ((err_rise || err_fall) && cmp_start) - $display ("ERROR at time %t" , $time); - //synthesis translate_on - end - - // FF inst to force synthesis to infer ff's. - // Done for timing. - FDRSE ff_error_1 - ( - .Q (error_tmp_r1), - .C (clk), - .CE (1'b1), - .D (error_tmp_r), - .R (1'b0), - .S (1'b0) - ); - - FDRSE ff_error_2 - ( - .Q (error_tmp_r2), - .C (clk), - .CE (1'b1), - .D (error_tmp_r1), - .R (1'b0), - .S (1'b0) - ); - - always @(posedge clk) begin - error <= error_tmp_r2; - error_cmp <= err_rise | err_fall; - end - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_data_gen.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_data_gen.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_data_gen.v (nonexistent) @@ -1,294 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_tb_test_data_gen.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Fri Sep 01 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module contains the data generation logic for the synthesizable -// testbench. -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_tb_test_data_gen # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter DM_WIDTH = 9, - parameter DQ_WIDTH = 72, - parameter APPDATA_WIDTH = 144, - parameter ECC_ENABLE = 0 - ) - ( - input clk, - input rst, - input wr_data_en, - input rd_data_valid, - input [APPDATA_WIDTH-1:0] bus_if_wr_data, - input [(APPDATA_WIDTH/8)-1:0] bus_if_wr_mask_data, - output app_wdf_wren, - output [APPDATA_WIDTH-1:0] app_wdf_data, - output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, - output [APPDATA_WIDTH-1:0] app_cmp_data - ); - - localparam RD_IDLE_FIRST_DATA = 2'b00; - localparam RD_SECOND_DATA = 2'b01; - localparam RD_THIRD_DATA = 2'b10; - localparam RD_FOURTH_DATA = 2'b11; - - reg [APPDATA_WIDTH-1:0] app_wdf_data_r; - reg [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data_r; - wire app_wdf_wren_r; - reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_fall; - reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_rise; - wire rd_data_valid_r; - reg [1:0] rd_state; - reg rst_r - /* synthesis syn_preserve = 1 */; - reg rst_r1 - /* synthesis syn_maxfan = 10 */; - wire [APPDATA_WIDTH-1:0] wr_data; - reg wr_data_en_r; - reg [(APPDATA_WIDTH/2)-1:0] wr_data_fall - /* synthesis syn_maxfan = 2 */; - reg [(APPDATA_WIDTH/2)-1:0] wr_data_rise - /* synthesis syn_maxfan = 2 */; - wire [(APPDATA_WIDTH/8)-1:0] wr_mask_data; - //wire [(APPDATA_WIDTH/16)-1:0] wr_mask_data_fall; - //wire [(APPDATA_WIDTH/16)-1:0] wr_mask_data_rise; - //reg [1:0] wr_state; - - // 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" - - //*************************************************************************** - - // 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 larger than fanout on RST_R, otherwise SLICES will be - // used for fanout control on RST_R. - always @(posedge clk) begin - rst_r <= rst; - rst_r1 <= rst_r; - end - -// always @(posedge clk) begin -// //app_wdf_data_r <= wr_data; -// //app_wdf_mask_data_r <= wr_mask_data; -// app_wdf_data <= wr_data; //app_wdf_data_r; -// app_wdf_mask_data <= wr_mask_data;//app_wdf_mask_data_r; -// end - assign app_wdf_data = wr_data; - assign app_wdf_mask_data = wr_mask_data; - // inst ff for timing - FDRSE ff_wdf_wren - ( - .Q (app_wdf_wren), - .C (clk), - .CE (1'b1), - .D (wr_data_en), //wr_data_en_r - .R (1'b0), - .S (1'b0) - ); - -// FDRSE ff_wdf_wren_r -// ( -// .Q (app_wdf_wren), -// .C (clk), -// .CE (1'b1), -// .D (app_wdf_wren_r), -// .R (1'b0), -// .S (1'b0) -// ); - - FDRSE ff_rd_data_valid_r - ( - .Q (rd_data_valid_r), - .C (clk), - .CE (1'b1), - .D (rd_data_valid), - .R (1'b0), - .S (1'b0) - ); - - assign wr_data = {wr_data_fall, wr_data_rise}; - assign wr_mask_data = bus_if_wr_mask_data; - - //data latching - //synthesis attribute max_fanout of wr_data_fall is 2 - //synthesis attribute max_fanout of wr_data_rise is 2 - always @(posedge clk) - begin - if (rst_r1) - begin - wr_data_rise <= {(APPDATA_WIDTH/2){1'bx}}; - wr_data_fall <= {(APPDATA_WIDTH/2){1'bx}}; - end - else - if (wr_data_en) - begin - wr_data_rise <= bus_if_wr_data[(APPDATA_WIDTH/2)-1:0]; - wr_data_fall <= bus_if_wr_data[APPDATA_WIDTH-1:(APPDATA_WIDTH/2)]; - end - end - -// //*************************************************************************** -// // DATA generation for WRITE DATA FIFOs & for READ DATA COMPARE -// //*************************************************************************** -// -// assign wr_data = {wr_data_fall, wr_data_rise}; -// assign wr_mask_data = {wr_mask_data_fall, wr_mask_data_rise}; -// -// //***************************************************************** -// // For now, don't vary data masks -// //***************************************************************** -// -// assign wr_mask_data_rise = {(APPDATA_WIDTH/8){1'b0}}; -// assign wr_mask_data_fall = {(APPDATA_WIDTH/8){1'b0}}; -// -// //***************************************************************** -// // Write data logic -// //***************************************************************** -// -// // write data generation -// //synthesis attribute max_fanout of wr_data_fall is 2 -// //synthesis attribute max_fanout of wr_data_rise is 2 -// always @(posedge clk) begin -// if (rst_r1) begin -// wr_data_rise <= {(APPDATA_WIDTH/2){1'bx}}; -// wr_data_fall <= {(APPDATA_WIDTH/2){1'bx}}; -// wr_state <= WR_IDLE_FIRST_DATA; -// end else begin -// case (wr_state) -// WR_IDLE_FIRST_DATA: -// if (wr_data_en) begin -// wr_data_rise <= {(APPDATA_WIDTH/2){1'b1}}; // 0xF -// wr_data_fall <= {(APPDATA_WIDTH/2){1'b0}}; // 0x0 -// wr_state <= WR_SECOND_DATA; -// end -// WR_SECOND_DATA: -// if (wr_data_en) begin -// wr_data_rise <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA -// wr_data_fall <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 -// wr_state <= WR_THIRD_DATA; -// end -// WR_THIRD_DATA: -// if (wr_data_en) begin -// wr_data_rise <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 -// wr_data_fall <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA -// wr_state <= WR_FOURTH_DATA; -// end -// WR_FOURTH_DATA: -// if (wr_data_en) begin -// wr_data_rise <= {(APPDATA_WIDTH/8){4'b1001}}; // 0x9 -// wr_data_fall <= {(APPDATA_WIDTH/8){4'b0110}}; // 0x6 -// wr_state <= WR_IDLE_FIRST_DATA; -// end -// endcase -// end -// end - //another 1 cc delay -// always @(posedge clk) -// if (rst_r1) -// wr_data_en_r <= 1'b0; -// else -// wr_data_en_r <= wr_data_en; - - //***************************************************************** - // Read data logic - //***************************************************************** - - // read comparison data generation - always @(posedge clk) - if (rst_r1) begin - rd_data_pat_rise <= {(APPDATA_WIDTH/2){1'bx}}; - rd_data_pat_fall <= {(APPDATA_WIDTH/2){1'bx}}; - rd_state <= RD_IDLE_FIRST_DATA; - end else begin - case (rd_state) - RD_IDLE_FIRST_DATA: - if (rd_data_valid_r) - begin - rd_data_pat_rise <= {(APPDATA_WIDTH/2){1'b1}}; // 0xF - rd_data_pat_fall <= {(APPDATA_WIDTH/2){1'b0}}; // 0x0 - rd_state <= RD_SECOND_DATA; - end - RD_SECOND_DATA: - if (rd_data_valid_r) begin - rd_data_pat_rise <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA - rd_data_pat_fall <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 - rd_state <= RD_THIRD_DATA; - end - RD_THIRD_DATA: - if (rd_data_valid_r) begin - rd_data_pat_rise <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 - rd_data_pat_fall <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA - rd_state <= RD_FOURTH_DATA; - end - RD_FOURTH_DATA: - if (rd_data_valid_r) begin - rd_data_pat_rise <= {(APPDATA_WIDTH/8){4'b1001}}; // 0x9 - rd_data_pat_fall <= {(APPDATA_WIDTH/8){4'b0110}}; // 0x6 - rd_state <= RD_IDLE_FIRST_DATA; - end - endcase - end - - //data to the compare circuit during read - assign app_cmp_data = {rd_data_pat_fall, rd_data_pat_rise}; - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_addr_gen.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_addr_gen.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_test_addr_gen.v (nonexistent) @@ -1,138 +0,0 @@ -//***************************************************************************** -// 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_tb_test_addr_gen.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Fri Sep 01 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// The address for the memory and the various user commands can be given -// through this module. It instantiates the block RAM which stores all the -// information in particular sequence. The data stored should be in a -// sequence starting from LSB: -// column address, row address, bank address, commands. -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_tb_test_addr_gen # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter COL_WIDTH = 10, - parameter ROW_WIDTH = 14 - ) - ( - input clk, - input rst, - input wr_addr_en, - input rd_op, - input [30:0] bus_if_addr, - output [2:0] app_af_cmd, - output [30:0] app_af_addr, - output reg app_af_wren - ); - - reg wr_addr_en_r1; - reg [2:0] af_cmd_r;//, af_cmd_r0, af_cmd_r1; - reg af_wren_r; - reg rst_r - /* synthesis syn_preserve = 1 */; - reg rst_r1 - /* synthesis syn_maxfan = 10 */; - reg [5:0] wr_addr_r;//wr_addr_cnt; - reg wr_addr_en_r0; - - // 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" - - //***************************************************************** - - // 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 larger than fanout on RST_R, otherwise SLICES will be - // used for fanout control on RST_R. - always @(posedge clk) begin - rst_r <= rst; - rst_r1 <= rst_r; - end - - - // register backend enables / FIFO enables - // write enable for Command/Address FIFO is generated 1 CC after WR_ADDR_EN - always @(posedge clk) - if (rst_r1) begin - app_af_wren <= 1'b0; - end else begin - app_af_wren <= wr_addr_en; - end - - always @ (posedge clk) - if (rst_r1) - wr_addr_r <= 0; - else if (wr_addr_en && (rd_op == 1'b0)) - wr_addr_r <= bus_if_addr; - - assign app_af_addr = wr_addr_r; - assign app_af_cmd = af_cmd_r; - - always @ (posedge clk) - begin - af_cmd_r <= 0; - if (rd_op) - af_cmd_r <= 3'b001; - end - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_top.v =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_top.v (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/sim/ddr2_tb_top.v (nonexistent) @@ -1,255 +0,0 @@ -//***************************************************************************** -// 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 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.6.1 -// \ \ Application: MIG -// / / Filename: ddr2_tb_top.v -// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ -// \ \ / \ Date Created: Fri Sep 01 2006 -// \___\/\___\ -// -//Device: Virtex-5 -//Design Name: DDR2 -//Purpose: -// This module is the synthesizable test bench for the memory interface. -// This Test bench is to compare the write and the read data and generate -// an error flag. -//Reference: -//Revision History: -//***************************************************************************** - -`timescale 1ns/1ps - -module ddr2_user_if_top # - ( - // 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 MEMCtrl module. Please refer to - // the MEMCtrl module for actual values. - parameter BANK_WIDTH = 2, - parameter COL_WIDTH = 10, - parameter DM_WIDTH = 9, - parameter DQ_WIDTH = 72, - parameter ROW_WIDTH = 14, - parameter APPDATA_WIDTH = 144, - parameter ECC_ENABLE = 0, - parameter BURST_LEN = 4 - ) - ( - input clk0, - input rst0, - input app_af_afull, - input app_wdf_afull, - input rd_data_valid, - input [APPDATA_WIDTH-1:0] rd_data_fifo_out, - input phy_init_done, - input rd_cmd, - input wr_cmd, - input [30:0] bus_if_addr, - input [APPDATA_WIDTH-1:0] bus_if_wr_data, - input [(APPDATA_WIDTH/8)-1:0] bus_if_wr_mask_data, - output end_op, - output req_wd, - output app_af_wren, - output [2:0] app_af_cmd, - output [30:0] app_af_addr, - output app_wdf_wren, - output [APPDATA_WIDTH-1:0] app_wdf_data, - output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, - output error, - output error_cmp - ); - - localparam BURST_LEN_DIV2 = BURST_LEN/2; - - localparam IDLE_CMD = 3'b000; - localparam WRITE_CMD = 3'b001; - localparam READ_CMD = 3'b010; - - reg app_af_not_afull_r; - wire [APPDATA_WIDTH-1:0] app_cmp_data; - reg app_wdf_not_afull_r ; - reg [2:0] burst_cnt; - reg phy_init_done_tb_r; - wire phy_init_done_r; - reg rst_r - /* synthesis syn_preserve = 1 */; - reg rst_r1 - /* synthesis syn_maxfan = 10 */; - reg [2:0] state; - reg [3:0] state_cnt; - reg wr_addr_en ; - reg wr_data_en ; - reg rd_op; - reg end_op_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" - - //***************************************************************** - - // 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 larger than fanout on RST_R, otherwise SLICES will be - // used for fanout control on RST_R. - always @(posedge clk0) begin - rst_r <= rst0; - rst_r1 <= rst_r; - end - - // Instantiate flops for timing. - FDRSE ff_phy_init_done - ( - .Q (phy_init_done_r), - .C (clk0), - .CE (1'b1), - .D (phy_init_done), - .R (1'b0), - .S (1'b0) - ); - - assign end_op = end_op_r; - //*************************************************************************** - // State Machine for writing to WRITE DATA & ADDRESS FIFOs - // state machine changed for low FIFO threshold values - //*************************************************************************** - - always @(posedge clk0) begin - if (rst_r1) begin - wr_data_en <= 1'bx; - wr_addr_en <= 1'bx; - state[2:0] <= IDLE_CMD; - state_cnt <= 4'bxxxx; - app_af_not_afull_r <= 1'bx; - app_wdf_not_afull_r <= 1'bx; - burst_cnt <= 3'bxxx; - phy_init_done_tb_r <= 1'bx; - rd_op <= 1'bx; - end_op_r <= 1'bx; - end else begin - wr_data_en <= 1'b0; - wr_addr_en <= 1'b0; - rd_op <= 1'b0; - end_op_r <= 1'b0; - app_af_not_afull_r <= ~app_af_afull; - app_wdf_not_afull_r <= ~app_wdf_afull; - phy_init_done_tb_r <= phy_init_done_r; - - case (state) - IDLE_CMD: begin - state_cnt <= 4'd0; - burst_cnt <= BURST_LEN_DIV2 - 1; - // only start writing when initialization done - if (app_wdf_not_afull_r && app_af_not_afull_r && phy_init_done_tb_r) - begin - if (rd_cmd) - state <= READ_CMD; - if (wr_cmd) - state <= WRITE_CMD; - end - end - - WRITE_CMD: - if (app_wdf_not_afull_r && app_af_not_afull_r) - begin - wr_data_en <= 1'b1; - // When we're done with the current burst... - if (burst_cnt == 3'd0) - begin - wr_addr_en <= 1'b1; - state <= IDLE_CMD; - end_op_r <= 1'b1; - end - else - burst_cnt <= burst_cnt - 1; - end - - READ_CMD: begin - burst_cnt <= BURST_LEN_DIV2 - 1; - if (app_af_not_afull_r) - begin - wr_addr_en <= 1'b1; - rd_op <= 1'b1; - state <= IDLE_CMD; - end_op_r <= 1'b1; - end - end - endcase - end - end - assign req_wd = (!wr_addr_en && wr_data_en)? 1'b1:1'b0; - - // Command/Address and Write Data generation - ddr2_tb_test_gen # - ( - .BANK_WIDTH (BANK_WIDTH), - .COL_WIDTH (COL_WIDTH), - .DM_WIDTH (DM_WIDTH), - .DQ_WIDTH (DQ_WIDTH), - .APPDATA_WIDTH (APPDATA_WIDTH), - .ECC_ENABLE (ECC_ENABLE), - .ROW_WIDTH (ROW_WIDTH) - ) - u_tb_test_gen - ( - .clk (clk0), - .rst (rst0), - .wr_addr_en (wr_addr_en), - .wr_data_en (wr_data_en), - .rd_op (rd_op), - .rd_data_valid (rd_data_valid), - .bus_if_addr (bus_if_addr), - .app_af_wren (app_af_wren), - .bus_if_wr_mask_data(bus_if_wr_mask_data), - .bus_if_wr_data (bus_if_wr_data), - .app_af_cmd (app_af_cmd), - .app_af_addr (app_af_addr), - .app_wdf_wren (app_wdf_wren), - .app_wdf_data (app_wdf_data), - .app_wdf_mask_data (app_wdf_mask_data)//, - //.app_cmp_data (app_cmp_data) - ); - -endmodule Index: trunk/rtl/XilinxMIG_MemCtrl/user_design/sim =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design/sim (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design/sim (nonexistent)
trunk/rtl/XilinxMIG_MemCtrl/user_design/sim Property changes : Deleted: bugtraq:number ## -1 +0,0 ## -true \ No newline at end of property Index: trunk/rtl/XilinxMIG_MemCtrl/user_design =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl/user_design (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl/user_design (nonexistent)
trunk/rtl/XilinxMIG_MemCtrl/user_design Property changes : Deleted: bugtraq:number ## -1 +0,0 ## -true \ No newline at end of property Index: trunk/rtl/XilinxMIG_MemCtrl =================================================================== --- trunk/rtl/XilinxMIG_MemCtrl (revision 2) +++ trunk/rtl/XilinxMIG_MemCtrl (nonexistent)
trunk/rtl/XilinxMIG_MemCtrl Property changes : Deleted: bugtraq:number ## -1 +0,0 ## -true \ No newline at end of property Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dqs_iob.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dqs_iob.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dqs_iob.v (revision 3) @@ -0,0 +1,266 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_dqs_iob.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module places the data strobes in the IOBs. +//Reference: +//Revision History: +// Rev 1.1 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 +// Rev 1.2 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added +// on IODELAY primitives. PK. 11/27/08 +// Rev 1.3 - IDDR primitve (u_iddr_dq_ce) is replaced with a negative-edge +// triggered flip-flop. PK. 03/20/09 +// Rev 1.4 - To fix CR 540201, S and syn_preserve attributes are added +// for dqs_oe_n_r. PK. 01/08/10 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_phy_dqs_iob # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter DDR_TYPE = 1, + parameter HIGH_PERFORMANCE_MODE = "TRUE", + parameter IODELAY_GRP = "IODELAY_MIG" + ) + ( + input clk0, + input clkdiv0, + input rst0, + input dlyinc_dqs, + input dlyce_dqs, + input dlyrst_dqs, + input dlyinc_gate, + input dlyce_gate, + input dlyrst_gate, + input dqs_oe_n, + input dqs_rst_n, + input en_dqs, + inout ddr_dqs, + inout ddr_dqs_n, + output dq_ce, + output delayed_dqs + ); + + wire clk180; + wire dqs_bufio; + + wire dqs_ibuf; + wire dqs_idelay; + wire dqs_oe_n_delay; + (* S = "TRUE" *) wire dqs_oe_n_r /* synthesis syn_preserve = 1*/; + wire dqs_rst_n_delay; + reg dqs_rst_n_r /* synthesis syn_preserve = 1*/; + wire dqs_out; + wire en_dqs_sync /* synthesis syn_keep = 1 */; + + // for simulation only. Synthesis should ignore this delay + localparam DQS_NET_DELAY = 0.8; + + assign clk180 = ~clk0; + + // add delta delay to inputs clocked by clk180 to avoid delta-delay + // simulation issues + assign dqs_rst_n_delay = dqs_rst_n; + assign dqs_oe_n_delay = dqs_oe_n; + + //*************************************************************************** + // DQS input-side resources: + // - IODELAY (pad -> IDELAY) + // - BUFIO (IDELAY -> BUFIO) + //*************************************************************************** + + // Route DQS from PAD to IDELAY + (* IODELAY_GROUP = IODELAY_GRP *) IODELAY # + ( + .DELAY_SRC("I"), + .IDELAY_TYPE("VARIABLE"), + .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE), + .IDELAY_VALUE(0), + .ODELAY_VALUE(0) + ) + u_idelay_dqs + ( + .DATAOUT (dqs_idelay), + .C (clkdiv0), + .CE (dlyce_dqs), + .DATAIN (), + .IDATAIN (dqs_ibuf), + .INC (dlyinc_dqs), + .ODATAIN (), + .RST (dlyrst_dqs), + .T () + ); + + // From IDELAY to BUFIO + BUFIO u_bufio_dqs + ( + .I (dqs_idelay), + .O (dqs_bufio) + ); + + // To model additional delay of DQS BUFIO + gating network + // for behavioral simulation. Make sure to select a delay number smaller + // than half clock cycle (otherwise output will not track input changes + // because of inertial delay). Duplicate to avoid delta delay issues. + assign #(DQS_NET_DELAY) i_delayed_dqs = dqs_bufio; + assign #(DQS_NET_DELAY) delayed_dqs = dqs_bufio; + + //*************************************************************************** + // DQS gate circuit (not supported for all controllers) + //*************************************************************************** + + // Gate routing: + // en_dqs -> IDELAY -> en_dqs_sync -> IDDR.S -> dq_ce -> + // capture IDDR.CE + + // Delay CE control so that it's in phase with delayed DQS + (* IODELAY_GROUP = IODELAY_GRP *) IODELAY # + ( + .DELAY_SRC ("DATAIN"), + .IDELAY_TYPE ("VARIABLE"), + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .IDELAY_VALUE (0), + .ODELAY_VALUE (0) + ) + u_iodelay_dq_ce + ( + .DATAOUT (en_dqs_sync), + .C (clkdiv0), + .CE (dlyce_gate), + .DATAIN (en_dqs), + .IDATAIN (), + .INC (dlyinc_gate), + .ODATAIN (), + .RST (dlyrst_gate), + .T () + ); + + // Generate sync'ed CE to DQ IDDR's using a negative-edge triggered flip-flop + // clocked by DQS. This flop should be locked to the IOB flip-flop at the same + // site as IODELAY u_idelay_dqs in order to use the dedicated route from + // the IODELAY to flip-flop (to keep this route as short as possible) + (* IOB = "FORCE" *) FDCPE_1 # + ( + .INIT(1'b0) + ) + u_iddr_dq_ce + ( + .Q (dq_ce), + .C (i_delayed_dqs), + .CE (1'b1), + .CLR (1'b0), + .D (en_dqs_sync), + .PRE (en_dqs_sync) + ) /* synthesis syn_useioff = 1 */ + /* synthesis syn_replicate = 0 */; + + //*************************************************************************** + // DQS output-side resources + //*************************************************************************** + + // synthesis attribute keep of dqs_rst_n_r is "true" + always @(posedge clk180) + dqs_rst_n_r <= dqs_rst_n_delay; + + ODDR # + ( + .SRTYPE("SYNC"), + .DDR_CLK_EDGE("OPPOSITE_EDGE") + ) + u_oddr_dqs + ( + .Q (dqs_out), + .C (clk180), + .CE (1'b1), + .D1 (dqs_rst_n_r), // keep output deasserted for write preamble + .D2 (1'b0), + .R (1'b0), + .S (1'b0) + ); + + (* IOB = "FORCE" *) FDP u_tri_state_dqs + ( + .D (dqs_oe_n_delay), + .Q (dqs_oe_n_r), + .C (clk180), + .PRE (rst0) + ) /* synthesis syn_useioff = 1 */; + + //*************************************************************************** + + // use either single-ended (for DDR1) or differential (for DDR2) DQS input + + generate + if (DDR_TYPE > 0) begin: gen_dqs_iob_ddr2 + IOBUFDS u_iobuf_dqs + ( + .O (dqs_ibuf), + .IO (ddr_dqs), + .IOB (ddr_dqs_n), + .I (dqs_out), + .T (dqs_oe_n_r) + ); + end else begin: gen_dqs_iob_ddr1 + IOBUF u_iobuf_dqs + ( + .O (dqs_ibuf), + .IO (ddr_dqs), + .I (dqs_out), + .T (dqs_oe_n_r) + ); + end + endgenerate + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_top.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_top.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_top.v (revision 3) @@ -0,0 +1,276 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_top.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// System level module. This level contains just the memory controller. +// This level will be intiantated when the user wants to remove the +// synthesizable test bench, IDELAY control block and the clock +// generation modules. +//Reference: +//Revision History: +// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 +// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 +// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_top # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, // # of memory bank addr bits + parameter CKE_WIDTH = 1, // # of memory clock enable outputs + parameter CLK_WIDTH = 1, // # of clock outputs + parameter COL_WIDTH = 10, // # of memory column bits + parameter CS_NUM = 1, // # of separate memory chip selects + parameter CS_BITS = 0, // set to log2(CS_NUM) (rounded up) + parameter CS_WIDTH = 1, // # of total memory chip selects + parameter USE_DM_PORT = 1, // enable Data Mask (=1 enable) + parameter DM_WIDTH = 9, // # of data mask bits + parameter DQ_WIDTH = 72, // # of data width + parameter DQ_BITS = 7, // set to log2(DQS_WIDTH*DQ_PER_DQS) + parameter DQ_PER_DQS = 8, // # of DQ data bits per strobe + parameter DQS_WIDTH = 9, // # of DQS strobes + parameter DQS_BITS = 4, // set to log2(DQS_WIDTH) + parameter HIGH_PERFORMANCE_MODE = "TRUE", // IODELAY Performance Mode + parameter IODELAY_GRP = "IODELAY_MIG", // IODELAY Group Name + parameter ODT_WIDTH = 1, // # of memory on-die term enables + parameter ROW_WIDTH = 14, // # of memory row & # of addr bits + parameter APPDATA_WIDTH = 144, // # of usr read/write data bus bits + parameter ADDITIVE_LAT = 0, // additive write latency + parameter BURST_LEN = 4, // burst length (in double words) + parameter BURST_TYPE = 0, // burst type (=0 seq; =1 interlved) + parameter CAS_LAT = 5, // CAS latency + parameter ECC_ENABLE = 0, // enable ECC (=1 enable) + parameter ODT_TYPE = 1, // ODT (=0(none),=1(75),=2(150),=3(50)) + parameter MULTI_BANK_EN = 1, // enable bank management + parameter TWO_T_TIME_EN = 0, // 2t timing for unbuffered dimms + parameter REDUCE_DRV = 0, // reduced strength mem I/O (=1 yes) + parameter REG_ENABLE = 1, // registered addr/ctrl (=1 yes) + parameter TREFI_NS = 7800, // auto refresh interval (ns) + parameter TRAS = 40000, // active->precharge delay + parameter TRCD = 15000, // active->read/write delay + parameter TRFC = 105000, // ref->ref, ref->active delay + parameter TRP = 15000, // precharge->command delay + parameter TRTP = 7500, // read->precharge delay + parameter TWR = 15000, // used to determine wr->prech + parameter TWTR = 10000, // write->read delay + parameter CLK_PERIOD = 3000, // Core/Mem clk period (in ps) + parameter SIM_ONLY = 0, // = 1 to skip power up delay + parameter DEBUG_EN = 0, // Enable debug signals/controls + parameter FPGA_SPEED_GRADE = 2 // FPGA Speed Grade + ) + ( + input clk0, + input clk90, + input clkdiv0, + input rst0, + input rst90, + input rstdiv0, + input [2:0] app_af_cmd, + input [30:0] app_af_addr, + input app_af_wren, + input app_wdf_wren, + input [APPDATA_WIDTH-1:0] app_wdf_data, + input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, + output app_af_afull, + output app_wdf_afull, + output rd_data_valid, + output [APPDATA_WIDTH-1:0] rd_data_fifo_out, + output [1:0] rd_ecc_error, + output phy_init_done, + output [CLK_WIDTH-1:0] ddr2_ck, + output [CLK_WIDTH-1:0] ddr2_ck_n, + output [ROW_WIDTH-1:0] ddr2_a, + output [BANK_WIDTH-1:0] ddr2_ba, + output ddr2_ras_n, + output ddr2_cas_n, + output ddr2_we_n, + output [CS_WIDTH-1:0] ddr2_cs_n, + output [CKE_WIDTH-1:0] ddr2_cke, + output [ODT_WIDTH-1:0] ddr2_odt, + output [DM_WIDTH-1:0] ddr2_dm, + inout [DQS_WIDTH-1:0] ddr2_dqs, + inout [DQS_WIDTH-1:0] ddr2_dqs_n, + inout [DQ_WIDTH-1:0] ddr2_dq, + // Debug signals (optional use) + input dbg_idel_up_all, + input dbg_idel_down_all, + input dbg_idel_up_dq, + input dbg_idel_down_dq, + input dbg_idel_up_dqs, + input dbg_idel_down_dqs, + input dbg_idel_up_gate, + input dbg_idel_down_gate, + input [DQ_BITS-1:0] dbg_sel_idel_dq, + input dbg_sel_all_idel_dq, + input [DQS_BITS:0] dbg_sel_idel_dqs, + input dbg_sel_all_idel_dqs, + input [DQS_BITS:0] dbg_sel_idel_gate, + input dbg_sel_all_idel_gate, + output [3:0] dbg_calib_done, + output [3:0] dbg_calib_err, + output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, + output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, + output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, + output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly + ); + + // memory initialization/control logic + ddr2_mem_if_top # + ( + .BANK_WIDTH (BANK_WIDTH), + .CKE_WIDTH (CKE_WIDTH), + .CLK_WIDTH (CLK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_BITS (CS_BITS), + .CS_NUM (CS_NUM), + .CS_WIDTH (CS_WIDTH), + .USE_DM_PORT (USE_DM_PORT), + .DM_WIDTH (DM_WIDTH), + .DQ_WIDTH (DQ_WIDTH), + .DQ_BITS (DQ_BITS), + .DQ_PER_DQS (DQ_PER_DQS), + .DQS_BITS (DQS_BITS), + .DQS_WIDTH (DQS_WIDTH), + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .IODELAY_GRP (IODELAY_GRP), + .ODT_WIDTH (ODT_WIDTH), + .ROW_WIDTH (ROW_WIDTH), + .APPDATA_WIDTH (APPDATA_WIDTH), + .ADDITIVE_LAT (ADDITIVE_LAT), + .BURST_LEN (BURST_LEN), + .BURST_TYPE (BURST_TYPE), + .CAS_LAT (CAS_LAT), + .ECC_ENABLE (ECC_ENABLE), + .MULTI_BANK_EN (MULTI_BANK_EN), + .TWO_T_TIME_EN (TWO_T_TIME_EN), + .ODT_TYPE (ODT_TYPE), + .DDR_TYPE (1), + .REDUCE_DRV (REDUCE_DRV), + .REG_ENABLE (REG_ENABLE), + .TREFI_NS (TREFI_NS), + .TRAS (TRAS), + .TRCD (TRCD), + .TRFC (TRFC), + .TRP (TRP), + .TRTP (TRTP), + .TWR (TWR), + .TWTR (TWTR), + .CLK_PERIOD (CLK_PERIOD), + .SIM_ONLY (SIM_ONLY), + .DEBUG_EN (DEBUG_EN), + .FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) + ) + u_mem_if_top + ( + .clk0 (clk0), + .clk90 (clk90), + .clkdiv0 (clkdiv0), + .rst0 (rst0), + .rst90 (rst90), + .rstdiv0 (rstdiv0), + .app_af_cmd (app_af_cmd), + .app_af_addr (app_af_addr), + .app_af_wren (app_af_wren), + .app_wdf_wren (app_wdf_wren), + .app_wdf_data (app_wdf_data), + .app_wdf_mask_data (app_wdf_mask_data), + .app_af_afull (app_af_afull), + .app_wdf_afull (app_wdf_afull), + .rd_data_valid (rd_data_valid), + .rd_data_fifo_out (rd_data_fifo_out), + .rd_ecc_error (rd_ecc_error), + .phy_init_done (phy_init_done), + .ddr_ck (ddr2_ck), + .ddr_ck_n (ddr2_ck_n), + .ddr_addr (ddr2_a), + .ddr_ba (ddr2_ba), + .ddr_ras_n (ddr2_ras_n), + .ddr_cas_n (ddr2_cas_n), + .ddr_we_n (ddr2_we_n), + .ddr_cs_n (ddr2_cs_n), + .ddr_cke (ddr2_cke), + .ddr_odt (ddr2_odt), + .ddr_dm (ddr2_dm), + .ddr_dqs (ddr2_dqs), + .ddr_dqs_n (ddr2_dqs_n), + .ddr_dq (ddr2_dq), + .dbg_idel_up_all (dbg_idel_up_all), + .dbg_idel_down_all (dbg_idel_down_all), + .dbg_idel_up_dq (dbg_idel_up_dq), + .dbg_idel_down_dq (dbg_idel_down_dq), + .dbg_idel_up_dqs (dbg_idel_up_dqs), + .dbg_idel_down_dqs (dbg_idel_down_dqs), + .dbg_idel_up_gate (dbg_idel_up_gate), + .dbg_idel_down_gate (dbg_idel_down_gate), + .dbg_sel_idel_dq (dbg_sel_idel_dq), + .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), + .dbg_sel_idel_dqs (dbg_sel_idel_dqs), + .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), + .dbg_sel_idel_gate (dbg_sel_idel_gate), + .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), + .dbg_calib_done (dbg_calib_done), + .dbg_calib_err (dbg_calib_err), + .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), + .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), + .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), + .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), + .dbg_calib_rden_dly (dbg_calib_rden_dly), + .dbg_calib_gate_dly (dbg_calib_gate_dly) + ); + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_ctrl.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_ctrl.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_ctrl.v (revision 3) @@ -0,0 +1,1230 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_ctrl.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ 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 MEMCtrl module. Please refer to + // the MEMCtrl 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 (rst_r1) + precharge_ok_cnt_r <= 5'd0; + else 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 + Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_addr_fifo.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_addr_fifo.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_addr_fifo.v (revision 3) @@ -0,0 +1,131 @@ +//***************************************************************************** +// 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 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_usr_addr_fifo.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Mon Aug 28 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module instantiates the block RAM based FIFO to store the user +// address and the command information. Also calculates potential bank/row +// conflicts by comparing the new address with last address issued. +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_usr_addr_fifo # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter COL_WIDTH = 10, + parameter CS_BITS = 0, + parameter ROW_WIDTH = 14 + ) + ( + input clk0, + input rst0, + input [2:0] app_af_cmd, + input [30:0] app_af_addr, + input app_af_wren, + input ctrl_af_rden, + output [2:0] af_cmd, + output [30:0] af_addr, + output af_empty, + output app_af_afull + ); + + wire [35:0] fifo_data_out; + reg rst_r; + + + always @(posedge clk0) + rst_r <= rst0; + + + //*************************************************************************** + + assign af_cmd = fifo_data_out[33:31]; + assign af_addr = fifo_data_out[30:0]; + + //*************************************************************************** + + FIFO36 # + ( + .ALMOST_EMPTY_OFFSET (13'h0007), + .ALMOST_FULL_OFFSET (13'h000F), + .DATA_WIDTH (36), + .DO_REG (1), + .EN_SYN ("TRUE"), + .FIRST_WORD_FALL_THROUGH ("FALSE") + ) + u_af + ( + .ALMOSTEMPTY (), + .ALMOSTFULL (app_af_afull), + .DO (fifo_data_out[31:0]), + .DOP (fifo_data_out[35:32]), + .EMPTY (af_empty), + .FULL (), + .RDCOUNT (), + .RDERR (), + .WRCOUNT (), + .WRERR (), + .DI ({app_af_cmd[0],app_af_addr}), + .DIP ({2'b00,app_af_cmd[2:1]}), + .RDCLK (clk0), + .RDEN (ctrl_af_rden), + .RST (rst_r), + .WRCLK (clk0), + .WREN (app_af_wren) + ); + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dm_iob.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dm_iob.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dm_iob.v (revision 3) @@ -0,0 +1,106 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_dm_iob.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module places the data mask signals into the IOBs. +//Reference: +//Revision History: +// Rev 1.1 - To fix timing issues with Synplicity 9.6.1, syn_preserve +// attribute added for the instance u_dm_ce. PK. 11/11/08 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_phy_dm_iob + ( + input clk90, + input dm_ce, + input mask_data_rise, + input mask_data_fall, + output ddr_dm + ); + + wire dm_out; + wire dm_ce_r; + + FDRSE_1 u_dm_ce + ( + .Q (dm_ce_r), + .C (clk90), + .CE (1'b1), + .D (dm_ce), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve=1 */; + + ODDR # + ( + .SRTYPE("SYNC"), + .DDR_CLK_EDGE("SAME_EDGE") + ) + u_oddr_dm + ( + .Q (dm_out), + .C (clk90), + .CE (dm_ce_r), + .D1 (mask_data_rise), + .D2 (mask_data_fall), + .R (1'b0), + .S (1'b0) + ); + + OBUF u_obuf_dm + ( + .I (dm_out), + .O (ddr_dm) + ); + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_write.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_write.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_write.v (revision 3) @@ -0,0 +1,469 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_write.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Thu Aug 24 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +//Reference: +// Handles delaying various write control signals appropriately depending +// on CAS latency, additive latency, etc. Also splits the data and mask in +// rise and fall buses. +//Revision History: +// Rev 1.1 - For Dual Rank parts support ODT logic corrected. PK. 08/05/08 +// Rev 1.2 - Retain current data pattern for stage 4 calibration, and create +// new pattern for stage 4. RC. 09/21/09. +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_phy_write # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter DQ_WIDTH = 72, + parameter CS_NUM = 1, + parameter ADDITIVE_LAT = 0, + parameter CAS_LAT = 5, + parameter ECC_ENABLE = 0, + parameter ODT_TYPE = 1, + parameter REG_ENABLE = 1, + parameter DDR_TYPE = 1 + ) + ( + input clk0, + input clk90, + input rst90, + input [(2*DQ_WIDTH)-1:0] wdf_data, + input [(2*DQ_WIDTH/8)-1:0] wdf_mask_data, + input ctrl_wren, + input phy_init_wren, + input phy_init_data_sel, + output reg dm_ce, + output reg [1:0] dq_oe_n, + output reg dqs_oe_n , + output reg dqs_rst_n , + output wdf_rden, + output reg [CS_NUM-1:0] odt , + output [DQ_WIDTH-1:0] wr_data_rise, + output [DQ_WIDTH-1:0] wr_data_fall, + output [(DQ_WIDTH/8)-1:0] mask_data_rise, + output [(DQ_WIDTH/8)-1:0] mask_data_fall + ); + + localparam MASK_WIDTH = DQ_WIDTH/8; + localparam DDR1 = 0; + localparam DDR2 = 1; + localparam DDR3 = 2; + + // (MIN,MAX) value of WR_LATENCY for DDR1: + // REG_ENABLE = (0,1) + // ECC_ENABLE = (0,1) + // Write latency = 1 + // Total: (1,3) + // (MIN,MAX) value of WR_LATENCY for DDR2: + // REG_ENABLE = (0,1) + // ECC_ENABLE = (0,1) + // Write latency = ADDITIVE_CAS + CAS_LAT - 1 = (0,4) + (3,5) - 1 = (2,8) + // ADDITIVE_LAT = (0,4) (JEDEC79-2B) + // CAS_LAT = (3,5) (JEDEC79-2B) + // Total: (2,10) + localparam WR_LATENCY = (DDR_TYPE == DDR3) ? + (ADDITIVE_LAT + (CAS_LAT) + REG_ENABLE ) : + (DDR_TYPE == DDR2) ? + (ADDITIVE_LAT + (CAS_LAT-1) + REG_ENABLE ) : + (1 + REG_ENABLE ); + + // NOTE that ODT timing does not need to be delayed for registered + // DIMM case, since like other control/address signals, it gets + // delayed by one clock cycle at the DIMM + localparam ODT_WR_LATENCY = WR_LATENCY - REG_ENABLE; + + wire dm_ce_0; + reg dm_ce_r; + wire [1:0] dq_oe_0; + reg [1:0] dq_oe_n_90_r1; + reg [1:0] dq_oe_270; + wire dqs_oe_0; + reg dqs_oe_270; + reg dqs_oe_n_180_r1; + wire dqs_rst_0; + reg dqs_rst_n_180_r1; + reg dqs_rst_270; + reg ecc_dm_error_r; + reg ecc_dm_error_r1; + reg [(DQ_WIDTH-1):0] init_data_f; + reg [(DQ_WIDTH-1):0] init_data_r; + reg [3:0] init_wdf_cnt_r; + wire odt_0; + reg rst90_r /* synthesis syn_maxfan = 10 */; + reg [10:0] wr_stages ; + reg [(2*DQ_WIDTH)-1:0] wdf_data_r; + reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r; + wire [(2*DQ_WIDTH/8)-1:0] wdf_ecc_mask; + + reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r1; + wire wdf_rden_0; + reg calib_rden_90_r; + reg wdf_rden_90_r; + reg wdf_rden_90_r1; + reg wdf_rden_270; + + always @(posedge clk90) + rst90_r <= rst90; + + //*************************************************************************** + // Analysis of additional pipeline delays: + // 1. dq_oe (DQ 3-state): 1 CLK90 cyc in IOB 3-state FF + // 2. dqs_oe (DQS 3-state): 1 CLK180 cyc in IOB 3-state FF + // 3. dqs_rst (DQS output value reset): 1 CLK180 cyc in FF + 1 CLK180 cyc + // in IOB DDR + // 4. odt (ODT control): 1 CLK0 cyc in IOB FF + // 5. write data (output two cyc after wdf_rden - output of RAMB_FIFO w/ + // output register enabled): 2 CLK90 cyc in OSERDES + //*************************************************************************** + + // DQS 3-state must be asserted one extra clock cycle due b/c of write + // pre- and post-amble (extra half clock cycle for each) + assign dqs_oe_0 = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2]; + + // same goes for ODT, need to handle both pre- and post-amble (generate + // ODT only for DDR2) + // ODT generation for DDR2 based on write latency. The MIN write + // latency is 2. Based on the write latency ODT is asserted. + generate + if ((DDR_TYPE != DDR1) && (ODT_TYPE > 0))begin: gen_odt_ddr2 + if(ODT_WR_LATENCY > 3) + assign odt_0 = + wr_stages[ODT_WR_LATENCY-2] | + wr_stages[ODT_WR_LATENCY-3] | + wr_stages[ODT_WR_LATENCY-4] ; + else if ( ODT_WR_LATENCY == 3) + assign odt_0 = + wr_stages[ODT_WR_LATENCY-1] | + wr_stages[ODT_WR_LATENCY-2] | + wr_stages[ODT_WR_LATENCY-3] ; + else + assign odt_0 = + wr_stages[ODT_WR_LATENCY] | + wr_stages[ODT_WR_LATENCY-1] | + wr_stages[ODT_WR_LATENCY-2] ; + end else + assign odt_0 = 1'b0; + endgenerate + + assign dq_oe_0[0] = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY]; + assign dq_oe_0[1] = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2]; + assign dqs_rst_0 = ~wr_stages[WR_LATENCY-2]; + assign dm_ce_0 = wr_stages[WR_LATENCY] | wr_stages[WR_LATENCY-1] + | wr_stages[WR_LATENCY-2]; + + // write data fifo, read flag assertion + generate + if (DDR_TYPE != DDR1) begin: gen_wdf_ddr2 + if (WR_LATENCY > 2) + assign wdf_rden_0 = wr_stages[WR_LATENCY-3]; + else + assign wdf_rden_0 = wr_stages[WR_LATENCY-2]; + end else begin: gen_wdf_ddr1 + assign wdf_rden_0 = wr_stages[WR_LATENCY-2]; + end + endgenerate + + // first stage isn't registered + always @(*) + wr_stages[0] = (phy_init_data_sel) ? ctrl_wren : phy_init_wren; + + always @(posedge clk0) begin + wr_stages[1] <= wr_stages[0]; + wr_stages[2] <= wr_stages[1]; + wr_stages[3] <= wr_stages[2]; + wr_stages[4] <= wr_stages[3]; + wr_stages[5] <= wr_stages[4]; + wr_stages[6] <= wr_stages[5]; + wr_stages[7] <= wr_stages[6]; + wr_stages[8] <= wr_stages[7]; + wr_stages[9] <= wr_stages[8]; + wr_stages[10] <= wr_stages[9]; + end + + // intermediate synchronization to CLK270 + always @(negedge clk90) begin + dq_oe_270 <= dq_oe_0; + dqs_oe_270 <= dqs_oe_0; + dqs_rst_270 <= dqs_rst_0; + wdf_rden_270 <= wdf_rden_0; + end + + // synchronize DQS signals to CLK180 + always @(negedge clk0) begin + dqs_oe_n_180_r1 <= ~dqs_oe_270; + dqs_rst_n_180_r1 <= ~dqs_rst_270; + end + + // All write data-related signals synced to CLK90 + always @(posedge clk90) begin + dq_oe_n_90_r1 <= ~dq_oe_270; + wdf_rden_90_r <= wdf_rden_270; + end + + // generate for wdf_rden and calib rden. These signals + // are asserted based on write latency. For write + // latency of 2, the extra register stage is taken out. + generate + if (WR_LATENCY > 2) begin + always @(posedge clk90) begin + // assert wdf rden only for non calibration opertations + wdf_rden_90_r1 <= wdf_rden_90_r & + phy_init_data_sel; + // rden for calibration + calib_rden_90_r <= wdf_rden_90_r; + end + end else begin + always @(*) begin + wdf_rden_90_r1 = wdf_rden_90_r + & phy_init_data_sel; + calib_rden_90_r = wdf_rden_90_r; + end + end // else: !if(WR_LATENCY > 2) + endgenerate + + // dm CE signal to stop dm oscilation + always @(negedge clk90)begin + dm_ce_r <= dm_ce_0; + dm_ce <= dm_ce_r; + end + + // When in ECC mode the upper byte [71:64] will have the + // ECC parity. Mapping the bytes which have valid data + // to the upper byte in ecc mode. Also in ecc mode there + // is an extra register stage to account for timing. + + genvar mask_i; + generate + if(ECC_ENABLE) begin + for (mask_i = 0; mask_i < (2*DQ_WIDTH)/72; + mask_i = mask_i+1) begin: gen_mask + assign wdf_ecc_mask[((mask_i*9)+9)-1:(mask_i*9)] = + {&wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9], + wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9]}; + end + end + endgenerate + + generate + if (ECC_ENABLE) begin:gen_ecc_reg + always @(posedge clk90)begin + if(phy_init_data_sel) + wdf_mask_r <= wdf_ecc_mask; + else + wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}}; + end + end else begin + always@(posedge clk90) begin + if (phy_init_data_sel) + wdf_mask_r <= wdf_mask_data; + else + wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}}; + end + end + endgenerate + + always @(posedge clk90) begin + if(phy_init_data_sel) + wdf_data_r <= wdf_data; + else + wdf_data_r <={init_data_f,init_data_r}; + end + + // Error generation block during simulation. + // Error will be displayed when all the DM + // bits are not zero. The error will be + // displayed only during the start of the sequence + // for errors that are continous over many cycles. + generate + if (ECC_ENABLE) begin: gen_ecc_error + always @(posedge clk90) begin + //synthesis translate_off + wdf_mask_r1 <= wdf_mask_r; + if(DQ_WIDTH > 72) + ecc_dm_error_r + <= ( + (~wdf_mask_r1[35] && (|wdf_mask_r1[34:27])) || + (~wdf_mask_r1[26] && (|wdf_mask_r1[25:18])) || + (~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) || + (~wdf_mask_r1[8] && (|wdf_mask_r1[7:0]))) && phy_init_data_sel; + else + ecc_dm_error_r + <= ((~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) || + (~wdf_mask_r1[8] && (|wdf_mask_r1[7:0]))) && phy_init_data_sel; + ecc_dm_error_r1 <= ecc_dm_error_r ; + if (ecc_dm_error_r && ~ecc_dm_error_r1) // assert the error only once. + $display ("ECC DM ERROR. "); + //synthesis translate_on + end + end + endgenerate + + //*************************************************************************** + // State logic to write calibration training patterns + //*************************************************************************** + + always @(posedge clk90) begin + if (rst90_r) begin + init_wdf_cnt_r <= 4'd0; + init_data_r <= {64{1'bx}}; + init_data_f <= {64{1'bx}}; + end else begin + init_wdf_cnt_r <= init_wdf_cnt_r + calib_rden_90_r; + casex (init_wdf_cnt_r) + // First stage calibration. Pattern (rise/fall) = 1(r)->0(f) + // The rise data and fall data are already interleaved in the manner + // required for data into the WDF write FIFO + 4'b00xx: begin + init_data_r <= {DQ_WIDTH{1'b1}}; + init_data_f <= {DQ_WIDTH{1'b0}}; + end + // Second stage calibration. Pattern = 1(r)->1(f)->0(r)->0(f) + 4'b01x0: begin + init_data_r <= {DQ_WIDTH{1'b1}}; + init_data_f <= {DQ_WIDTH{1'b1}}; + end + 4'b01x1: begin + init_data_r <= {DQ_WIDTH{1'b0}}; + init_data_f <= {DQ_WIDTH{1'b0}}; + end + // MIG 3.2: Changed Stage 3/4 training pattern + // Third stage calibration patern = + // 11(r)->ee(f)->ee(r)->11(f)-ee(r)->11(f)->ee(r)->11(f) + 4'b1000: begin + init_data_r <= {DQ_WIDTH/4{4'h1}}; + init_data_f <= {DQ_WIDTH/4{4'hE}}; + end + 4'b1001: begin + init_data_r <= {DQ_WIDTH/4{4'hE}}; + init_data_f <= {DQ_WIDTH/4{4'h1}}; + end + 4'b1010: begin + init_data_r <= {(DQ_WIDTH/4){4'hE}}; + init_data_f <= {(DQ_WIDTH/4){4'h1}}; + end + 4'b1011: begin + init_data_r <= {(DQ_WIDTH/4){4'hE}}; + init_data_f <= {(DQ_WIDTH/4){4'h1}}; + end + // Fourth stage calibration patern = + // 11(r)->ee(f)->ee(r)->11(f)-11(r)->ee(f)->ee(r)->11(f) + 4'b1100: begin + init_data_r <= {DQ_WIDTH/4{4'h1}}; + init_data_f <= {DQ_WIDTH/4{4'hE}}; + end + 4'b1101: begin + init_data_r <= {DQ_WIDTH/4{4'hE}}; + init_data_f <= {DQ_WIDTH/4{4'h1}}; + end + 4'b1110: begin + init_data_r <= {(DQ_WIDTH/4){4'h1}}; + init_data_f <= {(DQ_WIDTH/4){4'hE}}; + end + 4'b1111: begin + // MIG 3.5: Corrected last two writes for stage 4 calibration + // training pattern. Previously MIG 3.3 and MIG 3.4 had the + // incorrect pattern. This can sometimes result in a calibration + // point with small timing margin. +// init_data_r <= {(DQ_WIDTH/4){4'h1}}; +// init_data_f <= {(DQ_WIDTH/4){4'hE}}; + init_data_r <= {(DQ_WIDTH/4){4'hE}}; + init_data_f <= {(DQ_WIDTH/4){4'h1}}; + end + endcase + end + end + + //*************************************************************************** + + always @(posedge clk90) + dq_oe_n <= dq_oe_n_90_r1; + + always @(negedge clk0) + dqs_oe_n <= dqs_oe_n_180_r1; + + always @(negedge clk0) + dqs_rst_n <= dqs_rst_n_180_r1; + + // generate for odt. odt is asserted based on + // write latency. For write latency of 2 + // the extra register stage is taken out. + generate + if (ODT_WR_LATENCY > 3) begin + always @(posedge clk0) begin + odt <= 'b0; + odt[0] <= odt_0; + end + end else begin + always @ (*) begin + odt = 'b0; + odt[0] = odt_0; + end + end + endgenerate + + assign wdf_rden = wdf_rden_90_r1; + + //*************************************************************************** + // Format write data/mask: Data is in format: {fall, rise} + //*************************************************************************** + + assign wr_data_rise = wdf_data_r[DQ_WIDTH-1:0]; + assign wr_data_fall = wdf_data_r[(2*DQ_WIDTH)-1:DQ_WIDTH]; + assign mask_data_rise = wdf_mask_r[MASK_WIDTH-1:0]; + assign mask_data_fall = wdf_mask_r[(2*MASK_WIDTH)-1:MASK_WIDTH]; + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dq_iob.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dq_iob.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_dq_iob.v (revision 3) @@ -0,0 +1,592 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_dq_iob.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module places the data in the IOBs. +//Reference: +//Revision History: +// Rev 1.1 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 +// Rev 1.2 - DIRT strings removed and modified the code. PK. 11/13/08 +// Rev 1.3 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added +// on IODELAY primitive. PK. 11/27/08 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_phy_dq_iob # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter HIGH_PERFORMANCE_MODE = "TRUE", + parameter IODELAY_GRP = "IODELAY_MIG", + parameter FPGA_SPEED_GRADE = 2 + ) + ( + input clk0, + input clk90, + input clkdiv0, + input rst90, + input dlyinc, + input dlyce, + input dlyrst, + input [1:0] dq_oe_n, + input dqs, + input ce, + input rd_data_sel, + input wr_data_rise, + input wr_data_fall, + output rd_data_rise, + output rd_data_fall, + inout ddr_dq + ); + + wire dq_iddr_clk; + wire dq_idelay; + wire dq_in; + wire dq_oe_n_r; + wire dq_out; + wire stg2a_out_fall; + wire stg2a_out_rise; + (* XIL_PAR_DELAY = "0 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) + wire stg2b_out_fall; + (* XIL_PAR_DELAY = "0 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) + wire stg2b_out_rise; + wire stg3a_out_fall; + wire stg3a_out_rise; + wire stg3b_out_fall; + wire stg3b_out_rise; + + //*************************************************************************** + // Directed routing constraints for route between IDDR and stage 2 capture + // in fabric. + // Only 2 out of the 12 wire declarations will be used for any given + // instantiation of this module. + // Varies according: + // (1) I/O column (left, center, right) used + // (2) Which I/O in I/O pair (master, slave) used + // Nomenclature: _Xy, X = column (0 = left, 1 = center, 2 = right), + // y = master or slave + //*************************************************************************** + + // MODIFIED, RC, 06/13/08: Remove all references to DIRT, master/slave + + (* XIL_PAR_DELAY = "515 ps", XIL_PAR_SKEW = "55 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) + wire stg1_out_rise_sg3; + (* XIL_PAR_DELAY = "515 ps", XIL_PAR_SKEW = "55 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) + wire stg1_out_fall_sg3; + (* XIL_PAR_DELAY = "575 ps", XIL_PAR_SKEW = "65 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) + wire stg1_out_rise_sg2; + (* XIL_PAR_DELAY = "575 ps", XIL_PAR_SKEW = "65 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) + wire stg1_out_fall_sg2; + (* XIL_PAR_DELAY = "650 ps", XIL_PAR_SKEW = "70 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) + wire stg1_out_rise_sg1; + (* XIL_PAR_DELAY = "650 ps", XIL_PAR_SKEW = "70 ps", XIL_PAR_IP_NAME = "MIG", syn_keep = "1", keep = "TRUE" *) + wire stg1_out_fall_sg1; + + //*************************************************************************** + // Bidirectional I/O + //*************************************************************************** + + IOBUF u_iobuf_dq + ( + .I (dq_out), + .T (dq_oe_n_r), + .IO (ddr_dq), + .O (dq_in) + ); + + //*************************************************************************** + // Write (output) path + //*************************************************************************** + + // on a write, rising edge of DQS corresponds to rising edge of CLK180 + // (aka falling edge of CLK0 -> rising edge DQS). We also know: + // 1. data must be driven 1/4 clk cycle before corresponding DQS edge + // 2. first rising DQS edge driven on falling edge of CLK0 + // 3. rising data must be driven 1/4 cycle before falling edge of CLK0 + // 4. therefore, rising data driven on rising edge of CLK + ODDR # + ( + .SRTYPE("SYNC"), + .DDR_CLK_EDGE("SAME_EDGE") + ) + u_oddr_dq + ( + .Q (dq_out), + .C (clk90), + .CE (1'b1), + .D1 (wr_data_rise), + .D2 (wr_data_fall), + .R (1'b0), + .S (1'b0) + ); + + // make sure output is tri-state during reset (DQ_OE_N_R = 1) + ODDR # + ( + .SRTYPE("ASYNC"), + .DDR_CLK_EDGE("SAME_EDGE") + ) + u_tri_state_dq + ( + .Q (dq_oe_n_r), + .C (clk90), + .CE (1'b1), + .D1 (dq_oe_n[0]), + .D2 (dq_oe_n[1]), + .R (1'b0), + .S (rst90) + ); + + //*************************************************************************** + // Read data capture scheme description: + // Data capture consists of 3 ranks of flops, and a MUX + // 1. Rank 1 ("Stage 1"): IDDR captures delayed DDR DQ from memory using + // delayed DQS. + // - Data is split into 2 SDR streams, one each for rise and fall data. + // - BUFIO (DQS) input inverted to IDDR. IDDR configured in SAME_EDGE + // mode. This means that: (1) Q1 = fall data, Q2 = rise data, + // (2) Both rise and fall data are output on falling edge of DQS - + // rather than rise output being output on one edge of DQS, and fall + // data on the other edge if the IDDR were configured in OPPOSITE_EDGE + // mode. This simplifies Stage 2 capture (only one core clock edge + // used, removing effects of duty-cycle-distortion), and saves one + // fabric flop in Rank 3. + // 2. Rank 2 ("Stage 2"): Fabric flops are used to capture output of first + // rank into FPGA clock (CLK) domain. Each rising/falling SDR stream + // from IDDR is feed into two flops, one clocked off rising and one off + // falling edge of CLK. One of these flops is chosen, with the choice + // being the one that reduces # of DQ/DQS taps necessary to align Stage + // 1 and Stage 2. Same edge is used to capture both rise and fall SDR + // streams. + // 3. Rank 3 ("Stage 3"): Removes half-cycle paths in CLK domain from + // output of Rank 2. This stage, like Stage 2, is clocked by CLK. Note + // that Stage 3 can be expanded to also support SERDES functionality + // 4. Output MUX: Selects whether Stage 1 output is aligned to rising or + // falling edge of CLK (i.e. specifically this selects whether IDDR + // rise/fall output is transfered to rising or falling edge of CLK). + // Implementation: + // 1. Rank 1 is implemented using an IDDR primitive + // 2. Rank 2 is implemented using: + // - An RPM to fix the location of the capture flops near the DQ I/O. + // The exact RPM used depends on which I/O column (left, center, + // right) the DQ I/O is placed at - this affects the optimal location + // of the slice flops (or does it - can we always choose the two + // columns to slices to the immediate right of the I/O to use, no + // matter what the column?). The origin of the RPM must be set in the + // UCF file using the RLOC_ORIGIN constraint (where the original is + // based on the DQ I/O location). + // - Directed Routing Constraints ("DIRT strings") to fix the routing + // to the rank 2 fabric flops. This is done to minimize: (1) total + // route delay (and therefore minimize voltage/temperature-related + // variations), and (2) minimize skew both within each rising and + // falling data net, as well as between the rising and falling nets. + // The exact DIRT string used depends on: (1) which I/O column the + // DQ I/O is placed, and (2) whether the DQ I/O is placed on the + // "Master" or "Slave" I/O of a diff pair (DQ is not differential, but + // the routing will be affected by which of each I/O pair is used) + // 3. Rank 3 is implemented using fabric flops. No LOC or DIRT contraints + // are used, tools are expected to place these and meet PERIOD timing + // without constraints (constraints may be necessary for "full" designs, + // in this case, user may need to add LOC constraints - if this is the + // case, there are no constraints - other than meeting PERIOD timing - + // for rank 3 flops. + //*************************************************************************** + + //*************************************************************************** + // MIG 2.2: Define AREA_GROUP = "DDR_CAPTURE_FFS" contain all RPM flops in + // design. In UCF file, add constraint: + // AREA_GROUP "DDR_CAPTURE_FFS" GROUP = CLOSED; + // This is done to prevent MAP from packing unrelated logic into + // the slices used by the RPMs. Doing so may cause the DIRT strings + // that define the IDDR -> fabric flop routing to later become + // unroutable during PAR because the unrelated logic placed by MAP + // may use routing resources required by the DIRT strings. MAP + // does not currently take into account DIRT strings when placing + // logic + //*************************************************************************** + + // IDELAY to delay incoming data for synchronization purposes + (* IODELAY_GROUP = IODELAY_GRP *) IODELAY # + ( + .DELAY_SRC ("I"), + .IDELAY_TYPE ("VARIABLE"), + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .IDELAY_VALUE (0), + .ODELAY_VALUE (0) + ) + u_idelay_dq + ( + .DATAOUT (dq_idelay), + .C (clkdiv0), + .CE (dlyce), + .DATAIN (), + .IDATAIN (dq_in), + .INC (dlyinc), + .ODATAIN (), + .RST (dlyrst), + .T () + ); + + //*************************************************************************** + // Rank 1 capture: Use IDDR to generate two SDR outputs + //*************************************************************************** + + // invert clock to IDDR in order to use SAME_EDGE mode (otherwise, we "run + // out of clocks" because DQS is not continuous + assign dq_iddr_clk = ~dqs; + + //*************************************************************************** + // Rank 2 capture: Use fabric flops to capture Rank 1 output. Use RPM and + // DIRT strings here. + // BEL ("Basic Element of Logic") and relative location constraints for + // second stage capture. C + // Varies according: + // (1) I/O column (left, center, right) used + // (2) Which I/O in I/O pair (master, slave) used + //*************************************************************************** + + // MODIFIED, RC, 06/13/08: Remove all references to DIRT, master/slave + // Take out generate statements - collapses to a single case + + generate + if (FPGA_SPEED_GRADE == 3) begin: gen_stg2_sg3 + IDDR # + ( + .DDR_CLK_EDGE ("SAME_EDGE") + ) + u_iddr_dq + ( + .Q1 (stg1_out_fall_sg3), + .Q2 (stg1_out_rise_sg3), + .C (dq_iddr_clk), + .CE (ce), + .D (dq_idelay), + .R (1'b0), + .S (1'b0) + ); + + //********************************************************* + // Slice #1 (posedge CLK): Used for: + // 1. IDDR transfer to CLK0 rising edge domain ("stg2a") + // 2. stg2 falling edge -> stg3 rising edge transfer + //********************************************************* + + // Stage 2 capture + FDRSE u_ff_stg2a_fall + ( + .Q (stg2a_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg1_out_fall_sg3), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + FDRSE u_ff_stg2a_rise + ( + .Q (stg2a_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg1_out_rise_sg3), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + // Stage 3 falling -> rising edge translation + FDRSE u_ff_stg3b_fall + ( + .Q (stg3b_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg2b_out_fall), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + FDRSE u_ff_stg3b_rise + ( + .Q (stg3b_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg2b_out_rise), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + + //********************************************************* + // Slice #2 (posedge CLK): Used for: + // 1. IDDR transfer to CLK0 falling edge domain ("stg2b") + //********************************************************* + + FDRSE_1 u_ff_stg2b_fall + ( + .Q (stg2b_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg1_out_fall_sg3), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + + FDRSE_1 u_ff_stg2b_rise + ( + .Q (stg2b_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg1_out_rise_sg3), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + end else if (FPGA_SPEED_GRADE == 2) begin: gen_stg2_sg2 + IDDR # + ( + .DDR_CLK_EDGE ("SAME_EDGE") + ) + u_iddr_dq + ( + .Q1 (stg1_out_fall_sg2), + .Q2 (stg1_out_rise_sg2), + .C (dq_iddr_clk), + .CE (ce), + .D (dq_idelay), + .R (1'b0), + .S (1'b0) + ); + + //********************************************************* + // Slice #1 (posedge CLK): Used for: + // 1. IDDR transfer to CLK0 rising edge domain ("stg2a") + // 2. stg2 falling edge -> stg3 rising edge transfer + //********************************************************* + + // Stage 2 capture + FDRSE u_ff_stg2a_fall + ( + .Q (stg2a_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg1_out_fall_sg2), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + FDRSE u_ff_stg2a_rise + ( + .Q (stg2a_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg1_out_rise_sg2), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + // Stage 3 falling -> rising edge translation + FDRSE u_ff_stg3b_fall + ( + .Q (stg3b_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg2b_out_fall), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + FDRSE u_ff_stg3b_rise + ( + .Q (stg3b_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg2b_out_rise), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + + //********************************************************* + // Slice #2 (posedge CLK): Used for: + // 1. IDDR transfer to CLK0 falling edge domain ("stg2b") + //********************************************************* + + FDRSE_1 u_ff_stg2b_fall + ( + .Q (stg2b_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg1_out_fall_sg2), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + + FDRSE_1 u_ff_stg2b_rise + ( + .Q (stg2b_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg1_out_rise_sg2), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + end else if (FPGA_SPEED_GRADE == 1) begin: gen_stg2_sg1 + IDDR # + ( + .DDR_CLK_EDGE ("SAME_EDGE") + ) + u_iddr_dq + ( + .Q1 (stg1_out_fall_sg1), + .Q2 (stg1_out_rise_sg1), + .C (dq_iddr_clk), + .CE (ce), + .D (dq_idelay), + .R (1'b0), + .S (1'b0) + ); + + //********************************************************* + // Slice #1 (posedge CLK): Used for: + // 1. IDDR transfer to CLK0 rising edge domain ("stg2a") + // 2. stg2 falling edge -> stg3 rising edge transfer + //********************************************************* + + // Stage 2 capture + FDRSE u_ff_stg2a_fall + ( + .Q (stg2a_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg1_out_fall_sg1), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + FDRSE u_ff_stg2a_rise + ( + .Q (stg2a_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg1_out_rise_sg1), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + // Stage 3 falling -> rising edge translation + FDRSE u_ff_stg3b_fall + ( + .Q (stg3b_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg2b_out_fall), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + FDRSE u_ff_stg3b_rise + ( + .Q (stg3b_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg2b_out_rise), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + + //********************************************************* + // Slice #2 (posedge CLK): Used for: + // 1. IDDR transfer to CLK0 falling edge domain ("stg2b") + //********************************************************* + + FDRSE_1 u_ff_stg2b_fall + ( + .Q (stg2b_out_fall), + .C (clk0), + .CE (1'b1), + .D (stg1_out_fall_sg1), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + + FDRSE_1 u_ff_stg2b_rise + ( + .Q (stg2b_out_rise), + .C (clk0), + .CE (1'b1), + .D (stg1_out_rise_sg1), + .R (1'b0), + .S (1'b0) + )/* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + end + endgenerate + + //*************************************************************************** + // Second stage flops clocked by posedge CLK0 don't need another layer of + // registering + //*************************************************************************** + + assign stg3a_out_rise = stg2a_out_rise; + assign stg3a_out_fall = stg2a_out_fall; + + //******************************************************************* + + assign rd_data_rise = (rd_data_sel) ? stg3a_out_rise : stg3b_out_rise; + assign rd_data_fall = (rd_data_sel) ? stg3a_out_fall : stg3b_out_fall; + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_chipscope.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_chipscope.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_chipscope.v (revision 3) @@ -0,0 +1,114 @@ +//***************************************************************************** +// 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 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_chipscope.v +// /___/ /\ Date Last Modified: $Data$ +// \ \ / \ Date Created: 9/14/06 +// \___\/\___\ +// +//Device: Virtex-5 +//Purpose: +// Skeleton Chipscope module declarations - for simulation only +//Reference: +//Revision History: +// +//***************************************************************************** + +`timescale 1ns/1ps + +module icon4 + ( + control0, + control1, + control2, + control3 + ) + /* synthesis syn_black_box syn_noprune = 1 */; + output [35:0] control0; + output [35:0] control1; + output [35:0] control2; + output [35:0] control3; +endmodule + +module vio_async_in192 + ( + control, + async_in + ) + /* synthesis syn_black_box syn_noprune = 1 */; + input [35:0] control; + input [191:0] async_in; +endmodule + +module vio_async_in96 + ( + control, + async_in + ) + /* synthesis syn_black_box syn_noprune = 1 */; + input [35:0] control; + input [95:0] async_in; +endmodule + +module vio_async_in100 + ( + control, + async_in + ) + /* synthesis syn_black_box syn_noprune = 1 */; + input [35:0] control; + input [99:0] async_in; +endmodule + +module vio_sync_out32 + ( + control, + clk, + sync_out + ) + /* synthesis syn_black_box syn_noprune = 1 */; + input [35:0] control; + input clk; + output [31:0] sync_out; +endmodule \ No newline at end of file Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_mem_if_top.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_mem_if_top.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_mem_if_top.v (revision 3) @@ -0,0 +1,380 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_mem_if_top.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR/DDR2 +//Purpose: +// Top-level for parameterizable (DDR or DDR2) memory interface +//Reference: +//Revision History: +// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 +// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 +// Rev 1.3 - Parameter CS_BITS added. PK. 10/8/08 +// Rev 1.4 - Parameter IODELAY_GRP added. PK. 11/27/08 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_mem_if_top # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter CKE_WIDTH = 1, + parameter CLK_WIDTH = 1, + parameter COL_WIDTH = 10, + parameter CS_BITS = 0, + parameter CS_NUM = 1, + parameter CS_WIDTH = 1, + parameter USE_DM_PORT = 1, + parameter DM_WIDTH = 9, + parameter DQ_WIDTH = 72, + parameter DQ_BITS = 7, + parameter DQ_PER_DQS = 8, + parameter DQS_BITS = 4, + parameter DQS_WIDTH = 9, + parameter HIGH_PERFORMANCE_MODE = "TRUE", + parameter IODELAY_GRP = "IODELAY_MIG", + parameter ODT_WIDTH = 1, + parameter ROW_WIDTH = 14, + parameter APPDATA_WIDTH = 144, + parameter ADDITIVE_LAT = 0, + parameter BURST_LEN = 4, + parameter BURST_TYPE = 0, + parameter CAS_LAT = 5, + parameter ECC_ENABLE = 0, + parameter MULTI_BANK_EN = 1, + parameter TWO_T_TIME_EN = 0, + parameter ODT_TYPE = 1, + parameter DDR_TYPE = 1, + parameter REDUCE_DRV = 0, + parameter REG_ENABLE = 1, + parameter TREFI_NS = 7800, + parameter TRAS = 40000, + parameter TRCD = 15000, + parameter TRFC = 105000, + parameter TRP = 15000, + parameter TRTP = 7500, + parameter TWR = 15000, + parameter TWTR = 10000, + parameter CLK_PERIOD = 3000, + parameter SIM_ONLY = 0, + parameter DEBUG_EN = 0, + parameter FPGA_SPEED_GRADE = 2 + ) + ( + input clk0, + input clk90, + input clkdiv0, + input rst0, + input rst90, + input rstdiv0, + input [2:0] app_af_cmd, + input [30:0] app_af_addr, + input app_af_wren, + input app_wdf_wren, + input [APPDATA_WIDTH-1:0] app_wdf_data, + input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, + output [1:0] rd_ecc_error, + output app_af_afull, + output app_wdf_afull, + output rd_data_valid, + output [APPDATA_WIDTH-1:0] rd_data_fifo_out, + output phy_init_done, + output [CLK_WIDTH-1:0] ddr_ck, + output [CLK_WIDTH-1:0] ddr_ck_n, + output [ROW_WIDTH-1:0] ddr_addr, + output [BANK_WIDTH-1:0] ddr_ba, + output ddr_ras_n, + output ddr_cas_n, + output ddr_we_n, + output [CS_WIDTH-1:0] ddr_cs_n, + output [CKE_WIDTH-1:0] ddr_cke, + output [ODT_WIDTH-1:0] ddr_odt, + output [DM_WIDTH-1:0] ddr_dm, + inout [DQS_WIDTH-1:0] ddr_dqs, + inout [DQS_WIDTH-1:0] ddr_dqs_n, + inout [DQ_WIDTH-1:0] ddr_dq, + // Debug signals (optional use) + input dbg_idel_up_all, + input dbg_idel_down_all, + input dbg_idel_up_dq, + input dbg_idel_down_dq, + input dbg_idel_up_dqs, + input dbg_idel_down_dqs, + input dbg_idel_up_gate, + input dbg_idel_down_gate, + input [DQ_BITS-1:0] dbg_sel_idel_dq, + input dbg_sel_all_idel_dq, + input [DQS_BITS:0] dbg_sel_idel_dqs, + input dbg_sel_all_idel_dqs, + input [DQS_BITS:0] dbg_sel_idel_gate, + input dbg_sel_all_idel_gate, + output [3:0] dbg_calib_done, + output [3:0] dbg_calib_err, + output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, + output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, + output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, + output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly + ); + + wire [30:0] af_addr; + wire [2:0] af_cmd; + wire af_empty; + wire [ROW_WIDTH-1:0] ctrl_addr; + wire ctrl_af_rden; + wire [BANK_WIDTH-1:0] ctrl_ba; + wire ctrl_cas_n; + wire [CS_NUM-1:0] ctrl_cs_n; + wire ctrl_ras_n; + wire ctrl_rden; + wire ctrl_ref_flag; + wire ctrl_we_n; + wire ctrl_wren; + wire [DQS_WIDTH-1:0] phy_calib_rden; + wire [DQS_WIDTH-1:0] phy_calib_rden_sel; + wire [DQ_WIDTH-1:0] rd_data_fall; + wire [DQ_WIDTH-1:0] rd_data_rise; + wire [(2*DQ_WIDTH)-1:0] wdf_data; + wire [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data; + wire wdf_rden; + + //*************************************************************************** + + ddr2_phy_top # + ( + .BANK_WIDTH (BANK_WIDTH), + .CKE_WIDTH (CKE_WIDTH), + .CLK_WIDTH (CLK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_BITS (CS_BITS), + .CS_NUM (CS_NUM), + .CS_WIDTH (CS_WIDTH), + .USE_DM_PORT (USE_DM_PORT), + .DM_WIDTH (DM_WIDTH), + .DQ_WIDTH (DQ_WIDTH), + .DQ_BITS (DQ_BITS), + .DQ_PER_DQS (DQ_PER_DQS), + .DQS_BITS (DQS_BITS), + .DQS_WIDTH (DQS_WIDTH), + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .IODELAY_GRP (IODELAY_GRP), + .ODT_WIDTH (ODT_WIDTH), + .ROW_WIDTH (ROW_WIDTH), + .TWO_T_TIME_EN (TWO_T_TIME_EN), + .ADDITIVE_LAT (ADDITIVE_LAT), + .BURST_LEN (BURST_LEN), + .BURST_TYPE (BURST_TYPE), + .CAS_LAT (CAS_LAT), + .ECC_ENABLE (ECC_ENABLE), + .ODT_TYPE (ODT_TYPE), + .DDR_TYPE (DDR_TYPE), + .REDUCE_DRV (REDUCE_DRV), + .REG_ENABLE (REG_ENABLE), + .TWR (TWR), + .CLK_PERIOD (CLK_PERIOD), + .SIM_ONLY (SIM_ONLY), + .DEBUG_EN (DEBUG_EN), + .FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) + ) + u_phy_top + ( + .clk0 (clk0), + .clk90 (clk90), + .clkdiv0 (clkdiv0), + .rst0 (rst0), + .rst90 (rst90), + .rstdiv0 (rstdiv0), + .ctrl_wren (ctrl_wren), + .ctrl_addr (ctrl_addr), + .ctrl_ba (ctrl_ba), + .ctrl_ras_n (ctrl_ras_n), + .ctrl_cas_n (ctrl_cas_n), + .ctrl_we_n (ctrl_we_n), + .ctrl_cs_n (ctrl_cs_n), + .ctrl_rden (ctrl_rden), + .ctrl_ref_flag (ctrl_ref_flag), + .wdf_data (wdf_data), + .wdf_mask_data (wdf_mask_data), + .wdf_rden (wdf_rden), + .phy_init_done (phy_init_done), + .phy_calib_rden (phy_calib_rden), + .phy_calib_rden_sel (phy_calib_rden_sel), + .rd_data_rise (rd_data_rise), + .rd_data_fall (rd_data_fall), + .ddr_ck (ddr_ck), + .ddr_ck_n (ddr_ck_n), + .ddr_addr (ddr_addr), + .ddr_ba (ddr_ba), + .ddr_ras_n (ddr_ras_n), + .ddr_cas_n (ddr_cas_n), + .ddr_we_n (ddr_we_n), + .ddr_cs_n (ddr_cs_n), + .ddr_cke (ddr_cke), + .ddr_odt (ddr_odt), + .ddr_dm (ddr_dm), + .ddr_dqs (ddr_dqs), + .ddr_dqs_n (ddr_dqs_n), + .ddr_dq (ddr_dq), + .dbg_idel_up_all (dbg_idel_up_all), + .dbg_idel_down_all (dbg_idel_down_all), + .dbg_idel_up_dq (dbg_idel_up_dq), + .dbg_idel_down_dq (dbg_idel_down_dq), + .dbg_idel_up_dqs (dbg_idel_up_dqs), + .dbg_idel_down_dqs (dbg_idel_down_dqs), + .dbg_idel_up_gate (dbg_idel_up_gate), + .dbg_idel_down_gate (dbg_idel_down_gate), + .dbg_sel_idel_dq (dbg_sel_idel_dq), + .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), + .dbg_sel_idel_dqs (dbg_sel_idel_dqs), + .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), + .dbg_sel_idel_gate (dbg_sel_idel_gate), + .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), + .dbg_calib_done (dbg_calib_done), + .dbg_calib_err (dbg_calib_err), + .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), + .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), + .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), + .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), + .dbg_calib_rden_dly (dbg_calib_rden_dly), + .dbg_calib_gate_dly (dbg_calib_gate_dly) + ); + + ddr2_usr_top # + ( + .BANK_WIDTH (BANK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_BITS (CS_BITS), + .DQ_WIDTH (DQ_WIDTH), + .DQ_PER_DQS (DQ_PER_DQS), + .DQS_WIDTH (DQS_WIDTH), + .APPDATA_WIDTH (APPDATA_WIDTH), + .ECC_ENABLE (ECC_ENABLE), + .ROW_WIDTH (ROW_WIDTH) + ) + u_usr_top + ( + .clk0 (clk0), + .clk90 (clk90), + .rst0 (rst0), + .rd_data_in_rise (rd_data_rise), + .rd_data_in_fall (rd_data_fall), + .phy_calib_rden (phy_calib_rden), + .phy_calib_rden_sel(phy_calib_rden_sel), + .rd_data_valid (rd_data_valid), + .rd_ecc_error (rd_ecc_error), + .rd_data_fifo_out (rd_data_fifo_out), + .app_af_cmd (app_af_cmd), + .app_af_addr (app_af_addr), + .app_af_wren (app_af_wren), + .ctrl_af_rden (ctrl_af_rden), + .af_cmd (af_cmd), + .af_addr (af_addr), + .af_empty (af_empty), + .app_af_afull (app_af_afull), + .app_wdf_wren (app_wdf_wren), + .app_wdf_data (app_wdf_data), + .app_wdf_mask_data (app_wdf_mask_data), + .wdf_rden (wdf_rden), + .app_wdf_afull (app_wdf_afull), + .wdf_data (wdf_data), + .wdf_mask_data (wdf_mask_data) + ); + + + ddr2_ctrl # + ( + .BANK_WIDTH (BANK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_BITS (CS_BITS), + .CS_NUM (CS_NUM), + .ROW_WIDTH (ROW_WIDTH), + .ADDITIVE_LAT (ADDITIVE_LAT), + .BURST_LEN (BURST_LEN), + .CAS_LAT (CAS_LAT), + .ECC_ENABLE (ECC_ENABLE), + .REG_ENABLE (REG_ENABLE), + .MULTI_BANK_EN (MULTI_BANK_EN), + .TWO_T_TIME_EN (TWO_T_TIME_EN), + .TREFI_NS (TREFI_NS), + .TRAS (TRAS), + .TRCD (TRCD), + .TRFC (TRFC), + .TRP (TRP), + .TRTP (TRTP), + .TWR (TWR), + .TWTR (TWTR), + .CLK_PERIOD (CLK_PERIOD), + .DDR_TYPE (DDR_TYPE) + ) + u_ctrl + ( + .clk (clk0), + .rst (rst0), + .af_cmd (af_cmd), + .af_addr (af_addr), + .af_empty (af_empty), + .phy_init_done (phy_init_done), + .ctrl_ref_flag (ctrl_ref_flag), + .ctrl_af_rden (ctrl_af_rden), + .ctrl_wren (ctrl_wren), + .ctrl_rden (ctrl_rden), + .ctrl_addr (ctrl_addr), + .ctrl_ba (ctrl_ba), + .ctrl_ras_n (ctrl_ras_n), + .ctrl_cas_n (ctrl_cas_n), + .ctrl_we_n (ctrl_we_n), + .ctrl_cs_n (ctrl_cs_n) + ); + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_infrastructure.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_infrastructure.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_infrastructure.v (revision 3) @@ -0,0 +1,150 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_infrastructure.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// Clock distribution and reset synchronization +//Reference: +//Revision History: +// Rev 1.1 - Port name changed from dcm_lock to locked. PK. 10/14/08 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_infrastructure # + ( + parameter RST_ACT_LOW = 1 + ) + ( + input clk0, + input clk90, + input clk200, + input clkdiv0, + input locked, + input sys_rst_n, + input idelay_ctrl_rdy, + output rst0, + output rst90, + output rst200, + output rstdiv0 + ); + + // # of clock cycles to delay deassertion of reset. Needs to be a fairly + // high number not so much for metastability protection, but to give time + // for reset (i.e. stable clock cycles) to propagate through all state + // machines and to all control signals (i.e. not all control signals have + // resets, instead they rely on base state logic being reset, and the effect + // of that reset propagating through the logic). Need this because we may not + // be getting stable clock cycles while reset asserted (i.e. since reset + // depends on DCM lock status) + localparam RST_SYNC_NUM = 25; + + reg [RST_SYNC_NUM-1:0] rst0_sync_r /* synthesis syn_maxfan = 10 */; + reg [RST_SYNC_NUM-1:0] rst200_sync_r /* synthesis syn_maxfan = 10 */; + reg [RST_SYNC_NUM-1:0] rst90_sync_r /* synthesis syn_maxfan = 10 */; + reg [(RST_SYNC_NUM/2)-1:0] rstdiv0_sync_r /* synthesis syn_maxfan = 10 */; + wire rst_tmp; + wire sys_clk_ibufg; + wire sys_rst; + + assign sys_rst = RST_ACT_LOW ? ~sys_rst_n: sys_rst_n; + + //*************************************************************************** + // Reset synchronization + // NOTES: + // 1. shut down the whole operation if the DCM hasn't yet locked (and by + // inference, this means that external SYS_RST_IN has been asserted - + // DCM deasserts LOCKED as soon as SYS_RST_IN asserted) + // 2. In the case of all resets except rst200, also assert reset if the + // IDELAY master controller is not yet ready + // 3. asynchronously assert reset. This was we can assert reset even if + // there is no clock (needed for things like 3-stating output buffers). + // reset deassertion is synchronous. + //*************************************************************************** + + assign rst_tmp = sys_rst | ~locked | ~idelay_ctrl_rdy; + + // synthesis attribute max_fanout of rst0_sync_r is 10 + always @(posedge clk0 or posedge rst_tmp) + if (rst_tmp) + rst0_sync_r <= {RST_SYNC_NUM{1'b1}}; + else + // logical left shift by one (pads with 0) + rst0_sync_r <= rst0_sync_r << 1; + + // synthesis attribute max_fanout of rstdiv0_sync_r is 10 + always @(posedge clkdiv0 or posedge rst_tmp) + if (rst_tmp) + rstdiv0_sync_r <= {(RST_SYNC_NUM/2){1'b1}}; + else + // logical left shift by one (pads with 0) + rstdiv0_sync_r <= rstdiv0_sync_r << 1; + + // synthesis attribute max_fanout of rst90_sync_r is 10 + always @(posedge clk90 or posedge rst_tmp) + if (rst_tmp) + rst90_sync_r <= {RST_SYNC_NUM{1'b1}}; + else + rst90_sync_r <= rst90_sync_r << 1; + + // make sure CLK200 doesn't depend on IDELAY_CTRL_RDY, else chicken n' egg + // synthesis attribute max_fanout of rst200_sync_r is 10 + always @(posedge clk200 or negedge locked) + if (!locked) + rst200_sync_r <= {RST_SYNC_NUM{1'b1}}; + else + rst200_sync_r <= rst200_sync_r << 1; + + assign rst0 = rst0_sync_r[RST_SYNC_NUM-1]; + assign rst90 = rst90_sync_r[RST_SYNC_NUM-1]; + assign rst200 = rst200_sync_r[RST_SYNC_NUM-1]; + assign rstdiv0 = rstdiv0_sync_r[(RST_SYNC_NUM/2)-1]; + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_wr.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_wr.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_wr.v (revision 3) @@ -0,0 +1,334 @@ +//***************************************************************************** +// 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 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_usr_wr.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Mon Aug 28 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR/DDR2 +//Purpose: +// This module instantiates the modules containing internal FIFOs +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_usr_wr # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter COL_WIDTH = 10, + parameter CS_BITS = 0, + parameter DQ_WIDTH = 72, + parameter APPDATA_WIDTH = 144, + parameter ECC_ENABLE = 0, + parameter ROW_WIDTH = 14 + ) + ( + input clk0, + input clk90, + input rst0, + // Write data FIFO interface + input app_wdf_wren, + input [APPDATA_WIDTH-1:0] app_wdf_data, + input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, + input wdf_rden, + output app_wdf_afull, + output [(2*DQ_WIDTH)-1:0] wdf_data, + output [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data + ); + + // determine number of FIFO72's to use based on data width + // round up to next integer value when determining WDF_FIFO_NUM + localparam WDF_FIFO_NUM = (ECC_ENABLE) ? (APPDATA_WIDTH+63)/64 : + ((2*DQ_WIDTH)+63)/64; + // MASK_WIDTH = number of bytes in data bus + localparam MASK_WIDTH = DQ_WIDTH/8; + + wire [WDF_FIFO_NUM-1:0] i_wdf_afull; + wire [DQ_WIDTH-1:0] i_wdf_data_fall_in; + wire [DQ_WIDTH-1:0] i_wdf_data_fall_out; + wire [(64*WDF_FIFO_NUM)-1:0] i_wdf_data_in; + wire [(64*WDF_FIFO_NUM)-1:0] i_wdf_data_out; + wire [DQ_WIDTH-1:0] i_wdf_data_rise_in; + wire [DQ_WIDTH-1:0] i_wdf_data_rise_out; + wire [MASK_WIDTH-1:0] i_wdf_mask_data_fall_in; + wire [MASK_WIDTH-1:0] i_wdf_mask_data_fall_out; + wire [(8*WDF_FIFO_NUM)-1:0] i_wdf_mask_data_in; + wire [(8*WDF_FIFO_NUM)-1:0] i_wdf_mask_data_out; + wire [MASK_WIDTH-1:0] i_wdf_mask_data_rise_in; + wire [MASK_WIDTH-1:0] i_wdf_mask_data_rise_out; + reg rst_r; + + // ECC signals + wire [(2*DQ_WIDTH)-1:0] i_wdf_data_out_ecc; + wire [((2*DQ_WIDTH)/8)-1:0] i_wdf_mask_data_out_ecc; + wire [63:0] i_wdf_mask_data_out_ecc_wire; + wire [((2*DQ_WIDTH)/8)-1:0] mask_data_in_ecc; + wire [63:0] mask_data_in_ecc_wire; + + //*************************************************************************** + + assign app_wdf_afull = i_wdf_afull[0]; + + always @(posedge clk0 ) + rst_r <= rst0; + + genvar wdf_di_i; + genvar wdf_do_i; + genvar mask_i; + genvar wdf_i; + generate + if(ECC_ENABLE) begin // ECC code + + assign wdf_data = i_wdf_data_out_ecc; + + // the byte 9 dm is always held to 0 + assign wdf_mask_data = i_wdf_mask_data_out_ecc; + + + + // generate for write data fifo . + for (wdf_i = 0; wdf_i < WDF_FIFO_NUM; wdf_i = wdf_i + 1) begin: gen_wdf + + FIFO36_72 # + ( + .ALMOST_EMPTY_OFFSET (9'h007), + .ALMOST_FULL_OFFSET (9'h00F), + .DO_REG (1), // extra CC output delay + .EN_ECC_WRITE ("TRUE"), + .EN_ECC_READ ("FALSE"), + .EN_SYN ("FALSE"), + .FIRST_WORD_FALL_THROUGH ("FALSE") + ) + u_wdf_ecc + ( + .ALMOSTEMPTY (), + .ALMOSTFULL (i_wdf_afull[wdf_i]), + .DBITERR (), + .DO (i_wdf_data_out_ecc[((64*(wdf_i+1))+(wdf_i *8))-1: + (64*wdf_i)+(wdf_i *8)]), + .DOP (i_wdf_data_out_ecc[(72*(wdf_i+1))-1: + (64*(wdf_i+1))+ (8*wdf_i) ]), + .ECCPARITY (), + .EMPTY (), + .FULL (), + .RDCOUNT (), + .RDERR (), + .SBITERR (), + .WRCOUNT (), + .WRERR (), + .DI (app_wdf_data[(64*(wdf_i+1))-1: + (64*wdf_i)]), + .DIP (), + .RDCLK (clk90), + .RDEN (wdf_rden), + .RST (rst_r), // or can use rst0 + .WRCLK (clk0), + .WREN (app_wdf_wren) + ); + end + + // remapping the mask data. The mask data from user i/f does not have + // the mask for the ECC byte. Assigning 0 to the ECC mask byte. + for (mask_i = 0; mask_i < (DQ_WIDTH)/36; + mask_i = mask_i +1) begin: gen_mask + assign mask_data_in_ecc[((8*(mask_i+1))+ mask_i)-1:((8*mask_i)+mask_i)] + = app_wdf_mask_data[(8*(mask_i+1))-1:8*(mask_i)] ; + assign mask_data_in_ecc[((8*(mask_i+1))+mask_i)] = 1'd0; + end + + // assign ecc bits to temp variables to avoid + // sim warnings. Not all the 64 bits of the fifo + // are used in ECC mode. + assign mask_data_in_ecc_wire[((2*DQ_WIDTH)/8)-1:0] = mask_data_in_ecc; + assign mask_data_in_ecc_wire[63:((2*DQ_WIDTH)/8)] = + {(64-((2*DQ_WIDTH)/8)){1'b0}}; + assign i_wdf_mask_data_out_ecc = + i_wdf_mask_data_out_ecc_wire[((2*DQ_WIDTH)/8)-1:0]; + + + FIFO36_72 # + ( + .ALMOST_EMPTY_OFFSET (9'h007), + .ALMOST_FULL_OFFSET (9'h00F), + .DO_REG (1), // extra CC output delay + .EN_ECC_WRITE ("TRUE"), + .EN_ECC_READ ("FALSE"), + .EN_SYN ("FALSE"), + .FIRST_WORD_FALL_THROUGH ("FALSE") + ) + u_wdf_ecc_mask + ( + .ALMOSTEMPTY (), + .ALMOSTFULL (), + .DBITERR (), + .DO (i_wdf_mask_data_out_ecc_wire), + .DOP (), + .ECCPARITY (), + .EMPTY (), + .FULL (), + .RDCOUNT (), + .RDERR (), + .SBITERR (), + .WRCOUNT (), + .WRERR (), + .DI (mask_data_in_ecc_wire), + .DIP (), + .RDCLK (clk90), + .RDEN (wdf_rden), + .RST (rst_r), // or can use rst0 + .WRCLK (clk0), + .WREN (app_wdf_wren) + ); + end else begin + + //*********************************************************************** + + // Define intermediate buses: + assign i_wdf_data_rise_in + = app_wdf_data[DQ_WIDTH-1:0]; + assign i_wdf_data_fall_in + = app_wdf_data[(2*DQ_WIDTH)-1:DQ_WIDTH]; + assign i_wdf_mask_data_rise_in + = app_wdf_mask_data[MASK_WIDTH-1:0]; + assign i_wdf_mask_data_fall_in + = app_wdf_mask_data[(2*MASK_WIDTH)-1:MASK_WIDTH]; + + //*********************************************************************** + // Write data FIFO Input: + // Arrange DQ's so that the rise data and fall data are interleaved. + // the data arrives at the input of the wdf fifo as {fall,rise}. + // It is remapped as: + // {...fall[15:8],rise[15:8],fall[7:0],rise[7:0]} + // This is done to avoid having separate fifo's for rise and fall data + // and to keep rise/fall data for the same DQ's on same FIFO + // Data masks are interleaved in a similar manner + // NOTE: Initialization data from PHY_INIT module does not need to be + // interleaved - it's already in the correct format - and the same + // initialization pattern from PHY_INIT is sent to all write FIFOs + //*********************************************************************** + + for (wdf_di_i = 0; wdf_di_i < MASK_WIDTH; + wdf_di_i = wdf_di_i + 1) begin: gen_wdf_data_in + assign i_wdf_data_in[(16*wdf_di_i)+15:(16*wdf_di_i)] + = {i_wdf_data_fall_in[(8*wdf_di_i)+7:(8*wdf_di_i)], + i_wdf_data_rise_in[(8*wdf_di_i)+7:(8*wdf_di_i)]}; + assign i_wdf_mask_data_in[(2*wdf_di_i)+1:(2*wdf_di_i)] + = {i_wdf_mask_data_fall_in[wdf_di_i], + i_wdf_mask_data_rise_in[wdf_di_i]}; + end + + //*********************************************************************** + // Write data FIFO Output: + // FIFO DQ and mask outputs must be untangled and put in the standard + // format of {fall,rise}. Same goes for mask output + //*********************************************************************** + + for (wdf_do_i = 0; wdf_do_i < MASK_WIDTH; + wdf_do_i = wdf_do_i + 1) begin: gen_wdf_data_out + assign i_wdf_data_rise_out[(8*wdf_do_i)+7:(8*wdf_do_i)] + = i_wdf_data_out[(16*wdf_do_i)+7:(16*wdf_do_i)]; + assign i_wdf_data_fall_out[(8*wdf_do_i)+7:(8*wdf_do_i)] + = i_wdf_data_out[(16*wdf_do_i)+15:(16*wdf_do_i)+8]; + assign i_wdf_mask_data_rise_out[wdf_do_i] + = i_wdf_mask_data_out[2*wdf_do_i]; + assign i_wdf_mask_data_fall_out[wdf_do_i] + = i_wdf_mask_data_out[(2*wdf_do_i)+1]; + end + + assign wdf_data = {i_wdf_data_fall_out, + i_wdf_data_rise_out}; + + assign wdf_mask_data = {i_wdf_mask_data_fall_out, + i_wdf_mask_data_rise_out}; + + //*********************************************************************** + + for (wdf_i = 0; wdf_i < WDF_FIFO_NUM; wdf_i = wdf_i + 1) begin: gen_wdf + + FIFO36_72 # + ( + .ALMOST_EMPTY_OFFSET (9'h007), + .ALMOST_FULL_OFFSET (9'h00F), + .DO_REG (1), // extra CC output delay + .EN_ECC_WRITE ("FALSE"), + .EN_ECC_READ ("FALSE"), + .EN_SYN ("FALSE"), + .FIRST_WORD_FALL_THROUGH ("FALSE") + ) + u_wdf + ( + .ALMOSTEMPTY (), + .ALMOSTFULL (i_wdf_afull[wdf_i]), + .DBITERR (), + .DO (i_wdf_data_out[(64*(wdf_i+1))-1:64*wdf_i]), + .DOP (i_wdf_mask_data_out[(8*(wdf_i+1))-1:8*wdf_i]), + .ECCPARITY (), + .EMPTY (), + .FULL (), + .RDCOUNT (), + .RDERR (), + .SBITERR (), + .WRCOUNT (), + .WRERR (), + .DI (i_wdf_data_in[(64*(wdf_i+1))-1:64*wdf_i]), + .DIP (i_wdf_mask_data_in[(8*(wdf_i+1))-1:8*wdf_i]), + .RDCLK (clk90), + .RDEN (wdf_rden), + .RST (rst_r), // or can use rst0 + .WRCLK (clk0), + .WREN (app_wdf_wren) + ); + end + end + endgenerate + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_top.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_top.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_top.v (revision 3) @@ -0,0 +1,395 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_top.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// Top-level for memory physical layer (PHY) interface +//Reference: +//Revision History: +// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 +// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 +// Rev 1.3 - Parameter CS_BITS added. PK. 10/8/08 +// Rev 1.4 - Parameter IODELAY_GRP added. PK. 11/27/08 +//***************************************************************************** + +`timescale 1ns/1ps + +(* X_CORE_INFO = "mig_v3_61_ddr2_sdram_v5, Coregen 12.4" , CORE_GENERATION_INFO = "ddr2_sdram_v5,mig_v3_61,{component_name=ddr2_phy_top, BANK_WIDTH=2, CKE_WIDTH=1, CLK_WIDTH=2, COL_WIDTH=10, CS_NUM=1, CS_WIDTH=1, DM_WIDTH=8, DQ_WIDTH=64, DQ_PER_DQS=8, DQS_WIDTH=8, ODT_WIDTH=1, ROW_WIDTH=13, ADDITIVE_LAT=0, BURST_LEN=4, BURST_TYPE=0, CAS_LAT=3, ECC_ENABLE=0, MULTI_BANK_EN=1, TWO_T_TIME_EN=1, ODT_TYPE=1, REDUCE_DRV=0, REG_ENABLE=0, TREFI_NS=7800, TRAS=40000, TRCD=15000, TRFC=105000, TRP=15000, TRTP=7500, TWR=15000, TWTR=7500, CLK_PERIOD=8000, RST_ACT_LOW=1, INTERFACE_TYPE=DDR2_SDRAM, LANGUAGE=Verilog, SYNTHESIS_TOOL=ISE, NO_OF_CONTROLLERS=1}" *) +module ddr2_phy_top # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter CLK_WIDTH = 1, + parameter CKE_WIDTH = 1, + parameter COL_WIDTH = 10, + parameter CS_BITS = 0, + parameter CS_NUM = 1, + parameter CS_WIDTH = 1, + parameter USE_DM_PORT = 1, + parameter DM_WIDTH = 9, + parameter DQ_WIDTH = 72, + parameter DQ_BITS = 7, + parameter DQ_PER_DQS = 8, + parameter DQS_WIDTH = 9, + parameter DQS_BITS = 4, + parameter HIGH_PERFORMANCE_MODE = "TRUE", + parameter IODELAY_GRP = "IODELAY_MIG", + parameter ODT_WIDTH = 1, + parameter ROW_WIDTH = 14, + parameter ADDITIVE_LAT = 0, + parameter TWO_T_TIME_EN = 0, + parameter BURST_LEN = 4, + parameter BURST_TYPE = 0, + parameter CAS_LAT = 5, + parameter TWR = 15000, + parameter ECC_ENABLE = 0, + parameter ODT_TYPE = 1, + parameter DDR_TYPE = 1, + parameter REDUCE_DRV = 0, + parameter REG_ENABLE = 1, + parameter CLK_PERIOD = 3000, + parameter SIM_ONLY = 0, + parameter DEBUG_EN = 0, + parameter FPGA_SPEED_GRADE = 2 + ) + ( + input clk0, + input clk90, + input clkdiv0, + input rst0, + input rst90, + input rstdiv0, + input ctrl_wren, + input [ROW_WIDTH-1:0] ctrl_addr, + input [BANK_WIDTH-1:0] ctrl_ba, + input ctrl_ras_n, + input ctrl_cas_n, + input ctrl_we_n, + input [CS_NUM-1:0] ctrl_cs_n, + input ctrl_rden, + input ctrl_ref_flag, + input [(2*DQ_WIDTH)-1:0] wdf_data, + input [(2*DQ_WIDTH/8)-1:0] wdf_mask_data, + output wdf_rden, + output phy_init_done, + output [DQS_WIDTH-1:0] phy_calib_rden, + output [DQS_WIDTH-1:0] phy_calib_rden_sel, + output [DQ_WIDTH-1:0] rd_data_rise, + output [DQ_WIDTH-1:0] rd_data_fall, + output [CLK_WIDTH-1:0] ddr_ck, + output [CLK_WIDTH-1:0] ddr_ck_n, + output [ROW_WIDTH-1:0] ddr_addr, + output [BANK_WIDTH-1:0] ddr_ba, + output ddr_ras_n, + output ddr_cas_n, + output ddr_we_n, + output [CS_WIDTH-1:0] ddr_cs_n, + output [CKE_WIDTH-1:0] ddr_cke, + output [ODT_WIDTH-1:0] ddr_odt, + output [DM_WIDTH-1:0] ddr_dm, + inout [DQS_WIDTH-1:0] ddr_dqs, + inout [DQS_WIDTH-1:0] ddr_dqs_n, + inout [DQ_WIDTH-1:0] ddr_dq, + // Debug signals (optional use) + input dbg_idel_up_all, + input dbg_idel_down_all, + input dbg_idel_up_dq, + input dbg_idel_down_dq, + input dbg_idel_up_dqs, + input dbg_idel_down_dqs, + input dbg_idel_up_gate, + input dbg_idel_down_gate, + input [DQ_BITS-1:0] dbg_sel_idel_dq, + input dbg_sel_all_idel_dq, + input [DQS_BITS:0] dbg_sel_idel_dqs, + input dbg_sel_all_idel_dqs, + input [DQS_BITS:0] dbg_sel_idel_gate, + input dbg_sel_all_idel_gate, + output [3:0] dbg_calib_done, + output [3:0] dbg_calib_err, + output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, + output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, + output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, + output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly + ); + + wire [3:0] calib_done; + wire calib_ref_done; + wire calib_ref_req; + wire [3:0] calib_start; + wire dm_ce; + wire [1:0] dq_oe_n; + wire dqs_oe_n; + wire dqs_rst_n; + wire [(DQ_WIDTH/8)-1:0] mask_data_fall; + wire [(DQ_WIDTH/8)-1:0] mask_data_rise; + wire [CS_NUM-1:0] odt; + wire [ROW_WIDTH-1:0] phy_init_addr; + wire [BANK_WIDTH-1:0] phy_init_ba; + wire phy_init_cas_n; + wire [CKE_WIDTH-1:0] phy_init_cke; + wire [CS_NUM-1:0] phy_init_cs_n; + wire phy_init_data_sel; + wire phy_init_ras_n; + wire phy_init_rden; + wire phy_init_we_n; + wire phy_init_wren; + wire [DQ_WIDTH-1:0] wr_data_fall; + wire [DQ_WIDTH-1:0] wr_data_rise; + + //*************************************************************************** + + ddr2_phy_write # + ( + .DQ_WIDTH (DQ_WIDTH), + .CS_NUM (CS_NUM), + .ADDITIVE_LAT (ADDITIVE_LAT), + .CAS_LAT (CAS_LAT), + .ECC_ENABLE (ECC_ENABLE), + .ODT_TYPE (ODT_TYPE), + .REG_ENABLE (REG_ENABLE), + .DDR_TYPE (DDR_TYPE) + ) + u_phy_write + ( + .clk0 (clk0), + .clk90 (clk90), + .rst90 (rst90), + .wdf_data (wdf_data), + .wdf_mask_data (wdf_mask_data), + .ctrl_wren (ctrl_wren), + .phy_init_wren (phy_init_wren), + .phy_init_data_sel (phy_init_data_sel), + .dm_ce (dm_ce), + .dq_oe_n (dq_oe_n), + .dqs_oe_n (dqs_oe_n), + .dqs_rst_n (dqs_rst_n), + .wdf_rden (wdf_rden), + .odt (odt), + .wr_data_rise (wr_data_rise), + .wr_data_fall (wr_data_fall), + .mask_data_rise (mask_data_rise), + .mask_data_fall (mask_data_fall) + ); + + ddr2_phy_io # + ( + .CLK_WIDTH (CLK_WIDTH), + .USE_DM_PORT (USE_DM_PORT), + .DM_WIDTH (DM_WIDTH), + .DQ_WIDTH (DQ_WIDTH), + .DQ_BITS (DQ_BITS), + .DQ_PER_DQS (DQ_PER_DQS), + .DQS_BITS (DQS_BITS), + .DQS_WIDTH (DQS_WIDTH), + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .IODELAY_GRP (IODELAY_GRP), + .ODT_WIDTH (ODT_WIDTH), + .ADDITIVE_LAT (ADDITIVE_LAT), + .CAS_LAT (CAS_LAT), + .REG_ENABLE (REG_ENABLE), + .CLK_PERIOD (CLK_PERIOD), + .DDR_TYPE (DDR_TYPE), + .SIM_ONLY (SIM_ONLY), + .DEBUG_EN (DEBUG_EN), + .FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) + ) + u_phy_io + ( + .clk0 (clk0), + .clk90 (clk90), + .clkdiv0 (clkdiv0), + .rst0 (rst0), + .rst90 (rst90), + .rstdiv0 (rstdiv0), + .dm_ce (dm_ce), + .dq_oe_n (dq_oe_n), + .dqs_oe_n (dqs_oe_n), + .dqs_rst_n (dqs_rst_n), + .calib_start (calib_start), + .ctrl_rden (ctrl_rden), + .phy_init_rden (phy_init_rden), + .calib_ref_done (calib_ref_done), + .calib_done (calib_done), + .calib_ref_req (calib_ref_req), + .calib_rden (phy_calib_rden), + .calib_rden_sel (phy_calib_rden_sel), + .wr_data_rise (wr_data_rise), + .wr_data_fall (wr_data_fall), + .mask_data_rise (mask_data_rise), + .mask_data_fall (mask_data_fall), + .rd_data_rise (rd_data_rise), + .rd_data_fall (rd_data_fall), + .ddr_ck (ddr_ck), + .ddr_ck_n (ddr_ck_n), + .ddr_dm (ddr_dm), + .ddr_dqs (ddr_dqs), + .ddr_dqs_n (ddr_dqs_n), + .ddr_dq (ddr_dq), + .dbg_idel_up_all (dbg_idel_up_all), + .dbg_idel_down_all (dbg_idel_down_all), + .dbg_idel_up_dq (dbg_idel_up_dq), + .dbg_idel_down_dq (dbg_idel_down_dq), + .dbg_idel_up_dqs (dbg_idel_up_dqs), + .dbg_idel_down_dqs (dbg_idel_down_dqs), + .dbg_idel_up_gate (dbg_idel_up_gate), + .dbg_idel_down_gate (dbg_idel_down_gate), + .dbg_sel_idel_dq (dbg_sel_idel_dq), + .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), + .dbg_sel_idel_dqs (dbg_sel_idel_dqs), + .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), + .dbg_sel_idel_gate (dbg_sel_idel_gate), + .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), + .dbg_calib_done (dbg_calib_done), + .dbg_calib_err (dbg_calib_err), + .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), + .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), + .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), + .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), + .dbg_calib_rden_dly (dbg_calib_rden_dly), + .dbg_calib_gate_dly (dbg_calib_gate_dly) + ); + + ddr2_phy_ctl_io # + ( + .BANK_WIDTH (BANK_WIDTH), + .CKE_WIDTH (CKE_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_NUM (CS_NUM), + .CS_WIDTH (CS_WIDTH), + .TWO_T_TIME_EN (TWO_T_TIME_EN), + .ODT_WIDTH (ODT_WIDTH), + .ROW_WIDTH (ROW_WIDTH), + .DDR_TYPE (DDR_TYPE) + ) + u_phy_ctl_io + ( + .clk0 (clk0), + .clk90 (clk90), + .rst0 (rst0), + .rst90 (rst90), + .ctrl_addr (ctrl_addr), + .ctrl_ba (ctrl_ba), + .ctrl_ras_n (ctrl_ras_n), + .ctrl_cas_n (ctrl_cas_n), + .ctrl_we_n (ctrl_we_n), + .ctrl_cs_n (ctrl_cs_n), + .phy_init_addr (phy_init_addr), + .phy_init_ba (phy_init_ba), + .phy_init_ras_n (phy_init_ras_n), + .phy_init_cas_n (phy_init_cas_n), + .phy_init_we_n (phy_init_we_n), + .phy_init_cs_n (phy_init_cs_n), + .phy_init_cke (phy_init_cke), + .phy_init_data_sel (phy_init_data_sel), + .odt (odt), + .ddr_addr (ddr_addr), + .ddr_ba (ddr_ba), + .ddr_ras_n (ddr_ras_n), + .ddr_cas_n (ddr_cas_n), + .ddr_we_n (ddr_we_n), + .ddr_cke (ddr_cke), + .ddr_cs_n (ddr_cs_n), + .ddr_odt (ddr_odt) + ); + + ddr2_phy_init # + ( + .BANK_WIDTH (BANK_WIDTH), + .CKE_WIDTH (CKE_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_BITS (CS_BITS), + .CS_NUM (CS_NUM), + .DQ_WIDTH (DQ_WIDTH), + .ODT_WIDTH (ODT_WIDTH), + .ROW_WIDTH (ROW_WIDTH), + .ADDITIVE_LAT (ADDITIVE_LAT), + .BURST_LEN (BURST_LEN), + .BURST_TYPE (BURST_TYPE), + .TWO_T_TIME_EN(TWO_T_TIME_EN), + .CAS_LAT (CAS_LAT), + .ODT_TYPE (ODT_TYPE), + .REDUCE_DRV (REDUCE_DRV), + .REG_ENABLE (REG_ENABLE), + .TWR (TWR), + .CLK_PERIOD (CLK_PERIOD), + .DDR_TYPE (DDR_TYPE), + .SIM_ONLY (SIM_ONLY) + ) + u_phy_init + ( + .clk0 (clk0), + .clkdiv0 (clkdiv0), + .rst0 (rst0), + .rstdiv0 (rstdiv0), + .calib_done (calib_done), + .ctrl_ref_flag (ctrl_ref_flag), + .calib_ref_req (calib_ref_req), + .calib_start (calib_start), + .calib_ref_done (calib_ref_done), + .phy_init_wren (phy_init_wren), + .phy_init_rden (phy_init_rden), + .phy_init_addr (phy_init_addr), + .phy_init_ba (phy_init_ba), + .phy_init_ras_n (phy_init_ras_n), + .phy_init_cas_n (phy_init_cas_n), + .phy_init_we_n (phy_init_we_n), + .phy_init_cs_n (phy_init_cs_n), + .phy_init_cke (phy_init_cke), + .phy_init_done (phy_init_done), + .phy_init_data_sel (phy_init_data_sel) + ); + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_init.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_init.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_init.v (revision 3) @@ -0,0 +1,1219 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_init.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Thu Aug 24 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +//Reference: +// This module is the intialization control logic of the memory interface. +// All commands are issued from here acoording to the burst, CAS Latency and +// the user commands. +//Revision History: +// Rev 1.1 - Localparam WR_RECOVERY added and mapped to +// load mode register. PK. 14/7/08 +// Rev 1.2 - To issue an Auto Refresh command to each chip during various +// calibration stages logic modified. PK. 08/10/08 +// Rev 1.3 - Retain current data pattern for stage 4 calibration, and create +// new pattern for stage 4. RC. 09/21/09. +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_phy_init # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter CKE_WIDTH = 1, + parameter COL_WIDTH = 10, + parameter CS_BITS = 0, + parameter CS_NUM = 1, + parameter DQ_WIDTH = 72, + parameter ODT_WIDTH = 1, + parameter ROW_WIDTH = 14, + parameter ADDITIVE_LAT = 0, + parameter BURST_LEN = 4, + parameter TWO_T_TIME_EN = 0, + parameter BURST_TYPE = 0, + parameter CAS_LAT = 5, + parameter ODT_TYPE = 1, + parameter REDUCE_DRV = 0, + parameter REG_ENABLE = 1, + parameter TWR = 15000, + parameter CLK_PERIOD = 3000, + parameter DDR_TYPE = 1, + parameter SIM_ONLY = 0 + ) + ( + input clk0, + input clkdiv0, + input rst0, + input rstdiv0, + input [3:0] calib_done, + input ctrl_ref_flag, + input calib_ref_req, + output reg [3:0] calib_start, + output reg calib_ref_done, + output reg phy_init_wren, + output reg phy_init_rden, + output [ROW_WIDTH-1:0] phy_init_addr, + output [BANK_WIDTH-1:0] phy_init_ba, + output phy_init_ras_n, + output phy_init_cas_n, + output phy_init_we_n, + output [CS_NUM-1:0] phy_init_cs_n, + output [CKE_WIDTH-1:0] phy_init_cke, + output reg phy_init_done, + output phy_init_data_sel + ); + + // time to wait between consecutive commands in PHY_INIT - this is a + // generic number, and must be large enough to account for worst case + // timing parameter (tRFC - refresh-to-active) across all memory speed + // grades and operating frequencies. Expressed in CLKDIV clock cycles. + localparam CNTNEXT_CMD = 7'b1111111; + // time to wait between read and read or precharge for stage 3 & 4 + // the larger CNTNEXT_CMD can also be used, use smaller number to + // speed up calibration - avoid tRAS violation, and speeds up simulation + localparam CNTNEXT_RD = 4'b1111; + + // Write recovery (WR) time - is defined by + // tWR (in nanoseconds) by tCK (in nanoseconds) and rounding up a + // noninteger value to the next integer + localparam integer WR_RECOVERY = ((TWR + CLK_PERIOD) - 1)/CLK_PERIOD; + localparam CS_BITS_FIX = (CS_BITS == 0) ? 1 : CS_BITS; + + localparam INIT_CAL1_READ = 5'h00; + localparam INIT_CAL2_READ = 5'h01; + localparam INIT_CAL3_READ = 5'h02; + localparam INIT_CAL4_READ = 5'h03; + localparam INIT_CAL1_WRITE = 5'h04; + localparam INIT_CAL2_WRITE = 5'h05; + localparam INIT_CAL3_WRITE = 5'h06; + localparam INIT_DUMMY_ACTIVE_WAIT = 5'h07; + localparam INIT_PRECHARGE = 5'h08; + localparam INIT_LOAD_MODE = 5'h09; + localparam INIT_AUTO_REFRESH = 5'h0A; + localparam INIT_IDLE = 5'h0B; + localparam INIT_CNT_200 = 5'h0C; + localparam INIT_CNT_200_WAIT = 5'h0D; + localparam INIT_PRECHARGE_WAIT = 5'h0E; + localparam INIT_MODE_REGISTER_WAIT = 5'h0F; + localparam INIT_AUTO_REFRESH_WAIT = 5'h10; + localparam INIT_DEEP_MEMORY_ST = 5'h11; + localparam INIT_DUMMY_ACTIVE = 5'h12; + localparam INIT_CAL1_WRITE_READ = 5'h13; + localparam INIT_CAL1_READ_WAIT = 5'h14; + localparam INIT_CAL2_WRITE_READ = 5'h15; + localparam INIT_CAL2_READ_WAIT = 5'h16; + localparam INIT_CAL3_WRITE_READ = 5'h17; + localparam INIT_CAL3_READ_WAIT = 5'h18; + localparam INIT_CAL4_READ_WAIT = 5'h19; + localparam INIT_CALIB_REF = 5'h1A; + localparam INIT_ZQCL = 5'h1B; + localparam INIT_WAIT_DLLK_ZQINIT = 5'h1C; + localparam INIT_CAL4_WRITE = 5'h1D; // MIG 3.3: New state + localparam INIT_CAL4_WRITE_READ = 5'h1E; // MIG 3.3: New state + + localparam INIT_CNTR_INIT = 4'h0; + localparam INIT_CNTR_PRECH_1 = 4'h1; + localparam INIT_CNTR_EMR2_INIT = 4'h2; + localparam INIT_CNTR_EMR3_INIT = 4'h3; + localparam INIT_CNTR_EMR_EN_DLL = 4'h4; + localparam INIT_CNTR_MR_RST_DLL = 4'h5; + localparam INIT_CNTR_CNT_200_WAIT = 4'h6; + localparam INIT_CNTR_PRECH_2 = 4'h7; + localparam INIT_CNTR_AR_1 = 4'h8; + localparam INIT_CNTR_AR_2 = 4'h9; + localparam INIT_CNTR_MR_ACT_DLL = 4'hA; + localparam INIT_CNTR_EMR_DEF_OCD = 4'hB; + localparam INIT_CNTR_EMR_EXIT_OCD = 4'hC; + localparam INIT_CNTR_DEEP_MEM = 4'hD; + // MIG 3.3: Remove extra precharge occurring at end of calibration +// localparam INIT_CNTR_PRECH_3 = 4'hE; +// localparam INIT_CNTR_DONE = 4'hF; + localparam INIT_CNTR_DONE = 4'hE; + + localparam DDR1 = 0; + localparam DDR2 = 1; + localparam DDR3 = 2; + + reg [CS_BITS_FIX :0] auto_cnt_r; + reg [1:0] burst_addr_r; + reg [1:0] burst_cnt_r; + wire [1:0] burst_val; + wire cal_read; + wire cal_write; + wire cal_write_read; + reg cal1_started_r; + reg cal2_started_r; + reg cal4_started_r; + reg [3:0] calib_done_r; + reg calib_ref_req_posedge; + reg calib_ref_req_r; + reg [15:0] calib_start_shift0_r; + reg [15:0] calib_start_shift1_r; + reg [15:0] calib_start_shift2_r; + reg [15:0] calib_start_shift3_r; + reg [1:0] chip_cnt_r; + reg [4:0] cke_200us_cnt_r; + reg cke_200us_cnt_en_r; + reg [7:0] cnt_200_cycle_r; + reg cnt_200_cycle_done_r; + reg [6:0] cnt_cmd_r; + reg cnt_cmd_ok_r; + reg [3:0] cnt_rd_r; + reg cnt_rd_ok_r; + reg ctrl_ref_flag_r; + reg done_200us_r; + reg [ROW_WIDTH-1:0] ddr_addr_r; + reg [ROW_WIDTH-1:0] ddr_addr_r1; + reg [BANK_WIDTH-1:0] ddr_ba_r; + reg [BANK_WIDTH-1:0] ddr_ba_r1; + reg ddr_cas_n_r; + reg ddr_cas_n_r1; + reg [CKE_WIDTH-1:0] ddr_cke_r; + reg [CS_NUM-1:0] ddr_cs_n_r; + reg [CS_NUM-1:0] ddr_cs_n_r1; + reg [CS_NUM-1:0] ddr_cs_disable_r; + reg ddr_ras_n_r; + reg ddr_ras_n_r1; + reg ddr_we_n_r; + reg ddr_we_n_r1; + wire [15:0] ext_mode_reg; + reg [3:0] init_cnt_r; + reg init_done_r; + reg [4:0] init_next_state; + reg [4:0] init_state_r; + reg [4:0] init_state_r1; + reg [4:0] init_state_r1_2t; + reg [4:0] init_state_r2; + wire [15:0] load_mode_reg; + wire [15:0] load_mode_reg0; + wire [15:0] load_mode_reg1; + wire [15:0] load_mode_reg2; + wire [15:0] load_mode_reg3; + reg phy_init_done_r; + reg phy_init_done_r1; + reg phy_init_done_r2; + reg phy_init_done_r3; + reg refresh_req; + wire [3:0] start_cal; + + //*************************************************************************** + + //***************************************************************** + // DDR1 and DDR2 Load mode register + // Mode Register (MR): + // [15:14] - unused - 00 + // [13] - reserved - 0 + // [12] - Power-down mode - 0 (normal) + // [11:9] - write recovery - for Auto Precharge (tWR/tCK) + // [8] - DLL reset - 0 or 1 + // [7] - Test Mode - 0 (normal) + // [6:4] - CAS latency - CAS_LAT + // [3] - Burst Type - BURST_TYPE + // [2:0] - Burst Length - BURST_LEN + //***************************************************************** + + generate + if (DDR_TYPE == DDR2) begin: gen_load_mode_reg_ddr2 + assign load_mode_reg[2:0] = (BURST_LEN == 8) ? 3'b011 : + ((BURST_LEN == 4) ? 3'b010 : 3'b111); + assign load_mode_reg[3] = BURST_TYPE; + assign load_mode_reg[6:4] = (CAS_LAT == 3) ? 3'b011 : + ((CAS_LAT == 4) ? 3'b100 : + ((CAS_LAT == 5) ? 3'b101 : 3'b111)); + assign load_mode_reg[7] = 1'b0; + assign load_mode_reg[8] = 1'b0; // init value only (DLL not reset) + assign load_mode_reg[11:9] = (WR_RECOVERY == 6) ? 3'b101 : + ((WR_RECOVERY == 5) ? 3'b100 : + ((WR_RECOVERY == 4) ? 3'b011 : + ((WR_RECOVERY == 3) ? 3'b010 : + 3'b001))); + assign load_mode_reg[15:12] = 4'b000; + end else if (DDR_TYPE == DDR1)begin: gen_load_mode_reg_ddr1 + assign load_mode_reg[2:0] = (BURST_LEN == 8) ? 3'b011 : + ((BURST_LEN == 4) ? 3'b010 : + ((BURST_LEN == 2) ? 3'b001 : 3'b111)); + assign load_mode_reg[3] = BURST_TYPE; + assign load_mode_reg[6:4] = (CAS_LAT == 2) ? 3'b010 : + ((CAS_LAT == 3) ? 3'b011 : + ((CAS_LAT == 25) ? 3'b110 : 3'b111)); + assign load_mode_reg[12:7] = 6'b000000; // init value only + assign load_mode_reg[15:13] = 3'b000; + end + endgenerate + + //***************************************************************** + // DDR1 and DDR2 ext mode register + // Extended Mode Register (MR): + // [15:14] - unused - 00 + // [13] - reserved - 0 + // [12] - output enable - 0 (enabled) + // [11] - RDQS enable - 0 (disabled) + // [10] - DQS# enable - 0 (enabled) + // [9:7] - OCD Program - 111 or 000 (first 111, then 000 during init) + // [6] - RTT[1] - RTT[1:0] = 0(no ODT), 1(75), 2(150), 3(50) + // [5:3] - Additive CAS - ADDITIVE_CAS + // [2] - RTT[0] + // [1] - Output drive - REDUCE_DRV (= 0(full), = 1 (reduced) + // [0] - DLL enable - 0 (normal) + //***************************************************************** + + generate + if (DDR_TYPE == DDR2) begin: gen_ext_mode_reg_ddr2 + assign ext_mode_reg[0] = 1'b0; + assign ext_mode_reg[1] = REDUCE_DRV; + assign ext_mode_reg[2] = ((ODT_TYPE == 1) || (ODT_TYPE == 3)) ? + 1'b1 : 1'b0; + assign ext_mode_reg[5:3] = (ADDITIVE_LAT == 0) ? 3'b000 : + ((ADDITIVE_LAT == 1) ? 3'b001 : + ((ADDITIVE_LAT == 2) ? 3'b010 : + ((ADDITIVE_LAT == 3) ? 3'b011 : + ((ADDITIVE_LAT == 4) ? 3'b100 : + 3'b111)))); + assign ext_mode_reg[6] = ((ODT_TYPE == 2) || (ODT_TYPE == 3)) ? + 1'b1 : 1'b0; + assign ext_mode_reg[9:7] = 3'b000; + assign ext_mode_reg[10] = 1'b0; + assign ext_mode_reg[15:10] = 6'b000000; + end else if (DDR_TYPE == DDR1) begin: gen_ext_mode_reg_ddr1 + assign ext_mode_reg[0] = 1'b0; + assign ext_mode_reg[1] = REDUCE_DRV; + assign ext_mode_reg[12:2] = 11'b00000000000; + assign ext_mode_reg[15:13] = 3'b000; + end + endgenerate + + //***************************************************************** + // DDR3 Load mode reg0 + // Mode Register (MR0): + // [15:13] - unused - 000 + // [12] - Precharge Power-down DLL usage - 0 (DLL frozen, slow-exit), + // 1 (DLL maintained) + // [11:9] - write recovery for Auto Precharge (tWR/tCK = 6) + // [8] - DLL reset - 0 or 1 + // [7] - Test Mode - 0 (normal) + // [6:4],[2] - CAS latency - CAS_LAT + // [3] - Burst Type - BURST_TYPE + // [1:0] - Burst Length - BURST_LEN + //***************************************************************** + + generate + if (DDR_TYPE == DDR3) begin: gen_load_mode_reg0_ddr3 + assign load_mode_reg0[1:0] = (BURST_LEN == 8) ? 2'b00 : + ((BURST_LEN == 4) ? 2'b10 : 2'b11); + // Part of CAS latency. This bit is '0' for all CAS latencies + assign load_mode_reg0[2] = 1'b0; + assign load_mode_reg0[3] = BURST_TYPE; + assign load_mode_reg0[6:4] = (CAS_LAT == 5) ? 3'b001 : + (CAS_LAT == 6) ? 3'b010 : 3'b111; + assign load_mode_reg0[7] = 1'b0; + // init value only (DLL reset) + assign load_mode_reg0[8] = 1'b1; + assign load_mode_reg0[11:9] = 3'b010; + // Precharge Power-Down DLL 'slow-exit' + assign load_mode_reg0[12] = 1'b0; + assign load_mode_reg0[15:13] = 3'b000; + end + endgenerate + + //***************************************************************** + // DDR3 Load mode reg1 + // Mode Register (MR1): + // [15:13] - unused - 00 + // [12] - output enable - 0 (enabled for DQ, DQS, DQS#) + // [11] - TDQS enable - 0 (TDQS disabled and DM enabled) + // [10] - reserved - 0 (must be '0') + // [9] - RTT[2] - 0 + // [8] - reserved - 0 (must be '0') + // [7] - write leveling - 0 (disabled), 1 (enabled) + // [6] - RTT[1] - RTT[1:0] = 0(no ODT), 1(75), 2(150), 3(50) + // [5] - Output driver impedance[1] - 0 (RZQ/6 and RZQ/7) + // [4:3] - Additive CAS - ADDITIVE_CAS + // [2] - RTT[0] + // [1] - Output driver impedance[0] - 0(RZQ/6), or 1 (RZQ/7) + // [0] - DLL enable - 0 (normal) + //***************************************************************** + + generate + if (DDR_TYPE == DDR3) begin: gen_ext_mode_reg1_ddr3 + // DLL enabled during Imitialization + assign load_mode_reg1[0] = 1'b0; + // RZQ/6 + assign load_mode_reg1[1] = REDUCE_DRV; + assign load_mode_reg1[2] = ((ODT_TYPE == 1) || (ODT_TYPE == 3)) ? + 1'b1 : 1'b0; + assign load_mode_reg1[4:3] = (ADDITIVE_LAT == 0) ? 2'b00 : + ((ADDITIVE_LAT == 1) ? 2'b01 : + ((ADDITIVE_LAT == 2) ? 2'b10 : + 3'b111)); + // RZQ/6 + assign load_mode_reg1[5] = 1'b0; + assign load_mode_reg1[6] = ((ODT_TYPE == 2) || (ODT_TYPE == 3)) ? + 1'b1 : 1'b0; + // Make zero WRITE_LEVEL + assign load_mode_reg1[7] = 0; + assign load_mode_reg1[8] = 1'b0; + assign load_mode_reg1[9] = 1'b0; + assign load_mode_reg1[10] = 1'b0; + assign load_mode_reg1[15:11] = 5'b00000; + end + endgenerate + + //***************************************************************** + // DDR3 Load mode reg2 + // Mode Register (MR2): + // [15:11] - unused - 00 + // [10:9] - RTT_WR - 00 (Dynamic ODT off) + // [8] - reserved - 0 (must be '0') + // [7] - self-refresh temperature range - + // 0 (normal), 1 (extended) + // [6] - Auto Self-Refresh - 0 (manual), 1(auto) + // [5:3] - CAS Write Latency (CWL) - + // 000 (5 for 400 MHz device), + // 001 (6 for 400 MHz to 533 MHz devices), + // 010 (7 for 533 MHz to 667 MHz devices), + // 011 (8 for 667 MHz to 800 MHz) + // [2:0] - Partial Array Self-Refresh (Optional) - + // 000 (full array) + //***************************************************************** + + generate + if (DDR_TYPE == DDR3) begin: gen_ext_mode_reg2_ddr3 + assign load_mode_reg2[2:0] = 3'b000; + assign load_mode_reg2[5:3] = (CAS_LAT == 5) ? 3'b000 : + (CAS_LAT == 6) ? 3'b001 : 3'b111; + assign load_mode_reg2[6] = 1'b0; // Manual Self-Refresh + assign load_mode_reg2[7] = 1'b0; + assign load_mode_reg2[8] = 1'b0; + assign load_mode_reg2[10:9] = 2'b00; + assign load_mode_reg2[15:11] = 5'b00000; + end + endgenerate + + //***************************************************************** + // DDR3 Load mode reg3 + // Mode Register (MR3): + // [15:3] - unused - All zeros + // [2] - MPR Operation - 0(normal operation), 1(data flow from MPR) + // [1:0] - MPR location - 00 (Predefined pattern) + //***************************************************************** + + generate + if (DDR_TYPE == DDR3)begin: gen_ext_mode_reg3_ddr3 + assign load_mode_reg3[1:0] = 2'b00; + assign load_mode_reg3[2] = 1'b0; + assign load_mode_reg3[15:3] = 13'b0000000000000; + end + endgenerate + + //*************************************************************************** + // Logic for calibration start, and for auto-refresh during cal request + // CALIB_REF_REQ is used by calibration logic to request auto-refresh + // durign calibration (used to avoid tRAS violation is certain calibration + // stages take a long time). Once the auto-refresh is complete and cal can + // be resumed, CALIB_REF_DONE is asserted by PHY_INIT. + //*************************************************************************** + + // generate pulse for each of calibration start controls + assign start_cal[0] = ((init_state_r1 == INIT_CAL1_READ) && + (init_state_r2 != INIT_CAL1_READ)); + assign start_cal[1] = ((init_state_r1 == INIT_CAL2_READ) && + (init_state_r2 != INIT_CAL2_READ)); + assign start_cal[2] = ((init_state_r1 == INIT_CAL3_READ) && + (init_state_r2 == INIT_CAL3_WRITE_READ)); + assign start_cal[3] = ((init_state_r1 == INIT_CAL4_READ) && + (init_state_r2 != INIT_CAL4_READ)); + // MIG 3.3: Change to accomodate FSM changes related to stage 4 calibration +// (init_state_r2 == INIT_CAL4_WRITE_READ)); + + // Generate positive-edge triggered, latched signal to force initialization + // to pause calibration, and to issue auto-refresh. Clear flag as soon as + // refresh initiated + always @(posedge clkdiv0) + if (rstdiv0) begin + calib_ref_req_r <= 1'b0; + calib_ref_req_posedge <= 1'b0; + refresh_req <= 1'b0; + end else begin + calib_ref_req_r <= calib_ref_req; + calib_ref_req_posedge <= calib_ref_req & ~calib_ref_req_r; + if (init_state_r1 == INIT_AUTO_REFRESH) + refresh_req <= 1'b0; + else if (calib_ref_req_posedge) + refresh_req <= 1'b1; + end + + // flag to tell cal1 calibration was started. + // This flag is used for cal1 auto refreshes + // some of these bits may not be needed - only needed for those stages that + // need refreshes within the stage (i.e. very long stages) + always @(posedge clkdiv0) + if (rstdiv0) begin + cal1_started_r <= 1'b0; + cal2_started_r <= 1'b0; + cal4_started_r <= 1'b0; + end else begin + if (calib_start[0]) + cal1_started_r <= 1'b1; + if (calib_start[1]) + cal2_started_r <= 1'b1; + if (calib_start[3]) + cal4_started_r <= 1'b1; + end + + // Delay start of each calibration by 16 clock cycles to + // ensure that when calibration logic begins, that read data is already + // appearing on the bus. Don't really need it, it's more for simulation + // purposes. Each circuit should synthesize using an SRL16. + // In first stage of calibration periodic auto refreshes + // will be issued to meet memory timing. calib_start_shift0_r[15] will be + // asserted more than once.calib_start[0] is anded with cal1_started_r so + // that it is asserted only once. cal1_refresh_done is anded with + // cal1_started_r so that it is asserted after the auto refreshes. + always @(posedge clkdiv0) begin + calib_start_shift0_r <= {calib_start_shift0_r[14:0], start_cal[0]}; + calib_start_shift1_r <= {calib_start_shift1_r[14:0], start_cal[1]}; + calib_start_shift2_r <= {calib_start_shift2_r[14:0], start_cal[2]}; + calib_start_shift3_r <= {calib_start_shift3_r[14:0], start_cal[3]}; + calib_start[0] <= calib_start_shift0_r[15] & ~cal1_started_r; + calib_start[1] <= calib_start_shift1_r[15] & ~cal2_started_r; + calib_start[2] <= calib_start_shift2_r[15]; + calib_start[3] <= calib_start_shift3_r[15] & ~cal4_started_r; + calib_ref_done <= calib_start_shift0_r[15] | + calib_start_shift1_r[15] | + calib_start_shift3_r[15]; + end + + // generate delay for various states that require it (no maximum delay + // requirement, make sure that terminal count is large enough to cover + // all cases) + always @(posedge clkdiv0) begin + case (init_state_r) + INIT_PRECHARGE_WAIT, + INIT_MODE_REGISTER_WAIT, + INIT_AUTO_REFRESH_WAIT, + INIT_DUMMY_ACTIVE_WAIT, + INIT_CAL1_WRITE_READ, + INIT_CAL1_READ_WAIT, + INIT_CAL2_WRITE_READ, + INIT_CAL2_READ_WAIT, + INIT_CAL3_WRITE_READ, + INIT_CAL4_WRITE_READ : + cnt_cmd_r <= cnt_cmd_r + 1; + default: + cnt_cmd_r <= 7'b0000000; + endcase + end + + // assert when count reaches the value + always @(posedge clkdiv0) begin + if(cnt_cmd_r == CNTNEXT_CMD) + cnt_cmd_ok_r <= 1'b1; + else + cnt_cmd_ok_r <= 1'b0; + end + + always @(posedge clkdiv0) begin + case (init_state_r) + INIT_CAL3_READ_WAIT, + INIT_CAL4_READ_WAIT: + cnt_rd_r <= cnt_rd_r + 1; + default: + cnt_rd_r <= 4'b0000; + endcase + end + + always @(posedge clkdiv0) begin + if(cnt_rd_r == CNTNEXT_RD) + cnt_rd_ok_r <= 1'b1; + else + cnt_rd_ok_r <= 1'b0; + end + + //*************************************************************************** + // Initial delay after power-on + //*************************************************************************** + + // register the refresh flag from the controller. + // The refresh flag is in full frequency domain - so a pulsed version must + // be generated for half freq domain using 2 consecutive full clk cycles + // The registered version is used for the 200us counter + always @(posedge clk0) + ctrl_ref_flag_r <= ctrl_ref_flag; + always @(posedge clkdiv0) + cke_200us_cnt_en_r <= ctrl_ref_flag || ctrl_ref_flag_r; + + // 200us counter for cke + always @(posedge clkdiv0) + if (rstdiv0) begin + // skip power-up count if only simulating + if (SIM_ONLY) + cke_200us_cnt_r <= 5'b00001; + else + cke_200us_cnt_r <= 5'd27; + end else if (cke_200us_cnt_en_r) + cke_200us_cnt_r <= cke_200us_cnt_r - 1; + + always @(posedge clkdiv0) + if (rstdiv0) + done_200us_r <= 1'b0; + else if (!done_200us_r) + done_200us_r <= (cke_200us_cnt_r == 5'b00000); + + // 200 clocks counter - count value : h'64 required for initialization + // Counts 100 divided by two clocks + always @(posedge clkdiv0) + if (rstdiv0 || (init_state_r == INIT_CNT_200)) + cnt_200_cycle_r <= 8'h64; + else if (init_state_r == INIT_ZQCL) // ddr3 + cnt_200_cycle_r <= 8'hC8; + else if (cnt_200_cycle_r != 8'h00) + cnt_200_cycle_r <= cnt_200_cycle_r - 1; + + always @(posedge clkdiv0) + if (rstdiv0 || (init_state_r == INIT_CNT_200) + || (init_state_r == INIT_ZQCL)) + cnt_200_cycle_done_r <= 1'b0; + else if (cnt_200_cycle_r == 8'h00) + cnt_200_cycle_done_r <= 1'b1; + + //***************************************************************** + // handle deep memory configuration: + // During initialization: Repeat initialization sequence once for each + // chip select. Note that we could perform initalization for all chip + // selects simulataneously. Probably fine - any potential SI issues with + // auto refreshing all chip selects at once? + // Once initialization complete, assert only CS[1] for calibration. + //***************************************************************** + + always @(posedge clkdiv0) + if (rstdiv0) begin + chip_cnt_r <= 2'b00; + end else if (init_state_r == INIT_DEEP_MEMORY_ST) begin + if (chip_cnt_r != CS_NUM) + chip_cnt_r <= chip_cnt_r + 1; + else + chip_cnt_r <= 2'b00; + // MIG 2.4: Modified to issue an Auto Refresh commmand + // to each chip select during various calibration stages + end else if (init_state_r == INIT_PRECHARGE && init_done_r) begin + chip_cnt_r <= 2'b00; + end else if (init_state_r1 == INIT_AUTO_REFRESH && init_done_r) begin + if (chip_cnt_r < (CS_NUM-1)) + chip_cnt_r <= chip_cnt_r + 1; + end + + // keep track of which chip selects got auto-refreshed (avoid auto-refreshing + // all CS's at once to avoid current spike) + always @(posedge clkdiv0)begin + if (rstdiv0 || init_state_r == INIT_PRECHARGE) + auto_cnt_r <= 'd0; + else if (init_state_r == INIT_AUTO_REFRESH && init_done_r) begin + if (auto_cnt_r < CS_NUM) + auto_cnt_r <= auto_cnt_r + 1; + end + end + + always @(posedge clkdiv0) + if (rstdiv0) begin + ddr_cs_n_r <= {CS_NUM{1'b1}}; + end else begin + ddr_cs_n_r <= {CS_NUM{1'b1}}; + if ((init_state_r == INIT_DUMMY_ACTIVE) || + ((init_state_r == INIT_PRECHARGE) && (~init_done_r))|| + (init_state_r == INIT_LOAD_MODE) || + (init_state_r == INIT_AUTO_REFRESH) || + (init_state_r == INIT_ZQCL ) || + (((init_state_r == INIT_CAL1_READ) || + (init_state_r == INIT_CAL2_READ) || + (init_state_r == INIT_CAL3_READ) || + (init_state_r == INIT_CAL4_READ) || + (init_state_r == INIT_CAL1_WRITE) || + (init_state_r == INIT_CAL2_WRITE) || + (init_state_r == INIT_CAL3_WRITE) || + (init_state_r == INIT_CAL4_WRITE)) && (burst_cnt_r == 2'b00))) + ddr_cs_n_r[chip_cnt_r] <= 1'b0; + else if (init_state_r == INIT_PRECHARGE) + ddr_cs_n_r <= {CS_NUM{1'b0}}; + else + ddr_cs_n_r[chip_cnt_r] <= 1'b1; + end + + //*************************************************************************** + // Write/read burst logic + //*************************************************************************** + + assign cal_write = ((init_state_r == INIT_CAL1_WRITE) || + (init_state_r == INIT_CAL2_WRITE) || + (init_state_r == INIT_CAL3_WRITE) || + (init_state_r == INIT_CAL4_WRITE)); + assign cal_read = ((init_state_r == INIT_CAL1_READ) || + (init_state_r == INIT_CAL2_READ) || + (init_state_r == INIT_CAL3_READ) || + (init_state_r == INIT_CAL4_READ)); + assign cal_write_read = ((init_state_r == INIT_CAL1_READ) || + (init_state_r == INIT_CAL2_READ) || + (init_state_r == INIT_CAL3_READ) || + (init_state_r == INIT_CAL4_READ) || + (init_state_r == INIT_CAL1_WRITE) || + (init_state_r == INIT_CAL2_WRITE) || + (init_state_r == INIT_CAL3_WRITE) || + (init_state_r == INIT_CAL4_WRITE)); + + assign burst_val = (BURST_LEN == 4) ? 2'b00 : + (BURST_LEN == 8) ? 2'b01 : 2'b00; + + // keep track of current address - need this if burst length < 8 for + // stage 2-4 calibration writes and reads. Make sure value always gets + // initialized to 0 before we enter write/read state. This is used to + // keep track of when another burst must be issued + always @(posedge clkdiv0) + if (cal_write_read) + burst_addr_r <= burst_addr_r + 2; + else + burst_addr_r <= 2'b00; + + // write/read burst count + always @(posedge clkdiv0) + if (cal_write_read) + if (burst_cnt_r == 2'b00) + burst_cnt_r <= burst_val; + else // SHOULD THIS BE -2 CHECK THIS LOGIC + burst_cnt_r <= burst_cnt_r - 1; + else + burst_cnt_r <= 2'b00; + + // indicate when a write is occurring + always @(posedge clkdiv0) + // MIG 2.1: Remove (burst_addr_r<4) term - not used + // phy_init_wren <= cal_write && (burst_addr_r < 3'd4); + phy_init_wren <= cal_write; + + // used for read enable calibration, pulse to indicate when read issued + always @(posedge clkdiv0) + // MIG 2.1: Remove (burst_addr_r<4) term - not used + // phy_init_rden <= cal_read && (burst_addr_r < 3'd4); + phy_init_rden <= cal_read; + + //*************************************************************************** + // Initialization state machine + //*************************************************************************** + + always @(posedge clkdiv0) + // every time we need to initialize another rank of memory, need to + // reset init count, and repeat the entire initialization (but not + // calibration) sequence + if (rstdiv0 || (init_state_r == INIT_DEEP_MEMORY_ST)) + init_cnt_r <= INIT_CNTR_INIT; + else if ((DDR_TYPE == DDR1) && (init_state_r == INIT_PRECHARGE) && + (init_cnt_r == INIT_CNTR_PRECH_1)) + // skip EMR(2) and EMR(3) register loads + init_cnt_r <= INIT_CNTR_EMR_EN_DLL; + else if ((DDR_TYPE == DDR1) && (init_state_r == INIT_LOAD_MODE) && + (init_cnt_r == INIT_CNTR_MR_ACT_DLL)) + // skip OCD calibration for DDR1 + init_cnt_r <= INIT_CNTR_DEEP_MEM; + else if ((DDR_TYPE == DDR3) && (init_state_r == INIT_ZQCL)) + // skip states for DDR3 + init_cnt_r <= INIT_CNTR_DEEP_MEM; + else if ((init_state_r == INIT_LOAD_MODE) || + ((init_state_r == INIT_PRECHARGE) && + (init_state_r1 != INIT_CALIB_REF)) || + ((init_state_r == INIT_AUTO_REFRESH) && (~init_done_r)) || + (init_state_r == INIT_CNT_200) || + // MIG 3.3: Added increment when starting calibration + ((init_state_r == INIT_DUMMY_ACTIVE) && + (init_state_r1 == INIT_IDLE))) + init_cnt_r <= init_cnt_r + 1; + + always @(posedge clkdiv0) begin + if ((init_state_r == INIT_IDLE) && (init_cnt_r == INIT_CNTR_DONE)) begin + phy_init_done_r <= 1'b1; + end else + phy_init_done_r <= 1'b0; + end + + // phy_init_done to the controller and the user interface. + // It is delayed by four clocks to account for the + // multi cycle path constraint to the (phy_init_data_sel) + // to the phy layer. + always @(posedge clkdiv0) begin + phy_init_done_r1 <= phy_init_done_r; + phy_init_done_r2 <= phy_init_done_r1; + phy_init_done_r3 <= phy_init_done_r2; + phy_init_done <= phy_init_done_r3; + end + + // Instantiate primitive to allow this flop to be attached to multicycle + // path constraint in UCF. This signal goes to PHY_WRITE and PHY_CTL_IO + // datapath logic only. Because it is a multi-cycle path, it can be + // clocked by either CLKDIV0 or CLK0. + FDRSE u_ff_phy_init_data_sel + ( + .Q (phy_init_data_sel), + .C (clkdiv0), + .CE (1'b1), + .D (phy_init_done_r1), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve=1 */ + /* synthesis syn_replicate = 0 */; + + //synthesis translate_off + always @(posedge calib_done[0]) + $display ("First Stage Calibration completed at time %t", $time); + + always @(posedge calib_done[1]) + $display ("Second Stage Calibration completed at time %t", $time); + + always @(posedge calib_done[2]) begin + $display ("Third Stage Calibration completed at time %t", $time); + end + + always @(posedge calib_done[3]) begin + $display ("Fourth Stage Calibration completed at time %t", $time); + $display ("Calibration completed at time %t", $time); + end + //synthesis translate_on + + always @(posedge clkdiv0) begin + if ((init_cnt_r >= INIT_CNTR_DEEP_MEM))begin + init_done_r <= 1'b1; + end else + init_done_r <= 1'b0; + end + + //***************************************************************** + + always @(posedge clkdiv0) + if (rstdiv0) begin + init_state_r <= INIT_IDLE; + init_state_r1 <= INIT_IDLE; + init_state_r2 <= INIT_IDLE; + calib_done_r <= 4'b0000; + end else begin + init_state_r <= init_next_state; + init_state_r1 <= init_state_r; + init_state_r2 <= init_state_r1; + calib_done_r <= calib_done; // register for timing + end + + always @(*) begin + init_next_state = init_state_r; + (* full_case, parallel_case *) case (init_state_r) + INIT_IDLE: begin + if (done_200us_r) begin + (* parallel_case *) case (init_cnt_r) + INIT_CNTR_INIT: + init_next_state = INIT_CNT_200; + INIT_CNTR_PRECH_1: + init_next_state = INIT_PRECHARGE; + INIT_CNTR_EMR2_INIT: + init_next_state = INIT_LOAD_MODE; // EMR(2) + INIT_CNTR_EMR3_INIT: + init_next_state = INIT_LOAD_MODE; // EMR(3); + INIT_CNTR_EMR_EN_DLL: + init_next_state = INIT_LOAD_MODE; // EMR, enable DLL + INIT_CNTR_MR_RST_DLL: + init_next_state = INIT_LOAD_MODE; // MR, reset DLL + INIT_CNTR_CNT_200_WAIT:begin + if(DDR_TYPE == DDR3) + init_next_state = INIT_ZQCL; // DDR3 + else + // Wait 200cc after reset DLL + init_next_state = INIT_CNT_200; + end + INIT_CNTR_PRECH_2: + init_next_state = INIT_PRECHARGE; + INIT_CNTR_AR_1: + init_next_state = INIT_AUTO_REFRESH; + INIT_CNTR_AR_2: + init_next_state = INIT_AUTO_REFRESH; + INIT_CNTR_MR_ACT_DLL: + init_next_state = INIT_LOAD_MODE; // MR, unreset DLL + INIT_CNTR_EMR_DEF_OCD: + init_next_state = INIT_LOAD_MODE; // EMR, OCD default + INIT_CNTR_EMR_EXIT_OCD: + init_next_state = INIT_LOAD_MODE; // EMR, enable OCD exit + INIT_CNTR_DEEP_MEM: begin + if ((chip_cnt_r < CS_NUM-1)) + init_next_state = INIT_DEEP_MEMORY_ST; + else if (cnt_200_cycle_done_r) + init_next_state = INIT_DUMMY_ACTIVE; + else + init_next_state = INIT_IDLE; + end + // MIG 3.3: Remove extra precharge occurring at end of calibration +// INIT_CNTR_PRECH_3: +// init_next_state = INIT_PRECHARGE; + INIT_CNTR_DONE: + init_next_state = INIT_IDLE; + default : + init_next_state = INIT_IDLE; + endcase + end + end + INIT_CNT_200: + init_next_state = INIT_CNT_200_WAIT; + INIT_CNT_200_WAIT: + if (cnt_200_cycle_done_r) + init_next_state = INIT_IDLE; + INIT_PRECHARGE: + init_next_state = INIT_PRECHARGE_WAIT; + INIT_PRECHARGE_WAIT: + if (cnt_cmd_ok_r)begin + if (init_done_r && (!(&calib_done_r))) + init_next_state = INIT_AUTO_REFRESH; + else + init_next_state = INIT_IDLE; + end + INIT_ZQCL: + init_next_state = INIT_WAIT_DLLK_ZQINIT; + INIT_WAIT_DLLK_ZQINIT: + if (cnt_200_cycle_done_r) + init_next_state = INIT_IDLE; + INIT_LOAD_MODE: + init_next_state = INIT_MODE_REGISTER_WAIT; + INIT_MODE_REGISTER_WAIT: + if (cnt_cmd_ok_r) + init_next_state = INIT_IDLE; + INIT_AUTO_REFRESH: + init_next_state = INIT_AUTO_REFRESH_WAIT; + INIT_AUTO_REFRESH_WAIT: + // MIG 2.4: Modified to issue an Auto Refresh commmand + // to each chip select during various calibration stages + if (auto_cnt_r < CS_NUM && init_done_r) begin + if (cnt_cmd_ok_r) + init_next_state = INIT_AUTO_REFRESH; + end else if (cnt_cmd_ok_r)begin + if (init_done_r) + init_next_state = INIT_DUMMY_ACTIVE; + else + init_next_state = INIT_IDLE; + end + INIT_DEEP_MEMORY_ST: + init_next_state = INIT_IDLE; + // single row activate. All subsequent calibration writes and + // read will take place in this row + INIT_DUMMY_ACTIVE: + init_next_state = INIT_DUMMY_ACTIVE_WAIT; + INIT_DUMMY_ACTIVE_WAIT: + if (cnt_cmd_ok_r)begin + if (~calib_done_r[0]) begin + // if returning to stg1 after refresh, don't need to write + if (cal1_started_r) + init_next_state = INIT_CAL1_READ; + // if first entering stg1, need to write training pattern + else + init_next_state = INIT_CAL1_WRITE; + end else if (~calib_done[1]) begin + if (cal2_started_r) + init_next_state = INIT_CAL2_READ; + else + init_next_state = INIT_CAL2_WRITE; + end else if (~calib_done_r[2]) + // Stage 3 only requires a refresh after the entire stage is + // finished + init_next_state = INIT_CAL3_WRITE; + else begin + // Stage 4 requires a refresh after every DQS group + if (cal4_started_r) + init_next_state = INIT_CAL4_READ; + else + init_next_state = INIT_CAL4_WRITE; + end + end + // Stage 1 calibration (write and continuous read) + INIT_CAL1_WRITE: + if (burst_addr_r == 2'b10) + init_next_state = INIT_CAL1_WRITE_READ; + INIT_CAL1_WRITE_READ: + if (cnt_cmd_ok_r) + init_next_state = INIT_CAL1_READ; + INIT_CAL1_READ: + // Stage 1 requires inter-stage auto-refresh + if (calib_done_r[0] || refresh_req) + init_next_state = INIT_CAL1_READ_WAIT; + INIT_CAL1_READ_WAIT: + if (cnt_cmd_ok_r) + init_next_state = INIT_CALIB_REF; + // Stage 2 calibration (write and continuous read) + INIT_CAL2_WRITE: + if (burst_addr_r == 2'b10) + init_next_state = INIT_CAL2_WRITE_READ; + INIT_CAL2_WRITE_READ: + if (cnt_cmd_ok_r) + init_next_state = INIT_CAL2_READ; + INIT_CAL2_READ: + // Stage 2 requires inter-stage auto-refresh + if (calib_done_r[1] || refresh_req) + init_next_state = INIT_CAL2_READ_WAIT; + INIT_CAL2_READ_WAIT: + if (cnt_cmd_ok_r) + init_next_state = INIT_CALIB_REF; + // Stage 3 calibration (write and continuous read) + INIT_CAL3_WRITE: + if (burst_addr_r == 2'b10) + init_next_state = INIT_CAL3_WRITE_READ; + INIT_CAL3_WRITE_READ: + if (cnt_cmd_ok_r) + init_next_state = INIT_CAL3_READ; + INIT_CAL3_READ: + if (burst_addr_r == 2'b10) + init_next_state = INIT_CAL3_READ_WAIT; + INIT_CAL3_READ_WAIT: begin + if (cnt_rd_ok_r) + if (calib_done_r[2]) begin + init_next_state = INIT_CALIB_REF; + end else + init_next_state = INIT_CAL3_READ; + end + // Stage 4 calibration + INIT_CAL4_WRITE: + if (burst_addr_r == 2'b10) + init_next_state = INIT_CAL4_WRITE_READ; + INIT_CAL4_WRITE_READ: + if (cnt_cmd_ok_r) + init_next_state = INIT_CAL4_READ; + INIT_CAL4_READ: + if (burst_addr_r == 2'b10) + init_next_state = INIT_CAL4_READ_WAIT; + INIT_CAL4_READ_WAIT: begin + if (cnt_rd_ok_r) + // Stage 4 requires inter-stage auto-refresh + if (calib_done_r[3] || refresh_req) + // MIG 3.3: With removal of extra precharge, proceed to + // state CALIB_REF first to avoid incrementing init_cntr +// init_next_state = INIT_PRECHARGE; + init_next_state = INIT_CALIB_REF; + else + init_next_state = INIT_CAL4_READ; + end + INIT_CALIB_REF: + init_next_state = INIT_PRECHARGE; + endcase + end + + //*************************************************************************** + // Memory control/address + //*************************************************************************** + + always @(posedge clkdiv0) + if ((init_state_r == INIT_DUMMY_ACTIVE) || + (init_state_r == INIT_PRECHARGE) || + (init_state_r == INIT_LOAD_MODE) || + (init_state_r == INIT_AUTO_REFRESH)) begin + ddr_ras_n_r <= 1'b0; + end else begin + ddr_ras_n_r <= 1'b1; + end + + always @(posedge clkdiv0) + if ((init_state_r == INIT_LOAD_MODE) || + (init_state_r == INIT_AUTO_REFRESH) || + (cal_write_read && (burst_cnt_r == 2'b00))) begin + ddr_cas_n_r <= 1'b0; + end else begin + ddr_cas_n_r <= 1'b1; + end + + always @(posedge clkdiv0) + if ((init_state_r == INIT_LOAD_MODE) || + (init_state_r == INIT_PRECHARGE) || + (init_state_r == INIT_ZQCL) || + (cal_write && (burst_cnt_r == 2'b00)))begin + ddr_we_n_r <= 1'b0; + end else begin + ddr_we_n_r <= 1'b1; + end + + //***************************************************************** + // memory address during init + //***************************************************************** + + always @(posedge clkdiv0) begin + if ((init_state_r == INIT_PRECHARGE) + || (init_state_r == INIT_ZQCL))begin + // Precharge all - set A10 = 1 + ddr_addr_r <= {ROW_WIDTH{1'b0}}; + ddr_addr_r[10] <= 1'b1; + ddr_ba_r <= {BANK_WIDTH{1'b0}}; + end else if (init_state_r == INIT_LOAD_MODE) begin + ddr_ba_r <= {BANK_WIDTH{1'b0}}; + ddr_addr_r <= {ROW_WIDTH{1'b0}}; + case (init_cnt_r) + // EMR (2) + INIT_CNTR_EMR2_INIT: begin + ddr_ba_r[1:0] <= 2'b10; + ddr_addr_r <= {ROW_WIDTH{1'b0}}; + end + // EMR (3) + INIT_CNTR_EMR3_INIT: begin + ddr_ba_r[1:0] <= 2'b11; + if(DDR_TYPE == DDR3) + ddr_addr_r <= load_mode_reg3[ROW_WIDTH-1:0]; + else + ddr_addr_r <= {ROW_WIDTH{1'b0}}; + end + // EMR write - A0 = 0 for DLL enable + INIT_CNTR_EMR_EN_DLL: begin + ddr_ba_r[1:0] <= 2'b01; + if(DDR_TYPE == DDR3) + ddr_addr_r <= load_mode_reg1[ROW_WIDTH-1:0]; + else + ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; + end + // MR write, reset DLL (A8=1) + INIT_CNTR_MR_RST_DLL: begin + if(DDR_TYPE == DDR3) + ddr_addr_r <= load_mode_reg0[ROW_WIDTH-1:0]; + else + ddr_addr_r <= load_mode_reg[ROW_WIDTH-1:0]; + ddr_ba_r[1:0] <= 2'b00; + ddr_addr_r[8] <= 1'b1; + end + // MR write, unreset DLL (A8=0) + INIT_CNTR_MR_ACT_DLL: begin + ddr_ba_r[1:0] <= 2'b00; + ddr_addr_r <= load_mode_reg[ROW_WIDTH-1:0]; + end + // EMR write, OCD default state + INIT_CNTR_EMR_DEF_OCD: begin + ddr_ba_r[1:0] <= 2'b01; + ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; + ddr_addr_r[9:7] <= 3'b111; + end + // EMR write - OCD exit + INIT_CNTR_EMR_EXIT_OCD: begin + ddr_ba_r[1:0] <= 2'b01; + ddr_addr_r <= ext_mode_reg[ROW_WIDTH-1:0]; + end + default: begin + ddr_ba_r <= {BANK_WIDTH{1'bx}}; + ddr_addr_r <= {ROW_WIDTH{1'bx}}; + end + endcase + end else if (cal_write_read) begin + // when writing or reading for Stages 2-4, since training pattern is + // either 4 (stage 2) or 8 (stage 3-4) long, if BURST LEN < 8, then + // need to issue multiple bursts to read entire training pattern + ddr_addr_r[ROW_WIDTH-1:3] <= {ROW_WIDTH-4{1'b0}}; + ddr_addr_r[2:0] <= {burst_addr_r, 1'b0}; + ddr_ba_r <= {BANK_WIDTH-1{1'b0}}; + end else if (init_state_r == INIT_DUMMY_ACTIVE) begin + // all calibration writing read takes place in row 0x0 only + ddr_ba_r <= {BANK_WIDTH{1'b0}}; + ddr_addr_r <= {ROW_WIDTH{1'b0}}; + end else begin + // otherwise, cry me a river + ddr_ba_r <= {BANK_WIDTH{1'bx}}; + ddr_addr_r <= {ROW_WIDTH{1'bx}}; + end + end + + // Keep CKE asserted after initial power-on delay + always @(posedge clkdiv0) + ddr_cke_r <= {CKE_WIDTH{done_200us_r}}; + + // register commands to memory. Two clock cycle delay from state -> output + always @(posedge clk0) begin + ddr_addr_r1 <= ddr_addr_r; + ddr_ba_r1 <= ddr_ba_r; + ddr_cas_n_r1 <= ddr_cas_n_r; + ddr_ras_n_r1 <= ddr_ras_n_r; + ddr_we_n_r1 <= ddr_we_n_r; + ddr_cs_n_r1 <= ddr_cs_n_r; + end // always @ (posedge clk0) + + always @(posedge clk0) + init_state_r1_2t <= init_state_r1; + + // logic to toggle chip select. The chip_select is + // clocked of clkdiv0 and will be asserted for + // two clock cycles. + always @(posedge clk0) begin + if(rst0) + ddr_cs_disable_r <= {CS_NUM{1'b0}}; + else begin + if(| ddr_cs_disable_r) + ddr_cs_disable_r <= {CS_NUM{1'b0}}; + else begin + if (TWO_T_TIME_EN) begin + if (init_state_r1_2t == INIT_PRECHARGE && init_done_r) + ddr_cs_disable_r <= 'd3; + else + ddr_cs_disable_r[chip_cnt_r] <= ~ddr_cs_n_r1[chip_cnt_r]; + end + else begin + if (init_state_r1 == INIT_PRECHARGE && init_done_r) + ddr_cs_disable_r <= 'd3; + else + ddr_cs_disable_r[chip_cnt_r] <= ~ddr_cs_n_r[chip_cnt_r]; + end + end + end + end + + + assign phy_init_addr = ddr_addr_r; + assign phy_init_ba = ddr_ba_r; + assign phy_init_cas_n = ddr_cas_n_r; + assign phy_init_cke = ddr_cke_r; + assign phy_init_ras_n = ddr_ras_n_r; + assign phy_init_we_n = ddr_we_n_r; + assign phy_init_cs_n = (TWO_T_TIME_EN) ? + ddr_cs_n_r1 | ddr_cs_disable_r + : ddr_cs_n_r| ddr_cs_disable_r; + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_io.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_io.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_io.v (revision 3) @@ -0,0 +1,353 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_io.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module instantiates calibration logic, data, data strobe and the +// data mask iobs. +//Reference: +//Revision History: +// Rev 1.1 - DM_IOB instance made based on USE_DM_PORT value . PK. 25/6/08 +// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 +// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_phy_io # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter CLK_WIDTH = 1, + parameter USE_DM_PORT = 1, + parameter DM_WIDTH = 9, + parameter DQ_WIDTH = 72, + parameter DQ_BITS = 7, + parameter DQ_PER_DQS = 8, + parameter DQS_BITS = 4, + parameter DQS_WIDTH = 9, + parameter HIGH_PERFORMANCE_MODE = "TRUE", + parameter IODELAY_GRP = "IODELAY_MIG", + parameter ODT_WIDTH = 1, + parameter ADDITIVE_LAT = 0, + parameter CAS_LAT = 5, + parameter REG_ENABLE = 1, + parameter CLK_PERIOD = 3000, + parameter DDR_TYPE = 1, + parameter SIM_ONLY = 0, + parameter DEBUG_EN = 0, + parameter FPGA_SPEED_GRADE = 2 + ) + ( + input clk0, + input clk90, + input clkdiv0, + input rst0, + input rst90, + input rstdiv0, + input dm_ce, + input [1:0] dq_oe_n, + input dqs_oe_n, + input dqs_rst_n, + input [3:0] calib_start, + input ctrl_rden, + input phy_init_rden, + input calib_ref_done, + output [3:0] calib_done, + output calib_ref_req, + output [DQS_WIDTH-1:0] calib_rden, + output [DQS_WIDTH-1:0] calib_rden_sel, + input [DQ_WIDTH-1:0] wr_data_rise, + input [DQ_WIDTH-1:0] wr_data_fall, + input [(DQ_WIDTH/8)-1:0] mask_data_rise, + input [(DQ_WIDTH/8)-1:0] mask_data_fall, + output [(DQ_WIDTH)-1:0] rd_data_rise, + output [(DQ_WIDTH)-1:0] rd_data_fall, + output [CLK_WIDTH-1:0] ddr_ck, + output [CLK_WIDTH-1:0] ddr_ck_n, + output [DM_WIDTH-1:0] ddr_dm, + inout [DQS_WIDTH-1:0] ddr_dqs, + inout [DQS_WIDTH-1:0] ddr_dqs_n, + inout [DQ_WIDTH-1:0] ddr_dq, + // Debug signals (optional use) + input dbg_idel_up_all, + input dbg_idel_down_all, + input dbg_idel_up_dq, + input dbg_idel_down_dq, + input dbg_idel_up_dqs, + input dbg_idel_down_dqs, + input dbg_idel_up_gate, + input dbg_idel_down_gate, + input [DQ_BITS-1:0] dbg_sel_idel_dq, + input dbg_sel_all_idel_dq, + input [DQS_BITS:0] dbg_sel_idel_dqs, + input dbg_sel_all_idel_dqs, + input [DQS_BITS:0] dbg_sel_idel_gate, + input dbg_sel_all_idel_gate, + output [3:0] dbg_calib_done, + output [3:0] dbg_calib_err, + output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, + output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, + output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, + output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly + ); + + // ratio of # of physical DM outputs to bytes in data bus + // may be different - e.g. if using x4 components + localparam DM_TO_BYTE_RATIO = DM_WIDTH / (DQ_WIDTH/8); + + wire [CLK_WIDTH-1:0] ddr_ck_q; + wire [DQS_WIDTH-1:0] delayed_dqs; + wire [DQ_WIDTH-1:0] dlyce_dq; + wire [DQS_WIDTH-1:0] dlyce_dqs; + wire [DQS_WIDTH-1:0] dlyce_gate; + wire [DQ_WIDTH-1:0] dlyinc_dq; + wire [DQS_WIDTH-1:0] dlyinc_dqs; + wire [DQS_WIDTH-1:0] dlyinc_gate; + wire dlyrst_dq; + wire dlyrst_dqs; + wire [DQS_WIDTH-1:0] dlyrst_gate; + wire [DQS_WIDTH-1:0] dq_ce; + (* KEEP = "TRUE" *) wire [DQS_WIDTH-1:0] en_dqs /* synthesis syn_keep = 1 */; + wire [DQS_WIDTH-1:0] rd_data_sel; + + //*************************************************************************** + + ddr2_phy_calib # + ( + .DQ_WIDTH (DQ_WIDTH), + .DQ_BITS (DQ_BITS), + .DQ_PER_DQS (DQ_PER_DQS), + .DQS_BITS (DQS_BITS), + .DQS_WIDTH (DQS_WIDTH), + .ADDITIVE_LAT (ADDITIVE_LAT), + .CAS_LAT (CAS_LAT), + .REG_ENABLE (REG_ENABLE), + .CLK_PERIOD (CLK_PERIOD), + .SIM_ONLY (SIM_ONLY), + .DEBUG_EN (DEBUG_EN) + ) + u_phy_calib + ( + .clk (clk0), + .clkdiv (clkdiv0), + .rstdiv (rstdiv0), + .calib_start (calib_start), + .ctrl_rden (ctrl_rden), + .phy_init_rden (phy_init_rden), + .rd_data_rise (rd_data_rise), + .rd_data_fall (rd_data_fall), + .calib_ref_done (calib_ref_done), + .calib_done (calib_done), + .calib_ref_req (calib_ref_req), + .calib_rden (calib_rden), + .calib_rden_sel (calib_rden_sel), + .dlyrst_dq (dlyrst_dq), + .dlyce_dq (dlyce_dq), + .dlyinc_dq (dlyinc_dq), + .dlyrst_dqs (dlyrst_dqs), + .dlyce_dqs (dlyce_dqs), + .dlyinc_dqs (dlyinc_dqs), + .dlyrst_gate (dlyrst_gate), + .dlyce_gate (dlyce_gate), + .dlyinc_gate (dlyinc_gate), + .en_dqs (en_dqs), + .rd_data_sel (rd_data_sel), + .dbg_idel_up_all (dbg_idel_up_all), + .dbg_idel_down_all (dbg_idel_down_all), + .dbg_idel_up_dq (dbg_idel_up_dq), + .dbg_idel_down_dq (dbg_idel_down_dq), + .dbg_idel_up_dqs (dbg_idel_up_dqs), + .dbg_idel_down_dqs (dbg_idel_down_dqs), + .dbg_idel_up_gate (dbg_idel_up_gate), + .dbg_idel_down_gate (dbg_idel_down_gate), + .dbg_sel_idel_dq (dbg_sel_idel_dq), + .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), + .dbg_sel_idel_dqs (dbg_sel_idel_dqs), + .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), + .dbg_sel_idel_gate (dbg_sel_idel_gate), + .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate), + .dbg_calib_done (dbg_calib_done), + .dbg_calib_err (dbg_calib_err), + .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), + .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), + .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), + .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), + .dbg_calib_rden_dly (dbg_calib_rden_dly), + .dbg_calib_gate_dly (dbg_calib_gate_dly) + ); + + //*************************************************************************** + // Memory clock generation + //*************************************************************************** + + genvar ck_i; + generate + for(ck_i = 0; ck_i < CLK_WIDTH; ck_i = ck_i+1) begin: gen_ck + ODDR # + ( + .SRTYPE ("SYNC"), + .DDR_CLK_EDGE ("OPPOSITE_EDGE") + ) + u_oddr_ck_i + ( + .Q (ddr_ck_q[ck_i]), + .C (clk0), + .CE (1'b1), + .D1 (1'b0), + .D2 (1'b1), + .R (1'b0), + .S (1'b0) + ); + // Can insert ODELAY here if required + OBUFDS u_obuf_ck_i + ( + .I (ddr_ck_q[ck_i]), + .O (ddr_ck[ck_i]), + .OB (ddr_ck_n[ck_i]) + ); + end + endgenerate + + //*************************************************************************** + // DQS instances + //*************************************************************************** + + genvar dqs_i; + generate + for(dqs_i = 0; dqs_i < DQS_WIDTH; dqs_i = dqs_i+1) begin: gen_dqs + ddr2_phy_dqs_iob # + ( + .DDR_TYPE (DDR_TYPE), + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .IODELAY_GRP (IODELAY_GRP) + ) + u_iob_dqs + ( + .clk0 (clk0), + .clkdiv0 (clkdiv0), + .rst0 (rst0), + .dlyinc_dqs (dlyinc_dqs[dqs_i]), + .dlyce_dqs (dlyce_dqs[dqs_i]), + .dlyrst_dqs (dlyrst_dqs), + .dlyinc_gate (dlyinc_gate[dqs_i]), + .dlyce_gate (dlyce_gate[dqs_i]), + .dlyrst_gate (dlyrst_gate[dqs_i]), + .dqs_oe_n (dqs_oe_n), + .dqs_rst_n (dqs_rst_n), + .en_dqs (en_dqs[dqs_i]), + .ddr_dqs (ddr_dqs[dqs_i]), + .ddr_dqs_n (ddr_dqs_n[dqs_i]), + .dq_ce (dq_ce[dqs_i]), + .delayed_dqs (delayed_dqs[dqs_i]) + ); + end + endgenerate + + //*************************************************************************** + // DM instances + //*************************************************************************** + + genvar dm_i; + generate + if (USE_DM_PORT) begin: gen_dm_inst + for(dm_i = 0; dm_i < DM_WIDTH; dm_i = dm_i+1) begin: gen_dm + ddr2_phy_dm_iob u_iob_dm + ( + .clk90 (clk90), + .dm_ce (dm_ce), + .mask_data_rise (mask_data_rise[dm_i/DM_TO_BYTE_RATIO]), + .mask_data_fall (mask_data_fall[dm_i/DM_TO_BYTE_RATIO]), + .ddr_dm (ddr_dm[dm_i]) + ); + end + end + endgenerate + + //*************************************************************************** + // DQ IOB instances + //*************************************************************************** + + genvar dq_i; + generate + for(dq_i = 0; dq_i < DQ_WIDTH; dq_i = dq_i+1) begin: gen_dq + ddr2_phy_dq_iob # + ( + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .IODELAY_GRP (IODELAY_GRP), + .FPGA_SPEED_GRADE (FPGA_SPEED_GRADE) + ) + u_iob_dq + ( + .clk0 (clk0), + .clk90 (clk90), + .clkdiv0 (clkdiv0), + .rst90 (rst90), + .dlyinc (dlyinc_dq[dq_i]), + .dlyce (dlyce_dq[dq_i]), + .dlyrst (dlyrst_dq), + .dq_oe_n (dq_oe_n), + .dqs (delayed_dqs[dq_i/DQ_PER_DQS]), + .ce (dq_ce[dq_i/DQ_PER_DQS]), + .rd_data_sel (rd_data_sel[dq_i/DQ_PER_DQS]), + .wr_data_rise (wr_data_rise[dq_i]), + .wr_data_fall (wr_data_fall[dq_i]), + .rd_data_rise (rd_data_rise[dq_i]), + .rd_data_fall (rd_data_fall[dq_i]), + .ddr_dq (ddr_dq[dq_i]) + ); + end + endgenerate + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/MEMCtrl.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/MEMCtrl.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/MEMCtrl.v (revision 3) @@ -0,0 +1,605 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: MEMCtrl.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// Top-level module. Simple model for what the user might use +// Typically, the user will only instantiate MEM_INTERFACE_TOP in their +// code, and generate all backend logic (test bench) and all the other infrastructure logic +// separately. +// In addition to the memory controller, the module instantiates: +// 1. Reset logic based on user clocks +// 2. IDELAY control block +//Reference: +//Revision History: +// Rev 1.1 - Parameter USE_DM_PORT added. PK. 6/25/08 +// Rev 1.2 - Parameter HIGH_PERFORMANCE_MODE added. PK. 7/10/08 +// Rev 1.3 - Parameter IODELAY_GRP added. PK. 11/27/08 +//***************************************************************************** + +`timescale 1ns/1ps + +(* X_CORE_INFO = "mig_v3_61_ddr2_v5, Coregen 12.4" , CORE_GENERATION_INFO = "ddr2_v5,mig_v3_61,{component_name=MEMCtrl, BANK_WIDTH=2, CKE_WIDTH=1, CLK_WIDTH=2, COL_WIDTH=10, CS_NUM=1, CS_WIDTH=1, DM_WIDTH=8, DQ_WIDTH=64, DQ_PER_DQS=8, DQS_WIDTH=8, ODT_WIDTH=1, ROW_WIDTH=13, ADDITIVE_LAT=0, BURST_LEN=4, BURST_TYPE=0, CAS_LAT=3, ECC_ENABLE=0, MULTI_BANK_EN=1, TWO_T_TIME_EN=1, ODT_TYPE=1, REDUCE_DRV=0, REG_ENABLE=0, TREFI_NS=7800, TRAS=40000, TRCD=15000, TRFC=105000, TRP=15000, TRTP=7500, TWR=15000, TWTR=7500, CLK_PERIOD=8000, RST_ACT_LOW=1, INTERFACE_TYPE=DDR2_SDRAM, LANGUAGE=Verilog, SYNTHESIS_TOOL=ISE, NO_OF_CONTROLLERS=1}" *) +module MEMCtrl # + ( + parameter BANK_WIDTH = 2, + // # of memory bank addr bits. + parameter CKE_WIDTH = 1, + // # of memory clock enable outputs. + parameter CLK_WIDTH = 2, + // # of clock outputs. + parameter COL_WIDTH = 10, + // # of memory column bits. + parameter CS_NUM = 1, + // # of separate memory chip selects. + parameter CS_WIDTH = 1, + // # of total memory chip selects. + parameter CS_BITS = 0, + // set to log2(CS_NUM) (rounded up). + parameter DM_WIDTH = 8, + // # of data mask bits. + parameter DQ_WIDTH = 64, + // # of data width. + parameter DQ_PER_DQS = 8, + // # of DQ data bits per strobe. + parameter DQS_WIDTH = 8, + // # of DQS strobes. + parameter DQ_BITS = 6, + // set to log2(DQS_WIDTH*DQ_PER_DQS). + parameter DQS_BITS = 3, + // set to log2(DQS_WIDTH). + parameter ODT_WIDTH = 1, + // # of memory on-die term enables. + parameter ROW_WIDTH = 13, + // # of memory row and # of addr bits. + parameter ADDITIVE_LAT = 0, + // additive write latency. + parameter BURST_LEN = 4, + // burst length (in double words). + parameter BURST_TYPE = 0, + // burst type (=0 seq; =1 interleaved). + parameter CAS_LAT = 3, + // CAS latency. + parameter ECC_ENABLE = 0, + // enable ECC (=1 enable). + parameter APPDATA_WIDTH = 128, + // # of usr read/write data bus bits. + parameter MULTI_BANK_EN = 1, + // Keeps multiple banks open. (= 1 enable). + parameter TWO_T_TIME_EN = 1, + // 2t timing for unbuffered dimms. + parameter ODT_TYPE = 1, + // ODT (=0(none),=1(75),=2(150),=3(50)). + parameter REDUCE_DRV = 0, + // reduced strength mem I/O (=1 yes). + parameter REG_ENABLE = 0, + // registered addr/ctrl (=1 yes). + parameter TREFI_NS = 7800, + // auto refresh interval (ns). + parameter TRAS = 40000, + // active->precharge delay. + parameter TRCD = 15000, + // active->read/write delay. + parameter TRFC = 105000, + // refresh->refresh, refresh->active delay. + parameter TRP = 15000, + // precharge->command delay. + parameter TRTP = 7500, + // read->precharge delay. + parameter TWR = 15000, + // used to determine write->precharge. + parameter TWTR = 7500, + // write->read delay. + parameter HIGH_PERFORMANCE_MODE = "TRUE", + // # = TRUE, the IODELAY performance mode is set + // to high. + // # = FALSE, the IODELAY performance mode is set + // to low. + parameter SIM_ONLY = 0, + // = 1 to skip SDRAM power up delay. + parameter DEBUG_EN = 0, + // Enable debug signals/controls. + // When this parameter is changed from 0 to 1, + // make sure to uncomment the coregen commands + // in ise_flow.bat or create_ise.bat files in + // par folder. + parameter CLK_PERIOD = 8000, + // Core/Memory clock period (in ps). + parameter RST_ACT_LOW = 1 + // =1 for active low reset, =0 for active high. + ) + ( + inout [DQ_WIDTH-1:0] ddr2_dq, + output [ROW_WIDTH-1:0] ddr2_a, + output [BANK_WIDTH-1:0] ddr2_ba, + output ddr2_ras_n, + output ddr2_cas_n, + output ddr2_we_n, + output [CS_WIDTH-1:0] ddr2_cs_n, + output [ODT_WIDTH-1:0] ddr2_odt, + output [CKE_WIDTH-1:0] ddr2_cke, + output [DM_WIDTH-1:0] ddr2_dm, + input sys_rst_n, + output phy_init_done, + input locked, + output rst0_tb, + input clk0, + output clk0_tb, + input clk90, + input clkdiv0, + input clk200, + output app_wdf_afull, + output app_af_afull, + output rd_data_valid, + input app_wdf_wren, + input app_af_wren, + input [30:0] app_af_addr, + input [2:0] app_af_cmd, + output [(APPDATA_WIDTH)-1:0] rd_data_fifo_out, + input [(APPDATA_WIDTH)-1:0] app_wdf_data, + input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, + inout [DQS_WIDTH-1:0] ddr2_dqs, + inout [DQS_WIDTH-1:0] ddr2_dqs_n, + output [CLK_WIDTH-1:0] ddr2_ck, + output [CLK_WIDTH-1:0] ddr2_ck_n//, + //ADAUGAT PT LEDURI + //output error_o, error_cmp_o + ); + + //*************************************************************************** + // IODELAY Group Name: Replication and placement of IDELAYCTRLs will be + // handled automatically by software tools if IDELAYCTRLs have same refclk, + // reset and rdy nets. Designs with a unique RESET will commonly create a + // unique RDY. Constraint IODELAY_GROUP is associated to a set of IODELAYs + // with an IDELAYCTRL. The parameter IODELAY_GRP value can be any string. + //*************************************************************************** + + localparam IODELAY_GRP = "IODELAY_MIG"; + + + + + + wire rst0; + wire rst90; + wire rstdiv0; + wire rst200; + wire idelay_ctrl_rdy; + + wire error; + wire error_cmp; + wire [35:0] control; + wire [71:0] data; + wire [7:0] trig0; + + //Debug signals + + + wire [3:0] dbg_calib_done; + wire [3:0] dbg_calib_err; + wire [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt; + wire [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt; + wire [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt; + wire [DQS_WIDTH-1:0] dbg_calib_rd_data_sel; + wire [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly; + wire [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly; + wire dbg_idel_up_all; + wire dbg_idel_down_all; + wire dbg_idel_up_dq; + wire dbg_idel_down_dq; + wire dbg_idel_up_dqs; + wire dbg_idel_down_dqs; + wire dbg_idel_up_gate; + wire dbg_idel_down_gate; + wire [DQ_BITS-1:0] dbg_sel_idel_dq; + wire dbg_sel_all_idel_dq; + wire [DQS_BITS:0] dbg_sel_idel_dqs; + wire dbg_sel_all_idel_dqs; + wire [DQS_BITS:0] dbg_sel_idel_gate; + wire dbg_sel_all_idel_gate; + + + // Debug signals (optional use) + + //*********************************** + // PHY Debug Port demo + //*********************************** + wire [35:0] cs_control0; + wire [35:0] cs_control1; + wire [35:0] cs_control2; + wire [35:0] cs_control3; + wire [191:0] vio0_in; + wire [95:0] vio1_in; + wire [99:0] vio2_in; + wire [31:0] vio3_out; + + + + + //*************************************************************************** + + assign rst0_tb = rst0; + assign clk0_tb = clk0; + + +ddr2_idelay_ctrl # + ( + .IODELAY_GRP (IODELAY_GRP) + ) + u_ddr2_idelay_ctrl + ( + .rst200 (rst200), + .clk200 (clk200), + .idelay_ctrl_rdy (idelay_ctrl_rdy) + ); + + ddr2_infrastructure # + ( + .RST_ACT_LOW (RST_ACT_LOW) + ) +u_ddr2_infrastructure + ( + .sys_rst_n (sys_rst_n), + .locked (locked), + .rst0 (rst0), + .rst90 (rst90), + .rstdiv0 (rstdiv0), + .rst200 (rst200), + .clk0 (clk0), + .clk90 (clk90), + .clkdiv0 (clkdiv0), + .clk200 (clk200), + .idelay_ctrl_rdy (idelay_ctrl_rdy) + ); + + ddr2_top # + ( + .BANK_WIDTH (BANK_WIDTH), + .CKE_WIDTH (CKE_WIDTH), + .CLK_WIDTH (CLK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_NUM (CS_NUM), + .CS_WIDTH (CS_WIDTH), + .CS_BITS (CS_BITS), + .DM_WIDTH (DM_WIDTH), + .DQ_WIDTH (DQ_WIDTH), + .DQ_PER_DQS (DQ_PER_DQS), + .DQS_WIDTH (DQS_WIDTH), + .DQ_BITS (DQ_BITS), + .DQS_BITS (DQS_BITS), + .ODT_WIDTH (ODT_WIDTH), + .ROW_WIDTH (ROW_WIDTH), + .ADDITIVE_LAT (ADDITIVE_LAT), + .BURST_LEN (BURST_LEN), + .BURST_TYPE (BURST_TYPE), + .CAS_LAT (CAS_LAT), + .ECC_ENABLE (ECC_ENABLE), + .APPDATA_WIDTH (APPDATA_WIDTH), + .MULTI_BANK_EN (MULTI_BANK_EN), + .TWO_T_TIME_EN (TWO_T_TIME_EN), + .ODT_TYPE (ODT_TYPE), + .REDUCE_DRV (REDUCE_DRV), + .REG_ENABLE (REG_ENABLE), + .TREFI_NS (TREFI_NS), + .TRAS (TRAS), + .TRCD (TRCD), + .TRFC (TRFC), + .TRP (TRP), + .TRTP (TRTP), + .TWR (TWR), + .TWTR (TWTR), + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .IODELAY_GRP (IODELAY_GRP), + .SIM_ONLY (SIM_ONLY), + .DEBUG_EN (DEBUG_EN), + .FPGA_SPEED_GRADE (3), + .USE_DM_PORT (1), + .CLK_PERIOD (CLK_PERIOD) + ) +u_ddr2_top_0 +( + .ddr2_dq (ddr2_dq), + .ddr2_a (ddr2_a), + .ddr2_ba (ddr2_ba), + .ddr2_ras_n (ddr2_ras_n), + .ddr2_cas_n (ddr2_cas_n), + .ddr2_we_n (ddr2_we_n), + .ddr2_cs_n (ddr2_cs_n), + .ddr2_odt (ddr2_odt), + .ddr2_cke (ddr2_cke), + .ddr2_dm (ddr2_dm), + .phy_init_done (phy_init_done), + .rst0 (rst0), + .rst90 (rst90), + .rstdiv0 (rstdiv0), + .clk0 (clk0), + .clk90 (clk90), + .clkdiv0 (clkdiv0), + .app_wdf_afull (app_wdf_afull), + .app_af_afull (app_af_afull), + .rd_data_valid (rd_data_valid), + .app_wdf_wren (app_wdf_wren), + .app_af_wren (app_af_wren), + .app_af_addr (app_af_addr), + .app_af_cmd (app_af_cmd), + .rd_data_fifo_out (rd_data_fifo_out), + .app_wdf_data (app_wdf_data), + .app_wdf_mask_data (app_wdf_mask_data), + .ddr2_dqs (ddr2_dqs), + .ddr2_dqs_n (ddr2_dqs_n), + .ddr2_ck (ddr2_ck), + .rd_ecc_error (), + .ddr2_ck_n (ddr2_ck_n), + + .dbg_calib_done (dbg_calib_done), + .dbg_calib_err (dbg_calib_err), + .dbg_calib_dq_tap_cnt (dbg_calib_dq_tap_cnt), + .dbg_calib_dqs_tap_cnt (dbg_calib_dqs_tap_cnt), + .dbg_calib_gate_tap_cnt (dbg_calib_gate_tap_cnt), + .dbg_calib_rd_data_sel (dbg_calib_rd_data_sel), + .dbg_calib_rden_dly (dbg_calib_rden_dly), + .dbg_calib_gate_dly (dbg_calib_gate_dly), + .dbg_idel_up_all (dbg_idel_up_all), + .dbg_idel_down_all (dbg_idel_down_all), + .dbg_idel_up_dq (dbg_idel_up_dq), + .dbg_idel_down_dq (dbg_idel_down_dq), + .dbg_idel_up_dqs (dbg_idel_up_dqs), + .dbg_idel_down_dqs (dbg_idel_down_dqs), + .dbg_idel_up_gate (dbg_idel_up_gate), + .dbg_idel_down_gate (dbg_idel_down_gate), + .dbg_sel_idel_dq (dbg_sel_idel_dq), + .dbg_sel_all_idel_dq (dbg_sel_all_idel_dq), + .dbg_sel_idel_dqs (dbg_sel_idel_dqs), + .dbg_sel_all_idel_dqs (dbg_sel_all_idel_dqs), + .dbg_sel_idel_gate (dbg_sel_idel_gate), + .dbg_sel_all_idel_gate (dbg_sel_all_idel_gate) + ); + + + //***************************************************************** + // Hooks to prevent sim/syn compilation errors (mainly for VHDL - but + // keep it also in Verilog version of code) w/ floating inputs if + // DEBUG_EN = 0. + //***************************************************************** + + generate + if (DEBUG_EN == 0) begin: gen_dbg_tie_off + assign dbg_idel_up_all = 'b0; + assign dbg_idel_down_all = 'b0; + assign dbg_idel_up_dq = 'b0; + assign dbg_idel_down_dq = 'b0; + assign dbg_idel_up_dqs = 'b0; + assign dbg_idel_down_dqs = 'b0; + assign dbg_idel_up_gate = 'b0; + assign dbg_idel_down_gate = 'b0; + assign dbg_sel_idel_dq = 'b0; + assign dbg_sel_all_idel_dq = 'b0; + assign dbg_sel_idel_dqs = 'b0; + assign dbg_sel_all_idel_dqs = 'b0; + assign dbg_sel_idel_gate = 'b0; + assign dbg_sel_all_idel_gate = 'b0; + end else begin: gen_dbg_enable + + //***************************************************************** + // PHY Debug Port example - see MIG User's Guide, XAPP858 or + // Answer Record 29443 + // This logic supports up to 32 DQ and 8 DQS I/O + // NOTES: + // 1. PHY Debug Port demo connects to 4 VIO modules: + // - 3 VIO modules with only asynchronous inputs + // * Monitor IDELAY taps for DQ, DQS, DQS Gate + // * Calibration status + // - 1 VIO module with synchronous outputs + // * Allow dynamic adjustment o f IDELAY taps + // 2. User may need to modify this code to incorporate other + // chipscope-related modules in their larger design (e.g. + // if they have other ILA/VIO modules, they will need to + // for example instantiate a larger ICON module). In addition + // user may want to instantiate more VIO modules to control + // IDELAY for more DQ, DQS than is shown here + //***************************************************************** + + icon4 u_icon + ( + .control0 (cs_control0), + .control1 (cs_control1), + .control2 (cs_control2), + .control3 (cs_control3) + ); + + //***************************************************************** + // VIO ASYNC input: Display current IDELAY setting for up to 32 + // DQ taps (32x6) = 192 + //***************************************************************** + + vio_async_in192 u_vio0 + ( + .control (cs_control0), + .async_in (vio0_in) + ); + + //***************************************************************** + // VIO ASYNC input: Display current IDELAY setting for up to 8 DQS + // and DQS Gate taps (8x6x2) = 96 + //***************************************************************** + + vio_async_in96 u_vio1 + ( + .control (cs_control1), + .async_in (vio1_in) + ); + + //***************************************************************** + // VIO ASYNC input: Display other calibration results + //***************************************************************** + + vio_async_in100 u_vio2 + ( + .control (cs_control2), + .async_in (vio2_in) + ); + + //***************************************************************** + // VIO SYNC output: Dynamically change IDELAY taps + //***************************************************************** + + vio_sync_out32 u_vio3 + ( + .control (cs_control3), + .clk (clkdiv0), + .sync_out (vio3_out) + ); + + //***************************************************************** + // Bit assignments: + // NOTE: Not all VIO, ILA inputs/outputs may be used - these will + // be dependent on the user's particular bit width + //***************************************************************** + + if (DQ_WIDTH <= 32) begin: gen_dq_le_32 + assign vio0_in[(6*DQ_WIDTH)-1:0] + = dbg_calib_dq_tap_cnt[(6*DQ_WIDTH)-1:0]; + end else begin: gen_dq_gt_32 + assign vio0_in = dbg_calib_dq_tap_cnt[191:0]; + end + + if (DQS_WIDTH <= 8) begin: gen_dqs_le_8 + assign vio1_in[(6*DQS_WIDTH)-1:0] + = dbg_calib_dqs_tap_cnt[(6*DQS_WIDTH)-1:0]; + assign vio1_in[(12*DQS_WIDTH)-1:(6*DQS_WIDTH)] + = dbg_calib_gate_tap_cnt[(6*DQS_WIDTH)-1:0]; + end else begin: gen_dqs_gt_32 + assign vio1_in[47:0] = dbg_calib_dqs_tap_cnt[47:0]; + assign vio1_in[95:48] = dbg_calib_gate_tap_cnt[47:0]; + end + +//dbg_calib_rd_data_sel + + if (DQS_WIDTH <= 8) begin: gen_rdsel_le_8 + assign vio2_in[(DQS_WIDTH)+7:8] + = dbg_calib_rd_data_sel[(DQS_WIDTH)-1:0]; + end else begin: gen_rdsel_gt_32 + assign vio2_in[15:8] + = dbg_calib_rd_data_sel[7:0]; + end + +//dbg_calib_rden_dly + + if (DQS_WIDTH <= 8) begin: gen_calrd_le_8 + assign vio2_in[(5*DQS_WIDTH)+19:20] + = dbg_calib_rden_dly[(5*DQS_WIDTH)-1:0]; + end else begin: gen_calrd_gt_32 + assign vio2_in[59:20] + = dbg_calib_rden_dly[39:0]; + end + +//dbg_calib_gate_dly + + if (DQS_WIDTH <= 8) begin: gen_calgt_le_8 + assign vio2_in[(5*DQS_WIDTH)+59:60] + = dbg_calib_gate_dly[(5*DQS_WIDTH)-1:0]; + end else begin: gen_calgt_gt_32 + assign vio2_in[99:60] + = dbg_calib_gate_dly[39:0]; + end + +//dbg_sel_idel_dq + + if (DQ_BITS <= 5) begin: gen_selid_le_5 + assign dbg_sel_idel_dq[DQ_BITS-1:0] + = vio3_out[DQ_BITS+7:8]; + end else begin: gen_selid_gt_32 + assign dbg_sel_idel_dq[4:0] + = vio3_out[12:8]; + end + +//dbg_sel_idel_dqs + + if (DQS_BITS <= 3) begin: gen_seldqs_le_3 + assign dbg_sel_idel_dqs[DQS_BITS:0] + = vio3_out[(DQS_BITS+16):16]; + end else begin: gen_seldqs_gt_32 + assign dbg_sel_idel_dqs[3:0] + = vio3_out[19:16]; + end + +//dbg_sel_idel_gate + + if (DQS_BITS <= 3) begin: gen_gtdqs_le_3 + assign dbg_sel_idel_gate[DQS_BITS:0] + = vio3_out[(DQS_BITS+21):21]; + end else begin: gen_gtdqs_gt_32 + assign dbg_sel_idel_gate[3:0] + = vio3_out[24:21]; + end + + + assign vio2_in[3:0] = dbg_calib_done; + assign vio2_in[7:4] = dbg_calib_err; + + assign dbg_idel_up_all = vio3_out[0]; + assign dbg_idel_down_all = vio3_out[1]; + assign dbg_idel_up_dq = vio3_out[2]; + assign dbg_idel_down_dq = vio3_out[3]; + assign dbg_idel_up_dqs = vio3_out[4]; + assign dbg_idel_down_dqs = vio3_out[5]; + assign dbg_idel_up_gate = vio3_out[6]; + assign dbg_idel_down_gate = vio3_out[7]; + assign dbg_sel_all_idel_dq = vio3_out[15]; + assign dbg_sel_all_idel_dqs = vio3_out[20]; + assign dbg_sel_all_idel_gate = vio3_out[25]; + end + endgenerate + + +endmodule + + + Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_ctl_io.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_ctl_io.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_ctl_io.v (revision 3) @@ -0,0 +1,304 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_ctl_io.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Thu Aug 24 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module puts the memory control signals like address, bank address, +// row address strobe, column address strobe, write enable and clock enable +// in the IOBs. +//Reference: +//Revision History: +// Rev 1.1 - To fix CR 540201, S attribute is added for CS, CKE and ODT +// module (FDCPE) instances. PK. 01/08/10 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_phy_ctl_io # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter CKE_WIDTH = 1, + parameter COL_WIDTH = 10, + parameter CS_NUM = 1, + parameter TWO_T_TIME_EN = 0, + parameter CS_WIDTH = 1, + parameter ODT_WIDTH = 1, + parameter ROW_WIDTH = 14, + parameter DDR_TYPE = 1 + ) + ( + input clk0, + input clk90, + input rst0, + input rst90, + input [ROW_WIDTH-1:0] ctrl_addr, + input [BANK_WIDTH-1:0] ctrl_ba, + input ctrl_ras_n, + input ctrl_cas_n, + input ctrl_we_n, + input [CS_NUM-1:0] ctrl_cs_n, + input [ROW_WIDTH-1:0] phy_init_addr, + input [BANK_WIDTH-1:0] phy_init_ba, + input phy_init_ras_n, + input phy_init_cas_n, + input phy_init_we_n, + input [CS_NUM-1:0] phy_init_cs_n, + input [CKE_WIDTH-1:0] phy_init_cke, + input phy_init_data_sel, + input [CS_NUM-1:0] odt, + output [ROW_WIDTH-1:0] ddr_addr, + output [BANK_WIDTH-1:0] ddr_ba, + output ddr_ras_n, + output ddr_cas_n, + output ddr_we_n, + output [CKE_WIDTH-1:0] ddr_cke, + output [CS_WIDTH-1:0] ddr_cs_n, + output [ODT_WIDTH-1:0] ddr_odt + ); + + reg [ROW_WIDTH-1:0] addr_mux; + reg [BANK_WIDTH-1:0] ba_mux; + reg cas_n_mux; + reg [CS_NUM-1:0] cs_n_mux; + reg ras_n_mux; + reg we_n_mux; + + + + //*************************************************************************** + + + + + // MUX to choose from either PHY or controller for SDRAM control + + generate // in 2t timing mode the extra register stage cannot be used. + if(TWO_T_TIME_EN) begin // the control signals are asserted for two cycles + always @(*)begin + if (phy_init_data_sel) begin + addr_mux = ctrl_addr; + ba_mux = ctrl_ba; + cas_n_mux = ctrl_cas_n; + cs_n_mux = ctrl_cs_n; + ras_n_mux = ctrl_ras_n; + we_n_mux = ctrl_we_n; + end else begin + addr_mux = phy_init_addr; + ba_mux = phy_init_ba; + cas_n_mux = phy_init_cas_n; + cs_n_mux = phy_init_cs_n; + ras_n_mux = phy_init_ras_n; + we_n_mux = phy_init_we_n; + end + end + end else begin + always @(posedge clk0)begin // register the signals in non 2t mode + if (phy_init_data_sel) begin + addr_mux <= ctrl_addr; + ba_mux <= ctrl_ba; + cas_n_mux <= ctrl_cas_n; + cs_n_mux <= ctrl_cs_n; + ras_n_mux <= ctrl_ras_n; + we_n_mux <= ctrl_we_n; + end else begin + addr_mux <= phy_init_addr; + ba_mux <= phy_init_ba; + cas_n_mux <= phy_init_cas_n; + cs_n_mux <= phy_init_cs_n; + ras_n_mux <= phy_init_ras_n; + we_n_mux <= phy_init_we_n; + end + end + end + endgenerate + + //*************************************************************************** + // Output flop instantiation + // NOTE: Make sure all control/address flops are placed in IOBs + //*************************************************************************** + + // RAS: = 1 at reset + (* IOB = "FORCE" *) FDCPE u_ff_ras_n + ( + .Q (ddr_ras_n), + .C (clk0), + .CE (1'b1), + .CLR (1'b0), + .D (ras_n_mux), + .PRE (rst0) + ) /* synthesis syn_useioff = 1 */; + + // CAS: = 1 at reset + (* IOB = "FORCE" *) FDCPE u_ff_cas_n + ( + .Q (ddr_cas_n), + .C (clk0), + .CE (1'b1), + .CLR (1'b0), + .D (cas_n_mux), + .PRE (rst0) + ) /* synthesis syn_useioff = 1 */; + + // WE: = 1 at reset + (* IOB = "FORCE" *) FDCPE u_ff_we_n + ( + .Q (ddr_we_n), + .C (clk0), + .CE (1'b1), + .CLR (1'b0), + .D (we_n_mux), + .PRE (rst0) + ) /* synthesis syn_useioff = 1 */; + + // CKE: = 0 at reset + genvar cke_i; + generate + for (cke_i = 0; cke_i < CKE_WIDTH; cke_i = cke_i + 1) begin: gen_cke + (* IOB = "FORCE" *) (* S = "TRUE" *) FDCPE u_ff_cke + ( + .Q (ddr_cke[cke_i]), + .C (clk0), + .CE (1'b1), + .CLR (rst0), + .D (phy_init_cke[cke_i]), + .PRE (1'b0) + ) /* synthesis syn_useioff = 1 */; + end + endgenerate + + // chip select: = 1 at reset + // For unbuffered dimms the loading will be high. The chip select + // can be asserted early if the loading is very high. The + // code as is uses clock 0. If needed clock 270 can be used to + // toggle chip select 1/4 clock cycle early. The code has + // the clock 90 input for the early assertion of chip select. + + genvar cs_i; + generate + for(cs_i = 0; cs_i < CS_WIDTH; cs_i = cs_i + 1) begin: gen_cs_n + if(TWO_T_TIME_EN) begin + (* IOB = "FORCE" *) (* S = "TRUE" *) FDCPE u_ff_cs_n + ( + .Q (ddr_cs_n[cs_i]), + .C (clk0), + .CE (1'b1), + .CLR (1'b0), + .D (cs_n_mux[(cs_i*CS_NUM)/CS_WIDTH]), + .PRE (rst0) + ) /* synthesis syn_useioff = 1 */; + end else begin // if (TWO_T_TIME_EN) + (* IOB = "FORCE" *) (* S = "TRUE" *) FDCPE u_ff_cs_n + ( + .Q (ddr_cs_n[cs_i]), + .C (clk0), + .CE (1'b1), + .CLR (1'b0), + .D (cs_n_mux[(cs_i*CS_NUM)/CS_WIDTH]), + .PRE (rst0) + ) /* synthesis syn_useioff = 1 */; + end // else: !if(TWO_T_TIME_EN) + end + endgenerate + + // address: = X at reset + genvar addr_i; + generate + for (addr_i = 0; addr_i < ROW_WIDTH; addr_i = addr_i + 1) begin: gen_addr + (* IOB = "FORCE" *) FDCPE u_ff_addr + ( + .Q (ddr_addr[addr_i]), + .C (clk0), + .CE (1'b1), + .CLR (1'b0), + .D (addr_mux[addr_i]), + .PRE (1'b0) + ) /* synthesis syn_useioff = 1 */; + end + endgenerate + + // bank address = X at reset + genvar ba_i; + generate + for (ba_i = 0; ba_i < BANK_WIDTH; ba_i = ba_i + 1) begin: gen_ba + (* IOB = "FORCE" *) FDCPE u_ff_ba + ( + .Q (ddr_ba[ba_i]), + .C (clk0), + .CE (1'b1), + .CLR (1'b0), + .D (ba_mux[ba_i]), + .PRE (1'b0) + ) /* synthesis syn_useioff = 1 */; + end + endgenerate + + // ODT control = 0 at reset + genvar odt_i; + generate + if (DDR_TYPE > 0) begin: gen_odt_ddr2 + for (odt_i = 0; odt_i < ODT_WIDTH; odt_i = odt_i + 1) begin: gen_odt + (* IOB = "FORCE" *) (* S = "TRUE" *) FDCPE u_ff_odt + ( + .Q (ddr_odt[odt_i]), + .C (clk0), + .CE (1'b1), + .CLR (rst0), + .D (odt[(odt_i*CS_NUM)/ODT_WIDTH]), + .PRE (1'b0) + ) /* synthesis syn_useioff = 1 */; + end + end + endgenerate + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_calib.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_calib.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_phy_calib.v (revision 3) @@ -0,0 +1,2428 @@ +//***************************************************************************** +// (c) Copyright 2006-2009 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: 3.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_phy_calib.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Thu Aug 10 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module handles calibration after memory initialization. +//Reference: +//Revision History: +// Rev 1.1 - Default statement is added for the CASE statement of +// rdd_mux_sel logic. PK. 03/23/09 +// Rev 1.2 - Change training pattern detected for stage 3 calibration. +// Use 2-bits per DQS group for stage 3 pattern detection. +// RC. 09/21/09 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_phy_calib # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter DQ_WIDTH = 72, + parameter DQ_BITS = 7, + parameter DQ_PER_DQS = 8, + parameter DQS_BITS = 4, + parameter DQS_WIDTH = 9, + parameter ADDITIVE_LAT = 0, + parameter CAS_LAT = 5, + parameter REG_ENABLE = 1, + parameter CLK_PERIOD = 3000, + parameter SIM_ONLY = 0, + parameter DEBUG_EN = 0 + ) + ( + input clk, + input clkdiv, + input rstdiv, + input [3:0] calib_start, + input ctrl_rden, + input phy_init_rden, + input [DQ_WIDTH-1:0] rd_data_rise, + input [DQ_WIDTH-1:0] rd_data_fall, + input calib_ref_done, + output reg [3:0] calib_done, + output reg calib_ref_req, + output [DQS_WIDTH-1:0] calib_rden, + output reg [DQS_WIDTH-1:0] calib_rden_sel, + output reg dlyrst_dq, + output reg [DQ_WIDTH-1:0] dlyce_dq, + output reg [DQ_WIDTH-1:0] dlyinc_dq, + output reg dlyrst_dqs, + output reg [DQS_WIDTH-1:0] dlyce_dqs, + output reg [DQS_WIDTH-1:0] dlyinc_dqs, + output reg [DQS_WIDTH-1:0] dlyrst_gate, + output reg [DQS_WIDTH-1:0] dlyce_gate, + output reg [DQS_WIDTH-1:0] dlyinc_gate, + //(* XIL_PAR_NO_REG_ORDER = "TRUE", XIL_PAR_PATH="Q->u_iodelay_dq_ce.DATAIN", syn_keep = "1", keep = "TRUE"*) + output [DQS_WIDTH-1:0] en_dqs, + output [DQS_WIDTH-1:0] rd_data_sel, + // Debug signals (optional use) + input dbg_idel_up_all, + input dbg_idel_down_all, + input dbg_idel_up_dq, + input dbg_idel_down_dq, + input dbg_idel_up_dqs, + input dbg_idel_down_dqs, + input dbg_idel_up_gate, + input dbg_idel_down_gate, + input [DQ_BITS-1:0] dbg_sel_idel_dq, + input dbg_sel_all_idel_dq, + input [DQS_BITS:0] dbg_sel_idel_dqs, + input dbg_sel_all_idel_dqs, + input [DQS_BITS:0] dbg_sel_idel_gate, + input dbg_sel_all_idel_gate, + output [3:0] dbg_calib_done, + output [3:0] dbg_calib_err, + output [(6*DQ_WIDTH)-1:0] dbg_calib_dq_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_dqs_tap_cnt, + output [(6*DQS_WIDTH)-1:0] dbg_calib_gate_tap_cnt, + output [DQS_WIDTH-1:0] dbg_calib_rd_data_sel, + output [(5*DQS_WIDTH)-1:0] dbg_calib_rden_dly, + output [(5*DQS_WIDTH)-1:0] dbg_calib_gate_dly + ); + + // minimum time (in IDELAY taps) for which capture data must be stable for + // algorithm to consider + localparam MIN_WIN_SIZE = 5; + // IDEL_SET_VAL = (# of cycles - 1) to wait after changing IDELAY value + // we only have to wait enough for input with new IDELAY value to + // propagate through pipeline stages. + localparam IDEL_SET_VAL = 3'b111; + // # of clock cycles to delay read enable to determine if read data pattern + // is correct for stage 3/4 (RDEN, DQS gate) calibration + localparam CALIB_RDEN_PIPE_LEN = 31; + // translate CAS latency into number of clock cycles for read valid delay + // determination. Really only needed for CL = 2.5 (set to 2) + localparam CAS_LAT_RDEN = (CAS_LAT == 25) ? 2 : CAS_LAT; + // an SRL32 is used to delay CTRL_RDEN to generate read valid signal. This + // is min possible value delay through SRL32 can be + localparam RDEN_BASE_DELAY = CAS_LAT_RDEN + ADDITIVE_LAT + REG_ENABLE; + // an SRL32 is used to delay the CTRL_RDEN from the read postamble DQS + // gate. This is min possible value the SRL32 delay can be: + // - Delay from end of deassertion of CTRL_RDEN to last falling edge of + // read burst = 3.5 (CTRL_RDEN -> CAS delay) + 3 (min CAS latency) = 6.5 + // - Minimum time for DQS gate circuit to be generated: + // * 1 cyc to register CTRL_RDEN from controller + // * 1 cyc after RDEN_CTRL falling edge + // * 1 cyc min through SRL32 + // * 1 cyc through SRL32 output flop + // * 0 (<1) cyc of synchronization to DQS domain via IDELAY + // * 1 cyc of delay through IDDR to generate CE to DQ IDDR's + // Total = 5 cyc < 6.5 cycles + // The total should be less than 5.5 cycles to account prop delays + // adding one cycle to the synchronization time via the IDELAY. + // NOTE: Value differs because of optional pipeline register added + // for case of RDEN_BASE_DELAY > 3 to improve timing + localparam GATE_BASE_DELAY = RDEN_BASE_DELAY - 3; + localparam GATE_BASE_INIT = (GATE_BASE_DELAY <= 1) ? 0 : GATE_BASE_DELAY; + // used for RDEN calibration: difference between shift value used during + // calibration, and shift value for actual RDEN SRL. Only applies when + // RDEN edge is immediately captured by CLKDIV0. If not (depends on phase + // of CLK0 and CLKDIV0 when RDEN is asserted), then add 1 to this value. + localparam CAL3_RDEN_SRL_DLY_DELTA = 6; + // fix minimum value of DQS to be 1 to handle the case where's there's only + // one DQS group. We could also enforce that user always inputs minimum + // value of 1 for DQS_BITS (even when DQS_WIDTH=1). Leave this as safeguard + // Assume we don't have to do this for DQ, DQ_WIDTH always > 1 + localparam DQS_BITS_FIX = (DQS_BITS == 0) ? 1 : DQS_BITS; + // how many taps to "pre-delay" DQ before stg 1 calibration - not needed for + // current calibration, but leave for debug + localparam DQ_IDEL_INIT = 6'b000000; + // # IDELAY taps per bit time (i.e. half cycle). Limit to 63. + localparam integer BIT_TIME_TAPS = (CLK_PERIOD/150 < 64) ? + CLK_PERIOD/150 : 63; + + // used in various places during stage 4 cal: (1) determines maximum taps + // to increment when finding right edge, (2) amount to decrement after + // finding left edge, (3) amount to increment after finding right edge + localparam CAL4_IDEL_BIT_VAL = (BIT_TIME_TAPS >= 6'b100000) ? + 6'b100000 : BIT_TIME_TAPS; + + localparam CAL1_IDLE = 4'h0; + localparam CAL1_INIT = 4'h1; + localparam CAL1_INC_IDEL = 4'h2; + localparam CAL1_FIND_FIRST_EDGE = 4'h3; + localparam CAL1_FIRST_EDGE_IDEL_WAIT = 4'h4; + localparam CAL1_FOUND_FIRST_EDGE_WAIT = 4'h5; + localparam CAL1_FIND_SECOND_EDGE = 4'h6; + localparam CAL1_SECOND_EDGE_IDEL_WAIT = 4'h7; + localparam CAL1_CALC_IDEL = 4'h8; + localparam CAL1_DEC_IDEL = 4'h9; + localparam CAL1_DONE = 4'hA; + + localparam CAL2_IDLE = 4'h0; + localparam CAL2_INIT = 4'h1; + localparam CAL2_INIT_IDEL_WAIT = 4'h2; + localparam CAL2_FIND_EDGE_POS = 4'h3; + localparam CAL2_FIND_EDGE_IDEL_WAIT_POS = 4'h4; + localparam CAL2_FIND_EDGE_NEG = 4'h5; + localparam CAL2_FIND_EDGE_IDEL_WAIT_NEG = 4'h6; + localparam CAL2_DEC_IDEL = 4'h7; + localparam CAL2_DONE = 4'h8; + + localparam CAL3_IDLE = 3'h0; + localparam CAL3_INIT = 3'h1; + localparam CAL3_DETECT = 3'h2; + localparam CAL3_RDEN_PIPE_CLR_WAIT = 3'h3; + localparam CAL3_DONE = 3'h4; + + localparam CAL4_IDLE = 3'h0; + localparam CAL4_INIT = 3'h1; + localparam CAL4_FIND_WINDOW = 3'h2; + localparam CAL4_FIND_EDGE = 3'h3; + localparam CAL4_IDEL_WAIT = 3'h4; + localparam CAL4_RDEN_PIPE_CLR_WAIT = 3'h5; + localparam CAL4_ADJ_IDEL = 3'h6; + localparam CAL4_DONE = 3'h7; + + integer i, j; + + reg [5:0] cal1_bit_time_tap_cnt; + reg [1:0] cal1_data_chk_last; + reg cal1_data_chk_last_valid; + reg [1:0] cal1_data_chk_r; + reg cal1_dlyce_dq; + reg cal1_dlyinc_dq; + reg cal1_dqs_dq_init_phase; + reg cal1_detect_edge; + reg cal1_detect_stable; + reg cal1_found_second_edge; + reg cal1_found_rising; + reg cal1_found_window; + reg cal1_first_edge_done; + reg [5:0] cal1_first_edge_tap_cnt; + reg [6:0] cal1_idel_dec_cnt; + reg [5:0] cal1_idel_inc_cnt; + reg [5:0] cal1_idel_max_tap; + reg cal1_idel_max_tap_we; + reg [5:0] cal1_idel_tap_cnt; + reg cal1_idel_tap_limit_hit; + reg [6:0] cal1_low_freq_idel_dec; + reg cal1_ref_req; + wire cal1_refresh; + reg [3:0] cal1_state; + reg [3:0] cal1_window_cnt; + reg cal2_curr_sel; + wire cal2_detect_edge; + reg cal2_dlyce_dqs; + reg cal2_dlyinc_dqs; + reg [5:0] cal2_idel_dec_cnt; + reg [5:0] cal2_idel_tap_cnt; + reg [5:0] cal2_idel_tap_limit; + reg cal2_idel_tap_limit_hit; + reg cal2_rd_data_fall_last_neg; + reg cal2_rd_data_fall_last_pos; + reg cal2_rd_data_last_valid_neg; + reg cal2_rd_data_last_valid_pos; + reg cal2_rd_data_rise_last_neg; + reg cal2_rd_data_rise_last_pos; + reg [DQS_WIDTH-1:0] cal2_rd_data_sel; + wire cal2_rd_data_sel_edge; + reg [DQS_WIDTH-1:0] cal2_rd_data_sel_r; + reg cal2_ref_req; + reg [3:0] cal2_state; + reg cal3_data_match; + reg cal3_data_match_stgd; + wire cal3_data_valid; + wire cal3_match_found; + wire [4:0] cal3_rden_dly; + reg [4:0] cal3_rden_srl_a; + reg [2:0] cal3_state; + wire cal4_data_good; + reg cal4_data_match; + reg cal4_data_match_stgd; + wire cal4_data_valid; + reg cal4_dlyce_gate; + reg cal4_dlyinc_gate; + reg cal4_dlyrst_gate; + reg [4:0] cal4_gate_srl_a; + reg [5:0] cal4_idel_adj_cnt; + reg cal4_idel_adj_inc; + reg cal4_idel_bit_tap; + reg [5:0] cal4_idel_tap_cnt; + reg cal4_idel_max_tap; + reg [4:0] cal4_rden_srl_a; + reg cal4_ref_req; + reg cal4_seek_left; + reg cal4_stable_window; + reg [2:0] cal4_state; + reg [3:0] cal4_window_cnt; + reg [3:0] calib_done_tmp; // only for stg1/2/4 + reg calib_ctrl_gate_pulse_r; + reg calib_ctrl_rden; + reg calib_ctrl_rden_r; + wire calib_ctrl_rden_negedge; + reg calib_ctrl_rden_negedge_r; + reg [3:0] calib_done_r; + reg [3:0] calib_err; + reg [1:0] calib_err_2; + wire calib_init_gate_pulse; + reg calib_init_gate_pulse_r; + reg calib_init_gate_pulse_r1; + reg calib_init_rden; + reg calib_init_rden_r; + reg [4:0] calib_rden_srl_a; + wire [4:0] calib_rden_srl_a_r; + reg [(5*DQS_WIDTH)-1:0] calib_rden_dly; + reg calib_rden_edge_r; + reg [4:0] calib_rden_pipe_cnt; + wire calib_rden_srl_out; + wire calib_rden_srl_out_r; + reg calib_rden_srl_out_r1; + reg calib_rden_valid; + reg calib_rden_valid_stgd; + reg [DQ_BITS-1:0] count_dq; + reg [DQS_BITS_FIX-1:0] count_dqs; + reg [DQS_BITS_FIX-1:0] count_gate; + reg [DQS_BITS_FIX-1:0] count_rden; + reg ctrl_rden_r; + wire dlyce_or; + reg [(5*DQS_WIDTH)-1:0] gate_dly; + wire [(5*DQS_WIDTH)-1:0] gate_dly_r; + wire gate_srl_in; + wire [DQS_WIDTH-1:0] gate_srl_out; + wire [DQS_WIDTH-1:0] gate_srl_out_r; + reg [2:0] idel_set_cnt; + wire idel_set_wait; + reg [DQ_BITS-1:0] next_count_dq; + reg [DQS_BITS_FIX-1:0] next_count_dqs; + reg [DQS_BITS_FIX-1:0] next_count_gate; + reg phy_init_rden_r; + reg phy_init_rden_r1; + reg [DQS_WIDTH-1:0] rd_data_fall_1x_bit1_r1; + reg [DQ_WIDTH-1:0] rd_data_fall_1x_r; + reg [DQS_WIDTH-1:0] rd_data_fall_1x_r1; + reg [DQS_WIDTH-1:0] rd_data_fall_2x_bit1_r; + reg [DQS_WIDTH-1:0] rd_data_fall_2x_r; + wire [DQS_WIDTH-1:0] rd_data_fall_chk_q1; + wire [DQS_WIDTH-1:0] rd_data_fall_chk_q1_bit1; + wire [DQS_WIDTH-1:0] rd_data_fall_chk_q2; + wire [DQS_WIDTH-1:0] rd_data_fall_chk_q2_bit1; + reg [DQS_WIDTH-1:0] rd_data_rise_1x_bit1_r1; + reg [DQ_WIDTH-1:0] rd_data_rise_1x_r; + reg [DQS_WIDTH-1:0] rd_data_rise_1x_r1; + reg [DQS_WIDTH-1:0] rd_data_rise_2x_bit1_r; + reg [DQS_WIDTH-1:0] rd_data_rise_2x_r; + wire [DQS_WIDTH-1:0] rd_data_rise_chk_q1; + wire [DQS_WIDTH-1:0] rd_data_rise_chk_q1_bit1; + wire [DQS_WIDTH-1:0] rd_data_rise_chk_q2; + wire [DQS_WIDTH-1:0] rd_data_rise_chk_q2_bit1; + reg rdd_fall_q1; + reg rdd_fall_q1_bit1; + reg rdd_fall_q1_bit1_r; + reg rdd_fall_q1_bit1_r1; + reg rdd_fall_q1_r; + reg rdd_fall_q1_r1; + reg rdd_fall_q2; + reg rdd_fall_q2_bit1; + reg rdd_fall_q2_bit1_r; + reg rdd_fall_q2_r; + reg rdd_rise_q1; + reg rdd_rise_q1_bit1; + reg rdd_rise_q1_bit1_r; + reg rdd_rise_q1_bit1_r1; + reg rdd_rise_q1_r; + reg rdd_rise_q1_r1; + reg rdd_rise_q2; + reg rdd_rise_q2_bit1; + reg rdd_rise_q2_bit1_r; + reg rdd_rise_q2_r; + reg [DQS_BITS_FIX-1:0] rdd_mux_sel; + reg rden_dec; + reg [(5*DQS_WIDTH)-1:0] rden_dly; + wire [(5*DQS_WIDTH)-1:0] rden_dly_r; + reg [4:0] rden_dly_0; + reg rden_inc; + reg [DQS_WIDTH-1:0] rden_mux; + wire [DQS_WIDTH-1:0] rden_srl_out; + + // Debug + integer x; + reg [5:0] dbg_dq_tap_cnt [DQ_WIDTH-1:0]; + reg [5:0] dbg_dqs_tap_cnt [DQS_WIDTH-1:0]; + reg [5:0] dbg_gate_tap_cnt [DQS_WIDTH-1:0]; + + //*************************************************************************** + // Debug output ("dbg_phy_calib_*") + // NOTES: + // 1. All debug outputs coming out of PHY_CALIB are clocked off CLKDIV0, + // although they are also static after calibration is complete. This + // means the user can either connect them to a Chipscope ILA, or to + // either a sync/async VIO input block. Using an async VIO has the + // advantage of not requiring these paths to meet cycle-to-cycle timing. + // 2. The widths of most of these debug buses are dependent on the # of + // DQS/DQ bits (e.g. dq_tap_cnt width = 6 * (# of DQ bits) + // SIGNAL DESCRIPTION: + // 1. calib_done: 4 bits - each one asserted as each phase of calibration + // is completed. + // 2. calib_err: 4 bits - each one asserted when a calibration error + // encountered for that stage. Some of these bits may not + // be used (not all cal stages report an error). + // 3. dq_tap_cnt: final IDELAY tap counts for all DQ IDELAYs + // 4. dqs_tap_cnt: final IDELAY tap counts for all DQS IDELAYs + // 5. gate_tap_cnt: final IDELAY tap counts for all DQS gate + // synchronization IDELAYs + // 6. rd_data_sel: final read capture MUX (either "positive" or "negative" + // edge capture) settings for all DQS groups + // 7. rden_dly: related to # of cycles after issuing a read until when + // read data is valid - for all DQS groups + // 8. gate_dly: related to # of cycles after issuing a read until when + // clock enable for all DQ's is deasserted to prevent + // effect of DQS postamble glitch - for all DQS groups + //*************************************************************************** + + //***************************************************************** + // Record IDELAY tap values by "snooping" IDELAY control signals + //***************************************************************** + + // record DQ IDELAY tap values + genvar dbg_dq_tc_i; + generate + for (dbg_dq_tc_i = 0; dbg_dq_tc_i < DQ_WIDTH; + dbg_dq_tc_i = dbg_dq_tc_i + 1) begin: gen_dbg_dq_tap_cnt + assign dbg_calib_dq_tap_cnt[(6*dbg_dq_tc_i)+5:(6*dbg_dq_tc_i)] + = dbg_dq_tap_cnt[dbg_dq_tc_i]; + always @(posedge clkdiv) + if (rstdiv | dlyrst_dq) + dbg_dq_tap_cnt[dbg_dq_tc_i] <= 6'b000000; + else + if (dlyce_dq[dbg_dq_tc_i]) + if (dlyinc_dq[dbg_dq_tc_i]) + dbg_dq_tap_cnt[dbg_dq_tc_i] + <= dbg_dq_tap_cnt[dbg_dq_tc_i] + 1; + else + dbg_dq_tap_cnt[dbg_dq_tc_i] + <= dbg_dq_tap_cnt[dbg_dq_tc_i] - 1; + end + endgenerate + + // record DQS IDELAY tap values + genvar dbg_dqs_tc_i; + generate + for (dbg_dqs_tc_i = 0; dbg_dqs_tc_i < DQS_WIDTH; + dbg_dqs_tc_i = dbg_dqs_tc_i + 1) begin: gen_dbg_dqs_tap_cnt + assign dbg_calib_dqs_tap_cnt[(6*dbg_dqs_tc_i)+5:(6*dbg_dqs_tc_i)] + = dbg_dqs_tap_cnt[dbg_dqs_tc_i]; + always @(posedge clkdiv) + if (rstdiv | dlyrst_dqs) + dbg_dqs_tap_cnt[dbg_dqs_tc_i] <= 6'b000000; + else + if (dlyce_dqs[dbg_dqs_tc_i]) + if (dlyinc_dqs[dbg_dqs_tc_i]) + dbg_dqs_tap_cnt[dbg_dqs_tc_i] + <= dbg_dqs_tap_cnt[dbg_dqs_tc_i] + 1; + else + dbg_dqs_tap_cnt[dbg_dqs_tc_i] + <= dbg_dqs_tap_cnt[dbg_dqs_tc_i] - 1; + end + endgenerate + + // record DQS gate IDELAY tap values + genvar dbg_gate_tc_i; + generate + for (dbg_gate_tc_i = 0; dbg_gate_tc_i < DQS_WIDTH; + dbg_gate_tc_i = dbg_gate_tc_i + 1) begin: gen_dbg_gate_tap_cnt + assign dbg_calib_gate_tap_cnt[(6*dbg_gate_tc_i)+5:(6*dbg_gate_tc_i)] + = dbg_gate_tap_cnt[dbg_gate_tc_i]; + always @(posedge clkdiv) + if (rstdiv | dlyrst_gate[dbg_gate_tc_i]) + dbg_gate_tap_cnt[dbg_gate_tc_i] <= 6'b000000; + else + if (dlyce_gate[dbg_gate_tc_i]) + if (dlyinc_gate[dbg_gate_tc_i]) + dbg_gate_tap_cnt[dbg_gate_tc_i] + <= dbg_gate_tap_cnt[dbg_gate_tc_i] + 1; + else + dbg_gate_tap_cnt[dbg_gate_tc_i] + <= dbg_gate_tap_cnt[dbg_gate_tc_i] - 1; + end + endgenerate + + assign dbg_calib_done = calib_done; + assign dbg_calib_err = calib_err; + assign dbg_calib_rd_data_sel = cal2_rd_data_sel; + assign dbg_calib_rden_dly = rden_dly; + assign dbg_calib_gate_dly = gate_dly; + + //*************************************************************************** + // Read data pipelining, and read data "ISERDES" data width expansion + //*************************************************************************** + + // For all data bits, register incoming capture data to slow clock to improve + // timing. Adding single pipeline stage does not affect functionality (as + // long as we make sure to wait extra clock cycle after changing DQ IDELAY) + // Also note in this case that we're "missing" every other clock cycle's + // worth of data capture since we're sync'ing to the slow clock. This is + // fine for stage 1 and stage 2 cal, but not for stage 3 and 4 (see below + // for different circuit to handle those stages) + always @(posedge clkdiv) begin + rd_data_rise_1x_r <= rd_data_rise; + rd_data_fall_1x_r <= rd_data_fall; + end + + // For every DQ_PER_DQS bit, generate what is essentially a ISERDES-type + // data width expander. Will need this for stage 3 and 4 cal, where we need + // to compare data over consecutive clock cycles. We can also use this for + // stage 2 as well (stage 2 doesn't require every bit to be looked at, only + // one bit per DQS group) + // MIG 3.3: Expand to use lower two bits of each DQS group - use for stage + // 3 calibration for added robustness, since we will be checking for the + // training pattern from the memory even when the data bus is 3-stated. + // Theoretically it is possible for whatever garbage data is on the bus + // to be interpreted as the training sequence, although this can be made + // very unlikely by the choice of training sequence (bit sequence, length) + // and the number of bits compared for each DQS group. + genvar rdd_i; + generate + for (rdd_i = 0; rdd_i < DQS_WIDTH; rdd_i = rdd_i + 1) begin: gen_rdd + // first stage: keep data in fast clk domain. Store data over two + // consecutive clock cycles for rise/fall data for proper transfer + // to slow clock domain + always @(posedge clk) begin + rd_data_rise_2x_r[rdd_i] <= rd_data_rise[(rdd_i*DQ_PER_DQS)]; + rd_data_fall_2x_r[rdd_i] <= rd_data_fall[(rdd_i*DQ_PER_DQS)]; + rd_data_rise_2x_bit1_r[rdd_i] <= rd_data_rise[(rdd_i*DQ_PER_DQS)+1]; + rd_data_fall_2x_bit1_r[rdd_i] <= rd_data_fall[(rdd_i*DQ_PER_DQS)+1]; + end + // second stage, register first stage to slow clock domain, 2nd stage + // consists of both these flops, and the rd_data_rise_1x_r flops + always @(posedge clkdiv) begin + rd_data_rise_1x_r1[rdd_i] <= rd_data_rise_2x_r[rdd_i]; + rd_data_fall_1x_r1[rdd_i] <= rd_data_fall_2x_r[rdd_i]; + rd_data_rise_1x_bit1_r1[rdd_i] <= rd_data_rise_2x_bit1_r[rdd_i]; + rd_data_fall_1x_bit1_r1[rdd_i] <= rd_data_fall_2x_bit1_r[rdd_i]; + end + // now we have four outputs - representing rise/fall outputs over last + // 2 fast clock cycles. However, the ordering these represent can either + // be: (1) Q2 = data @ time = n, Q1 = data @ time = n+1, or (2) + // Q2 = data @ time = n - 1, Q1 = data @ time = n (and data at [Q1,Q2] + // is "staggered") - leave it up to the stage of calibration using this + // to figure out which is which, if they care at all (e.g. stage 2 cal + // doesn't care about the ordering) + assign rd_data_rise_chk_q1[rdd_i] + = rd_data_rise_1x_r[(rdd_i*DQ_PER_DQS)]; + assign rd_data_rise_chk_q2[rdd_i] + = rd_data_rise_1x_r1[rdd_i]; + assign rd_data_fall_chk_q1[rdd_i] + = rd_data_fall_1x_r[(rdd_i*DQ_PER_DQS)]; + assign rd_data_fall_chk_q2[rdd_i] + = rd_data_fall_1x_r1[rdd_i]; + // MIG 3.3: Added comparison for second bit in DQS group for stage 3 cal + assign rd_data_rise_chk_q1_bit1[rdd_i] + = rd_data_rise_1x_r[(rdd_i*DQ_PER_DQS)+1]; + assign rd_data_rise_chk_q2_bit1[rdd_i] + = rd_data_rise_1x_bit1_r1[rdd_i]; + assign rd_data_fall_chk_q1_bit1[rdd_i] + = rd_data_fall_1x_r[(rdd_i*DQ_PER_DQS)+1]; + assign rd_data_fall_chk_q2_bit1[rdd_i] + = rd_data_fall_1x_bit1_r1[rdd_i]; + end + endgenerate + + //***************************************************************** + // Outputs of these simplified ISERDES circuits then feed MUXes based on + // which DQ the current calibration algorithm needs to look at + //***************************************************************** + + // generate MUX control; assume that adding an extra pipeline stage isn't + // an issue - whatever stage cal logic is using output of MUX will wait + // enough time after changing it + always @(posedge clkdiv) begin + (* full_case, parallel_case *) case (calib_done[2:0]) + 3'b001: rdd_mux_sel <= next_count_dqs; + 3'b011: rdd_mux_sel <= count_rden; + 3'b111: rdd_mux_sel <= next_count_gate; + default: rdd_mux_sel <= {DQS_BITS_FIX{1'bx}}; + endcase + end + + always @(posedge clkdiv) begin + rdd_rise_q1 <= rd_data_rise_chk_q1[rdd_mux_sel]; + rdd_rise_q2 <= rd_data_rise_chk_q2[rdd_mux_sel]; + rdd_fall_q1 <= rd_data_fall_chk_q1[rdd_mux_sel]; + rdd_fall_q2 <= rd_data_fall_chk_q2[rdd_mux_sel]; + rdd_rise_q1_bit1 <= rd_data_rise_chk_q1_bit1[rdd_mux_sel]; + rdd_rise_q2_bit1 <= rd_data_rise_chk_q2_bit1[rdd_mux_sel]; + rdd_fall_q1_bit1 <= rd_data_fall_chk_q1_bit1[rdd_mux_sel]; + rdd_fall_q2_bit1 <= rd_data_fall_chk_q2_bit1[rdd_mux_sel]; + end + + //*************************************************************************** + // Demultiplexor to control (reset, increment, decrement) IDELAY tap values + // For DQ: + // STG1: for per-bit-deskew, only inc/dec the current DQ. For non-per + // deskew, increment all bits in the current DQS set + // STG2: inc/dec all DQ's in the current DQS set. + // NOTE: Nice to add some error checking logic here (or elsewhere in the + // code) to check if logic attempts to overflow tap value + //*************************************************************************** + + // don't use DLYRST to reset value of IDELAY after reset. Need to change this + // if we want to allow user to recalibrate after initial reset + always @(posedge clkdiv) + if (rstdiv) begin + dlyrst_dq <= 1'b1; + dlyrst_dqs <= 1'b1; + end else begin + dlyrst_dq <= 1'b0; + dlyrst_dqs <= 1'b0; + end + + always @(posedge clkdiv) begin + if (rstdiv) begin + dlyce_dq <= 'b0; + dlyinc_dq <= 'b0; + dlyce_dqs <= 'b0; + dlyinc_dqs <= 'b0; + end else begin + dlyce_dq <= 'b0; + dlyinc_dq <= 'b0; + dlyce_dqs <= 'b0; + dlyinc_dqs <= 'b0; + + // stage 1 cal: change only specified DQ + if (cal1_dlyce_dq) begin + if (SIM_ONLY == 0) begin + dlyce_dq[count_dq] <= 1'b1; + dlyinc_dq[count_dq] <= cal1_dlyinc_dq; + end else begin + // if simulation, then calibrate only first DQ, apply results + // to all DQs (i.e. assume delay on all DQs is the same) + for (i = 0; i < DQ_WIDTH; i = i + 1) begin: loop_sim_dq_dly + dlyce_dq[i] <= 1'b1; + dlyinc_dq[i] <= cal1_dlyinc_dq; + end + end + end else if (cal2_dlyce_dqs) begin + // stage 2 cal: change DQS and all corresponding DQ's + if (SIM_ONLY == 0) begin + dlyce_dqs[count_dqs] <= 1'b1; + dlyinc_dqs[count_dqs] <= cal2_dlyinc_dqs; + for (i = 0; i < DQ_PER_DQS; i = i + 1) begin: loop_dqs_dly + dlyce_dq[(DQ_PER_DQS*count_dqs)+i] <= 1'b1; + dlyinc_dq[(DQ_PER_DQS*count_dqs)+i] <= cal2_dlyinc_dqs; + end + end else begin + for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_dqs_dly + // if simulation, then calibrate only first DQS + dlyce_dqs[i] <= 1'b1; + dlyinc_dqs[i] <= cal2_dlyinc_dqs; + for (j = 0; j < DQ_PER_DQS; j = j + 1) begin: loop_sim_dq_dqs_dly + dlyce_dq[(DQ_PER_DQS*i)+j] <= 1'b1; + dlyinc_dq[(DQ_PER_DQS*i)+j] <= cal2_dlyinc_dqs; + end + end + end + end else if (DEBUG_EN != 0) begin + // DEBUG: allow user to vary IDELAY tap settings + // For DQ IDELAY taps + if (dbg_idel_up_all || dbg_idel_down_all || + dbg_sel_all_idel_dq) begin + for (x = 0; x < DQ_WIDTH; x = x + 1) begin: loop_dly_inc_dq + dlyce_dq[x] <= dbg_idel_up_all | dbg_idel_down_all | + dbg_idel_up_dq | dbg_idel_down_dq; + dlyinc_dq[x] <= dbg_idel_up_all | dbg_idel_up_dq; + end + end else begin + dlyce_dq <= 'b0; + dlyce_dq[dbg_sel_idel_dq] <= dbg_idel_up_dq | + dbg_idel_down_dq; + dlyinc_dq[dbg_sel_idel_dq] <= dbg_idel_up_dq; + end + // For DQS IDELAY taps + if (dbg_idel_up_all || dbg_idel_down_all || + dbg_sel_all_idel_dqs) begin + for (x = 0; x < DQS_WIDTH; x = x + 1) begin: loop_dly_inc_dqs + dlyce_dqs[x] <= dbg_idel_up_all | dbg_idel_down_all | + dbg_idel_up_dqs | dbg_idel_down_dqs; + dlyinc_dqs[x] <= dbg_idel_up_all | dbg_idel_up_dqs; + end + end else begin + dlyce_dqs <= 'b0; + dlyce_dqs[dbg_sel_idel_dqs] <= dbg_idel_up_dqs | + dbg_idel_down_dqs; + dlyinc_dqs[dbg_sel_idel_dqs] <= dbg_idel_up_dqs; + end + end + end + end + + // GATE synchronization is handled directly by Stage 4 calibration FSM + always @(posedge clkdiv) + if (rstdiv) begin + dlyrst_gate <= {DQS_WIDTH{1'b1}}; + dlyce_gate <= {DQS_WIDTH{1'b0}}; + dlyinc_gate <= {DQS_WIDTH{1'b0}}; + end else begin + dlyrst_gate <= {DQS_WIDTH{1'b0}}; + dlyce_gate <= {DQS_WIDTH{1'b0}}; + dlyinc_gate <= {DQS_WIDTH{1'b0}}; + + if (cal4_dlyrst_gate) begin + if (SIM_ONLY == 0) + dlyrst_gate[count_gate] <= 1'b1; + else + for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_gate_sim_dly_rst + dlyrst_gate[i] <= 1'b1; + end + end + + if (cal4_dlyce_gate) begin + if (SIM_ONLY == 0) begin + dlyce_gate[count_gate] <= 1'b1; + dlyinc_gate[count_gate] <= cal4_dlyinc_gate; + end else begin + // if simulation, then calibrate only first gate + for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_gate_sim_dly + dlyce_gate[i] <= 1'b1; + dlyinc_gate[i] <= cal4_dlyinc_gate; + end + end + end else if (DEBUG_EN != 0) begin + // DEBUG: allow user to vary IDELAY tap settings + if (dbg_idel_up_all || dbg_idel_down_all || + dbg_sel_all_idel_gate) begin + for (x = 0; x < DQS_WIDTH; x = x + 1) begin: loop_dly_inc_gate + dlyce_gate[x] <= dbg_idel_up_all | dbg_idel_down_all | + dbg_idel_up_gate | dbg_idel_down_gate; + dlyinc_gate[x] <= dbg_idel_up_all | dbg_idel_up_gate; + end + end else begin + dlyce_gate <= {DQS_WIDTH{1'b0}}; + dlyce_gate[dbg_sel_idel_gate] <= dbg_idel_up_gate | + dbg_idel_down_gate; + dlyinc_gate[dbg_sel_idel_gate] <= dbg_idel_up_gate; + end + end + end + + //*************************************************************************** + // signal to tell calibration state machines to wait and give IDELAY time to + // settle after it's value is changed (both time for IDELAY chain to settle, + // and for settled output to propagate through ISERDES). For general use: use + // for any calibration state machines that modify any IDELAY. + // Should give at least enough time for IDELAY output to settle (technically + // for V5, this should be "glitchless" when IDELAY taps are changed, so don't + // need any time here), and also time for new data to propagate through both + // ISERDES and the "RDD" MUX + associated pipelining + // For now, give very "generous" delay - doesn't really matter since only + // needed during calibration + //*************************************************************************** + + // determine if calibration polarity has changed + always @(posedge clkdiv) + cal2_rd_data_sel_r <= cal2_rd_data_sel; + + assign cal2_rd_data_sel_edge = |(cal2_rd_data_sel ^ cal2_rd_data_sel_r); + + // combine requests to modify any of the IDELAYs into one. Also when second + // stage capture "edge" polarity is changed (IDELAY isn't changed in this + // case, but use the same counter to stall cal logic) + assign dlyce_or = cal1_dlyce_dq | + cal2_dlyce_dqs | + cal2_rd_data_sel_edge | + cal4_dlyce_gate | + cal4_dlyrst_gate; + + // SYN_NOTE: Can later recode to avoid combinational path + assign idel_set_wait = dlyce_or || (idel_set_cnt != IDEL_SET_VAL); + + always @(posedge clkdiv) + if (rstdiv) + idel_set_cnt <= 4'b0000; + else if (dlyce_or) + idel_set_cnt <= 4'b0000; + else if (idel_set_cnt != IDEL_SET_VAL) + idel_set_cnt <= idel_set_cnt + 1; + + // generate request to PHY_INIT logic to issue auto-refresh + // used by certain states to force prech/auto-refresh part way through + // calibration to avoid a tRAS violation (which will happen if that + // stage of calibration lasts long enough). This signal must meet the + // following requirements: (1) only transition from 0->1 when the refresh + // request is needed, (2) stay at 1 and only transition 1->0 when + // CALIB_REF_DONE is asserted + always @(posedge clkdiv) + if (rstdiv) + calib_ref_req <= 1'b0; + else + calib_ref_req <= cal1_ref_req | cal2_ref_req | cal4_ref_req; + + // stage 1 calibration requests auto-refresh every 4 bits + generate + if (DQ_BITS < 2) begin: gen_cal1_refresh_dq_lte4 + assign cal1_refresh = 1'b0; + end else begin: gen_cal1_refresh_dq_gt4 + assign cal1_refresh = (next_count_dq[1:0] == 2'b00); + end + endgenerate + + //*************************************************************************** + // First stage calibration: DQ-DQS + // Definitions: + // edge: detected when varying IDELAY, and current capture data != prev + // capture data + // valid bit window: detected when current capture data == prev capture + // data for more than half the bit time + // starting conditions for DQS-DQ phase: + // case 1: when DQS starts somewhere in rising edge bit window, or + // on the right edge of the rising bit window. + // case 2: when DQS starts somewhere in falling edge bit window, or + // on the right edge of the falling bit window. + // Algorithm Description: + // 1. Increment DQ IDELAY until we find an edge. + // 2. While we're finding the first edge, note whether a valid bit window + // has been detected before we found an edge. If so, then figure out if + // this is the rising or falling bit window. If rising, then our starting + // DQS-DQ phase is case 1. If falling, then it's case 2. If don't detect + // a valid bit window, then we must have started on the edge of a window. + // Need to wait until later on to decide which case we are. + // - Store FIRST_EDGE IDELAY value + // 3. Now look for second edge. + // 4. While we're finding the second edge, note whether valid bit window + // is detected. If so, then use to, along with results from (2) to figure + // out what the starting case is. If in rising bit window, then we're in + // case 2. If falling, then case 1. + // - Store SECOND_EDGE IDELAY value + // NOTES: + // a. Finding two edges allows us to calculate the bit time (although + // not the "same" bit time polarity - need to investigate this + // more). + // b. If we run out of taps looking for the second edge, then the bit + // time must be too long (>= 2.5ns, and DQS-DQ starting phase must be + // case 1). + // 5. Calculate absolute amount to delay DQ as: + // If second edge found, and case 1: + // - DQ_IDELAY = FIRST_EDGE - 0.5*(SECOND_EDGE - FIRST_EDGE) + // If second edge found, and case 2: + // - DQ_IDELAY = SECOND_EDGE - 0.5*(SECOND_EDGE - FIRST_EDGE) + // If second edge not found, then need to make an approximation on + // how much to shift by (should be okay, because we have more timing + // margin): + // - DQ_IDELAY = FIRST_EDGE - 0.5 * (bit_time) + // NOTE: Does this account for either case 1 or case 2????? + // NOTE: It's also possible even when we find the second edge, that + // to instead just use half the bit time to subtract from either + // FIRST or SECOND_EDGE. Finding the actual bit time (which is + // what (SECOND_EDGE - FIRST_EDGE) is, is slightly more accurate, + // since it takes into account duty cycle distortion. + // 6. Repeat for each DQ in current DQS set. + //*************************************************************************** + + //***************************************************************** + // for first stage calibration - used for checking if DQS is aligned to the + // particular DQ, such that we're in the data valid window. Basically, this + // is one giant MUX. + // = [falling data, rising data] + // = [0, 1] = rising DQS aligned in proper (rising edge) bit window + // = [1, 0] = rising DQS aligned in wrong (falling edge) bit window + // = [0, 0], or [1,1] = in uncertain region between windows + //***************************************************************** + + // SYN_NOTE: May have to split this up into multiple levels - MUX can get + // very wide - as wide as the data bus width + always @(posedge clkdiv) + cal1_data_chk_r <= {rd_data_fall_1x_r[next_count_dq], + rd_data_rise_1x_r[next_count_dq]}; + + //***************************************************************** + // determine when an edge has occurred - when either the current value + // is different from the previous latched value or when the DATA_CHK + // outputs are the same (rare, but indicates that we're at an edge) + // This is only valid when the IDELAY output and propagation of the + // data through the capture flops has had a chance to settle out. + //***************************************************************** + + // write CAL1_DETECT_EDGE and CAL1_DETECT_STABLE in such a way that + // if X's are captured on the bus during functional simulation, that + // the logic will register this as an edge detected. Do this to allow + // use of this HDL with Denali memory models (Denali models drive DQ + // to X's on both edges of the data valid window to simulate jitter) + // This is only done for functional simulation purposes. **Should not** + // make the final synthesized logic more complicated, but it does make + // the HDL harder to understand b/c we have to "phrase" the logic + // slightly differently than when not worrying about X's + always @(*) begin + // no edge found if: (1) we have recorded prev edge, and rise + // data == fall data, (2) we haven't yet recorded prev edge, but + // rise/fall data is equal to either [0,1] or [1,0] (i.e. rise/fall + // data isn't either X's, or [0,0] or [1,1], which indicates we're + // in the middle of an edge, since normally rise != fall data for stg1) + if ((cal1_data_chk_last_valid && + (cal1_data_chk_r == cal1_data_chk_last)) || + (!cal1_data_chk_last_valid && + ((cal1_data_chk_r == 2'b01) || (cal1_data_chk_r == 2'b10)))) + cal1_detect_edge = 1'b0; + else + cal1_detect_edge = 1'b1; + end + + always @(*) begin + // assert if we've found a region where data valid window is stable + // over consecutive IDELAY taps, and either rise/fall = [1,0], or [0,1] + if ((cal1_data_chk_last_valid && + (cal1_data_chk_r == cal1_data_chk_last)) && + ((cal1_data_chk_r == 2'b01) || (cal1_data_chk_r == 2'b10))) + cal1_detect_stable = 1'b1; + else + cal1_detect_stable = 1'b0; + end + + //***************************************************************** + // Find valid window: keep track of how long we've been in the same data + // window. If it's been long enough, then declare that we've found a valid + // window. Also returns whether we found a rising or falling window (only + // valid when found_window is asserted) + //***************************************************************** + + always @(posedge clkdiv) begin + if (cal1_state == CAL1_INIT) begin + cal1_window_cnt <= 4'b0000; + cal1_found_window <= 1'b0; + cal1_found_rising <= 1'bx; + end else if (!cal1_data_chk_last_valid) begin + // if we haven't stored a previous value of CAL1_DATA_CHK (or it got + // invalidated because we detected an edge, and are now looking for the + // second edge), then make sure FOUND_WINDOW deasserted on following + // clock edge (to avoid finding a false window immediately after finding + // an edge). Note that because of jitter, it's possible to not find an + // edge at the end of the IDELAY increment settling time, but to find an + // edge on the next clock cycle (e.g. during CAL1_FIND_FIRST_EDGE) + cal1_window_cnt <= 4'b0000; + cal1_found_window <= 1'b0; + cal1_found_rising <= 1'bx; + end else if (((cal1_state == CAL1_FIRST_EDGE_IDEL_WAIT) || + (cal1_state == CAL1_SECOND_EDGE_IDEL_WAIT)) && + !idel_set_wait) begin + // while finding the first and second edges, see if we can detect a + // stable bit window (occurs over MIN_WIN_SIZE number of taps). If + // so, then we're away from an edge, and can conclusively determine the + // starting DQS-DQ phase. + if (cal1_detect_stable) begin + cal1_window_cnt <= cal1_window_cnt + 1; + if (cal1_window_cnt == MIN_WIN_SIZE-1) begin + cal1_found_window <= 1'b1; + if (cal1_data_chk_r == 2'b01) + cal1_found_rising <= 1'b1; + else + cal1_found_rising <= 1'b0; + end + end else begin + // otherwise, we're not in a data valid window, reset the window + // counter, and indicate we're not currently in window. This should + // happen by design at least once after finding the first edge. + cal1_window_cnt <= 4'b0000; + cal1_found_window <= 1'b0; + cal1_found_rising <= 1'bx; + end + end + end + + //***************************************************************** + // keep track of edge tap counts found, and whether we've + // incremented to the maximum number of taps allowed + //***************************************************************** + + always @(posedge clkdiv) + if (cal1_state == CAL1_INIT) begin + cal1_idel_tap_limit_hit <= 1'b0; + cal1_idel_tap_cnt <= 6'b000000; + end else if (cal1_dlyce_dq) begin + if (cal1_dlyinc_dq) begin + cal1_idel_tap_cnt <= cal1_idel_tap_cnt + 1; + cal1_idel_tap_limit_hit <= (cal1_idel_tap_cnt == 6'b111110); + end else begin + cal1_idel_tap_cnt <= cal1_idel_tap_cnt - 1; + cal1_idel_tap_limit_hit <= 1'b0; + end + end + + //***************************************************************** + // Pipeline for better timing - amount to decrement by if second + // edge not found + //***************************************************************** + // if only one edge found (possible for low frequencies), then: + // 1. Assume starting DQS-DQ phase has DQS in DQ window (aka "case 1") + // 2. We have to decrement by (63 - first_edge_tap_cnt) + (BIT_TIME_TAPS/2) + // (i.e. decrement by 63-first_edge_tap_cnt to get to right edge of + // DQ window. Then decrement again by (BIT_TIME_TAPS/2) to get to center + // of DQ window. + // 3. Clamp the above value at 63 to ensure we don't underflow IDELAY + // (note: clamping happens in the CAL1 state machine) + always @(posedge clkdiv) + cal1_low_freq_idel_dec + <= (7'b0111111 - {1'b0, cal1_first_edge_tap_cnt}) + + (BIT_TIME_TAPS/2); + + //***************************************************************** + // Keep track of max taps used during stage 1, use this to limit + // the number of taps that can be used in stage 2 + //***************************************************************** + + always @(posedge clkdiv) + if (rstdiv) begin + cal1_idel_max_tap <= 6'b000000; + cal1_idel_max_tap_we <= 1'b0; + end else begin + // pipeline latch enable for CAL1_IDEL_MAX_TAP - we have plenty + // of time, tap count gets updated, then dead cycles waiting for + // IDELAY output to settle + cal1_idel_max_tap_we <= (cal1_idel_max_tap < cal1_idel_tap_cnt); + // record maximum # of taps used for stg 1 cal + if ((cal1_state == CAL1_DONE) && cal1_idel_max_tap_we) + cal1_idel_max_tap <= cal1_idel_tap_cnt; + end + + //***************************************************************** + + always @(posedge clkdiv) + if (rstdiv) begin + calib_done[0] <= 1'b0; + calib_done_tmp[0] <= 1'bx; + calib_err[0] <= 1'b0; + count_dq <= {DQ_BITS{1'b0}}; + next_count_dq <= {DQ_BITS{1'b0}}; + cal1_bit_time_tap_cnt <= 6'bxxxxxx; + cal1_data_chk_last <= 2'bxx; + cal1_data_chk_last_valid <= 1'bx; + cal1_dlyce_dq <= 1'b0; + cal1_dlyinc_dq <= 1'b0; + cal1_dqs_dq_init_phase <= 1'bx; + cal1_first_edge_done <= 1'bx; + cal1_found_second_edge <= 1'bx; + cal1_first_edge_tap_cnt <= 6'bxxxxxx; + cal1_idel_dec_cnt <= 7'bxxxxxxx; + cal1_idel_inc_cnt <= 6'bxxxxxx; + cal1_ref_req <= 1'b0; + cal1_state <= CAL1_IDLE; + end else begin + // default values for all "pulse" outputs + cal1_ref_req <= 1'b0; + cal1_dlyce_dq <= 1'b0; + cal1_dlyinc_dq <= 1'b0; + + case (cal1_state) + CAL1_IDLE: begin + count_dq <= {DQ_BITS{1'b0}}; + next_count_dq <= {DQ_BITS{1'b0}}; + if (calib_start[0]) begin + calib_done[0] <= 1'b0; + calib_done_tmp[0] <= 1'b0; + cal1_state <= CAL1_INIT; + end + end + + CAL1_INIT: begin + cal1_data_chk_last_valid <= 1'b0; + cal1_found_second_edge <= 1'b0; + cal1_dqs_dq_init_phase <= 1'b0; + cal1_idel_inc_cnt <= 6'b000000; + cal1_state <= CAL1_INC_IDEL; + end + + // increment DQ IDELAY so that either: (1) DQS starts somewhere in + // first rising DQ window, or (2) DQS starts in first falling DQ + // window. The amount to shift is frequency dependent (and is either + // precalculated by MIG or possibly adjusted by the user) + CAL1_INC_IDEL: + if ((cal1_idel_inc_cnt == DQ_IDEL_INIT) && !idel_set_wait) begin + cal1_state <= CAL1_FIND_FIRST_EDGE; + end else if (cal1_idel_inc_cnt != DQ_IDEL_INIT) begin + cal1_idel_inc_cnt <= cal1_idel_inc_cnt + 1; + cal1_dlyce_dq <= 1'b1; + cal1_dlyinc_dq <= 1'b1; + end + + // look for first edge + CAL1_FIND_FIRST_EDGE: begin + // Determine DQS-DQ phase if we can detect enough of a valid window + if (cal1_found_window) + cal1_dqs_dq_init_phase <= ~cal1_found_rising; + // find first edge - if found then record position + if (cal1_detect_edge) begin + cal1_state <= CAL1_FOUND_FIRST_EDGE_WAIT; + cal1_first_edge_done <= 1'b0; + cal1_first_edge_tap_cnt <= cal1_idel_tap_cnt; + cal1_data_chk_last_valid <= 1'b0; + end else begin + // otherwise, store the current value of DATA_CHK, increment + // DQ IDELAY, and compare again + cal1_state <= CAL1_FIRST_EDGE_IDEL_WAIT; + cal1_data_chk_last <= cal1_data_chk_r; + // avoid comparing against DATA_CHK_LAST for previous iteration + cal1_data_chk_last_valid <= 1'b1; + cal1_dlyce_dq <= 1'b1; + cal1_dlyinc_dq <= 1'b1; + end + end + + // wait for DQ IDELAY to settle + CAL1_FIRST_EDGE_IDEL_WAIT: + if (!idel_set_wait) + cal1_state <= CAL1_FIND_FIRST_EDGE; + + // delay state between finding first edge and looking for second + // edge. Necessary in order to invalidate CAL1_FOUND_WINDOW before + // starting to look for second edge + CAL1_FOUND_FIRST_EDGE_WAIT: + cal1_state <= CAL1_FIND_SECOND_EDGE; + + // Try and find second edge + CAL1_FIND_SECOND_EDGE: begin + // When looking for 2nd edge, first make sure data stabilized (by + // detecting valid data window) - needed to avoid false edges + if (cal1_found_window) begin + cal1_first_edge_done <= 1'b1; + cal1_dqs_dq_init_phase <= cal1_found_rising; + end + // exit if run out of taps to increment + if (cal1_idel_tap_limit_hit) + cal1_state <= CAL1_CALC_IDEL; + else begin + // found second edge, record the current edge count + if (cal1_first_edge_done && cal1_detect_edge) begin + cal1_state <= CAL1_CALC_IDEL; + cal1_found_second_edge <= 1'b1; + cal1_bit_time_tap_cnt <= cal1_idel_tap_cnt - + cal1_first_edge_tap_cnt + 1; + end else begin + cal1_state <= CAL1_SECOND_EDGE_IDEL_WAIT; + cal1_data_chk_last <= cal1_data_chk_r; + cal1_data_chk_last_valid <= 1'b1; + cal1_dlyce_dq <= 1'b1; + cal1_dlyinc_dq <= 1'b1; + end + end + end + + // wait for DQ IDELAY to settle, then store ISERDES output + CAL1_SECOND_EDGE_IDEL_WAIT: + if (!idel_set_wait) + cal1_state <= CAL1_FIND_SECOND_EDGE; + + // pipeline delay state to calculate amount to decrement DQ IDELAY + // NOTE: We're calculating the amount to decrement by, not the + // absolute setting for DQ IDELAY + CAL1_CALC_IDEL: begin + // if two edges found + if (cal1_found_second_edge) + // case 1: DQS was in DQ window to start with. First edge found + // corresponds to left edge of DQ rising window. Backup by 1.5*BT + // NOTE: In this particular case, it is possible to decrement + // "below 0" in the case where DQS delay is less than 0.5*BT, + // need to limit decrement to prevent IDELAY tap underflow + if (!cal1_dqs_dq_init_phase) + cal1_idel_dec_cnt <= {1'b0, cal1_bit_time_tap_cnt} + + {1'b0, (cal1_bit_time_tap_cnt >> 1)}; + // case 2: DQS was in wrong DQ window (in DQ falling window). + // First edge found is right edge of DQ rising window. Second + // edge is left edge of DQ rising window. Backup by 0.5*BT + else + cal1_idel_dec_cnt <= {1'b0, (cal1_bit_time_tap_cnt >> 1)}; + // if only one edge found - assume will always be case 1 - DQS in + // DQS window. Case 2 only possible if path delay on DQS > 5ns + else + cal1_idel_dec_cnt <= cal1_low_freq_idel_dec; + cal1_state <= CAL1_DEC_IDEL; + end + + // decrement DQ IDELAY for final adjustment + CAL1_DEC_IDEL: + // once adjustment is complete, we're done with calibration for + // this DQ, now return to IDLE state and repeat for next DQ + // Add underflow protection for case of 2 edges found and DQS + // starting in DQ window (see comments for above state) - note we + // have to take into account delayed value of CAL1_IDEL_TAP_CNT - + // gets updated one clock cycle after CAL1_DLYCE/INC_DQ + if ((cal1_idel_dec_cnt == 7'b0000000) || + (cal1_dlyce_dq && (cal1_idel_tap_cnt == 6'b000001))) begin + cal1_state <= CAL1_DONE; + // stop when all DQ's calibrated, or DQ[0] cal'ed (for sim) + if ((count_dq == DQ_WIDTH-1) || (SIM_ONLY != 0)) + calib_done_tmp[0] <= 1'b1; + else + // need for VHDL simulation to prevent out-of-index error + next_count_dq <= count_dq + 1; + end else begin + // keep decrementing until final tap count reached + cal1_idel_dec_cnt <= cal1_idel_dec_cnt - 1; + cal1_dlyce_dq <= 1'b1; + cal1_dlyinc_dq <= 1'b0; + end + + // delay state to allow count_dq and DATA_CHK to point to the next + // DQ bit (allows us to potentially begin checking for an edge on + // next DQ right away). + CAL1_DONE: + if (!idel_set_wait) begin + count_dq <= next_count_dq; + if (calib_done_tmp[0]) begin + calib_done[0] <= 1'b1; + cal1_state <= CAL1_IDLE; + end else begin + // request auto-refresh after every 8-bits calibrated to + // avoid tRAS violation + if (cal1_refresh) begin + cal1_ref_req <= 1'b1; + if (calib_ref_done) + cal1_state <= CAL1_INIT; + end else + // if no need this time for refresh, proceed to next bit + cal1_state <= CAL1_INIT; + end + end + endcase + end + + //*************************************************************************** + // Second stage calibration: DQS-FPGA Clock + // Algorithm Description: + // 1. Assumes a training pattern that will produce a pattern oscillating at + // half the core clock frequency each on rise and fall outputs, and such + // that rise and fall outputs are 180 degrees out of phase from each + // other. Note that since the calibration logic runs at half the speed + // of the interface, expect that data sampled with the slow clock always + // to be constant (either always = 1, or = 0, and rise data != fall data) + // unless we cross the edge of the data valid window + // 2. Start by setting RD_DATA_SEL = 0. This selects the rising capture data + // sync'ed to rising edge of core clock, and falling edge data sync'ed + // to falling edge of core clock + // 3. Start looking for an edge. An edge is defined as either: (1) a + // change in capture value or (2) an invalid capture value (e.g. rising + // data != falling data for that same clock cycle). + // 4. If an edge is found, go to step (6). If edge hasn't been found, then + // set RD_DATA_SEL = 1, and try again. + // 5. If no edge is found, then increment IDELAY and return to step (3) + // 6. If an edge if found, then invert RD_DATA_SEL - this shifts the + // capture point 180 degrees from the edge of the window (minus duty + // cycle distortion, delay skew between rising/falling edge capture + // paths, etc.) + // 7. If no edge is found by CAL2_IDEL_TAP_LIMIT (= 63 - # taps used for + // stage 1 calibration), then decrement IDELAY (without reinverting + // RD_DATA_SEL) by CAL2_IDEL_TAP_LIMIT/2. This guarantees we at least + // have CAL2_IDEL_TAP_LIMIT/2 of slack both before and after the + // capture point (not optimal, but best we can do not having found an + // of the window). This happens only for very low frequencies. + // 8. Repeat for each DQS group. + // NOTE: Step 6 is not optimal. A better (and perhaps more complicated) + // algorithm might be to find both edges of the data valid window (using + // the same polarity of RD_DATA_SEL), and then decrement to the midpoint. + //*************************************************************************** + + // RD_DATA_SEL should be tagged with FROM-TO (multi-cycle) constraint in + // UCF file to relax timing. This net is "pseudo-static" (after value is + // changed, FSM waits number of cycles before using the output). + // Note that we are adding one clock cycle of delay (to isolate it from + // the other logic CAL2_RD_DATA_SEL feeds), make sure FSM waits long + // enough to compensate (by default it does, it waits a few cycles more + // than minimum # of clock cycles) + genvar rd_i; + generate + for (rd_i = 0; rd_i < DQS_WIDTH; rd_i = rd_i+1) begin: gen_rd_data_sel + FDRSE u_ff_rd_data_sel + ( + .Q (rd_data_sel[rd_i]), + .C (clkdiv), + .CE (1'b1), + .D (cal2_rd_data_sel[rd_i]), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + end + endgenerate + + //***************************************************************** + // Max number of taps used for stg2 cal dependent on number of taps + // used for stg1 (give priority to stg1 cal - let it use as many + // taps as it needs - the remainder of the IDELAY taps can be used + // by stg2) + //***************************************************************** + + always @(posedge clkdiv) + cal2_idel_tap_limit <= 6'b111111 - cal1_idel_max_tap; + + //***************************************************************** + // second stage calibration uses readback pattern of "1100" (i.e. + // 1st rising = 1, 1st falling = 1, 2nd rising = 0, 2nd falling = 0) + // only look at the first bit of each DQS group + //***************************************************************** + + // deasserted when captured data has changed since IDELAY was + // incremented, or when we're right on the edge (i.e. rise data = + // fall data). + assign cal2_detect_edge = + ((((rdd_rise_q1 != cal2_rd_data_rise_last_pos) || + (rdd_fall_q1 != cal2_rd_data_fall_last_pos)) && + cal2_rd_data_last_valid_pos && (!cal2_curr_sel)) || + (((rdd_rise_q1 != cal2_rd_data_rise_last_neg) || + (rdd_fall_q1 != cal2_rd_data_fall_last_neg)) && + cal2_rd_data_last_valid_neg && (cal2_curr_sel)) || + (rdd_rise_q1 != rdd_fall_q1)); + + //***************************************************************** + // keep track of edge tap counts found, and whether we've + // incremented to the maximum number of taps allowed + // NOTE: Assume stage 2 cal always increments the tap count (never + // decrements) when searching for edge of the data valid window + //***************************************************************** + + always @(posedge clkdiv) + if (cal2_state == CAL2_INIT) begin + cal2_idel_tap_limit_hit <= 1'b0; + cal2_idel_tap_cnt <= 6'b000000; + end else if (cal2_dlyce_dqs) begin + cal2_idel_tap_cnt <= cal2_idel_tap_cnt + 1; + cal2_idel_tap_limit_hit <= (cal2_idel_tap_cnt == + cal2_idel_tap_limit - 1); + end + + //***************************************************************** + + always @(posedge clkdiv) + if (rstdiv) begin + calib_done[1] <= 1'b0; + calib_done_tmp[1] <= 1'bx; + calib_err[1] <= 1'b0; + count_dqs <= 'b0; + next_count_dqs <= 'b0; + cal2_dlyce_dqs <= 1'b0; + cal2_dlyinc_dqs <= 1'b0; + cal2_idel_dec_cnt <= 6'bxxxxxx; + cal2_rd_data_last_valid_neg <= 1'bx; + cal2_rd_data_last_valid_pos <= 1'bx; + cal2_rd_data_sel <= 'b0; + cal2_ref_req <= 1'b0; + cal2_state <= CAL2_IDLE; + end else begin + cal2_ref_req <= 1'b0; + cal2_dlyce_dqs <= 1'b0; + cal2_dlyinc_dqs <= 1'b0; + + case (cal2_state) + CAL2_IDLE: begin + count_dqs <= 'b0; + next_count_dqs <= 'b0; + if (calib_start[1]) begin + cal2_rd_data_sel <= {DQS_WIDTH{1'b0}}; + calib_done[1] <= 1'b0; + calib_done_tmp[1] <= 1'b0; + cal2_state <= CAL2_INIT; + end + end + + // Pass through this state every time we calibrate a new DQS group + CAL2_INIT: begin + cal2_curr_sel <= 1'b0; + cal2_rd_data_last_valid_neg <= 1'b0; + cal2_rd_data_last_valid_pos <= 1'b0; + cal2_state <= CAL2_INIT_IDEL_WAIT; + end + + // Stall state only used if calibration run more than once. Can take + // this state out if design never runs calibration more than once. + // We need this state to give time for MUX'ed data to settle after + // resetting RD_DATA_SEL + CAL2_INIT_IDEL_WAIT: + if (!idel_set_wait) + cal2_state <= CAL2_FIND_EDGE_POS; + + // Look for an edge - first check "positive-edge" stage 2 capture + CAL2_FIND_EDGE_POS: begin + // if found an edge, then switch to the opposite edge stage 2 + // capture and we're done - no need to decrement the tap count, + // since switching to the opposite edge will shift the capture + // point by 180 degrees + if (cal2_detect_edge) begin + cal2_curr_sel <= 1'b1; + cal2_state <= CAL2_DONE; + // set all DQS groups to be the same for simulation + if (SIM_ONLY != 0) + cal2_rd_data_sel <= {DQS_WIDTH{1'b1}}; + else + cal2_rd_data_sel[count_dqs] <= 1'b1; + if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) + calib_done_tmp[1] <= 1'b1; + else + // MIG 2.1: Fix for simulation out-of-bounds error when + // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) + next_count_dqs <= count_dqs + 1; + end else begin + // otherwise, invert polarity of stage 2 capture and look for + // an edge with opposite capture clock polarity + cal2_curr_sel <= 1'b1; + cal2_rd_data_sel[count_dqs] <= 1'b1; + cal2_state <= CAL2_FIND_EDGE_IDEL_WAIT_POS; + cal2_rd_data_rise_last_pos <= rdd_rise_q1; + cal2_rd_data_fall_last_pos <= rdd_fall_q1; + cal2_rd_data_last_valid_pos <= 1'b1; + end + end + + // Give time to switch from positive-edge to negative-edge second + // stage capture (need time for data to filter though pipe stages) + CAL2_FIND_EDGE_IDEL_WAIT_POS: + if (!idel_set_wait) + cal2_state <= CAL2_FIND_EDGE_NEG; + + // Look for an edge - check "negative-edge" stage 2 capture + CAL2_FIND_EDGE_NEG: + if (cal2_detect_edge) begin + cal2_curr_sel <= 1'b0; + cal2_state <= CAL2_DONE; + // set all DQS groups to be the same for simulation + if (SIM_ONLY != 0) + cal2_rd_data_sel <= {DQS_WIDTH{1'b0}}; + else + cal2_rd_data_sel[count_dqs] <= 1'b0; + if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) + calib_done_tmp[1] <= 1'b1; + else + // MIG 2.1: Fix for simulation out-of-bounds error when + // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) + next_count_dqs <= count_dqs + 1; + end else if (cal2_idel_tap_limit_hit) begin + // otherwise, if we've run out of taps, then immediately + // backoff by half # of taps used - that's our best estimate + // for optimal calibration point. Doesn't matter whether which + // polarity we're using for capture (we don't know which one is + // best to use) + cal2_idel_dec_cnt <= {1'b0, cal2_idel_tap_limit[5:1]}; + cal2_state <= CAL2_DEC_IDEL; + if ((count_dqs == DQS_WIDTH-1) || (SIM_ONLY != 0)) + calib_done_tmp[1] <= 1'b1; + else + // MIG 2.1: Fix for simulation out-of-bounds error when + // SIM_ONLY=0, and DQS_WIDTH=(power of 2) (needed for VHDL) + next_count_dqs <= count_dqs + 1; + end else begin + // otherwise, increment IDELAY, and start looking for edge again + cal2_curr_sel <= 1'b0; + cal2_rd_data_sel[count_dqs] <= 1'b0; + cal2_state <= CAL2_FIND_EDGE_IDEL_WAIT_NEG; + cal2_rd_data_rise_last_neg <= rdd_rise_q1; + cal2_rd_data_fall_last_neg <= rdd_fall_q1; + cal2_rd_data_last_valid_neg <= 1'b1; + cal2_dlyce_dqs <= 1'b1; + cal2_dlyinc_dqs <= 1'b1; + end + + CAL2_FIND_EDGE_IDEL_WAIT_NEG: + if (!idel_set_wait) + cal2_state <= CAL2_FIND_EDGE_POS; + + // if no edge found, then decrement by half # of taps used + CAL2_DEC_IDEL: begin + if (cal2_idel_dec_cnt == 6'b000000) + cal2_state <= CAL2_DONE; + else begin + cal2_idel_dec_cnt <= cal2_idel_dec_cnt - 1; + cal2_dlyce_dqs <= 1'b1; + cal2_dlyinc_dqs <= 1'b0; + end + end + + // delay state to allow count_dqs and ISERDES data to point to next + // DQ bit (DQS group) before going to INIT + CAL2_DONE: + if (!idel_set_wait) begin + count_dqs <= next_count_dqs; + if (calib_done_tmp[1]) begin + calib_done[1] <= 1'b1; + cal2_state <= CAL2_IDLE; + end else begin + // request auto-refresh after every DQS group calibrated to + // avoid tRAS violation + cal2_ref_req <= 1'b1; + if (calib_ref_done) + cal2_state <= CAL2_INIT; + end + end + endcase + end + + //*************************************************************************** + // Stage 3 calibration: Read Enable + // Description: + // read enable calibration determines the "round-trip" time (in # of CLK0 + // cycles) between when a read command is issued by the controller, and + // when the corresponding read data is synchronized by into the CLK0 domain + // this is a long delay chain to delay read enable signal from controller/ + // initialization logic (i.e. this is used for both initialization and + // during normal controller operation). Stage 3 calibration logic decides + // which delayed version is appropriate to use (which is affected by the + // round trip delay of DQ/DQS) as a "valid" signal to tell rest of logic + // when the captured data output from ISERDES is valid. + //*************************************************************************** + + //***************************************************************** + // Delay chains: Use shift registers + // Two sets of delay chains are used: + // 1. One to delay RDEN from PHY_INIT module for calibration + // purposes (delay required for RDEN for calibration is different + // than during normal operation) + // 2. One per DQS group to delay RDEN from controller for normal + // operation - the value to delay for each DQS group can be different + // as is determined during calibration + //***************************************************************** + + //***************************************************************** + // First delay chain, use only for calibration + // input = asserted on rising edge of RDEN from PHY_INIT module + //***************************************************************** + + always @(posedge clk) begin + ctrl_rden_r <= ctrl_rden; + phy_init_rden_r <= phy_init_rden; + phy_init_rden_r1 <= phy_init_rden_r; + calib_rden_edge_r <= phy_init_rden_r & ~phy_init_rden_r1; + end + + // Calibration shift register used for both Stage 3 and Stage 4 cal + // (not strictly necessary for stage 4, but use as an additional check + // to make sure we're checking for correct data on the right clock cycle) + always @(posedge clkdiv) + if (!calib_done[2]) + calib_rden_srl_a <= cal3_rden_srl_a; + else + calib_rden_srl_a <= cal4_rden_srl_a; + + // Flops for targetting of multi-cycle path in UCF + genvar cal_rden_ff_i; + generate + for (cal_rden_ff_i = 0; cal_rden_ff_i < 5; + cal_rden_ff_i = cal_rden_ff_i+1) begin: gen_cal_rden_dly + FDRSE u_ff_cal_rden_dly + ( + .Q (calib_rden_srl_a_r[cal_rden_ff_i]), + .C (clkdiv), + .CE (1'b1), + .D (calib_rden_srl_a[cal_rden_ff_i]), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + end + endgenerate + + SRLC32E u_calib_rden_srl + ( + .Q (calib_rden_srl_out), + .Q31 (), + .A (calib_rden_srl_a_r), + .CE (1'b1), + .CLK (clk), + .D (calib_rden_edge_r) + ); + + FDRSE u_calib_rden_srl_out_r + ( + .Q (calib_rden_srl_out_r), + .C (clk), + .CE (1'b1), + .D (calib_rden_srl_out), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve = 1 */; + + // convert to CLKDIV domain. Two version are generated because we need + // to be able to tell exactly which fast (clk) clock cycle the read + // enable was asserted in. Only one of CALIB_DATA_VALID or + // CALIB_DATA_VALID_STGD will be asserted for any given shift value + always @(posedge clk) + calib_rden_srl_out_r1 <= calib_rden_srl_out_r; + + always @(posedge clkdiv) begin + calib_rden_valid <= calib_rden_srl_out_r; + calib_rden_valid_stgd <= calib_rden_srl_out_r1; + end + + //***************************************************************** + // Second set of delays chain, use for normal reads + // input = RDEN from controller + //***************************************************************** + + // Flops for targetting of multi-cycle path in UCF + genvar rden_ff_i; + generate + for (rden_ff_i = 0; rden_ff_i < 5*DQS_WIDTH; + rden_ff_i = rden_ff_i+1) begin: gen_rden_dly + FDRSE u_ff_rden_dly + ( + .Q (rden_dly_r[rden_ff_i]), + .C (clkdiv), + .CE (1'b1), + .D (rden_dly[rden_ff_i]), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + end + endgenerate + + // NOTE: Comment this section explaining purpose of SRL's + genvar rden_i; + generate + for (rden_i = 0; rden_i < DQS_WIDTH; rden_i = rden_i + 1) begin: gen_rden + SRLC32E u_rden_srl + ( + .Q (rden_srl_out[rden_i]), + .Q31 (), + .A ({rden_dly_r[(rden_i*5)+4], + rden_dly_r[(rden_i*5)+3], + rden_dly_r[(rden_i*5)+2], + rden_dly_r[(rden_i*5)+1], + rden_dly_r[(rden_i*5)]}), + .CE (1'b1), + .CLK (clk), + .D (ctrl_rden_r) + ); + FDRSE u_calib_rden_r + ( + .Q (calib_rden[rden_i]), + .C (clk), + .CE (1'b1), + .D (rden_srl_out[rden_i]), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve = 1 */; + end + endgenerate + + //***************************************************************** + // indicates that current received data is the correct pattern. Check both + // rising and falling data for first DQ in each DQS group. Note that + // we're checking using a pipelined version of read data, so need to take + // this inherent delay into account in determining final read valid delay + // Data is written to the memory in the following order (first -> last): + // 0x1, 0xE, 0xE, 0x1, 0x1, 0xE, 0x1, 0xE + // Looking at the two LSb bits, expect data in sequence (in binary): + // bit[0]: 1, 0, 0, 1, 0, 1, 0, 1 + // bit[1]: 0, 1, 1, 0, 1, 0, 1, 0 + // Check for the presence of the first 7 words, and compensate read valid + // delay accordingly. Don't check last falling edge data, it may be + // corrupted by the DQS tri-state glitch at end of read postamble + // (glitch protection not yet active until stage 4 cal) + //***************************************************************** + + always @(posedge clkdiv) begin + rdd_rise_q1_r <= rdd_rise_q1; + rdd_fall_q1_r <= rdd_fall_q1; + rdd_rise_q2_r <= rdd_rise_q2; + rdd_fall_q2_r <= rdd_fall_q2; + rdd_rise_q1_r1 <= rdd_rise_q1_r; + rdd_fall_q1_r1 <= rdd_fall_q1_r; + // MIG 3.3: Added comparison for second bit in DQS group for stage 3 cal + rdd_rise_q1_bit1_r <= rdd_rise_q1_bit1; + rdd_fall_q1_bit1_r <= rdd_fall_q1_bit1; + rdd_rise_q2_bit1_r <= rdd_rise_q2_bit1; + rdd_fall_q2_bit1_r <= rdd_fall_q2_bit1; + rdd_rise_q1_bit1_r1 <= rdd_rise_q1_bit1_r; + rdd_fall_q1_bit1_r1 <= rdd_fall_q1_bit1_r; + end + + always @(posedge clkdiv) begin + // For the following sequence from memory: + // rise[0], fall[0], rise[1], fall[1] + // if data is aligned out of fabric ISERDES: + // RDD_RISE_Q2 = rise[0] + // RDD_FALL_Q2 = fall[0] + // RDD_RISE_Q1 = rise[1] + // RDD_FALL_Q1 = fall[1] + cal3_data_match <= ((rdd_rise_q2_r == 1) && + (rdd_fall_q2_r == 0) && + (rdd_rise_q1_r == 0) && + (rdd_fall_q1_r == 1) && + (rdd_rise_q2 == 0) && + (rdd_fall_q2 == 1) && + (rdd_rise_q1 == 0) && + (rdd_rise_q2_bit1_r == 0) && + (rdd_fall_q2_bit1_r == 1) && + (rdd_rise_q1_bit1_r == 1) && + (rdd_fall_q1_bit1_r == 0) && + (rdd_rise_q2_bit1 == 1) && + (rdd_fall_q2_bit1 == 0) && + (rdd_rise_q1_bit1 == 1)); + + // if data is staggered out of fabric ISERDES: + // RDD_RISE_Q1_R = rise[0] + // RDD_FALL_Q1_R = fall[0] + // RDD_RISE_Q2 = rise[1] + // RDD_FALL_Q2 = fall[1] + cal3_data_match_stgd <= ((rdd_rise_q1_r1 == 1) && + (rdd_fall_q1_r1 == 0) && + (rdd_rise_q2_r == 0) && + (rdd_fall_q2_r == 1) && + (rdd_rise_q1_r == 0) && + (rdd_fall_q1_r == 1) && + (rdd_rise_q2 == 0) && + (rdd_rise_q1_bit1_r1 == 0) && + (rdd_fall_q1_bit1_r1 == 1) && + (rdd_rise_q2_bit1_r == 1) && + (rdd_fall_q2_bit1_r == 0) && + (rdd_rise_q1_bit1_r == 1) && + (rdd_fall_q1_bit1_r == 0) && + (rdd_rise_q2_bit1 == 1)); + end + + assign cal3_rden_dly = cal3_rden_srl_a - CAL3_RDEN_SRL_DLY_DELTA; + assign cal3_data_valid = (calib_rden_valid | calib_rden_valid_stgd); + assign cal3_match_found + = ((calib_rden_valid && cal3_data_match) || + (calib_rden_valid_stgd && cal3_data_match_stgd)); + + // when calibrating, check to see which clock cycle (after the read is + // issued) does the expected data pattern arrive. Record this result + // NOTE: Can add error checking here in case valid data not found on any + // of the available pipeline stages + always @(posedge clkdiv) begin + if (rstdiv) begin + cal3_rden_srl_a <= 5'bxxxxx; + cal3_state <= CAL3_IDLE; + calib_done[2] <= 1'b0; + calib_err_2[0] <= 1'b0; + count_rden <= {DQS_WIDTH{1'b0}}; + rden_dly <= {5*DQS_WIDTH{1'b0}}; + end else begin + + case (cal3_state) + CAL3_IDLE: begin + count_rden <= {DQS_WIDTH{1'b0}}; + if (calib_start[2]) begin + calib_done[2] <= 1'b0; + cal3_state <= CAL3_INIT; + end + end + + CAL3_INIT: begin + cal3_rden_srl_a <= RDEN_BASE_DELAY; + // let SRL pipe clear after loading initial shift value + cal3_state <= CAL3_RDEN_PIPE_CLR_WAIT; + end + + CAL3_DETECT: + if (cal3_data_valid) + // if match found at the correct clock cycle + if (cal3_match_found) begin + + // For simulation, load SRL addresses for all DQS with same value + if (SIM_ONLY != 0) begin + for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_rden_dly + rden_dly[(i*5)] <= cal3_rden_dly[0]; + rden_dly[(i*5)+1] <= cal3_rden_dly[1]; + rden_dly[(i*5)+2] <= cal3_rden_dly[2]; + rden_dly[(i*5)+3] <= cal3_rden_dly[3]; + rden_dly[(i*5)+4] <= cal3_rden_dly[4]; + end + end else begin + rden_dly[(count_rden*5)] <= cal3_rden_dly[0]; + rden_dly[(count_rden*5)+1] <= cal3_rden_dly[1]; + rden_dly[(count_rden*5)+2] <= cal3_rden_dly[2]; + rden_dly[(count_rden*5)+3] <= cal3_rden_dly[3]; + rden_dly[(count_rden*5)+4] <= cal3_rden_dly[4]; + end + + // Use for stage 4 calibration + calib_rden_dly[(count_rden*5)] <= cal3_rden_srl_a[0]; + calib_rden_dly[(count_rden*5)+1] <= cal3_rden_srl_a[1]; + calib_rden_dly[(count_rden*5)+2] <= cal3_rden_srl_a[2]; + calib_rden_dly[(count_rden*5)+3] <= cal3_rden_srl_a[3]; + calib_rden_dly[(count_rden*5)+4] <= cal3_rden_srl_a[4]; + cal3_state <= CAL3_DONE; + end else begin + // If we run out of stages to shift, without finding correct + // result, the stop and assert error + if (cal3_rden_srl_a == 5'b11111) begin + calib_err_2[0] <= 1'b1; + cal3_state <= CAL3_IDLE; + end else begin + // otherwise, increase the shift value and try again + cal3_rden_srl_a <= cal3_rden_srl_a + 1; + cal3_state <= CAL3_RDEN_PIPE_CLR_WAIT; + end + end + + // give additional time for RDEN_R pipe to clear from effects of + // previous pipeline or IDELAY tap change + CAL3_RDEN_PIPE_CLR_WAIT: + if (calib_rden_pipe_cnt == 5'b00000) + cal3_state <= CAL3_DETECT; + + CAL3_DONE: begin + if ((count_rden == DQS_WIDTH-1) || (SIM_ONLY != 0)) begin + calib_done[2] <= 1'b1; + cal3_state <= CAL3_IDLE; + end else begin + count_rden <= count_rden + 1; + cal3_state <= CAL3_INIT; + end + end + endcase + end + end + + //***************************************************************** + // Last part of stage 3 calibration - compensate for differences + // in delay between different DQS groups. Assume that in the worst + // case, DQS groups can only differ by one clock cycle. Data for + // certain DQS groups must be delayed by one clock cycle. + // NOTE: May need to increase allowable variation to greater than + // one clock cycle in certain customer designs. + // Algorithm is: + // 1. Record shift delay value for DQS[0] + // 2. Compare each DQS[x] delay value to that of DQS[0]: + // - If different, than record this fact (RDEN_MUX) + // - If greater than DQS[0], set RDEN_INC. Assume greater by + // one clock cycle only - this is a key assumption, assume no + // more than a one clock cycle variation. + // - If less than DQS[0], set RDEN_DEC + // 3. After calibration is complete, set control for DQS group + // delay (CALIB_RDEN_SEL): + // - If RDEN_DEC = 1, then assume that DQS[0] is the lowest + // delay (and at least one other DQS group has a higher + // delay). + // - If RDEN_INC = 1, then assume that DQS[0] is the highest + // delay (and that all other DQS groups have the same or + // lower delay). + // - If both RDEN_INC and RDEN_DEC = 1, then flag error + // (variation is too high for this algorithm to handle) + //***************************************************************** + + always @(posedge clkdiv) begin + if (rstdiv) begin + calib_err_2[1] <= 1'b0; + calib_rden_sel <= {DQS_WIDTH{1'bx}}; + rden_dec <= 1'b0; + rden_dly_0 <= 5'bxxxxx; + rden_inc <= 1'b0; + rden_mux <= {DQS_WIDTH{1'b0}}; + end else begin + // if a match if found, then store the value of rden_dly + if (!calib_done[2]) begin + if ((cal3_state == CAL3_DETECT) && cal3_match_found) begin + // store the value for DQS[0] as a reference + if (count_rden == 0) begin + // for simulation, RDEN calibration only happens for DQS[0] + // set RDEN_MUX for all DQS groups to be the same as DQS[0] + if (SIM_ONLY != 0) + rden_mux <= {DQS_WIDTH{1'b0}}; + else begin + // otherwise, load values for DQS[0] + rden_dly_0 <= cal3_rden_srl_a; + rden_mux[0] <= 1'b0; + end + end else if (SIM_ONLY == 0) begin + // for all other DQS groups, compare RDEN_DLY delay value with + // that of DQS[0] + if (rden_dly_0 != cal3_rden_srl_a) begin + // record that current DQS group has a different delay + // than DQS[0] (the "reference" DQS group) + rden_mux[count_rden] <= 1'b1; + if (rden_dly_0 > cal3_rden_srl_a) + rden_inc <= 1'b1; + else if (rden_dly_0 < cal3_rden_srl_a) + rden_dec <= 1'b1; + // otherwise, if current DQS group has same delay as DQS[0], + // then rden_mux[count_rden] remains at 0 (since rden_mux + // array contents initialized to 0) + end + end + end + end else begin + // Otherwise - if we're done w/ stage 2 calibration: + // set final value for RDEN data delay + // flag error if there's more than one cycle variation from DQS[0] + calib_err_2[1] <= (rden_inc && rden_dec); + if (rden_inc) + // if DQS[0] delay represents max delay + calib_rden_sel <= ~rden_mux; + else + // if DQS[0] delay represents min delay (or all the delays are + // the same between DQS groups) + calib_rden_sel <= rden_mux; + end + end + end + + // flag error for stage 3 if appropriate + always @(posedge clkdiv) + calib_err[2] <= calib_err_2[0] | calib_err_2[1]; + + //*************************************************************************** + // Stage 4 calibration: DQS gate + //*************************************************************************** + + //***************************************************************** + // indicates that current received data is the correct pattern. Same as + // for READ VALID calibration, except that the expected data sequence is + // different since DQS gate is asserted after the 6th word. + // Data sequence: + // Arrives from memory (at FPGA input) (R, F): 1 0 0 1 1 0 0 1 + // After gating the sequence looks like: 1 0 0 1 1 0 1 0 (7th word = + // 5th word, 8th word = 6th word) + // What is the gate timing is off? Need to make sure we can distinquish + // between the results of correct vs. incorrect gate timing. We also use + // the "read_valid" signal from stage 3 calibration to help us determine + // when to check for a valid sequence for stage 4 calibration (i.e. use + // CAL4_DATA_VALID in addition to CAL4_DATA_MATCH/CAL4_DATA_MATCH_STGD) + // Note that since the gate signal from the CLK0 domain is synchronized + // to the falling edge of DQS, that the effect of the gate will only be + // seen starting with a rising edge data (although it is possible + // the GATE IDDR output could go metastable and cause a unexpected result + // on the first rising and falling edges after the gate is enabled). + // Also note that the actual DQS glitch can come more than 0.5*tCK after + // the last falling edge of DQS and the constraint for this path is can + // be > 0.5*tCK; however, this means when calibrating, the output of the + // GATE IDDR may miss the setup time requirement of the rising edge flop + // and only meet it for the falling edge flop. Therefore the rising + // edge data immediately following the assertion of the gate can either + // be a 1 or 0 (can rely on either) + // As the timing on the gate is varied, we expect to see (sequence of + // captured read data shown below): + // - 1 0 0 1 1 0 0 1 (gate is really early, starts and ends before + // read burst even starts) + // - x 0 0 1 1 0 0 1 (gate pulse starts before the burst, and ends + // - x y 0 1 1 0 0 1 sometime during the burst; x,y = 0, or 1, but + // - x y x 1 1 0 0 1 all bits that show an x are the same value, + // - x y x y 1 0 0 1 and y are the same value) + // - x y x y x 0 0 1 + // - x y x y x y 0 1 (gate starts just before start of burst) + // - 1 0 x 0 x 0 x 0 (gate starts after 1st falling word. The "x" + // represents possiblity that gate may not disable + // clock for 2nd rising word in time) + // - 1 0 0 1 x 1 x 1 (gate starts after 2nd falling word) + // - 1 0 0 1 1 0 x 0 (gate starts after 3rd falling word - GOOD!!) + // - 1 0 0 1 1 0 0 1 (gate starts after burst is already done) + //***************************************************************** + + assign cal4_data_valid = calib_rden_valid | calib_rden_valid_stgd; + assign cal4_data_good = (calib_rden_valid & + cal4_data_match) | + (calib_rden_valid_stgd & + cal4_data_match_stgd); + + always @(posedge clkdiv) begin + // if data is aligned out of fabric ISERDES: + cal4_data_match <= ((rdd_rise_q2_r == 1) && + (rdd_fall_q2_r == 0) && + (rdd_rise_q1_r == 0) && + (rdd_fall_q1_r == 1) && + (rdd_rise_q2 == 1) && + (rdd_fall_q2 == 0) && + // MIG 2.1: Last rising edge data value not + // guaranteed to be certain value at higher + // frequencies + // (rdd_rise_q1 == 0) && + (rdd_fall_q1 == 0)); + // if data is staggered out of fabric ISERDES: + cal4_data_match_stgd <= ((rdd_rise_q1_r1 == 1) && + (rdd_fall_q1_r1 == 0) && + (rdd_rise_q2_r == 0) && + (rdd_fall_q2_r == 1) && + (rdd_rise_q1_r == 1) && + (rdd_fall_q1_r == 0) && + // MIG 2.1: Last rising edge data value not + // guaranteed to be certain value at higher + // frequencies + // (rdd_rise_q2 == 0) && + (rdd_fall_q2 == 0)); + end + + //***************************************************************** + // DQS gate enable generation: + // This signal gets synchronized to DQS domain, and drives IDDR + // register that in turn asserts/deasserts CE to all 4 or 8 DQ + // IDDR's in that DQS group. + // 1. During normal (post-cal) operation, this is only for 2 clock + // cycles following the end of a burst. Check for falling edge + // of RDEN. But must also make sure NOT assert for a read-idle- + // read (two non-consecutive reads, separated by exactly one + // idle cycle) - in this case, don't assert the gate because: + // (1) we don't have enough time to deassert the gate before the + // first rising edge of DQS for second burst (b/c of fact + // that DQS gate is generated in the fabric only off rising + // edge of CLK0 - if we somehow had an ODDR in fabric, we + // could pull this off, (2) assumption is that the DQS glitch + // will not rise enough to cause a glitch because the + // post-amble of the first burst is followed immediately by + // the pre-amble of the next burst + // 2. During stage 4 calibration, assert for 3 clock cycles + // (assert gate enable one clock cycle early), since we gate out + // the last two words (in addition to the crap on the DQ bus after + // the DQS read postamble). + // NOTE: PHY_INIT_RDEN and CTRL_RDEN have slightly different timing w/r + // to when they are asserted w/r to the start of the read burst + // (PHY_INIT_RDEN is one cycle earlier than CTRL_RDEN). + //***************************************************************** + + // register for timing purposes for fast clock path - currently only + // calib_done_r[2] used + always @(posedge clk) + calib_done_r <= calib_done; + + always @(*) begin + calib_ctrl_rden = ctrl_rden; + calib_init_rden = calib_done_r[2] & phy_init_rden; + end + + assign calib_ctrl_rden_negedge = ~calib_ctrl_rden & calib_ctrl_rden_r; + // check for read-idle-read before asserting DQS pulse at end of read + assign calib_ctrl_gate_pulse = calib_ctrl_rden_negedge_r & + ~calib_ctrl_rden; + always @(posedge clk) begin + calib_ctrl_rden_r <= calib_ctrl_rden; + calib_ctrl_rden_negedge_r <= calib_ctrl_rden_negedge; + calib_ctrl_gate_pulse_r <= calib_ctrl_gate_pulse; + end + + assign calib_init_gate_pulse = ~calib_init_rden & calib_init_rden_r; + always @(posedge clk) begin + calib_init_rden_r <= calib_init_rden; + calib_init_gate_pulse_r <= calib_init_gate_pulse; + calib_init_gate_pulse_r1 <= calib_init_gate_pulse_r; + end + + // Gate is asserted: (1) during cal, for 3 cycles, starting 1 cycle + // after falling edge of CTRL_RDEN, (2) during normal ops, for 2 + // cycles, starting 2 cycles after falling edge of CTRL_RDEN + assign gate_srl_in = ~((calib_ctrl_gate_pulse | + calib_ctrl_gate_pulse_r) | + (calib_init_gate_pulse | + calib_init_gate_pulse_r | + calib_init_gate_pulse_r1)); + + //***************************************************************** + // generate DQS enable signal for each DQS group + // There are differences between DQS gate signal for calibration vs. during + // normal operation: + // * calibration gates the second to last clock cycle of the burst, + // rather than after the last word (e.g. for a 8-word, 4-cycle burst, + // cycle 4 is gated for calibration; during normal operation, cycle + // 5 (i.e. cycle after the last word) is gated) + // enable for DQS is deasserted for two clock cycles, except when + // we have the preamble for the next read immediately following + // the postamble of the current read - assume DQS does not glitch + // during this time, that it stays low. Also if we did have to gate + // the DQS for this case, then we don't have enough time to deassert + // the gate in time for the first rising edge of DQS for the second + // read + //***************************************************************** + + // Flops for targetting of multi-cycle path in UCF + genvar gate_ff_i; + generate + for (gate_ff_i = 0; gate_ff_i < 5*DQS_WIDTH; + gate_ff_i = gate_ff_i+1) begin: gen_gate_dly + FDRSE u_ff_gate_dly + ( + .Q (gate_dly_r[gate_ff_i]), + .C (clkdiv), + .CE (1'b1), + .D (gate_dly[gate_ff_i]), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + end + endgenerate + + genvar gate_i; + generate + for (gate_i = 0; gate_i < DQS_WIDTH; gate_i = gate_i + 1) begin: gen_gate + SRLC32E u_gate_srl + ( + .Q (gate_srl_out[gate_i]), + .Q31 (), + .A ({gate_dly_r[(gate_i*5)+4], + gate_dly_r[(gate_i*5)+3], + gate_dly_r[(gate_i*5)+2], + gate_dly_r[(gate_i*5)+1], + gate_dly_r[(gate_i*5)]}), + .CE (1'b1), + .CLK (clk), + .D (gate_srl_in) + ); + + // For GATE_BASE_DELAY > 0, have one extra cycle to register outputs + // from controller before generating DQS gate pulse. In PAR, the + // location of the controller logic can be far from the DQS gate + // logic (DQS gate logic located near the DQS I/O's), contributing + // to large net delays. Registering the controller outputs for + // CL >= 4 (above 200MHz) adds a stage of pipelining to reduce net + // delays + if (GATE_BASE_DELAY > 0) begin: gen_gate_base_dly_gt3 + // add flop between SRL32 and EN_DQS flop (which is located near the + // DDR2 IOB's) + FDRSE u_gate_srl_ff + ( + .Q (gate_srl_out_r[gate_i]), + .C (clk), + .CE (1'b1), + .D (gate_srl_out[gate_i]), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve = 1 */; + end else begin: gen_gate_base_dly_le3 + assign gate_srl_out_r[gate_i] = gate_srl_out[gate_i]; + end + + FDRSE u_en_dqs_ff + ( + .Q (en_dqs[gate_i]), + .C (clk), + .CE (1'b1), + .D (gate_srl_out_r[gate_i]), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve = 1 */ + /* synthesis syn_replicate = 0 */; + end + endgenerate + + //***************************************************************** + // Find valid window: keep track of how long we've been in the same data + // window. If it's been long enough, then declare that we've found a stable + // valid window - in particular, that we're past any region of instability + // associated with the edge of the window. Use only when finding left edge + //***************************************************************** + + always @(posedge clkdiv) + // reset before we start to look for window + if (cal4_state == CAL4_INIT) begin + cal4_window_cnt <= 4'b0000; + cal4_stable_window <= 1'b0; + end else if ((cal4_state == CAL4_FIND_EDGE) && cal4_seek_left) begin + // if we're looking for left edge, and incrementing IDELAY, count + // consecutive taps over which we're in the window + if (cal4_data_valid) begin + if (cal4_data_good) + cal4_window_cnt <= cal4_window_cnt + 1; + else + cal4_window_cnt <= 4'b0000; + end + + if (cal4_window_cnt == MIN_WIN_SIZE-1) + cal4_stable_window <= 1'b1; + end + + //***************************************************************** + // keep track of edge tap counts found, and whether we've + // incremented to the maximum number of taps allowed + //***************************************************************** + + always @(posedge clkdiv) + if ((cal4_state == CAL4_INIT) || cal4_dlyrst_gate) begin + cal4_idel_max_tap <= 1'b0; + cal4_idel_bit_tap <= 1'b0; + cal4_idel_tap_cnt <= 6'b000000; + end else if (cal4_dlyce_gate) begin + if (cal4_dlyinc_gate) begin + cal4_idel_tap_cnt <= cal4_idel_tap_cnt + 1; + cal4_idel_bit_tap <= (cal4_idel_tap_cnt == CAL4_IDEL_BIT_VAL-2); + cal4_idel_max_tap <= (cal4_idel_tap_cnt == 6'b111110); + end else begin + cal4_idel_tap_cnt <= cal4_idel_tap_cnt - 1; + cal4_idel_bit_tap <= 1'b0; + cal4_idel_max_tap <= 1'b0; + end + end + + always @(posedge clkdiv) + if ((cal4_state != CAL4_RDEN_PIPE_CLR_WAIT) && + (cal3_state != CAL3_RDEN_PIPE_CLR_WAIT)) + calib_rden_pipe_cnt <= CALIB_RDEN_PIPE_LEN-1; + else + calib_rden_pipe_cnt <= calib_rden_pipe_cnt - 1; + + //***************************************************************** + // Stage 4 cal state machine + //***************************************************************** + + always @(posedge clkdiv) + if (rstdiv) begin + calib_done[3] <= 1'b0; + calib_done_tmp[3] <= 1'b0; + calib_err[3] <= 1'b0; + count_gate <= 'b0; + gate_dly <= 'b0; + next_count_gate <= 'b0; + cal4_idel_adj_cnt <= 6'bxxxxxx; + cal4_dlyce_gate <= 1'b0; + cal4_dlyinc_gate <= 1'b0; + cal4_dlyrst_gate <= 1'b0; // reset handled elsewhere in code + cal4_gate_srl_a <= 5'bxxxxx; + cal4_rden_srl_a <= 5'bxxxxx; + cal4_ref_req <= 1'b0; + cal4_seek_left <= 1'bx; + cal4_state <= CAL4_IDLE; + end else begin + cal4_ref_req <= 1'b0; + cal4_dlyce_gate <= 1'b0; + cal4_dlyinc_gate <= 1'b0; + cal4_dlyrst_gate <= 1'b0; + + case (cal4_state) + CAL4_IDLE: begin + count_gate <= 'b0; + next_count_gate <= 'b0; + if (calib_start[3]) begin + gate_dly <= 'b0; + calib_done[3] <= 1'b0; + cal4_state <= CAL4_INIT; + end + end + + CAL4_INIT: begin + // load: (1) initial value of gate delay SRL, (2) appropriate + // value of RDEN SRL (so that we get correct "data valid" timing) + cal4_gate_srl_a <= GATE_BASE_INIT; + cal4_rden_srl_a <= {calib_rden_dly[(count_gate*5)+4], + calib_rden_dly[(count_gate*5)+3], + calib_rden_dly[(count_gate*5)+2], + calib_rden_dly[(count_gate*5)+1], + calib_rden_dly[(count_gate*5)]}; + // let SRL pipe clear after loading initial shift value + cal4_state <= CAL4_RDEN_PIPE_CLR_WAIT; + end + + // sort of an initial state - start checking to see whether we're + // already in the window or not + CAL4_FIND_WINDOW: + // decide right away if we start in the proper window - this + // determines if we are then looking for the left (trailing) or + // right (leading) edge of the data valid window + if (cal4_data_valid) begin + // if we find a match - then we're already in window, now look + // for left edge. Otherwise, look for right edge of window + cal4_seek_left <= cal4_data_good; + cal4_state <= CAL4_FIND_EDGE; + end + + CAL4_FIND_EDGE: + // don't do anything until the exact clock cycle when to check that + // readback data is valid or not + if (cal4_data_valid) begin + // we're currently in the window, look for left edge of window + if (cal4_seek_left) begin + // make sure we've passed the right edge before trying to detect + // the left edge (i.e. avoid any edge "instability") - else, we + // may detect an "false" edge too soon. By design, if we start in + // the data valid window, always expect at least + // MIN(BIT_TIME_TAPS,32) (-/+ jitter, see below) taps of valid + // window before we hit the left edge (this is because when stage + // 4 calibration first begins (i.e., gate_dly = 00, and IDELAY = + // 00), we're guaranteed to NOT be in the window, and we always + // start searching for MIN(BIT_TIME_TAPS,32) for the right edge + // of window. If we don't find it, increment gate_dly, and if we + // now start in the window, we have at least approximately + // CLK_PERIOD-MIN(BIT_TIME_TAPS,32) = MIN(BIT_TIME_TAPS,32) taps. + // It's approximately because jitter, noise, etc. can bring this + // value down slightly. Because of this (although VERY UNLIKELY), + // we have to protect against not decrementing IDELAY below 0 + // during adjustment phase). + if (cal4_stable_window && !cal4_data_good) begin + // found left edge of window, dec by MIN(BIT_TIME_TAPS,32) + cal4_idel_adj_cnt <= CAL4_IDEL_BIT_VAL; + cal4_idel_adj_inc <= 1'b0; + cal4_state <= CAL4_ADJ_IDEL; + end else begin + // Otherwise, keep looking for left edge: + if (cal4_idel_max_tap) begin + // ran out of taps looking for left edge (max=63) - happens + // for low frequency case, decrement by 32 + cal4_idel_adj_cnt <= 6'b100000; + cal4_idel_adj_inc <= 1'b0; + cal4_state <= CAL4_ADJ_IDEL; + end else begin + cal4_dlyce_gate <= 1'b1; + cal4_dlyinc_gate <= 1'b1; + cal4_state <= CAL4_IDEL_WAIT; + end + end + end else begin + // looking for right edge of window: + // look for the first match - this means we've found the right + // (leading) edge of the data valid window, increment by + // MIN(BIT_TIME_TAPS,32) + if (cal4_data_good) begin + cal4_idel_adj_cnt <= CAL4_IDEL_BIT_VAL; + cal4_idel_adj_inc <= 1'b1; + cal4_state <= CAL4_ADJ_IDEL; + end else begin + // Otherwise, keep looking: + // only look for MIN(BIT_TIME_TAPS,32) taps for right edge, + // if we haven't found it, then inc gate delay, try again + if (cal4_idel_bit_tap) begin + // if we're already maxed out on gate delay, then error out + // (simulation only - calib_err isn't currently connected) + if (cal4_gate_srl_a == 5'b11111) begin + calib_err[3] <= 1'b1; + cal4_state <= CAL4_IDLE; + end else begin + // otherwise, increment gate delay count, and start + // over again + cal4_gate_srl_a <= cal4_gate_srl_a + 1; + cal4_dlyrst_gate <= 1'b1; + cal4_state <= CAL4_RDEN_PIPE_CLR_WAIT; + end + end else begin + // keep looking for right edge + cal4_dlyce_gate <= 1'b1; + cal4_dlyinc_gate <= 1'b1; + cal4_state <= CAL4_IDEL_WAIT; + end + end + end + end + + // wait for GATE IDELAY to settle, after reset or increment + CAL4_IDEL_WAIT: begin + // For simulation, load SRL addresses for all DQS with same value + if (SIM_ONLY != 0) begin + for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_gate_dly + gate_dly[(i*5)+4] <= cal4_gate_srl_a[4]; + gate_dly[(i*5)+3] <= cal4_gate_srl_a[3]; + gate_dly[(i*5)+2] <= cal4_gate_srl_a[2]; + gate_dly[(i*5)+1] <= cal4_gate_srl_a[1]; + gate_dly[(i*5)] <= cal4_gate_srl_a[0]; + end + end else begin + gate_dly[(count_gate*5)+4] <= cal4_gate_srl_a[4]; + gate_dly[(count_gate*5)+3] <= cal4_gate_srl_a[3]; + gate_dly[(count_gate*5)+2] <= cal4_gate_srl_a[2]; + gate_dly[(count_gate*5)+1] <= cal4_gate_srl_a[1]; + gate_dly[(count_gate*5)] <= cal4_gate_srl_a[0]; + end + // check to see if we've found edge of window + if (!idel_set_wait) + cal4_state <= CAL4_FIND_EDGE; + end + + // give additional time for RDEN_R pipe to clear from effects of + // previous pipeline (and IDELAY reset) + CAL4_RDEN_PIPE_CLR_WAIT: begin + // MIG 2.2: Bug fix - make sure to update GATE_DLY count, since + // possible for FIND_EDGE->RDEN_PIPE_CLR_WAIT->FIND_WINDOW + // transition (i.e. need to make sure the gate count updated in + // FIND_EDGE gets reflected in GATE_DLY by the time we reach + // state FIND_WINDOW) - previously GATE_DLY only being updated + // during state CAL4_IDEL_WAIT + if (SIM_ONLY != 0) begin + for (i = 0; i < DQS_WIDTH; i = i + 1) begin: loop_sim_gate_dly_pipe + gate_dly[(i*5)+4] <= cal4_gate_srl_a[4]; + gate_dly[(i*5)+3] <= cal4_gate_srl_a[3]; + gate_dly[(i*5)+2] <= cal4_gate_srl_a[2]; + gate_dly[(i*5)+1] <= cal4_gate_srl_a[1]; + gate_dly[(i*5)] <= cal4_gate_srl_a[0]; + end + end else begin + gate_dly[(count_gate*5)+4] <= cal4_gate_srl_a[4]; + gate_dly[(count_gate*5)+3] <= cal4_gate_srl_a[3]; + gate_dly[(count_gate*5)+2] <= cal4_gate_srl_a[2]; + gate_dly[(count_gate*5)+1] <= cal4_gate_srl_a[1]; + gate_dly[(count_gate*5)] <= cal4_gate_srl_a[0]; + end + // look for new window + if (calib_rden_pipe_cnt == 5'b00000) + cal4_state <= CAL4_FIND_WINDOW; + end + + // increment/decrement DQS/DQ IDELAY for final adjustment + CAL4_ADJ_IDEL: + // add underflow protection for corner case when left edge found + // using fewer than MIN(BIT_TIME_TAPS,32) taps + if ((cal4_idel_adj_cnt == 6'b000000) || + (cal4_dlyce_gate && !cal4_dlyinc_gate && + (cal4_idel_tap_cnt == 6'b000001))) begin + cal4_state <= CAL4_DONE; + // stop when all gates calibrated, or gate[0] cal'ed (for sim) + if ((count_gate == DQS_WIDTH-1) || (SIM_ONLY != 0)) + calib_done_tmp[3] <= 1'b1; + else + // need for VHDL simulation to prevent out-of-index error + next_count_gate <= count_gate + 1; + end else begin + cal4_idel_adj_cnt <= cal4_idel_adj_cnt - 1; + cal4_dlyce_gate <= 1'b1; + // whether inc or dec depends on whether left or right edge found + cal4_dlyinc_gate <= cal4_idel_adj_inc; + end + + // wait for IDELAY output to settle after decrement. Check current + // COUNT_GATE value and decide if we're done + CAL4_DONE: + if (!idel_set_wait) begin + count_gate <= next_count_gate; + if (calib_done_tmp[3]) begin + calib_done[3] <= 1'b1; + cal4_state <= CAL4_IDLE; + end else begin + // request auto-refresh after every DQS group calibrated to + // avoid tRAS violation + cal4_ref_req <= 1'b1; + if (calib_ref_done) + cal4_state <= CAL4_INIT; + end + end + endcase + end + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_top.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_top.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_top.v (revision 3) @@ -0,0 +1,181 @@ +//***************************************************************************** +// 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 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_usr_top.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Mon Aug 28 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module interfaces with the user. The user should provide the data +// and various commands. +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_usr_top # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter CS_BITS = 0, + parameter COL_WIDTH = 10, + parameter DQ_WIDTH = 72, + parameter DQ_PER_DQS = 8, + parameter APPDATA_WIDTH = 144, + parameter ECC_ENABLE = 0, + parameter DQS_WIDTH = 9, + parameter ROW_WIDTH = 14 + ) + ( + input clk0, + input clk90, + input rst0, + input [DQ_WIDTH-1:0] rd_data_in_rise, + input [DQ_WIDTH-1:0] rd_data_in_fall, + input [DQS_WIDTH-1:0] phy_calib_rden, + input [DQS_WIDTH-1:0] phy_calib_rden_sel, + output rd_data_valid, + output [APPDATA_WIDTH-1:0] rd_data_fifo_out, + input [2:0] app_af_cmd, + input [30:0] app_af_addr, + input app_af_wren, + input ctrl_af_rden, + output [2:0] af_cmd, + output [30:0] af_addr, + output af_empty, + output app_af_afull, + output [1:0] rd_ecc_error, + input app_wdf_wren, + input [APPDATA_WIDTH-1:0] app_wdf_data, + input [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, + input wdf_rden, + output app_wdf_afull, + output [(2*DQ_WIDTH)-1:0] wdf_data, + output [((2*DQ_WIDTH)/8)-1:0] wdf_mask_data + ); + + wire [(APPDATA_WIDTH/2)-1:0] i_rd_data_fifo_out_fall; + wire [(APPDATA_WIDTH/2)-1:0] i_rd_data_fifo_out_rise; + + //*************************************************************************** + + assign rd_data_fifo_out = {i_rd_data_fifo_out_fall, + i_rd_data_fifo_out_rise}; + + // read data de-skew and ECC calculation + ddr2_usr_rd # + ( + .DQ_PER_DQS (DQ_PER_DQS), + .ECC_ENABLE (ECC_ENABLE), + .APPDATA_WIDTH (APPDATA_WIDTH), + .DQS_WIDTH (DQS_WIDTH) + ) + u_usr_rd + ( + .clk0 (clk0), + .rst0 (rst0), + .rd_data_in_rise (rd_data_in_rise), + .rd_data_in_fall (rd_data_in_fall), + .rd_ecc_error (rd_ecc_error), + .ctrl_rden (phy_calib_rden), + .ctrl_rden_sel (phy_calib_rden_sel), + .rd_data_valid (rd_data_valid), + .rd_data_out_rise (i_rd_data_fifo_out_rise), + .rd_data_out_fall (i_rd_data_fifo_out_fall) + ); + + // Command/Addres FIFO + ddr2_usr_addr_fifo # + ( + .BANK_WIDTH (BANK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_BITS (CS_BITS), + .ROW_WIDTH (ROW_WIDTH) + ) + u_usr_addr_fifo + ( + .clk0 (clk0), + .rst0 (rst0), + .app_af_cmd (app_af_cmd), + .app_af_addr (app_af_addr), + .app_af_wren (app_af_wren), + .ctrl_af_rden (ctrl_af_rden), + .af_cmd (af_cmd), + .af_addr (af_addr), + .af_empty (af_empty), + .app_af_afull (app_af_afull) + ); + + ddr2_usr_wr # + ( + .BANK_WIDTH (BANK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .CS_BITS (CS_BITS), + .DQ_WIDTH (DQ_WIDTH), + .APPDATA_WIDTH (APPDATA_WIDTH), + .ECC_ENABLE (ECC_ENABLE), + .ROW_WIDTH (ROW_WIDTH) + ) + u_usr_wr + ( + .clk0 (clk0), + .clk90 (clk90), + .rst0 (rst0), + .app_wdf_wren (app_wdf_wren), + .app_wdf_data (app_wdf_data), + .app_wdf_mask_data (app_wdf_mask_data), + .wdf_rden (wdf_rden), + .app_wdf_afull (app_wdf_afull), + .wdf_data (wdf_data), + .wdf_mask_data (wdf_mask_data) + ); + +endmodule \ No newline at end of file Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_idelay_ctrl.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_idelay_ctrl.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_idelay_ctrl.v (revision 3) @@ -0,0 +1,87 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_idelay_ctrl.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Wed Aug 16 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module instantiates the IDELAYCTRL primitive of the Virtex-5 device +// which continuously calibrates the IDELAY elements in the region in case of +// varying operating conditions. It takes a 200MHz clock as an input +//Reference: +//Revision History: +// Rev 1.1 - Parameter IODELAY_GRP added and constraint IODELAY_GROUP added +// on IOELAYCTRL primitive. Generate logic on IDELAYCTRL removed +// since tools will replicate idelactrl primitives.PK. 11/27/08 +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_idelay_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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter IODELAY_GRP = "IODELAY_MIG" + ) + + ( + input clk200, + input rst200, + output idelay_ctrl_rdy + ); + + (* IODELAY_GROUP = IODELAY_GRP *) IDELAYCTRL u_idelayctrl + ( + .RDY(idelay_ctrl_rdy), + .REFCLK(clk200), + .RST(rst200) + ); + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_rd.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_rd.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl/ddr2_usr_rd.v (revision 3) @@ -0,0 +1,297 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_usr_rd.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Tue Aug 29 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// The delay between the read data with respect to the command issued is +// calculted in terms of no. of clocks. This data is then stored into the +// FIFOs and then read back and given as the ouput for comparison. +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_usr_rd # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter DQ_PER_DQS = 8, + parameter DQS_WIDTH = 9, + parameter APPDATA_WIDTH = 144, + parameter ECC_WIDTH = 72, + parameter ECC_ENABLE = 0 + ) + ( + input clk0, + input rst0, + input [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_rise, + input [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_fall, + input [DQS_WIDTH-1:0] ctrl_rden, + input [DQS_WIDTH-1:0] ctrl_rden_sel, + output reg [1:0] rd_ecc_error, + output rd_data_valid, + output reg [(APPDATA_WIDTH/2)-1:0] rd_data_out_rise, + output reg [(APPDATA_WIDTH/2)-1:0] rd_data_out_fall + ); + + // determine number of FIFO72's to use based on data width + localparam RDF_FIFO_NUM = ((APPDATA_WIDTH/2)+63)/64; + + reg [DQS_WIDTH-1:0] ctrl_rden_r; + wire [(DQS_WIDTH*DQ_PER_DQS)-1:0] fall_data; + reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_fall_r; + reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rd_data_in_rise_r; + wire rden; + reg [DQS_WIDTH-1:0] rden_sel_r + /* synthesis syn_preserve=1 */; + wire [DQS_WIDTH-1:0] rden_sel_mux; + wire [(DQS_WIDTH*DQ_PER_DQS)-1:0] rise_data; + + // ECC specific signals + wire [((RDF_FIFO_NUM -1) *2)+1:0] db_ecc_error; + reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] fall_data_r; + reg fifo_rden_r0; + reg fifo_rden_r1; + reg fifo_rden_r2; + reg fifo_rden_r3; + reg fifo_rden_r4; + reg fifo_rden_r5; + reg fifo_rden_r6; + wire [(APPDATA_WIDTH/2)-1:0] rd_data_out_fall_temp; + wire [(APPDATA_WIDTH/2)-1:0] rd_data_out_rise_temp; + reg rst_r; + reg [(DQS_WIDTH*DQ_PER_DQS)-1:0] rise_data_r; + wire [((RDF_FIFO_NUM -1) *2)+1:0] sb_ecc_error; + + + //*************************************************************************** + + always @(posedge clk0) begin + rden_sel_r <= ctrl_rden_sel; + ctrl_rden_r <= ctrl_rden; + rd_data_in_rise_r <= rd_data_in_rise; + rd_data_in_fall_r <= rd_data_in_fall; + end + + // Instantiate primitive to allow this flop to be attached to multicycle + // path constraint in UCF. Multicycle path allowed for data from read FIFO. + // This is the same signal as RDEN_SEL_R, but is only used to select data + // (does not affect control signals) + genvar rd_i; + generate + for (rd_i = 0; rd_i < DQS_WIDTH; rd_i = rd_i+1) begin: gen_rden_sel_mux + FDRSE u_ff_rden_sel_mux + ( + .Q (rden_sel_mux[rd_i]), + .C (clk0), + .CE (1'b1), + .D (ctrl_rden_sel[rd_i]), + .R (1'b0), + .S (1'b0) + ) /* synthesis syn_preserve=1 */; + end + endgenerate + + // determine correct read data valid signal timing + assign rden = (rden_sel_r[0]) ? ctrl_rden[0] : ctrl_rden_r[0]; + + // assign data based on the skew + genvar data_i; + generate + for(data_i = 0; data_i < DQS_WIDTH; data_i = data_i+1) begin: gen_data + assign rise_data[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): + (data_i*DQ_PER_DQS)] + = (rden_sel_mux[data_i]) ? + rd_data_in_rise[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1) : + (data_i*DQ_PER_DQS)] : + rd_data_in_rise_r[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): + (data_i*DQ_PER_DQS)]; + assign fall_data[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): + (data_i*DQ_PER_DQS)] + = (rden_sel_mux[data_i]) ? + rd_data_in_fall[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): + (data_i*DQ_PER_DQS)] : + rd_data_in_fall_r[(data_i*DQ_PER_DQS)+(DQ_PER_DQS-1): + (data_i*DQ_PER_DQS)]; + end + endgenerate + + // Generate RST for FIFO reset AND for read/write enable: + // ECC FIFO always being read from and written to + always @(posedge clk0) + rst_r <= rst0; + + genvar rdf_i; + generate + if (ECC_ENABLE) begin + always @(posedge clk0) begin + rd_ecc_error[0] <= (|sb_ecc_error) & fifo_rden_r5; + rd_ecc_error[1] <= (|db_ecc_error) & fifo_rden_r5; + rd_data_out_rise <= rd_data_out_rise_temp; + rd_data_out_fall <= rd_data_out_fall_temp; + rise_data_r <= rise_data; + fall_data_r <= fall_data; + end + + // can use any of the read valids, they're all delayed by same amount + assign rd_data_valid = fifo_rden_r6; + + // delay read valid to take into account max delay difference btw + // the read enable coming from the different DQS groups + always @(posedge clk0) begin + if (rst0) begin + fifo_rden_r0 <= 1'b0; + fifo_rden_r1 <= 1'b0; + fifo_rden_r2 <= 1'b0; + fifo_rden_r3 <= 1'b0; + fifo_rden_r4 <= 1'b0; + fifo_rden_r5 <= 1'b0; + fifo_rden_r6 <= 1'b0; + end else begin + fifo_rden_r0 <= rden; + fifo_rden_r1 <= fifo_rden_r0; + fifo_rden_r2 <= fifo_rden_r1; + fifo_rden_r3 <= fifo_rden_r2; + fifo_rden_r4 <= fifo_rden_r3; + fifo_rden_r5 <= fifo_rden_r4; + fifo_rden_r6 <= fifo_rden_r5; + end + end + + for (rdf_i = 0; rdf_i < RDF_FIFO_NUM; rdf_i = rdf_i + 1) begin: gen_rdf + + FIFO36_72 # // rise fifo + ( + .ALMOST_EMPTY_OFFSET (9'h007), + .ALMOST_FULL_OFFSET (9'h00F), + .DO_REG (1), // extra CC output delay + .EN_ECC_WRITE ("FALSE"), + .EN_ECC_READ ("TRUE"), + .EN_SYN ("FALSE"), + .FIRST_WORD_FALL_THROUGH ("FALSE") + ) + u_rdf + ( + .ALMOSTEMPTY (), + .ALMOSTFULL (), + .DBITERR (db_ecc_error[rdf_i + rdf_i]), + .DO (rd_data_out_rise_temp[(64*(rdf_i+1))-1: + (64 *rdf_i)]), + .DOP (), + .ECCPARITY (), + .EMPTY (), + .FULL (), + .RDCOUNT (), + .RDERR (), + .SBITERR (sb_ecc_error[rdf_i + rdf_i]), + .WRCOUNT (), + .WRERR (), + .DI (rise_data_r[((64*(rdf_i+1)) + (rdf_i*8))-1: + (64 *rdf_i)+(rdf_i*8)]), + .DIP (rise_data_r[(72*(rdf_i+1))-1: + (64*(rdf_i+1))+ (8*rdf_i)]), + .RDCLK (clk0), + .RDEN (~rst_r), + .RST (rst_r), + .WRCLK (clk0), + .WREN (~rst_r) + ); + + FIFO36_72 # // fall_fifo + ( + .ALMOST_EMPTY_OFFSET (9'h007), + .ALMOST_FULL_OFFSET (9'h00F), + .DO_REG (1), // extra CC output delay + .EN_ECC_WRITE ("FALSE"), + .EN_ECC_READ ("TRUE"), + .EN_SYN ("FALSE"), + .FIRST_WORD_FALL_THROUGH ("FALSE") + ) + u_rdf1 + ( + .ALMOSTEMPTY (), + .ALMOSTFULL (), + .DBITERR (db_ecc_error[(rdf_i+1) + rdf_i]), + .DO (rd_data_out_fall_temp[(64*(rdf_i+1))-1: + (64 *rdf_i)]), + .DOP (), + .ECCPARITY (), + .EMPTY (), + .FULL (), + .RDCOUNT (), + .RDERR (), + .SBITERR (sb_ecc_error[(rdf_i+1) + rdf_i]), + .WRCOUNT (), + .WRERR (), + .DI (fall_data_r[((64*(rdf_i+1)) + (rdf_i*8))-1: + (64*rdf_i)+(rdf_i*8)]), + .DIP (fall_data_r[(72*(rdf_i+1))-1: + (64*(rdf_i+1))+ (8*rdf_i)]), + .RDCLK (clk0), + .RDEN (~rst_r), + .RST (rst_r), // or can use rst0 + .WRCLK (clk0), + .WREN (~rst_r) + ); + end + end else begin + assign rd_data_valid = fifo_rden_r0; + always @(posedge clk0) begin + rd_data_out_rise <= rise_data; + rd_data_out_fall <= fall_data; + fifo_rden_r0 <= rden; + end + end + endgenerate + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl (revision 3)
trunk/rtl/ipcore_dir/MEMCtrl/user_design/rtl Property changes : Added: bugtraq:number ## -0,0 +1 ## +true \ No newline at end of property Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_cmp.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_cmp.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_cmp.v (revision 3) @@ -0,0 +1,266 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_tb_test_cmp.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Fri Sep 01 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module generates the error signal in case of bit errors. It compares +// the read data with expected data value. +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_tb_test_cmp # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter DQ_WIDTH = 72, + parameter APPDATA_WIDTH = 144, + parameter ECC_ENABLE = 0 + ) + ( + input clk, + input rst, + input phy_init_done, + input rd_data_valid, + input [APPDATA_WIDTH-1:0] app_cmp_data, + input [APPDATA_WIDTH-1:0] rd_data_fifo_in, + output reg error, + output reg error_cmp + ); + + wire [(APPDATA_WIDTH/16)-1:0] byte_err_fall; + reg [(APPDATA_WIDTH/16)-1:0] byte_err_fall_r; + wire [(APPDATA_WIDTH/16)-1:0] byte_err_rise; + reg [(APPDATA_WIDTH/16)-1:0] byte_err_rise_r; + wire [(APPDATA_WIDTH/2)-1:0] cmp_data_fall; + wire [(APPDATA_WIDTH/2)-1:0] cmp_data_rise; + wire [APPDATA_WIDTH-1:0] cmp_data_r; + reg [APPDATA_WIDTH-1:0] cmp_data_r1; + reg cmp_start; + wire [(APPDATA_WIDTH/2)-1:0] data_fall_r; + wire [(APPDATA_WIDTH/2)-1:0] data_rise_r; + reg err_fall; + reg err_rise; + reg error_tmp_r; + wire error_tmp_r1; + wire error_tmp_r2; + wire [APPDATA_WIDTH-1:0] rd_data_r; + wire [APPDATA_WIDTH-1:0] rd_data_r1; + reg [APPDATA_WIDTH-1:0] rd_data_r2; + wire rd_data_valid_r; + reg rd_data_valid_r1; + reg rd_data_valid_r2; + reg rst_r + /* synthesis syn_preserve = 1 */; + reg rst_r1 + /* synthesis syn_maxfan = 10 */; + + // 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" + + //*************************************************************************** + + // 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 larger than fanout on RST_R, otherwise SLICES will be + // used for fanout control on RST_R. + always @(posedge clk) begin + rst_r <= rst; + rst_r1 <= rst_r; + end + + // instantiate discrete flops for better timing + genvar rd_data_i; + generate + for (rd_data_i = 0; rd_data_i < APPDATA_WIDTH; + rd_data_i = rd_data_i + 1) begin: gen_rd_data + FDRSE ff_rd_data + ( + .Q (rd_data_r[rd_data_i]), + .C (clk), + .CE (1'b1), + .D (rd_data_fifo_in[rd_data_i]), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_rd_data_r1 + ( + .Q (rd_data_r1[rd_data_i]), + .C (clk), + .CE (1'b1), + .D (rd_data_r[rd_data_i]), + .R (1'b0), + .S (1'b0) + ); + end + endgenerate + + genvar cmp_data_i; + generate + for (cmp_data_i = 0; cmp_data_i < APPDATA_WIDTH; + cmp_data_i = cmp_data_i + 1) begin: gen_cmp_data + FDRSE ff_cmp_data + ( + .Q (cmp_data_r[cmp_data_i]), + .C (clk), + .CE (1'b1), + .D (app_cmp_data[cmp_data_i]), + .R (1'b0), + .S (1'b0) + ); + end + endgenerate + + assign data_fall_r = rd_data_r2[APPDATA_WIDTH-1:(APPDATA_WIDTH/2)]; + assign data_rise_r = rd_data_r2[(APPDATA_WIDTH/2)-1:0]; + assign cmp_data_fall = cmp_data_r[APPDATA_WIDTH-1:(APPDATA_WIDTH/2)]; + assign cmp_data_rise = cmp_data_r[(APPDATA_WIDTH/2)-1:0]; + + // Instantiate ff for timing. + FDRSE ff_rd_data_valid_r + ( + .Q (rd_data_valid_r), + .C (clk), + .CE (1'b1), + .D (rd_data_valid), + .R (1'b0), + .S (1'b0) + ); + + always @(posedge clk) begin + if (rst_r1) begin + rd_data_valid_r1 <= 1'd0; + end else begin + rd_data_valid_r1 <= rd_data_valid_r & phy_init_done; + end + end + + always @(posedge clk)begin + rd_data_r2 <= rd_data_r1; + cmp_data_r1 <= cmp_data_r; + rd_data_valid_r2 <= rd_data_valid_r1; + end + + genvar cmp_i; + generate + for (cmp_i = 0; cmp_i < APPDATA_WIDTH/16; cmp_i = cmp_i + 1) begin: gen_cmp + assign byte_err_fall[cmp_i] + = (rd_data_valid_r2 && + (data_fall_r[8*(cmp_i+1)-1:8*cmp_i] != + cmp_data_fall[8*(cmp_i+1)-1:8*cmp_i])); + assign byte_err_rise[cmp_i] + = (rd_data_valid_r2 && + (data_rise_r[8*(cmp_i+1)-1:8*cmp_i] != + cmp_data_rise[8*(cmp_i+1)-1:8*cmp_i])); + end + endgenerate + + always @(posedge clk) begin + byte_err_rise_r <= byte_err_rise; + byte_err_fall_r <= byte_err_fall; + end + + always @(posedge clk) + if (rst_r1) begin + err_rise <= 1'bx; + err_fall <= 1'bx; + cmp_start <= 1'b0; + error_tmp_r <= 1'b0; + end else begin + err_rise <= | byte_err_rise_r; + err_fall <= | byte_err_fall_r; + // start comparing when initialization/calibration complete, and we + // get first valid readback + if (rd_data_valid_r2) + cmp_start <= 1'b1; + if (cmp_start && !error_tmp_r) + error_tmp_r <= err_rise | err_fall; + //synthesis translate_off + if ((err_rise || err_fall) && cmp_start) + $display ("ERROR at time %t" , $time); + //synthesis translate_on + end + + // FF inst to force synthesis to infer ff's. + // Done for timing. + FDRSE ff_error_1 + ( + .Q (error_tmp_r1), + .C (clk), + .CE (1'b1), + .D (error_tmp_r), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_error_2 + ( + .Q (error_tmp_r2), + .C (clk), + .CE (1'b1), + .D (error_tmp_r1), + .R (1'b0), + .S (1'b0) + ); + + always @(posedge clk) begin + error <= error_tmp_r2; + error_cmp <= err_rise | err_fall; + end + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_data_gen.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_data_gen.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_data_gen.v (revision 3) @@ -0,0 +1,274 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_tb_test_data_gen.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Fri Sep 01 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module contains the data generation logic for the synthesizable +// testbench. +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_tb_test_data_gen # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter DM_WIDTH = 9, + parameter DQ_WIDTH = 72, + parameter APPDATA_WIDTH = 144, + parameter ECC_ENABLE = 0 + ) + ( + input clk, + input rst, + input wr_data_en, + input rd_data_valid, + output app_wdf_wren, + output reg [APPDATA_WIDTH-1:0] app_wdf_data, + output reg [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, + output [APPDATA_WIDTH-1:0] app_cmp_data + ); + + localparam WR_IDLE_FIRST_DATA = 2'b00; + localparam WR_SECOND_DATA = 2'b01; + localparam WR_THIRD_DATA = 2'b10; + localparam WR_FOURTH_DATA = 2'b11; + localparam RD_IDLE_FIRST_DATA = 2'b00; + localparam RD_SECOND_DATA = 2'b01; + localparam RD_THIRD_DATA = 2'b10; + localparam RD_FOURTH_DATA = 2'b11; + + reg [APPDATA_WIDTH-1:0] app_wdf_data_r; + reg [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data_r; + wire app_wdf_wren_r; + reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_fall; + reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_rise; + wire rd_data_valid_r; + reg [1:0] rd_state; + reg rst_r + /* synthesis syn_preserve = 1 */; + reg rst_r1 + /* synthesis syn_maxfan = 10 */; + wire [APPDATA_WIDTH-1:0] wr_data; + reg wr_data_en_r; + reg [(APPDATA_WIDTH/2)-1:0] wr_data_fall + /* synthesis syn_maxfan = 2 */; + reg [(APPDATA_WIDTH/2)-1:0] wr_data_rise + /* synthesis syn_maxfan = 2 */; + wire [(APPDATA_WIDTH/8)-1:0] wr_mask_data; + wire [(APPDATA_WIDTH/16)-1:0] wr_mask_data_fall; + wire [(APPDATA_WIDTH/16)-1:0] wr_mask_data_rise; + reg [1:0] wr_state; + + // 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" + + //*************************************************************************** + + // 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 larger than fanout on RST_R, otherwise SLICES will be + // used for fanout control on RST_R. + always @(posedge clk) begin + rst_r <= rst; + rst_r1 <= rst_r; + end + + always @(posedge clk) begin + app_wdf_data_r <= wr_data; + app_wdf_mask_data_r <= wr_mask_data; + app_wdf_data <= app_wdf_data_r; + app_wdf_mask_data <= app_wdf_mask_data_r; + end + + // inst ff for timing + FDRSE ff_wdf_wren + ( + .Q (app_wdf_wren_r), + .C (clk), + .CE (1'b1), + .D (wr_data_en_r), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_wdf_wren_r + ( + .Q (app_wdf_wren), + .C (clk), + .CE (1'b1), + .D (app_wdf_wren_r), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_rd_data_valid_r + ( + .Q (rd_data_valid_r), + .C (clk), + .CE (1'b1), + .D (rd_data_valid), + .R (1'b0), + .S (1'b0) + ); + + //*************************************************************************** + // DATA generation for WRITE DATA FIFOs & for READ DATA COMPARE + //*************************************************************************** + + assign wr_data = {wr_data_fall, wr_data_rise}; + assign wr_mask_data = {wr_mask_data_fall, wr_mask_data_rise}; + + //***************************************************************** + // For now, don't vary data masks + //***************************************************************** + + assign wr_mask_data_rise = {(APPDATA_WIDTH/8){1'b0}}; + assign wr_mask_data_fall = {(APPDATA_WIDTH/8){1'b0}}; + + //***************************************************************** + // Write data logic + //***************************************************************** + + // write data generation + //synthesis attribute max_fanout of wr_data_fall is 2 + //synthesis attribute max_fanout of wr_data_rise is 2 + always @(posedge clk) begin + if (rst_r1) begin + wr_data_rise <= {(APPDATA_WIDTH/2){1'bx}}; + wr_data_fall <= {(APPDATA_WIDTH/2){1'bx}}; + wr_state <= WR_IDLE_FIRST_DATA; + end else begin + case (wr_state) + WR_IDLE_FIRST_DATA: + if (wr_data_en) begin + wr_data_rise <= {(APPDATA_WIDTH/2){1'b1}}; // 0xF + wr_data_fall <= {(APPDATA_WIDTH/2){1'b0}}; // 0x0 + wr_state <= WR_SECOND_DATA; + end + WR_SECOND_DATA: + if (wr_data_en) begin + wr_data_rise <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA + wr_data_fall <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 + wr_state <= WR_THIRD_DATA; + end + WR_THIRD_DATA: + if (wr_data_en) begin + wr_data_rise <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 + wr_data_fall <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA + wr_state <= WR_FOURTH_DATA; + end + WR_FOURTH_DATA: + if (wr_data_en) begin + wr_data_rise <= {(APPDATA_WIDTH/8){4'b1001}}; // 0x9 + wr_data_fall <= {(APPDATA_WIDTH/8){4'b0110}}; // 0x6 + wr_state <= WR_IDLE_FIRST_DATA; + end + endcase + end + end + + always @(posedge clk) + if (rst_r1) + wr_data_en_r <= 1'b0; + else + wr_data_en_r <= wr_data_en; + + //***************************************************************** + // Read data logic + //***************************************************************** + + // read comparison data generation + always @(posedge clk) + if (rst_r1) begin + rd_data_pat_rise <= {(APPDATA_WIDTH/2){1'bx}}; + rd_data_pat_fall <= {(APPDATA_WIDTH/2){1'bx}}; + rd_state <= RD_IDLE_FIRST_DATA; + end else begin + case (rd_state) + RD_IDLE_FIRST_DATA: + if (rd_data_valid_r) + begin + rd_data_pat_rise <= {(APPDATA_WIDTH/2){1'b1}}; // 0xF + rd_data_pat_fall <= {(APPDATA_WIDTH/2){1'b0}}; // 0x0 + rd_state <= RD_SECOND_DATA; + end + RD_SECOND_DATA: + if (rd_data_valid_r) begin + rd_data_pat_rise <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA + rd_data_pat_fall <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 + rd_state <= RD_THIRD_DATA; + end + RD_THIRD_DATA: + if (rd_data_valid_r) begin + rd_data_pat_rise <= {(APPDATA_WIDTH/4){2'b01}}; // 0x5 + rd_data_pat_fall <= {(APPDATA_WIDTH/4){2'b10}}; // 0xA + rd_state <= RD_FOURTH_DATA; + end + RD_FOURTH_DATA: + if (rd_data_valid_r) begin + rd_data_pat_rise <= {(APPDATA_WIDTH/8){4'b1001}}; // 0x9 + rd_data_pat_fall <= {(APPDATA_WIDTH/8){4'b0110}}; // 0x6 + rd_state <= RD_IDLE_FIRST_DATA; + end + endcase + end + + //data to the compare circuit during read + assign app_cmp_data = {rd_data_pat_fall, rd_data_pat_rise}; + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_addr_gen.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_addr_gen.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_addr_gen.v (revision 3) @@ -0,0 +1,239 @@ +//***************************************************************************** +// 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_tb_test_addr_gen.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Fri Sep 01 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// The address for the memory and the various user commands can be given +// through this module. It instantiates the block RAM which stores all the +// information in particular sequence. The data stored should be in a +// sequence starting from LSB: +// column address, row address, bank address, commands. +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_tb_test_addr_gen # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter COL_WIDTH = 10, + parameter ROW_WIDTH = 14 + ) + ( + input clk, + input rst, + input wr_addr_en, + output reg [2:0] app_af_cmd, + output reg [30:0] app_af_addr, + output reg app_af_wren + ); + + // RAM initialization patterns + // NOTE: Not all bits in each range may be used (e.g. in an application + // using only 10 column bits, bits[11:10] of ROM output will be unused + // COLUMN = [11:0] + // ROW = [27:12] + // BANK = [30:28] + // CHIP = [31] + // COMMAND = [35:32] + + localparam RAM_INIT_00 = {128'h800020C0_800020C8_000020D0_000020D8, + 128'h000010E0_000010E8_800010F0_800010F8}; + localparam RAM_INIT_01 = {128'h800020C0_800020C8_000020D0_000020D8, + 128'h000010E0_000010E8_800010F0_800010F8}; + localparam RAM_INIT_02 = {128'h100040C0_100040C8_900040D0_900040D8, + 128'h900030E0_900030E8_100030F0_100030F8}; + localparam RAM_INIT_03 = {128'h100040C0_100040C8_900040D0_900040D8, + 128'h900030E0_900030E8_100030F0_100030F8}; + localparam RAM_INIT_04 = {128'hA00060C0_200060C8_200060D0_A00060D8, + 128'h200050E0_A00050E8_A00050F0_200050F8}; + localparam RAM_INIT_05 = {128'hA00060C0_200060C8_200060D0_A00060D8, + 128'h200050E0_A00050E8_A00050F0_200050F8}; + localparam RAM_INIT_06 = {128'h300080C0_B00080C8_B00080D0_300080D8, + 128'hB00070E0_300070E8_300070F0_B00070F8}; + localparam RAM_INIT_07 = {128'h300080C0_B00080C8_B00080D0_300080D8, + 128'hB00070E0_300070E8_300070F0_B00070F8}; + localparam RAM_INITP_00 = {128'h11111111_00000000_11111111_00000000, + 128'h11111111_00000000_11111111_00000000}; + + reg wr_addr_en_r1; + reg [2:0] af_cmd_r; + reg [30:0] af_addr_r; + reg af_wren_r; + wire [15:0] ramb_addr; + wire [35:0] ramb_dout; + reg rst_r + /* synthesis syn_preserve = 1 */; + reg rst_r1 + /* synthesis syn_maxfan = 10 */; + reg [5:0] wr_addr_cnt; + reg wr_addr_en_r0; + + // 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" + + //***************************************************************** + + // 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 larger than fanout on RST_R, otherwise SLICES will be + // used for fanout control on RST_R. + always @(posedge clk) begin + rst_r <= rst; + rst_r1 <= rst_r; + end + + //*************************************************************************** + // ADDRESS generation for Write and Read Address FIFOs: + // ROM with address patterns + // 512x36 mode is used with addresses 0-127 for storing write addresses and + // addresses (128-511) for storing read addresses + // INIP_OO: read 1 + // INIP_OO: write 0 + //*************************************************************************** + + assign ramb_addr = {5'b00000, wr_addr_cnt, 5'b00000}; + + RAMB36 # + ( + .READ_WIDTH_A (36), + .READ_WIDTH_B (36), + .DOA_REG (1), // register to help timing + .INIT_00 (RAM_INIT_00), + .INIT_01 (RAM_INIT_01), + .INIT_02 (RAM_INIT_02), + .INIT_03 (RAM_INIT_03), + .INIT_04 (RAM_INIT_04), + .INIT_05 (RAM_INIT_05), + .INIT_06 (RAM_INIT_06), + .INIT_07 (RAM_INIT_07), + .INITP_00 (RAM_INITP_00) + ) + u_wr_rd_addr_lookup + ( + .CASCADEOUTLATA (), + .CASCADEOUTLATB (), + .CASCADEOUTREGA (), + .CASCADEOUTREGB (), + .DOA (ramb_dout[31:0]), + .DOB (), + .DOPA (ramb_dout[35:32]), + .DOPB (), + .ADDRA (ramb_addr), + .ADDRB (16'h0000), + .CASCADEINLATA (), + .CASCADEINLATB (), + .CASCADEINREGA (), + .CASCADEINREGB (), + .CLKA (clk), + .CLKB (clk), + .DIA (32'b0), + .DIB (32'b0), + .DIPA (4'b0), + .DIPB (4'b0), + .ENA (1'b1), + .ENB (1'b1), + .REGCEA (1'b1), + .REGCEB (1'b1), + .SSRA (1'b0), + .SSRB (1'b0), + .WEA (4'b0000), + .WEB (4'b0000) + ); + + // register backend enables / FIFO enables + // write enable for Command/Address FIFO is generated 2 CC after WR_ADDR_EN + // (takes 2 CC to come out of test RAM) + always @(posedge clk) + if (rst_r1) begin + app_af_wren <= 1'b0; + wr_addr_en_r0 <= 1'b0; + wr_addr_en_r1 <= 1'b0; + af_wren_r <= 1'b0; + end else begin + wr_addr_en_r0 <= wr_addr_en; + wr_addr_en_r1 <= wr_addr_en_r0; + af_wren_r <= wr_addr_en_r1; + app_af_wren <= af_wren_r; + end + + // FIFO addresses + always @(posedge clk) begin + af_addr_r <= {30{1'b0}}; + af_addr_r[COL_WIDTH-1:0] <= ramb_dout[COL_WIDTH-1:0]; + af_addr_r[ROW_WIDTH+COL_WIDTH-1:COL_WIDTH] + <= ramb_dout[ROW_WIDTH+11:12]; + af_addr_r[BANK_WIDTH+ROW_WIDTH+COL_WIDTH-1:ROW_WIDTH+COL_WIDTH] + <= ramb_dout[BANK_WIDTH+27:28]; + af_addr_r[BANK_WIDTH+ROW_WIDTH+COL_WIDTH] + <= ramb_dout[31]; + // only reads and writes are supported for now + af_cmd_r <= {1'b0, ramb_dout[33:32]}; + app_af_cmd <= af_cmd_r; + app_af_addr <= af_addr_r; + end + + // address input for RAM + always @ (posedge clk) + if (rst_r1) + wr_addr_cnt <= 6'b000000; + else if (wr_addr_en) + wr_addr_cnt <= wr_addr_cnt + 1; + + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_top.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_top.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_top.v (revision 3) @@ -0,0 +1,322 @@ +//***************************************************************************** +// 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 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_tb_top.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Fri Sep 01 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module is the synthesizable test bench for the memory interface. +// This Test bench is to compare the write and the read data and generate +// an error flag. +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_tb_top # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter COL_WIDTH = 10, + parameter DM_WIDTH = 9, + parameter DQ_WIDTH = 72, + parameter ROW_WIDTH = 14, + parameter APPDATA_WIDTH = 144, + parameter ECC_ENABLE = 0, + parameter BURST_LEN = 4 + ) + ( + input clk0, + input rst0, + input app_af_afull, + input app_wdf_afull, + input rd_data_valid, + input [APPDATA_WIDTH-1:0] rd_data_fifo_out, + input phy_init_done, + output app_af_wren, + output [2:0] app_af_cmd, + output [30:0] app_af_addr, + output app_wdf_wren, + output [APPDATA_WIDTH-1:0] app_wdf_data, + output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, + output error, + output error_cmp + ); + + localparam BURST_LEN_DIV2 = BURST_LEN/2; + + localparam TB_IDLE = 3'b000; + localparam TB_WRITE = 3'b001; + localparam TB_READ = 3'b010; + + wire app_af_afull_r ; + wire app_af_afull_r1 ; + wire app_af_afull_r2; + reg app_af_not_afull_r; + wire [APPDATA_WIDTH-1:0] app_cmp_data; + wire app_wdf_afull_r; + wire app_wdf_afull_r1 ; + wire app_wdf_afull_r2; + reg app_wdf_not_afull_r ; + reg [2:0] burst_cnt; + reg phy_init_done_tb_r; + wire phy_init_done_r; + reg rst_r + /* synthesis syn_preserve = 1 */; + reg rst_r1 + /* synthesis syn_maxfan = 10 */; + reg [2:0] state; + reg [3:0] state_cnt; + reg wr_addr_en ; + reg wr_data_en ; + + // 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" + + //***************************************************************** + + // 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 larger than fanout on RST_R, otherwise SLICES will be + // used for fanout control on RST_R. + always @(posedge clk0) begin + rst_r <= rst0; + rst_r1 <= rst_r; + end + + // Instantiate flops for timing. + FDRSE ff_af_afull_r + ( + .Q (app_af_afull_r), + .C (clk0), + .CE (1'b1), + .D (app_af_afull), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_af_afull_r1 + ( + .Q (app_af_afull_r1), + .C (clk0), + .CE (1'b1), + .D (app_af_afull_r), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_af_afull_r2 + ( + .Q (app_af_afull_r2), + .C (clk0), + .CE (1'b1), + .D (app_af_afull_r1), + .R (1'b0), + .S (1'b0) + ); + + + FDRSE ff_wdf_afull_r + ( + .Q (app_wdf_afull_r), + .C (clk0), + .CE (1'b1), + .D (app_wdf_afull), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_wdf_afull_r1 + ( + .Q (app_wdf_afull_r1), + .C (clk0), + .CE (1'b1), + .D (app_wdf_afull_r), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_wdf_afull_r2 + ( + .Q (app_wdf_afull_r2), + .C (clk0), + .CE (1'b1), + .D (app_wdf_afull_r1), + .R (1'b0), + .S (1'b0) + ); + + FDRSE ff_phy_init_done + ( + .Q (phy_init_done_r), + .C (clk0), + .CE (1'b1), + .D (phy_init_done), + .R (1'b0), + .S (1'b0) + ); + + //*************************************************************************** + // State Machine for writing to WRITE DATA & ADDRESS FIFOs + // state machine changed for low FIFO threshold values + //*************************************************************************** + + always @(posedge clk0) begin + if (rst_r1) begin + wr_data_en <= 1'bx; + wr_addr_en <= 1'bx; + state[2:0] <= TB_IDLE; + state_cnt <= 4'bxxxx; + app_af_not_afull_r <= 1'bx; + app_wdf_not_afull_r <= 1'bx; + burst_cnt <= 3'bxxx; + phy_init_done_tb_r <= 1'bx; + end else begin + wr_data_en <= 1'b0; + wr_addr_en <= 1'b0; + app_af_not_afull_r <= ~app_af_afull_r2; + app_wdf_not_afull_r <= ~app_wdf_afull_r2; + phy_init_done_tb_r <= phy_init_done_r; + + case (state) + TB_IDLE: begin + state_cnt <= 4'd0; + burst_cnt <= BURST_LEN_DIV2 - 1; + // only start writing when initialization done + if (app_wdf_not_afull_r && app_af_not_afull_r && phy_init_done_tb_r) + state <= TB_WRITE; + end + + TB_WRITE: + if (app_wdf_not_afull_r && app_af_not_afull_r) begin + wr_data_en <= 1'b1; + // When we're done with the current burst... + if (burst_cnt == 3'd0) begin + burst_cnt <= BURST_LEN_DIV2 - 1; + wr_addr_en <= 1'b1; + // Writes occurs in groups of 8 consecutive bursts. Once 8 writes + // have been issued, now issue the corresponding read back bursts + if (state_cnt == 4'd7) begin + state <= TB_READ; + state_cnt <= 4'd0; + end else + state_cnt <= state_cnt + 1; + end else + burst_cnt <= burst_cnt - 1; + end + + TB_READ: begin + burst_cnt <= BURST_LEN_DIV2 - 1; + if (app_af_not_afull_r) begin + wr_addr_en <= 1'b1; + // if finished with all 8 reads, proceed to next 8 writes + if (state_cnt == 4'd7) begin + state <= TB_WRITE; + state_cnt <= 4'd0; + end else + state_cnt <= state_cnt + 1; + end + end + endcase + end + end + + // Read data comparision + ddr2_tb_test_cmp # + ( + .DQ_WIDTH (DQ_WIDTH), + .APPDATA_WIDTH (APPDATA_WIDTH), + .ECC_ENABLE (ECC_ENABLE) + ) + u_tb_test_cmp + ( + .clk (clk0), + .rst (rst0), + .phy_init_done (phy_init_done_tb_r), + .rd_data_valid (rd_data_valid), + .app_cmp_data (app_cmp_data), + .rd_data_fifo_in (rd_data_fifo_out), + .error (error), + .error_cmp (error_cmp) + ); + + // Command/Address and Write Data generation + ddr2_tb_test_gen # + ( + .BANK_WIDTH (BANK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .DM_WIDTH (DM_WIDTH), + .DQ_WIDTH (DQ_WIDTH), + .APPDATA_WIDTH (APPDATA_WIDTH), + .ECC_ENABLE (ECC_ENABLE), + .ROW_WIDTH (ROW_WIDTH) + ) + u_tb_test_gen + ( + .clk (clk0), + .rst (rst0), + .wr_addr_en (wr_addr_en), + .wr_data_en (wr_data_en), + .rd_data_valid (rd_data_valid), + .app_af_wren (app_af_wren), + .app_af_cmd (app_af_cmd), + .app_af_addr (app_af_addr), + .app_wdf_wren (app_wdf_wren), + .app_wdf_data (app_wdf_data), + .app_wdf_mask_data (app_wdf_mask_data), + .app_cmp_data (app_cmp_data) + ); + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_gen.v =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_gen.v (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim/ddr2_tb_test_gen.v (revision 3) @@ -0,0 +1,128 @@ +//***************************************************************************** +// 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 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.6.1 +// \ \ Application: MIG +// / / Filename: ddr2_tb_test_gen.v +// /___/ /\ Date Last Modified: $Date: 2010/11/26 18:26:02 $ +// \ \ / \ Date Created: Fri Sep 01 2006 +// \___\/\___\ +// +//Device: Virtex-5 +//Design Name: DDR2 +//Purpose: +// This module instantiates the addr_gen and the data_gen modules. It takes +// the user data stored in internal FIFOs and gives the data that is to be +// compared with the read data +//Reference: +//Revision History: +//***************************************************************************** + +`timescale 1ns/1ps + +module ddr2_tb_test_gen # + ( + // 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 MEMCtrl module. Please refer to + // the MEMCtrl module for actual values. + parameter BANK_WIDTH = 2, + parameter COL_WIDTH = 10, + parameter DM_WIDTH = 9, + parameter DQ_WIDTH = 72, + parameter APPDATA_WIDTH = 144, + parameter ECC_ENABLE = 0, + parameter ROW_WIDTH = 14 + ) + ( + input clk, + input rst, + input wr_addr_en, + input wr_data_en, + input rd_data_valid, + output app_af_wren, + output [2:0] app_af_cmd, + output [30:0] app_af_addr, + output app_wdf_wren, + output [APPDATA_WIDTH-1:0] app_wdf_data, + output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data, + output [APPDATA_WIDTH-1:0] app_cmp_data + ); + + //*************************************************************************** + + ddr2_tb_test_addr_gen # + ( + .BANK_WIDTH (BANK_WIDTH), + .COL_WIDTH (COL_WIDTH), + .ROW_WIDTH (ROW_WIDTH) + ) + u_addr_gen + ( + .clk (clk), + .rst (rst), + .wr_addr_en (wr_addr_en), + .app_af_cmd (app_af_cmd), + .app_af_addr (app_af_addr), + .app_af_wren (app_af_wren) + ); + + ddr2_tb_test_data_gen # + ( + .DM_WIDTH (DM_WIDTH), + .DQ_WIDTH (DQ_WIDTH), + .APPDATA_WIDTH (APPDATA_WIDTH), + .ECC_ENABLE (ECC_ENABLE) + ) + u_data_gen + ( + .clk (clk), + .rst (rst), + .wr_data_en (wr_data_en), + .rd_data_valid (rd_data_valid), + .app_wdf_wren (app_wdf_wren), + .app_wdf_data (app_wdf_data), + .app_wdf_mask_data (app_wdf_mask_data), + .app_cmp_data (app_cmp_data) + ); + +endmodule Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim (revision 3)
trunk/rtl/ipcore_dir/MEMCtrl/user_design/sim Property changes : Added: bugtraq:number ## -0,0 +1 ## +true \ No newline at end of property Index: trunk/rtl/ipcore_dir/MEMCtrl/user_design =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl/user_design (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl/user_design (revision 3)
trunk/rtl/ipcore_dir/MEMCtrl/user_design Property changes : Added: bugtraq:number ## -0,0 +1 ## +true \ No newline at end of property Index: trunk/rtl/ipcore_dir/MEMCtrl =================================================================== --- trunk/rtl/ipcore_dir/MEMCtrl (nonexistent) +++ trunk/rtl/ipcore_dir/MEMCtrl (revision 3)
trunk/rtl/ipcore_dir/MEMCtrl Property changes : Added: bugtraq:number ## -0,0 +1 ## +true \ No newline at end of property Index: trunk/rtl/ipcore_dir =================================================================== --- trunk/rtl/ipcore_dir (nonexistent) +++ trunk/rtl/ipcore_dir (revision 3)
trunk/rtl/ipcore_dir Property changes : Added: bugtraq:number ## -0,0 +1 ## +true \ No newline at end of property Index: trunk/rtl/debounceRst.v =================================================================== --- trunk/rtl/debounceRst.v (revision 2) +++ trunk/rtl/debounceRst.v (revision 3) @@ -37,7 +37,7 @@ wire async_rst, PLLRst, rst_edge, start_up_rst; - // --4-bit Shift Register For resetting the DCM on startup (Xilinx Answer Record: 14425) + // --4-bit Shift Register For resetting the PLL //--Asserts Start_Up_Rst for 4 clock periods SRL16E #( @@ -65,8 +65,8 @@ //---------------------------------------------------------------------------------- //-- Reset with take-off and landing - //-- delay 95 cc = RST_SYNC_NUM - 4 reset - //-- then keep it active for 3 cc (as long as one of RstQ(RST_SYNC_NUM-2), RstQ(RST_SYNC_NUM-3) or RstQ(RST_SYNC_NUM-4) is 0) + //-- delay 95 cc = DELAY_CC - 4 reset + //-- then keep it active for 3 cc (as long as one of rst_debounce_delay_loop[DELAY_CC-2], rst_debounce_delay_loop[DELAY_CC-3] or rst_debounce_delay_loop[DELAY_CC-4] is 0) //---------------------------------------------------------------------------------- always @(posedge clk) begin @@ -79,11 +79,11 @@ assign int_rst = ~PLLLocked; - //decrement counter for 100 cc then RstD(RstD'high) becomes 0 + //decrement counter for 100 cc then rst_cnt_delay[BITS_DELAY_CC-1] becomes 0 always @(posedge clk) begin if (int_rst) - rst_cnt_delay <= 228;//DELAY_CC + {1'b1, {(BITS_DELAY_CC-2){1'b0}}};//{1'b1, (BITS_DELAY_CC-1)'dDELAY_CC}; + rst_cnt_delay <= 228;//DELAY_CC + {1'b1, {(BITS_DELAY_CC-2){1'b0}}}; else if (rst_cnt_delay[BITS_DELAY_CC-1]) rst_cnt_delay <= rst_cnt_delay - 1;
/trunk/rtl/ddr2_adr_data_gen.v
0,0 → 1,159
//*****************************************************************************
// Company: UPT
// Engineer: Oana Boncalo & Alexandru Amaricai
//
// Create Date: 10:23:39 11/26/2012
// Design Name:
// Module Name: DDR2 user IF address and data generation
// Project Name:
// Target Devices:
// Tool versions:
//Device: Virtex-5
//Purpose:
// This module instantiates the addr_gen and the data_gen modules. It takes
// the user data stored in internal FIFOs and gives the data that is to be
// compared with the read data
//Reference:
//Revision History:
//*****************************************************************************
 
`timescale 1ns/1ps
 
module ddr2_adr_data_gen #
(
// 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 MEMCtrl module. Please refer to
// the MEMCtrl module for actual values.
parameter BANK_WIDTH = 2,
parameter COL_WIDTH = 10,
parameter DM_WIDTH = 9,
parameter DQ_WIDTH = 72,
parameter APPDATA_WIDTH = 144,
parameter ECC_ENABLE = 0,
parameter ROW_WIDTH = 14
)
(
input clk,
input rst,
input wr_addr_en,
input wr_data_en,
input rd_op,
input rd_data_valid,
input [30:0] bus_if_addr,
input [APPDATA_WIDTH-1:0] bus_if_wr_data,
input [(APPDATA_WIDTH/8)-1:0] bus_if_wr_mask_data,
output reg app_af_wren,
output [2:0] app_af_cmd,
output [30:0] app_af_addr,
output app_wdf_wren,
output [APPDATA_WIDTH-1:0] app_wdf_data,
output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data
);
//data
localparam RD_IDLE_FIRST_DATA = 2'b00;
localparam RD_SECOND_DATA = 2'b01;
localparam RD_THIRD_DATA = 2'b10;
localparam RD_FOURTH_DATA = 2'b11;
//address
reg wr_addr_en_r1;
reg [2:0] af_cmd_r;//, af_cmd_r0, af_cmd_r1;
reg af_wren_r;
reg rst_r
/* synthesis syn_preserve = 1 */;
reg rst_r1
/* synthesis syn_maxfan = 10 */;
reg [5:0] wr_addr_r;
reg wr_addr_en_r0;
//data
reg [APPDATA_WIDTH-1:0] app_wdf_data_r;
reg [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data_r;
wire app_wdf_wren_r;
reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_fall;
reg [(APPDATA_WIDTH/2)-1:0] rd_data_pat_rise;
reg [1:0] rd_state;
wire [APPDATA_WIDTH-1:0] wr_data;
reg wr_data_en_r;
reg [(APPDATA_WIDTH/2)-1:0] wr_data_fall
/* synthesis syn_maxfan = 2 */;
reg [(APPDATA_WIDTH/2)-1:0] wr_data_rise
/* synthesis syn_maxfan = 2 */;
wire [(APPDATA_WIDTH/8)-1:0] wr_mask_data;
 
//***************************************************************************
// 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 larger than fanout on RST_R, otherwise SLICES will be
// used for fanout control on RST_R.
always @(posedge clk) begin
rst_r <= rst;
rst_r1 <= rst_r;
end
// register backend enables / FIFO enables
// write enable for Command/Address FIFO is generated 1 CC after WR_ADDR_EN
always @(posedge clk)
if (rst_r1) begin
app_af_wren <= 1'b0;
end else begin
app_af_wren <= wr_addr_en;
end
 
always @ (posedge clk)
if (rst_r1)
wr_addr_r <= 0;
else if (wr_addr_en && (rd_op == 1'b0))
wr_addr_r <= bus_if_addr;
 
assign app_af_addr = wr_addr_r;
assign app_af_cmd = af_cmd_r;
always @ (posedge clk)
begin
af_cmd_r <= 0;
if (rd_op)
af_cmd_r <= 3'b001;
end
 
 
//data
assign app_wdf_data = wr_data;
assign app_wdf_mask_data = wr_mask_data;
// inst ff for timing
FDRSE ff_wdf_wren
(
.Q (app_wdf_wren),
.C (clk),
.CE (1'b1),
.D (wr_data_en),
.R (1'b0),
.S (1'b0)
);
 
assign wr_data = {wr_data_fall, wr_data_rise};
assign wr_mask_data = bus_if_wr_mask_data;
//data latching
//synthesis attribute max_fanout of wr_data_fall is 2
//synthesis attribute max_fanout of wr_data_rise is 2
always @(posedge clk)
begin
if (rst_r1)
begin
wr_data_rise <= {(APPDATA_WIDTH/2){1'bx}};
wr_data_fall <= {(APPDATA_WIDTH/2){1'bx}};
end
else
if (wr_data_en)
begin
wr_data_rise <= bus_if_wr_data[(APPDATA_WIDTH/2)-1:0];
wr_data_fall <= bus_if_wr_data[APPDATA_WIDTH-1:(APPDATA_WIDTH/2)];
end
end
 
endmodule
/trunk/rtl/ddr2_user_if_top.v
0,0 → 1,211
//*****************************************************************************
// Company: UPT
// Engineer: Oana Boncalo & Alexandru Amaricai
//
// Create Date: 10:23:39 11/26/2012
// Design Name:
// Module Name: DDR2 user IF for Genesys board
// Project Name:
// Target Devices:
// Tool versions:
//Device: Virtex-5
//Reference:
//Revision History:
//*****************************************************************************
 
`timescale 1ns/1ps
 
module ddr2_user_if_top #
(
// 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 MEMCtrl module. Please refer to
// the MEMCtrl module for actual values.
parameter BANK_WIDTH = 2,
parameter COL_WIDTH = 10,
parameter DM_WIDTH = 9,
parameter DQ_WIDTH = 72,
parameter ROW_WIDTH = 14,
parameter APPDATA_WIDTH = 144,
parameter ECC_ENABLE = 0,
parameter BURST_LEN = 4
)
(
input clk0,
input rst0,
input app_af_afull,
input app_wdf_afull,
input rd_data_valid,
input [APPDATA_WIDTH-1:0] rd_data_fifo_out,
input phy_init_done,
input rd_cmd,
input wr_cmd,
input [30:0] bus_if_addr,
input [APPDATA_WIDTH-1:0] bus_if_wr_data,
input [(APPDATA_WIDTH/8)-1:0] bus_if_wr_mask_data,
output end_op,
output req_wd,
output app_af_wren,
output [2:0] app_af_cmd,
output [30:0] app_af_addr,
output app_wdf_wren,
output [APPDATA_WIDTH-1:0] app_wdf_data,
output [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data,
output error,
output error_cmp
);
 
localparam BURST_LEN_DIV2 = BURST_LEN/2;
 
localparam IDLE_CMD = 3'b000;
localparam WRITE_CMD = 3'b001;
localparam READ_CMD = 3'b010;
 
reg app_af_not_afull_r;
wire [APPDATA_WIDTH-1:0] app_cmp_data;
reg app_wdf_not_afull_r ;
reg [2:0] burst_cnt;
reg phy_init_done_tb_r;
wire phy_init_done_r;
reg rst_r
/* synthesis syn_preserve = 1 */;
reg rst_r1
/* synthesis syn_maxfan = 10 */;
reg [2:0] state;
reg [3:0] state_cnt;
reg wr_addr_en ;
reg wr_data_en ;
reg rd_op;
reg end_op_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"
 
//*****************************************************************
 
// 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 larger than fanout on RST_R, otherwise SLICES will be
// used for fanout control on RST_R.
always @(posedge clk0) begin
rst_r <= rst0;
rst_r1 <= rst_r;
end
 
// Instantiate flops for timing.
FDRSE ff_phy_init_done
(
.Q (phy_init_done_r),
.C (clk0),
.CE (1'b1),
.D (phy_init_done),
.R (1'b0),
.S (1'b0)
);
 
assign end_op = end_op_r;
//***************************************************************************
// State Machine for writing to WRITE DATA & ADDRESS FIFOs
// state machine changed for low FIFO threshold values
//***************************************************************************
 
always @(posedge clk0) begin
if (rst_r1) begin
wr_data_en <= 1'bx;
wr_addr_en <= 1'bx;
state[2:0] <= IDLE_CMD;
state_cnt <= 4'bxxxx;
app_af_not_afull_r <= 1'bx;
app_wdf_not_afull_r <= 1'bx;
burst_cnt <= 3'bxxx;
phy_init_done_tb_r <= 1'bx;
rd_op <= 1'bx;
end_op_r <= 1'bx;
end else begin
wr_data_en <= 1'b0;
wr_addr_en <= 1'b0;
rd_op <= 1'b0;
end_op_r <= 1'b0;
app_af_not_afull_r <= ~app_af_afull;
app_wdf_not_afull_r <= ~app_wdf_afull;
phy_init_done_tb_r <= phy_init_done_r;
 
case (state)
IDLE_CMD: begin
state_cnt <= 4'd0;
burst_cnt <= BURST_LEN_DIV2 - 1;
end_op_r <= 1'b0;
// only start writing when initialization done
if (app_wdf_not_afull_r && app_af_not_afull_r && phy_init_done_tb_r)
begin
if (rd_cmd)
state <= READ_CMD;
if (wr_cmd)
state <= WRITE_CMD;
end
end
 
WRITE_CMD:
if (app_wdf_not_afull_r && app_af_not_afull_r)
begin
wr_data_en <= 1'b1;
// When we're done with the current burst...
if (burst_cnt == 3'd0)
begin
wr_addr_en <= 1'b1;
state <= IDLE_CMD;
end_op_r <= 1'b1;
end
else
burst_cnt <= burst_cnt - 1;
end
 
READ_CMD: begin
burst_cnt <= BURST_LEN_DIV2 - 1;
if (app_af_not_afull_r)
begin
wr_addr_en <= 1'b1;
rd_op <= 1'b1;
state <= IDLE_CMD;
end_op_r <= 1'b1;
end
end
endcase
end
end
assign req_wd = (!wr_addr_en && wr_data_en)? 1'b1:1'b0;
 
// Command/Address and Write Data generation
ddr2_adr_data_gen #
(
.BANK_WIDTH (BANK_WIDTH),
.COL_WIDTH (COL_WIDTH),
.DM_WIDTH (DM_WIDTH),
.DQ_WIDTH (DQ_WIDTH),
.APPDATA_WIDTH (APPDATA_WIDTH),
.ECC_ENABLE (ECC_ENABLE),
.ROW_WIDTH (ROW_WIDTH)
)
u_adr_data_gen
(
.clk (clk0),
.rst (rst0),
.wr_addr_en (wr_addr_en),
.wr_data_en (wr_data_en),
.rd_op (rd_op),
.rd_data_valid (rd_data_valid),
.bus_if_addr (bus_if_addr),
.app_af_wren (app_af_wren),
.bus_if_wr_mask_data(bus_if_wr_mask_data),
.bus_if_wr_data (bus_if_wr_data),
.app_af_cmd (app_af_cmd),
.app_af_addr (app_af_addr),
.app_wdf_wren (app_wdf_wren),
.app_wdf_data (app_wdf_data),
.app_wdf_mask_data (app_wdf_mask_data)
);
 
endmodule
/trunk/README.txt
0,0 → 1,84
genesys_ddr2: DDR2 memory controller for Digilent Genesys board
===================================================
 
 
What is this stuff?
==================
 
This is DDR2 memory controller for Digilent Genesys Board with wishbone slave interface and synthesizable test bench.
 
This IP is made-of several design files structured in the following directories:
- rtl: the user interface for the DDR2, the wishbone interface, external PLL clock generator, reset button debouncer as well as global reset generator
- rtl\ipcore_dir\MemCtrl: the DDR2 memory controller files generated by Xilinx MIG tool
- par: ucf file used for testing the synthesisable bench. The ucf file contains the memory pin placement as well as a reset pin connected to button from LOC = "G7"
- bench: synthesisable test files - top level module (test_DDR2_wb.v) and simple wishbone master mock that generates burst transactions for write followed by a read from the same address
 
 
 
DDR2 IP core
==============
DDR2_Mem.v - top level DDR2 memory wishbone compatible if module
|
|
--- ddr2_user_if_top.v - user interface top module: receives write/read commands from bus interface module
generates FIFO wr commands for address and data
|
|
--- ddr2_adr_data_gen.v : latches commands data byte enable rd/wr data to/from FIFOS
|
|
--- clkGenPLL.v - generates clk signals for memory controller: clk0_125MHz, clk0Phase90, clk0Div2, clk200MHz as well as clkTFT10MHz and clkTFT10_180 for VMODTFT
|
|
--- DDR2_mem_wb_if.v - wishbone slave interface: generates rd/wr command requests for user interface (ddr2_user_if_top.v) module
|
|
--- debounceRst.v - global reset generator & reset button debouncer
|
|
--- rtl\ipcore_dir\MemCtrl - files generated using Xilinx MIG Version: 3.6.1. Parameters: Bust length: 4, Data size: 64.
 
 
 
Synthesizable bench
====================
test_DDR2_wb.v - top level module FPGA proven
|
|
--- DDR2_Mem.v -top level DDR2 memory wishbone compatible if module
|
|
--- wishbone_master_mock - master wishbone interface connected to the memory slave interface; it generates a write burst followed by a read burst transaction
 
 
Tools used
=========
 
Xilinx ISE 14.4, Chipscope courtesy of Xilinx through Xilinx University Program.
 
 
Bench test
==============
 
FPGA proven toplevel module - top level module: test_DDR2_wb.v verified using Chipscope.
 
 
Known issues
=============
Attempt to move the PLL instance one level up in the hierarchy to test_DDR2_wb (test_DDR2_wb.v) resulted in the FPGA design not working.
 
 
 
genesys_ddr2 and OpenCores
==========================
 
This project is licensed under the GNU Public License version 3.
 
 
About the same idea as with GNU project except we want free and open source
IP (intellectual property) cores. We design open source, synthesizable
cores.
 
For more information visit us at http://www.opencores.org.

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.