[hw,sysrst_ctrl] Add test for combo detect with precondition
1. Add new sequence randomizing all of combo detect configuration registers
as listed in #17278
2. Move common tasks and functions from combo detect sequences to
base sequence of sysrst_ctrl
3. Update randomize_combo_input task to prevent randomizing input signals
that have activated precondition logic
4. Update get_combo_input function to optionally take an input argument,
specifying the input inversion setting
5. change illegal_bins to ignore_bins as these scenarios are not illegal
6. Add sample function for predetection timer in scoreboard
Signed-off-by: Raviteja Chatta <crteja@lowrisc.org>
diff --git a/hw/ip/sysrst_ctrl/data/sysrst_ctrl_testplan.hjson b/hw/ip/sysrst_ctrl/data/sysrst_ctrl_testplan.hjson
index e43cd46..fe66e88 100644
--- a/hw/ip/sysrst_ctrl/data/sysrst_ctrl_testplan.hjson
+++ b/hw/ip/sysrst_ctrl/data/sysrst_ctrl_testplan.hjson
@@ -87,6 +87,26 @@
}
{
+ name: combo_detect_with_pre_cond
+ desc: '''
+ Verify the combo detection with random action and precondition.
+
+ * Randomly set the input keys combination as precondition by configuring COM_PRE_SEL_CTL_0-3 register.
+ * Randomly set the input keys combination for combo detection by configuring COM_SEL_CTL_0-3 register.
+ * Set the random combo precondition duration via the COM_PRE_DET_CTL_0-3 register.
+ * Set the random combo duration via the COM_DET_CTL_0-3 register.
+ * Randomly select the action to be taken by configuring COM_OUT_CTL_0-3 register.
+ * Set the pulse width via EC_RST_CTL register.
+ * Randomly set the input keys, such that precondition and subsequent combo detection logic are activated randomly.
+ * Read the COMBO_INTR_STATUS register to check whether an interrupt is correctly raised for all the combinations.
+ Clear the interrupt in case it was raised.
+ * Check for bat_disable, rst_req or wake_up_o assertion depending on COM_OUT_CTL_0-3 register
+ '''
+ stage: V2
+ tests: ["sysrst_ctrl_combo_detect_with_pre_cond"]
+ }
+
+ {
name: auto_block_key_outputs
desc: '''
Verify the auto block key output feature.
diff --git a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_base_vseq.sv b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_base_vseq.sv
index bb19d4f..e78e877 100644
--- a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_base_vseq.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_base_vseq.sv
@@ -20,6 +20,45 @@
cfg.clk_aon_rst_vif.set_freq_khz(200);
endtask
+ // Set the inputs back to inactive
+ virtual function void reset_combo_inputs(bit[4:0] input_invert=5'h0);
+ cfg.vif.key0_in = ~input_invert[0];
+ cfg.vif.key1_in = ~input_invert[1];
+ cfg.vif.key2_in = ~input_invert[2];
+ cfg.vif.pwrb_in = ~input_invert[3];
+ cfg.vif.ac_present = ~input_invert[4];
+ endfunction
+
+ // Get input of combo detection logic
+ virtual function bit[4:0] get_combo_input();
+ get_combo_input[0] = cfg.vif.key0_in;
+ get_combo_input[1] = cfg.vif.key1_in;
+ get_combo_input[2] = cfg.vif.key2_in;
+ get_combo_input[3] = cfg.vif.pwrb_in;
+ get_combo_input[4] = cfg.vif.ac_present;
+ endfunction
+
+
+ // Disable ec_rst_l_o override
+ virtual task release_ec_rst_l_o();
+ uint16_t get_ec_rst_timer;
+
+ // Explicitly release the EC reset
+ // Disable the override function
+ ral.pin_out_ctl.ec_rst_l.set(0);
+ csr_update(ral.pin_out_ctl);
+ // Get the ec_rst timer value
+ csr_rd(ral.ec_rst_ctl, get_ec_rst_timer);
+
+ // Check ec_rst_l asserts for ec_rst_timer cycles after reset
+ monitor_ec_rst_low(get_ec_rst_timer);
+ cfg.clk_aon_rst_vif.wait_clks(10);
+
+ // ec_rst_l_o remains high
+ `DV_CHECK_EQ(cfg.vif.ec_rst_l_out, 1);
+
+ endtask
+
virtual task monitor_ec_rst_low(int exp_cycles);
int act_cycles, wait_cycles;
int aon_period_ns = cfg.clk_aon_rst_vif.clk_period_ps / 1000;
@@ -31,7 +70,7 @@
`DV_SPINWAIT(while (cfg.vif.ec_rst_l_out != 1) begin
cfg.clk_aon_rst_vif.wait_clks(1);
act_cycles++;
- end,"time out waiting for ec_rst == 1",aon_period_ns * (exp_cycles + 3))
+ end, "time out waiting for ec_rst == 1", aon_period_ns * (exp_cycles + 10))
`DV_CHECK(act_cycles inside {[exp_cycles - 3 : exp_cycles + 3]},
$sformatf("act(%0d) vs exp(%0d) +/-3", act_cycles, exp_cycles))
endtask
diff --git a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_vseq.sv b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_vseq.sv
index 34031a4..e461e13 100644
--- a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_vseq.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_vseq.sv
@@ -100,34 +100,6 @@
set_key_timer), UVM_LOW);
endtask
- function void reset_combo_inputs();
- // Set the inputs back to inactive to avoid its affect in next iterations
- cfg.vif.pwrb_in = 1;
- cfg.vif.key0_in = 1;
- cfg.vif.key1_in = 1;
- cfg.vif.key2_in = 1;
- cfg.vif.ac_present = 1;
- endfunction
-
- task release_ec_rst_l_o();
- uint16_t get_ec_rst_timer;
-
- // Explicitly release the EC reset
- // Disable the override function
- ral.pin_out_ctl.ec_rst_l.set(0);
- csr_update(ral.pin_out_ctl);
- // Get the ec_rst timer value
- csr_rd(ral.ec_rst_ctl, get_ec_rst_timer);
-
- // Check ec_rst_l asserts for ec_rst_timer cycles after reset
- monitor_ec_rst_low(get_ec_rst_timer);
- cfg.clk_aon_rst_vif.wait_clks(10);
-
- // ec_rst_l_o remains high
- `DV_CHECK_EQ(cfg.vif.ec_rst_l_out, 1);
-
- endtask
-
task body();
uvm_reg_data_t rdata;
bit triggered[4];
diff --git a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv
new file mode 100644
index 0000000..4025953
--- /dev/null
+++ b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv
@@ -0,0 +1,574 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This sequence writes a random values to combo detect registers including
+// precondition settings and checks for the combo detect interrupt.
+class sysrst_ctrl_combo_detect_with_pre_cond_vseq extends sysrst_ctrl_base_vseq;
+ `uvm_object_utils(sysrst_ctrl_combo_detect_with_pre_cond_vseq)
+
+ `uvm_object_new
+ rand uvm_reg_data_t set_action[4];
+ rand bit [4:0] trigger_combo[4], trigger_combo_precondition[4];
+ rand uint16_t set_duration[4], set_duration_precondition[4];
+ rand uint16_t cycles, cycles_precondition;
+ rand uint16_t set_pulse_width, set_key_timer, num_trans_combo_detect;
+ bit ec_rst_h2l_expected = 0 ;
+ bit ec_rst_l2h_expected = 0 ;
+ bit disable_ec_rst_check = 0;
+
+ constraint num_trans_c {num_trans == 50;}
+
+ constraint num_trans_combo_detect_c {num_trans_combo_detect == 10;}
+
+ constraint trigger_combo_precondition_c {
+ foreach (trigger_combo_precondition[i]) {
+ trigger_combo_precondition[i] != 0;
+ }
+ }
+
+ constraint trigger_combo_c {
+ foreach (trigger_combo[i]) {
+ trigger_combo[i] != 0;
+ (trigger_combo[i] & trigger_combo_precondition[i]) == 0;
+ }
+ }
+
+ constraint set_duration_precondition_c {
+ foreach (set_duration_precondition[i]) {
+ set_duration_precondition[i] dist {
+ [10 : 50] :/ 95,
+ [51 : 300] :/ 5
+ };
+ }
+ }
+
+ constraint set_duration_c {
+ foreach (set_duration[i]) {
+ set_duration[i] dist {
+ [10 : 50 ] :/ 95,
+ [51 : 300] :/ 5
+ };
+ }
+ }
+
+ constraint set_pulse_width_c {
+ set_pulse_width dist {
+ [10 : 50] :/ 95,
+ [51 : 300] :/ 5
+ };
+ // ec_rst will trigger a pulse, we check all the action after 4 set_duration are done
+ // make the set_pulse_width larger than any of the duration, so that we can still check it's
+ // value.
+ foreach (set_duration[i]) {
+ if (cycles > set_duration[i] + set_key_timer) {
+ set_pulse_width > cycles - (set_duration[i] + set_key_timer);
+ }
+ }
+ }
+
+ constraint set_key_timer_c {
+ set_key_timer dist {
+ [10 : 50 ] :/ 95,
+ [51 : 300] :/ 5
+ };
+ }
+
+ constraint cycles_c {
+ foreach (set_duration[i]) {
+ cycles dist {
+ [1 : (set_duration[i] + set_key_timer) - 2] :/ 5,
+ [(set_duration[i] + set_key_timer) + 5 : (set_duration[i] + set_key_timer) * 2] :/ 95
+ };
+ }
+ }
+
+ constraint cycles_precondition_c {
+ foreach (set_duration_precondition[i]) {
+ solve set_duration_precondition[i] before cycles_precondition;
+ cycles_precondition dist {
+ [1 : (set_duration_precondition[i] + set_key_timer) - 2] :/ 5,
+ [(set_duration_precondition[i]) + 5 :
+ (set_duration_precondition[i] + set_key_timer) * 2] :/ 95
+ };
+ }
+ }
+
+ task ec_rst_transition_check();
+ `uvm_info(`gfn, "Started ec_rst_l_o transition check", UVM_LOW)
+ fork
+ begin : ec_rst_posedge_check
+ forever begin
+ @(posedge cfg.vif.ec_rst_l_out);
+ wait(cfg.vif.ec_rst_l_out);
+ if(!disable_ec_rst_check)
+ `DV_CHECK(ec_rst_l2h_expected == 1, "Unexpected L2H transition of ec_rst_l_o");
+ end
+ end : ec_rst_posedge_check
+ begin : ec_rst_negedge_check
+ forever begin
+ @(negedge cfg.vif.ec_rst_l_out);
+ wait(!cfg.vif.ec_rst_l_out);
+ if(!disable_ec_rst_check)
+ `DV_CHECK(ec_rst_h2l_expected == 1, "Unexpected H2L transition of ec_rst_l_o");
+ end
+ end : ec_rst_negedge_check
+ join_none
+ endtask
+
+ task automatic set_ec_rst_transition_bits(ref int start_cycles[$], uint16_t pulse_width);
+ int window = 4, pulse_width_l, start_cycle;
+ if( start_cycles.size() == 0) return;
+ start_cycles.sort();
+ start_cycle = start_cycles[0];
+ // Update the aggregate pulse width in case of multiple combo blocks asserting ec_rst_l_o
+ if(start_cycles.size() == 1) begin
+ pulse_width_l = pulse_width;
+ end
+ else begin
+ if((start_cycles[0] + pulse_width) > start_cycles[$]) begin
+ pulse_width_l = pulse_width + (start_cycles[$] - start_cycles[0]);
+ end
+ end
+ `uvm_info(`gfn, $sformatf("pulse_width_l = %0d", pulse_width_l), UVM_LOW)
+
+ fork
+ begin
+ // Wait 2 cycles to account for domain crossing
+ cfg.clk_aon_rst_vif.wait_clks(2);
+ cfg.clk_aon_rst_vif.wait_clks(start_cycle-1);
+ ec_rst_h2l_expected = 1;
+ `uvm_info(`gfn, "ec_rst_h2l_expected == 1", UVM_LOW)
+ cfg.clk_aon_rst_vif.wait_clks(window);
+ ec_rst_h2l_expected = 0;
+ `uvm_info(`gfn, "ec_rst_h2l_expected == 0", UVM_LOW)
+ cfg.clk_aon_rst_vif.wait_clks(pulse_width_l-1);
+ `uvm_info(`gfn, "ec_rst_l2h_expected == 1", UVM_LOW)
+ ec_rst_l2h_expected = 1;
+ cfg.clk_aon_rst_vif.wait_clks(window);
+ ec_rst_l2h_expected = 0;
+ `uvm_info(`gfn, "ec_rst_l2h_expected == 0", UVM_LOW)
+ end
+ join_none
+ endtask
+
+ // Check for a input singal transition that triggers the combo detection logic
+ function bit get_combo_trigger(int index, bit [4:0] combo_input_prev);
+ logic [4:0] in;
+ int count_ones_prev, count_ones;
+ in[0] = cfg.vif.key0_in;
+ in[1] = cfg.vif.key1_in;
+ in[2] = cfg.vif.key2_in;
+ in[3] = cfg.vif.pwrb_in;
+ in[4] = cfg.vif.ac_present;
+ count_ones = $countones(in & trigger_combo[index]);
+ count_ones_prev = $countones(combo_input_prev & trigger_combo[index]);
+ `uvm_info(`gfn, $sformatf(
+ {
+ "DETECTION: i:%0d, in: %5b prev_in: %5b sel:%5b,",
+ "count_ones = %0d count_ones_prev = %0d "
+ },
+ index,
+ in,
+ combo_input_prev,
+ trigger_combo[index],
+ count_ones,
+ count_ones_prev
+ ), UVM_MEDIUM)
+ // Check for Or'd signal transition
+ return ((count_ones_prev > 0) && (count_ones == 0)) && (trigger_combo[index] != 0);
+ endfunction
+
+ // Check for a input combination that triggers the combo precondition logic
+ function bit get_combo_precondition_trigger(int index);
+ logic [4:0] in;
+ in[0] = cfg.vif.key0_in;
+ in[1] = cfg.vif.key1_in;
+ in[2] = cfg.vif.key2_in;
+ in[3] = cfg.vif.pwrb_in;
+ in[4] = cfg.vif.ac_present;
+ `uvm_info(`gfn, $sformatf(
+ "PRECONDITION: i:%0d, in: %5b sel:%5b", index, in, trigger_combo_precondition[index]),
+ UVM_MEDIUM)
+ return ((in & trigger_combo_precondition[index]) == 0);
+ endfunction
+
+ task check_ec_rst_inactive(int max_cycle);
+ cfg.clk_aon_rst_vif.wait_clks($urandom_range(0, max_cycle));
+ `DV_CHECK_EQ(cfg.vif.ec_rst_l_out, 1)
+ endtask
+
+ task config_register();
+ // Select the inputs for precondition
+ foreach (ral.com_pre_sel_ctl[i]) csr_wr(ral.com_pre_sel_ctl[i], trigger_combo_precondition[i]);
+
+ // Set the duration for precondition keys to pressed
+ foreach (ral.com_pre_det_ctl[i]) csr_wr(ral.com_pre_det_ctl[i], set_duration_precondition[i]);
+
+ // Select the inputs for the combo
+ foreach (ral.com_sel_ctl[i]) csr_wr(ral.com_sel_ctl[i], trigger_combo[i]);
+
+ // Set the duration for combo to pressed
+ foreach (ral.com_det_ctl[i]) csr_wr(ral.com_det_ctl[i], set_duration[i]);
+
+ // Set the trigger action
+ foreach (ral.com_out_ctl[i]) csr_wr(ral.com_out_ctl[i], set_action[i]);
+
+ // Set the ec_rst_0 pulse width
+ csr_wr(ral.ec_rst_ctl, set_pulse_width);
+ `uvm_info(`gfn, $sformatf("Write data of ec_rst_ctl register:0x%0h", set_pulse_width), UVM_LOW);
+ // Set the key triggered debounce timer
+ csr_wr(ral.key_intr_debounce_ctl, set_key_timer);
+ `uvm_info(`gfn, $sformatf("Write data of key_intr_debounce_ctl register:0x%0h", set_key_timer),
+ UVM_LOW);
+ endtask
+
+ task monitor_bat_disable_L2H(int exp_cycles);
+ int inactive_cycles = 0;
+ int aon_period_ns = cfg.clk_aon_rst_vif.clk_period_ps / 1000;
+ // Check bat_disable is low for exp_cycles. After exp_cycles+20, below will time out and fail.
+ `DV_SPINWAIT(while (cfg.vif.bat_disable != 1) begin
+ cfg.clk_aon_rst_vif.wait_clks(1);
+ inactive_cycles++;
+ end, "time out waiting for bat_disable == 1",
+ aon_period_ns * (exp_cycles + 20))
+ `DV_CHECK(inactive_cycles inside {[exp_cycles - 4 : exp_cycles + 4]},
+ $sformatf("bat_disable_check: inact(%0d) vs exp(%0d) +/-4", inactive_cycles, exp_cycles))
+ endtask
+
+ task monitor_rst_req_L2H(int exp_cycles);
+ int inactive_cycles = 0;
+ int aon_period_ns = cfg.clk_aon_rst_vif.clk_period_ps / 1000;
+ // Check rst_req is low for exp_cycles. After exp_cycles+20, below will time out and fail.
+ `DV_SPINWAIT(while (cfg.vif.rst_req != 1) begin
+ cfg.clk_aon_rst_vif.wait_clks(1);
+ inactive_cycles++;
+ end, "time out waiting for rst_req == 1",
+ aon_period_ns * (exp_cycles + 20))
+ `DV_CHECK(inactive_cycles inside {[exp_cycles - 4 : exp_cycles + 4]},
+ $sformatf("rst_req_check: inact(%0d) vs exp(%0d) +/-4", inactive_cycles, exp_cycles))
+ endtask
+
+ // Sample covergroups with key selections and combo actions
+ function void sample_coverpoints( int i,
+ bit [4:0] trigger_combo_pre,
+ bit [4:0] trigger_combo,
+ bit com_out_intr,
+ bit com_out_bat_disable,
+ bit com_out_ec_rst,
+ bit com_out_rst_req);
+
+ // Sample aggregate key selection
+ bit key0_in_sel_detect = get_field_val( ral.com_sel_ctl[i].key0_in_sel, trigger_combo);
+ bit key1_in_sel_detect = get_field_val( ral.com_sel_ctl[i].key1_in_sel, trigger_combo);
+ bit key2_in_sel_detect = get_field_val( ral.com_sel_ctl[i].key2_in_sel, trigger_combo);
+ bit pwrb_in_sel_detect = get_field_val( ral.com_sel_ctl[i].pwrb_in_sel, trigger_combo);
+ bit ac_present_sel_detect = get_field_val( ral.com_sel_ctl[i].ac_present_sel, trigger_combo);
+ bit key0_in_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].key0_in_sel, trigger_combo_pre);
+ bit key1_in_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].key1_in_sel, trigger_combo_pre);
+ bit key2_in_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].key2_in_sel, trigger_combo_pre);
+ bit pwrb_in_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].pwrb_in_sel, trigger_combo_pre);
+ bit ac_present_sel_precond = get_field_val( ral.com_pre_sel_ctl[i].ac_present_sel,
+ trigger_combo_pre);
+ // Sample combo actions and key selections for each combo channel
+ cov.combo_detect_action[i].sysrst_ctrl_combo_detect_action_cg.sample(
+ com_out_bat_disable, com_out_intr, com_out_ec_rst, com_out_rst_req,
+ key0_in_sel_detect,
+ key1_in_sel_detect,
+ key2_in_sel_detect,
+ pwrb_in_sel_detect,
+ ac_present_sel_detect,
+ key0_in_sel_precond,
+ key1_in_sel_precond,
+ key2_in_sel_precond,
+ pwrb_in_sel_precond,
+ ac_present_sel_precond);
+ // Sample key combination coverpoints
+ cov.combo_key_combinations.sysrst_ctrl_combo_key_combinations_cg.sample(
+ .bat_disable ( com_out_bat_disable ),
+ .interrupt ( com_out_intr ),
+ .ec_rst ( com_out_rst_req ),
+ .rst_req ( com_out_rst_req ),
+ .key0_in_sel ( key0_in_sel_detect ),
+ .key1_in_sel ( key1_in_sel_detect ),
+ .key2_in_sel ( key2_in_sel_detect ),
+ .pwrb_in_sel ( pwrb_in_sel_detect ),
+ .ac_present_sel ( ac_present_sel_detect ),
+ .precondition_key0_in_sel ( key0_in_sel_precond ),
+ .precondition_key1_in_sel ( key1_in_sel_precond ),
+ .precondition_key2_in_sel ( key2_in_sel_precond ),
+ .precondition_pwrb_in_sel ( pwrb_in_sel_precond ),
+ .precondition_ac_present_sel ( ac_present_sel_precond) );
+ endfunction
+
+ task body();
+
+ `uvm_info(`gfn, "Starting the body from combo detect with precondition", UVM_LOW)
+
+ // Start sequence by releaseing ec_rst_l_o. post reset ec_rst_l_o remains asserted,
+ // and must be deasserted. This is to make sure during test, the H->L and L->H transitions
+ // of ec_rst_l_o can be observed
+ release_ec_rst_l_o();
+ // Reset combo logic input
+ reset_combo_inputs();
+ // Configure combo logic registers
+ config_register();
+
+ `uvm_info(`gfn, $sformatf("Value of cycles_precondition:%0d", cycles_precondition), UVM_LOW)
+ `uvm_info(`gfn, $sformatf("Value of cycles:%0d", cycles), UVM_LOW)
+ // It takes 2-3 clock cycles to sync the register values
+ cfg.clk_aon_rst_vif.wait_clks(3);
+ ec_rst_transition_check();
+ repeat (num_trans) begin : main_block
+ bit precond_detected_for_one_block = 1'b0;
+ bit [3:0] precondition_detected = '{4{1'b0}};
+ // Randomize input
+ repeat ($urandom_range(1, 3)) cfg.vif.randomize_combo_input();
+ // Wait for debounce + detect timer
+ cfg.clk_aon_rst_vif.wait_clks(cycles_precondition);
+ for (int i = 0; i < 4; i++) begin
+ if(cycles_precondition > (set_duration_precondition[i] + set_key_timer) &&
+ get_combo_precondition_trigger(i)) begin
+ precondition_detected[i] = (trigger_combo[i] & trigger_combo_precondition[i]) == 0;
+ precond_detected_for_one_block |= precondition_detected[i];
+ end
+ end
+
+ if (precond_detected_for_one_block) begin : combo_detect_block
+ uvm_reg_data_t rdata;
+ uint16_t [3:0] get_duration;
+ uvm_reg_data_t [3:0] get_action;
+ bit [3:0] combo_detected;
+ bit [4:0] combo_precondition_mask = 5'd0;
+ bit [4:0] get_trigger_combo[4];
+ bit [4:0] get_trigger_combo_pre[4];
+ bit [4:0] combo_input_prev;
+ bit combo_triggered[4] = '{1'b0, 1'b0, 1'b0, 1'b0};
+ // Update combo_precondition_mask
+ for (int i = 0; i < 4; i++) begin
+ if (precondition_detected[i]) begin
+ // Dont change the signals asserted for precondition
+ combo_precondition_mask |= trigger_combo_precondition[i];
+ `uvm_info(`gfn, $sformatf("valid precondition detected for combo channel: %0d", i),
+ UVM_LOW)
+ end
+ else begin
+ // Disable blocks in Idle state
+ csr_wr(ral.com_sel_ctl[i], 5'd0);
+ csr_wr(ral.com_pre_sel_ctl[i], 5'd0);
+ end
+ end
+ // Wait for register updates to take effect
+ cfg.clk_aon_rst_vif.wait_clks(3);
+
+ combo_precondition_mask = ~combo_precondition_mask;
+ `uvm_info(`gfn, $sformatf("precondition_detected= %0x", precondition_detected), UVM_MEDIUM)
+ `uvm_info(`gfn, $sformatf("combo_precondition_mask= %0x", combo_precondition_mask),UVM_LOW)
+
+ while (precondition_detected > 0 && (combo_detected != precondition_detected) &&
+ num_trans_combo_detect>0) begin : combo_action_check
+ bit bat_act_triggered, ec_act_triggered, rst_act_triggered;
+ bit [3:0] intr_actions, intr_actions_pre_reset;
+ int bat_act_occur_cyc = 0;
+ int rst_req_act_occur_cyc = 0;
+ int bat_act_occur_cycles[$];
+ int rst_req_act_occur_cycles[$];
+ int ec_rst_start_time[$];
+ int max_wait_till_next_iter = set_pulse_width;
+
+ // Sample combo key inputs
+ combo_input_prev = get_combo_input();
+
+ // Sample the combo_intr_status covergroup to capture the trigger combo inputs
+ // before randomizing the inputs
+ if (cfg.en_cov) begin
+ foreach (intr_actions_pre_reset[i]) begin
+ intr_actions_pre_reset[i] =
+ get_field_val(ral.com_out_ctl[i].interrupt, get_action[i]);
+ end
+ cov.combo_intr_status.sysrst_ctrl_combo_intr_status_cg.sample(
+ get_field_val(ral.combo_intr_status.combo0_h2l, rdata),
+ get_field_val(ral.combo_intr_status.combo1_h2l, rdata),
+ get_field_val(ral.combo_intr_status.combo2_h2l, rdata),
+ get_field_val(ral.combo_intr_status.combo3_h2l, rdata),
+ cfg.vif.key0_in,
+ cfg.vif.key1_in,
+ cfg.vif.key2_in,
+ cfg.vif.pwrb_in,
+ cfg.vif.ac_present,
+ intr_actions_pre_reset);
+ end
+
+ // Read combo detection registers
+ foreach (ral.com_det_ctl[i]) csr_rd(ral.com_det_ctl[i], get_duration[i]);
+ foreach (ral.com_out_ctl[i]) csr_rd(ral.com_out_ctl[i], get_action[i]);
+ foreach (ral.com_sel_ctl[i]) csr_rd(ral.com_sel_ctl[i], get_trigger_combo[i]);
+ foreach (ral.com_sel_ctl[i]) csr_rd(ral.com_pre_sel_ctl[i], get_trigger_combo_pre[i]);
+
+ // Randomize combo logic inputs except the ones asserted for precondition
+ repeat ($urandom_range(1, 3)) cfg.vif.randomize_combo_input(combo_precondition_mask);
+
+ cfg.clk_aon_rst_vif.wait_clks(1);
+ // Update trigger value of Combo channel and ec_rst timing check bits
+ foreach (combo_triggered[i]) begin
+ bit com_out_ec_rst = get_field_val(ral.com_out_ctl[i].ec_rst, get_action[i]);
+ if (precondition_detected[i]) begin
+ int key_detect_time = int'(get_duration[i] + set_key_timer);
+ combo_triggered[i] = get_combo_trigger(i, combo_input_prev);
+ if (com_out_ec_rst && combo_triggered[i] &&
+ (cycles+set_pulse_width > key_detect_time)) begin
+ ec_rst_start_time.push_back(key_detect_time-1);
+ end
+ end
+ end
+ set_ec_rst_transition_bits(ec_rst_start_time, set_pulse_width);
+ // Wait for debounce + detect timer
+ cfg.clk_aon_rst_vif.wait_clks(cycles-1);
+
+ // Check if the interrupt has raised.
+ // NOTE: The interrupt will only raise if the interrupt combo action is set.
+ for (int i = 0; i < 4; i++) begin
+ if ((cycles + set_pulse_width) > (get_duration[i] + set_key_timer) &&
+ combo_triggered[i])
+ begin
+ int key_detect_time = get_duration[i] + set_key_timer;
+ bit com_out_intr = get_field_val(ral.com_out_ctl[i].interrupt, get_action[i]);
+ bit com_out_bat_disable = get_field_val(ral.com_out_ctl[i].bat_disable,
+ get_action[i]);
+ bit com_out_ec_rst = get_field_val(ral.com_out_ctl[i].ec_rst, get_action[i]);
+ bit com_out_rst_req = get_field_val(ral.com_out_ctl[i].rst_req, get_action[i]);
+
+ `uvm_info(`gfn, $sformatf("valid combo input transition detected for channel :%0d",i),
+ UVM_LOW)
+ intr_actions[i] = com_out_intr;
+ bat_act_triggered |= com_out_bat_disable;
+ ec_act_triggered |= com_out_ec_rst;
+ rst_act_triggered |= com_out_rst_req;
+ if (cfg.en_cov) begin
+ for (int i = 0; i < 4; i++) begin
+ sample_coverpoints( i,
+ get_trigger_combo_pre[i],
+ get_trigger_combo[i],
+ com_out_intr,
+ com_out_bat_disable,
+ com_out_ec_rst,
+ com_out_rst_req);
+ end
+ end
+ if (com_out_bat_disable) begin
+ bat_act_occur_cycles.push_back(key_detect_time);
+ end
+ if (com_out_rst_req) begin
+ rst_req_act_occur_cycles.push_back(key_detect_time);
+ end
+ combo_detected[i]= com_out_ec_rst | com_out_bat_disable | com_out_intr |
+ com_out_rst_req;
+ end
+ `uvm_info(`gfn, $sformatf("bat_act_triggered = %0b", bat_act_triggered), UVM_MEDIUM)
+ `uvm_info(`gfn, $sformatf("rst_act_triggered = %0b", rst_act_triggered), UVM_MEDIUM)
+ end
+ // Update start cycle of output assertion
+ if( bat_act_occur_cycles.size() > 0 ) begin
+ bat_act_occur_cycles.sort();
+ if( bat_act_occur_cycles[0] > cycles)
+ bat_act_occur_cyc = bat_act_occur_cycles[0] - cycles;
+ end
+ if( rst_req_act_occur_cycles.size() > 0 ) begin
+ rst_req_act_occur_cycles.sort();
+ if( rst_req_act_occur_cycles[0] > cycles)
+ rst_req_act_occur_cyc = rst_req_act_occur_cycles[0] - cycles;
+ end
+ `uvm_info(`gfn, $sformatf("bat_act_occur_cyc = %0d", bat_act_occur_cyc), UVM_MEDIUM)
+ `uvm_info(`gfn, $sformatf("rst_req_act_occur_cyc = %0d", rst_req_act_occur_cyc),
+ UVM_MEDIUM)
+ // Check for Combo output assertions
+ fork
+ begin
+ // Wait till next iteration
+ cfg.clk_aon_rst_vif.wait_clks(set_pulse_width);
+ // Reset combo inputs except the ones required to enable precondition
+ reset_combo_inputs(~combo_precondition_mask);
+ end
+ begin : bat_disable_check
+ if (bat_act_triggered) begin
+ if (bat_act_occur_cyc > 0) monitor_bat_disable_L2H(bat_act_occur_cyc);
+ else `DV_CHECK_EQ(cfg.vif.bat_disable, 1);
+ end else begin
+ `DV_CHECK_EQ(cfg.vif.bat_disable, 0);
+ end
+ end : bat_disable_check
+ begin : rst_req_check
+ if (rst_act_triggered) begin
+ if (rst_req_act_occur_cyc > 0) monitor_rst_req_L2H(rst_req_act_occur_cyc);
+ else `DV_CHECK_EQ(cfg.vif.rst_req, 1);
+ end else begin
+ `DV_CHECK_EQ(cfg.vif.rst_req, 0);
+ end
+ end : rst_req_check
+ join
+
+ // Check for interrupt status after output check
+ begin : intr_check
+ cfg.clk_aon_rst_vif.wait_clks(1);
+ csr_rd(ral.combo_intr_status, rdata);
+ `DV_CHECK_EQ(rdata, intr_actions)
+ if (intr_actions) begin
+ check_interrupts(.interrupts(1 << IntrSysrstCtrl), .check_set(1));
+
+ // Write to clear the interrupt.
+ csr_wr(ral.combo_intr_status, rdata);
+
+ cfg.clk_aon_rst_vif.wait_clks(5);
+ // Check if the interrupt is cleared.
+ csr_rd_check(ral.combo_intr_status, .compare_value(0));
+ // Sample the combo intr status covergroup.
+ // The combo_intr_status get updated only when the interrupt action is triggered.
+ if (cfg.en_cov) begin
+ cov.combo_intr_status.sysrst_ctrl_combo_intr_status_cg.sample(
+ get_field_val(ral.combo_intr_status.combo0_h2l, rdata), get_field_val(
+ ral.combo_intr_status.combo1_h2l, rdata), get_field_val(
+ ral.combo_intr_status.combo2_h2l, rdata), get_field_val(
+ ral.combo_intr_status.combo3_h2l, rdata), cfg.vif.key0_in, cfg.vif.key1_in,
+ cfg.vif.key2_in, cfg.vif.pwrb_in, cfg.vif.ac_present, intr_actions);
+ end
+ end else begin
+ check_interrupts(.interrupts(1 << IntrSysrstCtrl), .check_set(0));
+ end
+ end : intr_check
+
+ // Reset design for sticky combo output settings
+ if (bat_act_triggered || rst_act_triggered) begin
+ disable_ec_rst_check = 1;
+ // Reset combo logic input
+ reset_combo_inputs();
+ apply_resets_concurrently();
+ // Delay to avoid race condition when sending item and checking no item after
+ // reset occur at the same time.
+ #1ps;
+ // Release ec_rst_l_o after reset
+ release_ec_rst_l_o();
+ // Apply_resets_concurrently will set the registers to their default values,
+ // wait for sometime and reconfigure the registers for next iteration.
+ config_register();
+ disable_ec_rst_check = 0;
+ // Reset internal variables
+ precondition_detected = '{4{1'b0}};
+ combo_detected = '{4{1'b0}};
+ // Exit combo_action_check block
+ break;
+ end
+ num_trans_combo_detect--;
+ end : combo_action_check
+ end : combo_detect_block
+ // Reset combo inputs after iteration
+ reset_combo_inputs();
+ // Reprogram the combo selection registers
+ for (int i = 0; i < 4; i++) begin
+ csr_wr(ral.com_sel_ctl[i], trigger_combo[i]);
+ csr_wr(ral.com_pre_sel_ctl[i], trigger_combo_precondition[i]);
+ end
+ cfg.clk_aon_rst_vif.wait_clks(3);
+ end : main_block
+ endtask : body
+
+endclass : sysrst_ctrl_combo_detect_with_pre_cond_vseq
diff --git a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_vseq_list.sv b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_vseq_list.sv
index 12efdf6..c8ee82d 100644
--- a/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_vseq_list.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/seq_lib/sysrst_ctrl_vseq_list.sv
@@ -17,3 +17,4 @@
`include "sysrst_ctrl_combo_detect_vseq.sv"
`include "sysrst_ctrl_edge_detect_vseq.sv"
`include "sysrst_ctrl_stress_all_vseq.sv"
+`include "sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv"
diff --git a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_env.core b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_env.core
index 24fd0b2..234d676 100644
--- a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_env.core
+++ b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_env.core
@@ -33,6 +33,7 @@
- seq_lib/sysrst_ctrl_combo_detect_vseq.sv: {is_include_file: true}
- seq_lib/sysrst_ctrl_edge_detect_vseq.sv: {is_include_file: true}
- seq_lib/sysrst_ctrl_stress_all_vseq.sv: {is_include_file: true}
+ - seq_lib/sysrst_ctrl_combo_detect_with_pre_cond_vseq.sv: {is_include_file: true}
file_type: systemVerilogSource
generate:
diff --git a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_if.sv b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_if.sv
index e0aff58..d08096e 100644
--- a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_if.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_if.sv
@@ -57,17 +57,17 @@
flash_wp_l_in = flash_wp;
endtask
- task automatic randomize_combo_input();
+ task automatic randomize_combo_input(bit[4:0] mask=5'h1F);
// VCS doesn't support randomizing logic variable
// so declare bit variable, randomize it and assigned it to logic
bit pwrb, key0, key1, key2, ac_prst;
`DV_CHECK_FATAL(std::randomize(pwrb, key0, key1, key2, ac_prst), ,
"sysrst_ctrl_if")
- pwrb_in = pwrb;
- key0_in = key0;
- key1_in = key1;
- key2_in = key2;
- ac_present = ac_prst;
+ if(mask[0]) key0_in = key0;
+ if(mask[1]) key1_in = key1;
+ if(mask[2]) key2_in = key2;
+ if(mask[3]) pwrb_in = pwrb;
+ if(mask[4]) ac_present = ac_prst;
endtask
assign sysrst_ctrl_inputs = {flash_wp_l_in, ec_rst_l_in, ac_present, key2_in, key1_in, key0_in,
diff --git a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_scoreboard.sv b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_scoreboard.sv
index ca1ad5e..929b726 100644
--- a/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_scoreboard.sv
+++ b/hw/ip/sysrst_ctrl/dv/env/sysrst_ctrl_scoreboard.sv
@@ -233,9 +233,18 @@
end
"alert_test": begin
end
- // TODO: need support pre-condition
- "com_pre_sel_ctl_0", "com_pre_sel_ctl_1", "com_pre_sel_ctl_2", "com_pre_sel_ctl_3",
+ "com_pre_sel_ctl_0", "com_pre_sel_ctl_1", "com_pre_sel_ctl_2", "com_pre_sel_ctl_3": begin
+ // covered in sequence
+ end
"com_pre_det_ctl_0", "com_pre_det_ctl_1", "com_pre_det_ctl_2", "com_pre_det_ctl_3": begin
+ if (addr_phase_write) begin
+ string csr_name = csr.get_name();
+ string str_idx = csr_name.getc(csr_name.len - 1);
+ int idx = str_idx.atoi();
+ cov_if.cg_combo_precondition_det_sample (idx,
+ get_field_val(ral.com_pre_det_ctl[idx].precondition_timer, item.a_data)
+ );
+ end
end
default: begin
`uvm_error(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
diff --git a/hw/ip/sysrst_ctrl/dv/sysrst_ctrl_sim_cfg.hjson b/hw/ip/sysrst_ctrl/dv/sysrst_ctrl_sim_cfg.hjson
index 49780bc..58a55c3 100644
--- a/hw/ip/sysrst_ctrl/dv/sysrst_ctrl_sim_cfg.hjson
+++ b/hw/ip/sysrst_ctrl/dv/sysrst_ctrl_sim_cfg.hjson
@@ -106,6 +106,11 @@
uvm_test_seq: sysrst_ctrl_edge_detect_vseq
run_opts: ["+test_timeout_ns=10_000_000_000"]
}
+ {
+ name: sysrst_ctrl_combo_detect_with_pre_cond
+ uvm_test_seq: sysrst_ctrl_combo_detect_with_pre_cond_vseq
+ reseed: 100
+ }
]
// List of regressions.