URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/orpsocv2/boards
- from Rev 630 to Rev 631
- ↔ Reverse comparison
Rev 630 → Rev 631
/xilinx/atlys/bench/verilog/ddr2_model.v
0,0 → 1,2031
/**************************************************************************************** |
* |
* File Name: ddr2_model.v |
* Version: 5.82 |
* Model: BUS Functional |
* |
* Dependencies: ddr2_model_parameters.vh |
* |
* Description: Micron SDRAM DDR2 (Double Data Rate 2) |
* |
* Limitation: - doesn't check for average refresh timings |
* - positive ck and ck_n edges are used to form internal clock |
* - positive dqs and dqs_n edges are used to latch data |
* - test mode is not modeled |
* |
* Note: - Set simulator resolution to "ps" accuracy |
* - Set Debug = 0 to disable $display messages |
* |
* Disclaimer This software code and all associated documentation, comments or other |
* of Warranty: information (collectively "Software") is provided "AS IS" without |
* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY |
* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES |
* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT |
* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE |
* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. |
* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR |
* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, |
* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE |
* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, |
* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, |
* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, |
* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, |
* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE |
* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
* DAMAGES. Because some jurisdictions prohibit the exclusion or |
* limitation of liability for consequential or incidental damages, the |
* above limitation may not apply to you. |
* |
* Copyright 2003 Micron Technology, Inc. All rights reserved. |
* |
* Rev Author Date Changes |
* --------------------------------------------------------------------------------------- |
* 1.00 JMK 07/29/03 Initial Release |
* 1.10 JMK 08/09/03 Timing Parameter updates to tIS, tIH, tDS, tDH |
* 2.20 JMK 08/07/03 General cleanup |
* 2.30 JMK 11/26/03 Added CL_MIN, CL_MAX, wl_min and wl_max parameters. |
* Added AL_MIN and AL_MAX parameters. |
* Removed support for OCD. |
* 2.40 JMK 01/15/04 Removed verilog 2001 constructs. |
* 2.50 JMK 01/29/04 Removed tRP checks during Precharge command. |
* 2.60 JMK 04/20/04 Fixed tWTR check. |
* 2.70 JMK 04/30/04 Added tRFC maximum check. |
* Combined Self Refresh and Power Down always blocks. |
* Added Reset Function (CKE LOW Anytime). |
* 2.80 JMK 08/19/04 Precharge is treated as NOP when bank is not active. |
* Added checks for tRAS, tWR, tRTP to any bank during Pre-All. |
* tRFC maximum violation will only display one time. |
* 2.90 JMK 11/05/04 Fixed DQS checking during write. |
* Fixed false tRFC max assertion during power up and self ref. |
* Added warning for 200us CKE low time during initialization. |
* Added -3, -3E, and -37V speed grades to ddr2_parameters.v |
* 3.00 JMK 04/22/05 Removed ODT off requirement during power down. |
* Added tAOND, tAOFD, tANPD, tAXPD, tAONPD, and tAOFPD parameters. |
* Added ODT status messages. |
* Updated the initialization sequence. |
* Disable ODT and CLK pins during self refresh. |
* Disable cmd and addr pins during power down and self refresh. |
* 3.10 JMK 06/07/05 Disable trpa checking if the part does not have 8 banks. |
* Changed tAXPD message from error to a warning. |
* Added tDSS checking. |
* Removed tDQSL checking during tWPRE and tWPST. |
* Fixed a burst order error during writes. |
* Renamed parameters file with .vh extension. |
* 3.20 JMK 07/18/05 Removed 14 tCK requirement from LMR to READ. |
* 3.30 JMK 08/03/05 Added check for interrupting a burst with auto precharge. |
* 4.00 JMK 11/21/05 Parameter names all UPPERCASE, signal names all lowercase. |
* Clock jitter can be tolerated within specification range. |
* Clock frequency is sampled from the CK pin. |
* Scaleable up to 64 DQ and 16 DQS bits. |
* Read data can be randomly skewed using RANDOM_OUT_DELAY. |
* Parameterized read and write DQS, and read DQ. |
* Initialization can be bypassed using initialize task. |
* 4.10 JMK 11/30/05 Fixed compile errors when `MAX_MEM was defined. |
* 4.20 JMK 12/09/05 Fixed memory addressing error when `MAX_MEM was defined. |
* 4.30 JMK 02/15/06 Added dummy write to initialization sequence. |
* Removed tWPST maximum checking. |
* Rising dqs_n edge latches data when enabled in EMR. |
* Fixed a sign error in the tJIT(cc) calculation. |
* 4.40 JMK 02/16/06 Fixed dummy write when`MAX_MEM was defined. |
* 4.50 JMK 02/27/06 Fixed extra tDQSS assertions. |
* Fixed tRCD and tWTR checking. |
* Errors entering Power Down or Self Refresh will cause reset. |
* Ignore dqs_n when disabled in EMR. |
* 5.00 JMK 04/24/06 Test stimulus now included from external file (subtest.vh) |
* Fixed tRFC max assertion during self refresh. |
* Fixed tANPD checking during Power Down. |
* Removed dummy write from initialization sequence. |
* 5.01 JMK 04/28/06 Fixed Auto Precharge to Load Mode, Refresh and Self Refresh. |
* Removed Auto Precharge error message during Power Down Enter. |
* 5.10 JMK 07/26/06 Created internal clock using ck and ck_n. |
* RDQS can only be enabled in EMR for x8 configurations. |
* CAS latency is checked vs frequency when DLL locks. |
* tMOD changed from tCK units to ns units. |
* Added 50 Ohm setting for Rtt in EMR. |
* Improved checking of DQS during writes. |
* 5.20 JMK 10/02/06 Fixed DQS checking for interrupting write to write and x16. |
* 5.30 JMK 05/25/07 Fixed checking for 0-Z transition on write postamble. |
* 5.50 JMK 05/30/08 Renamed ddr2_dimm.v to ddr2_module.v and added SODIMM support. |
* Added a register delay to ddr2_module.v when RDIMM is defined. |
* Added multi-chip package model support in ddr2_mcp.v |
* Added High Temp Self Refresh rate setting in EMRS2[7] |
* 5.70 JMK 04/23/09 Updated tRPA definition |
* Increased internal width to 72 bit DQ bus |
* 5.80 SPH 08/12/09 Fixed tRAS maximum violation (only check if bank still open) |
* 5.81 SPH 12/08/09 Only check tIH for cmd_addr if CS# LOW |
* 5.82 SPH 04/08/10 Correct debug message for SRT in EMR2 |
* 5.81 SPH 12/08/09 Only check tIH for cmd_addr if CS# LOW |
* 5.81 SPH 12/08/09 Only check tIH for cmd_addr if CS# LOW |
****************************************************************************************/ |
|
// DO NOT CHANGE THE TIMESCALE |
// MAKE SURE YOUR SIMULATOR USES "PS" RESOLUTION |
`timescale 1ps / 1ps |
|
module ddr2_model ( |
ck, |
ck_n, |
cke, |
cs_n, |
ras_n, |
cas_n, |
we_n, |
dm_rdqs, |
ba, |
addr, |
dq, |
dqs, |
dqs_n, |
rdqs_n, |
odt |
); |
|
`include "ddr2_model_parameters.v" |
|
// text macros |
`define DQ_PER_DQS DQ_BITS/DQS_BITS |
`define BANKS (1<<BA_BITS) |
`define MAX_BITS (BA_BITS+ROW_BITS+COL_BITS-BL_BITS) |
`define MAX_SIZE (1<<(BA_BITS+ROW_BITS+COL_BITS-BL_BITS)) |
`define MEM_SIZE (1<<MEM_BITS) |
`define MAX_PIPE 2*(AL_MAX + CL_MAX) |
|
// Declare Ports |
input ck; |
input ck_n; |
input cke; |
input cs_n; |
input ras_n; |
input cas_n; |
input we_n; |
inout [DM_BITS-1:0] dm_rdqs; |
input [BA_BITS-1:0] ba; |
input [ADDR_BITS-1:0] addr; |
inout [DQ_BITS-1:0] dq; |
inout [DQS_BITS-1:0] dqs; |
inout [DQS_BITS-1:0] dqs_n; |
output [DQS_BITS-1:0] rdqs_n; |
input odt; |
|
// clock jitter |
real tck_avg; |
time tck_sample [TDLLK-1:0]; |
time tch_sample [TDLLK-1:0]; |
time tcl_sample [TDLLK-1:0]; |
time tck_i; |
time tch_i; |
time tcl_i; |
real tch_avg; |
real tcl_avg; |
time tm_ck_pos; |
time tm_ck_neg; |
real tjit_per_rtime; |
integer tjit_cc_time; |
real terr_nper_rtime; |
|
// clock skew |
real out_delay; |
integer dqsck [DQS_BITS-1:0]; |
integer dqsck_min; |
integer dqsck_max; |
integer dqsq_min; |
integer dqsq_max; |
integer seed; |
|
// Mode Registers |
reg burst_order; |
reg [BL_BITS:0] burst_length; |
integer cas_latency; |
integer additive_latency; |
reg dll_reset; |
reg dll_locked; |
reg dll_en; |
integer write_recovery; |
reg low_power; |
reg [1:0] odt_rtt; |
reg odt_en; |
reg [2:0] ocd; |
reg dqs_n_en; |
reg rdqs_en; |
reg out_en; |
integer read_latency; |
integer write_latency; |
|
// cmd encoding |
parameter |
LOAD_MODE = 4'b0000, |
REFRESH = 4'b0001, |
PRECHARGE = 4'b0010, |
ACTIVATE = 4'b0011, |
WRITE = 4'b0100, |
READ = 4'b0101, |
NOP = 4'b0111, |
PWR_DOWN = 4'b1000, |
SELF_REF = 4'b1001 |
; |
|
reg [8*9-1:0] cmd_string [9:0]; |
initial begin |
cmd_string[LOAD_MODE] = "Load Mode"; |
cmd_string[REFRESH ] = "Refresh "; |
cmd_string[PRECHARGE] = "Precharge"; |
cmd_string[ACTIVATE ] = "Activate "; |
cmd_string[WRITE ] = "Write "; |
cmd_string[READ ] = "Read "; |
cmd_string[NOP ] = "No Op "; |
cmd_string[PWR_DOWN ] = "Pwr Down "; |
cmd_string[SELF_REF ] = "Self Ref "; |
end |
|
// command state |
reg [`BANKS-1:0] active_bank; |
reg [`BANKS-1:0] auto_precharge_bank; |
reg [`BANKS-1:0] write_precharge_bank; |
reg [`BANKS-1:0] read_precharge_bank; |
reg [ROW_BITS-1:0] active_row [`BANKS-1:0]; |
reg in_power_down; |
reg in_self_refresh; |
reg [3:0] init_mode_reg; |
reg init_done; |
integer init_step; |
reg er_trfc_max; |
reg odt_state; |
reg prev_odt; |
|
// cmd timers/counters |
integer ref_cntr; |
integer ck_cntr; |
integer ck_load_mode; |
integer ck_write; |
integer ck_read; |
integer ck_write_ap; |
integer ck_power_down; |
integer ck_slow_exit_pd; |
integer ck_self_refresh; |
integer ck_cke; |
integer ck_odt; |
integer ck_dll_reset; |
integer ck_bank_write [`BANKS-1:0]; |
integer ck_bank_read [`BANKS-1:0]; |
time tm_refresh; |
time tm_precharge; |
time tm_precharge_all; |
time tm_activate; |
time tm_write_end; |
time tm_self_refresh; |
time tm_odt_en; |
time tm_bank_precharge [`BANKS-1:0]; |
time tm_bank_activate [`BANKS-1:0]; |
time tm_bank_write_end [`BANKS-1:0]; |
time tm_bank_read_end [`BANKS-1:0]; |
|
// pipelines |
reg [`MAX_PIPE:0] al_pipeline; |
reg [`MAX_PIPE:0] wr_pipeline; |
reg [`MAX_PIPE:0] rd_pipeline; |
reg [`MAX_PIPE:0] odt_pipeline; |
reg [BA_BITS-1:0] ba_pipeline [`MAX_PIPE:0]; |
reg [ROW_BITS-1:0] row_pipeline [`MAX_PIPE:0]; |
reg [COL_BITS-1:0] col_pipeline [`MAX_PIPE:0]; |
reg prev_cke; |
|
// data state |
reg [BL_MAX*DQ_BITS-1:0] memory_data; |
reg [BL_MAX*DQ_BITS-1:0] bit_mask; |
reg [BL_BITS-1:0] burst_position; |
reg [BL_BITS:0] burst_cntr; |
reg [DQ_BITS-1:0] dq_temp; |
reg [35:0] check_write_postamble; |
reg [35:0] check_write_preamble; |
reg [35:0] check_write_dqs_high; |
reg [35:0] check_write_dqs_low; |
reg [17:0] check_dm_tdipw; |
reg [71:0] check_dq_tdipw; |
|
// data timers/counters |
time tm_cke; |
time tm_odt; |
time tm_tdqss; |
time tm_dm [17:0]; |
time tm_dqs [17:0]; |
time tm_dqs_pos [35:0]; |
time tm_dqss_pos [35:0]; |
time tm_dqs_neg [35:0]; |
time tm_dq [71:0]; |
time tm_cmd_addr [22:0]; |
reg [8*7-1:0] cmd_addr_string [22:0]; |
initial begin |
cmd_addr_string[ 0] = "CS_N "; |
cmd_addr_string[ 1] = "RAS_N "; |
cmd_addr_string[ 2] = "CAS_N "; |
cmd_addr_string[ 3] = "WE_N "; |
cmd_addr_string[ 4] = "BA 0 "; |
cmd_addr_string[ 5] = "BA 1 "; |
cmd_addr_string[ 6] = "BA 2 "; |
cmd_addr_string[ 7] = "ADDR 0"; |
cmd_addr_string[ 8] = "ADDR 1"; |
cmd_addr_string[ 9] = "ADDR 2"; |
cmd_addr_string[10] = "ADDR 3"; |
cmd_addr_string[11] = "ADDR 4"; |
cmd_addr_string[12] = "ADDR 5"; |
cmd_addr_string[13] = "ADDR 6"; |
cmd_addr_string[14] = "ADDR 7"; |
cmd_addr_string[15] = "ADDR 8"; |
cmd_addr_string[16] = "ADDR 9"; |
cmd_addr_string[17] = "ADDR 10"; |
cmd_addr_string[18] = "ADDR 11"; |
cmd_addr_string[19] = "ADDR 12"; |
cmd_addr_string[20] = "ADDR 13"; |
cmd_addr_string[21] = "ADDR 14"; |
cmd_addr_string[22] = "ADDR 15"; |
end |
|
reg [8*5-1:0] dqs_string [1:0]; |
initial begin |
dqs_string[0] = "DQS "; |
dqs_string[1] = "DQS_N"; |
end |
|
// Memory Storage |
`ifdef MAX_MEM |
reg [BL_MAX*DQ_BITS-1:0] memory [0:`MAX_SIZE-1]; |
`else |
reg [BL_MAX*DQ_BITS-1:0] memory [0:`MEM_SIZE-1]; |
reg [`MAX_BITS-1:0] address [0:`MEM_SIZE-1]; |
reg [MEM_BITS:0] memory_index; |
reg [MEM_BITS:0] memory_used; |
`endif |
|
// receive |
reg ck_in; |
reg ck_n_in; |
reg cke_in; |
reg cs_n_in; |
reg ras_n_in; |
reg cas_n_in; |
reg we_n_in; |
reg [17:0] dm_in; |
reg [2:0] ba_in; |
reg [15:0] addr_in; |
reg [71:0] dq_in; |
reg [35:0] dqs_in; |
reg odt_in; |
|
reg [17:0] dm_in_pos; |
reg [17:0] dm_in_neg; |
reg [71:0] dq_in_pos; |
reg [71:0] dq_in_neg; |
reg dq_in_valid; |
reg dqs_in_valid; |
integer wdqs_cntr; |
integer wdq_cntr; |
integer wdqs_pos_cntr [35:0]; |
reg b2b_write; |
reg [35:0] prev_dqs_in; |
reg diff_ck; |
|
always @(ck ) ck_in <= #BUS_DELAY ck; |
always @(ck_n ) ck_n_in <= #BUS_DELAY ck_n; |
always @(cke ) cke_in <= #BUS_DELAY cke; |
always @(cs_n ) cs_n_in <= #BUS_DELAY cs_n; |
always @(ras_n ) ras_n_in <= #BUS_DELAY ras_n; |
always @(cas_n ) cas_n_in <= #BUS_DELAY cas_n; |
always @(we_n ) we_n_in <= #BUS_DELAY we_n; |
always @(dm_rdqs) dm_in <= #BUS_DELAY dm_rdqs; |
always @(ba ) ba_in <= #BUS_DELAY ba; |
always @(addr ) addr_in <= #BUS_DELAY addr; |
always @(dq ) dq_in <= #BUS_DELAY dq; |
always @(dqs or dqs_n) dqs_in <= #BUS_DELAY (dqs_n<<18) | dqs; |
always @(odt ) odt_in <= #BUS_DELAY odt; |
// create internal clock |
always @(posedge ck_in) diff_ck <= ck_in; |
always @(posedge ck_n_in) diff_ck <= ~ck_n_in; |
|
wire [17:0] dqs_even = dqs_in[17:0]; |
wire [17:0] dqs_odd = dqs_n_en ? dqs_in[35:18] : ~dqs_in[17:0]; |
wire [3:0] cmd_n_in = !cs_n_in ? {ras_n_in, cas_n_in, we_n_in} : NOP; //deselect = nop |
|
// transmit |
reg dqs_out_en; |
reg [DQS_BITS-1:0] dqs_out_en_dly; |
reg dqs_out; |
reg [DQS_BITS-1:0] dqs_out_dly; |
reg dq_out_en; |
reg [DQ_BITS-1:0] dq_out_en_dly; |
reg [DQ_BITS-1:0] dq_out; |
reg [DQ_BITS-1:0] dq_out_dly; |
integer rdqsen_cntr; |
integer rdqs_cntr; |
integer rdqen_cntr; |
integer rdq_cntr; |
|
bufif1 buf_dqs [DQS_BITS-1:0] (dqs, dqs_out_dly, dqs_out_en_dly & {DQS_BITS{out_en}}); |
bufif1 buf_dm [DM_BITS-1:0] (dm_rdqs, dqs_out_dly, dqs_out_en_dly & {DM_BITS {out_en}} & {DM_BITS{rdqs_en}}); |
bufif1 buf_dqs_n [DQS_BITS-1:0] (dqs_n, ~dqs_out_dly, dqs_out_en_dly & {DQS_BITS{out_en}} & {DQS_BITS{dqs_n_en}}); |
bufif1 buf_rdqs_n [DQS_BITS-1:0] (rdqs_n, ~dqs_out_dly, dqs_out_en_dly & {DQS_BITS{out_en}} & {DQS_BITS{dqs_n_en}} & {DQS_BITS{rdqs_en}}); |
bufif1 buf_dq [DQ_BITS-1:0] (dq, dq_out_dly, dq_out_en_dly & {DQ_BITS {out_en}}); |
|
initial begin |
if (BL_MAX < 2) |
$display("%m ERROR: BL_MAX parameter must be >= 2. \nBL_MAX = %d", BL_MAX); |
if ((1<<BO_BITS) > BL_MAX) |
$display("%m ERROR: 2^BO_BITS cannot be greater than BL_MAX parameter."); |
$timeformat (-12, 1, " ps", 1); |
reset_task; |
seed = RANDOM_SEED; |
ck_cntr = 0; |
end |
|
// calculate the absolute value of a real number |
function real abs_value; |
input arg; |
real arg; |
begin |
if (arg < 0.0) |
abs_value = -1.0 * arg; |
else |
abs_value = arg; |
end |
endfunction |
|
`ifdef MAX_MEM |
`else |
function get_index; |
input [`MAX_BITS-1:0] addr; |
begin : index |
get_index = 0; |
for (memory_index=0; memory_index<memory_used; memory_index=memory_index+1) begin |
if (address[memory_index] == addr) begin |
get_index = 1; |
disable index; |
end |
end |
end |
endfunction |
`endif |
|
task memory_write; |
input [BA_BITS-1:0] bank; |
input [ROW_BITS-1:0] row; |
input [COL_BITS-1:0] col; |
input [BL_MAX*DQ_BITS-1:0] data; |
reg [`MAX_BITS-1:0] addr; |
begin |
// chop off the lowest address bits |
addr = {bank, row, col}/BL_MAX; |
`ifdef MAX_MEM |
memory[addr] = data; |
`else |
if (get_index(addr)) begin |
address[memory_index] = addr; |
memory[memory_index] = data; |
end else if (memory_used == `MEM_SIZE) begin |
$display ("%m: at time %t ERROR: Memory overflow. Write to Address %h with Data %h will be lost.\nYou must increase the MEM_BITS parameter or define MAX_MEM.", $time, addr, data); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
address[memory_used] = addr; |
memory[memory_used] = data; |
memory_used = memory_used + 1; |
end |
`endif |
end |
endtask |
|
task memory_read; |
input [BA_BITS-1:0] bank; |
input [ROW_BITS-1:0] row; |
input [COL_BITS-1:0] col; |
output [BL_MAX*DQ_BITS-1:0] data; |
reg [`MAX_BITS-1:0] addr; |
begin |
// chop off the lowest address bits |
addr = {bank, row, col}/BL_MAX; |
`ifdef MAX_MEM |
data = memory[addr]; |
`else |
if (get_index(addr)) begin |
data = memory[memory_index]; |
end else begin |
data = {BL_MAX*DQ_BITS{1'bx}}; |
end |
`endif |
end |
endtask |
|
// Before this task runs, the model must be in a valid state for precharge power down. |
// After this task runs, NOP commands must be issued until tRFC has been met |
task initialize; |
input [ADDR_BITS-1:0] mode_reg0; |
input [ADDR_BITS-1:0] mode_reg1; |
input [ADDR_BITS-1:0] mode_reg2; |
input [ADDR_BITS-1:0] mode_reg3; |
begin |
if (DEBUG) $display ("%m: at time %t INFO: Performing Initialization Sequence", $time); |
cmd_task(1, NOP, 'bx, 'bx); |
cmd_task(1, PRECHARGE, 'bx, 1<<AP); // Precharege ALL |
cmd_task(1, LOAD_MODE, 3, mode_reg3); |
cmd_task(1, LOAD_MODE, 2, mode_reg2); |
cmd_task(1, LOAD_MODE, 1, mode_reg1); |
cmd_task(1, LOAD_MODE, 0, mode_reg0 | 'h100); // DLL Reset |
cmd_task(1, PRECHARGE, 'bx, 1<<AP); // Precharege ALL |
cmd_task(1, REFRESH, 'bx, 'bx); |
cmd_task(1, REFRESH, 'bx, 'bx); |
cmd_task(1, LOAD_MODE, 0, mode_reg0); |
cmd_task(1, LOAD_MODE, 1, mode_reg1 | 'h380); // OCD Default |
cmd_task(1, LOAD_MODE, 1, mode_reg1); |
cmd_task(0, NOP, 'bx, 'bx); |
end |
endtask |
|
task reset_task; |
integer i; |
begin |
// disable inputs |
dq_in_valid = 0; |
dqs_in_valid <= 0; |
wdqs_cntr = 0; |
wdq_cntr = 0; |
for (i=0; i<36; i=i+1) begin |
wdqs_pos_cntr[i] <= 0; |
end |
b2b_write <= 0; |
// disable outputs |
out_en = 0; |
dqs_n_en = 0; |
rdqs_en = 0; |
dq_out_en = 0; |
rdq_cntr = 0; |
dqs_out_en = 0; |
rdqs_cntr = 0; |
// disable ODT |
odt_en = 0; |
odt_state = 0; |
// reset bank state |
active_bank = {`BANKS{1'b1}}; |
auto_precharge_bank = 0; |
read_precharge_bank = 0; |
write_precharge_bank = 0; |
// require initialization sequence |
init_done = 0; |
init_step = 0; |
init_mode_reg = 0; |
// reset DLL |
dll_en = 0; |
dll_reset = 0; |
dll_locked = 0; |
ocd = 0; |
// exit power down and self refresh |
in_power_down = 0; |
in_self_refresh = 0; |
// clear pipelines |
al_pipeline = 0; |
wr_pipeline = 0; |
rd_pipeline = 0; |
odt_pipeline = 0; |
// clear memory |
`ifdef MAX_MEM |
for (i=0; i<=`MAX_SIZE; i=i+1) begin //erase memory ... one address at a time |
memory[i] <= 'bx; |
end |
`else |
memory_used <= 0; //erase memory |
`endif |
// clear maximum timing checks |
tm_refresh <= 'bx; |
for (i=0; i<`BANKS; i=i+1) begin |
tm_bank_activate[i] <= 'bx; |
end |
end |
endtask |
|
task chk_err; |
input samebank; |
input [BA_BITS-1:0] bank; |
input [3:0] fromcmd; |
input [3:0] cmd; |
reg err; |
begin |
// all matching case expressions will be evaluated |
casex ({samebank, fromcmd, cmd}) |
{1'b0, LOAD_MODE, 4'b0xxx } : begin if (ck_cntr - ck_load_mode < TMRD) $display ("%m: at time %t ERROR: tMRD violation during %s", $time, cmd_string[cmd]); end |
{1'b0, LOAD_MODE, 4'b100x } : begin if (ck_cntr - ck_load_mode < TMRD) begin $display ("%m: at time %t INFO: Load Mode to Reset condition.", $time); init_done = 0; end end |
{1'b0, REFRESH , 4'b0xxx } : begin if ($time - tm_refresh < TRFC_MIN) $display ("%m: at time %t ERROR: tRFC violation during %s", $time, cmd_string[cmd]); end |
{1'b0, REFRESH , PWR_DOWN } : ; // 1 tCK |
{1'b0, REFRESH , SELF_REF } : begin if ($time - tm_refresh < TRFC_MIN) begin $display ("%m: at time %t INFO: Refresh to Reset condition", $time); init_done = 0; end end |
{1'b0, PRECHARGE, 4'b000x } : begin if ($time - tm_precharge_all < TRPA) $display ("%m: at time %t ERROR: tRPA violation during %s", $time, cmd_string[cmd]); |
if ($time - tm_precharge < TRP) $display ("%m: at time %t ERROR: tRP violation during %s", $time, cmd_string[cmd]); end |
{1'b1, PRECHARGE, PRECHARGE} : begin if (DEBUG && ($time - tm_precharge_all < TRPA)) $display ("%m: at time %t INFO: Precharge All interruption during %s", $time, cmd_string[cmd]); |
if (DEBUG && ($time - tm_bank_precharge[bank] < TRP)) $display ("%m: at time %t INFO: Precharge bank %d interruption during %s", $time, cmd_string[cmd], bank); end |
{1'b1, PRECHARGE, ACTIVATE } : begin if ($time - tm_precharge_all < TRPA) $display ("%m: at time %t ERROR: tRPA violation during %s", $time, cmd_string[cmd]); |
if ($time - tm_bank_precharge[bank] < TRP) $display ("%m: at time %t ERROR: tRP violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b0, PRECHARGE, PWR_DOWN } : ; //1 tCK, can be concurrent with auto precharge |
{1'b0, PRECHARGE, SELF_REF } : begin if (($time - tm_precharge_all < TRPA) || ($time - tm_precharge < TRP)) begin $display ("%m: at time %t INFO: Precharge to Reset condition", $time); init_done = 0; end end |
{1'b0, ACTIVATE , REFRESH } : begin if ($time - tm_activate < TRC) $display ("%m: at time %t ERROR: tRC violation during %s", $time, cmd_string[cmd]); end |
{1'b1, ACTIVATE , PRECHARGE} : begin if (($time - tm_bank_activate[bank] > TRAS_MAX) && (active_bank[bank] === 1'b1)) $display ("%m: at time %t ERROR: tRAS maximum violation during %s to bank %d", $time, cmd_string[cmd], bank); |
if ($time - tm_bank_activate[bank] < TRAS_MIN) $display ("%m: at time %t ERROR: tRAS minimum violation during %s to bank %d", $time, cmd_string[cmd], bank);end |
{1'b0, ACTIVATE , ACTIVATE } : begin if ($time - tm_activate < TRRD) $display ("%m: at time %t ERROR: tRRD violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b1, ACTIVATE , ACTIVATE } : begin if ($time - tm_bank_activate[bank] < TRC) $display ("%m: at time %t ERROR: tRC violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b1, ACTIVATE , 4'b010x } : ; // tRCD is checked outside this task |
{1'b1, ACTIVATE , PWR_DOWN } : ; // 1 tCK |
{1'b1, WRITE , PRECHARGE} : begin if ((ck_cntr - ck_bank_write[bank] <= write_latency + burst_length/2) || ($time - tm_bank_write_end[bank] < TWR)) $display ("%m: at time %t ERROR: tWR violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b0, WRITE , WRITE } : begin if (ck_cntr - ck_write < TCCD) $display ("%m: at time %t ERROR: tCCD violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b0, WRITE , READ } : begin if ((ck_load_mode < ck_write) && (ck_cntr - ck_write < write_latency + burst_length/2 + 2 - additive_latency)) $display ("%m: at time %t ERROR: tWTR violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b0, WRITE , PWR_DOWN } : begin if ((ck_load_mode < ck_write) && ( |
|write_precharge_bank |
|| (ck_cntr - ck_write_ap < 1) |
|| (ck_cntr - ck_write < write_latency + burst_length/2 + 2) |
|| ($time - tm_write_end < TWTR))) begin $display ("%m: at time %t INFO: Write to Reset condition", $time); init_done = 0; end end |
{1'b1, READ , PRECHARGE} : begin if ((ck_cntr - ck_bank_read[bank] < additive_latency + burst_length/2) || ($time - tm_bank_read_end[bank] < TRTP)) $display ("%m: at time %t ERROR: tRTP violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b0, READ , WRITE } : begin if ((ck_load_mode < ck_read) && (ck_cntr - ck_read < read_latency + burst_length/2 + 1 - write_latency)) $display ("%m: at time %t ERROR: tRTW violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b0, READ , READ } : begin if (ck_cntr - ck_read < TCCD) $display ("%m: at time %t ERROR: tCCD violation during %s to bank %d", $time, cmd_string[cmd], bank); end |
{1'b0, READ , PWR_DOWN } : begin if ((ck_load_mode < ck_read) && (ck_cntr - ck_read < read_latency + burst_length/2 + 1)) begin $display ("%m: at time %t INFO: Read to Reset condition", $time); init_done = 0; end end |
{1'b0, PWR_DOWN , 4'b00xx } : begin if (ck_cntr - ck_power_down < TXP) $display ("%m: at time %t ERROR: tXP violation during %s", $time, cmd_string[cmd]); end |
{1'b0, PWR_DOWN , WRITE } : begin if (ck_cntr - ck_power_down < TXP) $display ("%m: at time %t ERROR: tXP violation during %s", $time, cmd_string[cmd]); end |
{1'b0, PWR_DOWN , READ } : begin if (ck_cntr - ck_slow_exit_pd < TXARDS - additive_latency) $display ("%m: at time %t ERROR: tXARDS violation during %s", $time, cmd_string[cmd]); |
else if (ck_cntr - ck_power_down < TXARD) $display ("%m: at time %t ERROR: tXARD violation during %s", $time, cmd_string[cmd]); end |
{1'b0, SELF_REF , 4'b00xx } : begin if ($time - tm_self_refresh < TXSNR) $display ("%m: at time %t ERROR: tXSNR violation during %s", $time, cmd_string[cmd]); end |
{1'b0, SELF_REF , WRITE } : begin if ($time - tm_self_refresh < TXSNR) $display ("%m: at time %t ERROR: tXSNR violation during %s", $time, cmd_string[cmd]); end |
{1'b0, SELF_REF , READ } : begin if (ck_cntr - ck_self_refresh < TXSRD) $display ("%m: at time %t ERROR: tXSRD violation during %s", $time, cmd_string[cmd]); end |
{1'b0, 4'b100x , 4'b100x } : begin if (ck_cntr - ck_cke < TCKE) begin $display ("%m: at time %t ERROR: tCKE violation on CKE", $time); init_done = 0; end end |
endcase |
end |
endtask |
|
task cmd_task; |
input cke; |
input [2:0] cmd; |
input [BA_BITS-1:0] bank; |
input [ADDR_BITS-1:0] addr; |
reg [`BANKS:0] i; |
integer j; |
reg [`BANKS:0] tfaw_cntr; |
reg [COL_BITS-1:0] col; |
begin |
|
// tRFC max check |
if (!er_trfc_max && !in_self_refresh) begin |
if ($time - tm_refresh > TRFC_MAX) begin |
$display ("%m: at time %t ERROR: tRFC maximum violation during %s", $time, cmd_string[cmd]); |
er_trfc_max = 1; |
end |
end |
if (cke) begin |
if ((cmd < NOP) && ((cmd != PRECHARGE) || !addr[AP])) begin |
for (j=0; j<NOP; j=j+1) begin |
chk_err(1'b0, bank, j, cmd); |
chk_err(1'b1, bank, j, cmd); |
end |
chk_err(1'b0, bank, PWR_DOWN, cmd); |
chk_err(1'b0, bank, SELF_REF, cmd); |
end |
|
case (cmd) |
LOAD_MODE : begin |
if (|active_bank) begin |
$display ("%m: at time %t ERROR: %s Failure. All banks must be Precharged.", $time, cmd_string[cmd]); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d", $time, cmd_string[cmd], bank); |
case (bank) |
0 : begin |
// Burst Length |
burst_length = 1<<addr[2:0]; |
if ((burst_length >= BL_MIN) && (burst_length <= BL_MAX)) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Length = %d", $time, cmd_string[cmd], bank, burst_length); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal Burst Length = %d", $time, cmd_string[cmd], bank, burst_length); |
end |
// Burst Order |
burst_order = addr[3]; |
if (!burst_order) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Order = Sequential", $time, cmd_string[cmd], bank); |
end else if (burst_order) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Burst Order = Interleaved", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal Burst Order = %d", $time, cmd_string[cmd], bank, burst_order); |
end |
// CAS Latency |
cas_latency = addr[6:4]; |
read_latency = cas_latency + additive_latency; |
write_latency = read_latency - 1; |
if ((cas_latency >= CL_MIN) && (cas_latency <= CL_MAX)) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d CAS Latency = %d", $time, cmd_string[cmd], bank, cas_latency); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal CAS Latency = %d", $time, cmd_string[cmd], bank, cas_latency); |
end |
// Test Mode |
if (!addr[7]) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Test Mode = Normal", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal Test Mode = %d", $time, cmd_string[cmd], bank, addr[7]); |
end |
// DLL Reset |
dll_reset = addr[8]; |
if (!dll_reset) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Reset = Normal", $time, cmd_string[cmd], bank); |
end else if (dll_reset) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Reset = Reset DLL", $time, cmd_string[cmd], bank); |
dll_locked = 0; |
ck_dll_reset <= ck_cntr; |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal DLL Reset = %d", $time, cmd_string[cmd], bank, dll_reset); |
end |
// Write Recovery |
write_recovery = addr[11:9] + 1; |
if ((write_recovery >= WR_MIN) && (write_recovery <= WR_MAX)) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Write Recovery = %d", $time, cmd_string[cmd], bank, write_recovery); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal Write Recovery = %d", $time, cmd_string[cmd], bank, write_recovery); |
end |
// Power Down Mode |
low_power = addr[12]; |
if (!low_power) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Power Down Mode = Fast Exit", $time, cmd_string[cmd], bank); |
end else if (low_power) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Power Down Mode = Slow Exit", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal Power Down Mode = %d", $time, cmd_string[cmd], bank, low_power); |
end |
end |
1 : begin |
// DLL Enable |
dll_en = !addr[0]; |
if (!dll_en) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Enable = Disabled", $time, cmd_string[cmd], bank); |
end else if (dll_en) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d DLL Enable = Enabled", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal DLL Enable = %d", $time, cmd_string[cmd], bank, dll_en); |
end |
// Output Drive Strength |
if (!addr[1]) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Drive Strength = Full", $time, cmd_string[cmd], bank); |
end else if (addr[1]) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Drive Strength = Reduced", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal Output Drive Strength = %d", $time, cmd_string[cmd], bank, addr[1]); |
end |
// ODT Rtt |
odt_rtt = {addr[6], addr[2]}; |
if (odt_rtt == 2'b00) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = Disabled", $time, cmd_string[cmd], bank); |
odt_en = 0; |
end else if (odt_rtt == 2'b01) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 75 Ohm", $time, cmd_string[cmd], bank); |
odt_en = 1; |
tm_odt_en <= $time; |
end else if (odt_rtt == 2'b10) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 150 Ohm", $time, cmd_string[cmd], bank); |
odt_en = 1; |
tm_odt_en <= $time; |
end else if (odt_rtt == 2'b11) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d ODT Rtt = 50 Ohm", $time, cmd_string[cmd], bank); |
odt_en = 1; |
tm_odt_en <= $time; |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal ODT Rtt = %d", $time, cmd_string[cmd], bank, odt_rtt); |
odt_en = 0; |
end |
// Additive Latency |
additive_latency = addr[5:3]; |
read_latency = cas_latency + additive_latency; |
write_latency = read_latency - 1; |
if ((additive_latency >= AL_MIN) && (additive_latency <= AL_MAX)) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Additive Latency = %d", $time, cmd_string[cmd], bank, additive_latency); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal Additive Latency = %d", $time, cmd_string[cmd], bank, additive_latency); |
end |
// OCD Program |
ocd = addr[9:7]; |
if (ocd == 3'b000) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d OCD Program = OCD Exit", $time, cmd_string[cmd], bank); |
end else if (ocd == 3'b111) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d OCD Program = OCD Default", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal OCD Program = %b", $time, cmd_string[cmd], bank, ocd); |
end |
|
// DQS_N Enable |
dqs_n_en = !addr[10]; |
if (!dqs_n_en) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d DQS_N Enable = Disabled", $time, cmd_string[cmd], bank); |
end else if (dqs_n_en) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d DQS_N Enable = Enabled", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal DQS_N Enable = %d", $time, cmd_string[cmd], bank, dqs_n_en); |
end |
// RDQS Enable |
rdqs_en = addr[11]; |
if (!rdqs_en) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d RDQS Enable = Disabled", $time, cmd_string[cmd], bank); |
end else if (rdqs_en) begin |
`ifdef x8 |
if (DEBUG) $display ("%m: at time %t INFO: %s %d RDQS Enable = Enabled", $time, cmd_string[cmd], bank); |
`else |
$display ("%m: at time %t WARNING: %s %d Illegal RDQS Enable. RDQS only exists on a x8 part", $time, cmd_string[cmd], bank); |
rdqs_en = 0; |
`endif |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal RDQS Enable = %d", $time, cmd_string[cmd], bank, rdqs_en); |
end |
// Output Enable |
out_en = !addr[12]; |
if (!out_en) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Enable = Disabled", $time, cmd_string[cmd], bank); |
end else if (out_en) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d Output Enable = Enabled", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal Output Enable = %d", $time, cmd_string[cmd], bank, out_en); |
end |
end |
2 : begin |
// High Temperature Self Refresh rate |
if (!addr[7]) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d High Temperature Self Refresh rate = 1X (0C-85C)", $time, cmd_string[cmd], bank); |
end else if (addr[7]) begin |
if (DEBUG) $display ("%m: at time %t INFO: %s %d High Temperature Self Refresh rate = 2X (>85C)", $time, cmd_string[cmd], bank); |
end else begin |
$display ("%m: at time %t ERROR: %s %d Illegal High Temperature Self Refresh rate = %d", $time, cmd_string[cmd], bank, addr[7]); |
end |
if ((addr & ~(1<<7)) !== 0) begin |
$display ("%m: at time %t ERROR: %s %d Illegal value. Reserved bits must be programmed to zero", $time, cmd_string[cmd], bank); |
end |
end |
3 : begin |
if (addr !== 0) begin |
$display ("%m: at time %t ERROR: %s %d Illegal value. Reserved bits must be programmed to zero", $time, cmd_string[cmd], bank); |
end |
end |
endcase |
init_mode_reg[bank] = 1; |
ck_load_mode <= ck_cntr; |
end |
end |
REFRESH : begin |
if (|active_bank) begin |
$display ("%m: at time %t ERROR: %s Failure. All banks must be Precharged.", $time, cmd_string[cmd]); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (DEBUG) $display ("%m: at time %t INFO: %s", $time, cmd_string[cmd]); |
er_trfc_max = 0; |
ref_cntr = ref_cntr + 1; |
tm_refresh <= $time; |
end |
end |
PRECHARGE : begin |
if (addr[AP]) begin |
// tRPA timing applies when the PRECHARGE (ALL) command is issued, regardless of |
// the number of banks already open or closed. |
for (i=0; i<`BANKS; i=i+1) begin |
for (j=0; j<NOP; j=j+1) begin |
chk_err(1'b0, i, j, cmd); |
chk_err(1'b1, i, j, cmd); |
end |
chk_err(1'b0, i, PWR_DOWN, cmd); |
chk_err(1'b0, i, SELF_REF, cmd); |
end |
if (|auto_precharge_bank) begin |
$display ("%m: at time %t ERROR: %s All Failure. Auto Precharge is scheduled.", $time, cmd_string[cmd]); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (DEBUG) $display ("%m: at time %t INFO: %s All", $time, cmd_string[cmd]); |
active_bank = 0; |
tm_precharge_all <= $time; |
end |
end else begin |
// A PRECHARGE command is allowed if there is no open row in that bank (idle state) |
// or if the previously open row is already in the process of precharging. |
// However, the precharge period will be determined by the last PRECHARGE command issued to the bank. |
if (auto_precharge_bank[bank]) begin |
$display ("%m: at time %t ERROR: %s Failure. Auto Precharge is scheduled to bank %d.", $time, cmd_string[cmd], bank); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (DEBUG) $display ("%m: at time %t INFO: %s bank %d", $time, cmd_string[cmd], bank); |
active_bank[bank] = 1'b0; |
tm_bank_precharge[bank] <= $time; |
tm_precharge <= $time; |
end |
end |
end |
ACTIVATE : begin |
if (`BANKS == 8) begin |
tfaw_cntr = 0; |
for (i=0; i<`BANKS; i=i+1) begin |
if ($time - tm_bank_activate[i] < TFAW) begin |
tfaw_cntr = tfaw_cntr + 1; |
end |
end |
if (tfaw_cntr > 3) begin |
$display ("%m: at time %t ERROR: tFAW violation during %s to bank %d", $time, cmd_string[cmd], bank); |
end |
end |
|
if (!init_done) begin |
$display ("%m: at time %t ERROR: %s Failure. Initialization sequence is not complete.", $time, cmd_string[cmd]); |
if (STOP_ON_ERROR) $stop(0); |
end else if (active_bank[bank]) begin |
$display ("%m: at time %t ERROR: %s Failure. Bank %d must be Precharged.", $time, cmd_string[cmd], bank); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (addr >= 1<<ROW_BITS) begin |
$display ("%m: at time %t WARNING: row = %h does not exist. Maximum row = %h", $time, addr, (1<<ROW_BITS)-1); |
end |
if (DEBUG) $display ("%m: at time %t INFO: %s bank %d row %h", $time, cmd_string[cmd], bank, addr); |
active_bank[bank] = 1'b1; |
active_row[bank] = addr; |
tm_bank_activate[bank] <= $time; |
tm_activate <= $time; |
end |
|
end |
WRITE : begin |
if (!init_done) begin |
$display ("%m: at time %t ERROR: %s Failure. Initialization sequence is not complete.", $time, cmd_string[cmd]); |
if (STOP_ON_ERROR) $stop(0); |
end else if (!active_bank[bank]) begin |
$display ("%m: at time %t ERROR: %s Failure. Bank %d must be Activated.", $time, cmd_string[cmd], bank); |
if (STOP_ON_ERROR) $stop(0); |
end else if (auto_precharge_bank[bank]) begin |
$display ("%m: at time %t ERROR: %s Failure. Auto Precharge is scheduled to bank %d.", $time, cmd_string[cmd], bank); |
if (STOP_ON_ERROR) $stop(0); |
end else if ((ck_cntr - ck_write < burst_length/2) && (ck_cntr - ck_write)%2) begin |
$display ("%m: at time %t ERROR: %s Failure. Illegal burst interruption.", $time, cmd_string[cmd]); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (addr[AP]) begin |
auto_precharge_bank[bank] = 1'b1; |
write_precharge_bank[bank] = 1'b1; |
end |
col = ((addr>>1) & -1*(1<<AP)) | (addr & {AP{1'b1}}); |
if (col >= 1<<COL_BITS) begin |
$display ("%m: at time %t WARNING: col = %h does not exist. Maximum col = %h", $time, col, (1<<COL_BITS)-1); |
end |
if (DEBUG) $display ("%m: at time %t INFO: %s bank %d col %h, auto precharge %d", $time, cmd_string[cmd], bank, col, addr[AP]); |
wr_pipeline[2*write_latency + 1] = 1; |
ba_pipeline[2*write_latency + 1] = bank; |
row_pipeline[2*write_latency + 1] = active_row[bank]; |
col_pipeline[2*write_latency + 1] = col; |
ck_bank_write[bank] <= ck_cntr; |
ck_write <= ck_cntr; |
end |
end |
READ : begin |
if (!dll_locked) |
$display ("%m: at time %t WARNING: %s prior to DLL locked. Failing to wait for synchronization to occur may result in a violation of the tAC or tDQSCK parameters.", $time, cmd_string[cmd]); |
if (!init_done) begin |
$display ("%m: at time %t ERROR: %s Failure. Initialization sequence is not complete.", $time, cmd_string[cmd]); |
if (STOP_ON_ERROR) $stop(0); |
end else if (!active_bank[bank]) begin |
$display ("%m: at time %t ERROR: %s Failure. Bank %d must be Activated.", $time, cmd_string[cmd], bank); |
if (STOP_ON_ERROR) $stop(0); |
end else if (auto_precharge_bank[bank]) begin |
$display ("%m: at time %t ERROR: %s Failure. Auto Precharge is scheduled to bank %d.", $time, cmd_string[cmd], bank); |
if (STOP_ON_ERROR) $stop(0); |
end else if ((ck_cntr - ck_read < burst_length/2) && (ck_cntr - ck_read)%2) begin |
$display ("%m: at time %t ERROR: %s Failure. Illegal burst interruption.", $time, cmd_string[cmd]); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (addr[AP]) begin |
auto_precharge_bank[bank] = 1'b1; |
read_precharge_bank[bank] = 1'b1; |
end |
col = ((addr>>1) & -1*(1<<AP)) | (addr & {AP{1'b1}}); |
if (col >= 1<<COL_BITS) begin |
$display ("%m: at time %t WARNING: col = %h does not exist. Maximum col = %h", $time, col, (1<<COL_BITS)-1); |
end |
if (DEBUG) $display ("%m: at time %t INFO: %s bank %d col %h, auto precharge %d", $time, cmd_string[cmd], bank, col, addr[AP]); |
rd_pipeline[2*read_latency - 1] = 1; |
ba_pipeline[2*read_latency - 1] = bank; |
row_pipeline[2*read_latency - 1] = active_row[bank]; |
col_pipeline[2*read_latency - 1] = col; |
ck_bank_read[bank] <= ck_cntr; |
ck_read <= ck_cntr; |
end |
end |
NOP: begin |
if (in_power_down) begin |
if (DEBUG) $display ("%m: at time %t INFO: Power Down Exit", $time); |
in_power_down = 0; |
if (|active_bank & low_power) begin // slow exit active power down |
ck_slow_exit_pd <= ck_cntr; |
end |
ck_power_down <= ck_cntr; |
end |
if (in_self_refresh) begin |
if ($time - tm_cke < TISXR) |
$display ("%m: at time %t ERROR: tISXR violation during Self Refresh Exit", $time); |
if (DEBUG) $display ("%m: at time %t INFO: Self Refresh Exit", $time); |
in_self_refresh = 0; |
ck_dll_reset <= ck_cntr; |
ck_self_refresh <= ck_cntr; |
tm_self_refresh <= $time; |
tm_refresh <= $time; |
end |
end |
endcase |
if ((prev_cke !== 1) && (cmd !== NOP)) begin |
$display ("%m: at time %t ERROR: NOP or Deselect is required when CKE goes active.", $time); |
end |
if (!init_done) begin |
case (init_step) |
0 : begin |
if ($time < 200000000) |
$display ("%m: at time %t WARNING: 200 us is required before CKE goes active.", $time); |
// if (cmd_chk + 200000000 > $time) |
// $display("%m: at time %t WARNING: NOP or DESELECT is required for 200 us before CKE is brought high", $time); |
init_step = init_step + 1; |
end |
1 : if (dll_en) init_step = init_step + 1; |
2 : begin |
if (&init_mode_reg && dll_reset) begin |
active_bank = {`BANKS{1'b1}}; // require Precharge All or bank Precharges |
ref_cntr = 0; // require refresh |
init_step = init_step + 1; |
end |
end |
3 : if (ref_cntr == 2) begin |
init_step = init_step + 1; |
end |
4 : if (!dll_reset) init_step = init_step + 1; |
5 : if (ocd == 3'b111) init_step = init_step + 1; |
6 : begin |
if (ocd == 3'b000) begin |
if (DEBUG) $display ("%m: at time %t INFO: Initialization Sequence is complete", $time); |
init_done = 1; |
end |
end |
endcase |
end |
end else if (prev_cke) begin |
if ((!init_done) && (init_step > 1)) begin |
$display ("%m: at time %t ERROR: CKE must remain active until the initialization sequence is complete.", $time); |
if (STOP_ON_ERROR) $stop(0); |
end |
case (cmd) |
REFRESH : begin |
for (j=0; j<NOP; j=j+1) begin |
chk_err(1'b0, bank, j, SELF_REF); |
end |
chk_err(1'b0, bank, PWR_DOWN, SELF_REF); |
chk_err(1'b0, bank, SELF_REF, SELF_REF); |
if (|active_bank) begin |
$display ("%m: at time %t ERROR: Self Refresh Failure. All banks must be Precharged.", $time); |
if (STOP_ON_ERROR) $stop(0); |
init_done = 0; |
end else if (odt_en && odt_state) begin |
$display ("%m: at time %t ERROR: ODT must be off prior to entering Self Refresh", $time); |
if (STOP_ON_ERROR) $stop(0); |
init_done = 0; |
end else if (!init_done) begin |
$display ("%m: at time %t ERROR: Self Refresh Failure. Initialization sequence is not complete.", $time); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (DEBUG) $display ("%m: at time %t INFO: Self Refresh Enter", $time); |
in_self_refresh = 1; |
dll_locked = 0; |
end |
end |
NOP : begin |
// entering slow_exit or precharge power down and tANPD has not been satisfied |
if ((low_power || (active_bank == 0)) && (ck_cntr - ck_odt < TANPD)) |
$display ("%m: at time %t WARNING: tANPD violation during %s. Synchronous or asynchronous change in termination resistance is possible.", $time, cmd_string[PWR_DOWN]); |
for (j=0; j<NOP; j=j+1) begin |
chk_err(1'b0, bank, j, PWR_DOWN); |
end |
chk_err(1'b0, bank, PWR_DOWN, PWR_DOWN); |
chk_err(1'b0, bank, SELF_REF, PWR_DOWN); |
|
if (!init_done) begin |
$display ("%m: at time %t ERROR: Power Down Failure. Initialization sequence is not complete.", $time); |
if (STOP_ON_ERROR) $stop(0); |
end else begin |
if (DEBUG) begin |
if (|active_bank) begin |
$display ("%m: at time %t INFO: Active Power Down Enter", $time); |
end else begin |
$display ("%m: at time %t INFO: Precharge Power Down Enter", $time); |
end |
end |
in_power_down = 1; |
end |
end |
default : begin |
$display ("%m: at time %t ERROR: NOP, Deselect, or Refresh is required when CKE goes inactive.", $time); |
init_done = 0; |
end |
endcase |
if (!init_done) begin |
if (DEBUG) $display ("%m: at time %t WARNING: Reset has occurred. Device must be re-initialized.", $time); |
reset_task; |
end |
end |
prev_cke = cke; |
end |
endtask |
|
task data_task; |
reg [BA_BITS-1:0] bank; |
reg [ROW_BITS-1:0] row; |
reg [COL_BITS-1:0] col; |
integer i; |
integer j; |
begin |
|
if (diff_ck) begin |
for (i=0; i<36; i=i+1) begin |
if (dq_in_valid && dll_locked && ($time - tm_dqs_neg[i] < $rtoi(TDSS*tck_avg))) |
$display ("%m: at time %t ERROR: tDSS violation on %s bit %d", $time, dqs_string[i/18], i%18); |
if (check_write_dqs_high[i]) |
$display ("%m: at time %t ERROR: %s bit %d latching edge required during the preceding clock period.", $time, dqs_string[i/18], i%18); |
end |
check_write_dqs_high <= 0; |
end else begin |
for (i=0; i<36; i=i+1) begin |
if (dll_locked && dq_in_valid) begin |
tm_tdqss = abs_value(1.0*tm_ck_pos - tm_dqss_pos[i]); |
if ((tm_tdqss < tck_avg/2.0) && (tm_tdqss > TDQSS*tck_avg)) |
$display ("%m: at time %t ERROR: tDQSS violation on %s bit %d", $time, dqs_string[i/18], i%18); |
end |
if (check_write_dqs_low[i]) |
$display ("%m: at time %t ERROR: %s bit %d latching edge required during the preceding clock period", $time, dqs_string[i/18], i%18); |
end |
check_write_preamble <= 0; |
check_write_postamble <= 0; |
check_write_dqs_low <= 0; |
end |
|
if (wr_pipeline[0] || rd_pipeline[0]) begin |
bank = ba_pipeline[0]; |
row = row_pipeline[0]; |
col = col_pipeline[0]; |
burst_cntr = 0; |
memory_read(bank, row, col, memory_data); |
end |
|
// burst counter |
if (burst_cntr < burst_length) begin |
burst_position = col ^ burst_cntr; |
if (!burst_order) begin |
burst_position[BO_BITS-1:0] = col + burst_cntr; |
end |
burst_cntr = burst_cntr + 1; |
end |
|
// write dqs counter |
if (wr_pipeline[WDQS_PRE + 1]) begin |
wdqs_cntr = WDQS_PRE + burst_length + WDQS_PST - 1; |
end |
// write dqs |
if ((wdqs_cntr == burst_length + WDQS_PST) && (wdq_cntr == 0)) begin //write preamble |
check_write_preamble <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; |
end |
if (wdqs_cntr > 1) begin // write data |
if ((wdqs_cntr - WDQS_PST)%2) begin |
check_write_dqs_high <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; |
end else begin |
check_write_dqs_low <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; |
end |
end |
if (wdqs_cntr == WDQS_PST) begin // write postamble |
check_write_postamble <= ({DQS_BITS{dqs_n_en}}<<18) | {DQS_BITS{1'b1}}; |
end |
if (wdqs_cntr > 0) begin |
wdqs_cntr = wdqs_cntr - 1; |
end |
|
// write dq |
if (dq_in_valid) begin // write data |
bit_mask = 0; |
if (diff_ck) begin |
for (i=0; i<DM_BITS; i=i+1) begin |
bit_mask = bit_mask | ({`DQ_PER_DQS{~dm_in_neg[i]}}<<(burst_position*DQ_BITS + i*`DQ_PER_DQS)); |
end |
memory_data = (dq_in_neg<<(burst_position*DQ_BITS) & bit_mask) | (memory_data & ~bit_mask); |
end else begin |
for (i=0; i<DM_BITS; i=i+1) begin |
bit_mask = bit_mask | ({`DQ_PER_DQS{~dm_in_pos[i]}}<<(burst_position*DQ_BITS + i*`DQ_PER_DQS)); |
end |
memory_data = (dq_in_pos<<(burst_position*DQ_BITS) & bit_mask) | (memory_data & ~bit_mask); |
end |
dq_temp = memory_data>>(burst_position*DQ_BITS); |
if (DEBUG) $display ("%m: at time %t INFO: WRITE @ DQS= bank = %h row = %h col = %h data = %h",$time, bank, row, (-1*BL_MAX & col) + burst_position, dq_temp); |
if (burst_cntr%BL_MIN == 0) begin |
memory_write(bank, row, col, memory_data); |
end |
end |
if (wr_pipeline[1]) begin |
wdq_cntr = burst_length; |
end |
if (wdq_cntr > 0) begin |
wdq_cntr = wdq_cntr - 1; |
dq_in_valid = 1'b1; |
end else begin |
dq_in_valid = 1'b0; |
dqs_in_valid <= 1'b0; |
for (i=0; i<36; i=i+1) begin |
wdqs_pos_cntr[i] <= 0; |
end |
end |
if (wr_pipeline[0]) begin |
b2b_write <= 1'b0; |
end |
if (wr_pipeline[2]) begin |
if (dqs_in_valid) begin |
b2b_write <= 1'b1; |
end |
dqs_in_valid <= 1'b1; |
end |
// read dqs enable counter |
if (rd_pipeline[RDQSEN_PRE]) begin |
rdqsen_cntr = RDQSEN_PRE + burst_length + RDQSEN_PST - 1; |
end |
if (rdqsen_cntr > 0) begin |
rdqsen_cntr = rdqsen_cntr - 1; |
dqs_out_en = 1'b1; |
end else begin |
dqs_out_en = 1'b0; |
end |
|
// read dqs counter |
if (rd_pipeline[RDQS_PRE]) begin |
rdqs_cntr = RDQS_PRE + burst_length + RDQS_PST - 1; |
end |
// read dqs |
if ((rdqs_cntr >= burst_length + RDQS_PST) && (rdq_cntr == 0)) begin //read preamble |
dqs_out = 1'b0; |
end else if (rdqs_cntr > RDQS_PST) begin // read data |
dqs_out = rdqs_cntr - RDQS_PST; |
end else if (rdqs_cntr > 0) begin // read postamble |
dqs_out = 1'b0; |
end else begin |
dqs_out = 1'b1; |
end |
if (rdqs_cntr > 0) begin |
rdqs_cntr = rdqs_cntr - 1; |
end |
|
// read dq enable counter |
if (rd_pipeline[RDQEN_PRE]) begin |
rdqen_cntr = RDQEN_PRE + burst_length + RDQEN_PST; |
end |
if (rdqen_cntr > 0) begin |
rdqen_cntr = rdqen_cntr - 1; |
dq_out_en = 1'b1; |
end else begin |
dq_out_en = 1'b0; |
end |
// read dq |
if (rd_pipeline[0]) begin |
rdq_cntr = burst_length; |
end |
if (rdq_cntr > 0) begin // read data |
dq_temp = memory_data>>(burst_position*DQ_BITS); |
dq_out = dq_temp; |
if (DEBUG) $display ("%m: at time %t INFO: READ @ DQS= bank = %h row = %h col = %h data = %h",$time, bank, row, (-1*BL_MAX & col) + burst_position, dq_temp); |
rdq_cntr = rdq_cntr - 1; |
end else begin |
dq_out = {DQ_BITS{1'b1}}; |
end |
|
// delay signals prior to output |
if (RANDOM_OUT_DELAY && (dqs_out_en || |dqs_out_en_dly || dq_out_en || |dq_out_en_dly)) begin |
for (i=0; i<DQS_BITS; i=i+1) begin |
// DQSCK requirements |
// 1.) less than tDQSCK |
// 2.) greater than -tDQSCK |
// 3.) cannot change more than tQHS + tDQSQ from previous DQS edge |
dqsck_max = TDQSCK; |
if (dqsck_max > dqsck[i] + TQHS + TDQSQ) begin |
dqsck_max = dqsck[i] + TQHS + TDQSQ; |
end |
dqsck_min = -1*TDQSCK; |
if (dqsck_min < dqsck[i] - TQHS - TDQSQ) begin |
dqsck_min = dqsck[i] - TQHS - TDQSQ; |
end |
|
// DQSQ requirements |
// 1.) less than tAC - DQSCK |
// 2.) less than tDQSQ |
// 3.) greater than -tAC |
// 4.) greater than tQH from previous DQS edge |
dqsq_min = -1*TAC; |
if (dqsq_min < dqsck[i] - TQHS) begin |
dqsq_min = dqsck[i] - TQHS; |
end |
if (dqsck_min == dqsck_max) begin |
dqsck[i] = dqsck_min; |
end else begin |
dqsck[i] = $dist_uniform(seed, dqsck_min, dqsck_max); |
end |
dqsq_max = TAC; |
if (dqsq_max > TDQSQ + dqsck[i]) begin |
dqsq_max = TDQSQ + dqsck[i]; |
end |
|
dqs_out_en_dly[i] <= #(tck_avg/2.0 + ($random % TAC)) dqs_out_en; |
dqs_out_dly[i] <= #(tck_avg/2.0 + dqsck[i]) dqs_out; |
for (j=0; j<`DQ_PER_DQS; j=j+1) begin |
if (dq_out_en) begin // tLZ2 |
dq_out_en_dly[i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + $dist_uniform(seed, -2*TAC, dqsq_max)) dq_out_en; |
end else begin // tHZ |
dq_out_en_dly[i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + ($random % TAC)) dq_out_en; |
end |
if (dqsq_min == dqsq_max) begin |
dq_out_dly [i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + dqsq_min) dq_out[i*`DQ_PER_DQS + j]; |
end else begin |
dq_out_dly [i*`DQ_PER_DQS + j] <= #(tck_avg/2.0 + $dist_uniform(seed, dqsq_min, dqsq_max)) dq_out[i*`DQ_PER_DQS + j]; |
end |
end |
end |
end else begin |
out_delay = tck_avg/2.0; |
dqs_out_en_dly <= #(out_delay) {DQS_BITS{dqs_out_en}}; |
dqs_out_dly <= #(out_delay) {DQS_BITS{dqs_out }}; |
dq_out_en_dly <= #(out_delay) {DQ_BITS {dq_out_en }}; |
dq_out_dly <= #(out_delay) {DQ_BITS {dq_out }}; |
end |
end |
endtask |
|
always @(diff_ck) begin : main |
integer i; |
|
if (!in_self_refresh && (diff_ck !== 1'b0) && (diff_ck !== 1'b1)) |
$display ("%m: at time %t ERROR: CK and CK_N are not allowed to go to an unknown state.", $time); |
data_task; |
if (diff_ck) begin |
// check setup of command signals |
if ($time > TIS) begin |
if ($time - tm_cke < TIS) |
$display ("%m: at time %t ERROR: tIS violation on CKE by %t", $time, tm_cke + TIS - $time); |
if (cke_in) begin |
for (i=0; i<22; i=i+1) begin |
if ($time - tm_cmd_addr[i] < TIS) |
$display ("%m: at time %t ERROR: tIS violation on %s by %t", $time, cmd_addr_string[i], tm_cmd_addr[i] + TIS - $time); |
end |
end |
end |
|
// update current state |
if (!dll_locked && !in_self_refresh && (ck_cntr - ck_dll_reset == TDLLK)) begin |
// check CL value against the clock frequency |
if (cas_latency*tck_avg < CL_TIME) |
$display ("%m: at time %t ERROR: CAS Latency = %d is illegal @tCK(avg) = %f", $time, cas_latency, tck_avg); |
// check WR value against the clock frequency |
if (write_recovery*tck_avg < TWR) |
$display ("%m: at time %t ERROR: Write Recovery = %d is illegal @tCK(avg) = %f", $time, write_recovery, tck_avg); |
dll_locked = 1; |
end |
if (|auto_precharge_bank) begin |
for (i=0; i<`BANKS; i=i+1) begin |
// Write with Auto Precharge Calculation |
// 1. Meet minimum tRAS requirement |
// 2. Write Latency PLUS BL/2 cycles PLUS WR after Write command |
if (write_precharge_bank[i] |
&& ($time - tm_bank_activate[i] >= TRAS_MIN) |
&& (ck_cntr - ck_bank_write[i] >= write_latency + burst_length/2 + write_recovery)) begin |
|
if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", $time, i); |
write_precharge_bank[i] = 0; |
active_bank[i] = 0; |
auto_precharge_bank[i] = 0; |
ck_write_ap = ck_cntr; |
tm_bank_precharge[i] = $time; |
tm_precharge = $time; |
end |
// Read with Auto Precharge Calculation |
// 1. Meet minimum tRAS requirement |
// 2. Additive Latency plus BL/2 cycles after Read command |
// 3. tRTP after the last 4-bit prefetch |
if (read_precharge_bank[i] |
&& ($time - tm_bank_activate[i] >= TRAS_MIN) |
&& (ck_cntr - ck_bank_read[i] >= additive_latency + burst_length/2)) begin |
|
read_precharge_bank[i] = 0; |
// In case the internal precharge is pushed out by tRTP, tRP starts at the point where |
// the internal precharge happens (not at the next rising clock edge after this event). |
if ($time - tm_bank_read_end[i] < TRTP) begin |
if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", tm_bank_read_end[i] + TRTP, i); |
active_bank[i] <= #(tm_bank_read_end[i] + TRTP - $time) 0; |
auto_precharge_bank[i] <= #(tm_bank_read_end[i] + TRTP - $time) 0; |
tm_bank_precharge[i] <= #(tm_bank_read_end[i] + TRTP - $time) tm_bank_read_end[i] + TRTP; |
tm_precharge <= #(tm_bank_read_end[i] + TRTP - $time) tm_bank_read_end[i] + TRTP; |
end else begin |
if (DEBUG) $display ("%m: at time %t INFO: Auto Precharge bank %d", $time, i); |
active_bank[i] = 0; |
auto_precharge_bank[i] = 0; |
tm_bank_precharge[i] = $time; |
tm_precharge = $time; |
end |
end |
end |
end |
|
// respond to incoming command |
if (cke_in ^ prev_cke) begin |
ck_cke <= ck_cntr; |
end |
|
cmd_task(cke_in, cmd_n_in, ba_in, addr_in); |
if ((cmd_n_in == WRITE) || (cmd_n_in == READ)) begin |
al_pipeline[2*additive_latency] = 1'b1; |
end |
if (al_pipeline[0]) begin |
// check tRCD after additive latency |
if ($time - tm_bank_activate[ba_pipeline[2*cas_latency - 1]] < TRCD) begin |
if (rd_pipeline[2*cas_latency - 1]) begin |
$display ("%m: at time %t ERROR: tRCD violation during %s", $time, cmd_string[READ]); |
end else begin |
$display ("%m: at time %t ERROR: tRCD violation during %s", $time, cmd_string[WRITE]); |
end |
end |
// check tWTR after additive latency |
if (rd_pipeline[2*cas_latency - 1]) begin |
if ($time - tm_write_end < TWTR) |
$display ("%m: at time %t ERROR: tWTR violation during %s", $time, cmd_string[READ]); |
end |
end |
if (rd_pipeline[2*(cas_latency - burst_length/2 + 2) - 1]) begin |
tm_bank_read_end[ba_pipeline[2*(cas_latency - burst_length/2 + 2) - 1]] <= $time; |
end |
for (i=0; i<`BANKS; i=i+1) begin |
if ((ck_cntr - ck_bank_write[i] > write_latency) && (ck_cntr - ck_bank_write[i] <= write_latency + burst_length/2)) begin |
tm_bank_write_end[i] <= $time; |
tm_write_end <= $time; |
end |
end |
|
// clk pin is disabled during self refresh |
if (!in_self_refresh) begin |
tjit_cc_time = $time - tm_ck_pos - tck_i; |
tck_i = $time - tm_ck_pos; |
tck_avg = tck_avg - tck_sample[ck_cntr%TDLLK]/$itor(TDLLK); |
tck_avg = tck_avg + tck_i/$itor(TDLLK); |
tck_sample[ck_cntr%TDLLK] = tck_i; |
tjit_per_rtime = tck_i - tck_avg; |
|
if (dll_locked) begin |
// check accumulated error |
terr_nper_rtime = 0; |
for (i=0; i<50; i=i+1) begin |
terr_nper_rtime = terr_nper_rtime + tck_sample[i] - tck_avg; |
terr_nper_rtime = abs_value(terr_nper_rtime); |
case (i) |
0 :; |
1 : if (terr_nper_rtime - TERR_2PER >= 1.0) $display ("%m: at time %t ERROR: tERR(2per) violation by %f ps.", $time, terr_nper_rtime - TERR_2PER); |
2 : if (terr_nper_rtime - TERR_3PER >= 1.0) $display ("%m: at time %t ERROR: tERR(3per) violation by %f ps.", $time, terr_nper_rtime - TERR_3PER); |
3 : if (terr_nper_rtime - TERR_4PER >= 1.0) $display ("%m: at time %t ERROR: tERR(4per) violation by %f ps.", $time, terr_nper_rtime - TERR_4PER); |
4 : if (terr_nper_rtime - TERR_5PER >= 1.0) $display ("%m: at time %t ERROR: tERR(5per) violation by %f ps.", $time, terr_nper_rtime - TERR_5PER); |
5,6,7,8,9 : if (terr_nper_rtime - TERR_N1PER >= 1.0) $display ("%m: at time %t ERROR: tERR(n1per) violation by %f ps.", $time, terr_nper_rtime - TERR_N1PER); |
default : if (terr_nper_rtime - TERR_N2PER >= 1.0) $display ("%m: at time %t ERROR: tERR(n2per) violation by %f ps.", $time, terr_nper_rtime - TERR_N2PER); |
endcase |
end |
|
// check tCK min/max/jitter |
if (abs_value(tjit_per_rtime) - TJIT_PER >= 1.0) |
$display ("%m: at time %t ERROR: tJIT(per) violation by %f ps.", $time, abs_value(tjit_per_rtime) - TJIT_PER); |
if (abs_value(tjit_cc_time) - TJIT_CC >= 1.0) |
$display ("%m: at time %t ERROR: tJIT(cc) violation by %f ps.", $time, abs_value(tjit_cc_time) - TJIT_CC); |
if (TCK_MIN - tck_avg >= 1.0) |
$display ("%m: at time %t ERROR: tCK(avg) minimum violation by %f ps.", $time, TCK_MIN - tck_avg); |
if (tck_avg - TCK_MAX >= 1.0) |
$display ("%m: at time %t ERROR: tCK(avg) maximum violation by %f ps.", $time, tck_avg - TCK_MAX); |
if (tm_ck_pos + TCK_MIN - TJIT_PER > $time) |
$display ("%m: at time %t ERROR: tCK(abs) minimum violation by %t", $time, tm_ck_pos + TCK_MIN - TJIT_PER - $time); |
if (tm_ck_pos + TCK_MAX + TJIT_PER < $time) |
$display ("%m: at time %t ERROR: tCK(abs) maximum violation by %t", $time, $time - tm_ck_pos - TCK_MAX - TJIT_PER); |
|
// check tCL |
if (tm_ck_neg + TCL_MIN*tck_avg - TJIT_DUTY > $time) |
$display ("%m: at time %t ERROR: tCL(abs) minimum violation on CLK by %t", $time, tm_ck_neg + TCL_MIN*tck_avg - TJIT_DUTY - $time); |
if (tm_ck_neg + TCL_MAX*tck_avg + TJIT_DUTY < $time) |
$display ("%m: at time %t ERROR: tCL(abs) maximum violation on CLK by %t", $time, $time - tm_ck_neg - TCL_MAX*tck_avg - TJIT_DUTY); |
if (tcl_avg < TCL_MIN*tck_avg) |
$display ("%m: at time %t ERROR: tCL(avg) minimum violation on CLK by %t", $time, TCL_MIN*tck_avg - tcl_avg); |
if (tcl_avg > TCL_MAX*tck_avg) |
$display ("%m: at time %t ERROR: tCL(avg) maximum violation on CLK by %t", $time, tcl_avg - TCL_MAX*tck_avg); |
end |
|
// calculate the tch avg jitter |
tch_avg = tch_avg - tch_sample[ck_cntr%TDLLK]/$itor(TDLLK); |
tch_avg = tch_avg + tch_i/$itor(TDLLK); |
tch_sample[ck_cntr%TDLLK] = tch_i; |
|
// update timers/counters |
tcl_i <= $time - tm_ck_neg; |
end |
|
prev_odt <= odt_in; |
// update timers/counters |
ck_cntr <= ck_cntr + 1; |
tm_ck_pos <= $time; |
end else begin |
// clk pin is disabled during self refresh |
if (!in_self_refresh) begin |
if (dll_locked) begin |
if (tm_ck_pos + TCH_MIN*tck_avg - TJIT_DUTY > $time) |
$display ("%m: at time %t ERROR: tCH(abs) minimum violation on CLK by %t", $time, tm_ck_pos + TCH_MIN*tck_avg - TJIT_DUTY + $time); |
if (tm_ck_pos + TCH_MAX*tck_avg + TJIT_DUTY < $time) |
$display ("%m: at time %t ERROR: tCH(abs) maximum violation on CLK by %t", $time, $time - tm_ck_pos - TCH_MAX*tck_avg - TJIT_DUTY); |
if (tch_avg < TCH_MIN*tck_avg) |
$display ("%m: at time %t ERROR: tCH(avg) minimum violation on CLK by %t", $time, TCH_MIN*tck_avg - tch_avg); |
if (tch_avg > TCH_MAX*tck_avg) |
$display ("%m: at time %t ERROR: tCH(avg) maximum violation on CLK by %t", $time, tch_avg - TCH_MAX*tck_avg); |
end |
|
// calculate the tcl avg jitter |
tcl_avg = tcl_avg - tcl_sample[ck_cntr%TDLLK]/$itor(TDLLK); |
tcl_avg = tcl_avg + tcl_i/$itor(TDLLK); |
tcl_sample[ck_cntr%TDLLK] = tcl_i; |
|
// update timers/counters |
tch_i <= $time - tm_ck_pos; |
end |
tm_ck_neg <= $time; |
end |
|
// on die termination |
if (odt_en) begin |
// clk pin is disabled during self refresh |
if (!in_self_refresh && diff_ck) begin |
if ($time - tm_odt < TIS) begin |
$display ("%m: at time %t ERROR: tIS violation on ODT by %t", $time, tm_odt + TIS - $time); |
end |
if (prev_odt ^ odt_in) begin |
if (!dll_locked) |
$display ("%m: at time %t WARNING: tDLLK violation during ODT transition.", $time); |
if (odt_in && ($time - tm_odt_en < TMOD)) |
$display ("%m: at time %t ERROR: tMOD violation during ODT transition", $time); |
if ($time - tm_self_refresh < TXSNR) |
$display ("%m: at time %t ERROR: tXSNR violation during ODT transition", $time); |
if (in_self_refresh) |
$display ("%m: at time %t ERROR: Illegal ODT transition during Self Refresh.", $time); |
|
// async ODT mode applies: |
// 1.) during active power down with slow exit |
// 2.) during precharge power down |
// 3.) if tANPD has not been satisfied |
// 4.) until tAXPD has been satisfied |
if ((in_power_down && (low_power || (active_bank == 0))) || (ck_cntr - ck_slow_exit_pd < TAXPD)) begin |
if (ck_cntr - ck_slow_exit_pd < TAXPD) |
$display ("%m: at time %t WARNING: tAXPD violation during ODT transition. Synchronous or asynchronous change in termination resistance is possible.", $time); |
if (odt_in) begin |
if (DEBUG) $display ("%m: at time %t INFO: Async On Die Termination = %d", $time + TAONPD, 1'b1); |
odt_state <= #(TAONPD) 1'b1; |
end else begin |
if (DEBUG) $display ("%m: at time %t INFO: Async On Die Termination = %d", $time + TAOFPD, 1'b0); |
odt_state <= #(TAOFPD) 1'b0; |
end |
// sync ODT mode applies: |
// 1.) during normal operation |
// 2.) during active power down with fast exit |
end else begin |
if (odt_in) begin |
i = TAOND*2; |
odt_pipeline[i] = 1'b1; |
end else begin |
i = TAOFD*2; |
odt_pipeline[i] = 1'b1; |
end |
end |
ck_odt <= ck_cntr; |
end |
end |
if (odt_pipeline[0]) begin |
odt_state = ~odt_state; |
if (DEBUG) $display ("%m: at time %t INFO: Sync On Die Termination = %d", $time, odt_state); |
end |
end |
|
// shift pipelines |
if (|wr_pipeline || |rd_pipeline || |al_pipeline) begin |
al_pipeline = al_pipeline>>1; |
wr_pipeline = wr_pipeline>>1; |
rd_pipeline = rd_pipeline>>1; |
for (i=0; i<`MAX_PIPE; i=i+1) begin |
ba_pipeline[i] = ba_pipeline[i+1]; |
row_pipeline[i] = row_pipeline[i+1]; |
col_pipeline[i] = col_pipeline[i+1]; |
end |
end |
if (|odt_pipeline) begin |
odt_pipeline = odt_pipeline>>1; |
end |
end |
|
// receiver(s) |
task dqs_even_receiver; |
input [4:0] i; |
reg [71:0] bit_mask; |
begin |
bit_mask = {`DQ_PER_DQS{1'b1}}<<(i*`DQ_PER_DQS); |
if (dqs_even[i]) begin |
if (rdqs_en) begin // rdqs disables dm |
dm_in_pos[i] = 1'b0; |
end else begin |
dm_in_pos[i] = dm_in[i]; |
end |
dq_in_pos = (dq_in & bit_mask) | (dq_in_pos & ~bit_mask); |
end |
end |
endtask |
|
always @(posedge dqs_even[ 0]) dqs_even_receiver( 0); |
always @(posedge dqs_even[ 1]) dqs_even_receiver( 1); |
always @(posedge dqs_even[ 2]) dqs_even_receiver( 2); |
always @(posedge dqs_even[ 3]) dqs_even_receiver( 3); |
always @(posedge dqs_even[ 4]) dqs_even_receiver( 4); |
always @(posedge dqs_even[ 5]) dqs_even_receiver( 5); |
always @(posedge dqs_even[ 6]) dqs_even_receiver( 6); |
always @(posedge dqs_even[ 7]) dqs_even_receiver( 7); |
always @(posedge dqs_even[ 8]) dqs_even_receiver( 8); |
always @(posedge dqs_even[ 9]) dqs_even_receiver( 9); |
always @(posedge dqs_even[10]) dqs_even_receiver(10); |
always @(posedge dqs_even[11]) dqs_even_receiver(11); |
always @(posedge dqs_even[12]) dqs_even_receiver(12); |
always @(posedge dqs_even[13]) dqs_even_receiver(13); |
always @(posedge dqs_even[14]) dqs_even_receiver(14); |
always @(posedge dqs_even[15]) dqs_even_receiver(15); |
always @(posedge dqs_even[16]) dqs_even_receiver(16); |
always @(posedge dqs_even[17]) dqs_even_receiver(17); |
|
task dqs_odd_receiver; |
input [4:0] i; |
reg [71:0] bit_mask; |
begin |
bit_mask = {`DQ_PER_DQS{1'b1}}<<(i*`DQ_PER_DQS); |
if (dqs_odd[i]) begin |
if (rdqs_en) begin // rdqs disables dm |
dm_in_neg[i] = 1'b0; |
end else begin |
dm_in_neg[i] = dm_in[i]; |
end |
dq_in_neg = (dq_in & bit_mask) | (dq_in_neg & ~bit_mask); |
end |
end |
endtask |
|
always @(posedge dqs_odd[ 0]) dqs_odd_receiver( 0); |
always @(posedge dqs_odd[ 1]) dqs_odd_receiver( 1); |
always @(posedge dqs_odd[ 2]) dqs_odd_receiver( 2); |
always @(posedge dqs_odd[ 3]) dqs_odd_receiver( 3); |
always @(posedge dqs_odd[ 4]) dqs_odd_receiver( 4); |
always @(posedge dqs_odd[ 5]) dqs_odd_receiver( 5); |
always @(posedge dqs_odd[ 6]) dqs_odd_receiver( 6); |
always @(posedge dqs_odd[ 7]) dqs_odd_receiver( 7); |
always @(posedge dqs_odd[ 8]) dqs_odd_receiver( 8); |
always @(posedge dqs_odd[ 9]) dqs_odd_receiver( 9); |
always @(posedge dqs_odd[10]) dqs_odd_receiver(10); |
always @(posedge dqs_odd[11]) dqs_odd_receiver(11); |
always @(posedge dqs_odd[12]) dqs_odd_receiver(12); |
always @(posedge dqs_odd[13]) dqs_odd_receiver(13); |
always @(posedge dqs_odd[14]) dqs_odd_receiver(14); |
always @(posedge dqs_odd[15]) dqs_odd_receiver(15); |
always @(posedge dqs_odd[16]) dqs_odd_receiver(16); |
always @(posedge dqs_odd[17]) dqs_odd_receiver(17); |
|
// Processes to check hold and pulse width of control signals |
always @(cke_in) begin |
if ($time > TIH) begin |
if ($time - tm_ck_pos < TIH) |
$display ("%m: at time %t ERROR: tIH violation on CKE by %t", $time, tm_ck_pos + TIH - $time); |
end |
if (dll_locked && ($time - tm_cke < $rtoi(TIPW*tck_avg))) |
$display ("%m: at time %t ERROR: tIPW violation on CKE by %t", $time, tm_cke + TIPW*tck_avg - $time); |
tm_cke = $time; |
end |
always @(odt_in) begin |
if (odt_en && !in_self_refresh) begin |
if ($time - tm_ck_pos < TIH) |
$display ("%m: at time %t ERROR: tIH violation on ODT by %t", $time, tm_ck_pos + TIH - $time); |
if (dll_locked && ($time - tm_odt < $rtoi(TIPW*tck_avg))) |
$display ("%m: at time %t ERROR: tIPW violation on ODT by %t", $time, tm_odt + TIPW*tck_avg - $time); |
end |
tm_odt = $time; |
end |
|
task cmd_addr_timing_check; |
input i; |
reg [4:0] i; |
begin |
if (prev_cke) begin |
if ((i == 0) && ($time - tm_ck_pos < TIH)) // Always check tIH for CS# |
$display ("%m: at time %t ERROR: tIH violation on %s by %t", $time, cmd_addr_string[i], tm_ck_pos + TIH - $time); |
if ((i > 0) && (cs_n_in == 1'b0) && ($time - tm_ck_pos < TIH)) // Only check tIH for cmd_addr if CS# low |
$display ("%m: at time %t ERROR: tIH violation on %s by %t", $time, cmd_addr_string[i], tm_ck_pos + TIH - $time); |
if (dll_locked && ($time - tm_cmd_addr[i] < $rtoi(TIPW*tck_avg))) |
$display ("%m: at time %t ERROR: tIPW violation on %s by %t", $time, cmd_addr_string[i], tm_cmd_addr[i] + TIPW*tck_avg - $time); |
end |
tm_cmd_addr[i] = $time; |
end |
endtask |
|
always @(cs_n_in ) cmd_addr_timing_check( 0); |
always @(ras_n_in ) cmd_addr_timing_check( 1); |
always @(cas_n_in ) cmd_addr_timing_check( 2); |
always @(we_n_in ) cmd_addr_timing_check( 3); |
always @(ba_in [ 0]) cmd_addr_timing_check( 4); |
always @(ba_in [ 1]) cmd_addr_timing_check( 5); |
always @(ba_in [ 2]) cmd_addr_timing_check( 6); |
always @(addr_in[ 0]) cmd_addr_timing_check( 7); |
always @(addr_in[ 1]) cmd_addr_timing_check( 8); |
always @(addr_in[ 2]) cmd_addr_timing_check( 9); |
always @(addr_in[ 3]) cmd_addr_timing_check(10); |
always @(addr_in[ 4]) cmd_addr_timing_check(11); |
always @(addr_in[ 5]) cmd_addr_timing_check(12); |
always @(addr_in[ 6]) cmd_addr_timing_check(13); |
always @(addr_in[ 7]) cmd_addr_timing_check(14); |
always @(addr_in[ 8]) cmd_addr_timing_check(15); |
always @(addr_in[ 9]) cmd_addr_timing_check(16); |
always @(addr_in[10]) cmd_addr_timing_check(17); |
always @(addr_in[11]) cmd_addr_timing_check(18); |
always @(addr_in[12]) cmd_addr_timing_check(19); |
always @(addr_in[13]) cmd_addr_timing_check(20); |
always @(addr_in[14]) cmd_addr_timing_check(21); |
always @(addr_in[15]) cmd_addr_timing_check(22); |
|
// Processes to check setup and hold of data signals |
task dm_timing_check; |
input i; |
reg [4:0] i; |
begin |
if (dqs_in_valid) begin |
if ($time - tm_dqs[i] < TDH) |
$display ("%m: at time %t ERROR: tDH violation on DM bit %d by %t", $time, i, tm_dqs[i] + TDH - $time); |
if (check_dm_tdipw[i]) begin |
if (dll_locked && ($time - tm_dm[i] < $rtoi(TDIPW*tck_avg))) |
$display ("%m: at time %t ERROR: tDIPW violation on DM bit %d by %t", $time, i, tm_dm[i] + TDIPW*tck_avg - $time); |
end |
end |
check_dm_tdipw[i] <= 1'b0; |
tm_dm[i] = $time; |
end |
endtask |
|
always @(dm_in[ 0]) dm_timing_check( 0); |
always @(dm_in[ 1]) dm_timing_check( 1); |
always @(dm_in[ 2]) dm_timing_check( 2); |
always @(dm_in[ 3]) dm_timing_check( 3); |
always @(dm_in[ 4]) dm_timing_check( 4); |
always @(dm_in[ 5]) dm_timing_check( 5); |
always @(dm_in[ 6]) dm_timing_check( 6); |
always @(dm_in[ 7]) dm_timing_check( 7); |
always @(dm_in[ 8]) dm_timing_check( 8); |
always @(dm_in[ 9]) dm_timing_check( 9); |
always @(dm_in[10]) dm_timing_check(10); |
always @(dm_in[11]) dm_timing_check(11); |
always @(dm_in[12]) dm_timing_check(12); |
always @(dm_in[13]) dm_timing_check(13); |
always @(dm_in[14]) dm_timing_check(14); |
always @(dm_in[15]) dm_timing_check(15); |
always @(dm_in[16]) dm_timing_check(16); |
always @(dm_in[17]) dm_timing_check(17); |
|
task dq_timing_check; |
input i; |
reg [6:0] i; |
begin |
if (dqs_in_valid) begin |
if ($time - tm_dqs[i/`DQ_PER_DQS] < TDH) |
$display ("%m: at time %t ERROR: tDH violation on DQ bit %d by %t", $time, i, tm_dqs[i/`DQ_PER_DQS] + TDH - $time); |
if (check_dq_tdipw[i]) begin |
if (dll_locked && ($time - tm_dq[i] < $rtoi(TDIPW*tck_avg))) |
$display ("%m: at time %t ERROR: tDIPW violation on DQ bit %d by %t", $time, i, tm_dq[i] + TDIPW*tck_avg - $time); |
end |
end |
check_dq_tdipw[i] <= 1'b0; |
tm_dq[i] = $time; |
end |
endtask |
|
always @(dq_in[ 0]) dq_timing_check( 0); |
always @(dq_in[ 1]) dq_timing_check( 1); |
always @(dq_in[ 2]) dq_timing_check( 2); |
always @(dq_in[ 3]) dq_timing_check( 3); |
always @(dq_in[ 4]) dq_timing_check( 4); |
always @(dq_in[ 5]) dq_timing_check( 5); |
always @(dq_in[ 6]) dq_timing_check( 6); |
always @(dq_in[ 7]) dq_timing_check( 7); |
always @(dq_in[ 8]) dq_timing_check( 8); |
always @(dq_in[ 9]) dq_timing_check( 9); |
always @(dq_in[10]) dq_timing_check(10); |
always @(dq_in[11]) dq_timing_check(11); |
always @(dq_in[12]) dq_timing_check(12); |
always @(dq_in[13]) dq_timing_check(13); |
always @(dq_in[14]) dq_timing_check(14); |
always @(dq_in[15]) dq_timing_check(15); |
always @(dq_in[16]) dq_timing_check(16); |
always @(dq_in[17]) dq_timing_check(17); |
always @(dq_in[18]) dq_timing_check(18); |
always @(dq_in[19]) dq_timing_check(19); |
always @(dq_in[20]) dq_timing_check(20); |
always @(dq_in[21]) dq_timing_check(21); |
always @(dq_in[22]) dq_timing_check(22); |
always @(dq_in[23]) dq_timing_check(23); |
always @(dq_in[24]) dq_timing_check(24); |
always @(dq_in[25]) dq_timing_check(25); |
always @(dq_in[26]) dq_timing_check(26); |
always @(dq_in[27]) dq_timing_check(27); |
always @(dq_in[28]) dq_timing_check(28); |
always @(dq_in[29]) dq_timing_check(29); |
always @(dq_in[30]) dq_timing_check(30); |
always @(dq_in[31]) dq_timing_check(31); |
always @(dq_in[32]) dq_timing_check(32); |
always @(dq_in[33]) dq_timing_check(33); |
always @(dq_in[34]) dq_timing_check(34); |
always @(dq_in[35]) dq_timing_check(35); |
always @(dq_in[36]) dq_timing_check(36); |
always @(dq_in[37]) dq_timing_check(37); |
always @(dq_in[38]) dq_timing_check(38); |
always @(dq_in[39]) dq_timing_check(39); |
always @(dq_in[40]) dq_timing_check(40); |
always @(dq_in[41]) dq_timing_check(41); |
always @(dq_in[42]) dq_timing_check(42); |
always @(dq_in[43]) dq_timing_check(43); |
always @(dq_in[44]) dq_timing_check(44); |
always @(dq_in[45]) dq_timing_check(45); |
always @(dq_in[46]) dq_timing_check(46); |
always @(dq_in[47]) dq_timing_check(47); |
always @(dq_in[48]) dq_timing_check(48); |
always @(dq_in[49]) dq_timing_check(49); |
always @(dq_in[50]) dq_timing_check(50); |
always @(dq_in[51]) dq_timing_check(51); |
always @(dq_in[52]) dq_timing_check(52); |
always @(dq_in[53]) dq_timing_check(53); |
always @(dq_in[54]) dq_timing_check(54); |
always @(dq_in[55]) dq_timing_check(55); |
always @(dq_in[56]) dq_timing_check(56); |
always @(dq_in[57]) dq_timing_check(57); |
always @(dq_in[58]) dq_timing_check(58); |
always @(dq_in[59]) dq_timing_check(59); |
always @(dq_in[60]) dq_timing_check(60); |
always @(dq_in[61]) dq_timing_check(61); |
always @(dq_in[62]) dq_timing_check(62); |
always @(dq_in[63]) dq_timing_check(63); |
always @(dq_in[64]) dq_timing_check(64); |
always @(dq_in[65]) dq_timing_check(65); |
always @(dq_in[66]) dq_timing_check(66); |
always @(dq_in[67]) dq_timing_check(67); |
always @(dq_in[68]) dq_timing_check(68); |
always @(dq_in[69]) dq_timing_check(69); |
always @(dq_in[70]) dq_timing_check(70); |
always @(dq_in[71]) dq_timing_check(71); |
|
task dqs_pos_timing_check; |
input i; |
reg [5:0] i; |
reg [3:0] j; |
begin |
if (dqs_in_valid && ((wdqs_pos_cntr[i] < burst_length/2) || b2b_write) && (dqs_n_en || i<18)) begin |
if (dqs_in[i] ^ prev_dqs_in[i]) begin |
if (dll_locked) begin |
if (check_write_preamble[i]) begin |
if ($time - tm_dqs_neg[i] < $rtoi(TWPRE*tck_avg)) |
$display ("%m: at time %t ERROR: tWPRE violation on &s bit %d", $time, dqs_string[i/18], i%18); |
end else if (check_write_postamble[i]) begin |
if ($time - tm_dqs_neg[i] < $rtoi(TWPST*tck_avg)) |
$display ("%m: at time %t ERROR: tWPST violation on %s bit %d", $time, dqs_string[i/18], i%18); |
end else begin |
if ($time - tm_dqs_neg[i] < $rtoi(TDQSL*tck_avg)) |
$display ("%m: at time %t ERROR: tDQSL violation on %s bit %d", $time, dqs_string[i/18], i%18); |
end |
end |
if ($time - tm_dm[i%18] < TDS) |
$display ("%m: at time %t ERROR: tDS violation on DM bit %d by %t", $time, i, tm_dm[i%18] + TDS - $time); |
if (!dq_out_en) begin |
for (j=0; j<`DQ_PER_DQS; j=j+1) begin |
if ($time - tm_dq[i*`DQ_PER_DQS+j] < TDS) |
$display ("%m: at time %t ERROR: tDS violation on DQ bit %d by %t", $time, i*`DQ_PER_DQS+j, tm_dq[i*`DQ_PER_DQS+j] + TDS - $time); |
check_dq_tdipw[i*`DQ_PER_DQS+j] <= 1'b1; |
end |
end |
if ((wdqs_pos_cntr[i] < burst_length/2) && !b2b_write) begin |
wdqs_pos_cntr[i] <= wdqs_pos_cntr[i] + 1; |
end else begin |
wdqs_pos_cntr[i] <= 1; |
end |
check_dm_tdipw[i%18] <= 1'b1; |
check_write_preamble[i] <= 1'b0; |
check_write_postamble[i] <= 1'b0; |
check_write_dqs_low[i] <= 1'b0; |
tm_dqs[i%18] <= $time; |
end else begin |
$display ("%m: at time %t ERROR: Invalid latching edge on %s bit %d", $time, dqs_string[i/18], i%18); |
end |
end |
tm_dqss_pos[i] <= $time; |
tm_dqs_pos[i] = $time; |
prev_dqs_in[i] <= dqs_in[i]; |
end |
endtask |
|
always @(posedge dqs_in[ 0]) dqs_pos_timing_check( 0); |
always @(posedge dqs_in[ 1]) dqs_pos_timing_check( 1); |
always @(posedge dqs_in[ 2]) dqs_pos_timing_check( 2); |
always @(posedge dqs_in[ 3]) dqs_pos_timing_check( 3); |
always @(posedge dqs_in[ 4]) dqs_pos_timing_check( 4); |
always @(posedge dqs_in[ 5]) dqs_pos_timing_check( 5); |
always @(posedge dqs_in[ 6]) dqs_pos_timing_check( 6); |
always @(posedge dqs_in[ 7]) dqs_pos_timing_check( 7); |
always @(posedge dqs_in[ 8]) dqs_pos_timing_check( 8); |
always @(posedge dqs_in[ 9]) dqs_pos_timing_check( 9); |
always @(posedge dqs_in[10]) dqs_pos_timing_check(10); |
always @(posedge dqs_in[11]) dqs_pos_timing_check(11); |
always @(posedge dqs_in[12]) dqs_pos_timing_check(12); |
always @(posedge dqs_in[13]) dqs_pos_timing_check(13); |
always @(posedge dqs_in[14]) dqs_pos_timing_check(14); |
always @(posedge dqs_in[15]) dqs_pos_timing_check(15); |
always @(posedge dqs_in[16]) dqs_pos_timing_check(16); |
always @(posedge dqs_in[17]) dqs_pos_timing_check(17); |
always @(negedge dqs_in[18]) dqs_pos_timing_check(18); |
always @(negedge dqs_in[19]) dqs_pos_timing_check(19); |
always @(negedge dqs_in[20]) dqs_pos_timing_check(20); |
always @(negedge dqs_in[21]) dqs_pos_timing_check(21); |
always @(negedge dqs_in[22]) dqs_pos_timing_check(22); |
always @(negedge dqs_in[23]) dqs_pos_timing_check(23); |
always @(negedge dqs_in[24]) dqs_pos_timing_check(24); |
always @(negedge dqs_in[25]) dqs_pos_timing_check(25); |
always @(negedge dqs_in[26]) dqs_pos_timing_check(26); |
always @(negedge dqs_in[27]) dqs_pos_timing_check(27); |
always @(negedge dqs_in[28]) dqs_pos_timing_check(28); |
always @(negedge dqs_in[29]) dqs_pos_timing_check(29); |
always @(negedge dqs_in[30]) dqs_pos_timing_check(30); |
always @(negedge dqs_in[31]) dqs_pos_timing_check(31); |
always @(negedge dqs_in[32]) dqs_neg_timing_check(32); |
always @(negedge dqs_in[33]) dqs_neg_timing_check(33); |
always @(negedge dqs_in[34]) dqs_neg_timing_check(34); |
always @(negedge dqs_in[35]) dqs_neg_timing_check(35); |
|
task dqs_neg_timing_check; |
input i; |
reg [5:0] i; |
reg [3:0] j; |
begin |
if (dqs_in_valid && (wdqs_pos_cntr[i] > 0) && check_write_dqs_high[i] && (dqs_n_en || i < 18)) begin |
if (dqs_in[i] ^ prev_dqs_in[i]) begin |
if (dll_locked) begin |
if ($time - tm_dqs_pos[i] < $rtoi(TDQSH*tck_avg)) |
$display ("%m: at time %t ERROR: tDQSH violation on %s bit %d", $time, dqs_string[i/18], i%18); |
if ($time - tm_ck_pos < $rtoi(TDSH*tck_avg)) |
$display ("%m: at time %t ERROR: tDSH violation on %s bit %d", $time, dqs_string[i/18], i%18); |
end |
if ($time - tm_dm[i%18] < TDS) |
$display ("%m: at time %t ERROR: tDS violation on DM bit %d by %t", $time, i, tm_dm[i%18] + TDS - $time); |
if (!dq_out_en) begin |
for (j=0; j<`DQ_PER_DQS; j=j+1) begin |
if ($time - tm_dq[i*`DQ_PER_DQS+j] < TDS) |
$display ("%m: at time %t ERROR: tDS violation on DQ bit %d by %t", $time, i*`DQ_PER_DQS+j, tm_dq[i*`DQ_PER_DQS+j] + TDS - $time); |
check_dq_tdipw[i*`DQ_PER_DQS+j] <= 1'b1; |
end |
end |
check_dm_tdipw[i%18] <= 1'b1; |
check_write_dqs_high[i] <= 1'b0; |
tm_dqs[i%18] <= $time; |
end else begin |
$display ("%m: at time %t ERROR: Invalid latching edge on %s bit %d", $time, dqs_string[i/18], i%18); |
end |
end |
tm_dqs_neg[i] = $time; |
prev_dqs_in[i] <= dqs_in[i]; |
end |
endtask |
|
always @(negedge dqs_in[ 0]) dqs_neg_timing_check( 0); |
always @(negedge dqs_in[ 1]) dqs_neg_timing_check( 1); |
always @(negedge dqs_in[ 2]) dqs_neg_timing_check( 2); |
always @(negedge dqs_in[ 3]) dqs_neg_timing_check( 3); |
always @(negedge dqs_in[ 4]) dqs_neg_timing_check( 4); |
always @(negedge dqs_in[ 5]) dqs_neg_timing_check( 5); |
always @(negedge dqs_in[ 6]) dqs_neg_timing_check( 6); |
always @(negedge dqs_in[ 7]) dqs_neg_timing_check( 7); |
always @(negedge dqs_in[ 8]) dqs_neg_timing_check( 8); |
always @(negedge dqs_in[ 9]) dqs_neg_timing_check( 9); |
always @(negedge dqs_in[10]) dqs_neg_timing_check(10); |
always @(negedge dqs_in[11]) dqs_neg_timing_check(11); |
always @(negedge dqs_in[12]) dqs_neg_timing_check(12); |
always @(negedge dqs_in[13]) dqs_neg_timing_check(13); |
always @(negedge dqs_in[14]) dqs_neg_timing_check(14); |
always @(negedge dqs_in[15]) dqs_neg_timing_check(15); |
always @(negedge dqs_in[16]) dqs_neg_timing_check(16); |
always @(negedge dqs_in[17]) dqs_neg_timing_check(17); |
always @(posedge dqs_in[18]) dqs_neg_timing_check(18); |
always @(posedge dqs_in[19]) dqs_neg_timing_check(19); |
always @(posedge dqs_in[20]) dqs_neg_timing_check(20); |
always @(posedge dqs_in[21]) dqs_neg_timing_check(21); |
always @(posedge dqs_in[22]) dqs_neg_timing_check(22); |
always @(posedge dqs_in[23]) dqs_neg_timing_check(23); |
always @(posedge dqs_in[24]) dqs_neg_timing_check(24); |
always @(posedge dqs_in[25]) dqs_neg_timing_check(25); |
always @(posedge dqs_in[26]) dqs_neg_timing_check(26); |
always @(posedge dqs_in[27]) dqs_neg_timing_check(27); |
always @(posedge dqs_in[28]) dqs_neg_timing_check(28); |
always @(posedge dqs_in[29]) dqs_neg_timing_check(29); |
always @(posedge dqs_in[30]) dqs_neg_timing_check(30); |
always @(posedge dqs_in[31]) dqs_neg_timing_check(31); |
always @(posedge dqs_in[32]) dqs_neg_timing_check(32); |
always @(posedge dqs_in[33]) dqs_neg_timing_check(33); |
always @(posedge dqs_in[34]) dqs_neg_timing_check(34); |
always @(posedge dqs_in[35]) dqs_neg_timing_check(35); |
|
endmodule |
/xilinx/atlys/bench/verilog/include/eth_stim.v
0,0 → 1,1471
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Ethernet MAC Stimulus //// |
//// //// |
//// Description //// |
//// Ethernet MAC stimulus tasks. Taken from the project //// |
//// testbench in the ethmac core. //// |
//// //// |
//// To Do: //// |
//// //// |
//// //// |
//// Author(s): //// |
//// - Tadej Markovic, tadej@opencores.org //// |
//// - Igor Mohor, igorM@opencores.org //// |
//// - Julius Baxter julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
`define TIME $display("Time: %0t", $time) |
|
// Defines for ethernet test to trigger sending/receiving |
// Is straight forward when using RTL design, but if using netlist then paths to |
// the RX/TX enabled bits depend on synthesis tool, etc, but ones here appear to |
// work with design put through Synplify, with hierarchy maintained. |
`define ETH_TOP dut.ethmac0 |
`define ETH_BD_RAM_PATH `ETH_TOP.wishbone.bd_ram |
`define ETH_MODER_PATH `ETH_TOP.ethreg1.MODER_0 |
|
`ifdef RTL_SIM |
`ifdef ethmac_IS_GATELEVEL |
`define ETH_MODER_TXEN_BIT `ETH_MODER_PATH.r_TxEn; |
`define ETH_MODER_RXEN_BIT `ETH_MODER_PATH.r_RxEn; |
`else |
`define ETH_MODER_TXEN_BIT `ETH_MODER_PATH.DataOut[1]; |
`define ETH_MODER_RXEN_BIT `ETH_MODER_PATH.DataOut[0]; |
`endif |
`endif |
|
`ifdef GATE_SIM |
`define ETH_MODER_TXEN_BIT `ETH_MODER_PATH.r_TxEn; |
`define ETH_MODER_RXEN_BIT `ETH_MODER_PATH.r_RxEn; |
`endif |
|
reg [15:0] eth_stim_rx_packet_length; |
reg [7:0] st_data; |
reg [31:0] lfsr; |
integer lfsr_last_byte; |
|
// Is number of ethernet packets to send if doing the eth-rx test. |
parameter eth_stim_num_rx_only_num_packets = 12; // Set to 0 for continuous RX |
parameter eth_stim_num_rx_only_packet_size = 60; |
parameter eth_stim_num_rx_only_packet_size_change = 2'b01; // 2'b01: Increment |
parameter eth_stim_num_rx_only_packet_size_change_amount = 127; |
parameter eth_stim_num_rx_only_IPG = 800_000; // ps |
|
// Do call/response test |
reg eth_stim_do_rx_reponse_to_tx; |
reg eth_stim_do_overflow_test; |
|
parameter num_tx_bds = 16; |
parameter num_tx_bds_mask = 4'hf; |
parameter num_rx_bds = 16; |
parameter num_rx_bds_mask = 4'hf; |
parameter max_eth_packet_size = 16'h0600; |
|
// If running eth-rxtxbig test (sending and receiving maximum packets), then |
// set this parameter to the max packet size, otherwise min packet size |
//parameter rx_while_tx_min_packet_size = max_eth_packet_size; |
parameter rx_while_tx_min_packet_size = 32; |
|
// Use the smallest possible IPG |
parameter eth_stim_use_min_IPG = 0; |
parameter eth_stim_IPG_delay_max = 100_000_000; // Maximum 100 us |
//parameter eth_stim_IPG_delay_max = 100_000_000; // Maximum 100mS between packets |
parameter eth_stim_IPG_min_10mb = 9600_000; // 9.6 uS |
parameter eth_stim_IPG_min_100mb = 800_000; // 860+~100 = 960 nS 100MBit min IPG |
parameter eth_stim_check_rx_packet_contents = 1; |
parameter eth_stim_check_tx_packet_contents = 1; |
|
parameter eth_inject_errors = 0; |
|
// When running simulations where you don't want to feed packets to the design |
// like this... |
parameter eth_stim_disable_rx_stim = 0; |
|
// Delay between seeing that the buffer descriptor for an RX packet says it's |
// been received and ending up in the memory. |
// For 25MHz sdram controller, use following: |
//parameter Td_rx_packet_check = (`BOARD_CLOCK_PERIOD * 2000); |
// For 64MHz sdram controller, use following: |
parameter Td_rx_packet_check = (`BOARD_CLOCK_PERIOD * 500); |
|
integer expected_rxbd;// init to 0 |
integer expected_txbd; |
|
wire ethmac_rxen; |
wire ethmac_txen; |
assign ethmac_rxen = eth_stim_disable_rx_stim ? 0 : `ETH_MODER_RXEN_BIT; |
assign ethmac_txen = `ETH_MODER_TXEN_BIT; |
|
integer eth_rx_num_packets_sent = 0; |
integer eth_rx_num_packets_checked = 0; |
integer num_tx_packets = 1; |
|
integer rx_packet_lengths [0:1023]; // Array of packet lengths |
|
|
integer speed_loop; |
|
// When txen is (re)enabled, the tx bd pointer goes back to 0 |
always @(posedge ethmac_txen) |
expected_txbd = 0; |
|
reg eth_stim_waiting; |
|
initial |
begin |
#1; |
//lfsr = 32'h84218421; // Init pseudo lfsr |
lfsr = 32'h00700001; // Init pseudo lfsr |
lfsr_last_byte = 0; |
|
eth_stim_waiting = 1; |
expected_rxbd = num_tx_bds; // init this here |
|
eth_stim_do_rx_reponse_to_tx = 0; |
eth_stim_do_overflow_test = 0; |
|
while (eth_stim_waiting) // Loop, waiting for enabling of MAC by software |
begin |
#100; |
// If RX enable and not TX enable... |
if(ethmac_rxen === 1'b1 & !(ethmac_txen===1'b1)) |
begin |
if (eth_inject_errors) |
begin |
do_rx_only_stim(16, 64, 0, 0); |
do_rx_only_stim(128, 64, 1'b1, 8); |
do_rx_only_stim(256, 64, 1'b1, 4); |
eth_stim_waiting = 0; |
end |
else |
begin |
//do_rx_only_stim(eth_stim_num_rx_only_num_packets, |
//eth_stim_num_rx_only_packet_size, 0, 0); |
|
// Call packet send loop directly. No error injection. |
send_packet_loop(eth_stim_num_rx_only_num_packets, |
eth_stim_num_rx_only_packet_size, |
eth_stim_num_rx_only_packet_size_change, |
eth_stim_num_rx_only_packet_size_change_amount, |
eth_phy0.eth_speed, // Speed |
eth_stim_num_rx_only_IPG, // IPG |
48'h0012_3456_789a, 48'h0708_090A_0B0C, 1, |
0, 0, 0); |
|
eth_stim_waiting = 0; |
end |
end // if (ethmac_rxen === 1'b1 & !(ethmac_txen===1'b1)) |
// If both RX and TX enabled |
else if (ethmac_rxen === 1'b1 & ethmac_txen===1'b1) |
begin |
// Both enabled - let's wait for the first packet transmitted |
// to see what stimulus we should provide |
while (num_tx_packets==1) |
#1000; |
|
$display("* ethmac RX/TX test request: %x", eth_phy0.tx_mem[0]); |
|
// Check the first received byte's value |
case (eth_phy0.tx_mem[0]) |
0: |
begin |
// kickoff call/response here |
eth_stim_do_rx_reponse_to_tx = 1; |
end |
1: |
begin |
// kickoff overflow test here |
eth_stim_do_overflow_test = 1; |
end |
default: |
begin |
do_rx_while_tx_stim(1400); |
end |
endcase // case (eth_phy0.tx_mem[0]) |
|
eth_stim_waiting = 0; |
end |
end // while (eth_stim_waiting) |
|
end // initial begin |
|
// Main Ethernet RX testing stimulus task. |
// Sends a set of packets at both speeds |
task do_rx_only_stim; |
input [31:0] num_packets; |
input [31:0] start_packet_size; |
input inject_errors; |
input [31:0] inject_errors_mod; |
|
begin |
|
for(speed_loop=1;speed_loop<3;speed_loop=speed_loop+1) |
begin |
|
send_packet_loop(num_packets, start_packet_size, 2'b01, 1, |
speed_loop[0], 10000, |
48'h0012_3456_789a, 48'h0708_090A_0B0C, 1, |
inject_errors, inject_errors_mod, 0); |
|
end |
|
end |
endtask // do_rx_stim |
|
// Generate RX packets while there's TX going on |
// Sends a set of packets at both speeds |
task do_rx_while_tx_stim; |
input [31:0] num_packets; |
reg [31:0] IPG; // Inter-packet gap |
reg [31:0] packet_size; |
|
integer j; |
begin |
|
for(j=0;j<num_packets;j=j+1) |
begin |
// Determine delay between RX packets: |
|
if (eth_stim_use_min_IPG) |
begin |
// Assign based on whether we're in 100mbit or 10mbit mode |
IPG = eth_phy0.eth_speed ? eth_stim_IPG_min_100mb : |
eth_stim_IPG_min_10mb; |
// Add a little bit of variability |
// Add up to 15 |
IPG = IPG + ($random & 32'h000000f); |
end |
else |
begin |
IPG = $random; |
|
while (IPG > eth_stim_IPG_delay_max) |
IPG = IPG / 2; |
|
|
end |
$display("do_rx_while_tx IPG = %0d", IPG); |
// Determine size of next packet: |
if (rx_while_tx_min_packet_size == max_eth_packet_size) |
// We want to transmit biggest packets possible, easy case |
packet_size = max_eth_packet_size - 4; |
else |
begin |
// Constrained random sized packets |
packet_size = $random; |
|
while (packet_size > (max_eth_packet_size-4)) |
packet_size = packet_size / 2; |
|
// Now divide by least significant bits of j |
packet_size = packet_size / {29'd0,j[1:0],1'b1}; |
if (packet_size < 60) |
packet_size = packet_size + 60; |
end |
|
$display("do_rx_while_tx packet_size = %0d", packet_size); |
send_packet_loop(1, packet_size, 2'b01, 1, eth_phy0.eth_speed, |
IPG, 48'h0012_3456_789a, |
48'h0708_090A_0B0C, 1, 1'b0, 0, 0); |
|
// If RX enable went low, wait for it go high again |
if (ethmac_rxen===1'b0) |
begin |
|
while (ethmac_rxen===1'b0) |
begin |
@(posedge ethmac_rxen); |
#10000; |
end |
|
// RX disabled and when re-enabled we reset the buffer descriptor number |
expected_rxbd = num_tx_bds; |
|
end |
|
end // for (j=0;j<num_packets;j=j+1) |
end |
endtask // do_rx_stim |
|
// Registers used in detecting transmitted packets |
reg eth_stim_tx_loop_keep_polling; |
reg [31:0] ethmac_txbd_lenstat, ethmac_last_txbd_lenstat; |
reg eth_stim_detected_packet_tx; |
|
// If in call-response mode, whenever we receive a TX packet, we generate |
// one and send it back |
always @(negedge eth_stim_detected_packet_tx) |
begin |
if (eth_stim_do_rx_reponse_to_tx & ethmac_rxen) |
// Continue if we are enabled |
do_rx_response_to_tx(); |
end |
|
|
// If in call-response mode, whenever we receive a TX packet, we generate |
// one and send it back |
always @(posedge eth_stim_do_overflow_test) |
begin |
// Continue if we are enabled |
do_overflow_stimulus(); |
end |
|
// Generate RX packet in rsponse to TX packet |
task do_rx_response_to_tx; |
//input unused; |
|
reg [31:0] IPG; // Inter-packet gap |
reg [31:0] packet_size; |
|
integer j; |
begin |
|
// Get packet size test wants us to send |
packet_size = {eth_phy0.tx_mem[0],eth_phy0.tx_mem[1], |
eth_phy0.tx_mem[2],eth_phy0.tx_mem[3]}; |
|
|
IPG = {eth_phy0.tx_mem[4],eth_phy0.tx_mem[5], |
eth_phy0.tx_mem[6],eth_phy0.tx_mem[7]}; |
|
|
$display("do_rx_response_to_tx IPG = %0d", IPG); |
if (packet_size == 0) |
begin |
// Constrained random sized packets |
packet_size = $random; |
|
while (packet_size > (max_eth_packet_size-4)) |
packet_size = packet_size / 2; |
|
if (packet_size < 60) |
packet_size = packet_size + 60; |
end |
|
$display("do_rx_response_to_tx packet_size = %0d", packet_size); |
send_packet_loop(1, packet_size, 2'b01, 1, eth_phy0.eth_speed, |
IPG, 48'h0012_3456_789a, |
48'h0708_090A_0B0C, 1, 1'b0, 0, 0); |
|
// If RX enable went low, wait for it go high again |
if (ethmac_rxen===1'b0) |
begin |
|
while (ethmac_rxen===1'b0) |
begin |
@(posedge ethmac_rxen); |
#10000; |
end |
|
// RX disabled and when re-enabled we reset the buffer |
// descriptor number |
expected_rxbd = num_tx_bds; |
|
end |
|
end |
endtask // do_rx_response_to_tx |
|
// Generate RX packet in rsponse to TX packet |
task do_overflow_stimulus; |
//input unused; |
reg [31:0] IPG; // Inter-packet gap |
reg [31:0] packet_size; |
|
integer j; |
|
begin |
|
// Maximum packet size |
packet_size = 1500; |
|
// Minimum IPG |
IPG = eth_stim_IPG_min_100mb; |
|
$display("do_overflow_stimulus IPG = %0d", IPG); |
|
|
$display("do_overflow_stimulus packetsize = %0d", packet_size); |
|
send_packet_loop(num_rx_bds, packet_size, 2'b01, 1, |
eth_phy0.eth_speed, |
IPG, 48'h0012_3456_789a, |
48'h0708_090A_0B0C, 1, 1'b0, 0, 0); |
|
// This one should cause overflow, don't check it gets there OK |
send_packet_loop(1, packet_size, 2'b01, 1, |
eth_phy0.eth_speed, |
IPG, 48'h0012_3456_789a, |
48'h0708_090A_0B0C, 1, 1'b0, 0, 1); |
|
// Wind back expected RXBD number |
if (expected_rxbd == num_tx_bds) |
expected_rxbd = num_tx_bds + num_rx_bds - 1; |
else |
expected_rxbd = expected_rxbd - 1; |
|
// This one should cause overflow, don't check it gets there OK |
send_packet_loop(1, packet_size, 2'b01, 1, |
eth_phy0.eth_speed, |
IPG, 48'h0012_3456_789a, |
48'h0708_090A_0B0C, 1, 1'b0, 0, 1); |
|
// Wind back expected RXBD number |
if (expected_rxbd == num_tx_bds) |
expected_rxbd = num_tx_bds + num_rx_bds - 1; |
else |
expected_rxbd = expected_rxbd - 1; |
|
|
// This one should cause overflow, don't check it gets there OK |
send_packet_loop(1, packet_size, 2'b01, 1, |
eth_phy0.eth_speed, |
IPG, 48'h0012_3456_789a, |
48'h0708_090A_0B0C, 1, 1'b0, 0, 1); |
|
// Wind back expected RXBD number |
if (expected_rxbd == num_tx_bds) |
expected_rxbd = num_tx_bds + num_rx_bds - 1; |
else |
expected_rxbd = expected_rxbd - 1; |
|
|
// This one should cause overflow, don't check it gets there OK |
send_packet_loop(1, packet_size, 2'b01, 1, |
eth_phy0.eth_speed, |
IPG, 48'h0012_3456_789a, |
48'h0708_090A_0B0C, 1, 1'b0, 0, 1); |
|
// Wind back expected RXBD number |
if (expected_rxbd == num_tx_bds) |
expected_rxbd = num_tx_bds + num_rx_bds - 1; |
else |
expected_rxbd = expected_rxbd - 1; |
|
|
// Wait until a buffer descriptor becomes available |
while(`ETH_TOP.wishbone.RxBDRead==1'b1) |
#1000; |
|
$display("%t: RxBDRead gone low",$time); |
#10000; |
|
|
|
send_packet_loop(1, packet_size, 2'b01, 1, eth_phy0.eth_speed, |
IPG, 48'h0012_3456_789a, |
48'h0708_090A_0B0C, 1, 1'b0, 0, 0); |
|
|
// If RX enable went low, wait for it go high again |
if (ethmac_rxen===1'b0) |
begin |
|
while (ethmac_rxen===1'b0) |
begin |
@(posedge ethmac_rxen); |
#10000; |
end |
|
// RX disabled and when re-enabled we reset the buffer |
// descriptor number |
expected_rxbd = num_tx_bds; |
|
end |
|
end |
endtask // do_overflow_stimulus |
|
|
// |
// always@() to check the TX buffer descriptors |
// |
always @(posedge ethmac_txen) |
begin |
ethmac_last_txbd_lenstat = 0; |
eth_stim_tx_loop_keep_polling=1; |
// Wait on the TxBD Ready bit |
while(eth_stim_tx_loop_keep_polling) |
begin |
#10; |
get_bd_lenstat(expected_txbd, ethmac_txbd_lenstat); |
// Check if we've finished transmitting this BD |
if (!ethmac_txbd_lenstat[15] & ethmac_last_txbd_lenstat[15]) |
// Falling edge of TX BD Ready |
eth_stim_detected_packet_tx = 1; |
|
ethmac_last_txbd_lenstat = ethmac_txbd_lenstat; |
|
// If TX en goes low then exit |
if (!ethmac_txen) |
eth_stim_tx_loop_keep_polling = 0; |
else if (eth_stim_detected_packet_tx) |
begin |
// Wait until the eth_phy has finished receiving it |
while (eth_phy0.mtxen_i === 1'b1) |
#10; |
|
$display("(%t) Check TX packet: bd %d: 0x%h",$time, |
expected_txbd, ethmac_txbd_lenstat); |
|
// Check the TXBD, see if the packet transmitted OK |
if (ethmac_txbd_lenstat[8] | ethmac_txbd_lenstat[3]) |
begin |
// Error occured |
`TIME; |
$display("*E TX Error of packet %0d detected.", |
num_tx_packets); |
$display(" TX BD %0d = 0x%h", expected_txbd, |
ethmac_txbd_lenstat); |
if (ethmac_txbd_lenstat[8]) |
$display(" Underrun in MAC during TX"); |
if (ethmac_txbd_lenstat[3]) |
$display(" Retransmission limit hit"); |
|
$finish; |
end |
else |
begin |
// Packet was OK, let's compare the contents we |
// received with those that were meant to be transmitted |
if (eth_stim_check_tx_packet_contents) |
begin |
check_tx_packet(expected_txbd); |
expected_txbd = (expected_txbd + 1) & |
num_tx_bds_mask; |
num_tx_packets = num_tx_packets + 1; |
eth_stim_detected_packet_tx = 0; |
end |
end |
end |
end // while (eth_stim_tx_loop_keep_polling) |
end // always @ (posedge ethmac_txen) |
|
|
|
|
`ifdef XILINX_DDR2 |
// Gets word from correct bank |
task get_32bitword_from_xilinx_ddr2; |
input [31:0] addr; |
output [31:0] insn; |
reg [16*8-1:0] ddr2_array_line0,ddr2_array_line1,ddr2_array_line2, |
ddr2_array_line3; |
integer word_in_line_num; |
begin |
u_mem0.memory_read(addr[28:27],addr[26:13], |
{addr[12:6],3'd0}, |
ddr2_array_line0); |
insn[31:0] = ddr2_array_line0[31:0]; |
|
end |
endtask |
|
task get_byte_from_xilinx_ddr2; |
input [31:0] addr; |
output [7:0] data_byte; |
reg [31:0] word; |
begin |
get_32bitword_from_xilinx_ddr2(addr, word); |
case (addr[1:0]) |
2'b00: |
data_byte = word[31:24]; |
2'b01: |
data_byte = word[23:16]; |
2'b10: |
data_byte = word[15:8]; |
2'b11: |
data_byte = word[7:0]; |
endcase // case (addr[1:0]) |
end |
endtask // get_byte_from_xilinx_ddr2 |
|
`endif |
|
`ifdef XILINX_DDR2 |
task sync_controller_cache_xilinx_ddr; |
begin |
// Sync cache (writeback dirty lines) with external memory |
dut.xilinx_ddr2_0.xilinx_ddr2_if0.do_sync; |
// Wait for it to occur. |
while (dut.xilinx_ddr2_0.xilinx_ddr2_if0.sync) |
#100; |
|
// Wait just incase writeback of all data hasn't fully occurred. |
// 4uS, in case RAM needs to refresh while writing back. |
#4_000_000; |
|
|
end |
endtask // sync_controller_cache_xilinx_ddr |
`endif |
|
|
// |
// Check packet TX'd by MAC was good |
// |
task check_tx_packet; |
input [31:0] tx_bd_num; |
|
reg [31:0] tx_bd_addr; |
reg [7:0] phy_byte; |
|
reg [31:0] txpnt_wb; // Pointer in array to where data should be |
reg [24:0] txpnt_sdram; // Index in array of shorts for data in SDRAM |
// part |
reg [21:0] buffer; |
reg [7:0] sdram_byte; |
reg [31:0] tx_len_bd; |
|
integer i; |
integer failure; |
begin |
failure = 0; |
|
get_bd_lenstat(tx_bd_num, tx_len_bd); |
|
tx_len_bd = {15'd0,tx_len_bd[31:16]}; |
|
// Check, if length didn't have to be padded, that |
// amount transmitted was correct |
if ((tx_len_bd > 60)&(tx_len_bd != (eth_phy0.tx_len-4))) |
begin |
$display("*E TX packet sent length, %0d != length in TX BD, %0d", |
eth_phy0.tx_len-4, tx_len_bd); |
#100; |
$finish; |
end |
|
`ifdef XILINX_DDR2 |
sync_controller_cache_xilinx_ddr; |
`endif |
|
get_bd_addr(tx_bd_num, tx_bd_addr); |
|
// We're never going to be using more than about 256K of receive buffer |
// so let's lop off the top bit of the address pointer - we only want |
// the offset from the base of the memory bank |
txpnt_wb = {14'd0,tx_bd_addr[17:0]}; |
txpnt_sdram = tx_bd_addr[24:0]; |
|
// Variable we'll use for index in the PHY's TX buffer |
buffer = 0; // Start of TX data |
|
for (i=0;i<tx_len_bd;i=i+1) |
begin |
//$display("Checking address in tx bd 0x%0h",txpnt_sdram); |
sdram_byte = 8'hx; |
`ifdef RAM_WB |
sdram_byte = dut.ram_wb0.ram_wb_b3_0.get_mem8(txpnt_sdram); |
`else |
`ifdef VERSATILE_SDRAM |
sdram0.get_byte(txpnt_sdram,sdram_byte); |
`else |
`ifdef XILINX_DDR2 |
get_byte_from_xilinx_ddr2(txpnt_sdram, sdram_byte); |
`else |
$display(" * Error: sdram_byte was %x", sdram_byte); |
|
$display(" * eth_stim needs to be able to access the main memory to check packet rx/tx"); |
$finish; |
|
`endif |
`endif |
`endif |
|
phy_byte = eth_phy0.tx_mem[buffer]; |
// Debugging output |
//$display("txpnt_sdram = 0x%h, sdram_byte = 0x%h, buffer = 0x%h, phy_byte = 0x%h", txpnt_sdram, sdram_byte, buffer, phy_byte); |
|
if (phy_byte !== sdram_byte) |
begin |
`TIME; |
$display("*E Wrong byte (%d) of TX packet! ram = %h, phy = %h",buffer, sdram_byte, phy_byte); |
failure = 1; |
end |
|
buffer = buffer + 1; |
|
txpnt_sdram = txpnt_sdram+1; |
|
end // for (i=0;i<tx_len_bd;i=i+1) |
|
if (failure) |
begin |
#100 |
`TIME; |
$display("*E Error transmitting packet %0d (%0d bytes). Finishing simulation", num_tx_packets, tx_len_bd); |
get_bd_lenstat(tx_bd_num, tx_len_bd); |
$display(" TXBD lenstat: 0x%0h",tx_len_bd); |
$display(" TXBD address: 0x%0h",tx_bd_addr); |
$finish; |
end |
else |
begin |
#1 $display( "(%0t)(%m) TX packet %0d: %0d bytes in memory OK!",$time,num_tx_packets, tx_len_bd); |
|
end |
|
|
end |
endtask // check_tx_packet |
|
|
// Local buffer of "sent" data to the ethernet MAC, we will check against |
// Size of our local buffer in bytes |
parameter eth_rx_sent_circbuf_size = (16*1024); |
parameter eth_rx_sent_circbuf_size_mask = eth_rx_sent_circbuf_size - 1; |
integer eth_rx_sent_circbuf_fill_ptr = 0; |
integer eth_rx_sent_circbuf_read_ptr = 0; |
// The actual buffer |
reg [7:0] eth_rx_sent_circbuf [0:eth_rx_sent_circbuf_size-1]; |
|
|
// |
// Task to send a set of packets |
// |
task send_packet_loop; |
input [31:0] num_packets; |
input [31:0] length; |
input [1:0] length_change; // 0 = none, 1 = incr, 2 = decrement |
input [31:0] length_change_size; // Size to change by |
input speed; |
input [31:0] back_to_back_delay; // #delay setting between packets |
input [47:0] dst_mac; |
input [47:0] src_mac; |
input random_fill; |
input random_errors; |
input [31:0] random_error_mod; |
input dont_confirm_rx; |
integer j, k; |
reg error_this_time; |
integer error_type; // 0 = rxerr, 1=bad preamble 2=bad crc 3=TODO |
reg [31:0] rx_bd_lenstat; |
begin |
error_type = 0; |
error_this_time = 0; |
|
if (num_packets == 0) |
// Loop forever when num_packets is 0 |
num_packets = 32'h7fffffff; |
|
|
if (speed & !(eth_phy0.control_bit14_10[13] === 1'b1)) |
begin |
// write to phy's control register for 100Mbps |
eth_phy0.control_bit14_10 = 5'b01000; // bit 13 set - speed 100 |
// Swapping speeds, give some delay |
#10000; |
end |
else if (!speed & !(eth_phy0.control_bit14_10[13] === 1'b0)) |
begin |
eth_phy0.control_bit14_10 = 5'b00000; // bit 13 reset - speed 10 |
// Swapping speeds, give some delay |
#10000; |
end |
|
eth_phy0.control_bit8_0 = 9'h1_00; |
|
for(j=0;j<num_packets | length <32;j=j+1) |
begin |
eth_stim_rx_packet_length = length[15:0]; // Bytes |
st_data = 8'h0F; |
|
// setup RX packet in buffer - length is without CRC |
set_rx_packet(0, eth_stim_rx_packet_length, 1'b0, dst_mac, |
src_mac, 16'h0D0E, st_data, random_fill); |
|
set_rx_addr_type(0, dst_mac, src_mac, 16'h0D0E); |
|
// Error type 2 is cause CRC error |
append_rx_crc(0, eth_stim_rx_packet_length, 1'b0, |
(error_type==2)); |
|
if (error_this_time) |
begin |
if (error_type == 0) |
// RX ERR assert during transmit |
eth_phy0.send_rx_packet(64'h0055_5555_5555_5555, 4'h7, |
8'hD5, 0, |
eth_stim_rx_packet_length+4, |
1'b0, 1'b1); |
else if (error_type == 1) |
// Incorrect preamble |
eth_phy0.send_rx_packet(64'h0055_5f55_5555_5555, 4'h7, |
8'hD5, 0, |
eth_stim_rx_packet_length+4, |
1'b0, 1'b0); |
else |
// Normal datapacket |
eth_phy0.send_rx_packet(64'h0055_5555_5555_5555, 4'h7, |
8'hD5, 0, |
eth_stim_rx_packet_length+4, |
1'b0, 1'b0); |
end |
else |
eth_phy0.send_rx_packet(64'h0055_5555_5555_5555, 4'h7, 8'hD5, |
0, eth_stim_rx_packet_length+4, 1'b0, |
1'b0); |
|
|
// if RX enable still set (might have gone low during this packet |
if (ethmac_rxen) |
begin |
if (error_this_time || dont_confirm_rx) begin |
// Put in dummy length, checking function will skip... |
rx_packet_lengths[(eth_rx_num_packets_sent& 12'h3ff)]=32'heeeeeeee; |
|
for(k=0;k<length;k=k+1) |
// skip data in verify buffer |
eth_rx_sent_circbuf_read_ptr = (eth_rx_sent_circbuf_read_ptr+1)& |
eth_rx_sent_circbuf_size_mask; |
|
end |
else |
rx_packet_lengths[(eth_rx_num_packets_sent & 12'h3ff)] = length; |
|
eth_rx_num_packets_sent = eth_rx_num_packets_sent + 1; |
|
end // if (ethmac_rxen) |
else |
begin |
// Force the loop to finish up |
j = num_packets; |
end |
|
|
// Inter-packet gap |
#back_to_back_delay; |
|
// Update length |
if (length_change == 2'b01) |
length = length + length_change_size; |
|
if ((length_change == 2'b10) && |
((length - length_change_size) > 32)) |
length = length - length_change_size; |
|
// Increment error type |
if (error_this_time) |
error_type = error_type + 1; |
if (error_type > 3) |
error_type = 0; |
|
|
// Check if we should put in an error this time |
if (j%random_error_mod == 0) |
error_this_time = 1; |
else |
error_this_time = 0; |
|
eth_phy0.rx_err(0); |
|
// Now wait to check if we have filled up all the RX BDs and |
// the this packet would start writing over them. Only really an |
// issue when doing minimum IPG tests. |
while(((eth_rx_num_packets_sent+1) - eth_rx_num_packets_checked) |
== num_rx_bds) |
#100; |
|
|
end // for (j=0;j<num_packets | length <32;j=j+1) |
end |
endtask // send_packet_loop |
|
/* |
TASKS for set and check RX packets: |
----------------------------------- |
set_rx_packet |
(rxpnt[31:0], len[15:0], plus_nibble, d_addr[47:0], s_addr[47:0], type_len[15:0], start_data[7:0]); |
check_rx_packet |
(rxpnt_phy[31:0], rxpnt_wb[31:0], len[15:0], plus_nibble, successful_nibble, failure[31:0]); |
*/ |
task set_rx_packet; |
input [31:0] rxpnt; // pointer to place in in the phy rx buffer we'll start at |
input [15:0] len; |
input plus_dribble_nibble; // if length is longer for one nibble |
input [47:0] eth_dest_addr; |
input [47:0] eth_source_addr; |
input [15:0] eth_type_len; |
input [7:0] eth_start_data; |
input random_fill; |
integer i, sd; |
reg [47:0] dest_addr; |
reg [47:0] source_addr; |
reg [15:0] type_len; |
reg [21:0] buffer; |
reg delta_t; |
|
begin |
buffer = rxpnt[21:0]; |
dest_addr = eth_dest_addr; |
source_addr = eth_source_addr; |
type_len = eth_type_len; |
sd = eth_start_data; |
delta_t = 0; |
for(i = 0; i < len; i = i + 1) |
begin |
if (i < 6) |
begin |
eth_phy0.rx_mem[buffer] = dest_addr[47:40]; |
dest_addr = dest_addr << 8; |
end |
else if (i < 12) |
begin |
eth_phy0.rx_mem[buffer] = source_addr[47:40]; |
source_addr = source_addr << 8; |
end |
else if (i < 14) |
begin |
eth_phy0.rx_mem[buffer] = type_len[15:8]; |
type_len = type_len << 8; |
end |
else |
begin |
if (random_fill) |
begin |
if (lfsr_last_byte == 0) |
eth_phy0.rx_mem[buffer] = lfsr[15:8]; |
if (lfsr_last_byte == 1) |
eth_phy0.rx_mem[buffer] = lfsr[23:16]; |
if (lfsr_last_byte == 2) |
eth_phy0.rx_mem[buffer] = lfsr[31:24]; |
if (lfsr_last_byte == 3) |
begin |
eth_phy0.rx_mem[buffer] = lfsr[7:0]; |
lfsr = {lfsr[30:0],(((lfsr[31] ^ lfsr[6]) ^ |
lfsr[5]) ^ lfsr[1])}; |
lfsr_last_byte = 0; |
end |
else |
lfsr_last_byte = lfsr_last_byte + 1; |
|
end // if (random_fill) |
else |
eth_phy0.rx_mem[buffer] = sd[7:0]; |
sd = sd + 1; |
end // else: !if(i < 14) |
|
// Update our local buffer |
eth_rx_sent_circbuf[eth_rx_sent_circbuf_fill_ptr] |
= eth_phy0.rx_mem[buffer]; |
eth_rx_sent_circbuf_fill_ptr = (eth_rx_sent_circbuf_fill_ptr+1)& |
eth_rx_sent_circbuf_size_mask; |
|
buffer = buffer + 1; |
end // for (i = 0; i < len; i = i + 1) |
|
delta_t = !delta_t; |
if (plus_dribble_nibble) |
eth_phy0.rx_mem[buffer] = {4'h0, 4'hD /*sd[3:0]*/}; |
delta_t = !delta_t; |
end |
endtask // set_rx_packet |
|
|
|
|
task set_rx_addr_type; |
input [31:0] rxpnt; |
input [47:0] eth_dest_addr; |
input [47:0] eth_source_addr; |
input [15:0] eth_type_len; |
integer i; |
reg [47:0] dest_addr; |
reg [47:0] source_addr; |
reg [15:0] type_len; |
reg [21:0] buffer; |
reg delta_t; |
begin |
buffer = rxpnt[21:0]; |
dest_addr = eth_dest_addr; |
source_addr = eth_source_addr; |
type_len = eth_type_len; |
delta_t = 0; |
for(i = 0; i < 14; i = i + 1) |
begin |
if (i < 6) |
begin |
eth_phy0.rx_mem[buffer] = dest_addr[47:40]; |
dest_addr = dest_addr << 8; |
end |
else if (i < 12) |
begin |
eth_phy0.rx_mem[buffer] = source_addr[47:40]; |
source_addr = source_addr << 8; |
end |
else // if (i < 14) |
begin |
eth_phy0.rx_mem[buffer] = type_len[15:8]; |
type_len = type_len << 8; |
end |
buffer = buffer + 1; |
end |
delta_t = !delta_t; |
end |
endtask // set_rx_addr_type |
|
|
// Check if we're using a synthesized version of eth module |
`ifdef ethmac_IS_GATELEVEL |
|
// Get the length/status register of the ethernet buffer descriptor |
task get_bd_lenstat; |
input [31:0] bd_num;// Number of ethernet BD to check |
output [31:0] bd_lenstat; |
`ifdef ACTEL |
reg [8:0] tmp; |
integer raddr; |
`endif |
begin |
`ifdef ACTEL |
|
// Pull from the Actel memory model |
raddr = `ETH_BD_RAM_PATH.\mem_tile.I_1 .get_address((bd_num*2)); |
|
tmp = `ETH_BD_RAM_PATH.\mem_tile.I_1 .MEM_512_9[(raddr*2)]; |
bd_lenstat[8:0] = tmp[8:0]; |
|
tmp = `ETH_BD_RAM_PATH.\mem_tile.I_1 .MEM_512_9[(raddr*2)+1]; |
bd_lenstat[17:9] = tmp[8:0]; |
|
raddr = `ETH_BD_RAM_PATH.\mem_tile_0.I_1 .get_address((bd_num*2)); |
|
tmp = `ETH_BD_RAM_PATH.\mem_tile_0.I_1 .MEM_512_9[(raddr*2)]; |
bd_lenstat[26:18] = tmp[8:0]; |
|
tmp = `ETH_BD_RAM_PATH.\mem_tile_0.I_1 .MEM_512_9[(raddr*2)+1]; |
bd_lenstat[31:27] = tmp[4:0]; |
|
//$display("(%t) read eth bd lenstat %h",$time, bd_lenstat); |
`endif |
end |
endtask // get_bd_lenstat |
|
// Get the length/status register of the ethernet buffer descriptor |
task get_bd_addr; |
input [31:0] bd_num;// Number of the ethernet BD to check |
output [31:0] bd_addr; |
`ifdef ACTEL |
reg [8:0] tmp; |
integer raddr; |
`endif |
begin |
`ifdef ACTEL |
// Pull from the Actel memory model |
raddr = `ETH_BD_RAM_PATH.\mem_tile.I_1 .get_address((bd_num*2)+1); |
|
tmp = `ETH_BD_RAM_PATH.\mem_tile.I_1 .MEM_512_9[(raddr*2)]; |
bd_addr[8:0] = tmp[8:0]; |
|
tmp = `ETH_BD_RAM_PATH.\mem_tile.I_1 .MEM_512_9[(raddr*2)+1]; |
bd_addr[17:9] = tmp[8:0]; |
|
raddr = `ETH_BD_RAM_PATH.\mem_tile_0.I_1 .get_address((bd_num*2)+1); |
|
tmp = `ETH_BD_RAM_PATH.\mem_tile_0.I_1 .MEM_512_9[(raddr*2)]; |
bd_addr[26:18] = tmp[8:0]; |
|
tmp = `ETH_BD_RAM_PATH.\mem_tile_0.I_1 .MEM_512_9[(raddr*2)+1]; |
bd_addr[31:27] = tmp[4:0]; |
|
//$display("(%t) read eth bd%d addr %h",$time,bd_num, bd_addr); |
`endif |
end |
endtask // get_bd_addr |
|
`else // !`ifdef ethmac_IS_GATELEVEL |
|
// Get the length/status register of the ethernet buffer descriptor |
task get_bd_lenstat; |
input [31:0] bd_num;// Number of ethernet BD to check |
output [31:0] bd_lenstat; |
begin |
bd_lenstat = `ETH_BD_RAM_PATH.mem[(bd_num*2)]; |
end |
endtask // get_bd_lenstat |
|
// Get the length/status register of the ethernet buffer descriptor |
task get_bd_addr; |
input [31:0] bd_num;// Number of the ethernet BD to check |
output [31:0] bd_addr; |
begin |
bd_addr = `ETH_BD_RAM_PATH.mem[((bd_num*2)+1)]; |
//$display("(%t) read eth bd%d addr %h",$time,bd_num, bd_addr); |
end |
endtask // get_bd_addr |
`endif |
|
// Always block triggered by finishing of transmission of new packet from |
// send_packet_loop |
integer eth_rx_packet_length_to_check; |
|
always @* |
begin |
// Loop here until: |
// 1 - packets sent is not equal to packets checked (ie. some to check) |
// 2 - we're explicitly disabled for some reason |
// 3 - Receive has been disabled in the MAC |
while((eth_rx_num_packets_sent == eth_rx_num_packets_checked) || |
!eth_stim_check_rx_packet_contents || !(ethmac_rxen===1'b1)) |
#1000; |
|
eth_rx_packet_length_to_check |
= rx_packet_lengths[(eth_rx_num_packets_checked & 12'h3ff)]; |
|
if ( eth_rx_packet_length_to_check !== 32'heeeeeeee) |
check_rx_packet(expected_rxbd, 0, eth_rx_packet_length_to_check); |
|
eth_rx_num_packets_checked = eth_rx_num_packets_checked + 1; |
|
expected_rxbd = expected_rxbd + 1; |
|
// Wrap |
if (expected_rxbd == (num_tx_bds + num_rx_bds)) |
expected_rxbd = num_tx_bds; |
end |
|
task check_rx_packet; |
|
input [31:0] rx_bd_num; |
input [31:0] rxpnt_phy; // Pointer in array of data in PHY |
input [31:0] len; |
|
reg [31:0] rx_bd_lenstat; |
reg [31:0] rx_bd_addr; |
reg [7:0] phy_byte; |
|
reg [31:0] rxpnt_wb; // Pointer in array to where data should be |
reg [24:0] rxpnt_sdram; // byte address from CPU in RAM |
reg [15:0] sdram_short; |
reg [7:0] sdram_byte; |
|
integer i; |
integer failure; |
|
begin |
|
failure = 0; |
|
// Wait until the buffer descriptor indicates the packet has been |
// received... |
get_bd_lenstat(rx_bd_num, rx_bd_lenstat); |
while (rx_bd_lenstat & 32'h00008000)// Check Empty bit |
begin |
#10; |
get_bd_lenstat(rx_bd_num, rx_bd_lenstat); |
//$display("(%t) check_rx_packet: poll bd %d: 0x%h",$time, |
// rx_bd_num, rx_bd_lenstat); |
end |
|
|
// Delay some time - takes a bit for the Wishbone FSM to pipe out the |
// packet over Wishbone and into whatever memory it's going into |
#Td_rx_packet_check; |
|
`ifdef XILINX_DDR2 |
sync_controller_cache_xilinx_ddr; |
`endif |
|
// Ok, buffer filled, let's get its offset in memory |
get_bd_addr(rx_bd_num, rx_bd_addr); |
|
$display("(%t) Check RX packet: bd %d: 0x%h, addr 0x%h",$time, |
rx_bd_num, rx_bd_lenstat, rx_bd_addr); |
|
|
// We're never going to be using more than about 256KB of receive buffer |
// so let's lop off the top bit of the address pointer - we only want |
// the offset from the base of the memory bank |
|
rxpnt_wb = {14'd0,rx_bd_addr[17:0]}; |
rxpnt_sdram = rx_bd_addr[24:0]; |
|
|
//$display("RAM pointer for BD is 0x%h, SDRAM addr is 0x%h", rx_bd_addr, rxpnt_sdram); |
|
|
for (i=0;i<len;i=i+1) |
begin |
|
sdram_byte = 8'hx; |
|
`ifdef RAM_WB |
sdram_byte = dut.ram_wb0.ram_wb_b3_0.get_mem8(rxpnt_sdram); |
`else |
`ifdef XILINX_DDR2 |
get_byte_from_xilinx_ddr2(rxpnt_sdram, sdram_byte); |
`else |
$display(" * Error:"); |
|
$display(" * eth_stim needs to be able to access the main memory to check packet rx/tx"); |
$finish; |
`endif |
`endif |
|
phy_byte = eth_rx_sent_circbuf[eth_rx_sent_circbuf_read_ptr]; |
|
if (phy_byte !== sdram_byte) |
begin |
// `TIME; |
$display("*E Wrong byte (%5d) of RX packet %5d. phy mem = %h, ram = %h", |
i, eth_rx_num_packets_checked, phy_byte, sdram_byte); |
failure = 1; |
end |
|
eth_rx_sent_circbuf_read_ptr = (eth_rx_sent_circbuf_read_ptr+1)& |
eth_rx_sent_circbuf_size_mask; |
|
rxpnt_sdram = rxpnt_sdram+1; |
|
end // for (i=0;i<len;i=i+2) |
|
if (failure) |
begin |
#100 |
`TIME; |
$display("*E Recieved packet %0d, length %0d bytes, had an error. Finishing simulation.", eth_rx_num_packets_checked, len); |
$finish; |
end |
else |
begin |
#1 $display( "(%0t)(%m) RX packet %0d: %0d bytes in memory OK!",$time,eth_rx_num_packets_checked, len); |
|
end |
end |
endtask // check_rx_packet |
|
|
////////////////////////////////////////////////////////////// |
// Ethernet CRC Basic tasks |
////////////////////////////////////////////////////////////// |
|
task append_rx_crc; |
input [31:0] rxpnt_phy; // source |
input [15:0] len; // length in bytes without CRC |
input plus_dribble_nibble; // if length is longer for one nibble |
input negated_crc; // if appended CRC is correct or not |
reg [31:0] crc; |
reg [7:0] tmp; |
reg [31:0] addr_phy; |
reg delta_t; |
begin |
addr_phy = rxpnt_phy + len; |
delta_t = 0; |
// calculate CRC from prepared packet |
paralel_crc_phy_rx(rxpnt_phy, {16'h0, len}, plus_dribble_nibble, crc); |
if (negated_crc) |
crc = ~crc; |
delta_t = !delta_t; |
|
if (plus_dribble_nibble) |
begin |
tmp = eth_phy0.rx_mem[addr_phy]; |
eth_phy0.rx_mem[addr_phy] = {crc[27:24], tmp[3:0]}; |
eth_phy0.rx_mem[addr_phy + 1] = {crc[19:16], crc[31:28]}; |
eth_phy0.rx_mem[addr_phy + 2] = {crc[11:8], crc[23:20]}; |
eth_phy0.rx_mem[addr_phy + 3] = {crc[3:0], crc[15:12]}; |
eth_phy0.rx_mem[addr_phy + 4] = {4'h0, crc[7:4]}; |
end |
else |
begin |
eth_phy0.rx_mem[addr_phy] = crc[31:24]; |
eth_phy0.rx_mem[addr_phy + 1] = crc[23:16]; |
eth_phy0.rx_mem[addr_phy + 2] = crc[15:8]; |
eth_phy0.rx_mem[addr_phy + 3] = crc[7:0]; |
end |
end |
endtask // append_rx_crc |
|
task append_rx_crc_delayed; |
input [31:0] rxpnt_phy; // source |
input [15:0] len; // length in bytes without CRC |
input plus_dribble_nibble; // if length is longer for one nibble |
input negated_crc; // if appended CRC is correct or not |
reg [31:0] crc; |
reg [7:0] tmp; |
reg [31:0] addr_phy; |
reg delta_t; |
begin |
addr_phy = rxpnt_phy + len; |
delta_t = 0; |
// calculate CRC from prepared packet |
paralel_crc_phy_rx(rxpnt_phy+4, {16'h0, len}-4, plus_dribble_nibble, crc); |
if (negated_crc) |
crc = ~crc; |
delta_t = !delta_t; |
|
if (plus_dribble_nibble) |
begin |
tmp = eth_phy0.rx_mem[addr_phy]; |
eth_phy0.rx_mem[addr_phy] = {crc[27:24], tmp[3:0]}; |
eth_phy0.rx_mem[addr_phy + 1] = {crc[19:16], crc[31:28]}; |
eth_phy0.rx_mem[addr_phy + 2] = {crc[11:8], crc[23:20]}; |
eth_phy0.rx_mem[addr_phy + 3] = {crc[3:0], crc[15:12]}; |
eth_phy0.rx_mem[addr_phy + 4] = {4'h0, crc[7:4]}; |
end |
else |
begin |
eth_phy0.rx_mem[addr_phy] = crc[31:24]; |
eth_phy0.rx_mem[addr_phy + 1] = crc[23:16]; |
eth_phy0.rx_mem[addr_phy + 2] = crc[15:8]; |
eth_phy0.rx_mem[addr_phy + 3] = crc[7:0]; |
end |
end |
endtask // append_rx_crc_delayed |
|
|
// paralel CRC calculating for PHY RX |
task paralel_crc_phy_rx; |
input [31:0] start_addr; // start address |
input [31:0] len; // length of frame in Bytes without CRC length |
input plus_dribble_nibble; // if length is longer for one nibble |
output [31:0] crc_out; |
reg [21:0] addr_cnt; // only 22 address lines |
integer word_cnt; |
integer nibble_cnt; |
reg [31:0] load_reg; |
reg delta_t; |
reg [31:0] crc_next; |
reg [31:0] crc; |
reg crc_error; |
reg [3:0] data_in; |
integer i; |
begin |
#1 addr_cnt = start_addr[21:0]; |
word_cnt = 24; // 27; // start of the frame - nibble granularity (MSbit first) |
crc = 32'hFFFF_FFFF; // INITIAL value |
delta_t = 0; |
// length must include 4 bytes of ZEROs, to generate CRC |
// get number of nibbles from Byte length (2^1 = 2) |
if (plus_dribble_nibble) |
nibble_cnt = ((len + 4) << 1) + 1'b1; // one nibble longer |
else |
nibble_cnt = ((len + 4) << 1); |
// because of MAGIC NUMBER nibbles are swapped [3:0] -> [0:3] |
load_reg[31:24] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15: 8] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[ 7: 0] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
while (nibble_cnt > 0) |
begin |
// wait for delta time |
delta_t = !delta_t; |
// shift data in |
|
if(nibble_cnt <= 8) // for additional 8 nibbles shift ZEROs in! |
data_in[3:0] = 4'h0; |
else |
|
data_in[3:0] = {load_reg[word_cnt], load_reg[word_cnt+1], load_reg[word_cnt+2], load_reg[word_cnt+3]}; |
crc_next[0] = (data_in[0] ^ crc[28]); |
crc_next[1] = (data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29]); |
crc_next[2] = (data_in[2] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[30]); |
crc_next[3] = (data_in[3] ^ data_in[2] ^ data_in[1] ^ crc[29] ^ crc[30] ^ crc[31]); |
crc_next[4] = (data_in[3] ^ data_in[2] ^ data_in[0] ^ crc[28] ^ crc[30] ^ crc[31]) ^ crc[0]; |
crc_next[5] = (data_in[3] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[31]) ^ crc[1]; |
crc_next[6] = (data_in[2] ^ data_in[1] ^ crc[29] ^ crc[30]) ^ crc[ 2]; |
crc_next[7] = (data_in[3] ^ data_in[2] ^ data_in[0] ^ crc[28] ^ crc[30] ^ crc[31]) ^ crc[3]; |
crc_next[8] = (data_in[3] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[31]) ^ crc[4]; |
crc_next[9] = (data_in[2] ^ data_in[1] ^ crc[29] ^ crc[30]) ^ crc[5]; |
crc_next[10] = (data_in[3] ^ data_in[2] ^ data_in[0] ^ crc[28] ^ crc[30] ^ crc[31]) ^ crc[6]; |
crc_next[11] = (data_in[3] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[31]) ^ crc[7]; |
crc_next[12] = (data_in[2] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[30]) ^ crc[8]; |
crc_next[13] = (data_in[3] ^ data_in[2] ^ data_in[1] ^ crc[29] ^ crc[30] ^ crc[31]) ^ crc[9]; |
crc_next[14] = (data_in[3] ^ data_in[2] ^ crc[30] ^ crc[31]) ^ crc[10]; |
crc_next[15] = (data_in[3] ^ crc[31]) ^ crc[11]; |
crc_next[16] = (data_in[0] ^ crc[28]) ^ crc[12]; |
crc_next[17] = (data_in[1] ^ crc[29]) ^ crc[13]; |
crc_next[18] = (data_in[2] ^ crc[30]) ^ crc[14]; |
crc_next[19] = (data_in[3] ^ crc[31]) ^ crc[15]; |
crc_next[20] = crc[16]; |
crc_next[21] = crc[17]; |
crc_next[22] = (data_in[0] ^ crc[28]) ^ crc[18]; |
crc_next[23] = (data_in[1] ^ data_in[0] ^ crc[29] ^ crc[28]) ^ crc[19]; |
crc_next[24] = (data_in[2] ^ data_in[1] ^ crc[30] ^ crc[29]) ^ crc[20]; |
crc_next[25] = (data_in[3] ^ data_in[2] ^ crc[31] ^ crc[30]) ^ crc[21]; |
crc_next[26] = (data_in[3] ^ data_in[0] ^ crc[31] ^ crc[28]) ^ crc[22]; |
crc_next[27] = (data_in[1] ^ crc[29]) ^ crc[23]; |
crc_next[28] = (data_in[2] ^ crc[30]) ^ crc[24]; |
crc_next[29] = (data_in[3] ^ crc[31]) ^ crc[25]; |
crc_next[30] = crc[26]; |
crc_next[31] = crc[27]; |
|
crc = crc_next; |
crc_error = crc[31:0] != 32'hc704dd7b; // CRC not equal to magic number |
case (nibble_cnt) |
9: crc_out = {!crc[24], !crc[25], !crc[26], !crc[27], !crc[28], !crc[29], !crc[30], !crc[31], |
!crc[16], !crc[17], !crc[18], !crc[19], !crc[20], !crc[21], !crc[22], !crc[23], |
!crc[ 8], !crc[ 9], !crc[10], !crc[11], !crc[12], !crc[13], !crc[14], !crc[15], |
!crc[ 0], !crc[ 1], !crc[ 2], !crc[ 3], !crc[ 4], !crc[ 5], !crc[ 6], !crc[ 7]}; |
default: crc_out = crc_out; |
endcase |
// wait for delta time |
delta_t = !delta_t; |
// increment address and load new data |
if ((word_cnt+3) == 7)//4) |
begin |
// because of MAGIC NUMBER nibbles are swapped [3:0] -> [0:3] |
load_reg[31:24] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15: 8] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[ 7: 0] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
end |
// set new load bit position |
if((word_cnt+3) == 31) |
word_cnt = 16; |
else if ((word_cnt+3) == 23) |
word_cnt = 8; |
else if ((word_cnt+3) == 15) |
word_cnt = 0; |
else if ((word_cnt+3) == 7) |
word_cnt = 24; |
else |
word_cnt = word_cnt + 4;// - 4; |
// decrement nibble counter |
nibble_cnt = nibble_cnt - 1; |
// wait for delta time |
delta_t = !delta_t; |
end // while |
#1; |
end |
endtask // paralel_crc_phy_rx |
|
|
|
|
/xilinx/atlys/bench/verilog/include/eth_phy_defines.v
0,0 → 1,91
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name: eth_phy_defines.v //// |
//// //// |
//// This file is part of the Ethernet IP core project //// |
//// http://www.opencores.org/projects/ethmac/ //// |
//// //// |
//// Author(s): //// |
//// - Tadej Markovic, tadej@opencores.org //// |
//// //// |
//// All additional information is available in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2002, Authors //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.1 2002/09/13 11:57:20 mohor |
// New testbench. Thanks to Tadej M - "The Spammer". |
// |
// |
// |
|
// Address of PHY device (LXT971A) |
`define ETH_PHY_ADDR 5'h00 //Changed to 0 -jb |
|
// LED/Configuration pins on PHY device - see the specification, page 26, table 8 |
// Initial set of bits 13, 12 and 8 of Control Register |
`define LED_CFG1 1'b0 |
`define LED_CFG2 1'b1 |
`define LED_CFG3 1'b1 |
|
|
// Supported speeds and physical ports - see the specification, page 67, table 41 |
// Set bits 15 to 9 of Status Register |
`define SUPPORTED_SPEED_AND_PORT 7'h3F |
|
// Extended status register (address 15) |
// Set bit 8 of Status Register |
`define EXTENDED_STATUS 1'b0 |
|
// Default status bits - see the specification, page 67, table 41 |
// Set bits 6 to 0 of Status Register |
`define DEFAULT_STATUS 7'h09 |
|
// PHY ID 1 number - see the specification, page 68, table 42 |
// Set bits of Phy Id Register 1 |
`define PHY_ID1 16'h0013 |
|
// PHY ID 2 number - see the specification, page 68, table 43 |
// Set bits 15 to 10 of Phy Id Register 2 |
`define PHY_ID2 6'h1E |
|
// Manufacturer MODEL number - see the specification, page 68, table 43 |
// Set bits 9 to 4 of Phy Id Register 2 |
`define MAN_MODEL_NUM 6'h0E |
|
// Manufacturer REVISION number - see the specification, page 68, table 43 |
// Set bits 3 to 0 of Phy Id Register 2 |
`define MAN_REVISION_NUM 4'h2 |
|
|
|
|
/xilinx/atlys/bench/verilog/include/ddr2_model_parameters.v
0,0 → 1,1399
/**************************************************************************************** |
* |
* Disclaimer This software code and all associated documentation, comments or other |
* of Warranty: information (collectively "Software") is provided "AS IS" without |
* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY |
* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES |
* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT |
* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE |
* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE. |
* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR |
* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, |
* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE |
* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI, |
* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT, |
* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING, |
* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, |
* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE |
* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
* DAMAGES. Because some jurisdictions prohibit the exclusion or |
* limitation of liability for consequential or incidental damages, the |
* above limitation may not apply to you. |
* |
* Copyright 2003 Micron Technology, Inc. All rights reserved. |
* |
****************************************************************************************/ |
|
// Timing parameters based on Speed Grade |
|
// SYMBOL UNITS DESCRIPTION |
// ------ ----- ----------- |
`define x1Gb |
`define x16 |
`define sg25E |
|
`ifdef x256Mb |
|
`ifdef sg187E |
parameter TCK_MIN = 1875; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 90; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 75; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 180; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 132; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 157; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 175; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 188; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 250; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 425; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 250; // tQHS ps Data hold skew factor |
parameter TAC = 350; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 0; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 75; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 300; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 175; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 125; // tIS ps Input Setup Time |
parameter TIH = 200; // tIH ps Input Hold Time |
parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 13125; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 13125; // tRP ps Precharge command period |
parameter TRPA = 13125; // tRPA ps Precharge All period |
parameter TXARDS = 10; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 3; // tXARD tCK Exit active power down to a read command |
parameter TXP = 3; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 4; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 11; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 13125; // CL ps Minimum CAS Latency |
`else `ifdef sg25E |
parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 100; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 300; // tQHS ps Data hold skew factor |
parameter TAC = 400; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 175; // tIS ps Input Setup Time |
parameter TIH = 250; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 12500; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 12500; // tRP ps Precharge command period |
parameter TRPA = 12500; // tRPA ps Precharge All period |
parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 12500; // CL ps Minimum CAS Latency |
`else `ifdef sg25 |
parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 100; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 300; // tQHS ps Data hold skew factor |
parameter TAC = 400; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 175; // tIS ps Input Setup Time |
parameter TIH = 250; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `ifdef sg3E |
parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 340; // tQHS ps Data hold skew factor |
parameter TAC = 450; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 200; // tIS ps Input Setup Time |
parameter TIH = 275; // tIH ps Input Hold Time |
parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 12000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 12000; // tRP ps Precharge command period |
parameter TRPA = 12000; // tRPA ps Precharge All period |
parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 12000; // CL ps Minimum CAS Latency |
`else `ifdef sg3 |
parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 340; // tQHS ps Data hold skew factor |
parameter TAC = 450; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 200; // tIS ps Input Setup Time |
parameter TIH = 275; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `ifdef sg37E |
parameter TCK_MIN = 3750; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 400; // tQHS ps Data hold skew factor |
parameter TAC = 500; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 225; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 450; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 300; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 250; // tIS ps Input Setup Time |
parameter TIH = 375; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `define sg5E |
parameter TCK_MIN = 5000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 150; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 450; // tQHS ps Data hold skew factor |
parameter TAC = 600; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 150; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 275; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 500; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 350; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 350; // tIS ps Input Setup Time |
parameter TIH = 475; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 10000; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`endif `endif `endif `endif `endif `endif |
|
`ifdef x16 |
`ifdef sg187E |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25E |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25 |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else // sg3E, sg3, sg37E, sg5E |
parameter TFAW = 50000; // tFAW ps Four Bank Activate window |
`endif `endif `endif |
`else // x4, x8 |
`ifdef sg187E |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25E |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25 |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else // sg3E, sg3, sg37E, sg5E |
parameter TFAW = 37500; // tFAW ps Four Bank Activate window |
`endif `endif `endif |
`endif |
|
// Timing Parameters |
|
// Mode Register |
parameter AL_MIN = 0; // AL tCK Minimum Additive Latency |
parameter AL_MAX = 6; // AL tCK Maximum Additive Latency |
parameter CL_MIN = 3; // CL tCK Minimum CAS Latency |
parameter CL_MAX = 7; // CL tCK Maximum CAS Latency |
parameter WR_MIN = 2; // WR tCK Minimum Write Recovery |
parameter WR_MAX = 8; // WR tCK Maximum Write Recovery |
parameter BL_MIN = 4; // BL tCK Minimum Burst Length |
parameter BL_MAX = 8; // BL tCK Minimum Burst Length |
// Clock |
parameter TCK_MAX = 8000; // tCK ps Maximum Clock Cycle Time |
parameter TCH_MIN = 0.48; // tCH tCK Minimum Clock High-Level Pulse Width |
parameter TCH_MAX = 0.52; // tCH tCK Maximum Clock High-Level Pulse Width |
parameter TCL_MIN = 0.48; // tCL tCK Minimum Clock Low-Level Pulse Width |
parameter TCL_MAX = 0.52; // tCL tCK Maximum Clock Low-Level Pulse Width |
// Data |
parameter TLZ = TAC; // tLZ ps Data-out low-impedance window from CK/CK# |
parameter THZ = TAC; // tHZ ps Data-out high impedance window from CK/CK# |
parameter TDIPW = 0.35; // tDIPW tCK DQ and DM input Pulse Width |
// Data Strobe |
parameter TDQSH = 0.35; // tDQSH tCK DQS input High Pulse Width |
parameter TDQSL = 0.35; // tDQSL tCK DQS input Low Pulse Width |
parameter TDSS = 0.20; // tDSS tCK DQS falling edge to CLK rising (setup time) |
parameter TDSH = 0.20; // tDSH tCK DQS falling edge from CLK rising (hold time) |
parameter TWPRE = 0.35; // tWPRE tCK DQS Write Preamble |
parameter TWPST = 0.40; // tWPST tCK DQS Write Postamble |
parameter TDQSS = 0.25; // tDQSS tCK Rising clock edge to DQS/DQS# latching transition |
// Command and Address |
parameter TIPW = 0.6; // tIPW tCK Control and Address input Pulse Width |
parameter TCCD = 2; // tCCD tCK Cas to Cas command delay |
parameter TRAS_MIN = 40000; // tRAS ps Minimum Active to Precharge command time |
parameter TRAS_MAX =70000000; // tRAS ps Maximum Active to Precharge command time |
parameter TRTP = 7500; // tRTP ps Read to Precharge command delay |
parameter TWR = 15000; // tWR ps Write recovery time |
parameter TMRD = 2; // tMRD tCK Load Mode Register command cycle time |
parameter TDLLK = 200; // tDLLK tCK DLL locking time |
// Refresh |
parameter TRFC_MIN = 75000; // tRFC ps Refresh to Refresh Command interval minimum value |
parameter TRFC_MAX =70000000; // tRFC ps Refresh to Refresh Command Interval maximum value |
// Self Refresh |
parameter TXSNR = TRFC_MIN + 10000; // tXSNR ps Exit self refesh to a non-read command |
parameter TXSRD = 200; // tXSRD tCK Exit self refresh to a read command |
parameter TISXR = TIS; // tISXR ps CKE setup time during self refresh exit. |
// ODT |
parameter TAOND = 2; // tAOND tCK ODT turn-on delay |
parameter TAOFD = 2.5; // tAOFD tCK ODT turn-off delay |
parameter TAONPD = 2000; // tAONPD ps ODT turn-on (precharge power-down mode) |
parameter TAOFPD = 2000; // tAOFPD ps ODT turn-off (precharge power-down mode) |
parameter TMOD = 12000; // tMOD ps ODT enable in EMR to ODT pin transition |
// Power Down |
parameter TCKE = 3; // tCKE tCK CKE minimum high or low pulse width |
|
// Size Parameters based on Part Width |
|
`ifdef x4 |
parameter DM_BITS = 1; // Number of Data Mask bits |
parameter ROW_BITS = 13; // Number of Address bits |
parameter COL_BITS = 11; // Number of Column bits |
parameter DQ_BITS = 4; // Number of Data bits |
parameter DQS_BITS = 1; // Number of Dqs bits |
parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time |
`else `ifdef x8 |
parameter DM_BITS = 1; // Number of Data Mask bits |
parameter ROW_BITS = 13; // Number of Address bits |
parameter COL_BITS = 10; // Number of Column bits |
parameter DQ_BITS = 8; // Number of Data bits |
parameter DQS_BITS = 1; // Number of Dqs bits |
parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time |
`else `define x16 |
parameter DM_BITS = 2; // Number of Data Mask bits |
parameter ROW_BITS = 13; // Number of Address bits |
parameter COL_BITS = 9; // Number of Column bits |
parameter DQ_BITS = 16; // Number of Data bits |
parameter DQS_BITS = 2; // Number of Dqs bits |
parameter TRRD = 10000; // tRRD Active bank a to Active bank b command time |
`endif `endif |
|
`ifdef QUAD_RANK |
`define DUAL_RANK // also define DUAL_RANK |
parameter CS_BITS = 4; // Number of Chip Select Bits |
parameter RANKS = 4; // Number of Chip Select Bits |
`else `ifdef DUAL_RANK |
parameter CS_BITS = 2; // Number of Chip Select Bits |
parameter RANKS = 2; // Number of Chip Select Bits |
`else |
parameter CS_BITS = 2; // Number of Chip Select Bits |
parameter RANKS = 1; // Number of Chip Select Bits |
`endif `endif |
|
// Size Parameters |
parameter BA_BITS = 2; // Set this parmaeter to control how many Bank Address bits |
parameter ADDR_BITS = 13; // Address Bits |
parameter MEM_BITS = 10; // Number of write data bursts can be stored in memory. The default is 2^10=1024. |
parameter AP = 10; // the address bit that controls auto-precharge and precharge-all |
parameter BL_BITS = 3; // the number of bits required to count to MAX_BL |
parameter BO_BITS = 2; // the number of Burst Order Bits |
|
`else `ifdef x512Mb |
|
`ifdef sg187E |
parameter TCK_MIN = 1875; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 90; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 75; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 180; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 132; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 157; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 175; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 188; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 250; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 425; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 250; // tQHS ps Data hold skew factor |
parameter TAC = 350; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 0; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 75; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 300; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 175; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 125; // tIS ps Input Setup Time |
parameter TIH = 200; // tIH ps Input Hold Time |
parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 13125; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 13125; // tRP ps Precharge command period |
parameter TRPA = 13125; // tRPA ps Precharge All period |
parameter TXARDS = 10; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 3; // tXARD tCK Exit active power down to a read command |
parameter TXP = 3; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 4; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 11; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 13125; // CL ps Minimum CAS Latency |
`else `ifdef sg25E |
parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 100; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 300; // tQHS ps Data hold skew factor |
parameter TAC = 400; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 175; // tIS ps Input Setup Time |
parameter TIH = 250; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 12500; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 12500; // tRP ps Precharge command period |
parameter TRPA = 12500; // tRPA ps Precharge All period |
parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 12500; // CL ps Minimum CAS Latency |
`else `ifdef sg25 |
parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 100; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 300; // tQHS ps Data hold skew factor |
parameter TAC = 400; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 175; // tIS ps Input Setup Time |
parameter TIH = 250; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `ifdef sg3E |
parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 340; // tQHS ps Data hold skew factor |
parameter TAC = 450; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 200; // tIS ps Input Setup Time |
parameter TIH = 275; // tIH ps Input Hold Time |
parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 12000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 12000; // tRP ps Precharge command period |
parameter TRPA = 12000; // tRPA ps Precharge All period |
parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 12000; // CL ps Minimum CAS Latency |
`else `ifdef sg3 |
parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 340; // tQHS ps Data hold skew factor |
parameter TAC = 450; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 200; // tIS ps Input Setup Time |
parameter TIH = 275; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `ifdef sg37E |
parameter TCK_MIN = 3750; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 400; // tQHS ps Data hold skew factor |
parameter TAC = 500; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 225; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 450; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 300; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 250; // tIS ps Input Setup Time |
parameter TIH = 375; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `define sg5E |
parameter TCK_MIN = 5000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 150; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 450; // tQHS ps Data hold skew factor |
parameter TAC = 600; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 150; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 275; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 500; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 350; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 350; // tIS ps Input Setup Time |
parameter TIH = 475; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 10000; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`endif `endif `endif `endif `endif `endif |
|
`ifdef x16 |
`ifdef sg187E |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25E |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25 |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else // sg3E, sg3, sg37E, sg5E |
parameter TFAW = 50000; // tFAW ps Four Bank Activate window |
`endif `endif `endif |
`else // x4, x8 |
`ifdef sg187E |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25E |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25 |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else // sg3E, sg3, sg37E, sg5E |
parameter TFAW = 37500; // tFAW ps Four Bank Activate window |
`endif `endif `endif |
`endif |
|
// Timing Parameters |
|
// Mode Register |
parameter AL_MIN = 0; // AL tCK Minimum Additive Latency |
parameter AL_MAX = 6; // AL tCK Maximum Additive Latency |
parameter CL_MIN = 3; // CL tCK Minimum CAS Latency |
parameter CL_MAX = 7; // CL tCK Maximum CAS Latency |
parameter WR_MIN = 2; // WR tCK Minimum Write Recovery |
parameter WR_MAX = 8; // WR tCK Maximum Write Recovery |
parameter BL_MIN = 4; // BL tCK Minimum Burst Length |
parameter BL_MAX = 8; // BL tCK Minimum Burst Length |
// Clock |
parameter TCK_MAX = 8000; // tCK ps Maximum Clock Cycle Time |
parameter TCH_MIN = 0.48; // tCH tCK Minimum Clock High-Level Pulse Width |
parameter TCH_MAX = 0.52; // tCH tCK Maximum Clock High-Level Pulse Width |
parameter TCL_MIN = 0.48; // tCL tCK Minimum Clock Low-Level Pulse Width |
parameter TCL_MAX = 0.52; // tCL tCK Maximum Clock Low-Level Pulse Width |
// Data |
parameter TLZ = TAC; // tLZ ps Data-out low-impedance window from CK/CK# |
parameter THZ = TAC; // tHZ ps Data-out high impedance window from CK/CK# |
parameter TDIPW = 0.35; // tDIPW tCK DQ and DM input Pulse Width |
// Data Strobe |
parameter TDQSH = 0.35; // tDQSH tCK DQS input High Pulse Width |
parameter TDQSL = 0.35; // tDQSL tCK DQS input Low Pulse Width |
parameter TDSS = 0.20; // tDSS tCK DQS falling edge to CLK rising (setup time) |
parameter TDSH = 0.20; // tDSH tCK DQS falling edge from CLK rising (hold time) |
parameter TWPRE = 0.35; // tWPRE tCK DQS Write Preamble |
parameter TWPST = 0.40; // tWPST tCK DQS Write Postamble |
parameter TDQSS = 0.25; // tDQSS tCK Rising clock edge to DQS/DQS# latching transition |
// Command and Address |
parameter TIPW = 0.6; // tIPW tCK Control and Address input Pulse Width |
parameter TCCD = 2; // tCCD tCK Cas to Cas command delay |
parameter TRAS_MIN = 40000; // tRAS ps Minimum Active to Precharge command time |
parameter TRAS_MAX =70000000; // tRAS ps Maximum Active to Precharge command time |
parameter TRTP = 7500; // tRTP ps Read to Precharge command delay |
parameter TWR = 15000; // tWR ps Write recovery time |
parameter TMRD = 2; // tMRD tCK Load Mode Register command cycle time |
parameter TDLLK = 200; // tDLLK tCK DLL locking time |
// Refresh |
parameter TRFC_MIN = 105000; // tRFC ps Refresh to Refresh Command interval minimum value |
parameter TRFC_MAX =70000000; // tRFC ps Refresh to Refresh Command Interval maximum value |
// Self Refresh |
parameter TXSNR = TRFC_MIN + 10000; // tXSNR ps Exit self refesh to a non-read command |
parameter TXSRD = 200; // tXSRD tCK Exit self refresh to a read command |
parameter TISXR = TIS; // tISXR ps CKE setup time during self refresh exit. |
// ODT |
parameter TAOND = 2; // tAOND tCK ODT turn-on delay |
parameter TAOFD = 2.5; // tAOFD tCK ODT turn-off delay |
parameter TAONPD = 2000; // tAONPD ps ODT turn-on (precharge power-down mode) |
parameter TAOFPD = 2000; // tAOFPD ps ODT turn-off (precharge power-down mode) |
parameter TMOD = 12000; // tMOD ps ODT enable in EMR to ODT pin transition |
// Power Down |
parameter TCKE = 3; // tCKE tCK CKE minimum high or low pulse width |
|
// Size Parameters based on Part Width |
|
`ifdef x4 |
parameter ADDR_BITS = 14; // Address Bits |
parameter ROW_BITS = 14; // Number of Address bits |
parameter COL_BITS = 11; // Number of Column bits |
parameter DM_BITS = 1; // Number of Data Mask bits |
parameter DQ_BITS = 4; // Number of Data bits |
parameter DQS_BITS = 1; // Number of Dqs bits |
parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time |
`else `ifdef x8 |
parameter ADDR_BITS = 14; // Address Bits |
parameter ROW_BITS = 14; // Number of Address bits |
parameter COL_BITS = 10; // Number of Column bits |
parameter DM_BITS = 1; // Number of Data Mask bits |
parameter DQ_BITS = 8; // Number of Data bits |
parameter DQS_BITS = 1; // Number of Dqs bits |
parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time |
`else `define x16 |
parameter ADDR_BITS = 13; // Address Bits |
parameter ROW_BITS = 13; // Number of Address bits |
parameter COL_BITS = 10; // Number of Column bits |
parameter DM_BITS = 2; // Number of Data Mask bits |
parameter DQ_BITS = 16; // Number of Data bits |
parameter DQS_BITS = 2; // Number of Dqs bits |
parameter TRRD = 10000; // tRRD Active bank a to Active bank b command time |
`endif `endif |
|
`ifdef QUAD_RANK |
`define DUAL_RANK // also define DUAL_RANK |
parameter CS_BITS = 4; // Number of Chip Select Bits |
parameter RANKS = 4; // Number of Chip Select Bits |
`else `ifdef DUAL_RANK |
parameter CS_BITS = 2; // Number of Chip Select Bits |
parameter RANKS = 2; // Number of Chip Select Bits |
`else |
parameter CS_BITS = 2; // Number of Chip Select Bits |
parameter RANKS = 1; // Number of Chip Select Bits |
`endif `endif |
|
// Size Parameters |
parameter BA_BITS = 2; // Set this parmaeter to control how many Bank Address bits |
parameter MEM_BITS = 10; // Number of write data bursts can be stored in memory. The default is 2^10=1024. |
parameter AP = 10; // the address bit that controls auto-precharge and precharge-all |
parameter BL_BITS = 3; // the number of bits required to count to MAX_BL |
parameter BO_BITS = 2; // the number of Burst Order Bits |
|
`else `ifdef x1Gb |
|
`ifdef sg187E |
parameter TCK_MIN = 1875; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 90; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 75; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 180; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 132; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 157; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 175; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 188; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 250; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 425; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 250; // tQHS ps Data hold skew factor |
parameter TAC = 350; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 0; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 75; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 300; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 175; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 125; // tIS ps Input Setup Time |
parameter TIH = 200; // tIH ps Input Hold Time |
parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 13125; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 13125; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 10; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 3; // tXARD tCK Exit active power down to a read command |
parameter TXP = 3; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 4; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 11; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 13125; // CL ps Minimum CAS Latency |
`else `ifdef sg25E |
parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 100; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 300; // tQHS ps Data hold skew factor |
parameter TAC = 400; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 175; // tIS ps Input Setup Time |
parameter TIH = 250; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 12500; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 12500; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 12500; // CL ps Minimum CAS Latency |
`else `ifdef sg25 |
parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 100; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 300; // tQHS ps Data hold skew factor |
parameter TAC = 400; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 175; // tIS ps Input Setup Time |
parameter TIH = 250; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 17500; // tRPA ps Precharge All period |
parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `ifdef sg3E |
parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 340; // tQHS ps Data hold skew factor |
parameter TAC = 450; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 200; // tIS ps Input Setup Time |
parameter TIH = 275; // tIH ps Input Hold Time |
parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 12000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 12000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 12000; // CL ps Minimum CAS Latency |
`else `ifdef sg3 |
parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 340; // tQHS ps Data hold skew factor |
parameter TAC = 450; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 200; // tIS ps Input Setup Time |
parameter TIH = 275; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 18000; // tRPA ps Precharge All period |
parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `ifdef sg37E |
parameter TCK_MIN = 3750; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 400; // tQHS ps Data hold skew factor |
parameter TAC = 500; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 225; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 450; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 300; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 250; // tIS ps Input Setup Time |
parameter TIH = 375; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 18750; // tRPA ps Precharge All period |
parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `define sg5E |
parameter TCK_MIN = 5000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 150; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 450; // tQHS ps Data hold skew factor |
parameter TAC = 600; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 150; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 275; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 500; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 350; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 350; // tIS ps Input Setup Time |
parameter TIH = 475; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 10000; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 20000; // tRPA ps Precharge All period |
parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`endif `endif `endif `endif `endif `endif |
|
`ifdef x16 |
`ifdef sg187E |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25E |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25 |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else // sg3E, sg3, sg37E, sg5E |
parameter TFAW = 50000; // tFAW ps Four Bank Activate window |
`endif `endif `endif |
`else // x4, x8 |
`ifdef sg187E |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25E |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25 |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else // sg3E, sg3, sg37E, sg5E |
parameter TFAW = 37500; // tFAW ps Four Bank Activate window |
`endif `endif `endif |
`endif |
|
// Timing Parameters |
|
// Mode Register |
parameter AL_MIN = 0; // AL tCK Minimum Additive Latency |
parameter AL_MAX = 6; // AL tCK Maximum Additive Latency |
parameter CL_MIN = 3; // CL tCK Minimum CAS Latency |
parameter CL_MAX = 7; // CL tCK Maximum CAS Latency |
parameter WR_MIN = 2; // WR tCK Minimum Write Recovery |
parameter WR_MAX = 8; // WR tCK Maximum Write Recovery |
parameter BL_MIN = 4; // BL tCK Minimum Burst Length |
parameter BL_MAX = 8; // BL tCK Minimum Burst Length |
// Clock |
parameter TCK_MAX = 8000; // tCK ps Maximum Clock Cycle Time |
parameter TCH_MIN = 0.48; // tCH tCK Minimum Clock High-Level Pulse Width |
parameter TCH_MAX = 0.52; // tCH tCK Maximum Clock High-Level Pulse Width |
parameter TCL_MIN = 0.48; // tCL tCK Minimum Clock Low-Level Pulse Width |
parameter TCL_MAX = 0.52; // tCL tCK Maximum Clock Low-Level Pulse Width |
// Data |
parameter TLZ = TAC; // tLZ ps Data-out low-impedance window from CK/CK# |
parameter THZ = TAC; // tHZ ps Data-out high impedance window from CK/CK# |
parameter TDIPW = 0.35; // tDIPW tCK DQ and DM input Pulse Width |
// Data Strobe |
parameter TDQSH = 0.35; // tDQSH tCK DQS input High Pulse Width |
parameter TDQSL = 0.35; // tDQSL tCK DQS input Low Pulse Width |
parameter TDSS = 0.20; // tDSS tCK DQS falling edge to CLK rising (setup time) |
parameter TDSH = 0.20; // tDSH tCK DQS falling edge from CLK rising (hold time) |
parameter TWPRE = 0.35; // tWPRE tCK DQS Write Preamble |
parameter TWPST = 0.40; // tWPST tCK DQS Write Postamble |
parameter TDQSS = 0.25; // tDQSS tCK Rising clock edge to DQS/DQS# latching transition |
// Command and Address |
parameter TIPW = 0.6; // tIPW tCK Control and Address input Pulse Width |
parameter TCCD = 2; // tCCD tCK Cas to Cas command delay |
parameter TRAS_MIN = 40000; // tRAS ps Minimum Active to Precharge command time |
parameter TRAS_MAX =70000000; // tRAS ps Maximum Active to Precharge command time |
parameter TRTP = 7500; // tRTP ps Read to Precharge command delay |
parameter TWR = 15000; // tWR ps Write recovery time |
parameter TMRD = 2; // tMRD tCK Load Mode Register command cycle time |
parameter TDLLK = 200; // tDLLK tCK DLL locking time |
// Refresh |
parameter TRFC_MIN = 127500; // tRFC ps Refresh to Refresh Command interval minimum value |
parameter TRFC_MAX =70000000; // tRFC ps Refresh to Refresh Command Interval maximum value |
// Self Refresh |
parameter TXSNR = TRFC_MIN + 10000; // tXSNR ps Exit self refesh to a non-read command |
parameter TXSRD = 200; // tXSRD tCK Exit self refresh to a read command |
parameter TISXR = TIS; // tISXR ps CKE setup time during self refresh exit. |
// ODT |
parameter TAOND = 2; // tAOND tCK ODT turn-on delay |
parameter TAOFD = 2.5; // tAOFD tCK ODT turn-off delay |
parameter TAONPD = 2000; // tAONPD ps ODT turn-on (precharge power-down mode) |
parameter TAOFPD = 2000; // tAOFPD ps ODT turn-off (precharge power-down mode) |
parameter TMOD = 12000; // tMOD ps ODT enable in EMR to ODT pin transition |
// Power Down |
parameter TCKE = 3; // tCKE tCK CKE minimum high or low pulse width |
|
// Size Parameters based on Part Width |
|
`ifdef x4 |
parameter ADDR_BITS = 14; // Address Bits |
parameter ROW_BITS = 14; // Number of Address bits |
parameter COL_BITS = 11; // Number of Column bits |
parameter DM_BITS = 1; // Number of Data Mask bits |
parameter DQ_BITS = 4; // Number of Data bits |
parameter DQS_BITS = 1; // Number of Dqs bits |
parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time |
`else `ifdef x8 |
parameter ADDR_BITS = 14; // Address Bits |
parameter ROW_BITS = 14; // Number of Address bits |
parameter COL_BITS = 10; // Number of Column bits |
parameter DM_BITS = 1; // Number of Data Mask bits |
parameter DQ_BITS = 8; // Number of Data bits |
parameter DQS_BITS = 1; // Number of Dqs bits |
parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time |
`else `define x16 |
parameter ADDR_BITS = 13; // Address Bits |
parameter ROW_BITS = 13; // Number of Address bits |
parameter COL_BITS = 10; // Number of Column bits |
parameter DM_BITS = 2; // Number of Data Mask bits |
parameter DQ_BITS = 16; // Number of Data bits |
parameter DQS_BITS = 2; // Number of Dqs bits |
parameter TRRD = 10000; // tRRD Active bank a to Active bank b command time |
`endif `endif |
|
`ifdef QUAD_RANK |
`define DUAL_RANK // also define DUAL_RANK |
parameter CS_BITS = 4; // Number of Chip Select Bits |
parameter RANKS = 4; // Number of Chip Select Bits |
`else `ifdef DUAL_RANK |
parameter CS_BITS = 2; // Number of Chip Select Bits |
parameter RANKS = 2; // Number of Chip Select Bits |
`else |
parameter CS_BITS = 2; // Number of Chip Select Bits |
parameter RANKS = 1; // Number of Chip Select Bits |
`endif `endif |
|
// Size Parameters |
parameter BA_BITS = 3; // Set this parmaeter to control how many Bank Address bits |
//parameter MEM_BITS = 10; // Number of write data bursts can be stored in memory. The default is 2^10=1024. |
parameter MEM_BITS = 17; // Number of write data bursts can be stored in memory. |
parameter AP = 10; // the address bit that controls auto-precharge and precharge-all |
parameter BL_BITS = 3; // the number of bits required to count to MAX_BL |
parameter BO_BITS = 2; // the number of Burst Order Bits |
|
`else `define x2Gb |
|
`ifdef sg187E |
parameter TCK_MIN = 1875; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 90; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 75; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 180; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 132; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 157; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 175; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 188; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 250; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 425; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 250; // tQHS ps Data hold skew factor |
parameter TAC = 350; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 0; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 75; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 300; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 175; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 125; // tIS ps Input Setup Time |
parameter TIH = 200; // tIH ps Input Hold Time |
parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 13125; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 13125; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 10; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 3; // tXARD tCK Exit active power down to a read command |
parameter TXP = 3; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 4; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 11; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 13125; // CL ps Minimum CAS Latency |
`else `ifdef sg25E |
parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 100; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 300; // tQHS ps Data hold skew factor |
parameter TAC = 400; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 175; // tIS ps Input Setup Time |
parameter TIH = 250; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 12500; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 12500; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 12500; // CL ps Minimum CAS Latency |
`else `ifdef sg25 |
parameter TCK_MIN = 2500; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 100; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 100; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 200; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 150; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 175; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 200; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 200; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 300; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 300; // tQHS ps Data hold skew factor |
parameter TAC = 400; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 50; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 125; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 350; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 200; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 175; // tIS ps Input Setup Time |
parameter TIH = 250; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 17500; // tRPA ps Precharge All period |
parameter TXARDS = 8; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 10; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `ifdef sg3E |
parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 340; // tQHS ps Data hold skew factor |
parameter TAC = 450; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 200; // tIS ps Input Setup Time |
parameter TIH = 275; // tIH ps Input Hold Time |
parameter TRC = 54000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 12000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 12000; // tRP ps Precharge command period |
parameter TRPA = 15000; // tRPA ps Precharge All period |
parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 12000; // CL ps Minimum CAS Latency |
`else `ifdef sg3 |
parameter TCK_MIN = 3000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 340; // tQHS ps Data hold skew factor |
parameter TAC = 450; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 175; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 400; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 240; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 200; // tIS ps Input Setup Time |
parameter TIH = 275; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 18000; // tRPA ps Precharge All period |
parameter TXARDS = 7; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `ifdef sg37E |
parameter TCK_MIN = 3750; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 125; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 400; // tQHS ps Data hold skew factor |
parameter TAC = 500; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 100; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 225; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 450; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 300; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 250; // tIS ps Input Setup Time |
parameter TIH = 375; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 7500; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 18750; // tRPA ps Precharge All period |
parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`else `define sg5E |
parameter TCK_MIN = 5000; // tCK ps Minimum Clock Cycle Time |
parameter TJIT_PER = 125; // tJIT(per) ps Period JItter |
parameter TJIT_DUTY = 150; // tJIT(duty) ps Half Period Jitter |
parameter TJIT_CC = 250; // tJIT(cc) ps Cycle to Cycle jitter |
parameter TERR_2PER = 175; // tERR(nper) ps Accumulated Error (2-cycle) |
parameter TERR_3PER = 225; // tERR(nper) ps Accumulated Error (3-cycle) |
parameter TERR_4PER = 250; // tERR(nper) ps Accumulated Error (4-cycle) |
parameter TERR_5PER = 250; // tERR(nper) ps Accumulated Error (5-cycle) |
parameter TERR_N1PER = 350; // tERR(nper) ps Accumulated Error (6-10-cycle) |
parameter TERR_N2PER = 450; // tERR(nper) ps Accumulated Error (11-50-cycle) |
parameter TQHS = 450; // tQHS ps Data hold skew factor |
parameter TAC = 600; // tAC ps DQ output access time from CK/CK# |
parameter TDS = 150; // tDS ps DQ and DM input setup time relative to DQS |
parameter TDH = 275; // tDH ps DQ and DM input hold time relative to DQS |
parameter TDQSCK = 500; // tDQSCK ps DQS output access time from CK/CK# |
parameter TDQSQ = 350; // tDQSQ ps DQS-DQ skew, DQS to last DQ valid, per group, per access |
parameter TIS = 350; // tIS ps Input Setup Time |
parameter TIH = 475; // tIH ps Input Hold Time |
parameter TRC = 55000; // tRC ps Active to Active/Auto Refresh command time |
parameter TRCD = 15000; // tRCD ps Active to Read/Write command time |
parameter TWTR = 10000; // tWTR ps Write to Read command delay |
parameter TRP = 15000; // tRP ps Precharge command period |
parameter TRPA = 20000; // tRPA ps Precharge All period |
parameter TXARDS = 6; // tXARDS tCK Exit low power active power down to a read command |
parameter TXARD = 2; // tXARD tCK Exit active power down to a read command |
parameter TXP = 2; // tXP tCK Exit power down to a non-read command |
parameter TANPD = 3; // tANPD tCK ODT to power-down entry latency |
parameter TAXPD = 8; // tAXPD tCK ODT power-down exit latency |
parameter CL_TIME = 15000; // CL ps Minimum CAS Latency |
`endif `endif `endif `endif `endif `endif |
|
`ifdef x16 |
`ifdef sg187E |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25E |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25 |
parameter TFAW = 45000; // tFAW ps Four Bank Activate window |
`else // sg3E, sg3, sg37E, sg5E |
parameter TFAW = 50000; // tFAW ps Four Bank Activate window |
`endif `endif `endif |
`else // x4, x8 |
`ifdef sg187E |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25E |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else `ifdef sg25 |
parameter TFAW = 35000; // tFAW ps Four Bank Activate window |
`else // sg3E, sg3, sg37E, sg5E |
parameter TFAW = 37500; // tFAW ps Four Bank Activate window |
`endif `endif `endif |
`endif |
|
// Timing Parameters |
|
// Mode Register |
parameter AL_MIN = 0; // AL tCK Minimum Additive Latency |
parameter AL_MAX = 6; // AL tCK Maximum Additive Latency |
parameter CL_MIN = 3; // CL tCK Minimum CAS Latency |
parameter CL_MAX = 7; // CL tCK Maximum CAS Latency |
parameter WR_MIN = 2; // WR tCK Minimum Write Recovery |
parameter WR_MAX = 8; // WR tCK Maximum Write Recovery |
parameter BL_MIN = 4; // BL tCK Minimum Burst Length |
parameter BL_MAX = 8; // BL tCK Minimum Burst Length |
// Clock |
parameter TCK_MAX = 8000; // tCK ps Maximum Clock Cycle Time |
parameter TCH_MIN = 0.48; // tCH tCK Minimum Clock High-Level Pulse Width |
parameter TCH_MAX = 0.52; // tCH tCK Maximum Clock High-Level Pulse Width |
parameter TCL_MIN = 0.48; // tCL tCK Minimum Clock Low-Level Pulse Width |
parameter TCL_MAX = 0.52; // tCL tCK Maximum Clock Low-Level Pulse Width |
// Data |
parameter TLZ = TAC; // tLZ ps Data-out low-impedance window from CK/CK# |
parameter THZ = TAC; // tHZ ps Data-out high impedance window from CK/CK# |
parameter TDIPW = 0.35; // tDIPW tCK DQ and DM input Pulse Width |
// Data Strobe |
parameter TDQSH = 0.35; // tDQSH tCK DQS input High Pulse Width |
parameter TDQSL = 0.35; // tDQSL tCK DQS input Low Pulse Width |
parameter TDSS = 0.20; // tDSS tCK DQS falling edge to CLK rising (setup time) |
parameter TDSH = 0.20; // tDSH tCK DQS falling edge from CLK rising (hold time) |
parameter TWPRE = 0.35; // tWPRE tCK DQS Write Preamble |
parameter TWPST = 0.40; // tWPST tCK DQS Write Postamble |
parameter TDQSS = 0.25; // tDQSS tCK Rising clock edge to DQS/DQS# latching transition |
// Command and Address |
parameter TIPW = 0.6; // tIPW tCK Control and Address input Pulse Width |
parameter TCCD = 2; // tCCD tCK Cas to Cas command delay |
parameter TRAS_MIN = 40000; // tRAS ps Minimum Active to Precharge command time |
parameter TRAS_MAX =70000000; // tRAS ps Maximum Active to Precharge command time |
parameter TRTP = 7500; // tRTP ps Read to Precharge command delay |
parameter TWR = 15000; // tWR ps Write recovery time |
parameter TMRD = 2; // tMRD tCK Load Mode Register command cycle time |
parameter TDLLK = 200; // tDLLK tCK DLL locking time |
// Refresh |
parameter TRFC_MIN = 197500; // tRFC ps Refresh to Refresh Command interval minimum value |
parameter TRFC_MAX =70000000; // tRFC ps Refresh to Refresh Command Interval maximum value |
// Self Refresh |
parameter TXSNR = TRFC_MIN + 10000; // tXSNR ps Exit self refesh to a non-read command |
parameter TXSRD = 200; // tXSRD tCK Exit self refresh to a read command |
parameter TISXR = TIS; // tISXR ps CKE setup time during self refresh exit. |
// ODT |
parameter TAOND = 2; // tAOND tCK ODT turn-on delay |
parameter TAOFD = 2.5; // tAOFD tCK ODT turn-off delay |
parameter TAONPD = 2000; // tAONPD ps ODT turn-on (precharge power-down mode) |
parameter TAOFPD = 2000; // tAOFPD ps ODT turn-off (precharge power-down mode) |
parameter TMOD = 12000; // tMOD ps ODT enable in EMR to ODT pin transition |
// Power Down |
parameter TCKE = 3; // tCKE tCK CKE minimum high or low pulse width |
|
// Size Parameters based on Part Width |
|
`ifdef x4 |
parameter ADDR_BITS = 15; // Address Bits |
parameter ROW_BITS = 15; // Number of Address bits |
parameter COL_BITS = 11; // Number of Column bits |
parameter DM_BITS = 1; // Number of Data Mask bits |
parameter DQ_BITS = 4; // Number of Data bits |
parameter DQS_BITS = 1; // Number of Dqs bits |
parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time |
`else `ifdef x8 |
parameter ADDR_BITS = 15; // Address Bits |
parameter ROW_BITS = 15; // Number of Address bits |
parameter COL_BITS = 10; // Number of Column bits |
parameter DM_BITS = 1; // Number of Data Mask bits |
parameter DQ_BITS = 8; // Number of Data bits |
parameter DQS_BITS = 1; // Number of Dqs bits |
parameter TRRD = 7500; // tRRD Active bank a to Active bank b command time |
`else `define x16 |
parameter ADDR_BITS = 14; // Address Bits |
parameter ROW_BITS = 14; // Number of Address bits |
parameter COL_BITS = 10; // Number of Column bits |
parameter DM_BITS = 2; // Number of Data Mask bits |
parameter DQ_BITS = 16; // Number of Data bits |
parameter DQS_BITS = 2; // Number of Dqs bits |
parameter TRRD = 10000; // tRRD Active bank a to Active bank b command time |
`endif `endif |
|
`ifdef QUAD_RANK |
`define DUAL_RANK // also define DUAL_RANK |
parameter CS_BITS = 4; // Number of Chip Select Bits |
parameter RANKS = 4; // Number of Chip Select Bits |
`else `ifdef DUAL_RANK |
parameter CS_BITS = 2; // Number of Chip Select Bits |
parameter RANKS = 2; // Number of Chip Select Bits |
`else |
parameter CS_BITS = 2; // Number of Chip Select Bits |
parameter RANKS = 1; // Number of Chip Select Bits |
`endif `endif |
|
// Size Parameters |
parameter BA_BITS = 3; // Set this parmaeter to control how many Bank Address bits |
parameter MEM_BITS = 10; // Number of write data bursts can be stored in memory. The default is 2^10=1024. |
parameter AP = 10; // the address bit that controls auto-precharge and precharge-all |
parameter BL_BITS = 3; // the number of bits required to count to MAX_BL |
parameter BO_BITS = 2; // the number of Burst Order Bits |
|
`endif `endif `endif |
|
// Simulation parameters |
parameter STOP_ON_ERROR = 1; // If set to 1, the model will halt on command sequence/major errors |
parameter DEBUG = 0; // Turn on Debug messages |
parameter BUS_DELAY = 0; // delay in nanoseconds |
parameter RANDOM_OUT_DELAY = 0; // If set to 1, the model will put a random amount of delay on DQ/DQS during reads |
parameter RANDOM_SEED = 711689044; //seed value for random generator. |
|
parameter RDQSEN_PRE = 2; // DQS driving time prior to first read strobe |
parameter RDQSEN_PST = 1; // DQS driving time after last read strobe |
parameter RDQS_PRE = 2; // DQS low time prior to first read strobe |
parameter RDQS_PST = 1; // DQS low time after last valid read strobe |
parameter RDQEN_PRE = 0; // DQ/DM driving time prior to first read data |
parameter RDQEN_PST = 0; // DQ/DM driving time after last read data |
parameter WDQS_PRE = 1; // DQS half clock periods prior to first write strobe |
parameter WDQS_PST = 1; // DQS half clock periods after last valid write strobe |
/xilinx/atlys/bench/verilog/include/ddr2_model_preload.v
0,0 → 1,46
// File intended to be included in the generate statement for each DDR2 part. |
// The following loads a vmem file, "sram.vmem" by default, into the SDRAM. |
|
// Wait until the DDR memory is initialised, and then magically |
// load it |
@(posedge dut.xilinx_ddr2_0.xilinx_ddr2_if0.ddr2_calib_done); |
//$display("%t: Loading DDR2",$time); |
|
$readmemh("sram.vmem", program_array); |
/* Now dish it out to the DDR2 model's memory */ |
for(ram_ptr = 0 ; ram_ptr < 4096 ; ram_ptr = ram_ptr + 1) |
begin |
|
// Construct the burst line |
program_word_ptr = ram_ptr*4; |
tmp_program_word = program_array[program_word_ptr]; |
ddr2_ram_mem_line[31:0] = tmp_program_word; |
|
program_word_ptr = program_word_ptr + 1; |
tmp_program_word = program_array[program_word_ptr]; |
ddr2_ram_mem_line[63:32] = tmp_program_word; |
|
|
program_word_ptr = program_word_ptr + 1; |
tmp_program_word = program_array[program_word_ptr]; |
ddr2_ram_mem_line[95:64] = tmp_program_word; |
|
|
program_word_ptr = program_word_ptr + 1; |
tmp_program_word = program_array[program_word_ptr]; |
ddr2_ram_mem_line[127:96] = tmp_program_word; |
|
// Put this assembled line into the RAM using its memory writing TASK |
if (C3_MEM_ADDR_ORDER == "BANK_ROW_COLUMN") begin |
u_mem0.memory_write(2'b00,ram_ptr[19:7], |
{ram_ptr[6:0],3'b000},ddr2_ram_mem_line); |
end else if (C3_MEM_ADDR_ORDER == "ROW_BANK_COLUMN") begin |
u_mem0.memory_write(ram_ptr[8:7],{2'b00,ram_ptr[19:9]}, |
{ram_ptr[6:0],3'b000},ddr2_ram_mem_line); |
|
end |
//$display("Writing 0x%h, ramline=%d",ddr2_ram_mem_line, ram_ptr); |
|
end // for (ram_ptr = 0 ; ram_ptr < ... |
$display("(%t) * DDR2 RAM preloaded",$time); |
|
/xilinx/atlys/bench/verilog/include/synthesis-defines.v
0,0 → 1,2
// Nothing in here, just providing synthesis-defines.v for files that include |
// it (clkgen, for one.) |
/xilinx/atlys/bench/verilog/include/timescale.v
0,0 → 1,2
`timescale 1ns/1ps |
/xilinx/atlys/bench/verilog/orpsoc_testbench.v
0,0 → 1,447
////////////////////////////////////////////////////////////////////// |
/// //// |
/// ORPSoC Atlys testbench //// |
/// //// |
/// Instantiate ORPSoC, monitors, provide stimulus //// |
/// //// |
/// Julius Baxter, julius@opencores.org //// |
/// Contributor(s): //// |
/// Stefan Kristiansson, stefan.kristiansson@saunalahti.fi //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
`include "orpsoc-defines.v" |
`include "orpsoc-testbench-defines.v" |
`include "test-defines.v" |
`include "timescale.v" |
// Xilinx simulation: |
`include "glbl.v" |
|
module orpsoc_testbench; |
|
// Clock and reset signal registers |
reg clk = 0; |
reg rst_n = 1; // Active LOW |
|
always |
#((`BOARD_CLOCK_PERIOD)/2) clk <= ~clk; |
|
wire clk_n, clk_p; |
assign clk_p = clk; |
assign clk_n = ~clk; |
|
|
// Reset, ACTIVE LOW |
initial |
begin |
#1; |
repeat (32) @(negedge clk) |
rst_n <= 1; |
repeat (32) @(negedge clk) |
rst_n <= 0; |
repeat (32) @(negedge clk) |
rst_n <= 1; |
end |
|
// Include design parameters file |
`include "orpsoc-params.v" |
|
// Pullup bus for I2C |
tri1 i2c_scl, i2c_sda; |
|
`ifdef JTAG_DEBUG |
wire tdo_pad_o; |
wire tck_pad_i; |
wire tms_pad_i; |
wire tdi_pad_i; |
`endif |
`ifdef UART0 |
wire uart0_stx_pad_o; |
wire uart0_srx_pad_i; |
`endif |
`ifdef GPIO0 |
wire [gpio0_io_width-1:0] gpio0_io; |
`endif |
`ifdef SPI0 |
wire spi0_mosi_o; |
wire spi0_miso_i; |
wire spi0_sck_o; |
wire spi0_hold_n_o; |
wire spi0_w_n_o; |
wire [spi0_ss_width-1:0] spi0_ss_o; |
`endif |
`ifdef ETH0 |
wire mtx_clk_o; |
wire [3:0] ethphy_mii_tx_d; |
wire ethphy_mii_tx_en; |
wire ethphy_mii_tx_err; |
wire mrx_clk_o; |
wire [3:0] mrxd_o; |
wire mrxdv_o; |
wire mrxerr_o; |
wire mcoll_o; |
wire mcrs_o; |
wire ethphy_rst_n; |
wire eth0_mdc_pad_o; |
wire eth0_md_pad_io; |
`endif |
`ifdef XILINX_DDR2 |
`include "xilinx_ddr2_params.v" |
localparam DEVICE_WIDTH = 16; // Memory device data width |
localparam real CLK_PERIOD_NS = C3_MEMCLK_PERIOD / 1000.0; |
localparam real TCYC_200 = 5.0; |
localparam real TPROP_DQS = 0.00; // Delay for DQS signal during Write Operation |
localparam real TPROP_DQS_RD = 0.00; // Delay for DQS signal during Read Operation |
localparam real TPROP_PCB_CTRL = 0.00; // Delay for Address and Ctrl signals |
localparam real TPROP_PCB_DATA = 0.00; // Delay for data signal during Write operation |
localparam real TPROP_PCB_DATA_RD = 0.00; // Delay for data signal during Read operation |
|
wire [DQ_WIDTH-1:0] ddr2_dq_fpga; |
wire [DQS_WIDTH-1:0] ddr2_dqs_fpga; |
wire [DQS_WIDTH-1:0] ddr2_dqs_n_fpga; |
wire ddr2_udqs_fpga; |
wire ddr2_udqs_n_fpga; |
wire [DM_WIDTH-1:0] ddr2_dm_fpga; |
wire ddr2_udm_fpga; |
wire [CLK_WIDTH-1:0] ddr2_ck_fpga; |
wire [CLK_WIDTH-1:0] ddr2_ck_n_fpga; |
wire [ROW_WIDTH-1:0] ddr2_a_fpga; |
wire [BANK_WIDTH-1:0] ddr2_ba_fpga; |
wire ddr2_ras_n_fpga; |
wire ddr2_cas_n_fpga; |
wire ddr2_we_n_fpga; |
wire [CKE_WIDTH-1:0] ddr2_cke_fpga; |
wire [ODT_WIDTH-1:0] ddr2_odt_fpga; |
|
wire ddr2_rzq; |
wire ddr2_zio; |
`endif |
|
orpsoc_top dut |
( |
`ifdef JTAG_DEBUG |
.tms_pad_i (tms_pad_i), |
.tck_pad_i (tck_pad_i), |
.tdi_pad_i (tdi_pad_i), |
.tdo_pad_o (tdo_pad_o), |
`endif |
`ifdef XILINX_DDR2 |
.ddr2_a (ddr2_a_fpga), |
.ddr2_ba (ddr2_ba_fpga), |
.ddr2_ras_n (ddr2_ras_n_fpga), |
.ddr2_cas_n (ddr2_cas_n_fpga), |
.ddr2_we_n (ddr2_we_n_fpga), |
.ddr2_rzq (ddr2_rzq), |
.ddr2_zio (ddr2_zio), |
.ddr2_odt (ddr2_odt_fpga), |
.ddr2_cke (ddr2_cke_fpga), |
.ddr2_dm (ddr2_dm_fpga), |
.ddr2_udm (ddr2_udm_fpga), |
.ddr2_ck (ddr2_ck_fpga), |
.ddr2_ck_n (ddr2_ck_n_fpga), |
.ddr2_dq (ddr2_dq_fpga), |
.ddr2_dqs (ddr2_dqs_fpga), |
.ddr2_dqs_n (ddr2_dqs_n_fpga), |
.ddr2_udqs (ddr2_udqs_fpga), |
.ddr2_udqs_n (ddr2_udqs_n_fpga), |
`endif |
`ifdef UART0 |
.uart0_stx_pad_o (uart0_stx_pad_o), |
.uart0_srx_pad_i (uart0_srx_pad_i), |
`ifdef UART0_EXPHEADER |
.uart0_stx_expheader_pad_o (uart0_stx_pad_o), |
.uart0_srx_expheader_pad_i (uart0_srx_pad_i), |
`endif |
`endif |
`ifdef SPI0 |
.spi0_sck_o (spi0_sck_o), |
.spi0_miso_i (spi0_miso_i), |
.spi0_mosi_o (spi0_mosi_o), |
.spi0_ss_o (spi0_ss_o), |
`endif |
`ifdef I2C0 |
.i2c0_sda_io (i2c_sda), |
.i2c0_scl_io (i2c_scl), |
`endif |
`ifdef I2C1 |
.i2c1_sda_io (i2c_sda), |
.i2c1_scl_io (i2c_scl), |
`endif |
`ifdef GPIO0 |
.gpio0_io (gpio0_io), |
`endif |
`ifdef ETH0 |
.eth0_tx_clk (mtx_clk_o), |
.eth0_tx_data (ethphy_mii_tx_d), |
.eth0_tx_en (ethphy_mii_tx_en), |
.eth0_tx_er (ethphy_mii_tx_err), |
.eth0_rx_clk (mrx_clk_o), |
.eth0_rx_data (mrxd_o), |
.eth0_dv (mrxdv_o), |
.eth0_rx_er (mrxerr_o), |
.eth0_col (mcoll_o), |
.eth0_crs (mcrs_o), |
.eth0_rst_n_o (ethphy_rst_n), |
.eth0_mdc_pad_o (eth0_mdc_pad_o), |
.eth0_md_pad_io (eth0_md_pad_io), |
`endif // `ifdef ETH0 |
|
.sys_clk_in (clk), |
|
.rst_n_pad_i (rst_n) |
); |
|
// |
// Instantiate OR1200 monitor |
// |
or1200_monitor monitor(); |
|
`ifndef SIM_QUIET |
`define CPU_ic_top or1200_ic_top |
`define CPU_dc_top or1200_dc_top |
wire ic_en = orpsoc_testbench.dut.or1200_top0.or1200_ic_top.ic_en; |
always @(posedge ic_en) |
$display("Or1200 IC enabled at %t", $time); |
|
wire dc_en = orpsoc_testbench.dut.or1200_top0.or1200_dc_top.dc_en; |
always @(posedge dc_en) |
$display("Or1200 DC enabled at %t", $time); |
`endif |
|
|
`ifdef JTAG_DEBUG |
`ifdef VPI_DEBUG |
// Debugging interface |
vpi_debug_module vpi_dbg |
( |
.tms(tms_pad_i), |
.tck(tck_pad_i), |
.tdi(tdi_pad_i), |
.tdo(tdo_pad_o) |
); |
`else |
// If no VPI debugging, tie off JTAG inputs |
assign tdi_pad_i = 1; |
assign tck_pad_i = 0; |
assign tms_pad_i = 1; |
`endif // !`ifdef VPI_DEBUG_ENABLE |
`endif // `ifdef JTAG_DEBUG |
|
`ifdef SPI0 |
|
// SPI flash memory - M25P16 compatible SPI protocol |
AT26DFxxx |
#(.MEMSIZE(16384*1024)) // 16MB flash on Atlys |
spi0_flash |
(// Outputs |
.SO (spi0_miso_i), |
// Inputs |
.CSB (spi0_ss_o), |
.SCK (spi0_sck_o), |
.SI (spi0_mosi_o), |
.WPB (1'b1) |
); |
|
|
`endif // `ifdef SPI0 |
|
`ifdef ETH0 |
|
/* TX/RXes packets and checks them, enabled when ethernet MAC is */ |
`include "eth_stim.v" |
|
eth_phy eth_phy0 |
( |
// Outputs |
.mtx_clk_o (mtx_clk_o), |
.mrx_clk_o (mrx_clk_o), |
.mrxd_o (mrxd_o[3:0]), |
.mrxdv_o (mrxdv_o), |
.mrxerr_o (mrxerr_o), |
.mcoll_o (mcoll_o), |
.mcrs_o (mcrs_o), |
.link_o (), |
.speed_o (), |
.duplex_o (), |
.smii_clk_i (1'b0), |
.smii_sync_i (1'b0), |
.smii_rx_o (), |
// Inouts |
.md_io (eth0_md_pad_io), |
// Inputs |
`ifndef ETH0_PHY_RST |
// If no reset out from the design, hook up to the board's active low rst |
.m_rst_n_i (rst_n), |
`else |
.m_rst_n_i (ethphy_rst_n), |
`endif |
.mtxd_i (ethphy_mii_tx_d[3:0]), |
.mtxen_i (ethphy_mii_tx_en), |
.mtxerr_i (ethphy_mii_tx_err), |
.mdc_i (eth0_mdc_pad_o)); |
|
`endif // `ifdef ETH0 |
|
`ifdef XILINX_DDR2 |
`ifndef GATE_SIM |
defparam dut.xilinx_ddr2_0.xilinx_ddr2_if0.ddr2_mig.C3_SIMULATION = "TRUE"; |
`endif |
|
PULLDOWN ddr2_zio_pulldown (.O(ddr2_zio)); PULLDOWN ddr2_rzq_pulldown (.O(ddr2_rzq)); |
|
parameter NUM_PROGRAM_WORDS=1048576; |
integer ram_ptr, program_word_ptr, k; |
reg [31:0] tmp_program_word; |
reg [31:0] program_array [0:NUM_PROGRAM_WORDS-1]; // 1M words = 4MB |
reg [8*16-1:0] ddr2_ram_mem_line; //8*16-bits= 8 shorts (half-words) |
initial |
begin |
|
`ifdef PRELOAD_RAM |
`include "ddr2_model_preload.v" |
`endif |
end |
|
ddr2_model u_mem0 |
( |
.ck (ddr2_ck_fpga), |
.ck_n (ddr2_ck_n_fpga), |
.cke (ddr2_cke_fpga), |
.cs_n (1'b0), |
.ras_n (ddr2_ras_n_fpga), |
.cas_n (ddr2_cas_n_fpga), |
.we_n (ddr2_we_n_fpga), |
.dm_rdqs ({ddr2_udm_fpga,ddr2_dm_fpga}), |
.ba (ddr2_ba_fpga), |
.addr (ddr2_a_fpga), |
.dq (ddr2_dq_fpga), |
.dqs ({ddr2_udqs_fpga,ddr2_dqs_fpga}), |
.dqs_n ({ddr2_udqs_n_fpga,ddr2_dqs_n_fpga}), |
.rdqs_n (), |
.odt (ddr2_odt_fpga) |
); |
`endif |
|
|
`ifdef VCD |
reg vcd_go = 0; |
always @(vcd_go) |
begin |
|
`ifdef VCD_DELAY |
#(`VCD_DELAY); |
`endif |
|
// Delay by x insns |
`ifdef VCD_DELAY_INSNS |
#10; // Delay until after the value becomes valid |
while (monitor.insns < `VCD_DELAY_INSNS) |
@(posedge clk); |
`endif |
|
`ifdef SIMULATOR_MODELSIM |
// Modelsim can GZip VCDs on the fly if given in the suffix |
`define VCD_SUFFIX ".vcd.gz" |
`else |
`define VCD_SUFFIX ".vcd" |
`endif |
|
`ifndef SIM_QUIET |
$display("* VCD in %s\n", {"../out/",`TEST_NAME_STRING,`VCD_SUFFIX}); |
`endif |
$dumpfile({"../out/",`TEST_NAME_STRING,`VCD_SUFFIX}); |
`ifndef VCD_DEPTH |
`define VCD_DEPTH 0 |
`endif |
$dumpvars(`VCD_DEPTH); |
|
end |
`endif // `ifdef VCD |
|
initial |
begin |
`ifndef SIM_QUIET |
$display("\n* Starting simulation of design RTL.\n* Test: %s\n", |
`TEST_NAME_STRING ); |
`endif |
|
`ifdef VCD |
vcd_go = 1; |
`endif |
|
end // initial begin |
|
`ifdef END_TIME |
initial begin |
#(`END_TIME); |
`ifndef SIM_QUIET |
$display("* Finish simulation due to END_TIME being set at %t", $time); |
`endif |
$finish; |
end |
`endif |
|
`ifdef END_INSNS |
initial begin |
#10 |
while (monitor.insns < `END_INSNS) |
@(posedge clk); |
`ifndef SIM_QUIET |
$display("* Finish simulation due to END_INSNS count (%d) reached at %t", |
`END_INSNS, $time); |
`endif |
$finish; |
end |
`endif |
|
`ifdef UART0 |
// |
// UART0 decoder |
// |
uart_decoder |
#( |
.uart_baudrate_period_ns(8680) // 115200 baud = period 8.68uS |
) |
uart0_decoder |
( |
.clk(clk), |
.uart_tx(uart0_stx_pad_o) |
); |
|
// Loopback UART lines |
assign uart0_srx_pad_i = uart0_stx_pad_o; |
|
`endif // `ifdef UART0 |
|
endmodule // orpsoc_testbench |
|
// Local Variables: |
// verilog-library-directories:("." "../../rtl/verilog/orpsoc_top") |
// verilog-library-files:() |
// verilog-library-extensions:(".v" ".h") |
// End: |
|
/xilinx/atlys/bench/verilog/or1200_monitor.v
0,0 → 1,1814
////////////////////////////////////////////////////////////////////// |
//// //// |
//// or1200_monitor.v //// |
//// //// |
//// OR1200 processor monitor module //// |
//// //// |
//// Author(s): //// |
//// - Damjan Lampret, lampret@opencores.org //// |
//// - Julius Baxter, julius@opencores.org //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009, 2010 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
`include "timescale.v" |
`include "or1200_defines.v" |
`include "or1200_monitor_defines.v" |
`include "test-defines.v" |
|
|
module or1200_monitor; |
|
integer fexe; |
integer finsn; |
|
reg [23:0] ref; |
`ifdef OR1200_MONITOR_SPRS |
integer fspr; |
`endif |
integer fgeneral; |
`ifdef OR1200_MONITOR_LOOKUP |
integer flookup; |
`endif |
integer r3; |
integer insns; |
|
|
// |
// Initialization |
// |
initial begin |
ref = 0; |
`ifdef OR1200_MONITOR_EXEC_STATE |
fexe = $fopen({"../out/",`TEST_NAME_STRING,"-executed.log"}); |
`endif |
`ifdef OR1200_MONITOR_EXEC_LOG_DISASSEMBLY |
finsn = fexe; |
`endif |
$timeformat (-9, 2, " ns", 12); |
`ifdef OR1200_MONITOR_SPRS |
fspr = $fopen({"../out/",`TEST_NAME_STRING,"-sprs.log"}); |
`endif |
fgeneral = $fopen({"../out/",`TEST_NAME_STRING,"-general.log"}); |
`ifdef OR1200_MONITOR_LOOKUP |
flookup = $fopen({"../out/",`TEST_NAME_STRING,"-lookup.log"}); |
`endif |
insns = 0; |
|
end |
|
// |
// Get GPR |
// |
task get_gpr; |
input [4:0] gpr_no; |
output [31:0] gpr; |
integer j; |
begin |
|
`ifdef OR1200_RFRAM_GENERIC |
for(j = 0; j < 32; j = j + 1) begin |
gpr[j] = `OR1200_TOP.`CPU_cpu.`CPU_rf.rf_a.mem[gpr_no*32+j]; |
end |
|
`else |
//gpr = `OR1200_TOP.`CPU_cpu.`CPU_rf.rf_a.mem[gpr_no]; |
gpr = `OR1200_TOP.`CPU_cpu.`CPU_rf.rf_a.get_gpr(gpr_no); |
|
`endif |
|
|
end |
endtask |
|
// |
// Write state of the OR1200 registers into a file |
// |
// Limitation: only a small subset of register file RAMs |
// are supported |
// |
task display_arch_state; |
reg [5:0] i; |
reg [31:0] r; |
integer j; |
begin |
`ifdef OR1200_MONITOR_EXEC_STATE |
ref = ref + 1; |
`ifdef OR1200_MONITOR_LOOKUP |
$fdisplay(flookup, "Instruction %d: %t", insns, $time); |
`endif |
$fwrite(fexe, "\nEXECUTED(%d): %h: %h", insns, |
`OR1200_TOP.`CPU_cpu.`CPU_except.wb_pc, |
`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn); |
`ifdef OR1200_MONITOR_EXEC_LOG_DISASSEMBLY |
$fwrite(fexe,"\t"); |
// Decode the instruction, print it out |
or1200_print_op(`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn); |
`endif |
for(i = 0; i < 32; i = i + 1) begin |
if (i % 4 == 0) |
$fdisplay(fexe); |
get_gpr(i, r); |
$fwrite(fexe, "GPR%d: %h ", i, r); |
end |
$fdisplay(fexe); |
r = `OR1200_TOP.`CPU_cpu.`CPU_sprs.sr; |
$fwrite(fexe, "SR : %h ", r); |
r = `OR1200_TOP.`CPU_cpu.`CPU_sprs.epcr; |
$fwrite(fexe, "EPCR0: %h ", r); |
r = `OR1200_TOP.`CPU_cpu.`CPU_sprs.eear; |
$fwrite(fexe, "EEAR0: %h ", r); |
r = `OR1200_TOP.`CPU_cpu.`CPU_sprs.esr; |
$fdisplay(fexe, "ESR0 : %h", r); |
`endif // `ifdef OR1200_MONITOR_EXEC_STATE |
`ifdef OR1200_DISPLAY_EXECUTED |
ref = ref + 1; |
`ifdef OR1200_MONITOR_LOOKUP |
$fdisplay(flookup, "Instruction %d: %t", insns, $time); |
`endif |
$fwrite(fexe, "\nEXECUTED(%d): %h: %h", insns, `OR1200_TOP.`CPU_cpu.`CPU_except.wb_pc, `OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn); |
`endif |
insns = insns + 1; |
end |
endtask // display_arch_state |
|
/* Keep a trace buffer of the last lot of instructions and addresses |
* "executed",as read from the writeback stage, and cause a $finish if we hit |
* an instruction that is invalid, such as all zeros. |
* Currently, only breaks on an all zero instruction, but should probably be |
* made to break for anything with an X in it too. And of course ideally this |
* shouldn't be needed - but is handy if someone changes something and stops |
* the test continuing forever. |
*/ |
integer num_nul_inst; |
initial num_nul_inst = 0; |
|
task monitor_for_crash; |
`define OR1200_MONITOR_CRASH_TRACE_SIZE 32 |
//Trace buffer of 32 instructions |
reg [31:0] insn_trace [0:`OR1200_MONITOR_CRASH_TRACE_SIZE-1]; |
//Trace buffer of the addresses of those instructions |
reg [31:0] addr_trace [0:`OR1200_MONITOR_CRASH_TRACE_SIZE-1]; |
integer i; |
|
begin |
if (`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn == 32'h00000000) |
num_nul_inst = num_nul_inst + 1; |
else |
num_nul_inst = 0; // Reset it |
|
if (num_nul_inst == 1000) // Sat a loop a bit too long... |
begin |
$fdisplay(fgeneral, "ERROR - no instruction at PC %h", |
`OR1200_TOP.`CPU_cpu.`CPU_except.wb_pc); |
$fdisplay(fgeneral, "Crash trace: Last %d instructions: ", |
`OR1200_MONITOR_CRASH_TRACE_SIZE); |
|
$fdisplay(fgeneral, "PC\t\tINSTR"); |
for(i=`OR1200_MONITOR_CRASH_TRACE_SIZE-1;i>=0;i=i-1) begin |
$fdisplay(fgeneral, "%h\t%h",addr_trace[i], insn_trace[i]); |
end |
$display("*"); |
$display("* or1200_monitor : OR1200 crash detected (suspected CPU PC corruption)"); |
$display("*"); |
|
#100 $finish; |
end |
else |
begin |
for(i=`OR1200_MONITOR_CRASH_TRACE_SIZE-1;i>0;i=i-1) begin |
insn_trace[i] = insn_trace[i-1]; |
addr_trace[i] = addr_trace[i-1]; |
end |
insn_trace[0] = `OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn; |
addr_trace[0] = `OR1200_TOP.`CPU_cpu.`CPU_except.wb_pc; |
end |
|
end |
endtask // monitor_for_crash |
|
|
// |
// Write state of the OR1200 registers into a file; version for exception |
// |
task display_arch_state_except; |
reg [5:0] i; |
reg [31:0] r; |
integer j; |
begin |
`ifdef OR1200_MONITOR_EXEC_STATE |
ref = ref + 1; |
`ifdef OR1200_MONITOR_LOOKUP |
$fdisplay(flookup, "Instruction %d: %t", insns, $time); |
`endif |
$fwrite(fexe, "\nEXECUTED(%d): %h: %h (exception)", insns, `OR1200_TOP.`CPU_cpu.`CPU_except.ex_pc, `OR1200_TOP.`CPU_cpu.`CPU_ctrl.ex_insn); |
for(i = 0; i < 32; i = i + 1) begin |
if (i % 4 == 0) |
$fdisplay(fexe); |
get_gpr(i, r); |
$fwrite(fexe, "GPR%d: %h ", i, r); |
end |
$fdisplay(fexe); |
r = `OR1200_TOP.`CPU_cpu.`CPU_sprs.sr; |
$fwrite(fexe, "SR : %h ", r); |
r = `OR1200_TOP.`CPU_cpu.`CPU_sprs.epcr; |
$fwrite(fexe, "EPCR0: %h ", r); |
r = `OR1200_TOP.`CPU_cpu.`CPU_sprs.eear; |
$fwrite(fexe, "EEAR0: %h ", r); |
r = `OR1200_TOP.`CPU_cpu.`CPU_sprs.esr; |
$fdisplay(fexe, "ESR0 : %h", r); |
insns = insns + 1; |
`endif // `ifdef OR1200_MONITOR_EXEC_STATE |
`ifdef OR1200_DISPLAY_EXECUTED |
ref = ref + 1; |
`ifdef OR1200_MONITOR_LOOKUP |
$fdisplay(flookup, "Instruction %d: %t", insns, $time); |
`endif |
$fwrite(fexe, "\nEXECUTED(%d): %h: %h (exception)", insns, |
`OR1200_TOP.`CPU_cpu.`CPU_except.ex_pc, |
`OR1200_TOP.`CPU_cpu.`CPU_ctrl.ex_insn); |
insns = insns + 1; |
`endif |
|
end |
endtask |
|
integer iwb_progress; |
reg [31:0] iwb_progress_addr; |
// |
// WISHBONE bus checker |
// |
always @(posedge `OR1200_TOP.iwb_clk_i) |
if (`OR1200_TOP.iwb_rst_i) begin |
iwb_progress = 0; |
iwb_progress_addr = `OR1200_TOP.iwb_adr_o; |
end |
else begin |
if (`OR1200_TOP.iwb_cyc_o && (iwb_progress != 2)) begin |
iwb_progress = 1; |
end |
if (`OR1200_TOP.iwb_stb_o) begin |
if (iwb_progress >= 1) begin |
if (iwb_progress == 1) |
iwb_progress_addr = `OR1200_TOP.iwb_adr_o; |
iwb_progress = 2; |
end |
else begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.iwb_stb_o raised without `OR1200_TOP.iwb_cyc_o, at %t\n", $time); |
#100 $finish; |
end |
end |
if (`OR1200_TOP.iwb_ack_i & `OR1200_TOP.iwb_err_i) begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.iwb_ack_i and `OR1200_TOP.iwb_err_i raised at the same time, at %t\n", $time); |
end |
if ((iwb_progress == 2) && (iwb_progress_addr != `OR1200_TOP.iwb_adr_o)) begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.iwb_adr_o changed while waiting for `OR1200_TOP.iwb_err_i/`OR1200_TOP.iwb_ack_i, at %t\n", $time); |
#100 $finish; |
end |
if (`OR1200_TOP.iwb_ack_i | `OR1200_TOP.iwb_err_i) |
if (iwb_progress == 2) begin |
iwb_progress = 0; |
iwb_progress_addr = `OR1200_TOP.iwb_adr_o; |
end |
else begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.iwb_ack_i/`OR1200_TOP.iwb_err_i raised without `OR1200_TOP.iwb_cyc_i/`OR1200_TOP.iwb_stb_i, at %t\n", $time); |
#100 $finish; |
end |
if ((iwb_progress == 2) && !`OR1200_TOP.iwb_stb_o) begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.iwb_stb_o lowered without `OR1200_TOP.iwb_err_i/`OR1200_TOP.iwb_ack_i, at %t\n", $time); |
#100 $finish; |
end |
end |
|
integer dwb_progress; |
reg [31:0] dwb_progress_addr; |
// |
// WISHBONE bus checker |
// |
always @(posedge `OR1200_TOP.dwb_clk_i) |
if (`OR1200_TOP.dwb_rst_i) |
dwb_progress = 0; |
else begin |
if (`OR1200_TOP.dwb_cyc_o && (dwb_progress != 2)) |
dwb_progress = 1; |
if (`OR1200_TOP.dwb_stb_o) |
if (dwb_progress >= 1) begin |
if (dwb_progress == 1) |
dwb_progress_addr = `OR1200_TOP.dwb_adr_o; |
dwb_progress = 2; |
end |
else begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.dwb_stb_o raised without `OR1200_TOP.dwb_cyc_o, at %t\n", $time); |
#100 $finish; |
end |
if (`OR1200_TOP.dwb_ack_i & `OR1200_TOP.dwb_err_i) begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.dwb_ack_i and `OR1200_TOP.dwb_err_i raised at the same time, at %t\n", $time); |
end |
if ((dwb_progress == 2) && (dwb_progress_addr != `OR1200_TOP.dwb_adr_o)) begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.dwb_adr_o changed while waiting for `OR1200_TOP.dwb_err_i/`OR1200_TOP.dwb_ack_i, at %t\n", $time); |
#100 $finish; |
end |
if (`OR1200_TOP.dwb_ack_i | `OR1200_TOP.dwb_err_i) |
if (dwb_progress == 2) begin |
dwb_progress = 0; |
dwb_progress_addr = `OR1200_TOP.dwb_adr_o; |
end |
else begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.dwb_ack_i/`OR1200_TOP.dwb_err_i raised without `OR1200_TOP.dwb_cyc_i/`OR1200_TOP.dwb_stb_i, at %t\n", $time); |
#100 $finish; |
end |
if ((dwb_progress == 2) && !`OR1200_TOP.dwb_stb_o) begin |
$fdisplay(fgeneral, "WISHBONE protocol violation: `OR1200_TOP.dwb_stb_o lowered without `OR1200_TOP.dwb_err_i/`OR1200_TOP.dwb_ack_i, at %t\n", $time); |
#100 $finish; |
end |
end |
|
// |
// Hooks for: |
// - displaying registers |
// - end of simulation |
// - access to SPRs |
// |
always @(posedge `CPU_CORE_CLK) |
if (!`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_freeze) begin |
// #2; |
if (((`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn[31:26] != `OR1200_OR32_NOP) |
| !`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn[16]) |
& !(`OR1200_TOP.`CPU_cpu.`CPU_except.except_flushpipe & |
`OR1200_TOP.`CPU_cpu.`CPU_except.ex_dslot)) |
begin |
display_arch_state; |
monitor_for_crash; |
end |
else |
if (`OR1200_TOP.`CPU_cpu.`CPU_except.except_flushpipe) |
display_arch_state_except; |
// small hack to stop simulation (l.nop 1): |
if (`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn == 32'h1500_0001) begin |
get_gpr(3, r3); |
$fdisplay(fgeneral, "%t: l.nop exit (%h)", $time, r3); |
`ifdef OR1200_MONITOR_VERBOSE_NOPS |
$display("exit(%h)",r3); |
`endif |
$finish; |
end |
// debug if test (l.nop 10) |
if (`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn == 32'h1500_000a) begin |
$fdisplay(fgeneral, "%t: l.nop dbg_if_test", $time); |
end |
// simulation reports (l.nop 2) |
if (`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn == 32'h1500_0002) begin |
get_gpr(3, r3); |
$fdisplay(fgeneral, "%t: l.nop report (0x%h)", $time, r3); |
`ifdef OR1200_MONITOR_VERBOSE_NOPS |
$display("report (0x%h);", r3); |
`endif |
end |
// simulation printfs (l.nop 3) |
if (`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn == 32'h1500_0003) begin |
get_gpr(3, r3); |
$fdisplay(fgeneral, "%t: l.nop printf (%h)", $time, r3); |
end |
if (`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn == 32'h1500_0004) begin |
// simulation putc (l.nop 4) |
get_gpr(3, r3); |
$write("%c", r3); |
$fdisplay(fgeneral, "%t: l.nop putc (%c)", $time, r3); |
end |
`ifdef OR1200_MONITOR_SPRS |
if (`OR1200_TOP.`CPU_cpu.`CPU_sprs.spr_we) |
$fdisplay(fspr, "%t: Write to SPR : [%h] <- %h", $time, |
`OR1200_TOP.`CPU_cpu.`CPU_sprs.spr_addr, |
`OR1200_TOP.`CPU_cpu.`CPU_sprs.spr_dat_o); |
if ((|`OR1200_TOP.`CPU_cpu.`CPU_sprs.spr_cs) & |
!`OR1200_TOP.`CPU_cpu.`CPU_sprs.spr_we) |
$fdisplay(fspr, "%t: Read from SPR: [%h] -> %h", $time, |
`OR1200_TOP.`CPU_cpu.`CPU_sprs.spr_addr, |
`OR1200_TOP.`CPU_cpu.`CPU_sprs.to_wbmux); |
`endif |
end |
|
|
`ifdef RAM_WB |
`define RAM_WB_TOP `DUT_TOP.ram_wb0.ram_wb_b3_0 |
task get_insn_from_wb_ram; |
input [31:0] addr; |
output [31:0] insn; |
begin |
insn = `RAM_WB_TOP.get_mem32(addr[31:2]); |
end |
endtask // get_insn_from_wb_ram |
`endif |
|
`ifdef VERSATILE_SDRAM |
`define SDRAM_TOP `TB_TOP.sdram0 |
// Bit selects to define the bank |
// 32 MB part with 4 banks |
`define SDRAM_BANK_SEL_BITS 24:23 |
`define SDRAM_WORD_SEL_TOP_BIT 22 |
// Gets instruction word from correct bank |
task get_insn_from_sdram; |
input [31:0] addr; |
output [31:0] insn; |
reg [`SDRAM_WORD_SEL_TOP_BIT-1:0] word_addr; |
|
begin |
word_addr = addr[`SDRAM_WORD_SEL_TOP_BIT:2]; |
if (addr[`SDRAM_BANK_SEL_BITS] == 2'b00) |
begin |
|
//$display("%t: get_insn_from_sdram bank0, word 0x%h, (%h and %h in SDRAM)", $time, word_addr, `SDRAM_TOP.Bank0[{word_addr,1'b0}], `SDRAM_TOP.Bank0[{word_addr,1'b1}]); |
insn[15:0] = `SDRAM_TOP.Bank0[{word_addr,1'b1}]; |
insn[31:16] = `SDRAM_TOP.Bank0[{word_addr,1'b0}]; |
end |
end |
|
endtask // get_insn_from_sdram |
`endif // `ifdef VERSATILE_SDRAM |
|
`ifdef XILINX_DDR2 |
//SJK this needs to be fixed |
//SJK `define DDR2_TOP `TB_TOP.gen_cs[0] |
// Gets instruction word from correct bank |
task get_insn_from_xilinx_ddr2; |
input [31:0] addr; |
output [31:0] insn; |
reg [16*8-1:0] ddr2_array_line0,ddr2_array_line1,ddr2_array_line2, |
ddr2_array_line3; |
integer word_in_line_num; |
begin |
// Get our 4 128-bit chunks (8 half-words in each!! Confused yet?), |
// 16 words total |
/* SJK |
`DDR2_TOP.gen[0].u_mem0.memory_read(addr[28:27],addr[26:13],{addr[12:6],3'd0},ddr2_array_line0); |
`DDR2_TOP.gen[1].u_mem0.memory_read(addr[28:27],addr[26:13],{addr[12:6],3'd0},ddr2_array_line1); |
`DDR2_TOP.gen[2].u_mem0.memory_read(addr[28:27],addr[26:13],{addr[12:6],3'd0},ddr2_array_line2); |
`DDR2_TOP.gen[3].u_mem0.memory_read(addr[28:27],addr[26:13],{addr[12:6],3'd0},ddr2_array_line3); |
*/ |
u_mem0.memory_read(addr[28:27],addr[26:13],{addr[12:6],3'd0},ddr2_array_line0); |
insn[31:0] = ddr2_array_line0[31:0]; |
$display("SJK DEBUG"); |
|
/* |
case (addr[5:2]) |
4'h0: |
begin |
insn[15:0] = ddr2_array_line0[15:0]; |
insn[31:16] = ddr2_array_line1[15:0]; |
end |
4'h1: |
begin |
insn[15:0] = ddr2_array_line2[15:0]; |
insn[31:16] = ddr2_array_line3[15:0]; |
end |
4'h2: |
begin |
insn[15:0] = ddr2_array_line0[31:16]; |
insn[31:16] = ddr2_array_line1[31:16]; |
end |
4'h3: |
begin |
insn[15:0] = ddr2_array_line2[31:16]; |
insn[31:16] = ddr2_array_line3[31:16]; |
end |
4'h4: |
begin |
insn[15:0] = ddr2_array_line0[47:32]; |
insn[31:16] = ddr2_array_line1[47:32]; |
end |
4'h5: |
begin |
insn[15:0] = ddr2_array_line2[47:32]; |
insn[31:16] = ddr2_array_line3[47:32]; |
end |
4'h6: |
begin |
insn[15:0] = ddr2_array_line0[63:48]; |
insn[31:16] = ddr2_array_line1[63:48]; |
end |
4'h7: |
begin |
insn[15:0] = ddr2_array_line2[63:48]; |
insn[31:16] = ddr2_array_line3[63:48]; |
end |
4'h8: |
begin |
insn[15:0] = ddr2_array_line0[79:64]; |
insn[31:16] = ddr2_array_line1[79:64]; |
end |
4'h9: |
begin |
insn[15:0] = ddr2_array_line2[79:64]; |
insn[31:16] = ddr2_array_line3[79:64]; |
end |
4'ha: |
begin |
insn[15:0] = ddr2_array_line0[95:80]; |
insn[31:16] = ddr2_array_line1[95:80]; |
end |
4'hb: |
begin |
insn[15:0] = ddr2_array_line2[95:80]; |
insn[31:16] = ddr2_array_line3[95:80]; |
end |
4'hc: |
begin |
insn[15:0] = ddr2_array_line0[111:96]; |
insn[31:16] = ddr2_array_line1[111:96]; |
end |
4'hd: |
begin |
insn[15:0] = ddr2_array_line2[111:96]; |
insn[31:16] = ddr2_array_line3[111:96]; |
end |
4'he: |
begin |
insn[15:0] = ddr2_array_line0[127:112]; |
insn[31:16] = ddr2_array_line1[127:112]; |
end |
4'hf: |
begin |
insn[15:0] = ddr2_array_line2[127:112]; |
insn[31:16] = ddr2_array_line3[127:112]; |
end |
endcase // case (addr[5:2]) |
SJK */ |
end |
endtask // get_insn_from_xilinx_ddr2 |
`endif |
|
|
task get_insn_from_memory; |
input [31:0] id_pc; |
output [31:0] insn; |
begin |
// do a decode of which server we should look in |
case (id_pc[31:28]) |
`ifdef VERSATILE_SDRAM |
4'h0: |
get_insn_from_sdram(id_pc, insn); |
`endif |
`ifdef XILINX_DDR2 |
4'h0: |
get_insn_from_xilinx_ddr2(id_pc, insn); |
`endif |
`ifdef RAM_WB |
4'h0: |
get_insn_from_wb_ram(id_pc, insn); |
`endif |
4'hf: |
// Flash isn't stored in a memory, it's an FSM so just skip/ignore |
insn = `OR1200_TOP.`CPU_cpu.`CPU_ctrl.id_insn; |
default: |
begin |
$fdisplay(fgeneral, "%t: Unknown memory server for address 0x%h", $time,id_pc); |
insn = 32'hxxxxxxxx; // Unknown server |
end |
endcase // case (id_pc[31:28]) |
end |
endtask // get_insn_from_memory |
|
|
// |
// Look in the iMMU TLB MR for this address' page, if MMUs are on and enabled |
// |
task check_for_immu_entry; |
input [31:0] pc; |
output [31:0] physical_pc; |
output mmu_tlb_miss; |
integer w,x; |
|
reg [31:`OR1200_IMMU_PS] pc_vpn; |
|
reg [`OR1200_ITLBTRW-1:0] itlb_tr; |
reg [`OR1200_ITLBMRW-1:0] itlb_mr; |
|
integer tlb_index; |
reg mmu_en; |
|
|
begin |
mmu_tlb_miss = 0; |
|
`ifdef OR1200_NO_IMMU |
physical_pc = pc; |
`else |
mmu_en = `OR1200_TOP.`CPU_immu_top.immu_en; |
// If MMU is enabled |
if (mmu_en) |
begin |
|
// Look in the iTLB for mapping - get virtual page number |
pc_vpn = pc[31:`OR1200_IMMU_PS]; |
|
tlb_index = pc[`OR1200_ITLB_INDX]; |
|
// Look at the ITLB match register |
itlb_mr = `OR1200_TOP.`CPU_immu_top.`CPU_immu_tlb.itlb_mr_ram.mem[tlb_index]; |
|
// Get the translate register here too, in case there's an error, we print it |
itlb_tr = `OR1200_TOP.`CPU_immu_top.`CPU_immu_tlb.itlb_tr_ram.mem[tlb_index]; |
|
if ((itlb_mr[`OR1200_ITLBMR_V_BITS] === 1'b1) & (itlb_mr[`OR1200_ITLBMRW-1:1] === pc[`OR1200_ITLB_TAG])) |
begin |
// Page number in match register matches page number of virtual PC, so get the physical |
// address from the translate memory |
// Now pull the physical page number out of the tranlsate register (it's after bottom 3 bits) |
physical_pc = {itlb_tr[`OR1200_ITLBTRW-1:`OR1200_ITLBTRW-(32-`OR1200_IMMU_PS)],pc[`OR1200_IMMU_PS-1:0]}; |
//$display("check_for_immu_entry: found match for virtual PC 0x%h in entry %d of iMMU, mr = 0x%x tr = 0x%x, phys. PC = 0x%h", pc, pc[`OR1200_ITLB_INDX], itlb_mr, itlb_tr, physical_pc); |
end // if ((itlb_mr[`OR1200_ITLBMR_V_BITS]) & (itlb_mr[`OR1200_ITLBMRW-1:1] == pc[`OR1200_ITLB_TAG])) |
else |
begin |
|
// Wait a couple of clocks, see if we're doing a miss |
@(posedge `CPU_CORE_CLK); |
@(posedge `CPU_CORE_CLK); |
if (!(`OR1200_TOP.`CPU_immu_top.miss)) // MMU should indicate miss |
begin |
$display("%t: check_for_immu_entry - ERROR - no match found for virtual PC 0x%h in entry %d of iMMU, mr = 0x%x tr = 0x%x, and no miss generated", |
$time, pc, pc[`OR1200_ITLB_INDX], itlb_mr, itlb_tr); |
#100; |
$finish; |
end |
else |
begin |
mmu_tlb_miss = 1; // Started a miss, so ignore this instruction |
end |
end // else: !if((itlb_mr[`OR1200_ITLBMR_V_BITS]) & (itlb_mr[`OR1200_ITLBMRW-1:1] == pc[`OR1200_ITLB_TAG])) |
|
end // if (`OR1200_TOP.`CPU_immu_top.immu_en === 1'b1) |
else |
physical_pc = pc; |
`endif // !`ifdef OR1200_NO_IMMU |
end |
endtask // check_for_immu_entry |
|
|
/* |
Instruction memory coherence checking. |
|
For new instruction executed in the pipeline - ensure it matches |
what is in the main program memory. Perform MMU translations if |
it is enabled. |
*/ |
|
reg [31:0] mem_word; |
reg [31:0] last_addr = 0; |
reg [31:0] last_mem_word; |
reg [31:0] physical_pc; |
reg tlb_miss; |
|
|
`ifdef MEM_COHERENCE_CHECK |
`define MEM_COHERENCE_TRIGGER (`OR1200_TOP.`CPU_cpu.`CPU_ctrl.id_void === 1'b0) |
|
`define INSN_TO_CHECK `OR1200_TOP.`CPU_cpu.`CPU_ctrl.id_insn |
`define PC_TO_CHECK `OR1200_TOP.`CPU_cpu.`CPU_except.id_pc |
|
// Check instruction in decode stage is what is in the RAM |
always @(posedge `CPU_CORE_CLK) |
begin |
if (`MEM_COHERENCE_TRIGGER) |
begin |
|
check_for_immu_entry(`PC_TO_CHECK, physical_pc, tlb_miss); |
|
// Check if it's a new PC - will also get triggered if the |
// instruction has changed since we last checked it |
if (((physical_pc !== last_addr) || |
(last_mem_word != `INSN_TO_CHECK)) & !tlb_miss) |
begin |
// Decode stage not void, check instruction |
// get PC |
get_insn_from_memory(physical_pc, mem_word); |
|
if (mem_word !== `INSN_TO_CHECK) |
begin |
$fdisplay(fgeneral, "%t: Instruction mismatch for PC 0x%h (phys. 0x%h) - memory had 0x%h, CPU had 0x%h", |
$time, `PC_TO_CHECK, physical_pc, mem_word, |
`INSN_TO_CHECK); |
$display("%t: Instruction mismatch for PC 0x%h (phys. 0x%h) - memory had 0x%h, CPU had 0x%h", |
$time, `PC_TO_CHECK, physical_pc, mem_word, |
`INSN_TO_CHECK); |
#200; |
$finish; |
end |
last_addr = physical_pc; |
last_mem_word = mem_word; |
|
end // if (((physical_pc !== last_addr) || (last_mem_word != `INSN_TO_CHECK))... |
end // if (`MEM_COHERENCE_TRIGGER) |
end // always @ (posedge `CPU_CORE_CLK) |
|
`endif // `ifdef MEM_COHERENCE_CHECK |
|
// Trigger on each instruction that gets into writeback stage properly |
reg exception_coming1, exception_coming2, exception_here; |
reg will_jump, jumping, jump_dslot, jumped; |
reg rfe, except_during_rfe; |
reg dslot_expt; |
|
|
// Maintain a copy of GPRS for previous instruction |
reg [31:0] current_gprs [0:31]; |
reg [31:0] current_epcr, current_eear, current_esr, current_sr; |
reg [31:0] previous_gprs [0:31]; |
reg [31:0] previous_epcr; |
reg [31:0] previous_eear; |
reg [31:0] previous_esr; |
reg [31:0] previous_sr; |
|
task update_current_gprs; |
integer j; |
begin |
for(j=0;j<32;j=j+1) |
begin |
get_gpr(j,current_gprs[j]); |
end |
current_sr = `OR1200_TOP.`CPU_cpu.`CPU_sprs.sr ; |
current_esr = `OR1200_TOP.`CPU_cpu.`CPU_sprs.epcr ; |
current_epcr = `OR1200_TOP.`CPU_cpu.`CPU_sprs.epcr ; |
current_eear = `OR1200_TOP.`CPU_cpu.`CPU_sprs.eear ; |
end |
endtask |
|
task update_previous_gprs; |
integer j; |
begin |
for(j=0;j<32;j=j+1) |
begin |
previous_gprs[j] = current_gprs[j]; |
end |
previous_sr = current_sr; |
previous_esr = current_esr; |
previous_epcr = current_epcr; |
previous_eear = current_eear; |
end |
endtask // update_previous_gprs |
|
// Maintain a list of addresses we expect the processor to execute |
// Whenever we hit a branch or jump or rfe we add to this list - when we |
// execute it then we remove it from the list. |
reg [31:0] expected_addresses [0:31]; |
reg expected_addresses_waiting [0:31]; // List indicating if address is waiting |
reg duplicate_expected_addresses_waiting [0:31]; // List indicating if a waiting address will be cleared by the single return |
integer expected_address_num; |
// Initialise things on reset |
always @(`OR1200_TOP.iwb_rst_i) |
begin |
for (expected_address_num=0;expected_address_num<32;expected_address_num=expected_address_num+1) |
begin |
expected_addresses_waiting[expected_address_num] = 0; |
duplicate_expected_addresses_waiting[expected_address_num] = 0; |
end |
expected_address_num = 0; |
end |
|
task add_expected_address; |
input [31:0] expected_pc; |
begin |
if (expected_address_num == 31) |
begin |
$display("%t: Too many branches not reached",$time); |
#100; |
$finish; |
end |
if (expected_addresses_waiting[expected_address_num]) |
begin |
$display("%t: expected_addresses tracker bugged out. expected_address_num = %0d",$time,expected_address_num); |
#100; |
$finish; |
end |
else |
begin |
`ifdef OR1200_MONITOR_JUMPTRACK_DEBUG_OUTPUT |
// Debugging output... |
$display("%t: Adding address 0x%h to expected list index %0d",$time, expected_pc,expected_address_num); |
`endif |
// Put the expected PC in the list, increase the index |
expected_addresses[expected_address_num] = expected_pc; |
expected_addresses_waiting[expected_address_num] = 1; |
expected_address_num = expected_address_num + 1; |
end // else: !if(expected_addresses_waiting[expected_address_num]) |
end |
endtask // add_address_to_expect |
|
// Use this in the case that there's an execption after a jump, in which |
// case we'll have two entries when we finally jump back (the one the |
// original jump put in, and the one put in by the l.rfe or l.jr/ when |
// returning outside of exception handler), so mark this one as OK for |
// removing the duplicate of |
task mark_duplicate_expected_address; |
begin |
// This will always be done on the first instruction of an exception |
// that has occured after a delay slot instruction, so |
// expected_address_num will be one past the entry for the one we will |
// get a duplicate return call for |
duplicate_expected_addresses_waiting[expected_address_num-1] = 1; |
end |
endtask // mark_duplicate_expected_address |
|
|
task check_expected_address; |
input [31:0] pc; |
input expecting_hit; |
integer i,j; |
reg hit; |
reg duplicates; |
|
begin |
hit = 0; |
//$display("%t: check_expected_addr 0x%h, index %0d", |
// $time,pc, expected_address_num); |
if (expected_address_num > 0) |
begin |
// First check the last jump we did |
if (expected_addresses[expected_address_num-1] == pc) |
begin |
// Jump address hit |
// Debugging printout: |
`ifdef OR1200_MONITOR_JUMPTRACK_DEBUG_OUTPUT |
$display("%t: PC address 0x%h was in expected list, index %0d",$time, pc,expected_address_num-1); |
`endif |
expected_address_num = expected_address_num-1; |
expected_addresses_waiting[expected_address_num] = 0; |
hit = 1; |
end |
else |
begin |
// Check through the list |
for(i=0;i<expected_address_num;i=i+1) |
begin |
if (expected_addresses[i] == pc) |
begin |
// Jump address hit |
// Debugging printout: |
`ifdef OR1200_MONITOR_JUMPTRACK_DEBUG_OUTPUT |
$display("%t: PC address 0x%h was in expected list, index %0d",$time, pc,i); |
`endif |
for(j=i;j<expected_address_num;j=j+1) |
begin |
// Pull all of the ones above us down one |
expected_addresses_waiting[j] |
= expected_addresses_waiting[j+1]; |
expected_addresses[j] |
= expected_addresses[j+1]; |
duplicate_expected_addresses_waiting[j] |
= duplicate_expected_addresses_waiting[j+1]; |
end |
expected_address_num = expected_address_num-1; |
hit = 1; |
// quit out. only allow 1 hit |
i = expected_address_num; |
end |
end |
end // else: !if(expected_addresses[expected_ad... |
end // if (expected_address_num > 0) |
|
// Check for duplicates this way because of the way we've declared |
// the array... |
duplicates=0; |
for(i=0;i<32;i=i+1) |
duplicates = duplicates | duplicate_expected_addresses_waiting[i]; |
|
if (hit & duplicates) |
begin |
// If we got a hit, check for duplicates we're also meant to clear |
`ifdef OR1200_MONITOR_JUMPTRACK_DEBUG_OUTPUT |
$display; |
`endif |
for(i=0;i<expected_address_num;i=i+1) |
begin |
if(duplicate_expected_addresses_waiting[i] & |
expected_addresses_waiting[i] & |
expected_addresses[i] == pc) |
begin |
// Found a duplicate call address, clear it |
duplicate_expected_addresses_waiting[i] = 0; |
expected_addresses_waiting[i] = 0; |
|
// Now reorder the list - pull all the ones above us |
// down by one |
for(j=i;j<expected_address_num;j=j+1) |
begin |
expected_addresses_waiting[j] = expected_addresses_waiting[j+1]; |
expected_addresses[j] = expected_addresses[j+1]; |
duplicate_expected_addresses_waiting[j] = duplicate_expected_addresses_waiting[j+1]; |
end |
expected_address_num = expected_address_num - 1; |
end |
end // for (i=0;i<expected_address_num;i=i+1) |
end // if (hit & duplicates) |
|
if (expecting_hit & !hit) |
begin |
// Expected this address to be one we're supposed to jump to, but it wasn't! |
$display("%t: Failed to find current PC, 0x%h, in expected PCs for branches/jumps",$time,pc); |
#100; |
$finish; |
end |
|
end |
endtask // check_expected_address |
|
// Task to assert value of GPR |
task assert_gpr_val; |
input [5:0] regnum; |
input [31:0] assert_value; |
input [31:0] pc; |
reg [31:0] reg_val; |
|
begin |
get_gpr(regnum, reg_val); |
if (reg_val !== assert_value) |
begin |
$display("%t: Assert r%0d value (0x%h) = 0x%h failed. pc=0x%h", |
$time, regnum, reg_val, assert_value,pc); |
#100; |
$finish; |
end |
end |
endtask // assert_gpr_val |
|
// Task to assert something is true |
task assert_this; |
input assert_result; |
input [31:0] pc; |
begin |
if (!assert_result) |
begin |
$display("%t: Assert failed for instruction at pc=0x%h", |
$time , pc); |
#100; |
$finish; |
end |
end |
endtask // assert_gpr_val |
|
// The jumping variable doesn't get updated until we do the proper check of |
// the current instruction reaching the writeback stage. We need to know |
// earlier, eg. in the exception checking part, if this instruction will |
// jump. We do that with this task. |
task check_for_jump; |
input [31:0] insn; |
reg [5:0] opcode; |
reg flag; |
begin |
opcode = insn[`OR1K_OPCODE_POS]; |
// Use the flag from the previous instruction, as the decision |
// is made in the execute stage not in te writeback stage, |
// which is where we're getting our instructions. |
flag = previous_sr[`OR1200_SR_F]; |
|
case (opcode) |
`OR1200_OR32_J, |
`OR1200_OR32_JR, |
`OR1200_OR32_JAL, |
`OR1200_OR32_JALR: |
will_jump = 1; |
`OR1200_OR32_BNF: |
will_jump = !flag; |
`OR1200_OR32_BF: |
will_jump = flag; |
default: |
will_jump = 0; |
endcase // case (opcode) |
end |
endtask // check_for_jump |
|
|
|
// Detect exceptions from the processor here |
reg [13:0] except_trig_r; |
reg exception_coming; |
|
always @(posedge `CPU_CORE_CLK) |
if (`OR1200_TOP.iwb_rst_i) |
begin |
except_trig_r = 0; |
exception_coming = 0; |
except_during_rfe = 0; |
end |
else if ((|`OR1200_TOP.`CPU_cpu.`CPU_except.except_trig) && !exception_coming) |
begin |
exception_coming = 1; |
except_trig_r = `OR1200_TOP.`CPU_cpu.`CPU_except.except_trig; |
except_during_rfe = rfe; |
end |
|
task check_incoming_exceptions; |
begin |
|
// Exception timing - depends on the trigger. |
// Appears to be: |
// tick timer - dslot - 1 instruction delay, else 2 |
// tlb lookasides - 1 instruction for both |
|
casex (except_trig_r) |
13'b1_xxxx_xxxx_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_TICK; |
exception_here = exception_coming2; |
exception_coming2 = jump_dslot ? exception_coming: exception_coming1 ; |
exception_coming1 = jump_dslot ? 0 : exception_coming; |
end |
13'b0_1xxx_xxxx_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_INT; |
#1; |
end |
13'b0_01xx_xxxx_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_ITLBMISS; |
exception_here = exception_coming2; |
exception_coming2 = jump_dslot ? exception_coming : exception_coming1 ; |
exception_coming1 = jump_dslot ? 0 : exception_coming; |
end |
13'b0_001x_xxxx_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_IPF; |
exception_here = exception_coming2; |
exception_coming2 = jump_dslot ? exception_coming : exception_coming1 ; |
exception_coming1 = jump_dslot ? 0 : exception_coming; |
end |
13'b0_0001_xxxx_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_BUSERR; |
exception_here = exception_coming; |
exception_coming2 = 0; |
exception_coming1 = 0; |
end |
13'b0_0000_1xxx_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_ILLEGAL; |
if (will_jump) |
begin |
// Writeback stage instruction will jump, and we have an |
// illegal instruction in the decode/execute stage, which is |
// the delay slot, so indicate the exception is coming... |
exception_here = exception_coming2; |
exception_coming2 = exception_coming; |
exception_coming1 = 0; |
end |
else |
begin |
exception_here = jump_dslot ? |
exception_coming2 : exception_coming; |
exception_coming2 = jump_dslot ? exception_coming : 0; |
exception_coming1 = 0; |
end |
end |
13'b0_0000_01xx_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_ALIGN; |
if(will_jump) |
begin |
exception_here = exception_coming2; |
exception_coming2 = exception_coming; |
exception_coming1 = 0; |
end |
else |
begin |
exception_here = (rfe) ? exception_coming : exception_coming2; |
exception_coming2 = (rfe) ? 0 : exception_coming; |
exception_coming1 = 0; |
end |
end |
13'b0_0000_001x_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_DTLBMISS; |
// Looks like except_trig goes high here after we check the |
// instruction before the itlb miss after a delay slot, so we |
// miss the dslot variable (it gets propegated before we call |
// this task) so we use the jumped variable here to see if we |
// are an exception after a delay slot |
//exception_here = (jumped | rfe) ? exception_coming : exception_coming2 ; |
//exception_coming2 = (jumped | rfe) ? 0 : exception_coming; |
|
exception_here = (jumped | rfe) ? exception_coming : exception_coming2 ; |
exception_coming2 = (jumped | rfe) ? 0 : exception_coming; |
|
exception_coming1 = 0; |
end |
13'b0_0000_0001_xxxx: begin |
//except_type <= #1 `OR1200_EXCEPT_DPF; |
if (jumped) begin // Jumped onto illegal instruction |
exception_here = exception_coming ; |
exception_coming2 = 0; |
exception_coming1 = 0; |
end |
else begin |
exception_here = exception_coming2; |
exception_coming2 = exception_coming; |
exception_coming1 = 0; |
end |
end |
13'b0_0000_0000_1xxx: begin // Data Bus Error |
//except_type <= #1 `OR1200_EXCEPT_BUSERR; |
exception_here = exception_coming2 ; |
exception_coming2 = exception_coming; |
exception_coming1 = 0; |
end |
13'b0_0000_0000_01xx: begin |
//except_type <= #1 `OR1200_EXCEPT_RANGE; |
#1; |
end |
13'b0_0000_0000_001x: begin |
// trap |
#1; |
end |
13'b0_0000_0000_0001: begin |
//except_type <= #1 `OR1200_EXCEPT_SYSCALL; |
exception_here = exception_coming2; |
exception_coming2 = jumped ? exception_coming: exception_coming1 ; |
exception_coming1 = jumped ? 0 : exception_coming; |
end |
endcase // casex (except_trig_r) |
|
exception_coming = 0; |
except_during_rfe = 0; |
|
end |
endtask // check_incoming_exceptions |
|
|
|
|
///////////////////////////////////////////////////////////////////////// |
// Execution tracking task |
///////////////////////////////////////////////////////////////////////// |
|
|
`ifdef OR1200_SYSTEM_CHECKER |
always @(posedge `CPU_CORE_CLK) |
begin |
if (`OR1200_TOP.iwb_rst_i) |
begin |
exception_coming1 = 0;exception_coming2 = 0;exception_here= 0; |
jumping = 0; jump_dslot = 0; jumped = 0; |
rfe = 0; |
end |
if (!`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_freeze) begin |
//#2 ; |
// If instruction isn't a l.nop with bit 16 set (implementation's |
// filler instruction in pipeline), and do not have an exception |
// signaled with a dslot instruction in the execute stage |
if (((`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn[`OR1K_OPCODE_POS] != |
`OR1200_OR32_NOP) || !`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn[16]) |
&& !(`OR1200_TOP.`CPU_cpu.`CPU_except.except_flushpipe && |
`OR1200_TOP.`CPU_cpu.`CPU_except.ex_dslot)) // and not except start |
begin |
|
// Propegate jump-tracking variables |
// If was exception in delay slot, we didn't actually jump |
// so don't set jumped in this case. |
jumped = exception_here ? 0 : jump_dslot; |
jump_dslot = jumping; |
jumping = 0; |
rfe = 0; |
|
// Now, check if current instruction will jump/branch, this is |
// needed by the exception checking code, sets will_jump=1 |
check_for_jump(`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn); |
|
// Now check if it's an exception this instruction |
check_incoming_exceptions; |
|
// Case where we just went to an exception after a jump, so we |
// mark the address we were meant to jump to as a place which will |
// have duplicate return entries in the expected address list |
if (exception_here & (jumped | jump_dslot)) |
begin |
$display("%t: marked as jump address with exception (dup)" |
,$time); |
mark_duplicate_expected_address; |
end |
|
or1200_check_execution(`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn, |
`OR1200_TOP.`CPU_cpu.`CPU_except.wb_pc, |
exception_here); |
//$write("%t: pc:0x%h\t",$time, |
// `OR1200_TOP.`CPU_cpu.`CPU_except.wb_pc); |
// Decode the instruction, print it out |
//or1200_print_op(`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_insn); |
//$write("\t exc:%0h dsl:%0h\n",exception_here,jump_dslot); |
|
|
|
end |
end // if (!`OR1200_TOP.`CPU_cpu.`CPU_ctrl.wb_freeze) |
end // always @ (posedge `CPU_CORE_CLK) |
`endif |
|
|
task or1200_check_execution; |
input [31:0] insn; |
input [31:0] pc; |
input exception; |
|
reg [5:0] opcode; |
|
reg [25:0] j_imm; |
reg [25:0] br_imm; |
|
reg [4:0] rD_num, rA_num, rB_num; |
reg [31:0] rD_val, rA_val, rB_val; |
reg [15:0] imm_16bit; |
|
reg [15:0] mtspr_imm; |
|
reg [3:0] alu_op; |
reg [1:0] shrot_op; |
|
reg [5:0] shroti_imm; |
|
reg [5:0] sf_op; |
|
reg [5:0] xsync_op; |
|
reg flag; |
|
reg [31:0] br_j_ea; // Branch/jump effective address |
|
|
begin |
|
// Instruction opcode |
opcode = insn[`OR1K_OPCODE_POS]; |
// Immediates for jump or branch instructions |
j_imm = insn[`OR1K_J_BR_IMM_POS]; |
br_imm = insn[`OR1K_J_BR_IMM_POS]; |
// Register numbers (D, A and B) |
rD_num = insn[`OR1K_RD_POS]; |
rA_num = insn[`OR1K_RA_POS]; |
rB_num = insn[`OR1K_RB_POS]; |
// Bottom 16 bits when used as immediates in various instructions |
imm_16bit = insn[15:0]; |
// 16-bit immediate for mtspr instructions |
mtspr_imm = {insn[25:21],insn[10:0]}; |
// ALU op for ALU instructions |
alu_op = insn[`OR1K_ALU_OP_POS]; |
// Shift-rotate op for SHROT ALU instructions |
shrot_op = insn[`OR1K_SHROT_OP_POS]; |
shroti_imm = insn[`OR1K_SHROTI_IMM_POS]; |
|
// Set flag op |
sf_op = insn[`OR1K_SF_OP]; |
|
// Xsync/syscall/trap opcode |
xsync_op = insn[`OR1K_XSYNC_OP_POS]; |
|
// Use the flag from the previous instruction, as the decision |
// is made in the execute stage not in te writeback stage, |
// which is where we're getting our instructions. |
flag = previous_sr[`OR1200_SR_F]; |
|
update_current_gprs; |
|
// Check MSbit of the immediate, sign extend if set |
br_j_ea = j_imm[25] ? pc + {4'hf,j_imm,2'b00} : |
pc + {4'h0,j_imm,2'b00}; |
|
if (exception) |
begin |
$display("%t: exception - at 0x%x",$time, pc); |
// get epcr, put it in the addresses we expect to jump |
// back to |
// Maybe DON'T do this. Because maybe in linux things we |
// interrupt out of, we don't want to execute them again? |
//add_expected_address(current_epcr); |
end |
|
|
check_expected_address(pc, (jumped & !exception)); |
|
rfe = 0; |
|
case (opcode) |
`OR1200_OR32_J: |
begin |
// |
// PC < - exts(Immediate < < 2) + JumpInsnAddr |
// |
//The immediate value is shifted left two bits, sign-extended |
// to program counter width, and then added to the address of |
// the jump instruction. The result is the effective address |
// of the jump. The program unconditionally jumps to EA with |
// a delay of one instruction. |
|
add_expected_address(br_j_ea); |
|
jumping = 1; |
end |
`OR1200_OR32_JAL: |
begin |
// |
//PC < - exts(Immediate < < 2) + JumpInsnAddr |
//LR < - DelayInsnAddr + 4 |
// |
// Link reg is r9, check it is PC+8 |
// |
add_expected_address(br_j_ea); |
assert_gpr_val(9, pc+8, pc); |
jumping = 1; // |
end |
`OR1200_OR32_BNF: |
begin |
//EA < - exts(Immediate < < 2) + BranchInsnAddr |
//PC < - EA if SR[F] cleared |
if (!flag) |
begin |
add_expected_address(br_j_ea); |
jumping = 1; |
end |
end |
`OR1200_OR32_BF: |
begin |
//EA < - exts(Immediate < < 2) + BranchInsnAddr |
//PC < - EA if SR[F] set |
if (flag) |
begin |
add_expected_address(br_j_ea); |
jumping = 1; |
end |
end |
`OR1200_OR32_RFE: |
begin |
add_expected_address(current_epcr); |
// jumping variable keeps track of jumps/branches with delay |
// slot - there is none for l.rfe |
rfe = 1; |
end |
`OR1200_OR32_JR: |
begin |
//PC < - rB |
get_gpr(rB_num, rB_val); |
add_expected_address(rB_val); |
jumping = 1; |
end |
`OR1200_OR32_JALR: |
begin |
//PC < - rB |
//LR < - DelayInsnAddr + 4 |
get_gpr(rB_num, rB_val); |
add_expected_address(rB_val); |
assert_gpr_val(9, pc+8, pc); |
jumping = 1; |
end |
/* |
`OR1200_OR32_LWZ, |
`OR1200_OR32_LBZ, |
`OR1200_OR32_LBS, |
`OR1200_OR32_LHZ, |
`OR1200_OR32_LHS, |
`OR1200_OR32_SW, |
`OR1200_OR32_SB, |
`OR1200_OR32_SH: |
begin |
// Should result in databus access if data cache disabled |
$display("%t: lsu instruction",$time); |
end |
|
`OR1200_OR32_MFSPR, |
`OR1200_OR32_MTSPR: |
begin |
// Confirm RF values end up in the correct SPR |
$display("%t: mxspr",$time); |
end |
|
`OR1200_OR32_MOVHI, |
`OR1200_OR32_ADDI, |
`OR1200_OR32_ADDIC, |
`OR1200_OR32_ANDI, |
`OR1200_OR32_ORI, |
`OR1200_OR32_XORI, |
`OR1200_OR32_MULI, |
`OR1200_OR32_ALU: |
begin |
// Double check operations done on RF and immediate values |
$display("%t: ALU op",$time); |
end |
|
`OR1200_OR32_SH_ROTI: |
begin |
// Rotate according to immediate - maybe should be in ALU ops |
$display("%t: rotate op",$time); |
end |
|
`OR1200_OR32_SFXXI, |
`OR1200_OR32_SFXX: |
begin |
// Set flag - do the check oursevles, check flag |
$display("%t: set flag op",$time); |
end |
|
`OR1200_OR32_MACI, |
`OR1200_OR32_MACMSB: |
begin |
// Either, multiply signed and accumulate, l.mac |
// or multiply signed and subtract, l.msb |
$display("%t: MAC op",$time); |
end |
*/ |
|
/*default: |
begin |
$display("%t: Unknown opcode 0x%h at pc 0x%x\n", |
$time,opcode, pc); |
end |
*/ |
endcase // case (opcode) |
|
update_previous_gprs; |
|
end |
endtask // or1200_check_execution |
|
|
///////////////////////////////////////////////////////////////////////// |
// Instruction decode task |
///////////////////////////////////////////////////////////////////////// |
|
task or1200_print_op; |
input [31:0] insn; |
|
reg [5:0] opcode; |
|
reg [25:0] j_imm; |
reg [25:0] br_imm; |
|
reg [4:0] rD_num, rA_num, rB_num; |
reg [31:0] rA_val, rB_val; |
reg [15:0] imm_16bit; |
reg [10:0] imm_split16bit; |
|
reg [3:0] alu_op; |
reg [1:0] shrot_op; |
|
reg [5:0] shroti_imm; |
|
reg [5:0] sf_op; |
|
reg [5:0] xsync_op; |
|
begin |
// Instruction opcode |
opcode = insn[`OR1K_OPCODE_POS]; |
// Immediates for jump or branch instructions |
j_imm = insn[`OR1K_J_BR_IMM_POS]; |
br_imm = insn[`OR1K_J_BR_IMM_POS]; |
// Register numbers (D, A and B) |
rD_num = insn[`OR1K_RD_POS]; |
rA_num = insn[`OR1K_RA_POS]; |
rB_num = insn[`OR1K_RB_POS]; |
// Bottom 16 bits when used as immediates in various instructions |
imm_16bit = insn[15:0]; |
// Bottom 11 bits used as immediates for l.sX instructions |
|
// Split 16-bit immediate for l.mtspr/l.sX instructions |
imm_split16bit = {insn[25:21],insn[10:0]}; |
// ALU op for ALU instructions |
alu_op = insn[`OR1K_ALU_OP_POS]; |
// Shift-rotate op for SHROT ALU instructions |
shrot_op = insn[`OR1K_SHROT_OP_POS]; |
shroti_imm = insn[`OR1K_SHROTI_IMM_POS]; |
|
// Set flag op |
sf_op = insn[`OR1K_SF_OP]; |
|
// Xsync/syscall/trap opcode |
xsync_op = insn[`OR1K_XSYNC_OP_POS]; |
|
case (opcode) |
`OR1200_OR32_J: |
begin |
$fwrite(finsn,"l.j 0x%h", {j_imm,2'b00}); |
end |
|
`OR1200_OR32_JAL: |
begin |
$fwrite(finsn,"l.jal 0x%h", {j_imm,2'b00}); |
end |
|
`OR1200_OR32_BNF: |
begin |
$fwrite(finsn,"l.bnf 0x%h", {br_imm,2'b00}); |
end |
|
`OR1200_OR32_BF: |
begin |
$fwrite(finsn,"l.bf 0x%h", {br_imm,2'b00}); |
end |
|
`OR1200_OR32_RFE: |
begin |
$fwrite(finsn,"l.rfe"); |
end |
|
`OR1200_OR32_JR: |
begin |
$fwrite(finsn,"l.jr r%0d",rB_num); |
end |
|
`OR1200_OR32_JALR: |
begin |
$fwrite(finsn,"l.jalr r%0d",rB_num); |
end |
|
`OR1200_OR32_LWZ: |
begin |
$fwrite(finsn,"l.lwz r%0d,0x%0h(r%0d)",rD_num,imm_16bit,rA_num); |
end |
|
`OR1200_OR32_LBZ: |
begin |
$fwrite(finsn,"l.lbz r%0d,0x%0h(r%0d)",rD_num,imm_16bit,rA_num); |
end |
|
`OR1200_OR32_LBS: |
begin |
$fwrite(finsn,"l.lbs r%0d,0x%0h(r%0d)",rD_num,imm_16bit,rA_num); |
end |
|
`OR1200_OR32_LHZ: |
begin |
$fwrite(finsn,"l.lhz r%0d,0x%0h(r%0d)",rD_num,imm_16bit,rA_num); |
end |
|
`OR1200_OR32_LHS: |
begin |
$fwrite(finsn,"l.lhs r%0d,0x%0h(r%0d)",rD_num,imm_16bit,rA_num); |
end |
|
`OR1200_OR32_SW: |
begin |
$fwrite(finsn,"l.sw 0x%0h(r%0d),r%0d",imm_split16bit,rA_num,rB_num); |
end |
|
`OR1200_OR32_SB: |
begin |
$fwrite(finsn,"l.sb 0x%0h(r%0d),r%0d",imm_split16bit,rA_num,rB_num); |
end |
|
`OR1200_OR32_SH: |
begin |
$fwrite(finsn,"l.sh 0x%0h(r%0d),r%0d",imm_split16bit,rA_num,rB_num); |
end |
|
`OR1200_OR32_MFSPR: |
begin |
$fwrite(finsn,"l.mfspr r%0d,r%0d,0x%h",rD_num,rA_num,imm_16bit,); |
end |
|
`OR1200_OR32_MTSPR: |
begin |
$fwrite(finsn,"l.mtspr r%0d,r%0d,0x%h",rA_num,rB_num,imm_split16bit); |
end |
|
`OR1200_OR32_MOVHI: |
begin |
if (!insn[16]) |
$fwrite(finsn,"l.movhi r%0d,0x%h",rD_num,imm_16bit); |
else |
$fwrite(finsn,"l.macrc r%0d",rD_num); |
end |
|
`OR1200_OR32_ADDI: |
begin |
$fwrite(finsn,"l.addi r%0d,r%0d,0x%h",rD_num,rA_num,imm_16bit); |
end |
|
`OR1200_OR32_ADDIC: |
begin |
$fwrite(finsn,"l.addic r%0d,r%0d,0x%h",rD_num,rA_num,imm_16bit); |
end |
|
`OR1200_OR32_ANDI: |
begin |
$fwrite(finsn,"l.andi r%0d,r%0d,0x%h",rD_num,rA_num,imm_16bit); |
end |
|
`OR1200_OR32_ORI: |
begin |
$fwrite(finsn,"l.ori r%0d,r%0d,0x%h",rD_num,rA_num,imm_16bit); |
end |
|
`OR1200_OR32_XORI: |
begin |
$fwrite(finsn,"l.xori r%0d,r%0d,0x%h",rD_num,rA_num,imm_16bit); |
end |
|
`OR1200_OR32_MULI: |
begin |
$fwrite(finsn,"l.muli r%0d,r%0d,0x%h",rD_num,rA_num,imm_16bit); |
end |
|
`OR1200_OR32_ALU: |
begin |
case(alu_op) |
`OR1200_ALUOP_ADD: |
$fwrite(finsn,"l.add "); |
`OR1200_ALUOP_ADDC: |
$fwrite(finsn,"l.addc "); |
`OR1200_ALUOP_SUB: |
$fwrite(finsn,"l.sub "); |
`OR1200_ALUOP_AND: |
$fwrite(finsn,"l.and "); |
`OR1200_ALUOP_OR: |
$fwrite(finsn,"l.or "); |
`OR1200_ALUOP_XOR: |
$fwrite(finsn,"l.xor "); |
`OR1200_ALUOP_MUL: |
$fwrite(finsn,"l.mul "); |
`OR1200_ALUOP_SHROT: |
begin |
case(shrot_op) |
`OR1200_SHROTOP_SLL: |
$fwrite(finsn,"l.sll "); |
`OR1200_SHROTOP_SRL: |
$fwrite(finsn,"l.srl "); |
`OR1200_SHROTOP_SRA: |
$fwrite(finsn,"l.sra "); |
`OR1200_SHROTOP_ROR: |
$fwrite(finsn,"l.ror "); |
endcase // case (shrot_op) |
end |
`OR1200_ALUOP_DIV: |
$fwrite(finsn,"l.div "); |
`OR1200_ALUOP_DIVU: |
$fwrite(finsn,"l.divu "); |
`OR1200_ALUOP_CMOV: |
$fwrite(finsn,"l.cmov "); |
endcase // case (alu_op) |
$fwrite(finsn,"r%0d,r%0d,r%0d",rD_num,rA_num,rB_num); |
end |
|
`OR1200_OR32_SH_ROTI: |
begin |
case(shrot_op) |
`OR1200_SHROTOP_SLL: |
$fwrite(finsn,"l.slli "); |
`OR1200_SHROTOP_SRL: |
$fwrite(finsn,"l.srli "); |
`OR1200_SHROTOP_SRA: |
$fwrite(finsn,"l.srai "); |
`OR1200_SHROTOP_ROR: |
$fwrite(finsn,"l.rori "); |
endcase // case (shrot_op) |
$fwrite(finsn,"r%0d,r%0d,0x%h",rD_num,rA_num,shroti_imm); |
end |
|
`OR1200_OR32_SFXXI: |
begin |
case(sf_op[2:0]) |
`OR1200_COP_SFEQ: |
$fwrite(finsn,"l.sfeqi "); |
`OR1200_COP_SFNE: |
$fwrite(finsn,"l.sfnei "); |
`OR1200_COP_SFGT: |
begin |
if (sf_op[`OR1200_SIGNED_COMPARE]) |
$fwrite(finsn,"l.sfgtsi "); |
else |
$fwrite(finsn,"l.sfgtui "); |
end |
`OR1200_COP_SFGE: |
begin |
if (sf_op[`OR1200_SIGNED_COMPARE]) |
$fwrite(finsn,"l.sfgesi "); |
else |
$fwrite(finsn,"l.sfgeui "); |
end |
`OR1200_COP_SFLT: |
begin |
if (sf_op[`OR1200_SIGNED_COMPARE]) |
$fwrite(finsn,"l.sfltsi "); |
else |
$fwrite(finsn,"l.sfltui "); |
end |
`OR1200_COP_SFLE: |
begin |
if (sf_op[`OR1200_SIGNED_COMPARE]) |
$fwrite(finsn,"l.sflesi "); |
else |
$fwrite(finsn,"l.sfleui "); |
end |
endcase // case (sf_op[2:0]) |
|
$fwrite(finsn,"r%0d,0x%h",rA_num, imm_16bit); |
|
end // case: `OR1200_OR32_SFXXI |
|
`OR1200_OR32_SFXX: |
begin |
case(sf_op[2:0]) |
`OR1200_COP_SFEQ: |
$fwrite(finsn,"l.sfeq "); |
`OR1200_COP_SFNE: |
$fwrite(finsn,"l.sfne "); |
`OR1200_COP_SFGT: |
begin |
if (sf_op[`OR1200_SIGNED_COMPARE]) |
$fwrite(finsn,"l.sfgts "); |
else |
$fwrite(finsn,"l.sfgtu "); |
end |
`OR1200_COP_SFGE: |
begin |
if (sf_op[`OR1200_SIGNED_COMPARE]) |
$fwrite(finsn,"l.sfges "); |
else |
$fwrite(finsn,"l.sfgeu "); |
end |
`OR1200_COP_SFLT: |
begin |
if (sf_op[`OR1200_SIGNED_COMPARE]) |
$fwrite(finsn,"l.sflts "); |
else |
$fwrite(finsn,"l.sfltu "); |
end |
`OR1200_COP_SFLE: |
begin |
if (sf_op[`OR1200_SIGNED_COMPARE]) |
$fwrite(finsn,"l.sfles "); |
else |
$fwrite(finsn,"l.sfleu "); |
end |
|
endcase // case (sf_op[2:0]) |
|
$fwrite(finsn,"r%0d,r%0d",rA_num, rB_num); |
|
end |
|
`OR1200_OR32_MACI: |
begin |
$fwrite(finsn,"l.maci r%0d,0x%h",rA_num,imm_16bit); |
end |
|
`OR1200_OR32_MACMSB: |
begin |
if(insn[3:0] == 4'h1) |
$fwrite(finsn,"l.mac "); |
else if(insn[3:0] == 4'h2) |
$fwrite(finsn,"l.msb "); |
|
$fwrite(finsn,"r%0d,r%0d",rA_num,rB_num); |
end |
|
`OR1200_OR32_NOP: |
begin |
$fwrite(finsn,"l.nop 0x%0h",imm_16bit); |
end |
|
`OR1200_OR32_XSYNC: |
begin |
case (xsync_op) |
5'd0: |
$fwrite(finsn,"l.sys 0x%h",imm_16bit); |
5'd8: |
$fwrite(finsn,"l.trap 0x%h",imm_16bit); |
5'd16: |
$fwrite(finsn,"l.msync"); |
5'd20: |
$fwrite(finsn,"l.psync"); |
5'd24: |
$fwrite(finsn,"l.csync"); |
default: |
begin |
$display("%t: Instruction with opcode 0x%h has bad specific type information: 0x%h",$time,opcode,insn); |
$fwrite(finsn,"%t: Instruction with opcode 0x%h has has bad specific type information: 0x%h",$time,opcode,insn); |
end |
endcase // case (xsync_op) |
end |
|
default: |
begin |
$display("%t: Unknown opcode 0x%h",$time,opcode); |
$fwrite(finsn,"%t: Unknown opcode 0x%h",$time,opcode); |
end |
|
endcase // case (opcode) |
|
end |
endtask // or1200_print_op |
|
|
|
endmodule |
xilinx/atlys/bench/verilog/or1200_monitor.v
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property