Example #1
0
    AstVarScope* getCreateLastClk(AstVarScope* vscp) {
	if (vscp->user1p()) return ((AstVarScope*)vscp->user1p());
	AstVar* varp = vscp->varp();
	if (!varp->width1()) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
	string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->name());
        AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1);
        newvarp->noReset(true);  // Reset by below assign
	m_modp->addStmtp(newvarp);
	AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
	vscp->user1p(newvscp);
	m_scopep->addVarp(newvscp);
        // Add init
        AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
        if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
        AstNode* newinitp = new AstAssign(vscp->fileline(),
                                          new AstVarRef(newvarp->fileline(), newvscp, true),
                                          fromp);
        addToInitial(newinitp);
	// At bottom, assign them
	AstAssign* finalp
            = new AstAssign(vscp->fileline(),
                            new AstVarRef(vscp->fileline(), newvscp, true),
                            new AstVarRef(vscp->fileline(), vscp, false));
	m_evalFuncp->addFinalsp(finalp);
	//
	UINFO(4,"New Last: "<<newvscp<<endl);
	return newvscp;
    }
Example #2
0
    AstVar* createEnableVar(AstNode* outp, AstVarRef* outrefp, AstNode* enrhsp, int width, string suffix="") {
	// this function creates an  __en Var that corresponds to
	// the outp and outrefp and creates an assignw to enrhsp
        AstVar* enp = new AstVar (outrefp->varp()->fileline(),
				  AstVarType::MODULETEMP,
				  outrefp->name() + "__en" + suffix + cvtToStr(m_unique++),
				  AstLogicPacked(), width);
	enp->varType2Out();

	if (enp->width() != enrhsp->width()) {
	    if (enrhsp->width1()) { // it seems from my futzing that the linter guarantees this condition
		enrhsp = new AstReplicate(enrhsp->fileline(), enrhsp,
					  new AstConst(enrhsp->fileline(), V3Number(enrhsp->fileline(), 32, enp->width())));
		enrhsp->width(enp->width(), enp->width());  //minwidth==width
	    } else {
		enrhsp->v3error("Don't know how to deal with selection logic wider than 1 bit");
	    }
	}

	AstNode* newassp = new AstAssignW (enp->fileline(),
					   new AstVarRef (enp->fileline(), enp, true),
					   enrhsp);
	if (debug()>=9) enp->dumpTreeAndNext(cout,"-   cev-out: ");
	if (debug()>=9) newassp->dumpTreeAndNext(cout,"-   cev-out: ");
        m_modp->addStmtp(enp);
        m_modp->addStmtp(newassp);

	outrefp->user1p(enp); // put __en signal into varref for later usage
	outrefp->varp()->user1p(enp); // put __en signal into var as well in the event this is a single lhs driver and this needs passed up one level

	return enp;
    }
Example #3
0
    void warnAlwCombOrder(AstVarRef* nodep) {
	AstVar* varp = nodep->varp();
	if (!varp->isParam() && !varp->isGenVar() && !varp->isUsedLoopIdx()
	    && !varp->fileline()->warnIsOff(V3ErrorCode::ALWCOMBORDER)) {  // Warn only once per variable
	    nodep->v3warn(ALWCOMBORDER, "Always_comb variable driven after use: "<<nodep->prettyName());
	    varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, true);  // Complain just once for any usage
	}
    }
Example #4
0
    virtual void visit(AstPin* nodep, AstNUser*) {
	// Check to see if any output pins have __en pins and create the __en pins to match
	AstVarRef* refp = findVarRef(nodep);

	if (refp && refp->lvalue() && nodep->modVarp()->user1p()) {
	    AstVar* enchildp = (AstVar*)nodep->modVarp()->user1p();
	    UINFO(9, "       Pulling __en var" << enchildp << endl);
	    AstVar* enp = new AstVar(enchildp->fileline(),
				     AstVarType::OUTPUT,
				     enchildp->name()+cvtToStr(m_unique++),
				     enchildp);
	    enp->user2(enchildp->user2());
	    m_modp->addStmtp(enp);
	    AstPin* pinp = new AstPin(nodep->fileline(),
				      nodep->pinNum(),
				      enp->name(),
				      new AstVarRef(nodep->fileline(), enp, true));
	    AstVarRef *rp = findVarRef(pinp);
	    rp->replaceWith(new AstVarRef(nodep->fileline(), enp, true));
	    rp->deleteTree(); rp=NULL;
	    pinp->width(enp->width(),enp->width());  // minwidth==width
	    pinp->modVarp(enchildp);
	    m_cellp->addPinsp(pinp);
	    refp->user1p(enp);
	    refp->varp()->user1p(enp);
	}
	// Simplify interconnect in preperation for V3Inst
	// (This could be a separate visitor, but we're in the neighborhood)
	V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
    }
Example #5
0
    void genChangeDet(AstVarScope* vscp) {
#ifdef NEW_ORDERING
	vscp->v3fatalSrc("Not applicable\n");
#endif
	AstVar* varp = vscp->varp();
	vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
	AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
	AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
	bool isArray = arrayp;
	bool isStruct = structp && structp->packedUnsup();
	int elements = isArray ? arrayp->elementsConst() : 1;
	if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
	    vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
			 <<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()<<endl
			 <<vscp->warnMore()
			 <<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(elements));
	} else if (!isArray && !isStruct
		   && !varp->dtypeSkipRefp()->castBasicDType()) {
	    if (debug()) varp->dumpTree(cout,"-DETECTARRAY-");
	    vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
	} else {
	    string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();
	    // Create:  VARREF(_last)
	    //          ASSIGN(VARREF(_last), VARREF(var))
	    //          ...
	    //          CHANGEDET(VARREF(_last), VARREF(var))
	    AstVar* newvarp = new AstVar (varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
	    m_topModp->addStmtp(newvarp);
	    AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
	    m_scopetopp->addVarp(newvscp);
	    for (int index=0; index<elements; ++index) {
		AstChangeDet* changep
		    = new AstChangeDet (vscp->fileline(),
					aselIfNeeded(isArray, index,
						     new AstVarRef(vscp->fileline(), vscp, false)),
					aselIfNeeded(isArray, index,
						     new AstVarRef(vscp->fileline(), newvscp, false)),
					false);
		m_chgFuncp->addStmtsp(changep);
		AstAssign* initp
		    = new AstAssign (vscp->fileline(),
				     aselIfNeeded(isArray, index,
						  new AstVarRef(vscp->fileline(), newvscp, true)),
				     aselIfNeeded(isArray, index,
						  new AstVarRef(vscp->fileline(), vscp, false)));
		m_chgFuncp->addFinalsp(initp);
	    }
	}
    }
void V3LinkLevel::wrapTopCell(AstNetlist* netlistp) {
    AstNodeModule* newmodp = netlistp->modulesp();
    if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
    AstNodeModule* oldmodp = newmodp->nextp()->castNodeModule();
    if (!oldmodp) netlistp->v3fatalSrc("No module found to process");

    // Add instance
    AstCell* cellp = new AstCell(newmodp->fileline(),
				 ((v3Global.opt.l2Name()!="") ? v3Global.opt.l2Name() : oldmodp->name()),
				 oldmodp->name(),
				 NULL, NULL, NULL);
    cellp->modp(oldmodp);
    newmodp->addStmtp(cellp);

    // Add pins
    for (AstNode* subnodep=oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
	if (AstVar* oldvarp=subnodep->castVar()) {
	    UINFO(8,"VARWRAP "<<oldvarp<<endl);
	    if (oldvarp->isIO()) {
		AstVar* varp = oldvarp->cloneTree(false);
		newmodp->addStmtp(varp);
		varp->sigPublic(true);	// User needs to be able to get to it...
		if (oldvarp->isIO()) {
		    oldvarp->primaryIO(true);
		    varp->primaryIO(true);
		}
		if (varp->isIO() && v3Global.opt.systemC()) {
		    varp->sc(true);
		    // User can see trace one level down from the wrapper
		    // Avoids packing & unpacking SC signals a second time
		    varp->trace(false);
		}

		AstPin* pinp = new AstPin(oldvarp->fileline(),0,oldvarp->name(),
					  new AstVarRef(varp->fileline(),
							varp, oldvarp->isOutput()));
		// Skip length and width comp; we know it's a direct assignment
		pinp->modVarp(oldvarp);
		cellp->addPinsp(pinp);
	    }
	}
    }
}
Example #7
0
    // METHODS
    AstVarScope* genInpClk(AstVarScope* vscp) {
	if (vscp->user2p()) {
            return VN_CAST(vscp->user2p(), VarScope);
	} else {
	    AstVar* varp = vscp->varp();
	    string newvarname = "__VinpClk__"+vscp->scopep()->nameDotless()+"__"+varp->name();
	    // Create:  VARREF(inpclk)
	    //          ...
	    //          ASSIGN(VARREF(inpclk), VARREF(var))
            AstVar* newvarp = new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
	    m_topModp->addStmtp(newvarp);
	    AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
	    m_scopetopp->addVarp(newvscp);
            AstAssign* asninitp = new AstAssign(vscp->fileline(),
                                                new AstVarRef(vscp->fileline(), newvscp, true),
                                                new AstVarRef(vscp->fileline(), vscp, false));
	    m_scopetopp->addFinalClkp(asninitp);
	    //
	    vscp->user2p(newvscp);
	    return newvscp;
	}
    }
 void reportViolations() {
     // Combine bits into overall state
     AstVar* nodep = m_varp;
     if (!nodep->isParam() && !nodep->isGenVar()) {
         bool allU=true;
         bool allD=true;
         bool anyU=m_usedWhole;
         bool anyD=m_drivenWhole;
         bool anyUnotD=false;
         bool anyDnotU=false;
         bool anynotDU=false;
         for (unsigned bit=0; bit<m_flags.size()/FLAGS_PER_BIT; bit++) {
             bool used = usedFlag(bit);
             bool driv = drivenFlag(bit);
             allU &= used;
             anyU |= used;
             allD &= driv;
             anyD |= driv;
             anyUnotD |= used && !driv;
             anyDnotU |= !used && driv;
             anynotDU |= !used && !driv;
         }
         if (allU) m_usedWhole = true;
         if (allD) m_drivenWhole = true;
         // Test results
         if (allU && allD) {
             // It's fine
         } else if (!anyD && !anyU) {
             // UNDRIVEN is considered more serious - as is more likely a bug,
             // thus undriven+unused bits get UNUSED warnings, as they're not as buggy.
             if (!unusedMatch(nodep)) {
                 nodep->v3warn(UNUSED, "Signal is not driven, nor used: "<<nodep->prettyName());
                 nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);  // Warn only once
             }
         } else if (allD && !anyU) {
             if (!unusedMatch(nodep)) {
                 nodep->v3warn(UNUSED, "Signal is not used: "<<nodep->prettyName());
                 nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);  // Warn only once
             }
         } else if (!anyD && allU) {
             nodep->v3warn(UNDRIVEN, "Signal is not driven: "<<nodep->prettyName());
             nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true);  // Warn only once
         } else {
             // Bits have different dispositions
             bool setU=false;
             bool setD=false;
             if (anynotDU && !unusedMatch(nodep)) {
                 nodep->v3warn(UNUSED, "Bits of signal are not driven, nor used: "<<nodep->prettyName()
                               <<bitNames(BN_BOTH));
                 setU=true;
             }
             if (anyDnotU && !unusedMatch(nodep)) {
                 nodep->v3warn(UNUSED, "Bits of signal are not used: "<<nodep->prettyName()
                               <<bitNames(BN_UNUSED));
                 setU=true;
             }
             if (anyUnotD) {
                 nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<<nodep->prettyName()
                               <<bitNames(BN_UNDRIVEN));
                 setD=true;
             }
             if (setU) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);  // Warn only once
             if (setD) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true);  // Warn only once
         }
     }
 }
Example #9
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);
    }
    static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule*,
					  bool forTristate, bool alwaysCvt) {
	// If a pin connection is "simple" leave it as-is
	// Else create a intermediate wire to perform the interconnect
	// Return the new assignment, if one was made
	// Note this module calles cloneTree() via new AstVar
	AstVar* pinVarp = pinp->modVarp();
	AstVarRef* connectRefp = pinp->exprp()->castVarRef();
	AstBasicDType* pinBasicp = pinVarp->dtypep()->basicp();  // Maybe NULL
	AstBasicDType* connBasicp = NULL;
	AstAssignW* assignp = NULL;
	if (connectRefp) connBasicp = connectRefp->varp()->dtypep()->basicp();
	//
	if (!alwaysCvt
	    && connectRefp
	    && connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
	    && !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
	    // Done. Same data type
	} else if (!alwaysCvt
		   && connectRefp
		   && connectRefp->varp()->isIfaceRef()) {
	    // Done. Interface
	} else if (!alwaysCvt
		   && connBasicp
		   && pinBasicp
		   && connBasicp->width() == pinBasicp->width()
		   && connBasicp->lsb() == pinBasicp->lsb()
		   && !connectRefp->varp()->isSc()	// Need the signal as a 'shell' to convert types
		   && connBasicp->width() == pinVarp->width()
		   && 1) {
	    // Done. One to one interconnect won't need a temporary variable.
	} else if (!alwaysCvt && !forTristate && pinp->exprp()->castConst()) {
	    // Done. Constant.
	} else {
	    // Make a new temp wire
	    //if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
	    AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
	    string newvarname = ((string)(pinVarp->isOutput() ? "__Vcellout" : "__Vcellinp")
				 +(forTristate?"t":"")  // Prevent name conflict if both tri & non-tri add signals
				 +"__"+cellp->name()+"__"+pinp->name());
	    AstVar* newvarp = new AstVar (pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
	    // Important to add statement next to cell, in case there is a generate with same named cell
	    cellp->addNextHere(newvarp);
	    if (pinVarp->isInout()) {
		pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be direct one-to-one connection (without any expression)");
	    } else if (pinVarp->isOutput()) {
		// See also V3Inst
		AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
		UINFO(5,"pinRecon width "<<pinVarp->width()<<" >? "<<rhsp->width()<<" >? "<<pinexprp->width()<<endl);
		rhsp = extendOrSel (pinp->fileline(), rhsp, pinVarp);
		pinp->exprp(new AstVarRef (newvarp->fileline(), newvarp, true));
		AstNode* rhsSelp = extendOrSel (pinp->fileline(), rhsp, pinexprp);
		assignp = new AstAssignW (pinp->fileline(), pinexprp, rhsSelp);
	    } else {
		// V3 width should have range/extended to make the widths correct
		assignp = new AstAssignW (pinp->fileline(),
					  new AstVarRef(pinp->fileline(), newvarp, true),
					  pinexprp);
		pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false));
	    }
	    if (assignp) cellp->addNextHere(assignp);
	    //if (debug()) { pinp->dumpTree(cout,"-  out:"); }
	    //if (debug()) { assignp->dumpTree(cout,"- aout:"); }
	}
	return assignp;
    }
Example #11
0
void V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule* modp) {
    // If a pin connection is "simple" leave it as-is
    // Else create a intermediate wire to perform the interconnect
    // Note this module calles cloneTree() via new AstVar
    AstVar* pinVarp = pinp->modVarp();
    AstVarRef* connectRefp = pinp->exprp()->castVarRef();
    AstBasicDType* pinBasicp = pinVarp->dtypep()->basicp();  // Maybe NULL
    AstBasicDType* connBasicp = NULL;
    if (connectRefp) connBasicp = connectRefp->varp()->dtypep()->basicp();
    //
    if (connectRefp
	&& connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
	&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
	// Done.  Same data type
    } else if (connBasicp
	       && pinBasicp
	       && connBasicp->width() == pinBasicp->width()
	       && connBasicp->lsb() == pinBasicp->lsb()
	       && !connectRefp->varp()->isSc()	// Need the signal as a 'shell' to convert types
	       && pinp->width() == pinVarp->width()
	       && 1) {
	// Done. One to one interconnect won't need a temporary variable.
    } else if (pinp->exprp()->castConst()) {
	// Done. Constant.
    } else {
	// Make a new temp wire
	//if (1||debug()>=9) { pinp->dumpTree(cout,"in_pin:"); }
	AstAssignW* assignp = NULL;
	AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
	string newvarname = "__Vcellinp__"+cellp->name()+"__"+pinp->name();
	AstVar* newvarp = new AstVar (pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
	modp->addStmtp(newvarp);
	if (pinVarp->isInout()) {
	    pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be direct one-to-one connection (without any expression)");
	} else if (pinVarp->isOutput()) {
	    // See also V3Inst
	    AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
	    if (pinp->width() > rhsp->width()) {
		if (rhsp->isSigned()) {
		    rhsp = new AstExtendS(pinp->fileline(), rhsp);
		} else {
		    rhsp = new AstExtend (pinp->fileline(), rhsp);
		}
	    } else if (pinp->width() < rhsp->width()) {
		rhsp = new AstSel    (pinp->fileline(), rhsp, 0, pinp->width());
	    }
	    rhsp->widthSignedFrom(pinp);
	    assignp = new AstAssignW (pinp->fileline(), pinexprp, rhsp);
	    pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, true));
	} else {
	    // V3 width should have range/extended to make the widths correct
	    if (pinexprp->width() != pinVarp->width()) pinp->v3fatalSrc("Input pin width mismatch");
	    assignp = new AstAssignW (pinp->fileline(),
				      new AstVarRef(pinp->fileline(), newvarp, true),
				      pinexprp);
	    pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false));
	}
	pinp->widthSignedFrom(pinp->exprp());
	if (assignp) modp->addStmtp(assignp);
	//if (1||debug()) { pinp->dumpTree(cout,"  out:"); }
	//if (1||debug()) { assignp->dumpTree(cout," aout:"); }
    }
}