fvutils / pyvsc

Python packages providing a library for Verification Stimulus and Coverage
https://fvutils.github.io/pyvsc
Apache License 2.0
113 stars 26 forks source link

Issue with size method for list type attributes in constraint block while using solve_order #45

Closed aneels3 closed 3 years ago

aneels3 commented 3 years ago

Hi @mballance I came across a situation where I am not able to use the list_field.size inside the constraint block. I am attaching a test case for you for a better understanding of this issue.

import vsc
from enum import IntEnum, auto

class reg_t(IntEnum):
    A = 0
    B = auto()
    C = auto()
    D = auto()
    E = auto()
    F = auto()
    G = auto()

@vsc.randobj
class my_c:
    def __init__(self):
        self.offset = vsc.randsz_list_t(vsc.int32_t())
        self.reg = vsc.randsz_list_t(vsc.enum_t(reg_t))
        self.num_of_regs = vsc.rand_uint32_t()
        self.reserved_regs = vsc.randsz_list_t(vsc.enum_t(reg_t))
        self.max_offset = vsc.rand_uint32_t()

    @vsc.constraint
    def num_of_reg_c(self):
        self.num_of_regs == 2
        self.reserved_regs.size == 3

    @vsc.constraint
    def reg_c(self):
        vsc.solve_order(self.num_of_regs, self.reg)
        self.reg.size == 2  # self.num_of_regs
        self.offset.size == 2  # self.num_of_regs
        with vsc.foreach(self.reg, idx=True) as i:
            self.reg[i].not_inside(vsc.rangelist(self.reserved_regs, reg_t.A))
        vsc.unique(self.reg)

    @vsc.constraint
    def offset_c(self):
        with vsc.foreach(self.offset, idx=True) as i:
            self.offset[i] in vsc.rangelist(vsc.rng(0, self.max_offset - 1))

obj = my_c()
for i in range(20):
    obj.randomize()
    print(obj.reg)
    print(obj.num_of_regs)
    print(obj.offset)

As you can see in constraint reg_c, I am not able to constraint the reg list size using self.num_of_regs . With Direct values, It's working but that is not I am expecting at all.

With these two statements

self.reg.size == self.num_of_regs
self.offset.size == self.num_of_regs

the error is something like this image

Also, I am assuming this line is redundant. https://github.com/fvutils/pyvsc/blob/5c2aff02b3e71e24a0b23817a66336562708b33f/src/vsc/constraints.py#L369

Please have a look at this. Thanks and regards, Anil

mballance commented 3 years ago

Thanks, @aneels3. Very useful testcase! PyVSC uses an approximation method to determine the maximum size of arrays before randomizing them. Previously, this mechanism did not take into account for transitive equality relationships (eg reg.size == num_of_regs == 2). I've enhanced the approximation to do this properly. Please see the 0.2.7 release

Best Regards, Matthew

aneels3 commented 3 years ago

Hi @mballance Thanks for the fix. The above particular test is working fine as expected.

I have modified the above test with minor changes as per the use-case. here is the modified test

import vsc
from enum import IntEnum, auto

class reg_t(IntEnum):
    A = 0
    B = auto()
    C = auto()
    D = auto()
    E = auto()
    F = auto()
    G = auto()

@vsc.randobj
class my_c:
    def __init__(self):
        self.offset = vsc.randsz_list_t(vsc.int32_t())
        self.reg = vsc.randsz_list_t(vsc.enum_t(reg_t))
        self.num_of_regs = vsc.uint32_t(2)
        self.reserved_regs = vsc.randsz_list_t(vsc.enum_t(reg_t))
        self.max_offset = vsc.rand_uint32_t()

    @vsc.constraint
    def num_of_reg_c(self):
        # self.num_of_regs == 2
        self.reserved_regs.size == 3

    @vsc.constraint
    def reg_c(self):
        vsc.solve_order(self.num_of_regs, self.reg)
        self.reg.size == self.num_of_regs
        self.offset.size == self.num_of_regs
        with vsc.foreach(self.reg, idx=True) as i:
            self.reg[i].not_inside(vsc.rangelist(self.reserved_regs, reg_t.A))
        vsc.unique(self.reg)

    @vsc.constraint
    def offset_c(self):
        with vsc.foreach(self.offset, idx=True) as i:
            self.offset[i] in vsc.rangelist(vsc.rng(0, self.max_offset - 1))

obj = my_c()
for i in range(20):
    obj.randomize()
    print(obj.reg.size)
    print(obj.num_of_regs)
    print(obj.offset.size)

I am getting the same error with this test. Here I am passing the self.num_of_regs = 2 as default value and changed the variable to non-random type. Please look into this!

Regards Anil

aneels3 commented 3 years ago

Hi @mballance Did you get a chance to look into this?