1
0
mirror of git://projects.qi-hardware.com/xue.git synced 2024-12-29 12:29:53 +02:00
xue/sim/verilog/micron_mobile_ddr/mobile_ddr.v
2010-12-19 01:38:43 +00:00

2127 lines
90 KiB
Verilog

/****************************************************************************************
*
* File Name: mobile_ddr.v
* Version: 6.03
* Model: BUS Functional
*
* Dependencies: mobile_ddr_parameters.vh
*
* Description: Micron MOBILE DDR SDRAM
*
* Limitation: - Doesn't check for 8K-cycle refresh
*
* Note: - Set simulator resolution to "ps" accuracy
* - Set Debug = 0 to disable $display messages
* - Model assume Clk and Clk# crossing at both edge
*
* 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 2008 Micron Technology, Inc. All rights reserved.
*
* Rev Author Date Changes
* --- ------ ---------- ---------------------------------------
* 1.0 NMB 03/19/02 - Initial Release of Mobile DDR model
* based off of version 5.0 of DDR model
* 1.1 ritz 12/03/04 - New feature: 1/8th strength driver in Drive Strength (Ext Mode Reg).
* Bugfix - ba[0] ba[1] were swapped for determening ext_mode_enable
* thus ext_mode_reg wasnt being programmed.
* 1.2 ritz 12/07/04 - Logging transactions in transcript for automated testing
* 1.3 ritz 01/31/05 - updated to SMG DDR model version 5.2 (dqs edge checking errors fix)
* 1.4 ritz 02/15/05 - Fixed display.*WRITE to use hex for "data".
* 1.5 ritz 03/22/05 - Fixed read latency (#0.5 and 2*Read_latency-1) for MMG latency
* 2.0 bas 07/19/06 - Added PASR support and clk_n checking
* 3.0 bas 08/07/06 - Added tXP check, tCke check, Power-down/Deep power down enter/exit messages
FULL_MEM fix
* 3.11 bas 10/18/06 - Added clk spd chk, added RP support, added T48M part, added SRR functionality, changed tMRD checker to measure in tck pos edge, DPD optimization for FULL_MEM mode
* 3.12 bas 10/19/06 - Fixed PASR in FULL_MEM mode
* 3.20 bas 10/23/06 - changed tXP check to tPDX check for T25L, Initial release to web
* 3.30 bas 01/15/07 - Updated T48M Parameters (updated as of 12/06)
* 3.35 bas 02/28/07 - Model uses tAC correctly to calculate strobe/data launch
* 3.36 bas 03/05/07 - fixed error messages for different banks interrupting
reads/writes w/autoprecharge
* 3.37 bas 03/21/07 - Added T47M Part to 512Mb parameter file
* 3.40 bas 06/25/07 - Removed RP options from 1024Mb
- Updated 128Mb, 256Mb, and 512Mb parts to 05/07 datasheet
- Updated 1024Mb part to 02/07
- Added illegal Cas Latency check per speed grade
* 3.40 jwm 08/02/07 - Support for 512Mb T47M
* 3.80 clk 10/29/07 - Support for 1024Mb T48M
* 4.00 clk 12/30/07 - Fixed Read terminated by precharge testcase
* 4.70 clk 03/30/08 - Fixed typo in SRR code
* 4.80 clk 04/03/08 - Disable clk checking during initialization
* 4.90 clk 04/16/08 - Fixed tInit, added mpc support, updated t35m timing
* 5.00 clk 05/14/08 - Fixed back to back auto precharge commands
* 5.20 clk 05/21/08 - Fixed read interrupt by pre (BL8), fixed 1024Mb parameter file
* 5.30 clk 05/22/08 - Fixed DM signal which cause false tWTR errors
05/27/08 - Rewrote write and read pipelines, strobes
* 5.40 clk 05/28/08 - Fixed Addressing problem in Burst Order logic
* 5.50 clk 07/25/08 - Added T36N part type
* 5.60 clk 09/05/08 - Fixed tXP in 256Mb part type
* 5.70 clk 09/17/08 - Fixed burst term check for write w/ all DM active
* 5.80 clk 11/18/08 - Fixed internally latched dq & mask widths
* 5.90 clk 12/10/08 - Updated T36N parameters to latest datasheet
* 6.00 clk 03/05/09 - Fixed DQS problem w/ CL = 2, Fix Wr Pipeline during Rd interrupt
* 6.01 sph 01/20/10 - Added clock stop detection to fix tCH/tCL timing violation
* 6.02 sph 01/22/10 - Added check for nop/des is used when enter/exit stop clock mode
* 6.03 sph 06/07/10 - Include all the mobile_ddr_parameters.vh into a single package
****************************************************************************************/
// DO NOT CHANGE THE TIMESCALE
// MAKE SURE YOUR SIMULATOR USES "PS" RESOLUTION
`timescale 1ns / 1ps
module mobile_ddr (Dq, Dqs, Addr, Ba, Clk, Clk_n, Cke, Cs_n, Ras_n, Cas_n, We_n, Dm);
`ifdef den128Mb
`include "128Mb_mobile_ddr_parameters.vh"
`elsif den256Mb
`include "256Mb_mobile_ddr_parameters.vh"
`elsif den512Mb
`include "512Mb_mobile_ddr_parameters.vh"
`elsif den1024Mb
`include "1024Mb_mobile_ddr_parameters.vh"
`elsif den2048Mb
`include "2048Mb_mobile_ddr_parameters.vh"
`else
// NOTE: Intentionally cause a compile fail here to force the users
// to select the correct component density before continuing
ERROR: You must specify component density with +define+den____Mb.
`endif
`define MAX_PIPE 2*(CL_MAX + BL_MAX)
// Port Declarations
input Clk;
input Clk_n;
input Cke;
input Cs_n;
input Ras_n;
input Cas_n;
input We_n;
input [ADDR_BITS - 1 : 0] Addr;
input [1 : 0] Ba;
inout [DQ_BITS - 1 : 0] Dq;
inout [DQS_BITS - 1 : 0] Dqs;
input [DM_BITS - 1 : 0] Dm;
//time variables
realtime tXP_chk ;
reg enter_DPD ;
reg enter_PD ;
reg enter_APD ;
//integer clk checks
// Internal Wires (fixed width)
wire [31 : 0] Dq_in;
wire [3 : 0] Dqs_in;
wire [3 : 0] Dm_in;
assign Dq_in [DQ_BITS - 1 : 0] = Dq;
assign Dqs_in [DQS_BITS - 1 : 0] = Dqs;
assign Dm_in [DM_BITS - 1 : 0] = Dm;
// Data pair
reg [DQ_BITS-1 : 0] dq_rise;
reg [DM_BITS-1 : 0] dm_rise;
reg [DQ_BITS-1 : 0] dq_fall;
reg [DM_BITS-1 : 0] dm_fall;
reg [DM_BITS*2-1 : 0] dm_pair;
reg [DQ_BITS-1 : 0] Dq_buf;
// Power-down cycle counter
reg [03:00] PD_cntr ;
// prev cmd value
reg prev_Cs_n ;
reg prev_Ras_n ;
reg prev_Cas_n ;
reg prev_We_n ;
reg [01:00] prev_Ba ;
reg prev_cke ;
wire prev_nop = ~prev_Cs_n & prev_Ras_n & prev_Cas_n & prev_We_n ;
wire prev_des = prev_Cs_n ;
wire prev_bt = ~prev_Cs_n & prev_Ras_n & prev_Cas_n & ~prev_We_n ;
wire prev_rd = ~prev_Cs_n & prev_Ras_n & ~prev_Cas_n & prev_We_n ;
reg Clk_Chk_enable = 1'b0 ;
//differential clk
reg diff_ck;
always @(posedge Clk) diff_ck <= Clk;
always @(posedge Clk_n) diff_ck <= ~Clk_n;
//measure clock period
realtime clk_period ;
realtime pos_clk_edge ;
integer clk_pos_edge_cnt ;
always @(posedge diff_ck) begin
clk_period = $realtime - pos_clk_edge ;
pos_clk_edge = $realtime ;
if ((Cke == 1'b1) && (clk_pos_edge_cnt < 2)) begin
clk_pos_edge_cnt = clk_pos_edge_cnt + 1 ;
end else if (Cke == 1'b0) begin
clk_pos_edge_cnt = 2'b00 ;
end
end
//measure duty cycle
realtime neg_clk_edge ;
always @(negedge diff_ck) begin
neg_clk_edge = $realtime ;
end
realtime pos_clk_time ;
realtime neg_clk_time ;
reg clock_stop = 0;
// Mode Register
reg [ADDR_BITS - 1 : 0] Mode_reg;
reg [ADDR_BITS - 1 : 0] Ext_Mode_reg;
reg [2*DQ_BITS - 1 : 0] Srr_reg;
// SRR Registers
reg SRR_read;
// Internal System Clock
reg CkeZ, Sys_clk;
// Internal Dqs initialize
// reg Dqs_int;
// Dqs buffer
reg Dqs_out;
// reg [DQS_BITS - 1 : 0] Dqs_gen;
reg Dqs_out_en;
// Dq buffer
reg [DQ_BITS - 1 : 0] Dq_out_temp;
reg [DQ_BITS - 1 : 0] Dq_out;
reg Dq_out_en;
// Read pipeline variables
reg [`MAX_PIPE : 0] Read_pipeline ;
reg [1 : 0] Read_bank [0 : 6];
reg [COL_BITS - 1 : 0] Read_cols [0 : 6];
// Write pipeline variables
reg [`MAX_PIPE :-2] Write_pipeline;
reg [BA_BITS-1 : 0] Write_bank_pipeline [`MAX_PIPE :-2];
reg [COL_BITS - 1 : 0] Write_col_pipeline [`MAX_PIPE :-2];
// Auto precharge variables
reg [3:0] Read_precharge_access ;
reg [3:0] Read_precharge_pre ;
reg [3:0] Write_precharge_access ;
reg [3:0] Write_precharge_pre ;
integer Count_precharge [0:3];
reg SelfRefresh;
reg [3:0] Read_precharge_count [3:0] ;
reg [3:0] Write_precharge_count [3:0];
reg wr_ap_display_msg ;
reg rd_ap_display_msg ;
// Manual precharge variables
// reg [0 : 6] A10_precharge ;
// reg [1 : 0] Bank_precharge [0 : 6];
// reg [0 : 6] Cmnd_precharge ;
// Burst terminate variables
// reg Cmnd_bst [0 : 6];
// tMRD counter
integer MRD_cntr ;
integer SRR_cntr ;
integer SRC_cntr ;
integer tWTR_cntr ;
// 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
// Dqs edge checking
integer i;
reg [3:0] expect_pos_dqs;
reg [3:0] expect_neg_dqs;
// Burst counter
reg [COL_BITS - 1 : 0] Burst_counter;
// Burst counter delay
reg [COL_BITS - 1 : 0] Burst_counter_dly;
always @(Mode_reg or Burst_counter) begin
if (Mode_reg[6:4] == 3'b010) begin
// Burst_counter_dly <= #tAC2_max Burst_counter;
end else if (Mode_reg[6:4] == 3'b011) begin
// Burst_counter_dly <= #tAC3_max Burst_counter;
end
end
// Precharge variables
reg Pc_b0, Pc_b1, Pc_b2, Pc_b3;
// Activate variables
reg Act_b0, Act_b1, Act_b2, Act_b3;
// Data IO variables
// reg Data_in_enable;
wire Data_in_enable = Write_pipeline[-2];
// reg Data_out_enable;
wire Data_out_enable = Read_pipeline[0];
wire tWTR_en = ((|Write_pipeline[`MAX_PIPE : 0]) & ~(&Dm));
// Data Out Enable delay
// reg Data_out_enable_dly;
// always @(Mode_reg or Data_out_enable) begin
// if (Mode_reg[6:4] == 3'b010) begin
// Data_out_enable_dly <= #tAC2_max Data_out_enable;
// end else if (Mode_reg[6:4] == 3'b011) begin
// Data_out_enable_dly <= #tAC3_max Data_out_enable;
// end
// end
// Internal address mux variables
reg [1 : 0] Prev_bank;
reg [1 : 0] Bank_addr;
reg [COL_BITS - 1 : 0] Cols_addr, Cols_brst, Cols_temp;
reg [ADDR_BITS - 1 : 0] Rows_addr;
reg [ADDR_BITS - 1 : 0] B0_row_addr;
reg [ADDR_BITS - 1 : 0] B1_row_addr;
reg [ADDR_BITS - 1 : 0] B2_row_addr;
reg [ADDR_BITS - 1 : 0] B3_row_addr;
integer aref_count;
reg ext_mode_load_done;
reg mode_load_done;
reg power_up_done;
// Write DQS for tDSS , tDSH, tDQSH, tDQSL checks
wire wdqs_valid = Write_pipeline[`MAX_PIPE:0];
// Commands Decode
wire Active_enable = ~Cs_n & ~Ras_n & Cas_n & We_n;
wire Aref_enable = ~Cs_n & ~Ras_n & ~Cas_n & We_n & Cke;
wire Sref_enable = ~Cs_n & ~Ras_n & ~Cas_n & We_n & ~Cke;
wire Burst_term = ~Cs_n & Ras_n & Cas_n & ~We_n;
wire Ext_mode_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n & Ba[1] & ~Ba[0];
wire Mode_reg_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n & ~Ba[1] & ~Ba[0];
wire Prech_enable = ~Cs_n & ~Ras_n & Cas_n & ~We_n;
wire Read_enable = ~Cs_n & Ras_n & ~Cas_n & We_n;
wire Write_enable = ~Cs_n & Ras_n & ~Cas_n & ~We_n;
wire DPD_enable = ~Cs_n & Ras_n & Cas_n & ~We_n & ~Cke;
wire PD_enable = ((~Cs_n & Ras_n & Cas_n & We_n) | Cs_n) & ~Cke;
wire nop_enable = ~Cs_n & Ras_n & Cas_n & We_n ;
wire des_enable = Cs_n ;
wire srr_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n & ~Ba[1] & Ba[0] & ((part_size==128)|(part_size==512)|(part_size==1024)) ;
reg Cke_Chk = 0 ;
parameter tInit = 200000 ;
reg Cke_Print = 1'b0 ;
real Init_Cmd_Chk ;
// Burst Length Decode
// reg [4:0] burst_length = 1 << (Mode_reg[2:0]);
reg [4:0] burst_length ;
reg read_precharge_truncation;
// CAS Latency Decode
wire [2:0] cas_latency = Mode_reg[6:4] ;
wire [2:0] cas_latency_x2 = ((2*Mode_reg[6:4])-1);
real tAC_max ;
always @ (Mode_reg)
begin
if (Mode_reg[6:4] == 3'b011)
tAC_max = tAC3_max ;
else if (Mode_reg[6:4] == 3'b010)
tAC_max = tAC2_max ;
end
// DQS Buffer
reg [DQS_BITS - 1 : 0] dqs_delayed ;
// always@* begin
// dqs_delayed <= Dqs_out ;
// end
assign Dqs = (Dqs_out_en) ? {DQS_BITS{Dqs_out}} : 'bz;
assign Dq = (Dq_out_en ) ? Dq_out : 'bz;
// Debug message
wire Debug = 1'b0;
// Timing Check
// realtime MRD_chk;
realtime RFC_chk;
realtime RRD_chk;
realtime RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3;
realtime RAP_chk0, RAP_chk1, RAP_chk2, RAP_chk3;
realtime RC_chk0, RC_chk1, RC_chk2, RC_chk3;
realtime RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3;
realtime RP_chk0, RP_chk1, RP_chk2, RP_chk3;
realtime WR_chk0, WR_chk1, WR_chk2, WR_chk3;
realtime SRR_chk;
//
reg [2:0] current_init_state ;
parameter [2:0] begin_init = 3'b000 ;
parameter [2:0] cke_init = 3'b001 ;
parameter [2:0] prech_init = 3'b010 ;
parameter [2:0] begin_mode_init = 3'b011 ;
parameter [2:0] mode_init = 3'b100 ;
parameter [2:0] ext_mode_init = 3'b101 ;
parameter [2:0] mode_done_init = 3'b110 ;
initial begin
CkeZ = 1'b0;
Sys_clk = 1'b0;
{Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 4'b0000;
{Act_b0, Act_b1, Act_b2, Act_b3} = 4'b1111;
// Dqs_int = 1'b0;
Dqs_out_en = {DQS_BITS{1'b0}};
Dqs_out = {DQS_BITS{1'bz}};
// Dqs_gen = {DQS_BITS{1'bz}};
Dq_out = {DQ_BITS{1'bz}};
Dq_out_en = {DQ_BITS{1'b0}};
// dq_delayed = {DQ_BITS{1'bz}};
// Data_in_enable = 1'b0;
// Data_out_enable = 1'b0;
aref_count = 0;
SelfRefresh = 1'b0;
power_up_done = 0;
ext_mode_load_done = 0;
mode_load_done = 0;
// MRD_chk = 0;
RFC_chk = 0;
RRD_chk = 0;
RAS_chk0 = 0;
RAS_chk1 = 0;
RAS_chk2 = 0;
RAS_chk3 = 0;
RAP_chk0 = 0;
RAP_chk1 = 0;
RAP_chk2 = 0;
RAP_chk3 = 0;
RC_chk0 = 0;
RC_chk1 = 0;
RC_chk2 = 0;
RC_chk3 = 0;
RCD_chk0 = 0;
RCD_chk1 = 0;
RCD_chk2 = 0;
RCD_chk3 = 0;
RP_chk0 = 0;
RP_chk1 = 0;
RP_chk2 = 0;
RP_chk3 = 0;
WR_chk0 = 0;
WR_chk1 = 0;
WR_chk2 = 0;
WR_chk3 = 0;
SRR_chk = 0;
$timeformat (-9, 3, " ns", 12);
pos_clk_time = 0;
neg_clk_time = 0;
enter_DPD = 0;
enter_PD = 0;
enter_APD = 0;
current_init_state = begin_init ;
SRR_read = 1'b0;
MRD_cntr = 8;
SRR_cntr = 8;
SRC_cntr = 8;
tWTR_cntr = 8;
Read_precharge_access[0] = 1'b0 ;
Read_precharge_access[1] = 1'b0 ;
Read_precharge_access[2] = 1'b0 ;
Read_precharge_access[3] = 1'b0 ;
Read_precharge_pre[0] = 1'b0 ;
Read_precharge_pre[1] = 1'b0 ;
Read_precharge_pre[2] = 1'b0 ;
Read_precharge_pre[3] = 1'b0 ;
Write_precharge_access[0] = 1'b0 ;
Write_precharge_access[1] = 1'b0 ;
Write_precharge_access[2] = 1'b0 ;
Write_precharge_access[3] = 1'b0 ;
Write_precharge_pre[0] = 1'b0 ;
Write_precharge_pre[1] = 1'b0 ;
Write_precharge_pre[2] = 1'b0 ;
Write_precharge_pre[3] = 1'b0 ;
wr_ap_display_msg = 1'b0 ;
rd_ap_display_msg = 1'b0 ;
Read_precharge_count[0] = 4'hf;
Read_precharge_count[1] = 4'hf;
Read_precharge_count[2] = 4'hf;
Read_precharge_count[3] = 4'hf;
Write_precharge_count[0] = 4'hf;
Write_precharge_count[1] = 4'hf;
Write_precharge_count[2] = 4'hf;
Write_precharge_count[3] = 4'hf;
end
// make sure 200 us has passed since cke for first command
always @ (Clk_Chk_enable or nop_enable or des_enable)
begin
if (~Clk_Chk_enable) begin
if (~nop_enable & ~des_enable) begin
Clk_Chk_enable = 1'b1 ;
if (~Cke_Chk) begin
if (($realtime - Init_Cmd_Chk < tInit - 0.001) & ~Cke_Print) begin
$display("Warning: You must wait 200 us from CKE assertion before you perform a command. Current wait time: %3.0f ns", $realtime - (Init_Cmd_Chk));
Cke_Print = 1'b1 ;
end
end
end
end
end
// Check for tCH, tCK, and clock stop mode
always @(diff_ck) begin
if (diff_ck) begin
neg_clk_time = $realtime - neg_clk_edge ;
end
if (~diff_ck) begin
pos_clk_time = $realtime - pos_clk_edge ;
end
if (Cke & Clk_Chk_enable) begin
// clock stop mode when either pulse width is 2x bigger than the other (reasonable assumption???)
clock_stop = ((pos_clk_time / neg_clk_time > 2) | (neg_clk_time / pos_clk_time > 2));
// Check if NOP/DES when enter/exit clock stop mode
if ((clock_stop && diff_ck) && (~(prev_nop || prev_des) || ~(nop_enable || des_enable))) begin
$display ("%m: at time %t ERROR: Nop or Deselect is required when enter or exit Stop Clock Mode", $time);
end
if ((pos_clk_time / clk_period < tCH_MIN) && ~clock_stop) begin
$display ("%m: at time %t ERROR: tCH minimum violation on CLK by %t", $time, tCH_MIN*clk_period - pos_clk_time);
end
if ((pos_clk_time / clk_period > tCH_MAX) && ~clock_stop) begin
$display ("%m: at time %t ERROR: tCH maximum violation on CLK by %t", $time, pos_clk_time - tCH_MAX*clk_period);
end
if ((neg_clk_time / clk_period < tCL_MIN) && ~clock_stop) begin
$display ("%m: at time %t ERROR: tCL minimum violation on CLK by %t", $time, tCL_MIN*clk_period - pos_clk_time);
end
if ((neg_clk_time / clk_period > tCL_MAX) && ~clock_stop) begin
$display ("%m: at time %t ERROR: tCL maximum violation on CLK by %t", $time, pos_clk_time - tCL_MAX*clk_period);
end
end
end
//clock Frequency Check
always @(posedge diff_ck) begin
if (clk_pos_edge_cnt > 1) begin
if (Mode_reg[6:4] == 3'b011) begin
if (clk_period < (tCK3_min-0.001)) begin
$display ("%m : at time %t ERROR : Illegal clk period for CAS Latency 3", $realtime);
$display ("%m : at time %t CLK PERIOD = %t", $realtime, clk_period);
end
end
if (Mode_reg[6:4] == 3'b010) begin
if (clk_period < (tCK2_min-0.001)) begin
$display ("%m : at time %t ERROR : Illegal clk period for CAS Latency 2", $realtime);
$display ("%m : at time %t CLK PERIOD = %t", $realtime, clk_period);
end
end
end
end
//SRR reg settings
always @(posedge power_up_done) begin
Srr_reg = 'b0 ;
Srr_reg[3:0] = 4'b1111 ; //Manufacturer(Micron)
Srr_reg[7:4] = 4'b0000 ; //Revision ID(Default to 0 in model)
Srr_reg[10:8] = 3'b100 ; //Refresh Rate(based on temp sensor - will default to 1x in model)
Srr_reg[11] = (DQ_BITS == 32)? 1'b1 : 1'b0 ; //Part width(x32 or x16)
Srr_reg[12] = 1'b0 ; //Device Type (LP DDR)
Srr_reg[15:13] = (part_size == 1024)? 3'b011 :
(part_size == 512 )? 3'b010 :
(part_size == 256 )? 3'b001 :
3'b000 ; //Density(1024Mb, 512Mb, 256Mb, 128Mb)
end
// System Clock
always begin
@ (posedge diff_ck) begin
Sys_clk = CkeZ;
CkeZ = Cke;
end
@ (negedge diff_ck) begin
Sys_clk = 1'b0;
end
end
task store_prev_cmd;
begin
prev_Cs_n <= Cs_n ;
prev_Ras_n <= Ras_n ;
prev_Cas_n <= Cas_n ;
prev_We_n <= We_n ;
prev_Ba[1] <= Ba[1] ;
prev_Ba[0] <= Ba[0] ;
prev_cke <= Cke ;
end
endtask
task MRD_counter;
begin
if (Cke) begin
if (MRD_cntr < tMRD) begin
MRD_cntr = MRD_cntr + 1'b1;
end
end
end
endtask
task SRR_counter;
begin
if (Cke) begin
if (SRR_cntr < tSRR) begin
SRR_cntr = SRR_cntr + 1'b1;
end
end
end
endtask
task SRC_counter;
begin
if (Cke) begin
if (SRC_cntr < ((Mode_reg[6:4])+1)) begin
SRC_cntr = SRC_cntr + 1'b1;
end
end
end
endtask
task tWTR_counter;
begin
if (Cke) begin
if (tWTR_en) begin
tWTR_cntr = 0 ;
end else begin
tWTR_cntr = tWTR_cntr + 1'b1;
end
end
end
endtask
task command_counter;
begin
if (Cke) begin
for (i=0; i<4;i=i+1) begin
if (Read_precharge_count[i] < 4'hf) begin
Read_precharge_count[i] = Read_precharge_count[i] + 1'b1;
end
end
for (i=0; i<4;i=i+1) begin
if (Write_precharge_count[i] < 4'hf) begin
Write_precharge_count[i] = Write_precharge_count[i] + 1'b1;
end
end
end
end
endtask
task PD_counter;
begin
if (~Cke) begin
if (PD_cntr < tCKE) begin
PD_cntr = PD_cntr + (enter_DPD | enter_PD | DPD_enable | PD_enable);
end
end else begin
PD_cntr = 4'h0 ;
end
end
endtask
task tXP_check;
begin
if (Cke == 1'b1 && prev_cke == 1'b0) begin
tXP_chk = $realtime ;
end
if (Cke) begin
if (~nop_enable && ~des_enable) begin
if ($realtime-tXP_chk < tXP - 0.001) begin
`ifdef T25L
$display ("%m: At time %t ERROR: tPDX violation", $realtime);
`else
$display ("%m: At time %t ERROR: tXP violation", $realtime);
`endif
end
end
end
end
endtask
// DPD pos edge clk cntr
always begin
@ (posedge diff_ck) begin
tXP_check ;
Power_down_chk ;
PD_counter ;
store_prev_cmd ;
end
end
// Check to make sure that we have a Deselect or NOP command on the bus when CKE is brought high
always @(Cke) begin
if (Cke === 1'b1) begin
Init_Cmd_Chk = $realtime ;
if (SelfRefresh === 1'b1) begin
SelfRefresh = 1'b0;
end
if (!((Cs_n) || (~Cs_n & Ras_n & Cas_n & We_n))) begin
$display ("%m: At time %t MEMORY ERROR: You must have a Deselect or NOP command applied", $realtime);
$display ("%m: when the Clock Enable is brought High.");
end
end
end
//BL Mode Reg settings
always@(Mode_reg[2:0] or mode_load_done) begin
if (mode_load_done) begin
case (Mode_reg[2:0])
3'b001 : burst_length = 5'b00010;
3'b010 : burst_length = 5'b00100;
3'b011 : burst_length = 5'b01000;
3'b100 : burst_length = 5'b10000;
default : burst_length = 5'bxxxxx;
endcase
end
end
// Init sequence
always @(current_init_state or Cke or Prech_enable or ext_mode_load_done or mode_load_done or aref_count) begin
if (current_init_state == begin_init) begin
if (Cke) begin
current_init_state = cke_init ;
power_up_done = 1'b0 ;
end
end
if (current_init_state == cke_init) begin
if (Prech_enable) begin
current_init_state = prech_init ;
aref_count = 0 ;
end
end
if (current_init_state == prech_init) begin
if (~Prech_enable) begin
current_init_state = begin_mode_init ;
end
end
if (current_init_state == begin_mode_init) begin
if (ext_mode_load_done) begin
current_init_state = ext_mode_init ;
end
if (mode_load_done) begin
current_init_state = mode_init ;
end
end
if (current_init_state == mode_init) begin
if (ext_mode_load_done) begin
current_init_state = mode_done_init ;
end
end
if (current_init_state == ext_mode_init) begin
if (mode_load_done) begin
current_init_state = mode_done_init ;
end
end
if (current_init_state == mode_done_init && aref_count >= 2) begin
power_up_done = 1'b1;
end
end
// this task will erase the contents of 0 or more banks
task erase_mem;
input [BA_BITS+1:0] bank_MSB_row; //bank bits + 2 row MSB
input DPD_mode ; //erase all memory locations
integer i;
begin
if (DPD_mode) begin
`ifdef FULL_MEM
for (i=0; i<{(BA_BITS+ROW_BITS+COL_BITS){1'b1}}; i=i+1) begin
mem_array[i] = 'bx;
end
`else
memory_index = 0;
i = 0;
// remove the selected banks
for (memory_index=0; memory_index<mem_used; memory_index=memory_index+1) begin
addr_array[i] = 'bx;
mem_array[i] = 'bx;
i = i + 1;
end
`endif
end else begin
`ifdef FULL_MEM
for (i={bank_MSB_row, {(ROW_BITS+COL_BITS-2){1'b1}}}; i<={1'b0, {(BA_BITS+ROW_BITS+COL_BITS){1'b1}}}; i=i+1) begin
mem_array[i] = 'bx;
end
`else
memory_index = 0;
i = 0;
// remove the selected banks
for (memory_index=0; memory_index<mem_used; memory_index=memory_index+1) begin
if (addr_array[memory_index]>({bank_MSB_row, {(ROW_BITS+COL_BITS-2){1'b1}}})) begin
addr_array[i] = 'bx;
mem_array[i] = 'bx;
i = i + 1;
end else begin
i = i + 1;
end
end
`endif
end
end
endtask
// Write Memory
task write_mem;
input [full_mem_bits - 1 : 0] addr;
input [DQ_BITS - 1 : 0] data;
reg [part_mem_bits : 0] i;
begin
`ifdef FULL_MEM
mem_array[addr] = data;
`else
begin : loop
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i] === addr) 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, addr, data);
end else begin
mem_used = mem_used + 1;
addr_array[i] = addr;
end
end
mem_array[i] = data;
`endif
end
endtask
// Read Memory
task read_mem;
input [full_mem_bits - 1 : 0] addr;
output [DQ_BITS - 1 : 0] data;
reg [part_mem_bits : 0] i;
begin
`ifdef FULL_MEM
data = mem_array[addr];
`else
begin : loop
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i] === addr) begin
disable loop;
end
end
end
if (i <= mem_used) begin
data = mem_array[i];
end else begin
data = 'bx;
end
`endif
end
endtask
// Burst Decode
task Burst_Decode;
begin
// Advance Burst Counter
// if (Burst_counter < burst_length) begin
if (Write_pipeline[-2]) begin
Burst_counter = Burst_counter + 1;
end
// Burst Type
if (Mode_reg[3] === 1'b0) begin // Sequential Burst
Cols_temp = Cols_addr + 1;
end else if (Mode_reg[3] === 1'b1) begin // Interleaved Burst
Cols_temp[2] = Burst_counter[2] ^ Cols_brst[2];
Cols_temp[1] = Burst_counter[1] ^ Cols_brst[1];
Cols_temp[0] = Burst_counter[0] ^ Cols_brst[0];
end
// Burst Length
if (burst_length === 2) begin
Cols_addr [0] = Cols_temp [0];
end else if (burst_length === 4) begin
Cols_addr [1 : 0] = Cols_temp [1 : 0];
end else if (burst_length === 8) begin
Cols_addr [2 : 0] = Cols_temp [2 : 0];
end else if (burst_length === 16) begin
Cols_addr [3 : 0] = Cols_temp [3 : 0];
end else begin
Cols_addr = Cols_temp;
end
// Data Counter
// if (Burst_counter >= burst_length) begin
// Data_in_enable = 1'b0;
// Data_out_enable = 1'b0;
// read_precharge_truncation = 1'b0;
// SRR_read = 1'b0;
// end
end
endtask
// SRC check
task Timing_chk_SRC;
begin
if (Active_enable || Aref_enable || Sref_enable || Burst_term ||
Ext_mode_enable || Mode_reg_enable || Prech_enable || Read_enable ||
Write_enable || DPD_enable || PD_enable || srr_enable) begin
if (part_size == 1024) begin
if (SRC_cntr < ((Mode_reg[6:4])+tSRC)) begin
$display ("%m: At time %t ERROR: tSRC Violation", $realtime);
end
end
end
end
endtask
task ShiftPipelines;
begin
// read command pipeline
Read_pipeline = Read_pipeline >> 1;
Write_pipeline = Write_pipeline >> 1;
for (i = -2; i < `MAX_PIPE-1; i = i + 1)
begin
Write_col_pipeline [i] = Write_col_pipeline[i+1];
Write_bank_pipeline [i] = Write_bank_pipeline[i+1];
end
end
endtask
// Dq and Dqs Drivers
task Dq_Dqs_Drivers;
begin
// Initialize Read command
if (Read_pipeline [0] === 1'b1) begin
// Data_out_enable = 1'b1;
Bank_addr = Write_bank_pipeline[0];
Cols_addr = Write_col_pipeline [0];
Cols_brst = Cols_addr [2 : 0];
// if (SRR_read == 1'b1) begin
// Burst_counter = burst_length - 2;
// end else begin
// Burst_counter = 0;
// end
// Row Address Mux
case (Bank_addr)
2'd0 : Rows_addr = B0_row_addr;
2'd1 : Rows_addr = B1_row_addr;
2'd2 : Rows_addr = B2_row_addr;
2'd3 : Rows_addr = B3_row_addr;
default : $display ("%m: At time %t ERROR: Invalid Bank Address", $realtime);
endcase
end
// Read latch
if (Read_pipeline[0] === 1'b1) begin
// output data
if (SRR_read == 1'b1) begin
if (Cols_addr == 0) begin
Dq_out_temp = Srr_reg[DQ_BITS-1:0];
end else begin
Dq_out_temp = Srr_reg[2*DQ_BITS-1:DQ_BITS];
SRR_read = 1'b0 ;
end
end else begin
read_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_out_temp);
end
if (Debug) begin
$display ("At time %t %m:READ: Bank = %d, Row = %d, Col = %d, Data = %d", $realtime, Bank_addr, Rows_addr, Cols_addr, Dq_out);
end
end
Dq_out <= #(tAC_max) Dq_out_temp ;
Dqs_out <= #(tAC_max) ((|Read_pipeline[0]) & Sys_clk) ;
if (cas_latency == 3)
Dqs_out_en <= #(tAC_max) (|Read_pipeline[2:0]);
else
Dqs_out_en <= #(tAC_max) (|Read_pipeline[1:0]);
if (Sys_clk) begin
Dq_out_en <= #(tAC_max) (Read_pipeline[0]);
end
end
endtask
// Write FIFO and DM Mask Logic
task Write_FIFO_DM_Mask_Logic;
begin
// Initialize Write command
if (Write_pipeline [-2] === 1'b1) begin
// Data_in_enable = 1'b1;
Bank_addr = Write_bank_pipeline [-2];
Cols_addr = Write_col_pipeline [-2];
Cols_brst = Cols_addr [2 : 0];
// Burst_counter = 0;
// Row address mux
case (Bank_addr)
2'd0 : Rows_addr = B0_row_addr;
2'd1 : Rows_addr = B1_row_addr;
2'd2 : Rows_addr = B2_row_addr;
2'd3 : Rows_addr = B3_row_addr;
default : $display ("%m: At time %t ERROR: Invalid Row Address", $realtime);
endcase
end
// Write data
// if (Data_in_enable === 1'b1) begin
if (Write_pipeline[-2] === 1'b1) begin
// Data Buffer
read_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_buf);
// write negedge Dqs on posedge Sys_clk
if (Sys_clk) begin
if (!dm_fall[0]) begin
Dq_buf [ 7 : 0] = dq_fall [ 7 : 0];
end
if (!dm_fall[1]) begin
Dq_buf [15 : 8] = dq_fall [15 : 8];
end
`ifdef x32
if (!dm_fall[2]) begin
Dq_buf [23 : 16] = dq_fall [23 : 16];
end
if (!dm_fall[3]) begin
Dq_buf [31 : 24] = dq_fall [31 : 24];
end
`endif
if (~&dm_fall) begin
if (Debug) begin
$display ("At time %t %m:WRITE: Bank = %d, Row = %d, Col = %d, Data = %h", $realtime, Bank_addr, Rows_addr, Cols_addr, Dq_buf[DQ_BITS-1:0]);
end
end
// write posedge Dqs on negedge Sys_clk
end else begin
if (!dm_rise[0]) begin
Dq_buf [ 7 : 0] = dq_rise [ 7 : 0];
end
if (!dm_rise[1]) begin
Dq_buf [15 : 8] = dq_rise [15 : 8];
end
`ifdef x32
if (!dm_rise[2]) begin
Dq_buf [23 : 16] = dq_rise [23 : 16];
end
if (!dm_rise[3]) begin
Dq_buf [31 : 24] = dq_rise [31 : 24];
end
`endif
if (~&dm_rise) begin
if (Debug) begin
$display ("At time %t %m:WRITE: Bank = %d, Row = %d, Col = %d, Data = %h", $realtime, Bank_addr, Rows_addr, Cols_addr, Dq_buf[DQ_BITS-1:0]);
end
end
end
// Write Data
write_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_buf);
// tWR start and tWTR check
if (Sys_clk && &dm_pair === 1'b0) begin
case (Bank_addr)
2'd0 : WR_chk0 = $realtime;
2'd1 : WR_chk1 = $realtime;
2'd2 : WR_chk2 = $realtime;
2'd3 : WR_chk3 = $realtime;
default : $display ("%m: At time %t ERROR: Invalid Bank Address (tWR)", $realtime);
endcase
// // tWTR check
// if (Read_enable === 1'b1) begin
// $display ("%m: At time %t ERROR: tWTR violation during Read", $realtime);
// end
end
end
end
endtask
// Auto Precharge Calculation
task Auto_Precharge_Calculation;
begin
// Precharge counter
if (Read_precharge_access [0] === 1'b1 || Write_precharge_access [0] === 1'b1) begin
Count_precharge [0] = Count_precharge [0] + 1;
end
if (Read_precharge_access [1] === 1'b1 || Write_precharge_access [1] === 1'b1) begin
Count_precharge [1] = Count_precharge [1] + 1;
end
if (Read_precharge_access [2] === 1'b1 || Write_precharge_access [2] === 1'b1) begin
Count_precharge [2] = Count_precharge [2] + 1;
end
if (Read_precharge_access [3] === 1'b1 || Write_precharge_access [3] === 1'b1) begin
Count_precharge [3] = Count_precharge [3] + 1;
end
// Read with AutoPrecharge Calculation
// The device start internal precharge when:
// 1. BL/2 cycles after command
// 2. Meet tRAS requirement
if (Read_precharge_access[0] & (Count_precharge[0] >= burst_length/2)) begin
Read_precharge_access[0] = 1'b0 ;
Read_precharge_pre[0] = 1'b1 ;
end
if ((Read_precharge_pre[0] === 1'b1) && ($realtime - RAS_chk0 >= tRAS - 0.001)) begin
Pc_b0 = 1'b1;
Act_b0 = 1'b0;
RP_chk0 = $realtime;
Read_precharge_pre[0] = 1'b0;
end
if (Read_precharge_access[1] & (Count_precharge[1] >= burst_length/2)) begin
Read_precharge_access[1] = 1'b0 ;
Read_precharge_pre[1] = 1'b1 ;
end
if ((Read_precharge_pre[1] === 1'b1) && ($realtime - RAS_chk1 >= tRAS - 0.001)) begin
Pc_b1 = 1'b1;
Act_b1 = 1'b0;
RP_chk1 = $realtime;
Read_precharge_pre[1] = 1'b0;
end
if (Read_precharge_access[2] & (Count_precharge[2] >= burst_length/2)) begin
Read_precharge_access[2] = 1'b0 ;
Read_precharge_pre[2] = 1'b1 ;
end
if ((Read_precharge_pre[2] === 1'b1) && ($realtime - RAS_chk2 >= tRAS - 0.001)) begin
Pc_b2 = 1'b1;
Act_b2 = 1'b0;
RP_chk2 = $realtime;
Read_precharge_pre[2] = 1'b0;
end
if (Read_precharge_access[3] & (Count_precharge[3] >= burst_length/2)) begin
Read_precharge_access[3] = 1'b0 ;
Read_precharge_pre[3] = 1'b1 ;
end
if ((Read_precharge_pre[3] === 1'b1) && ($realtime - RAS_chk3 >= tRAS - 0.001)) begin
Pc_b3 = 1'b1;
Act_b3 = 1'b0;
RP_chk3 = $realtime;
Read_precharge_pre[3] = 1'b0;
end
// Write with AutoPrecharge Calculation
// The device start internal precharge when:
// 1. Meet tRAS requirement
// 2. Two clock after last burst
// Since tWR is time base, the model will compensate tRP
if (Write_precharge_access[0] & (Count_precharge[0] >= burst_length/2+3)) begin
Write_precharge_access[0] = 1'b0 ;
Write_precharge_pre[0] = 1'b1 ;
end
if (Write_precharge_pre[0] & ($realtime - RAS_chk0 >= tRAS - 0.001)) begin
Write_precharge_pre[0] = 1'b0;
Pc_b0 = 1'b1;
Act_b0 = 1'b0;
RP_chk0 = $realtime - ((2 * clk_period) - tWR);
end
if (Write_precharge_access[1] & (Count_precharge[1] >= burst_length/2+3)) begin
Write_precharge_access[1] = 1'b0 ;
Write_precharge_pre[1] = 1'b1 ;
end
if (Write_precharge_pre[1] & ($realtime - RAS_chk1 >= tRAS - 0.001)) begin
Write_precharge_pre[1] = 1'b0;
Pc_b1 = 1'b1;
Act_b1 = 1'b0;
RP_chk1 = $realtime - ((2 * clk_period) - tWR);
end
if (Write_precharge_access[2] & (Count_precharge[2] >= burst_length/2+3)) begin
Write_precharge_access[2] = 1'b0 ;
Write_precharge_pre[2] = 1'b1 ;
end
if (Write_precharge_pre[2] & ($realtime - RAS_chk2 >= tRAS - 0.001)) begin
Write_precharge_pre[2] = 1'b0;
Pc_b2 = 1'b1;
Act_b2 = 1'b0;
RP_chk2 = $realtime - ((2 * clk_period) - tWR);
end
if (Write_precharge_access[3] & (Count_precharge[3] >= burst_length/2+3)) begin
Write_precharge_access[3] = 1'b0 ;
Write_precharge_pre[3] = 1'b1 ;
end
if (Write_precharge_pre[3] & ($realtime - RAS_chk3 >= tRAS - 0.001)) begin
Write_precharge_pre[3] = 1'b0;
Pc_b3 = 1'b1;
Act_b3 = 1'b0;
RP_chk3 = $realtime - ((2 * clk_period) - tWR);
end
end
endtask
task Power_down_chk;
begin
if (DPD_enable == 1'b1 && enter_DPD == 1'b0) begin
if (prev_cke & Pc_b0 & Pc_b1 & Pc_b2 & Pc_b3) begin
erase_mem(4'b0000, 1'b1);
current_init_state = begin_init ;
ext_mode_load_done = 1'b0 ;
mode_load_done = 1'b0 ;
enter_DPD = 1'b1;
$display ("%m: at time %t Entering Deep Power-Down Mode", $realtime);
end
end
if (enter_DPD == 1'b1) begin
if (Cke == 1'b1 && prev_cke == 1'b0) begin
if (PD_cntr < tCKE) begin
$display ("%m: At time %t ERROR: tCKE violation during exiting of Deep Power-Down Mode", $realtime);
end
$display ("%m: at time %t Exiting Deep Power-Down Mode - A 200 us delay is required with either DESELECT or NOP commands present before the initialization sequence may begin", $realtime);
enter_DPD = 1'b0;
end
end
if (PD_enable == 1'b1 && enter_PD == 1'b0) begin
if (prev_cke) begin
if (Pc_b0 & Pc_b1 & Pc_b2 & Pc_b3) begin
$display ("%m: at time %t Entering Power-Down Mode", $realtime);
enter_PD = 1'b1;
end else if (~Pc_b0 | ~Pc_b1 | ~Pc_b2 | ~Pc_b3) begin
$display ("%m: at time %t Entering Active Power-Down Mode", $realtime);
enter_APD = 1'b1;
end
end
end
if (enter_PD == 1'b1 || enter_APD == 1'b1) begin
if (Cke == 1'b1 && prev_cke == 1'b0) begin
if (PD_cntr < tCKE) begin
if (enter_PD == 1'b1) begin
$display ("%m: At time %t ERROR: tCKE violation during exiting of Power-Down Mode", $realtime);
end else if (enter_APD == 1'b1) begin
$display ("%m: At time %t ERROR: tCKE violation during exiting of Active Power-Down Mode", $realtime);
end
end
if (enter_PD == 1'b1) begin
$display ("%m: at time %t Exiting Power-Down Mode", $realtime);
enter_PD = 1'b0 ;
end else if (enter_APD == 1'b1) begin
$display ("%m: at time %t Exiting Active Power-Down Mode", $realtime);
enter_APD = 1'b0 ;
end
end
end
end
endtask
reg [31:0] xx ;
function [COL_BITS-1:0] Burst_Order;
input [COL_BITS-1:0] Col;
input [31:0] i;
begin
if (Mode_reg[3] == 1'b1) //interleaved
Burst_Order = (Col & -1*burst_length) + (Col%burst_length ^ i);
else // sequential
begin
xx = -1*burst_length;
Burst_Order = (Col & xx) + (Col%burst_length + i) % (burst_length);
end
end
endfunction
// Control Logic
task Control_Logic;
begin
// Self Refresh
if (Sref_enable === 1'b1) begin
// Partial Array Self Refresh
if (part_size == 128) begin
case (Ext_Mode_reg[2:0])
3'b000 : ;//keep Bank 0-7
3'b001 : begin $display("%m: at time %t INFO: Banks 2-3 will be lost due to Partial Array Self Refresh", $realtime) ; erase_mem(4'b0111, 1'b0); end
3'b010 : begin $display("%m: at time %t INFO: Banks 1-3 will be lost due to Partial Array Self Refresh", $realtime) ; erase_mem(4'b0011, 1'b0); end
3'b011 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end
3'b100 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end
3'b101 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end
3'b110 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end
endcase
end else begin
case (Ext_Mode_reg[2:0])
3'b000 : ;//keep Bank 0-7
3'b001 : begin $display("%m: at time %t INFO: Banks 2-3 will be lost due to Partial Array Self Refresh", $realtime) ; erase_mem(4'b0111, 1'b0); end
3'b010 : begin $display("%m: at time %t INFO: Banks 1-3 will be lost due to Partial Array Self Refresh", $realtime) ; erase_mem(4'b0011, 1'b0); end
3'b011 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end
3'b100 : begin $display("%m: at time %t INFO: Reserved", $realtime) ; end
3'b101 : begin $display("%m: at time %t INFO: Banks 1-3 and 1/2 of bank 0 will be lost due to Partial Array Self Refresh", $realtime); erase_mem(4'b0001, 1'b0); end
3'b110 : begin $display("%m: at time %t INFO: Banks 1-3 and 3/4 of bank 0 will be lost due to Partial Array Self Refresh", $realtime); erase_mem(4'b0000, 1'b0); end
endcase
end
SelfRefresh = 1'b1;
end
if (Aref_enable === 1'b1) begin
if (Debug) begin
$display ("Debug: At time %t %m:AUTOREFRESH: Auto Refresh", $realtime);
end
// aref_count is to make sure we have met part of the initialization sequence
if (~power_up_done) begin
aref_count = aref_count + 1;
end
// Auto Refresh to Auto Refresh
if ($realtime - RFC_chk < tRFC - 0.001) begin
$display ("%m: At time %t ERROR: tRFC violation during Auto Refresh", $realtime);
end
// Precharge to Auto Refresh
if (($realtime - RP_chk0 < tRP - 0.001) || ($realtime - RP_chk1 < tRP - 0.001) ||
($realtime - RP_chk2 < tRP - 0.001) || ($realtime - RP_chk3 < tRP - 0.001)) begin
$display ("%m: At time %t ERROR: tRP violation during Auto Refresh", $realtime);
end
// Precharge to Auto Refresh
if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin
$display ("%m: At time %t ERROR: All banks must be Precharged before Auto Refresh", $realtime);
end
// Record Current tRFC time
RFC_chk = $realtime;
end
// SRR Register
if (srr_enable == 1'b1) begin
if (Pc_b0 === 1'b1 && Pc_b1 === 1'b1 && Pc_b2 === 1'b1 && Pc_b3 === 1'b1 &&
Data_out_enable === 1'b0 && Data_in_enable === 1'b0) begin
SRR_read = 1'b1;
SRR_chk = $realtime;
SRR_cntr = 0;
end
end
// Extended Mode Register
if (Ext_mode_enable == 1'b1) begin
if (Debug) begin
$display ("Debug: At time %t %m:EMR : Extended Mode Register", $realtime);
end
// Register Mode
Ext_Mode_reg = Addr;
if (Pc_b0 === 1'b1 && Pc_b1 === 1'b1 && Pc_b2 === 1'b1 && Pc_b3 === 1'b1) begin
// ensure that power sequence is met properly
if (~power_up_done) begin
ext_mode_load_done = 1'b1;
end
$display ("At time %t %m:ELMR : Extended Load Mode Register", $realtime);
if (part_size == 128) begin
// Self Refresh Coverage
case (Addr[2 : 0])
3'b000 : $display ("%m : Self Refresh Cov = 4 banks");
3'b001 : $display ("%m : Self Refresh Cov = 2 banks");
3'b010 : $display ("%m : Self Refresh Cov = 1 bank");
3'b101 : $display ("%m : PASR = Reserved");
3'b110 : $display ("%m : PASR = Reserved");
default : $display ("%m : PASR = Reserved");
endcase
end else begin
// Self Refresh Coverage
case (Addr[2 : 0])
3'b000 : $display ("%m : Self Refresh Cov = 4 banks");
3'b001 : $display ("%m : Self Refresh Cov = 2 banks");
3'b010 : $display ("%m : Self Refresh Cov = 1 bank");
3'b101 : $display ("%m : Self Refresh Cov = 1/2 bank");
3'b110 : $display ("%m : Self Refresh Cov = 1/4 bank");
default : $display ("%m : PASR = Reserved");
endcase
end
// Maximum Case Temp
// case (Addr[4 : 3])
// 2'b11 : $display ("%m : Maximum Case Temp = 85C");
// 2'b00 : $display ("%m : Maximum Case Temp = 70C");
// 2'b01 : $display ("%m : Maximum Case Temp = 45C");
// 2'b10 : $display ("%m : Maximum Case Temp = 15C");
// endcase
// Drive Strength
case (Addr[7 : 5])
3'b000 : $display ("%m : Drive Strength = Full Strength");
3'b001 : $display ("%m : Drive Strength = Half Strength");
3'b010 : $display ("%m : Drive Strength = Quarter Strength");
3'b011 : $display ("%m : Drive Strength = Three Quarter Strength");
3'b100 : $display ("%m : Drive Strength = Three Quarter Strength");
endcase
end else begin
$display ("%m: At time %t ERROR: all banks must be Precharged before Extended Mode Register", $realtime);
end
// Precharge to EMR
if (($realtime - RP_chk0 < tRP - 0.001) || ($realtime - RP_chk1 < tRP - 0.001) ||
($realtime - RP_chk2 < tRP - 0.001) || ($realtime - RP_chk3 < tRP - 0.001)) begin
$display ("%m: At time %t ERROR: tRP violation during Extended Mode Register", $realtime);
end
// LMR/EMR to LMR/EMR
// if ($realtime - MRD_chk < tMRD) begin
// $display ("%m: At time %t ERROR: tMRD violation during Extended Mode Register", $realtime);
// end
if (MRD_cntr < tMRD) begin
$display ("%m: At time %t ERROR: tMRD violation during Extended Mode Register", $realtime);
end
// Record current tMRD time
// MRD_chk = $realtime;
MRD_cntr = 0;
end
// Load Mode Register
if (Mode_reg_enable === 1'b1) begin
if (Debug) begin
$display ("Debug: At time %t %m:LMR : Load Mode Register", $realtime);
end
// Register Mode
Mode_reg = Addr;
if (Mode_reg[6:4] == 3'b010) begin
if (tCK2_min == 0) begin
$display ("%m : at time %t ERROR : Illegal CAS Latency of 2 set for current speed grade", $realtime);
end
end
// Precharge to LMR
if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin
$display ("%m: At time %t ERROR: all banks must be Precharged before Load Mode Register", $realtime);
end
// Precharge to LMR
if (($realtime - RP_chk0 < tRP - 0.001) || ($realtime - RP_chk1 < tRP - 0.001) ||
($realtime - RP_chk2 < tRP - 0.001) || ($realtime - RP_chk3 < tRP - 0.001)) begin
$display ("%m: At time %t ERROR: tRP violation during Load Mode Register", $realtime);
end
// LMR/EMR to LMR/EMR
// if ($realtime - MRD_chk < tMRD) begin
// $display ("%m: At time %t ERROR: tMRD violation during Load Mode Register", $realtime);
// end
if (MRD_cntr < tMRD) begin
$display ("%m: At time %t ERROR: tMRD violation during Load Mode Register", $realtime);
end
if (Pc_b0 === 1'b1 && Pc_b1 === 1'b1 && Pc_b2 === 1'b1 && Pc_b3 === 1'b1) begin
// ensure that power sequence is met properly
if (~power_up_done) begin
mode_load_done = 1'b1;
end
// Burst Length
case (Addr [2 : 0])
3'b001 : $display ("At time %t %m:LMR : Burst Length = 2", $realtime);
3'b010 : $display ("At time %t %m:LMR : Burst Length = 4", $realtime);
3'b011 : $display ("At time %t %m:LMR : Burst Length = 8", $realtime);
3'b100 : $display ("At time %t %m:LMR : Burst Length = 16",$realtime);
default :
begin
$display ("%m: At time %t ERROR: Undefined burst length selection", $realtime);
$stop;
end
endcase
// CAS Latency
case (Addr [6 : 4])
3'b010 : $display ("At time %t %m:LMR : CAS Latency = 2", $realtime);
3'b011 : $display ("At time %t %m:LMR : CAS Latency = 3", $realtime);
default : begin
$display ("%m: At time %t ERROR: CAS Latency not supported", $realtime);
$stop;
end
endcase
end
// Record current tMRD time
// MRD_chk = $realtime;
MRD_cntr = 0;
end
// Activate Block
if (Active_enable === 1'b1) begin
if (!(power_up_done)) begin
$display ("%m: At time %t ERROR: Power Up and Initialization Sequence not completed before executing Activate command", $realtime);
end
// Display Debug Message
if (Debug) begin
$display ("Debug: At time %t %m:ACTIVATE: Bank = %d, Row = %d", $realtime, Ba, Addr);
end
// Activating an open bank can cause corruption.
if ((Ba === 2'b00 && Pc_b0 === 1'b0) || (Ba === 2'b01 && Pc_b1 === 1'b0) ||
(Ba === 2'b10 && Pc_b2 === 1'b0) || (Ba === 2'b11 && Pc_b3 === 1'b0)) begin
$display ("%m: At time %t ERROR: Bank = %d is already activated - data can be corrupted", $realtime, Ba);
end
// Activate Bank 0
if (Ba === 2'b00 && Pc_b0 === 1'b1) begin
// Activate to Activate (same bank)
if ($realtime - RC_chk0 < tRC - 0.001) begin
$display ("%m: At time %t ERROR: tRC violation during Activate bank %d", $realtime, Ba);
end
// Precharge to Activate
if ($realtime - RP_chk0 < tRP - 0.001) begin
$display ("%m: At time %t ERROR: tRP violation during Activate bank %d", $realtime, Ba);
end
// Record variables for checking violation
Act_b0 = 1'b1;
Pc_b0 = 1'b0;
B0_row_addr = Addr;
RC_chk0 = $realtime;
RCD_chk0 = $realtime;
RAS_chk0 = $realtime;
RAP_chk0 = $realtime;
end
// Activate Bank 1
if (Ba === 2'b01 && Pc_b1 === 1'b1) begin
// Activate to Activate (same bank)
if ($realtime - RC_chk1 < tRC - 0.001) begin
$display ("%m: At time %t ERROR: tRC violation during Activate bank %d", $realtime, Ba);
end
// Precharge to Activate
if ($realtime - RP_chk1 < tRP - 0.001) begin
$display ("%m: At time %t ERROR: tRP violation during Activate bank %d", $realtime, Ba);
end
// Record variables for checking violation
Act_b1 = 1'b1;
Pc_b1 = 1'b0;
B1_row_addr = Addr;
RC_chk1 = $realtime;
RCD_chk1 = $realtime;
RAS_chk1 = $realtime;
RAP_chk1 = $realtime;
end
// Activate Bank 2
if (Ba === 2'b10 && Pc_b2 === 1'b1) begin
// Activate to Activate (same bank)
if ($realtime - RC_chk2 < tRC - 0.001) begin
$display ("%m: At time %t ERROR: tRC violation during Activate bank %d", $realtime, Ba);
end
// Precharge to Activate
if ($realtime - RP_chk2 < tRP - 0.001) begin
$display ("%m: At time %t ERROR: tRP violation during Activate bank %d", $realtime, Ba);
end
// Record variables for checking violation
Act_b2 = 1'b1;
Pc_b2 = 1'b0;
B2_row_addr = Addr;
RC_chk2 = $realtime;
RCD_chk2 = $realtime;
RAS_chk2 = $realtime;
RAP_chk2 = $realtime;
end
// Activate Bank 3
if (Ba === 2'b11 && Pc_b3 === 1'b1) begin
// Activate to Activate (same bank)
if ($realtime - RC_chk3 < tRC - 0.001) begin
$display ("%m: t time %t ERROR: tRC violation during Activate bank %d", $realtime, Ba);
end
// Precharge to Activate
if ($realtime - RP_chk3 < tRP - 0.001) begin
$display ("%m: At time %t ERROR: tRP violation during Activate bank %d", $realtime, Ba);
end
// Record variables for checking violation
Act_b3 = 1'b1;
Pc_b3 = 1'b0;
B3_row_addr = Addr;
RC_chk3 = $realtime;
RCD_chk3 = $realtime;
RAS_chk3 = $realtime;
RAP_chk3 = $realtime;
end
// Activate to Activate (different bank)
if ((Prev_bank != Ba) && ($realtime - RRD_chk < tRRD - 0.001)) begin
$display ("%m: At time %t ERROR: tRRD violation during Activate bank = %d", $realtime, Ba);
end
// AutoRefresh to Activate
if ($realtime - RFC_chk < tRFC - 0.001) begin
$display ("%m: At time %t ERROR: tRFC violation during Activate bank %d", $realtime, Ba);
end
// Record variable for checking violation
RRD_chk = $realtime;
Prev_bank = Ba;
end
// Precharge Block - consider NOP if bank already precharged or in process of precharging
if (Prech_enable === 1'b1) begin
// Display Debug Message
if (Debug) begin
$display ("Debug: At time %t %m:PRE: Addr[10] = %b, Bank = %b", $realtime, Addr[10], Ba);
end
// EMR or LMR to Precharge
// if ($realtime - MRD_chk < tMRD) begin
// $display ("%m: At time %t ERROR: tMRD violation during Precharge", $realtime);
// end
if (MRD_cntr < tMRD) begin
$display ("%m: At time %t ERROR: tMRD violation during Precharge", $realtime);
end
// Precharge bank 0
if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b00)) && Act_b0 === 1'b1) begin
Act_b0 = 1'b0;
Pc_b0 = 1'b1;
RP_chk0 = $realtime;
// Activate to Precharge Bank
if ($realtime - RAS_chk0 < tRAS - 0.001) begin
$display ("%m: At time %t ERROR: tRAS violation during Precharge", $realtime);
end
// tWR violation check for Write
if ($realtime - WR_chk0 < tWR - 0.001) begin
$display ("%m: At time %t ERROR: tWR violation during Precharge", $realtime);
end
end
// Precharge bank 1
if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b01)) && Act_b1 === 1'b1) begin
Act_b1 = 1'b0;
Pc_b1 = 1'b1;
RP_chk1 = $realtime;
// Activate to Precharge Bank 1
if ($realtime - RAS_chk1 < tRAS - 0.001) begin
$display ("%m: At time %t ERROR: tRAS violation during Precharge", $realtime);
end
// tWR violation check for Write
if ($realtime - WR_chk1 < tWR - 0.001) begin
$display ("%m: At time %t ERROR: tWR violation during Precharge", $realtime);
end
end
// Precharge bank 2
if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b10)) && Act_b2 === 1'b1) begin
Act_b2 = 1'b0;
Pc_b2 = 1'b1;
RP_chk2 = $realtime;
// Activate to Precharge Bank 2
if ($realtime - RAS_chk2 < tRAS - 0.001) begin
$display ("%m: At time %t ERROR: tRAS violation during Precharge", $realtime);
end
// tWR violation check for Write
if ($realtime - WR_chk2 < tWR - 0.001) begin
$display ("%m: At time %t ERROR: tWR violation during Precharge", $realtime);
end
end
// Precharge bank 3
if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b11)) && Act_b3 === 1'b1) begin
Act_b3 = 1'b0;
Pc_b3 = 1'b1;
RP_chk3 = $realtime;
// Activate to Precharge Bank 3
if ($realtime - RAS_chk3 < tRAS - 0.001) begin
$display ("%m: At time %t ERROR: tRAS violation during Precharge", $realtime);
end
// tWR violation check for Write
if ($realtime - WR_chk3 < tWR - 0.001) begin
$display ("%m: At time %t ERROR: tWR violation during Precharge", $realtime);
end
end
// Pipeline for READ
if ((Addr[10] === 1'b1) | (Ba == Write_bank_pipeline[4]))
for (i = 4; i < `MAX_PIPE; i = i + 1)
Read_pipeline[i] = 1'b0 ;
end
// Burst terminate
if (Burst_term === 1'b1) begin
// Display Debug Message
if (Debug) begin
$display ("Debug: %m: At time %t BURST_TERMINATE): Burst Terminate",$realtime);
end
// Burst Terminate Command Pipeline for Read
for (i = cas_latency_x2-1; i < `MAX_PIPE; i = i + 1)
Read_pipeline[i] = 1'b0 ;
// Illegal to burst terminate a Write
if ((Data_in_enable === 1'b1) & ~((&dm_rise) & (&dm_fall))) begin
$display ("%m: At time %t ERROR: It's illegal to burst terminate a Write", $realtime);
end
// Illegal to burst terminate a Read with Auto Precharge
if (|Read_precharge_access) begin
$display ("%m: At time %t ERROR: It's illegal to burst terminate a Read with Auto Precharge", $realtime);
end
end
// Read Command
if (Read_enable === 1'b1) begin
if (!(power_up_done)) begin
$display ("%m: At time %t ERROR: Power Up and Initialization Sequence not completed before executing Read Command", $realtime);
end
// Display Debug Message
if (Debug) begin
$display ("Debug: At time %t %m:READ: Bank = %d, Col = %d", $realtime, Ba, {Addr [11], Addr [9 : 0]});
end
if (part_size == 1024) begin
if (SRR_read == 1'b1) begin
if (SRR_cntr < tSRR) begin
$display ("%m: At time %t ERROR: tSRR Violation", $realtime);
end
SRC_cntr = 0 ;
end
end else begin
if (SRR_read == 1'b1) begin
if ($realtime - SRR_chk < tSRR-0.01) begin
$display ("%m: At time %t ERROR: tSRR Violation", $realtime);
end
SRC_cntr = 0;
end
end
// CAS Latency pipeline
if (SRR_read) begin
if ({Ba, Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]} > 0) begin
$display ("%m: At time %t ERROR: Address must be all 0 during SRR Read", $realtime);
end
for (i=0; i<2; i=i+1)
begin
Read_pipeline[cas_latency_x2 - 2 + i + 1] = 1'b1;
Write_col_pipeline [cas_latency_x2 - 2 + i + 1] = i;
Write_bank_pipeline [cas_latency_x2 - 2 + i + 1] = 0;
end
end else begin
for (i=0; i<burst_length; i=i+1)
begin
Read_pipeline[cas_latency_x2 - 2 + i + 1] = 1'b1;
Write_bank_pipeline [cas_latency_x2 - 2 + i + 1] = Ba;
Write_col_pipeline [cas_latency_x2 - 2 + i + 1] = Burst_Order({Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]}, i);
end
end
// Clear out Write Pipeline
Write_pipeline = 64'b0;
// Interrupt a Read with Auto Precharge
if (Read_precharge_access [Ba] === 1'b1) begin
$display ("%m: At time %t ERROR: It's illegal to interrupt a Read with Auto Precharge (same bank)", $realtime);
end else if ((Read_precharge_access [0] === 1'b1) |
(Read_precharge_access [1] === 1'b1) |
(Read_precharge_access [2] === 1'b1) |
(Read_precharge_access [3] === 1'b1) ) begin
$display ("%m: At time %t ERROR: It's illegal to interrupt a Read with Auto Precharge (different banks)", $realtime);
end
// Interrupt a Write with Auto Precharge
if (Write_precharge_access [Ba] === 1'b1) begin
// $display ("%m: At time %t ERROR: It's illegal to interrupt a Write with Auto Precharge (same banks)", $realtime);
end else if ((Write_precharge_count [0] < (burst_length/2 )) & (Mode_reg[6:4] == 3'b010) |
(Write_precharge_count [1] < (burst_length/2 )) & (Mode_reg[6:4] == 3'b010) |
(Write_precharge_count [2] < (burst_length/2 )) & (Mode_reg[6:4] == 3'b010) |
(Write_precharge_count [3] < (burst_length/2 )) & (Mode_reg[6:4] == 3'b010) |
(Write_precharge_count [0] < (burst_length/2-1)) & (Mode_reg[6:4] == 3'b011) |
(Write_precharge_count [1] < (burst_length/2-1)) & (Mode_reg[6:4] == 3'b011) |
(Write_precharge_count [2] < (burst_length/2-1)) & (Mode_reg[6:4] == 3'b011) |
(Write_precharge_count [3] < (burst_length/2-1)) & (Mode_reg[6:4] == 3'b011) ) begin
$display ("%m: At time %t ERROR: It's illegal to interrupt a data transfer on a Write with Auto Precharge (different banks)", $realtime);
end
// Activate to Read
if (((Ba === 2'b00 && Pc_b0 === 1'b1) || (Ba === 2'b01 && Pc_b1 === 1'b1) ||
(Ba === 2'b10 && Pc_b2 === 1'b1) || (Ba === 2'b11 && Pc_b3 === 1'b1)) &&
(SRR_read == 1'b0)) begin
$display("%m: At time %t ERROR: Bank is not Activated for Read", $realtime);
end
// Activate to Read without Auto Precharge
if ((Addr [10] === 1'b0 && Ba === 2'b00 && $realtime - RCD_chk0 < tRCD - 0.001) ||
(Addr [10] === 1'b0 && Ba === 2'b01 && $realtime - RCD_chk1 < tRCD - 0.001) ||
(Addr [10] === 1'b0 && Ba === 2'b10 && $realtime - RCD_chk2 < tRCD - 0.001) ||
(Addr [10] === 1'b0 && Ba === 2'b11 && $realtime - RCD_chk3 < tRCD - 0.001)) begin
$display("%m: At time %t ERROR: tRCD violation during Read", $realtime);
end
// Auto Precharge
if (Addr[10] === 1'b1) begin
Read_precharge_access [Ba]= 1'b1;
Count_precharge [Ba]= 0;
Read_precharge_count[Ba] = 4'h0;
end
// tWTR
if (tWTR_cntr < tWTR - 0.001) begin
$display("%m: At time %t ERROR: tWTR violation during Read", $realtime);
end
end
// Write Command
if (Write_enable === 1'b1) begin
if (!(power_up_done)) begin
$display ("%m: At time %t ERROR: Power Up and Initialization Sequence not completed before executing Write Command", $realtime);
end
// display debug message
if (Debug) begin
$display ("Debug: At time %t %m:WRITE: Bank = %d, Col = %d", $realtime, Ba, {Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]});
end
// Pipeline for Write
// Write_pipeline [3] = 1'b1;
for (i=0; i<burst_length; i=i+1)
begin
Write_pipeline[1 + i] = 1'b1;
// Write_col_pipeline [1 + i] = {Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]} + i;
Write_col_pipeline [1 + i] = Burst_Order({Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]}, i);
Write_bank_pipeline [1 + i] = Ba;
end
// Interrupt a Write with Auto Precharge (same bank only)
if (Write_precharge_access [Ba] === 1'b1) begin
$display ("%m: At time %t ERROR: It's illegal to interrupt a Write with Auto Precharge", $realtime);
end
// Activate to Write
if ((Ba === 2'b00 && Pc_b0 === 1'b1) || (Ba === 2'b01 && Pc_b1 === 1'b1) ||
(Ba === 2'b10 && Pc_b2 === 1'b1) || (Ba === 2'b11 && Pc_b3 === 1'b1)) begin
$display("%m: At time %t ERROR: Bank is not Activated for Write", $realtime);
end
// Activate to Write
if ((Ba === 2'b00 && $realtime - RCD_chk0 < tRCD - 0.001) ||
(Ba === 2'b01 && $realtime - RCD_chk1 < tRCD - 0.001) ||
(Ba === 2'b10 && $realtime - RCD_chk2 < tRCD - 0.001) ||
(Ba === 2'b11 && $realtime - RCD_chk3 < tRCD - 0.001)) begin
$display("%m: At time %t ERROR: tRCD violation during Write to Bank %d", $realtime, Ba);
end
if (Read_pipeline[0]) begin
$display("%m: At time %t ERROR: Read to Write violation", $realtime);
end
// Interrupt a Write with Auto Precharge
if (Write_precharge_access [Ba] === 1'b1) begin
$display ("%m: At time %t ERROR: It's illegal to interrupt a Write with Auto Precharge (same bank)", $realtime);
end else if (((Write_precharge_access [0] === 1'b1) & (Count_precharge[0] < (burst_length/2))) |
((Write_precharge_access [1] === 1'b1) & (Count_precharge[1] < (burst_length/2))) |
((Write_precharge_access [2] === 1'b1) & (Count_precharge[2] < (burst_length/2))) |
((Write_precharge_access [3] === 1'b1) & (Count_precharge[3] < (burst_length/2))) ) begin
$display ("%m: At time %t ERROR: It's illegal to interrupt a Write with Auto Precharge (different bank)", $realtime);
end
// Interrupt a Read with Auto Precharge
if (((Read_precharge_count [Ba] < (4'h2 + (burst_length/2))) & (Mode_reg[6:4] == 3'b010)) |
((Read_precharge_count [Ba] < (4'h3 + (burst_length/2))) & (Mode_reg[6:4] == 3'b011)) ) begin
// $display ("%m: At time %t ERROR: It's illegal to interrupt a Read with Auto Precharge (same bank)", $realtime);
end else if (((Read_precharge_count [0] < (4'h2 + (burst_length/2))) & (Mode_reg[6:4] == 3'b010)) |
((Read_precharge_count [1] < (4'h2 + (burst_length/2))) & (Mode_reg[6:4] == 3'b010)) |
((Read_precharge_count [2] < (4'h2 + (burst_length/2))) & (Mode_reg[6:4] == 3'b010)) |
((Read_precharge_count [3] < (4'h2 + (burst_length/2))) & (Mode_reg[6:4] == 3'b010)) |
((Read_precharge_count [0] < (4'h3 + (burst_length/2))) & (Mode_reg[6:4] == 3'b011)) |
((Read_precharge_count [1] < (4'h3 + (burst_length/2))) & (Mode_reg[6:4] == 3'b011)) |
((Read_precharge_count [2] < (4'h3 + (burst_length/2))) & (Mode_reg[6:4] == 3'b011)) |
((Read_precharge_count [3] < (4'h3 + (burst_length/2))) & (Mode_reg[6:4] == 3'b011)) ) begin
$display ("%m: At time %t ERROR: It's illegal to interrupt a data transfer on a Read with Auto Precharge (different bank)", $realtime);
end
// Auto Precharge
if (Addr[10] === 1'b1) begin
Write_precharge_access [Ba]= 1'b1;
Count_precharge [Ba]= 0;
Write_precharge_count[Ba] = 4'h0;
end
end
end
endtask
// Main Logic
always @ (posedge Sys_clk) begin
ShiftPipelines;
// Manual_Precharge_Pipeline;
// Burst_Terminate_Pipeline;
Dq_Dqs_Drivers;
Write_FIFO_DM_Mask_Logic;
Burst_Decode;
Auto_Precharge_Calculation;
Timing_chk_SRC;
Control_Logic;
MRD_counter;
SRR_counter;
SRC_counter;
tWTR_counter;
command_counter;
end
always @ (negedge Sys_clk) begin
ShiftPipelines;
// Manual_Precharge_Pipeline;
// Burst_Terminate_Pipeline;
Dq_Dqs_Drivers;
Write_FIFO_DM_Mask_Logic;
Burst_Decode;
end
// Dqs Receiver
always @ (posedge Dqs_in[0]) begin
// Latch data at posedge Dqs
dq_rise[7 : 0] = Dq_in[7 : 0];
dm_rise[0] = Dm_in[0];
expect_pos_dqs[0] = 0;
end
always @ (posedge Dqs_in[1]) begin
// Latch data at posedge Dqs
dq_rise[15 : 8] = Dq_in[15 : 8];
dm_rise[1] = Dm_in[1];
expect_pos_dqs[1] = 0;
end
`ifdef x32
always @ (posedge Dqs_in[2]) begin
// Latch data at posedge Dqs
dq_rise[23 : 16] = Dq_in[23 : 16];
dm_rise[2] = Dm_in[2];
expect_pos_dqs[2] = 0;
end
always @ (posedge Dqs_in[3]) begin
// Latch data at posedge Dqs
dq_rise[31 : 24] = Dq_in[31 : 24];
dm_rise[3] = Dm_in[3];
expect_pos_dqs[3] = 0;
end
`endif
always @ (negedge Dqs_in[0]) begin
// Latch data at negedge Dqs
dq_fall[7 : 0] = Dq_in[7 : 0];
dm_fall[0] = Dm_in[0];
dm_pair[1:0] = {dm_rise[0], dm_fall[0]};
expect_neg_dqs[0] = 0;
end
always @ (negedge Dqs_in[1]) begin
// Latch data at negedge Dqs
dq_fall[15: 8] = Dq_in[15 : 8];
dm_fall[1] = Dm_in[1];
dm_pair[3:2] = {dm_rise[1], dm_fall[1]};
expect_neg_dqs[1] = 0;
end
`ifdef x32
always @ (negedge Dqs_in[2]) begin
// Latch data at negedge Dqs
dq_fall[23: 16] = Dq_in[23 : 16];
dm_fall[2] = Dm_in[2];
dm_pair[5:4] = {dm_rise[2], dm_fall[2]};
expect_neg_dqs[2] = 0;
end
always @ (negedge Dqs_in[3]) begin
// Latch data at negedge Dqs
dq_fall[31: 24] = Dq_in[31 : 24];
dm_fall[3] = Dm_in[3];
dm_pair[7:6] = {dm_rise[3], dm_fall[3]};
expect_neg_dqs[3] = 0;
end
`endif
// Dqs edge checking
always @ (posedge Sys_clk) begin
// if (Write_pipeline[2] || Write_pipeline[1] || Data_in_enable) begin
if (Write_pipeline[-1]) begin
for (i=0; i<DQS_BITS; i=i+1) begin
if (expect_neg_dqs[i]) begin
$display ("%m: At time %t ERROR: Negative DQS[%1d] transition required.", $realtime, i);
end
expect_neg_dqs[i] = 1'b1;
end
end else begin
expect_neg_dqs = 0;
expect_pos_dqs = 0;
end
end
always @ (negedge Sys_clk) begin
// if (Write_pipeline[2] || Write_pipeline[1] || Data_in_enable) begin
if (Write_pipeline[-1]) begin
for (i=0; i<DQS_BITS; i=i+1) begin
if (expect_pos_dqs[i]) begin
$display ("%m: At time %t ERROR: Positive DQS[%1d] transition required.", $realtime, i);
end
expect_pos_dqs[i] = 1'b1;
end
end else begin
expect_neg_dqs = 0;
expect_pos_dqs = 0;
end
end
specify
// SYMBOL UNITS DESCRIPTION
// ------ ----- -----------
`ifdef sg5 // specparams for -6 (CL = 3)
specparam tCLK_MIN = 5.0 ; // tCLK ns minimum clk cycle time
specparam tDSS = 1.0 ; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.0 ; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.0 ; // tIH ns Input Hold Time (fast)
specparam tIS = 1.0 ; // tIS ns Input Setup Time (fast)
specparam tDQSH = 1.75; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 1.75; // tDQSL ns DQS input Low Pulse Width
`elsif sg54 // specparams for -6 (CL = 3)
specparam tCLK_MIN = 5.4; // tCLK ns minimum clk cycle time
specparam tDSS = 1.08; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.08; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.0; // tIH ns Input Hold Time (fast)
specparam tIS = 1.0; // tIS ns Input Setup Time (fast)
specparam tDQSH = 2.16; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 2.16; // tDQSL ns DQS input Low Pulse Width
`elsif sg6 // specparams for -6 (CL = 3)
specparam tCLK_MIN = 6.0; // tCLK ns minimum clk cycle time
specparam tDSS = 1.2; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.2; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.1; // tIH ns Input Hold Time (fast)
specparam tIS = 1.1; // tIS ns Input Setup Time (fast)
specparam tDQSH = 2.1; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 2.1; // tDQSL ns DQS input Low Pulse Width
`elsif sg75 // specparams for -75 (CL = 3)
specparam tCLK_MIN = 7.5; // tCLK ns minimum clk cycle time
specparam tDSS = 1.5; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.5; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.3; // tIH ns Input Hold Time (fast)
specparam tIS = 1.3; // tIS ns Input Setup Time (fast)
specparam tDQSH = 3.0; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 3.0; // tDQSL ns DQS input Low Pulse Width
`elsif sg5v18 // specparams for -6 (CL = 3)
specparam tCLK_MIN = 5.0 ; // tCLK ns minimum clk cycle time
specparam tDSS = 1.0 ; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.0 ; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 0.9 ; // tIH ns Input Hold Time (fast)
specparam tIS = 0.9 ; // tIS ns Input Setup Time (fast)
specparam tDQSH = 2.0 ; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 2.0 ; // tDQSL ns DQS input Low Pulse Width
`elsif sg6v18 // specparams for -6 (CL = 3)
specparam tCLK_MIN = 6.0; // tCLK ns minimum clk cycle time
specparam tDSS = 1.2; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.2; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.1; // tIH ns Input Hold Time (fast)
specparam tIS = 1.1; // tIS ns Input Setup Time (fast)
specparam tDQSH = 2.4; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 2.4; // tDQSL ns DQS input Low Pulse Width
`elsif sg75v18 // specparams for -75 (CL = 3)
specparam tCLK_MIN = 7.5; // tCLK ns minimum clk cycle time
specparam tDSS = 1.5; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.5; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.3; // tIH ns Input Hold Time (fast)
specparam tIS = 1.3; // tIS ns Input Setup Time (fast)
specparam tDQSH = 3.0; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 3.0; // tDQSL ns DQS input Low Pulse Width
`elsif sg6v12 // specparams for -6 (CL = 3)
specparam tCLK_MIN = 6.0; // tCLK ns minimum clk cycle time
specparam tDSS = 1.2; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.2; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.1; // tIH ns Input Hold Time (fast)
specparam tIS = 1.1; // tIS ns Input Setup Time (fast)
specparam tDQSH = 2.1; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 2.1; // tDQSL ns DQS input Low Pulse Width
`elsif sg75v12 // specparams for -75 (CL = 3)
specparam tCLK_MIN = 7.5; // tCLK ns minimum clk cycle time
specparam tDSS = 1.5; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.5; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.3; // tIH ns Input Hold Time (fast)
specparam tIS = 1.3; // tIS ns Input Setup Time (fast)
specparam tDQSH = 3.0; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 3.0; // tDQSL ns DQS input Low Pulse Width
`elsif sg10v12 // specparams for -10 (CL = 3)
specparam tCLK_MIN = 9.6; // tCLK ns minimum clk cycle time
specparam tDSS = 1.92; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.92; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.7; // tIH ns Input Hold Time (fast)
specparam tIS = 1.7; // tIS ns Input Setup Time (fast)
specparam tDQSH = 3.84; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 3.84; // tDQSL ns DQS input Low Pulse Width
`else `define sg10 // specparams for -10 (CL = 3)
specparam tCLK_MIN = 9.6; // tCLK ns minimum clk cycle time
specparam tDSS = 1.92; // tDSS ns DQS falling edge to CLK rising (setup time)
specparam tDSH = 1.92; // tDSH ns DQS falling edge from CLK rising (hold time)
specparam tIH = 1.5; // tIH ns Input Hold Time (fast)
specparam tIS = 1.5; // tIS ns Input Setup Time (fast)
specparam tDQSH = 3.84; // tDQSH ns DQS input High Pulse Width
specparam tDQSL = 3.84; // tDQSL ns DQS input Low Pulse Width
`endif
$period (posedge Clk, tCLK_MIN);
$width (posedge Dqs_in[0] &&& wdqs_valid, tDQSH);
$width (posedge Dqs_in[1] &&& wdqs_valid, tDQSH);
$width (negedge Dqs_in[0] &&& wdqs_valid, tDQSL);
$width (negedge Dqs_in[1] &&& wdqs_valid, tDQSL);
$setuphold(posedge Clk, Cke, tIS, tIH);
$setuphold(posedge Clk, Cs_n, tIS, tIH);
$setuphold(posedge Clk, Cas_n, tIS, tIH);
$setuphold(posedge Clk, Ras_n, tIS, tIH);
$setuphold(posedge Clk, We_n, tIS, tIH);
$setuphold(posedge Clk, Addr, tIS, tIH);
$setuphold(posedge Clk, Ba, tIS, tIH);
$setuphold(posedge Clk, negedge Dqs &&& wdqs_valid, tDSS , tDSH);
endspecify
endmodule