[sram_ctrl] Harden initialization counter

Signed-off-by: Michael Schaffner <msf@google.com>
diff --git a/hw/ip/prim/rtl/prim_ram_1p_scr.sv b/hw/ip/prim/rtl/prim_ram_1p_scr.sv
index 103edfc..8e3fe19 100644
--- a/hw/ip/prim/rtl/prim_ram_1p_scr.sv
+++ b/hw/ip/prim/rtl/prim_ram_1p_scr.sv
@@ -337,16 +337,18 @@
   logic rvalid_q;
   assign rvalid_o = rvalid_q;
 
+  logic intg_error_q;
   logic [Width-1:0] wmask_q;
   always_comb begin : p_forward_mux
     rdata_o = '0;
-    // regular reads
-    if (rvalid_q) begin
+    // regular reads. note that we just return zero in case
+    // an integrity error was signalled.
+    if (rvalid_q && !intg_error_q) begin
       rdata_o = rdata;
     end
     // In case of a collision, we forward the valid bytes of the write data from the unscrambled
     // holding register.
-    if (addr_collision_q) begin
+    if (addr_collision_q && !intg_error_q) begin
       for (int k = 0; k < Width; k++) begin
         if (wmask_q[k]) begin
           rdata_o[k] = wdata_q[k];
@@ -365,6 +367,7 @@
       addr_collision_q    <= 1'b0;
       rvalid_q            <= 1'b0;
       write_en_q          <= 1'b0;
+      intg_error_q        <= 1'b0;
       raddr_q             <= '0;
       waddr_q             <= '0;
       wmask_q             <= '0;
@@ -375,6 +378,7 @@
       addr_collision_q    <= addr_collision_d;
       rvalid_q            <= read_en;
       write_en_q          <= write_en_d;
+      intg_error_q        <= intg_error_i;
 
       if (read_en) begin
         raddr_q <= addr_i;
diff --git a/hw/ip/sram_ctrl/data/sram_ctrl.hjson b/hw/ip/sram_ctrl/data/sram_ctrl.hjson
index 2edd01b..57e49fd 100644
--- a/hw/ip/sram_ctrl/data/sram_ctrl.hjson
+++ b/hw/ip/sram_ctrl/data/sram_ctrl.hjson
@@ -17,8 +17,11 @@
   ///////////////////////////
 
   alert_list: [
-    { name: "fatal_bus_integ_error",
-      desc: "This fatal alert is triggered when a fatal TL-UL bus integrity fault is detected."
+    { name: "fatal_error",
+      desc: '''
+            This fatal alert is triggered when a fatal TL-UL bus integrity fault is detected,
+            or if the initialization mechanism has reached an invalid state.
+            '''
     }
   ],
 
@@ -126,11 +129,21 @@
             name: "BUS_INTEG_ERROR"
             desc: '''
                   This bit is set to 1 if a fatal bus integrity fault is detected.
-                  This error triggers a fatal_bus_integ_error alert.
+                  This error triggers a fatal_error alert.
+                  This condition is terminal.
                   ''',
             resval: 0,
           }
           { bits: "1"
+            name: "INIT_ERROR"
+            desc: '''
+                  This bit is set to 1 if a the initialization counter has reached an invalid state.
+                  This error triggers a fatal_error alert.
+                  This condition is terminal.
+                  ''',
+            resval: 0,
+          }
+          { bits: "2"
             name: "ESCALATED"
             desc: '''
                   Set to 1 if the sram controller has received an escalate request.
@@ -140,7 +153,7 @@
                   ''',
             resval: 0,
           }
-          { bits: "2"
+          { bits: "3"
             name: "SCR_KEY_VALID"
             desc: '''
                   Set to 1 if a new scrambling key has been successfully obtained from OTP.
@@ -149,7 +162,7 @@
                   ''',
             resval: 0,
           }
-          { bits: "3"
+          { bits: "4"
             name: "SCR_KEY_SEED_VALID"
             desc: '''
                   Set to 1 if the scrambling key has been derived from a valid key seed in OTP.
@@ -160,7 +173,7 @@
                   ''',
             resval: 0,
           }
-          { bits: "4"
+          { bits: "5"
             name: "INIT_DONE"
             desc: '''
                   Set to 1 if the hardware initialization triggered via !!CTRL.INIT has completed.
diff --git a/hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv b/hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv
index 8ca50c2..47e9c63 100644
--- a/hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv
+++ b/hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv
@@ -49,7 +49,7 @@
   //
   virtual task req_mem_init();
     csr_wr(.ptr(ral.ctrl), .value(3));
-    csr_spinwait(.ptr(ral.ctrl.init), .exp_data(0));
+    csr_spinwait(.ptr(ral.status.init_done), .exp_data(1));
   endtask
 
   // Request a new scrambling key from the OTP interface.
diff --git a/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_cfg.sv b/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_cfg.sv
index 6b11603..b12c9c5 100644
--- a/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_cfg.sv
+++ b/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_cfg.sv
@@ -24,7 +24,7 @@
 
   virtual function void initialize(bit [31:0] csr_base_addr = '1);
     list_of_alerts = sram_ctrl_env_pkg::LIST_OF_ALERTS;
-    tl_intg_alert_name = "fatal_intg_error";
+    tl_intg_alert_name = "fatal_error";
     super.initialize(csr_base_addr);
 
     // Build KDI cfg object and configure
diff --git a/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_pkg.sv b/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_pkg.sv
index 6b4e18e..86186f7 100644
--- a/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_pkg.sv
+++ b/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_pkg.sv
@@ -24,7 +24,7 @@
   `include "dv_macros.svh"
 
   // parameters
-  parameter string LIST_OF_ALERTS[] = { "fatal_bus_integ_error"};
+  parameter string LIST_OF_ALERTS[] = { "fatal_error"};
   parameter uint   NUM_ALERTS = 1;
 
   // Number of bits in the otp_ctrl_pkg::sram_otp_key_rsp_t struct:
@@ -48,11 +48,12 @@
   } sram_ctrl_e;
 
   typedef enum bit [2:0] {
-    SramCtrlError           = 0,
-    SramCtrlEscalated       = 1,
-    SramCtrlScrKeyValid     = 2,
-    SramCtrlScrKeySeedValid = 3,
-    SramCtrlInitDone        = 4
+    SramCtrlBusIntegError   = 0,
+    SramCtrlInitError       = 1,
+    SramCtrlEscalated       = 2,
+    SramCtrlScrKeyValid     = 3,
+    SramCtrlScrKeySeedValid = 4,
+    SramCtrlInitDone        = 5
   } sram_ctrl_status_e;
 
   // package sources
diff --git a/hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv b/hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv
index 5b38e92..2e546ae 100644
--- a/hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv
+++ b/hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv
@@ -326,6 +326,7 @@
 
       exp_status[SramCtrlEscalated]       = 1;
       exp_status[SramCtrlScrKeySeedValid] = 0;
+      exp_status[SramCtrlScrKeyValid]     = 0;
       exp_status[SramCtrlInitDone]        = 0;
 
       // escalation resets the key and nonce back to defaults
diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl.sv
index 98504be..54b94c4 100644
--- a/hw/ip/sram_ctrl/rtl/sram_ctrl.sv
+++ b/hw/ip/sram_ctrl/rtl/sram_ctrl.sv
@@ -51,8 +51,8 @@
 );
 
   // This is later on pruned to the correct width at the SRAM wrapper interface.
-  parameter int Depth = MemSizeRam >> 2;
-  parameter int AddrWidth = prim_util_pkg::vbits(Depth);
+  parameter int unsigned Depth = MemSizeRam >> 2;
+  parameter int unsigned AddrWidth = prim_util_pkg::vbits(Depth);
 
   `ASSERT_INIT(NonceWidthsLessThanSource_A, NonceWidth + LfsrWidth <= otp_ctrl_pkg::SramNonceWidth)
 
@@ -91,10 +91,13 @@
   logic alert_test;
   assign alert_test = reg2hw.alert_test.q & reg2hw.alert_test.qe;
 
-  logic bus_integ_error, bus_integ_error_q;
-  assign bus_integ_error_q                = reg2hw.status.bus_integ_error.q;
+  logic bus_integ_error;
   assign hw2reg.status.bus_integ_error.d  = 1'b1;
-  assign hw2reg.status.bus_integ_error.de = bus_integ_error | bus_integ_error_q;
+  assign hw2reg.status.bus_integ_error.de = bus_integ_error;
+
+  logic init_error;
+  assign hw2reg.status.init_error.d  = 1'b1;
+  assign hw2reg.status.init_error.de = init_error;
 
   prim_alert_sender #(
     .AsyncOn(AlertAsyncOn[0]),
@@ -102,17 +105,17 @@
   ) u_prim_alert_sender_parity (
     .clk_i,
     .rst_ni,
-    .alert_test_i  ( alert_test        ),
-    .alert_req_i   ( bus_integ_error   ),
-    .alert_ack_o   (                   ),
-    .alert_state_o (                   ),
-    .alert_rx_i    ( alert_rx_i[0]     ),
-    .alert_tx_o    ( alert_tx_o[0]     )
+    .alert_test_i  ( alert_test                   ),
+    .alert_req_i   ( bus_integ_error | init_error ),
+    .alert_ack_o   (                              ),
+    .alert_state_o (                              ),
+    .alert_rx_i    ( alert_rx_i[0]                ),
+    .alert_tx_o    ( alert_tx_o[0]                )
   );
 
-  //////////////////////////////////////////
-  // Lifecycle Escalation Synchronization //
-  //////////////////////////////////////////
+  /////////////////////////
+  // Escalation Triggers //
+  /////////////////////////
 
   lc_ctrl_pkg::lc_tx_t escalate_en;
   prim_lc_sync #(
@@ -124,6 +127,76 @@
     .lc_en_o (escalate_en)
   );
 
+  logic escalate;
+  assign escalate = (escalate_en != lc_ctrl_pkg::Off);
+  assign hw2reg.status.escalated.d  = 1'b1;
+  assign hw2reg.status.escalated.de = escalate;
+
+  // Aggregate external and internal escalation sources. This is used on countermeasures further
+  // below (key reset, transaction blocking and scrambling nonce reversal).
+  logic local_esc;
+  assign local_esc = escalate                   |
+                     init_error                 |
+                     bus_integ_error            |
+                     reg2hw.status.escalated.q  |
+                     reg2hw.status.init_error.q |
+                     reg2hw.status.bus_integ_error.q;
+
+  ///////////////////////
+  // HW Initialization //
+  ///////////////////////
+
+  // A write to the init register reloads the LFSR seed, resets the init counter and
+  // sets init_q to flag a pending initialization request.
+  logic init_trig;
+  assign init_trig = reg2hw.ctrl.init.q & reg2hw.ctrl.init.qe;
+
+  // We employ two redundant counters to guard against FI attacks.
+  // If any of the two is glitched and the two counter states do not agree,
+  // we trigger an alert.
+  logic [1:0] init_req, init_done, init_q;
+  logic [1:0][AddrWidth-1:0] init_cnt_q;
+  for (genvar k = 0; k < 2; k++) begin : gen_double_cnt
+
+    // These size_only buffers are instantiated in order to prevent
+    // optimization / merging of the two counters.
+    logic init_trig_buf;
+    prim_buf u_prim_buf_trig (
+      .in_i(init_trig),
+      .out_o(init_trig_buf)
+    );
+
+    // This waits until the scrambling keys are actually valid (this allows the SW to trigger
+    // key renewal and initialization at the same time).
+    assign init_req[k]  = init_q[k] & reg2hw.status.scr_key_valid.q;
+    assign init_done[k] = (init_cnt_q[k] == AddrWidth'(Depth - 1)) & init_req[k];
+
+    logic init_d;
+    assign init_d     = (init_done[k])  ? 1'b0 :
+                        (init_trig_buf) ? 1'b1 : init_q[k];
+
+    logic [AddrWidth-1:0] init_cnt_d;
+    assign init_cnt_d = (init_trig_buf) ? '0                   :
+                        (init_req[k])   ? init_cnt_q[k] + 1'b1 : init_cnt_q[k];
+
+    prim_flop #(
+      .Width(1+AddrWidth)
+    ) u_prim_flop_cnt (
+      .clk_i,
+      .rst_ni,
+      .d_i({init_d, init_cnt_d}),
+      .q_o({init_q[k], init_cnt_q[k]})
+    );
+  end
+
+  // Clear this bit on local escalation.
+  assign hw2reg.status.init_done.d  = init_done[0] & ~init_trig & ~local_esc;
+  assign hw2reg.status.init_done.de = init_done[0] | init_trig | local_esc;
+
+  // Check whether counter is glitched into an invalid state
+  assign init_error = {init_q[0], init_cnt_q[0]} !=
+                      {init_q[1], init_cnt_q[1]};
+
   ////////////////////////////
   // Scrambling Key Request //
   ////////////////////////////
@@ -138,33 +211,6 @@
   assign key_req_pending_d = (key_req) ? 1'b1 :
                              (key_ack) ? 1'b0 : key_req_pending_q;
 
-  logic init_q, init_d;
-  logic init_trig, init_req, init_done;
-  logic [AddrWidth-1:0] init_cnt_d, init_cnt_q;
-  // A write to the init register reloads the LFSR seed, resets the init counter and
-  // sets init_q to flag a pending initialization request.
-  assign init_trig = reg2hw.ctrl.init.q & reg2hw.ctrl.init.qe;
-  // This waits until the scrambling keys are actually valid (this allows the SW to trigger
-  // key renewal and initialization at the same time).
-  assign init_req  = init_q & reg2hw.status.scr_key_valid.q;
-  assign init_done = (init_cnt_q == Depth - 1) & init_req;
-
-  assign init_d      = (init_done) ? 1'b0 :
-                       (init_trig) ? 1'b1 : init_q;
-
-  // TODO: Do we need to harden this counter long term?
-  assign init_cnt_d  = (init_trig) ? '0                :
-                       (init_req)  ? init_cnt_q + 1'b1 : init_cnt_q;
-
-  assign hw2reg.status.init_done.d  = init_done & ~init_trig;
-  assign hw2reg.status.init_done.de = init_done | init_trig;
-
-  // Trigger escalation
-  logic escalate;
-  assign escalate = (escalate_en != lc_ctrl_pkg::Off) | reg2hw.status.escalated.q;
-  assign hw2reg.status.escalated.d  = 1'b1;
-  assign hw2reg.status.escalated.de = escalate;
-
   // The SRAM scrambling wrapper will not accept any transactions while
   // the key req is pending or if we have escalated.
   // Note that we're not using key_valid_q here, such that the SRAM can be used
@@ -172,30 +218,28 @@
   logic key_valid;
   assign key_valid = ~(key_req_pending_q | reg2hw.status.escalated.q);
 
-  assign hw2reg.status.scr_key_valid.d   = key_ack & ~key_req;
-  assign hw2reg.status.scr_key_valid.de  = key_req | key_ack;
+  // Clear this bit on local escalation.
+  assign hw2reg.status.scr_key_valid.d   = key_ack & ~key_req & ~local_esc;
+  assign hw2reg.status.scr_key_valid.de  = key_req | key_ack | local_esc;
 
+  // Clear this bit on local escalation.
   logic key_seed_valid;
-  assign hw2reg.status.scr_key_seed_valid.d  = key_seed_valid & ~escalate;
-  assign hw2reg.status.scr_key_seed_valid.de = key_ack | escalate;
+  assign hw2reg.status.scr_key_seed_valid.d  = key_seed_valid & ~local_esc;
+  assign hw2reg.status.scr_key_seed_valid.de = key_ack | local_esc;
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
     if (!rst_ni) begin
-      init_q            <= '0;
-      init_cnt_q        <= '0;
       key_req_pending_q <= 1'b0;
       key_q             <= RndCnstSramKey;
       nonce_q           <= RndCnstSramNonce;
     end else begin
-      init_q            <= init_d;
-      init_cnt_q        <= init_cnt_d;
       key_req_pending_q <= key_req_pending_d;
       if (key_ack) begin
         key_q   <= key_d;
         nonce_q <= nonce_d;
       end
       // This scraps the keys.
-      if (escalate) begin
+      if (local_esc) begin
         key_q   <= RndCnstSramKey;
         nonce_q <= RndCnstSramNonce;
       end
@@ -264,7 +308,7 @@
   ) u_lfsr (
     .clk_i,
     .rst_ni,
-    .lfsr_en_i(init_req),
+    .lfsr_en_i(init_req[0]),
     .seed_en_i(init_trig),
     .seed_i(nonce_q[NonceWidth +: LfsrWidth]),
     .entropy_i('0),
@@ -319,13 +363,13 @@
   );
 
   // Interposing mux logic for initialization with pseudo random data.
-  assign sram_req        = tlul_req | init_req;
-  assign tlul_gnt        = sram_gnt & ~init_req;
-  assign sram_we         = tlul_we | init_req;
-  assign sram_intg_error = bus_integ_error_q & ~init_req;
-  assign sram_addr       = (init_req) ? init_cnt_q        : tlul_addr;
-  assign sram_wdata      = (init_req) ? lfsr_out_integ    : tlul_wdata;
-  assign sram_wmask      = (init_req) ? {DataWidth{1'b1}} : tlul_wmask;
+  assign sram_req        = tlul_req | init_req[0];
+  assign tlul_gnt        = sram_gnt & ~init_req[0];
+  assign sram_we         = tlul_we | init_req[0];
+  assign sram_intg_error = local_esc & ~init_req[0];
+  assign sram_addr       = (init_req[0]) ? init_cnt_q[0]     : tlul_addr;
+  assign sram_wdata      = (init_req[0]) ? lfsr_out_integ    : tlul_wdata;
+  assign sram_wmask      = (init_req[0]) ? {DataWidth{1'b1}} : tlul_wmask;
 
   prim_ram_1p_scr #(
     .Width(DataWidth),
diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv
index 514d5b7..f8a3f29 100644
--- a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv
+++ b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv
@@ -28,6 +28,9 @@
     } bus_integ_error;
     struct packed {
       logic        q;
+    } init_error;
+    struct packed {
+      logic        q;
     } escalated;
     struct packed {
       logic        q;
@@ -63,6 +66,10 @@
     struct packed {
       logic        d;
       logic        de;
+    } init_error;
+    struct packed {
+      logic        d;
+      logic        de;
     } escalated;
     struct packed {
       logic        d;
@@ -80,15 +87,15 @@
 
   // Register -> HW type for regs interface
   typedef struct packed {
-    sram_ctrl_reg2hw_alert_test_reg_t alert_test; // [13:12]
-    sram_ctrl_reg2hw_status_reg_t status; // [11:7]
+    sram_ctrl_reg2hw_alert_test_reg_t alert_test; // [14:13]
+    sram_ctrl_reg2hw_status_reg_t status; // [12:7]
     sram_ctrl_reg2hw_exec_reg_t exec; // [6:4]
     sram_ctrl_reg2hw_ctrl_reg_t ctrl; // [3:0]
   } sram_ctrl_regs_reg2hw_t;
 
   // HW -> register type for regs interface
   typedef struct packed {
-    sram_ctrl_hw2reg_status_reg_t status; // [9:0]
+    sram_ctrl_hw2reg_status_reg_t status; // [11:0]
   } sram_ctrl_regs_hw2reg_t;
 
   // Register offsets for regs interface
@@ -101,7 +108,7 @@
 
   // Reset values for hwext registers and their fields for regs interface
   parameter logic [0:0] SRAM_CTRL_ALERT_TEST_RESVAL = 1'h 0;
-  parameter logic [0:0] SRAM_CTRL_ALERT_TEST_FATAL_BUS_INTEG_ERROR_RESVAL = 1'h 0;
+  parameter logic [0:0] SRAM_CTRL_ALERT_TEST_FATAL_ERROR_RESVAL = 1'h 0;
 
   // Register index for regs interface
   typedef enum int {
diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv
index 42f0932..6506427 100644
--- a/hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv
+++ b/hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv
@@ -112,6 +112,7 @@
   logic alert_test_we;
   logic alert_test_wd;
   logic status_bus_integ_error_qs;
+  logic status_init_error_qs;
   logic status_escalated_qs;
   logic status_scr_key_valid_qs;
   logic status_scr_key_seed_valid_qs;
@@ -174,7 +175,33 @@
   );
 
 
-  //   F[escalated]: 1:1
+  //   F[init_error]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_status_init_error (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.status.init_error.de),
+    .d      (hw2reg.status.init_error.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.status.init_error.q),
+
+    // to register interface (read)
+    .qs     (status_init_error_qs)
+  );
+
+
+  //   F[escalated]: 2:2
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -200,7 +227,7 @@
   );
 
 
-  //   F[scr_key_valid]: 2:2
+  //   F[scr_key_valid]: 3:3
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -226,7 +253,7 @@
   );
 
 
-  //   F[scr_key_seed_valid]: 3:3
+  //   F[scr_key_seed_valid]: 4:4
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -252,7 +279,7 @@
   );
 
 
-  //   F[init_done]: 4:4
+  //   F[init_done]: 5:5
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -466,10 +493,11 @@
 
       addr_hit[1]: begin
         reg_rdata_next[0] = status_bus_integ_error_qs;
-        reg_rdata_next[1] = status_escalated_qs;
-        reg_rdata_next[2] = status_scr_key_valid_qs;
-        reg_rdata_next[3] = status_scr_key_seed_valid_qs;
-        reg_rdata_next[4] = status_init_done_qs;
+        reg_rdata_next[1] = status_init_error_qs;
+        reg_rdata_next[2] = status_escalated_qs;
+        reg_rdata_next[3] = status_scr_key_valid_qs;
+        reg_rdata_next[4] = status_scr_key_seed_valid_qs;
+        reg_rdata_next[5] = status_init_done_qs;
       end
 
       addr_hit[2]: begin
diff --git a/hw/ip/tlul/rtl/tlul_sram_byte.sv b/hw/ip/tlul/rtl/tlul_sram_byte.sv
index 89e07ec..d865e96 100644
--- a/hw/ip/tlul/rtl/tlul_sram_byte.sv
+++ b/hw/ip/tlul/rtl/tlul_sram_byte.sv
@@ -69,6 +69,7 @@
   logic wr_txn;
   logic byte_wr_txn;
   logic byte_req_ack;
+  logic a_ack_q, a_ack_d;
 
   assign a_ack = tl_i.a_valid & tl_o.a_ready;
   assign sram_a_ack = tl_sram_o.a_valid & tl_sram_i.a_ready;
@@ -80,9 +81,12 @@
   if (EnableIntg) begin : gen_dyn_sel
     assign byte_wr_txn = tl_i.a_valid & ~&tl_i.a_mask & wr_txn;
     assign sel_int = byte_wr_txn | stall_host ? SelInt : SelPassThru;
+    // TODO(#7461): remove this register, once this issue has been addressed.
+    assign a_ack_d = a_ack;
   end else begin : gen_static_sel
     assign byte_wr_txn = '0;
     assign sel_int = SelPassThru;
+    assign a_ack_d = 1'b0;
   end
 
   // state machine handling
@@ -94,8 +98,13 @@
 
     unique case (state_q)
       StPassThru: begin
-
-        if (byte_req_ack) begin
+        // TODO(#7461): remove the first if condition once all RAW corner cases are handled in DV.
+        // This introduces an artificial bubble before entering a read modify write operation
+        // in case there was another transaction right before this one. This ensures that the
+        // previous operation can complete.
+        if (byte_wr_txn && a_ack_q) begin
+          stall_host = 1'b1;
+        end else if (byte_req_ack) begin
           state_d = StWaitRd;
         end
       end
@@ -119,6 +128,8 @@
       end
 
       // TODO(#7461): remove this once all RAW corner cases are handled in DV.
+      // This state artificially introduces a bubble after each read modify write
+      // operation such that it can complete.
       StWait: begin
         stall_host = 1'b1;
         state_d = StPassThru;
@@ -130,6 +141,14 @@
 
   end
 
+  always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
+    if (!rst_ni) begin
+       a_ack_q <= 1'b0;
+    end else begin
+       a_ack_q <= a_ack_d;
+    end
+  end
+
   // prim fifo for capturing info
   typedef struct packed {
     logic                  [2:0]  a_param;
diff --git a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
index 25c084d..46b3a95 100644
--- a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
+++ b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
@@ -12801,7 +12801,7 @@
       module_name: sensor_ctrl_aon
     }
     {
-      name: sram_ctrl_ret_aon_fatal_bus_integ_error
+      name: sram_ctrl_ret_aon_fatal_error
       width: 1
       type: alert
       async: "1"
@@ -12927,7 +12927,7 @@
       module_name: edn1
     }
     {
-      name: sram_ctrl_main_fatal_bus_integ_error
+      name: sram_ctrl_main_fatal_error
       width: 1
       type: alert
       async: "1"
diff --git a/hw/top_earlgrey/dv/env/autogen/chip_env_pkg__params.sv b/hw/top_earlgrey/dv/env/autogen/chip_env_pkg__params.sv
index d2e7bb9..e2aeb1b 100644
--- a/hw/top_earlgrey/dv/env/autogen/chip_env_pkg__params.sv
+++ b/hw/top_earlgrey/dv/env/autogen/chip_env_pkg__params.sv
@@ -46,7 +46,7 @@
   "sensor_ctrl_aon_recov_ot3",
   "sensor_ctrl_aon_recov_ot4",
   "sensor_ctrl_aon_recov_ot5",
-  "sram_ctrl_ret_aon_fatal_bus_integ_error",
+  "sram_ctrl_ret_aon_fatal_error",
   "flash_ctrl_recov_err",
   "flash_ctrl_recov_mp_err",
   "flash_ctrl_recov_ecc_err",
@@ -64,7 +64,7 @@
   "entropy_src_fatal_alert",
   "edn0_fatal_alert",
   "edn1_fatal_alert",
-  "sram_ctrl_main_fatal_bus_integ_error",
+  "sram_ctrl_main_fatal_error",
   "otbn_fatal",
   "otbn_recov",
   "rom_ctrl_fatal",
diff --git a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
index 2075a37..0a21d99 100644
--- a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
+++ b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
@@ -1890,7 +1890,7 @@
     .MemSizeRam(4096),
     .InstrExec(SramCtrlRetAonInstrExec)
   ) u_sram_ctrl_ret_aon (
-      // [41]: fatal_bus_integ_error
+      // [41]: fatal_error
       .alert_tx_o  ( alert_tx[41:41] ),
       .alert_rx_i  ( alert_rx[41:41] ),
 
@@ -2286,7 +2286,7 @@
     .MemSizeRam(131072),
     .InstrExec(SramCtrlMainInstrExec)
   ) u_sram_ctrl_main (
-      // [59]: fatal_bus_integ_error
+      // [59]: fatal_error
       .alert_tx_o  ( alert_tx[59:59] ),
       .alert_rx_i  ( alert_rx[59:59] ),
 
diff --git a/hw/top_earlgrey/sw/autogen/top_earlgrey.c b/hw/top_earlgrey/sw/autogen/top_earlgrey.c
index f5fb4e0..baa4da7 100644
--- a/hw/top_earlgrey/sw/autogen/top_earlgrey.c
+++ b/hw/top_earlgrey/sw/autogen/top_earlgrey.c
@@ -244,7 +244,7 @@
   [kTopEarlgreyAlertIdSensorCtrlAonRecovOt3] = kTopEarlgreyAlertPeripheralSensorCtrlAon,
   [kTopEarlgreyAlertIdSensorCtrlAonRecovOt4] = kTopEarlgreyAlertPeripheralSensorCtrlAon,
   [kTopEarlgreyAlertIdSensorCtrlAonRecovOt5] = kTopEarlgreyAlertPeripheralSensorCtrlAon,
-  [kTopEarlgreyAlertIdSramCtrlRetAonFatalBusIntegError] = kTopEarlgreyAlertPeripheralSramCtrlRetAon,
+  [kTopEarlgreyAlertIdSramCtrlRetAonFatalError] = kTopEarlgreyAlertPeripheralSramCtrlRetAon,
   [kTopEarlgreyAlertIdFlashCtrlRecovErr] = kTopEarlgreyAlertPeripheralFlashCtrl,
   [kTopEarlgreyAlertIdFlashCtrlRecovMpErr] = kTopEarlgreyAlertPeripheralFlashCtrl,
   [kTopEarlgreyAlertIdFlashCtrlRecovEccErr] = kTopEarlgreyAlertPeripheralFlashCtrl,
@@ -262,7 +262,7 @@
   [kTopEarlgreyAlertIdEntropySrcFatalAlert] = kTopEarlgreyAlertPeripheralEntropySrc,
   [kTopEarlgreyAlertIdEdn0FatalAlert] = kTopEarlgreyAlertPeripheralEdn0,
   [kTopEarlgreyAlertIdEdn1FatalAlert] = kTopEarlgreyAlertPeripheralEdn1,
-  [kTopEarlgreyAlertIdSramCtrlMainFatalBusIntegError] = kTopEarlgreyAlertPeripheralSramCtrlMain,
+  [kTopEarlgreyAlertIdSramCtrlMainFatalError] = kTopEarlgreyAlertPeripheralSramCtrlMain,
   [kTopEarlgreyAlertIdOtbnFatal] = kTopEarlgreyAlertPeripheralOtbn,
   [kTopEarlgreyAlertIdOtbnRecov] = kTopEarlgreyAlertPeripheralOtbn,
   [kTopEarlgreyAlertIdRomCtrlFatal] = kTopEarlgreyAlertPeripheralRomCtrl,
diff --git a/hw/top_earlgrey/sw/autogen/top_earlgrey.h b/hw/top_earlgrey/sw/autogen/top_earlgrey.h
index 554e57f..62926be 100644
--- a/hw/top_earlgrey/sw/autogen/top_earlgrey.h
+++ b/hw/top_earlgrey/sw/autogen/top_earlgrey.h
@@ -1298,7 +1298,7 @@
   kTopEarlgreyAlertIdSensorCtrlAonRecovOt3 = 38, /**< sensor_ctrl_aon_recov_ot3 */
   kTopEarlgreyAlertIdSensorCtrlAonRecovOt4 = 39, /**< sensor_ctrl_aon_recov_ot4 */
   kTopEarlgreyAlertIdSensorCtrlAonRecovOt5 = 40, /**< sensor_ctrl_aon_recov_ot5 */
-  kTopEarlgreyAlertIdSramCtrlRetAonFatalBusIntegError = 41, /**< sram_ctrl_ret_aon_fatal_bus_integ_error */
+  kTopEarlgreyAlertIdSramCtrlRetAonFatalError = 41, /**< sram_ctrl_ret_aon_fatal_error */
   kTopEarlgreyAlertIdFlashCtrlRecovErr = 42, /**< flash_ctrl_recov_err */
   kTopEarlgreyAlertIdFlashCtrlRecovMpErr = 43, /**< flash_ctrl_recov_mp_err */
   kTopEarlgreyAlertIdFlashCtrlRecovEccErr = 44, /**< flash_ctrl_recov_ecc_err */
@@ -1316,7 +1316,7 @@
   kTopEarlgreyAlertIdEntropySrcFatalAlert = 56, /**< entropy_src_fatal_alert */
   kTopEarlgreyAlertIdEdn0FatalAlert = 57, /**< edn0_fatal_alert */
   kTopEarlgreyAlertIdEdn1FatalAlert = 58, /**< edn1_fatal_alert */
-  kTopEarlgreyAlertIdSramCtrlMainFatalBusIntegError = 59, /**< sram_ctrl_main_fatal_bus_integ_error */
+  kTopEarlgreyAlertIdSramCtrlMainFatalError = 59, /**< sram_ctrl_main_fatal_error */
   kTopEarlgreyAlertIdOtbnFatal = 60, /**< otbn_fatal */
   kTopEarlgreyAlertIdOtbnRecov = 61, /**< otbn_recov */
   kTopEarlgreyAlertIdRomCtrlFatal = 62, /**< rom_ctrl_fatal */