[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;