OpenCores
URL https://opencores.org/ocsvn/mips_enhanced/mips_enhanced/trunk

Subversion Repositories mips_enhanced

[/] [mips_enhanced/] [trunk/] [grlib-gpl-1.0.19-b3188/] [lib/] [micron/] [ddr/] [ddr2.v] - Blame information for rev 2

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.