blob: 0fa6070d6f716d833783013cd2ebea0986914277 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// AES shadowed control register
//
// This module implements the AES shadowed 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 control register from software.
// Whenever the module is busy, control register writes are ignored.
// 2. Invalid values written by software are resolved to valid configurations.
`include "prim_assert.sv"
module aes_ctrl_reg_shadowed
import aes_pkg::*;
import aes_reg_pkg::*;
#(
parameter bit AES192Enable = 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 logic phase_o,
output aes_op_e operation_o,
output aes_mode_e mode_o,
output key_len_e key_len_o,
output logic sideload_o,
output prs_rate_e prng_reseed_rate_o,
output logic manual_operation_o,
// Alerts
output logic err_update_o,
output logic err_storage_o,
// Bus interface
input aes_reg2hw_ctrl_shadowed_reg_t reg2hw_ctrl_i,
output aes_hw2reg_ctrl_shadowed_reg_t hw2reg_ctrl_o
);
// Signals
ctrl_reg_t ctrl_wd;
aes_op_e op;
aes_mode_e mode;
key_len_e key_len;
prs_rate_e prng_reseed_rate;
logic phase_operation;
logic phase_mode;
logic phase_key_len;
logic phase_key_sideload;
logic phase_prng_reseed_rate;
logic phase_manual_operation;
logic err_update_operation;
logic err_update_mode;
logic err_update_key_len;
logic err_update_sideload;
logic err_update_prng_reseed_rate;
logic err_update_manual_operation;
logic err_storage_operation;
logic err_storage_mode;
logic err_storage_key_len;
logic err_storage_sideload;
logic err_storage_prng_reseed_rate;
logic err_storage_manual_operation;
// Get and forward write enable. Writes are only allowed if the module is idle.
assign qe_o = reg2hw_ctrl_i.operation.qe & reg2hw_ctrl_i.mode.qe &
reg2hw_ctrl_i.key_len.qe & reg2hw_ctrl_i.sideload.qe &
reg2hw_ctrl_i.prng_reseed_rate.qe & reg2hw_ctrl_i.manual_operation.qe;
// Get and resolve values from register interface.
assign op = aes_op_e'(reg2hw_ctrl_i.operation.q);
always_comb begin : operation_get
unique case (op)
AES_ENC: ctrl_wd.operation = AES_ENC;
AES_DEC: ctrl_wd.operation = AES_DEC;
default: ctrl_wd.operation = AES_ENC; // unsupported values are mapped to AES_ENC
endcase
end
assign mode = aes_mode_e'(reg2hw_ctrl_i.mode.q);
always_comb begin : mode_get
unique case (mode)
AES_ECB: ctrl_wd.mode = AES_ECB;
AES_CBC: ctrl_wd.mode = AES_CBC;
AES_CFB: ctrl_wd.mode = AES_CFB;
AES_OFB: ctrl_wd.mode = AES_OFB;
AES_CTR: ctrl_wd.mode = AES_CTR;
default: ctrl_wd.mode = AES_NONE; // unsupported values are mapped to AES_NONE
endcase
end
assign key_len = key_len_e'(reg2hw_ctrl_i.key_len.q);
always_comb begin : key_len_get
unique case (key_len)
AES_128: ctrl_wd.key_len = AES_128;
AES_256: ctrl_wd.key_len = AES_256;
AES_192: ctrl_wd.key_len = AES192Enable ? AES_192 : AES_256;
default: ctrl_wd.key_len = AES_256; // unsupported values are mapped to AES_256
endcase
end
assign ctrl_wd.sideload = reg2hw_ctrl_i.sideload.q;
assign prng_reseed_rate = prs_rate_e'(reg2hw_ctrl_i.prng_reseed_rate.q);
always_comb begin : prng_reseed_rate_get
unique case (prng_reseed_rate)
PER_1: ctrl_wd.prng_reseed_rate = PER_1;
PER_64: ctrl_wd.prng_reseed_rate = PER_64;
PER_8K: ctrl_wd.prng_reseed_rate = PER_8K;
default: ctrl_wd.prng_reseed_rate = PER_1; // unsupported values are mapped to PER_1.
endcase
end
assign ctrl_wd.manual_operation = reg2hw_ctrl_i.manual_operation.q;
// SEC_CM: MAIN.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(aes_op_e)),
.SwAccess(prim_subreg_pkg::SwAccessWO),
.RESVAL (AES_CTRL_SHADOWED_OPERATION_RESVAL)
) u_ctrl_reg_shadowed_operation (
.clk_i,
.rst_ni,
.rst_shadowed_ni,
.re (reg2hw_ctrl_i.operation.re),
.we (we_i),
.wd ({ctrl_wd.operation}),
.de (1'b0),
.d ('0),
.qe (),
.q (hw2reg_ctrl_o.operation.d),
.qs (),
.ds (),
.phase (phase_operation),
.err_update (err_update_operation),
.err_storage(err_storage_operation)
);
prim_subreg_shadow #(
.DW ($bits(aes_mode_e)),
.SwAccess(prim_subreg_pkg::SwAccessWO),
.RESVAL (AES_CTRL_SHADOWED_MODE_RESVAL)
) u_ctrl_reg_shadowed_mode (
.clk_i,
.rst_ni,
.rst_shadowed_ni,
.re (reg2hw_ctrl_i.mode.re),
.we (we_i),
.wd ({ctrl_wd.mode}),
.de (1'b0),
.d ('0),
.qe (),
.q (hw2reg_ctrl_o.mode.d),
.qs (),
.ds (),
.phase (phase_mode),
.err_update (err_update_mode),
.err_storage(err_storage_mode)
);
prim_subreg_shadow #(
.DW ($bits(key_len_e)),
.SwAccess(prim_subreg_pkg::SwAccessWO),
.RESVAL (AES_CTRL_SHADOWED_KEY_LEN_RESVAL)
) u_ctrl_reg_shadowed_key_len (
.clk_i,
.rst_ni,
.rst_shadowed_ni,
.re (reg2hw_ctrl_i.key_len.re),
.we (we_i),
.wd ({ctrl_wd.key_len}),
.de (1'b0),
.d ('0),
.qe (),
.q (hw2reg_ctrl_o.key_len.d),
.qs (),
.ds (),
.phase (phase_key_len),
.err_update (err_update_key_len),
.err_storage(err_storage_key_len)
);
prim_subreg_shadow #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessWO),
.RESVAL (AES_CTRL_SHADOWED_SIDELOAD_RESVAL)
) u_ctrl_reg_shadowed_sideload (
.clk_i,
.rst_ni,
.rst_shadowed_ni,
.re (reg2hw_ctrl_i.sideload.re),
.we (we_i),
.wd (ctrl_wd.sideload),
.de (1'b0),
.d ('0),
.qe (),
.q (hw2reg_ctrl_o.sideload.d),
.qs (),
.ds (),
.phase (phase_key_sideload),
.err_update (err_update_sideload),
.err_storage(err_storage_sideload)
);
prim_subreg_shadow #(
.DW ($bits(prs_rate_e)),
.SwAccess(prim_subreg_pkg::SwAccessWO),
.RESVAL (AES_CTRL_SHADOWED_PRNG_RESEED_RATE_RESVAL)
) u_ctrl_reg_shadowed_prng_reseed_rate (
.clk_i,
.rst_ni,
.rst_shadowed_ni,
.re (reg2hw_ctrl_i.prng_reseed_rate.re),
.we (we_i),
.wd ({ctrl_wd.prng_reseed_rate}),
.de (1'b0),
.d ('0),
.qe (),
.q (hw2reg_ctrl_o.prng_reseed_rate.d),
.qs (),
.ds (),
.phase (phase_prng_reseed_rate),
.err_update (err_update_prng_reseed_rate),
.err_storage(err_storage_prng_reseed_rate)
);
prim_subreg_shadow #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessWO),
.RESVAL (AES_CTRL_SHADOWED_MANUAL_OPERATION_RESVAL)
) u_ctrl_reg_shadowed_manual_operation (
.clk_i,
.rst_ni,
.rst_shadowed_ni,
.re (reg2hw_ctrl_i.manual_operation.re),
.we (we_i),
.wd (ctrl_wd.manual_operation),
.de (1'b0),
.d ('0),
.qe (),
.q (hw2reg_ctrl_o.manual_operation.d),
.qs (),
.ds (),
.phase (phase_manual_operation),
.err_update (err_update_manual_operation),
.err_storage(err_storage_manual_operation)
);
// Collect phase signals.
assign phase_o = phase_operation | phase_mode | phase_key_len | phase_key_sideload |
phase_prng_reseed_rate | phase_manual_operation;
// Collect alerts.
assign err_update_o = err_update_operation | err_update_mode | err_update_key_len |
err_update_sideload | err_update_prng_reseed_rate | err_update_manual_operation;
assign err_storage_o = err_storage_operation | err_storage_mode | err_storage_key_len |
err_storage_sideload | err_storage_prng_reseed_rate | err_storage_manual_operation;
// Generate shorter references.
// Doing that here as opposed to in aes_core avoids several Verilator lint errors.
assign operation_o = aes_op_e'(hw2reg_ctrl_o.operation.d);
assign mode_o = aes_mode_e'(hw2reg_ctrl_o.mode.d);
assign key_len_o = key_len_e'(hw2reg_ctrl_o.key_len.d);
assign sideload_o = hw2reg_ctrl_o.sideload.d;
assign prng_reseed_rate_o = prs_rate_e'(hw2reg_ctrl_o.prng_reseed_rate.d);
assign manual_operation_o = hw2reg_ctrl_o.manual_operation.d;
endmodule