[kmac] Add Main State Machine

This commit adds main state machine at the KMAC top and add
`in_progress` and `in_keyblock` signals for the entropy generation logic
to refresh the entropy.

The entropy logic uses in_progress signal to refresh the LFSR seed.
in_keyblock signal let entropy logic to refresh the entropy everytime it
is consumed, if not in keyblock state, entropy logic gives randome value
and not changed by consumed signal.

Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/hw/ip/kmac/rtl/kmac.sv b/hw/ip/kmac/rtl/kmac.sv
index 3d46a36..c31a9ea 100644
--- a/hw/ip/kmac/rtl/kmac.sv
+++ b/hw/ip/kmac/rtl/kmac.sv
@@ -55,6 +55,26 @@
   /////////////////
   // Definitions //
   /////////////////
+  // This state machine is to track the current process based on SW input and
+  // KMAC operation.
+  typedef enum logic [2:0] {
+    // Idle state
+    KmacIdle,
+
+    // When software writes CmdStart @ KmacIdle and kmac_en, FSM moves to this
+    KmacPrefix,
+
+    // When SHA3 engine processes Key block, FSM moves to here.
+    KmacKeyBlock,
+
+    // Message Feed
+    KmacMsgFeed,
+
+    // Complete and squeeze
+    KmacDigest
+
+  } kmac_st_e;
+  kmac_st_e kmac_st, kmac_st_d;
 
   /////////////
   // Signals //
@@ -80,6 +100,12 @@
   // Sequence: start --> process(multiple) --> get absorbed event --> {run -->} done
   logic sha3_start, sha3_run, sha3_done, sha3_absorbed, unused_sha3_squeeze;
 
+  // Indicate one block processed
+  logic sha3_block_processed;
+
+  // EStatus for entropy
+  logic entropy_in_progress, entropy_in_keyblock;
+
   // KeyMgr interface logic generates event_absorbed from sha3_absorbed.
   // It is active only if SW initiates the hashing engine.
   logic event_absorbed;
@@ -187,6 +213,7 @@
 
   logic entropy_ready;
   entropy_mode_e entropy_mode;
+  logic entropy_fast_process;
 
   // SHA3 Error response
   sha3_pkg::err_t sha3_err;
@@ -317,6 +344,7 @@
   // Entropy config
   assign entropy_ready = reg2hw.cfg.entropy_ready.q;
   assign entropy_mode  = entropy_mode_e'(reg2hw.cfg.entropy_mode.q);
+  assign entropy_fast_process = reg2hw.cfg.entropy_fast_process.q;
 
   assign hw2reg.cfg.entropy_ready.de = entropy_ready;
   assign hw2reg.cfg.entropy_ready.d = 1'b 0; // always clear when ready
@@ -419,6 +447,87 @@
     .intr_o                 (intr_kmac_err_o)
   );
 
+  ///////////////////
+  // State Machine //
+  ///////////////////
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      kmac_st <= KmacIdle;
+    end else begin
+      kmac_st <= kmac_st_d;
+    end
+  end
+
+  always_comb begin
+    // Default value
+    kmac_st_d = KmacIdle;
+
+    entropy_in_progress = 1'b 0;
+    entropy_in_keyblock = 1'b 0;
+
+    unique case (kmac_st)
+      KmacIdle: begin
+        if (kmac_cmd == CmdStart) begin
+          // If cSHAKE turned on
+          if (sha3_pkg::CShake == sha3_pkg::sha3_mode_e'(reg2hw.cfg.mode.q)) begin
+            kmac_st_d = KmacPrefix;
+          end else begin
+            // Jump to Msg feed directly
+            kmac_st_d = KmacMsgFeed;
+          end
+        end else begin
+          kmac_st_d = KmacIdle;
+        end
+      end
+
+      KmacPrefix: begin
+        entropy_in_progress =1'b 1;
+        // Wait until SHA3 processes one block
+        if (sha3_block_processed) begin
+          kmac_st_d = (reg2hw.cfg.kmac_en.q) ? KmacKeyBlock : KmacMsgFeed ;
+        end else begin
+          kmac_st_d = KmacPrefix;
+        end
+      end
+
+      KmacKeyBlock: begin
+        entropy_in_progress = 1'b 1;
+        entropy_in_keyblock = 1'b 1;
+        if (sha3_block_processed) begin
+          kmac_st_d = KmacMsgFeed;
+        end else begin
+          kmac_st_d = KmacKeyBlock;
+        end
+      end
+
+      KmacMsgFeed: begin
+        entropy_in_progress = 1'b 1;
+        // If absorbed, move to Digest
+        if (sha3_absorbed) begin
+          kmac_st_d = KmacDigest;
+        end else begin
+          kmac_st_d = KmacMsgFeed;
+        end
+      end
+
+      KmacDigest: begin
+        entropy_in_progress = 1'b 1;
+        // SW can manually run it, wait till done
+        if (sha3_done) begin
+          kmac_st_d = KmacIdle;
+        end else begin
+          kmac_st_d = KmacDigest;
+        end
+      end
+
+      default: begin
+        kmac_st_d = KmacIdle;
+      end
+    endcase
+  end
+  `ASSERT_KNOWN(KmacStKnown_A, kmac_st)
+
   ///////////////
   // Instances //
   ///////////////
@@ -493,6 +602,8 @@
     .absorbed_o  (sha3_absorbed),
     .squeezing_o (unused_sha3_squeeze),
 
+    .block_processed_o (sha3_block_processed),
+
     .sha3_fsm_o (sha3_fsm),
 
     .state_valid_o (state_valid),
@@ -669,13 +780,14 @@
 
       // Status from internal logic
       //// SHA3 engine run indicator
-      .in_progress_i (),
+      .in_progress_i (entropy_in_progress),
       //// KMAC secret block handling indicator
-      .in_keyblock_i (),
+      .in_keyblock_i (entropy_in_keyblock),
 
       // Configuration
       .mode_i          (entropy_mode),
       .entropy_ready_i (entropy_ready),
+      .fast_process_i  (entropy_fast_process),
 
       //// Entropy refresh period in clk cycles
       .entropy_timer_limit_i (entropy_timer_limit),
@@ -708,6 +820,9 @@
     assign unused_refresh_period = {wait_timer_limit, entropy_timer_limit};
 
     assign entropy_err = '{valid: 1'b 0, code: ErrNone, info: '0};
+
+    logic [1:0] unused_entropy_status;
+    assign unused_entropy_status = {entropy_in_keyblock, entropy_in_progress};
   end
 
   // Register top
diff --git a/hw/ip/kmac/rtl/kmac_entropy.sv b/hw/ip/kmac/rtl/kmac_entropy.sv
index e3db4a9..f0b9159 100644
--- a/hw/ip/kmac/rtl/kmac_entropy.sv
+++ b/hw/ip/kmac/rtl/kmac_entropy.sv
@@ -31,6 +31,11 @@
   //// interface.
   input entropy_ready_i,
 
+  //// Garbage random value when not processing Keyblock, if this config is
+  //// turned on, the logic sending garbage value and never de-assert
+  //// rand_valid_o unless it is not processing KeyBlock.
+  input fast_process_i,
+
   //// SW update of seed
   input        seed_update_i,
   input [63:0] seed_data_i,
@@ -288,7 +293,7 @@
       rand_valid_o <= 1'b 0;
     end else if (rand_valid_set) begin
       rand_valid_o <= 1'b 1;
-    end else if (rand_valid_clear || rand_consumed_i) begin
+    end else if (rand_valid_clear) begin
       rand_valid_o <= 1'b 0;
     end
   end
@@ -403,7 +408,12 @@
       StRandReady: begin
         timer_enable = 1'b 1; // If limit is zero, timer won't work
 
-        if (rand_consumed_i) begin
+        if ( (fast_process_i && in_keyblock_i && rand_consumed_i)
+          || (!fast_process_i && rand_consumed_i)) begin
+          // If fast_process is set, don't clear the rand valid, even
+          // consumed. So, the logic does not expand the entropy again.
+          // If fast_process is not set, then every rand_consume signal
+          // triggers rand expansion.
           st_d = StRandExpand;
 
           lfsr_en           = 1'b 1;
diff --git a/hw/ip/kmac/rtl/sha3.sv b/hw/ip/kmac/rtl/sha3.sv
index 7dfd855..3c85006 100644
--- a/hw/ip/kmac/rtl/sha3.sv
+++ b/hw/ip/kmac/rtl/sha3.sv
@@ -55,6 +55,10 @@
   output logic absorbed_o,
   output logic squeezing_o,
 
+  // Indicate of one block processed. KMAC main state tracks the progression
+  // based on this signal.
+  output logic block_processed_o,
+
   output sha3_st_e sha3_fsm_o,
 
   // digest output
@@ -130,6 +134,8 @@
   // Squeezing output
   assign squeezing_o = squeezing;
 
+  assign block_processed_o = keccak_complete;
+
   // State connection
   assign state_valid_o = state_valid;
   assign state_o = state_guarded;