Skip to content

rand_mode on rand_attr nested object crashes inside randomize_with() #266

@BanuAdrian

Description

@BanuAdrian

Description

Setting rand_mode on a nested object declared with vsc.rand_attr inside pre_randomize() causes an AttributeError when used with randomize_with(). After the first failure, all subsequent randomize_with() calls on the same object also fail, even with unrelated constraints.

Minimal Reproducible Example

import vsc

@vsc.randobj
class Inner:
    def __init__(self):
        self.x = vsc.rand_uint8_t()

@vsc.randobj
class Outer:
    def __init__(self):
        self.inner = vsc.rand_attr(Inner())
        self.y = vsc.rand_uint8_t()

    def pre_randomize(self):
        with vsc.raw_mode():
            self.inner.rand_mode = True  # crashes

item = Outer()
item.randomize()

try:
    with item.randomize_with() as it:
        it.y.inside(vsc.rangelist((0, 10)))
        it.y.inside(vsc.rangelist((100, 200)))  # intentional conflict
except Exception as e:
    print(f"first: {e}")  # 'Inner' object has no attribute '_int_rand_info'

try:
    with item.randomize_with() as it:
        it.y.inside(vsc.rangelist((0, 10)))
    print(f"second ok: y={item.y}")
except Exception as e:
    print(f"second: {e}")  # same error - permanently broken

Expected output

first: solve failure
second ok: y=5

Actual output

first: 'Inner' object has no attribute '_int_rand_info'
second: 'Inner' object has no attribute '_int_rand_info'

Workaround

Based on #136, rand_mode doesn't fully work in pre_randomize() for scalar fields either. The suggested workaround from that issue is to use set_used_rand() alongside rand_mode to mimic SystemVerilog behavior:

def pre_randomize(self):
    with vsc.raw_mode():
        self.y.rand_mode = False
        self.y.get_model().set_used_rand(False)  # needed because of #136

Following that approach, I applied both calls to a rand_attr nested object as well. However, using rand_mode on a rand_attr object (not a scalar field) triggers the crash described above - _int_rand_info is not initialized at that point. The fix for rand_attr is to skip rand_mode entirely and rely only on set_used_rand():

def pre_randomize(self):
    with vsc.raw_mode():
        # rand_mode alone doesn't work (#136), set_used_rand is needed anyway
        # but on rand_attr, rand_mode also crashes - so skip it entirely
        self.inner.get_model().set_used_rand(True)

Root Cause

I believe the root cause is in rand_obj.py __setattr__:

elif field == "rand_mode":
    self._int_rand_info.rand_mode = bool(val)

_int_rand_info is not initialized on nested rand_attr objects before pre_randomize() is called inside randomize_with.__exit__, so the setter crashes.

Note on #136

This issue is closely related to #136. Since rand_mode in pre_randomize() doesn't work correctly for scalar fields either, many users end up using set_used_rand() as the primary workaround. Is there any update on when #136 will be fixed? A proper fix there would also clarify the intended API for controlling randomization at the pre_randomize() level.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions