Support constraint_mode (#5338)

This commit is contained in:
Krzysztof Bieganski
2024-08-21 06:16:44 -04:00
committed by GitHub
parent 13e0fc7c27
commit 930f35acc9
16 changed files with 495 additions and 253 deletions
+271 -131
View File
@@ -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;
}