[dv/alert_handler] Add sequence to check low power group

This PR adds a lpg sequence to check if alert_handler disabled the ping
timer in low power group, which finishes part of the TODO from
Issue #8814
Followed this PR I will open another one to collect functional coverage
for each alert_receiver.

Signed-off-by: Cindy Chen <chencindy@opentitan.org>
diff --git a/hw/ip_templates/alert_handler/data/alert_handler_testplan.hjson b/hw/ip_templates/alert_handler/data/alert_handler_testplan.hjson
index 3b61b19..dba5e18 100644
--- a/hw/ip_templates/alert_handler/data/alert_handler_testplan.hjson
+++ b/hw/ip_templates/alert_handler/data/alert_handler_testplan.hjson
@@ -95,6 +95,24 @@
       tests: ["alert_handler_ping_timeout"]
     }
     {
+      name: lpg
+      desc: '''
+            Test alert_handler low_power_group(lpg) request.
+
+            Stimulus:
+            - Randomly enabled alert_receivers' `alert_en` but disable their ping response.
+            - Turn on their low-power control by either set `lpg_cg_en_i` or `lpg_rst_en_i`.
+            - Enable alert ping timeout local alert.
+            - Run alert_handler_entropy_vseq.
+
+            Checks:
+            - Expect no ping timeout error because the alert_receivers are disabled via low-power
+              group.
+            '''
+      milestone: V2
+      tests: ["alert_handler_lpg"]
+    }
+    {
       name: stress_all
       desc: '''
             Combine above sequences in one test to run sequentially with the following exclusions:
diff --git a/hw/ip_templates/alert_handler/dv/alert_handler_sim_cfg.hjson.tpl b/hw/ip_templates/alert_handler/dv/alert_handler_sim_cfg.hjson.tpl
index 7dafab8..96bbd62 100644
--- a/hw/ip_templates/alert_handler/dv/alert_handler_sim_cfg.hjson.tpl
+++ b/hw/ip_templates/alert_handler/dv/alert_handler_sim_cfg.hjson.tpl
@@ -87,6 +87,11 @@
     }
 
     {
+      name: alert_handler_lpg
+      uvm_test_seq: alert_handler_lpg_vseq
+    }
+
+    {
       name: alert_handler_stress_all
       run_opts: ["+test_timeout_ns=15_000_000_000"]
     }
diff --git a/hw/ip_templates/alert_handler/dv/env/alert_handler_env.core b/hw/ip_templates/alert_handler/dv/env/alert_handler_env.core
index d2179df..ffe32f6 100644
--- a/hw/ip_templates/alert_handler/dv/env/alert_handler_env.core
+++ b/hw/ip_templates/alert_handler/dv/env/alert_handler_env.core
@@ -29,6 +29,7 @@
       - seq_lib/alert_handler_sig_int_fail_vseq.sv: {is_include_file: true}
       - seq_lib/alert_handler_entropy_vseq.sv: {is_include_file: true}
       - seq_lib/alert_handler_ping_timeout_vseq.sv: {is_include_file: true}
+      - seq_lib/alert_handler_lpg_vseq.sv: {is_include_file: true}
       - seq_lib/alert_handler_stress_all_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
diff --git a/hw/ip_templates/alert_handler/dv/env/alert_handler_if.sv b/hw/ip_templates/alert_handler/dv/env/alert_handler_if.sv
index 4504fa5..c2ea2d9 100644
--- a/hw/ip_templates/alert_handler/dv/env/alert_handler_if.sv
+++ b/hw/ip_templates/alert_handler/dv/env/alert_handler_if.sv
@@ -18,7 +18,7 @@
   endfunction
 
   // TODO: randomize all values outside of the mubi4 enum.
-  function automatic void set_lpg_en(int index);
+  function automatic void set_lpg_cg_en(int index);
     check_lpg_index(index);
     lpg_cg_en[index] = MuBi4True;
   endfunction
diff --git a/hw/ip_templates/alert_handler/dv/env/alert_handler_scoreboard.sv b/hw/ip_templates/alert_handler/dv/env/alert_handler_scoreboard.sv
index 8b2ea7d..bc58653 100644
--- a/hw/ip_templates/alert_handler/dv/env/alert_handler_scoreboard.sv
+++ b/hw/ip_templates/alert_handler/dv/env/alert_handler_scoreboard.sv
@@ -80,12 +80,15 @@
   virtual task process_alert_fifo();
     foreach (alert_fifo[i]) begin
       automatic int index = i;
+      automatic int lpg_index = alert_handler_reg_pkg::LpgMap[index];
       fork
         forever begin
           bit alert_en, loc_alert_en;
           alert_esc_seq_item act_item;
           alert_fifo[index].get(act_item);
-          alert_en = ral.alert_en_shadowed[index].get_mirrored_value();
+          alert_en = ral.alert_en_shadowed[index].get_mirrored_value() &&
+                     cfg.alert_handler_vif.lpg_cg_en[lpg_index] == prim_mubi_pkg::MuBi4False &&
+                     cfg.alert_handler_vif.lpg_rst_en[lpg_index] == prim_mubi_pkg::MuBi4False;
           if (alert_en) begin
             // alert detected
             if (act_item.alert_esc_type == AlertEscSigTrans && !act_item.ping_timeout &&
diff --git a/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_lpg_vseq.sv b/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_lpg_vseq.sv
new file mode 100644
index 0000000..68b2b83
--- /dev/null
+++ b/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_lpg_vseq.sv
@@ -0,0 +1,58 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class alert_handler_lpg_vseq extends alert_handler_entropy_vseq;
+  `uvm_object_utils(alert_handler_lpg_vseq)
+
+  `uvm_object_new
+
+  constraint sig_int_c {
+    alert_int_err          == 0;
+    esc_int_err            == 0;
+    esc_standalone_int_err == 0;
+  }
+
+  constraint loc_alert_en_c {
+    local_alert_en[LocalAlertPingFail] > 0;
+  }
+
+  constraint ping_fail_c {
+    alert_ping_timeout == alert_en;
+    esc_ping_timeout   == 0;
+  }
+
+  constraint alert_trigger_c {
+    alert_trigger == 0;
+  }
+
+  // disable interrupt timeout
+  constraint esc_intr_timeout_c {
+    foreach (intr_timeout_cyc[i]) {intr_timeout_cyc[i] == 0;}
+  }
+
+  function void pre_randomize();
+    this.enable_classa_only_c.constraint_mode(0);
+    this.enable_one_alert_c.constraint_mode(0);
+    verbosity = UVM_HIGH;
+  endfunction
+
+  function void disable_lpg_group(bit [NUM_ALERTS-1:0] alert_en_i);
+    foreach (alert_en_i[i]) begin
+      int index = alert_handler_reg_pkg::LpgMap[i];
+      if ($urandom_range(0, 1)) cfg.alert_handler_vif.set_lpg_cg_en(index);
+      if ($urandom_range(0, 1)) cfg.alert_handler_vif.set_lpg_rst_en(index);
+    end
+  endfunction
+
+  task body();
+    fork
+      begin : isolation_fork
+        trigger_non_blocking_seqs();
+        disable_lpg_group(alert_en);
+        run_smoke_seq();
+        disable fork; // disable non-blocking seqs for stress_all tests
+      end // end fork
+    join
+  endtask : body
+endclass : alert_handler_lpg_vseq
diff --git a/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_smoke_vseq.sv b/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_smoke_vseq.sv
index 1dc01c0..b1e65ae 100644
--- a/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_smoke_vseq.sv
+++ b/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_smoke_vseq.sv
@@ -118,6 +118,12 @@
 
   virtual task run_smoke_seq();
     `uvm_info(`gfn, $sformatf("num_trans=%0d", num_trans), UVM_LOW)
+    if (verbosity != UVM_LOW) begin
+      `uvm_info(`gfn,
+          $sformatf("Config: intr_en=%0b, alert=%0b, alert_en=%0b, loc_alert_en=%0b",
+          intr_en, alert_trigger, alert_en, local_alert_en), UVM_LOW)
+    end
+
     for (int i = 1; i <= num_trans; i++) begin
       `DV_CHECK_RANDOMIZE_FATAL(this)
 
diff --git a/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_vseq_list.sv b/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_vseq_list.sv
index 14b176f..22b07a7 100644
--- a/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_vseq_list.sv
+++ b/hw/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_vseq_list.sv
@@ -12,4 +12,5 @@
 `include "alert_handler_sig_int_fail_vseq.sv"
 `include "alert_handler_entropy_vseq.sv"
 `include "alert_handler_ping_timeout_vseq.sv"
+`include "alert_handler_lpg_vseq.sv"
 `include "alert_handler_stress_all_vseq.sv"
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/data/alert_handler_testplan.hjson b/hw/top_earlgrey/ip_autogen/alert_handler/data/alert_handler_testplan.hjson
index 3b61b19..dba5e18 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/data/alert_handler_testplan.hjson
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/data/alert_handler_testplan.hjson
@@ -95,6 +95,24 @@
       tests: ["alert_handler_ping_timeout"]
     }
     {
+      name: lpg
+      desc: '''
+            Test alert_handler low_power_group(lpg) request.
+
+            Stimulus:
+            - Randomly enabled alert_receivers' `alert_en` but disable their ping response.
+            - Turn on their low-power control by either set `lpg_cg_en_i` or `lpg_rst_en_i`.
+            - Enable alert ping timeout local alert.
+            - Run alert_handler_entropy_vseq.
+
+            Checks:
+            - Expect no ping timeout error because the alert_receivers are disabled via low-power
+              group.
+            '''
+      milestone: V2
+      tests: ["alert_handler_lpg"]
+    }
+    {
       name: stress_all
       desc: '''
             Combine above sequences in one test to run sequentially with the following exclusions:
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/alert_handler_sim_cfg.hjson b/hw/top_earlgrey/ip_autogen/alert_handler/dv/alert_handler_sim_cfg.hjson
index d9932c8..448bb2b 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/alert_handler_sim_cfg.hjson
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/alert_handler_sim_cfg.hjson
@@ -87,6 +87,11 @@
     }
 
     {
+      name: alert_handler_lpg
+      uvm_test_seq: alert_handler_lpg_vseq
+    }
+
+    {
       name: alert_handler_stress_all
       run_opts: ["+test_timeout_ns=15_000_000_000"]
     }
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env.core b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env.core
index d2179df..ffe32f6 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env.core
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env.core
@@ -29,6 +29,7 @@
       - seq_lib/alert_handler_sig_int_fail_vseq.sv: {is_include_file: true}
       - seq_lib/alert_handler_entropy_vseq.sv: {is_include_file: true}
       - seq_lib/alert_handler_ping_timeout_vseq.sv: {is_include_file: true}
+      - seq_lib/alert_handler_lpg_vseq.sv: {is_include_file: true}
       - seq_lib/alert_handler_stress_all_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_if.sv b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_if.sv
index 4504fa5..c2ea2d9 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_if.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_if.sv
@@ -18,7 +18,7 @@
   endfunction
 
   // TODO: randomize all values outside of the mubi4 enum.
-  function automatic void set_lpg_en(int index);
+  function automatic void set_lpg_cg_en(int index);
     check_lpg_index(index);
     lpg_cg_en[index] = MuBi4True;
   endfunction
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_scoreboard.sv b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_scoreboard.sv
index 8b2ea7d..bc58653 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_scoreboard.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_scoreboard.sv
@@ -80,12 +80,15 @@
   virtual task process_alert_fifo();
     foreach (alert_fifo[i]) begin
       automatic int index = i;
+      automatic int lpg_index = alert_handler_reg_pkg::LpgMap[index];
       fork
         forever begin
           bit alert_en, loc_alert_en;
           alert_esc_seq_item act_item;
           alert_fifo[index].get(act_item);
-          alert_en = ral.alert_en_shadowed[index].get_mirrored_value();
+          alert_en = ral.alert_en_shadowed[index].get_mirrored_value() &&
+                     cfg.alert_handler_vif.lpg_cg_en[lpg_index] == prim_mubi_pkg::MuBi4False &&
+                     cfg.alert_handler_vif.lpg_rst_en[lpg_index] == prim_mubi_pkg::MuBi4False;
           if (alert_en) begin
             // alert detected
             if (act_item.alert_esc_type == AlertEscSigTrans && !act_item.ping_timeout &&
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_lpg_vseq.sv b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_lpg_vseq.sv
new file mode 100644
index 0000000..68b2b83
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_lpg_vseq.sv
@@ -0,0 +1,58 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class alert_handler_lpg_vseq extends alert_handler_entropy_vseq;
+  `uvm_object_utils(alert_handler_lpg_vseq)
+
+  `uvm_object_new
+
+  constraint sig_int_c {
+    alert_int_err          == 0;
+    esc_int_err            == 0;
+    esc_standalone_int_err == 0;
+  }
+
+  constraint loc_alert_en_c {
+    local_alert_en[LocalAlertPingFail] > 0;
+  }
+
+  constraint ping_fail_c {
+    alert_ping_timeout == alert_en;
+    esc_ping_timeout   == 0;
+  }
+
+  constraint alert_trigger_c {
+    alert_trigger == 0;
+  }
+
+  // disable interrupt timeout
+  constraint esc_intr_timeout_c {
+    foreach (intr_timeout_cyc[i]) {intr_timeout_cyc[i] == 0;}
+  }
+
+  function void pre_randomize();
+    this.enable_classa_only_c.constraint_mode(0);
+    this.enable_one_alert_c.constraint_mode(0);
+    verbosity = UVM_HIGH;
+  endfunction
+
+  function void disable_lpg_group(bit [NUM_ALERTS-1:0] alert_en_i);
+    foreach (alert_en_i[i]) begin
+      int index = alert_handler_reg_pkg::LpgMap[i];
+      if ($urandom_range(0, 1)) cfg.alert_handler_vif.set_lpg_cg_en(index);
+      if ($urandom_range(0, 1)) cfg.alert_handler_vif.set_lpg_rst_en(index);
+    end
+  endfunction
+
+  task body();
+    fork
+      begin : isolation_fork
+        trigger_non_blocking_seqs();
+        disable_lpg_group(alert_en);
+        run_smoke_seq();
+        disable fork; // disable non-blocking seqs for stress_all tests
+      end // end fork
+    join
+  endtask : body
+endclass : alert_handler_lpg_vseq
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_smoke_vseq.sv b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_smoke_vseq.sv
index 1dc01c0..b1e65ae 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_smoke_vseq.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_smoke_vseq.sv
@@ -118,6 +118,12 @@
 
   virtual task run_smoke_seq();
     `uvm_info(`gfn, $sformatf("num_trans=%0d", num_trans), UVM_LOW)
+    if (verbosity != UVM_LOW) begin
+      `uvm_info(`gfn,
+          $sformatf("Config: intr_en=%0b, alert=%0b, alert_en=%0b, loc_alert_en=%0b",
+          intr_en, alert_trigger, alert_en, local_alert_en), UVM_LOW)
+    end
+
     for (int i = 1; i <= num_trans; i++) begin
       `DV_CHECK_RANDOMIZE_FATAL(this)
 
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_vseq_list.sv b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_vseq_list.sv
index 14b176f..22b07a7 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_vseq_list.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_vseq_list.sv
@@ -12,4 +12,5 @@
 `include "alert_handler_sig_int_fail_vseq.sv"
 `include "alert_handler_entropy_vseq.sv"
 `include "alert_handler_ping_timeout_vseq.sv"
+`include "alert_handler_lpg_vseq.sv"
 `include "alert_handler_stress_all_vseq.sv"