[dv/otp_ctrl] check timeout failure

This PR supports one kind of check failure - the timeout failure.
The timoeut failure is triggered by setting the timeout value to a small
value. The timeout failure will send out a fatal alert and status
timeout error bit will be set.

Signed-off-by: Cindy Chen <chencindy@google.com>
diff --git a/hw/ip/otp_ctrl/data/otp_ctrl_testplan.hjson b/hw/ip/otp_ctrl/data/otp_ctrl_testplan.hjson
index cfbd683..4d3daed 100644
--- a/hw/ip/otp_ctrl/data/otp_ctrl_testplan.hjson
+++ b/hw/ip/otp_ctrl/data/otp_ctrl_testplan.hjson
@@ -69,7 +69,7 @@
             - Check if the error_code register is set correctly
             '''
       milestone: V2
-      tests: []
+      tests: ["otp_ctrl_check_fail"]
     }
     {
       name: regwen_during_otp_init
diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_env.core b/hw/ip/otp_ctrl/dv/env/otp_ctrl_env.core
index c360c00..8c815ab 100644
--- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_env.core
+++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_env.core
@@ -28,6 +28,7 @@
       - seq_lib/otp_ctrl_dai_lock_vseq.sv: {is_include_file: true}
       - seq_lib/otp_ctrl_dai_errs_vseq.sv: {is_include_file: true}
       - seq_lib/otp_ctrl_macro_errs_vseq.sv: {is_include_file: true}
+      - seq_lib/otp_ctrl_check_fail_vseq.sv: {is_include_file: true}
       - seq_lib/otp_ctrl_parallel_base_vseq.sv: {is_include_file: true}
       - seq_lib/otp_ctrl_regwen_vseq.sv: {is_include_file: true}
       - seq_lib/otp_ctrl_parallel_key_req_vseq.sv: {is_include_file: true}
diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_pkg.sv b/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_pkg.sv
index 6580e83..fd55a0e 100644
--- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_pkg.sv
+++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_pkg.sv
@@ -86,6 +86,8 @@
   parameter uint NUM_SRAM_EDN_REQ = 10;
   parameter uint NUM_OTBN_EDN_REQ = 16;
 
+  parameter uint CHK_TIMEOUT_CYC = 40;
+
   // lc does not have digest
   parameter int PART_BASE_ADDRS [NumPart-1] = {
     CreatorSwCfgOffset,
diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
index 3be3eb1..313e92f 100644
--- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
+++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
@@ -547,7 +547,10 @@
           // update status mask
           status_mask = 0;
           // Mask out check_pending field - we do not know how long it takes to process checks.
-          if (under_chk) status_mask[OtpCheckPendingIdx] = 1;
+          // Check failure can trigger all kinds of errors.
+          if (under_chk) status_mask = '1;
+
+          if (!under_chk && `gmv(ral.status.check_pending)) status_mask[OtpTimeoutErrIdx] = 1;
 
           // Mask out otp_dai access related field - we do not know how long it takes to finish
           // DAI access.
@@ -590,6 +593,10 @@
       "check_trigger": begin
         if (addr_phase_write && `gmv(ral.check_trigger_regwen) && item.a_data inside {[1:3]}) begin
           exp_status[OtpCheckPendingIdx] = 1;
+          if (`gmv(ral.check_timeout) > 0 && `gmv(ral.check_timeout) <= CHK_TIMEOUT_CYC) begin
+            set_exp_alert("fatal_check_error", 1, `gmv(ral.check_timeout));
+            predict_status_err(.timeout_err(1));
+          end
         end
       end
       "hw_cfg_digest_0", "hw_cfg_digest_1", "", "secret0_digest_0", "secret0_digest_1",
@@ -858,13 +865,14 @@
                                                                       dai_addr >> 2;
   endfunction
 
-  virtual function void predict_status_err(bit dai_err = 0, bit lc_err = 0);
+  virtual function void predict_status_err(bit dai_err = 0, bit lc_err = 0, bit timeout_err = 0);
     void'(ral.intr_state.otp_error.predict(.value(1), .kind(UVM_PREDICT_READ)));
     if (dai_err) begin
       exp_status[OtpDaiIdleIdx] = 1;
       exp_status[OtpDaiErrIdx]  = 1;
     end
     if (lc_err) exp_status[OtpLciErrIdx] = 1;
+    if (timeout_err) exp_status[OtpTimeoutErrIdx] = 1;
   endfunction
 
   virtual function void predict_dai_idle_status_wo_err();
diff --git a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_check_fail_vseq.sv b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_check_fail_vseq.sv
new file mode 100644
index 0000000..cd9f21f
--- /dev/null
+++ b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_check_fail_vseq.sv
@@ -0,0 +1,18 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This sequence creates the following check failure scenarios:
+// 1. Check timeout
+// 2. TODO: add when support
+class otp_ctrl_check_fail_vseq extends otp_ctrl_dai_errs_vseq;
+  `uvm_object_utils(otp_ctrl_check_fail_vseq)
+
+  `uvm_object_new
+
+  // 50% chance of having a check timeout
+  constraint check_timeout_val_c {
+    check_timeout_val dist {[1 : CHK_TIMEOUT_CYC] :/ 1,
+                            [100_000 :'1]         :/ 1};
+  }
+endclass
diff --git a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_smoke_vseq.sv b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_smoke_vseq.sv
index 717839f..de3cde6 100644
--- a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_smoke_vseq.sv
+++ b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_smoke_vseq.sv
@@ -90,7 +90,9 @@
       // set consistency and integrity checks
       csr_wr(ral.check_regwen, check_regwen_val);
       csr_wr(ral.check_trigger_regwen, check_trigger_regwen_val);
-      csr_wr(ral.check_timeout, check_timeout_val);
+      if (check_trigger_val && `gmv(ral.check_trigger_regwen)) begin
+        csr_wr(ral.check_timeout, check_timeout_val);
+      end
       trigger_checks(.val(check_trigger_val), .wait_done(1));
 
       if (do_req_keys) begin
diff --git a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_vseq_list.sv b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_vseq_list.sv
index 8b685d6..c6e9dd0 100644
--- a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_vseq_list.sv
+++ b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_vseq_list.sv
@@ -10,6 +10,7 @@
 `include "otp_ctrl_dai_lock_vseq.sv"
 `include "otp_ctrl_dai_errs_vseq.sv"
 `include "otp_ctrl_macro_errs_vseq.sv"
+`include "otp_ctrl_check_fail_vseq.sv"
 `include "otp_ctrl_parallel_base_vseq.sv"
 `include "otp_ctrl_parallel_key_req_vseq.sv"
 `include "otp_ctrl_parallel_lc_req_vseq.sv"
diff --git a/hw/ip/otp_ctrl/dv/otp_ctrl_sim_cfg.hjson b/hw/ip/otp_ctrl/dv/otp_ctrl_sim_cfg.hjson
index 7641690..fe6d41e 100644
--- a/hw/ip/otp_ctrl/dv/otp_ctrl_sim_cfg.hjson
+++ b/hw/ip/otp_ctrl/dv/otp_ctrl_sim_cfg.hjson
@@ -81,6 +81,11 @@
     }
 
     {
+      name: otp_ctrl_check_fail
+      uvm_test_seq: otp_ctrl_check_fail_vseq
+    }
+
+    {
       name: otp_ctrl_macro_errs
       uvm_test_seq: otp_ctrl_macro_errs_vseq
     }