[lc_ctrl] Switch to sparse fsm primitive

Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/lc_ctrl/dv/env/lc_ctrl_if.sv b/hw/ip/lc_ctrl/dv/env/lc_ctrl_if.sv
index cb0e1de..d237af5 100644
--- a/hw/ip/lc_ctrl/dv/env/lc_ctrl_if.sv
+++ b/hw/ip/lc_ctrl/dv/env/lc_ctrl_if.sv
@@ -6,7 +6,7 @@
 
 `ifndef LC_CTRL_FSM_STATE_REGS_PATH
 `define LC_CTRL_FSM_STATE_REGS_PATH \
-    tb.dut.u_lc_ctrl_fsm.u_fsm_state_regs.gen_generic.u_impl_generic.d_i
+    tb.dut.u_lc_ctrl_fsm.u_fsm_state_regs.u_state_flop.gen_generic.u_impl_generic.d_i
 `endif
 
 `ifndef LC_CTRL_FSM_COUNT_REGS_PATH
diff --git a/hw/ip/lc_ctrl/lc_ctrl.core b/hw/ip/lc_ctrl/lc_ctrl.core
index e15ef19..27833e9 100644
--- a/hw/ip/lc_ctrl/lc_ctrl.core
+++ b/hw/ip/lc_ctrl/lc_ctrl.core
@@ -14,6 +14,7 @@
       - lowrisc:prim:lc_sync
       - lowrisc:prim:lc_sender
       - lowrisc:prim:mubi
+      - lowrisc:prim:sparse_fsm
       - lowrisc:ip:lc_ctrl_pkg
       - lowrisc:ip:tlul
       - lowrisc:ip:pwrmgr_pkg
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl.sv
index 0502576..0b60236 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl.sv
@@ -581,7 +581,7 @@
   // KMAC Interface //
   ////////////////////
 
-  logic token_hash_req, token_hash_req_chk, token_hash_ack, token_hash_err;
+  logic token_hash_req, token_hash_req_chk, token_hash_ack, token_hash_err, token_if_fsm_err;
   lc_token_t hashed_token;
   lc_ctrl_kmac_if u_lc_ctrl_kmac_if (
     .clk_i,
@@ -595,6 +595,7 @@
     .token_hash_req_chk_i ( token_hash_req_chk ),
     .token_hash_ack_o     ( token_hash_ack     ),
     .token_hash_err_o     ( token_hash_err     ),
+    .token_if_fsm_err_o   ( token_if_fsm_err   ),
     .hashed_token_o       ( hashed_token       )
   );
 
@@ -633,6 +634,7 @@
     .token_hash_req_chk_o   ( token_hash_req_chk               ),
     .token_hash_ack_i       ( token_hash_ack                   ),
     .token_hash_err_i       ( token_hash_err                   ),
+    .token_if_fsm_err_i     ( token_if_fsm_err                 ),
     .hashed_token_i         ( hashed_token                     ),
     .otp_prog_req_o         ( lc_otp_program_o.req             ),
     .otp_prog_lc_state_o    ( lc_otp_program_o.state           ),
@@ -692,4 +694,10 @@
   `ASSERT_KNOWN(LcFlashRmaReqKnown_A,   lc_flash_rma_req_o         )
   `ASSERT_KNOWN(LcKeymgrDiv_A,          lc_keymgr_div_o            )
 
+  // Alert assertions for sparse FSMs.
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlLcFsmCheck_A,
+      u_lc_ctrl_fsm.u_fsm_state_regs, alert_tx_o[1])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlKmacIfFsmCheck_A,
+      u_lc_ctrl_kmac_if.u_state_regs, alert_tx_o[1])
+
 endmodule : lc_ctrl
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_fsm.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_fsm.sv
index 7e82f07..eea2de2 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_fsm.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_fsm.sv
@@ -48,6 +48,7 @@
   output logic                  token_hash_req_chk_o,
   input                         token_hash_ack_i,
   input                         token_hash_err_i,
+  input                         token_if_fsm_err_i,
   input  lc_token_t             hashed_token_i,
   // OTP programming interface
   output logic                  otp_prog_req_o,
@@ -416,11 +417,11 @@
       ///////////////////////////////////////////////////////////////////
     endcase
 
-    // If at any time the life cycle state encoding is not valid,
-    // we jump into the terminal error state right away.
+    // If at any time the life cycle state encoding or any other FSM state within this module
+    // is not valid, we jump into the terminal error state right away.
     // Note that state_invalid_error is a multibit error signal
     // with different error sources - need to reduce this to one bit here.
-    if (|state_invalid_error) begin
+    if (|state_invalid_error | token_if_fsm_err_i) begin
       fsm_state_d = InvalidSt;
       state_invalid_error_o = 1'b1;
     end else if (esc_scrap_state0_i || esc_scrap_state1_i) begin
@@ -436,14 +437,15 @@
   // flops in order to prevent FSM state encoding optimizations.
   logic [FsmStateWidth-1:0] fsm_state_raw_q;
   assign fsm_state_q = fsm_state_e'(fsm_state_raw_q);
-  prim_flop #(
+  prim_sparse_fsm_flop #(
+    .StateEnumT(fsm_state_e),
     .Width(FsmStateWidth),
     .ResetValue(FsmStateWidth'(ResetSt))
   ) u_fsm_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( fsm_state_d     ),
-    .q_o ( fsm_state_raw_q )
+    .state_i ( fsm_state_d     ),
+    .state_o ( fsm_state_raw_q )
   );
 
   logic [LcStateWidth-1:0] lc_state_raw_q;
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_kmac_if.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_kmac_if.sv
index 6949d55..00b7202 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_kmac_if.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_kmac_if.sv
@@ -26,8 +26,9 @@
   input                         token_hash_req_i,
   // Used for gating assertions inside CDC primitives.
   input                         token_hash_req_chk_i,
-  output                        token_hash_ack_o,
-  output                        token_hash_err_o,
+  output logic                  token_hash_ack_o,
+  output logic                  token_hash_err_o,
+  output logic                  token_if_fsm_err_o,
   output lc_token_t             hashed_token_o
 );
 
@@ -141,15 +142,15 @@
   //
   // Minimum Hamming distance: 5
   // Maximum Hamming distance: 6
-  // Minimum Hamming weight: 1
+  // Minimum Hamming weight: 2
   // Maximum Hamming weight: 6
   //
   localparam int StateWidth = 8;
   typedef enum logic [StateWidth-1:0] {
-    FirstSt  = 8'b00000001,
-    SecondSt = 8'b11110011,
-    WaitSt   = 8'b10111100,
-    DoneSt   = 8'b01001110
+    FirstSt  = 8'b01011011,
+    SecondSt = 8'b10010100,
+    WaitSt   = 8'b11100111,
+    DoneSt   = 8'b00101000
   } state_e;
 
   state_e state_d, state_q;
@@ -159,6 +160,7 @@
     state_d = state_q;
     kmac_data_o = '0;
     kmac_ack = 1'b0;
+    token_if_fsm_err_o = 1'b0;
 
     unique case (state_q)
       // Wait for request and transfer first half of
@@ -193,7 +195,9 @@
       // Terminal state (by design we can only perform
       // one token hashing operation per reset cycle).
       DoneSt: ;
-      default: state_d = DoneSt;
+      default: begin
+        token_if_fsm_err_o = 1'b1;
+      end
     endcase // state_q
   end
 
@@ -201,14 +205,15 @@
   // flops in order to prevent FSM state encoding optimizations.
   logic [StateWidth-1:0] state_raw_q;
   assign state_q = state_e'(state_raw_q);
-  prim_flop #(
+  prim_sparse_fsm_flop #(
+    .StateEnumT(state_e),
     .Width(StateWidth),
     .ResetValue(StateWidth'(FirstSt))
   ) u_state_regs (
-    .clk_i  ( clk_kmac_i  ),
-    .rst_ni ( rst_kmac_ni ),
-    .d_i    ( state_d     ),
-    .q_o    ( state_raw_q )
+    .clk_i   ( clk_kmac_i  ),
+    .rst_ni  ( rst_kmac_ni ),
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
   );
 
 endmodule : lc_ctrl_kmac_if
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
index 98cd875..2545145 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
@@ -62,14 +62,14 @@
   //  3: --
   //  4: --
   //  5: ||||||| (7.62%)
-  //  6: |||||||||| (10.48%)
-  //  7: ||||||||||||||||| (17.14%)
-  //  8: |||||||||||||||||||| (20.00%)
-  //  9: ||||||||||||||||||| (19.05%)
-  // 10: |||||||||||||| (14.29%)
+  //  6: ||||||||| (9.52%)
+  //  7: |||||||||||||||| (17.14%)
+  //  8: |||||||||||||||||||| (20.95%)
+  //  9: ||||||||||||||||| (18.10%)
+  // 10: ||||||||||||| (14.29%)
   // 11: |||||| (6.67%)
   // 12: ||| (3.81%)
-  // 13:  (0.95%)
+  // 13: | (1.90%)
   // 14: --
   // 15: --
   // 16: --
@@ -81,13 +81,13 @@
   //
   localparam int FsmStateWidth = 16;
   typedef enum logic [FsmStateWidth-1:0] {
-    ResetSt       = 16'b1100000001111011,
-    IdleSt        = 16'b1111011010111100,
-    ClkMuxSt      = 16'b0000011110101101,
-    CntIncrSt     = 16'b1100111011001001,
-    CntProgSt     = 16'b0011001111000111,
-    TransCheckSt  = 16'b0000110001010100,
-    TokenHashSt   = 16'b0110111010110000,
+    ResetSt       = 16'b1111011010111100,
+    IdleSt        = 16'b0000011110101101,
+    ClkMuxSt      = 16'b1100111011001001,
+    CntIncrSt     = 16'b0011001111000111,
+    CntProgSt     = 16'b0000110001010100,
+    TransCheckSt  = 16'b0110111010110000,
+    TokenHashSt   = 16'b1101001000111111,
     FlashRmaSt    = 16'b1110100010001111,
     TokenCheck0St = 16'b0010000011000000,
     TokenCheck1St = 16'b1101010101101111,