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.
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.
Description
Setting
rand_modeon a nested object declared withvsc.rand_attrinsidepre_randomize()causes anAttributeErrorwhen used withrandomize_with(). After the first failure, all subsequentrandomize_with()calls on the same object also fail, even with unrelated constraints.Minimal Reproducible Example
Expected output
Actual output
Workaround
Based on #136,
rand_modedoesn't fully work inpre_randomize()for scalar fields either. The suggested workaround from that issue is to useset_used_rand()alongsiderand_modeto mimic SystemVerilog behavior:Following that approach, I applied both calls to a
rand_attrnested object as well. However, usingrand_modeon arand_attrobject (not a scalar field) triggers the crash described above -_int_rand_infois not initialized at that point. The fix forrand_attris to skiprand_modeentirely and rely only onset_used_rand():Root Cause
I believe the root cause is in
rand_obj.py__setattr__:_int_rand_infois not initialized on nestedrand_attrobjects beforepre_randomize()is called insiderandomize_with.__exit__, so the setter crashes.Note on #136
This issue is closely related to #136. Since
rand_modeinpre_randomize()doesn't work correctly for scalar fields either, many users end up usingset_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 thepre_randomize()level.