blob: b202dd71f69ab9de950ccf2295d519346bb5b3a6 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// This sequence asserts the inputs of sysrst_ctrl such that the
// key detection blocks transition from Debounce to Idle state
class sysrst_ctrl_feature_disable_vseq extends sysrst_ctrl_base_vseq;
`uvm_object_utils(sysrst_ctrl_feature_disable_vseq)
`uvm_object_new
// Combo detect egister settings
rand bit [4:0] trigger_combo[4];
rand bit [4:0] trigger_combo_precondition[4];
rand uvm_reg_data_t set_action[4];
rand uint16_t set_duration[4], set_duration_precondition[4];
rand uint16_t set_key_timer;
// ec_rst_l_o assertion time
rand uint16_t set_pulse_width;
// Key debounce timer
rand uint16_t set_key_intr_timer;
rand uvm_reg_data_t auto_block_out_ctl;
rand uint16_t auto_block_debounce_ctl;
// ULP debounce timer
rand uint16_t ulp_debounce_ctl;
constraint set_timer_c {set_key_intr_timer inside {[15 : 50]};}
constraint trigger_combo_c {
foreach (trigger_combo[i]) {
!(trigger_combo_precondition[i] & trigger_combo[i]);
trigger_combo[i] > 0;
}
}
constraint trigger_combo_precondition_c {
foreach (trigger_combo_precondition[i]) {
trigger_combo_precondition[i] > 0;
solve trigger_combo_precondition[i] before trigger_combo[i];
}
}
// Set ec_rst_l_o assertion as combo output for all channels
constraint set_action_c {
foreach (set_action[i]) {
set_action[i] == 4;
}
}
constraint set_duration_c {
foreach (set_duration[i]) {
set_duration[i] inside {[10 : 50]};
}
}
constraint set_duration_precondition_c {
foreach (set_duration_precondition[i]) {
set_duration_precondition[i] inside {[10 : 50]};
}
}
constraint set_pulse_width_c {set_pulse_width inside {[50 : 100]};}
constraint set_key_timer_c {set_key_timer inside {[15 : 50]};}
constraint auto_block_debounce_ctl_c {auto_block_debounce_ctl inside {[15 : 50]};}
constraint auto_block_out_ctl_c {
// At least one input is auto-blocked
auto_block_out_ctl & 'h3 > 0;
}
constraint ulp_debounce_time_c {ulp_debounce_ctl inside {[15 : 50]};}
function void set_combo_inputs(input bit [4:0] val = 5'h1F, bit [4:0] mask = 5'h1F);
// Set the inputs
if (mask[0]) cfg.vif.key0_in = val[0];
if (mask[1]) cfg.vif.key1_in = val[1];
if (mask[2]) cfg.vif.key2_in = val[2];
if (mask[3]) cfg.vif.pwrb_in = val[3];
if (mask[4]) cfg.vif.ac_present = val[4];
endfunction
task config_combo_register(int i, uint16_t mask = 16'hFF);
// Select the inputs for precondition
csr_wr(ral.com_pre_sel_ctl[i], mask & trigger_combo_precondition[i]);
// Set the duration for precondition keys to pressed
csr_wr(ral.com_pre_det_ctl[i], mask & set_duration_precondition[i]);
// Select the inputs for the combo
csr_wr(ral.com_sel_ctl[i], mask & trigger_combo[i]);
// Set the duration for combo to pressed
csr_wr(ral.com_det_ctl[i], mask & set_duration[i]);
// Set the trigger action
csr_wr(ral.com_out_ctl[i], mask & set_action[i]);
// It takes 2-3 clock cycles to sync the register values
cfg.clk_aon_rst_vif.wait_clks(3);
endtask
task combo_debounce_to_idle();
// Reset Combo detect inputs
set_combo_inputs();
release_ec_rst_l_o();
// 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:%0d", 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:%0d", set_key_timer),
UVM_LOW);
for (int i = 0; i < 4; i++) begin
`uvm_info(`gfn, $sformatf("configuring combo channel %0d", i), UVM_LOW)
// Scenario : Trigger precondition Debounce to Idle state via
// deassertion of inputs before debounce timer
config_combo_register(i);
// Set combo input
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer - 10);
// Deassert input signals before debounce timer
set_combo_inputs();
cfg.clk_aon_rst_vif.wait_clks(15);
// Scenario : Trigger precondition Debounce to Idle state via
// disabling precondition before debounce timer
// Assert input signals to match predoncition selection
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer - 10);
// Disable precondition before debounce timer
csr_wr(ral.com_pre_sel_ctl[i], 0);
cfg.clk_aon_rst_vif.wait_clks(10);
set_combo_inputs();
cfg.clk_aon_rst_vif.wait_clks(3);
// Scenario : Trigger precondition Detect to Idle state via
// disabling precondition before detect timer
// Assert input signals to match predoncition selection
config_combo_register(i);
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration_precondition[i] - 10);
// Disable precondition before detect timer
csr_wr(ral.com_pre_sel_ctl[i], 0);
cfg.clk_aon_rst_vif.wait_clks(10);
set_combo_inputs();
cfg.clk_aon_rst_vif.wait_clks(3);
// Scenario : Trigger precondition Detect to Idle state via
// deassertion of input signals
// Assert input signals to match predoncition selection
config_combo_register(i);
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration_precondition[i] - 10);
// Disable precondition before detect timer
set_combo_inputs();
cfg.clk_aon_rst_vif.wait_clks(15);
// Scenario : Trigger combo detect Debounce to Idle state via
// deassertion of input signals before debounce timer
// Set combo input to trigger precondition
config_combo_register(i);
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration_precondition[i] + 10);
// Set combo input to trigger combo detection
set_combo_inputs(~trigger_combo[i], ~trigger_combo_precondition[i]);
// Wait for some time but dont exceed debounce time
cfg.clk_aon_rst_vif.wait_clks(set_key_timer - 10);
// Deassert combo inputs before debounce timer
set_combo_inputs();
cfg.clk_aon_rst_vif.wait_clks(10);
// Scenario : Trigger combo detect Debounce to Idle state via
// disabling detection before debounce timer
// Set combo input to trigger precondition
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration_precondition[i] + 10);
// Set combo input to trigger combo detection
set_combo_inputs(~trigger_combo[i], ~trigger_combo_precondition[i]);
// Wait for some time but dont exceed debounce time
cfg.clk_aon_rst_vif.wait_clks(set_key_timer - 10);
// Disable combo detect before debounce timer
csr_wr(ral.com_sel_ctl[i], 0);
cfg.clk_aon_rst_vif.wait_clks(15);
// Reset combo inputs
set_combo_inputs();
cfg.clk_aon_rst_vif.wait_clks(10);
// Scenario : Trigger combo Detect to Idle state via
// disabling detect before detect timer
// Set combo input to trigger precondition
config_combo_register(i);
// Wait for 3 clock cycles to sync the register value
cfg.clk_aon_rst_vif.wait_clks(3);
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration_precondition[i] + 10);
// Set combo input to trigger combo detection
set_combo_inputs(~trigger_combo[i], ~trigger_combo_precondition[i]);
// Wait for some time but dont exceed detect time
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration[i] - 10);
// Disable combo detect before detect timer
csr_wr(ral.com_sel_ctl[i], 0);
cfg.clk_aon_rst_vif.wait_clks(10);
set_combo_inputs();
cfg.clk_aon_rst_vif.wait_clks(10);
// Scenario : Trigger combo Detect to Idle state via
// deassertion of input signals
// Set combo input to trigger precondition
config_combo_register(i);
// Wait for 3 clock cycles to sync the register value
cfg.clk_aon_rst_vif.wait_clks(3);
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration_precondition[i] + 10);
// Set combo input to trigger combo detection
set_combo_inputs(~trigger_combo[i], ~trigger_combo_precondition[i]);
// Wait for some time but dont exceed detect time
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration[i] - 10);
// Deassert combo inputs before detect timer
set_combo_inputs();
cfg.clk_aon_rst_vif.wait_clks(20);
check_interrupts(.interrupts(1 << IntrSysrstCtrl), .check_set(0));
// Reset combo registers
config_combo_register(i, 16'h0);
end
endtask
task combo_action_ec_rst_l_i_assert();
`uvm_info(`gfn, "ec_rst_l_i assertion check for combo detect", UVM_LOW)
for (int i = 0; i < 4; i++) begin
`uvm_info(`gfn, $sformatf("configuring combo channel %0d", i), UVM_LOW)
// Scenario : Assert ec_rst_l_i just before combo action triggers ec_rst_l_o
config_combo_register(i);
set_combo_inputs(~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration_precondition[i] + 10);
set_combo_inputs(~trigger_combo[i], ~trigger_combo_precondition[i]);
cfg.clk_aon_rst_vif.wait_clks(set_key_timer + set_duration[i] - 5);
fork
begin
// Assert ec_rst_l_i signal
cfg.vif.ec_rst_l_in = 1'b0;
cfg.clk_aon_rst_vif.wait_clks(10);
cfg.vif.ec_rst_l_in = 1'b1;
cfg.clk_aon_rst_vif.wait_clks(set_pulse_width + 10);
end
begin
cfg.clk_aon_rst_vif.wait_clks(5);
monitor_ec_rst_low(set_pulse_width);
end
join
`uvm_info(`gfn, "ec_rst_l_o asserted as expected", UVM_LOW)
// Reset combo inputs
set_combo_inputs();
// Disable combo detect
config_combo_register(i, 0);
end
endtask
task set_edge_detector_input(string field_name, bit reset = 1);
// Select the edge detect input
case (field_name)
"pwrb_in_h2l": cfg.vif.pwrb_in = reset ? 1 : 0;
"pwrb_in_l2h": cfg.vif.pwrb_in = reset ? 0 : 1;
"key0_in_h2l": cfg.vif.key0_in = reset ? 1 : 0;
"key0_in_l2h": cfg.vif.key0_in = reset ? 0 : 1;
"key1_in_h2l": cfg.vif.key1_in = reset ? 1 : 0;
"key1_in_l2h": cfg.vif.key1_in = reset ? 0 : 1;
"key2_in_h2l": cfg.vif.key2_in = reset ? 1 : 0;
"key2_in_l2h": cfg.vif.key2_in = reset ? 0 : 1;
"ac_present_l2h": cfg.vif.ac_present = reset ? 0 : 1;
"ac_present_h2l": cfg.vif.ac_present = reset ? 1 : 0;
"flash_wp_l_h2l": cfg.vif.flash_wp_l_in = reset ? 1 : 0;
"flash_wp_l_l2h": cfg.vif.flash_wp_l_in = reset ? 0 : 1;
"ec_rst_l_h2l": cfg.vif.ec_rst_l_in = reset ? 1 : 0;
"ec_rst_l_l2h": cfg.vif.ec_rst_l_in = reset ? 0 : 1;
default: `uvm_error(`gfn,$sformatf("Unknown field name %s", field_name))
endcase
cfg.clk_aon_rst_vif.wait_clks(3);
endtask
task edge_detect_en(uvm_reg_data_t field_mask);
uvm_reg_data_t rdata;
csr_rd(ral.key_intr_ctl, rdata);
csr_wr(ral.key_intr_ctl, rdata | field_mask);
cfg.clk_aon_rst_vif.wait_clks(3);
endtask
task edge_detect_dis(uvm_reg_data_t field_mask);
uvm_reg_data_t rdata;
csr_rd(ral.key_intr_ctl, rdata);
csr_wr(ral.key_intr_ctl, rdata & ~field_mask);
cfg.clk_aon_rst_vif.wait_clks(3);
endtask
// Key intrrrupt control Debounce to idle state transition
// 1. disable config before debounce
// 2. disable config after debounce and before detect time
task key_intr_debounce_to_idle();
dv_base_reg_field fields[] = {
ral.key_intr_ctl.pwrb_in_h2l,
ral.key_intr_ctl.pwrb_in_l2h,
ral.key_intr_ctl.key0_in_h2l,
ral.key_intr_ctl.key0_in_l2h,
ral.key_intr_ctl.key1_in_h2l,
ral.key_intr_ctl.key1_in_l2h,
ral.key_intr_ctl.key2_in_h2l,
ral.key_intr_ctl.key2_in_l2h,
ral.key_intr_ctl.ac_present_h2l,
ral.key_intr_ctl.ac_present_l2h,
ral.key_intr_ctl.ec_rst_l_h2l,
ral.key_intr_ctl.ec_rst_l_l2h,
ral.key_intr_ctl.flash_wp_l_h2l,
ral.key_intr_ctl.flash_wp_l_l2h
};
// Set the key interrupt debounce timer value
csr_wr(ral.key_intr_debounce_ctl, set_key_intr_timer);
for (int i = 0; i < fields.size(); i += 1) begin
string field_name = fields[i].get_name();
uvm_reg_data_t field_mask = fields[i].get_field_mask();
`uvm_info(`gfn, $sformatf("checking debounce to idle transition for %s", field_name), UVM_LOW)
// Scenario : Disable edge detect before debounce timer
// Reset input
set_edge_detector_input(field_name);
// Enable edge detection
edge_detect_en(field_mask);
set_edge_detector_input(field_name, 0);
// Disable edge detection before debounce timer
cfg.clk_aon_rst_vif.wait_clks(set_key_timer - 6);
edge_detect_dis(field_mask);
// Wait till debounce time expires
cfg.clk_aon_rst_vif.wait_clks(10);
// Reset input
set_edge_detector_input(field_name);
// Wait for pulse width in case of ec_rst_l_h2l
if (field_name == "ec_rst_l_h2l") cfg.clk_aon_rst_vif.wait_clks(set_pulse_width + 10);
end
endtask
task auto_block_debounce_to_idle();
// Deassert key inputs
cfg.vif.key0_in = 1;
cfg.vif.key1_in = 1;
cfg.vif.key2_in = 1;
cfg.vif.pwrb_in = 1;
cfg.clk_aon_rst_vif.wait_clks(3);
// Set the auto block key
csr_wr(ral.auto_block_out_ctl, auto_block_out_ctl);
cfg.clk_aon_rst_vif.wait_clks(3);
// Enable the auto block key feature
ral.auto_block_debounce_ctl.auto_block_enable.set(1'b1);
ral.auto_block_debounce_ctl.debounce_timer.set(auto_block_debounce_ctl);
csr_update(ral.auto_block_debounce_ctl);
cfg.clk_aon_rst_vif.wait_clks(3);
// Assert key inputs
cfg.vif.key0_in = 0;
cfg.vif.key1_in = 0;
cfg.vif.key2_in = 0;
cfg.clk_aon_rst_vif.wait_clks(3);
fork
begin
// Scenario : assert pwrb_in and disable auto block before debounce time
// Assert pwrb_in
cfg.vif.pwrb_in = 0;
cfg.clk_aon_rst_vif.wait_clks(set_key_timer - 10);
// Disable auto block before debounce timer
ral.auto_block_debounce_ctl.auto_block_enable.set(1'b0);
csr_update(ral.auto_block_debounce_ctl);
cfg.clk_aon_rst_vif.wait_clks(10);
cfg.vif.pwrb_in = 1;
end
// Check for key outputs
begin
repeat (20) `DV_CHECK_EQ(cfg.vif.key0_in, cfg.vif.key0_out)
end
begin
repeat (20) `DV_CHECK_EQ(cfg.vif.key1_in, cfg.vif.key1_out)
end
begin
repeat (20) `DV_CHECK_EQ(cfg.vif.key2_in, cfg.vif.key2_out)
end
join
// Release key inputs
cfg.vif.key0_in = 0;
cfg.vif.key1_in = 0;
cfg.vif.key2_in = 0;
endtask
task drive_ac(uint16_t cycles);
cfg.vif.ac_present = 1;
cfg.clk_aon_rst_vif.wait_clks(cycles);
cfg.vif.ac_present = 0;
endtask
task drive_pwrb(uint16_t cycles);
cfg.vif.pwrb_in = 1;
cfg.clk_aon_rst_vif.wait_clks(1);
cfg.vif.pwrb_in = 0;
cfg.clk_aon_rst_vif.wait_clks(cycles);
cfg.vif.pwrb_in = 1;
endtask
task drive_lid(uint16_t cycles);
cfg.vif.lid_open = 0;
cfg.clk_aon_rst_vif.wait_clks(1);
cfg.vif.lid_open = 1;
cfg.clk_aon_rst_vif.wait_clks(cycles);
cfg.vif.lid_open = 0;
endtask
task ulp_debounce_to_idle();
`uvm_info(`gfn, "Executing task to trigger deebounce to idle state transition in ULP", UVM_LOW)
// Scenario: disable ULP feature before debounce timer
// Program ULP registers
// Set the debounce timer for pwrb_in, ac_present and lid_open
csr_wr(ral.ulp_ac_debounce_ctl, ulp_debounce_ctl);
csr_wr(ral.ulp_lid_debounce_ctl, ulp_debounce_ctl);
csr_wr(ral.ulp_pwrb_debounce_ctl, ulp_debounce_ctl);
// Enable ultra low power feature
ral.ulp_ctl.ulp_enable.set(1'b1);
csr_update(ral.ulp_ctl);
// Wait for registers to update
cfg.clk_aon_rst_vif.wait_clks(2);
// Drive ULP key inputs for debounce time and disable ULP before debounce time
fork
begin
drive_ac(ulp_debounce_ctl + 10);
end
begin
drive_pwrb(ulp_debounce_ctl + 10);
end
begin
drive_lid(ulp_debounce_ctl + 10);
end
begin
cfg.clk_aon_rst_vif.wait_clks(ulp_debounce_ctl - 10);
// Disable ultra low power feature
ral.ulp_ctl.ulp_enable.set(1'b0);
csr_update(ral.ulp_ctl);
cfg.clk_aon_rst_vif.wait_clks(2);
end
join
// Check ULP status
csr_rd_check(ral.ulp_status, .compare_value(0));
// Scenario: deassert input signal before debounce timer
// Enable ultra low power feature
ral.ulp_ctl.ulp_enable.set(1'b1);
csr_update(ral.ulp_ctl);
// It takes 2-3 clock cycles to sync the register values
cfg.clk_aon_rst_vif.wait_clks(2);
// Disable the bus clock
cfg.clk_rst_vif.stop_clk();
cfg.clk_aon_rst_vif.wait_clks(2);
// Drive ULP key inputs for debounce time and deassert before debounce time
fork
begin
drive_ac(ulp_debounce_ctl - 10);
end
begin
drive_pwrb(ulp_debounce_ctl - 10);
end
begin
drive_lid(ulp_debounce_ctl - 10);
end
join
// Enable the bus clock to read the status register
cfg.clk_rst_vif.start_clk();
// Check ULP status
csr_rd_check(ral.ulp_status, .compare_value(0));
// Disable ultra low power feature
ral.ulp_ctl.ulp_enable.set(1'b0);
csr_update(ral.ulp_ctl);
cfg.clk_aon_rst_vif.wait_clks(2);
endtask
task body();
`uvm_info(`gfn, "Starting the body from feature disable", UVM_LOW)
combo_debounce_to_idle();
combo_action_ec_rst_l_i_assert();
key_intr_debounce_to_idle();
auto_block_debounce_to_idle();
ulp_debounce_to_idle();
endtask
endclass : sysrst_ctrl_feature_disable_vseq