[aes] Ignore writes to control register when not idle

Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/hw/ip/aes/data/aes.hjson b/hw/ip/aes/data/aes.hjson
index 589789d..ce09b74 100644
--- a/hw/ip/aes/data/aes.hjson
+++ b/hw/ip/aes/data/aes.hjson
@@ -88,10 +88,14 @@
 ##############################################################################
 # control and status registers
   { name: "CTRL",
-    desc: "Control Register",
+    desc: '''
+      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.
+    '''
     swaccess: "rw",
     hwaccess: "hro",
-    hwqe: "true",
+    hwext:    "true",
+    hwqe:     "true",
     fields: [
       { bits: "0",
         name: "MODE",
diff --git a/hw/ip/aes/rtl/aes_control.sv b/hw/ip/aes/rtl/aes_control.sv
index 0b68b5e..a05acdb 100644
--- a/hw/ip/aes/rtl/aes_control.sv
+++ b/hw/ip/aes/rtl/aes_control.sv
@@ -13,8 +13,8 @@
   // Main control inputs
   input  aes_pkg::mode_e          mode_i,
   input  aes_pkg::key_len_e       key_len_i,
-  input  logic                    force_data_overwrite_i,
   input  logic                    manual_start_trigger_i,
+  input  logic                    force_data_overwrite_i,
   input  logic                    start_i,
   input  logic                    key_clear_i,
   input  logic                    data_in_clear_i,
diff --git a/hw/ip/aes/rtl/aes_core.sv b/hw/ip/aes/rtl/aes_core.sv
index ec5af2f..b4afff3 100644
--- a/hw/ip/aes/rtl/aes_core.sv
+++ b/hw/ip/aes/rtl/aes_core.sv
@@ -25,8 +25,13 @@
   logic     [7:0][31:0] key_init;
   logic     [7:0]       key_init_qe;
 
-  mode_e                mode, key_expand_mode;
-  key_len_e             key_len_q, key_len;
+  logic                 ctrl_qe;
+  logic                 ctrl_we;
+  mode_e                mode_d, mode_q;
+  key_len_e             key_len;
+  key_len_e             key_len_d, key_len_q;
+  logic                 manual_start_trigger_q;
+  logic                 force_data_overwrite_q;
 
   logic [3:0][3:0][7:0] state_init;
   logic [3:0][3:0][7:0] state_d;
@@ -54,6 +59,7 @@
   logic                 key_dec_we;
   key_dec_sel_e         key_dec_sel;
   logic     [7:0][31:0] key_expand_out;
+  mode_e                key_expand_mode;
   logic                 key_expand_step;
   logic                 key_expand_clear;
   logic           [3:0] key_expand_round;
@@ -71,9 +77,6 @@
 
   // Unused signals
   logic     [3:0][31:0] unused_data_out_q;
-  logic                 unused_mode_qe;
-  logic                 unused_manual_start_trigger_qe;
-  logic                 unused_force_data_overwrite_qe;
 
   ////////////
   // Inputs //
@@ -102,23 +105,20 @@
     end
   end
 
-  assign mode = mode_e'(reg2hw.ctrl.mode.q);
+  assign mode_d = mode_e'(reg2hw.ctrl.mode.q);
 
-  assign key_len_q = key_len_e'(reg2hw.ctrl.key_len.q);
+  assign key_len = key_len_e'(reg2hw.ctrl.key_len.q);
   always_comb begin : get_key_len
-    unique case (key_len_q)
-      AES_128: key_len = AES_128;
-      AES_256: key_len = AES_256;
-      AES_192: key_len = AES192Enable ? AES_192 : AES_128;
-      default: key_len = AES_128; // unsupported values are mapped to AES_128
+    unique case (key_len)
+      AES_128: key_len_d = AES_128;
+      AES_256: key_len_d = AES_256;
+      AES_192: key_len_d = AES192Enable ? AES_192 : AES_128;
+      default: key_len_d = AES_128; // unsupported values are mapped to AES_128
     endcase
   end
 
-  // Unused inputs
-  // key_len is hrw and hwqe, other fields of ctrl reg are hro and don't need hwqe
-  assign unused_mode_qe                 = reg2hw.ctrl.mode.qe;
-  assign unused_manual_start_trigger_qe = reg2hw.ctrl.manual_start_trigger.qe;
-  assign unused_force_data_overwrite_qe = reg2hw.ctrl.force_data_overwrite.qe;
+  assign ctrl_qe = reg2hw.ctrl.mode.qe & reg2hw.ctrl.key_len.qe &
+      reg2hw.ctrl.manual_start_trigger.qe & reg2hw.ctrl.force_data_overwrite.qe;
 
   //////////
   // Data //
@@ -147,19 +147,19 @@
 
   // Cipher data path
   aes_sub_bytes aes_sub_bytes (
-    .mode_i ( mode          ),
+    .mode_i ( mode_q        ),
     .data_i ( state_q       ),
     .data_o ( sub_bytes_out )
   );
 
   aes_shift_rows aes_shift_rows (
-    .mode_i ( mode           ),
+    .mode_i ( mode_q         ),
     .data_i ( sub_bytes_out  ),
     .data_o ( shift_rows_out )
   );
 
   aes_mix_columns aes_mix_columns (
-    .mode_i ( mode            ),
+    .mode_i ( mode_q          ),
     .data_i ( shift_rows_out  ),
     .data_o ( mix_columns_out )
   );
@@ -246,7 +246,7 @@
     .step_i    ( key_expand_step  ),
     .clear_i   ( key_expand_clear ),
     .round_i   ( key_expand_round ),
-    .key_len_i ( key_len          ),
+    .key_len_i ( key_len_q        ),
     .key_i     ( key_full_q       ),
     .key_o     ( key_expand_out   )
   );
@@ -289,10 +289,10 @@
     .clk_i                  ( clk_i                              ),
     .rst_ni                 ( rst_ni                             ),
 
-    .mode_i                 ( mode                               ),
-    .key_len_i              ( key_len                            ),
-    .force_data_overwrite_i ( reg2hw.ctrl.force_data_overwrite.q ),
-    .manual_start_trigger_i ( reg2hw.ctrl.manual_start_trigger.q ),
+    .mode_i                 ( mode_q                             ),
+    .key_len_i              ( key_len_q                          ),
+    .manual_start_trigger_i ( manual_start_trigger_q             ),
+    .force_data_overwrite_i ( force_data_overwrite_q             ),
     .start_i                ( reg2hw.trigger.start.q             ),
     .key_clear_i            ( reg2hw.trigger.key_clear.q         ),
     .data_in_clear_i        ( reg2hw.trigger.data_in_clear.q     ),
@@ -349,6 +349,23 @@
     end
   end
 
+  // Control register
+  assign ctrl_we = ctrl_qe & hw2reg.status.idle.d;
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin : ctrl_reg
+    if (!rst_ni) begin
+      mode_q                 <= AES_ENC;
+      key_len_q              <= AES_128;
+      manual_start_trigger_q <= '0;
+      force_data_overwrite_q <= '0;
+    end else if (ctrl_we) begin
+      mode_q                 <= mode_d;
+      key_len_q              <= key_len_d;
+      manual_start_trigger_q <= reg2hw.ctrl.manual_start_trigger.q;
+      force_data_overwrite_q <= reg2hw.ctrl.force_data_overwrite.q;
+    end
+  end
+
   /////////////
   // Outputs //
   /////////////
@@ -377,7 +394,6 @@
     end
   end
 
-  assign hw2reg.ctrl.key_len.d  = {key_len};
-  assign hw2reg.ctrl.key_len.de = reg2hw.ctrl.key_len.qe;
+  assign hw2reg.ctrl.key_len.d  = {key_len_q};
 
 endmodule
diff --git a/hw/ip/aes/rtl/aes_reg_pkg.sv b/hw/ip/aes/rtl/aes_reg_pkg.sv
index 9bccb69..7a49cf1 100644
--- a/hw/ip/aes/rtl/aes_reg_pkg.sv
+++ b/hw/ip/aes/rtl/aes_reg_pkg.sv
@@ -79,7 +79,6 @@
   typedef struct packed {
     struct packed {
       logic [2:0]  d;
-      logic        de;
     } key_len;
   } aes_hw2reg_ctrl_reg_t;
 
@@ -137,12 +136,12 @@
   // Internal design logic to register //
   ///////////////////////////////////////
   typedef struct packed {
-    aes_hw2reg_key_mreg_t [7:0] key; // [535:280]
-    aes_hw2reg_data_in_mreg_t [3:0] data_in; // [279:148]
-    aes_hw2reg_data_out_mreg_t [3:0] data_out; // [147:20]
-    aes_hw2reg_ctrl_reg_t ctrl; // [19:10]
-    aes_hw2reg_trigger_reg_t trigger; // [9:6]
-    aes_hw2reg_status_reg_t status; // [5:6]
+    aes_hw2reg_key_mreg_t [7:0] key; // [534:279]
+    aes_hw2reg_data_in_mreg_t [3:0] data_in; // [278:147]
+    aes_hw2reg_data_out_mreg_t [3:0] data_out; // [146:19]
+    aes_hw2reg_ctrl_reg_t ctrl; // [18:9]
+    aes_hw2reg_trigger_reg_t trigger; // [8:5]
+    aes_hw2reg_status_reg_t status; // [4:5]
   } aes_hw2reg_t;
 
   // Register Address
diff --git a/hw/ip/aes/rtl/aes_reg_top.sv b/hw/ip/aes/rtl/aes_reg_top.sv
index d02d28e..d343722 100644
--- a/hw/ip/aes/rtl/aes_reg_top.sv
+++ b/hw/ip/aes/rtl/aes_reg_top.sv
@@ -104,15 +104,19 @@
   logic ctrl_mode_qs;
   logic ctrl_mode_wd;
   logic ctrl_mode_we;
+  logic ctrl_mode_re;
   logic [2:0] ctrl_key_len_qs;
   logic [2:0] ctrl_key_len_wd;
   logic ctrl_key_len_we;
+  logic ctrl_key_len_re;
   logic ctrl_manual_start_trigger_qs;
   logic ctrl_manual_start_trigger_wd;
   logic ctrl_manual_start_trigger_we;
+  logic ctrl_manual_start_trigger_re;
   logic ctrl_force_data_overwrite_qs;
   logic ctrl_force_data_overwrite_wd;
   logic ctrl_force_data_overwrite_we;
+  logic ctrl_force_data_overwrite_re;
   logic trigger_start_qs;
   logic trigger_start_wd;
   logic trigger_start_we;
@@ -433,108 +437,64 @@
   );
 
 
-  // R[ctrl]: V(False)
+  // R[ctrl]: V(True)
 
   //   F[mode]: 0:0
-  prim_subreg #(
-    .DW      (1),
-    .SWACCESS("RW"),
-    .RESVAL  (1'h0)
+  prim_subreg_ext #(
+    .DW    (1)
   ) u_ctrl_mode (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (ctrl_mode_re),
     .we     (ctrl_mode_we),
     .wd     (ctrl_mode_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0  ),
-
-    // to internal hardware
+    .d      ('0),
+    .qre    (),
     .qe     (reg2hw.ctrl.mode.qe),
     .q      (reg2hw.ctrl.mode.q ),
-
-    // to register interface (read)
     .qs     (ctrl_mode_qs)
   );
 
 
   //   F[key_len]: 3:1
-  prim_subreg #(
-    .DW      (3),
-    .SWACCESS("RW"),
-    .RESVAL  (3'h1)
+  prim_subreg_ext #(
+    .DW    (3)
   ) u_ctrl_key_len (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (ctrl_key_len_re),
     .we     (ctrl_key_len_we),
     .wd     (ctrl_key_len_wd),
-
-    // from internal hardware
-    .de     (hw2reg.ctrl.key_len.de),
-    .d      (hw2reg.ctrl.key_len.d ),
-
-    // to internal hardware
+    .d      (hw2reg.ctrl.key_len.d),
+    .qre    (),
     .qe     (reg2hw.ctrl.key_len.qe),
     .q      (reg2hw.ctrl.key_len.q ),
-
-    // to register interface (read)
     .qs     (ctrl_key_len_qs)
   );
 
 
   //   F[manual_start_trigger]: 4:4
-  prim_subreg #(
-    .DW      (1),
-    .SWACCESS("RW"),
-    .RESVAL  (1'h0)
+  prim_subreg_ext #(
+    .DW    (1)
   ) u_ctrl_manual_start_trigger (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (ctrl_manual_start_trigger_re),
     .we     (ctrl_manual_start_trigger_we),
     .wd     (ctrl_manual_start_trigger_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0  ),
-
-    // to internal hardware
+    .d      ('0),
+    .qre    (),
     .qe     (reg2hw.ctrl.manual_start_trigger.qe),
     .q      (reg2hw.ctrl.manual_start_trigger.q ),
-
-    // to register interface (read)
     .qs     (ctrl_manual_start_trigger_qs)
   );
 
 
   //   F[force_data_overwrite]: 5:5
-  prim_subreg #(
-    .DW      (1),
-    .SWACCESS("RW"),
-    .RESVAL  (1'h0)
+  prim_subreg_ext #(
+    .DW    (1)
   ) u_ctrl_force_data_overwrite (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (ctrl_force_data_overwrite_re),
     .we     (ctrl_force_data_overwrite_we),
     .wd     (ctrl_force_data_overwrite_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0  ),
-
-    // to internal hardware
+    .d      ('0),
+    .qre    (),
     .qe     (reg2hw.ctrl.force_data_overwrite.qe),
     .q      (reg2hw.ctrl.force_data_overwrite.q ),
-
-    // to register interface (read)
     .qs     (ctrl_force_data_overwrite_qs)
   );
 
@@ -845,15 +805,19 @@
 
   assign ctrl_mode_we = addr_hit[16] & reg_we & ~wr_err;
   assign ctrl_mode_wd = reg_wdata[0];
+  assign ctrl_mode_re = addr_hit[16] && reg_re;
 
   assign ctrl_key_len_we = addr_hit[16] & reg_we & ~wr_err;
   assign ctrl_key_len_wd = reg_wdata[3:1];
+  assign ctrl_key_len_re = addr_hit[16] && reg_re;
 
   assign ctrl_manual_start_trigger_we = addr_hit[16] & reg_we & ~wr_err;
   assign ctrl_manual_start_trigger_wd = reg_wdata[4];
+  assign ctrl_manual_start_trigger_re = addr_hit[16] && reg_re;
 
   assign ctrl_force_data_overwrite_we = addr_hit[16] & reg_we & ~wr_err;
   assign ctrl_force_data_overwrite_wd = reg_wdata[5];
+  assign ctrl_force_data_overwrite_re = addr_hit[16] && reg_re;
 
   assign trigger_start_we = addr_hit[17] & reg_we & ~wr_err;
   assign trigger_start_wd = reg_wdata[0];