mirror of
https://github.com/verilator/verilator.git
synced 2026-08-31 18:14:33 +02:00
Fixes #7910.
This commit is contained in:
+69
-26
@@ -133,6 +133,13 @@ union RandomizeMode final {
|
||||
int asInt; // Representation as int to be stored in nodep->user*
|
||||
};
|
||||
|
||||
// Look through unpacked array dimensions to the element type
|
||||
static AstNodeDType* arrayElementDTypep(AstNodeDType* dtypep) {
|
||||
dtypep = dtypep->skipRefp();
|
||||
while (dtypep->isNonPackedArray()) dtypep = dtypep->subDTypep()->skipRefp();
|
||||
return dtypep;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// Visitor that marks classes needing a randomize() method
|
||||
|
||||
@@ -783,6 +790,53 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the one directly-referenced member; it must reach the solver even when it
|
||||
// carries no rand qualifier (the constraint refers to it).
|
||||
void markConstrainedRandMember(AstStructDType* const structp, const std::string& name) {
|
||||
AstMemberDType* const memberp
|
||||
= VN_CAST(m_memberMap.findMember(structp, name), MemberDType);
|
||||
UASSERT_OBJ(memberp, structp, "Constraint references unknown struct member " << name);
|
||||
memberp->markConstrainedRand(true);
|
||||
}
|
||||
|
||||
// True when the aggregate is reached through rand-qualified struct members only
|
||||
bool isRandQualifiedPath(const AstNodeExpr* nodep) {
|
||||
while (nodep) {
|
||||
if (const AstStructSel* const selp = VN_CAST(nodep, StructSel)) {
|
||||
if (AstStructDType* const structp
|
||||
= VN_CAST(selp->fromp()->dtypep()->skipRefp(), StructDType)) {
|
||||
const AstMemberDType* const memberp
|
||||
= VN_CAST(m_memberMap.findMember(structp, selp->name()), MemberDType);
|
||||
if (memberp && !memberp->rand().isRandomizable()) return false;
|
||||
}
|
||||
nodep = selp->fromp();
|
||||
} else if (const AstArraySel* const selp = VN_CAST(nodep, ArraySel)) {
|
||||
nodep = selp->fromp();
|
||||
} else if (const AstCMethodHard* const methodp = VN_CAST(nodep, CMethodHard)) {
|
||||
nodep = methodp->fromp();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// IEEE 1800-2023 18.4: all rand members of a rand unpacked struct are solved
|
||||
// concurrently, so unreferenced rand members must still reach the solver.
|
||||
static void markStructConstrainedRandRecurse(AstNodeDType* const dtypep) {
|
||||
AstStructDType* const structp = VN_CAST(arrayElementDTypep(dtypep), StructDType);
|
||||
if (!structp || structp->packed()) return;
|
||||
structp->markConstrainedRand(true);
|
||||
for (AstMemberDType* memberp = structp->membersp(); memberp;
|
||||
memberp = VN_AS(memberp->nextp(), MemberDType)) {
|
||||
// Non-rand members keep their value. TODO: randc members are solved as
|
||||
// plain rand (uniform); per-member cyclic state is not generated for structs.
|
||||
if (!memberp->rand().isRandomizable()) continue;
|
||||
memberp->markConstrainedRand(true);
|
||||
markStructConstrainedRandRecurse(memberp->subDTypep());
|
||||
}
|
||||
}
|
||||
|
||||
// Build full path for a MemberSel chain (e.g., "obj.l2.l3.l4")
|
||||
std::string buildMemberPath(const AstMemberSel* const memberSelp) {
|
||||
const AstNode* fromp = memberSelp->fromp();
|
||||
@@ -1409,7 +1463,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
}
|
||||
if (VN_IS(varp->dtypeSkipRefp(), StructDType)
|
||||
&& !VN_AS(varp->dtypeSkipRefp(), StructDType)->packed()) {
|
||||
VN_AS(varp->dtypeSkipRefp(), StructDType)->markConstrainedRand(true);
|
||||
markStructConstrainedRandRecurse(varp->dtypeSkipRefp());
|
||||
dimension = 1;
|
||||
}
|
||||
methodp->dtypeSetVoid();
|
||||
@@ -1433,9 +1487,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
varRefp->classOrPackagep(classOrPackagep);
|
||||
methodp->addPinsp(varRefp);
|
||||
}
|
||||
AstNodeDType* tmpDtypep = varp->dtypep();
|
||||
while (tmpDtypep->isNonPackedArray()) tmpDtypep = tmpDtypep->subDTypep();
|
||||
const size_t width = tmpDtypep->width();
|
||||
const size_t width = arrayElementDTypep(varp->dtypep())->width();
|
||||
methodp->addPinsp(
|
||||
new AstConst{varp->dtypep()->fileline(), AstConst::Unsized64{}, width});
|
||||
AstNodeExpr* const varnamep = new AstCExpr{varp->fileline(), AstCExpr::Pure{},
|
||||
@@ -1917,16 +1969,12 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
m_structSel = true;
|
||||
if (VN_IS(nodep->fromp()->dtypep()->skipRefp(), StructDType)) {
|
||||
AstNodeExpr* const fromp = nodep->fromp();
|
||||
if (VN_IS(fromp, StructSel)) {
|
||||
VN_AS(fromp->dtypep()->skipRefp(), StructDType)->markConstrainedRand(true);
|
||||
}
|
||||
AstMemberDType* memberp = VN_AS(fromp->dtypep()->skipRefp(), StructDType)->membersp();
|
||||
while (memberp) {
|
||||
if (memberp->name() == nodep->name()) {
|
||||
memberp->markConstrainedRand(true);
|
||||
break;
|
||||
} else
|
||||
memberp = VN_CAST(memberp->nextp(), MemberDType);
|
||||
AstStructDType* const structp = VN_AS(fromp->dtypep()->skipRefp(), StructDType);
|
||||
markConstrainedRandMember(structp, nodep->name());
|
||||
if (isRandQualifiedPath(fromp)) {
|
||||
markStructConstrainedRandRecurse(fromp->dtypep());
|
||||
} else {
|
||||
structp->markConstrainedRand(true);
|
||||
}
|
||||
}
|
||||
// Mark Random for structArray
|
||||
@@ -1934,16 +1982,13 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
AstNodeExpr* const fromp = VN_IS(nodep->fromp(), ArraySel)
|
||||
? VN_AS(nodep->fromp(), ArraySel)->fromp()
|
||||
: VN_AS(nodep->fromp(), CMethodHard)->fromp();
|
||||
AstStructDType* const dtypep
|
||||
AstStructDType* const structp
|
||||
= VN_AS(fromp->dtypep()->skipRefp()->subDTypep()->skipRefp(), StructDType);
|
||||
dtypep->markConstrainedRand(true);
|
||||
AstMemberDType* memberp = dtypep->membersp();
|
||||
while (memberp) {
|
||||
if (memberp->name() == nodep->name()) {
|
||||
memberp->markConstrainedRand(true);
|
||||
break;
|
||||
} else
|
||||
memberp = VN_CAST(memberp->nextp(), MemberDType);
|
||||
markConstrainedRandMember(structp, nodep->name());
|
||||
if (isRandQualifiedPath(fromp)) {
|
||||
markStructConstrainedRandRecurse(fromp->dtypep()->skipRefp()->subDTypep());
|
||||
} else {
|
||||
structp->markConstrainedRand(true);
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
@@ -5412,9 +5457,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
dimension = dims.second;
|
||||
}
|
||||
|
||||
AstNodeDType* tmpDtypep = arrVarp->dtypep();
|
||||
while (tmpDtypep->isNonPackedArray()) tmpDtypep = tmpDtypep->subDTypep();
|
||||
const size_t width = tmpDtypep->width();
|
||||
const size_t width = arrayElementDTypep(arrVarp->dtypep())->width();
|
||||
|
||||
methodp->addPinsp(new AstConst{fl, AstConst::Unsized64{}, width});
|
||||
AstNodeExpr* const varnamep = new AstCExpr{
|
||||
|
||||
Reference in New Issue
Block a user