Exemple #1
0
    AstVar* createEnableVar(AstNode* outp, AstVarRef* outrefp, AstNode* enrhsp, int width, string suffix="") {
	// this function creates an  __en Var that corresponds to
	// the outp and outrefp and creates an assignw to enrhsp
        AstVar* enp = new AstVar (outrefp->varp()->fileline(),
				  AstVarType::MODULETEMP,
				  outrefp->name() + "__en" + suffix + cvtToStr(m_unique++),
				  AstLogicPacked(), width);
	enp->varType2Out();

	if (enp->width() != enrhsp->width()) {
	    if (enrhsp->width1()) { // it seems from my futzing that the linter guarantees this condition
		enrhsp = new AstReplicate(enrhsp->fileline(), enrhsp,
					  new AstConst(enrhsp->fileline(), V3Number(enrhsp->fileline(), 32, enp->width())));
		enrhsp->width(enp->width(), enp->width());  //minwidth==width
	    } else {
		enrhsp->v3error("Don't know how to deal with selection logic wider than 1 bit");
	    }
	}

	AstNode* newassp = new AstAssignW (enp->fileline(),
					   new AstVarRef (enp->fileline(), enp, true),
					   enrhsp);
	if (debug()>=9) enp->dumpTreeAndNext(cout,"-   cev-out: ");
	if (debug()>=9) newassp->dumpTreeAndNext(cout,"-   cev-out: ");
        m_modp->addStmtp(enp);
        m_modp->addStmtp(newassp);

	outrefp->user1p(enp); // put __en signal into varref for later usage
	outrefp->varp()->user1p(enp); // put __en signal into var as well in the event this is a single lhs driver and this needs passed up one level

	return enp;
    }
Exemple #2
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);
    }
Exemple #3
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)
    }
Exemple #4
0
    virtual void visit(AstRepeat* nodep, AstNUser*) {
	// So later optimizations don't need to deal with them,
	//    REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
	// Note var can be signed or unsigned based on original number.
	AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
   	string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
	// Spec says value is integral, if negative is ignored
	AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
				  nodep->findSigned32DType());
	varp->usedLoopIdx(true);
	m_modp->addStmtp(varp);
	AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
					countp);
	AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
				      new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
						 new AstConst(nodep->fileline(), 1)));
	V3Number zero (nodep->fileline(), 32, 0);  zero.isSigned(true);
	AstNode* zerosp = new AstConst(nodep->fileline(), zero);
	AstNode* condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
				    zerosp);
	AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
	AstNode* newp = new AstWhile(nodep->fileline(),
				     condp,
				     bodysp,
				     decp);
	initsp = initsp->addNext(newp);
	newp = initsp;
	nodep->replaceWith(newp);
	nodep->deleteTree(); VL_DANGLING(nodep);
    }
Exemple #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);
    }
    virtual void visit(AstUdpTable* nodep, AstNUser*) {
	UINFO(5,"UDPTABLE  "<<nodep<<endl);
	if (!v3Global.opt.bboxUnsup()) {
	    // We don't warn until V3Inst, so that UDPs that are in libraries and
	    // never used won't result in any warnings.
	} else {
	    // Massive hack, just tie off all outputs so our analysis can proceed
	    AstVar* varoutp = NULL;
	    for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
		if (AstVar* varp = stmtp->castVar()) {
		    if (varp->isInput()) {
		    } else if (varp->isOutput()) {
			if (varoutp) { varp->v3error("Multiple outputs not allowed in udp modules"); }
			varoutp = varp;
			// Tie off
			m_modp->addStmtp(new AstAssignW(varp->fileline(),
							new AstVarRef(varp->fileline(), varp, true),
							new AstConst(varp->fileline(), AstConst::LogicFalse())));
		    } else {
			varp->v3error("Only inputs and outputs are allowed in udp modules");
		    }
		}
	    }
	    nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
	}
    }
Exemple #7
0
    AstVarScope* getCreateLastClk(AstVarScope* vscp) {
	if (vscp->user1p()) return ((AstVarScope*)vscp->user1p());
	AstVar* varp = vscp->varp();
	if (!varp->width1()) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
	string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->name());
        AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1);
        newvarp->noReset(true);  // Reset by below assign
	m_modp->addStmtp(newvarp);
	AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
	vscp->user1p(newvscp);
	m_scopep->addVarp(newvscp);
        // Add init
        AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
        if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
        AstNode* newinitp = new AstAssign(vscp->fileline(),
                                          new AstVarRef(newvarp->fileline(), newvscp, true),
                                          fromp);
        addToInitial(newinitp);
	// At bottom, assign them
	AstAssign* finalp
            = new AstAssign(vscp->fileline(),
                            new AstVarRef(vscp->fileline(), newvscp, true),
                            new AstVarRef(vscp->fileline(), vscp, false));
	m_evalFuncp->addFinalsp(finalp);
	//
	UINFO(4,"New Last: "<<newvscp<<endl);
	return newvscp;
    }
Exemple #8
0
    virtual void visit(AstCFunc* nodep, AstNUser*) {
	if (!nodep->user1()) {
	    m_needThis = false;
	    nodep->iterateChildren(*this);
	    nodep->user1(true);
	    if (m_needThis) {
		nodep->v3fatalSrc("old code");
		// Really we should have more node types for backend optimization of this stuff
		string text = v3Global.opt.modPrefix() + "_" + m_modp->name()
		    +"* thisp = &("+m_scopep->nameVlSym()+");\n";
		nodep->addInitsp(new AstCStmt(nodep->fileline(), text));
	    }
	    // If it's under a scope, move it up to the top
	    if (m_scopep) {
		nodep->unlinkFrBack();
		m_modp->addStmtp(nodep);

		if (nodep->funcPublic()) {
		    // There may be multiple public functions by the same name;
		    // record for later correction or making of shells
		    m_modFuncs.insert(make_pair(nodep->name(), nodep));
		    nodep->name(m_scopep->nameDotless() +"__" + nodep->name());
		}
	    }
	}
    }
Exemple #9
0
    AstVarScope* createVarSc(AstVarScope* oldvarscp, string name, int width/*0==fromoldvar*/) {
	// Because we've already scoped it, we may need to add both the AstVar and the AstVarScope
	if (!oldvarscp->scopep()) oldvarscp->v3fatalSrc("Var unscoped");
	AstVar* varp;
	AstNodeModule* addmodp = oldvarscp->scopep()->modp();
	// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
	VarMap::iterator iter = m_modVarMap.find(make_pair(addmodp,name));
	if (iter != m_modVarMap.end()) {
	    // Created module's AstVar earlier under some other scope
	    varp = iter->second;
	} else {
	    if (width==0) {
		varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, oldvarscp->varp());
		varp->widthSignedFrom(oldvarscp);
	    } else { // Used for vset and dimensions, so can zero init
		varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, AstBitPacked(), width);
	    }
	    addmodp->addStmtp(varp);
	    m_modVarMap.insert(make_pair(make_pair(addmodp, name), varp));
	}

	AstVarScope* varscp = new AstVarScope (oldvarscp->fileline(), oldvarscp->scopep(), varp);
	oldvarscp->scopep()->addVarp(varscp);
	return varscp;
    }
    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 (m_unnamedScope != "") {
	    // Rename it
	    nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
	    // Move to module
	    nodep->unlinkFrBack();
	    if (m_ftaskp) m_ftaskp->addStmtsp(nodep);   // Begins under funcs just move into the func
	    else m_modp->addStmtp(nodep);
	}
    }
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);
	    }
	}
    }
}
    virtual void visit(AstCell* nodep, AstNUser*) {
	UINFO(8,"   CELL "<<nodep<<endl);
	if (m_namedScope != "") {
	    // Rename it
	    nodep->name(m_namedScope+"__DOT__"+nodep->name());
	    UINFO(8,"     rename to "<<nodep->name()<<endl);
	    // Move to module
	    nodep->unlinkFrBack();
	    m_modp->addStmtp(nodep);
	}
    }
Exemple #14
0
    AstVarScope* getCreateLocalVar(FileLine* fl, const string& name, AstVar* examplep, int width) {
	AstVar* newvarp;
	if (width) {
	    newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, VFlagLogicPacked(), width);
	} else {
	    newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, examplep); // No range; 1 bit.
	}
	m_modp->addStmtp(newvarp);
	AstVarScope* newvscp = new AstVarScope(fl, m_scopep, newvarp);
	m_scopep->addVarp(newvscp);
	return newvscp;
    }
Exemple #15
0
    void walkReplace(AstNode* node1p, AstNode* node2p,
		     AstNode* last1p, AstNode* last2p) {  // Final node in linked list, maybe null if all statements to be grabbed
	// Make new function
	string oldname = m_funcp->name();
	string::size_type pos;
	if ((pos=oldname.find("_common")) != string::npos) {
	    oldname.erase(pos);
	}
	if ((pos=oldname.find("__")) != string::npos) {
	    oldname.erase(pos);
	}
	AstCFunc* newfuncp = new AstCFunc(node1p->fileline(),
					  oldname+"_common"+cvtToStr(++m_modNFuncs),
					  NULL);
	m_modp->addStmtp(newfuncp);
	// Create calls
	AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp);
	AstCCall* call2p = new AstCCall(node2p->fileline(), newfuncp);
	// Grab statement bodies
	AstNRelinker relink1Handle;
	AstNRelinker relink2Handle;
	for (AstNode* nextp, *walkp = node1p; 1; walkp = nextp) {
	    nextp = walkp->nextp();
	    if (walkp==node1p) 	walkp->unlinkFrBack(&relink1Handle);
	    else { walkp->unlinkFrBack(); node1p->addNext(walkp); }
	    if (walkp==last1p) break;
	}
	for (AstNode* nextp, *walkp = node2p; 1; walkp = nextp) {
	    nextp = walkp->nextp();
	    if (walkp==node2p) 	walkp->unlinkFrBack(&relink2Handle);
	    else { walkp->unlinkFrBack(); node2p->addNext(walkp); }
	    if (walkp==last2p) break;
	}
	// Move node1 statements to new function
	newfuncp->addStmtsp(node1p);
	//newfuncp->dumpTree(cout," newfunctree: ");
	// Mark node2 statements as dead
	CombMarkVisitor visitor(node2p);
	pushDeletep(node2p);	// Delete later
	// Link in new function
	relink1Handle.relink(call1p);
	relink2Handle.relink(call2p);
	// Hash the new function
	hashFunctions(newfuncp);
	m_call.addCall(call1p);
	m_call.addCall(call2p);
	// If either new statement makes a func with only a single call, replace
	// the above callers to call it directly
	replaceOnlyCallFunc(call1p); VL_DANGLING(call1p);
	replaceOnlyCallFunc(call2p); VL_DANGLING(call2p);
    }
Exemple #16
0
    void genChangeDet(AstVarScope* vscp) {
#ifdef NEW_ORDERING
	vscp->v3fatalSrc("Not applicable\n");
#endif
	AstVar* varp = vscp->varp();
	vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
	AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
	AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
	bool isArray = arrayp;
	bool isStruct = structp && structp->packedUnsup();
	int elements = isArray ? arrayp->elementsConst() : 1;
	if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
	    vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
			 <<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()<<endl
			 <<vscp->warnMore()
			 <<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(elements));
	} else if (!isArray && !isStruct
		   && !varp->dtypeSkipRefp()->castBasicDType()) {
	    if (debug()) varp->dumpTree(cout,"-DETECTARRAY-");
	    vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
	} else {
	    string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();
	    // Create:  VARREF(_last)
	    //          ASSIGN(VARREF(_last), VARREF(var))
	    //          ...
	    //          CHANGEDET(VARREF(_last), VARREF(var))
	    AstVar* newvarp = new AstVar (varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
	    m_topModp->addStmtp(newvarp);
	    AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
	    m_scopetopp->addVarp(newvscp);
	    for (int index=0; index<elements; ++index) {
		AstChangeDet* changep
		    = new AstChangeDet (vscp->fileline(),
					aselIfNeeded(isArray, index,
						     new AstVarRef(vscp->fileline(), vscp, false)),
					aselIfNeeded(isArray, index,
						     new AstVarRef(vscp->fileline(), newvscp, false)),
					false);
		m_chgFuncp->addStmtsp(changep);
		AstAssign* initp
		    = new AstAssign (vscp->fileline(),
				     aselIfNeeded(isArray, index,
						  new AstVarRef(vscp->fileline(), newvscp, true)),
				     aselIfNeeded(isArray, index,
						  new AstVarRef(vscp->fileline(), vscp, false)));
		m_chgFuncp->addFinalsp(initp);
	    }
	}
    }
Exemple #17
0
    virtual void visit(AstVar* nodep, AstNUser*) {
	if (m_state == CONVERT_VARS) {
	    if (nodep->isTristate() && !m_ftaskp) {
		// create the input var and leave the original as the output var
		AstVar* varinp = nodep->cloneTree(false)->castVar();
		varinp->name(varinp->name() + "__in");
		varinp->varType2In();

		nodep->combineType(AstVarType::OUTPUT);
		nodep->varType2Out();
		m_modp->addStmtp(varinp);
		nodep->user1p(varinp);
	    }
	}
    }
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);
	}
    }
}
Exemple #19
0
    AstCFunc* createDeepFunc(AstNode* nodep) {
	AstNRelinker relinkHandle;
	nodep->unlinkFrBack(&relinkHandle);
	// Create function
	string name = m_funcp->name()+"__deep"+cvtToStr(++m_deepNum);
	AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, NULL);
	funcp->argTypes(EmitCBaseVisitor::symClassVar());
	funcp->symProlog(true);
	funcp->slow(m_funcp->slow());
	funcp->addStmtsp(nodep);
	m_modp->addStmtp(funcp);
	// Call it at the point where the body was removed from
	AstCCall* callp = new AstCCall(nodep->fileline(), funcp);
	callp->argTypes("vlSymsp");
	UINFO(6,"      New "<<callp<<endl);
	//
	relinkHandle.relink(callp);
	return funcp;
    }
    virtual void visit(AstBind* nodep, AstNUser*) {
	// Bind: Has cells underneath that need to be put into the new module, and cells which need resolution
	// TODO this doesn't allow bind to dotted hier names, that would require
	// this move to post param, which would mean we do not auto-read modules
	// and means we cannot compute module levels until later.
	UINFO(4,"Link Bind: "<<nodep<<endl);
	AstNodeModule* modp = resolveModule(nodep,nodep->name());
	if (modp) {
	    AstNode* cellsp = nodep->cellsp()->unlinkFrBackWithNext();
	    // Module may have already linked, so need to pick up these new cells
	    AstNodeModule* oldModp = m_modp;
	    {
		m_modp = modp;
		modp->addStmtp(cellsp);  // Important that this adds to end, as next iterate assumes does all cells
		cellsp->iterateAndNext(*this);
	    }
	    m_modp = oldModp;
	}
	pushDeletep(nodep->unlinkFrBack());
    }
Exemple #21
0
    // METHODS
    AstVarScope* genInpClk(AstVarScope* vscp) {
	if (vscp->user2p()) {
            return VN_CAST(vscp->user2p(), VarScope);
	} else {
	    AstVar* varp = vscp->varp();
	    string newvarname = "__VinpClk__"+vscp->scopep()->nameDotless()+"__"+varp->name();
	    // Create:  VARREF(inpclk)
	    //          ...
	    //          ASSIGN(VARREF(inpclk), VARREF(var))
            AstVar* newvarp = new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
	    m_topModp->addStmtp(newvarp);
	    AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
	    m_scopetopp->addVarp(newvscp);
            AstAssign* asninitp = new AstAssign(vscp->fileline(),
                                                new AstVarRef(vscp->fileline(), newvscp, true),
                                                new AstVarRef(vscp->fileline(), vscp, false));
	    m_scopetopp->addFinalClkp(asninitp);
	    //
	    vscp->user2p(newvscp);
	    return newvscp;
	}
    }
Exemple #22
0
    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:"); }
	}
    }
    virtual void visit(AstConst* nodep) {
	if (m_constXCvt
	    && nodep->num().isFourState()) {
	    UINFO(4," CONST4 "<<nodep<<endl);
	    if (debug()>=9) nodep->dumpTree(cout,"  Const_old: ");
	    // CONST(num) -> VARREF(newvarp)
	    //		-> VAR(newvarp)
	    //		-> INITIAL(VARREF(newvarp, OR(num_No_Xs,AND(random,num_1s_Where_X))
	    V3Number numb1 (nodep->fileline(), nodep->width());
	    numb1.opBitsOne(nodep->num());
	    V3Number numbx (nodep->fileline(), nodep->width());
	    numbx.opBitsXZ(nodep->num());
	    if (v3Global.opt.xAssign()!="unique") {
		// All X bits just become 0; fastest simulation, but not nice
		V3Number numnew (nodep->fileline(), numb1.width());
		if (v3Global.opt.xAssign()=="1") {
		    numnew.opOr(numb1, numbx);
		} else {
		    numnew.opAssign(numb1);
		}
		AstConst* newp = new AstConst(nodep->fileline(), numnew);
		nodep->replaceWith(newp);
		nodep->deleteTree(); VL_DANGLING(nodep);
		UINFO(4,"   -> "<<newp<<endl);
	    } else {
		// Make a Vxrand variable
		// We use the special XTEMP type so it doesn't break pure functions
		if (!m_modp) nodep->v3fatalSrc("X number not under module");
		string newvarname = ((string)"__Vxrand"
				     +cvtToStr(m_modp->varNumGetInc()));
		AstVar* newvarp
		    = new AstVar (nodep->fileline(), AstVarType::XTEMP, newvarname,
				  VFlagLogicPacked(), nodep->width());
		++m_statUnkVars;
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false);
		replaceHandle.relink(newref1p);	    // Replace const with varref
		AstInitial* newinitp
		    = new AstInitial(
			nodep->fileline(),
			new AstAssign(
			    nodep->fileline(),
			    new AstVarRef(nodep->fileline(), newvarp, true),
			    new AstOr(nodep->fileline(),
				      new AstConst(nodep->fileline(),numb1),
				      new AstAnd(nodep->fileline(),
						 new AstConst(nodep->fileline(),numbx),
						 new AstRand(nodep->fileline(),
							     nodep->dtypep(), true)))));
		// Add inits in front of other statement.
		// In the future, we should stuff the initp into the module's constructor.
		AstNode* afterp = m_modp->stmtsp()->unlinkFrBackWithNext();
		m_modp->addStmtp(newvarp);
		m_modp->addStmtp(newinitp);
		m_modp->addStmtp(afterp);
		if (debug()>=9) newref1p->dumpTree(cout,"     _new: ");
		if (debug()>=9) newvarp->dumpTree(cout,"     _new: ");
		if (debug()>=9) newinitp->dumpTree(cout,"     _new: ");
		nodep->deleteTree(); VL_DANGLING(nodep);
	    }
	}
    }
    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
	}
    }