예제 #1
0
    virtual void runTest() {
	V3Graph* gp = &m_graph;
	// Verify we break edges at a good point
	// A simple alg would make 3 breaks, below only requires b->i to break
	V3GraphTestVertex* i	= new V3GraphTestVarVertex(gp,"*INPUTS*");
	V3GraphTestVertex* a	= new V3GraphTestVarVertex(gp,"a");
	V3GraphTestVertex* b	= new V3GraphTestVarVertex(gp,"b");
	V3GraphTestVertex* g1	= new V3GraphTestVarVertex(gp,"g1");
	V3GraphTestVertex* g2	= new V3GraphTestVarVertex(gp,"g2");
	V3GraphTestVertex* g3	= new V3GraphTestVarVertex(gp,"g3");
	V3GraphTestVertex* q	= new V3GraphTestVarVertex(gp,"q");
	new V3GraphEdge(gp, i, a, 2, true);
	new V3GraphEdge(gp, a, b, 2, true);
	new V3GraphEdge(gp, b, g1, 2, true);
	new V3GraphEdge(gp, b, g2, 2, true);
	new V3GraphEdge(gp, b, g3, 2, true);
	new V3GraphEdge(gp, g1, a, 2, true);
	new V3GraphEdge(gp, g3, g2, 2, true);
	new V3GraphEdge(gp, g2, g3, 2, true);
	new V3GraphEdge(gp, g1, q, 2, true);
	new V3GraphEdge(gp, g2, q, 2, true);
	new V3GraphEdge(gp, g3, q, 2, true);

	gp->stronglyConnected(&V3GraphEdge::followAlwaysTrue);
	dump();

	UASSERT(i->color()!=a->color() && a->color() != g2->color() && g2->color() != q->color(), "Separate colors not assigned");
	UASSERT(a->color()==b->color() && a->color()==g1->color(), "Strongly connected nodes not colored together");
	UASSERT(g2->color()==g3->color(), "Strongly connected nodes not colored together");
    }
예제 #2
0
void GateVisitor::consumedMark() {
    // Propagate consumed signals backwards to all producers into a consumed node
    m_graph.userClearVertices();
    for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	GateEitherVertex* evertexp = (GateEitherVertex*)vertexp;
	if (!evertexp->user() && evertexp->consumed()) {
	    consumedMarkRecurse(evertexp);
	}
    }
}
예제 #3
0
    void newAlwaysTrees(AstAlways* nodep) {
	// Across all variables we're moving
	uint32_t lastColor = 0;
	AstNode* lastExprp = NULL;
	for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	    if (GaterVarVertex* vVxp = dynamic_cast<GaterVarVertex*>(vertexp)) {
		if (!lastExprp || lastColor != vVxp->color()) {
		    lastColor = vVxp->color();
		    // Create the block we've just finished
		    if (lastExprp) newAlwaysTree(nodep, lastExprp); // Duplicate below
		    // New expression for this color
		    lastExprp = newExprFromGraph(vVxp);
		}
		// Mark variable to move
		if (vVxp->nodep()->user2p()) vVxp->nodep()->v3fatalSrc("One variable got marked under two gaters");
		vVxp->nodep()->user2p(lastExprp);
		m_statBits += vVxp->nodep()->width();  // Moving a wide bus counts more!
		// There shouldn't be two possibilities we want to
		// move to, IE {A,B} <= Z because we marked such
		// things as unoptimizable
	    }
	}
	// Create the final block we've just finished
	if (lastExprp) newAlwaysTree(nodep, lastExprp);   // Duplicate above
    }
예제 #4
0
void GateVisitor::warnSignals() {
    AstNode::user2ClearTree();
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    AstVarScope* vscp = vvertexp->varScp();
	    AstNode* sp = vvertexp->rstSyncNodep();
	    AstNode* ap = vvertexp->rstAsyncNodep();
	    if (ap && sp && !vscp->varp()->user2()) {
		// This is somewhat wrong, as marking one flop as ok for sync
		// may mean a different flop now fails.  However it's a pain to
		// then report a warning in a new place - we should report them all at once.
		// Instead we'll disable if any disabled
		if (!vscp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
		    && !ap->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
		    && !sp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
		    ) {
		    vscp->varp()->user2(true);  // Warn only once per signal
		    vscp->v3warn(SYNCASYNCNET,"Signal flopped as both synchronous and async: "<<vscp->prettyName()<<endl
				 <<ap->warnMore()<<"... Location of async usage"<<endl
				 <<sp->warnMore()<<"... Location of sync usage"<<endl);
		}
	    }
	}
    }
}
예제 #5
0
    // METHODS -- GRAPH stuff
    void simplifyGraph() {
	if (debug()>=9) m_graph.dumpDotFilePrefixed("gater_init", false);

	// We now have all PLI variables with edges FROM the pli vertex
	simplifyPli();
	if (debug()>=9) m_graph.dumpDotFilePrefixed("gater_pli", false);

	// Any vertex that points along both true & false path to variable
	// can be simplfied so parent points to that vertex.  Any vertex
	// that points to a (great...) grandparent of a variable can just
	// point to the edge.
	m_graph.userClearVertices();	// user() will contain VarUsage
	simplifyIfElseRecurse(m_headVertexp);
	if (debug()>=9) m_graph.dumpDotFilePrefixed("gater_ifelse", false);

	m_graph.userClearVertices();	// user() will contain VarUsage
	simplifyGrandRecurse(m_headVertexp, 1);
	if (debug()>=9) m_graph.dumpDotFilePrefixed("gater_grand", false);

	simplifyRemoveUngated(m_headVertexp);

	// Give all signals with same gating term same color
	graphColorSameFeeder();

	if (debug()>=9) m_graph.dumpDotFilePrefixed("gater_done", false);
    }
예제 #6
0
void GateVisitor::mergeAssigns() {
    GateMergeAssignsGraphVisitor merger(&m_graph);
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    merger.mergeAssignsTree(vvertexp);
	}
    }
    m_statAssignMerged += merger.numMergedAssigns();
}
예제 #7
0
    // VISITORS
    virtual void visit(AstNetlist* nodep, AstNUser*) {
	nodep->iterateChildren(*this);
	//if (debug()>6) m_graph.dump();
	if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre");
	m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue);
	m_graph.dumpDotFilePrefixed("gate_simp");
	// Find gate interconnect and optimize
	m_graph.userClearVertices();	// vertex->user(): bool.  True indicates we've set it as consumed
	// Get rid of buffers first,
	optimizeSignals(false);
	// Then propagate more complicated equations
	optimizeSignals(true);
	// Warn
	warnSignals();
	consumedMark();
	m_graph.dumpDotFilePrefixed("gate_opt");
	// Rewrite assignments
	consumedMove();
	replaceAssigns();
    }
예제 #8
0
void GateVisitor::dedupe() {
    AstNode::user2ClearTree();
    GateDedupeGraphVisitor deduper;
    // Traverse starting from each of the clocks
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    if (vvertexp->isClock()) {
		deduper.dedupeTree(vvertexp);
	    }
	}
    }
    // Traverse starting from each of the outputs
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    if (vvertexp->isTop() && vvertexp->varScp()->varp()->isOutput()) {
		deduper.dedupeTree(vvertexp);
	    }
	}
    }
    m_statDedupLogic += deduper.numDeduped();
}
예제 #9
0
파일: V3Split.cpp 프로젝트: jeras/verilator
    void scoreboardClear() {
	//VV*****  We reset user1p() and user2p on each block!!!
	m_inDly = false;
	m_graph.clear();
	m_stmtStackps.clear();
	m_pliVertexp = NULL;
	m_noReorderWhy = "";
	AstNode::user1ClearTree();
	AstNode::user2ClearTree();
	AstNode::user3ClearTree();
	AstNode::user4ClearTree();
    }
예제 #10
0
    virtual void runTest() {
	V3Graph* gp = &m_graph;
	// Verify we break edges at a good point
	// A simple alg would make 3 breaks, below only requires b->i to break
	V3GraphTestVertex* i	= new V3GraphTestVarVertex(gp,"*INPUTS*");
	V3GraphTestVertex* a	= new V3GraphTestVarVertex(gp,"a");
	V3GraphTestVertex* b	= new V3GraphTestVarVertex(gp,"b");
	V3GraphTestVertex* g1	= new V3GraphTestVarVertex(gp,"g1");
	V3GraphTestVertex* g2	= new V3GraphTestVarVertex(gp,"g2");
	V3GraphTestVertex* g3	= new V3GraphTestVarVertex(gp,"g3");
	new V3GraphEdge(gp, i, a, 2, true);
	new V3GraphEdge(gp, a, b, 2, true);
	new V3GraphEdge(gp, b, g1, 2, true);
	new V3GraphEdge(gp, b, g2, 2, true);
	new V3GraphEdge(gp, b, g3, 2, true);
	new V3GraphEdge(gp, g1, a, 2, true);
	new V3GraphEdge(gp, g2, a, 2, true);
	new V3GraphEdge(gp, g3, a, 2, true);

	gp->acyclic(&V3GraphEdge::followAlwaysTrue);
	gp->order();
	dump();
    }
예제 #11
0
    // VISITORS
    virtual void visit(AstAlways* nodep, AstNUser*) {
	if (debug()>=9) cout<<endl<<endl<<endl;
	UINFO(5, "Gater: ALWAYS: "<<nodep<<endl);
	if (nodep->user4Inc()) return;

	clear();

	if (debug()>=9) nodep->dumpTree(cout,"  Alwin:  ");

	// Look for constructs we can't optimize
	// Form graph with Vertices at each IF, and each Variable
	m_aboveTrue = VU_IF | VU_ELSE;
	iterateChildrenAlw(nodep, true);

	// Other reasons to not optimize
	if (!m_numIfs) nonOptimizable(nodep, "No if statements");

	// Something to optimize, oh my!
	if (m_nonopt!="") {
	    UINFO(5, "  Gater non-opt: "<<m_nonopt<<endl);
	} else {
	    // Process it
	    simplifyGraph();

	    // See how much moves
	    uint32_t lastColor = 0;
	    for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
		if (GaterVarVertex* vVxp = dynamic_cast<GaterVarVertex*>(vertexp)) {
		    if (lastColor < vVxp->color()) {
			lastColor = vVxp->color();
		    }
		}
	    }
	    if (lastColor == 0) { // Nothing we moved!
		nonOptimizable(nodep, "Nothing moved");
	    }
	    else if (lastColor > DOMAINS_MAX) {
		// Our move algorithm is fairly slow and if we're splitting
		// up too much it'll get really nasty.  It's probably a bad
		// move for performance to split too much, anyhow, as the
		// number of gaters will result in calling many small c functions.
		nonOptimizable(nodep, "Too much moved");
	    }
	    if (m_nonopt=="") {
		newAlwaysTrees(nodep);
		if (debug()>=9) nodep->dumpTree(cout,"  Gaterout: ");
	    }
	}
	UINFO(5, "  Gater done"<<endl);
    }
예제 #12
0
    void clear() {
	m_nonopt = "";
	m_directlyUnderAlw = false;
	m_ifDepth = 0;
	m_numIfs = 0;
	AstNode::user1ClearTree();
	AstNode::user2ClearTree();
	// Prepare graph
	m_graph.clear();
	GaterVertex::clearRank();
	m_pliVertexp = NULL;
	m_headVertexp = new GaterHeadVertex(&m_graph);
	m_aboveVertexp = m_headVertexp;
	m_aboveTrue = false;
	m_stmtVscp = NULL;
	m_stmtInPli = false;
    }
예제 #13
0
파일: V3Split.cpp 프로젝트: jeras/verilator
 void pruneDepsOnInputs() {
     for (V3GraphVertex* vertexp = m_graph.verticesBeginp();
          vertexp; vertexp=vertexp->verticesNextp()) {
         if (!vertexp->outBeginp()
             && dynamic_cast<SplitVarStdVertex*>(vertexp)) {
             if (debug() >= 9) {
                 SplitVarStdVertex* stdp = (SplitVarStdVertex*)(vertexp);
                 UINFO(0, "Will prune deps on var "<<stdp->nodep()<<endl);
                 stdp->nodep()->dumpTree(cout, "- ");
             }
             for (V3GraphEdge* edgep = vertexp->inBeginp();
                  edgep; edgep=edgep->inNextp()) {
                 SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
                 oedgep->setIgnoreThisStep();
             }
         }
     }
 }
예제 #14
0
void GateVisitor::consumedMove() {
    // Remove unused logic (logic that doesn't hit a combo block or a display statement)
    // We need the "usually" block logic to do a better job at this
    for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(vertexp)) {
	    if (!vvertexp->consumed() && !vvertexp->user()) {
		UINFO(8, "Unconsumed "<<vvertexp->varScp()<<endl);
	    }
	}
	if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(vertexp)) {
	    AstNode* nodep = lvertexp->nodep();
	    AstActive* oldactp = lvertexp->activep();  // NULL under cfunc
	    if (!lvertexp->consumed() && oldactp) {
		// Eventually: Move the statement to a new active block with "tracing-on" sensitivity
		UINFO(8,"    Remove unconsumed "<<nodep<<endl);
		nodep->unlinkFrBack();
		pushDeletep(nodep); VL_DANGLING(nodep);
	    }
	}
    }
}
예제 #15
0
    void simplifyPli() {
	// For now, we'll not gate any logic with PLI lvariables in it.  In
	// the future we may move PLI statements.  One way to do so is to
	// all below pli VARs to go IfVertex -> PliVertex -> VarVertex then
	// they all must get colored the same. There may be a lot of
	// duplicated edges to the PLI; they'll need cleanup.  All of the
	// later optimizations need to deal, and the GaterBodyVisitor needs
	// to know how to move them.
	if (m_pliVertexp) {
	    // Follow PLI out edges to find all relevant variables
	    for (V3GraphEdge* nextp,* edgep = m_pliVertexp->outBeginp(); edgep; edgep = nextp) {
		nextp = edgep->outNextp();  // We may edit the list
		if (GaterVarVertex* vVxp = dynamic_cast<GaterVarVertex*>(edgep->top())) {
		    vVxp->unlinkDelete(&m_graph); vVxp=NULL; edgep=NULL;
		} else {
		    m_graph.dump();
		    v3fatalSrc("PLI vertex points to non-signal");
		}
	    }
	    m_pliVertexp->unlinkDelete(&m_graph); m_pliVertexp = NULL;
	}
    }
예제 #16
0
void GateVisitor::replaceAssigns() {
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    // Take the Comments/assigns that were moved to the VarScope and change them to a
	    // simple value assignment
	    AstVarScope* vscp = vvertexp->varScp();
	    if (vscp->valuep() && !vscp->valuep()->castNodeMath()) {
		//if (debug()>9) vscp->dumpTree(cout, "-vscPre:  ");
		while (AstNode* delp=vscp->valuep()->castComment()) {
		    delp->unlinkFrBack()->deleteTree(); VL_DANGLING(delp);
		}
		if (AstInitial* delp=vscp->valuep()->castInitial()) {
		    AstNode* bodyp=delp->bodysp();
		    bodyp->unlinkFrBackWithNext();
		    delp->replaceWith(bodyp);
		    delp->deleteTree(); VL_DANGLING(delp);
		}
		if (AstAlways* delp=vscp->valuep()->castAlways()) {
		    AstNode* bodyp=delp->bodysp();
		    bodyp->unlinkFrBackWithNext();
		    delp->replaceWith(bodyp);
		    delp->deleteTree(); VL_DANGLING(delp);
		}
		if (AstNodeAssign* delp=vscp->valuep()->castNodeAssign()) {
		    AstNode* rhsp=delp->rhsp();
		    rhsp->unlinkFrBack();
		    delp->replaceWith(rhsp);
		    delp->deleteTree(); VL_DANGLING(delp);
		}
		//if (debug()>9) {vscp->dumpTree(cout, "-vscDone: "); cout<<endl;}
		if (!vscp->valuep()->castNodeMath()
		    || vscp->valuep()->nextp()) {
		    vscp->dumpTree(cerr, "vscStrange: ");
		    vscp->v3fatalSrc("Value of varscope not mathematical\n");
		}
	    }
	}
    }
}
예제 #17
0
    void graphColorSameFeeder() {
	// Assign same color to all destination vertices that have same
	// subgraph feeding into them
	// (I.E. all "from" nodes are common within each color)
	// We could hash, but instead it's faster to sort edges, so we know
	// the same edge list is always adjacent.  The result is a
	// O(vertices*edges) loop, but we'd need that to hash too.
	if (debug()>9) { cout<<"PreColor:\n"; m_graph.dump(); }

	m_graph.sortEdges();

	// Now sort vertices, so same inbound edge set ends up adjacent
	m_graph.sortVertices();

	// Now walk and assign colors; same color is adjacent
	m_graph.clearColors();
	m_graph.userClearEdges(); // Used by newExprFromGraph
	uint32_t color = 1;
	GaterVarVertex* lastVxp	= NULL;
	for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	    if (GaterVarVertex* vVxp = dynamic_cast<GaterVarVertex*>(vertexp)) {
		if (!vVxp->inBeginp()) {
		    // At this point, any variable not linked is an error
		    // (It should have at least landed under the Head node)
		    vVxp->nodep()->v3fatalSrc("Variable became stranded in clk gate detection\n");
		}
		if (!lastVxp || vVxp->sortCmp(lastVxp)) {
		    // Different sources for this new node
		    color++;
		}
		vVxp->color(color);
		lastVxp = vVxp;
	    }
	}

	if (debug()>9) { cout<<"PostColor:\n"; m_graph.dump(); }
    }
예제 #18
0
    void cleanupBlockGraph(AstNode* nodep) {
	// Transform the graph into what we need
	UINFO(5, "ReorderBlock "<<nodep<<endl);
	m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);

	if (debug()>=9) {
	    m_graph.dumpDotFilePrefixed("splitg_nodup", false);
	    //m_graph.dump(); cout<<endl;
	}

	// Mark all the logic for this step
	// Vertex::m_user begin: true indicates logic for this step
	m_graph.userClearVertices();
	for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
	    SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
	    vvertexp->user(true);
	}

	// If a var vertex has only inputs, it's a input-only node,
	// and can be ignored for coloring **this block only**
	SplitEdge::incrementStep();
	uint32_t numVertexes = 1;  // As colors start at 1, not 0
	for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	    numVertexes++;
	    if (!vertexp->outBeginp() && dynamic_cast<SplitVarStdVertex*>(vertexp)) {
		for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
		    SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
		    oedgep->setIgnoreThisStep();
		}
	    }
	    // Mark all logic vertexes not involved with this step as unimportant
	    if (SplitLogicVertex* vvertexp = dynamic_cast<SplitLogicVertex*>(vertexp)) {
		if (!vvertexp->user()) {
		    for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
			SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
			oedgep->setIgnoreThisStep();
		    }
		    for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
			SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
			oedgep->setIgnoreThisStep();
		    }
		}
	    }
	}

	// Weak coloring to determine what needs to remain in order
	// This follows all step-relevant edges excluding PostEdges, which are done later
	m_graph.weaklyConnected(&SplitEdge::followScoreboard);

	// Add hard orderings between all nodes of same color, in the order they appeared
	vector<SplitLogicVertex*> lastOfColor;  lastOfColor.resize(numVertexes);
	for (uint32_t i=0; i<numVertexes; i++) lastOfColor[i] = NULL;
	for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
	    SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
	    vvertexp->splitColor(vvertexp->color());
	    uint32_t color = vvertexp->splitColor();
	    if (color >= numVertexes) nextp->v3fatalSrc("More colors than vertexes!\n");
	    if (!color) nextp->v3fatalSrc("No node color assigned\n");
	    if (lastOfColor[color]) {
		new SplitStrictEdge(&m_graph, lastOfColor[color], vvertexp);
	    }
	    lastOfColor[color] = vvertexp;
	}

	// And a real ordering to get the statements into something reasonable
	// We don't care if there's cutable violations here...
	// Non-cutable violations should be impossible; as those edges are program-order
	if (debug()>=9) m_graph.dumpDotFilePrefixed((string)"splitg_preo", false);
	m_graph.acyclic(&SplitEdge::followCyclic);
	m_graph.rank(&SplitEdge::followCyclic);  // Or order(), but that's more expensive
	if (debug()>=9) m_graph.dumpDotFilePrefixed((string)"splitg_opt", false);
    }
예제 #19
0
    virtual void runTest() {
	V3Graph* gp = &m_graph;

	V3GraphTestVertex* clk	= new V3GraphTestVarVertex(gp,"$clk");

	V3GraphTestVertex* a	= new V3GraphTestVarVertex(gp,"$a");
	V3GraphTestVertex* a_dly	= new V3GraphTestVarVertex(gp,"$a_dly");
	V3GraphTestVertex* a_dlyblk= new V3GraphTestVarVertex(gp,"$a_dlyblk");
	V3GraphTestVertex* b	= new V3GraphTestVarVertex(gp,"$b");
	V3GraphTestVertex* b_dly	= new V3GraphTestVarVertex(gp,"$b_dly");
	V3GraphTestVertex* b_dlyblk= new V3GraphTestVarVertex(gp,"$b_dlyblk");
	V3GraphTestVertex* c	= new V3GraphTestVarVertex(gp,"$c");
	V3GraphTestVertex* i	= new V3GraphTestVarVertex(gp,"$i");

	V3GraphTestVertex* ap	= new V3GraphTestVarVertex(gp,"$a_pre");
	V3GraphTestVertex* bp	= new V3GraphTestVarVertex(gp,"$b_pre");
	V3GraphTestVertex* cp	= new V3GraphTestVarVertex(gp,"$c_pre");

	V3GraphTestVertex* n;

	// Logical order between clk, and posedge blocks
	//   implemented by special CLK prod/cons?
	// Required order between first x_DLY<=x_pre and final x<=x_DLY
	//   implemented by producer/consumer on a_dly signals
	// Required order between first x_DLY<=x_pre and x_DLY<=setters
	//   implemented by fake dependency on _dlyblk
	// Required order between x_DLY<=setters and final x<=x_DLY
	//   implemented by producer/consumer on a_dly signals
	// Desired order between different _DLY blocks so we can elim temporaries
	//   implemented by cutable "pre" signal dependencies


	n = new V3GraphTestVertex(gp,"*INPUTS*"); {
	    new V3GraphEdge(gp, n, clk, 2);
	    new V3GraphEdge(gp, n, i, 2);
	}

	V3GraphTestVertex* posedge = n = new V3GraphTestVertex(gp,"*posedge clk*"); {
	    new V3GraphEdge(gp, clk, n, 2);
	}

	// AssignPre's     VarRefs on LHS:  generate special BLK
	//    normal:      VarRefs on LHS:  generate normal
	//    underSBlock: VarRefs on RHS:  consume 'pre' (required to save cutable tests)
	n = new V3GraphTestVertex(gp,"a_dly<PRE=a"); {
	    new V3GraphEdge(gp, n, a_dlyblk, 2);  // Block ordering
	    new V3GraphEdge(gp, n, a_dly, 2);
	    new V3GraphEdge(gp, ap, n, 2, true);   // DESIRED delayed ordering (inp is required)
	    new V3GraphEdge(gp, posedge, n, 2);
	}
	n = new V3GraphTestVertex(gp,"b_dly<PRE=b"); {
	    new V3GraphEdge(gp, n, b_dlyblk, 2);  // Block ordering
	    new V3GraphEdge(gp, n, b_dly, 2);
	    new V3GraphEdge(gp, bp, n, 2, true);   // DESIRED delayed ordering
	    new V3GraphEdge(gp, posedge, n, 2);
	}

	// AssignDly's     VarRefs on LHS:  consume special BLK
	//    normal:      VarRefs on LHS:  generate normal
	//    underSBlock: VarRefs on RHS:  generate 'pre' signals (cutable)
	//    SenItems:    consume CLOCK dependency
	n = new V3GraphTestVertex(gp,"a_dly<=b|c"); {
	    new V3GraphEdge(gp, a_dlyblk, n, 2);  // Block ordering in
	    new V3GraphEdge(gp, n, a_dly, 2);
	    // Note we don't include ap as we're generating a_dly
	    new V3GraphEdge(gp, n, bp, 2);   // DESIRED delayed usage
	    new V3GraphEdge(gp, n, cp, 2);   // DESIRED delayed usage
	    new V3GraphEdge(gp, posedge, n, 2);
	}
	n = new V3GraphTestVertex(gp,"b_dly<=a"); {
	    new V3GraphEdge(gp, b_dlyblk, n, 2);  // Block ordering in
	    new V3GraphEdge(gp, n, b_dly, 2);
	    new V3GraphEdge(gp, n, ap, 2);   // DESIRED delayed usage
	    new V3GraphEdge(gp, posedge, n, 2);
	}

	// AssignPost's
	//    normal:      VarRefs on LHS:  generate normal
	//    underSBlock: VarRefs on RHS:  consume normal
	n = new V3GraphTestVertex(gp,"a=POST=a_dly"); {
	    new V3GraphEdge(gp, n, a, 3);
	    new V3GraphEdge(gp, a_dly, n, 3);
	    new V3GraphEdge(gp, posedge, n, 2);
	}
	n = new V3GraphTestVertex(gp,"b=POST=b_dly"); {
	    new V3GraphEdge(gp, n, b, 3);
	    new V3GraphEdge(gp, b_dly, n, 3);
	    new V3GraphEdge(gp, posedge, n, 2);
	}

	// COMBO
	// Inbound edges are always uncutable, because we must put combo logic after sequential
	// Outbound are cutable, as we may need to evaluate multiple times

	{
	    V3GraphTestVertex* n	= new V3GraphTestVertex(gp,"c=a|b|i");
	    new V3GraphEdge(gp, n, c, 1, true);
	    new V3GraphEdge(gp, a, n, 1, false);
	    new V3GraphEdge(gp, b, n, 1, false);
	    new V3GraphEdge(gp, i, n, 1, false);
	}

	gp->acyclic(&V3GraphEdge::followAlwaysTrue);
	gp->order();

	dump();
    }
예제 #20
0
void GateVisitor::optimizeSignals(bool allowMultiIn) {
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    if (vvertexp->inEmpty()) {
		vvertexp->clearReducibleAndDedupable("inEmpty");	// Can't deal with no sources
		if (!vvertexp->isTop()		// Ok if top inputs are driverless
		    && !vvertexp->varScp()->varp()->valuep()
		    && !vvertexp->varScp()->varp()->isSigPublic()) {
		    UINFO(4, "No drivers "<<vvertexp->varScp()<<endl);
		    if (0) {
			// If we warned here after constant propagation, what the user considered
			// reasonable logic may have disappeared.  Issuing a warning would
			// thus be confusing.  V3Undriven now handles this.
			vvertexp->varScp()->varp()->v3warn(UNDRIVEN,"Signal has no drivers "
							   <<vvertexp->scopep()->prettyName()<<"."
							   <<vvertexp->varScp()->varp()->prettyName());
		    }
		}
	    }
	    else if (!vvertexp->inSize1()) {
		vvertexp->clearReducibleAndDedupable("size!1");	// Can't deal with more than one src
	    }
	    // Reduce it?
	    if (!vvertexp->reducible()) {
		UINFO(8, "SigNotRed "<<vvertexp->name()<<endl);
	    } else {
		UINFO(8, "Sig "<<vvertexp->name()<<endl);
		GateLogicVertex* logicVertexp = dynamic_cast<GateLogicVertex*>
		    (vvertexp->inBeginp()->fromp());
		UINFO(8, "  From "<<logicVertexp->name()<<endl);
		AstNode* logicp = logicVertexp->nodep();
		if (logicVertexp->reducible()) {
		    // Can we eliminate?
		    GateOkVisitor okVisitor(logicp, vvertexp->isClock(), false);
		    bool multiInputs = okVisitor.rhsVarRefs().size() > 1;
		    // Was it ok?
		    bool doit = okVisitor.isSimple();
		    if (doit && multiInputs) {
			if (!allowMultiIn) doit = false;
			// Doit if one input, or not used, or used only once, ignoring traces
			int n=0;
			for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
			    GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->top());
			    if (!consumeVertexp->slow()) { // Not tracing or other slow path junk
				if (edgep->top()->outBeginp()) {  // Destination is itself used
				    n += edgep->weight();
				}
			    }
			    if (n>1) {
				doit = false;
				break;
			    }
			}
		    }
		    // Process it
		    if (!doit) {
			if (allowMultiIn && (debug()>=9)) {
			    UINFO(9, "Not ok simp"<<okVisitor.isSimple()<<" mi"<<multiInputs
				  <<" ob"<<vvertexp->outBeginp()<<" on"<<(vvertexp->outBeginp()?vvertexp->outBeginp()->outNextp():0)
				  <<" "<<vvertexp->name()
				  <<endl);
			    for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
				GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->top());
				UINFO(9, "    edge "<<edgep<<" to: "<<consumeVertexp->nodep()<<endl);
			    }
			    for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
				GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->fromp());
				UINFO(9, "    edge "<<edgep<<" from: "<<consumeVertexp->nodep()<<endl);
			    }
			}
		    }
		    else {
			AstNode* substp = okVisitor.substTree();
			if (debug()>=5) logicp->dumpTree(cout,"\telimVar:  ");
			if (debug()>=5) substp->dumpTree(cout,"\t  subst:  ");
			++m_statSigs;
			bool removedAllUsages = true;
			for (V3GraphEdge* edgep = vvertexp->outBeginp();
			     edgep; ) {
			    GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->top());
			    AstNode* consumerp = consumeVertexp->nodep();
			    if (!elimLogicOkOutputs(consumeVertexp, okVisitor/*ref*/)) {
				// Cannot optimize this replacement
				removedAllUsages = false;
				edgep = edgep->outNextp();
			    } else {
				optimizeElimVar(vvertexp->varScp(), substp, consumerp);
				// If the new replacement referred to a signal,
				// Correct the graph to point to this new generating variable
				const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs();
				for (GateVarRefList::const_iterator it = rhsVarRefs.begin();
				     it != rhsVarRefs.end(); ++it) {
				    AstVarScope* newvarscp = (*it)->varScopep();
				    UINFO(9,"         Point-to-new vertex "<<newvarscp<<endl);
				    GateVarVertex* varvertexp = makeVarVertex(newvarscp);
				    new V3GraphEdge(&m_graph, varvertexp, consumeVertexp, 1);
				    // Propagate clock attribute onto generating node
				    varvertexp->propagateAttrClocksFrom(vvertexp);
				}
				// Remove the edge
				edgep->unlinkDelete(); VL_DANGLING(edgep);
				++m_statRefs;
				edgep = vvertexp->outBeginp();
			    }
			}
			if (removedAllUsages) {
			    // Remove input links
			    while (V3GraphEdge* edgep = vvertexp->inBeginp()) {
				edgep->unlinkDelete(); VL_DANGLING(edgep);
			    }
			    // Clone tree so we remember it for tracing, and keep the pointer
			    // to the "ALWAYS" part of the tree as part of this statement
			    // That way if a later signal optimization that retained a pointer to the always
			    // can optimize it further
			    logicp->unlinkFrBack();
			    vvertexp->varScp()->valuep(logicp);
			    logicp = NULL;
			    // Mark the vertex so we don't mark it as being unconsumed in the next step
			    vvertexp->user(true);
			    logicVertexp->user(true);
			}
		    }
		}
	    }
	}
    }
}