[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")