# 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.
from vsc.model.expr_model import ExprModel
from vsc.model.expr_cond_model import ExprCondModel
from vsc.model.expr_literal_model import ExprLiteralModel
from vsc.model.coveritem_base import CoverItemBase
from vsc.model.rand_if import RandIF
from typing import Set, List, Tuple
import random
from _random import Random
from vsc.model.coverage_options_model import CoverageOptionsModel
from vsc.model.rangelist_model import RangelistModel
from vsc.model.coverpoint_bin_type import CoverpointBinType
# Created on Aug 3, 2019
#
# @author: ballance
[docs]
class CoverpointModel(CoverItemBase):
def __init__(self,
target : ExprModel,
name : str,
options,
iff : ExprModel = None):
super().__init__()
self.parent = None
self.target = target
self.iff = iff
# Cached value Target-ref field. This is used to retrieve values for
# type covergroups
self.iff_val_cache = True
self.iff_val_cache_valid = False
self.target_val_cache = 0
self.target_val_cache_valid = False
self.name = name
self.n_bins = 0
self.n_ignore_bins = 0
self.n_illegal_bins = 0
self.unhit_s : Set[int] = set()
self.hit_l : List[int] = []
self.hit_ignore_l : List[int] = []
self.hit_illegal_l : List[int] = []
self.bin_model_l = []
self.ignore_bin_model_l = []
self.illegal_bin_model_l = []
self.srcinfo_decl = None
self.bin_expr = None
# Tracks
self.coverage = 0.0
self.coverage_calc_valid = False
if options is None:
self.options = CoverageOptionsModel()
else:
self.options = options
[docs]
def set_target_value_cache(self, val, iff=True):
self.target_val_cache = val
self.target_val_cache_valid = True
self.iff_val_cache = iff
self.iff_val_cache_valid = True
[docs]
def reset(self):
self.target_val_cache_valid = False
self.iff_val_cache_valid = False
[docs]
def add_bin_model(self, bin_m):
bin_m.parent = self
self.bin_model_l.append(bin_m)
return bin_m
[docs]
def add_ignore_bin_model(self, bin_m):
bin_m.parent = self
bin_m.set_bin_type(CoverpointBinType.Ignore)
self.ignore_bin_model_l.append(bin_m)
return bin_m
[docs]
def add_illegal_bin_model(self, bin_m):
bin_m.parent = self
bin_m.set_bin_type(CoverpointBinType.Illegal)
self.illegal_bin_model_l.append(bin_m)
return bin_m
[docs]
def finalize(self):
self.n_bins = 0
self.n_ignore_bins = 0
self.n_illegal_bins = 0
for b in self.bin_model_l:
self.n_bins += b.finalize(self.n_bins)
for b in self.ignore_bin_model_l:
self.n_ignore_bins += b.finalize(self.n_ignore_bins)
for b in self.illegal_bin_model_l:
self.n_illegal_bins += b.finalize(self.n_illegal_bins)
# Track unhit bins within this coverpoint
self.unhit_s.update(range(self.n_bins))
self.hit_l = [0]*self.n_bins
self.hit_ignore_l = [0]*self.n_ignore_bins
self.hit_illegal_l = [0]*self.n_illegal_bins
[docs]
def get_bin_expr(self, bin_idx):
b = None
# First, find the bin this index applies to
for i in range(len(self.bin_model_l)):
b = self.bin_model_l[i]
if b.get_n_bins() > bin_idx:
break
bin_idx -= b.get_n_bins()
# Now, return the actual expression
return b.get_bin_expr(bin_idx)
def _get_target_bin(self, bin_idx)->Tuple['CoverpointBinModelBase',int]:
b = None
# First, find the bin this index applies to
for i in range(len(self.bin_model_l)):
b = self.bin_model_l[i]
if b.get_n_bins() > bin_idx:
break
bin_idx -= b.get_n_bins()
return (b,bin_idx)
def _get_target_ignore_bin(self, bin_idx)->Tuple['CoverpointBinModelBase',int]:
b = None
# First, find the bin this index applies to
for i in range(len(self.ignore_bin_model_l)):
b = self.ignore_bin_model_l[i]
if b.get_n_bins() > bin_idx:
break
bin_idx -= b.get_n_bins()
return (b,bin_idx)
def _get_target_illegal_bin(self, bin_idx)->Tuple['CoverpointBinModelBase',int]:
b = None
# First, find the bin this index applies to
for i in range(len(self.illegal_bin_model_l)):
b = self.illegal_bin_model_l[i]
if b.get_n_bins() > bin_idx:
break
bin_idx -= b.get_n_bins()
return (b,bin_idx)
[docs]
def get_coverage(self)->float:
if self.parent.type_cg is None:
return self.get_inst_coverage()
else:
return self.get_inst_coverage()
[docs]
def get_inst_coverage(self):
if not self.coverage_calc_valid:
self.coverage = (len(self.hit_l)-len(self.unhit_s))/len(self.hit_l) * 100.0
self.coverage_calc_valid = True
return self.coverage
[docs]
def sample(self):
if self.iff is not None and not self.iff_val_cache_valid:
self.iff_val_cache_valid = True
self.iff_val_cache = bool(self.iff.val())
if self.iff_val_cache:
for b in self.bin_model_l:
b.sample()
for b in self.ignore_bin_model_l:
b.sample()
for b in self.illegal_bin_model_l:
b.sample()
[docs]
def select_unhit_bin(self, r:RandIF)->int:
if len(self.unhit_s) > 0:
return r.sample(self.unhit_s,1)[0]
# return random.sample(self.unhit_s,1)[0]
else:
return -1
[docs]
def get_bin_range(self, bin_idx) -> RangelistModel:
b,off = self._get_target_bin(bin_idx)
return b.get_bin_range(off)
pass
[docs]
def coverage_ev(self, bin_idx, bin_type):
"""Called by a bin to signal that an uncovered bin has been covered"""
self.coverage_calc_valid = False
if bin_type == CoverpointBinType.Bins:
if bin_idx in self.unhit_s:
self.parent.coverage_ev(self, bin_idx)
self.unhit_s.remove(bin_idx)
self.hit_l[bin_idx] += 1
self.coverage_calc_valid = False
elif bin_type == CoverpointBinType.Ignore:
self.hit_ignore_l[bin_idx] += 1
elif bin_type == CoverpointBinType.Illegal:
self.hit_illegal_l[bin_idx] += 1
[docs]
def get_val(self):
if self.target is not None and not self.target_val_cache_valid:
self.target_val_cache_valid = True
self.target_val_cache = self.target.val()
return self.target_val_cache
[docs]
def accept(self, v):
v.visit_coverpoint(self)
[docs]
def dump(self, ind=""):
print(ind + "Coverpoint: " + self.name)
for b in self.bin_model_l:
b.dump(ind + " ")
[docs]
def get_n_bins(self):
return self.n_bins
[docs]
def get_n_ignore_bins(self):
return self.n_ignore_bins
[docs]
def get_n_illegal_bins(self):
return self.n_illegal_bins
[docs]
def get_n_hit_bins(self):
return len(self.hit_l)-len(self.unhit_s)
[docs]
def get_bin_hits(self, bin_idx):
return self.hit_l[bin_idx]
[docs]
def get_ignore_bin_hits(self, bin_idx):
return self.hit_ignore_l[bin_idx]
[docs]
def get_illegal_bin_hits(self, bin_idx):
return self.hit_illegal_l[bin_idx]
[docs]
def get_bin_name(self, bin_idx)->str:
b,idx = self._get_target_bin(bin_idx)
return b.get_bin_name(idx)
[docs]
def get_ignore_bin_name(self, bin_idx)->str:
b,idx = self._get_target_ignore_bin(bin_idx)
return b.get_bin_name(idx)
[docs]
def get_illegal_bin_name(self, bin_idx)->str:
b,idx = self._get_target_illegal_bin(bin_idx)
return b.get_bin_name(idx)
[docs]
def get_hit_bins(self, bin_l):
bin_idx = 0
for b in self.bin_model_l:
if b.hit_idx() != -1:
bin_l.append(bin_idx + b.hit_idx())
bin_idx += b.n_bins()
[docs]
def equals(self, oth:'CoverpointModel')->bool:
eq = True
eq &= self.name == oth.name
if len(self.bin_model_l) == len(oth.bin_model_l):
for s,o in zip(self.bin_model_l, oth.bin_model_l):
eq &= s.equals(o)
else:
eq= False
if len(self.ignore_bin_model_l) == len(oth.ignore_bin_model_l):
for s,o in zip(self.ignore_bin_model_l, oth.ignore_bin_model_l):
eq &= s.equals(o)
else:
eq= False
if len(self.illegal_bin_model_l) == len(oth.illegal_bin_model_l):
for s,o in zip(self.illegal_bin_model_l, oth.illegal_bin_model_l):
eq &= s.equals(o)
else:
eq= False
return eq
[docs]
def clone(self)->'CoverpointModel':
ret = CoverpointModel(self.target, self.name, self.options.clone())
ret.srcinfo_decl = None if self.srcinfo_decl is None else self.srcinfo_decl.clone()
for bn in self.bin_model_l:
ret.add_bin_model(bn.clone())
for bn in self.ignore_bin_model_l:
ret.add_ignore_bin_model(bn.clone())
for bn in self.illegal_bin_model_l:
ret.add_illegal_bin_model(bn.clone())
return ret