From e1e4bde125fb64ca2735a4624dbe994926839afe Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 27 Aug 2019 17:51:06 -0400 Subject: [PATCH] Remove old V3ClkGater code --- src/Makefile_obj.in | 1 - src/V3ClkGater.cpp | 924 -------------------------------------------- src/V3ClkGater.h | 37 -- src/V3Graph.h | 5 - src/V3Options.cpp | 2 - src/V3Options.h | 2 - src/Verilator.cpp | 7 - 7 files changed, 978 deletions(-) delete mode 100644 src/V3ClkGater.cpp delete mode 100644 src/V3ClkGater.h diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index d7019eb86..9a084e3d7 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -169,7 +169,6 @@ RAW_OBJS = \ V3Cdc.o \ V3Changed.o \ V3Clean.o \ - V3ClkGater.o \ V3Clock.o \ V3Combine.o \ V3Config.o \ diff --git a/src/V3ClkGater.cpp b/src/V3ClkGater.cpp deleted file mode 100644 index 4cce3f1b5..000000000 --- a/src/V3ClkGater.cpp +++ /dev/null @@ -1,924 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Break always into sensitivity active domains -// -// Code available from: http://www.veripool.org/verilator -// -//************************************************************************* -// -// Copyright 2008-2019 by Wilson Snyder. This program is free software; you can -// redistribute it and/or modify it under the terms of either the GNU -// Lesser General Public License Version 3 or the Perl Artistic License -// Version 2.0. -// -// Verilator is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -//************************************************************************* -// V3ClkGater's Transformations: -// -// Look for clock gaters -// Note there's overlap between this process and V3Split's -// ALWAYS: Build graph -// IF: Form vertex pointing to any IFs or ALWAYS above -// VARREF: Form vertex pointing to IFs it is under -// ASSIGN: If under normal assignment, disable optimization -// FUTURE OPTIMIZE: If signal is set to itself, consider that OK for gating. -// !splitable: Mark all VARREFs in this statement as comming from it -// Optimize graph so if signal is referenced under multiple IF branches it moves up -// Make ALWAYS for each new gating term, and move statements there -//************************************************************************* - -#include "config_build.h" -#include "verilatedos.h" - -#include "V3Global.h" -#include "V3Ast.h" -#include "V3Stats.h" -#include "V3Graph.h" -#include "V3ClkGater.h" - -#include -#include -#include -#include - -//###################################################################### -// Base for debug - -class GaterBaseVisitor : public AstNVisitor { -protected: - VL_DEBUG_FUNC; // Declare debug() -}; - -//###################################################################### -// Support classes - -class GaterVarVertex; - -class GaterVertex : public V3GraphVertex { - static uint32_t s_rankNum; -public: - explicit GaterVertex(V3Graph* graphp) - : V3GraphVertex(graphp) { - s_rankNum++; rank(s_rankNum); - } - virtual ~GaterVertex() {} - virtual int typeNum() const = 0; - static void clearRank() { s_rankNum = 0; } - virtual int sortCmp(const V3GraphVertex* rhsp) const; -}; -uint32_t GaterVertex::s_rankNum = 0; - -class GaterHeadVertex : public GaterVertex { -public: - explicit GaterHeadVertex(V3Graph* graphp) - : GaterVertex(graphp) {} - virtual ~GaterHeadVertex() {} - virtual int typeNum() const { return __LINE__; } // C++ typeof() equivelent - virtual string name() const { return "*HEAD*"; } - virtual string dotColor() const { return "green"; } -}; - -class GaterPliVertex : public GaterVertex { -public: - explicit GaterPliVertex(V3Graph* graphp) - : GaterVertex(graphp) {} - virtual ~GaterPliVertex() {} - virtual int typeNum() const { return __LINE__; } // C++ typeof() equivelent - virtual string name() const { return "*PLI*"; } - virtual string dotColor() const { return "red"; } -}; - -class GaterIfVertex : public GaterVertex { - AstNodeIf* m_nodep; -public: - AstNodeIf* nodep() const { return m_nodep; } - GaterIfVertex(V3Graph* graphp, AstNodeIf* nodep) - : GaterVertex(graphp), m_nodep(nodep) { } - virtual ~GaterIfVertex() {} - virtual int typeNum() const { return __LINE__; } // C++ typeof() equivelent - virtual string name() const { - return cvtToHex(m_nodep)+" {"+cvtToStr(m_nodep->fileline()->lineno())+"}"; } -}; - -class GaterVarVertex : public GaterVertex { - AstVarScope* m_nodep; -public: - AstVarScope* nodep() const { return m_nodep; } - GaterVarVertex(V3Graph* graphp, AstVarScope* nodep) - : GaterVertex(graphp), m_nodep(nodep) { } - virtual ~GaterVarVertex() {} - virtual int typeNum() const { return __LINE__; } // C++ typeof() equivelent - virtual string name() const { return nodep()->name(); } - virtual string dotColor() const { return "skyblue"; } -}; - -//###################################################################### -// Edge types - -class GaterEdge : public V3GraphEdge { - uint32_t m_ifelse; // True branch of if -public: - // These are used as shift amounts into node's user() -#define VU_DEFINE enum VarUsage { VU_NONE=0, VU_IF=1, VU_ELSE=2, VU_PLI=4, VU_MADE=8} - VU_DEFINE; - - uint32_t ifelse() const { return m_ifelse; } - bool ifelseTrue() const { return m_ifelse & VU_IF; } - bool ifelseFalse() const { return m_ifelse & VU_ELSE; } - bool ifelseBoth() const { return ifelseTrue() && ifelseFalse(); } - GaterEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, uint32_t ifelse) - : V3GraphEdge(graphp, fromp, top, 10, false), m_ifelse(ifelse) {} - virtual ~GaterEdge() {} - virtual string dotColor() const { return ((ifelse() & VU_PLI) ? "red" - : (ifelseBoth() ? "blue" - : (ifelseTrue() ? "green" - : "darkgreen"))); } - virtual int sortCmp(const V3GraphEdge* rEdgep) const { - // Our master sort sorts by edges first, so we don't want to - // consider the upstream vertex::sortCmp when sorting by edges. - // We do want to order by something though; rank works - if (fromp()->rank() < rEdgep->fromp()->rank()) return -1; - if (fromp()->rank() > rEdgep->fromp()->rank()) return 1; - // If same, resolve by ifelse - const GaterEdge* crEdgep = static_cast(rEdgep); - if (m_ifelse < crEdgep->m_ifelse) return -1; - if (m_ifelse > crEdgep->m_ifelse) return 1; - return 0; - } -}; - -int GaterVertex::sortCmp(const V3GraphVertex* rhsp) const { - const GaterVertex* crhsp = static_cast(rhsp); - // We really only care about ordering Var's together, but... - // First put same type together - if (typeNum() < crhsp->typeNum()) return -1; - if (typeNum() > crhsp->typeNum()) return 1; - // If variable, group by same input fanin - // (know they're the same type based on above compare) - if (dynamic_cast(this)) { - // We've already sorted by edges, so just see if same tree - // If this gets too slow, we could compute a hash up front - V3GraphEdge* lEdgep = this->inBeginp(); - V3GraphEdge* rEdgep = rhsp->inBeginp(); - while (lEdgep && rEdgep) { - const GaterEdge* clEdgep = static_cast(lEdgep); - const GaterEdge* crEdgep = static_cast(rEdgep); - if (lEdgep->fromp()->rank() < rEdgep->fromp()->rank()) return -1; - if (lEdgep->fromp()->rank() > rEdgep->fromp()->rank()) return 1; - if (clEdgep->ifelse() < crEdgep->ifelse()) return -1; - if (clEdgep->ifelse() > crEdgep->ifelse()) return 1; - lEdgep = lEdgep->inNextp(); - rEdgep = rEdgep->inNextp(); - } - if (!lEdgep && !rEdgep) return 0; - return lEdgep ? -1 : 1; - } - // Finally by rank of this vertex - if (rank() < rhsp->rank()) return -1; - if (rank() > rhsp->rank()) return 1; - return 0; -} - -//###################################################################### -// Check for non-simple gating equations - -class GaterCondVisitor : public GaterBaseVisitor { -private: - // RETURN STATE - bool m_isSimple; // Set false when we know it isn't simple - // METHODS - inline void okIterate(AstNode* nodep) { - if (m_isSimple) iterateChildren(nodep); - } - // VISITORS - virtual void visit(AstOr* nodep) { okIterate(nodep); } - virtual void visit(AstAnd* nodep) { okIterate(nodep); } - virtual void visit(AstNot* nodep) { okIterate(nodep); } - virtual void visit(AstLogOr* nodep) { okIterate(nodep); } - virtual void visit(AstLogAnd* nodep) { okIterate(nodep); } - virtual void visit(AstLogNot* nodep) { okIterate(nodep); } - virtual void visit(AstVarRef* nodep) { okIterate(nodep); } - - // Other possibilities are equals, etc - // But, we don't want to get too complicated or it will take too much - // effort to calculate the gater - - virtual void visit(AstNode* nodep) { - m_isSimple = false; - //iterateChildren(nodep); - } -public: - // CONSTUCTORS - explicit GaterCondVisitor(AstNode* nodep) { - m_isSimple = true; - iterate(nodep); - } - virtual ~GaterCondVisitor() {} - // PUBLIC METHODS - bool isSimple() const { return m_isSimple; } -}; - -//###################################################################### -// Check for non-simple gating equations - -class GaterBodyVisitor : public GaterBaseVisitor { - // NODE STATE - // Input state - // AstVarScope::user2p() -> AstAlways* moving this variable to - - enum State { - // This is used as a bitmask - STATE_UNKNOWN = 0, - STATE_KEEP = 1, // Seen a variable we need, keep this statement - STATE_DELETE = 2 // Seen a variable we need, delete this statement - // 3=keep & delete - }; - - bool m_original; // Deleting original statements, vs deleting new var statements - AstNode* m_exprp; // New gater expression we are building - bool m_cloning; // Clone this object 0=not sure yet, 1=do - uint32_t m_state; // Parsing state - - // VISITORS - virtual void visit(AstVarRef* nodep) { - if (nodep->lvalue()) { - AstVarScope* vscp = nodep->varScopep(); - if (vscp->user2p() == m_exprp) { - // This variable's block needs to move to the new always - if (m_original) { - UINFO(9," VARREF delete in old: "<isStatement()) { - iterateChildren(nodep); - return; - } - uint32_t oldstate = m_state; - // Find if children want to delete this or not. - // Note children may bicker, and want to both keep and delete (branches on a if) - uint32_t childstate; - { - m_state = STATE_UNKNOWN; - iterateChildren(nodep); - childstate = m_state; - } - m_state = oldstate; - UINFO(9," Did state="<unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); - // Pass upwards we did delete - m_state |= STATE_DELETE; - } else { - // Pass upwards we must keep - m_state |= STATE_KEEP; - } - } - virtual void visit(AstNode* nodep) { - iterateChildren(nodep); - } -public: - // CONSTUCTORS - GaterBodyVisitor(AstAlways* nodep, AstNode* exprp, bool original) { - m_exprp = exprp; - m_original = original; - m_state = STATE_UNKNOWN; - m_cloning = false; - if (debug()>=9) nodep->dumpTree(cout, " GateBodyIn: "); - iterateAndNextNull(nodep->bodysp()); - if (debug()>=9) nodep->dumpTree(cout, " GateBodyOut: "); - // If there's no statements we shouldn't have had a resulting graph - // vertex asking for this creation - } - virtual ~GaterBodyVisitor() {} -}; - -//###################################################################### -// Create clock gaters - -class GaterVisitor : public GaterBaseVisitor { - // NODE STATE - // Cleared on Always - // AstVarScope::user1p() -> GaterVarVertex* - // AstAlways::user4() -> bool. True indicates processed - // Cleared on each new Always - // AstVarScope::user2p() -> AstAlways* moving this variable to - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser4InUse m_inuser4; - - // GRAPH STATE - // Cleared on simplify - // Vertex::user() -> VarUsage: Mark of which if/else edges are hit - - // TYPES - VU_DEFINE; - - enum MiscConsts { - IF_DEPTH_MAX = 4, // IFs deep we bother to analyze - DOMAINS_MAX = 32 // Clock domains before avoiding O(N^2) blowup - }; - - // MEMBERS - string m_nonopt; // Reason block is not optimizable - V3Double0 m_statGaters; // Statistic tracking - V3Double0 m_statBits; // Statistic tracking - bool m_directlyUnderAlw; // Immediately under Always or If - int m_ifDepth; // Depth of IF statements - int m_numIfs; // Number of IF statements - V3Graph m_graph; // Scoreboard of var usages/dependencies - GaterPliVertex* m_pliVertexp; // Element specifying PLI ordering - GaterHeadVertex* m_headVertexp; // Top vertex - V3GraphVertex* m_aboveVertexp; // Vertex above this point in tree - uint32_t m_aboveTrue; // Vertex above this point is true branch - AstVarScope* m_stmtVscp; // Current statement had variable assigned - bool m_stmtInPli; // Current statement has PLI - - // METHODS - void nonOptimizable(AstNode* nodep, const char* reasonp) { - if (m_nonopt=="") { - UINFO(9," Nonopt: "<(m_stmtVscp->user1p()); - new GaterEdge(&m_graph, m_pliVertexp, varVtxp, VU_PLI); - } - m_stmtInPli = true; // Mark all followon variables too - } - - // 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); - } - - 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(edgep->top())) { - vVxp->unlinkDelete(&m_graph); VL_DANGLING(vVxp); VL_DANGLING(edgep); - } else { - m_graph.dump(); - v3fatalSrc("PLI vertex points to non-signal"); - } - } - m_pliVertexp->unlinkDelete(&m_graph); m_pliVertexp = NULL; - } - } - - void simplifyIfElseRecurse(V3GraphVertex* vertexp) { - // From bottom-up, propagate duplicate IF/ELSE branches to grandparent - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - simplifyIfElseRecurse(edgep->top()); - } - //UINFO(9,"IERecurse "<(vertexp)) { - // Clear indications - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - edgep->top()->user(VU_NONE); - } - // Mark nodes on to/from side - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - V3GraphVertex* toVxp = edgep->top(); - GaterEdge* cedgep = static_cast(edgep); - // We may mark this twice in one pass - if so it's duplicated; no worries - if (cedgep->ifelseTrue()) toVxp->user(toVxp->user() | VU_IF); - if (cedgep->ifelseFalse()) toVxp->user(toVxp->user() | VU_ELSE); - //UINFO(9," mark "<outBeginp(); edgep; edgep = nextp) { - nextp = edgep->outNextp(); // We may edit the list - V3GraphVertex* toVxp = edgep->top(); - //UINFO(9," to "<user()<<" "<user() & VU_IF) && (toVxp->user() & VU_ELSE)) { - edgep->unlinkDelete(); VL_DANGLING(edgep); - if (!(toVxp->user() & VU_MADE)) { // Make an edge only once - toVxp->user(toVxp->user() | VU_MADE); - GaterEdge* inedgep = static_cast(vertexp->inBeginp()); - V3GraphVertex* grandparent = inedgep->fromp(); - new GaterEdge(&m_graph, grandparent, toVxp, inedgep->ifelse()); - } - } - } - } - } - - void simplifyGrandRecurse(V3GraphVertex* vertexp, uint32_t depth) { - // From top-down delete any vars that grandparents source - // IE A -> B -> C -> VAR - // \----------^ - //UINFO(9,"GRecurse "<outBeginp(); edgep; edgep=nextp) { - nextp = edgep->outNextp(); // We may edit the list - if (GaterVarVertex* toVxp = dynamic_cast(edgep->top())) { - if (toVxp->user() && toVxp->user() < depth) { - // A recursion "above" us marked it, - // Remove this edge, it's redundant with the upper edge - edgep->unlinkDelete(); VL_DANGLING(edgep); - } else { - GaterEdge* cedgep = static_cast(edgep); - if (cedgep->ifelseBoth()) { - toVxp->user(depth); - } - } - } - } - // Recurse - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - simplifyGrandRecurse(edgep->top(), depth+1); - } - // Clean our marks - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { - V3GraphVertex* toVxp = edgep->top(); - if (toVxp->user() && toVxp->user() < depth) { // A recursion "above" us marked it; don't mess with it - } else { - toVxp->user(0); // We marked it originally, so unmark now - } - } - // Delete any If nodes with no children - // Last, as want bottom-up cleanup - for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) { - nextp = edgep->outNextp(); // We may edit the list - if (GaterIfVertex* toVxp = dynamic_cast(edgep->top())) { - if (!toVxp->outBeginp()) { - if (!nextp || nextp->top() != edgep->top()) { // Else next would disappear; we'll do it next loop - toVxp->unlinkDelete(&m_graph); VL_DANGLING(toVxp); VL_DANGLING(edgep); - } - } - } - } - } - - void simplifyRemoveUngated(V3GraphVertex* vertexp) { - // Remove variables that are ungated - // At this point, any variable under the head is ungated - for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) { - nextp = edgep->outNextp(); // We may edit the list - if (GaterVarVertex* toVxp = dynamic_cast(edgep->top())) { - if (!nextp || nextp->top() != edgep->top()) { // Else next would disappear; we'll do it next loop - toVxp->unlinkDelete(&m_graph); VL_DANGLING(toVxp); VL_DANGLING(edgep); - } - } - } - } - - 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(vertexp)) { - // At this point, any variable not linked is an error - // (It should have at least landed under the Head node) - UASSERT_OBJ(vVxp->inBeginp(), vVxp->nodep(), - "Variable became stranded in clk gate detection"); - 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(); } - } - - AstNode* newExprFromGraph(GaterVarVertex* vertexp) { - // Recurse backwards, then form equation on return path - // We could use user()!=0, but zeroing it is slow, so instead we'll mark with a generation - // We get equations like "a | (!a & b)" which obviously could be reduced here, - // instead out of generality, there's a V3Const::matchOrAndNot that'll clean it up - static uint32_t s_generation = 0; - ++s_generation; - nafgMarkRecurse(vertexp, s_generation); - AstNode* nodep = nafgCreateRecurse(m_headVertexp, s_generation); - if (debug()>=9) nodep->dumpTree(cout, " GateExpr: "); - return nodep; - } - void nafgMarkRecurse(V3GraphVertex* vertexp, uint32_t generation) { - // Backwards mark user() on the path we recurse - //UINFO(9," nafgMark: v "<name()<inBeginp(); edgep; edgep = edgep->inNextp()) { - //UINFO(9," nafgMark: "<name()<user(generation); - nafgMarkRecurse(edgep->fromp(), generation); - } - } - AstNode* nafgCreateRecurse(V3GraphVertex* vertexp, uint32_t generation) { - // Forewards follow user() marked previously and build tree - AstNode* nodep = NULL; - // OR across all edges found at this level - //UINFO(9," nafgEnter: v "<name()<outBeginp(); edgep; edgep = edgep->outNextp()) { - if (edgep->user() == generation) { - GaterEdge* cedgep = static_cast(edgep); - AstNode* eqnp = NULL; - //UINFO(9," nafgFollow: "<name()<(edgep->fromp())) { - // Just OR in all lower terms - eqnp = nafgCreateRecurse(edgep->top(), generation); - } else if (GaterIfVertex* cVxp = dynamic_cast(edgep->fromp())) { - // Edges from IFs represent a real IF branch in the equation tree - //UINFO(9," ifver "<dotColor()<nodep()->condp()->cloneTree(true); - UASSERT_OBJ(eqnp, cVxp->nodep(), "null condition"); - if (cedgep->ifelseFalse()) { - eqnp = new AstNot(eqnp->fileline(), eqnp); - } - // We need to AND this term onto whatever was found below it - AstNode* belowp = nafgCreateRecurse(edgep->top(), generation); - if (belowp) eqnp = new AstAnd(eqnp->fileline(), eqnp, belowp); - } - // Top level we could choose to make multiple gaters, or ORs under the gater - // Right now we'll put OR lower down and let other optimizations deal - if (nodep) nodep = new AstOr(nodep->fileline(), nodep, eqnp); - else nodep = eqnp; - //if (debug()>=9) nodep->dumpTree(cout, " followExpr: "); - } - } - //UINFO(9," nafgExit: "<name()<verticesNextp()) { - if (GaterVarVertex* vVxp = dynamic_cast(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 - UASSERT_OBJ(!vVxp->nodep()->user2p(), vVxp->nodep(), - "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 - } - - void newAlwaysTree(AstAlways* nodep, AstNode* exprp) { - // Create new always with specified gating expression - // Relevant vars are already marked with user2p - - // Should we put the gater under the always itself, - // or make a new signal? - // New signal: May cause replicated logic until we can combine - // Need way to toggle signal on complicated pos/negedge - // Under Always: More complicated, may not propagate logic with gateer - // Untill we get better gate optimization, we'll go this route. -//#define GATER_NOP -#ifdef GATER_NOP - // For testing only, don't clock gate but still make new always - AstSenTree* sensesp = nodep->sensesp()->cloneTree(true); -#else - // Make a SenGate - AstSenItem* oldsenitemsp = VN_CAST(nodep->sensesp()->sensesp(), SenItem); - UASSERT_OBJ(oldsenitemsp, nodep, "SenTree doesn't have any SenItem under it"); - - AstSenTree* sensesp = new AstSenTree(nodep->fileline(), - new AstSenGate(nodep->fileline(), - oldsenitemsp->cloneTree(true), - exprp)); -#endif - - // Make new body; note clone will preserve user2p() indicating moving vars - AstNode* bodyp = nodep->bodysp()->cloneTree(true); - - AstAlways* alwp = new AstAlways(nodep->fileline(), - nodep->keyword(), - sensesp, - bodyp); - - alwp->user4(1); // No need to process the new always again! - nodep->addNextHere(alwp); - - // Blow moved statements from old body - { GaterBodyVisitor vis(nodep, exprp, true); } - // Blow old statements from new body - { GaterBodyVisitor vis(alwp, exprp, false); } - - ++m_statGaters; - if (debug()>=9) alwp->dumpTree(cout, " new: "); - } - - // VISITORS - virtual void visit(AstAlways* nodep) { - if (debug()>=9) cout<user4SetOnce()) 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: "<verticesNextp()) { - if (GaterVarVertex* vVxp = dynamic_cast(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"<lvalue()) { - AstVarScope* vscp = nodep->varScopep(); - if (nodep->varp()->isSigPublic()) { - // Public signals shouldn't be changed, pli code might be messing with them - scoreboardPli(nodep); - } - // If another lvalue in this node, give up optimizing. - // We could just not optimize this variable, but we've already marked the - // other variable as optimizable, so we can instead pretend it's a PLI node. - if (m_stmtVscp) { - UINFO(5, " Multiple lvalues in one statement: "<(vscp->user1p()); - if (!vertexp) { - vertexp = new GaterVarVertex(&m_graph, vscp); - vscp->user1p(vertexp); - } - new GaterEdge(&m_graph, m_aboveVertexp, vertexp, m_aboveTrue); - if (m_stmtInPli) { - new GaterEdge(&m_graph, m_pliVertexp, vertexp, VU_PLI); - } - } - } - virtual void visit(AstNodeIf* nodep) { - m_ifDepth++; - bool allowGater = m_directlyUnderAlw && m_ifDepth <= IF_DEPTH_MAX; - if (allowGater) { - GaterCondVisitor condVisitor(nodep->condp()); - if (!condVisitor.isSimple()) { - // Don't clear optimization, simply drop this IF as part of the gating - UINFO(5," IFnon-simple-condition: "<condp()); // directlyUnder stays as-is - } - { - m_aboveVertexp = vertexp; // Vars will point at this edge - m_aboveTrue = VU_IF; - iterateAndNextNull(nodep->ifsp()); // directlyUnder stays as-is (true) - } - { - m_aboveVertexp = vertexp; // Vars will point at this edge - m_aboveTrue = VU_ELSE; - iterateAndNextNull(nodep->elsesp()); // directlyUnder stays as-is (true) - } - m_aboveVertexp = lastabovep; - m_aboveTrue = lasttrue; - } - m_ifDepth--; - } - - virtual void visit(AstAssignDly* nodep) { - // iterateChildrenAlw will detect this is a statement for us - iterateChildrenAlw(nodep, false); - } - - virtual void visit(AstNodeAssign* nodep) { - // Note NOT AssignDly; handled above, We'll just mark this block as - // not optimizable. - // - // A future alternative is to look for any lvalues that are also - // variables in the sensitivity list, or rvalues in this block. If - // any hit, disable optimization. Unlikely to be useful (For loops - // being an exception, but they're already unrolled.) - nonOptimizable(nodep, "Non-delayed assignment"); - // No reason to iterate. - } - - virtual void visit(AstSenItem* nodep) { - if (!nodep->isClocked()) { - nonOptimizable(nodep, "Non-clocked sensitivity"); - } - iterateChildrenAlw(nodep, false); - } - - //-------------------- - virtual void visit(AstNode* nodep) { - if (m_nonopt=="") { // Else accelerate - iterateChildrenAlw(nodep, false); - } - } - inline void iterateChildrenAlw(AstNode* nodep, bool under) { - // **** USE THIS INSTEAD OF iterateChildren! - // Note If visitor doesn't call here; does it its own way - bool lastdua = m_directlyUnderAlw; - AstVarScope* lastvscp = m_stmtVscp; - bool lastpli = m_stmtInPli; - m_directlyUnderAlw = under; - if (VN_IS(nodep, NodeStmt)) { // Restored below - UINFO(9," Stmt: "<isPure() || nodep->isBrancher()) { - // May also be a new statement (above if); if so we mark it immediately - UINFO(9," NotPure "<= 3); -} diff --git a/src/V3ClkGater.h b/src/V3ClkGater.h deleted file mode 100644 index b33e3fa9d..000000000 --- a/src/V3ClkGater.h +++ /dev/null @@ -1,37 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Break always into clock gated blocks -// -// Code available from: http://www.veripool.org/verilator -// -//************************************************************************* -// -// Copyright 2003-2019 by Wilson Snyder. This program is free software; you can -// redistribute it and/or modify it under the terms of either the GNU -// Lesser General Public License Version 3 or the Perl Artistic License -// Version 2.0. -// -// Verilator is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -//************************************************************************* - -#ifndef _V3CLKGATER_H_ -#define _V3CLKGATER_H_ 1 - -#include "config_build.h" -#include "verilatedos.h" - -#include "V3Error.h" -#include "V3Ast.h" - -//============================================================================ - -class V3ClkGater { -public: - static void clkGaterAll(AstNetlist* nodep); -}; - -#endif // Guard diff --git a/src/V3Graph.h b/src/V3Graph.h index 6417ac25f..798173c76 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -118,11 +118,6 @@ public: /// (I.E. all loops will occur within each color, not between them.) void stronglyConnected(V3EdgeFuncP edgeFuncp); - /// Assign same color to all destination vertices that have same - /// subgraph feeding into them - /// (I.E. all "from" nodes are common within each color) - /// See V3ClkGater if this is needed again; it got specialized - /// Assign a ordering number to all vertexes in a tree. /// All nodes with no inputs will get rank 1 void rank(V3EdgeFuncP edgeFuncp); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 6c89914f0..d03009055 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -730,7 +730,6 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char case 'd': m_oDedupe = flag; break; case 'm': m_oAssemble = flag; break; case 'e': m_oCase = flag; break; - case 'f': m_oFlopGater = flag; break; case 'g': m_oGate = flag; break; case 'i': m_oInline = flag; break; case 'k': m_oSubstConst = flag; break; @@ -1421,7 +1420,6 @@ void V3Options::optimize(int level) { m_oCombine = flag; m_oConst = flag; m_oExpand = flag; - m_oFlopGater = flag; m_oGate = flag; m_oInline = flag; m_oLife = flag; diff --git a/src/V3Options.h b/src/V3Options.h index 6f28ce538..c7b90d32e 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -204,7 +204,6 @@ class V3Options { bool m_oDedupe; // main switch: -Od: logic deduplication bool m_oAssemble; // main switch: -Om: assign assemble bool m_oExpand; // main switch: -Ox: expansion of C macros - bool m_oFlopGater; // main switch: -Of: flop gater detection bool m_oGate; // main switch: -Og: gate wire elimination bool m_oLife; // main switch: -Ol: variable lifetime bool m_oLifePost; // main switch: -Ot: delayed assignment elimination @@ -377,7 +376,6 @@ class V3Options { bool oDedupe() const { return m_oDedupe; } bool oAssemble() const { return m_oAssemble; } bool oExpand() const { return m_oExpand; } - bool oFlopGater() const { return m_oFlopGater; } bool oGate() const { return m_oGate; } bool oDup() const { return oLife(); } bool oLife() const { return m_oLife; } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 3235868e7..614389728 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -31,7 +31,6 @@ #include "V3Cast.h" #include "V3Changed.h" #include "V3Clean.h" -#include "V3ClkGater.h" #include "V3Clock.h" #include "V3Combine.h" #include "V3Const.h" @@ -332,12 +331,6 @@ void process() { V3Dead::deadifyDTypesScoped(v3Global.rootp()); v3Global.checkTree(); - // Detect clock enables and mode into sensitives, and split always based on clocks - // (so this is a good prelude to splitAlways.) - if (v3Global.opt.oFlopGater()) { - V3ClkGater::clkGaterAll(v3Global.rootp()); - } - // Move assignments/sensitives into a SBLOCK for each unique sensitivity list // (May convert some ALWAYS to combo blocks, so should be before V3Gate step.) V3Active::activeAll(v3Global.rootp());