[dv/rstmgr] Test rst_cpu_i input

This input affects reset recording functionality.
Introduce a controllable responder that automatically sets
rst_cpu_n input in response to resets_o.rst_sys_n.
Disable this responder to check the capture functionality
controlled by rst_cpu_n.

Signed-off-by: Guillermo Maturana <maturana@google.com>
diff --git a/hw/ip/rstmgr/data/rstmgr_testplan.hjson b/hw/ip/rstmgr/data/rstmgr_testplan.hjson
index 039c974..a0ed6d5 100644
--- a/hw/ip/rstmgr/data/rstmgr_testplan.hjson
+++ b/hw/ip/rstmgr/data/rstmgr_testplan.hjson
@@ -20,6 +20,7 @@
             Checks the behavior of rstmgr when receiving various reset requests.
 
             **Stimulus**:
+            - Send a scan reset.
             - Send a low power entry reset.
             - Send a peripheral reset request.
             - Send a debug reset.
@@ -158,6 +159,23 @@
       tests: ["rstmgr_reset"]
     }
     {
+      name: reset_info_capture
+      desc: '''Test the capture blocking effect of rst_cpu_n input.
+
+            After an AON reset reset capture is blocked until the input
+            rst_cpu_n goes inactive.
+
+            **Stimulus**:
+            - Wait for a random number of resets before setting rst_cpu_n
+              inactive.
+
+            **Checks**:
+            - Non-AON resets prior to this event don't capture.
+            '''
+      milestone: V2
+      tests: ["rstmgr_reset"]
+    }
+    {
       name: stress_all
       desc: '''This runs random tests sequentially.
 
diff --git a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv
index 60ff998..4d1bc54 100644
--- a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv
+++ b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv
@@ -30,10 +30,28 @@
   // Some extra cycles from reset going inactive before the CPU's reset goes inactive.
   localparam int CPU_RESET_CLK_CYCLES = 10;
 
-  rand logic                                sw_reset;
-  rand logic                                scan_reset;
-  rand logic                                low_power_reset;
-  rand logic                                ndm_reset;
+  // The different types of reset.
+  typedef enum int {
+    ResetPOR,
+    ResetScan,
+    ResetLowPower,
+    ResetNdm,
+    ResetSw,
+    ResetHw
+  } reset_e;
+
+  typedef struct {
+    int code;
+    logic enable;
+    logic update;
+  } reset_expectations_t;
+
+  typedef struct {
+    string description;
+    reset_expectations_t expects;
+  } reset_test_info_t;
+
+  rand reset_e                              which_reset;
 
   rand sw_rst_t                             sw_rst_regwen;
   rand sw_rst_t                             sw_rst_ctrl_n;
@@ -63,11 +81,68 @@
   rand int sys_to_cpu_rst_active_cycles;
   constraint sys_to_cpu_rst_active_cycles_c {sys_to_cpu_rst_active_cycles inside {[0 : 4]};}
 
+  rand int sys_to_cpu_rst_inactive_cycles;
+  constraint sys_to_cpu_rst_inactive_cycles_c {sys_to_cpu_rst_inactive_cycles inside {[0 : 4]};}
+
   // various knobs to enable certain routines
-  bit     do_rstmgr_init     = 1'b1;
+  bit do_rstmgr_init = 1'b1;
+  bit responders_running = 0;
+  static bit enable_cpu_to_sys_rst_release_response = 1'b1;
 
   mubi4_t scanmode;
-  int     scanmode_on_weight = 8;
+  int scanmode_on_weight = 8;
+
+  // What to expect when testing resets.
+  reset_test_info_t reset_test_infos[reset_e] = '{
+    ResetPOR: '{
+      description: "POR reset",
+      expects: '{
+        code: 1,
+        enable: 1'b0,
+        update: 1'b0
+      }
+    },
+    ResetScan: '{
+      description: "scan reset",
+      expects: '{
+        code: 1,
+        enable: 1'b0,
+        update: 1'b0
+      }
+    },
+    ResetLowPower: '{
+      description: "low power reset",
+      expects: '{
+        code: 2,
+        enable: 1'b1,
+        update: 1'b1
+      }
+    },
+    ResetNdm: '{
+      description: "ndm reset",
+      expects: '{
+        code: 4,
+        enable: 1'b1,
+        update: 1'b1
+      }
+    },
+    ResetSw: '{
+      description: "software reset",
+      expects: '{
+        code: 8,
+        enable: 1'b0,
+        update: 1'b1
+      }
+    },
+    ResetHw: '{
+      description: "hardware reset",
+      expects: '{
+        code: 16,
+        enable: 1'b0,
+        update: 1'b1
+      }
+    }
+  };
 
   `uvm_object_new
 
@@ -102,6 +177,10 @@
     cfg.rstmgr_vif.cpu_i.ndmreset_req = value;
   endfunction
 
+  function logic get_rst_cpu_n();
+    return cfg.rstmgr_vif.cpu_i.rst_cpu_n;
+  endfunction
+
   function void set_rst_cpu_n(logic value);
     `uvm_info(`gfn, $sformatf("Setting rst_cpu_n=%b", value), UVM_MEDIUM)
     cfg.rstmgr_vif.cpu_i.rst_cpu_n = value;
@@ -291,6 +370,7 @@
     update_scanmode(prim_mubi_pkg::MuBi4False);
     update_scan_rst_n(1'b1);
     reset_done();
+
     // This makes sure the clock has restarted before this returns.
     cfg.io_div4_clk_rst_vif.wait_clks(1);
     `uvm_info(`gfn, "Done sending scan reset.", UVM_MEDIUM)
@@ -341,7 +421,7 @@
     join
   endtask
 
-  local task por_reset();
+  virtual protected task por_reset();
     `uvm_info(`gfn, "Starting POR", UVM_MEDIUM)
     start_clocks();
     cfg.rstmgr_vif.por_n = '0;
@@ -353,33 +433,20 @@
     `DV_SPINWAIT_EXIT(wait (cfg.rstmgr_vif.resets_o.rst_sys_n[1] == 1'b1);,
                       cfg.clk_rst_vif.wait_clks(CPU_RESET_CLK_CYCLES);,
                       "timeout waiting for cpu reset inactive")
-    cfg.clk_rst_vif.wait_clks(sys_to_cpu_rst_active_cycles);
-    set_rst_cpu_n(1);
-  endtask
-
-  // This waits till the outgoing reset for the CPU goes inactive. It also waits at least one
-  // aon cycle to make sure we don't drop por_n_i before SVA has time to detect the por_aon
-  // reset went inactive.
-  local task wait_for_cpu_out_of_reset();
-    `DV_SPINWAIT_EXIT(wait (cfg.rstmgr_vif.resets_o.rst_sys_n[1] == 1'b1);,
-                      cfg.clk_rst_vif.wait_clks(CPU_RESET_CLK_CYCLES);,
-                      "timeout waiting for cpu reset inactive")
-    cfg.aon_clk_rst_vif.wait_clks(1);
+    if (!responders_running) begin
+      `uvm_info(`gfn, "Responders not running, release cpu reset", UVM_MEDIUM)
+      cfg.clk_rst_vif.wait_clks(sys_to_cpu_rst_active_cycles);
+      set_rst_cpu_n(1);
+    end
   endtask
 
   virtual task apply_reset(string kind = "HARD");
     fork
       por_reset();
-      start_clocks();
       super.apply_reset(kind);
     join
   endtask
 
-  task post_apply_reset(string reset_kind = "HARD");
-    super.post_apply_reset(reset_kind);
-    wait_for_cpu_out_of_reset();
-  endtask
-
   virtual task apply_resets_concurrently(int reset_duration_ps = 0);
     fork
       por_reset();
@@ -388,6 +455,42 @@
     join
   endtask
 
+  virtual protected task responders();
+    fork
+      forever
+        @(negedge cfg.rstmgr_vif.resets_o.rst_sys_n[1]) begin
+          cfg.clk_rst_vif.wait_clks(sys_to_cpu_rst_active_cycles);
+          set_rst_cpu_n(0);
+        end
+      forever
+        @cfg.clk_rst_vif.cb begin
+          if (enable_cpu_to_sys_rst_release_response && cfg.rstmgr_vif.resets_o.rst_sys_n[1] &&
+              !get_rst_cpu_n()) begin
+            `uvm_info(`gfn, "release responder activated", UVM_MEDIUM)
+            cfg.clk_rst_vif.wait_clks(sys_to_cpu_rst_active_cycles);
+            set_rst_cpu_n(1);
+          end
+        end
+    join_none
+  endtask : responders
+
+  local task start_responders();
+    fork : isolation_fork
+      fork
+        `uvm_info(`gfn, "Starting responders", UVM_MEDIUM)
+        responders();
+      join
+    join
+    responders_running = 1;
+  endtask
+
+  task pre_start();
+    if (do_rstmgr_init) rstmgr_init();
+    super.pre_start();
+    start_responders();
+    `uvm_info(`gfn, "Started responders", UVM_MEDIUM)
+  endtask
+
   // setup basic rstmgr features
   virtual task rstmgr_init();
     cfg.aon_clk_rst_vif.set_freq_mhz(AON_FREQ_MHZ);
@@ -403,7 +506,7 @@
     set_rstreqs('0);
     set_reset_cause(pwrmgr_pkg::ResetNone);
     set_ndmreset_req('0);
-    set_rst_cpu_n('1);
+    set_rst_cpu_n('0);
   endtask
 
 endclass : rstmgr_base_vseq
diff --git a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_reset_vseq.sv b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_reset_vseq.sv
index b05d99f..ddab302 100644
--- a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_reset_vseq.sv
+++ b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_reset_vseq.sv
@@ -3,6 +3,17 @@
 // SPDX-License-Identifier: Apache-2.0
 
 // Tests the reset_info CSR settings for random resets.
+// Notice as far as rstmgr once POR or scan reset are asserted, they have
+// identical side-effects for rstmgr.
+//
+// Each run releases rst_cpu_n a few cycles after a scan reset. This requires
+// the responder to be disabled from automatically deactivating rst_cpu_n after
+// rst_sys_src_n goes inactive.
+//
+// It is simpler to manipulate the responder once running so we cause a scan
+// reset after disabling it, and before the other resets. This tests that resets
+// other than scan don't update the reset_info CSR, and don't capture cpu or
+// alert dumps.
 class rstmgr_reset_vseq extends rstmgr_base_vseq;
   `uvm_object_utils(rstmgr_reset_vseq)
 
@@ -11,54 +22,45 @@
   rand logic enable_alert_info;
   rand logic enable_cpu_info;
 
-  constraint sw_reset_c {
-    sw_reset dist {
-      1 := 1,
-      0 := 3
-    };
-  }
-  constraint scan_reset_c {
-    solve sw_reset before scan_reset;
-    if (sw_reset == 0) {
-      scan_reset dist {
-        1 := 1,
-        0 := 3
-      };
-    } else {
-      scan_reset == 0;
-    }
-  }
-  constraint low_power_reset_c {
-    solve scan_reset before low_power_reset;
-    if (scan_reset == 0) {
-      low_power_reset dist {
-        1 := 1,
-        0 := 3
-      };
-    } else {
-      low_power_reset == 0;
-    }
-  }
-  constraint ndm_reset_c {
-    solve low_power_reset before ndm_reset;
-    if (low_power_reset == 0) {
-      ndm_reset dist {
-        1 := 1,
-        0 := 3
-      };
-    } else {
-      ndm_reset == 0;
-    }
-  }
-  constraint rstreqs_c {
-    solve ndm_reset before rstreqs;
-    if (ndm_reset == 0) {rstreqs != '0;} else {rstreqs == '0;}
+  rand int   wait_for_release_response_update_cycles;
+  constraint wait_for_release_response_update_cycles_c {
+    wait_for_release_response_update_cycles inside {[4 : 12]};
   }
 
+  rand int rand_trans_before_enabling_cpu_rst_response;
+  constraint rand_trans_before_enabling_cpu_rst_response_c {
+    rand_trans_before_enabling_cpu_rst_response >= 0;
+    rand_trans_before_enabling_cpu_rst_response < 4;
+  }
+
+  rand reset_e start_reset;
+  constraint start_reset_c {start_reset inside {ResetPOR, ResetScan};}
+
+  local task update_cpu_to_sys_rst_release_response(bit enable);
+    enable_cpu_to_sys_rst_release_response = enable;
+    `uvm_info(`gfn, $sformatf("%0sabling sys_rst_responder", enable ? "En" : "Dis"), UVM_MEDIUM)
+    // Wait a small number of cycles for this to take effect.
+    // If wait too little capture may be unpredictable.
+    cfg.clk_rst_vif.wait_clks(wait_for_release_response_update_cycles);
+  endtask
+
+  // Disable automatic deassertion of rst_cpu_n when running standalone,
+  // in order to test info capture.
+  task pre_start();
+    super.pre_start();
+    `uvm_info(`gfn, "In pre_start", UVM_MEDIUM)
+    update_cpu_to_sys_rst_release_response(.enable(0));
+  endtask
+
   task body();
-    int expected_reset_info;
+    reset_test_info_t reset_test_info;
+    int expected_reset_info_code;
+    logic expected_alert_enable;
+    logic expected_cpu_enable;
     alert_pkg::alert_crashdump_t prev_alert_dump = '0;
     ibex_pkg::crash_dump_t prev_cpu_dump = '0;
+    int trans_before_enabling_cpu_rst_response;
+    bit capture = 0;
 
     // Expect reset info to be POR when running the sequence standalone.
     if (is_running_sequence("rstmgr_reset_vseq")) begin
@@ -66,76 +68,100 @@
       check_alert_and_cpu_info_after_reset(.alert_dump('0), .cpu_dump('0), .enable(1'b0));
     end
 
+    `DV_CHECK_RANDOMIZE_FATAL(this)
+
+    // Run with cpu_rst_response disabled for a few cycles to make sure no capture happens
+    // until rst_cpu_n is inactive.
+    trans_before_enabling_cpu_rst_response = rand_trans_before_enabling_cpu_rst_response;
+    `uvm_info(`gfn, $sformatf(
+              "Will wait for %0d resets before enabling rst_cpu_n response",
+              trans_before_enabling_cpu_rst_response
+              ), UVM_MEDIUM)
+
     // Clear reset_info register, and enable cpu and alert info capture.
+    set_alert_info_for_capture(alert_dump, enable_alert_info);
+    set_cpu_info_for_capture(cpu_dump, enable_cpu_info);
     csr_wr(.ptr(ral.reset_info), .value('1));
 
-    for (int i = 0; i < num_trans; ++i) begin
-      logic  [TL_DW-1:0] value;
-      string             reset_type;
-      logic              expected_info_enable;
-      logic              expected_info_update;
+    // We need to start with an AON reset to process non-capturing resets.
+    if (start_reset == ResetPOR) por_reset();
+    else if (start_reset == ResetScan) send_scan_reset();
 
-      `uvm_info(`gfn, "Starting new round", UVM_MEDIUM)
+    reset_test_info = reset_test_infos[start_reset];
+    cfg.clk_rst_vif.wait_clks(8);
+    // Wait till rst_lc_n is inactive for non-aon.
+    wait(cfg.rstmgr_vif.resets_o.rst_lc_n[1]);
+
+    check_reset_info(reset_test_info.expects.code, reset_test_info.description);
+    check_alert_info_after_reset('0, 0);
+    check_cpu_info_after_reset('0, 0);
+
+    for (int i = 0; i < num_trans; ++i) begin
+      `uvm_info(`gfn, $sformatf("Starting new round %0d", i), UVM_MEDIUM)
       `DV_CHECK_RANDOMIZE_FATAL(this)
       set_alert_info_for_capture(alert_dump, enable_alert_info);
       set_cpu_info_for_capture(cpu_dump, enable_cpu_info);
       csr_wr(.ptr(ral.reset_info), .value('1));
+      reset_test_info = reset_test_infos[which_reset];
 
-      if (scan_reset) begin
-        // This resets the info registers, which means the previous info contents become zero.
-        expected_reset_info = 1;
-        expected_info_enable = 0;
-        expected_info_update = 0;
-        prev_alert_dump = '0;
-        prev_cpu_dump = '0;
-        send_scan_reset();
-        reset_type = "scan reset POR";
-      end else if (low_power_reset) begin
-        expected_reset_info  = 2;
-        expected_info_enable = 1;
-        expected_info_update = 1;
-        send_reset(pwrmgr_pkg::LowPwrEntry, 0);
-        reset_type = "low power reset";
-      end else if (ndm_reset) begin
-        expected_reset_info  = 4;
-        expected_info_enable = 1;
-        expected_info_update = 1;
-        send_ndm_reset();
-        reset_type = "ndm reset";
-      end else if (sw_reset) begin
-        expected_reset_info  = 8;
-        expected_info_enable = 0;
-        expected_info_update = 1;
-        send_sw_reset();
-        reset_type = "sw reset reset";
-      end else if (rstreqs) begin
-        expected_reset_info  = {'0, rstreqs, 4'b0};
-        expected_info_enable = 0;
-        expected_info_update = 1;
-        send_reset(pwrmgr_pkg::HwReq, rstreqs);
-        reset_type = "hw reset";
+      if (i == trans_before_enabling_cpu_rst_response) begin
+        update_cpu_to_sys_rst_release_response(.enable(1));
+        capture = 1;
       end
+      expected_reset_info_code = reset_test_info.expects.code;
+      expected_alert_enable = enable_alert_info && (!capture || reset_test_info.expects.enable);
+      expected_cpu_enable = enable_cpu_info && (!capture || reset_test_info.expects.enable);
+
+      case (which_reset)
+        ResetPOR, ResetScan: begin
+          // This resets the info registers, which means the previous info contents become zero.
+          prev_alert_dump = '0;
+          prev_cpu_dump = '0;
+          expected_alert_enable = 0;
+          expected_cpu_enable = 0;
+          if (which_reset == ResetPOR) por_reset();
+          else if (which_reset == ResetScan) send_scan_reset();
+        end
+        ResetLowPower: send_reset(pwrmgr_pkg::LowPwrEntry, 0);
+        ResetNdm: send_ndm_reset();
+        ResetSw: send_sw_reset();
+        ResetHw: begin
+          expected_reset_info_code = {'0, rstreqs, 4'b0};
+          send_reset(pwrmgr_pkg::HwReq, rstreqs);
+        end
+        default: `uvm_fatal(`gfn, $sformatf("Unexpected reset type %0d", which_reset))
+      endcase
 
       cfg.clk_rst_vif.wait_clks(8);
-      wait(cfg.rstmgr_vif.resets_o.rst_lc_n);
-      check_reset_info(expected_reset_info, reset_type);
-
-      if (expected_info_update && enable_alert_info) begin
-        check_alert_info_after_reset(alert_dump, enable_alert_info && expected_info_enable);
-        prev_alert_dump = alert_dump;
+      wait(cfg.rstmgr_vif.resets_o.rst_lc_n[1]);
+      if (!capture) begin
+        `uvm_info(`gfn, $sformatf("In no capture %0d", i), UVM_MEDIUM)
+        check_reset_info(which_reset inside {ResetPOR, ResetScan} ? expected_reset_info_code : 0,
+                         reset_test_info.description);
+        check_alert_info_after_reset(.alert_dump('0), .enable(expected_alert_enable));
+        check_cpu_info_after_reset(.cpu_dump('0), .enable(expected_cpu_enable));
       end else begin
-        check_alert_info_after_reset(prev_alert_dump, enable_alert_info && expected_info_enable);
-      end
+        `uvm_info(`gfn, $sformatf("In capture %0d", i), UVM_MEDIUM)
+        check_reset_info(expected_reset_info_code, reset_test_info.description);
 
-      if (expected_info_update && enable_cpu_info) begin
-        check_cpu_info_after_reset(cpu_dump, enable_cpu_info && expected_info_enable);
-        prev_cpu_dump = cpu_dump;
-      end else begin
-        check_cpu_info_after_reset(prev_cpu_dump, enable_cpu_info && expected_info_enable);
+        if (reset_test_info.expects.update && enable_alert_info) begin
+          check_alert_info_after_reset(alert_dump, expected_alert_enable);
+          prev_alert_dump = alert_dump;
+        end else begin
+          check_alert_info_after_reset(prev_alert_dump, expected_alert_enable);
+        end
+
+        if (reset_test_info.expects.update && enable_cpu_info) begin
+          check_cpu_info_after_reset(cpu_dump, expected_cpu_enable);
+          prev_cpu_dump = cpu_dump;
+        end else begin
+          check_cpu_info_after_reset(prev_cpu_dump, expected_cpu_enable);
+        end
       end
     end
     csr_wr(.ptr(ral.reset_info), .value('1));
     // This clears the info registers to cancel side-effects into other sequences with stress tests.
+    update_cpu_to_sys_rst_release_response(.enable(1));
     clear_alert_and_cpu_info();
   endtask