1 | /**************************************************************************************** |
---|
2 | * |
---|
3 | * File Name: ddr2_model.v |
---|
4 | * Version: 5.82 |
---|
5 | * Model: BUS Functional |
---|
6 | * |
---|
7 | * Dependencies: ddr2_model_parameters.vh |
---|
8 | * |
---|
9 | * Description: Micron SDRAM DDR2 (Double Data Rate 2) |
---|
10 | * |
---|
11 | * Limitation: - doesn't check for average refresh timings |
---|
12 | * - positive ck and ck_n edges are used to form internal clock |
---|
13 | * - positive dqs and dqs_n edges are used to latch data |
---|
14 | * - test mode is not modeled |
---|
15 | * |
---|
16 | * Note: - Set simulator resolution to "ps" accuracy |
---|
17 | * - Set Debug = 0 to disable $display messages |
---|
18 | * |
---|
19 | * Disclaimer This software code and all associated documentation, comments or other |
---|
20 | * of Warranty: information (collectively "Software") is provided "AS IS" without |
---|
21 | * warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY |
---|
22 | * DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
---|
23 | * TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES |
---|
24 | * OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT |
---|
25 | * WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE |
---|
26 | * OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. |
---|
27 | * FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR |
---|
28 | * THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, |
---|
29 | * ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE |
---|
30 | * OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, |
---|
31 | * ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, |
---|
32 | * INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, |
---|
33 | * WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, |
---|
34 | * OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE |
---|
35 | * THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
---|
36 | * DAMAGES. Because some jurisdictions prohibit the exclusion or |
---|
37 | * limitation of liability for consequential or incidental damages, the |
---|
38 | * above limitation may not apply to you. |
---|
39 | * |
---|
40 | * Copyright 2003 Micron Technology, Inc. All rights reserved. |
---|
41 | * |
---|
42 | * Rev Author Date Changes |
---|
43 | * --------------------------------------------------------------------------------------- |
---|
44 | * 1.00 JMK 07/29/03 Initial Release |
---|
45 | * 1.10 JMK 08/09/03 Timing Parameter updates to tIS, tIH, tDS, tDH |
---|
46 | * 2.20 JMK 08/07/03 General cleanup |
---|
47 | * 2.30 JMK 11/26/03 Added CL_MIN, CL_MAX, wl_min and wl_max parameters. |
---|
48 | * Added AL_MIN and AL_MAX parameters. |
---|
49 | * Removed support for OCD. |
---|
50 | * 2.40 JMK 01/15/04 Removed verilog 2001 constructs. |
---|
51 | * 2.50 JMK 01/29/04 Removed tRP checks during Precharge command. |
---|
52 | * 2.60 JMK 04/20/04 Fixed tWTR check. |
---|
53 | * 2.70 JMK 04/30/04 Added tRFC maximum check. |
---|
54 | * Combined Self Refresh and Power Down always blocks. |
---|
55 | * Added Reset Function (CKE LOW Anytime). |
---|
56 | * 2.80 JMK 08/19/04 Precharge is treated as NOP when bank is not active. |
---|
57 | * Added checks for tRAS, tWR, tRTP to any bank during Pre-All. |
---|
58 | * tRFC maximum violation will only display one time. |
---|
59 | * 2.90 JMK 11/05/04 Fixed DQS checking during write. |
---|
60 | * Fixed false tRFC max assertion during power up and self ref. |
---|
61 | * Added warning for 200us CKE low time during initialization. |
---|
62 | * Added -3, -3E, and -37V speed grades to ddr2_parameters.v |
---|
63 | * 3.00 JMK 04/22/05 Removed ODT off requirement during power down. |
---|
64 | * Added tAOND, tAOFD, tANPD, tAXPD, tAONPD, and tAOFPD parameters. |
---|
65 | * Added ODT status messages. |
---|
66 | * Updated the initialization sequence. |
---|
67 | * Disable ODT and CLK pins during self refresh. |
---|
68 | * Disable cmd and addr pins during power down and self refresh. |
---|
69 | * 3.10 JMK 06/07/05 Disable trpa checking if the part does not have 8 banks. |
---|
70 | * Changed tAXPD message from error to a warning. |
---|
71 | * Added tDSS checking. |
---|
72 | * Removed tDQSL checking during tWPRE and tWPST. |
---|
73 | * Fixed a burst order error during writes. |
---|
74 | * Renamed parameters file with .vh extension. |
---|
75 | * 3.20 JMK 07/18/05 Removed 14 tCK requirement from LMR to READ. |
---|
76 | * 3.30 JMK 08/03/05 Added check for interrupting a burst with auto precharge. |
---|
77 | * 4.00 JMK 11/21/05 Parameter names all UPPERCASE, signal names all lowercase. |
---|
78 | * Clock jitter can be tolerated within specification range. |
---|
79 | * Clock frequency is sampled from the CK pin. |
---|
80 | * Scaleable up to 64 DQ and 16 DQS bits. |
---|
81 | * Read data can be randomly skewed using RANDOM_OUT_DELAY. |
---|
82 | * Parameterized read and write DQS, and read DQ. |
---|
83 | * Initialization can be bypassed using initialize task. |
---|
84 | * 4.10 JMK 11/30/05 Fixed compile errors when `MAX_MEM was defined. |
---|
85 | * 4.20 JMK 12/09/05 Fixed memory addressing error when `MAX_MEM was defined. |
---|
86 | * 4.30 JMK 02/15/06 Added dummy write to initialization sequence. |
---|
87 | * Removed tWPST maximum checking. |
---|
88 | * Rising dqs_n edge latches data when enabled in EMR. |
---|
89 | * Fixed a sign error in the tJIT(cc) calculation. |
---|
90 | * 4.40 JMK 02/16/06 Fixed dummy write when`MAX_MEM was defined. |
---|
91 | * 4.50 JMK 02/27/06 Fixed extra tDQSS assertions. |
---|
92 | * Fixed tRCD and tWTR checking. |
---|
93 | * Errors entering Power Down or Self Refresh will cause reset. |
---|
94 | * Ignore dqs_n when disabled in EMR. |
---|
95 | * 5.00 JMK 04/24/06 Test stimulus now included from external file (subtest.vh) |
---|
96 | * Fixed tRFC max assertion during self refresh. |
---|
97 | * Fixed tANPD checking during Power Down. |
---|
98 | * Removed dummy write from initialization sequence. |
---|
99 | * 5.01 JMK 04/28/06 Fixed Auto Precharge to Load Mode, Refresh and Self Refresh. |
---|
100 | * Removed Auto Precharge error message during Power Down Enter. |
---|
101 | * 5.10 JMK 07/26/06 Created internal clock using ck and ck_n. |
---|
102 | * RDQS can only be enabled in EMR for x8 configurations. |
---|
103 | * CAS latency is checked vs frequency when DLL locks. |
---|
104 | * tMOD changed from tCK units to ns units. |
---|
105 | * Added 50 Ohm setting for Rtt in EMR. |
---|
106 | * Improved checking of DQS during writes. |
---|
107 | * 5.20 JMK 10/02/06 Fixed DQS checking for interrupting write to write and x16. |
---|
108 | * 5.30 JMK 05/25/07 Fixed checking for 0-Z transition on write postamble. |
---|
109 | * 5.50 JMK 05/30/08 Renamed ddr2_dimm.v to ddr2_module.v and added SODIMM support. |
---|
110 | * Added a register delay to ddr2_module.v when RDIMM is defined. |
---|
111 | * Added multi-chip package model support in ddr2_mcp.v |
---|
112 | * Added High Temp Self Refresh rate setting in EMRS2[7] |
---|
113 | * 5.70 JMK 04/23/09 Updated tRPA definition |
---|
114 | * Increased internal width to 72 bit DQ bus |
---|
115 | * 5.80 SPH 08/12/09 Fixed tRAS maximum violation (only check if bank still open) |
---|
116 | * 5.81 SPH 12/08/09 Only check tIH for cmd_addr if CS# LOW |
---|
117 | * 5.82 SPH 04/08/10 Correct debug message for SRT in EMR2 |
---|
118 | * 5.81 SPH 12/08/09 Only check tIH for cmd_addr if CS# LOW |
---|
119 | * 5.81 SPH 12/08/09 Only check tIH for cmd_addr if CS# LOW |
---|
120 | ****************************************************************************************/ |
---|
121 | |
---|
122 | // DO NOT CHANGE THE TIMESCALE |
---|
123 | // MAKE SURE YOUR SIMULATOR USES "PS" RESOLUTION |
---|
124 | `timescale 1ps / 1ps |
---|
125 | |
---|
126 | module ddr2_model ( |
---|
127 | ck, |
---|
128 | ck_n, |
---|
129 | cke, |
---|
130 | cs_n, |
---|
131 | ras_n, |
---|
132 | cas_n, |
---|
133 | we_n, |
---|
134 | dm_rdqs, |
---|
135 | ba, |
---|
136 | addr, |
---|
137 | dq, |
---|
138 | dqs, |
---|
139 | dqs_n, |
---|
140 | rdqs_n, |
---|
141 | odt |
---|
142 | ); |
---|
143 | |
---|
144 | `include "ddr2_model_parameters.vh" |
---|
145 | |
---|
146 | // text macros |
---|
147 | `define DQ_PER_DQS DQ_BITS/DQS_BITS |
---|
148 | `define BANKS (1<<BA_BITS) |
---|
149 | `define MAX_BITS (BA_BITS+ROW_BITS+COL_BITS-BL_BITS) |
---|
150 | `define MAX_SIZE (1<<(BA_BITS+ROW_BITS+COL_BITS-BL_BITS)) |
---|
151 | `define MEM_SIZE (1<<MEM_BITS) |
---|
152 | `define MAX_PIPE 2*(AL_MAX + CL_MAX) |
---|
153 | |
---|
154 | // Declare Ports |
---|
155 | input ck; |
---|
156 | input ck_n; |
---|
157 | input cke; |
---|
158 | input cs_n; |
---|
159 | input ras_n; |
---|
160 | input cas_n; |
---|
161 | input we_n; |
---|
162 | inout [DM_BITS-1:0] dm_rdqs; |
---|
163 | input [BA_BITS-1:0] ba; |
---|
164 | input [ADDR_BITS-1:0] addr; |
---|
165 | inout [DQ_BITS-1:0] dq; |
---|
166 | inout [DQS_BITS-1:0] dqs; |
---|
167 | inout [DQS_BITS-1:0] dqs_n; |
---|
168 | output [DQS_BITS-1:0] rdqs_n; |
---|
169 | input odt; |
---|
170 | |
---|
171 | // clock jitter |
---|
172 | real tck_avg; |
---|
173 | time tck_sample [TDLLK-1:0]; |
---|
174 | time tch_sample [TDLLK-1:0]; |
---|
175 | time tcl_sample [TDLLK-1:0]; |
---|
176 | time tck_i; |
---|
177 | time tch_i; |
---|
178 | time tcl_i; |
---|
179 | real tch_avg; |
---|
180 | real tcl_avg; |
---|
181 | time tm_ck_pos; |
---|
182 | time tm_ck_neg; |
---|
183 | real tjit_per_rtime; |
---|
184 | integer tjit_cc_time; |
---|
185 | real terr_nper_rtime; |
---|
186 | |
---|
187 | // clock skew |
---|
188 | real out_delay; |
---|
189 | integer dqsck [DQS_BITS-1:0]; |
---|
190 | integer dqsck_min; |
---|
191 | integer dqsck_max; |
---|
192 | integer dqsq_min; |
---|
193 | integer dqsq_max; |
---|
194 | integer seed; |
---|
195 | |
---|
196 | // Mode Registers |
---|
197 | reg burst_order; |
---|
198 | reg [BL_BITS:0] burst_length; |
---|
199 | integer cas_latency; |
---|
200 | integer additive_latency; |
---|
201 | reg dll_reset; |
---|
202 | reg dll_locked; |
---|
203 | reg dll_en; |
---|
204 | integer write_recovery; |
---|
205 | reg low_power; |
---|
206 | reg [1:0] odt_rtt; |
---|
207 | reg odt_en; |
---|
208 | reg [2:0] ocd; |
---|
209 | reg dqs_n_en; |
---|
210 | reg rdqs_en; |
---|
211 | reg out_en; |
---|
212 | integer read_latency; |
---|
213 | integer write_latency; |
---|
214 | |
---|
215 | // cmd encoding |
---|
216 | parameter |
---|
217 | LOAD_MODE = 4'b0000, |
---|
218 | REFRESH = 4'b0001, |
---|
219 | PRECHARGE = 4'b0010, |
---|
220 | ACTIVATE = 4'b0011, |
---|
221 | WRITE = 4'b0100, |
---|
222 | READ = 4'b0101, |
---|
223 | NOP = 4'b0111, |
---|
224 | PWR_DOWN = 4'b1000, |
---|
225 | SELF_REF = 4'b1001 |
---|
226 | ; |
---|
227 | |
---|
228 | reg [8*9-1:0] cmd_string [9:0]; |
---|
229 | initial begin |
---|
230 | cmd_string[LOAD_MODE] = "Load Mode"; |
---|
231 | cmd_string[REFRESH ] = "Refresh "; |
---|
232 | cmd_string[PRECHARGE] = "Precharge"; |
---|
233 | cmd_string[ACTIVATE ] = "Activate "; |
---|
234 | cmd_string[WRITE ] = "Write "; |
---|
235 | cmd_string[READ ] = "Read "; |
---|
236 | cmd_string[NOP ] = "No Op "; |
---|
237 | cmd_string[PWR_DOWN ] = "Pwr Down "; |
---|
238 | cmd_string[SELF_REF ] = "Self Ref "; |
---|
239 | end |
---|
240 | |
---|
241 | // command state |
---|
242 | reg [`BANKS-1:0] active_bank; |
---|
243 | reg [`BANKS-1:0] auto_precharge_bank; |
---|
244 | reg [`BANKS-1:0] write_precharge_bank; |
---|
245 | reg [`BANKS-1:0] read_precharge_bank; |
---|
246 | reg [ROW_BITS-1:0] active_row [`BANKS-1:0]; |
---|
247 | reg in_power_down; |
---|
248 | reg in_self_refresh; |
---|
249 | reg [3:0] init_mode_reg; |
---|
250 | reg init_done; |
---|
251 | integer init_step; |
---|
252 | reg er_trfc_max; |
---|
253 | reg odt_state; |
---|
254 | reg prev_odt; |
---|
255 | |
---|
256 | // cmd timers/counters |
---|
257 | integer ref_cntr; |
---|
258 | integer ck_cntr; |
---|
259 | integer ck_load_mode; |
---|
260 | integer ck_write; |
---|
261 | integer ck_read; |
---|
262 | integer ck_write_ap; |
---|
263 | integer ck_power_down; |
---|
264 | integer ck_slow_exit_pd; |
---|
265 | integer ck_self_refresh; |
---|
266 | integer ck_cke; |
---|
267 | integer ck_odt; |
---|
268 | integer ck_dll_reset; |
---|
269 | integer ck_bank_write [`BANKS-1:0]; |
---|
270 | integer ck_bank_read [`BANKS-1:0]; |
---|
271 | time tm_refresh; |
---|
272 | time tm_precharge; |
---|
273 | time tm_precharge_all; |
---|
274 | time tm_activate; |
---|
275 | time tm_write_end; |
---|
276 | time tm_self_refresh; |
---|
277 | time tm_odt_en; |
---|
278 | time tm_bank_precharge [`BANKS-1:0]; |
---|
279 | time tm_bank_activate [`BANKS-1:0]; |
---|
280 | time tm_bank_write_end [`BANKS-1:0]; |
---|
281 | time tm_bank_read_end [`BANKS-1:0]; |
---|
282 | |
---|
283 | // pipelines |
---|
284 | reg [`MAX_PIPE:0] al_pipeline; |
---|
285 | reg [`MAX_PIPE:0] wr_pipeline; |
---|
286 | reg [`MAX_PIPE:0] rd_pipeline; |
---|
287 | reg [`MAX_PIPE:0] odt_pipeline; |
---|
288 | reg [BA_BITS-1:0] ba_pipeline [`MAX_PIPE:0]; |
---|
289 | reg [ROW_BITS-1:0] row_pipeline [`MAX_PIPE:0]; |
---|
290 | reg [COL_BITS-1:0] col_pipeline [`MAX_PIPE:0]; |
---|
291 | reg prev_cke; |
---|
292 | |
---|
293 | // data state |
---|
294 | reg [BL_MAX*DQ_BITS-1:0] memory_data; |
---|
295 | reg [BL_MAX*DQ_BITS-1:0] bit_mask; |
---|
296 | reg [BL_BITS-1:0] burst_position; |
---|
297 | reg [BL_BITS:0] burst_cntr; |
---|
298 | reg [DQ_BITS-1:0] dq_temp; |
---|
299 | reg [35:0] check_write_postamble; |
---|
300 | reg [35:0] check_write_preamble; |
---|
301 | reg [35:0] check_write_dqs_high; |
---|
302 | reg [35:0] check_write_dqs_low; |
---|
303 | reg [17:0] check_dm_tdipw; |
---|
304 | reg [71:0] check_dq_tdipw; |
---|
305 | |
---|
306 | // data timers/counters |
---|
307 | time tm_cke; |
---|
308 | time tm_odt; |
---|
309 | time tm_tdqss; |
---|
310 | time tm_dm [17:0]; |
---|
311 | time tm_dqs [17:0]; |
---|
312 | time tm_dqs_pos [35:0]; |
---|
313 | time tm_dqss_pos [35:0]; |
---|
314 | time tm_dqs_neg [35:0]; |
---|
315 | time tm_dq [71:0]; |
---|
316 | time tm_cmd_addr [22:0]; |
---|
317 | reg [8*7-1:0] cmd_addr_string [22:0]; |
---|
318 | initial begin |
---|
319 | cmd_addr_string[ 0] = "CS_N "; |
---|
320 | cmd_addr_string[ 1] = "RAS_N "; |
---|
321 | cmd_addr_string[ 2] = "CAS_N "; |
---|
322 | cmd_addr_string[ 3] = "WE_N "; |
---|
323 | cmd_addr_string[ 4] = "BA 0 "; |
---|
324 | cmd_addr_string[ 5] = "BA 1 "; |
---|
325 | cmd_addr_string[ 6] = "BA 2 "; |
---|
326 | cmd_addr_string[ 7] = "ADDR 0"; |
---|
327 | cmd_addr_string[ 8] = "ADDR 1"; |
---|
328 | cmd_addr_string[ 9] = "ADDR 2"; |
---|
329 | cmd_addr_string[10] = "ADDR 3"; |
---|
330 | cmd_addr_string[11] = "ADDR 4"; |
---|
331 | cmd_addr_string[12] = "ADDR 5"; |
---|
332 | cmd_addr_string[13] = "ADDR 6"; |
---|
333 | cmd_addr_string[14] = "ADDR 7"; |
---|
334 | cmd_addr_string[15] = "ADDR 8"; |
---|
335 | cmd_addr_string[16] = "ADDR 9"; |
---|
336 | cmd_addr_string[17] = "ADDR 10"; |
---|
337 | cmd_addr_string[18] = "ADDR 11"; |
---|
338 | cmd_addr_string[19] = "ADDR 12"; |
---|
339 | cmd_addr_string[20] = "ADDR 13"; |
---|
340 | cmd_addr_string[21] = "ADDR 14"; |
---|
341 | cmd_addr_string[22] = "ADDR 15"; |
---|
342 | end |
---|
343 | |
---|
344 | reg [8*5-1:0] dqs_string [1:0]; |
---|
345 | initial begin |
---|
346 | dqs_string[0] = "DQS "; |
---|
347 | dqs_string[1] = "DQS_N"; |
---|
348 | end |
---|
349 | |
---|
350 | // Memory Storage |
---|
351 | `ifdef MAX_MEM |
---|
352 | reg [BL_MAX*DQ_BITS-1:0] memory [0:`MAX_SIZE-1]; |
---|
353 | `else |
---|
354 | reg [BL_MAX*DQ_BITS-1:0] memory [0:`MEM_SIZE-1]; |
---|
355 | reg [`MAX_BITS-1:0] address [0:`MEM_SIZE-1]; |
---|
356 | reg [MEM_BITS:0] memory_index; |
---|
357 | reg [MEM_BITS:0] memory_used; |
---|
358 | `endif |
---|
359 | |
---|
360 | // receive |
---|
361 | reg ck_in; |
---|
362 | reg ck_n_in; |
---|
363 | reg cke_in; |
---|
364 | reg cs_n_in; |
---|
365 | reg ras_n_in; |
---|
366 | reg cas_n_in; |
---|
367 | reg we_n_in; |
---|
368 | reg [17:0] dm_in; |
---|
369 | reg [2:0] ba_in; |
---|
370 | reg [15:0] addr_in; |
---|
371 | reg [71:0] dq_in; |
---|
372 | reg [35:0] dqs_in; |
---|
373 | reg odt_in; |
---|
374 | |
---|
375 | reg [17:0] dm_in_pos; |
---|
376 | reg [17:0] dm_in_neg; |
---|
377 | reg [71:0] dq_in_pos; |
---|
378 | reg [71:0] dq_in_neg; |
---|
379 | reg dq_in_valid; |
---|
380 | reg dqs_in_valid; |
---|
381 | integer wdqs_cntr; |
---|
382 | integer wdq_cntr; |
---|
383 | integer wdqs_pos_cntr [35:0]; |
---|
384 | reg b2b_write; |
---|
385 | reg [35:0] prev_dqs_in; |
---|
386 | reg diff_ck; |
---|
387 | |
---|
388 | always @(ck ) ck_in <= #BUS_DELAY ck; |
---|
389 | always @(ck_n ) ck_n_in <= #BUS_DELAY ck_n; |
---|
390 | always @(cke ) cke_in <= #BUS_DELAY cke; |
---|
391 | always @(cs_n ) cs_n_in <= #BUS_DELAY cs_n; |
---|
392 | always @(ras_n ) ras_n_in <= #BUS_DELAY ras_n; |
---|
393 | always @(cas_n ) cas_n_in <= #BUS_DELAY cas_n; |
---|
394 | always @(we_n ) we_n_in <= #BUS_DELAY we_n; |
---|
395 | always @(dm_rdqs) dm_in <= #BUS_DELAY dm_rdqs; |
---|
396 | always @(ba ) ba_in <= #BUS_DELAY ba; |
---|
397 | always @(addr ) addr_in <= #BUS_DELAY addr; |
---|
398 | always @(dq ) dq_in <= #BUS_DELAY dq; |
---|
399 | always @(dqs or dqs_n) dqs_in <= #BUS_DELAY (dqs_n<<18) | dqs; |
---|
400 | always @(odt ) odt_in <= #BUS_DELAY odt; |
---|
401 | // create internal clock |
---|
402 | always @(posedge ck_in) diff_ck <= ck_in; |
---|
403 | always @(posedge ck_n_in) diff_ck <= ~ck_n_in; |
---|
404 | |
---|
405 | wire [17:0] dqs_even = dqs_in[17:0]; |
---|
406 | wire [17:0] dqs_odd = dqs_n_en ? dqs_in[35:18] : ~dqs_in[17:0]; |
---|
407 | wire [3:0] cmd_n_in = !cs_n_in ? {ras_n_in, cas_n_in, we_n_in} : NOP; //deselect = nop |
---|
408 | |
---|
409 | // transmit |
---|
410 | reg dqs_out_en; |
---|
411 | reg [DQS_BITS-1:0] dqs_out_en_dly; |
---|
412 | reg dqs_out; |
---|
413 | reg [DQS_BITS-1:0] dqs_out_dly; |
---|
414 | reg dq_out_en; |
---|
415 | reg [DQ_BITS-1:0] dq_out_en_dly; |
---|
416 | reg [DQ_BITS-1:0] dq_out; |
---|
417 | reg [DQ_BITS-1:0] dq_out_dly; |
---|
418 | integer rdqsen_cntr; |
---|
419 | integer rdqs_cntr; |
---|
420 | integer rdqen_cntr; |
---|
421 | integer rdq_cntr; |
---|
422 | |
---|
423 | bufif1 buf_dqs [DQS_BITS-1:0] (dqs, dqs_out_dly, dqs_out_en_dly & {DQS_BITS{out_en}}); |
---|
424 | bufif1 buf_dm [DM_BITS-1:0] (dm_rdqs, dqs_out_dly, dqs_out_en_dly & {DM_BITS {out_en}} & {DM_BITS{rdqs_en}}); |
---|
425 | bufif1 buf_dqs_n [DQS_BITS-1:0] (dqs_n, ~dqs_out_dly, dqs_out_en_dly & {DQS_BITS{out_en}} & {DQS_BITS{dqs_n_en}}); |
---|
426 | bufif1 buf_rdqs_n [DQS_BITS-1:0] (rdqs_n, ~dqs_out_dly, dqs_out_en_dly & {DQS_BITS{out_en}} & {DQS_BITS{dqs_n_en}} & {DQS_BITS{rdqs_en}}); |
---|
427 | bufif1 buf_dq [DQ_BITS-1:0] (dq, dq_out_dly, dq_out_en_dly & {DQ_BITS {out_en}}); |
---|
428 | |
---|
429 | initial begin |
---|
430 | if (BL_MAX < 2) |
---|
431 | $display("%m ERROR: BL_MAX parameter must be >= 2. \nBL_MAX = %d", BL_MAX); |
---|
432 | if ((1<<BO_BITS) > BL_MAX) |
---|
433 | $display("%m ERROR: 2^BO_BITS cannot be greater than BL_MAX parameter."); |
---|
434 | $timeformat (-12, 1, " ps", 1); |
---|
435 | reset_task; |
---|
436 | seed = RANDOM_SEED; |
---|
437 | ck_cntr = 0; |
---|
438 | end |
---|
439 | |
---|
440 | // calculate the absolute value of a real number |
---|
441 | function real abs_value; |
---|
442 | input arg; |
---|
443 | real arg; |
---|
444 | begin |
---|
445 | if (arg < 0.0) |
---|
446 | abs_value = -1.0 * arg; |
---|
447 | else |
---|
448 | abs_value = arg; |
---|
449 | end |
---|
450 | endfunction |
---|
451 | |
---|
452 | `ifdef MAX_MEM |
---|
453 | `else |
---|
454 | function get_index; |
---|
455 | input [`MAX_BITS-1:0] addr; |
---|
456 | begin : index |
---|
457 | get_index = 0; |
---|
458 | for (memory_index=0; memory_index<memory_used; memory_index=memory_index+1) begin |
---|
459 | if (address[memory_index] == addr) begin |
---|
460 | get_index = 1; |
---|
461 | disable index; |
---|
462 | end |
---|
463 | end |
---|
464 | end |
---|
465 | endfunction |
---|
466 | `endif |
---|
467 | |
---|
468 | task memory_write; |
---|
469 | input [BA_BITS-1:0] bank; |
---|
470 | input [ROW_BITS-1:0] row; |
---|
471 | input [COL_BITS-1:0] col; |
---|
472 | input [BL_MAX*DQ_BITS-1:0] data; |
---|
473 | reg [`MAX_BITS-1:0] addr; |
---|
474 | begin |
---|
475 | // chop off the lowest address bits |
---|
476 | addr = {bank, row, col}/BL_MAX; |
---|
477 | `ifdef MAX_MEM |
---|
478 | memory[addr] = data; |
---|
479 | `else |
---|
480 | if (get_index(addr)) begin |
---|
481 | address[memory_index] = addr; |
---|
482 | memory[memory_index] = data; |
---|
483 | end else if (memory_used == `MEM_SIZE) begin |
---|
484 | $display ("%m: at time %t ERROR: Memory overflow. Write to Address %h with Data %h will be lost.\nYou must increase the MEM_BITS parameter or define MAX_MEM.", $time, addr, data); |
---|
485 | if (STOP_ON_ERROR) $stop(0); |
---|
486 | end else begin |
---|
487 | address[memory_used] = addr; |
---|
488 | memory[memory_used] = data; |
---|
489 | memory_used = memory_used + 1; |
---|
490 | end |
---|
491 | `endif |
---|
492 | end |
---|
493 | endtask |
---|
494 | |
---|
495 | task memory_read; |
---|
496 | input [BA_BITS-1:0] bank; |
---|
497 | input [ROW_BITS-1:0] row; |
---|
498 | input [COL_BITS-1:0] col; |
---|
499 | output [BL_MAX*DQ_BITS-1:0] data; |
---|
500 | reg [`MAX_BITS-1:0] addr; |
---|
501 | begin |
---|
502 | // chop off the lowest address bits |
---|
503 | addr = {bank, row, col}/BL_MAX; |
---|
504 | `ifdef MAX_MEM |
---|
505 | data = memory[addr]; |
---|
506 | `else |
---|
507 | if (get_index(addr)) begin |
---|
508 | data = memory[memory_index]; |
---|
509 | end else begin |
---|
510 | data = {BL_MAX*DQ_BITS{1'bx}}; |
---|
511 | end |
---|
512 | `endif |
---|
513 | end |
---|
514 | endtask |
---|
515 | |
---|
516 | // Before this task runs, the model must be in a valid state for precharge power down. |
---|
517 | // After this task runs, NOP commands must be issued until tRFC has been met |
---|
518 | task initialize; |
---|
519 | input [ADDR_BITS-1:0] mode_reg0; |
---|
520 | input [ADDR_BITS-1:0] mode_reg1; |
---|
521 | input [ADDR_BITS-1:0] mode_reg2; |
---|
522 | input [ADDR_BITS-1:0] mode_reg3; |
---|
523 | begin |
---|
524 | if (DEBUG) $display ("%m: at time %t INFO: Performing Initialization Sequence", $time); |
---|
525 | cmd_task(1, NOP, 'bx, 'bx); |
---|
526 | cmd_task(1, PRECHARGE, 'bx, 1<<AP); // Precharege ALL |
---|
527 | cmd_task(1, LOAD_MODE, 3, mode_reg3); |
---|
528 | cmd_task(1, LOAD_MODE, 2, mode_reg2); |
---|
529 | cmd_task(1, LOAD_MODE, 1, mode_reg1); |
---|
530 | cmd_task(1, LOAD_MODE, 0, mode_reg0 | 'h100); // DLL Reset |
---|
531 | cmd_task(1, PRECHARGE, 'bx, 1<<AP); // Precharege ALL |
---|
532 | cmd_task(1, REFRESH, 'bx, 'bx); |
---|
533 | cmd_task(1, REFRESH, 'bx, 'bx); |
---|
534 | cmd_task(1, LOAD_MODE, 0, mode_reg0); |
---|
535 | cmd_task(1, LOAD_MODE, 1, mode_reg1 | 'h380); // OCD Default |
---|
536 | cmd_task(1, LOAD_MODE, 1, mode_reg1); |
---|
537 | cmd_task(0, NOP, 'bx, 'bx); |
---|
538 | end |
---|
539 | endtask |
---|
540 | |
---|
541 | task reset_task; |
---|
542 | integer i; |
---|
543 | begin |
---|
544 | // disable inputs |
---|
545 | dq_in_valid = 0; |
---|
546 | dqs_in_valid <= 0; |
---|
547 | wdqs_cntr = 0; |
---|
548 | wdq_cntr = 0; |
---|
549 | for (i=0; i<36; i=i+1) begin |
---|
550 | wdqs_pos_cntr[i] <= 0; |
---|
551 | end |
---|
552 | b2b_write <= 0; |
---|
553 | // disable outputs |
---|
554 | out_en = 0; |
---|
555 | dqs_n_en = 0; |
---|
556 | rdqs_en = 0; |
---|
557 | dq_out_en = 0; |
---|
558 | rdq_cntr = 0; |
---|
559 | dqs_out_en = 0; |
---|
560 | rdqs_cntr = 0; |
---|
561 | // disable ODT |
---|
562 | odt_en = 0; |
---|
563 | odt_state = 0; |
---|
564 | // reset bank state |
---|
565 | active_bank = {`BANKS{1'b1}}; |
---|
566 | auto_precharge_bank = 0; |
---|
567 | read_precharge_bank = 0; |
---|
568 | write_precharge_bank = 0; |
---|
569 | // require initialization sequence |
---|
570 | init_done = 0; |
---|
571 | init_step = 0; |
---|
572 | init_mode_reg = 0; |
---|
573 | // reset DLL |
---|
574 | dll_en = 0; |
---|
575 | dll_reset = 0; |
---|
576 | dll_locked = 0; |
---|
577 | ocd = 0; |
---|
578 | // exit power down and self refresh |
---|
579 | in_power_down = 0; |
---|
580 | in_self_refresh = 0; |
---|
581 | // clear pipelines |
---|
582 | al_pipeline = 0; |
---|
583 | wr_pipeline = 0; |
---|
584 | rd_pipeline = 0; |
---|
585 | odt_pipeline = 0; |
---|
586 | // clear memory |
---|
587 | `ifdef MAX_MEM |
---|
588 | for (i=0; i<=`MAX_SIZE; i=i+1) begin //erase memory ... one address at a time |
---|
589 | memory[i] <= 'bx; |
---|
590 | end |
---|
591 | `else |
---|
592 | memory_used <= 0; //erase memory |
---|
593 | `endif |
---|
594 | // clear maximum timing checks |
---|
595 | tm_refresh <= 'bx; |
---|
596 | for (i=0; i<`BANKS; i=i+1) begin |
---|
597 | tm_bank_activate[i] <= 'bx; |
---|
598 | end |
---|
599 | end |
---|
600 | endtask |
---|
601 | |
---|
602 | task chk_err; |
---|
603 | input samebank; |
---|
604 | input [BA_BITS-1:0] bank; |
---|
605 | input [3:0] fromcmd; |
---|
606 | input [3:0] cmd; |
---|
607 | reg err; |
---|
608 | begin |
---|
609 | // all matching case expressions will be evaluated |
---|
610 | casex ({samebank, fromcmd, cmd}) |
---|
611 | {1'b0, LOAD_MODE, 4'b0xxx } : begin if (ck_cntr - ck_load_mode < TMRD) $display ("%m: at time %t ERROR: tMRD violation during %s", $time, cmd_string[cmd]); end |
---|
612 | {1'b0, LOAD_MODE, 4'b100x } : begin if (ck_cntr - ck_load_mode < TMRD) begin $display ("%m: at time %t INFO: Load Mode to Reset condition.", $time); init_done = 0; end end |
---|
613 | {1'b0, REFRESH , 4'b0xxx } : begin if ($time - tm_refresh < TRFC_MIN) $display ("%m: at time %t ERROR: tRFC violation during %s", $time, cmd_string[cmd]); end |
---|
614 | {1'b0, REFRESH , PWR_DOWN } : ; // 1 tCK |
---|
615 | {1'b0, REFRESH , SELF_REF } : begin if ($time - tm_refresh < TRFC_MIN) begin $display ("%m: at time %t INFO: Refresh to Reset condition", $time); init_done = 0; end end |
---|
616 | {1'b0, PRECHARGE, 4'b000x } : begin if ($time - tm_precharge_all < TRPA) $display ("%m: at time %t ERROR: tRPA violation during %s", $time, cmd_string[cmd]); |
---|
617 | if ($time - tm_precharge < TRP) $display ("%m: at time %t ERROR: tRP violation during %s", $time, cmd_string[cmd]); end |
---|
618 | {1'b1, PRECHARGE, PRECHARGE} : begin if (DEBUG && ($time - tm_precharge_all < TRPA)) $display ("%m: at time %t INFO: Precharge All interruption during %s", $time, cmd_string[cmd]); |
---|
619 | if (DEBUG && ($time - tm_bank_precharge[bank] < TRP)) $display ("%m: at time %t INFO: Precharge bank %d interruption during %s", $time, cmd_string[cmd], bank); end |
---|
620 | {1'b1, PRECHARGE, ACTIVATE } : begin if ($time - tm_precharge_all < TRPA) $display ("%m: at time %t ERROR: tRPA violation during %s", $time, cmd_string[cmd]); |
---|
621 | if ($time - tm_bank_precharge[bank] < TRP) $display ("%m: at time %t ERROR: tRP violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
622 | {1'b0, PRECHARGE, PWR_DOWN } : ; //1 tCK, can be concurrent with auto precharge |
---|
623 | {1'b0, PRECHARGE, SELF_REF } : begin if (($time - tm_precharge_all < TRPA) || ($time - tm_precharge < TRP)) begin $display ("%m: at time %t INFO: Precharge to Reset condition", $time); init_done = 0; end end |
---|
624 | {1'b0, ACTIVATE , REFRESH } : begin if ($time - tm_activate < TRC) $display ("%m: at time %t ERROR: tRC violation during %s", $time, cmd_string[cmd]); end |
---|
625 | {1'b1, ACTIVATE , PRECHARGE} : begin if (($time - tm_bank_activate[bank] > TRAS_MAX) && (active_bank[bank] === 1'b1)) $display ("%m: at time %t ERROR: tRAS maximum violation during %s to bank %d", $time, cmd_string[cmd], bank); |
---|
626 | if ($time - tm_bank_activate[bank] < TRAS_MIN) $display ("%m: at time %t ERROR: tRAS minimum violation during %s to bank %d", $time, cmd_string[cmd], bank);end |
---|
627 | {1'b0, ACTIVATE , ACTIVATE } : begin if ($time - tm_activate < TRRD) $display ("%m: at time %t ERROR: tRRD violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
628 | {1'b1, ACTIVATE , ACTIVATE } : begin if ($time - tm_bank_activate[bank] < TRC) $display ("%m: at time %t ERROR: tRC violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
629 | {1'b1, ACTIVATE , 4'b010x } : ; // tRCD is checked outside this task |
---|
630 | {1'b1, ACTIVATE , PWR_DOWN } : ; // 1 tCK |
---|
631 | {1'b1, WRITE , PRECHARGE} : begin if ((ck_cntr - ck_bank_write[bank] <= write_latency + burst_length/2) || ($time - tm_bank_write_end[bank] < TWR)) $display ("%m: at time %t ERROR: tWR violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
632 | {1'b0, WRITE , WRITE } : begin if (ck_cntr - ck_write < TCCD) $display ("%m: at time %t ERROR: tCCD violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
633 | {1'b0, WRITE , READ } : begin if ((ck_load_mode < ck_write) && (ck_cntr - ck_write < write_latency + burst_length/2 + 2 - additive_latency)) $display ("%m: at time %t ERROR: tWTR violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
634 | {1'b0, WRITE , PWR_DOWN } : begin if ((ck_load_mode < ck_write) && ( |
---|
635 | |write_precharge_bank |
---|
636 | || (ck_cntr - ck_write_ap < 1) |
---|
637 | || (ck_cntr - ck_write < write_latency + burst_length/2 + 2) |
---|
638 | || ($time - tm_write_end < TWTR))) begin $display ("%m: at time %t INFO: Write to Reset condition", $time); init_done = 0; end end |
---|
639 | {1'b1, READ , PRECHARGE} : begin if ((ck_cntr - ck_bank_read[bank] < additive_latency + burst_length/2) || ($time - tm_bank_read_end[bank] < TRTP)) $display ("%m: at time %t ERROR: tRTP violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
640 | {1'b0, READ , WRITE } : begin if ((ck_load_mode < ck_read) && (ck_cntr - ck_read < read_latency + burst_length/2 + 1 - write_latency)) $display ("%m: at time %t ERROR: tRTW violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
641 | {1'b0, READ , READ } : begin if (ck_cntr - ck_read < TCCD) $display ("%m: at time %t ERROR: tCCD violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
---|
642 | {1'b0, READ , PWR_DOWN } : begin if ((ck_load_mode < ck_read) && (ck_cntr - ck_read < read_latency + burst_length/2 + 1)) begin $display ("%m: at time %t INFO: Read to Reset condition", $time); init_done = 0; end end |
---|
643 | {1'b0, PWR_DOWN , 4'b00xx } : begin if (ck_cntr - ck_power_down < TXP) $display ("%m: at time %t ERROR: tXP violation during %s", $time, cmd_string[cmd]); end |
---|
644 | {1'b0, PWR_DOWN , WRITE } : begin if (ck_cntr - ck_power_down < TXP) $display ("%m: at time %t ERROR: tXP violation during %s", $time, cmd_string[cmd]); end |
---|
645 | {1'b0, PWR_DOWN , READ } : begin if (ck_cntr - ck_slow_exit_pd < TXARDS - additive_latency) $display ("%m: at time %t ERROR: tXARDS violation during %s", $time, cmd_string[cmd]); |
---|
646 | else if (ck_cntr - ck_power_down < TXARD) $display ("%m: at time %t ERROR: tXARD violation during %s", $time, cmd_string[cmd]); end |
---|
647 | {1'b0, SELF_REF , 4'b00xx } : begin if ($time - tm_self_refresh < TXSNR) $display ("%m: at time %t ERROR: tXSNR violation during %s", $time, cmd_string[cmd]); end |
---|
648 | {1'b0, SELF_REF , WRITE } : begin if ($time - tm_self_refresh < TXSNR) $display ("%m: at time %t ERROR: tXSNR violation during %s", $time, cmd_string[cmd]); end |
---|
649 | {1'b0, SELF_REF , READ } : begin if (ck_cntr - ck_self_refresh < TXSRD) $display ("%m: at time %t ERROR: tXSRD violation during %s", $time, cmd_string[cmd]); end |
---|
650 | {1'b0, 4'b100x , 4'b100x } : begin if (ck_cntr - ck_cke < TCKE) begin $display ("%m: at time %t ERROR: tCKE violation on CKE", $time); init_done = 0; end end |
---|
651 | endcase |
---|
652 | end |
---|
653 | endtask |
---|
654 | |
---|
655 | task cmd_task; |
---|
656 | input cke; |
---|
657 | input [2:0] cmd; |
---|
658 | input [BA_BITS-1:0] bank; |
---|
659 | input [ADDR_BITS-1:0] addr; |
---|
660 | reg [`BANKS:0] i; |
---|
661 | integer j; |
---|
662 | reg [`BANKS:0] tfaw_cntr; |
---|
663 | reg [COL_BITS-1:0] col; |
---|
664 | begin |
---|
665 | |
---|
666 | // tRFC max check |
---|
667 | if (!er_trfc_max && !in_self_refresh) begin |
---|
668 | if ($time - tm_refresh > TRFC_MAX) begin |
---|
669 | $display ("%m: at time %t ERROR: tRFC maximum violation during %s", $time, cmd_string[cmd]); |
---|
670 | er_trfc_max = 1; |
---|
671 | end |
---|
672 | end |
---|
673 | if (cke) begin |
---|
674 | if ((cmd < NOP) && ((cmd != PRECHARGE) || !addr[AP])) begin |
---|
675 | for (j=0; j<NOP; j=j+1) begin |
---|
676 | chk_err(1'b0, bank, j, cmd); |
---|
677 | chk_err(1'b1, bank, j, cmd); |
---|
678 | end |
---|
679 | chk_err(1'b0, bank, PWR_DOWN, cmd); |
---|
680 | chk_err(1'b0, bank, SELF_REF, cmd); |
---|
681 | end |
---|
682 | |
---|
683 | case (cmd) |
---|
684 | LOAD_MODE : begin |
---|
685 | if (|active_bank) begin |
---|
686 | $display ("%m: at time %t ERROR: %s Failure. All banks must be Precharged.", $time, cmd_string[cmd]); |
---|
687 | if (STOP_ON_ERROR) $stop(0); |
---|
688 | end else begin |
---|
689 | if (DEBUG) $display ("%m: at time %t INFO: %s %d", $time, cmd_string[cmd], bank); |
---|
690 | case (bank) |
---|
691 | 0 : begin |
---|
692 | // Burst Length |
---|
693 | burst_length = 1<<addr[2:0]; |
---|
694 | if ((burst_length >= BL_MIN) && (burst_length <= BL_MAX)) begin |
---|
695 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Length = %d", $time, cmd_string[cmd], bank, burst_length); |
---|
696 | end else begin |
---|
697 | $display ("%m: at time %t ERROR: %s %d Illegal Burst Length = %d", $time, cmd_string[cmd], bank, burst_length); |
---|
698 | end |
---|
699 | // Burst Order |
---|
700 | burst_order = addr[3]; |
---|
701 | if (!burst_order) begin |
---|
702 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Order = Sequential", $time, cmd_string[cmd], bank); |
---|
703 | end else if (burst_order) begin |
---|
704 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Order = Interleaved", $time, cmd_string[cmd], bank); |
---|
705 | end else begin |
---|
706 | $display ("%m: at time %t ERROR: %s %d Illegal Burst Order = %d", $time, cmd_string[cmd], bank, burst_order); |
---|
707 | end |
---|
708 | // CAS Latency |
---|
709 | cas_latency = addr[6:4]; |
---|
710 | read_latency = cas_latency + additive_latency; |
---|
711 | write_latency = read_latency - 1; |
---|
712 | if ((cas_latency >= CL_MIN) && (cas_latency <= CL_MAX)) begin |
---|
713 | if (DEBUG) $display ("%m: at time %t INFO: %s %d CAS Latency = %d", $time, cmd_string[cmd], bank, cas_latency); |
---|
714 | end else begin |
---|
715 | $display ("%m: at time %t ERROR: %s %d Illegal CAS Latency = %d", $time, cmd_string[cmd], bank, cas_latency); |
---|
716 | end |
---|
717 | // Test Mode |
---|
718 | if (!addr[7]) begin |
---|
719 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Test Mode = Normal", $time, cmd_string[cmd], bank); |
---|
720 | end else begin |
---|
721 | $display ("%m: at time %t ERROR: %s %d Illegal Test Mode = %d", $time, cmd_string[cmd], bank, addr[7]); |
---|
722 | end |
---|
723 | // DLL Reset |
---|
724 | dll_reset = addr[8]; |
---|
725 | if (!dll_reset) begin |
---|
726 | if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Reset = Normal", $time, cmd_string[cmd], bank); |
---|
727 | end else if (dll_reset) begin |
---|
728 | if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Reset = Reset DLL", $time, cmd_string[cmd], bank); |
---|
729 | dll_locked = 0; |
---|
730 | ck_dll_reset <= ck_cntr; |
---|
731 | end else begin |
---|
732 | $display ("%m: at time %t ERROR: %s %d Illegal DLL Reset = %d", $time, cmd_string[cmd], bank, dll_reset); |
---|
733 | end |
---|
734 | // Write Recovery |
---|
735 | write_recovery = addr[11:9] + 1; |
---|
736 | if ((write_recovery >= WR_MIN) && (write_recovery <= WR_MAX)) begin |
---|
737 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Write Recovery = %d", $time, cmd_string[cmd], bank, write_recovery); |
---|
738 | end else begin |
---|
739 | $display ("%m: at time %t ERROR: %s %d Illegal Write Recovery = %d", $time, cmd_string[cmd], bank, write_recovery); |
---|
740 | end |
---|
741 | // Power Down Mode |
---|
742 | low_power = addr[12]; |
---|
743 | if (!low_power) begin |
---|
744 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Power Down Mode = Fast Exit", $time, cmd_string[cmd], bank); |
---|
745 | end else if (low_power) begin |
---|
746 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Power Down Mode = Slow Exit", $time, cmd_string[cmd], bank); |
---|
747 | end else begin |
---|
748 | $display ("%m: at time %t ERROR: %s %d Illegal Power Down Mode = %d", $time, cmd_string[cmd], bank, low_power); |
---|
749 | end |
---|
750 | end |
---|
751 | 1 : begin |
---|
752 | // DLL Enable |
---|
753 | dll_en = !addr[0]; |
---|
754 | if (!dll_en) begin |
---|
755 | if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Enable = Disabled", $time, cmd_string[cmd], bank); |
---|
756 | end else if (dll_en) begin |
---|
757 | if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Enable = Enabled", $time, cmd_string[cmd], bank); |
---|
758 | end else begin |
---|
759 | $display ("%m: at time %t ERROR: %s %d Illegal DLL Enable = %d", $time, cmd_string[cmd], bank, dll_en); |
---|
760 | end |
---|
761 | // Output Drive Strength |
---|
762 | if (!addr[1]) begin |
---|
763 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Drive Strength = Full", $time, cmd_string[cmd], bank); |
---|
764 | end else if (addr[1]) begin |
---|
765 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Drive Strength = Reduced", $time, cmd_string[cmd], bank); |
---|
766 | end else begin |
---|
767 | $display ("%m: at time %t ERROR: %s %d Illegal Output Drive Strength = %d", $time, cmd_string[cmd], bank, addr[1]); |
---|
768 | end |
---|
769 | // ODT Rtt |
---|
770 | odt_rtt = {addr[6], addr[2]}; |
---|
771 | if (odt_rtt == 2'b00) begin |
---|
772 | if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = Disabled", $time, cmd_string[cmd], bank); |
---|
773 | odt_en = 0; |
---|
774 | end else if (odt_rtt == 2'b01) begin |
---|
775 | if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 75 Ohm", $time, cmd_string[cmd], bank); |
---|
776 | odt_en = 1; |
---|
777 | tm_odt_en <= $time; |
---|
778 | end else if (odt_rtt == 2'b10) begin |
---|
779 | if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 150 Ohm", $time, cmd_string[cmd], bank); |
---|
780 | odt_en = 1; |
---|
781 | tm_odt_en <= $time; |
---|
782 | end else if (odt_rtt == 2'b11) begin |
---|
783 | if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 50 Ohm", $time, cmd_string[cmd], bank); |
---|
784 | odt_en = 1; |
---|
785 | tm_odt_en <= $time; |
---|
786 | end else begin |
---|
787 | $display ("%m: at time %t ERROR: %s %d Illegal ODT Rtt = %d", $time, cmd_string[cmd], bank, odt_rtt); |
---|
788 | odt_en = 0; |
---|
789 | end |
---|
790 | // Additive Latency |
---|
791 | additive_latency = addr[5:3]; |
---|
792 | read_latency = cas_latency + additive_latency; |
---|
793 | write_latency = read_latency - 1; |
---|
794 | if ((additive_latency >= AL_MIN) && (additive_latency <= AL_MAX)) begin |
---|
795 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Additive Latency = %d", $time, cmd_string[cmd], bank, additive_latency); |
---|
796 | end else begin |
---|
797 | $display ("%m: at time %t ERROR: %s %d Illegal Additive Latency = %d", $time, cmd_string[cmd], bank, additive_latency); |
---|
798 | end |
---|
799 | // OCD Program |
---|
800 | ocd = addr[9:7]; |
---|
801 | if (ocd == 3'b000) begin |
---|
802 | if (DEBUG) $display ("%m: at time %t INFO: %s %d OCD Program = OCD Exit", $time, cmd_string[cmd], bank); |
---|
803 | end else if (ocd == 3'b111) begin |
---|
804 | if (DEBUG) $display ("%m: at time %t INFO: %s %d OCD Program = OCD Default", $time, cmd_string[cmd], bank); |
---|
805 | end else begin |
---|
806 | $display ("%m: at time %t ERROR: %s %d Illegal OCD Program = %b", $time, cmd_string[cmd], bank, ocd); |
---|
807 | end |
---|
808 | |
---|
809 | // DQS_N Enable |
---|
810 | dqs_n_en = !addr[10]; |
---|
811 | if (!dqs_n_en) begin |
---|
812 | if (DEBUG) $display ("%m: at time %t INFO: %s %d DQS_N Enable = Disabled", $time, cmd_string[cmd], bank); |
---|
813 | end else if (dqs_n_en) begin |
---|
814 | if (DEBUG) $display ("%m: at time %t INFO: %s %d DQS_N Enable = Enabled", $time, cmd_string[cmd], bank); |
---|
815 | end else begin |
---|
816 | $display ("%m: at time %t ERROR: %s %d Illegal DQS_N Enable = %d", $time, cmd_string[cmd], bank, dqs_n_en); |
---|
817 | end |
---|
818 | // RDQS Enable |
---|
819 | rdqs_en = addr[11]; |
---|
820 | if (!rdqs_en) begin |
---|
821 | if (DEBUG) $display ("%m: at time %t INFO: %s %d RDQS Enable = Disabled", $time, cmd_string[cmd], bank); |
---|
822 | end else if (rdqs_en) begin |
---|
823 | `ifdef x8 |
---|
824 | if (DEBUG) $display ("%m: at time %t INFO: %s %d RDQS Enable = Enabled", $time, cmd_string[cmd], bank); |
---|
825 | `else |
---|
826 | $display ("%m: at time %t WARNING: %s %d Illegal RDQS Enable. RDQS only exists on a x8 part", $time, cmd_string[cmd], bank); |
---|
827 | rdqs_en = 0; |
---|
828 | `endif |
---|
829 | end else begin |
---|
830 | $display ("%m: at time %t ERROR: %s %d Illegal RDQS Enable = %d", $time, cmd_string[cmd], bank, rdqs_en); |
---|
831 | end |
---|
832 | // Output Enable |
---|
833 | out_en = !addr[12]; |
---|
834 | if (!out_en) begin |
---|
835 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Enable = Disabled", $time, cmd_string[cmd], bank); |
---|
836 | end else if (out_en) begin |
---|
837 | if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Enable = Enabled", $time, cmd_string[cmd], bank); |
---|
838 | end else begin |
---|
839 | $display ("%m: at time %t ERROR: %s %d Illegal Output Enable = %d", $time, cmd_string[cmd], bank, out_en); |
---|
840 | end |
---|
841 | end |
---|
842 | 2 : begin |
---|
843 | // High Temperature Self Refresh rate |
---|
844 | if (!addr[7]) begin |
---|
845 | if (DEBUG) $display ("%m: at time %t INFO: %s %d High Temperature Self Refresh rate = 1X (0C-85C)", $time, cmd_string[cmd], bank); |
---|
846 | end else if (addr[7]) begin |
---|
847 | if (DEBUG) $display ("%m: at time %t INFO: %s %d High Temperature Self Refresh rate = 2X (>85C)", $time, cmd_string[cmd], bank); |
---|
848 | end else begin |
---|
849 | $display ("%m: at time %t ERROR: %s %d Illegal High Temperature Self Refresh rate = %d", $time, cmd_string[cmd], bank, addr[7]); |
---|
850 | end |
---|
851 | if ((addr & ~(1<<7)) !== 0) begin |
---|
852 | $display ("%m: at time %t ERROR: %s %d Illegal value. Reserved bits must be programmed to zero", $time, cmd_string[cmd], bank); |
---|
853 | end |
---|
854 | end |
---|
855 | 3 : begin |
---|
856 | if (addr !== 0) begin |
---|
857 | $display ("%m: at time %t ERROR: %s %d Illegal value. Reserved bits must be programmed to zero", $time, cmd_string[cmd], bank); |
---|
858 | end |
---|
859 | end |
---|
860 | endcase |
---|
861 | init_mode_reg[bank] = 1; |
---|
862 | ck_load_mode <= ck_cntr; |
---|
863 | end |
---|
864 | end |
---|
865 | REFRESH : begin |
---|
866 | if (|active_bank) begin |
---|
867 | $display ("%m: at time %t ERROR: %s Failure. All banks must be Precharged.", $time, cmd_string[cmd]); |
---|
868 | if (STOP_ON_ERROR) $stop(0); |
---|
869 | end else begin |
---|
870 | if (DEBUG) $display ("%m: at time %t INFO: %s", $time, cmd_string[cmd]); |
---|
871 | er_trfc_max = 0; |
---|
872 | ref_cntr = ref_cntr + 1; |
---|
873 | tm_refresh <= $time; |
---|
874 | end |
---|
875 | end |
---|
876 | PRECHARGE : begin |
---|
877 | if (addr[AP]) begin |
---|
878 | // tRPA timing applies when the PRECHARGE (ALL) command is issued, regardless of |
---|
879 | // the number of banks already open or closed. |
---|
880 | for (i=0; i<`BANKS; i=i+1) begin |
---|
881 | for (j=0; j<NOP; j=j+1) begin |
---|
882 | chk_err(1'b0, i, j, cmd); |
---|
883 | chk_err(1'b1, i, j, cmd); |
---|
884 | end |
---|
885 | chk_err(1'b0, i, PWR_DOWN, cmd); |
---|
886 | chk_err(1'b0, i, SELF_REF, cmd); |
---|
887 | end |
---|
888 | if (|auto_precharge_bank) begin |
---|
889 | $display ("%m: at time %t ERROR: %s All Failure. Auto Precharge is scheduled.", $time, cmd_string[cmd]); |
---|
890 | if (STOP_ON_ERROR) $stop(0); |
---|
891 | end else begin |
---|
892 | if (DEBUG) $display ("%m: at time %t INFO: %s All", $time, cmd_string[cmd]); |
---|
893 | active_bank = 0; |
---|
894 | tm_precharge_all <= $time; |
---|
895 | end |
---|
896 | end else begin |
---|
897 | // A PRECHARGE command is allowed if there is no open row in that bank (idle state) |
---|
898 | // or if the previously open row is already in the process of precharging. |
---|
899 | // However, the precharge period will be determined by the last PRECHARGE command issued to the bank. |
---|
900 | if (auto_precharge_bank[bank]) begin |
---|
901 | $display ("%m: at time %t ERROR: %s Failure. Auto Precharge is scheduled to bank %d.", $time, cmd_string[cmd], bank); |
---|
902 | if (STOP_ON_ERROR) $stop(0); |
---|
903 | end else begin |
---|
904 | if (DEBUG) $display ("%m: at time %t INFO: %s bank %d", $time, cmd_string[cmd], bank); |
---|
905 | active_bank[bank] = 1'b0; |
---|
906 | tm_bank_precharge[bank] <= $time; |
---|
907 | tm_precharge <= $time; |
---|
908 | end |
---|
909 | end |
---|
910 | end |
---|
911 | ACTIVATE : begin |
---|
912 | if (`BANKS == 8) begin |
---|
913 | tfaw_cntr = 0; |
---|
914 | for (i=0; i<`BANKS; i=i+1) begin |
---|
915 | if ($time - tm_bank_activate[i] < TFAW) begin |
---|
916 | tfaw_cntr = tfaw_cntr + 1; |
---|
917 | end |
---|
918 | end |
---|
919 | if (tfaw_cntr > 3) begin |
---|
920 | $display ("%m: at time %t ERROR: tFAW violation during %s to bank %d", $time, cmd_string[cmd], bank); |
---|
921 | end |
---|
922 | end |
---|
923 | |
---|
924 | if (!init_done) begin |
---|
925 | $display ("%m: at time %t ERROR: %s Failure. Initialization sequence is not complete.", $time, cmd_string[cmd]); |
---|
926 | if (STOP_ON_ERROR) $stop(0); |
---|
927 | end else if (active_bank[bank]) begin |
---|
928 | $display ("%m: at time %t ERROR: %s Failure. Bank %d must be Precharged.", $time, cmd_string[cmd], bank); |
---|
929 | if (STOP_ON_ERROR) $stop(0); |
---|
930 | end else begin |
---|
931 | if (addr >= 1<<ROW_BITS) begin |
---|
932 | $display ("%m: at time %t WARNING: row = %h does not exist. Maximum row = %h", $time, addr, (1<<ROW_BITS)-1); |
---|
933 | end |
---|
934 | if (DEBUG) $display ("%m: at time %t INFO: %s bank %d row %h", $time, cmd_string[cmd], bank, addr); |
---|
935 | active_bank[bank] = 1'b1; |
---|
936 | active_row[bank] = addr; |
---|
937 | tm_bank_activate[bank] <= $time; |
---|
938 | tm_activate <= $time; |
---|
939 | end |
---|
940 | |
---|
941 | end |
---|
942 | WRITE : begin |
---|
943 | if (!init_done) begin |
---|
944 | $display ("%m: at time %t ERROR: %s Failure. Initialization sequence is not complete.", $time, cmd_string[cmd]); |
---|
945 | if (STOP_ON_ERROR) $stop(0); |
---|
946 | end else if (!active_bank[bank]) begin |
---|
947 | $display ("%m: at time %t ERROR: %s Failure. Bank %d must be Activated.", $time, cmd_string[cmd], bank); |
---|
948 | if (STOP_ON_ERROR) $stop(0); |
---|
949 | end else if (auto_precharge_bank[bank]) begin |
---|
950 | $display ("%m: at time %t ERROR: %s Failure. Auto Precharge is scheduled to bank %d.", $time, cmd_string[cmd], bank); |
---|
951 | if (STOP_ON_ERROR) $stop(0); |
---|
952 | end else if ((ck_cntr - ck_write < burst_length/2) && (ck_cntr - ck_write)%2) begin |
---|
953 | $display ("%m: at time %t ERROR: %s Failure. Illegal burst interruption.", $time, cmd_string[cmd]); |
---|
954 | if (STOP_ON_ERROR) $stop(0); |
---|
955 | end else begin |
---|
956 | if (addr[AP]) begin |
---|
957 | auto_precharge_bank[bank] = 1'b1; |
---|
958 | write_precharge_bank[bank] = 1'b1; |
---|
959 | end |
---|
960 | col = ((addr>>1) & -1*(1<<AP)) | (addr & {AP{1'b1}}); |
---|
961 | if (col >= 1<<COL_BITS) begin |
---|
962 | $display ("%m: at time %t WARNING: col = %h does not exist. Maximum col = %h", $time, col, (1<<COL_BITS)-1); |
---|
963 | end |
---|
964 | if (DEBUG) $display ("%m: at time %t INFO: %s bank %d col %h, auto precharge %d", $time, cmd_string[cmd], bank, col, addr[AP]); |
---|
965 | wr_pipeline[2*write_latency + 1] = 1; |
---|
966 | ba_pipeline[2*write_latency + 1] = bank; |
---|
967 | row_pipeline[2*write_latency + 1] = active_row[bank]; |
---|
968 | col_pipeline[2*write_latency + 1] = col; |
---|
969 | ck_bank_write[bank] <= ck_cntr; |
---|
970 | ck_write <= ck_cntr; |
---|
971 | end |
---|
972 | end |
---|
973 | READ : begin |
---|
974 | if (!dll_locked) |
---|
975 | $display ("%m: at time %t WARNING: %s prior to DLL locked. Failing to wait for synchronization to occur may result in a violation of the tAC or tDQSCK parameters.", $time, cmd_string[cmd]); |
---|
976 | if (!init_done) begin |
---|
977 | $display ("%m: at time %t ERROR: %s Failure. Initialization sequence is not complete.", $time, cmd_string[cmd]); |
---|
978 | if (STOP_ON_ERROR) $stop(0); |
---|
979 | end else if (!active_bank[bank]) begin |
---|
980 | $display ("%m: at time %t ERROR: %s Failure. Bank %d must be Activated.", $time, cmd_string[cmd], bank); |
---|
981 | if (STOP_ON_ERROR) $stop(0); |
---|
982 | end else if (auto_precharge_bank[bank]) begin |
---|
983 | $display ("%m: at time %t ERROR: %s Failure. Auto Precharge is scheduled to bank %d.", $time, cmd_string[cmd], bank); |
---|
984 | if (STOP_ON_ERROR) $stop(0); |
---|
985 | end else if ((ck_cntr - ck_read < burst_length/2) && (ck_cntr - ck_read)%2) begin |
---|
986 | $display ("%m: at time %t ERROR: %s Failure. Illegal burst interruption.", $time, cmd_string[cmd]); |
---|
987 | if (STOP_ON_ERROR) $stop(0); |
---|
988 | end else begin |
---|
989 | if (addr[AP]) begin |
---|
990 | auto_precharge_bank[bank] = 1'b1; |
---|
991 | read_precharge_bank[bank] = 1'b1; |
---|
992 | end |
---|
993 | col = ((addr>>1) & -1*(1<<AP)) | (addr & {AP{1'b1}}); |
---|
994 | if (col >= 1<<COL_BITS) begin |
---|
995 | $display ("%m: at time %t WARNING: col = %h does not exist. Maximum col = %h", $time, col, (1<<COL_BITS)-1); |
---|
996 | end |
---|
997 | if (DEBUG) $display ("%m: at time %t INFO: %s bank %d col %h, auto precharge %d", $time, cmd_string[cmd], bank, col, addr[AP]); |
---|
998 | rd_pipeline[2*read_latency - 1] = 1; |
---|
999 | ba_pipeline[2*read_latency - 1] = bank; |
---|
1000 | row_pipeline[2*read_latency - 1] = active_row[bank]; |
---|
1001 | col_pipeline[2*read_latency - 1] = col; |
---|
1002 | ck_bank_read[bank] <= ck_cntr; |
---|
1003 | ck_read <= ck_cntr; |
---|
1004 | end |
---|
1005 | end |
---|
1006 | NOP: begin |
---|
1007 | if (in_power_down) begin |
---|
1008 | if (DEBUG) $display ("%m: at time %t INFO: Power Down Exit", $time); |
---|
1009 | in_power_down = 0; |
---|
1010 | if (|active_bank & low_power) begin // slow exit active power down |
---|
1011 | ck_slow_exit_pd <= ck_cntr; |
---|
1012 | end |
---|
1013 | ck_power_down <= ck_cntr; |
---|
1014 | end |
---|
1015 | if (in_self_refresh) begin |
---|
1016 | if ($time - tm_cke < TISXR) |
---|
1017 | $display ("%m: at time %t ERROR: tISXR violation during Self Refresh Exit", $time); |
---|
1018 | if (DEBUG) $display ("%m: at time %t INFO: Self Refresh Exit", $time); |
---|
1019 | in_self_refresh = 0; |
---|
1020 | ck_dll_reset <= ck_cntr; |
---|
1021 | ck_self_refresh <= ck_cntr; |
---|
1022 | tm_self_refresh <= $time; |
---|
1023 | tm_refresh <= $time; |
---|
1024 | end |
---|
1025 | end |
---|
1026 | endcase |
---|
1027 | if ((prev_cke !== 1) && (cmd !== NOP)) begin |
---|
1028 | $display ("%m: at time %t ERROR: NOP or Deselect is required when CKE goes active.", $time); |
---|
1029 | end |
---|
1030 | if (!init_done) begin |
---|
1031 | case (init_step) |
---|
1032 | 0 : begin |
---|
1033 | if ($time < 200000000) |
---|
1034 | $display ("%m: at time %t WARNING: 200 us is required before CKE goes active.", $time); |
---|
1035 | // if (cmd_chk + 200000000 > $time) |
---|
1036 | // $display("%m: at time %t WARNING: NOP or DESELECT is required for 200 us before CKE is brought high", $time); |
---|
1037 | init_step = init_step + 1; |
---|
1038 | end |
---|
1039 | 1 : if (dll_en) init_step = init_step + 1; |
---|
1040 | 2 : begin |
---|
1041 | if (&init_mode_reg && dll_reset) begin |
---|
1042 | active_bank = {`BANKS{1'b1}}; // require Precharge All or bank Precharges |
---|
1043 | ref_cntr = 0; // require refresh |
---|
1044 | init_step = init_step + 1; |
---|
1045 | end |
---|
1046 | end |
---|
1047 | 3 : if (ref_cntr == 2) begin |
---|
1048 | init_step = init_step + 1; |
---|
1049 | end |
---|
1050 | 4 : if (!dll_reset) init_step = init_step + 1; |
---|
1051 | 5 : if (ocd == 3'b111) init_step = init_step + 1; |
---|
1052 | 6 : begin |
---|
1053 | if (ocd == 3'b000) begin |
---|
1054 | if (DEBUG) $display ("%m: at time %t INFO: Initialization Sequence is complete", $time); |
---|
1055 | init_done = 1; |
---|
1056 | end |
---|
1057 | end |
---|
1058 | endcase |
---|
1059 | end |
---|
1060 | end else if (prev_cke) begin |
---|
1061 | if ((!init_done) && (init_step > 1)) begin |
---|
1062 | $display ("%m: at time %t ERROR: CKE must remain active until the initialization sequence is complete.", $time); |
---|
1063 | if (STOP_ON_ERROR) $stop(0); |
---|
1064 | end |
---|
1065 | case (cmd) |
---|
1066 | REFRESH : begin |
---|
1067 | for (j=0; j<NOP; j=j+1) begin |
---|
1068 | chk_err(1'b0, bank, j, SELF_REF); |
---|
1069 | end |
---|
1070 | chk_err(1'b0, bank, PWR_DOWN, SELF_REF); |
---|
1071 | chk_err(1'b0, bank, SELF_REF, SELF_REF); |
---|
1072 | if (|active_bank) begin |
---|
1073 | $display ("%m: at time %t ERROR: Self Refresh Failure. All banks must be Precharged.", $time); |
---|
1074 | if (STOP_ON_ERROR) $stop(0); |
---|
1075 | init_done = 0; |
---|
1076 | end else if (odt_en && odt_state) begin |
---|
1077 | $display ("%m: at time %t ERROR: ODT must be off prior to entering Self Refresh", $time); |
---|
1078 | if (STOP_ON_ERROR) $stop(0); |
---|
1079 | init_done = 0; |
---|
1080 | end else if (!init_done) begin |
---|
1081 | $display ("%m: at time %t ERROR: Self Refresh Failure. Initialization sequence is not complete.", $time); |
---|
1082 | if (STOP_ON_ERROR) $stop(0); |
---|
1083 | end else begin |
---|
1084 | if (DEBUG) $display ("%m: at time %t INFO: Self Refresh Enter", $time); |
---|
1085 | in_self_refresh = 1; |
---|
1086 | dll_locked = 0; |
---|
1087 | end |
---|
1088 | end |
---|
1089 | NOP : begin |
---|
1090 | // entering slow_exit or precharge power down and tANPD has not been satisfied |
---|
1091 | if ((low_power || (active_bank == 0)) && (ck_cntr - ck_odt < TANPD)) |
---|
1092 | $display ("%m: at time %t WARNING: tANPD violation during %s. Synchronous or asynchronous change in termination resistance is possible.", $time, cmd_string[PWR_DOWN]); |
---|
1093 | for (j=0; j<NOP; j=j+1) begin |
---|
1094 | chk_err(1'b0, bank, j, PWR_DOWN); |
---|
1095 | end |
---|
1096 | chk_err(1'b0, bank, PWR_DOWN, PWR_DOWN); |
---|
1097 | chk_err(1'b0, bank, SELF_REF, PWR_DOWN); |
---|
1098 | |
---|
1099 | if (!init_done) begin |
---|
1100 | $display ("%m: at time %t ERROR: Power Down Failure. Initialization sequence is not complete.", $time); |
---|
1101 | if (STOP_ON_ERROR) $stop(0); |
---|
1102 | end else begin |
---|
1103 | if (DEBUG) begin |
---|
1104 | if (|active_bank) begin |
---|
1105 | $display ("%m: at time %t INFO: Active Power Down Enter", $time); |
---|
1106 | end else begin |
---|
1107 | $display ("%m: at time %t INFO: Precharge Power Down Enter", $time); |
---|
1108 | end |
---|
1109 | end |
---|
1110 | in_power_down = 1; |
---|
1111 | end |
---|
1112 | end |
---|
1113 | default : begin |
---|
1114 | $display ("%m: at time %t ERROR: NOP, Deselect, or Refresh is required when CKE goes inactive.", $time); |
---|
1115 | init_done = 0; |
---|
1116 | end |
---|
1117 | endcase |
---|
1118 | if (!init_done) begin |
---|
1119 | if (DEBUG) $display ("%m: at time %t WARNING: Reset has occurred. Device must be re-initialized.", $time); |
---|
1120 | reset_task; |
---|
1121 | end |
---|
1122 | end |
---|
1123 | prev_cke = cke; |
---|
1124 | end |
---|
1125 | endtask |
---|
1126 | |
---|
1127 | task data_task; |
---|
1128 | reg [BA_BITS-1:0] bank; |
---|
1129 | reg [ROW_BITS-1:0] row; |
---|
1130 | reg [COL_BITS-1:0] col; |
---|
1131 | integer i; |
---|
1132 | integer j; |
---|
1133 | begin |
---|
1134 | |
---|
1135 | if (diff_ck) begin |
---|
1136 | for (i=0; i<36; i=i+1) begin |
---|
1137 | if (dq_in_valid && dll_locked && ($time - tm_dqs_neg[i] < $rtoi(TDSS*tck_avg))) |
---|
1138 | $display ("%m: at time %t ERROR: tDSS violation on %s bit %d", $time, dqs_string[i/18], i%18); |
---|
1139 | if (check_write_dqs_high[i]) |
---|
1140 | $display ("%m: at time %t ERROR: %s bit %d latching edge required during the preceding clock period.", $time, dqs_string[i/18], i%18); |
---|
1141 | end |
---|
1142 | check_write_dqs_high <= 0; |
---|
1143 | end else begin |
---|
1144 | for (i=0; i<36; i=i+1) begin |
---|
1145 | if (dll_locked && dq_in_valid) begin |
---|
1146 | tm_tdqss = abs_value(1.0*tm_ck_pos - tm_dqss_pos[i]); |
---|
1147 | if ((tm_tdqss < tck_avg/2.0) && (tm_tdqss > TDQSS*tck_avg)) |
---|
1148 | $display ("%m: at time %t ERROR: tDQSS violation on %s bit %d", $time, dqs_string[i/18], i%18); |
---|
1149 | end |
---|
1150 | if (check_write_dqs_low[i]) |
---|
1151 | $display ("%m: at time %t ERROR: %s bit %d latching edge required during the preceding clock period", $time, dqs_string[i/18], i%18); |
---|
1152 | end |
---|
1153 | check_write_preamble <= 0; |
---|
1154 | check_write_postamble <= 0; |
---|
1155 | check_write_dqs_low <= 0; |
---|
1156 | end |
---|
1157 | |
---|
1158 | if (wr_pipeline[0] || rd_pipeline[0]) begin |
---|
1159 | bank = ba_pipeline[0]; |
---|
1160 | row = row_pipeline[0]; |
---|
1161 | col = col_pipeline[0]; |
---|
1162 | burst_cntr = 0; |
---|
1163 | memory_read(bank, row, col, memory_data); |
---|
1164 | end |
---|
1165 | |
---|
1166 | // burst counter |
---|
1167 | if (burst_cntr < burst_length) begin |
---|
1168 | burst_position = col ^ burst_cntr; |
---|
1169 | if (!burst_order) begin |
---|
1170 | burst_position[BO_BITS-1:0] = col + burst_cntr; |
---|
1171 | end |
---|
1172 | burst_cntr = burst_cntr + 1; |
---|
1173 | end |
---|
1174 | |
---|
1175 | // write dqs counter |
---|
1176 | if (wr_pipeline[WDQS_PRE + 1]) begin |
---|
1177 | wdqs_cntr = WDQS_PRE + burst_length + WDQS_PST - 1; |
---|
1178 | end |
---|
1179 | // write dqs |
---|
1180 | if ((wdqs_cntr == burst_length + WDQS_PST) && (wdq_cntr == 0)) begin //write preamble |
---|
1181 | check_write_preamble <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; |
---|
1182 | end |
---|
1183 | if (wdqs_cntr > 1) begin // write data |
---|
1184 | if ((wdqs_cntr - WDQS_PST)%2) begin |
---|
1185 | check_write_dqs_high <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; |
---|
1186 | end else begin |
---|
1187 | check_write_dqs_low <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; |
---|
1188 | end |
---|
1189 | end |
---|
1190 | if (wdqs_cntr == WDQS_PST) begin // write postamble |
---|
1191 | check_write_postamble <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; |
---|
1192 | end |
---|
1193 | if (wdqs_cntr > 0) begin |
---|
1194 | wdqs_cntr = wdqs_cntr - 1; |
---|
1195 | end |
---|
1196 | |
---|
1197 | // write dq |
---|
1198 | if (dq_in_valid) begin // write data |
---|
1199 | bit_mask = 0; |
---|
1200 | if (diff_ck) begin |
---|
1201 | for (i=0; i<DM_BITS; i=i+1) begin |
---|
1202 | bit_mask = bit_mask | ({`DQ_PER_DQS{~dm_in_neg[i]}}<<(burst_position*DQ_BITS + i*`DQ_PER_DQS)); |
---|
1203 | end |
---|
1204 | memory_data = (dq_in_neg<<(burst_position*DQ_BITS) & bit_mask) | (memory_data & ~bit_mask); |
---|
1205 | end else begin |
---|
1206 | for (i=0; i<DM_BITS; i=i+1) begin |
---|
1207 | bit_mask = bit_mask | ({`DQ_PER_DQS{~dm_in_pos[i]}}<<(burst_position*DQ_BITS + i*`DQ_PER_DQS)); |
---|
1208 | end |
---|
1209 | memory_data = (dq_in_pos<<(burst_position*DQ_BITS) & bit_mask) | (memory_data & ~bit_mask); |
---|
1210 | end |
---|
1211 | dq_temp = memory_data>>(burst_position*DQ_BITS); |
---|
1212 | if (DEBUG) $display ("%m: at time %t INFO: WRITE @ DQS= bank = %h row = %h col = %h data = %h",$time, bank, row, (-1*BL_MAX & col) + burst_position, dq_temp); |
---|
1213 | if (burst_cntr%BL_MIN == 0) begin |
---|
1214 | memory_write(bank, row, col, memory_data); |
---|
1215 | end |
---|
1216 | end |
---|
1217 | if (wr_pipeline[1]) begin |
---|
1218 | wdq_cntr = burst_length; |
---|
1219 | end |
---|
1220 | if (wdq_cntr > 0) begin |
---|
1221 | wdq_cntr = wdq_cntr - 1; |
---|
1222 | dq_in_valid = 1'b1; |
---|
1223 | end else begin |
---|
1224 | dq_in_valid = 1'b0; |
---|
1225 | dqs_in_valid <= 1'b0; |
---|
1226 | for (i=0; i<36; i=i+1) begin |
---|
1227 | wdqs_pos_cntr[i] <= 0; |
---|
1228 | end |
---|
1229 | end |
---|
1230 | if (wr_pipeline[0]) begin |
---|
1231 | b2b_write <= 1'b0; |
---|
1232 | end |
---|
1233 | if (wr_pipeline[2]) begin |
---|
1234 | if (dqs_in_valid) begin |
---|
1235 | b2b_write <= 1'b1; |
---|
1236 | end |
---|
1237 | dqs_in_valid <= 1'b1; |
---|
1238 | end |
---|
1239 | // read dqs enable counter |
---|
1240 | if (rd_pipeline[RDQSEN_PRE]) begin |
---|
1241 | rdqsen_cntr = RDQSEN_PRE + burst_length + RDQSEN_PST - 1; |
---|
1242 | end |
---|
1243 | if (rdqsen_cntr > 0) begin |
---|
1244 | rdqsen_cntr = rdqsen_cntr - 1; |
---|
1245 | dqs_out_en = 1'b1; |
---|
1246 | end else begin |
---|
1247 | dqs_out_en = 1'b0; |
---|
1248 | end |
---|
1249 | |
---|
1250 | // read dqs counter |
---|
1251 | if (rd_pipeline[RDQS_PRE]) begin |
---|
1252 | rdqs_cntr = RDQS_PRE + burst_length + RDQS_PST - 1; |
---|
1253 | end |
---|
1254 | // read dqs |
---|
1255 | if ((rdqs_cntr >= burst_length + RDQS_PST) && (rdq_cntr == 0)) begin //read preamble |
---|
1256 | dqs_out = 1'b0; |
---|
1257 | end else if (rdqs_cntr > RDQS_PST) begin // read data |
---|
1258 | dqs_out = rdqs_cntr - RDQS_PST; |
---|
1259 | end else if (rdqs_cntr > 0) begin // read postamble |
---|
1260 | dqs_out = 1'b0; |
---|
1261 | end else begin |
---|
1262 | dqs_out = 1'b1; |
---|
1263 | end |
---|
1264 | if (rdqs_cntr > 0) begin |
---|
1265 | rdqs_cntr = rdqs_cntr - 1; |
---|
1266 | end |
---|
1267 | |
---|
1268 | // read dq enable counter |
---|
1269 | if (rd_pipeline[RDQEN_PRE]) begin |
---|
1270 | rdqen_cntr = RDQEN_PRE + burst_length + RDQEN_PST; |
---|
1271 | end |
---|
1272 | if (rdqen_cntr > 0) begin |
---|
1273 | rdqen_cntr = rdqen_cntr - 1; |
---|
1274 | dq_out_en = 1'b1; |
---|
1275 | end else begin |
---|
1276 | dq_out_en = 1'b0; |
---|
1277 | end |
---|
1278 | // read dq |
---|
1279 | if (rd_pipeline[0]) begin |
---|
1280 | rdq_cntr = burst_length; |
---|
1281 | end |
---|
1282 | if (rdq_cntr > 0) begin // read data |
---|
1283 | dq_temp = memory_data>>(burst_position*DQ_BITS); |
---|
1284 | dq_out = dq_temp; |
---|
1285 | if (DEBUG) $display ("%m: at time %t INFO: READ @ DQS= bank = %h row = %h col = %h data = %h",$time, bank, row, (-1*BL_MAX & col) + burst_position, dq_temp); |
---|
1286 | rdq_cntr = rdq_cntr - 1; |
---|
1287 | end else begin |
---|
1288 | dq_out = {DQ_BITS{1'b1}}; |
---|
1289 | end |
---|
1290 | |
---|
1291 | // delay signals prior to output |
---|
1292 | if (RANDOM_OUT_DELAY && (dqs_out_en || |dqs_out_en_dly || dq_out_en || |dq_out_en_dly)) begin |
---|
1293 | for (i=0; i<DQS_BITS; i=i+1) begin |
---|
1294 | // DQSCK requirements |
---|
1295 | // 1.) less than tDQSCK |
---|
1296 | // 2.) greater than -tDQSCK |
---|
1297 | // 3.) cannot change more than tQHS + tDQSQ from previous DQS edge |
---|
1298 | dqsck_max = TDQSCK; |
---|
1299 | if (dqsck_max > dqsck[i] + TQHS + TDQSQ) begin |
---|
1300 | dqsck_max = dqsck[i] + TQHS + TDQSQ; |
---|
1301 | end |
---|
1302 | dqsck_min = -1*TDQSCK; |
---|
1303 | if (dqsck_min < dqsck[i] - TQHS - TDQSQ) begin |
---|
1304 | dqsck_min = dqsck[i] - TQHS - TDQSQ; |
---|
1305 | end |
---|
1306 | |
---|
1307 | // DQSQ requirements |
---|
1308 | // 1.) less than tAC - DQSCK |
---|
1309 | // 2.) less than tDQSQ |
---|
1310 | // 3.) greater than -tAC |
---|
1311 | // 4.) greater than tQH from previous DQS edge |
---|
1312 | dqsq_min = -1*TAC; |
---|
1313 | if (dqsq_min < dqsck[i] - TQHS) begin |
---|
1314 | dqsq_min = dqsck[i] - TQHS; |
---|
1315 | end |
---|
1316 | if (dqsck_min == dqsck_max) begin |
---|
1317 | dqsck[i] = dqsck_min; |
---|
1318 | end else begin |
---|
1319 | dqsck[i] = $dist_uniform(seed, dqsck_min, dqsck_max); |
---|
1320 | end |
---|
1321 | dqsq_max = TAC; |
---|
1322 | if (dqsq_max > TDQSQ + dqsck[i]) begin |
---|
1323 | dqsq_max = TDQSQ + dqsck[i]; |
---|
1324 | end |
---|
1325 | |
---|
1326 | dqs_out_en_dly[i] <= #(tck_avg/2.0 + ($random % TAC)) dqs_out_en; |
---|
1327 | dqs_out_dly[i] <= #(tck_avg/2.0 + dqsck[i]) dqs_out; |
---|
1328 | for (j=0; j<`DQ_PER_DQS; j=j+1) begin |
---|
1329 | if (dq_out_en) begin // tLZ2 |
---|
1330 | dq_out_en_dly[i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + $dist_uniform(seed, -2*TAC, dqsq_max)) dq_out_en; |
---|
1331 | end else begin // tHZ |
---|
1332 | dq_out_en_dly[i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + ($random % TAC)) dq_out_en; |
---|
1333 | end |
---|
1334 | if (dqsq_min == dqsq_max) begin |
---|
1335 | dq_out_dly [i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + dqsq_min) dq_out[i*`DQ_PER_DQS + j]; |
---|
1336 | end else begin |
---|
1337 | dq_out_dly [i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + $dist_uniform(seed, dqsq_min, dqsq_max)) dq_out[i*`DQ_PER_DQS + j]; |
---|
1338 | end |
---|
1339 | end |
---|
1340 | end |
---|
1341 | end else begin |
---|
1342 | out_delay = tck_avg/2.0; |
---|
1343 | dqs_out_en_dly <= #(out_delay) {DQS_BITS{dqs_out_en}}; |
---|
1344 | dqs_out_dly <= #(out_delay) {DQS_BITS{dqs_out }}; |
---|
1345 | dq_out_en_dly <= #(out_delay) {DQ_BITS {dq_out_en }}; |
---|
1346 | dq_out_dly <= #(out_delay) {DQ_BITS {dq_out }}; |
---|
1347 | end |
---|
1348 | end |
---|
1349 | endtask |
---|
1350 | |
---|
1351 | always @(diff_ck) begin : main |
---|
1352 | integer i; |
---|
1353 | |
---|
1354 | if (!in_self_refresh && (diff_ck !== 1'b0) && (diff_ck !== 1'b1)) |
---|
1355 | $display ("%m: at time %t ERROR: CK and CK_N are not allowed to go to an unknown state.", $time); |
---|
1356 | data_task; |
---|
1357 | if (diff_ck) begin |
---|
1358 | // check setup of command signals |
---|
1359 | if ($time > TIS) begin |
---|
1360 | if ($time - tm_cke < TIS) |
---|
1361 | $display ("%m: at time %t ERROR: tIS violation on CKE by %t", $time, tm_cke + TIS - $time); |
---|
1362 | if (cke_in) begin |
---|
1363 | for (i=0; i<22; i=i+1) begin |
---|
1364 | if ($time - tm_cmd_addr[i] < TIS) |
---|
1365 | $display ("%m: at time %t ERROR: tIS violation on %s by %t", $time, cmd_addr_string[i], tm_cmd_addr[i] + TIS - $time); |
---|
1366 | end |
---|
1367 | end |
---|
1368 | end |
---|
1369 | |
---|
1370 | // update current state |
---|
1371 | if (!dll_locked && !in_self_refresh && (ck_cntr - ck_dll_reset == TDLLK)) begin |
---|
1372 | // check CL value against the clock frequency |
---|
1373 | if (cas_latency*tck_avg < CL_TIME) |
---|
1374 | $display ("%m: at time %t ERROR: CAS Latency = %d is illegal @tCK(avg) = %f", $time, cas_latency, tck_avg); |
---|
1375 | // check WR value against the clock frequency |
---|
1376 | if (write_recovery*tck_avg < TWR) |
---|
1377 | $display ("%m: at time %t ERROR: Write Recovery = %d is illegal @tCK(avg) = %f", $time, write_recovery, tck_avg); |
---|
1378 | dll_locked = 1; |
---|
1379 | end |
---|
1380 | if (|auto_precharge_bank) begin |
---|
1381 | for (i=0; i<`BANKS; i=i+1) begin |
---|
1382 | // Write with Auto Precharge Calculation |
---|
1383 | // 1. Meet minimum tRAS requirement |
---|
1384 | // 2. Write Latency PLUS BL/2 cycles PLUS WR after Write command |
---|
1385 | if (write_precharge_bank[i] |
---|
1386 | && ($time - tm_bank_activate[i] >= TRAS_MIN) |
---|
1387 | && (ck_cntr - ck_bank_write[i] >= write_latency + burst_length/2 + write_recovery)) begin |
---|
1388 | |
---|
1389 | if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", $time, i); |
---|
1390 | write_precharge_bank[i] = 0; |
---|
1391 | active_bank[i] = 0; |
---|
1392 | auto_precharge_bank[i] = 0; |
---|
1393 | ck_write_ap = ck_cntr; |
---|
1394 | tm_bank_precharge[i] = $time; |
---|
1395 | tm_precharge = $time; |
---|
1396 | end |
---|
1397 | // Read with Auto Precharge Calculation |
---|
1398 | // 1. Meet minimum tRAS requirement |
---|
1399 | // 2. Additive Latency plus BL/2 cycles after Read command |
---|
1400 | // 3. tRTP after the last 4-bit prefetch |
---|
1401 | if (read_precharge_bank[i] |
---|
1402 | && ($time - tm_bank_activate[i] >= TRAS_MIN) |
---|
1403 | && (ck_cntr - ck_bank_read[i] >= additive_latency + burst_length/2)) begin |
---|
1404 | |
---|
1405 | read_precharge_bank[i] = 0; |
---|
1406 | // In case the internal precharge is pushed out by tRTP, tRP starts at the point where |
---|
1407 | // the internal precharge happens (not at the next rising clock edge after this event). |
---|
1408 | if ($time - tm_bank_read_end[i] < TRTP) begin |
---|
1409 | if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", tm_bank_read_end[i] + TRTP, i); |
---|
1410 | active_bank[i] <= #(tm_bank_read_end[i] + TRTP - $time) 0; |
---|
1411 | auto_precharge_bank[i] <= #(tm_bank_read_end[i] + TRTP - $time) 0; |
---|
1412 | tm_bank_precharge[i] <= #(tm_bank_read_end[i] + TRTP - $time) tm_bank_read_end[i] + TRTP; |
---|
1413 | tm_precharge <= #(tm_bank_read_end[i] + TRTP - $time) tm_bank_read_end[i] + TRTP; |
---|
1414 | end else begin |
---|
1415 | if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", $time, i); |
---|
1416 | active_bank[i] = 0; |
---|
1417 | auto_precharge_bank[i] = 0; |
---|
1418 | tm_bank_precharge[i] = $time; |
---|
1419 | tm_precharge = $time; |
---|
1420 | end |
---|
1421 | end |
---|
1422 | end |
---|
1423 | end |
---|
1424 | |
---|
1425 | // respond to incoming command |
---|
1426 | if (cke_in ^ prev_cke) begin |
---|
1427 | ck_cke <= ck_cntr; |
---|
1428 | end |
---|
1429 | |
---|
1430 | cmd_task(cke_in, cmd_n_in, ba_in, addr_in); |
---|
1431 | if ((cmd_n_in == WRITE) || (cmd_n_in == READ)) begin |
---|
1432 | al_pipeline[2*additive_latency] = 1'b1; |
---|
1433 | end |
---|
1434 | if (al_pipeline[0]) begin |
---|
1435 | // check tRCD after additive latency |
---|
1436 | if ($time - tm_bank_activate[ba_pipeline[2*cas_latency - 1]] < TRCD) begin |
---|
1437 | if (rd_pipeline[2*cas_latency - 1]) begin |
---|
1438 | $display ("%m: at time %t ERROR: tRCD violation during %s", $time, cmd_string[READ]); |
---|
1439 | end else begin |
---|
1440 | $display ("%m: at time %t ERROR: tRCD violation during %s", $time, cmd_string[WRITE]); |
---|
1441 | end |
---|
1442 | end |
---|
1443 | // check tWTR after additive latency |
---|
1444 | if (rd_pipeline[2*cas_latency - 1]) begin |
---|
1445 | if ($time - tm_write_end < TWTR) |
---|
1446 | $display ("%m: at time %t ERROR: tWTR violation during %s", $time, cmd_string[READ]); |
---|
1447 | end |
---|
1448 | end |
---|
1449 | if (rd_pipeline[2*(cas_latency - burst_length/2 + 2) - 1]) begin |
---|
1450 | tm_bank_read_end[ba_pipeline[2*(cas_latency - burst_length/2 + 2) - 1]] <= $time; |
---|
1451 | end |
---|
1452 | for (i=0; i<`BANKS; i=i+1) begin |
---|
1453 | if ((ck_cntr - ck_bank_write[i] > write_latency) && (ck_cntr - ck_bank_write[i] <= write_latency + burst_length/2)) begin |
---|
1454 | tm_bank_write_end[i] <= $time; |
---|
1455 | tm_write_end <= $time; |
---|
1456 | end |
---|
1457 | end |
---|
1458 | |
---|
1459 | // clk pin is disabled during self refresh |
---|
1460 | if (!in_self_refresh) begin |
---|
1461 | tjit_cc_time = $time - tm_ck_pos - tck_i; |
---|
1462 | tck_i = $time - tm_ck_pos; |
---|
1463 | tck_avg = tck_avg - tck_sample[ck_cntr%TDLLK]/$itor(TDLLK); |
---|
1464 | tck_avg = tck_avg + tck_i/$itor(TDLLK); |
---|
1465 | tck_sample[ck_cntr%TDLLK] = tck_i; |
---|
1466 | tjit_per_rtime = tck_i - tck_avg; |
---|
1467 | |
---|
1468 | if (dll_locked) begin |
---|
1469 | // check accumulated error |
---|
1470 | terr_nper_rtime = 0; |
---|
1471 | for (i=0; i<50; i=i+1) begin |
---|
1472 | terr_nper_rtime = terr_nper_rtime + tck_sample[i] - tck_avg; |
---|
1473 | terr_nper_rtime = abs_value(terr_nper_rtime); |
---|
1474 | case (i) |
---|
1475 | 0 :; |
---|
1476 | 1 : if (terr_nper_rtime - TERR_2PER >= 1.0) $display ("%m: at time %t ERROR: tERR(2per) violation by %f ps.", $time, terr_nper_rtime - TERR_2PER); |
---|
1477 | 2 : if (terr_nper_rtime - TERR_3PER >= 1.0) $display ("%m: at time %t ERROR: tERR(3per) violation by %f ps.", $time, terr_nper_rtime - TERR_3PER); |
---|
1478 | 3 : if (terr_nper_rtime - TERR_4PER >= 1.0) $display ("%m: at time %t ERROR: tERR(4per) violation by %f ps.", $time, terr_nper_rtime - TERR_4PER); |
---|
1479 | 4 : if (terr_nper_rtime - TERR_5PER >= 1.0) $display ("%m: at time %t ERROR: tERR(5per) violation by %f ps.", $time, terr_nper_rtime - TERR_5PER); |
---|
1480 | 5,6,7,8,9 : if (terr_nper_rtime - TERR_N1PER >= 1.0) $display ("%m: at time %t ERROR: tERR(n1per) violation by %f ps.", $time, terr_nper_rtime - TERR_N1PER); |
---|
1481 | default : if (terr_nper_rtime - TERR_N2PER >= 1.0) $display ("%m: at time %t ERROR: tERR(n2per) violation by %f ps.", $time, terr_nper_rtime - TERR_N2PER); |
---|
1482 | endcase |
---|
1483 | end |
---|
1484 | |
---|
1485 | // check tCK min/max/jitter |
---|
1486 | if (abs_value(tjit_per_rtime) - TJIT_PER >= 1.0) |
---|
1487 | $display ("%m: at time %t ERROR: tJIT(per) violation by %f ps.", $time, abs_value(tjit_per_rtime) - TJIT_PER); |
---|
1488 | if (abs_value(tjit_cc_time) - TJIT_CC >= 1.0) |
---|
1489 | $display ("%m: at time %t ERROR: tJIT(cc) violation by %f ps.", $time, abs_value(tjit_cc_time) - TJIT_CC); |
---|
1490 | if (TCK_MIN - tck_avg >= 1.0) |
---|
1491 | $display ("%m: at time %t ERROR: tCK(avg) minimum violation by %f ps.", $time, TCK_MIN - tck_avg); |
---|
1492 | if (tck_avg - TCK_MAX >= 1.0) |
---|
1493 | $display ("%m: at time %t ERROR: tCK(avg) maximum violation by %f ps.", $time, tck_avg - TCK_MAX); |
---|
1494 | if (tm_ck_pos + TCK_MIN - TJIT_PER > $time) |
---|
1495 | $display ("%m: at time %t ERROR: tCK(abs) minimum violation by %t", $time, tm_ck_pos + TCK_MIN - TJIT_PER - $time); |
---|
1496 | if (tm_ck_pos + TCK_MAX + TJIT_PER < $time) |
---|
1497 | $display ("%m: at time %t ERROR: tCK(abs) maximum violation by %t", $time, $time - tm_ck_pos - TCK_MAX - TJIT_PER); |
---|
1498 | |
---|
1499 | // check tCL |
---|
1500 | if (tm_ck_neg + TCL_MIN*tck_avg - TJIT_DUTY > $time) |
---|
1501 | $display ("%m: at time %t ERROR: tCL(abs) minimum violation on CLK by %t", $time, tm_ck_neg + TCL_MIN*tck_avg - TJIT_DUTY - $time); |
---|
1502 | if (tm_ck_neg + TCL_MAX*tck_avg + TJIT_DUTY < $time) |
---|
1503 | $display ("%m: at time %t ERROR: tCL(abs) maximum violation on CLK by %t", $time, $time - tm_ck_neg - TCL_MAX*tck_avg - TJIT_DUTY); |
---|
1504 | if (tcl_avg < TCL_MIN*tck_avg) |
---|
1505 | $display ("%m: at time %t ERROR: tCL(avg) minimum violation on CLK by %t", $time, TCL_MIN*tck_avg - tcl_avg); |
---|
1506 | if (tcl_avg > TCL_MAX*tck_avg) |
---|
1507 | $display ("%m: at time %t ERROR: tCL(avg) maximum violation on CLK by %t", $time, tcl_avg - TCL_MAX*tck_avg); |
---|
1508 | end |
---|
1509 | |
---|
1510 | // calculate the tch avg jitter |
---|
1511 | tch_avg = tch_avg - tch_sample[ck_cntr%TDLLK]/$itor(TDLLK); |
---|
1512 | tch_avg = tch_avg + tch_i/$itor(TDLLK); |
---|
1513 | tch_sample[ck_cntr%TDLLK] = tch_i; |
---|
1514 | |
---|
1515 | // update timers/counters |
---|
1516 | tcl_i <= $time - tm_ck_neg; |
---|
1517 | end |
---|
1518 | |
---|
1519 | prev_odt <= odt_in; |
---|
1520 | // update timers/counters |
---|
1521 | ck_cntr <= ck_cntr + 1; |
---|
1522 | tm_ck_pos <= $time; |
---|
1523 | end else begin |
---|
1524 | // clk pin is disabled during self refresh |
---|
1525 | if (!in_self_refresh) begin |
---|
1526 | if (dll_locked) begin |
---|
1527 | if (tm_ck_pos + TCH_MIN*tck_avg - TJIT_DUTY > $time) |
---|
1528 | $display ("%m: at time %t ERROR: tCH(abs) minimum violation on CLK by %t", $time, tm_ck_pos + TCH_MIN*tck_avg - TJIT_DUTY + $time); |
---|
1529 | if (tm_ck_pos + TCH_MAX*tck_avg + TJIT_DUTY < $time) |
---|
1530 | $display ("%m: at time %t ERROR: tCH(abs) maximum violation on CLK by %t", $time, $time - tm_ck_pos - TCH_MAX*tck_avg - TJIT_DUTY); |
---|
1531 | if (tch_avg < TCH_MIN*tck_avg) |
---|
1532 | $display ("%m: at time %t ERROR: tCH(avg) minimum violation on CLK by %t", $time, TCH_MIN*tck_avg - tch_avg); |
---|
1533 | if (tch_avg > TCH_MAX*tck_avg) |
---|
1534 | $display ("%m: at time %t ERROR: tCH(avg) maximum violation on CLK by %t", $time, tch_avg - TCH_MAX*tck_avg); |
---|
1535 | end |
---|
1536 | |
---|
1537 | // calculate the tcl avg jitter |
---|
1538 | tcl_avg = tcl_avg - tcl_sample[ck_cntr%TDLLK]/$itor(TDLLK); |
---|
1539 | tcl_avg = tcl_avg + tcl_i/$itor(TDLLK); |
---|
1540 | tcl_sample[ck_cntr%TDLLK] = tcl_i; |
---|
1541 | |
---|
1542 | // update timers/counters |
---|
1543 | tch_i <= $time - tm_ck_pos; |
---|
1544 | end |
---|
1545 | tm_ck_neg <= $time; |
---|
1546 | end |
---|
1547 | |
---|
1548 | // on die termination |
---|
1549 | if (odt_en) begin |
---|
1550 | // clk pin is disabled during self refresh |
---|
1551 | if (!in_self_refresh && diff_ck) begin |
---|
1552 | if ($time - tm_odt < TIS) begin |
---|
1553 | $display ("%m: at time %t ERROR: tIS violation on ODT by %t", $time, tm_odt + TIS - $time); |
---|
1554 | end |
---|
1555 | if (prev_odt ^ odt_in) begin |
---|
1556 | if (!dll_locked) |
---|
1557 | $display ("%m: at time %t WARNING: tDLLK violation during ODT transition.", $time); |
---|
1558 | if (odt_in && ($time - tm_odt_en < TMOD)) |
---|
1559 | $display ("%m: at time %t ERROR: tMOD violation during ODT transition", $time); |
---|
1560 | if ($time - tm_self_refresh < TXSNR) |
---|
1561 | $display ("%m: at time %t ERROR: tXSNR violation during ODT transition", $time); |
---|
1562 | if (in_self_refresh) |
---|
1563 | $display ("%m: at time %t ERROR: Illegal ODT transition during Self Refresh.", $time); |
---|
1564 | |
---|
1565 | // async ODT mode applies: |
---|
1566 | // 1.) during active power down with slow exit |
---|
1567 | // 2.) during precharge power down |
---|
1568 | // 3.) if tANPD has not been satisfied |
---|
1569 | // 4.) until tAXPD has been satisfied |
---|
1570 | if ((in_power_down && (low_power || (active_bank == 0))) || (ck_cntr - ck_slow_exit_pd < TAXPD)) begin |
---|
1571 | if (ck_cntr - ck_slow_exit_pd < TAXPD) |
---|
1572 | $display ("%m: at time %t WARNING: tAXPD violation during ODT transition. Synchronous or asynchronous change in termination resistance is possible.", $time); |
---|
1573 | if (odt_in) begin |
---|
1574 | if (DEBUG) $display ("%m: at time %t INFO: Async On Die Termination = %d", $time + TAONPD, 1'b1); |
---|
1575 | odt_state <= #(TAONPD) 1'b1; |
---|
1576 | end else begin |
---|
1577 | if (DEBUG) $display ("%m: at time %t INFO: Async On Die Termination = %d", $time + TAOFPD, 1'b0); |
---|
1578 | odt_state <= #(TAOFPD) 1'b0; |
---|
1579 | end |
---|
1580 | // sync ODT mode applies: |
---|
1581 | // 1.) during normal operation |
---|
1582 | // 2.) during active power down with fast exit |
---|
1583 | end else begin |
---|
1584 | if (odt_in) begin |
---|
1585 | i = TAOND*2; |
---|
1586 | odt_pipeline[i] = 1'b1; |
---|
1587 | end else begin |
---|
1588 | i = TAOFD*2; |
---|
1589 | odt_pipeline[i] = 1'b1; |
---|
1590 | end |
---|
1591 | end |
---|
1592 | ck_odt <= ck_cntr; |
---|
1593 | end |
---|
1594 | end |
---|
1595 | if (odt_pipeline[0]) begin |
---|
1596 | odt_state = ~odt_state; |
---|
1597 | if (DEBUG) $display ("%m: at time %t INFO: Sync On Die Termination = %d", $time, odt_state); |
---|
1598 | end |
---|
1599 | end |
---|
1600 | |
---|
1601 | // shift pipelines |
---|
1602 | if (|wr_pipeline || |rd_pipeline || |al_pipeline) begin |
---|
1603 | al_pipeline = al_pipeline>>1; |
---|
1604 | wr_pipeline = wr_pipeline>>1; |
---|
1605 | rd_pipeline = rd_pipeline>>1; |
---|
1606 | for (i=0; i<`MAX_PIPE; i=i+1) begin |
---|
1607 | ba_pipeline[i] = ba_pipeline[i+1]; |
---|
1608 | row_pipeline[i] = row_pipeline[i+1]; |
---|
1609 | col_pipeline[i] = col_pipeline[i+1]; |
---|
1610 | end |
---|
1611 | end |
---|
1612 | if (|odt_pipeline) begin |
---|
1613 | odt_pipeline = odt_pipeline>>1; |
---|
1614 | end |
---|
1615 | end |
---|
1616 | |
---|
1617 | // receiver(s) |
---|
1618 | task dqs_even_receiver; |
---|
1619 | input [4:0] i; |
---|
1620 | reg [71:0] bit_mask; |
---|
1621 | begin |
---|
1622 | bit_mask = {`DQ_PER_DQS{1'b1}}<<(i*`DQ_PER_DQS); |
---|
1623 | if (dqs_even[i]) begin |
---|
1624 | if (rdqs_en) begin // rdqs disables dm |
---|
1625 | dm_in_pos[i] = 1'b0; |
---|
1626 | end else begin |
---|
1627 | dm_in_pos[i] = dm_in[i]; |
---|
1628 | end |
---|
1629 | dq_in_pos = (dq_in & bit_mask) | (dq_in_pos & ~bit_mask); |
---|
1630 | end |
---|
1631 | end |
---|
1632 | endtask |
---|
1633 | |
---|
1634 | always @(posedge dqs_even[ 0]) dqs_even_receiver( 0); |
---|
1635 | always @(posedge dqs_even[ 1]) dqs_even_receiver( 1); |
---|
1636 | always @(posedge dqs_even[ 2]) dqs_even_receiver( 2); |
---|
1637 | always @(posedge dqs_even[ 3]) dqs_even_receiver( 3); |
---|
1638 | always @(posedge dqs_even[ 4]) dqs_even_receiver( 4); |
---|
1639 | always @(posedge dqs_even[ 5]) dqs_even_receiver( 5); |
---|
1640 | always @(posedge dqs_even[ 6]) dqs_even_receiver( 6); |
---|
1641 | always @(posedge dqs_even[ 7]) dqs_even_receiver( 7); |
---|
1642 | always @(posedge dqs_even[ 8]) dqs_even_receiver( 8); |
---|
1643 | always @(posedge dqs_even[ 9]) dqs_even_receiver( 9); |
---|
1644 | always @(posedge dqs_even[10]) dqs_even_receiver(10); |
---|
1645 | always @(posedge dqs_even[11]) dqs_even_receiver(11); |
---|
1646 | always @(posedge dqs_even[12]) dqs_even_receiver(12); |
---|
1647 | always @(posedge dqs_even[13]) dqs_even_receiver(13); |
---|
1648 | always @(posedge dqs_even[14]) dqs_even_receiver(14); |
---|
1649 | always @(posedge dqs_even[15]) dqs_even_receiver(15); |
---|
1650 | always @(posedge dqs_even[16]) dqs_even_receiver(16); |
---|
1651 | always @(posedge dqs_even[17]) dqs_even_receiver(17); |
---|
1652 | |
---|
1653 | task dqs_odd_receiver; |
---|
1654 | input [4:0] i; |
---|
1655 | reg [71:0] bit_mask; |
---|
1656 | begin |
---|
1657 | bit_mask = {`DQ_PER_DQS{1'b1}}<<(i*`DQ_PER_DQS); |
---|
1658 | if (dqs_odd[i]) begin |
---|
1659 | if (rdqs_en) begin // rdqs disables dm |
---|
1660 | dm_in_neg[i] = 1'b0; |
---|
1661 | end else begin |
---|
1662 | dm_in_neg[i] = dm_in[i]; |
---|
1663 | end |
---|
1664 | dq_in_neg = (dq_in & bit_mask) | (dq_in_neg & ~bit_mask); |
---|
1665 | end |
---|
1666 | end |
---|
1667 | endtask |
---|
1668 | |
---|
1669 | always @(posedge dqs_odd[ 0]) dqs_odd_receiver( 0); |
---|
1670 | always @(posedge dqs_odd[ 1]) dqs_odd_receiver( 1); |
---|
1671 | always @(posedge dqs_odd[ 2]) dqs_odd_receiver( 2); |
---|
1672 | always @(posedge dqs_odd[ 3]) dqs_odd_receiver( 3); |
---|
1673 | always @(posedge dqs_odd[ 4]) dqs_odd_receiver( 4); |
---|
1674 | always @(posedge dqs_odd[ 5]) dqs_odd_receiver( 5); |
---|
1675 | always @(posedge dqs_odd[ 6]) dqs_odd_receiver( 6); |
---|
1676 | always @(posedge dqs_odd[ 7]) dqs_odd_receiver( 7); |
---|
1677 | always @(posedge dqs_odd[ 8]) dqs_odd_receiver( 8); |
---|
1678 | always @(posedge dqs_odd[ 9]) dqs_odd_receiver( 9); |
---|
1679 | always @(posedge dqs_odd[10]) dqs_odd_receiver(10); |
---|
1680 | always @(posedge dqs_odd[11]) dqs_odd_receiver(11); |
---|
1681 | always @(posedge dqs_odd[12]) dqs_odd_receiver(12); |
---|
1682 | always @(posedge dqs_odd[13]) dqs_odd_receiver(13); |
---|
1683 | always @(posedge dqs_odd[14]) dqs_odd_receiver(14); |
---|
1684 | always @(posedge dqs_odd[15]) dqs_odd_receiver(15); |
---|
1685 | always @(posedge dqs_odd[16]) dqs_odd_receiver(16); |
---|
1686 | always @(posedge dqs_odd[17]) dqs_odd_receiver(17); |
---|
1687 | |
---|
1688 | // Processes to check hold and pulse width of control signals |
---|
1689 | always @(cke_in) begin |
---|
1690 | if ($time > TIH) begin |
---|
1691 | if ($time - tm_ck_pos < TIH) |
---|
1692 | $display ("%m: at time %t ERROR: tIH violation on CKE by %t", $time, tm_ck_pos + TIH - $time); |
---|
1693 | end |
---|
1694 | if (dll_locked && ($time - tm_cke < $rtoi(TIPW*tck_avg))) |
---|
1695 | $display ("%m: at time %t ERROR: tIPW violation on CKE by %t", $time, tm_cke + TIPW*tck_avg - $time); |
---|
1696 | tm_cke = $time; |
---|
1697 | end |
---|
1698 | always @(odt_in) begin |
---|
1699 | if (odt_en && !in_self_refresh) begin |
---|
1700 | if ($time - tm_ck_pos < TIH) |
---|
1701 | $display ("%m: at time %t ERROR: tIH violation on ODT by %t", $time, tm_ck_pos + TIH - $time); |
---|
1702 | if (dll_locked && ($time - tm_odt < $rtoi(TIPW*tck_avg))) |
---|
1703 | $display ("%m: at time %t ERROR: tIPW violation on ODT by %t", $time, tm_odt + TIPW*tck_avg - $time); |
---|
1704 | end |
---|
1705 | tm_odt = $time; |
---|
1706 | end |
---|
1707 | |
---|
1708 | task cmd_addr_timing_check; |
---|
1709 | input i; |
---|
1710 | reg [4:0] i; |
---|
1711 | begin |
---|
1712 | if (prev_cke) begin |
---|
1713 | if ((i == 0) && ($time - tm_ck_pos < TIH)) // Always check tIH for CS# |
---|
1714 | $display ("%m: at time %t ERROR: tIH violation on %s by %t", $time, cmd_addr_string[i], tm_ck_pos + TIH - $time); |
---|
1715 | if ((i > 0) && (cs_n_in == 1'b0) && ($time - tm_ck_pos < TIH)) // Only check tIH for cmd_addr if CS# low |
---|
1716 | $display ("%m: at time %t ERROR: tIH violation on %s by %t", $time, cmd_addr_string[i], tm_ck_pos + TIH - $time); |
---|
1717 | if (dll_locked && ($time - tm_cmd_addr[i] < $rtoi(TIPW*tck_avg))) |
---|
1718 | $display ("%m: at time %t ERROR: tIPW violation on %s by %t", $time, cmd_addr_string[i], tm_cmd_addr[i] + TIPW*tck_avg - $time); |
---|
1719 | end |
---|
1720 | tm_cmd_addr[i] = $time; |
---|
1721 | end |
---|
1722 | endtask |
---|
1723 | |
---|
1724 | always @(cs_n_in ) cmd_addr_timing_check( 0); |
---|
1725 | always @(ras_n_in ) cmd_addr_timing_check( 1); |
---|
1726 | always @(cas_n_in ) cmd_addr_timing_check( 2); |
---|
1727 | always @(we_n_in ) cmd_addr_timing_check( 3); |
---|
1728 | always @(ba_in [ 0]) cmd_addr_timing_check( 4); |
---|
1729 | always @(ba_in [ 1]) cmd_addr_timing_check( 5); |
---|
1730 | always @(ba_in [ 2]) cmd_addr_timing_check( 6); |
---|
1731 | always @(addr_in[ 0]) cmd_addr_timing_check( 7); |
---|
1732 | always @(addr_in[ 1]) cmd_addr_timing_check( 8); |
---|
1733 | always @(addr_in[ 2]) cmd_addr_timing_check( 9); |
---|
1734 | always @(addr_in[ 3]) cmd_addr_timing_check(10); |
---|
1735 | always @(addr_in[ 4]) cmd_addr_timing_check(11); |
---|
1736 | always @(addr_in[ 5]) cmd_addr_timing_check(12); |
---|
1737 | always @(addr_in[ 6]) cmd_addr_timing_check(13); |
---|
1738 | always @(addr_in[ 7]) cmd_addr_timing_check(14); |
---|
1739 | always @(addr_in[ 8]) cmd_addr_timing_check(15); |
---|
1740 | always @(addr_in[ 9]) cmd_addr_timing_check(16); |
---|
1741 | always @(addr_in[10]) cmd_addr_timing_check(17); |
---|
1742 | always @(addr_in[11]) cmd_addr_timing_check(18); |
---|
1743 | always @(addr_in[12]) cmd_addr_timing_check(19); |
---|
1744 | always @(addr_in[13]) cmd_addr_timing_check(20); |
---|
1745 | always @(addr_in[14]) cmd_addr_timing_check(21); |
---|
1746 | always @(addr_in[15]) cmd_addr_timing_check(22); |
---|
1747 | |
---|
1748 | // Processes to check setup and hold of data signals |
---|
1749 | task dm_timing_check; |
---|
1750 | input i; |
---|
1751 | reg [4:0] i; |
---|
1752 | begin |
---|
1753 | if (dqs_in_valid) begin |
---|
1754 | if ($time - tm_dqs[i] < TDH) |
---|
1755 | $display ("%m: at time %t ERROR: tDH violation on DM bit %d by %t", $time, i, tm_dqs[i] + TDH - $time); |
---|
1756 | if (check_dm_tdipw[i]) begin |
---|
1757 | if (dll_locked && ($time - tm_dm[i] < $rtoi(TDIPW*tck_avg))) |
---|
1758 | $display ("%m: at time %t ERROR: tDIPW violation on DM bit %d by %t", $time, i, tm_dm[i] + TDIPW*tck_avg - $time); |
---|
1759 | end |
---|
1760 | end |
---|
1761 | check_dm_tdipw[i] <= 1'b0; |
---|
1762 | tm_dm[i] = $time; |
---|
1763 | end |
---|
1764 | endtask |
---|
1765 | |
---|
1766 | always @(dm_in[ 0]) dm_timing_check( 0); |
---|
1767 | always @(dm_in[ 1]) dm_timing_check( 1); |
---|
1768 | always @(dm_in[ 2]) dm_timing_check( 2); |
---|
1769 | always @(dm_in[ 3]) dm_timing_check( 3); |
---|
1770 | always @(dm_in[ 4]) dm_timing_check( 4); |
---|
1771 | always @(dm_in[ 5]) dm_timing_check( 5); |
---|
1772 | always @(dm_in[ 6]) dm_timing_check( 6); |
---|
1773 | always @(dm_in[ 7]) dm_timing_check( 7); |
---|
1774 | always @(dm_in[ 8]) dm_timing_check( 8); |
---|
1775 | always @(dm_in[ 9]) dm_timing_check( 9); |
---|
1776 | always @(dm_in[10]) dm_timing_check(10); |
---|
1777 | always @(dm_in[11]) dm_timing_check(11); |
---|
1778 | always @(dm_in[12]) dm_timing_check(12); |
---|
1779 | always @(dm_in[13]) dm_timing_check(13); |
---|
1780 | always @(dm_in[14]) dm_timing_check(14); |
---|
1781 | always @(dm_in[15]) dm_timing_check(15); |
---|
1782 | always @(dm_in[16]) dm_timing_check(16); |
---|
1783 | always @(dm_in[17]) dm_timing_check(17); |
---|
1784 | |
---|
1785 | task dq_timing_check; |
---|
1786 | input i; |
---|
1787 | reg [6:0] i; |
---|
1788 | begin |
---|
1789 | if (dqs_in_valid) begin |
---|
1790 | if ($time - tm_dqs[i/`DQ_PER_DQS] < TDH) |
---|
1791 | $display ("%m: at time %t ERROR: tDH violation on DQ bit %d by %t", $time, i, tm_dqs[i/`DQ_PER_DQS] + TDH - $time); |
---|
1792 | if (check_dq_tdipw[i]) begin |
---|
1793 | if (dll_locked && ($time - tm_dq[i] < $rtoi(TDIPW*tck_avg))) |
---|
1794 | $display ("%m: at time %t ERROR: tDIPW violation on DQ bit %d by %t", $time, i, tm_dq[i] + TDIPW*tck_avg - $time); |
---|
1795 | end |
---|
1796 | end |
---|
1797 | check_dq_tdipw[i] <= 1'b0; |
---|
1798 | tm_dq[i] = $time; |
---|
1799 | end |
---|
1800 | endtask |
---|
1801 | |
---|
1802 | always @(dq_in[ 0]) dq_timing_check( 0); |
---|
1803 | always @(dq_in[ 1]) dq_timing_check( 1); |
---|
1804 | always @(dq_in[ 2]) dq_timing_check( 2); |
---|
1805 | always @(dq_in[ 3]) dq_timing_check( 3); |
---|
1806 | always @(dq_in[ 4]) dq_timing_check( 4); |
---|
1807 | always @(dq_in[ 5]) dq_timing_check( 5); |
---|
1808 | always @(dq_in[ 6]) dq_timing_check( 6); |
---|
1809 | always @(dq_in[ 7]) dq_timing_check( 7); |
---|
1810 | always @(dq_in[ 8]) dq_timing_check( 8); |
---|
1811 | always @(dq_in[ 9]) dq_timing_check( 9); |
---|
1812 | always @(dq_in[10]) dq_timing_check(10); |
---|
1813 | always @(dq_in[11]) dq_timing_check(11); |
---|
1814 | always @(dq_in[12]) dq_timing_check(12); |
---|
1815 | always @(dq_in[13]) dq_timing_check(13); |
---|
1816 | always @(dq_in[14]) dq_timing_check(14); |
---|
1817 | always @(dq_in[15]) dq_timing_check(15); |
---|
1818 | always @(dq_in[16]) dq_timing_check(16); |
---|
1819 | always @(dq_in[17]) dq_timing_check(17); |
---|
1820 | always @(dq_in[18]) dq_timing_check(18); |
---|
1821 | always @(dq_in[19]) dq_timing_check(19); |
---|
1822 | always @(dq_in[20]) dq_timing_check(20); |
---|
1823 | always @(dq_in[21]) dq_timing_check(21); |
---|
1824 | always @(dq_in[22]) dq_timing_check(22); |
---|
1825 | always @(dq_in[23]) dq_timing_check(23); |
---|
1826 | always @(dq_in[24]) dq_timing_check(24); |
---|
1827 | always @(dq_in[25]) dq_timing_check(25); |
---|
1828 | always @(dq_in[26]) dq_timing_check(26); |
---|
1829 | always @(dq_in[27]) dq_timing_check(27); |
---|
1830 | always @(dq_in[28]) dq_timing_check(28); |
---|
1831 | always @(dq_in[29]) dq_timing_check(29); |
---|
1832 | always @(dq_in[30]) dq_timing_check(30); |
---|
1833 | always @(dq_in[31]) dq_timing_check(31); |
---|
1834 | always @(dq_in[32]) dq_timing_check(32); |
---|
1835 | always @(dq_in[33]) dq_timing_check(33); |
---|
1836 | always @(dq_in[34]) dq_timing_check(34); |
---|
1837 | always @(dq_in[35]) dq_timing_check(35); |
---|
1838 | always @(dq_in[36]) dq_timing_check(36); |
---|
1839 | always @(dq_in[37]) dq_timing_check(37); |
---|
1840 | always @(dq_in[38]) dq_timing_check(38); |
---|
1841 | always @(dq_in[39]) dq_timing_check(39); |
---|
1842 | always @(dq_in[40]) dq_timing_check(40); |
---|
1843 | always @(dq_in[41]) dq_timing_check(41); |
---|
1844 | always @(dq_in[42]) dq_timing_check(42); |
---|
1845 | always @(dq_in[43]) dq_timing_check(43); |
---|
1846 | always @(dq_in[44]) dq_timing_check(44); |
---|
1847 | always @(dq_in[45]) dq_timing_check(45); |
---|
1848 | always @(dq_in[46]) dq_timing_check(46); |
---|
1849 | always @(dq_in[47]) dq_timing_check(47); |
---|
1850 | always @(dq_in[48]) dq_timing_check(48); |
---|
1851 | always @(dq_in[49]) dq_timing_check(49); |
---|
1852 | always @(dq_in[50]) dq_timing_check(50); |
---|
1853 | always @(dq_in[51]) dq_timing_check(51); |
---|
1854 | always @(dq_in[52]) dq_timing_check(52); |
---|
1855 | always @(dq_in[53]) dq_timing_check(53); |
---|
1856 | always @(dq_in[54]) dq_timing_check(54); |
---|
1857 | always @(dq_in[55]) dq_timing_check(55); |
---|
1858 | always @(dq_in[56]) dq_timing_check(56); |
---|
1859 | always @(dq_in[57]) dq_timing_check(57); |
---|
1860 | always @(dq_in[58]) dq_timing_check(58); |
---|
1861 | always @(dq_in[59]) dq_timing_check(59); |
---|
1862 | always @(dq_in[60]) dq_timing_check(60); |
---|
1863 | always @(dq_in[61]) dq_timing_check(61); |
---|
1864 | always @(dq_in[62]) dq_timing_check(62); |
---|
1865 | always @(dq_in[63]) dq_timing_check(63); |
---|
1866 | always @(dq_in[64]) dq_timing_check(64); |
---|
1867 | always @(dq_in[65]) dq_timing_check(65); |
---|
1868 | always @(dq_in[66]) dq_timing_check(66); |
---|
1869 | always @(dq_in[67]) dq_timing_check(67); |
---|
1870 | always @(dq_in[68]) dq_timing_check(68); |
---|
1871 | always @(dq_in[69]) dq_timing_check(69); |
---|
1872 | always @(dq_in[70]) dq_timing_check(70); |
---|
1873 | always @(dq_in[71]) dq_timing_check(71); |
---|
1874 | |
---|
1875 | task dqs_pos_timing_check; |
---|
1876 | input i; |
---|
1877 | reg [5:0] i; |
---|
1878 | reg [3:0] j; |
---|
1879 | begin |
---|
1880 | if (dqs_in_valid && ((wdqs_pos_cntr[i] < burst_length/2) || b2b_write) && (dqs_n_en || i<18)) begin |
---|
1881 | if (dqs_in[i] ^ prev_dqs_in[i]) begin |
---|
1882 | if (dll_locked) begin |
---|
1883 | if (check_write_preamble[i]) begin |
---|
1884 | if ($time - tm_dqs_neg[i] < $rtoi(TWPRE*tck_avg)) |
---|
1885 | $display ("%m: at time %t ERROR: tWPRE violation on &s bit %d", $time, dqs_string[i/18], i%18); |
---|
1886 | end else if (check_write_postamble[i]) begin |
---|
1887 | if ($time - tm_dqs_neg[i] < $rtoi(TWPST*tck_avg)) |
---|
1888 | $display ("%m: at time %t ERROR: tWPST violation on %s bit %d", $time, dqs_string[i/18], i%18); |
---|
1889 | end else begin |
---|
1890 | if ($time - tm_dqs_neg[i] < $rtoi(TDQSL*tck_avg)) |
---|
1891 | $display ("%m: at time %t ERROR: tDQSL violation on %s bit %d", $time, dqs_string[i/18], i%18); |
---|
1892 | end |
---|
1893 | end |
---|
1894 | if ($time - tm_dm[i%18] < TDS) |
---|
1895 | $display ("%m: at time %t ERROR: tDS violation on DM bit %d by %t", $time, i, tm_dm[i%18] + TDS - $time); |
---|
1896 | if (!dq_out_en) begin |
---|
1897 | for (j=0; j<`DQ_PER_DQS; j=j+1) begin |
---|
1898 | if ($time - tm_dq[i*`DQ_PER_DQS+j] < TDS) |
---|
1899 | $display ("%m: at time %t ERROR: tDS violation on DQ bit %d by %t", $time, i*`DQ_PER_DQS+j, tm_dq[i*`DQ_PER_DQS+j] + TDS - $time); |
---|
1900 | check_dq_tdipw[i*`DQ_PER_DQS+j] <= 1'b1; |
---|
1901 | end |
---|
1902 | end |
---|
1903 | if ((wdqs_pos_cntr[i] < burst_length/2) && !b2b_write) begin |
---|
1904 | wdqs_pos_cntr[i] <= wdqs_pos_cntr[i] + 1; |
---|
1905 | end else begin |
---|
1906 | wdqs_pos_cntr[i] <= 1; |
---|
1907 | end |
---|
1908 | check_dm_tdipw[i%18] <= 1'b1; |
---|
1909 | check_write_preamble[i] <= 1'b0; |
---|
1910 | check_write_postamble[i] <= 1'b0; |
---|
1911 | check_write_dqs_low[i] <= 1'b0; |
---|
1912 | tm_dqs[i%18] <= $time; |
---|
1913 | end else begin |
---|
1914 | $display ("%m: at time %t ERROR: Invalid latching edge on %s bit %d", $time, dqs_string[i/18], i%18); |
---|
1915 | end |
---|
1916 | end |
---|
1917 | tm_dqss_pos[i] <= $time; |
---|
1918 | tm_dqs_pos[i] = $time; |
---|
1919 | prev_dqs_in[i] <= dqs_in[i]; |
---|
1920 | end |
---|
1921 | endtask |
---|
1922 | |
---|
1923 | always @(posedge dqs_in[ 0]) dqs_pos_timing_check( 0); |
---|
1924 | always @(posedge dqs_in[ 1]) dqs_pos_timing_check( 1); |
---|
1925 | always @(posedge dqs_in[ 2]) dqs_pos_timing_check( 2); |
---|
1926 | always @(posedge dqs_in[ 3]) dqs_pos_timing_check( 3); |
---|
1927 | always @(posedge dqs_in[ 4]) dqs_pos_timing_check( 4); |
---|
1928 | always @(posedge dqs_in[ 5]) dqs_pos_timing_check( 5); |
---|
1929 | always @(posedge dqs_in[ 6]) dqs_pos_timing_check( 6); |
---|
1930 | always @(posedge dqs_in[ 7]) dqs_pos_timing_check( 7); |
---|
1931 | always @(posedge dqs_in[ 8]) dqs_pos_timing_check( 8); |
---|
1932 | always @(posedge dqs_in[ 9]) dqs_pos_timing_check( 9); |
---|
1933 | always @(posedge dqs_in[10]) dqs_pos_timing_check(10); |
---|
1934 | always @(posedge dqs_in[11]) dqs_pos_timing_check(11); |
---|
1935 | always @(posedge dqs_in[12]) dqs_pos_timing_check(12); |
---|
1936 | always @(posedge dqs_in[13]) dqs_pos_timing_check(13); |
---|
1937 | always @(posedge dqs_in[14]) dqs_pos_timing_check(14); |
---|
1938 | always @(posedge dqs_in[15]) dqs_pos_timing_check(15); |
---|
1939 | always @(posedge dqs_in[16]) dqs_pos_timing_check(16); |
---|
1940 | always @(posedge dqs_in[17]) dqs_pos_timing_check(17); |
---|
1941 | always @(negedge dqs_in[18]) dqs_pos_timing_check(18); |
---|
1942 | always @(negedge dqs_in[19]) dqs_pos_timing_check(19); |
---|
1943 | always @(negedge dqs_in[20]) dqs_pos_timing_check(20); |
---|
1944 | always @(negedge dqs_in[21]) dqs_pos_timing_check(21); |
---|
1945 | always @(negedge dqs_in[22]) dqs_pos_timing_check(22); |
---|
1946 | always @(negedge dqs_in[23]) dqs_pos_timing_check(23); |
---|
1947 | always @(negedge dqs_in[24]) dqs_pos_timing_check(24); |
---|
1948 | always @(negedge dqs_in[25]) dqs_pos_timing_check(25); |
---|
1949 | always @(negedge dqs_in[26]) dqs_pos_timing_check(26); |
---|
1950 | always @(negedge dqs_in[27]) dqs_pos_timing_check(27); |
---|
1951 | always @(negedge dqs_in[28]) dqs_pos_timing_check(28); |
---|
1952 | always @(negedge dqs_in[29]) dqs_pos_timing_check(29); |
---|
1953 | always @(negedge dqs_in[30]) dqs_pos_timing_check(30); |
---|
1954 | always @(negedge dqs_in[31]) dqs_pos_timing_check(31); |
---|
1955 | always @(negedge dqs_in[32]) dqs_neg_timing_check(32); |
---|
1956 | always @(negedge dqs_in[33]) dqs_neg_timing_check(33); |
---|
1957 | always @(negedge dqs_in[34]) dqs_neg_timing_check(34); |
---|
1958 | always @(negedge dqs_in[35]) dqs_neg_timing_check(35); |
---|
1959 | |
---|
1960 | task dqs_neg_timing_check; |
---|
1961 | input i; |
---|
1962 | reg [5:0] i; |
---|
1963 | reg [3:0] j; |
---|
1964 | begin |
---|
1965 | if (dqs_in_valid && (wdqs_pos_cntr[i] > 0) && check_write_dqs_high[i] && (dqs_n_en || i < 18)) begin |
---|
1966 | if (dqs_in[i] ^ prev_dqs_in[i]) begin |
---|
1967 | if (dll_locked) begin |
---|
1968 | if ($time - tm_dqs_pos[i] < $rtoi(TDQSH*tck_avg)) |
---|
1969 | $display ("%m: at time %t ERROR: tDQSH violation on %s bit %d", $time, dqs_string[i/18], i%18); |
---|
1970 | if ($time - tm_ck_pos < $rtoi(TDSH*tck_avg)) |
---|
1971 | $display ("%m: at time %t ERROR: tDSH violation on %s bit %d", $time, dqs_string[i/18], i%18); |
---|
1972 | end |
---|
1973 | if ($time - tm_dm[i%18] < TDS) |
---|
1974 | $display ("%m: at time %t ERROR: tDS violation on DM bit %d by %t", $time, i, tm_dm[i%18] + TDS - $time); |
---|
1975 | if (!dq_out_en) begin |
---|
1976 | for (j=0; j<`DQ_PER_DQS; j=j+1) begin |
---|
1977 | if ($time - tm_dq[i*`DQ_PER_DQS+j] < TDS) |
---|
1978 | $display ("%m: at time %t ERROR: tDS violation on DQ bit %d by %t", $time, i*`DQ_PER_DQS+j, tm_dq[i*`DQ_PER_DQS+j] + TDS - $time); |
---|
1979 | check_dq_tdipw[i*`DQ_PER_DQS+j] <= 1'b1; |
---|
1980 | end |
---|
1981 | end |
---|
1982 | check_dm_tdipw[i%18] <= 1'b1; |
---|
1983 | check_write_dqs_high[i] <= 1'b0; |
---|
1984 | tm_dqs[i%18] <= $time; |
---|
1985 | end else begin |
---|
1986 | $display ("%m: at time %t ERROR: Invalid latching edge on %s bit %d", $time, dqs_string[i/18], i%18); |
---|
1987 | end |
---|
1988 | end |
---|
1989 | tm_dqs_neg[i] = $time; |
---|
1990 | prev_dqs_in[i] <= dqs_in[i]; |
---|
1991 | end |
---|
1992 | endtask |
---|
1993 | |
---|
1994 | always @(negedge dqs_in[ 0]) dqs_neg_timing_check( 0); |
---|
1995 | always @(negedge dqs_in[ 1]) dqs_neg_timing_check( 1); |
---|
1996 | always @(negedge dqs_in[ 2]) dqs_neg_timing_check( 2); |
---|
1997 | always @(negedge dqs_in[ 3]) dqs_neg_timing_check( 3); |
---|
1998 | always @(negedge dqs_in[ 4]) dqs_neg_timing_check( 4); |
---|
1999 | always @(negedge dqs_in[ 5]) dqs_neg_timing_check( 5); |
---|
2000 | always @(negedge dqs_in[ 6]) dqs_neg_timing_check( 6); |
---|
2001 | always @(negedge dqs_in[ 7]) dqs_neg_timing_check( 7); |
---|
2002 | always @(negedge dqs_in[ 8]) dqs_neg_timing_check( 8); |
---|
2003 | always @(negedge dqs_in[ 9]) dqs_neg_timing_check( 9); |
---|
2004 | always @(negedge dqs_in[10]) dqs_neg_timing_check(10); |
---|
2005 | always @(negedge dqs_in[11]) dqs_neg_timing_check(11); |
---|
2006 | always @(negedge dqs_in[12]) dqs_neg_timing_check(12); |
---|
2007 | always @(negedge dqs_in[13]) dqs_neg_timing_check(13); |
---|
2008 | always @(negedge dqs_in[14]) dqs_neg_timing_check(14); |
---|
2009 | always @(negedge dqs_in[15]) dqs_neg_timing_check(15); |
---|
2010 | always @(negedge dqs_in[16]) dqs_neg_timing_check(16); |
---|
2011 | always @(negedge dqs_in[17]) dqs_neg_timing_check(17); |
---|
2012 | always @(posedge dqs_in[18]) dqs_neg_timing_check(18); |
---|
2013 | always @(posedge dqs_in[19]) dqs_neg_timing_check(19); |
---|
2014 | always @(posedge dqs_in[20]) dqs_neg_timing_check(20); |
---|
2015 | always @(posedge dqs_in[21]) dqs_neg_timing_check(21); |
---|
2016 | always @(posedge dqs_in[22]) dqs_neg_timing_check(22); |
---|
2017 | always @(posedge dqs_in[23]) dqs_neg_timing_check(23); |
---|
2018 | always @(posedge dqs_in[24]) dqs_neg_timing_check(24); |
---|
2019 | always @(posedge dqs_in[25]) dqs_neg_timing_check(25); |
---|
2020 | always @(posedge dqs_in[26]) dqs_neg_timing_check(26); |
---|
2021 | always @(posedge dqs_in[27]) dqs_neg_timing_check(27); |
---|
2022 | always @(posedge dqs_in[28]) dqs_neg_timing_check(28); |
---|
2023 | always @(posedge dqs_in[29]) dqs_neg_timing_check(29); |
---|
2024 | always @(posedge dqs_in[30]) dqs_neg_timing_check(30); |
---|
2025 | always @(posedge dqs_in[31]) dqs_neg_timing_check(31); |
---|
2026 | always @(posedge dqs_in[32]) dqs_neg_timing_check(32); |
---|
2027 | always @(posedge dqs_in[33]) dqs_neg_timing_check(33); |
---|
2028 | always @(posedge dqs_in[34]) dqs_neg_timing_check(34); |
---|
2029 | always @(posedge dqs_in[35]) dqs_neg_timing_check(35); |
---|
2030 | |
---|
2031 | endmodule |
---|