// VISITORS virtual void visit(AstNodeVarRef* nodep, AstNUser*) { if (nodep->varScopep() == m_elimVarScp) { // Substitute in the new tree // It's possible we substitute into something that will be reduced more later // however, as we never delete the top Always/initial statement, all should be well. m_didReplace = true; if (nodep->lvalue()) nodep->v3fatalSrc("Can't replace lvalue assignments with const var"); AstNode* substp = m_replaceTreep->cloneTree(false); if (nodep->castNodeVarRef() && substp->castNodeVarRef() && nodep->same(substp)) { // Prevent a infinite loop... substp->v3fatalSrc("Replacing node with itself; perhaps circular logic?"); } // Which fileline() to use? // If replacing with logic, an error/warning is likely to want to point to the logic // IE what we're replacing with. // However a VARREF should point to the original as it's otherwise confusing // to throw warnings that point to a PIN rather than where the pin us used. if (substp->castVarRef()) substp->fileline(nodep->fileline()); // Make the substp an rvalue like nodep. This facilitate the hashing in dedupe. if (AstNodeVarRef* varrefp = substp->castNodeVarRef()) varrefp->lvalue(false); nodep->replaceWith(substp); nodep->deleteTree(); VL_DANGLING(nodep); } }
void V3Hashed::erase(iterator it) { AstNode* nodep = iteratorNodep(it); UINFO(8," erase "<<nodep<<endl); if (!nodep->user4p()) nodep->v3fatalSrc("Called removeNode on non-hashed node"); m_hashMmap.erase(it); nodep->user4p(NULL); // So we don't allow removeNode again }
virtual void visit(AstPin* nodep, AstNUser*) { // PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input) // or ASSIGNW(expr,VARXREF(p)) (if sub's output) UINFO(4," PIN "<<nodep<<endl); if (!nodep->exprp()) return; // No-connect if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: "); if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst()) nodep->v3error("Output port is connected to a constant pin, electrical short"); // Use user1p on the PIN to indicate we created an assign for this pin if (!nodep->user1SetOnce()) { // Simplify it V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, false); // Make a ASSIGNW (expr, pin) AstNode* exprp = nodep->exprp()->cloneTree(false); if (exprp->width() != nodep->modVarp()->width()) nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple\n"); if (nodep->modVarp()->isInout()) { nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator"); } else if (nodep->modVarp()->isOutput()) { AstNode* rhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false); AstAssignW* assp = new AstAssignW (exprp->fileline(), exprp, rhsp); m_modp->addStmtp(assp); } else if (nodep->modVarp()->isInput()) { // Don't bother moving constants now, // we'll be pushing the const down to the cell soon enough. AstNode* assp = new AstAssignW (exprp->fileline(), new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true), exprp); m_modp->addStmtp(assp); if (debug()>=9) assp->dumpTree(cout," _new: "); } else if (nodep->modVarp()->isIfaceRef()) { // Create an AstAssignVarScope for Vars to Cells so we can link with their scope later AstNode* lhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false); AstVarRef* refp = exprp->castVarRef(); if (!refp) exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef"); AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, refp); m_modp->addStmtp(assp); } else { nodep->v3error("Assigned pin is neither input nor output"); } } // We're done with the pin nodep->unlinkFrBack()->deleteTree(); nodep=NULL; }
void replaceBoundLvalue(AstNode* nodep, AstNode* condp) { // Spec says a out-of-range LHS SEL results in a NOP. // This is a PITA. We could: // 1. IF(...) around an ASSIGN, // but that would break a "foo[TOO_BIG]=$fopen(...)". // 2. Hack to extend the size of the output structure // by one bit, and write to that temporary, but never read it. // That makes there be two widths() and is likely a bug farm. // 3. Make a special SEL to choose between the real lvalue // and a temporary NOP register. // 4. Assign to a temp, then IF that assignment. // This is suspected to be nicest to later optimizations. // 4 seems best but breaks later optimizations. 3 was tried, // but makes a mess in the emitter as lvalue switching is needed. So 4. // SEL(...) -> temp // if (COND(LTE(bit<=maxlsb))) ASSIGN(SEL(...)),temp) if (m_assignwp) { // Wire assigns must become always statements to deal with insertion // of multiple statements. Perhaps someday make all wassigns into always's? UINFO(5," IM_WireRep "<<m_assignwp<<endl); m_assignwp->convertToAlways(); pushDeletep(m_assignwp); m_assignwp=NULL; } bool needDly = (m_assigndlyp != NULL); if (m_assigndlyp) { // Delayed assignments become normal assignments, // then the temp created becomes the delayed assignment AstNode* newp = new AstAssign(m_assigndlyp->fileline(), m_assigndlyp->lhsp()->unlinkFrBackWithNext(), m_assigndlyp->rhsp()->unlinkFrBackWithNext()); m_assigndlyp->replaceWith(newp); pushDeletep(m_assigndlyp); m_assigndlyp=NULL; } AstNode* prep = nodep; // Scan back to put the condlvalue above all selects (IE top of the lvalue) while (prep->backp()->castNodeSel() || prep->backp()->castSel()) { prep=prep->backp(); } FileLine* fl = nodep->fileline(); VL_DANGLING(nodep); // Zap it so we don't use it by mistake - use prep // Already exists; rather than IF(a,... IF(b... optimize to IF(a&&b, // Saves us teaching V3Const how to optimize, and it won't be needed again. if (AstIf* ifp = prep->user2p()->castIf()) { if (needDly) prep->v3fatalSrc("Should have already converted to non-delay"); AstNRelinker replaceHandle; AstNode* earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle); AstNode* newp = new AstLogAnd (condp->fileline(), condp, earliercondp); UINFO(4, "Edit BOUNDLVALUE "<<newp<<endl); replaceHandle.relink(newp); } else { string name = ((string)"__Vlvbound"+cvtToStr(m_modp->varNumGetInc())); AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name, prep->dtypep()); m_modp->addStmtp(varp); AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace prep->replaceWith(new AstVarRef(fl, varp, true)); AstNode* newp = new AstIf(fl, condp, (needDly ? static_cast<AstNode*> (new AstAssignDly(fl, prep, new AstVarRef(fl, varp, false))) : static_cast<AstNode*> (new AstAssign (fl, prep, new AstVarRef(fl, varp, false)))), NULL); if (debug()>=9) newp->dumpTree(cout," _new: "); abovep->addNextStmt(newp,abovep); prep->user2p(newp); // Save so we may LogAnd it next time } }