[dv/rstmgr] Create dv collateral

Use uvmdvgen.py to create files needed for dv.
Modify them as needed to get CSR tests passing.

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
new file mode 100644
index 0000000..2145659
--- /dev/null
+++ b/hw/ip/rstmgr/data/rstmgr_testplan.hjson
@@ -0,0 +1,39 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+  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: [
+    {
+      name: smoke
+      desc: '''
+            Smoke test accessing a major datapath within the rstmgr.
+
+            **Stimulus**:
+            - TBD
+
+            **Checks**:
+            - TBD
+            '''
+      milestone: V1
+      tests: ["rstmgr_smoke"]
+    }
+    {
+      name: feature1
+      desc: '''Add more test entries here like above.'''
+      milestone: V1
+      tests: []
+    }
+  ]
+
+  covergroups: [
+    {
+      name: rstmgr_feature_cg
+      desc: '''Describe the functionality covered by this covergroup.'''
+    }
+  ]
+}
diff --git a/hw/ip/rstmgr/doc/dv/index.md b/hw/ip/rstmgr/doc/dv/index.md
new file mode 100644
index 0000000..f0d7ba2
--- /dev/null
+++ b/hw/ip/rstmgr/doc/dv/index.md
@@ -0,0 +1,123 @@
+---
+title: "RSTMGR DV document"
+---
+
+<!-- Copy this file to hw/ip/rstmgr/doc/dv/index.md and make changes as needed.
+For convenience 'rstmgr' in the document can be searched and replaced easily with the
+desired IP (with case sensitivity!). Also, use the testbench block diagram
+located at OpenTitan team drive / 'design verification'
+as a starting point and modify it to reflect your rstmgr testbench and save it
+to hw/ip/rstmgr/doc/dv/tb.svg. It should get linked and rendered under the block
+diagram section below. Please update / modify / remove sections below as
+applicable. Once done, remove this comment before making a PR. -->
+
+## Goals
+* **DV**
+  * Verify all RSTMGR IP features by running dynamic simulations with a SV/UVM based testbench
+  * Develop and run all tests based on the [DV plan](#dv-plan) below towards closing code and functional coverage on the IP and all of its sub-modules
+* **FPV**
+  * Verify TileLink device protocol compliance with an SVA based testbench
+
+## Current status
+* [Design & verification stage]({{< relref "hw" >}})
+  * [HW development stages]({{< relref "doc/project/development_stages" >}})
+* [Simulation results](https://reports.opentitan.org/hw/ip/rstmgr/dv/latest/results.html)
+
+## Design features
+For detailed information on RSTMGR design features, please see the [RSTMGR HWIP technical specification]({{< relref "hw/ip/rstmgr/doc" >}}).
+
+## Testbench architecture
+RSTMGR testbench has been constructed based on the [CIP testbench architecture]({{< relref "hw/dv/sv/cip_lib/doc" >}}).
+
+### Block diagram
+![Block diagram](tb.svg)
+
+### 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`.
+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" >}}))
+* Alerts ([`alert_esc_if`]({{< relref "hw/dv/sv/alert_esc_agent/README.md" >}}))
+* Devmode ([`pins_if`]({{< relref "hw/dv/sv/common_ifs" >}}))
+
+### Common DV utility components
+The following utilities provide generic helper tasks and functions to perform activities that are common across the project:
+* [dv_utils_pkg]({{< relref "hw/dv/sv/dv_utils/README.md" >}})
+* [csr_utils_pkg]({{< relref "hw/dv/sv/csr_utils/README.md" >}})
+
+### Compile-time configurations
+[list compile time configurations, if any and what are they used for]
+
+### Global types & methods
+All common types and methods defined at the package level can be found in
+`rstmgr_env_pkg`. Some of them in use are:
+```systemverilog
+[list a few parameters, types & methods; no need to mention all]
+```
+### TL_agent
+The RSTMGR testbench instantiates (already handled in CIP base env) [tl_agent]({{< relref "hw/dv/sv/tl_agent/README.md" >}}).
+This provides the ability to drive and independently monitor random traffic via the TL host interface into the RSTMGR device.
+
+### Alert_agents
+RSTMGR testbench instantiates (already handled in CIP base env) [alert_agents]({{< relref "hw/dv/sv/alert_esc_agent/README.md" >}}):
+[list alert names].
+The alert_agents provide the ability to drive and independently monitor alert handshakes via alert interfaces in RSTMGR device.
+
+### UVC/agent 1
+[Describe here or add link to its README]
+
+### UVC/agent 2
+[Describe here or add link to its README]
+
+### UVM RAL Model
+The RSTMGR RAL model is created with the [`ralgen`]({{< relref "hw/dv/tools/ralgen/README.md" >}}) FuseSoC generator script automatically when the simulation is at the build stage.
+
+It can be created manually by invoking [`regtool`]({{< relref "util/reggen/README.md" >}}):
+
+### Reference models
+[Describe reference models in use if applicable, example: SHA256/HMAC]
+
+### Stimulus strategy
+#### 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 2:
+
+#### 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:
+* cg1:
+* cg2:
+
+### Self-checking strategy
+#### Scoreboard
+The `rstmgr_scoreboard` is primarily used for end to end checking.
+It creates the following analysis ports to retrieve the data monitored by corresponding interface agents:
+* analysis port1:
+* analysis port2:
+<!-- explain inputs monitored, flow of data and outputs checked -->
+
+#### Assertions
+* TLUL assertions: The `tb/rstmgr_bind.sv` file binds the `tlul_assert` [assertions]({{< relref "hw/ip/tlul/doc/TlulProtocolChecker.md" >}}) to the IP to ensure TileLink interface protocol compliance.
+* Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset.
+* assert prop 1:
+* assert prop 2:
+
+## Building and running tests
+We are using our in-house developed [regression tool]({{< relref "hw/dv/tools/README.md" >}}) for building and running our tests and regressions.
+Please take a look at the link for detailed information on the usage, capabilities, features and known issues.
+Here's how to run a smoke test:
+```console
+$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/rstmgr/dv/rstmgr_sim_cfg.hjson -i rstmgr_smoke
+```
+
+## DV plan
+<!-- TODO: uncomment the line below after adding the testplan.
+Please make sure the testplan is added to `/util/build_docs.py`. -->
+{{</* incGenFromIpDesc "hw/ip/rstmgr/data/rstmgr_testplan.hjson" "testplan" */>}}
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_env.core b/hw/ip/rstmgr/dv/env/rstmgr_env.core
new file mode 100644
index 0000000..b4ef080
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/rstmgr_env.core
@@ -0,0 +1,44 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:rstmgr_env:0.1"
+description: "RSTMGR DV UVM environment"
+filesets:
+  files_rtl:
+    depend:
+      - lowrisc:ip:rstmgr
+
+  files_dv:
+    depend:
+      - lowrisc:dv:ralgen
+      - lowrisc:dv:cip_lib
+
+    files:
+      - rstmgr_env_pkg.sv
+      - rstmgr_env_cfg.sv: {is_include_file: true}
+      - rstmgr_env_cov.sv: {is_include_file: true}
+      - rstmgr_virtual_sequencer.sv: {is_include_file: true}
+      - rstmgr_scoreboard.sv: {is_include_file: true}
+      - rstmgr_env.sv: {is_include_file: true}
+      - seq_lib/rstmgr_vseq_list.sv: {is_include_file: true}
+      - seq_lib/rstmgr_base_vseq.sv: {is_include_file: true}
+      - seq_lib/rstmgr_common_vseq.sv: {is_include_file: true}
+      - seq_lib/rstmgr_smoke_vseq.sv: {is_include_file: true}
+      - rstmgr_if.sv
+    file_type: systemVerilogSource
+
+generate:
+  ral:
+    generator: ralgen
+    parameters:
+      name: rstmgr
+      ip_hjson: ../../../../top_earlgrey/ip/rstmgr/data/autogen/rstmgr.hjson
+
+targets:
+  default:
+    filesets:
+      - files_dv
+      - files_rtl
+    generate:
+      - ral
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_env.sv b/hw/ip/rstmgr/dv/env/rstmgr_env.sv
new file mode 100644
index 0000000..e58af5d
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/rstmgr_env.sv
@@ -0,0 +1,57 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class rstmgr_env extends cip_base_env #(
+  .CFG_T              (rstmgr_env_cfg),
+  .COV_T              (rstmgr_env_cov),
+  .VIRTUAL_SEQUENCER_T(rstmgr_virtual_sequencer),
+  .SCOREBOARD_T       (rstmgr_scoreboard)
+);
+  `uvm_component_utils(rstmgr_env)
+
+  `uvm_component_new
+
+  function void build_phase(uvm_phase phase);
+    super.build_phase(phase);
+
+    if (!uvm_config_db#(virtual clk_rst_if)::get(
+            this, "", "aon_clk_rst_vif", cfg.aon_clk_rst_vif
+        )) begin
+      `uvm_fatal(`gfn, "failed to get aon_clk_rst_vif from uvm_config_db")
+    end
+    if (!uvm_config_db#(virtual clk_rst_if)::get(
+            this, "", "io_clk_rst_vif", cfg.io_clk_rst_vif
+        )) begin
+      `uvm_fatal(`gfn, "failed to get io_clk_rst_vif from uvm_config_db")
+    end
+    if (!uvm_config_db#(virtual clk_rst_if)::get(
+            this, "", "io_div2_clk_rst_vif", cfg.io_div2_clk_rst_vif
+        )) begin
+      `uvm_fatal(`gfn, "failed to get io_div2_clk_rst_vif from uvm_config_db")
+    end
+    if (!uvm_config_db#(virtual clk_rst_if)::get(
+            this, "", "io_div4_clk_rst_vif", cfg.io_div4_clk_rst_vif
+        )) begin
+      `uvm_fatal(`gfn, "failed to get io_div4_clk_rst_vif from uvm_config_db")
+    end
+    if (!uvm_config_db#(virtual clk_rst_if)::get(
+            this, "", "main_clk_rst_vif", cfg.main_clk_rst_vif
+        )) begin
+      `uvm_fatal(`gfn, "failed to get main_clk_rst_vif from uvm_config_db")
+    end
+    if (!uvm_config_db#(virtual clk_rst_if)::get(
+            this, "", "usb_clk_rst_vif", cfg.usb_clk_rst_vif
+        )) begin
+      `uvm_fatal(`gfn, "failed to get usb_clk_rst_vif from uvm_config_db")
+    end
+    if (!uvm_config_db#(virtual rstmgr_if)::get(this, "", "rstmgr_vif", cfg.rstmgr_vif)) begin
+      `uvm_fatal(`gfn, "failed to get rstmgr_vif from uvm_config_db")
+    end
+  endfunction
+
+  function void connect_phase(uvm_phase phase);
+    super.connect_phase(phase);
+  endfunction
+
+endclass
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_env_cfg.sv b/hw/ip/rstmgr/dv/env/rstmgr_env_cfg.sv
new file mode 100644
index 0000000..8b45c2f
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/rstmgr_env_cfg.sv
@@ -0,0 +1,29 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class rstmgr_env_cfg extends cip_base_env_cfg #(
+  .RAL_T(rstmgr_reg_block)
+);
+
+  // ext component cfgs
+
+  `uvm_object_utils_begin(rstmgr_env_cfg)
+  `uvm_object_utils_end
+
+  `uvm_object_new
+
+  virtual rstmgr_if  rstmgr_vif;
+  virtual clk_rst_if aon_clk_rst_vif;
+  virtual clk_rst_if io_clk_rst_vif;
+  virtual clk_rst_if io_div2_clk_rst_vif;
+  virtual clk_rst_if io_div4_clk_rst_vif;
+  virtual clk_rst_if main_clk_rst_vif;
+  virtual clk_rst_if usb_clk_rst_vif;
+
+  virtual function void initialize(bit [31:0] csr_base_addr = '1);
+    list_of_alerts = rstmgr_env_pkg::LIST_OF_ALERTS;
+    super.initialize(csr_base_addr);
+  endfunction
+
+endclass
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_env_cov.sv b/hw/ip/rstmgr/dv/env/rstmgr_env_cov.sv
new file mode 100644
index 0000000..d415634
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/rstmgr_env_cov.sv
@@ -0,0 +1,34 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * Covergoups that are dependent on run-time parameters that may be available
+ * only in build_phase can be defined here
+ * Covergroups may also be wrapped inside helper classes if needed.
+ */
+
+class rstmgr_env_cov extends cip_base_env_cov #(
+  .CFG_T(rstmgr_env_cfg)
+);
+  `uvm_component_utils(rstmgr_env_cov)
+
+  // the base class provides the following handles for use:
+  // rstmgr_env_cfg: cfg
+
+  // covergroups
+  // [add covergroups here]
+
+  function new(string name, uvm_component parent);
+    super.new(name, parent);
+    // [instantiate covergroups here]
+  endfunction : new
+
+  virtual function void build_phase(uvm_phase phase);
+    super.build_phase(phase);
+    // [or instantiate covergroups here]
+    // Please instantiate sticky_intr_cov array of objects for all interrupts that are sticky
+    // See cip_base_env_cov for details
+  endfunction
+
+endclass
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_env_pkg.sv b/hw/ip/rstmgr/dv/env/rstmgr_env_pkg.sv
new file mode 100644
index 0000000..b29ea5b
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/rstmgr_env_pkg.sv
@@ -0,0 +1,38 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package rstmgr_env_pkg;
+  // dep packages
+  import uvm_pkg::*;
+  import top_pkg::*;
+  import dv_utils_pkg::*;
+  import dv_lib_pkg::*;
+  import tl_agent_pkg::*;
+  import cip_base_pkg::*;
+  import dv_base_reg_pkg::*;
+  import csr_utils_pkg::*;
+  import rstmgr_ral_pkg::*;
+
+  // macro includes
+  `include "uvm_macros.svh"
+  `include "dv_macros.svh"
+
+  // parameters
+  // TODO: add the names of alerts in order
+  parameter string LIST_OF_ALERTS[] = {"fatal_fault"};
+  parameter uint NUM_ALERTS = 1;
+
+  // types
+
+  // functions
+
+  // package sources
+  `include "rstmgr_env_cfg.sv"
+  `include "rstmgr_env_cov.sv"
+  `include "rstmgr_virtual_sequencer.sv"
+  `include "rstmgr_scoreboard.sv"
+  `include "rstmgr_env.sv"
+  `include "rstmgr_vseq_list.sv"
+
+endpackage
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_if.sv b/hw/ip/rstmgr/dv/env/rstmgr_if.sv
new file mode 100644
index 0000000..87c6b68
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/rstmgr_if.sv
@@ -0,0 +1,36 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// clkmgr interface.
+
+interface rstmgr_if (
+  input logic clk,
+  input logic rst_n
+);
+
+  import rstmgr_env_pkg::*;
+  import rstmgr_pkg::*;
+
+  pwrmgr_pkg::pwr_rst_req_t pwr_i;
+  pwrmgr_pkg::pwr_rst_rsp_t pwr_o;
+
+  // cpu related inputs
+  rstmgr_pkg::rstmgr_cpu_t cpu_i;
+
+  // Interface to alert handler
+  alert_pkg::alert_crashdump_t alert_dump_i;
+
+  // Interface to cpu crash dump
+  ibex_pkg::crash_dump_t cpu_dump_i;
+
+  // dft bypass
+  logic scan_rst_ni;
+
+  lc_ctrl_pkg::lc_tx_t scanmode_i;
+
+  // reset outputs
+  rstmgr_pkg::rstmgr_ast_out_t resets_ast_o;
+  rstmgr_pkg::rstmgr_out_t resets_o;
+
+endinterface
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_scoreboard.sv b/hw/ip/rstmgr/dv/env/rstmgr_scoreboard.sv
new file mode 100644
index 0000000..e8eeaa2
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/rstmgr_scoreboard.sv
@@ -0,0 +1,133 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class rstmgr_scoreboard extends cip_base_scoreboard #(
+  .CFG_T(rstmgr_env_cfg),
+  .RAL_T(rstmgr_reg_block),
+  .COV_T(rstmgr_env_cov)
+);
+  `uvm_component_utils(rstmgr_scoreboard)
+
+  // local variables
+
+  // TLM agent fifos
+
+  // local queues to hold incoming packets pending comparison
+
+  `uvm_component_new
+
+  function void build_phase(uvm_phase phase);
+    super.build_phase(phase);
+    // TODO: remove once support alert checking
+    do_alert_check = 0;
+  endfunction
+
+  function void connect_phase(uvm_phase phase);
+    super.connect_phase(phase);
+  endfunction
+
+  task run_phase(uvm_phase phase);
+    super.run_phase(phase);
+    fork
+    join_none
+  endtask
+
+  virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name);
+    uvm_reg        csr;
+    bit            do_read_check = 1'b1;
+    bit            write = item.is_write();
+    uvm_reg_addr_t csr_addr = ral.get_word_aligned_addr(item.a_addr);
+
+    bit            addr_phase_read = (!write && channel == AddrChannel);
+    bit            addr_phase_write = (write && channel == AddrChannel);
+    bit            data_phase_read = (!write && channel == DataChannel);
+    bit            data_phase_write = (write && channel == DataChannel);
+
+    // if access was to a valid csr, get the csr handle
+    if (csr_addr inside {cfg.ral_models[ral_name].csr_addrs}) begin
+      csr = ral.default_map.get_reg_by_offset(csr_addr);
+      `DV_CHECK_NE_FATAL(csr, null)
+    end else begin
+      `uvm_fatal(`gfn, $sformatf("Access unexpected addr 0x%0h", csr_addr))
+    end
+
+    // if incoming access is a write to a valid csr, then make updates right away
+    if (addr_phase_write) begin
+      void'(csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask)));
+    end
+
+    // process the csr req:
+    // for write, update local variable and fifo at address phase,
+    // for read, update predication at address phase and compare at data phase.
+    // TODO Add support for reading registers with separate write-enable.
+    case (csr.get_name())
+      // add individual case item for each csr
+      "alert_test": begin
+        // Write only.
+        do_read_check = 1'b0;
+      end
+      "reset_info": begin
+        // RW1C.
+        do_read_check = 1'b0;
+      end
+      "alert_regwen": begin
+        // RW0C.
+        // do_read_check = 1'b0;
+      end
+      "alert_info_ctrl": begin
+      end
+      "alert_info_attr": begin
+        // Read only.
+        do_read_check = 1'b0;
+      end
+      "alert_info": begin
+        // Read only.
+        do_read_check = 1'b0;
+      end
+      "cpu_regwen": begin
+        // RW0C.
+        // do_read_check = 1'b0;
+      end
+      "cpu_info_ctrl": begin
+      end
+      "cpu_info_attr": begin
+        // Read only.
+        do_read_check = 1'b0;
+      end
+      "cpu_info": begin
+        // Read only.
+        do_read_check = 1'b0;
+      end
+      "sw_rst_regen": begin
+      end
+      "sw_rst_ctrl_n": begin
+        // TODO Check with bitwise enables from sw_rst_regen.
+        do_read_check = 1'b0;
+      end
+      default: begin
+        `uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
+      end
+    endcase
+
+    // On reads, if do_read_check, is set, then check mirrored_value against item.d_data
+    if (data_phase_read) begin
+      if (do_read_check) begin
+        `DV_CHECK_EQ(csr.get_mirrored_value(), item.d_data, $sformatf(
+                     "reg name: %0s", csr.get_full_name()))
+      end
+      void'(csr.predict(.value(item.d_data), .kind(UVM_PREDICT_READ)));
+    end
+  endtask
+
+  virtual function void reset(string kind = "HARD");
+    super.reset(kind);
+    // reset local fifos queues and variables
+  endfunction
+
+  function void check_phase(uvm_phase phase);
+    super.check_phase(phase);
+    // post test checks - ensure that all local fifos and queues are empty
+  endfunction
+
+endclass
diff --git a/hw/ip/rstmgr/dv/env/rstmgr_virtual_sequencer.sv b/hw/ip/rstmgr/dv/env/rstmgr_virtual_sequencer.sv
new file mode 100644
index 0000000..28875a5
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/rstmgr_virtual_sequencer.sv
@@ -0,0 +1,14 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class rstmgr_virtual_sequencer extends cip_base_virtual_sequencer #(
+  .CFG_T(rstmgr_env_cfg),
+  .COV_T(rstmgr_env_cov)
+);
+  `uvm_component_utils(rstmgr_virtual_sequencer)
+
+
+  `uvm_component_new
+
+endclass
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
new file mode 100644
index 0000000..b6b603b
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_base_vseq.sv
@@ -0,0 +1,179 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class rstmgr_base_vseq extends cip_base_vseq #(
+  .RAL_T              (rstmgr_reg_block),
+  .CFG_T              (rstmgr_env_cfg),
+  .COV_T              (rstmgr_env_cov),
+  .VIRTUAL_SEQUENCER_T(rstmgr_virtual_sequencer)
+);
+  `uvm_object_utils(rstmgr_base_vseq)
+
+  // Set clock frequencies per spec, except the aon is 200kHZ, which is
+  // too slow and could slow testing down for no good reason.
+  localparam int AON_FREQ_MHZ = 3;
+  localparam int IO_FREQ_MHZ = 96;
+  localparam int IO_DIV2_FREQ_MHZ = 48;
+  localparam int IO_DIV4_FREQ_MHZ = 24;
+  localparam int MAIN_FREQ_MHZ = 100;
+  localparam int USB_FREQ_MHZ = 48;
+
+  localparam int RESET_CLK_PERIODS = 5;
+  // This needs to be longer than RESET_CLK_PERIODS times the slowest clock,
+  // which is the AON's.
+  localparam int DELAY_FOR_RESETS_CONCURRENTLY_PS = 5_000_000;
+
+  typedef enum {
+    LcTxTSelOn,
+    LcTxTSelOff,
+    LcTxTSelOther
+  } lc_tx_t_sel_e;
+
+  // This simplifies the constraint blocks.
+  function lc_ctrl_pkg::lc_tx_t get_lc_tx_t_from_sel(lc_tx_t_sel_e sel, lc_ctrl_pkg::lc_tx_t other);
+    case (sel)
+      LcTxTSelOn: return lc_ctrl_pkg::On;
+      LcTxTSelOff: return lc_ctrl_pkg::Off;
+      LcTxTSelOther: return other;
+    endcase
+  endfunction
+
+  rand lc_ctrl_pkg::lc_tx_t scanmode_other;
+  rand lc_tx_t_sel_e        sel_scanmode;
+  int                       scanmode_on_weight = 8;
+
+  constraint scanmode_c {
+    sel_scanmode dist {
+      LcTxTSelOn    := scanmode_on_weight,
+      LcTxTSelOff   := 4,
+      LcTxTSelOther := 4
+    };
+    !(scanmode_other inside {lc_ctrl_pkg::On, lc_ctrl_pkg::Off});
+  }
+
+  pwrmgr_pkg::pwr_rst_req_t pwr_i;
+
+  rand logic scan_rst_ni;
+  constraint scan_rst_ni_c {scan_rst_ni == 1;}
+
+  lc_ctrl_pkg::lc_tx_t scanmode;
+
+  // various knobs to enable certain routines
+  bit do_rstmgr_init = 1'b1;
+
+  `uvm_object_new
+
+  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;
+  endfunction
+
+  function void set_rstreqs(logic [pwrmgr_reg_pkg::NumRstReqs:0] rstreqs);
+    cfg.rstmgr_vif.pwr_i.rstreqs = rstreqs;
+  endfunction
+
+  function void set_reset_cause(pwrmgr_pkg::reset_cause_e reset_cause);
+    cfg.rstmgr_vif.pwr_i.reset_cause = reset_cause;
+  endfunction
+
+  function void set_ndmreset_req(logic value);
+    cfg.rstmgr_vif.cpu_i.ndmreset_req = value;
+  endfunction
+
+  function void set_rst_cpu_n(logic value);
+    cfg.rstmgr_vif.cpu_i.rst_cpu_n = value;
+  endfunction
+
+  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");
+    if (do_rstmgr_init) rstmgr_init();
+    super.dut_init();
+  endtask
+
+  virtual task dut_shutdown();
+    // check for pending rstmgr operations and wait for them to complete
+    // TODO
+  endtask
+
+  task fork_resets();
+    fork
+      cfg.aon_clk_rst_vif.apply_reset(.pre_reset_dly_clks(0), .reset_width_clks(RESET_CLK_PERIODS));
+      cfg.io_clk_rst_vif.apply_reset(.pre_reset_dly_clks(0), .reset_width_clks(RESET_CLK_PERIODS));
+      cfg.io_div2_clk_rst_vif.apply_reset(.pre_reset_dly_clks(0),
+                                          .reset_width_clks(RESET_CLK_PERIODS));
+      cfg.io_div4_clk_rst_vif.apply_reset(.pre_reset_dly_clks(0),
+                                          .reset_width_clks(RESET_CLK_PERIODS));
+      cfg.main_clk_rst_vif.apply_reset(.pre_reset_dly_clks(0),
+                                       .reset_width_clks(RESET_CLK_PERIODS));
+      cfg.usb_clk_rst_vif.apply_reset(.pre_reset_dly_clks(0), .reset_width_clks(RESET_CLK_PERIODS));
+    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);
+  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(
+                 "apply_resets_concurrently delay (%0d) must exceed slowest reset (%0d)",
+                 DELAY_FOR_RESETS_CONCURRENTLY_PS,
+                 freq_mhz_to_ps(
+                     AON_FREQ_MHZ
+                 ) * RESET_CLK_PERIODS
+                 ))
+    fork
+      super.apply_reset(kind);
+      if (kind == "HARD") begin
+        // Apply reset to all clk_rst_if instances so the clocks start, even if
+        // the rst_n output is not connected.
+        fork_resets();
+      end
+    join
+    wait_for_reset_stretcher();
+  endtask
+
+  virtual task apply_resets_concurrently(int reset_duration_ps = 0);
+    cfg.aon_clk_rst_vif.drive_rst_pin(0);
+    cfg.io_clk_rst_vif.drive_rst_pin(0);
+    cfg.io_div2_clk_rst_vif.drive_rst_pin(0);
+    cfg.io_div4_clk_rst_vif.drive_rst_pin(0);
+    cfg.main_clk_rst_vif.drive_rst_pin(0);
+    cfg.usb_clk_rst_vif.drive_rst_pin(0);
+    super.apply_resets_concurrently(DELAY_FOR_RESETS_CONCURRENTLY_PS);
+    cfg.aon_clk_rst_vif.drive_rst_pin(1);
+    cfg.io_clk_rst_vif.drive_rst_pin(1);
+    cfg.io_div2_clk_rst_vif.drive_rst_pin(1);
+    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
+  virtual task rstmgr_init();
+    cfg.aon_clk_rst_vif.set_freq_mhz(AON_FREQ_MHZ);
+    cfg.io_clk_rst_vif.set_freq_mhz(IO_FREQ_MHZ);
+    cfg.io_div2_clk_rst_vif.set_freq_mhz(IO_DIV2_FREQ_MHZ);
+    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);
+  endtask
+
+endclass : rstmgr_base_vseq
diff --git a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_common_vseq.sv b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_common_vseq.sv
new file mode 100644
index 0000000..91c06c0
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_common_vseq.sv
@@ -0,0 +1,15 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class rstmgr_common_vseq extends rstmgr_base_vseq;
+  `uvm_object_utils(rstmgr_common_vseq)
+
+  constraint num_trans_c {num_trans inside {[1 : 2]};}
+  `uvm_object_new
+
+  virtual task body();
+    run_common_vseq_wrapper(num_trans);
+  endtask : body
+
+endclass
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
new file mode 100644
index 0000000..470930d
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_smoke_vseq.sv
@@ -0,0 +1,15 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// smoke test vseq
+class rstmgr_smoke_vseq extends rstmgr_base_vseq;
+  `uvm_object_utils(rstmgr_smoke_vseq)
+
+  `uvm_object_new
+
+  task body();
+    `uvm_error(`gfn, "FIXME")
+  endtask : body
+
+endclass : rstmgr_smoke_vseq
diff --git a/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_vseq_list.sv b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_vseq_list.sv
new file mode 100644
index 0000000..ce18690
--- /dev/null
+++ b/hw/ip/rstmgr/dv/env/seq_lib/rstmgr_vseq_list.sv
@@ -0,0 +1,7 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+`include "rstmgr_base_vseq.sv"
+`include "rstmgr_smoke_vseq.sv"
+`include "rstmgr_common_vseq.sv"
diff --git a/hw/ip/rstmgr/dv/rstmgr_sim.core b/hw/ip/rstmgr/dv/rstmgr_sim.core
new file mode 100644
index 0000000..ceccbd2
--- /dev/null
+++ b/hw/ip/rstmgr/dv/rstmgr_sim.core
@@ -0,0 +1,30 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:rstmgr_sim:0.1"
+description: "RSTMGR DV sim target"
+filesets:
+  files_rtl:
+    depend:
+      - lowrisc:ip:rstmgr
+
+  files_dv:
+    depend:
+      - lowrisc:dv:rstmgr_test
+      - lowrisc:dv:rstmgr_sva
+    files:
+      - tb.sv
+    file_type: systemVerilogSource
+
+targets:
+  sim: &sim_target
+    toplevel: tb
+    filesets:
+      - files_rtl
+      - files_dv
+    default_tool: vcs
+
+  # TODO: add a lint check cfg in `hw/top_earlgrey/lint/top_earlgrey_dv_lint_cfgs.hjson`
+  lint:
+    <<: *sim_target
diff --git a/hw/ip/rstmgr/dv/rstmgr_sim_cfg.hjson b/hw/ip/rstmgr/dv/rstmgr_sim_cfg.hjson
new file mode 100644
index 0000000..3d94750
--- /dev/null
+++ b/hw/ip/rstmgr/dv/rstmgr_sim_cfg.hjson
@@ -0,0 +1,74 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+  // Name of the sim cfg - typically same as the name of the DUT.
+  name: rstmgr
+
+  // Top level dut name (sv module).
+  dut: rstmgr
+
+  // Top level testbench name (sv module).
+  tb: tb
+
+  // Simulator used to sign off this block
+  tool: vcs
+
+  // Fusesoc core file used for building the file list.
+  fusesoc_core: lowrisc:dv:rstmgr_sim:0.1
+
+  // Testplan hjson file.
+  testplan: "{proj_root}/hw/ip/rstmgr/data/rstmgr_testplan.hjson"
+
+  // RAL spec - used to generate the RAL model.
+  ral_spec: "{proj_root}/hw/top_earlgrey/ip/rstmgr/data/autogen/rstmgr.hjson"
+
+  // Import additional common sim cfg files.
+  // TODO: remove imported cfgs that do not apply.
+  import_cfgs: [// Project wide common sim cfg file
+                "{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson",
+                // Common CIP test lists
+                "{proj_root}/hw/dv/tools/dvsim/tests/csr_tests.hjson",
+                "{proj_root}/hw/dv/tools/dvsim/tests/mem_tests.hjson",
+                "{proj_root}/hw/dv/tools/dvsim/tests/alert_test.hjson",
+                "{proj_root}/hw/dv/tools/dvsim/tests/tl_access_tests.hjson",
+                // Disable until the stress_all sequence is created.
+                //"{proj_root}/hw/dv/tools/dvsim/tests/stress_tests.hjson"
+                ]
+
+  // Overrides
+  overrides: [
+    {
+      name: design_level
+      value: "top"
+    }
+  ]
+
+  // Add additional tops for simulation.
+  sim_tops: ["rstmgr_bind"]
+
+  // Default iterations for all tests - each test entry can override this.
+  reseed: 50
+
+  // Default UVM test and seq class name.
+  uvm_test: rstmgr_base_test
+  uvm_test_seq: rstmgr_base_vseq
+
+  // List of test specifications.
+  tests: [
+    {
+      name: rstmgr_smoke
+      uvm_test_seq: rstmgr_smoke_vseq
+    }
+
+    // TODO: add more tests here
+  ]
+
+  // List of regressions.
+  regressions: [
+    {
+      name: smoke
+      tests: ["rstmgr_smoke"]
+    }
+  ]
+}
diff --git a/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv b/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv
new file mode 100644
index 0000000..2e576d2
--- /dev/null
+++ b/hw/ip/rstmgr/dv/sva/rstmgr_bind.sv
@@ -0,0 +1,23 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+module rstmgr_bind;
+
+  bind rstmgr tlul_assert #(
+    .EndpointType("Device")
+  ) 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)
+  );
+
+endmodule
diff --git a/hw/ip/rstmgr/dv/sva/rstmgr_sva.core b/hw/ip/rstmgr/dv/sva/rstmgr_sva.core
new file mode 100644
index 0000000..c2920de
--- /dev/null
+++ b/hw/ip/rstmgr/dv/sva/rstmgr_sva.core
@@ -0,0 +1,37 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:rstmgr_sva:0.1"
+description: "RSTMGR assertion modules and bind file."
+filesets:
+  files_dv:
+    depend:
+      - lowrisc:tlul:headers
+      - lowrisc:fpv:csr_assert_gen
+    files:
+      - rstmgr_bind.sv
+    file_type: systemVerilogSource
+
+  files_formal:
+    depend:
+      - lowrisc:systems:rstmgr
+
+generate:
+  csr_assert_gen:
+    generator: csr_assert_gen
+    parameters:
+      spec: ../../data/rstmgr.hjson
+
+targets:
+  default: &default_target
+    filesets:
+      - files_dv
+    generate:
+      - csr_assert_gen
+  formal:
+    <<: *default_target
+    filesets:
+      - files_formal
+      - files_dv
+    toplevel: rstmgr
diff --git a/hw/ip/rstmgr/dv/tb.sv b/hw/ip/rstmgr/dv/tb.sv
new file mode 100644
index 0000000..bbc2770
--- /dev/null
+++ b/hw/ip/rstmgr/dv/tb.sv
@@ -0,0 +1,115 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+module tb;
+  // dep packages
+  import uvm_pkg::*;
+  import dv_utils_pkg::*;
+  import rstmgr_env_pkg::*;
+  import rstmgr_test_pkg::*;
+
+  // macro includes
+  `include "uvm_macros.svh"
+  `include "dv_macros.svh"
+
+  wire clk, rst_n;
+  wire clk_aon;
+  wire clk_io_div4_i;
+  wire clk_main_i;
+  wire clk_io_i;
+  wire clk_io_div2_i;
+  wire clk_usb_i;
+
+  wire devmode;
+
+  // interfaces
+  clk_rst_if clk_rst_if (
+    .clk  (clk),
+    .rst_n(rst_n)
+  );
+  clk_rst_if aon_clk_rst_if (.clk(clk_aon));
+  clk_rst_if io_clk_rst_if (.clk(clk_io));
+  clk_rst_if io_div2_clk_rst_if (.clk(clk_io_div2));
+  clk_rst_if io_div4_clk_rst_if (.clk(clk_io_div4));
+  clk_rst_if main_clk_rst_if (.clk(clk_main));
+  clk_rst_if usb_clk_rst_if (.clk(clk_usb));
+
+  pins_if #(1) devmode_if (devmode);
+  tl_if tl_if (
+    .clk  (clk),
+    .rst_n(rst_n)
+  );
+
+  rstmgr_if rstmgr_if (
+    .clk  (clk),
+    .rst_n(rst_n)
+  );
+
+  initial begin
+    clk_rst_if.set_active();
+    aon_clk_rst_if.set_active();
+    io_clk_rst_if.set_active();
+    io_div2_clk_rst_if.set_active();
+    io_div4_clk_rst_if.set_active();
+    main_clk_rst_if.set_active();
+    usb_clk_rst_if.set_active();
+  end
+
+  `DV_ALERT_IF_CONNECT
+
+  // dut
+  rstmgr dut (
+    .clk_i        (clk),
+    .rst_ni       (rst_n),
+    .clk_aon_i    (clk_aon),
+    .clk_io_div4_i(clk_io_div4),
+    .clk_main_i   (clk_main),
+    .clk_io_i     (clk_io),
+    .clk_io_div2_i(clk_io_div2),
+    .clk_usb_i    (clk_usb),
+
+    .tl_i      (tl_if.h2d),
+    .tl_o      (tl_if.d2h),
+    .alert_rx_i(alert_rx),
+    .alert_tx_o(alert_tx),
+
+    .pwr_i(rstmgr_if.pwr_i),
+    .pwr_o(rstmgr_if.pwr_o),
+
+    .rst_cpu_n_i(rstmgr_if.cpu_i.rst_cpu_n),
+    .ndmreset_req_i(rstmgr_if.cpu_i.ndmreset_req),
+
+    .alert_dump_i(rstmgr_if.alert_dump_i),
+
+    .cpu_dump_i(rstmgr_if.cpu_dump_i),
+
+    .scan_rst_ni(rstmgr_if.scan_rst_ni),
+    .scanmode_i (rstmgr_if.scanmode_i),
+
+    .resets_ast_o(rstmgr_if.resets_ast_o),
+    .resets_o    (rstmgr_if.resets_o)
+  );
+
+  initial begin
+    // drive clk and rst_n from clk_rst_if
+    clk_rst_if.set_active();
+    uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "clk_rst_vif", clk_rst_if);
+    uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "aon_clk_rst_vif", aon_clk_rst_if);
+    uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "io_clk_rst_vif", io_clk_rst_if);
+    uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "io_div2_clk_rst_vif",
+                                            io_div2_clk_rst_if);
+    uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "io_div4_clk_rst_vif",
+                                            io_div4_clk_rst_if);
+    uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "main_clk_rst_vif", main_clk_rst_if);
+    uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "usb_clk_rst_vif", usb_clk_rst_if);
+    uvm_config_db#(devmode_vif)::set(null, "*.env", "devmode_vif", devmode_if);
+    uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if);
+
+    uvm_config_db#(virtual rstmgr_if)::set(null, "*.env", "rstmgr_vif", rstmgr_if);
+
+    $timeformat(-12, 0, " ps", 12);
+    run_test();
+  end
+
+endmodule
diff --git a/hw/ip/rstmgr/dv/tests/rstmgr_base_test.sv b/hw/ip/rstmgr/dv/tests/rstmgr_base_test.sv
new file mode 100644
index 0000000..d4bf455
--- /dev/null
+++ b/hw/ip/rstmgr/dv/tests/rstmgr_base_test.sv
@@ -0,0 +1,20 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class rstmgr_base_test extends cip_base_test #(
+    .CFG_T(rstmgr_env_cfg),
+    .ENV_T(rstmgr_env)
+  );
+
+  `uvm_component_utils(rstmgr_base_test)
+  `uvm_component_new
+
+  // the base class dv_base_test creates the following instances:
+  // rstmgr_env_cfg: cfg
+  // rstmgr_env:     env
+
+  // the base class also looks up UVM_TEST_SEQ plusarg to create and run that seq in
+  // the run_phase; as such, nothing more needs to be done
+
+endclass : rstmgr_base_test
diff --git a/hw/ip/rstmgr/dv/tests/rstmgr_test.core b/hw/ip/rstmgr/dv/tests/rstmgr_test.core
new file mode 100644
index 0000000..8830baf
--- /dev/null
+++ b/hw/ip/rstmgr/dv/tests/rstmgr_test.core
@@ -0,0 +1,19 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:rstmgr_test:0.1"
+description: "RSTMGR DV UVM test"
+filesets:
+  files_dv:
+    depend:
+      - lowrisc:dv:rstmgr_env
+    files:
+      - rstmgr_test_pkg.sv
+      - rstmgr_base_test.sv: {is_include_file: true}
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_dv
diff --git a/hw/ip/rstmgr/dv/tests/rstmgr_test_pkg.sv b/hw/ip/rstmgr/dv/tests/rstmgr_test_pkg.sv
new file mode 100644
index 0000000..49ca06c
--- /dev/null
+++ b/hw/ip/rstmgr/dv/tests/rstmgr_test_pkg.sv
@@ -0,0 +1,22 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package rstmgr_test_pkg;
+  // dep packages
+  import uvm_pkg::*;
+  import cip_base_pkg::*;
+  import rstmgr_env_pkg::*;
+
+  // macro includes
+  `include "uvm_macros.svh"
+  `include "dv_macros.svh"
+
+  // local types
+
+  // functions
+
+  // package sources
+  `include "rstmgr_base_test.sv"
+
+endpackage
diff --git a/util/build_docs.py b/util/build_docs.py
index c56f40f..c997c74 100755
--- a/util/build_docs.py
+++ b/util/build_docs.py
@@ -120,6 +120,7 @@
         "hw/ip/pwm/data/pwm_testplan.hjson",
         "hw/ip/pwrmgr/data/pwrmgr_testplan.hjson",
         "hw/ip/rom_ctrl/data/rom_ctrl_testplan.hjson",
+        "hw/ip/rstmgr/data/rstmgr_testplan.hjson",
         "hw/ip/rv_plic/data/rv_plic_fpv_testplan.hjson",
         "hw/ip/rv_timer/data/rv_timer_testplan.hjson",
         "hw/ip/spi_device/data/spi_device_testplan.hjson",
@@ -428,8 +429,9 @@
         args += ["server"]
         # --bind-wan only applies when previewing.
         if bind_wan:
-            args += ["--bind", "0.0.0.0", "--baseURL", "http://"+socket.getfqdn()]
-    if hugo_opts != None:
+            args += ["--bind", "0.0.0.0", "--baseURL",
+                     "http://" + socket.getfqdn()]
+    if hugo_opts is not None:
         args += hugo_opts
 
     subprocess.run(args, check=True, cwd=str(SRCTREE_TOP))