[dv/pwrmgr] Add test with both wakeups and resets Fix handling of some reset related random variables. Add coverage sampling for reset in sleep state. Signed-off-by: Guillermo Maturana <maturana@google.com>
diff --git a/hw/ip/pwrmgr/data/pwrmgr_testplan.hjson b/hw/ip/pwrmgr/data/pwrmgr_testplan.hjson index 39d3f7b..8193f82 100644 --- a/hw/ip/pwrmgr/data/pwrmgr_testplan.hjson +++ b/hw/ip/pwrmgr/data/pwrmgr_testplan.hjson
@@ -190,14 +190,16 @@ **Stimulus**: - Trigger reset and wakeup from low power as described for other testpoints. - - Make sure to test them coinciding also. + - Issue reset and wakeup a random number of cycles after the slow + state machine is in LowPower state. + - This also checks them coinciding. **Check**: - Similar tests as for the wakeup and reset testpoints, except making sure they happen per the triggering order. ''' milestone: V2 - tests: [] + tests: ["pwrmgr_wakeup_reset"] } { name: lowpower_wakeup_race
diff --git a/hw/ip/pwrmgr/dv/env/pwrmgr_env.core b/hw/ip/pwrmgr/dv/env/pwrmgr_env.core index 75dcf25..1dd1ccc 100644 --- a/hw/ip/pwrmgr/dv/env/pwrmgr_env.core +++ b/hw/ip/pwrmgr/dv/env/pwrmgr_env.core
@@ -24,6 +24,7 @@ - seq_lib/pwrmgr_lowpower_wakeup_race_vseq.sv: {is_include_file: true} - seq_lib/pwrmgr_reset_vseq.sv: {is_include_file: true} - seq_lib/pwrmgr_smoke_vseq.sv: {is_include_file: true} + - seq_lib/pwrmgr_wakeup_reset_vseq.sv: {is_include_file: true} - seq_lib/pwrmgr_wakeup_vseq.sv: {is_include_file: true} file_type: systemVerilogSource
diff --git a/hw/ip/pwrmgr/dv/env/pwrmgr_if.sv b/hw/ip/pwrmgr/dv/env/pwrmgr_if.sv index fd7679c..dd38449 100644 --- a/hw/ip/pwrmgr/dv/env/pwrmgr_if.sv +++ b/hw/ip/pwrmgr/dv/env/pwrmgr_if.sv
@@ -190,6 +190,7 @@ pwr_cpu = pwrmgr_pkg::PWR_CPU_DEFAULT; wakeups_i = pwrmgr_pkg::WAKEUPS_DEFAULT; rstreqs_i = pwrmgr_pkg::RSTREQS_DEFAULT; + sw_rst_req_i = prim_mubi_pkg::MuBi4False; rom_ctrl = rom_ctrl_pkg::PWRMGR_DATA_DEFAULT; esc_rst_tx = prim_esc_pkg::ESC_TX_DEFAULT; end
diff --git a/hw/ip/pwrmgr/dv/env/pwrmgr_scoreboard.sv b/hw/ip/pwrmgr/dv/env/pwrmgr_scoreboard.sv index 0fc8189..eb2d377 100644 --- a/hw/ip/pwrmgr/dv/env/pwrmgr_scoreboard.sv +++ b/hw/ip/pwrmgr/dv/env/pwrmgr_scoreboard.sv
@@ -87,6 +87,16 @@ .sw_rst(cfg.pwrmgr_vif.sw_rst_req_i == prim_mubi_pkg::MuBi4True), .sleep(1'b0)); end end + forever + @(posedge cfg.pwrmgr_vif.slow_state == pwrmgr_pkg::SlowPwrStateLowPower) begin + if (cfg.en_cov) begin + cov.reset_cg.sample( + .hw_resets(cfg.pwrmgr_vif.rstreqs_i), .hw_resets_en(cfg.pwrmgr_vif.reset_en), + .esc_rst(cfg.pwrmgr_vif.pwr_rst_req.rstreqs[pwrmgr_pkg::ResetEscIdx]), + .main_pwr_rst(cfg.pwrmgr_vif.pwr_rst_req.rstreqs[pwrmgr_pkg::ResetMainPwrIdx]), + .sw_rst(cfg.pwrmgr_vif.sw_rst_req_i == prim_mubi_pkg::MuBi4True), .sleep(1'b1)); + end + end endtask virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name);
diff --git a/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_base_vseq.sv b/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_base_vseq.sv index 0e1f1fe..a90c9f0 100644 --- a/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_base_vseq.sv +++ b/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_base_vseq.sv
@@ -25,6 +25,15 @@ rand wakeups_t wakeups_en; rand resets_t resets; rand resets_t resets_en; + rand bit power_glitch_reset; + rand bit escalation_reset; + + // TODO(maturana) Enable escalation resets once there is support for driving them. + constraint escalation_reset_c {escalation_reset == 1'b0;} + constraint resets_en_c { + solve resets, power_glitch_reset, escalation_reset before resets_en; + |{resets_en & resets, power_glitch_reset, escalation_reset} == 1'b1; + } rand bit disable_wakeup_capture; @@ -77,6 +86,9 @@ } constraint cycles_before_main_pok_c {cycles_before_main_pok inside {[2 : MaxCyclesBeforeEnable]};} + // This is used to trigger a software reset, as per rstmgr's `reset_req` CSR. + prim_mubi_pkg::mubi4_t sw_rst_from_rstmgr = prim_mubi_pkg::MuBi4False; + bit do_pwrmgr_init = 1'b1; // This static variable is incremented in each pre_start and decremented in each post_start. // It is used to start and stop the responders when the parent sequence starts and ends.
diff --git a/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_reset_vseq.sv b/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_reset_vseq.sv index f3baa33..e140dc2 100644 --- a/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_reset_vseq.sv +++ b/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_reset_vseq.sv
@@ -12,21 +12,9 @@ `uvm_object_new - rand bit power_glitch_reset; - rand bit escalation_reset; - - // TODO(maturana) Enable escalation resets once there is support for driving them. - constraint escalation_reset_c {escalation_reset == 1'b0;} - constraint resets_en_c { - solve resets, power_glitch_reset, escalation_reset before resets_en; - |{resets_en & resets, power_glitch_reset, escalation_reset} == 1'b1; - } - constraint wakeups_c {wakeups == 0;} constraint wakeups_en_c {wakeups_en == 0;} - prim_mubi_pkg::mubi4_t sw_rst_from_rstmgr; - function void post_randomize(); sw_rst_from_rstmgr = get_rand_mubi4_val(8, 4, 4); super.post_randomize(); @@ -43,10 +31,11 @@ `DV_CHECK_RANDOMIZE_FATAL(this) enabled_resets = resets_en & resets; `uvm_info(`gfn, $sformatf( - "Enabled resets=0x%x, power_reset=%b, escalation=%b", + "Enabled resets=0x%x, power_reset=%b, escalation=%b, sw_reset=%b", enabled_resets, power_glitch_reset, - escalation_reset + escalation_reset, + sw_rst_from_rstmgr ), UVM_MEDIUM) csr_wr(.ptr(ral.reset_en[0]), .value(resets_en));
diff --git a/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_vseq_list.sv b/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_vseq_list.sv index 3b7476a..28b4211 100644 --- a/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_vseq_list.sv +++ b/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_vseq_list.sv
@@ -7,5 +7,6 @@ `include "pwrmgr_lowpower_wakeup_race_vseq.sv" `include "pwrmgr_reset_vseq.sv" `include "pwrmgr_smoke_vseq.sv" +`include "pwrmgr_wakeup_reset_vseq.sv" `include "pwrmgr_wakeup_vseq.sv" `include "pwrmgr_common_vseq.sv"
diff --git a/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_wakeup_reset_vseq.sv b/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_wakeup_reset_vseq.sv new file mode 100644 index 0000000..81cf49f --- /dev/null +++ b/hw/ip/pwrmgr/dv/env/seq_lib/pwrmgr_wakeup_reset_vseq.sv
@@ -0,0 +1,112 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// The wakeup_reset test randomly enables wakeups and resets, info capture, and interrupts, +// and sends wakeups and resets in close temporal proximity at random times. +class pwrmgr_wakeup_reset_vseq extends pwrmgr_base_vseq; + `uvm_object_utils(pwrmgr_wakeup_reset_vseq) + + `uvm_object_new + + constraint wakeups_c {wakeups != 0;} + + constraint wakeup_en_c { + solve wakeups before wakeups_en; + |(wakeups_en & wakeups) == 1'b1; + } + constraint disable_wakeup_capture_c {disable_wakeup_capture == 1'b0;} + + task body(); + logic [TL_DW-1:0] value; + resets_t enabled_resets; + wakeups_t enabled_wakeups; + + cfg.slow_clk_rst_vif.wait_for_reset(.wait_negedge(0)); + csr_rd_check(.ptr(ral.reset_status[0]), .compare_value(0)); + csr_rd_check(.ptr(ral.wake_status[0]), .compare_value(0)); + for (int i = 0; i < num_trans; ++i) begin + `uvm_info(`gfn, "Starting new round", UVM_MEDIUM) + `DV_CHECK_RANDOMIZE_FATAL(this) + // Enable resets. + enabled_resets = resets_en & resets; + `uvm_info(`gfn, $sformatf( + "Enabled resets=0x%x, power_reset=%b, escalation=%b, sw_reset=%b", + enabled_resets, + power_glitch_reset, + escalation_reset, + sw_rst_from_rstmgr + ), UVM_MEDIUM) + csr_wr(.ptr(ral.reset_en[0]), .value(resets_en)); + + // Enable wakeups. + enabled_wakeups = wakeups_en & wakeups; + `DV_CHECK(enabled_wakeups, $sformatf( + "Some wakeup must be enabled: wkups=%b, wkup_en=%b", wakeups, wakeups_en)) + `uvm_info(`gfn, $sformatf("Enabled wakeups=0x%x", enabled_wakeups), UVM_MEDIUM) + csr_wr(.ptr(ral.wakeup_en[0]), .value(wakeups_en)); + + clear_wake_info(); + + `uvm_info(`gfn, $sformatf("%0sabling wakeup capture", disable_wakeup_capture ? "Dis" : "En"), + UVM_MEDIUM) + csr_wr(.ptr(ral.wake_info_capture_dis), .value(disable_wakeup_capture)); + + update_control_enables(1'b1); + + wait_for_csr_to_propagate_to_slow_domain(); + + // Initiate low power transition. + cfg.pwrmgr_vif.update_cpu_sleeping(1'b1); + set_nvms_idle(); + + // Wait for the slow state machine to be in low power. + wait (cfg.pwrmgr_vif.slow_state == pwrmgr_pkg::SlowPwrStateLowPower); + + // This will send the wakeup and reset so they almost coincide. + fork + begin + cfg.clk_rst_vif.wait_clks(cycles_before_reset); + cfg.pwrmgr_vif.update_resets(resets); + cfg.pwrmgr_vif.update_sw_rst_req(sw_rst_from_rstmgr); + end + begin + cfg.clk_rst_vif.wait_clks(cycles_before_wakeup); + cfg.pwrmgr_vif.update_wakeups(wakeups); + end + join + + // Check wake_status prior to wakeup, or the unit requesting wakeup will have been reset. + // This read will not work in the chip, since the processor will be asleep. + cfg.slow_clk_rst_vif.wait_clks(4); + csr_rd_check(.ptr(ral.wake_status[0]), .compare_value(enabled_wakeups), + .err_msg("failed wake_status check")); + `uvm_info(`gfn, $sformatf("Got wake_status=0x%x", enabled_wakeups), UVM_MEDIUM) + csr_rd_check(.ptr(ral.reset_status[0]), .compare_value(enabled_resets), + .err_msg("failed reset_status check")); + wait(cfg.pwrmgr_vif.pwr_clk_req.main_ip_clk_en == 1'b1); + + wait_for_fast_fsm_active(); + + csr_rd_check(.ptr(ral.reset_status[0]), .compare_value(0), + .err_msg("failed reset_status check")); + + check_wake_info(.reasons(enabled_wakeups), .prior_reasons(1'b0), .fall_through(1'b0), + .prior_fall_through(1'b0), .abort(1'b0), + .prior_abort(1'b0)); + + // This is the expected side-effect of the low power entry reset, since the source of the + // non-aon wakeup sources will deassert it as a consequence of their reset. + // Some aon wakeups may remain active until software clears them. If they didn't, such wakeups + // will remain active, preventing the device from going to sleep. + cfg.pwrmgr_vif.update_wakeups('0); + cfg.slow_clk_rst_vif.wait_clks(10); + csr_rd_check(.ptr(ral.reset_status[0]), .compare_value('0)); + csr_rd_check(.ptr(ral.wake_status[0]), .compare_value('0)); + + // Wait for interrupt to be generated whether or not it is enabled. + cfg.slow_clk_rst_vif.wait_clks(10); + end + endtask + +endclass : pwrmgr_wakeup_reset_vseq
diff --git a/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson b/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson index 6e27b50..b51d969 100644 --- a/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson +++ b/hw/ip/pwrmgr/dv/pwrmgr_sim_cfg.hjson
@@ -75,6 +75,11 @@ run_opts: ["+test_timeout_ns=1000000"] } { + name: pwrmgr_wakeup_reset + uvm_test_seq: pwrmgr_wakeup_reset_vseq + run_opts: ["+test_timeout_ns=1000000"] + } + { name: pwrmgr_aborted_low_power uvm_test_seq: pwrmgr_aborted_low_power_vseq }