virtual void visit(AstNodeVarRef* nodep, AstNUser*) { if (m_scopep) { if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block\n"); AstVarScope* varscp = nodep->varScopep(); if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n"); GateVarVertex* vvertexp = makeVarVertex(varscp); UINFO(5," VARREF to "<<varscp<<endl); if (m_inSenItem) vvertexp->setIsClock(); // For SYNCASYNCNET if (m_inSenItem) varscp->user2(true); else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) { if (varscp->user2()) { if (!vvertexp->rstSyncNodep()) vvertexp->rstSyncNodep(nodep); } else { if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep); } } // We use weight of one; if we ref the var more than once, when we simplify, // the weight will increase if (nodep->lvalue()) { new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1); } else { new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1); } } }
virtual void visit(AstVarRef* nodep, AstNUser*) { if (nodep->lvalue()) { AstVarScope* vscp = nodep->varScopep(); if (nodep->varp()->isSigPublic()) { // Public signals shouldn't be changed, pli code might be messing with them scoreboardPli(nodep); } // If another lvalue in this node, give up optimizing. // We could just not optimize this variable, but we've already marked the // other variable as optimizable, so we can instead pretend it's a PLI node. if (m_stmtVscp) { UINFO(5, " Multiple lvalues in one statement: "<<nodep<<endl); scoreboardPli(nodep); // This will set m_stmtInPli } m_stmtVscp = vscp; // Find, or make new Vertex GaterVarVertex* vertexp = (GaterVarVertex*)(vscp->user1p()); if (!vertexp) { vertexp = new GaterVarVertex(&m_graph, vscp); vscp->user1p(vertexp); } new GaterEdge(&m_graph, m_aboveVertexp, vertexp, m_aboveTrue); if (m_stmtInPli) { new GaterEdge(&m_graph, m_pliVertexp, vertexp, VU_PLI); } } }
// NODE STATE // INPUT: // AstVarScope::user4p() -> AstVarScope*, If set, replace this varscope with specified new one // STATE // VISITORS virtual void visit(AstVarRef* nodep, AstNUser*) { AstVarScope* vscp = nodep->varScopep(); if (!vscp) nodep->v3fatalSrc("Scope not assigned"); if (AstVarScope* newvscp = (AstVarScope*)vscp->user4p()) { UINFO(9, " Replace "<<nodep<<" to "<<newvscp<<endl); AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue()); nodep->replaceWith(newrefp); nodep->deleteTree(); nodep=NULL; } }
virtual void visit(AstVarRef* nodep, AstNUser*) { // Consumption/generation of a variable, AstVarScope* vscp = nodep->varScopep(); if (!vscp) nodep->v3fatalSrc("Scope not assigned"); m_sequence++; if (nodep->lvalue()) { // First generator if (!vscp->user1()) vscp->user1(m_sequence); } else { // Last consumer vscp->user2(m_sequence); } }
virtual void visit(AstVarRef* nodep) { // Consumption/generation of a variable, AstVarScope* vscp = nodep->varScopep(); if (!vscp) nodep->v3fatalSrc("Scope not assigned"); if (m_activep) { UINFO(8," VarAct "<<nodep<<endl); vscp->user1(true); } if (m_assignp && nodep->lvalue() && vscp->user1()) { // Variable was previously used as a clock, and is now being set // Thus a unordered generated clock... UINFO(8," VarSetAct "<<nodep<<endl); vscp->circular(true); } }
//---- 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(AstUnpackArrayDType* nodep, AstNUser*) { // Note more specific dtypes above if (m_traVscp) { if ((int)nodep->arrayUnpackedElements() > v3Global.opt.traceMaxArray()) { addIgnore("Wide memory > --trace-max-array ents"); } else if (nodep->subDTypep()->skipRefp()->castBasicDType() // Nothing lower than this array && m_traVscp->dtypep()->skipRefp() == nodep) { // Nothing above this array // Simple 1-D array, use exising V3EmitC runtime loop rather than unrolling // This will put "(index)" at end of signal name for us addTraceDecl(nodep->declRange()); } else { // Unroll now, as have no other method to get right signal names AstNodeDType* subtypep = nodep->subDTypep()->skipRefp(); for (int i=nodep->lsb(); i<=nodep->msb(); ++i) { string oldShowname = m_traShowname; AstNode* oldValuep = m_traValuep; { m_traShowname += string("(")+cvtToStr(i)+string(")"); m_traValuep = new AstArraySel(nodep->fileline(), m_traValuep->cloneTree(true), i - nodep->lsb()); subtypep->accept(*this); m_traValuep->deleteTree(); m_traValuep = NULL; } m_traShowname = oldShowname; m_traValuep = oldValuep; } } } }
virtual void visit(AstVarRef* nodep) { if (!m_stmtStackps.empty()) { AstVarScope* vscp = nodep->varScopep(); if (!vscp) nodep->v3fatalSrc("Not linked"); if (!nodep->varp()->isConst()) { // Constant lookups can be ignored // --- // NOTE: Formerly at this location we would avoid // splitting or reordering if the variable is public. // // However, it should be perfectly safe to split an // always block containing a public variable. // Neither operation should perturb PLI's view of // the variable. // // Former code: // // if (nodep->varp()->isSigPublic()) { // // Public signals shouldn't be changed, // // pli code might be messing with them // scoreboardPli(nodep); // } // --- // Create vertexes for variable if (!vscp->user1p()) { SplitVarStdVertex* vstdp = new SplitVarStdVertex(&m_graph, vscp); vscp->user1p(vstdp); } SplitVarStdVertex* vstdp = (SplitVarStdVertex*) vscp->user1p(); // SPEEDUP: We add duplicate edges, that should be fixed if (m_inDly && nodep->lvalue()) { UINFO(4," VARREFDLY: "<<nodep<<endl); // Delayed variable is different from non-delayed variable if (!vscp->user2p()) { SplitVarPostVertex* vpostp = new SplitVarPostVertex(&m_graph, vscp); vscp->user2p(vpostp); new SplitPostEdge(&m_graph, vstdp, vpostp); } SplitVarPostVertex* vpostp = (SplitVarPostVertex*)vscp->user2p(); // Add edges for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) { new SplitLVEdge(&m_graph, vpostp, *it); } } else { // Nondelayed assignment if (nodep->lvalue()) { // Non-delay; need to maintain existing ordering with all consumers of the signal UINFO(4," VARREFLV: "<<nodep<<endl); for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) { new SplitLVEdge(&m_graph, vstdp, *it); } } else { UINFO(4," VARREF: "<<nodep<<endl); makeRvalueEdges(vstdp); } } } } }
virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) { // Check that we haven't been here before if (vvertexp->varScp()->user2()) return NULL; vvertexp->varScp()->user2(true); AstNodeVarRef* dupVarRefp = (AstNodeVarRef*) vvertexp->iterateInEdges(*this, (AstNUser*) vvertexp); if (dupVarRefp && vvertexp->inSize1()) { V3GraphEdge* edgep = vvertexp->inBeginp(); GateLogicVertex* lvertexp = (GateLogicVertex*)edgep->fromp(); if (!vvertexp->dedupable()) vvertexp->varScp()->v3fatalSrc("GateLogicVertex* visit should have returned NULL if consumer var vertex is not dedupable."); GateOkVisitor okVisitor(lvertexp->nodep(), false, true); if (okVisitor.isSimple()) { AstVarScope* dupVarScopep = dupVarRefp->varScopep(); GateVarVertex* dupVvertexp = (GateVarVertex*) (dupVarScopep->user1p()); UINFO(4,"replacing " << vvertexp << " with " << dupVvertexp << endl); ++m_numDeduped; // Replace all of this varvertex's consumers with dupVarRefp for (V3GraphEdge* outedgep = vvertexp->outBeginp();outedgep;) { GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(outedgep->top()); AstNode* consumerp = consumeVertexp->nodep(); GateElimVisitor elimVisitor(consumerp,vvertexp->varScp(),dupVarRefp); outedgep = outedgep->relinkFromp(dupVvertexp); } // Propogate attributes dupVvertexp->propagateAttrClocksFrom(vvertexp); // Remove inputs links while (V3GraphEdge* inedgep = vvertexp->inBeginp()) { inedgep->unlinkDelete(); VL_DANGLING(inedgep); } // replaceAssigns() does the deleteTree on lvertexNodep in a later step AstNode* lvertexNodep = lvertexp->nodep(); lvertexNodep->unlinkFrBack(); vvertexp->varScp()->valuep(lvertexNodep); lvertexNodep = NULL; vvertexp->user(true); lvertexp->user(true); } } return NULL; }
void addTraceDecl(const VNumRange& arrayRange) { VNumRange bitRange; AstBasicDType* bdtypep = m_traValuep->dtypep()->basicp(); if (bdtypep) bitRange = bdtypep->nrange(); AstTraceDecl* declp = new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traValuep, bitRange, arrayRange); if (m_initSubStmts && v3Global.opt.outputSplitCTrace() && m_initSubStmts > v3Global.opt.outputSplitCTrace()) { m_initSubFuncp = newCFuncSub(m_initFuncp); m_initSubStmts = 0; } m_initSubFuncp->addStmtsp(declp); m_initSubStmts += EmitCBaseCounterVisitor(declp).count(); m_chgFuncp->addStmtsp(new AstTraceInc(m_traVscp->fileline(), declp, m_traValuep->cloneTree(true))); // The full version will get constructed in V3Trace }
void GateVisitor::warnSignals() { AstNode::user2ClearTree(); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) { AstVarScope* vscp = vvertexp->varScp(); AstNode* sp = vvertexp->rstSyncNodep(); AstNode* ap = vvertexp->rstAsyncNodep(); if (ap && sp && !vscp->varp()->user2()) { // This is somewhat wrong, as marking one flop as ok for sync // may mean a different flop now fails. However it's a pain to // then report a warning in a new place - we should report them all at once. // Instead we'll disable if any disabled if (!vscp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET) && !ap->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET) && !sp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET) ) { vscp->varp()->user2(true); // Warn only once per signal vscp->v3warn(SYNCASYNCNET,"Signal flopped as both synchronous and async: "<<vscp->prettyName()<<endl <<ap->warnMore()<<"... Location of async usage"<<endl <<sp->warnMore()<<"... Location of sync usage"<<endl); } } } } }
void deadCheckVar() { // Delete any unused varscopes for (vector<AstVarScope*>::iterator it = m_vscsp.begin(); it!=m_vscsp.end(); ++it) { AstVarScope* vscp = *it; if (vscp->user1() == 0) { UINFO(4," Dead "<<vscp<<endl); pair <AssignMap::iterator,AssignMap::iterator> eqrange = m_assignMap.equal_range(vscp); for (AssignMap::iterator it = eqrange.first; it != eqrange.second; ++it) { AstNodeAssign* assp = it->second; UINFO(4," Dead assign "<<assp<<endl); assp->unlinkFrBack()->deleteTree(); VL_DANGLING(assp); } vscp->unlinkFrBack()->deleteTree(); VL_DANGLING(vscp); } } for (vector<AstNode*>::iterator it = m_varEtcsp.begin(); it!=m_varEtcsp.end(); ++it) { if ((*it)->user1() == 0) { UINFO(4," Dead "<<(*it)<<endl); (*it)->unlinkFrBack()->deleteTree(); (*it)=NULL; } } }
// VISITORS virtual void visit(AstVarRef* nodep, AstNUser*) { if (nodep->lvalue()) { AstVarScope* vscp = nodep->varScopep(); if (vscp->user2p()->castNode() == m_exprp) { // This variable's block needs to move to the new always if (m_original) { UINFO(9," VARREF delete in old: "<<nodep<<endl); m_state |= STATE_DELETE; } else { UINFO(9," VARREF stays in new: "<<nodep<<endl); m_state |= STATE_KEEP; } } else { if (m_original) { UINFO(9," VARREF other stays in old\n"); m_state |= STATE_KEEP; } else { UINFO(9," VARREF other delete in new\n"); m_state |= STATE_DELETE; } } } }
void dualBranch(LifeBlock* life1p, LifeBlock* life2p) { // Find any common sets on both branches of IF and propagate upwards //life1p->lifeDump(); //life2p->lifeDump(); AstNode::user1ClearTree(); // user1p() used on entire tree for (LifeMap::iterator it = life1p->m_map.begin(); it!=life1p->m_map.end(); ++it) { // When the if branch sets a var before it's used, mark that variable if (it->second.setBeforeUse()) it->first->user1(1); } for (LifeMap::iterator it = life2p->m_map.begin(); it!=life2p->m_map.end(); ++it) { // When the else branch sets a var before it's used AstVarScope* nodep = it->first; if (it->second.setBeforeUse() && nodep->user1()) { // Both branches set the var, we can remove the assignment before the IF. UINFO(4,"DUALBRANCH "<<nodep<<endl); LifeMap::iterator itab = m_map.find(nodep); if (itab != m_map.end()) { checkRemoveAssign(itab); } } } //this->lifeDump(); }
void scoreboardPli(AstNode* nodep) { // Order all PLI statements with other PLI statements // This insures $display's and such remain in proper order // We don't prevent splitting out other non-pli statements, however, // because it is common to have $uasserts sprinkled about. if (!m_pliVertexp) { m_pliVertexp = new GaterPliVertex(&m_graph); } if (m_stmtVscp) { // Already saw a variable, be sure to mark it! GaterVarVertex* varVtxp = (GaterVarVertex*)(m_stmtVscp->user1p()); new GaterEdge(&m_graph, m_pliVertexp, varVtxp, VU_PLI); } m_stmtInPli = true; // Mark all followon variables too }
virtual void visit(AstVarRef* nodep, AstNUser*) { if (!m_stmtStackps.empty()) { AstVarScope* vscp = nodep->varScopep(); if (!vscp) nodep->v3fatalSrc("Not linked"); if (!nodep->varp()->isConst()) { // Constant lookups can be ignored if (nodep->varp()->isSigPublic()) { // Public signals shouldn't be changed, pli code might be messing with them scoreboardPli(); } // Create vertexes for variable if (!vscp->user1p()) { SplitVarStdVertex* vstdp = new SplitVarStdVertex(&m_graph, vscp); vscp->user1p(vstdp); } SplitVarStdVertex* vstdp = (SplitVarStdVertex*) vscp->user1p(); // SPEEDUP: We add duplicate edges, that should be fixed if (m_inDly && nodep->lvalue()) { UINFO(4," VARREFDLY: "<<nodep<<endl); // Delayed variable is different from non-delayed variable if (!vscp->user2p()) { SplitVarPostVertex* vpostp = new SplitVarPostVertex(&m_graph, vscp); vscp->user2p(vpostp); new SplitPostEdge(&m_graph, vstdp, vpostp); } SplitVarPostVertex* vpostp = (SplitVarPostVertex*)vscp->user2p(); // Add edges for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) { new SplitLVEdge(&m_graph, vpostp, *it); } } else { // Nondelayed assignment if (nodep->lvalue()) { // Non-delay; need to maintain existing ordering with all consumers of the signal UINFO(4," VARREFLV: "<<nodep<<endl); for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) { new SplitLVEdge(&m_graph, vstdp, *it); } } else { UINFO(4," VARREF: "<<nodep<<endl); for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) { new SplitRVEdge(&m_graph, *it, vstdp); } } } } } }
virtual void visit(AstVarRef* nodep, AstNUser*) { if (!nodep->user2Inc()) { // Not done yet if (m_inDly && nodep->lvalue()) { UINFO(4,"AssignDlyVar: "<<nodep<<endl); markVarUsage(nodep->varScopep(), VU_DLY); if (!m_activep) nodep->v3fatalSrc("<= not under sensitivity block"); if (!m_activep->hasClocked()) nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active"); AstVarScope* oldvscp = nodep->varScopep(); if (!oldvscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n"); AstVarScope* dlyvscp = oldvscp->user1p()->castNode()->castVarScope(); if (dlyvscp) { // Multiple use of delayed variable AstActive* oldactivep = dlyvscp->user2p()->castNode()->castActive(); checkActivePost(nodep, oldactivep); } if (!dlyvscp) { // First use of this delayed variable string newvarname = (string("__Vdly__")+nodep->varp()->shortName()); dlyvscp = createVarSc(oldvscp, newvarname, 0); AstNodeAssign* prep = new AstAssignPre (nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true), new AstVarRef(nodep->fileline(), oldvscp, false)); AstNodeAssign* postp = new AstAssignPost (nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true), new AstVarRef(nodep->fileline(), dlyvscp, false)); postp->lhsp()->user2(true); // Don't detect this assignment oldvscp->user1p(dlyvscp); // So we can find it later // Make new ACTIVE with identical sensitivity tree AstActive* newactp = createActivePost(nodep); dlyvscp->user2p(newactp); newactp->addStmtsp(prep); // Add to FRONT of statements newactp->addStmtsp(postp); } AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true); newrefp->user2(true); // No reason to do it again nodep->replaceWith(newrefp); nodep->deleteTree(); nodep=NULL; } else if (!m_inDly && nodep->lvalue()) { //UINFO(9,"NBA "<<nodep<<endl); if (!m_inInitial) { UINFO(4,"AssignNDlyVar: "<<nodep<<endl); markVarUsage(nodep->varScopep(), VU_NONDLY); } } } }
virtual void visit(AstAlways* nodep, AstNUser*) { // Are there any lvalue references below this? // There could be more than one. So, we process the first one found first. AstVarScope* lastSplitVscp = NULL; while (!nodep->user1()) { // Find any splittable variables SplitAsFindVisitor visitor (nodep); m_splitVscp = visitor.splitVscp(); if (m_splitVscp && m_splitVscp == lastSplitVscp) { // We did this last time! Something's stuck! nodep->v3fatalSrc("Infinite loop in isolate_assignments removal for: "<<m_splitVscp->prettyName()) m_splitVscp = NULL; } lastSplitVscp = m_splitVscp; // Now isolate the always if (m_splitVscp) { splitAlways(nodep); ++m_statSplits; } else { nodep->user1(true); } } }
void GateVisitor::replaceAssigns() { for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) { // Take the Comments/assigns that were moved to the VarScope and change them to a // simple value assignment AstVarScope* vscp = vvertexp->varScp(); if (vscp->valuep() && !vscp->valuep()->castNodeMath()) { //if (debug()>9) vscp->dumpTree(cout, "-vscPre: "); while (AstNode* delp=vscp->valuep()->castComment()) { delp->unlinkFrBack()->deleteTree(); VL_DANGLING(delp); } if (AstInitial* delp=vscp->valuep()->castInitial()) { AstNode* bodyp=delp->bodysp(); bodyp->unlinkFrBackWithNext(); delp->replaceWith(bodyp); delp->deleteTree(); VL_DANGLING(delp); } if (AstAlways* delp=vscp->valuep()->castAlways()) { AstNode* bodyp=delp->bodysp(); bodyp->unlinkFrBackWithNext(); delp->replaceWith(bodyp); delp->deleteTree(); VL_DANGLING(delp); } if (AstNodeAssign* delp=vscp->valuep()->castNodeAssign()) { AstNode* rhsp=delp->rhsp(); rhsp->unlinkFrBack(); delp->replaceWith(rhsp); delp->deleteTree(); VL_DANGLING(delp); } //if (debug()>9) {vscp->dumpTree(cout, "-vscDone: "); cout<<endl;} if (!vscp->valuep()->castNodeMath() || vscp->valuep()->nextp()) { vscp->dumpTree(cerr, "vscStrange: "); vscp->v3fatalSrc("Value of varscope not mathematical\n"); } } } } }
void addIgnore(const char* why) { ++m_statIgnSigs; m_initSubFuncp->addStmtsp( new AstComment(m_traVscp->fileline(), "Tracing: "+m_traShowname+" // Ignored: "+why)); }