[dv] Update countermeasure verification

1. update prim_count_if to force on the actual storage
2. add cfg.sec_cm_alert_name for sec alert
3. split sec_cm_bind to multiple bind files as we can only bind the
   prim_*_if when the design uses the prim
4. update keymgr for above changes

Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/cip_lib/cip_base_env_cfg.sv b/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
index 469d24f..0c87be8 100644
--- a/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
@@ -13,6 +13,7 @@
 
   // Override this alert name at `initialize` if it's not as below
   string              tl_intg_alert_name = "fatal_fault";
+  string              sec_cm_alert_name  = "fatal_fault";
 
   // If there is a bit in an "alert cause" register that will be set by a corrupt bus access, this
   // should be the name of that field (with syntax "reg.field"). Used by cip_base_scoreboard to
diff --git a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__sec_cm_fi.svh b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__sec_cm_fi.svh
index 663758a..f18c02c 100644
--- a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__sec_cm_fi.svh
+++ b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq__sec_cm_fi.svh
@@ -25,12 +25,9 @@
 // - Verify any operations that follow fail (as applicable).
 // refer to ip/keymgr/dv/env/seq_lib/keymgr_common_vseq.sv as an example
 virtual task check_sec_cm_fi_resp(sec_cm_base_if_proxy if_proxy);
-  // TODO, it's better to unify these to one alert
-  string sec_cm_alert_name = cfg.tl_intg_alert_name;
-
-  `DV_CHECK_FATAL(sec_cm_alert_name inside {cfg.list_of_alerts},
+  `DV_CHECK_FATAL(cfg.sec_cm_alert_name inside {cfg.list_of_alerts},
                   $sformatf("sec_cm_alert_name (%s) is not inside %p",
-                            sec_cm_alert_name, cfg.list_of_alerts))
+                            cfg.sec_cm_alert_name, cfg.list_of_alerts))
 
   `uvm_info(`gfn, $sformatf("expected fatal alert is triggered for %s", if_proxy.sec_cm_type.name),
             UVM_LOW)
@@ -38,7 +35,7 @@
   // This is a fatal alert and design keeps sending it until reset is issued.
   // Check alerts are triggered for a few times
   repeat (5) begin
-    wait_alert_trigger(sec_cm_alert_name, .wait_complete(1));
+    wait_alert_trigger(cfg.sec_cm_alert_name, .wait_complete(1));
   end
 endtask : check_sec_cm_fi_resp
 
diff --git a/hw/dv/sv/sec_cm/prim_count_if.sv b/hw/dv/sv/sec_cm/prim_count_if.sv
index e540ed4..97c145e 100644
--- a/hw/dv/sv/sec_cm/prim_count_if.sv
+++ b/hw/dv/sv/sec_cm/prim_count_if.sv
@@ -18,7 +18,8 @@
   prim_count_pkg::prim_count_style_e cnt_style = CntStyle;
 
   string path = dv_utils_pkg::get_parent_hier($sformatf("%m"));
-  string signal_forced;
+  string signal_forced = $sformatf("%s.gen_cnts[0].u_cnt_flop.gen_generic.u_impl_generic.q_o",
+                                   path);
 
   class prim_count_if_proxy extends sec_cm_pkg::sec_cm_base_if_proxy;
     `uvm_object_new
@@ -46,13 +47,7 @@
   endclass
 
   prim_count_if_proxy if_proxy;
-
   initial begin
-    case (cnt_style)
-      prim_count_pkg::CrossCnt: signal_forced = $sformatf("%s.up_cnt_q", path);
-      prim_count_pkg::DupCnt: signal_forced = $sformatf("%s.up_cnt_q[0]", path);
-      default: `uvm_fatal(msg_id, $sformatf("unsupported style %s", cnt_style.name()))
-    endcase
     `DV_CHECK_FATAL(uvm_hdl_check_path(signal_forced), , msg_id)
 
     // Store the proxy object for TB to use
diff --git a/hw/dv/sv/sec_cm/sec_cm.core b/hw/dv/sv/sec_cm/sec_cm.core
index 299f023..52c86b6 100644
--- a/hw/dv/sv/sec_cm/sec_cm.core
+++ b/hw/dv/sv/sec_cm/sec_cm.core
@@ -17,7 +17,6 @@
       - sec_cm_base_if_proxy.sv: {is_include_file: true}
       - prim_count_if.sv
       - prim_sparse_fsm_flop_if.sv
-      - sec_cm_bind.sv
     file_type: systemVerilogSource
 
 targets:
diff --git a/hw/dv/sv/sec_cm/sec_cm_prim_count_bind.core b/hw/dv/sv/sec_cm/sec_cm_prim_count_bind.core
new file mode 100644
index 0000000..cceece0
--- /dev/null
+++ b/hw/dv/sv/sec_cm/sec_cm_prim_count_bind.core
@@ -0,0 +1,19 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:sec_cm_prim_count_bind"
+description: "Common bind file for testing prim_count countermeasures"
+
+filesets:
+  files_dv:
+    depend:
+      - lowrisc:prim:count
+    files:
+      - sec_cm_prim_count_bind.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_dv
diff --git a/hw/dv/sv/sec_cm/sec_cm_bind.sv b/hw/dv/sv/sec_cm/sec_cm_prim_count_bind.sv
similarity index 65%
copy from hw/dv/sv/sec_cm/sec_cm_bind.sv
copy to hw/dv/sv/sec_cm/sec_cm_prim_count_bind.sv
index b0d8820..8454cbd 100644
--- a/hw/dv/sv/sec_cm/sec_cm_bind.sv
+++ b/hw/dv/sv/sec_cm/sec_cm_prim_count_bind.sv
@@ -2,9 +2,6 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
-module sec_cm_bind();
+module sec_cm_prim_count_bind();
   bind prim_count prim_count_if #(.CntStyle(CntStyle), .Width(Width)) u_prim_count_if (.*);
-
-  bind prim_sparse_fsm_flop prim_sparse_fsm_flop_if #(
-         .Width(Width)) u_prim_sparse_fsm_flop_if (.*);
 endmodule
diff --git a/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.core b/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.core
new file mode 100644
index 0000000..02a5f8a
--- /dev/null
+++ b/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.core
@@ -0,0 +1,19 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:sec_cm_prim_sparse_fsm_flop_bind"
+description: "Common bind file for testing sparse_fsm countermeasures"
+
+filesets:
+  files_dv:
+    depend:
+      - lowrisc:prim:sparse_fsm
+    files:
+      - sec_cm_prim_sparse_fsm_flop_bind.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_dv
diff --git a/hw/dv/sv/sec_cm/sec_cm_bind.sv b/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.sv
similarity index 70%
rename from hw/dv/sv/sec_cm/sec_cm_bind.sv
rename to hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.sv
index b0d8820..7bc15ae 100644
--- a/hw/dv/sv/sec_cm/sec_cm_bind.sv
+++ b/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.sv
@@ -2,9 +2,7 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
-module sec_cm_bind();
-  bind prim_count prim_count_if #(.CntStyle(CntStyle), .Width(Width)) u_prim_count_if (.*);
-
+module sec_cm_prim_sparse_fsm_flop_bind();
   bind prim_sparse_fsm_flop prim_sparse_fsm_flop_if #(
          .Width(Width)) u_prim_sparse_fsm_flop_if (.*);
 endmodule
diff --git a/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv b/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
index 2c42fa7..1089672 100644
--- a/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
+++ b/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
@@ -17,6 +17,7 @@
   virtual function void initialize(bit [31:0] csr_base_addr = '1);
     list_of_alerts = keymgr_env_pkg::LIST_OF_ALERTS;
     tl_intg_alert_name = "fatal_fault_err";
+    sec_cm_alert_name  = tl_intg_alert_name;
     num_edn = 1;
     has_shadowed_regs = 1;
     super.initialize(csr_base_addr);
diff --git a/hw/ip/keymgr/dv/keymgr_sim.core b/hw/ip/keymgr/dv/keymgr_sim.core
index 3bd7d8f..2e405b4 100644
--- a/hw/ip/keymgr/dv/keymgr_sim.core
+++ b/hw/ip/keymgr/dv/keymgr_sim.core
@@ -8,6 +8,8 @@
   files_rtl:
     depend:
       - lowrisc:ip:keymgr
+      - lowrisc:dv:sec_cm_prim_count_bind
+      - lowrisc:dv:sec_cm_prim_sparse_fsm_flop_bind
 
   files_dv:
     depend:
diff --git a/hw/ip/keymgr/dv/keymgr_sim_cfg.hjson b/hw/ip/keymgr/dv/keymgr_sim_cfg.hjson
index c5b9c6a..abc3972 100644
--- a/hw/ip/keymgr/dv/keymgr_sim_cfg.hjson
+++ b/hw/ip/keymgr/dv/keymgr_sim_cfg.hjson
@@ -38,7 +38,7 @@
                 ]
 
   // Add additional tops for simulation.
-  sim_tops: ["keymgr_bind", "sec_cm_bind"]
+  sim_tops: ["keymgr_bind", "sec_cm_prim_count_bind", "sec_cm_prim_sparse_fsm_flop_bind"]
 
   // Default iterations for all tests - each test entry can override this.
   reseed: 50
diff --git a/hw/ip/prim/rtl/prim_count.sv b/hw/ip/prim/rtl/prim_count.sv
index bf7e5f4..09b8c1d 100644
--- a/hw/ip/prim/rtl/prim_count.sv
+++ b/hw/ip/prim/rtl/prim_count.sv
@@ -180,24 +180,28 @@
   // Clear and set should not be seen at the same time
   `ASSUME(SimulClrSet_A, clr_i || set_i |-> clr_i != set_i)
 
-  `ASSERT(OutClr_A, clr_i |=> OutSelDnCnt ? &cnt_o : cnt_o == 0)
+  // when the counter is forced by TB, it can be any value, but we should see err_o is set.
+  `ASSERT(OutClr_A, clr_i |=> (OutSelDnCnt ? &cnt_o : cnt_o == 0) || err_o)
 
   // When `en_i` is set without `clr_i` and `set_i`, and counter does not reach max/min value,
-  // we expect `cnt_o` to increment or decrement base on `step_i`.
+  // we expect `cnt_o` to increment or decrement base on `step_i`, or error occurs
   `ASSERT(OutStep_A,
           !(clr_i ||set_i) throughout en_i ##[1:$] en_i && max_val > cnt_o && cnt_o > 0 |->
-          (CntStyle == DupCnt || !OutSelDnCnt) ? cnt_o - past_cnt_o == past_step_i :
-           past_cnt_o - cnt_o == past_step_i)
+          ((CntStyle == DupCnt || !OutSelDnCnt) ? cnt_o - past_cnt_o == past_step_i :
+           past_cnt_o - cnt_o == past_step_i) || err_o)
 
   // When `set_i` is set, at next clock cycle:
   // 1). For duplicate counter, sets the `cnt_o` to `set_cnt_i`.
   // 2). For cross up counter, sets the `max_value` to `set_cnt_i`.
   // 3). For cross down counter, sets the `cnt_o` and `max_value` to `set_cnt_i`.
+  // 4). error occurs due to a fault injection
   `ASSERT(OutSet_A, ##1 set_i |=>
-          (CntStyle == DupCnt || OutSelDnCnt) ? cnt_o == $past(set_cnt_i) : cnt_o == 0)
+          ((CntStyle == DupCnt || OutSelDnCnt) ? cnt_o == $past(set_cnt_i) : cnt_o == 0) || err_o)
 
-  // If the up counter reaches its max value, the value won't increment or change.
-  `ASSERT(MaxUpCntStable_A, up_cnt_q[0] == max_val && !clr_i && !set_i |=> $stable(up_cnt_q[0]))
+  // If the up counter reaches its max value, the value won't increment or change, unless there is
+  // a fault injection
+  `ASSERT(MaxUpCntStable_A, up_cnt_q[0] == max_val && !clr_i && !set_i |=>
+          $stable(up_cnt_q[0]) || err_o)
 
   // This logic that will be assign to one, when user adds macro
   // ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT to check the error with alert, in case that prim_count