Support randc (#4349).

This commit is contained in:
Wilson Snyder
2023-09-18 21:17:21 -04:00
parent 47b3f464a9
commit 24ff3155ae
18 changed files with 220 additions and 61 deletions
+62 -8
View File
@@ -144,6 +144,7 @@ private:
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
int m_randCaseNum = 0; // Randcase number within a module for var naming
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
// METHODS
AstVar* enumValueTabp(AstEnumDType* nodep) {
@@ -172,8 +173,49 @@ private:
nodep->user2p(varp);
return varp;
}
AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeVarRef* varrefp, int offset = 0,
AstMemberDType* memberp = nullptr) {
AstCDType* findVlRandCDType(FileLine* fl, uint64_t items) {
// For 8 items we need to have a 9 item LFSR so items is max count
const std::string type = AstCDType::typeToHold(items);
const std::string name = "VlRandC<" + type + ", " + cvtToStr(items) + "ULL>";
// Create or reuse (to avoid duplicates) randomization object dtype
auto it = m_randcDtypes.find(name);
if (it != m_randcDtypes.end()) return it->second;
AstCDType* newp = new AstCDType{fl, name};
v3Global.rootp()->typeTablep()->addTypesp(newp);
m_randcDtypes.emplace(std::make_pair(name, newp));
return newp;
}
AstVar* newRandcVarsp(AstVar* varp) {
// If a randc, make a VlRandC object to hold the state
if (!varp->isRandC()) return nullptr;
uint64_t items = 0;
if (AstEnumDType* const enumDtp = VN_CAST(varp->dtypep()->skipRefToEnump(), EnumDType)) {
items = static_cast<uint64_t>(enumDtp->itemCount());
} else {
AstBasicDType* const basicp = varp->dtypep()->skipRefp()->basicp();
UASSERT_OBJ(basicp, varp, "Unexpected randc variable dtype");
if (basicp->width() > 32) {
varp->v3error("Maxiumum implemented width for randc is 32 bits, "
<< varp->prettyNameQ() << " is " << basicp->width() << " bits");
varp->isRandC(false);
varp->isRand(true);
return nullptr;
}
items = 1ULL << basicp->width();
}
AstCDType* newdtp = findVlRandCDType(varp->fileline(), items);
AstVar* newp
= new AstVar{varp->fileline(), VVarType::MEMBER, varp->name() + "__Vrandc", newdtp};
newp->isInternal(true);
varp->addNextHere(newp);
UINFO(9, "created " << varp << endl);
return newp;
}
AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeVarRef* varrefp, AstVar* randcVarp,
int offset = 0, AstMemberDType* memberp = nullptr) {
if (const auto* const structDtp
= VN_CAST(memberp ? memberp->subDTypep()->skipRefp() : varrefp->dtypep()->skipRefp(),
StructDType)) {
@@ -182,7 +224,7 @@ private:
for (AstMemberDType* smemberp = structDtp->membersp(); smemberp;
smemberp = VN_AS(smemberp->nextp(), MemberDType)) {
AstNodeStmt* const randp = newRandStmtsp(
fl, stmtsp ? varrefp->cloneTree(false) : varrefp, offset, smemberp);
fl, stmtsp ? varrefp->cloneTree(false) : varrefp, nullptr, offset, smemberp);
if (stmtsp) {
stmtsp->addNext(randp);
} else {
@@ -198,15 +240,15 @@ private:
AstVarRef* const tabRefp
= new AstVarRef{fl, enumValueTabp(enumDtp), VAccess::READ};
tabRefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
AstRandRNG* const randp
= new AstRandRNG{fl, varrefp->findBasicDType(VBasicDTypeKwd::UINT32)};
AstNodeExpr* const randp
= newRandValue(fl, randcVarp, varrefp->findBasicDType(VBasicDTypeKwd::UINT32));
AstNodeExpr* const moddivp = new AstModDiv{
fl, randp, new AstConst{fl, static_cast<uint32_t>(enumDtp->itemCount())}};
moddivp->dtypep(enumDtp);
valp = new AstArraySel{fl, tabRefp, moddivp};
} else {
valp = new AstRandRNG{fl,
(memberp ? memberp->dtypep() : varrefp->varp()->dtypep())};
valp = newRandValue(fl, randcVarp,
(memberp ? memberp->dtypep() : varrefp->varp()->dtypep()));
}
return new AstAssign{fl,
new AstSel{fl, varrefp, offset + (memberp ? memberp->lsb() : 0),
@@ -214,6 +256,17 @@ private:
valp};
}
}
AstNodeExpr* newRandValue(FileLine* fl, AstVar* randcVarp, AstNodeDType* dtypep) {
if (randcVarp) {
AstNode* argsp = new AstVarRef{fl, randcVarp, VAccess::READWRITE};
argsp->addNext(new AstText{fl, ".randomize(__Vm_rng)"});
AstCExpr* newp = new AstCExpr{fl, argsp};
newp->dtypep(dtypep);
return newp;
} else {
return new AstRandRNG{fl, dtypep};
}
}
void addPrePostCall(AstClass* classp, AstFunc* funcp, const string& name) {
if (AstTask* userFuncp = VN_CAST(m_memberMap.findMember(classp, name), Task)) {
AstTaskRef* const callp
@@ -271,8 +324,9 @@ private:
if (!memberVarp || !memberVarp->isRand()) continue;
const AstNodeDType* const dtypep = memberp->dtypep()->skipRefp();
if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) {
AstVar* const randcVarp = newRandcVarsp(memberVarp);
AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE};
AstNodeStmt* const stmtp = newRandStmtsp(fl, refp);
AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp);
funcp->addStmtsp(stmtp);
} else if (const auto* const classRefp = VN_CAST(dtypep, ClassRefDType)) {
if (classRefp->classp() == nodep) {