[spi_device] Revise Upload Pre DV to test payload > 256B

This commit revises the pre_dv upload direct testcase to test the
payload greater than 256B.

Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/hw/ip/spi_device/pre_dv/tb/spid_common.sv b/hw/ip/spi_device/pre_dv/tb/spid_common.sv
index e79d69b..35dd100 100644
--- a/hw/ip/spi_device/pre_dv/tb/spid_common.sv
+++ b/hw/ip/spi_device/pre_dv/tb/spid_common.sv
@@ -494,6 +494,9 @@
     8'h 11  // Write Status 3
   };
 
+  parameter int unsigned OffsetW = $clog2(SramStrbW);
+  parameter int unsigned PayloadByte = SramPayloadDepth * (SramDw/8);
+
   // spi_transaction: Send/ Receive data using data fifo.
   task automatic spi_transaction(
     virtual spi_if.tb sif,
diff --git a/hw/ip/spi_device/pre_dv/tb/spid_upload_tb.sv b/hw/ip/spi_device/pre_dv/tb/spid_upload_tb.sv
index cb9aebc..f7ae984 100644
--- a/hw/ip/spi_device/pre_dv/tb/spid_upload_tb.sv
+++ b/hw/ip/spi_device/pre_dv/tb/spid_upload_tb.sv
@@ -139,10 +139,10 @@
   logic [31:0] addrfifo_rdata;
   logic cmdfifo_notempty, addrfifo_notempty;
   logic payload_overflow;
-  logic [           $clog2(SramCmdFifoDepth+1)-1:0] cmdfifo_depth;
-  logic [          $clog2(SramAddrFifoDepth+1)-1:0] addrfifo_depth;
-  logic [$clog2(SramPayloadDepth*(SramDw/8)+1)-1:0] payload_depth;
-  logic [  $clog2(SramPayloadDepth*(SramDw/8))-1:0] payload_start_idx;
+  logic [ $clog2(SramCmdFifoDepth+1)-1:0] cmdfifo_depth;
+  logic [$clog2(SramAddrFifoDepth+1)-1:0] addrfifo_depth;
+  logic [      $clog2(PayloadByte+1)-1:0] payload_depth;
+  logic [        $clog2(PayloadByte)-1:0] payload_start_idx;
 
   // Upload module signals
   logic cfg_addr_4b_en;
@@ -171,7 +171,7 @@
 
     fork
       begin
-        #20us
+        #300us
         $display("TEST TIMED OUT!!");
         $finish();
       end
@@ -183,6 +183,10 @@
   end
 
   static task host();
+    //  Prep data
+    automatic logic [7:0] payload [$];
+    automatic int unsigned payload_bytes;
+
     // Wait
     #200ns
 
@@ -217,7 +221,71 @@
 
     // Cmd & Payload : Write Status
 
-    #300ns
+    // Cmd & Addr & Payload : less than 256B
+    repeat (100) @(sck_clk.cbn);
+    for (int i = 0 ; i < 255 ; i++) begin
+      payload[i] = i;
+    end
+    spiflash_program(
+      sif.tb,
+      8'h 02,         // opcode
+      32'h 00AB_CDEF, // addr
+      1'b 0,          // addr_4b_en
+      payload
+    );
+    payload = {};
+    
+    repeat(256) @(sck_clk.cbn); // Wait payload size (4clk per word read?)
+
+    // Cmd & Addr & Payload : equal to 256B
+    for (int i = 0 ; i < 256 ; i++) begin
+      payload[i] = i;
+    end
+    spiflash_program(
+      sif.tb,
+      8'h 02,         // opcode
+      32'h 00_0000, // addr
+      1'b 0,          // addr_4b_en
+      payload
+    );
+    payload = {};
+    
+    repeat(256) @(sck_clk.cbn); // Wait payload size (4clk per word read?)
+
+    // Cmd & Addr & Payload : 256B < x <= 512B
+    payload_bytes = $urandom_range(512, 257);
+    for (int i = 0 ; i < payload_bytes; i++ ) begin
+      payload[i] = i % PayloadByte;
+    end
+    spiflash_program(
+      sif.tb,
+      8'h 02,         // opcode
+      32'h 00_0000, // addr
+      1'b 0,          // addr_4b_en
+      payload
+    );
+    payload = {};
+    
+    repeat(payload_bytes) @(sck_clk.cbn); // Wait payload size (4clk per word read?)
+
+    // Cmd & Addr & Payload : greater than 512B
+    payload_bytes = $urandom_range(1024, 513);
+    for (int i = 0 ; i < payload_bytes; i++ ) begin
+      payload[i] = i % PayloadByte ^ 8'(i/PayloadByte) ;
+    end
+    spiflash_program(
+      sif.tb,
+      8'h 02,         // opcode
+      32'h 00_0000, // addr
+      1'b 0,          // addr_4b_en
+      payload
+    );
+    payload = {};
+    
+    repeat(payload_bytes) @(sck_clk.cbn); // Wait payload size (4clk per word read?)
+
+   
+    #10us // Wait enough for SW to pop
     @(sck_clk.cbn);
   endtask : host
 
@@ -285,15 +353,27 @@
           repeat (5) @(posedge clk);
 
           // fetch payload buffer
-          read_sram(sw_l2m, sw_m2l,
-            SramPayloadIdx, payload_depth, payload);
+          if (payload_overflow) begin
+            $display("Payload Overflow: Read from offset and max depth(%d)", payload_depth);
+            $display("  Start Addr: 'h %8X",
+                     SramPayloadIdx + (payload_start_idx >> OffsetW));
+            read_sram_wrap(sw_l2m, sw_m2l,
+              SramPayloadIdx,
+              PayloadByte,
+              SramPayloadIdx + (payload_start_idx >> OffsetW),
+              payload_start_idx[0+:OffsetW],
+              payload_depth,
+              payload);
+          end else begin
+            assert(payload_start_idx == '0);
+            read_sram(sw_l2m, sw_m2l,
+              SramPayloadIdx, payload_depth, payload);
+          end
         end
 
       endcase
     end
 
-
-    forever @(posedge clk); // Wait host transaction done
   endtask : sw
 
   // CSb pulse
@@ -407,7 +487,7 @@
     .sys_cmdfifo_depth_o     (cmdfifo_depth),
     .sys_addrfifo_depth_o    (addrfifo_depth),
     .sys_payload_depth_o     (payload_depth),
-    .sys_payload_start_idx_o (payload_start_idx),
+    .sys_payload_start_idx_o (payload_start_idx)
   );
 
   spi_cmdparse cmdparse (
@@ -575,4 +655,81 @@
     data = result;
   endtask : read_sram
 
+  static task read_sram_wrap(
+    ref       sram_l2m_t      l2m,
+    const ref sram_m2l_t      m2l,
+    input logic [SramAw-1:0]  BaseAddr, // Buffer Base Address
+    input int                 MaxSize,  // Max buffer size (in bytes)
+    input logic [SramAw-1:0]  addr,
+    input logic [OffsetW-1:0] offset,
+    input int unsigned        size,     // in byte
+    output logic [7:0]        data [$]
+  );
+    automatic logic [7:0] result    [$];
+    automatic logic [7:0] sram_data [$];
+    automatic logic [SramAw-1:0]  current_addr;
+    automatic logic [OffsetW-1:0] current_offset;
+    automatic int                 remained_bytes;
+    automatic int                 request_bytes; // sram request bytes
+
+    // Check if wrap
+    automatic bit wrap = (({BaseAddr, {OffsetW{1'b0}}} + MaxSize)
+                       > ({addr, offset} + size)) ? 1'b 1 : 1'b 0;
+
+    if (wrap) begin
+      $display("Overflow: Read will be twice");
+    end
+    //  don't wrap: just read. loop depends on the offset, size
+    //
+    //  wrap: first:  (2*size - MaxSize) bytes
+    //        second: (MaxSize - size)   bytes
+    current_addr   = addr;
+    current_offset = offset;
+    remained_bytes = size;
+
+    do begin
+      $display("Transaction: CurAddr('h%X) / CurOffset('h%X) / RemainedByte('d%3d)",
+               current_addr, current_offset, remained_bytes);
+      // start addr of current transaction
+
+      // end addr of current transaction
+      if (({BaseAddr, {OffsetW{1'b0}}} + MaxSize) < ({current_addr, current_offset} + remained_bytes)) begin
+        // Read to the end of the buffer
+        request_bytes = MaxSize - (current_addr - BaseAddr)*(SramDw/8);
+      end else begin
+        // Request only remained bytes
+        request_bytes = remained_bytes;
+      end
+
+      // request SRAM read
+      $display("Sending SRAM request");
+      read_sram(l2m, m2l, current_addr, request_bytes, sram_data);
+
+      // push to result (based on current_offset, currnt_size)
+      $display("Pushing the return data(from SRAM) into the result queue");
+      data = {data, sram_data[current_offset:$]}; // push back the sram read
+      
+      // start addr of next transaction
+      $display("Calculating for the next SRAM transaction");
+      remained_bytes = remained_bytes - (request_bytes - current_offset);
+      current_offset = '0; // always word based for the next transaction
+      current_addr = BaseAddr; // always read from the first entry of buffer
+
+      sram_data = {}; // Delete all
+
+      if (remained_bytes == 0) begin
+        $display("All payloads are read out.");
+      end else begin
+        $display("Still pending bytes ('d%3d). Requesting the next transaction",
+          remained_bytes);
+      end
+    end while (remained_bytes != 0);
+
+
+    // Check the # entires per transaction
+    // first entry, addr
+    // last entry,  ceil({addr,offset} + size)/(SramDw/8)
+
+  endtask : read_sram_wrap
+
 endmodule : spid_upload_tb