[dv/clkmgr] Add clocking related covergroups.

Add covergroup for peripheral and transactional units clocking.

Signed-off-by: Guillermo Maturana <maturana@google.com>
diff --git a/hw/ip/clkmgr/dv/env/clkmgr_env_cov.sv b/hw/ip/clkmgr/dv/env/clkmgr_env_cov.sv
index a56e1a4..3c9587a 100644
--- a/hw/ip/clkmgr/dv/env/clkmgr_env_cov.sv
+++ b/hw/ip/clkmgr/dv/env/clkmgr_env_cov.sv
@@ -8,20 +8,85 @@
  * Covergroups may also be wrapped inside helper classes if needed.
  */
 
+// Wrapper class for peripheral clock covergroup.
+class clkmgr_peri_cg_wrap;
+  // This covergroup collects signals affecting peripheral clock.
+  covergroup peri_cg(string name) with function sample(bit enable, bit ip_clk_en, bit scanmode);
+    option.name = name;
+
+    csr_enable_cp: coverpoint enable;
+    ip_clk_en_cp: coverpoint ip_clk_en;
+    scanmode_cp: coverpoint scanmode;
+  endgroup
+
+  function new(string name);
+    peri_cg = new(name);
+  endfunction
+
+  function void sample(bit enable, bit ip_clk_en, bit scanmode);
+    peri_cg.sample(enable, ip_clk_en, scanmode);
+  endfunction
+endclass
+
+// Wrapper class for transactional unit clock covergroup.
+class clkmgr_trans_cg_wrap;
+  // This covergroup collects signals affecting transactional clock.
+  covergroup trans_cg(string name) with function
+      sample(bit hint, bit ip_clk_en, bit scanmode, bit idle);
+    option.name = name;
+
+    csr_hint_cp: coverpoint hint;
+    ip_clk_en_cp: coverpoint ip_clk_en;
+    scanmode_cp: coverpoint scanmode;
+    idle_cp: coverpoint idle;
+  endgroup
+
+  function new(string name);
+    trans_cg = new(name);
+  endfunction
+
+  function sample(bit hint, bit ip_clk_en, bit scanmode, bit idle);
+    trans_cg.sample(hint, ip_clk_en, scanmode, idle);
+  endfunction
+endclass
+
 class clkmgr_env_cov extends cip_base_env_cov #(.CFG_T(clkmgr_env_cfg));
+  import clkmgr_env_pkg::*;
+
   `uvm_component_utils(clkmgr_env_cov)
 
   // the base class provides the following handles for use:
   // clkmgr_env_cfg: cfg
 
-  // covergroups
-  // [add covergroups here]
+  // These covergroups collect signals affecting peripheral clocks.
+  clkmgr_peri_cg_wrap peri_cg_wrap[NUM_PERI];
+
+  // These covergroups collect signals affecting transactional clocks.
+  clkmgr_trans_cg_wrap trans_cg_wrap[NUM_TRANS];
 
   function new(string name, uvm_component parent);
     super.new(name, parent);
-    // [instantiate covergroups here]
+    // The peripheral covergoups.
+    foreach (peri_cg_wrap[i]) begin
+      peri_e peri = peri_e'(i);
+      peri_cg_wrap[i] = new(peri.name);
+    end
+    // The transactional covergroups.
+    foreach (trans_cg_wrap[i]) begin
+      trans_e trans = trans_e'(i);
+      trans_cg_wrap[i] = new(trans.name);
+    end
   endfunction : new
 
+  function void update_peri_cgs(logic [NUM_PERI-1:0] enables, logic ip_clk_en, logic scanmode);
+    foreach (peri_cg_wrap[i]) peri_cg_wrap[i].sample(enables[i], ip_clk_en, scanmode);
+  endfunction
+
+  function void update_trans_cgs(logic [NUM_TRANS-1:0] hints, logic ip_clk_en, logic scanmode,
+                                 logic [NUM_TRANS-1:0] idle);
+    foreach (trans_cg_wrap[i]) trans_cg_wrap[i].sample(hints[i], ip_clk_en, scanmode, idle[i]);
+  endfunction
+
   virtual function void build_phase(uvm_phase phase);
     super.build_phase(phase);
     // [or instantiate covergroups here]
diff --git a/hw/ip/clkmgr/dv/env/clkmgr_if.sv b/hw/ip/clkmgr/dv/env/clkmgr_if.sv
index 4692171..ba93bb3 100644
--- a/hw/ip/clkmgr/dv/env/clkmgr_if.sv
+++ b/hw/ip/clkmgr/dv/env/clkmgr_if.sv
@@ -75,7 +75,7 @@
     clk_enables = ens;
   endfunction
 
-  function automatic void update_hints(logic [$bits(clk_hints)-1:0] hints);
+  function automatic void update_hints(clk_hints_t hints);
     clk_hints = hints;
   endfunction
 
@@ -83,10 +83,6 @@
     idle_i = value;
   endfunction
 
-  function automatic void update_trans_idle(logic value, trans_e trans);
-    idle_i[trans] = value;
-  endfunction
-
   task automatic go_idle(trans_e trans, int cycles);
     if (!idle_i[trans]) begin
       repeat(cycles) @(negedge clk);
diff --git a/hw/ip/clkmgr/dv/env/clkmgr_scoreboard.sv b/hw/ip/clkmgr/dv/env/clkmgr_scoreboard.sv
index 4e06820..ea85780 100644
--- a/hw/ip/clkmgr/dv/env/clkmgr_scoreboard.sv
+++ b/hw/ip/clkmgr/dv/env/clkmgr_scoreboard.sv
@@ -28,9 +28,18 @@
   task run_phase(uvm_phase phase);
     super.run_phase(phase);
     fork
+      monitor_idle();
     join_none
   endtask
 
+  task monitor_idle();
+    forever @cfg.clkmgr_vif.idle_i
+      if (cfg.en_cov) begin
+        cov.update_trans_cgs(ral.clk_hints.get(), cfg.clkmgr_vif.pwr_i.ip_clk_en,
+                             cfg.clkmgr_vif.scanmode_i, cfg.clkmgr_vif.idle_i);
+      end
+  endtask
+
   virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name);
     uvm_reg csr;
     bit     do_read_check   = 1'b1;
@@ -90,11 +99,19 @@
       "clk_enables":
         if (addr_phase_write) begin
           cfg.clkmgr_vif.update_clk_enables(item.a_data);
+          if (cfg.en_cov) begin
+            cov.update_peri_cgs(item.a_data, cfg.clkmgr_vif.pwr_i.ip_clk_en,
+                                cfg.clkmgr_vif.scanmode_i);
+          end
         end
       "clk_hints":
         // Clearing a hint sets an expectation for the status to transition to zero.
         if (addr_phase_write) begin
           cfg.clkmgr_vif.update_hints(item.a_data);
+          if (cfg.en_cov) begin
+            cov.update_trans_cgs(item.a_data, cfg.clkmgr_vif.pwr_i.ip_clk_en,
+                                 cfg.clkmgr_vif.scanmode_i, cfg.clkmgr_vif.idle_i);
+          end
         end
       "clk_hints_status": begin
         // The status will respond to the hint once the target unit is idle. We check it in
diff --git a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_base_vseq.sv b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_base_vseq.sv
index 284befc..a132121 100644
--- a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_base_vseq.sv
+++ b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_base_vseq.sv
@@ -73,4 +73,14 @@
     cfg.aon_clk_rst_vif.set_freq_mhz(7);
   endtask
 
+  virtual function void update_idle(logic [NUM_TRANS-1:0] value);
+    idle = value;
+    cfg.clkmgr_vif.update_idle(idle);
+  endfunction
+
+  virtual function void update_trans_idle(logic value, trans_e trans);
+    idle[trans] = value;
+    update_idle(idle);
+  endfunction
+
 endclass : clkmgr_base_vseq
diff --git a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_peri_vseq.sv b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_peri_vseq.sv
index 63aff76..77ffc1f 100644
--- a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_peri_vseq.sv
+++ b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_peri_vseq.sv
@@ -17,7 +17,6 @@
     logic [NUM_PERI-1:0] flipped_enables;
     `uvm_info(`gfn, $sformatf("Initializing clk_enables with 0x%0x", initial_enables), UVM_LOW)
     csr_wr(.ptr(ral.clk_enables), .value(initial_enables));
-
     cfg.clk_rst_vif.wait_clks(10);
     // Flip all bits of clk_enables.
     flipped_enables = initial_enables ^ ((1 << ral.clk_enables.get_n_bits()) - 1);
diff --git a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_smoke_vseq.sv b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_smoke_vseq.sv
index 1e8ec13..81d3b8e 100644
--- a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_smoke_vseq.sv
+++ b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_smoke_vseq.sv
@@ -47,11 +47,10 @@
         '{TransAes, ral.clk_hints.clk_main_otbn_hint, ral.clk_hints_status.clk_main_otbn_val}
     };
 
-    cfg.clkmgr_vif.update_idle(0);
+    update_idle(0);
     trans = trans.first;
     csr_rd(.ptr(ral.clk_hints), .value(value));
     `uvm_info(`gfn, $sformatf("Updating hints to 0x%0x", value), UVM_MEDIUM)
-    cfg.clkmgr_vif.update_hints(value);
     do begin
       trans_descriptor_t descriptor = trans_descriptors[int'(trans)];
       `uvm_info(`gfn, $sformatf("Clearing %s hint bit", descriptor.unit.name), UVM_MEDIUM)
@@ -62,7 +61,7 @@
 
       `uvm_info(`gfn, $sformatf("Setting %s idle bit", descriptor.unit.name), UVM_MEDIUM)
       cfg.clkmgr_vif.wait_clks(1);
-      cfg.clkmgr_vif.update_trans_idle(1'b1, trans);
+      update_trans_idle(1'b1, trans);
       // Some cycles for the logic to settle.
       cfg.clk_rst_vif.wait_clks(3);
       csr_rd(.ptr(descriptor.value_bit), .value(bit_value));
diff --git a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_trans_vseq.sv b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_trans_vseq.sv
index 6c7277a..042e7ed 100644
--- a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_trans_vseq.sv
+++ b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_trans_vseq.sv
@@ -23,13 +23,11 @@
     trans = trans.first;
     `uvm_info(`gfn, $sformatf("Updating hints to 0x%0x", initial_hints), UVM_MEDIUM)
     csr_wr(.ptr(ral.clk_hints), .value(initial_hints));
-    cfg.clkmgr_vif.update_hints(initial_hints);
     cfg.clkmgr_vif.wait_clks(5);
     csr_rd(.ptr(ral.clk_hints_status), .value(value));
     // We expect the status to be determined by hints and idle.
     `DV_CHECK_EQ(value, initial_hints | ~idle, "Busy units have status high")
-    idle = '1;
-    cfg.clkmgr_vif.update_idle(idle);
+    update_idle('1);
     cfg.clkmgr_vif.wait_clks(5);
     csr_rd(.ptr(ral.clk_hints_status), .value(value));
     `DV_CHECK_EQ(value, initial_hints, "All idle: units status matches hints")