[pattgen, dv] Update pattgen dv

  - Add functional coverage dv/cov
  - Update scoreboard for coverage

Signed-off-by: Hoang Tung <Hoang.Tung@wdc.com>
diff --git a/hw/ip/pattgen/data/pattgen_testplan.hjson b/hw/ip/pattgen/data/pattgen_testplan.hjson
index 5d64b48..3275a90 100644
--- a/hw/ip/pattgen/data/pattgen_testplan.hjson
+++ b/hw/ip/pattgen/data/pattgen_testplan.hjson
@@ -5,7 +5,7 @@
   name: "pattgen"
   import_testplans: ["hw/dv/tools/dvsim/testplans/csr_testplan.hjson",
                      "hw/dv/tools/dvsim/testplans/intr_test_testplan.hjson",
-"hw/dv/tools/dvsim/testplans/stress_all_with_reset_testplan.hjson",
+                     "hw/dv/tools/dvsim/testplans/stress_all_with_reset_testplan.hjson",
                      "hw/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson"],
   entries: [
     {
diff --git a/hw/ip/pattgen/dv/cov/pattgen_cov.core b/hw/ip/pattgen/dv/cov/pattgen_cov.core
new file mode 100644
index 0000000..26d55ed
--- /dev/null
+++ b/hw/ip/pattgen/dv/cov/pattgen_cov.core
@@ -0,0 +1,20 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:pattgen_cov:0.1"
+description: "PATTGEN functional coverage interface & bind."
+
+filesets:
+  files_dv:
+    depend:
+      - lowrisc:dv:dv_utils
+    files:
+      - pattgen_cov_if.sv
+      - pattgen_cov_bind.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_dv
diff --git a/hw/ip/pattgen/dv/cov/pattgen_cov_bind.sv b/hw/ip/pattgen/dv/cov/pattgen_cov_bind.sv
new file mode 100644
index 0000000..82c936c
--- /dev/null
+++ b/hw/ip/pattgen/dv/cov/pattgen_cov_bind.sv
@@ -0,0 +1,10 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Binds PATTGEN functional coverage interaface to the top level PATTGEN module.
+module pattgen_cov_bind;
+
+  bind pattgen pattgen_cov_if u_pattgen_cov_if (.*);
+
+endmodule
diff --git a/hw/ip/pattgen/dv/cov/pattgen_cov_if.sv b/hw/ip/pattgen/dv/cov/pattgen_cov_if.sv
new file mode 100644
index 0000000..a1bf1c6
--- /dev/null
+++ b/hw/ip/pattgen/dv/cov/pattgen_cov_if.sv
@@ -0,0 +1,82 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Implements functional coverage for PATTGEN.
+interface pattgen_cov_if (
+  input logic clk_i
+);
+
+  import uvm_pkg::*;
+  import dv_utils_pkg::*;
+  `include "dv_fcov_macros.svh"
+
+  bit en_full_cov = 1'b1;
+  bit en_intg_cov = 1'b1;
+
+  // If en_full_cov is set, then en_intg_cov must also be set since it is a subset.
+  bit en_intg_cov_loc;
+  assign en_intg_cov_loc = en_full_cov | en_intg_cov;
+
+  bit ch0_perf, ch1_perf;
+  assign ch0_perf = {u_pattgen_core.ch0_ctrl.len, 
+                     u_pattgen_core.ch0_ctrl.reps, 
+                     u_pattgen_core.ch0_ctrl.prediv} == 'h0;
+  assign ch1_perf = {u_pattgen_core.ch1_ctrl.len,
+                     u_pattgen_core.ch1_ctrl.reps,
+                     u_pattgen_core.ch1_ctrl.prediv} == 'h0;
+
+  covergroup pattgen_op_cg @(u_pattgen_core.ch0_ctrl.enable or u_pattgen_core.ch1_ctrl.enable);
+    option.name         = "pattgen_op_cg";
+    option.comment      = "PATTGEN CH0 and CH1 operation";
+    option.per_instance = 1;
+
+    // Channel 0 coverpoints
+    cp_enable: coverpoint {u_pattgen_core.ch1_ctrl.enable, u_pattgen_core.ch0_ctrl.enable} {
+      bins CH0_ENABLE  = (2'b00 => 2'b01);
+      bins CH0_DISABLE = (2'b01 => 2'b00);
+      bins CH1_ENABLE  = (2'b00 => 2'b10);
+      bins CH1_DISABLE = (2'b10 => 2'b00);
+      bins CHX_ENABLE  = (2'b00 => 2'b11);  // CHX: dual channels
+      bins CHX_DISABLE = (2'b11 => 2'b00);
+      bins CHX_OTHERS  = default;
+    }
+    // Channel 0 coverpoints
+    cp_ch0_perf: coverpoint {ch0_perf} {
+      bins LOW_PERF = {'h0};
+      bins TYP_PERF = {!'h0};
+    }
+    cp_ch0_polarity: coverpoint {u_pattgen_core.ch0_ctrl.polarity} {
+      bins TX_CLK_FALL = {1'b0};
+      bins TX_CLK_RISE = {1'b1};
+    }
+
+    // Channel 1 coverpoints
+    cp_ch1_perf: coverpoint {ch1_perf} {
+      bins LOW_PERF = {'h0};
+      bins TYP_PERF = {!'h0};
+    }
+    cp_ch1_polarity: coverpoint {u_pattgen_core.ch1_ctrl.polarity} {
+      bins TX_CLK_FALL = {1'b0};
+      bins TX_CLK_RISE = {1'b1};
+    }
+
+    // Cross coverpoints
+    cr_ch0_op: cross cp_enable, cp_ch0_polarity, cp_ch0_perf {
+      bins CH0_OP_ENABLE  = binsof(cp_enable.CH0_ENABLE);
+      bins CH0_OP_DISABLE = binsof(cp_enable.CH0_DISABLE);
+    }
+    cr_ch1_op: cross cp_enable, cp_ch1_polarity, cp_ch1_perf {
+      bins CH1_OP_ENABLE  = binsof(cp_enable.CH1_ENABLE);
+      bins CH1_OP_DISABLE = binsof(cp_enable.CH1_DISABLE);
+    }
+    cr_chx_op: cross cp_enable, cp_ch0_polarity, cp_ch0_perf, cp_ch1_polarity, cp_ch1_perf {
+      bins CHX_OP_ENABLE  = binsof(cp_enable.CHX_ENABLE);
+      bins CHX_OP_DISABLE = binsof(cp_enable.CHX_DISABLE);
+    }
+
+  endgroup : pattgen_op_cg
+
+  `DV_FCOV_INSTANTIATE_CG(pattgen_op_cg, en_full_cov)
+
+endinterface : pattgen_cov_if
diff --git a/hw/ip/pattgen/dv/env/pattgen_scoreboard.sv b/hw/ip/pattgen/dv/env/pattgen_scoreboard.sv
index 41c3b86..e95cd53 100644
--- a/hw/ip/pattgen/dv/env/pattgen_scoreboard.sv
+++ b/hw/ip/pattgen/dv/env/pattgen_scoreboard.sv
@@ -10,10 +10,6 @@
   `uvm_component_utils(pattgen_scoreboard)
   `uvm_component_new
 
-  //****************************************************
-  // TODO: This is still WIP (cleaned up later)
-  //****************************************************
-
   // TLM fifos hold the transactions sent by monitor
   uvm_tlm_analysis_fifo #(pattgen_item) item_fifo[NUM_PATTGEN_CHANNELS];
 
@@ -23,6 +19,7 @@
   local pattgen_item exp_item_q[NUM_PATTGEN_CHANNELS][$];
   // local variables
   local pattgen_channel_cfg channel_cfg[NUM_PATTGEN_CHANNELS-1:0];
+  local bit [NumPattgenIntr-1:0] intr_exp_at_addr_phase;
 
   function void build_phase(uvm_phase phase);
     super.build_phase(phase);
@@ -34,11 +31,17 @@
 
   task run_phase(uvm_phase phase);
     super.run_phase(phase);
-    for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
-      fork
-        automatic uint channel = i;
-        compare_trans(channel);
-      join_none
+    forever begin
+      `DV_SPINWAIT_EXIT(
+        for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
+          fork
+            automatic uint channel = i;
+            compare_trans(channel);
+          join_none
+        end
+        wait fork;,
+        @(negedge cfg.clk_rst_vif.rst_n),
+      )
     end
   endtask : run_phase
 
@@ -48,6 +51,9 @@
     bit             do_read_check = 1'b1;
     bit             write = item.is_write();
 
+    bit addr_phase_write = (write && channel  == AddrChannel);
+    bit data_phase_read  = (!write && channel == DataChannel);
+
     uvm_reg_addr_t csr_addr = ral.get_word_aligned_addr(item.a_addr);
     // if access was to a valid csr, get the csr handle
     if (csr_addr inside {cfg.csr_addrs}) begin
@@ -58,7 +64,7 @@
     end
 
     // address write phase
-    if (write  && channel == AddrChannel) begin
+    if (addr_phase_write) begin
       // if incoming access is a write to a valid csr, then make updates right away
       void'(csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask)));
 
@@ -131,7 +137,12 @@
           // no special handle is needed
         end
         "intr_state": begin
-          // TODO: add coverage
+          bit[TL_DW-1:0] intr_wdata = item.a_data;
+          fork begin
+            bit [NumPattgenIntr-1:0] pre_intr = intr_exp;
+            cfg.clk_rst_vif.wait_clks(1);
+            intr_exp &= ~intr_wdata;
+          end join_none
         end
         default: begin
           `uvm_fatal(`gfn, $sformatf("\n  scb: write to invalid csr: %0s", csr.get_full_name()))
@@ -139,10 +150,13 @@
       endcase
     end
 
-    // On reads, if do_read_check, is set, then check mirrored_value against item.d_data
-    if (!write && channel == DataChannel) begin
+    // On reads and & data phase, if do_read_check, is set, then
+    // check mirrored_value against item.d_data
+    if (data_phase_read) begin
       case (csr.get_name())
         "intr_state": begin
+          pattgen_intr_e     intr;
+          bit [TL_DW-1:0] intr_en = ral.intr_enable.get_mirrored_value();
           do_read_check = 1'b0;
           // done_ch0/done_ch1 is asserted to indicate a pattern is completely generated
           reg_value = item.d_data;
@@ -153,6 +167,13 @@
           for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
             generate_exp_items(.channel(i), .error_injected(1'b0));
           end
+          foreach (intr_exp[i]) begin
+            intr = pattgen_intr_e'(i); // cast to enum to get interrupt name
+            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
+          end
         end
         "ctrl", "size", "intr_test", "intr_enable",
         "prediv_ch0", "data_ch0_0", "data_ch0_1",
diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv
index 730d926..599f451 100644
--- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv
+++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv
@@ -23,7 +23,7 @@
         1'b0 :/ cfg.seq_cfg.pattgen_low_polarity_pct,
         1'b1 :/ (100 - cfg.seq_cfg.pattgen_low_polarity_pct)
       };
-      ch_cfg.prediv dist {0 :/ 1, 1024 :/ 2};
+      ch_cfg.prediv dist {0 :/ 1, 1024 :/ 1};
       ch_cfg.len    dist {0 :/ 1, 1023 :/ 1};
       ch_cfg.reps   dist {0 :/ 1,   63 :/ 1};
       // dependent constraints
diff --git a/hw/ip/pattgen/dv/pattgen_sim.core b/hw/ip/pattgen/dv/pattgen_sim.core
index 2b63661..4550314 100644
--- a/hw/ip/pattgen/dv/pattgen_sim.core
+++ b/hw/ip/pattgen/dv/pattgen_sim.core
@@ -13,6 +13,7 @@
     depend:
       - lowrisc:dv:pattgen_test
       - lowrisc:dv:pattgen_sva
+      - lowrisc:dv:pattgen_cov
     files:
       - tb.sv
     file_type: systemVerilogSource
diff --git a/hw/ip/pattgen/dv/pattgen_sim_cfg.hjson b/hw/ip/pattgen/dv/pattgen_sim_cfg.hjson
index 33ae366..0e3f898 100644
--- a/hw/ip/pattgen/dv/pattgen_sim_cfg.hjson
+++ b/hw/ip/pattgen/dv/pattgen_sim_cfg.hjson
@@ -41,7 +41,13 @@
 
   // Default UVM test and seq class name.
   uvm_test: pattgen_base_test
-  uvm_test_seq: pattgen_base_vseq
+  uvm_test_seq: pattgen_base_vseq,
+
+  // additional top for coverage
+  sim_tops: [ "pattgen_bind", "pattgen_cov_bind"]
+  
+  // Pattgen functional coverage
+  xcelium_cov_refine_files: ["{proj_root}/hw/ip/pattgen/dv/cov/pattgen_cov.vRefine"]
 
   // List of test specifications.
   tests: [