blob: 34031a4b82752f06f6baec2670fffd11934f3a33 [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 will write a random values to combo detect registers
// and check for the combo detect interrupt.
class sysrst_ctrl_combo_detect_vseq extends sysrst_ctrl_base_vseq;
`uvm_object_utils(sysrst_ctrl_combo_detect_vseq)
`uvm_object_new
rand uvm_reg_data_t set_action[4];
rand bit[4:0] trigger_combo[4];
rand uint16_t set_duration[4];
rand uint16_t set_pulse_width, set_key_timer;
rand uint16_t cycles;
constraint num_trans_c {num_trans == 20;}
constraint set_duration_c {
foreach (set_duration[i]) {
set_duration[i] dist {
[10:100] :/ 95,
[101:300] :/ 5
};
}
}
constraint set_pulse_width_c {
set_pulse_width dist {
[10:100] :/ 95,
[101: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:100] :/ 95,
[101:300] :/ 5
};
}
constraint cycles_c {
foreach (set_duration[i]) {
cycles dist {
[1 : (set_duration[i] + set_key_timer) - 2] :/ 20,
[(set_duration[i] + set_key_timer) + 5 : (set_duration[i] + set_key_timer) * 2] :/ 80
};
// Don't fall into this uncerntain period.
!(cycles inside {[(set_duration[i] + set_key_timer) - 1 :
(set_duration[i] + set_key_timer) + 5]});
}
}
function bit get_combo_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;
return ((in & trigger_combo[index]) == 0) && (trigger_combo[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();
// Disable the override function
ral.pin_out_ctl.ec_rst_l.set(0);
csr_update(ral.pin_out_ctl);
// 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
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];
uint16_t [3:0] set_duration;
uint16_t [3:0] get_duration;
uvm_reg_data_t [3:0] get_action;
bit[4:0] get_trigger_combo[4];
bit [4:0] get_trigger_combo_pre[4];
`uvm_info(`gfn, "Starting the body from combo detect", UVM_LOW)
// 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_inputs();
config_register();
// It takes 2-3 clock cycles to sync the register values
cfg.clk_aon_rst_vif.wait_clks(3);
repeat (num_trans) begin
bit bat_act_triggered, ec_act_triggered, rst_act_triggered;
bit current_bat_act, current_ec_act, current_rst_act;
bit [3:0] intr_actions, intr_actions_pre_reset;
int ec_act_occur_cyc = 0;
repeat ($urandom_range(1, 2)) begin
// Trigger the input pins
cfg.clk_aon_rst_vif.wait_clks(1);
cfg.vif.randomize_combo_input();
end
// Wait for debounce + detect timer
cfg.clk_aon_rst_vif.wait_clks(cycles);
// Latch the trigger value before resetting the input pins
foreach (triggered[i]) triggered[i] = get_combo_trigger(i);
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
// Sample the combo_intr_status covergroup to capture the trigger combo inputs
// before resetting the combo inputs.
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_pre_reset
);
end
reset_combo_inputs();
`uvm_info(`gfn, $sformatf("Value of cycles:%0d", cycles), UVM_LOW)
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]);
// Check if the interrupt has raised.
// NOTE: The interrupt will only raise if the interrupt combo action is set.
for (int i = 0; i <= 3; i++) begin
if (cycles > (get_duration[i] + set_key_timer) && triggered[i]) begin
intr_actions[i] = get_field_val(ral.com_out_ctl[i].interrupt, get_action[i]);
current_bat_act = get_field_val(ral.com_out_ctl[i].bat_disable, get_action[i]);
current_ec_act = get_field_val(ral.com_out_ctl[i].ec_rst, get_action[i]);
current_rst_act = get_field_val(ral.com_out_ctl[i].rst_req, get_action[i]);
bat_act_triggered |= current_bat_act;
ec_act_triggered |= current_ec_act;
rst_act_triggered |= current_rst_act;
if (cfg.en_cov) begin
cov.combo_detect_action[i].sysrst_ctrl_combo_detect_action_cg.sample(
current_bat_act,
intr_actions[i],
current_ec_act,
current_rst_act,
get_field_val(ral.com_sel_ctl[i].key0_in_sel, get_trigger_combo[i]),
get_field_val(ral.com_sel_ctl[i].key1_in_sel, get_trigger_combo[i]),
get_field_val(ral.com_sel_ctl[i].key2_in_sel, get_trigger_combo[i]),
get_field_val(ral.com_sel_ctl[i].pwrb_in_sel, get_trigger_combo[i]),
get_field_val(ral.com_sel_ctl[i].ac_present_sel, get_trigger_combo[i]),
get_field_val(ral.com_pre_sel_ctl[i].key0_in_sel, get_trigger_combo_pre[i]),
get_field_val(ral.com_pre_sel_ctl[i].key1_in_sel, get_trigger_combo_pre[i]),
get_field_val(ral.com_pre_sel_ctl[i].key2_in_sel, get_trigger_combo_pre[i]),
get_field_val(ral.com_pre_sel_ctl[i].pwrb_in_sel, get_trigger_combo_pre[i]),
get_field_val(ral.com_pre_sel_ctl[i].ac_present_sel, get_trigger_combo_pre[i])
);
cov.combo_key_combinations.sysrst_ctrl_combo_key_combinations_cg.sample(
current_bat_act,
intr_actions[i],
current_ec_act,
current_rst_act,
get_field_val(ral.com_sel_ctl[i].key0_in_sel, get_trigger_combo[i]),
get_field_val(ral.com_sel_ctl[i].key1_in_sel, get_trigger_combo[i]),
get_field_val(ral.com_sel_ctl[i].key2_in_sel, get_trigger_combo[i]),
get_field_val(ral.com_sel_ctl[i].pwrb_in_sel, get_trigger_combo[i]),
get_field_val(ral.com_sel_ctl[i].ac_present_sel, get_trigger_combo[i]),
get_field_val(ral.com_pre_sel_ctl[i].key0_in_sel, get_trigger_combo_pre[i]),
get_field_val(ral.com_pre_sel_ctl[i].key1_in_sel, get_trigger_combo_pre[i]),
get_field_val(ral.com_pre_sel_ctl[i].key2_in_sel, get_trigger_combo_pre[i]),
get_field_val(ral.com_pre_sel_ctl[i].pwrb_in_sel, get_trigger_combo_pre[i]),
get_field_val(ral.com_pre_sel_ctl[i].ac_present_sel, get_trigger_combo_pre[i])
);
end
if (get_field_val(ral.com_out_ctl[i].ec_rst, get_action[i])) begin
ec_act_triggered = 1;
// Record which cycle the ec_rst occurs, just need to know the last combo that triggers
// the ec_rst
ec_act_occur_cyc = max2(ec_act_occur_cyc, get_duration[i] + set_key_timer);
end
end
end
if (ec_act_triggered) begin
// We don't check ec_rst_pulse right after it occurs. past_cycles indicates how many
// cycles the pulse has been active.
// -2 is because cross clock domaim make take ~2 cycles.
int past_cycles = cycles - ec_act_occur_cyc - 2;
monitor_ec_rst_low(set_pulse_width - past_cycles);
end else begin
check_ec_rst_inactive(set_pulse_width);
`DV_CHECK_EQ(cfg.vif.ec_rst_l_out, 1);
end
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
// If bat_disable trigger action is set then check if there is a transition
// on cio_bat_disable_o signal.
if (bat_act_triggered) begin
`DV_CHECK_EQ(cfg.vif.bat_disable, 1);
end else begin
`DV_CHECK_EQ(cfg.vif.bat_disable, 0);
end
// If reset req trigger action is set then check if there is a event
// on aon_rst_req_o pin.
if (rst_act_triggered) begin
`DV_CHECK_EQ(cfg.vif.rst_req, 1);
end else begin
`DV_CHECK_EQ(cfg.vif.rst_req, 0);
end
if (bat_act_triggered || rst_act_triggered) begin
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();
end
cfg.clk_aon_rst_vif.wait_clks(10);
end
endtask : body
endclass : sysrst_ctrl_combo_detect_vseq