[uart/dv] Add functional cov for intr

Add functional coverage for interrupt pin, intr_test and sticky
interrupts
diff --git a/hw/ip/uart/dv/env/uart_env_cov.sv b/hw/ip/uart/dv/env/uart_env_cov.sv
index cd0c20c..2ed6678 100644
--- a/hw/ip/uart/dv/env/uart_env_cov.sv
+++ b/hw/ip/uart/dv/env/uart_env_cov.sv
@@ -16,6 +16,8 @@
   function new(string name, uvm_component parent);
     super.new(name, parent);
     fifo_level_cg = new();
+    sticky_intr_cov["TxWatermark"] = new(.name("TxWatermark"), .toggle_cov_en(0));
+    sticky_intr_cov["RxWatermark"] = new(.name("RxWatermark"), .toggle_cov_en(0));
   endfunction : new
 
 endclass
diff --git a/hw/ip/uart/dv/env/uart_scoreboard.sv b/hw/ip/uart/dv/env/uart_scoreboard.sv
index 66e9f0b..fab54b3 100644
--- a/hw/ip/uart/dv/env/uart_scoreboard.sv
+++ b/hw/ip/uart/dv/env/uart_scoreboard.sv
@@ -108,14 +108,18 @@
     end // forever
   endtask
 
-  virtual function void predict_tx_watermark_intr(uint tx_q_size = tx_q.size);
+  virtual function void predict_tx_watermark_intr(uint tx_q_size = tx_q.size, bit just_cleared = 0);
     uint watermark = get_watermark_bytes_by_level(ral.fifo_ctrl.txilvl.get_mirrored_value());
     intr_exp[TxWatermark] |= (tx_q_size >= watermark);
+    // cover the interrupt sticky behavior
+    if (cfg.en_cov) cov.sticky_intr_cov["TxWatermark"].sample(just_cleared & intr_exp[TxWatermark]);
   endfunction
 
-  virtual function void predict_rx_watermark_intr(uint rx_q_size = rx_q.size);
+  virtual function void predict_rx_watermark_intr(uint rx_q_size = rx_q.size, bit just_cleared = 0);
     uint watermark = get_watermark_bytes_by_level(ral.fifo_ctrl.rxilvl.get_mirrored_value());
     intr_exp[RxWatermark] |= (rx_q_size >= watermark);
+    // cover the interrupt sticky behavior
+    if (cfg.en_cov) cov.sticky_intr_cov["RxWatermark"].sample(just_cleared & intr_exp[RxWatermark]);
   endfunction
 
   // we don't model uart cycle-acurrately, ignore checking when item is just/almost finished
@@ -232,7 +236,13 @@
       end
       "intr_test": begin
         if (write && channel == AddrChannel) begin
+          bit [TL_DW-1:0] intr_en = ral.intr_enable.get_mirrored_value();
           intr_exp |= item.a_data;
+          if (cfg.en_cov) begin
+            foreach (intr_exp[i]) begin
+              cov.intr_test_cg.sample(i, item.a_data[i], intr_en[i], intr_exp[i]);
+            end
+          end
           // this field is WO - always returns 0
           void'(csr.predict(.value(0), .kind(UVM_PREDICT_WRITE)));
         end
@@ -309,13 +319,16 @@
         if (write && channel == AddrChannel) begin // write & address phase
           bit[TL_DW-1:0] intr_wdata = item.a_data;
           fork begin
+            bit [NumUartIntr-1:0] pre_intr = intr_exp;
             // add 1 cycle delay to avoid race condition when fifo changing and interrupt clearing
             // occur simultaneously
             cfg.clk_rst_vif.wait_clks(1);
             intr_exp &= ~intr_wdata;
             // recalculate tx/rx watermark, will be set again if fifo size >= watermark
-            predict_tx_watermark_intr();
-            predict_rx_watermark_intr();
+            predict_tx_watermark_intr(.just_cleared(pre_intr[TxWatermark] &
+                                                    intr_wdata[TxWatermark]));
+            predict_rx_watermark_intr(.just_cleared(pre_intr[RxWatermark] &
+                                                    intr_wdata[RxWatermark]));
           end join_none
         end else if (!write && channel == AddrChannel) begin // read & addr phase
           intr_exp_at_addr_phase = intr_exp;
@@ -325,7 +338,10 @@
           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], intr_exp[intr]);
+            if (cfg.en_cov) begin
+              cov.intr_cg.sample(intr, intr_en[intr], intr_exp[intr]);
+              cov.intr_pins_cg.sample(intr, cfg.intr_vif.pins[intr]);
+            end
             // 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;