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