Example #1
0
    virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) {
	for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; ) {
	    V3GraphEdge* oldedgep = edgep;
	    edgep = edgep->inNextp();  // for recursive since the edge could be deleted
	    if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
		if (AstNodeAssign* assignp = lvertexp->nodep()->castNodeAssign()) {
		    //if (lvertexp->outSize1() && assignp->lhsp()->castSel()) {
		    if (assignp->lhsp()->castSel() && lvertexp->outSize1()) {
			UINFO(9, "assing to the nodep["<<assignp->lhsp()->castSel()->lsbConst()<<"]"<<endl);
			// first assign with Sel-lhs
			if (!m_activep) m_activep = lvertexp->activep();
			if (!m_logicvp) m_logicvp = lvertexp;
			if (!m_assignp) m_assignp = assignp;

			// not under the same active
			if (m_activep != lvertexp->activep()) {
			    m_activep = lvertexp->activep();
			    m_logicvp = lvertexp;
			    m_assignp = assignp;
			    continue;
			}

			AstSel* preselp = m_assignp->lhsp()->castSel();
			AstSel* curselp = assignp->lhsp()->castSel();
			if (!preselp || !curselp) continue;

			if (AstSel* newselp = merge(preselp, curselp)) {
			    UINFO(5, "assemble to new sel: "<<newselp<<endl);
			    // replace preSel with newSel
			    preselp->replaceWith(newselp); preselp->deleteTree(); VL_DANGLING(preselp);
			    // create new rhs for pre assignment
			    AstNode* newrhsp = new AstConcat(m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false), assignp->rhsp()->cloneTree(false));
			    AstNode* oldrhsp = m_assignp->rhsp();
			    oldrhsp->replaceWith(newrhsp); oldrhsp->deleteTree(); VL_DANGLING(oldrhsp);
			    m_assignp->dtypeChgWidthSigned(m_assignp->width()+assignp->width(), m_assignp->width()+assignp->width(), AstNumeric::fromBool(true));
			    // don't need to delete, will be handled
			    //assignp->unlinkFrBack(); assignp->deleteTree(); VL_DANGLING(assignp);

			    // update the graph
			    {
				// delete all inedges to lvertexp
				if (!lvertexp->inEmpty()) { 
				    for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep; ) {
					V3GraphEdge* oedgep = ledgep;
					ledgep = ledgep->inNextp();
					GateEitherVertex* fromvp = dynamic_cast<GateEitherVertex*>(oedgep->fromp());
					new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
					oedgep->unlinkDelete(); VL_DANGLING(oedgep);
				    }
				}
				// delete all outedges to lvertexp, only one
				oldedgep->unlinkDelete(); VL_DANGLING(oldedgep);
			    }
			    ++m_numMergedAssigns;
			} else {
			    m_assignp = assignp;
			    m_logicvp = lvertexp;
			}
		    }
		}
	    }
	}
	return NULL;
    }
Example #2
0
    virtual void visit(AstNodeModule* nodep, AstNUser*) {
	UINFO(9," MOD   "<<nodep<<endl);
	m_unique = 0;
	VarMap* lhsmapp = new VarMap();

	// expand tristate nodes and detect multiple LHS drivers for this module
	TristateExpander(nodep, lhsmapp);

	// iterate the children to grab any  __en signals from subcells
	m_modp = nodep;
	nodep->iterateChildren(*this);
	m_modp = NULL;

	// go through each multiple lhs driver & collapse it to a single driver
	for (VarMap::iterator nextit, it=lhsmapp->begin(); it != lhsmapp->end(); it=nextit) {
	    nextit = it; ++nextit;
	    m_unique = 0;
	    AstVar* lhsp = (*it).first;
	    RefVec* refs = (*it).second;
	    bool isOutput = (lhsp->varType() == AstVarType::OUTPUT) && (nodep->level() > 1); // force termination at top level

	    if (refs->size() < 2 && isOutput) {
		// if only one driver and this is an output, then exit and
		// let the driver propagate on its own.  If the signals
		// terminates at this level, then we need to let the
		// undriven state get generated.
		lhsmapp->erase(lhsp);
		delete refs;
		continue;
	    }


	    UINFO(9, "       Checking " << refs->size() << " drivers for tristates signals on net " << lhsp << endl);
	    int pull = 0;  // initially assume no pull direction

	    // Now remove and multple lhs signals that do not have __en for
	    // all possible drivers.
	    bool complete = true;
	    int found_one = 0;

	    for (RefVec::iterator ii=refs->begin(); ii != refs->end(); ++ii) {
		AstVarRef* refp = (*ii);
		if (!refp->user1p()) { // if no __en signal, then delete the entry
		    complete = false;
		} else {
		    found_one++;
		}
	    }
	    if (!complete) {
		if (found_one) {
		    UINFO(9, "       Problem mixing tristate and low-Z on " << lhsp << endl);
		    UINFO(9, "       Found " << found_one << " __en signals from of " << refs->size() << " possible drivers" << endl);
		    // not sure what I should do here other than error that they are mixing low-Z and tristate drivers.
		    // The other scenerio, and probably more likely, is that they are using a high-Z construct that
		    // is not supported.  Improving the high-Z detection logic will reduce the occurance of this failure.
		    nodep->v3error("Mixing tristate and low-Z drivers.  Perhaps you are using a high-Z construct not supported");
		} else  {
		    UINFO(9, "       No tristates found on " << lhsp <<endl);
		}
		lhsmapp->erase(lhsp);
		delete refs;
		continue;
	    }

	    UINFO(9, "       TRISTATE LHS DRIVER FOUND:" << lhsp << endl);

	    AstNode* orp = NULL,* andp = NULL,* undrivenp = NULL,* newenlogicp = NULL;

	    // loop through the lhs drivers to build the driver resolution logic
	    for (RefVec::iterator ii=refs->begin(); ii != refs->end(); ++ii) {
		AstVarRef* refp = (*ii);
		int w = lhsp->width();
		int wfill = 0; // width filler when necessary due to sels
		AstSel* selp = NULL;
		if (refp->user3p()) { // this varref has a sel
		    selp = (AstSel*) refp->user3p();
		    w = selp->widthConst();
		    wfill = lhsp->width() - w;
		}

		// create a new var for this assignment.
		AstVar* enp = (AstVar*)refp->user1p();
		AstVar* newlhsp = new AstVar(lhsp->fileline(),
					     AstVarType::MODULETEMP,
					     lhsp->name()+"__lhs"+cvtToStr(m_unique++),
					     AstLogicPacked(), w);
		nodep->addStmtp(newlhsp);

		// now append this driver to the driver logic.
		AstNode* ref1 = new AstVarRef(nodep->fileline(), newlhsp,false);
		AstNode* ref2 = new AstVarRef(nodep->fileline(), enp, false);
		andp = new AstAnd(nodep->fileline(), ref1, ref2);


		AstVar* bitselp = NULL;
		if (selp) { // this varref has a sel
		    int ws = V3Number::log2b(lhsp->width())+1;
		    bitselp = new AstVar(lhsp->fileline(),
					 AstVarType::MODULETEMP,
					 lhsp->name()+"__sel"+cvtToStr(m_unique-1),
					 AstLogicPacked(), ws);
		    //
		    nodep->addStmtp(bitselp);
		    nodep->addStmtp(new AstAssignW(lhsp->fileline(),
						   new AstVarRef(lhsp->fileline(), bitselp, true),
						   selp->lsbp()->cloneTree(false)));
		    andp = new AstShiftL(lhsp->fileline(),
					 new AstConcat(lhsp->fileline(), new AstConst(lhsp->fileline(), V3Number(lhsp->fileline(), wfill, 0)), andp),
					 new AstVarRef(lhsp->fileline(), bitselp, false),
					 lhsp->width()
			);

		    selp->replaceWith(new AstVarRef(refp->fileline(), newlhsp, true));
		    pushDeletep(selp);  // Setting selp here or deleting immediately
		    // breaks the t_tri_select test, this probably indicates a problem
		} else {
		    refp->varp(newlhsp); // assign the new var to the varref
		    refp->name(newlhsp->name());
		}

		// or this to the others
		orp = (!orp) ? andp : new AstOr(nodep->fileline(), orp, andp);

		if (isOutput) {
		    AstNode *en1p = new AstVarRef(nodep->fileline(), enp, false);
		    if (selp) {
			en1p = new AstShiftL(enp->fileline(),
					     new AstConcat(lhsp->fileline(), new AstConst(lhsp->fileline(), V3Number(lhsp->fileline(), wfill, 0)), en1p),
					     new AstVarRef(lhsp->fileline(), bitselp, false),
					     lhsp->width()
			    );
		    }
		    if (!newenlogicp) {
			newenlogicp = en1p;
		    } else {
			newenlogicp = new AstOr(nodep->fileline(), newenlogicp, en1p);
		    }
		} else {
		    if (!undrivenp) {
			undrivenp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), enp, false));
			if (selp)
			    undrivenp = new AstShiftL(enp->fileline(),
						      new AstConcat(lhsp->fileline(), new AstConst(lhsp->fileline(), V3Number(lhsp->fileline(), wfill, 0)), undrivenp),
						      new AstVarRef(lhsp->fileline(), bitselp, false),
						      lhsp->width());
		    } else {
			AstNode *tmp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), enp, false));
			if (selp) {
			    tmp = new AstShiftL(enp->fileline(),
						new AstConcat(lhsp->fileline(), new AstConst(lhsp->fileline(), V3Number(lhsp->fileline(), wfill, 0)), tmp),
						new AstVarRef(lhsp->fileline(), bitselp, false),
						lhsp->width());
			}
			undrivenp = new AstAnd(nodep->fileline(), tmp, undrivenp);
		    }
		}

		refp->user1p(NULL); // clear the user1p() as we done with it in the VarRef at this point

		if (enp->user2()) { // if this net is pulled up/down
		    int newpull = enp->user2();
		    if (pull == 0) {
			pull = newpull;
		    } else if (newpull != pull) {
			pull = -1; // conflict over the pull direction
		    }
		}
	    }
	    if (isOutput) {
		AstVar* newenp = new AstVar(lhsp->fileline(),
					    AstVarType::OUTPUT,
					    lhsp->name()+"__enout"+cvtToStr(m_unique++),
					    lhsp);
		nodep->addStmtp(newenp);
		nodep->addStmtp(new AstAssignW(lhsp->fileline(),
					       new AstVarRef(lhsp->fileline(), newenp, true),
					       newenlogicp));
		newenp->user2(pull); // put the pull direction in the next __en signal to pass it up
		lhsp->user1p(newenp); // put the new __en signal in the var so it can be pushed up the hierarchy.

	    } else { // this is the level where the signal terminates, we do final conflict resolution here
		UINFO(9, "       Terminating tristate logic for " << lhsp->name() << endl);
		UINFO(9, "       Pull direction is " << pull << " where -1=X, 0=Z, 1=low, 2=high." << endl);
		// figure out what to drive when no one is driving the bus
		V3Number num(nodep->fileline(), lhsp->width());
		if (pull==0) {
		    num.setAllBitsZ();
		} else if (pull==1) {
		    num.setAllBits0();
		} else if (pull==2) {
		    num.setAllBits1();
		} else {
		    num.setAllBitsX();
		}
		undrivenp = new AstAnd(nodep->fileline(), undrivenp,
				       new AstConst(nodep->fileline(), num));
		orp = new AstOr(nodep->fileline(), orp, undrivenp);
	    }
	    nodep->addStmtp(new AstAssignW(lhsp->fileline(),
					   new AstVarRef(lhsp->fileline(), lhsp, true), orp));

	    // delete the map and vector list now that we have collapsed it.
	    lhsmapp->erase(lhsp);
	    delete refs;
	}
	delete lhsmapp; // delete the map now that we are done
	nodep->user1p(NULL);
    }
Example #3
0
    void replaceSelPlusMinus(AstNodePreSel* nodep) {
	// Select of a range specified with +: or -:, i.e. "array[2+:3], [2-:3]"
	// This select style has a lsb and width
	UINFO(6,"SELPLUS/MINUS "<<nodep<<endl);
	// Below 2 lines may change nodep->widthp()
	if (debug()>=9) nodep->dumpTree(cout,"--SELPM0: ");
	V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
	checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
	if (debug()>=9) nodep->dumpTree(cout,"--SELPM3: ");
	// Now replace it with an AstSel
	AstNode* fromp = nodep->lhsp()->unlinkFrBack();
	AstNode* rhsp  = nodep->rhsp()->unlinkFrBack();
	AstNode* widthp = nodep->thsp()->unlinkFrBack();
	int width = widthp->castConst()->toSInt();
	if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "<<widthp->prettyName());
	if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
	FromData fromdata = fromDataForArray(nodep, fromp, width!=1);
	AstNodeDType* ddtypep = fromdata.m_dtypep;
	VNumRange fromRange = fromdata.m_fromRange;
	if (ddtypep->castBasicDType()
	    || ddtypep->castPackArrayDType()
	    || (ddtypep->castNodeClassDType()
		&& ddtypep->castNodeClassDType()->packedUnsup())) {
	    int elwidth = 1;
	    AstNode* newwidthp = widthp;
	    if (AstPackArrayDType* adtypep = ddtypep->castPackArrayDType()) {
		elwidth = adtypep->width() / fromRange.elements();
		newwidthp = new AstConst (nodep->fileline(),AstConst::Unsized32(), width * elwidth);
	    }
	    AstNode* newlsbp = NULL;
	    if (nodep->castSelPlus()) {
		if (fromRange.littleEndian()) {
		    // SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
		    newlsbp = newSubNeg((fromRange.hi()-width+1), rhsp);
		} else {
		    // SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
		    newlsbp = newSubNeg(rhsp, fromRange.lo());
		}
	    } else if (nodep->castSelMinus()) {
		if (fromRange.littleEndian()) {
		    // SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
		    newlsbp = newSubNeg(fromRange.hi(), rhsp);
		} else {
		    // SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
		    newlsbp = newSubNeg(rhsp, fromRange.lo()+(width-1));
		}
	    } else {
		nodep->v3fatalSrc("Bad Case");
	    }
	    if (elwidth != 1) newlsbp = new AstMul (nodep->fileline(), newlsbp,
						    new AstConst (nodep->fileline(), elwidth));
	    AstSel* newp = new AstSel (nodep->fileline(),
				       fromp, newlsbp, newwidthp);
	    newp->declRange(fromRange);
	    newp->declElWidth(elwidth);
	    UINFO(6,"   new "<<newp<<endl);
	    if (debug()>=9) newp->dumpTree(cout,"--SELNEW: ");
	    nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	else {  // NULL=bad extract, or unknown node type
	    nodep->v3error("Illegal +: or -: select; type already selected, or bad dimension: type is "
			   <<fromdata.m_errp->prettyTypeName());
	    // How to recover?  We'll strip a dimension.
	    nodep->replaceWith(fromp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	// delete whataver we didn't use in reconstruction
	if (!fromp->backp()) { pushDeletep(fromp); VL_DANGLING(fromp); }
	if (!rhsp->backp()) { pushDeletep(rhsp); VL_DANGLING(rhsp); }
	if (!widthp->backp()) { pushDeletep(widthp); VL_DANGLING(widthp); }
    }
Example #4
0
    virtual void visit(AstSelExtract* nodep, AstNUser*) {
	// Select of a range specified part of an array, i.e. "array[2:3]"
	// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
	// This select style has a (msb or lsb) and width
	UINFO(6,"SELEXTRACT "<<nodep<<endl);
	//if (debug()>=9) nodep->dumpTree(cout,"--SELEX0: ");
	// Below 2 lines may change nodep->widthp()
	V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
	V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
	//if (debug()>=9) nodep->dumpTree(cout,"--SELEX3: ");
	checkConstantOrReplace(nodep->lsbp(), "First value of [a:b] isn't a constant, maybe you want +: or -:");
	checkConstantOrReplace(nodep->msbp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:");
	AstNode* fromp = nodep->lhsp()->unlinkFrBack();
	AstNode* msbp = nodep->rhsp()->unlinkFrBack();
	AstNode* lsbp = nodep->thsp()->unlinkFrBack();
	vlsint32_t msb = msbp->castConst()->toSInt();
	vlsint32_t lsb = lsbp->castConst()->toSInt();
	FromData fromdata = fromDataForArray(nodep, fromp, false);
	AstNodeDType* ddtypep = fromdata.m_dtypep;
	VNumRange fromRange = fromdata.m_fromRange;
	if (ddtypep->castUnpackArrayDType()) {
	    // Slice extraction
	    if (fromRange.elements() == (msb-lsb+1)
		&& fromRange.lo() == lsb) { // Extracting whole of original array
		nodep->replaceWith(fromp); pushDeletep(nodep); VL_DANGLING(nodep);
	    } else {
		// TODO when unpacked arrays fully supported probably need new data type here
		AstArraySel* newp = new AstArraySel (nodep->fileline(), fromp, lsbp);
		newp->start(lsb);
		newp->length((msb - lsb) + 1);
		nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	    }
	}
	else if (AstPackArrayDType* adtypep = ddtypep->castPackArrayDType()) {
	    // SELEXTRACT(array, msb, lsb) -> SEL(array, lsb*width-of-subindex, width-of-subindex*(msb-lsb))
	    if (!fromRange.elements() || (adtypep->width() % fromRange.elements())!=0)
		adtypep->v3fatalSrc("Array extraction with width miscomputed "
				    <<adtypep->width()<<"/"<<fromRange.elements());
	    int elwidth = adtypep->width() / fromRange.elements();
	    AstSel* newp = new AstSel (nodep->fileline(),
				       fromp,
				       new AstConst(nodep->fileline(),AstConst::Unsized32(),lsb*elwidth),
				       new AstConst(nodep->fileline(),AstConst::Unsized32(),(msb-lsb+1)*elwidth));
	    newp->declRange(fromRange);
	    newp->declElWidth(elwidth);
	    newp->dtypeFrom(sliceDType(adtypep, msb, lsb));
	    //if (debug()>=9) newp->dumpTree(cout,"--EXTBTn: ");
	    if (newp->widthMin()!=(int)newp->widthConst()) nodep->v3fatalSrc("Width mismatch");
	    nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	else if (ddtypep->castBasicDType()) {
	    if (fromRange.littleEndian()) {
		// Below code assumes big bit endian; just works out if we swap
		int x = msb; msb = lsb; lsb = x;
	    }
	    if (lsb > msb) {
		nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
		int x = msb; msb = lsb; lsb = x;
	    }
	    AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
					    msb +1-lsb);
	    AstSel* newp = new AstSel (nodep->fileline(),
				       fromp,
				       newSubLsbOf(lsbp, fromRange),
				       widthp);
	    newp->declRange(fromRange);
	    UINFO(6,"   new "<<newp<<endl);
	    //if (debug()>=9) newp->dumpTree(cout,"--SELEXnew: ");
	    nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	else if (ddtypep->castNodeClassDType()) {
	    // Classes aren't little endian
	    if (lsb > msb) {
		nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
		int x = msb; msb = lsb; lsb = x;
	    }
	    AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
					    msb +1-lsb);
	    AstSel* newp = new AstSel (nodep->fileline(),
				       fromp,
				       newSubLsbOf(lsbp, fromRange),
				       widthp);
	    newp->declRange(fromRange);
	    UINFO(6,"   new "<<newp<<endl);
	    //if (debug()>=9) newp->dumpTree(cout,"--SELEXnew: ");
	    nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	else {  // NULL=bad extract, or unknown node type
	    nodep->v3error("Illegal range select; type already selected, or bad dimension: type is "
			   <<fromdata.m_errp->prettyName());
	    UINFO(1,"    Related ddtype: "<<ddtypep<<endl);
	    // How to recover?  We'll strip a dimension.
	    nodep->replaceWith(fromp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	// delete whataver we didn't use in reconstruction
	if (!fromp->backp()) { pushDeletep(fromp); VL_DANGLING(fromp); }
	if (!msbp->backp()) { pushDeletep(msbp); VL_DANGLING(msbp); }
	if (!lsbp->backp()) { pushDeletep(lsbp); VL_DANGLING(lsbp); }
    }
Example #5
0
    virtual void visit(AstSelBit* nodep, AstNUser*) {
	// Select of a non-width specified part of an array, i.e. "array[2]"
	// This select style has a lsb and msb (no user specified width)
	UINFO(6,"SELBIT "<<nodep<<endl);
	if (debug()>=9) nodep->backp()->dumpTree(cout,"--SELBT0: ");
	// lhsp/rhsp do not need to be constant
	AstNode* fromp = nodep->lhsp()->unlinkFrBack();
	AstNode* rhsp = nodep->rhsp()->unlinkFrBack();  // bit we're extracting
	if (debug()>=9) nodep->dumpTree(cout,"--SELBT2: ");
	FromData fromdata = fromDataForArray(nodep, fromp, false);
	AstNodeDType* ddtypep = fromdata.m_dtypep;
	VNumRange fromRange = fromdata.m_fromRange;
	UINFO(6,"  ddtypep "<<ddtypep<<endl);
	if (AstUnpackArrayDType* adtypep = ddtypep->castUnpackArrayDType()) {
	    // SELBIT(array, index) -> ARRAYSEL(array, index)
	    AstNode* subp = rhsp;
	    if (fromRange.lo()!=0 || fromRange.hi()<0) {
		subp = newSubNeg (subp, fromRange.lo());
	    }
	    AstArraySel* newp = new AstArraySel (nodep->fileline(),
						 fromp, subp);
	    newp->dtypeFrom(adtypep->subDTypep());  // Need to strip off array reference
	    if (debug()>=9) newp->dumpTree(cout,"--SELBTn: ");
	    nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	else if (AstPackArrayDType* adtypep = ddtypep->castPackArrayDType()) {
	    // SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex)
	    AstNode* subp = rhsp;
	    if (fromRange.lo()!=0 || fromRange.hi()<0) {
		subp = newSubNeg (subp, fromRange.lo());
	    }
	    if (!fromRange.elements() || (adtypep->width() % fromRange.elements())!=0)
		adtypep->v3fatalSrc("Array extraction with width miscomputed "
				    <<adtypep->width()<<"/"<<fromRange.elements());
	    int elwidth = adtypep->width() / fromRange.elements();
	    AstSel* newp = new AstSel (nodep->fileline(),
				       fromp,
				       new AstMul(nodep->fileline(),
						  new AstConst(nodep->fileline(),AstConst::Unsized32(),elwidth),
						  subp),
				       new AstConst (nodep->fileline(),AstConst::Unsized32(),elwidth));
	    newp->declRange(fromRange);
	    newp->declElWidth(elwidth);
	    newp->dtypeFrom(adtypep->subDTypep());  // Need to strip off array reference
	    if (debug()>=9) newp->dumpTree(cout,"--SELBTn: ");
	    nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	else if (ddtypep->castBasicDType()) {
	    // SELBIT(range, index) -> SEL(array, index, 1)
	    AstSel* newp = new AstSel (nodep->fileline(),
				       fromp,
				       newSubLsbOf(rhsp, fromRange),
				       // Unsized so width from user
				       new AstConst (nodep->fileline(),AstConst::Unsized32(),1));
	    newp->declRange(fromRange);
	    UINFO(6,"   new "<<newp<<endl);
	    if (debug()>=9) newp->dumpTree(cout,"--SELBTn: ");
	    nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	else if (ddtypep->castNodeClassDType()) {  // It's packed, so a bit from the packed struct
	    // SELBIT(range, index) -> SEL(array, index, 1)
	    AstSel* newp = new AstSel (nodep->fileline(),
				       fromp,
				       newSubLsbOf(rhsp, fromRange),
				       // Unsized so width from user
				       new AstConst (nodep->fileline(),AstConst::Unsized32(),1));
	    newp->declRange(fromRange);
	    UINFO(6,"   new "<<newp<<endl);
	    if (debug()>=9) newp->dumpTree(cout,"--SELBTn: ");
	    nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	else {  // NULL=bad extract, or unknown node type
	    nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: type is"
			   <<fromdata.m_errp->prettyName());
	    // How to recover?  We'll strip a dimension.
	    nodep->replaceWith(fromp); pushDeletep(nodep); VL_DANGLING(nodep);
	}
	if (!rhsp->backp()) { pushDeletep(rhsp); VL_DANGLING(rhsp); }
    }
Example #6
0
    AstNode* createDlyArray(AstAssignDly* nodep, AstNode* lhsp) {
	// Create delayed assignment
	// See top of this file for transformation
	// Return the new LHS for the assignment, Null = unlink
	// Find selects
	AstNode* newlhsp = NULL;	// NULL = unlink old assign
	AstSel*  bitselp = NULL;
	AstArraySel*  arrayselp = NULL;
	if (lhsp->castSel()) {
	    bitselp = lhsp->castSel();
	    arrayselp = bitselp->fromp()->castArraySel();
	} else {
	    arrayselp = lhsp->castArraySel();
	}
	if (!arrayselp) nodep->v3fatalSrc("No arraysel under bitsel?");
	if (arrayselp->length()!=1) nodep->v3fatalSrc("ArraySel with length!=1 should have been removed in V3Slice");

	UINFO(4,"AssignDlyArray: "<<nodep<<endl);
	//
	//=== Dimensions: __Vdlyvdim__
	deque<AstNode*> dimvalp;		// Assignment value for each dimension of assignment
	AstNode* dimselp=arrayselp;
	for (; dimselp->castArraySel(); dimselp=dimselp->castArraySel()->fromp()) {
	    AstNode* valp = dimselp->castArraySel()->bitp()->unlinkFrBack();
	    dimvalp.push_front(valp);
	}
	AstVarRef* varrefp = dimselp->castVarRef();
	if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels\n");
	if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
	varrefp->unlinkFrBack();
	AstVar* oldvarp = varrefp->varp();
	int modVecNum = oldvarp->user4();  oldvarp->user4(modVecNum+1);
	//
	deque<AstNode*> dimreadps;		// Read value for each dimension of assignment
	for (unsigned dimension=0; dimension<dimvalp.size(); dimension++) {
	    AstNode* dimp = dimvalp[dimension];
	    if (dimp->castConst()) { // bit = const, can just use it
		dimreadps.push_front(dimp);
	    } else {
		string bitvarname = (string("__Vdlyvdim")+cvtToStr(dimension)
				     +"__"+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
		AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, dimp->width());
		AstAssign* bitassignp
		    = new AstAssign (nodep->fileline(),
				     new AstVarRef(nodep->fileline(), bitvscp, true),
				     dimp);
		nodep->addNextHere(bitassignp);
		dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
	    }
	}
	//
	//=== Bitselect: __Vdlyvlsb__
	AstNode* bitreadp=NULL;  // Code to read Vdlyvlsb
	if (bitselp) {
	    AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
	    if (bitselp->fromp()->castConst()) {// vlsb = constant, can just push constant into where we use it
		bitreadp = lsbvaluep;
	    } else {
		string bitvarname = (string("__Vdlyvlsb__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
		AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width());
		AstAssign* bitassignp = new AstAssign (nodep->fileline(),
						       new AstVarRef(nodep->fileline(), bitvscp, true),
						       lsbvaluep);
		nodep->addNextHere(bitassignp);
		bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
	    }
	}
	//
	//=== Value: __Vdlyvval__
	AstNode* valreadp;	// Code to read Vdlyvval
	if (nodep->rhsp()->castConst()) {	// vval = constant, can just push constant into where we use it
	    valreadp = nodep->rhsp()->unlinkFrBack();
	} else {
	    string valvarname = (string("__Vdlyvval__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
	    AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, nodep->rhsp()->width());
	    newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
	    valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
	}
	//
	//=== Setting/not setting boolean: __Vdlyvset__
	AstVarScope* setvscp;
	AstAssignPre* setinitp = NULL;

	if (nodep->user3p()) {
	    // Simplistic optimization.  If the previous statement in same scope was also a =>,
	    // then we told this nodep->user3 we can use its Vdlyvset rather than making a new one.
	    // This is good for code like:
	    //    for (i=0; i<5; i++)  vector[i] <= something;
	    setvscp = nodep->user3p()->castNode()->castVarScope();
	    ++m_statSharedSet;
	} else {  // Create new one
	    string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
	    setvscp = createVarSc(varrefp->varScopep(), setvarname, 1);
	    setinitp = new AstAssignPre (nodep->fileline(),
					 new AstVarRef(nodep->fileline(), setvscp, true),
					 new AstConst(nodep->fileline(), 0));
	    AstAssign* setassignp
		= new AstAssign (nodep->fileline(),
				 new AstVarRef(nodep->fileline(), setvscp, true),
				 new AstConst(nodep->fileline(),
					      V3Number(nodep->fileline(),1,true)));
	    nodep->addNextHere(setassignp);
	}
	if (m_nextDlyp) {  // Tell next assigndly it can share the variable
	    m_nextDlyp->user3p(setvscp);
	}
	//
	// Create ALWAYSPOST for delayed variable
	// We add all logic to the same block if it's for the same memory
	// This insures that multiple assignments to the same memory will result
	// in correctly ordered code - the last assignment must be last.
	// It also has the nice side effect of assisting cache locality.
	AstNode* selectsp = varrefp;
	for (int dimension=int(dimreadps.size())-1; dimension>=0; --dimension) {
	    selectsp = new AstArraySel(nodep->fileline(), selectsp, dimreadps[dimension]);
	}
	if (bitselp) {
	    selectsp = new AstSel(nodep->fileline(), selectsp, bitreadp,
				  bitselp->widthp()->cloneTree(false));
	}
	// Build "IF (changeit) ...
	UINFO(9,"   For "<<setvscp<<endl);
	UINFO(9,"     & "<<varrefp<<endl);
	AstAlwaysPost* finalp = varrefp->varScopep()->user4p()->castNode()->castAlwaysPost();
	if (finalp) {
	    AstActive* oldactivep = finalp->user2p()->castNode()->castActive();
	    checkActivePost(varrefp, oldactivep);
	    if (setinitp) oldactivep->addStmtsp(setinitp);
	} else { // first time we've dealt with this memory
	    finalp = new AstAlwaysPost(nodep->fileline(), NULL/*sens*/, NULL/*body*/);
	    UINFO(9,"     Created "<<finalp<<endl);
	    AstActive* newactp = createActivePost(varrefp);
	    newactp->addStmtsp(finalp);
	    varrefp->varScopep()->user4p(finalp);
	    finalp->user2p(newactp);
	    if (setinitp) newactp->addStmtsp(setinitp);
	}
	AstIf* postLogicp;
	if (finalp->user3p()->castNode() == setvscp) {
	    // Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*,
	    // we can share the IF statement too
	    postLogicp = finalp->user4p()->castNode()->castIf();
	    if (!postLogicp) nodep->v3fatalSrc("Delayed assignment misoptimized; prev var found w/o associated IF");
	} else {
	    postLogicp = new AstIf (nodep->fileline(),
				    new AstVarRef(nodep->fileline(), setvscp, false),
				    NULL,
				    NULL);
	    UINFO(9,"     Created "<<postLogicp<<endl);
	    finalp->addBodysp(postLogicp);
	    finalp->user3p(setvscp);	// Remember IF's vset variable
	    finalp->user4p(postLogicp);	// and the associated IF, as we may be able to reuse it
	}
	postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp));
	return newlhsp;
    }