Beispiel #1
0
    void warnAlwCombOrder(AstVarRef* nodep) {
	AstVar* varp = nodep->varp();
	if (!varp->isParam() && !varp->isGenVar() && !varp->isUsedLoopIdx()
	    && !varp->fileline()->warnIsOff(V3ErrorCode::ALWCOMBORDER)) {  // Warn only once per variable
	    nodep->v3warn(ALWCOMBORDER, "Always_comb variable driven after use: "<<nodep->prettyName());
	    varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, true);  // Complain just once for any usage
	}
    }
 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
         }
     }
 }
Beispiel #3
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;
    }
    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");
	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->name()<<endl);
	}
	if (m_generate) V3Const::constifyParamsEdit(initAssp->rhsp());  // rhsp may change
	AstConst* constInitp = initAssp->rhsp()->castConst();
	if (!constInitp) return cantUnroll(nodep, "non-constant initializer");
	//
	// 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");
	AstNodeBiop* incInstrp = incAssp->rhsp()->castNodeBiop();
	//
	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: ");
	//
	// Extract the constant loop bounds
	bool subtract = incInstrp->castSub();
	{
	    if (!subtract && !incInstrp->castAdd()) return cantUnroll(nodep, "missing add/sub for incrementer");
	    AstVarRef* incVarrp   = (subtract ? incInstrp->lhsp()->castVarRef()
				     : incInstrp->rhsp()->castVarRef());
	    if (!incVarrp) return cantUnroll(nodep, "missing variable in incrementer");
	    if (incVarrp->varp() != m_forVarp
		|| incVarrp->varScopep() != m_forVscp) {
		return cantUnroll(nodep, "different variables in incrementer");
	    }
	}
	//
	// Adds have the # on the lhsp because V3Const pushes rhs consts over to the lhs
	// Subtracts have it on the rhs, because you write i=i-1; i=1-i is non-sensible.
	AstConst* preconstIncp = (subtract ? incInstrp->rhsp()->castConst()
				  : incInstrp->lhsp()->castConst());
	if (m_generate) preconstIncp = V3Const::constifyParamsEdit(preconstIncp)->castConst();
	AstConst* constIncp = (subtract ? incInstrp->rhsp()->castConst()
			       : incInstrp->lhsp()->castConst());
	UINFO(8, "   Inc expr ok:  "<<constIncp<<endl);
	if (!constIncp) return cantUnroll(nodep, "non-constant increment");
	if (constIncp->isZero()) return cantUnroll(nodep, "zero increment");  // Or we could loop forever below...

        bool lt  = condp->castLt() || condp->castLtS();
        bool lte = condp->castLte() || condp->castLteS();
	bool gt  = condp->castGt() || condp->castGtS();
	bool gte = condp->castGte() || condp->castGteS();
	if (!lt && !lte && !gt && !gte)
	    return cantUnroll(nodep, "condition not <= or <");
	AstNodeBiop* condBip = condp->castNodeBiop();
	if (!condBip->lhsp()->castVarRef())
	    return cantUnroll(nodep, "no variable on lhs of condition");
	if (condBip->lhsp()->castVarRef()->varp() != m_forVarp
	    || condBip->lhsp()->castVarRef()->varScopep() != m_forVscp)
	    return cantUnroll(nodep, "different variable in condition");
	if (m_generate) V3Const::constifyParamsEdit(condBip->rhsp());  // rhsp may change
	AstConst* constStopp = condBip->rhsp()->castConst();
	if (!constStopp) return cantUnroll(nodep, "non-constant final value");
	UINFO(8, "   Stop expr ok: "<<constStopp<<endl);
	//
	if (constInitp->width()>32 || constInitp->num().isFourState()
	    || constStopp->width()>32 || constStopp->num().isFourState()
	    || constIncp->width()>32  || constIncp->num().isFourState())
	    return cantUnroll(nodep, "init/final/increment too large or four state");
	vlsint32_t valInit = constInitp->num().toSInt();
	vlsint32_t valStop = constStopp->num().toSInt();
	if (lte) valStop++;  if (gte) valStop--;
	vlsint32_t valInc  = constIncp->num().toSInt();
	if (subtract) valInc = -valInc;
	UINFO(8,"     In Numbers: for (v="<<valInit<<"; v<"<<valStop<<"; v=v+"<<valInc<<")\n");
	//
	if (!m_generate) {
	    int loops = ((valStop - valInit)/valInc);
	    if (loops < 0) { loops += (1ULL<<constStopp->width()); } // Will roll around
	    UINFO(8, "         ~Iters: "<<loops<<" c="<<unrollCount()<<endl);
	    if (loops > unrollCount())
		return cantUnroll(nodep, "too many iterations");

	    // 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");
	    }
	}
	//
	// 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");
	//
	// Finally, we can do it
	forUnroller(nodep, initp, precondsp, condp, incp, bodysp,
		    constInitp->num(),
		    condBip, constStopp->num(),
		    incInstrp, constIncp->num()); nodep = NULL;
	// Cleanup
	return true;
    }