fix(spid): Latch read command address only for Readbuffer

Related Issue: https://github.com/lowRISC/opentitan/issues/14538

This commit revises logic to latch read address only pointing to the
read buffer space.

The change is to latch the `addr_q` only when FSM is sending the data
(`main_st` is `MainOutput`). Previous design latches `addr_d` (pointing
the next byte).

Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/hw/ip/spi_device/rtl/spi_readcmd.sv b/hw/ip/spi_device/rtl/spi_readcmd.sv
index 64a453f..447a3f0 100644
--- a/hw/ip/spi_device/rtl/spi_readcmd.sv
+++ b/hw/ip/spi_device/rtl/spi_readcmd.sv
@@ -277,6 +277,7 @@
   // state based on the cmd_info.addr_mode and addr_4b_en_i
   logic [4:0] addr_cnt_d, addr_cnt_q;
   logic addr_cnt_set; // no need to clear the counter
+  logic addr_latched_d;
 
   logic [31:0] addr_q, addr_d;
 
@@ -303,9 +304,9 @@
   // Compare addr_d[SramAw-1:2] and mailbox_addr_i with mailbox_mask_i. If the
   // value falls into mailbox, set this.  Even this is set, it only uses when
   // sram address is sent.
-  logic addr_in_mailbox;
+  logic addr_d_in_mailbox, addr_q_in_mailbox;
 
-  logic [31:0] mailbox_masked_addr;
+  logic [31:0] mailbox_masked_addr_d, mailbox_masked_addr_q;
 
   // Double buffering signals
   logic readbuf_idx; // 0 or 1
@@ -347,12 +348,20 @@
     end
   end
 
+  // readbuf_addr is visible to SW after CSb is de-asserted. (last_read_addr)
+  //
+  // It indicates the last byte address the host read.
+  // To precisely represent the last byte:
+  //
+  // - the logic does not latch address field (not yet read the byte)
+  // - the logic latches `addr_q` at the last beat. But compare `addr_q` to
+  //   mailbox address.
   always_ff @(posedge clk_i or negedge sys_rst_ni) begin
     if (!sys_rst_ni) begin
       readbuf_addr <= '0;
-    end else if (addr_latch_en && sel_dp_i == DpReadCmd
-                 && !(mailbox_en_i && addr_in_mailbox)) begin
-      readbuf_addr <= addr_d;
+    end else if ((main_st == MainOutput) && (sel_dp_i == DpReadCmd)
+      && addr_latch_en && !(mailbox_en_i && addr_q_in_mailbox)) begin
+      readbuf_addr <= addr_q;
     end
   end
   assign readbuf_address_o = readbuf_addr;
@@ -386,7 +395,6 @@
   assign addr_ready_in_halfword = (addr_cnt_d == 5'd 1);
 
   // addr_latched should be a pulse to be used in spid_readsram
-  logic  addr_latched_d;
   assign addr_latched_d = (addr_cnt_d == 5'd 0);
 
   prim_edge_detector #(
@@ -476,10 +484,12 @@
   localparam int unsigned MailboxAw = $clog2(MailboxDepth);
   localparam logic [31:0] MailboxMask = {{30-MailboxAw{1'b1}}, {2+MailboxAw{1'b0}}};
 
-  assign mailbox_masked_addr = addr_d & MailboxMask;
+  assign mailbox_masked_addr_d = addr_d & MailboxMask;
+  assign mailbox_masked_addr_q = addr_q & MailboxMask;
 
   // Only valid when logic sends SRAM request
-  assign addr_in_mailbox = (mailbox_masked_addr == mailbox_addr_i);
+  assign addr_d_in_mailbox = (mailbox_masked_addr_d == mailbox_addr_i);
+  assign addr_q_in_mailbox = (mailbox_masked_addr_q == mailbox_addr_i);
 
   // internal addr is the address that the logic tracks.
   // the first address comes from host system and then the internal logic
@@ -493,13 +503,13 @@
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) mailbox_assumed_o <= 1'b 0;
     else if (sram_req && mailbox_en_i && cfg_intercept_en_mbx_i
-            && addr_in_mailbox) begin
+            && addr_d_in_mailbox) begin
       mailbox_assumed_o <= 1'b 1;
     end else if (mailbox_en_i && cfg_intercept_en_mbx_i
-                && addr_in_mailbox && (bitcnt == 3'h 0)) begin
+                && addr_d_in_mailbox && (bitcnt == 3'h 0)) begin
       // Keep checking if the next byte falls into the mailbox region
       mailbox_assumed_o <= 1'b 1;
-    end else if (!addr_in_mailbox && (bitcnt == 3'h 0)) begin
+    end else if (!addr_d_in_mailbox && (bitcnt == 3'h 0)) begin
       // At every byte, Check the address goes out of mailbox region.
       mailbox_assumed_o <= 1'b 0;
     end
@@ -752,7 +762,7 @@
     .threshold_i       (readbuf_threshold_i),
 
     .sfdp_hit_i    (sfdp_hit),
-    .mailbox_hit_i (addr_in_mailbox),
+    .mailbox_hit_i (addr_d_in_mailbox),
     .mailbox_en_i  (mailbox_en_i),
 
     .start_i (readbuf_start),