[top-level/pwrmgr] Extend chip_sw_pwrmgr_main_power_glitch_reset

Add three groups of assertions to check that:
- the clock valids are deasserted if a power glitch is detected.
- clocks are stopped if their valid is deasserted.
- clocks are running if their valid is asserted.
Enable pwrmgr_ast_sva_if.sv assertions in _vseq file.
Add main_, io_, usb_ clock inputs to pwrmgr_ast_sva_if and
create a binding in tb.sv for that.

Signed-off-by: Abdullah Varici <abdullah.varici@lowrisc.org>
diff --git a/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson b/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson
index a3168a2..50f3d42 100644
--- a/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson
+++ b/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson
@@ -46,7 +46,7 @@
   vcs_cov_excl_files: ["{proj_root}/hw/ip/pwrmgr/dv/cov/pwrmgr_cov_excl.el"]
   // Add additional tops for simulation.
   sim_tops: ["pwrmgr_bind",
-             "pwrmgr_rstmgr_bind",
+             "pwrmgr_unit_bind",
              "pwrmgr_cov_bind",
              "sec_cm_prim_count_bind",
              "sec_cm_prim_sparse_fsm_flop_bind",
diff --git a/hw/ip/pwrmgr/dv/sva/pwrmgr_ast_sva_if.sv b/hw/ip/pwrmgr/dv/sva/pwrmgr_ast_sva_if.sv
index 5834451..281660a 100644
--- a/hw/ip/pwrmgr/dv/sva/pwrmgr_ast_sva_if.sv
+++ b/hw/ip/pwrmgr/dv/sva/pwrmgr_ast_sva_if.sv
@@ -5,9 +5,14 @@
 // This has some assertions that check the inputs from ast react according to
 // the pwrmgr outputs. The ast inputs are generated by the base sequences, but
 // these assertions will also be useful at full chip level.
-interface pwrmgr_ast_sva_if (
+interface pwrmgr_ast_sva_if #(
+  parameter bit CheckClocks = 1'b0
+) (
   input logic clk_slow_i,
   input logic rst_slow_ni,
+  input logic clk_main_i,
+  input logic clk_io_i,
+  input logic clk_usb_i,
   // The pwrmgr outputs.
   input pwrmgr_pkg::pwr_ast_req_t pwr_ast_o,
   // The pwrmgr inputs.
@@ -50,6 +55,43 @@
   `ASSERT(UsbClkHandshakeOff_A, !pwr_ast_o.usb_clk_en |-> `CLK_WAIT_BOUNDS !pwr_ast_i.usb_clk_val,
           clk_slow_i, reset_or_disable)
 
+  if (CheckClocks) begin : gen_check_clock
+    int main_clk_cycles, io_clk_cycles, usb_clk_cycles;
+    always_ff @(posedge clk_main_i) main_clk_cycles++;
+    always_ff @(posedge clk_io_i) io_clk_cycles++;
+    always_ff @(posedge clk_usb_i) usb_clk_cycles++;
+
+    `ASSERT(MainClkStopped_A,
+            $fell(
+                pwr_ast_i.core_clk_val
+            ) |=> ($stable(
+                main_clk_cycles
+            ) throughout (!pwr_ast_i.core_clk_val) [* 1: $]),
+            clk_slow_i, reset_or_disable)
+    `ASSERT(MainClkRun_A, $rose(pwr_ast_i.core_clk_val) |=> !($stable(main_clk_cycles)),
+            clk_slow_i, reset_or_disable)
+
+    `ASSERT(IOClkStopped_A,
+            $fell(
+                pwr_ast_i.io_clk_val
+            ) |=> ($stable(
+                io_clk_cycles
+            ) throughout (!pwr_ast_i.io_clk_val) [* 1: $]),
+            clk_slow_i, reset_or_disable)
+    `ASSERT(IOClkRun_A, $rose(pwr_ast_i.io_clk_val) |=> !($stable(io_clk_cycles)), clk_slow_i,
+            reset_or_disable)
+
+    `ASSERT(USBClkStopped_A,
+            $fell(
+                pwr_ast_i.usb_clk_val
+            ) |=> ($stable(
+                usb_clk_cycles
+            ) throughout (!pwr_ast_i.usb_clk_val) [* 1: $]),
+            clk_slow_i, reset_or_disable)
+    `ASSERT(USBClkRun_A, $rose(pwr_ast_i.usb_clk_val) |=> !($stable(usb_clk_cycles)), clk_slow_i,
+            reset_or_disable)
+  end
+
   // Main pd-pok
   `ASSERT(MainPdHandshakeOn_A, pwr_ast_o.main_pd_n |-> `PDN_WAIT_BOUNDS pwr_ast_i.main_pok,
           clk_slow_i, reset_or_disable)
diff --git a/hw/ip/pwrmgr/dv/sva/pwrmgr_bind.sv b/hw/ip/pwrmgr/dv/sva/pwrmgr_bind.sv
index 2c6bcf0..39e5bc5 100644
--- a/hw/ip/pwrmgr/dv/sva/pwrmgr_bind.sv
+++ b/hw/ip/pwrmgr/dv/sva/pwrmgr_bind.sv
@@ -34,15 +34,6 @@
     .usb_clk_en(pwr_ast_o.usb_clk_en)
   );
 
-  bind pwrmgr pwrmgr_ast_sva_if pwrmgr_ast_sva_if (
-    .clk_slow_i,
-    .rst_slow_ni,
-    // The pwrmgr outputs.
-    .pwr_ast_o,
-    // The pwrmgr input.
-    .pwr_ast_i
-  );
-
   bind pwrmgr clkmgr_pwrmgr_sva_if clkmgr_pwrmgr_sva_if (
     .clk_i,
     .rst_ni,
diff --git a/hw/ip/pwrmgr/dv/sva/pwrmgr_sva.core b/hw/ip/pwrmgr/dv/sva/pwrmgr_sva.core
index e01c431..0d83c52 100644
--- a/hw/ip/pwrmgr/dv/sva/pwrmgr_sva.core
+++ b/hw/ip/pwrmgr/dv/sva/pwrmgr_sva.core
@@ -14,7 +14,7 @@
       - lowrisc:dv:pwrmgr_rstmgr_sva_if
     files:
       - pwrmgr_bind.sv
-      - pwrmgr_rstmgr_bind.sv
+      - pwrmgr_unit_bind.sv
       - pwrmgr_ast_sva_if.sv
       - pwrmgr_clock_enables_sva_if.sv
       - pwrmgr_sec_cm_checker_assert.sv
diff --git a/hw/ip/pwrmgr/dv/sva/pwrmgr_rstmgr_bind.sv b/hw/ip/pwrmgr/dv/sva/pwrmgr_unit_bind.sv
similarity index 78%
rename from hw/ip/pwrmgr/dv/sva/pwrmgr_rstmgr_bind.sv
rename to hw/ip/pwrmgr/dv/sva/pwrmgr_unit_bind.sv
index 05b6d6c..b569bc4 100644
--- a/hw/ip/pwrmgr/dv/sva/pwrmgr_rstmgr_bind.sv
+++ b/hw/ip/pwrmgr/dv/sva/pwrmgr_unit_bind.sv
@@ -5,7 +5,7 @@
 // This is split off from pwrmgr_bind so that we can instantiate that in chip top, but
 // specialize the bind of pwrmgr_rstmgr_sva_if for top_earlgrey, which is needed in order
 // to hook up ndm_sys_req because pwrmgr doesn't see it.
-module pwrmgr_rstmgr_bind;
+module pwrmgr_unit_bind;
 
   bind pwrmgr pwrmgr_rstmgr_sva_if pwrmgr_rstmgr_sva_if (
     .clk_i,
@@ -31,4 +31,16 @@
     .rst_sys_src_n(pwr_rst_i.rst_sys_src_n)
   );
 
+  bind pwrmgr pwrmgr_ast_sva_if #(
+    .CheckClocks(1'b0)
+  ) pwrmgr_ast_sva_if (
+    .clk_slow_i,
+    .rst_slow_ni,
+    // Leave clk_*_i inputs unconnected as they are not used by assertions in unit tests.
+    // The pwrmgr outputs.
+    .pwr_ast_o,
+    // The pwrmgr input.
+    .pwr_ast_i
+  );
+
 endmodule
diff --git a/hw/ip/pwrmgr/rtl/pwrmgr.sv b/hw/ip/pwrmgr/rtl/pwrmgr.sv
index c5b40ea..b773ca8 100644
--- a/hw/ip/pwrmgr/rtl/pwrmgr.sv
+++ b/hw/ip/pwrmgr/rtl/pwrmgr.sv
@@ -287,6 +287,15 @@
   assign hw2reg.fault_status.main_pd_glitch.de  = peri_reqs_masked.rstreqs[ResetMainPwrIdx];
   assign hw2reg.fault_status.main_pd_glitch.d   = 1'b1;
 
+  // Check that the clock enables are deasserted in the next slow clock cycle if a power glitch is
+  // detected.
+  `ASSERT(PwrmgrMainPowerGlitchMainClkVld, $rose(hw2reg.fault_status.main_pd_glitch.de)
+                                           |=> !pwr_clk_o.main_ip_clk_en, clk_slow_i, !rst_slow_ni)
+  `ASSERT(PwrmgrMainPowerGlitchIOClkVld, $rose(hw2reg.fault_status.main_pd_glitch.de)
+                                         |=> !pwr_clk_o.io_ip_clk_en, clk_slow_i, !rst_slow_ni)
+  `ASSERT(PwrmgrMainPowerGlitchUSBClkVld, $rose(hw2reg.fault_status.main_pd_glitch.de)
+                                          |=> !pwr_clk_o.usb_ip_clk_en, clk_slow_i, !rst_slow_ni)
+
 
   ////////////////////////////
   ///  alerts
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_main_power_glitch_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_main_power_glitch_vseq.sv
index c91937d..a1ec782 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_main_power_glitch_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_main_power_glitch_vseq.sv
@@ -14,7 +14,6 @@
   virtual task pre_start();
     super.pre_start();
     // disable expected assertion error for power glitch test
-    $assertoff(0,"pwrmgr_ast_sva_if");
     $assertoff(1,"tb.dut.top_earlgrey.pwrmgr_rstmgr_sva_if.MainPwrRstOff_A");
     $assertoff(1,"tb.dut.top_earlgrey.pwrmgr_rstmgr_sva_if.MainPwrRstOn_A");
   endtask
diff --git a/hw/top_earlgrey/dv/sva/top_earlgrey_bind.sv b/hw/top_earlgrey/dv/sva/top_earlgrey_bind.sv
index f5f7658..1604133 100644
--- a/hw/top_earlgrey/dv/sva/top_earlgrey_bind.sv
+++ b/hw/top_earlgrey/dv/sva/top_earlgrey_bind.sv
@@ -30,4 +30,18 @@
     .rst_sys_src_n(u_pwrmgr_aon.pwr_rst_i.rst_sys_src_n)
   );
 
+  bind pwrmgr pwrmgr_ast_sva_if #(
+    .CheckClocks(1'b1)
+  ) pwrmgr_ast_sva_if (
+    .clk_slow_i(u_pwrmgr_aon.clk_slow_i),
+    .rst_slow_ni(u_pwrmgr_aon.rst_slow_ni),
+    .clk_main_i(u_clkmgr_aon.clk_main_i),
+    .clk_io_i(u_clkmgr_aon.clk_io_i),
+    .clk_usb_i(u_clkmgr_aon.clk_usb_i),
+    // The pwrmgr outputs.
+    .pwr_ast_o,
+    // The pwrmgr input.
+    .pwr_ast_i
+  );
+
 endmodule