[spi_device] Re-write SRAM access in Readcmd

This commit re-writes the SRAM access logic in `spi_readcmd` module. It
is split into a new submodule `spid_readsram`. The logic receives
a request from the Read command FSM and fills the internal FIFO for the
Read command logic to return the data through SPI lines.

Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/hw/ip/spi_device/lint/spi_device.waiver b/hw/ip/spi_device/lint/spi_device.waiver
index dfd06fd..a89b32a 100644
--- a/hw/ip/spi_device/lint/spi_device.waiver
+++ b/hw/ip/spi_device/lint/spi_device.waiver
@@ -10,6 +10,9 @@
 waive -rules {ARITH_CONTEXT} -location {spi_readcmd.sv} \
       -regexp {'addr_q\[31:2\] \+ 1'b1' is self-determined} \
       -comment "Leave it as it is for readability"
+waive -rules {ARITH_CONTEXT} -location {spid_readsram.sv} \
+      -regexp {'current_address_i\[31:2\] \+ 1'b1' is self-deter} \
+      -comment "Leave it as it is for readability"
 
 waive -rules HIER_NET_NOT_READ -location {spi_device.sv} -regexp {[nN]et.*a_(address|param|user).*not read from} \
       -comment "several TLUL signals are not used by register file"
diff --git a/hw/ip/spi_device/rtl/spi_readcmd.sv b/hw/ip/spi_device/rtl/spi_readcmd.sv
index dc6648e..ce3f6f9 100644
--- a/hw/ip/spi_device/rtl/spi_readcmd.sv
+++ b/hw/ip/spi_device/rtl/spi_readcmd.sv
@@ -276,7 +276,7 @@
   /////////////
 
   // Address shift & latch
-  logic addr_ready_in_word;
+  logic addr_ready_in_word, addr_ready_in_halfword;
   logic addr_latched;
   logic addr_shift_en;
   logic addr_latch_en;
@@ -320,17 +320,12 @@
   // bit count within a word
   logic bitcnt_update;
   logic bitcnt_dec;
-  logic [4:0] bitcnt; // count down from 31 or partial for first unaligned
+  logic [2:0] bitcnt; // count down from 7 or partial for first unaligned
 
   // FIFO
   logic unused_fifo_rvalid, fifo_pop;
-  sram_data_t fifo_rdata;
+  spi_byte_t fifo_rdata;
 
-  // offset_update: latch addr_d[1:0] into fifo_byteoffset when the statemachine
-  // moves to Output stage.
-  logic       offset_update;
-  logic [1:0] fifo_byteoffset; // the byte position in SRAM word
-  logic [7:0] fifo_byte [4]; // converting word sram data into a SPI byte
   logic [7:0] p2s_byte;
   logic       p2s_valid_inclk;
 
@@ -370,18 +365,23 @@
     if (addr_ready_in_word) begin
       // Return word based address, but should not latch
       addr_d = {addr_q[31:8], s2p_byte_i[5:0], 2'b00};
+    end else if (addr_ready_in_halfword) begin
+      // When addr is a cycle earlier than full addr, sram req sent in
+      // spid_readsram
+      addr_d = {addr_q[31:8], s2p_byte_i[6:0], 1'b 0};
     end else if (addr_shift_en && s2p_valid_i) begin
       // Latch
       addr_d = {addr_q[23:0], s2p_byte_i[7:0]};
       addr_latch_en = 1'b 1;
     end else if (addr_inc) begin
       // Increase the address to next
-      addr_d = {addr_q[31:2] + 1'b1, 2'b00};
+      addr_d = addr_q[31:0] + 1'b1;
       addr_latch_en = 1'b 1;
     end
   end
 
-  assign addr_ready_in_word = (addr_cnt_d == 5'd 2);
+  assign addr_ready_in_word     = (addr_cnt_d == 5'd 2);
+  assign addr_ready_in_halfword = (addr_cnt_d == 5'd 1);
 
   // TODO: Check if addr_cnt_d or addr_cnt_q ?
   assign addr_latched = (addr_cnt_d == 5'd 0);
@@ -406,6 +406,8 @@
       addr_cnt_d = (cmd_info_i.addr_4b_affected && addr_4b_en_i) ? 5'd 30 : 5'd 22;
 
       // TODO: Dual IO/ Quad IO case
+
+      // TODO: Force 4B mode
     end else if (addr_cnt_q == '0) begin
       addr_cnt_d = addr_cnt_q;
     end else if (addr_shift_en) begin
@@ -432,15 +434,19 @@
     if (!rst_ni) begin
       bitcnt <= '0;
     end else if (bitcnt_update) begin
-      unique case (addr_d[1:0])
-        2'b 00: bitcnt <= 5'h 1f;
-        2'b 01: bitcnt <= 5'h 17;
-        2'b 10: bitcnt <= 5'h 0f;
-        2'b 11: bitcnt <= 5'h 07;
-        default: bitcnt <= 5'h 1f;
+      unique case (cmd_info_i.payload_en)
+        4'b 0010: bitcnt <= 3'h 7;
+        4'b 0011: bitcnt <= 3'h 6;
+        4'b 1111: bitcnt <= 3'h 4;
+        default:  bitcnt <= 3'h 7;
       endcase
     end else if (bitcnt_dec) begin
-      bitcnt <= bitcnt - 1'b 1;
+      unique case (cmd_info_i.payload_en)
+        4'b 0010: bitcnt <= bitcnt - 3'h 1;
+        4'b 0011: bitcnt <= bitcnt - 3'h 2;
+        4'b 1111: bitcnt <= bitcnt - 3'h 4;
+        default:  bitcnt <= bitcnt - 3'h 1;
+      endcase
     end
   end
 
@@ -451,7 +457,6 @@
   // Convert into masked address
   localparam int unsigned MailboxAw = $clog2(MailboxDepth);
   localparam logic [31:0] MailboxMask = {{30-MailboxAw{1'b1}}, {2+MailboxAw{1'b0}}};
-  localparam int unsigned SfdpAw = $clog2(SfdpDepth);
 
   assign mailbox_masked_addr = addr_d & MailboxMask;
 
@@ -463,47 +468,10 @@
   // manages the address to follow.
 
   logic sram_req;
-  logic [SramAw-1:0] sram_addr;
-
-  always_comb begin
-    sram_addr = '0;
-    if (sel_dp_i == DpReadSFDP) begin
-      // SFDP Read command. Upper address is swapped to SFDP Base Addr
-      sram_addr = SfdpBaseAddr | sram_addr_t'(addr_d[2+:SfdpAw]);
-    end else if (mailbox_en_i && addr_in_mailbox) begin
-      sram_addr = MailboxBaseAddr | sram_addr_t'(addr_d[2+:MailboxAw]);
-    end else begin
-      // Read Buffer Address
-      // TODO: Double buffering
-      sram_addr = ReadBaseAddr | sram_addr_t'({readbuf_idx, addr_d[2+:$clog2(ReadBufferDepth)]});
-    end
-  end
-
-  assign sram_addr_o = sram_addr;
-
-  assign sram_req_o = sram_req;
-  assign sram_we_o = 1'b 0;    // always read
-  assign sram_wdata_o = '0;    // always read
-
   //- END:   SRAM Datapath ----------------------------------------------------
 
   //= BEGIN: FIFO to P2S datapath =============================================
-  assign fifo_byte = '{fifo_rdata.data[7:0],   fifo_rdata.data[15:8],
-                       fifo_rdata.data[23:16], fifo_rdata.data[31:24]};
-  // TODO: addr_inc should not affect this until it is accepted.
-  assign p2s_byte = fifo_byte[fifo_byteoffset];
-
-  // TODO: fifo_byteoffset
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      fifo_byteoffset <= '0;
-    end else if (offset_update) begin
-      fifo_byteoffset <= addr_d[1:0];
-    end else if (p2s_valid_inclk && bitcnt[2:0] == 0) begin
-      // at the MainOutput state, when it sends a byte, increase offset
-      fifo_byteoffset <= fifo_byteoffset + 1'b 1;
-    end
-  end
+  assign p2s_byte = fifo_rdata;
 
   // outclk latch
   // can't put async fifo. DC constraint should have half clk datapath
@@ -571,8 +539,6 @@
     p2s_valid_inclk = 1'b 0;
     fifo_pop        = 1'b 0;
 
-    offset_update = 1'b 0;
-
     bitcnt_update = 1'b 0;
     bitcnt_dec = 1'b 0;
 
@@ -592,8 +558,9 @@
       MainAddress: begin
         addr_shift_en = 1'b 1;
 
+        // TODO: DualIO/ QuadIO case
         if (addr_ready_in_word) begin
-          // TODO: Send Address request. No need to move the state
+          sram_req = 1'b 1;
         end
 
         if (addr_latched) begin
@@ -601,9 +568,6 @@
           // could be 23, 15, or 7
           bitcnt_update = 1'b 1;
 
-          // latch addr_d[1:0] to fifo_byteoffset;
-          offset_update = 1'b 1;
-
           // Next state:
           //  MByte if mbyte enabled
           //  Dummy if mbyte = 0 and dummy_en = 1
@@ -666,14 +630,7 @@
           default:  io_mode_o = SingleIO;
         endcase
 
-        // if 2 bits left, increase the address
-        // TODO: Dual or Quad output I/O handling
-        if (bitcnt == 5'h 2) begin
-          addr_inc = 1'b 1;
-          sram_req = 1'b 1;
-        end
-
-        if (bitcnt == 5'h 0) begin
+        if (bitcnt == 3'h 0) begin
           // sent all words
           bitcnt_update = 1'b 1;
           // TODO: FIFO pop here?
@@ -696,50 +653,42 @@
   // Instances //
   ///////////////
 
-  // FIFO for read data from DPSRAM
-  logic unused_full;
-  logic [1:0] unused_depth;
-  prim_fifo_sync #(
-    .Width             ($bits(sram_data_t)),
-    .Pass              (1'b1),
-    .Depth             (2),
-    .OutputZeroIfEmpty (1'b0)
-  ) u_fifo (
+  spid_readsram #(
+    .ReadBaseAddr    (ReadBaseAddr),
+    .ReadBufferDepth (ReadBufferDepth),
+    .MailboxBaseAddr (MailboxBaseAddr),
+    .MailboxDepth    (MailboxDepth),
+    .SfdpBaseAddr    (SfdpBaseAddr),
+    .SfdpDepth       (SfdpDepth)
+  ) u_readsram (
     .clk_i,
     .rst_ni,
 
-    .clr_i   ( 1'b0),
+    .sram_read_req_i   (sram_req),
+    .addr_latched_i    (addr_latched),
+    .current_address_i (addr_d), // TODO: Change it
 
-    .wvalid_i (sram_rvalid_i),
-    .wready_o (), // not used
-    .wdata_i  (sram_rdata_i),
+    .mailbox_en_i,
+    .mailbox_hit_i (addr_in_mailbox),
+    .sfdp_hit_i    (sel_dp_i == DpReadSFDP),
 
-    .rvalid_o (unused_fifo_rvalid),
-    .rready_i (fifo_pop),
-    .rdata_o  (fifo_rdata),
+    .sram_req_o,
+    .sram_we_o,
+    .sram_addr_o,
+    .sram_wdata_o,
+    .sram_rvalid_i,
+    .sram_rdata_i,
+    .sram_rerror_i,
 
-    .full_o   (unused_full),
-    .depth_o  (unused_depth)
+    // FIFO
+    .fifo_rvalid_o (unused_fifo_rvalid),
+    .fifo_rready_i (fifo_pop),
+    .fifo_rdata_o  (fifo_rdata)
   );
 
-  // TODO: Handle SRAM integrity errors
-  sram_err_t unused_sram_rerror;
-  assign unused_sram_rerror = sram_rerror_i;
-
+  ////////////////
   // Assertions //
-  // FIFO should not overflow. The Main state machine shall send request only
-  // when it needs the data within 2 cycles
-  `ASSERT(NotOverflow_A, sram_req_o && !sram_we_o |-> !unused_full)
-
-  // SRAM access always read
-  `ASSERT(SramReadOnly_A, sram_req_o |-> !sram_we_o)
-
-  // SRAM data should return in next cycle
-  `ASSUME(SramDataReturnRequirement_M, sram_req_o && !sram_we_o |=> sram_rvalid_i)
-
-  // TODO: When main state machine returns data to SPI (via p2s), the FIFO shall
-  // not be empty
-  `ASSERT(NotEmpty_A, p2s_valid_inclk |-> (unused_depth != 0))
+  ////////////////
 
   // `addr_inc` should not be asserted in Address phase
   `ASSERT(AddrIncNotAssertInAddressState_A, addr_inc |-> main_st != MainAddress)
diff --git a/hw/ip/spi_device/rtl/spid_readsram.sv b/hw/ip/spi_device/rtl/spid_readsram.sv
new file mode 100644
index 0000000..9ca420e
--- /dev/null
+++ b/hw/ip/spi_device/rtl/spid_readsram.sv
@@ -0,0 +1,358 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// SPI Device Flash Read command SRAM request/rsp
+
+/*
+  spid_readsram module is a submodule of the read command process block. Its
+  main purpose is to manage the SRAM request address and returning of the data
+  in a spi_byte_t size.
+
+  The sequence is:
+
+  1. read FSM sends the buffer fill request.
+  2. this logic sends the SRAM request based on the current address.
+  3. when it returns, based on the current address, the internal FSM pushes
+     data into the FIFO. It means, the FIFO push happens when addr[0] is
+     received.
+  4. If the available depth becomes 4, the logic increases the address
+     ({current_address_i[31:2] + 1'b 1, 2'b00}) and sends another SRAM read
+     request.
+*/
+`include "prim_assert.sv"
+
+module spid_readsram
+  import spi_device_pkg::*;
+#(
+  // Read command configurations
+  // Base address: Index of DPSRAM
+  // Buffer size: # of indices assigned to Read Buffer.
+  //    This is used to calculate double buffering and threshold.
+  parameter sram_addr_t  ReadBaseAddr    = spi_device_pkg::SramReadBufferIdx,
+  parameter int unsigned ReadBufferDepth = spi_device_pkg::SramMsgDepth,
+
+  // Mailbox Base Addr: Beginning Index of Mailbox in DPSRAM
+  // Mailbox Size: Mailbox buffer size (# of indices)
+  parameter sram_addr_t  MailboxBaseAddr = spi_device_pkg::SramMailboxIdx,
+  parameter int unsigned MailboxDepth    = spi_device_pkg::SramMailboxDepth,
+
+  // SFDP Base Addr: the beginning index of the SFDP region in DPSRAM
+  // SFDP Depth: The size of the SFDP buffer (64 fixed in the spi_device_pkg)
+  parameter sram_addr_t  SfdpBaseAddr    = spi_device_pkg::SramSfdpIdx,
+  parameter int unsigned SfdpDepth       = spi_device_pkg::SramSfdpDepth
+) (
+  input clk_i,      // SCK
+  input rst_ni,     // CSb
+
+  input sram_read_req_i, // from FSM
+
+  // addr_latched_i
+  //        _________ _________
+  // ADDR: X addr[1] X addr[0] >----
+  //             _________
+  // sig:  _____/         \_________
+  input addr_latched_i,  // indicator of addr[1] -> addr[0]
+
+  // current_address_i is the address pointer the byte sent to the host system.
+  // If it is the first request of the command, then the current_address_i is
+  // the latched address field.
+  input [31:0] current_address_i,
+
+  input mailbox_en_i,
+  input mailbox_hit_i, // the received address field hits the mailbox
+  input sfdp_hit_i,    // selected DP is DpReadSFDP
+
+  // SRAM request and response
+  output logic       sram_req_o,
+  output logic       sram_we_o,
+  output sram_addr_t sram_addr_o,
+  output sram_data_t sram_wdata_o,
+  input              sram_rvalid_i,
+  input  sram_data_t sram_rdata_i,
+  input  sram_err_t  sram_rerror_i,
+
+  // FIFO output (spi_byte_t)
+  output logic      fifo_rvalid_o,
+  input             fifo_rready_i,
+  output spi_byte_t fifo_rdata_o
+);
+
+
+  ////////////////
+  // Definition //
+  ////////////////
+
+  // States
+  typedef enum logic [1:0] {
+    StIdle, // Reset state, waits sram_read_req
+    StPush, // With returned data, push the data into spi_byte_t fifo
+    StActive // Now in the middle of the process. Sits here
+  } st_e;
+  st_e st_q, st_d;
+
+  typedef enum logic {
+    AddrInput,     // Received command address
+    AddrContinuous // Continuous Read
+  } addr_sel_e;
+  addr_sel_e addr_sel;
+
+  localparam int unsigned ReadBufAw = $clog2(ReadBufferDepth);
+  localparam int unsigned MailboxAw = $clog2(MailboxDepth);
+  localparam int unsigned SfdpAw    = $clog2(SfdpDepth);
+
+  ////////////
+  // Signal //
+  ////////////
+
+  // State Machine output
+
+  // data_inc: incoming data is word size (sram_data_t).
+  // FIFO size is spi_byte_t. So, only a byte can be pushed to the FIFO at
+  // a time. data_inc to increase the index to next
+  logic data_inc;
+
+  // strb_set: When addr[0] phase, strb_set is 1 (by FSM). This is to latch
+  // the offset of the received address. The offset is used to push to the
+  // FIFO only for the required bytes.
+  logic strb_set;
+  assign strb_set = addr_latched_i;
+
+  logic [31:0] next_address;
+
+  logic sram_req;
+  assign sram_req_o   = sram_req;
+  assign sram_we_o    = 1'b 0;
+  assign sram_wdata_o = '0;
+
+  sram_addr_t sram_addr;
+  assign sram_addr_o = sram_addr;
+
+  sram_data_t sram_data;
+
+  // FIFO
+  logic fifo_wvalid, fifo_wready;
+  spi_byte_t fifo_wdata;
+
+  logic sram_d_valid, sram_d_ready;
+  logic sram_fifo_full;
+  logic unused_sram_depth;
+
+  // Unused
+  logic unused_fifo_full;
+  logic [1:0] unused_fifo_depth;
+
+  logic unused_next_address;
+  assign unused_next_address = ^{next_address[31:$bits(sram_addr_t)+1],next_address[1:0]};
+
+  //////////////
+  // Datapath //
+  //////////////
+
+  logic sram_latched; // sram request sent
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) sram_latched <= 1'b 0;
+    else if (sram_req_o) sram_latched <= 1'b 1;
+  end
+
+  logic [1:0] strb;
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) strb <= 2'b 00;
+    else if (data_inc) strb <= strb + 1'b 1; // Overflow is OK
+    else if (strb_set) strb <= current_address_i[1:0];
+  end
+
+  // fifo_wdata
+  always_comb begin
+    unique case (strb)
+      2'b 00:  fifo_wdata = sram_data.data[ 7: 0];
+      2'b 01:  fifo_wdata = sram_data.data[15: 8];
+      2'b 10:  fifo_wdata = sram_data.data[23:16];
+      2'b 11:  fifo_wdata = sram_data.data[31:24];
+      default: fifo_wdata = '0;
+    endcase
+  end
+
+  // Address calculation
+  assign next_address = (addr_sel == AddrContinuous)
+                      ? {current_address_i[31:2] + 1'b1, 2'b00}
+                      : current_address_i;
+
+  // Sram Address
+  always_comb begin
+    if (sfdp_hit_i) begin
+      sram_addr = SfdpBaseAddr | sram_addr_t'(next_address[2+:SfdpAw]);
+    end else if (mailbox_en_i && mailbox_hit_i) begin
+      sram_addr = MailboxBaseAddr | sram_addr_t'(next_address[2+:MailboxAw]);
+    end else begin
+      sram_addr = ReadBaseAddr | sram_addr_t'(next_address[2+:ReadBufAw]);
+    end
+  end
+
+  ///////////////////
+  // State Machine //
+  ///////////////////
+
+  /*
+       _   _   _   _   _
+  SCK | |_| |_| |_| |_| |_|
+         ___ ___ ___ ___
+  ADDR  X___X___X___X___X
+          3   2   1   0
+           ___
+  S.RE    /   \__________
+               ___
+  S.R.V  _____/   \______
+
+  STRB              / V \
+
+  State  Idle X P   X Push
+  */
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) st_q <= StIdle;
+    else         st_q <= st_d;
+  end
+
+  always_comb begin
+    st_d = StIdle;
+
+    fifo_wvalid = 1'b 0;
+
+    addr_sel = AddrInput;
+    data_inc = 1'b 0;
+
+    sram_req = 1'b 0;
+    sram_d_ready = 1'b 0;
+
+    unique case (st_q)
+      StIdle: begin
+        if (sram_read_req_i) begin // TODO: Change to STRB set
+          sram_req = 1'b 1;
+          addr_sel = AddrInput;
+        end
+
+        if ((sram_req_o || sram_latched) && strb_set) begin
+          // Only when both are valid
+          st_d = StPush;
+        end else begin
+          st_d = StIdle;
+        end
+      end
+
+      StPush: begin
+        if (sram_d_valid) begin
+          fifo_wvalid = 1'b 1; // push to FIFO
+        end
+
+        if (fifo_wready) data_inc = 1'b 1;
+
+        if (strb == 2'b 11 && fifo_wready) begin
+          // pushed all bytes to FIFO
+          st_d = StActive;
+
+          sram_d_ready = 1'b 1;
+        end else begin
+          st_d = StPush;
+        end
+      end
+
+      StActive: begin
+        if (!sram_fifo_full) begin
+          st_d = StPush;
+
+          sram_req = 1'b 1;
+          addr_sel = AddrContinuous;
+        end else begin
+          st_d = StActive;
+        end
+      end
+
+      default: begin
+        st_d = StIdle;
+      end
+    endcase
+  end
+
+  //////////////
+  // Instance //
+  //////////////
+  prim_fifo_sync #(
+    .Width ($bits(sram_data_t)),
+    .Pass  (1'b 1),
+    .Depth (1),
+    .OutputZeroIfEmpty (1'b 0)
+  ) u_sram_fifo (
+    .clk_i,
+    .rst_ni,
+
+    .clr_i (1'b 0),
+
+    .wvalid_i (sram_rvalid_i),
+    .wready_o (),
+    .wdata_i  (sram_rdata_i),
+
+    .rvalid_o (sram_d_valid),
+    .rready_i (sram_d_ready),
+    .rdata_o  (sram_data),
+
+    .full_o   (sram_fifo_full),
+    .depth_o  (unused_sram_depth)
+  );
+
+  prim_fifo_sync #(
+    .Width             ($bits(spi_byte_t)),
+    .Pass              (1'b1),
+    .Depth             (2),
+    .OutputZeroIfEmpty (1'b0)
+  ) u_fifo (
+    .clk_i,
+    .rst_ni,
+
+    .clr_i    (1'b 0),
+
+    .wvalid_i (fifo_wvalid),
+    .wready_o (fifo_wready), // always assume empty space
+    .wdata_i  (fifo_wdata ),
+
+    .rvalid_o (fifo_rvalid_o),
+    .rready_i (fifo_rready_i),
+    .rdata_o  (fifo_rdata_o ),
+
+    .full_o   (unused_fifo_full ),
+    .depth_o  (unused_fifo_depth)
+  );
+
+  // TODO: Handle SRAM integrity errors
+  sram_err_t unused_sram_rerror;
+  assign unused_sram_rerror = sram_rerror_i;
+
+
+  ////////////////
+  // Assertions //
+  ////////////////
+
+  // sfdp_hit keeps high until CSb de-assertion
+
+  // mailbox_hit keeps high until CSb de-assertion
+
+  // current_address keeps increasing (by word? or by byte) after receiving
+  // sram_req
+
+  // FIFO should not overflow. The Main state machine shall send request only
+  // when it needs the data within 2 cycles
+  `ASSERT(NotOverflow_A, sram_req_o && !sram_we_o |-> !sram_fifo_full)
+
+  // SRAM access always read
+  `ASSERT(SramReadOnly_A, sram_req_o |-> !sram_we_o)
+
+  // SRAM data should return in next cycle
+  `ASSUME(SramDataReturnRequirement_M, sram_req_o && !sram_we_o |=> sram_rvalid_i)
+
+  // in fifo_pop, FIFO should not be empty.
+  `ASSERT(FifoNotEmpty_A, fifo_rready_i |-> unused_fifo_depth != 0)
+
+  // strb_set is asserted together with sram_req or follows the req
+  `ASSUME(ReqStrbRelation_M, sram_read_req_i |-> ##[0:2] addr_latched_i)
+
+endmodule : spid_readsram
diff --git a/hw/ip/spi_device/spi_device.core b/hw/ip/spi_device/spi_device.core
index b6b4828..3cd7197 100644
--- a/hw/ip/spi_device/spi_device.core
+++ b/hw/ip/spi_device/spi_device.core
@@ -23,6 +23,7 @@
       - rtl/spi_fwm_txf_ctrl.sv
       - rtl/spi_fwmode.sv
       - rtl/spi_cmdparse.sv
+      - rtl/spid_readsram.sv
       - rtl/spi_readcmd.sv
       - rtl/spi_passthrough.sv
       - rtl/spi_s2p.sv