mirror of
https://github.com/verilator/verilator.git
synced 2026-09-03 08:24:31 +02:00
Support constraint_mode (#5338)
This commit is contained in:
+271
-131
@@ -100,13 +100,13 @@ struct RandModeTarget final {
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
// Stores info about a variable's rand_mode state
|
||||
// Stores info about a variable's rand_mode state/a constraint's constraint_mode state
|
||||
|
||||
union VarRandMode final {
|
||||
union RandomizeMode final {
|
||||
// MEMBERS
|
||||
struct {
|
||||
bool usesRandMode : 1; // True if variable uses rand_mode
|
||||
uint32_t index : 31; // Index of var in rand_mode vector
|
||||
bool usesMode : 1; // Variable/constraint uses rand_mode/constraint_mode
|
||||
uint32_t index : 31; // Index of var/constraint in rand_mode/constraint_mode vector
|
||||
};
|
||||
int asInt; // Representation as int to be stored in nodep->user*
|
||||
};
|
||||
@@ -155,8 +155,8 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
||||
}
|
||||
// If the class is randomized inline, all members use rand mode
|
||||
if (nodep->user1() == IS_RANDOMIZED_INLINE) {
|
||||
VarRandMode randMode = {};
|
||||
randMode.usesRandMode = true;
|
||||
RandomizeMode randMode = {};
|
||||
randMode.usesMode = true;
|
||||
varp->user1(randMode.asInt);
|
||||
}
|
||||
}
|
||||
@@ -257,8 +257,8 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
||||
valid = false;
|
||||
} else if (randModeTarget.receiverp && randModeTarget.receiverp->isRand()) {
|
||||
// Called on a rand member variable
|
||||
VarRandMode randMode = {};
|
||||
randMode.usesRandMode = true;
|
||||
RandomizeMode randMode = {};
|
||||
randMode.usesMode = true;
|
||||
randModeTarget.receiverp->user1(randMode.asInt);
|
||||
} else {
|
||||
// Called on 'this' or a non-rand class instance
|
||||
@@ -269,8 +269,8 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
||||
"Unsupported: 'rand_mode()' on static variable: "
|
||||
<< varp->prettyNameQ());
|
||||
}
|
||||
VarRandMode randMode = {};
|
||||
randMode.usesRandMode = true;
|
||||
RandomizeMode randMode = {};
|
||||
randMode.usesMode = true;
|
||||
varp->user1(randMode.asInt);
|
||||
});
|
||||
}
|
||||
@@ -285,6 +285,69 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodep->name() == "constraint_mode") {
|
||||
bool valid = true;
|
||||
if (nodep->pinsp() && !VN_IS(nodep->backp(), StmtExpr)) {
|
||||
nodep->v3error(
|
||||
"'constraint_mode()' with arguments cannot be called as a function");
|
||||
valid = false;
|
||||
} else if (!nodep->pinsp() && VN_IS(nodep->backp(), StmtExpr)) {
|
||||
nodep->v3warn(
|
||||
IGNOREDRETURN,
|
||||
"Ignoring return value of non-void function (IEEE 1800-2023 13.4.1)");
|
||||
valid = false;
|
||||
}
|
||||
AstConstraint* constrp = nullptr;
|
||||
AstClass* classp = m_classp;
|
||||
if (const AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall)) {
|
||||
if (const AstConstraintRef* const constrRefp
|
||||
= VN_CAST(methodCallp->fromp(), ConstraintRef)) {
|
||||
constrp = constrRefp->constrp();
|
||||
if (constrRefp->fromp()) classp = VN_AS(constrRefp->classOrPackagep(), Class);
|
||||
if (constrp->isStatic()) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: 'constraint_mode()' on static constraint");
|
||||
valid = false;
|
||||
}
|
||||
} else if (AstClassRefDType* classRefDtp
|
||||
= VN_CAST(methodCallp->fromp()->dtypep()->skipRefp(), ClassRefDType)) {
|
||||
classp = classRefDtp->classp();
|
||||
} else {
|
||||
nodep->v3error("Cannot call 'constraint_mode()' on a non-class variable");
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
if (!nodep->pinsp() && !constrp) {
|
||||
nodep->v3error("Cannot call 'constraint_mode()' as a function on a variable");
|
||||
valid = false;
|
||||
}
|
||||
if (valid) {
|
||||
RandomizeMode constraintMode = {};
|
||||
constraintMode.usesMode = true;
|
||||
if (constrp) {
|
||||
constrp->user1(constraintMode.asInt);
|
||||
} else {
|
||||
classp->foreachMember([=](AstClass*, AstConstraint* constrp) {
|
||||
if (constrp->isStatic()) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: 'constraint_mode()' on static constraint: "
|
||||
<< constrp->prettyNameQ());
|
||||
}
|
||||
constrp->user1(constraintMode.asInt);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!nodep->pinsp() && !VN_IS(nodep->backp(), StmtExpr)) {
|
||||
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else {
|
||||
m_stmtp->unlinkFrBack();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodep->name() != "randomize") return;
|
||||
AstClass* classp = m_classp;
|
||||
if (const AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall)) {
|
||||
@@ -324,8 +387,8 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
||||
if (randVarp == fromVarp) break;
|
||||
AstNode* backp = randVarp;
|
||||
while (backp && !VN_IS(backp, Class)) backp = backp->backp();
|
||||
VarRandMode randMode = {};
|
||||
randMode.usesRandMode = true;
|
||||
RandomizeMode randMode = {};
|
||||
randMode.usesMode = true;
|
||||
randVarp->user1(randMode.asInt);
|
||||
VN_AS(backp, Class)->user1(IS_RANDOMIZED_INLINE);
|
||||
}
|
||||
@@ -493,15 +556,15 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
AstVar* const varp = nodep->varp();
|
||||
AstNodeModule* const classOrPackagep = nodep->classOrPackagep();
|
||||
const VarRandMode randMode = {.asInt = varp->user1()};
|
||||
if (!randMode.usesRandMode && editFormat(nodep)) return;
|
||||
const RandomizeMode randMode = {.asInt = varp->user1()};
|
||||
if (!randMode.usesMode && editFormat(nodep)) return;
|
||||
|
||||
// In SMT just variable name, but we also ensure write_var for the variable
|
||||
const std::string smtName = nodep->name(); // Can be anything unique
|
||||
VNRelinker relinker;
|
||||
nodep->unlinkFrBack(&relinker);
|
||||
AstNodeExpr* exprp = new AstSFormatF{nodep->fileline(), smtName, false, nullptr};
|
||||
if (randMode.usesRandMode) {
|
||||
if (randMode.usesMode) {
|
||||
AstNodeExpr* constFormatp = getConstFormat(nodep);
|
||||
AstCMethodHard* const atp = new AstCMethodHard{
|
||||
nodep->fileline(),
|
||||
@@ -533,7 +596,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
= new AstCExpr{varp->fileline(), "\"" + smtName + "\"", varp->width()};
|
||||
varnamep->dtypep(varp->dtypep());
|
||||
methodp->addPinsp(varnamep);
|
||||
if (randMode.usesRandMode) {
|
||||
if (randMode.usesMode) {
|
||||
methodp->addPinsp(
|
||||
new AstConst{varp->fileline(), AstConst::Unsized64{}, randMode.index});
|
||||
}
|
||||
@@ -1012,10 +1075,10 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
// AstVar::user2p() -> AstClass*. Pointer to containing class
|
||||
// AstEnumDType::user2() -> AstVar*. Pointer to table with enum values
|
||||
// AstConstraint::user2p() -> AstTask*. Pointer to constraint setup procedure
|
||||
// AstClass::user2p() -> AstTask*. Pointer to full constraint setup procedure
|
||||
// AstClass::user2p() -> AstVar*. Rand mode state variable
|
||||
// AstVar::user3() -> bool. Handled in constraints
|
||||
// AstClass::user3p() -> AstVar*. Constrained randomizer variable
|
||||
// AstClass::user4p() -> AstVar*. Rand mode state variable
|
||||
// AstClass::user4p() -> AstVar*. Constraint mode state variable
|
||||
// VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor)
|
||||
// VNUser2InUse m_inuser2; (Allocated for use in RandomizeMarkVisitor)
|
||||
const VNUser3InUse m_inuser3;
|
||||
@@ -1023,8 +1086,8 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
|
||||
// STATE
|
||||
V3UniqueNames m_inlineUniqueNames; // For generating unique function names
|
||||
V3UniqueNames m_randModeUniqueNames{"__Vrandmode"}; // For generating unique rand mode state
|
||||
// var names
|
||||
V3UniqueNames m_modeUniqueNames{"__Vmode"}; // For generating unique rand/constraint
|
||||
// mode state var names
|
||||
VMemberMap m_memberMap; // Member names cached for fast lookup
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
@@ -1053,20 +1116,49 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
return nullptr;
|
||||
}
|
||||
AstTask* getCreateConstraintSetupFunc(AstClass* classp) {
|
||||
if (classp->user2p()) return VN_AS(classp->user2p(), Task);
|
||||
AstTask* const setupAllTaskp
|
||||
= new AstTask{classp->fileline(), "__Vsetup_constraints", nullptr};
|
||||
static const char* const name = "__Vsetup_constraints";
|
||||
AstTask* setupAllTaskp = VN_AS(m_memberMap.findMember(classp, name), Task);
|
||||
if (setupAllTaskp) return setupAllTaskp;
|
||||
setupAllTaskp = new AstTask{classp->fileline(), "__Vsetup_constraints", nullptr};
|
||||
setupAllTaskp->classMethod(true);
|
||||
setupAllTaskp->isVirtual(true);
|
||||
classp->addMembersp(setupAllTaskp);
|
||||
classp->user2p(setupAllTaskp);
|
||||
m_memberMap.insert(classp, setupAllTaskp);
|
||||
return setupAllTaskp;
|
||||
}
|
||||
AstVar* getCreateRandModeVar(AstClass* const classp) {
|
||||
if (classp->user4p()) return VN_AS(classp->user4p(), Var);
|
||||
if (classp->user2p()) return VN_AS(classp->user2p(), Var);
|
||||
if (AstClassExtends* const extendsp = classp->extendsp()) {
|
||||
return getCreateRandModeVar(extendsp->classp());
|
||||
}
|
||||
AstVar* const randModeVarp = createModeVar(classp, "__Vrandmode");
|
||||
classp->user2p(randModeVarp);
|
||||
return randModeVarp;
|
||||
}
|
||||
static AstVar* getRandModeVar(AstClass* const classp) {
|
||||
if (classp->user2p()) return VN_AS(classp->user2p(), Var);
|
||||
if (AstClassExtends* const extendsp = classp->extendsp()) {
|
||||
return getRandModeVar(extendsp->classp());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
AstVar* getCreateConstraintModeVar(AstClass* const classp) {
|
||||
if (classp->user4p()) return VN_AS(classp->user4p(), Var);
|
||||
if (AstClassExtends* const extendsp = classp->extendsp()) {
|
||||
return getCreateConstraintModeVar(extendsp->classp());
|
||||
}
|
||||
AstVar* const constraintModeVarp = createModeVar(classp, "__Vconstraintmode");
|
||||
classp->user4p(constraintModeVarp);
|
||||
return constraintModeVarp;
|
||||
}
|
||||
static AstVar* getConstraintModeVar(AstClass* const classp) {
|
||||
if (classp->user4p()) return VN_AS(classp->user4p(), Var);
|
||||
if (AstClassExtends* const extendsp = classp->extendsp()) {
|
||||
return getConstraintModeVar(extendsp->classp());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
AstVar* createModeVar(AstClass* const classp, const char* const name) {
|
||||
FileLine* const fl = classp->fileline();
|
||||
if (!m_dynarrayDtp) {
|
||||
m_dynarrayDtp = new AstDynArrayDType{
|
||||
@@ -1074,23 +1166,13 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
m_dynarrayDtp->dtypep(m_dynarrayDtp);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(m_dynarrayDtp);
|
||||
}
|
||||
AstVar* const randModeVarp
|
||||
= new AstVar{fl, VVarType::MODULETEMP, "__Vrandmode", m_dynarrayDtp};
|
||||
|
||||
randModeVarp->user2p(classp);
|
||||
classp->addStmtsp(randModeVarp);
|
||||
classp->user4p(randModeVarp);
|
||||
return randModeVarp;
|
||||
AstVar* const modeVarp = new AstVar{fl, VVarType::MODULETEMP, name, m_dynarrayDtp};
|
||||
modeVarp->user2p(classp);
|
||||
classp->addStmtsp(modeVarp);
|
||||
return modeVarp;
|
||||
}
|
||||
AstVar* getRandModeVar(AstClass* const classp) {
|
||||
if (classp->user4p()) return VN_AS(classp->user4p(), Var);
|
||||
if (AstClassExtends* const extendsp = classp->extendsp()) {
|
||||
return getRandModeVar(extendsp->classp());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void addSetRandMode(AstNodeFTask* const ftaskp, AstVar* const genp,
|
||||
AstVar* const randModeVarp) {
|
||||
static void addSetRandMode(AstNodeFTask* const ftaskp, AstVar* const genp,
|
||||
AstVar* const randModeVarp) {
|
||||
FileLine* const fl = ftaskp->fileline();
|
||||
AstCMethodHard* const setRandModep = new AstCMethodHard{
|
||||
fl, new AstVarRef{fl, VN_AS(genp->user2p(), NodeModule), genp, VAccess::WRITE},
|
||||
@@ -1101,46 +1183,62 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
ftaskp->addStmtsp(setRandModep->makeStmt());
|
||||
}
|
||||
void createRandomizeClassVars(AstNetlist* const netlistp) {
|
||||
netlistp->foreach([&](AstClass* const classp) {
|
||||
if (classp->existsMember(
|
||||
[&](const AstClass*, const AstConstraint*) { return true; })) {
|
||||
createRandomGenerator(classp);
|
||||
}
|
||||
netlistp->foreach([this](AstClass* const classp) {
|
||||
bool hasConstraints = false;
|
||||
uint32_t randModeCount = 0;
|
||||
classp->foreachMember([&](AstClass*, AstVar* memberVarp) {
|
||||
VarRandMode randMode = {.asInt = memberVarp->user1()};
|
||||
if (!randMode.usesRandMode) return;
|
||||
uint32_t constraintModeCount = 0;
|
||||
classp->foreachMember([&](AstClass*, AstNode* memberp) {
|
||||
// SystemVerilog only allows single inheritance, so we don't need to worry about
|
||||
// index overlap. If the index > 0, it's already been set.
|
||||
if (randMode.index == 0) {
|
||||
randMode.index = randModeCount++;
|
||||
memberVarp->user1(randMode.asInt);
|
||||
} else {
|
||||
randModeCount = randMode.index + 1;
|
||||
if (VN_IS(memberp, Constraint)) {
|
||||
hasConstraints = true;
|
||||
RandomizeMode constraintMode = {.asInt = memberp->user1()};
|
||||
if (!constraintMode.usesMode) return;
|
||||
if (constraintMode.index == 0) {
|
||||
constraintMode.index = constraintModeCount++;
|
||||
memberp->user1(constraintMode.asInt);
|
||||
} else {
|
||||
constraintModeCount = constraintMode.index + 1;
|
||||
}
|
||||
} else if (VN_IS(memberp, Var)) {
|
||||
RandomizeMode randMode = {.asInt = memberp->user1()};
|
||||
if (!randMode.usesMode) return;
|
||||
if (randMode.index == 0) {
|
||||
randMode.index = randModeCount++;
|
||||
memberp->user1(randMode.asInt);
|
||||
} else {
|
||||
randModeCount = randMode.index + 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (hasConstraints) createRandomGenerator(classp);
|
||||
if (randModeCount > 0) {
|
||||
AstVar* const randModeVarp = getCreateRandModeVar(classp);
|
||||
AstNodeModule* const randModeModp = VN_AS(randModeVarp->user2p(), NodeModule);
|
||||
FileLine* fl = randModeVarp->fileline();
|
||||
AstCMethodHard* const dynarrayNewp = new AstCMethodHard{
|
||||
fl, new AstVarRef{fl, randModeModp, randModeVarp, VAccess::WRITE},
|
||||
"renew_copy", new AstConst{fl, randModeCount}};
|
||||
dynarrayNewp->addPinsp(
|
||||
new AstVarRef{fl, randModeModp, randModeVarp, VAccess::READ});
|
||||
dynarrayNewp->dtypeSetVoid();
|
||||
AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
|
||||
UASSERT_OBJ(newp, classp, "No new() in class");
|
||||
fl = classp->fileline();
|
||||
newp->addStmtsp(dynarrayNewp->makeStmt());
|
||||
newp->addStmtsp(makeRandModeInitLoop(
|
||||
fl, new AstVarRef{fl, randModeModp, randModeVarp, VAccess::WRITE},
|
||||
new AstConst{fl, 1}, true));
|
||||
makeModeInit(randModeVarp, classp, randModeCount);
|
||||
}
|
||||
if (constraintModeCount > 0) {
|
||||
AstVar* const constraintModeVarp = getCreateConstraintModeVar(classp);
|
||||
makeModeInit(constraintModeVarp, classp, constraintModeCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
static AstNode* makeRandModeInitLoop(FileLine* const fl, AstNodeExpr* const lhsp,
|
||||
AstNodeExpr* const rhsp, bool inTask) {
|
||||
void makeModeInit(AstVar* modeVarp, AstClass* classp, uint32_t modeCount) {
|
||||
AstNodeModule* const modeVarModp = VN_AS(modeVarp->user2p(), NodeModule);
|
||||
FileLine* fl = modeVarp->fileline();
|
||||
AstCMethodHard* const dynarrayNewp
|
||||
= new AstCMethodHard{fl, new AstVarRef{fl, modeVarModp, modeVarp, VAccess::WRITE},
|
||||
"renew_copy", new AstConst{fl, modeCount}};
|
||||
dynarrayNewp->addPinsp(new AstVarRef{fl, modeVarModp, modeVarp, VAccess::READ});
|
||||
dynarrayNewp->dtypeSetVoid();
|
||||
AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
|
||||
UASSERT_OBJ(newp, classp, "No new() in class");
|
||||
newp->addStmtsp(dynarrayNewp->makeStmt());
|
||||
newp->addStmtsp(makeModeSetLoop(fl,
|
||||
new AstVarRef{fl, modeVarModp, modeVarp, VAccess::WRITE},
|
||||
new AstConst{fl, 1}, true));
|
||||
}
|
||||
static AstNode* makeModeSetLoop(FileLine* const fl, AstNodeExpr* const lhsp,
|
||||
AstNodeExpr* const rhsp, bool inTask) {
|
||||
AstVar* const iterVarp = new AstVar{fl, VVarType::BLOCKTEMP, "i", lhsp->findUInt32DType()};
|
||||
iterVarp->funcLocal(inTask);
|
||||
iterVarp->lifetime(VLifetime::AUTOMATIC);
|
||||
@@ -1160,16 +1258,20 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
new AstVarRef{fl, iterVarp, VAccess::READ}}}});
|
||||
return new AstBegin{fl, "", stmtsp, false, true};
|
||||
}
|
||||
AstNodeStmt* wrapIfRandMode(AstVar* const varp, AstNodeStmt* stmtp) {
|
||||
static AstNodeStmt* wrapIfRandMode(AstClass* classp, AstVar* const varp, AstNodeStmt* stmtp) {
|
||||
return VN_AS(wrapIfMode({.asInt = varp->user1()}, getRandModeVar(classp), stmtp),
|
||||
NodeStmt);
|
||||
}
|
||||
static AstNode* wrapIfConstraintMode(AstClass* classp, AstConstraint* const constrp,
|
||||
AstNode* stmtp) {
|
||||
return wrapIfMode({.asInt = constrp->user1()}, getConstraintModeVar(classp), stmtp);
|
||||
}
|
||||
static AstNode* wrapIfMode(const RandomizeMode mode, AstVar* modeVarp, AstNode* stmtp) {
|
||||
FileLine* const fl = stmtp->fileline();
|
||||
const VarRandMode randMode = {.asInt = varp->user1()};
|
||||
if (randMode.usesRandMode) {
|
||||
AstVar* randModeVarp = getRandModeVar(VN_AS(m_modp, Class));
|
||||
AstCMethodHard* const atp
|
||||
= new AstCMethodHard{fl,
|
||||
new AstVarRef{fl, VN_AS(randModeVarp->user2p(), Class),
|
||||
randModeVarp, VAccess::READ},
|
||||
"at", new AstConst{fl, randMode.index}};
|
||||
if (mode.usesMode) {
|
||||
AstCMethodHard* const atp = new AstCMethodHard{
|
||||
fl, new AstVarRef{fl, VN_AS(modeVarp->user2p(), Class), modeVarp, VAccess::READ},
|
||||
"at", new AstConst{fl, mode.index}};
|
||||
atp->dtypeSetUInt32();
|
||||
return new AstIf{fl, atp, stmtp};
|
||||
}
|
||||
@@ -1299,7 +1401,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
if (varrefp->access().isWriteOrRW()) varp = varrefp->varp();
|
||||
return varp != nullptr;
|
||||
});
|
||||
return wrapIfRandMode(varp, assignp);
|
||||
return wrapIfRandMode(VN_AS(m_modp, Class), varp, assignp);
|
||||
}
|
||||
}
|
||||
AstNodeExpr* newRandValue(FileLine* const fl, AstVar* const randcVarp,
|
||||
@@ -1365,9 +1467,8 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
AstVar* makeTmpRandModeVar(AstNodeExpr* siblingExprp, AstVar* randModeVarp,
|
||||
AstNode*& storeStmtspr, AstNodeStmt*& restoreStmtspr) {
|
||||
FileLine* const fl = randModeVarp->fileline();
|
||||
AstVar* const randModeTmpVarp
|
||||
= new AstVar{fl, VVarType::BLOCKTEMP, m_randModeUniqueNames.get(randModeVarp),
|
||||
randModeVarp->dtypep()};
|
||||
AstVar* const randModeTmpVarp = new AstVar{
|
||||
fl, VVarType::BLOCKTEMP, m_modeUniqueNames.get(randModeVarp), randModeVarp->dtypep()};
|
||||
randModeTmpVarp->funcLocal(m_ftaskp);
|
||||
randModeTmpVarp->lifetime(VLifetime::AUTOMATIC);
|
||||
storeStmtspr = AstNode::addNext(
|
||||
@@ -1376,8 +1477,8 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
makeSiblingRefp(siblingExprp, randModeVarp, VAccess::READ)});
|
||||
storeStmtspr = AstNode::addNext(
|
||||
storeStmtspr,
|
||||
makeRandModeInitLoop(fl, makeSiblingRefp(siblingExprp, randModeVarp, VAccess::WRITE),
|
||||
new AstConst{fl, 0}, m_ftaskp));
|
||||
makeModeSetLoop(fl, makeSiblingRefp(siblingExprp, randModeVarp, VAccess::WRITE),
|
||||
new AstConst{fl, 0}, m_ftaskp));
|
||||
restoreStmtspr = AstNode::addNext(
|
||||
restoreStmtspr,
|
||||
new AstAssign{fl, makeSiblingRefp(siblingExprp, randModeVarp, VAccess::WRITE),
|
||||
@@ -1438,8 +1539,9 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
UASSERT_OBJ(newp, nodep, "No new() in class");
|
||||
nodep->foreachMember([&](AstClass* classp, AstVar* memberVarp) {
|
||||
if (!memberVarp->rand().isRandomizable()) return;
|
||||
const VarRandMode randMode = {.asInt = memberVarp->user1()};
|
||||
if (randMode.usesRandMode && !memberVarp->isRand()) { // Not randomizable by default
|
||||
const RandomizeMode randMode = {.asInt = memberVarp->user1()};
|
||||
if (randMode.usesMode
|
||||
&& !memberVarp->rand().isRand()) { // Not randomizable by default
|
||||
AstCMethodHard* atp = new AstCMethodHard{
|
||||
nodep->fileline(),
|
||||
new AstVarRef{fl, VN_AS(randModeVarp->user2p(), NodeModule), randModeVarp,
|
||||
@@ -1477,7 +1579,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
new AstConst{fl, AstConst::Null{}}},
|
||||
new AstAssign{fl, basicFvarRefp->cloneTree(false),
|
||||
new AstAnd{fl, basicFvarRefReadp, callp}}};
|
||||
basicRandomizep->addStmtsp(wrapIfRandMode(memberVarp, assignIfNotNullp));
|
||||
basicRandomizep->addStmtsp(wrapIfRandMode(nodep, memberVarp, assignIfNotNullp));
|
||||
} else {
|
||||
memberVarp->v3warn(E_UNSUPPORTED, "Unsupported: random member variable with type "
|
||||
<< memberVarp->dtypep()->prettyDTypeNameQ());
|
||||
@@ -1485,6 +1587,54 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
});
|
||||
}
|
||||
|
||||
// Creates a lvalue reference to the randomize mode var. Called by visit(AstNodeFTaskRef*)
|
||||
AstNodeExpr* makeModeAssignLhs(FileLine* const fl, AstClass* const classp,
|
||||
AstNodeExpr* const fromp, AstVar* const modeVarp) {
|
||||
if (classp == m_modp) {
|
||||
// Called on 'this' or a member of 'this'
|
||||
return new AstVarRef{fl, VN_AS(modeVarp->user2p(), NodeModule), modeVarp,
|
||||
VAccess::WRITE};
|
||||
} else {
|
||||
AstMemberSel* const memberselp = new AstMemberSel{fl, fromp->unlinkFrBack(), modeVarp};
|
||||
memberselp->foreach([](AstVarRef* varrefp) { varrefp->access(VAccess::WRITE); });
|
||||
return memberselp;
|
||||
}
|
||||
}
|
||||
// Replace the node with an assignment to the mode variable. Called by visit(AstNodeFTaskRef*)
|
||||
void replaceWithModeAssign(AstNodeFTaskRef* const ftaskRefp, AstNode* const receiverp,
|
||||
AstNodeExpr* const lhsp) {
|
||||
FileLine* const fl = ftaskRefp->fileline();
|
||||
if (ftaskRefp->pinsp()) {
|
||||
UASSERT_OBJ(VN_IS(ftaskRefp->backp(), StmtExpr), ftaskRefp, "Should be a statement");
|
||||
AstNodeExpr* const rhsp = VN_AS(ftaskRefp->pinsp(), Arg)->exprp()->unlinkFrBack();
|
||||
if (receiverp) {
|
||||
// Called on a rand member variable/constraint. Set the variable/constraint's
|
||||
// mode
|
||||
const RandomizeMode mode = {.asInt = receiverp->user1()};
|
||||
UASSERT_OBJ(mode.usesMode, ftaskRefp, "Failed to set usesMode");
|
||||
AstCMethodHard* const atp
|
||||
= new AstCMethodHard{fl, lhsp, "at", new AstConst{fl, mode.index}};
|
||||
atp->dtypeSetUInt32();
|
||||
m_stmtp->replaceWith(new AstAssign{fl, atp, rhsp});
|
||||
} else {
|
||||
// For rand_mode: Called on 'this' or a non-rand class instance.
|
||||
// For constraint_mode: Called on a class instance.
|
||||
// Set the rand mode of all members
|
||||
m_stmtp->replaceWith(makeModeSetLoop(fl, lhsp, rhsp, m_ftaskp));
|
||||
}
|
||||
pushDeletep(m_stmtp);
|
||||
} else {
|
||||
UASSERT_OBJ(receiverp, ftaskRefp, "Should have receiver");
|
||||
const RandomizeMode mode = {.asInt = receiverp->user1()};
|
||||
UASSERT_OBJ(mode.usesMode, ftaskRefp, "Failed to set usesMode");
|
||||
AstCMethodHard* const atp
|
||||
= new AstCMethodHard{fl, lhsp, "at", new AstConst{fl, mode.index}};
|
||||
atp->dtypeSetUInt32();
|
||||
ftaskRefp->replaceWith(atp);
|
||||
VL_DO_DANGLING(pushDeletep(ftaskRefp), ftaskRefp);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle inline random variable control. After this, the randomize() call has no args
|
||||
void handleRandomizeArgs(AstNodeFTaskRef* const nodep) {
|
||||
if (!nodep->pinsp()) return;
|
||||
@@ -1545,7 +1695,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
savedRandModeVarps.insert(randModeVarp);
|
||||
tmpVarps = AstNode::addNext(tmpVarps, randModeTmpVarp);
|
||||
}
|
||||
const VarRandMode randMode = {.asInt = randVarp->user1()};
|
||||
const RandomizeMode randMode = {.asInt = randVarp->user1()};
|
||||
AstCMethodHard* atp
|
||||
= new AstCMethodHard{fl, makeSiblingRefp(exprp, randModeVarp, VAccess::WRITE),
|
||||
"at", new AstConst{fl, randMode.index}};
|
||||
@@ -1616,7 +1766,10 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
|
||||
|
||||
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp, randModeVarp};
|
||||
if (constrp->itemsp()) taskp->addStmtsp(constrp->itemsp()->unlinkFrBackWithNext());
|
||||
if (constrp->itemsp()) {
|
||||
taskp->addStmtsp(wrapIfConstraintMode(
|
||||
nodep, constrp, constrp->itemsp()->unlinkFrBackWithNext()));
|
||||
}
|
||||
});
|
||||
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
|
||||
AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep);
|
||||
@@ -1727,49 +1880,36 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
const RandModeTarget randModeTarget = RandModeTarget::get(fromp, m_modp);
|
||||
UASSERT_OBJ(randModeTarget.classp, nodep,
|
||||
"Should have checked in RandomizeMarkVisitor");
|
||||
AstVar* const receiverp = randModeTarget.receiverp;
|
||||
AstVar* const randModeVarp = getRandModeVar(randModeTarget.classp);
|
||||
AstNodeExpr* lhsp = nullptr;
|
||||
if (randModeTarget.classp == m_modp) {
|
||||
// Called on 'this' or a member of 'this'
|
||||
lhsp = new AstVarRef{nodep->fileline(), VN_AS(randModeVarp->user2p(), NodeModule),
|
||||
randModeVarp, VAccess::WRITE};
|
||||
} else {
|
||||
AstMemberSel* const memberselp = new AstMemberSel{
|
||||
nodep->fileline(), randModeTarget.fromp->unlinkFrBack(), randModeVarp};
|
||||
memberselp->foreach([](AstVarRef* varrefp) { varrefp->access(VAccess::WRITE); });
|
||||
lhsp = memberselp;
|
||||
}
|
||||
if (nodep->pinsp()) { // Set rand mode
|
||||
UASSERT_OBJ(VN_IS(nodep->backp(), StmtExpr), nodep, "Should be a statement");
|
||||
AstNodeExpr* const rhsp = VN_AS(nodep->pinsp(), Arg)->exprp()->unlinkFrBack();
|
||||
if (randModeTarget.receiverp && randModeTarget.receiverp->isRand()) {
|
||||
// Called on a rand member variable. Set the variable's rand mode
|
||||
const VarRandMode randMode = {.asInt = randModeTarget.receiverp->user1()};
|
||||
UASSERT_OBJ(randMode.usesRandMode, nodep, "Failed to set usesRandMode");
|
||||
AstCMethodHard* const atp
|
||||
= new AstCMethodHard{nodep->fileline(), lhsp, "at",
|
||||
new AstConst{nodep->fileline(), randMode.index}};
|
||||
atp->dtypeSetUInt32();
|
||||
m_stmtp->replaceWith(new AstAssign{nodep->fileline(), atp, rhsp});
|
||||
} else {
|
||||
// Called on 'this' or a non-rand class instance. Set the rand mode of all
|
||||
// members
|
||||
m_stmtp->replaceWith(
|
||||
makeRandModeInitLoop(nodep->fileline(), lhsp, rhsp, m_ftaskp));
|
||||
AstNodeExpr* const lhsp = makeModeAssignLhs(nodep->fileline(), randModeTarget.classp,
|
||||
randModeTarget.fromp, randModeVarp);
|
||||
replaceWithModeAssign(nodep,
|
||||
// If the receiver is not rand, set the rand_mode for all members
|
||||
receiverp && receiverp->rand().isRand() ? receiverp : nullptr,
|
||||
lhsp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodep->name() == "constraint_mode") {
|
||||
AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall);
|
||||
AstNodeExpr* fromp = methodCallp ? methodCallp->fromp() : nullptr;
|
||||
AstConstraint* constrp = nullptr;
|
||||
AstClass* classp = VN_CAST(m_modp, Class);
|
||||
if (AstConstraintRef* const constrRefp = VN_CAST(fromp, ConstraintRef)) {
|
||||
constrp = constrRefp->constrp();
|
||||
if (constrRefp->fromp()) {
|
||||
fromp = constrRefp->fromp();
|
||||
classp = VN_AS(fromp->dtypep()->skipRefp(), ClassRefDType)->classp();
|
||||
}
|
||||
pushDeletep(m_stmtp);
|
||||
} else { // Retrieve rand mode
|
||||
UASSERT_OBJ(randModeTarget.receiverp, nodep, "Should have receiver");
|
||||
UASSERT_OBJ(randModeTarget.receiverp->isRand(), nodep, "Should be rand");
|
||||
const VarRandMode randMode = {.asInt = randModeTarget.receiverp->user1()};
|
||||
UASSERT_OBJ(randMode.usesRandMode, nodep, "Failed to set usesRandMode");
|
||||
AstCMethodHard* const atp
|
||||
= new AstCMethodHard{nodep->fileline(), lhsp, "at",
|
||||
new AstConst{nodep->fileline(), randMode.index}};
|
||||
atp->dtypeSetUInt32();
|
||||
nodep->replaceWith(atp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (fromp) {
|
||||
classp = VN_AS(fromp->dtypep()->skipRefp(), ClassRefDType)->classp();
|
||||
}
|
||||
UASSERT_OBJ(classp, nodep, "Failed to find class");
|
||||
AstVar* const constraintModeVarp = getConstraintModeVar(classp);
|
||||
AstNodeExpr* const lhsp
|
||||
= makeModeAssignLhs(nodep->fileline(), classp, fromp, constraintModeVarp);
|
||||
replaceWithModeAssign(nodep, constrp, lhsp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user