mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Fix inline constraints creating class random generator (#5280)
This commit is contained in:
+26
-3
@@ -2338,17 +2338,40 @@ public:
|
||||
// root superclass). Note: after V3Scope, several children are moved under an AstScope and will
|
||||
// not be found by this.
|
||||
template <typename Callable>
|
||||
void foreachMember(const Callable& visit) {
|
||||
void foreachMember(const Callable& f) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type;
|
||||
static_assert(
|
||||
vlstd::is_invocable<Callable, AstClass*, T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Callable 'f' must have a signature compatible with 'void(AstClass*, T_Node*)', "
|
||||
"with 'T_Node' being a subtype of 'AstNode'");
|
||||
if (AstClassExtends* const extendsp = this->extendsp()) {
|
||||
extendsp->classp()->foreachMember(visit);
|
||||
extendsp->classp()->foreachMember(f);
|
||||
}
|
||||
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (T_Node* memberp = AstNode::privateCast<T_Node, decltype(stmtp)>(stmtp)) {
|
||||
visit(this, memberp);
|
||||
f(this, memberp);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Same as above, but stops after first match
|
||||
template <typename Callable>
|
||||
bool existsMember(const Callable& p) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, Callable, const AstClass*, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Predicate 'p' must have a signature compatible with 'bool(const AstClass*, "
|
||||
"const T_Node*)', with 'T_Node' being a subtype of 'AstNode'");
|
||||
if (AstClassExtends* const extendsp = this->extendsp()) {
|
||||
if (extendsp->classp()->existsMember(p)) return true;
|
||||
}
|
||||
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (T_Node* memberp = AstNode::privateCast<T_Node, decltype(stmtp)>(stmtp)) {
|
||||
if (p(this, memberp)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
class AstClassPackage final : public AstNodeModule {
|
||||
// The static information portion of a class (treated similarly to a package)
|
||||
|
||||
+41
-26
@@ -552,15 +552,22 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
|
||||
|
||||
// METHODS
|
||||
AstVar* getCreateRandomGenerator(AstClass* classp) {
|
||||
if (classp->user3p()) return VN_AS(classp->user3p(), Var);
|
||||
if (classp->extendsp()) return getCreateRandomGenerator(classp->extendsp()->classp());
|
||||
void createRandomGenerator(AstClass* const classp) {
|
||||
if (classp->user3p()) return;
|
||||
if (classp->extendsp()) {
|
||||
createRandomGenerator(classp->extendsp()->classp());
|
||||
return;
|
||||
}
|
||||
AstVar* const genp = new AstVar{classp->fileline(), VVarType::MEMBER, "constraint",
|
||||
classp->findBasicDType(VBasicDTypeKwd::RANDOM_GENERATOR)};
|
||||
genp->user2p(classp);
|
||||
classp->addMembersp(genp);
|
||||
classp->user3p(genp);
|
||||
return genp;
|
||||
}
|
||||
AstVar* getRandomGenerator(AstClass* const classp) {
|
||||
if (classp->user3p()) return VN_AS(classp->user3p(), Var);
|
||||
if (classp->extendsp()) return getRandomGenerator(classp->extendsp()->classp());
|
||||
return nullptr;
|
||||
}
|
||||
AstTask* getCreateConstraintSetupFunc(AstClass* classp) {
|
||||
if (classp->user2p()) return VN_AS(classp->user2p(), Task);
|
||||
@@ -572,6 +579,14 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
classp->user2p(setupAllTaskp);
|
||||
return setupAllTaskp;
|
||||
}
|
||||
void createRandomizeClassVars(AstNetlist* const netlistp) {
|
||||
netlistp->foreach([&](AstClass* const classp) {
|
||||
if (classp->existsMember(
|
||||
[&](const AstClass*, const AstConstraint*) { return true; })) {
|
||||
createRandomGenerator(classp);
|
||||
}
|
||||
});
|
||||
}
|
||||
AstVar* enumValueTabp(AstEnumDType* const nodep) {
|
||||
if (nodep->user2p()) return VN_AS(nodep->user2p(), Var);
|
||||
UINFO(9, "Construct Venumvaltab " << nodep << endl);
|
||||
@@ -756,27 +771,26 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
FileLine* fl = nodep->fileline();
|
||||
|
||||
AstNodeExpr* beginValp = nullptr;
|
||||
AstVar* genp = nullptr;
|
||||
nodep->foreachMember([&](AstClass* classp, AstConstraint* constrp) {
|
||||
AstTask* taskp = VN_AS(constrp->user2p(), Task);
|
||||
if (!taskp) {
|
||||
taskp = newSetupConstraintTask(classp, constrp->name());
|
||||
constrp->user2p(taskp);
|
||||
}
|
||||
AstTaskRef* const setupTaskRefp
|
||||
= new AstTaskRef{constrp->fileline(), taskp->name(), nullptr};
|
||||
setupTaskRefp->taskp(taskp);
|
||||
setupTaskRefp->classOrPackagep(classp);
|
||||
|
||||
genp = getCreateRandomGenerator(nodep);
|
||||
AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep);
|
||||
|
||||
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
|
||||
|
||||
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp};
|
||||
if (constrp->itemsp()) taskp->addStmtsp(constrp->itemsp()->unlinkFrBackWithNext());
|
||||
});
|
||||
AstVar* genp = getRandomGenerator(nodep);
|
||||
if (genp) {
|
||||
nodep->foreachMember([&](AstClass* const classp, AstConstraint* const constrp) {
|
||||
AstTask* taskp = VN_AS(constrp->user2p(), Task);
|
||||
if (!taskp) {
|
||||
taskp = newSetupConstraintTask(classp, constrp->name());
|
||||
constrp->user2p(taskp);
|
||||
}
|
||||
AstTaskRef* const setupTaskRefp
|
||||
= new AstTaskRef{constrp->fileline(), taskp->name(), nullptr};
|
||||
setupTaskRefp->taskp(taskp);
|
||||
setupTaskRefp->classOrPackagep(classp);
|
||||
|
||||
AstTask* const setupAllTaskp = getCreateConstraintSetupFunc(nodep);
|
||||
|
||||
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
|
||||
|
||||
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp};
|
||||
if (constrp->itemsp()) taskp->addStmtsp(constrp->itemsp()->unlinkFrBackWithNext());
|
||||
});
|
||||
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
|
||||
AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep);
|
||||
AstTaskRef* const setupTaskRefp = new AstTaskRef{fl, setupAllTaskp->name(), nullptr};
|
||||
@@ -926,13 +940,13 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
UASSERT_OBJ(classp, m_modp, "Module not class, should have failed in V3Width");
|
||||
}
|
||||
if (classp->user1()) {
|
||||
// We need to first ensure that the class randomizer is instantiated if needed
|
||||
// We need to first ensure that the class constraints are transformed
|
||||
// NOTE: This is safe only because AstClass visit function overwrites all
|
||||
// nesting-dependent state variables
|
||||
iterate(classp);
|
||||
}
|
||||
|
||||
AstVar* const classGenp = getCreateRandomGenerator(classp);
|
||||
AstVar* const classGenp = getRandomGenerator(classp);
|
||||
AstVar* const localGenp
|
||||
= new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, "randomizer",
|
||||
classp->findBasicDType(VBasicDTypeKwd::RANDOM_GENERATOR)};
|
||||
@@ -1007,6 +1021,7 @@ public:
|
||||
// CONSTRUCTORS
|
||||
explicit RandomizeVisitor(AstNetlist* nodep)
|
||||
: m_inlineUniqueNames("__Vrandwith") {
|
||||
createRandomizeClassVars(nodep);
|
||||
iterate(nodep);
|
||||
nodep->foreach([&](AstConstraint* constrp) {
|
||||
VL_DO_DANGLING(pushDeletep(constrp->unlinkFrBack()), constrp);
|
||||
|
||||
Reference in New Issue
Block a user