mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2024-10-01 01:45:38 -04:00
Adding testbench and simulation targets for the SPI master.
This commit is contained in:
parent
3bc2453287
commit
f61d254fda
2
.gitignore
vendored
2
.gitignore
vendored
@ -60,6 +60,6 @@ fp-info-cache
|
||||
*.net
|
||||
*.dsn
|
||||
*.ses
|
||||
|
||||
__pycache__
|
||||
application_fpga_par.json
|
||||
MEM.TXT
|
||||
|
@ -249,4 +249,17 @@ https://www.mouser.se/datasheet/2/949/w25q80dv_dl_revh_10022015-1489677.pdf
|
||||
The core is implemented as a single module. Future versions will
|
||||
probably be separated into separate modules.
|
||||
|
||||
|
||||
## Winbond Flash memory model
|
||||
|
||||
The testbench for the SPI master requires a memory model of the
|
||||
Winbond Flash memory. The model [can be downloaded from
|
||||
Winbond](https://www.winbond.com/hq/support/documentation/downloadV2022.jsp?__locale=en&xmlPath=/support/resources/.content/item/DA02-KAG049.html&level=2)
|
||||
by providing the requested information and supplying the received
|
||||
verification code.
|
||||
|
||||
From the downloaded file 'W25Q80DL.zip', please extract the file
|
||||
W25Q80DL.v and place it in the 'tb' directory before building the
|
||||
simulation model.
|
||||
|
||||
---
|
||||
|
@ -58,6 +58,10 @@ module tb_tk1();
|
||||
localparam ADDR_CPU_MON_FIRST = 8'h61;
|
||||
localparam ADDR_CPU_MON_LAST = 8'h62;
|
||||
|
||||
localparam ADDR_SPI_EN = 8'h80;
|
||||
localparam ADDR_SPI_XFER = 8'h81;
|
||||
localparam ADDR_SPI_DATA = 8'h82;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Register and Wire declarations.
|
||||
@ -89,6 +93,11 @@ module tb_tk1();
|
||||
wire tb_gpio3;
|
||||
wire tb_gpio4;
|
||||
|
||||
wire tb_spi_ss;
|
||||
wire tb_spi_sck;
|
||||
wire tb_spi_mosi;
|
||||
wire tb_spi_miso;
|
||||
|
||||
reg tb_cs;
|
||||
reg tb_we;
|
||||
reg [7 : 0] tb_address;
|
||||
@ -96,6 +105,12 @@ module tb_tk1();
|
||||
wire [31 : 0] tb_read_data;
|
||||
wire tb_ready;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Continuous assignments.
|
||||
//----------------------------------------------------------------
|
||||
// Inverted loopback of SPI data lines.
|
||||
assign tb_spi_miso = ~tb_spi_mosi;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Device Under Test.
|
||||
@ -124,6 +139,11 @@ module tb_tk1();
|
||||
.gpio3(tb_gpio3),
|
||||
.gpio4(tb_gpio4),
|
||||
|
||||
.spi_ss(tb_spi_ss),
|
||||
.spi_sck(tb_spi_sck),
|
||||
.spi_mosi(tb_spi_mosi),
|
||||
.spi_miso(tb_spi_miso),
|
||||
|
||||
.cs(tb_cs),
|
||||
.we(tb_we),
|
||||
.address(tb_address),
|
||||
@ -614,7 +634,38 @@ module tb_tk1();
|
||||
$display("--- test9: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // test8
|
||||
endtask // test9
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test10()
|
||||
// SPI master loopback test.
|
||||
//----------------------------------------------------------------
|
||||
task test10;
|
||||
begin
|
||||
tc_ctr = tc_ctr + 1;
|
||||
|
||||
$display("");
|
||||
$display("--- test10: Loopback in SPI Master started.");
|
||||
|
||||
$display("--- test10: Sending a byte.");
|
||||
write_word(ADDR_SPI_EN, 32'h1);
|
||||
write_word(ADDR_SPI_DATA, 32'ha7);
|
||||
write_word(ADDR_SPI_XFER, 32'h1);
|
||||
|
||||
while (!dut.spi_ready) begin
|
||||
#(CLK_PERIOD);
|
||||
end
|
||||
$display("--- test10: Byte should have been sent.");
|
||||
write_word(ADDR_SPI_EN, 32'h0);
|
||||
|
||||
// 0x58 is the inverse of 0xa7.
|
||||
read_word(ADDR_SPI_DATA, 32'h58);
|
||||
|
||||
$display("--- test10: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // test10
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@ -639,6 +690,8 @@ module tb_tk1();
|
||||
test7();
|
||||
test8();
|
||||
test9();
|
||||
test9();
|
||||
test10();
|
||||
|
||||
display_test_result();
|
||||
$display("");
|
||||
|
732
hw/application_fpga/core/tk1/tb/tb_tk1_spi_master.v
Normal file
732
hw/application_fpga/core/tk1/tb/tb_tk1_spi_master.v
Normal file
@ -0,0 +1,732 @@
|
||||
//======================================================================
|
||||
//
|
||||
// tb_tk1_spi_master.v
|
||||
// -------------------
|
||||
// Testbench for the TK1_SPI_MASTER core.
|
||||
//
|
||||
//
|
||||
// Author: Joachim Strombergson
|
||||
// Copyright (C) 2023 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
`default_nettype none
|
||||
`timescale 1ns / 1ns
|
||||
|
||||
module tb_tk1_spi_master();
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Internal constant and parameter definitions.
|
||||
//----------------------------------------------------------------
|
||||
parameter DEBUG = 1;
|
||||
|
||||
parameter CLK_HALF_PERIOD = 1;
|
||||
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
|
||||
|
||||
parameter MISO_ALL_ZERO = 0;
|
||||
parameter MISO_ALL_ONE = 1;
|
||||
parameter MISO_MOSI = 2;
|
||||
parameter MISO_INV_MOSI = 3;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Register and Wire declarations.
|
||||
//----------------------------------------------------------------
|
||||
reg [31 : 0] cycle_ctr;
|
||||
reg [31 : 0] error_ctr;
|
||||
reg [31 : 0] tc_ctr;
|
||||
reg monitor;
|
||||
reg verbose;
|
||||
|
||||
reg tb_clk;
|
||||
reg tb_reset_n;
|
||||
wire tb_spi_ss;
|
||||
wire tb_spi_sck;
|
||||
wire tb_spi_mosi;
|
||||
wire tb_spi_miso;
|
||||
reg tb_spi_enable;
|
||||
reg tb_spi_enable_vld;
|
||||
reg tb_spi_start;
|
||||
reg [7 : 0] tb_spi_tx_data;
|
||||
reg tb_spi_tx_data_vld;
|
||||
wire [7 : 0] tb_spi_rx_data;
|
||||
wire tb_spi_ready;
|
||||
|
||||
wire mem_model_WPn;
|
||||
wire mem_model_HOLDn;
|
||||
|
||||
reg [1 : 0] tb_miso_mux_ctrl;
|
||||
|
||||
reg my_tb_spi_ss;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Assignments.
|
||||
//----------------------------------------------------------------
|
||||
assign mem_model_WPn = 1'h1;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Device Under Test.
|
||||
//----------------------------------------------------------------
|
||||
tk1_spi_master dut(
|
||||
.clk(tb_clk),
|
||||
.reset_n(tb_reset_n),
|
||||
|
||||
.spi_ss(tb_spi_ss),
|
||||
.spi_sck(tb_spi_sck),
|
||||
.spi_mosi(tb_spi_mosi),
|
||||
.spi_miso(tb_spi_miso),
|
||||
|
||||
.spi_enable(tb_spi_enable),
|
||||
.spi_enable_vld(tb_spi_enable_vld),
|
||||
.spi_start(tb_spi_start),
|
||||
.spi_tx_data(tb_spi_tx_data),
|
||||
.spi_tx_data_vld(tb_spi_tx_data_vld),
|
||||
.spi_rx_data(tb_spi_rx_data),
|
||||
.spi_ready(tb_spi_ready)
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// spi_memory
|
||||
//----------------------------------------------------------------
|
||||
W25Q80DL spi_memory(
|
||||
.CSn(tb_spi_ss),
|
||||
.CLK(tb_spi_sck),
|
||||
.DIO(tb_spi_mosi),
|
||||
.DO(tb_spi_miso),
|
||||
.WPn(mem_model_WPn),
|
||||
.HOLDn(mem_model_HOLDn)
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// clk_gen
|
||||
//
|
||||
// Always running clock generator process.
|
||||
//----------------------------------------------------------------
|
||||
always
|
||||
begin : clk_gen
|
||||
#CLK_HALF_PERIOD;
|
||||
tb_clk = !tb_clk;
|
||||
end // clk_gen
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// sys_monitor()
|
||||
//
|
||||
// An always running process that creates a cycle counter and
|
||||
// conditionally displays information about the DUT.
|
||||
//----------------------------------------------------------------
|
||||
always
|
||||
begin : sys_monitor
|
||||
cycle_ctr = cycle_ctr + 1;
|
||||
#(CLK_PERIOD);
|
||||
if (monitor)
|
||||
begin
|
||||
dump_dut_state();
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// dump_dut_state()
|
||||
//
|
||||
// Dump the state of the dump when needed.
|
||||
//----------------------------------------------------------------
|
||||
task dump_dut_state;
|
||||
begin : dump_dut_state
|
||||
$display("");
|
||||
$display("State of DUT at cycle: %08d", cycle_ctr);
|
||||
$display("------------");
|
||||
$display("Inputs and outputs:");
|
||||
$display("spi_ss: 0x%1x, spi_sck: 0x%1x, spi_mosi: 0x%1x, spi_miso:0x%1x",
|
||||
dut.spi_ss, dut.spi_sck, dut.spi_mosi, dut.spi_miso);
|
||||
$display("spi_enable_vld: 0x%1x, spi_enable: 0x%1x",
|
||||
dut.spi_enable_vld, dut.spi_enable);
|
||||
$display("spi_tx_data_vld: 0x%1x, spi_tx_data: 0x%02x",
|
||||
dut.spi_tx_data_vld, dut.spi_tx_data);
|
||||
$display("spi_start: 0x%1x, spi_ready: 0x%1x, spi_rx_data: 0x%02x",
|
||||
dut.spi_start, dut.spi_ready, dut.spi_rx_data);
|
||||
$display("");
|
||||
|
||||
|
||||
$display("");
|
||||
$display("Internal state:");
|
||||
$display("spi_clk_ctr_rst: 0x%1x, spi_clk_ctr_reg: 0x%02x",
|
||||
dut.spi_clk_ctr_rst, dut.spi_clk_ctr_reg);
|
||||
$display("");
|
||||
$display("spi_bit_ctr_rst: 0x%1x, spi_bit_ctr_inc: 0x%1x, spi_bit_ctr_reg: 0x%02x",
|
||||
dut.spi_bit_ctr_rst, dut.spi_bit_ctr_inc, dut.spi_bit_ctr_reg);
|
||||
$display("");
|
||||
$display("spi_ctrl_reg: 0x%02x, spi_ctrl_new: 0x%02x, spi_ctrl_we: 0x%1x",
|
||||
dut.spi_ctrl_reg, dut.spi_ctrl_new, dut.spi_ctrl_we);
|
||||
|
||||
$display("");
|
||||
$display("spi_tx_data_new: 0x%1x, spi_tx_data_nxt: 0x%1x, spi_tx_data_we: 0x%1x",
|
||||
dut.spi_tx_data_new, dut.spi_tx_data_nxt, dut.spi_tx_data_we);
|
||||
$display("spi_tx_data_reg: 0x%02x, spi_tx_data_new: 0x%02x",
|
||||
dut.spi_tx_data_reg, dut.spi_tx_data_new);
|
||||
$display("");
|
||||
$display("spi_rx_data_nxt: 0x%1x, spi_rx_data_we: 0x%1x",
|
||||
dut.spi_rx_data_nxt, dut.spi_rx_data_we);
|
||||
$display("spi_rx_data_reg: 0x%02x, spi_rx_data_new: 0x%02x",
|
||||
dut.spi_rx_data_reg, dut.spi_rx_data_new);
|
||||
$display("spi_rx_data_reg0: 0x%1x, spi_rx_data_new0: 0x%1x",
|
||||
dut.spi_rx_data_reg[0], dut.spi_rx_data_new[0]);
|
||||
$display("spi_rx_data_reg1: 0x%1x, spi_rx_data_new1: 0x%1x",
|
||||
dut.spi_rx_data_reg[1], dut.spi_rx_data_new[1]);
|
||||
$display("spi_rx_data_reg2: 0x%1x, spi_rx_data_new2: 0x%1x",
|
||||
dut.spi_rx_data_reg[2], dut.spi_rx_data_new[2]);
|
||||
$display("spi_rx_data_reg3: 0x%1x, spi_rx_data_new3: 0x%1x",
|
||||
dut.spi_rx_data_reg[3], dut.spi_rx_data_new[3]);
|
||||
$display("spi_rx_data_reg4: 0x%1x, spi_rx_data_new4: 0x%1x",
|
||||
dut.spi_rx_data_reg[4], dut.spi_rx_data_new[4]);
|
||||
$display("spi_rx_data_reg5: 0x%1x, spi_rx_data_new5: 0x%1x",
|
||||
dut.spi_rx_data_reg[5], dut.spi_rx_data_new[5]);
|
||||
$display("spi_rx_data_reg6: 0x%1x, spi_rx_data_new6: 0x%1x",
|
||||
dut.spi_rx_data_reg[6], dut.spi_rx_data_new[6]);
|
||||
$display("spi_rx_data_reg7: 0x%1x, spi_rx_data_new7: 0x%1x",
|
||||
dut.spi_rx_data_reg[7], dut.spi_rx_data_new[7]);
|
||||
$display("");
|
||||
end
|
||||
endtask // dump_dut_state
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// reset_dut()
|
||||
//
|
||||
// Toggle reset to put the DUT into a well known state.
|
||||
//----------------------------------------------------------------
|
||||
task reset_dut;
|
||||
begin
|
||||
$display("--- Toggle reset.");
|
||||
tb_reset_n = 0;
|
||||
#(2 * CLK_PERIOD);
|
||||
tb_reset_n = 1;
|
||||
end
|
||||
endtask // reset_dut
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// display_test_result()
|
||||
//
|
||||
// Display the accumulated test results.
|
||||
//----------------------------------------------------------------
|
||||
task display_test_result;
|
||||
begin
|
||||
if (error_ctr == 0)
|
||||
begin
|
||||
$display("--- All %02d test cases completed successfully", tc_ctr);
|
||||
end
|
||||
else
|
||||
begin
|
||||
$display("--- %02d tests completed - %02d test cases did not complete successfully.",
|
||||
tc_ctr, error_ctr);
|
||||
end
|
||||
end
|
||||
endtask // display_test_result
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// init_sim()
|
||||
//
|
||||
// Initialize all counters and testbed functionality as well
|
||||
// as setting the DUT inputs to defined values.
|
||||
//----------------------------------------------------------------
|
||||
task init_sim;
|
||||
begin
|
||||
cycle_ctr = 0;
|
||||
error_ctr = 0;
|
||||
tc_ctr = 0;
|
||||
monitor = 0;
|
||||
|
||||
tb_clk = 1'h0;
|
||||
tb_reset_n = 1'h1;
|
||||
tb_spi_enable = 1'h0;
|
||||
tb_spi_enable_vld = 1'h0;
|
||||
tb_spi_start = 1'h0;
|
||||
tb_spi_tx_data = 8'h0;
|
||||
tb_spi_tx_data_vld = 1'h0;
|
||||
tb_miso_mux_ctrl = MISO_MOSI;
|
||||
end
|
||||
endtask // init_sim
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// enable_spi
|
||||
//
|
||||
// Enable the SPI-interface
|
||||
//----------------------------------------------------------------
|
||||
task enable_spi;
|
||||
begin
|
||||
if (verbose) begin
|
||||
$display("enable_spi: Started");
|
||||
end
|
||||
|
||||
tb_spi_enable = 1'h1;
|
||||
tb_spi_enable_vld = 1'h1;
|
||||
#(CLK_PERIOD);
|
||||
tb_spi_enable_vld = 1'h0;
|
||||
#(CLK_PERIOD);
|
||||
|
||||
if (verbose) begin
|
||||
$display("enable_spi: Completed");
|
||||
end
|
||||
end
|
||||
endtask // enable_spi
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// disable_spi
|
||||
//
|
||||
// Disable the SPI-interface
|
||||
//----------------------------------------------------------------
|
||||
task disable_spi;
|
||||
begin
|
||||
if (verbose) begin
|
||||
$display("disable_spi: Started");
|
||||
end
|
||||
|
||||
tb_spi_enable = 1'h0;
|
||||
tb_spi_enable_vld = 1'h1;
|
||||
#(CLK_PERIOD);
|
||||
tb_spi_enable_vld = 1'h0;
|
||||
#(CLK_PERIOD);
|
||||
|
||||
if (verbose) begin
|
||||
$display("disable_spi: Completed");
|
||||
end
|
||||
end
|
||||
endtask // disable_spi
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// xfer_byte
|
||||
//
|
||||
// Wait until the SPI-master is ready, then send input byte
|
||||
// and return the received byte.
|
||||
//----------------------------------------------------------------
|
||||
task xfer_byte (input [7 : 0] to_mem, output [7 : 0] from_mem);
|
||||
begin
|
||||
if (verbose) begin
|
||||
$display("xfer_byte: Trying to send 0x%02x to mem", to_mem);
|
||||
end
|
||||
|
||||
tb_spi_tx_data = to_mem;
|
||||
tb_spi_tx_data_vld = 1'h1;
|
||||
#(CLK_PERIOD);
|
||||
tb_spi_tx_data_vld = 1'h0;
|
||||
#(CLK_PERIOD);
|
||||
|
||||
while (tb_spi_ready == 1'h0) begin
|
||||
#(CLK_PERIOD);
|
||||
end
|
||||
#(CLK_PERIOD);
|
||||
|
||||
tb_spi_start = 1'h1;
|
||||
#(CLK_PERIOD);
|
||||
tb_spi_start = 1'h0;
|
||||
#(CLK_PERIOD);
|
||||
|
||||
while (tb_spi_ready == 1'h0) begin
|
||||
#(CLK_PERIOD);
|
||||
end
|
||||
#(CLK_PERIOD);
|
||||
|
||||
from_mem = tb_spi_rx_data;
|
||||
#(CLK_PERIOD);
|
||||
if (verbose) begin
|
||||
$display("xfer_byte: Received 0x%02x from mem", from_mem);
|
||||
end
|
||||
end
|
||||
endtask // xfer_byte
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// read_mem_range()
|
||||
//
|
||||
// Read out a specified memory range. Result is printed,
|
||||
//----------------------------------------------------------------
|
||||
task read_mem_range (input [23 : 0] address, input integer num_bytes);
|
||||
begin : read_mem_range
|
||||
reg [7 : 0] rx_byte;
|
||||
integer i;
|
||||
|
||||
if (verbose) begin
|
||||
$display("read_mem_range: Reading out %d bytes starting at address 0x%06x", num_bytes, address);
|
||||
end
|
||||
|
||||
#(2 * CLK_PERIOD);
|
||||
enable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
// Send read command 0x03.
|
||||
xfer_byte(8'h03, rx_byte);
|
||||
|
||||
// Send adress 0x000000.
|
||||
xfer_byte(address[23 : 16], rx_byte);
|
||||
xfer_byte(address[15 : 8], rx_byte);
|
||||
xfer_byte(address[7 : 0], rx_byte);
|
||||
|
||||
// Read out num_bytes bytes.
|
||||
for (i = 0 ; i < num_bytes ; i = i + 1) begin
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_read_mem_range: Byte 0x%06x: 0x%02x", address + i, rx_byte);
|
||||
end
|
||||
|
||||
disable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
if (verbose) begin
|
||||
$display("read_mem_range: Completed");
|
||||
end
|
||||
end
|
||||
endtask // read_mem_range
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// read_status()
|
||||
//----------------------------------------------------------------
|
||||
task read_status ();
|
||||
begin : read_status
|
||||
reg [7 : 0] dummy;
|
||||
reg [15 : 0] status;
|
||||
enable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
xfer_byte(8'h05, dummy);
|
||||
xfer_byte(8'h00, status[15 : 8]);
|
||||
xfer_byte(8'h00, status[7 : 0]);
|
||||
#(2 * CLK_PERIOD);
|
||||
disable_spi();
|
||||
$display("--- read_status: 0x%04x", status);
|
||||
end
|
||||
endtask // read_status
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// tc_get_device_id()
|
||||
//
|
||||
// Test case that reads out the device ID.
|
||||
//----------------------------------------------------------------
|
||||
task tc_get_device_id;
|
||||
begin : tc_get_id
|
||||
reg [7 : 0] rx_byte;
|
||||
tc_ctr = tc_ctr + 1;
|
||||
monitor = 0;
|
||||
|
||||
$display("");
|
||||
$display("--- tc_get_device_id: Read out device id from the memory.");
|
||||
|
||||
#(2 * CLK_PERIOD);
|
||||
enable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
// Send 0xab command.
|
||||
$display("--- tc_get_device_id: Sending 0xab command.");
|
||||
xfer_byte(8'hab, rx_byte);
|
||||
#(CLK_PERIOD);
|
||||
|
||||
// Dummy bytes.
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_device_id: Got 0x%02x after dummy byte 1", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_device_id: Got 0x%02x after dummy byte 2", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_device_id: Got 0x%02x after dummy byte 3", rx_byte);
|
||||
|
||||
// Get the ID byte.
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_device_id: Got ID 0x%02x after dummy byte 4", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_device_id: Got ID 0x%02x after dummy byte 5", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_device_id: Got ID 0x%02x after dummy byte 6", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_device_id: Got ID 0x%02x after dummy byte 6", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_device_id: Got ID 0x%02x after dummy byte 6", rx_byte);
|
||||
|
||||
disable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
$display("--- tc_get_device_id: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // tc_get_device_id
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// tc_get_jedec_id()
|
||||
//
|
||||
// Test case that reads out the JEDEC ID.
|
||||
//----------------------------------------------------------------
|
||||
task tc_get_jedec_id;
|
||||
begin : tc_get_id
|
||||
reg [7 : 0] rx_byte;
|
||||
tc_ctr = tc_ctr + 1;
|
||||
monitor = 0;
|
||||
verbose = 0;
|
||||
|
||||
$display("");
|
||||
$display("--- tc_get_jedec_id: Read out JEDEC device id, type and capacity from the memory.");
|
||||
|
||||
#(2 * CLK_PERIOD);
|
||||
enable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
// Send 0x9f command.
|
||||
$display("--- tc_get_jedec_id: Sending 0xab command.");
|
||||
xfer_byte(8'h9f, rx_byte);
|
||||
|
||||
// Send dummy bytes and get response back.
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_jedec_id: Got manufacture ID 0x%02x", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_jedec_id: Got memory type 0x%02x", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_jedec_id: Got memory capacity 0x%02x", rx_byte);
|
||||
|
||||
disable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
$display("--- tc_get_jedec_id: completed.");
|
||||
$display("");
|
||||
|
||||
verbose = 1;
|
||||
end
|
||||
endtask // tc_get_jedec_id
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// tc_get_unique_device_id()
|
||||
//
|
||||
// Test case that reads out the JEDEC ID.
|
||||
// Expected: 0xdc02030405060708
|
||||
//----------------------------------------------------------------
|
||||
task tc_get_unique_device_id;
|
||||
begin : tc_get_id
|
||||
reg [7 : 0] rx_byte;
|
||||
integer i;
|
||||
tc_ctr = tc_ctr + 1;
|
||||
monitor = 0;
|
||||
verbose = 0;
|
||||
|
||||
$display("");
|
||||
$display("--- tc_get_unique_device_id: Read out unique id from the memory");
|
||||
$display("--- tc_get_unique_device_id: Expected result: 0x0102030405060708");
|
||||
|
||||
#(2 * CLK_PERIOD);
|
||||
enable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
// Send 0x9f command.
|
||||
$display("--- tc_get_unique_device_id: Sending 0x4b command.");
|
||||
xfer_byte(8'h4b, rx_byte);
|
||||
|
||||
// Send four dummy bytes and get response back.
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
|
||||
// Send eight bytes and get unique device id back.
|
||||
$display("--- tc_get_unique_device_id: reading out the unique device ID");
|
||||
for (i = 0 ; i < 8 ; i = i + 1) begin
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_unique_device_id: 0x%02x", rx_byte);
|
||||
end
|
||||
|
||||
disable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
$display("--- tc_get_unique_device_id: completed.");
|
||||
$display("");
|
||||
|
||||
verbose = 1;
|
||||
end
|
||||
endtask // tc_get_unique_device_id
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// tc_get_manufacturer_id()
|
||||
//
|
||||
// Test case that reads out the device ID.
|
||||
//----------------------------------------------------------------
|
||||
task tc_get_manufacturer_id;
|
||||
begin : tc_get_id
|
||||
reg [7 : 0] rx_byte;
|
||||
tc_ctr = tc_ctr + 1;
|
||||
monitor = 0;
|
||||
|
||||
$display("");
|
||||
$display("--- tc_get_manufacturer_id: Read out device id from the memory.");
|
||||
|
||||
#(2 * CLK_PERIOD);
|
||||
enable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
// Send 0x90 command.
|
||||
$display("--- tc_get_manufacturer_id: Sending 0xab command.");
|
||||
xfer_byte(8'h90, rx_byte);
|
||||
|
||||
// Dummy bytes.
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_manufacturer_id: Got 0x%02x after dummy byte 1", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_manufacturer_id: Got 0x%02x after dummy byte 2", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_manufacturer_id: Got 0x%02x after dummy byte 3", rx_byte);
|
||||
|
||||
// Get the ID byte.
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_manufacturer_id: Got ID 0x%02x after dummy byte 4", rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_get_manufacturer_id: Got ID 0x%02x after dummy byte 5", rx_byte);
|
||||
|
||||
disable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
$display("--- tc_get_manufacturer_id: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // tc_get_manufacturer_id
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// tc_read_mem()
|
||||
//
|
||||
// Test case that reads out the first 16 bytes of the memory.
|
||||
//----------------------------------------------------------------
|
||||
task tc_read_mem;
|
||||
begin : tc_get_id
|
||||
reg [7 : 0] rx_byte;
|
||||
integer i;
|
||||
tc_ctr = tc_ctr + 1;
|
||||
monitor = 0;
|
||||
verbose = 0;
|
||||
|
||||
$display("");
|
||||
$display("--- tc_read_mem: Read out the first 16 bytes from the memory.");
|
||||
|
||||
#(2 * CLK_PERIOD);
|
||||
enable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
// Send read command 0x03.
|
||||
$display("--- tc_read_mem: Sending 0x03 command.");
|
||||
xfer_byte(8'h03, rx_byte);
|
||||
|
||||
// Send adress 0x000000.
|
||||
$display("--- tc_read_mem: Sending 24 bit address 0x000000.");
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
|
||||
// Read out 16 bytes.
|
||||
$display("--- tc_read_mem: Reading out 16 bytes from the memory.");
|
||||
for (i = 1 ; i < 17 ; i = i + 1) begin
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
$display("--- tc_read_mem: Byte %d: 0x%02x", i, rx_byte);
|
||||
end
|
||||
|
||||
disable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
$display("--- tc_read_mem: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // tc_read_mem
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// tc_rmr_mem()
|
||||
//
|
||||
// Test case that reads out the first 16 bytes of the memory,
|
||||
// erase the same area, reads out the contents again, writes
|
||||
// a known pattern and the reads it out again.
|
||||
//----------------------------------------------------------------
|
||||
task tc_rmr_mem;
|
||||
begin : tc_get_id
|
||||
reg [7 : 0] rx_byte;
|
||||
integer i;
|
||||
tc_ctr = tc_ctr + 1;
|
||||
monitor = 0;
|
||||
verbose = 0;
|
||||
|
||||
$display("");
|
||||
$display("--- tc_rmr_mem: Read out the first 16 bytes from the memory.");
|
||||
read_mem_range(24'h000000, 16);
|
||||
|
||||
$display("");
|
||||
$display("--- tc_rmr_mem: Status before write enable:");
|
||||
read_status();
|
||||
|
||||
// Set write enable mode.
|
||||
enable_spi();
|
||||
// #(2 * CLK_PERIOD);
|
||||
xfer_byte(8'h06, rx_byte);
|
||||
// #(2 * CLK_PERIOD);
|
||||
disable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
$display("--- tc_rmr_mem: Status after write enable:");
|
||||
read_status();
|
||||
|
||||
// Erase sector. Command 0x20 followed by 24 bit address.
|
||||
enable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
xfer_byte(8'h20, rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
xfer_byte(8'h00, rx_byte);
|
||||
disable_spi();
|
||||
#(4096 * CLK_PERIOD);
|
||||
$display("--- tc_rmr_mem: Content of memory after erase.");
|
||||
read_mem_range(24'h000000, 16);
|
||||
|
||||
disable_spi();
|
||||
#(2 * CLK_PERIOD);
|
||||
|
||||
$display("--- tc_rmr_mem: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // tc_rmr_mem
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// tk1_spi_master_test
|
||||
//----------------------------------------------------------------
|
||||
initial
|
||||
begin : tk1_spi_master_test
|
||||
$display("");
|
||||
$display(" -= Testbench for tk1_spi_master started =-");
|
||||
$display(" =======================================");
|
||||
$display("");
|
||||
|
||||
init_sim();
|
||||
reset_dut();
|
||||
disable_spi();
|
||||
|
||||
verbose = 1;
|
||||
|
||||
// tc_get_device_id();
|
||||
tc_get_jedec_id();
|
||||
// tc_get_manufacturer_id();
|
||||
tc_get_unique_device_id();
|
||||
tc_read_mem();
|
||||
// tc_rmr_mem();
|
||||
|
||||
display_test_result();
|
||||
$display("");
|
||||
$display(" -= Testbench for tk1_spi_master completed =-");
|
||||
$display(" =========================================");
|
||||
$display("");
|
||||
$finish;
|
||||
end // tk1_spi_master_test
|
||||
endmodule // tb_tk1_spi_master
|
||||
|
||||
//======================================================================
|
||||
// EOF tb_tk1_spi_master.v
|
||||
//======================================================================
|
@ -11,9 +11,13 @@
|
||||
#
|
||||
#===================================================================
|
||||
|
||||
TOP_SRC=../rtl/tk1.v
|
||||
SPI_SRC=../rtl/tk1_spi_master.v
|
||||
TB_SPI_SRC =../tb/tb_tk1_spi_master.v
|
||||
MEM_MODEL_SRC =../tb/W25Q80DL.v
|
||||
|
||||
TOP_SRC=../rtl/tk1.v $(SPI_SRC)
|
||||
TB_TOP_SRC =../tb/tb_tk1.v ../tb/sb_rgba_drv.v ../tb/udi_rom_sim.v
|
||||
LINT_SRC=../rtl/tk1.v ../tb/sb_rgba_drv.v ../tb/udi_rom_sim.v
|
||||
LINT_SRC=$(TOP_SRC) ../tb/sb_rgba_drv.v ../tb/udi_rom_sim.v
|
||||
|
||||
CC = iverilog
|
||||
CC_FLAGS = -Wall
|
||||
@ -22,11 +26,23 @@ LINT = verilator
|
||||
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
|
||||
|
||||
|
||||
all: top.sim
|
||||
all: MEM.TXT spi.sim top.sim
|
||||
|
||||
|
||||
MEM.TXT:
|
||||
../tools/mem_gen.py > MEM.TXT
|
||||
|
||||
|
||||
spi.sim: $(TB_SPI_SRC) $(SPI_SRC) $(MEM_MODEL_SRC)
|
||||
$(CC) $(CC_FLAGS) -o spi.sim $^
|
||||
|
||||
|
||||
top.sim: $(TB_TOP_SRC) $(TOP_SRC)
|
||||
$(CC) $(CC_FLAGS) -o top.sim $(TB_TOP_SRC) $(TOP_SRC) -DUDI_HEX=\"../tb/udi.hex\"
|
||||
$(CC) $(CC_FLAGS) -o top.sim $^ -DUDI_HEX=\"../tb/udi.hex\" -DINCLUDE_SPI_MASTER
|
||||
|
||||
|
||||
sim-spi: spi.sim
|
||||
./spi.sim
|
||||
|
||||
|
||||
sim-top: top.sim
|
||||
@ -34,22 +50,21 @@ sim-top: top.sim
|
||||
|
||||
|
||||
lint-top: $(LINT_SRC)
|
||||
$(LINT) $(LINT_FLAGS) $(LINT_SRC)
|
||||
|
||||
|
||||
lint-spi: $(SPI_SRC)
|
||||
$(LINT) $(LINT_FLAGS) $^
|
||||
$(LINT) $(LINT_FLAGS) $^ -DUDI_HEX=\"../tb/udi.hex\" -DINCLUDE_SPI_MASTER
|
||||
|
||||
|
||||
clean:
|
||||
rm -f spi.sim
|
||||
rm -f top.sim
|
||||
|
||||
rm -f MEM.TXT
|
||||
|
||||
help:
|
||||
@echo "Build system for simulation of TK1 core"
|
||||
@echo ""
|
||||
@echo "Supported targets:"
|
||||
@echo "------------------"
|
||||
@echo "spi.sim: Build SPI simulation target."
|
||||
@echo "sim-spi: Run SPI simulation."
|
||||
@echo "top.sim: Build top level simulation target."
|
||||
@echo "sim-top: Run top level simulation."
|
||||
@echo "lint-top: Lint top rtl source files."
|
||||
|
19
hw/application_fpga/core/tk1/tools/mem_gen.py
Executable file
19
hw/application_fpga/core/tk1/tools/mem_gen.py
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#=======================================================================
|
||||
#
|
||||
# mem_gen.py
|
||||
# ------
|
||||
# Program that generates hex memory file read by the memory model.
|
||||
#
|
||||
# Copyright (C) 2024 - Tillitis AB
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
#=======================================================================
|
||||
|
||||
# print("// Memory data loaded into the module at init.")
|
||||
for i in range(int(16793600 / 4)):
|
||||
print("de")
|
||||
print("ad")
|
||||
print("be")
|
||||
print("ef")
|
Loading…
Reference in New Issue
Block a user