[dv/alert] Support LPG in alert_sender/receiver pair

This PR supports LPG in prim_alert testbench by randomly issue
init_trigger_i in alert_receiver side when alert handshake is on-going.
This PR implements part of the TODO in issue #8814.

Signed-off-by: Cindy Chen <chencindy@opentitan.org>
diff --git a/hw/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson b/hw/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson
index 009d6c6..33c588e 100644
--- a/hw/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson
+++ b/hw/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson
@@ -35,6 +35,24 @@
     }
 
     {
+      name: prim_alert_init_trigger_test
+      desc: '''Verify init_trigger input from prim_alert_receiver.
+
+            Based on the prim_alert_test, this test adds a parallel sequence to randomly drive
+            init_trigger_i in prim_alert_receiver.
+
+            Check if alert sender/receiver pairs can resume normal handshake after init_trigger_i
+            is set.
+            For fatal alert, check if fatal alerts keep firing until reset is issued.
+            '''
+      milestone: V1
+      tests: ["prim_async_alert",
+              "prim_async_fatal_alert",
+              "prim_sync_alert",
+              "prim_sync_fatal_alert"]
+    }
+
+    {
       name: prim_alert_ping_request_test
       desc: '''Verify ping request from prim_alert_sender.
 
diff --git a/hw/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson b/hw/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson
index dc450da..e4cbe68 100644
--- a/hw/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson
+++ b/hw/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson
@@ -24,7 +24,7 @@
   import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"]
 
   // Default iterations for all tests - each test entry can override this.
-  reseed: 1
+  reseed: 20
 
   build_modes: [
     {
diff --git a/hw/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv b/hw/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv
index e77bb74..de1ce51 100644
--- a/hw/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv
+++ b/hw/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv
@@ -40,7 +40,7 @@
   localparam int  MinHandshakeWait = 2 + WaitCycle;
 
   // Clock cycles for alert init handshake to finish.
-  localparam int  WaitAlertInitDone = 20;
+  localparam int  WaitAlertInitDone = 30;
 
   typedef enum bit [3:0]{
     AlertSet,
@@ -74,7 +74,7 @@
   logic ping_req, ping_ok, integ_fail, alert_o;
   prim_alert_pkg::alert_rx_t alert_rx;
   prim_alert_pkg::alert_tx_t alert_tx;
-
+  prim_mubi_pkg::mubi4_t     init_trig = prim_mubi_pkg::MuBi4False;
   prim_alert_sender #(
     .AsyncOn(IsAsync),
     .IsFatal(IsFatal)
@@ -94,8 +94,7 @@
   ) i_alert_receiver (
     .clk_i(clk),
     .rst_ni(rst_n),
-    // TODO: randomly trigger this
-    .init_trig_i(prim_mubi_pkg::MuBi4False),
+    .init_trig_i(init_trig),
     .ping_req_i(ping_req),
     .ping_ok_o(ping_ok),
     .integ_fail_o(integ_fail),
@@ -209,30 +208,51 @@
     main_clk.wait_clks(WaitAlertInitDone);
 
     // Sequence 1). Alert request sequence.
-    main_clk.wait_clks($urandom_range(0, 10));
-    alert_req = 1;
-    fork
-      begin
+    for (int num_trans = 1; num_trans <= 10; num_trans++) begin
+      int rand_wait_alert_req = $urandom_range(MinHandshakeWait, 10);
+      int rand_wait_init_trig = $urandom_range(0, 30);
+      fork
+        begin
+          main_clk.wait_clks(rand_wait_alert_req);
+          alert_req = 1;
+          fork
+            begin
+              main_clk.wait_clks(1);
+              check_alert_handshake(.exp_ping_value(0));
+            end
+            // While waiting to check alert handshake, reset alert_req as soon as alert is acked to
+            // avoid triggering multiple alert requests.
+            begin
+              wait (alert_ack == 1);
+              alert_req = 0;
+            end
+          join
+        end
+        begin
+          main_clk.wait_clks(rand_wait_init_trig);
+          init_trig = prim_mubi_pkg::MuBi4True;
+        end
+      join_any
+      disable fork;
+      if (init_trig == prim_mubi_pkg::MuBi4True) begin
+        alert_req = 0;
+        main_clk.wait_clks($urandom_range(0, 10));
+        init_trig = prim_mubi_pkg::MuBi4False;
+        main_clk.wait_clks(WaitAlertInitDone);
+      end
+      // For fatal alert, ensure alert keeps firing until reset.
+      // This check is valid if the alert is fatal, and alert is requested before init request.
+      if (IsFatal && (rand_wait_alert_req + 1) <= rand_wait_init_trig) begin
+        main_clk.wait_clks($urandom_range(10, 100));
+        wait (alert_tx.alert_p == 0);
+        wait (alert_tx.alert_p == 1);
         main_clk.wait_clks(1);
         check_alert_handshake(.exp_ping_value(0));
+        main_clk.apply_reset();
+        main_clk.wait_clks(WaitAlertInitDone);
       end
-      begin
-        wait (alert_ack == 1);
-        alert_req = 0;
-      end
-    join
-
-    // If alert is fatal, check alert will continuously fire until reset.
-    if (IsFatal) begin
-      main_clk.wait_clks($urandom_range(10, 1000));
-      wait (alert_tx.alert_p == 0);
-      wait (alert_tx.alert_p == 1);
-      main_clk.wait_clks(1);
-      check_alert_handshake(.exp_ping_value(0));
-      main_clk.apply_reset();
-      main_clk.wait_clks(WaitAlertInitDone);
+      $display("Alert request sequence %0d/10 finished!", num_trans);
     end
-    $display("Alert request sequence finished!");
 
     // Sequence 2). Alert test sequence.
     main_clk.wait_clks($urandom_range(MinHandshakeWait, 10));