[hmac] Block the configuration change while processing

There were a few test failures on the sudden CFG register update during
SHA/HMAC process. A few bugs caused system hang. They blocked the
interconnect so that the software cannot release the errors.

Related commits: 14a4312 13678cf

Latest one that @cindychip found at Issue #991 also caused hang
condition inside HMAC. Rather fixing every hang condition, it seems to
be better to block the CFG update in the middle of the process. If the
software wants to update CFG, it can update CFG but it only can be
visible to the hardware after the current HMAC/SHA process is completed.

This PR also blocks the secret key update while the hash engine is
active. Secret key (KEY0 .. KEY7) can only be updated after the engine
completes the computing of hash and before the new message is fed.

If the event occurs (secret key is updated in process), the error will
be reported to the software through the ERROR FIFO.

This is related to #991

Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/hw/ip/hmac/data/hmac.hjson b/hw/ip/hmac/data/hmac.hjson
index 0adc5ea..fc2449d 100644
--- a/hw/ip/hmac/data/hmac.hjson
+++ b/hw/ip/hmac/data/hmac.hjson
@@ -31,9 +31,16 @@
   regwidth: "32",
   registers: [
     { name: "CFG",
-      desc: "HMAC Configuration register",
+      desc: '''HMAC Configuration register.
+
+            The register is updated when the engine is in Idle.
+            If the software updates the register while the engine computes the hash,
+            the updated value is discarded.
+            ''',
+      hwext:    "true",
+      hwqe:     "true",
       swaccess: "rw",
-      hwaccess: "hro",
+      hwaccess: "hrw",
       fields: [
         { bits: "0",
           name: "hmac_en",
@@ -137,9 +144,15 @@
               SHA256 assumes secret key is hashed 256bit key.
               Order of the secret key is:
               key[255:0] = {KEY0, KEY1, KEY2, ... , KEY7};
+
+              The registers are allowed to be updated when the engine is in Idle state.
+              If the engine computes the hash, it discards any attempts to update the secret keys
+              and report an error.
               ''',
         count: "NumWords",
         cname: "HMAC",
+        hwext: "true",
+        hwqe : "true",
         swaccess: "wo",
         hwaccess: "hrw",
         fields: [
diff --git a/hw/ip/hmac/doc/_index.md b/hw/ip/hmac/doc/_index.md
index 755fff1..8cef218 100644
--- a/hw/ip/hmac/doc/_index.md
+++ b/hw/ip/hmac/doc/_index.md
@@ -269,6 +269,13 @@
 }
 ```
 
+## Updating the configurations
+
+The HMAC IP prevents {{< regref "CFG" >}} and {{< regref "KEY" >}} registers from updating during the engine is processing the messages.
+The attempts are discarded.
+The {{< regref "KEY" >}} discards the attempt of the secret key access in the middle of the process.
+In case of when the software tries to update the KEY, the IP reports an error through the Error FIFO. The error code is `SwUpdateSecretKeyInProcess`, `0x0003`.
+
 ## Interrupt Handling
 
 ### FIFO_FULL
diff --git a/hw/ip/hmac/rtl/hmac.sv b/hw/ip/hmac/rtl/hmac.sv
index 15bc7a4..da306f6 100644
--- a/hw/ip/hmac/rtl/hmac.sv
+++ b/hw/ip/hmac/rtl/hmac.sv
@@ -91,6 +91,9 @@
 
   sha_word_t [7:0] digest;
 
+  hmac_reg2hw_cfg_reg_t cfg_reg;
+  logic                 cfg_block;  // Prevent changing config
+
   ///////////////////////
   // Connect registers //
   ///////////////////////
@@ -102,20 +105,40 @@
   assign wipe_secret = reg2hw.wipe_secret.qe;
   assign wipe_v      = reg2hw.wipe_secret.q;
 
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      secret_key <= '0;
+    end else if (wipe_secret) begin
+      secret_key <= secret_key ^ {8{wipe_v}};
+    end else if (!cfg_block) begin
+      // Allow updating secret key only when the engine is in Idle.
+      for (int i = 0; i < 8; i++) begin
+        if (reg2hw.key[7-i].qe) begin
+          secret_key[32*i+:32] <= reg2hw.key[7-i].q;
+        end
+      end
+    end
+  end
+
   for (genvar i = 0; i < 8; i++) begin : gen_key_digest
-    // secret key
-    assign secret_key[32*i +: 32] = reg2hw.key[7-i].q;
-    assign hw2reg.key[i].de       = wipe_secret;
-    assign hw2reg.key[7-i].d      = secret_key[32*i +: 32] ^ wipe_v;
+    assign hw2reg.key[7-i].d      = '0;
     // digest
     assign hw2reg.digest[i].d = conv_endian(digest[i], digest_swap);
   end
 
+  logic [3:0] unused_cfg_qe;
 
-  assign sha_en = reg2hw.cfg.sha_en.q;
-  assign hmac_en = reg2hw.cfg.hmac_en.q;
-  assign endian_swap = reg2hw.cfg.endian_swap.q;
-  assign digest_swap = reg2hw.cfg.digest_swap.q;
+  assign unused_cfg_qe = {cfg_reg.sha_en.qe,      cfg_reg.hmac_en.qe,
+                          cfg_reg.endian_swap.qe, cfg_reg.digest_swap.qe};
+
+  assign sha_en      = cfg_reg.sha_en.q;
+  assign hmac_en     = cfg_reg.hmac_en.q;
+  assign endian_swap = cfg_reg.endian_swap.q;
+  assign digest_swap = cfg_reg.digest_swap.q;
+  assign hw2reg.cfg.hmac_en.d     = cfg_reg.hmac_en.q;
+  assign hw2reg.cfg.sha_en.d      = cfg_reg.sha_en.q;
+  assign hw2reg.cfg.endian_swap.d = cfg_reg.endian_swap.q;
+  assign hw2reg.cfg.digest_swap.d = cfg_reg.digest_swap.q;
 
   assign reg_hash_start   = reg2hw.cmd.hash_start.qe   & reg2hw.cmd.hash_start.q;
   assign reg_hash_process = reg2hw.cmd.hash_process.qe & reg2hw.cmd.hash_process.q;
@@ -129,6 +152,23 @@
   /////////////////////
   assign hash_start = reg_hash_start & sha_en;
 
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      cfg_block <= '0;
+    end else if (hash_start) begin
+      cfg_block <= 1'b 1;
+    end else if (reg_hash_done) begin
+      cfg_block <= 1'b 0;
+    end
+  end
+  // Hold the configuration during the process
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      cfg_reg <= '{endian_swap: '{q: 1'b1, qe: 1'b0}, default:'0};
+    end else if (!cfg_block && reg2hw.cfg.hmac_en.qe) begin
+      cfg_reg <= reg2hw.cfg ;
+    end
+  end
   ////////////////
   // Interrupts //
   ////////////////
@@ -376,16 +416,30 @@
   /////////////////////////
   // HMAC Error Handling //
   /////////////////////////
-  logic msg_push_sha_disabled, hash_start_sha_disabled;
+  logic msg_push_sha_disabled, hash_start_sha_disabled, update_seckey_inprocess;
   assign msg_push_sha_disabled = msg_write & ~sha_en;
   assign hash_start_sha_disabled = reg_hash_start & ~sha_en;
 
+  always_comb begin
+    update_seckey_inprocess = 1'b0;
+    if (cfg_block) begin
+      for (int i = 0 ; i < 8 ; i++) begin
+        if (reg2hw.key[i].qe) begin
+          update_seckey_inprocess = update_seckey_inprocess | 1'b1;
+        end
+      end
+    end else begin
+      update_seckey_inprocess = 1'b0;
+    end
+  end
+
   // Update ERR_CODE register and interrupt only when no pending interrupt.
   // This ensures only the first event of the series of events can be seen to sw.
   // It is recommended that the software reads ERR_CODE register when interrupt
   // is pending to avoid any race conditions.
   assign err_valid = ~reg2hw.intr_state.hmac_err.q &
-                   ( msg_push_sha_disabled | hash_start_sha_disabled );
+                   ( msg_push_sha_disabled | hash_start_sha_disabled
+                   | update_seckey_inprocess);
 
   always_comb begin
     err_code = NoError;
@@ -397,6 +451,10 @@
         err_code = SwHashStartWhenShaDisabled;
       end
 
+      update_seckey_inprocess: begin
+        err_code = SwUpdateSecretKeyInProcess;
+      end
+
       default: begin
         err_code = NoError;
       end
diff --git a/hw/ip/hmac/rtl/hmac_pkg.sv b/hw/ip/hmac/rtl/hmac_pkg.sv
index 7050fd8..ebf7322 100644
--- a/hw/ip/hmac/rtl/hmac_pkg.sv
+++ b/hw/ip/hmac/rtl/hmac_pkg.sv
@@ -86,7 +86,8 @@
   typedef enum logic [31:0] {
     NoError                    = 32'h 0000_0000,
     SwPushMsgWhenShaDisabled   = 32'h 0000_0001,
-    SwHashStartWhenShaDisabled = 32'h 0000_0002
+    SwHashStartWhenShaDisabled = 32'h 0000_0002,
+    SwUpdateSecretKeyInProcess = 32'h 0000_0003
   } err_code_e;
 
 endpackage : hmac_pkg
diff --git a/hw/ip/hmac/rtl/hmac_reg_pkg.sv b/hw/ip/hmac/rtl/hmac_reg_pkg.sv
index f0e22e8..b10967a 100644
--- a/hw/ip/hmac/rtl/hmac_reg_pkg.sv
+++ b/hw/ip/hmac/rtl/hmac_reg_pkg.sv
@@ -54,15 +54,19 @@
   typedef struct packed {
     struct packed {
       logic        q;
+      logic        qe;
     } hmac_en;
     struct packed {
       logic        q;
+      logic        qe;
     } sha_en;
     struct packed {
       logic        q;
+      logic        qe;
     } endian_swap;
     struct packed {
       logic        q;
+      logic        qe;
     } digest_swap;
   } hmac_reg2hw_cfg_reg_t;
 
@@ -84,6 +88,7 @@
 
   typedef struct packed {
     logic [31:0] q;
+    logic        qe;
   } hmac_reg2hw_key_mreg_t;
 
 
@@ -105,6 +110,21 @@
   typedef struct packed {
     struct packed {
       logic        d;
+    } hmac_en;
+    struct packed {
+      logic        d;
+    } sha_en;
+    struct packed {
+      logic        d;
+    } endian_swap;
+    struct packed {
+      logic        d;
+    } digest_swap;
+  } hmac_hw2reg_cfg_reg_t;
+
+  typedef struct packed {
+    struct packed {
+      logic        d;
     } fifo_empty;
     struct packed {
       logic        d;
@@ -121,7 +141,6 @@
 
   typedef struct packed {
     logic [31:0] d;
-    logic        de;
   } hmac_hw2reg_key_mreg_t;
 
   typedef struct packed {
@@ -143,26 +162,27 @@
   // Register to internal design logic //
   ///////////////////////////////////////
   typedef struct packed {
-    hmac_reg2hw_intr_state_reg_t intr_state; // [308:306]
-    hmac_reg2hw_intr_enable_reg_t intr_enable; // [305:303]
-    hmac_reg2hw_intr_test_reg_t intr_test; // [302:297]
-    hmac_reg2hw_cfg_reg_t cfg; // [296:293]
-    hmac_reg2hw_cmd_reg_t cmd; // [292:289]
-    hmac_reg2hw_wipe_secret_reg_t wipe_secret; // [288:256]
-    hmac_reg2hw_key_mreg_t [7:0] key; // [255:0]
+    hmac_reg2hw_intr_state_reg_t intr_state; // [320:318]
+    hmac_reg2hw_intr_enable_reg_t intr_enable; // [317:315]
+    hmac_reg2hw_intr_test_reg_t intr_test; // [314:309]
+    hmac_reg2hw_cfg_reg_t cfg; // [308:301]
+    hmac_reg2hw_cmd_reg_t cmd; // [300:297]
+    hmac_reg2hw_wipe_secret_reg_t wipe_secret; // [296:264]
+    hmac_reg2hw_key_mreg_t [7:0] key; // [263:0]
   } hmac_reg2hw_t;
 
   ///////////////////////////////////////
   // Internal design logic to register //
   ///////////////////////////////////////
   typedef struct packed {
-    hmac_hw2reg_intr_state_reg_t intr_state; // [631:629]
-    hmac_hw2reg_status_reg_t status; // [628:629]
-    hmac_hw2reg_err_code_reg_t err_code; // [628:629]
-    hmac_hw2reg_key_mreg_t [7:0] key; // [628:365]
-    hmac_hw2reg_digest_mreg_t [7:0] digest; // [364:109]
-    hmac_hw2reg_msg_length_lower_reg_t msg_length_lower; // [108:109]
-    hmac_hw2reg_msg_length_upper_reg_t msg_length_upper; // [108:109]
+    hmac_hw2reg_intr_state_reg_t intr_state; // [627:625]
+    hmac_hw2reg_cfg_reg_t cfg; // [624:617]
+    hmac_hw2reg_status_reg_t status; // [616:617]
+    hmac_hw2reg_err_code_reg_t err_code; // [616:617]
+    hmac_hw2reg_key_mreg_t [7:0] key; // [616:361]
+    hmac_hw2reg_digest_mreg_t [7:0] digest; // [360:105]
+    hmac_hw2reg_msg_length_lower_reg_t msg_length_lower; // [104:105]
+    hmac_hw2reg_msg_length_upper_reg_t msg_length_upper; // [104:105]
   } hmac_hw2reg_t;
 
   // Register Address
diff --git a/hw/ip/hmac/rtl/hmac_reg_top.sv b/hw/ip/hmac/rtl/hmac_reg_top.sv
index d72bb4a..6310db8 100644
--- a/hw/ip/hmac/rtl/hmac_reg_top.sv
+++ b/hw/ip/hmac/rtl/hmac_reg_top.sv
@@ -142,15 +142,19 @@
   logic cfg_hmac_en_qs;
   logic cfg_hmac_en_wd;
   logic cfg_hmac_en_we;
+  logic cfg_hmac_en_re;
   logic cfg_sha_en_qs;
   logic cfg_sha_en_wd;
   logic cfg_sha_en_we;
+  logic cfg_sha_en_re;
   logic cfg_endian_swap_qs;
   logic cfg_endian_swap_wd;
   logic cfg_endian_swap_we;
+  logic cfg_endian_swap_re;
   logic cfg_digest_swap_qs;
   logic cfg_digest_swap_wd;
   logic cfg_digest_swap_we;
+  logic cfg_digest_swap_re;
   logic cmd_hash_start_wd;
   logic cmd_hash_start_we;
   logic cmd_hash_process_wd;
@@ -407,108 +411,64 @@
   );
 
 
-  // R[cfg]: V(False)
+  // R[cfg]: V(True)
 
   //   F[hmac_en]: 0:0
-  prim_subreg #(
-    .DW      (1),
-    .SWACCESS("RW"),
-    .RESVAL  (1'h0)
+  prim_subreg_ext #(
+    .DW    (1)
   ) u_cfg_hmac_en (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (cfg_hmac_en_re),
     .we     (cfg_hmac_en_we),
     .wd     (cfg_hmac_en_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0  ),
-
-    // to internal hardware
-    .qe     (),
+    .d      (hw2reg.cfg.hmac_en.d),
+    .qre    (),
+    .qe     (reg2hw.cfg.hmac_en.qe),
     .q      (reg2hw.cfg.hmac_en.q ),
-
-    // to register interface (read)
     .qs     (cfg_hmac_en_qs)
   );
 
 
   //   F[sha_en]: 1:1
-  prim_subreg #(
-    .DW      (1),
-    .SWACCESS("RW"),
-    .RESVAL  (1'h0)
+  prim_subreg_ext #(
+    .DW    (1)
   ) u_cfg_sha_en (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (cfg_sha_en_re),
     .we     (cfg_sha_en_we),
     .wd     (cfg_sha_en_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0  ),
-
-    // to internal hardware
-    .qe     (),
+    .d      (hw2reg.cfg.sha_en.d),
+    .qre    (),
+    .qe     (reg2hw.cfg.sha_en.qe),
     .q      (reg2hw.cfg.sha_en.q ),
-
-    // to register interface (read)
     .qs     (cfg_sha_en_qs)
   );
 
 
   //   F[endian_swap]: 2:2
-  prim_subreg #(
-    .DW      (1),
-    .SWACCESS("RW"),
-    .RESVAL  (1'h1)
+  prim_subreg_ext #(
+    .DW    (1)
   ) u_cfg_endian_swap (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (cfg_endian_swap_re),
     .we     (cfg_endian_swap_we),
     .wd     (cfg_endian_swap_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0  ),
-
-    // to internal hardware
-    .qe     (),
+    .d      (hw2reg.cfg.endian_swap.d),
+    .qre    (),
+    .qe     (reg2hw.cfg.endian_swap.qe),
     .q      (reg2hw.cfg.endian_swap.q ),
-
-    // to register interface (read)
     .qs     (cfg_endian_swap_qs)
   );
 
 
   //   F[digest_swap]: 3:3
-  prim_subreg #(
-    .DW      (1),
-    .SWACCESS("RW"),
-    .RESVAL  (1'h0)
+  prim_subreg_ext #(
+    .DW    (1)
   ) u_cfg_digest_swap (
-    .clk_i   (clk_i    ),
-    .rst_ni  (rst_ni  ),
-
-    // from register interface
+    .re     (cfg_digest_swap_re),
     .we     (cfg_digest_swap_we),
     .wd     (cfg_digest_swap_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0  ),
-
-    // to internal hardware
-    .qe     (),
+    .d      (hw2reg.cfg.digest_swap.d),
+    .qre    (),
+    .qe     (reg2hw.cfg.digest_swap.qe),
     .q      (reg2hw.cfg.digest_swap.q ),
-
-    // to register interface (read)
     .qs     (cfg_digest_swap_qs)
   );
 
@@ -636,210 +596,130 @@
 
 
   // 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
-    .qe     (),
+    .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
-    .qe     (),
+    .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
-    .qe     (),
+    .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
-    .qe     (),
+    .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
-    .qe     (),
+    .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
-    .qe     (),
+    .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
-    .qe     (),
+    .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
-    .qe     (),
+    .d      (hw2reg.key[7].d),
+    .qre    (),
+    .qe     (reg2hw.key[7].qe),
     .q      (reg2hw.key[7].q ),
-
     .qs     ()
   );
 
@@ -1121,15 +1001,19 @@
 
   assign cfg_hmac_en_we = addr_hit[3] & reg_we & ~wr_err;
   assign cfg_hmac_en_wd = reg_wdata[0];
+  assign cfg_hmac_en_re = addr_hit[3] && reg_re;
 
   assign cfg_sha_en_we = addr_hit[3] & reg_we & ~wr_err;
   assign cfg_sha_en_wd = reg_wdata[1];
+  assign cfg_sha_en_re = addr_hit[3] && reg_re;
 
   assign cfg_endian_swap_we = addr_hit[3] & reg_we & ~wr_err;
   assign cfg_endian_swap_wd = reg_wdata[2];
+  assign cfg_endian_swap_re = addr_hit[3] && reg_re;
 
   assign cfg_digest_swap_we = addr_hit[3] & reg_we & ~wr_err;
   assign cfg_digest_swap_wd = reg_wdata[3];
+  assign cfg_digest_swap_re = addr_hit[3] && reg_re;
 
   assign cmd_hash_start_we = addr_hit[4] & reg_we & ~wr_err;
   assign cmd_hash_start_wd = reg_wdata[0];