Beispiel #1
0
    void mergeEnd() {
        if (!m_mgAssignps.empty()) {
            uint32_t items = m_mgIndexHi - m_mgIndexLo + 1;
            UINFO(9, "End merge iter="<<items<<" "<<m_mgIndexHi<<":"<<m_mgIndexLo
                  <<" "<<m_mgAssignps[0]<<endl);
            if (items >= RELOOP_MIN_ITERS) {
                UINFO(6, "Reloop merging items="<<items<<" "<<m_mgIndexHi<<":"<<m_mgIndexLo
                      <<" "<<m_mgAssignps[0]<<endl);
                ++m_statReloops;
                m_statReItems += items;

                // Transform first assign into for loop body
                AstNodeAssign* bodyp = m_mgAssignps.front();
                if (bodyp->lhsp() != m_mgSelLp) bodyp->v3fatalSrc("Corrupt queue/state");
                FileLine* fl = bodyp->fileline();
                AstVar* itp = findCreateVarTemp(fl, m_mgCfuncp);

                AstNode* initp = new AstAssign(fl, new AstVarRef(fl, itp, true),
                                               new AstConst(fl, m_mgIndexLo));
                AstNode* condp = new AstLte(fl, new AstVarRef(fl, itp, false),
                                            new AstConst(fl, m_mgIndexHi));
                AstNode* incp = new AstAssign(fl, new AstVarRef(fl, itp, true),
                                              new AstAdd(fl, new AstConst(fl, 1),
                                                         new AstVarRef(fl, itp, false)));
                AstWhile* whilep = new AstWhile(fl, condp, NULL, incp);
                initp->addNext(whilep);
                bodyp->replaceWith(initp);
                whilep->addBodysp(bodyp);

                // Replace constant index with new loop index
                AstNode* lbitp = m_mgSelLp->bitp();
                lbitp->replaceWith(new AstVarRef(fl, itp, false));
                lbitp->deleteTree(); VL_DANGLING(lbitp);
                if (m_mgSelRp) {  // else constant and no replace
                    AstNode* rbitp = m_mgSelRp->bitp();
                    rbitp->replaceWith(new AstVarRef(fl, itp, false));
                    rbitp->deleteTree(); VL_DANGLING(lbitp);
                }
                if (debug()>=9) initp->dumpTree(cout, "-new: ");
                if (debug()>=9) whilep->dumpTree(cout, "-new: ");

                // Remove remaining assigns
                for (AssVec::iterator it=m_mgAssignps.begin(); it!=m_mgAssignps.end(); ++it) {
                    AstNodeAssign* assp = *it;
                    if (assp != bodyp) {
                        assp->unlinkFrBack()->deleteTree(); VL_DANGLING(assp);
                    }
                }
            }
            // Setup for next merge
            m_mgAssignps.clear();
            m_mgSelLp = NULL;
            m_mgSelRp = NULL;
            m_mgVarrefLp = NULL;
            m_mgVarrefRp = NULL;
            m_mgConstRp = NULL;
        }
    }
Beispiel #2
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;
    }
    virtual void visit(AstSenItem* nodep, AstNUser*) {
	// Remove bit selects, and bark if it's not a simple variable
	nodep->iterateChildren(*this);
	if (nodep->isClocked()) {
	    // If it's not a simple variable wrap in a temporary
	    // This is a bit unfortunate as we haven't done width resolution
	    // and any width errors will look a bit odd, but it works.
	    AstNode* sensp = nodep->sensp();
	    if (sensp
		&& !sensp->castNodeVarRef()
		&& !sensp->castConst()) {
		// Make a new temp wire
		string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum);
		AstVar* newvarp = new AstVar (sensp->fileline(), AstVarType::MODULETEMP, newvarname,
					      VFlagLogicPacked(), 1);
		// We can't just add under the module, because we may be inside a generate, begin, etc.
		// We know a SenItem should be under a SenTree/Always etc, we we'll just hunt upwards
		AstNode* addwherep = nodep;  // Add to this element's next
		while (addwherep->castSenItem()
		       || addwherep->castSenTree()) {
		    addwherep = addwherep->backp();
		}
		if (!addwherep->castAlways()) {  // Assertion perhaps?
		    sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under some complicated block");
		    addwherep = m_modp;
		}
		addwherep->addNext(newvarp);

		sensp->replaceWith(new AstVarRef (sensp->fileline(), newvarp, false));
		AstAssignW* assignp = new AstAssignW
		    (sensp->fileline(),
		     new AstVarRef(sensp->fileline(), newvarp, true),
		     sensp);
		addwherep->addNext(assignp);
	    }
	} else {  // Old V1995 sensitivity list; we'll probably mostly ignore
	    bool did=1;
	    while (did) {
		did=0;
		if (AstNodeSel* selp = nodep->sensp()->castNodeSel()) {
		    AstNode* fromp = selp->fromp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
		// NodeSel doesn't include AstSel....
		if (AstSel* selp = nodep->sensp()->castSel()) {
		    AstNode* fromp = selp->fromp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
		if (AstNodePreSel* selp = nodep->sensp()->castNodePreSel()) {
		    AstNode* fromp = selp->lhsp()->unlinkFrBack();
		    selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
		    did=1;
		}
	    }
	}
	if (!nodep->sensp()->castNodeVarRef()
	    && !nodep->sensp()->castEnumItemRef()) {  // V3Const will cleanup
	    if (debug()) nodep->dumpTree(cout,"-tree: ");
	    nodep->v3error("Unsupported: Complex statement in sensitivity list");
	}
    }
    void replaceBoundLvalue(AstNode* nodep, AstNode* condp) {
	// Spec says a out-of-range LHS SEL results in a NOP.
	// This is a PITA.  We could:
	//  1. IF(...) around an ASSIGN,
	//     but that would break a "foo[TOO_BIG]=$fopen(...)".
	//  2. Hack to extend the size of the output structure
	//     by one bit, and write to that temporary, but never read it.
	//     That makes there be two widths() and is likely a bug farm.
	//  3. Make a special SEL to choose between the real lvalue
	//     and a temporary NOP register.
	//  4. Assign to a temp, then IF that assignment.
	//     This is suspected to be nicest to later optimizations.
	// 4 seems best but breaks later optimizations.  3 was tried,
	// but makes a mess in the emitter as lvalue switching is needed.  So 4.
	// SEL(...) -> temp
	//             if (COND(LTE(bit<=maxlsb))) ASSIGN(SEL(...)),temp)
	if (m_assignwp) {
	    // Wire assigns must become always statements to deal with insertion
	    // of multiple statements.  Perhaps someday make all wassigns into always's?
	    UINFO(5,"     IM_WireRep  "<<m_assignwp<<endl);
	    m_assignwp->convertToAlways(); pushDeletep(m_assignwp); m_assignwp=NULL;
	}
	bool needDly = (m_assigndlyp != NULL);
	if (m_assigndlyp) {
	    // Delayed assignments become normal assignments,
	    // then the temp created becomes the delayed assignment
	    AstNode* newp = new AstAssign(m_assigndlyp->fileline(),
					  m_assigndlyp->lhsp()->unlinkFrBackWithNext(),
					  m_assigndlyp->rhsp()->unlinkFrBackWithNext());
	    m_assigndlyp->replaceWith(newp); pushDeletep(m_assigndlyp); m_assigndlyp=NULL;
	}
	AstNode* prep = nodep;

	// Scan back to put the condlvalue above all selects (IE top of the lvalue)
	while (prep->backp()->castNodeSel()
	       || prep->backp()->castSel()) {
	    prep=prep->backp();
	}
	FileLine* fl = nodep->fileline();
	VL_DANGLING(nodep);  // Zap it so we don't use it by mistake - use prep

	// Already exists; rather than IF(a,... IF(b... optimize to IF(a&&b,
	// Saves us teaching V3Const how to optimize, and it won't be needed again.
	if (AstIf* ifp = prep->user2p()->castIf()) {
	    if (needDly) prep->v3fatalSrc("Should have already converted to non-delay");
	    AstNRelinker replaceHandle;
	    AstNode* earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
	    AstNode* newp = new AstLogAnd (condp->fileline(),
					   condp,
					   earliercondp);
	    UINFO(4, "Edit BOUNDLVALUE "<<newp<<endl);
	    replaceHandle.relink(newp);
	}
	else {
	    string name = ((string)"__Vlvbound"+cvtToStr(m_modp->varNumGetInc()));
	    AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name,
				      prep->dtypep());
	    m_modp->addStmtp(varp);

	    AstNode* abovep = prep->backp();  // Grab above point before lose it w/ next replace
	    prep->replaceWith(new AstVarRef(fl, varp, true));
	    AstNode* newp = new AstIf(fl, condp,
				      (needDly
				       ? static_cast<AstNode*>
				       (new AstAssignDly(fl, prep,
							 new AstVarRef(fl, varp, false)))
				       : static_cast<AstNode*>
				       (new AstAssign   (fl, prep,
							 new AstVarRef(fl, varp, false)))),
				      NULL);
	    if (debug()>=9) newp->dumpTree(cout,"     _new: ");
	    abovep->addNextStmt(newp,abovep);
	    prep->user2p(newp);  // Save so we may LogAnd it next time
	}
    }