Commit cbbd4ed1 authored by Andrey Filippov's avatar Andrey Filippov

split top level test fixture file into separate includes with tasks

parent 38d73a7b
......@@ -2,7 +2,7 @@
* File: x393_tasks01.vh
* Date:2015-02-07
* Author: andrey
* Description: Simulation tasks for the x393
* Description: Simulation tasks for the x393 (low level)
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* x393_tasks01.vh is free software; you can redistribute it and/or modify
......@@ -20,6 +20,14 @@
*******************************************************************************/
// Low-level tasks
// alternative way to check for empty read queue (without a separate counter)
task write_contol_register;
input [29:0] reg_addr;
input [31:0] data;
begin
axi_write_single_w(CONTROL_ADDR+reg_addr, data);
end
endtask
task wait_read_queue_empty;
begin
wait (~rvalid && rready && (rid==LAST_ARID)); // nothing left in read queue?
......
/*******************************************************************************
* File: x393_tasks_mcntrl_buffers.vh
* Date:2015-02-07
* Author: andrey
* Description: Simulation tasks for software reading/writing (with test patterns)
* of the block buffers.
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* x393_tasks_mcntrl_buffers.vh 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.
*
* x393_tasks_mcntrl_buffers.vh 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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
//MCONTR_BUF1_WR_ADDR
task write_block_buf_chn; // S uppressThisWarning VEditor : may be unused
input integer chn; // buffer channel
input [1:0] page;
input integer num_words; // number of words to write (will be rounded up to multiple of 16)
reg [29:0] start_addr;
begin
case (chn)
1: start_addr=MCONTR_BUF1_WR_ADDR + (page << 8);
3: start_addr=MCONTR_BUF3_WR_ADDR + (page << 8);
default: begin
$display("**** ERROR: Invalid channel for write buffer = %d @%t", chn, $time);
start_addr = MCONTR_BUF1_WR_ADDR+ (page << 8);
end
endcase
write_block_buf (start_addr, num_words);
end
endtask
task write_block_buf;
input [29:0] start_word_address;
input integer num_words; // number of words to write (will be rounded up to multiple of 16)
integer i, j;
begin
$display("**** write_block_buf @%t", $time);
for (i = 0; i < num_words; i = i + 16) begin
axi_write_addr_data(
i, // id
{start_word_address,2'b0}+( i << 2),
// (MCONTR_BUF1_WR_ADDR + (page <<8)+ i) << 2, // addr
i | (((i + 7) & 'hff) << 8) | (((i + 23) & 'hff) << 16) | (((i + 31) & 'hff) << 24),
4'hf, // len
1, // burst type - increment
1'b1, // data_en
4'hf, // wstrb
1'b0 // last
);
$display("+Write block data (addr:data): 0x%x:0x%08x @%t", i, i | (((i + 7) & 'hff) << 8) | (((i + 23) & 'hff) << 16) | (((i + 31) & 'hff) << 24), $time);
for (j = 1; j < 16; j = j + 1) begin
axi_write_data(
i, // id
(i + j) | ((((i + j) + 7) & 'hff) << 8) | ((((i + j) + 23) & 'hff) << 16) | ((((i + j) + 31) & 'hff) << 24),
4'hf, // wstrb
(1 == 15) ? 1 : 0 // last
);
$display(" Write block data (addr:data): 0x%08x:0x%x @%t", (i + j),
(i + j) | ((((i + j) + 7) & 'hff) << 8) | ((((i + j) + 23) & 'hff) << 16) | ((((i + j) + 31) & 'hff) << 24), $time);
end
end
end
endtask
// read memory
task read_block_buf_chn; // S uppressThisWarning VEditor : may be unused
input integer chn; // buffer channel
input [1:0] page;
input integer num_read; // number of words to read (will be rounded up to multiple of 16)
input wait_done;
reg [29:0] start_addr;
begin
case (chn)
0: start_addr=MCONTR_BUF0_RD_ADDR + (page << 8);
2: start_addr=MCONTR_BUF2_RD_ADDR + (page << 8);
4: start_addr=MCONTR_BUF4_RD_ADDR + (page << 8);
default: begin
$display("**** ERROR: Invalid channel for read buffer = %d @%t", chn, $time);
start_addr = 30'b0+ (page << 8);
end
endcase
read_block_buf (start_addr, num_read, wait_done);
end
endtask
task read_block_buf;
input [29:0] start_word_address;
input integer num_read; // number of words to read (will be rounded up to multiple of 16)
input wait_done;
integer i; //,j;
begin
wait (~rstb);
SIMUL_AXI_FULL<=1'b0;
$display("**** read_block_buf @%t", $time);
axi_set_rd_lag(0);
for (i = 0; i < num_read; i = i + 16) begin
wait(arready);
// $display ("read_block_buf (0x%x) @%t",i,$time);
axi_read_addr(
i, // id
{start_word_address,2'b0}+( i << 2), // addr
4'hf, // len
1 // burst type - increment
);
end
if (wait_done) begin
// wait (AXI_RD_EMPTY);
wait_read_queue_empty;
end
end
endtask
/*******************************************************************************
* File: x393_tasks_mcntrl_en_dis_priority.vh
* Date:2015-02-07
* Author: andrey
* Description: Simulation tasks for software reading/writing (with test patterns)
* of the block buffers.
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* x393_tasks_mcntrl_en_dis_priority.vh 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.
*
* x393_tasks_mcntrl_en_dis_priority.vh 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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
task enable_cmda;
input en;
begin
write_contol_register(MCONTR_PHY_0BIT_ADDR + MCONTR_PHY_0BIT_CMDA_EN + en, 0);
end
endtask
task enable_cke;
input en;
begin
write_contol_register(MCONTR_PHY_0BIT_ADDR + MCONTR_PHY_0BIT_CKE_EN + en, 0);
end
endtask
task activate_sdrst;
input en;
begin
write_contol_register(MCONTR_PHY_0BIT_ADDR + MCONTR_PHY_0BIT_SDRST_ACT + en, 0);
end
endtask
task enable_refresh;
input en;
begin
write_contol_register(MCONTR_TOP_0BIT_ADDR + MCONTR_TOP_0BIT_REFRESH_EN + en, 0);
end
endtask
task enable_memcntrl;
input en;
begin
write_contol_register(MCONTR_TOP_0BIT_ADDR + MCONTR_TOP_0BIT_MCONTR_EN + en, 0);
end
endtask
task enable_memcntrl_channels;
input [15:0] chnen; // bit-per-channel, 1 - enable;
begin
write_contol_register(MCONTR_TOP_16BIT_ADDR + MCONTR_TOP_16BIT_CHN_EN, {16'b0,chnen});
end
endtask
task configure_channel_priority;
input [ 3:0] chn;
input [15:0] priority; // (higher is more important)
begin
write_contol_register(MCONTR_ARBIT_ADDR + chn, {16'b0,priority});
end
endtask
/*******************************************************************************
* File: x393_tasks_mcntrl_timing.vh
* Date:2015-02-07
* Author: andrey
* Description: Simulation tasks for programming I/O delays and other timing
* parameters in the memory controller
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* x393_tasks_mcntrl_timing.vh 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.
*
* x393_tasks_mcntrl_timing.vh 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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
task axi_set_same_delays; //SuppressThisWarning VEditor : may be unused
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_dqs_odelay_nominal; //SuppressThisWarning VEditor : may be unused
begin
// axi_set_dqs_idelay(
write_contol_register(LD_DLY_LANE0_ODELAY + 8, (DLY_LANE0_ODELAY >> (8<<3)) & 32'hff);
write_contol_register(LD_DLY_LANE1_ODELAY + 8, (DLY_LANE1_ODELAY >> (8<<3)) & 32'hff);
write_contol_register(DLY_SET,0);
end
endtask
task axi_set_dqs_idelay_nominal; //SuppressThisWarning VEditor : may be unused
begin
// axi_set_dqs_idelay(
write_contol_register(LD_DLY_LANE0_IDELAY + 8, (DLY_LANE0_IDELAY >> (8<<3)) & 32'hff);
write_contol_register(LD_DLY_LANE1_IDELAY + 8, (DLY_LANE1_IDELAY >> (8<<3)) & 32'hff);
write_contol_register(DLY_SET,0);
end
endtask
task axi_set_dqs_idelay_wlv; //SuppressThisWarning VEditor : may be unused
begin
write_contol_register(LD_DLY_LANE0_IDELAY + 8, DLY_LANE0_DQS_WLV_IDELAY);
write_contol_register(LD_DLY_LANE1_IDELAY + 8, DLY_LANE1_DQS_WLV_IDELAY);
write_contol_register(DLY_SET,0);
end
endtask
task axi_set_delays; // set all individual delays
integer i;
begin
for (i=0;i<10;i=i+1) begin
write_contol_register(LD_DLY_LANE0_ODELAY + i, (DLY_LANE0_ODELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<9;i=i+1) begin
write_contol_register(LD_DLY_LANE0_IDELAY + i, (DLY_LANE0_IDELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<10;i=i+1) begin
write_contol_register(LD_DLY_LANE1_ODELAY + i, (DLY_LANE1_ODELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<9;i=i+1) begin
write_contol_register(LD_DLY_LANE1_IDELAY + i, (DLY_LANE1_IDELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<32;i=i+1) begin
write_contol_register(LD_DLY_CMDA + i, (DLY_CMDA >> (i<<3)) & 32'hff);
end
// write_contol_register(DLY_SET,0);
axi_set_phase(DLY_PHASE); // also sets all delays
end
endtask
task axi_set_dq_idelay; // sets same delay to all dq idelay
input [7:0] delay;
begin
$display("SET DQ IDELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_IDELAY, 8, delay);
axi_set_multiple_delays(LD_DLY_LANE1_IDELAY, 8, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_dq_odelay;
input [7:0] delay;
begin
$display("SET DQ ODELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_ODELAY, 8, delay);
axi_set_multiple_delays(LD_DLY_LANE1_ODELAY, 8, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_dqs_idelay;
input [7:0] delay;
begin
$display("SET DQS IDELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_IDELAY + 8, 1, delay);
axi_set_multiple_delays(LD_DLY_LANE1_IDELAY + 8, 1, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_dqs_odelay;
input [7:0] delay;
begin
$display("SET DQS ODELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_ODELAY + 8, 1, delay);
axi_set_multiple_delays(LD_DLY_LANE1_ODELAY + 8, 1, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_dm_odelay;
input [7:0] delay;
begin
$display("SET DQM IDELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_ODELAY + 9, 1, delay);
axi_set_multiple_delays(LD_DLY_LANE1_ODELAY + 9, 1, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_cmda_odelay;
input [7:0] delay;
begin
$display("SET COMMAND and ADDRESS ODELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_CMDA, 32, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_multiple_delays;
input [29:0] reg_addr;
input integer number;
input [7:0] delay;
integer i;
begin
for (i=0;i<number;i=i+1) begin
write_contol_register(reg_addr + i, {24'b0,delay}); // control regiter address
end
end
endtask
task axi_set_phase;
input [PHASE_WIDTH-1:0] phase;
begin
$display("SET CLOCK PHASE to 0x%x @ %t",phase,$time);
write_contol_register(LD_DLY_PHASE, {{(32-PHASE_WIDTH){1'b0}},phase}); // control regiter address
write_contol_register(DLY_SET,0);
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);
write_contol_register(MCONTR_PHY_16BIT_ADDR+MCONTR_PHY_16BIT_WBUF_DELAY, {28'h0, delay});
end
endtask
// set dq /dqs tristate on/off patterns
task axi_set_tristate_patterns;
begin
$display("SET TRISTATE PATTERNS @ %t",$time);
write_contol_register(MCONTR_PHY_16BIT_ADDR +MCONTR_PHY_16BIT_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.)
write_contol_register(MCONTR_PHY_16BIT_ADDR + MCONTR_PHY_16BIT_PATTERNS,
32'h0055);
end
endtask
/*******************************************************************************
* File: x393_tasks_pio_sequences.vh
* Date:2015-02-07
* Author: andrey
* Description: Simulation tasks for programming memory transaction
* sequences (controlles by PS)
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* x393_tasks_pio_sequences.vh 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.
*
* x393_tasks_pio_sequences.vh 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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
task enable_reset_ps_pio; // control reset and enable of the PS PIO channel;
input en;
input rst;
begin
write_contol_register(MCNTRL_PS_ADDR + MCNTRL_PS_EN_RST, {30'b0,en,~rst});
end
endtask
task set_read_block;
input [ 2:0] ba;
input [14:0] ra;
input [ 9:0] ca;
reg [29:0] cmd_addr;
reg [31:0] data;
integer i;
begin
cmd_addr <= MCONTR_CMD_WR_ADDR + READ_BLOCK_OFFSET;
// activate
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( ra[14:0], ba[2:0], 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// see if pause is needed . See when buffer read should be started - maybe before WR command
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// first read
// read
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( {5'b0,ca[9:0]}, ba[2:0], 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
//repeat remaining reads
for (i=1;i<64;i=i+1) begin
// read
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd({5'b0,ca[9:0]}+(i<<3),ba[2:0],2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
// nop - all 3 below are the same? - just repeat?
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// tRTP = 4*tCK is already satisfied, no skip here
// precharge, end of a page (B_RST)
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( ra[14:0], ba[2:0], 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Turn off DCI, set DONE
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
endtask
task set_write_block;
input[2:0]ba;
input[14:0]ra;
input[9:0]ca;
reg[29:0] cmd_addr;
reg[31:0] data;
integer i;
begin
cmd_addr <= MCONTR_CMD_WR_ADDR + WRITE_BLOCK_OFFSET;
// activate
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( ra[14:0], ba[2:0], 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// see if pause is needed . See when buffer read should be started - maybe before WR command
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); // tRCD - 2 read bufs
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// first write, 3 rd_buf
// write
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( {5'b0,ca[9:0]}, ba[2:0], 3, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0); // B_RD moved 1 cycle earlier
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop 4-th rd_buf
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
// data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 1, 1, 1, 0, 1, 0, 1, 0);
data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 0, 1, 1, 0, 0, 0, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
//repeat remaining writes
for (i = 1; i < 63; i = i + 1) begin
// write
// add bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( {5'b0,ca[9:0]}+(i<<3),ba[2:0],3, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
// One last write pair w/o buffer
// add bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( {5'b0,ca[9:0]}+(63<<3),ba[2:0],3,1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 0, 1, 1, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 0, 1, 1, 1, 0, 0, 0, 1); // removed B_RD 1 cycle earlier
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 0, 1, 1, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// ODT off, it has latency
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, ba[2:0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// precharge, ODT off
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( ra[14:0], ba[2:0], 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, ba[2:0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Finalize, set DONE
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
endtask
// Set MR3, read nrep*8 words, save to buffer (port0). No ACTIVATE/PRECHARGE are needed/allowed
task set_read_pattern;
input integer nrep;
// input [ 2:0] ba;
// input [14:0] ra;
// input [ 9:0] ca;
reg[29:0] cmd_addr;
reg[31:0] data;
reg[17:0] mr3_norm;
reg[17:0] mr3_patt;
integer i;
begin
cmd_addr <= MCONTR_CMD_WR_ADDR + READ_PATTERN_OFFSET;
mr3_norm <= 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...
mr3_patt <= ddr3_mr3(
1'h1, // mpr; // MPR mode: 0 - normal, 1 - dataflow from MPR
2'h0); // [1:0] mpr_rf; // MPR read function: 2'b00: predefined pattern 0101...
@(posedge CLK);
// Set pattern mode
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr3_patt[14:0], mr3_patt[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // tMOD
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// first read
// read
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( 0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop (combine with previous?)
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
//repeat remaining reads
for (i = 1; i < nrep; i = i + 1) begin
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( 0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
// nop - all 3 below are the same? - just repeat?
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop, no write buffer - next page
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Turn off read pattern mode
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr3_norm[14:0], mr3_norm[17:15], 7, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// tMOD (keep DCI enabled)
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Turn off DCI
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Finalize (set DONE)
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
endtask
task set_write_lev;
input[CMD_PAUSE_BITS-1:0]nrep;
reg[17:0] mr1_norm;
reg[17:0] mr1_wlev;
reg[29: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 <= MCONTR_CMD_WR_ADDR + WRITELEV_OFFSET;
// Enter write leveling mode
@(posedge CLK)
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr1_wlev[14:0], mr1_wlev[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // tWLDQSEN=25tCK
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// enable DQS output, keep it low (15 more tCK for the total of 40 tCK
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip(dqs_low_rpt, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Toggle DQS as needed for write leveling, write to buffer
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip(nrep_minus_1,0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// continue toggling (5 times), but disable writing to buffer (used same wbuf latency as for read)
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 4, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Keep DCI (but not ODT) active ODT should be off befor MRS
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// exit write leveling mode, ODT off, DCI off
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr1_norm[14:0], mr1_norm[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // tMOD
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Finalize. See if DONE can be combined with B_RST, if not - insert earlier
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); // can DONE be combined with B_RST?
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
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[29:0] cmd_addr;
reg[31:0] data;
begin
cmd_addr <= MCONTR_CMD_WR_ADDR + REFRESH_OFFSET;
@(posedge CLK)
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// =50 tREFI=260 ns before next ACTIVATE or REFRESH, @2.5ns clock, @5ns cycle
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( t_rfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Ready for normal operation
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// write_contol_register(DLY_SET,0);
write_contol_register(MCONTR_TOP_16BIT_ADDR + MCONTR_TOP_16BIT_REFRESH_ADDRESS, REFRESH_OFFSET);
write_contol_register(MCONTR_TOP_16BIT_ADDR + MCONTR_TOP_16BIT_REFRESH_PERIOD, {24'h0,t_refi});
// enable refresh - should it be done here?
// write_contol_register(MCONTR_PHY_0BIT_ADDR + MCONTR_TOP_0BIT_REFRESH_EN + 1, 0);
end
endtask
task set_mrs; // will also calibrate ZQ
input reset_dll;
reg[17:0] mr0;
reg[17:0] mr1;
reg[17:0] mr2;
reg[17:0] mr3;
reg[29: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 <= MCONTR_CMD_WR_ADDR + INITIALIZE_OFFSET;
@(posedge CLK)
$display("mr0=0x%x", mr0);
$display("mr1=0x%x", mr1);
$display("mr2=0x%x", mr2);
$display("mr3=0x%x", mr3);
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr2[14:0], mr2[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr3[14:0], mr3[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr1[14:0], mr1[17:15], 7, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); // SEL==1 - just testing?
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr0[14:0], mr0[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// encode ZQCL:
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(15'h400, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// 512 clock cycles after ZQCL
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// sequence done bit, skip length is ignored
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
endtask
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
/*******************************************************************************
* File: x393_tasks_ps_pio.vh
* Date:2015-02-07
* Author: andrey
* Description: Simulation tasks for mcntrl_ps_pio module (launching software
* - programmed memory transaction sequences)
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* x393_tasks_ps_pio.vh 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.
*
* x393_tasks_ps_pio.vh 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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
task schedule_ps_pio; // shedule software-control memory operation (may need to check FIFO status first)
input [9:0] seq_addr; // sequence start address
input [1:0] page; // buffer page number
input urgent; // high priority request (only for competion wityh other channels, wiil not pass in this FIFO)
input chn; // channel buffer to use: 0 - memory read, 1 - memory write
input wait_complete; // Do not request a newe transaction from the scheduler until previous memory transaction is finished
begin
// wait_ps_pio_ready(DEFAULT_STATUS_MODE); // wait FIFO not half full
write_contol_register(MCNTRL_PS_ADDR + MCNTRL_PS_CMD, {17'b0,wait_complete,chn,urgent,page,seq_addr});
end
endtask
task wait_ps_pio_ready; // wait PS PIO module can accept comamnds (fifo half empty)
input [1:0] mode;
begin
wait_status_condition (
MCNTRL_PS_STATUS_REG_ADDR,
MCNTRL_PS_ADDR+MCNTRL_PS_STATUS_CNTRL,
mode,
0,
2 << STATUS_2LSB_SHFT,
0);
end
endtask
task wait_ps_pio_done; // wait PS PIO module has no pending/running memory transaction
input [1:0] mode;
begin
wait_status_condition (
MCNTRL_PS_STATUS_REG_ADDR,
MCNTRL_PS_ADDR+MCNTRL_PS_STATUS_CNTRL,
mode,
0,
3 << STATUS_2LSB_SHFT,
0);
end
endtask
/*******************************************************************************
* File: x393_status.vh
* Date:2015-02-07
* Author: andrey
* Description: Simulation tasks for the x393 related to status
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* x393_status.vh 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.
*
* x393_status.vh 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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
task wait_status_condition;
input [STATUS_DEPTH-1:0] status_address;
input [29:0] status_control_address;
input [1:0] status_mode;
input [25:0] pattern; // bits as in read registers
input [25:0] mask; // which bits to compare
input invert_match; // 0 - wait until match to pattern (all bits), 1 - wait until no match (any of bits differ)
reg match;
reg [5:0] seq_num;
begin
WAITING_STATUS = 1;
for (match=0; !match; match = invert_match ^ (((registered_rdata ^ {6'h0,pattern}) & {6'h0,mask})==0)) begin
read_and_wait_status(status_address);
write_contol_register(status_control_address, {24'b0,status_mode,registered_rdata[STATUS_SEQ_SHFT+:6] ^ 6'h20});
seq_num <= registered_rdata[STATUS_SEQ_SHFT+:6] ^ 6'h20;
read_and_wait_status(status_address);
while (((registered_rdata[STATUS_SEQ_SHFT+:6] ^ seq_num) & 6'h30)!=0) begin // match just 2 MSBs
read_and_wait_status(status_address);
end
end
WAITING_STATUS = 0;
end
endtask
task wait_phase_shifter_ready;
begin
WAITING_STATUS = 1;
read_and_wait_status(MCONTR_PHY_STATUS_REG_ADDR);
while (((registered_rdata & STATUS_PSHIFTER_RDY_MASK) == 0) || (((registered_rdata ^ {24'h0,target_phase}) & 'hff) != 0)) begin
read_and_wait_status(MCONTR_PHY_STATUS_REG_ADDR); // exits after negedge CLK
end
WAITING_STATUS = 0;
end
endtask
task read_all_status;
begin
read_and_wait_status (MCONTR_PHY_STATUS_REG_ADDR);
read_and_wait_status (MCONTR_TOP_STATUS_REG_ADDR);
read_and_wait_status (MCNTRL_PS_STATUS_REG_ADDR);
read_and_wait_status (MCNTRL_SCANLINE_STATUS_REG_CHN2_ADDR);
read_and_wait_status (MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR);
read_and_wait_status (MCNTRL_TILED_STATUS_REG_CHN4_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN2_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN3_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN4_ADDR);
end
endtask
task read_and_wait_status;
input [STATUS_DEPTH-1:0] address;
begin
read_and_wait_w(STATUS_ADDR + address ); // Will set: registered_rdata <= rdata;
end
endtask
task program_status_all;
input [1:0] mode;
input [5:0] seq_num;
begin
program_status (MCONTR_PHY_16BIT_ADDR, MCONTR_PHY_STATUS_CNTRL, mode,seq_num); //MCONTR_PHY_STATUS_REG_ADDR= 'h0,
program_status (MCONTR_TOP_16BIT_ADDR, MCONTR_TOP_16BIT_STATUS_CNTRL, mode,seq_num); //MCONTR_TOP_STATUS_REG_ADDR= 'h1,
program_status (MCNTRL_PS_ADDR, MCNTRL_PS_STATUS_CNTRL, mode,seq_num); //MCNTRL_PS_STATUS_REG_ADDR= 'h2,
program_status (MCNTRL_SCANLINE_CHN2_ADDR, MCNTRL_SCANLINE_STATUS_CNTRL, mode,seq_num); //MCNTRL_SCANLINE_STATUS_REG_CHN2_ADDR='h4,
program_status (MCNTRL_SCANLINE_CHN3_ADDR, MCNTRL_SCANLINE_STATUS_CNTRL, mode,seq_num); //MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR='h5,
program_status (MCNTRL_TILED_CHN4_ADDR, MCNTRL_TILED_STATUS_CNTRL, mode,seq_num); //MCNTRL_TILED_STATUS_REG_CHN4_ADDR= 'h6,
program_status (MCNTRL_TEST01_ADDR, MCNTRL_TEST01_CHN2_STATUS_CNTRL,mode,seq_num); //MCNTRL_TEST01_STATUS_REG_CHN2_ADDR= 'h3c,
program_status (MCNTRL_TEST01_ADDR, MCNTRL_TEST01_CHN3_STATUS_CNTRL,mode,seq_num); //MCNTRL_TEST01_STATUS_REG_CHN3_ADDR= 'h3d,
program_status (MCNTRL_TEST01_ADDR, MCNTRL_TEST01_CHN4_STATUS_CNTRL,mode,seq_num); //MCNTRL_TEST01_STATUS_REG_CHN4_ADDR= 'h3e,
end
endtask
task program_status;
input [29:0] base_addr;
input [7:0] reg_addr;
input [1:0] mode;
// mode bits:
// 0 disable status generation,
// 1 single status request,
// 2 - auto status, keep specified seq number,
// 3 - auto, inc sequence number
input [5:0] seq_number;
begin
// axi_write_single_w(CONTROL_ADDR+base_addr+reg_addr, {24'b0,mode,seq_number});
write_contol_register(base_addr + reg_addr, {24'b0,mode,seq_number});
end
endtask
[*]
[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI
[*] Fri Feb 13 18:38:10 2015
[*] Fri Feb 13 20:24:18 2015
[*]
[dumpfile] "/home/andrey/git/x393/simulation/x393_testbench01-20150213111425884.lxt"
[dumpfile_mtime] "Fri Feb 13 18:19:38 2015"
[dumpfile_size] 232662775
[dumpfile] "/home/andrey/git/x393/simulation/x393_testbench01-20150213113832125.lxt"
[dumpfile_mtime] "Fri Feb 13 18:43:22 2015"
[dumpfile_size] 233070602
[savefile] "/home/andrey/git/x393/x393_testbench01.sav"
[timestart] 138611000
[timestart] 97060000
[size] 1823 1173
[pos] 1922 0
*-20.698502 143181875 141406879 141780000 142422500 142495000 143137500 143495000 144137500 140756879 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
*-23.698502 146225000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] x393_testbench01.
[treeopen] x393_testbench01.x393_i.
[treeopen] x393_testbench01.x393_i.mcntrl393_i.
......@@ -1455,6 +1455,8 @@ x393_testbench01.x393_i.mcntrl393_i.mcntrl_ps_pio_i.chn1_buf_i.rpage_in[1:0]
x393_testbench01.x393_i.mcntrl393_i.mcntrl_ps_pio_i.chn1_buf_i.rpage_set[0]
@1000200
-PS_PIO_CHN1
@c00201
-other_modules
@28
x393_testbench01.x393_i.mcntrl393_i.memctrl16_i.ext_buf_rrun[0]
x393_testbench01.x393_i.mcntrl393_i.memctrl16_i.ext_buf_wrun[0]
......@@ -1490,6 +1492,8 @@ x393_testbench01.x393_i.mcntrl393_i.memctrl16_i.seq_done1[0]
x393_testbench01.x393_i.mcntrl393_i.memctrl16_i.seq_done0[0]
@1001200
-group_end
@1401201
-other_modules
@200
-
@28
......
......@@ -396,7 +396,7 @@ assign bvalid= x393_i.ps7_i.MAXIGP0BVALID;
assign x393_i.ps7_i.MAXIGP0BREADY= bready;
assign bid= x393_i.ps7_i.MAXIGP0BID;
assign bresp= x393_i.ps7_i.MAXIGP0BRESP;
//TODO: See how to show problems in include files opened in the editor (test all top *.v files that have it)
// Top module under test
x393 #(
.MCONTR_WR_MASK (MCONTR_WR_MASK),
......@@ -958,1047 +958,13 @@ task set_all_sequences;
end
endtask
task enable_cmda;
input en;
begin
write_contol_register(MCONTR_PHY_0BIT_ADDR + MCONTR_PHY_0BIT_CMDA_EN + en, 0);
end
endtask
task enable_cke;
input en;
begin
write_contol_register(MCONTR_PHY_0BIT_ADDR + MCONTR_PHY_0BIT_CKE_EN + en, 0);
end
endtask
task activate_sdrst;
input en;
begin
write_contol_register(MCONTR_PHY_0BIT_ADDR + MCONTR_PHY_0BIT_SDRST_ACT + en, 0);
end
endtask
task enable_refresh;
input en;
begin
write_contol_register(MCONTR_TOP_0BIT_ADDR + MCONTR_TOP_0BIT_REFRESH_EN + en, 0);
end
endtask
task enable_memcntrl;
input en;
begin
write_contol_register(MCONTR_TOP_0BIT_ADDR + MCONTR_TOP_0BIT_MCONTR_EN + en, 0);
end
endtask
task enable_memcntrl_channels;
input [15:0] chnen; // bit-per-channel, 1 - enable;
begin
write_contol_register(MCONTR_TOP_16BIT_ADDR + MCONTR_TOP_16BIT_CHN_EN, {16'b0,chnen});
end
endtask
task configure_channel_priority;
input [ 3:0] chn;
input [15:0] priority; // (higher is more important)
begin
write_contol_register(MCONTR_ARBIT_ADDR + chn, {16'b0,priority});
end
endtask
task enable_reset_ps_pio; // control reset and enable of the PS PIO channel;
input en;
input rst;
begin
write_contol_register(MCNTRL_PS_ADDR + MCNTRL_PS_EN_RST, {30'b0,en,~rst});
end
endtask
task schedule_ps_pio; // shedule software-control memory operation (may need to check FIFO status first)
input [9:0] seq_addr; // sequence start address
input [1:0] page; // buffer page number
input urgent; // high priority request (only for competion wityh other channels, wiil not pass in this FIFO)
input chn; // channel buffer to use: 0 - memory read, 1 - memory write
input wait_complete; // Do not request a newe transaction from the scheduler until previous memory transaction is finished
begin
// wait_ps_pio_ready(DEFAULT_STATUS_MODE); // wait FIFO not half full
write_contol_register(MCNTRL_PS_ADDR + MCNTRL_PS_CMD, {17'b0,wait_complete,chn,urgent,page,seq_addr});
end
endtask
//MCONTR_BUF1_WR_ADDR
task write_block_buf_chn; // S uppressThisWarning VEditor : may be unused
input integer chn; // buffer channel
input [1:0] page;
input integer num_words; // number of words to write (will be rounded up to multiple of 16)
reg [29:0] start_addr;
begin
case (chn)
1: start_addr=MCONTR_BUF1_WR_ADDR + (page << 8);
3: start_addr=MCONTR_BUF3_WR_ADDR + (page << 8);
default: begin
$display("**** ERROR: Invalid channel for write buffer = %d @%t", chn, $time);
start_addr = MCONTR_BUF1_WR_ADDR+ (page << 8);
end
endcase
write_block_buf (start_addr, num_words);
end
endtask
task write_block_buf;
input [29:0] start_word_address;
input integer num_words; // number of words to write (will be rounded up to multiple of 16)
integer i, j;
begin
$display("**** write_block_buf @%t", $time);
for (i = 0; i < num_words; i = i + 16) begin
axi_write_addr_data(
i, // id
{start_word_address,2'b0}+( i << 2),
// (MCONTR_BUF1_WR_ADDR + (page <<8)+ i) << 2, // addr
i | (((i + 7) & 'hff) << 8) | (((i + 23) & 'hff) << 16) | (((i + 31) & 'hff) << 24),
4'hf, // len
1, // burst type - increment
1'b1, // data_en
4'hf, // wstrb
1'b0 // last
);
$display("+Write block data (addr:data): 0x%x:0x%08x @%t", i, i | (((i + 7) & 'hff) << 8) | (((i + 23) & 'hff) << 16) | (((i + 31) & 'hff) << 24), $time);
for (j = 1; j < 16; j = j + 1) begin
axi_write_data(
i, // id
(i + j) | ((((i + j) + 7) & 'hff) << 8) | ((((i + j) + 23) & 'hff) << 16) | ((((i + j) + 31) & 'hff) << 24),
4'hf, // wstrb
(1 == 15) ? 1 : 0 // last
);
$display(" Write block data (addr:data): 0x%08x:0x%x @%t", (i + j),
(i + j) | ((((i + j) + 7) & 'hff) << 8) | ((((i + j) + 23) & 'hff) << 16) | ((((i + j) + 31) & 'hff) << 24), $time);
end
end
end
endtask
// read memory
task read_block_buf_chn; // S uppressThisWarning VEditor : may be unused
input integer chn; // buffer channel
input [1:0] page;
input integer num_read; // number of words to read (will be rounded up to multiple of 16)
input wait_done;
reg [29:0] start_addr;
begin
case (chn)
0: start_addr=MCONTR_BUF0_RD_ADDR + (page << 8);
2: start_addr=MCONTR_BUF2_RD_ADDR + (page << 8);
4: start_addr=MCONTR_BUF4_RD_ADDR + (page << 8);
default: begin
$display("**** ERROR: Invalid channel for read buffer = %d @%t", chn, $time);
start_addr = 30'b0+ (page << 8);
end
endcase
read_block_buf (start_addr, num_read, wait_done);
end
endtask
task read_block_buf;
input [29:0] start_word_address;
input integer num_read; // number of words to read (will be rounded up to multiple of 16)
input wait_done;
integer i; //,j;
begin
wait (~rstb);
SIMUL_AXI_FULL<=1'b0;
$display("**** read_block_buf @%t", $time);
axi_set_rd_lag(0);
for (i = 0; i < num_read; i = i + 16) begin
wait(arready);
// $display ("read_block_buf (0x%x) @%t",i,$time);
axi_read_addr(
i, // id
{start_word_address,2'b0}+( i << 2), // addr
4'hf, // len
1 // burst type - increment
);
end
if (wait_done) begin
// wait (AXI_RD_EMPTY);
wait_read_queue_empty;
end
end
endtask
task set_read_block;
input [ 2:0] ba;
input [14:0] ra;
input [ 9:0] ca;
reg [29:0] cmd_addr;
reg [31:0] data;
integer i;
begin
cmd_addr <= MCONTR_CMD_WR_ADDR + READ_BLOCK_OFFSET;
// activate
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( ra[14:0], ba[2:0], 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// see if pause is needed . See when buffer read should be started - maybe before WR command
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// first read
// read
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( {5'b0,ca[9:0]}, ba[2:0], 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
//repeat remaining reads
for (i=1;i<64;i=i+1) begin
// read
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd({5'b0,ca[9:0]}+(i<<3),ba[2:0],2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
// nop - all 3 below are the same? - just repeat?
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// tRTP = 4*tCK is already satisfied, no skip here
// precharge, end of a page (B_RST)
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( ra[14:0], ba[2:0], 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Turn off DCI, set DONE
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
endtask
task set_write_block;
input[2:0]ba;
input[14:0]ra;
input[9:0]ca;
reg[29:0] cmd_addr;
reg[31:0] data;
integer i;
begin
cmd_addr <= MCONTR_CMD_WR_ADDR + WRITE_BLOCK_OFFSET;
// activate
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( ra[14:0], ba[2:0], 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// see if pause is needed . See when buffer read should be started - maybe before WR command
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); // tRCD - 2 read bufs
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// first write, 3 rd_buf
// write
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( {5'b0,ca[9:0]}, ba[2:0], 3, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0); // B_RD moved 1 cycle earlier
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop 4-th rd_buf
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
// data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 1, 1, 1, 0, 1, 0, 1, 0);
data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 0, 1, 1, 0, 0, 0, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
//repeat remaining writes
for (i = 1; i < 63; i = i + 1) begin
// write
// add bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( {5'b0,ca[9:0]}+(i<<3),ba[2:0],3, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
// One last write pair w/o buffer
// add bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( {5'b0,ca[9:0]}+(63<<3),ba[2:0],3,1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 0, 1, 1, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 0, 1, 1, 1, 0, 0, 0, 1); // removed B_RD 1 cycle earlier
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, ba[2:0], 1, 0, 0, 1, 1, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// ODT off, it has latency
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, ba[2:0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// precharge, ODT off
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( ra[14:0], ba[2:0], 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, ba[2:0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Finalize, set DONE
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
endtask
// Set MR3, read nrep*8 words, save to buffer (port0). No ACTIVATE/PRECHARGE are needed/allowed
task set_read_pattern;
input integer nrep;
// input [ 2:0] ba;
// input [14:0] ra;
// input [ 9:0] ca;
reg[29:0] cmd_addr;
reg[31:0] data;
reg[17:0] mr3_norm;
reg[17:0] mr3_patt;
integer i;
begin
cmd_addr <= MCONTR_CMD_WR_ADDR + READ_PATTERN_OFFSET;
mr3_norm <= 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...
mr3_patt <= ddr3_mr3(
1'h1, // mpr; // MPR mode: 0 - normal, 1 - dataflow from MPR
2'h0); // [1:0] mpr_rf; // MPR read function: 2'b00: predefined pattern 0101...
@(posedge CLK);
// Set pattern mode
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr3_patt[14:0], mr3_patt[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // tMOD
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// first read
// read
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( 0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop (combine with previous?)
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
//repeat remaining reads
for (i = 1; i < nrep; i = i + 1) begin
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( 0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
// nop - all 3 below are the same? - just repeat?
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// nop, no write buffer - next page
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Turn off read pattern mode
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr3_norm[14:0], mr3_norm[17:15], 7, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// tMOD (keep DCI enabled)
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Turn off DCI
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Finalize (set DONE)
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
endtask
task set_write_lev;
input[CMD_PAUSE_BITS-1:0]nrep;
reg[17:0] mr1_norm;
reg[17:0] mr1_wlev;
reg[29: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 <= MCONTR_CMD_WR_ADDR + WRITELEV_OFFSET;
// Enter write leveling mode
@(posedge CLK)
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr1_wlev[14:0], mr1_wlev[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // tWLDQSEN=25tCK
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// enable DQS output, keep it low (15 more tCK for the total of 40 tCK
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip(dqs_low_rpt, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Toggle DQS as needed for write leveling, write to buffer
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip(nrep_minus_1,0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// continue toggling (5 times), but disable writing to buffer (used same wbuf latency as for read)
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 4, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Keep DCI (but not ODT) active ODT should be off befor MRS
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// exit write leveling mode, ODT off, DCI off
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr1_norm[14:0], mr1_norm[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // tMOD
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Finalize. See if DONE can be combined with B_RST, if not - insert earlier
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); // can DONE be combined with B_RST?
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
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[29:0] cmd_addr;
reg[31:0] data;
begin
cmd_addr <= MCONTR_CMD_WR_ADDR + REFRESH_OFFSET;
@(posedge CLK)
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd( 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// =50 tREFI=260 ns before next ACTIVATE or REFRESH, @2.5ns clock, @5ns cycle
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( t_rfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// Ready for normal operation
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// write_contol_register(DLY_SET,0);
write_contol_register(MCONTR_TOP_16BIT_ADDR + MCONTR_TOP_16BIT_REFRESH_ADDRESS, REFRESH_OFFSET);
write_contol_register(MCONTR_TOP_16BIT_ADDR + MCONTR_TOP_16BIT_REFRESH_PERIOD, {24'h0,t_refi});
// enable refresh - should it be done here?
// write_contol_register(MCONTR_PHY_0BIT_ADDR + MCONTR_TOP_0BIT_REFRESH_EN + 1, 0);
end
endtask
task set_mrs; // will also calibrate ZQ
input reset_dll;
reg[17:0] mr0;
reg[17:0] mr1;
reg[17:0] mr2;
reg[17:0] mr3;
reg[29: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 <= MCONTR_CMD_WR_ADDR + INITIALIZE_OFFSET;
@(posedge CLK)
$display("mr0=0x%x", mr0);
$display("mr1=0x%x", mr1);
$display("mr2=0x%x", mr2);
$display("mr3=0x%x", mr3);
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr2[14:0], mr2[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr3[14:0], mr3[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr1[14:0], mr1[17:15], 7, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); // SEL==1 - just testing?
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(mr0[14:0], mr0[17:15], 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// encode ZQCL:
// addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data <= func_encode_cmd(15'h400, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// 512 clock cycles after ZQCL
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
// sequence done bit, skip length is ignored
// skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data <= func_encode_skip( 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@(posedge CLK) axi_write_single_w(cmd_addr, data); cmd_addr <= cmd_addr + 1;
end
endtask
/*
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
task axi_set_same_delays; //SuppressThisWarning VEditor : may be unused
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_dqs_odelay_nominal; //SuppressThisWarning VEditor : may be unused
begin
// axi_set_dqs_idelay(
write_contol_register(LD_DLY_LANE0_ODELAY + 8, (DLY_LANE0_ODELAY >> (8<<3)) & 32'hff);
write_contol_register(LD_DLY_LANE1_ODELAY + 8, (DLY_LANE1_ODELAY >> (8<<3)) & 32'hff);
write_contol_register(DLY_SET,0);
end
endtask
task axi_set_dqs_idelay_nominal; //SuppressThisWarning VEditor : may be unused
begin
// axi_set_dqs_idelay(
write_contol_register(LD_DLY_LANE0_IDELAY + 8, (DLY_LANE0_IDELAY >> (8<<3)) & 32'hff);
write_contol_register(LD_DLY_LANE1_IDELAY + 8, (DLY_LANE1_IDELAY >> (8<<3)) & 32'hff);
write_contol_register(DLY_SET,0);
end
endtask
task axi_set_dqs_idelay_wlv; //SuppressThisWarning VEditor : may be unused
begin
write_contol_register(LD_DLY_LANE0_IDELAY + 8, DLY_LANE0_DQS_WLV_IDELAY);
write_contol_register(LD_DLY_LANE1_IDELAY + 8, DLY_LANE1_DQS_WLV_IDELAY);
write_contol_register(DLY_SET,0);
end
endtask
task axi_set_delays; // set all individual delays
integer i;
begin
for (i=0;i<10;i=i+1) begin
write_contol_register(LD_DLY_LANE0_ODELAY + i, (DLY_LANE0_ODELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<9;i=i+1) begin
write_contol_register(LD_DLY_LANE0_IDELAY + i, (DLY_LANE0_IDELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<10;i=i+1) begin
write_contol_register(LD_DLY_LANE1_ODELAY + i, (DLY_LANE1_ODELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<9;i=i+1) begin
write_contol_register(LD_DLY_LANE1_IDELAY + i, (DLY_LANE1_IDELAY >> (i<<3)) & 32'hff);
end
for (i=0;i<32;i=i+1) begin
write_contol_register(LD_DLY_CMDA + i, (DLY_CMDA >> (i<<3)) & 32'hff);
end
// write_contol_register(DLY_SET,0);
axi_set_phase(DLY_PHASE); // also sets all delays
end
endtask
task axi_set_dq_idelay; // sets same delay to all dq idelay
input [7:0] delay;
begin
$display("SET DQ IDELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_IDELAY, 8, delay);
axi_set_multiple_delays(LD_DLY_LANE1_IDELAY, 8, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_dq_odelay;
input [7:0] delay;
begin
$display("SET DQ ODELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_ODELAY, 8, delay);
axi_set_multiple_delays(LD_DLY_LANE1_ODELAY, 8, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_dqs_idelay;
input [7:0] delay;
begin
$display("SET DQS IDELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_IDELAY + 8, 1, delay);
axi_set_multiple_delays(LD_DLY_LANE1_IDELAY + 8, 1, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_dqs_odelay;
input [7:0] delay;
begin
$display("SET DQS ODELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_ODELAY + 8, 1, delay);
axi_set_multiple_delays(LD_DLY_LANE1_ODELAY + 8, 1, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_dm_odelay;
input [7:0] delay;
begin
$display("SET DQM IDELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_LANE0_ODELAY + 9, 1, delay);
axi_set_multiple_delays(LD_DLY_LANE1_ODELAY + 9, 1, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_cmda_odelay;
input [7:0] delay;
begin
$display("SET COMMAND and ADDRESS ODELAY=0x%x @ %t",delay,$time);
axi_set_multiple_delays(LD_DLY_CMDA, 32, delay);
write_contol_register(DLY_SET,0); // set all delays
end
endtask
task axi_set_multiple_delays;
input [29:0] reg_addr;
input integer number;
input [7:0] delay;
integer i;
begin
for (i=0;i<number;i=i+1) begin
write_contol_register(reg_addr + i, {24'b0,delay}); // control regiter address
end
end
endtask
task axi_set_phase;
input [PHASE_WIDTH-1:0] phase;
begin
$display("SET CLOCK PHASE to 0x%x @ %t",phase,$time);
write_contol_register(LD_DLY_PHASE, {{(32-PHASE_WIDTH){1'b0}},phase}); // control regiter address
write_contol_register(DLY_SET,0);
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);
write_contol_register(MCONTR_PHY_16BIT_ADDR+MCONTR_PHY_16BIT_WBUF_DELAY, {28'h0, delay});
end
endtask
// set dq /dqs tristate on/off patterns
task axi_set_tristate_patterns;
begin
$display("SET TRISTATE PATTERNS @ %t",$time);
write_contol_register(MCONTR_PHY_16BIT_ADDR +MCONTR_PHY_16BIT_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.)
write_contol_register(MCONTR_PHY_16BIT_ADDR + MCONTR_PHY_16BIT_PATTERNS,
32'h0055);
end
endtask
task wait_ps_pio_ready; // wait PS PIO module can accept comamnds (fifo half empty)
input [1:0] mode;
begin
wait_status_condition (
MCNTRL_PS_STATUS_REG_ADDR,
MCNTRL_PS_ADDR+MCNTRL_PS_STATUS_CNTRL,
mode,
0,
2 << STATUS_2LSB_SHFT,
0);
end
endtask
task wait_ps_pio_done; // wait PS PIO module has no pending/running memory transaction
input [1:0] mode;
begin
wait_status_condition (
MCNTRL_PS_STATUS_REG_ADDR,
MCNTRL_PS_ADDR+MCNTRL_PS_STATUS_CNTRL,
mode,
0,
3 << STATUS_2LSB_SHFT,
0);
end
endtask
/*
localparam STATUS_SEQ_SHFT= 26; // bits [31:26] is the sequence number
localparam STATUS_2LSB_SHFT= 24; // bits [25:24] get the 2 LSB of the status (transmitted with the sequence number in the second byte)
localparam STATUS_MSB_RSHFT= 2; // status bits [25:2] are read through [23:0]
localparam STATUS_PSHIFTER_RDY_MASK = 1<<STATUS_2LSB_SHFT;
parameter MCONTR_PHY_STATUS_REG_ADDR= 'h0,//8 or less bits: status register address to use for memory controller phy
parameter MCONTR_TOP_STATUS_REG_ADDR= 'h1,//8 or less bits: status register address to use for memory controller
parameter MCNTRL_PS_STATUS_REG_ADDR= 'h2
parameter MCNTRL_SCANLINE_STATUS_REG_CHN2_ADDR='h4,
parameter MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR='h5,
parameter MCNTRL_TILED_STATUS_REG_CHN4_ADDR= 'h6,
parameter MCNTRL_TEST01_STATUS_REG_CHN2_ADDR= 'h3c, // status/readback register for channel 2
parameter MCNTRL_TEST01_STATUS_REG_CHN3_ADDR= 'h3d, // status/readback register for channel 3
parameter MCNTRL_TEST01_STATUS_REG_CHN4_ADDR= 'h3e // status/readback register for channel 4
*/
task wait_status_condition;
input [STATUS_DEPTH-1:0] status_address;
input [29:0] status_control_address;
input [1:0] status_mode;
input [25:0] pattern; // bits as in read registers
input [25:0] mask; // which bits to compare
input invert_match; // 0 - wait until match to pattern (all bits), 1 - wait until no match (any of bits differ)
reg match;
reg [5:0] seq_num;
begin
WAITING_STATUS = 1;
for (match=0; !match; match = invert_match ^ (((registered_rdata ^ {6'h0,pattern}) & {6'h0,mask})==0)) begin
read_and_wait_status(status_address);
write_contol_register(status_control_address, {24'b0,status_mode,registered_rdata[STATUS_SEQ_SHFT+:6] ^ 6'h20});
seq_num <= registered_rdata[STATUS_SEQ_SHFT+:6] ^ 6'h20;
read_and_wait_status(status_address);
while (((registered_rdata[STATUS_SEQ_SHFT+:6] ^ seq_num) & 6'h30)!=0) begin // match just 2 MSBs
read_and_wait_status(status_address);
end
end
WAITING_STATUS = 0;
end
endtask
task wait_phase_shifter_ready;
begin
WAITING_STATUS = 1;
read_and_wait_status(MCONTR_PHY_STATUS_REG_ADDR);
while (((registered_rdata & STATUS_PSHIFTER_RDY_MASK) == 0) || (((registered_rdata ^ {24'h0,target_phase}) & 'hff) != 0)) begin
read_and_wait_status(MCONTR_PHY_STATUS_REG_ADDR); // exits after negedge CLK
end
WAITING_STATUS = 0;
end
endtask
task read_all_status;
begin
read_and_wait_status (MCONTR_PHY_STATUS_REG_ADDR);
read_and_wait_status (MCONTR_TOP_STATUS_REG_ADDR);
read_and_wait_status (MCNTRL_PS_STATUS_REG_ADDR);
read_and_wait_status (MCNTRL_SCANLINE_STATUS_REG_CHN2_ADDR);
read_and_wait_status (MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR);
read_and_wait_status (MCNTRL_TILED_STATUS_REG_CHN4_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN2_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN3_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN4_ADDR);
end
endtask
task read_and_wait_status;
input [STATUS_DEPTH-1:0] address;
begin
read_and_wait_w(STATUS_ADDR + address ); // Will set: registered_rdata <= rdata;
end
endtask
task program_status_all;
input [1:0] mode;
input [5:0] seq_num;
begin
program_status (MCONTR_PHY_16BIT_ADDR, MCONTR_PHY_STATUS_CNTRL, mode,seq_num); //MCONTR_PHY_STATUS_REG_ADDR= 'h0,
program_status (MCONTR_TOP_16BIT_ADDR, MCONTR_TOP_16BIT_STATUS_CNTRL, mode,seq_num); //MCONTR_TOP_STATUS_REG_ADDR= 'h1,
program_status (MCNTRL_PS_ADDR, MCNTRL_PS_STATUS_CNTRL, mode,seq_num); //MCNTRL_PS_STATUS_REG_ADDR= 'h2,
program_status (MCNTRL_SCANLINE_CHN2_ADDR, MCNTRL_SCANLINE_STATUS_CNTRL, mode,seq_num); //MCNTRL_SCANLINE_STATUS_REG_CHN2_ADDR='h4,
program_status (MCNTRL_SCANLINE_CHN3_ADDR, MCNTRL_SCANLINE_STATUS_CNTRL, mode,seq_num); //MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR='h5,
program_status (MCNTRL_TILED_CHN4_ADDR, MCNTRL_TILED_STATUS_CNTRL, mode,seq_num); //MCNTRL_TILED_STATUS_REG_CHN4_ADDR= 'h6,
program_status (MCNTRL_TEST01_ADDR, MCNTRL_TEST01_CHN2_STATUS_CNTRL,mode,seq_num); //MCNTRL_TEST01_STATUS_REG_CHN2_ADDR= 'h3c,
program_status (MCNTRL_TEST01_ADDR, MCNTRL_TEST01_CHN3_STATUS_CNTRL,mode,seq_num); //MCNTRL_TEST01_STATUS_REG_CHN3_ADDR= 'h3d,
program_status (MCNTRL_TEST01_ADDR, MCNTRL_TEST01_CHN4_STATUS_CNTRL,mode,seq_num); //MCNTRL_TEST01_STATUS_REG_CHN4_ADDR= 'h3e,
end
endtask
task program_status;
input [29:0] base_addr;
input [7:0] reg_addr;
input [1:0] mode;
// mode bits:
// 0 disable status generation,
// 1 single status request,
// 2 - auto status, keep specified seq number,
// 3 - auto, inc sequence number
input [5:0] seq_number;
begin
// axi_write_single_w(CONTROL_ADDR+base_addr+reg_addr, {24'b0,mode,seq_number});
write_contol_register(base_addr + reg_addr, {24'b0,mode,seq_number});
end
endtask
task write_contol_register;
input [29:0] reg_addr;
// input [29:0] base_addr;
// input [7:0] reg_addr;
input [31:0] data;
begin
// axi_write_single_w(CONTROL_ADDR+base_addr+reg_addr, data);
axi_write_single_w(CONTROL_ADDR+reg_addr, data);
end
endtask
`include "includes/x393_tasks_mcntrl_en_dis_priority.vh"
`include "includes/x393_tasks_mcntrl_buffers.vh"
`include "includes/x393_tasks_pio_sequences.vh"
`include "includes/x393_tasks_mcntrl_timing.vh"
`include "includes/x393_tasks_ps_pio.vh"
`include "includes/x393_tasks_status.vh"
`include "includes/x393_tasks01.vh"
`include "includes/x393_mcontr_encode_cmd.vh"
endmodule
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment