|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // AES counter for CTR mode | 
|  | // | 
|  | // This module uses one counter with a width of SliceSizeCtr to iteratively increment the 128-bit | 
|  | // counter value. | 
|  |  | 
|  | module aes_ctr import aes_pkg::*; | 
|  | ( | 
|  | input  logic                                       clk_i, | 
|  | input  logic                                       rst_ni, | 
|  |  | 
|  | input  sp2v_e                                      incr_i, | 
|  | output sp2v_e                                      ready_o, | 
|  | output logic                                       alert_o, | 
|  |  | 
|  | input  logic  [NumSlicesCtr-1:0][SliceSizeCtr-1:0] ctr_i, | 
|  | output logic  [NumSlicesCtr-1:0][SliceSizeCtr-1:0] ctr_o, | 
|  | output sp2v_e [NumSlicesCtr-1:0]                   ctr_we_o | 
|  | ); | 
|  |  | 
|  | // Reverse byte order - unrelated to NumSlicesCtr and SliceSizeCtr | 
|  | function automatic logic [15:0][7:0] aes_rev_order_byte(logic [15:0][7:0] in); | 
|  | logic [15:0][7:0] out; | 
|  | for (int i = 0; i < 16; i++) begin | 
|  | out[i] = in[15-i]; | 
|  | end | 
|  | return out; | 
|  | endfunction | 
|  |  | 
|  | // Reverse sp2v order | 
|  | function automatic sp2v_e [NumSlicesCtr-1:0] aes_rev_order_sp2v(sp2v_e [NumSlicesCtr-1:0] in); | 
|  | sp2v_e [NumSlicesCtr-1:0] out; | 
|  | for (int i = 0; i < NumSlicesCtr; i++) begin | 
|  | out[i] = in[NumSlicesCtr - 1 - i]; | 
|  | end | 
|  | return out; | 
|  | endfunction | 
|  |  | 
|  | // Signals | 
|  | logic                   [SliceIdxWidth-1:0] ctr_slice_idx; | 
|  |  | 
|  | logic  [NumSlicesCtr-1:0][SliceSizeCtr-1:0] ctr_i_rev; // 8 times 2 bytes | 
|  | logic  [NumSlicesCtr-1:0][SliceSizeCtr-1:0] ctr_o_rev; // 8 times 2 bytes | 
|  | sp2v_e [NumSlicesCtr-1:0]                   ctr_we_o_rev; | 
|  | sp2v_e                                      ctr_we; | 
|  |  | 
|  | logic                    [SliceSizeCtr-1:0] ctr_i_slice; | 
|  | logic                    [SliceSizeCtr-1:0] ctr_o_slice; | 
|  |  | 
|  | sp2v_e                                      incr; | 
|  | logic                                       incr_err; | 
|  | logic                                       mr_err; | 
|  |  | 
|  | // Sparsified FSM signals. These are needed for connecting the individual bits of the Sp2V | 
|  | // signals to the single-rail FSMs. | 
|  | logic    [Sp2VWidth-1:0]                    sp_incr; | 
|  | logic    [Sp2VWidth-1:0]                    sp_ready; | 
|  | logic    [Sp2VWidth-1:0]                    sp_ctr_we; | 
|  |  | 
|  | // Multi-rail signals. These are outputs of the single-rail FSMs and need combining. | 
|  | logic    [Sp2VWidth-1:0]                    mr_alert; | 
|  | logic    [Sp2VWidth-1:0][SliceIdxWidth-1:0] mr_ctr_slice_idx; | 
|  | logic    [Sp2VWidth-1:0] [SliceSizeCtr-1:0] mr_ctr_o_slice; | 
|  |  | 
|  | //////////// | 
|  | // Inputs // | 
|  | //////////// | 
|  |  | 
|  | // Reverse byte order | 
|  | assign ctr_i_rev = aes_rev_order_byte(ctr_i); | 
|  |  | 
|  | // SEC_CM: CTRL.SPARSE | 
|  | // Check sparsely encoded incr signal. | 
|  | logic [Sp2VWidth-1:0] incr_raw; | 
|  | aes_sel_buf_chk #( | 
|  | .Num      ( Sp2VNum   ), | 
|  | .Width    ( Sp2VWidth ), | 
|  | .EnSecBuf ( 1'b0      ) | 
|  | ) u_aes_sb_en_buf_chk ( | 
|  | .clk_i  ( clk_i    ), | 
|  | .rst_ni ( rst_ni   ), | 
|  | .sel_i  ( incr_i   ), | 
|  | .sel_o  ( incr_raw ), | 
|  | .err_o  ( incr_err ) | 
|  | ); | 
|  | assign incr = sp2v_e'(incr_raw); | 
|  |  | 
|  | ///////////// | 
|  | // Counter // | 
|  | ///////////// | 
|  |  | 
|  | // We do SliceSizeCtr bits at a time. | 
|  | assign ctr_i_slice = ctr_i_rev[ctr_slice_idx]; | 
|  |  | 
|  | ///////// | 
|  | // FSM // | 
|  | ///////// | 
|  |  | 
|  | // Convert sp2v_e signals to sparsified inputs. | 
|  | assign sp_incr = {incr}; | 
|  |  | 
|  | // SEC_CM: CTR.FSM.REDUN | 
|  | // For every bit in the Sp2V signals, one separate rail is instantiated. The inputs and outputs | 
|  | // of every rail are buffered to prevent aggressive synthesis optimizations. | 
|  | for (genvar i = 0; i < Sp2VWidth; i++) begin : gen_fsm | 
|  | if (SP2V_LOGIC_HIGH[i] == 1'b1) begin : gen_fsm_p | 
|  | aes_ctr_fsm_p u_aes_ctr_fsm_i ( | 
|  | .clk_i           ( clk_i               ), | 
|  | .rst_ni          ( rst_ni              ), | 
|  |  | 
|  | .incr_i          ( sp_incr[i]          ), // Sparsified | 
|  | .ready_o         ( sp_ready[i]         ), // Sparsified | 
|  | .incr_err_i      ( incr_err            ), | 
|  | .mr_err_i        ( mr_err              ), | 
|  | .alert_o         ( mr_alert[i]         ), // OR-combine | 
|  |  | 
|  | .ctr_slice_idx_o ( mr_ctr_slice_idx[i] ), // OR-combine | 
|  | .ctr_slice_i     ( ctr_i_slice         ), | 
|  | .ctr_slice_o     ( mr_ctr_o_slice[i]   ), // OR-combine | 
|  | .ctr_we_o        ( sp_ctr_we[i]        )  // Sparsified | 
|  | ); | 
|  | end else begin : gen_fsm_n | 
|  | aes_ctr_fsm_n u_aes_ctr_fsm_i ( | 
|  | .clk_i           ( clk_i               ), | 
|  | .rst_ni          ( rst_ni              ), | 
|  |  | 
|  | .incr_ni         ( sp_incr[i]          ), // Sparsified | 
|  | .ready_no        ( sp_ready[i]         ), // Sparsified | 
|  | .incr_err_i      ( incr_err            ), | 
|  | .mr_err_i        ( mr_err              ), | 
|  | .alert_o         ( mr_alert[i]         ), // OR-combine | 
|  |  | 
|  | .ctr_slice_idx_o ( mr_ctr_slice_idx[i] ), // OR-combine | 
|  | .ctr_slice_i     ( ctr_i_slice         ), | 
|  | .ctr_slice_o     ( mr_ctr_o_slice[i]   ), // OR-combine | 
|  | .ctr_we_no       ( sp_ctr_we[i]        )  // Sparsified | 
|  | ); | 
|  | end | 
|  | end | 
|  |  | 
|  | // Convert sparsified outputs to sp2v_e type. | 
|  | assign ready_o = sp2v_e'(sp_ready); | 
|  | assign ctr_we  = sp2v_e'(sp_ctr_we); | 
|  |  | 
|  | // Combine single-bit FSM outputs. | 
|  | // OR: One bit is sufficient to drive the corresponding output bit high. | 
|  | assign alert_o = |mr_alert; | 
|  |  | 
|  | // Combine multi-bit FSM outputs. We simply OR them together and compare the values | 
|  | // to detect errors. | 
|  | always_comb begin : combine_sparse_signals | 
|  | ctr_slice_idx = '0; | 
|  | ctr_o_slice   = '0; | 
|  | mr_err        = 1'b0; | 
|  |  | 
|  | for (int i = 0; i < Sp2VWidth; i++) begin | 
|  | ctr_slice_idx |= mr_ctr_slice_idx[i]; | 
|  | ctr_o_slice   |= mr_ctr_o_slice[i]; | 
|  |  | 
|  | if (ctr_slice_idx != mr_ctr_slice_idx[i] || | 
|  | ctr_o_slice   != mr_ctr_o_slice[i]) begin | 
|  | mr_err = 1'b1; | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | ///////////// | 
|  | // Outputs // | 
|  | ///////////// | 
|  |  | 
|  | // Combine input and counter output. | 
|  | always_comb begin | 
|  | ctr_o_rev                = ctr_i_rev; | 
|  | ctr_o_rev[ctr_slice_idx] = ctr_o_slice; | 
|  | end | 
|  |  | 
|  | // Generate the sliced write enable. | 
|  | always_comb begin | 
|  | ctr_we_o_rev                = {NumSlicesCtr{SP2V_LOW}}; | 
|  | ctr_we_o_rev[ctr_slice_idx] = ctr_we; | 
|  | end | 
|  |  | 
|  | // Reverse byte and bit order. | 
|  | assign ctr_o    = aes_rev_order_byte(ctr_o_rev); | 
|  | assign ctr_we_o = aes_rev_order_sp2v(ctr_we_o_rev); | 
|  |  | 
|  | endmodule |