/*******************************************************************************
* Module: ddrc_test01_testbench
* Date:2014-05-20
* Author: Andrey Filippov
* Description: testbench for ddrc_test01
*
* Copyright (c) 2014 Elphel, Inc.
* ddrc_test01_testbench.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ddrc_test01_testbench.v 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`timescale 1ns/1ps
`define use200Mhz 1
module ddrc_test01_testbench #(
parameter PHASE_WIDTH = 8,
parameter SLEW_DQ = "SLOW",
parameter SLEW_DQS = "SLOW",
parameter SLEW_CMDA = "SLOW",
parameter SLEW_CLK = "SLOW",
parameter IBUF_LOW_PWR = "TRUE",
`ifdef use200Mhz
parameter real REFCLK_FREQUENCY = 200.0, // 300.0,
parameter HIGH_PERFORMANCE_MODE = "FALSE",
parameter CLKIN_PERIOD = 20, // 10, //ns >1.25, 6001.25, 6001 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(5,0,0,0); // tMOD
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// first read
// read
data <= {
15'h0, //{5'b0,ca[9:0]},
3'h0, //ba[2:0], //phy_bank_in[2:0],
3'b010, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
3'h0, //ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, // phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
//repeat remaining reads
for (i=1;i1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b1, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
end
// nop
data <= {
15'b0, // skip 0
3'h0, //ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
3'h0, //ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
3'h0, //ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(2,0,1,0); // keep dci enabled
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// Turn off read pattern mode
@(posedge CLK)
data <= encode_seq_word(
mr3_norm[14:0], // [14:0] phy_addr_in;
mr3_norm[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b111, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in == 0; // first/second half-cycle,
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(5,0,1,0 ); // tMOD (keep DCI enabled)
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// Turn off DCI
data <= encode_seq_word(
15'h0, // [14:0] phy_addr_in;
3'h0, //mr3_norm[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b000, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in == 1;
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in;
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(0,1,0,0); // end of sequence (no dci, no odt)
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
end
endtask
task set_read_block;
input [ 2:0] ba;
input [14:0] ra;
input [ 9:0] ca;
reg [31:0] cmd_addr;
reg [31:0] data;
integer i;
begin
cmd_addr <= BASEADDR_CMD0 + (READ_BLOCK_OFFSET << 2);
// activate
data <= {
ra[14:0],
ba[2:0], //phy_bank_in[2:0],
3'b100, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// see if pause is needed . See when buffer read should be started - maybe before WR command
data <= encode_seq_skip(1,0,0,0);
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// first read
// read
data <= {
{5'b0,ca[9:0]},
ba[2:0], //phy_bank_in[2:0],
3'b010, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, // phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
//repeat remaining reads
for (i=1;i<64;i=i+1) begin
// read
data <= {
{5'b0,ca[9:0]} + (i<<3),
ba[2:0], //phy_bank_in[2:0],
3'b010, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b1, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
end
// nop
data <= {
15'b0, // skip 0
ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// tRTP = 4*tCK is already satisfied, no skip here
/*
data <= encode_seq_skip(1,0,1,0); // keep DCI // What delay is needed tRTP (4 tCK or 7.5ns)
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
*/
// precharge
data <= {
ra[14:0],
ba[2:0], //phy_bank_in[2:0],
3'b101, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, // keep DCI enabled
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(2,0,1,0); // keep DCI
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(0,1,0,0); // end of sequence . TODO: verify DCI is disabled here - yes, OK
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
end
endtask
task set_write_block;
input [ 2:0] ba;
input [14:0] ra;
input [ 9:0] ca;
reg [31:0] cmd_addr;
reg [31:0] data;
integer i;
begin
cmd_addr <= BASEADDR_CMD0 + (WRITE_BLOCK_OFFSET << 2);
// activate
data <= {
ra[14:0],
ba[2:0], //phy_bank_in[2:0],
3'b100, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// see if pause is needed . See when buffer read should be started - maybe before WR command
data <= encode_seq_skip(1,0,0,0); // tRCD
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// first write
// write
data <= {
{5'b0,ca[9:0]},
ba[2:0], //phy_bank_in[2:0],
3'b011, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in,
1'b0, // phy_cke_inv,
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in,
1'b0, // phy_cke_inv,
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b1, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b1, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
//repeat remaining writes
for (i=1;i<64;i=i+1) begin
// write
data <= {
{5'b0,ca[9:0]} + (i<<3),
ba[2:0], //phy_bank_in[2:0],
3'b011, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in,
1'b0, // phy_cke_inv,
1'b1, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b1, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b1, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b1, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
end
// nop
data <= {
15'b0, // skip 0
ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b1, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b1, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in,
1'b0, // phy_cke_inv,
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b1, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b1, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// nop
data <= {
15'b0, // skip 0
ba[2:0], //phy_bank_in[2:0],
3'b000, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in,
1'b0, // phy_cke_inv,
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b1, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// ODT off, it has latency
data <= encode_seq_skip(2,0,0,0); // tWR = 15ns (6 cycles for 2.5ns) from end of write (not write command)
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// precharge, ODT off
data <= {
ra[14:0],
ba[2:0], //phy_bank_in[2:0],
3'b101, // phy_rcw_in[2:0], // {ras,cas,we}
1'b0, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(2,0,0,0); //
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(0,1,0,0); // end of sequence
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
end
endtask
task set_write_lev;
input [CMD_PAUSE_BITS-1:0] nrep;
reg [17:0] mr1_norm;
reg [17:0] mr1_wlev;
reg [31:0] cmd_addr;
reg [31:0] data;
reg [CMD_PAUSE_BITS-1:0] dqs_low_rpt;
reg [CMD_PAUSE_BITS-1:0] nrep_minus_1;
begin
dqs_low_rpt <= 8;
nrep_minus_1 <= nrep-1;
mr1_norm <= ddr3_mr1 (
1'h0, // qoff; // output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
1'h0, // tdqs; // termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
3'h2, // [2:0] rtt; // on-die termination resistance: // 3'b010 - RZQ/2 (120 Ohm)
1'h0, // wlev; // write leveling
2'h0, // ods; // output drive strength: // 2'b00 - RZQ/6 - 40 Ohm
2'h0, // [1:0] al; // additive latency: 2'b00 - disabled (AL=0)
1'b0); // dll; // 0 - DLL enabled (normal), 1 - DLL disabled
mr1_wlev <= ddr3_mr1 (
1'h0, // qoff; // output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
1'h0, // tdqs; // termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
3'h2, // [2:0] rtt; // on-die termination resistance: // 3'b010 - RZQ/2 (120 Ohm)
1'h1, // wlev; // write leveling
2'h0, // ods; // output drive strength: // 2'b00 - RZQ/6 - 40 Ohm
2'h0, // [1:0] al; // additive latency: 2'b00 - disabled (AL=0)
1'b0); // dll; // 0 - DLL enabled (normal), 1 - DLL disabled
cmd_addr <= BASEADDR_CMD0 + (WRITELEV_OFFSET<<2);
// Enter write leveling mode
@(posedge CLK)
data <= encode_seq_word(
mr1_wlev[14:0], // [14:0] phy_addr_in;
mr1_wlev[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b111, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in == 0; // first/second half-cycle,
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(13,0,0,0); // tWLDQSEN=25tCK
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// enable DQS output, keep it low (15 more tCK for the total of 40 tCK
data <= { // encode_seq_skip(nrep,0); // Adjust skip
{15-CMD_DONE_BIT{1'b0}},
dqs_low_rpt, // 16 tCK
3'b0, //phy_bank_in[2:0],
3'b0, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in,
1'b0, // phy_cke_inv,
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// Toggle DQS as needed for write leveling, write to buffer
data <= { // encode_seq_skip(nrep,0); // Adjust skip
{15-CMD_DONE_BIT{1'b0}},
nrep_minus_1[CMD_PAUSE_BITS-1:0],
3'b0, //phy_bank_in[2:0],
3'b0, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b1, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// continue toggling, but disable writing to buffer (used same wbuf latency as for read)
data <= { // encode_seq_skip(nrep,0); // Adjust skip
15'h4, // 4 cycles
3'b0, //phy_bank_in[2:0],
3'b0, // phy_rcw_in[2:0], // {ras,cas,we}
1'b1, // phy_odt_in, // may be optimized?
1'b0, // phy_cke_inv, // may be optimized?
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_en_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b1, // phy_dqs_toggle_en;
1'b1, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // no write
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// data <= encode_seq_skip(1,0,1,1); // Keep DCI and ODT active
// @(posedge CLK)
// axi_write_single(cmd_addr, data);
// cmd_addr <= cmd_addr + 4;
//
data <= encode_seq_skip(2,0,1,0); // Keep DCI (but not ODT) active ODT should be off befor MRS
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// exit write leveling mode, ODT off, DCI off
data <= encode_seq_word(
mr1_norm[14:0], // [14:0] phy_addr_in;
mr1_norm[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b111, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in == 0; // first/second half-cycle,
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(5,0,0,0); // tMOD
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// Ready for normal operation
data <= encode_seq_skip(10,1,0,0); // sequence done bit, skip length is ignored
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
end
endtask
task set_refresh;
input [ 9:0] t_rfc; // =50 for tCK=2.5ns
input [ 7:0] t_refi; // 48/97 for normal, 8 - for simulation
reg [31:0] cmd_addr;
reg [31:0] data;
begin
cmd_addr <= BASEADDR_CMD0 + (REFRESH_OFFSET<<2);
@(posedge CLK)
data <= encode_seq_word(
15'h0, // [14:0] phy_addr_in;
3'b0, // [ 2:0] phy_bank_in; //TODO: debug!
3'b110, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in; // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(t_rfc,0,0,0); // =50 tREFI=260 ns before next ACTIVATE or REFRESH, @2.5ns clock, @5ns cycle
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// Ready for normal operation
data <= encode_seq_skip(0,1,0,0); // sequence done bit, skip length is ignored
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
axi_write_single(BASEADDR_REFRESH_ADDR, REFRESH_OFFSET);
axi_write_single(BASEADDR_REFRESH_PER, {24'h0,t_refi});
end
endtask
task set_mrs; // will also calibrate ZQ
input reset_dll;
// reg [ADDRESS_NUMBER+2:0] mr0;
// reg [ADDRESS_NUMBER+2:0] mr1;
// reg [ADDRESS_NUMBER+2:0] mr2;
// reg [ADDRESS_NUMBER+2:0] mr3;
reg [17:0] mr0;
reg [17:0] mr1;
reg [17:0] mr2;
reg [17:0] mr3;
reg [31:0] cmd_addr;
reg [31:0] data;
begin
mr0 <= ddr3_mr0 (
1'h0, // pd; // precharge power down 0 - dll off (slow exit), 1 - dll on (fast exit)
3'h2, // [2:0] wr; // write recovery (encode ceil(tWR/tCK)) // 3'b010: 6
reset_dll, // dll_rst; // 1 - dll reset (self clearing bit)
4'h4, // [3:0] cl; // CAS latency: // 0100: 6 (time 15ns)
1'h0, // bt; // read burst type: 0 sequential (nibble), 1 - interleave
2'h0); // [1:0] bl; // burst length: // 2'b00 - fixed BL8
mr1 <= ddr3_mr1 (
1'h0, // qoff; // output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
1'h0, // tdqs; // termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
3'h2, // [2:0] rtt; // on-die termination resistance: // 3'b010 - RZQ/2 (120 Ohm)
1'h0, // wlev; // write leveling
2'h0, // ods; // output drive strength: // 2'b00 - RZQ/6 - 40 Ohm
2'h0, // [1:0] al; // additive latency: 2'b00 - disabled (AL=0)
1'b0); // dll; // 0 - DLL enabled (normal), 1 - DLL disabled
mr2 <= ddr3_mr2 (
2'h0, // [1:0] rtt_wr; // Dynamic ODT : // 2'b00 - disabled, 2'b01 - RZQ/4 = 60 Ohm, 2'b10 - RZQ/2 = 120 Ohm
1'h0, // srt; // Self-refresh temperature 0 - normal (0-85C), 1 - extended (<=95C)
1'h0, // asr; // Auto self-refresh 0 - disabled (manual), 1 - enabled (auto)
3'h0); // [2:0] cwl; // CAS write latency:3'b000 5CK (tCK >= 2.5ns), 3'b001 6CK (1.875ns <= tCK < 2.5ns)
mr3 <= ddr3_mr3 (
1'h0, // mpr; // MPR mode: 0 - normal, 1 - dataflow from MPR
2'h0); // [1:0] mpr_rf; // MPR read function: 2'b00: predefined pattern 0101...
cmd_addr <= BASEADDR_CMD0 + (INITIALIZE_OFFSET << 2);
@(posedge CLK)
$display("mr0=0x%x",mr0);
$display("mr1=0x%x",mr1);
$display("mr2=0x%x",mr2);
$display("mr3=0x%x",mr3);
data <= encode_seq_word(
mr2[14:0], // [14:0] phy_addr_in;
mr2[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b111, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in; // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(1,0,0,0); // 6 cycles between mrs commands
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_word(
mr3[14:0], // [14:0] phy_addr_in;
mr3[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b111, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in; // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// TODO: function - does not check arguments number
data <= encode_seq_skip(0,0,0,0); // 5 cycles between mrs commands (next command has phy_sel_in == 1)
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_word(
mr1[14:0], // [14:0] phy_addr_in;
mr1[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b111, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b1, // phy_sel_in == 1 (test); // first/second half-cycle,
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(2,0,0,0); // 7 cycles between mrs commands ( prev. command had phy_sel_in == 1)
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_word(
mr0[14:0], // [14:0] phy_addr_in;
mr0[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b111, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in; // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(5,0,0,0); // tMOD = 12 CK or 15ns, (tMOD/2)-1
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_word(
15'h400, // A10 == 1 -> ZQCL
3'h0, // phy_bank_in;
3'b001, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive - ZQC?
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in; // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr;
1'b0, // phy_buf_rd; // connect to external buffer
1'b0); // add NOP after the current command, keep other data
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
data <= encode_seq_skip(256,0,0,0); // 512 clock cycles after ZQCL
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// Ready for normal operation
data <= encode_seq_skip(10,1,0,0); // sequence done bit, skip length is ignored
@(posedge CLK)
axi_write_single(cmd_addr, data);
cmd_addr <= cmd_addr + 4;
// TODO: Function of function does not work - debug
/*
axi_write_single(cmd_addr,
encode_seq_word(
mr2[14:0], // [14:0] phy_addr_in;
mr2[17:15], // [ 2:0] phy_bank_in; //TODO: debug!
3'b111, // [ 2:0] phy_rcw_in; // {ras,cas,we}, positive
1'b0, // phy_odt_in; // may be optimized?
1'b0, // phy_cke_inv; // may be optimized?
1'b0, // phy_sel_in; // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in;
1'b0, // phy_dqs_en_in;
1'b0, // phy_dqs_toggle_en;
1'b0, // phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr; // connect to external buffer
1'b0, // phy_buf_rd; // connect to external buffer
1'b0)); // add NOP after the current command, keep other data
*/
end
endtask
function [31:0] encode_seq_word;
input [14:0] phy_addr_in; // also provides pause length when the command is NOP
input [ 2:0] phy_bank_in;
input [ 2:0] phy_rcw_in; // {ras,cas,we}
input phy_odt_in; // may be optimized?
input phy_cke_inv; // invert CKE
input phy_sel_in; // first/second half-cycle, other will be nop (cke+odt applicable to both)
input phy_dq_en_in;
input phy_dqs_en_in;
input phy_dqs_toggle_en;//enable toggle DQS according to the pattern
input phy_dci_en_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
input phy_buf_wr; // connect to external buffer
input phy_buf_rd; // connect to external buffer
input add_nop; // add NOP after the current command, keep other data
begin
encode_seq_word={
phy_addr_in[14:0],
phy_bank_in[2:0],
phy_rcw_in[2:0], // {ras,cas,we}, positive logic (3'b0 - NOP)
phy_odt_in, // may be optimized?
phy_cke_inv, // invert CKE
phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
phy_dqs_en_in, //phy_dqs_tri_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
phy_dqs_toggle_en,//enable toggle DQS according to the pattern
phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
phy_buf_wr, // connect to external buffer (but only if not paused)
phy_buf_rd, // connect to external buffer (but only if not paused)
add_nop, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
end
endfunction
// parameter CMD_PAUSE_BITS= 6, // numer of (address) bits to encode pause
// parameter CMD_DONE_BIT= 6 // bit number (address) to signal sequence done
function [31:0] encode_seq_skip;
input [CMD_PAUSE_BITS-1:0] skip;
input done;
input dci_en;
input odt_en;
begin
encode_seq_skip={
{14-CMD_DONE_BIT{1'b0}},
done,
skip[CMD_PAUSE_BITS-1:0],
3'b0, //phy_bank_in[2:0],
3'b0, // phy_rcw_in[2:0], // {ras,cas,we}
odt_en, // phy_odt_in,
1'b0, // phy_cke_in, // may be optimized?
1'b0, // phy_sel_in, // first/second half-cycle, other will be nop (cke+odt applicable to both)
1'b0, // phy_dq_en_in, //phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0)
1'b0, // phy_dqs_en_in, //phy_dqs_tri_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0)
1'b0, //enable toggle DQS according to the pattern
dci_en, // phy_dci_en_in, //phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
1'b0, // phy_buf_wr, // connect to external buffer (but only if not paused)
1'b0, // phy_buf_rd, // connect to external buffer (but only if not paused)
1'b0, // add NOP after the current command, keep other data
1'b0 // Reserved for future use
};
end
endfunction
function [ADDRESS_NUMBER+2:0] ddr3_mr0;
input pd; // precharge power down 0 - dll off (slow exit), 1 - dll on (fast exit)
input [2:0] wr; // write recovery:
// 3'b000: 16
// 3'b001: 5
// 3'b010: 6
// 3'b011: 7
// 3'b100: 8
// 3'b101: 10
// 3'b110: 12
// 3'b111: 14
input dll_rst; // 1 - dll reset (self clearing bit)
input [3:0] cl; // CAS latency (>=15ns):
// 0000: reserved
// 0010: 5
// 0100: 6
// 0110: 7
// 1000: 8
// 1010: 9
// 1100: 10
// 1110: 11
// 0001: 12
// 0011: 13
// 0101: 14
input bt; // read burst type: 0 sequential (nibble), 1 - interleaved
input [1:0] bl; // burst length:
// 2'b00 - fixed BL8
// 2'b01 - 4 or 8 on-the-fly by A12
// 2'b10 - fixed BL4 (chop)
// 2'b11 - reserved
begin
ddr3_mr0 = {
3'b0,
{ADDRESS_NUMBER-13{1'b0}},
pd, // MR0.12
wr, // MR0.11_9
dll_rst, // MR0.8
1'b0, // MR0.7
cl[3:1], // MR0.6_4
bt, // MR0.3
cl[0], // MR0.2
bl[1:0]}; // MR0.1_0
end
endfunction
function [ADDRESS_NUMBER+2:0] ddr3_mr1;
input qoff; // output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
input tdqs; // termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
input [2:0] rtt; // on-die termination resistance:
// 3'b000 - disabled
// 3'b001 - RZQ/4 (60 Ohm)
// 3'b010 - RZQ/2 (120 Ohm)
// 3'b011 - RZQ/6 (40 Ohm)
// 3'b100 - RZQ/12(20 Ohm)
// 3'b101 - RZQ/8 (30 Ohm)
// 3'b11x - reserved
input wlev; // write leveling
input [1:0] ods; // output drive strength:
// 2'b00 - RZQ/6 - 40 Ohm
// 2'b01 - RZQ/7 - 34 Ohm
// 2'b1x - reserved
input [1:0] al; // additive latency:
// 2'b00 - disabled (AL=0)
// 2'b01 - AL=CL-1;
// 2'b10 - AL=CL-2
// 2'b11 - reserved
input dll; // 0 - DLL enabled (normal), 1 - DLL disabled
begin
ddr3_mr1 = {
3'h1,
{ADDRESS_NUMBER-13{1'b0}},
qoff, // MR1.12
tdqs, // MR1.11
1'b0, // MR1.10
rtt[2], // MR1.9
1'b0, // MR1.8
wlev, // MR1.7
rtt[1], // MR1.6
ods[1], // MR1.5
al[1:0], // MR1.4_3
rtt[0], // MR1.2
ods[0], // MR1.1
dll}; // MR1.0
end
endfunction
function [ADDRESS_NUMBER+2:0] ddr3_mr2;
input [1:0] rtt_wr; // Dynamic ODT :
// 2'b00 - disabled
// 2'b01 - RZQ/4 = 60 Ohm
// 2'b10 - RZQ/2 = 120 Ohm
// 2'b11 - reserved
input srt; // Self-refresh temperature 0 - normal (0-85C), 1 - extended (<=95C)
input asr; // Auto self-refresh 0 - disabled (manual), 1 - enabled (auto)
input [2:0] cwl; // CAS write latency:
// 3'b000 5CK ( tCK >= 2.5ns)
// 3'b001 6CK (1.875ns <= tCK < 2.5ns)
// 3'b010 7CK (1.5ns <= tCK < 1.875ns)
// 3'b011 8CK (1.25ns <= tCK < 1.5ns)
// 3'b100 9CK (1.071ns <= tCK < 1.25ns)
// 3'b101 10CK (0.938ns <= tCK < 1.071ns)
// 3'b11x reserved
begin
ddr3_mr2 = {
3'h2,
{ADDRESS_NUMBER-11{1'b0}},
rtt_wr[1:0], // MR2.10_9
1'b0, // MR2.8
srt, // MR2.7
asr, // MR2.6
cwl[2:0], // MR2.5_3
3'b0}; // MR2.2_0
end
endfunction
function [ADDRESS_NUMBER+2:0] ddr3_mr3;
input mpr; // MPR mode: 0 - normal, 1 - dataflow from MPR
input [1:0] mpr_rf; // MPR read function:
// 2'b00: predefined pattern 0101...
// 2'b1x, 2'bx1 - reserved
begin
ddr3_mr3 = {
3'h3,
{ADDRESS_NUMBER-3{1'b0}},
mpr, // MR3.2
mpr_rf[1:0]}; // MR3.1_0
end
endfunction
reg [7:0] target_phase=0;
// initialize delays
// set dq /dqs tristate on/off patterns
task axi_set_tristate_patterns;
begin
$display("SET TRISTATE PATTERNS @ %t",$time);
axi_write_single(BASEADDR_PATTERNS_TRI, {16'h0, DQSTRI_LAST, DQSTRI_FIRST, DQTRI_LAST, DQTRI_FIRST});
end
endtask
task axi_set_dqs_dqm_patterns;
begin
$display("SET DQS+DQM PATTERNS @ %t",$time);
// set patterns for DM (always 0) and DQS - always the same (may try different for write lev.)
axi_write_single(BASEADDR_PATTERNS, 32'h0055);
end
endtask
// use to set all different delays from tables, use axi_set_same_delays for same delays
task axi_set_delays;
integer i;
begin
for (i=0;i<10;i=i+1) begin
axi_write_single(BASEADDRESS_LANE0_ODELAY + (i<<2), (DLY_LANE0_ODELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<9;i=i+1) begin
axi_write_single(BASEADDRESS_LANE0_IDELAY + (i<<2), (DLY_LANE0_IDELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<10;i=i+1) begin
axi_write_single(BASEADDRESS_LANE1_ODELAY + (i<<2), (DLY_LANE1_ODELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<9;i=i+1) begin
axi_write_single(BASEADDRESS_LANE1_IDELAY + (i<<2), (DLY_LANE1_IDELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<32;i=i+1) begin
axi_write_single(BASEADDRESS_CMDA + (i<<2), (DLY_CMDA >> (i<<3)) & 32'hff);
end
axi_write_single(BASEADDR_DLY_SET, 0); // set all dealys - remove after fixed axi_set_phase
axi_set_phase(DLY_PHASE);
axi_write_single(BASEADDR_DLY_SET, 0); // set all dealys
end
endtask
task axi_set_dqs_idelay_nominal;
begin
axi_write_single(BASEADDRESS_LANE0_IDELAY + (8<<2), (DLY_LANE0_IDELAY >> (8<<3)) & 32'hff);
axi_write_single(BASEADDRESS_LANE1_IDELAY + (8<<2), (DLY_LANE1_IDELAY >> (8<<3)) & 32'hff);
axi_write_single(BASEADDR_DLY_SET, 0); // set all dealys
end
endtask
task axi_set_dqs_idelay_wlv;
begin
axi_write_single(BASEADDRESS_LANE0_IDELAY + (8<<2), DLY_LANE0_DQS_WLV_IDELAY);
axi_write_single(BASEADDRESS_LANE1_IDELAY + (8<<2), DLY_LANE1_DQS_WLV_IDELAY);
axi_write_single(BASEADDR_DLY_SET, 0); // set all dealys
end
endtask
task axi_set_dly_single;
input [2:0] group; // 0 - lane 0 odelay, 1 - lane0 idelay, 2 - lane 1 odelay, 3 - lane1 idelay, 4 - cmda odelay
input [4:0] index; // 0..7 - DQ, 8 - DQS, 9 DQM (for byte lanes)
input [7:0] delay;
integer i;
integer dly;
begin
i = index;
dly=delay;
if (group == 0) begin
axi_write_single(BASEADDRESS_LANE0_ODELAY + (i<<2), dly & 32'hff);
end else if (group == 1) begin
axi_write_single(BASEADDRESS_LANE0_IDELAY + (i<<2), dly & 32'hff);
end else if (group == 2) begin
axi_write_single(BASEADDRESS_LANE1_ODELAY + (i<<2), dly & 32'hff);
end else if (group == 3) begin
axi_write_single(BASEADDRESS_LANE1_IDELAY + (i<<2), dly & 32'hff);
end else if (group == 4) begin
axi_write_single(BASEADDRESS_CMDA + (i<<2), dly & 32'hff);
end
axi_write_single(BASEADDR_DLY_SET, 0); // set all delays - remove after fixed axi_set_phase
end
endtask
task axi_set_dq_idelay;
input [7:0] delay;
integer i, dly;
begin
dly=delay;
$display("SET DQ IDELAY=0x%x @ %t",delay,$time);
for (i=0;i<8;i=i+1) begin
axi_write_single(BASEADDRESS_LANE0_IDELAY + (i<<2), dly & 32'hff);
end
for (i=0;i<8;i=i+1) begin
axi_write_single(BASEADDRESS_LANE1_IDELAY + (i<<2), dly & 32'hff);
end
axi_write_single(BASEADDR_DLY_SET, 0); // set all delays
end
endtask
task axi_set_dq_odelay;
input [7:0] delay;
integer i, dly;
begin
dly=delay;
$display("SET DQ ODELAY=0x%x @ %t",delay,$time);
for (i=0;i<8;i=i+1) begin
axi_write_single(BASEADDRESS_LANE0_ODELAY + (i<<2), dly & 32'hff);
end
for (i=0;i<8;i=i+1) begin
axi_write_single(BASEADDRESS_LANE1_ODELAY + (i<<2), dly & 32'hff);
end
axi_write_single(BASEADDR_DLY_SET, 0); // set all delays
end
endtask
task axi_set_dqs_idelay;
input [7:0] delay;
integer i, dly;
begin
dly=delay;
i=8;
$display("SET DQS IDELAY=0x%x @ %t",delay,$time);
axi_write_single(BASEADDRESS_LANE0_IDELAY + (i<<2), dly & 32'hff);
axi_write_single(BASEADDRESS_LANE1_IDELAY + (i<<2), dly & 32'hff);
axi_write_single(BASEADDR_DLY_SET, 0); // set all delays
end
endtask
task axi_set_dqs_odelay;
input [7:0] delay;
integer i, dly;
begin
dly=delay;
i=8;
$display("SET DQS ODELAY=0x%x @ %t",delay,$time);
axi_write_single(BASEADDRESS_LANE0_ODELAY + (i<<2), dly & 32'hff);
axi_write_single(BASEADDRESS_LANE1_ODELAY + (i<<2), dly & 32'hff);
axi_write_single(BASEADDR_DLY_SET, 0); // set all delays
end
endtask
task axi_set_dm_odelay;
input [7:0] delay;
integer i, dly;
begin
dly=delay;
i=9;
$display("SET DQM IDELAY=0x%x @ %t",delay,$time);
axi_write_single(BASEADDRESS_LANE0_ODELAY + (i<<2), dly & 32'hff);
axi_write_single(BASEADDRESS_LANE1_ODELAY + (i<<2), dly & 32'hff);
axi_write_single(BASEADDR_DLY_SET, 0); // set all delays
end
endtask
task axi_set_cmda_odelay;
input [7:0] delay;
integer i, dly;
begin
dly=delay;
$display("SET COMMAND and ADDRESS ODELAY=0x%x @ %t",delay,$time);
for (i=0;i<32;i=i+1) begin
axi_write_single(BASEADDRESS_CMDA + (i<<2), dly & 32'hff);
end
axi_write_single(BASEADDR_DLY_SET, 0); // set all delays
end
endtask
task axi_set_same_delays;
input [7:0] dq_idelay;
input [7:0] dq_odelay;
input [7:0] dqs_idelay;
input [7:0] dqs_odelay;
input [7:0] dm_odelay;
input [7:0] cmda_odelay;
begin
$display("SET DELAYS(0x%x,0x%x,0x%x,0x%x,0x%x,0x%x) @ %t",
dq_idelay,dq_odelay,dqs_idelay,dqs_odelay,dm_odelay,cmda_odelay,$time);
axi_set_dq_idelay(dq_idelay);
axi_set_dq_odelay(dq_odelay);
axi_set_dqs_idelay(dqs_idelay);
axi_set_dqs_odelay(dqs_odelay);
axi_set_dm_odelay(dm_odelay);
axi_set_cmda_odelay(cmda_odelay);
end
endtask
task axi_set_phase;
input [PHASE_WIDTH-1:0] phase;
begin
$display("SET CLOCK PHASE to 0x%x @ %t",phase,$time);
axi_write_single(BASEADDRESS_PHASE, {{(32-PHASE_WIDTH){1'b0}},phase});
axi_write_single(BASEADDR_DLY_SET, 0); // set all delays
target_phase <= phase;
end
endtask
task axi_set_wbuf_delay;
input [3:0] delay;
begin
$display("SET WBUF DELAY to 0x%x @ %t",delay,$time);
axi_write_single(BASEADDR_WBUF_DELAY, {28'h0, delay});
end
endtask
/*
assign rdata={21'b0,run_busy,locked,ps_rdy,ps_out[7:0]};
*/
task wait_phase_shifter_ready;
begin
read_status;
while (((registered_rdata & STATUS_PSHIFTER_RDY_MASK) == 0) || (((registered_rdata ^ {24'h0,target_phase}) & 'hff) != 0)) read_status;
end
endtask
task wait_sequencer_ready;
input integer num_skip; //skip this cycles before testing ready (latency from write to busy)
begin
repeat (num_skip) @(posedge CLK);
read_status;
repeat (8) @(posedge CLK); // latency from read command to registered_rdata. TODO: make it certain (read with the same ID)
while ((registered_rdata & STATUS_SEQ_BUSY_MASK) != 0) read_status;
end
endtask
task read_status;
begin
read_and_wait(BASEADDR_STATUS);
end
endtask
/*
task read_status;
begin
read_and_wait(BASEADDR_STATUS);
end
endtask
*/
// Low-level tasks
task axi_set_rd_lag;
input [3:0] lag;
begin
@(posedge CLK);
RD_LAG <= lag;
end
endtask
task axi_set_b_lag;
input [3:0] lag;
begin
@(posedge CLK);
B_LAG <= lag;
end
endtask
reg [11:0] GLOBAL_WRITE_ID=0;
reg [11:0] GLOBAL_READ_ID=0;
task read_and_wait;
input [31:0] address;
begin
axi_read_addr(
GLOBAL_READ_ID, // id
address & 32'hfffffffc, // addr
4'h0, // len - single
1 // burst type - increment
);
GLOBAL_READ_ID <= GLOBAL_READ_ID+1;
wait (!CLK && rvalid && rready);
wait (CLK);
registered_rdata <= rdata;
end
endtask
task axi_write_single; // address in bytes, not words
input [31:0] address;
input [31:0] data;
begin
`ifdef DEBUG_WR_SINGLE
$display("axi_write_single %h:%h @ %t",address,data,$time);
`endif
axi_write_addr_data(
GLOBAL_WRITE_ID, // id
// address << 2, // addr
address & 32'hfffffffc, // addr
data,
4'h0, // len - single
1, // burst type - increment
1'b1, // data_en
4'hf, // wstrb
1'b1 // last
);
GLOBAL_WRITE_ID <= GLOBAL_WRITE_ID+1;
#0.1; // without this delay axi_write_addr_data() used old value of GLOBAL_WRITE_ID
end
endtask
task axi_write_addr_data;
input [11:0] id;
input [31:0] addr;
input [31:0] data;
input [ 3:0] len;
input [ 1:0] burst;
input data_en; // if 0 - do not send data, only address
input [ 3:0] wstrb;
input last;
reg data_sent;
// wire data_sent_d;
// assign #(.1) data_sent_d= data_sent;
begin
wait (!CLK && AW_READY);
AWID_IN_r <= id;
AWADDR_IN_r <= addr;
AWLEN_IN_r <= len;
AWSIZE_IN_r <= 3'b010;
AWBURST_IN_r <= burst;
AW_SET_CMD_r <= 1'b1;
if (data_en && W_READY) begin
WID_IN_r <= id;
WDATA_IN_r <= data;
WSTRB_IN_r <= wstrb;
WLAST_IN_r <= last;
W_SET_CMD_r <= 1'b1;
data_sent <= 1'b1;
end else begin
data_sent <= 1'b0;
end
DEBUG1 <=1'b1;
wait (CLK);
DEBUG1 <=1'b0;
AWID_IN_r <= 'hz;
AWADDR_IN_r <= 'hz;
AWLEN_IN_r <= 'hz;
AWSIZE_IN_r <= 'hz;
AWBURST_IN_r <= 'hz;
AW_SET_CMD_r <= 1'b0;
DEBUG2 <=1'b1;
if (data_sent) begin
WID_IN_r <= 'hz;
WDATA_IN_r <= 'hz;
WSTRB_IN_r <= 'hz;
WLAST_IN_r <= 'hz;
W_SET_CMD_r <= 1'b0;
end
// Now sent data if it was not sent simultaneously with the address
if (data_en && !data_sent) begin
DEBUG3 <=1'b1;
wait (!CLK && W_READY);
DEBUG3 <=1'b0;
WID_IN_r <= id;
WDATA_IN_r <= data;
WSTRB_IN_r <= wstrb;
WLAST_IN_r <= last;
W_SET_CMD_r <= 1'b1;
wait (CLK);
DEBUG3 <=1'bx;
WID_IN_r <= 'hz;
WDATA_IN_r <= 'hz;
WSTRB_IN_r <= 'hz;
WLAST_IN_r <= 'hz;
W_SET_CMD_r <= 1'b0;
end
DEBUG2 <=1'b0;
#0.1;
data_sent <= 1'b0;
#0.1;
end
endtask
task axi_write_data;
input [11:0] id;
input [31:0] data;
input [ 3:0] wstrb;
input last;
begin
wait (!CLK && W_READY);
WID_IN_r <= id;
WDATA_IN_r <= data;
WSTRB_IN_r <= wstrb;
WLAST_IN_r <= last;
W_SET_CMD_r <= 1'b1;
wait (CLK);
WID_IN_r <= 12'hz;
WDATA_IN_r <= 'hz;
WSTRB_IN_r <= 4'hz;
WLAST_IN_r <= 1'bz;
W_SET_CMD_r <= 1'b0;
#0.1;
end
endtask
task axi_read_addr;
input [11:0] id;
input [31:0] addr;
input [ 3:0] len;
input [ 1:0] burst;
begin
wait (!CLK && AR_READY);
ARID_IN_r <= id;
ARADDR_IN_r <= addr;
ARLEN_IN_r <= len;
ARSIZE_IN_r <= 3'b010;
ARBURST_IN_r <= burst;
AR_SET_CMD_r <= 1'b1;
wait (CLK);
ARID_IN_r <= 12'hz;
ARADDR_IN_r <= 'hz;
ARLEN_IN_r <= 4'hz;
ARSIZE_IN_r <= 3'hz;
ARBURST_IN_r <= 2'hz;
AR_SET_CMD_r <= 1'b0;
LAST_ARID <= id;
end
endtask
task set_all_sequences;
begin
$display("SET MRS @ %t",$time);
set_mrs(1);
$display("SET REFRESH @ %t",$time);
set_refresh(
50, // input [ 9:0] t_rfc; // =50 for tCK=2.5ns
16); //input [ 7:0] t_refi; // 48/97 for normal, 8 - for simulation
$display("SET WRITE LEVELING @ %t",$time);
set_write_lev(16); // write leveling, 16 times (full buffer - 128)
$display("SET READ PATTERN @ %t",$time);
set_read_pattern(8); // 8x2*64 bits, 32x32 bits to read
$display("SET WRITE BLOCK @ %t",$time);
set_write_block(
3'h5, // bank
15'h1234, // row address
10'h100 // column address
);
$display("SET READ BLOCK @ %t",$time);
set_read_block(
3'h5, // bank
15'h1234, // row address
10'h100 // column address
);
end
endtask
/*
task set_same_delays;
input [7:0] dq_idelay;
input [7:0] dq_odelay;
input [7:0] dqs_idelay;
input [7:0] dqs_odelay;
input [7:0] dm_odelay;
input [7:0] cmda_odelay;
*/
task set_up;
begin
// set dq /dqs tristate on/off patterns
axi_set_tristate_patterns;
// set patterns for DM (always 0) and DQS - always the same (may try different for write lev.)
axi_set_dqs_dqm_patterns;
// prepare all sequences
set_all_sequences;
// prepare write buffer
write_block_buf; // fill block memory
// set all delays
//#axi_set_delays - from tables, per-pin
axi_set_same_delays(DLY_DQ_IDELAY,DLY_DQ_ODELAY,DLY_DQS_IDELAY,DLY_DQS_ODELAY,DLY_DM_ODELAY,DLY_CMDA_ODELAY);
// set clock phase relative to DDR clk
axi_set_phase(DLY_PHASE);
end
endtask
endmodule