[rv_timer DV] Reduce rv_timer smoke test runtime
`rv_timer_smoke` is the longest running test in the private CI<
consuming a whopping 6 minutes of runtime.
In this change, the existing smoke vseq is renamed to random vseq and a
`smoke_test` switch is added to it. If set, it significantly reduces the
scope and runtime of the CI test so that we can continue to stay within
the 20 minute timeout.
The original `rv_timer_smoke` test entry is duplicated to
`rv_timer_random`, with both running the same random vseq. For the smoke
test version, the above plusarg is set to 1 and it is also reseeded only
once, since there is no need to run it multiple times.
This brings the `rv_timer_smoke` test runtime down from 6 minutes to 52
seconds, which will enable us to add more DUTs to the regression list
without blowing the 20 minute timeout.
Signed-off-by: Srikrishna Iyer <sriyer@google.com>
diff --git a/hw/ip/rv_timer/data/rv_timer_testplan.hjson b/hw/ip/rv_timer/data/rv_timer_testplan.hjson
index 256d254..c2a73f1 100644
--- a/hw/ip/rv_timer/data/rv_timer_testplan.hjson
+++ b/hw/ip/rv_timer/data/rv_timer_testplan.hjson
@@ -9,20 +9,20 @@
"hw/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson"]
entries: [
{
- name: smoke
- desc: '''RV_TIMER smoke test performs following steps for number of iterations
+ name: random
+ desc: '''RV_TIMER random test performs following steps for number of iterations
- Program zero to CTRL.active* Register(deactivate timer)
- Program random legal values in CFG*, TIMER_V_*, COMPARE_*, INTR_ENABLE*
- Program one to CTRL.active* (activate timer)
- Wait for number of cycles to have mTime>= mTimeCmp
- Check Interrupt state register and Interrupt signal (scoreboard logic)'''
milestone: V1
- tests: ["rv_timer_smoke"]
+ tests: ["rv_timer_smoke", "rv_timer_random"]
}
{
name: random_reset
desc: '''This test is to exercise on the fly reset(timer is active)
- - Assert reset randomly in the middle of smoke test steps
+ - Assert reset randomly in the middle of random test steps
- Scoreboard check for all register go back to reset value'''
milestone: V2
tests: ["rv_timer_random_reset"]
diff --git a/hw/ip/rv_timer/dv/env/rv_timer_env.core b/hw/ip/rv_timer/dv/env/rv_timer_env.core
index 3e15546..4669628 100644
--- a/hw/ip/rv_timer/dv/env/rv_timer_env.core
+++ b/hw/ip/rv_timer/dv/env/rv_timer_env.core
@@ -18,7 +18,7 @@
- seq_lib/rv_timer_vseq_list.sv: {is_include_file: true}
- seq_lib/rv_timer_base_vseq.sv: {is_include_file: true}
- seq_lib/rv_timer_common_vseq.sv: {is_include_file: true}
- - seq_lib/rv_timer_smoke_vseq.sv: {is_include_file: true}
+ - seq_lib/rv_timer_random_vseq.sv: {is_include_file: true}
- seq_lib/rv_timer_disabled_vseq.sv: {is_include_file: true}
- seq_lib/rv_timer_cfg_update_on_fly_vseq.sv: {is_include_file: true}
- seq_lib/rv_timer_random_reset_vseq.sv: {is_include_file: true}
diff --git a/hw/ip/rv_timer/dv/env/rv_timer_scoreboard.sv b/hw/ip/rv_timer/dv/env/rv_timer_scoreboard.sv
index f36320f..4c72901 100644
--- a/hw/ip/rv_timer/dv/env/rv_timer_scoreboard.sv
+++ b/hw/ip/rv_timer/dv/env/rv_timer_scoreboard.sv
@@ -305,7 +305,7 @@
end
// enabling one clock cycle of ignore period
ignore_period[a_i][a_j] = 1'b1;
- `uvm_info(`gfn, $sformatf("Timer expired check for interrupt"), UVM_LOW)
+ `uvm_info(`gfn, $sformatf("Timer expired check for interrupt"), UVM_MEDIUM)
// Update exp val and predict it in read address_channel
intr_status_exp[a_i][a_j] = 1'b1;
check_interrupt_pin();
diff --git a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_base_vseq.sv b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_base_vseq.sv
index d1f56a4..6584537 100644
--- a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_base_vseq.sv
+++ b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_base_vseq.sv
@@ -23,8 +23,10 @@
}
// hart specific parameters
- bit [TL_DW-1:0] max_prescale;
- bit [TL_DW-1:0] max_step;
+ // These need to be NUM_HARTS size arrays; but the current assumption is these values will be the
+ // same for all harts.
+ bit [TL_DW-1:0] max_prescale;
+ bit [TL_DW-1:0] max_step;
`uvm_object_new
diff --git a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_cfg_update_on_fly_vseq.sv b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_cfg_update_on_fly_vseq.sv
index 59cc220..677b418 100644
--- a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_cfg_update_on_fly_vseq.sv
+++ b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_cfg_update_on_fly_vseq.sv
@@ -7,7 +7,7 @@
// after disabling timer. This seq also exercise upating timer cfg multiple
// times when timer is close to expire (1 prescale before).
-class rv_timer_cfg_update_on_fly_vseq extends rv_timer_smoke_vseq;
+class rv_timer_cfg_update_on_fly_vseq extends rv_timer_random_vseq;
`uvm_object_utils(rv_timer_cfg_update_on_fly_vseq)
`uvm_object_new
diff --git a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_disabled_vseq.sv b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_disabled_vseq.sv
index 486c3c8..2960f56 100644
--- a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_disabled_vseq.sv
+++ b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_disabled_vseq.sv
@@ -5,7 +5,7 @@
// This sequence check no activity on timer register and interrupt when timer
// is disabled
-class rv_timer_disabled_vseq extends rv_timer_smoke_vseq;
+class rv_timer_disabled_vseq extends rv_timer_random_vseq;
`uvm_object_utils(rv_timer_disabled_vseq)
`uvm_object_new
diff --git a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_random_reset_vseq.sv b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_random_reset_vseq.sv
index 44c52da..513c919 100644
--- a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_random_reset_vseq.sv
+++ b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_random_reset_vseq.sv
@@ -4,7 +4,7 @@
// This sequence assert reset randomly in between running timer
-class rv_timer_random_reset_vseq extends rv_timer_smoke_vseq;
+class rv_timer_random_reset_vseq extends rv_timer_random_vseq;
`uvm_object_utils(rv_timer_random_reset_vseq)
`uvm_object_new
diff --git a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_smoke_vseq.sv b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_random_vseq.sv
similarity index 66%
rename from hw/ip/rv_timer/dv/env/seq_lib/rv_timer_smoke_vseq.sv
rename to hw/ip/rv_timer/dv/env/seq_lib/rv_timer_random_vseq.sv
index 612b3fc..2d4b7b5 100644
--- a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_smoke_vseq.sv
+++ b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_random_vseq.sv
@@ -2,8 +2,8 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-class rv_timer_smoke_vseq extends rv_timer_base_vseq;
- `uvm_object_utils(rv_timer_smoke_vseq)
+class rv_timer_random_vseq extends rv_timer_base_vseq;
+ `uvm_object_utils(rv_timer_random_vseq)
`uvm_object_new
rand bit [NUM_TIMERS-1:0] en_timers;
@@ -18,6 +18,11 @@
rand uint ticks[NUM_HARTS];
rand bit assert_reset;
+ // The scope and runtime of this test can be reduced by setting this variable. This is useful to
+ // keep the runtime down especially in time-sensitive runs such as CI, which is meant to check
+ // the code health and not find design bugs. It is set via plusarg.
+ bit smoke_test;
+
uint64 max_clks_until_expiry = 5_000_000;
constraint assert_reset_c {
@@ -25,48 +30,59 @@
}
constraint num_trans_c {
- num_trans inside {[1:6]};
+ if (smoke_test) num_trans == 1;
+ else num_trans inside {[1:6]};
}
- // at least 1 timer enabled
+ // Enable at least 1 timer.
constraint en_timers_c {
(|en_timers == 1'b1);
}
- // at least 1 hart enabled
+ // Enable at least 1 hart.
constraint en_harts_c {
(|en_harts == 1'b1);
}
- // prescaler less than max prescale for enabled hart
+ // Prescaler must be less than max prescale for the enabled hart.
constraint prescale_c {
solve en_harts before prescale;
foreach (prescale[i]) {
- if (en_harts[i]) prescale[i] inside {[0:max_prescale]};
- else prescale[i] == 0;
- }
- }
-
- // step less than max step for enabled hart
- constraint step_c {
- solve en_harts before step;
- foreach (step[i]) {
- if (en_harts[i]) step[i] inside {[1:max_step]};
- else step[i] == 0;
- }
- }
-
- // ticks * prescale < max clks
- constraint ticks_c {
- solve prescale before ticks;
- foreach (ticks[i]) {
if (en_harts[i]) {
- (ticks[i] * (prescale[i] + 1)) <= max_clks_until_expiry;
+ if (smoke_test) prescale[i] == 1;
+ else prescale[i] inside {[0:max_prescale]};
+ } else {
+ prescale[i] == 0;
}
}
}
- // timer expiry needs to occur within reasonable amount of time
+ // Step value must be less than max step for the enabled hart.
+ constraint step_c {
+ solve en_harts before step;
+ foreach (step[i]) {
+ if (en_harts[i]) {
+ if (smoke_test) step[i] == 1;
+ else step[i] inside {[1:max_step]};
+ } else {
+ step[i] == 0;
+ }
+ }
+ }
+
+ // Ticks * prescale < max clks, to keep the simulated time within bounds.
+ constraint ticks_c {
+ solve prescale before ticks;
+ foreach (ticks[i]) {
+ if (en_harts[i]) {
+ // For smoke test, timeout between 50 and 200 ticks.
+ if (smoke_test) ticks[i] inside {[50:200]};
+ else (ticks[i] * (prescale[i] + 1)) <= max_clks_until_expiry;
+ }
+ }
+ }
+
+ // Timer expiry needs to occur within reasonable amount of time.
constraint timer_exp_c {
solve en_harts before compare_val;
solve en_timers before compare_val;
@@ -82,18 +98,25 @@
}
}
+ function void pre_randomize();
+ super.pre_randomize();
+ // Retrieve this before randomization, so that it can be used inside constraints.
+ void'($value$plusargs("smoke_test=%0b", smoke_test));
+ endfunction
+
task pre_start();
super.pre_start();
// Check Scoreboard is enabled
`DV_CHECK_EQ_FATAL(cfg.en_scb, 1'b1)
+ num_trans.rand_mode(0);
endtask
task body();
- num_trans.rand_mode(0);
for (int trans = 1; trans <= num_trans; trans++) begin
`uvm_info(`gfn, $sformatf("Running test iteration %0d/%0d", trans, num_trans), UVM_LOW)
- `DV_CHECK_RANDOMIZE_FATAL(this)
+ if (trans > 1) `DV_CHECK_RANDOMIZE_FATAL(this)
+
// disable timers first
csr_wr(.csr(ral.ctrl), .value(ral.ctrl.get_reset()));
@@ -121,11 +144,11 @@
for (int i = 0; i < NUM_HARTS; i++) begin
automatic int a_i = i;
fork
- // poll a intr_status continuously until it reads the expected value
- // in `timeout_ns` the delay value is mulitplied by two due to the
- // `intr_state_spinwait` task: if interrupt is set right after csr_rd, then the worst
- // case the code will wait for two `spinwait_delay_ns` before hitting the break
- // statement
+ // Poll intr_status continuously until it reads the expected value.
+ // The delay value set for the `timeout_ns` arg is mulitplied by two due to
+ // `intr_state_spinwait` task: if the interrupt is set right after csr_rd, then in the
+ // worst case, the code will wait for two `spinwait_delay_ns` before hitting the break
+ // statement.
if (en_harts[a_i]) begin
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(delay)
intr_state_spinwait(.hart(a_i), .exp_data(en_timers), .spinwait_delay_ns(delay),
@@ -138,10 +161,10 @@
end : isolation_fork
join
- // Disable timers
+ // Disable timers.
csr_wr(.csr(ral.ctrl), .value(ral.ctrl.get_reset()));
- // Write one to clear the interrupt status
+ // Write one to clear the interrupt status.
for (int i = 0; i < NUM_HARTS; i++) begin
for (int j = 0; j < NUM_TIMERS; j++) begin
if (en_harts[i] && en_timers[j]) begin
@@ -160,7 +183,7 @@
((mtime_dif % step[hart]) != 0)) * (prescale[hart] +1) + 1;
endfunction : calculate_num_clks
- // configure all timers and harts based on rand fields
+ // Configure all timers and harts based on rand fields.
task cfg_all_timers();
for (int i = 0; i < NUM_HARTS; i++) begin
cfg_hart(.hart(i), .prescale(prescale[i]), .step(step[i]));
@@ -172,4 +195,4 @@
end
endtask : cfg_all_timers
-endclass : rv_timer_smoke_vseq
+endclass : rv_timer_random_vseq
diff --git a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_stress_all_vseq.sv b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_stress_all_vseq.sv
index a8c8643..6b2ce5f 100644
--- a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_stress_all_vseq.sv
+++ b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_stress_all_vseq.sv
@@ -11,7 +11,7 @@
`uvm_object_new
task body();
- string seq_names[] = {"rv_timer_smoke_vseq",
+ string seq_names[] = {"rv_timer_random_vseq",
"rv_timer_disabled_vseq",
"rv_timer_common_vseq"}; // for intr_test
for (int i = 1; i <= num_trans; i++) begin
diff --git a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_vseq_list.sv b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_vseq_list.sv
index 988e9d8..e6646ee 100644
--- a/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_vseq_list.sv
+++ b/hw/ip/rv_timer/dv/env/seq_lib/rv_timer_vseq_list.sv
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
`include "rv_timer_base_vseq.sv"
-`include "rv_timer_smoke_vseq.sv"
+`include "rv_timer_random_vseq.sv"
`include "rv_timer_random_reset_vseq.sv"
`include "rv_timer_disabled_vseq.sv"
`include "rv_timer_cfg_update_on_fly_vseq.sv"
diff --git a/hw/ip/rv_timer/dv/rv_timer_sim_cfg.hjson b/hw/ip/rv_timer/dv/rv_timer_sim_cfg.hjson
index 643191e..4bfb74a 100644
--- a/hw/ip/rv_timer/dv/rv_timer_sim_cfg.hjson
+++ b/hw/ip/rv_timer/dv/rv_timer_sim_cfg.hjson
@@ -46,7 +46,14 @@
tests: [
{
name: rv_timer_smoke
- uvm_test_seq: rv_timer_smoke_vseq
+ uvm_test_seq: rv_timer_random_vseq
+ run_opts: ["+smoke_test=1"]
+ reseed: 20
+ }
+
+ {
+ name: rv_timer_random
+ uvm_test_seq: rv_timer_random_vseq
reseed: 200
}