[dv/alert_handler] Add checking for crashdump_o output

This PR supports checking in scb regarding the crashdumo_o output.
To avoid a cycle-accurate model, I left a TODO to see how to check
esc_cnt and alert_accum_count.

Signed-off-by: Cindy Chen <chencindy@opentitan.org>
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 1634e02..184ff07 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
@@ -8,6 +8,7 @@
   files_dv:
     depend:
       - lowrisc:dv:cip_lib
+      - lowrisc:ip:alert_handler_component # import alert_pkg
     files:
       - alert_handler_env_pkg.sv
       - alert_handler_env_cfg.sv: {is_include_file: true}
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 f2e51bc..8b2ea7d 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
@@ -40,6 +40,9 @@
 
   string class_name[] = {"a", "b", "c", "d"};
   bit [TL_DW-1:0] intr_state_val;
+
+  bit crashdump_triggered = 0;
+
   // TLM agent fifos
   uvm_tlm_analysis_fifo #(alert_esc_seq_item) alert_fifo[NUM_ALERTS];
   uvm_tlm_analysis_fifo #(alert_esc_seq_item) esc_fifo[NUM_ESCS];
@@ -67,6 +70,7 @@
     fork
       process_alert_fifo();
       process_esc_fifo();
+      check_crashdump();
       check_intr_timeout_trigger_esc();
       esc_phase_signal_cnter();
       release_esc_signal();
@@ -388,6 +392,50 @@
     end
   endtask
 
+  virtual task check_crashdump();
+    forever begin
+      wait (cfg.under_reset == 0 && cfg.en_scb == 1);
+      @(cfg.crashdump_vif.pins) begin
+        alert_pkg::alert_crashdump_t crashdump_val =
+            alert_pkg::alert_crashdump_t'(cfg.crashdump_vif.sample());
+
+        // If crashdump reached the phase programmed at `crashdump_trigger_shadowed`, `crashdump_o`
+        // value should keep stable until reset.
+        if (crashdump_triggered) begin
+          `uvm_fatal(`gfn, "crashdump value should not change after trigger condition is reached!")
+        end
+
+        // Wait two negedge clock cycles to make sure csr mirrored values are updated.
+        `DV_SPINWAIT_EXIT(cfg.clk_rst_vif.wait_n_clks(2);, wait (cfg.under_reset == 1);)
+
+        if (!cfg.under_reset) begin
+          foreach (crashdump_val.class_esc_state[i]) begin
+            uvm_reg crashdump_trigger_csr = ral.get_reg_by_name(
+                    $sformatf("class%0s_crashdump_trigger_shadowed", class_name[i]));
+            if (crashdump_val.class_esc_state[i] == (`gmv(crashdump_trigger_csr) + 3'b100)) begin
+              crashdump_triggered = 1;
+              break;
+             end
+          end
+
+          for (int i = 0; i < NUM_ALERTS; i++) begin
+            `DV_CHECK_EQ(crashdump_val.alert_cause[i], `gmv(ral.alert_cause[i]))
+          end
+          for (int i = 0; i < NUM_LOCAL_ALERTS; i++) begin
+            `DV_CHECK_EQ(crashdump_val.loc_alert_cause[i], `gmv(ral.loc_alert_cause[i]))
+          end
+          for (int i = 0; i < NUM_ALERT_CLASSES; i++) begin
+            // TODO: check the remaining field of crashdump without using cycle accurate model.
+            if (state_per_class[i] != 0) begin
+              `DV_CHECK_GT(crashdump_val.class_accum_cnt, 0)
+              `DV_CHECK_GT(crashdump_val.class_esc_cnt, 0)
+            end
+          end
+        end
+      end
+    end
+  endtask
+
   // a counter to count how long each interrupt pins stay high until it is being reset
   // if counter exceeds threshold, call predict_esc() function to calculate related esc
   virtual task check_intr_timeout_trigger_esc();
@@ -509,6 +557,7 @@
     accum_cnter_per_class = '{default:0};
     state_per_class       = '{default:EscStateIdle};
     clr_esc_under_intr    = 0;
+    crashdump_triggered   = 0;
     last_triggered_alert_per_class = '{default:$realtime};
   endfunction
 
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 1634e02..184ff07 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
@@ -8,6 +8,7 @@
   files_dv:
     depend:
       - lowrisc:dv:cip_lib
+      - lowrisc:ip:alert_handler_component # import alert_pkg
     files:
       - alert_handler_env_pkg.sv
       - alert_handler_env_cfg.sv: {is_include_file: true}
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 f2e51bc..8b2ea7d 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
@@ -40,6 +40,9 @@
 
   string class_name[] = {"a", "b", "c", "d"};
   bit [TL_DW-1:0] intr_state_val;
+
+  bit crashdump_triggered = 0;
+
   // TLM agent fifos
   uvm_tlm_analysis_fifo #(alert_esc_seq_item) alert_fifo[NUM_ALERTS];
   uvm_tlm_analysis_fifo #(alert_esc_seq_item) esc_fifo[NUM_ESCS];
@@ -67,6 +70,7 @@
     fork
       process_alert_fifo();
       process_esc_fifo();
+      check_crashdump();
       check_intr_timeout_trigger_esc();
       esc_phase_signal_cnter();
       release_esc_signal();
@@ -388,6 +392,50 @@
     end
   endtask
 
+  virtual task check_crashdump();
+    forever begin
+      wait (cfg.under_reset == 0 && cfg.en_scb == 1);
+      @(cfg.crashdump_vif.pins) begin
+        alert_pkg::alert_crashdump_t crashdump_val =
+            alert_pkg::alert_crashdump_t'(cfg.crashdump_vif.sample());
+
+        // If crashdump reached the phase programmed at `crashdump_trigger_shadowed`, `crashdump_o`
+        // value should keep stable until reset.
+        if (crashdump_triggered) begin
+          `uvm_fatal(`gfn, "crashdump value should not change after trigger condition is reached!")
+        end
+
+        // Wait two negedge clock cycles to make sure csr mirrored values are updated.
+        `DV_SPINWAIT_EXIT(cfg.clk_rst_vif.wait_n_clks(2);, wait (cfg.under_reset == 1);)
+
+        if (!cfg.under_reset) begin
+          foreach (crashdump_val.class_esc_state[i]) begin
+            uvm_reg crashdump_trigger_csr = ral.get_reg_by_name(
+                    $sformatf("class%0s_crashdump_trigger_shadowed", class_name[i]));
+            if (crashdump_val.class_esc_state[i] == (`gmv(crashdump_trigger_csr) + 3'b100)) begin
+              crashdump_triggered = 1;
+              break;
+             end
+          end
+
+          for (int i = 0; i < NUM_ALERTS; i++) begin
+            `DV_CHECK_EQ(crashdump_val.alert_cause[i], `gmv(ral.alert_cause[i]))
+          end
+          for (int i = 0; i < NUM_LOCAL_ALERTS; i++) begin
+            `DV_CHECK_EQ(crashdump_val.loc_alert_cause[i], `gmv(ral.loc_alert_cause[i]))
+          end
+          for (int i = 0; i < NUM_ALERT_CLASSES; i++) begin
+            // TODO: check the remaining field of crashdump without using cycle accurate model.
+            if (state_per_class[i] != 0) begin
+              `DV_CHECK_GT(crashdump_val.class_accum_cnt, 0)
+              `DV_CHECK_GT(crashdump_val.class_esc_cnt, 0)
+            end
+          end
+        end
+      end
+    end
+  endtask
+
   // a counter to count how long each interrupt pins stay high until it is being reset
   // if counter exceeds threshold, call predict_esc() function to calculate related esc
   virtual task check_intr_timeout_trigger_esc();
@@ -509,6 +557,7 @@
     accum_cnter_per_class = '{default:0};
     state_per_class       = '{default:EscStateIdle};
     clr_esc_under_intr    = 0;
+    crashdump_triggered   = 0;
     last_triggered_alert_per_class = '{default:$realtime};
   endfunction