Add spiflash testbench and add support for QSPI and DDR QSPI to SPI flash sim model
This commit is contained in:
parent
82a51bc8a4
commit
571f5d5df7
|
@ -1,5 +1,7 @@
|
||||||
/testbench.vcd
|
/testbench.vcd
|
||||||
/testbench.vvp
|
/testbench.vvp
|
||||||
|
/spiflash_tb.vcd
|
||||||
|
/spiflash_tb.vvp
|
||||||
/firmware.elf
|
/firmware.elf
|
||||||
/firmware_vma.elf
|
/firmware_vma.elf
|
||||||
/firmware.hex
|
/firmware.hex
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
|
|
||||||
test: testbench.vvp firmware.hex
|
testbench: testbench.vvp firmware.hex
|
||||||
vvp -N $<
|
vvp -N $<
|
||||||
|
|
||||||
|
testbench.vvp: spiflash.v spimemio.v testbench.v top.v ../picorv32.v
|
||||||
|
iverilog -s testbench -o $@ $^
|
||||||
|
|
||||||
|
spiflash_tb: spiflash_tb.vvp firmware.hex
|
||||||
|
vvp -N $<
|
||||||
|
|
||||||
|
spiflash_tb.vvp: spiflash.v spiflash_tb.v
|
||||||
|
iverilog -s testbench -o $@ $^
|
||||||
|
|
||||||
prog: design.bin firmware.bin
|
prog: design.bin firmware.bin
|
||||||
iceprog design.bin
|
iceprog design.bin
|
||||||
iceprog -o 1M firmware.bin
|
iceprog -o 1M firmware.bin
|
||||||
|
|
||||||
testbench.vvp: spiflash.v spimemio.v testbench.v top.v ../picorv32.v
|
|
||||||
iverilog -s testbench -o $@ $^
|
|
||||||
|
|
||||||
firmware.elf: firmware.s
|
firmware.elf: firmware.s
|
||||||
riscv32-unknown-elf-gcc -c -o firmware.elf firmware.s
|
riscv32-unknown-elf-gcc -c -o firmware.elf firmware.s
|
||||||
|
|
||||||
|
@ -32,9 +38,9 @@ design.bin: design.asc
|
||||||
icepack design.asc design.bin
|
icepack design.asc design.bin
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f testbench.vvp testbench.vcd
|
rm -f testbench.vvp testbench.vcd spiflash_tb.vvp spiflash_tb.vcd
|
||||||
rm -f firmware.elf firmware_vma.elf firmware.hex firmware.bin
|
rm -f firmware.elf firmware_vma.elf firmware.hex firmware.bin
|
||||||
rm -f design.blif design.log design.asc design.rpt design.bin
|
rm -f design.blif design.log design.asc design.rpt design.bin
|
||||||
|
|
||||||
.PHONY: test prog clean
|
.PHONY: testbench spiflash_tb prog clean
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,13 @@
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*
|
*
|
||||||
|
*
|
||||||
|
* Supported commands:
|
||||||
|
* AB, B9, FF, 03, EB, ED
|
||||||
|
*
|
||||||
|
* Well written SPI flash data sheets:
|
||||||
|
* Cypress S25FL064L http://www.cypress.com/file/316661/download
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module spiflash (
|
module spiflash (
|
||||||
|
@ -30,8 +37,10 @@ module spiflash (
|
||||||
reg [7:0] buffer;
|
reg [7:0] buffer;
|
||||||
integer bitcount = 0;
|
integer bitcount = 0;
|
||||||
integer bytecount = 0;
|
integer bytecount = 0;
|
||||||
|
integer dummycount = 0;
|
||||||
|
|
||||||
reg [7:0] spi_cmd;
|
reg [7:0] spi_cmd;
|
||||||
|
reg [7:0] xip_cmd = 0;
|
||||||
reg [23:0] spi_addr;
|
reg [23:0] spi_addr;
|
||||||
|
|
||||||
reg [7:0] spi_in;
|
reg [7:0] spi_in;
|
||||||
|
@ -40,12 +49,40 @@ module spiflash (
|
||||||
|
|
||||||
reg qspi_active = 0;
|
reg qspi_active = 0;
|
||||||
reg powered_up = 0;
|
reg powered_up = 0;
|
||||||
reg in_xfer = 0;
|
|
||||||
|
|
||||||
reg spi_miso;
|
localparam [3:0] mode_spi = 1;
|
||||||
|
localparam [3:0] mode_qspi_rd = 2;
|
||||||
|
localparam [3:0] mode_qspi_wr = 3;
|
||||||
|
localparam [3:0] mode_qspi_ddr_rd = 4;
|
||||||
|
localparam [3:0] mode_qspi_ddr_wr = 5;
|
||||||
|
|
||||||
wire spi_mosi = io0;
|
reg [3:0] mode = 0;
|
||||||
assign io1 = spi_miso;
|
reg [3:0] next_mode = 0;
|
||||||
|
|
||||||
|
reg io0_oe = 0;
|
||||||
|
reg io1_oe = 0;
|
||||||
|
reg io2_oe = 0;
|
||||||
|
reg io3_oe = 0;
|
||||||
|
|
||||||
|
reg io0_dout = 0;
|
||||||
|
reg io1_dout = 0;
|
||||||
|
reg io2_dout = 0;
|
||||||
|
reg io3_dout = 0;
|
||||||
|
|
||||||
|
assign io0 = io0_oe ? io0_dout : 1'bz;
|
||||||
|
assign io1 = io1_oe ? io1_dout : 1'bz;
|
||||||
|
assign io2 = io2_oe ? io2_dout : 1'bz;
|
||||||
|
assign io3 = io3_oe ? io3_dout : 1'bz;
|
||||||
|
|
||||||
|
wire io0_delayed;
|
||||||
|
wire io1_delayed;
|
||||||
|
wire io2_delayed;
|
||||||
|
wire io3_delayed;
|
||||||
|
|
||||||
|
assign #1 io0_delayed = io0;
|
||||||
|
assign #1 io1_delayed = io1;
|
||||||
|
assign #1 io2_delayed = io2;
|
||||||
|
assign #1 io3_delayed = io3;
|
||||||
|
|
||||||
// 16 MB (128Mb) Flash
|
// 16 MB (128Mb) Flash
|
||||||
reg [7:0] memory [0:16*1024*1024-1];
|
reg [7:0] memory [0:16*1024*1024-1];
|
||||||
|
@ -60,15 +97,18 @@ module spiflash (
|
||||||
|
|
||||||
if (bytecount == 1) begin
|
if (bytecount == 1) begin
|
||||||
spi_cmd = buffer;
|
spi_cmd = buffer;
|
||||||
if (spi_cmd == 8'hAB)
|
|
||||||
|
if (spi_cmd == 8'h ab)
|
||||||
powered_up = 1;
|
powered_up = 1;
|
||||||
if (spi_cmd == 8'hB9)
|
|
||||||
|
if (spi_cmd == 8'h b9)
|
||||||
powered_up = 0;
|
powered_up = 0;
|
||||||
if (spi_cmd == 8'hFF)
|
|
||||||
|
if (spi_cmd == 8'h ff)
|
||||||
qspi_active = 0;
|
qspi_active = 0;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (powered_up && spi_cmd == 'h03) begin
|
if (powered_up && spi_cmd == 'h 03) begin
|
||||||
if (bytecount == 2)
|
if (bytecount == 2)
|
||||||
spi_addr[23:16] = buffer;
|
spi_addr[23:16] = buffer;
|
||||||
|
|
||||||
|
@ -84,6 +124,56 @@ module spiflash (
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (powered_up && spi_cmd == 'h eb) begin
|
||||||
|
if (bytecount == 1)
|
||||||
|
mode = mode_qspi_rd;
|
||||||
|
|
||||||
|
if (bytecount == 2)
|
||||||
|
spi_addr[23:16] = buffer;
|
||||||
|
|
||||||
|
if (bytecount == 3)
|
||||||
|
spi_addr[15:8] = buffer;
|
||||||
|
|
||||||
|
if (bytecount == 4)
|
||||||
|
spi_addr[7:0] = buffer;
|
||||||
|
|
||||||
|
if (bytecount == 5) begin
|
||||||
|
xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
|
||||||
|
mode = mode_qspi_wr;
|
||||||
|
dummycount = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (bytecount >= 5) begin
|
||||||
|
buffer = memory[spi_addr];
|
||||||
|
spi_addr = spi_addr + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (powered_up && spi_cmd == 'h ed) begin
|
||||||
|
if (bytecount == 1)
|
||||||
|
next_mode = mode_qspi_ddr_rd;
|
||||||
|
|
||||||
|
if (bytecount == 2)
|
||||||
|
spi_addr[23:16] = buffer;
|
||||||
|
|
||||||
|
if (bytecount == 3)
|
||||||
|
spi_addr[15:8] = buffer;
|
||||||
|
|
||||||
|
if (bytecount == 4)
|
||||||
|
spi_addr[7:0] = buffer;
|
||||||
|
|
||||||
|
if (bytecount == 5) begin
|
||||||
|
xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
|
||||||
|
mode = mode_qspi_ddr_wr;
|
||||||
|
dummycount = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (bytecount >= 5) begin
|
||||||
|
buffer = memory[spi_addr];
|
||||||
|
spi_addr = spi_addr + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
spi_out = buffer;
|
spi_out = buffer;
|
||||||
spi_io_vld = 1;
|
spi_io_vld = 1;
|
||||||
|
|
||||||
|
@ -96,37 +186,159 @@ module spiflash (
|
||||||
end
|
end
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
|
task ddr_rd_edge;
|
||||||
|
begin
|
||||||
|
buffer = {buffer, io3_delayed, io2_delayed, io1_delayed, io0_delayed};
|
||||||
|
bitcount = bitcount + 4;
|
||||||
|
if (bitcount == 8) begin
|
||||||
|
bitcount = 0;
|
||||||
|
bytecount = bytecount + 1;
|
||||||
|
spi_action;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task ddr_wr_edge;
|
||||||
|
begin
|
||||||
|
io0_oe = 1;
|
||||||
|
io1_oe = 1;
|
||||||
|
io2_oe = 1;
|
||||||
|
io3_oe = 1;
|
||||||
|
|
||||||
|
io0_dout = buffer[4];
|
||||||
|
io1_dout = buffer[5];
|
||||||
|
io2_dout = buffer[6];
|
||||||
|
io3_dout = buffer[7];
|
||||||
|
|
||||||
|
buffer = {buffer, 4'h 0};
|
||||||
|
bitcount = bitcount + 4;
|
||||||
|
if (bitcount == 8) begin
|
||||||
|
bitcount = 0;
|
||||||
|
bytecount = bytecount + 1;
|
||||||
|
spi_action;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
always @(csb) begin
|
always @(csb) begin
|
||||||
if (csb) begin
|
if (csb) begin
|
||||||
if (verbose && in_xfer) begin
|
if (verbose) begin
|
||||||
$display("");
|
$display("");
|
||||||
$fflush;
|
$fflush;
|
||||||
end
|
end
|
||||||
buffer = 0;
|
buffer = 0;
|
||||||
in_xfer = 0;
|
|
||||||
bitcount = 0;
|
bitcount = 0;
|
||||||
bytecount = 0;
|
bytecount = 0;
|
||||||
spi_miso = 0;
|
mode = mode_spi;
|
||||||
|
io0_oe = 0;
|
||||||
|
io1_oe = 0;
|
||||||
|
io2_oe = 0;
|
||||||
|
io3_oe = 0;
|
||||||
|
end else
|
||||||
|
if (xip_cmd) begin
|
||||||
|
buffer = xip_cmd;
|
||||||
|
bitcount = 0;
|
||||||
|
bytecount = 1;
|
||||||
|
spi_action;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
always @(csb, clk) begin
|
always @(csb, clk) begin
|
||||||
spi_io_vld = 0;
|
spi_io_vld = 0;
|
||||||
if (!csb && !clk) begin
|
if (!csb && !clk) begin
|
||||||
spi_miso = buffer[7];
|
if (dummycount > 0) begin
|
||||||
|
io0_oe = 0;
|
||||||
|
io1_oe = 0;
|
||||||
|
io2_oe = 0;
|
||||||
|
io3_oe = 0;
|
||||||
|
end else
|
||||||
|
case (mode)
|
||||||
|
mode_spi: begin
|
||||||
|
io0_oe = 0;
|
||||||
|
io1_oe = 1;
|
||||||
|
io2_oe = 0;
|
||||||
|
io3_oe = 0;
|
||||||
|
io1_dout = buffer[7];
|
||||||
|
end
|
||||||
|
mode_qspi_rd: begin
|
||||||
|
io0_oe = 0;
|
||||||
|
io1_oe = 0;
|
||||||
|
io2_oe = 0;
|
||||||
|
io3_oe = 0;
|
||||||
|
end
|
||||||
|
mode_qspi_wr: begin
|
||||||
|
io0_oe = 1;
|
||||||
|
io1_oe = 1;
|
||||||
|
io2_oe = 1;
|
||||||
|
io3_oe = 1;
|
||||||
|
io0_dout = buffer[4];
|
||||||
|
io1_dout = buffer[5];
|
||||||
|
io2_dout = buffer[6];
|
||||||
|
io3_dout = buffer[7];
|
||||||
|
end
|
||||||
|
mode_qspi_ddr_rd: begin
|
||||||
|
ddr_rd_edge;
|
||||||
|
end
|
||||||
|
mode_qspi_ddr_wr: begin
|
||||||
|
ddr_wr_edge;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
if (next_mode) begin
|
||||||
|
case (next_mode)
|
||||||
|
mode_qspi_ddr_rd: begin
|
||||||
|
io0_oe = 0;
|
||||||
|
io1_oe = 0;
|
||||||
|
io2_oe = 0;
|
||||||
|
io3_oe = 0;
|
||||||
|
end
|
||||||
|
mode_qspi_ddr_wr: begin
|
||||||
|
io0_oe = 1;
|
||||||
|
io1_oe = 1;
|
||||||
|
io2_oe = 1;
|
||||||
|
io3_oe = 1;
|
||||||
|
io0_dout = buffer[4];
|
||||||
|
io1_dout = buffer[5];
|
||||||
|
io2_dout = buffer[6];
|
||||||
|
io3_dout = buffer[7];
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
mode = next_mode;
|
||||||
|
next_mode = 0;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
if (!csb) begin
|
if (!csb) begin
|
||||||
buffer = {buffer, spi_mosi};
|
if (dummycount > 0) begin
|
||||||
|
dummycount = dummycount - 1;
|
||||||
|
end else
|
||||||
|
case (mode)
|
||||||
|
mode_spi: begin
|
||||||
|
buffer = {buffer, io0};
|
||||||
bitcount = bitcount + 1;
|
bitcount = bitcount + 1;
|
||||||
if (bitcount == 8) begin
|
if (bitcount == 8) begin
|
||||||
in_xfer = 1;
|
|
||||||
bitcount = 0;
|
bitcount = 0;
|
||||||
bytecount = bytecount + 1;
|
bytecount = bytecount + 1;
|
||||||
spi_action;
|
spi_action;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
mode_qspi_rd, mode_qspi_wr: begin
|
||||||
|
buffer = {buffer, io3, io2, io1, io0};
|
||||||
|
bitcount = bitcount + 4;
|
||||||
|
if (bitcount == 8) begin
|
||||||
|
bitcount = 0;
|
||||||
|
bytecount = bytecount + 1;
|
||||||
|
spi_action;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mode_qspi_ddr_rd: begin
|
||||||
|
ddr_rd_edge;
|
||||||
|
end
|
||||||
|
mode_qspi_ddr_wr: begin
|
||||||
|
ddr_wr_edge;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -0,0 +1,363 @@
|
||||||
|
/*
|
||||||
|
* A simple test bench for the SPI flash simulation model
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
module testbench;
|
||||||
|
reg flash_csb = 1;
|
||||||
|
reg flash_clk = 0;
|
||||||
|
|
||||||
|
wire flash_io0;
|
||||||
|
wire flash_io1;
|
||||||
|
wire flash_io2;
|
||||||
|
wire flash_io3;
|
||||||
|
|
||||||
|
reg flash_io0_oe = 0;
|
||||||
|
reg flash_io1_oe = 0;
|
||||||
|
reg flash_io2_oe = 0;
|
||||||
|
reg flash_io3_oe = 0;
|
||||||
|
|
||||||
|
reg flash_io0_dout = 0;
|
||||||
|
reg flash_io1_dout = 0;
|
||||||
|
reg flash_io2_dout = 0;
|
||||||
|
reg flash_io3_dout = 0;
|
||||||
|
|
||||||
|
assign flash_io0 = flash_io0_oe ? flash_io0_dout : 1'bz;
|
||||||
|
assign flash_io1 = flash_io1_oe ? flash_io1_dout : 1'bz;
|
||||||
|
assign flash_io2 = flash_io2_oe ? flash_io2_dout : 1'bz;
|
||||||
|
assign flash_io3 = flash_io3_oe ? flash_io3_dout : 1'bz;
|
||||||
|
|
||||||
|
spiflash uut (
|
||||||
|
.csb(flash_csb),
|
||||||
|
.clk(flash_clk),
|
||||||
|
.io0(flash_io0),
|
||||||
|
.io1(flash_io1),
|
||||||
|
.io2(flash_io2),
|
||||||
|
.io3(flash_io3)
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam [23:0] offset = 24'h100000;
|
||||||
|
localparam [31:0] word0 = 32'h 01300293;
|
||||||
|
localparam [31:0] word1 = 32'h 00502223;
|
||||||
|
|
||||||
|
reg [7:0] rdata;
|
||||||
|
integer errcount = 0;
|
||||||
|
|
||||||
|
task expect;
|
||||||
|
input [7:0] data;
|
||||||
|
begin
|
||||||
|
if (data !== rdata) begin
|
||||||
|
$display("ERROR: Got %x (%b) but expected %x (%b).", rdata, rdata, data, data);
|
||||||
|
errcount = errcount + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task xfer_begin;
|
||||||
|
begin
|
||||||
|
#50;
|
||||||
|
flash_csb = 0;
|
||||||
|
$display("-- BEGIN");
|
||||||
|
#50;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task xfer_dummy;
|
||||||
|
begin
|
||||||
|
flash_io0_oe = 0;
|
||||||
|
flash_io1_oe = 0;
|
||||||
|
flash_io2_oe = 0;
|
||||||
|
flash_io3_oe = 0;
|
||||||
|
|
||||||
|
#50;
|
||||||
|
flash_clk = 1;
|
||||||
|
#50;
|
||||||
|
flash_clk = 0;
|
||||||
|
#50;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task xfer_end;
|
||||||
|
begin
|
||||||
|
#50;
|
||||||
|
flash_csb = 1;
|
||||||
|
flash_io0_oe = 0;
|
||||||
|
flash_io1_oe = 0;
|
||||||
|
flash_io2_oe = 0;
|
||||||
|
flash_io3_oe = 0;
|
||||||
|
$display("-- END");
|
||||||
|
$display("");
|
||||||
|
#50;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task xfer_spi;
|
||||||
|
input [7:0] data;
|
||||||
|
integer i;
|
||||||
|
begin
|
||||||
|
flash_io0_oe = 1;
|
||||||
|
flash_io1_oe = 0;
|
||||||
|
flash_io2_oe = 0;
|
||||||
|
flash_io3_oe = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i=i+1) begin
|
||||||
|
flash_io0_dout = data[7-i];
|
||||||
|
#50;
|
||||||
|
rdata[7-i] = flash_io1;
|
||||||
|
flash_clk <= 1;
|
||||||
|
#50;
|
||||||
|
flash_clk = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
$display("-- SPI SDR %02x %02x", data, rdata);
|
||||||
|
#50;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task xfer_qspi_wr;
|
||||||
|
input [7:0] data;
|
||||||
|
integer i;
|
||||||
|
begin
|
||||||
|
flash_io0_oe = 1;
|
||||||
|
flash_io1_oe = 1;
|
||||||
|
flash_io2_oe = 1;
|
||||||
|
flash_io3_oe = 1;
|
||||||
|
|
||||||
|
flash_io0_dout = data[4];
|
||||||
|
flash_io1_dout = data[5];
|
||||||
|
flash_io2_dout = data[6];
|
||||||
|
flash_io3_dout = data[7];
|
||||||
|
|
||||||
|
#50;
|
||||||
|
flash_clk = 1;
|
||||||
|
#50;
|
||||||
|
flash_clk = 0;
|
||||||
|
|
||||||
|
flash_io0_dout = data[0];
|
||||||
|
flash_io1_dout = data[1];
|
||||||
|
flash_io2_dout = data[2];
|
||||||
|
flash_io3_dout = data[3];
|
||||||
|
|
||||||
|
#50;
|
||||||
|
flash_clk = 1;
|
||||||
|
#50;
|
||||||
|
flash_clk = 0;
|
||||||
|
|
||||||
|
$display("-- QSPI SDR %02x --", data);
|
||||||
|
#50;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task xfer_qspi_rd;
|
||||||
|
integer i;
|
||||||
|
begin
|
||||||
|
flash_io0_oe = 0;
|
||||||
|
flash_io1_oe = 0;
|
||||||
|
flash_io2_oe = 0;
|
||||||
|
flash_io3_oe = 0;
|
||||||
|
|
||||||
|
#50;
|
||||||
|
rdata[4] = flash_io0;
|
||||||
|
rdata[5] = flash_io1;
|
||||||
|
rdata[6] = flash_io2;
|
||||||
|
rdata[7] = flash_io3;
|
||||||
|
flash_clk <= 1;
|
||||||
|
#50;
|
||||||
|
flash_clk = 0;
|
||||||
|
|
||||||
|
#50;
|
||||||
|
rdata[0] = flash_io0;
|
||||||
|
rdata[1] = flash_io1;
|
||||||
|
rdata[2] = flash_io2;
|
||||||
|
rdata[3] = flash_io3;
|
||||||
|
flash_clk <= 1;
|
||||||
|
#50;
|
||||||
|
flash_clk = 0;
|
||||||
|
|
||||||
|
$display("-- QSPI SDR -- %02x", rdata);
|
||||||
|
#50;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task xfer_qspi_ddr_wr;
|
||||||
|
input [7:0] data;
|
||||||
|
integer i;
|
||||||
|
begin
|
||||||
|
flash_io0_oe = 1;
|
||||||
|
flash_io1_oe = 1;
|
||||||
|
flash_io2_oe = 1;
|
||||||
|
flash_io3_oe = 1;
|
||||||
|
|
||||||
|
flash_io0_dout <= data[4];
|
||||||
|
flash_io1_dout <= data[5];
|
||||||
|
flash_io2_dout <= data[6];
|
||||||
|
flash_io3_dout <= data[7];
|
||||||
|
|
||||||
|
#50;
|
||||||
|
flash_clk = 1;
|
||||||
|
|
||||||
|
flash_io0_dout <= data[0];
|
||||||
|
flash_io1_dout <= data[1];
|
||||||
|
flash_io2_dout <= data[2];
|
||||||
|
flash_io3_dout <= data[3];
|
||||||
|
|
||||||
|
#50;
|
||||||
|
flash_clk = 0;
|
||||||
|
|
||||||
|
$display("-- QSPI DDR %02x --", data);
|
||||||
|
#50;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task xfer_qspi_ddr_rd;
|
||||||
|
integer i;
|
||||||
|
begin
|
||||||
|
flash_io0_oe = 0;
|
||||||
|
flash_io1_oe = 0;
|
||||||
|
flash_io2_oe = 0;
|
||||||
|
flash_io3_oe = 0;
|
||||||
|
|
||||||
|
#50;
|
||||||
|
rdata[4] = flash_io0;
|
||||||
|
rdata[5] = flash_io1;
|
||||||
|
rdata[6] = flash_io2;
|
||||||
|
rdata[7] = flash_io3;
|
||||||
|
flash_clk <= 1;
|
||||||
|
|
||||||
|
#50;
|
||||||
|
rdata[0] = flash_io0;
|
||||||
|
rdata[1] = flash_io1;
|
||||||
|
rdata[2] = flash_io2;
|
||||||
|
rdata[3] = flash_io3;
|
||||||
|
flash_clk <= 0;
|
||||||
|
|
||||||
|
$display("-- QSPI DDR -- %02x", rdata);
|
||||||
|
#50;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("spiflash_tb.vcd");
|
||||||
|
$dumpvars(0, testbench);
|
||||||
|
$display("");
|
||||||
|
|
||||||
|
$display("Reset (FFh)");
|
||||||
|
xfer_begin;
|
||||||
|
xfer_spi(8'h ff);
|
||||||
|
xfer_end;
|
||||||
|
|
||||||
|
$display("Power Up (ABh)");
|
||||||
|
xfer_begin;
|
||||||
|
xfer_spi(8'h ab);
|
||||||
|
xfer_end;
|
||||||
|
|
||||||
|
$display("Read Data (03h)");
|
||||||
|
xfer_begin;
|
||||||
|
xfer_spi(8'h 03);
|
||||||
|
xfer_spi(offset[23:16]);
|
||||||
|
xfer_spi(offset[15:8]);
|
||||||
|
xfer_spi(offset[7:0]);
|
||||||
|
xfer_spi(8'h 00); expect(word0[7:0]);
|
||||||
|
xfer_spi(8'h 00); expect(word0[15:8]);
|
||||||
|
xfer_spi(8'h 00); expect(word0[23:16]);
|
||||||
|
xfer_spi(8'h 00); expect(word0[31:24]);
|
||||||
|
xfer_spi(8'h 00); expect(word1[7:0]);
|
||||||
|
xfer_spi(8'h 00); expect(word1[15:8]);
|
||||||
|
xfer_spi(8'h 00); expect(word1[23:16]);
|
||||||
|
xfer_spi(8'h 00); expect(word1[31:24]);
|
||||||
|
xfer_end;
|
||||||
|
|
||||||
|
$display("Quad I/O Read (EBh)");
|
||||||
|
xfer_begin;
|
||||||
|
xfer_spi(8'h eb);
|
||||||
|
xfer_qspi_wr(offset[23:16]);
|
||||||
|
xfer_qspi_wr(offset[15:8]);
|
||||||
|
xfer_qspi_wr(offset[7:0]);
|
||||||
|
xfer_qspi_wr(8'h a5);
|
||||||
|
xfer_dummy;
|
||||||
|
xfer_qspi_rd; expect(word0[7:0]);
|
||||||
|
xfer_qspi_rd; expect(word0[15:8]);
|
||||||
|
xfer_qspi_rd; expect(word0[23:16]);
|
||||||
|
xfer_qspi_rd; expect(word0[31:24]);
|
||||||
|
xfer_qspi_rd; expect(word1[7:0]);
|
||||||
|
xfer_qspi_rd; expect(word1[15:8]);
|
||||||
|
xfer_qspi_rd; expect(word1[23:16]);
|
||||||
|
xfer_qspi_rd; expect(word1[31:24]);
|
||||||
|
xfer_end;
|
||||||
|
|
||||||
|
$display("Continous Quad I/O Read");
|
||||||
|
xfer_begin;
|
||||||
|
xfer_qspi_wr(offset[23:16]);
|
||||||
|
xfer_qspi_wr(offset[15:8]);
|
||||||
|
xfer_qspi_wr(offset[7:0]);
|
||||||
|
xfer_qspi_wr(8'h ff);
|
||||||
|
xfer_dummy;
|
||||||
|
xfer_qspi_rd; expect(word0[7:0]);
|
||||||
|
xfer_qspi_rd; expect(word0[15:8]);
|
||||||
|
xfer_qspi_rd; expect(word0[23:16]);
|
||||||
|
xfer_qspi_rd; expect(word0[31:24]);
|
||||||
|
xfer_qspi_rd; expect(word1[7:0]);
|
||||||
|
xfer_qspi_rd; expect(word1[15:8]);
|
||||||
|
xfer_qspi_rd; expect(word1[23:16]);
|
||||||
|
xfer_qspi_rd; expect(word1[31:24]);
|
||||||
|
xfer_end;
|
||||||
|
|
||||||
|
$display("DDR Quad I/O Read (EDh)");
|
||||||
|
xfer_begin;
|
||||||
|
xfer_spi(8'h ed);
|
||||||
|
xfer_qspi_ddr_wr(offset[23:16]);
|
||||||
|
xfer_qspi_ddr_wr(offset[15:8]);
|
||||||
|
xfer_qspi_ddr_wr(offset[7:0]);
|
||||||
|
xfer_qspi_ddr_wr(8'h a5);
|
||||||
|
xfer_dummy;
|
||||||
|
xfer_qspi_ddr_rd; expect(word0[7:0]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word0[15:8]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word0[23:16]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word0[31:24]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word1[7:0]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word1[15:8]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word1[23:16]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word1[31:24]);
|
||||||
|
xfer_end;
|
||||||
|
|
||||||
|
$display("Continous DDR Quad I/O Read");
|
||||||
|
xfer_begin;
|
||||||
|
xfer_qspi_ddr_wr(offset[23:16]);
|
||||||
|
xfer_qspi_ddr_wr(offset[15:8]);
|
||||||
|
xfer_qspi_ddr_wr(offset[7:0]);
|
||||||
|
xfer_qspi_ddr_wr(8'h ff);
|
||||||
|
xfer_dummy;
|
||||||
|
xfer_qspi_ddr_rd; expect(word0[7:0]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word0[15:8]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word0[23:16]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word0[31:24]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word1[7:0]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word1[15:8]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word1[23:16]);
|
||||||
|
xfer_qspi_ddr_rd; expect(word1[31:24]);
|
||||||
|
xfer_end;
|
||||||
|
|
||||||
|
#500;
|
||||||
|
|
||||||
|
if (errcount) begin
|
||||||
|
$display("FAIL");
|
||||||
|
$stop;
|
||||||
|
end else begin
|
||||||
|
$display("PASS");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
Loading…
Reference in New Issue