[flash_ctrl] D2 preparation steps

- fully covnert to new sparse fsm
- add additional fsms as needed

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 1f9fc41..32068de 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.hjson
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.hjson
@@ -177,6 +177,10 @@
     { name: "BUS.INTEGRITY",
       desc: "End-to-end bus integrity scheme."
     }
+
+    { name: "FSM.SPARSE",
+      desc: "sparse fsm encoding in life cycle interface."
+    }
   ]
 
   scan: "true",       // Enable `scanmode_i` port
@@ -1568,6 +1572,12 @@
               '''
           },
           { bits: "9",
+            name: "arb_fsm_err",
+            desc: '''
+              The software / hardware interface has encountered a fatal error.
+              '''
+          },
+          { bits: "10",
             name: "storage_err",
             desc: '''
               A shadow register encountered a storage fault.
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl b/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
index aa2d601..e7a6b10 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.hjson.tpl
@@ -184,6 +184,10 @@
     { name: "BUS.INTEGRITY",
       desc: "End-to-end bus integrity scheme."
     }
+
+    { name: "FSM.SPARSE",
+      desc: "sparse fsm encoding in life cycle interface."
+    }
   ]
 
   scan: "true",       // Enable `scanmode_i` port
@@ -1069,6 +1073,12 @@
               '''
           },
           { bits: "9",
+            name: "arb_fsm_err",
+            desc: '''
+              The software / hardware interface has encountered a fatal error.
+              '''
+          },
+          { bits: "10",
             name: "storage_err",
             desc: '''
               A shadow register encountered a storage fault.
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
index 1495297..1a2dc46 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
@@ -216,6 +216,7 @@
   logic sw_sel;
   flash_lcmgr_phase_e hw_phase;
   logic lcmgr_err;
+  logic arb_fsm_err;
 
   // Flash control arbitration connections to software interface
   logic sw_ctrl_done;
@@ -360,7 +361,8 @@
     .phase_o(phase),
 
     // indication that sw has been selected
-    .sel_o(if_sel)
+    .sel_o(if_sel),
+    .fsm_err_o(arb_fsm_err)
   );
 
   assign op_start      = muxed_ctrl.start.q;
@@ -915,6 +917,7 @@
   assign hw2reg.fault_status.reg_intg_err.d   = 1'b1;
   assign hw2reg.fault_status.phy_intg_err.d   = 1'b1;
   assign hw2reg.fault_status.lcmgr_err.d      = 1'b1;
+  assign hw2reg.fault_status.arb_fsm_err.d    = 1'b1;
   assign hw2reg.fault_status.storage_err.d    = 1'b1;
   assign hw2reg.fault_status.mp_err.de        = hw_err.mp_err;
   assign hw2reg.fault_status.rd_err.de        = hw_err.rd_err;
@@ -924,6 +927,7 @@
   assign hw2reg.fault_status.reg_intg_err.de  = intg_err;
   assign hw2reg.fault_status.phy_intg_err.de  = flash_phy_rsp.intg_err;
   assign hw2reg.fault_status.lcmgr_err.de     = lcmgr_err;
+  assign hw2reg.fault_status.arb_fsm_err.de   = arb_fsm_err;
   assign hw2reg.fault_status.storage_err.de   = storage_err;
 
   // Correctable ECC count / address
@@ -1176,4 +1180,11 @@
                                          alert_tx_o[0])
   `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(WordCntAlertCheck_A, u_flash_hw_if.u_word_cnt,
                                          alert_tx_o[0])
+
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(LcCtrlFsmCheck_A,
+    u_flash_hw_if.u_state_regs, alert_tx_o[0])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(LcCtrlRmaFsmCheck_A,
+    u_flash_hw_if.u_rma_state_regs, alert_tx_o[0])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(ArbFsmCheck_A,
+    u_ctrl_arb.u_state_regs, alert_tx_o[0])
 endmodule
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 63a7926..70e8d4d 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl_pkg.sv.tpl
@@ -586,13 +586,14 @@
   //
   localparam int RmaStateWidth = 10;
   typedef enum logic [RmaStateWidth-1:0] {
-    StRmaIdle        = 10'b1000000111,
-    StRmaPageSel     = 10'b0110100101,
-    StRmaErase       = 10'b0100011100,
-    StRmaWordSel     = 10'b1011110010,
-    StRmaProgram     = 10'b0000111011,
-    StRmaProgramWait = 10'b0011001000,
-    StRmaRdVerify    = 10'b1101101001
+    StRmaIdle        = 10'b1101000011,
+    StRmaPageSel     = 10'b0010111001,
+    StRmaErase       = 10'b1111010100,
+    StRmaWordSel     = 10'b0001011111,
+    StRmaProgram     = 10'b0110001110,
+    StRmaProgramWait = 10'b1000110110,
+    StRmaRdVerify    = 10'b1011101010,
+    StRmaInvalid     = 10'b1100101101
   } rma_state_e;
 
 endpackage : flash_ctrl_pkg
diff --git a/hw/ip/flash_ctrl/flash_ctrl.core b/hw/ip/flash_ctrl/flash_ctrl.core
index 1a52ede..bcd5f35 100644
--- a/hw/ip/flash_ctrl/flash_ctrl.core
+++ b/hw/ip/flash_ctrl/flash_ctrl.core
@@ -12,11 +12,12 @@
       - lowrisc:prim:all
       - lowrisc:prim:count
       - lowrisc:prim:edge_detector
-      - lowrisc:prim:secded
-      - lowrisc:prim:lfsr
       - lowrisc:prim:flash
       - lowrisc:prim:gf_mult
       - lowrisc:prim:lc_sync
+      - lowrisc:prim:lfsr
+      - lowrisc:prim:secded
+      - lowrisc:prim:sparse_fsm
       - lowrisc:ip:otp_ctrl_pkg
       - lowrisc:ip:flash_ctrl_pkg
       - lowrisc:ip:jtag_pkg
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
index 226e044..7868578 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
@@ -217,6 +217,7 @@
   logic sw_sel;
   flash_lcmgr_phase_e hw_phase;
   logic lcmgr_err;
+  logic arb_fsm_err;
 
   // Flash control arbitration connections to software interface
   logic sw_ctrl_done;
@@ -361,7 +362,8 @@
     .phase_o(phase),
 
     // indication that sw has been selected
-    .sel_o(if_sel)
+    .sel_o(if_sel),
+    .fsm_err_o(arb_fsm_err)
   );
 
   assign op_start      = muxed_ctrl.start.q;
@@ -916,6 +918,7 @@
   assign hw2reg.fault_status.reg_intg_err.d   = 1'b1;
   assign hw2reg.fault_status.phy_intg_err.d   = 1'b1;
   assign hw2reg.fault_status.lcmgr_err.d      = 1'b1;
+  assign hw2reg.fault_status.arb_fsm_err.d    = 1'b1;
   assign hw2reg.fault_status.storage_err.d    = 1'b1;
   assign hw2reg.fault_status.mp_err.de        = hw_err.mp_err;
   assign hw2reg.fault_status.rd_err.de        = hw_err.rd_err;
@@ -925,6 +928,7 @@
   assign hw2reg.fault_status.reg_intg_err.de  = intg_err;
   assign hw2reg.fault_status.phy_intg_err.de  = flash_phy_rsp.intg_err;
   assign hw2reg.fault_status.lcmgr_err.de     = lcmgr_err;
+  assign hw2reg.fault_status.arb_fsm_err.de   = arb_fsm_err;
   assign hw2reg.fault_status.storage_err.de   = storage_err;
 
   // Correctable ECC count / address
@@ -1177,4 +1181,11 @@
                                          alert_tx_o[0])
   `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(WordCntAlertCheck_A, u_flash_hw_if.u_word_cnt,
                                          alert_tx_o[0])
+
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(LcCtrlFsmCheck_A,
+    u_flash_hw_if.u_state_regs, alert_tx_o[0])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(LcCtrlRmaFsmCheck_A,
+    u_flash_hw_if.u_rma_state_regs, alert_tx_o[0])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(ArbFsmCheck_A,
+    u_ctrl_arb.u_state_regs, alert_tx_o[0])
 endmodule
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_arb.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_arb.sv
index a5a1fd6..9e14caf 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_arb.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_arb.sv
@@ -83,37 +83,73 @@
   output flash_lcmgr_phase_e phase_o,
 
   // indication that sw has been selected
-  output flash_sel_e sel_o
+  output flash_sel_e sel_o,
+
+  // fsm sparse error
+  output logic fsm_err_o
 
 );
 
   // arbitration FSM
-  typedef enum logic [1:0] {
-    StReset,  // at reset wait for flash phy to be ready
-    StHw,
-    StSwActive,
-    StSwIdle
-  } state_e;
+  // Encoding generated with:
+  // $ ./util/design/sparse-fsm-encode.py -d 5 -m 5 -n 10 \
+  //      -s 1044018132 --language=sv --avoid-zero
+  //
+  // Hamming distance histogram:
+  //
+  //  0: --
+  //  1: --
+  //  2: --
+  //  3: --
+  //  4: --
+  //  5: |||||||||||||||||||| (50.00%)
+  //  6: |||||||||||||||| (40.00%)
+  //  7: |||| (10.00%)
+  //  8: --
+  //  9: --
+  // 10: --
+  //
+  // Minimum Hamming distance: 5
+  // Maximum Hamming distance: 7
+  // Minimum Hamming weight: 5
+  // Maximum Hamming weight: 7
+  //
+  localparam int StateWidth = 10;
+  typedef enum logic [StateWidth-1:0] {
+    StReset    = 10'b1010101011,
+    StHw       = 10'b1111010001,
+    StSwActive = 10'b1011001100,
+    StSwIdle   = 10'b0101100111,
+    StInvalid  = 10'b0111111010
+  } arb_state_e;
 
   flash_sel_e func_sel;
-  state_e state_q, state_d;
+  arb_state_e state_q, state_d;
 
   logic sw_req;
   assign sw_req = sw_ctrl_i.start.q;
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      state_q <= StReset;
-    end else begin
-      state_q <= state_d;
-    end
-  end
+  // This primitive is used to place a size-only constraint on the
+  // flops in order to prevent FSM state encoding optimizations.
+  logic [StateWidth-1:0] state_raw_q;
+  assign state_q = arb_state_e'(state_raw_q);
+  prim_sparse_fsm_flop #(
+    .StateEnumT(arb_state_e),
+    .Width(StateWidth),
+    .ResetValue(StateWidth'(StReset))
+  ) u_state_regs (
+    .clk_i,
+    .rst_ni,
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
+  );
 
   always_comb begin
 
     func_sel = NoneSel;
     fifo_clr_o = 1'b0;
     state_d = state_q;
+    fsm_err_o = 1'b0;
 
     unique case (state_q)
       StReset: begin
@@ -158,7 +194,15 @@
         end
       end
 
-      default:;
+      StInvalid: begin
+        fsm_err_o = 1'b1;
+      end
+
+      default: begin
+        state_d = StInvalid;
+      end
+
+
     endcase // unique case (state_q)
   end // always_comb
 
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 e7e2f79..510c7cc 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
@@ -973,6 +973,7 @@
   logic fault_status_reg_intg_err_qs;
   logic fault_status_phy_intg_err_qs;
   logic fault_status_lcmgr_err_qs;
+  logic fault_status_arb_fsm_err_qs;
   logic fault_status_storage_err_qs;
   logic [19:0] err_addr_qs;
   logic ecc_single_err_cnt_we;
@@ -11508,7 +11509,32 @@
     .qs     (fault_status_lcmgr_err_qs)
   );
 
-  //   F[storage_err]: 9:9
+  //   F[arb_fsm_err]: 9:9
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_arb_fsm_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.arb_fsm_err.de),
+    .d      (hw2reg.fault_status.arb_fsm_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.arb_fsm_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_arb_fsm_err_qs)
+  );
+
+  //   F[storage_err]: 10:10
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -13603,7 +13629,8 @@
         reg_rdata_next[6] = fault_status_reg_intg_err_qs;
         reg_rdata_next[7] = fault_status_phy_intg_err_qs;
         reg_rdata_next[8] = fault_status_lcmgr_err_qs;
-        reg_rdata_next[9] = fault_status_storage_err_qs;
+        reg_rdata_next[9] = fault_status_arb_fsm_err_qs;
+        reg_rdata_next[10] = fault_status_storage_err_qs;
       end
 
       addr_hit[87]: begin
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
index 2ee60d4..3a3ccd4 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
@@ -90,21 +90,60 @@
   // the various seed outputs
   logic [NumSeeds-1:0][SeedReads-1:0][BusWidth-1:0] seeds_q;
 
+  // Hamming distance histogram:
+  //
+  //  0: --
+  //  1: --
+  //  2: --
+  //  3: --
+  //  4: --
+  //  5: |||||||||||||||||||| (55.56%)
+  //  6: |||||||||||||||| (44.44%)
+  //  7: --
+  //  8: --
+  //  9: --
+  // 10: --
+  //
+  // Minimum Hamming distance: 5
+  // Maximum Hamming distance: 6
+  // Minimum Hamming weight: 5
+  // Maximum Hamming weight: 6
+  //
+  localparam int StateWidth = 10;
+
   // progress through and read out the various pieces of content
   // This FSM should become sparse, especially for StRmaRsp
-  typedef enum logic [3:0] {
-    StIdle,
-    StReqAddrKey,
-    StReqDataKey,
-    StReadSeeds,
-    StWait,
-    StEntropyReseed,
-    StRmaWipe,
-    StRmaRsp,
-    StInvalid
-  } state_e;
+  typedef enum logic [StateWidth-1:0] {
+    StIdle          = 10'b1001100110,
+    StReqAddrKey    = 10'b1010101101,
+    StReqDataKey    = 10'b0100110101,
+    StReadSeeds     = 10'b1110010110,
+    StWait          = 10'b1111000001,
+    StEntropyReseed = 10'b0011110011,
+    StRmaWipe       = 10'b0011011100,
+    StRmaRsp        = 10'b0101001111,
+    StInvalid       = 10'b0110101010
+  } lcmgr_state_e;
 
-  state_e state_q, state_d;
+  lcmgr_state_e state_q, state_d;
+  logic state_err;
+
+  // This primitive is used to place a size-only constraint on the
+  // flops in order to prevent FSM state encoding optimizations.
+  logic [StateWidth-1:0] state_raw_q;
+  assign state_q = lcmgr_state_e'(state_raw_q);
+  //SEC_CM: FSM.SPARSE
+  prim_sparse_fsm_flop #(
+    .StateEnumT(lcmgr_state_e),
+    .Width(StateWidth),
+    .ResetValue(StateWidth'(StIdle))
+  ) u_state_regs (
+    .clk_i,
+    .rst_ni,
+    .state_i ( state_d ),
+    .state_o ( state_raw_q )
+  );
+
   lc_ctrl_pkg::lc_tx_t err_sts;
   logic err_sts_set;
   lc_ctrl_pkg::lc_tx_t rma_ack_d, rma_ack_q;
@@ -125,11 +164,9 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      state_q <= StIdle;
       rma_ack_q <= lc_ctrl_pkg::Off;
       validate_q <= 1'b0;
     end else begin
-      state_q <= state_d;
       rma_ack_q <= rma_ack_d;
       validate_q <= validate_d;
     end
@@ -315,6 +352,8 @@
     rma_wipe_req = 1'b0;
     rma_wipe_idx_incr = 1'b0;
 
+    state_err = 1'b0;
+
     unique case (state_q)
 
       // If rma request is seen, directly transition to wipe.
@@ -433,10 +472,14 @@
         end
       end
 
-      // Invalid catch-all state
-      default: begin
+      StInvalid: begin
+        state_err = 1'b1;
         phase = PhaseInvalid;
         rma_ack_d = lc_ctrl_pkg::Off;
+      end
+
+      // Invalid catch-all state
+      default: begin
         state_d = StInvalid;
       end
 
@@ -474,14 +517,15 @@
   // flops in order to prevent FSM state encoding optimizations.
   logic [RmaStateWidth-1:0] rma_state_raw_q;
   assign rma_state_q = rma_state_e'(rma_state_raw_q);
-  prim_flop #(
+  prim_sparse_fsm_flop #(
+    .StateEnumT(rma_state_e),
     .Width(RmaStateWidth),
     .ResetValue(RmaStateWidth'(StRmaIdle))
-  ) u_state_regs (
+  ) u_rma_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( rma_state_d     ),
-    .q_o ( rma_state_raw_q )
+    .state_i ( rma_state_d ),
+    .state_o ( rma_state_raw_q )
   );
 
   logic page_err_q, page_err_d;
@@ -691,11 +735,15 @@
         end
       end
 
-      default: begin
+      StRmaInvalid: begin
         err_sts_set = 1'b1;
         fsm_err = 1'b1;
       end
 
+      default: begin
+        rma_state_d = StRmaInvalid;
+      end
+
     endcase // unique case (rma_state_q)
   end // always_comb
 
@@ -720,7 +768,7 @@
   assign rma_ack_o = rma_ack_q;
 
   // all of these are considered fatal errors
-  assign fatal_err_o = page_err_q | word_err_q | fsm_err;
+  assign fatal_err_o = page_err_q | word_err_q | fsm_err | state_err;
 
   logic unused_seed_valid;
   assign unused_seed_valid = otp_key_rsp_i.seed_valid;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
index 9a2684f..62a4b65 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
@@ -585,13 +585,14 @@
   //
   localparam int RmaStateWidth = 10;
   typedef enum logic [RmaStateWidth-1:0] {
-    StRmaIdle        = 10'b1000000111,
-    StRmaPageSel     = 10'b0110100101,
-    StRmaErase       = 10'b0100011100,
-    StRmaWordSel     = 10'b1011110010,
-    StRmaProgram     = 10'b0000111011,
-    StRmaProgramWait = 10'b0011001000,
-    StRmaRdVerify    = 10'b1101101001
+    StRmaIdle        = 10'b1101000011,
+    StRmaPageSel     = 10'b0010111001,
+    StRmaErase       = 10'b1111010100,
+    StRmaWordSel     = 10'b0001011111,
+    StRmaProgram     = 10'b0110001110,
+    StRmaProgramWait = 10'b1000110110,
+    StRmaRdVerify    = 10'b1011101010,
+    StRmaInvalid     = 10'b1100101101
   } rma_state_e;
 
 endpackage : flash_ctrl_pkg
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 20747d3..bcc27c3 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_pkg.sv
@@ -507,6 +507,9 @@
     } lcmgr_err;
     struct packed {
       logic        q;
+    } arb_fsm_err;
+    struct packed {
+      logic        q;
     } storage_err;
   } flash_ctrl_reg2hw_fault_status_reg_t;
 
@@ -684,6 +687,10 @@
     struct packed {
       logic        d;
       logic        de;
+    } arb_fsm_err;
+    struct packed {
+      logic        d;
+      logic        de;
     } storage_err;
   } flash_ctrl_hw2reg_fault_status_reg_t;
 
@@ -719,33 +726,33 @@
 
   // Register -> HW type for core interface
   typedef struct packed {
-    flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [576:571]
-    flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [570:565]
-    flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [564:553]
-    flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [552:549]
-    flash_ctrl_reg2hw_dis_reg_t dis; // [548:545]
-    flash_ctrl_reg2hw_exec_reg_t exec; // [544:513]
-    flash_ctrl_reg2hw_init_reg_t init; // [512:512]
-    flash_ctrl_reg2hw_control_reg_t control; // [511:492]
-    flash_ctrl_reg2hw_addr_reg_t addr; // [491:472]
-    flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [471:470]
-    flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [469:469]
-    flash_ctrl_reg2hw_mp_region_cfg_shadowed_mreg_t [7:0] mp_region_cfg_shadowed; // [468:261]
-    flash_ctrl_reg2hw_default_region_shadowed_reg_t default_region_shadowed; // [260:255]
+    flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [577:572]
+    flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [571:566]
+    flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [565:554]
+    flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [553:550]
+    flash_ctrl_reg2hw_dis_reg_t dis; // [549:546]
+    flash_ctrl_reg2hw_exec_reg_t exec; // [545:514]
+    flash_ctrl_reg2hw_init_reg_t init; // [513:513]
+    flash_ctrl_reg2hw_control_reg_t control; // [512:493]
+    flash_ctrl_reg2hw_addr_reg_t addr; // [492:473]
+    flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [472:471]
+    flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [470:470]
+    flash_ctrl_reg2hw_mp_region_cfg_shadowed_mreg_t [7:0] mp_region_cfg_shadowed; // [469:262]
+    flash_ctrl_reg2hw_default_region_shadowed_reg_t default_region_shadowed; // [261:256]
     flash_ctrl_reg2hw_bank0_info0_page_cfg_shadowed_mreg_t [9:0]
-        bank0_info0_page_cfg_shadowed; // [254:185]
+        bank0_info0_page_cfg_shadowed; // [255:186]
     flash_ctrl_reg2hw_bank0_info1_page_cfg_shadowed_mreg_t [0:0]
-        bank0_info1_page_cfg_shadowed; // [184:178]
+        bank0_info1_page_cfg_shadowed; // [185:179]
     flash_ctrl_reg2hw_bank0_info2_page_cfg_shadowed_mreg_t [1:0]
-        bank0_info2_page_cfg_shadowed; // [177:164]
+        bank0_info2_page_cfg_shadowed; // [178:165]
     flash_ctrl_reg2hw_bank1_info0_page_cfg_shadowed_mreg_t [9:0]
-        bank1_info0_page_cfg_shadowed; // [163:94]
+        bank1_info0_page_cfg_shadowed; // [164:95]
     flash_ctrl_reg2hw_bank1_info1_page_cfg_shadowed_mreg_t [0:0]
-        bank1_info1_page_cfg_shadowed; // [93:87]
+        bank1_info1_page_cfg_shadowed; // [94:88]
     flash_ctrl_reg2hw_bank1_info2_page_cfg_shadowed_mreg_t [1:0]
-        bank1_info2_page_cfg_shadowed; // [86:73]
-    flash_ctrl_reg2hw_mp_bank_cfg_shadowed_mreg_t [1:0] mp_bank_cfg_shadowed; // [72:71]
-    flash_ctrl_reg2hw_fault_status_reg_t fault_status; // [70:62]
+        bank1_info2_page_cfg_shadowed; // [87:74]
+    flash_ctrl_reg2hw_mp_bank_cfg_shadowed_mreg_t [1:0] mp_bank_cfg_shadowed; // [73:72]
+    flash_ctrl_reg2hw_fault_status_reg_t fault_status; // [71: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]
@@ -756,14 +763,14 @@
 
   // HW -> register type for core interface
   typedef struct packed {
-    flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [147:136]
-    flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [135:135]
-    flash_ctrl_hw2reg_control_reg_t control; // [134:133]
-    flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [132:131]
-    flash_ctrl_hw2reg_op_status_reg_t op_status; // [130:127]
-    flash_ctrl_hw2reg_status_reg_t status; // [126:117]
-    flash_ctrl_hw2reg_err_code_reg_t err_code; // [116:105]
-    flash_ctrl_hw2reg_fault_status_reg_t fault_status; // [104:87]
+    flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [149:138]
+    flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [137:137]
+    flash_ctrl_hw2reg_control_reg_t control; // [136:135]
+    flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [134:133]
+    flash_ctrl_hw2reg_op_status_reg_t op_status; // [132:129]
+    flash_ctrl_hw2reg_status_reg_t status; // [128:119]
+    flash_ctrl_hw2reg_err_code_reg_t err_code; // [118:107]
+    flash_ctrl_hw2reg_fault_status_reg_t fault_status; // [106:87]
     flash_ctrl_hw2reg_err_addr_reg_t err_addr; // [86: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]
diff --git a/hw/top_earlgrey/ip/flash_ctrl/data/autogen/flash_ctrl.hjson b/hw/top_earlgrey/ip/flash_ctrl/data/autogen/flash_ctrl.hjson
index ab4ac75..cb0939f 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/data/autogen/flash_ctrl.hjson
+++ b/hw/top_earlgrey/ip/flash_ctrl/data/autogen/flash_ctrl.hjson
@@ -183,6 +183,10 @@
     { name: "BUS.INTEGRITY",
       desc: "End-to-end bus integrity scheme."
     }
+
+    { name: "FSM.SPARSE",
+      desc: "sparse fsm encoding in life cycle interface."
+    }
   ]
 
   scan: "true",       // Enable `scanmode_i` port
@@ -1574,6 +1578,12 @@
               '''
           },
           { bits: "9",
+            name: "arb_fsm_err",
+            desc: '''
+              The software / hardware interface has encountered a fatal error.
+              '''
+          },
+          { bits: "10",
             name: "storage_err",
             desc: '''
               A shadow register encountered a storage fault.
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl.sv
index 663aa25..d6d0659 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl.sv
@@ -223,6 +223,7 @@
   logic sw_sel;
   flash_lcmgr_phase_e hw_phase;
   logic lcmgr_err;
+  logic arb_fsm_err;
 
   // Flash control arbitration connections to software interface
   logic sw_ctrl_done;
@@ -367,7 +368,8 @@
     .phase_o(phase),
 
     // indication that sw has been selected
-    .sel_o(if_sel)
+    .sel_o(if_sel),
+    .fsm_err_o(arb_fsm_err)
   );
 
   assign op_start      = muxed_ctrl.start.q;
@@ -922,6 +924,7 @@
   assign hw2reg.fault_status.reg_intg_err.d   = 1'b1;
   assign hw2reg.fault_status.phy_intg_err.d   = 1'b1;
   assign hw2reg.fault_status.lcmgr_err.d      = 1'b1;
+  assign hw2reg.fault_status.arb_fsm_err.d    = 1'b1;
   assign hw2reg.fault_status.storage_err.d    = 1'b1;
   assign hw2reg.fault_status.mp_err.de        = hw_err.mp_err;
   assign hw2reg.fault_status.rd_err.de        = hw_err.rd_err;
@@ -931,6 +934,7 @@
   assign hw2reg.fault_status.reg_intg_err.de  = intg_err;
   assign hw2reg.fault_status.phy_intg_err.de  = flash_phy_rsp.intg_err;
   assign hw2reg.fault_status.lcmgr_err.de     = lcmgr_err;
+  assign hw2reg.fault_status.arb_fsm_err.de   = arb_fsm_err;
   assign hw2reg.fault_status.storage_err.de   = storage_err;
 
   // Correctable ECC count / address
@@ -1183,4 +1187,11 @@
                                          alert_tx_o[0])
   `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(WordCntAlertCheck_A, u_flash_hw_if.u_word_cnt,
                                          alert_tx_o[0])
+
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(LcCtrlFsmCheck_A,
+    u_flash_hw_if.u_state_regs, alert_tx_o[0])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(LcCtrlRmaFsmCheck_A,
+    u_flash_hw_if.u_rma_state_regs, alert_tx_o[0])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(ArbFsmCheck_A,
+    u_ctrl_arb.u_state_regs, alert_tx_o[0])
 endmodule
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
index e7e2f79..510c7cc 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
@@ -973,6 +973,7 @@
   logic fault_status_reg_intg_err_qs;
   logic fault_status_phy_intg_err_qs;
   logic fault_status_lcmgr_err_qs;
+  logic fault_status_arb_fsm_err_qs;
   logic fault_status_storage_err_qs;
   logic [19:0] err_addr_qs;
   logic ecc_single_err_cnt_we;
@@ -11508,7 +11509,32 @@
     .qs     (fault_status_lcmgr_err_qs)
   );
 
-  //   F[storage_err]: 9:9
+  //   F[arb_fsm_err]: 9:9
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_arb_fsm_err (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.arb_fsm_err.de),
+    .d      (hw2reg.fault_status.arb_fsm_err.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.arb_fsm_err.q),
+
+    // to register interface (read)
+    .qs     (fault_status_arb_fsm_err_qs)
+  );
+
+  //   F[storage_err]: 10:10
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -13603,7 +13629,8 @@
         reg_rdata_next[6] = fault_status_reg_intg_err_qs;
         reg_rdata_next[7] = fault_status_phy_intg_err_qs;
         reg_rdata_next[8] = fault_status_lcmgr_err_qs;
-        reg_rdata_next[9] = fault_status_storage_err_qs;
+        reg_rdata_next[9] = fault_status_arb_fsm_err_qs;
+        reg_rdata_next[10] = fault_status_storage_err_qs;
       end
 
       addr_hit[87]: begin
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_pkg.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_pkg.sv
index 035bf72..5adbe31 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_pkg.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_pkg.sv
@@ -591,13 +591,14 @@
   //
   localparam int RmaStateWidth = 10;
   typedef enum logic [RmaStateWidth-1:0] {
-    StRmaIdle        = 10'b1000000111,
-    StRmaPageSel     = 10'b0110100101,
-    StRmaErase       = 10'b0100011100,
-    StRmaWordSel     = 10'b1011110010,
-    StRmaProgram     = 10'b0000111011,
-    StRmaProgramWait = 10'b0011001000,
-    StRmaRdVerify    = 10'b1101101001
+    StRmaIdle        = 10'b1101000011,
+    StRmaPageSel     = 10'b0010111001,
+    StRmaErase       = 10'b1111010100,
+    StRmaWordSel     = 10'b0001011111,
+    StRmaProgram     = 10'b0110001110,
+    StRmaProgramWait = 10'b1000110110,
+    StRmaRdVerify    = 10'b1011101010,
+    StRmaInvalid     = 10'b1100101101
   } rma_state_e;
 
 endpackage : flash_ctrl_pkg
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_reg_pkg.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_reg_pkg.sv
index df55426..03f3024 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_reg_pkg.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_reg_pkg.sv
@@ -507,6 +507,9 @@
     } lcmgr_err;
     struct packed {
       logic        q;
+    } arb_fsm_err;
+    struct packed {
+      logic        q;
     } storage_err;
   } flash_ctrl_reg2hw_fault_status_reg_t;
 
@@ -684,6 +687,10 @@
     struct packed {
       logic        d;
       logic        de;
+    } arb_fsm_err;
+    struct packed {
+      logic        d;
+      logic        de;
     } storage_err;
   } flash_ctrl_hw2reg_fault_status_reg_t;
 
@@ -719,33 +726,33 @@
 
   // Register -> HW type for core interface
   typedef struct packed {
-    flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [576:571]
-    flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [570:565]
-    flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [564:553]
-    flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [552:549]
-    flash_ctrl_reg2hw_dis_reg_t dis; // [548:545]
-    flash_ctrl_reg2hw_exec_reg_t exec; // [544:513]
-    flash_ctrl_reg2hw_init_reg_t init; // [512:512]
-    flash_ctrl_reg2hw_control_reg_t control; // [511:492]
-    flash_ctrl_reg2hw_addr_reg_t addr; // [491:472]
-    flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [471:470]
-    flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [469:469]
-    flash_ctrl_reg2hw_mp_region_cfg_shadowed_mreg_t [7:0] mp_region_cfg_shadowed; // [468:261]
-    flash_ctrl_reg2hw_default_region_shadowed_reg_t default_region_shadowed; // [260:255]
+    flash_ctrl_reg2hw_intr_state_reg_t intr_state; // [577:572]
+    flash_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [571:566]
+    flash_ctrl_reg2hw_intr_test_reg_t intr_test; // [565:554]
+    flash_ctrl_reg2hw_alert_test_reg_t alert_test; // [553:550]
+    flash_ctrl_reg2hw_dis_reg_t dis; // [549:546]
+    flash_ctrl_reg2hw_exec_reg_t exec; // [545:514]
+    flash_ctrl_reg2hw_init_reg_t init; // [513:513]
+    flash_ctrl_reg2hw_control_reg_t control; // [512:493]
+    flash_ctrl_reg2hw_addr_reg_t addr; // [492:473]
+    flash_ctrl_reg2hw_prog_type_en_reg_t prog_type_en; // [472:471]
+    flash_ctrl_reg2hw_erase_suspend_reg_t erase_suspend; // [470:470]
+    flash_ctrl_reg2hw_mp_region_cfg_shadowed_mreg_t [7:0] mp_region_cfg_shadowed; // [469:262]
+    flash_ctrl_reg2hw_default_region_shadowed_reg_t default_region_shadowed; // [261:256]
     flash_ctrl_reg2hw_bank0_info0_page_cfg_shadowed_mreg_t [9:0]
-        bank0_info0_page_cfg_shadowed; // [254:185]
+        bank0_info0_page_cfg_shadowed; // [255:186]
     flash_ctrl_reg2hw_bank0_info1_page_cfg_shadowed_mreg_t [0:0]
-        bank0_info1_page_cfg_shadowed; // [184:178]
+        bank0_info1_page_cfg_shadowed; // [185:179]
     flash_ctrl_reg2hw_bank0_info2_page_cfg_shadowed_mreg_t [1:0]
-        bank0_info2_page_cfg_shadowed; // [177:164]
+        bank0_info2_page_cfg_shadowed; // [178:165]
     flash_ctrl_reg2hw_bank1_info0_page_cfg_shadowed_mreg_t [9:0]
-        bank1_info0_page_cfg_shadowed; // [163:94]
+        bank1_info0_page_cfg_shadowed; // [164:95]
     flash_ctrl_reg2hw_bank1_info1_page_cfg_shadowed_mreg_t [0:0]
-        bank1_info1_page_cfg_shadowed; // [93:87]
+        bank1_info1_page_cfg_shadowed; // [94:88]
     flash_ctrl_reg2hw_bank1_info2_page_cfg_shadowed_mreg_t [1:0]
-        bank1_info2_page_cfg_shadowed; // [86:73]
-    flash_ctrl_reg2hw_mp_bank_cfg_shadowed_mreg_t [1:0] mp_bank_cfg_shadowed; // [72:71]
-    flash_ctrl_reg2hw_fault_status_reg_t fault_status; // [70:62]
+        bank1_info2_page_cfg_shadowed; // [87:74]
+    flash_ctrl_reg2hw_mp_bank_cfg_shadowed_mreg_t [1:0] mp_bank_cfg_shadowed; // [73:72]
+    flash_ctrl_reg2hw_fault_status_reg_t fault_status; // [71: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]
@@ -756,14 +763,14 @@
 
   // HW -> register type for core interface
   typedef struct packed {
-    flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [147:136]
-    flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [135:135]
-    flash_ctrl_hw2reg_control_reg_t control; // [134:133]
-    flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [132:131]
-    flash_ctrl_hw2reg_op_status_reg_t op_status; // [130:127]
-    flash_ctrl_hw2reg_status_reg_t status; // [126:117]
-    flash_ctrl_hw2reg_err_code_reg_t err_code; // [116:105]
-    flash_ctrl_hw2reg_fault_status_reg_t fault_status; // [104:87]
+    flash_ctrl_hw2reg_intr_state_reg_t intr_state; // [149:138]
+    flash_ctrl_hw2reg_ctrl_regwen_reg_t ctrl_regwen; // [137:137]
+    flash_ctrl_hw2reg_control_reg_t control; // [136:135]
+    flash_ctrl_hw2reg_erase_suspend_reg_t erase_suspend; // [134:133]
+    flash_ctrl_hw2reg_op_status_reg_t op_status; // [132:129]
+    flash_ctrl_hw2reg_status_reg_t status; // [128:119]
+    flash_ctrl_hw2reg_err_code_reg_t err_code; // [118:107]
+    flash_ctrl_hw2reg_fault_status_reg_t fault_status; // [106:87]
     flash_ctrl_hw2reg_err_addr_reg_t err_addr; // [86: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]