[dv,clkmgr] sec cm dv component

Signed-off-by: Jaedon Kim <jdonjdon@google.com>
diff --git a/hw/ip/clkmgr/dv/cov/clkmgr_cov_bind.sv b/hw/ip/clkmgr/dv/cov/clkmgr_cov_bind.sv
new file mode 100644
index 0000000..81594ae
--- /dev/null
+++ b/hw/ip/clkmgr/dv/cov/clkmgr_cov_bind.sv
@@ -0,0 +1,38 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description:
+// Clock manager coverage bindings for multi bus input
+module clkmgr_cov_bind;
+  bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_idle_mubi_cov_if (
+    .rst_ni (rst_ni),
+    .mubi   (idle_i)
+  );
+
+  bind clkmgr cip_mubi_cov_if #(.Width(lc_ctrl_pkg::TxWidth)) u_lc_hw_debug_en_mubi_cov_if (
+    .rst_ni (rst_ni),
+    .mubi   (lc_hw_debug_en_i)
+  );
+
+  bind clkmgr cip_mubi_cov_if #(.Width(lc_ctrl_pkg::TxWidth)) u_lc_clk_byp_req_mubi_cov_if (
+    .rst_ni (rst_ni),
+    .mubi   (lc_clk_byp_req_i)
+  );
+
+  bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_io_clk_byp_ack_mubi_cov_if (
+    .rst_ni (rst_ni),
+    .mubi   (io_clk_byp_ack_i)
+  );
+
+  bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_all_clk_byp_ack_mubi_cov_if (
+    .rst_ni (rst_ni),
+    .mubi   (all_clk_byp_ack_i)
+  );
+
+  bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_div_step_down_req_mubi_cov_if (
+    .rst_ni (rst_ni),
+    .mubi   (div_step_down_req_i)
+  );
+
+endmodule // clkmgr_cov_bind
diff --git a/hw/ip/clkmgr/dv/env/clkmgr_env_pkg.sv b/hw/ip/clkmgr/dv/env/clkmgr_env_pkg.sv
index b495222..e2b3318 100644
--- a/hw/ip/clkmgr/dv/env/clkmgr_env_pkg.sv
+++ b/hw/ip/clkmgr/dv/env/clkmgr_env_pkg.sv
@@ -95,6 +95,16 @@
     ClkMesrUsb
   } clk_mesr_e;
 
+  // Mubi test mode
+  typedef enum int {
+    ClkmgrMubiNone = 0,
+    ClkmgrMubiIdle = 1,
+    ClkmgrMubiLcCtrl = 2,
+    ClkmgrMubiLcHand = 3,
+    ClkmgrMubiHand = 4,
+    ClkmgrMubiDiv = 5
+  } clkmgr_mubi_e;
+
   // This is to examine separately the measurement and timeout recoverable error bits.
   typedef logic [ClkMesrUsb:0] recov_bits_t;
 
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 297b38d..901dd12 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
@@ -31,6 +31,7 @@
 
   lc_tx_t               extclk_ctrl_low_speed_sel;
   lc_tx_t               extclk_ctrl_sel;
+  clkmgr_mubi_e         mubi_mode;
 
   virtual function void set_scanmode_on_low_weight();
     scanmode_on_weight = 2;
@@ -80,6 +81,8 @@
   endfunction
 
   task pre_start();
+    mubi_mode = ClkmgrMubiNone;
+    void'($value$plusargs("clkmgr_mubi_mode=%0d", mubi_mode));
     // Disable the assertions requiring strict mubi4 and lc_tx_t to test non-strict-true values.
     $assertoff(0, "prim_mubi4_sync");
     $assertoff(0, "prim_lc_sync");
@@ -335,5 +338,4 @@
     // Increasing its frequency improves DV efficiency without compromising quality.
     cfg.aon_clk_rst_vif.set_freq_mhz((1.0 * FakeAonClkHz) / 1_000_000);
   endtask
-
 endclass : clkmgr_base_vseq
diff --git a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_extclk_vseq.sv b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_extclk_vseq.sv
index 87a4f6e..7c70bb4 100644
--- a/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_extclk_vseq.sv
+++ b/hw/ip/clkmgr/dv/env/seq_lib/clkmgr_extclk_vseq.sv
@@ -45,11 +45,22 @@
   mubi4_t div_step_down_req_non_true;
 
   function void post_randomize();
-    lc_clk_byp_req = get_rand_lc_tx_val(8, 2, 2);
-    lc_debug_en = get_rand_lc_tx_val(8, 2, 2);
-    io_clk_byp_ack_non_true = get_rand_mubi4_val(0, 2, 8);
-    all_clk_byp_ack_non_true = get_rand_mubi4_val(0, 2, 8);
-    div_step_down_req_non_true = get_rand_mubi4_val(0, 2, 8);
+    if (mubi_mode == ClkmgrMubiLcHand) begin
+      // increase weight of illgal value only in ClkmgrMubiLcHand
+      lc_clk_byp_req = get_rand_lc_tx_val(.t_weight(1), .f_weight(1), .other_weight(14));
+    end else begin
+      lc_clk_byp_req = get_rand_lc_tx_val(.t_weight(8), .f_weight(2), .other_weight(2));
+    end
+    if (mubi_mode == ClkmgrMubiLcCtrl) begin
+      // increase weight of illgal value only in ClkmgrMubiLcHand
+      lc_debug_en = get_rand_lc_tx_val(.t_weight(1), .f_weight(1), .other_weight(14));
+    end else begin
+      lc_debug_en = get_rand_lc_tx_val(.t_weight(8), .f_weight(2), .other_weight(2));
+    end
+
+    io_clk_byp_ack_non_true = get_rand_mubi4_val(.t_weight(0), .f_weight(2), .other_weight(8));
+    all_clk_byp_ack_non_true = get_rand_mubi4_val(.t_weight(0), .f_weight(2), .other_weight(8));
+    div_step_down_req_non_true = get_rand_mubi4_val(.t_weight(0), .f_weight(2), .other_weight(8));
 
     `uvm_info(`gfn, $sformatf(
               "randomize gives lc_clk_byp_req=0x%x, lc_debug_en=0x%x", lc_clk_byp_req, lc_debug_en),
@@ -60,16 +71,34 @@
   // Notice only all_clk_byp_req and io_clk_byp_req Mubi4True and Mubi4False cause transitions.
 
   local task delayed_update_all_clk_byp_ack(mubi4_t value, int cycles);
+    if (mubi_mode == ClkmgrMubiHand && value == MuBi4True) begin
+      cfg.clk_rst_vif.wait_clks($urandom_range(1, 10));
+      cfg.clkmgr_vif.update_all_clk_byp_ack(get_rand_mubi4_val(.t_weight(0),
+                                                               .f_weight(1),
+                                                               .other_weight(1)));
+    end
     cfg.clk_rst_vif.wait_clks(cycles);
     cfg.clkmgr_vif.update_all_clk_byp_ack(value);
   endtask
 
   local task delayed_update_div_step_down_req(mubi4_t value, int cycles);
+    if (mubi_mode ==  ClkmgrMubiDiv && value == MuBi4True) begin
+      cfg.clk_rst_vif.wait_clks($urandom_range(1, 10));
+      cfg.clkmgr_vif.update_div_step_down_req(get_rand_mubi4_val(.t_weight(0),
+                                                                 .f_weight(1),
+                                                                 .other_weight(1)));
+    end
     cfg.clk_rst_vif.wait_clks(cycles);
     cfg.clkmgr_vif.update_div_step_down_req(value);
   endtask
 
   local task delayed_update_io_clk_byp_ack(mubi4_t value, int cycles);
+    if (mubi_mode == ClkmgrMubiHand && value == MuBi4True) begin
+      cfg.clk_rst_vif.wait_clks($urandom_range(1, 10));
+      cfg.clkmgr_vif.update_io_clk_byp_ack(get_rand_mubi4_val(.t_weight(0),
+                                                              .f_weight(1),
+                                                              .other_weight(1)));
+    end
     cfg.clk_rst_vif.wait_clks(cycles);
     cfg.clkmgr_vif.update_io_clk_byp_ack(value);
   endtask
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 da02a00..32b8462 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
@@ -5,7 +5,7 @@
 // trans test vseq
 // This is a more randomized version of the corresponding test in the smoke sequence.
 // Starts with random units busy, set the hints at random. The idle units whose hint bit is off
-// will be disabled, but the others will remain enabled. Then all units are made idle to check 
+// will be disabled, but the others will remain enabled. Then all units are made idle to check
 // that status matches hints. Prior to the next round this raises all hints to avoid units whose
 // clock is off but are not idle.
 //
@@ -44,6 +44,8 @@
       bool_idle = mubi_hintables_to_hintables(idle);
       `DV_CHECK_EQ(value, initial_hints | ~bool_idle, $sformatf(
                    "Busy units have status high: hints=0x%x, idle=0x%x", initial_hints, bool_idle))
+      // Add random idle
+      if (mubi_mode == ClkmgrMubiIdle) drive_idle();
 
       // Setting all idle should make hint_status match hints.
       cfg.clkmgr_vif.update_idle({NUM_TRANS{MuBi4True}});
@@ -51,6 +53,9 @@
       csr_rd(.ptr(ral.clk_hints_status), .value(value));
       `DV_CHECK_EQ(value, initial_hints, "All idle: units status matches hints")
 
+
+      if (mubi_mode == ClkmgrMubiIdle) drive_idle();
+
       // Now set all hints, and the status should also be all ones.
       csr_wr(.ptr(ral.clk_hints), .value('1));
       cfg.io_clk_rst_vif.wait_clks(IO_DIV4_SYNC_CYCLES);
@@ -62,4 +67,16 @@
     end
   endtask : body
 
+  task drive_idle();
+    int period;
+
+    repeat (30) begin
+      period = $urandom_range(1, 10);
+      @cfg.clkmgr_vif.trans_cb;
+      cfg.clkmgr_vif.idle_i = get_rand_mubi4_val(.t_weight(0),
+                                                 .f_weight(0),
+                                                 .other_weight(1));
+      repeat(period) @cfg.clkmgr_vif.trans_cb;
+    end
+  endtask // drive_idle
 endclass : clkmgr_trans_vseq