Beispiel #1
0
    // VISITORS
    virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
	if (nodep->varScopep() == m_elimVarScp) {
	    // Substitute in the new tree
	    // It's possible we substitute into something that will be reduced more later
	    // however, as we never delete the top Always/initial statement, all should be well.
	    m_didReplace = true;
	    if (nodep->lvalue()) nodep->v3fatalSrc("Can't replace lvalue assignments with const var");
	    AstNode* substp = m_replaceTreep->cloneTree(false);
	    if (nodep->castNodeVarRef()
		&& substp->castNodeVarRef()
		&& nodep->same(substp)) {
		// Prevent a infinite loop...
		substp->v3fatalSrc("Replacing node with itself; perhaps circular logic?");
	    }
	    // Which fileline() to use?
	    // If replacing with logic, an error/warning is likely to want to point to the logic
	    // IE what we're replacing with.
	    // However a VARREF should point to the original as it's otherwise confusing
	    // to throw warnings that point to a PIN rather than where the pin us used.
	    if (substp->castVarRef()) substp->fileline(nodep->fileline());
	    // Make the substp an rvalue like nodep. This facilitate the hashing in dedupe.
	    if (AstNodeVarRef* varrefp = substp->castNodeVarRef()) varrefp->lvalue(false);
	    nodep->replaceWith(substp);
	    nodep->deleteTree(); VL_DANGLING(nodep);
	}
    }
Beispiel #2
0
    void visit(AstSel* nodep, AstNUser*) {
	nodep->iterateChildren(*this);
	if (!nodep->user1Inc()) {
	    // Guard against reading/writing past end of bit vector array
	    int maxmsb = 0;
	    bool lvalue = false;
	    AstNode* basefromp = AstArraySel::baseFromp(nodep);
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
		lvalue = varrefp->lvalue();
		maxmsb = (varrefp->varp()->width()-1);
	    } else {
		// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
		maxmsb = basefromp->width()-1;
	    }
	    int maxlsb = maxmsb - nodep->width() + 1;
	    if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
	    V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb);

	    // See if the condition is constant true
	    AstNode* condp = new AstLte (nodep->fileline(),
					 nodep->lsbp()->cloneTree(false),
					 new AstConst(nodep->fileline(), maxlsbnum));
	    // Note below has null backp(); the Edit function knows how to deal with that.
	    condp = V3Const::constifyEdit(condp);
	    if (condp->isOne()) {
		// We don't need to add a conditional; we know the existing expression is ok
		condp->deleteTree();
	    }
	    else if (!lvalue) {
		// SEL(...) -> COND(LTE(bit<=maxlsb), ARRAYSEL(...), {width{1'bx}})
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		V3Number xnum (nodep->fileline(), nodep->width());
		xnum.setAllBitsX();
		AstNode* newp = new AstCondBound (nodep->fileline(),
						  condp,
						  nodep,
						  new AstConst(nodep->fileline(), xnum));
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		// Link in conditional
		replaceHandle.relink(newp);
		// Added X's, tristate them too
		newp->accept(*this);
	    }
	    else { // lvalue
		replaceBoundLvalue(nodep, condp);
	    }
	}
    }
    virtual void visit(AstSel* nodep) {
	nodep->iterateChildren(*this);
	if (!nodep->user1SetOnce()) {
	    // Guard against reading/writing past end of bit vector array
	    AstNode* basefromp = AstArraySel::baseFromp(nodep);
	    bool lvalue = false;
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
		lvalue = varrefp->lvalue();
	    }
	    // Find range of dtype we are selecting from
	    // Similar code in V3Const::warnSelect
	    int maxmsb = nodep->fromp()->dtypep()->width()-1;
	    if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
	    V3Number maxmsbnum (nodep->fileline(), nodep->lsbp()->width(), maxmsb);

	    // If (maxmsb >= selected), we're in bound
	    AstNode* condp = new AstGte (nodep->fileline(),
					 new AstConst(nodep->fileline(), maxmsbnum),
					 nodep->lsbp()->cloneTree(false));
	    // See if the condition is constant true (e.g. always in bound due to constant select)
	    // Note below has null backp(); the Edit function knows how to deal with that.
	    condp = V3Const::constifyEdit(condp);
	    if (condp->isOne()) {
		// We don't need to add a conditional; we know the existing expression is ok
		condp->deleteTree();
	    }
	    else if (!lvalue) {
		// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		V3Number xnum (nodep->fileline(), nodep->width());
		xnum.setAllBitsX();
		AstNode* newp = new AstCondBound (nodep->fileline(),
						  condp,
						  nodep,
						  new AstConst(nodep->fileline(), xnum));
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		// Link in conditional
		replaceHandle.relink(newp);
		// Added X's, tristate them too
		newp->accept(*this);
	    }
	    else { // lvalue
		replaceBoundLvalue(nodep, condp);
	    }
	}
    }
Beispiel #4
0
    // PUBLIC METHODS
    AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
	m_assignp = NULL;
	m_ifCondp = NULL;
	m_always = false;
	m_dedupable = true;
	nodep->accept(*this);
	if (m_dedupable && m_assignp) {
	    AstNode* lhsp = m_assignp->lhsp();
	    // Possible todo, handle more complex lhs expressions
	    if (AstNodeVarRef* lhsVarRefp = lhsp->castNodeVarRef()) {
		if (lhsVarRefp->varScopep() != consumerVarScopep) consumerVarScopep->v3fatalSrc("Consumer doesn't match lhs of assign");
		if (AstNodeAssign* dup =  m_hash.hashAndFindDupe(m_assignp,activep,m_ifCondp)) {
		    return (AstNodeVarRef*) dup->lhsp();
		}
	    }
	}
	return NULL;
    }
    virtual void visit(AstNodePreSel* nodep, AstNUser*) {
	if (!nodep->attrp()) {
	    nodep->iterateChildren(*this);
	    // Constification may change the fromp() to a constant, which will lose the
	    // variable we're extracting from (to determine MSB/LSB/endianness/etc.)
	    // So we replicate it in another node
	    // Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
	    AstNode* basefromp = AstArraySel::baseFromp(nodep);
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {  // Maybe varxref - so need to clone
		nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
					   varrefp->cloneTree(false)));
	    } else if (AstMemberSel* fromp = basefromp->castMemberSel()) {
		nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::MEMBER_BASE,
					   fromp->cloneTree(false)));
	    } else {
		nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from");
	    }
	}
    }
    virtual void visit(AstSenItem* nodep, AstNUser*) {
	// Remove bit selects, and bark if it's not a simple variable
	nodep->iterateChildren(*this);
	if (nodep->isClocked()) {
	    // If it's not a simple variable wrap in a temporary
	    // This is a bit unfortunate as we haven't done width resolution
	    // and any width errors will look a bit odd, but it works.
	    AstNode* sensp = nodep->sensp();
	    if (sensp
		&& !sensp->castNodeVarRef()
		&& !sensp->castConst()) {
		// Make a new temp wire
		string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum);
		AstVar* newvarp = new AstVar (sensp->fileline(), AstVarType::MODULETEMP, newvarname,
					      VFlagLogicPacked(), 1);
		// We can't just add under the module, because we may be inside a generate, begin, etc.
		// We know a SenItem should be under a SenTree/Always etc, we we'll just hunt upwards
		AstNode* addwherep = nodep;  // Add to this element's next
		while (addwherep->castSenItem()
		       || addwherep->castSenTree()) {
		    addwherep = addwherep->backp();
		}
		if (!addwherep->castAlways()) {  // Assertion perhaps?
		    sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under some complicated block");
		    addwherep = m_modp;
		}
		addwherep->addNext(newvarp);

		sensp->replaceWith(new AstVarRef (sensp->fileline(), newvarp, false));
		AstAssignW* assignp = new AstAssignW
		    (sensp->fileline(),
		     new AstVarRef(sensp->fileline(), newvarp, true),
		     sensp);
		addwherep->addNext(assignp);
	    }
	} else {  // Old V1995 sensitivity list; we'll probably mostly ignore
	    bool did=1;
	    while (did) {
		did=0;
		if (AstNodeSel* selp = nodep->sensp()->castNodeSel()) {
		    AstNode* fromp = selp->fromp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
		// NodeSel doesn't include AstSel....
		if (AstSel* selp = nodep->sensp()->castSel()) {
		    AstNode* fromp = selp->fromp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
		if (AstNodePreSel* selp = nodep->sensp()->castNodePreSel()) {
		    AstNode* fromp = selp->lhsp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
	    }
	}
	if (!nodep->sensp()->castNodeVarRef()
	    && !nodep->sensp()->castEnumItemRef()) {  // V3Const will cleanup
	    if (debug()) nodep->dumpTree(cout,"-tree: ");
	    nodep->v3error("Unsupported: Complex statement in sensitivity list");
	}
    }
    virtual void visit(AstArraySel* nodep) {
	nodep->iterateChildren(*this);
	if (!nodep->user1SetOnce()) {
	    if (debug()==9) nodep->dumpTree(cout,"-in: ");
	    // Guard against reading/writing past end of arrays
	    AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
	    bool lvalue = false;
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
		lvalue = varrefp->lvalue();
	    } else if (basefromp->castConst()) {
		// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
	    } else {
		nodep->v3fatalSrc("No VarRef or Const under ArraySel");
	    }
	    // Find range of dtype we are selecting from
	    int declElements = -1;
	    AstNodeDType* dtypep = nodep->fromp()->dtypep()->skipRefp();
	    if (!dtypep) nodep->v3fatalSrc("Select of non-selectable type");
	    if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
		declElements = adtypep->elementsConst();
	    } else {
		nodep->v3error("Select from non-array "<<dtypep->prettyTypeName());
	    }
	    if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: ");
	    V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), declElements-1);

	    // See if the condition is constant true
	    AstNode* condp = new AstGte (nodep->fileline(),
					 new AstConst(nodep->fileline(), widthnum),
					 nodep->bitp()->cloneTree(false));
	    // Note below has null backp(); the Edit function knows how to deal with that.
	    condp = V3Const::constifyEdit(condp);
	    if (condp->isOne()) {
		// We don't need to add a conditional; we know the existing expression is ok
		condp->deleteTree();
	    }
	    else if (!lvalue
		     && !nodep->backp()->castArraySel()) {	// Too complicated and slow if mid-multidimension
		// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		V3Number xnum (nodep->fileline(), nodep->width());
		if (nodep->isString()) {
		    xnum = V3Number(V3Number::String(), nodep->fileline(), "");
		} else {
		    xnum.setAllBitsX();
		}
		AstNode* newp = new AstCondBound (nodep->fileline(),
						  condp,
						  nodep,
						  new AstConst(nodep->fileline(), xnum));
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		// Link in conditional, can blow away temp xor
		replaceHandle.relink(newp);
		// Added X's, tristate them too
		newp->accept(*this);
	    }
	    else if (!lvalue) {  // Mid-multidimension read, just use zero
		// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
		AstNRelinker replaceHandle;
		AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
		V3Number zeronum (nodep->fileline(), bitp->width(), 0);
		AstNode* newp = new AstCondBound (bitp->fileline(),
						  condp,
						  bitp,
						  new AstConst(bitp->fileline(), zeronum));
		// Added X's, tristate them too
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		replaceHandle.relink(newp);
		newp->accept(*this);
	    }
	    else {  // lvalue
		replaceBoundLvalue(nodep, condp);
	    }
	}
    }
Beispiel #8
0
    virtual void visit(AstArraySel* nodep, AstNUser*) {
	nodep->iterateChildren(*this);
	if (!nodep->user1Inc()) {
	    if (debug()==9) nodep->dumpTree(cout,"-in: ");
	    // Guard against reading/writing past end of arrays
	    AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
	    int dimension      = AstArraySel::dimension(nodep->fromp());
	    int maxmsb = 0;
	    bool lvalue = false;
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
		AstArrayDType* adtypep = varrefp->varp()->dtypep()->dtypeDimensionp(dimension)->castArrayDType();
		if (!adtypep) nodep->v3fatalSrc("ArraySel to type without array at same depth");
		lvalue = varrefp->lvalue();
		maxmsb = adtypep->elementsConst()-1;
	    } else if (AstConst* lhconstp = basefromp->castConst()) {
		// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
		maxmsb = lhconstp->width();
	    } else {
		nodep->v3fatalSrc("No VarRef or Const under ArraySel\n");
	    }
	    if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: ");
	    V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), maxmsb);

	    // See if the condition is constant true
	    AstNode* condp = new AstLte (nodep->fileline(),
					 nodep->bitp()->cloneTree(false),
					 new AstConst(nodep->fileline(), widthnum));
	    // Note below has null backp(); the Edit function knows how to deal with that.
	    condp = V3Const::constifyEdit(condp);
	    if (condp->isOne()) {
		// We don't need to add a conditional; we know the existing expression is ok
		condp->deleteTree();
	    }
	    else if (!lvalue
		&& !nodep->backp()->castArraySel()) {	// Too complicated and slow if mid-multidimension
		// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		V3Number xnum (nodep->fileline(), nodep->width());
		xnum.setAllBitsX();
		AstNode* newp = new AstCondBound (nodep->fileline(),
						  condp,
						  nodep,
						  new AstConst(nodep->fileline(), xnum));
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		// Link in conditional, can blow away temp xor
		replaceHandle.relink(newp);
		// Added X's, tristate them too
		newp->accept(*this);
	    }
	    else if (!lvalue) {  // Mid-multidimension read, just use zero
		// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
		AstNRelinker replaceHandle;
		AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
		V3Number zeronum (nodep->fileline(), bitp->width(), 0);
		AstNode* newp = new AstCondBound (bitp->fileline(),
						  condp,
						  bitp,
						  new AstConst(bitp->fileline(), zeronum));
		// Added X's, tristate them too
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		replaceHandle.relink(newp);
		newp->accept(*this);
	    }
	    else {  // lvalue
		replaceBoundLvalue(nodep, condp);
	    }
	}
    }