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);
    }