[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