[sv/alert] add alert support in cip_base

In cip_base_scoreboard, add the following alert_esc_agent support:
1. Add tlm_analysis port to detect alert sent from DUT
2. Use process_alert_fifos task to filter out illegal alert_items (ping
responses and sig_int_err). If real alert happened, or real alert
handshake finished, both condition will call "process_alert_sig"
function.

In cip_base_vseq, add support:
1. add a knob to en_auto_alerts_response in cip_base_vseq - default on
2. add run_alert_response_nonblocking in dut_init
3. If user disabled the en_auto_alerts_response knob, the nonblocking
sequence will wait for current response to finish then exit
4. If user wants to re-enable the en_auto_alerts_response knob, they
have to also trigger dut_init() again

Signed-off-by: Cindy Chen <chencindy@google.com>
diff --git a/hw/dv/sv/cip_lib/cip_base_env.sv b/hw/dv/sv/cip_lib/cip_base_env.sv
index 035e374..059e972 100644
--- a/hw/dv/sv/cip_lib/cip_base_env.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env.sv
@@ -42,6 +42,7 @@
     // create components
     m_tl_agent = tl_agent::type_id::create("m_tl_agent", this);
     m_tl_reg_adapter = tl_reg_adapter#()::type_id::create("m_tl_reg_adapter");
+
     // create alert agents and cfgs
     foreach(cfg.list_of_alerts[i]) begin
       string alert_name = cfg.list_of_alerts[i];
@@ -52,6 +53,7 @@
       uvm_config_db#(alert_esc_agent_cfg)::set(this, agent_name, "cfg",
           cfg.m_alert_agent_cfg[alert_name]);
     end
+
     uvm_config_db#(tl_agent_cfg)::set(this, "m_tl_agent*", "cfg", cfg.m_tl_agent_cfg);
   endfunction
 
@@ -59,6 +61,12 @@
     super.connect_phase(phase);
     m_tl_agent.monitor.a_chan_port.connect(scoreboard.tl_a_chan_fifo.analysis_export);
     m_tl_agent.monitor.d_chan_port.connect(scoreboard.tl_d_chan_fifo.analysis_export);
+    foreach (cfg.list_of_alerts[i]) begin
+      string alert_name = cfg.list_of_alerts[i];
+      m_alert_agent[alert_name].monitor.alert_esc_port.connect(
+          scoreboard.alert_fifos[alert_name].analysis_export);
+    end
+
     if (cfg.is_active) begin
       virtual_sequencer.tl_sequencer_h = m_tl_agent.sequencer;
     end
diff --git a/hw/dv/sv/cip_lib/cip_base_scoreboard.sv b/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
index d4451b4..21f0b77 100644
--- a/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
+++ b/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
@@ -12,6 +12,9 @@
   uvm_tlm_analysis_fifo #(tl_seq_item)  tl_a_chan_fifo;
   uvm_tlm_analysis_fifo #(tl_seq_item)  tl_d_chan_fifo;
 
+  // Alert_fifo to notify scb if DUT sends an alert
+  uvm_tlm_analysis_fifo #(alert_esc_seq_item) alert_fifos[string];
+
   mem_model#() exp_mem;
 
   `uvm_component_new
@@ -20,6 +23,10 @@
     super.build_phase(phase);
     tl_a_chan_fifo = new("tl_a_chan_fifo", this);
     tl_d_chan_fifo = new("tl_d_chan_fifo", this);
+    foreach(cfg.list_of_alerts[i]) begin
+      string alert_name = cfg.list_of_alerts[i];
+      alert_fifos[alert_name] = new($sformatf("alert_fifo[%s]", alert_name), this);
+    end
     exp_mem = mem_model#()::type_id::create("exp_mem", this);
   endfunction
 
@@ -28,6 +35,7 @@
     fork
       process_tl_a_chan_fifo();
       process_tl_d_chan_fifo();
+      if (cfg.list_of_alerts.size()) process_alert_fifos();
     join_none
   endtask
 
@@ -64,6 +72,35 @@
     end
   endtask
 
+  virtual task process_alert_fifos();
+    foreach (alert_fifos[i]) begin
+      automatic string alert_name = i;
+      fork
+        forever begin
+          alert_esc_seq_item item;
+          alert_fifos[alert_name].get(item);
+          if (!cfg.en_scb) continue;
+          if (item.alert_esc_type == AlertEscSigTrans && !item.timeout &&
+              item.alert_handshake_sta inside {AlertReceived, AlertAckComplete}) begin
+            process_alert(alert_name, item);
+          // IP level alert protocol does not drive any sig_int_err or ping response
+          end else if (item.alert_esc_type == AlertEscIntFail) begin
+            `uvm_error(`gfn, $sformatf("alert %s has unexpected signal int error", alert_name))
+          end else if (item.timeout) begin
+            `uvm_error(`gfn, $sformatf("alert %s has unexpected timeout error", alert_name))
+          end else if (item.alert_esc_type == AlertEscPingTrans) begin
+            `uvm_error(`gfn, $sformatf("alert %s has unexpected alert ping response", alert_name))
+          end
+        end
+      join_none
+    end
+  endtask
+
+  virtual function void process_alert(string alert_name, alert_esc_seq_item item);
+    `uvm_info(`gfn, $sformatf("alert %0s detected, alert_status is %s", alert_name,
+                              item.alert_handshake_sta), UVM_DEBUG)
+  endfunction
+
   // task to process tl access
   virtual task process_tl_access(tl_seq_item item, tl_channels_e channel = DataChannel);
     `uvm_fatal(`gfn, "this method is not supposed to be called directly!")
diff --git a/hw/dv/sv/cip_lib/cip_base_vseq.sv b/hw/dv/sv/cip_lib/cip_base_vseq.sv
index 6b23b07..2435164 100644
--- a/hw/dv/sv/cip_lib/cip_base_vseq.sv
+++ b/hw/dv/sv/cip_lib/cip_base_vseq.sv
@@ -10,6 +10,10 @@
   `uvm_object_new
   // knobs to disable post_start clear interrupt routine
   bit  do_clear_all_interrupts = 1'b1;
+  // knobs to enable alert auto reponse, once disabled it won't be able to enable again unless
+  // dut_init is issued
+  bit  en_auto_alerts_response = 1'b1;
+
   // csr queue for intr test/enable/state
   dv_base_reg intr_test_csrs[$];
   dv_base_reg intr_state_csrs[$];
@@ -47,6 +51,11 @@
 
   `include "cip_base_vseq__tl_errors.svh"
 
+  virtual task dut_init(string reset_kind = "HARD");
+    super.dut_init(reset_kind);
+    if (en_auto_alerts_response && cfg.list_of_alerts.size()) run_alert_rsp_seq_nonblocking();
+  endtask
+
   task pre_start();
     csr_utils_pkg::max_outstanding_accesses = 1 << TL_AIW;
     super.pre_start();
@@ -556,13 +565,22 @@
 
   virtual task run_alert_rsp_seq_nonblocking();
     foreach (cfg.list_of_alerts[i]) begin
-      automatic string seqr_name = cfg.list_of_alerts[i];
+      automatic string alert_name = cfg.list_of_alerts[i];
       fork
-        forever begin
-          alert_receiver_alert_rsp_seq ack_seq =
-              alert_receiver_alert_rsp_seq::type_id::create("ack_seq");
-          `DV_CHECK_RANDOMIZE_FATAL(ack_seq);
-          ack_seq.start(p_sequencer.alert_esc_sequencer_h[seqr_name]);
+        begin
+          fork
+            forever begin
+              alert_receiver_alert_rsp_seq ack_seq =
+                  alert_receiver_alert_rsp_seq::type_id::create("ack_seq");
+              `DV_CHECK_RANDOMIZE_FATAL(ack_seq);
+              ack_seq.start(p_sequencer.alert_esc_sequencer_h[alert_name]);
+            end
+            begin
+              wait(!en_auto_alerts_response || cfg.under_reset);
+              cfg.m_alert_agent_cfg[alert_name].vif.wait_ack_complete();
+            end
+          join_any
+          disable fork;
         end
       join_none
     end
diff --git a/hw/ip/hmac/dv/env/seq_lib/hmac_base_vseq.sv b/hw/ip/hmac/dv/env/seq_lib/hmac_base_vseq.sv
index e47cf9c..b608497 100644
--- a/hw/ip/hmac/dv/env/seq_lib/hmac_base_vseq.sv
+++ b/hw/ip/hmac/dv/env/seq_lib/hmac_base_vseq.sv
@@ -33,17 +33,9 @@
 
   virtual task dut_init(string reset_kind = "HARD");
     super.dut_init(reset_kind);
-    alert_send_ping();
     if (do_hmac_init) hmac_init();
   endtask
 
-  virtual task alert_send_ping();
-    alert_receiver_seq ping_seq;
-    `uvm_create_on(ping_seq, p_sequencer.alert_esc_sequencer_h[cfg.list_of_alerts[0]]);
-    `DV_CHECK_RANDOMIZE_FATAL(ping_seq)
-    `uvm_send(ping_seq)
-  endtask
-
   virtual task dut_shutdown();
     super.dut_shutdown();
     // TODO: nothing extra to do yet