mciepluc / cocotb-coverage

Functional Coverage and Constrained Randomization Extensions for Cocotb
BSD 2-Clause "Simplified" License
100 stars 15 forks source link

How to set bins with two values #82

Closed Kuri-aldec closed 1 year ago

Kuri-aldec commented 1 year ago

Hello,

I would like to set the following SystemVerilog coverpoints using the cocotb-coverage:

parity_cover: coverpoint LCR[4:3] iff(WR_B[3] & init_end) {
    wildcard bins n_parity = {2'b?0};
    bins parity_odd  = {2'b01};
    bins parity_even = {2'b11};
}

The documentation says that wildcards are not allowed in CoverPoints:

Please note, that in cocotb-coverage all bins must be explicitly defined in the “bins” list. There is no option to use a wildcard or ignore bins.

I tried some descriptions, but it didn't work properly :

CoverPoint ("TxMod.pt1", xf = lambda data_bit, stop_bit, parity_bit: parity_bit, bins = [(0, 2), 1, 3], bins_labels = ["n_parity", "parity_o", "parity_e"])

First case, the n_parity is not couted (I think cocotb-coverage treats it as a transition)

CoverPoint ("TxMod.pt1", xf = lambda data_bit, stop_bit, parity_bit: parity_bit, bins = [0, 2, 1, 3], bins_labels = ["n_parity", "n_parity", "parity_o", "parity_e"])

Secound case, only count if the value is 2

CoverPoint ("TxMod.pt1", xf = lambda data_bit, stop_bit, parity_bit: parity_bit, bins = [{0, 2}, 1, 3], bins_labels = ["n_parity", "parity_o", "parity_e"])

Last case, Type error occured.

Would you give some advice how to write?

mciepluc commented 1 year ago

Hi @Kuri-aldec

If I understood correctly you would like to define your bins for two types: int value and tuple. You can do this by defining your own relation function. By default, relation function is a unity operator, that is why you are seeing the described behavior. You need to overload this function to make sure it correctly handles both int values and tuples.

Kuri-aldec commented 1 year ago

Hi @mciepluc

Thank you for your advice. I will try to change relation function, but it's going to take a while

Kuri-aldec commented 1 year ago

Hi @mciepluc

I was able to do that by updating the relations in coverage.py Here are the changes for your reference. Please let me know if you have any comments.

INIT constructor in coverage.py:

            # equality operator is the default bins matching relation
            self._relation = rel if rel is not None else operator.eq
            self._weight = weight
            self._at_least = at_least
            self._injection = inj

            def tuple_check (a):  # Aldec : extract tuple from list
                _tuple_temp = []
                for i in range(len(a)):
                    if (isinstance(a[i], tuple)):
                        _tuple_temp.append(a[i])
                return(_tuple_temp)

            if (len(bins) != 0):
                self._size = self._weight * len(bins)
                self._tuple_list = tuple_check(bins)  # Aldec get tupple list
                self._hits = OrderedDict.fromkeys(bins, 0)
            else:  # if no bins specified, add one bin equal True
                self._size = self._weight
                self._tuple_list = tuple_check(bins)  # Aldec get tupple list
               self._hits = OrderedDict.fromkeys([True], 0)

CALL constructor in coverage.py:

            current_coverage = self.coverage
            self._new_hits = []

            def tuple_results (a):  # Aldec : Check result by tuple
                _result_temp = self._transformation(*cb_args)
                for i in range(len(a)):
                    for j in range(len(a[i])):
                        if (a[i][j] == _result_temp):
                            return (a[i])
                        else:
                            _result = _result_temp
                return (_result)

            # if function is bound then remove "self" from the arguments list
            if self._decorates_method ^ self._trans_is_method:
                result = self._transformation(*cb_args[1:])
            else:
##                result = self._transformation(*cb_args)  #aldec
                result = tuple_results(self._tuple_list)  # # Aldec get result using tuple 
Kuri-aldec commented 1 year ago

There was a mistake The correct is as follows :

            def tuple_results (a):  # Aldec : Check result by tuple
                _result_temp = self._transformation(*cb_args)
                for i in range(len(a)):
                    for j in range(len(a[i])):
                        if (a[i][j] == _result_temp):
                            return (a[i])
                _result = _result_temp
                return (_result)