[util, reggen] Support standardized cdc handling for regfile

- Support two asynchronous schemes on regfile
  - Fully asynchronous - a tlul_fifo_async directly instantiated in regfile
  - Mixed asynchronous - allow user to selectively mark registers as async
  - These two schemes are mutually exclusive

- Add an 'async' key for bus interfaces to indicate the reg block is fully asynchornous
- Add an 'async' key per register to indicate register clock domain
- Add extra clock/reset ports to reg module
- Add prim_subreg_cdc to handle regiser domain clock crossing

Signed-off-by: Timothy Chen <timothytim@google.com>

[aon_timer] Updates to aon_timer to experiment with new cdc scheme

Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/adc_ctrl/rtl/adc_ctrl_reg_top.sv b/hw/ip/adc_ctrl/rtl/adc_ctrl_reg_top.sv
index c662ced..13b41df 100644
--- a/hw/ip/adc_ctrl/rtl/adc_ctrl_reg_top.sv
+++ b/hw/ip/adc_ctrl/rtl/adc_ctrl_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -3536,6 +3541,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -3546,12 +3562,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/aes/rtl/aes_reg_top.sv b/hw/ip/aes/rtl/aes_reg_top.sv
index 1fe3ef1..63963ae 100644
--- a/hw/ip/aes/rtl/aes_reg_top.sv
+++ b/hw/ip/aes/rtl/aes_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1422,6 +1427,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1432,12 +1448,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/alert_handler/rtl/alert_handler_reg_top.sv b/hw/ip/alert_handler/rtl/alert_handler_reg_top.sv
index d555726..feb00d3 100644
--- a/hw/ip/alert_handler/rtl/alert_handler_reg_top.sv
+++ b/hw/ip/alert_handler/rtl/alert_handler_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -5850,6 +5855,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -5860,12 +5876,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/aon_timer/data/aon_timer.hjson b/hw/ip/aon_timer/data/aon_timer.hjson
index c1d3444..9d623d6 100644
--- a/hw/ip/aon_timer/data/aon_timer.hjson
+++ b/hw/ip/aon_timer/data/aon_timer.hjson
@@ -9,7 +9,7 @@
     {clock: "clk_aon_i", reset: "rst_aon_ni"}
   ]
   bus_interfaces: [
-    { protocol: "tlul", direction: "device" }
+    { protocol: "tlul", direction: "device"}
   ],
   interrupt_list: [
     { name: "wkup_timer_expired",
@@ -82,6 +82,7 @@
       desc: "Wakeup Timer Control register",
       swaccess: "rw",
       hwaccess: "hro",
+      async: "clk_aon_i",
       fields: [
         { bits: "0",
           name: "enable",
@@ -97,6 +98,7 @@
       desc: "Wakeup Timer Threshold Register",
       swaccess: "rw",
       hwaccess: "hro",
+      async: "clk_aon_i",
       fields: [
         { bits: "31:0",
           name: "threshold",
@@ -108,6 +110,7 @@
       desc: "Wakeup Timer Count Register",
       swaccess: "rw",
       hwaccess: "hrw",
+      async: "clk_aon_i",
       fields: [
         { bits: "31:0",
           name: "count",
@@ -133,6 +136,7 @@
       desc: "Watchdog Timer Control register",
       swaccess: "rw",
       hwaccess: "hro",
+      async: "clk_aon_i",
       regwen: "WDOG_REGWEN",
       fields: [
         { bits: "0",
@@ -149,6 +153,7 @@
       desc: "Watchdog Timer Bark Threshold Register",
       swaccess: "rw",
       hwaccess: "hro",
+      async: "clk_aon_i",
       regwen: "WDOG_REGWEN",
       fields: [
         { bits: "31:0",
@@ -161,6 +166,7 @@
       desc: "Watchdog Timer Bite Threshold Register",
       swaccess: "rw",
       hwaccess: "hro",
+      async: "clk_aon_i",
       regwen: "WDOG_REGWEN",
       fields: [
         { bits: "31:0",
@@ -173,6 +179,7 @@
       desc: "Watchdog Timer Count Register",
       swaccess: "rw",
       hwaccess: "hrw",
+      async: "clk_aon_i",
       fields: [
         { bits: "31:0",
           name: "count",
@@ -220,6 +227,7 @@
       desc: "Wakeup request status",
       swaccess: "rw0c",
       hwaccess: "hrw",
+      async: "clk_aon_i",
       fields: [
         { bits: "0",
           name: "cause",
diff --git a/hw/ip/aon_timer/rtl/aon_timer.sv b/hw/ip/aon_timer/rtl/aon_timer.sv
index a436eba..e62bc99 100644
--- a/hw/ip/aon_timer/rtl/aon_timer.sv
+++ b/hw/ip/aon_timer/rtl/aon_timer.sv
@@ -41,55 +41,64 @@
   localparam int AON_WKUP = 0;
   localparam int AON_WDOG = 1;
 
-  // TLUL structs
-  tlul_pkg::tl_h2d_t         tl_aon_h2d;
-  tlul_pkg::tl_d2h_t         tl_aon_d2h;
   // Register structs
-  aon_timer_reg2hw_t         aon_reg2hw;
-  aon_timer_hw2reg_t         aon_hw2reg;
+  aon_timer_reg2hw_t         reg2hw;
+  aon_timer_hw2reg_t         hw2reg;
   // Register write signals
-  logic                      wkup_count_reg_wr;
-  logic [31:0]               wkup_count_wr_data;
-  logic                      wdog_count_reg_wr;
-  logic [31:0]               wdog_count_wr_data;
+  logic                      aon_wkup_count_reg_wr;
+  logic [31:0]               aon_wkup_count_wr_data;
+  logic                      aon_wdog_count_reg_wr;
+  logic [31:0]               aon_wdog_count_wr_data;
   // Other sync signals
   lc_ctrl_pkg::lc_tx_t [2:0] lc_escalate_en;
   // Interrupt signals
   logic                      aon_wkup_intr_set;
   logic                      aon_wdog_intr_set;
-  logic [1:0]                intr_aon_test_q;
-  logic                      intr_aon_test_qe;
-  logic [1:0]                intr_aon_state_q;
-  logic                      intr_aon_state_de;
-  logic [1:0]                intr_aon_state_d;
+  logic [1:0]                intr_test_q;
+  logic                      intr_test_qe;
+  logic [1:0]                intr_state_q;
+  logic                      intr_state_de;
+  logic [1:0]                intr_state_d;
   logic [1:0]                intr_out;
   // Reset signals
   logic                      aon_rst_req_set;
   logic                      aon_rst_req_d, aon_rst_req_q;
   // Alert signals
-  logic [NumAlerts-1:0]      aon_alert_test, aon_alerts;
+  logic [NumAlerts-1:0]      alert_test, alerts;
 
   //////////////////////////////
   // Register Write Interface //
   //////////////////////////////
 
-  assign aon_hw2reg.wkup_count.de = wkup_count_reg_wr;
-  assign aon_hw2reg.wkup_count.d  = wkup_count_wr_data;
-  assign aon_hw2reg.wdog_count.de = wdog_count_reg_wr;
-  assign aon_hw2reg.wdog_count.d  = wdog_count_wr_data;
+  logic aon_sleep_mode;
+  prim_flop_2sync #(
+    .Width(1)
+  ) u_sync_sleep_mode (
+    .clk_i   (clk_aon_i),
+    .rst_ni  (rst_aon_ni),
+    .d_i     (sleep_mode_i),
+    .q_o     (aon_sleep_mode)
+  );
+
+  assign hw2reg.wkup_count.de = aon_wkup_count_reg_wr;
+  assign hw2reg.wkup_count.d  = aon_wkup_count_wr_data;
+  assign hw2reg.wdog_count.de = aon_wdog_count_reg_wr;
+  assign hw2reg.wdog_count.d  = aon_wdog_count_wr_data;
 
   // registers instantiation
   aon_timer_reg_top u_reg (
-    .clk_i      (clk_aon_i),
-    .rst_ni     (rst_aon_ni),
+    .clk_i,
+    .rst_ni,
+    .clk_aon_i,
+    .rst_aon_ni,
 
-    .tl_i       (tl_aon_h2d),
-    .tl_o       (tl_aon_d2h),
+    .tl_i,
+    .tl_o,
 
-    .reg2hw     (aon_reg2hw),
-    .hw2reg     (aon_hw2reg),
+    .reg2hw,
+    .hw2reg,
 
-    .intg_err_o (aon_alerts[0]),
+    .intg_err_o (alerts[0]),
     .devmode_i  (1'b1)
   );
 
@@ -97,9 +106,9 @@
   // Alerts //
   ////////////
 
-  assign aon_alert_test = {
-    aon_reg2hw.alert_test.q &
-    aon_reg2hw.alert_test.qe
+  assign alert_test = {
+    reg2hw.alert_test.q &
+    reg2hw.alert_test.qe
   };
 
   for (genvar i = 0; i < NumAlerts; i++) begin : gen_alert_tx
@@ -107,35 +116,17 @@
       .AsyncOn(AlertAsyncOn[i]),
       .IsFatal(1'b1)
     ) u_prim_alert_sender (
-      .clk_i         (clk_aon_i),
-      .rst_ni        (rst_aon_ni),
-      .alert_test_i  ( aon_alert_test[i] ),
-      .alert_req_i   ( aon_alerts[0]     ),
-      .alert_ack_o   (                   ),
-      .alert_state_o (                   ),
-      .alert_rx_i    ( alert_rx_i[i]     ),
-      .alert_tx_o    ( alert_tx_o[i]     )
+      .clk_i,
+      .rst_ni,
+      .alert_test_i  ( alert_test[i] ),
+      .alert_req_i   ( alerts[0]     ),
+      .alert_ack_o   (               ),
+      .alert_state_o (               ),
+      .alert_rx_i    ( alert_rx_i[i] ),
+      .alert_tx_o    ( alert_tx_o[i] )
     );
   end
 
-  ///////////////////////////////////////
-  // Sync TLUL signals into AON Domain //
-  ///////////////////////////////////////
-
-  tlul_fifo_async #(
-      .ReqDepth (1), // There will only ever be 1 req outstanding from the core
-      .RspDepth (1)
-  ) u_tlul_fifo (
-      .clk_h_i    (clk_i),
-      .rst_h_ni   (rst_aon_ni), // keep pointers consistent by using single reset
-      .clk_d_i    (clk_aon_i),
-      .rst_d_ni   (rst_aon_ni),
-      .tl_h_i     (tl_i),
-      .tl_h_o     (tl_o),
-      .tl_d_o     (tl_aon_h2d),
-      .tl_d_i     (tl_aon_d2h)
-  );
-
   // Lifecycle sync
   prim_lc_sync #(
     .NumCopies(3)
@@ -150,26 +141,16 @@
   // Timer Core //
   ////////////////
 
-  logic sleep_mode;
-  prim_flop_2sync #(
-    .Width(1)
-  ) u_sync_sleep_mode (
-    .clk_i   (clk_aon_i),
-    .rst_ni  (rst_aon_ni),
-    .d_i     (sleep_mode_i),
-    .q_o     (sleep_mode)
-  );
-
   aon_timer_core u_core (
     .clk_aon_i,
     .rst_aon_ni,
-    .sleep_mode_i              (sleep_mode),
+    .sleep_mode_i              (aon_sleep_mode),
     .lc_escalate_en_i          (lc_escalate_en),
-    .reg2hw_i                  (aon_reg2hw),
-    .wkup_count_reg_wr_o       (wkup_count_reg_wr),
-    .wkup_count_wr_data_o      (wkup_count_wr_data),
-    .wdog_count_reg_wr_o       (wdog_count_reg_wr),
-    .wdog_count_wr_data_o      (wdog_count_wr_data),
+    .reg2hw_i                  (reg2hw),
+    .wkup_count_reg_wr_o       (aon_wkup_count_reg_wr),
+    .wkup_count_wr_data_o      (aon_wkup_count_wr_data),
+    .wdog_count_reg_wr_o       (aon_wdog_count_reg_wr),
+    .wdog_count_wr_data_o      (aon_wdog_count_wr_data),
     .wkup_intr_o               (aon_wkup_intr_set),
     .wdog_intr_o               (aon_wdog_intr_set),
     .wdog_reset_req_o          (aon_rst_req_set)
@@ -181,15 +162,15 @@
 
   // Wakeup request is set by HW and cleared by SW
   // The wakeup cause is always captured and only sent out when the system has entered sleep mode
-  assign aon_hw2reg.wkup_cause.de = aon_wkup_intr_set | aon_wdog_intr_set;
-  assign aon_hw2reg.wkup_cause.d  = 1'b1;
+  assign hw2reg.wkup_cause.de = aon_wkup_intr_set | aon_wdog_intr_set;
+  assign hw2reg.wkup_cause.d  = 1'b1;
 
   // wakeup output is flopped in case of clock domain crossing
   always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
     if (!rst_aon_ni) begin
       aon_timer_wkup_req_o <= '0;
     end else begin
-      aon_timer_wkup_req_o <= aon_reg2hw.wkup_cause.q & sleep_mode;
+      aon_timer_wkup_req_o <= reg2hw.wkup_cause.q & aon_sleep_mode;
     end
   end
 
@@ -197,54 +178,79 @@
   // Interrupt Handling //
   ////////////////////////
 
+  // capture these signals as the origin sets are pulsed and it may
+  // happen when the bus clocks are not available.
+  logic [1:0] aon_intr_event_q;
+  always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+    if (!rst_aon_ni) begin
+      aon_intr_event_q <= '0;
+    end else begin
+      if (aon_wdog_intr_set) begin
+        aon_intr_event_q[AON_WDOG] <= ~aon_intr_event_q[AON_WDOG];
+      end
+      if (aon_wkup_intr_set) begin
+        aon_intr_event_q[AON_WKUP] <= ~aon_intr_event_q[AON_WKUP];
+      end
+    end
+  end
+
+  logic [1:0] aon_intr_set;
+  assign aon_intr_set[AON_WDOG] = aon_wdog_intr_set;
+  assign aon_intr_set[AON_WKUP] = aon_wkup_intr_set;
+
+  logic [1:0] intr_event_q, intr_event_q1;
+
+  for (genvar i = 0; i < 2; i++) begin : gen_intr_sync
+    prim_pulse_sync u_intr_sync (
+     .clk_src_i(clk_aon_i),
+     .rst_src_ni(rst_aon_ni),
+     .src_pulse_i(aon_intr_set[i]),
+     .clk_dst_i(clk_i),
+     .rst_dst_ni(rst_ni),
+     .dst_pulse_o(intr_event_q[i])
+    );
+  end
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      intr_event_q1 <= '0;
+    end else begin
+      intr_event_q1 <= intr_event_q;
+    end
+  end
+
   // Registers to interrupt
-  assign intr_aon_test_qe           = aon_reg2hw.intr_test.wkup_timer_expired.qe |
-                                      aon_reg2hw.intr_test.wdog_timer_expired.qe;
-  assign intr_aon_test_q [AON_WKUP] = aon_reg2hw.intr_test.wkup_timer_expired.q;
-  assign intr_aon_state_q[AON_WKUP] = aon_reg2hw.intr_state.wkup_timer_expired.q;
-  assign intr_aon_test_q [AON_WDOG] = aon_reg2hw.intr_test.wdog_timer_expired.q;
-  assign intr_aon_state_q[AON_WDOG] = aon_reg2hw.intr_state.wdog_timer_expired.q;
+  assign intr_test_qe           = reg2hw.intr_test.wkup_timer_expired.qe |
+                                  reg2hw.intr_test.wdog_timer_expired.qe;
+  assign intr_test_q [AON_WKUP] = reg2hw.intr_test.wkup_timer_expired.q;
+  assign intr_state_q[AON_WKUP] = reg2hw.intr_state.wkup_timer_expired.q;
+  assign intr_test_q [AON_WDOG] = reg2hw.intr_test.wdog_timer_expired.q;
+  assign intr_state_q[AON_WDOG] = reg2hw.intr_state.wdog_timer_expired.q;
 
   // Interrupts to registers
-  assign aon_hw2reg.intr_state.wkup_timer_expired.d  = intr_aon_state_d[AON_WKUP];
-  assign aon_hw2reg.intr_state.wkup_timer_expired.de = intr_aon_state_de;
-  assign aon_hw2reg.intr_state.wdog_timer_expired.d  = intr_aon_state_d[AON_WDOG];
-  assign aon_hw2reg.intr_state.wdog_timer_expired.de = intr_aon_state_de;
+  assign hw2reg.intr_state.wkup_timer_expired.d  = intr_state_d[AON_WKUP];
+  assign hw2reg.intr_state.wkup_timer_expired.de = intr_state_de;
+  assign hw2reg.intr_state.wdog_timer_expired.d  = intr_state_d[AON_WDOG];
+  assign hw2reg.intr_state.wdog_timer_expired.de = intr_state_de;
 
   prim_intr_hw #(
     .Width (2)
   ) u_intr_hw (
-    .clk_i                  (clk_aon_i),
-    .rst_ni                 (rst_aon_ni),
-    .event_intr_i           ({aon_wdog_intr_set, aon_wkup_intr_set}),
-
+    .clk_i,
+    .rst_ni,
+    .event_intr_i           (intr_event_q ^ intr_event_q1),
     .reg2hw_intr_enable_q_i (2'b11),
-    .reg2hw_intr_test_q_i   (intr_aon_test_q),
-    .reg2hw_intr_test_qe_i  (intr_aon_test_qe),
-    .reg2hw_intr_state_q_i  (intr_aon_state_q),
-    .hw2reg_intr_state_de_o (intr_aon_state_de),
-    .hw2reg_intr_state_d_o  (intr_aon_state_d),
+    .reg2hw_intr_test_q_i   (intr_test_q),
+    .reg2hw_intr_test_qe_i  (intr_test_qe),
+    .reg2hw_intr_state_q_i  (intr_state_q),
+    .hw2reg_intr_state_de_o (intr_state_de),
+    .hw2reg_intr_state_d_o  (intr_state_d),
 
     .intr_o                 (intr_out)
   );
 
-  prim_flop_2sync #(
-    .Width(1)
-  ) u_sync_wkup_intr (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-    .d_i     (intr_out[AON_WKUP]),
-    .q_o     (intr_wkup_timer_expired_o)
-  );
-
-  prim_flop_2sync #(
-    .Width(1)
-  ) u_sync_wdog_intr (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-    .d_i     (intr_out[AON_WDOG]),
-    .q_o     (intr_wdog_timer_bark_o)
-  );
+  assign intr_wkup_timer_expired_o = intr_out[AON_WKUP];
+  assign intr_wdog_timer_bark_o = intr_out[AON_WDOG];
 
   // The interrupt line can be routed as nmi as well.
   assign nmi_wdog_timer_bark_o = intr_wdog_timer_bark_o;
diff --git a/hw/ip/aon_timer/rtl/aon_timer_core.sv b/hw/ip/aon_timer/rtl/aon_timer_core.sv
index 044ceba..9fe0f7d 100644
--- a/hw/ip/aon_timer/rtl/aon_timer_core.sv
+++ b/hw/ip/aon_timer/rtl/aon_timer_core.sv
@@ -72,6 +72,8 @@
   // Timer reset
   assign wdog_reset_req_o = wdog_incr & (reg2hw_i.wdog_count.q == reg2hw_i.wdog_bite_thold.q);
 
-  assign unused_reg2hw = |{reg2hw_i.intr_state, reg2hw_i.intr_test, reg2hw_i.wkup_cause};
+  assign unused_reg2hw = |{reg2hw_i.intr_state, reg2hw_i.intr_test, reg2hw_i.wkup_cause,
+                           reg2hw_i.alert_test};
+
 
 endmodule
diff --git a/hw/ip/aon_timer/rtl/aon_timer_reg_top.sv b/hw/ip/aon_timer/rtl/aon_timer_reg_top.sv
index 69087c6..e891aea 100644
--- a/hw/ip/aon_timer/rtl/aon_timer_reg_top.sv
+++ b/hw/ip/aon_timer/rtl/aon_timer_reg_top.sv
@@ -9,6 +9,8 @@
 module aon_timer_reg_top (
   input clk_i,
   input rst_ni,
+  input clk_aon_i,
+  input rst_aon_ni,
 
   input  tlul_pkg::tl_h2d_t tl_i,
   output tlul_pkg::tl_d2h_t tl_o,
@@ -41,14 +43,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +76,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +87,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +98,22 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+    logic sync_aon_update;
+  prim_pulse_sync u_aon_tgl (
+    .clk_src_i(clk_aon_i),
+    .rst_src_ni(rst_aon_ni),
+    .src_pulse_i(1'b1),
+    .clk_dst_i(clk_i),
+    .rst_dst_ni(rst_ni),
+    .dst_pulse_o(sync_aon_update)
+  );
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -109,31 +125,40 @@
   logic wkup_ctrl_we;
   logic wkup_ctrl_enable_qs;
   logic wkup_ctrl_enable_wd;
+  logic wkup_ctrl_enable_busy;
   logic [11:0] wkup_ctrl_prescaler_qs;
   logic [11:0] wkup_ctrl_prescaler_wd;
+  logic wkup_ctrl_prescaler_busy;
   logic wkup_thold_we;
   logic [31:0] wkup_thold_qs;
   logic [31:0] wkup_thold_wd;
+  logic wkup_thold_busy;
   logic wkup_count_we;
   logic [31:0] wkup_count_qs;
   logic [31:0] wkup_count_wd;
+  logic wkup_count_busy;
   logic wdog_regwen_we;
   logic wdog_regwen_qs;
   logic wdog_regwen_wd;
   logic wdog_ctrl_we;
   logic wdog_ctrl_enable_qs;
   logic wdog_ctrl_enable_wd;
+  logic wdog_ctrl_enable_busy;
   logic wdog_ctrl_pause_in_sleep_qs;
   logic wdog_ctrl_pause_in_sleep_wd;
+  logic wdog_ctrl_pause_in_sleep_busy;
   logic wdog_bark_thold_we;
   logic [31:0] wdog_bark_thold_qs;
   logic [31:0] wdog_bark_thold_wd;
+  logic wdog_bark_thold_busy;
   logic wdog_bite_thold_we;
   logic [31:0] wdog_bite_thold_qs;
   logic [31:0] wdog_bite_thold_wd;
+  logic wdog_bite_thold_busy;
   logic wdog_count_we;
   logic [31:0] wdog_count_qs;
   logic [31:0] wdog_count_wd;
+  logic wdog_count_busy;
   logic intr_state_we;
   logic intr_state_wkup_timer_expired_qs;
   logic intr_state_wkup_timer_expired_wd;
@@ -145,6 +170,7 @@
   logic wkup_cause_we;
   logic wkup_cause_qs;
   logic wkup_cause_wd;
+  logic wkup_cause_busy;
 
   // Register instances
   // R[alert_test]: V(True)
@@ -166,108 +192,92 @@
   // R[wkup_ctrl]: V(False)
 
   //   F[enable]: 0:0
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (1'h0)
   ) u_wkup_ctrl_enable (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wkup_ctrl_we),
-    .wd     (wkup_ctrl_enable_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wkup_ctrl.enable.q),
-
-    // to register interface (read)
-    .qs     (wkup_ctrl_enable_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wkup_ctrl_we),
+    .src_wd_i     (wkup_ctrl_enable_wd),
+    .dst_de_i     (1'b0),
+    .dst_d_i      ('0),
+    .src_busy_o   (wkup_ctrl_enable_busy),
+    .src_qs_o     (wkup_ctrl_enable_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wkup_ctrl.enable.q)
   );
 
 
   //   F[prescaler]: 12:1
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (12),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (12'h0)
   ) u_wkup_ctrl_prescaler (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wkup_ctrl_we),
-    .wd     (wkup_ctrl_prescaler_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wkup_ctrl.prescaler.q),
-
-    // to register interface (read)
-    .qs     (wkup_ctrl_prescaler_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wkup_ctrl_we),
+    .src_wd_i     (wkup_ctrl_prescaler_wd),
+    .dst_de_i     (1'b0),
+    .dst_d_i      ('0),
+    .src_busy_o   (wkup_ctrl_prescaler_busy),
+    .src_qs_o     (wkup_ctrl_prescaler_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wkup_ctrl.prescaler.q)
   );
 
 
   // R[wkup_thold]: V(False)
 
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (32),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (32'h0)
   ) u_wkup_thold (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wkup_thold_we),
-    .wd     (wkup_thold_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wkup_thold.q),
-
-    // to register interface (read)
-    .qs     (wkup_thold_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wkup_thold_we),
+    .src_wd_i     (wkup_thold_wd),
+    .dst_de_i     (1'b0),
+    .dst_d_i      ('0),
+    .src_busy_o   (wkup_thold_busy),
+    .src_qs_o     (wkup_thold_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wkup_thold.q)
   );
 
 
   // R[wkup_count]: V(False)
 
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (32),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (32'h0)
   ) u_wkup_count (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wkup_count_we),
-    .wd     (wkup_count_wd),
-
-    // from internal hardware
-    .de     (hw2reg.wkup_count.de),
-    .d      (hw2reg.wkup_count.d),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wkup_count.q),
-
-    // to register interface (read)
-    .qs     (wkup_count_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wkup_count_we),
+    .src_wd_i     (wkup_count_wd),
+    .dst_de_i     (hw2reg.wkup_count.de),
+    .dst_d_i      (hw2reg.wkup_count.d),
+    .src_busy_o   (wkup_count_busy),
+    .src_qs_o     (wkup_count_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wkup_count.q)
   );
 
 
@@ -301,135 +311,115 @@
   // R[wdog_ctrl]: V(False)
 
   //   F[enable]: 0:0
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (1'h0)
   ) u_wdog_ctrl_enable (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wdog_ctrl_we & wdog_regwen_qs),
-    .wd     (wdog_ctrl_enable_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wdog_ctrl.enable.q),
-
-    // to register interface (read)
-    .qs     (wdog_ctrl_enable_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wdog_ctrl_we & wdog_regwen_qs),
+    .src_wd_i     (wdog_ctrl_enable_wd),
+    .dst_de_i     (1'b0),
+    .dst_d_i      ('0),
+    .src_busy_o   (wdog_ctrl_enable_busy),
+    .src_qs_o     (wdog_ctrl_enable_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wdog_ctrl.enable.q)
   );
 
 
   //   F[pause_in_sleep]: 1:1
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (1'h0)
   ) u_wdog_ctrl_pause_in_sleep (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wdog_ctrl_we & wdog_regwen_qs),
-    .wd     (wdog_ctrl_pause_in_sleep_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wdog_ctrl.pause_in_sleep.q),
-
-    // to register interface (read)
-    .qs     (wdog_ctrl_pause_in_sleep_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wdog_ctrl_we & wdog_regwen_qs),
+    .src_wd_i     (wdog_ctrl_pause_in_sleep_wd),
+    .dst_de_i     (1'b0),
+    .dst_d_i      ('0),
+    .src_busy_o   (wdog_ctrl_pause_in_sleep_busy),
+    .src_qs_o     (wdog_ctrl_pause_in_sleep_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wdog_ctrl.pause_in_sleep.q)
   );
 
 
   // R[wdog_bark_thold]: V(False)
 
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (32),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (32'h0)
   ) u_wdog_bark_thold (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wdog_bark_thold_we & wdog_regwen_qs),
-    .wd     (wdog_bark_thold_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wdog_bark_thold.q),
-
-    // to register interface (read)
-    .qs     (wdog_bark_thold_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wdog_bark_thold_we & wdog_regwen_qs),
+    .src_wd_i     (wdog_bark_thold_wd),
+    .dst_de_i     (1'b0),
+    .dst_d_i      ('0),
+    .src_busy_o   (wdog_bark_thold_busy),
+    .src_qs_o     (wdog_bark_thold_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wdog_bark_thold.q)
   );
 
 
   // R[wdog_bite_thold]: V(False)
 
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (32),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (32'h0)
   ) u_wdog_bite_thold (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wdog_bite_thold_we & wdog_regwen_qs),
-    .wd     (wdog_bite_thold_wd),
-
-    // from internal hardware
-    .de     (1'b0),
-    .d      ('0),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wdog_bite_thold.q),
-
-    // to register interface (read)
-    .qs     (wdog_bite_thold_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wdog_bite_thold_we & wdog_regwen_qs),
+    .src_wd_i     (wdog_bite_thold_wd),
+    .dst_de_i     (1'b0),
+    .dst_d_i      ('0),
+    .src_busy_o   (wdog_bite_thold_busy),
+    .src_qs_o     (wdog_bite_thold_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wdog_bite_thold.q)
   );
 
 
   // R[wdog_count]: V(False)
 
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (32),
     .SwAccess(prim_subreg_pkg::SwAccessRW),
     .RESVAL  (32'h0)
   ) u_wdog_count (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wdog_count_we),
-    .wd     (wdog_count_wd),
-
-    // from internal hardware
-    .de     (hw2reg.wdog_count.de),
-    .d      (hw2reg.wdog_count.d),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wdog_count.q),
-
-    // to register interface (read)
-    .qs     (wdog_count_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wdog_count_we),
+    .src_wd_i     (wdog_count_wd),
+    .dst_de_i     (hw2reg.wdog_count.de),
+    .dst_d_i      (hw2reg.wdog_count.d),
+    .src_busy_o   (wdog_count_busy),
+    .src_qs_o     (wdog_count_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wdog_count.q)
   );
 
 
@@ -521,28 +511,24 @@
 
   // R[wkup_cause]: V(False)
 
-  prim_subreg #(
+  prim_subreg_async #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessW0C),
     .RESVAL  (1'h0)
   ) u_wkup_cause (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
-
-    // from register interface
-    .we     (wkup_cause_we),
-    .wd     (wkup_cause_wd),
-
-    // from internal hardware
-    .de     (hw2reg.wkup_cause.de),
-    .d      (hw2reg.wkup_cause.d),
-
-    // to internal hardware
-    .qe     (),
-    .q      (reg2hw.wkup_cause.q),
-
-    // to register interface (read)
-    .qs     (wkup_cause_qs)
+    .clk_src_i    (clk_i),
+    .rst_src_ni   (rst_ni),
+    .clk_dst_i    (clk_aon_i),
+    .rst_dst_ni   (rst_aon_ni),
+    .src_update_i (sync_aon_update),
+    .src_we_i     (wkup_cause_we),
+    .src_wd_i     (wkup_cause_wd),
+    .dst_de_i     (hw2reg.wkup_cause.de),
+    .dst_d_i      (hw2reg.wkup_cause.d),
+    .src_busy_o   (wkup_cause_busy),
+    .src_qs_o     (wkup_cause_qs),
+    .dst_qe_o     (),
+    .q            (reg2hw.wkup_cause.q)
   );
 
 
@@ -690,6 +676,45 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      addr_hit[1]: begin
+        reg_busy =
+          wkup_ctrl_enable_busy |
+          wkup_ctrl_prescaler_busy;
+      end
+      addr_hit[2]: begin
+        reg_busy = wkup_thold_busy;
+      end
+      addr_hit[3]: begin
+        reg_busy = wkup_count_busy;
+      end
+      addr_hit[5]: begin
+        reg_busy =
+          wdog_ctrl_enable_busy |
+          wdog_ctrl_pause_in_sleep_busy;
+      end
+      addr_hit[6]: begin
+        reg_busy = wdog_bark_thold_busy;
+      end
+      addr_hit[7]: begin
+        reg_busy = wdog_bite_thold_busy;
+      end
+      addr_hit[8]: begin
+        reg_busy = wdog_count_busy;
+      end
+      addr_hit[11]: begin
+        reg_busy = wkup_cause_busy;
+      end
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -700,12 +725,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/clkmgr/rtl/clkmgr_reg_top.sv b/hw/ip/clkmgr/rtl/clkmgr_reg_top.sv
index be5ac3a..86c690d 100644
--- a/hw/ip/clkmgr/rtl/clkmgr_reg_top.sv
+++ b/hw/ip/clkmgr/rtl/clkmgr_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -335,6 +340,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -345,12 +361,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/csrng/rtl/csrng_reg_top.sv b/hw/ip/csrng/rtl/csrng_reg_top.sv
index 87d27f9..1d96823 100644
--- a/hw/ip/csrng/rtl/csrng_reg_top.sv
+++ b/hw/ip/csrng/rtl/csrng_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1793,6 +1798,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1803,12 +1819,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/edn/rtl/edn_reg_top.sv b/hw/ip/edn/rtl/edn_reg_top.sv
index 5701d78..d298c25 100644
--- a/hw/ip/edn/rtl/edn_reg_top.sv
+++ b/hw/ip/edn/rtl/edn_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1014,6 +1019,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1024,12 +1040,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/entropy_src/rtl/entropy_src_reg_top.sv b/hw/ip/entropy_src/rtl/entropy_src_reg_top.sv
index 3493ae8..c703b8a 100644
--- a/hw/ip/entropy_src/rtl/entropy_src_reg_top.sv
+++ b/hw/ip/entropy_src/rtl/entropy_src_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -3091,6 +3096,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -3101,12 +3117,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
index e768b89..73ff107 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_core_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [3];
@@ -106,8 +108,8 @@
     .DReqDepth  ({3{4'h0}}),
     .DRspDepth  ({3{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -136,8 +138,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -147,10 +149,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -12322,6 +12327,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -12332,12 +12348,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_prim_reg_top.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_prim_reg_top.sv
index 53c5691..65335a1 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_prim_reg_top.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_prim_reg_top.sv
@@ -24,10 +24,11 @@
   import flash_ctrl_reg_pkg::* ;
 
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -51,7 +52,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [0];
@@ -73,8 +74,8 @@
     .DReqDepth  ({0{4'h0}}),
     .DRspDepth  ({0{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
diff --git a/hw/ip/gpio/rtl/gpio_reg_top.sv b/hw/ip/gpio/rtl/gpio_reg_top.sv
index 7b1aa9c..7fa64ea 100644
--- a/hw/ip/gpio/rtl/gpio_reg_top.sv
+++ b/hw/ip/gpio/rtl/gpio_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -753,6 +758,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -763,12 +779,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/hmac/rtl/hmac_reg_top.sv b/hw/ip/hmac/rtl/hmac_reg_top.sv
index e0540f1..73c7863 100644
--- a/hw/ip/hmac/rtl/hmac_reg_top.sv
+++ b/hw/ip/hmac/rtl/hmac_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [2];
@@ -104,8 +106,8 @@
     .DReqDepth  ({2{4'h0}}),
     .DRspDepth  ({2{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -131,8 +133,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -142,10 +144,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1222,6 +1227,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1232,12 +1248,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/i2c/rtl/i2c_reg_top.sv b/hw/ip/i2c/rtl/i2c_reg_top.sv
index 1fd9250..857d66d 100644
--- a/hw/ip/i2c/rtl/i2c_reg_top.sv
+++ b/hw/ip/i2c/rtl/i2c_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -3200,6 +3205,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -3210,12 +3226,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/keymgr/rtl/keymgr_reg_top.sv b/hw/ip/keymgr/rtl/keymgr_reg_top.sv
index b6e2e62..59ea9be 100644
--- a/hw/ip/keymgr/rtl/keymgr_reg_top.sv
+++ b/hw/ip/keymgr/rtl/keymgr_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -2599,6 +2604,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -2609,12 +2625,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/kmac/rtl/kmac_reg_top.sv b/hw/ip/kmac/rtl/kmac_reg_top.sv
index 37aeea9..a94576d 100644
--- a/hw/ip/kmac/rtl/kmac_reg_top.sv
+++ b/hw/ip/kmac/rtl/kmac_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [3];
@@ -106,8 +108,8 @@
     .DReqDepth  ({3{4'h0}}),
     .DRspDepth  ({3{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -136,8 +138,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -147,10 +149,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -2589,6 +2594,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -2599,12 +2615,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv
index 32eba82..fb91e96 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1139,6 +1144,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1149,12 +1165,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/otbn/rtl/otbn_reg_top.sv b/hw/ip/otbn/rtl/otbn_reg_top.sv
index 7f00872..9da0db1 100644
--- a/hw/ip/otbn/rtl/otbn_reg_top.sv
+++ b/hw/ip/otbn/rtl/otbn_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(0)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [3];
@@ -106,8 +108,8 @@
     .DReqDepth  ({3{4'h0}}),
     .DRspDepth  ({3{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -136,8 +138,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(1)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -147,10 +149,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -869,6 +874,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -879,12 +895,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_core_reg_top.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_core_reg_top.sv
index 2134b4e..c1ac0e7 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_core_reg_top.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_core_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [2];
@@ -104,8 +106,8 @@
     .DReqDepth  ({2{4'h0}}),
     .DRspDepth  ({2{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -131,8 +133,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -142,10 +144,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1773,6 +1778,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1783,12 +1799,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_prim_reg_top.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_prim_reg_top.sv
index b9a3870..4052500 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_prim_reg_top.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_prim_reg_top.sv
@@ -24,10 +24,11 @@
   import otp_ctrl_reg_pkg::* ;
 
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -51,7 +52,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [0];
@@ -73,8 +74,8 @@
     .DReqDepth  ({0{4'h0}}),
     .DRspDepth  ({0{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_reg_top.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_reg_top.sv
new file mode 100644
index 0000000..d75b4af
--- /dev/null
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_reg_top.sv
@@ -0,0 +1,1818 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Top module auto-generated by `reggen`
+
+`include "prim_assert.sv"
+
+module otp_ctrl_reg_top (
+  input clk_i,
+  input rst_ni,
+
+  input  tlul_pkg::tl_h2d_t tl_i,
+  output tlul_pkg::tl_d2h_t tl_o,
+
+  // Output port for window
+  output tlul_pkg::tl_h2d_t tl_win_o  [2],
+  input  tlul_pkg::tl_d2h_t tl_win_i  [2],
+
+  // To HW
+  output otp_ctrl_reg_pkg::otp_ctrl_reg2hw_t reg2hw, // Write
+  input  otp_ctrl_reg_pkg::otp_ctrl_hw2reg_t hw2reg, // Read
+
+  // Integrity check errors
+  output logic intg_err_o,
+
+  // Config
+  input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+  import otp_ctrl_reg_pkg::* ;
+
+  localparam int AW = 14;
+  localparam int DW = 32;
+  localparam int DBW = DW/8;                    // Byte Width
+
+  // register signals
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
+
+  logic          addrmiss, wr_err;
+
+  logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
+
+  tlul_pkg::tl_h2d_t tl_reg_h2d;
+  tlul_pkg::tl_d2h_t tl_reg_d2h;
+
+
+  // incoming payload check
+  logic intg_err;
+  tlul_cmd_intg_chk u_chk (
+    .tl_i(tl_i),
+    .err_o(intg_err)
+  );
+
+  logic intg_err_q;
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      intg_err_q <= '0;
+    end else if (intg_err) begin
+      intg_err_q <= 1'b1;
+    end
+  end
+
+  // integrity error output is permanent and should be used for alert generation
+  // register errors are transactional
+  assign intg_err_o = intg_err_q | intg_err;
+
+  // outgoing integrity generation
+  tlul_pkg::tl_d2h_t tl_o_pre;
+  tlul_rsp_intg_gen #(
+    .EnableRspIntgGen(1),
+    .EnableDataIntgGen(1)
+  ) u_rsp_intg_gen (
+    .tl_i(tl_o_pre),
+    .tl_o(tl_o)
+  );
+
+  tlul_pkg::tl_h2d_t tl_socket_h2d [3];
+  tlul_pkg::tl_d2h_t tl_socket_d2h [3];
+
+  logic [1:0] reg_steer;
+
+  // socket_1n connection
+  assign tl_reg_h2d = tl_socket_h2d[2];
+  assign tl_socket_d2h[2] = tl_reg_d2h;
+
+  assign tl_win_o[0] = tl_socket_h2d[0];
+  assign tl_socket_d2h[0] = tl_win_i[0];
+  assign tl_win_o[1] = tl_socket_h2d[1];
+  assign tl_socket_d2h[1] = tl_win_i[1];
+
+  // Create Socket_1n
+  tlul_socket_1n #(
+    .N          (3),
+    .HReqPass   (1'b1),
+    .HRspPass   (1'b1),
+    .DReqPass   ({3{1'b1}}),
+    .DRspPass   ({3{1'b1}}),
+    .HReqDepth  (4'h0),
+    .HRspDepth  (4'h0),
+    .DReqDepth  ({3{4'h0}}),
+    .DRspDepth  ({3{4'h0}})
+  ) u_socket (
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
+    .tl_h_i (tl_i),
+    .tl_h_o (tl_o_pre),
+    .tl_d_o (tl_socket_h2d),
+    .tl_d_i (tl_socket_d2h),
+    .dev_select_i (reg_steer)
+  );
+
+  // Create steering logic
+  always_comb begin
+    reg_steer = 2;       // Default set to register
+
+    // TODO: Can below codes be unique case () inside ?
+    if (tl_i.a_address[AW-1:0] >= 4096 && tl_i.a_address[AW-1:0] < 6144) begin
+      reg_steer = 0;
+    end
+    if (tl_i.a_address[AW-1:0] >= 8192 && tl_i.a_address[AW-1:0] < 8256) begin
+      reg_steer = 1;
+    end
+    if (intg_err) begin
+      reg_steer = 2;
+    end
+  end
+
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW),
+    .EnableDataIntgGen(0)
+  ) u_reg_if (
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
+
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
+
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .busy_i  (reg_busy),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
+
+  // cdc oversampling signals
+
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
+
+  // Define SW related signals
+  // Format: <reg>_<field>_{wd|we|qs}
+  //        or <reg>_{wd|we|qs} if field == 1 or 0
+  logic intr_state_we;
+  logic intr_state_otp_operation_done_qs;
+  logic intr_state_otp_operation_done_wd;
+  logic intr_state_otp_error_qs;
+  logic intr_state_otp_error_wd;
+  logic intr_enable_we;
+  logic intr_enable_otp_operation_done_qs;
+  logic intr_enable_otp_operation_done_wd;
+  logic intr_enable_otp_error_qs;
+  logic intr_enable_otp_error_wd;
+  logic intr_test_we;
+  logic intr_test_otp_operation_done_wd;
+  logic intr_test_otp_error_wd;
+  logic alert_test_we;
+  logic alert_test_fatal_macro_error_wd;
+  logic alert_test_fatal_check_error_wd;
+  logic alert_test_fatal_bus_integ_error_wd;
+  logic status_re;
+  logic status_creator_sw_cfg_error_qs;
+  logic status_owner_sw_cfg_error_qs;
+  logic status_hw_cfg_error_qs;
+  logic status_secret0_error_qs;
+  logic status_secret1_error_qs;
+  logic status_secret2_error_qs;
+  logic status_life_cycle_error_qs;
+  logic status_dai_error_qs;
+  logic status_lci_error_qs;
+  logic status_timeout_error_qs;
+  logic status_lfsr_fsm_error_qs;
+  logic status_scrambling_fsm_error_qs;
+  logic status_key_deriv_fsm_error_qs;
+  logic status_bus_integ_error_qs;
+  logic status_dai_idle_qs;
+  logic status_check_pending_qs;
+  logic err_code_re;
+  logic [2:0] err_code_err_code_0_qs;
+  logic [2:0] err_code_err_code_1_qs;
+  logic [2:0] err_code_err_code_2_qs;
+  logic [2:0] err_code_err_code_3_qs;
+  logic [2:0] err_code_err_code_4_qs;
+  logic [2:0] err_code_err_code_5_qs;
+  logic [2:0] err_code_err_code_6_qs;
+  logic [2:0] err_code_err_code_7_qs;
+  logic [2:0] err_code_err_code_8_qs;
+  logic direct_access_regwen_re;
+  logic direct_access_regwen_qs;
+  logic direct_access_cmd_we;
+  logic direct_access_cmd_rd_wd;
+  logic direct_access_cmd_wr_wd;
+  logic direct_access_cmd_digest_wd;
+  logic direct_access_address_we;
+  logic [10:0] direct_access_address_qs;
+  logic [10:0] direct_access_address_wd;
+  logic direct_access_wdata_0_we;
+  logic [31:0] direct_access_wdata_0_qs;
+  logic [31:0] direct_access_wdata_0_wd;
+  logic direct_access_wdata_1_we;
+  logic [31:0] direct_access_wdata_1_qs;
+  logic [31:0] direct_access_wdata_1_wd;
+  logic direct_access_rdata_0_re;
+  logic [31:0] direct_access_rdata_0_qs;
+  logic direct_access_rdata_1_re;
+  logic [31:0] direct_access_rdata_1_qs;
+  logic check_trigger_regwen_we;
+  logic check_trigger_regwen_qs;
+  logic check_trigger_regwen_wd;
+  logic check_trigger_we;
+  logic check_trigger_integrity_wd;
+  logic check_trigger_consistency_wd;
+  logic check_regwen_we;
+  logic check_regwen_qs;
+  logic check_regwen_wd;
+  logic check_timeout_we;
+  logic [31:0] check_timeout_qs;
+  logic [31:0] check_timeout_wd;
+  logic integrity_check_period_we;
+  logic [31:0] integrity_check_period_qs;
+  logic [31:0] integrity_check_period_wd;
+  logic consistency_check_period_we;
+  logic [31:0] consistency_check_period_qs;
+  logic [31:0] consistency_check_period_wd;
+  logic creator_sw_cfg_read_lock_we;
+  logic creator_sw_cfg_read_lock_qs;
+  logic creator_sw_cfg_read_lock_wd;
+  logic owner_sw_cfg_read_lock_we;
+  logic owner_sw_cfg_read_lock_qs;
+  logic owner_sw_cfg_read_lock_wd;
+  logic creator_sw_cfg_digest_0_re;
+  logic [31:0] creator_sw_cfg_digest_0_qs;
+  logic creator_sw_cfg_digest_1_re;
+  logic [31:0] creator_sw_cfg_digest_1_qs;
+  logic owner_sw_cfg_digest_0_re;
+  logic [31:0] owner_sw_cfg_digest_0_qs;
+  logic owner_sw_cfg_digest_1_re;
+  logic [31:0] owner_sw_cfg_digest_1_qs;
+  logic hw_cfg_digest_0_re;
+  logic [31:0] hw_cfg_digest_0_qs;
+  logic hw_cfg_digest_1_re;
+  logic [31:0] hw_cfg_digest_1_qs;
+  logic secret0_digest_0_re;
+  logic [31:0] secret0_digest_0_qs;
+  logic secret0_digest_1_re;
+  logic [31:0] secret0_digest_1_qs;
+  logic secret1_digest_0_re;
+  logic [31:0] secret1_digest_0_qs;
+  logic secret1_digest_1_re;
+  logic [31:0] secret1_digest_1_qs;
+  logic secret2_digest_0_re;
+  logic [31:0] secret2_digest_0_qs;
+  logic secret2_digest_1_re;
+  logic [31:0] secret2_digest_1_qs;
+
+  // Register instances
+  // R[intr_state]: V(False)
+
+  //   F[otp_operation_done]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("W1C"),
+    .RESVAL  (1'h0)
+  ) u_intr_state_otp_operation_done (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (intr_state_we),
+    .wd     (intr_state_otp_operation_done_wd),
+
+    // from internal hardware
+    .de     (hw2reg.intr_state.otp_operation_done.de),
+    .d      (hw2reg.intr_state.otp_operation_done.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.intr_state.otp_operation_done.q),
+
+    // to register interface (read)
+    .qs     (intr_state_otp_operation_done_qs)
+  );
+
+
+  //   F[otp_error]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("W1C"),
+    .RESVAL  (1'h0)
+  ) u_intr_state_otp_error (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (intr_state_we),
+    .wd     (intr_state_otp_error_wd),
+
+    // from internal hardware
+    .de     (hw2reg.intr_state.otp_error.de),
+    .d      (hw2reg.intr_state.otp_error.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.intr_state.otp_error.q),
+
+    // to register interface (read)
+    .qs     (intr_state_otp_error_qs)
+  );
+
+
+  // R[intr_enable]: V(False)
+
+  //   F[otp_operation_done]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_intr_enable_otp_operation_done (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (intr_enable_we),
+    .wd     (intr_enable_otp_operation_done_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.intr_enable.otp_operation_done.q),
+
+    // to register interface (read)
+    .qs     (intr_enable_otp_operation_done_qs)
+  );
+
+
+  //   F[otp_error]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_intr_enable_otp_error (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (intr_enable_we),
+    .wd     (intr_enable_otp_error_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.intr_enable.otp_error.q),
+
+    // to register interface (read)
+    .qs     (intr_enable_otp_error_qs)
+  );
+
+
+  // R[intr_test]: V(True)
+
+  //   F[otp_operation_done]: 0:0
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_intr_test_otp_operation_done (
+    .re     (1'b0),
+    .we     (intr_test_we),
+    .wd     (intr_test_otp_operation_done_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.intr_test.otp_operation_done.qe),
+    .q      (reg2hw.intr_test.otp_operation_done.q),
+    .qs     ()
+  );
+
+
+  //   F[otp_error]: 1:1
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_intr_test_otp_error (
+    .re     (1'b0),
+    .we     (intr_test_we),
+    .wd     (intr_test_otp_error_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.intr_test.otp_error.qe),
+    .q      (reg2hw.intr_test.otp_error.q),
+    .qs     ()
+  );
+
+
+  // R[alert_test]: V(True)
+
+  //   F[fatal_macro_error]: 0:0
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_alert_test_fatal_macro_error (
+    .re     (1'b0),
+    .we     (alert_test_we),
+    .wd     (alert_test_fatal_macro_error_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.alert_test.fatal_macro_error.qe),
+    .q      (reg2hw.alert_test.fatal_macro_error.q),
+    .qs     ()
+  );
+
+
+  //   F[fatal_check_error]: 1:1
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_alert_test_fatal_check_error (
+    .re     (1'b0),
+    .we     (alert_test_we),
+    .wd     (alert_test_fatal_check_error_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.alert_test.fatal_check_error.qe),
+    .q      (reg2hw.alert_test.fatal_check_error.q),
+    .qs     ()
+  );
+
+
+  //   F[fatal_bus_integ_error]: 2:2
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_alert_test_fatal_bus_integ_error (
+    .re     (1'b0),
+    .we     (alert_test_we),
+    .wd     (alert_test_fatal_bus_integ_error_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.alert_test.fatal_bus_integ_error.qe),
+    .q      (reg2hw.alert_test.fatal_bus_integ_error.q),
+    .qs     ()
+  );
+
+
+  // R[status]: V(True)
+
+  //   F[creator_sw_cfg_error]: 0:0
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_creator_sw_cfg_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.creator_sw_cfg_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_creator_sw_cfg_error_qs)
+  );
+
+
+  //   F[owner_sw_cfg_error]: 1:1
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_owner_sw_cfg_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.owner_sw_cfg_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_owner_sw_cfg_error_qs)
+  );
+
+
+  //   F[hw_cfg_error]: 2:2
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_hw_cfg_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.hw_cfg_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_hw_cfg_error_qs)
+  );
+
+
+  //   F[secret0_error]: 3:3
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_secret0_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.secret0_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_secret0_error_qs)
+  );
+
+
+  //   F[secret1_error]: 4:4
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_secret1_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.secret1_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_secret1_error_qs)
+  );
+
+
+  //   F[secret2_error]: 5:5
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_secret2_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.secret2_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_secret2_error_qs)
+  );
+
+
+  //   F[life_cycle_error]: 6:6
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_life_cycle_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.life_cycle_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_life_cycle_error_qs)
+  );
+
+
+  //   F[dai_error]: 7:7
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_dai_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.dai_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_dai_error_qs)
+  );
+
+
+  //   F[lci_error]: 8:8
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_lci_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.lci_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_lci_error_qs)
+  );
+
+
+  //   F[timeout_error]: 9:9
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_timeout_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.timeout_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_timeout_error_qs)
+  );
+
+
+  //   F[lfsr_fsm_error]: 10:10
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_lfsr_fsm_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.lfsr_fsm_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_lfsr_fsm_error_qs)
+  );
+
+
+  //   F[scrambling_fsm_error]: 11:11
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_scrambling_fsm_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.scrambling_fsm_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_scrambling_fsm_error_qs)
+  );
+
+
+  //   F[key_deriv_fsm_error]: 12:12
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_key_deriv_fsm_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.key_deriv_fsm_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_key_deriv_fsm_error_qs)
+  );
+
+
+  //   F[bus_integ_error]: 13:13
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_bus_integ_error (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.bus_integ_error.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_bus_integ_error_qs)
+  );
+
+
+  //   F[dai_idle]: 14:14
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_dai_idle (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.dai_idle.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_dai_idle_qs)
+  );
+
+
+  //   F[check_pending]: 15:15
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_status_check_pending (
+    .re     (status_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.status.check_pending.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (status_check_pending_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg err_code
+  // R[err_code]: V(True)
+
+  // F[err_code_0]: 2:0
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_0 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[0].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_0_qs)
+  );
+
+
+  // F[err_code_1]: 5:3
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_1 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[1].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_1_qs)
+  );
+
+
+  // F[err_code_2]: 8:6
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_2 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[2].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_2_qs)
+  );
+
+
+  // F[err_code_3]: 11:9
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_3 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[3].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_3_qs)
+  );
+
+
+  // F[err_code_4]: 14:12
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_4 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[4].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_4_qs)
+  );
+
+
+  // F[err_code_5]: 17:15
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_5 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[5].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_5_qs)
+  );
+
+
+  // F[err_code_6]: 20:18
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_6 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[6].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_6_qs)
+  );
+
+
+  // F[err_code_7]: 23:21
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_7 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[7].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_7_qs)
+  );
+
+
+  // F[err_code_8]: 26:24
+  prim_subreg_ext #(
+    .DW    (3)
+  ) u_err_code_err_code_8 (
+    .re     (err_code_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.err_code[8].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (err_code_err_code_8_qs)
+  );
+
+
+
+  // R[direct_access_regwen]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_direct_access_regwen (
+    .re     (direct_access_regwen_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.direct_access_regwen.d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (direct_access_regwen_qs)
+  );
+
+
+  // R[direct_access_cmd]: V(True)
+
+  //   F[rd]: 0:0
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_direct_access_cmd_rd (
+    .re     (1'b0),
+    .we     (direct_access_cmd_we & direct_access_regwen_qs),
+    .wd     (direct_access_cmd_rd_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.direct_access_cmd.rd.qe),
+    .q      (reg2hw.direct_access_cmd.rd.q),
+    .qs     ()
+  );
+
+
+  //   F[wr]: 1:1
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_direct_access_cmd_wr (
+    .re     (1'b0),
+    .we     (direct_access_cmd_we & direct_access_regwen_qs),
+    .wd     (direct_access_cmd_wr_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.direct_access_cmd.wr.qe),
+    .q      (reg2hw.direct_access_cmd.wr.q),
+    .qs     ()
+  );
+
+
+  //   F[digest]: 2:2
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_direct_access_cmd_digest (
+    .re     (1'b0),
+    .we     (direct_access_cmd_we & direct_access_regwen_qs),
+    .wd     (direct_access_cmd_digest_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.direct_access_cmd.digest.qe),
+    .q      (reg2hw.direct_access_cmd.digest.q),
+    .qs     ()
+  );
+
+
+  // R[direct_access_address]: V(False)
+
+  prim_subreg #(
+    .DW      (11),
+    .SWACCESS("RW"),
+    .RESVAL  (11'h0)
+  ) u_direct_access_address (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (direct_access_address_we & direct_access_regwen_qs),
+    .wd     (direct_access_address_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.direct_access_address.q),
+
+    // to register interface (read)
+    .qs     (direct_access_address_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg direct_access_wdata
+  // R[direct_access_wdata_0]: V(False)
+
+  prim_subreg #(
+    .DW      (32),
+    .SWACCESS("RW"),
+    .RESVAL  (32'h0)
+  ) u_direct_access_wdata_0 (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (direct_access_wdata_0_we & direct_access_regwen_qs),
+    .wd     (direct_access_wdata_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.direct_access_wdata[0].q),
+
+    // to register interface (read)
+    .qs     (direct_access_wdata_0_qs)
+  );
+
+  // Subregister 1 of Multireg direct_access_wdata
+  // R[direct_access_wdata_1]: V(False)
+
+  prim_subreg #(
+    .DW      (32),
+    .SWACCESS("RW"),
+    .RESVAL  (32'h0)
+  ) u_direct_access_wdata_1 (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (direct_access_wdata_1_we & direct_access_regwen_qs),
+    .wd     (direct_access_wdata_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.direct_access_wdata[1].q),
+
+    // to register interface (read)
+    .qs     (direct_access_wdata_1_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg direct_access_rdata
+  // R[direct_access_rdata_0]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_direct_access_rdata_0 (
+    .re     (direct_access_rdata_0_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.direct_access_rdata[0].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (direct_access_rdata_0_qs)
+  );
+
+  // Subregister 1 of Multireg direct_access_rdata
+  // R[direct_access_rdata_1]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_direct_access_rdata_1 (
+    .re     (direct_access_rdata_1_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.direct_access_rdata[1].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (direct_access_rdata_1_qs)
+  );
+
+
+  // R[check_trigger_regwen]: V(False)
+
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("W0C"),
+    .RESVAL  (1'h1)
+  ) u_check_trigger_regwen (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (check_trigger_regwen_we),
+    .wd     (check_trigger_regwen_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (check_trigger_regwen_qs)
+  );
+
+
+  // R[check_trigger]: V(True)
+
+  //   F[integrity]: 0:0
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_check_trigger_integrity (
+    .re     (1'b0),
+    .we     (check_trigger_we & check_trigger_regwen_qs),
+    .wd     (check_trigger_integrity_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.check_trigger.integrity.qe),
+    .q      (reg2hw.check_trigger.integrity.q),
+    .qs     ()
+  );
+
+
+  //   F[consistency]: 1:1
+  prim_subreg_ext #(
+    .DW    (1)
+  ) u_check_trigger_consistency (
+    .re     (1'b0),
+    .we     (check_trigger_we & check_trigger_regwen_qs),
+    .wd     (check_trigger_consistency_wd),
+    .d      ('0),
+    .qre    (),
+    .qe     (reg2hw.check_trigger.consistency.qe),
+    .q      (reg2hw.check_trigger.consistency.q),
+    .qs     ()
+  );
+
+
+  // R[check_regwen]: V(False)
+
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("W0C"),
+    .RESVAL  (1'h1)
+  ) u_check_regwen (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (check_regwen_we),
+    .wd     (check_regwen_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (check_regwen_qs)
+  );
+
+
+  // R[check_timeout]: V(False)
+
+  prim_subreg #(
+    .DW      (32),
+    .SWACCESS("RW"),
+    .RESVAL  (32'h0)
+  ) u_check_timeout (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (check_timeout_we & check_regwen_qs),
+    .wd     (check_timeout_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.check_timeout.q),
+
+    // to register interface (read)
+    .qs     (check_timeout_qs)
+  );
+
+
+  // R[integrity_check_period]: V(False)
+
+  prim_subreg #(
+    .DW      (32),
+    .SWACCESS("RW"),
+    .RESVAL  (32'h0)
+  ) u_integrity_check_period (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (integrity_check_period_we & check_regwen_qs),
+    .wd     (integrity_check_period_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.integrity_check_period.q),
+
+    // to register interface (read)
+    .qs     (integrity_check_period_qs)
+  );
+
+
+  // R[consistency_check_period]: V(False)
+
+  prim_subreg #(
+    .DW      (32),
+    .SWACCESS("RW"),
+    .RESVAL  (32'h0)
+  ) u_consistency_check_period (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (consistency_check_period_we & check_regwen_qs),
+    .wd     (consistency_check_period_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.consistency_check_period.q),
+
+    // to register interface (read)
+    .qs     (consistency_check_period_qs)
+  );
+
+
+  // R[creator_sw_cfg_read_lock]: V(False)
+
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("W0C"),
+    .RESVAL  (1'h1)
+  ) u_creator_sw_cfg_read_lock (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (creator_sw_cfg_read_lock_we & direct_access_regwen_qs),
+    .wd     (creator_sw_cfg_read_lock_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.creator_sw_cfg_read_lock.q),
+
+    // to register interface (read)
+    .qs     (creator_sw_cfg_read_lock_qs)
+  );
+
+
+  // R[owner_sw_cfg_read_lock]: V(False)
+
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("W0C"),
+    .RESVAL  (1'h1)
+  ) u_owner_sw_cfg_read_lock (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (owner_sw_cfg_read_lock_we & direct_access_regwen_qs),
+    .wd     (owner_sw_cfg_read_lock_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.owner_sw_cfg_read_lock.q),
+
+    // to register interface (read)
+    .qs     (owner_sw_cfg_read_lock_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg creator_sw_cfg_digest
+  // R[creator_sw_cfg_digest_0]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_creator_sw_cfg_digest_0 (
+    .re     (creator_sw_cfg_digest_0_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.creator_sw_cfg_digest[0].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (creator_sw_cfg_digest_0_qs)
+  );
+
+  // Subregister 1 of Multireg creator_sw_cfg_digest
+  // R[creator_sw_cfg_digest_1]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_creator_sw_cfg_digest_1 (
+    .re     (creator_sw_cfg_digest_1_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.creator_sw_cfg_digest[1].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (creator_sw_cfg_digest_1_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg owner_sw_cfg_digest
+  // R[owner_sw_cfg_digest_0]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_owner_sw_cfg_digest_0 (
+    .re     (owner_sw_cfg_digest_0_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.owner_sw_cfg_digest[0].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (owner_sw_cfg_digest_0_qs)
+  );
+
+  // Subregister 1 of Multireg owner_sw_cfg_digest
+  // R[owner_sw_cfg_digest_1]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_owner_sw_cfg_digest_1 (
+    .re     (owner_sw_cfg_digest_1_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.owner_sw_cfg_digest[1].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (owner_sw_cfg_digest_1_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg hw_cfg_digest
+  // R[hw_cfg_digest_0]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_hw_cfg_digest_0 (
+    .re     (hw_cfg_digest_0_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.hw_cfg_digest[0].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (hw_cfg_digest_0_qs)
+  );
+
+  // Subregister 1 of Multireg hw_cfg_digest
+  // R[hw_cfg_digest_1]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_hw_cfg_digest_1 (
+    .re     (hw_cfg_digest_1_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.hw_cfg_digest[1].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (hw_cfg_digest_1_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg secret0_digest
+  // R[secret0_digest_0]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_secret0_digest_0 (
+    .re     (secret0_digest_0_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.secret0_digest[0].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (secret0_digest_0_qs)
+  );
+
+  // Subregister 1 of Multireg secret0_digest
+  // R[secret0_digest_1]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_secret0_digest_1 (
+    .re     (secret0_digest_1_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.secret0_digest[1].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (secret0_digest_1_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg secret1_digest
+  // R[secret1_digest_0]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_secret1_digest_0 (
+    .re     (secret1_digest_0_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.secret1_digest[0].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (secret1_digest_0_qs)
+  );
+
+  // Subregister 1 of Multireg secret1_digest
+  // R[secret1_digest_1]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_secret1_digest_1 (
+    .re     (secret1_digest_1_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.secret1_digest[1].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (secret1_digest_1_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg secret2_digest
+  // R[secret2_digest_0]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_secret2_digest_0 (
+    .re     (secret2_digest_0_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.secret2_digest[0].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (secret2_digest_0_qs)
+  );
+
+  // Subregister 1 of Multireg secret2_digest
+  // R[secret2_digest_1]: V(True)
+
+  prim_subreg_ext #(
+    .DW    (32)
+  ) u_secret2_digest_1 (
+    .re     (secret2_digest_1_re),
+    .we     (1'b0),
+    .wd     ('0),
+    .d      (hw2reg.secret2_digest[1].d),
+    .qre    (),
+    .qe     (),
+    .q      (),
+    .qs     (secret2_digest_1_qs)
+  );
+
+
+
+
+  logic [32:0] addr_hit;
+  always_comb begin
+    addr_hit = '0;
+    addr_hit[ 0] = (reg_addr == OTP_CTRL_INTR_STATE_OFFSET);
+    addr_hit[ 1] = (reg_addr == OTP_CTRL_INTR_ENABLE_OFFSET);
+    addr_hit[ 2] = (reg_addr == OTP_CTRL_INTR_TEST_OFFSET);
+    addr_hit[ 3] = (reg_addr == OTP_CTRL_ALERT_TEST_OFFSET);
+    addr_hit[ 4] = (reg_addr == OTP_CTRL_STATUS_OFFSET);
+    addr_hit[ 5] = (reg_addr == OTP_CTRL_ERR_CODE_OFFSET);
+    addr_hit[ 6] = (reg_addr == OTP_CTRL_DIRECT_ACCESS_REGWEN_OFFSET);
+    addr_hit[ 7] = (reg_addr == OTP_CTRL_DIRECT_ACCESS_CMD_OFFSET);
+    addr_hit[ 8] = (reg_addr == OTP_CTRL_DIRECT_ACCESS_ADDRESS_OFFSET);
+    addr_hit[ 9] = (reg_addr == OTP_CTRL_DIRECT_ACCESS_WDATA_0_OFFSET);
+    addr_hit[10] = (reg_addr == OTP_CTRL_DIRECT_ACCESS_WDATA_1_OFFSET);
+    addr_hit[11] = (reg_addr == OTP_CTRL_DIRECT_ACCESS_RDATA_0_OFFSET);
+    addr_hit[12] = (reg_addr == OTP_CTRL_DIRECT_ACCESS_RDATA_1_OFFSET);
+    addr_hit[13] = (reg_addr == OTP_CTRL_CHECK_TRIGGER_REGWEN_OFFSET);
+    addr_hit[14] = (reg_addr == OTP_CTRL_CHECK_TRIGGER_OFFSET);
+    addr_hit[15] = (reg_addr == OTP_CTRL_CHECK_REGWEN_OFFSET);
+    addr_hit[16] = (reg_addr == OTP_CTRL_CHECK_TIMEOUT_OFFSET);
+    addr_hit[17] = (reg_addr == OTP_CTRL_INTEGRITY_CHECK_PERIOD_OFFSET);
+    addr_hit[18] = (reg_addr == OTP_CTRL_CONSISTENCY_CHECK_PERIOD_OFFSET);
+    addr_hit[19] = (reg_addr == OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_OFFSET);
+    addr_hit[20] = (reg_addr == OTP_CTRL_OWNER_SW_CFG_READ_LOCK_OFFSET);
+    addr_hit[21] = (reg_addr == OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_OFFSET);
+    addr_hit[22] = (reg_addr == OTP_CTRL_CREATOR_SW_CFG_DIGEST_1_OFFSET);
+    addr_hit[23] = (reg_addr == OTP_CTRL_OWNER_SW_CFG_DIGEST_0_OFFSET);
+    addr_hit[24] = (reg_addr == OTP_CTRL_OWNER_SW_CFG_DIGEST_1_OFFSET);
+    addr_hit[25] = (reg_addr == OTP_CTRL_HW_CFG_DIGEST_0_OFFSET);
+    addr_hit[26] = (reg_addr == OTP_CTRL_HW_CFG_DIGEST_1_OFFSET);
+    addr_hit[27] = (reg_addr == OTP_CTRL_SECRET0_DIGEST_0_OFFSET);
+    addr_hit[28] = (reg_addr == OTP_CTRL_SECRET0_DIGEST_1_OFFSET);
+    addr_hit[29] = (reg_addr == OTP_CTRL_SECRET1_DIGEST_0_OFFSET);
+    addr_hit[30] = (reg_addr == OTP_CTRL_SECRET1_DIGEST_1_OFFSET);
+    addr_hit[31] = (reg_addr == OTP_CTRL_SECRET2_DIGEST_0_OFFSET);
+    addr_hit[32] = (reg_addr == OTP_CTRL_SECRET2_DIGEST_1_OFFSET);
+  end
+
+  assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+  // Check sub-word write is permitted
+  always_comb begin
+    wr_err = (reg_we &
+              ((addr_hit[ 0] & (|(OTP_CTRL_PERMIT[ 0] & ~reg_be))) |
+               (addr_hit[ 1] & (|(OTP_CTRL_PERMIT[ 1] & ~reg_be))) |
+               (addr_hit[ 2] & (|(OTP_CTRL_PERMIT[ 2] & ~reg_be))) |
+               (addr_hit[ 3] & (|(OTP_CTRL_PERMIT[ 3] & ~reg_be))) |
+               (addr_hit[ 4] & (|(OTP_CTRL_PERMIT[ 4] & ~reg_be))) |
+               (addr_hit[ 5] & (|(OTP_CTRL_PERMIT[ 5] & ~reg_be))) |
+               (addr_hit[ 6] & (|(OTP_CTRL_PERMIT[ 6] & ~reg_be))) |
+               (addr_hit[ 7] & (|(OTP_CTRL_PERMIT[ 7] & ~reg_be))) |
+               (addr_hit[ 8] & (|(OTP_CTRL_PERMIT[ 8] & ~reg_be))) |
+               (addr_hit[ 9] & (|(OTP_CTRL_PERMIT[ 9] & ~reg_be))) |
+               (addr_hit[10] & (|(OTP_CTRL_PERMIT[10] & ~reg_be))) |
+               (addr_hit[11] & (|(OTP_CTRL_PERMIT[11] & ~reg_be))) |
+               (addr_hit[12] & (|(OTP_CTRL_PERMIT[12] & ~reg_be))) |
+               (addr_hit[13] & (|(OTP_CTRL_PERMIT[13] & ~reg_be))) |
+               (addr_hit[14] & (|(OTP_CTRL_PERMIT[14] & ~reg_be))) |
+               (addr_hit[15] & (|(OTP_CTRL_PERMIT[15] & ~reg_be))) |
+               (addr_hit[16] & (|(OTP_CTRL_PERMIT[16] & ~reg_be))) |
+               (addr_hit[17] & (|(OTP_CTRL_PERMIT[17] & ~reg_be))) |
+               (addr_hit[18] & (|(OTP_CTRL_PERMIT[18] & ~reg_be))) |
+               (addr_hit[19] & (|(OTP_CTRL_PERMIT[19] & ~reg_be))) |
+               (addr_hit[20] & (|(OTP_CTRL_PERMIT[20] & ~reg_be))) |
+               (addr_hit[21] & (|(OTP_CTRL_PERMIT[21] & ~reg_be))) |
+               (addr_hit[22] & (|(OTP_CTRL_PERMIT[22] & ~reg_be))) |
+               (addr_hit[23] & (|(OTP_CTRL_PERMIT[23] & ~reg_be))) |
+               (addr_hit[24] & (|(OTP_CTRL_PERMIT[24] & ~reg_be))) |
+               (addr_hit[25] & (|(OTP_CTRL_PERMIT[25] & ~reg_be))) |
+               (addr_hit[26] & (|(OTP_CTRL_PERMIT[26] & ~reg_be))) |
+               (addr_hit[27] & (|(OTP_CTRL_PERMIT[27] & ~reg_be))) |
+               (addr_hit[28] & (|(OTP_CTRL_PERMIT[28] & ~reg_be))) |
+               (addr_hit[29] & (|(OTP_CTRL_PERMIT[29] & ~reg_be))) |
+               (addr_hit[30] & (|(OTP_CTRL_PERMIT[30] & ~reg_be))) |
+               (addr_hit[31] & (|(OTP_CTRL_PERMIT[31] & ~reg_be))) |
+               (addr_hit[32] & (|(OTP_CTRL_PERMIT[32] & ~reg_be)))));
+  end
+  assign intr_state_we = addr_hit[0] & reg_we & !reg_error;
+
+  assign intr_state_otp_operation_done_wd = reg_wdata[0];
+
+  assign intr_state_otp_error_wd = reg_wdata[1];
+  assign intr_enable_we = addr_hit[1] & reg_we & !reg_error;
+
+  assign intr_enable_otp_operation_done_wd = reg_wdata[0];
+
+  assign intr_enable_otp_error_wd = reg_wdata[1];
+  assign intr_test_we = addr_hit[2] & reg_we & !reg_error;
+
+  assign intr_test_otp_operation_done_wd = reg_wdata[0];
+
+  assign intr_test_otp_error_wd = reg_wdata[1];
+  assign alert_test_we = addr_hit[3] & reg_we & !reg_error;
+
+  assign alert_test_fatal_macro_error_wd = reg_wdata[0];
+
+  assign alert_test_fatal_check_error_wd = reg_wdata[1];
+
+  assign alert_test_fatal_bus_integ_error_wd = reg_wdata[2];
+  assign status_re = addr_hit[4] & reg_re & !reg_error;
+  assign err_code_re = addr_hit[5] & reg_re & !reg_error;
+  assign direct_access_regwen_re = addr_hit[6] & reg_re & !reg_error;
+  assign direct_access_cmd_we = addr_hit[7] & reg_we & !reg_error;
+
+  assign direct_access_cmd_rd_wd = reg_wdata[0];
+
+  assign direct_access_cmd_wr_wd = reg_wdata[1];
+
+  assign direct_access_cmd_digest_wd = reg_wdata[2];
+  assign direct_access_address_we = addr_hit[8] & reg_we & !reg_error;
+
+  assign direct_access_address_wd = reg_wdata[10:0];
+  assign direct_access_wdata_0_we = addr_hit[9] & reg_we & !reg_error;
+
+  assign direct_access_wdata_0_wd = reg_wdata[31:0];
+  assign direct_access_wdata_1_we = addr_hit[10] & reg_we & !reg_error;
+
+  assign direct_access_wdata_1_wd = reg_wdata[31:0];
+  assign direct_access_rdata_0_re = addr_hit[11] & reg_re & !reg_error;
+  assign direct_access_rdata_1_re = addr_hit[12] & reg_re & !reg_error;
+  assign check_trigger_regwen_we = addr_hit[13] & reg_we & !reg_error;
+
+  assign check_trigger_regwen_wd = reg_wdata[0];
+  assign check_trigger_we = addr_hit[14] & reg_we & !reg_error;
+
+  assign check_trigger_integrity_wd = reg_wdata[0];
+
+  assign check_trigger_consistency_wd = reg_wdata[1];
+  assign check_regwen_we = addr_hit[15] & reg_we & !reg_error;
+
+  assign check_regwen_wd = reg_wdata[0];
+  assign check_timeout_we = addr_hit[16] & reg_we & !reg_error;
+
+  assign check_timeout_wd = reg_wdata[31:0];
+  assign integrity_check_period_we = addr_hit[17] & reg_we & !reg_error;
+
+  assign integrity_check_period_wd = reg_wdata[31:0];
+  assign consistency_check_period_we = addr_hit[18] & reg_we & !reg_error;
+
+  assign consistency_check_period_wd = reg_wdata[31:0];
+  assign creator_sw_cfg_read_lock_we = addr_hit[19] & reg_we & !reg_error;
+
+  assign creator_sw_cfg_read_lock_wd = reg_wdata[0];
+  assign owner_sw_cfg_read_lock_we = addr_hit[20] & reg_we & !reg_error;
+
+  assign owner_sw_cfg_read_lock_wd = reg_wdata[0];
+  assign creator_sw_cfg_digest_0_re = addr_hit[21] & reg_re & !reg_error;
+  assign creator_sw_cfg_digest_1_re = addr_hit[22] & reg_re & !reg_error;
+  assign owner_sw_cfg_digest_0_re = addr_hit[23] & reg_re & !reg_error;
+  assign owner_sw_cfg_digest_1_re = addr_hit[24] & reg_re & !reg_error;
+  assign hw_cfg_digest_0_re = addr_hit[25] & reg_re & !reg_error;
+  assign hw_cfg_digest_1_re = addr_hit[26] & reg_re & !reg_error;
+  assign secret0_digest_0_re = addr_hit[27] & reg_re & !reg_error;
+  assign secret0_digest_1_re = addr_hit[28] & reg_re & !reg_error;
+  assign secret1_digest_0_re = addr_hit[29] & reg_re & !reg_error;
+  assign secret1_digest_1_re = addr_hit[30] & reg_re & !reg_error;
+  assign secret2_digest_0_re = addr_hit[31] & reg_re & !reg_error;
+  assign secret2_digest_1_re = addr_hit[32] & reg_re & !reg_error;
+
+  // Read data return
+  always_comb begin
+    reg_rdata_next = '0;
+    unique case (1'b1)
+      addr_hit[0]: begin
+        reg_rdata_next[0] = intr_state_otp_operation_done_qs;
+        reg_rdata_next[1] = intr_state_otp_error_qs;
+      end
+
+      addr_hit[1]: begin
+        reg_rdata_next[0] = intr_enable_otp_operation_done_qs;
+        reg_rdata_next[1] = intr_enable_otp_error_qs;
+      end
+
+      addr_hit[2]: begin
+        reg_rdata_next[0] = '0;
+        reg_rdata_next[1] = '0;
+      end
+
+      addr_hit[3]: begin
+        reg_rdata_next[0] = '0;
+        reg_rdata_next[1] = '0;
+        reg_rdata_next[2] = '0;
+      end
+
+      addr_hit[4]: begin
+        reg_rdata_next[0] = status_creator_sw_cfg_error_qs;
+        reg_rdata_next[1] = status_owner_sw_cfg_error_qs;
+        reg_rdata_next[2] = status_hw_cfg_error_qs;
+        reg_rdata_next[3] = status_secret0_error_qs;
+        reg_rdata_next[4] = status_secret1_error_qs;
+        reg_rdata_next[5] = status_secret2_error_qs;
+        reg_rdata_next[6] = status_life_cycle_error_qs;
+        reg_rdata_next[7] = status_dai_error_qs;
+        reg_rdata_next[8] = status_lci_error_qs;
+        reg_rdata_next[9] = status_timeout_error_qs;
+        reg_rdata_next[10] = status_lfsr_fsm_error_qs;
+        reg_rdata_next[11] = status_scrambling_fsm_error_qs;
+        reg_rdata_next[12] = status_key_deriv_fsm_error_qs;
+        reg_rdata_next[13] = status_bus_integ_error_qs;
+        reg_rdata_next[14] = status_dai_idle_qs;
+        reg_rdata_next[15] = status_check_pending_qs;
+      end
+
+      addr_hit[5]: begin
+        reg_rdata_next[2:0] = err_code_err_code_0_qs;
+        reg_rdata_next[5:3] = err_code_err_code_1_qs;
+        reg_rdata_next[8:6] = err_code_err_code_2_qs;
+        reg_rdata_next[11:9] = err_code_err_code_3_qs;
+        reg_rdata_next[14:12] = err_code_err_code_4_qs;
+        reg_rdata_next[17:15] = err_code_err_code_5_qs;
+        reg_rdata_next[20:18] = err_code_err_code_6_qs;
+        reg_rdata_next[23:21] = err_code_err_code_7_qs;
+        reg_rdata_next[26:24] = err_code_err_code_8_qs;
+      end
+
+      addr_hit[6]: begin
+        reg_rdata_next[0] = direct_access_regwen_qs;
+      end
+
+      addr_hit[7]: begin
+        reg_rdata_next[0] = '0;
+        reg_rdata_next[1] = '0;
+        reg_rdata_next[2] = '0;
+      end
+
+      addr_hit[8]: begin
+        reg_rdata_next[10:0] = direct_access_address_qs;
+      end
+
+      addr_hit[9]: begin
+        reg_rdata_next[31:0] = direct_access_wdata_0_qs;
+      end
+
+      addr_hit[10]: begin
+        reg_rdata_next[31:0] = direct_access_wdata_1_qs;
+      end
+
+      addr_hit[11]: begin
+        reg_rdata_next[31:0] = direct_access_rdata_0_qs;
+      end
+
+      addr_hit[12]: begin
+        reg_rdata_next[31:0] = direct_access_rdata_1_qs;
+      end
+
+      addr_hit[13]: begin
+        reg_rdata_next[0] = check_trigger_regwen_qs;
+      end
+
+      addr_hit[14]: begin
+        reg_rdata_next[0] = '0;
+        reg_rdata_next[1] = '0;
+      end
+
+      addr_hit[15]: begin
+        reg_rdata_next[0] = check_regwen_qs;
+      end
+
+      addr_hit[16]: begin
+        reg_rdata_next[31:0] = check_timeout_qs;
+      end
+
+      addr_hit[17]: begin
+        reg_rdata_next[31:0] = integrity_check_period_qs;
+      end
+
+      addr_hit[18]: begin
+        reg_rdata_next[31:0] = consistency_check_period_qs;
+      end
+
+      addr_hit[19]: begin
+        reg_rdata_next[0] = creator_sw_cfg_read_lock_qs;
+      end
+
+      addr_hit[20]: begin
+        reg_rdata_next[0] = owner_sw_cfg_read_lock_qs;
+      end
+
+      addr_hit[21]: begin
+        reg_rdata_next[31:0] = creator_sw_cfg_digest_0_qs;
+      end
+
+      addr_hit[22]: begin
+        reg_rdata_next[31:0] = creator_sw_cfg_digest_1_qs;
+      end
+
+      addr_hit[23]: begin
+        reg_rdata_next[31:0] = owner_sw_cfg_digest_0_qs;
+      end
+
+      addr_hit[24]: begin
+        reg_rdata_next[31:0] = owner_sw_cfg_digest_1_qs;
+      end
+
+      addr_hit[25]: begin
+        reg_rdata_next[31:0] = hw_cfg_digest_0_qs;
+      end
+
+      addr_hit[26]: begin
+        reg_rdata_next[31:0] = hw_cfg_digest_1_qs;
+      end
+
+      addr_hit[27]: begin
+        reg_rdata_next[31:0] = secret0_digest_0_qs;
+      end
+
+      addr_hit[28]: begin
+        reg_rdata_next[31:0] = secret0_digest_1_qs;
+      end
+
+      addr_hit[29]: begin
+        reg_rdata_next[31:0] = secret1_digest_0_qs;
+      end
+
+      addr_hit[30]: begin
+        reg_rdata_next[31:0] = secret1_digest_1_qs;
+      end
+
+      addr_hit[31]: begin
+        reg_rdata_next[31:0] = secret2_digest_0_qs;
+      end
+
+      addr_hit[32]: begin
+        reg_rdata_next[31:0] = secret2_digest_1_qs;
+      end
+
+      default: begin
+        reg_rdata_next = '1;
+      end
+    endcase
+  end
+
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
+  // Unused signal tieoff
+
+  // wdata / byte enable are not always fully used
+  // add a blanket unused statement to handle lint waivers
+  logic unused_wdata;
+  logic unused_be;
+  assign unused_wdata = ^reg_wdata;
+  assign unused_be = ^reg_be;
+
+  // Assertions for Register Interface
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
+
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
+
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
+
+  // this is formulated as an assumption such that the FPV testbenches do disprove this
+  // property by mistake
+  //`ASSUME(reqParity, tl_reg_h2d.a_valid |-> tl_reg_h2d.a_user.chk_en == tlul_pkg::CheckDis)
+
+endmodule
diff --git a/hw/ip/pattgen/rtl/pattgen_reg_top.sv b/hw/ip/pattgen/rtl/pattgen_reg_top.sv
index ec6b0da..2368204 100644
--- a/hw/ip/pattgen/rtl/pattgen_reg_top.sv
+++ b/hw/ip/pattgen/rtl/pattgen_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -850,6 +855,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -860,12 +876,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/pinmux/rtl/pinmux_reg_top.sv b/hw/ip/pinmux/rtl/pinmux_reg_top.sv
index a499017..276e961 100644
--- a/hw/ip/pinmux/rtl/pinmux_reg_top.sv
+++ b/hw/ip/pinmux/rtl/pinmux_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -17951,6 +17956,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -17961,12 +17977,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/prim/prim_subreg.core b/hw/ip/prim/prim_subreg.core
index df4672b..815ca24 100644
--- a/hw/ip/prim/prim_subreg.core
+++ b/hw/ip/prim/prim_subreg.core
@@ -10,8 +10,11 @@
     files:
       - rtl/prim_subreg_pkg.sv
       - rtl/prim_subreg_arb.sv
+      - rtl/prim_subreg_cdc.sv
       - rtl/prim_subreg.sv
+      - rtl/prim_subreg_async.sv
       - rtl/prim_subreg_ext.sv
+      - rtl/prim_subreg_ext_async.sv
       - rtl/prim_subreg_shadow.sv
     file_type: systemVerilogSource
 
diff --git a/hw/ip/prim/rtl/prim_subreg_async.sv b/hw/ip/prim/rtl/prim_subreg_async.sv
new file mode 100644
index 0000000..b9d1ae1
--- /dev/null
+++ b/hw/ip/prim/rtl/prim_subreg_async.sv
@@ -0,0 +1,85 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Asynchronous implementation of prim_subreg
+
+module prim_subreg_async
+  import prim_subreg_pkg::*;
+#(
+  parameter int            DW       = 32  ,
+  parameter sw_access_e    SwAccess = SwAccessRW,
+  parameter logic [DW-1:0] RESVAL   = '0    // Reset value
+) (
+  input clk_src_i,
+  input rst_src_ni,
+  input clk_dst_i,
+  input rst_dst_ni,
+
+  // destination sample pulse
+  input src_update_i,
+
+  // From SW: valid for RW, WO, W1C, W1S, W0C, RC
+  // In case of RC, Top connects Read Pulse to we
+  input          src_we_i,
+  input [DW-1:0] src_wd_i,
+
+  // From HW: valid for HRW, HWO
+  input          dst_de_i,
+  input [DW-1:0] dst_d_i,
+
+  // output to Reg Read
+  output logic          src_busy_o,
+  output logic [DW-1:0] src_qs_o,
+
+  // output to HW read
+  output logic          dst_qe_o,
+  // This output does not follow comportable convention to work with
+  // current DV assumptions.
+  output logic [DW-1:0] q
+);
+
+  logic dst_we;
+  logic [DW-1:0] dst_wdata;
+  logic [DW-1:0] q_int;
+
+  prim_subreg_cdc #(
+    .DW(DW),
+    .RESVAL(RESVAL)
+  ) u_reg_cdc (
+    .clk_src_i,
+    .rst_src_ni,
+    .clk_dst_i,
+    .rst_dst_ni,
+    .src_update_i,
+    .src_req_i(src_we_i),
+    // data that crosses domain
+    .src_data_i(src_wd_i),
+    // data readback to software
+    .src_data_o(src_qs_o),
+    .src_busy_o,
+    .dst_req_o(dst_we),
+    // hardware written data
+    .dst_data_i(q_int),
+    // data to write to hardware
+    .dst_data_o(dst_wdata)
+  );
+
+  prim_subreg #(
+    .DW(DW),
+    .SwAccess(SwAccess),
+    .RESVAL(RESVAL)
+  ) u_subreg (
+    .clk_i(clk_dst_i),
+    .rst_ni(rst_dst_ni),
+    .we(dst_we),
+    .wd(dst_wdata),
+    .de(dst_de_i),
+    .d(dst_d_i),
+    .qe(dst_qe_o),
+    .q(q_int),
+    .qs()
+  );
+  assign q = q_int;
+
+endmodule
diff --git a/hw/ip/prim/rtl/prim_subreg_cdc.sv b/hw/ip/prim/rtl/prim_subreg_cdc.sv
new file mode 100644
index 0000000..18618be
--- /dev/null
+++ b/hw/ip/prim/rtl/prim_subreg_cdc.sv
@@ -0,0 +1,135 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Component handling register CDC
+
+`include "prim_assert.sv"
+
+module prim_subreg_cdc #(
+  parameter int            DW       = 32,
+  parameter logic [DW-1:0] RESVAL   = '0    // Reset value
+) (
+  input clk_src_i,
+  input rst_src_ni,
+  input clk_dst_i,
+  input rst_dst_ni,
+
+  input src_update_i,
+  input src_req_i,
+  input [DW-1:0] src_data_i,
+  output logic src_busy_o,
+  output logic [DW-1:0] src_data_o,
+
+  input [DW-1:0] dst_data_i,
+  output logic dst_req_o,
+  output logic [DW-1:0] dst_data_o
+);
+
+  ////////////////////////////
+  // Source domain
+  ////////////////////////////
+  logic src_ack;
+  logic src_busy_q;
+  logic [DW-1:0] src_q;
+
+  // busy indication back-pressures upstream if the register is accessed
+  // again.  The busy indication is also used as a "commit" indication for
+  // resolving software and hardware write conflicts
+  always_ff @(posedge clk_src_i or negedge rst_src_ni) begin
+    if (!rst_src_ni) begin
+      src_busy_q <= '0;
+    end else if (src_req_i) begin
+      src_busy_q <= 1'b1;
+    end else if (src_busy_q && src_ack) begin
+      src_busy_q <= 1'b0;
+    end
+  end
+
+  assign src_busy_o = src_busy_q;
+
+  // src_q acts as both the write holding register and the software read back
+  // register.
+  // When software performs a write, the write data is captured in src_q for
+  // CDC purposes.  When not performing a write, the src_q periodically
+  // samples the destination domain using the src_update_i indication.
+  //
+  // To resolve software and hardware conflicts, the process is as follows:
+  // When software issues a write, this module asserts "busy".  While busy,
+  // src_q does not sample the destination value.  Since the
+  // logic has committed to updating based on software command, there is an irreversible
+  // window from which hardware writes are ignored.  Once the busy window completes,
+  // the cdc portion then begins sampling once more.
+  //
+  // This is consistent with prim_subreg_arb where during software / hardware conflicts,
+  // software is always prioritized.  The main difference is the conflict resolution window
+  // is now larger instead of just one destination clock cycle.
+
+  logic busy;
+  assign busy = src_busy_q & !src_ack;
+
+  always_ff @(posedge clk_src_i or negedge rst_src_ni) begin
+    if (!rst_src_ni) begin
+      src_q <= RESVAL;
+    end else if (src_req_i && !busy) begin
+      src_q <= src_data_i;
+    end else if (src_busy_q && src_ack || src_update_i && !busy) begin
+      // sample data whenever a busy transaction finishes OR
+      // when an update pulse is seen.
+      // TODO: We should add a cover group to test different sync timings
+      // between src_ack and src_update. Ie, there can be 3 scearios:
+      // 1. update one cycle before ack
+      // 2. ack one cycle before update
+      // 3. update / ack on the same cycle
+      // During all 3 cases the read data should be correct
+      src_q <= dst_data_i;
+    end
+  end
+
+  // src_q is always updated in the clk_src domain.
+  // when performing an update to the destination domain, it is guaranteed
+  // to not change by protocol.
+  assign src_data_o = src_q;
+  assign dst_data_o = src_q;
+
+  ////////////////////////////
+  // CDC handling
+  ////////////////////////////
+  prim_sync_reqack u_prim_sync (
+    .clk_src_i,
+    .rst_src_ni,
+    .clk_dst_i,
+    .rst_dst_ni,
+    .req_chk_i(1'b0),
+    // prim_sync_reqack does not natively handle single
+    // pulse requests, so use src_busy to even it out.
+    .src_req_i(src_req_i | src_busy_q),
+    .src_ack_o(src_ack),
+    .dst_req_o(dst_req_o),
+    // immediately ack on destination once request is seen
+    .dst_ack_i(dst_req_o)
+  );
+
+  `ASSERT_KNOWN(SrcBusyKnown_A, src_busy_o, clk_src_i, !rst_src_ni)
+  `ASSERT_KNOWN(DstReqKnown_A, dst_req_o, clk_dst_i, !rst_dst_ni)
+
+  // If busy goes high, we must eventually see an ack
+  `ASSERT(HungHandShake_A, $rose(src_busy_o) |-> strong(##[0:$] src_ack), clk_src_i, !rst_src_ni)
+
+  `ifdef SIMULATION
+    logic async_flag;
+    always_ff @(posedge src_req_i or posedge dst_req_o or
+      negedge rst_src_ni or negedge rst_dst_ni) begin
+      if (!rst_src_ni && !rst_dst_ni) begin
+        async_flag <= '0;
+      end else if (src_req_i) begin
+        async_flag <= 1'b1;
+      end else if (dst_req_o) begin
+        async_flag <= 1'b0;
+      end
+    end
+    `ASSERT(ReqTimeout_A, $rose(async_flag) |-> strong(##[0:3] dst_req_o), clk_dst_i, !rst_dst_ni)
+  `endif
+
+
+endmodule // prim_subreg_cdc
diff --git a/hw/ip/prim/rtl/prim_subreg_ext_async.sv b/hw/ip/prim/rtl/prim_subreg_ext_async.sv
new file mode 100644
index 0000000..7b8576e
--- /dev/null
+++ b/hw/ip/prim/rtl/prim_subreg_ext_async.sv
@@ -0,0 +1,68 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Asynchronous implementation of prim_subreg_ext
+
+module prim_subreg_ext_async #(
+  parameter int unsigned DW = 32
+) (
+  input          clk_src_i,
+  input          rst_src_ni,
+  input          clk_dst_i,
+  input          rst_dst_ni,
+
+  // source domain signals
+  input          re,
+  input          we,
+  input [DW-1:0] wd,
+  input          src_update_i,
+  output logic   src_busy_o,
+
+  // destination domain signals
+  input [DW-1:0] d,
+
+  // outputs to destination domain
+  output logic          qe,
+  output logic          qre,
+  output logic [DW-1:0] q,
+
+  // outputs to source domain
+  output logic [DW-1:0] qs
+);
+
+  logic dst_req;
+  logic [DW-1:0] dst_wdata;
+  logic dst_we;
+  logic unused_src_we;
+
+  // Capture both data and write-enable
+  // write enable is needed to determine whether qe or qre should be generated
+  // in the desitnation domain.
+  prim_subreg_cdc #(
+    .DW(DW + 1)
+  ) u_reg_cdc (
+    .clk_src_i,
+    .rst_src_ni,
+    .clk_dst_i,
+    .rst_dst_ni,
+    .src_update_i,
+    .src_req_i(re | we),
+    .src_data_i({wd, we}),
+    .src_data_o({qs, unused_src_we}),
+    .src_busy_o,
+    .dst_req_o(dst_req),
+    .dst_data_i({d, 1'b0}),
+    .dst_data_o({dst_wdata, dst_we})
+  );
+
+  /////////////////////
+  // Destination domain
+  /////////////////////
+
+  assign qe  = dst_req ? dst_we    : '0;
+  assign qre = dst_req ? ~dst_we   : '0;
+  assign q   = dst_req ? dst_wdata : '0;
+
+
+endmodule
diff --git a/hw/ip/pwm/rtl/pwm_reg_top.sv b/hw/ip/pwm/rtl/pwm_reg_top.sv
index e54be57..8b2a130 100644
--- a/hw/ip/pwm/rtl/pwm_reg_top.sv
+++ b/hw/ip/pwm/rtl/pwm_reg_top.sv
@@ -40,14 +40,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -71,7 +73,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -82,8 +84,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -93,10 +95,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -2181,6 +2186,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -2191,12 +2207,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr_reg_top.sv b/hw/ip/pwrmgr/rtl/pwrmgr_reg_top.sv
index 1054560..c12cc98 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr_reg_top.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -836,6 +841,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -846,12 +862,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/rom_ctrl/rtl/rom_ctrl_regs_reg_top.sv b/hw/ip/rom_ctrl/rtl/rom_ctrl_regs_reg_top.sv
index b29706b..a37b59d 100644
--- a/hw/ip/rom_ctrl/rtl/rom_ctrl_regs_reg_top.sv
+++ b/hw/ip/rom_ctrl/rtl/rom_ctrl_regs_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -768,6 +773,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -778,12 +794,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/rom_ctrl/rtl/rom_ctrl_rom_reg_top.sv b/hw/ip/rom_ctrl/rtl/rom_ctrl_rom_reg_top.sv
index da9fbd3..b5246ff 100644
--- a/hw/ip/rom_ctrl/rtl/rom_ctrl_rom_reg_top.sv
+++ b/hw/ip/rom_ctrl/rtl/rom_ctrl_rom_reg_top.sv
@@ -29,10 +29,11 @@
   import rom_ctrl_reg_pkg::* ;
 
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -56,7 +57,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_win_o = tl_i;
diff --git a/hw/ip/rstmgr/rtl/rstmgr_reg_top.sv b/hw/ip/rstmgr/rtl/rstmgr_reg_top.sv
index 28e60fc..0494e24 100644
--- a/hw/ip/rstmgr/rtl/rstmgr_reg_top.sv
+++ b/hw/ip/rstmgr/rtl/rstmgr_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -512,6 +517,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -522,12 +538,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/rv_core_ibex/rtl/rv_core_ibex_cfg_reg_top.sv b/hw/ip/rv_core_ibex/rtl/rv_core_ibex_cfg_reg_top.sv
index 39ad51b..7575efe 100644
--- a/hw/ip/rv_core_ibex/rtl/rv_core_ibex_cfg_reg_top.sv
+++ b/hw/ip/rv_core_ibex/rtl/rv_core_ibex_cfg_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1290,6 +1295,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1300,12 +1316,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/rv_dm/rtl/rv_dm_regs_reg_top.sv b/hw/ip/rv_dm/rtl/rv_dm_regs_reg_top.sv
index 0f99a74..dfc1768 100644
--- a/hw/ip/rv_dm/rtl/rv_dm_regs_reg_top.sv
+++ b/hw/ip/rv_dm/rtl/rv_dm_regs_reg_top.sv
@@ -40,14 +40,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -71,7 +73,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -82,8 +84,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -93,10 +95,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -156,6 +161,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -166,12 +182,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/rv_dm/rtl/rv_dm_rom_reg_top.sv b/hw/ip/rv_dm/rtl/rv_dm_rom_reg_top.sv
index 68b2083..86fc22a 100644
--- a/hw/ip/rv_dm/rtl/rv_dm_rom_reg_top.sv
+++ b/hw/ip/rv_dm/rtl/rv_dm_rom_reg_top.sv
@@ -29,10 +29,11 @@
   import rv_dm_reg_pkg::* ;
 
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -56,7 +57,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_win_o = tl_i;
diff --git a/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv b/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
index f91e2b5..12aa254 100644
--- a/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
+++ b/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -4427,6 +4432,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -4437,12 +4453,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv b/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
index 8ce4007..c682f34 100644
--- a/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
+++ b/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -536,6 +541,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -546,12 +562,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/spi_device/rtl/spi_device_reg_top.sv b/hw/ip/spi_device/rtl/spi_device_reg_top.sv
index dd7dafa..4f2a0e7 100644
--- a/hw/ip/spi_device/rtl/spi_device_reg_top.sv
+++ b/hw/ip/spi_device/rtl/spi_device_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [2];
@@ -104,8 +106,8 @@
     .DReqDepth  ({2{4'h0}}),
     .DRspDepth  ({2{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -131,8 +133,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -142,10 +144,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -14302,6 +14307,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -14312,12 +14328,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/spi_host/rtl/spi_host_reg_top.sv b/hw/ip/spi_host/rtl/spi_host_reg_top.sv
index 8ad601d..731e63a 100644
--- a/hw/ip/spi_host/rtl/spi_host_reg_top.sv
+++ b/hw/ip/spi_host/rtl/spi_host_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [2];
@@ -104,8 +106,8 @@
     .DReqDepth  ({2{4'h0}}),
     .DRspDepth  ({2{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -131,8 +133,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -142,10 +144,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1822,6 +1827,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1832,12 +1848,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/spi_host/rtl/spi_host_window.sv b/hw/ip/spi_host/rtl/spi_host_window.sv
index 768a93d..2af9cda 100644
--- a/hw/ip/spi_host/rtl/spi_host_window.sv
+++ b/hw/ip/spi_host/rtl/spi_host_window.sv
@@ -40,6 +40,7 @@
     .addr_o    (addr),
     .wdata_o   (tx_data_o),
     .be_o      (tx_be_o),
+    .busy_i    ('0),
     .rdata_i   (rx_data_i),
     .error_i   (win_error)
   );
diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_top.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_top.sv
index d5d1917..1353931 100644
--- a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_top.sv
+++ b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -456,6 +461,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -466,12 +482,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/sysrst_ctrl/rtl/sysrst_ctrl_reg_top.sv b/hw/ip/sysrst_ctrl/rtl/sysrst_ctrl_reg_top.sv
index 4b526e5..999f324 100644
--- a/hw/ip/sysrst_ctrl/rtl/sysrst_ctrl_reg_top.sv
+++ b/hw/ip/sysrst_ctrl/rtl/sysrst_ctrl_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -4611,6 +4616,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -4621,12 +4637,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/tlul/rtl/tlul_adapter_reg.sv b/hw/ip/tlul/rtl/tlul_adapter_reg.sv
index 49625f9..54c0d9c 100644
--- a/hw/ip/tlul/rtl/tlul_adapter_reg.sv
+++ b/hw/ip/tlul/rtl/tlul_adapter_reg.sv
@@ -27,6 +27,7 @@
   output logic [RegAw-1:0] addr_o,
   output logic [RegDw-1:0] wdata_o,
   output logic [RegBw-1:0] be_o,
+  input                    busy_i,
   input        [RegDw-1:0] rdata_i,
   input                    error_i
 );
@@ -108,8 +109,13 @@
     assign data_intg = '0;
   end
 
+  logic req_valid;
+  assign req_valid = tl_i.a_valid;
+
   assign tl_o = '{
-    a_ready:  ~outstanding,
+    // busy is selected based on address
+    // thus if there is no valid transaction, we should ignore busy
+    a_ready:  ~(outstanding | req_valid & busy_i),
     d_valid:  outstanding,
     d_opcode: rspop,
     d_param:  '0,
diff --git a/hw/ip/trial1/data/trial1.hjson b/hw/ip/trial1/data/trial1.hjson
index 4b7697e..4052afc 100644
--- a/hw/ip/trial1/data/trial1.hjson
+++ b/hw/ip/trial1/data/trial1.hjson
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0
 { name: "TRIAL1",
   regwidth: 32,
-  clocking: [{clock: "clk_fixed", reset: "rst_fixed_n"}],
+  clocking: [{clock: "clk_fixed_i", reset: "rst_fixed_n"}],
   bus_interfaces: [
     { protocol: "tlul", direction: "device" }
   ],
diff --git a/hw/ip/trial1/rtl/trial1_reg_top.sv b/hw/ip/trial1/rtl/trial1_reg_top.sv
index 40798c3..4c21906 100644
--- a/hw/ip/trial1/rtl/trial1_reg_top.sv
+++ b/hw/ip/trial1/rtl/trial1_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1272,6 +1277,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1282,12 +1298,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/uart/rtl/uart_reg_top.sv b/hw/ip/uart/rtl/uart_reg_top.sv
index 4c5740f..e4d0381 100644
--- a/hw/ip/uart/rtl/uart_reg_top.sv
+++ b/hw/ip/uart/rtl/uart_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1635,6 +1640,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1645,12 +1661,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/usbdev/rtl/usbdev_reg_top.sv b/hw/ip/usbdev/rtl/usbdev_reg_top.sv
index 111f5f8..75ee722 100644
--- a/hw/ip/usbdev/rtl/usbdev_reg_top.sv
+++ b/hw/ip/usbdev/rtl/usbdev_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [2];
@@ -104,8 +106,8 @@
     .DReqDepth  ({2{4'h0}}),
     .DRspDepth  ({2{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -131,8 +133,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -142,10 +144,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -6702,6 +6707,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -6712,12 +6728,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/ip/usbuart/rtl/usbuart_reg_top.sv b/hw/ip/usbuart/rtl/usbuart_reg_top.sv
index 1b70d0c..ec7f13c 100644
--- a/hw/ip/usbuart/rtl/usbuart_reg_top.sv
+++ b/hw/ip/usbuart/rtl/usbuart_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1757,6 +1762,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1767,12 +1783,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/alert_handler/rtl/autogen/alert_handler_reg_top.sv b/hw/top_earlgrey/ip/alert_handler/rtl/autogen/alert_handler_reg_top.sv
index 8172158..5f6c923 100644
--- a/hw/top_earlgrey/ip/alert_handler/rtl/autogen/alert_handler_reg_top.sv
+++ b/hw/top_earlgrey/ip/alert_handler/rtl/autogen/alert_handler_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -16900,6 +16905,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -16910,12 +16926,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/ast/rtl/ast_reg_top.sv b/hw/top_earlgrey/ip/ast/rtl/ast_reg_top.sv
index a3a5fba..02be432 100644
--- a/hw/top_earlgrey/ip/ast/rtl/ast_reg_top.sv
+++ b/hw/top_earlgrey/ip/ast/rtl/ast_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -2508,6 +2513,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -2518,12 +2534,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_top.sv b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_top.sv
index e99b488..35382ad 100644
--- a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_top.sv
+++ b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -718,6 +723,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -728,12 +744,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
index e768b89..73ff107 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_core_reg_top.sv
@@ -46,14 +46,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -77,7 +79,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [3];
@@ -106,8 +108,8 @@
     .DReqDepth  ({3{4'h0}}),
     .DRspDepth  ({3{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
@@ -136,8 +138,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -147,10 +149,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -12322,6 +12327,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -12332,12 +12348,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_prim_reg_top.sv b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_prim_reg_top.sv
index 53c5691..65335a1 100644
--- a/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_prim_reg_top.sv
+++ b/hw/top_earlgrey/ip/flash_ctrl/rtl/autogen/flash_ctrl_prim_reg_top.sv
@@ -24,10 +24,11 @@
   import flash_ctrl_reg_pkg::* ;
 
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -51,7 +52,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   tlul_pkg::tl_h2d_t tl_socket_h2d [0];
@@ -73,8 +74,8 @@
     .DReqDepth  ({0{4'h0}}),
     .DRspDepth  ({0{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
     .tl_h_i (tl_i),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
diff --git a/hw/top_earlgrey/ip/pinmux/rtl/autogen/pinmux_reg_top.sv b/hw/top_earlgrey/ip/pinmux/rtl/autogen/pinmux_reg_top.sv
index 36a1897..741afa7 100644
--- a/hw/top_earlgrey/ip/pinmux/rtl/autogen/pinmux_reg_top.sv
+++ b/hw/top_earlgrey/ip/pinmux/rtl/autogen/pinmux_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -25916,6 +25921,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -25926,12 +25942,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/pwrmgr/rtl/autogen/pwrmgr_reg_top.sv b/hw/top_earlgrey/ip/pwrmgr/rtl/autogen/pwrmgr_reg_top.sv
index b657f8e..787b243 100644
--- a/hw/top_earlgrey/ip/pwrmgr/rtl/autogen/pwrmgr_reg_top.sv
+++ b/hw/top_earlgrey/ip/pwrmgr/rtl/autogen/pwrmgr_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1200,6 +1205,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1210,12 +1226,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/rstmgr/rtl/autogen/rstmgr_reg_top.sv b/hw/top_earlgrey/ip/rstmgr/rtl/autogen/rstmgr_reg_top.sv
index f8c10c6..5021532 100644
--- a/hw/top_earlgrey/ip/rstmgr/rtl/autogen/rstmgr_reg_top.sv
+++ b/hw/top_earlgrey/ip/rstmgr/rtl/autogen/rstmgr_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -993,6 +998,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1003,12 +1019,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/rv_plic/rtl/autogen/rv_plic_reg_top.sv b/hw/top_earlgrey/ip/rv_plic/rtl/autogen/rv_plic_reg_top.sv
index 01dd5f3..cb7d631 100644
--- a/hw/top_earlgrey/ip/rv_plic/rtl/autogen/rv_plic_reg_top.sv
+++ b/hw/top_earlgrey/ip/rv_plic/rtl/autogen/rv_plic_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -23530,6 +23535,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -23540,12 +23556,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/hw/top_earlgrey/ip/sensor_ctrl/rtl/sensor_ctrl_reg_top.sv b/hw/top_earlgrey/ip/sensor_ctrl/rtl/sensor_ctrl_reg_top.sv
index e24bf41..e41bf6b 100644
--- a/hw/top_earlgrey/ip/sensor_ctrl/rtl/sensor_ctrl_reg_top.sv
+++ b/hw/top_earlgrey/ip/sensor_ctrl/rtl/sensor_ctrl_reg_top.sv
@@ -41,14 +41,16 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(tl_i),
     .err_o(intg_err)
   );
 
@@ -72,7 +74,7 @@
     .EnableDataIntgGen(1)
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(tl_o)
   );
 
   assign tl_reg_h2d = tl_i;
@@ -83,8 +85,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(0)
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (clk_i),
+    .rst_ni (rst_ni),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -94,10 +96,13 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+  // cdc oversampling signals
+
   assign reg_rdata = reg_rdata_next ;
   assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
 
@@ -1733,6 +1738,17 @@
     endcase
   end
 
+  // register busy
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+
+
   // Unused signal tieoff
 
   // wdata / byte enable are not always fully used
@@ -1743,12 +1759,12 @@
   assign unused_be = ^reg_be;
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+  `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
diff --git a/util/reggen/bus_interfaces.py b/util/reggen/bus_interfaces.py
index 98ce995..32d3312 100644
--- a/util/reggen/bus_interfaces.py
+++ b/util/reggen/bus_interfaces.py
@@ -14,30 +14,36 @@
     def __init__(self,
                  has_unnamed_host: bool,
                  named_hosts: List[str],
+                 host_async: Dict[Optional[str], str],
                  has_unnamed_device: bool,
-                 named_devices: List[str]):
+                 named_devices: List[str],
+                 device_async: Dict[Optional[str], str]):
         assert has_unnamed_device or named_devices
         assert len(named_hosts) == len(set(named_hosts))
         assert len(named_devices) == len(set(named_devices))
 
         self.has_unnamed_host = has_unnamed_host
         self.named_hosts = named_hosts
+        self.host_async = host_async
         self.has_unnamed_device = has_unnamed_device
         self.named_devices = named_devices
+        self.device_async = device_async
 
     @staticmethod
     def from_raw(raw: object, where: str) -> 'BusInterfaces':
         has_unnamed_host = False
         named_hosts = []
+        host_async = {}
 
         has_unnamed_device = False
         named_devices = []
+        device_async = {}
 
         for idx, raw_entry in enumerate(check_list(raw, where)):
             entry_what = 'entry {} of {}'.format(idx + 1, where)
             ed = check_keys(raw_entry, entry_what,
                             ['protocol', 'direction'],
-                            ['name'])
+                            ['name', 'async'])
 
             protocol = check_str(ed['protocol'],
                                  'protocol field of ' + entry_what)
@@ -54,6 +60,9 @@
             name = check_optional_str(ed.get('name'),
                                       'name field of ' + entry_what)
 
+            async_clk = check_optional_str(ed.get('async'),
+                                           'async field of ' + entry_what)
+
             if direction == 'host':
                 if name is None:
                     if has_unnamed_host:
@@ -67,6 +76,9 @@
                                          'with name {!r} at {}'
                                          .format(name, where))
                     named_hosts.append(name)
+
+                if async_clk is not None:
+                    host_async[name] = async_clk
             else:
                 if name is None:
                     if has_unnamed_device:
@@ -81,11 +93,14 @@
                                          .format(name, where))
                     named_devices.append(name)
 
+                if async_clk is not None:
+                    device_async[name] = async_clk
+
         if not (has_unnamed_device or named_devices):
             raise ValueError('No device interface at ' + where)
 
-        return BusInterfaces(has_unnamed_host, named_hosts,
-                             has_unnamed_device, named_devices)
+        return BusInterfaces(has_unnamed_host, named_hosts, host_async,
+                             has_unnamed_device, named_devices, device_async)
 
     def has_host(self) -> bool:
         return bool(self.has_unnamed_host or self.named_hosts)
diff --git a/util/reggen/clocking.py b/util/reggen/clocking.py
index 41108fd..b2330c4 100644
--- a/util/reggen/clocking.py
+++ b/util/reggen/clocking.py
@@ -7,6 +7,7 @@
 from typing import Dict, List, Optional
 
 from .lib import check_keys, check_list, check_bool, check_optional_name
+import re
 
 
 class ClockingItem:
@@ -14,12 +15,14 @@
                  clock: Optional[str],
                  reset: Optional[str],
                  idle: Optional[str],
-                 primary: bool):
+                 primary: bool,
+                 clock_base_name: Optional[str]):
         if primary:
             assert clock is not None
             assert reset is not None
 
         self.clock = clock
+        self.clock_base_name = clock_base_name
         self.reset = reset
         self.primary = primary
         self.idle = idle
@@ -35,6 +38,15 @@
         primary = check_bool(rd.get('primary', only_item),
                              'primary field of ' + what)
 
+        match = re.match(r'^clk_([A-Za-z0-9_]+)_i', str(clock))
+        if not clock or clock in ['clk_i', 'scan_clk_i']:
+            clock_base_name = ""
+        elif match:
+            clock_base_name = match.group(1)
+        else:
+            raise ValueError(f'clock name must be of the form clk_*_i or clk_i. '
+                             f'{clock} is illegal.')
+
         if primary:
             if clock is None:
                 raise ValueError('No clock signal for primary '
@@ -43,7 +55,7 @@
                 raise ValueError('No reset signal for primary '
                                  f'clocking item at {what}.')
 
-        return ClockingItem(clock, reset, idle, primary)
+        return ClockingItem(clock, reset, idle, primary, clock_base_name)
 
     def _asdict(self) -> Dict[str, object]:
         ret = {}  # type: Dict[str, object]
@@ -100,3 +112,15 @@
 
     def reset_signals(self) -> List[str]:
         return [item.reset for item in self.items if item.reset is not None]
+
+    def get_by_clock(self, name: Optional[str]) -> ClockingItem:
+        ret = None
+        for item in self.items:
+            if name == item.clock:
+                 ret = item
+                 break
+
+        if ret is None:
+            raise ValueError(f'The requested clock {name} does not exist.')
+        else:
+            return ret
diff --git a/util/reggen/ip_block.py b/util/reggen/ip_block.py
index 06d473c..9a59d3c 100644
--- a/util/reggen/ip_block.py
+++ b/util/reggen/ip_block.py
@@ -202,8 +202,6 @@
 
         scan = check_bool(rd.get('scan', False), 'scan field of ' + what)
 
-        reg_blocks = RegBlock.build_blocks(init_block, rd['registers'])
-
         r_inter_signals = check_list(rd.get('inter_signal_list', []),
                                      'inter_signal_list field')
         inter_signals = [
@@ -224,6 +222,10 @@
         clocking = Clocking.from_raw(rd['clocking'],
                                      'clocking field of ' + what)
 
+        reg_blocks = RegBlock.build_blocks(init_block, rd['registers'],
+                                           bus_interfaces,
+                                           clocking)
+
         xputs = (
             Signal.from_raw_list('available_inout_list for block ' + name,
                                  rd.get('available_inout_list', [])),
diff --git a/util/reggen/multi_register.py b/util/reggen/multi_register.py
index 1963bd4..004bd26 100644
--- a/util/reggen/multi_register.py
+++ b/util/reggen/multi_register.py
@@ -5,6 +5,7 @@
 from typing import Dict, List
 
 from reggen import register
+from .clocking import Clocking
 from .field import Field
 from .lib import check_keys, check_str, check_name, check_bool
 from .params import ReggenParams
@@ -38,7 +39,13 @@
     'compact': [
         'pb', "If true, allow multireg compacting."
         "If false, do not compact."
-    ]
+    ],
+    'cdc': [
+        's',
+        "indicates the register must cross to a different "
+        "clock domain before use.  The value shown here "
+        "should correspond to one of the module's clocks."
+    ],
 })
 
 
@@ -48,7 +55,8 @@
                  addrsep: int,
                  reg_width: int,
                  params: ReggenParams,
-                 raw: object):
+                 raw: object,
+                 clocks: Clocking):
         super().__init__(offset)
 
         rd = check_keys(raw, 'multireg',
@@ -64,7 +72,12 @@
         reg_rd = {key: value
                   for key, value in rd.items()
                   if key in reg_allowed_keys}
-        self.reg = Register.from_raw(reg_width, offset, params, reg_rd)
+        self.reg = Register.from_raw(reg_width, offset, params, reg_rd, clocks)
+
+        # The entire multi-reg block is always on the same clock
+        # This is guaranteed by design
+        self.async_name = self.reg.async_name
+        self.async_clk = self.reg.async_clk
 
         self.cname = check_name(rd['cname'],
                                 'cname field of multireg {}'
diff --git a/util/reggen/reg_block.py b/util/reggen/reg_block.py
index fa9d3c4..b75415d 100644
--- a/util/reggen/reg_block.py
+++ b/util/reggen/reg_block.py
@@ -9,6 +9,8 @@
 
 from .alert import Alert
 from .access import SWAccess, HWAccess
+from .bus_interfaces import BusInterfaces
+from .clocking import Clocking, ClockingItem
 from .field import Field
 from .signal import Signal
 from .lib import check_int, check_list, check_str_dict, check_str
@@ -25,6 +27,8 @@
         self._reg_width = reg_width
         self._params = params
 
+        self.name = ""  # type: str
+        self.clocks = {}  # type: Dict[str, ClockingItem]
         self.offset = 0
         self.multiregs = []  # type: List[MultiRegister]
         self.registers = []  # type: List[Register]
@@ -57,9 +61,14 @@
         # A list of all write enable names
         self.wennames = []  # type: List[str]
 
+        # Boolean indication that the block is fully asynchronous
+        self.async_if = False
+
     @staticmethod
     def build_blocks(block: 'RegBlock',
-                     raw: object) -> Dict[Optional[str], 'RegBlock']:
+                     raw: object,
+                     bus: BusInterfaces,
+                     clocks: Clocking) -> Dict[Optional[str], 'RegBlock']:
         '''Build a dictionary of blocks for a 'registers' field in the hjson
 
         There are two different syntaxes we might see here. The simple syntax
@@ -76,7 +85,10 @@
         '''
         if isinstance(raw, list):
             # This is the simple syntax
-            block.add_raw_registers(raw, 'registers field at top-level')
+            block.add_raw_registers(raw,
+                                    'registers field at top-level',
+                                    clocks,
+                                    bus.device_async.get(None))
             return {None: block}
 
         # This is the more complicated syntax
@@ -101,22 +113,38 @@
             block.add_raw_registers(rb_val,
                                     'item {} of the registers '
                                     'dictionary at top-level'
-                                    .format(idx + 1))
+                                    .format(idx + 1),
+                                    clocks,
+                                    bus.device_async.get(r_key))
             block.validate()
 
             assert rb_key not in ret
+            block.name = rb_key
             ret[rb_key] = block
 
         return ret
 
-    def add_raw_registers(self, raw: object, what: str) -> None:
+    def add_raw_registers(self,
+                          raw: object,
+                          what: str,
+                          clocks: Clocking,
+                          async_if: Optional[str]) -> None:
+
+        # the interface is fully asynchronous
+        if async_if:
+            self.async_if = True
+            self.clocks[async_if] = clocks.get_by_clock(async_if)
+
         rl = check_list(raw, 'registers field at top-level')
         for entry_idx, entry_raw in enumerate(rl):
             where = ('entry {} of the top-level registers field'
                      .format(entry_idx + 1))
-            self.add_raw(where, entry_raw)
+            self.add_raw(where, entry_raw, clocks)
 
-    def add_raw(self, where: str, raw: object) -> None:
+    def add_raw(self,
+                where: str,
+                raw: object,
+                clocks: Clocking) -> None:
         entry = check_str_dict(raw, where)
 
         handlers = {
@@ -151,14 +179,49 @@
         entry_where = ('At offset {:#x}, {}, type {!r}'
                        .format(self.offset, where, entry_type))
 
-        handlers[entry_type](entry_where, entry_body)
+        handlers[entry_type](entry_where, entry_body, clocks)
 
-    def _handle_register(self, where: str, body: object) -> None:
+    def _validate_async(self, name: Optional[str], clk: object) -> None:
+        '''Check for async definition consistency
+
+        If a reg block is marked fully asynchronous through its bus interface,
+        its register definition cannot also mark individual registers with
+        asynchronous designations.
+
+        The two asynchronous regfile schemes are mutually exclusive.
+        '''
+
+        if self.name:
+            block_name = self.name
+        else:
+            block_name = "Default"
+
+        if self.async_if and name:
+            raise ValueError(f'''
+            {block_name} register block has incompatible async definitions.
+            The corresponding device interface is marked fully async, however
+            there are individual registers that also contain the async_clk
+            designation, this is not allowed.
+
+            Either remove all register async_clk designations, or remove
+            async designation of the bus interface.
+            ''')
+
+        # If there is an asynchronous clock defined, then the clock must be a
+        # valid clocking item
+        if name:
+            assert isinstance(clk, ClockingItem)
+            self.clocks[name] = clk
+
+    def _handle_register(self, where: str, body: object, clocks: Clocking) -> None:
         reg = Register.from_raw(self._reg_width,
-                                self.offset, self._params, body)
+                                self.offset, self._params, body, clocks)
+
+        self._validate_async(reg.async_name, reg.async_clk)
+
         self.add_register(reg)
 
-    def _handle_reserved(self, where: str, body: object) -> None:
+    def _handle_reserved(self, where: str, body: object, clocks: Optional[Clocking]) -> None:
         nreserved = check_int(body, 'body of ' + where)
         if nreserved <= 0:
             raise ValueError('Reserved count in {} is {}, '
@@ -167,7 +230,7 @@
 
         self.offset += self._addrsep * nreserved
 
-    def _handle_skipto(self, where: str, body: object) -> None:
+    def _handle_skipto(self, where: str, body: object, clocks: Optional[Clocking]) -> None:
         skipto = check_int(body, 'body of ' + where)
         if skipto < self.offset:
             raise ValueError('Destination of skipto in {} is {:#x}, '
@@ -179,7 +242,7 @@
                              .format(where, skipto, self._addrsep))
         self.offset = skipto
 
-    def _handle_window(self, where: str, body: object) -> None:
+    def _handle_window(self, where: str, body: object, clocks: Optional[Clocking]) -> None:
         window = Window.from_raw(self.offset,
                                  self._reg_width, self._params, body)
         if window.name is not None:
@@ -191,9 +254,14 @@
                                          self.name_to_offset[lname]))
         self.add_window(window)
 
-    def _handle_multireg(self, where: str, body: object) -> None:
+    def _handle_multireg(self, where: str, body: object, clocks: Clocking) -> None:
         mr = MultiRegister(self.offset,
-                           self._addrsep, self._reg_width, self._params, body)
+                           self._addrsep, self._reg_width, self._params, body,
+                           clocks)
+
+        # validate async schemes
+        self._validate_async(mr.async_name, mr.async_clk)
+
         for reg in mr.regs:
             lname = reg.name.lower()
             if lname in self.name_to_offset:
@@ -344,6 +412,8 @@
         reg = Register(self.offset,
                        reg_name,
                        reg_desc,
+                       async_name="",
+                       async_clk=None,
                        hwext=is_testreg,
                        hwqe=is_testreg,
                        hwre=False,
diff --git a/util/reggen/reg_top.sv.tpl b/util/reggen/reg_top.sv.tpl
index aa29048..b9d9d34 100644
--- a/util/reggen/reg_top.sv.tpl
+++ b/util/reggen/reg_top.sv.tpl
@@ -9,6 +9,7 @@
   from reggen.lib import get_basename
   from reggen.register import Register
   from reggen.multi_register import MultiRegister
+  from reggen.bits import Bits
 
   num_wins = len(rb.windows)
   num_wins_width = ((num_wins+1).bit_length()) - 1
@@ -42,12 +43,28 @@
   common_data_intg_gen = 0 if rb.has_data_intg_passthru else 1
   adapt_data_intg_gen = 1 if rb.has_data_intg_passthru else 0
   assert common_data_intg_gen != adapt_data_intg_gen
+
+  # declare a fully asynchronous interface
+  reg_clk_expr = "clk_i"
+  reg_rst_expr = "rst_ni"
+  tl_h2d_expr = "tl_i"
+  tl_d2h_expr = "tl_o"
+  if rb.async_if:
+    tl_h2d_expr = "tl_async_h2d"
+    tl_d2h_expr = "tl_async_d2h"
+    for clock in rb.clocks.values():
+      reg_clk_expr = clock.clock
+      reg_rst_expr = clock.reset
 %>
 `include "prim_assert.sv"
 
 module ${mod_name} (
   input clk_i,
   input rst_ni,
+% for clock in rb.clocks.values():
+  input ${clock.clock},
+  input ${clock.reset},
+% endfor
 
   input  tlul_pkg::tl_h2d_t tl_i,
   output tlul_pkg::tl_d2h_t tl_o,
@@ -94,21 +111,40 @@
   logic          addrmiss, wr_err;
 
   logic [DW-1:0] reg_rdata_next;
+  logic reg_busy;
 
   tlul_pkg::tl_h2d_t tl_reg_h2d;
   tlul_pkg::tl_d2h_t tl_reg_d2h;
 % endif
 
+  % if rb.async_if:
+  tlul_pkg::tl_h2d_t tl_async_h2d;
+  tlul_pkg::tl_d2h_t tl_async_d2h;
+  tlul_fifo_async #(
+    .ReqDepth(2),
+    .RspDepth(2)
+  ) u_if_sync (
+    .clk_h_i(clk_i),
+    .rst_h_ni(rst_ni),
+    .clk_d_i(${reg_clk_expr}),
+    .rst_d_ni(${reg_rst_expr}),
+    .tl_h_i(tl_i),
+    .tl_h_o(tl_o),
+    .tl_d_o(${tl_h2d_expr}),
+    .tl_d_i(${tl_d2h_expr})
+  );
+  % endif
+
   // incoming payload check
   logic intg_err;
   tlul_cmd_intg_chk u_chk (
-    .tl_i,
+    .tl_i(${tl_h2d_expr}),
     .err_o(intg_err)
   );
 
   logic intg_err_q;
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
+  always_ff @(posedge ${reg_clk_expr} or negedge ${reg_rst_expr}) begin
+    if (!${reg_rst_expr}) begin
       intg_err_q <= '0;
     end else if (intg_err) begin
       intg_err_q <= 1'b1;
@@ -126,17 +162,17 @@
     .EnableDataIntgGen(${common_data_intg_gen})
   ) u_rsp_intg_gen (
     .tl_i(tl_o_pre),
-    .tl_o
+    .tl_o(${tl_d2h_expr})
   );
 
 % if num_dsp == 1:
   ## Either no windows (and just registers) or no registers and only
   ## one window.
   % if num_wins == 0:
-  assign tl_reg_h2d = tl_i;
+  assign tl_reg_h2d = ${tl_h2d_expr};
   assign tl_o_pre   = tl_reg_d2h;
   % else:
-  assign tl_win_o = tl_i;
+  assign tl_win_o = ${tl_h2d_expr};
   assign tl_o_pre = tl_win_i;
   % endif
 % else:
@@ -183,9 +219,9 @@
     .DReqDepth  ({${num_dsp}{4'h0}}),
     .DRspDepth  ({${num_dsp}{4'h0}})
   ) u_socket (
-    .clk_i,
-    .rst_ni,
-    .tl_h_i (tl_i),
+    .clk_i  (${reg_clk_expr}),
+    .rst_ni (${reg_rst_expr}),
+    .tl_h_i (${tl_h2d_expr}),
     .tl_h_o (tl_o_pre),
     .tl_d_o (tl_socket_h2d),
     .tl_d_i (tl_socket_d2h),
@@ -202,12 +238,12 @@
       base_addr = w.offset
       limit_addr = w.offset + w.size_in_bytes
 
-      hi_check = 'tl_i.a_address[AW-1:0] < {}'.format(limit_addr)
+      hi_check = f'{tl_h2d_expr}.a_address[AW-1:0] < {limit_addr}'
       addr_checks = []
       if base_addr > 0:
-        addr_checks.append('tl_i.a_address[AW-1:0] >= {}'.format(base_addr))
+        addr_checks.append(f'{tl_h2d_expr}.a_address[AW-1:0] >= {base_addr}')
       if limit_addr < 2**addr_width:
-        addr_checks.append('tl_i.a_address[AW-1:0] < {}'.format(limit_addr))
+        addr_checks.append(f'{tl_h2d_expr}.a_address[AW-1:0] < {limit_addr}')
 
       addr_test = ' && '.join(addr_checks)
 %>\
@@ -231,8 +267,8 @@
     .RegDw(DW),
     .EnableDataIntgGen(${adapt_data_intg_gen})
   ) u_reg_if (
-    .clk_i,
-    .rst_ni,
+    .clk_i  (${reg_clk_expr}),
+    .rst_ni (${reg_rst_expr}),
 
     .tl_i (tl_reg_h2d),
     .tl_o (tl_reg_d2h),
@@ -242,10 +278,32 @@
     .addr_o  (reg_addr),
     .wdata_o (reg_wdata),
     .be_o    (reg_be),
+    .busy_i  (reg_busy),
     .rdata_i (reg_rdata),
     .error_i (reg_error)
   );
 
+% if not rb.async_if:
+  // cdc oversampling signals
+  % for clock in rb.clocks.values():
+  <%
+    clk_name = clock.clock_base_name
+    tgl_expr = clk_name + "_tgl"
+    cname = clock.clock
+    rname = clock.reset
+  %>\
+  logic sync_${clk_name}_update;
+  prim_pulse_sync u_${tgl_expr} (
+    .clk_src_i(${cname}),
+    .rst_src_ni(${rname}),
+    .src_pulse_i(1'b1),
+    .clk_dst_i(${reg_clk_expr}),
+    .rst_dst_ni(${reg_rst_expr}),
+    .dst_pulse_o(sync_${clk_name}_update)
+  );
+  % endfor
+% endif
+
   % if block.expose_reg_if:
   assign reg2hw.reg_if.reg_we    = reg_we;
   assign reg2hw.reg_if.reg_re    = reg_re;
@@ -267,7 +325,7 @@
         fld_suff = '_' + f.name.lower() if len(r.fields) > 1 else ''
         sig_name = r.name.lower() + fld_suff
 %>\
-${field_sig_decl(f, sig_name, r.hwext, r.shadowed)}\
+${field_sig_decl(f, sig_name, r.hwext, r.shadowed, r.async_clk)}\
     % endfor
   % endfor
 
@@ -401,6 +459,35 @@
       end
     endcase
   end
+
+  // register busy
+  % if rb.async_if:
+  assign reg_busy = '0;
+  % else:
+  always_comb begin
+    reg_busy = '0;
+    unique case (1'b1)
+      % for i, r in enumerate(regs_flat):
+        % if r.async_clk and len(r.fields) == 1:
+      addr_hit[${i}]: begin
+        reg_busy = ${r.name.lower() + "_busy"};
+      end
+        % elif r.async_clk:
+      addr_hit[${i}]: begin
+        reg_busy =
+          % for f in r.fields:
+          ${r.name.lower() + "_" + f.name.lower() + "_busy"}${";" if loop.last else " |"}
+          % endfor
+      end
+        % endif
+      % endfor
+      default: begin
+        reg_busy  = '0;
+      end
+    endcase
+  end
+  % endif
+
 % endif
 
   // Unused signal tieoff
@@ -420,12 +507,12 @@
 % if rb.all_regs:
 
   // Assertions for Register Interface
-  `ASSERT_PULSE(wePulse, reg_we)
-  `ASSERT_PULSE(rePulse, reg_re)
+  `ASSERT_PULSE(wePulse, reg_we, ${reg_clk_expr}, !${reg_rst_expr})
+  `ASSERT_PULSE(rePulse, reg_re, ${reg_clk_expr}, !${reg_rst_expr})
 
-  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, ${reg_clk_expr}, !${reg_rst_expr})
 
-  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), ${reg_clk_expr}, !${reg_rst_expr})
 
   // this is formulated as an assumption such that the FPV testbenches do disprove this
   // property by mistake
@@ -453,13 +540,16 @@
   logic ${reg.name.lower()}_we;
   % endif
 </%def>\
-<%def name="field_sig_decl(field, sig_name, hwext, shadowed)">\
+<%def name="field_sig_decl(field, sig_name, hwext, shadowed, async_clk)">\
   % if field.swaccess.allows_read():
   logic ${str_arr_sv(field.bits)}${sig_name}_qs;
   % endif
   % if field.swaccess.allows_write():
   logic ${str_arr_sv(field.bits)}${sig_name}_wd;
   % endif
+  % if async_clk:
+  logic ${str_arr_sv(Bits(0,0))}${sig_name}_busy;
+  % endif
 </%def>\
 <%def name="finst_gen(reg, field, finst_name, fsig_name)">\
 <%
@@ -498,10 +588,27 @@
 
     qs_expr = f'{finst_name}_qs' if field.swaccess.allows_read() else ''
 %>\
+<%
+    clk_expr = reg.async_clk.clock if reg.async_clk else reg_clk_expr
+    rst_expr = reg.async_clk.reset if reg.async_clk else reg_rst_expr
+    if reg.async_clk:
+      update_expr = "sync_" + reg.async_clk.clock.strip("_iclk_")+ "_update"
+%>\
   % if reg.hwext:       ## if hwext, instantiate prim_subreg_ext
-  prim_subreg_ext #(
+<%
+    subreg_block = "prim_subreg_ext_async" if reg.async_clk else "prim_subreg_ext"
+%>\
+  ${subreg_block} #(
     .DW    (${field.bits.width()})
   ) u_${finst_name} (
+    % if reg.async_clk:
+    .clk_src_i    (${reg_clk_expr}),
+    .rst_src_ni   (${reg_rst_expr}),
+    .clk_dst_i    (${clk_expr}),
+    .rst_dst_ni   (${rst_expr}),
+    .src_update_i (${update_expr}),
+    .src_busy_o   (${finst_name}_busy),
+    % endif
     .re     (${re_expr}),
     .we     (${we_expr}),
     .wd     (${wd_expr}),
@@ -527,14 +634,34 @@
     % if is_const_reg:
   // constant-only read
   assign ${finst_name}_qs = ${resval_expr};
+    % elif reg.async_clk:
+  prim_subreg_async #(
+    .DW      (${field.bits.width()}),
+    .SwAccess(prim_subreg_pkg::SwAccess${field.swaccess.value[1].name.upper()}),
+    .RESVAL  (${resval_expr})
+  ) u_${finst_name} (
+    .clk_src_i    (${reg_clk_expr}),
+    .rst_src_ni   (${reg_rst_expr}),
+    .clk_dst_i    (${clk_expr}),
+    .rst_dst_ni   (${rst_expr}),
+    .src_update_i (${update_expr}),
+    .src_we_i     (${we_expr}),
+    .src_wd_i     (${wd_expr}),
+    .dst_de_i     (${de_expr}),
+    .dst_d_i      (${d_expr}),
+    .src_busy_o   (${finst_name}_busy),
+    .src_qs_o     (${qs_expr}),
+    .dst_qe_o     (${qe_expr}),
+    .q            (${q_expr})
+  );
     % else:
   ${subreg_block} #(
     .DW      (${field.bits.width()}),
     .SwAccess(prim_subreg_pkg::SwAccess${field.swaccess.value[1].name.upper()}),
     .RESVAL  (${resval_expr})
   ) u_${finst_name} (
-    .clk_i   (clk_i),
-    .rst_ni  (rst_ni),
+    .clk_i   (${reg_clk_expr}),
+    .rst_ni  (${reg_rst_expr}),
 
     // from register interface
       % if reg.shadowed:
@@ -594,3 +721,25 @@
         reg_rdata_next[${str_bits_sv(field.bits)}] = '0;
 % endif
 </%def>\
+<%def name="reg_enable_gen(reg, idx)">\
+  % if reg.needs_re():
+  assign ${reg.name.lower()}_re = addr_hit[${idx}] & reg_re & !reg_error;
+  % endif
+  % if reg.needs_we():
+  assign ${reg.name.lower()}_we = addr_hit[${idx}] & reg_we & !reg_error;
+  % endif
+</%def>\
+<%def name="reg_cdc_gen(field, sig_name, hwext, shadowed, idx)">\
+<%
+    needs_wd = field.swaccess.allows_write()
+    space = '\n' if needs_wd or needs_re else ''
+%>\
+${space}\
+% if needs_wd:
+  % if field.swaccess.swrd() == SwRdAccess.RC:
+  assign ${sig_name}_wd = '1;
+  % else:
+  assign ${sig_name}_wd = reg_wdata[${str_bits_sv(field.bits)}];
+  % endif
+% endif
+</%def>\
diff --git a/util/reggen/register.py b/util/reggen/register.py
index 86cd005..537ac8c 100644
--- a/util/reggen/register.py
+++ b/util/reggen/register.py
@@ -5,6 +5,7 @@
 from typing import Dict, List, Optional
 
 from .access import SWAccess, HWAccess
+from .clocking import Clocking
 from .field import Field
 from .lib import (check_keys, check_str, check_name, check_bool,
                   check_list, check_str_list, check_int)
@@ -20,6 +21,12 @@
 }
 
 OPTIONAL_FIELDS = {
+    'async': [
+        's',
+        "indicates the register must cross to a different "
+        "clock domain before use.  The value shown here "
+        "should correspond to one of the module's clocks."
+    ],
     'swaccess': [
         's',
         "software access permission to use for "
@@ -82,6 +89,8 @@
                  offset: int,
                  name: str,
                  desc: str,
+                 async_name: str,
+                 async_clk: object,
                  hwext: bool,
                  hwqe: bool,
                  hwre: bool,
@@ -95,6 +104,8 @@
         super().__init__(offset)
         self.name = name
         self.desc = desc
+        self.async_name = async_name
+        self.async_clk = async_clk
         self.hwext = hwext
         self.hwqe = hwqe
         self.hwre = hwre
@@ -182,7 +193,8 @@
     def from_raw(reg_width: int,
                  offset: int,
                  params: ReggenParams,
-                 raw: object) -> 'Register':
+                 raw: object,
+                 clocks: Clocking) -> 'Register':
         rd = check_keys(raw, 'register',
                         list(REQUIRED_FIELDS.keys()),
                         list(OPTIONAL_FIELDS.keys()))
@@ -190,6 +202,20 @@
         name = check_name(rd['name'], 'name of register')
         desc = check_str(rd['desc'], 'desc for {} register'.format(name))
 
+        async_name = check_str(rd.get('async', ''), 'async clock for {} register'.format(name))
+        async_clk = None
+
+        if async_name:
+            valid_clocks = clocks.clock_signals()
+            if async_name not in valid_clocks:
+                raise ValueError('async clock {} defined for {} does not exist '
+                                 'in valid module clocks {}.'
+                                 .format(async_name,
+                                         name,
+                                         valid_clocks))
+            else:
+                async_clk = clocks.get_by_clock(async_name)
+
         swaccess = SWAccess('{} register'.format(name),
                             rd.get('swaccess', 'none'))
         hwaccess = HWAccess('{} register'.format(name),
@@ -260,7 +286,7 @@
                                            'storage_err_alert for {} register'
                                            .format(name))
 
-        return Register(offset, name, desc,
+        return Register(offset, name, desc, async_name, async_clk,
                         hwext, hwqe, hwre, regwen,
                         tags, resval, shadowed, fields,
                         update_err_alert, storage_err_alert)
@@ -380,7 +406,7 @@
         # we've replicated fields).
         new_resval = None
 
-        return Register(offset, new_name, self.desc,
+        return Register(offset, new_name, self.desc, self.async_name, self.async_clk,
                         self.hwext, self.hwqe, self.hwre, new_regwen,
                         self.tags, new_resval, self.shadowed, new_fields,
                         self.update_err_alert, self.storage_err_alert)