diff --git a/src/V3Simulate.h b/src/V3Simulate.h new file mode 100644 index 000000000..293010299 --- /dev/null +++ b/src/V3Simulate.h @@ -0,0 +1,392 @@ +// -*- C++ -*- +//************************************************************************* +// DESCRIPTION: Verilator: Simulate code to determine output values/variables +// +// Code available from: http://www.veripool.org/verilator +// +// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli +// +//************************************************************************* +// +// Copyright 2003-2009 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. +// +//************************************************************************* +// +// void example_usage() { +// SimulateVisitor simvis (false); +// simvis.clear(); +// // Set all inputs to the constant +// for (deque::iterator it = m_inVarps.begin(); it!=m_inVarps.end(); ++it) { +// simvis.newNumber(invscp, #); +// } +// // Simulate +// simvis.main(nodep); +// // Read outputs +// for (deque::iterator it = m_outVarps.begin(); it!=m_outVarps.end(); ++it) { +// V3Number* outnump = simvis.fetchOutNumberNull(outvscp); +// +//************************************************************************* + + +#ifndef _V3SIMULATE_H_ +#define _V3SIMULATE_H_ 1 +#include "config_build.h" +#include "verilatedos.h" +#include "V3Error.h" +#include "V3Ast.h" + +//============================================================================ + +//###################################################################### +// Simulate class functions + +class SimulateVisitor : public AstNVisitor { + // Simulate a node tree, returning value of variables + // Two major operating modes: + // Test the tree to see if it is conformant + // Given a set of input values, find the output values + // Both are done in this same visitor to reduce risk; if a visitor + // is missing, we will simply not apply the optimization, rather then bomb. + +private: + // NODE STATE + // Cleared on each always/assignw + AstUser1InUse m_inuser1; + AstUser3InUse m_inuser3; + AstUser4InUse m_inuser4; + + // Checking: + // AstVarScope::user1() -> VarUsage. Set true to indicate tracking as lvalue/rvalue + // Simulating: + // AstVarScope::user3() -> V3Number*. Input value of variable or node (and output for non-delayed assignments) + // AstVarScope::user4() -> V3Number*. Output value of variable (delayed assignments) + + enum VarUsage { VU_NONE=0, VU_LV=1, VU_RV=2, VU_LVDLY=4 }; + + // STATE + bool m_checking; ///< Checking vs. simulation mode + // Checking: + const char* m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize + bool m_anyAssignDly; ///< True if found a delayed assignment + bool m_anyAssignComb; ///< True if found a non-delayed assignment + bool m_inDlyAssign; ///< Under delayed assignment + int m_instrCount; ///< Number of nodes + int m_dataCount; ///< Bytes of data + // Simulating: + deque m_numFreeps; ///< List of all numbers free and not in use + deque m_numAllps; ///< List of all numbers free and in use + + // Note level 8&9 include debugging each simulation value + static int debug() { + static int level = -1; + if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); + return level; + } + + // Checking METHODS +public: + /// Call other-this function on all new var references + virtual void varRefCb(AstVarRef* nodep) {} + + void clearOptimizable(AstNode* nodep/*null ok*/, const char* why) { + if (!m_whyNotOptimizable) { + if (debug()>=5) { + UINFO(0,"Clear optimizable: "<width()<width(nodep->width()); + nump->fileline(nodep->fileline()); + nump->setLong(value); // We do support more than 32 bit numbers, just valuep=0 in that case + } else { + //UINFO(7,"Num New "<width()<fileline(), nodep->width(), value); + m_numAllps.push_back(nump); + } + return nump; + } +public: + V3Number* newNumber(AstNode* nodep, uint32_t value=0) { + // Set a constant value for this node + if (!nodep->user3p()) { + V3Number* nump = allocNumber(nodep, value); + setNumber(nodep, nump); + } + return (fetchNumber(nodep)); + } + V3Number* newOutNumber(AstNode* nodep, uint32_t value=0) { + // Set a constant value for this node + if (!nodep->user4p()) { + V3Number* nump = allocNumber(nodep, value); + setOutNumber(nodep, nump); + } + return (fetchOutNumber(nodep)); + } + V3Number* fetchNumberNull(AstNode* nodep) { + return ((V3Number*)nodep->user3p()); + } + V3Number* fetchOutNumberNull(AstNode* nodep) { + return ((V3Number*)nodep->user4p()); + } + V3Number* fetchNumber(AstNode* nodep) { + V3Number* nump = fetchNumberNull(nodep); + if (!nump) nodep->v3fatalSrc("No value found for node."); + return nump; + } + V3Number* fetchOutNumber(AstNode* nodep) { + V3Number* nump = fetchOutNumberNull(nodep); + if (!nump) nodep->v3fatalSrc("No value found for node."); + return nump; + } +private: + void setNumber(AstNode* nodep, const V3Number* nump) { + UINFO(9," set num "<<*nump<<" on "<user3p((AstNUser*)nump); + } + void setOutNumber(AstNode* nodep, const V3Number* nump) { + UINFO(9," set num "<<*nump<<" on "<user4p((AstNUser*)nump); + } + + void checkNodeInfo(AstNode* nodep) { + m_instrCount += nodep->instrCount(); + m_dataCount += nodep->width(); + if (!nodep->isPredictOptimizable()) { + //UINFO(9," !predictopt "<iterateChildren(*this); + } + virtual void visit(AstSenTree* nodep, AstNUser*) { + // Sensitivities aren't inputs per se; we'll keep our tree under the same sens. + } + virtual void visit(AstVarRef* nodep, AstNUser*) { + AstVarScope* vscp = nodep->varScopep(); + if (!vscp) nodep->v3fatalSrc("Not linked"); + if (m_checking) { + if (m_checking && !optimizable()) return; // Accelerate + // We can't have non-delayed assignments with same value on LHS and RHS + // as we don't figure out variable ordering. + // Delayed is OK though, as we'll decode the next state separately. + if (nodep->varp()->arraysp()) clearOptimizable(nodep,"Array references"); + if (nodep->lvalue()) { + if (m_inDlyAssign) { + if (!(vscp->user1() & VU_LVDLY)) { + vscp->user1( vscp->user1() | VU_LVDLY); + varRefCb (nodep); + } + } else { // nondly asn + if (!(vscp->user1() & VU_LV)) { + if (vscp->user1() & VU_RV) clearOptimizable(nodep,"Var read & write"); + vscp->user1( vscp->user1() | VU_LV); + varRefCb (nodep); + } + } + } else { + if (!(vscp->user1() & VU_RV)) { + if (vscp->user1() & VU_LV) clearOptimizable(nodep,"Var write & read"); + vscp->user1( vscp->user1() | VU_RV); + varRefCb (nodep); + } + } + } + else { // simulating + if (nodep->lvalue()) { + nodep->v3fatalSrc("LHS varref should be handled in AstAssign visitor."); + } else { + // Return simulation value + V3Number* nump = fetchNumberNull(vscp); + if (!nump) nodep->v3fatalSrc("Variable value should have been set before any visitor called."); + setNumber(nodep, nump); + } + } + } + virtual void visit(AstNodeIf* nodep, AstNUser*) { + if (m_checking) { + checkNodeInfo(nodep); + nodep->iterateChildren(*this); + } else { + nodep->condp()->iterateAndNext(*this); + if (fetchNumber(nodep->condp())->isNeqZero()) { + nodep->ifsp()->iterateAndNext(*this); + } else { + nodep->elsesp()->iterateAndNext(*this); + } + } + } + virtual void visit(AstConst* nodep, AstNUser*) { + if (m_checking) { + checkNodeInfo(nodep); + } else { + setNumber(nodep, &(nodep->num())); + } + } + virtual void visit(AstNodeUniop* nodep, AstNUser*) { + if (m_checking) { + if (!optimizable()) return; // Accelerate + checkNodeInfo(nodep); + nodep->iterateChildren(*this); + } else { + nodep->iterateChildren(*this); + nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp())); + } + } + virtual void visit(AstNodeBiop* nodep, AstNUser*) { + if (m_checking) { + if (!optimizable()) return; // Accelerate + checkNodeInfo(nodep); + nodep->iterateChildren(*this); + } else { + nodep->iterateChildren(*this); + nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp()), *fetchNumber(nodep->rhsp())); + } + } + virtual void visit(AstNodeTriop* nodep, AstNUser*) { + if (m_checking) { + if (!optimizable()) return; // Accelerate + checkNodeInfo(nodep); + nodep->iterateChildren(*this); + } else { + nodep->iterateChildren(*this); + nodep->numberOperate(*newNumber(nodep), + *fetchNumber(nodep->lhsp()), + *fetchNumber(nodep->rhsp()), + *fetchNumber(nodep->thsp())); + } + } + virtual void visit(AstNodeCond* nodep, AstNUser*) { + // We could use above visit(AstNodeTriop), but it's slower even O(n^2) to evaluate + // both sides when we really only need to evaluate one side. + if (m_checking) { + if (!optimizable()) return; // Accelerate + checkNodeInfo(nodep); + nodep->iterateChildren(*this); + } else { + nodep->condp()->accept(*this); + if (fetchNumber(nodep->condp())->isNeqZero()) { + nodep->expr1p()->accept(*this); + newNumber(nodep)->opAssign(*fetchNumber(nodep->expr1p())); + } else { + nodep->expr2p()->accept(*this); + newNumber(nodep)->opAssign(*fetchNumber(nodep->expr2p())); + } + } + } + virtual void visit(AstNodeAssign* nodep, AstNUser*) { + if (m_checking) { + if (!optimizable()) return; // Accelerate + if (nodep->castAssignDly()) { + if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns"); + m_anyAssignDly = true; + m_inDlyAssign = true; + } else { + if (m_anyAssignDly) clearOptimizable(nodep, "Mix of dly/non dly assigns"); + m_anyAssignComb = true; + } + nodep->iterateChildren(*this); + } + if (!nodep->lhsp()->castVarRef()) { + clearOptimizable(nodep, "LHS isn't simple variable"); + } + else if (!m_checking) { + nodep->rhsp()->iterateAndNext(*this); + AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep(); + if (nodep->castAssignDly()) { + // Don't do setNumber, as value isn't yet visible to following statements + setOutNumber(vscp, fetchNumber(nodep->rhsp())); + } else { + setNumber(vscp, fetchNumber(nodep->rhsp())); + setOutNumber(vscp, fetchNumber(nodep->rhsp())); + } + } + m_inDlyAssign = false; + } + + virtual void visit(AstComment*, AstNUser*) {} + // default + // These types are definately not reducable + // AstCoverInc, AstNodePli, AstArraySel, AstStop, AstFinish, + // AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt + // In theory, we could follow the loop, but might be slow + // AstFor, AstWhile + virtual void visit(AstNode* nodep, AstNUser*) { + if (m_checking) { + checkNodeInfo(nodep); + if (optimizable()) { + // Hmm, what is this then? + // In production code, we'll just not optimize. It should be fixed though. + clearOptimizable(nodep, "Unknown node type, perhaps missing visitor in SimulateVisitor"); +#ifdef VL_DEBUG + UINFO(0,"Unknown node type in SimulateVisitor: "<prettyTypeName()<v3fatalSrc("Optimizable should have been cleared in check step, and never reach simulation."); + } + } + +public: + // CONSTRUCTORS + SimulateVisitor(bool checking) { + m_checking = checking; + clear(); // We reuse this structure in the main loop, so put initializers inside clear() + } + void clear() { + m_whyNotOptimizable = NULL; + m_anyAssignComb = false; + m_anyAssignDly = false; + m_inDlyAssign = false; + m_instrCount = 0; + m_dataCount = 0; + + AstNode::user1ClearTree(); // user1p() used on entire tree + AstNode::user3ClearTree(); // user3p() used on entire tree + AstNode::user4ClearTree(); // user4p() used on entire tree + + // Move all allocated numbers to the free pool + m_numFreeps = m_numAllps; + } + void main (AstNode* nodep) { + nodep->accept(*this); + } + virtual ~SimulateVisitor() { + for (deque::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) { + delete (*it); + } + m_numFreeps.clear(); + m_numAllps.clear(); + } +}; + +#endif // Guard diff --git a/src/V3Table.cpp b/src/V3Table.cpp index c7dd1307c..8dffbc580 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -36,6 +36,7 @@ #include "V3Global.h" #include "V3Table.h" +#include "V3Simulate.h" #include "V3Stats.h" #include "V3Ast.h" @@ -48,365 +49,32 @@ static const double TABLE_TOTAL_BYTES = 64*1024*1024; // 64MB is close to max me static const double TABLE_SPACE_TIME_MULT = 8; // Worth 8 bytes of data to replace a instruction static const int TABLE_MIN_NODE_COUNT = 32; // If < 32 instructions, not worth the effort +//###################################################################### + class TableVisitor; -//###################################################################### - -class TableBaseVisitor : public AstNVisitor { -public: - // Note level 8&9 include debugging each simulation value - static int debug() { - static int level = -1; - if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); - return level; - } -}; - -//###################################################################### - -class TableSimulateVisitor : public TableBaseVisitor { - // Simulate a node tree, returning value of variables - // Two major operating modes: - // Test the tree to see if it is conformant - // Given a set of input values, find the output values - // Both are done in this same visitor to reduce risk; if a visitor - // is missing, we will simply not apply the optimization, rather then bomb. - -private: - // NODE STATE - // Cleared on each always/assignw - // Checking: - // AstVarScope::user1() -> VarUsage. Set true to indicate tracking as lvalue/rvalue - // Simulating: - // AstVarScope::user3() -> V3Number*. Input value of variable or node (and output for non-delayed assignments) - // AstVarScope::user4() -> V3Number*. Output value of variable (delayed assignments) - - enum VarUsage { VU_NONE=0, VU_LV=1, VU_RV=2, VU_LVDLY=4 }; - - // STATE - bool m_checking; ///< Checking vs. simulation mode - // Checking: +class TableSimulateVisitor : public SimulateVisitor { + // MEMBERS TableVisitor* m_cbthis; ///< Class for callback - const char* m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize - bool m_anyAssignDly; ///< True if found a delayed assignment - bool m_anyAssignComb; ///< True if found a non-delayed assignment - bool m_inDlyAssign; ///< Under delayed assignment - int m_instrCount; ///< Number of nodes - int m_dataCount; ///< Bytes of data - // Simulating: - deque m_numFreeps; ///< List of all numbers free and not in use - deque m_numAllps; ///< List of all numbers free and in use - - // Checking METHODS -public: - void varRefCb(AstVarRef* nodep); ///< Call other-this function on all new var references - - void clearOptimizable(AstNode* nodep/*null ok*/, const char* why) { - if (!m_whyNotOptimizable) { - if (debug()>=5) { - UINFO(0,"Clear optimizable: "<width()<width(nodep->width()); - nump->fileline(nodep->fileline()); - nump->setLong(value); // We do support more than 32 bit numbers, just valuep=0 in that case - } else { - //UINFO(7,"Num New "<width()<fileline(), nodep->width(), value); - m_numAllps.push_back(nump); - } - return nump; - } -public: - V3Number* newNumber(AstNode* nodep, uint32_t value=0) { - // Set a constant value for this node - if (!nodep->user3p()) { - V3Number* nump = allocNumber(nodep, value); - setNumber(nodep, nump); - } - return (fetchNumber(nodep)); - } - V3Number* newOutNumber(AstNode* nodep, uint32_t value=0) { - // Set a constant value for this node - if (!nodep->user4p()) { - V3Number* nump = allocNumber(nodep, value); - setOutNumber(nodep, nump); - } - return (fetchOutNumber(nodep)); - } - V3Number* fetchNumberNull(AstNode* nodep) { - return ((V3Number*)nodep->user3p()); - } - V3Number* fetchOutNumberNull(AstNode* nodep) { - return ((V3Number*)nodep->user4p()); - } - V3Number* fetchNumber(AstNode* nodep) { - V3Number* nump = fetchNumberNull(nodep); - if (!nump) nodep->v3fatalSrc("No value found for node."); - return nump; - } - V3Number* fetchOutNumber(AstNode* nodep) { - V3Number* nump = fetchOutNumberNull(nodep); - if (!nump) nodep->v3fatalSrc("No value found for node."); - return nump; - } -private: - void setNumber(AstNode* nodep, const V3Number* nump) { - UINFO(9," set num "<<*nump<<" on "<user3p((AstNUser*)nump); - } - void setOutNumber(AstNode* nodep, const V3Number* nump) { - UINFO(9," set num "<<*nump<<" on "<user4p((AstNUser*)nump); - } - - void checkNodeInfo(AstNode* nodep) { - m_instrCount += nodep->instrCount(); - m_dataCount += nodep->width(); - if (!nodep->isPredictOptimizable()) { - //UINFO(9," !predictopt "<iterateChildren(*this); - } - virtual void visit(AstSenTree* nodep, AstNUser*) { - // Sensitivities aren't inputs per se; we'll keep our tree under the same sens. - } - virtual void visit(AstVarRef* nodep, AstNUser*) { - AstVarScope* vscp = nodep->varScopep(); - if (!vscp) nodep->v3fatalSrc("Not linked"); - if (m_checking) { - if (m_checking && !optimizable()) return; // Accelerate - // We can't have non-delayed assignments with same value on LHS and RHS - // as we don't figure out variable ordering. - // Delayed is OK though, as we'll decode the next state separately. - if (nodep->varp()->arraysp()) clearOptimizable(nodep,"Array references"); - if (nodep->lvalue()) { - if (m_inDlyAssign) { - if (!(vscp->user1() & VU_LVDLY)) { - vscp->user1( vscp->user1() | VU_LVDLY); - varRefCb (nodep); - } - } else { // nondly asn - if (!(vscp->user1() & VU_LV)) { - if (vscp->user1() & VU_RV) clearOptimizable(nodep,"Var read & write"); - vscp->user1( vscp->user1() | VU_LV); - varRefCb (nodep); - } - } - } else { - if (!(vscp->user1() & VU_RV)) { - if (vscp->user1() & VU_LV) clearOptimizable(nodep,"Var write & read"); - vscp->user1( vscp->user1() | VU_RV); - varRefCb (nodep); - } - } - } - else { // simulating - if (nodep->lvalue()) { - nodep->v3fatalSrc("LHS varref should be handled in AstAssign visitor."); - } else { - // Return simulation value - V3Number* nump = fetchNumberNull(vscp); - if (!nump) nodep->v3fatalSrc("Variable value should have been set before any visitor called."); - setNumber(nodep, nump); - } - } - } - virtual void visit(AstNodeIf* nodep, AstNUser*) { - if (m_checking) { - checkNodeInfo(nodep); - nodep->iterateChildren(*this); - } else { - nodep->condp()->iterateAndNext(*this); - if (fetchNumber(nodep->condp())->isNeqZero()) { - nodep->ifsp()->iterateAndNext(*this); - } else { - nodep->elsesp()->iterateAndNext(*this); - } - } - } - virtual void visit(AstConst* nodep, AstNUser*) { - if (m_checking) { - checkNodeInfo(nodep); - } else { - setNumber(nodep, &(nodep->num())); - } - } - virtual void visit(AstNodeUniop* nodep, AstNUser*) { - if (m_checking) { - if (!optimizable()) return; // Accelerate - checkNodeInfo(nodep); - nodep->iterateChildren(*this); - } else { - nodep->iterateChildren(*this); - nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp())); - } - } - virtual void visit(AstNodeBiop* nodep, AstNUser*) { - if (m_checking) { - if (!optimizable()) return; // Accelerate - checkNodeInfo(nodep); - nodep->iterateChildren(*this); - } else { - nodep->iterateChildren(*this); - nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp()), *fetchNumber(nodep->rhsp())); - } - } - virtual void visit(AstNodeTriop* nodep, AstNUser*) { - if (m_checking) { - if (!optimizable()) return; // Accelerate - checkNodeInfo(nodep); - nodep->iterateChildren(*this); - } else { - nodep->iterateChildren(*this); - nodep->numberOperate(*newNumber(nodep), - *fetchNumber(nodep->lhsp()), - *fetchNumber(nodep->rhsp()), - *fetchNumber(nodep->thsp())); - } - } - virtual void visit(AstNodeCond* nodep, AstNUser*) { - // We could use above visit(AstNodeTriop), but it's slower even O(n^2) to evaluate - // both sides when we really only need to evaluate one side. - if (m_checking) { - if (!optimizable()) return; // Accelerate - checkNodeInfo(nodep); - nodep->iterateChildren(*this); - } else { - nodep->condp()->accept(*this); - if (fetchNumber(nodep->condp())->isNeqZero()) { - nodep->expr1p()->accept(*this); - newNumber(nodep)->opAssign(*fetchNumber(nodep->expr1p())); - } else { - nodep->expr2p()->accept(*this); - newNumber(nodep)->opAssign(*fetchNumber(nodep->expr2p())); - } - } - } - virtual void visit(AstNodeAssign* nodep, AstNUser*) { - if (m_checking) { - if (!optimizable()) return; // Accelerate - if (nodep->castAssignDly()) { - if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns"); - m_anyAssignDly = true; - m_inDlyAssign = true; - } else { - if (m_anyAssignDly) clearOptimizable(nodep, "Mix of dly/non dly assigns"); - m_anyAssignComb = true; - } - nodep->iterateChildren(*this); - } - if (!nodep->lhsp()->castVarRef()) { - clearOptimizable(nodep, "LHS isn't simple variable"); - } - else if (!m_checking) { - nodep->rhsp()->iterateAndNext(*this); - AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep(); - if (nodep->castAssignDly()) { - // Don't do setNumber, as value isn't yet visible to following statements - setOutNumber(vscp, fetchNumber(nodep->rhsp())); - } else { - setNumber(vscp, fetchNumber(nodep->rhsp())); - setOutNumber(vscp, fetchNumber(nodep->rhsp())); - } - } - m_inDlyAssign = false; - } - - virtual void visit(AstComment*, AstNUser*) {} - // default - // These types are definately not reducable - // AstCoverInc, AstNodePli, AstArraySel, AstStop, AstFinish, - // AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt - // In theory, we could follow the loop, but might be slow - // AstFor, AstWhile - virtual void visit(AstNode* nodep, AstNUser*) { - if (m_checking) { - checkNodeInfo(nodep); - if (optimizable()) { - // Hmm, what is this then? - // In production code, we'll just not optimize. It should be fixed though. - clearOptimizable(nodep, "Unknown node type, perhaps missing visitor in TableSimulateVisitor"); -#ifdef VL_DEBUG - UINFO(0,"Unknown node type in TableSimulateVisitor: "<prettyTypeName()<v3fatalSrc("Optimizable should have been cleared in check step, and never reach simulation."); - } - } public: + virtual void varRefCb(AstVarRef* nodep); ///< Call other-this function on all new var references + // CONSTRUCTORS - TableSimulateVisitor(TableVisitor* cbthis, bool checking) { + TableSimulateVisitor(TableVisitor* cbthis, bool checking) + : SimulateVisitor(checking) { m_cbthis = cbthis; - m_checking = checking; - clear(); // We reuse this structure in the main loop, so put initializers inside clear() - } - void clear() { - m_whyNotOptimizable = NULL; - m_anyAssignComb = false; - m_anyAssignDly = false; - m_inDlyAssign = false; - m_instrCount = 0; - m_dataCount = 0; - - AstNode::user1ClearTree(); // user1p() used on entire tree - AstNode::user3ClearTree(); // user3p() used on entire tree - AstNode::user4ClearTree(); // user4p() used on entire tree - - // Move all allocated numbers to the free pool - m_numFreeps = m_numAllps; - } - void main (AstNode* nodep) { - nodep->accept(*this); - } - virtual ~TableSimulateVisitor() { - for (deque::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) { - delete (*it); - } - m_numFreeps.clear(); - m_numAllps.clear(); } + virtual ~TableSimulateVisitor() {} }; - //###################################################################### // Table class functions -class TableVisitor : public TableBaseVisitor { +class TableVisitor : public AstNVisitor { private: // NODE STATE // Cleared on each always/assignw - AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; - AstUser4InUse m_inuser4; // STATE double m_totalBytes; // Total bytes in tables created @@ -432,6 +100,12 @@ private: deque m_tableVarps; // Table being created // METHODS + static int debug() { + static int level = -1; + if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); + return level; + } + bool treeTest(AstAlways* nodep) { // Process alw/assign tree m_inWidth = 0;