parent
4426aff3d3
commit
22cd9bcadc
|
|
@ -882,20 +882,49 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||||
|
|
||||||
VNRelinker relinker;
|
VNRelinker relinker;
|
||||||
nodep->unlinkFrBack(&relinker);
|
nodep->unlinkFrBack(&relinker);
|
||||||
AstNodeExpr* exprp = new AstSFormatF{nodep->fileline(), smtName, false, nullptr};
|
AstNodeExpr* exprp;
|
||||||
if (randMode.usesMode) {
|
if (randMode.usesMode) {
|
||||||
AstNodeExpr* constFormatp = getConstFormat(nodep);
|
// Use string literal to avoid double formatting
|
||||||
UASSERT_OBJ(m_randModeVarp, nodep, "No m_randModeVarp");
|
exprp = new AstCExpr{nodep->fileline(), "std::string(\"" + smtName + "\")", 1};
|
||||||
AstCMethodHard* const atp = new AstCMethodHard{
|
exprp->dtypeSetString();
|
||||||
nodep->fileline(),
|
|
||||||
new AstVarRef{varp->fileline(), VN_AS(m_randModeVarp->user2p(), NodeModule),
|
// Get const format, using membersel if available for correct width/value
|
||||||
m_randModeVarp, VAccess::READ},
|
AstNodeExpr* constFormatp
|
||||||
VCMethod::ARRAY_AT, new AstConst{nodep->fileline(), randMode.index}};
|
= membersel ? getConstFormat(membersel->cloneTree(false)) : getConstFormat(nodep);
|
||||||
|
|
||||||
|
// Build randmode access: for membersel, access parent object's __Vrandmode
|
||||||
|
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);
|
||||||
|
if (effectiveRandModeVarp) {
|
||||||
|
AstMemberSel* randModeSel
|
||||||
|
= new AstMemberSel{varp->fileline(), parentAccess, effectiveRandModeVarp};
|
||||||
|
randModeSel->dtypep(effectiveRandModeVarp->dtypep());
|
||||||
|
randModeAccess = randModeSel;
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
= new AstVarRef{varp->fileline(), VN_AS(m_randModeVarp->user2p(), NodeModule),
|
||||||
|
m_randModeVarp, VAccess::READ};
|
||||||
|
}
|
||||||
|
|
||||||
|
AstCMethodHard* const atp
|
||||||
|
= new AstCMethodHard{nodep->fileline(), randModeAccess, VCMethod::ARRAY_AT,
|
||||||
|
new AstConst{nodep->fileline(), randMode.index}};
|
||||||
atp->dtypeSetUInt32();
|
atp->dtypeSetUInt32();
|
||||||
exprp = new AstCond{varp->fileline(), atp, exprp, constFormatp};
|
exprp = new AstCond{varp->fileline(), atp, exprp, constFormatp};
|
||||||
} else if (!isGlobalConstrained) {
|
exprp->user1(true); // Mark as formatted
|
||||||
// Non-global constraints: delete nodep immediately
|
} else {
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
exprp = new AstSFormatF{nodep->fileline(), smtName, false, nullptr};
|
||||||
|
if (!isGlobalConstrained) { VL_DO_DANGLING(pushDeletep(nodep), nodep); }
|
||||||
}
|
}
|
||||||
// else: Global constraints keep nodep alive for write_var processing
|
// else: Global constraints keep nodep alive for write_var processing
|
||||||
relinker.relink(exprp);
|
relinker.relink(exprp);
|
||||||
|
|
@ -952,7 +981,9 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||||
methodp->addPinsp(varnamep);
|
methodp->addPinsp(varnamep);
|
||||||
methodp->addPinsp(
|
methodp->addPinsp(
|
||||||
new AstConst{varp->dtypep()->fileline(), AstConst::Unsized64{}, dimension});
|
new AstConst{varp->dtypep()->fileline(), AstConst::Unsized64{}, dimension});
|
||||||
if (randMode.usesMode) {
|
// Don't pass randMode.index for global constraints with membersel
|
||||||
|
// because constraint object can't access nested object's randmode array
|
||||||
|
if (randMode.usesMode && !(isGlobalConstrained && membersel)) {
|
||||||
methodp->addPinsp(
|
methodp->addPinsp(
|
||||||
new AstConst{varp->fileline(), AstConst::Unsized64{}, randMode.index});
|
new AstConst{varp->fileline(), AstConst::Unsized64{}, randMode.index});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
if not test.have_solver:
|
||||||
|
test.skip("No constraint solver installed")
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by PlanV GmbH.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class RandomValue;
|
||||||
|
rand int value;
|
||||||
|
constraint small_int_c {
|
||||||
|
value < 10;
|
||||||
|
}
|
||||||
|
task disable_val();
|
||||||
|
value.rand_mode(0);
|
||||||
|
endtask
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Base;
|
||||||
|
rand RandomValue v = new;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Foo extends Base;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t;
|
||||||
|
initial begin
|
||||||
|
Foo d = new;
|
||||||
|
Base b = d;
|
||||||
|
b.v.disable_val();
|
||||||
|
b.v.value = 11;
|
||||||
|
if (bit'(b.randomize())) $stop;
|
||||||
|
if (b.v.value != 11) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue