[gpio dv] GPIO Functional Coverage Updates
1. cip_base_env_cov.sv: Common covergroup for interrupt pins
2. gpio_env_cov.sv: Optimize covergroup creation part by
enclosing covergroups definitions inside dedicated class,
and having arrrays of each class type on per pin, per
register name basis.
3. gpio_scoreboard.sv: Modified coverage sampling based on
above changes.
4. gpio_base_vseq.sv: Specify function set_gpio_pulls() to be
of void return type.
diff --git a/hw/dv/sv/cip_lib/cip_base_env_cov.sv b/hw/dv/sv/cip_lib/cip_base_env_cov.sv
index 8d3e16c..ca02b55 100644
--- a/hw/dv/sv/cip_lib/cip_base_env_cov.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env_cov.sv
@@ -29,9 +29,22 @@
cross cp_intr, cp_intr_test, cp_intr_en, cp_intr_state {
illegal_bins test_0_state_1 = binsof(cp_intr_test) intersect {0} &&
binsof(cp_intr_state) intersect {1};
+ illegal_bins test_1_state_0 = binsof(cp_intr_test) intersect {1} &&
+ binsof(cp_intr_state) intersect {0};
}
endgroup
+covergroup intr_pins_covergroup (uint num_interrupts) with function sample(uint intr_pin, bit intr_pin_value);
+ cp_intr_pin: coverpoint intr_pin {
+ bins all_pins[] = {[0:num_interrupts-1]};
+ }
+ cp_intr_pin_value: coverpoint intr_pin_value {
+ bins values[] = {0, 1};
+ bins transitions[] = (0 => 1), (1 => 0);
+ }
+ cp_intr_pins_all_values: cross cp_intr_pin, cp_intr_pin_value;
+endgroup
+
covergroup alert_covergroup (uint num_alerts) with function sample(uint alert);
cp_alert: coverpoint alert {
bins all_values[] = {[0:num_alerts-1]};
@@ -43,6 +56,7 @@
intr_covergroup intr_cg;
intr_test_covergroup intr_test_cg;
+ intr_pins_covergroup intr_pins_cg;
alert_covergroup alert_cg;
`uvm_component_new
@@ -50,8 +64,9 @@
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (cfg.num_interrupts != 0) begin
- intr_cg = new(cfg.num_interrupts);
- intr_test_cg = new(cfg.num_interrupts);
+ intr_cg = new(cfg.num_interrupts);
+ intr_test_cg = new(cfg.num_interrupts);
+ intr_pins_cg = new(cfg.num_interrupts);
end
if (cfg.num_alerts != 0) alert_cg = new(cfg.num_alerts);
endfunction
diff --git a/hw/ip/gpio/dv/env/gpio_env_cov.sv b/hw/ip/gpio/dv/env/gpio_env_cov.sv
index 0db3496..4dff5c3 100644
--- a/hw/ip/gpio/dv/env/gpio_env_cov.sv
+++ b/hw/ip/gpio/dv/env/gpio_env_cov.sv
@@ -2,64 +2,139 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-// Generic covergroup definitions
-covergroup gpio_generic_cg(string name) with function sample(bit value);
- option.per_instance = 1;
- option.name = name;
- cp_value: coverpoint value;
- cp_transitions: coverpoint value {
- bins rising = (0 => 1);
- bins falling = (1 => 0);
- }
-endgroup : gpio_generic_cg
+class gpio_generic_cov_obj extends uvm_object;
+ `uvm_object_utils(gpio_generic_cov_obj)
-covergroup gpio_intr_type_en_state_cg(string name) with function sample(bit intr_type,
- bit intr_en,
- bit intr_state);
- option.per_instance = 1;
- option.name = name;
- cp_cross_intr_type_en_state: cross intr_type, intr_en, intr_state {
- ignore_bins intr_type_disabled = binsof(intr_type) intersect {0};
- }
-endgroup : gpio_intr_type_en_state_cg
+ // Covergroup: generic_cg
+ // Generic covergroup definition
+ covergroup generic_cg(string name) with function sample(bit value);
+ option.per_instance = 1;
+ option.name = name;
+ cp_value: coverpoint value;
+ cp_transitions: coverpoint value {
+ bins rising = (0 => 1);
+ bins falling = (1 => 0);
+ }
+ endgroup : generic_cg
+
+ // Function: new
+ function new(string name="gpio_generic_cov");
+ super.new(name);
+ generic_cg = new(name);
+ endfunction : new
+
+endclass : gpio_generic_cov_obj
+
+class gpio_intr_type_cov_obj extends uvm_object;
+ `uvm_object_utils(gpio_intr_type_cov_obj)
+
+ // Covergroup: intr_type_cg
+ // Covergroup for different interrupt types based on "Interrupt Control" registers in
+ // gpio. This group samples combination of interrupt type, interrupt enable and
+ // interrupt state, on per bit basis.
+ covergroup intr_type_cg(string name) with function sample(bit type_ctrl_en,
+ bit intr_en,
+ bit intr_state);
+ option.per_instance = 1;
+ option.name = name;
+ cp_cross_type_en_state: cross type_ctrl_en, intr_en, intr_state {
+ ignore_bins intr_type_disabled = binsof(type_ctrl_en) intersect {0};
+ }
+ endgroup : intr_type_cg
+
+ // Function: new
+ function new(string name="gpio_intr_type_cov_obj");
+ super.new(name);
+ intr_type_cg = new(name);
+ endfunction : new
+endclass : gpio_intr_type_cov_obj
+
+class gpio_two_vars_generic_cov_obj extends uvm_object;
+ `uvm_object_utils(gpio_two_vars_generic_cov_obj)
+
+ // Covergroup: var1_var2_cg
+ // Generic covergroup that samples two bit variables and
+ // looks for their individual coverage as well as cross coverage.
+ covergroup var1_var2_cg(string name) with function sample(bit var1, bit var2);
+ option.per_instance = 1;
+ option.name = name;
+ cp_var1: coverpoint var1;
+ cp_var2: coverpoint var2;
+ cp_var1_var2_cross: cross cp_var1, cp_var2;
+ endgroup : var1_var2_cg
+
+ // Function: new
+ function new(string name="gpio_two_vars_generic_cov_obj");
+ super.new(name);
+ var1_var2_cg = new(name);
+ endfunction : new
+endclass : gpio_two_vars_generic_cov_obj
class gpio_env_cov extends cip_base_env_cov #(.CFG_T(gpio_env_cfg));
`uvm_component_utils(gpio_env_cov)
- // Per pin coverage for values '0' and '1' and transitions
- gpio_generic_cg gpio_pin_values_cg[NUM_GPIOS];
+ // Array of coverage objects for per pin coverage for gpio pin values
+ gpio_generic_cov_obj gpio_pin_values_cov_obj[NUM_GPIOS];
// Interrupt State (Interrupt bit getting set and cleared)
- gpio_generic_cg intr_state_cg[TL_DW];
+ gpio_generic_cov_obj intr_state_cov_obj[NUM_GPIOS];
// Interrupt Control Enable registers' values
- gpio_generic_cg intr_ctrl_en_rising_cg[TL_DW];
- gpio_generic_cg intr_ctrl_en_falling_cg[TL_DW];
- gpio_generic_cg intr_ctrl_en_lvlhigh_cg[TL_DW];
- gpio_generic_cg intr_ctrl_en_lvllow_cg[TL_DW];
+ gpio_generic_cov_obj intr_ctrl_en_cov_objs[NUM_GPIOS][string];
// Different gpio interrupt types' occurrences
- gpio_intr_type_en_state_cg rising_edge_intr_event_cg[TL_DW];
- gpio_intr_type_en_state_cg falling_edge_intr_event_cg[TL_DW];
- gpio_intr_type_en_state_cg lvlhigh_intr_event_cg[TL_DW];
- gpio_intr_type_en_state_cg lvllow_intr_event_cg[TL_DW];
+ gpio_intr_type_cov_obj intr_event_type_cov_objs[NUM_GPIOS][string];
+ // Per bit coverage on *out* and *oe* registers
+ gpio_generic_cov_obj out_oe_cov_objs[NUM_GPIOS][string];
+
+ // Coverage on data and mask fields of masked* registers
+ gpio_two_vars_generic_cov_obj out_oe_mask_data_cov_objs[NUM_GPIOS/2][string];
+ // Coverage on effective values of DATA_OUT and DATA_OE
+ gpio_two_vars_generic_cov_obj data_out_data_oe_cov_obj[NUM_GPIOS];
+ // data_in register per bit value coverage
+ gpio_generic_cov_obj data_in_cov_obj[NUM_GPIOS];
function new(string name, uvm_component parent);
super.new(name, parent);
- // Create coverage for each gpio pin value
- foreach (gpio_pin_values_cg[each_pin]) begin
- gpio_pin_values_cg [each_pin] = new($sformatf("gpio_pin-%0d", each_pin));
- end
- // Create coverage for interrupt control policies and state
- for (uint each_bit = 0; each_bit < TL_DW; each_bit++) begin
- intr_state_cg[each_bit] = new($sformatf("intr_state_cg%0d", each_bit));
- intr_ctrl_en_rising_cg[each_bit] = new($sformatf("intr_ctrl_en_rising_cg%0d", each_bit));
- intr_ctrl_en_falling_cg[each_bit] = new($sformatf("intr_ctrl_en_falling_cg%0d", each_bit));
- intr_ctrl_en_lvlhigh_cg[each_bit] = new($sformatf("intr_ctrl_en_lvlhigh_cg%0d", each_bit));
- intr_ctrl_en_lvllow_cg [each_bit] = new($sformatf("intr_ctrl_en_lvllow_cg%0d", each_bit));
- rising_edge_intr_event_cg[each_bit] = new($sformatf("rising_edge_intr_event_cg%0d",
- each_bit));
- falling_edge_intr_event_cg[each_bit] = new($sformatf("falling_edge_intr_event_cg%0d",
- each_bit));
- lvlhigh_intr_event_cg[each_bit] = new($sformatf("lvlhigh_intr_event_cg%0d", each_bit));
- lvllow_intr_event_cg[each_bit] = new($sformatf("lvllow_intr_event_cg%0d", each_bit));
+ begin
+ string intr_types[4] = '{"rising", "falling", "lvlhigh", "lvllow"};
+ string out_oe_reg_names[6] = '{"direct_out",
+ "direct_oe",
+ "masked_out_lower",
+ "masked_oe_lower",
+ "masked_out_upper",
+ "masked_oe_upper"};
+ foreach (intr_state_cov_obj[each_pin]) begin
+ // Create coverage for each gpio pin values and transitions
+ gpio_pin_values_cov_obj[each_pin] = new($sformatf("gpio_values_cov_obj_pin%0d", each_pin));
+ // Create per pin coverage for interrupt state values and transitions
+ intr_state_cov_obj[each_pin] = new($sformatf("intr_state_cov_obj_pin%0d", each_pin));
+ // Create per pin coverage interrupts
+ foreach(intr_types[each_type]) begin
+ // Per pin coverage for "Intrrupt Control Enable" values
+ // and transitions for each type of interrupt
+ intr_ctrl_en_cov_objs[each_pin][{"intr_ctrl_en_", intr_types[each_type]}] =
+ new({"intr_ctrl_en_", intr_types[each_type], $sformatf("_pin%0d_cov", each_pin)});
+ // Per pin coverage for different types of interrupt event occurrences
+ intr_event_type_cov_objs[each_pin][{"intr_event_", intr_types[each_type]}] =
+ new({"intr_event_", intr_types[each_type], $sformatf("_pin%0d", each_pin)});
+ end
+ // Per pin coverage for values of different *out* and *oe* registers
+ foreach (out_oe_reg_names[each_reg]) begin
+ out_oe_cov_objs[each_pin][out_oe_reg_names[each_reg]] =
+ new({out_oe_reg_names[each_reg], $sformatf("_cov_obj_pin%0d", each_pin)});
+ end
+ data_out_data_oe_cov_obj[each_pin] = new($sformatf("data_out_data_oe_cov_obj_pin%0d",
+ each_pin));
+ data_in_cov_obj[each_pin] = new($sformatf("data_in_cov_obj_pin%0d", each_pin));
+ end
+ // Per pin coverage and cross coverage for mask and data
+ // fields within masked_* registers
+ foreach (out_oe_mask_data_cov_objs[each_pin]) begin
+ foreach (out_oe_reg_names[each_reg]) begin
+ if (!uvm_re_match("masked*", out_oe_reg_names[each_reg])) begin
+ out_oe_mask_data_cov_objs[each_pin][out_oe_reg_names[each_reg]] =
+ new({out_oe_reg_names[each_reg], $sformatf("_mask_data_cov_obj_pin%0d", each_pin)});
+ end
+ end
+ end
end
endfunction : new
diff --git a/hw/ip/gpio/dv/env/gpio_scoreboard.sv b/hw/ip/gpio/dv/env/gpio_scoreboard.sv
index 5fe1b23..7a83581 100644
--- a/hw/ip/gpio/dv/env/gpio_scoreboard.sv
+++ b/hw/ip/gpio/dv/env/gpio_scoreboard.sv
@@ -40,7 +40,10 @@
// Task: run_phase
task run_phase(uvm_phase phase);
super.run_phase(phase);
- monitor_gpio_i();
+ fork
+ monitor_gpio_i();
+ monitor_gpio_interrupt_pins();
+ join_none
endtask
// Task : process_tl_access
@@ -114,8 +117,9 @@
intr_state_write_to_clear_update.reg_value[each_bit] == 1'b1 &&
item.a_data[each_bit] == 1'b1) begin
intr_state_write_to_clear_update.reg_value[each_bit] = 1'b0;
+ // Coverage Sampling: gpio interrupt cleared
if (cfg.en_cov) begin
- cov.intr_state_cg[each_bit].sample(1'b0);
+ cov.intr_state_cov_obj[each_bit].generic_cg.sample(1'b0);
end
end
end
@@ -140,6 +144,25 @@
if (csr.get_name() == "intr_test") begin
// Store the written value as it is WO register
last_intr_test_event = item.a_data;
+ end else begin
+ // Coverage Sampling: coverage on *out* and *oe* register values
+ if (cfg.en_cov && (!uvm_re_match("*out*", csr.get_name()) ||
+ !uvm_re_match("*oe*", csr.get_name()))) begin
+ for (uint each_pin = 0; each_pin < NUM_GPIOS; each_pin++) begin
+
+ cov.out_oe_cov_objs[each_pin][csr.get_name()].generic_cg.sample(
+ item.a_data[each_pin]);
+ end
+ // Coverage Sampling: Cross coverage on mask and data within masked_* registers
+ if (!uvm_re_match("masked*", csr.get_name())) begin
+ bit [(NUM_GPIOS/2) - 1:0] mask, data;
+ {mask, data} = item.d_data;
+ for (uint each_pin = 0; each_pin < NUM_GPIOS/2; each_pin++) begin
+ cov.out_oe_mask_data_cov_objs[each_pin][csr.get_name()].var1_var2_cg.sample(
+ mask[each_pin], data[each_pin]);
+ end
+ end
+ end
end
csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask));
end
@@ -176,10 +199,10 @@
`uvm_info(`gfn, $sformatf("cfg.gpio_vif.pins = %0h, under_reset = %0b",
cfg.gpio_vif.pins, under_reset), UVM_HIGH)
if (under_reset == 1'b0) begin
- // Coverage Sampling-1: gpio pin values' coverage
+ // Coverage Sampling: gpio pin values' coverage
if (cfg.en_cov) begin
- foreach (cov.gpio_pin_values_cg[each_pin]) begin
- cov.gpio_pin_values_cg[each_pin].sample(cfg.gpio_vif.pins[each_pin]);
+ foreach (cov.gpio_pin_values_cov_obj[each_pin]) begin
+ cov.gpio_pin_values_cov_obj[each_pin].generic_cg.sample(cfg.gpio_vif.pins[each_pin]);
end
end
// evaluate gpio input driven to dut
@@ -271,6 +294,22 @@
endtask : monitor_gpio_i
+ // Task: monitor_gpio_interrupt_pins
+ virtual task monitor_gpio_interrupt_pins();
+ forever begin : monitor_gpio_intr
+ @(cfg.intr_vif.pins or under_reset) begin
+ if (under_reset == 0) begin
+ if (cfg.en_cov) begin
+ // Coverage Sampling: gpio interrupt pin values and transitions
+ for (uint each_pin = 0; each_pin < NUM_GPIOS; each_pin++) begin
+ cov.intr_pins_cg.sample(each_pin, cfg.intr_vif.pins[each_pin]);
+ end
+ end
+ end
+ end
+ end
+ endtask : monitor_gpio_interrupt_pins
+
// Function: actual_gpio_i_activity
function bit actual_gpio_i_activity();
return ~((prv_gpio_i_pins_o === cfg.gpio_vif.pins_o) &&
@@ -454,6 +493,12 @@
current_data_in_update.reg_value = pred_val_gpio_pins;
current_data_in_update.eval_time = $time;
data_in_update_queue.push_back(current_data_in_update);
+ // Coverage Sampling: data_in register coverage
+ if (cfg.en_cov) begin
+ for (uint each_bit = 0; each_bit < NUM_GPIOS; each_bit++) begin
+ cov.data_in_cov_obj[each_bit].generic_cg.sample(pred_val_gpio_pins[each_bit]);
+ end
+ end
end
// If update was due to register write, we can call predict right away
if (csr != null) begin
@@ -497,13 +542,17 @@
end
end
- // Coverage Sampling-2: gpio interrupt types
+ // Coverage Sampling: gpio interrupt types
if (cfg.en_cov) begin
foreach (intr_ctrl_en_rising[each_bit]) begin
- cov.intr_ctrl_en_rising_cg [each_bit].sample(intr_ctrl_en_rising[each_bit]);
- cov.intr_ctrl_en_falling_cg[each_bit].sample(intr_ctrl_en_falling[each_bit]);
- cov.intr_ctrl_en_lvlhigh_cg[each_bit].sample(intr_ctrl_en_lvlhigh[each_bit]);
- cov.intr_ctrl_en_lvllow_cg [each_bit].sample(intr_ctrl_en_lvllow[each_bit]);
+ cov.intr_ctrl_en_cov_objs[each_bit]["intr_ctrl_en_rising"].generic_cg.sample(
+ intr_ctrl_en_rising[each_bit]);
+ cov.intr_ctrl_en_cov_objs[each_bit]["intr_ctrl_en_falling"].generic_cg.sample(
+ intr_ctrl_en_falling[each_bit]);
+ cov.intr_ctrl_en_cov_objs[each_bit]["intr_ctrl_en_lvlhigh"].generic_cg.sample(
+ intr_ctrl_en_lvlhigh[each_bit]);
+ cov.intr_ctrl_en_cov_objs[each_bit]["intr_ctrl_en_lvllow"].generic_cg.sample(
+ intr_ctrl_en_lvllow[each_bit]);
// Interrupt Test coverage
cov.intr_test_cg.sample(each_bit,
last_intr_test_event[each_bit],
@@ -535,15 +584,18 @@
end
end
end
- // Cross coverage of (edge tiggered intr type)x(enable)x(state) when type is enabled
+ // Coverage Sampling: Cross coverage of (edge tiggered intr type)x(enable)x(state)
+ // when type is enabled
if (cfg.en_cov) begin
foreach (rising_edge_intr_events[each_bit]) begin
- cov.rising_edge_intr_event_cg[each_bit].sample(intr_ctrl_en_rising[each_bit],
- intr_enable[each_bit],
- rising_edge_intr_events[each_bit]);
- cov.falling_edge_intr_event_cg[each_bit].sample(intr_ctrl_en_falling[each_bit],
- intr_enable[each_bit],
- falling_edge_intr_events[each_bit]);
+ cov.intr_event_type_cov_objs[each_bit]["intr_event_rising"].intr_type_cg.sample(
+ intr_ctrl_en_rising[each_bit],
+ intr_enable[each_bit],
+ rising_edge_intr_events[each_bit]);
+ cov.intr_event_type_cov_objs[each_bit]["intr_event_falling"].intr_type_cg.sample(
+ intr_ctrl_en_falling[each_bit],
+ intr_enable[each_bit],
+ falling_edge_intr_events[each_bit]);
end
end
end
@@ -565,24 +617,30 @@
end
end
end
- // Cross coverage of (edge tiggered intr type)x(enable)x(state) when type is enabled
+ // Coverage Sampling: Cross coverage of (edge tiggered intr type)x(enable)x(state)
+ // when type is enabled
if (cfg.en_cov) begin
foreach (lvlhigh_intr_events[each_bit]) begin
- cov.lvlhigh_intr_event_cg[each_bit].sample(intr_ctrl_en_lvlhigh[each_bit],
- intr_enable[each_bit],
- lvlhigh_intr_events[each_bit]);
- cov.lvllow_intr_event_cg[each_bit].sample(intr_ctrl_en_lvllow[each_bit],
- intr_enable[each_bit],
- lvllow_intr_events[each_bit]);
+ cov.intr_event_type_cov_objs[each_bit]["intr_event_lvlhigh"].intr_type_cg.sample(
+ intr_ctrl_en_lvlhigh[each_bit],
+ intr_enable[each_bit],
+ lvlhigh_intr_events[each_bit]);
+ cov.intr_event_type_cov_objs[each_bit]["intr_event_lvllow"].intr_type_cg.sample(
+ intr_ctrl_en_lvllow[each_bit],
+ intr_enable[each_bit],
+ lvllow_intr_events[each_bit]);
end
end
end
// 3. Apply effect of "Interrupt Test"
exp_intr_status |= last_intr_test_event;
+ // Coverage Sampling: Coverage on Interrupt Index, Interrupt Enable,
+ // Interrupt Status and their cross coverage
if (cfg.en_cov) begin
foreach (exp_intr_status[each_bit]) begin
cov.intr_cg.sample(each_bit, intr_enable[each_bit], exp_intr_status[each_bit]);
- cov.intr_state_cg[each_bit].sample(last_intr_update_except_clearing[each_bit]);
+ cov.intr_state_cov_obj[each_bit].generic_cg.sample(
+ last_intr_update_except_clearing[each_bit]);
end
end
// Clear last_intr_test_event
@@ -634,6 +692,8 @@
end
ral.masked_out_upper.mask.predict(.value(mask), .kind(UVM_PREDICT_WRITE));
ral.masked_out_upper.data.predict(.value(data), .kind(UVM_PREDICT_WRITE));
+ // Coverage Sampling: Coverage on DATA_OUT values and its combinations with DATA_OE
+ sample_data_out_data_oe_coverage();
endfunction : update_gpio_out_regs
// Function : update_gpio_oe_regs
@@ -661,8 +721,20 @@
end
ral.masked_oe_upper.mask.predict(.value(mask), .kind(UVM_PREDICT_WRITE));
ral.masked_oe_upper.data.predict(.value(data), .kind(UVM_PREDICT_WRITE));
+ // Coverage Sampling: Coverage on DATA_OUT values and its combinations with DATA_OE
+ sample_data_out_data_oe_coverage();
endfunction : update_gpio_oe_regs
+ // Function: sample_data_out_data_oe_coverage
+ function void sample_data_out_data_oe_coverage();
+ if (cfg.en_cov) begin
+ for (uint each_bit = 0; each_bit < NUM_GPIOS; each_bit++) begin
+ cov.data_out_data_oe_cov_obj[each_bit].var1_var2_cg.sample(data_out[each_bit],
+ data_oe[each_bit]);
+ end
+ end
+ endfunction : sample_data_out_data_oe_coverage
+
// Function: reset
virtual function void reset(string kind = "HARD");
super.reset(kind);
diff --git a/hw/ip/gpio/dv/env/seq_lib/gpio_base_vseq.sv b/hw/ip/gpio/dv/env/seq_lib/gpio_base_vseq.sv
index 69c5bcf..7db4e09 100644
--- a/hw/ip/gpio/dv/env/seq_lib/gpio_base_vseq.sv
+++ b/hw/ip/gpio/dv/env/seq_lib/gpio_base_vseq.sv
@@ -34,7 +34,7 @@
// from extended sequence.
// Note: This function does not check whether only one of 'pu' and 'pd' is passed 1.
// If we pass both pu and pd to be 1, gpio pullup will be used.
- protected function set_gpio_pulls(bit pu = 1'b1, bit pd = 1'b0);
+ protected function void set_gpio_pulls(bit pu = 1'b1, bit pd = 1'b0);
bit no_pullup_pulldown;
cfg.pullup_en = pu;
cfg.pulldown_en = pd;