[otp_ctrl] Switch to sparse fsm primitive

Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/otp_ctrl/otp_ctrl.core b/hw/ip/otp_ctrl/otp_ctrl.core
index 0411fb0..159c101 100644
--- a/hw/ip/otp_ctrl/otp_ctrl.core
+++ b/hw/ip/otp_ctrl/otp_ctrl.core
@@ -21,6 +21,7 @@
       - lowrisc:prim:edn_req
       - lowrisc:ip:pwrmgr_pkg
       - lowrisc:ip:edn_pkg
+      - lowrisc:prim:sparse_fsm
       - "fileset_partner  ? (partner:systems:ast_pkg)"
       - "!fileset_partner ? (lowrisc:systems:ast_pkg)"
     files:
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
index 4c285ba..85a0a9e 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
@@ -828,7 +828,7 @@
   logic scrmbl_arb_req_ready, scrmbl_arb_rsp_valid;
   logic [NumAgents-1:0] part_scrmbl_req_ready, part_scrmbl_rsp_valid;
 
-  otp_ctrl_scrmbl u_scrmbl (
+  otp_ctrl_scrmbl u_otp_ctrl_scrmbl (
     .clk_i,
     .rst_ni,
     .cmd_i         ( scrmbl_req_bundle.cmd       ),
@@ -1070,6 +1070,9 @@
                                          integ_chk_req[k],
                                          cnsty_chk_req[k]};
 
+      // Alert assertion for sparse FSM.
+      `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlPartBufFsmCheck_A,
+          u_part_unbuf.u_state_regs, alert_tx_o[1])
     ////////////////////////////////////////////////////////////////////////////////////////////////
     end else if (PartInfo[k].variant == Buffered) begin : gen_buffered
       otp_ctrl_part_buf #(
@@ -1120,6 +1123,11 @@
       assign part_tlul_rerror[k] = '0;
       assign part_tlul_rvalid[k] = 1'b0;
       assign part_tlul_rdata[k]  = '0;
+
+      // Alert assertion for sparse FSM.
+      `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlPartBufFsmCheck_A,
+          u_part_buf.u_state_regs, alert_tx_o[1])
+    ////////////////////////////////////////////////////////////////////////////////////////////////
     end else if (PartInfo[k].variant == LifeCycle) begin : gen_lifecycle
       otp_ctrl_part_buf #(
         .Info(PartInfo[k]),
@@ -1182,10 +1190,15 @@
       assign unused_part_scrmbl_sigs = ^{part_scrmbl_mtx_gnt[k],
                                          part_scrmbl_req_ready[k],
                                          part_scrmbl_rsp_valid[k]};
+      // Alert assertion for sparse FSM.
+      `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlPartLcFsmCheck_A,
+          u_part_buf.u_state_regs, alert_tx_o[1])
+    ////////////////////////////////////////////////////////////////////////////////////////////////
     end else begin : gen_invalid
       // This is invalid and should break elaboration
       assert_static_in_generate_invalid assert_static_in_generate_invalid();
     end
+    ////////////////////////////////////////////////////////////////////////////////////////////////
   end
 
   //////////////////////////////////
@@ -1308,4 +1321,16 @@
   `ASSERT_KNOWN(OtpOtgnKeyKnown_A,           otbn_otp_key_o)
   `ASSERT_KNOWN(OtpHwCfgKnown_A,             otp_hw_cfg_o)
 
+  // Alert assertions for sparse FSMs.
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlDaiFsmCheck_A,
+      u_otp_ctrl_dai.u_state_regs, alert_tx_o[1])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlKdiFsmCheck_A,
+      u_otp_ctrl_kdi.u_state_regs, alert_tx_o[1])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlLciFsmCheck_A,
+      u_otp_ctrl_lci.u_state_regs, alert_tx_o[1])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlLfsrTimerFsmCheck_A,
+      u_otp_ctrl_lfsr_timer.u_state_regs, alert_tx_o[1])
+  `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlScrambleFsmCheck_A,
+      u_otp_ctrl_scrmbl.u_state_regs, alert_tx_o[1])
+
 endmodule : otp_ctrl
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
index 1b705b6..c2704fc 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
@@ -79,48 +79,53 @@
   // DAI Control FSM //
   /////////////////////
 
-  // Encoding generated with ./sparse-fsm-encode.py -d 5 -m 20 -n 12 -s 3011551511
+  // Encoding generated with:
+  // $ ./util/design/sparse-fsm-encode.py -d 5 -m 20 -n 12 \
+  //      -s 3011551511 --language=sv
+  //
   // Hamming distance histogram:
   //
-  // 0:  --
-  // 1:  --
-  // 2:  --
-  // 3:  --
-  // 4:  --
-  // 5:  |||||||||||||||||| (32.11%)
-  // 6:  |||||||||||||||||||| (35.26%)
-  // 7:  |||||||| (15.79%)
-  // 8:  |||||| (11.58%)
-  // 9:  | (2.11%)
-  // 10:  (1.05%)
-  // 11: | (2.11%)
+  //  0: --
+  //  1: --
+  //  2: --
+  //  3: --
+  //  4: --
+  //  5: |||||||||||||||| (31.05%)
+  //  6: |||||||||||||||||||| (36.84%)
+  //  7: |||||||| (15.26%)
+  //  8: |||| (8.95%)
+  //  9: || (5.26%)
+  // 10:  (1.58%)
+  // 11:  (1.05%)
   // 12: --
   //
   // Minimum Hamming distance: 5
   // Maximum Hamming distance: 11
+  // Minimum Hamming weight: 2
+  // Maximum Hamming weight: 9
   //
-  parameter int StateWidth = 12;
+  localparam int StateWidth = 12;
   typedef enum logic [StateWidth-1:0] {
-    ResetSt       = 12'b001000011011,
-    InitOtpSt     = 12'b101111001001,
-    InitPartSt    = 12'b101010100111,
-    IdleSt        = 12'b110100110101,
-    ErrorSt       = 12'b100011010000,
-    ReadSt        = 12'b111001010110,
-    ReadWaitSt    = 12'b000101100111,
-    DescrSt       = 12'b110001001101,
-    DescrWaitSt   = 12'b010000110010,
-    WriteSt       = 12'b101101111100,
-    WriteWaitSt   = 12'b100100101010,
-    ScrSt         = 12'b111110010011,
-    ScrWaitSt     = 12'b010110011000,
-    DigClrSt      = 12'b011100001110,
-    DigReadSt     = 12'b011001101000,
-    DigReadWaitSt = 12'b000011111110,
-    DigSt         = 12'b000010101001,
-    DigPadSt      = 12'b000000000100,
-    DigFinSt      = 12'b010011000011,
-    DigWaitSt     = 12'b011011110101
+    ResetSt       = 12'b101111010100,
+    InitOtpSt     = 12'b110000110010,
+    InitPartSt    = 12'b000111111001,
+    IdleSt        = 12'b111010000011,
+    ErrorSt       = 12'b100010001110,
+    ReadSt        = 12'b100101100110,
+    ReadWaitSt    = 12'b001100000000,
+    DescrSt       = 12'b011000101111,
+    DescrWaitSt   = 12'b110101011111,
+    WriteSt       = 12'b110111001000,
+    WriteWaitSt   = 12'b111001111100,
+    ScrSt         = 12'b000000010101,
+    ScrWaitSt     = 12'b010110110100,
+    DigClrSt      = 12'b001111001111,
+    DigReadSt     = 12'b001001110011,
+    DigReadWaitSt = 12'b101110111010,
+    DigSt         = 12'b011111100010,
+    DigPadSt      = 12'b011010011000,
+    DigFinSt      = 12'b110011100101,
+    DigWaitSt     = 12'b100000101001
   } state_e;
 
   typedef enum logic [1:0] {
@@ -720,14 +725,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'(ResetSt))
   ) u_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( state_d     ),
-    .q_o ( state_raw_q )
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
index 125fbed..8339c62 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
@@ -248,7 +248,7 @@
   /////////////////
 
   // Encoding generated with:
-  // $ ./sparse-fsm-encode.py -d 5 -m 11 -n 10 \
+  // $ ./util/design/sparse-fsm-encode.py -d 5 -m 11 -n 10 \
   //      -s 2544133835 --language=sv
   //
   // Hamming distance histogram:
@@ -267,20 +267,22 @@
   //
   // Minimum Hamming distance: 5
   // Maximum Hamming distance: 6
+  // Minimum Hamming weight: 3
+  // Maximum Hamming weight: 9
   //
   localparam int StateWidth = 10;
   typedef enum logic [StateWidth-1:0] {
-    ResetSt        = 10'b0111100000,
-    IdleSt         = 10'b0001111101,
-    DigClrSt       = 10'b1101101011,
-    DigLoadSt      = 10'b0100011010,
-    FetchEntropySt = 10'b0010001001,
-    DigEntropySt   = 10'b0110110111,
-    DigFinSt       = 10'b0001000110,
-    DigWaitSt      = 10'b1100000101,
-    FetchNonceSt   = 10'b1010101110,
-    FinishSt       = 10'b1111011100,
-    ErrorSt        = 10'b1011010011
+    ResetSt        = 10'b0101100001,
+    IdleSt         = 10'b0001011011,
+    DigClrSt       = 10'b1101010110,
+    DigLoadSt      = 10'b0010110111,
+    FetchEntropySt = 10'b1000001101,
+    DigEntropySt   = 10'b0100111100,
+    DigFinSt       = 10'b1000100010,
+    DigWaitSt      = 10'b1110010001,
+    FetchNonceSt   = 10'b0011000100,
+    FinishSt       = 10'b1011111000,
+    ErrorSt        = 10'b1111101111
   } state_e;
 
   state_e state_d, state_q;
@@ -505,14 +507,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'(ResetSt))
   ) u_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( state_d     ),
-    .q_o ( state_raw_q )
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
index 4ccdff4..1dc605d 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
@@ -66,30 +66,35 @@
   // Controller FSM //
   ////////////////////
 
-  // Encoding generated with ./sparse-fsm-encode.py -d 5 -m 5 -n 9 -s 558234734
+  // Encoding generated with:
+  // $ ./util/design/sparse-fsm-encode.py -d 5 -m 5 -n 9 \
+  //      -s 558234734 --language=sv
+  //
   // Hamming distance histogram:
   //
-  // 0: --
-  // 1: --
-  // 2: --
-  // 3: --
-  // 4: --
-  // 5: |||||||||||||||||||| (60.00%)
-  // 6: ||||||||||||| (40.00%)
-  // 7: --
-  // 8: --
-  // 9: --
+  //  0: --
+  //  1: --
+  //  2: --
+  //  3: --
+  //  4: --
+  //  5: |||||||||||||||||||| (60.00%)
+  //  6: ||||||||||||| (40.00%)
+  //  7: --
+  //  8: --
+  //  9: --
   //
   // Minimum Hamming distance: 5
   // Maximum Hamming distance: 6
+  // Minimum Hamming weight: 1
+  // Maximum Hamming weight: 7
   //
   localparam int StateWidth = 9;
   typedef enum logic [StateWidth-1:0] {
-    ResetSt     = 9'b010110111,
-    IdleSt      = 9'b101010010,
-    WriteSt     = 9'b111101110,
-    WriteWaitSt = 9'b100011101,
-    ErrorSt     = 9'b010000000
+    ResetSt     = 9'b000101011,
+    IdleSt      = 9'b110011110,
+    WriteSt     = 9'b101010001,
+    WriteWaitSt = 9'b010000000,
+    ErrorSt     = 9'b011111101
   } state_e;
 
   logic cnt_clr, cnt_en;
@@ -243,14 +248,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'(ResetSt))
   ) u_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( state_d     ),
-    .q_o ( state_raw_q )
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
index 3c63175..7ec2d67 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
@@ -217,30 +217,35 @@
   // Ping and Timeout Logic //
   ////////////////////////////
 
-  // Encoding generated with ./sparse-fsm-encode.py -d 5 -m 5 -n 9 -s 628816752
+  // Encoding generated with:
+  // $ ./util/design/sparse-fsm-encode.py -d 5 -m 5 -n 9 \
+  //      -s 628816752 --language=sv
+  //
   // Hamming distance histogram:
   //
-  // 0: --
-  // 1: --
-  // 2: --
-  // 3: --
-  // 4: --
-  // 5: |||||||||||||||||||| (60.00%)
-  // 6: ||||||||||||| (40.00%)
-  // 7: --
-  // 8: --
-  // 9: --
+  //  0: --
+  //  1: --
+  //  2: --
+  //  3: --
+  //  4: --
+  //  5: |||||||||||||||||||| (60.00%)
+  //  6: ||||||||||||| (40.00%)
+  //  7: --
+  //  8: --
+  //  9: --
   //
   // Minimum Hamming distance: 5
   // Maximum Hamming distance: 6
+  // Minimum Hamming weight: 4
+  // Maximum Hamming weight: 6
   //
   localparam int StateWidth = 9;
   typedef enum logic [StateWidth-1:0] {
-    ResetSt     = 9'b011111011,
-    IdleSt      = 9'b000100000,
-    IntegWaitSt = 9'b110010101,
-    CnstyWaitSt = 9'b001010110,
-    ErrorSt     = 9'b100101111
+    ResetSt     = 9'b100100101,
+    IdleSt      = 9'b001101110,
+    IntegWaitSt = 9'b010110011,
+    CnstyWaitSt = 9'b111010110,
+    ErrorSt     = 9'b001011001
   } state_e;
 
   state_e state_d, state_q;
@@ -373,14 +378,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'(ResetSt))
   ) u_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( state_d     ),
-    .q_o ( state_raw_q )
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
index 147a7a8..1367f2f 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
@@ -103,44 +103,49 @@
   // OTP Partition FSM //
   ///////////////////////
 
-  // Encoding generated with ./sparse-fsm-encode.py -d 5 -m 16 -n 12 -s 3370657881
+  // Encoding generated with:
+  // $ ./util/design/sparse-fsm-encode.py -d 5 -m 16 -n 12 \
+  //      -s 3370657881 --language=sv
+  //
   // Hamming distance histogram:
   //
-  // 0:  --
-  // 1:  --
-  // 2:  --
-  // 3:  --
-  // 4:  --
-  // 5:  |||||||||||||||||| (30.00%)
-  // 6:  |||||||||||||||||||| (32.50%)
-  // 7:  ||||||||||| (19.17%)
-  // 8:  ||||||| (11.67%)
-  // 9:  || (4.17%)
+  //  0: --
+  //  1: --
+  //  2: --
+  //  3: --
+  //  4: --
+  //  5: |||||||||||||| (28.33%)
+  //  6: |||||||||||||||||||| (38.33%)
+  //  7: |||||||||| (19.17%)
+  //  8: ||| (5.83%)
+  //  9: || (4.17%)
   // 10: | (2.50%)
-  // 11: --
-  // 12: --
+  // 11:  (0.83%)
+  // 12:  (0.83%)
   //
   // Minimum Hamming distance: 5
-  // Maximum Hamming distance: 10
+  // Maximum Hamming distance: 12
+  // Minimum Hamming weight: 4
+  // Maximum Hamming weight: 8
   //
   localparam int StateWidth = 12;
   typedef enum logic [StateWidth-1:0] {
-    ResetSt         = 12'b001001101010,
+    ResetSt         = 12'b011000001110,
     InitSt          = 12'b110100100111,
     InitWaitSt      = 12'b001110110001,
     InitDescrSt     = 12'b110010000100,
-    InitDescrWaitSt = 12'b101000011100,
-    IdleSt          = 12'b100110101000,
-    IntegScrSt      = 12'b010101001101,
-    IntegScrWaitSt  = 12'b110101011010,
-    IntegDigClrSt   = 12'b011000011011,
-    IntegDigSt      = 12'b101001000001,
-    IntegDigPadSt   = 12'b101111010111,
+    InitDescrWaitSt = 12'b100110101000,
+    IdleSt          = 12'b010101001101,
+    IntegScrSt      = 12'b110101011010,
+    IntegScrWaitSt  = 12'b100010011111,
+    IntegDigClrSt   = 12'b101001000001,
+    IntegDigSt      = 12'b011101100010,
+    IntegDigPadSt   = 12'b001101010111,
     IntegDigFinSt   = 12'b011011100101,
     IntegDigWaitSt  = 12'b100011110010,
-    CnstyReadSt     = 12'b111111101110,
-    CnstyReadWaitSt = 12'b001100000110,
-    ErrorSt         = 12'b000011011001
+    CnstyReadSt     = 12'b000001101011,
+    CnstyReadWaitSt = 12'b101001111100,
+    ErrorSt         = 12'b010110111110
   } state_e;
 
   typedef enum logic {
@@ -667,14 +672,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'(ResetSt))
   ) u_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( state_d     ),
-    .q_o ( state_raw_q )
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
index 82a643d..b07268c 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
@@ -73,33 +73,38 @@
   // OTP Partition FSM //
   ///////////////////////
 
-  // Encoding generated with ./sparse-fsm-encode.py -d 5 -m 7 -n 10 -s 4247417884
+  // Encoding generated with:
+  // $ ./util/design/sparse-fsm-encode.py -d 5 -m 7 -n 10 \
+  //      -s 4247417884 --language=sv
+  //
   // Hamming distance histogram:
   //
-  // 0: --
-  // 1: --
-  // 2: --
-  // 3: --
-  // 4: --
-  // 5: |||||||||||||||||||| (52.38%)
-  // 6: |||||||||||||| (38.10%)
-  // 7: | (4.76%)
-  // 8: | (4.76%)
-  // 9: --
+  //  0: --
+  //  1: --
+  //  2: --
+  //  3: --
+  //  4: --
+  //  5: |||||||||||||||||||| (52.38%)
+  //  6: |||||||||||| (33.33%)
+  //  7: | (4.76%)
+  //  8: ||| (9.52%)
+  //  9: --
   // 10: --
   //
   // Minimum Hamming distance: 5
   // Maximum Hamming distance: 8
+  // Minimum Hamming weight: 3
+  // Maximum Hamming weight: 9
   //
   localparam int StateWidth = 10;
   typedef enum logic [StateWidth-1:0] {
-    ResetSt    = 10'b1000111001,
-    InitSt     = 10'b1010110110,
-    InitWaitSt = 10'b0100010011,
-    IdleSt     = 10'b0101011100,
-    ReadSt     = 10'b0011000010,
-    ReadWaitSt = 10'b1101100000,
-    ErrorSt    = 10'b0110100101
+    ResetSt    = 10'b1010110110,
+    InitSt     = 10'b0100010011,
+    InitWaitSt = 10'b0001011000,
+    IdleSt     = 10'b1011101001,
+    ReadSt     = 10'b0101101110,
+    ReadWaitSt = 10'b0110100101,
+    ErrorSt    = 10'b1111011111
   } state_e;
 
   typedef enum logic {
@@ -388,14 +393,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'(ResetSt))
   ) u_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( state_d     ),
-    .q_o ( state_raw_q )
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
index 15c67c4..0682ebc 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
@@ -202,30 +202,35 @@
   // FSM //
   /////////
 
-  // Encoding generated with ./sparse-fsm-encode.py -d 5 -m 5 -n 9 -s 2193087944
+  // Encoding generated with:
+  // $ ./util/design/sparse-fsm-encode.py -d 5 -m 5 -n 9 \
+  //      -s 2193087944 --language=sv
+  //
   // Hamming distance histogram:
   //
-  // 0: --
-  // 1: --
-  // 2: --
-  // 3: --
-  // 4: --
-  // 5: |||||||||||||||||||| (60.00%)
-  // 6: ||||||||||||| (40.00%)
-  // 7: --
-  // 8: --
-  // 9: --
+  //  0: --
+  //  1: --
+  //  2: --
+  //  3: --
+  //  4: --
+  //  5: |||||||||||||||||||| (60.00%)
+  //  6: ||||||||||||| (40.00%)
+  //  7: --
+  //  8: --
+  //  9: --
   //
   // Minimum Hamming distance: 5
   // Maximum Hamming distance: 6
+  // Minimum Hamming weight: 4
+  // Maximum Hamming weight: 7
   //
   localparam int StateWidth = 9;
   typedef enum logic [StateWidth-1:0] {
-    IdleSt    = 9'b100010111,
-    DecryptSt = 9'b001010000,
-    EncryptSt = 9'b011001011,
-    DigestSt  = 9'b100101000,
-    ErrorSt   = 9'b010111101
+    IdleSt    = 9'b100011001,
+    DecryptSt = 9'b101101111,
+    EncryptSt = 9'b010010111,
+    DigestSt  = 9'b111000010,
+    ErrorSt   = 9'b011111000
   } state_e;
 
   localparam int CntWidth = $clog2(NumPresentRounds+1);
@@ -419,14 +424,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'(IdleSt))
   ) u_state_regs (
     .clk_i,
     .rst_ni,
-    .d_i ( state_d     ),
-    .q_o ( state_raw_q )
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
   );
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs