1bb831a352091abb10dbeedebb3801ca857f8833
[fleet.git] / src / edu / berkeley / fleet / fpga / greg / ddr2_phy_write.v
1 //*****************************************************************************
2 // DISCLAIMER OF LIABILITY
3 //
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.
15 //
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
30 // purpose.
31 //
32 // Xilinx products are not intended for use in life support
33 // appliances, devices, or systems. Use in such applications is
34 // expressly prohibited.
35 //
36 // Any modifications that are made to the Source Code are
37 // done at the user\92s sole risk and will be unsupported.
38 //
39 // Copyright (c) 2006-2007 Xilinx, Inc. All rights reserved.
40 //
41 // This copyright and support notice must be retained as part
42 // of this text at all times.
43 //*****************************************************************************
44 //   ____  ____
45 //  /   /\/   /
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
52 //  \___\/\___\
53 //
54 //Device: Virtex-5
55 //Design Name: DDR2
56 //Purpose:
57 //Reference:
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.
61 //Revision History:
62 //   Rev 1.1 - For Dual Rank parts support ODT logic corrected. PK. 08/05/08
63 //*****************************************************************************
64
65 `timescale 1ns/1ps
66
67 module ddr2_phy_write #
68   (
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,
74    parameter CS_NUM        = 1,
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
81    )
82   (
83    input                       clk0,
84    input                       clk90,
85    input                       rst90,
86    input [(2*DQ_WIDTH)-1:0]    wdf_data,
87    input [(2*DQ_WIDTH/8)-1:0]  wdf_mask_data,
88    input                       ctrl_wren,
89    input                       phy_init_wren,
90    input                       phy_init_data_sel,
91    output reg                  dm_ce,
92    output reg [1:0]            dq_oe_n,
93    output reg                  dqs_oe_n ,
94    output reg                  dqs_rst_n ,
95    output                      wdf_rden,
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
101    );
102
103   localparam   MASK_WIDTH               = DQ_WIDTH/8;
104   localparam   DDR1                     = 0;
105   localparam   DDR2                     = 1;
106   localparam   DDR3                     = 2;
107
108   // (MIN,MAX) value of WR_LATENCY for DDR1:
109   //   REG_ENABLE   = (0,1)
110   //   ECC_ENABLE   = (0,1)
111   //   Write latency = 1
112   //   Total: (1,3)
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)
119   //   Total: (2,10)
120   localparam WR_LATENCY = (DDR_TYPE == DDR3) ?
121              (ADDITIVE_LAT + (CAS_LAT) + REG_ENABLE ) :
122              (DDR_TYPE == DDR2) ?
123              (ADDITIVE_LAT + (CAS_LAT-1) + REG_ENABLE ) :
124              (1 + REG_ENABLE );
125
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;
130
131   wire                     dm_ce_0;
132   reg                      dm_ce_r;
133   wire [1:0]               dq_oe_0;
134   reg [1:0]                dq_oe_n_90_r1;
135   reg [1:0]                dq_oe_270;
136   wire                     dqs_oe_0;
137   reg                      dqs_oe_270;
138   reg                      dqs_oe_n_180_r1;
139   wire                     dqs_rst_0;
140   reg                      dqs_rst_n_180_r1;
141   reg                      dqs_rst_270;
142   reg                      ecc_dm_error_r;
143   reg                      ecc_dm_error_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;
147   wire                     odt_0;
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;
153
154   reg [(2*DQ_WIDTH/8)-1:0] wdf_mask_r1;
155   wire                     wdf_rden_0;
156   reg                      calib_rden_90_r;
157   reg                      wdf_rden_90_r;
158   reg                      wdf_rden_90_r1;
159   reg                      wdf_rden_270;
160
161   always @(posedge clk90)
162       rst90_r <= rst90;
163
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
169   //      in IOB DDR
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   //***************************************************************************
174
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];
178
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.
183   generate
184     if ((DDR_TYPE != DDR1) && (ODT_TYPE > 0))begin: gen_odt_ddr2
185        if(ODT_WR_LATENCY > 2)
186          assign odt_0 =
187                    wr_stages[ODT_WR_LATENCY-1] |
188                    wr_stages[ODT_WR_LATENCY-2] |
189                    wr_stages[ODT_WR_LATENCY-3] ;
190        else
191          assign odt_0 =
192                   wr_stages[ODT_WR_LATENCY] |
193                   wr_stages[ODT_WR_LATENCY-1] |
194                   wr_stages[ODT_WR_LATENCY-2] ;
195     end else
196       assign odt_0 = 1'b0;
197    endgenerate
198
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];
204
205   // write data fifo, read flag assertion
206   generate
207     if (DDR_TYPE != DDR1) begin: gen_wdf_ddr2
208       if (WR_LATENCY > 2)
209         assign wdf_rden_0 = wr_stages[WR_LATENCY-3];
210       else
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];
214     end
215   endgenerate
216
217   // first stage isn't registered
218   always @(*)
219     wr_stages[0] = (phy_init_data_sel) ? ctrl_wren : phy_init_wren;
220
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];
232   end
233
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;
240   end
241
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;
246   end
247
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;
252   end
253
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.
257   generate
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 &
262                            phy_init_data_sel;
263         // rden for calibration
264         calib_rden_90_r <= wdf_rden_90_r;
265      end
266    end else begin
267      always @(*) begin
268         wdf_rden_90_r1 = wdf_rden_90_r
269                          & phy_init_data_sel;
270         calib_rden_90_r = wdf_rden_90_r;
271      end
272   end // else: !if(WR_LATENCY > 2)
273   endgenerate
274
275   // dm CE signal to stop dm oscilation
276   always @(negedge clk90)begin
277     dm_ce_r <= dm_ce_0;
278     dm_ce <= dm_ce_r;
279   end
280
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.
285
286   genvar mask_i;
287   generate
288     if(ECC_ENABLE) begin
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]};
294       end
295     end
296    endgenerate
297
298   generate
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;
303           else
304              wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}};
305       end       
306     end else begin
307       always@(posedge clk90) begin
308         if (phy_init_data_sel)
309           wdf_mask_r <= wdf_mask_data;
310         else
311           wdf_mask_r <= {(2*DQ_WIDTH/8){1'b0}};
312       end
313     end
314   endgenerate
315
316    always @(posedge clk90) begin
317       if(phy_init_data_sel)
318           wdf_data_r <= wdf_data;
319       else
320           wdf_data_r <={init_data_f,init_data_r};
321    end
322
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.
328   generate
329     if (ECC_ENABLE) begin: gen_ecc_error
330       always @(posedge clk90) begin
331         //synthesis translate_off
332         wdf_mask_r1 <= wdf_mask_r;
333         if(DQ_WIDTH > 72)
334            ecc_dm_error_r
335               <= (
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;
340          else
341             ecc_dm_error_r
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
348       end
349     end
350   endgenerate
351
352   //***************************************************************************
353   // State logic to write calibration training patterns
354   //***************************************************************************
355
356   always @(posedge clk90) begin
357     if (rst90_r) begin
358       init_wdf_cnt_r  <= 4'd0;
359       init_data_r <= {64{1'bx}};
360       init_data_f <= {64{1'bx}};
361     end else begin
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
367         4'b00xx: begin
368           init_data_r <= {DQ_WIDTH{1'b1}};
369           init_data_f <= {DQ_WIDTH{1'b0}};
370         end
371         // Second stage calibration. Pattern = 1(r)->1(f)->0(r)->0(f)
372         4'b01x0: begin
373            init_data_r <= {DQ_WIDTH{1'b1}};
374            init_data_f <= {DQ_WIDTH{1'b1}};
375           end
376         4'b01x1: begin
377            init_data_r <= {DQ_WIDTH{1'b0}};
378            init_data_f <= {DQ_WIDTH{1'b0}};
379         end
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)
383         4'b1000: begin
384           init_data_r <= {DQ_WIDTH/4{4'h1}};
385           init_data_f <= {DQ_WIDTH/4{4'hE}};
386         end
387         4'b1001: begin
388           init_data_r <= {DQ_WIDTH/4{4'hE}};
389           init_data_f <= {DQ_WIDTH/4{4'h1}};
390           end
391         4'b1010: begin
392           init_data_r <= {(DQ_WIDTH/4){4'h1}};
393           init_data_f <= {(DQ_WIDTH/4){4'hE}};
394         end
395         4'b1011: begin
396           init_data_r <= {(DQ_WIDTH/4){4'hE}};
397           init_data_f <= {(DQ_WIDTH/4){4'h1}};
398          end
399         default: begin
400           init_data_f <= {(2*DQ_WIDTH){1'bx}};
401           init_data_r <= {(2*DQ_WIDTH){1'bx}};
402         end
403       endcase
404     end
405   end
406
407   //***************************************************************************
408
409   always @(posedge clk90)
410     dq_oe_n   <= dq_oe_n_90_r1;
411
412   always @(negedge clk0)
413     dqs_oe_n  <= dqs_oe_n_180_r1;
414
415   always @(negedge clk0)
416     dqs_rst_n <= dqs_rst_n_180_r1;
417
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.
421   generate
422     if (ODT_WR_LATENCY > 2) begin
423       always @(posedge clk0) begin
424         odt    <= 'b0;
425         odt[0] <= odt_0;
426       end
427     end else begin
428       always @ (*) begin
429         odt = 'b0;
430         odt[0] = odt_0;
431       end
432     end
433   endgenerate
434
435   assign wdf_rden  = wdf_rden_90_r1;
436
437   //***************************************************************************
438   // Format write data/mask: Data is in format: {fall, rise}
439   //***************************************************************************
440
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];
445
446 endmodule