|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // AES main control | 
|  | // | 
|  | // This module controls the interplay of input/output registers and the AES cipher core. | 
|  |  | 
|  | `include "prim_assert.sv" | 
|  |  | 
|  | module aes_control | 
|  | import aes_pkg::*; | 
|  | import aes_reg_pkg::*; | 
|  | #( | 
|  | parameter int unsigned SecStartTriggerDelay = 0 | 
|  | ) ( | 
|  | input  logic                      clk_i, | 
|  | input  logic                      rst_ni, | 
|  |  | 
|  | // Main control signals | 
|  | input  logic                      ctrl_qe_i, | 
|  | output logic                      ctrl_we_o, | 
|  | input  logic                      ctrl_err_storage_i, | 
|  | input  aes_op_e                   op_i, | 
|  | input  aes_mode_e                 mode_i, | 
|  | input  ciph_op_e                  cipher_op_i, | 
|  | input  logic                      sideload_i, | 
|  | input  logic                      manual_operation_i, | 
|  | input  logic                      start_i, | 
|  | input  logic                      key_iv_data_in_clear_i, | 
|  | input  logic                      data_out_clear_i, | 
|  | input  logic                      prng_reseed_i, | 
|  | input  logic                      mux_sel_err_i, | 
|  | input  logic                      sp_enc_err_i, | 
|  | input  lc_ctrl_pkg::lc_tx_t       lc_escalate_en_i, | 
|  | input  logic                      alert_fatal_i, | 
|  | output logic                      alert_o, | 
|  |  | 
|  | // I/O register read/write enables | 
|  | input  logic                      key_sideload_valid_i, | 
|  | input  logic     [NumRegsKey-1:0] key_init_qe_i [NumSharesKey], | 
|  | input  logic      [NumRegsIv-1:0] iv_qe_i, | 
|  | input  logic    [NumRegsData-1:0] data_in_qe_i, | 
|  | input  logic    [NumRegsData-1:0] data_out_re_i, | 
|  | output logic                      data_in_we_o, | 
|  | output sp2v_e                     data_out_we_o, | 
|  |  | 
|  | // Previous input data register | 
|  | output dip_sel_e                  data_in_prev_sel_o, | 
|  | output sp2v_e                     data_in_prev_we_o, | 
|  |  | 
|  | // Cipher I/O muxes | 
|  | output si_sel_e                   state_in_sel_o, | 
|  | output add_si_sel_e               add_state_in_sel_o, | 
|  | output add_so_sel_e               add_state_out_sel_o, | 
|  |  | 
|  | // Counter | 
|  | output sp2v_e                     ctr_incr_o, | 
|  | input  sp2v_e                     ctr_ready_i, | 
|  | input  sp2v_e  [NumSlicesCtr-1:0] ctr_we_i, | 
|  |  | 
|  | // Cipher core control and sync | 
|  | output sp2v_e                     cipher_in_valid_o, | 
|  | input  sp2v_e                     cipher_in_ready_i, | 
|  | input  sp2v_e                     cipher_out_valid_i, | 
|  | output sp2v_e                     cipher_out_ready_o, | 
|  | output sp2v_e                     cipher_crypt_o, | 
|  | input  sp2v_e                     cipher_crypt_i, | 
|  | output sp2v_e                     cipher_dec_key_gen_o, | 
|  | input  sp2v_e                     cipher_dec_key_gen_i, | 
|  | output logic                      cipher_key_clear_o, | 
|  | input  logic                      cipher_key_clear_i, | 
|  | output logic                      cipher_data_out_clear_o, | 
|  | input  logic                      cipher_data_out_clear_i, | 
|  |  | 
|  | // Initial key registers | 
|  | output key_init_sel_e             key_init_sel_o, | 
|  | output sp2v_e    [NumRegsKey-1:0] key_init_we_o [NumSharesKey], | 
|  |  | 
|  | // IV registers | 
|  | output iv_sel_e                   iv_sel_o, | 
|  | output sp2v_e  [NumSlicesCtr-1:0] iv_we_o, | 
|  |  | 
|  | // Pseudo-random number generator interface | 
|  | output logic                      prng_data_req_o, | 
|  | input  logic                      prng_data_ack_i, | 
|  | output logic                      prng_reseed_req_o, | 
|  | input  logic                      prng_reseed_ack_i, | 
|  |  | 
|  | // Trigger register | 
|  | output logic                      start_o, | 
|  | output logic                      start_we_o, | 
|  | output logic                      key_iv_data_in_clear_o, | 
|  | output logic                      key_iv_data_in_clear_we_o, | 
|  | output logic                      data_out_clear_o, | 
|  | output logic                      data_out_clear_we_o, | 
|  | output logic                      prng_reseed_o, | 
|  | output logic                      prng_reseed_we_o, | 
|  |  | 
|  | // Status register | 
|  | output logic                      idle_o, | 
|  | output logic                      idle_we_o, | 
|  | output logic                      stall_o, | 
|  | output logic                      stall_we_o, | 
|  | input  logic                      output_lost_i, | 
|  | output logic                      output_lost_o, | 
|  | output logic                      output_lost_we_o, | 
|  | output logic                      output_valid_o, | 
|  | output logic                      output_valid_we_o, | 
|  | output logic                      input_ready_o, | 
|  | output logic                      input_ready_we_o | 
|  | ); | 
|  |  | 
|  | import aes_pkg::*; | 
|  |  | 
|  | // Encoding generated with: | 
|  | // $ ./util/design/sparse-fsm-encode.py -d 3 -m 7 -n 6 \ | 
|  | //      -s 31468618 --language=sv | 
|  | // | 
|  | // Hamming distance histogram: | 
|  | // | 
|  | //  0: -- | 
|  | //  1: -- | 
|  | //  2: -- | 
|  | //  3: |||||||||||||||||||| (57.14%) | 
|  | //  4: ||||||||||||||| (42.86%) | 
|  | //  5: -- | 
|  | //  6: -- | 
|  | // | 
|  | // Minimum Hamming distance: 3 | 
|  | // Maximum Hamming distance: 4 | 
|  | // Minimum Hamming weight: 1 | 
|  | // Maximum Hamming weight: 5 | 
|  | // | 
|  | localparam int StateWidth = 6; | 
|  | typedef enum logic [StateWidth-1:0] { | 
|  | IDLE        = 6'b111100, | 
|  | LOAD        = 6'b101001, | 
|  | PRNG_UPDATE = 6'b010000, | 
|  | PRNG_RESEED = 6'b100010, | 
|  | FINISH      = 6'b011011, | 
|  | CLEAR       = 6'b110111, | 
|  | ERROR       = 6'b001110 | 
|  | } aes_ctrl_e; | 
|  |  | 
|  | aes_ctrl_e                aes_ctrl_ns, aes_ctrl_cs; | 
|  |  | 
|  | // Signals | 
|  | aes_mode_e                mode; | 
|  | logic                     key_init_clear; | 
|  | sp2v_e                    key_init_new, key_init_new_chk; | 
|  | logic                     key_init_load; | 
|  | logic                     key_init_arm; | 
|  | sp2v_e                    key_init_ready, key_init_ready_chk; | 
|  | logic                     key_sideload; | 
|  |  | 
|  | logic  [NumSlicesCtr-1:0] iv_qe; | 
|  | logic                     iv_clear; | 
|  | logic                     iv_load; | 
|  | logic                     iv_arm; | 
|  | sp2v_e                    iv_ready, iv_ready_chk; | 
|  |  | 
|  | logic   [NumRegsData-1:0] data_in_new_d, data_in_new_q; | 
|  | sp2v_e                    data_in_new, data_in_new_chk; | 
|  | logic                     data_in_load; | 
|  |  | 
|  | logic   [NumRegsData-1:0] data_out_read_d, data_out_read_q; | 
|  | sp2v_e                    data_out_read, data_out_read_chk; | 
|  | sp2v_e                    output_valid_d, output_valid_q; | 
|  |  | 
|  | logic                     start_trigger; | 
|  | logic                     cfg_valid; | 
|  | logic                     no_alert; | 
|  | sp2v_e                    start_common, start_ecb, start_cbc, start_cfb, start_ofb, start_ctr; | 
|  | sp2v_e                    start, start_chk; | 
|  | sp2v_e                    finish, finish_chk; | 
|  | sp2v_e                    crypt, crypt_chk; | 
|  | sp2v_e                    cipher_out_done, cipher_out_done_chk; | 
|  | logic                     cipher_out_done_err_d, cipher_out_done_err_q; | 
|  | sp2v_e                    doing_cbc_enc, doing_cbc_enc_chk, doing_cbc_dec, doing_cbc_dec_chk; | 
|  | sp2v_e                    doing_cfb_enc, doing_cfb_enc_chk, doing_cfb_dec, doing_cfb_dec_chk; | 
|  | sp2v_e                    doing_ofb, doing_ofb_chk; | 
|  | sp2v_e                    doing_ctr, doing_ctr_chk; | 
|  | logic                     ctrl_we_q; | 
|  | sp2v_e                    ctr_ready; | 
|  | sp2v_e [NumSlicesCtr-1:0] ctr_we; | 
|  | logic                     clear_in_out_status; | 
|  | sp2v_e                    cipher_in_ready; | 
|  | sp2v_e                    cipher_out_valid; | 
|  | sp2v_e                    cipher_crypt; | 
|  | sp2v_e                    cipher_dec_key_gen; | 
|  | logic                     sp_enc_err; | 
|  |  | 
|  | logic                     start_we; | 
|  | logic                     key_iv_data_in_clear_we; | 
|  | logic                     data_out_clear_we; | 
|  | logic                     prng_reseed_we; | 
|  |  | 
|  | logic                     idle; | 
|  | logic                     idle_we; | 
|  | logic                     stall; | 
|  | logic                     stall_we; | 
|  | logic                     output_lost; | 
|  | logic                     output_lost_we; | 
|  | logic                     output_valid; | 
|  | logic                     output_valid_we; | 
|  | logic                     input_ready; | 
|  | logic                     input_ready_we; | 
|  |  | 
|  | if (SecStartTriggerDelay > 0) begin : gen_start_delay | 
|  | // Delay the manual start trigger input for SCA measurements. | 
|  | localparam int unsigned WidthCounter = $clog2(SecStartTriggerDelay+1); | 
|  | logic [WidthCounter-1:0] count_d, count_q; | 
|  |  | 
|  | // Clear counter when input goes low. Keep value if the specified delay is reached. | 
|  | assign count_d = !start_i       ? '0      : | 
|  | start_trigger ? count_q : count_q + 1'b1; | 
|  | assign start_trigger = (count_q == SecStartTriggerDelay[WidthCounter-1:0]) ? 1'b1 : 1'b0; | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) begin | 
|  | count_q <= '0; | 
|  | end else begin | 
|  | count_q <= count_d; | 
|  | end | 
|  | end | 
|  | end else begin : gen_no_start_delay | 
|  | // Directly forward the manual start trigger input. | 
|  | assign start_trigger = start_i; | 
|  | end | 
|  |  | 
|  | // Software updates IV in chunks of 32 bits, the counter updates SliceSizeCtr bits at a time. | 
|  | // Convert word write enable to internal half-word write enable. | 
|  | assign iv_qe = {iv_qe_i[3], iv_qe_i[3], iv_qe_i[2], iv_qe_i[2], | 
|  | iv_qe_i[1], iv_qe_i[1], iv_qe_i[0], iv_qe_i[0]}; | 
|  |  | 
|  | // The cipher core is only ever allowed to start or finish if the control register holds a valid | 
|  | // configuration and if no fatal alert condition occured. | 
|  | assign cfg_valid = ~((mode == AES_NONE) | ctrl_err_storage_i); | 
|  | assign no_alert  = ~alert_fatal_i; | 
|  |  | 
|  | // Check common start conditions. These are needed for any mode, unless we are running in | 
|  | // manual mode. | 
|  | assign start_common = | 
|  | (key_init_ready_chk == SP2V_HIGH && data_in_new_chk == SP2V_HIGH) ? | 
|  | // If key sideload is enabled, we only start if the key is valid. | 
|  | (sideload_i ? (key_sideload_valid_i ? SP2V_HIGH : SP2V_LOW) : SP2V_HIGH) : SP2V_LOW; | 
|  |  | 
|  | // Check mode-specific start conditions. If the IV (and counter) is needed, we only start if | 
|  | // also the IV (and counter) is ready. | 
|  | assign start_ecb = (mode == AES_ECB)                                ? SP2V_HIGH : SP2V_LOW; | 
|  | assign start_cbc = (mode == AES_CBC && iv_ready_chk == SP2V_HIGH)   ? SP2V_HIGH : SP2V_LOW; | 
|  | assign start_cfb = (mode == AES_CFB && iv_ready_chk == SP2V_HIGH)   ? SP2V_HIGH : SP2V_LOW; | 
|  | assign start_ofb = (mode == AES_OFB && iv_ready_chk == SP2V_HIGH)   ? SP2V_HIGH : SP2V_LOW; | 
|  | assign start_ctr = (mode == AES_CTR && iv_ready_chk == SP2V_HIGH && | 
|  | ctr_ready == SP2V_HIGH) ? SP2V_HIGH : SP2V_LOW; | 
|  |  | 
|  | // If set to start manually, we just wait for the trigger. Otherwise, check common as well as | 
|  | // mode-specific start conditions. | 
|  | assign start = | 
|  | (cfg_valid && no_alert && (SP2V_HIGH == | 
|  | // Manual operation has priority. | 
|  | (manual_operation_i      ? (start_trigger ? SP2V_HIGH : SP2V_LOW) : | 
|  | // Check start conditions for automatic operation. | 
|  | (start_ecb == SP2V_HIGH || | 
|  | start_cbc == SP2V_HIGH || | 
|  | start_cfb == SP2V_HIGH || | 
|  | start_ofb == SP2V_HIGH || | 
|  | start_ctr == SP2V_HIGH) ? start_common                           : SP2V_LOW)) | 
|  | ) ? SP2V_HIGH : SP2V_LOW; | 
|  |  | 
|  | // If not set to overwrite data, we wait for any previous output data to be read. data_out_read | 
|  | // synchronously clears output_valid_q, unless new output data is written in the exact same | 
|  | // clock cycle. | 
|  | assign finish = | 
|  | (cfg_valid && no_alert && (SP2V_HIGH == | 
|  | // Manual operation has priority. | 
|  | (manual_operation_i              ? SP2V_HIGH : | 
|  | // Make sure previous output data has been read. | 
|  | (output_valid_q    == SP2V_LOW || | 
|  | data_out_read_chk == SP2V_HIGH) ? SP2V_HIGH : SP2V_LOW)) | 
|  | ) ? SP2V_HIGH : SP2V_LOW; | 
|  |  | 
|  | // Helper signals for FSM | 
|  | assign crypt = (cipher_crypt_o == SP2V_HIGH || | 
|  | cipher_crypt_i == SP2V_HIGH) ? SP2V_HIGH : SP2V_LOW; | 
|  |  | 
|  | assign doing_cbc_enc = (mode == AES_CBC && op_i == AES_ENC) ? crypt_chk : SP2V_LOW; | 
|  | assign doing_cbc_dec = (mode == AES_CBC && op_i == AES_DEC) ? crypt_chk : SP2V_LOW; | 
|  | assign doing_cfb_enc = (mode == AES_CFB && op_i == AES_ENC) ? crypt_chk : SP2V_LOW; | 
|  | assign doing_cfb_dec = (mode == AES_CFB && op_i == AES_DEC) ? crypt_chk : SP2V_LOW; | 
|  | assign doing_ofb     = (mode == AES_OFB)                    ? crypt_chk : SP2V_LOW; | 
|  | assign doing_ctr     = (mode == AES_CTR)                    ? crypt_chk : SP2V_LOW; | 
|  |  | 
|  | // FSM | 
|  | always_comb begin : aes_ctrl_fsm | 
|  |  | 
|  | // Previous input data register control | 
|  | data_in_prev_sel_o = DIP_CLEAR; | 
|  | data_in_prev_we_o  = SP2V_LOW; | 
|  |  | 
|  | // Cipher I/O mux control | 
|  | state_in_sel_o      = SI_DATA; | 
|  | add_state_in_sel_o  = ADD_SI_ZERO; | 
|  | add_state_out_sel_o = ADD_SO_ZERO; | 
|  |  | 
|  | // Counter control | 
|  | ctr_incr_o = SP2V_LOW; | 
|  |  | 
|  | // Cipher core control | 
|  | cipher_in_valid_o       = SP2V_LOW; | 
|  | cipher_out_ready_o      = SP2V_LOW; | 
|  | cipher_out_done         = SP2V_LOW; | 
|  | cipher_crypt_o          = SP2V_LOW; | 
|  | cipher_dec_key_gen_o    = SP2V_LOW; | 
|  | cipher_key_clear_o      = 1'b0; | 
|  | cipher_data_out_clear_o = 1'b0; | 
|  |  | 
|  | // Initial key registers | 
|  | key_init_sel_o = sideload_i ? KEY_INIT_KEYMGR : KEY_INIT_INPUT; | 
|  | for (int s = 0; s < NumSharesKey; s++) begin | 
|  | key_init_we_o[s] = {NumRegsKey{SP2V_LOW}}; | 
|  | end | 
|  |  | 
|  | // IV registers | 
|  | iv_sel_o = IV_INPUT; | 
|  | iv_we_o  = {NumSlicesCtr{SP2V_LOW}}; | 
|  |  | 
|  | // Control register | 
|  | ctrl_we_o = 1'b0; | 
|  |  | 
|  | // Alert | 
|  | alert_o = 1'b0; | 
|  |  | 
|  | // Pseudo-random number generator control | 
|  | prng_data_req_o   = 1'b0; | 
|  | prng_reseed_req_o = 1'b0; | 
|  |  | 
|  | // Trigger register control | 
|  | start_we                = 1'b0; | 
|  | key_iv_data_in_clear_we = 1'b0; | 
|  | data_out_clear_we       = 1'b0; | 
|  | prng_reseed_we          = 1'b0; | 
|  |  | 
|  | // Status register | 
|  | idle     = 1'b0; | 
|  | idle_we  = 1'b0; | 
|  | stall    = 1'b0; | 
|  | stall_we = 1'b0; | 
|  |  | 
|  | // Key, data I/O register control | 
|  | data_in_load  = 1'b0; | 
|  | data_in_we_o  = 1'b0; | 
|  | data_out_we_o = SP2V_LOW; | 
|  |  | 
|  | // Register status tracker control | 
|  | key_init_clear = 1'b0; | 
|  | key_init_load  = 1'b0; | 
|  | key_init_arm   = 1'b0; | 
|  | iv_clear       = 1'b0; | 
|  | iv_load        = 1'b0; | 
|  | iv_arm         = 1'b0; | 
|  |  | 
|  | // FSM | 
|  | aes_ctrl_ns = aes_ctrl_cs; | 
|  |  | 
|  | unique case (aes_ctrl_cs) | 
|  |  | 
|  | IDLE: begin | 
|  | idle    = (start_chk == SP2V_HIGH || key_iv_data_in_clear_i || data_out_clear_i || | 
|  | prng_reseed_i) ? 1'b0 : 1'b1; | 
|  | idle_we = 1'b1; | 
|  |  | 
|  | if (idle) begin | 
|  | // Initial key and IV updates are ignored if we are not idle. If key sideload is enabled, | 
|  | // software writes to the initial key registers are ignored. | 
|  | for (int s = 0; s < NumSharesKey; s++) begin | 
|  | for (int i = 0; i < NumRegsKey; i++) begin | 
|  | key_init_we_o[s][i] = | 
|  | sideload_i          ? (key_sideload ? SP2V_HIGH : SP2V_LOW) : | 
|  | key_init_qe_i[s][i] ? SP2V_HIGH                             : SP2V_LOW; | 
|  | end | 
|  | end | 
|  | for (int i = 0; i < NumSlicesCtr; i++) begin | 
|  | iv_we_o[i] = iv_qe[i] ? SP2V_HIGH : SP2V_LOW; | 
|  | end | 
|  |  | 
|  | // Updates to the control register are only allowed if we are idle and we don't have a | 
|  | // storage error. A storage error is unrecoverable and requires a reset. | 
|  | ctrl_we_o      = !ctrl_err_storage_i ? ctrl_qe_i : 1'b0; | 
|  |  | 
|  | // Control register updates clear all register status trackers. | 
|  | key_init_clear = ctrl_we_o; | 
|  | iv_clear       = ctrl_we_o; | 
|  | end | 
|  |  | 
|  | if (prng_reseed_i) begin | 
|  | // PRNG reseeding has highest priority. | 
|  | aes_ctrl_ns = PRNG_RESEED; | 
|  |  | 
|  | end else if (key_iv_data_in_clear_i || data_out_clear_i) begin | 
|  | // To clear registers, we must first request fresh pseudo-random data. | 
|  | aes_ctrl_ns = PRNG_UPDATE; | 
|  |  | 
|  | end else if (start_chk == SP2V_HIGH) begin | 
|  | // Signal that we want to start encryption/decryption. | 
|  | cipher_crypt_o = SP2V_HIGH; | 
|  |  | 
|  | // We got a new initial key, but want to do decryption. The cipher core must first | 
|  | // generate the start key for decryption. | 
|  | cipher_dec_key_gen_o = (cipher_op_i == CIPH_INV) ? key_init_new_chk : SP2V_LOW; | 
|  |  | 
|  | // Previous input data register control | 
|  | data_in_prev_sel_o = (doing_cbc_dec_chk == SP2V_HIGH) ? DIP_DATA_IN : | 
|  | (doing_cfb_enc_chk == SP2V_HIGH) ? DIP_DATA_IN : | 
|  | (doing_cfb_dec_chk == SP2V_HIGH) ? DIP_DATA_IN : | 
|  | (doing_ofb         == SP2V_HIGH) ? DIP_DATA_IN : | 
|  | (doing_ctr         == SP2V_HIGH) ? DIP_DATA_IN : DIP_CLEAR; | 
|  | data_in_prev_we_o  = (doing_cbc_dec_chk == SP2V_HIGH) ? SP2V_HIGH : | 
|  | (doing_cfb_enc_chk == SP2V_HIGH) ? SP2V_HIGH : | 
|  | (doing_cfb_dec_chk == SP2V_HIGH) ? SP2V_HIGH : | 
|  | (doing_ofb_chk     == SP2V_HIGH) ? SP2V_HIGH : | 
|  | (doing_ctr_chk     == SP2V_HIGH) ? SP2V_HIGH : SP2V_LOW; | 
|  |  | 
|  | // State input mux control | 
|  | state_in_sel_o     = (doing_cfb_enc_chk == SP2V_HIGH) ? SI_ZERO : | 
|  | (doing_cfb_dec_chk == SP2V_HIGH) ? SI_ZERO : | 
|  | (doing_ofb_chk     == SP2V_HIGH) ? SI_ZERO : | 
|  | (doing_ctr_chk     == SP2V_HIGH) ? SI_ZERO : SI_DATA; | 
|  |  | 
|  | // State input additon mux control | 
|  | add_state_in_sel_o = (doing_cbc_enc_chk == SP2V_HIGH) ? ADD_SI_IV : | 
|  | (doing_cfb_enc_chk == SP2V_HIGH) ? ADD_SI_IV : | 
|  | (doing_cfb_dec_chk == SP2V_HIGH) ? ADD_SI_IV : | 
|  | (doing_ofb_chk     == SP2V_HIGH) ? ADD_SI_IV : | 
|  | (doing_ctr_chk     == SP2V_HIGH) ? ADD_SI_IV : ADD_SI_ZERO; | 
|  |  | 
|  | // We have work for the cipher core, perform handshake. | 
|  | cipher_in_valid_o = SP2V_HIGH; | 
|  | if (cipher_in_ready == SP2V_HIGH) begin | 
|  | // Do not yet clear a possible start trigger if we are just starting the generation of | 
|  | // the start key for decryption. | 
|  | start_we    = (cipher_dec_key_gen_o == SP2V_LOW); | 
|  | aes_ctrl_ns = LOAD; | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | LOAD: begin | 
|  | // Signal that we have used the current key, IV, data input to register status tracking. | 
|  | key_init_load = (cipher_dec_key_gen == SP2V_HIGH); // This key is no longer "new", but | 
|  | // still clean. | 
|  | key_init_arm  = (cipher_dec_key_gen == SP2V_LOW);  // The key is still "new", prevent | 
|  | // partial updates. | 
|  | iv_load       = (cipher_dec_key_gen == SP2V_HIGH) & | 
|  | (doing_cbc_enc_chk == SP2V_HIGH | doing_cbc_dec_chk == SP2V_HIGH | | 
|  | doing_cfb_enc_chk == SP2V_HIGH | doing_cfb_dec_chk == SP2V_HIGH | | 
|  | doing_ofb_chk     == SP2V_HIGH | doing_ctr_chk     == SP2V_HIGH); | 
|  | data_in_load  = (cipher_dec_key_gen == SP2V_LOW); | 
|  |  | 
|  | // Trigger counter increment. | 
|  | ctr_incr_o   = doing_ctr_chk; | 
|  |  | 
|  | // Unless we are just generating the start key for decryption, we must update the PRNG. | 
|  | aes_ctrl_ns  = (cipher_dec_key_gen == SP2V_LOW) ? PRNG_UPDATE : FINISH; | 
|  | end | 
|  |  | 
|  | PRNG_UPDATE: begin | 
|  | // Fresh pseudo-random data is used to: | 
|  | // - clear the state in the final cipher round, | 
|  | // - clear any other registers in the CLEAR state. | 
|  |  | 
|  | // IV control in case of ongoing encryption/decryption | 
|  | // - CTR: IV registers are updated by counter during cipher operation | 
|  | iv_sel_o = (doing_ctr_chk == SP2V_HIGH) ? IV_CTR : IV_INPUT; | 
|  | iv_we_o  = (doing_ctr_chk == SP2V_HIGH) ? ctr_we : {NumSlicesCtr{SP2V_LOW}}; | 
|  |  | 
|  | // Request fresh pseudo-random data, perform handshake. | 
|  | prng_data_req_o = 1'b1; | 
|  | if (prng_data_ack_i) begin | 
|  |  | 
|  | // Ongoing encryption/decryption operations have the highest priority. The clear triggers | 
|  | // might have become asserted after the handshake with the cipher core. | 
|  | if (cipher_crypt == SP2V_HIGH) begin | 
|  | aes_ctrl_ns = FINISH; | 
|  |  | 
|  | end else begin // (key_iv_data_in_clear_i || data_out_clear_i) | 
|  | // To clear the output data registers, we re-use the muxing resources of the cipher | 
|  | // core. To clear all key material, some key registers inside the cipher core need to | 
|  | // be cleared. | 
|  | cipher_key_clear_o      = key_iv_data_in_clear_i; | 
|  | cipher_data_out_clear_o = data_out_clear_i; | 
|  |  | 
|  | // We have work for the cipher core, perform handshake. | 
|  | cipher_in_valid_o = SP2V_HIGH; | 
|  | if (cipher_in_ready == SP2V_HIGH) begin | 
|  | aes_ctrl_ns = CLEAR; | 
|  | end | 
|  | end // cipher_crypt | 
|  | end // prng_data_ack_i | 
|  | end | 
|  |  | 
|  | PRNG_RESEED: begin | 
|  | // Request a reseed of the PRNG, perform handshake. | 
|  | prng_reseed_req_o = 1'b1; | 
|  | if (prng_reseed_ack_i) begin | 
|  | // Clear the trigger and return. | 
|  | prng_reseed_we = 1'b1; | 
|  | aes_ctrl_ns    = IDLE; | 
|  | end | 
|  | end | 
|  |  | 
|  | FINISH: begin | 
|  | // Wait for cipher core to finish. | 
|  |  | 
|  | if (cipher_dec_key_gen == SP2V_HIGH) begin | 
|  | // We are ready. | 
|  | cipher_out_ready_o = SP2V_HIGH; | 
|  | if (cipher_out_valid == SP2V_HIGH) begin | 
|  | aes_ctrl_ns = IDLE; | 
|  | end | 
|  | end else begin | 
|  | // Handshake signals: We are ready once the output data registers can be written. Don't | 
|  | // let data propagate in case of mux selector or sparsely encoded signals taking on | 
|  | // invalid values. | 
|  | cipher_out_ready_o = finish_chk; | 
|  | cipher_out_done    = (finish_chk == SP2V_HIGH && cipher_out_valid == SP2V_HIGH && | 
|  | !mux_sel_err_i && !sp_enc_err) ? SP2V_HIGH : SP2V_LOW; | 
|  |  | 
|  | // Signal if the cipher core is stalled (because previous output has not yet been read). | 
|  | stall    = (finish_chk == SP2V_LOW) & (cipher_out_valid == SP2V_HIGH); | 
|  | stall_we = 1'b1; | 
|  |  | 
|  | // State out addition mux control | 
|  | add_state_out_sel_o = (doing_cbc_dec_chk == SP2V_HIGH) ? ADD_SO_IV  : | 
|  | (doing_cfb_enc_chk == SP2V_HIGH) ? ADD_SO_DIP : | 
|  | (doing_cfb_dec_chk == SP2V_HIGH) ? ADD_SO_DIP : | 
|  | (doing_ofb_chk     == SP2V_HIGH) ? ADD_SO_DIP : | 
|  | (doing_ctr_chk     == SP2V_HIGH) ? ADD_SO_DIP : ADD_SO_ZERO; | 
|  |  | 
|  | // IV control | 
|  | // - CBC/CFB/OFB: IV registers are only updated when cipher finishes. | 
|  | // - CTR: IV registers are updated by counter during cipher operation. | 
|  | iv_sel_o = (doing_cbc_enc_chk == SP2V_HIGH)  ? IV_DATA_OUT     : | 
|  | (doing_cbc_dec_chk == SP2V_HIGH)  ? IV_DATA_IN_PREV : | 
|  | (doing_cfb_enc_chk == SP2V_HIGH)  ? IV_DATA_OUT     : | 
|  | (doing_cfb_dec_chk == SP2V_HIGH)  ? IV_DATA_IN_PREV : | 
|  | (doing_ofb_chk     == SP2V_HIGH)  ? IV_DATA_OUT_RAW : | 
|  | (doing_ctr_chk     == SP2V_HIGH)  ? IV_CTR          : IV_INPUT; | 
|  | iv_we_o  = (doing_cbc_enc_chk == SP2V_HIGH) || | 
|  | (doing_cbc_dec_chk == SP2V_HIGH) || | 
|  | (doing_cfb_enc_chk == SP2V_HIGH) || | 
|  | (doing_cfb_dec_chk == SP2V_HIGH) || | 
|  | (doing_ofb_chk     == SP2V_HIGH) ? {NumSlicesCtr{cipher_out_done_chk}} : | 
|  | (doing_ctr_chk     == SP2V_HIGH) ? ctr_we          : {NumSlicesCtr{SP2V_LOW}}; | 
|  |  | 
|  | // Arm the IV status tracker: After finishing, the IV registers can be written again | 
|  | // by software. We need to make sure software does not partially update the IV. | 
|  | iv_arm = (doing_cbc_enc_chk == SP2V_HIGH) || | 
|  | (doing_cbc_dec_chk == SP2V_HIGH) || | 
|  | (doing_cfb_enc_chk == SP2V_HIGH) || | 
|  | (doing_cfb_dec_chk == SP2V_HIGH) || | 
|  | (doing_ofb_chk     == SP2V_HIGH) || | 
|  | (doing_ctr_chk     == SP2V_HIGH) ? (cipher_out_done_chk == SP2V_HIGH) : 1'b0; | 
|  |  | 
|  | // Proceed upon successful handshake. | 
|  | if (cipher_out_done_chk == SP2V_HIGH) begin | 
|  | data_out_we_o = SP2V_HIGH; | 
|  | aes_ctrl_ns   = IDLE; | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | CLEAR: begin | 
|  | // Initial Key, IV and input data registers can be cleared right away. | 
|  | if (key_iv_data_in_clear_i) begin | 
|  | // Initial Key | 
|  | key_init_sel_o = KEY_INIT_CLEAR; | 
|  | for (int s = 0; s < NumSharesKey; s++) begin | 
|  | key_init_we_o[s] = {NumRegsKey{SP2V_HIGH}}; | 
|  | end | 
|  | key_init_clear = 1'b1; | 
|  |  | 
|  | // IV | 
|  | iv_sel_o = IV_CLEAR; | 
|  | iv_we_o  = {NumSlicesCtr{SP2V_HIGH}}; | 
|  | iv_clear = 1'b1; | 
|  |  | 
|  | // Input data | 
|  | data_in_we_o       = 1'b1; | 
|  | data_in_prev_sel_o = DIP_CLEAR; | 
|  | data_in_prev_we_o  = SP2V_HIGH; | 
|  | end | 
|  |  | 
|  | // Perform handshake with cipher core. | 
|  | cipher_out_ready_o = SP2V_HIGH; | 
|  | if (cipher_out_valid == SP2V_HIGH) begin | 
|  |  | 
|  | // Full Key and Decryption Key registers are cleared by the cipher core. | 
|  | // key_iv_data_in_clear_i is acknowledged by the cipher core with cipher_key_clear_i. | 
|  | if (cipher_key_clear_i) begin | 
|  | // Clear the trigger bit. | 
|  | key_iv_data_in_clear_we = 1'b1; | 
|  | end | 
|  |  | 
|  | // To clear the output data registers, we re-use the muxing resources of the cipher core. | 
|  | // data_out_clear_i is acknowledged by the cipher core with cipher_data_out_clear_i. | 
|  | if (cipher_data_out_clear_i) begin | 
|  | // Clear output data and the trigger bit. Don't release data from cipher core in case | 
|  | // of mux selector or sparsely encoded signals taking on invalid values. | 
|  | data_out_we_o     = (!mux_sel_err_i && !sp_enc_err) ? SP2V_HIGH : SP2V_LOW; | 
|  | data_out_clear_we = 1'b1; | 
|  | end | 
|  |  | 
|  | aes_ctrl_ns = IDLE; | 
|  | end | 
|  | end | 
|  |  | 
|  | ERROR: begin | 
|  | // Terminal error state | 
|  | alert_o = 1'b1; | 
|  | end | 
|  |  | 
|  | // We should never get here. If we do (e.g. via a malicious glitch), error out immediately. | 
|  | default: begin | 
|  | aes_ctrl_ns = ERROR; | 
|  | end | 
|  | endcase | 
|  |  | 
|  | // Unconditionally jump into the terminal error state in case a mux selector or a sparsely | 
|  | // encoded signal becomes invalid, or if the life cycle controller triggers an escalation. | 
|  | if (mux_sel_err_i || sp_enc_err || lc_escalate_en_i != lc_ctrl_pkg::Off) begin | 
|  | aes_ctrl_ns = ERROR; | 
|  | end | 
|  | end | 
|  |  | 
|  | // This primitive is used to place a size-only constraint on the | 
|  | // flops in order to prevent FSM state encoding optimizations. | 
|  | logic [StateWidth-1:0] aes_ctrl_cs_raw; | 
|  | assign aes_ctrl_cs = aes_ctrl_e'(aes_ctrl_cs_raw); | 
|  | prim_flop #( | 
|  | .Width(StateWidth), | 
|  | .ResetValue(StateWidth'(IDLE)) | 
|  | ) u_state_regs ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .d_i ( aes_ctrl_ns     ), | 
|  | .q_o ( aes_ctrl_cs_raw ) | 
|  | ); | 
|  |  | 
|  | ///////////////////// | 
|  | // Status Tracking // | 
|  | ///////////////////// | 
|  |  | 
|  | // We only take a new sideload key if sideload is enabled, if the provided sideload key is marked | 
|  | // as valid, and after the control register has been written. After that point we don't update | 
|  | // the key anymore, as we don't have a notion of when it actually changes. This would be required | 
|  | // to trigger decryption key generation for ECB/CBC decryption. | 
|  | // To update the sideload key, software has to: | 
|  | // 1) wait unitl AES is idle, | 
|  | // 2) wait for the key manager to provide the new key, | 
|  | // 3) start a new message by writing the control register and providing the IV (if needed). | 
|  | assign key_sideload = sideload_i & key_sideload_valid_i & ctrl_we_q; | 
|  |  | 
|  | // We only use clean initial keys. Either software/counter has updated | 
|  | // - all initial key registers, or | 
|  | // - none of the initial key registers but the registers were updated in the past. | 
|  | logic [NumRegsKey-1:0] key_init_we [NumSharesKey]; | 
|  | for (genvar s = 0; s < NumSharesKey; s++) begin : gen_status_key_init_we_shares | 
|  | for (genvar i = 0; i < NumRegsKey; i++) begin : gen_status_key_init_we | 
|  | assign key_init_we[s][i] = (key_init_we_o[s][i] == SP2V_HIGH); | 
|  | end | 
|  | end | 
|  | aes_reg_status #( | 
|  | .Width ( $bits(key_init_we) ) | 
|  | ) u_reg_status_key_init ( | 
|  | .clk_i   ( clk_i                            ), | 
|  | .rst_ni  ( rst_ni                           ), | 
|  | .we_i    ( {key_init_we[1], key_init_we[0]} ), | 
|  | .use_i   ( key_init_load                    ), | 
|  | .clear_i ( key_init_clear                   ), | 
|  | .arm_i   ( key_init_arm                     ), | 
|  | .new_o   ( key_init_new                     ), | 
|  | .clean_o ( key_init_ready                   ) | 
|  | ); | 
|  |  | 
|  | // We only use clean and unused IVs. Either software/counter has updated | 
|  | // - all IV registers, or | 
|  | // - none of the IV registers but the registers were updated in the past | 
|  | // and this particular IV has not yet been used. | 
|  | logic [NumSlicesCtr-1:0] iv_we; | 
|  | for (genvar i = 0; i < NumSlicesCtr; i++) begin : gen_status_iv_we | 
|  | assign iv_we[i] = (iv_we_o[i] == SP2V_HIGH); | 
|  | end | 
|  | aes_reg_status #( | 
|  | .Width ( $bits(iv_we) ) | 
|  | ) u_reg_status_iv ( | 
|  | .clk_i   ( clk_i    ), | 
|  | .rst_ni  ( rst_ni   ), | 
|  | .we_i    ( iv_we    ), | 
|  | .use_i   ( iv_load  ), | 
|  | .clear_i ( iv_clear ), | 
|  | .arm_i   ( iv_arm   ), | 
|  | .new_o   ( iv_ready ), | 
|  | .clean_o (          ) | 
|  | ); | 
|  |  | 
|  | // Input and output data register status tracking detects if: | 
|  | // - A complete new data input block is available, and | 
|  | // - An output data block has been read completely. | 
|  | // The status tracking needs to be cleared upon writes to the control register. The clearing is | 
|  | // applied one cycle later here to avoid zero-latency loops. This additional delay is not | 
|  | // relevant as if we are about to start encryption/decryption, we anyway don't allow writes | 
|  | // to the control register. | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin : reg_ctrl_we | 
|  | if (!rst_ni) begin | 
|  | ctrl_we_q <= 1'b0; | 
|  | end else begin | 
|  | ctrl_we_q <= ctrl_we_o; | 
|  | end | 
|  | end | 
|  | assign clear_in_out_status = ctrl_we_q; | 
|  |  | 
|  | // Collect writes to data input registers. Cleared if: | 
|  | // - data is loaded into cipher core, | 
|  | // - clearing data input registers with random data, | 
|  | // - clearing the status tracking. | 
|  | assign data_in_new_d = data_in_load || data_in_we_o || clear_in_out_status ? '0 : | 
|  | data_in_new_q | data_in_qe_i; | 
|  | assign data_in_new   = &data_in_new_d ? SP2V_HIGH : SP2V_LOW; | 
|  |  | 
|  | // Collect reads of data output registers. data_out_read is high for one clock cycle only and | 
|  | // clears output_valid_q unless new output is written in the exact same cycle. Cleared if: | 
|  | // - clearing data ouput registers with random data, | 
|  | // - clearing the status tracking. | 
|  | assign data_out_read_d = &data_out_read_q || clear_in_out_status ? '0 : | 
|  | data_out_read_q | data_out_re_i; | 
|  | assign data_out_read   = &data_out_read_d ? SP2V_HIGH : SP2V_LOW; | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin : reg_edge_detection | 
|  | if (!rst_ni) begin | 
|  | data_in_new_q   <= '0; | 
|  | data_out_read_q <= '0; | 
|  | end else begin | 
|  | data_in_new_q   <= data_in_new_d; | 
|  | data_out_read_q <= data_out_read_d; | 
|  | end | 
|  | end | 
|  |  | 
|  | // Status register bits for data input and output | 
|  | // Cleared to 1 if: | 
|  | // - data is loaded into cipher core, | 
|  | // - clearing data input registers with random data, | 
|  | // - clearing the status tracking. | 
|  | assign input_ready    = (data_in_new == SP2V_LOW); | 
|  | assign input_ready_we = (data_in_new == SP2V_HIGH) | data_in_load | data_in_we_o | | 
|  | clear_in_out_status; | 
|  |  | 
|  | // Cleared if: | 
|  | // - all data output registers have been read (unless new output is written in the same cycle), | 
|  | // - clearing data ouput registers with random data, | 
|  | // - clearing the status tracking. | 
|  | assign output_valid    = (data_out_we_o == SP2V_HIGH) & ~data_out_clear_we; | 
|  | assign output_valid_we = (data_out_we_o == SP2V_HIGH) | (data_out_read_chk == SP2V_HIGH) | | 
|  | data_out_clear_we | clear_in_out_status; | 
|  |  | 
|  | assign output_valid_d  = !output_valid_we ? output_valid_q : | 
|  | output_valid_o ? SP2V_HIGH      : SP2V_LOW; | 
|  |  | 
|  | // This primitive is used to place a size-only constraint on the | 
|  | // flops in order to prevent optimizations on this status signal. | 
|  | logic [Sp2VWidth-1:0] output_valid_q_raw; | 
|  | prim_flop #( | 
|  | .Width      ( Sp2VWidth            ), | 
|  | .ResetValue ( Sp2VWidth'(SP2V_LOW) ) | 
|  | ) u_output_valid_regs ( | 
|  | .clk_i  ( clk_i              ), | 
|  | .rst_ni ( rst_ni             ), | 
|  | .d_i    ( output_valid_d     ), | 
|  | .q_o    ( output_valid_q_raw ) | 
|  | ); | 
|  |  | 
|  | // Output lost status register bit | 
|  | // Cleared when updating the Control Register. Set when overwriting previous output data that has | 
|  | // not yet been read. | 
|  | assign output_lost    = ctrl_we_o     ? 1'b0 : | 
|  | output_lost_i ? 1'b1 : | 
|  | (output_valid_q == SP2V_HIGH) & (data_out_read_chk == SP2V_LOW); | 
|  | assign output_lost_we = ctrl_we_o | (data_out_we_o == SP2V_HIGH); | 
|  |  | 
|  | ///////////////////// | 
|  | // Status Register // | 
|  | ///////////////////// | 
|  | // Fatal alerts clear all other bits in the status register. | 
|  | assign idle_o            = alert_fatal_i ? 1'b0 : idle; | 
|  | assign idle_we_o         = alert_fatal_i ? 1'b1 : idle_we; | 
|  | assign stall_o           = alert_fatal_i ? 1'b0 : stall; | 
|  | assign stall_we_o        = alert_fatal_i ? 1'b1 : stall_we; | 
|  | assign output_lost_o     = alert_fatal_i ? 1'b0 : output_lost; | 
|  | assign output_lost_we_o  = alert_fatal_i ? 1'b1 : output_lost_we; | 
|  | assign output_valid_o    = alert_fatal_i ? 1'b0 : output_valid; | 
|  | assign output_valid_we_o = alert_fatal_i ? 1'b1 : output_valid_we; | 
|  | assign input_ready_o     = alert_fatal_i ? 1'b0 : input_ready; | 
|  | assign input_ready_we_o  = alert_fatal_i ? 1'b1 : input_ready_we; | 
|  |  | 
|  | ////////////////////// | 
|  | // Trigger Register // | 
|  | ////////////////////// | 
|  | // Triggers are only ever cleared by control. Fatal alerts clear all bits in the trigger | 
|  | // register. | 
|  | assign start_o                   = 1'b0; | 
|  | assign start_we_o                = alert_fatal_i ? 1'b1 : start_we; | 
|  | assign key_iv_data_in_clear_o    = 1'b0; | 
|  | assign key_iv_data_in_clear_we_o = alert_fatal_i ? 1'b1 : key_iv_data_in_clear_we; | 
|  | assign data_out_clear_o          = 1'b0; | 
|  | assign data_out_clear_we_o       = alert_fatal_i ? 1'b1 : data_out_clear_we; | 
|  | assign prng_reseed_o             = 1'b0; | 
|  | assign prng_reseed_we_o          = alert_fatal_i ? 1'b1 : prng_reseed_we; | 
|  |  | 
|  | ////////////////////////////// | 
|  | // Sparsely Encoded Signals // | 
|  | ////////////////////////////// | 
|  |  | 
|  | // We use sparse encodings for various critical signals and must ensure that: | 
|  | // 1. The synthesis tool doesn't optimize away the sparse encoding. | 
|  | // 2. The sparsely encoded signal is always valid. More precisely, an alert or SVA is triggered | 
|  | //    if a sparse signal takes on an invalid value. | 
|  | // 3. The alert signal remains asserted until reset even if the sparse signal becomes valid again | 
|  | //    This is achieved by driving the control FSM into the terminal error state whenever any | 
|  | //    sparsely encoded signal becomes invalid. | 
|  | // | 
|  | // If any sparsely encoded signal becomes invalid, the controller further immediately de-asserts | 
|  | // data_out_we_o and other write-enable signals to prevent any data from being released. | 
|  |  | 
|  | // We use vectors of sparsely encoded signals to reduce code duplication. | 
|  | localparam int unsigned NumSp2VSig = 21 + NumSlicesCtr; | 
|  | sp2v_e [NumSp2VSig-1:0]                sp2v_sig; | 
|  | sp2v_e [NumSp2VSig-1:0]                sp2v_sig_chk; | 
|  | logic  [NumSp2VSig-1:0][Sp2VWidth-1:0] sp2v_sig_chk_raw; | 
|  | logic  [NumSp2VSig-1:0]                sp2v_sig_err; | 
|  |  | 
|  | assign sp2v_sig[0]  = cipher_in_ready_i; | 
|  | assign sp2v_sig[1]  = cipher_out_valid_i; | 
|  | assign sp2v_sig[2]  = cipher_crypt_i; | 
|  | assign sp2v_sig[3]  = cipher_dec_key_gen_i; | 
|  | assign sp2v_sig[4]  = crypt; | 
|  | assign sp2v_sig[5]  = doing_cbc_enc; | 
|  | assign sp2v_sig[6]  = doing_cbc_dec; | 
|  | assign sp2v_sig[7]  = doing_cfb_enc; | 
|  | assign sp2v_sig[8]  = doing_cfb_dec; | 
|  | assign sp2v_sig[9]  = doing_ofb; | 
|  | assign sp2v_sig[10] = doing_ctr; | 
|  | assign sp2v_sig[11] = key_init_new; | 
|  | assign sp2v_sig[12] = key_init_ready; | 
|  | assign sp2v_sig[13] = iv_ready; | 
|  | assign sp2v_sig[14] = data_in_new; | 
|  | assign sp2v_sig[15] = data_out_read; | 
|  | assign sp2v_sig[16] = sp2v_e'(output_valid_q_raw); | 
|  | assign sp2v_sig[17] = ctr_ready_i; | 
|  | assign sp2v_sig[18] = start; | 
|  | assign sp2v_sig[19] = finish; | 
|  | for (genvar i = 0; i < NumSlicesCtr; i++) begin : gen_use_ctr_we_i | 
|  | assign sp2v_sig[20+i] = ctr_we_i[i]; | 
|  | end | 
|  | assign sp2v_sig[20 + NumSlicesCtr] = cipher_out_done; | 
|  |  | 
|  | // Individually check sparsely encoded signals. | 
|  | for (genvar i = 0; i < NumSp2VSig; i++) begin : gen_sel_buf_chk | 
|  | aes_sel_buf_chk #( | 
|  | .Num   ( Sp2VNum   ), | 
|  | .Width ( Sp2VWidth ) | 
|  | ) u_aes_sp2v_sig_buf_chk_i ( | 
|  | .clk_i  ( clk_i               ), | 
|  | .rst_ni ( rst_ni              ), | 
|  | .sel_i  ( sp2v_sig[i]         ), | 
|  | .sel_o  ( sp2v_sig_chk_raw[i] ), | 
|  | .err_o  ( sp2v_sig_err[i]     ) | 
|  | ); | 
|  | assign sp2v_sig_chk[i] = sp2v_e'(sp2v_sig_chk_raw[i]); | 
|  | end | 
|  |  | 
|  | assign cipher_in_ready       = sp2v_sig_chk[0]; | 
|  | assign cipher_out_valid      = sp2v_sig_chk[1]; | 
|  | assign cipher_crypt          = sp2v_sig_chk[2]; | 
|  | assign cipher_dec_key_gen    = sp2v_sig_chk[3]; | 
|  | assign crypt_chk             = sp2v_sig_chk[4]; | 
|  | assign doing_cbc_enc_chk     = sp2v_sig_chk[5]; | 
|  | assign doing_cbc_dec_chk     = sp2v_sig_chk[6]; | 
|  | assign doing_cfb_enc_chk     = sp2v_sig_chk[7]; | 
|  | assign doing_cfb_dec_chk     = sp2v_sig_chk[8]; | 
|  | assign doing_ofb_chk         = sp2v_sig_chk[9]; | 
|  | assign doing_ctr_chk         = sp2v_sig_chk[10]; | 
|  | assign key_init_new_chk      = sp2v_sig_chk[11]; | 
|  | assign key_init_ready_chk    = sp2v_sig_chk[12]; | 
|  | assign iv_ready_chk          = sp2v_sig_chk[13]; | 
|  | assign data_in_new_chk       = sp2v_sig_chk[14]; | 
|  | assign data_out_read_chk     = sp2v_sig_chk[15]; | 
|  | assign output_valid_q        = sp2v_sig_chk[16]; | 
|  | assign ctr_ready             = sp2v_sig_chk[17]; | 
|  | assign start_chk             = sp2v_sig_chk[18]; | 
|  | assign finish_chk            = sp2v_sig_chk[19]; | 
|  | for (genvar i = 0; i < NumSlicesCtr; i++) begin : gen_ctr_we | 
|  | assign ctr_we[i]           = sp2v_sig_chk[20+i]; | 
|  | end | 
|  | assign cipher_out_done_chk   = sp2v_sig_chk[20 + NumSlicesCtr]; | 
|  | assign cipher_out_done_err_d = sp2v_sig_err[20 + NumSlicesCtr]; | 
|  |  | 
|  | // We need to register the error signal for cipher_out_done to avoid circular loops in the FSM. | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin : reg_sp_enc_err | 
|  | if (!rst_ni) begin | 
|  | cipher_out_done_err_q <= 1'b0; | 
|  | end else if (cipher_out_done_err_d) begin | 
|  | cipher_out_done_err_q <= 1'b1; | 
|  | end | 
|  | end | 
|  |  | 
|  | // Collect encoding errors. | 
|  | // We instantiate the checker modules as close as possible to where the sparsely encoded signals | 
|  | // are used. Here, we collect also encoding errors detected in other places of the core. | 
|  | assign sp_enc_err = |sp2v_sig_err[NumSp2VSig-2:0] | cipher_out_done_err_q | sp_enc_err_i; | 
|  |  | 
|  | // Prevent synthesis optimizations on the mode signal. | 
|  | logic [$bits(aes_mode_e)-1:0] mode_in_raw, mode_buf_raw; | 
|  | assign mode_in_raw = {mode_i}; | 
|  | for (genvar i = 0; i < $bits(mode_i); i++) begin : gen_mode_buf | 
|  | prim_buf u_prim_buf_sel_i ( | 
|  | .in_i  ( mode_in_raw[i]  ), | 
|  | .out_o ( mode_buf_raw[i] ) | 
|  | ); | 
|  | end | 
|  | assign mode = aes_mode_e'(mode_buf_raw); | 
|  |  | 
|  | //////////////// | 
|  | // Assertions // | 
|  | //////////////// | 
|  |  | 
|  | // Selectors must be known/valid | 
|  | `ASSERT(AesModeValid, !ctrl_err_storage_i |-> mode inside { | 
|  | AES_ECB, | 
|  | AES_CBC, | 
|  | AES_CFB, | 
|  | AES_OFB, | 
|  | AES_CTR, | 
|  | AES_NONE | 
|  | }) | 
|  | `ASSERT_KNOWN(AesOpKnown, op_i) | 
|  | `ASSERT_KNOWN(AesCiphOpKnown, cipher_op_i) | 
|  | `ASSERT(AesControlStateValid, !alert_o |-> aes_ctrl_cs inside { | 
|  | IDLE, | 
|  | LOAD, | 
|  | PRNG_UPDATE, | 
|  | PRNG_RESEED, | 
|  | FINISH, | 
|  | CLEAR | 
|  | }) | 
|  |  | 
|  | // Check parameters | 
|  | `ASSERT_INIT(AesNumSlicesCtr, NumSlicesCtr == 8) | 
|  |  | 
|  | endmodule |