virtual void visit(AstPin* nodep, AstNUser*) { // Any non-direct pins need reconnection with a part-select if (!nodep->exprp()) return; // No-connect if (m_cellRangep) { UINFO(4," PIN "<<nodep<<endl); int pinwidth = nodep->modVarp()->width(); int expwidth = nodep->exprp()->width(); if (expwidth == pinwidth) { // NOP: Arrayed instants: widths match so connect to each instance } else if (expwidth == pinwidth*m_cellRangep->elementsConst()) { // Arrayed instants: one bit for each of the instants (each assign is 1 pinwidth wide) AstNode* exprp = nodep->exprp()->unlinkFrBack(); bool inputPin = nodep->modVarp()->isInput(); if (!inputPin && !exprp->castVarRef() && !exprp->castConcat() // V3Const will collapse the SEL with the one we're about to make && !exprp->castSel()) { // V3Const will collapse the SEL with the one we're about to make nodep->v3error("Unsupported: Per-bit array instantiations with output connections to non-wires."); // Note spec allows more complicated matches such as slices and such } exprp = new AstSel (exprp->fileline(), exprp, pinwidth*(m_instNum-m_instLsb), pinwidth); nodep->exprp(exprp); } else { nodep->v3fatalSrc("Width mismatch; V3Width should have errored out."); } } }
//******************************************************************* // The following visitor functions deal with detecting Z's in the // logic, stripping the Z's out and creating an __en signal and its // logic. //******************************************************************* virtual void visit(AstPull* nodep, AstNUser*) { // replace any pullup/pulldowns with assignw logic and an __en // signal just like it is any other tristate signal. The only // difference is that the user2() variable on the __en signal // will be given a pull direction--i.e. pulldown=1, pullup=2. // This will signal the driver exansion logic to put a default // pullup or pulldown state on the tristate bus under the high-Z // condition when no one is driving the bus. Given the complexity // of merging tristate drivers at any level, the current limitation // of this implementation is that a pullup/down gets applied // to all bits of a bus and a bus cannot have drivers in opposite // directions on indvidual pins. AstNode* outp = nodep->lhsp()->unlinkFrBack();; AstVarRef* outrefp = NULL; int width=-1; if (outp->castVarRef()) { outrefp = outp->castVarRef(); } else if (outp->castSel()) { outrefp = outp->castSel()->fromp()->castVarRef(); width = outp->castSel()->widthConst(); } else { nodep->v3error("Can't find LHS varref"); } outrefp->lvalue(true); AstVar* varp = outrefp->varp(); if (width==-1) width=varp->width(); V3Number num0 (nodep->fileline(), width); num0.setAllBits0(); V3Number num1 (nodep->fileline(), width); num1.setAllBits1(); AstConst* enrhsp = new AstConst(nodep->fileline(), num0); AstVar* enp = createEnableVar(outp, outrefp, enrhsp, width, "pull"); enp->user2(nodep->direction()+1); // record the pull direction AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp, new AstConst(nodep->fileline(), nodep->direction() ? num1 : num0)); nodep->replaceWith(newassp); nodep->deleteTree(); nodep=NULL; newassp->iterateChildren(*this); }
virtual void visit(AstAssignW* nodep, AstNUser*) { // Note: this detects and expands tristates of the forms: // assign x = (OE) ? y : 'hZ; // assign x = (OE) ? 'hz : y; // see if this a COND and separate out the __en logic from the output logic if it is if (AstCond* condp = nodep->rhsp()->castCond()) { //if (debug()>=9) nodep->dumpTree(cout,"- cond-in: "); AstNode* oep = condp->condp(); AstNode* expr1p = condp->expr1p(); AstNode* expr2p = condp->expr2p(); AstNode* enrhsp; AstNode* outrhsp; if (expr1p->castConst() && expr1p->castConst()->num().isAllZ()) { enrhsp = new AstNot(oep->fileline(), oep->unlinkFrBack()); outrhsp = expr2p->unlinkFrBack(); } else if (expr2p->castConst() && expr2p->castConst()->num().isAllZ()){ enrhsp = oep->unlinkFrBack(); outrhsp = expr1p->unlinkFrBack(); } else { // not a tristate or not in a form we recgonize, so exit and move on. return; } AstNode* outp = nodep->lhsp()->unlinkFrBack();; AstVarRef* outrefp = NULL; if (outp->castVarRef()) { outrefp = outp->castVarRef(); } else if (outp->castSel()) { outrefp = outp->castSel()->fromp()->castVarRef(); } else { nodep->v3error("Can't find LHS varref"); } createEnableVar(outp, outrefp, enrhsp, outrhsp->width()); // replace the old assign logic with the new one AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp,outrhsp); //if (debug()>=9) newassp->dumpTreeAndNext(cout,"- cond-out: "); nodep->replaceWith(newassp); nodep->deleteTree(); nodep=NULL; newassp->iterateChildren(*this); } // How about a tri gate? else if (AstBufIf1* bufp = nodep->rhsp()->castBufIf1()) { //if (debug()>=9) nodep->dumpTree(cout,"- tri-in : "); AstNode* enrhsp = bufp->lhsp()->unlinkFrBack(); AstNode* outrhsp = bufp->rhsp()->unlinkFrBack(); AstNode* outp = nodep->lhsp()->unlinkFrBack();; AstVarRef* outrefp = NULL; if (outp->castVarRef()) { outrefp = outp->castVarRef(); } else if (outp->castSel()) { outrefp = outp->castSel()->fromp()->castVarRef(); } else { nodep->v3error("Can't find LHS varref"); } createEnableVar(outp, outrefp, enrhsp, outrhsp->width()); // replace the old assign logic with the new one AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp,outrhsp); //if (debug()>=9) newassp->dumpTreeAndNext(cout,"- tri-out: "); nodep->replaceWith(newassp); nodep->deleteTree(); nodep=NULL; newassp->iterateChildren(*this); } else { nodep->iterateChildren(*this); } }