[aes] Ignore writes to key 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 9171216..589789d 100644
--- a/hw/ip/aes/data/aes.hjson
+++ b/hw/ip/aes/data/aes.hjson
@@ -30,13 +30,15 @@
       desc: '''
         Initial Key Registers. Loaded into the internal Full Key register upon
         starting encryption/decryption of the next block. Can only be updated
-        when the AES unit is idle. All keys registers must be updated when the
+        when the AES unit is idle. If the AES unit is non-idle, writes to these
+        registers are ignored. All key registers must be updated when the
         key is changed, regardless of key length (write 0 for unusued bits).
       '''
       count: "NumRegsKey",
       cname: "KEY",
       swaccess: "wo",
       hwaccess: "hrw",
+      hwext:    "true",
       hwqe:     "true",
       fields: [
         { bits: "31:0", name: "key", desc: "Initial Key" }
diff --git a/hw/ip/aes/rtl/aes_control.sv b/hw/ip/aes/rtl/aes_control.sv
index 701193e..0b68b5e 100644
--- a/hw/ip/aes/rtl/aes_control.sv
+++ b/hw/ip/aes/rtl/aes_control.sv
@@ -32,6 +32,8 @@
 
   // Control outputs key expand data path
   output aes_pkg::mode_e          key_expand_mode_o,
+  output aes_pkg::key_init_sel_e  key_init_sel_o,
+  output logic [7:0]              key_init_we_o,
   output aes_pkg::key_full_sel_e  key_full_sel_o,
   output logic                    key_full_we_o,
   output aes_pkg::key_dec_sel_e   key_dec_sel_o,
@@ -43,7 +45,6 @@
   output aes_pkg::round_key_sel_e round_key_sel_o,
 
   // Key/data registers
-  output logic                    key_we_o,
   output logic                    data_in_we_o,
   output logic                    data_out_we_o,
 
@@ -82,6 +83,7 @@
   logic       data_in_new;
   logic       data_in_load;
 
+  logic       key_init_clear;
   logic [7:0] key_init_new_d, key_init_new_q;
   logic       key_init_new;
   logic       dec_key_gen;
@@ -112,6 +114,8 @@
     add_rk_sel_o = ADD_RK_ROUND;
 
     // Key expand data path
+    key_init_sel_o     = KEY_INIT_INPUT;
+    key_init_we_o      = 8'h00;
     key_full_sel_o     = KEY_FULL_ROUND;
     key_full_we_o      = 1'b0;
     key_dec_sel_o      = KEY_DEC_EXPAND;
@@ -136,7 +140,6 @@
     // Key, data I/O register control
     dec_key_gen   = 1'b0;
     data_in_load  = 1'b0;
-    key_we_o      = 1'b0;
     data_in_we_o  = 1'b0;
     data_out_we_o = 1'b0;
 
@@ -191,6 +194,8 @@
 
           aes_ctrl_ns = CLEAR;
         end
+
+        key_init_we_o = idle_o ? key_init_qe_i : 8'h00;
       end
 
       INIT: begin
@@ -353,7 +358,8 @@
 
       CLEAR: begin
         if (key_clear_i) begin
-          key_we_o       = 1'b1;
+          key_init_sel_o = KEY_INIT_CLEAR;
+          key_init_we_o  = 8'hFF;
           key_full_sel_o = KEY_FULL_CLEAR;
           key_full_we_o  = 1'b1;
           key_dec_sel_o  = KEY_DEC_CLEAR;
@@ -398,7 +404,8 @@
 
   // Detect new key, new input, output read
   // Edge detectors are cleared by the FSM
-  assign key_init_new_d = (dec_key_gen | key_we_o) ? '0 : (key_init_new_q | key_init_qe_i);
+  assign key_init_clear = (key_init_sel_o == KEY_INIT_CLEAR) & (&key_init_we_o);
+  assign key_init_new_d = (dec_key_gen | key_init_clear) ? '0 : (key_init_new_q | key_init_qe_i);
   assign key_init_new   = &key_init_new_d;
 
   assign data_in_new_d = (data_in_load | data_in_we_o) ? '0 : (data_in_new_q | data_in_qe_i);
diff --git a/hw/ip/aes/rtl/aes_core.sv b/hw/ip/aes/rtl/aes_core.sv
index 2f1a565..ec5af2f 100644
--- a/hw/ip/aes/rtl/aes_core.sv
+++ b/hw/ip/aes/rtl/aes_core.sv
@@ -22,7 +22,6 @@
   logic     [3:0][31:0] data_in;
   logic     [3:0]       data_in_qe;
   logic                 data_in_we;
-  logic                 key_we;
   logic     [7:0][31:0] key_init;
   logic     [7:0]       key_init_qe;
 
@@ -42,6 +41,10 @@
   logic [3:0][3:0][7:0] add_round_key_out;
   add_rk_sel_e          add_round_key_in_sel;
 
+  logic     [7:0][31:0] key_init_d;
+  logic     [7:0][31:0] key_init_q;
+  logic     [7:0]       key_init_we;
+  key_init_sel_e        key_init_sel;
   logic     [7:0][31:0] key_full_d;
   logic     [7:0][31:0] key_full_q;
   logic                 key_full_we;
@@ -176,10 +179,31 @@
   // Key //
   /////////
 
+  // Initial Key registers
+  always_comb begin : key_init_mux
+    unique case (key_init_sel)
+      KEY_INIT_INPUT: key_init_d = key_init;
+      KEY_INIT_CLEAR: key_init_d = '0;
+      default:        key_init_d = 'X;
+    endcase
+  end
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin : key_init_reg
+    if (!rst_ni) begin
+      key_init_q <= '0;
+    end else begin
+      for (int i=0; i<8; i++) begin
+        if (key_init_we[i]) begin
+          key_init_q[i] <= key_init_d[i];
+        end
+      end
+    end
+  end
+
   // Full Key registers
   always_comb begin : key_full_mux
     unique case (key_full_sel)
-      KEY_FULL_ENC_INIT: key_full_d = key_init;
+      KEY_FULL_ENC_INIT: key_full_d = key_init_q;
       KEY_FULL_DEC_INIT: key_full_d = key_dec_q;
       KEY_FULL_ROUND:    key_full_d = key_expand_out;
       KEY_FULL_CLEAR:    key_full_d = '0;
@@ -281,7 +305,10 @@
     .state_sel_o            ( state_sel                          ),
     .state_we_o             ( state_we                           ),
     .add_rk_sel_o           ( add_round_key_in_sel               ),
+
     .key_expand_mode_o      ( key_expand_mode                    ),
+    .key_init_sel_o         ( key_init_sel                       ),
+    .key_init_we_o          ( key_init_we                        ),
     .key_full_sel_o         ( key_full_sel                       ),
     .key_full_we_o          ( key_full_we                        ),
     .key_dec_sel_o          ( key_dec_sel                        ),
@@ -292,7 +319,6 @@
     .key_words_sel_o        ( key_words_sel                      ),
     .round_key_sel_o        ( round_key_sel                      ),
 
-    .key_we_o               ( key_we                             ),
     .data_in_we_o           ( data_in_we                         ),
     .data_out_we_o          ( data_out_we                        ),
 
@@ -315,14 +341,7 @@
     .stall_we_o             ( hw2reg.status.stall.de             )
   );
 
-  // Key and input data register clear
-  always_comb begin : key_reg_clear
-    for (int i=0; i<8; i++) begin
-      hw2reg.key[i].d  = '0;
-      hw2reg.key[i].de = key_we;
-    end
-  end
-
+  // Input data register clear
   always_comb begin : data_in_reg_clear
     for (int i=0; i<4; i++) begin
       hw2reg.data_in[i].d  = '0;
@@ -346,6 +365,12 @@
   end
 
   // Outputs
+  always_comb begin : key_reg_put
+    for (int i=0; i<8; i++) begin
+      hw2reg.key[i].d  = key_init_q[i];
+    end
+  end
+
   always_comb begin : data_out_put
     for (int i=0; i<4; i++) begin
       hw2reg.data_out[i].d = data_out_q[i];
diff --git a/hw/ip/aes/rtl/aes_pkg.sv b/hw/ip/aes/rtl/aes_pkg.sv
index 004bb5d..ebaf949 100644
--- a/hw/ip/aes/rtl/aes_pkg.sv
+++ b/hw/ip/aes/rtl/aes_pkg.sv
@@ -29,6 +29,11 @@
   ADD_RK_FINAL
 } add_rk_sel_e;
 
+typedef enum logic {
+  KEY_INIT_INPUT,
+  KEY_INIT_CLEAR
+} key_init_sel_e;
+
 typedef enum logic [1:0] {
   KEY_FULL_ENC_INIT,
   KEY_FULL_DEC_INIT,
diff --git a/hw/ip/aes/rtl/aes_reg_pkg.sv b/hw/ip/aes/rtl/aes_reg_pkg.sv
index 9d6587d..9bccb69 100644
--- a/hw/ip/aes/rtl/aes_reg_pkg.sv
+++ b/hw/ip/aes/rtl/aes_reg_pkg.sv
@@ -65,7 +65,6 @@
 
   typedef struct packed {
     logic [31:0] d;
-    logic        de;
   } aes_hw2reg_key_mreg_t;
 
   typedef struct packed {
@@ -138,7 +137,7 @@
   // Internal design logic to register //
   ///////////////////////////////////////
   typedef struct packed {
-    aes_hw2reg_key_mreg_t [7:0] key; // [543:280]
+    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]
diff --git a/hw/ip/aes/rtl/aes_reg_top.sv b/hw/ip/aes/rtl/aes_reg_top.sv
index 646a3eb..d02d28e 100644
--- a/hw/ip/aes/rtl/aes_reg_top.sv
+++ b/hw/ip/aes/rtl/aes_reg_top.sv
@@ -133,210 +133,130 @@
   // Register instances
 
   // Subregister 0 of Multireg key
-  // R[key0]: V(False)
+  // R[key0]: V(True)
 
-  prim_subreg #(
-    .DW      (32),
-    .SWACCESS("WO"),
-    .RESVAL  (32'h0)
+  prim_subreg_ext #(
+    .DW    (32)
   ) u_key0 (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (1'b0),
     .we     (key0_we),
     .wd     (key0_wd),
-
-    // from internal hardware
-    .de     (hw2reg.key[0].de),
-    .d      (hw2reg.key[0].d ),
-
-    // to internal hardware
+    .d      (hw2reg.key[0].d),
+    .qre    (),
     .qe     (reg2hw.key[0].qe),
     .q      (reg2hw.key[0].q ),
-
     .qs     ()
   );
 
   // Subregister 1 of Multireg key
-  // R[key1]: V(False)
+  // R[key1]: V(True)
 
-  prim_subreg #(
-    .DW      (32),
-    .SWACCESS("WO"),
-    .RESVAL  (32'h0)
+  prim_subreg_ext #(
+    .DW    (32)
   ) u_key1 (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (1'b0),
     .we     (key1_we),
     .wd     (key1_wd),
-
-    // from internal hardware
-    .de     (hw2reg.key[1].de),
-    .d      (hw2reg.key[1].d ),
-
-    // to internal hardware
+    .d      (hw2reg.key[1].d),
+    .qre    (),
     .qe     (reg2hw.key[1].qe),
     .q      (reg2hw.key[1].q ),
-
     .qs     ()
   );
 
   // Subregister 2 of Multireg key
-  // R[key2]: V(False)
+  // R[key2]: V(True)
 
-  prim_subreg #(
-    .DW      (32),
-    .SWACCESS("WO"),
-    .RESVAL  (32'h0)
+  prim_subreg_ext #(
+    .DW    (32)
   ) u_key2 (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (1'b0),
     .we     (key2_we),
     .wd     (key2_wd),
-
-    // from internal hardware
-    .de     (hw2reg.key[2].de),
-    .d      (hw2reg.key[2].d ),
-
-    // to internal hardware
+    .d      (hw2reg.key[2].d),
+    .qre    (),
     .qe     (reg2hw.key[2].qe),
     .q      (reg2hw.key[2].q ),
-
     .qs     ()
   );
 
   // Subregister 3 of Multireg key
-  // R[key3]: V(False)
+  // R[key3]: V(True)
 
-  prim_subreg #(
-    .DW      (32),
-    .SWACCESS("WO"),
-    .RESVAL  (32'h0)
+  prim_subreg_ext #(
+    .DW    (32)
   ) u_key3 (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (1'b0),
     .we     (key3_we),
     .wd     (key3_wd),
-
-    // from internal hardware
-    .de     (hw2reg.key[3].de),
-    .d      (hw2reg.key[3].d ),
-
-    // to internal hardware
+    .d      (hw2reg.key[3].d),
+    .qre    (),
     .qe     (reg2hw.key[3].qe),
     .q      (reg2hw.key[3].q ),
-
     .qs     ()
   );
 
   // Subregister 4 of Multireg key
-  // R[key4]: V(False)
+  // R[key4]: V(True)
 
-  prim_subreg #(
-    .DW      (32),
-    .SWACCESS("WO"),
-    .RESVAL  (32'h0)
+  prim_subreg_ext #(
+    .DW    (32)
   ) u_key4 (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (1'b0),
     .we     (key4_we),
     .wd     (key4_wd),
-
-    // from internal hardware
-    .de     (hw2reg.key[4].de),
-    .d      (hw2reg.key[4].d ),
-
-    // to internal hardware
+    .d      (hw2reg.key[4].d),
+    .qre    (),
     .qe     (reg2hw.key[4].qe),
     .q      (reg2hw.key[4].q ),
-
     .qs     ()
   );
 
   // Subregister 5 of Multireg key
-  // R[key5]: V(False)
+  // R[key5]: V(True)
 
-  prim_subreg #(
-    .DW      (32),
-    .SWACCESS("WO"),
-    .RESVAL  (32'h0)
+  prim_subreg_ext #(
+    .DW    (32)
   ) u_key5 (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (1'b0),
     .we     (key5_we),
     .wd     (key5_wd),
-
-    // from internal hardware
-    .de     (hw2reg.key[5].de),
-    .d      (hw2reg.key[5].d ),
-
-    // to internal hardware
+    .d      (hw2reg.key[5].d),
+    .qre    (),
     .qe     (reg2hw.key[5].qe),
     .q      (reg2hw.key[5].q ),
-
     .qs     ()
   );
 
   // Subregister 6 of Multireg key
-  // R[key6]: V(False)
+  // R[key6]: V(True)
 
-  prim_subreg #(
-    .DW      (32),
-    .SWACCESS("WO"),
-    .RESVAL  (32'h0)
+  prim_subreg_ext #(
+    .DW    (32)
   ) u_key6 (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (1'b0),
     .we     (key6_we),
     .wd     (key6_wd),
-
-    // from internal hardware
-    .de     (hw2reg.key[6].de),
-    .d      (hw2reg.key[6].d ),
-
-    // to internal hardware
+    .d      (hw2reg.key[6].d),
+    .qre    (),
     .qe     (reg2hw.key[6].qe),
     .q      (reg2hw.key[6].q ),
-
     .qs     ()
   );
 
   // Subregister 7 of Multireg key
-  // R[key7]: V(False)
+  // R[key7]: V(True)
 
-  prim_subreg #(
-    .DW      (32),
-    .SWACCESS("WO"),
-    .RESVAL  (32'h0)
+  prim_subreg_ext #(
+    .DW    (32)
   ) u_key7 (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (1'b0),
     .we     (key7_we),
     .wd     (key7_wd),
-
-    // from internal hardware
-    .de     (hw2reg.key[7].de),
-    .d      (hw2reg.key[7].d ),
-
-    // to internal hardware
+    .d      (hw2reg.key[7].d),
+    .qre    (),
     .qe     (reg2hw.key[7].qe),
     .q      (reg2hw.key[7].q ),
-
     .qs     ()
   );