|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // SHA-256 Padding logic | 
|  | // | 
|  |  | 
|  | module sha2_pad import hmac_pkg::*; ( | 
|  | input clk_i, | 
|  | input rst_ni, | 
|  |  | 
|  | input            wipe_secret, | 
|  | input sha_word_t wipe_v, | 
|  |  | 
|  | // To actual FIFO | 
|  | input                 fifo_rvalid, | 
|  | input  sha_fifo_t     fifo_rdata, | 
|  | output logic          fifo_rready, | 
|  |  | 
|  | // from SHA2 compress engine | 
|  | output logic          shaf_rvalid, | 
|  | output sha_word_t     shaf_rdata, | 
|  | input                 shaf_rready, | 
|  |  | 
|  | input sha_en, | 
|  | input hash_start, | 
|  | input hash_process, | 
|  | input hash_done, | 
|  |  | 
|  | input        [63:0] message_length, // # of bytes in bits (8 bits granularity) | 
|  | output logic        msg_feed_complete // Indicates, all message is feeded | 
|  | ); | 
|  |  | 
|  | //logic [8:0] length_added; | 
|  |  | 
|  | logic [63:0] tx_count;    // fin received data count. | 
|  |  | 
|  | logic inc_txcount; | 
|  | logic fifo_partial; | 
|  | logic txcnt_eq_1a0; | 
|  | logic hash_process_flag; // Set by hash_process, clear by hash_done | 
|  |  | 
|  | assign fifo_partial = ~&fifo_rdata.mask; | 
|  |  | 
|  | // tx_count[8:0] == 'h1c0 --> should send LenHi | 
|  | assign txcnt_eq_1a0 = (tx_count[8:0] == 9'h1a0); | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) begin | 
|  | hash_process_flag <= 1'b0; | 
|  | end else if (hash_process) begin | 
|  | hash_process_flag <= 1'b1; | 
|  | end else if (hash_done || hash_start) begin | 
|  | hash_process_flag <= 1'b0; | 
|  | end | 
|  | end | 
|  |  | 
|  | // Data path: fout_wdata | 
|  | typedef enum logic [2:0] { | 
|  | FifoIn,         // fin_wdata, fin_wstrb | 
|  | Pad80,          // {8'h80, 8'h00} , strb (calc based on len[4:3]) | 
|  | Pad00,          // 32'h0, full strb | 
|  | LenHi,          // len[63:32], full strb | 
|  | LenLo           // len[31:0], full strb | 
|  | } sel_data_e; | 
|  | sel_data_e sel_data; | 
|  |  | 
|  | always_comb begin | 
|  | unique case (sel_data) | 
|  | FifoIn: begin | 
|  | shaf_rdata = fifo_rdata.data; | 
|  | end | 
|  |  | 
|  | Pad80: begin | 
|  | // {a[7:0], b[7:0], c[7:0], d[7:0]} | 
|  | // msglen[4:3] == 00 |-> {'h80, 'h00, 'h00, 'h00} | 
|  | // msglen[4:3] == 01 |-> {msg,  'h80, 'h00, 'h00} | 
|  | // msglen[4:3] == 10 |-> {msg[15:0],  'h80, 'h00} | 
|  | // msglen[4:3] == 11 |-> {msg[23:0],        'h80} | 
|  | unique case (message_length[4:3]) | 
|  | 2'b 00: shaf_rdata = 32'h 8000_0000; | 
|  | 2'b 01: shaf_rdata = {fifo_rdata.data[31:24], 24'h 8000_00}; | 
|  | 2'b 10: shaf_rdata = {fifo_rdata.data[31:16], 16'h 8000}; | 
|  | 2'b 11: shaf_rdata = {fifo_rdata.data[31: 8],  8'h 80}; | 
|  | default: shaf_rdata = 32'h0; | 
|  | endcase | 
|  | end | 
|  |  | 
|  | Pad00: begin | 
|  | shaf_rdata = '0; | 
|  | end | 
|  |  | 
|  | LenHi: begin | 
|  | shaf_rdata = message_length[63:32]; | 
|  | end | 
|  |  | 
|  | LenLo: begin | 
|  | shaf_rdata = message_length[31:0]; | 
|  | end | 
|  |  | 
|  | default: begin | 
|  | shaf_rdata = '0; | 
|  | end | 
|  | endcase | 
|  | end | 
|  |  | 
|  | // Padded length | 
|  | // $ceil(message_length + 8 + 64, 512) -> message_length [8:0] + 440 and ignore carry | 
|  | //assign length_added = (message_length[8:0] + 9'h1b8) ; | 
|  |  | 
|  | // fifo control | 
|  | // add 8'h 80 , N 8'h00, 64'h message_length | 
|  |  | 
|  | // Steps | 
|  | // 1. `hash_start` from CPU (or DMA?) | 
|  | // 2. calculate `padded_length` from `message_length` | 
|  | // 3. Check if tx_count == message_length, then go to 5 | 
|  | // 4. Receiving FIFO input (hand over to fifo output) | 
|  | // 5. Padding bit 1 (8'h80) followed by 8'h00 if needed | 
|  | // 6. Padding with length (high -> low) | 
|  |  | 
|  | // State Machine | 
|  | typedef enum logic [2:0] { | 
|  | StIdle,        // fin_full to prevent unwanted FIFO write | 
|  | StFifoReceive, // Check tx_count == message_length | 
|  | StPad80,       // 8'h 80 + 8'h 00 X N | 
|  | StPad00, | 
|  | StLenHi, | 
|  | StLenLo | 
|  | } pad_st_e; | 
|  |  | 
|  | pad_st_e st_q, st_d; | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) begin | 
|  | st_q <= StIdle; | 
|  | end else begin | 
|  | st_q <= st_d; | 
|  | end | 
|  | end | 
|  |  | 
|  | // Next state | 
|  | always_comb begin | 
|  | shaf_rvalid = 1'b0; | 
|  | inc_txcount = 1'b0; | 
|  | sel_data = FifoIn; | 
|  | fifo_rready = 1'b0; | 
|  |  | 
|  | st_d = StIdle; | 
|  |  | 
|  | unique case (st_q) | 
|  | StIdle: begin | 
|  | sel_data = FifoIn; | 
|  | shaf_rvalid = 1'b0; | 
|  |  | 
|  | if (sha_en && hash_start) begin | 
|  | inc_txcount = 1'b0; | 
|  |  | 
|  | st_d = StFifoReceive; | 
|  | end else begin | 
|  | st_d = StIdle; | 
|  | end | 
|  | end | 
|  |  | 
|  | StFifoReceive: begin | 
|  | sel_data = FifoIn; | 
|  |  | 
|  | if (fifo_partial && fifo_rvalid) begin | 
|  | // End of the message, assume hash_process_flag is set | 
|  | shaf_rvalid  = 1'b0; // Update entry at StPad80 | 
|  | inc_txcount = 1'b0; | 
|  | fifo_rready = 1'b0; | 
|  |  | 
|  | st_d = StPad80; | 
|  | end else if (!hash_process_flag) begin | 
|  | fifo_rready = shaf_rready; | 
|  | shaf_rvalid  = fifo_rvalid; | 
|  | inc_txcount = shaf_rready; | 
|  |  | 
|  | st_d = StFifoReceive; | 
|  | end else if (tx_count == message_length) begin | 
|  | // already received all msg and was waiting process flag | 
|  | shaf_rvalid  = 1'b0; | 
|  | inc_txcount = 1'b0; | 
|  | fifo_rready = 1'b0; | 
|  |  | 
|  | st_d = StPad80; | 
|  | end else begin | 
|  | shaf_rvalid  = fifo_rvalid; | 
|  | fifo_rready = shaf_rready; // 0 always | 
|  | inc_txcount = shaf_rready; // 0 always | 
|  |  | 
|  | st_d = StFifoReceive; | 
|  | end | 
|  | end | 
|  |  | 
|  | StPad80: begin | 
|  | sel_data = Pad80; | 
|  |  | 
|  | shaf_rvalid = 1'b1; | 
|  | fifo_rready = shaf_rready && |message_length[4:3]; // Only when partial | 
|  |  | 
|  | // exactly 96 bits left, do not need to pad00's | 
|  | if (shaf_rready && txcnt_eq_1a0) begin | 
|  | st_d = StLenHi; | 
|  | inc_txcount = 1'b1; | 
|  | // it does not matter if value is < or > than 416 bits.  If it's the former, 00 pad until | 
|  | // length field.  If >, then the next chunk will contain the length field with appropriate | 
|  | // 0 padding. | 
|  | end else if (shaf_rready && !txcnt_eq_1a0) begin | 
|  | st_d = StPad00; | 
|  | inc_txcount = 1'b1; | 
|  | end else begin | 
|  | st_d = StPad80; | 
|  | inc_txcount = 1'b0; | 
|  | end | 
|  |  | 
|  | // # Below part is temporal code to speed up the SHA by 16 clocks per chunk | 
|  | // # (80 clk --> 64 clk) | 
|  | // # leaving this as a reference but needs to verify it. | 
|  | //if (shaf_rready && !txcnt_eq_1a0) begin | 
|  | //  st_d = StPad00; | 
|  | // | 
|  | //  inc_txcount = 1'b1; | 
|  | //  shaf_rvalid = (msg_word_aligned) ? 1'b1 : fifo_rvalid; | 
|  | //  fifo_rready = (msg_word_aligned) ? 1'b0 : 1'b1; | 
|  | //end else if (!shaf_rready && !txcnt_eq_1a0) begin | 
|  | //  st_d = StPad80; | 
|  | // | 
|  | //  inc_txcount = 1'b0; | 
|  | //  shaf_rvalid = (msg_word_aligned) ? 1'b1 : fifo_rvalid; | 
|  | // | 
|  | //end else if (shaf_rready && txcnt_eq_1a0) begin | 
|  | //  st_d = StLenHi; | 
|  | //  inc_txcount = 1'b1; | 
|  | //end else begin | 
|  | //  // !shaf_rready && txcnt_eq_1a0 , just wait until fifo_rready asserted | 
|  | //  st_d = StPad80; | 
|  | //  inc_txcount = 1'b0; | 
|  | //end | 
|  | end | 
|  |  | 
|  | StPad00: begin | 
|  | sel_data = Pad00; | 
|  | shaf_rvalid = 1'b1; | 
|  |  | 
|  | if (shaf_rready) begin | 
|  | inc_txcount = 1'b1; | 
|  |  | 
|  | if (txcnt_eq_1a0) begin | 
|  | st_d = StLenHi; | 
|  | end else begin | 
|  | st_d = StPad00; | 
|  | end | 
|  | end else begin | 
|  | st_d = StPad00; | 
|  | end | 
|  | end | 
|  |  | 
|  | StLenHi: begin | 
|  | sel_data = LenHi; | 
|  | shaf_rvalid = 1'b1; | 
|  |  | 
|  | if (shaf_rready) begin | 
|  | st_d = StLenLo; | 
|  |  | 
|  | inc_txcount = 1'b1; | 
|  | end else begin | 
|  | st_d = StLenHi; | 
|  |  | 
|  | inc_txcount = 1'b0; | 
|  | end | 
|  | end | 
|  |  | 
|  | StLenLo: begin | 
|  | sel_data = LenLo; | 
|  | shaf_rvalid = 1'b1; | 
|  |  | 
|  | if (shaf_rready) begin | 
|  | st_d = StIdle; | 
|  |  | 
|  | inc_txcount = 1'b1; | 
|  | end else begin | 
|  | st_d = StLenLo; | 
|  |  | 
|  | inc_txcount = 1'b0; | 
|  | end | 
|  | end | 
|  |  | 
|  | default: begin | 
|  | st_d = StIdle; | 
|  | end | 
|  | endcase | 
|  | end | 
|  |  | 
|  | // tx_count | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) begin | 
|  | tx_count <= '0; | 
|  | end else if (hash_start) begin | 
|  | tx_count <= '0; | 
|  | end else if (inc_txcount) begin | 
|  | tx_count[63:5] <= tx_count[63:5] + 1'b1; | 
|  | end | 
|  | end | 
|  |  | 
|  | // State machine is in Idle only when it meets tx_count == message length | 
|  | assign msg_feed_complete = hash_process_flag && (st_q == StIdle); | 
|  |  | 
|  | // When fifo_partial, fifo shouldn't be empty and hash_process was set | 
|  | `ASSERT(ValidPartialConditionAssert, | 
|  | fifo_partial && fifo_rvalid |-> hash_process_flag, | 
|  | clk_i, !rst_ni) | 
|  |  | 
|  | endmodule |