[otbn] Add a "reset" vseq that resets in the middle of operations

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 f5bec69..68b98a0 100644
--- a/hw/ip/otbn/data/otbn_testplan.hjson
+++ b/hw/ip/otbn/data/otbn_testplan.hjson
@@ -54,7 +54,7 @@
 
             '''
       milestone: V2
-      tests: []
+      tests: ["otbn_reset"]
     }
     {
       name: mem_integrity
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_env.core b/hw/ip/otbn/dv/uvm/env/otbn_env.core
index 9b147c2..af06087 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_env.core
+++ b/hw/ip/otbn/dv/uvm/env/otbn_env.core
@@ -32,6 +32,7 @@
       - seq_lib/otbn_base_vseq.sv: {is_include_file: true}
       - seq_lib/otbn_common_vseq.sv: {is_include_file: true}
       - seq_lib/otbn_multi_vseq.sv: {is_include_file: true}
+      - seq_lib/otbn_reset_vseq.sv: {is_include_file: true}
       - seq_lib/otbn_single_vseq.sv: {is_include_file: true}
       - seq_lib/otbn_smoke_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
diff --git a/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_reset_vseq.sv b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_reset_vseq.sv
new file mode 100644
index 0000000..ac5bbc9
--- /dev/null
+++ b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_reset_vseq.sv
@@ -0,0 +1,63 @@
+// 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 multiple times, resetting in the middle of runs
+
+class otbn_reset_vseq extends otbn_base_vseq;
+  `uvm_object_utils(otbn_reset_vseq)
+
+  int unsigned num_iters = 10;
+
+  `uvm_object_new
+
+  task body();
+    int max_cycles;
+    string elf_path;
+
+    elf_path = pick_elf_path();
+    `uvm_info(`gfn, $sformatf("Loading OTBN binary from `%0s'", elf_path), UVM_LOW)
+    load_elf(elf_path, 1'b1);
+
+    max_cycles = 1000;
+    for (int i = 0; i < num_iters; i++) begin
+      int cycle_counter;
+      int reset_wait;
+      bit timed_out = 1'b0;
+
+      // Guess the number of cycles until reset. The first time around, we pick any number between 1
+      // and 1,000. After that, we replace "1,000" with "75% of the longest we've seen the sequence
+      // run before terminating". This should avoid problems where we keep resetting after the
+      // sequence has finished.
+      reset_wait = $urandom_range(max_cycles * 3 / 4) + 1;
+
+      fork
+        run_otbn();
+        begin
+          repeat (reset_wait) begin
+            @(cfg.clk_rst_vif.cb);
+            cycle_counter++;
+          end
+          timed_out = 1'b1;
+        end
+      join_any
+
+      // When we get here, we know that either the OTBN sequence finished (in which case timed_out =
+      // 1'b0) or we timed out. If the OTBN sequence finished, kill the counter process. We don't
+      // kill the run_otbn task: it will spot a reset and terminate on its own.
+      if (!timed_out) begin
+        // If the OTBN sequence finished, update max_cycles. cycle_counter should always be less
+        // than max_cycles (because of how we calculate reset_wait).
+        `DV_CHECK_FATAL(cycle_counter < max_cycles);
+        max_cycles = cycle_counter;
+        disable fork;
+      end
+
+      // If this isn't the last iteration, or if we timed out, reset the DUT
+      if (timed_out || i + 1 < num_iters) begin
+        dut_init("HARD");
+      end
+    end
+  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 5320855..b063f20 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
@@ -5,5 +5,6 @@
 `include "otbn_base_vseq.sv"
 `include "otbn_common_vseq.sv"
 `include "otbn_multi_vseq.sv"
+`include "otbn_reset_vseq.sv"
 `include "otbn_single_vseq.sv"
 `include "otbn_smoke_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 669da52..8b6b07a 100644
--- a/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
+++ b/hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson
@@ -140,7 +140,12 @@
       reseed: 5
     }
 
-    // TODO: add more tests here
+    {
+      name: "otbn_reset"
+      uvm_test_seq: "otbn_reset_vseq"
+      en_run_modes: ["build_otbn_rig_binary_mode"]
+      reseed: 5
+    }
   ]
 
   // List of regressions.