virtual void visit(AstUdpTable* nodep, AstNUser*) { UINFO(5,"UDPTABLE "<<nodep<<endl); if (!v3Global.opt.bboxUnsup()) { // We don't warn until V3Inst, so that UDPs that are in libraries and // never used won't result in any warnings. } else { // Massive hack, just tie off all outputs so our analysis can proceed AstVar* varoutp = NULL; for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) { if (AstVar* varp = stmtp->castVar()) { if (varp->isInput()) { } else if (varp->isOutput()) { if (varoutp) { varp->v3error("Multiple outputs not allowed in udp modules"); } varoutp = varp; // Tie off m_modp->addStmtp(new AstAssignW(varp->fileline(), new AstVarRef(varp->fileline(), varp, true), new AstConst(varp->fileline(), AstConst::LogicFalse()))); } else { varp->v3error("Only inputs and outputs are allowed in udp modules"); } } } nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; } }
void replaceFunc (AstCFunc* oldfuncp, AstCFunc* newfuncp) { if (oldfuncp==newfuncp) return; if (newfuncp) { UINFO(4, " Replace "<<oldfuncp<<" -WITH-> "<<newfuncp<<endl); } else UINFO(4, " Remove "<<oldfuncp<<endl); pair <CallMmap::iterator,CallMmap::iterator> eqrange = m_callMmap.equal_range(oldfuncp); for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) { CallMmap::iterator eqit = nextit++; AstCCall* callp = eqit->second; if (!callp->user3()) { // !already done UINFO(4, " Called "<<callp<<endl); if (callp->funcp() != oldfuncp) callp->v3fatalSrc("Call list broken, points to call w/different func"); if (newfuncp) { AstCCall* newp = new AstCCall(callp, newfuncp); // Special new AstCCall form above transfers children of callp to newfuncp callp->replaceWith(newp); addCall(newp); // Fix the table } else { // Just deleting empty function callp->unlinkFrBack(); } callp->user3(true); // Dead now pushDeletep(callp); VL_DANGLING(callp); m_callMmap.erase(eqit); // Fix the table } } }
bool canSimulate(AstNode *nodep) { SimulateVisitor simvis; AstNode* clonep = nodep->cloneTree(true); simvis.mainCheckTree(clonep); pushDeletep(clonep); clonep = NULL; return simvis.optimizable(); }
virtual void visit(AstUnlinkedVarXRef* nodep, AstNUser*) { m_unlinkedTxt.clear(); nodep->cellrefp()->iterate(*this); nodep->varxrefp()->dotted(m_unlinkedTxt); nodep->replaceWith(nodep->varxrefp()->unlinkFrBack()); pushDeletep(nodep); VL_DANGLING(nodep); }
void checkActivePost(AstVarRef* varrefp, AstActive* oldactivep) { // Check for MULTIDRIVEN, and if so make new sentree that joins old & new sentree if (!oldactivep) varrefp->v3fatalSrc("<= old dly assignment not put under sensitivity block"); if (oldactivep->sensesp() != m_activep->sensesp()) { if (!varrefp->varp()->fileline()->warnIsOff(V3ErrorCode::MULTIDRIVEN) && !varrefp->varp()->user2()) { varrefp->varp()->v3warn(MULTIDRIVEN,"Signal has multiple driving blocks: "<<varrefp->varp()->prettyName()); varrefp->v3warn(MULTIDRIVEN,"... Location of first driving block"); oldactivep->v3warn(MULTIDRIVEN,"... Location of other driving block"); varrefp->varp()->user2(true); } UINFO(4,"AssignDupDlyVar: "<<varrefp<<endl); UINFO(4," Act: "<<m_activep<<endl); UINFO(4," Act: "<<oldactivep<<endl); // Make a new sensitivity list, which is the combination of both blocks AstNodeSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true); AstNodeSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true); AstSenTree* treep = new AstSenTree(m_activep->fileline(), sena); if (senb) treep->addSensesp(senb); if (AstSenTree* storep = oldactivep->sensesStorep()) { storep->unlinkFrBack(); pushDeletep(storep); } oldactivep->sensesStorep(treep); oldactivep->sensesp(treep); } }
virtual void visit(AstWhile* nodep, AstNUser*) { nodep->iterateChildren(*this); if (m_varModeCheck || m_varModeReplace) { } else { // Constify before unroll call, as it may change what is underneath. if (nodep->precondsp()) V3Const::constifyEdit(nodep->precondsp()); // precondsp may change if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change // Grab initial value AstNode* initp = NULL; // Should be statement before the while. if (nodep->backp()->nextp() == nodep) initp=nodep->backp(); if (initp) { V3Const::constifyEdit(initp); VL_DANGLING(initp); } if (nodep->backp()->nextp() == nodep) initp=nodep->backp(); // Grab assignment AstNode* incp = NULL; // Should be last statement if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp()); if (nodep->incsp()) incp = nodep->incsp(); else { for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} if (incp) { V3Const::constifyEdit(incp); VL_DANGLING(incp); } for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed } // And check it if (forUnrollCheck(nodep, initp, nodep->precondsp(), nodep->condp(), incp, nodep->bodysp())) { pushDeletep(nodep); VL_DANGLING(nodep); // Did replacement } } }
virtual void visit(AstGenFor* nodep, AstNUser*) { if (!m_generate || m_varModeReplace) { nodep->iterateChildren(*this); } // else V3Param will recursively call each for loop to be unrolled for us if (m_varModeCheck || m_varModeReplace) { } else { // Constify before unroll call, as it may change what is underneath. if (nodep->initsp()) V3Const::constifyEdit(nodep->initsp()); // initsp may change if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp()); // incsp may change if (nodep->condp()->isZero()) { // We don't need to do any loops. Remove the GenFor, // Genvar's don't care about any initial assignments. // // Note normal For's can't do exactly this deletion, as // we'd need to initialize the variable to the initial // condition, but they'll become while's which can be // deleted by V3Const. nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); } else if (forUnrollCheck(nodep, nodep->initsp(), NULL, nodep->condp(), nodep->incsp(), nodep->bodysp())) { pushDeletep(nodep); VL_DANGLING(nodep); // Did replacement } else { nodep->v3error("For loop doesn't have genvar index, or is malformed"); } } }
// VISITORS virtual void visit(AstCell* nodep, AstNUser*) { if (nodep->rangep()) { m_cellRangep = nodep->rangep(); UINFO(4," CELL "<<nodep<<endl); // Make all of the required clones m_instLsb = m_cellRangep->lsbConst(); for (m_instNum = m_instLsb; m_instNum<=m_cellRangep->msbConst(); m_instNum++) { AstCell* newp = nodep->cloneTree(false); nodep->addNextHere(newp); // Remove ranging and fix name newp->rangep()->unlinkFrBack()->deleteTree(); // Somewhat illogically, we need to rename the orignal name of the cell too. // as that is the name users expect for dotting // The spec says we add [x], but that won't work in C... newp->name(newp->name()+"__BRA__"+cvtToStr(m_instNum)+"__KET__"); newp->origName(newp->origName()+"__BRA__"+cvtToStr(m_instNum)+"__KET__"); // Fixup pins newp->pinsp()->iterateAndNext(*this); if (debug()==9) { newp->dumpTree(cout,"newcell: "); cout<<endl; } } // Done. Delete original m_cellRangep=NULL; nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; } }
// VISITORS //========== Statements virtual void visit(AstPslDefClock* nodep, AstNUser*) { nodep->iterateChildren(*this); // Store the new default clock, reset on new module m_seniDefaultp = nodep->sensesp(); // Trash it nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; }
void checkConstantOrReplace(AstNode* nodep, const string& message) { // See also V3Width::checkConstantOrReplace // Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us! if (!nodep->castConst()) { nodep->v3error(message); nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Unsized32(), 1)); pushDeletep(nodep); VL_DANGLING(nodep); } }
void replaceFuncWFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) { UINFO(5," DupFunc "<<hex<<V3Hash(newfuncp->user4p())<<" "<<newfuncp<<endl); UINFO(5," and "<<hex<<V3Hash(oldfuncp->user4p())<<" "<<oldfuncp<<endl); // Mark user3p on entire old tree, so we don't process it more ++m_statCombs; CombMarkVisitor visitor(oldfuncp); m_call.replaceFunc(oldfuncp, newfuncp); oldfuncp->unlinkFrBack(); pushDeletep(oldfuncp); VL_DANGLING(oldfuncp); }
virtual void visit(AstBreak* nodep, AstNUser*) { nodep->iterateChildren(*this); if (!m_loopp) { nodep->v3error("break isn't underneath a loop"); } else { // Jump to the end of the loop AstJumpLabel* labelp = findAddLabel(m_loopp, false); nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp)); } nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep); }
virtual void visit(AstIf* nodep, AstNUser*) { if (nodep->user1SetOnce()) return; if (nodep->uniquePragma() || nodep->unique0Pragma()) { AstNodeIf* ifp = nodep; AstNode* propp = NULL; bool hasDefaultElse = false; do { // If this statement ends with 'else if', then nextIf will point to the // nextIf statement. Otherwise it will be null. AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp()); ifp->condp()->iterateAndNext(*this); // Recurse into the true case. ifp->ifsp()->iterateAndNext(*this); // If the last else is not an else if, recurse into that too. if (ifp->elsesp() && !nextifp) { ifp->elsesp()->iterateAndNext(*this); } // Build a bitmask of the true predicates AstNode* predp = ifp->condp()->cloneTree(false); if (propp) { propp = new AstConcat(nodep->fileline(), predp, propp); } else { propp = predp; } // Record if this ends with an 'else' that does not have an if if (ifp->elsesp() && !nextifp) { hasDefaultElse = true; } ifp = nextifp; } while (ifp); AstNode *newifp = nodep->cloneTree(false); bool allow_none = nodep->unique0Pragma(); // Note: if this ends with an 'else', then we don't need to validate that one of the // predicates evaluates to true. AstNode* ohot = ((allow_none || hasDefaultElse) ? (new AstOneHot0(nodep->fileline(), propp))->castNode() : (new AstOneHot (nodep->fileline(), propp))->castNode()); AstIf* checkifp = new AstIf (nodep->fileline(), new AstLogNot (nodep->fileline(), ohot), newFireAssert(nodep, "'unique if' statement violated"), newifp); checkifp->branchPred(AstBranchPred::BP_UNLIKELY); nodep->replaceWith(checkifp); pushDeletep(nodep); } else { nodep->iterateChildren(*this); } }
virtual void visit(AstContinue* nodep, AstNUser*) { nodep->iterateChildren(*this); if (!m_loopp) { nodep->v3error("continue isn't underneath a loop"); } else { // Jump to the end of this iteration // If a "for" loop then need to still do the post-loop increment AstJumpLabel* labelp = findAddLabel(m_loopp, true); nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp)); } nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep); }
virtual void visit(AstPragma* nodep, AstNUser*) { if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) { if (!m_modp) nodep->v3fatalSrc("PUBLIC_MODULE not under a module\n"); m_modp->modPublic(true); nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; } else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) { if (!m_ftaskp) nodep->v3fatalSrc("PUBLIC_TASK not under a task\n"); m_ftaskp->taskPublic(true); m_modp->modPublic(true); // Need to get to the task... nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; } else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) { if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize better without nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; } } else { nodep->iterateChildren(*this); } }
virtual void visit(AstClocking* nodep, AstNUser*) { UINFO(8," CLOCKING"<<nodep<<endl); // Store the new default clock, reset on new module m_seniDefaultp = nodep->sensesp(); // Trash it, keeping children if (nodep->bodysp()) { nodep->replaceWith(nodep->bodysp()->unlinkFrBack()); } else { nodep->unlinkFrBack(); } pushDeletep(nodep); nodep=NULL; }
void walkReplace(AstNode* node1p, AstNode* node2p, AstNode* last1p, AstNode* last2p) { // Final node in linked list, maybe null if all statements to be grabbed // Make new function string oldname = m_funcp->name(); string::size_type pos; if ((pos=oldname.find("_common")) != string::npos) { oldname.erase(pos); } if ((pos=oldname.find("__")) != string::npos) { oldname.erase(pos); } AstCFunc* newfuncp = new AstCFunc(node1p->fileline(), oldname+"_common"+cvtToStr(++m_modNFuncs), NULL); m_modp->addStmtp(newfuncp); // Create calls AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp); AstCCall* call2p = new AstCCall(node2p->fileline(), newfuncp); // Grab statement bodies AstNRelinker relink1Handle; AstNRelinker relink2Handle; for (AstNode* nextp, *walkp = node1p; 1; walkp = nextp) { nextp = walkp->nextp(); if (walkp==node1p) walkp->unlinkFrBack(&relink1Handle); else { walkp->unlinkFrBack(); node1p->addNext(walkp); } if (walkp==last1p) break; } for (AstNode* nextp, *walkp = node2p; 1; walkp = nextp) { nextp = walkp->nextp(); if (walkp==node2p) walkp->unlinkFrBack(&relink2Handle); else { walkp->unlinkFrBack(); node2p->addNext(walkp); } if (walkp==last2p) break; } // Move node1 statements to new function newfuncp->addStmtsp(node1p); //newfuncp->dumpTree(cout," newfunctree: "); // Mark node2 statements as dead CombMarkVisitor visitor(node2p); pushDeletep(node2p); // Delete later // Link in new function relink1Handle.relink(call1p); relink2Handle.relink(call2p); // Hash the new function hashFunctions(newfuncp); m_call.addCall(call1p); m_call.addCall(call2p); // If either new statement makes a func with only a single call, replace // the above callers to call it directly replaceOnlyCallFunc(call1p); VL_DANGLING(call1p); replaceOnlyCallFunc(call2p); VL_DANGLING(call2p); }
virtual void visit(AstBegin* nodep, AstNUser*) { // Begin blocks were only useful in variable creation, change names and delete UINFO(8," "<<nodep<<endl); string oldScope = m_namedScope; string oldUnnamed = m_unnamedScope; { UINFO(8,"nname "<<m_namedScope<<endl); if (nodep->name() != "") { // Else unneeded unnamed block // Create data for dotted variable resolution string dottedname = nodep->name() + "__DOT__"; // So always found string::size_type pos; while ((pos=dottedname.find("__DOT__")) != string::npos) { string ident = dottedname.substr(0,pos); dottedname = dottedname.substr(pos+strlen("__DOT__")); if (!nodep->unnamed()) { if (m_namedScope=="") m_namedScope = ident; else m_namedScope = m_namedScope + "__DOT__"+ident; } if (m_unnamedScope=="") m_unnamedScope = ident; else m_unnamedScope = m_unnamedScope + "__DOT__"+ident; // Create CellInline for dotted var resolution if (!m_ftaskp) { AstCellInline* inlinep = new AstCellInline(nodep->fileline(), m_unnamedScope, "__BEGIN__"); m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells } } } // Remap var names and replace lower Begins nodep->stmtsp()->iterateAndNext(*this); if (nodep->genforp()) nodep->v3fatalSrc("GENFORs should have been expanded earlier"); } m_namedScope = oldScope; m_unnamedScope = oldUnnamed; // Cleanup AstNode* addsp = NULL; if (AstNode* stmtsp = nodep->stmtsp()) { stmtsp->unlinkFrBackWithNext(); if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; } } if (addsp) { nodep->replaceWith(addsp); } else { nodep->unlinkFrBack(); } pushDeletep(nodep); nodep=NULL; }
void newPslAssertion(AstNode* nodep, AstNode* propp, AstSenTree* sentreep, AstNode* stmtsp, const string& message) { propp->unlinkFrBack(); sentreep->unlinkFrBack(); if (stmtsp) stmtsp->unlinkFrBack(); // AstNode* bodysp = NULL; bool selfDestruct = false; if (AstPslCover* snodep = nodep->castPslCover()) { if (!v3Global.opt.coverageUser()) { selfDestruct = true; } else { // V3Coverage assigned us a bucket to increment. AstCoverInc* covincp = snodep->coverincp()->castCoverInc(); if (!covincp) snodep->v3fatalSrc("Missing AstCoverInc under assertion"); covincp->unlinkFrBack(); if (message!="") covincp->declp()->comment(message); bodysp = covincp; } } else if (nodep->castPslAssert()) { bodysp = newFireAssert(nodep,message); // We assert the property is always true... so report when it fails // (Note this is opposite the behavior of coverage statements.) // Need: 'never' operator: not hold in current or any future cycle propp = new AstLogNot (nodep->fileline(), propp); } else { nodep->v3fatalSrc("Unknown node type"); } if (stmtsp) bodysp = bodysp->addNext(stmtsp); AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL); bodysp = ifp; if (nodep->castPslAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY); // AstNode* newp = new AstAlways (nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, bodysp); // Install it if (selfDestruct) { // Delete it after making the tree. This way we can tell the user // if it wasn't constructed nicely or has other errors without needing --coverage. newp->deleteTree(); nodep->unlinkFrBack(); } else { nodep->replaceWith(newp); } // Bye pushDeletep(nodep); nodep=NULL; }
void walkEmptyFuncs() { for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) { AstNode* node1p = it->second; AstCFunc* oldfuncp = node1p->castCFunc(); if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) { UINFO(5," EmptyFunc "<<hex<<V3Hash(oldfuncp->user4p())<<" "<<oldfuncp<<endl); // Mark user3p on entire old tree, so we don't process it more CombMarkVisitor visitor(oldfuncp); m_call.replaceFunc(oldfuncp, NULL); oldfuncp->unlinkFrBack(); pushDeletep(oldfuncp); VL_DANGLING(oldfuncp); } } }
//---- virtual void visit(AstVarRef* nodep) { // Consumption/generation of a variable, AstVarScope* vscp = nodep->varScopep(); if (!vscp) nodep->v3fatalSrc("Scope not assigned"); if (m_activep && !nodep->user3()) { nodep->user3(true); if (vscp->isCircular()) { UINFO(8," VarActReplace "<<nodep<<endl); // Replace with the new variable AstVarScope* newvscp = genInpClk(vscp); AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue()); nodep->replaceWith(newrefp); pushDeletep(nodep); VL_DANGLING(nodep); } } }
virtual void visit(AstVarRef* nodep, AstNUser*) { if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp && nodep->lvalue()) { UINFO(8," Itervar assigned to: "<<nodep<<endl); m_varAssignHit = true; } if (m_varModeReplace && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp && !nodep->lvalue()) { AstNode* newconstp = m_varValuep->cloneTree(false); nodep->replaceWith(newconstp); pushDeletep(nodep); } }
virtual void visit(AstPslClocked* nodep, AstNUser*) { nodep->iterateChildren(*this); if (m_senip) { nodep->v3error("Unsupported: Only one PSL clock allowed per assertion"); } // Block is the new expression to evaluate AstNode* blockp = nodep->propp()->unlinkFrBack(); if (nodep->disablep()) { blockp = new AstAnd(nodep->disablep()->fileline(), new AstNot(nodep->disablep()->fileline(), nodep->disablep()->unlinkFrBack()), blockp); } // Unlink and just keep a pointer to it, convert to sentree as needed m_senip = nodep->sensesp(); nodep->replaceWith(blockp); pushDeletep(nodep); nodep=NULL; }
// METHODS void readModNames() { // Look at all modules, and store pointers to all module names for (AstNodeModule* nextp,* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nextp) { nextp = nodep->nextp()->castNodeModule(); AstNode* foundp = m_mods.rootp()->findIdFallback(nodep->name())->nodep(); if (foundp && foundp != nodep) { if (!(foundp->fileline()->warnIsOff(V3ErrorCode::MODDUP) || nodep->fileline()->warnIsOff(V3ErrorCode::MODDUP))) { nodep->v3warn(MODDUP,"Duplicate declaration of module: "<<nodep->prettyName()<<endl <<foundp->warnMore()<<"... Location of original declaration"); } nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; } else if (!foundp) { m_mods.rootp()->insert(nodep->name(), new VSymEnt(&m_mods, nodep)); } } //if (debug()>=9) m_mods.dump(cout, "-syms: "); }
virtual void visit(AstReturn* nodep, AstNUser*) { nodep->iterateChildren(*this); AstFunc* funcp = m_ftaskp->castFunc(); if (!m_ftaskp) { nodep->v3error("Return isn't underneath a task or function"); } else if (funcp && !nodep->lhsp()) { nodep->v3error("Return underneath a function should have return value"); } else if (!funcp && nodep->lhsp()) { nodep->v3error("Return underneath a task shouldn't have return value"); } else { if (funcp && nodep->lhsp()) { // Set output variable to return value nodep->addPrev(new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), funcp->fvarp()->castVar(), true), nodep->lhsp()->unlinkFrBackWithNext())); } // Jump to the end of the function call AstJumpLabel* labelp = findAddLabel(m_ftaskp, false); nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp)); } nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep); }
virtual void visit(AstActive* nodep, AstNUser*) { UINFO(4," ACTIVE "<<nodep<<endl); V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change! AstSenTree* sensesp = nodep->sensesp(); if (!sensesp) nodep->v3fatalSrc("NULL"); if (sensesp->sensesp() && sensesp->sensesp()->castSenItem() && sensesp->sensesp()->castSenItem()->isNever()) { // Never executing. Kill it. if (sensesp->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated."); nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); return; } // Copy combo tree to settlement tree with duplicated statements if (sensesp->hasCombo()) { AstSenTree* newsentreep = new AstSenTree (nodep->fileline(), new AstSenItem (nodep->fileline(), AstSenItem::Settle())); AstActive* newp = new AstActive(nodep->fileline(),"settle", newsentreep); newp->sensesStorep(newsentreep); if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true)); nodep->addNextHere(newp); } // Move the SENTREE for each active up to the global level. // This way we'll easily see what clock domains are identical AstSenTree* wantp = m_finder.getSenTree(nodep->fileline(), sensesp); UINFO(4," lookdone\n"); if (wantp != sensesp) { // Move the active's contents to the other active UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl); if (nodep->sensesStorep()) { if (sensesp != nodep->sensesStorep()) nodep->v3fatalSrc("sensesStore should have been deleted earlier if different\n"); sensesp->unlinkFrBack(); // There may be other references to same sense tree, // we'll be removing all references when we get to them, // but don't dangle our pointer yet! pushDeletep(sensesp); } nodep->sensesp(wantp); } // No need to do statements under it, they're already moved. //nodep->iterateChildren(*this); }
virtual void visit(AstBind* nodep, AstNUser*) { // Bind: Has cells underneath that need to be put into the new module, and cells which need resolution // TODO this doesn't allow bind to dotted hier names, that would require // this move to post param, which would mean we do not auto-read modules // and means we cannot compute module levels until later. UINFO(4,"Link Bind: "<<nodep<<endl); AstNodeModule* modp = resolveModule(nodep,nodep->name()); if (modp) { AstNode* cellsp = nodep->cellsp()->unlinkFrBackWithNext(); // Module may have already linked, so need to pick up these new cells AstNodeModule* oldModp = m_modp; { m_modp = modp; modp->addStmtp(cellsp); // Important that this adds to end, as next iterate assumes does all cells cellsp->iterateAndNext(*this); } m_modp = oldModp; } pushDeletep(nodep->unlinkFrBack()); }
bool simulateTree(AstNode *nodep, const V3Number *loopValue, AstNode *dtypep, V3Number &outNum) { AstNode* clone = nodep->cloneTree(true); if (!clone) { nodep->v3fatalSrc("Failed to clone tree"); return false; } if (loopValue) { m_varValuep = new AstConst (nodep->fileline(), *loopValue); // Iteration requires a back, so put under temporary node AstBegin* tempp = new AstBegin (nodep->fileline(), "[EditWrapper]", clone); m_varModeReplace = true; tempp->stmtsp()->iterateAndNext(*this); m_varModeReplace = false; clone = tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); tempp = NULL; pushDeletep(m_varValuep); m_varValuep = NULL; } SimulateVisitor simvis; simvis.mainParamEmulate(clone); if (!simvis.optimizable()) { UINFO(3, "Unable to simulate" << endl); if (debug()>=9) nodep->dumpTree(cout,"- _simtree: "); return false; } // Fetch the result V3Number* res = simvis.fetchNumberNull(clone); if (!res) { UINFO(3, "No number returned from simulation" << endl); return false; } // Patch up datatype if (dtypep) { AstConst new_con (clone->fileline(), *res); new_con.dtypeFrom(dtypep); outNum = new_con.num(); return true; } outNum = *res; return true; }
void detectDuplicates() { UINFO(9,"Finding duplicates\n"); // Note uses user4 V3Hashed hashed; // Duplicate code detection // Hash all of the original signals we toggle cover for (ToggleList::iterator it = m_toggleps.begin(); it != m_toggleps.end(); ++it) { AstCoverToggle* nodep = *it; hashed.hashAndInsert(nodep->origp()); } // Find if there are any duplicates for (ToggleList::iterator it = m_toggleps.begin(); it != m_toggleps.end(); ++it) { AstCoverToggle* nodep = *it; if (nodep->backp()) { // nodep->backp() is null if we already detected it's a duplicate and unlinked it // Want to choose a base node, and keep finding duplicates that are identical // This prevents making chains where a->b, then c->d, then b->c, as we'll find a->b, a->c, a->d directly. while (1) { V3Hashed::iterator dupit = hashed.findDuplicate(nodep->origp()); if (dupit == hashed.end()) break; // AstNode* duporigp = hashed.iteratorNodep(dupit); // Note hashed will point to the original variable (what's duplicated), not the covertoggle, // but we need to get back to the covertoggle which is immediately above, so: AstCoverToggle* removep = duporigp->backp()->castCoverToggle(); if (!removep) nodep->v3fatalSrc("CoverageJoin duplicate of wrong type"); UINFO(8," Orig "<<nodep<<" -->> "<<nodep->incp()->declp()<<endl); UINFO(8," dup "<<removep<<" -->> "<<removep->incp()->declp()<<endl); // The CoverDecl the duplicate pointed to now needs to point to the original's data // IE the duplicate will get the coverage number from the non-duplicate AstCoverDecl* datadeclp = nodep->incp()->declp()->dataDeclThisp(); removep->incp()->declp()->dataDeclp (datadeclp); UINFO(8," new "<<removep->incp()->declp()<<endl); // Mark the found node as a duplicate of the first node // (Not vice-versa as we have the iterator for the found node) removep->unlinkFrBack(); pushDeletep(removep); removep=NULL; // Remove node from comparison so don't hit it again hashed.erase(dupit); ++m_statToggleJoins; } } } }
void newVAssertion(AstVAssert* nodep, AstNode* propp) { propp->unlinkFrBackWithNext(); AstNode* passsp = nodep->passsp(); if (passsp) passsp->unlinkFrBackWithNext(); AstNode* failsp = nodep->failsp(); if (failsp) failsp->unlinkFrBackWithNext(); // if (nodep->castVAssert()) { if (passsp) passsp = newIfAssertOn(passsp); if (failsp) failsp = newIfAssertOn(failsp); } else { nodep->v3fatalSrc("Unknown node type"); } AstIf* ifp = new AstIf (nodep->fileline(), propp, passsp, failsp); AstNode* newp = ifp; if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY); // // Install it nodep->replaceWith(newp); // Bye pushDeletep(nodep); nodep=NULL; }