diff --git a/target/rtl/test/spi_tb.sv b/target/rtl/test/spi_tb.sv index e2178e57..7ea817c3 100644 --- a/target/rtl/test/spi_tb.sv +++ b/target/rtl/test/spi_tb.sv @@ -1,3 +1,7 @@ +`define SEEK_SET 0 +`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 @@ -27,10 +31,10 @@ task automatic spi_read(input logic [31:0] addr, input integer length); end @(posedge spis_sck_i); - spis_csb_i = 1; // Bring CSB high to end the transaction + spis_csb_i = 1; // Bring CSB high to end the transaction #1us; // Wait for a clock edge to align @(posedge spis_sck_i); - spis_csb_i = 0; // Bring CSB high to end the transaction + spis_csb_i = 0; // Bring CSB high to end the transaction // Set the SPI Read MEM code cmd = 8'hB; @@ -91,3 +95,115 @@ task automatic spi_read(input logic [31:0] addr, input integer length); @(negedge spis_sck_i); spis_csb_i = 1; endtask + + +task automatic spi_write(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; + 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; + + // Wait for a clock edge to align + @(posedge spis_sck_i); + spis_csb_i = 0; + + // Switch SPI to Quad SPI mode + cmd = 8'h1; + for (i = 7; i >= 0; i--) begin + @(negedge spis_sck_i); + spis_sd_i[0] = cmd[i]; // Send 1 bit at a time on MOSI + end + // Enable Quad SPI mode by writing 0x01 to the status register + for (i = 7; i >= 0; i--) begin + @(negedge spis_sck_i); + spis_sd_i[0] = cmd[i]; // Send 1 bit at a time on MOSI + end + + @(posedge spis_sck_i); + spis_csb_i = 1; // Bring CSB high to end the transaction + #1us; // Wait for a clock edge to align + @(posedge spis_sck_i); + spis_csb_i = 0; // Bring CSB high to end the transaction + + // 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); + 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 + + // Send the 32-bit address over 4 data lines (8 clock cycles) + for (i = 31; i >= 0; i -= 4) begin + @(negedge spis_sck_i); + 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 + + @(negedge spis_sck_i); // Wait for last data to be sent + + + // Insert dummy cycles if required (e.g., 32 cycles) + // This is the bug of ETH: @spi_slave_rx.sv, the counter count one more 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"); + if (file == 0) begin + $display("Error: Could not open file %s", path); + return; + end + $fseek(file, 0, `SEEK_END); + file_size = $ftell(file); + $fseek(file, 0, `SEEK_SET); + + // Read the file in chunks of 4 bytes + for (i = 0; i < file_size; i = i + 1) begin + reg [7:0] byte_data; + byte_data = $fgetc(file); + + for (j = 7; j >= 0; j -= 4) begin + @(posedge spis_sck_i); + if (j >= 3) begin + mosi_data = byte_data[j-:4]; + end else begin + // For j = 3 to 0 + mosi_data = byte_data[3:0] << (3 - j); + end + spis_sd_i = mosi_data; // Drive data lines + end + end + $fclose(file); + $display("Wrote %0d bytes to address %h", file_size, addr); + @(negedge spis_sck_i); + + // Bring CSB high to end the transaction + spis_csb_i = 1; + force i_occamy.rst_ni = 0; // Force reset the chip + #10ns; + release i_occamy.rst_ni; // Release reset +endtask diff --git a/target/rtl/test/testharness.sv.tpl b/target/rtl/test/testharness.sv.tpl index 0881df06..daf05e06 100644 --- a/target/rtl/test/testharness.sv.tpl +++ b/target/rtl/test/testharness.sv.tpl @@ -45,12 +45,15 @@ module testharness import occamy_pkg::*; ( logic [3:0] spis_sd_en_o; logic [3:0] spis_sd_i = '1; - // Inject the signals into SPI device - `include "spi_tb.sv" - initial begin - #1us; - spi_read(32'h80000000, 128); - end + `ifndef TARGET_VSIM + // Inject the signals into SPI device + `include "spi_tb.sv" + initial begin + #10us; + // spi_read(32'h80000000, 128); + spi_write("app.bin", 32'h80000000); + end + `endif <%def name="tb_memory(bus, name)"> ${bus.req_type()} ${name}_req;