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
|
*.net
|
||||||
*.dsn
|
*.dsn
|
||||||
*.ses
|
*.ses
|
||||||
|
|
||||||
__pycache__
|
__pycache__
|
||||||
application_fpga_par.json
|
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
|
The core is implemented as a single module. Future versions will
|
||||||
probably be separated into separate modules.
|
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_FIRST = 8'h61;
|
||||||
localparam ADDR_CPU_MON_LAST = 8'h62;
|
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.
|
// Register and Wire declarations.
|
||||||
@ -89,6 +93,11 @@ module tb_tk1();
|
|||||||
wire tb_gpio3;
|
wire tb_gpio3;
|
||||||
wire tb_gpio4;
|
wire tb_gpio4;
|
||||||
|
|
||||||
|
wire tb_spi_ss;
|
||||||
|
wire tb_spi_sck;
|
||||||
|
wire tb_spi_mosi;
|
||||||
|
wire tb_spi_miso;
|
||||||
|
|
||||||
reg tb_cs;
|
reg tb_cs;
|
||||||
reg tb_we;
|
reg tb_we;
|
||||||
reg [7 : 0] tb_address;
|
reg [7 : 0] tb_address;
|
||||||
@ -96,6 +105,12 @@ module tb_tk1();
|
|||||||
wire [31 : 0] tb_read_data;
|
wire [31 : 0] tb_read_data;
|
||||||
wire tb_ready;
|
wire tb_ready;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Continuous assignments.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Inverted loopback of SPI data lines.
|
||||||
|
assign tb_spi_miso = ~tb_spi_mosi;
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Device Under Test.
|
// Device Under Test.
|
||||||
@ -124,6 +139,11 @@ module tb_tk1();
|
|||||||
.gpio3(tb_gpio3),
|
.gpio3(tb_gpio3),
|
||||||
.gpio4(tb_gpio4),
|
.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),
|
.cs(tb_cs),
|
||||||
.we(tb_we),
|
.we(tb_we),
|
||||||
.address(tb_address),
|
.address(tb_address),
|
||||||
@ -614,7 +634,38 @@ module tb_tk1();
|
|||||||
$display("--- test9: completed.");
|
$display("--- test9: completed.");
|
||||||
$display("");
|
$display("");
|
||||||
end
|
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();
|
test7();
|
||||||
test8();
|
test8();
|
||||||
test9();
|
test9();
|
||||||
|
test9();
|
||||||
|
test10();
|
||||||
|
|
||||||
display_test_result();
|
display_test_result();
|
||||||
$display("");
|
$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
|
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 = iverilog
|
||||||
CC_FLAGS = -Wall
|
CC_FLAGS = -Wall
|
||||||
@ -22,11 +26,23 @@ LINT = verilator
|
|||||||
LINT_FLAGS = +1364-2005ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME
|
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)
|
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
|
sim-top: top.sim
|
||||||
@ -34,22 +50,21 @@ sim-top: top.sim
|
|||||||
|
|
||||||
|
|
||||||
lint-top: $(LINT_SRC)
|
lint-top: $(LINT_SRC)
|
||||||
$(LINT) $(LINT_FLAGS) $(LINT_SRC)
|
$(LINT) $(LINT_FLAGS) $^ -DUDI_HEX=\"../tb/udi.hex\" -DINCLUDE_SPI_MASTER
|
||||||
|
|
||||||
|
|
||||||
lint-spi: $(SPI_SRC)
|
|
||||||
$(LINT) $(LINT_FLAGS) $^
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
rm -f spi.sim
|
||||||
rm -f top.sim
|
rm -f top.sim
|
||||||
|
rm -f MEM.TXT
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Build system for simulation of TK1 core"
|
@echo "Build system for simulation of TK1 core"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Supported targets:"
|
@echo "Supported targets:"
|
||||||
@echo "------------------"
|
@echo "------------------"
|
||||||
|
@echo "spi.sim: Build SPI simulation target."
|
||||||
|
@echo "sim-spi: Run SPI simulation."
|
||||||
@echo "top.sim: Build top level simulation target."
|
@echo "top.sim: Build top level simulation target."
|
||||||
@echo "sim-top: Run top level simulation."
|
@echo "sim-top: Run top level simulation."
|
||||||
@echo "lint-top: Lint top rtl source files."
|
@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