Example #1
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);
	    }
	}
    }
void ParamVisitor::visitCell(AstCell* nodep) {
    // Cell: Check for parameters in the instantiation.
    nodep->iterateChildren(*this);
    if (!nodep->modp()) nodep->v3fatalSrc("Not linked?");
    if (nodep->paramsp()
	|| 1  // Need to look for interfaces; could track when one exists, but should be harmless to always do this
	) {
	UINFO(4,"De-parameterize: "<<nodep<<endl);
	// Create new module name with _'s between the constants
	if (debug()>=10) nodep->dumpTree(cout,"-cell:\t");
	// Evaluate all module constants
	V3Const::constifyParamsEdit(nodep);

	// Make sure constification worked
	// Must be a separate loop, as constant conversion may have changed some pointers.
	//if (debug()) nodep->dumpTree(cout,"-cel2:\t");
	string longname = nodep->modp()->name();
	bool any_overrides = false;
	longname += "_";
	if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout,"-cellparams:\t");
	for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
	    if (!pinp->exprp()) continue; // No-connect
	    AstVar* modvarp = pinp->modVarp();
	    if (!modvarp) {
		pinp->v3error("Parameter not found in sub-module: Param "<<pinp->name()<<" of "<<nodep->prettyName());
	    } else if (!modvarp->isGParam()) {
		pinp->v3error("Attempted parameter setting of non-parameter: Param "<<pinp->name()<<" of "<<nodep->prettyName());
	    } else {
		AstConst* constp = pinp->exprp()->castConst();
		AstConst* origconstp = modvarp->valuep()->castConst();
		if (!constp) {
		    //if (debug()) pinp->dumpTree(cout,"error:");
		    pinp->v3error("Can't convert defparam value to constant: Param "<<pinp->name()<<" of "<<nodep->prettyName());
		    pinp->exprp()->replaceWith(new AstConst(pinp->fileline(), V3Number(pinp->fileline(), modvarp->width(), 0)));
		} else if (origconstp && constp->sameTree(origconstp)) {
		    // Setting parameter to its default value.  Just ignore it.
		    // This prevents making additional modules, and makes coverage more
		    // obvious as it won't show up under a unique module page name.
		} else {
		    longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+constp->num().ascii(false);
		    any_overrides = true;
		}
	    }
	}
	IfaceRefRefs ifaceRefRefs;
	for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
	    AstVar* modvarp = pinp->modVarp();
	    if (modvarp->isIfaceRef()) {
		AstIfaceRefDType* portIrefp = modvarp->subDTypep()->castIfaceRefDType();
		//UINFO(9,"     portIfaceRef "<<portIrefp<<endl);
		if (!pinp->exprp()
		    || !pinp->exprp()->castVarRef()
		    || !pinp->exprp()->castVarRef()->varp()
		    || !pinp->exprp()->castVarRef()->varp()->subDTypep()
		    || !pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType()) {
		    pinp->v3error("Interface port '"<<modvarp->prettyName()<<"' is not connected to interface/modport pin expression");
		} else {
		    AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType();
		    //UINFO(9,"     pinIfaceRef "<<pinIrefp<<endl);
		    if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
			UINFO(9,"     IfaceRefDType needs reconnect  "<<pinIrefp<<endl);
			longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+paramValueNumber(pinIrefp);
			any_overrides = true;
			ifaceRefRefs.push_back(make_pair(portIrefp,pinIrefp));
		    }
		}
	    }
	}

	if (!any_overrides) {
	    UINFO(8,"Cell parameters all match original values, skipping expansion.\n");
	} else {
	    // If the name is very long, we don't want to overwhelm the filename limit
	    // We don't do this always, as it aids debugability to have intuitive naming.
	    // TODO can use new V3Name hash replacement instead of this
	    string newname = longname;
	    if (longname.length()>30) {
		LongMap::iterator iter = m_longMap.find(longname);
		if (iter != m_longMap.end()) {
		    newname = iter->second;
		} else {
		    newname = nodep->modp()->name();
		    newname += "__pi"+cvtToStr(++m_longId);  // We use all upper case above, so lower here can't conflict
		    m_longMap.insert(make_pair(longname, newname));
		}
	    }
	    UINFO(4,"Name: "<<nodep->modp()->name()<<"->"<<longname<<"->"<<newname<<endl);

	    //
	    // Already made this flavor?
	    AstNodeModule* modp = NULL;
	    ModNameMap::iterator iter = m_modNameMap.find(newname);
	    if (iter != m_modNameMap.end()) modp = iter->second.m_modp;
	    if (!modp) {
		// Deep clone of new module
		// Note all module internal variables will be re-linked to the new modules by clone
		// However links outside the module (like on the upper cells) will not.
		modp = nodep->modp()->cloneTree(false);
		modp->name(newname);
		modp->user5(false); // We need to re-recurse this module once changed
		nodep->modp()->addNextHere(modp);  // Keep tree sorted by cell occurrences

		m_modNameMap.insert(make_pair(modp->name(), ModInfo(modp)));
		iter = m_modNameMap.find(newname);
		VarCloneMap* clonemapp = &(iter->second.m_cloneMap);
		UINFO(4,"     De-parameterize to new: "<<modp<<endl);

		// Grab all I/O so we can remap our pins later
		// Note we allow multiple users of a parameterized model, thus we need to stash this info.
		for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
		    if (AstVar* varp = stmtp->castVar()) {
			if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
			    // Cloning saved a pointer to the new node for us, so just follow that link.
			    AstVar* oldvarp = varp->clonep()->castVar();
			    //UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl);
			    clonemapp->insert(make_pair(oldvarp, varp));
			}
		    }
		}

		// Relink parameter vars to the new module
		relinkPins(clonemapp, nodep->paramsp());

		// Fix any interface references
		for (IfaceRefRefs::iterator it=ifaceRefRefs.begin(); it!=ifaceRefRefs.end(); ++it) {
		    AstIfaceRefDType* portIrefp = it->first;
		    AstIfaceRefDType* pinIrefp = it->second;
		    AstIfaceRefDType* cloneIrefp = portIrefp->clonep()->castIfaceRefDType();
		    UINFO(8,"     IfaceOld "<<portIrefp<<endl);
		    UINFO(8,"     IfaceTo  "<<pinIrefp<<endl);
		    if (!cloneIrefp) portIrefp->v3fatalSrc("parameter clone didn't hit AstIfaceRefDType");
		    UINFO(8,"     IfaceClo "<<cloneIrefp<<endl);
		    cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
		    UINFO(8,"     IfaceNew "<<cloneIrefp<<endl);
		}

		// Assign parameters to the constants specified
		// DOES clone() so must be finished with module clonep() before here
		for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
		    AstVar* modvarp = pinp->modVarp();
		    if (modvarp && pinp->exprp()) {
			AstConst* constp = pinp->exprp()->castConst();
			// Remove any existing parameter
			if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree();
			// Set this parameter to value requested by cell
			modvarp->valuep(constp->cloneTree(false));
		    }
		}
	    } else {
		UINFO(4,"     De-parameterize to old: "<<modp<<endl);
	    }

	    // Have child use this module instead.
	    nodep->modp(modp);
	    nodep->modName(newname);

	    // We need to relink the pins to the new module
	    VarCloneMap* clonemapp = &(iter->second.m_cloneMap);
	    relinkPins(clonemapp, nodep->pinsp());
	    UINFO(8,"     Done with "<<modp<<endl);
	} // if any_overrides

	// Delete the parameters from the cell; they're not relevant any longer.
	if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
	UINFO(8,"     Done with "<<nodep<<endl);
	//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
    }

    // Now remember to process the child module at the end of the module
    m_todoModps.insert(make_pair(nodep->modp()->level(),nodep->modp()));
}
 void reportViolations() {
     // Combine bits into overall state
     AstVar* nodep = m_varp;
     if (!nodep->isParam() && !nodep->isGenVar()) {
         bool allU=true;
         bool allD=true;
         bool anyU=m_usedWhole;
         bool anyD=m_drivenWhole;
         bool anyUnotD=false;
         bool anyDnotU=false;
         bool anynotDU=false;
         for (unsigned bit=0; bit<m_flags.size()/FLAGS_PER_BIT; bit++) {
             bool used = usedFlag(bit);
             bool driv = drivenFlag(bit);
             allU &= used;
             anyU |= used;
             allD &= driv;
             anyD |= driv;
             anyUnotD |= used && !driv;
             anyDnotU |= !used && driv;
             anynotDU |= !used && !driv;
         }
         if (allU) m_usedWhole = true;
         if (allD) m_drivenWhole = true;
         // Test results
         if (allU && allD) {
             // It's fine
         } else if (!anyD && !anyU) {
             // UNDRIVEN is considered more serious - as is more likely a bug,
             // thus undriven+unused bits get UNUSED warnings, as they're not as buggy.
             if (!unusedMatch(nodep)) {
                 nodep->v3warn(UNUSED, "Signal is not driven, nor used: "<<nodep->prettyName());
                 nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);  // Warn only once
             }
         } else if (allD && !anyU) {
             if (!unusedMatch(nodep)) {
                 nodep->v3warn(UNUSED, "Signal is not used: "<<nodep->prettyName());
                 nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);  // Warn only once
             }
         } else if (!anyD && allU) {
             nodep->v3warn(UNDRIVEN, "Signal is not driven: "<<nodep->prettyName());
             nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true);  // Warn only once
         } else {
             // Bits have different dispositions
             bool setU=false;
             bool setD=false;
             if (anynotDU && !unusedMatch(nodep)) {
                 nodep->v3warn(UNUSED, "Bits of signal are not driven, nor used: "<<nodep->prettyName()
                               <<bitNames(BN_BOTH));
                 setU=true;
             }
             if (anyDnotU && !unusedMatch(nodep)) {
                 nodep->v3warn(UNUSED, "Bits of signal are not used: "<<nodep->prettyName()
                               <<bitNames(BN_UNUSED));
                 setU=true;
             }
             if (anyUnotD) {
                 nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<<nodep->prettyName()
                               <<bitNames(BN_UNDRIVEN));
                 setD=true;
             }
             if (setU) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);  // Warn only once
             if (setD) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true);  // Warn only once
         }
     }
 }
Example #4
0
    bool forUnrollCheck(AstNode* nodep,
			AstNode* initp,	// Maybe under nodep (no nextp), or standalone (ignore nextp)
			AstNode* precondsp, AstNode* condp,
			AstNode* incp,		// Maybe under nodep or in bodysp
			AstNode* bodysp) {
	// To keep the IF levels low, we return as each test fails.
	UINFO(4, " FOR Check "<<nodep<<endl);
	if (initp)	UINFO(6, "    Init "<<initp<<endl);
	if (precondsp)	UINFO(6, "    Pcon "<<precondsp<<endl);
	if (condp)	UINFO(6, "    Cond "<<condp<<endl);
	if (incp)	UINFO(6, "    Inc  "<<incp<<endl);

	// Initial value check
	AstAssign* initAssp = initp->castAssign();
	if (!initAssp) return cantUnroll(nodep, "no initial assignment");
	if (initp->nextp() && initp->nextp()!=nodep) nodep->v3fatalSrc("initial assignment shouldn't be a list");
	if (!initAssp->lhsp()->castVarRef()) return cantUnroll(nodep, "no initial assignment to simple variable");
	//
	// Condition check
	if (condp->nextp()) nodep->v3fatalSrc("conditional shouldn't be a list");
	//
	// Assignment of next value check
	AstAssign* incAssp = incp->castAssign();
	if (!incAssp) return cantUnroll(nodep, "no increment assignment");
	if (incAssp->nextp()) nodep->v3fatalSrc("increment shouldn't be a list");

	m_forVarp = initAssp->lhsp()->castVarRef()->varp();
	m_forVscp = initAssp->lhsp()->castVarRef()->varScopep();
	if (nodep->castGenFor() && !m_forVarp->isGenVar()) {
	    nodep->v3error("Non-genvar used in generate for: "<<m_forVarp->prettyName()<<endl);
	}
	if (m_generate) V3Const::constifyParamsEdit(initAssp->rhsp());  // rhsp may change

	// This check shouldn't be needed when using V3Simulate
	// however, for repeat loops, the loop variable is auto-generated
	// and the initp statements will reference a variable outside of the initp scope
	// alas, failing to simulate.
	AstConst* constInitp = initAssp->rhsp()->castConst();
	if (!constInitp) return cantUnroll(nodep, "non-constant initializer");

	//
	// Now, make sure there's no assignment to this variable in the loop
	m_varModeCheck = true;
	m_varAssignHit = false;
	m_ignoreIncp = incp;
	precondsp->iterateAndNext(*this);
	bodysp->iterateAndNext(*this);
	incp->iterateAndNext(*this);
	m_varModeCheck = false;
	m_ignoreIncp = NULL;
	if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");

	//
	if (m_forVscp) { UINFO(8, "   Loop Variable: "<<m_forVscp<<endl); }
	else	       { UINFO(8, "   Loop Variable: "<<m_forVarp<<endl); }
	if (debug()>=9) nodep->dumpTree(cout,"-   for: ");


	if (!m_generate) {
	    AstAssign *incpAssign = incp->castAssign();
	    if (!canSimulate(incpAssign->rhsp())) return cantUnroll(incp, "Unable to simulate increment");
	    if (!canSimulate(condp)) return cantUnroll(condp, "Unable to simulate condition");

	    // Check whether to we actually want to try and unroll.
	    int loops;
	    if (!countLoops(initAssp, condp, incp, unrollCount(), loops))
		return cantUnroll(nodep, "Unable to simulate loop");

	    // Less than 10 statements in the body?
	    int bodySize = 0;
	    int bodyLimit = v3Global.opt.unrollStmts();
	    if (loops>0) bodyLimit = v3Global.opt.unrollStmts() / loops;
	    if (bodySizeOverRecurse(precondsp, bodySize/*ref*/, bodyLimit)
		|| bodySizeOverRecurse(bodysp, bodySize/*ref*/, bodyLimit)
		|| bodySizeOverRecurse(incp, bodySize/*ref*/, bodyLimit)) {
		return cantUnroll(nodep, "too many statements");
	    }
	}
	// Finally, we can do it
	if (!forUnroller(nodep, initAssp, condp, precondsp, incp, bodysp)) {
	    return cantUnroll(nodep, "Unable to unroll loop");
	}
	VL_DANGLING(nodep);
	// Cleanup
	return true;
    }
Example #5
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;
    }