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.");
	    }
	}
    }
Example #2
0
    //*******************************************************************
    // 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);
    }
Example #3
0
    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);
	}
    }