[otbn,dv] Add a sequence that drives the lc_escalate_en_i input

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/data/otbn_testplan.hjson b/hw/ip/otbn/data/otbn_testplan.hjson
index 2e672ee..1884e8c 100644
--- a/hw/ip/otbn/data/otbn_testplan.hjson
+++ b/hw/ip/otbn/data/otbn_testplan.hjson
@@ -119,7 +119,7 @@
             Trigger the life cycle escalation input.
             '''
       milestone: V2
-      tests: []
+      tests: ["otbn_escalate"]
     }
   ]
 }
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_env.core b/hw/ip/otbn/dv/uvm/env/otbn_env.core
index 039ad68..53e1a9f 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_env.core
+++ b/hw/ip/otbn/dv/uvm/env/otbn_env.core
@@ -44,6 +44,7 @@
       - seq_lib/otbn_single_vseq.sv: {is_include_file: true}
       - seq_lib/otbn_smoke_vseq.sv: {is_include_file: true}
       - seq_lib/otbn_stress_all_vseq.sv: {is_include_file: true}
+      - seq_lib/otbn_escalate_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
 generate:
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_escalate_if.sv b/hw/ip/otbn/dv/uvm/env/otbn_escalate_if.sv
index fc26dba..dc7fc06 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_escalate_if.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_escalate_if.sv
@@ -11,4 +11,19 @@
 
   lc_ctrl_pkg::lc_tx_t enable;
 
+  function automatic void reset_signals();
+    enable = lc_ctrl_pkg::Off;
+  endfunction
+
+  task automatic set_after_n_clocks(int unsigned n);
+    `DV_SPINWAIT_EXIT(
+      begin
+        repeat (n) @(posedge clk_i);
+        enable = lc_ctrl_pkg::On;
+      end,
+      @(negedge rst_ni);,
+      "Not setting enable signal because we've gone into reset",
+      "otbn_escalate_if")
+  endtask
+
 endinterface
diff --git a/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_base_vseq.sv b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_base_vseq.sv
index 71af972..99513b8 100644
--- a/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_base_vseq.sv
+++ b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_base_vseq.sv
@@ -38,7 +38,7 @@
   // Overridden from dv_base_vseq
   task dut_init(string reset_kind = "HARD");
     // Always drive the lifecycle escalation signal to off at the start of the sequence.
-    cfg.escalate_vif.enable = lc_ctrl_pkg::Off;
+    cfg.escalate_vif.reset_signals();
 
     super.dut_init(reset_kind);
   endtask
diff --git a/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_escalate_vseq.sv b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_escalate_vseq.sv
new file mode 100644
index 0000000..d2388a5
--- /dev/null
+++ b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_escalate_vseq.sv
@@ -0,0 +1,76 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// A sequence that runs a program, asserting the lc_escalate_en_i at some point during the run.
+// Occasionally, it will assert just before or just after.
+
+class otbn_escalate_vseq extends otbn_base_vseq;
+  `uvm_object_utils(otbn_escalate_vseq)
+
+  `uvm_object_new
+
+  task body();
+    string       elf_path;
+    int unsigned bda_idx;
+    bit          go_before, go_during, go_after;
+
+    elf_path = pick_elf_path();
+    `uvm_info(`gfn, $sformatf("Loading OTBN binary from `%0s'", elf_path), UVM_LOW)
+
+    // Pick whether we're going before (5%), during (90%), or after (5%).
+    bda_idx = $urandom_range(100);
+    go_before = bda_idx < 5;
+    go_during = 5 <= bda_idx && bda_idx < 95;
+    go_after = 95 <= bda_idx;
+
+    fork
+      load_elf(elf_path, .backdoor(1'b0));
+      if (go_before) send_escalation_signal(100);
+    join
+
+    if (go_before) begin
+      // At this point, we've sent our escalation signal already. Wait for the fatal alert to
+      // trigger and then return.
+      wait_alert_and_reset();
+      return;
+    end
+
+    if (go_after) begin
+      // We want to send the escalation signal after OTBN is finished. Run an operation, send the
+      // signal, then wait for the fatal alert.
+      run_otbn();
+      send_escalation_signal(10);
+      wait_alert_and_reset();
+      return;
+    end
+
+    // This is the interesting case. Start OTBN running. When this task returns, we'll be in the
+    // middle of a run.
+    start_running_otbn(.check_end_addr(1'b0));
+
+    // Send an escalation signal immediately (the randomisation about where we should strike has
+    // already been done inside start_running_otbn())
+    send_escalation_signal(1);
+
+    // Wait for an alert to come out before returning
+    wait_alert_and_reset();
+  endtask
+
+  // Wait between zero and max_cycles clock cycles and then set the escalation signal to enabled.
+  // Return immediately if we go into reset.
+  task send_escalation_signal(int unsigned max_cycles);
+    cfg.escalate_vif.set_after_n_clocks($urandom_range(max_cycles));
+  endtask
+
+  // Wait for a fatal alert to come out and retrigger at least once. Then reset the DUT. This is
+  // needed at the end of the sequence because otherwise the monitor that sees the re-triggering
+  // fatal alert will stop the test from ever finishing.
+  task wait_alert_and_reset();
+    repeat (2) wait_alert_trigger("fatal", .wait_complete(1));
+
+    do_apply_reset = 1'b1;
+    dut_init("HARD");
+  endtask
+
+endclass
diff --git a/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_vseq_list.sv b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_vseq_list.sv
index cc1ed50..ccefedc 100644
--- a/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_vseq_list.sv
+++ b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_vseq_list.sv
@@ -12,3 +12,4 @@
 `include "otbn_imem_err_vseq.sv"
 `include "otbn_dmem_err_vseq.sv"
 `include "otbn_stress_all_vseq.sv"
+`include "otbn_escalate_vseq.sv"
diff --git a/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson b/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
index 02380ce..c4ee920 100644
--- a/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
+++ b/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
@@ -197,6 +197,13 @@
     }
 
     {
+      name: "otbn_escalate"
+      uvm_test_seq: "otbn_escalate_vseq"
+      en_run_modes: ["build_otbn_rig_binary_mode"]
+      reseed: 5
+    }
+
+    {
       name: "otbn_stress_all"
       uvm_test_seq: "otbn_stress_all_vseq"
       en_run_modes: ["build_otbn_rig_binaries_mode"]