ReonV/lib/micron/sdram/mobile_sdr.v

2131 lines
95 KiB
Verilog
Raw Permalink Blame History

/**************************************************************************
*
* File Name: model.v
* Version: 4.0
* Date: Jul 12 2006
* Model: BUS Functional
* Simulator: Model Technology
*
* Dependencies: None
*
* Email: modelsupport@micron.com
* Company: Micron Technology, Inc.
* Model: Mobile SDR
*
* Description: Micron Mobile SDRAM Verilog model
*
* Limitation: - Doesn't check for 4096 cycle refresh
*
* 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 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 <20> 2001-2006 Micron Technology, Inc. All rights reserved.
*
*
* Rev Author Date Changes
* --- -------------------------- ---------------------------------------
* 4.20 bas 10/11/2006 - Changed tRRD check to use tCK min based on CL
* 4.17 bas 10/10/2006 - fixed read problem during CL3 BL1 related to read w/autoprecharge followed by activate to the same bank causing read from incorrect row, updated parameter sheets
* 4.16 bas 09/27/2006 - fixed tRRD check for parts spec using # of clks instead of ns delay
* 4.15 bas 09/26/2006 - Wrote WRap & RDap code to use #delay due to non-freerunning clock operation, fixed tRP, fixed WRap/RDap interrupt operation
* 4.12 bas 09/08/2006 - Removed realtime array instantiations of variables for NCVerilog
* 4.11 bas 09/07/2006 - tHZ issue, read DQM issue, write/read to precharged bank error(data was still being written), tRP during WRaP issue, RP option added, part selection added
* 4.1 bas 08/23/2006 - fixed masking and tHZ timing issue
* 4.0 bh 07/12/2006 - merged MT48H16M16LF & MT48H32M16LF to create single model file for all types & densities
* 3.2 dritz 11/04/2005 - Fixed Driver Strength bits
* 3.1 dritz 09/22/2005 - Fixed dqm bits to be [1:0] and tb.v as well
* 3.0 dritz 06/28/2005 - MT48H32M16LF
* 2.1 dritz 03/23/2005 - MT48LC8M32LF Fixed dqm mask bits and functionality
* 2.0 dritz 01/11/2005 - MT48LC8M32B2
* 1.0 NB 07/14/2004 - MT48M16LF
*
**************************************************************************/
`timescale 1ps / 1ps
module mobile_sdr (
clk ,
cke ,
addr ,
ba ,
cs_n ,
ras_n ,
cas_n ,
we_n ,
dq ,
dqm
);
//------------- Include Statements -------------
//`include "mobile_sdr_parameters.vh"
/****************************************************************************************
*
* 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 2005 Micron Technology, Inc. All rights reserved.
*
****************************************************************************************/
// Timing parameters based on Speed Grade and part type (Y47M) 03/07
`define sg6
// SYMBOL UNITS DESCRIPTION
// ------ ----- -----------
`ifdef sg6 // Timing Parameters for -75 (CL = 3)
parameter tCK = 6000; // tCK ps Nominal Clock Cycle Time
parameter tCK3_min = 6000; // tCK ps Nominal Clock Cycle Time
parameter tCK2_min = 9600; // tCK ps Nominal Clock Cycle Time
parameter tCK1_min = 0; // tCK ps Nominal Clock Cycle Time
parameter tAC3 = 5000; // tAC3 ps Access time from CLK (pos edge) CL = 3
parameter tAC2 = 8000; // tAC2 ps Access time from CLK (pos edge) CL = 2
parameter tAC1 = 0; // tAC1 ps Parameter definition for compilation - CL = 1 illegal for sg75
parameter tHZ3 = 5000; // tHZ3 ps Data Out High Z time - CL = 3
parameter tHZ2 = 8000; // tHZ2 ps Data Out High Z time - CL = 2
parameter tHZ1 = 0; // tHZ1 ps Parameter definition for compilation - CL = 1 illegal for sg75
parameter tOH = 2500; // tOH ps Data Out Hold time
parameter tMRD = 2; // tMRD tCK Load Mode Register command cycle time (2 * tCK)
parameter tRAS = 42000; // tRAS ps Active to Precharge command time
parameter tRC = 60000; // tRC ps Active to Active/Auto Refresh command time
parameter tRFC = 97500; // tRFC ps Refresh to Refresh Command interval time
parameter tRCD = 18000; // tRCD ps Active to Read/Write command time
parameter tRP = 18000; // tRP ps Precharge command period
parameter tRRD = 2; // tRRD tCK Active bank a to Active bank b command time
parameter tWRa = 7500; // tWR ps Write recovery time (auto-precharge mode - must add 1 CLK)
parameter tWRm = 15000; // tWR ps Write recovery time
parameter tCH = 2600; // tCH ps Clock high level width
parameter tCL = 2600; // tCL ps Clock low level width
parameter tXSR = 120000; // tXSR ps Clock low level width
`else `ifdef sg75 // Timing Parameters for -8 (CL = 3)
parameter tCK = 7500; // tCK ps Nominal Clock Cycle Time
parameter tCK3_min = 7500; // tCK ps Nominal Clock Cycle Time
parameter tCK2_min = 9600; // tCK ps Nominal Clock Cycle Time
parameter tCK1_min = 0; // tCK ps Nominal Clock Cycle Time
parameter tAC3 = 5400; // tAC3 ps Access time from CLK (pos edge) CL = 3
parameter tAC2 = 8000; // tAC2 ps Access time from CLK (pos edge) CL = 2
parameter tAC1 = 0; // tAC1 ps Access time from CLK (pos edge) CL = 1
parameter tHZ3 = 5400; // tHZ3 ps Data Out High Z time - CL = 3
parameter tHZ2 = 8000; // tHZ2 ps Data Out High Z time - CL = 2
parameter tHZ1 = 0; // tHZ1 ps Data Out High Z time - CL = 1
parameter tOH = 2500; // tOH ps Data Out Hold time
parameter tMRD = 2; // tMRD tCK Load Mode Register command cycle time (2 * tCK)
parameter tRAS = 45000; // tRAS ps Active to Precharge command time
parameter tRC = 67500; // tRC ps Active to Active/Auto Refresh command time
parameter tRFC = 97500; // tRFC ps Refresh to Refresh Command interval time
parameter tRCD = 19200; // tRCD ps Active to Read/Write command time
parameter tRP = 19200; // tRP ps Precharge command period
parameter tRRD = 2; // tRRD tCK Active bank a to Active bank b command time (2 * tCK)
parameter tWRa = 7500; // tWR ps Write recovery time (auto-precharge mode - must add 1 CLK)
parameter tWRm = 15000; // tWR ps Write recovery time
parameter tCH = 3000; // tCH ps Clock high level width
parameter tCL = 3000; // tCL ps Clock low level width
parameter tXSR = 120000; // tXSR ps Clock low level width
`endif `endif
// Size Parameters based on Part Width
`define x16
`ifdef x32
parameter ADDR_BITS = 13; // Set this parameter to control how many Address bits are used
parameter ROW_BITS = 13; // Set this parameter to control how many Row bits are used
parameter DQ_BITS = 32; // Set this parameter to control how many Data bits are used
parameter DM_BITS = 4; // Set this parameter to control how many DM bits are used
parameter COL_BITS = 9; // Set this parameter to control how many Column bits are used
parameter BA_BITS = 2; // Bank bits
`else `ifdef x16
parameter ADDR_BITS = 13; // Set this parameter to control how many Address bits are used
parameter ROW_BITS = 13; // Set this parameter to control how many Row bits are used
parameter DQ_BITS = 16; // Set this parameter to control how many Data bits are used
parameter DM_BITS = 2; // Set this parameter to control how many DM bits are used
parameter COL_BITS = 10; // Set this parameter to control how many Column bits are used
parameter BA_BITS = 2; // Bank bits
`endif `endif
// Other Parameters
parameter full_mem_bits = BA_BITS+ADDR_BITS+COL_BITS; // Set this parameter to control how many unique addresses are used
parameter part_mem_bits = 10; // For fast sim load
parameter part_size = 256; // Set this parameter to indicate part size(512Mb, 256Mb, 128Mb)
//------------- Define Statements --------------
`define BANKS (1<<BA_BITS)
`define PAGE_SIZE (1<<COL_BITS)
//------------- Parameters (cke, addr[10], cs_n, ras_n, cas_n, we_n) --------------
parameter NOP = 6'b100111 ;
parameter ACTIVATE = 6'b100011 ;
parameter READ = 6'b100101 ;
parameter READ_AP = 6'b110101 ;
parameter READ_SUSPEND = 6'b000101 ;
parameter READ_AP_SUSPEND = 6'b010101 ;
parameter WRITE = 6'b100100 ;
parameter WRITE_AP = 6'b110100 ;
parameter WRITE_SUSPEND = 6'b000100 ;
parameter WRITE_AP_SUSPEND = 6'b010100 ;
parameter BURST_TERMINATE = 6'b100110 ;
parameter POWER_DOWN_CI = 6'b001111 ;
parameter POWER_DOWN_NOP = 6'b000111 ;
parameter DEEP_POWER_DOWN = 6'b000110 ;
parameter PRECHARGE = 6'b100010 ;
parameter PRECHARGE_ALL = 6'b110010 ;
parameter AUTO_REFRESH = 6'b100001 ;
parameter SELF_REFRESH = 6'b000001 ;
parameter LOAD_MODE = 6'b100000 ;
parameter CKE_DISABLE = 6'b011111 ;
parameter DEBUG = 0 ;
//----------------------------------------
// Error codes and reporting
//----------------------------------------
parameter ERR_MAX_REPORTED = -1; // >0 = report errors up to ERR_MAX_REPORTED, <0 = report all errors
parameter ERR_MAX = -1; // >0 = stop the simulation after ERR_MAX has been reached, <0 = never stop the simulation
parameter MSGLENGTH = 256;
parameter ERR_CODES = 16; // track up to 44 different error codes
// Enumerated error codes (0 = unused)
parameter ERR_MISC = 1;
parameter ERR_CMD = 2;
parameter ERR_STATUS = 3;
parameter ERR_tMRD = 4;
parameter ERR_tRAS = 5;
parameter ERR_tRC = 6;
parameter ERR_tRFC = 7;
parameter ERR_tRCD = 8;
parameter ERR_tRP = 9;
parameter ERR_tRRD = 11;
parameter ERR_tWR = 12;
parameter ERR_tCH = 13;
parameter ERR_tCL = 14;
parameter ERR_tXSR = 15;
parameter ERR_tCK_MIN = 16;
wire [ERR_CODES : 1] EXP_ERR ;
reg [ERR_CODES : 1] errcount ;
reg [8*12-1:0] err_strings [1:ERR_CODES];
integer ERR_MAX_INT = ERR_MAX;
assign EXP_ERR = {ERR_CODES {1'b0}}; // the model expects no errors. Can only be changed for debug by 'force' statement in testbench.
//------------- Port Declarations --------------
input clk ;
input cke ;
input [ADDR_BITS - 1 : 0] addr ;
input [BA_BITS - 1 : 0] ba ;
input cs_n ;
input ras_n ;
input cas_n ;
input we_n ;
input [DM_BITS - 1 : 0] dqm ;
inout [DQ_BITS - 1 : 0] dq ;
//------------- Register Declarations --------------
reg [8*MSGLENGTH:1] msg ;
reg [`BANKS - 1 :0] active_bank ;
reg [ADDR_BITS - 1 :0] activate_row [`BANKS - 1 : 0] ;
reg auto_refresh1_done ;
reg [ COL_BITS - 1 : 0] burst_count ;
reg [COL_BITS - 1 : 0] col_addr_burst_order [`PAGE_SIZE-1 : 0] ;
reg [BA_BITS - 1 : 0] bank_access_q [`PAGE_SIZE+2 : 0] ;
reg [ROW_BITS - 1 : 0] row_access_q [`PAGE_SIZE+2 : 0] ;
reg [COL_BITS - 1 : 0] column_access_q [`PAGE_SIZE+2 : 0] ;
reg [ 1 : 0] column_access_valid_q [`PAGE_SIZE+2 : 0] ;
reg [ 2 : 0] cas_latency ;
reg write_burst_mode ;
reg [BA_BITS - 1 : 0] interrupt_bank ;
reg burst_type ;
reg [DQ_BITS-1 : 0] Dq_out ;
reg [DQ_BITS-1 : 0] Dq_out_tAC ;
reg [DQ_BITS - 1 : 0] mdata ;
reg [`BANKS-1:0] ap_set ;
reg cke_q ;
reg [DM_BITS - 1 : 0] dqm_q ;
reg [ 1 : 0] dqm_rtw_chk ;
reg Sys_clk ;
reg [3 : 0] initialization_state ;
reg self_refresh_enter ;
reg power_down_enter ;
reg command_sequence_error ;
reg read_write_in_progress ;
// Memory Banks
`ifdef FULL_MEM
reg [DQ_BITS - 1 : 0] mem_array [0 : (1<<full_mem_bits)-1];
`else
reg [DQ_BITS - 1 : 0] mem_array [0 : (1<<part_mem_bits)-1];
reg [full_mem_bits - 1 : 0] addr_array [0 : (1<<part_mem_bits)-1];
reg [part_mem_bits : 0] mem_used;
reg [part_mem_bits : 0] memory_index;
initial mem_used = 0;
`endif
//------------- Integer Declarations --------------
integer ck_cntr_initial ;
integer ck_cntr_activate ;
integer ck_cntr_read ;
integer ck_cntr_read_ap ;
integer ck_cntr_write ;
integer ck_cntr_write_ap ;
integer ck_cntr_burst_terminate ;
integer ck_cntr_precharge ;
integer ck_cntr_auto_refresh ;
integer ck_cntr_self_refresh ;
integer ck_cntr_power_down ;
integer ck_cntr_clock_suspend ;
integer ck_cntr_deep_power_down ;
integer ck_cntr_load_mode ;
integer ck_cntr_cke ;
integer ck_cntr_cke_n ;
integer ck_cntr_cke_high ;
integer ck_cntr_bank_precharge [`BANKS-1:0] ;
integer ck_cntr_bank_activate [`BANKS-1:0] ;
integer ck_cntr_bank_write [`BANKS-1:0] ;
integer ck_cntr_bank_read [`BANKS-1:0] ;
integer ck_cntr_write_dq [`BANKS-1:0] ;
integer interrupt_write_ap_n [`BANKS-1:0] ;
integer interrupt_read_ap_n [`BANKS-1:0] ;
integer pasr ;
integer warnings ;
integer errors ;
integer burst_length ;
integer i ;
//------------- Time Declarations --------------
time tm_initial ;
time tm_activate ;
time tm_read ;
time tm_write ;
time tm_burst_terminate ;
time tm_precharge ;
time tm_auto_refresh ;
time tm_self_refresh ;
time tm_power_down ;
time tm_clock_suspend ;
time tm_deep_power_down ;
time tm_load_mode ;
time tm_bank_precharge [`BANKS-1:0] ;
time tm_bank_activate [`BANKS-1:0] ;
time tm_bank_write [`BANKS-1:0] ;
time tm_bank_read [`BANKS-1:0] ;
time tm_write_dq [`BANKS-1:0] ;
time tm_cke ;
time tm_cke_n ;
time tm_cke_high ;
time tm_clk_high_pulse_width ;
time tm_clk_low_pulse_width ;
time tm_clk_period ;
time tm_clk_negedge ;
time tm_clk_posedge ;
//------------- Wire Declarations --------------
wire addr_10 ;
wire [ 5 : 0] command ;
//--------------------- Outputs -----------------------
assign dq = Dq_out_tAC ;
//--------------------- Initialization -----------------------
initial begin
auto_refresh1_done = 1'b0 ;
initialization_state = 4'h0 ;
active_bank = {`BANKS{1'b1}} ;
Dq_out_tAC = 'bz ;
tm_initial = 0 ;
tm_activate = 0 ;
tm_read = 0 ;
tm_write = 0 ;
tm_burst_terminate = 0 ;
tm_precharge = 0 ;
tm_auto_refresh = 0 ;
tm_self_refresh = 0 ;
tm_power_down = 0 ;
tm_clock_suspend = 0 ;
tm_deep_power_down = 0 ;
tm_load_mode = 0 ;
for (i=0; i<`BANKS; i=i+1) begin
tm_bank_precharge[i] = 0 ;
tm_bank_activate[i] = 0 ;
tm_bank_write[i] = 0 ;
tm_bank_read[i] = 0 ;
tm_write_dq[i] = 0 ;
end
tm_cke = 0 ;
tm_cke_n = 0 ;
tm_cke_high = 0 ;
tm_clk_period = 0 ;
tm_clk_low_pulse_width = 0 ;
tm_clk_high_pulse_width= 0 ;
tm_clk_negedge = 0 ;
tm_clk_posedge = 0 ;
tm_clk_low_pulse_width = 0 ;
for (i=0; i<`BANKS; i=i+1) begin
ap_set[i] = 1'b0 ;
end
ck_cntr_initial = 100;
ck_cntr_activate = 100;
ck_cntr_read = 100;
ck_cntr_read_ap = 100;
ck_cntr_write = 100;
ck_cntr_write_ap = 100;
ck_cntr_burst_terminate = 100;
ck_cntr_precharge = 100;
ck_cntr_auto_refresh = 100;
ck_cntr_self_refresh = 100;
ck_cntr_power_down = 100;
ck_cntr_clock_suspend = 100;
ck_cntr_deep_power_down = 100;
ck_cntr_load_mode = 100;
ck_cntr_cke = 100;
ck_cntr_cke_n = 100;
ck_cntr_cke_high = 100;
for (i=0; i<`BANKS; i=i+1) begin
ck_cntr_bank_precharge[i] = 100;
ck_cntr_bank_activate[i] = 100;
ck_cntr_bank_write[i] = 100;
ck_cntr_bank_read[i] = 100;
ck_cntr_write_dq[i] = 100;
interrupt_write_ap_n[i] = 2;
interrupt_read_ap_n[i] = 1;
end
for (i=0; i<`PAGE_SIZE+3;i=i+1) begin
bank_access_q[i] = 'bz ;
row_access_q[i] = 'bz ;
column_access_q[i] = 'bz ;
column_access_valid_q[i] = 2'b00 ;
end
for (i=0; i<`PAGE_SIZE+3; i=i+1) begin
column_access_valid_q[i] = 2'b00 ;
end
warnings = 0;
errors = 0;
for (i=1; i<=ERR_CODES; i=i+1) begin
errcount[i] = 0;
end
self_refresh_enter = 0;
power_down_enter = 0;
command_sequence_error = 0;
read_write_in_progress = 0;
pasr = 0;
end
//---------------------- Command Selection ----------------------
assign addr_10 = addr[10] & ((cke_q & ~cs_n & ras_n & ~cas_n & we_n & ~(burst_length == `PAGE_SIZE) ) | // Read w/ap
(cke_q & ~cs_n & ras_n & ~cas_n & ~we_n & ~(burst_length == `PAGE_SIZE) ) | // Write w/ap
(cke_q & ~cs_n & ~ras_n & cas_n & ~we_n ) ); // Precharge all
// assign command = ({cke, addr_10, cs_n, (ras_n | cs_n), (cas_n | cs_n), (we_n | cs_n)} & {cke_q, {5{1'b1}}}) | {1'b0, {5{~cke_q}}};
assign command = {cke, addr_10, cs_n, (ras_n | cs_n), (cas_n | cs_n), (we_n | cs_n)} ;
//---------------------- Mode Register Selection ----------------------
task set_mode_reg;
begin
// Burst Length selection
if (addr[2:0] == 3'b000) begin
burst_length = 1 ;
end else if (addr[2:0] == 3'b001) begin
burst_length = 2 ;
end else if (addr[2:0] == 3'b010) begin
burst_length = 4 ;
end else if (addr[2:0] == 3'b011) begin
burst_length = 8 ;
end else if (addr[2:0] == 3'b111) begin
burst_length = `PAGE_SIZE ;
end else begin
burst_length = 0 ;
end
burst_type = addr[3] ;
cas_latency = addr[6:4] ;
write_burst_mode = addr[9] ;
end
endtask
task set_ext_mode_reg;
begin
// PASR selection
if (addr[2:0] == 3'b000) begin
pasr = 0 ;
end else if (addr[2:0] == 3'b001) begin
pasr = 1 ;
end else if (addr[2:0] == 3'b010) begin
pasr = 2 ;
end else if (addr[2:0] == 3'b101) begin
pasr = 3 ;
end else if (addr[2:0] == 3'b110) begin
pasr = 4 ;
end else begin
pasr = 5 ;
end
end
endtask
task column_burst_order;
begin
burst_count = 0 ;
for (i=0; i<burst_length; i=i+1) begin
if (burst_length == `PAGE_SIZE) begin
if (burst_type == 1'b0) begin
col_addr_burst_order[i] = addr[COL_BITS-1:0] + burst_count ;
end else if (burst_type == 1'b1) begin
col_addr_burst_order[i] = {COL_BITS{1'bx}} ;
end
end else if (burst_length == 1) begin
if (burst_type == 1'b0) begin
col_addr_burst_order[i] = {addr[COL_BITS-1:3], addr[2:0]} ;
end else if (burst_type == 1'b1) begin
col_addr_burst_order[i] = {addr[COL_BITS-1:3], addr[2:0]} ;
end
end else if (burst_length == 2) begin
if (burst_type == 1'b0) begin
col_addr_burst_order[i] = {addr[COL_BITS-1:3], addr[2:1], (burst_count[0] + addr[0])} ;
end else if (burst_type == 1'b1) begin
col_addr_burst_order[i] = {addr[COL_BITS-1:3], addr[2:1], (burst_count[0] ^ addr[0])} ;
end
end else if (burst_length == 4) begin
if (burst_type == 1'b0) begin
col_addr_burst_order[i] = {addr[COL_BITS-1:3], addr[2], (burst_count[1:0] + addr[1:0])} ;
end else if (burst_type == 1'b1) begin
col_addr_burst_order[i] = {addr[COL_BITS-1:3], addr[2], (burst_count[1:0] ^ addr[1:0])} ;
end
end else if (burst_length == 8) begin
if (burst_type == 1'b0) begin
col_addr_burst_order[i] = {addr[COL_BITS-1:3], (burst_count[2:0] + addr[2:0])} ;
end else if (burst_type == 1'b1) begin
col_addr_burst_order[i] = {addr[COL_BITS-1:3], (burst_count[2:0] ^ addr[2:0])} ;
end
end
burst_count = burst_count + 1'b1 ;
end
end
endtask
//---------------------- Memory Address Queue ----------------------
task column_address_read_queue;
begin
for (i=0; i<burst_length;i=i+1) begin
bank_access_q[cas_latency-1+i] = ba ;
row_access_q[cas_latency-1+i] = activate_row[ba] ;
column_access_q[cas_latency-1+i] = col_addr_burst_order[i] ;
column_access_valid_q[cas_latency-1+i] = 2'b10 ;
end
if (burst_length < `PAGE_SIZE) begin
for (i=burst_length; i< (burst_length+cas_latency-1);i=i+1) begin
bank_access_q[cas_latency-1+i] = 'bz ;
row_access_q[cas_latency-1+i] = 'bz ;
column_access_q[cas_latency-1+i] = 'bz ;
column_access_valid_q[cas_latency-1+i] = 2'b00 ;
end
end
end
endtask
task column_address_write_queue;
begin
for (i=0; i<burst_length;i=i+1) begin
bank_access_q[i] = ba ;
row_access_q[i] = activate_row[ba] ;
column_access_q[i] = col_addr_burst_order[i] ;
column_access_valid_q[i] = 2'b01 ;
end
if (burst_length < `PAGE_SIZE) begin
for (i=burst_length; i<(burst_length+cas_latency-1);i=i+1) begin
bank_access_q[i] = 'bz ;
row_access_q[i] = 'bz ;
column_access_q[i] = 'bz ;
column_access_valid_q[i] = 2'b00 ;
end
end
end
endtask
task burst_term_read_queue;
begin
for (i=0; i<burst_length;i=i+1) begin
bank_access_q[cas_latency-1+i] = 'bz ;
row_access_q[cas_latency-1+i] = 'bz ;
column_access_q[cas_latency-1+i] = 'bz ;
column_access_valid_q[cas_latency-1+i] = 2'b00 ;
end
end
endtask
task burst_term_write_queue;
begin
for (i=0; i<burst_length;i=i+1) begin
bank_access_q[i] = 'bz ;
row_access_q[i] = 'bz ;
column_access_q[i] = 'bz ;
column_access_valid_q[i] = 2'b00 ;
end
end
endtask
//---------------------- Read Data suppression ----------------------
task read_data_suppression;
input [DQ_BITS - 1 : 0] data ;
input [DM_BITS - 1 : 0] dqm ;
output [DQ_BITS - 1 : 0] mdata ;
begin
for (i=0; i<DQ_BITS; i=i+1) begin
if (~dqm[i/8]) begin
mdata[i] = data[i];
end else if (dqm[i/8]) begin
mdata[i] = 1'bz;
end
end
end
endtask
//---------------------- Mask Data ----------------------
task mask_data;
input [BA_BITS - 1 : 0] bank ;
input [ADDR_BITS - 1 : 0] row ;
input [COL_BITS - 1 : 0] col ;
input [DQ_BITS - 1 : 0] data ;
input [DM_BITS - 1 : 0] dqm ;
output [DQ_BITS - 1 : 0] mdata ;
reg [DQ_BITS - 1 : 0] read_data ;
begin
read_mem({bank, row, col}, read_data);
for (i=0; i<DQ_BITS; i=i+1) begin
if (~dqm[i/8]) begin
mdata[i] = data[i];
end else if (dqm[i/8]) begin
mdata[i] = read_data[i];
end
end
end
endtask
//---------------------- Check for active read/write command task ----------------------
task active_read_write;
begin
read_write_in_progress = 1'b0 ;
for (i=0; i<cas_latency; i=i+1) begin
if (|column_access_valid_q[i] != 1'b0) begin
read_write_in_progress = 1'b1 ;
end
end
end
endtask
//---------------------- Auto-Precharge tasks ----------------------
task interrupt_auto_precharge;
input [BA_BITS - 1 : 0] bank ;
begin
if (ap_set[bank]) begin
if (interrupt_write_ap_n[bank] < 2) begin
if ((interrupt_write_ap_n[bank] == 1 ) &
(($time - tm_bank_activate[bank]) >= tRAS) ) begin
ap_set[bank] = 1'b0 ;
precharge_cmd_func(bank, tWRa) ;
interrupt_write_ap_n[bank] = 2 ;
end else begin
interrupt_write_ap_n[bank] = 1 ;
ck_cntr_write_dq[bank] = 0 ;
tm_write_dq[bank] = $time;
end
end else if (interrupt_read_ap_n[bank] == 0) begin
if (($time - tm_bank_activate[bank]) >= tRAS) begin
ap_set[bank] = 1'b0 ;
precharge_cmd_func(bank, 0) ;
interrupt_read_ap_n[bank] = 1 ;
end
end
end
end
endtask
task auto_precharge_management;
begin
for (i=0; i<`BANKS; i=i+1) begin
if (ap_set[i]) begin
if (tm_bank_write[i] > tm_bank_read[i]) begin
if ((ck_cntr_bank_write[i] >= burst_length) &
(($time - tm_bank_activate[i]) >= tRAS ) ) begin
precharge_cmd_func(i, tWRa) ;
end
end else begin
if ((ck_cntr_bank_read[i] >= burst_length) &
(($time - tm_bank_activate[i]) >= tRAS ) ) begin
precharge_cmd_func(i, 0) ;
end
end
end
end
end
endtask
//---------------------- DQ Management ----------------------
task data_management;
output [DQ_BITS - 1 :0] Dq_out ;
reg [DQ_BITS - 1 :0] rdata_out ;
begin
if (column_access_valid_q[0] == 2'b01) begin
mask_data ( bank_access_q[0], row_access_q[0], column_access_q[0] , dq, dqm, mdata );
write_mem ({bank_access_q[0], row_access_q[0], column_access_q[0]}, mdata );
if (~(|dqm == 1'b1)) begin
ck_cntr_write_dq[bank_access_q[0]] = 0 ;
tm_write_dq[bank_access_q[0]] = $time ;
end
end
if (column_access_valid_q[0] == 2'b10) begin
read_mem ({bank_access_q[0], row_access_q[0], column_access_q[0]}, rdata_out );
read_data_suppression(rdata_out, dqm_q, Dq_out );
end else begin
Dq_out = 'bz ;
end
end
endtask
//--------------------- dq buffer Output -----------------------
task Dq_buffer_output;
begin
if (cas_latency == 3) begin
Dq_out_tAC <= #tAC3 Dq_out ;
end else if (cas_latency == 2) begin
Dq_out_tAC <= #tAC2 Dq_out ;
end else if (cas_latency == 1) begin
Dq_out_tAC <= #tAC1 Dq_out ;
end
end
endtask
//-------------------------------- Clk Stabilization Error Check -------------------------------
task clk_stabilization_func;
begin
if (clk) begin
tm_clk_low_pulse_width = $time - tm_clk_negedge ;
tm_clk_period = $time - tm_clk_posedge ;
tm_clk_posedge = $time ;
end else if (~clk) begin
tm_clk_high_pulse_width = $time - tm_clk_posedge ;
tm_clk_negedge = $time ;
end
end
endtask
task clk_stabilization_err_chk;
begin
if (cke) begin
if (tm_clk_high_pulse_width < tCH) begin
if (DEBUG == 1'b1) begin
$sformat (msg, " : tCH violation, High Pulse Width = %t", tm_clk_high_pulse_width); ERROR(ERR_tCH, msg);
end
end
if (tm_clk_low_pulse_width < tCL) begin
if (DEBUG == 1'b1) begin
$sformat (msg, " : tCL violation, Low Pulse Width = %t", tm_clk_low_pulse_width); ERROR(ERR_tCL, msg);
end
end
if (cas_latency == 3) begin
if (tm_clk_period < tCK3_min) begin
if (DEBUG == 1'b1) begin
$sformat (msg, " : tCK Min violation, Clock Period = %t", tm_clk_period); ERROR(ERR_tCK_MIN, msg);
end
end
end else if (cas_latency == 2) begin
if (tm_clk_period < tCK2_min) begin
if (DEBUG == 1'b1) begin
$sformat (msg, " : tCK Min violation, Clock Period = %t", tm_clk_period); ERROR(ERR_tCK_MIN, msg);
end
end
end else if (cas_latency == 1) begin
if (tm_clk_period < tCK1_min) begin
if (DEBUG == 1'b1) begin
$sformat (msg, " : tCK Min violation, Clock Period = %t", tm_clk_period); ERROR(ERR_tCK_MIN, msg);
end
end
end
end
end
endtask
//-------------------------------- Initialization tasks -------------------------------
task initialization_cmd_func; // ************************** INITIALIZATION STATES ********************************
begin // initialization_state 0 - waiting for power up and stable clock
if (initialization_state == 4'h0) begin // initialization_state 1 - chip powered up and stable clock applied
if (cke & ~cke_q) begin // initialization_state 2 - all banks precharged
initialization_state = 4'h1 ; // initialization_state 3 - one auto refresh command executed
end // initialization_state 4 - two auto refresh commands executed
end else if (initialization_state == 4'h1) begin // initialization_state 5 - load mode command executed
if (~(|active_bank)) begin // initialization_state 6 - extended load mode command executed
initialization_state = 4'h2 ; // initialization_state 7 - both load mode and extended load mode command executed
end // initialization_state 8 - tRFC after the second auto refresh command has expired
end else if (initialization_state == 4'h2) begin // initialization_state 9 - Initialization message printed to the screen
if (command == AUTO_REFRESH) begin
initialization_state = 4'h3 ;
end
end else if (initialization_state == 4'h3) begin
if (command == AUTO_REFRESH) begin
initialization_state = 4'h4 ;
end
end else if (initialization_state == 4'h4) begin
if ((command == LOAD_MODE) &
(ba == 0 ) ) begin
initialization_state = 4'h5 ;
end
if ((command == LOAD_MODE) &
(ba == 2 ) ) begin
initialization_state = 4'h6 ;
end
end else if (initialization_state == 4'h5) begin
if ((command == LOAD_MODE) &
(ba == 2 ) ) begin
initialization_state = 4'h7 ;
end
end else if (initialization_state == 4'h6) begin
if ((command == LOAD_MODE) &
(ba == 0 ) ) begin
initialization_state = 4'h7 ;
end
end else if (initialization_state == 4'h7) begin
if (($time - tm_auto_refresh) > tRFC) begin
initialization_state = 4'h8 ;
end
end else if (initialization_state == 4'h8) begin
initialization_state = 4'h9 ;
end
end
endtask
task initialization_err_chk;
begin
if ((cke & ~cke_q) &
(initialization_state != 4'h9)) begin
$sformat (msg, "WARNING: SDRAM requires a 100us delay prior to issuing any command other than COMMAND INHIBIT or NOP"); WARN(msg);
end
if (((command == ACTIVATE ) |
(command == ACTIVATE ) |
(command == READ ) |
(command == READ_AP ) |
(command == WRITE ) |
(command == WRITE_AP ) ) &
(initialization_state < 8) ) begin
$sformat (msg, " ERROR: Initialization incomplete"); ERROR(ERR_MISC, msg);
end
end
endtask
task initialization_cmd_display;
begin
if (DEBUG == 1'b1) begin
if (initialization_state == 8) begin
$sformat (msg, " INIT : INITIALIZATION COMPLETE"); NOTE(msg);
end
end
end
endtask
//-------------------------------- Load Mode Tasks -------------------------------
task load_mode_cmd_func;
begin
if (ba == 2'b10) begin
set_ext_mode_reg;
// Ext_mode_reg = addr ;
end else if (ba == 2'b00) begin
// Mode_reg = addr ;
set_mode_reg;
end
ck_cntr_load_mode = 0 ;
tm_load_mode = $time ;
end
endtask
task load_mode_err_chk;
begin
if (|active_bank) begin
if (ba == 0) begin
$sformat (msg, " ERROR: Bank is not Precharged for Lode Mode command, Bank = %d", i); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Lode Mode command will be ignored"); NOTE(msg);
end else if (ba == 2) begin
$sformat (msg, " ERROR: Bank is not Precharged for Extended Lode Mode command, Bank = %d", i); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Extended Lode Mode command will be ignored"); NOTE(msg);
end
end else begin
if ((addr[3] == 1'b1 ) &
(addr[2:0] == 3'b111) ) begin
$sformat (msg, " ERROR: Burst Type Interleaved is illegal with Full Page Mode, Bank = %d", i); ERROR(ERR_MISC, msg);
end
if ($time - tm_precharge < tRP) begin
$sformat (msg, " ERROR: tRP violation"); ERROR(ERR_tRP, msg);
end
if ($time - tm_auto_refresh < tRFC) begin
$sformat (msg, " ERROR: tRFC violation"); ERROR(ERR_tRFC, msg);
end
if (ck_cntr_load_mode < tMRD) begin
$sformat (msg, " ERROR: tMRD violation"); ERROR(ERR_tMRD, msg);
end
end
end
endtask
task load_mode_cmd_display;
input [BA_BITS - 1 : 0] bank ;
input [ADDR_BITS - 1 : 0] address ;
begin
if (bank == 2'b10) begin
$sformat (msg, " LMR : EXTENDED LOAD MODE REGISTER"); NOTE(msg);
// Self Refresh Coverage
case (address[2 : 0])
3'b000 : $sformat (msg, " EMR : Self Refresh Cov = 4 banks") ;
3'b001 : $sformat (msg, " EMR : Self Refresh Cov = 2 banks") ;
3'b010 : $sformat (msg, " EMR : Self Refresh Cov = 1 bank") ;
3'b101 : $sformat (msg, " EMR : Self Refresh Cov = 1/2 bank");
3'b110 : $sformat (msg, " EMR : Self Refresh Cov = 1/4 bank");
default : $sformat (msg, " EMR : Error: Self Refresh Cov = Reserved");
endcase
NOTE(msg);
// Maximum Case Temp
//case (address[4 : 3])
//2'b11 : $sformat (msg, " EMR : Maximum Case Temp = 85C");
//2'b00 : $sformat (msg, " EMR : Maximum Case Temp = 70C");
//2'b01 : $sformat (msg, " EMR : Maximum Case Temp = 45C");
//2'b10 : $sformat (msg, " EMR : Maximum Case Temp = 15C");
//endcase
//NOTE(msg);
// Drive Strength
case (address[6 : 5])
2'b00 : $sformat (msg, " EMR : Drive Strength = Full Strength") ;
2'b01 : $sformat (msg, " EMR : Drive Strength = Half Strength") ;
2'b10 : $sformat (msg, " EMR : Drive Strength = Quarter Strength");
2'b11 : $sformat (msg, " EMR : Drive Strength = Eighth Strength") ;
default : $sformat (msg, " EMR : Error: Drive Strength = Reserved") ;
endcase
NOTE(msg);
// Reserved
case (address[11 : 7])
5'b00000 : begin end //do nothing
default : $sformat (msg, " EMR : Error: Ext_mode_Reg[11:7] are Reserved");
endcase
NOTE(msg);
set_ext_mode_reg;
end else if (bank == 2'b00) begin
$sformat (msg, " LMR : LOAD MODE REGISTER"); NOTE(msg);
// Burst Length
case (address[2 : 0])
3'b000 : $sformat (msg, " LMR : Burst Length = 1") ;
3'b001 : $sformat (msg, " LMR : Burst Length = 2") ;
3'b010 : $sformat (msg, " LMR : Burst Length = 4") ;
3'b011 : $sformat (msg, " LMR : Burst Length = 8") ;
3'b111 : $sformat (msg, " LMR : Burst Length = Full") ;
default : $sformat (msg, " LMR : Error: Burst Length = Reserved");
endcase
NOTE(msg);
// Burst Type
if (address[3] === 1'b0) begin
$sformat (msg, " LMR : Burst Type = Sequential"); NOTE(msg);
end else if (address[3] === 1'b1) begin
$sformat (msg, " LMR : Burst Type = Interleaved"); NOTE(msg);
end else begin
$sformat (msg, " LMR : Error: Burst Type = Reserved"); NOTE(msg);
end
// CAS Latency
case (address[6 : 4])
3'b001 : $sformat (msg, " LMR : CAS Latency = 1") ;
3'b010 : $sformat (msg, " LMR : CAS Latency = 2") ;
3'b011 : $sformat (msg, " LMR : CAS Latency = 3") ;
default : $sformat (msg, " LMR : Error: CAS Latency = Reserved");
endcase
NOTE(msg);
// Op Mode
case (address[8 : 7])
2'b00 : begin end // do nothing
default : $sformat (msg, " LMR : Error: CAS Latency = Reserved");
endcase
NOTE(msg);
// Write Burst Mode
if (address[9] === 1'b0) begin
$sformat (msg, " LMR : Write Burst Mode = Programmed Burst Length"); NOTE(msg);
end else if (address[9] === 1'b1) begin
$sformat (msg, " LMR : Write Burst Mode = Single Location Access"); NOTE(msg);
end else begin
$sformat (msg, " LMR : Error: Write Burst Mode = Reserved"); NOTE(msg);
end
// Reserved
case (address[11 : 10])
5'b00000 : begin end //do nothing
default : $sformat (msg, " LMR : Error: Ext_mode_Reg[11:10] should be 0");
endcase
NOTE(msg);
set_mode_reg;
end
end
endtask
//-------------------------------- Activate Tasks -------------------------------
task activate_cmd_func;
input [BA_BITS-1 : 0] bank ;
input [ADDR_BITS-1 : 0] address ;
begin
activate_row[bank] = address ;
active_bank[bank] = 1'b1 ;
ck_cntr_activate[bank] = 0 ;
tm_activate[bank] = $time ;
ck_cntr_bank_activate[bank] = 0 ;
tm_bank_activate[bank] = $time ;
end
endtask
task activate_err_chk;
begin
if (active_bank[ba] == 1'b1) begin
$sformat (msg, " ERROR: Bank already activated -- data can be corrupted"); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Activate command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1;
end else begin
`ifdef Y15W
for (i=0; i<`BANKS; i=i+1) begin
if (i != ba) begin
if (ck_cntr_bank_activate[i] < tRRD) begin
$sformat (msg, " ERROR: tRRD violation : Bank = %d", ba); ERROR(ERR_tRRD, msg);
end
end
end
`else `ifdef Y25M
for (i=0; i<`BANKS; i=i+1) begin
if (i != ba) begin
if ($time - tm_bank_activate[i] < tRRD) begin
$sformat (msg, " ERROR: tRRD violation : Bank = %d", ba); ERROR(ERR_tRRD, msg);
end
end
end
`else `ifdef Y26W
for (i=0; i<`BANKS; i=i+1) begin
if (i != ba) begin
if ($time - tm_bank_activate[i] < tRRD) begin
$sformat (msg, " ERROR: tRRD violation : Bank = %d", ba); ERROR(ERR_tRRD, msg);
end
end
end
`else
if ((part_size == 128) |
(part_size == 64 ) ) begin
for (i=0; i<`BANKS; i=i+1) begin
if (i != ba) begin
if ($time - tm_bank_activate[i] < tRRD) begin
$sformat (msg, " ERROR: tRRD violation : Bank = %d", ba); ERROR(ERR_tRRD, msg);
end
end
end
end else begin
for (i=0; i<`BANKS; i=i+1) begin
if (i != ba) begin
if (ck_cntr_bank_activate[i] < tRRD) begin
$sformat (msg, " ERROR: tRRD violation : Bank = %d", ba); ERROR(ERR_tRRD, msg);
end
end
end
end
`endif `endif `endif
if ($time - tm_bank_activate[ba] < tRC) begin
$sformat (msg, " ERROR: tRC violation : Bank = %d", ba); ERROR(ERR_tRC, msg);
end
if ($time - tm_bank_precharge[ba] < tRP) begin
$sformat (msg, " ERROR: tRP violation : Bank = %d", ba); ERROR(ERR_tRP, msg);
end
if ($time - tm_auto_refresh < tRFC) begin
$sformat (msg, " ERROR: tRFC violation : Bank = %d", ba); ERROR(ERR_tRFC, msg);
end
if (($time - tm_cke_high < tXSR) &
(self_refresh_enter == 1 ) ) begin
$sformat (msg, " ERROR: tXSR violation"); ERROR(ERR_tXSR, msg);
end
if (ck_cntr_load_mode < tMRD) begin
$sformat (msg, " ERROR: tMRD violation"); ERROR(ERR_tMRD, msg);
end
if (active_bank[ba] == 1'b1) begin
$sformat (msg, " ERROR: Bank already activated -- data can be corrupted"); ERROR(ERR_CMD, msg);
end
self_refresh_enter = 0 ;
end
end
endtask
task activate_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " ACT : ACTIVATE - Bank = %d Row = %h", ba, addr); NOTE(msg);
end
end
endtask
//-------------------------------- Precharge Tasks -------------------------------
task precharge_cmd_func;
input [BA_BITS-1 : 0] bank ;
input integer delay;
begin
if (delay > 0) begin
active_bank[bank] <= #delay 1'b0 ;
ck_cntr_bank_precharge[bank] <= #delay 0 ;
ck_cntr_precharge <= #delay 0 ;
tm_bank_precharge[bank] <= #delay ($time + delay) ;
tm_precharge <= #delay ($time + delay) ;
ap_set[bank] <= #delay 1'b0 ;
end else begin
active_bank[bank] = 1'b0 ;
ck_cntr_bank_precharge[bank] = 0 ;
ck_cntr_precharge = 0 ;
tm_bank_precharge[bank] = $time ;
tm_precharge = $time ;
ap_set[bank] = 1'b0 ;
// Precharge interrupt a read command to the same bank
if (bank_access_q[0] == bank) begin
for (i=(cas_latency-1); i<((cas_latency-1)+burst_length); i=i+1) begin
if (bank_access_q[i] == bank) begin
column_access_valid_q[i] = 2'b00 ;
end
end
end
// Precharge interrupt a write command to the same bank
if ((bank_access_q[0] == bank ) &
(column_access_valid_q[0] == 2'b01) ) begin
for (i=0; i<burst_length; i=i+1) begin
if (bank_access_q[i] == bank) begin
column_access_valid_q[i] = 2'b00 ;
end
end
end
end
end
endtask
task precharge_err_chk;
input [BA_BITS-1 : 0] bank ;
begin
if (active_bank[bank] == 1'b1) begin
if ($time - tm_bank_activate[bank] < tRAS) begin
$sformat (msg, " ERROR: tRAS violation : Bank = %d", bank); ERROR(ERR_tRAS, msg);
end
if ($time - tm_write_dq[bank] < tWRm) begin
$sformat (msg, " ERROR: tWR violation : Bank = %d", bank); ERROR(ERR_tWR, msg);
end
if ($time - tm_auto_refresh < tRFC) begin
$sformat (msg, " ERROR: tRFC violation"); ERROR(ERR_tRFC, msg);
end
if (ck_cntr_load_mode < tMRD) begin
$sformat (msg, " ERROR: tMRD violation"); ERROR(ERR_tMRD, msg);
end
if ((ap_set[bank] == 1'b1) &
(ba == bank ) ) begin
$sformat (msg, " ERROR: Precharge issued to bank currently in auto precharge mode : Bank = %d", bank); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Precharge command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1 ;
end
if ((column_access_valid_q[0] == 2'b01 ) &
(ap_set[bank] == 1'b0 ) &
(dqm != {DM_BITS{1'b1}} ) ) begin
$sformat (msg, " ERROR: Incorrect assertion of data masks during write to precharge, Bank = %d", bank); ERROR(ERR_MISC, msg);
end
end
end
endtask
task precharge_cmd_display;
input [BA_BITS-1 : 0] bank ;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " PRE : PRECHARGE - Bank = %d", bank); NOTE(msg);
end
end
endtask
//-------------------------------- Precharge All Tasks -------------------------------
task precharge_all_cmd_func;
begin
for (i=0; i<`BANKS; i=i+1) begin
precharge_cmd_func(i, 0);
end
end
endtask
task precharge_all_err_chk;
begin
for (i=0; i<`BANKS; i=i+1) begin
precharge_err_chk(i);
end
end
endtask
task precharge_all_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, "PREALL: PRECHARGE ALL"); NOTE(msg);
end
end
endtask
//-------------------------------- Write Tasks -------------------------------
task write_cmd_func;
begin
column_burst_order ;
column_address_write_queue ;
tm_write = $time ;
tm_bank_write[ba] = $time ;
ck_cntr_write = 0 ;
ck_cntr_bank_write[ba] = 0 ;
// write interrupt write ap
if ((column_access_valid_q[0] == 2'b01) &
(bank_access_q[0] != ba ) &
(|ap_set ) ) begin
interrupt_write_ap_n[ba] = 0 ;
interrupt_bank = bank_access_q[0];
end
// write interrupt read ap
if ((column_access_valid_q[0] == 2'b10) &
(bank_access_q[0] != ba ) &
(|ap_set ) ) begin
interrupt_read_ap_n[ba] = 0 ;
interrupt_bank = bank_access_q[0];
end
end
endtask
task write_err_chk;
begin
if (active_bank[ba] == 1'b0) begin
$sformat (msg, " ERROR: Bank is not Activated for Write, Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Write command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1 ;
end else begin
if (($time - tm_bank_activate[ba]) < tRCD) begin
$sformat (msg, " ERROR: tRCD violation : Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_tRCD, msg);
end
if ((ap_set[ba] == 1'b1 ) &
(tm_bank_write[ba] > tm_bank_read[ba]) ) begin
$sformat (msg, " ERROR: Write interrupt Write with autoprecharge to the same bank: Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Write command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end
if ((ap_set[ba] == 1'b1 ) &
(tm_bank_write[ba] < tm_bank_read[ba]) ) begin
$sformat (msg, " ERROR: Write interrupt Read with autoprecharge to the same bank: Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Write command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end
if (((dqm_rtw_chk[0] == 1'b1 ) |
(dqm_rtw_chk[1] == 1'b1 ) ) &
(ap_set[ba] == 1'b0 ) ) begin
$sformat (msg, " ERROR: DQ contention caused by incorrect assertion of data masks during read to write, Bank = %d", ba); ERROR(ERR_MISC, msg);
end
end
end
endtask
task write_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " WR : WRITE - Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); NOTE(msg);
end
end
endtask
//-------------------------------- Read Tasks -------------------------------
task read_cmd_func;
begin
column_burst_order ;
if (column_access_valid_q[0] == 2'b01) begin
for (i=0; i<(burst_length+cas_latency-1); i=i+1) begin
column_access_valid_q[i] = 2'b00 ;
end
end
column_address_read_queue ;
tm_read = $time ;
tm_bank_read[ba] = $time ;
ck_cntr_read = 0 ;
ck_cntr_bank_read[ba] = 0 ;
// read interrupt write ap
if ((column_access_valid_q[0] == 2'b01) &
(|ap_set ) ) begin
interrupt_write_ap_n[ba] = 0 ;
interrupt_bank = bank_access_q[0];
end
// read interrupt read ap
if ((column_access_valid_q[0] == 2'b10) &
(|ap_set ) ) begin
interrupt_read_ap_n[ba] = 0 ;
interrupt_bank = bank_access_q[0];
end
end
endtask
task read_err_chk;
begin
if (active_bank[ba] == 1'b0) begin
$sformat (msg, " ERROR: Bank is not Activated for Read, Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Read command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1 ;
end else begin
if (($time - tm_bank_activate[ba]) < tRCD) begin
$sformat (msg, " ERROR: tRCD violation : Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_tRCD, msg);
end
if ((ap_set[ba] == 1'b1 ) &
(tm_bank_write[ba] > tm_bank_read[ba]) ) begin
$sformat (msg, " ERROR: Read interrupt Write with autoprecharge to the same bank: Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Read command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1 ;
end
if ((ap_set[ba] == 1'b1 ) &
(tm_bank_write[ba] < tm_bank_read[ba]) ) begin
$sformat (msg, " ERROR: Read interrupt Read with autoprecharge to the same bank: Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Read command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1 ;
end
end
end
endtask
task read_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " RD : READ - Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); NOTE(msg);
end
end
endtask
//-------------------------------- Write with auto-precharge Tasks -------------------------------
task write_ap_cmd_func;
begin
column_burst_order ;
column_address_write_queue ;
tm_write = $time ;
tm_bank_write[ba] = $time ;
ck_cntr_write = 0 ;
ck_cntr_bank_write[ba] = 0 ;
// write ap interrupt write ap
if ((column_access_valid_q[0] == 2'b01) &
(|ap_set ) ) begin
interrupt_write_ap_n[ba] = 0 ;
interrupt_bank = bank_access_q[0];
end
// write ap interrupt read ap
if ((column_access_valid_q[0] == 2'b10) &
(|ap_set ) ) begin
interrupt_read_ap_n[ba] = 0 ;
interrupt_bank = bank_access_q[0];
end
ap_set[ba] = 1 ;
end
endtask
task write_ap_err_chk;
begin
if (active_bank[ba] == 1'b0) begin
$sformat (msg, " ERROR: Bank is not Activated for Write with autoprecharge, Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Write with autoprecharge command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end else begin
if (($time - tm_bank_activate[ba]) < tRCD) begin
$sformat (msg, " ERROR: tRCD violation : Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_tRCD, msg);
end
if ((ap_set[ba] == 1'b1 ) &
(tm_bank_write[ba] > tm_bank_read[ba]) ) begin
$sformat (msg, " ERROR: Write with autoprecharge interrupt Write with autoprecharge to the same bank: Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Write with autoprecharge command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end
if ((ap_set[ba] == 1'b1 ) &
(tm_bank_write[ba] < tm_bank_read[ba]) ) begin
$sformat (msg, " ERROR: Write with autoprecharge interrupt Read with autoprecharge to the same bank: Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Write with autoprecharge command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end
if (((dqm_rtw_chk[0] == 1'b1 ) |
(dqm_rtw_chk[1] == 1'b1 ) ) &
(ap_set[ba] == 1'b0 ) ) begin
$sformat (msg, " ERROR: DQ contention caused by incorrect assertion of data masks during read to write, Bank = %d", ba); ERROR(ERR_CMD, msg);
end
end
end
endtask
task write_ap_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " WRAP : WRITE WITH AUTOPRECHARGE - Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); NOTE(msg);
end
end
endtask
//-------------------------------- Read with auto-precharge Tasks -------------------------------
task read_ap_cmd_func;
begin
column_burst_order ;
if (column_access_valid_q[0] == 2'b01) begin
for (i=0; i<(burst_length+cas_latency-1); i=i+1) begin
column_access_valid_q[i] = 2'b00 ;
end
end
column_address_read_queue ;
tm_read = $time ;
tm_bank_read[ba] = $time ;
ck_cntr_read = 0 ;
ck_cntr_bank_read[ba] = 0 ;
// read interrupt write ap
if ((column_access_valid_q[0] == 2'b01) &
(bank_access_q[0] != ba ) &
(|ap_set ) ) begin
interrupt_write_ap_n[ba] = 0 ;
interrupt_bank = bank_access_q[0];
end
// read interrupt read ap
if ((column_access_valid_q[0] == 2'b10) &
(bank_access_q[0] != ba ) &
(|ap_set ) ) begin
interrupt_read_ap_n[ba] = 0 ;
interrupt_bank = bank_access_q[0];
end
ap_set[ba] = 1 ;
end
endtask
task read_ap_err_chk;
begin
if (active_bank[ba] == 1'b0) begin
$sformat (msg, " ERROR: Bank is not Activated for Read with autoprecharge, Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Read with autoprecharge command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end else begin
if (($time - tm_bank_activate[ba]) < tRCD) begin
$sformat (msg, " ERROR: tRCD violation : Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_tRCD, msg);
end
if ((ap_set[ba] == 1'b1 ) &
(tm_bank_write[ba] > tm_bank_read[ba]) ) begin
$sformat (msg, " ERROR: Read with autoprecharge interrupt Write with autoprecharge to the same bank: Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Read with autoprecharge command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end
if ((ap_set[ba] == 1'b1 ) &
(tm_bank_write[ba] < tm_bank_read[ba]) ) begin
$sformat (msg, " ERROR: Read with autoprecharge interrupt Read with autoprecharge to the same bank: Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Read with autoprecharge command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end
end
end
endtask
task read_ap_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " RDAP : READ WITH AUTOPRECHARGE - Bank = %d, Row = %h, Col = %h", ba, activate_row[ba], addr); NOTE(msg);
end
end
endtask
//-------------------------------- Auto-refresh Tasks -------------------------------
task auto_refresh_cmd_func;
begin
tm_auto_refresh = $time ;
ck_cntr_auto_refresh = 0 ;
end
endtask
task auto_refresh_err_chk;
begin
if (|active_bank) begin
$sformat (msg, " ERROR: Banks are not precharged for auto refresh"); ERROR(ERR_CMD, msg);
$sformat (msg, " NOTE : Auto refresh command will be ignored : Bank = %d", ba); NOTE(msg);
command_sequence_error = 1'b1 ;
end else begin
if (($time - tm_precharge) < tRP) begin
$sformat (msg, " ERROR: tRP violation during auto refresh"); ERROR(ERR_tRP, msg);
end
if (($time - tm_auto_refresh) < tRFC) begin
$sformat (msg, " ERROR: tRFC violation during auto refresh"); ERROR(ERR_tRFC, msg);
end
if (ck_cntr_load_mode < tMRD) begin
$sformat (msg, " ERROR: tMRD violation during auto refresh"); ERROR(ERR_tMRD, msg);
end
end
end
endtask
task auto_refresh_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " AREF : AUTO REFRESH"); NOTE(msg);
end
end
endtask
//-------------------------------- Self-refresh Tasks -------------------------------
task self_refresh_cmd_func;
begin
erase_mem(pasr);
tm_self_refresh = $time ;
ck_cntr_self_refresh = 0 ;
self_refresh_enter = 1 ;
end
endtask
task self_refresh_err_chk;
begin
if (|active_bank) begin
$sformat (msg, " ERROR: Banks are not precharged for self refresh command"); ERROR(ERR_CMD, msg);
end else begin
if (($time - tm_precharge) < tRP) begin
$sformat (msg, " ERROR: tRP violation during self refresh command"); ERROR(ERR_tRP, msg);
end
if (($time - tm_auto_refresh) < tRFC) begin
$sformat (msg, " ERROR: tRFC violation during self refresh command"); ERROR(ERR_tRFC, msg);
end
if (ck_cntr_load_mode < tMRD) begin
$sformat (msg, " ERROR: tMRD violation during self refresh command"); ERROR(ERR_tMRD, msg);
end
end
end
endtask
task self_refresh_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " SREF : SELF REFRESH"); NOTE(msg);
end
end
endtask
//-------------------------------- ???????????????? -------------------------------
task clock_suspend_cmd_func;
begin
tm_clock_suspend = $time ;
ck_cntr_clock_suspend = 0 ;
end
endtask
task clock_suspend_err_chk;
begin
end
endtask
task clock_suspend_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " CKSM : CLOCK SUSPEND MODE"); NOTE(msg);
end
end
endtask
//-------------------------------- Exit Power Down Tasks -------------------------------
//------------- Parameters (cke, addr[10], cs_n, ras_n, cas_n, we_n) --------------
task exit_power_down_err_chk;
begin
if (cke & ~cke_q) begin
if ((power_down_enter == 1'b1 ) |
(self_refresh_enter == 1'b1) ) begin
if (~( (command == NOP) |
(cke & cs_n ) ) ) begin
$sformat (msg, " ERROR: exit powerdown violation"); ERROR(ERR_CMD, msg);
end
power_down_enter = 1'b0;
end
end
end
endtask
//-------------------------------- Power Down Tasks -------------------------------
task power_down_cmd_func;
begin
tm_power_down = $time ;
ck_cntr_power_down = 0 ;
end
endtask
task power_down_err_chk;
begin
if (|active_bank) begin
$sformat (msg, " ERROR: All banks need to be precharged before powerdown"); ERROR(ERR_CMD, msg);
end else begin
if (ck_cntr_precharge < 2) begin
$sformat (msg, " ERROR: precharge to powerdown violation"); ERROR(ERR_MISC, msg);
end
if (($time - tm_auto_refresh) < tRFC) begin
$sformat (msg, " ERROR: tRFC violation"); ERROR(ERR_tRFC, msg);
end
if (ck_cntr_load_mode < tMRD) begin
$sformat (msg, " ERROR: tMRD violation"); ERROR(ERR_tMRD, msg);
end
power_down_enter = 1'b1 ;
end
end
endtask
task power_down_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " PREPD: PRECHARGE POWERDOWN"); NOTE(msg);
end
end
endtask
//-------------------------------- Deep Power Down Tasks -------------------------------
task deep_power_down_cmd_func;
begin
if (cke_q) begin
erase_mem(0);
end
tm_deep_power_down = $time ;
ck_cntr_deep_power_down = 0 ;
end
endtask
task deep_power_down_err_chk;
begin
if (($time - ck_cntr_precharge) < 2) begin
$sformat (msg, " ERROR: precharge to deep power down violation"); ERROR(ERR_CMD, msg);
end
if (($time - tm_auto_refresh) < tRFC) begin
$sformat (msg, " ERROR: auto refresh to deep power down violation"); ERROR(ERR_tRFC, msg);
end
if (ck_cntr_load_mode < tMRD) begin
$sformat (msg, " ERROR: load mode to deep power down violation"); ERROR(ERR_tMRD, msg);
end
end
endtask
task deep_power_down_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " DPD : DEEP POWERDOWN"); NOTE(msg);
end
end
endtask
//-------------------------------- Deep Power Down Tasks -------------------------------
task burst_term_cmd_func;
time tm_bank_burst_term ;
begin
tm_bank_burst_term = 0 ;
for (i=0; i<`BANKS; i=i+1) begin
if (tm_bank_read[i] > tm_bank_burst_term) begin
tm_bank_burst_term = tm_bank_read[i] ;
burst_term_read_queue ;
end
if (tm_bank_write[i] > tm_bank_burst_term) begin
tm_bank_burst_term = tm_bank_write[i] ;
burst_term_write_queue ;
end
end
tm_burst_terminate = $time ;
ck_cntr_burst_terminate = 0 ;
end
endtask
task burst_term_err_chk;
begin
end
endtask
task burst_term_cmd_display;
begin
if (DEBUG == 1'b1) begin
$sformat (msg, " BT : BURST TERMINATE"); NOTE(msg);
end
end
endtask
//-------------------------------- Exit Power Down (cke high) Tasks -------------------------------
task cke_cmd_func;
begin
if (cke & ~cke_q) begin
tm_cke = $time ;
ck_cntr_cke = 0 ;
end
end
endtask
task cke_err_chk;
begin
if (cke & ~cke_q) begin
if (tm_cke_high - tm_self_refresh < tRAS) begin
$sformat (msg, " ERROR: tRAS violation during self refresh command exit"); ERROR(ERR_tRAS, msg);
end
end
end
endtask
//---------------------- Error count ----------------------
task ERROR;
input [7:0] errcode;
input [MSGLENGTH*8:1] msg;
begin
errcount[errcode] = errcount[errcode] + 1;
errors = errors + 1;
if ((errcount[errcode] <= ERR_MAX_REPORTED) || (ERR_MAX_REPORTED < 0))
if ((EXP_ERR[errcode] === 1) && ((errcount[errcode] <= ERR_MAX_INT) || (ERR_MAX_INT < 0))) begin
$display("Caught expected violation at time %t: %0s", $time, msg);
end else begin
$display("%m at time %t: %0s", $time, msg);
end
if (errcount[errcode] == ERR_MAX_REPORTED) begin
$sformat(msg, "Reporting for %s has been disabled because ERR_MAX_REPORTED has been reached.", err_strings[errcode]);
NOTE(msg);
end
//overall model maximum error limit
if ((errcount[errcode] > ERR_MAX_INT) && (ERR_MAX_INT >= 0)) begin
STOP;
end
end
endtask
//-------------------------------- Display Tasks -------------------------------
task NOTE;
input [MSGLENGTH*8:1] msg;
begin
$display("%m at time %t: %0s", $time, msg);
end
endtask
task WARN;
input [MSGLENGTH*8:1] msg;
begin
$display("%m at time %t: %0s", $time, msg);
warnings = warnings + 1;
end
endtask
//---------------------------------------------------
// TASK: Stop()
//---------------------------------------------------
task STOP;
begin
$display("%m at time %t: %d warnings, %d errors", $time, warnings, errors);
$stop(0);
end
endtask
//-------------------------------- Memory Storage Tasks -------------------------------
// Erase Memory
task erase_mem;
input integer pasr ;
reg [part_mem_bits : 0] i;
reg [part_mem_bits : 0] j;
reg [full_mem_bits : 0] k;
begin
`ifdef FULL_MEM
if (pasr == 0) begin
// for (k = 0; k > {(full_mem_bits){1'b1}}; k = k + 1) begin
// mem_array[k] = {DQ_BITS{1'bx}};
// end
end else if (pasr == 1) begin
for (k = {(full_mem_bits){1'b1}}; k > {(full_mem_bits-1){1'b1}}; k = k - 1) begin
mem_array[k] = {DQ_BITS{1'bx}};
end
end else if (pasr == 2) begin
for (k = {(full_mem_bits){1'b1}}; k > {(full_mem_bits-2){1'b1}}; k = k - 1) begin
mem_array[k] = {DQ_BITS{1'bx}};
end
end else if (pasr == 3) begin
for (k = {(full_mem_bits){1'b1}}; k > {(full_mem_bits-3){1'b1}}; k = k - 1) begin
mem_array[k] = {DQ_BITS{1'bx}};
end
end else if (pasr == 4) begin
for (k = {(full_mem_bits){1'b1}}; k > {(full_mem_bits-4){1'b1}}; k = k - 1) begin
mem_array[k] = {DQ_BITS{1'bx}};
end
end else begin
for (k = 0; k <= {(full_mem_bits){1'b1}}; k = k + 1) begin
mem_array[k] = {DQ_BITS{1'bx}};
end
$display ("%m: At time %t ERROR: illegal PASR setting.\n All Data will be lost.\n", $realtime);
end
`else
if (pasr == 0) begin
// for (i = 0; i < mem_used; i = i + 1) begin
// addr_array[i] = {full_mem_bits{1'bx}};
// mem_array[i] = {DQ_BITS{1'bx}};
// end
end else if (pasr == 1) begin
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i][full_mem_bits - 1] != 1'b0) begin
addr_array[i] = {full_mem_bits{1'bx}};
mem_array[i] = {DQ_BITS{1'bx}};
end
end
end else if (pasr == 2) begin
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i][full_mem_bits - 1: full_mem_bits - 2] != {2{1'b0}}) begin
addr_array[i] = {full_mem_bits{1'bx}};
mem_array[i] = {DQ_BITS{1'bx}};
end
end
end else if (pasr == 3) begin
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i][full_mem_bits - 1: full_mem_bits - 3] != {3{1'b0}}) begin
addr_array[i] = {full_mem_bits{1'bx}};
mem_array[i] = {DQ_BITS{1'bx}};
end
end
end else if (pasr == 4) begin
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i][full_mem_bits - 1: full_mem_bits - 4] != {4{1'b0}}) begin
addr_array[i] = {full_mem_bits{1'bx}};
mem_array[i] = {DQ_BITS{1'bx}};
end
end
end else begin
for (i = 0; i < mem_used; i = i + 1) begin
addr_array[i] = {full_mem_bits{1'bx}};
mem_array[i] = {DQ_BITS{1'bx}};
end
mem_used = 0 ;
$display ("%m: At time %t ERROR: illegal PASR setting.\n All Data will be lost.\n", $realtime);
end
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i] === {full_mem_bits{1'bx}}) begin
for (j=i; j < mem_used; j=j+1) begin
addr_array[j] = addr_array[j+1];
mem_array[j] = mem_array[j+1];
end
mem_used = mem_used - 1 ;
i = i - 1 ;
end
end
`endif
end
endtask
// Write Memory
task write_mem;
input [full_mem_bits - 1 : 0] address;
input [DQ_BITS - 1 : 0] data;
reg [part_mem_bits : 0] i;
begin
`ifdef FULL_MEM
mem_array[address] = data;
`else
begin : loop
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i] === address) begin
disable loop;
end
end
end
if (i === mem_used) begin
if (i === (1<<part_mem_bits)) begin
$display ("%m: At time %t ERROR: Memory overflow.\n Write to Address %d with Data %d will be lost.\n You must increase the part_mem_bits parameter or `define FULL_MEM.", $realtime, address, data);
end else begin
mem_used = mem_used + 1;
addr_array[i] = address;
end
end
mem_array[i] = data;
`endif
end
endtask
//test//
// Read Memory
task read_mem;
input [full_mem_bits - 1 : 0] address;
output [DQ_BITS - 1 : 0] data;
reg [part_mem_bits : 0] i;
begin
`ifdef FULL_MEM
data = mem_array[address];
`else
begin : loop
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i] === address) begin
disable loop;
end
end
end
if (i <= mem_used) begin
data = mem_array[i];
end else begin
data = 'bx;
end
`endif
end
endtask
//------------- Access Registers --------------
task clk_access_reg;
begin
for (i=0; i<`PAGE_SIZE+2; i=i+1) begin
bank_access_q[i] = bank_access_q[i+1] ;
row_access_q[i] = row_access_q[i+1] ;
column_access_q[i] = column_access_q[i+1] ;
column_access_valid_q[i] = column_access_valid_q[i+1] ;
end
bank_access_q[`PAGE_SIZE+2] = 'bz ;
row_access_q[`PAGE_SIZE+2] = 'bz ;
column_access_q[`PAGE_SIZE+2] = 'bz ;
column_access_valid_q[`PAGE_SIZE+2] = 2'b00 ;
end
endtask
//------------- clock counters --------------
task clk_counters;
begin
if ((ck_cntr_self_refresh + 1) > ck_cntr_self_refresh ) begin ck_cntr_self_refresh = ck_cntr_self_refresh + 1 ; end
if ((ck_cntr_power_down + 1) > ck_cntr_power_down ) begin ck_cntr_power_down = ck_cntr_power_down + 1 ; end
if ((ck_cntr_cke + 1) > ck_cntr_cke ) begin ck_cntr_cke = ck_cntr_cke + 1 ; end
if ((ck_cntr_cke_n + 1) > ck_cntr_cke_n ) begin ck_cntr_cke_n = ck_cntr_cke_n + 1 ; end
if ((ck_cntr_activate + 1) > ck_cntr_activate ) begin ck_cntr_activate = ck_cntr_activate + 1 ; end
if ((ck_cntr_read + 1) > ck_cntr_read ) begin ck_cntr_read = ck_cntr_read + 1 ; end
if ((ck_cntr_read_ap + 1) > ck_cntr_read_ap ) begin ck_cntr_read_ap = ck_cntr_read_ap + 1 ; end
if ((ck_cntr_write + 1) > ck_cntr_write ) begin ck_cntr_write = ck_cntr_write + 1 ; end
if ((ck_cntr_write_ap + 1) > ck_cntr_write_ap ) begin ck_cntr_write_ap = ck_cntr_write_ap + 1 ; end
if ((ck_cntr_burst_terminate + 1) > ck_cntr_burst_terminate) begin ck_cntr_burst_terminate = ck_cntr_burst_terminate + 1 ; end
if ((ck_cntr_precharge + 1) > ck_cntr_precharge ) begin ck_cntr_precharge = ck_cntr_precharge + 1 ; end
if ((ck_cntr_auto_refresh + 1) > ck_cntr_auto_refresh ) begin ck_cntr_auto_refresh = ck_cntr_auto_refresh + 1 ; end
if ((ck_cntr_load_mode + 1) > ck_cntr_load_mode ) begin ck_cntr_load_mode = ck_cntr_load_mode + 1 ; end
for (i=0; i<`BANKS; i=i+1) begin
if ((ck_cntr_bank_precharge[i] + 1) > ck_cntr_bank_precharge[i]) begin ck_cntr_bank_precharge[i] = ck_cntr_bank_precharge[i] + 1 ; end
if ((ck_cntr_bank_activate[i] + 1) > ck_cntr_bank_activate[i] ) begin ck_cntr_bank_activate[i] = ck_cntr_bank_activate[i] + 1 ; end
if ((ck_cntr_bank_write[i] + 1) > ck_cntr_bank_write[i] ) begin ck_cntr_bank_write[i] = ck_cntr_bank_write[i] + 1 ; end
if ((ck_cntr_bank_read[i] + 1) > ck_cntr_bank_read[i] ) begin ck_cntr_bank_read[i] = ck_cntr_bank_read[i] + 1 ; end
if ((ck_cntr_write_dq[i] + 1) > ck_cntr_write_dq[i] ) begin ck_cntr_write_dq[i] = ck_cntr_write_dq[i] + 1 ; end
end
end
endtask
//------------- Clock Enable --------------
always@(posedge cke) begin
tm_cke_high = $time ;
ck_cntr_cke_high = 0 ;
end
always@(clk) begin
if (clk) begin
clk_counters ;
exit_power_down_err_chk ;
initialization_cmd_func ;
initialization_err_chk ;
initialization_cmd_display ;
end
clk_stabilization_func ;
clk_stabilization_err_chk ;
cke_err_chk ;
cke_cmd_func ;
if (cke_q == 1'b1) begin
Sys_clk <= clk ;
end else begin
Sys_clk <= 1'b0 ;
end
if (clk) begin
cke_q = cke ;
end
end
//------------- System clock --------------
always@(posedge Sys_clk) begin
clk_access_reg;
active_read_write;
interrupt_auto_precharge(interrupt_bank);
auto_precharge_management;
if (command == ACTIVATE ) begin activate_err_chk ; end
if (command == READ ) begin read_err_chk ; end
if (command == READ_AP ) begin read_ap_err_chk ; end
if (command == READ_SUSPEND ) begin read_err_chk ; end
if (command == READ_AP_SUSPEND ) begin read_ap_err_chk ; end
if (command == WRITE ) begin write_err_chk ; end
if (command == WRITE_AP ) begin write_ap_err_chk ; end
if (command == WRITE_SUSPEND ) begin write_err_chk ; end
if (command == WRITE_AP_SUSPEND) begin write_ap_err_chk ; end
if (command == BURST_TERMINATE ) begin burst_term_err_chk ; end
if (command == AUTO_REFRESH ) begin auto_refresh_err_chk ; end
if (command == PRECHARGE ) begin precharge_err_chk(ba) ; end
if (command == PRECHARGE_ALL ) begin precharge_all_err_chk ; end
if (command == LOAD_MODE ) begin load_mode_err_chk ; end
if ((~read_write_in_progress ) &
(command != READ_SUSPEND ) &
(command != READ_AP_SUSPEND ) &
(command != WRITE_SUSPEND ) &
(command != WRITE_AP_SUSPEND ) ) begin
if (command == SELF_REFRESH ) begin self_refresh_err_chk ; end
if (command == POWER_DOWN_CI ) begin power_down_err_chk ; end
if (command == POWER_DOWN_NOP ) begin power_down_err_chk ; end
if (command == DEEP_POWER_DOWN ) begin deep_power_down_err_chk ; end
end else begin
if (command == SELF_REFRESH ) begin clock_suspend_err_chk ; end
if (command == POWER_DOWN_CI ) begin clock_suspend_err_chk ; end
if (command == POWER_DOWN_NOP ) begin clock_suspend_err_chk ; end
if (command == DEEP_POWER_DOWN ) begin clock_suspend_err_chk ; end
end
if (command_sequence_error == 0) begin
if (command == ACTIVATE ) begin activate_cmd_func(ba, addr) ; end
if (command == READ ) begin read_cmd_func ; end
if (command == READ_AP ) begin read_ap_cmd_func ; end
if (command == READ_SUSPEND ) begin read_cmd_func ; end
if (command == READ_AP_SUSPEND ) begin read_ap_cmd_func ; end
if (command == WRITE ) begin write_cmd_func ; end
if (command == WRITE_AP ) begin write_ap_cmd_func ; end
if (command == WRITE_SUSPEND ) begin write_cmd_func ; end
if (command == WRITE_AP_SUSPEND ) begin write_ap_cmd_func ; end
if (command == BURST_TERMINATE ) begin burst_term_cmd_func ; end
if (command == AUTO_REFRESH ) begin auto_refresh_cmd_func ; end
if (command == PRECHARGE ) begin precharge_cmd_func(ba, 0) ; end
if (command == PRECHARGE_ALL ) begin precharge_all_cmd_func ; end
if (command == LOAD_MODE ) begin load_mode_cmd_func ; end
if ((~read_write_in_progress ) &
(command != READ_SUSPEND ) &
(command != READ_AP_SUSPEND ) &
(command != WRITE_SUSPEND ) &
(command != WRITE_AP_SUSPEND ) ) begin
if (command == SELF_REFRESH ) begin self_refresh_cmd_func ; end
if (command == POWER_DOWN_CI ) begin power_down_cmd_func ; end
if (command == POWER_DOWN_NOP ) begin power_down_cmd_func ; end
if (command == DEEP_POWER_DOWN ) begin deep_power_down_cmd_func ; end
end else begin
if (command == SELF_REFRESH ) begin clock_suspend_cmd_func ; end
if (command == POWER_DOWN_CI ) begin clock_suspend_cmd_func ; end
if (command == POWER_DOWN_NOP ) begin clock_suspend_cmd_func ; end
if (command == DEEP_POWER_DOWN ) begin clock_suspend_cmd_func ; end
end
if ((command == ACTIVATE ) & (DEBUG == 1'b1)) begin activate_cmd_display ; end
if ((command == READ ) & (DEBUG == 1'b1)) begin read_cmd_display ; end
if ((command == READ_AP ) & (DEBUG == 1'b1)) begin read_ap_cmd_display ; end
if ((command == READ_SUSPEND ) & (DEBUG == 1'b1)) begin clock_suspend_cmd_display ; end
if ((command == READ_AP_SUSPEND ) & (DEBUG == 1'b1)) begin clock_suspend_cmd_display ; end
if ((command == WRITE ) & (DEBUG == 1'b1)) begin write_cmd_display ; end
if ((command == WRITE_AP ) & (DEBUG == 1'b1)) begin write_ap_cmd_display ; end
if ((command == WRITE_SUSPEND ) & (DEBUG == 1'b1)) begin clock_suspend_cmd_display ; end
if ((command == WRITE_AP_SUSPEND) & (DEBUG == 1'b1)) begin clock_suspend_cmd_display ; end
if ((command == BURST_TERMINATE ) & (DEBUG == 1'b1)) begin burst_term_cmd_display ; end
if ((command == AUTO_REFRESH ) & (DEBUG == 1'b1)) begin auto_refresh_cmd_display ; end
if ((command == PRECHARGE ) & (DEBUG == 1'b1)) begin precharge_cmd_display(ba) ; end
if ((command == PRECHARGE_ALL ) & (DEBUG == 1'b1)) begin precharge_all_cmd_display ; end
if ((command == LOAD_MODE ) & (DEBUG == 1'b1)) begin load_mode_cmd_display(ba, addr) ; end
if ((~read_write_in_progress ) &
(command != READ_SUSPEND ) &
(command != READ_AP_SUSPEND ) &
(command != WRITE_SUSPEND ) &
(command != WRITE_AP_SUSPEND ) ) begin
if ((command == SELF_REFRESH ) & (DEBUG == 1'b1)) begin self_refresh_cmd_display ; end
if ((command == POWER_DOWN_CI ) & (DEBUG == 1'b1)) begin power_down_cmd_display ; end
if ((command == POWER_DOWN_NOP ) & (DEBUG == 1'b1)) begin power_down_cmd_display ; end
if ((command == DEEP_POWER_DOWN) & (DEBUG == 1'b1)) begin deep_power_down_cmd_display ; end
end else begin
if ((command == SELF_REFRESH ) & (DEBUG == 1'b1)) begin clock_suspend_cmd_display ; end
if ((command == POWER_DOWN_CI ) & (DEBUG == 1'b1)) begin clock_suspend_cmd_display ; end
if ((command == POWER_DOWN_NOP ) & (DEBUG == 1'b1)) begin clock_suspend_cmd_display ; end
if ((command == DEEP_POWER_DOWN) & (DEBUG == 1'b1)) begin clock_suspend_cmd_display ; end
end
end
command_sequence_error = 0 ;
data_management(Dq_out);
dqm_q <= dqm ;
dqm_rtw_chk[1] <= dqm_rtw_chk[0];
dqm_rtw_chk[0] <= (column_access_valid_q[0] == 2'b10) & (&dqm_q === 1'b0) & (Dq_out !== {DQ_BITS{1'bz}}) ;
end
always@(Dq_out) begin
Dq_buffer_output ;
end
endmodule