[gpio dv] First set of functional coverage for gpio
1. cip_base_env_cov.sv: Update common interrupt covergroup to include intr_state
2. gpio_env_cov.sv: Some functional coverage for gpio pin activity and interrupts
3. gpio_scoreboard.sv: Sampling of implemented coverage
4. uart_scoreboard.sv: Updated sampling of interrupt covergroup
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 10695f7..8d3e16c 100644
--- a/hw/dv/sv/cip_lib/cip_base_env_cov.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env_cov.sv
@@ -5,12 +5,31 @@
// put these covergoups outside the class in order to create them anywhere after get cfg object
// if more than one interrupt/alert registers, these can be reused
// in extended cov class, better to have the covergroup inside the class and create in new function
-covergroup intr_covergroup (uint num_interrupts) with function sample(uint intr, bit intr_en);
+covergroup intr_covergroup (uint num_interrupts) with function sample(uint intr,
+ bit intr_en,
+ bit intr_state);
cp_intr: coverpoint intr {
bins all_values[] = {[0:num_interrupts-1]};
}
cp_intr_en: coverpoint intr_en;
- cross cp_intr, cp_intr_en;
+ cp_intr_state: coverpoint intr_state;
+ cross cp_intr, cp_intr_en, cp_intr_state;
+endgroup
+
+covergroup intr_test_covergroup (uint num_interrupts) with function sample(uint intr,
+ bit intr_test,
+ bit intr_en,
+ bit intr_state);
+ cp_intr: coverpoint intr {
+ bins all_values[] = {[0:num_interrupts-1]};
+ }
+ cp_intr_test: coverpoint intr_test;
+ cp_intr_en: coverpoint intr_en;
+ cp_intr_state: coverpoint intr_state;
+ 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};
+ }
endgroup
covergroup alert_covergroup (uint num_alerts) with function sample(uint alert);
@@ -22,15 +41,19 @@
class cip_base_env_cov #(type CFG_T = cip_base_env_cfg) extends dv_base_env_cov #(CFG_T);
`uvm_component_param_utils(cip_base_env_cov #(CFG_T))
- intr_covergroup intr_cg;
- alert_covergroup alert_cg;
+ intr_covergroup intr_cg;
+ intr_test_covergroup intr_test_cg;
+ alert_covergroup alert_cg;
`uvm_component_new
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
- if (cfg.num_interrupts != 0) intr_cg = new(cfg.num_interrupts);
- if (cfg.num_alerts != 0) alert_cg = new(cfg.num_alerts);
+ if (cfg.num_interrupts != 0) begin
+ intr_cg = new(cfg.num_interrupts);
+ intr_test_cg = new(cfg.num_interrupts);
+ end
+ if (cfg.num_alerts != 0) alert_cg = new(cfg.num_alerts);
endfunction
endclass
diff --git a/hw/ip/gpio/dv/env/gpio_env_cfg.sv b/hw/ip/gpio/dv/env/gpio_env_cfg.sv
index 52093cf..9208089 100644
--- a/hw/ip/gpio/dv/env/gpio_env_cfg.sv
+++ b/hw/ip/gpio/dv/env/gpio_env_cfg.sv
@@ -10,10 +10,10 @@
// flag to indicate if weak pulldown has been introduced on gpio
rand bit pulldown_en;
// gpio virtual interface
- gpio_vif gpio_vif;
+ gpio_vif gpio_vif;
constraint pullup_pulldown_en_c {
- (pullup_en ^ pulldown_en) == 1'b1;
+ pullup_en ^ pulldown_en;
}
`uvm_object_utils(gpio_env_cfg)
diff --git a/hw/ip/gpio/dv/env/gpio_env_cov.sv b/hw/ip/gpio/dv/env/gpio_env_cov.sv
index 62ab507..0db3496 100644
--- a/hw/ip/gpio/dv/env/gpio_env_cov.sv
+++ b/hw/ip/gpio/dv/env/gpio_env_cov.sv
@@ -2,12 +2,65 @@
// 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
+
+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
+
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];
+ // Interrupt State (Interrupt bit getting set and cleared)
+ gpio_generic_cg intr_state_cg[TL_DW];
+ // 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];
+ // 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];
+
function new(string name, uvm_component parent);
super.new(name, parent);
- // add more covergroup here
+ // 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));
+ end
endfunction : new
endclass
diff --git a/hw/ip/gpio/dv/env/gpio_scoreboard.sv b/hw/ip/gpio/dv/env/gpio_scoreboard.sv
index 6514f31..b9d64ea 100644
--- a/hw/ip/gpio/dv/env/gpio_scoreboard.sv
+++ b/hw/ip/gpio/dv/env/gpio_scoreboard.sv
@@ -114,6 +114,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;
+ if (cfg.en_cov) begin
+ cov.intr_state_cg[each_bit].sample(1'b0);
+ end
end
end
// If same time stamp as last entry, update entry to account for "still active" event
@@ -149,6 +152,12 @@
if (do_read_check) begin
// Checker-2: Check if reg read data matches expected value or not
`DV_CHECK_EQ(csr.get_mirrored_value(), item.d_data)
+ // Checker-3: Check value of interrupt pins against predicted value
+ if (csr.get_name() == "intr_state") begin
+ bit [TL_DW-1:0] pred_val_intr_pins = csr.get_mirrored_value() &
+ ral.intr_enable.get_mirrored_value();
+ `DV_CHECK_EQ(cfg.intr_vif.pins, pred_val_intr_pins)
+ end
end
end // if (write == 0)
end
@@ -164,6 +173,12 @@
`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
+ 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]);
+ end
+ end
// evaluate gpio input driven to dut
foreach (cfg.gpio_vif.pins_oe[pin_num]) begin
if (cfg.gpio_vif.pins_oe[pin_num] == 1'b1) begin
@@ -460,57 +475,113 @@
input gpio_transition_t [NUM_GPIOS-1:0] gpio_i_transition = {NUM_GPIOS{2'b00}});
string msg_id = {`gfn, $sformatf(" gpio_interrupt_predict: ")};
- bit [NUM_GPIOS-1:0] intr_state = ral.intr_state.get_mirrored_value();
- bit [NUM_GPIOS-1:0] intr_ctrl_en_rising = ral.intr_ctrl_en_rising.get_mirrored_value();
- bit [NUM_GPIOS-1:0] intr_ctrl_en_falling = ral.intr_ctrl_en_falling.get_mirrored_value();
- bit [NUM_GPIOS-1:0] intr_ctrl_en_lvlhigh = ral.intr_ctrl_en_lvlhigh.get_mirrored_value();
- bit [NUM_GPIOS-1:0] intr_ctrl_en_lvllow = ral.intr_ctrl_en_lvllow.get_mirrored_value();
+ bit [TL_DW-1:0] intr_enable = ral.intr_enable.get_mirrored_value();
+ bit [TL_DW-1:0] intr_state = ral.intr_state.get_mirrored_value();
+ bit [TL_DW-1:0] intr_ctrl_en_rising = ral.intr_ctrl_en_rising.get_mirrored_value();
+ bit [TL_DW-1:0] intr_ctrl_en_falling = ral.intr_ctrl_en_falling.get_mirrored_value();
+ bit [TL_DW-1:0] intr_ctrl_en_lvlhigh = ral.intr_ctrl_en_lvlhigh.get_mirrored_value();
+ bit [TL_DW-1:0] intr_ctrl_en_lvllow = ral.intr_ctrl_en_lvllow.get_mirrored_value();
// expected(predicted) value of interrupt status
- bit [NUM_GPIOS-1:0] exp_intr_status;
+ bit [TL_DW-1:0] exp_intr_status;
+ // Reset value of last_intr_update_except_clearing to 0
+ last_intr_update_except_clearing = '0;
+ // Check if there is already INTR_STATE value update which was already due
+ // for update, but not actually updated
if (intr_state_update_queue.size() > 0) begin
- // Check if there is already INTR_STATE value update which was already due
- // for update, but not actually updated
if (intr_state_update_queue[$].needs_update) begin
intr_state = intr_state_update_queue[$].reg_value;
end
end
- // Reset value of last_intr_update_except_clearing to 0
- last_intr_update_except_clearing = '0;
+ // Coverage Sampling-2: 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]);
+ // Interrupt Test coverage
+ cov.intr_test_cg.sample(each_bit,
+ last_intr_test_event[each_bit],
+ intr_enable[each_bit],
+ last_intr_test_event[each_bit]);
+ end
+ end
// 1. Look for edge triggerred interrupts
- if (gpio_i_transition != {NUM_GPIOS{2'b00}}) begin
- foreach (gpio_i_transition[each_pin]) begin
- if (gpio_i_transition[each_pin].transition_occurred) begin
- if ((gpio_i_transition[each_pin].is_rising_edge == 1'b0 &&
- intr_ctrl_en_falling[each_pin] == 1'b1) ||
- (gpio_i_transition[each_pin].is_rising_edge == 1'b1 &&
- intr_ctrl_en_rising[each_pin] == 1'b1))
- begin
- exp_intr_status[each_pin] = 1'b1;
- // Register the latest edge triggered gpio interrupt update, if any
- last_intr_update_except_clearing[each_pin] = 1'b1;
- end else begin
- exp_intr_status[each_pin] = intr_state[each_pin];
+ begin
+ bit [TL_DW-1:0] rising_edge_intr_events, falling_edge_intr_events;
+ if (gpio_i_transition != {NUM_GPIOS{2'b00}}) begin
+ foreach (rising_edge_intr_events[each_bit]) begin
+ if (gpio_i_transition[each_bit].transition_occurred) begin
+ rising_edge_intr_events[each_bit] = gpio_i_transition[each_bit].is_rising_edge &
+ intr_ctrl_en_rising[each_bit];
+ falling_edge_intr_events[each_bit] = !gpio_i_transition[each_bit].is_rising_edge &
+ intr_ctrl_en_falling[each_bit];
end
end
+ foreach (gpio_i_transition[each_bit]) begin
+ if (gpio_i_transition[each_bit].transition_occurred) begin
+ if (rising_edge_intr_events[each_bit] || falling_edge_intr_events[each_bit]) begin
+ exp_intr_status[each_bit] = 1'b1;
+ // Register the latest edge triggered gpio interrupt update, if any
+ last_intr_update_except_clearing[each_bit] = 1'b1;
+ end else begin
+ exp_intr_status[each_bit] = intr_state[each_bit];
+ end
+ end
+ end
+ end
+ // 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]);
+ end
end
end
// 2. Look for level triggerred interrupts
- for (uint each_pin = 0; each_pin < TL_DW; each_pin++) begin
- if (exp_intr_status[each_pin] == 1'b0) begin
- if ((cfg.gpio_vif.pins[each_pin] == 1'b1 && intr_ctrl_en_lvlhigh[each_pin] == 1'b1) ||
- (cfg.gpio_vif.pins[each_pin] == 1'b0 && intr_ctrl_en_lvllow[each_pin] == 1'b1)) begin
- exp_intr_status[each_pin] = 1'b1;
- // Register the latest level triggered gpio interrupt update, if any
- last_intr_update_except_clearing[each_pin] = 1'b1;
- end else begin
- exp_intr_status[each_pin] = intr_state[each_pin];
+ begin
+ bit [TL_DW-1:0] lvlhigh_intr_events, lvllow_intr_events;
+ for (uint each_bit = 0; each_bit < TL_DW; each_bit++) begin
+ lvlhigh_intr_events[each_bit] = (cfg.gpio_vif.pins[each_bit] == 1'b1) &&
+ (intr_ctrl_en_lvlhigh[each_bit] == 1'b1);
+ lvllow_intr_events[each_bit] = (cfg.gpio_vif.pins[each_bit] == 1'b0) &&
+ (intr_ctrl_en_lvllow[each_bit] == 1'b1);
+ if (exp_intr_status[each_bit] == 1'b0) begin
+ if (lvlhigh_intr_events[each_bit] || lvllow_intr_events[each_bit]) begin
+ exp_intr_status[each_bit] = 1'b1;
+ // Register the latest level triggered gpio interrupt update, if any
+ last_intr_update_except_clearing[each_bit] = 1'b1;
+ end else begin
+ exp_intr_status[each_bit] = intr_state[each_bit];
+ end
+ end
+ end
+ // 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]);
end
end
end
// 3. Apply effect of "Interrupt Test"
exp_intr_status |= last_intr_test_event;
+ 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]);
+ end
+ end
// Clear last_intr_test_event
last_intr_test_event = '0;
`uvm_info(msg_id, $sformatf("Predicted interrupt status = 0x%0h [%0b]",
diff --git a/hw/ip/gpio/dv/env/seq_lib/gpio_random_long_reg_writes_reg_reads_vseq.sv b/hw/ip/gpio/dv/env/seq_lib/gpio_random_long_reg_writes_reg_reads_vseq.sv
index c63563f..7d1355b 100644
--- a/hw/ip/gpio/dv/env/seq_lib/gpio_random_long_reg_writes_reg_reads_vseq.sv
+++ b/hw/ip/gpio/dv/env/seq_lib/gpio_random_long_reg_writes_reg_reads_vseq.sv
@@ -49,7 +49,8 @@
`DV_CHECK_STD_RANDOMIZE_FATAL(gpio_i)
`DV_CHECK_STD_RANDOMIZE_FATAL(gpio_i_oen)
`uvm_info(msg_id, $sformatf("drive random value 0x%0h on gpio_i", gpio_i), UVM_HIGH)
- `uvm_info(msg_id, $sformatf("drive random value 0x%0h on gpio_i_oen", gpio_i_oen), UVM_HIGH)
+ `uvm_info(msg_id, $sformatf("drive random value 0x%0h on gpio_i_oen", gpio_i_oen),
+ UVM_HIGH)
// drive gpio_vif after setting all output enables to 0's
cfg.gpio_vif.pins_oe = gpio_i_oen;
diff --git a/hw/ip/uart/dv/env/uart_scoreboard.sv b/hw/ip/uart/dv/env/uart_scoreboard.sv
index d656429..bd15269 100644
--- a/hw/ip/uart/dv/env/uart_scoreboard.sv
+++ b/hw/ip/uart/dv/env/uart_scoreboard.sv
@@ -324,7 +324,7 @@
do_read_check = 1'b0;
foreach (intr_exp[i]) begin
intr = i; // cast to enum to get interrupt name
- if (cfg.en_cov) cov.intr_cg.sample(intr, intr_en[intr]);
+ if (cfg.en_cov) cov.intr_cg.sample(intr, intr_en[intr], intr_exp[intr]);
// don't check it when it's in ignored period
if (intr inside {TxWatermark, TxOverflow}) begin // TX interrupts
if (is_in_ignored_period(UartTx)) continue;