void visitModules() {
	// Loop on all modules left to process
	// Hitting a cell adds to the appropriate level of this level-sorted list,
	// so since cells originally exist top->bottom we process in top->bottom order too.
	while (!m_todoModps.empty()) {
	    LevelModMap::iterator it = m_todoModps.begin();
	    AstNodeModule* nodep = it->second;
	    m_todoModps.erase(it);
	    if (!nodep->user5SetOnce()) {  // Process once; note clone() must clear so we do it again
		UINFO(4," MOD   "<<nodep<<endl);
		nodep->iterateChildren(*this);
		// Note above iterate may add to m_todoModps
		//
		// Process interface cells, then non-interface which may ref an interface cell
		for (int nonIf=0; nonIf<2; ++nonIf) {
		    for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
			AstCell* nodep = *it;
			if ((nonIf==0 && nodep->modp()->castIface())
			    || (nonIf==1 && !nodep->modp()->castIface())) {
			    visitCell(nodep);
			}
		    }
		}
		m_cellps.clear();
	    }
	}
    }
Esempio n. 2
0
    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);
 }
    // 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;
	}
    }
Esempio n. 5
0
    virtual void visit(AstPin* nodep, AstNUser*) {
	// Check to see if any output pins have __en pins and create the __en pins to match
	AstVarRef* refp = findVarRef(nodep);

	if (refp && refp->lvalue() && nodep->modVarp()->user1p()) {
	    AstVar* enchildp = (AstVar*)nodep->modVarp()->user1p();
	    UINFO(9, "       Pulling __en var" << enchildp << endl);
	    AstVar* enp = new AstVar(enchildp->fileline(),
				     AstVarType::OUTPUT,
				     enchildp->name()+cvtToStr(m_unique++),
				     enchildp);
	    enp->user2(enchildp->user2());
	    m_modp->addStmtp(enp);
	    AstPin* pinp = new AstPin(nodep->fileline(),
				      nodep->pinNum(),
				      enp->name(),
				      new AstVarRef(nodep->fileline(), enp, true));
	    AstVarRef *rp = findVarRef(pinp);
	    rp->replaceWith(new AstVarRef(nodep->fileline(), enp, true));
	    rp->deleteTree(); rp=NULL;
	    pinp->width(enp->width(),enp->width());  // minwidth==width
	    pinp->modVarp(enchildp);
	    m_cellp->addPinsp(pinp);
	    refp->user1p(enp);
	    refp->varp()->user1p(enp);
	}
	// Simplify interconnect in preperation for V3Inst
	// (This could be a separate visitor, but we're in the neighborhood)
	V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
    }
Esempio n. 6
0
    virtual void visit(AstCoverDecl* nodep, AstNUser*) {
	// Fix path in coverage statements
	nodep->hier(m_cellp->prettyName()
		    + (nodep->hier()!="" ? ".":"")
		    + nodep->hier());
	nodep->iterateChildren(*this);
    }
Esempio n. 7
0
    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;
    }
Esempio n. 9
0
    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);
    }
Esempio n. 10
0
void V3LinkLevel::wrapTopPackages(AstNetlist* netlistp) {
    // Instantiate all packages under the top wrapper
    // This way all later SCOPE based optimizations can ignore packages
    AstNodeModule* newmodp = netlistp->modulesp();
    if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
    for (AstNodeModule* modp = netlistp->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
	if (modp->castPackage()) {
	    AstCell* cellp = new AstCell(modp->fileline(),
					 // Could add __03a__03a="::" to prevent conflict
					 // with module names/"v"
					 modp->name(),
					 modp->name(),
					 NULL, NULL, NULL);
	    cellp->modp(modp);
	    newmodp->addStmtp(cellp);
	}
    }
}
Esempio n. 11
0
void V3LinkLevel::wrapTopCell(AstNetlist* netlistp) {
    AstNodeModule* newmodp = netlistp->modulesp();
    if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
    AstNodeModule* oldmodp = newmodp->nextp()->castNodeModule();
    if (!oldmodp) netlistp->v3fatalSrc("No module found to process");

    // Add instance
    AstCell* cellp = new AstCell(newmodp->fileline(),
				 ((v3Global.opt.l2Name()!="") ? v3Global.opt.l2Name() : oldmodp->name()),
				 oldmodp->name(),
				 NULL, NULL, NULL);
    cellp->modp(oldmodp);
    newmodp->addStmtp(cellp);

    // Add pins
    for (AstNode* subnodep=oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
	if (AstVar* oldvarp=subnodep->castVar()) {
	    UINFO(8,"VARWRAP "<<oldvarp<<endl);
	    if (oldvarp->isIO()) {
		AstVar* varp = oldvarp->cloneTree(false);
		newmodp->addStmtp(varp);
		varp->sigPublic(true);	// User needs to be able to get to it...
		if (oldvarp->isIO()) {
		    oldvarp->primaryIO(true);
		    varp->primaryIO(true);
		}
		if (varp->isIO() && v3Global.opt.systemC()) {
		    varp->sc(true);
		    // User can see trace one level down from the wrapper
		    // Avoids packing & unpacking SC signals a second time
		    varp->trace(false);
		}

		AstPin* pinp = new AstPin(oldvarp->fileline(),0,oldvarp->name(),
					  new AstVarRef(varp->fileline(),
							varp, oldvarp->isOutput()));
		// Skip length and width comp; we know it's a direct assignment
		pinp->modVarp(oldvarp);
		cellp->addPinsp(pinp);
	    }
	}
    }
}
Esempio n. 12
0
    // 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);
    }
Esempio n. 13
0
    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)
    }
Esempio n. 14
0
    virtual void visit(AstPin* nodep, AstNUser*) {
	if (m_state == CONVERT_PINS) {
	    if (nodep->modVarp()->user1p()) {
		// create the input pin
		AstVarRef* refp = nodep->exprp()->castVarRef();
		if (!refp) nodep->v3fatal("Unsupported: Tristate pin not connected to simple net");
		AstVar* inp;
		if (refp->varp()->user1p()) { // this is a tristate
		    inp = (AstVar*) refp->varp()->user1p();
		} else {
		    inp = refp->varp();
		}
		AstPin* pinp = new AstPin(nodep->fileline(),
					  nodep->pinNum(),
					  nodep->name() + "__in",
					  new AstVarRef(nodep->fileline(), inp, false));
		m_cellp->addPinsp(pinp);

		// now link it
		pinp->modVarp((AstVar*) nodep->modVarp()->user1p());
	    }
	}
    }
Esempio n. 15
0
    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);
    }
Esempio n. 16
0
    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);
    }
Esempio n. 17
0
    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);
    }