From 29e7ceda7ccbe5fc20a262feae254b0c9fcd679f Mon Sep 17 00:00:00 2001 From: Wolfgang Spraul Date: Sun, 19 Dec 2010 01:38:43 +0000 Subject: [PATCH] unzipped 2 files --- sim/verilog/micron/2048Mb_ddr2.zip | Bin 37247 -> 0 bytes sim/verilog/micron/mobile_ddr.zip | Bin 39500 -> 0 bytes sim/verilog/micron_2048Mb_ddr2/ddr2.v | 2031 ++++++++++++++++ sim/verilog/micron_2048Mb_ddr2/ddr2_mcp.v | 94 + sim/verilog/micron_2048Mb_ddr2/ddr2_module.v | 377 +++ .../micron_2048Mb_ddr2/ddr2_parameters.vh | 383 +++ sim/verilog/micron_2048Mb_ddr2/readme.txt | 190 ++ sim/verilog/micron_2048Mb_ddr2/subtest.vh | 225 ++ sim/verilog/micron_2048Mb_ddr2/tb.do | 31 + sim/verilog/micron_2048Mb_ddr2/tb.v | 468 ++++ .../1024Mb_mobile_ddr_parameters.vh | 167 ++ .../128Mb_mobile_ddr_parameters.vh | 153 ++ .../2048Mb_mobile_ddr_parameters.vh | 179 ++ .../256Mb_mobile_ddr_parameters.vh | 134 ++ .../512Mb_mobile_ddr_parameters.vh | 162 ++ sim/verilog/micron_mobile_ddr/mobile_ddr.v | 2126 +++++++++++++++++ .../micron_mobile_ddr/mobile_ddr_mcp.v | 84 + sim/verilog/micron_mobile_ddr/readme.txt | 167 ++ sim/verilog/micron_mobile_ddr/subtest.vh | 32 + sim/verilog/micron_mobile_ddr/tb.do | 39 + sim/verilog/micron_mobile_ddr/tb.v | 587 +++++ 21 files changed, 7629 insertions(+) delete mode 100644 sim/verilog/micron/2048Mb_ddr2.zip delete mode 100644 sim/verilog/micron/mobile_ddr.zip create mode 100644 sim/verilog/micron_2048Mb_ddr2/ddr2.v create mode 100644 sim/verilog/micron_2048Mb_ddr2/ddr2_mcp.v create mode 100644 sim/verilog/micron_2048Mb_ddr2/ddr2_module.v create mode 100644 sim/verilog/micron_2048Mb_ddr2/ddr2_parameters.vh create mode 100644 sim/verilog/micron_2048Mb_ddr2/readme.txt create mode 100644 sim/verilog/micron_2048Mb_ddr2/subtest.vh create mode 100644 sim/verilog/micron_2048Mb_ddr2/tb.do create mode 100644 sim/verilog/micron_2048Mb_ddr2/tb.v create mode 100644 sim/verilog/micron_mobile_ddr/1024Mb_mobile_ddr_parameters.vh create mode 100644 sim/verilog/micron_mobile_ddr/128Mb_mobile_ddr_parameters.vh create mode 100644 sim/verilog/micron_mobile_ddr/2048Mb_mobile_ddr_parameters.vh create mode 100644 sim/verilog/micron_mobile_ddr/256Mb_mobile_ddr_parameters.vh create mode 100644 sim/verilog/micron_mobile_ddr/512Mb_mobile_ddr_parameters.vh create mode 100644 sim/verilog/micron_mobile_ddr/mobile_ddr.v create mode 100644 sim/verilog/micron_mobile_ddr/mobile_ddr_mcp.v create mode 100644 sim/verilog/micron_mobile_ddr/readme.txt create mode 100644 sim/verilog/micron_mobile_ddr/subtest.vh create mode 100644 sim/verilog/micron_mobile_ddr/tb.do create mode 100644 sim/verilog/micron_mobile_ddr/tb.v diff --git a/sim/verilog/micron/2048Mb_ddr2.zip b/sim/verilog/micron/2048Mb_ddr2.zip deleted file mode 100644 index 783db03b604395e6de5a9e5d6002a41f77314149..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37247 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 RoI!iqb)K@w#iW0({s-46plbjC diff --git a/sim/verilog/micron_2048Mb_ddr2/ddr2.v b/sim/verilog/micron_2048Mb_ddr2/ddr2.v new file mode 100644 index 0000000..481fadc --- /dev/null +++ b/sim/verilog/micron_2048Mb_ddr2/ddr2.v @@ -0,0 +1,2031 @@ +/**************************************************************************************** +* +* File Name: ddr2.v +* Version: 5.83 +* Model: BUS Functional +* +* Dependencies: ddr2_parameters.vh +* +* Description: Micron SDRAM DDR2 (Double Data Rate 2) +* +* Limitation: - doesn't check for average refresh timings +* - positive ck and ck_n edges are used to form internal clock +* - positive dqs and dqs_n edges are used to latch data +* - test mode is not modeled +* +* Note: - Set simulator resolution to "ps" accuracy +* - Set Debug = 0 to disable $display messages +* +* Disclaimer This software code and all associated documentation, comments or other +* of Warranty: information (collectively "Software") is provided "AS IS" without +* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY +* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES +* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT +* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE +* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. +* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR +* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE +* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, +* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, +* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, +* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, +* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE +* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGES. Because some jurisdictions prohibit the exclusion or +* limitation of liability for consequential or incidental damages, the +* above limitation may not apply to you. +* +* Copyright 2003 Micron Technology, Inc. All rights reserved. +* +* Rev Author Date Changes +* --------------------------------------------------------------------------------------- +* 1.00 JMK 07/29/03 Initial Release +* 1.10 JMK 08/09/03 Timing Parameter updates to tIS, tIH, tDS, tDH +* 2.20 JMK 08/07/03 General cleanup +* 2.30 JMK 11/26/03 Added CL_MIN, CL_MAX, wl_min and wl_max parameters. +* Added AL_MIN and AL_MAX parameters. +* Removed support for OCD. +* 2.40 JMK 01/15/04 Removed verilog 2001 constructs. +* 2.50 JMK 01/29/04 Removed tRP checks during Precharge command. +* 2.60 JMK 04/20/04 Fixed tWTR check. +* 2.70 JMK 04/30/04 Added tRFC maximum check. +* Combined Self Refresh and Power Down always blocks. +* Added Reset Function (CKE LOW Anytime). +* 2.80 JMK 08/19/04 Precharge is treated as NOP when bank is not active. +* Added checks for tRAS, tWR, tRTP to any bank during Pre-All. +* tRFC maximum violation will only display one time. +* 2.90 JMK 11/05/04 Fixed DQS checking during write. +* Fixed false tRFC max assertion during power up and self ref. +* Added warning for 200us CKE low time during initialization. +* Added -3, -3E, and -37V speed grades to ddr2_parameters.v +* 3.00 JMK 04/22/05 Removed ODT off requirement during power down. +* Added tAOND, tAOFD, tANPD, tAXPD, tAONPD, and tAOFPD parameters. +* Added ODT status messages. +* Updated the initialization sequence. +* Disable ODT and CLK pins during self refresh. +* Disable cmd and addr pins during power down and self refresh. +* 3.10 JMK 06/07/05 Disable trpa checking if the part does not have 8 banks. +* Changed tAXPD message from error to a warning. +* Added tDSS checking. +* Removed tDQSL checking during tWPRE and tWPST. +* Fixed a burst order error during writes. +* Renamed parameters file with .vh extension. +* 3.20 JMK 07/18/05 Removed 14 tCK requirement from LMR to READ. +* 3.30 JMK 08/03/05 Added check for interrupting a burst with auto precharge. +* 4.00 JMK 11/21/05 Parameter names all UPPERCASE, signal names all lowercase. +* Clock jitter can be tolerated within specification range. +* Clock frequency is sampled from the CK pin. +* Scaleable up to 64 DQ and 16 DQS bits. +* Read data can be randomly skewed using RANDOM_OUT_DELAY. +* Parameterized read and write DQS, and read DQ. +* Initialization can be bypassed using initialize task. +* 4.10 JMK 11/30/05 Fixed compile errors when `MAX_MEM was defined. +* 4.20 JMK 12/09/05 Fixed memory addressing error when `MAX_MEM was defined. +* 4.30 JMK 02/15/06 Added dummy write to initialization sequence. +* Removed tWPST maximum checking. +* Rising dqs_n edge latches data when enabled in EMR. +* Fixed a sign error in the tJIT(cc) calculation. +* 4.40 JMK 02/16/06 Fixed dummy write when`MAX_MEM was defined. +* 4.50 JMK 02/27/06 Fixed extra tDQSS assertions. +* Fixed tRCD and tWTR checking. +* Errors entering Power Down or Self Refresh will cause reset. +* Ignore dqs_n when disabled in EMR. +* 5.00 JMK 04/24/06 Test stimulus now included from external file (subtest.vh) +* Fixed tRFC max assertion during self refresh. +* Fixed tANPD checking during Power Down. +* Removed dummy write from initialization sequence. +* 5.01 JMK 04/28/06 Fixed Auto Precharge to Load Mode, Refresh and Self Refresh. +* Removed Auto Precharge error message during Power Down Enter. +* 5.10 JMK 07/26/06 Created internal clock using ck and ck_n. +* RDQS can only be enabled in EMR for x8 configurations. +* CAS latency is checked vs frequency when DLL locks. +* tMOD changed from tCK units to ns units. +* Added 50 Ohm setting for Rtt in EMR. +* Improved checking of DQS during writes. +* 5.20 JMK 10/02/06 Fixed DQS checking for interrupting write to write and x16. +* 5.30 JMK 05/25/07 Fixed checking for 0-Z transition on write postamble. +* 5.50 JMK 05/30/08 Renamed ddr2_dimm.v to ddr2_module.v and added SODIMM support. +* Added a register delay to ddr2_module.v when RDIMM is defined. +* Added multi-chip package model support in ddr2_mcp.v +* Added High Temp Self Refresh rate setting in EMRS2[7] +* 5.70 JMK 04/23/09 Updated tRPA definition +* Increased internal width to 72 bit DQ bus +* 5.80 SPH 08/12/09 Fixed tRAS maximum violation (only check if bank still open) +* 5.81 SPH 12/08/09 Only check tIH for cmd_addr if CS# LOW +* 5.82 SPH 04/08/10 Correct debug message for SRT in EMR2 +* 5.83 SPH 04/29/10 Correct tDQSS check on valid DQS group +****************************************************************************************/ + +// DO NOT CHANGE THE TIMESCALE +// MAKE SURE YOUR SIMULATOR USES "PS" RESOLUTION +`timescale 1ps / 1ps + +module ddr2 ( + ck, + ck_n, + cke, + cs_n, + ras_n, + cas_n, + we_n, + dm_rdqs, + ba, + addr, + dq, + dqs, + dqs_n, + rdqs_n, + odt +); + + `include "ddr2_parameters.vh" + + // text macros + `define DQ_PER_DQS DQ_BITS/DQS_BITS + `define BANKS (1<= 2. \nBL_MAX = %d", BL_MAX); + if ((1< BL_MAX) + $display("%m ERROR: 2^BO_BITS cannot be greater than BL_MAX parameter."); + $timeformat (-12, 1, " ps", 1); + reset_task; + seed = RANDOM_SEED; + ck_cntr = 0; + end + + // calculate the absolute value of a real number + function real abs_value; + input arg; + real arg; + begin + if (arg < 0.0) + abs_value = -1.0 * arg; + else + abs_value = arg; + end + endfunction + +`ifdef MAX_MEM +`else + function get_index; + input [`MAX_BITS-1:0] addr; + begin : index + get_index = 0; + for (memory_index=0; memory_index TRAS_MAX) && (active_bank[bank] === 1'b1)) $display ("%m: at time %t ERROR: tRAS maximum violation during %s to bank %d", $time, cmd_string[cmd], bank); + 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 + {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 + {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 + {1'b1, ACTIVATE , 4'b010x } : ; // tRCD is checked outside this task + {1'b1, ACTIVATE , PWR_DOWN } : ; // 1 tCK + {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 + {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 + {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 + {1'b0, WRITE , PWR_DOWN } : begin if ((ck_load_mode < ck_write) && ( + |write_precharge_bank + || (ck_cntr - ck_write_ap < 1) + || (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 + {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 + {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 + {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 + {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 + {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 + {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 + {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]); + else if (ck_cntr - ck_power_down < TXARD) $display ("%m: at time %t ERROR: tXARD violation during %s", $time, cmd_string[cmd]); end + {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 + {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 + {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 + {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 + endcase + end + endtask + + task cmd_task; + input cke; + input [2:0] cmd; + input [BA_BITS-1:0] bank; + input [ADDR_BITS-1:0] addr; + reg [`BANKS:0] i; + integer j; + reg [`BANKS:0] tfaw_cntr; + reg [COL_BITS-1:0] col; + begin + + // tRFC max check + if (!er_trfc_max && !in_self_refresh) begin + if ($time - tm_refresh > TRFC_MAX) begin + $display ("%m: at time %t ERROR: tRFC maximum violation during %s", $time, cmd_string[cmd]); + er_trfc_max = 1; + end + end + if (cke) begin + if ((cmd < NOP) && ((cmd != PRECHARGE) || !addr[AP])) begin + for (j=0; j= BL_MIN) && (burst_length <= BL_MAX)) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Length = %d", $time, cmd_string[cmd], bank, burst_length); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal Burst Length = %d", $time, cmd_string[cmd], bank, burst_length); + end + // Burst Order + burst_order = addr[3]; + if (!burst_order) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Order = Sequential", $time, cmd_string[cmd], bank); + end else if (burst_order) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Order = Interleaved", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal Burst Order = %d", $time, cmd_string[cmd], bank, burst_order); + end + // CAS Latency + cas_latency = addr[6:4]; + read_latency = cas_latency + additive_latency; + write_latency = read_latency - 1; + if ((cas_latency >= CL_MIN) && (cas_latency <= CL_MAX)) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d CAS Latency = %d", $time, cmd_string[cmd], bank, cas_latency); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal CAS Latency = %d", $time, cmd_string[cmd], bank, cas_latency); + end + // Test Mode + if (!addr[7]) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Test Mode = Normal", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal Test Mode = %d", $time, cmd_string[cmd], bank, addr[7]); + end + // DLL Reset + dll_reset = addr[8]; + if (!dll_reset) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Reset = Normal", $time, cmd_string[cmd], bank); + end else if (dll_reset) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Reset = Reset DLL", $time, cmd_string[cmd], bank); + dll_locked = 0; + ck_dll_reset <= ck_cntr; + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal DLL Reset = %d", $time, cmd_string[cmd], bank, dll_reset); + end + // Write Recovery + write_recovery = addr[11:9] + 1; + if ((write_recovery >= WR_MIN) && (write_recovery <= WR_MAX)) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Write Recovery = %d", $time, cmd_string[cmd], bank, write_recovery); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal Write Recovery = %d", $time, cmd_string[cmd], bank, write_recovery); + end + // Power Down Mode + low_power = addr[12]; + if (!low_power) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Power Down Mode = Fast Exit", $time, cmd_string[cmd], bank); + end else if (low_power) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Power Down Mode = Slow Exit", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal Power Down Mode = %d", $time, cmd_string[cmd], bank, low_power); + end + end + 1 : begin + // DLL Enable + dll_en = !addr[0]; + if (!dll_en) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Enable = Disabled", $time, cmd_string[cmd], bank); + end else if (dll_en) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Enable = Enabled", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal DLL Enable = %d", $time, cmd_string[cmd], bank, dll_en); + end + // Output Drive Strength + if (!addr[1]) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Drive Strength = Full", $time, cmd_string[cmd], bank); + end else if (addr[1]) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Drive Strength = Reduced", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal Output Drive Strength = %d", $time, cmd_string[cmd], bank, addr[1]); + end + // ODT Rtt + odt_rtt = {addr[6], addr[2]}; + if (odt_rtt == 2'b00) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = Disabled", $time, cmd_string[cmd], bank); + odt_en = 0; + end else if (odt_rtt == 2'b01) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 75 Ohm", $time, cmd_string[cmd], bank); + odt_en = 1; + tm_odt_en <= $time; + end else if (odt_rtt == 2'b10) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 150 Ohm", $time, cmd_string[cmd], bank); + odt_en = 1; + tm_odt_en <= $time; + end else if (odt_rtt == 2'b11) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 50 Ohm", $time, cmd_string[cmd], bank); + odt_en = 1; + tm_odt_en <= $time; + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal ODT Rtt = %d", $time, cmd_string[cmd], bank, odt_rtt); + odt_en = 0; + end + // Additive Latency + additive_latency = addr[5:3]; + read_latency = cas_latency + additive_latency; + write_latency = read_latency - 1; + if ((additive_latency >= AL_MIN) && (additive_latency <= AL_MAX)) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Additive Latency = %d", $time, cmd_string[cmd], bank, additive_latency); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal Additive Latency = %d", $time, cmd_string[cmd], bank, additive_latency); + end + // OCD Program + ocd = addr[9:7]; + if (ocd == 3'b000) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d OCD Program = OCD Exit", $time, cmd_string[cmd], bank); + end else if (ocd == 3'b111) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d OCD Program = OCD Default", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal OCD Program = %b", $time, cmd_string[cmd], bank, ocd); + end + + // DQS_N Enable + dqs_n_en = !addr[10]; + if (!dqs_n_en) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d DQS_N Enable = Disabled", $time, cmd_string[cmd], bank); + end else if (dqs_n_en) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d DQS_N Enable = Enabled", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal DQS_N Enable = %d", $time, cmd_string[cmd], bank, dqs_n_en); + end + // RDQS Enable + rdqs_en = addr[11]; + if (!rdqs_en) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d RDQS Enable = Disabled", $time, cmd_string[cmd], bank); + end else if (rdqs_en) begin +`ifdef x8 + if (DEBUG) $display ("%m: at time %t INFO: %s %d RDQS Enable = Enabled", $time, cmd_string[cmd], bank); +`else + $display ("%m: at time %t WARNING: %s %d Illegal RDQS Enable. RDQS only exists on a x8 part", $time, cmd_string[cmd], bank); + rdqs_en = 0; +`endif + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal RDQS Enable = %d", $time, cmd_string[cmd], bank, rdqs_en); + end + // Output Enable + out_en = !addr[12]; + if (!out_en) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Enable = Disabled", $time, cmd_string[cmd], bank); + end else if (out_en) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Enable = Enabled", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal Output Enable = %d", $time, cmd_string[cmd], bank, out_en); + end + end + 2 : begin + // High Temperature Self Refresh rate + if (!addr[7]) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d High Temperature Self Refresh rate = 1X (0C-85C)", $time, cmd_string[cmd], bank); + end else if (addr[7]) begin + if (DEBUG) $display ("%m: at time %t INFO: %s %d High Temperature Self Refresh rate = 2X (>85C)", $time, cmd_string[cmd], bank); + end else begin + $display ("%m: at time %t ERROR: %s %d Illegal High Temperature Self Refresh rate = %d", $time, cmd_string[cmd], bank, addr[7]); + end + if ((addr & ~(1<<7)) !== 0) begin + $display ("%m: at time %t ERROR: %s %d Illegal value. Reserved bits must be programmed to zero", $time, cmd_string[cmd], bank); + end + end + 3 : begin + if (addr !== 0) begin + $display ("%m: at time %t ERROR: %s %d Illegal value. Reserved bits must be programmed to zero", $time, cmd_string[cmd], bank); + end + end + endcase + init_mode_reg[bank] = 1; + ck_load_mode <= ck_cntr; + end + end + REFRESH : begin + if (|active_bank) begin + $display ("%m: at time %t ERROR: %s Failure. All banks must be Precharged.", $time, cmd_string[cmd]); + if (STOP_ON_ERROR) $stop(0); + end else begin + if (DEBUG) $display ("%m: at time %t INFO: %s", $time, cmd_string[cmd]); + er_trfc_max = 0; + ref_cntr = ref_cntr + 1; + tm_refresh <= $time; + end + end + PRECHARGE : begin + if (addr[AP]) begin + // tRPA timing applies when the PRECHARGE (ALL) command is issued, regardless of + // the number of banks already open or closed. + for (i=0; i<`BANKS; i=i+1) begin + for (j=0; j 3) begin + $display ("%m: at time %t ERROR: tFAW violation during %s to bank %d", $time, cmd_string[cmd], bank); + end + end + + if (!init_done) begin + $display ("%m: at time %t ERROR: %s Failure. Initialization sequence is not complete.", $time, cmd_string[cmd]); + if (STOP_ON_ERROR) $stop(0); + end else if (active_bank[bank]) begin + $display ("%m: at time %t ERROR: %s Failure. Bank %d must be Precharged.", $time, cmd_string[cmd], bank); + if (STOP_ON_ERROR) $stop(0); + end else begin + if (addr >= 1<>1) & -1*(1<= 1<>1) & -1*(1<= 1< $time) +// $display("%m: at time %t WARNING: NOP or DESELECT is required for 200 us before CKE is brought high", $time); + init_step = init_step + 1; + end + 1 : if (dll_en) init_step = init_step + 1; + 2 : begin + if (&init_mode_reg && dll_reset) begin + active_bank = {`BANKS{1'b1}}; // require Precharge All or bank Precharges + ref_cntr = 0; // require refresh + init_step = init_step + 1; + end + end + 3 : if (ref_cntr == 2) begin + init_step = init_step + 1; + end + 4 : if (!dll_reset) init_step = init_step + 1; + 5 : if (ocd == 3'b111) init_step = init_step + 1; + 6 : begin + if (ocd == 3'b000) begin + if (DEBUG) $display ("%m: at time %t INFO: Initialization Sequence is complete", $time); + init_done = 1; + end + end + endcase + end + end else if (prev_cke) begin + if ((!init_done) && (init_step > 1)) begin + $display ("%m: at time %t ERROR: CKE must remain active until the initialization sequence is complete.", $time); + if (STOP_ON_ERROR) $stop(0); + end + case (cmd) + REFRESH : begin + for (j=0; j TDQSS*tck_avg)) + $display ("%m: at time %t ERROR: tDQSS violation on %s bit %d", $time, dqs_string[i/18], i%18); + end + if (check_write_dqs_low[i]) + $display ("%m: at time %t ERROR: %s bit %d latching edge required during the preceding clock period", $time, dqs_string[i/18], i%18); + end + check_write_preamble <= 0; + check_write_postamble <= 0; + check_write_dqs_low <= 0; + end + + if (wr_pipeline[0] || rd_pipeline[0]) begin + bank = ba_pipeline[0]; + row = row_pipeline[0]; + col = col_pipeline[0]; + burst_cntr = 0; + memory_read(bank, row, col, memory_data); + end + + // burst counter + if (burst_cntr < burst_length) begin + burst_position = col ^ burst_cntr; + if (!burst_order) begin + burst_position[BO_BITS-1:0] = col + burst_cntr; + end + burst_cntr = burst_cntr + 1; + end + + // write dqs counter + if (wr_pipeline[WDQS_PRE + 1]) begin + wdqs_cntr = WDQS_PRE + burst_length + WDQS_PST - 1; + end + // write dqs + if ((wdqs_cntr == burst_length + WDQS_PST) && (wdq_cntr == 0)) begin //write preamble + check_write_preamble <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; + end + if (wdqs_cntr > 1) begin // write data + if ((wdqs_cntr - WDQS_PST)%2) begin + check_write_dqs_high <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; + end else begin + check_write_dqs_low <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; + end + end + if (wdqs_cntr == WDQS_PST) begin // write postamble + check_write_postamble <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; + end + if (wdqs_cntr > 0) begin + wdqs_cntr = wdqs_cntr - 1; + end + + // write dq + if (dq_in_valid) begin // write data + bit_mask = 0; + if (diff_ck) begin + for (i=0; i>(burst_position*DQ_BITS); + 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); + if (burst_cntr%BL_MIN == 0) begin + memory_write(bank, row, col, memory_data); + end + end + if (wr_pipeline[1]) begin + wdq_cntr = burst_length; + end + if (wdq_cntr > 0) begin + wdq_cntr = wdq_cntr - 1; + dq_in_valid = 1'b1; + end else begin + dq_in_valid = 1'b0; + dqs_in_valid <= 1'b0; + for (i=0; i<36; i=i+1) begin + wdqs_pos_cntr[i] <= 0; + end + end + if (wr_pipeline[0]) begin + b2b_write <= 1'b0; + end + if (wr_pipeline[2]) begin + if (dqs_in_valid) begin + b2b_write <= 1'b1; + end + dqs_in_valid <= 1'b1; + end + // read dqs enable counter + if (rd_pipeline[RDQSEN_PRE]) begin + rdqsen_cntr = RDQSEN_PRE + burst_length + RDQSEN_PST - 1; + end + if (rdqsen_cntr > 0) begin + rdqsen_cntr = rdqsen_cntr - 1; + dqs_out_en = 1'b1; + end else begin + dqs_out_en = 1'b0; + end + + // read dqs counter + if (rd_pipeline[RDQS_PRE]) begin + rdqs_cntr = RDQS_PRE + burst_length + RDQS_PST - 1; + end + // read dqs + if ((rdqs_cntr >= burst_length + RDQS_PST) && (rdq_cntr == 0)) begin //read preamble + dqs_out = 1'b0; + end else if (rdqs_cntr > RDQS_PST) begin // read data + dqs_out = rdqs_cntr - RDQS_PST; + end else if (rdqs_cntr > 0) begin // read postamble + dqs_out = 1'b0; + end else begin + dqs_out = 1'b1; + end + if (rdqs_cntr > 0) begin + rdqs_cntr = rdqs_cntr - 1; + end + + // read dq enable counter + if (rd_pipeline[RDQEN_PRE]) begin + rdqen_cntr = RDQEN_PRE + burst_length + RDQEN_PST; + end + if (rdqen_cntr > 0) begin + rdqen_cntr = rdqen_cntr - 1; + dq_out_en = 1'b1; + end else begin + dq_out_en = 1'b0; + end + // read dq + if (rd_pipeline[0]) begin + rdq_cntr = burst_length; + end + if (rdq_cntr > 0) begin // read data + dq_temp = memory_data>>(burst_position*DQ_BITS); + dq_out = dq_temp; + 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); + rdq_cntr = rdq_cntr - 1; + end else begin + dq_out = {DQ_BITS{1'b1}}; + end + + // delay signals prior to output + if (RANDOM_OUT_DELAY && (dqs_out_en || |dqs_out_en_dly || dq_out_en || |dq_out_en_dly)) begin + for (i=0; i dqsck[i] + TQHS + TDQSQ) begin + dqsck_max = dqsck[i] + TQHS + TDQSQ; + end + dqsck_min = -1*TDQSCK; + if (dqsck_min < dqsck[i] - TQHS - TDQSQ) begin + dqsck_min = dqsck[i] - TQHS - TDQSQ; + end + + // DQSQ requirements + // 1.) less than tAC - DQSCK + // 2.) less than tDQSQ + // 3.) greater than -tAC + // 4.) greater than tQH from previous DQS edge + dqsq_min = -1*TAC; + if (dqsq_min < dqsck[i] - TQHS) begin + dqsq_min = dqsck[i] - TQHS; + end + if (dqsck_min == dqsck_max) begin + dqsck[i] = dqsck_min; + end else begin + dqsck[i] = $dist_uniform(seed, dqsck_min, dqsck_max); + end + dqsq_max = TAC; + if (dqsq_max > TDQSQ + dqsck[i]) begin + dqsq_max = TDQSQ + dqsck[i]; + end + + dqs_out_en_dly[i] <= #(tck_avg/2.0 + ($random % TAC)) dqs_out_en; + dqs_out_dly[i] <= #(tck_avg/2.0 + dqsck[i]) dqs_out; + for (j=0; j<`DQ_PER_DQS; j=j+1) begin + if (dq_out_en) begin // tLZ2 + dq_out_en_dly[i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + $dist_uniform(seed, -2*TAC, dqsq_max)) dq_out_en; + end else begin // tHZ + dq_out_en_dly[i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + ($random % TAC)) dq_out_en; + end + if (dqsq_min == dqsq_max) begin + dq_out_dly [i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + dqsq_min) dq_out[i*`DQ_PER_DQS + j]; + end else begin + dq_out_dly [i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + $dist_uniform(seed, dqsq_min, dqsq_max)) dq_out[i*`DQ_PER_DQS + j]; + end + end + end + end else begin + out_delay = tck_avg/2.0; + dqs_out_en_dly <= #(out_delay) {DQS_BITS{dqs_out_en}}; + dqs_out_dly <= #(out_delay) {DQS_BITS{dqs_out }}; + dq_out_en_dly <= #(out_delay) {DQ_BITS {dq_out_en }}; + dq_out_dly <= #(out_delay) {DQ_BITS {dq_out }}; + end + end + endtask + + always @(diff_ck) begin : main + integer i; + + if (!in_self_refresh && (diff_ck !== 1'b0) && (diff_ck !== 1'b1)) + $display ("%m: at time %t ERROR: CK and CK_N are not allowed to go to an unknown state.", $time); + data_task; + if (diff_ck) begin + // check setup of command signals + if ($time > TIS) begin + if ($time - tm_cke < TIS) + $display ("%m: at time %t ERROR: tIS violation on CKE by %t", $time, tm_cke + TIS - $time); + if (cke_in) begin + for (i=0; i<22; i=i+1) begin + if ($time - tm_cmd_addr[i] < TIS) + $display ("%m: at time %t ERROR: tIS violation on %s by %t", $time, cmd_addr_string[i], tm_cmd_addr[i] + TIS - $time); + end + end + end + + // update current state + if (!dll_locked && !in_self_refresh && (ck_cntr - ck_dll_reset == TDLLK)) begin + // check CL value against the clock frequency + if (cas_latency*tck_avg < CL_TIME) + $display ("%m: at time %t ERROR: CAS Latency = %d is illegal @tCK(avg) = %f", $time, cas_latency, tck_avg); + // check WR value against the clock frequency + if (write_recovery*tck_avg < TWR) + $display ("%m: at time %t ERROR: Write Recovery = %d is illegal @tCK(avg) = %f", $time, write_recovery, tck_avg); + dll_locked = 1; + end + if (|auto_precharge_bank) begin + for (i=0; i<`BANKS; i=i+1) begin + // Write with Auto Precharge Calculation + // 1. Meet minimum tRAS requirement + // 2. Write Latency PLUS BL/2 cycles PLUS WR after Write command + if (write_precharge_bank[i] + && ($time - tm_bank_activate[i] >= TRAS_MIN) + && (ck_cntr - ck_bank_write[i] >= write_latency + burst_length/2 + write_recovery)) begin + + if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", $time, i); + write_precharge_bank[i] = 0; + active_bank[i] = 0; + auto_precharge_bank[i] = 0; + ck_write_ap = ck_cntr; + tm_bank_precharge[i] = $time; + tm_precharge = $time; + end + // Read with Auto Precharge Calculation + // 1. Meet minimum tRAS requirement + // 2. Additive Latency plus BL/2 cycles after Read command + // 3. tRTP after the last 4-bit prefetch + if (read_precharge_bank[i] + && ($time - tm_bank_activate[i] >= TRAS_MIN) + && (ck_cntr - ck_bank_read[i] >= additive_latency + burst_length/2)) begin + + read_precharge_bank[i] = 0; + // In case the internal precharge is pushed out by tRTP, tRP starts at the point where + // the internal precharge happens (not at the next rising clock edge after this event). + if ($time - tm_bank_read_end[i] < TRTP) begin + if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", tm_bank_read_end[i] + TRTP, i); + active_bank[i] <= #(tm_bank_read_end[i] + TRTP - $time) 0; + auto_precharge_bank[i] <= #(tm_bank_read_end[i] + TRTP - $time) 0; + tm_bank_precharge[i] <= #(tm_bank_read_end[i] + TRTP - $time) tm_bank_read_end[i] + TRTP; + tm_precharge <= #(tm_bank_read_end[i] + TRTP - $time) tm_bank_read_end[i] + TRTP; + end else begin + if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", $time, i); + active_bank[i] = 0; + auto_precharge_bank[i] = 0; + tm_bank_precharge[i] = $time; + tm_precharge = $time; + end + end + end + end + + // respond to incoming command + if (cke_in ^ prev_cke) begin + ck_cke <= ck_cntr; + end + + cmd_task(cke_in, cmd_n_in, ba_in, addr_in); + if ((cmd_n_in == WRITE) || (cmd_n_in == READ)) begin + al_pipeline[2*additive_latency] = 1'b1; + end + if (al_pipeline[0]) begin + // check tRCD after additive latency + if ($time - tm_bank_activate[ba_pipeline[2*cas_latency - 1]] < TRCD) begin + if (rd_pipeline[2*cas_latency - 1]) begin + $display ("%m: at time %t ERROR: tRCD violation during %s", $time, cmd_string[READ]); + end else begin + $display ("%m: at time %t ERROR: tRCD violation during %s", $time, cmd_string[WRITE]); + end + end + // check tWTR after additive latency + if (rd_pipeline[2*cas_latency - 1]) begin + if ($time - tm_write_end < TWTR) + $display ("%m: at time %t ERROR: tWTR violation during %s", $time, cmd_string[READ]); + end + end + if (rd_pipeline[2*(cas_latency - burst_length/2 + 2) - 1]) begin + tm_bank_read_end[ba_pipeline[2*(cas_latency - burst_length/2 + 2) - 1]] <= $time; + end + for (i=0; i<`BANKS; i=i+1) begin + if ((ck_cntr - ck_bank_write[i] > write_latency) && (ck_cntr - ck_bank_write[i] <= write_latency + burst_length/2)) begin + tm_bank_write_end[i] <= $time; + tm_write_end <= $time; + end + end + + // clk pin is disabled during self refresh + if (!in_self_refresh) begin + tjit_cc_time = $time - tm_ck_pos - tck_i; + tck_i = $time - tm_ck_pos; + tck_avg = tck_avg - tck_sample[ck_cntr%TDLLK]/$itor(TDLLK); + tck_avg = tck_avg + tck_i/$itor(TDLLK); + tck_sample[ck_cntr%TDLLK] = tck_i; + tjit_per_rtime = tck_i - tck_avg; + + if (dll_locked) begin + // check accumulated error + terr_nper_rtime = 0; + for (i=0; i<50; i=i+1) begin + terr_nper_rtime = terr_nper_rtime + tck_sample[i] - tck_avg; + terr_nper_rtime = abs_value(terr_nper_rtime); + case (i) + 0 :; + 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); + 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); + 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); + 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); + 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); + 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); + endcase + end + + // check tCK min/max/jitter + if (abs_value(tjit_per_rtime) - TJIT_PER >= 1.0) + $display ("%m: at time %t ERROR: tJIT(per) violation by %f ps.", $time, abs_value(tjit_per_rtime) - TJIT_PER); + if (abs_value(tjit_cc_time) - TJIT_CC >= 1.0) + $display ("%m: at time %t ERROR: tJIT(cc) violation by %f ps.", $time, abs_value(tjit_cc_time) - TJIT_CC); + if (TCK_MIN - tck_avg >= 1.0) + $display ("%m: at time %t ERROR: tCK(avg) minimum violation by %f ps.", $time, TCK_MIN - tck_avg); + if (tck_avg - TCK_MAX >= 1.0) + $display ("%m: at time %t ERROR: tCK(avg) maximum violation by %f ps.", $time, tck_avg - TCK_MAX); + if (tm_ck_pos + TCK_MIN - TJIT_PER > $time) + $display ("%m: at time %t ERROR: tCK(abs) minimum violation by %t", $time, tm_ck_pos + TCK_MIN - TJIT_PER - $time); + if (tm_ck_pos + TCK_MAX + TJIT_PER < $time) + $display ("%m: at time %t ERROR: tCK(abs) maximum violation by %t", $time, $time - tm_ck_pos - TCK_MAX - TJIT_PER); + + // check tCL + if (tm_ck_neg + TCL_MIN*tck_avg - TJIT_DUTY > $time) + $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); + if (tm_ck_neg + TCL_MAX*tck_avg + TJIT_DUTY < $time) + $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); + if (tcl_avg < TCL_MIN*tck_avg) + $display ("%m: at time %t ERROR: tCL(avg) minimum violation on CLK by %t", $time, TCL_MIN*tck_avg - tcl_avg); + if (tcl_avg > TCL_MAX*tck_avg) + $display ("%m: at time %t ERROR: tCL(avg) maximum violation on CLK by %t", $time, tcl_avg - TCL_MAX*tck_avg); + end + + // calculate the tch avg jitter + tch_avg = tch_avg - tch_sample[ck_cntr%TDLLK]/$itor(TDLLK); + tch_avg = tch_avg + tch_i/$itor(TDLLK); + tch_sample[ck_cntr%TDLLK] = tch_i; + + // update timers/counters + tcl_i <= $time - tm_ck_neg; + end + + prev_odt <= odt_in; + // update timers/counters + ck_cntr <= ck_cntr + 1; + tm_ck_pos <= $time; + end else begin + // clk pin is disabled during self refresh + if (!in_self_refresh) begin + if (dll_locked) begin + if (tm_ck_pos + TCH_MIN*tck_avg - TJIT_DUTY > $time) + $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); + if (tm_ck_pos + TCH_MAX*tck_avg + TJIT_DUTY < $time) + $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); + if (tch_avg < TCH_MIN*tck_avg) + $display ("%m: at time %t ERROR: tCH(avg) minimum violation on CLK by %t", $time, TCH_MIN*tck_avg - tch_avg); + if (tch_avg > TCH_MAX*tck_avg) + $display ("%m: at time %t ERROR: tCH(avg) maximum violation on CLK by %t", $time, tch_avg - TCH_MAX*tck_avg); + end + + // calculate the tcl avg jitter + tcl_avg = tcl_avg - tcl_sample[ck_cntr%TDLLK]/$itor(TDLLK); + tcl_avg = tcl_avg + tcl_i/$itor(TDLLK); + tcl_sample[ck_cntr%TDLLK] = tcl_i; + + // update timers/counters + tch_i <= $time - tm_ck_pos; + end + tm_ck_neg <= $time; + end + + // on die termination + if (odt_en) begin + // clk pin is disabled during self refresh + if (!in_self_refresh && diff_ck) begin + if ($time - tm_odt < TIS) begin + $display ("%m: at time %t ERROR: tIS violation on ODT by %t", $time, tm_odt + TIS - $time); + end + if (prev_odt ^ odt_in) begin + if (!dll_locked) + $display ("%m: at time %t WARNING: tDLLK violation during ODT transition.", $time); + if (odt_in && ($time - tm_odt_en < TMOD)) + $display ("%m: at time %t ERROR: tMOD violation during ODT transition", $time); + if ($time - tm_self_refresh < TXSNR) + $display ("%m: at time %t ERROR: tXSNR violation during ODT transition", $time); + if (in_self_refresh) + $display ("%m: at time %t ERROR: Illegal ODT transition during Self Refresh.", $time); + + // async ODT mode applies: + // 1.) during active power down with slow exit + // 2.) during precharge power down + // 3.) if tANPD has not been satisfied + // 4.) until tAXPD has been satisfied + if ((in_power_down && (low_power || (active_bank == 0))) || (ck_cntr - ck_slow_exit_pd < TAXPD)) begin + if (ck_cntr - ck_slow_exit_pd < TAXPD) + $display ("%m: at time %t WARNING: tAXPD violation during ODT transition. Synchronous or asynchronous change in termination resistance is possible.", $time); + if (odt_in) begin + if (DEBUG) $display ("%m: at time %t INFO: Async On Die Termination = %d", $time + TAONPD, 1'b1); + odt_state <= #(TAONPD) 1'b1; + end else begin + if (DEBUG) $display ("%m: at time %t INFO: Async On Die Termination = %d", $time + TAOFPD, 1'b0); + odt_state <= #(TAOFPD) 1'b0; + end + // sync ODT mode applies: + // 1.) during normal operation + // 2.) during active power down with fast exit + end else begin + if (odt_in) begin + i = TAOND*2; + odt_pipeline[i] = 1'b1; + end else begin + i = TAOFD*2; + odt_pipeline[i] = 1'b1; + end + end + ck_odt <= ck_cntr; + end + end + if (odt_pipeline[0]) begin + odt_state = ~odt_state; + if (DEBUG) $display ("%m: at time %t INFO: Sync On Die Termination = %d", $time, odt_state); + end + end + + // shift pipelines + if (|wr_pipeline || |rd_pipeline || |al_pipeline) begin + al_pipeline = al_pipeline>>1; + wr_pipeline = wr_pipeline>>1; + rd_pipeline = rd_pipeline>>1; + for (i=0; i<`MAX_PIPE; i=i+1) begin + ba_pipeline[i] = ba_pipeline[i+1]; + row_pipeline[i] = row_pipeline[i+1]; + col_pipeline[i] = col_pipeline[i+1]; + end + end + if (|odt_pipeline) begin + odt_pipeline = odt_pipeline>>1; + end + end + + // receiver(s) + task dqs_even_receiver; + input [4:0] i; + reg [71:0] bit_mask; + begin + bit_mask = {`DQ_PER_DQS{1'b1}}<<(i*`DQ_PER_DQS); + if (dqs_even[i]) begin + if (rdqs_en) begin // rdqs disables dm + dm_in_pos[i] = 1'b0; + end else begin + dm_in_pos[i] = dm_in[i]; + end + dq_in_pos = (dq_in & bit_mask) | (dq_in_pos & ~bit_mask); + end + end + endtask + + always @(posedge dqs_even[ 0]) dqs_even_receiver( 0); + always @(posedge dqs_even[ 1]) dqs_even_receiver( 1); + always @(posedge dqs_even[ 2]) dqs_even_receiver( 2); + always @(posedge dqs_even[ 3]) dqs_even_receiver( 3); + always @(posedge dqs_even[ 4]) dqs_even_receiver( 4); + always @(posedge dqs_even[ 5]) dqs_even_receiver( 5); + always @(posedge dqs_even[ 6]) dqs_even_receiver( 6); + always @(posedge dqs_even[ 7]) dqs_even_receiver( 7); + always @(posedge dqs_even[ 8]) dqs_even_receiver( 8); + always @(posedge dqs_even[ 9]) dqs_even_receiver( 9); + always @(posedge dqs_even[10]) dqs_even_receiver(10); + always @(posedge dqs_even[11]) dqs_even_receiver(11); + always @(posedge dqs_even[12]) dqs_even_receiver(12); + always @(posedge dqs_even[13]) dqs_even_receiver(13); + always @(posedge dqs_even[14]) dqs_even_receiver(14); + always @(posedge dqs_even[15]) dqs_even_receiver(15); + always @(posedge dqs_even[16]) dqs_even_receiver(16); + always @(posedge dqs_even[17]) dqs_even_receiver(17); + + task dqs_odd_receiver; + input [4:0] i; + reg [71:0] bit_mask; + begin + bit_mask = {`DQ_PER_DQS{1'b1}}<<(i*`DQ_PER_DQS); + if (dqs_odd[i]) begin + if (rdqs_en) begin // rdqs disables dm + dm_in_neg[i] = 1'b0; + end else begin + dm_in_neg[i] = dm_in[i]; + end + dq_in_neg = (dq_in & bit_mask) | (dq_in_neg & ~bit_mask); + end + end + endtask + + always @(posedge dqs_odd[ 0]) dqs_odd_receiver( 0); + always @(posedge dqs_odd[ 1]) dqs_odd_receiver( 1); + always @(posedge dqs_odd[ 2]) dqs_odd_receiver( 2); + always @(posedge dqs_odd[ 3]) dqs_odd_receiver( 3); + always @(posedge dqs_odd[ 4]) dqs_odd_receiver( 4); + always @(posedge dqs_odd[ 5]) dqs_odd_receiver( 5); + always @(posedge dqs_odd[ 6]) dqs_odd_receiver( 6); + always @(posedge dqs_odd[ 7]) dqs_odd_receiver( 7); + always @(posedge dqs_odd[ 8]) dqs_odd_receiver( 8); + always @(posedge dqs_odd[ 9]) dqs_odd_receiver( 9); + always @(posedge dqs_odd[10]) dqs_odd_receiver(10); + always @(posedge dqs_odd[11]) dqs_odd_receiver(11); + always @(posedge dqs_odd[12]) dqs_odd_receiver(12); + always @(posedge dqs_odd[13]) dqs_odd_receiver(13); + always @(posedge dqs_odd[14]) dqs_odd_receiver(14); + always @(posedge dqs_odd[15]) dqs_odd_receiver(15); + always @(posedge dqs_odd[16]) dqs_odd_receiver(16); + always @(posedge dqs_odd[17]) dqs_odd_receiver(17); + + // Processes to check hold and pulse width of control signals + always @(cke_in) begin + if ($time > TIH) begin + if ($time - tm_ck_pos < TIH) + $display ("%m: at time %t ERROR: tIH violation on CKE by %t", $time, tm_ck_pos + TIH - $time); + end + if (dll_locked && ($time - tm_cke < $rtoi(TIPW*tck_avg))) + $display ("%m: at time %t ERROR: tIPW violation on CKE by %t", $time, tm_cke + TIPW*tck_avg - $time); + tm_cke = $time; + end + always @(odt_in) begin + if (odt_en && !in_self_refresh) begin + if ($time - tm_ck_pos < TIH) + $display ("%m: at time %t ERROR: tIH violation on ODT by %t", $time, tm_ck_pos + TIH - $time); + if (dll_locked && ($time - tm_odt < $rtoi(TIPW*tck_avg))) + $display ("%m: at time %t ERROR: tIPW violation on ODT by %t", $time, tm_odt + TIPW*tck_avg - $time); + end + tm_odt = $time; + end + + task cmd_addr_timing_check; + input i; + reg [4:0] i; + begin + if (prev_cke) begin + if ((i == 0) && ($time - tm_ck_pos < TIH)) // Always check tIH for CS# + $display ("%m: at time %t ERROR: tIH violation on %s by %t", $time, cmd_addr_string[i], tm_ck_pos + TIH - $time); + if ((i > 0) && (cs_n_in == 1'b0) && ($time - tm_ck_pos < TIH)) // Only check tIH for cmd_addr if CS# low + $display ("%m: at time %t ERROR: tIH violation on %s by %t", $time, cmd_addr_string[i], tm_ck_pos + TIH - $time); + if (dll_locked && ($time - tm_cmd_addr[i] < $rtoi(TIPW*tck_avg))) + $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); + end + tm_cmd_addr[i] = $time; + end + endtask + + always @(cs_n_in ) cmd_addr_timing_check( 0); + always @(ras_n_in ) cmd_addr_timing_check( 1); + always @(cas_n_in ) cmd_addr_timing_check( 2); + always @(we_n_in ) cmd_addr_timing_check( 3); + always @(ba_in [ 0]) cmd_addr_timing_check( 4); + always @(ba_in [ 1]) cmd_addr_timing_check( 5); + always @(ba_in [ 2]) cmd_addr_timing_check( 6); + always @(addr_in[ 0]) cmd_addr_timing_check( 7); + always @(addr_in[ 1]) cmd_addr_timing_check( 8); + always @(addr_in[ 2]) cmd_addr_timing_check( 9); + always @(addr_in[ 3]) cmd_addr_timing_check(10); + always @(addr_in[ 4]) cmd_addr_timing_check(11); + always @(addr_in[ 5]) cmd_addr_timing_check(12); + always @(addr_in[ 6]) cmd_addr_timing_check(13); + always @(addr_in[ 7]) cmd_addr_timing_check(14); + always @(addr_in[ 8]) cmd_addr_timing_check(15); + always @(addr_in[ 9]) cmd_addr_timing_check(16); + always @(addr_in[10]) cmd_addr_timing_check(17); + always @(addr_in[11]) cmd_addr_timing_check(18); + always @(addr_in[12]) cmd_addr_timing_check(19); + always @(addr_in[13]) cmd_addr_timing_check(20); + always @(addr_in[14]) cmd_addr_timing_check(21); + always @(addr_in[15]) cmd_addr_timing_check(22); + + // Processes to check setup and hold of data signals + task dm_timing_check; + input i; + reg [4:0] i; + begin + if (dqs_in_valid) begin + if ($time - tm_dqs[i] < TDH) + $display ("%m: at time %t ERROR: tDH violation on DM bit %d by %t", $time, i, tm_dqs[i] + TDH - $time); + if (check_dm_tdipw[i]) begin + if (dll_locked && ($time - tm_dm[i] < $rtoi(TDIPW*tck_avg))) + $display ("%m: at time %t ERROR: tDIPW violation on DM bit %d by %t", $time, i, tm_dm[i] + TDIPW*tck_avg - $time); + end + end + check_dm_tdipw[i] <= 1'b0; + tm_dm[i] = $time; + end + endtask + + always @(dm_in[ 0]) dm_timing_check( 0); + always @(dm_in[ 1]) dm_timing_check( 1); + always @(dm_in[ 2]) dm_timing_check( 2); + always @(dm_in[ 3]) dm_timing_check( 3); + always @(dm_in[ 4]) dm_timing_check( 4); + always @(dm_in[ 5]) dm_timing_check( 5); + always @(dm_in[ 6]) dm_timing_check( 6); + always @(dm_in[ 7]) dm_timing_check( 7); + always @(dm_in[ 8]) dm_timing_check( 8); + always @(dm_in[ 9]) dm_timing_check( 9); + always @(dm_in[10]) dm_timing_check(10); + always @(dm_in[11]) dm_timing_check(11); + always @(dm_in[12]) dm_timing_check(12); + always @(dm_in[13]) dm_timing_check(13); + always @(dm_in[14]) dm_timing_check(14); + always @(dm_in[15]) dm_timing_check(15); + always @(dm_in[16]) dm_timing_check(16); + always @(dm_in[17]) dm_timing_check(17); + + task dq_timing_check; + input i; + reg [6:0] i; + begin + if (dqs_in_valid) begin + if ($time - tm_dqs[i/`DQ_PER_DQS] < TDH) + $display ("%m: at time %t ERROR: tDH violation on DQ bit %d by %t", $time, i, tm_dqs[i/`DQ_PER_DQS] + TDH - $time); + if (check_dq_tdipw[i]) begin + if (dll_locked && ($time - tm_dq[i] < $rtoi(TDIPW*tck_avg))) + $display ("%m: at time %t ERROR: tDIPW violation on DQ bit %d by %t", $time, i, tm_dq[i] + TDIPW*tck_avg - $time); + end + end + check_dq_tdipw[i] <= 1'b0; + tm_dq[i] = $time; + end + endtask + + always @(dq_in[ 0]) dq_timing_check( 0); + always @(dq_in[ 1]) dq_timing_check( 1); + always @(dq_in[ 2]) dq_timing_check( 2); + always @(dq_in[ 3]) dq_timing_check( 3); + always @(dq_in[ 4]) dq_timing_check( 4); + always @(dq_in[ 5]) dq_timing_check( 5); + always @(dq_in[ 6]) dq_timing_check( 6); + always @(dq_in[ 7]) dq_timing_check( 7); + always @(dq_in[ 8]) dq_timing_check( 8); + always @(dq_in[ 9]) dq_timing_check( 9); + always @(dq_in[10]) dq_timing_check(10); + always @(dq_in[11]) dq_timing_check(11); + always @(dq_in[12]) dq_timing_check(12); + always @(dq_in[13]) dq_timing_check(13); + always @(dq_in[14]) dq_timing_check(14); + always @(dq_in[15]) dq_timing_check(15); + always @(dq_in[16]) dq_timing_check(16); + always @(dq_in[17]) dq_timing_check(17); + always @(dq_in[18]) dq_timing_check(18); + always @(dq_in[19]) dq_timing_check(19); + always @(dq_in[20]) dq_timing_check(20); + always @(dq_in[21]) dq_timing_check(21); + always @(dq_in[22]) dq_timing_check(22); + always @(dq_in[23]) dq_timing_check(23); + always @(dq_in[24]) dq_timing_check(24); + always @(dq_in[25]) dq_timing_check(25); + always @(dq_in[26]) dq_timing_check(26); + always @(dq_in[27]) dq_timing_check(27); + always @(dq_in[28]) dq_timing_check(28); + always @(dq_in[29]) dq_timing_check(29); + always @(dq_in[30]) dq_timing_check(30); + always @(dq_in[31]) dq_timing_check(31); + always @(dq_in[32]) dq_timing_check(32); + always @(dq_in[33]) dq_timing_check(33); + always @(dq_in[34]) dq_timing_check(34); + always @(dq_in[35]) dq_timing_check(35); + always @(dq_in[36]) dq_timing_check(36); + always @(dq_in[37]) dq_timing_check(37); + always @(dq_in[38]) dq_timing_check(38); + always @(dq_in[39]) dq_timing_check(39); + always @(dq_in[40]) dq_timing_check(40); + always @(dq_in[41]) dq_timing_check(41); + always @(dq_in[42]) dq_timing_check(42); + always @(dq_in[43]) dq_timing_check(43); + always @(dq_in[44]) dq_timing_check(44); + always @(dq_in[45]) dq_timing_check(45); + always @(dq_in[46]) dq_timing_check(46); + always @(dq_in[47]) dq_timing_check(47); + always @(dq_in[48]) dq_timing_check(48); + always @(dq_in[49]) dq_timing_check(49); + always @(dq_in[50]) dq_timing_check(50); + always @(dq_in[51]) dq_timing_check(51); + always @(dq_in[52]) dq_timing_check(52); + always @(dq_in[53]) dq_timing_check(53); + always @(dq_in[54]) dq_timing_check(54); + always @(dq_in[55]) dq_timing_check(55); + always @(dq_in[56]) dq_timing_check(56); + always @(dq_in[57]) dq_timing_check(57); + always @(dq_in[58]) dq_timing_check(58); + always @(dq_in[59]) dq_timing_check(59); + always @(dq_in[60]) dq_timing_check(60); + always @(dq_in[61]) dq_timing_check(61); + always @(dq_in[62]) dq_timing_check(62); + always @(dq_in[63]) dq_timing_check(63); + always @(dq_in[64]) dq_timing_check(64); + always @(dq_in[65]) dq_timing_check(65); + always @(dq_in[66]) dq_timing_check(66); + always @(dq_in[67]) dq_timing_check(67); + always @(dq_in[68]) dq_timing_check(68); + always @(dq_in[69]) dq_timing_check(69); + always @(dq_in[70]) dq_timing_check(70); + always @(dq_in[71]) dq_timing_check(71); + + task dqs_pos_timing_check; + input i; + reg [5:0] i; + reg [3:0] j; + begin + if (dqs_in_valid && ((wdqs_pos_cntr[i] < burst_length/2) || b2b_write) && (dqs_n_en || i<18)) begin + if (dqs_in[i] ^ prev_dqs_in[i]) begin + if (dll_locked) begin + if (check_write_preamble[i]) begin + if ($time - tm_dqs_neg[i] < $rtoi(TWPRE*tck_avg)) + $display ("%m: at time %t ERROR: tWPRE violation on &s bit %d", $time, dqs_string[i/18], i%18); + end else if (check_write_postamble[i]) begin + if ($time - tm_dqs_neg[i] < $rtoi(TWPST*tck_avg)) + $display ("%m: at time %t ERROR: tWPST violation on %s bit %d", $time, dqs_string[i/18], i%18); + end else begin + if ($time - tm_dqs_neg[i] < $rtoi(TDQSL*tck_avg)) + $display ("%m: at time %t ERROR: tDQSL violation on %s bit %d", $time, dqs_string[i/18], i%18); + end + end + if ($time - tm_dm[i%18] < TDS) + $display ("%m: at time %t ERROR: tDS violation on DM bit %d by %t", $time, i, tm_dm[i%18] + TDS - $time); + if (!dq_out_en) begin + for (j=0; j<`DQ_PER_DQS; j=j+1) begin + if ($time - tm_dq[i*`DQ_PER_DQS+j] < TDS) + $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); + check_dq_tdipw[i*`DQ_PER_DQS+j] <= 1'b1; + end + end + if ((wdqs_pos_cntr[i] < burst_length/2) && !b2b_write) begin + wdqs_pos_cntr[i] <= wdqs_pos_cntr[i] + 1; + end else begin + wdqs_pos_cntr[i] <= 1; + end + check_dm_tdipw[i%18] <= 1'b1; + check_write_preamble[i] <= 1'b0; + check_write_postamble[i] <= 1'b0; + check_write_dqs_low[i] <= 1'b0; + tm_dqs[i%18] <= $time; + end else begin + $display ("%m: at time %t ERROR: Invalid latching edge on %s bit %d", $time, dqs_string[i/18], i%18); + end + end + tm_dqss_pos[i] <= $time; + tm_dqs_pos[i] = $time; + prev_dqs_in[i] <= dqs_in[i]; + end + endtask + + always @(posedge dqs_in[ 0]) dqs_pos_timing_check( 0); + always @(posedge dqs_in[ 1]) dqs_pos_timing_check( 1); + always @(posedge dqs_in[ 2]) dqs_pos_timing_check( 2); + always @(posedge dqs_in[ 3]) dqs_pos_timing_check( 3); + always @(posedge dqs_in[ 4]) dqs_pos_timing_check( 4); + always @(posedge dqs_in[ 5]) dqs_pos_timing_check( 5); + always @(posedge dqs_in[ 6]) dqs_pos_timing_check( 6); + always @(posedge dqs_in[ 7]) dqs_pos_timing_check( 7); + always @(posedge dqs_in[ 8]) dqs_pos_timing_check( 8); + always @(posedge dqs_in[ 9]) dqs_pos_timing_check( 9); + always @(posedge dqs_in[10]) dqs_pos_timing_check(10); + always @(posedge dqs_in[11]) dqs_pos_timing_check(11); + always @(posedge dqs_in[12]) dqs_pos_timing_check(12); + always @(posedge dqs_in[13]) dqs_pos_timing_check(13); + always @(posedge dqs_in[14]) dqs_pos_timing_check(14); + always @(posedge dqs_in[15]) dqs_pos_timing_check(15); + always @(posedge dqs_in[16]) dqs_pos_timing_check(16); + always @(posedge dqs_in[17]) dqs_pos_timing_check(17); + always @(negedge dqs_in[18]) dqs_pos_timing_check(18); + always @(negedge dqs_in[19]) dqs_pos_timing_check(19); + always @(negedge dqs_in[20]) dqs_pos_timing_check(20); + always @(negedge dqs_in[21]) dqs_pos_timing_check(21); + always @(negedge dqs_in[22]) dqs_pos_timing_check(22); + always @(negedge dqs_in[23]) dqs_pos_timing_check(23); + always @(negedge dqs_in[24]) dqs_pos_timing_check(24); + always @(negedge dqs_in[25]) dqs_pos_timing_check(25); + always @(negedge dqs_in[26]) dqs_pos_timing_check(26); + always @(negedge dqs_in[27]) dqs_pos_timing_check(27); + always @(negedge dqs_in[28]) dqs_pos_timing_check(28); + always @(negedge dqs_in[29]) dqs_pos_timing_check(29); + always @(negedge dqs_in[30]) dqs_pos_timing_check(30); + always @(negedge dqs_in[31]) dqs_pos_timing_check(31); + always @(negedge dqs_in[32]) dqs_neg_timing_check(32); + always @(negedge dqs_in[33]) dqs_neg_timing_check(33); + always @(negedge dqs_in[34]) dqs_neg_timing_check(34); + always @(negedge dqs_in[35]) dqs_neg_timing_check(35); + + task dqs_neg_timing_check; + input i; + reg [5:0] i; + reg [3:0] j; + begin + if (dqs_in_valid && (wdqs_pos_cntr[i] > 0) && check_write_dqs_high[i] && (dqs_n_en || i < 18)) begin + if (dqs_in[i] ^ prev_dqs_in[i]) begin + if (dll_locked) begin + if ($time - tm_dqs_pos[i] < $rtoi(TDQSH*tck_avg)) + $display ("%m: at time %t ERROR: tDQSH violation on %s bit %d", $time, dqs_string[i/18], i%18); + if ($time - tm_ck_pos < $rtoi(TDSH*tck_avg)) + $display ("%m: at time %t ERROR: tDSH violation on %s bit %d", $time, dqs_string[i/18], i%18); + end + if ($time - tm_dm[i%18] < TDS) + $display ("%m: at time %t ERROR: tDS violation on DM bit %d by %t", $time, i, tm_dm[i%18] + TDS - $time); + if (!dq_out_en) begin + for (j=0; j<`DQ_PER_DQS; j=j+1) begin + if ($time - tm_dq[i*`DQ_PER_DQS+j] < TDS) + $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); + check_dq_tdipw[i*`DQ_PER_DQS+j] <= 1'b1; + end + end + check_dm_tdipw[i%18] <= 1'b1; + check_write_dqs_high[i] <= 1'b0; + tm_dqs[i%18] <= $time; + end else begin + $display ("%m: at time %t ERROR: Invalid latching edge on %s bit %d", $time, dqs_string[i/18], i%18); + end + end + tm_dqs_neg[i] = $time; + prev_dqs_in[i] <= dqs_in[i]; + end + endtask + + always @(negedge dqs_in[ 0]) dqs_neg_timing_check( 0); + always @(negedge dqs_in[ 1]) dqs_neg_timing_check( 1); + always @(negedge dqs_in[ 2]) dqs_neg_timing_check( 2); + always @(negedge dqs_in[ 3]) dqs_neg_timing_check( 3); + always @(negedge dqs_in[ 4]) dqs_neg_timing_check( 4); + always @(negedge dqs_in[ 5]) dqs_neg_timing_check( 5); + always @(negedge dqs_in[ 6]) dqs_neg_timing_check( 6); + always @(negedge dqs_in[ 7]) dqs_neg_timing_check( 7); + always @(negedge dqs_in[ 8]) dqs_neg_timing_check( 8); + always @(negedge dqs_in[ 9]) dqs_neg_timing_check( 9); + always @(negedge dqs_in[10]) dqs_neg_timing_check(10); + always @(negedge dqs_in[11]) dqs_neg_timing_check(11); + always @(negedge dqs_in[12]) dqs_neg_timing_check(12); + always @(negedge dqs_in[13]) dqs_neg_timing_check(13); + always @(negedge dqs_in[14]) dqs_neg_timing_check(14); + always @(negedge dqs_in[15]) dqs_neg_timing_check(15); + always @(negedge dqs_in[16]) dqs_neg_timing_check(16); + always @(negedge dqs_in[17]) dqs_neg_timing_check(17); + always @(posedge dqs_in[18]) dqs_neg_timing_check(18); + always @(posedge dqs_in[19]) dqs_neg_timing_check(19); + always @(posedge dqs_in[20]) dqs_neg_timing_check(20); + always @(posedge dqs_in[21]) dqs_neg_timing_check(21); + always @(posedge dqs_in[22]) dqs_neg_timing_check(22); + always @(posedge dqs_in[23]) dqs_neg_timing_check(23); + always @(posedge dqs_in[24]) dqs_neg_timing_check(24); + always @(posedge dqs_in[25]) dqs_neg_timing_check(25); + always @(posedge dqs_in[26]) dqs_neg_timing_check(26); + always @(posedge dqs_in[27]) dqs_neg_timing_check(27); + always @(posedge dqs_in[28]) dqs_neg_timing_check(28); + always @(posedge dqs_in[29]) dqs_neg_timing_check(29); + always @(posedge dqs_in[30]) dqs_neg_timing_check(30); + always @(posedge dqs_in[31]) dqs_neg_timing_check(31); + always @(posedge dqs_in[32]) dqs_neg_timing_check(32); + always @(posedge dqs_in[33]) dqs_neg_timing_check(33); + always @(posedge dqs_in[34]) dqs_neg_timing_check(34); + always @(posedge dqs_in[35]) dqs_neg_timing_check(35); + +endmodule diff --git a/sim/verilog/micron_2048Mb_ddr2/ddr2_mcp.v b/sim/verilog/micron_2048Mb_ddr2/ddr2_mcp.v new file mode 100644 index 0000000..38e04bb --- /dev/null +++ b/sim/verilog/micron_2048Mb_ddr2/ddr2_mcp.v @@ -0,0 +1,94 @@ +/**************************************************************************************** +* +* File Name: ddr2_mcp.v +* +* Dependencies: ddr2.v, ddr2_parameters.vh +* +* Description: Micron SDRAM DDR2 (Double Data Rate 2) multi-chip package model +* +* Disclaimer This software code and all associated documentation, comments or other +* of Warranty: information (collectively "Software") is provided "AS IS" without +* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY +* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES +* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT +* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE +* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. +* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR +* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE +* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, +* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, +* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, +* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, +* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE +* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGES. Because some jurisdictions prohibit the exclusion or +* limitation of liability for consequential or incidental damages, the +* above limitation may not apply to you. +* +* Copyright 2003 Micron Technology, Inc. All rights reserved. +* +****************************************************************************************/ + `timescale 1ps / 1ps + +module ddr2_mcp ( + ck, + ck_n, + cke, + cs_n, + ras_n, + cas_n, + we_n, + dm_rdqs, + ba, + addr, + dq, + dqs, + dqs_n, + rdqs_n, + odt +); + + `include "ddr2_parameters.vh" + + // Declare Ports + input ck; + input ck_n; + input [CS_BITS-1:0] cke; + input [CS_BITS-1:0] cs_n; + input ras_n; + input cas_n; + input we_n; + inout [DM_BITS-1:0] dm_rdqs; + input [BA_BITS-1:0] ba; + input [ADDR_BITS-1:0] addr; + inout [DQ_BITS-1:0] dq; + inout [DQS_BITS-1:0] dqs; + inout [DQS_BITS-1:0] dqs_n; + output [DQS_BITS-1:0] rdqs_n; + input [CS_BITS-1:0] odt; + + wire [RANKS-1:0] cke_mcp = cke; + wire [RANKS-1:0] cs_n_mcp = cs_n; + wire [RANKS-1:0] odt_mcp = odt; + + ddr2 rank [RANKS-1:0] ( + ck, + ck_n, + cke_mcp, + cs_n_mcp, + ras_n, + cas_n, + we_n, + dm_rdqs, + ba, + addr, + dq, + dqs, + dqs_n, + rdqs_n, + odt_mcp + ); + +endmodule diff --git a/sim/verilog/micron_2048Mb_ddr2/ddr2_module.v b/sim/verilog/micron_2048Mb_ddr2/ddr2_module.v new file mode 100644 index 0000000..2fd45be --- /dev/null +++ b/sim/verilog/micron_2048Mb_ddr2/ddr2_module.v @@ -0,0 +1,377 @@ +/**************************************************************************************** +* +* File Name: ddr2_module.v +* +* Dependencies: ddr2.v, ddr2.v, ddr2_parameters.vh +* +* Description: Micron SDRAM DDR2 (Double Data Rate 2) module model +* +* Limitation: - SPD (Serial Presence-Detect) is not modeled +* +* Disclaimer This software code and all associated documentation, comments or other +* of Warranty: information (collectively "Software") is provided "AS IS" without +* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY +* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES +* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT +* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE +* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. +* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR +* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE +* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, +* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, +* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, +* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, +* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE +* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGES. Because some jurisdictions prohibit the exclusion or +* limitation of liability for consequential or incidental damages, the +* above limitation may not apply to you. +* +* Copyright 2003 Micron Technology, Inc. All rights reserved. +* +* Rev Author Date Changes +* --------------------------------------------------------------------------------------- +* 1.00 SPH 09/18/09 Fixed cb connection in ECC mode +* Added invalid ECC mode error message in x16 configuration +****************************************************************************************/ + `timescale 1ps / 1ps + +module ddr2_module ( +`ifdef SODIMM +`else + reset_n, + cb , +`endif + ck , + ck_n , + cke , + s_n , + ras_n , + cas_n , + we_n , + ba , + addr , + odt , + dqs , + dqs_n , + dq , + scl , + sa , + sda +); + +`include "ddr2_parameters.vh" + + input [1:0] cke ; + input ras_n ; + input cas_n ; + input we_n ; + input [2:0] ba ; + input [15:0] addr ; + input [1:0] odt ; + inout [17:0] dqs ; + inout [17:0] dqs_n ; + inout [63:0] dq ; + input scl ; // no connect + inout sda ; // no connect + +`ifdef QUAD_RANK + initial if (DEBUG) $display("%m: Quad Rank"); +`else `ifdef DUAL_RANK + initial if (DEBUG) $display("%m: Dual Rank"); +`else + initial if (DEBUG) $display("%m: Single Rank"); +`endif `endif + +`ifdef ECC + initial if (DEBUG) $display("%m: ECC"); + `ifdef SODIMM + initial begin + $display("%m ERROR: ECC is not available on SODIMM configurations"); + if (STOP_ON_ERROR) $stop(0); + end + `endif + `ifdef x16 + initial begin + $display("%m ERROR: ECC is not available on x16 configurations"); + if (STOP_ON_ERROR) $stop(0); + end + `endif +`else + initial if (DEBUG) $display("%m: non ECC"); +`endif + +`ifdef RDIMM + initial if (DEBUG) $display("%m: RDIMM"); + input reset_n; + input ck ; + input ck_n ; + input [3:0] s_n ; + inout [7:0] cb ; + input [2:0] sa ; // no connect + + wire [5:0] rck = {6{ck}}; + wire [5:0] rck_n = {6{ck_n}}; + reg [3:0] rs_n ; + reg rras_n ; + reg rcas_n ; + reg rwe_n ; + reg [2:0] rba ; + reg [15:0] raddr ; + reg [3:0] rcke ; + reg [3:0] rodt ; + + always @(negedge reset_n or posedge ck) begin + if (!reset_n) begin + rs_n <= #(500) 0; + rras_n <= #(500) 0; + rcas_n <= #(500) 0; + rwe_n <= #(500) 0; + rba <= #(500) 0; + raddr <= #(500) 0; + rcke <= #(500) 0; + rodt <= #(500) 0; + end else begin + rs_n <= #(500) s_n ; + rras_n <= #(500) ras_n; + rcas_n <= #(500) cas_n; + rwe_n <= #(500) we_n ; + rba <= #(500) ba ; + raddr <= #(500) addr ; + `ifdef QUAD_RANK + rcke <= #(500) {{2{cke[1]}}, {2{cke[0]}}}; + rodt <= #(500) {{2{odt[1]}}, {2{odt[0]}}}; + `else + rcke <= #(500) {2'b00, cke}; + rodt <= #(500) {2'b00, odt}; + `endif + + end + end +`else + `ifdef SODIMM + initial if (DEBUG) $display("%m: SODIMM"); + input [1:0] ck ; + input [1:0] ck_n ; + input [1:0] s_n ; + input [1:0] sa ; // no connect + + wire [7:0] cb; + wire [5:0] rck = {{3{ck[1]}}, {3{ck[0]}}}; + wire [5:0] rck_n = {{3{ck_n[1]}}, {3{ck_n[0]}}}; + `else + initial if (DEBUG) $display("%m: UDIMM"); + input reset_n; + input [2:0] ck ; + input [2:0] ck_n ; + input [1:0] s_n ; + inout [7:0] cb ; + input [2:0] sa ; // no connect + + wire [5:0] rck = {2{ck}}; + wire [5:0] rck_n = {2{ck_n}}; + `endif + + wire [2:0] rba = ba ; + wire [15:0] raddr = addr ; + wire rras_n = ras_n; + wire rcas_n = cas_n; + wire rwe_n = we_n ; + `ifdef QUAD_RANK + wire [3:0] rs_n = {{2{s_n[1]}}, {2{s_n[0]}}}; + wire [3:0] rcke = {{2{cke[1]}}, {2{cke[0]}}}; + wire [3:0] rodt = {{2{odt[1]}}, {2{odt[0]}}}; + `else + wire [3:0] rs_n = {2'b00, s_n}; + wire [3:0] rcke = {2'b00, cke}; + wire [3:0] rodt = {2'b00, odt}; + `endif +`endif + wire [15:0] rcb = {8'b0, cb}; + wire zero = 1'b0; + wire one = 1'b1; + + //ddr2 (ck , ck_n , cke , cs_n , ras_n , cas_n , we_n , dm_rdqs , ba , addr , dq , dqs , dqs_n , rdqs_n , odt ); +`ifdef x4 + initial if (DEBUG) $display("%m: Component Width = x4"); + ddr2 U1R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [ 3: 0], dqs[ 0] , dqs_n[ 0], , rodt[0]); + ddr2 U2R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [11: 8], dqs[ 1] , dqs_n[ 1], , rodt[0]); + ddr2 U3R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [19:16], dqs[ 2] , dqs_n[ 2], , rodt[0]); + ddr2 U4R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [27:24], dqs[ 3] , dqs_n[ 3], , rodt[0]); + ddr2 U6R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [35:32], dqs[ 4] , dqs_n[ 4], , rodt[0]); + ddr2 U7R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [43:40], dqs[ 5] , dqs_n[ 5], , rodt[0]); + ddr2 U8R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [51:48], dqs[ 6] , dqs_n[ 6], , rodt[0]); + ddr2 U9R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [59:56], dqs[ 7] , dqs_n[ 7], , rodt[0]); + `ifdef ECC + ddr2 U5R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], cb [ 3: 0], dqs[ 8] , dqs_n[ 8], , rodt[0]); + `endif + ddr2 U18R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [ 7: 4], dqs[ 9] , dqs_n[ 9], , rodt[0]); + ddr2 U17R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [15:12], dqs[ 10] , dqs_n[ 10], , rodt[0]); + ddr2 U16R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [23:20], dqs[ 11] , dqs_n[ 11], , rodt[0]); + ddr2 U15R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [31:28], dqs[ 12] , dqs_n[ 12], , rodt[0]); + ddr2 U13R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [39:36], dqs[ 13] , dqs_n[ 13], , rodt[0]); + ddr2 U12R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [47:44], dqs[ 14] , dqs_n[ 14], , rodt[0]); + ddr2 U11R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [55:52], dqs[ 15] , dqs_n[ 15], , rodt[0]); + ddr2 U10R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [63:60], dqs[ 16] , dqs_n[ 16], , rodt[0]); + `ifdef ECC + ddr2 U14R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], cb [ 7: 4], dqs[ 17] , dqs_n[ 17], , rodt[0]); + `endif + `ifdef DUAL_RANK + ddr2 U1R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [ 3: 0], dqs[ 0] , dqs_n[ 0], , rodt[1]); + ddr2 U2R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [11: 8], dqs[ 1] , dqs_n[ 1], , rodt[1]); + ddr2 U3R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [19:16], dqs[ 2] , dqs_n[ 2], , rodt[1]); + ddr2 U4R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [27:24], dqs[ 3] , dqs_n[ 3], , rodt[1]); + ddr2 U6R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [35:32], dqs[ 4] , dqs_n[ 4], , rodt[1]); + ddr2 U7R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [43:40], dqs[ 5] , dqs_n[ 5], , rodt[1]); + ddr2 U8R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [51:48], dqs[ 6] , dqs_n[ 6], , rodt[1]); + ddr2 U9R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [59:56], dqs[ 7] , dqs_n[ 7], , rodt[1]); + `ifdef ECC + ddr2 U5R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], cb [ 3: 0], dqs[ 8] , dqs_n[ 8], , rodt[1]); + `endif + ddr2 U18R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [ 7: 4], dqs[ 9] , dqs_n[ 9], , rodt[1]); + ddr2 U17R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [15:12], dqs[ 10] , dqs_n[ 10], , rodt[1]); + ddr2 U16R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [23:20], dqs[ 11] , dqs_n[ 11], , rodt[1]); + ddr2 U15R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [31:28], dqs[ 12] , dqs_n[ 12], , rodt[1]); + ddr2 U13R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [39:36], dqs[ 13] , dqs_n[ 13], , rodt[1]); + ddr2 U12R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [47:44], dqs[ 14] , dqs_n[ 14], , rodt[1]); + ddr2 U11R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [55:52], dqs[ 15] , dqs_n[ 15], , rodt[1]); + ddr2 U10R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [63:60], dqs[ 16] , dqs_n[ 16], , rodt[1]); + `ifdef ECC + ddr2 U14R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], cb [ 7: 4], dqs[ 17] , dqs_n[ 17], , rodt[1]); + `endif + `endif + `ifdef QUAD_RANK + ddr2 U1R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [ 3: 0], dqs[ 0] , dqs_n[ 0], , rodt[2]); + ddr2 U2R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [11: 8], dqs[ 1] , dqs_n[ 1], , rodt[2]); + ddr2 U3R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [19:16], dqs[ 2] , dqs_n[ 2], , rodt[2]); + ddr2 U4R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [27:24], dqs[ 3] , dqs_n[ 3], , rodt[2]); + ddr2 U6R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [35:32], dqs[ 4] , dqs_n[ 4], , rodt[2]); + ddr2 U7R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [43:40], dqs[ 5] , dqs_n[ 5], , rodt[2]); + ddr2 U8R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [51:48], dqs[ 6] , dqs_n[ 6], , rodt[2]); + ddr2 U9R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [59:56], dqs[ 7] , dqs_n[ 7], , rodt[2]); + `ifdef ECC + ddr2 U5R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], cb [ 3: 0], dqs[ 8] , dqs_n[ 8], , rodt[2]); + `endif + ddr2 U18R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [ 7: 4], dqs[ 9] , dqs_n[ 9], , rodt[2]); + ddr2 U17R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [15:12], dqs[ 10] , dqs_n[ 10], , rodt[2]); + ddr2 U16R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [23:20], dqs[ 11] , dqs_n[ 11], , rodt[2]); + ddr2 U15R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [31:28], dqs[ 12] , dqs_n[ 12], , rodt[2]); + ddr2 U13R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [39:36], dqs[ 13] , dqs_n[ 13], , rodt[2]); + ddr2 U12R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [47:44], dqs[ 14] , dqs_n[ 14], , rodt[2]); + ddr2 U11R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [55:52], dqs[ 15] , dqs_n[ 15], , rodt[2]); + ddr2 U10R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [63:60], dqs[ 16] , dqs_n[ 16], , rodt[2]); + `ifdef ECC + ddr2 U14R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], cb [ 7: 4], dqs[ 17] , dqs_n[ 17], , rodt[2]); + `endif + ddr2 U1R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [ 3: 0], dqs[ 0] , dqs_n[ 0], , rodt[3]); + ddr2 U2R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [11: 8], dqs[ 1] , dqs_n[ 1], , rodt[3]); + ddr2 U3R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [19:16], dqs[ 2] , dqs_n[ 2], , rodt[3]); + ddr2 U4R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [27:24], dqs[ 3] , dqs_n[ 3], , rodt[3]); + ddr2 U6R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [35:32], dqs[ 4] , dqs_n[ 4], , rodt[3]); + ddr2 U7R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [43:40], dqs[ 5] , dqs_n[ 5], , rodt[3]); + ddr2 U8R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [51:48], dqs[ 6] , dqs_n[ 6], , rodt[3]); + ddr2 U9R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [59:56], dqs[ 7] , dqs_n[ 7], , rodt[3]); + `ifdef ECC + ddr2 U5R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], cb [ 3: 0], dqs[ 8] , dqs_n[ 8], , rodt[3]); + `endif + ddr2 U18R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [ 7: 4], dqs[ 9] , dqs_n[ 9], , rodt[3]); + ddr2 U17R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [15:12], dqs[ 10] , dqs_n[ 10], , rodt[3]); + ddr2 U16R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [23:20], dqs[ 11] , dqs_n[ 11], , rodt[3]); + ddr2 U15R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [31:28], dqs[ 12] , dqs_n[ 12], , rodt[3]); + ddr2 U13R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [39:36], dqs[ 13] , dqs_n[ 13], , rodt[3]); + ddr2 U12R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [47:44], dqs[ 14] , dqs_n[ 14], , rodt[3]); + ddr2 U11R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [55:52], dqs[ 15] , dqs_n[ 15], , rodt[3]); + ddr2 U10R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], dq [63:60], dqs[ 16] , dqs_n[ 16], , rodt[3]); + `ifdef ECC + ddr2 U14R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, zero , rba, raddr[ADDR_BITS-1:0], cb [ 7: 4], dqs[ 17] , dqs_n[ 17], , rodt[3]); + `endif + `endif +`else `ifdef x8 + initial if (DEBUG) $display("%m: Component Width = x8"); + ddr2 U1R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[ 9] , rba, raddr[ADDR_BITS-1:0], dq [ 7: 0], dqs[ 0] , dqs_n[ 0], dqs_n[ 9], rodt[0]); + ddr2 U2R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[10] , rba, raddr[ADDR_BITS-1:0], dq [15: 8], dqs[ 1] , dqs_n[ 1], dqs_n[10], rodt[0]); + ddr2 U3R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[11] , rba, raddr[ADDR_BITS-1:0], dq [23:16], dqs[ 2] , dqs_n[ 2], dqs_n[11], rodt[0]); + ddr2 U4R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[12] , rba, raddr[ADDR_BITS-1:0], dq [31:24], dqs[ 3] , dqs_n[ 3], dqs_n[12], rodt[0]); + ddr2 U6R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[13] , rba, raddr[ADDR_BITS-1:0], dq [39:32], dqs[ 4] , dqs_n[ 4], dqs_n[13], rodt[0]); + ddr2 U7R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[14] , rba, raddr[ADDR_BITS-1:0], dq [47:40], dqs[ 5] , dqs_n[ 5], dqs_n[14], rodt[0]); + ddr2 U8R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[15] , rba, raddr[ADDR_BITS-1:0], dq [55:48], dqs[ 6] , dqs_n[ 6], dqs_n[15], rodt[0]); + ddr2 U9R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[16] , rba, raddr[ADDR_BITS-1:0], dq [63:56], dqs[ 7] , dqs_n[ 7], dqs_n[16], rodt[0]); + `ifdef ECC + ddr2 U5R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[17] , rba, raddr[ADDR_BITS-1:0], cb [ 7: 0], dqs[ 8] , dqs_n[ 8], dqs_n[17], rodt[0]); + `endif + `ifdef DUAL_RANK + ddr2 U1R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[ 9] , rba, raddr[ADDR_BITS-1:0], dq [ 7: 0], dqs[ 0] , dqs_n[ 0], dqs_n[ 9], rodt[1]); + ddr2 U2R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[10] , rba, raddr[ADDR_BITS-1:0], dq [15: 8], dqs[ 1] , dqs_n[ 1], dqs_n[10], rodt[1]); + ddr2 U3R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[11] , rba, raddr[ADDR_BITS-1:0], dq [23:16], dqs[ 2] , dqs_n[ 2], dqs_n[11], rodt[1]); + ddr2 U4R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[12] , rba, raddr[ADDR_BITS-1:0], dq [31:24], dqs[ 3] , dqs_n[ 3], dqs_n[12], rodt[1]); + ddr2 U6R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[13] , rba, raddr[ADDR_BITS-1:0], dq [39:32], dqs[ 4] , dqs_n[ 4], dqs_n[13], rodt[1]); + ddr2 U7R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[14] , rba, raddr[ADDR_BITS-1:0], dq [47:40], dqs[ 5] , dqs_n[ 5], dqs_n[14], rodt[1]); + ddr2 U8R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[15] , rba, raddr[ADDR_BITS-1:0], dq [55:48], dqs[ 6] , dqs_n[ 6], dqs_n[15], rodt[1]); + ddr2 U9R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[16] , rba, raddr[ADDR_BITS-1:0], dq [63:56], dqs[ 7] , dqs_n[ 7], dqs_n[16], rodt[1]); + `ifdef ECC + ddr2 U5R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[17] , rba, raddr[ADDR_BITS-1:0], cb [ 7: 0], dqs[ 8] , dqs_n[ 8], dqs_n[17], rodt[1]); + `endif + `endif + `ifdef QUAD_RANK + ddr2 U1R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[ 9] , rba, raddr[ADDR_BITS-1:0], dq [ 7: 0], dqs[ 0] , dqs_n[ 0], dqs_n[ 9], rodt[2]); + ddr2 U2R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[10] , rba, raddr[ADDR_BITS-1:0], dq [15: 8], dqs[ 1] , dqs_n[ 1], dqs_n[10], rodt[2]); + ddr2 U3R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[11] , rba, raddr[ADDR_BITS-1:0], dq [23:16], dqs[ 2] , dqs_n[ 2], dqs_n[11], rodt[2]); + ddr2 U4R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[12] , rba, raddr[ADDR_BITS-1:0], dq [31:24], dqs[ 3] , dqs_n[ 3], dqs_n[12], rodt[2]); + ddr2 U6R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[13] , rba, raddr[ADDR_BITS-1:0], dq [39:32], dqs[ 4] , dqs_n[ 4], dqs_n[13], rodt[2]); + ddr2 U7R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[14] , rba, raddr[ADDR_BITS-1:0], dq [47:40], dqs[ 5] , dqs_n[ 5], dqs_n[14], rodt[2]); + ddr2 U8R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[15] , rba, raddr[ADDR_BITS-1:0], dq [55:48], dqs[ 6] , dqs_n[ 6], dqs_n[15], rodt[2]); + ddr2 U9R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[16] , rba, raddr[ADDR_BITS-1:0], dq [63:56], dqs[ 7] , dqs_n[ 7], dqs_n[16], rodt[2]); + `ifdef ECC + ddr2 U5R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[17] , rba, raddr[ADDR_BITS-1:0], cb [ 7: 0], dqs[ 8] , dqs_n[ 8], dqs_n[17], rodt[2]); + `endif + ddr2 U1R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[ 9] , rba, raddr[ADDR_BITS-1:0], dq [ 7: 0], dqs[ 0] , dqs_n[ 0], dqs_n[ 9], rodt[3]); + ddr2 U2R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[10] , rba, raddr[ADDR_BITS-1:0], dq [15: 8], dqs[ 1] , dqs_n[ 1], dqs_n[10], rodt[3]); + ddr2 U3R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[11] , rba, raddr[ADDR_BITS-1:0], dq [23:16], dqs[ 2] , dqs_n[ 2], dqs_n[11], rodt[3]); + ddr2 U4R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[12] , rba, raddr[ADDR_BITS-1:0], dq [31:24], dqs[ 3] , dqs_n[ 3], dqs_n[12], rodt[3]); + ddr2 U6R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[13] , rba, raddr[ADDR_BITS-1:0], dq [39:32], dqs[ 4] , dqs_n[ 4], dqs_n[13], rodt[3]); + ddr2 U7R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[14] , rba, raddr[ADDR_BITS-1:0], dq [47:40], dqs[ 5] , dqs_n[ 5], dqs_n[14], rodt[3]); + ddr2 U8R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[15] , rba, raddr[ADDR_BITS-1:0], dq [55:48], dqs[ 6] , dqs_n[ 6], dqs_n[15], rodt[3]); + ddr2 U9R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[16] , rba, raddr[ADDR_BITS-1:0], dq [63:56], dqs[ 7] , dqs_n[ 7], dqs_n[16], rodt[3]); + `ifdef ECC + ddr2 U5R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[17] , rba, raddr[ADDR_BITS-1:0], cb [ 7: 0], dqs[ 8] , dqs_n[ 8], dqs_n[17], rodt[3]); + `endif + `endif +`else `ifdef x16 + initial if (DEBUG) $display("%m: Component Width = x16"); + ddr2 U1R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[10: 9] , rba, raddr[ADDR_BITS-1:0], dq [15: 0], dqs[1:0] , dqs_n[1:0], , rodt[0]); + ddr2 U2R0 (rck[1], rck_n[1], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[12:11] , rba, raddr[ADDR_BITS-1:0], dq [31:16], dqs[3:2] , dqs_n[3:2], , rodt[0]); + ddr2 U4R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[14:13] , rba, raddr[ADDR_BITS-1:0], dq [47:32], dqs[5:4] , dqs_n[5:4], , rodt[0]); + ddr2 U5R0 (rck[2], rck_n[2], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[16:15] , rba, raddr[ADDR_BITS-1:0], dq [63:48], dqs[7:6] , dqs_n[7:6], , rodt[0]); + `ifdef ECC + ddr2 U3R0 (rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, {one, dqs[17]}, rba, raddr[ADDR_BITS-1:0], rcb[15: 0], {zero, dqs[8]}, {one, dqs_n[8]}, , rodt[0]); + `endif + `ifdef DUAL_RANK + ddr2 U1R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[10: 9] , rba, raddr[ADDR_BITS-1:0], dq [15: 0], dqs[1:0] , dqs_n[1:0], , rodt[1]); + ddr2 U2R1 (rck[4], rck_n[4], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[12:11] , rba, raddr[ADDR_BITS-1:0], dq [31:16], dqs[3:2] , dqs_n[3:2], , rodt[1]); + ddr2 U4R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[14:13] , rba, raddr[ADDR_BITS-1:0], dq [47:32], dqs[5:4] , dqs_n[5:4], , rodt[1]); + ddr2 U5R1 (rck[5], rck_n[5], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, dqs[16:15] , rba, raddr[ADDR_BITS-1:0], dq [63:48], dqs[7:6] , dqs_n[7:6], , rodt[1]); + `ifdef ECC + ddr2 U3R1 (rck[3], rck_n[3], rcke[1], rs_n[1], rras_n, rcas_n, rwe_n, {one, dqs[17]}, rba, raddr[ADDR_BITS-1:0], rcb[15: 0], {zero, dqs[8]}, {one, dqs_n[8]}, , rodt[1]); + `endif + `endif + `ifdef QUAD_RANK + ddr2 U1R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[10: 9] , rba, raddr[ADDR_BITS-1:0], dq [15: 0], dqs[1:0] , dqs_n[1:0], , rodt[2]); + ddr2 U2R2 (rck[1], rck_n[1], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[12:11] , rba, raddr[ADDR_BITS-1:0], dq [31:16], dqs[3:2] , dqs_n[3:2], , rodt[2]); + ddr2 U4R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[14:13] , rba, raddr[ADDR_BITS-1:0], dq [47:32], dqs[5:4] , dqs_n[5:4], , rodt[2]); + ddr2 U5R2 (rck[2], rck_n[2], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, dqs[16:15] , rba, raddr[ADDR_BITS-1:0], dq [63:48], dqs[7:6] , dqs_n[7:6], , rodt[2]); + `ifdef ECC + ddr2 U3R2 (rck[0], rck_n[0], rcke[2], rs_n[2], rras_n, rcas_n, rwe_n, {one, dqs[17]}, rba, raddr[ADDR_BITS-1:0], rcb[15: 0], {zero, dqs[8]}, {one, dqs_n[8]}, , rodt[2]); + `endif + ddr2 U1R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[10: 9] , rba, raddr[ADDR_BITS-1:0], dq [15: 0], dqs[1:0] , dqs_n[1:0], , rodt[3]); + ddr2 U2R3 (rck[4], rck_n[4], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[12:11] , rba, raddr[ADDR_BITS-1:0], dq [31:16], dqs[3:2] , dqs_n[3:2], , rodt[3]); + ddr2 U4R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[14:13] , rba, raddr[ADDR_BITS-1:0], dq [47:32], dqs[5:4] , dqs_n[5:4], , rodt[3]); + ddr2 U5R3 (rck[5], rck_n[5], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, dqs[16:15] , rba, raddr[ADDR_BITS-1:0], dq [63:48], dqs[7:6] , dqs_n[7:6], , rodt[3]); + `ifdef ECC + ddr2 U3R3 (rck[3], rck_n[3], rcke[3], rs_n[3], rras_n, rcas_n, rwe_n, {one, dqs[17]}, rba, raddr[ADDR_BITS-1:0], rcb[15: 0], {zero, dqs[8]}, {one, dqs_n[8]}, , rodt[3]); + `endif + `endif +`endif `endif `endif + +endmodule diff --git a/sim/verilog/micron_2048Mb_ddr2/ddr2_parameters.vh b/sim/verilog/micron_2048Mb_ddr2/ddr2_parameters.vh new file mode 100644 index 0000000..4e4d866 --- /dev/null +++ b/sim/verilog/micron_2048Mb_ddr2/ddr2_parameters.vh @@ -0,0 +1,383 @@ +/**************************************************************************************** +* +* Disclaimer This software code and all associated documentation, comments or other +* of Warranty: information (collectively "Software") is provided "AS IS" without +* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY +* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES +* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT +* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE +* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. +* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR +* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE +* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, +* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, +* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, +* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, +* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE +* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGES. Because some jurisdictions prohibit the exclusion or +* limitation of liability for consequential or incidental damages, the +* above limitation may not apply to you. +* +* Copyright 2003 Micron Technology, Inc. All rights reserved. +* +****************************************************************************************/ + + // Parameters current with 2Gb datasheet rev B + + // Timing parameters based on Speed Grade + + // SYMBOL UNITS DESCRIPTION + // ------ ----- ----------- +`ifdef sg187E + parameter TCK_MIN = 1875; // tCK ps Minimum Clock Cycle Time + parameter TJIT_PER = 90; // tJIT(per) ps Period JItter + parameter TJIT_DUTY = 75; // tJIT(duty) ps Half Period Jitter + parameter TJIT_CC = 180; // tJIT(cc) ps Cycle to Cycle jitter + parameter TERR_2PER = 132; // tERR(nper) ps Accumulated Error (2-cycle) + parameter TERR_3PER = 157; // tERR(nper) ps Accumulated Error (3-cycle) + parameter TERR_4PER = 175; // tERR(nper) ps Accumulated Error (4-cycle) + parameter TERR_5PER = 188; // tERR(nper) ps Accumulated Error (5-cycle) + parameter TERR_N1PER = 250; // tERR(nper) ps Accumulated Error (6-10-cycle) + parameter TERR_N2PER = 425; // tERR(nper) ps Accumulated Error (11-50-cycle) + parameter TQHS = 250; // tQHS ps Data hold skew factor + parameter TAC = 350; // tAC ps DQ output access time from CK/CK# + parameter TDS = 0; // tDS ps DQ and DM input setup time relative to DQS + parameter TDH = 75; // tDH ps DQ and DM input hold time relative to DQS + parameter TDQSCK = 300; // tDQSCK ps DQS output access time from CK/CK# + parameter TDQSQ = 175; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access + parameter TIS = 125; // tIS ps Input Setup Time + parameter TIH = 200; // tIH ps Input Hold Time + parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time + parameter TRCD = 13125; // tRCD ps Active to Read/Write command time + parameter TWTR = 7500; // tWTR ps Write to Read command delay + parameter TRP = 13125; // tRP ps Precharge command period + parameter TRPA = 15000; // tRPA ps Precharge All period + parameter TXARDS = 10; // tXARDS tCK Exit low power active power down to a read command + parameter TXARD = 3; // tXARD tCK Exit active power down to a read command + parameter TXP = 3; // tXP tCK Exit power down to a non-read command + parameter TANPD = 4; // tANPD tCK ODT to power-down entry latency + parameter TAXPD = 11; // tAXPD tCK ODT power-down exit latency + parameter CL_TIME = 13125; // CL ps Minimum CAS Latency +`else `ifdef sg25E + parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time + parameter TJIT_PER = 100; // tJIT(per) ps Period JItter + parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter + parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter + parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) + parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) + parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) + parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) + parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) + parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) + parameter TQHS = 300; // tQHS ps Data hold skew factor + parameter TAC = 400; // tAC ps DQ output access time from CK/CK# + parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS + parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS + parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# + parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access + parameter TIS = 175; // tIS ps Input Setup Time + parameter TIH = 250; // tIH ps Input Hold Time + parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time + parameter TRCD = 12500; // tRCD ps Active to Read/Write command time + parameter TWTR = 7500; // tWTR ps Write to Read command delay + parameter TRP = 12500; // tRP ps Precharge command period + parameter TRPA = 15000; // tRPA ps Precharge All period + parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command + parameter TXARD = 2; // tXARD tCK Exit active power down to a read command + parameter TXP = 2; // tXP tCK Exit power down to a non-read command + parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency + parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency + parameter CL_TIME = 12500; // CL ps Minimum CAS Latency +`else `ifdef sg25 + parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time + parameter TJIT_PER = 100; // tJIT(per) ps Period JItter + parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter + parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter + parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) + parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) + parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) + parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) + parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) + parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) + parameter TQHS = 300; // tQHS ps Data hold skew factor + parameter TAC = 400; // tAC ps DQ output access time from CK/CK# + parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS + parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS + parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# + parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access + parameter TIS = 175; // tIS ps Input Setup Time + parameter TIH = 250; // tIH ps Input Hold Time + parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time + parameter TRCD = 15000; // tRCD ps Active to Read/Write command time + parameter TWTR = 7500; // tWTR ps Write to Read command delay + parameter TRP = 15000; // tRP ps Precharge command period + parameter TRPA = 17500; // tRPA ps Precharge All period + parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command + parameter TXARD = 2; // tXARD tCK Exit active power down to a read command + parameter TXP = 2; // tXP tCK Exit power down to a non-read command + parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency + parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency + parameter CL_TIME = 15000; // CL ps Minimum CAS Latency +`else `ifdef sg3E + parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time + parameter TJIT_PER = 125; // tJIT(per) ps Period JItter + parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter + parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter + parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) + parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) + parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) + parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) + parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) + parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) + parameter TQHS = 340; // tQHS ps Data hold skew factor + parameter TAC = 450; // tAC ps DQ output access time from CK/CK# + parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS + parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS + parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# + parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access + parameter TIS = 200; // tIS ps Input Setup Time + parameter TIH = 275; // tIH ps Input Hold Time + parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time + parameter TRCD = 12000; // tRCD ps Active to Read/Write command time + parameter TWTR = 7500; // tWTR ps Write to Read command delay + parameter TRP = 12000; // tRP ps Precharge command period + parameter TRPA = 15000; // tRPA ps Precharge All period + parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command + parameter TXARD = 2; // tXARD tCK Exit active power down to a read command + parameter TXP = 2; // tXP tCK Exit power down to a non-read command + parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency + parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency + parameter CL_TIME = 12000; // CL ps Minimum CAS Latency +`else `ifdef sg3 + parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time + parameter TJIT_PER = 125; // tJIT(per) ps Period JItter + parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter + parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter + parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) + parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) + parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) + parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) + parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) + parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) + parameter TQHS = 340; // tQHS ps Data hold skew factor + parameter TAC = 450; // tAC ps DQ output access time from CK/CK# + parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS + parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS + parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# + parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access + parameter TIS = 200; // tIS ps Input Setup Time + parameter TIH = 275; // tIH ps Input Hold Time + parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time + parameter TRCD = 15000; // tRCD ps Active to Read/Write command time + parameter TWTR = 7500; // tWTR ps Write to Read command delay + parameter TRP = 15000; // tRP ps Precharge command period + parameter TRPA = 18000; // tRPA ps Precharge All period + parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command + parameter TXARD = 2; // tXARD tCK Exit active power down to a read command + parameter TXP = 2; // tXP tCK Exit power down to a non-read command + parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency + parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency + parameter CL_TIME = 15000; // CL ps Minimum CAS Latency +`else `ifdef sg37E + parameter TCK_MIN = 3750; // tCK ps Minimum Clock Cycle Time + parameter TJIT_PER = 125; // tJIT(per) ps Period JItter + parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter + parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter + parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) + parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) + parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) + parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) + parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) + parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) + parameter TQHS = 400; // tQHS ps Data hold skew factor + parameter TAC = 500; // tAC ps DQ output access time from CK/CK# + parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS + parameter TDH = 225; // tDH ps DQ and DM input hold time relative to DQS + parameter TDQSCK = 450; // tDQSCK ps DQS output access time from CK/CK# + parameter TDQSQ = 300; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access + parameter TIS = 250; // tIS ps Input Setup Time + parameter TIH = 375; // tIH ps Input Hold Time + parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time + parameter TRCD = 15000; // tRCD ps Active to Read/Write command time + parameter TWTR = 7500; // tWTR ps Write to Read command delay + parameter TRP = 15000; // tRP ps Precharge command period + parameter TRPA = 18750; // tRPA ps Precharge All period + parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command + parameter TXARD = 2; // tXARD tCK Exit active power down to a read command + parameter TXP = 2; // tXP tCK Exit power down to a non-read command + parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency + parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency + parameter CL_TIME = 15000; // CL ps Minimum CAS Latency +`else `define sg5E + parameter TCK_MIN = 5000; // tCK ps Minimum Clock Cycle Time + parameter TJIT_PER = 125; // tJIT(per) ps Period JItter + parameter TJIT_DUTY = 150; // tJIT(duty) ps Half Period Jitter + parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter + parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) + parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) + parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) + parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) + parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) + parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) + parameter TQHS = 450; // tQHS ps Data hold skew factor + parameter TAC = 600; // tAC ps DQ output access time from CK/CK# + parameter TDS = 150; // tDS ps DQ and DM input setup time relative to DQS + parameter TDH = 275; // tDH ps DQ and DM input hold time relative to DQS + parameter TDQSCK = 500; // tDQSCK ps DQS output access time from CK/CK# + parameter TDQSQ = 350; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access + parameter TIS = 350; // tIS ps Input Setup Time + parameter TIH = 475; // tIH ps Input Hold Time + parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time + parameter TRCD = 15000; // tRCD ps Active to Read/Write command time + parameter TWTR = 10000; // tWTR ps Write to Read command delay + parameter TRP = 15000; // tRP ps Precharge command period + parameter TRPA = 20000; // tRPA ps Precharge All period + parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command + parameter TXARD = 2; // tXARD tCK Exit active power down to a read command + parameter TXP = 2; // tXP tCK Exit power down to a non-read command + parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency + parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency + parameter CL_TIME = 15000; // CL ps Minimum CAS Latency +`endif `endif `endif `endif `endif `endif + +`ifdef x16 + `ifdef sg187E + parameter TFAW = 45000; // tFAW ps Four Bank Activate window + `else `ifdef sg25E + parameter TFAW = 45000; // tFAW ps Four Bank Activate window + `else `ifdef sg25 + parameter TFAW = 45000; // tFAW ps Four Bank Activate window + `else // sg3E, sg3, sg37E, sg5E + parameter TFAW = 50000; // tFAW ps Four Bank Activate window + `endif `endif `endif +`else // x4, x8 + `ifdef sg187E + parameter TFAW = 35000; // tFAW ps Four Bank Activate window + `else `ifdef sg25E + parameter TFAW = 35000; // tFAW ps Four Bank Activate window + `else `ifdef sg25 + parameter TFAW = 35000; // tFAW ps Four Bank Activate window + `else // sg3E, sg3, sg37E, sg5E + parameter TFAW = 37500; // tFAW ps Four Bank Activate window + `endif `endif `endif +`endif + + // Timing Parameters + + // Mode Register + parameter AL_MIN = 0; // AL tCK Minimum Additive Latency + parameter AL_MAX = 6; // AL tCK Maximum Additive Latency + parameter CL_MIN = 3; // CL tCK Minimum CAS Latency + parameter CL_MAX = 7; // CL tCK Maximum CAS Latency + parameter WR_MIN = 2; // WR tCK Minimum Write Recovery + parameter WR_MAX = 8; // WR tCK Maximum Write Recovery + parameter BL_MIN = 4; // BL tCK Minimum Burst Length + parameter BL_MAX = 8; // BL tCK Minimum Burst Length + // Clock + parameter TCK_MAX = 8000; // tCK ps Maximum Clock Cycle Time + parameter TCH_MIN = 0.48; // tCH tCK Minimum Clock High-Level Pulse Width + parameter TCH_MAX = 0.52; // tCH tCK Maximum Clock High-Level Pulse Width + parameter TCL_MIN = 0.48; // tCL tCK Minimum Clock Low-Level Pulse Width + parameter TCL_MAX = 0.52; // tCL tCK Maximum Clock Low-Level Pulse Width + // Data + parameter TLZ = TAC; // tLZ ps Data-out low-impedance window from CK/CK# + parameter THZ = TAC; // tHZ ps Data-out high impedance window from CK/CK# + parameter TDIPW = 0.35; // tDIPW tCK DQ and DM input Pulse Width + // Data Strobe + parameter TDQSH = 0.35; // tDQSH tCK DQS input High Pulse Width + parameter TDQSL = 0.35; // tDQSL tCK DQS input Low Pulse Width + parameter TDSS = 0.20; // tDSS tCK DQS falling edge to CLK rising (setup time) + parameter TDSH = 0.20; // tDSH tCK DQS falling edge from CLK rising (hold time) + parameter TWPRE = 0.35; // tWPRE tCK DQS Write Preamble + parameter TWPST = 0.40; // tWPST tCK DQS Write Postamble + parameter TDQSS = 0.25; // tDQSS tCK Rising clock edge to DQS/DQS# latching transition + // Command and Address + parameter TIPW = 0.6; // tIPW tCK Control and Address input Pulse Width + parameter TCCD = 2; // tCCD tCK Cas to Cas command delay + parameter TRAS_MIN = 40000; // tRAS ps Minimum Active to Precharge command time + parameter TRAS_MAX =70000000; // tRAS ps Maximum Active to Precharge command time + parameter TRTP = 7500; // tRTP ps Read to Precharge command delay + parameter TWR = 15000; // tWR ps Write recovery time + parameter TMRD = 2; // tMRD tCK Load Mode Register command cycle time + parameter TDLLK = 200; // tDLLK tCK DLL locking time + // Refresh + parameter TRFC_MIN = 197500; // tRFC ps Refresh to Refresh Command interval minimum value + parameter TRFC_MAX =70000000; // tRFC ps Refresh to Refresh Command Interval maximum value + // Self Refresh + parameter TXSNR = TRFC_MIN + 10000; // tXSNR ps Exit self refesh to a non-read command + parameter TXSRD = 200; // tXSRD tCK Exit self refresh to a read command + parameter TISXR = TIS; // tISXR ps CKE setup time during self refresh exit. + // ODT + parameter TAOND = 2; // tAOND tCK ODT turn-on delay + parameter TAOFD = 2.5; // tAOFD tCK ODT turn-off delay + parameter TAONPD = 2000; // tAONPD ps ODT turn-on (precharge power-down mode) + parameter TAOFPD = 2000; // tAOFPD ps ODT turn-off (precharge power-down mode) + parameter TMOD = 12000; // tMOD ps ODT enable in EMR to ODT pin transition + // Power Down + parameter TCKE = 3; // tCKE tCK CKE minimum high or low pulse width + + // Size Parameters based on Part Width + +`ifdef x4 + parameter ADDR_BITS = 15; // Address Bits + parameter ROW_BITS = 15; // Number of Address bits + parameter COL_BITS = 11; // Number of Column bits + parameter DM_BITS = 1; // Number of Data Mask bits + parameter DQ_BITS = 4; // Number of Data bits + parameter DQS_BITS = 1; // Number of Dqs bits + parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time +`else `ifdef x8 + parameter ADDR_BITS = 15; // Address Bits + parameter ROW_BITS = 15; // Number of Address bits + parameter COL_BITS = 10; // Number of Column bits + parameter DM_BITS = 1; // Number of Data Mask bits + parameter DQ_BITS = 8; // Number of Data bits + parameter DQS_BITS = 1; // Number of Dqs bits + parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time +`else `define x16 + parameter ADDR_BITS = 14; // Address Bits + parameter ROW_BITS = 14; // Number of Address bits + parameter COL_BITS = 10; // Number of Column bits + parameter DM_BITS = 2; // Number of Data Mask bits + parameter DQ_BITS = 16; // Number of Data bits + parameter DQS_BITS = 2; // Number of Dqs bits + parameter TRRD = 10000; // tRRD Active bank a to Active bank b command time +`endif `endif + +`ifdef QUAD_RANK + `define DUAL_RANK // also define DUAL_RANK + parameter CS_BITS = 4; // Number of Chip Select Bits + parameter RANKS = 4; // Number of Chip Select Bits +`else `ifdef DUAL_RANK + parameter CS_BITS = 2; // Number of Chip Select Bits + parameter RANKS = 2; // Number of Chip Select Bits +`else + parameter CS_BITS = 2; // Number of Chip Select Bits + parameter RANKS = 1; // Number of Chip Select Bits +`endif `endif + + // Size Parameters + parameter BA_BITS = 3; // Set this parmaeter to control how many Bank Address bits + parameter MEM_BITS = 10; // Number of write data bursts can be stored in memory. The default is 2^10=1024. + parameter AP = 10; // the address bit that controls auto-precharge and precharge-all + parameter BL_BITS = 3; // the number of bits required to count to MAX_BL + parameter BO_BITS = 2; // the number of Burst Order Bits + + // Simulation parameters + parameter STOP_ON_ERROR = 1; // If set to 1, the model will halt on command sequence/major errors + parameter DEBUG = 1; // Turn on Debug messages + parameter BUS_DELAY = 0; // delay in nanoseconds + parameter RANDOM_OUT_DELAY = 0; // If set to 1, the model will put a random amount of delay on DQ/DQS during reads + parameter RANDOM_SEED = 711689044; //seed value for random generator. + + parameter RDQSEN_PRE = 2; // DQS driving time prior to first read strobe + parameter RDQSEN_PST = 1; // DQS driving time after last read strobe + parameter RDQS_PRE = 2; // DQS low time prior to first read strobe + parameter RDQS_PST = 1; // DQS low time after last valid read strobe + parameter RDQEN_PRE = 0; // DQ/DM driving time prior to first read data + parameter RDQEN_PST = 0; // DQ/DM driving time after last read data + parameter WDQS_PRE = 1; // DQS half clock periods prior to first write strobe + parameter WDQS_PST = 1; // DQS half clock periods after last valid write strobe diff --git a/sim/verilog/micron_2048Mb_ddr2/readme.txt b/sim/verilog/micron_2048Mb_ddr2/readme.txt new file mode 100644 index 0000000..cc0507d --- /dev/null +++ b/sim/verilog/micron_2048Mb_ddr2/readme.txt @@ -0,0 +1,190 @@ +Disclaimer of Warranty: +----------------------- +This software code and all associated documentation, comments or other +information (collectively "Software") is provided "AS IS" without +warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY +DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES +OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT +WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE +OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. +FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR +THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE +OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, +ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, +INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, +WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, +OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE +THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. Because some jurisdictions prohibit the exclusion or +limitation of liability for consequential or incidental damages, the +above limitation may not apply to you. + +Copyright 2003 Micron Technology, Inc. All rights reserved. + +Getting Started: +---------------- +Unzip the included files to a folder. +Compile ddr2.v, ddr2_mcp.v, and tb.v using a verilog simulator. +Simulate the top level test bench tb. +Or, if you are using the ModelSim simulator, type "do tb.do" at the prompt. + +File Descriptions: +------------------ +ddr2.v -ddr2 model +ddr2_mcp.v -structural wrapper for ddr2 - multi-chip package model +ddr2_module.v -structural wrapper for ddr2 - module model +ddr2_parameters.vh -file that contains all parameters used by the model +readme.txt -this file +tb.v -ddr2 model test bench +subtest.vh -example test included by the test bench. +tb.do -compiles and runs the ddr2 model and test bench + +Defining the Speed Grade: +------------------------- +The verilog compiler directive "`define" may be used to choose between +multiple speed grades supported by the ddr2 model. Allowable speed +grades are listed in the ddr2_parameters.vh file and begin with the +letters "sg". The speed grade is used to select a set of timing +parameters for the ddr2 model. The following are examples of defining +the speed grade. + + simulator command line + --------- ------------ + ModelSim vlog +define+sg5 ddr2.v + NC-Verilog ncverilog +define+sg5 ddr2.v + VCS vcs +define+sg5 ddr2.v + +Defining the Organization: +-------------------------- +The verilog compiler directive "`define" may be used to choose between +multiple organizations supported by the ddr2 model. Valid +organizations include "x4", "x8", and x16, and are listed in the +ddr2_parameters.vh file. The organization is used to select the amount +of memory and the port sizes of the ddr2 model. The following are +examples of defining the organization. + + simulator command line + --------- ------------ + ModelSim vlog +define+x8 ddr2.v + NC-Verilog ncverilog +define+x8 ddr2.v + VCS vcs +define+x8 ddr2.v + +All combinations of speed grade and organization are considered valid +by the ddr2 model even though a Micron part may not exist for every +combination. + +Allocating Memory: +------------------ +An associative array has been implemented to reduce the amount of +static memory allocated by the ddr2 model. Each entry in the +associative array is a burst length of eight in size. The number of +entries in the associative array is controlled by the MEM_BITS +parameter, and is equal to 2^MEM_BITS. For example, if the MEM_BITS +parameter is equal to 10, the associative array will be large enough +to store 1024 writes of burst length 8 to unique addresses. The +following are examples of setting the MEM_BITS parameter to 8. + + simulator command line + --------- ------------ + ModelSim vsim -GMEM_BITS=8 ddr2 + NC-Verilog ncverilog +defparam+ddr2.MEM_BITS=8 ddr2.v + VCS vcs -pvalue+MEM_BITS=8 ddr2.v + +It is possible to allocate memory for every address supported by the +ddr2 model by using the verilog compiler directive "`define MAX_MEM". +This procedure will improve simulation performance at the expense of +system memory. The following are examples of allocating memory for +every address. + + Simulator command line + --------- ------------ + ModelSim vlog +define+MAX_MEM ddr2.v + NC-Verilog ncverilog +define+MAX_MEM ddr2.v + VCS vcs +define+MAX_MEM ddr2.v + + +********************************************************************** +The following information is provided to assist the modeling engineer +in creating multi-chip package (mcp) models. ddr2_mcp.v is a +structural wrapper that instantiates ddr2 models. This wrapper can be +used to create single, dual, or quad rank mcp models. From the +perspective of the model, the only item that needs to be defined is the +number of ranks. +********************************************************************** + +Defining the Number of Ranks in a multi-chip package: +---------------------------------------------------- +The verilog compiler directive "`define" may be used to choose between +single, dual, and quad rank mcp configurations. The default is single +rank if nothing is defined. Dual rank configuration can be selected by +defining "DUAL_RANK" when the ddr2_mcp is compiled. Quad rank +configuration can be selected by defining "QUAD_RANK" when the ddr2_mcp +is compiled. The following are examples of defining a dual rank mcp +configuration. + + simulator command line + --------- ------------ + ModelSim vlog +define+DUAL_RANK ddr2.v ddr2_mcp.v + NC-Verilog ncverilog +define+DUAL_RANK ddr2.v ddr2_mcp.v + VCS vcs +define+DUAL_RANK ddr2.v ddr2_mcp.v + + +********************************************************************** +The following information is provided to assist the modeling engineer +in creating DIMM models. ddr2_module.v is a structural wrapper that +instantiates ddr2 models. This wrapper can be used to create UDIMM, +RDIMM or SODIMM models. Other form factors are not supported +(MiniDIMM, VLP DIMM, etc.). From the perspective of the model, the +items that need to be defined are the number of ranks, the module +type, and the presence of ECC. All combinations of ranks, module +type, and ECC are considered valid by the ddr2_module model even +though a Micron part may not exist for every combination. +********************************************************************** + +Defining the Number of Ranks on a module: +---------------------------------------- +The verilog compiler directive "`define" may be used to choose between +single, dual, and quad rank module configurations. The default is single +rank if nothing is defined. Dual rank configuration can be selected by +defining "DUAL_RANK" when the ddr2_module is compiled. Quad rank +configuration can be selected by defining "QUAD_RANK" when the ddr2_module +is compiled. The following are examples of defining a dual rank module +configuration. + + simulator command line + --------- ------------ + ModelSim vlog +define+DUAL_RANK ddr2.v ddr2_module.v + NC-Verilog ncverilog +define+DUAL_RANK ddr2.v ddr2_module.v + VCS vcs +define+DUAL_RANK ddr2.v ddr2_module.v + +Defining the Module Type: +----------------------------------- +The verilog compiler directive "`define" may be used to choose between +UDIMM, RDIMM, and SODIMM module configurations. The default is +unregistered (UDIMM) if nothing is defined. SODIMM configuration can be +selected by defining "SODIMM" when the ddr2_module is compiled. Registered +configuration can be selected by defining "RDIMM" when the ddr2_module is +compiled. The following are examples of defining a registered module +configuration. + + simulator command line + --------- ------------ + ModelSim vlog +define+RDIMM ddr2.v ddr2_module.v + NC-Verilog ncverilog +define+RDIMM ddr2.v ddr2_module.v + VCS vcs +define+RDIMM ddr2.v ddr2_module.v + +Defining the ECC for a module: +----------------------------- +The verilog compiler directive "`define" may be used to choose between +ECC and nonECC module configurations. The default is nonECC if nothing +is defined. ECC configuration can be selected by defining "ECC" when +the ddr2_module is compiled. The following are examples of defining an +ECC module configuration. + + simulator command line + --------- ------------ + ModelSim vlog +define+ECC ddr2.v ddr2_module.v + NC-Verilog ncverilog +define+ECC ddr2.v ddr2_module.v + VCS vcs +define+ECC ddr2.v ddr2_module.v diff --git a/sim/verilog/micron_2048Mb_ddr2/subtest.vh b/sim/verilog/micron_2048Mb_ddr2/subtest.vh new file mode 100644 index 0000000..ec1e8f3 --- /dev/null +++ b/sim/verilog/micron_2048Mb_ddr2/subtest.vh @@ -0,0 +1,225 @@ +/**************************************************************************************** +* +* File Name: subtest.vh +* +* Description: Micron SDRAM DDR2 (Double Data Rate 2) +* This file is included by tb.v +* +* Disclaimer This software code and all associated documentation, comments or other +* of Warranty: information (collectively "Software") is provided "AS IS" without +* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY +* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES +* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT +* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE +* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. +* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR +* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE +* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, +* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, +* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, +* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, +* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE +* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGES. Because some jurisdictions prohibit the exclusion or +* limitation of liability for consequential or incidental damages, the +* above limitation may not apply to you. +* +* Copyright 2003 Micron Technology, Inc. All rights reserved. +* +****************************************************************************************/ + + initial begin : test + cke <= 1'b0; + cs_n <= 1'b1; + ras_n <= 1'b1; + cas_n <= 1'b1; + we_n <= 1'b1; + ba <= {BA_BITS{1'bz}}; + a <= {ADDR_BITS{1'bz}}; + odt <= 1'b0; + dq_en <= 1'b0; + dqs_en <= 1'b0; + + cke <= 1'b1; + + // POWERUP SECTION + power_up; + + // INITIALIZE SECTION + precharge (0, 1); // Precharge all banks + nop (trp); + + load_mode (2, 0); // Extended Mode Register (2) + nop (tmrd-1); + + load_mode (3, 0); // Extended Mode Register (3) + nop (tmrd-1); + + load_mode (1, 13'b0_0_0_000_0_000_1_0_0); // Extended Mode Register with DLL Enable + nop (tmrd-1); + + load_mode (0, 13'b0_000_1_0_000_0_011 | (twr-1)<<9 | taa<<4); // Mode Register without DLL Reset (bl=8) + nop (tmrd-1); + + precharge (0, 1); // Precharge all banks + nop (trp); + + refresh; + nop (trfc-1); + + refresh; + nop (trfc-1); + + load_mode (0, 13'b0_000_0_0_000_0_011 | (twr-1)<<9 | taa<<4); // Mode Register without DLL Reset (bl=8) + nop (tmrd-1); + + load_mode (1, 13'b0_0_0_111_0_000_1_0_0); // Extended Mode Register with OCD Default + nop (tmrd-1); + + load_mode (1, 13'b0_0_0_000_0_000_1_0_0); // Extended Mode Register with OCD Exit + nop (tmrd-1); + + // DLL RESET ENABLE - you will need 200 TCK before any read command. + nop (200); + + // WRITE SECTION + activate (0, 0); // Activate Bank 0, Row 0 + nop (trcd-1); + write (0, 4, 0, 0, 'h3210); // Write Bank 0, Col 0 + nop (tccd-1); + write (0, 0, 1, 0, 'h0123); // Write Bank 0, Col 0 + + activate (1, 0); // Activate Bank 1, Row 0 + nop (trcd-1); + write (1, 0, 1, 0, 'h4567); // Write Bank 1, Col 0 + + activate (2, 0); // Activate Bank 2, Row 0 + nop (trcd-1); + write (2, 0, 1, 0, 'h89AB); // Write Bank 2, Col 0 + + activate (3, 0); // Activate Bank 3, Row 0 + nop (trcd-1); + write (3, 0, 1, 0, 'hCDEF); // Write Bank 3, Col 0 + + nop (cl - 1 + bl/2 + twtr-1); + + nop (tras); + + // READ SECTION + activate (0, 0); // Activate Bank 0, Row 0 + nop (trrd-1); + activate (1, 0); // Activate Bank 1, Row 0 + nop (trrd-1); + activate (2, 0); // Activate Bank 2, Row 0 + nop (trrd-1); + activate (3, 0); // Activate Bank 3, Row 0 + read (0, 0, 1); // Read Bank 0, Col 0 + nop (bl/2); + read (1, 1, 1); // Read Bank 1, Col 1 + nop (bl/2); + read (2, 2, 1); // Read Bank 2, Col 2 + nop (bl/2); + read (3, 3, 1); // Read Bank 3, Col 3 + nop (rl + bl/2); + + activate (0, 0); // Activate Bank 0, Row 0 + nop (trrd-1); + activate (1, 0); // Activate Bank 1, Row 0 + nop (trcd-1); + $display ("%m at time %t: Figure 22: Consecutive READ Bursts", $time); + read (0, 0, 0); // Read Bank 0, Col 0 + nop (bl/2-1); + read (0, 4, 0); // Read Bank 0, Col 4 + nop (rl + bl/2); + + $display ("%m at time %t: Figure 23: Nonconsecutive READ Bursts", $time); + read (0, 0, 0); // Read Bank 0, Col 0 + nop (bl/2); + read (0, 4, 0); // Read Bank 0, Col 4 + nop (rl + bl/2); + + $display ("%m at time %t: Figure 24: READ Interrupted by READ", $time); + read (0, 0, 0); // Read Bank 0, Col 0 + nop (tccd-1); + read (1, 0, 0); // Read Bank 0, Col 0 + nop (rl + bl/2); + + $display ("%m at time %t: Figure 25 & 26: READ to PRECHARGE", $time); + read (0, 0, 0); // Read Bank 0, Col 0 + nop (al + bl/2 + trtp - 2); + precharge (0, 0); // Precharge Bank 0 + nop (trp-1); + + activate (0, 0); // Activate Bank 0, Row 0 + nop (trcd-1); + $display ("%m at time %t: Figure 27: READ to WRITE", $time); + read (0, 0, 0); // Read Bank 0, Col 0 + nop (rl + bl/2 - wl); + write (0, 0, 1, 0, 'h0123); // Write Bank 0, Col 0 + nop (wl + bl/2 + twr + trp-1); + + activate (0, 0); // Activate Bank 0, Row 0 + nop (trcd-1); + $display ("%m at time %t: Figure 36: Nonconsecutive WRITE to WRITE", $time); + write (0, 0, 0, 0, 'h0123); // Write Bank 0, Col 0 + nop (bl/2); + write (0, 4, 0, 0, 'h0123); // Write Bank 0, Col 0 + nop (wl + bl/2); + + $display ("%m at time %t: Figure 37: Random WRITE Cycles", $time); + write (0, 0, 0, 0, 'h0123); // Write Bank 0, Col 0 + nop (bl/2-1); + write (0, 4, 0, 0, 'h0123); // Write Bank 0, Col 0 + nop (wl + bl/2); + + $display ("%m at time %t: Figure 37: Figure 38: WRITE Interrupted by WRITE", $time); + write (0, 0, 0, 0, 'h0123); // Write Bank 0, Col 0 + nop (tccd-1); + write (1, 4, 0, 0, 'h0123); // Write Bank 0, Col 0 + nop (wl + bl/2); + + $display ("%m at time %t: Figure 39: WRITE to READ", $time); + write (0, 0, 0, 0, 'h0123); // Write Bank 0, Col 0 + nop (wl + bl/2 + twtr-1); + read_verify (0, 0, 0, 0, 'h0123); // Read Bank 0, Col 0 + nop (rl + bl/2); + + $display ("%m at time %t: Figure 40: WRITE to PRECHARGE", $time); + write (0, 0, 0, 0, 'h0123); // Write Bank 0, Col 0 + nop (wl + bl/2 + twr-1); + precharge (0, 1); // Precharge all banks + nop (trp-1); + + // odt Section + $display ("%m at time %t: Figure 60: odt Timing for Active or Fast-Exit Power-Down Mode", $time); + odt = 1'b1; + nop (1); + odt = 1'b0; + nop (tanpd); + + $display ("%m at time %t: Figure 61: odt timing for Slow-Exit or Precharge Power-Down Modes", $time); + cke = 1'b0; + @(negedge ck); + odt = 1'b1; + @(negedge ck); + odt = 1'b0; + repeat(tanpd)@(negedge ck); + nop (taxpd); + + $display ("%m at time %t: Figure 62 & 63: odt Transition Timings when Entering Power-Down Mode", $time); + odt = 1'b1; + nop (tanpd); + power_down (tcke); + + // Self Refresh Section + nop (taxpd); + odt = 1'b0; + nop (3); // taofd + self_refresh (tcke); + nop (tdllk); + nop (tcke); + + test_done; + end diff --git a/sim/verilog/micron_2048Mb_ddr2/tb.do b/sim/verilog/micron_2048Mb_ddr2/tb.do new file mode 100644 index 0000000..7f5f482 --- /dev/null +++ b/sim/verilog/micron_2048Mb_ddr2/tb.do @@ -0,0 +1,31 @@ +######################################################################################### +# +# Disclaimer This software code and all associated documentation, comments or other +# of Warranty: information (collectively "Software") is provided "AS IS" without +# warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY +# DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +# TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES +# OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT +# WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE +# OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. +# FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR +# THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +# ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE +# OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, +# ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, +# INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, +# WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, +# OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE +# THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGES. Because some jurisdictions prohibit the exclusion or +# limitation of liability for consequential or incidental damages, the +# above limitation may not apply to you. +# +# Copyright 2003 Micron Technology, Inc. All rights reserved. +# +######################################################################################### + +vlog -novopt ddr2.v tb.v +vsim -novopt tb +add wave -p sdramddr2/* +run -all diff --git a/sim/verilog/micron_2048Mb_ddr2/tb.v b/sim/verilog/micron_2048Mb_ddr2/tb.v new file mode 100644 index 0000000..a08db2f --- /dev/null +++ b/sim/verilog/micron_2048Mb_ddr2/tb.v @@ -0,0 +1,468 @@ +/**************************************************************************************** +* +* File Name: tb.v +* +* Dependencies: ddr2.v, ddr2_parameters.vh +* +* Description: Micron SDRAM DDR2 (Double Data Rate 2) test bench +* +* Note: -Set simulator resolution to "ps" accuracy +* -Set Debug = 0 to disable $display messages +* +* Disclaimer This software code and all associated documentation, comments or other +* of Warranty: information (collectively "Software") is provided "AS IS" without +* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY +* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES +* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT +* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE +* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. +* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR +* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE +* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, +* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, +* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, +* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, +* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE +* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGES. Because some jurisdictions prohibit the exclusion or +* limitation of liability for consequential or incidental damages, the +* above limitation may not apply to you. +* +* Copyright 2003 Micron Technology, Inc. All rights reserved. +* +****************************************************************************************/ + +// DO NOT CHANGE THE TIMESCALE + +`timescale 1ps / 1ps + +module tb; + +`include "ddr2_parameters.vh" + + // ports + reg ck; + wire ck_n = ~ck; + reg cke; + reg cs_n; + reg ras_n; + reg cas_n; + reg we_n; + reg [BA_BITS-1:0] ba; + reg [ADDR_BITS-1:0] a; + wire [DM_BITS-1:0] dm; + wire [DQ_BITS-1:0] dq; + wire [DQS_BITS-1:0] dqs; + wire [DQS_BITS-1:0] dqs_n; + wire [DQS_BITS-1:0] rdqs_n; + reg odt; + + // mode registers + reg [ADDR_BITS-1:0] mode_reg0; //Mode Register + reg [ADDR_BITS-1:0] mode_reg1; //Extended Mode Register + wire [2:0] cl = mode_reg0[6:4]; //CAS Latency + wire bo = mode_reg0[3]; //Burst Order + wire [7:0] bl = (1< $rtoi(number)) + ceil = $rtoi(number) + 1; + else + ceil = number; + endfunction + + function integer max; + input arg1; + input arg2; + integer arg1; + integer arg2; + if (arg1 > arg2) + max = arg1; + else + max = arg2; + endfunction + + task power_up; + begin + cke <= 1'b0; + odt <= 1'b0; + repeat(10) @(negedge ck); + cke <= 1'b1; + nop (400000/tck+1); + end + endtask + + task load_mode; + input [BA_BITS-1:0] bank; + input [ADDR_BITS-1:0] addr; + begin + case (bank) + 0: mode_reg0 = addr; + 1: mode_reg1 = addr; + endcase + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b0; + cas_n <= 1'b0; + we_n <= 1'b0; + ba <= bank; + a <= addr; + @(negedge ck); + end + endtask + + task refresh; + begin + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b0; + cas_n <= 1'b0; + we_n <= 1'b1; + @(negedge ck); + end + endtask + + task precharge; + input [BA_BITS-1:0] bank; + input ap; //precharge all + begin + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b0; + cas_n <= 1'b1; + we_n <= 1'b0; + ba <= bank; + a <= (ap<<10); + @(negedge ck); + end + endtask + + task activate; + input [BA_BITS-1:0] bank; + input [ROW_BITS-1:0] row; + begin + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b0; + cas_n <= 1'b1; + we_n <= 1'b1; + ba <= bank; + a <= row; + @(negedge ck); + end + endtask + + //write task supports burst lengths <= 8 + task write; + input [BA_BITS-1:0] bank; + input [COL_BITS-1:0] col; + input ap; //Auto Precharge + input [8*DM_BITS-1:0] dm; + input [8*DQ_BITS-1:0] dq; + reg [ADDR_BITS-1:0] atemp [1:0]; + integer i; + begin + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b1; + cas_n <= 1'b0; + we_n <= 1'b0; + ba <= bank; + atemp[0] = col & 10'h3ff; //addr[ 9: 0] = COL[ 9: 0] + atemp[1] = (col>>10)<<11; //addr[ N:11] = COL[ N:10] + a <= atemp[0] | atemp[1] | (ap<<10); + for (i=0; i<=bl; i=i+1) begin + + dqs_en <= #(wl*tck + i*tck/2) 1'b1; + if (i%2 == 0) begin + dqs_out <= #(wl*tck + i*tck/2) {DQS_BITS{1'b0}}; + end else begin + dqs_out <= #(wl*tck + i*tck/2) {DQS_BITS{1'b1}}; + end + + dq_en <= #(wl*tck + i*tck/2 + tck/4) 1'b1; + dm_out <= #(wl*tck + i*tck/2 + tck/4) dm>>i*DM_BITS; + dq_out <= #(wl*tck + i*tck/2 + tck/4) dq>>i*DQ_BITS; + end + dqs_en <= #(wl*tck + bl*tck/2 + tck/2) 1'b0; + dq_en <= #(wl*tck + bl*tck/2 + tck/4) 1'b0; + @(negedge ck); + end + endtask + + // read without data verification + task read; + input [BA_BITS-1:0] bank; + input [COL_BITS-1:0] col; + input ap; //Auto Precharge + reg [ADDR_BITS-1:0] atemp [1:0]; + begin + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b1; + cas_n <= 1'b0; + we_n <= 1'b1; + ba <= bank; + atemp[0] = col & 10'h3ff; //addr[ 9: 0] = COL[ 9: 0] + atemp[1] = (col>>10)<<11; //addr[ N:11] = COL[ N:10] + a <= atemp[0] | atemp[1] | (ap<<10); + @(negedge ck); + end + endtask + + task nop; + input [31:0] count; + begin + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b1; + cas_n <= 1'b1; + we_n <= 1'b1; + repeat(count) @(negedge ck); + end + endtask + + task deselect; + input [31:0] count; + begin + cke <= 1'b1; + cs_n <= 1'b1; + ras_n <= 1'b1; + cas_n <= 1'b1; + we_n <= 1'b1; + repeat(count) @(negedge ck); + end + endtask + + task power_down; + input [31:0] count; + begin + cke <= 1'b0; + cs_n <= 1'b1; + ras_n <= 1'b1; + cas_n <= 1'b1; + we_n <= 1'b1; + repeat(count) @(negedge ck); + end + endtask + + task self_refresh; + input [31:0] count; + begin + cke <= 1'b0; + cs_n <= 1'b0; + ras_n <= 1'b0; + cas_n <= 1'b0; + we_n <= 1'b1; + cs_n <= #(tck) 1'b1; + ras_n <= #(tck) 1'b1; + cas_n <= #(tck) 1'b1; + we_n <= #(tck) 1'b1; + repeat(count) @(negedge ck); + end + endtask + + // read with data verification + task read_verify; + input [BA_BITS-1:0] bank; + input [COL_BITS-1:0] col; + input ap; //Auto Precharge + input [8*DM_BITS-1:0] dm; //Expected Data Mask + input [8*DQ_BITS-1:0] dq; //Expected Data + integer i; + begin + read (bank, col, ap); + for (i=0; i> (i*DM_BITS); + dq_fifo[2*rl + i] = dq >> (i*DQ_BITS); + end + end + endtask + + // receiver(s) for data_verify process + dqrx dqrx[DQS_BITS-1:0] (dqs, dq, q0, q1, q2, q3); + + // perform data verification as a result of read_verify task call + always @(ck) begin:data_verify + integer i; + integer j; + reg [DQ_BITS-1:0] bit_mask; + reg [DM_BITS-1:0] dm_temp; + reg [DQ_BITS-1:0] dq_temp; + + for (i = !ck; (i < 2/(2.0 - !ck)); i=i+1) begin + if (dm_fifo[i] === {DM_BITS{1'bx}}) begin + burst_cntr = 0; + end else begin + + dm_temp = dm_fifo[i]; + for (j=0; j 2) | (neg_clk_time / pos_clk_time > 2)); + + // Check if NOP/DES when enter/exit clock stop mode + if ((clock_stop && diff_ck) && (~(prev_nop || prev_des) || ~(nop_enable || des_enable))) begin + $display ("%m: at time %t ERROR: Nop or Deselect is required when enter or exit Stop Clock Mode", $time); + end + + if ((pos_clk_time / clk_period < tCH_MIN) && ~clock_stop) begin + $display ("%m: at time %t ERROR: tCH minimum violation on CLK by %t", $time, tCH_MIN*clk_period - pos_clk_time); + end + if ((pos_clk_time / clk_period > tCH_MAX) && ~clock_stop) begin + $display ("%m: at time %t ERROR: tCH maximum violation on CLK by %t", $time, pos_clk_time - tCH_MAX*clk_period); + end + if ((neg_clk_time / clk_period < tCL_MIN) && ~clock_stop) begin + $display ("%m: at time %t ERROR: tCL minimum violation on CLK by %t", $time, tCL_MIN*clk_period - pos_clk_time); + end + if ((neg_clk_time / clk_period > tCL_MAX) && ~clock_stop) begin + $display ("%m: at time %t ERROR: tCL maximum violation on CLK by %t", $time, pos_clk_time - tCL_MAX*clk_period); + end + end + end + + //clock Frequency Check + always @(posedge diff_ck) begin + if (clk_pos_edge_cnt > 1) begin + if (Mode_reg[6:4] == 3'b011) begin + if (clk_period < (tCK3_min-0.001)) begin + $display ("%m : at time %t ERROR : Illegal clk period for CAS Latency 3", $realtime); + $display ("%m : at time %t CLK PERIOD = %t", $realtime, clk_period); + end + end + if (Mode_reg[6:4] == 3'b010) begin + if (clk_period < (tCK2_min-0.001)) begin + $display ("%m : at time %t ERROR : Illegal clk period for CAS Latency 2", $realtime); + $display ("%m : at time %t CLK PERIOD = %t", $realtime, clk_period); + end + end + end + end + + //SRR reg settings + always @(posedge power_up_done) begin + Srr_reg = 'b0 ; + Srr_reg[3:0] = 4'b1111 ; //Manufacturer(Micron) + Srr_reg[7:4] = 4'b0000 ; //Revision ID(Default to 0 in model) + Srr_reg[10:8] = 3'b100 ; //Refresh Rate(based on temp sensor - will default to 1x in model) + Srr_reg[11] = (DQ_BITS == 32)? 1'b1 : 1'b0 ; //Part width(x32 or x16) + Srr_reg[12] = 1'b0 ; //Device Type (LP DDR) + Srr_reg[15:13] = (part_size == 1024)? 3'b011 : + (part_size == 512 )? 3'b010 : + (part_size == 256 )? 3'b001 : + 3'b000 ; //Density(1024Mb, 512Mb, 256Mb, 128Mb) + end + + // System Clock + always begin + @ (posedge diff_ck) begin + Sys_clk = CkeZ; + CkeZ = Cke; + end + @ (negedge diff_ck) begin + Sys_clk = 1'b0; + end + end + + task store_prev_cmd; + begin + prev_Cs_n <= Cs_n ; + prev_Ras_n <= Ras_n ; + prev_Cas_n <= Cas_n ; + prev_We_n <= We_n ; + prev_Ba[1] <= Ba[1] ; + prev_Ba[0] <= Ba[0] ; + prev_cke <= Cke ; + end + endtask + + task MRD_counter; + begin + if (Cke) begin + if (MRD_cntr < tMRD) begin + MRD_cntr = MRD_cntr + 1'b1; + end + end + end + endtask + + task SRR_counter; + begin + if (Cke) begin + if (SRR_cntr < tSRR) begin + SRR_cntr = SRR_cntr + 1'b1; + end + end + end + endtask + + task SRC_counter; + begin + if (Cke) begin + if (SRC_cntr < ((Mode_reg[6:4])+1)) begin + SRC_cntr = SRC_cntr + 1'b1; + end + end + end + endtask + + task tWTR_counter; + begin + if (Cke) begin + if (tWTR_en) begin + tWTR_cntr = 0 ; + end else begin + tWTR_cntr = tWTR_cntr + 1'b1; + end + end + end + endtask + + task command_counter; + begin + if (Cke) begin + for (i=0; i<4;i=i+1) begin + if (Read_precharge_count[i] < 4'hf) begin + Read_precharge_count[i] = Read_precharge_count[i] + 1'b1; + end + end + for (i=0; i<4;i=i+1) begin + if (Write_precharge_count[i] < 4'hf) begin + Write_precharge_count[i] = Write_precharge_count[i] + 1'b1; + end + end + end + end + endtask + + + task PD_counter; + begin + if (~Cke) begin + if (PD_cntr < tCKE) begin + PD_cntr = PD_cntr + (enter_DPD | enter_PD | DPD_enable | PD_enable); + end + end else begin + PD_cntr = 4'h0 ; + end + end + endtask + + task tXP_check; + begin + if (Cke == 1'b1 && prev_cke == 1'b0) begin + tXP_chk = $realtime ; + end + if (Cke) begin + if (~nop_enable && ~des_enable) begin + if ($realtime-tXP_chk < tXP - 0.001) begin +`ifdef T25L + $display ("%m: At time %t ERROR: tPDX violation", $realtime); +`else + $display ("%m: At time %t ERROR: tXP violation", $realtime); +`endif + end + end + end + end + endtask + + // DPD pos edge clk cntr + always begin + @ (posedge diff_ck) begin + tXP_check ; + Power_down_chk ; + PD_counter ; + store_prev_cmd ; + end + end + + // Check to make sure that we have a Deselect or NOP command on the bus when CKE is brought high + always @(Cke) begin + if (Cke === 1'b1) begin + Init_Cmd_Chk = $realtime ; + if (SelfRefresh === 1'b1) begin + SelfRefresh = 1'b0; + end + if (!((Cs_n) || (~Cs_n & Ras_n & Cas_n & We_n))) begin + $display ("%m: At time %t MEMORY ERROR: You must have a Deselect or NOP command applied", $realtime); + $display ("%m: when the Clock Enable is brought High."); + end + end + end + + //BL Mode Reg settings + always@(Mode_reg[2:0] or mode_load_done) begin + if (mode_load_done) begin + case (Mode_reg[2:0]) + 3'b001 : burst_length = 5'b00010; + 3'b010 : burst_length = 5'b00100; + 3'b011 : burst_length = 5'b01000; + 3'b100 : burst_length = 5'b10000; + default : burst_length = 5'bxxxxx; + endcase + end + end + +// Init sequence +always @(current_init_state or Cke or Prech_enable or ext_mode_load_done or mode_load_done or aref_count) begin + if (current_init_state == begin_init) begin + if (Cke) begin + current_init_state = cke_init ; + power_up_done = 1'b0 ; + end + end + if (current_init_state == cke_init) begin + if (Prech_enable) begin + current_init_state = prech_init ; + aref_count = 0 ; + end + end + if (current_init_state == prech_init) begin + if (~Prech_enable) begin + current_init_state = begin_mode_init ; + end + end + if (current_init_state == begin_mode_init) begin + if (ext_mode_load_done) begin + current_init_state = ext_mode_init ; + end + if (mode_load_done) begin + current_init_state = mode_init ; + end + end + if (current_init_state == mode_init) begin + if (ext_mode_load_done) begin + current_init_state = mode_done_init ; + end + end + if (current_init_state == ext_mode_init) begin + if (mode_load_done) begin + current_init_state = mode_done_init ; + end + end + if (current_init_state == mode_done_init && aref_count >= 2) begin + power_up_done = 1'b1; + end +end + + + // this task will erase the contents of 0 or more banks + task erase_mem; + input [BA_BITS+1:0] bank_MSB_row; //bank bits + 2 row MSB + input DPD_mode ; //erase all memory locations + integer i; + begin + + if (DPD_mode) begin +`ifdef FULL_MEM + for (i=0; i<{(BA_BITS+ROW_BITS+COL_BITS){1'b1}}; i=i+1) begin + mem_array[i] = 'bx; + end +`else + memory_index = 0; + i = 0; + // remove the selected banks + for (memory_index=0; memory_index= burst_length) begin +// Data_in_enable = 1'b0; +// Data_out_enable = 1'b0; +// read_precharge_truncation = 1'b0; +// SRR_read = 1'b0; +// end + end + endtask + + + // SRC check + task Timing_chk_SRC; + begin + if (Active_enable || Aref_enable || Sref_enable || Burst_term || + Ext_mode_enable || Mode_reg_enable || Prech_enable || Read_enable || + Write_enable || DPD_enable || PD_enable || srr_enable) begin + if (part_size == 1024) begin + if (SRC_cntr < ((Mode_reg[6:4])+tSRC)) begin + $display ("%m: At time %t ERROR: tSRC Violation", $realtime); + end + end + end + end + endtask + + task ShiftPipelines; + begin + // read command pipeline + Read_pipeline = Read_pipeline >> 1; + Write_pipeline = Write_pipeline >> 1; + for (i = -2; i < `MAX_PIPE-1; i = i + 1) + begin + Write_col_pipeline [i] = Write_col_pipeline[i+1]; + Write_bank_pipeline [i] = Write_bank_pipeline[i+1]; + end + end + endtask + + // Dq and Dqs Drivers + task Dq_Dqs_Drivers; + begin + + // Initialize Read command + if (Read_pipeline [0] === 1'b1) begin +// Data_out_enable = 1'b1; + Bank_addr = Write_bank_pipeline[0]; + Cols_addr = Write_col_pipeline [0]; + Cols_brst = Cols_addr [2 : 0]; +// if (SRR_read == 1'b1) begin +// Burst_counter = burst_length - 2; +// end else begin +// Burst_counter = 0; +// end + + // Row Address Mux + case (Bank_addr) + 2'd0 : Rows_addr = B0_row_addr; + 2'd1 : Rows_addr = B1_row_addr; + 2'd2 : Rows_addr = B2_row_addr; + 2'd3 : Rows_addr = B3_row_addr; + default : $display ("%m: At time %t ERROR: Invalid Bank Address", $realtime); + endcase + end + + // Read latch + if (Read_pipeline[0] === 1'b1) begin + // output data + if (SRR_read == 1'b1) begin + if (Cols_addr == 0) begin + Dq_out_temp = Srr_reg[DQ_BITS-1:0]; + end else begin + Dq_out_temp = Srr_reg[2*DQ_BITS-1:DQ_BITS]; + SRR_read = 1'b0 ; + end + end else begin + read_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_out_temp); + end + if (Debug) begin + $display ("At time %t %m:READ: Bank = %d, Row = %d, Col = %d, Data = %d", $realtime, Bank_addr, Rows_addr, Cols_addr, Dq_out); + end + + end + + Dq_out <= #(tAC_max) Dq_out_temp ; + Dqs_out <= #(tAC_max) ((|Read_pipeline[0]) & Sys_clk) ; + + if (cas_latency == 3) + Dqs_out_en <= #(tAC_max) (|Read_pipeline[2:0]); + else + Dqs_out_en <= #(tAC_max) (|Read_pipeline[1:0]); + if (Sys_clk) begin + Dq_out_en <= #(tAC_max) (Read_pipeline[0]); + end + + end + endtask + + // Write FIFO and DM Mask Logic + task Write_FIFO_DM_Mask_Logic; + begin + + // Initialize Write command + if (Write_pipeline [-2] === 1'b1) begin +// Data_in_enable = 1'b1; + Bank_addr = Write_bank_pipeline [-2]; + Cols_addr = Write_col_pipeline [-2]; + Cols_brst = Cols_addr [2 : 0]; +// Burst_counter = 0; + + // Row address mux + case (Bank_addr) + 2'd0 : Rows_addr = B0_row_addr; + 2'd1 : Rows_addr = B1_row_addr; + 2'd2 : Rows_addr = B2_row_addr; + 2'd3 : Rows_addr = B3_row_addr; + default : $display ("%m: At time %t ERROR: Invalid Row Address", $realtime); + endcase + end + + // Write data +// if (Data_in_enable === 1'b1) begin + if (Write_pipeline[-2] === 1'b1) begin + + // Data Buffer + read_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_buf); + + // write negedge Dqs on posedge Sys_clk + if (Sys_clk) begin + if (!dm_fall[0]) begin + Dq_buf [ 7 : 0] = dq_fall [ 7 : 0]; + end + if (!dm_fall[1]) begin + Dq_buf [15 : 8] = dq_fall [15 : 8]; + end +`ifdef x32 + if (!dm_fall[2]) begin + Dq_buf [23 : 16] = dq_fall [23 : 16]; + end + if (!dm_fall[3]) begin + Dq_buf [31 : 24] = dq_fall [31 : 24]; + end +`endif + if (~&dm_fall) begin + if (Debug) begin + $display ("At time %t %m:WRITE: Bank = %d, Row = %d, Col = %d, Data = %h", $realtime, Bank_addr, Rows_addr, Cols_addr, Dq_buf[DQ_BITS-1:0]); + end + end + // write posedge Dqs on negedge Sys_clk + end else begin + if (!dm_rise[0]) begin + Dq_buf [ 7 : 0] = dq_rise [ 7 : 0]; + end + if (!dm_rise[1]) begin + Dq_buf [15 : 8] = dq_rise [15 : 8]; + end +`ifdef x32 + if (!dm_rise[2]) begin + Dq_buf [23 : 16] = dq_rise [23 : 16]; + end + if (!dm_rise[3]) begin + Dq_buf [31 : 24] = dq_rise [31 : 24]; + end +`endif + if (~&dm_rise) begin + if (Debug) begin + $display ("At time %t %m:WRITE: Bank = %d, Row = %d, Col = %d, Data = %h", $realtime, Bank_addr, Rows_addr, Cols_addr, Dq_buf[DQ_BITS-1:0]); + end + end + end + + // Write Data + write_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_buf); + // tWR start and tWTR check + if (Sys_clk && &dm_pair === 1'b0) begin + case (Bank_addr) + 2'd0 : WR_chk0 = $realtime; + 2'd1 : WR_chk1 = $realtime; + 2'd2 : WR_chk2 = $realtime; + 2'd3 : WR_chk3 = $realtime; + default : $display ("%m: At time %t ERROR: Invalid Bank Address (tWR)", $realtime); + endcase + +// // tWTR check +// if (Read_enable === 1'b1) begin +// $display ("%m: At time %t ERROR: tWTR violation during Read", $realtime); +// end + end + end + end + endtask + + // Auto Precharge Calculation + task Auto_Precharge_Calculation; + begin + // Precharge counter + if (Read_precharge_access [0] === 1'b1 || Write_precharge_access [0] === 1'b1) begin + Count_precharge [0] = Count_precharge [0] + 1; + end + if (Read_precharge_access [1] === 1'b1 || Write_precharge_access [1] === 1'b1) begin + Count_precharge [1] = Count_precharge [1] + 1; + end + if (Read_precharge_access [2] === 1'b1 || Write_precharge_access [2] === 1'b1) begin + Count_precharge [2] = Count_precharge [2] + 1; + end + if (Read_precharge_access [3] === 1'b1 || Write_precharge_access [3] === 1'b1) begin + Count_precharge [3] = Count_precharge [3] + 1; + end + + // Read with AutoPrecharge Calculation + // The device start internal precharge when: + // 1. BL/2 cycles after command + // 2. Meet tRAS requirement + if (Read_precharge_access[0] & (Count_precharge[0] >= burst_length/2)) begin + Read_precharge_access[0] = 1'b0 ; + Read_precharge_pre[0] = 1'b1 ; + end + if ((Read_precharge_pre[0] === 1'b1) && ($realtime - RAS_chk0 >= tRAS - 0.001)) begin + Pc_b0 = 1'b1; + Act_b0 = 1'b0; + RP_chk0 = $realtime; + Read_precharge_pre[0] = 1'b0; + end + + if (Read_precharge_access[1] & (Count_precharge[1] >= burst_length/2)) begin + Read_precharge_access[1] = 1'b0 ; + Read_precharge_pre[1] = 1'b1 ; + end + if ((Read_precharge_pre[1] === 1'b1) && ($realtime - RAS_chk1 >= tRAS - 0.001)) begin + Pc_b1 = 1'b1; + Act_b1 = 1'b0; + RP_chk1 = $realtime; + Read_precharge_pre[1] = 1'b0; + end + + if (Read_precharge_access[2] & (Count_precharge[2] >= burst_length/2)) begin + Read_precharge_access[2] = 1'b0 ; + Read_precharge_pre[2] = 1'b1 ; + end + if ((Read_precharge_pre[2] === 1'b1) && ($realtime - RAS_chk2 >= tRAS - 0.001)) begin + Pc_b2 = 1'b1; + Act_b2 = 1'b0; + RP_chk2 = $realtime; + Read_precharge_pre[2] = 1'b0; + end + + if (Read_precharge_access[3] & (Count_precharge[3] >= burst_length/2)) begin + Read_precharge_access[3] = 1'b0 ; + Read_precharge_pre[3] = 1'b1 ; + end + if ((Read_precharge_pre[3] === 1'b1) && ($realtime - RAS_chk3 >= tRAS - 0.001)) begin + Pc_b3 = 1'b1; + Act_b3 = 1'b0; + RP_chk3 = $realtime; + Read_precharge_pre[3] = 1'b0; + end + + // Write with AutoPrecharge Calculation + // The device start internal precharge when: + // 1. Meet tRAS requirement + // 2. Two clock after last burst + // Since tWR is time base, the model will compensate tRP + if (Write_precharge_access[0] & (Count_precharge[0] >= burst_length/2+3)) begin + Write_precharge_access[0] = 1'b0 ; + Write_precharge_pre[0] = 1'b1 ; + end + if (Write_precharge_pre[0] & ($realtime - RAS_chk0 >= tRAS - 0.001)) begin + Write_precharge_pre[0] = 1'b0; + Pc_b0 = 1'b1; + Act_b0 = 1'b0; + RP_chk0 = $realtime - ((2 * clk_period) - tWR); + end + + if (Write_precharge_access[1] & (Count_precharge[1] >= burst_length/2+3)) begin + Write_precharge_access[1] = 1'b0 ; + Write_precharge_pre[1] = 1'b1 ; + end + if (Write_precharge_pre[1] & ($realtime - RAS_chk1 >= tRAS - 0.001)) begin + Write_precharge_pre[1] = 1'b0; + Pc_b1 = 1'b1; + Act_b1 = 1'b0; + RP_chk1 = $realtime - ((2 * clk_period) - tWR); + end + + if (Write_precharge_access[2] & (Count_precharge[2] >= burst_length/2+3)) begin + Write_precharge_access[2] = 1'b0 ; + Write_precharge_pre[2] = 1'b1 ; + end + if (Write_precharge_pre[2] & ($realtime - RAS_chk2 >= tRAS - 0.001)) begin + Write_precharge_pre[2] = 1'b0; + Pc_b2 = 1'b1; + Act_b2 = 1'b0; + RP_chk2 = $realtime - ((2 * clk_period) - tWR); + end + + if (Write_precharge_access[3] & (Count_precharge[3] >= burst_length/2+3)) begin + Write_precharge_access[3] = 1'b0 ; + Write_precharge_pre[3] = 1'b1 ; + end + if (Write_precharge_pre[3] & ($realtime - RAS_chk3 >= tRAS - 0.001)) begin + Write_precharge_pre[3] = 1'b0; + Pc_b3 = 1'b1; + Act_b3 = 1'b0; + RP_chk3 = $realtime - ((2 * clk_period) - tWR); + end + end + endtask + + task Power_down_chk; + begin + if (DPD_enable == 1'b1 && enter_DPD == 1'b0) begin + if (prev_cke & Pc_b0 & Pc_b1 & Pc_b2 & Pc_b3) begin + erase_mem(4'b0000, 1'b1); + current_init_state = begin_init ; + ext_mode_load_done = 1'b0 ; + mode_load_done = 1'b0 ; + enter_DPD = 1'b1; + $display ("%m: at time %t Entering Deep Power-Down Mode", $realtime); + end + end + if (enter_DPD == 1'b1) begin + if (Cke == 1'b1 && prev_cke == 1'b0) begin + if (PD_cntr < tCKE) begin + $display ("%m: At time %t ERROR: tCKE violation during exiting of Deep Power-Down Mode", $realtime); + end + $display ("%m: at time %t Exiting Deep Power-Down Mode - A 200 us delay is required with either DESELECT or NOP commands present before the initialization sequence may begin", $realtime); + enter_DPD = 1'b0; + end + end + if (PD_enable == 1'b1 && enter_PD == 1'b0) begin + if (prev_cke) begin + if (Pc_b0 & Pc_b1 & Pc_b2 & Pc_b3) begin + $display ("%m: at time %t Entering Power-Down Mode", $realtime); + enter_PD = 1'b1; + end else if (~Pc_b0 | ~Pc_b1 | ~Pc_b2 | ~Pc_b3) begin + $display ("%m: at time %t Entering Active Power-Down Mode", $realtime); + enter_APD = 1'b1; + end + end + end + if (enter_PD == 1'b1 || enter_APD == 1'b1) begin + if (Cke == 1'b1 && prev_cke == 1'b0) begin + if (PD_cntr < tCKE) begin + if (enter_PD == 1'b1) begin + $display ("%m: At time %t ERROR: tCKE violation during exiting of Power-Down Mode", $realtime); + end else if (enter_APD == 1'b1) begin + $display ("%m: At time %t ERROR: tCKE violation during exiting of Active Power-Down Mode", $realtime); + end + end + if (enter_PD == 1'b1) begin + $display ("%m: at time %t Exiting Power-Down Mode", $realtime); + enter_PD = 1'b0 ; + end else if (enter_APD == 1'b1) begin + $display ("%m: at time %t Exiting Active Power-Down Mode", $realtime); + enter_APD = 1'b0 ; + end + end + end + + end + endtask + + reg [31:0] xx ; + function [COL_BITS-1:0] Burst_Order; + input [COL_BITS-1:0] Col; + input [31:0] i; + begin + if (Mode_reg[3] == 1'b1) //interleaved + Burst_Order = (Col & -1*burst_length) + (Col%burst_length ^ i); + else // sequential + begin + xx = -1*burst_length; + Burst_Order = (Col & xx) + (Col%burst_length + i) % (burst_length); + end + end + endfunction + + // Control Logic + task Control_Logic; + begin + + // Self Refresh + if (Sref_enable === 1'b1) begin + // Partial Array Self Refresh + if (part_size == 128) begin + case (Ext_Mode_reg[2:0]) + 3'b000 : ;//keep Bank 0-7 + 3'b001 : begin $display("%m: at time %t INFO: Banks 2-3 will be lost due to Partial Array Self Refresh", $realtime) ; erase_mem(4'b0111, 1'b0); end + 3'b010 : begin $display("%m: at time %t INFO: Banks 1-3 will be lost due to Partial Array Self Refresh", $realtime) ; erase_mem(4'b0011, 1'b0); end + 3'b011 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end + 3'b100 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end + 3'b101 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end + 3'b110 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end + endcase + end else begin + case (Ext_Mode_reg[2:0]) + 3'b000 : ;//keep Bank 0-7 + 3'b001 : begin $display("%m: at time %t INFO: Banks 2-3 will be lost due to Partial Array Self Refresh", $realtime) ; erase_mem(4'b0111, 1'b0); end + 3'b010 : begin $display("%m: at time %t INFO: Banks 1-3 will be lost due to Partial Array Self Refresh", $realtime) ; erase_mem(4'b0011, 1'b0); end + 3'b011 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end + 3'b100 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end + 3'b101 : begin $display("%m: at time %t INFO: Banks 1-3 and 1/2 of bank 0 will be lost due to Partial Array Self Refresh", $realtime); erase_mem(4'b0001, 1'b0); end + 3'b110 : begin $display("%m: at time %t INFO: Banks 1-3 and 3/4 of bank 0 will be lost due to Partial Array Self Refresh", $realtime); erase_mem(4'b0000, 1'b0); end + endcase + end + SelfRefresh = 1'b1; + end + if (Aref_enable === 1'b1) begin + if (Debug) begin + $display ("Debug: At time %t %m:AUTOREFRESH: Auto Refresh", $realtime); + end + // aref_count is to make sure we have met part of the initialization sequence + if (~power_up_done) begin + aref_count = aref_count + 1; + end + + // Auto Refresh to Auto Refresh + if ($realtime - RFC_chk < tRFC - 0.001) begin + $display ("%m: At time %t ERROR: tRFC violation during Auto Refresh", $realtime); + end + + // Precharge to Auto Refresh + if (($realtime - RP_chk0 < tRP - 0.001) || ($realtime - RP_chk1 < tRP - 0.001) || + ($realtime - RP_chk2 < tRP - 0.001) || ($realtime - RP_chk3 < tRP - 0.001)) begin + $display ("%m: At time %t ERROR: tRP violation during Auto Refresh", $realtime); + end + + // Precharge to Auto Refresh + if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin + $display ("%m: At time %t ERROR: All banks must be Precharged before Auto Refresh", $realtime); + end + + // Record Current tRFC time + RFC_chk = $realtime; + end + + // SRR Register + if (srr_enable == 1'b1) begin + if (Pc_b0 === 1'b1 && Pc_b1 === 1'b1 && Pc_b2 === 1'b1 && Pc_b3 === 1'b1 && + Data_out_enable === 1'b0 && Data_in_enable === 1'b0) begin + SRR_read = 1'b1; + SRR_chk = $realtime; + SRR_cntr = 0; + end + end + + + // Extended Mode Register + if (Ext_mode_enable == 1'b1) begin + if (Debug) begin + $display ("Debug: At time %t %m:EMR : Extended Mode Register", $realtime); + end + + // Register Mode + Ext_Mode_reg = Addr; + + if (Pc_b0 === 1'b1 && Pc_b1 === 1'b1 && Pc_b2 === 1'b1 && Pc_b3 === 1'b1) begin + // ensure that power sequence is met properly + if (~power_up_done) begin + ext_mode_load_done = 1'b1; + end + $display ("At time %t %m:ELMR : Extended Load Mode Register", $realtime); + if (part_size == 128) begin + // Self Refresh Coverage + case (Addr[2 : 0]) + 3'b000 : $display ("%m : Self Refresh Cov = 4 banks"); + 3'b001 : $display ("%m : Self Refresh Cov = 2 banks"); + 3'b010 : $display ("%m : Self Refresh Cov = 1 bank"); + 3'b101 : $display ("%m : PASR = Reserved"); + 3'b110 : $display ("%m : PASR = Reserved"); + default : $display ("%m : PASR = Reserved"); + endcase + end else begin + // Self Refresh Coverage + case (Addr[2 : 0]) + 3'b000 : $display ("%m : Self Refresh Cov = 4 banks"); + 3'b001 : $display ("%m : Self Refresh Cov = 2 banks"); + 3'b010 : $display ("%m : Self Refresh Cov = 1 bank"); + 3'b101 : $display ("%m : Self Refresh Cov = 1/2 bank"); + 3'b110 : $display ("%m : Self Refresh Cov = 1/4 bank"); + default : $display ("%m : PASR = Reserved"); + endcase + end + // Maximum Case Temp +// case (Addr[4 : 3]) +// 2'b11 : $display ("%m : Maximum Case Temp = 85C"); +// 2'b00 : $display ("%m : Maximum Case Temp = 70C"); +// 2'b01 : $display ("%m : Maximum Case Temp = 45C"); +// 2'b10 : $display ("%m : Maximum Case Temp = 15C"); +// endcase + + // Drive Strength + case (Addr[7 : 5]) + 3'b000 : $display ("%m : Drive Strength = Full Strength"); + 3'b001 : $display ("%m : Drive Strength = Half Strength"); + 3'b010 : $display ("%m : Drive Strength = Quarter Strength"); + 3'b011 : $display ("%m : Drive Strength = Three Quarter Strength"); + 3'b100 : $display ("%m : Drive Strength = Three Quarter Strength"); + endcase + + end else begin + $display ("%m: At time %t ERROR: all banks must be Precharged before Extended Mode Register", $realtime); + end + + // Precharge to EMR + if (($realtime - RP_chk0 < tRP - 0.001) || ($realtime - RP_chk1 < tRP - 0.001) || + ($realtime - RP_chk2 < tRP - 0.001) || ($realtime - RP_chk3 < tRP - 0.001)) begin + $display ("%m: At time %t ERROR: tRP violation during Extended Mode Register", $realtime); + end + + // LMR/EMR to LMR/EMR +// if ($realtime - MRD_chk < tMRD) begin +// $display ("%m: At time %t ERROR: tMRD violation during Extended Mode Register", $realtime); +// end + + if (MRD_cntr < tMRD) begin + $display ("%m: At time %t ERROR: tMRD violation during Extended Mode Register", $realtime); + end + + // Record current tMRD time +// MRD_chk = $realtime; + MRD_cntr = 0; + end + + // Load Mode Register + if (Mode_reg_enable === 1'b1) begin + if (Debug) begin + $display ("Debug: At time %t %m:LMR : Load Mode Register", $realtime); + end + + // Register Mode + Mode_reg = Addr; + + if (Mode_reg[6:4] == 3'b010) begin + if (tCK2_min == 0) begin + $display ("%m : at time %t ERROR : Illegal CAS Latency of 2 set for current speed grade", $realtime); + end + end + + // Precharge to LMR + if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin + $display ("%m: At time %t ERROR: all banks must be Precharged before Load Mode Register", $realtime); + end + + // Precharge to LMR + if (($realtime - RP_chk0 < tRP - 0.001) || ($realtime - RP_chk1 < tRP - 0.001) || + ($realtime - RP_chk2 < tRP - 0.001) || ($realtime - RP_chk3 < tRP - 0.001)) begin + $display ("%m: At time %t ERROR: tRP violation during Load Mode Register", $realtime); + end + + // LMR/EMR to LMR/EMR +// if ($realtime - MRD_chk < tMRD) begin +// $display ("%m: At time %t ERROR: tMRD violation during Load Mode Register", $realtime); +// end + if (MRD_cntr < tMRD) begin + $display ("%m: At time %t ERROR: tMRD violation during Load Mode Register", $realtime); + end + + if (Pc_b0 === 1'b1 && Pc_b1 === 1'b1 && Pc_b2 === 1'b1 && Pc_b3 === 1'b1) begin + // ensure that power sequence is met properly + if (~power_up_done) begin + mode_load_done = 1'b1; + end + // Burst Length + case (Addr [2 : 0]) + 3'b001 : $display ("At time %t %m:LMR : Burst Length = 2", $realtime); + 3'b010 : $display ("At time %t %m:LMR : Burst Length = 4", $realtime); + 3'b011 : $display ("At time %t %m:LMR : Burst Length = 8", $realtime); + 3'b100 : $display ("At time %t %m:LMR : Burst Length = 16",$realtime); + default : + begin + $display ("%m: At time %t ERROR: Undefined burst length selection", $realtime); + $stop; + end + endcase + + // CAS Latency + case (Addr [6 : 4]) + 3'b010 : $display ("At time %t %m:LMR : CAS Latency = 2", $realtime); + 3'b011 : $display ("At time %t %m:LMR : CAS Latency = 3", $realtime); + default : begin + $display ("%m: At time %t ERROR: CAS Latency not supported", $realtime); + $stop; + end + endcase + + end + // Record current tMRD time +// MRD_chk = $realtime; + MRD_cntr = 0; + end + + // Activate Block + if (Active_enable === 1'b1) begin + if (!(power_up_done)) begin + $display ("%m: At time %t ERROR: Power Up and Initialization Sequence not completed before executing Activate command", $realtime); + end + // Display Debug Message + if (Debug) begin + $display ("Debug: At time %t %m:ACTIVATE: Bank = %d, Row = %d", $realtime, Ba, Addr); + end + + // Activating an open bank can cause corruption. + if ((Ba === 2'b00 && Pc_b0 === 1'b0) || (Ba === 2'b01 && Pc_b1 === 1'b0) || + (Ba === 2'b10 && Pc_b2 === 1'b0) || (Ba === 2'b11 && Pc_b3 === 1'b0)) begin + $display ("%m: At time %t ERROR: Bank = %d is already activated - data can be corrupted", $realtime, Ba); + end + + // Activate Bank 0 + if (Ba === 2'b00 && Pc_b0 === 1'b1) begin + // Activate to Activate (same bank) + if ($realtime - RC_chk0 < tRC - 0.001) begin + $display ("%m: At time %t ERROR: tRC violation during Activate bank %d", $realtime, Ba); + end + + // Precharge to Activate + if ($realtime - RP_chk0 < tRP - 0.001) begin + $display ("%m: At time %t ERROR: tRP violation during Activate bank %d", $realtime, Ba); + end + + // Record variables for checking violation + Act_b0 = 1'b1; + Pc_b0 = 1'b0; + B0_row_addr = Addr; + RC_chk0 = $realtime; + RCD_chk0 = $realtime; + RAS_chk0 = $realtime; + RAP_chk0 = $realtime; + end + + // Activate Bank 1 + if (Ba === 2'b01 && Pc_b1 === 1'b1) begin + // Activate to Activate (same bank) + if ($realtime - RC_chk1 < tRC - 0.001) begin + $display ("%m: At time %t ERROR: tRC violation during Activate bank %d", $realtime, Ba); + end + + // Precharge to Activate + if ($realtime - RP_chk1 < tRP - 0.001) begin + $display ("%m: At time %t ERROR: tRP violation during Activate bank %d", $realtime, Ba); + end + + // Record variables for checking violation + Act_b1 = 1'b1; + Pc_b1 = 1'b0; + B1_row_addr = Addr; + RC_chk1 = $realtime; + RCD_chk1 = $realtime; + RAS_chk1 = $realtime; + RAP_chk1 = $realtime; + end + + // Activate Bank 2 + if (Ba === 2'b10 && Pc_b2 === 1'b1) begin + // Activate to Activate (same bank) + if ($realtime - RC_chk2 < tRC - 0.001) begin + $display ("%m: At time %t ERROR: tRC violation during Activate bank %d", $realtime, Ba); + end + + // Precharge to Activate + if ($realtime - RP_chk2 < tRP - 0.001) begin + $display ("%m: At time %t ERROR: tRP violation during Activate bank %d", $realtime, Ba); + end + + // Record variables for checking violation + Act_b2 = 1'b1; + Pc_b2 = 1'b0; + B2_row_addr = Addr; + RC_chk2 = $realtime; + RCD_chk2 = $realtime; + RAS_chk2 = $realtime; + RAP_chk2 = $realtime; + end + + // Activate Bank 3 + if (Ba === 2'b11 && Pc_b3 === 1'b1) begin + // Activate to Activate (same bank) + if ($realtime - RC_chk3 < tRC - 0.001) begin + $display ("%m: t time %t ERROR: tRC violation during Activate bank %d", $realtime, Ba); + end + + // Precharge to Activate + if ($realtime - RP_chk3 < tRP - 0.001) begin + $display ("%m: At time %t ERROR: tRP violation during Activate bank %d", $realtime, Ba); + end + + // Record variables for checking violation + Act_b3 = 1'b1; + Pc_b3 = 1'b0; + B3_row_addr = Addr; + RC_chk3 = $realtime; + RCD_chk3 = $realtime; + RAS_chk3 = $realtime; + RAP_chk3 = $realtime; + end + + // Activate to Activate (different bank) + if ((Prev_bank != Ba) && ($realtime - RRD_chk < tRRD - 0.001)) begin + $display ("%m: At time %t ERROR: tRRD violation during Activate bank = %d", $realtime, Ba); + end + + // AutoRefresh to Activate + if ($realtime - RFC_chk < tRFC - 0.001) begin + $display ("%m: At time %t ERROR: tRFC violation during Activate bank %d", $realtime, Ba); + end + + // Record variable for checking violation + RRD_chk = $realtime; + Prev_bank = Ba; + end + + // Precharge Block - consider NOP if bank already precharged or in process of precharging + if (Prech_enable === 1'b1) begin + // Display Debug Message + if (Debug) begin + $display ("Debug: At time %t %m:PRE: Addr[10] = %b, Bank = %b", $realtime, Addr[10], Ba); + end + + // EMR or LMR to Precharge +// if ($realtime - MRD_chk < tMRD) begin +// $display ("%m: At time %t ERROR: tMRD violation during Precharge", $realtime); +// end + if (MRD_cntr < tMRD) begin + $display ("%m: At time %t ERROR: tMRD violation during Precharge", $realtime); + end + + // Precharge bank 0 + if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b00)) && Act_b0 === 1'b1) begin + Act_b0 = 1'b0; + Pc_b0 = 1'b1; + RP_chk0 = $realtime; + + // Activate to Precharge Bank + if ($realtime - RAS_chk0 < tRAS - 0.001) begin + $display ("%m: At time %t ERROR: tRAS violation during Precharge", $realtime); + end + + // tWR violation check for Write + if ($realtime - WR_chk0 < tWR - 0.001) begin + $display ("%m: At time %t ERROR: tWR violation during Precharge", $realtime); + end + end + + // Precharge bank 1 + if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b01)) && Act_b1 === 1'b1) begin + Act_b1 = 1'b0; + Pc_b1 = 1'b1; + RP_chk1 = $realtime; + + // Activate to Precharge Bank 1 + if ($realtime - RAS_chk1 < tRAS - 0.001) begin + $display ("%m: At time %t ERROR: tRAS violation during Precharge", $realtime); + end + + // tWR violation check for Write + if ($realtime - WR_chk1 < tWR - 0.001) begin + $display ("%m: At time %t ERROR: tWR violation during Precharge", $realtime); + end + end + + // Precharge bank 2 + if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b10)) && Act_b2 === 1'b1) begin + Act_b2 = 1'b0; + Pc_b2 = 1'b1; + RP_chk2 = $realtime; + + // Activate to Precharge Bank 2 + if ($realtime - RAS_chk2 < tRAS - 0.001) begin + $display ("%m: At time %t ERROR: tRAS violation during Precharge", $realtime); + end + + // tWR violation check for Write + if ($realtime - WR_chk2 < tWR - 0.001) begin + $display ("%m: At time %t ERROR: tWR violation during Precharge", $realtime); + end + end + + // Precharge bank 3 + if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b11)) && Act_b3 === 1'b1) begin + Act_b3 = 1'b0; + Pc_b3 = 1'b1; + RP_chk3 = $realtime; + + // Activate to Precharge Bank 3 + if ($realtime - RAS_chk3 < tRAS - 0.001) begin + $display ("%m: At time %t ERROR: tRAS violation during Precharge", $realtime); + end + + // tWR violation check for Write + if ($realtime - WR_chk3 < tWR - 0.001) begin + $display ("%m: At time %t ERROR: tWR violation during Precharge", $realtime); + end + end + + // Pipeline for READ + if ((Addr[10] === 1'b1) | (Ba == Write_bank_pipeline[4])) + for (i = 4; i < `MAX_PIPE; i = i + 1) + Read_pipeline[i] = 1'b0 ; + + end + + // Burst terminate + if (Burst_term === 1'b1) begin + // Display Debug Message + if (Debug) begin + $display ("Debug: %m: At time %t BURST_TERMINATE): Burst Terminate",$realtime); + end + + // Burst Terminate Command Pipeline for Read + for (i = cas_latency_x2-1; i < `MAX_PIPE; i = i + 1) + Read_pipeline[i] = 1'b0 ; + // Illegal to burst terminate a Write + if ((Data_in_enable === 1'b1) & ~((&dm_rise) & (&dm_fall))) begin + $display ("%m: At time %t ERROR: It's illegal to burst terminate a Write", $realtime); + end + + // Illegal to burst terminate a Read with Auto Precharge + if (|Read_precharge_access) begin + $display ("%m: At time %t ERROR: It's illegal to burst terminate a Read with Auto Precharge", $realtime); + end + end + + // Read Command + if (Read_enable === 1'b1) begin + if (!(power_up_done)) begin + $display ("%m: At time %t ERROR: Power Up and Initialization Sequence not completed before executing Read Command", $realtime); + end + // Display Debug Message + if (Debug) begin + $display ("Debug: At time %t %m:READ: Bank = %d, Col = %d", $realtime, Ba, {Addr [11], Addr [9 : 0]}); + end + if (part_size == 1024) begin + if (SRR_read == 1'b1) begin + if (SRR_cntr < tSRR) begin + $display ("%m: At time %t ERROR: tSRR Violation", $realtime); + end + SRC_cntr = 0 ; + end + end else begin + if (SRR_read == 1'b1) begin + if ($realtime - SRR_chk < tSRR-0.01) begin + $display ("%m: At time %t ERROR: tSRR Violation", $realtime); + end + SRC_cntr = 0; + end + end + // CAS Latency pipeline + if (SRR_read) begin + if ({Ba, Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]} > 0) begin + $display ("%m: At time %t ERROR: Address must be all 0 during SRR Read", $realtime); + end + for (i=0; i<2; i=i+1) + begin + Read_pipeline[cas_latency_x2 - 2 + i + 1] = 1'b1; + Write_col_pipeline [cas_latency_x2 - 2 + i + 1] = i; + Write_bank_pipeline [cas_latency_x2 - 2 + i + 1] = 0; + end + end else begin + for (i=0; i $rtoi(number)) + ceil = $rtoi(number) + 1; + else + ceil = number; + endfunction + + function integer max; + input arg1; + input arg2; + integer arg1; + integer arg2; + if (arg1 > arg2) + max = arg1; + else + max = arg2; + endfunction + + function [8*DQ_BITS-1:0] burst_order; + input [8-1:0] col; + input [8*DQ_BITS-1:0] dq; + reg [3:0] i; + reg [2:0] j; + integer k; + begin + burst_order = dq; + for (i=0; i>10)<<11; //addr[ N:11] = COL[ N:10] + a <= atemp[0] | atemp[1] | (ap<<10); + for (i=0; i<=bl; i=i+1) begin + dqs_en <= #(wl*tck + i*tck/2) 1'b1; + if (i%2 == 0) begin + dqs_out <= #(wl*tck + i*tck/2) {DQS_BITS{1'b0}}; + end else begin + dqs_out <= #(wl*tck + i*tck/2) {DQS_BITS{1'b1}}; + end + + dq_en <= #(wl*tck + i*tck/2 + tck/4) 1'b1; + dm_out <= #(wl*tck + i*tck/2 + tck/4) dm>>i*DM_BITS; + dq_out <= #(wl*tck + i*tck/2 + tck/4) dq>>i*DQ_BITS; + end + dqs_en <= #(wl*tck + bl*tck/2 + tck/2) 1'b0; + dq_en <= #(wl*tck + bl*tck/2 + tck/4) 1'b0; + @(negedge ck_tb); + end + endtask + + // read without data verification + task read; + input [BA_BITS-1:0] bank; + input [COL_BITS-1:0] col; + input ap; //Auto Precharge + reg [ADDR_BITS-1:0] atemp [1:0]; + begin + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b1; + cas_n <= 1'b0; + we_n <= 1'b1; + ba <= bank; + atemp[0] = col & 10'h3ff; //addr[ 9: 0] = COL[ 9: 0] + atemp[1] = (col>>10)<<11; //addr[ N:11] = COL[ N:10] + a <= atemp[0] | atemp[1] | (ap<<10); + @(negedge ck_tb); + end + endtask + + task burst_term; + integer i; + begin + cke <= 1'b1; + cs_n <= 1'b0; + ras_n <= 1'b1; + cas_n <= 1'b1; + we_n <= 1'b0; + @(negedge ck_tb); + for (i=0; i>(i*DM_BITS); + dq_fifo[2*cl + i] <= dq>>(i*DQ_BITS); + end + end + endtask + + // receiver(s) for data_verify process + dqrx dqrx[DQS_BITS-1:0] (ptr_rst_n, dqs, dq, q0, q1, q2, q3); + + // perform data verification as a result of read_verify task call + reg [DQ_BITS-1:0] bit_mask; + reg [DM_BITS-1:0] dm_temp; + reg [DQ_BITS-1:0] dq_temp; + always @(ck) begin:data_verify + integer i; + integer j; + + for (i=!ck; (i<2/(2.0 - !ck)); i=i+1) begin + if (dm_fifo[i] === {DM_BITS{1'bx}}) begin + burst_cntr = 0; + end else begin + + dm_temp = dm_fifo[i]; + for (j=0; j