/**************************************************************************
*
*    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 © 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


