Source code for vsc.coverage

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

# Created on Aug 3, 2019
#
# @author: ballance

from enum import Enum, auto
import enum
import inspect

from vsc.impl import ctor
from vsc.impl.coverage_registry import CoverageRegistry
from vsc.impl.covergroup_int import CovergroupInt
from vsc.impl.ctor import pop_expr
from vsc.impl.expr_mode import expr_mode
from vsc.impl.options import Options
from vsc.impl.type_options import TypeOptions
from vsc.model.covergroup_model import CovergroupModel
from vsc.model.coverpoint_bin_array_model import CoverpointBinArrayModel
from vsc.model.coverpoint_bin_collection_model import CoverpointBinCollectionModel
from vsc.model.coverpoint_bin_enum_model import CoverpointBinEnumModel
from vsc.model.coverpoint_bin_single_bag_model import CoverpointBinSingleBagModel
from vsc.model.coverpoint_bin_single_val_model import CoverpointBinSingleValModel
from vsc.model.coverpoint_cross_model import CoverpointCrossModel
from vsc.model.coverpoint_model import CoverpointModel
from vsc.model.enum_field_model import EnumFieldModel
from vsc.model.expr_fieldref_model import ExprFieldRefModel
from vsc.model.expr_ref_model import ExprRefModel
from vsc.model.field_composite_model import FieldCompositeModel
from vsc.model.field_scalar_model import FieldScalarModel
from vsc.model.rangelist_model import RangelistModel
from vsc.model.source_info import SourceInfo
from vsc.types import rangelist, bit_t, to_expr, type_base, enum_t, type_enum, \
    expr, field_info
from vsc.impl.wildcard_bin_factory import WildcardBinFactory
from vsc.model.coverpoint_bin_single_wildcard_model import CoverpointBinSingleWildcardModel
from vsc.model.wildcard_binspec import WildcardBinspec


[docs] def covergroup(T): """Covergroup decorator marks as class as being a covergroup""" if not hasattr(T, "_cg_init"): def dump(self, ind=""): model = self.get_model() model.dump(ind) # TODO: Make adding sample parameters additive? def with_sample(self, *args, **kwargs): model = self.get_model() cg_i = self._get_int() if len(args) == 1 and isinstance(args[0], dict): params = args[0] elif len(kwargs) > 0: params = kwargs else: raise Exception("incorrect call to with_sample. Expect single dict parameter or kwargs") for pn,pt in params.items(): if hasattr(pt, "_int_field_info"): pm = pt.build_field_model(pn) pt._int_field_info.name = pn # Note: this is only used if the field is a list pt._int_field_info.id = len(model.field_l) if hasattr(pt, "_id_fields"): # This field is a composite field, and we # must access its children via indexed references pt._id_fields( pt, self._int_field_info) else: # Scalar field pt._int_field_info.parent = self._int_field_info setattr(self, pn, pt) cg_i.sample_var_l.append(pn) cg_i.sample_obj_l.append(pt) # Add a field to the covergroup model model.add_field(pm) pt._int_field_info.root_e = ExprFieldRefModel(model) else: raise Exception("Sample arguments must vsc objects, not " + str(pt)) # elif len(kwargs) > 0: # for pn,pt in kwargs.items(): # if hasattr(pt, "build_field_model"): # setattr(self, pn, pt) # pm = pt.build_field_model(pn) # # Add a field to the covergroup model # model.add_field(pm) # cg_i.sample_var_l.append(pn) # cg_i.sample_obj_l.append(pt) # else: # print("TODO: handle non-field-model") # setattr(self, pn, lambda:getattr(self, "_" + pn)) # else: # raise Exception("incorrect call to with_sample") def sample(self, *args, **kwargs): """Base sampling method that samples all coverpoints and crosses""" # Build the model if we haven't yet cg_i = self._get_int() # TODO: Need to propagate values to base classes model = self.get_model() sample_var_len = len(cg_i.sample_var_l) if len(args) != sample_var_len: raise Exception("Wrong number of parameters: expect " + str(sample_var_len) + " receive " + str(len(args))) model = self.get_model() for i in range(len(args)): # TODO: need to account for inheritance ex_f = model.get_field(i) us_f = cg_i.sample_obj_l[i] if isinstance(ex_f, FieldCompositeModel): # TODO: probably need to do something a bit more than this? model.set_field(i, args[i].get_model()) elif isinstance(ex_f, EnumFieldModel): ei = us_f.enum_i if isinstance(args[i], type_enum): ex_f.set_val(args[i].get_val()) else: # Use the enum map to convert to an int ex_f.set_val(ei.e2v(args[i])) elif isinstance(ex_f, FieldScalarModel): if isinstance(args[i], type_base): ex_f.set_val(args[i].get_val()) else: ex_f.set_val(int(args[i])) else: raise Exception("unhandled sample case") setattr(self, cg_i.sample_var_l[i], args[i]) # getattr(self, cg_i.sample_var_l[i]).set_val(args[i]) model.sample() pass def get_coverage(self): """ Queries coverage achieved by all instances of this covergroup type :return: coverage achieved as percentage (0..100) """ return self.get_model().get_coverage() def get_inst_coverage(self): """ Queries coverage achieved by this instances of this covergroup type :return: coverage achieved as percentage (0..100) """ return self.get_model().get_inst_coverage() def get_model(self): cg_i = self._get_int() if cg_i.model is None: cg_i.model = CovergroupModel(T.__name__) cg_i.model.srcinfo_decl = getattr(type(self), "_srcinfo_decl") cg_i.model.srcinfo_inst = cg_i.srcinfo_inst return cg_i.model def build_model(self): cg_i = self._get_int() self.get_model() cg_i.model.options = self.options.create_model(None) # Configure the covergroup name # - name specified via 'set_name' takes precedence # - name specified via option has second level name = T.__name__ if hasattr(self, "name") and self.name is not None: name = self.name elif self.options.name is not None: name = self.options.name cg_i.model.name = name obj_name_m = {} for n in dir(self): obj = getattr(self, n) if hasattr(obj, "build_cov_model"): obj_name_m[obj] = n for b in self.buildable_l: cp_m = b.build_cov_model(cg_i.model, obj_name_m[b]) cg_i.model.add_coverpoint(cp_m) # Register the covergroup in the registry. This will ensure that # this coverage instance is properly connected to the type coverage # If the instance covergroup happens to be parameterized, # then the type covergroup must have the same parameterization CoverageRegistry.inst().register_cg(self.get_model()) # We're done, so lock the covergroup self.lock() # Finalize the contents of the covergroup cg_i.model.finalize() def _get_int(self): if not hasattr(self, "_cg_int"): self._cg_int = CovergroupInt(self) return self._cg_int def lock(self): cg_i = self._get_int() cg_i.locked = True self.options.lock() self.type_options._lock() def _setattr(self, field, val): if hasattr(val, "build_cov_model"): if not hasattr(self, "buildable_l"): object.__setattr__(self, "buildable_l", []) self.buildable_l.append(val) object.__setattr__(self, field, val) def set_name(self, name): self.name = name cg_i = self._get_int() if cg_i.model is not None: cg_i.model.name = name def get_name(self) -> str: return self.name def configure_options(self, *args, **kwargs): if len(args) == 1 and isinstance(args[0], dict): opts=args[0] else: opts = kwargs print("TODO: reconfigure options") print("TODO: detect wether options are locked") return self setattr(T, "dump", dump) setattr(T, "with_sample", with_sample) setattr(T, "sample", sample) setattr(T, "get_coverage", get_coverage) setattr(T, "get_inst_coverage", get_inst_coverage) setattr(T, "get_model", get_model) setattr(T, "build_model", build_model) setattr(T, "_get_int", _get_int) setattr(T, "lock", lock) setattr(T, "__setattr__", _setattr) setattr(T, "set_name", set_name) setattr(T, "get_name", get_name) setattr(T, "_cg_init", True) setattr(T, "configure_options", configure_options) else: raise Exception("Covergroup inheritance is not currently supported") # Store declaration information on the type if hasattr(T, "__file__"): try: file = inspect.getsourcefile(T) if file is not None: lineno = inspect.getsourcelines(T)[1] else: file = "<unknown>" lineno = -1 except Exception: # In case an exception is encountered -- perhaps due to # the code being Cython compiled file = "<unknown>" lineno = -1 else: file = "<unknown>" lineno = -1 setattr(T, "_srcinfo_decl", SourceInfo(file, lineno)) # This is the interposer class that wraps a user-defined # covergroup class. It ensures that the coverage model is # created while field refs are treated as expressions class covergroup_interposer(T): def __init__(self, *args, **kwargs): cg_i = self._get_int() # Capture the instantiation location of this covergroup frame = inspect.stack()[1] cg_i.srcinfo_inst = SourceInfo(frame.filename, frame.lineno) self.buildable_l = [] # Construct the model model = self.get_model() # Ensure options/type_options created before # calling (user) base-class __init__ if not hasattr(self, "options"): self.options = Options() if not hasattr(self, "type_options"): self.type_options = TypeOptions() for a in args: if hasattr(a, "_ro_init"): # Ensure the model is constructed a.get_model() if cg_i.ctor_level == 0: self._int_field_info = field_info() self._int_field_info.root_e = ExprFieldRefModel(model) with cg_i: super().__init__(*args, **kwargs) if cg_i.ctor_level == 0: # TODO: need to actually elaborate the model self.build_model() ret = type(T.__name__, (covergroup_interposer,), dict()) return ret
[docs] class bin(object): """Specifies a single coverage bin""" def __init__(self, *args): self.range_l = args # Capture the declaration location of this bin frame = inspect.stack()[1] self.srcinfo_decl = SourceInfo(frame.filename, frame.lineno)
[docs] def build_cov_model(self, parent, name, exclude_bins : RangelistModel): # Construct a range model range_l = RangelistModel(self.range_l) range_l.compact() if exclude_bins is not None and len(exclude_bins.range_l) > 0: # Apply exclusions range_l.intersect(exclude_bins) if len(range_l.range_l) > 0: ret = CoverpointBinSingleBagModel(name, range_l) ret.srcinfo_decl = self.srcinfo_decl else: ret = None return ret
[docs] class bin_array(object): """Specifies an array of bins""" def __init__(self, nbins, *args): """ args may be one of two formats - Single list of tuples or lists of values or ranges (eg [[1], [2,4], [8]]) - Arguments comprising values and ranges (eg 1, [2,4], 8) """ self.nbins = nbins self.ranges = RangelistModel() # Convert the specification into canonical form: list of tuples if len(args) == 1: # Argument must be a value, a single-level list, or if isinstance(args[0], (list,tuple)): # Must determine whether this is a programmatic description # or a single user-specified range if isinstance(args[0][0], (list,tuple)): # Programmatic description for r in args: if isinstance(r, (list,tuple)): if len(r) not in [1,2]: raise Exception("Programmatic bin specification elements require 1 or 2 elements: " + str(r)) self.ranges.add_range(r[0], r[1]) elif isinstance(r, int): self.ranges.add_value(r) else: raise Exception("Unknown bin specification " + str(r)) else: # User-specified range if len(args[0]) != 2: raise Exception("Expect two elements in a user-specified range") if not isinstance(args[0][0], int): raise Exception("Bin value " + str(args[0][0]) + " is not integral") if not isinstance(args[0][1], int): raise Exception("Bin value " + str(args[0][1]) + " is not integral") self.ranges.add_range(args[0][0], args[0][1]) elif isinstance(args[0],int): # user-specified single-value bin self.ranges.add_value(args[0]) else: raise Exception("Bin specification " + str(args[0]) + " is neither value nor range") pass else: # Multiple arguments. Expect each to be a single-level tuple or list for a in args: if isinstance(a,(list,tuple)): if len(a) != 2: raise Exception("Bin range " + str(a) + " must have two elements") else: self.ranges.add_range(a[0], a[1]) elif isinstance(a,int): self.ranges.add_value(a) else: raise Exception("Bin specification " + str(a) + " is neither value nor range") if isinstance(nbins,list): if len(nbins) not in (0,1): raise Exception("Only 0 or 1 argument can be specified to the nbins argument") self.nbins = -1 if len(nbins) == 0 else nbins[0] else: self.nbins = int(nbins) if len(args) == 0: raise Exception("No bins range specified") self.ranges.compact() # Capture the declaration location of this bin frame = inspect.stack()[1] self.srcinfo_decl = SourceInfo(frame.filename, frame.lineno)
[docs] def build_cov_model(self, parent, name, exclude_bins : RangelistModel): ret = None if len(exclude_bins.range_l) > 0: self.ranges.intersect(exclude_bins) # First, need to determine how many total bins # Construct a range model if self.nbins == -1: # unlimited number of bins if len(self.ranges.range_l) == 1: r = self.ranges.range_l[0] ret = CoverpointBinArrayModel(name, r[0], r[1]) else: idx=0 ret = CoverpointBinCollectionModel(name) for r in self.ranges.range_l: if r[0] != r[1]: b = ret.add_bin(CoverpointBinArrayModel(name, r[0], r[1])) b.srcinfo_decl = self.srcinfo_decl idx += ((r[1] - r[0]) + 1) elif r[0] == r[1]: b = ret.add_bin(CoverpointBinSingleValModel(name + "[" + str(idx) + "]", r[0])) b.srcinfo_decl = self.srcinfo_decl idx += 1 else: raise Exception("Internal error: expect bin to have 1 or 2 elements not " + str(len(r)) + " (" + name + " " + self.srcinfo_decl.filename + ":" + str(self.srcinfo_decl.lineno) + ")") else: ret = CoverpointBinCollectionModel.mk_collection(name, self.ranges, self.nbins) ret.srcinfo_decl = self.srcinfo_decl return ret
[docs] class wildcard_bin(object): """Specifies a single wildcard coverage bin""" def __init__(self, *args): # Capture the declaration location of this bin self.srcinfo_decl = SourceInfo.mk() self.range_l = [] for a in args: if isinstance(a, tuple): # Expressed in mask form # (value, mask) where 1-bits in mask are compared and 0-bits are ignored self.range_l.append(a) elif isinstance(a, str): # Expressed in string form in either oct, hex, or bin format # value, mask = WildcardBinFactory.str2bin(a) self.range_l.append((value,mask)) else: raise Exception("Unknown argument %s to wildcard bin. Expect tuple or string" % ( str(a)))
[docs] def build_cov_model(self, parent, name, excluded_bins): ret = CoverpointBinSingleWildcardModel( name, WildcardBinspec(self.range_l)) ret.srcinfo_decl = self.srcinfo_decl return ret
[docs] class wildcard_bin_array(object): """Specifies an array of bins using wildcard specifications""" def __init__(self, nbins, *args): """ args may be one of two formats - Single list of wildcard strings (eg "0x82x") - Single list of value/mask tuples (eg [(0x820,0xFF0)]) - Single string - Single tuple """ self.nbins = nbins self.range_l = [] # Convert the specification into canonical form: list of tuples if len(args) == 1: if isinstance(args[0], str): value, mask = WildcardBinFactory.str2bin(args[0]) self.range_l.extend(WildcardBinFactory.valmask2binlist(value, mask)) elif isinstance(args[0], (list,tuple)): # value/mask if len(args[0]) != 2: raise Exception("Wildcard bin specification requires two elements (value,mask)") self.range_l.extend(WildcardBinFactory.valmask2binlist(args[0][0], args[0][1])) else: raise Exception("Bin specification " + str(args[0]) + " is neither string nor value/mask") pass else: # Multiple arguments. Expect each to be a single-level string or tuple for a in args: if isinstance(a,(list,tuple)): if len(a) != 2: raise Exception("Wildcard bin range " + str(a) + " must have two elements") else: self.range_l.extend(WildcardBinFactory.valmask2binlist(a[0], a[1])) elif isinstance(a,str): value, mask = WildcardBinFactory.str2bin(a) self.range_l.extend(WildcardBinFactory.valmask2binlist(value, mask)) else: raise Exception("Wildcard bin specification " + str(a) + " is neither value nor range") # TODO: handle overlap self.range_l.sort(key=lambda e: e[0]) # Now, collapse overlaps i=0 while i < len(self.range_l): if i+1 < len(self.range_l) and self.range_l[i][1]+1 >= self.range_l[i+1][0]: self.range_l[i] = (self.range_l[i][0], self.range_l[i+1][1]) self.range_l.pop(i+1) else: i += 1 if isinstance(nbins,list): if len(nbins) not in (0,1): raise Exception("Only 0 or 1 argument can be specified to the nbins argument") self.nbins = -1 if len(nbins) == 0 else nbins[0] else: self.nbins = int(nbins) if len(args) == 0: raise Exception("No bins range specified") # Capture the declaration location of this bin frame = inspect.stack()[1] self.srcinfo_decl = SourceInfo(frame.filename, frame.lineno)
[docs] def build_cov_model(self, parent, name, excluded_bins): ret = None # First, need to determine how many total bins # Construct a range model if self.nbins == -1: # unlimited number of bins if len(self.range_l) == 1: r = self.range_l[0] ret = CoverpointBinArrayModel(name, r[0], r[1]) else: idx=0 ret = CoverpointBinCollectionModel(name) for r in self.range_l: if len(r) == 2: if r[0] != r[1]: b = ret.add_bin(CoverpointBinArrayModel(name, r[0], r[1])) b.srcinfo_decl = self.srcinfo_decl idx += ((r[1] - r[0]) + 1) else: b = ret.add_bin(CoverpointBinSingleValModel(name + "[" + str(idx) + "]", r[0])) b.srcinfo_decl = self.srcinfo_decl idx += 1 elif len(r) == 1: b = ret.add_bin(CoverpointBinSingleValModel(name + "[" + str(idx) + "]", r[0])) b.srcinfo_decl = self.srcinfo_decl idx += 1 else: raise Exception("Internal error: expect bin to have 1 or 2 elements not " + str(len(r)) + " (" + name + " " + self.srcinfo_decl.filename + ":" + str(self.srcinfo_decl.lineno) + ")") else: ret = CoverpointBinCollectionModel.mk_collection(name, RangelistModel(self.range_l), self.nbins) ret.srcinfo_decl = self.srcinfo_decl return ret
[docs] class binsof(object): # TODO: future implementation of the 'binsof' operator def __init__(self, cp): pass
[docs] def intersect(self, rng): pass
def __and__(self, rhs): pass def __not__(self, rhs): pass def __or__(self, rhs): pass
[docs] class coverpoint(object): def __init__(self, target, cp_t=None, # Type of the coverpoint, when it needs to be specified iff=None, bins=None, ignore_bins=None, illegal_bins=None, options=None, type_options=None, name=None): self.have_var = False self.target = None self.cp_t = cp_t self.model = None self.target_kind = None self.target_type = None self.get_val_f = None self.options = Options() self.type_options = TypeOptions() self.name = name self.iff = None self.iff_f = None # Capture the declaration location of this coverpoint frame = inspect.stack()[1] self.srcinfo_decl = SourceInfo(frame.filename, frame.lineno) ctor.clear_exprs() if options is not None: self.options.set(options) if type_options is not None: self.type_options.set(type_options) with expr_mode(): if isinstance(target, type_enum): self.have_var = True self.target = target.to_expr().em self.cp_t = target elif isinstance(target, type_base): self.have_var = True self.target = target.to_expr().em self.cp_t = target elif callable(target): if cp_t is None and bins is None: raise Exception("Auto-binned coverpoint with a callable target must specify type using 'cp_t'") # Accept the user-specified type self.cp_t = cp_t self.target = target self.get_val_f = target elif isinstance(target, expr): self.have_var = True self.target = target.em if cp_t is not None: self.cp_t = cp_t else: # Get the express width for the implied type self.cp_t = bit_t(target.em.width()) else: # should be an actual variable (?) # TODO: or, could be an expression print("TODO: handle actual variables") to_expr(target) self.target = pop_expr() print("target=" + str(self.target)) self.get_val_f = self.target.val print("self.get_val_f=" + str(self.get_val_f)) if iff is not None: if isinstance(iff, expr): self.iff = iff.em elif isinstance(iff, (type_enum,type_base)): iff.to_expr() self.iff = pop_expr() elif callable(iff): # The user has provided a function to # gate when sampling occurs self.iff_f = iff else: raise Exception("Unknown iff type " + str(iff)) self.bins = bins self.ignore_bins = ignore_bins self.illegal_bins = illegal_bins ctor.clear_exprs()
[docs] def get_coverage(self): if self.model is None: return 0.0 else: return self.model.get_coverage()
[docs] def get_inst_coverage(self): if self.model is None: return 0.0 else: return self.model.get_inst_coverage()
[docs] def build_cov_model(self, parent, name): if self.model is None: options = self.options.create_model(parent.options) if self.get_val_f is not None: if self.cp_t is not None and isinstance(self.cp_t, type_base): width = self.cp_t.width is_signed = self.cp_t.is_signed else: width = 32 is_signed = True sample_expr = ExprRefModel( self.get_val_f, width, is_signed) else: sample_expr = self.target iff_e = None if self.iff_f is not None: iff_e = ExprRefModel(self.iff_f, 1, False) elif self.iff is not None: iff_e = self.iff self.model = CoverpointModel( sample_expr, name if self.name is None else self.name, options, iff_e) self.model.srcinfo_decl = self.srcinfo_decl with expr_mode(): exclude_bins = RangelistModel() if self.ignore_bins is not None: if not isinstance(self.ignore_bins, dict): raise Exception("ignore_bins must be a 'dict'") for ib_name in self.ignore_bins.keys(): ib = self.ignore_bins[ib_name] if isinstance(ib, bin): for r in ib.range_l: if isinstance(r, (dict,tuple)): exclude_bins.add_range(r[0], r[1]) else: exclude_bins.add_value(r) else: raise Exception("ignore_bins only supports 'bin' elements") if self.illegal_bins is not None: if not isinstance(self.illegal_bins, dict): raise Exception("illegal_bins must be a 'dict'") for ib_name in self.illegal_bins.keys(): ib = self.illegal_bins[ib_name] if isinstance(ib, bin): for r in ib.range_l: if isinstance(r, (dict,tuple)): exclude_bins.add_range(r[0], r[1]) else: exclude_bins.add_value(r) else: raise Exception("ignore_bins only supports 'bin' elements") if len(exclude_bins.range_l) > 0: exclude_bins.compact() # TODO: handle illegal_bins in the future if self.bins is None or len(self.bins) == 0: if isinstance(self.cp_t, type_enum): ei = self.cp_t.enum_i enum_bins = RangelistModel() for e,v in ei.e2v_m.items(): enum_bins.add_value(v) # Ensure that they're ordered enum_bins.compact() if len(exclude_bins.range_l) > 0: enum_bins.intersect(exclude_bins) for v in enum_bins.range_l: e = ei.v2e_m[v[0]] # IntEnum.__str__ returns the value rather than the name, use Enum.__str__ instead self.model.add_bin_model(CoverpointBinEnumModel(Enum.__str__(e), v[0])) elif isinstance(self.cp_t, type_base): binspec = RangelistModel() if not self.cp_t.is_signed: binspec.add_range(0, (1 << self.cp_t.width)-1) else: low = (1 << self.cp_t.width-1) high = (1 << self.cp_t.width-1)-1 binspec.add_range(-low, high) if len(exclude_bins.range_l) > 0: # Need to trim bins exclude_bins.compact() binspec.intersect(exclude_bins) self.model.add_bin_model(CoverpointBinCollectionModel.mk_collection( name, binspec, options.auto_bin_max)) else: raise Exception("attempting to create auto-bins from unknown type " + str(self.cp_t)) else: # TODO: need a pre-step where we build the ranges, then trim for bin_name,bin_spec in self.bins.items(): if not hasattr(bin_spec, "build_cov_model"): raise Exception("Bin specification doesn't have a build_cov_model method") bin_m = bin_spec.build_cov_model(self.model, bin_name, exclude_bins) if bin_m is not None: self.model.add_bin_model(bin_m) if self.ignore_bins is not None and len(self.ignore_bins) != 0: # Build dedicated ignore_bins for bin_name,bin_spec in self.ignore_bins.items(): if not hasattr(bin_spec, "build_cov_model"): raise Exception("Bin specification doesn't have a build_cov_model method") bin_m = bin_spec.build_cov_model(self.model, bin_name, None) if bin_m is not None: self.model.add_ignore_bin_model(bin_m) if self.illegal_bins is not None and len(self.illegal_bins) != 0: # Build dedicated ignore_bins for bin_name,bin_spec in self.illegal_bins.items(): if not hasattr(bin_spec, "build_cov_model"): raise Exception("Bin specification doesn't have a build_cov_model method") bin_m = bin_spec.build_cov_model(self.model, bin_name, None) if bin_m is not None: self.model.add_illegal_bin_model(bin_m) return self.model
[docs] def get_model(self): return self.model
[docs] def get_val(self, cp_m): ret = int(self.get_val_f()) return ret
[docs] def set_val(self, val): self.target.set_val(val)
def __le__(self, rhs): if self.have_var: self.target(rhs) else: raise Exception("Attempting to set value of non-variable coverpoint") def _lock(self): self.options.lock() self.type_options._lock()
[docs] class cross(object): def __init__(self, target_l, bins=None, options=None, name=None, iff=None): for t in target_l: if not isinstance(t, coverpoint): raise Exception("Cross target \"" + str(t) + "\" is not a coverpoint") self.target_l = target_l self.bins = bins self.options = Options() if options is not None: self.options.set(options) self.iff_f = None self.iff = None if iff is not None: with expr_mode(): if isinstance(iff, expr): self.iff = iff.em elif isinstance(iff, (type_enum,type_base)): iff.to_expr() self.iff = pop_expr() elif callable(iff): self.iff_f = iff else: raise Exception("Unknown iff type " + str(iff)) # Capture the declaration location of this cross frame = inspect.stack()[1] self.srcinfo_decl = SourceInfo(frame.filename, frame.lineno) self.name = name self.model = None
[docs] def build_cov_model(self, parent, name): # Let the user-specified name take precedence if self.model is None: iff = None options = self.options.create_model(parent.options) if self.iff_f: iff = ExprRefModel(self.iff_f, 1, False) elif self.iff: iff = self.iff ret = CoverpointCrossModel( name if self.name is None else self.name, options, iff) ret.srcinfo_decl = self.srcinfo_decl for cp in self.target_l: m = cp.get_model() ret.add_coverpoint(m) self.model = ret return self.model
[docs] def get_coverage(self): if self.model is None: return 0.0 else: return self.model.get_coverage()