1 //*****************************************************************************
2 // DISCLAIMER OF LIABILITY
4 // This text/file contains proprietary, confidential
5 // information of Xilinx, Inc., is distributed under license
6 // from Xilinx, Inc., and may be used, copied and/or
7 // disclosed only pursuant to the terms of a valid license
8 // agreement with Xilinx, Inc. Xilinx hereby grants you a
9 // license to use this text/file solely for design, simulation,
10 // implementation and creation of design files limited
11 // to Xilinx devices or technologies. Use with non-Xilinx
12 // devices or technologies is expressly prohibited and
13 // immediately terminates your license unless covered by
14 // a separate agreement.
16 // Xilinx is providing this design, code, or information
17 // "as-is" solely for use in developing programs and
18 // solutions for Xilinx devices, with no obligation on the
19 // part of Xilinx to provide support. By providing this design,
20 // code, or information as one possible implementation of
21 // this feature, application or standard, Xilinx is making no
22 // representation that this implementation is free from any
23 // claims of infringement. You are responsible for
24 // obtaining any rights you may require for your implementation.
25 // Xilinx expressly disclaims any warranty whatsoever with
26 // respect to the adequacy of the implementation, including
27 // but not limited to any warranties or representations that this
28 // implementation is free from claims of infringement, implied
29 // warranties of merchantability or fitness for a particular
32 // Xilinx products are not intended for use in life support
33 // appliances, devices, or systems. Use in such applications is
34 // expressly prohibited.
36 // Any modifications that are made to the Source Code are
37 // done at the users sole risk and will be unsupported.
39 // Copyright (c) 2006-2007 Xilinx, Inc. All rights reserved.
41 // This copyright and support notice must be retained as part
42 // of this text at all times.
43 //*****************************************************************************
46 // /___/ \ / Vendor: Xilinx
47 // \ \ \/ Version: 2.3
48 // \ \ Application: MIG
49 // / / Filename: ddr2_phy_write.v
50 // /___/ /\ Date Last Modified: $Date: 2008/07/29 15:24:03 $
51 // \ \ / \ Date Created: Thu Aug 24 2006
58 // Handles delaying various write control signals appropriately depending
59 // on CAS latency, additive latency, etc. Also splits the data and mask in
60 // rise and fall buses.
62 // Rev 1.1 - For Dual Rank parts support ODT logic corrected. PK. 08/05/08
63 //*****************************************************************************
67 module ddr2_phy_write #
69 // Following parameters are for 72-bit RDIMM design (for ML561 Reference
70 // board design). Actual values may be different. Actual parameters values
71 // are passed from design top module ddr2_sdram module. Please refer to
72 // the ddr2_sdram module for actual values.
73 parameter DQ_WIDTH = 72,
75 parameter ADDITIVE_LAT = 0,
76 parameter CAS_LAT = 5,
77 parameter ECC_ENABLE = 0,
78 parameter ODT_TYPE = 1,
79 parameter REG_ENABLE = 1,
80 parameter DDR_TYPE = 1
86 input [(2*DQ_WIDTH)-1:0] wdf_data,
87 input [(2*DQ_WIDTH/8)-1:0] wdf_mask_data,
90 input phy_init_data_sel,
92 output reg [1:0] dq_oe_n,
94 output reg dqs_rst_n ,
96 output reg [CS_NUM-1:0] odt ,
97 output [DQ_WIDTH-1:0] wr_data_rise,
98 output [DQ_WIDTH-1:0] wr_data_fall,
99 output [(DQ_WIDTH/8)-1:0] mask_data_rise,
100 output [(DQ_WIDTH/8)-1:0] mask_data_fall
103 localparam MASK_WIDTH = DQ_WIDTH/8;
108 // (MIN,MAX) value of WR_LATENCY for DDR1:
109 // REG_ENABLE = (0,1)
110 // ECC_ENABLE = (0,1)
113 // (MIN,MAX) value of WR_LATENCY for DDR2:
114 // REG_ENABLE = (0,1)
115 // ECC_ENABLE = (0,1)
116 // Write latency = ADDITIVE_CAS + CAS_LAT - 1 = (0,4) + (3,5) - 1 = (2,8)
117 // ADDITIVE_LAT = (0,4) (JEDEC79-2B)
118 // CAS_LAT = (3,5) (JEDEC79-2B)
120 localparam WR_LATENCY = (DDR_TYPE == DDR3) ?
121 (ADDITIVE_LAT + (CAS_LAT) + REG_ENABLE ) :
123 (ADDITIVE_LAT + (CAS_LAT-1) + REG_ENABLE ) :
126 // NOTE that ODT timing does not need to be delayed for registered
127 // DIMM case, since like other control/address signals, it gets
128 // delayed by one clock cycle at the DIMM
129 localparam ODT_WR_LATENCY = WR_LATENCY - REG_ENABLE;
134 reg [1:0] dq_oe_n_90_r1;
140 reg dqs_rst_n_180_r1;
144 reg [(DQ_WIDTH-1):0] init_data_f;
145 reg [(DQ_WIDTH-1):0] init_data_r;
146 reg [3:0] init_wdf_cnt_r;
148 reg rst90_r /* synthesis syn_maxfan = 10 */;
149 reg [10:0] wr_stages ;
150 reg [(2*DQ_WIDTH)-1:0] wdf_data_r;
151 reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r;
152 wire [(2*DQ_WIDTH/8)-1:0] wdf_ecc_mask;
154 reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r1;
161 always @(posedge clk90)
164 //***************************************************************************
165 // Analysis of additional pipeline delays:
166 // 1. dq_oe (DQ 3-state): 1 CLK90 cyc in IOB 3-state FF
167 // 2. dqs_oe (DQS 3-state): 1 CLK180 cyc in IOB 3-state FF
168 // 3. dqs_rst (DQS output value reset): 1 CLK180 cyc in FF + 1 CLK180 cyc
170 // 4. odt (ODT control): 1 CLK0 cyc in IOB FF
171 // 5. write data (output two cyc after wdf_rden - output of RAMB_FIFO w/
172 // output register enabled): 2 CLK90 cyc in OSERDES
173 //***************************************************************************
175 // DQS 3-state must be asserted one extra clock cycle due b/c of write
176 // pre- and post-amble (extra half clock cycle for each)
177 assign dqs_oe_0 = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2];
179 // same goes for ODT, need to handle both pre- and post-amble (generate
180 // ODT only for DDR2)
181 // ODT generation for DDR2 based on write latency. The MIN write
182 // latency is 2. Based on the write latency ODT is asserted.
184 if ((DDR_TYPE != DDR1) && (ODT_TYPE > 0))begin: gen_odt_ddr2
185 if(ODT_WR_LATENCY > 2)
187 wr_stages[ODT_WR_LATENCY-1] |
188 wr_stages[ODT_WR_LATENCY-2] |
189 wr_stages[ODT_WR_LATENCY-3] ;
192 wr_stages[ODT_WR_LATENCY] |
193 wr_stages[ODT_WR_LATENCY-1] |
194 wr_stages[ODT_WR_LATENCY-2] ;
199 assign dq_oe_0[0] = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY];
200 assign dq_oe_0[1] = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2];
201 assign dqs_rst_0 = ~wr_stages[WR_LATENCY-2];
202 assign dm_ce_0 = wr_stages[WR_LATENCY] | wr_stages[WR_LATENCY-1]
203 | wr_stages[WR_LATENCY-2];
205 // write data fifo, read flag assertion
207 if (DDR_TYPE != DDR1) begin: gen_wdf_ddr2
209 assign wdf_rden_0 = wr_stages[WR_LATENCY-3];
211 assign wdf_rden_0 = wr_stages[WR_LATENCY-2];
212 end else begin: gen_wdf_ddr1
213 assign wdf_rden_0 = wr_stages[WR_LATENCY-2];
217 // first stage isn't registered
219 wr_stages[0] = (phy_init_data_sel) ? ctrl_wren : phy_init_wren;
221 always @(posedge clk0) begin
222 wr_stages[1] <= wr_stages[0];
223 wr_stages[2] <= wr_stages[1];
224 wr_stages[3] <= wr_stages[2];
225 wr_stages[4] <= wr_stages[3];
226 wr_stages[5] <= wr_stages[4];
227 wr_stages[6] <= wr_stages[5];
228 wr_stages[7] <= wr_stages[6];
229 wr_stages[8] <= wr_stages[7];
230 wr_stages[9] <= wr_stages[8];
231 wr_stages[10] <= wr_stages[9];
234 // intermediate synchronization to CLK270
235 always @(negedge clk90) begin
236 dq_oe_270 <= dq_oe_0;
237 dqs_oe_270 <= dqs_oe_0;
238 dqs_rst_270 <= dqs_rst_0;
239 wdf_rden_270 <= wdf_rden_0;
242 // synchronize DQS signals to CLK180
243 always @(negedge clk0) begin
244 dqs_oe_n_180_r1 <= ~dqs_oe_270;
245 dqs_rst_n_180_r1 <= ~dqs_rst_270;
248 // All write data-related signals synced to CLK90
249 always @(posedge clk90) begin
250 dq_oe_n_90_r1 <= ~dq_oe_270;
251 wdf_rden_90_r <= wdf_rden_270;
254 // generate for wdf_rden and calib rden. These signals
255 // are asserted based on write latency. For write
256 // latency of 2, the extra register stage is taken out.
258 if (WR_LATENCY > 2) begin
259 always @(posedge clk90) begin
260 // assert wdf rden only for non calibration opertations
261 wdf_rden_90_r1 <= wdf_rden_90_r &
263 // rden for calibration
264 calib_rden_90_r <= wdf_rden_90_r;
268 wdf_rden_90_r1 = wdf_rden_90_r
270 calib_rden_90_r = wdf_rden_90_r;
272 end // else: !if(WR_LATENCY > 2)
275 // dm CE signal to stop dm oscilation
276 always @(negedge clk90)begin
281 // When in ECC mode the upper byte [71:64] will have the
282 // ECC parity. Mapping the bytes which have valid data
283 // to the upper byte in ecc mode. Also in ecc mode there
284 // is an extra register stage to account for timing.
289 for (mask_i = 0; mask_i < (2*DQ_WIDTH)/72;
290 mask_i = mask_i+1) begin: gen_mask
291 assign wdf_ecc_mask[((mask_i*9)+9)-1:(mask_i*9)] =
292 {&wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9],
293 wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9]};
299 if (ECC_ENABLE) begin:gen_ecc_reg
300 always @(posedge clk90)begin
301 if(phy_init_data_sel)
302 wdf_mask_r <= wdf_ecc_mask;
304 wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}};
307 always@(posedge clk90) begin
308 if (phy_init_data_sel)
309 wdf_mask_r <= wdf_mask_data;
311 wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}};
316 always @(posedge clk90) begin
317 if(phy_init_data_sel)
318 wdf_data_r <= wdf_data;
320 wdf_data_r <={init_data_f,init_data_r};
323 // Error generation block during simulation.
324 // Error will be displayed when all the DM
325 // bits are not zero. The error will be
326 // displayed only during the start of the sequence
327 // for errors that are continous over many cycles.
329 if (ECC_ENABLE) begin: gen_ecc_error
330 always @(posedge clk90) begin
331 //synthesis translate_off
332 wdf_mask_r1 <= wdf_mask_r;
336 (~wdf_mask_r1[35] && (|wdf_mask_r1[34:27])) ||
337 (~wdf_mask_r1[26] && (|wdf_mask_r1[25:18])) ||
338 (~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) ||
339 (~wdf_mask_r1[8] && (|wdf_mask_r1[7:0]))) && phy_init_data_sel;
342 <= ((~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) ||
343 (~wdf_mask_r1[8] && (|wdf_mask_r1[7:0]))) && phy_init_data_sel;
344 ecc_dm_error_r1 <= ecc_dm_error_r ;
345 if (ecc_dm_error_r && ~ecc_dm_error_r1) // assert the error only once.
346 $display ("ECC DM ERROR. ");
347 //synthesis translate_on
352 //***************************************************************************
353 // State logic to write calibration training patterns
354 //***************************************************************************
356 always @(posedge clk90) begin
358 init_wdf_cnt_r <= 4'd0;
359 init_data_r <= {64{1'bx}};
360 init_data_f <= {64{1'bx}};
362 init_wdf_cnt_r <= init_wdf_cnt_r + calib_rden_90_r;
363 casex (init_wdf_cnt_r)
364 // First stage calibration. Pattern (rise/fall) = 1(r)->0(f)
365 // The rise data and fall data are already interleaved in the manner
366 // required for data into the WDF write FIFO
368 init_data_r <= {DQ_WIDTH{1'b1}};
369 init_data_f <= {DQ_WIDTH{1'b0}};
371 // Second stage calibration. Pattern = 1(r)->1(f)->0(r)->0(f)
373 init_data_r <= {DQ_WIDTH{1'b1}};
374 init_data_f <= {DQ_WIDTH{1'b1}};
377 init_data_r <= {DQ_WIDTH{1'b0}};
378 init_data_f <= {DQ_WIDTH{1'b0}};
380 // MIG 2.1: Changed Stage 3/4 training pattern
381 // Third and fourth stage calibration patern =
382 // 11(r)->ee(f)->ee(r)->11(f)-11(r)->ee(f)->ee(r)->11(f)
384 init_data_r <= {DQ_WIDTH/4{4'h1}};
385 init_data_f <= {DQ_WIDTH/4{4'hE}};
388 init_data_r <= {DQ_WIDTH/4{4'hE}};
389 init_data_f <= {DQ_WIDTH/4{4'h1}};
392 init_data_r <= {(DQ_WIDTH/4){4'h1}};
393 init_data_f <= {(DQ_WIDTH/4){4'hE}};
396 init_data_r <= {(DQ_WIDTH/4){4'hE}};
397 init_data_f <= {(DQ_WIDTH/4){4'h1}};
400 init_data_f <= {(2*DQ_WIDTH){1'bx}};
401 init_data_r <= {(2*DQ_WIDTH){1'bx}};
407 //***************************************************************************
409 always @(posedge clk90)
410 dq_oe_n <= dq_oe_n_90_r1;
412 always @(negedge clk0)
413 dqs_oe_n <= dqs_oe_n_180_r1;
415 always @(negedge clk0)
416 dqs_rst_n <= dqs_rst_n_180_r1;
418 // generate for odt. odt is asserted based on
419 // write latency. For write latency of 2
420 // the extra register stage is taken out.
422 if (ODT_WR_LATENCY > 2) begin
423 always @(posedge clk0) begin
435 assign wdf_rden = wdf_rden_90_r1;
437 //***************************************************************************
438 // Format write data/mask: Data is in format: {fall, rise}
439 //***************************************************************************
441 assign wr_data_rise = wdf_data_r[DQ_WIDTH-1:0];
442 assign wr_data_fall = wdf_data_r[(2*DQ_WIDTH)-1:DQ_WIDTH];
443 assign mask_data_rise = wdf_mask_r[MASK_WIDTH-1:0];
444 assign mask_data_fall = wdf_mask_r[(2*MASK_WIDTH)-1:MASK_WIDTH];