[dv/rstmgr] Create smoke test

Create a smoke test checking the response to various reset requests.
Update dv spec and testplan for smoke test.

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 2145659..6739996 100644
--- a/hw/ip/rstmgr/data/rstmgr_testplan.hjson
+++ b/hw/ip/rstmgr/data/rstmgr_testplan.hjson
@@ -5,7 +5,6 @@
   name: "rstmgr"
   import_testplans: ["hw/dv/tools/dvsim/testplans/alert_test_testplan.hjson",
                      "hw/dv/tools/dvsim/testplans/csr_testplan.hjson",
-                     "hw/dv/tools/dvsim/testplans/intr_test_testplan.hjson",
                      "hw/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson"]
   testpoints: [
     {
@@ -13,11 +12,19 @@
       desc: '''
             Smoke test accessing a major datapath within the rstmgr.
 
+            Checks the behavior of rstmgr when receiving various reset requests.
+
             **Stimulus**:
-            - TBD
+            - Send a low power entry reset.
+            - Send a peripheral reset request.
+            - Send a debug reset.
+            - Configure a software request for peripheral reset.
 
             **Checks**:
-            - TBD
+            - Checks the reset_info matches expected values.
+            - Checks the cpu_info CSR correctly captures the input info.
+            - Checks the output reset pins corresponding to sw resettable
+              units match `sw_rst_ctrl_n` CSR.
             '''
       milestone: V1
       tests: ["rstmgr_smoke"]
diff --git a/hw/ip/rstmgr/doc/dv/index.md b/hw/ip/rstmgr/doc/dv/index.md
index f0d7ba2..c9d594a 100644
--- a/hw/ip/rstmgr/doc/dv/index.md
+++ b/hw/ip/rstmgr/doc/dv/index.md
@@ -34,12 +34,11 @@
 
 ### Top level testbench
 The top level testbench is located at `hw/ip/rstmgr/dv/tb.sv`.
-It instantiates the RSTMGR DUT module `hw/ip/rstmgr/rtl/rstmgr.sv`.
+It instantiates the RSTMGR DUT module `hw/top_earlgrey/ip/rstmgr/rtl/autogen/rstmgr.sv`.
 In addition, it instantiates the following interfaces, connects them to the DUT and sets their handle into `uvm_config_db`:
 * [Clock and reset interface]({{< relref "hw/dv/sv/common_ifs" >}})
 * [TileLink host interface]({{< relref "hw/dv/sv/tl_agent/README.md" >}})
-* RSTMGR IOs
-* Interrupts ([`pins_if`]({{< relref "hw/dv/sv/common_ifs" >}}))
+* RSTMGR interface `hw/ip/rstmgr/dv/env/rstmgr_if.sv`
 * Alerts ([`alert_esc_if`]({{< relref "hw/dv/sv/alert_esc_agent/README.md" >}}))
 * Devmode ([`pins_if`]({{< relref "hw/dv/sv/common_ifs" >}}))
 
@@ -81,14 +80,19 @@
 [Describe reference models in use if applicable, example: SHA256/HMAC]
 
 ### Stimulus strategy
+The following test sequences and covergroupsare described in more detail in the testplan at `hw/ip/pwrmgr/data/rstmgr_testplan.hjson`, and also included [below](#dv-plan).
+
 #### Test sequences
 The test sequences reside in `hw/ip/rstmgr/dv/env/seq_lib`.
 All test sequences are extended from `rstmgr_base_vseq`, which is extended from `cip_base_vseq` and serves as a starting point.
 It provides commonly used handles, variables, functions and tasks that the test sequences can simple use / call.
 Some of the most commonly used tasks / functions are as follows:
-* task 1:
+* task `wait_for_cpu_out_of_reset`:
+  Waits for the `resets_o.rst_sys_n[1]` to go high, indicating the CPU is out of reset and CSRs can be accessed.
 * task 2:
 
+The `rstmgr_smoke_vseq` tests the rstmgr through software initiated low power, peripheral reset, ndm reset, and software initiated resets.
+
 #### Functional coverage
 To ensure high quality constrained random stimulus, it is necessary to develop a functional coverage model.
 The following covergroups have been developed to prove that the test intent has been adequately met:
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 b6b603b..95a653c 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
@@ -24,6 +24,10 @@
   // which is the AON's.
   localparam int DELAY_FOR_RESETS_CONCURRENTLY_PS = 5_000_000;
 
+  // This should exceed the clock cycles needed by the reset stretcher, which is normally 32
+  // AON cycles, but can be extended for tests that introduce reset glitches.
+  localparam int RESET_STRETCHER_TIMEOUT_NS = 4_000_000;
+
   typedef enum {
     LcTxTSelOn,
     LcTxTSelOff,
@@ -64,6 +68,10 @@
 
   `uvm_object_new
 
+  local function real freq_mhz_to_period_in_ps(real freq);
+    return 1e12 / (freq * 1_000_000.0);
+  endfunction
+
   function void set_pwrmgr_rst_reqs(logic rst_lc_req, logic rst_sys_req);
     cfg.rstmgr_vif.pwr_i.rst_lc_req  = rst_lc_req;
     cfg.rstmgr_vif.pwr_i.rst_sys_req = rst_sys_req;
@@ -85,15 +93,26 @@
     cfg.rstmgr_vif.cpu_i.rst_cpu_n = value;
   endfunction
 
+  function void set_cpu_dump_info(ibex_pkg::crash_dump_t cpu_dump);
+    cfg.rstmgr_vif.cpu_dump_i = cpu_dump;
+  endfunction
+
+  task check_cpu_dump_info(ibex_pkg::crash_dump_t cpu_dump);
+    csr_wr(.ptr(ral.cpu_info_ctrl.index), .value(3));
+    csr_rd_check(.ptr(ral.cpu_info), .compare_value(cpu_dump.current_pc),
+                 .err_msg("checking current_pc"));
+    csr_wr(.ptr(ral.cpu_info_ctrl.index), .value(2));
+    csr_rd_check(.ptr(ral.cpu_info), .compare_value(cpu_dump.next_pc),
+                 .err_msg("checking next_pc"));
+    csr_wr(.ptr(ral.cpu_info_ctrl.index), .value(1));
+    csr_rd_check(.ptr(ral.cpu_info), .compare_value(cpu_dump.last_data_addr),
+                 .err_msg("checking last_data_addr"));
+    csr_wr(.ptr(ral.cpu_info_ctrl.index), .value(0));
+    csr_rd_check(.ptr(ral.cpu_info), .compare_value(cpu_dump.exception_addr),
+                 .err_msg("checking exception_addr"));
+  endtask
+
   function void post_randomize();
-    // TODO Some of these should go in rstmgr_ or dut_init.
-    cfg.rstmgr_vif.scanmode_i  = lc_ctrl_pkg::Off;
-    cfg.rstmgr_vif.scan_rst_ni = scan_rst_ni;
-    set_pwrmgr_rst_reqs(1'b0, 1'b0);
-    set_rstreqs('0);
-    set_reset_cause(pwrmgr_pkg::ResetNone);
-    set_ndmreset_req('0);
-    set_rst_cpu_n('1);
   endfunction
 
   virtual task dut_init(string reset_kind = "HARD");
@@ -120,21 +139,18 @@
     join
   endtask
 
-  local function real freq_mhz_to_ps(real freq);
-    return 1e12 / (freq * 1_000_000.0);
-  endfunction
-
-  // This adds enough delay to cover the stretched delay, which is around 32 AON cycles.
-  local task wait_for_reset_stretcher();
-    cfg.aon_clk_rst_vif.wait_clks(50);
+  // This waits till the outgoing POR reset for the CPU goes inactive.
+  local task wait_for_cpu_out_of_reset();
+    `DV_SPINWAIT(wait (cfg.rstmgr_vif.resets_o.rst_sys_n[1] == 1'b1);,
+                 "timeout waiting for POR reset to cpu output", RESET_STRETCHER_TIMEOUT_NS)
   endtask
 
   virtual task apply_reset(string kind = "HARD");
-    `DV_CHECK_LT(freq_mhz_to_ps(AON_FREQ_MHZ) * RESET_CLK_PERIODS, DELAY_FOR_RESETS_CONCURRENTLY_PS,
-                 $sformatf(
+    `DV_CHECK_LT(freq_mhz_to_period_in_ps(AON_FREQ_MHZ) * RESET_CLK_PERIODS,
+                 DELAY_FOR_RESETS_CONCURRENTLY_PS, $sformatf(
                  "apply_resets_concurrently delay (%0d) must exceed slowest reset (%0d)",
                  DELAY_FOR_RESETS_CONCURRENTLY_PS,
-                 freq_mhz_to_ps(
+                 freq_mhz_to_period_in_ps(
                      AON_FREQ_MHZ
                  ) * RESET_CLK_PERIODS
                  ))
@@ -146,7 +162,10 @@
         fork_resets();
       end
     join
-    wait_for_reset_stretcher();
+  endtask
+
+  task post_apply_reset(string kind = "HARD");
+    wait_for_cpu_out_of_reset();
   endtask
 
   virtual task apply_resets_concurrently(int reset_duration_ps = 0);
@@ -163,7 +182,6 @@
     cfg.io_div4_clk_rst_vif.drive_rst_pin(1);
     cfg.main_clk_rst_vif.drive_rst_pin(1);
     cfg.usb_clk_rst_vif.drive_rst_pin(1);
-    wait_for_reset_stretcher();
   endtask
 
   // setup basic rstmgr features
@@ -174,6 +192,14 @@
     cfg.io_div4_clk_rst_vif.set_freq_mhz(IO_DIV4_FREQ_MHZ);
     cfg.main_clk_rst_vif.set_freq_mhz(MAIN_FREQ_MHZ);
     cfg.usb_clk_rst_vif.set_freq_mhz(USB_FREQ_MHZ);
+    // Initial values for some input pins.
+    cfg.rstmgr_vif.scanmode_i  = lc_ctrl_pkg::Off;
+    cfg.rstmgr_vif.scan_rst_ni = scan_rst_ni;
+    set_pwrmgr_rst_reqs(1'b0, 1'b0);
+    set_rstreqs('0);
+    set_reset_cause(pwrmgr_pkg::ResetNone);
+    set_ndmreset_req('0);
+    set_rst_cpu_n('1);
   endtask
 
 endclass : rstmgr_base_vseq
diff --git a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_smoke_vseq.sv b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_smoke_vseq.sv
index 470930d..93e3000 100644
--- a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_smoke_vseq.sv
+++ b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_smoke_vseq.sv
@@ -9,7 +9,115 @@
   `uvm_object_new
 
   task body();
-    `uvm_error(`gfn, "FIXME")
+    // The rstmgr is ready for CSR accesses.
+    logic [TL_DW-1:0] value;
+    ibex_pkg::crash_dump_t cpu_dump;
+
+    cpu_dump = '{current_pc: 32'hdead_beef, next_pc: 32'hbeef_dead, last_data_addr: 32'haaaa_aaaa,
+                 exception_addr: 32'h5555_5555};
+    set_cpu_dump_info(cpu_dump);
+
+    // Send a reset for low power exit.
+    // Expect reset info to be POR.
+    csr_rd_check(.ptr(ral.reset_info), .compare_value(32'h1));
+    check_cpu_dump_info('0);
+
+    // Clear reset_info register.
+    csr_wr(.ptr(ral.reset_info), .value('1));
+
+    // Send low power entry reset.
+    set_reset_cause(pwrmgr_pkg::LowPwrEntry);
+    set_pwrmgr_rst_reqs(.rst_lc_req('1), .rst_sys_req('1));
+    set_rstreqs(3'b1);
+    `uvm_info(`gfn, $sformatf("Sending reset for low power"), UVM_LOW)
+    cfg.io_div4_clk_rst_vif.wait_clks(10);
+    csr_rd_check(.ptr(ral.reset_info), .compare_value(32'h2),
+                 .err_msg("Expected reset info to be low power"));
+    // Pwrmgr drops reset requests.
+    `uvm_info(`gfn, $sformatf("Clearing reset for low power"), UVM_LOW)
+    set_reset_cause(pwrmgr_pkg::ResetNone);
+    set_pwrmgr_rst_reqs(.rst_lc_req('0), .rst_sys_req('0));
+
+    // Clear reset_info register.
+    csr_wr(.ptr(ral.reset_info), .value('1));
+    cfg.io_div4_clk_rst_vif.wait_clks(10);
+
+    // Send HwReq.
+    // Enable cpu_info capture.
+    // TODO Also enable alert_info recording and send alert_info.
+    csr_wr(.ptr(ral.cpu_info_ctrl.en), .value(1'b1));
+    cpu_dump = '{current_pc: 32'h0, next_pc: 32'h444, last_data_addr: 32'h888,
+                 exception_addr: 32'hccc};
+    `uvm_info(`gfn, $sformatf("Setting cpu_dump_i to %p", cpu_dump), UVM_LOW)
+    set_cpu_dump_info(cpu_dump);
+
+    set_reset_cause(pwrmgr_pkg::HwReq);
+    set_pwrmgr_rst_reqs(.rst_lc_req('1), .rst_sys_req('1));
+    `uvm_info(`gfn, $sformatf("Sending hw req reset"), UVM_LOW)
+
+    cfg.io_div4_clk_rst_vif.wait_clks(10);
+    csr_rd_check(.ptr(ral.reset_info), .compare_value(32'h8));
+    // Pwrmgr drops reset requests.
+    `uvm_info(`gfn, $sformatf("Clearing hw req reset"), UVM_LOW)
+    set_reset_cause(pwrmgr_pkg::ResetNone);
+    set_pwrmgr_rst_reqs(.rst_lc_req('0), .rst_sys_req('0));
+    check_cpu_dump_info(cpu_dump);
+
+    // Clear reset_info register.
+    csr_wr(.ptr(ral.reset_info), .value('1));
+
+    cpu_dump = '{current_pc: 32'haaaa_cccc, next_pc: 32'hbbbb_8888, last_data_addr: 32'hcccc_4444,
+                 exception_addr: 32'hdddd_0000};
+    `uvm_info(`gfn, $sformatf("Setting cpu_dump_i to %p", cpu_dump), UVM_LOW)
+    set_cpu_dump_info(cpu_dump);
+
+    // Send debug reset.
+    set_ndmreset_req(1'b1);
+    `uvm_info(`gfn, $sformatf("Sending ndm reset"), UVM_LOW)
+    cfg.io_div4_clk_rst_vif.wait_clks(10);
+    csr_rd_check(.ptr(ral.reset_info), .compare_value(32'h4));
+
+    set_ndmreset_req(1'b0);
+    `uvm_info(`gfn, $sformatf("Clearing ndm reset"), UVM_LOW)
+    check_cpu_dump_info(cpu_dump);
+
+    // Clear reset_info register.
+    csr_wr(.ptr(ral.reset_info), .value('1));
+
+    // Testing software resets.
+    begin : sw_rst
+      logic [6:0] regen;
+      logic [6:0] maybe_ctrl_n;
+      logic [6:0] initial_value;
+      logic [6:0] actual_ctrl_n;
+      ibex_pkg::crash_dump_t not_captured_cpu_dump;
+
+      not_captured_cpu_dump = '{current_pc: 'x, next_pc: 'x, last_data_addr: 'x, exception_addr: 'x};
+      set_cpu_dump_info(not_captured_cpu_dump);
+      csr_rd(.ptr(ral.sw_rst_ctrl_n), .value(initial_value));
+      // Send a software reset via CSR writes. Enable 1, 3, 5, and 6.
+      regen = 7'h6a;
+      csr_wr(.ptr(ral.sw_rst_regen), .value(regen));
+      `uvm_info(`gfn, $sformatf("sw_rst_regen set to 0x%0h", regen), UVM_LOW)
+      // And enable reset at bit 1.
+      maybe_ctrl_n = 7'h78;
+      csr_wr(.ptr(ral.sw_rst_ctrl_n), .value(maybe_ctrl_n));
+      `uvm_info(`gfn, $sformatf("sw_rst_ctrl_n set to 0x%0x", maybe_ctrl_n), UVM_LOW)
+      actual_ctrl_n = initial_value & ~regen | maybe_ctrl_n & regen;
+      csr_rd_check(.ptr(ral.sw_rst_ctrl_n), .compare_value(actual_ctrl_n),
+                   .err_msg("actual sw_rst_ctrl_n"));
+
+      // And check that the reset outputs match the actual ctrl_n settings.
+      `DV_CHECK_EQ(cfg.rstmgr_vif.resets_o.rst_spi_device_n[1], actual_ctrl_n[0])
+      `DV_CHECK_EQ(cfg.rstmgr_vif.resets_o.rst_spi_host0_n[1], actual_ctrl_n[1])
+      `DV_CHECK_EQ(cfg.rstmgr_vif.resets_o.rst_spi_host1_n[1], actual_ctrl_n[2])
+      `DV_CHECK_EQ(cfg.rstmgr_vif.resets_o.rst_usb_n[1], actual_ctrl_n[3])
+      `DV_CHECK_EQ(cfg.rstmgr_vif.resets_o.rst_i2c0_n[1], actual_ctrl_n[4])
+      `DV_CHECK_EQ(cfg.rstmgr_vif.resets_o.rst_i2c1_n[1], actual_ctrl_n[5])
+      `DV_CHECK_EQ(cfg.rstmgr_vif.resets_o.rst_i2c2_n[1], actual_ctrl_n[6])
+      check_cpu_dump_info(cpu_dump);
+    end
+    cfg.io_div4_clk_rst_vif.wait_clks(100);
   endtask : body
 
 endclass : rstmgr_smoke_vseq
diff --git a/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv b/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv
index 2e576d2..96c1f23 100644
--- a/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv
+++ b/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv
@@ -6,18 +6,8 @@
 
   bind rstmgr tlul_assert #(
     .EndpointType("Device")
-  ) tlul_assert_device (
-    .clk_i,
-    .rst_ni,
-    .h2d  (tl_i),
-    .d2h  (tl_o)
-  );
+  ) tlul_assert_device (.clk_i, .rst_ni, .h2d(tl_i), .d2h(tl_o));
 
-  bind rstmgr rstmgr_csr_assert_fpv rstmgr_csr_assert (
-    .clk_i,
-    .rst_ni,
-    .h2d    (tl_i),
-    .d2h    (tl_o)
-  );
+  bind rstmgr rstmgr_csr_assert_fpv rstmgr_csr_assert (.clk_i, .rst_ni, .h2d(tl_i), .d2h(tl_o));
 
 endmodule
diff --git a/hw/ip/rstmgr/dv/tests/rstmgr_base_test.sv b/hw/ip/rstmgr/dv/tests/rstmgr_base_test.sv
index d4bf455..736d54c 100644
--- a/hw/ip/rstmgr/dv/tests/rstmgr_base_test.sv
+++ b/hw/ip/rstmgr/dv/tests/rstmgr_base_test.sv
@@ -3,9 +3,9 @@
 // SPDX-License-Identifier: Apache-2.0
 
 class rstmgr_base_test extends cip_base_test #(
-    .CFG_T(rstmgr_env_cfg),
-    .ENV_T(rstmgr_env)
-  );
+  .CFG_T(rstmgr_env_cfg),
+  .ENV_T(rstmgr_env)
+);
 
   `uvm_component_utils(rstmgr_base_test)
   `uvm_component_new