Root/Examples/sram_gpio/logic/sim/ddr/ddr.v

1/****************************************************************************************
2*
3* File Name: ddr.v
4* Version: 5.7
5* Model: BUS Functional
6*
7* Dependencies: ddr_parameters.v
8*
9* Description: Micron SDRAM DDR (Double Data Rate)
10*
11* Limitation: - Doesn't check for 8K-cycle refresh.
12* - Doesn't check power-down entry/exit
13* - Doesn't check self-refresh entry/exit.
14*
15* Note: - Set simulator resolution to "ps" accuracy
16* - Set Debug = 0 to disable $display messages
17* - Model assume Clk and Clk# crossing at both edge
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* 2.1 SPH 03/19/2002 - Second Release
45* - Fix tWR and several incompatability
46* between different simulators
47* 3.0 TFK 02/18/2003 - Added tDSS and tDSH timing checks.
48* - Added tDQSH and tDQSL timing checks.
49* 3.1 CAH 05/28/2003 - update all models to release version 3.1
50* (no changes to this model)
51* 3.2 JMK 06/16/2003 - updated all DDR400 models to support CAS Latency 3
52* 3.3 JMK 09/11/2003 - Added initialization sequence checks.
53* 4.0 JMK 12/01/2003 - Grouped parameters into "ddr_parameters.v"
54* - Fixed tWTR check
55* 4.1 JMK 01/14/2004 - Grouped specify parameters by speed grade
56* - Fixed mem_sizes parameter
57* 4.2 JMK 03/19/2004 - Fixed pulse width checking on Dqs
58* 4.3 JMK 04/27/2004 - Changed BL wire size in tb module
59* - Changed Dq_buf size to [15:0]
60* 5.0 JMK 06/16/2004 - Added read to write checking.
61* - Added read with precharge truncation to write checking.
62* - Added associative memory array to reduce memory consumption.
63* - Added checking for required DQS edges during write.
64* 5.1 JMK 08/16/2004 - Fixed checking for required DQS edges during write.
65* - Fixed wdqs_valid window.
66* 5.2 JMK 09/24/2004 - Read or Write without activate will be ignored.
67* 5.3 JMK 10/27/2004 - Added tMRD checking during Auto Refresh and Activate.
68* - Added tRFC checking during Load Mode and Precharge.
69* 5.4 JMK 12/13/2004 - The model will not respond to illegal command sequences.
70* 5.5 SPH 01/13/2005 - The model will issue a halt on illegal command sequences.
71* JMK 02/11/2005 - Changed the display format for numbers to hex.
72* 5.6 JMK 04/22/2005 - Fixed Write with auto precharge calculation.
73* 5.7 JMK 08/05/2005 - Changed conditions for read with precharge truncation error.
74* - Renamed parameters file with .vh extension.
75****************************************************************************************/
76
77// DO NOT CHANGE THE TIMESCALE
78// MAKE SURE YOUR SIMULATOR USE "PS" RESOLUTION
79`timescale 1ns / 1ps
80
81module ddr (Dq, Dqs, Addr, Ba, Clk, Clk_n, Cke, Cs_n, Ras_n, Cas_n, We_n, Dm);
82
83    `include "ddr_parameters.vh"
84
85    // Port Declarations
86    inout [DQ_BITS - 1 : 0] Dq;
87    inout [DQS_BITS - 1 : 0] Dqs;
88    input [ADDR_BITS - 1 : 0] Addr;
89    input [1 : 0] Ba;
90    input Clk;
91    input Clk_n;
92    input Cke;
93    input Cs_n;
94    input Ras_n;
95    input Cas_n;
96    input We_n;
97    input [DM_BITS - 1 : 0] Dm;
98
99    // Internal Wires (fixed width)
100    wire [15 : 0] Dq_in;
101    wire [1 : 0] Dqs_in;
102    wire [1 : 0] Dm_in;
103    
104    assign Dq_in [DQ_BITS - 1 : 0] = Dq;
105    assign Dqs_in [DQS_BITS - 1 : 0] = Dqs;
106    assign Dm_in [DM_BITS - 1 : 0] = Dm;
107
108    // Data pair
109    reg [15 : 0] dq_rise;
110    reg [1 : 0] dm_rise;
111    reg [15 : 0] dq_fall;
112    reg [1 : 0] dm_fall;
113    reg [3 : 0] dm_pair;
114    reg [15 : 0] Dq_buf;
115    
116    // Mode Register
117    reg [ADDR_BITS - 1 : 0] Mode_reg;
118
119    // Internal System Clock
120    reg CkeZ, Sys_clk;
121
122    // Internal Dqs initialize
123    reg Dqs_int;
124
125    // Dqs buffer
126    reg [DQS_BITS - 1 : 0] Dqs_out;
127
128    // Dq buffer
129    reg [DQ_BITS - 1 : 0] Dq_out;
130
131    // Read pipeline variables
132    reg Read_cmnd [0 : 6];
133    reg [1 : 0] Read_bank [0 : 6];
134    reg [COL_BITS - 1 : 0] Read_cols [0 : 6];
135
136    // Write pipeline variables
137    reg Write_cmnd [0 : 3];
138    reg [1 : 0] Write_bank [0 : 3];
139    reg [COL_BITS - 1 : 0] Write_cols [0 : 3];
140
141    // Auto precharge variables
142    reg Read_precharge [0 : 3];
143    reg Write_precharge [0 : 3];
144    integer Count_precharge [0 : 3];
145
146    // Manual precharge variables
147    reg A10_precharge [0 : 6];
148    reg [1 : 0] Bank_precharge [0 : 6];
149    reg Cmnd_precharge [0 : 6];
150
151    // Burst terminate variables
152    reg Cmnd_bst [0 : 6];
153
154    // Memory Banks
155`ifdef FULL_MEM
156    reg [DQ_BITS - 1 : 0] mem_array [0 : (1<<full_mem_bits)-1];
157`else
158    reg [DQ_BITS - 1 : 0] mem_array [0 : (1<<part_mem_bits)-1];
159    reg [full_mem_bits - 1 : 0] addr_array [0 : (1<<part_mem_bits)-1];
160    reg [part_mem_bits : 0] mem_used;
161    initial mem_used = 0;
162`endif
163
164    // Dqs edge checking
165    integer i;
166    reg [1:0] expect_pos_dqs;
167    reg [1:0] expect_neg_dqs;
168
169    // Burst counter
170    reg [COL_BITS - 1 : 0] Burst_counter;
171
172    // Precharge variables
173    reg Pc_b0, Pc_b1, Pc_b2, Pc_b3;
174
175    // Activate variables
176    reg Act_b0, Act_b1, Act_b2, Act_b3;
177
178    // Data IO variables
179    reg Data_in_enable;
180    reg Data_out_enable;
181
182    // Internal address mux variables
183    reg [1 : 0] Prev_bank;
184    reg [1 : 0] Bank_addr;
185    reg [COL_BITS - 1 : 0] Cols_addr, Cols_brst, Cols_temp;
186    reg [ADDR_BITS - 1 : 0] Rows_addr;
187    reg [ADDR_BITS - 1 : 0] B0_row_addr;
188    reg [ADDR_BITS - 1 : 0] B1_row_addr;
189    reg [ADDR_BITS - 1 : 0] B2_row_addr;
190    reg [ADDR_BITS - 1 : 0] B3_row_addr;
191
192    // DLL Reset variable
193    reg DLL_enable;
194    reg DLL_reset;
195    reg DLL_done;
196    integer DLL_count;
197    integer aref_count;
198    integer Prech_count;
199    reg power_up_done;
200
201    // Write DQS for tDSS, tDSH, tDQSH, tDQSL checks
202    wire wdqs_valid = Write_cmnd[2] || Write_cmnd[1] || Data_in_enable;
203
204    // Commands Decode
205    wire Active_enable = ~Cs_n & ~Ras_n & Cas_n & We_n;
206    wire Aref_enable = ~Cs_n & ~Ras_n & ~Cas_n & We_n;
207    wire Burst_term = ~Cs_n & Ras_n & Cas_n & ~We_n;
208    wire Ext_mode_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n & Ba[0] & ~Ba[1];
209    wire Mode_reg_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n & ~Ba[0] & ~Ba[1];
210    wire Prech_enable = ~Cs_n & ~Ras_n & Cas_n & ~We_n;
211    wire Read_enable = ~Cs_n & Ras_n & ~Cas_n & We_n;
212    wire Write_enable = ~Cs_n & Ras_n & ~Cas_n & ~We_n;
213
214    // Burst Length Decode
215    wire [3:0] burst_length = 1 << (Mode_reg[2:0]);
216    reg [3:0] read_precharge_truncation;
217
218    // CAS Latency Decode
219// wire [2:0] cas_latency_x2 = (Mode_reg[6:4] === 3'o6) ? 5 : 2*Mode_reg[6:4];
220    wire [2:0] cas_latency_x2 = 5;
221
222    // DQS Buffer
223    assign Dqs = Dqs_out;
224
225    // DQ Buffer
226    assign Dq = Dq_out;
227
228    // Timing Check
229    time MRD_chk;
230    time RFC_chk;
231    time RRD_chk;
232    time RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3;
233    time RAP_chk0, RAP_chk1, RAP_chk2, RAP_chk3;
234    time RC_chk0, RC_chk1, RC_chk2, RC_chk3;
235    time RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3;
236    time RP_chk0, RP_chk1, RP_chk2, RP_chk3;
237    time WR_chk0, WR_chk1, WR_chk2, WR_chk3;
238
239    initial begin
240        CkeZ = 1'b0;
241        Sys_clk = 1'b0;
242        {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 4'b0000;
243        {Act_b0, Act_b1, Act_b2, Act_b3} = 4'b1111;
244        Dqs_int = 1'b0;
245        Dqs_out = {DQS_BITS{1'bz}};
246        Dq_out = {DQ_BITS{1'bz}};
247        Data_in_enable = 1'b0;
248        Data_out_enable = 1'b0;
249        DLL_enable = 1'b0;
250        DLL_reset = 1'b0;
251        DLL_done = 1'b0;
252        DLL_count = 0;
253        aref_count = 0;
254        Prech_count = 0;
255        power_up_done = 0;
256        MRD_chk = 0;
257        RFC_chk = 0;
258        RRD_chk = 0;
259        {RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3} = 0;
260        {RAP_chk0, RAP_chk1, RAP_chk2, RAP_chk3} = 0;
261        {RC_chk0, RC_chk1, RC_chk2, RC_chk3} = 0;
262        {RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3} = 0;
263        {RP_chk0, RP_chk1, RP_chk2, RP_chk3} = 0;
264        {WR_chk0, WR_chk1, WR_chk2, WR_chk3} = 0;
265        $timeformat (-9, 3, " ns", 12);
266    end
267
268    // System Clock
269    always begin
270        @ (posedge Clk) begin
271            Sys_clk = CkeZ;
272            CkeZ = Cke;
273        end
274        @ (negedge Clk) begin
275            Sys_clk = 1'b0;
276        end
277    end
278
279    // Check to make sure that we have a Deselect or NOP command on the bus when CKE is brought high
280    always @(Cke) begin
281        if (Cke === 1'b1) begin
282            if (!((Cs_n) || (~Cs_n & Ras_n & Cas_n & We_n))) begin
283                $display ("%m: at time %t MEMORY ERROR: You must have a Deselect or NOP command applied", $time);
284                $display ("%m: when the Clock Enable is brought High.");
285            end
286        end
287    end
288
289    // Check the initialization sequence
290    initial begin
291        @ (posedge Cke) begin
292            @ (posedge DLL_enable) begin
293                aref_count = 0;
294                @ (posedge DLL_reset) begin
295                    @ (Prech_count) begin
296                        if (aref_count >= 2) begin
297                            if (Debug) $display ("%m: at time %t MEMORY: Power Up and Initialization Sequence is complete", $time);
298                            power_up_done = 1;
299                        end else begin
300                            aref_count = 0;
301                            @ (aref_count >= 2) begin
302                                if (Debug) $display ("%m: at time %t MEMORY: Power Up and Initialization Sequence is complete", $time);
303                                power_up_done = 1;
304                            end
305                        end
306                    end
307                end
308            end
309        end
310    end
311
312    // Write Memory
313    task write_mem;
314        input [full_mem_bits - 1 : 0] addr;
315        input [DQ_BITS - 1 : 0] data;
316        reg [part_mem_bits : 0] i;
317        begin
318`ifdef FULL_MEM
319            mem_array[addr] = data;
320`else
321            begin : loop
322                for (i = 0; i < mem_used; i = i + 1) begin
323                    if (addr_array[i] === addr) begin
324                        disable loop;
325                    end
326                end
327            end
328            if (i === mem_used) begin
329                if (i === (1<<part_mem_bits)) begin
330                    $display ("At time %t ERROR: Memory overflow.\n Write to Address %h with Data %h will be lost.\n You must increase the part_mem_bits parameter or define FULL_MEM.", $time, addr, data);
331                end else begin
332                    mem_used = mem_used + 1;
333                    addr_array[i] = addr;
334                end
335            end
336            mem_array[i] = data;
337`endif
338        end
339    endtask
340
341    // Read Memory
342    task read_mem;
343        input [full_mem_bits - 1 : 0] addr;
344        output [DQ_BITS - 1 : 0] data;
345        reg [part_mem_bits : 0] i;
346        begin
347`ifdef FULL_MEM
348            data = mem_array[addr];
349`else
350            begin : loop
351                for (i = 0; i < mem_used; i = i + 1) begin
352                    if (addr_array[i] === addr) begin
353                        disable loop;
354                    end
355                end
356            end
357            if (i <= mem_used) begin
358                data = mem_array[i];
359            end
360`endif
361        end
362    endtask
363
364    // Burst Decode
365    task Burst_Decode;
366    begin
367
368        // Advance Burst Counter
369        if (Burst_counter < burst_length) begin
370            Burst_counter = Burst_counter + 1;
371        end
372
373        // Burst Type
374        if (Mode_reg[3] === 1'b0) begin // Sequential Burst
375            Cols_temp = Cols_addr + 1;
376        end else if (Mode_reg[3] === 1'b1) begin // Interleaved Burst
377            Cols_temp[2] = Burst_counter[2] ^ Cols_brst[2];
378            Cols_temp[1] = Burst_counter[1] ^ Cols_brst[1];
379            Cols_temp[0] = Burst_counter[0] ^ Cols_brst[0];
380        end
381
382        // Burst Length
383        if (burst_length === 2) begin
384            Cols_addr [0] = Cols_temp [0];
385        end else if (burst_length === 4) begin
386            Cols_addr [1 : 0] = Cols_temp [1 : 0];
387        end else if (burst_length === 8) begin
388            Cols_addr [2 : 0] = Cols_temp [2 : 0];
389        end else begin
390            Cols_addr = Cols_temp;
391        end
392
393        // Data Counter
394        if (Burst_counter >= burst_length) begin
395            Data_in_enable = 1'b0;
396            Data_out_enable = 1'b0;
397            read_precharge_truncation = 4'h0;
398        end
399        
400    end
401    endtask
402
403    // Manual Precharge Pipeline
404    task Manual_Precharge_Pipeline;
405    begin
406        // A10 Precharge Pipeline
407        A10_precharge[0] = A10_precharge[1];
408        A10_precharge[1] = A10_precharge[2];
409        A10_precharge[2] = A10_precharge[3];
410        A10_precharge[3] = A10_precharge[4];
411        A10_precharge[4] = A10_precharge[5];
412        A10_precharge[5] = A10_precharge[6];
413        A10_precharge[6] = 1'b0;
414
415        // Bank Precharge Pipeline
416        Bank_precharge[0] = Bank_precharge[1];
417        Bank_precharge[1] = Bank_precharge[2];
418        Bank_precharge[2] = Bank_precharge[3];
419        Bank_precharge[3] = Bank_precharge[4];
420        Bank_precharge[4] = Bank_precharge[5];
421        Bank_precharge[5] = Bank_precharge[6];
422        Bank_precharge[6] = 2'b0;
423
424        // Command Precharge Pipeline
425        Cmnd_precharge[0] = Cmnd_precharge[1];
426        Cmnd_precharge[1] = Cmnd_precharge[2];
427        Cmnd_precharge[2] = Cmnd_precharge[3];
428        Cmnd_precharge[3] = Cmnd_precharge[4];
429        Cmnd_precharge[4] = Cmnd_precharge[5];
430        Cmnd_precharge[5] = Cmnd_precharge[6];
431        Cmnd_precharge[6] = 1'b0;
432
433        // Terminate a Read if same bank or all banks
434        if (Cmnd_precharge[0] === 1'b1) begin
435            if (Bank_precharge[0] === Bank_addr || A10_precharge[0] === 1'b1) begin
436                if (Data_out_enable === 1'b1) begin
437                    Data_out_enable = 1'b0;
438                    read_precharge_truncation = 4'hF;
439                end
440            end
441        end
442    end
443    endtask
444
445    // Burst Terminate Pipeline
446    task Burst_Terminate_Pipeline;
447    begin
448        // Command Precharge Pipeline
449        Cmnd_bst[0] = Cmnd_bst[1];
450        Cmnd_bst[1] = Cmnd_bst[2];
451        Cmnd_bst[2] = Cmnd_bst[3];
452        Cmnd_bst[3] = Cmnd_bst[4];
453        Cmnd_bst[4] = Cmnd_bst[5];
454        Cmnd_bst[5] = Cmnd_bst[6];
455        Cmnd_bst[6] = 1'b0;
456
457        // Terminate a Read regardless of banks
458        if (Cmnd_bst[0] === 1'b1 && Data_out_enable === 1'b1) begin
459            Data_out_enable = 1'b0;
460        end
461    end
462    endtask
463
464    // Dq and Dqs Drivers
465    task Dq_Dqs_Drivers;
466    begin
467        // read command pipeline
468        Read_cmnd [0] = Read_cmnd [1];
469        Read_cmnd [1] = Read_cmnd [2];
470        Read_cmnd [2] = Read_cmnd [3];
471        Read_cmnd [3] = Read_cmnd [4];
472        Read_cmnd [4] = Read_cmnd [5];
473        Read_cmnd [5] = Read_cmnd [6];
474        Read_cmnd [6] = 1'b0;
475
476        // read bank pipeline
477        Read_bank [0] = Read_bank [1];
478        Read_bank [1] = Read_bank [2];
479        Read_bank [2] = Read_bank [3];
480        Read_bank [3] = Read_bank [4];
481        Read_bank [4] = Read_bank [5];
482        Read_bank [5] = Read_bank [6];
483        Read_bank [6] = 2'b0;
484
485        // read column pipeline
486        Read_cols [0] = Read_cols [1];
487        Read_cols [1] = Read_cols [2];
488        Read_cols [2] = Read_cols [3];
489        Read_cols [3] = Read_cols [4];
490        Read_cols [4] = Read_cols [5];
491        Read_cols [5] = Read_cols [6];
492        Read_cols [6] = 0;
493
494        // Initialize Read command
495        if (Read_cmnd [0] === 1'b1) begin
496            Data_out_enable = 1'b1;
497            Bank_addr = Read_bank [0];
498            Cols_addr = Read_cols [0];
499            Cols_brst = Cols_addr [2 : 0];
500            Burst_counter = 0;
501
502            // Row Address Mux
503            case (Bank_addr)
504                2'd0 : Rows_addr = B0_row_addr;
505                2'd1 : Rows_addr = B1_row_addr;
506                2'd2 : Rows_addr = B2_row_addr;
507                2'd3 : Rows_addr = B3_row_addr;
508                default : $display ("At time %t ERROR: Invalid Bank Address", $time);
509            endcase
510        end
511
512        // Toggle Dqs during Read command
513        if (Data_out_enable === 1'b1) begin
514            Dqs_int = 1'b0;
515            if (Dqs_out === {DQS_BITS{1'b0}}) begin
516                Dqs_out = {DQS_BITS{1'b1}};
517            end else if (Dqs_out === {DQS_BITS{1'b1}}) begin
518                Dqs_out = {DQS_BITS{1'b0}};
519            end else begin
520                Dqs_out = {DQS_BITS{1'b0}};
521            end
522        end else if (Data_out_enable === 1'b0 && Dqs_int === 1'b0) begin
523            Dqs_out = {DQS_BITS{1'bz}};
524        end
525
526        // Initialize dqs for Read command
527        if (Read_cmnd [2] === 1'b1) begin
528            if (Data_out_enable === 1'b0) begin
529                Dqs_int = 1'b1;
530                Dqs_out = {DQS_BITS{1'b0}};
531            end
532        end
533
534        // Read latch
535        if (Data_out_enable === 1'b1) begin
536            // output data
537            read_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_out);
538            if (Debug) begin
539                $display ("At time %t READ : Bank = %h, Row = %h, Col = %h, Data = %h", $time, Bank_addr, Rows_addr, Cols_addr, Dq_out);
540            end
541        end else begin
542            Dq_out = {DQ_BITS{1'bz}};
543        end
544    end
545    endtask
546
547    // Write FIFO and DM Mask Logic
548    task Write_FIFO_DM_Mask_Logic;
549    begin
550        // Write command pipeline
551        Write_cmnd [0] = Write_cmnd [1];
552        Write_cmnd [1] = Write_cmnd [2];
553        Write_cmnd [2] = Write_cmnd [3];
554        Write_cmnd [3] = 1'b0;
555
556        // Write command pipeline
557        Write_bank [0] = Write_bank [1];
558        Write_bank [1] = Write_bank [2];
559        Write_bank [2] = Write_bank [3];
560        Write_bank [3] = 2'b0;
561
562        // Write column pipeline
563        Write_cols [0] = Write_cols [1];
564        Write_cols [1] = Write_cols [2];
565        Write_cols [2] = Write_cols [3];
566        Write_cols [3] = {COL_BITS{1'b0}};
567
568        // Initialize Write command
569        if (Write_cmnd [0] === 1'b1) begin
570            Data_in_enable = 1'b1;
571            Bank_addr = Write_bank [0];
572            Cols_addr = Write_cols [0];
573            Cols_brst = Cols_addr [2 : 0];
574            Burst_counter = 0;
575
576            // Row address mux
577            case (Bank_addr)
578                2'd0 : Rows_addr = B0_row_addr;
579                2'd1 : Rows_addr = B1_row_addr;
580                2'd2 : Rows_addr = B2_row_addr;
581                2'd3 : Rows_addr = B3_row_addr;
582                default : $display ("At time %t ERROR: Invalid Row Address", $time);
583            endcase
584        end
585
586        // Write data
587        if (Data_in_enable === 1'b1) begin
588
589            // Data Buffer
590            read_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_buf);
591
592            // write negedge Dqs on posedge Sys_clk
593            if (Sys_clk) begin
594                if (!dm_fall[0]) begin
595                    Dq_buf [ 7 : 0] = dq_fall [ 7 : 0];
596                end
597                if (!dm_fall[1]) begin
598                    Dq_buf [15 : 8] = dq_fall [15 : 8];
599                end
600                if (~&dm_fall) begin
601                    if (Debug) begin
602                        $display ("At time %t WRITE: Bank = %h, Row = %h, Col = %h, Data = %h", $time, Bank_addr, Rows_addr, Cols_addr, Dq_buf[DQ_BITS-1:0]);
603                    end
604                end
605            // write posedge Dqs on negedge Sys_clk
606            end else begin
607                if (!dm_rise[0]) begin
608                    Dq_buf [ 7 : 0] = dq_rise [ 7 : 0];
609                end
610                if (!dm_rise[1]) begin
611                    Dq_buf [15 : 8] = dq_rise [15 : 8];
612                end
613                if (~&dm_rise) begin
614                    if (Debug) begin
615                        $display ("At time %t WRITE: Bank = %h, Row = %h, Col = %h, Data = %h", $time, Bank_addr, Rows_addr, Cols_addr, Dq_buf[DQ_BITS-1:0]);
616                    end
617                end
618            end
619
620            // Write Data
621            write_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_buf);
622
623            // tWR start and tWTR check
624            if (Sys_clk && &dm_pair === 1'b0) begin
625                case (Bank_addr)
626                    2'd0 : WR_chk0 = $time;
627                    2'd1 : WR_chk1 = $time;
628                    2'd2 : WR_chk2 = $time;
629                    2'd3 : WR_chk3 = $time;
630                    default : $display ("At time %t ERROR: Invalid Bank Address (tWR)", $time);
631                endcase
632
633                // tWTR check
634                if (Read_enable === 1'b1) begin
635                    $display ("At time %t ERROR: tWTR violation during Read", $time);
636                end
637            end
638        end
639    end
640    endtask
641
642    // Auto Precharge Calculation
643    task Auto_Precharge_Calculation;
644    begin
645        // Precharge counter
646        if (Read_precharge [0] === 1'b1 || Write_precharge [0] === 1'b1) begin
647            Count_precharge [0] = Count_precharge [0] + 1;
648        end
649        if (Read_precharge [1] === 1'b1 || Write_precharge [1] === 1'b1) begin
650            Count_precharge [1] = Count_precharge [1] + 1;
651        end
652        if (Read_precharge [2] === 1'b1 || Write_precharge [2] === 1'b1) begin
653            Count_precharge [2] = Count_precharge [2] + 1;
654        end
655        if (Read_precharge [3] === 1'b1 || Write_precharge [3] === 1'b1) begin
656            Count_precharge [3] = Count_precharge [3] + 1;
657        end
658
659        // Read with AutoPrecharge Calculation
660        // The device start internal precharge when:
661        // 1. Meet tRAS requirement
662        // 2. BL/2 cycles after command
663        if ((Read_precharge[0] === 1'b1) && ($time - RAS_chk0 >= tRAS)) begin
664            if (Count_precharge[0] >= burst_length/2) begin
665                Pc_b0 = 1'b1;
666                Act_b0 = 1'b0;
667                RP_chk0 = $time;
668                Read_precharge[0] = 1'b0;
669            end
670        end
671        if ((Read_precharge[1] === 1'b1) && ($time - RAS_chk1 >= tRAS)) begin
672            if (Count_precharge[1] >= burst_length/2) begin
673                Pc_b1 = 1'b1;
674                Act_b1 = 1'b0;
675                RP_chk1 = $time;
676                Read_precharge[1] = 1'b0;
677            end
678        end
679        if ((Read_precharge[2] === 1'b1) && ($time - RAS_chk2 >= tRAS)) begin
680            if (Count_precharge[2] >= burst_length/2) begin
681                Pc_b2 = 1'b1;
682                Act_b2 = 1'b0;
683                RP_chk2 = $time;
684                Read_precharge[2] = 1'b0;
685            end
686        end
687        if ((Read_precharge[3] === 1'b1) && ($time - RAS_chk3 >= tRAS)) begin
688            if (Count_precharge[3] >= burst_length/2) begin
689                Pc_b3 = 1'b1;
690                Act_b3 = 1'b0;
691                RP_chk3 = $time;
692                Read_precharge[3] = 1'b0;
693            end
694        end
695
696        // Write with AutoPrecharge Calculation
697        // The device start internal precharge when:
698        // 1. Meet tRAS requirement
699        // 2. Write Latency PLUS BL/2 cycles PLUS tWR after Write command
700
701        if ((Write_precharge[0] === 1'b1) && ($time - RAS_chk0 >= tRAS)) begin
702            if ((Count_precharge[0] >= burst_length/2+1) && ($time - WR_chk0 >= tWR)) begin
703                Pc_b0 = 1'b1;
704                Act_b0 = 1'b0;
705                RP_chk0 = $time;
706                Write_precharge[0] = 1'b0;
707            end
708        end
709        if ((Write_precharge[1] === 1'b1) && ($time - RAS_chk1 >= tRAS)) begin
710            if ((Count_precharge[1] >= burst_length/2+1) && ($time - WR_chk1 >= tWR)) begin
711                Pc_b1 = 1'b1;
712                Act_b1 = 1'b0;
713                RP_chk1 = $time;
714                Write_precharge[1] = 1'b0;
715            end
716        end
717        if ((Write_precharge[2] === 1'b1) && ($time - RAS_chk2 >= tRAS)) begin
718            if ((Count_precharge[2] >= burst_length/2+1) && ($time - WR_chk2 >= tWR)) begin
719                Pc_b2 = 1'b1;
720                Act_b2 = 1'b0;
721                RP_chk2 = $time;
722                Write_precharge[2] = 1'b0;
723            end
724        end
725        if ((Write_precharge[3] === 1'b1) && ($time - RAS_chk3 >= tRAS)) begin
726            if ((Count_precharge[3] >= burst_length/2+1) && ($time - WR_chk3 >= tWR)) begin
727                Pc_b3 = 1'b1;
728                Act_b3 = 1'b0;
729                RP_chk3 = $time;
730                Write_precharge[3] = 1'b0;
731            end
732        end
733    end
734    endtask
735
736    // DLL Counter
737    task DLL_Counter;
738    begin
739        if (DLL_reset === 1'b1 && DLL_done === 1'b0) begin
740            DLL_count = DLL_count + 1;
741            if (DLL_count >= 200) begin
742                DLL_done = 1'b1;
743            end
744        end
745    end
746    endtask
747
748    // Control Logic
749    task Control_Logic;
750    begin
751        // Auto Refresh
752        if (Aref_enable === 1'b1) begin
753            // Display Debug Message
754            if (Debug) begin
755                $display ("At time %t AREF : Auto Refresh", $time);
756            end
757            
758            // Precharge to Auto Refresh
759            if (($time - RP_chk0 < tRP) || ($time - RP_chk1 < tRP) ||
760                ($time - RP_chk2 < tRP) || ($time - RP_chk3 < tRP)) begin
761                $display ("At time %t ERROR: tRP violation during Auto Refresh", $time);
762            end
763            
764            // LMR/EMR to Auto Refresh
765            if ($time - MRD_chk < tMRD) begin
766                $display ("At time %t ERROR: tMRD violation during Auto Refresh", $time);
767            end
768
769            // Auto Refresh to Auto Refresh
770            if ($time - RFC_chk < tRFC) begin
771                $display ("At time %t ERROR: tRFC violation during Auto Refresh", $time);
772            end
773            
774            // Precharge to Auto Refresh
775            if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin
776                $display ("At time %t ERROR: All banks must be Precharged before Auto Refresh", $time);
777                if (!no_halt) $stop (0);
778            end else begin
779                aref_count = aref_count + 1;
780                RFC_chk = $time;
781            end
782        end
783    
784        // Extended Mode Register
785        if (Ext_mode_enable === 1'b1) begin
786            if (Debug) begin
787                $display ("At time %t EMR : Extended Mode Register", $time);
788            end
789
790            // Precharge to LMR/EMR
791            if (($time - RP_chk0 < tRP) || ($time - RP_chk1 < tRP) ||
792                ($time - RP_chk2 < tRP) || ($time - RP_chk3 < tRP)) begin
793                $display ("At time %t ERROR: tRP violation during Extended Mode Register", $time);
794            end
795
796            // LMR/EMR to LMR/EMR
797            if ($time - MRD_chk < tMRD) begin
798                $display ("At time %t ERROR: tMRD violation during Extended Mode Register", $time);
799            end
800
801            // Auto Refresh to LMR/EMR
802            if ($time - RFC_chk < tRFC) begin
803                $display ("At time %t ERROR: tRFC violation during Extended Mode Register", $time);
804            end
805
806            // Precharge to LMR/EMR
807            if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin
808                $display ("At time %t ERROR: all banks must be Precharged before Extended Mode Register", $time);
809                if (!no_halt) $stop (0);
810            end else begin
811                if (Addr[0] === 1'b0) begin
812                    DLL_enable = 1'b1;
813                    if (Debug) begin
814                        $display ("At time %t EMR : Enable DLL", $time);
815                    end
816                end else begin
817                    DLL_enable = 1'b0;
818                    if (Debug) begin
819                        $display ("At time %t EMR : Disable DLL", $time);
820                    end
821                end
822                MRD_chk = $time;
823            end
824        end
825    
826        // Load Mode Register
827        if (Mode_reg_enable === 1'b1) begin
828            if (Debug) begin
829                $display ("At time %t LMR : Load Mode Register", $time);
830            end
831
832            // Precharge to LMR/EMR
833            if (($time - RP_chk0 < tRP) || ($time - RP_chk1 < tRP) ||
834                ($time - RP_chk2 < tRP) || ($time - RP_chk3 < tRP)) begin
835                $display ("At time %t ERROR: tRP violation during Load Mode Register", $time);
836            end
837
838            // LMR/EMR to LMR/EMR
839            if ($time - MRD_chk < tMRD) begin
840                $display ("At time %t ERROR: tMRD violation during Load Mode Register", $time);
841            end
842
843            // Auto Refresh to LMR/EMR
844            if ($time - RFC_chk < tRFC) begin
845                $display ("At time %t ERROR: tRFC violation during Load Mode Register", $time);
846            end
847
848            // Precharge to LMR/EMR
849            if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin
850                $display ("At time %t ERROR: all banks must be Precharged before Load Mode Register", $time);
851            end else begin
852                // Register Mode
853                Mode_reg = Addr;
854
855                // DLL Reset
856                if (DLL_enable === 1'b1 && Addr [8] === 1'b1) begin
857                    DLL_reset = 1'b1;
858                    DLL_done = 1'b0;
859                    DLL_count = 0;
860                end else if (DLL_enable === 1'b1 && DLL_reset === 1'b0 && Addr [8] === 1'b0) begin
861                    $display ("At time %t ERROR: DLL is ENABLE: DLL RESET is required.", $time);
862                end else if (DLL_enable === 1'b0 && Addr [8] === 1'b1) begin
863                    $display ("At time %t ERROR: DLL is DISABLE: DLL RESET will be ignored.", $time);
864                end
865
866                // Burst Length
867                case (Addr [2 : 0])
868                    3'b001 : $display ("At time %t LMR : Burst Length = 2", $time);
869                    3'b010 : $display ("At time %t LMR : Burst Length = 4", $time);
870                    3'b011 : $display ("At time %t LMR : Burst Length = 8", $time);
871                    default : $display ("At time %t ERROR: Burst Length not supported", $time);
872                endcase
873
874                // CAS Latency
875                case (Addr [6 : 4])
876                    3'b010 : $display ("At time %t LMR : CAS Latency = 2", $time);
877                    3'b110 : $display ("At time %t LMR : CAS Latency = 2.5", $time);
878                    3'b011 : $display ("At time %t LMR : CAS Latency = 3", $time);
879                    default : $display ("At time %t ERROR: CAS Latency not supported", $time);
880                endcase
881
882                // Record current tMRD time
883                MRD_chk = $time;
884            end
885        end
886
887        // Activate Block
888        if (Active_enable === 1'b1) begin
889            if (!(power_up_done)) begin
890                $display ("%m: at time %t ERROR: Power Up and Initialization Sequence not completed before executing Activate command", $time);
891            end
892            // Display Debug Message
893            if (Debug) begin
894                $display ("At time %t ACT : Bank = %h, Row = %h", $time, Ba, Addr);
895            end
896
897            // Activate to Activate (different bank)
898            if ((Prev_bank != Ba) && ($time - RRD_chk < tRRD)) begin
899                $display ("At time %t ERROR: tRRD violation during Activate bank %h", $time, Ba);
900            end
901            
902            // LMR/EMR to Activate
903            if ($time - MRD_chk < tMRD) begin
904                $display ("At time %t ERROR: tMRD violation during Activate bank %h", $time, Ba);
905            end
906
907            // AutoRefresh to Activate
908            if ($time - RFC_chk < tRFC) begin
909                $display ("At time %t ERROR: tRFC violation during Activate bank %h", $time, Ba);
910            end
911
912            // Precharge to Activate
913            if ((Ba === 2'b00 && Pc_b0 === 1'b0) || (Ba === 2'b01 && Pc_b1 === 1'b0) ||
914                (Ba === 2'b10 && Pc_b2 === 1'b0) || (Ba === 2'b11 && Pc_b3 === 1'b0)) begin
915                $display ("At time %t ERROR: Bank = %h is already activated - Command Ignored", $time, Ba);
916                if (!no_halt) $stop (0);
917            end else begin
918                // Activate Bank 0
919                if (Ba === 2'b00 && Pc_b0 === 1'b1) begin
920                    // Activate to Activate (same bank)
921                    if ($time - RC_chk0 < tRC) begin
922                        $display ("At time %t ERROR: tRC violation during Activate bank %h", $time, Ba);
923                    end
924
925                    // Precharge to Activate
926                    if ($time - RP_chk0 < tRP) begin
927                        $display ("At time %t ERROR: tRP violation during Activate bank %h", $time, Ba);
928                    end
929
930                    // Record variables for checking violation
931                    Act_b0 = 1'b1;
932                    Pc_b0 = 1'b0;
933                    B0_row_addr = Addr;
934                    RC_chk0 = $time;
935                    RCD_chk0 = $time;
936                    RAS_chk0 = $time;
937                    RAP_chk0 = $time;
938                end
939
940                // Activate Bank 1
941                if (Ba === 2'b01 && Pc_b1 === 1'b1) begin
942                    // Activate to Activate (same bank)
943                    if ($time - RC_chk1 < tRC) begin
944                        $display ("At time %t ERROR: tRC violation during Activate bank %h", $time, Ba);
945                    end
946
947                    // Precharge to Activate
948                    if ($time - RP_chk1 < tRP) begin
949                        $display ("At time %t ERROR: tRP violation during Activate bank %h", $time, Ba);
950                    end
951
952                    // Record variables for checking violation
953                    Act_b1 = 1'b1;
954                    Pc_b1 = 1'b0;
955                    B1_row_addr = Addr;
956                    RC_chk1 = $time;
957                    RCD_chk1 = $time;
958                    RAS_chk1 = $time;
959                    RAP_chk1 = $time;
960                end
961
962                // Activate Bank 2
963                if (Ba === 2'b10 && Pc_b2 === 1'b1) begin
964                    // Activate to Activate (same bank)
965                    if ($time - RC_chk2 < tRC) begin
966                        $display ("At time %t ERROR: tRC violation during Activate bank %h", $time, Ba);
967                    end
968
969                    // Precharge to Activate
970                    if ($time - RP_chk2 < tRP) begin
971                        $display ("At time %t ERROR: tRP violation during Activate bank %h", $time, Ba);
972                    end
973
974                    // Record variables for checking violation
975                    Act_b2 = 1'b1;
976                    Pc_b2 = 1'b0;
977                    B2_row_addr = Addr;
978                    RC_chk2 = $time;
979                    RCD_chk2 = $time;
980                    RAS_chk2 = $time;
981                    RAP_chk2 = $time;
982                end
983
984                // Activate Bank 3
985                if (Ba === 2'b11 && Pc_b3 === 1'b1) begin
986                    // Activate to Activate (same bank)
987                    if ($time - RC_chk3 < tRC) begin
988                        $display ("At time %t ERROR: tRC violation during Activate bank %h", $time, Ba);
989                    end
990
991                    // Precharge to Activate
992                    if ($time - RP_chk3 < tRP) begin
993                        $display ("At time %t ERROR: tRP violation during Activate bank %h", $time, Ba);
994                    end
995
996                    // Record variables for checking violation
997                    Act_b3 = 1'b1;
998                    Pc_b3 = 1'b0;
999                    B3_row_addr = Addr;
1000                    RC_chk3 = $time;
1001                    RCD_chk3 = $time;
1002                    RAS_chk3 = $time;
1003                    RAP_chk3 = $time;
1004                end
1005                // Record variable for checking violation
1006                RRD_chk = $time;
1007                Prev_bank = Ba;
1008                read_precharge_truncation[Ba] = 1'b0;
1009            end
1010        end
1011    
1012        // Precharge Block - consider NOP if bank already precharged or in process of precharging
1013        if (Prech_enable === 1'b1) begin
1014            // Display Debug Message
1015            if (Debug) begin
1016                $display ("At time %t PRE : Addr[10] = %b, Bank = %b", $time, Addr[10], Ba);
1017            end
1018
1019            // LMR/EMR to Precharge
1020            if ($time - MRD_chk < tMRD) begin
1021                $display ("At time %t ERROR: tMRD violation during Precharge", $time);
1022            end
1023
1024            // AutoRefresh to Precharge
1025            if ($time - RFC_chk < tRFC) begin
1026                $display ("At time %t ERROR: tRFC violation during Precharge", $time);
1027            end
1028
1029            // Precharge bank 0
1030            if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b00)) && Act_b0 === 1'b1) begin
1031                Act_b0 = 1'b0;
1032                Pc_b0 = 1'b1;
1033                RP_chk0 = $time;
1034                
1035                // Activate to Precharge Bank
1036                if ($time - RAS_chk0 < tRAS) begin
1037                    $display ("At time %t ERROR: tRAS violation during Precharge", $time);
1038                end
1039                
1040                // tWR violation check for Write
1041                if ($time - WR_chk0 < tWR) begin
1042                    $display ("At time %t ERROR: tWR violation during Precharge", $time);
1043                end
1044            end
1045
1046            // Precharge bank 1
1047            if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b01)) && Act_b1 === 1'b1) begin
1048                Act_b1 = 1'b0;
1049                Pc_b1 = 1'b1;
1050                RP_chk1 = $time;
1051
1052                // Activate to Precharge Bank 1
1053                if ($time - RAS_chk1 < tRAS) begin
1054                    $display ("At time %t ERROR: tRAS violation during Precharge", $time);
1055                end
1056                
1057                // tWR violation check for Write
1058                if ($time - WR_chk1 < tWR) begin
1059                    $display ("At time %t ERROR: tWR violation during Precharge", $time);
1060                end
1061            end
1062
1063            // Precharge bank 2
1064            if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b10)) && Act_b2 === 1'b1) begin
1065                Act_b2 = 1'b0;
1066                Pc_b2 = 1'b1;
1067                RP_chk2 = $time;
1068                
1069                // Activate to Precharge Bank 2
1070                if ($time - RAS_chk2 < tRAS) begin
1071                    $display ("At time %t ERROR: tRAS violation during Precharge", $time);
1072                end
1073                
1074                // tWR violation check for Write
1075                if ($time - WR_chk2 < tWR) begin
1076                    $display ("At time %t ERROR: tWR violation during Precharge", $time);
1077                end
1078            end
1079
1080            // Precharge bank 3
1081            if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b11)) && Act_b3 === 1'b1) begin
1082                Act_b3 = 1'b0;
1083                Pc_b3 = 1'b1;
1084                RP_chk3 = $time;
1085                
1086                // Activate to Precharge Bank 3
1087                if ($time - RAS_chk3 < tRAS) begin
1088                    $display ("At time %t ERROR: tRAS violation during Precharge", $time);
1089                end
1090                
1091                // tWR violation check for Write
1092                if ($time - WR_chk3 < tWR) begin
1093                    $display ("At time %t ERROR: tWR violation during Precharge", $time);
1094                end
1095            end
1096
1097            // Prech_count is to make sure we have met part of the initialization sequence
1098            Prech_count = Prech_count + 1;
1099
1100            // Pipeline for READ
1101            A10_precharge [cas_latency_x2] = Addr[10];
1102            Bank_precharge[cas_latency_x2] = Ba;
1103            Cmnd_precharge[cas_latency_x2] = 1'b1;
1104        end
1105    
1106        // Burst terminate
1107        if (Burst_term === 1'b1) begin
1108            // Display Debug Message
1109            if (Debug) begin
1110                $display ("At time %t BST : Burst Terminate",$time);
1111            end
1112
1113            if (Data_in_enable === 1'b1) begin
1114                // Illegal to burst terminate a Write
1115                $display ("At time %t ERROR: It's illegal to burst terminate a Write", $time);
1116                if (!no_halt) $stop (0);
1117            end else if (Read_precharge[0] === 1'b1 || Read_precharge[1] === 1'b1 ||
1118                // Illegal to burst terminate a Read with Auto Precharge
1119                Read_precharge[2] === 1'b1 || Read_precharge[3] === 1'b1) begin
1120                $display ("At time %t ERROR: It's illegal to burst terminate a Read with Auto Precharge", $time);
1121                if (!no_halt) $stop (0);
1122            end else begin
1123                // Burst Terminate Command Pipeline for Read
1124                Cmnd_bst[cas_latency_x2] = 1'b1;
1125            end
1126
1127        end
1128        
1129        // Read Command
1130        if (Read_enable === 1'b1) begin
1131            if (!(power_up_done)) begin
1132                $display ("%m: at time %t ERROR: Power Up and Initialization Sequence not completed before executing Read Command", $time);
1133            end
1134            // Check for DLL reset before Read
1135            if (DLL_reset === 1 && DLL_done === 0) begin
1136                $display ("%m: at time %t ERROR: You need to wait 200 tCK after DLL Reset Enable to Read, Not %0d clocks.", $time, DLL_count);
1137            end
1138            // Display Debug Message
1139            if (Debug) begin
1140                $display ("At time %t READ : Bank = %h, Col = %h", $time, Ba, {Addr [11], Addr [9 : 0]});
1141            end
1142
1143            // Terminate a Write
1144            if (Data_in_enable === 1'b1) begin
1145                Data_in_enable = 1'b0;
1146            end
1147
1148            // Activate to Read without Auto Precharge
1149            if ((Addr [10] === 1'b0 && Ba === 2'b00 && $time - RCD_chk0 < tRCD) ||
1150                (Addr [10] === 1'b0 && Ba === 2'b01 && $time - RCD_chk1 < tRCD) ||
1151                (Addr [10] === 1'b0 && Ba === 2'b10 && $time - RCD_chk2 < tRCD) ||
1152                (Addr [10] === 1'b0 && Ba === 2'b11 && $time - RCD_chk3 < tRCD)) begin
1153                $display("At time %t ERROR: tRCD violation during Read", $time);
1154            end
1155
1156            // Activate to Read with Auto Precharge
1157            if ((Addr [10] === 1'b1 && Ba === 2'b00 && $time - RAP_chk0 < tRAP) ||
1158                (Addr [10] === 1'b1 && Ba === 2'b01 && $time - RAP_chk1 < tRAP) ||
1159                (Addr [10] === 1'b1 && Ba === 2'b10 && $time - RAP_chk2 < tRAP) ||
1160                (Addr [10] === 1'b1 && Ba === 2'b11 && $time - RAP_chk3 < tRAP)) begin
1161                $display ("At time %t ERROR: tRAP violation during Read", $time);
1162            end
1163
1164            // Interrupt a Read with Auto Precharge (same bank only)
1165            if (Read_precharge [Ba] === 1'b1) begin
1166                $display ("At time %t ERROR: It's illegal to interrupt a Read with Auto Precharge", $time);
1167                if (!no_halt) $stop (0);
1168                // Cancel Auto Precharge
1169                if (Addr[10] === 1'b0) begin
1170                    Read_precharge [Ba]= 1'b0;
1171                end
1172            end
1173            // Activate to Read
1174            if ((Ba === 2'b00 && Pc_b0 === 1'b1) || (Ba === 2'b01 && Pc_b1 === 1'b1) ||
1175                (Ba === 2'b10 && Pc_b2 === 1'b1) || (Ba === 2'b11 && Pc_b3 === 1'b1)) begin
1176                $display("At time %t ERROR: Bank is not Activated for Read", $time);
1177                if (!no_halt) $stop (0);
1178            end else begin
1179                // CAS Latency pipeline
1180                Read_cmnd[cas_latency_x2] = 1'b1;
1181                Read_bank[cas_latency_x2] = Ba;
1182                Read_cols[cas_latency_x2] = {Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]};
1183                // Auto Precharge
1184                if (Addr[10] === 1'b1) begin
1185                    Read_precharge [Ba]= 1'b1;
1186                    Count_precharge [Ba]= 0;
1187                end
1188            end
1189        end
1190
1191        // Write Command
1192        if (Write_enable === 1'b1) begin
1193            if (!(power_up_done)) begin
1194                $display ("%m: at time %t ERROR: Power Up and Initialization Sequence not completed before executing Write Command", $time);
1195                if (!no_halt) $stop (0);
1196            end
1197            // display debug message
1198            if (Debug) begin
1199                $display ("At time %t WRITE: Bank = %h, Col = %h", $time, Ba, {Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]});
1200            end
1201
1202            // Activate to Write
1203            if ((Ba === 2'b00 && $time - RCD_chk0 < tRCD) ||
1204                (Ba === 2'b01 && $time - RCD_chk1 < tRCD) ||
1205                (Ba === 2'b10 && $time - RCD_chk2 < tRCD) ||
1206                (Ba === 2'b11 && $time - RCD_chk3 < tRCD)) begin
1207                $display("At time %t ERROR: tRCD violation during Write to Bank %h", $time, Ba);
1208            end
1209
1210            // Read to Write
1211            if (Read_cmnd[0] || Read_cmnd[1] || Read_cmnd[2] || Read_cmnd[3] ||
1212                Read_cmnd[4] || Read_cmnd[5] || Read_cmnd[6] || (Burst_counter < burst_length)) begin
1213                if (Data_out_enable || read_precharge_truncation[Ba]) begin
1214                    $display("At time %t ERROR: Read to Write violation", $time);
1215                end
1216            end
1217            
1218            // Interrupt a Write with Auto Precharge (same bank only)
1219            if (Write_precharge [Ba] === 1'b1) begin
1220                $display ("At time %t ERROR: it's illegal to interrupt a Write with Auto Precharge", $time);
1221                if (!no_halt) $stop (0);
1222                // Cancel Auto Precharge
1223                if (Addr[10] === 1'b0) begin
1224                    Write_precharge [Ba]= 1'b0;
1225                end
1226            end
1227            // Activate to Write
1228            if ((Ba === 2'b00 && Pc_b0 === 1'b1) || (Ba === 2'b01 && Pc_b1 === 1'b1) ||
1229                (Ba === 2'b10 && Pc_b2 === 1'b1) || (Ba === 2'b11 && Pc_b3 === 1'b1)) begin
1230                $display("At time %t ERROR: Bank is not Activated for Write", $time);
1231                if (!no_halt) $stop (0);
1232            end else begin
1233                // Pipeline for Write
1234                Write_cmnd [3] = 1'b1;
1235                Write_bank [3] = Ba;
1236                Write_cols [3] = {Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]};
1237                // Auto Precharge
1238                if (Addr[10] === 1'b1) begin
1239                    Write_precharge [Ba]= 1'b1;
1240                    Count_precharge [Ba]= 0;
1241                end
1242            end
1243        end
1244    end
1245    endtask
1246
1247    task check_neg_dqs;
1248    begin
1249        if (Write_cmnd[2] || Write_cmnd[1] || Data_in_enable) begin
1250            for (i=0; i<DQS_BITS; i=i+1) begin
1251                if (expect_neg_dqs[i]) begin
1252                    $display ("At time %t ERROR: Negative DQS[%1d] transition required.", $time, i);
1253                end
1254                expect_neg_dqs[i] = 1'b1;
1255            end
1256        end else begin
1257            expect_pos_dqs = 0;
1258            expect_neg_dqs = 0;
1259        end
1260    end
1261    endtask
1262
1263    task check_pos_dqs;
1264    begin
1265        if (Write_cmnd[2] || Write_cmnd[1] || Data_in_enable) begin
1266            for (i=0; i<DQS_BITS; i=i+1) begin
1267                if (expect_pos_dqs[i]) begin
1268                    $display ("At time %t ERROR: Positive DQS[%1d] transition required.", $time, i);
1269                end
1270                expect_pos_dqs[i] = 1'b1;
1271            end
1272        end else begin
1273            expect_pos_dqs = 0;
1274            expect_neg_dqs = 0;
1275        end
1276    end
1277    endtask
1278
1279    // Main Logic
1280    always @ (posedge Sys_clk) begin
1281        Manual_Precharge_Pipeline;
1282        Burst_Terminate_Pipeline;
1283        Dq_Dqs_Drivers;
1284        Write_FIFO_DM_Mask_Logic;
1285        Burst_Decode;
1286        check_neg_dqs;
1287        Auto_Precharge_Calculation;
1288        DLL_Counter;
1289        Control_Logic;
1290    end
1291
1292    always @ (negedge Sys_clk) begin
1293        Manual_Precharge_Pipeline;
1294        Burst_Terminate_Pipeline;
1295        Dq_Dqs_Drivers;
1296        Write_FIFO_DM_Mask_Logic;
1297        Burst_Decode;
1298        check_pos_dqs;
1299    end
1300
1301    // Dqs Receiver
1302    always @ (posedge Dqs_in[0]) begin
1303        // Latch data at posedge Dqs
1304        dq_rise[7 : 0] = Dq_in[7 : 0];
1305        dm_rise[0] = Dm_in[0];
1306        expect_pos_dqs[0] = 0;
1307    end
1308
1309    always @ (posedge Dqs_in[1]) begin
1310        // Latch data at posedge Dqs
1311        dq_rise[15 : 8] = Dq_in[15 : 8];
1312        dm_rise[1] = Dm_in [1];
1313        expect_pos_dqs[1] = 0;
1314    end
1315
1316    always @ (negedge Dqs_in[0]) begin
1317        // Latch data at negedge Dqs
1318        dq_fall[7 : 0] = Dq_in[7 : 0];
1319        dm_fall[0] = Dm_in[0];
1320        dm_pair[1:0] = {dm_rise[0], dm_fall[0]};
1321        expect_neg_dqs[0] = 0;
1322    end
1323
1324    always @ (negedge Dqs_in[1]) begin
1325        // Latch data at negedge Dqs
1326        dq_fall[15: 8] = Dq_in[15 : 8];
1327        dm_fall[1] = Dm_in[1];
1328        dm_pair[3:2] = {dm_rise[1], dm_fall[1]};
1329        expect_neg_dqs[1] = 0;
1330    end
1331
1332    specify
1333                                              // SYMBOL UNITS DESCRIPTION
1334                                              // ------ ----- -----------
1335//`ifdef sg5B // specparams for -5B (CL = 3)
1336// specparam tDSS = 1.0; // tDSS ns DQS falling edge to CLK rising (setup time) = 0.2*tCK
1337// specparam tDSH = 1.0; // tDSH ns DQS falling edge from CLK rising (hold time) = 0.2*tCK
1338// specparam tIH = 0.600; // tIH ns Input Hold Time
1339// specparam tIS = 0.600; // tIS ns Input Setup Time
1340// specparam tDQSH = 1.75; // tDQSH ns DQS input High Pulse Width = 0.35*tCK
1341// specparam tDQSL = 1.75; // tDQSL ns DQS input Low Pulse Width = 0.35*tCK
1342//`else `ifdef sg6 // specparams for -6 (CL = 2.5)
1343        specparam tDSS = 1.2; // tDSS ns DQS falling edge to CLK rising (setup time) = 0.2*tCK
1344        specparam tDSH = 1.2; // tDSH ns DQS falling edge from CLK rising (hold time) = 0.2*tCK
1345        specparam tIH = 0.750; // tIH ns Input Hold Time
1346        specparam tIS = 0.750; // tIS ns Input Setup Time
1347        specparam tDQSH = 2.1; // tDQSH ns DQS input High Pulse Width = 0.35*tCK
1348        specparam tDQSL = 2.1; // tDQSL ns DQS input Low Pulse Width = 0.35*tCK
1349//`else `ifdef sg75E // specparams for -75E (CL = 2)
1350// specparam tDSS = 1.5; // tDSS ns DQS falling edge to CLK rising (setup time) = 0.2*tCK
1351// specparam tDSH = 1.5; // tDSH ns DQS falling edge from CLK rising (hold time) = 0.2*tCK
1352// specparam tIH = 0.900; // tIH ns Input Hold Time
1353// specparam tIS = 0.900; // tIS ns Input Setup Time
1354// specparam tDQSH = 2.625; // tDQSH ns DQS input High Pulse Width = 0.35*tCK
1355// specparam tDQSL = 2.625; // tDQSL ns DQS input Low Pulse Width = 0.35*tCK
1356//`else
1357//`define sg75Z // specparams for -75Z (CL = 2)
1358// specparam tDSS = 1.5; // tDSS ns DQS falling edge to CLK rising (setup time) = 0.2*tCK
1359// specparam tDSH = 1.5; // tDSH ns DQS falling edge from CLK rising (hold time) = 0.2*tCK
1360// specparam tIH = 0.900; // tIH ns Input Hold Time
1361// specparam tIS = 0.900; // tIS ns Input Setup Time
1362// specparam tDQSH = 2.625; // tDQSH ns DQS input High Pulse Width = 0.35*tCK
1363// specparam tDQSL = 2.625; // tDQSL ns DQS input Low Pulse Width = 0.35*tCK
1364//`endif `endif `endif
1365        $width (posedge Dqs_in[0] &&& wdqs_valid, tDQSH);
1366        $width (posedge Dqs_in[1] &&& wdqs_valid, tDQSH);
1367        $width (negedge Dqs_in[0] &&& wdqs_valid, tDQSL);
1368        $width (negedge Dqs_in[1] &&& wdqs_valid, tDQSL);
1369        $setuphold(posedge Clk, Cke, tIS, tIH);
1370        $setuphold(posedge Clk, Cs_n, tIS, tIH);
1371        $setuphold(posedge Clk, Cas_n, tIS, tIH);
1372        $setuphold(posedge Clk, Ras_n, tIS, tIH);
1373        $setuphold(posedge Clk, We_n, tIS, tIH);
1374        $setuphold(posedge Clk, Addr, tIS, tIH);
1375        $setuphold(posedge Clk, Ba, tIS, tIH);
1376        $setuphold(posedge Clk, negedge Dqs &&& wdqs_valid, tDSS, tDSH);
1377    endspecify
1378
1379endmodule
1380

Archive Download this file

Branches:
master



interactive