diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 0d8468fb2..77bf43812 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -892,18 +892,25 @@ class ConstraintExprVisitor final : public VNVisitor { AstNodeExpr* constFormatp = membersel ? getConstFormat(membersel->cloneTree(false)) : getConstFormat(nodep); - // Build randmode access: for membersel, access parent object's __Vrandmode + // Build randmode access: for membersel, use member's class randmode if available AstNodeExpr* randModeAccess; if (membersel) { - AstNodeExpr* parentAccess = membersel->fromp()->cloneTree(false); AstNodeModule* const varClassp = VN_AS(varp->user2p(), NodeModule); AstVar* const effectiveRandModeVarp = VN_AS(varClassp->user2p(), Var); - UASSERT_OBJ(effectiveRandModeVarp, nodep, - "Member-selected variable must have randmode in its class"); - AstMemberSel* randModeSel - = new AstMemberSel{varp->fileline(), parentAccess, effectiveRandModeVarp}; - randModeSel->dtypep(effectiveRandModeVarp->dtypep()); - randModeAccess = randModeSel; + if (effectiveRandModeVarp) { + // Member's class has randmode, use it + AstNodeExpr* parentAccess = membersel->fromp()->cloneTree(false); + AstMemberSel* randModeSel + = new AstMemberSel{varp->fileline(), parentAccess, effectiveRandModeVarp}; + randModeSel->dtypep(effectiveRandModeVarp->dtypep()); + randModeAccess = randModeSel; + } else { + // Member's class has no randmode, use current scope's randmode + UASSERT_OBJ(m_randModeVarp, nodep, "No m_randModeVarp"); + randModeAccess = new AstVarRef{varp->fileline(), + VN_AS(m_randModeVarp->user2p(), NodeModule), + m_randModeVarp, VAccess::READ}; + } } else { UASSERT_OBJ(m_randModeVarp, nodep, "No m_randModeVarp"); randModeAccess diff --git a/test_regress/t/t_constraint_global_randMode.v b/test_regress/t/t_constraint_global_randMode.v index b6bde927b..e5906e54c 100755 --- a/test_regress/t/t_constraint_global_randMode.v +++ b/test_regress/t/t_constraint_global_randMode.v @@ -21,14 +21,65 @@ endclass class Foo extends Base; endclass -module t; +package uvm_pkg; + virtual class uvm_object; + endclass + + class uvm_sequence_item; + endclass + + virtual class uvm_sequencer_param_base; + function void send_request(uvm_sequence_item t); + uvm_sequence_item par; + if (0 == par.randomize()) begin + end + endfunction + endclass + + class uvm_reg_item extends uvm_sequence_item; + rand uvm_object extension; + endclass + + class uvm_reg_field extends uvm_object; + rand int value; + virtual function bit get_rand_mode(); + return bit'(value.rand_mode()); + endfunction + endclass + +endpackage + +module t_constraint_global_randMode; + import uvm_pkg::*; + + class reg_r extends uvm_object; + rand int value; + local rand uvm_reg_field _dummy; + constraint _dummy_is_reg {_dummy.value == value;} + function new(); + _dummy = new; + endfunction + endclass + initial begin - Foo d = new; - Base b = d; + Foo d; + Base b; + reg_r r; + + // Test 1: Member class with randmode + d = new; + b = d; b.v.disable_val(); b.v.value = 11; + /* verilator lint_off WIDTHTRUNC */ if (bit'(b.randomize())) $stop; if (b.v.value != 11) $stop; + + // Test 2: Member class without randmode + r = new; + if (!r.randomize()) $stop; + /* verilator lint_on WIDTHTRUNC */ + $write("*-* All Finished *-*\n"); $finish; end