From 15a0f007a28c0222dc4c52d8a34be3a65410be19 Mon Sep 17 00:00:00 2001 From: Yunhao Deng Date: Tue, 15 Oct 2024 09:47:02 +0200 Subject: [PATCH] Update SPI Testbench to support multiple read / write demands (#64) --- target/rtl/test/spi_tb.sv | 119 +++++++++++++++++++---------- target/rtl/test/testharness.sv.tpl | 15 +++- 2 files changed, 92 insertions(+), 42 deletions(-) diff --git a/target/rtl/test/spi_tb.sv b/target/rtl/test/spi_tb.sv index e83a1c21..e6ca7ad7 100644 --- a/target/rtl/test/spi_tb.sv +++ b/target/rtl/test/spi_tb.sv @@ -2,17 +2,9 @@ `define SEEK_CUR 1 `define SEEK_END 2 -task automatic spi_read(input logic [31:0] addr, input integer length); - // Inputs: - // addr - 32-bit Address to read from - // length - Number of bytes to read - // Output: - // data - Array to store read data - - reg [7:0] cmd; // SPI read command code - integer i, j, k; - reg [3:0] mosi_data; // Data to send over SPI (master out) - reg [3:0] miso_data; // Data received from SPI (slave out) +task automatic spi_init(); + reg [7:0] cmd; // SPI command code + integer i; // Wait for a clock edge to align @(posedge spis_sck_i); @@ -32,7 +24,22 @@ task automatic spi_read(input logic [31:0] addr, input integer length); @(posedge spis_sck_i); spis_csb_i = 1; // Bring CSB high to end the transaction - #1us; // Wait for a clock edge to align + +endtask + +task automatic spi_read(input integer length, input logic [31:0] addr); + // Inputs: + // addr - 32-bit Address to read from + // length - Number of bytes to read + // Output: + // data - Array to store read data + + reg [7:0] cmd; // SPI read command code + integer i, j, k; + reg [3:0] mosi_data; // Data to send over SPI (master out) + reg [3:0] miso_data; // Data received from SPI (slave out) + + // Wait for a clock edge to align @(posedge spis_sck_i); spis_csb_i = 0; // Bring CSB high to end the transaction @@ -102,39 +109,80 @@ task automatic spi_read(input logic [31:0] addr, input integer length); spis_csb_i = 1; endtask +task automatic spi_read_u32(input logic [31:0] addr); + spi_read(4, addr); +endtask -task automatic spi_write(input string path, input logic [31:0] addr); +task automatic spi_write_u32(input logic [31:0] data, input logic [31:0] addr); // Inputs: - // path - Path to the file to write - // addr - 32-bit Address to read from + // data - 8-bit data to write + // addr - 32-bit Address to write to reg [7:0] cmd; // SPI write command code - integer i, j, k; + integer i, j; reg [3:0] mosi_data; // Data to send over SPI (master out) - reg [3:0] miso_data; // Data received from SPI (slave out) - integer file; - integer file_size; - // Start to load binaries from file // Wait for a clock edge to align @(posedge spis_sck_i); - spis_csb_i = 0; + spis_csb_i = 0; // Bring CSB high to end the transaction - // Switch SPI to Quad SPI mode - cmd = 8'h1; - for (i = 7; i >= 0; i--) begin + // Set the SPI Write MEM code + cmd = 8'h2; + + // Send the command code (8 bits) over 4 data lines (2 clock cycles) + for (i = 7; i >= 0; i -= 4) begin @(negedge spis_sck_i); - spis_sd_i[0] = cmd[i]; // Send 1 bit at a time on MOSI + if (i >= 3) begin + mosi_data = cmd[i-:4]; + end else begin + // For i = 3 to 0 + mosi_data = cmd[3:0]; + mosi_data = mosi_data << (3 - i); // Left-align to 4 bits + end + spis_sd_i = mosi_data; // Drive data lines end - // Enable Quad SPI mode by writing 0x01 to the status register - for (i = 7; i >= 0; i--) begin + + // Send the 32-bit address over 4 data lines (8 clock cycles) + for (i = 31; i >= 0; i -= 4) begin @(negedge spis_sck_i); - spis_sd_i[0] = cmd[i]; // Send 1 bit at a time on MOSI + if (i >= 3) begin + mosi_data = addr[i-:4]; + end else begin + // For i = 3 to 0 + mosi_data = addr[3:0]; + mosi_data = mosi_data << (3 - i); // Left-align to 4 bits + end + spis_sd_i = mosi_data; // Drive data lines end - @(posedge spis_sck_i); - spis_csb_i = 1; // Bring CSB high to end the transaction - #1us; // Wait for a clock edge to align + // Send the 32-bit data over 4 data lines (8 clock cycles) + for (i = 31; i >= 0; i -= 4) begin + @(negedge spis_sck_i); + mosi_data = data[i-:4]; + spis_sd_i = mosi_data; // Drive data lines + + end + $display("Wrote to address %h finished", addr); + @(negedge spis_sck_i); + + // Bring CSB high to end the transaction + spis_csb_i = 1; +endtask + +task automatic spi_write_image(input string path, input logic [31:0] addr); + // Inputs: + // path - Path to the file to write + // addr - 32-bit Address to read from + + reg [7:0] cmd; // SPI write command code + integer i, j, k; + reg [3:0] mosi_data; // Data to send over SPI (master out) + reg [3:0] miso_data; // Data received from SPI (slave out) + integer file; + integer file_size; + + // Start to load binaries from file + // Wait for a clock edge to align @(posedge spis_sck_i); spis_csb_i = 0; // Bring CSB high to end the transaction @@ -167,15 +215,6 @@ task automatic spi_write(input string path, input logic [31:0] addr); spis_sd_i = mosi_data; // Drive data lines end - // @(negedge spis_sck_i); // Wait for last data to be sent - - // Insert dummy cycles if required (e.g., 32 cycles) - // Write process seems not need dummy cycles - // for (i = 0; i <= 32; i = i + 1) begin - // @(posedge spis_sck_i); - // // Do nothing, just wait - // end - // Now write the data to the slave // Open the file for reading and get the size of the file file = $fopen(path, "r"); diff --git a/target/rtl/test/testharness.sv.tpl b/target/rtl/test/testharness.sv.tpl index 350dcc48..0bd642bc 100644 --- a/target/rtl/test/testharness.sv.tpl +++ b/target/rtl/test/testharness.sv.tpl @@ -50,8 +50,19 @@ module testharness import occamy_pkg::*; ( `include "spi_tb.sv" initial begin #10us; - // spi_read(32'h80000000, 128); - // spi_write("app.bin", 32'h80000000); + // spi_init(); + // #1us; + // spi_read(128, 32'h80000000); + // #1us; + // spi_write_u32('0, 32'h80000300); + // #1us; + // spi_read_u32(32'h80000300); + // #1us; + // spi_write_u32(32'hABCDEF00, 32'h80000300); + // #1us; + // spi_read_u32(32'h80000300); + // #1us; + // spi_write_image("app.bin", 32'h80000000); #1us; end `endif