[otbn] Added sparse FSM encoding

Signed-off-by: Vladimir Rozic <vrozic@lowrisc.org>
diff --git a/hw/ip/otbn/rtl/otbn_controller.sv b/hw/ip/otbn/rtl/otbn_controller.sv
index 5e2fd16..8eb1f41 100644
--- a/hw/ip/otbn/rtl/otbn_controller.sv
+++ b/hw/ip/otbn/rtl/otbn_controller.sv
@@ -138,6 +138,8 @@
   input  logic        illegal_bus_access_i,
   input  logic        lifecycle_escalation_i,
   input  logic        software_errs_fatal_i,
+  input  logic        start_stop_state_error_i,
+  input  logic        otbn_scramble_state_error_i,
 
   input logic [1:0] sideload_key_shares_valid_i,
 
@@ -157,6 +159,7 @@
   logic recoverable_err;
   logic done_complete;
   logic executing;
+  logic state_error;
 
   logic                     insn_fetch_req_valid_raw;
   logic [ImemAddrWidth-1:0] insn_fetch_req_addr_last;
@@ -304,7 +307,8 @@
     err_bits_en              = 1'b0;
     prefetch_en_o            = 1'b0;
 
-    // TODO: Harden state machine
+    state_error = 1'b0;
+
     unique case (state_q)
       OtbnStateHalt: begin
         if (start_i) begin
@@ -370,7 +374,9 @@
         insn_fetch_req_valid_raw = 1'b0;
         state_d                  = OtbnStateLocked;
       end
-      default: ;
+      default: begin
+        state_error = 1'b1;
+      end
     endcase
 
     // On any error immediately halt, either going to OtbnStateLocked or OtbnStateHalt depending on
@@ -427,7 +433,8 @@
   assign err_bits.fatal_software       = software_err & software_errs_fatal_i;
   assign err_bits.lifecycle_escalation = lifecycle_escalation_i;
   assign err_bits.illegal_bus_access   = illegal_bus_access_i;
-  assign err_bits.bad_internal_state   = 0;
+  assign err_bits.bad_internal_state   = start_stop_state_error_i | state_error |
+                                          otbn_scramble_state_error_i;
   assign err_bits.bus_intg_violation   = bus_intg_violation_i;
   assign err_bits.reg_intg_violation   = rf_base_rd_data_err_i | rf_bignum_rd_data_err_i;
   assign err_bits.dmem_intg_violation  = lsu_rdata_err_i;
@@ -459,6 +466,7 @@
   assign fatal_err = |{err_bits.fatal_software,
                        err_bits.lifecycle_escalation,
                        err_bits.illegal_bus_access,
+                       err_bits.bad_internal_state ,
                        err_bits.bus_intg_violation,
                        err_bits.reg_intg_violation,
                        err_bits.dmem_intg_violation,
@@ -511,13 +519,20 @@
   `ASSERT(NoStallOnBranch,
       insn_valid_i & insn_dec_shared_i.branch_insn |-> state_q != OtbnStateStall)
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      state_q <= OtbnStateHalt;
-    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 [StateControllerWidth-1:0] state_raw_q;
+  assign state_q = otbn_state_e'(state_raw_q);
+  prim_sparse_fsm_flop #(
+    .StateEnumT(otbn_state_e),
+    .Width(StateControllerWidth),
+    .ResetValue(StateControllerWidth'(OtbnStateHalt))
+  ) u_state_regs (
+    .clk_i,
+    .rst_ni,
+    .state_i ( state_d     ),
+    .state_o ( state_raw_q )
+  );
 
   assign insn_cnt_clear = state_reset_i | (state_q == OtbnStateLocked) | insn_cnt_clear_i;