[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