From 08509c594fe118c70ed70a6e436ca73be8f925ab Mon Sep 17 00:00:00 2001 From: Pirmin Vogel Date: Mon, 7 Oct 2024 12:06:45 +0200 Subject: [PATCH] [aes] Extend CSRs for AES-GCM support Signed-off-by: Pirmin Vogel --- hw/ip/aes/aes.core | 1 + hw/ip/aes/data/aes.hjson | 124 ++++++++++++++- hw/ip/aes/rtl/aes.sv | 2 + hw/ip/aes/rtl/aes_control.sv | 11 ++ hw/ip/aes/rtl/aes_control_fsm.sv | 21 ++- hw/ip/aes/rtl/aes_control_fsm_n.sv | 20 +++ hw/ip/aes/rtl/aes_control_fsm_p.sv | 20 +++ hw/ip/aes/rtl/aes_core.sv | 52 ++++++- hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv | 173 +++++++++++++++++++++ hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv | 4 +- hw/ip/aes/rtl/aes_pkg.sv | 22 ++- hw/ip/aes/rtl/aes_reg_pkg.sv | 76 ++++++--- hw/ip/aes/rtl/aes_reg_top.sv | 65 +++++++- 13 files changed, 547 insertions(+), 44 deletions(-) create mode 100644 hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv diff --git a/hw/ip/aes/aes.core b/hw/ip/aes/aes.core index 5c19412af405ff..f20c3d42979484 100644 --- a/hw/ip/aes/aes.core +++ b/hw/ip/aes/aes.core @@ -22,6 +22,7 @@ filesets: - rtl/aes_pkg.sv - rtl/aes_reg_top.sv - rtl/aes_ctrl_reg_shadowed.sv + - rtl/aes_ctrl_gcm_reg_shadowed.sv - rtl/aes_core.sv - rtl/aes_ctr.sv - rtl/aes_ctr_fsm.sv diff --git a/hw/ip/aes/data/aes.hjson b/hw/ip/aes/data/aes.hjson index fe00ea2125b6ea..a1d43aac383674 100644 --- a/hw/ip/aes/data/aes.hjson +++ b/hw/ip/aes/data/aes.hjson @@ -635,11 +635,11 @@ } { bits: "7:2", name: "MODE", - resval: "0x20", + resval: "0x3f", hwaccess: "hrw", desc: ''' 6-bit one-hot field to select AES block cipher mode. - Invalid input values, i.e., values with multiple bits set and value 6'b00_0000, are mapped to AES_NONE (6'b10_0000). + Invalid input values, i.e., values with multiple bits set and value 6'b00_0000, are mapped to AES_NONE (6'b11_1111). ''' enum: [ { value: "1", @@ -673,9 +673,16 @@ ''' }, { value: "32", + name: "AES_GCM", + desc: ''' + 6'b10_0000: Galois/Counter Mode (GCM). + In case support for GCM has been disabled at compile time, setting this value results in configuring AES_NONE (6'b11_1111). + ''' + }, + { value: "63", name: "AES_NONE", desc: ''' - 6'b10_0000: Invalid input values, i.e., value with multiple bits set and value 6'b00_0000, are mapped to AES_NONE. + 6'b11_1111: Invalid input values, i.e., value with multiple bits set, value 6'b00_0000, and value 6'b10_0000 in case GCM is not supported (because disabled at compile time) are mapped to AES_NONE. ''' } ] @@ -970,5 +977,116 @@ } ] }, + { name: "CTRL_GCM_SHADOWED", + desc: ''' + Galois/Counter Mode (GCM) Control Register. + + Can only be updated when the AES unit is idle. + If the AES unit is non-idle, writes to this register are ignored. + This register is shadowed, meaning two subsequent write operations are required to change its content. + If the two write operations try to set a different value, a recoverable alert is triggered (See Status Register). + A read operation clears the internal phase tracking: The next write operation is always considered a first write operation of an update sequence. + ''' + swaccess: "rw", + hwaccess: "hrw", + hwext: "true", + hwqe: "true", + shadowed: "true", + update_err_alert: "recov_ctrl_update_err", + storage_err_alert: "fatal_fault", + fields: [ + { bits: "6:0", + name: "PHASE", + resval: "0x01", + hwaccess: "hrw", + desc: ''' + 7-bit one-hot field to select the phase of the Galois/Counter Mode (GCM) of operation. + Invalid input values, i.e., values with multiple bits set and value 7'b000_0000, are mapped to GCM_INIT (7'b000_0001). + In case support for GCM has been disabled at compile time, this field is not writable and always reads as GCM_INIT (7'b000_0001). + ''' + enum: [ + { value: "1", + name: "GCM_INIT", + desc: ''' + 7'b000_0001: Initialization phase. + Software configures the Initial Key and IV Registers. + The hardware then generates the hash subkey and loads it into the internal GHASH block. + Once the AES unit is idle again, software can advance to the next phase. + Possible next phases are GCM_RESTORE, GCM_AAD and GCM_TEXT. + Invalid input values, i.e., values with multiple bits set, value 7'b000_0000, and all other values in case GCM is not supported (because disabled at compile time) are mapped to GCM_INIT. + ''' + }, + { value: "2", + name: "GCM_RESTORE", + desc: ''' + 7'b000_0010: Optional context restore phase. + Software configures the IV and Input Data Registers to restore a previously saved AES-GCM context (IV and GHASH state). + Possible next phases are GCM_INIT, GCM_AAD and GCM_TEXT. + ''' + }, + { value: "4", + name: "GCM_AAD", + desc: ''' + 7'b000_0100: Optional additional authenticated data phase (AAD). + Software inputs the AAD via Input Data Registers block by block via Input Data Registers. + Possible next phases are GCM_INIT, GCM_TEXT, GCM_SAVE and GCM_LEN. + ''' + }, + { value: "8", + name: "GCM_TEXT", + desc: ''' + 7'b000_1000: Optional plaintext/ciphertext phase. + Software inputs the plaintext/ciphertext block by block via Input Data Registers, and retrieves the output ciphertext/plaintext block by block via Output Data Registers. + Possible next phases are GCM_INIT, GCM_SAVE and GCM_LEN. + ''' + }, + { value: "16", + name: "GCM_SAVE", + desc: ''' + 7'b001_0000: Optional context save phase. + The hardware stops accepting inputs. + Software reads the current GHASH state and IV via Output Data and IV Registers, respectively. + The only possible next phase is GCM_INIT. + ''' + }, + { value: "32", + name: "GCM_LEN", + desc: ''' + 7'b010_0000: Length phase. + Software inputs a single data block containing the length of the AAD and the ciphertext via Input Data Registers. + Once the AES unit is idle again, software reads the GHASH output via Output Data Registers and then advances to the next phase. + Possible next phase are GCM_INIT and GCM_TAG. + ''' + }, + { value: "64", + name: "GCM_TAG", + desc: ''' + 7'b100_0000: Tag phase. + Software inputs again the original IV via IV Registers and the previously read GHASH output via Input Data Registers. + Once the AES unit is idle again, software reads the final integrity tag via Data Out Registers. + The only possible next phase is GCM_INIT. + ''' + } + ] + tags: ["shadowed_reg_path:u_aes_core.u_ctrl_gcm_reg_shadowed.u_ctrl_gcm_reg_shadowed_phase"] + } + { bits: "12:8", + name: "NUM_VALID_BYTES", + resval: "16", + hwaccess: "hrw", + desc: ''' + Number of valid bytes of the current input block. + Only the last block in the GCM_AAD and GCM_TEXT phases are expected to have not all bytes marked as valid. + For all other blocks, the number of valid bytes should be set to 16. + Invalid input values, i.e., the value 5'b0_0000, and all other values different from 5'b1_0000 in case GCM is not supported (because disabled at compile time) are mapped to 5'b1_0000. + ''' + tags: ["shadowed_reg_path:u_aes_core.u_ctrl_gcm_reg_shadowed.u_ctrl_gcm_reg_shadowed_num_valid_bytes"] + } + ] + tags: [// Updated by the HW. + // Updates based on writes to this reg (reset test possible). + // Exclude from write-read checks. + "excl:CsrNonInitTests:CsrExclWriteCheck"] + }, ], } diff --git a/hw/ip/aes/rtl/aes.sv b/hw/ip/aes/rtl/aes.sv index b104713abededb..9f66d1380cd75a 100644 --- a/hw/ip/aes/rtl/aes.sv +++ b/hw/ip/aes/rtl/aes.sv @@ -11,6 +11,7 @@ module aes import aes_reg_pkg::*; #( parameter bit AES192Enable = 1, // Can be 0 (disable), or 1 (enable). + parameter bit AESGCMEnable = 1, // Can be 0 (disable), or 1 (enable). parameter bit SecMasking = 1, // Can be 0 (no masking), or // 1 (first-order masking) of the cipher // core. Masking requires the use of a @@ -174,6 +175,7 @@ module aes // AES core aes_core #( .AES192Enable ( AES192Enable ), + .AESGCMEnable ( AESGCMEnable ), .SecMasking ( SecMasking ), .SecSBoxImpl ( SecSBoxImpl ), .SecStartTriggerDelay ( SecStartTriggerDelay ), diff --git a/hw/ip/aes/rtl/aes_control.sv b/hw/ip/aes/rtl/aes_control.sv index fe752436890df7..053fffbf67e3e4 100644 --- a/hw/ip/aes/rtl/aes_control.sv +++ b/hw/ip/aes/rtl/aes_control.sv @@ -30,6 +30,9 @@ module aes_control input prs_rate_e prng_reseed_rate_i, input logic manual_operation_i, input logic key_touch_forces_reseed_i, + input logic ctrl_gcm_qe_i, + output logic ctrl_gcm_we_o, + input gcm_phase_e gcm_phase_i, input logic start_i, input logic key_iv_data_in_clear_i, input logic data_out_clear_i, @@ -174,6 +177,7 @@ module aes_control // Multi-rail signals. These are outputs of the single-rail FSMs and need combining. logic [Sp2VWidth-1:0] mr_ctrl_we; + logic [Sp2VWidth-1:0] mr_ctrl_gcm_we; logic [Sp2VWidth-1:0] mr_alert; logic [Sp2VWidth-1:0] mr_data_in_we; dip_sel_e [Sp2VWidth-1:0] mr_data_in_prev_sel; @@ -263,6 +267,9 @@ module aes_control .prng_reseed_rate_i ( prng_reseed_rate_i ), .manual_operation_i ( manual_operation_i ), .key_touch_forces_reseed_i ( key_touch_forces_reseed_i ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe_i ), + .ctrl_gcm_we_o ( mr_ctrl_gcm_we[i] ), // AND-combine + .gcm_phase_i ( gcm_phase_i ), .start_i ( start_trigger ), .key_iv_data_in_clear_i ( key_iv_data_in_clear_i ), .data_out_clear_i ( data_out_clear_i ), @@ -354,6 +361,9 @@ module aes_control .prng_reseed_rate_i ( prng_reseed_rate_i ), .manual_operation_i ( manual_operation_i ), .key_touch_forces_reseed_i ( key_touch_forces_reseed_i ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe_i ), + .ctrl_gcm_we_o ( mr_ctrl_gcm_we[i] ), // AND-combine + .gcm_phase_i ( gcm_phase_i ), .start_i ( start_trigger ), .key_iv_data_in_clear_i ( key_iv_data_in_clear_i ), .data_out_clear_i ( data_out_clear_i ), @@ -453,6 +463,7 @@ module aes_control // AND: Only if all bits are high, the corresponding action should be triggered. assign ctrl_we_o = &mr_ctrl_we; + assign ctrl_gcm_we_o = &mr_ctrl_gcm_we; assign data_in_we_o = &mr_data_in_we; assign key_iv_data_in_clear_we_o = &mr_key_iv_data_in_clear_we; assign data_out_clear_we_o = &mr_data_out_clear_we; diff --git a/hw/ip/aes/rtl/aes_control_fsm.sv b/hw/ip/aes/rtl/aes_control_fsm.sv index 0d60b390058b04..0b394e644748a2 100644 --- a/hw/ip/aes/rtl/aes_control_fsm.sv +++ b/hw/ip/aes/rtl/aes_control_fsm.sv @@ -30,6 +30,9 @@ module aes_control_fsm input prs_rate_e prng_reseed_rate_i, input logic manual_operation_i, input logic key_touch_forces_reseed_i, + input logic ctrl_gcm_qe_i, + output logic ctrl_gcm_we_o, + input gcm_phase_e gcm_phase_i, input logic start_i, input logic key_iv_data_in_clear_i, input logic data_out_clear_i, @@ -176,6 +179,10 @@ module aes_control_fsm logic block_ctr_expr; logic block_ctr_decr; + // TODO: Use this signal to generate the controls for the various GCM phases. + gcm_phase_e unused_gcm_phase; + assign unused_gcm_phase = gcm_phase_i; + // 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], @@ -267,8 +274,9 @@ module aes_control_fsm iv_sel_o = IV_INPUT; iv_we_o = {NumSlicesCtr{1'b0}}; - // Control register - ctrl_we_o = 1'b0; + // Control registers + ctrl_we_o = 1'b0; + ctrl_gcm_we_o = 1'b0; // Alert alert_o = 1'b0; @@ -333,9 +341,11 @@ module aes_control_fsm key_init_we_o = sideload_i ? {NumSharesKey * NumRegsKey{key_sideload}} : key_init_qe_i; iv_we_o = iv_qe; - // Updates to the control register are only allowed if the core is not about to start and - // there isn't a storage error. A storage error is unrecoverable and requires a reset. - ctrl_we_o = !ctrl_err_storage_i ? ctrl_qe_i : 1'b0; + // Updates to the main and GCM control registers are only allowed if the core is not + // about to start and there isn't a storage error. A storage error is unrecoverable and + // requires a reset. + ctrl_we_o = !ctrl_err_storage_i ? ctrl_qe_i : 1'b0; + ctrl_gcm_we_o = !ctrl_err_storage_i ? ctrl_gcm_qe_i : 1'b0; // Control register updates clear all register status trackers. key_init_clear = ctrl_we_o; @@ -850,6 +860,7 @@ module aes_control_fsm AES_CFB, AES_OFB, AES_CTR, + AES_GCM, AES_NONE }) `ASSERT(AesOpValid, !ctrl_err_storage_i |-> op_i inside { diff --git a/hw/ip/aes/rtl/aes_control_fsm_n.sv b/hw/ip/aes/rtl/aes_control_fsm_n.sv index 9f0afbeb18b4fd..f61a259f949824 100644 --- a/hw/ip/aes/rtl/aes_control_fsm_n.sv +++ b/hw/ip/aes/rtl/aes_control_fsm_n.sv @@ -35,6 +35,9 @@ module aes_control_fsm_n input prs_rate_e prng_reseed_rate_i, input logic manual_operation_i, input logic key_touch_forces_reseed_i, + input logic ctrl_gcm_qe_i, + output logic ctrl_gcm_we_o, + input gcm_phase_e gcm_phase_i, input logic start_i, input logic key_iv_data_in_clear_i, input logic data_out_clear_i, @@ -134,6 +137,8 @@ module aes_control_fsm_n prng_reseed_rate_i, manual_operation_i, key_touch_forces_reseed_i, + ctrl_gcm_qe_i, + gcm_phase_i, start_i, key_iv_data_in_clear_i, data_out_clear_i, @@ -174,6 +179,8 @@ module aes_control_fsm_n prng_reseed_rate_i, manual_operation_i, key_touch_forces_reseed_i, + ctrl_gcm_qe_i, + gcm_phase_i, start_i, key_iv_data_in_clear_i, data_out_clear_i, @@ -221,6 +228,9 @@ module aes_control_fsm_n prs_rate_e prng_reseed_rate; logic manual_operation; logic key_touch_forces_reseed; + logic ctrl_gcm_qe; + gcm_phase_e gcm_phase; + logic [$bits(gcm_phase)-1:0] gcm_phase_raw; logic start; logic key_iv_data_in_clear; logic data_out_clear; @@ -257,6 +267,8 @@ module aes_control_fsm_n prng_reseed_rate, manual_operation, key_touch_forces_reseed, + ctrl_gcm_qe, + gcm_phase_raw, start, key_iv_data_in_clear, data_out_clear, @@ -284,9 +296,11 @@ module aes_control_fsm_n output_lost_in_buf} = in_buf; assign cipher_op = ciph_op_e'(cipher_op_raw); + assign gcm_phase = gcm_phase_e'(gcm_phase_raw); // Intermediate output signals logic ctrl_we; + logic ctrl_gcm_we; logic alert; logic data_in_we; logic data_out_we; @@ -350,6 +364,9 @@ module aes_control_fsm_n .prng_reseed_rate_i ( prng_reseed_rate ), .manual_operation_i ( manual_operation ), .key_touch_forces_reseed_i ( key_touch_forces_reseed ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe ), + .ctrl_gcm_we_o ( ctrl_gcm_we ), + .gcm_phase_i ( gcm_phase ), .start_i ( start ), .key_iv_data_in_clear_i ( key_iv_data_in_clear ), .data_out_clear_i ( data_out_clear ), @@ -430,6 +447,7 @@ module aes_control_fsm_n localparam int NumOutBufBits = $bits({ ctrl_we_o, + ctrl_gcm_we_o, alert_o, data_in_we_o, data_out_we_no, @@ -475,6 +493,7 @@ module aes_control_fsm_n // inverters back into the regular FSM. assign out = { ctrl_we, + ctrl_gcm_we, alert, data_in_we, ~data_out_we, @@ -524,6 +543,7 @@ module aes_control_fsm_n ); assign {ctrl_we_o, + ctrl_gcm_we_o, alert_o, data_in_we_o, data_out_we_no, diff --git a/hw/ip/aes/rtl/aes_control_fsm_p.sv b/hw/ip/aes/rtl/aes_control_fsm_p.sv index 053fdb20256b30..81684e55364871 100644 --- a/hw/ip/aes/rtl/aes_control_fsm_p.sv +++ b/hw/ip/aes/rtl/aes_control_fsm_p.sv @@ -31,6 +31,9 @@ module aes_control_fsm_p input prs_rate_e prng_reseed_rate_i, input logic manual_operation_i, input logic key_touch_forces_reseed_i, + input logic ctrl_gcm_qe_i, + output logic ctrl_gcm_we_o, + input gcm_phase_e gcm_phase_i, input logic start_i, input logic key_iv_data_in_clear_i, input logic data_out_clear_i, @@ -130,6 +133,8 @@ module aes_control_fsm_p prng_reseed_rate_i, manual_operation_i, key_touch_forces_reseed_i, + ctrl_gcm_qe_i, + gcm_phase_i, start_i, key_iv_data_in_clear_i, data_out_clear_i, @@ -170,6 +175,8 @@ module aes_control_fsm_p prng_reseed_rate_i, manual_operation_i, key_touch_forces_reseed_i, + ctrl_gcm_qe_i, + gcm_phase_i, start_i, key_iv_data_in_clear_i, data_out_clear_i, @@ -217,6 +224,9 @@ module aes_control_fsm_p prs_rate_e prng_reseed_rate; logic manual_operation; logic key_touch_forces_reseed; + logic ctrl_gcm_qe; + gcm_phase_e gcm_phase; + logic [$bits(gcm_phase)-1:0] gcm_phase_raw; logic start; logic key_iv_data_in_clear; logic data_out_clear; @@ -253,6 +263,8 @@ module aes_control_fsm_p prng_reseed_rate, manual_operation, key_touch_forces_reseed, + ctrl_gcm_qe, + gcm_phase_raw, start, key_iv_data_in_clear, data_out_clear, @@ -280,9 +292,11 @@ module aes_control_fsm_p output_lost_in_buf} = in_buf; assign cipher_op = ciph_op_e'(cipher_op_raw); + assign gcm_phase = gcm_phase_e'(gcm_phase_raw); // Intermediate output signals logic ctrl_we; + logic ctrl_gcm_we; logic alert; logic data_in_we; logic data_out_we; @@ -342,6 +356,9 @@ module aes_control_fsm_p .prng_reseed_rate_i ( prng_reseed_rate ), .manual_operation_i ( manual_operation ), .key_touch_forces_reseed_i ( key_touch_forces_reseed ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe ), + .ctrl_gcm_we_o ( ctrl_gcm_we ), + .gcm_phase_i ( gcm_phase ), .start_i ( start ), .key_iv_data_in_clear_i ( key_iv_data_in_clear ), .data_out_clear_i ( data_out_clear ), @@ -422,6 +439,7 @@ module aes_control_fsm_p localparam int NumOutBufBits = $bits({ ctrl_we_o, + ctrl_gcm_we_o, alert_o, data_in_we_o, data_out_we_o, @@ -465,6 +483,7 @@ module aes_control_fsm_p assign out = { ctrl_we, + ctrl_gcm_we, alert, data_in_we, data_out_we, @@ -514,6 +533,7 @@ module aes_control_fsm_p ); assign {ctrl_we_o, + ctrl_gcm_we_o, alert_o, data_in_we_o, data_out_we_o, diff --git a/hw/ip/aes/rtl/aes_core.sv b/hw/ip/aes/rtl/aes_core.sv index 8b9db779928e3f..a350f00059c512 100644 --- a/hw/ip/aes/rtl/aes_core.sv +++ b/hw/ip/aes/rtl/aes_core.sv @@ -11,6 +11,7 @@ module aes_core import aes_reg_pkg::*; #( parameter bit AES192Enable = 1, + parameter bit AESGCMEnable = 1, parameter bit SecMasking = 1, parameter sbox_impl_e SecSBoxImpl = SBoxImplDom, parameter int unsigned SecStartTriggerDelay = 0, @@ -70,6 +71,12 @@ module aes_core logic manual_operation_q; logic ctrl_reg_err_update; logic ctrl_reg_err_storage; + logic ctrl_gcm_qe; + logic ctrl_gcm_we; + gcm_phase_e gcm_phase_q; + logic [4:0] num_valid_bytes_q; + logic ctrl_gcm_reg_err_update; + logic ctrl_gcm_reg_err_storage; logic ctrl_err_update; logic ctrl_err_storage; logic ctrl_err_storage_d; @@ -408,7 +415,8 @@ module aes_core (aes_mode_q == AES_CBC && aes_op_q == AES_DEC) ? CIPH_INV : (aes_mode_q == AES_CFB) ? CIPH_FWD : (aes_mode_q == AES_OFB) ? CIPH_FWD : - (aes_mode_q == AES_CTR) ? CIPH_FWD : CIPH_FWD; + (aes_mode_q == AES_CTR) ? CIPH_FWD : + (aes_mode_q == AES_GCM) ? CIPH_FWD : CIPH_FWD; // This primitive is used to place a size-only constraint on the // buffers to act as a synthesis optimization barrier. @@ -552,13 +560,21 @@ module aes_core // Convert output state to output data format (every column corresponds to one output word). assign data_out_d = aes_transpose(state_out ^ add_state_out); - ////////////////////// - // Control Register // - ////////////////////// + /////////// + // GHASH // + /////////// + // TODO: Implement and integrate the GHASH block. + logic [4:0] unused_num_valid_bytes; + assign unused_num_valid_bytes = num_valid_bytes_q; + + /////////////////////// + // Control Registers // + /////////////////////// // Shadowed register primitve aes_ctrl_reg_shadowed #( - .AES192Enable ( AES192Enable ) + .AES192Enable ( AES192Enable ), + .AESGCMEnable ( AESGCMEnable ) ) u_ctrl_reg_shadowed ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -582,6 +598,23 @@ module aes_core assign key_touch_forces_reseed = reg2hw.ctrl_aux_shadowed.key_touch_forces_reseed.q; assign force_masks = reg2hw.ctrl_aux_shadowed.force_masks.q; + // GCM control register + aes_ctrl_gcm_reg_shadowed #( + .AESGCMEnable ( AESGCMEnable ) + ) u_ctrl_gcm_reg_shadowed ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .rst_shadowed_ni ( rst_shadowed_ni ), + .qe_o ( ctrl_gcm_qe ), + .we_i ( ctrl_gcm_we ), + .gcm_phase_o ( gcm_phase_q ), + .num_valid_bytes_o ( num_valid_bytes_q ), + .err_update_o ( ctrl_gcm_reg_err_update ), + .err_storage_o ( ctrl_gcm_reg_err_storage ), + .reg2hw_ctrl_gcm_i ( reg2hw.ctrl_gcm_shadowed ), + .hw2reg_ctrl_gcm_o ( hw2reg.ctrl_gcm_shadowed ) + ); + ///////////// // Control // ///////////// @@ -605,6 +638,9 @@ module aes_core .prng_reseed_rate_i ( prng_reseed_rate_q ), .manual_operation_i ( manual_operation_q ), .key_touch_forces_reseed_i ( key_touch_forces_reseed ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe ), + .ctrl_gcm_we_o ( ctrl_gcm_we ), + .gcm_phase_i ( gcm_phase_q ), .start_i ( reg2hw.trigger.start.q ), .key_iv_data_in_clear_i ( reg2hw.trigger.key_iv_data_in_clear.q ), .data_out_clear_i ( reg2hw.trigger.data_out_clear.q ), @@ -907,7 +943,7 @@ module aes_core assign clear_on_fatal = ClearStatusOnFatalAlert ? alert_fatal_o : 1'b0; // Recoverable alert conditions are signaled as a single alert event. - assign ctrl_err_update = ctrl_reg_err_update | shadowed_update_err_i; + assign ctrl_err_update = ctrl_reg_err_update | shadowed_update_err_i | ctrl_gcm_reg_err_update; assign alert_recov_o = ctrl_err_update; // The recoverable alert is observable via status register until the AES operation is restarted @@ -916,7 +952,8 @@ module aes_core assign hw2reg.status.alert_recov_ctrl_update_err.de = ctrl_err_update | ctrl_we | clear_on_fatal; // Fatal alert conditions need to remain asserted until reset. - assign ctrl_err_storage_d = ctrl_reg_err_storage | shadowed_storage_err_i; + assign ctrl_err_storage_d = + ctrl_reg_err_storage | shadowed_storage_err_i | ctrl_gcm_reg_err_storage; always_ff @(posedge clk_i or negedge rst_ni) begin : ctrl_err_storage_reg if (!rst_ni) begin ctrl_err_storage_q <= 1'b0; @@ -959,6 +996,7 @@ module aes_core AES_CFB, AES_OFB, AES_CTR, + AES_GCM, AES_NONE }) `ASSERT(AesOpValid, !ctrl_err_storage |-> aes_op_q inside { diff --git a/hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv b/hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv new file mode 100644 index 00000000000000..2bda1dcd628d87 --- /dev/null +++ b/hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv @@ -0,0 +1,173 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// AES Galois/Counter Mode (GCM) shadowed control register +// +// This module implements the shadowed AES GCM control register. The main differences compared +// to implementing the register as part of the auto-generated aes_reg_top.sv are: +// +// 1. The hardware can block updates to the GCM control register from software. +// Whenever the module is busy, GCM control register writes are ignored. +// 2. Invalid values written by software are resolved to valid configurations. + +`include "prim_assert.sv" + +module aes_ctrl_gcm_reg_shadowed + import aes_pkg::*; + import aes_reg_pkg::*; +#( + parameter bit AESGCMEnable = 1 +) ( + input logic clk_i, + input logic rst_ni, + input logic rst_shadowed_ni, + // Main control + output logic qe_o, // software wants to write + input logic we_i, // hardware grants software write + output gcm_phase_e gcm_phase_o, + output logic [4:0] num_valid_bytes_o, + + // Alerts + output logic err_update_o, + output logic err_storage_o, + + // Bus interface + input aes_reg2hw_ctrl_gcm_shadowed_reg_t reg2hw_ctrl_gcm_i, + output aes_hw2reg_ctrl_gcm_shadowed_reg_t hw2reg_ctrl_gcm_o +); + + // Signals + logic err_update_gcm_phase; + logic err_update_num_valid_bytes; + logic err_storage_gcm_phase; + logic err_storage_num_valid_bytes; + + // Get and forward write enable. Writes are only allowed if the module is idle. + assign qe_o = reg2hw_ctrl_gcm_i.phase.qe & reg2hw_ctrl_gcm_i.num_valid_bytes.qe; + + if (AESGCMEnable) begin : gen_ctrl_gcm_reg_shadowed + ctrl_gcm_reg_t ctrl_gcm_wd; + gcm_phase_e gcm_phase_reg_if, gcm_phase_d, gcm_phase_q; + logic [4:0] num_valid_bytes; + + // Get and resolve values from register interface. + assign gcm_phase_reg_if = gcm_phase_e'(reg2hw_ctrl_gcm_i.phase.q); + always_comb begin : gcm_phase_get + // Resolve unsupported input values. + unique case (gcm_phase_reg_if) + GCM_INIT: gcm_phase_d = GCM_INIT; + GCM_RESTORE: gcm_phase_d = GCM_RESTORE; + GCM_AAD: gcm_phase_d = GCM_AAD; + GCM_TEXT: gcm_phase_d = GCM_TEXT; + GCM_SAVE: gcm_phase_d = GCM_SAVE; + GCM_LEN: gcm_phase_d = GCM_LEN; + GCM_TAG: gcm_phase_d = GCM_TAG; + default: gcm_phase_d = GCM_INIT; // Unsupported values are mapped to GCM_INIT. + endcase + + // Only a subset of next phase transitions are allowed. + unique case (gcm_phase_q) + GCM_INIT: gcm_phase_d = gcm_phase_d == GCM_RESTORE || + gcm_phase_d == GCM_AAD || + gcm_phase_d == GCM_TEXT ? gcm_phase_d : gcm_phase_q; + GCM_RESTORE: gcm_phase_d = gcm_phase_d == GCM_INIT || + gcm_phase_d == GCM_AAD || + gcm_phase_d == GCM_TEXT ? gcm_phase_d : gcm_phase_q; + GCM_AAD: gcm_phase_d = gcm_phase_d == GCM_INIT || + gcm_phase_d == GCM_TEXT || + gcm_phase_d == GCM_SAVE || + gcm_phase_d == GCM_LEN ? gcm_phase_d : gcm_phase_q; + GCM_TEXT: gcm_phase_d = gcm_phase_d == GCM_INIT || + gcm_phase_d == GCM_SAVE || + gcm_phase_d == GCM_LEN ? gcm_phase_d : gcm_phase_q; + GCM_SAVE: gcm_phase_d = gcm_phase_d == GCM_INIT ? gcm_phase_d : gcm_phase_q; + GCM_LEN: gcm_phase_d = gcm_phase_d == GCM_INIT || + gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q; + GCM_TAG: gcm_phase_d = gcm_phase_d == GCM_INIT ? gcm_phase_d : gcm_phase_q; + default: gcm_phase_d = gcm_phase_q; // If we end up in an unspported value (which + // should never happen), keep it. + endcase + end + assign ctrl_gcm_wd.phase = gcm_phase_d; + + assign num_valid_bytes = reg2hw_ctrl_gcm_i.num_valid_bytes.q; + // Unsupported values are mapped to 16. + assign ctrl_gcm_wd.num_valid_bytes = num_valid_bytes != 5'd0 ? num_valid_bytes : 5'd16; + + // SEC_CM: GCM.CONFIG.SHADOW + // Instantiate one shadowed register primitive per field. An update error in a field should + // only prevent the update of the affected field. + prim_subreg_shadow #( + .DW ($bits(gcm_phase_e)), + .SwAccess(prim_subreg_pkg::SwAccessWO), + .RESVAL (AES_CTRL_GCM_SHADOWED_PHASE_RESVAL) + ) u_ctrl_gcm_reg_shadowed_phase ( + .clk_i, + .rst_ni, + .rst_shadowed_ni, + .re (reg2hw_ctrl_gcm_i.phase.re), + .we (we_i), + .wd ({ctrl_gcm_wd.phase}), + .de (1'b0), + .d ('0), + .qe (), + .q (gcm_phase_q), + .qs (), + .ds (), + .phase (), + .err_update (err_update_gcm_phase), + .err_storage(err_storage_gcm_phase) + ); + assign hw2reg_ctrl_gcm_o.phase.d = {gcm_phase_q}; + + prim_subreg_shadow #( + .DW (5), + .SwAccess(prim_subreg_pkg::SwAccessWO), + .RESVAL (AES_CTRL_GCM_SHADOWED_NUM_VALID_BYTES_RESVAL) + ) u_ctrl_gcm_reg_shadowed_num_valid_bytes ( + .clk_i, + .rst_ni, + .rst_shadowed_ni, + .re (reg2hw_ctrl_gcm_i.num_valid_bytes.re), + .we (we_i), + .wd ({ctrl_gcm_wd.num_valid_bytes}), + .de (1'b0), + .d ('0), + .qe (), + .q (hw2reg_ctrl_gcm_o.num_valid_bytes.d), + .qs (), + .ds (), + .phase (), + .err_update (err_update_num_valid_bytes), + .err_storage(err_storage_num_valid_bytes) + ); + end else begin : gen_no_ctrl_gcm_reg_shadowed + // Tie off unused inputs. + logic unsused_ctrl_gcm; + assign unsused_ctrl_gcm = ^{reg2hw_ctrl_gcm_i.phase.re, + reg2hw_ctrl_gcm_i.phase.q, + reg2hw_ctrl_gcm_i.num_valid_bytes.re, + reg2hw_ctrl_gcm_i.num_valid_bytes.q}; + + // Tie off control signals. + assign hw2reg_ctrl_gcm_o.phase.d = {GCM_INIT}; + assign hw2reg_ctrl_gcm_o.num_valid_bytes.d = 5'd16; + + // Tie off error signals. + assign err_update_gcm_phase = 1'b0; + assign err_update_num_valid_bytes = 1'b0; + assign err_storage_gcm_phase = 1'b0; + assign err_storage_num_valid_bytes = 1'b0; + end + + // Collect alerts. + assign err_update_o = err_update_gcm_phase | err_update_num_valid_bytes; + assign err_storage_o = err_storage_gcm_phase | err_storage_num_valid_bytes; + + // Generate shorter references. + // Doing that here as opposed to in aes_core avoids several Verilator lint errors. + assign gcm_phase_o = gcm_phase_e'(hw2reg_ctrl_gcm_o.phase.d); + assign num_valid_bytes_o = hw2reg_ctrl_gcm_o.num_valid_bytes.d; + +endmodule diff --git a/hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv b/hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv index 46d824008b0680..f92707bf334884 100644 --- a/hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv +++ b/hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv @@ -17,7 +17,8 @@ module aes_ctrl_reg_shadowed import aes_pkg::*; import aes_reg_pkg::*; #( - parameter bit AES192Enable = 1 + parameter bit AES192Enable = 1, + parameter bit AESGCMEnable = 1 ) ( input logic clk_i, input logic rst_ni, @@ -90,6 +91,7 @@ module aes_ctrl_reg_shadowed AES_CFB: ctrl_wd.mode = AES_CFB; AES_OFB: ctrl_wd.mode = AES_OFB; AES_CTR: ctrl_wd.mode = AES_CTR; + AES_GCM: ctrl_wd.mode = AESGCMEnable ? AES_GCM : AES_NONE; default: ctrl_wd.mode = AES_NONE; // unsupported values are mapped to AES_NONE endcase end diff --git a/hw/ip/aes/rtl/aes_pkg.sv b/hw/ip/aes/rtl/aes_pkg.sv index 0643bb88cf6059..d0112eaafbc7dd 100644 --- a/hw/ip/aes/rtl/aes_pkg.sv +++ b/hw/ip/aes/rtl/aes_pkg.sv @@ -89,6 +89,7 @@ parameter int AES_OP_WIDTH = 2; parameter int AES_MODE_WIDTH = 6; parameter int AES_KEYLEN_WIDTH = 3; parameter int AES_PRNGRESEEDRATE_WIDTH = 3; +parameter int AES_GCMPHASE_WIDTH = 7; // SEC_CM: MAIN.CONFIG.SPARSE typedef enum logic [AES_OP_WIDTH-1:0] { @@ -103,9 +104,11 @@ typedef enum logic [AES_MODE_WIDTH-1:0] { AES_CFB = 6'b00_0100, AES_OFB = 6'b00_1000, AES_CTR = 6'b01_0000, - AES_NONE = 6'b10_0000 + AES_GCM = 6'b10_0000, + AES_NONE = 6'b11_1111 } aes_mode_e; +// SEC_CM: MAIN.CONFIG.SPARSE typedef enum logic [AES_OP_WIDTH-1:0] { CIPH_FWD = 2'b01, CIPH_INV = 2'b10 @@ -126,6 +129,17 @@ typedef enum logic [AES_PRNGRESEEDRATE_WIDTH-1:0] { } prs_rate_e; parameter int unsigned BlockCtrWidth = 13; +// SEC_CM: GCM.CONFIG.SPARSE +typedef enum logic [AES_GCMPHASE_WIDTH-1:0] { + GCM_INIT = 7'b000_0001, + GCM_RESTORE = 7'b000_0010, + GCM_AAD = 7'b000_0100, + GCM_TEXT = 7'b000_1000, + GCM_SAVE = 7'b001_0000, + GCM_LEN = 7'b010_0000, + GCM_TAG = 7'b100_0000 +} gcm_phase_e; + typedef struct packed { logic [31:7] unused; logic alert_fatal_fault; @@ -453,6 +467,12 @@ parameter ctrl_reg_t CTRL_RESET = '{ operation: aes_op_e'(aes_reg_pkg::AES_CTRL_SHADOWED_OPERATION_RESVAL) }; +// GCM control register type +typedef struct packed { + logic [4:0] num_valid_bytes; + gcm_phase_e phase; +} ctrl_gcm_reg_t; + // Multiplication by {02} (i.e. x) on GF(2^8) // with field generating polynomial {01}{1b} (9'h11b) // Sometimes also denoted by xtime(). diff --git a/hw/ip/aes/rtl/aes_reg_pkg.sv b/hw/ip/aes/rtl/aes_reg_pkg.sv index 9edec48bd6c64b..33a178c384b531 100644 --- a/hw/ip/aes/rtl/aes_reg_pkg.sv +++ b/hw/ip/aes/rtl/aes_reg_pkg.sv @@ -121,6 +121,19 @@ package aes_reg_pkg; } idle; } aes_reg2hw_status_reg_t; + typedef struct packed { + struct packed { + logic [4:0] q; + logic qe; + logic re; + } num_valid_bytes; + struct packed { + logic [6:0] q; + logic qe; + logic re; + } phase; + } aes_reg2hw_ctrl_gcm_shadowed_reg_t; + typedef struct packed { logic [31:0] d; } aes_hw2reg_key_share0_mreg_t; @@ -213,30 +226,41 @@ package aes_reg_pkg; } alert_fatal_fault; } aes_hw2reg_status_reg_t; + typedef struct packed { + struct packed { + logic [6:0] d; + } phase; + struct packed { + logic [4:0] d; + } num_valid_bytes; + } aes_hw2reg_ctrl_gcm_shadowed_reg_t; + // Register -> HW type typedef struct packed { - aes_reg2hw_alert_test_reg_t alert_test; // [957:954] - aes_reg2hw_key_share0_mreg_t [7:0] key_share0; // [953:690] - aes_reg2hw_key_share1_mreg_t [7:0] key_share1; // [689:426] - aes_reg2hw_iv_mreg_t [3:0] iv; // [425:294] - aes_reg2hw_data_in_mreg_t [3:0] data_in; // [293:162] - aes_reg2hw_data_out_mreg_t [3:0] data_out; // [161:30] - aes_reg2hw_ctrl_shadowed_reg_t ctrl_shadowed; // [29:8] - aes_reg2hw_ctrl_aux_shadowed_reg_t ctrl_aux_shadowed; // [7:6] - aes_reg2hw_trigger_reg_t trigger; // [5:2] - aes_reg2hw_status_reg_t status; // [1:0] + aes_reg2hw_alert_test_reg_t alert_test; // [971:968] + aes_reg2hw_key_share0_mreg_t [7:0] key_share0; // [967:704] + aes_reg2hw_key_share1_mreg_t [7:0] key_share1; // [703:440] + aes_reg2hw_iv_mreg_t [3:0] iv; // [439:308] + aes_reg2hw_data_in_mreg_t [3:0] data_in; // [307:176] + aes_reg2hw_data_out_mreg_t [3:0] data_out; // [175:44] + aes_reg2hw_ctrl_shadowed_reg_t ctrl_shadowed; // [43:22] + aes_reg2hw_ctrl_aux_shadowed_reg_t ctrl_aux_shadowed; // [21:20] + aes_reg2hw_trigger_reg_t trigger; // [19:16] + aes_reg2hw_status_reg_t status; // [15:14] + aes_reg2hw_ctrl_gcm_shadowed_reg_t ctrl_gcm_shadowed; // [13:0] } aes_reg2hw_t; // HW -> register type typedef struct packed { - aes_hw2reg_key_share0_mreg_t [7:0] key_share0; // [937:682] - aes_hw2reg_key_share1_mreg_t [7:0] key_share1; // [681:426] - aes_hw2reg_iv_mreg_t [3:0] iv; // [425:298] - aes_hw2reg_data_in_mreg_t [3:0] data_in; // [297:166] - aes_hw2reg_data_out_mreg_t [3:0] data_out; // [165:38] - aes_hw2reg_ctrl_shadowed_reg_t ctrl_shadowed; // [37:22] - aes_hw2reg_trigger_reg_t trigger; // [21:14] - aes_hw2reg_status_reg_t status; // [13:0] + aes_hw2reg_key_share0_mreg_t [7:0] key_share0; // [949:694] + aes_hw2reg_key_share1_mreg_t [7:0] key_share1; // [693:438] + aes_hw2reg_iv_mreg_t [3:0] iv; // [437:310] + aes_hw2reg_data_in_mreg_t [3:0] data_in; // [309:178] + aes_hw2reg_data_out_mreg_t [3:0] data_out; // [177:50] + aes_hw2reg_ctrl_shadowed_reg_t ctrl_shadowed; // [49:34] + aes_hw2reg_trigger_reg_t trigger; // [33:26] + aes_hw2reg_status_reg_t status; // [25:12] + aes_hw2reg_ctrl_gcm_shadowed_reg_t ctrl_gcm_shadowed; // [11:0] } aes_hw2reg_t; // Register offsets @@ -274,6 +298,7 @@ package aes_reg_pkg; parameter logic [BlockAw-1:0] AES_CTRL_AUX_REGWEN_OFFSET = 8'h 7c; parameter logic [BlockAw-1:0] AES_TRIGGER_OFFSET = 8'h 80; parameter logic [BlockAw-1:0] AES_STATUS_OFFSET = 8'h 84; + parameter logic [BlockAw-1:0] AES_CTRL_GCM_SHADOWED_OFFSET = 8'h 88; // Reset values for hwext registers and their fields parameter logic [1:0] AES_ALERT_TEST_RESVAL = 2'h 0; @@ -327,13 +352,16 @@ package aes_reg_pkg; parameter logic [31:0] AES_DATA_OUT_2_DATA_OUT_2_RESVAL = 32'h 0; parameter logic [31:0] AES_DATA_OUT_3_RESVAL = 32'h 0; parameter logic [31:0] AES_DATA_OUT_3_DATA_OUT_3_RESVAL = 32'h 0; - parameter logic [15:0] AES_CTRL_SHADOWED_RESVAL = 16'h 1181; + parameter logic [15:0] AES_CTRL_SHADOWED_RESVAL = 16'h 11fd; parameter logic [1:0] AES_CTRL_SHADOWED_OPERATION_RESVAL = 2'h 1; - parameter logic [5:0] AES_CTRL_SHADOWED_MODE_RESVAL = 6'h 20; + parameter logic [5:0] AES_CTRL_SHADOWED_MODE_RESVAL = 6'h 3f; parameter logic [2:0] AES_CTRL_SHADOWED_KEY_LEN_RESVAL = 3'h 1; parameter logic [0:0] AES_CTRL_SHADOWED_SIDELOAD_RESVAL = 1'h 0; parameter logic [2:0] AES_CTRL_SHADOWED_PRNG_RESEED_RATE_RESVAL = 3'h 1; parameter logic [0:0] AES_CTRL_SHADOWED_MANUAL_OPERATION_RESVAL = 1'h 0; + parameter logic [12:0] AES_CTRL_GCM_SHADOWED_RESVAL = 13'h 1001; + parameter logic [6:0] AES_CTRL_GCM_SHADOWED_PHASE_RESVAL = 7'h 1; + parameter logic [4:0] AES_CTRL_GCM_SHADOWED_NUM_VALID_BYTES_RESVAL = 5'h 10; // Register index typedef enum int { @@ -370,11 +398,12 @@ package aes_reg_pkg; AES_CTRL_AUX_SHADOWED, AES_CTRL_AUX_REGWEN, AES_TRIGGER, - AES_STATUS + AES_STATUS, + AES_CTRL_GCM_SHADOWED } aes_id_e; // Register width information to check illegal writes - parameter logic [3:0] AES_PERMIT [34] = '{ + parameter logic [3:0] AES_PERMIT [35] = '{ 4'b 0001, // index[ 0] AES_ALERT_TEST 4'b 1111, // index[ 1] AES_KEY_SHARE0_0 4'b 1111, // index[ 2] AES_KEY_SHARE0_1 @@ -408,7 +437,8 @@ package aes_reg_pkg; 4'b 0001, // index[30] AES_CTRL_AUX_SHADOWED 4'b 0001, // index[31] AES_CTRL_AUX_REGWEN 4'b 0001, // index[32] AES_TRIGGER - 4'b 0001 // index[33] AES_STATUS + 4'b 0001, // index[33] AES_STATUS + 4'b 0011 // index[34] AES_CTRL_GCM_SHADOWED }; endpackage diff --git a/hw/ip/aes/rtl/aes_reg_top.sv b/hw/ip/aes/rtl/aes_reg_top.sv index 6731f93256c9b3..b327511a22298b 100644 --- a/hw/ip/aes/rtl/aes_reg_top.sv +++ b/hw/ip/aes/rtl/aes_reg_top.sv @@ -56,9 +56,9 @@ module aes_reg_top ( // also check for spurious write enables logic reg_we_err; - logic [33:0] reg_we_check; + logic [34:0] reg_we_check; prim_reg_we_check #( - .OneHotWidth(34) + .OneHotWidth(35) ) u_prim_reg_we_check ( .clk_i(clk_i), .rst_ni(rst_ni), @@ -231,6 +231,12 @@ module aes_reg_top ( logic status_input_ready_qs; logic status_alert_recov_ctrl_update_err_qs; logic status_alert_fatal_fault_qs; + logic ctrl_gcm_shadowed_re; + logic ctrl_gcm_shadowed_we; + logic [6:0] ctrl_gcm_shadowed_phase_qs; + logic [6:0] ctrl_gcm_shadowed_phase_wd; + logic [4:0] ctrl_gcm_shadowed_num_valid_bytes_qs; + logic [4:0] ctrl_gcm_shadowed_num_valid_bytes_wd; // Register instances // R[alert_test]: V(True) @@ -1429,8 +1435,45 @@ module aes_reg_top ( ); + // R[ctrl_gcm_shadowed]: V(True) + logic ctrl_gcm_shadowed_qe; + logic [1:0] ctrl_gcm_shadowed_flds_we; + assign ctrl_gcm_shadowed_qe = &ctrl_gcm_shadowed_flds_we; + // F[phase]: 6:0 + prim_subreg_ext #( + .DW (7) + ) u_ctrl_gcm_shadowed_phase ( + .re (ctrl_gcm_shadowed_re), + .we (ctrl_gcm_shadowed_we), + .wd (ctrl_gcm_shadowed_phase_wd), + .d (hw2reg.ctrl_gcm_shadowed.phase.d), + .qre (reg2hw.ctrl_gcm_shadowed.phase.re), + .qe (ctrl_gcm_shadowed_flds_we[0]), + .q (reg2hw.ctrl_gcm_shadowed.phase.q), + .ds (), + .qs (ctrl_gcm_shadowed_phase_qs) + ); + assign reg2hw.ctrl_gcm_shadowed.phase.qe = ctrl_gcm_shadowed_qe; + + // F[num_valid_bytes]: 12:8 + prim_subreg_ext #( + .DW (5) + ) u_ctrl_gcm_shadowed_num_valid_bytes ( + .re (ctrl_gcm_shadowed_re), + .we (ctrl_gcm_shadowed_we), + .wd (ctrl_gcm_shadowed_num_valid_bytes_wd), + .d (hw2reg.ctrl_gcm_shadowed.num_valid_bytes.d), + .qre (reg2hw.ctrl_gcm_shadowed.num_valid_bytes.re), + .qe (ctrl_gcm_shadowed_flds_we[1]), + .q (reg2hw.ctrl_gcm_shadowed.num_valid_bytes.q), + .ds (), + .qs (ctrl_gcm_shadowed_num_valid_bytes_qs) + ); + assign reg2hw.ctrl_gcm_shadowed.num_valid_bytes.qe = ctrl_gcm_shadowed_qe; - logic [33:0] addr_hit; + + + logic [34:0] addr_hit; always_comb begin addr_hit = '0; addr_hit[ 0] = (reg_addr == AES_ALERT_TEST_OFFSET); @@ -1467,6 +1510,7 @@ module aes_reg_top ( addr_hit[31] = (reg_addr == AES_CTRL_AUX_REGWEN_OFFSET); addr_hit[32] = (reg_addr == AES_TRIGGER_OFFSET); addr_hit[33] = (reg_addr == AES_STATUS_OFFSET); + addr_hit[34] = (reg_addr == AES_CTRL_GCM_SHADOWED_OFFSET); end assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; @@ -1507,7 +1551,8 @@ module aes_reg_top ( (addr_hit[30] & (|(AES_PERMIT[30] & ~reg_be))) | (addr_hit[31] & (|(AES_PERMIT[31] & ~reg_be))) | (addr_hit[32] & (|(AES_PERMIT[32] & ~reg_be))) | - (addr_hit[33] & (|(AES_PERMIT[33] & ~reg_be))))); + (addr_hit[33] & (|(AES_PERMIT[33] & ~reg_be))) | + (addr_hit[34] & (|(AES_PERMIT[34] & ~reg_be))))); end // Generate write-enables @@ -1628,6 +1673,12 @@ module aes_reg_top ( assign trigger_data_out_clear_wd = reg_wdata[2]; assign trigger_prng_reseed_wd = reg_wdata[3]; + assign ctrl_gcm_shadowed_re = addr_hit[34] & reg_re & !reg_error; + assign ctrl_gcm_shadowed_we = addr_hit[34] & reg_we & !reg_error; + + assign ctrl_gcm_shadowed_phase_wd = reg_wdata[6:0]; + + assign ctrl_gcm_shadowed_num_valid_bytes_wd = reg_wdata[12:8]; // Assign write-enables to checker logic vector. always_comb begin @@ -1666,6 +1717,7 @@ module aes_reg_top ( reg_we_check[31] = ctrl_aux_regwen_we; reg_we_check[32] = trigger_we; reg_we_check[33] = 1'b0; + reg_we_check[34] = ctrl_gcm_shadowed_we; end // Read data return @@ -1824,6 +1876,11 @@ module aes_reg_top ( reg_rdata_next[6] = status_alert_fatal_fault_qs; end + addr_hit[34]: begin + reg_rdata_next[6:0] = ctrl_gcm_shadowed_phase_qs; + reg_rdata_next[12:8] = ctrl_gcm_shadowed_num_valid_bytes_qs; + end + default: begin reg_rdata_next = '1; end