//***************************************************************************** // 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 // \ \ Application: MIG // / / Filename: ddr2_phy_dq_iob.v // /___/ /\ Date Last Modified: $Date: 2010/06/29 12:03:43 $ // \ \ / \ 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 dram module. Please refer to // the dram 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