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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions