source: XOpenSparcT1/trunk/Xilinx/ddr2_phy_write.v @ 10

Revision 10, 16.7 KB checked in by pntsvt00, 13 years ago (diff)

versione sintetizzabile

Line 
1//*****************************************************************************
2// DISCLAIMER OF LIABILITY
3//
4// This file contains proprietary and confidential information of
5// Xilinx, Inc. ("Xilinx"), that is distributed under a license
6// from Xilinx, and may be used, copied and/or disclosed only
7// pursuant to the terms of a valid license agreement with Xilinx.
8//
9// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION
10// ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
11// EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT
12// LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT,
13// MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx
14// does not warrant that functions included in the Materials will
15// meet the requirements of Licensee, or that the operation of the
16// Materials will be uninterrupted or error-free, or that defects
17// in the Materials will be corrected. Furthermore, Xilinx does
18// not warrant or make any representations regarding use, or the
19// results of the use, of the Materials in terms of correctness,
20// accuracy, reliability or otherwise.
21//
22// Xilinx products are not designed or intended to be fail-safe,
23// or for use in any application requiring fail-safe performance,
24// such as life-support or safety devices or systems, Class III
25// medical devices, nuclear facilities, applications related to
26// the deployment of airbags, or any other applications that could
27// lead to death, personal injury or severe property or
28// environmental damage (individually and collectively, "critical
29// applications"). Customer assumes the sole risk and liability
30// of any use of Xilinx products in critical applications,
31// subject only to applicable laws and regulations governing
32// limitations on product liability.
33//
34// Copyright 2006, 2007, 2008 Xilinx, Inc.
35// All rights reserved.
36//
37// This disclaimer and copyright notice must be retained as part
38// of this file at all times.
39//*****************************************************************************
40//   ____  ____
41//  /   /\/   /
42// /___/  \  /    Vendor: Xilinx
43// \   \   \/     Version: 3.6
44//  \   \         Application: MIG
45//  /   /         Filename: ddr2_phy_write.v
46// /___/   /\     Date Last Modified: $Date: 2010/06/29 12:03:43 $
47// \   \  /  \    Date Created: Thu Aug 24 2006
48//  \___\/\___\
49//
50//Device: Virtex-5
51//Design Name: DDR2
52//Purpose:
53//Reference:
54//   Handles delaying various write control signals appropriately depending
55//   on CAS latency, additive latency, etc. Also splits the data and mask in
56//   rise and fall buses.
57//Revision History:
58//   Rev 1.1 - For Dual Rank parts support ODT logic corrected. PK. 08/05/08
59//   Rev 1.2 - Retain current data pattern for stage 4 calibration, and create
60//             new pattern for stage 4. RC. 09/21/09.
61//*****************************************************************************
62
63`timescale 1ns/1ps
64
65module ddr2_phy_write #
66  (
67   // Following parameters are for 72-bit RDIMM design (for ML561 Reference
68   // board design). Actual values may be different. Actual parameters values
69   // are passed from design top module dram module. Please refer to
70   // the dram module for actual values.
71   parameter DQ_WIDTH      = 72,
72   parameter CS_NUM        = 1,
73   parameter ADDITIVE_LAT  = 0,
74   parameter CAS_LAT       = 5,
75   parameter ECC_ENABLE    = 0,
76   parameter ODT_TYPE      = 1,
77   parameter REG_ENABLE    = 1,
78   parameter DDR_TYPE      = 1
79   )
80  (
81   input                       clk0,
82   input                       clk90,
83   input                       rst90,
84   input [(2*DQ_WIDTH)-1:0]    wdf_data,
85   input [(2*DQ_WIDTH/8)-1:0]  wdf_mask_data,
86   input                       ctrl_wren,
87   input                       phy_init_wren,
88   input                       phy_init_data_sel,
89   output reg                  dm_ce,
90   output reg [1:0]            dq_oe_n,
91   output reg                  dqs_oe_n ,
92   output reg                  dqs_rst_n ,
93   output                      wdf_rden,
94   output reg [CS_NUM-1:0]     odt ,
95   output [DQ_WIDTH-1:0]       wr_data_rise,
96   output [DQ_WIDTH-1:0]       wr_data_fall,
97   output [(DQ_WIDTH/8)-1:0]   mask_data_rise,
98   output [(DQ_WIDTH/8)-1:0]   mask_data_fall
99   );
100
101  localparam   MASK_WIDTH               = DQ_WIDTH/8;
102  localparam   DDR1                     = 0;
103  localparam   DDR2                     = 1;
104  localparam   DDR3                     = 2;
105
106  // (MIN,MAX) value of WR_LATENCY for DDR1:
107  //   REG_ENABLE   = (0,1)
108  //   ECC_ENABLE   = (0,1)
109  //   Write latency = 1
110  //   Total: (1,3)
111  // (MIN,MAX) value of WR_LATENCY for DDR2:
112  //   REG_ENABLE   = (0,1)
113  //   ECC_ENABLE   = (0,1)
114  //   Write latency = ADDITIVE_CAS + CAS_LAT - 1 = (0,4) + (3,5) - 1 = (2,8)
115  //     ADDITIVE_LAT = (0,4) (JEDEC79-2B)
116  //     CAS_LAT      = (3,5) (JEDEC79-2B)
117  //   Total: (2,10)
118  localparam WR_LATENCY = (DDR_TYPE == DDR3) ?
119             (ADDITIVE_LAT + (CAS_LAT) + REG_ENABLE ) :
120             (DDR_TYPE == DDR2) ?
121             (ADDITIVE_LAT + (CAS_LAT-1) + REG_ENABLE ) :
122             (1 + REG_ENABLE );
123
124  // NOTE that ODT timing does not need to be delayed for registered
125  // DIMM case, since like other control/address signals, it gets
126  // delayed by one clock cycle at the DIMM
127  localparam ODT_WR_LATENCY = WR_LATENCY - REG_ENABLE;
128
129  wire                     dm_ce_0;
130  reg                      dm_ce_r;
131  wire [1:0]               dq_oe_0;
132  reg [1:0]                dq_oe_n_90_r1;
133  reg [1:0]                dq_oe_270;
134  wire                     dqs_oe_0;
135  reg                      dqs_oe_270;
136  reg                      dqs_oe_n_180_r1;
137  wire                     dqs_rst_0;
138  reg                      dqs_rst_n_180_r1;
139  reg                      dqs_rst_270;
140  reg                      ecc_dm_error_r;
141  reg                      ecc_dm_error_r1;
142  reg [(DQ_WIDTH-1):0]     init_data_f;
143  reg [(DQ_WIDTH-1):0]     init_data_r;
144  reg [3:0]                init_wdf_cnt_r;
145  wire                     odt_0;
146  reg                      rst90_r /* synthesis syn_maxfan = 10 */;
147  reg [10:0]               wr_stages ;
148  reg [(2*DQ_WIDTH)-1:0]   wdf_data_r;
149  reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r;
150  wire [(2*DQ_WIDTH/8)-1:0] wdf_ecc_mask;
151
152  reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r1;
153  wire                     wdf_rden_0;
154  reg                      calib_rden_90_r;
155  reg                      wdf_rden_90_r;
156  reg                      wdf_rden_90_r1;
157  reg                      wdf_rden_270;
158
159  always @(posedge clk90)
160      rst90_r <= rst90;
161
162  //***************************************************************************
163  // Analysis of additional pipeline delays:
164  //   1. dq_oe (DQ 3-state): 1 CLK90 cyc in IOB 3-state FF
165  //   2. dqs_oe (DQS 3-state): 1 CLK180 cyc in IOB 3-state FF
166  //   3. dqs_rst (DQS output value reset): 1 CLK180 cyc in FF + 1 CLK180 cyc
167  //      in IOB DDR
168  //   4. odt (ODT control): 1 CLK0 cyc in IOB FF
169  //   5. write data (output two cyc after wdf_rden - output of RAMB_FIFO w/
170  //      output register enabled): 2 CLK90 cyc in OSERDES
171  //***************************************************************************
172
173  // DQS 3-state must be asserted one extra clock cycle due b/c of write
174  // pre- and post-amble (extra half clock cycle for each)
175  assign dqs_oe_0 = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2];
176
177  // same goes for ODT, need to handle both pre- and post-amble (generate
178  // ODT only for DDR2)
179  // ODT generation for DDR2 based on write latency. The MIN write
180  // latency is 2. Based on the write latency ODT is asserted.
181  generate
182    if ((DDR_TYPE != DDR1) && (ODT_TYPE > 0))begin: gen_odt_ddr2
183       if(ODT_WR_LATENCY > 3)
184         assign odt_0 =
185                   wr_stages[ODT_WR_LATENCY-2] |
186                   wr_stages[ODT_WR_LATENCY-3] |
187                   wr_stages[ODT_WR_LATENCY-4] ;
188       else if ( ODT_WR_LATENCY == 3)
189         assign odt_0 =
190                   wr_stages[ODT_WR_LATENCY-1] |
191                   wr_stages[ODT_WR_LATENCY-2] |
192                   wr_stages[ODT_WR_LATENCY-3] ;
193       else
194         assign odt_0 =
195                  wr_stages[ODT_WR_LATENCY] |
196                  wr_stages[ODT_WR_LATENCY-1] |
197                  wr_stages[ODT_WR_LATENCY-2] ;
198    end else
199      assign odt_0 = 1'b0;
200   endgenerate
201
202  assign dq_oe_0[0]   = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY];
203  assign dq_oe_0[1]   = wr_stages[WR_LATENCY-1] | wr_stages[WR_LATENCY-2];
204  assign dqs_rst_0    = ~wr_stages[WR_LATENCY-2];
205  assign dm_ce_0      = wr_stages[WR_LATENCY] | wr_stages[WR_LATENCY-1]
206                        | wr_stages[WR_LATENCY-2];
207
208  // write data fifo, read flag assertion
209  generate
210    if (DDR_TYPE != DDR1) begin: gen_wdf_ddr2
211      if (WR_LATENCY > 2)
212        assign wdf_rden_0 = wr_stages[WR_LATENCY-3];
213      else
214        assign wdf_rden_0 = wr_stages[WR_LATENCY-2];
215    end else begin: gen_wdf_ddr1
216      assign wdf_rden_0 = wr_stages[WR_LATENCY-2];
217    end
218  endgenerate
219
220  // first stage isn't registered
221  always @(*)
222    wr_stages[0] = (phy_init_data_sel) ? ctrl_wren : phy_init_wren;
223
224  always @(posedge clk0) begin
225    wr_stages[1] <= wr_stages[0];
226    wr_stages[2] <= wr_stages[1];
227    wr_stages[3] <= wr_stages[2];
228    wr_stages[4] <= wr_stages[3];
229    wr_stages[5] <= wr_stages[4];
230    wr_stages[6] <= wr_stages[5];
231    wr_stages[7] <= wr_stages[6];
232    wr_stages[8] <= wr_stages[7];
233    wr_stages[9] <= wr_stages[8];
234    wr_stages[10] <= wr_stages[9];
235  end
236
237  // intermediate synchronization to CLK270
238  always @(negedge clk90) begin
239    dq_oe_270         <= dq_oe_0;
240    dqs_oe_270        <= dqs_oe_0;
241    dqs_rst_270       <= dqs_rst_0;
242    wdf_rden_270      <= wdf_rden_0;
243  end
244
245  // synchronize DQS signals to CLK180
246  always @(negedge clk0) begin
247    dqs_oe_n_180_r1  <= ~dqs_oe_270;
248    dqs_rst_n_180_r1 <= ~dqs_rst_270;
249  end
250
251  // All write data-related signals synced to CLK90
252  always @(posedge clk90) begin
253    dq_oe_n_90_r1  <= ~dq_oe_270;
254    wdf_rden_90_r  <= wdf_rden_270;
255  end
256
257  // generate for wdf_rden and calib rden. These signals
258  // are asserted based on write latency. For write
259  // latency of 2, the extra register stage is taken out.
260  generate
261   if (WR_LATENCY > 2) begin
262     always @(posedge clk90) begin
263        // assert wdf rden only for non calibration opertations
264        wdf_rden_90_r1 <=  wdf_rden_90_r &
265                           phy_init_data_sel;
266        // rden for calibration
267        calib_rden_90_r <= wdf_rden_90_r;
268     end
269   end else begin
270     always @(*) begin
271        wdf_rden_90_r1 = wdf_rden_90_r
272                         & phy_init_data_sel;
273        calib_rden_90_r = wdf_rden_90_r;
274     end
275  end // else: !if(WR_LATENCY > 2)
276  endgenerate
277
278  // dm CE signal to stop dm oscilation
279  always @(negedge clk90)begin
280    dm_ce_r <= dm_ce_0;
281    dm_ce <= dm_ce_r;
282  end
283
284  // When in ECC mode the upper byte [71:64] will have the
285  // ECC parity. Mapping the bytes which have valid data
286  // to the upper byte in ecc mode. Also in ecc mode there
287  // is an extra register stage to account for timing.
288
289  genvar mask_i;
290  generate
291    if(ECC_ENABLE) begin
292      for (mask_i  = 0; mask_i < (2*DQ_WIDTH)/72;
293          mask_i = mask_i+1) begin: gen_mask
294       assign wdf_ecc_mask[((mask_i*9)+9)-1:(mask_i*9)] =
295                {&wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9],
296                wdf_mask_data[(mask_i*8)+(7+mask_i):mask_i*9]};
297      end
298    end
299   endgenerate
300
301  generate
302    if (ECC_ENABLE) begin:gen_ecc_reg
303       always @(posedge clk90)begin
304          if(phy_init_data_sel)
305               wdf_mask_r <= wdf_ecc_mask;
306          else
307             wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}};
308      end       
309    end else begin
310      always@(posedge clk90) begin
311        if (phy_init_data_sel)
312          wdf_mask_r <= wdf_mask_data;
313        else
314          wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}};
315      end
316    end
317  endgenerate
318
319   always @(posedge clk90) begin
320      if(phy_init_data_sel)
321          wdf_data_r <= wdf_data;
322      else
323          wdf_data_r <={init_data_f,init_data_r};
324   end
325
326  // Error generation block during simulation.
327  // Error will be displayed when all the DM
328  // bits are not zero. The error will be
329  // displayed only during the start of the sequence
330  // for errors that are continous over many cycles.
331  generate
332    if (ECC_ENABLE) begin: gen_ecc_error
333      always @(posedge clk90) begin
334        //synthesis translate_off
335        wdf_mask_r1 <= wdf_mask_r;
336        if(DQ_WIDTH > 72)
337           ecc_dm_error_r
338              <= (
339              (~wdf_mask_r1[35] && (|wdf_mask_r1[34:27])) ||
340              (~wdf_mask_r1[26] && (|wdf_mask_r1[25:18])) ||
341              (~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) ||
342              (~wdf_mask_r1[8] &&  (|wdf_mask_r1[7:0]))) && phy_init_data_sel;
343         else
344            ecc_dm_error_r
345              <= ((~wdf_mask_r1[17] && (|wdf_mask_r1[16:9])) ||
346              (~wdf_mask_r1[8] &&  (|wdf_mask_r1[7:0]))) && phy_init_data_sel;
347        ecc_dm_error_r1 <= ecc_dm_error_r ;
348        if (ecc_dm_error_r && ~ecc_dm_error_r1) // assert the error only once.
349          $display ("ECC DM ERROR. ");
350        //synthesis translate_on
351      end
352    end
353  endgenerate
354
355  //***************************************************************************
356  // State logic to write calibration training patterns
357  //***************************************************************************
358
359  always @(posedge clk90) begin
360    if (rst90_r) begin
361      init_wdf_cnt_r  <= 4'd0;
362      init_data_r <= {64{1'bx}};
363      init_data_f <= {64{1'bx}};
364    end else begin
365      init_wdf_cnt_r  <= init_wdf_cnt_r + calib_rden_90_r;
366      casex (init_wdf_cnt_r)
367        // First stage calibration. Pattern (rise/fall) = 1(r)->0(f)
368        // The rise data and fall data are already interleaved in the manner
369        // required for data into the WDF write FIFO
370        4'b00xx: begin
371          init_data_r <= {DQ_WIDTH{1'b1}};
372          init_data_f <= {DQ_WIDTH{1'b0}};
373        end
374        // Second stage calibration. Pattern = 1(r)->1(f)->0(r)->0(f)
375        4'b01x0: begin
376           init_data_r <= {DQ_WIDTH{1'b1}};
377           init_data_f <= {DQ_WIDTH{1'b1}};
378          end
379        4'b01x1: begin
380           init_data_r <= {DQ_WIDTH{1'b0}};
381           init_data_f <= {DQ_WIDTH{1'b0}};
382        end
383        // MIG 3.2: Changed Stage 3/4 training pattern
384        // Third stage calibration patern =
385        //   11(r)->ee(f)->ee(r)->11(f)-ee(r)->11(f)->ee(r)->11(f)
386        4'b1000: begin
387          init_data_r <= {DQ_WIDTH/4{4'h1}};
388          init_data_f <= {DQ_WIDTH/4{4'hE}};
389        end
390        4'b1001: begin
391          init_data_r <= {DQ_WIDTH/4{4'hE}};
392          init_data_f <= {DQ_WIDTH/4{4'h1}};
393          end
394        4'b1010: begin
395          init_data_r <= {(DQ_WIDTH/4){4'hE}};
396          init_data_f <= {(DQ_WIDTH/4){4'h1}};
397        end
398        4'b1011: begin
399          init_data_r <= {(DQ_WIDTH/4){4'hE}};
400          init_data_f <= {(DQ_WIDTH/4){4'h1}};
401        end
402        // Fourth stage calibration patern =
403        //   11(r)->ee(f)->ee(r)->11(f)-11(r)->ee(f)->ee(r)->11(f)
404        4'b1100: begin
405          init_data_r <= {DQ_WIDTH/4{4'h1}};
406          init_data_f <= {DQ_WIDTH/4{4'hE}};
407        end
408        4'b1101: begin
409          init_data_r <= {DQ_WIDTH/4{4'hE}};
410          init_data_f <= {DQ_WIDTH/4{4'h1}};
411          end
412        4'b1110: begin
413          init_data_r <= {(DQ_WIDTH/4){4'h1}};
414          init_data_f <= {(DQ_WIDTH/4){4'hE}};
415        end
416        4'b1111: begin
417          // MIG 3.5: Corrected last two writes for stage 4 calibration
418          // training pattern. Previously MIG 3.3 and MIG 3.4 had the
419          // incorrect pattern. This can sometimes result in a calibration
420          // point with small timing margin.
421//          init_data_r <= {(DQ_WIDTH/4){4'h1}};
422//          init_data_f <= {(DQ_WIDTH/4){4'hE}};
423          init_data_r <= {(DQ_WIDTH/4){4'hE}};
424          init_data_f <= {(DQ_WIDTH/4){4'h1}};
425        end
426      endcase
427    end
428  end
429
430  //***************************************************************************
431
432  always @(posedge clk90)
433    dq_oe_n   <= dq_oe_n_90_r1;
434
435  always @(negedge clk0)
436    dqs_oe_n  <= dqs_oe_n_180_r1;
437
438  always @(negedge clk0)
439    dqs_rst_n <= dqs_rst_n_180_r1;
440
441  // generate for odt. odt is asserted based on
442  //  write latency. For write latency of 2
443  //  the extra register stage is taken out.
444  generate
445    if (ODT_WR_LATENCY > 3) begin
446      always @(posedge clk0) begin
447        odt    <= 'b0;
448        odt[0] <= odt_0;
449      end
450    end else begin
451      always @ (*) begin
452        odt = 'b0;
453        odt[0] = odt_0;
454      end
455    end
456  endgenerate
457
458  assign wdf_rden  = wdf_rden_90_r1;
459
460  //***************************************************************************
461  // Format write data/mask: Data is in format: {fall, rise}
462  //***************************************************************************
463
464  assign wr_data_rise = wdf_data_r[DQ_WIDTH-1:0];
465  assign wr_data_fall = wdf_data_r[(2*DQ_WIDTH)-1:DQ_WIDTH];
466  assign mask_data_rise = wdf_mask_r[MASK_WIDTH-1:0];
467  assign mask_data_fall = wdf_mask_r[(2*MASK_WIDTH)-1:MASK_WIDTH];
468
469endmodule
Note: See TracBrowser for help on using the repository browser.