// 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; } }
virtual void visit(AstVarXRef* nodep) { // Track what scope it was originally under so V3LinkDot can resolve it string newname = m_cellp->name(); if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); } nodep->inlinedDots(newname); if (m_renamedInterfaces.count(nodep->dotted())) { nodep->dotted(m_cellp->name() + "__DOT__" + nodep->dotted()); } nodep->iterateChildren(*this); }
virtual void visit(AstScopeName* nodep, AstNUser*) { // If there's a %m in the display text, we add a special node that will contain the name() // Similar code in V3Begin // To keep correct visual order, must add before other Text's AstNode* afterp = nodep->scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name())); if (afterp) nodep->scopeAttrp(afterp); afterp = nodep->scopeEntrp(); if (afterp) afterp->unlinkFrBackWithNext(); nodep->scopeEntrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name())); if (afterp) nodep->scopeEntrp(afterp); nodep->iterateChildren(*this); }
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { // Track what scope it was originally under so V3LinkDot can resolve it string newname = m_cellp->name(); if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); } nodep->inlinedDots(newname); UINFO(8," "<<nodep<<endl); nodep->iterateChildren(*this); }
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; }
virtual void visit(AstVar* nodep, AstNUser*) { if (nodep->user2p()) { // Make an assignment, so we'll trace it properly // user2p is either a const or a var. AstConst* exprconstp = nodep->user2p()->castNode()->castConst(); AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef(); UINFO(8,"connectto: "<<nodep->user2p()->castNode()<<endl); if (!exprconstp && !exprvarrefp) { nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n"); } if (exprconstp) { m_modp->addStmtp(new AstAssignW(nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), exprconstp->cloneTree(true))); } else if (nodep->user3()) { // Public variable at the lower module end - we need to make sure we propagate // the logic changes up and down; if we aliased, we might remove the change detection // on the output variable. UINFO(9,"public pin assign: "<<exprvarrefp<<endl); if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias"); m_modp->addStmtp(new AstAssignW(nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), new AstVarRef(nodep->fileline(), nodep, false))); } else if (nodep->isIfaceRef()) { m_modp->addStmtp(new AstAssignVarScope(nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); AstNode* nodebp=exprvarrefp->varp(); nodep ->fileline()->modifyStateInherit(nodebp->fileline()); nodebp->fileline()->modifyStateInherit(nodep ->fileline()); } else { // Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below m_modp->addStmtp(new AstAssignAlias(nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); AstNode* nodebp=exprvarrefp->varp(); nodep ->fileline()->modifyStateInherit(nodebp->fileline()); nodebp->fileline()->modifyStateInherit(nodep ->fileline()); } } // Variable under the inline cell, need to rename to avoid conflicts // Also clear I/O bits, as it is now local. string name = m_cellp->name() + "__DOT__" + nodep->name(); if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name); if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); } if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); } // Iterate won't hit AstIfaceRefDType directly as it is no longer underneath the module if (AstIfaceRefDType* ifacerefp = nodep->dtypep()->castIfaceRefDType()) { // Relink to point to newly cloned cell if (ifacerefp->cellp()) { if (AstCell* newcellp = ifacerefp->cellp()->user4p()->castNode()->castCell()) { ifacerefp->cellp(newcellp); ifacerefp->cellName(newcellp->name()); } } } nodep->iterateChildren(*this); }
// VISITORS virtual void visit(AstCellInline* nodep, AstNUser*) { // Inlined cell under the inline cell, need to move to avoid conflicts nodep->unlinkFrBack(); m_modp->addInlinesp(nodep); // Rename string name = m_cellp->name() + "__DOT__" + nodep->name(); nodep->name(name); UINFO(6, " Inline "<<nodep<<endl); // Do CellInlines under this, but don't move them nodep->iterateChildren(*this); }
virtual void visit(AstNodeModule* nodep, AstNUser*) { // Create required blocks and add to module string scopename; if (!m_aboveScopep) scopename = "TOP"; else scopename = m_aboveScopep->name()+"."+m_aboveCellp->name(); UINFO(4," MOD AT "<<scopename<<" "<<nodep<<endl); AstNode::user1ClearTree(); m_scopep = new AstScope((m_aboveCellp?(AstNode*)m_aboveCellp:(AstNode*)nodep)->fileline(), nodep, scopename, m_aboveScopep, m_aboveCellp); // Now for each child cell, iterate the module this cell points to for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp=cellnextp->nextp()) { if (AstCell* cellp = cellnextp->castCell()) { AstScope* oldScopep = m_scopep; AstCell* oldAbCellp = m_aboveCellp; AstScope* oldAbScopep = m_aboveScopep; { m_aboveCellp = cellp; m_aboveScopep = m_scopep; AstNodeModule* modp = cellp->modp(); if (!modp) cellp->v3fatalSrc("Unlinked mod"); modp->accept(*this); // Recursive call to visit(AstNodeModule) } // Done, restore vars m_scopep = oldScopep; m_aboveCellp = oldAbCellp; m_aboveScopep = oldAbScopep; } } // Create scope for the current usage of this module UINFO(4," back AT "<<scopename<<" "<<nodep<<endl); AstNode::user1ClearTree(); m_modp = nodep; if (m_modp->isTop()) { AstTopScope* topscp = new AstTopScope(nodep->fileline(), m_scopep); m_modp->addStmtp(topscp); } else { m_modp->addStmtp(m_scopep); } // Copy blocks into this scope // If this is the first usage of the block ever, we can simply move the reference nodep->iterateChildren(*this); // ***Note m_scopep is passed back to the caller of the routine (above) }
virtual void visit(AstTypedef* nodep, AstNUser*) { // Typedef under the inline cell, need to rename to avoid conflicts nodep->name(m_cellp->name() + "__DOT__" + nodep->name()); nodep->iterateChildren(*this); }
virtual void visit(AstCell* nodep, AstNUser*) { // Cell under the inline cell, need to rename to avoid conflicts string name = m_cellp->name() + "__DOT__" + nodep->name(); nodep->name(name); nodep->iterateChildren(*this); }
virtual void visit(AstNodeFTask* nodep) { // Function under the inline cell, need to rename to avoid conflicts nodep->name(m_cellp->name() + "__DOT__" + nodep->name()); nodep->iterateChildren(*this); }