[flash_ctrl] Various clean-up and updates

- use prim_intr_hw, (#8035 for flash)
- clean-up error mechanisms and related usage
- clean-up error and data signaling when multi-bit errors are seen

Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.hjson b/hw/ip/flash_ctrl/data/flash_ctrl.hjson
index 6c800cb..1d37a7e 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.hjson
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.hjson
@@ -28,21 +28,15 @@
     { name: "rd_full",    desc: "Read FIFO full" },
     { name: "rd_lvl",     desc: "Read FIFO filled to level" },
     { name: "op_done",    desc: "Operation complete" },
-    { name: "err",        desc: "Error encountered"},
+    { name: "corr_err",   desc: "Correctable error encountered"},
   ],
 
   alert_list: [
     { name: "recov_err",
-      desc: "flash alerts directly from prim_flash",
+      desc: "flash recoverable errors",
     },
-    { name: "recov_mp_err",
-      desc: "recoverable flash alert for permission error"
-    },
-    { name: "recov_ecc_err",
-      desc: "recoverable flash alert for ecc error"
-    },
-    { name: "fatal_intg_err",
-      desc: "Fatal integrity error"
+    { name: "fatal_err",
+      desc: "flash fatal errors"
     },
   ],
 
@@ -1384,159 +1378,172 @@
         ]
       },
 
-      { name: "ERR_CODE_INTR_EN",
-        desc: '''
-          Interrupt enable mask for error code.
-          Only enabled bits will generate interrupts.
-          Bits that are not enabled will still be reflected in the !!ERR_CODE register, but will not trigger
-          an interrupt
-        '''
-        swaccess: "rw",
-        hwaccess: "hro",
-        fields: [
-          { bits: "0",
-            name: "flash_err_en",
-            desc: "interrupt mask for flash error"
-          },
-          { bits: "1",
-            name: "flash_alert_en",
-            desc: "interrupt mask for flash alert"
-          },
-          { bits: "2",
-            name: "oob_err",
-            desc: "interrupt mask for software address out of bounds error"
-          },
-          { bits: "3",
-            name: "mp_err",
-            desc: "interrupt mask for memory properties error"
-          },
-          { bits: "4",
-            name: "ecc_single_err",
-            desc: "interrupt mask for single bit ecc error"
-          },
-          { bits: "5",
-            name: "ecc_multi_err",
-            desc: "interrupt mask for multiple bits ecc error"
-          },
-        ]
-      },
-
       { name: "ERR_CODE",
         desc: '''
           Flash error code register.
           This register tabulates detailed error status of the flash.
           This is separate from !!OP_STATUS, which is used to indicate the current state of the software initiated
           flash operation.
+
+          Note, all errors in this register are considered recoverable errors, ie, errors that could have been
+          generated by software.
         '''
         swaccess: "rw1c",
-        hwaccess: "hrw",
+        hwaccess: "hwo",
         fields: [
           { bits: "0",
-            name: "flash_err",
-            desc: '''
-              The flash memory itself has an error, please check the vendor specs for details of the error.
-            '''
-          },
-          { bits: "1",
-            name: "flash_alert",
-            desc: '''
-              The flash memory itself has triggered an alert, please check the vendor specs for details of the error.
-            '''
-          },
-          { bits: "2",
             name: "oob_err",
             desc: '''
               The supplied address !!ADDR is invalid and out of bounds.
+              This is a synchronous error.
             '''
           },
-          { bits: "3",
+          { bits: "1",
             name: "mp_err",
             desc: '''
               Flash access has encountered an access permission error.
               Please see !!ERR_ADDR for exact address.
+              This is a synchronous error.
+            '''
+          },
+          { bits: "2",
+            name: "rd_err",
+            desc: '''
+              Flash read has an uncorrectable data error.
+              Please see !!ERR_ADDR for exact address.
+              This is a synchronous error.
+            '''
+          },
+          { bits: "3",
+            name: "prog_win_err",
+            desc: '''
+              Flash program has a window resolution error.  Ie, the start of program
+              and end of program are in different windows.  Please check !!ADDR.
+              This is a synchronous error.
             '''
           },
           { bits: "4",
-            name: "ecc_single_err",
+            name: "prog_type_err",
             desc: '''
-              Flash access has encountered a single bit ECC error.
-              Please see !!ECC_SINGLE_ERR_ADDR for exact address.
+              Flash program selected unavailable type, see !!PROG_TYPE_EN.
+              This is a synchronous error.
             '''
           },
           { bits: "5",
-            name: "ecc_multi_err",
+            name: "flash_phy_err",
             desc: '''
-              Flash access has encountered a multi bit ECC error.
-              Please see !!ECC_MULTI_ERR_ADDR for exact address.
+              The flash access encountered a native flash error.
+              Please check the vendor specs for details of the error.
+              This is a synchronous error.
+            '''
+          },
+        ]
+      },
+
+      { name: "FAULT_STATUS",
+        desc: '''
+          Flash fault status register.
+          This register tabulates detailed fault status of the flash.
+
+          These are errors that are impossible to have been caused by software or unrecoverable
+          in nature.
+        '''
+        swaccess: "ro",
+        hwaccess: "hrw",
+        fields: [
+          { bits: "0",
+            name: "oob_err",
+            desc: '''
+              The flash hardware interface supplied an out of bound value.
+            '''
+          },
+          { bits: "1",
+            name: "mp_err",
+            desc: '''
+              The flash hardware interface encountered a memory permission error.
+            '''
+          },
+          { bits: "2",
+            name: "rd_err",
+            desc: '''
+              The flash hardware interface encountered a read data error.
+            '''
+          },
+          { bits: "3",
+            name: "prog_win_err",
+            desc: '''
+              The flash hardware interface encountered a program resolution error.
+            '''
+          },
+          { bits: "4",
+            name: "prog_type_err",
+            desc: '''
+              The flash hardware interface encountered a program type error.
+            '''
+          },
+          { bits: "5",
+            name: "flash_phy_err",
+            desc: '''
+              The flash hardware interface encountered a native flash error.
+            '''
+          },
+          { bits: "6",
+            name: "reg_intg_err",
+            desc: '''
+              The flash controller encountered a register integrity error.
+            '''
+          },
+          { bits: "7",
+            name: "phy_intg_err",
+            desc: '''
+              The flash memory encountered a register integrity error.
             '''
           },
         ]
       },
 
       { name: "ERR_ADDR",
-        desc: "Access permission error address",
+        desc: "Synchronous error address",
         swaccess: "ro",
         hwaccess: "hwo",
         fields: [
-          { bits: "8:0",
-            resval: 0,
-          },
-        ]
-      },
-
-      { name: "ECC_SINGLE_ERR_CNT",
-        desc: "Total number of single bit ECC error count",
-        swaccess: "rw1c",
-        hwaccess: "hrw",
-        fields: [
-          { bits: "7:0",
-            desc: "This count will not wrap when saturated",
+          { bits: "31:0",
             resval: 0,
           },
         ]
       },
 
       { multireg: {
-          cname: "ECC_SINGLE_ERR"
+          cname: "ECC_SINGLE_ERR",
+          name: "ECC_SINGLE_ERR_CNT",
+          desc: "Total number of single bit ECC error count",
+          count: "RegNumBanks",
+          swaccess: "rw",
+          hwaccess: "hrw",
+          fields: [
+            { bits: "7:0",
+              desc: "This count will not wrap when saturated",
+              resval: 0,
+            },
+          ]
+        }
+      },
+
+      { multireg: {
+          cname: "ECC_SINGLE_ERR",
           name: "ECC_SINGLE_ERR_ADDR",
-          desc: "Latest single bit error address (correctable)",
+          desc: "Latest address of ECC single err",
           count: "RegNumBanks",
           swaccess: "ro",
           hwaccess: "hwo",
           fields: [
             { bits: "19:0",
+              desc: "Latest single error address for this bank",
               resval: 0,
             },
           ]
         }
-      },
-
-      { name: "ECC_MULTI_ERR_CNT",
-        desc: "Total number of multi bit ECC error count",
-        swaccess: "rw1c",
-        hwaccess: "hrw",
-        fields: [
-          { bits: "7:0",
-            desc: "This count will not wrap when saturated",
-            resval: 0,
-          },
-        ]
-      },
-
-      { multireg: {
-          cname: "ECC_MULTI_ERR"
-          name: "ECC_MULTI_ERR_ADDR",
-          desc: "Latest multi bit error address (uncorrectable)",
-          count: "RegNumBanks",
-          swaccess: "ro",
-          hwaccess: "hwo",
-          fields: [
-            { bits: "19:0",
-              resval: 0,
-            },
-          ]
-        }
-      },
+      }
 
       { name: "PHY_ERR_CFG_REGWEN",
         swaccess: "rw0c",
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl b/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
index 9a91548..e3fac44 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
@@ -35,21 +35,15 @@
     { name: "rd_full",    desc: "Read FIFO full" },
     { name: "rd_lvl",     desc: "Read FIFO filled to level" },
     { name: "op_done",    desc: "Operation complete" },
-    { name: "err",        desc: "Error encountered"},
+    { name: "corr_err",   desc: "Correctable error encountered"},
   ],
 
   alert_list: [
     { name: "recov_err",
-      desc: "flash alerts directly from prim_flash",
+      desc: "flash recoverable errors",
     },
-    { name: "recov_mp_err",
-      desc: "recoverable flash alert for permission error"
-    },
-    { name: "recov_ecc_err",
-      desc: "recoverable flash alert for ecc error"
-    },
-    { name: "fatal_intg_err",
-      desc: "Fatal integrity error"
+    { name: "fatal_err",
+      desc: "flash fatal errors"
     },
   ],
 
@@ -900,159 +894,172 @@
         ]
       },
 
-      { name: "ERR_CODE_INTR_EN",
-        desc: '''
-          Interrupt enable mask for error code.
-          Only enabled bits will generate interrupts.
-          Bits that are not enabled will still be reflected in the !!ERR_CODE register, but will not trigger
-          an interrupt
-        '''
-        swaccess: "rw",
-        hwaccess: "hro",
-        fields: [
-          { bits: "0",
-            name: "flash_err_en",
-            desc: "interrupt mask for flash error"
-          },
-          { bits: "1",
-            name: "flash_alert_en",
-            desc: "interrupt mask for flash alert"
-          },
-          { bits: "2",
-            name: "oob_err",
-            desc: "interrupt mask for software address out of bounds error"
-          },
-          { bits: "3",
-            name: "mp_err",
-            desc: "interrupt mask for memory properties error"
-          },
-          { bits: "4",
-            name: "ecc_single_err",
-            desc: "interrupt mask for single bit ecc error"
-          },
-          { bits: "5",
-            name: "ecc_multi_err",
-            desc: "interrupt mask for multiple bits ecc error"
-          },
-        ]
-      },
-
       { name: "ERR_CODE",
         desc: '''
           Flash error code register.
           This register tabulates detailed error status of the flash.
           This is separate from !!OP_STATUS, which is used to indicate the current state of the software initiated
           flash operation.
+
+          Note, all errors in this register are considered recoverable errors, ie, errors that could have been
+          generated by software.
         '''
         swaccess: "rw1c",
-        hwaccess: "hrw",
+        hwaccess: "hwo",
         fields: [
           { bits: "0",
-            name: "flash_err",
-            desc: '''
-              The flash memory itself has an error, please check the vendor specs for details of the error.
-            '''
-          },
-          { bits: "1",
-            name: "flash_alert",
-            desc: '''
-              The flash memory itself has triggered an alert, please check the vendor specs for details of the error.
-            '''
-          },
-          { bits: "2",
             name: "oob_err",
             desc: '''
               The supplied address !!ADDR is invalid and out of bounds.
+              This is a synchronous error.
             '''
           },
-          { bits: "3",
+          { bits: "1",
             name: "mp_err",
             desc: '''
               Flash access has encountered an access permission error.
               Please see !!ERR_ADDR for exact address.
+              This is a synchronous error.
+            '''
+          },
+          { bits: "2",
+            name: "rd_err",
+            desc: '''
+              Flash read has an uncorrectable data error.
+              Please see !!ERR_ADDR for exact address.
+              This is a synchronous error.
+            '''
+          },
+          { bits: "3",
+            name: "prog_win_err",
+            desc: '''
+              Flash program has a window resolution error.  Ie, the start of program
+              and end of program are in different windows.  Please check !!ADDR.
+              This is a synchronous error.
             '''
           },
           { bits: "4",
-            name: "ecc_single_err",
+            name: "prog_type_err",
             desc: '''
-              Flash access has encountered a single bit ECC error.
-              Please see !!ECC_SINGLE_ERR_ADDR for exact address.
+              Flash program selected unavailable type, see !!PROG_TYPE_EN.
+              This is a synchronous error.
             '''
           },
           { bits: "5",
-            name: "ecc_multi_err",
+            name: "flash_phy_err",
             desc: '''
-              Flash access has encountered a multi bit ECC error.
-              Please see !!ECC_MULTI_ERR_ADDR for exact address.
+              The flash access encountered a native flash error.
+              Please check the vendor specs for details of the error.
+              This is a synchronous error.
+            '''
+          },
+        ]
+      },
+
+      { name: "FAULT_STATUS",
+        desc: '''
+          Flash fault status register.
+          This register tabulates detailed fault status of the flash.
+
+          These are errors that are impossible to have been caused by software or unrecoverable
+          in nature.
+        '''
+        swaccess: "ro",
+        hwaccess: "hrw",
+        fields: [
+          { bits: "0",
+            name: "oob_err",
+            desc: '''
+              The flash hardware interface supplied an out of bound value.
+            '''
+          },
+          { bits: "1",
+            name: "mp_err",
+            desc: '''
+              The flash hardware interface encountered a memory permission error.
+            '''
+          },
+          { bits: "2",
+            name: "rd_err",
+            desc: '''
+              The flash hardware interface encountered a read data error.
+            '''
+          },
+          { bits: "3",
+            name: "prog_win_err",
+            desc: '''
+              The flash hardware interface encountered a program resolution error.
+            '''
+          },
+          { bits: "4",
+            name: "prog_type_err",
+            desc: '''
+              The flash hardware interface encountered a program type error.
+            '''
+          },
+          { bits: "5",
+            name: "flash_phy_err",
+            desc: '''
+              The flash hardware interface encountered a native flash error.
+            '''
+          },
+          { bits: "6",
+            name: "reg_intg_err",
+            desc: '''
+              The flash controller encountered a register integrity error.
+            '''
+          },
+          { bits: "7",
+            name: "phy_intg_err",
+            desc: '''
+              The flash memory encountered a register integrity error.
             '''
           },
         ]
       },
 
       { name: "ERR_ADDR",
-        desc: "Access permission error address",
+        desc: "Synchronous error address",
         swaccess: "ro",
         hwaccess: "hwo",
         fields: [
-          { bits: "${bank_width + page_width -1}:0",
-            resval: 0,
-          },
-        ]
-      },
-
-      { name: "ECC_SINGLE_ERR_CNT",
-        desc: "Total number of single bit ECC error count",
-        swaccess: "rw1c",
-        hwaccess: "hrw",
-        fields: [
-          { bits: "7:0",
-            desc: "This count will not wrap when saturated",
+          { bits: "31:0",
             resval: 0,
           },
         ]
       },
 
       { multireg: {
-          cname: "ECC_SINGLE_ERR"
+          cname: "ECC_SINGLE_ERR",
+          name: "ECC_SINGLE_ERR_CNT",
+          desc: "Total number of single bit ECC error count",
+          count: "RegNumBanks",
+          swaccess: "rw",
+          hwaccess: "hrw",
+          fields: [
+            { bits: "7:0",
+              desc: "This count will not wrap when saturated",
+              resval: 0,
+            },
+          ]
+        }
+      },
+
+      { multireg: {
+          cname: "ECC_SINGLE_ERR",
           name: "ECC_SINGLE_ERR_ADDR",
-          desc: "Latest single bit error address (correctable)",
+          desc: "Latest address of ECC single err",
           count: "RegNumBanks",
           swaccess: "ro",
           hwaccess: "hwo",
           fields: [
             { bits: "${total_byte_width-1}:0",
+              desc: "Latest single error address for this bank",
               resval: 0,
             },
           ]
         }
-      },
-
-      { name: "ECC_MULTI_ERR_CNT",
-        desc: "Total number of multi bit ECC error count",
-        swaccess: "rw1c",
-        hwaccess: "hrw",
-        fields: [
-          { bits: "7:0",
-            desc: "This count will not wrap when saturated",
-            resval: 0,
-          },
-        ]
-      },
-
-      { multireg: {
-          cname: "ECC_MULTI_ERR"
-          name: "ECC_MULTI_ERR_ADDR",
-          desc: "Latest multi bit error address (uncorrectable)",
-          count: "RegNumBanks",
-          swaccess: "ro",
-          hwaccess: "hwo",
-          fields: [
-            { bits: "${total_byte_width-1}:0",
-              resval: 0,
-            },
-          ]
-        }
-      },
+      }
 
       { name: "PHY_ERR_CFG_REGWEN",
         swaccess: "rw0c",
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
index 925a158..4565bef 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
@@ -58,7 +58,7 @@
   output logic cio_tdo_o,
 
   // Interrupts
-  output logic intr_err_o,        // ERR_CODE is non-zero
+  output logic intr_corr_err_o,   // Correctable errors encountered
   output logic intr_prog_empty_o, // Program fifo is empty
   output logic intr_prog_lvl_o,   // Program fifo is empty
   output logic intr_rd_full_o,    // Read fifo is full
@@ -144,18 +144,16 @@
   flash_erase_e erase_flash_type;
   logic erase_op_valid;
 
-  // combined indication that an operation has started
-  logic op_valid;
-
   // Done / Error signaling from ctrl modules
   logic prog_done, rd_done, erase_done;
-  logic prog_err, rd_err, erase_err;
+  flash_ctrl_err_t prog_err, rd_err, erase_err;
+  logic [BusAddrW-1:0] prog_err_addr, rd_err_addr, erase_err_addr;
 
   // Flash Memory Properties Connections
   logic [BusAddrW-1:0] flash_addr;
   logic flash_req;
   logic flash_rd_done, flash_prog_done, flash_erase_done;
-  logic flash_mp_error;
+  logic flash_mp_err;
   logic [BusWidth-1:0] flash_prog_data;
   logic flash_prog_last;
   flash_prog_e flash_prog_type;
@@ -165,7 +163,6 @@
   logic rd_op;
   logic prog_op;
   logic erase_op;
-  logic [AllPagesW-1:0] err_addr;
   flash_lcmgr_phase_e phase;
 
   // Flash control arbitration connections to hardware interface
@@ -177,7 +174,7 @@
   logic hw_req;
   logic [top_pkg::TL_AW-1:0] hw_addr;
   logic hw_done;
-  logic hw_err;
+  flash_ctrl_err_t hw_err;
   logic hw_rvalid;
   logic hw_rready;
   logic hw_wvalid;
@@ -191,7 +188,7 @@
 
   // Flash control arbitration connections to software interface
   logic sw_ctrl_done;
-  logic sw_ctrl_err;
+  flash_ctrl_err_t sw_ctrl_err;
 
   // Flash control muxed connections
   flash_ctrl_reg2hw_control_reg_t muxed_ctrl;
@@ -199,6 +196,7 @@
   logic op_start;
   logic [11:0] op_num_words;
   logic [BusAddrW-1:0] op_addr;
+  logic [BusAddrW-1:0] ctrl_err_addr;
   // SW or HW supplied address is out of bounds
   logic op_addr_oob;
   flash_op_e op_type;
@@ -305,6 +303,9 @@
     .clk_i,
     .rst_ni,
 
+    // error output shared by both interfaces
+    .ctrl_err_addr_o(ctrl_err_addr),
+
     // software interface to rd_ctrl / erase_ctrl
     .sw_ctrl_i(reg2hw.control),
     .sw_addr_i(reg2hw.addr.q),
@@ -346,10 +347,13 @@
     .muxed_addr_o(muxed_addr),
     .prog_ack_i(prog_done),
     .prog_err_i(prog_err),
+    .prog_err_addr_i(prog_err_addr),
     .rd_ack_i(rd_done),
     .rd_err_i(rd_err),
+    .rd_err_addr_i(rd_err_addr),
     .erase_ack_i(erase_done),
     .erase_err_i(erase_err),
+    .erase_err_addr_i(erase_err_addr),
 
     // muxed interface to rd_fifo
     .rd_fifo_rvalid_i(rd_fifo_rvalid),
@@ -388,7 +392,6 @@
   assign prog_op       = op_type == FlashOpProgram;
   assign erase_op      = op_type == FlashOpErase;
   assign sw_sel        = if_sel == SwSel;
-  assign op_valid      = prog_op_valid | rd_op_valid | erase_op_valid;
 
   // software privilege to creator seed
   assign creator_seed_priv = lc_creator_seed_sw_rw_en == lc_ctrl_pkg::On;
@@ -524,6 +527,7 @@
     .op_addr_oob_i  (op_addr_oob),
     .op_type_i      (op_prog_type),
     .type_avail_i   (prog_type_en),
+    .op_err_addr_o  (prog_err_addr),
 
     // FIFO Interface
     .data_i         (prog_fifo_rdata),
@@ -538,7 +542,9 @@
     .flash_last_o   (flash_prog_last),
     .flash_type_o   (flash_prog_type),
     .flash_done_i   (flash_prog_done),
-    .flash_error_i  (flash_mp_error)
+    // TODO, pending feedback
+    .flash_phy_err_i(flash_phy_rsp.flash_err),
+    .flash_mp_err_i (flash_mp_err)
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
@@ -602,6 +608,7 @@
     .op_num_words_i (op_num_words),
     .op_done_o      (rd_done),
     .op_err_o       (rd_err),
+    .op_err_addr_o  (rd_err_addr),
     .op_addr_i      (op_addr),
     .op_addr_oob_i  (op_addr_oob),
 
@@ -616,7 +623,9 @@
     .flash_ovfl_o   (rd_flash_ovfl),
     .flash_data_i   (flash_rd_data),
     .flash_done_i   (flash_rd_done),
-    .flash_error_i  (flash_mp_error | flash_rd_err)
+    .flash_mp_err_i (flash_mp_err),
+    .flash_rd_err_i (flash_rd_err),
+    .flash_phy_err_i(flash_phy_rsp.flash_err)
   );
 
   // Erase handler does not consume fifo
@@ -629,13 +638,15 @@
     .op_err_o       (erase_err),
     .op_addr_i      (op_addr),
     .op_addr_oob_i  (op_addr_oob),
+    .op_err_addr_o  (erase_err_addr),
 
     // Flash Macro Interface
     .flash_req_o    (erase_flash_req),
     .flash_addr_o   (erase_flash_addr),
     .flash_op_o     (erase_flash_type),
     .flash_done_i   (flash_erase_done),
-    .flash_error_i  (flash_mp_error)
+    .flash_mp_err_i (flash_mp_err),
+    .flash_phy_err_i(flash_phy_rsp.flash_err)
   );
 
   // Final muxing to flash macro module
@@ -755,8 +766,7 @@
     .rd_done_o(flash_rd_done),
     .prog_done_o(flash_prog_done),
     .erase_done_o(flash_erase_done),
-    .error_o(flash_mp_error),
-    .err_addr_o(err_addr),
+    .error_o(flash_mp_err),
 
     // flash phy interface
     .req_o(flash_phy_req.req),
@@ -780,7 +790,7 @@
   assign hw2reg.op_status.done.d     = 1'b1;
   assign hw2reg.op_status.done.de    = sw_ctrl_done;
   assign hw2reg.op_status.err.d      = 1'b1;
-  assign hw2reg.op_status.err.de     = sw_ctrl_err;
+  assign hw2reg.op_status.err.de     = |sw_ctrl_err;
   assign hw2reg.status.rd_full.d     = rd_fifo_full;
   assign hw2reg.status.rd_full.de    = sw_sel;
   assign hw2reg.status.rd_empty.d    = ~rd_fifo_rvalid;
@@ -855,31 +865,24 @@
   logic [NumAlerts-1:0] alert_srcs;
   logic [NumAlerts-1:0] alert_tests;
 
+  // TODO Add shadow update
+  // An excessive number of recoverable errors may also indicate an attack
   logic recov_err;
-  assign recov_err = flash_phy_rsp.flash_alert_p | ~flash_phy_rsp.flash_alert_n;
+  assign recov_err = sw_ctrl_done & |sw_ctrl_err;
 
-  logic recov_mp_err;
-  assign recov_mp_err = flash_mp_error;
+  logic fatal_err;
+  assign fatal_err = |reg2hw.fault_status;
 
-  logic recov_ecc_err;
-  assign recov_ecc_err = |flash_phy_rsp.ecc_single_err | |flash_phy_rsp.ecc_multi_err;
 
-  logic fatal_intg_err;
-  assign fatal_intg_err = flash_phy_rsp.intg_err | intg_err;
-
-  assign alert_srcs = { fatal_intg_err,
-                        recov_ecc_err,
-                        recov_mp_err,
+  assign alert_srcs = { fatal_err,
                         recov_err
                       };
 
-  assign alert_tests = { reg2hw.alert_test.fatal_intg_err.q & reg2hw.alert_test.fatal_intg_err.qe,
-                         reg2hw.alert_test.recov_ecc_err.q & reg2hw.alert_test.recov_ecc_err.qe,
-                         reg2hw.alert_test.recov_mp_err.q  & reg2hw.alert_test.recov_mp_err.qe,
-                         reg2hw.alert_test.recov_err.q     & reg2hw.alert_test.recov_err.qe
+  assign alert_tests = { reg2hw.alert_test.fatal_err.q & reg2hw.alert_test.fatal_err.qe,
+                         reg2hw.alert_test.recov_err.q & reg2hw.alert_test.recov_err.qe
                        };
 
-  localparam logic [NumAlerts-1:0] IsFatal = {1'b1, 1'b0, 1'b0, 1'b0};
+  localparam logic [NumAlerts-1:0] IsFatal = {1'b1, 1'b0};
   for (genvar i = 0; i < NumAlerts; i++) begin : gen_alert_senders
     prim_alert_sender #(
       .AsyncOn(AlertAsyncOn[i]),
@@ -900,7 +903,7 @@
   // Flash Disable
   //////////////////////////////////////
   assign flash_disable = reg2hw.flash_disable.q ? lc_ctrl_pkg::On :
-                         fatal_intg_err         ? lc_ctrl_pkg::On : lc_ctrl_pkg::Off;
+                         fatal_err              ? lc_ctrl_pkg::On : lc_ctrl_pkg::Off;
 
   lc_ctrl_pkg::lc_tx_t lc_escalate_en;
   prim_lc_sync #(
@@ -918,133 +921,184 @@
   // Errors and Interrupts
   //////////////////////////////////////
 
-  assign hw2reg.err_code.oob_err.d = 1'b1;
-  assign hw2reg.err_code.mp_err.d = 1'b1;
-  assign hw2reg.err_code.ecc_single_err.d = 1'b1;
-  assign hw2reg.err_code.ecc_multi_err.d = 1'b1;
-  assign hw2reg.err_code.flash_err.d = 1'b1;
-  assign hw2reg.err_code.flash_alert.d = 1'b1;
-  assign hw2reg.err_code.oob_err.de = op_valid & op_addr_oob;
-  assign hw2reg.err_code.mp_err.de = flash_mp_error;
-  assign hw2reg.err_code.ecc_single_err.de = |flash_phy_rsp.ecc_single_err;
-  assign hw2reg.err_code.ecc_multi_err.de = |flash_phy_rsp.ecc_multi_err;
-  assign hw2reg.err_code.flash_err.de = flash_phy_rsp.flash_err;
-  assign hw2reg.err_code.flash_alert.de = flash_phy_rsp.flash_alert_p |
-                                          ~flash_phy_rsp.flash_alert_n;
-  assign hw2reg.err_addr.d = err_addr;
-  assign hw2reg.err_addr.de = flash_mp_error;
+  // all software interface errors are treated as synchronous errors
+  assign hw2reg.err_code.oob_err.d        = 1'b1;
+  assign hw2reg.err_code.mp_err.d         = 1'b1;
+  assign hw2reg.err_code.rd_err.d         = 1'b1;
+  assign hw2reg.err_code.prog_win_err.d   = 1'b1;
+  assign hw2reg.err_code.prog_type_err.d  = 1'b1;
+  assign hw2reg.err_code.flash_phy_err.d  = 1'b1;
+  assign hw2reg.err_code.oob_err.de       = sw_ctrl_err.oob_err;
+  assign hw2reg.err_code.mp_err.de        = sw_ctrl_err.mp_err;
+  assign hw2reg.err_code.rd_err.de        = sw_ctrl_err.rd_err;
+  assign hw2reg.err_code.prog_win_err.de  = sw_ctrl_err.prog_win_err;
+  assign hw2reg.err_code.prog_type_err.de = sw_ctrl_err.prog_type_err;
+  assign hw2reg.err_code.flash_phy_err.de = sw_ctrl_err.phy_err;
+  assign hw2reg.err_addr.d                = {reg2hw.addr.q[31:BusAddrW],ctrl_err_addr};
+  assign hw2reg.err_addr.de               = sw_ctrl_err.mp_err |
+                                            sw_ctrl_err.rd_err |
+                                            sw_ctrl_err.phy_err;
 
-  for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_single_err_cons
-    assign hw2reg.ecc_single_err_addr[bank].d  = {flash_phy_rsp.ecc_addr[bank],
-      {BusByteWidth{1'b0}}};
-    assign hw2reg.ecc_single_err_addr[bank].de = flash_phy_rsp.ecc_single_err[bank];
+  // all hardware interface errors are considered faults
+  assign hw2reg.fault_status.oob_err.d        = 1'b1;
+  assign hw2reg.fault_status.mp_err.d         = 1'b1;
+  assign hw2reg.fault_status.rd_err.d         = 1'b1;
+  assign hw2reg.fault_status.prog_win_err.d   = 1'b1;
+  assign hw2reg.fault_status.prog_type_err.d  = 1'b1;
+  assign hw2reg.fault_status.flash_phy_err.d  = 1'b1;
+  assign hw2reg.fault_status.reg_intg_err.d   = 1'b1;
+  assign hw2reg.fault_status.phy_intg_err.d   = 1'b1;
+  assign hw2reg.fault_status.oob_err.de       = hw_err.oob_err;
+  assign hw2reg.fault_status.mp_err.de        = hw_err.mp_err;
+  assign hw2reg.fault_status.rd_err.de        = hw_err.rd_err;
+  assign hw2reg.fault_status.prog_win_err.de  = hw_err.prog_win_err;
+  assign hw2reg.fault_status.prog_type_err.de = hw_err.prog_type_err;
+  assign hw2reg.fault_status.flash_phy_err.de = hw_err.phy_err;
+  assign hw2reg.fault_status.reg_intg_err.de  = intg_err;
+  assign hw2reg.fault_status.phy_intg_err.de  = flash_phy_rsp.intg_err;
+
+  // Correctable ECC count / address
+  for (genvar i = 0; i < NumBanks; i++) begin : gen_ecc_single_err_reg
+    assign hw2reg.ecc_single_err_cnt[i].de = flash_phy_rsp.ecc_single_err[i];
+    assign hw2reg.ecc_single_err_cnt[i].d = &reg2hw.ecc_single_err_cnt[i].q ?
+                                            reg2hw.ecc_single_err_cnt[i].q :
+                                            reg2hw.ecc_single_err_cnt[i].q + 1'b1;
+
+    assign hw2reg.ecc_single_err_addr[i].de = flash_phy_rsp.ecc_single_err[i];
+    assign hw2reg.ecc_single_err_addr[i].d = {flash_phy_rsp.ecc_addr[i], {BusByteWidth{1'b0}}};
   end
 
-  for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_multi_err_cons
-    assign hw2reg.ecc_multi_err_addr[bank].d  = {flash_phy_rsp.ecc_addr[bank],
-      {BusByteWidth{1'b0}}};
-    assign hw2reg.ecc_multi_err_addr[bank].de = flash_phy_rsp.ecc_multi_err[bank];
-  end
-
-  logic [7:0] single_err_cnt_d, multi_err_cnt_d;
-  always_comb begin
-    single_err_cnt_d = reg2hw.ecc_single_err_cnt.q;
-    multi_err_cnt_d = reg2hw.ecc_multi_err_cnt.q;
-
-    if (|flash_phy_rsp.ecc_single_err && single_err_cnt_d < '1) begin
-      single_err_cnt_d = single_err_cnt_d + 1'b1;
-    end
-
-    if (|flash_phy_rsp.ecc_multi_err && multi_err_cnt_d < '1) begin
-      multi_err_cnt_d = multi_err_cnt_d + 1'b1;
-    end
-  end
-
-  // feed back in error count
-  assign hw2reg.ecc_single_err_cnt.de = 1'b1;
-  assign hw2reg.ecc_single_err_cnt.d  = single_err_cnt_d;
-  assign hw2reg.ecc_multi_err_cnt.de  = 1'b1;
-  assign hw2reg.ecc_multi_err_cnt.d   = multi_err_cnt_d;
-
-  // err code interrupt event
-  flash_ctrl_reg2hw_err_code_reg_t err_code_d, err_code_q;
-  logic err_code_intr_event;
-
-  assign err_code_d = reg2hw.err_code & reg2hw.err_code_intr_en;
-
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      err_code_q <= '0;
-    end else begin
-      err_code_q <= err_code_d;
-    end
-  end
-
-  assign err_code_intr_event = err_code_d != err_code_q;
-
   // general interrupt events
-  logic [3:0] intr_src_d;
-  logic [3:0] intr_src_q;
+  logic [LastIntrIdx-1:0] intr_event;
 
-  assign intr_src_d = { ~prog_fifo_rvalid,
-                        reg2hw.fifo_lvl.prog.q == prog_fifo_depth,
-                        rd_fifo_full,
-                        reg2hw.fifo_lvl.rd.q == rd_fifo_depth
-                      };
+  prim_edge_detector #(
+    .Width(1),
+    .ResetValue(1)
+  ) u_prog_empty_event (
+    .clk_i,
+    .rst_ni,
+    .d_i(~prog_fifo_rvalid),
+    .q_sync_o(),
+    .q_posedge_pulse_o(intr_event[ProgEmpty]),
+    .q_negedge_pulse_o()
+  );
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      intr_src_q <= 4'h8; //prog_fifo is empty by default
-    end else begin
-      if (sw_sel) begin
-        intr_src_q[3:0] <= intr_src_d[3:0];
-      end
-    end
-  end
+  prim_intr_hw #(.Width(1)) u_intr_prog_empty (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[ProgEmpty]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.prog_empty.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.prog_empty.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.prog_empty.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.prog_empty.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.prog_empty.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.prog_empty.d),
+    .intr_o                 (intr_prog_empty_o)
+  );
 
-  // interrupt events
-  logic [4:0] intr_assert;
-  assign intr_assert[4] = err_code_intr_event;
-  assign intr_assert[3:0] = ~intr_src_q & intr_src_d;
+  prim_edge_detector #(
+    .Width(1),
+    .ResetValue(0)
+  ) u_prog_lvl_event (
+    .clk_i,
+    .rst_ni,
+    .d_i(reg2hw.fifo_lvl.prog.q == prog_fifo_depth),
+    .q_sync_o(),
+    .q_posedge_pulse_o(intr_event[ProgLvl]),
+    .q_negedge_pulse_o()
+  );
 
-  assign intr_prog_empty_o = reg2hw.intr_enable.prog_empty.q & reg2hw.intr_state.prog_empty.q;
-  assign intr_prog_lvl_o = reg2hw.intr_enable.prog_lvl.q & reg2hw.intr_state.prog_lvl.q;
-  assign intr_rd_full_o = reg2hw.intr_enable.rd_full.q & reg2hw.intr_state.rd_full.q;
-  assign intr_rd_lvl_o = reg2hw.intr_enable.rd_lvl.q & reg2hw.intr_state.rd_lvl.q;
-  assign intr_op_done_o = reg2hw.intr_enable.op_done.q & reg2hw.intr_state.op_done.q;
-  assign intr_err_o = reg2hw.intr_enable.err.q & reg2hw.intr_state.err.q;
+  prim_intr_hw #(.Width(1)) u_intr_prog_lvl (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[ProgLvl]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.prog_lvl.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.prog_lvl.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.prog_lvl.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.prog_lvl.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.prog_lvl.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.prog_lvl.d),
+    .intr_o                 (intr_prog_lvl_o)
+  );
 
-  assign hw2reg.intr_state.err.d  = 1'b1;
-  assign hw2reg.intr_state.err.de = intr_assert[4] |
-                                    (reg2hw.intr_test.err.qe  &
-                                    reg2hw.intr_test.err.q);
+  prim_edge_detector #(
+    .Width(1),
+    .ResetValue(0)
+  ) u_rd_full_event (
+    .clk_i,
+    .rst_ni,
+    .d_i(rd_fifo_full),
+    .q_sync_o(),
+    .q_posedge_pulse_o(intr_event[RdFull]),
+    .q_negedge_pulse_o()
+  );
 
-  assign hw2reg.intr_state.prog_empty.d  = 1'b1;
-  assign hw2reg.intr_state.prog_empty.de = intr_assert[3]  |
-                                           (reg2hw.intr_test.prog_empty.qe  &
-                                           reg2hw.intr_test.prog_empty.q);
+  prim_intr_hw #(.Width(1)) u_intr_rd_full (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[RdFull]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.rd_full.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.rd_full.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.rd_full.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.rd_full.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.rd_full.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.rd_full.d),
+    .intr_o                 (intr_rd_full_o)
+  );
 
-  assign hw2reg.intr_state.prog_lvl.d  = 1'b1;
-  assign hw2reg.intr_state.prog_lvl.de = intr_assert[2]  |
-                                         (reg2hw.intr_test.prog_lvl.qe  &
-                                         reg2hw.intr_test.prog_lvl.q);
+  prim_edge_detector #(
+    .Width(1),
+    .ResetValue(0)
+  ) u_rd_lvl_event (
+    .clk_i,
+    .rst_ni,
+    .d_i(reg2hw.fifo_lvl.rd.q == rd_fifo_depth),
+    .q_sync_o(),
+    .q_posedge_pulse_o(intr_event[RdLvl]),
+    .q_negedge_pulse_o()
+  );
 
-  assign hw2reg.intr_state.rd_full.d  = 1'b1;
-  assign hw2reg.intr_state.rd_full.de = intr_assert[1] |
-                                        (reg2hw.intr_test.rd_full.qe  &
-                                        reg2hw.intr_test.rd_full.q);
+  prim_intr_hw #(.Width(1)) u_intr_rd_lvl (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[RdLvl]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.rd_lvl.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.rd_lvl.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.rd_lvl.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.rd_lvl.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.rd_lvl.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.rd_lvl.d),
+    .intr_o                 (intr_rd_lvl_o)
+  );
 
-  assign hw2reg.intr_state.rd_lvl.d  = 1'b1;
-  assign hw2reg.intr_state.rd_lvl.de =  intr_assert[0] |
-                                       (reg2hw.intr_test.rd_lvl.qe  &
-                                       reg2hw.intr_test.rd_lvl.q);
+  assign intr_event[OpDone] = sw_ctrl_done;
+  assign intr_event[CorrErr] = |flash_phy_rsp.ecc_single_err;
 
-  assign hw2reg.intr_state.op_done.d  = 1'b1;
-  assign hw2reg.intr_state.op_done.de = sw_ctrl_done  |
-                                        (reg2hw.intr_test.op_done.qe  &
-                                        reg2hw.intr_test.op_done.q);
+  prim_intr_hw #(.Width(1)) u_intr_op_done (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[OpDone]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.op_done.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.op_done.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.op_done.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.op_done.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.op_done.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.op_done.d),
+    .intr_o                 (intr_op_done_o)
+  );
 
-
+  prim_intr_hw #(.Width(1)) u_intr_corr_err (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[CorrErr]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.corr_err.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.corr_err.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.corr_err.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.corr_err.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.corr_err.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.corr_err.d),
+    .intr_o                 (intr_corr_err_o)
+  );
 
   // Unused bits
   logic [BusByteWidth-1:0] unused_byte_sel;
@@ -1143,12 +1197,15 @@
   `ASSERT_KNOWN(IntrProgRdFullKnownO_A, intr_rd_full_o   )
   `ASSERT_KNOWN(IntrRdLvlKnownO_A,      intr_rd_lvl_o    )
   `ASSERT_KNOWN(IntrOpDoneKnownO_A,     intr_op_done_o   )
-  `ASSERT_KNOWN(IntrErrO_A,             intr_err_o       )
+  `ASSERT_KNOWN(IntrErrO_A,             intr_corr_err_o  )
 
-
+  // combined indication that an operation has started
+  // This is used only for assertions
+  logic unused_op_valid;
+  assign unused_op_valid = prog_op_valid | rd_op_valid | erase_op_valid;
 
   // if there is an out of bounds error, flash request should never assert
-  `ASSERT(OutofBoundsReq_A, op_valid & op_addr_oob |-> ~flash_phy_req.req)
+  `ASSERT(OutofBoundsReq_A, unused_op_valid & op_addr_oob |-> ~flash_phy_req.req)
 
   // add more assertions
 
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl b/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl
index 545e2ec..d41b4bb 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl
@@ -364,10 +364,7 @@
     logic [BusWidth-1:0] rd_data;
     logic                init_busy;
     logic                flash_err;
-    logic                flash_alert_p;
-    logic                flash_alert_n;
     logic [NumBanks-1:0] ecc_single_err;
-    logic [NumBanks-1:0] ecc_multi_err;
     logic [NumBanks-1:0][BusAddrW-1:0] ecc_addr;
     jtag_pkg::jtag_rsp_t jtag_rsp;
     logic                intg_err;
@@ -383,10 +380,7 @@
     rd_data:            '0,
     init_busy:          1'b0,
     flash_err:          1'b0,
-    flash_alert_p:      1'b0,
-    flash_alert_n:      1'b1,
     ecc_single_err:     '0,
-    ecc_multi_err:      '0,
     ecc_addr:           '0,
     jtag_rsp:           '0,
     intg_err:           '0
@@ -468,6 +462,27 @@
     FlashLcDftLast
   } flash_lc_jtag_e;
 
+  // Error bit positioning
+  typedef struct packed {
+    logic oob_err;
+    logic mp_err;
+    logic rd_err;
+    logic prog_win_err;
+    logic prog_type_err;
+    logic phy_err;
+  } flash_ctrl_err_t;
+
+  // interrupt bit positioning
+  typedef enum logic[2:0] {
+    ProgEmpty,
+    ProgLvl,
+    RdFull,
+    RdLvl,
+    OpDone,
+    CorrErr,
+    LastIntrIdx
+  } flash_ctrl_intr_e;
+
   // find the max number pages among info types
   function automatic integer max_info_pages(int infos[InfoTypes]);
     int current_max = 0;
diff --git a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_pkg.sv b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_pkg.sv
index 9695ad0..fab4915 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_pkg.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_pkg.sv
@@ -22,7 +22,7 @@
 
   // parameters
   parameter string LIST_OF_ALERTS[] = {
-    "recov_err", "recov_mp_err", "recov_ecc_err", "fatal_intg_err"
+    "recov_err", "fatal_err"
   };
 
   parameter uint NUM_ALERTS = 4;
diff --git a/hw/ip/flash_ctrl/dv/tb/tb.sv b/hw/ip/flash_ctrl/dv/tb/tb.sv
index d47739f..1b2a162 100644
--- a/hw/ip/flash_ctrl/dv/tb/tb.sv
+++ b/hw/ip/flash_ctrl/dv/tb/tb.sv
@@ -99,7 +99,7 @@
     .intr_rd_full_o     (intr_rd_full   ),
     .intr_rd_lvl_o      (intr_rd_lvl    ),
     .intr_op_done_o     (intr_op_done   ),
-    .intr_err_o         (intr_err       ),
+    .intr_corr_err_o    (intr_err       ),
     .alert_rx_i         (alert_rx       ),
     .alert_tx_o         (alert_tx       )
   );
diff --git a/hw/ip/flash_ctrl/flash_ctrl.core b/hw/ip/flash_ctrl/flash_ctrl.core
index a52c69b..0466737 100644
--- a/hw/ip/flash_ctrl/flash_ctrl.core
+++ b/hw/ip/flash_ctrl/flash_ctrl.core
@@ -10,6 +10,7 @@
     depend:
       - lowrisc:ip:tlul
       - lowrisc:prim:all
+      - lowrisc:prim:edge_detector
       - lowrisc:prim:secded
       - lowrisc:prim:lfsr
       - lowrisc:prim:flash
diff --git a/hw/ip/flash_ctrl/lint/flash_ctrl.waiver b/hw/ip/flash_ctrl/lint/flash_ctrl.waiver
index ad4073d..171ab8e 100644
--- a/hw/ip/flash_ctrl/lint/flash_ctrl.waiver
+++ b/hw/ip/flash_ctrl/lint/flash_ctrl.waiver
@@ -21,3 +21,7 @@
 
 waive -rules INPUT_NOT_READ -location {prim_flop_2sync.sv} -regexp {Input port.*} \
       -comment "Silience prim related errors"
+
+# State is handled as part of "default"
+waive -rules MISSING_STATE -location {flash_phy_core.sv} \
+      -regexp {.*'StDisable' does not have corresponding case branch tag}
\ No newline at end of file
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
index 029a5dd..fae6622 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
@@ -58,7 +58,7 @@
   output logic cio_tdo_o,
 
   // Interrupts
-  output logic intr_err_o,        // ERR_CODE is non-zero
+  output logic intr_corr_err_o,   // Correctable errors encountered
   output logic intr_prog_empty_o, // Program fifo is empty
   output logic intr_prog_lvl_o,   // Program fifo is empty
   output logic intr_rd_full_o,    // Read fifo is full
@@ -144,18 +144,16 @@
   flash_erase_e erase_flash_type;
   logic erase_op_valid;
 
-  // combined indication that an operation has started
-  logic op_valid;
-
   // Done / Error signaling from ctrl modules
   logic prog_done, rd_done, erase_done;
-  logic prog_err, rd_err, erase_err;
+  flash_ctrl_err_t prog_err, rd_err, erase_err;
+  logic [BusAddrW-1:0] prog_err_addr, rd_err_addr, erase_err_addr;
 
   // Flash Memory Properties Connections
   logic [BusAddrW-1:0] flash_addr;
   logic flash_req;
   logic flash_rd_done, flash_prog_done, flash_erase_done;
-  logic flash_mp_error;
+  logic flash_mp_err;
   logic [BusWidth-1:0] flash_prog_data;
   logic flash_prog_last;
   flash_prog_e flash_prog_type;
@@ -165,7 +163,6 @@
   logic rd_op;
   logic prog_op;
   logic erase_op;
-  logic [AllPagesW-1:0] err_addr;
   flash_lcmgr_phase_e phase;
 
   // Flash control arbitration connections to hardware interface
@@ -177,7 +174,7 @@
   logic hw_req;
   logic [top_pkg::TL_AW-1:0] hw_addr;
   logic hw_done;
-  logic hw_err;
+  flash_ctrl_err_t hw_err;
   logic hw_rvalid;
   logic hw_rready;
   logic hw_wvalid;
@@ -191,7 +188,7 @@
 
   // Flash control arbitration connections to software interface
   logic sw_ctrl_done;
-  logic sw_ctrl_err;
+  flash_ctrl_err_t sw_ctrl_err;
 
   // Flash control muxed connections
   flash_ctrl_reg2hw_control_reg_t muxed_ctrl;
@@ -199,6 +196,7 @@
   logic op_start;
   logic [11:0] op_num_words;
   logic [BusAddrW-1:0] op_addr;
+  logic [BusAddrW-1:0] ctrl_err_addr;
   // SW or HW supplied address is out of bounds
   logic op_addr_oob;
   flash_op_e op_type;
@@ -305,6 +303,9 @@
     .clk_i,
     .rst_ni,
 
+    // error output shared by both interfaces
+    .ctrl_err_addr_o(ctrl_err_addr),
+
     // software interface to rd_ctrl / erase_ctrl
     .sw_ctrl_i(reg2hw.control),
     .sw_addr_i(reg2hw.addr.q),
@@ -346,10 +347,13 @@
     .muxed_addr_o(muxed_addr),
     .prog_ack_i(prog_done),
     .prog_err_i(prog_err),
+    .prog_err_addr_i(prog_err_addr),
     .rd_ack_i(rd_done),
     .rd_err_i(rd_err),
+    .rd_err_addr_i(rd_err_addr),
     .erase_ack_i(erase_done),
     .erase_err_i(erase_err),
+    .erase_err_addr_i(erase_err_addr),
 
     // muxed interface to rd_fifo
     .rd_fifo_rvalid_i(rd_fifo_rvalid),
@@ -388,7 +392,6 @@
   assign prog_op       = op_type == FlashOpProgram;
   assign erase_op      = op_type == FlashOpErase;
   assign sw_sel        = if_sel == SwSel;
-  assign op_valid      = prog_op_valid | rd_op_valid | erase_op_valid;
 
   // software privilege to creator seed
   assign creator_seed_priv = lc_creator_seed_sw_rw_en == lc_ctrl_pkg::On;
@@ -524,6 +527,7 @@
     .op_addr_oob_i  (op_addr_oob),
     .op_type_i      (op_prog_type),
     .type_avail_i   (prog_type_en),
+    .op_err_addr_o  (prog_err_addr),
 
     // FIFO Interface
     .data_i         (prog_fifo_rdata),
@@ -538,7 +542,9 @@
     .flash_last_o   (flash_prog_last),
     .flash_type_o   (flash_prog_type),
     .flash_done_i   (flash_prog_done),
-    .flash_error_i  (flash_mp_error)
+    // TODO, pending feedback
+    .flash_phy_err_i(flash_phy_rsp.flash_err),
+    .flash_mp_err_i (flash_mp_err)
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
@@ -602,6 +608,7 @@
     .op_num_words_i (op_num_words),
     .op_done_o      (rd_done),
     .op_err_o       (rd_err),
+    .op_err_addr_o  (rd_err_addr),
     .op_addr_i      (op_addr),
     .op_addr_oob_i  (op_addr_oob),
 
@@ -616,7 +623,9 @@
     .flash_ovfl_o   (rd_flash_ovfl),
     .flash_data_i   (flash_rd_data),
     .flash_done_i   (flash_rd_done),
-    .flash_error_i  (flash_mp_error | flash_rd_err)
+    .flash_mp_err_i (flash_mp_err),
+    .flash_rd_err_i (flash_rd_err),
+    .flash_phy_err_i(flash_phy_rsp.flash_err)
   );
 
   // Erase handler does not consume fifo
@@ -629,13 +638,15 @@
     .op_err_o       (erase_err),
     .op_addr_i      (op_addr),
     .op_addr_oob_i  (op_addr_oob),
+    .op_err_addr_o  (erase_err_addr),
 
     // Flash Macro Interface
     .flash_req_o    (erase_flash_req),
     .flash_addr_o   (erase_flash_addr),
     .flash_op_o     (erase_flash_type),
     .flash_done_i   (flash_erase_done),
-    .flash_error_i  (flash_mp_error)
+    .flash_mp_err_i (flash_mp_err),
+    .flash_phy_err_i(flash_phy_rsp.flash_err)
   );
 
   // Final muxing to flash macro module
@@ -756,8 +767,7 @@
     .rd_done_o(flash_rd_done),
     .prog_done_o(flash_prog_done),
     .erase_done_o(flash_erase_done),
-    .error_o(flash_mp_error),
-    .err_addr_o(err_addr),
+    .error_o(flash_mp_err),
 
     // flash phy interface
     .req_o(flash_phy_req.req),
@@ -781,7 +791,7 @@
   assign hw2reg.op_status.done.d     = 1'b1;
   assign hw2reg.op_status.done.de    = sw_ctrl_done;
   assign hw2reg.op_status.err.d      = 1'b1;
-  assign hw2reg.op_status.err.de     = sw_ctrl_err;
+  assign hw2reg.op_status.err.de     = |sw_ctrl_err;
   assign hw2reg.status.rd_full.d     = rd_fifo_full;
   assign hw2reg.status.rd_full.de    = sw_sel;
   assign hw2reg.status.rd_empty.d    = ~rd_fifo_rvalid;
@@ -856,31 +866,24 @@
   logic [NumAlerts-1:0] alert_srcs;
   logic [NumAlerts-1:0] alert_tests;
 
+  // TODO Add shadow update
+  // An excessive number of recoverable errors may also indicate an attack
   logic recov_err;
-  assign recov_err = flash_phy_rsp.flash_alert_p | ~flash_phy_rsp.flash_alert_n;
+  assign recov_err = sw_ctrl_done & |sw_ctrl_err;
 
-  logic recov_mp_err;
-  assign recov_mp_err = flash_mp_error;
+  logic fatal_err;
+  assign fatal_err = |reg2hw.fault_status;
 
-  logic recov_ecc_err;
-  assign recov_ecc_err = |flash_phy_rsp.ecc_single_err | |flash_phy_rsp.ecc_multi_err;
 
-  logic fatal_intg_err;
-  assign fatal_intg_err = flash_phy_rsp.intg_err | intg_err;
-
-  assign alert_srcs = { fatal_intg_err,
-                        recov_ecc_err,
-                        recov_mp_err,
+  assign alert_srcs = { fatal_err,
                         recov_err
                       };
 
-  assign alert_tests = { reg2hw.alert_test.fatal_intg_err.q & reg2hw.alert_test.fatal_intg_err.qe,
-                         reg2hw.alert_test.recov_ecc_err.q & reg2hw.alert_test.recov_ecc_err.qe,
-                         reg2hw.alert_test.recov_mp_err.q  & reg2hw.alert_test.recov_mp_err.qe,
-                         reg2hw.alert_test.recov_err.q     & reg2hw.alert_test.recov_err.qe
+  assign alert_tests = { reg2hw.alert_test.fatal_err.q & reg2hw.alert_test.fatal_err.qe,
+                         reg2hw.alert_test.recov_err.q & reg2hw.alert_test.recov_err.qe
                        };
 
-  localparam logic [NumAlerts-1:0] IsFatal = {1'b1, 1'b0, 1'b0, 1'b0};
+  localparam logic [NumAlerts-1:0] IsFatal = {1'b1, 1'b0};
   for (genvar i = 0; i < NumAlerts; i++) begin : gen_alert_senders
     prim_alert_sender #(
       .AsyncOn(AlertAsyncOn[i]),
@@ -901,7 +904,7 @@
   // Flash Disable
   //////////////////////////////////////
   assign flash_disable = reg2hw.flash_disable.q ? lc_ctrl_pkg::On :
-                         fatal_intg_err         ? lc_ctrl_pkg::On : lc_ctrl_pkg::Off;
+                         fatal_err              ? lc_ctrl_pkg::On : lc_ctrl_pkg::Off;
 
   lc_ctrl_pkg::lc_tx_t lc_escalate_en;
   prim_lc_sync #(
@@ -919,133 +922,184 @@
   // Errors and Interrupts
   //////////////////////////////////////
 
-  assign hw2reg.err_code.oob_err.d = 1'b1;
-  assign hw2reg.err_code.mp_err.d = 1'b1;
-  assign hw2reg.err_code.ecc_single_err.d = 1'b1;
-  assign hw2reg.err_code.ecc_multi_err.d = 1'b1;
-  assign hw2reg.err_code.flash_err.d = 1'b1;
-  assign hw2reg.err_code.flash_alert.d = 1'b1;
-  assign hw2reg.err_code.oob_err.de = op_valid & op_addr_oob;
-  assign hw2reg.err_code.mp_err.de = flash_mp_error;
-  assign hw2reg.err_code.ecc_single_err.de = |flash_phy_rsp.ecc_single_err;
-  assign hw2reg.err_code.ecc_multi_err.de = |flash_phy_rsp.ecc_multi_err;
-  assign hw2reg.err_code.flash_err.de = flash_phy_rsp.flash_err;
-  assign hw2reg.err_code.flash_alert.de = flash_phy_rsp.flash_alert_p |
-                                          ~flash_phy_rsp.flash_alert_n;
-  assign hw2reg.err_addr.d = err_addr;
-  assign hw2reg.err_addr.de = flash_mp_error;
+  // all software interface errors are treated as synchronous errors
+  assign hw2reg.err_code.oob_err.d        = 1'b1;
+  assign hw2reg.err_code.mp_err.d         = 1'b1;
+  assign hw2reg.err_code.rd_err.d         = 1'b1;
+  assign hw2reg.err_code.prog_win_err.d   = 1'b1;
+  assign hw2reg.err_code.prog_type_err.d  = 1'b1;
+  assign hw2reg.err_code.flash_phy_err.d  = 1'b1;
+  assign hw2reg.err_code.oob_err.de       = sw_ctrl_err.oob_err;
+  assign hw2reg.err_code.mp_err.de        = sw_ctrl_err.mp_err;
+  assign hw2reg.err_code.rd_err.de        = sw_ctrl_err.rd_err;
+  assign hw2reg.err_code.prog_win_err.de  = sw_ctrl_err.prog_win_err;
+  assign hw2reg.err_code.prog_type_err.de = sw_ctrl_err.prog_type_err;
+  assign hw2reg.err_code.flash_phy_err.de = sw_ctrl_err.phy_err;
+  assign hw2reg.err_addr.d                = {reg2hw.addr.q[31:BusAddrW],ctrl_err_addr};
+  assign hw2reg.err_addr.de               = sw_ctrl_err.mp_err |
+                                            sw_ctrl_err.rd_err |
+                                            sw_ctrl_err.phy_err;
 
-  for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_single_err_cons
-    assign hw2reg.ecc_single_err_addr[bank].d  = {flash_phy_rsp.ecc_addr[bank],
-      {BusByteWidth{1'b0}}};
-    assign hw2reg.ecc_single_err_addr[bank].de = flash_phy_rsp.ecc_single_err[bank];
+  // all hardware interface errors are considered faults
+  assign hw2reg.fault_status.oob_err.d        = 1'b1;
+  assign hw2reg.fault_status.mp_err.d         = 1'b1;
+  assign hw2reg.fault_status.rd_err.d         = 1'b1;
+  assign hw2reg.fault_status.prog_win_err.d   = 1'b1;
+  assign hw2reg.fault_status.prog_type_err.d  = 1'b1;
+  assign hw2reg.fault_status.flash_phy_err.d  = 1'b1;
+  assign hw2reg.fault_status.reg_intg_err.d   = 1'b1;
+  assign hw2reg.fault_status.phy_intg_err.d   = 1'b1;
+  assign hw2reg.fault_status.oob_err.de       = hw_err.oob_err;
+  assign hw2reg.fault_status.mp_err.de        = hw_err.mp_err;
+  assign hw2reg.fault_status.rd_err.de        = hw_err.rd_err;
+  assign hw2reg.fault_status.prog_win_err.de  = hw_err.prog_win_err;
+  assign hw2reg.fault_status.prog_type_err.de = hw_err.prog_type_err;
+  assign hw2reg.fault_status.flash_phy_err.de = hw_err.phy_err;
+  assign hw2reg.fault_status.reg_intg_err.de  = intg_err;
+  assign hw2reg.fault_status.phy_intg_err.de  = flash_phy_rsp.intg_err;
+
+  // Correctable ECC count / address
+  for (genvar i = 0; i < NumBanks; i++) begin : gen_ecc_single_err_reg
+    assign hw2reg.ecc_single_err_cnt[i].de = flash_phy_rsp.ecc_single_err[i];
+    assign hw2reg.ecc_single_err_cnt[i].d = &reg2hw.ecc_single_err_cnt[i].q ?
+                                            reg2hw.ecc_single_err_cnt[i].q :
+                                            reg2hw.ecc_single_err_cnt[i].q + 1'b1;
+
+    assign hw2reg.ecc_single_err_addr[i].de = flash_phy_rsp.ecc_single_err[i];
+    assign hw2reg.ecc_single_err_addr[i].d = {flash_phy_rsp.ecc_addr[i], {BusByteWidth{1'b0}}};
   end
 
-  for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_multi_err_cons
-    assign hw2reg.ecc_multi_err_addr[bank].d  = {flash_phy_rsp.ecc_addr[bank],
-      {BusByteWidth{1'b0}}};
-    assign hw2reg.ecc_multi_err_addr[bank].de = flash_phy_rsp.ecc_multi_err[bank];
-  end
-
-  logic [7:0] single_err_cnt_d, multi_err_cnt_d;
-  always_comb begin
-    single_err_cnt_d = reg2hw.ecc_single_err_cnt.q;
-    multi_err_cnt_d = reg2hw.ecc_multi_err_cnt.q;
-
-    if (|flash_phy_rsp.ecc_single_err && single_err_cnt_d < '1) begin
-      single_err_cnt_d = single_err_cnt_d + 1'b1;
-    end
-
-    if (|flash_phy_rsp.ecc_multi_err && multi_err_cnt_d < '1) begin
-      multi_err_cnt_d = multi_err_cnt_d + 1'b1;
-    end
-  end
-
-  // feed back in error count
-  assign hw2reg.ecc_single_err_cnt.de = 1'b1;
-  assign hw2reg.ecc_single_err_cnt.d  = single_err_cnt_d;
-  assign hw2reg.ecc_multi_err_cnt.de  = 1'b1;
-  assign hw2reg.ecc_multi_err_cnt.d   = multi_err_cnt_d;
-
-  // err code interrupt event
-  flash_ctrl_reg2hw_err_code_reg_t err_code_d, err_code_q;
-  logic err_code_intr_event;
-
-  assign err_code_d = reg2hw.err_code & reg2hw.err_code_intr_en;
-
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      err_code_q <= '0;
-    end else begin
-      err_code_q <= err_code_d;
-    end
-  end
-
-  assign err_code_intr_event = err_code_d != err_code_q;
-
   // general interrupt events
-  logic [3:0] intr_src_d;
-  logic [3:0] intr_src_q;
+  logic [LastIntrIdx-1:0] intr_event;
 
-  assign intr_src_d = { ~prog_fifo_rvalid,
-                        reg2hw.fifo_lvl.prog.q == prog_fifo_depth,
-                        rd_fifo_full,
-                        reg2hw.fifo_lvl.rd.q == rd_fifo_depth
-                      };
+  prim_edge_detector #(
+    .Width(1),
+    .ResetValue(1)
+  ) u_prog_empty_event (
+    .clk_i,
+    .rst_ni,
+    .d_i(~prog_fifo_rvalid),
+    .q_sync_o(),
+    .q_posedge_pulse_o(intr_event[ProgEmpty]),
+    .q_negedge_pulse_o()
+  );
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      intr_src_q <= 4'h8; //prog_fifo is empty by default
-    end else begin
-      if (sw_sel) begin
-        intr_src_q[3:0] <= intr_src_d[3:0];
-      end
-    end
-  end
+  prim_intr_hw #(.Width(1)) u_intr_prog_empty (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[ProgEmpty]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.prog_empty.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.prog_empty.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.prog_empty.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.prog_empty.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.prog_empty.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.prog_empty.d),
+    .intr_o                 (intr_prog_empty_o)
+  );
 
-  // interrupt events
-  logic [4:0] intr_assert;
-  assign intr_assert[4] = err_code_intr_event;
-  assign intr_assert[3:0] = ~intr_src_q & intr_src_d;
+  prim_edge_detector #(
+    .Width(1),
+    .ResetValue(0)
+  ) u_prog_lvl_event (
+    .clk_i,
+    .rst_ni,
+    .d_i(reg2hw.fifo_lvl.prog.q == prog_fifo_depth),
+    .q_sync_o(),
+    .q_posedge_pulse_o(intr_event[ProgLvl]),
+    .q_negedge_pulse_o()
+  );
 
-  assign intr_prog_empty_o = reg2hw.intr_enable.prog_empty.q & reg2hw.intr_state.prog_empty.q;
-  assign intr_prog_lvl_o = reg2hw.intr_enable.prog_lvl.q & reg2hw.intr_state.prog_lvl.q;
-  assign intr_rd_full_o = reg2hw.intr_enable.rd_full.q & reg2hw.intr_state.rd_full.q;
-  assign intr_rd_lvl_o = reg2hw.intr_enable.rd_lvl.q & reg2hw.intr_state.rd_lvl.q;
-  assign intr_op_done_o = reg2hw.intr_enable.op_done.q & reg2hw.intr_state.op_done.q;
-  assign intr_err_o = reg2hw.intr_enable.err.q & reg2hw.intr_state.err.q;
+  prim_intr_hw #(.Width(1)) u_intr_prog_lvl (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[ProgLvl]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.prog_lvl.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.prog_lvl.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.prog_lvl.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.prog_lvl.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.prog_lvl.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.prog_lvl.d),
+    .intr_o                 (intr_prog_lvl_o)
+  );
 
-  assign hw2reg.intr_state.err.d  = 1'b1;
-  assign hw2reg.intr_state.err.de = intr_assert[4] |
-                                    (reg2hw.intr_test.err.qe  &
-                                    reg2hw.intr_test.err.q);
+  prim_edge_detector #(
+    .Width(1),
+    .ResetValue(0)
+  ) u_rd_full_event (
+    .clk_i,
+    .rst_ni,
+    .d_i(rd_fifo_full),
+    .q_sync_o(),
+    .q_posedge_pulse_o(intr_event[RdFull]),
+    .q_negedge_pulse_o()
+  );
 
-  assign hw2reg.intr_state.prog_empty.d  = 1'b1;
-  assign hw2reg.intr_state.prog_empty.de = intr_assert[3]  |
-                                           (reg2hw.intr_test.prog_empty.qe  &
-                                           reg2hw.intr_test.prog_empty.q);
+  prim_intr_hw #(.Width(1)) u_intr_rd_full (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[RdFull]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.rd_full.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.rd_full.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.rd_full.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.rd_full.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.rd_full.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.rd_full.d),
+    .intr_o                 (intr_rd_full_o)
+  );
 
-  assign hw2reg.intr_state.prog_lvl.d  = 1'b1;
-  assign hw2reg.intr_state.prog_lvl.de = intr_assert[2]  |
-                                         (reg2hw.intr_test.prog_lvl.qe  &
-                                         reg2hw.intr_test.prog_lvl.q);
+  prim_edge_detector #(
+    .Width(1),
+    .ResetValue(0)
+  ) u_rd_lvl_event (
+    .clk_i,
+    .rst_ni,
+    .d_i(reg2hw.fifo_lvl.rd.q == rd_fifo_depth),
+    .q_sync_o(),
+    .q_posedge_pulse_o(intr_event[RdLvl]),
+    .q_negedge_pulse_o()
+  );
 
-  assign hw2reg.intr_state.rd_full.d  = 1'b1;
-  assign hw2reg.intr_state.rd_full.de = intr_assert[1] |
-                                        (reg2hw.intr_test.rd_full.qe  &
-                                        reg2hw.intr_test.rd_full.q);
+  prim_intr_hw #(.Width(1)) u_intr_rd_lvl (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[RdLvl]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.rd_lvl.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.rd_lvl.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.rd_lvl.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.rd_lvl.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.rd_lvl.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.rd_lvl.d),
+    .intr_o                 (intr_rd_lvl_o)
+  );
 
-  assign hw2reg.intr_state.rd_lvl.d  = 1'b1;
-  assign hw2reg.intr_state.rd_lvl.de =  intr_assert[0] |
-                                       (reg2hw.intr_test.rd_lvl.qe  &
-                                       reg2hw.intr_test.rd_lvl.q);
+  assign intr_event[OpDone] = sw_ctrl_done;
+  assign intr_event[CorrErr] = |flash_phy_rsp.ecc_single_err;
 
-  assign hw2reg.intr_state.op_done.d  = 1'b1;
-  assign hw2reg.intr_state.op_done.de = sw_ctrl_done  |
-                                        (reg2hw.intr_test.op_done.qe  &
-                                        reg2hw.intr_test.op_done.q);
+  prim_intr_hw #(.Width(1)) u_intr_op_done (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[OpDone]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.op_done.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.op_done.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.op_done.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.op_done.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.op_done.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.op_done.d),
+    .intr_o                 (intr_op_done_o)
+  );
 
-
+  prim_intr_hw #(.Width(1)) u_intr_corr_err (
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event[CorrErr]),
+    .reg2hw_intr_enable_q_i (reg2hw.intr_enable.corr_err.q),
+    .reg2hw_intr_test_q_i   (reg2hw.intr_test.corr_err.q),
+    .reg2hw_intr_test_qe_i  (reg2hw.intr_test.corr_err.qe),
+    .reg2hw_intr_state_q_i  (reg2hw.intr_state.corr_err.q),
+    .hw2reg_intr_state_de_o (hw2reg.intr_state.corr_err.de),
+    .hw2reg_intr_state_d_o  (hw2reg.intr_state.corr_err.d),
+    .intr_o                 (intr_corr_err_o)
+  );
 
   // Unused bits
   logic [BusByteWidth-1:0] unused_byte_sel;
@@ -1144,12 +1198,15 @@
   `ASSERT_KNOWN(IntrProgRdFullKnownO_A, intr_rd_full_o   )
   `ASSERT_KNOWN(IntrRdLvlKnownO_A,      intr_rd_lvl_o    )
   `ASSERT_KNOWN(IntrOpDoneKnownO_A,     intr_op_done_o   )
-  `ASSERT_KNOWN(IntrErrO_A,             intr_err_o       )
+  `ASSERT_KNOWN(IntrErrO_A,             intr_corr_err_o  )
 
-
+  // combined indication that an operation has started
+  // This is used only for assertions
+  logic unused_op_valid;
+  assign unused_op_valid = prog_op_valid | rd_op_valid | erase_op_valid;
 
   // if there is an out of bounds error, flash request should never assert
-  `ASSERT(OutofBoundsReq_A, op_valid & op_addr_oob |-> ~flash_phy_req.req)
+  `ASSERT(OutofBoundsReq_A, unused_op_valid & op_addr_oob |-> ~flash_phy_req.req)
 
   // add more assertions
 
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_arb.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_arb.sv
index 0ec54d7..1963079 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_arb.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_arb.sv
@@ -16,11 +16,14 @@
   input clk_i,
   input rst_ni,
 
+  // error address shared between interfaces
+  output logic [BusAddrW-1:0] ctrl_err_addr_o,
+
   // software interface to rd_ctrl / erase_ctrl
   input flash_ctrl_reg_pkg::flash_ctrl_reg2hw_control_reg_t sw_ctrl_i,
   input [31:0] sw_addr_i,
   output logic sw_ack_o,
-  output logic sw_err_o,
+  output flash_ctrl_err_t sw_err_o,
 
   // software interface to rd_fifo
   output logic sw_rvalid_o,
@@ -37,7 +40,7 @@
   input flash_lcmgr_phase_e hw_phase_i,
   input [31:0] hw_addr_i,
   output logic hw_ack_o,
-  output logic hw_err_o,
+  output flash_ctrl_err_t hw_err_o,
 
   // hardware interface to rd_fifo
   output logic hw_rvalid_o,
@@ -52,11 +55,14 @@
   output flash_ctrl_reg_pkg::flash_ctrl_reg2hw_control_reg_t muxed_ctrl_o,
   output logic [31:0] muxed_addr_o,
   input prog_ack_i,
-  input prog_err_i,
+  input flash_ctrl_err_t prog_err_i,
+  input [BusAddrW-1:0] prog_err_addr_i,
   input rd_ack_i,
-  input rd_err_i,
+  input flash_ctrl_err_t rd_err_i,
+  input [BusAddrW-1:0] rd_err_addr_i,
   input erase_ack_i,
-  input erase_err_i,
+  input flash_ctrl_err_t erase_err_i,
+  input [BusAddrW-1:0] erase_err_addr_i,
 
   // muxed interface to rd_fifo
   input rd_fifo_rvalid_i,
@@ -156,22 +162,23 @@
     endcase // unique case (state_q)
   end // always_comb
 
-  logic ctrl_ack, ctrl_err;
+  logic ctrl_ack;
+  flash_ctrl_err_t ctrl_err;
 
   always_comb begin
     muxed_ctrl_o = '0;
     muxed_addr_o = '0;
-    sw_ack_o = 1'b0;
-    sw_err_o = 1'b0;
-    sw_rvalid_o = 1'b0;
-    sw_wready_o = 1'b0;
-    hw_ack_o = 1'b0;
-    hw_err_o = 1'b0;
-    hw_rvalid_o = 1'b0;
-    hw_wready_o = 1'b0;
-    prog_fifo_wvalid_o = 1'b0;
+    sw_ack_o = '0;
+    sw_err_o = '0;
+    sw_rvalid_o = '0;
+    sw_wready_o = '0;
+    hw_ack_o = '0;
+    hw_err_o = '0;
+    hw_rvalid_o = '0;
+    hw_wready_o = '0;
+    prog_fifo_wvalid_o = '0;
     prog_fifo_wdata_o = '0;
-    rd_fifo_rready_o = 1'b0;
+    rd_fifo_rready_o = '0;
 
     unique case (func_sel)
       HwSel: begin
@@ -213,16 +220,29 @@
   always_comb begin
     ctrl_ack = '0;
     ctrl_err = '0;
-    if (muxed_ctrl_o.op.q == FlashOpProgram) begin
-      ctrl_ack = prog_ack_i;
-      ctrl_err = prog_err_i;
-    end else if (muxed_ctrl_o.op.q == FlashOpErase) begin
-      ctrl_ack = erase_ack_i;
-      ctrl_err = erase_err_i;
-    end else if (muxed_ctrl_o.op.q == FlashOpRead) begin
-      ctrl_ack = rd_ack_i;
-      ctrl_err = rd_err_i;
-    end
+    ctrl_err_addr_o = '0;
+
+    unique case (muxed_ctrl_o.op.q)
+      FlashOpProgram: begin
+        ctrl_ack = prog_ack_i;
+        ctrl_err = prog_err_i;
+        ctrl_err_addr_o = prog_err_addr_i;
+      end
+
+      FlashOpErase: begin
+        ctrl_ack = erase_ack_i;
+        ctrl_err = erase_err_i;
+        ctrl_err_addr_o = erase_err_addr_i;
+      end
+
+      FlashOpRead: begin
+        ctrl_ack = rd_ack_i;
+        ctrl_err = rd_err_i;
+        ctrl_err_addr_o = rd_err_addr_i;
+      end
+
+      default:;
+    endcase // unique case (muxed_ctrl_o.op.q)
   end
 
   assign sel_o = func_sel;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
index 4ca672f..59d2a99 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
@@ -121,10 +121,10 @@
     reg_steer = 2;       // Default set to register
 
     // TODO: Can below codes be unique case () inside ?
-    if (tl_i.a_address[AW-1:0] >= 400 && tl_i.a_address[AW-1:0] < 404) begin
+    if (tl_i.a_address[AW-1:0] >= 388 && tl_i.a_address[AW-1:0] < 392) begin
       reg_steer = 0;
     end
-    if (tl_i.a_address[AW-1:0] >= 404 && tl_i.a_address[AW-1:0] < 408) begin
+    if (tl_i.a_address[AW-1:0] >= 392 && tl_i.a_address[AW-1:0] < 396) begin
       reg_steer = 1;
     end
     if (intg_err) begin
@@ -172,8 +172,8 @@
   logic intr_state_rd_lvl_wd;
   logic intr_state_op_done_qs;
   logic intr_state_op_done_wd;
-  logic intr_state_err_qs;
-  logic intr_state_err_wd;
+  logic intr_state_corr_err_qs;
+  logic intr_state_corr_err_wd;
   logic intr_enable_we;
   logic intr_enable_prog_empty_qs;
   logic intr_enable_prog_empty_wd;
@@ -185,20 +185,18 @@
   logic intr_enable_rd_lvl_wd;
   logic intr_enable_op_done_qs;
   logic intr_enable_op_done_wd;
-  logic intr_enable_err_qs;
-  logic intr_enable_err_wd;
+  logic intr_enable_corr_err_qs;
+  logic intr_enable_corr_err_wd;
   logic intr_test_we;
   logic intr_test_prog_empty_wd;
   logic intr_test_prog_lvl_wd;
   logic intr_test_rd_full_wd;
   logic intr_test_rd_lvl_wd;
   logic intr_test_op_done_wd;
-  logic intr_test_err_wd;
+  logic intr_test_corr_err_wd;
   logic alert_test_we;
   logic alert_test_recov_err_wd;
-  logic alert_test_recov_mp_err_wd;
-  logic alert_test_recov_ecc_err_wd;
-  logic alert_test_fatal_intg_err_wd;
+  logic alert_test_fatal_err_wd;
   logic flash_disable_we;
   logic flash_disable_qs;
   logic flash_disable_wd;
@@ -908,43 +906,35 @@
   logic status_prog_full_qs;
   logic status_prog_empty_qs;
   logic status_init_wip_qs;
-  logic err_code_intr_en_we;
-  logic err_code_intr_en_flash_err_en_qs;
-  logic err_code_intr_en_flash_err_en_wd;
-  logic err_code_intr_en_flash_alert_en_qs;
-  logic err_code_intr_en_flash_alert_en_wd;
-  logic err_code_intr_en_oob_err_qs;
-  logic err_code_intr_en_oob_err_wd;
-  logic err_code_intr_en_mp_err_qs;
-  logic err_code_intr_en_mp_err_wd;
-  logic err_code_intr_en_ecc_single_err_qs;
-  logic err_code_intr_en_ecc_single_err_wd;
-  logic err_code_intr_en_ecc_multi_err_qs;
-  logic err_code_intr_en_ecc_multi_err_wd;
   logic err_code_we;
-  logic err_code_flash_err_qs;
-  logic err_code_flash_err_wd;
-  logic err_code_flash_alert_qs;
-  logic err_code_flash_alert_wd;
   logic err_code_oob_err_qs;
   logic err_code_oob_err_wd;
   logic err_code_mp_err_qs;
   logic err_code_mp_err_wd;
-  logic err_code_ecc_single_err_qs;
-  logic err_code_ecc_single_err_wd;
-  logic err_code_ecc_multi_err_qs;
-  logic err_code_ecc_multi_err_wd;
-  logic [8:0] err_addr_qs;
+  logic err_code_rd_err_qs;
+  logic err_code_rd_err_wd;
+  logic err_code_prog_win_err_qs;
+  logic err_code_prog_win_err_wd;
+  logic err_code_prog_type_err_qs;
+  logic err_code_prog_type_err_wd;
+  logic err_code_flash_phy_err_qs;
+  logic err_code_flash_phy_err_wd;
+  logic fault_status_oob_err_qs;
+  logic fault_status_mp_err_qs;
+  logic fault_status_rd_err_qs;
+  logic fault_status_prog_win_err_qs;
+  logic fault_status_prog_type_err_qs;
+  logic fault_status_flash_phy_err_qs;
+  logic fault_status_reg_intg_err_qs;
+  logic fault_status_phy_intg_err_qs;
+  logic [31:0] err_addr_qs;
   logic ecc_single_err_cnt_we;
-  logic [7:0] ecc_single_err_cnt_qs;
-  logic [7:0] ecc_single_err_cnt_wd;
+  logic [7:0] ecc_single_err_cnt_ecc_single_err_cnt_0_qs;
+  logic [7:0] ecc_single_err_cnt_ecc_single_err_cnt_0_wd;
+  logic [7:0] ecc_single_err_cnt_ecc_single_err_cnt_1_qs;
+  logic [7:0] ecc_single_err_cnt_ecc_single_err_cnt_1_wd;
   logic [19:0] ecc_single_err_addr_0_qs;
   logic [19:0] ecc_single_err_addr_1_qs;
-  logic ecc_multi_err_cnt_we;
-  logic [7:0] ecc_multi_err_cnt_qs;
-  logic [7:0] ecc_multi_err_cnt_wd;
-  logic [19:0] ecc_multi_err_addr_0_qs;
-  logic [19:0] ecc_multi_err_addr_1_qs;
   logic phy_err_cfg_regwen_we;
   logic phy_err_cfg_regwen_qs;
   logic phy_err_cfg_regwen_wd;
@@ -1098,29 +1088,29 @@
     .qs     (intr_state_op_done_qs)
   );
 
-  //   F[err]: 5:5
+  //   F[corr_err]: 5:5
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessW1C),
     .RESVAL  (1'h0)
-  ) u_intr_state_err (
+  ) u_intr_state_corr_err (
     .clk_i   (clk_i),
     .rst_ni  (rst_ni),
 
     // from register interface
     .we     (intr_state_we),
-    .wd     (intr_state_err_wd),
+    .wd     (intr_state_corr_err_wd),
 
     // from internal hardware
-    .de     (hw2reg.intr_state.err.de),
-    .d      (hw2reg.intr_state.err.d),
+    .de     (hw2reg.intr_state.corr_err.de),
+    .d      (hw2reg.intr_state.corr_err.d),
 
     // to internal hardware
     .qe     (),
-    .q      (reg2hw.intr_state.err.q),
+    .q      (reg2hw.intr_state.corr_err.q),
 
     // to register interface (read)
-    .qs     (intr_state_err_qs)
+    .qs     (intr_state_corr_err_qs)
   );
 
 
@@ -1250,18 +1240,18 @@
     .qs     (intr_enable_op_done_qs)
   );
 
-  //   F[err]: 5:5
+  //   F[corr_err]: 5:5
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (1'h0)
-  ) u_intr_enable_err (
+  ) u_intr_enable_corr_err (
     .clk_i   (clk_i),
     .rst_ni  (rst_ni),
 
     // from register interface
     .we     (intr_enable_we),
-    .wd     (intr_enable_err_wd),
+    .wd     (intr_enable_corr_err_wd),
 
     // from internal hardware
     .de     (1'b0),
@@ -1269,10 +1259,10 @@
 
     // to internal hardware
     .qe     (),
-    .q      (reg2hw.intr_enable.err.q),
+    .q      (reg2hw.intr_enable.corr_err.q),
 
     // to register interface (read)
-    .qs     (intr_enable_err_qs)
+    .qs     (intr_enable_corr_err_qs)
   );
 
 
@@ -1347,17 +1337,17 @@
     .qs     ()
   );
 
-  //   F[err]: 5:5
+  //   F[corr_err]: 5:5
   prim_subreg_ext #(
     .DW    (1)
-  ) u_intr_test_err (
+  ) u_intr_test_corr_err (
     .re     (1'b0),
     .we     (intr_test_we),
-    .wd     (intr_test_err_wd),
+    .wd     (intr_test_corr_err_wd),
     .d      ('0),
     .qre    (),
-    .qe     (reg2hw.intr_test.err.qe),
-    .q      (reg2hw.intr_test.err.q),
+    .qe     (reg2hw.intr_test.corr_err.qe),
+    .q      (reg2hw.intr_test.corr_err.q),
     .qs     ()
   );
 
@@ -1377,45 +1367,17 @@
     .qs     ()
   );
 
-  //   F[recov_mp_err]: 1:1
+  //   F[fatal_err]: 1:1
   prim_subreg_ext #(
     .DW    (1)
-  ) u_alert_test_recov_mp_err (
+  ) u_alert_test_fatal_err (
     .re     (1'b0),
     .we     (alert_test_we),
-    .wd     (alert_test_recov_mp_err_wd),
+    .wd     (alert_test_fatal_err_wd),
     .d      ('0),
     .qre    (),
-    .qe     (reg2hw.alert_test.recov_mp_err.qe),
-    .q      (reg2hw.alert_test.recov_mp_err.q),
-    .qs     ()
-  );
-
-  //   F[recov_ecc_err]: 2:2
-  prim_subreg_ext #(
-    .DW    (1)
-  ) u_alert_test_recov_ecc_err (
-    .re     (1'b0),
-    .we     (alert_test_we),
-    .wd     (alert_test_recov_ecc_err_wd),
-    .d      ('0),
-    .qre    (),
-    .qe     (reg2hw.alert_test.recov_ecc_err.qe),
-    .q      (reg2hw.alert_test.recov_ecc_err.q),
-    .qs     ()
-  );
-
-  //   F[fatal_intg_err]: 3:3
-  prim_subreg_ext #(
-    .DW    (1)
-  ) u_alert_test_fatal_intg_err (
-    .re     (1'b0),
-    .we     (alert_test_we),
-    .wd     (alert_test_fatal_intg_err_wd),
-    .d      ('0),
-    .qre    (),
-    .qe     (reg2hw.alert_test.fatal_intg_err.qe),
-    .q      (reg2hw.alert_test.fatal_intg_err.q),
+    .qe     (reg2hw.alert_test.fatal_err.qe),
+    .q      (reg2hw.alert_test.fatal_err.q),
     .qs     ()
   );
 
@@ -9548,210 +9510,8 @@
   );
 
 
-  // R[err_code_intr_en]: V(False)
-  //   F[flash_err_en]: 0:0
-  prim_subreg #(
-    .DW      (1),
-    .SwAccess(prim_subreg_pkg::SwAccessRW),
-    .RESVAL  (1'h0)
-  ) u_err_code_intr_en_flash_err_en (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (err_code_intr_en_we),
-    .wd     (err_code_intr_en_flash_err_en_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.err_code_intr_en.flash_err_en.q),
-
-    // to register interface (read)
-    .qs     (err_code_intr_en_flash_err_en_qs)
-  );
-
-  //   F[flash_alert_en]: 1:1
-  prim_subreg #(
-    .DW      (1),
-    .SwAccess(prim_subreg_pkg::SwAccessRW),
-    .RESVAL  (1'h0)
-  ) u_err_code_intr_en_flash_alert_en (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (err_code_intr_en_we),
-    .wd     (err_code_intr_en_flash_alert_en_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.err_code_intr_en.flash_alert_en.q),
-
-    // to register interface (read)
-    .qs     (err_code_intr_en_flash_alert_en_qs)
-  );
-
-  //   F[oob_err]: 2:2
-  prim_subreg #(
-    .DW      (1),
-    .SwAccess(prim_subreg_pkg::SwAccessRW),
-    .RESVAL  (1'h0)
-  ) u_err_code_intr_en_oob_err (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (err_code_intr_en_we),
-    .wd     (err_code_intr_en_oob_err_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.err_code_intr_en.oob_err.q),
-
-    // to register interface (read)
-    .qs     (err_code_intr_en_oob_err_qs)
-  );
-
-  //   F[mp_err]: 3:3
-  prim_subreg #(
-    .DW      (1),
-    .SwAccess(prim_subreg_pkg::SwAccessRW),
-    .RESVAL  (1'h0)
-  ) u_err_code_intr_en_mp_err (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (err_code_intr_en_we),
-    .wd     (err_code_intr_en_mp_err_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.err_code_intr_en.mp_err.q),
-
-    // to register interface (read)
-    .qs     (err_code_intr_en_mp_err_qs)
-  );
-
-  //   F[ecc_single_err]: 4:4
-  prim_subreg #(
-    .DW      (1),
-    .SwAccess(prim_subreg_pkg::SwAccessRW),
-    .RESVAL  (1'h0)
-  ) u_err_code_intr_en_ecc_single_err (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (err_code_intr_en_we),
-    .wd     (err_code_intr_en_ecc_single_err_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.err_code_intr_en.ecc_single_err.q),
-
-    // to register interface (read)
-    .qs     (err_code_intr_en_ecc_single_err_qs)
-  );
-
-  //   F[ecc_multi_err]: 5:5
-  prim_subreg #(
-    .DW      (1),
-    .SwAccess(prim_subreg_pkg::SwAccessRW),
-    .RESVAL  (1'h0)
-  ) u_err_code_intr_en_ecc_multi_err (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (err_code_intr_en_we),
-    .wd     (err_code_intr_en_ecc_multi_err_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.err_code_intr_en.ecc_multi_err.q),
-
-    // to register interface (read)
-    .qs     (err_code_intr_en_ecc_multi_err_qs)
-  );
-
-
   // R[err_code]: V(False)
-  //   F[flash_err]: 0:0
-  prim_subreg #(
-    .DW      (1),
-    .SwAccess(prim_subreg_pkg::SwAccessW1C),
-    .RESVAL  (1'h0)
-  ) u_err_code_flash_err (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (err_code_we),
-    .wd     (err_code_flash_err_wd),
-
-    // from internal hardware
-    .de     (hw2reg.err_code.flash_err.de),
-    .d      (hw2reg.err_code.flash_err.d),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.err_code.flash_err.q),
-
-    // to register interface (read)
-    .qs     (err_code_flash_err_qs)
-  );
-
-  //   F[flash_alert]: 1:1
-  prim_subreg #(
-    .DW      (1),
-    .SwAccess(prim_subreg_pkg::SwAccessW1C),
-    .RESVAL  (1'h0)
-  ) u_err_code_flash_alert (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (err_code_we),
-    .wd     (err_code_flash_alert_wd),
-
-    // from internal hardware
-    .de     (hw2reg.err_code.flash_alert.de),
-    .d      (hw2reg.err_code.flash_alert.d),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.err_code.flash_alert.q),
-
-    // to register interface (read)
-    .qs     (err_code_flash_alert_qs)
-  );
-
-  //   F[oob_err]: 2:2
+  //   F[oob_err]: 0:0
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessW1C),
@@ -9770,13 +9530,13 @@
 
     // to internal hardware
     .qe     (),
-    .q      (reg2hw.err_code.oob_err.q),
+    .q      (),
 
     // to register interface (read)
     .qs     (err_code_oob_err_qs)
   );
 
-  //   F[mp_err]: 3:3
+  //   F[mp_err]: 1:1
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessW1C),
@@ -9795,68 +9555,320 @@
 
     // to internal hardware
     .qe     (),
-    .q      (reg2hw.err_code.mp_err.q),
+    .q      (),
 
     // to register interface (read)
     .qs     (err_code_mp_err_qs)
   );
 
-  //   F[ecc_single_err]: 4:4
+  //   F[rd_err]: 2:2
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessW1C),
     .RESVAL  (1'h0)
-  ) u_err_code_ecc_single_err (
+  ) u_err_code_rd_err (
     .clk_i   (clk_i),
     .rst_ni  (rst_ni),
 
     // from register interface
     .we     (err_code_we),
-    .wd     (err_code_ecc_single_err_wd),
+    .wd     (err_code_rd_err_wd),
 
     // from internal hardware
-    .de     (hw2reg.err_code.ecc_single_err.de),
-    .d      (hw2reg.err_code.ecc_single_err.d),
+    .de     (hw2reg.err_code.rd_err.de),
+    .d      (hw2reg.err_code.rd_err.d),
 
     // to internal hardware
     .qe     (),
-    .q      (reg2hw.err_code.ecc_single_err.q),
+    .q      (),
 
     // to register interface (read)
-    .qs     (err_code_ecc_single_err_qs)
+    .qs     (err_code_rd_err_qs)
   );
 
-  //   F[ecc_multi_err]: 5:5
+  //   F[prog_win_err]: 3:3
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessW1C),
     .RESVAL  (1'h0)
-  ) u_err_code_ecc_multi_err (
+  ) u_err_code_prog_win_err (
     .clk_i   (clk_i),
     .rst_ni  (rst_ni),
 
     // from register interface
     .we     (err_code_we),
-    .wd     (err_code_ecc_multi_err_wd),
+    .wd     (err_code_prog_win_err_wd),
 
     // from internal hardware
-    .de     (hw2reg.err_code.ecc_multi_err.de),
-    .d      (hw2reg.err_code.ecc_multi_err.d),
+    .de     (hw2reg.err_code.prog_win_err.de),
+    .d      (hw2reg.err_code.prog_win_err.d),
 
     // to internal hardware
     .qe     (),
-    .q      (reg2hw.err_code.ecc_multi_err.q),
+    .q      (),
 
     // to register interface (read)
-    .qs     (err_code_ecc_multi_err_qs)
+    .qs     (err_code_prog_win_err_qs)
+  );
+
+  //   F[prog_type_err]: 4:4
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessW1C),
+    .RESVAL  (1'h0)
+  ) u_err_code_prog_type_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (err_code_we),
+    .wd     (err_code_prog_type_err_wd),
+
+    // from internal hardware
+    .de     (hw2reg.err_code.prog_type_err.de),
+    .d      (hw2reg.err_code.prog_type_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (err_code_prog_type_err_qs)
+  );
+
+  //   F[flash_phy_err]: 5:5
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessW1C),
+    .RESVAL  (1'h0)
+  ) u_err_code_flash_phy_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (err_code_we),
+    .wd     (err_code_flash_phy_err_wd),
+
+    // from internal hardware
+    .de     (hw2reg.err_code.flash_phy_err.de),
+    .d      (hw2reg.err_code.flash_phy_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (err_code_flash_phy_err_qs)
+  );
+
+
+  // R[fault_status]: V(False)
+  //   F[oob_err]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_oob_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.oob_err.de),
+    .d      (hw2reg.fault_status.oob_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.oob_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_oob_err_qs)
+  );
+
+  //   F[mp_err]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_mp_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.mp_err.de),
+    .d      (hw2reg.fault_status.mp_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.mp_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_mp_err_qs)
+  );
+
+  //   F[rd_err]: 2:2
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_rd_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.rd_err.de),
+    .d      (hw2reg.fault_status.rd_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.rd_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_rd_err_qs)
+  );
+
+  //   F[prog_win_err]: 3:3
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_prog_win_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.prog_win_err.de),
+    .d      (hw2reg.fault_status.prog_win_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.prog_win_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_prog_win_err_qs)
+  );
+
+  //   F[prog_type_err]: 4:4
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_prog_type_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.prog_type_err.de),
+    .d      (hw2reg.fault_status.prog_type_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.prog_type_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_prog_type_err_qs)
+  );
+
+  //   F[flash_phy_err]: 5:5
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_flash_phy_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.flash_phy_err.de),
+    .d      (hw2reg.fault_status.flash_phy_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.flash_phy_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_flash_phy_err_qs)
+  );
+
+  //   F[reg_intg_err]: 6:6
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_reg_intg_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.reg_intg_err.de),
+    .d      (hw2reg.fault_status.reg_intg_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.reg_intg_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_reg_intg_err_qs)
+  );
+
+  //   F[phy_intg_err]: 7:7
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_phy_intg_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.phy_intg_err.de),
+    .d      (hw2reg.fault_status.phy_intg_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.phy_intg_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_phy_intg_err_qs)
   );
 
 
   // R[err_addr]: V(False)
   prim_subreg #(
-    .DW      (9),
+    .DW      (32),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
-    .RESVAL  (9'h0)
+    .RESVAL  (32'h0)
   ) u_err_addr (
     .clk_i   (clk_i),
     .rst_ni  (rst_ni),
@@ -9878,29 +9890,56 @@
   );
 
 
+  // Subregister 0 of Multireg ecc_single_err_cnt
   // R[ecc_single_err_cnt]: V(False)
+  //   F[ecc_single_err_cnt_0]: 7:0
   prim_subreg #(
     .DW      (8),
-    .SwAccess(prim_subreg_pkg::SwAccessW1C),
+    .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (8'h0)
-  ) u_ecc_single_err_cnt (
+  ) u_ecc_single_err_cnt_ecc_single_err_cnt_0 (
     .clk_i   (clk_i),
     .rst_ni  (rst_ni),
 
     // from register interface
     .we     (ecc_single_err_cnt_we),
-    .wd     (ecc_single_err_cnt_wd),
+    .wd     (ecc_single_err_cnt_ecc_single_err_cnt_0_wd),
 
     // from internal hardware
-    .de     (hw2reg.ecc_single_err_cnt.de),
-    .d      (hw2reg.ecc_single_err_cnt.d),
+    .de     (hw2reg.ecc_single_err_cnt[0].de),
+    .d      (hw2reg.ecc_single_err_cnt[0].d),
 
     // to internal hardware
     .qe     (),
-    .q      (reg2hw.ecc_single_err_cnt.q),
+    .q      (reg2hw.ecc_single_err_cnt[0].q),
 
     // to register interface (read)
-    .qs     (ecc_single_err_cnt_qs)
+    .qs     (ecc_single_err_cnt_ecc_single_err_cnt_0_qs)
+  );
+
+  //   F[ecc_single_err_cnt_1]: 15:8
+  prim_subreg #(
+    .DW      (8),
+    .SwAccess(prim_subreg_pkg::SwAccessRW),
+    .RESVAL  (8'h0)
+  ) u_ecc_single_err_cnt_ecc_single_err_cnt_1 (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (ecc_single_err_cnt_we),
+    .wd     (ecc_single_err_cnt_ecc_single_err_cnt_1_wd),
+
+    // from internal hardware
+    .de     (hw2reg.ecc_single_err_cnt[1].de),
+    .d      (hw2reg.ecc_single_err_cnt[1].d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.ecc_single_err_cnt[1].q),
+
+    // to register interface (read)
+    .qs     (ecc_single_err_cnt_ecc_single_err_cnt_1_qs)
   );
 
 
@@ -9958,86 +9997,6 @@
   );
 
 
-  // R[ecc_multi_err_cnt]: V(False)
-  prim_subreg #(
-    .DW      (8),
-    .SwAccess(prim_subreg_pkg::SwAccessW1C),
-    .RESVAL  (8'h0)
-  ) u_ecc_multi_err_cnt (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (ecc_multi_err_cnt_we),
-    .wd     (ecc_multi_err_cnt_wd),
-
-    // from internal hardware
-    .de     (hw2reg.ecc_multi_err_cnt.de),
-    .d      (hw2reg.ecc_multi_err_cnt.d),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.ecc_multi_err_cnt.q),
-
-    // to register interface (read)
-    .qs     (ecc_multi_err_cnt_qs)
-  );
-
-
-  // Subregister 0 of Multireg ecc_multi_err_addr
-  // R[ecc_multi_err_addr_0]: V(False)
-  prim_subreg #(
-    .DW      (20),
-    .SwAccess(prim_subreg_pkg::SwAccessRO),
-    .RESVAL  (20'h0)
-  ) u_ecc_multi_err_addr_0 (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (1'b0),
-    .wd     ('0),
-
-    // from internal hardware
-    .de     (hw2reg.ecc_multi_err_addr[0].de),
-    .d      (hw2reg.ecc_multi_err_addr[0].d),
-
-    // to internal hardware
-    .qe     (),
-    .q      (),
-
-    // to register interface (read)
-    .qs     (ecc_multi_err_addr_0_qs)
-  );
-
-
-  // Subregister 1 of Multireg ecc_multi_err_addr
-  // R[ecc_multi_err_addr_1]: V(False)
-  prim_subreg #(
-    .DW      (20),
-    .SwAccess(prim_subreg_pkg::SwAccessRO),
-    .RESVAL  (20'h0)
-  ) u_ecc_multi_err_addr_1 (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (1'b0),
-    .wd     ('0),
-
-    // from internal hardware
-    .de     (hw2reg.ecc_multi_err_addr[1].de),
-    .d      (hw2reg.ecc_multi_err_addr[1].d),
-
-    // to internal hardware
-    .qe     (),
-    .q      (),
-
-    // to register interface (read)
-    .qs     (ecc_multi_err_addr_1_qs)
-  );
-
-
   // R[phy_err_cfg_regwen]: V(False)
   prim_subreg #(
     .DW      (1),
@@ -10324,7 +10283,7 @@
 
 
 
-  logic [99:0] addr_hit;
+  logic [96:0] addr_hit;
   always_comb begin
     addr_hit = '0;
     addr_hit[ 0] = (reg_addr == FLASH_CTRL_INTR_STATE_OFFSET);
@@ -10411,22 +10370,19 @@
     addr_hit[81] = (reg_addr == FLASH_CTRL_MP_BANK_CFG_OFFSET);
     addr_hit[82] = (reg_addr == FLASH_CTRL_OP_STATUS_OFFSET);
     addr_hit[83] = (reg_addr == FLASH_CTRL_STATUS_OFFSET);
-    addr_hit[84] = (reg_addr == FLASH_CTRL_ERR_CODE_INTR_EN_OFFSET);
-    addr_hit[85] = (reg_addr == FLASH_CTRL_ERR_CODE_OFFSET);
+    addr_hit[84] = (reg_addr == FLASH_CTRL_ERR_CODE_OFFSET);
+    addr_hit[85] = (reg_addr == FLASH_CTRL_FAULT_STATUS_OFFSET);
     addr_hit[86] = (reg_addr == FLASH_CTRL_ERR_ADDR_OFFSET);
     addr_hit[87] = (reg_addr == FLASH_CTRL_ECC_SINGLE_ERR_CNT_OFFSET);
     addr_hit[88] = (reg_addr == FLASH_CTRL_ECC_SINGLE_ERR_ADDR_0_OFFSET);
     addr_hit[89] = (reg_addr == FLASH_CTRL_ECC_SINGLE_ERR_ADDR_1_OFFSET);
-    addr_hit[90] = (reg_addr == FLASH_CTRL_ECC_MULTI_ERR_CNT_OFFSET);
-    addr_hit[91] = (reg_addr == FLASH_CTRL_ECC_MULTI_ERR_ADDR_0_OFFSET);
-    addr_hit[92] = (reg_addr == FLASH_CTRL_ECC_MULTI_ERR_ADDR_1_OFFSET);
-    addr_hit[93] = (reg_addr == FLASH_CTRL_PHY_ERR_CFG_REGWEN_OFFSET);
-    addr_hit[94] = (reg_addr == FLASH_CTRL_PHY_ERR_CFG_OFFSET);
-    addr_hit[95] = (reg_addr == FLASH_CTRL_PHY_ALERT_CFG_OFFSET);
-    addr_hit[96] = (reg_addr == FLASH_CTRL_PHY_STATUS_OFFSET);
-    addr_hit[97] = (reg_addr == FLASH_CTRL_SCRATCH_OFFSET);
-    addr_hit[98] = (reg_addr == FLASH_CTRL_FIFO_LVL_OFFSET);
-    addr_hit[99] = (reg_addr == FLASH_CTRL_FIFO_RST_OFFSET);
+    addr_hit[90] = (reg_addr == FLASH_CTRL_PHY_ERR_CFG_REGWEN_OFFSET);
+    addr_hit[91] = (reg_addr == FLASH_CTRL_PHY_ERR_CFG_OFFSET);
+    addr_hit[92] = (reg_addr == FLASH_CTRL_PHY_ALERT_CFG_OFFSET);
+    addr_hit[93] = (reg_addr == FLASH_CTRL_PHY_STATUS_OFFSET);
+    addr_hit[94] = (reg_addr == FLASH_CTRL_SCRATCH_OFFSET);
+    addr_hit[95] = (reg_addr == FLASH_CTRL_FIFO_LVL_OFFSET);
+    addr_hit[96] = (reg_addr == FLASH_CTRL_FIFO_RST_OFFSET);
   end
 
   assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
@@ -10530,10 +10486,7 @@
                (addr_hit[93] & (|(FLASH_CTRL_CORE_PERMIT[93] & ~reg_be))) |
                (addr_hit[94] & (|(FLASH_CTRL_CORE_PERMIT[94] & ~reg_be))) |
                (addr_hit[95] & (|(FLASH_CTRL_CORE_PERMIT[95] & ~reg_be))) |
-               (addr_hit[96] & (|(FLASH_CTRL_CORE_PERMIT[96] & ~reg_be))) |
-               (addr_hit[97] & (|(FLASH_CTRL_CORE_PERMIT[97] & ~reg_be))) |
-               (addr_hit[98] & (|(FLASH_CTRL_CORE_PERMIT[98] & ~reg_be))) |
-               (addr_hit[99] & (|(FLASH_CTRL_CORE_PERMIT[99] & ~reg_be)))));
+               (addr_hit[96] & (|(FLASH_CTRL_CORE_PERMIT[96] & ~reg_be)))));
   end
   assign intr_state_we = addr_hit[0] & reg_we & !reg_error;
 
@@ -10547,7 +10500,7 @@
 
   assign intr_state_op_done_wd = reg_wdata[4];
 
-  assign intr_state_err_wd = reg_wdata[5];
+  assign intr_state_corr_err_wd = reg_wdata[5];
   assign intr_enable_we = addr_hit[1] & reg_we & !reg_error;
 
   assign intr_enable_prog_empty_wd = reg_wdata[0];
@@ -10560,7 +10513,7 @@
 
   assign intr_enable_op_done_wd = reg_wdata[4];
 
-  assign intr_enable_err_wd = reg_wdata[5];
+  assign intr_enable_corr_err_wd = reg_wdata[5];
   assign intr_test_we = addr_hit[2] & reg_we & !reg_error;
 
   assign intr_test_prog_empty_wd = reg_wdata[0];
@@ -10573,16 +10526,12 @@
 
   assign intr_test_op_done_wd = reg_wdata[4];
 
-  assign intr_test_err_wd = reg_wdata[5];
+  assign intr_test_corr_err_wd = reg_wdata[5];
   assign alert_test_we = addr_hit[3] & reg_we & !reg_error;
 
   assign alert_test_recov_err_wd = reg_wdata[0];
 
-  assign alert_test_recov_mp_err_wd = reg_wdata[1];
-
-  assign alert_test_recov_ecc_err_wd = reg_wdata[2];
-
-  assign alert_test_fatal_intg_err_wd = reg_wdata[3];
+  assign alert_test_fatal_err_wd = reg_wdata[1];
   assign flash_disable_we = addr_hit[4] & reg_we & !reg_error;
 
   assign flash_disable_wd = reg_wdata[0];
@@ -11286,58 +11235,44 @@
   assign op_status_done_wd = reg_wdata[0];
 
   assign op_status_err_wd = reg_wdata[1];
-  assign err_code_intr_en_we = addr_hit[84] & reg_we & !reg_error;
+  assign err_code_we = addr_hit[84] & reg_we & !reg_error;
 
-  assign err_code_intr_en_flash_err_en_wd = reg_wdata[0];
+  assign err_code_oob_err_wd = reg_wdata[0];
 
-  assign err_code_intr_en_flash_alert_en_wd = reg_wdata[1];
+  assign err_code_mp_err_wd = reg_wdata[1];
 
-  assign err_code_intr_en_oob_err_wd = reg_wdata[2];
+  assign err_code_rd_err_wd = reg_wdata[2];
 
-  assign err_code_intr_en_mp_err_wd = reg_wdata[3];
+  assign err_code_prog_win_err_wd = reg_wdata[3];
 
-  assign err_code_intr_en_ecc_single_err_wd = reg_wdata[4];
+  assign err_code_prog_type_err_wd = reg_wdata[4];
 
-  assign err_code_intr_en_ecc_multi_err_wd = reg_wdata[5];
-  assign err_code_we = addr_hit[85] & reg_we & !reg_error;
-
-  assign err_code_flash_err_wd = reg_wdata[0];
-
-  assign err_code_flash_alert_wd = reg_wdata[1];
-
-  assign err_code_oob_err_wd = reg_wdata[2];
-
-  assign err_code_mp_err_wd = reg_wdata[3];
-
-  assign err_code_ecc_single_err_wd = reg_wdata[4];
-
-  assign err_code_ecc_multi_err_wd = reg_wdata[5];
+  assign err_code_flash_phy_err_wd = reg_wdata[5];
   assign ecc_single_err_cnt_we = addr_hit[87] & reg_we & !reg_error;
 
-  assign ecc_single_err_cnt_wd = reg_wdata[7:0];
-  assign ecc_multi_err_cnt_we = addr_hit[90] & reg_we & !reg_error;
+  assign ecc_single_err_cnt_ecc_single_err_cnt_0_wd = reg_wdata[7:0];
 
-  assign ecc_multi_err_cnt_wd = reg_wdata[7:0];
-  assign phy_err_cfg_regwen_we = addr_hit[93] & reg_we & !reg_error;
+  assign ecc_single_err_cnt_ecc_single_err_cnt_1_wd = reg_wdata[15:8];
+  assign phy_err_cfg_regwen_we = addr_hit[90] & reg_we & !reg_error;
 
   assign phy_err_cfg_regwen_wd = reg_wdata[0];
-  assign phy_err_cfg_we = addr_hit[94] & reg_we & !reg_error;
+  assign phy_err_cfg_we = addr_hit[91] & reg_we & !reg_error;
 
   assign phy_err_cfg_wd = reg_wdata[0];
-  assign phy_alert_cfg_we = addr_hit[95] & reg_we & !reg_error;
+  assign phy_alert_cfg_we = addr_hit[92] & reg_we & !reg_error;
 
   assign phy_alert_cfg_alert_ack_wd = reg_wdata[0];
 
   assign phy_alert_cfg_alert_trig_wd = reg_wdata[1];
-  assign scratch_we = addr_hit[97] & reg_we & !reg_error;
+  assign scratch_we = addr_hit[94] & reg_we & !reg_error;
 
   assign scratch_wd = reg_wdata[31:0];
-  assign fifo_lvl_we = addr_hit[98] & reg_we & !reg_error;
+  assign fifo_lvl_we = addr_hit[95] & reg_we & !reg_error;
 
   assign fifo_lvl_prog_wd = reg_wdata[4:0];
 
   assign fifo_lvl_rd_wd = reg_wdata[12:8];
-  assign fifo_rst_we = addr_hit[99] & reg_we & !reg_error;
+  assign fifo_rst_we = addr_hit[96] & reg_we & !reg_error;
 
   assign fifo_rst_wd = reg_wdata[0];
 
@@ -11351,7 +11286,7 @@
         reg_rdata_next[2] = intr_state_rd_full_qs;
         reg_rdata_next[3] = intr_state_rd_lvl_qs;
         reg_rdata_next[4] = intr_state_op_done_qs;
-        reg_rdata_next[5] = intr_state_err_qs;
+        reg_rdata_next[5] = intr_state_corr_err_qs;
       end
 
       addr_hit[1]: begin
@@ -11360,7 +11295,7 @@
         reg_rdata_next[2] = intr_enable_rd_full_qs;
         reg_rdata_next[3] = intr_enable_rd_lvl_qs;
         reg_rdata_next[4] = intr_enable_op_done_qs;
-        reg_rdata_next[5] = intr_enable_err_qs;
+        reg_rdata_next[5] = intr_enable_corr_err_qs;
       end
 
       addr_hit[2]: begin
@@ -11375,8 +11310,6 @@
       addr_hit[3]: begin
         reg_rdata_next[0] = '0;
         reg_rdata_next[1] = '0;
-        reg_rdata_next[2] = '0;
-        reg_rdata_next[3] = '0;
       end
 
       addr_hit[4]: begin
@@ -11938,29 +11871,32 @@
       end
 
       addr_hit[84]: begin
-        reg_rdata_next[0] = err_code_intr_en_flash_err_en_qs;
-        reg_rdata_next[1] = err_code_intr_en_flash_alert_en_qs;
-        reg_rdata_next[2] = err_code_intr_en_oob_err_qs;
-        reg_rdata_next[3] = err_code_intr_en_mp_err_qs;
-        reg_rdata_next[4] = err_code_intr_en_ecc_single_err_qs;
-        reg_rdata_next[5] = err_code_intr_en_ecc_multi_err_qs;
+        reg_rdata_next[0] = err_code_oob_err_qs;
+        reg_rdata_next[1] = err_code_mp_err_qs;
+        reg_rdata_next[2] = err_code_rd_err_qs;
+        reg_rdata_next[3] = err_code_prog_win_err_qs;
+        reg_rdata_next[4] = err_code_prog_type_err_qs;
+        reg_rdata_next[5] = err_code_flash_phy_err_qs;
       end
 
       addr_hit[85]: begin
-        reg_rdata_next[0] = err_code_flash_err_qs;
-        reg_rdata_next[1] = err_code_flash_alert_qs;
-        reg_rdata_next[2] = err_code_oob_err_qs;
-        reg_rdata_next[3] = err_code_mp_err_qs;
-        reg_rdata_next[4] = err_code_ecc_single_err_qs;
-        reg_rdata_next[5] = err_code_ecc_multi_err_qs;
+        reg_rdata_next[0] = fault_status_oob_err_qs;
+        reg_rdata_next[1] = fault_status_mp_err_qs;
+        reg_rdata_next[2] = fault_status_rd_err_qs;
+        reg_rdata_next[3] = fault_status_prog_win_err_qs;
+        reg_rdata_next[4] = fault_status_prog_type_err_qs;
+        reg_rdata_next[5] = fault_status_flash_phy_err_qs;
+        reg_rdata_next[6] = fault_status_reg_intg_err_qs;
+        reg_rdata_next[7] = fault_status_phy_intg_err_qs;
       end
 
       addr_hit[86]: begin
-        reg_rdata_next[8:0] = err_addr_qs;
+        reg_rdata_next[31:0] = err_addr_qs;
       end
 
       addr_hit[87]: begin
-        reg_rdata_next[7:0] = ecc_single_err_cnt_qs;
+        reg_rdata_next[7:0] = ecc_single_err_cnt_ecc_single_err_cnt_0_qs;
+        reg_rdata_next[15:8] = ecc_single_err_cnt_ecc_single_err_cnt_1_qs;
       end
 
       addr_hit[88]: begin
@@ -11972,46 +11908,34 @@
       end
 
       addr_hit[90]: begin
-        reg_rdata_next[7:0] = ecc_multi_err_cnt_qs;
-      end
-
-      addr_hit[91]: begin
-        reg_rdata_next[19:0] = ecc_multi_err_addr_0_qs;
-      end
-
-      addr_hit[92]: begin
-        reg_rdata_next[19:0] = ecc_multi_err_addr_1_qs;
-      end
-
-      addr_hit[93]: begin
         reg_rdata_next[0] = phy_err_cfg_regwen_qs;
       end
 
-      addr_hit[94]: begin
+      addr_hit[91]: begin
         reg_rdata_next[0] = phy_err_cfg_qs;
       end
 
-      addr_hit[95]: begin
+      addr_hit[92]: begin
         reg_rdata_next[0] = phy_alert_cfg_alert_ack_qs;
         reg_rdata_next[1] = phy_alert_cfg_alert_trig_qs;
       end
 
-      addr_hit[96]: begin
+      addr_hit[93]: begin
         reg_rdata_next[0] = phy_status_init_wip_qs;
         reg_rdata_next[1] = phy_status_prog_normal_avail_qs;
         reg_rdata_next[2] = phy_status_prog_repair_avail_qs;
       end
 
-      addr_hit[97]: begin
+      addr_hit[94]: begin
         reg_rdata_next[31:0] = scratch_qs;
       end
 
-      addr_hit[98]: begin
+      addr_hit[95]: begin
         reg_rdata_next[4:0] = fifo_lvl_prog_qs;
         reg_rdata_next[12:8] = fifo_lvl_rd_qs;
       end
 
-      addr_hit[99]: begin
+      addr_hit[96]: begin
         reg_rdata_next[0] = fifo_rst_qs;
       end
 
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
index b20e22b..9243916 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
@@ -12,14 +12,16 @@
   input [BusAddrW-1:0]        op_addr_i,
   input                       op_addr_oob_i,
   output logic                op_done_o,
-  output logic                op_err_o,
+  output flash_ctrl_err_t     op_err_o,
+  output logic [BusAddrW-1:0] op_err_addr_o,
 
   // Flash Macro Interface
   output logic                flash_req_o,
   output logic [BusAddrW-1:0] flash_addr_o,
   output flash_erase_e        flash_op_o,
   input                       flash_done_i,
-  input                       flash_error_i
+  input                       flash_mp_err_i,
+  input                       flash_phy_err_i
 );
 
   import flash_ctrl_pkg::*;
@@ -42,8 +44,15 @@
   assign oob_err = op_start_i & op_addr_oob_i;
 
   // IO assignments
-  assign op_done_o = flash_req_o & flash_done_i | oob_err;
-  assign op_err_o = flash_req_o & flash_error_i | oob_err;
+  assign op_done_o = flash_req_o & (flash_done_i | oob_err);
+
+  always_comb begin
+    op_err_o = '0;
+    op_err_o.oob_err = op_done_o & oob_err;
+    op_err_o.mp_err = op_done_o & flash_mp_err_i;
+    op_err_o.phy_err = op_done_o & flash_phy_err_i;
+  end
+
 
   // Flash Interface assignments
   assign flash_req_o = op_start_i & ~op_addr_oob_i;
@@ -52,6 +61,8 @@
                         op_addr_i & PageAddrMask :
                         op_addr_i & BankAddrMask;
 
+  assign op_err_addr_o = flash_addr_o;
+
   // unused bus
   logic [WordsBitWidth-1:0] unused_addr_i;
   assign unused_addr_i = op_addr_i[WordsBitWidth-1:0];
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
index fd5931b..53b8e1f 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
@@ -25,7 +25,7 @@
   output logic req_o,
   output logic [top_pkg::TL_AW-1:0] addr_o,
   input done_i,
-  input err_i,
+  input flash_ctrl_err_t err_i,
 
   // interface to ctrl_arb data ports
   output logic rready_o,
@@ -590,7 +590,7 @@
         rma_start = 1'b1;
         rma_op = FlashOpErase;
         if (done_i) begin
-          err_sts_set = err_i;
+          err_sts_set = |err_i;
           rma_state_d = StRmaWordSel;
         end
       end
@@ -621,7 +621,7 @@
 
         if (done_i) begin
           beat_cnt_clr = 1'b1;
-          err_sts_set = err_i;
+          err_sts_set = |err_i;
           rma_state_d = StRmaRdVerify;
         end
       end
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
index 46b6a37..2cd5948 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
@@ -364,10 +364,7 @@
     logic [BusWidth-1:0] rd_data;
     logic                init_busy;
     logic                flash_err;
-    logic                flash_alert_p;
-    logic                flash_alert_n;
     logic [NumBanks-1:0] ecc_single_err;
-    logic [NumBanks-1:0] ecc_multi_err;
     logic [NumBanks-1:0][BusAddrW-1:0] ecc_addr;
     jtag_pkg::jtag_rsp_t jtag_rsp;
     logic                intg_err;
@@ -383,10 +380,7 @@
     rd_data:            '0,
     init_busy:          1'b0,
     flash_err:          1'b0,
-    flash_alert_p:      1'b0,
-    flash_alert_n:      1'b1,
     ecc_single_err:     '0,
-    ecc_multi_err:      '0,
     ecc_addr:           '0,
     jtag_rsp:           '0,
     intg_err:           '0
@@ -468,6 +462,27 @@
     FlashLcDftLast
   } flash_lc_jtag_e;
 
+  // Error bit positioning
+  typedef struct packed {
+    logic oob_err;
+    logic mp_err;
+    logic rd_err;
+    logic prog_win_err;
+    logic prog_type_err;
+    logic phy_err;
+  } flash_ctrl_err_t;
+
+  // interrupt bit positioning
+  typedef enum logic[2:0] {
+    ProgEmpty,
+    ProgLvl,
+    RdFull,
+    RdLvl,
+    OpDone,
+    CorrErr,
+    LastIntrIdx
+  } flash_ctrl_intr_e;
+
   // find the max number pages among info types
   function automatic integer max_info_pages(int infos[InfoTypes]);
     int current_max = 0;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
index 6c5f714..9b925e9 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
@@ -13,11 +13,12 @@
   input                    op_start_i,
   input  [11:0]            op_num_words_i,
   output logic             op_done_o,
-  output logic             op_err_o,
+  output flash_ctrl_err_t  op_err_o,
   input [BusAddrW-1:0]     op_addr_i,
   input                    op_addr_oob_i,
   input flash_prog_e       op_type_i,
   input [ProgTypes-1:0]    type_avail_i,
+  output logic [BusAddrW-1:0] op_err_addr_o,
 
   // FIFO Interface
   input                    data_rdy_i,
@@ -32,7 +33,8 @@
   output logic             flash_last_o, // last beat of prog data
   output flash_prog_e      flash_type_o,
   input                    flash_done_i,
-  input                    flash_error_i
+  input                    flash_phy_err_i,
+  input                    flash_mp_err_i
 );
 
   typedef enum logic {
@@ -40,26 +42,53 @@
     StErr   = 'h1
   } state_e;
 
-  state_e st, st_nxt;
-  logic [11:0] cnt, cnt_nxt;
+  state_e st_q, st_d;
+  logic [11:0] cnt;
   logic cnt_hit;
   logic [BusAddrW:0] int_addr;
   logic txn_done;
 
+  flash_ctrl_err_t op_err_q, op_err_d;
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      st_q <= StNorm;
+    end else begin
+      st_q <= st_d;
+    end
+  end
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
       cnt <= '0;
-      st <= StNorm;
-    end else begin
-      cnt <= cnt_nxt;
-      st <= st_nxt;
+    end else if (op_start_i && op_done_o) begin
+      cnt <= '0;
+    end else if (data_rd_o) begin
+      cnt <= cnt + 1'b1;
+    end
+  end
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      op_err_addr_o <= '0;
+    end else if (~|op_err_q && |op_err_d) begin
+      op_err_addr_o <= flash_addr_o;
     end
   end
 
   assign txn_done = flash_req_o && flash_done_i;
   assign cnt_hit = (cnt == op_num_words_i);
 
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      op_err_q <= '0;
+    end else if (op_start_i && op_done_o) begin
+      op_err_q <= '0;
+    end else begin
+      op_err_q <= op_err_d;
+    end
+  end
+
   // if the requested prog type is available
   logic prog_type_avail;
   assign prog_type_avail = type_avail_i[op_type_i];
@@ -70,53 +99,58 @@
   localparam int WindowWidth = BusAddrW - BusPgmResWidth;
   logic [WindowWidth-1:0] start_window, end_window;
   logic [BusAddrW-1:0] end_addr;
+  logic pgm_res_err;
   logic win_err;
   assign end_addr = op_addr_i + BusAddrW'(op_num_words_i);
   assign start_window = op_addr_i[BusAddrW-1:BusPgmResWidth];
   assign end_window = end_addr[BusAddrW-1:BusPgmResWidth];
-  assign win_err = (start_window != end_window) | op_addr_oob_i;
+  assign pgm_res_err = start_window != end_window;
+  assign win_err = pgm_res_err | op_addr_oob_i;
 
   // when error'd, continue to drain all program fifo contents like normal operation
   // if this is not done, software may fill up the fifo without anyone
   // draining the contents, leading to a lockup
   always_comb begin
-    st_nxt = st;
-    cnt_nxt = cnt;
+    st_d = st_q;
     flash_req_o = 1'b0;
     data_rd_o = 1'b0;
     op_done_o = 1'b0;
-    op_err_o = 1'b0;
+    op_err_d = op_err_q;
 
-    unique case (st)
+    unique case (st_q)
+
+      // Note the address counter is incremented on tx_done
+      // and cleared when the entire operation is complete.
       StNorm: begin
         // if the select operation type is not available, error
         if (op_start_i && prog_type_avail && !win_err) begin
           flash_req_o = data_rdy_i;
 
-          if(txn_done && cnt_hit) begin
-            cnt_nxt = '0;
+          if (txn_done) begin
+            op_err_d.mp_err = flash_mp_err_i;
+            op_err_d.phy_err = flash_phy_err_i;
             data_rd_o = 1'b1;
-            op_done_o = 1'b1;
-            op_err_o = flash_error_i;
-          end else if(txn_done) begin
-            cnt_nxt = cnt + 1'b1;
-            data_rd_o = 1'b1;
-            st_nxt = flash_error_i ? StErr : StNorm;
+
+            if (cnt_hit) begin
+              op_done_o = 1'b1;
+            end else begin
+              st_d = |op_err_d ? StErr : StNorm;
+            end
           end
+
         end else if (op_start_i && (!prog_type_avail || win_err)) begin
-          st_nxt = StErr;
+          op_err_d.oob_err = op_addr_oob_i;
+          op_err_d.prog_type_err = !prog_type_avail;
+          op_err_d.prog_win_err = pgm_res_err;
+          st_d = StErr;
         end
       end
       StErr: begin
         data_rd_o = data_rdy_i;
 
         if (data_rdy_i && cnt_hit) begin
-          st_nxt = StNorm;
-          cnt_nxt = '0;
+          st_d = StNorm;
           op_done_o = 1'b1;
-          op_err_o = 1'b1;
-        end else if (data_rdy_i) begin
-          cnt_nxt = cnt + 1'b1;
         end
       end
       default:;
@@ -129,6 +163,7 @@
   assign flash_ovfl_o = int_addr[BusAddrW];
   assign flash_last_o = flash_req_o & cnt_hit;
   assign flash_type_o = op_type_i;
+  assign op_err_o = op_err_q | op_err_d;
 
   // unused signals
   logic [BusPgmResWidth-1:0] unused_end_addr;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
index 80d7f99..4973761 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_rd.sv
@@ -13,9 +13,10 @@
   input                    op_start_i,
   input  [11:0]            op_num_words_i,
   output logic             op_done_o,
-  output logic             op_err_o,
+  flash_ctrl_err_t         op_err_o,
   input [BusAddrW-1:0]     op_addr_i,
   input                    op_addr_oob_i,
+  output logic [BusAddrW-1:0] op_err_addr_o,
 
   // FIFO Interface
   input                    data_rdy_i,
@@ -28,7 +29,9 @@
   output logic             flash_ovfl_o,
   input [BusWidth-1:0]     flash_data_i,
   input                    flash_done_i,
-  input                    flash_error_i
+  input                    flash_phy_err_i,
+  input                    flash_rd_err_i,
+  input                    flash_mp_err_i
 );
 
   typedef enum logic [1:0] {
@@ -37,75 +40,100 @@
     StErr
   } state_e;
 
-  state_e st, st_nxt;
-  logic [11:0] cnt, cnt_nxt;
+  state_e st_q, st_d;
+  logic [11:0] cnt;
   logic cnt_hit;
   logic [BusAddrW:0] int_addr;
   logic txn_done;
   logic err_sel; //1 selects error data, 0 selects normal data
+  flash_ctrl_err_t op_err_q, op_err_d;
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      st_q <= StIdle;
+    end else begin
+      st_q <= st_d;
+    end
+  end
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      op_err_q <= '0;
+    end else if (op_start_i && op_done_o) begin
+      op_err_q <= '0;
+    end else begin
+      op_err_q <= op_err_d;
+    end
+  end
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
       cnt <= '0;
-      st <= StIdle;
-    end else begin
-      cnt <= cnt_nxt;
-      st <= st_nxt;
+    end else if (op_start_i && op_done_o) begin
+      cnt <= '0;
+    end else if (data_wr_o) begin
+      cnt <= cnt + 1'b1;
+    end
+  end
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      op_err_addr_o <= '0;
+    end else if (~|op_err_q && |op_err_d) begin
+      op_err_addr_o <= flash_addr_o;
     end
   end
 
   assign txn_done = flash_req_o & flash_done_i;
   assign cnt_hit = (cnt == op_num_words_i);
 
+
   // when error'd, continue to complete existing read transaction but fill in with all 1's
   // if this is not done, software may continue to attempt to read out of the fifo
   // and eventually cause a bus deadlock as the fifo would be empty
   // This scheme is similar to burst completion up an error
   always_comb begin
-    st_nxt = st;
-    cnt_nxt = cnt;
+    st_d = st_q;
     flash_req_o = 1'b0;
     data_wr_o = 1'b0;
     op_done_o = 1'b0;
-    op_err_o = 1'b0;
-    err_sel = 1'b0;
+    op_err_d = op_err_q;
 
-    unique case (st)
+    unique case (st_q)
       StIdle: begin
-        if (op_start_i && op_addr_oob_i) begin
-          st_nxt = StErr;
-        end else if (op_start_i) begin
-          st_nxt = StNorm;
+        if (op_start_i) begin
+          op_err_d.oob_err = op_addr_oob_i;
+          st_d = |op_err_d ? StErr : StNorm;
         end
       end
 
+      // Note the address counter is incremented on tx_done
+      // and cleared when the entire operation is complete.
       StNorm: begin
         flash_req_o = op_start_i & data_rdy_i;
 
-        if (txn_done && cnt_hit) begin
-          cnt_nxt = '0;
+        if (txn_done) begin
+          op_err_d.mp_err = flash_mp_err_i;
+          op_err_d.rd_err = flash_rd_err_i;
+          op_err_d.phy_err = flash_phy_err_i;
+
           data_wr_o = 1'b1;
-          op_done_o = 1'b1;
-          op_err_o = flash_error_i;
-        end else if (txn_done) begin
-          cnt_nxt = cnt + 1'b1;
-          data_wr_o = 1'b1;
-          err_sel = flash_error_i;
-          st_nxt = flash_error_i ? StErr : StIdle;
+
+          if (cnt_hit) begin
+            op_done_o = 1'b1;
+            st_d = StIdle;
+          end else begin
+            st_d = |op_err_d ? StErr : StNorm;
+          end
         end
       end
 
       StErr: begin
         data_wr_o = data_rdy_i;
-        err_sel = 1'b1;
 
         if (data_rdy_i && cnt_hit) begin
-          st_nxt = StIdle;
-          cnt_nxt = '0;
+          st_d = StIdle;
           op_done_o = 1'b1;
-          op_err_o = 1'b1;
-        end else if (data_rdy_i) begin
-          cnt_nxt = cnt + 1'b1;
         end
       end
       default:;
@@ -117,7 +145,9 @@
   assign flash_addr_o = int_addr[0 +: BusAddrW];
   assign flash_ovfl_o = int_addr[BusAddrW];
   // if error, return "empty" data
+  assign err_sel = data_wr_o & |op_err_o;
   assign data_o = err_sel ? {BusWidth{1'b1}} : flash_data_i;
+  assign op_err_o = op_err_q | op_err_d;
 
 
 endmodule // flash_ctrl_rd
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv
index 7955b1f..2d8ce15 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv
@@ -20,7 +20,7 @@
   parameter int BytesPerWord = 8;
   parameter int BytesPerPage = 2048;
   parameter int BytesPerBank = 524288;
-  parameter int NumAlerts = 4;
+  parameter int NumAlerts = 2;
 
   // Address widths within the block
   parameter int CoreAw = 9;
@@ -49,7 +49,7 @@
     } op_done;
     struct packed {
       logic        q;
-    } err;
+    } corr_err;
   } flash_ctrl_reg2hw_intr_state_reg_t;
 
   typedef struct packed {
@@ -70,7 +70,7 @@
     } op_done;
     struct packed {
       logic        q;
-    } err;
+    } corr_err;
   } flash_ctrl_reg2hw_intr_enable_reg_t;
 
   typedef struct packed {
@@ -97,7 +97,7 @@
     struct packed {
       logic        q;
       logic        qe;
-    } err;
+    } corr_err;
   } flash_ctrl_reg2hw_intr_test_reg_t;
 
   typedef struct packed {
@@ -108,15 +108,7 @@
     struct packed {
       logic        q;
       logic        qe;
-    } recov_mp_err;
-    struct packed {
-      logic        q;
-      logic        qe;
-    } recov_ecc_err;
-    struct packed {
-      logic        q;
-      logic        qe;
-    } fatal_intg_err;
+    } fatal_err;
   } flash_ctrl_reg2hw_alert_test_reg_t;
 
   typedef struct packed {
@@ -370,52 +362,33 @@
   typedef struct packed {
     struct packed {
       logic        q;
-    } flash_err_en;
-    struct packed {
-      logic        q;
-    } flash_alert_en;
-    struct packed {
-      logic        q;
     } oob_err;
     struct packed {
       logic        q;
     } mp_err;
     struct packed {
       logic        q;
-    } ecc_single_err;
+    } rd_err;
     struct packed {
       logic        q;
-    } ecc_multi_err;
-  } flash_ctrl_reg2hw_err_code_intr_en_reg_t;
-
-  typedef struct packed {
+    } prog_win_err;
     struct packed {
       logic        q;
-    } flash_err;
+    } prog_type_err;
     struct packed {
       logic        q;
-    } flash_alert;
+    } flash_phy_err;
     struct packed {
       logic        q;
-    } oob_err;
+    } reg_intg_err;
     struct packed {
       logic        q;
-    } mp_err;
-    struct packed {
-      logic        q;
-    } ecc_single_err;
-    struct packed {
-      logic        q;
-    } ecc_multi_err;
-  } flash_ctrl_reg2hw_err_code_reg_t;
+    } phy_intg_err;
+  } flash_ctrl_reg2hw_fault_status_reg_t;
 
   typedef struct packed {
     logic [7:0]  q;
-  } flash_ctrl_reg2hw_ecc_single_err_cnt_reg_t;
-
-  typedef struct packed {
-    logic [7:0]  q;
-  } flash_ctrl_reg2hw_ecc_multi_err_cnt_reg_t;
+  } flash_ctrl_reg2hw_ecc_single_err_cnt_mreg_t;
 
   typedef struct packed {
     logic        q;
@@ -471,7 +444,7 @@
     struct packed {
       logic        d;
       logic        de;
-    } err;
+    } corr_err;
   } flash_ctrl_hw2reg_intr_state_reg_t;
 
   typedef struct packed {
@@ -528,11 +501,30 @@
     struct packed {
       logic        d;
       logic        de;
-    } flash_err;
+    } oob_err;
     struct packed {
       logic        d;
       logic        de;
-    } flash_alert;
+    } mp_err;
+    struct packed {
+      logic        d;
+      logic        de;
+    } rd_err;
+    struct packed {
+      logic        d;
+      logic        de;
+    } prog_win_err;
+    struct packed {
+      logic        d;
+      logic        de;
+    } prog_type_err;
+    struct packed {
+      logic        d;
+      logic        de;
+    } flash_phy_err;
+  } flash_ctrl_hw2reg_err_code_reg_t;
+
+  typedef struct packed {
     struct packed {
       logic        d;
       logic        de;
@@ -544,22 +536,38 @@
     struct packed {
       logic        d;
       logic        de;
-    } ecc_single_err;
+    } rd_err;
     struct packed {
       logic        d;
       logic        de;
-    } ecc_multi_err;
-  } flash_ctrl_hw2reg_err_code_reg_t;
+    } prog_win_err;
+    struct packed {
+      logic        d;
+      logic        de;
+    } prog_type_err;
+    struct packed {
+      logic        d;
+      logic        de;
+    } flash_phy_err;
+    struct packed {
+      logic        d;
+      logic        de;
+    } reg_intg_err;
+    struct packed {
+      logic        d;
+      logic        de;
+    } phy_intg_err;
+  } flash_ctrl_hw2reg_fault_status_reg_t;
 
   typedef struct packed {
-    logic [8:0]  d;
+    logic [31:0] d;
     logic        de;
   } flash_ctrl_hw2reg_err_addr_reg_t;
 
   typedef struct packed {
     logic [7:0]  d;
     logic        de;
-  } flash_ctrl_hw2reg_ecc_single_err_cnt_reg_t;
+  } flash_ctrl_hw2reg_ecc_single_err_cnt_mreg_t;
 
   typedef struct packed {
     logic [19:0] d;
@@ -567,16 +575,6 @@
   } flash_ctrl_hw2reg_ecc_single_err_addr_mreg_t;
 
   typedef struct packed {
-    logic [7:0]  d;
-    logic        de;
-  } flash_ctrl_hw2reg_ecc_multi_err_cnt_reg_t;
-
-  typedef struct packed {
-    logic [19:0] d;
-    logic        de;
-  } flash_ctrl_hw2reg_ecc_multi_err_addr_mreg_t;
-
-  typedef struct packed {
     struct packed {
       logic        d;
       logic        de;
@@ -593,29 +591,27 @@
 
   // Register -> HW type for core interface
   typedef struct packed {
-    flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [560:555]
-    flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [554:549]
-    flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [548:537]
-    flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [536:529]
-    flash_ctrl_reg2hw_flash_disable_reg_t flash_disable; // [528:528]
-    flash_ctrl_reg2hw_init_reg_t init; // [527:527]
-    flash_ctrl_reg2hw_control_reg_t control; // [526:507]
-    flash_ctrl_reg2hw_addr_reg_t addr; // [506:475]
-    flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [474:473]
-    flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [472:472]
-    flash_ctrl_reg2hw_mp_region_cfg_mreg_t [7:0] mp_region_cfg; // [471:264]
-    flash_ctrl_reg2hw_default_region_reg_t default_region; // [263:258]
-    flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t [9:0] bank0_info0_page_cfg; // [257:188]
-    flash_ctrl_reg2hw_bank0_info1_page_cfg_mreg_t [0:0] bank0_info1_page_cfg; // [187:181]
-    flash_ctrl_reg2hw_bank0_info2_page_cfg_mreg_t [1:0] bank0_info2_page_cfg; // [180:167]
-    flash_ctrl_reg2hw_bank1_info0_page_cfg_mreg_t [9:0] bank1_info0_page_cfg; // [166:97]
-    flash_ctrl_reg2hw_bank1_info1_page_cfg_mreg_t [0:0] bank1_info1_page_cfg; // [96:90]
-    flash_ctrl_reg2hw_bank1_info2_page_cfg_mreg_t [1:0] bank1_info2_page_cfg; // [89:76]
-    flash_ctrl_reg2hw_mp_bank_cfg_mreg_t [1:0] mp_bank_cfg; // [75:74]
-    flash_ctrl_reg2hw_err_code_intr_en_reg_t err_code_intr_en; // [73:68]
-    flash_ctrl_reg2hw_err_code_reg_t err_code; // [67:62]
-    flash_ctrl_reg2hw_ecc_single_err_cnt_reg_t ecc_single_err_cnt; // [61:54]
-    flash_ctrl_reg2hw_ecc_multi_err_cnt_reg_t ecc_multi_err_cnt; // [53:46]
+    flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [552:547]
+    flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [546:541]
+    flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [540:529]
+    flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [528:525]
+    flash_ctrl_reg2hw_flash_disable_reg_t flash_disable; // [524:524]
+    flash_ctrl_reg2hw_init_reg_t init; // [523:523]
+    flash_ctrl_reg2hw_control_reg_t control; // [522:503]
+    flash_ctrl_reg2hw_addr_reg_t addr; // [502:471]
+    flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [470:469]
+    flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [468:468]
+    flash_ctrl_reg2hw_mp_region_cfg_mreg_t [7:0] mp_region_cfg; // [467:260]
+    flash_ctrl_reg2hw_default_region_reg_t default_region; // [259:254]
+    flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t [9:0] bank0_info0_page_cfg; // [253:184]
+    flash_ctrl_reg2hw_bank0_info1_page_cfg_mreg_t [0:0] bank0_info1_page_cfg; // [183:177]
+    flash_ctrl_reg2hw_bank0_info2_page_cfg_mreg_t [1:0] bank0_info2_page_cfg; // [176:163]
+    flash_ctrl_reg2hw_bank1_info0_page_cfg_mreg_t [9:0] bank1_info0_page_cfg; // [162:93]
+    flash_ctrl_reg2hw_bank1_info1_page_cfg_mreg_t [0:0] bank1_info1_page_cfg; // [92:86]
+    flash_ctrl_reg2hw_bank1_info2_page_cfg_mreg_t [1:0] bank1_info2_page_cfg; // [85:72]
+    flash_ctrl_reg2hw_mp_bank_cfg_mreg_t [1:0] mp_bank_cfg; // [71:70]
+    flash_ctrl_reg2hw_fault_status_reg_t fault_status; // [69:62]
+    flash_ctrl_reg2hw_ecc_single_err_cnt_mreg_t [1:0] ecc_single_err_cnt; // [61:46]
     flash_ctrl_reg2hw_phy_err_cfg_reg_t phy_err_cfg; // [45:45]
     flash_ctrl_reg2hw_phy_alert_cfg_reg_t phy_alert_cfg; // [44:43]
     flash_ctrl_reg2hw_scratch_reg_t scratch; // [42:11]
@@ -625,18 +621,17 @@
 
   // HW -> register type for core interface
   typedef struct packed {
-    flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [160:149]
-    flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [148:148]
-    flash_ctrl_hw2reg_control_reg_t control; // [147:146]
-    flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [145:144]
-    flash_ctrl_hw2reg_op_status_reg_t op_status; // [143:140]
-    flash_ctrl_hw2reg_status_reg_t status; // [139:130]
-    flash_ctrl_hw2reg_err_code_reg_t err_code; // [129:118]
-    flash_ctrl_hw2reg_err_addr_reg_t err_addr; // [117:108]
-    flash_ctrl_hw2reg_ecc_single_err_cnt_reg_t ecc_single_err_cnt; // [107:99]
-    flash_ctrl_hw2reg_ecc_single_err_addr_mreg_t [1:0] ecc_single_err_addr; // [98:57]
-    flash_ctrl_hw2reg_ecc_multi_err_cnt_reg_t ecc_multi_err_cnt; // [56:48]
-    flash_ctrl_hw2reg_ecc_multi_err_addr_mreg_t [1:0] ecc_multi_err_addr; // [47:6]
+    flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [157:146]
+    flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [145:145]
+    flash_ctrl_hw2reg_control_reg_t control; // [144:143]
+    flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [142:141]
+    flash_ctrl_hw2reg_op_status_reg_t op_status; // [140:137]
+    flash_ctrl_hw2reg_status_reg_t status; // [136:127]
+    flash_ctrl_hw2reg_err_code_reg_t err_code; // [126:115]
+    flash_ctrl_hw2reg_fault_status_reg_t fault_status; // [114:99]
+    flash_ctrl_hw2reg_err_addr_reg_t err_addr; // [98:66]
+    flash_ctrl_hw2reg_ecc_single_err_cnt_mreg_t [1:0] ecc_single_err_cnt; // [65:48]
+    flash_ctrl_hw2reg_ecc_single_err_addr_mreg_t [1:0] ecc_single_err_addr; // [47:6]
     flash_ctrl_hw2reg_phy_status_reg_t phy_status; // [5:0]
   } flash_ctrl_core_hw2reg_t;
 
@@ -725,22 +720,19 @@
   parameter logic [CoreAw-1:0] FLASH_CTRL_MP_BANK_CFG_OFFSET = 9'h 144;
   parameter logic [CoreAw-1:0] FLASH_CTRL_OP_STATUS_OFFSET = 9'h 148;
   parameter logic [CoreAw-1:0] FLASH_CTRL_STATUS_OFFSET = 9'h 14c;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_ERR_CODE_INTR_EN_OFFSET = 9'h 150;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_ERR_CODE_OFFSET = 9'h 154;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_ERR_CODE_OFFSET = 9'h 150;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_FAULT_STATUS_OFFSET = 9'h 154;
   parameter logic [CoreAw-1:0] FLASH_CTRL_ERR_ADDR_OFFSET = 9'h 158;
   parameter logic [CoreAw-1:0] FLASH_CTRL_ECC_SINGLE_ERR_CNT_OFFSET = 9'h 15c;
   parameter logic [CoreAw-1:0] FLASH_CTRL_ECC_SINGLE_ERR_ADDR_0_OFFSET = 9'h 160;
   parameter logic [CoreAw-1:0] FLASH_CTRL_ECC_SINGLE_ERR_ADDR_1_OFFSET = 9'h 164;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_ECC_MULTI_ERR_CNT_OFFSET = 9'h 168;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_ECC_MULTI_ERR_ADDR_0_OFFSET = 9'h 16c;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_ECC_MULTI_ERR_ADDR_1_OFFSET = 9'h 170;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_PHY_ERR_CFG_REGWEN_OFFSET = 9'h 174;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_PHY_ERR_CFG_OFFSET = 9'h 178;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_PHY_ALERT_CFG_OFFSET = 9'h 17c;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_PHY_STATUS_OFFSET = 9'h 180;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_SCRATCH_OFFSET = 9'h 184;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_FIFO_LVL_OFFSET = 9'h 188;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_FIFO_RST_OFFSET = 9'h 18c;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_PHY_ERR_CFG_REGWEN_OFFSET = 9'h 168;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_PHY_ERR_CFG_OFFSET = 9'h 16c;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_PHY_ALERT_CFG_OFFSET = 9'h 170;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_PHY_STATUS_OFFSET = 9'h 174;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_SCRATCH_OFFSET = 9'h 178;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_FIFO_LVL_OFFSET = 9'h 17c;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_FIFO_RST_OFFSET = 9'h 180;
 
   // Reset values for hwext registers and their fields for core interface
   parameter logic [5:0] FLASH_CTRL_INTR_TEST_RESVAL = 6'h 0;
@@ -749,19 +741,17 @@
   parameter logic [0:0] FLASH_CTRL_INTR_TEST_RD_FULL_RESVAL = 1'h 0;
   parameter logic [0:0] FLASH_CTRL_INTR_TEST_RD_LVL_RESVAL = 1'h 0;
   parameter logic [0:0] FLASH_CTRL_INTR_TEST_OP_DONE_RESVAL = 1'h 0;
-  parameter logic [0:0] FLASH_CTRL_INTR_TEST_ERR_RESVAL = 1'h 0;
-  parameter logic [3:0] FLASH_CTRL_ALERT_TEST_RESVAL = 4'h 0;
+  parameter logic [0:0] FLASH_CTRL_INTR_TEST_CORR_ERR_RESVAL = 1'h 0;
+  parameter logic [1:0] FLASH_CTRL_ALERT_TEST_RESVAL = 2'h 0;
   parameter logic [0:0] FLASH_CTRL_ALERT_TEST_RECOV_ERR_RESVAL = 1'h 0;
-  parameter logic [0:0] FLASH_CTRL_ALERT_TEST_RECOV_MP_ERR_RESVAL = 1'h 0;
-  parameter logic [0:0] FLASH_CTRL_ALERT_TEST_RECOV_ECC_ERR_RESVAL = 1'h 0;
-  parameter logic [0:0] FLASH_CTRL_ALERT_TEST_FATAL_INTG_ERR_RESVAL = 1'h 0;
+  parameter logic [0:0] FLASH_CTRL_ALERT_TEST_FATAL_ERR_RESVAL = 1'h 0;
   parameter logic [0:0] FLASH_CTRL_CTRL_REGWEN_RESVAL = 1'h 1;
   parameter logic [0:0] FLASH_CTRL_CTRL_REGWEN_EN_RESVAL = 1'h 1;
 
   // Window parameters for core interface
-  parameter logic [CoreAw-1:0] FLASH_CTRL_PROG_FIFO_OFFSET = 9'h 190;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_PROG_FIFO_OFFSET = 9'h 184;
   parameter int unsigned       FLASH_CTRL_PROG_FIFO_SIZE   = 'h 4;
-  parameter logic [CoreAw-1:0] FLASH_CTRL_RD_FIFO_OFFSET = 9'h 194;
+  parameter logic [CoreAw-1:0] FLASH_CTRL_RD_FIFO_OFFSET = 9'h 188;
   parameter int unsigned       FLASH_CTRL_RD_FIFO_SIZE   = 'h 4;
 
   // Register index for core interface
@@ -850,15 +840,12 @@
     FLASH_CTRL_MP_BANK_CFG,
     FLASH_CTRL_OP_STATUS,
     FLASH_CTRL_STATUS,
-    FLASH_CTRL_ERR_CODE_INTR_EN,
     FLASH_CTRL_ERR_CODE,
+    FLASH_CTRL_FAULT_STATUS,
     FLASH_CTRL_ERR_ADDR,
     FLASH_CTRL_ECC_SINGLE_ERR_CNT,
     FLASH_CTRL_ECC_SINGLE_ERR_ADDR_0,
     FLASH_CTRL_ECC_SINGLE_ERR_ADDR_1,
-    FLASH_CTRL_ECC_MULTI_ERR_CNT,
-    FLASH_CTRL_ECC_MULTI_ERR_ADDR_0,
-    FLASH_CTRL_ECC_MULTI_ERR_ADDR_1,
     FLASH_CTRL_PHY_ERR_CFG_REGWEN,
     FLASH_CTRL_PHY_ERR_CFG,
     FLASH_CTRL_PHY_ALERT_CFG,
@@ -869,7 +856,7 @@
   } flash_ctrl_core_id_e;
 
   // Register width information to check illegal writes for core interface
-  parameter logic [3:0] FLASH_CTRL_CORE_PERMIT [100] = '{
+  parameter logic [3:0] FLASH_CTRL_CORE_PERMIT [97] = '{
     4'b 0001, // index[ 0] FLASH_CTRL_INTR_STATE
     4'b 0001, // index[ 1] FLASH_CTRL_INTR_ENABLE
     4'b 0001, // index[ 2] FLASH_CTRL_INTR_TEST
@@ -954,22 +941,19 @@
     4'b 0001, // index[81] FLASH_CTRL_MP_BANK_CFG
     4'b 0001, // index[82] FLASH_CTRL_OP_STATUS
     4'b 0001, // index[83] FLASH_CTRL_STATUS
-    4'b 0001, // index[84] FLASH_CTRL_ERR_CODE_INTR_EN
-    4'b 0001, // index[85] FLASH_CTRL_ERR_CODE
-    4'b 0011, // index[86] FLASH_CTRL_ERR_ADDR
-    4'b 0001, // index[87] FLASH_CTRL_ECC_SINGLE_ERR_CNT
+    4'b 0001, // index[84] FLASH_CTRL_ERR_CODE
+    4'b 0001, // index[85] FLASH_CTRL_FAULT_STATUS
+    4'b 1111, // index[86] FLASH_CTRL_ERR_ADDR
+    4'b 0011, // index[87] FLASH_CTRL_ECC_SINGLE_ERR_CNT
     4'b 0111, // index[88] FLASH_CTRL_ECC_SINGLE_ERR_ADDR_0
     4'b 0111, // index[89] FLASH_CTRL_ECC_SINGLE_ERR_ADDR_1
-    4'b 0001, // index[90] FLASH_CTRL_ECC_MULTI_ERR_CNT
-    4'b 0111, // index[91] FLASH_CTRL_ECC_MULTI_ERR_ADDR_0
-    4'b 0111, // index[92] FLASH_CTRL_ECC_MULTI_ERR_ADDR_1
-    4'b 0001, // index[93] FLASH_CTRL_PHY_ERR_CFG_REGWEN
-    4'b 0001, // index[94] FLASH_CTRL_PHY_ERR_CFG
-    4'b 0001, // index[95] FLASH_CTRL_PHY_ALERT_CFG
-    4'b 0001, // index[96] FLASH_CTRL_PHY_STATUS
-    4'b 1111, // index[97] FLASH_CTRL_SCRATCH
-    4'b 0011, // index[98] FLASH_CTRL_FIFO_LVL
-    4'b 0001  // index[99] FLASH_CTRL_FIFO_RST
+    4'b 0001, // index[90] FLASH_CTRL_PHY_ERR_CFG_REGWEN
+    4'b 0001, // index[91] FLASH_CTRL_PHY_ERR_CFG
+    4'b 0001, // index[92] FLASH_CTRL_PHY_ALERT_CFG
+    4'b 0001, // index[93] FLASH_CTRL_PHY_STATUS
+    4'b 1111, // index[94] FLASH_CTRL_SCRATCH
+    4'b 0011, // index[95] FLASH_CTRL_FIFO_LVL
+    4'b 0001  // index[96] FLASH_CTRL_FIFO_RST
   };
 
 endpackage
diff --git a/hw/ip/flash_ctrl/rtl/flash_mp.sv b/hw/ip/flash_ctrl/rtl/flash_mp.sv
index 3adfcf0..bafa659 100644
--- a/hw/ip/flash_ctrl/rtl/flash_mp.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_mp.sv
@@ -36,7 +36,6 @@
   output logic prog_done_o,
   output logic erase_done_o,
   output logic error_o,
-  output logic [AllPagesW-1:0] err_addr_o,
 
   // interface signals to/from flash_phy
   output logic req_o,
@@ -263,12 +262,10 @@
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
       txn_err <= 1'b0;
-      err_addr_o <= '0;
     end else if (txn_err) begin
       txn_err <= 1'b0;
     end else if (no_allowed_txn) begin
       txn_err <= 1'b1;
-      err_addr_o <= bank_page_addr;
     end
   end
 
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy.sv b/hw/ip/flash_ctrl/rtl/flash_phy.sv
index 134fc33..da8f947 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy.sv
@@ -159,11 +159,9 @@
   flash_phy_pkg::flash_phy_prim_flash_req_t [NumBanks-1:0] prim_flash_req;
   flash_phy_pkg::flash_phy_prim_flash_rsp_t [NumBanks-1:0] prim_flash_rsp;
   logic [NumBanks-1:0] ecc_single_err;
-  logic [NumBanks-1:0] ecc_multi_err;
   logic [NumBanks-1:0][BusAddrW-1:0] ecc_addr;
 
   assign flash_ctrl_o.ecc_single_err = ecc_single_err;
-  assign flash_ctrl_o.ecc_multi_err = ecc_multi_err;
   assign flash_ctrl_o.ecc_addr = ecc_addr;
 
   lc_ctrl_pkg::lc_tx_t [NumBanks-1:0] flash_disable;
@@ -250,7 +248,6 @@
       .prim_flash_req_o(prim_flash_req[bank]),
       .prim_flash_rsp_i(prim_flash_rsp[bank]),
       .ecc_single_err_o(ecc_single_err[bank]),
-      .ecc_multi_err_o(ecc_multi_err[bank]),
       .ecc_addr_o(ecc_addr[bank][BusBankAddrW-1:0])
     );
   end // block: gen_flash_banks
@@ -311,8 +308,6 @@
   );
   logic unused_alert;
   assign unused_alert = flash_ctrl_i.alert_trig & flash_ctrl_i.alert_ack;
-  assign flash_ctrl_o.flash_alert_p = flash_alert_o.p;
-  assign flash_ctrl_o.flash_alert_n = flash_alert_o.n;
 
   logic unused_trst_n;
   assign unused_trst_n = flash_ctrl_i.jtag_req.trst_n;
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_core.sv b/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
index ebc2c0b..372e878 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
@@ -52,7 +52,6 @@
   output logic [BusWidth-1:0]        rd_data_o,
   output logic                       rd_err_o,
   output logic                       ecc_single_err_o,
-  output logic                       ecc_multi_err_o,
   output logic [BusBankAddrW-1:0]    ecc_addr_o
 );
 
@@ -298,7 +297,6 @@
     .mask_i(scramble_mask),
     .descrambled_data_i(rd_descrambled_data),
     .ecc_single_err_o,
-    .ecc_multi_err_o,
     .ecc_addr_o
     );
 
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv b/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
index b5e6cae..fdec5d8 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_prog.sv
@@ -74,7 +74,7 @@
   logic align_next;
   data_sel_e data_sel;
 
-  localparam bit [WordSelW-1:0] MaxIdx = WordSelW'(WidthMultiple - 1);
+  localparam int MaxIdx = WidthMultiple - 1;
 
   logic [WidthMultiple-1:0][BusWidth-1:0] packed_data;
 
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_rd.sv b/hw/ip/flash_ctrl/rtl/flash_phy_rd.sv
index 18a0498..45b915a 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_rd.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_rd.sv
@@ -68,8 +68,9 @@
   input [FullDataWidth-1:0] data_i,
 
   // error status reporting
+  // only single bit error is shown here as multi-bit errors are
+  // actual data errors are reflected in-band through data_err_o
   output logic ecc_single_err_o,
-  output logic ecc_multi_err_o,
   output logic [BusBankAddrW-1:0] ecc_addr_o
   );
 
@@ -339,6 +340,7 @@
 
   // scrambled data must pass through ECC first
   logic valid_ecc;
+  logic ecc_multi_err_raw;
   logic ecc_multi_err;
   logic ecc_single_err;
   logic [DataWidth-1:0] data_ecc_chk;
@@ -355,26 +357,27 @@
     .data_i(data_i[ScrDataWidth-1:0]),
     .data_o(data_ecc_chk),
     .syndrome_o(),
-    .err_o({ecc_multi_err, ecc_single_err})
+    .err_o({ecc_multi_err_raw, ecc_single_err})
   );
 
-  // If data needs to be de-scrambled and has not been erased, pass through ecc decoder.
-  // Otherwise, pass the data through untouched.
-  // Likewise, ecc error is only observed if the data needs to be de-scrambled and has not been
-  // erased.
-  // rd_done signal below is duplicated (already in data_erased) to show clear intent of the code.
-  assign data_int = valid_ecc ? data_ecc_chk :
-                                data_i[DataWidth-1:0];
-
   // For instruction type accesses, always return the transaction error
   // For data type accesses, allow the error return to be configurable, as the actual data may
   // need to be debugged
-  assign data_err = (rd_attrs.req_type == tlul_pkg::InstrType) ?
-                    ecc_multi_err_o :
-                    ecc_multi_err_o & ecc_multi_err_en_i;
+  assign ecc_multi_err = (rd_attrs.req_type == tlul_pkg::InstrType) ?
+                         ecc_multi_err_raw :
+                         ecc_multi_err_raw & ecc_multi_err_en_i;
+
+  // If there is a detected multi-bit error or a single bit error, always return the
+  // ECC corrected result (even though it is possibly wrong).
+  // There is no data error of any kind (specifically when multi_err is disabled), just
+  // return the raw data so that it can be debugged.
+  assign data_int = data_err | ecc_single_err_o ?
+                    data_ecc_chk :
+                    data_i[DataWidth-1:0];
+
+  assign data_err = valid_ecc & ecc_multi_err;
 
   // always send out sideband indication on error
-  assign ecc_multi_err_o = valid_ecc & ecc_multi_err;
   assign ecc_single_err_o = valid_ecc & ecc_single_err;
 
   // ecc address return is always the full flash word
diff --git a/hw/ip/prim_generic/lint/prim_generic_flash.waiver b/hw/ip/prim_generic/lint/prim_generic_flash.waiver
index 16bdd05..c9602d5 100644
--- a/hw/ip/prim_generic/lint/prim_generic_flash.waiver
+++ b/hw/ip/prim_generic/lint/prim_generic_flash.waiver
@@ -3,3 +3,7 @@
 # SPDX-License-Identifier: Apache-2.0
 #
 # waiver file for prim_generic_flash
+
+# The prim generic module does not make use of the IO ports
+waive -rules INOUT_AS_IN -location {prim_generic_flash.sv} \
+      -regexp {Inout port 'flash_.*_io' has no driver}
diff --git a/sw/device/silicon_creator/lib/drivers/alert_functest.c b/sw/device/silicon_creator/lib/drivers/alert_functest.c
index de8c9a1..d232db8 100644
--- a/sw/device/silicon_creator/lib/drivers/alert_functest.c
+++ b/sw/device/silicon_creator/lib/drivers/alert_functest.c
@@ -62,13 +62,13 @@
       .phase_cycles = {1, 10, 100, 1000},
   };
 
-  LOG_INFO("Configure FlashCtrlFatalIntgErr as class A");
-  RETURN_IF_ERROR(alert_configure(kTopEarlgreyAlertIdFlashCtrlFatalIntgErr,
+  LOG_INFO("Configure FlashCtrlFatalErr as class A");
+  RETURN_IF_ERROR(alert_configure(kTopEarlgreyAlertIdFlashCtrlFatalErr,
                                   kAlertClassA, kAlertEnableEnabled));
   LOG_INFO("Configure class A alerts");
   RETURN_IF_ERROR(alert_class_configure(kAlertClassA, &config));
   LOG_INFO("Generate alert via test regs");
-  abs_mmio_write32(kFlashBase + FLASH_CTRL_ALERT_TEST_REG_OFFSET, 8);
+  abs_mmio_write32(kFlashBase + FLASH_CTRL_ALERT_TEST_REG_OFFSET, 2);
   return kErrorUnknown;
 }