[dv] add mubi coverage for CSR and update reggen
1. reggen is udpated to know if this reg field is mubi or not
2. add functional coverage for mubi type CSRs
3. disable sampling mubi covergroup in CSR tests as CSR tests won't
really take the effect of CSRs
Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
index 6e81c47..52dd6d8 100644
--- a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
+++ b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
@@ -390,9 +390,24 @@
end
endtask
+ // some coverage sampling should be disabled when it's a CSR test
+ virtual function void disable_coverage_sample_for_csr_test();
+ `uvm_info(`gfn, "mubi reg coverage sampling is disabled as this is a CSR test", UVM_HIGH)
+ foreach (all_csrs[i]) begin
+ dv_base_reg_field fields[$];
+
+ all_csrs[i].get_dv_base_reg_fields(fields);
+ // assign null to all mubi_cov object, so that coverage sampling is skipped
+ foreach (fields[j]) fields[j].mubi_cov = null;
+ end
+ endfunction
+
// wrapper task to call common test or csr tests
virtual task run_common_vseq_wrapper(int num_times = 1);
if (common_seq_type == "") void'($value$plusargs("run_%0s", common_seq_type));
+
+ disable_coverage_sample_for_csr_test();
+
// check which test type
case (common_seq_type)
"intr_test": run_intr_test_vseq(num_times);
diff --git a/hw/dv/sv/dv_base_reg/dv_base_mubi_cov.sv b/hw/dv/sv/dv_base_reg/dv_base_mubi_cov.sv
new file mode 100644
index 0000000..f3af2b9
--- /dev/null
+++ b/hw/dv/sv/dv_base_reg/dv_base_mubi_cov.sv
@@ -0,0 +1,88 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// coverage object for a fixed width mubi
+class mubi_cov #(parameter int Width = 4,
+ parameter int ValueTrue = prim_mubi_pkg::MuBi4True,
+ parameter int ValueFalse = prim_mubi_pkg::MuBi4False
+ ) extends uvm_object;
+ `uvm_object_param_utils(mubi_cov #(Width, ValueTrue, ValueFalse))
+
+ // Collect true, false and at least N other values (N = Width)
+ covergroup mubi_cg(string name) with function sample(bit [Width-1:0] value);
+ option.per_instance = 1;
+ option.name = name;
+
+ cp_value: coverpoint value {
+ bins true = {ValueTrue};
+ bins false = {ValueFalse};
+ bins others[Width] = {[0:{Width{1'b1}}]} with (!(item inside {ValueTrue, ValueFalse}));
+ }
+ endgroup : mubi_cg
+
+ // use reg_field name as this name
+ function new(string name = "");
+ mubi_cg = new($sformatf("mubi%0d_cov_of_%s", Width, name));
+ endfunction : new
+
+ virtual function void sample(bit [Width-1:0] value);
+ mubi_cg.sample(value);
+ endfunction : sample
+endclass : mubi_cov
+
+typedef mubi_cov #(.Width(4),
+ .ValueTrue(prim_mubi_pkg::MuBi4True),
+ .ValueFalse(prim_mubi_pkg::MuBi4False)) mubi4_cov;
+typedef mubi_cov #(.Width(8),
+ .ValueTrue(prim_mubi_pkg::MuBi8True),
+ .ValueFalse(prim_mubi_pkg::MuBi8False)) mubi8_cov;
+typedef mubi_cov #(.Width(12),
+ .ValueTrue(prim_mubi_pkg::MuBi12True),
+ .ValueFalse(prim_mubi_pkg::MuBi12False)) mubi12_cov;
+typedef mubi_cov #(.Width(16),
+ .ValueTrue(prim_mubi_pkg::MuBi16True),
+ .ValueFalse(prim_mubi_pkg::MuBi16False)) mubi16_cov;
+
+// a mubi coverage object, which allows to dynamically select the width of mubi
+class dv_base_mubi_cov extends uvm_object;
+ int mubi_width = 0;
+
+ // declare all mubi types, but only one will be created
+ mubi4_cov m_mubi4_cov;
+ mubi8_cov m_mubi8_cov;
+ mubi12_cov m_mubi12_cov;
+ mubi16_cov m_mubi16_cov;
+
+ `uvm_object_utils(dv_base_mubi_cov)
+ `uvm_object_new
+
+ // use reg_field name as this name
+ function void create_cov(int mubi_width);
+ string cov_name = $sformatf("mubi%0d_cov_of_%s", mubi_width, `gfn);
+
+ // create_cov can be invoked only once
+ `DV_CHECK_EQ(this.mubi_width, 0)
+ this.mubi_width = mubi_width;
+
+ case (mubi_width)
+ 4: m_mubi4_cov = mubi4_cov::type_id::create(cov_name);
+ 8: m_mubi8_cov = mubi8_cov::type_id::create(cov_name);
+ 12: m_mubi12_cov = mubi12_cov::type_id::create(cov_name);
+ 16: m_mubi16_cov = mubi16_cov::type_id::create(cov_name);
+ default: `uvm_fatal(`gfn, $sformatf("Unsupported mubi width (%0d) is used", mubi_width))
+ endcase
+ endfunction : create_cov
+
+ virtual function void sample(int value);
+ case (mubi_width)
+ 4: m_mubi4_cov.sample(value);
+ 8: m_mubi8_cov.sample(value);
+ 12: m_mubi12_cov.sample(value);
+ 16: m_mubi16_cov.sample(value);
+ default: `uvm_fatal(`gfn, $sformatf("Unsupported mubi width (%0d) is used", mubi_width))
+ endcase
+ endfunction : sample
+endclass : dv_base_mubi_cov
+
+
diff --git a/hw/dv/sv/dv_base_reg/dv_base_reg.core b/hw/dv/sv/dv_base_reg/dv_base_reg.core
index dec50d7..39a147b 100644
--- a/hw/dv/sv/dv_base_reg/dv_base_reg.core
+++ b/hw/dv/sv/dv_base_reg/dv_base_reg.core
@@ -9,6 +9,7 @@
files_dv:
depend:
- lowrisc:dv:dv_utils
+ - lowrisc:prim:mubi
files:
- dv_base_reg_pkg.sv
- csr_excl_item.sv: {is_include_file: true}
@@ -18,6 +19,7 @@
- dv_base_reg_block.sv: {is_include_file: true}
- dv_base_reg_map.sv: {is_include_file: true}
- dv_base_lockable_field_cov.sv: {is_include_file: true}
+ - dv_base_mubi_cov.sv: {is_include_file: true}
file_type: systemVerilogSource
targets:
diff --git a/hw/dv/sv/dv_base_reg/dv_base_reg_field.sv b/hw/dv/sv/dv_base_reg/dv_base_reg_field.sv
index 1f5bf09..c6998d8 100644
--- a/hw/dv/sv/dv_base_reg/dv_base_reg_field.sv
+++ b/hw/dv/sv/dv_base_reg/dv_base_reg_field.sv
@@ -14,6 +14,9 @@
local dv_base_reg_field regwen_fld;
local dv_base_lockable_field_cov lockable_field_cov;
+ // variable for mubi coverage, which is only created when this is a mubi reg
+ dv_base_mubi_cov mubi_cov;
+
`uvm_object_utils(dv_base_reg_field)
`uvm_object_new
@@ -115,6 +118,11 @@
lockable_field_cov = dv_base_lockable_field_cov::type_id::create(`gfn);
endfunction
+ function void create_mubi_cov(int mubi_width);
+ mubi_cov = dv_base_mubi_cov::type_id::create(`gfn);
+ mubi_cov.create_cov(mubi_width);
+ endfunction
+
// Returns true if this field can lock the specified register/field, else return false.
// If lockable register is partially lockable (only certain field is lockable), this method will
// still return true.
@@ -156,6 +164,8 @@
uvm_reg_data_t field_val = rw.value[0] & ((1 << get_n_bits()) - 1);
if (lockable_field_cov != null) lockable_field_cov.post_write(field_val, `gmv(regwen_fld));
+
+ if (mubi_cov != null) mubi_cov.sample(field_val);
end
endtask
diff --git a/hw/dv/sv/dv_base_reg/dv_base_reg_pkg.sv b/hw/dv/sv/dv_base_reg/dv_base_reg_pkg.sv
index 5824ae0..cfe03e3 100644
--- a/hw/dv/sv/dv_base_reg/dv_base_reg_pkg.sv
+++ b/hw/dv/sv/dv_base_reg/dv_base_reg_pkg.sv
@@ -114,6 +114,7 @@
`include "csr_excl_item.sv"
`include "dv_base_lockable_field_cov.sv"
+ `include "dv_base_mubi_cov.sv"
`include "dv_base_reg_field.sv"
`include "dv_base_reg.sv"
`include "dv_base_mem.sv"
diff --git a/util/reggen/field.py b/util/reggen/field.py
index 56fe9a7..ebb8122 100644
--- a/util/reggen/field.py
+++ b/util/reggen/field.py
@@ -58,7 +58,8 @@
hwaccess: HWAccess,
bits: Bits,
resval: Optional[int],
- enum: Optional[List[EnumEntry]]):
+ enum: Optional[List[EnumEntry]],
+ mubi: bool):
self.name = name
self.desc = desc
self.tags = tags
@@ -67,6 +68,7 @@
self.bits = bits
self.resval = resval
self.enum = enum
+ self.mubi = mubi
@staticmethod
def from_raw(reg_name: str,
@@ -204,7 +206,7 @@
enum.append(entry)
enum_val_to_name[entry.value] = entry.name
- return Field(name, desc, tags, swaccess, hwaccess, bits, resval, enum)
+ return Field(name, desc, tags, swaccess, hwaccess, bits, resval, enum, is_mubi)
def has_incomplete_enum(self) -> bool:
return (self.enum is not None and
@@ -277,7 +279,7 @@
ret.append(Field(name, desc,
self.tags, self.swaccess, self.hwaccess,
- bits, self.resval, enum))
+ bits, self.resval, enum, self.mubi))
return ret
@@ -291,7 +293,7 @@
return Field(self.name + suffix,
desc, self.tags, self.swaccess, self.hwaccess,
- self.bits, self.resval, enum)
+ self.bits, self.resval, enum, self.mubi)
def _asdict(self) -> Dict[str, object]:
rd = {
diff --git a/util/reggen/reg_block.py b/util/reggen/reg_block.py
index a15dd37..933ef13 100644
--- a/util/reggen/reg_block.py
+++ b/util/reggen/reg_block.py
@@ -407,7 +407,8 @@
hwaccess=hwaccess_obj,
bits=signal.bits,
resval=0,
- enum=None))
+ enum=None,
+ mubi=False))
reg = Register(self.offset,
reg_name,
diff --git a/util/reggen/uvm_reg_base.sv.tpl b/util/reggen/uvm_reg_base.sv.tpl
index b7bef49..4550826 100644
--- a/util/reggen/uvm_reg_base.sv.tpl
+++ b/util/reggen/uvm_reg_base.sv.tpl
@@ -394,6 +394,9 @@
.individually_accessible(1));
${fname}.set_original_access("${field_access}");
+% if field.mubi:
+ ${fname}.create_mubi_cov(.mubi_width(${field_size}));
+% endif
% if field_tags:
// create field tags
% for field_tag in field_tags: