// 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(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; }
virtual void visit(AstCell* nodep, AstNUser*) { if (nodep->modp()->user1()) { // Marked with inline request UINFO(5," Inline CELL "<<nodep<<endl); UINFO(5," To MOD "<<m_modp<<endl); ++m_statCells; // Before cloning simplify pin assignments // Better off before, as if module has multiple instantiations // we'll save work, and we can't call pinReconnectSimple in // this loop as it clone()s itself. for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) { if (!pinp->exprp()) continue; V3Inst::pinReconnectSimple(pinp, nodep, m_modp, false); } // Clone original module if (debug()>=9) { nodep->dumpTree(cout,"inlcell:"); } //if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); } AstNodeModule* newmodp = nodep->modp()->cloneTree(false); if (debug()>=9) { newmodp->dumpTree(cout,"newmod:"); } // Clear var markings and find cell cross references AstNode::user2ClearTree(); AstNode::user4ClearTree(); { InlineCollectVisitor(nodep->modp()); } // {} to destroy visitor immediately // Create data for dotted variable resolution AstCellInline* inlinep = new AstCellInline(nodep->fileline(), nodep->name(), nodep->modp()->origName()); m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells // Create assignments to the pins for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) { if (!pinp->exprp()) continue; UINFO(6," Pin change from "<<pinp->modVarp()<<endl); // Make new signal; even though we'll optimize the interconnect, we // need an alias to trace correctly. If tracing is disabled, we'll // delete it in later optimizations. AstVar* pinOldVarp = pinp->modVarp(); AstVar* pinNewVarp = pinOldVarp->clonep()->castVar(); AstNode* connectRefp = pinp->exprp(); if (!connectRefp->castConst() && !connectRefp->castVarRef()) { pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n"); } if (pinNewVarp->isOutOnly() && connectRefp->castConst()) { pinp->v3error("Output port is connected to a constant pin, electrical short"); } // Propagate any attributes across the interconnect pinNewVarp->propagateAttrFrom(pinOldVarp); if (connectRefp->castVarRef()) { connectRefp->castVarRef()->varp()->propagateAttrFrom(pinOldVarp); } // One to one interconnect won't make a temporary variable. // This prevents creating a lot of extra wires for clock signals. // It will become a tracing alias. UINFO(6,"One-to-one "<<connectRefp<<endl); UINFO(6," -to "<<pinNewVarp<<endl); pinNewVarp->user2p(connectRefp); // Public output inside the cell must go via an assign rather than alias // Else the public logic will set the alias, loosing the value to be propagated up // (InOnly isn't a problem as the AssignAlias will create the assignment for us) pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly()); } // Cleanup var names, etc, to not conflict { InlineRelinkVisitor(newmodp, m_modp, nodep); } // Move statements to top module if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); } AstNode* stmtsp = newmodp->stmtsp(); if (stmtsp) stmtsp->unlinkFrBackWithNext(); if (stmtsp) m_modp->addStmtp(stmtsp); // Remove the cell newmodp->deleteTree(); newmodp=NULL; // Clear any leftover ports, etc nodep->unlinkFrBack(); pushDeletep(nodep); nodep = NULL; if (debug()>=9) { m_modp->dumpTree(cout,"donemod:"); } } }