[dv/alert_handler] Support esc resp integrity fail

Add support for esc response int fail

Signed-off-by: Cindy Chen <chencindy@google.com>
diff --git a/hw/dv/sv/alert_esc_agent/alert_esc_agent_pkg.sv b/hw/dv/sv/alert_esc_agent/alert_esc_agent_pkg.sv
index f8cb402..14e7724 100644
--- a/hw/dv/sv/alert_esc_agent/alert_esc_agent_pkg.sv
+++ b/hw/dv/sv/alert_esc_agent/alert_esc_agent_pkg.sv
@@ -42,6 +42,12 @@
     HasAlertBeforeAfterIntFail = 'b11
   } alert_sig_int_err_e;
 
+  typedef enum {
+    NoResponse,
+    RandResponse,
+    SigPNIntErr
+  } resp_sig_int_err_e;
+
   // macro includes
   `include "uvm_macros.svh"
   `include "dv_macros.svh"
diff --git a/hw/dv/sv/alert_esc_agent/alert_esc_if.sv b/hw/dv/sv/alert_esc_agent/alert_esc_if.sv
index e9a7b41..2b6cd9d 100644
--- a/hw/dv/sv/alert_esc_agent/alert_esc_if.sv
+++ b/hw/dv/sv/alert_esc_agent/alert_esc_if.sv
@@ -124,11 +124,11 @@
   // tasks for escalator sender/receiver pairs
 
   task automatic wait_esc();
-    while (esc_tx.esc_p !== 1'b1) @(monitor_cb);
+    while (esc_tx.esc_p === 1'b0 && esc_tx.esc_n === 1'b1) @(monitor_cb);
   endtask : wait_esc
 
   task automatic wait_esc_complete();
-    while (esc_tx.esc_p !== 1'b0) @(monitor_cb);
+    while (esc_tx.esc_p === 1'b1 && esc_tx.esc_n === 1'b0) @(monitor_cb);
   endtask : wait_esc_complete
 
   task automatic reset_esc();
@@ -146,12 +146,15 @@
     receiver_cb.esc_rx.resp_n <= 1'b1;
   endtask
 
-  function automatic bit get_esc_p();
-    return monitor_cb.esc_tx.esc_p;
+  function automatic bit get_esc();
+    return monitor_cb.esc_tx.esc_p && !monitor_cb.esc_tx.esc_n;
   endfunction
 
   function automatic bit get_resp_p();
     return monitor_cb.esc_rx.resp_p;
   endfunction
 
+  function automatic bit get_resp_n();
+    return monitor_cb.esc_rx.resp_n;
+  endfunction
 endinterface: alert_esc_if
diff --git a/hw/dv/sv/alert_esc_agent/alert_esc_seq_item.sv b/hw/dv/sv/alert_esc_agent/alert_esc_seq_item.sv
index 6cfad90..5ac8555 100644
--- a/hw/dv/sv/alert_esc_agent/alert_esc_seq_item.sv
+++ b/hw/dv/sv/alert_esc_agent/alert_esc_seq_item.sv
@@ -16,7 +16,8 @@
   rand bit r_esc_rsp;
   rand bit int_err;
   rand bit timeout;
-  rand alert_sig_int_err_e int_err_scenario;
+  rand alert_sig_int_err_e alert_int_err_type;
+  rand resp_sig_int_err_e  resp_int_err_type;
 
   // for monitor only
   rand alert_esc_trans_type_e alert_esc_type;
@@ -46,8 +47,9 @@
   }
 
   // TODO: temp constraint, will support soon
-  constraint sig_int_fail_c {
-    int_err_scenario == NoAlertBeforeAfterIntFail;
+  constraint sig_int_err_c {
+    alert_int_err_type == NoAlertBeforeAfterIntFail;
+    resp_int_err_type == RandResponse;
   }
 
   `uvm_object_utils_begin(alert_esc_seq_item)
@@ -58,6 +60,13 @@
     `uvm_field_int (r_esc_rsp,         UVM_DEFAULT)
     `uvm_field_int (int_err,           UVM_DEFAULT)
     `uvm_field_int (timeout,           UVM_DEFAULT)
+    `uvm_field_int (ping_delay,        UVM_DEFAULT)
+    `uvm_field_int (ack_delay,         UVM_DEFAULT)
+    `uvm_field_int (ack_stable,        UVM_DEFAULT)
+    `uvm_field_int (alert_delay,       UVM_DEFAULT)
+    `uvm_field_int (int_err_cyc,       UVM_DEFAULT)
+    `uvm_field_enum(alert_sig_int_err_e,    alert_int_err_type,  UVM_DEFAULT)
+    `uvm_field_enum(resp_sig_int_err_e,     resp_int_err_type,   UVM_DEFAULT)
     `uvm_field_enum(alert_esc_trans_type_e, alert_esc_type,      UVM_DEFAULT)
     `uvm_field_enum(alert_handshake_e,      alert_handshake_sta, UVM_DEFAULT)
     `uvm_field_enum(esc_handshake_e,        esc_handshake_sta,   UVM_DEFAULT)
diff --git a/hw/dv/sv/alert_esc_agent/alert_sender_driver.sv b/hw/dv/sv/alert_esc_agent/alert_sender_driver.sv
index 86eedcb..e20eb63 100644
--- a/hw/dv/sv/alert_esc_agent/alert_sender_driver.sv
+++ b/hw/dv/sv/alert_esc_agent/alert_sender_driver.sv
@@ -79,9 +79,9 @@
       reset_alert_pins(ack_delay);
     // alert signals integrity fail
     end else begin
-      if (req.int_err_scenario & HasAlertBeforeIntFailOnly) set_alert_pins(alert_delay);
+      if (req.alert_int_err_type & HasAlertBeforeIntFailOnly) set_alert_pins(alert_delay);
       random_drive_int_fail(req.int_err_cyc);
-      if (req.int_err_scenario & HasAlertAfterIntFailOnly) begin
+      if (req.alert_int_err_type & HasAlertAfterIntFailOnly) begin
         set_alert_pins(alert_delay);
       end else begin
         cfg.vif.reset_alert();
diff --git a/hw/dv/sv/alert_esc_agent/esc_monitor.sv b/hw/dv/sv/alert_esc_agent/esc_monitor.sv
index 39b11fd..eb87c14 100644
--- a/hw/dv/sv/alert_esc_agent/esc_monitor.sv
+++ b/hw/dv/sv/alert_esc_agent/esc_monitor.sv
@@ -19,6 +19,7 @@
     fork
       esc_thread(phase);
       reset_thread(phase);
+      int_fail_thread(phase);
     join_none
   endtask : run_phase
 
@@ -34,7 +35,7 @@
     alert_esc_seq_item req;
     bit                esc_p;
     forever @(cfg.vif.monitor_cb) begin
-      if (!esc_p && cfg.vif.get_esc_p() === 1'b1) begin
+      if (!esc_p && cfg.vif.get_esc() === 1'b1) begin
         phase.raise_objection(this, $sformatf("%s objection raised", `gfn));
         req = alert_esc_seq_item::type_id::create("req");
         req.alert_esc_type = AlertEscSigTrans;
@@ -52,7 +53,7 @@
               begin : wait_esc_handshake
                 @(cfg.vif.monitor_cb);
                 check_esc_resp_toggle(req);
-                while (cfg.vif.get_esc_p() === 1) check_esc_resp_toggle(req);
+                while (cfg.vif.get_esc() === 1) check_esc_resp_toggle(req);
                 if (req.esc_handshake_sta != EscIntFail) begin
                   req.esc_handshake_sta = EscRespComplete;
                 end
@@ -66,10 +67,24 @@
         alert_esc_port.write(req);
         phase.drop_objection(this, $sformatf("%s objection dropped", `gfn));
       end
-      esc_p = cfg.vif.get_esc_p();
+      esc_p = cfg.vif.get_esc();
     end
   endtask : esc_thread
 
+  virtual task int_fail_thread(uvm_phase phase);
+    alert_esc_seq_item req;
+    forever @(cfg.vif.monitor_cb) begin
+      while (cfg.vif.get_esc() === 1'b0) begin
+        @(cfg.vif.monitor_cb);
+        if (cfg.vif.get_resp_p() === 1'b1 && cfg.vif.get_resp_n() == 1'b0) begin
+          req = alert_esc_seq_item::type_id::create("req");
+          req.alert_esc_type = AlertEscIntFail;
+          alert_esc_port.write(req);
+        end
+      end
+    end
+  endtask : int_fail_thread
+
   virtual task check_esc_resp_toggle(alert_esc_seq_item req);
     if (cfg.vif.get_resp_p() != 1) req.esc_handshake_sta = EscIntFail;
     @(cfg.vif.monitor_cb);
diff --git a/hw/dv/sv/alert_esc_agent/esc_receiver_driver.sv b/hw/dv/sv/alert_esc_agent/esc_receiver_driver.sv
index 2d7878d..0559534 100644
--- a/hw/dv/sv/alert_esc_agent/esc_receiver_driver.sv
+++ b/hw/dv/sv/alert_esc_agent/esc_receiver_driver.sv
@@ -1,7 +1,6 @@
 // Copyright lowRISC contributors.
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
-//
 
 // ---------------------------------------------
 // Alert_handler receiver driver
@@ -27,25 +26,48 @@
       alert_esc_seq_item req, rsp;
       wait(r_esc_rsp_q.size() > 0);
       req = r_esc_rsp_q.pop_front();
-      $cast(rsp, req.clone());
-      rsp.set_id_info(req);
-      `uvm_info(`gfn,
-          $sformatf("starting to send receiver item, esc_rsp=%0b, int_fail=%0b",
-          req.r_esc_rsp, req.int_err), UVM_HIGH)
+      fork
+        begin
+          $cast(rsp, req.clone());
+          rsp.set_id_info(req);
+          `uvm_info(`gfn,
+              $sformatf("starting to send receiver item, esc_rsp=%0b, int_fail=%0b",
+              req.r_esc_rsp, req.int_err), UVM_HIGH)
 
-      cfg.vif.wait_esc();
-      @(cfg.vif.receiver_cb);
-      while (cfg.vif.receiver_cb.esc_tx.esc_p === 1'b1) begin
-        cfg.vif.set_resp();
-        @(cfg.vif.receiver_cb);
-        cfg.vif.reset_resp();
-        @(cfg.vif.receiver_cb);
-      end
-
-      `uvm_info(`gfn,
-          $sformatf("finished sending receiver item, esc_rsp=%0b, int_fail=%0b",
-          req.r_esc_rsp, req.int_err), UVM_HIGH)
-      seq_item_port.put_response(rsp);
-    end
+          // toggle resp signals only when esc signals are not set
+          if (req.int_err && req.resp_int_err_type == RandResponse) begin
+            cfg.vif.wait_esc_complete();
+            repeat (req.int_err_cyc) begin
+              if (cfg.vif.get_esc() === 1'b0) begin
+                randcase
+                  1: cfg.vif.set_resp();
+                  1: cfg.vif.reset_resp();
+                endcase
+              end else begin
+                break;
+              end
+              @(cfg.vif.receiver_cb);
+            end
+            if (cfg.vif.get_esc() === 1'b0) cfg.vif.reset_resp();
+          end else begin
+            cfg.vif.wait_esc();
+            @(cfg.vif.receiver_cb);
+            while (cfg.vif.get_esc() === 1'b1) toggle_resp_signal();
+          end
+          `uvm_info(`gfn,
+              $sformatf("finished sending receiver item, esc_rsp=%0b, int_fail=%0b",
+              req.r_esc_rsp, req.int_err), UVM_HIGH)
+          seq_item_port.put_response(rsp);
+        end
+      join_none
+    end // end forever
   endtask : rsp_escalator
+
+  task toggle_resp_signal();
+    cfg.vif.set_resp();
+    @(cfg.vif.receiver_cb);
+    cfg.vif.reset_resp();
+    @(cfg.vif.receiver_cb);
+  endtask : toggle_resp_signal
+
 endclass : esc_receiver_driver
diff --git a/hw/dv/sv/alert_esc_agent/seq_lib/esc_receiver_esc_rsp_seq.sv b/hw/dv/sv/alert_esc_agent/seq_lib/esc_receiver_esc_rsp_seq.sv
index 69db9de..de1f8e7 100644
--- a/hw/dv/sv/alert_esc_agent/seq_lib/esc_receiver_esc_rsp_seq.sv
+++ b/hw/dv/sv/alert_esc_agent/seq_lib/esc_receiver_esc_rsp_seq.sv
@@ -12,12 +12,15 @@
   `uvm_object_utils(esc_receiver_esc_rsp_seq)
   `uvm_object_new
 
+  rand bit int_err;
+
   virtual task body();
     `uvm_info(`gfn, $sformatf("starting escalator receiver transfer"), UVM_HIGH)
     req = alert_esc_seq_item::type_id::create("req");
     start_item(req);
     `DV_CHECK_RANDOMIZE_WITH_FATAL(req,
         r_esc_rsp == 1;
+        int_err   == local::int_err;
     )
     `uvm_info(`gfn, $sformatf("seq_item: esc_rsp, int_err=%0b", req.int_err), UVM_HIGH)
     finish_item(req);
diff --git a/hw/ip/alert_handler/dv/env/alert_handler_scoreboard.sv b/hw/ip/alert_handler/dv/env/alert_handler_scoreboard.sv
index 594481b..2ad3a43 100644
--- a/hw/ip/alert_handler/dv/env/alert_handler_scoreboard.sv
+++ b/hw/ip/alert_handler/dv/env/alert_handler_scoreboard.sv
@@ -126,6 +126,10 @@
               act_item.esc_handshake_sta == EscRespComplete) begin
             check_esc_phase(phase_info);
           end
+          if (act_item.alert_esc_type == AlertEscIntFail) begin
+            bit [TL_DW-1:0] loc_alert_en = ral.loc_alert_en.get_mirrored_value();
+            if (loc_alert_en[LocalEscIntFail]) process_alert_sig(index, 1, LocalEscIntFail);
+          end
         end
       join_none
     end
@@ -335,12 +339,14 @@
             for (int phase_i = 0; phase_i < NUM_ESC_PHASES; phase_i++) begin
               int phase_thresh = reg_esc_phase_cycs_per_class_q[class_i][phase_i]
                                 .get_mirrored_value();
-              @(cfg.clk_rst_vif.cb);
-              intr_timer_per_class[class_i] = 1;
-              while (under_esc_classes[class_i] != 0 &&
-                     intr_timer_per_class[class_i] < phase_thresh) begin
+              if (!under_reset && under_esc_classes[class_i]) begin
                 @(cfg.clk_rst_vif.cb);
-                intr_timer_per_class[class_i] += 1;
+                intr_timer_per_class[class_i] = 1;
+                while (under_esc_classes[class_i] != 0 &&
+                       intr_timer_per_class[class_i] < phase_thresh) begin
+                  @(cfg.clk_rst_vif.cb);
+                  intr_timer_per_class[class_i] += 1;
+                end
               end
             end
             @(cfg.clk_rst_vif.cb);
diff --git a/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_base_vseq.sv b/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_base_vseq.sv
index bb04d53..a257f7f 100644
--- a/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_base_vseq.sv
+++ b/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_base_vseq.sv
@@ -86,6 +86,27 @@
     join
   endtask
 
+  virtual task drive_esc_resp(bit[alert_pkg::N_ESC_SEV-1:0] esc_int_err);
+    fork
+      begin : isolation_fork
+        foreach (esc_int_err[i]) begin
+          if (esc_int_err[i]) begin
+            automatic int index = i;
+            fork
+              begin
+                esc_receiver_esc_rsp_seq esc_seq;
+                `uvm_create_on(esc_seq, p_sequencer.esc_device_seqr_h[index]);
+                `DV_CHECK_RANDOMIZE_WITH_FATAL(esc_seq, int_err == 1;)
+                `uvm_send(esc_seq)
+              end
+            join_none
+          end
+        end
+        wait fork;
+      end
+    join
+  endtask
+
   virtual task clear_esc();
     csr_wr(.csr(ral.classa_clr), .value(1));
     csr_wr(.csr(ral.classb_clr), .value(1));
@@ -149,7 +170,7 @@
         forever begin
           esc_receiver_esc_rsp_seq esc_seq =
               esc_receiver_esc_rsp_seq::type_id::create("esc_seq");
-          `DV_CHECK_RANDOMIZE_FATAL(esc_seq);
+          `DV_CHECK_RANDOMIZE_WITH_FATAL(esc_seq, int_err == 0;);
           esc_seq.start(p_sequencer.esc_device_seqr_h[index]);
         end
       join_none
diff --git a/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_sanity_vseq.sv b/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_sanity_vseq.sv
index bce8d80..eba7894 100644
--- a/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_sanity_vseq.sv
+++ b/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_sanity_vseq.sv
@@ -15,6 +15,7 @@
   rand bit [alert_pkg::NAlerts*2-1:0]      alert_class_map;
   rand bit [NUM_LOCAL_ALERT-1:0]           local_alert_en;
   rand bit [NUM_LOCAL_ALERT*2-1:0]         local_alert_class_map;
+  rand bit [alert_pkg::N_ESC_SEV-1:0]      esc_int_err;
 
   rand bit do_clr_esc;
   rand bit do_wr_phases_cyc;
@@ -49,6 +50,7 @@
 
   constraint sig_int_c {
     alert_int_err == 0;
+    esc_int_err   == 0;
   }
 
   task body();
@@ -75,6 +77,7 @@
       if (do_esc_intr_timeout) wr_intr_timeout_cycle(intr_timeout_cyc);
       wr_class_accum_threshold(accum_thresh);
 
+      if (esc_int_err) drive_esc_resp(esc_int_err);
       // drive alert
       drive_alert(alert_trigger, alert_int_err);
 
diff --git a/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_sig_int_fail_vseq.sv b/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_sig_int_fail_vseq.sv
index f23ae0e..8be3ae7 100644
--- a/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_sig_int_fail_vseq.sv
+++ b/hw/ip/alert_handler/dv/env/seq_lib/alert_handler_sig_int_fail_vseq.sv
@@ -14,12 +14,13 @@
   }
 
   constraint enable_alert_int_fail_only_c {
-    local_alert_en == (1 << LocalAlertIntFail); // TODO: temp constraint, take off once scb support esc int fail
+    local_alert_en inside {1 << LocalAlertIntFail, 1 << LocalEscIntFail};
+    // TODO: temp constraint, take off once scb support ping response fail
   }
 
   function void pre_randomize();
     this.enable_one_alert_c.constraint_mode(0);
-    this.enable_classa_only_c.constraint_mode(0);
+    // TODO: add support this.enable_classa_only_c.constraint_mode(0);
   endfunction
 
 endclass : alert_handler_sig_int_fail_vseq