| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 | // | 
 | // SHA3 padding logic | 
 |  | 
 | `include "prim_assert.sv" | 
 |  | 
 | module sha3pad | 
 |   import sha3_pkg::*; | 
 | #( | 
 |   parameter  bit EnMasking = 0, | 
 |   localparam int Share = (EnMasking) ? 2 : 1 | 
 | ) ( | 
 |   input clk_i, | 
 |   input rst_ni, | 
 |  | 
 |   // Message interface (FIFO) | 
 |   input                       msg_valid_i, | 
 |   input        [MsgWidth-1:0] msg_data_i [Share], | 
 |   input        [MsgStrbW-1:0] msg_strb_i,         // one strobe for shares | 
 |   output logic                msg_ready_o, | 
 |  | 
 |   // N, S: Used in cSHAKE mode only | 
 |   input [NSRegisterSize*8-1:0] ns_data_i, // See sha3_pkg for details | 
 |  | 
 |   // output to keccak_round: message path | 
 |   output logic                       keccak_valid_o, | 
 |   output logic [KeccakMsgAddrW-1:0]  keccak_addr_o, | 
 |   output logic [MsgWidth-1:0]        keccak_data_o [Share], | 
 |   input  logic                       keccak_ready_i, | 
 |  | 
 |   // keccak_round control and status | 
 |   // `run` initiates the keccak_round to process full keccak_f (24rounds). | 
 |   // `complete` is an input from keccak round showing the current keccak_f is | 
 |   // completed. | 
 |   output logic keccak_run_o, | 
 |   input        keccak_complete_i, | 
 |  | 
 |   // configurations | 
 |   input sha3_mode_e       mode_i, | 
 |   // strength_i is used in bytepad operation. bytepad() is used in cSHAKE only. | 
 |   // SHA3, SHAKE doesn't have encode_N,S | 
 |   input keccak_strength_e strength_i, | 
 |  | 
 |   // control signal | 
 |   // start_i is a pulse signal triggers the padding logic (and the rest of SHA) | 
 |   // to accept the incoming messages. This signal is used in the pad module, | 
 |   // to initiate the prefix transmitting to keccak_round | 
 |   input start_i, | 
 |   // process_i is a pulse signal triggers the pad logic to stop receiving the | 
 |   // message from MSG_FIFO and pad the trailing bits specified in the SHA3 | 
 |   // standard. Look at `funcpad` signal for the values. | 
 |   input process_i, | 
 |   // done_i is a pulse signal to make the pad logic to clear internal variables | 
 |   // and to move back to the Idle state for next hashing process. | 
 |   // done_i may not needed if sw controls the keccak_round directly. | 
 |   input done_i, | 
 |  | 
 |   // Indication of the Keccak Sponge Absorbing is complete, it is time for SW to | 
 |   // control the Keccak-round if it needs more digest, or complete by asserting | 
 |   // `done_i` | 
 |   output logic absorbed_o | 
 | ); | 
 |  | 
 |   ///////////////// | 
 |   // Definitions // | 
 |   ///////////////// | 
 |  | 
 |   // Padding States | 
 |   // TODO: Make it has Hamming Distance >= 3 to be resistent to glitch attacks. | 
 |   typedef enum logic [3:0] { | 
 |     StPadIdle, | 
 |  | 
 |     // Sending a block of prefix, if cSHAKE mode is turned on. For the rest | 
 |     // (SHA3, SHAKE), sending prefix is not needed. FSM moves from Idle to | 
 |     // Message directly in that case. | 
 |     // | 
 |     // As prim_slicer is instantiated, zerofill after the actual prefix is done | 
 |     // by the module. | 
 |     StPrefix, | 
 |     StPrefixWait, | 
 |  | 
 |     // Sending Message. In this state, it directly forwards the incoming data | 
 |     // to Keccak round module. If `process_i` is asserted, then the rest of the | 
 |     // messages will be discarded until new `start_i` is asserted. | 
 |     // | 
 |     // The incoming data can be partial write. Padding logic counts the number | 
 |     // of bytes received and pause if a block size is transferred. | 
 |     StMessage, | 
 |     StMessageWait, | 
 |  | 
 |     // After sending the messages, then `process_i` is set, the FSM pads at the | 
 |     // end of the message based on `mode_i`. If this is the last byte of the | 
 |     // block, then it pads [7] to 1 to complete `pad10*1()` function. | 
 |     StPad, | 
 |     StPadRun, | 
 |  | 
 |     // If the padding isn't the end of the block byte (which will be rare case), | 
 |     // FSM moves to another zerofill state. In contrast to StZerofill, this state | 
 |     StPad01, | 
 |  | 
 |     // Flushing the internal packers in front of the Keccak data output port. | 
 |     StPadFlush | 
 |   } pad_st_e; | 
 |  | 
 |   typedef enum logic [2:0] { | 
 |     MuxNone    = 3'b 000, | 
 |     MuxFifo    = 3'b 001, | 
 |     MuxPrefix  = 3'b 010, | 
 |     MuxFuncPad = 3'b 011, | 
 |     MuxZeroEnd = 3'b 100 | 
 |   } mux_sel_e; | 
 |  | 
 |   //////////////////// | 
 |   // Configurations // | 
 |   //////////////////// | 
 |  | 
 |   logic [KeccakCountW-1:0] block_addr_limit; | 
 |  | 
 |   // Block size based on the address. | 
 |   // This is used for bytepad() and also pad10*1() | 
 |   // assign block_addr_limit = KeccakRate[strength_i]; | 
 |   // but below is easier to understand | 
 |   always_comb begin | 
 |     unique case (strength_i) | 
 |       L128: block_addr_limit = KeccakCountW'(KeccakRate[L128]); | 
 |       L224: block_addr_limit = KeccakCountW'(KeccakRate[L224]); | 
 |       L256: block_addr_limit = KeccakCountW'(KeccakRate[L256]); | 
 |       L384: block_addr_limit = KeccakCountW'(KeccakRate[L384]); | 
 |       L512: block_addr_limit = KeccakCountW'(KeccakRate[L512]); | 
 |  | 
 |       default: block_addr_limit = '0; | 
 |     endcase | 
 |   end | 
 |  | 
 |   ///////////////////// | 
 |   // Control Signals // | 
 |   ///////////////////// | 
 |  | 
 |   // `sel_mux` selects the output data among the incoming or internally generated data. | 
 |   // MuxFifo:    data from external (msg_data_i) | 
 |   // MuxPrefix:  bytepad(encode_string(N)||encode_string(S), ) | 
 |   // MuxFuncPad: function_pad with end of message | 
 |   // MuxZeroEnd: all 0 | 
 |   mux_sel_e sel_mux; | 
 |  | 
 |   // `sent_message` indicates the number of entries sent to keccak round per | 
 |   // block. The value shall be enough to cover Maximum entry of the Keccak | 
 |   // storage as defined in sha3_pkg, `$clog2(KeccakEntries+1)`. Logically, | 
 |   // it is not needed to have more than KeccakEntries but for safety in case of | 
 |   // SHA3 context switch resuming the SHA3 from the middle of sponge | 
 |   // construction. If needed, the software should be able to write whole 1600 | 
 |   // bits. The `sent_message` is used to check sent_blocksize. | 
 |   logic [KeccakCountW-1:0] sent_message; | 
 |   logic inc_sentmsg, clr_sentmsg; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni)          sent_message <= '0; | 
 |     else if (clr_sentmsg) sent_message <= '0; | 
 |     else if (inc_sentmsg) sent_message <= sent_message + 1'b 1; | 
 |   end | 
 |  | 
 |   assign inc_sentmsg = keccak_valid_o & keccak_ready_i ; | 
 |  | 
 |   // Prefix index to slice the `prefix` n-bits into multiple of 64bit. | 
 |   logic [KeccakMsgAddrW-1:0] prefix_index; | 
 |   assign prefix_index = (sent_message < block_addr_limit) ? sent_message : '0; | 
 |  | 
 |   // fsm_keccak_valid is an output signal from FSM which to send data generated | 
 |   // inside the pad logic to keccak_round | 
 |   logic fsm_keccak_valid; | 
 |  | 
 |   // hold_msg to prevent message from being forwarded into keccak_round and | 
 |   // acked. Mainly the usage is to hold the message and initiates the | 
 |   // keccak_round for current block. | 
 |   logic hold_msg; | 
 |  | 
 |   // latch the partial write. Latched data is used for funcpad_merged | 
 |   logic en_msgbuf; | 
 |   logic clr_msgbuf; | 
 |  | 
 |   /////////////////// | 
 |   // State Machine // | 
 |   /////////////////// | 
 |  | 
 |   // Inputs | 
 |  | 
 |   // FSM moves to StPrefix only when cSHAKE is enabled | 
 |   logic mode_eq_cshake; | 
 |   assign mode_eq_cshake = (mode_i == CShake) ? 1'b 1 : 1'b 0; | 
 |  | 
 |   // `sent_blocksize` indicates the pad logic pushed block size data into | 
 |   // keccak round logic. | 
 |   logic sent_blocksize; | 
 |  | 
 |   assign sent_blocksize = (sent_message == block_addr_limit) ? 1'b 1 : 1'b 0; | 
 |  | 
 |   // `keccak_ack` indicates the request is accepted in keccak_round | 
 |   logic keccak_ack; | 
 |  | 
 |   assign keccak_ack = keccak_valid_o & keccak_ready_i ; | 
 |  | 
 |   // msg_partial indicates the incoming message is partial write or not. | 
 |   // This is used to check if the incoming message need to be latched inside or | 
 |   // not. If no partial message is at the end, msg_buf doesn't have to latch | 
 |   // msg_data_i. It is assumed that the partial message is permitted only at | 
 |   // the end of the message. So if (msg_valid_i && msg_partial && msg_ready_o), | 
 |   // there will be no msg_valid_i till process_latched. | 
 |   // Shall be used with msg_valid_i together. | 
 |   logic msg_partial; | 
 |   assign msg_partial = (&msg_strb_i != 1'b 1); | 
 |  | 
 |  | 
 |   // `process_latched` latches the `process_i` input before it is seen in the | 
 |   // FSM. `process_i` may follow `start_i` too fast so that the FSM may not | 
 |   // see it fast enought in case of cSHAKE mode. cSHAKE needs to process the | 
 |   // prefix prior to see the process indicator. | 
 |   logic process_latched; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       process_latched <= 1'b 0; | 
 |     // TODO: Reconsider the set condition, what if process_i comes without | 
 |     // `start_i` ? | 
 |     end else if (process_i) begin | 
 |       process_latched <= 1'b 1; | 
 |     // TODO: Reconsider the clear indicator, done_i is good enough? | 
 |     end else if (done_i) begin | 
 |       process_latched <= 1'b0; | 
 |     end | 
 |   end | 
 |  | 
 |   // State Register =========================================================== | 
 |   pad_st_e st, st_d; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       st <= StPadIdle; | 
 |     end else begin | 
 |       st <= st_d; | 
 |     end | 
 |   end | 
 |  | 
 |   // `end_of_block` indicates current beat is end of the block | 
 |   // It shall set when the address reaches to the end of the block. End address | 
 |   // is set by the strength_i, which is `block_addr_limit`. | 
 |   // TODO: Decide if it needs to compare with the FSM in {StPad, StPad01} or not | 
 |   logic end_of_block; | 
 |  | 
 |   assign end_of_block = ((sent_message + 1'b1) == block_addr_limit) ? 1'b 1 : 1'b 0; | 
 |  | 
 |  | 
 |   // Next logic and output logic ============================================== | 
 |   logic absorbed_d; | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) absorbed_o <= 1'b 0; | 
 |     else         absorbed_o <= absorbed_d; | 
 |   end | 
 |  | 
 |   always_comb begin | 
 |     st_d = StPadIdle; | 
 |  | 
 |     // FSM output : default values | 
 |     keccak_run_o = 1'b 0; | 
 |     sel_mux      = MuxNone; | 
 |  | 
 |     fsm_keccak_valid = 1'b 0; | 
 |  | 
 |     hold_msg = 1'b 0; | 
 |     clr_sentmsg = 1'b 0; | 
 |  | 
 |     en_msgbuf = 1'b 0; | 
 |     clr_msgbuf = 1'b 0; | 
 |  | 
 |     absorbed_d = 1'b 0; | 
 |  | 
 |     unique case (st) | 
 |  | 
 |       // In Idle state, the FSM checks if the software (or upper FSM) initiates | 
 |       // the hash process. If `start_i` is asserted (assume it is pulse), FSM | 
 |       // starts to push the data into the keccak round logic. Depending on the | 
 |       // hashing mode, FSM may push additional prefex in front of the actual | 
 |       // message. It means, the message could be back-pressured until the first | 
 |       // prefix is processed. | 
 |       StPadIdle: begin | 
 |         if (start_i) begin | 
 |           // If cSHAKE, move to Prefix state | 
 |           // TODO: Reset sent_message to count on next states | 
 |           if (mode_eq_cshake) begin | 
 |             st_d = StPrefix; | 
 |           end else begin | 
 |             st_d = StMessage; | 
 |           end | 
 |         end else begin | 
 |           st_d = StPadIdle; | 
 |         end | 
 |       end | 
 |  | 
 |       // At Prefix state, FSM pushes | 
 |       // `bytepad(encode_string(N)||encode_string(S), 168or136)`. The software | 
 |       // already prepared `encode_string(N) || encode_string(S)` in the regs. | 
 |       // So, the FSM adds 2Byte in front of ns_data_i, which is an encoded | 
 |       // block size (see `encoded_bytepad` below) | 
 |       // After pushing the prefix, it initiates the hash process and move to | 
 |       // Message state. | 
 |       StPrefix: begin | 
 |         sel_mux = MuxPrefix; | 
 |  | 
 |         if (sent_blocksize) begin | 
 |           st_d = StPrefixWait; | 
 |  | 
 |           // TODO: Set keccak to run, drop the keccak valid | 
 |           keccak_run_o = 1'b 1; | 
 |           fsm_keccak_valid = 1'b 0; | 
 |           clr_sentmsg = 1'b 1; | 
 |         end else begin | 
 |           st_d = StPrefix; | 
 |  | 
 |           fsm_keccak_valid = 1'b 1; | 
 |         end | 
 |       end | 
 |  | 
 |       StPrefixWait: begin | 
 |         sel_mux = MuxPrefix; | 
 |  | 
 |         if (keccak_complete_i) begin | 
 |           st_d = StMessage; | 
 |         end else begin | 
 |           st_d = StPrefixWait; | 
 |         end | 
 |       end | 
 |  | 
 |       // Message state pushes the incoming message into keccak round logic. | 
 |       // It forwards the message while counting the data and if it reaches | 
 |       // the block size, it triggers the keccak round to run. If `process` is | 
 |       // set, it moves to Pad state. | 
 |       StMessage: begin | 
 |         sel_mux = MuxFifo; | 
 |  | 
 |         if (msg_valid_i && msg_partial) begin | 
 |           st_d = StMessage; | 
 |  | 
 |           en_msgbuf = 1'b 1; | 
 |         end else if (sent_blocksize) begin | 
 |           // Check block completion first even process is set. | 
 |           st_d = StMessageWait; | 
 |  | 
 |           keccak_run_o = 1'b 1; | 
 |           clr_sentmsg = 1'b 1; | 
 |           hold_msg = 1'b 1; | 
 |         end else if (process_latched) begin | 
 |           st_d = StPad; | 
 |         end else begin | 
 |           st_d = StMessage; | 
 |  | 
 |         end | 
 |       end | 
 |  | 
 |       StMessageWait: begin | 
 |         hold_msg = 1'b 1; | 
 |  | 
 |         if (keccak_complete_i) begin | 
 |           st_d = StMessage; | 
 |         end else begin | 
 |           st_d = StMessageWait; | 
 |         end | 
 |       end | 
 |  | 
 |       // Pad state just pushes the ending suffix. Depending on the mode, the | 
 |       // padding value is unique. SHA3 adds 2'b10, SHAKE adds 4'b1111, and | 
 |       // cSHAKE adds 2'b 00. Refer `function_pad`. The signal has one more bit | 
 |       // defined to accomodate first 1 bit of `pad10*1()` function. | 
 |       StPad: begin | 
 |         sel_mux = MuxFuncPad; | 
 |  | 
 |         fsm_keccak_valid = 1'b 1; | 
 |  | 
 |         if (keccak_ack && end_of_block) begin | 
 |           // If padding is the last block, don't have to move to StPad01, just | 
 |           // run Keccak and complete | 
 |           st_d = StPadRun; | 
 |  | 
 |           // always clear the latched msgbuf | 
 |           clr_msgbuf = 1'b 1; | 
 |           clr_sentmsg = 1'b 1; | 
 |         end else if (keccak_ack) begin | 
 |           st_d = StPad01; | 
 |           clr_msgbuf = 1'b 1; | 
 |         end else begin | 
 |           st_d = StPad; | 
 |         end | 
 |       end | 
 |  | 
 |       StPadRun: begin | 
 |         st_d = StPadFlush; | 
 |  | 
 |         keccak_run_o = 1'b 1; | 
 |         clr_sentmsg = 1'b 1; | 
 |       end | 
 |  | 
 |       // Pad01 pushes the end bit of pad10*1() function. As keccak accepts byte | 
 |       // size only, StPad always pushes partial (5bits). So at this state, it | 
 |       // pushes rest of 3bits. If the data pushed in StPad is the last byte of | 
 |       // the block, then Pad01 pushes to the same byte, if not, it first | 
 |       // zero-fill the block then pad 1 to the end. | 
 |       StPad01: begin | 
 |         sel_mux = MuxZeroEnd; | 
 |  | 
 |         // There's no chance StPad01 can be a start of the block. So can be | 
 |         // discard that the sent_blocksize is set at the beginning. | 
 |         if (sent_blocksize) begin | 
 |           st_d = StPadFlush; | 
 |  | 
 |           fsm_keccak_valid = 1'b 0; | 
 |           // TODO: Trigger keccak_round | 
 |           keccak_run_o = 1'b 1; | 
 |           clr_sentmsg = 1'b 1; | 
 |         end else begin | 
 |           st_d = StPad01; | 
 |  | 
 |           fsm_keccak_valid = 1'b 1; | 
 |         end | 
 |       end | 
 |  | 
 |       StPadFlush: begin | 
 |         // Wait completion from keccak_round or wait SW indicator. | 
 |         clr_sentmsg = 1'b 1; | 
 |         clr_msgbuf = 1'b 1; | 
 |  | 
 |         if (keccak_complete_i) begin | 
 |           st_d = StPadIdle; | 
 |  | 
 |           absorbed_d = 1'b 1; | 
 |           // TODO: Clear internal variables to fresh start | 
 |         end else begin | 
 |           st_d = StPadFlush; | 
 |         end | 
 |       end | 
 |  | 
 |       default: begin | 
 |         st_d = StPadIdle; | 
 |       end | 
 |  | 
 |     endcase | 
 |   end | 
 |  | 
 |   ////////////// | 
 |   // Datapath // | 
 |   ////////////// | 
 |  | 
 |   // `encode_bytepad` represents the first two bytes of bytepad() | 
 |   // It depends on the block size. We can reuse KeccakRate | 
 |   // 10000000 || 00010101 // 168 | 
 |   // 10000000 || 00010001 // 136 | 
 |   logic [15:0] encode_bytepad; | 
 |  | 
 |   assign encode_bytepad = encode_bytepad_len(strength_i); | 
 |  | 
 |   // Prefix size ============================================================== | 
 |   // Prefix represents bytepad(encode_string(N) || encode_string(S), 168 or 136) | 
 |   // encode_string(N) || encode_string(S) is prepared by the software and given | 
 |   // through `ns_data_i`. The first part of bytepad is determined by the | 
 |   // `strength_i` and stored into `encode_bytepad`. | 
 |  | 
 |   // It is assumed that the prefix always smaller than the block size. | 
 |   logic [PrefixSize*8-1:0] prefix; | 
 |  | 
 |   assign prefix = {ns_data_i, encode_bytepad}; | 
 |  | 
 |   logic [MsgWidth-1:0] prefix_sliced; | 
 |   logic [MsgWidth-1:0] prefix_data [Share]; | 
 |  | 
 |   prim_slicer #( | 
 |     .InW (PrefixSize*8), | 
 |     .IndexW(KeccakMsgAddrW), | 
 |     .OutW(MsgWidth) | 
 |   ) u_prefix_slicer ( | 
 |     .sel_i  (prefix_index), | 
 |     .data_i (prefix), | 
 |     .data_o (prefix_sliced) | 
 |   ); | 
 |  | 
 |   if (EnMasking) begin : gen_prefix_masked | 
 |     // If Masking is enabled, prefix is two share. | 
 |     assign prefix_data[0] = '0; | 
 |     assign prefix_data[1] = prefix_sliced; | 
 |   end else begin : gen_prefix_unmasked | 
 |     // If Unmasked, only one share exists. | 
 |     assign prefix_data[0] = prefix_sliced; | 
 |   end | 
 |  | 
 |   // ========================================================================== | 
 |   // function_pad is the unique value padded at the end of the message based on | 
 |   // the function among SHA3, SHAKE, cSHAKE. The standard mentioned that SHA3 | 
 |   // pads `01` , SHAKE pads `1111`, and cSHAKE pads `00`. | 
 |   // | 
 |   // Then pad10*1() function follows. It adds `1` first then fill 0 until it | 
 |   // reaches the block size -1, then adds `1`. | 
 |   // | 
 |   // It means always `1` is followed by the function pad. | 
 |   logic [4:0] funcpad; | 
 |  | 
 |   logic [MsgWidth-1:0] funcpad_data [Share]; | 
 |  | 
 |   always_comb begin | 
 |     unique case (mode_i) | 
 |       Sha3:   funcpad = 5'b 00110; | 
 |       Shake:  funcpad = 5'b 11111; | 
 |       CShake: funcpad = 5'b 00100; | 
 |  | 
 |       default: begin | 
 |         // Just create non-padding but pad10*1 only | 
 |         funcpad = 5'b 00001; | 
 |       end | 
 |     endcase | 
 |   end | 
 |  | 
 |   // ========================================================================== | 
 |   // `zero_with_endbit` contains all zero unless the message is for the last | 
 |   // MsgWidth beat in the block. If it is the end of the block, the last bit | 
 |   // will be set to complete pad10*1() functionality. | 
 |   logic [MsgWidth-1:0] zero_with_endbit [Share]; | 
 |  | 
 |   if (EnMasking) begin : gen_zeroend_masked | 
 |     assign zero_with_endbit[0]               = '0; | 
 |     assign zero_with_endbit[1][MsgWidth-1]   = end_of_block; | 
 |     assign zero_with_endbit[1][MsgWidth-2:0] = '0; | 
 |   end else begin : gen_zeroend_unmasked | 
 |     assign zero_with_endbit[0][MsgWidth-1]   = end_of_block; | 
 |     assign zero_with_endbit[0][MsgWidth-2:0] = '0; | 
 |   end | 
 |  | 
 |   // ========================================================================== | 
 |   // Data mux for output data | 
 |  | 
 |   assign keccak_addr_o = (sent_message < block_addr_limit) ? sent_message : '0; | 
 |  | 
 |   always_comb begin | 
 |     unique case (sel_mux) | 
 |       MuxFifo:    keccak_data_o = msg_data_i; | 
 |       MuxPrefix:  keccak_data_o = prefix_data; | 
 |       MuxFuncPad: keccak_data_o = funcpad_data; | 
 |       MuxZeroEnd: keccak_data_o = zero_with_endbit; | 
 |  | 
 |       // MuxNone | 
 |       default:  keccak_data_o = '{default:'0}; | 
 |     endcase | 
 |   end | 
 |  | 
 |   // TODO: keccak_valid_o mux | 
 |   always_comb begin | 
 |     unique case (sel_mux) | 
 |       MuxFifo:    keccak_valid_o = msg_valid_i & ~hold_msg & ~en_msgbuf; | 
 |       MuxPrefix:  keccak_valid_o = fsm_keccak_valid; | 
 |       MuxFuncPad: keccak_valid_o = fsm_keccak_valid; | 
 |       MuxZeroEnd: keccak_valid_o = fsm_keccak_valid; | 
 |  | 
 |       // MuxNone | 
 |       default:  keccak_valid_o = 1'b 0; | 
 |     endcase | 
 |   end | 
 |  | 
 |   // TODO: msg_ready_o mux | 
 |   always_comb begin | 
 |     unique case (sel_mux) | 
 |       MuxFifo:    msg_ready_o = en_msgbuf | (keccak_ready_i & ~hold_msg); | 
 |       MuxPrefix:  msg_ready_o = 1'b 0; | 
 |       MuxFuncPad: msg_ready_o = 1'b 0; | 
 |       MuxZeroEnd: msg_ready_o = 1'b 0; | 
 |  | 
 |       // MuxNone | 
 |       default: msg_ready_o = 1'b 0; | 
 |     endcase | 
 |   end | 
 |  | 
 |   // prim_packer : packing to 64bit to update keccak storage | 
 |   // two prim_packer in this module are used to pack the data received from | 
 |   // upper layer (KMAC core) and also the 5bit padding bits. | 
 |   // It is assumed that the message from upper layer could be partial at the | 
 |   // end of the message. Then the 2 or 4bit padding is required. It can be | 
 |   // handled by some custom logic or could be done by prim_packer. | 
 |   // If packer is used, the MSG_FIFO doesn't have to have another prim_packer | 
 |   // in front of the FIFO. This logic can handle the partial writes from the | 
 |   // software. | 
 |   // | 
 |   // If a custom logic is implemented here, prim_packer is necessary in front | 
 |   // of the FIFO, as this logic only appends at the end of the message when | 
 |   // `process_i` is asserted. Also, in this case, even prim_packer is not | 
 |   // needed, still 64bit registers to latch the partial write is required. | 
 |   // If not, the logic has to delay the acceptance of the incoming write | 
 |   // accesses. It may trigger the back-pressuring in some case which may result | 
 |   // that the software(or upper layer) may not set process_i. | 
 |   // | 
 |   // For custom logic, it could be implemented by the 8 mux selection. | 
 |   // for instance: (subject to be changed) | 
 |   //   unique case (sent_byte[2:0]) // generated from msg_strb_i | 
 |   //     3'b 000: funcpad_merged = {end_of_block, 63'(function_pad)                  }; | 
 |   //     3'b 001: funcpad_merged = {end_of_block, 55'(function_pad), msg_data_i[ 7:0]}; | 
 |   //     3'b 010: funcpad_merged = {end_of_block, 47'(function_pad), msg_data_i[15:0]}; | 
 |   //     3'b 011: funcpad_merged = {end_of_block, 39'(function_pad), msg_data_i[23:0]}; | 
 |   //     3'b 100: funcpad_merged = {end_of_block, 31'(function_pad), msg_data_i[31:0]}; | 
 |   //     3'b 101: funcpad_merged = {end_of_block, 23'(function_pad), msg_data_i[39:0]}; | 
 |   //     3'b 110: funcpad_merged = {end_of_block, 15'(function_pad), msg_data_i[47:0]}; | 
 |   //     3'b 111: funcpad_merged = {end_of_block,  7'(function_pad), msg_data_i[55:0]}; | 
 |   //     default: funcpad_merged = '0; | 
 |   //   endcase | 
 |  | 
 |   // internal buffer to store partial write. It doesn't have to store last byte as it | 
 |   // stores only when partial write. | 
 |   logic [MsgWidth-8-1:0] msg_buf [Share]; | 
 |   logic [MsgStrbW-1-1:0] msg_strb; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       msg_buf  <= '{default:'0}; | 
 |       msg_strb <= '0; | 
 |     end else if (en_msgbuf) begin | 
 |       for (int i = 0 ; i < Share ; i++) begin | 
 |         msg_buf[i]  <= msg_data_i[i][0+:(MsgWidth-8)]; | 
 |       end | 
 |       msg_strb <= msg_strb_i[0+:(MsgStrbW-1)]; | 
 |     end else if (clr_msgbuf) begin | 
 |       msg_buf  <= '{default:'0}; | 
 |       msg_strb <= '0; | 
 |     end | 
 |   end | 
 |  | 
 |   if (EnMasking) begin : gen_funcpad_data_masked | 
 |     always_comb begin | 
 |       unique case (msg_strb) | 
 |         7'b 000_0000: begin | 
 |           funcpad_data[0] = '0; | 
 |           funcpad_data[1] = {end_of_block, 63'(funcpad)                  }; | 
 |         end | 
 |         7'b 000_0001: begin | 
 |           funcpad_data[0] = {56'h0,                      msg_buf[0][ 7:0]}; | 
 |           funcpad_data[1] = {end_of_block, 55'(funcpad), msg_buf[1][ 7:0]}; | 
 |         end | 
 |         7'b 000_0011: begin | 
 |           funcpad_data[0] = {48'h0,                      msg_buf[0][15:0]}; | 
 |           funcpad_data[1] = {end_of_block, 47'(funcpad), msg_buf[1][15:0]}; | 
 |         end | 
 |         7'b 000_0111: begin | 
 |           funcpad_data[0] = {40'h0,                      msg_buf[0][23:0]}; | 
 |           funcpad_data[1] = {end_of_block, 39'(funcpad), msg_buf[1][23:0]}; | 
 |         end | 
 |         7'b 000_1111: begin | 
 |           funcpad_data[0] = {32'h0,                      msg_buf[0][31:0]}; | 
 |           funcpad_data[1] = {end_of_block, 31'(funcpad), msg_buf[1][31:0]}; | 
 |         end | 
 |         7'b 001_1111: begin | 
 |           funcpad_data[0] = {24'h0,                      msg_buf[0][39:0]}; | 
 |           funcpad_data[1] = {end_of_block, 23'(funcpad), msg_buf[1][39:0]}; | 
 |         end | 
 |         7'b 011_1111: begin | 
 |           funcpad_data[0] = {16'h0,                      msg_buf[0][47:0]}; | 
 |           funcpad_data[1] = {end_of_block, 15'(funcpad), msg_buf[1][47:0]}; | 
 |         end | 
 |         7'b 111_1111: begin | 
 |           funcpad_data[0] = { 8'h0,                      msg_buf[0][55:0]}; | 
 |           funcpad_data[1] = {end_of_block,  7'(funcpad), msg_buf[1][55:0]}; | 
 |         end | 
 |  | 
 |         default: funcpad_data = '{default:'0}; | 
 |       endcase | 
 |     end | 
 |   end else begin : gen_funcpad_data_unmasked | 
 |     always_comb begin | 
 |       unique case (msg_strb) | 
 |         7'b 000_0000: funcpad_data[0] = {end_of_block, 63'(funcpad)                  }; | 
 |         7'b 000_0001: funcpad_data[0] = {end_of_block, 55'(funcpad), msg_buf[0][ 7:0]}; | 
 |         7'b 000_0011: funcpad_data[0] = {end_of_block, 47'(funcpad), msg_buf[0][15:0]}; | 
 |         7'b 000_0111: funcpad_data[0] = {end_of_block, 39'(funcpad), msg_buf[0][23:0]}; | 
 |         7'b 000_1111: funcpad_data[0] = {end_of_block, 31'(funcpad), msg_buf[0][31:0]}; | 
 |         7'b 001_1111: funcpad_data[0] = {end_of_block, 23'(funcpad), msg_buf[0][39:0]}; | 
 |         7'b 011_1111: funcpad_data[0] = {end_of_block, 15'(funcpad), msg_buf[0][47:0]}; | 
 |         7'b 111_1111: funcpad_data[0] = {end_of_block,  7'(funcpad), msg_buf[0][55:0]}; | 
 |  | 
 |         default: funcpad_data = '{default:'0}; | 
 |       endcase | 
 |     end | 
 |   end | 
 |  | 
 |   //////////////// | 
 |   // Assertions // | 
 |   //////////////// | 
 |  | 
 |   // Prefix size is smaller than the smallest Keccak Block Size, which is 72 bytes. | 
 |   `ASSERT_INIT(PrefixLessThanBlock_A, PrefixSize/8 < KeccakRate[4]) | 
 |  | 
 |   // Some part of datapath in sha3pad assumes Data width as 64bit. | 
 |   // If data width need to be changed, funcpad_data part should be changed too. | 
 |   // Also, The blocksize shall be divided by MsgWidth, which means, MsgWidth | 
 |   // can be {16, 32, 64} even funcpad_data mux is fully flexible. | 
 |   `ASSERT_INIT(MsgWidthidth_A, MsgWidth == 64) | 
 |  | 
 |   // Assume pulse signals: start, process, done | 
 |   `ASSUME(StartPulse_A, start_i |=> !start_i) | 
 |   `ASSUME(ProcessPulse_A, process_i |=> !process_i) | 
 |   `ASSUME(DonePulse_A, done_i |=> !done_i) | 
 |  | 
 |   // ASSERT output pulse signals: absorbed_o, keccak_run_o | 
 |   `ASSERT(AbsorbedPulse_A, absorbed_o |=> !absorbed_o) | 
 |   `ASSERT(KeccakRunPulse_A, keccak_run_o |=> !keccak_run_o) | 
 |  | 
 |   // start_i, done_i, process_i cannot set high at the same time | 
 |   `ASSUME(StartProcessDoneMutex_a, $onehot0({start_i, process_i, done_i})) | 
 |  | 
 |   // Sequence, start_i --> process_i --> absorbed_o --> done_i | 
 |   //`ASSUME(Sequence_a, start_i ##[1:$] process_i ##[1:$] ##[1:$] absorbed_o ##[1:$] done_i) | 
 |  | 
 | `ifndef SYNTHESIS | 
 |   // Process only asserts after start and all message are fed. | 
 |   // These valid signals are qualifier of FPV to trigger the control signal | 
 |   // It is a little bit hard to specify these criteria in SVA property so creating | 
 |   // qualifiers in RTL form is easier. | 
 |   logic start_valid, process_valid, absorb_valid, done_valid; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       start_valid <= 1'b 1; | 
 |     end else if (start_i) begin | 
 |       start_valid <= 1'b 0; | 
 |     end else if (done_i) begin | 
 |       start_valid <= 1'b 1; | 
 |     end | 
 |   end | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       process_valid <= 1'b 0; | 
 |     end else if (start_i) begin | 
 |       process_valid <= 1'b 1; | 
 |     end else if (process_i) begin | 
 |       process_valid <= 1'b 0; | 
 |     end | 
 |   end | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       done_valid <= 1'b 0; | 
 |     end else if (absorbed_o) begin | 
 |       done_valid <= 1'b 1; | 
 |     end else if (done_i) begin | 
 |       done_valid <= 1'b 0; | 
 |     end | 
 |   end | 
 |  | 
 |   // Message can be fed in between start_i and process_i. | 
 |   `ASSUME(MessageCondition_M, msg_valid_i && msg_ready_o |-> process_valid && !process_i) | 
 |  | 
 |   `ASSUME(ProcessCondition_M, process_i |-> process_valid) | 
 |   `ASSUME(StartCondition_M, start_i |-> start_valid) | 
 |   `ASSUME(DoneCondition_M, done_i |-> done_valid) | 
 |  | 
 |   // Assume mode_i and strength_i are stable during the operation | 
 |   // This will be guarded at the kmac top level | 
 |   `ASSUME(ModeStableDuringOp_M, | 
 |     $changed(mode_i) |-> start_valid) | 
 |   `ASSUME(StrengthStableDuringOp_M, | 
 |     $changed(strength_i) |-> start_valid) | 
 |  | 
 | `endif // SYNTHESIS | 
 |  | 
 |   // If not full block is written, the pad shall send message to keccak_round | 
 |   // If it is end of the message, the state moves to StPad and send the request | 
 |   `ASSERT(CompleteBlockWhenProcess_A, | 
 |     $rose(process_latched) && (!end_of_block && !sent_blocksize ) | 
 |     && !(st inside {StPrefixWait, StMessageWait}) |-> ##[1:5] keccak_valid_o) | 
 |   // If `process_i` is asserted, eventually sha3pad trigger run signal | 
 |   `ASSERT(ProcessToRun_A, process_i |-> strong(##[2:$] keccak_run_o)) | 
 |  | 
 |   // If process_i asserted, completion shall be asserted shall be asserted | 
 |   //`ASSERT(ProcessToAbsorbed_A, process_i |=> strong(##[24*Share:$] absorbed_o)) | 
 |  | 
 |  | 
 |   // Assumption of input mode_i and strength_i | 
 |   // SHA3 variants: SHA3-224, SHA3-256, SHA3-384, SHA3-512 | 
 |   // SHAKE, cSHAKE variants: SHAKE128, SHAKE256, cSHAKE128, cSHAKE256 | 
 |   `ASSUME(ModeStrengthCombinations_M, | 
 |     start_i |-> | 
 |       (mode_i == Sha3 && (strength_i inside {L224, L256, L384, L512})) || | 
 |       ((mode_i == Shake || mode_i == CShake) && (strength_i inside {L128, L256})), | 
 |     clk_i, !rst_ni) | 
 |  | 
 |   // Keccak control interface | 
 |   // Keccak run triggered -> completion should come | 
 |   `ASSUME(RunThenComplete_M, | 
 |     keccak_run_o |-> strong(##[24*Share:$] keccak_complete_i)) | 
 |  | 
 |   // No partial write is allowed for Message FIFO interface | 
 |   `ASSUME(NoPartialMsgFifo_M, | 
 |     keccak_valid_o && (sel_mux == MuxFifo) |-> (&msg_strb_i) == 1'b1, | 
 |     clk_i, !rst_ni) | 
 |  | 
 |   // When transaction is stored into msg_buf, it shall be partial write. | 
 |   `ASSUME(AlwaysPartialMsgBuf_M, | 
 |     en_msgbuf |-> msg_valid_i && (msg_strb_i[MsgStrbW-1] == 1'b0), | 
 |     clk_i, !rst_ni) | 
 |  | 
 |   // if partial write comes and is acked, then no more msg_valid_i until | 
 |   // next message | 
 |   `ASSUME(PartialEndOfMsg_M, | 
 |     msg_valid_i && msg_ready_o && msg_partial |=> | 
 |       !msg_valid_i ##[1:$] $stable(msg_valid_i) ##1 process_latched, | 
 |     clk_i, !rst_ni) | 
 |  | 
 |   // At the first clock in StPad01 state, sent_blocksize shall not be set | 
 |   `ASSERT(Pad01NotAttheEndOfBlock_A, | 
 |     (st == StPad && st_d == StPad01) |-> !end_of_block, | 
 |     clk_i, !rst_ni) | 
 |  | 
 |   // When data sent to the keccak_round, the address should be in the range | 
 |   `ASSERT(KeccakAddrInRange_A, | 
 |     keccak_valid_o |-> keccak_addr_o < KeccakRate[strength_i], | 
 |     clk_i, !rst_ni) | 
 |  | 
 |   // NS data shall be stable during the operation. | 
 |   //`ASSUME(NsStableInProcess_A, | 
 |   //  $stable(ns_data_i) throughout(start_i ##[1:$] process_i ##[1:$] absorbed_o), | 
 |   //  clk_i, !rst_ni) | 
 |  | 
 |   // Functional Coverage | 
 |   `COVER(StMessageFeed_C, st == StMessage) | 
 |   `COVER(StPad_C, st == StPad01 && sent_blocksize) | 
 |   `COVER(StPadSendMsg_C, st == StPad01 && keccak_ack) | 
 |   `COVER(StComplete_C, st == StPadFlush) | 
 | endmodule | 
 |  |