2012-04-13 03:08:20 +02:00
|
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2009-07-14 17:24:21 +02:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
// DESCRIPTION: Verilator: Simulate code to determine output values/variables
|
|
|
|
|
|
//
|
|
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
|
|
|
|
|
//
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
//
|
2018-01-03 00:05:06 +01:00
|
|
|
|
// Copyright 2003-2018 by Wilson Snyder. This program is free software; you can
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// 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() {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
// SimulateVisitor simvis (false, false);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// simvis.clear();
|
|
|
|
|
|
// // Set all inputs to the constant
|
|
|
|
|
|
// for (deque<AstVarScope*>::iterator it = m_inVarps.begin(); it!=m_inVarps.end(); ++it) {
|
|
|
|
|
|
// simvis.newNumber(invscp, #);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// // Simulate
|
|
|
|
|
|
// simvis.main(nodep);
|
|
|
|
|
|
// // Read outputs
|
|
|
|
|
|
// for (deque<AstVarScope*>::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"
|
2009-07-17 20:13:11 +02:00
|
|
|
|
#include "V3Width.h"
|
2009-12-01 00:36:31 +01:00
|
|
|
|
#include "V3Task.h"
|
2009-07-14 17:24:21 +02:00
|
|
|
|
|
2009-10-31 15:08:38 +01:00
|
|
|
|
#include <deque>
|
2017-05-10 00:54:15 +02:00
|
|
|
|
#include <sstream>
|
2009-10-31 15:08:38 +01:00
|
|
|
|
|
2009-07-14 17:24:21 +02:00
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
// Simulate class functions
|
|
|
|
|
|
|
2017-05-10 00:54:15 +02:00
|
|
|
|
class SimulateStackNode {
|
|
|
|
|
|
public:
|
|
|
|
|
|
// MEMBERS
|
|
|
|
|
|
AstFuncRef* m_funcp;
|
|
|
|
|
|
V3TaskConnects* m_tconnects;
|
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
|
SimulateStackNode(AstFuncRef* funcp, V3TaskConnects* tconnects):
|
|
|
|
|
|
m_funcp(funcp),
|
|
|
|
|
|
m_tconnects(tconnects) {}
|
|
|
|
|
|
~SimulateStackNode() {}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2009-07-14 17:24:21 +02:00
|
|
|
|
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;
|
2009-07-16 21:30:34 +02:00
|
|
|
|
AstUser2InUse m_inuser2;
|
2009-07-14 17:24:21 +02:00
|
|
|
|
AstUser3InUse m_inuser3;
|
|
|
|
|
|
|
|
|
|
|
|
// Checking:
|
2012-04-02 03:04:28 +02:00
|
|
|
|
// AstVar(Scope)::user1() -> VarUsage. Set true to indicate tracking as lvalue/rvalue
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// Simulating:
|
2012-04-02 03:04:28 +02:00
|
|
|
|
// AstVar(Scope)::user3() -> V3Number*. Input value of variable or node (and output for non-delayed assignments)
|
|
|
|
|
|
// AstVar(Scope)::user2() -> V3Number*. Output value of variable (delayed assignments)
|
2009-07-14 17:24:21 +02:00
|
|
|
|
|
|
|
|
|
|
enum VarUsage { VU_NONE=0, VU_LV=1, VU_RV=2, VU_LVDLY=4 };
|
|
|
|
|
|
|
|
|
|
|
|
// STATE
|
2009-07-17 20:13:11 +02:00
|
|
|
|
// Major mode
|
2009-07-21 20:31:16 +02:00
|
|
|
|
bool m_checkOnly; ///< Checking only (no simulation) mode
|
2009-07-16 21:30:34 +02:00
|
|
|
|
bool m_scoped; ///< Running with AstVarScopes instead of AstVars
|
2009-07-17 20:13:11 +02:00
|
|
|
|
bool m_params; ///< Doing parameter propagation
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// Checking:
|
2009-07-17 20:13:11 +02:00
|
|
|
|
string m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize
|
2009-07-16 21:30:34 +02:00
|
|
|
|
AstNode* m_whyNotNodep; ///< First node not optimizable
|
2009-07-14 17:24:21 +02:00
|
|
|
|
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
|
2010-02-14 16:01:21 +01:00
|
|
|
|
AstJumpGo* m_jumpp; ///< Jump label we're branching from
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// Simulating:
|
|
|
|
|
|
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
|
|
|
|
|
|
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
|
2017-05-10 00:54:15 +02:00
|
|
|
|
deque<SimulateStackNode*> m_callStack; ///< Call stack for verbose error messages
|
2009-07-14 17:24:21 +02:00
|
|
|
|
|
2017-03-17 23:40:16 +01:00
|
|
|
|
// Cleanup
|
|
|
|
|
|
// V3Numbers that represents strings are a bit special and the API for V3Number does not allow changing them.
|
|
|
|
|
|
deque<V3Number*> m_stringNumbersp; // List of allocated string numbers
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-05-10 00:54:15 +02:00
|
|
|
|
// Potentially very slow, intended for debugging
|
|
|
|
|
|
string prettyNumber(V3Number* nump, AstNodeDType* dtypep) {
|
|
|
|
|
|
if (AstRefDType* refdtypep = dtypep->castRefDType()) {
|
|
|
|
|
|
dtypep = refdtypep->skipRefp();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (AstStructDType* stp = dtypep->castStructDType()) {
|
|
|
|
|
|
if (stp->packed()) {
|
|
|
|
|
|
ostringstream out;
|
|
|
|
|
|
out<<"'{";
|
|
|
|
|
|
for (AstMemberDType* itemp = stp->membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
|
|
|
|
|
|
int width = itemp->width();
|
|
|
|
|
|
int lsb = itemp->lsb();
|
|
|
|
|
|
int msb = lsb + width - 1;
|
|
|
|
|
|
V3Number fieldNum = V3Number(nump->fileline(), width);
|
|
|
|
|
|
fieldNum.opSel(*nump, msb, lsb);
|
|
|
|
|
|
out<<itemp->name()<<": ";
|
|
|
|
|
|
if (AstNodeDType * childTypep = itemp->subDTypep()) {
|
|
|
|
|
|
out<<prettyNumber(&fieldNum, childTypep);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
out<<fieldNum;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (itemp->nextp()) out<<", ";
|
|
|
|
|
|
}
|
|
|
|
|
|
out<<"}";
|
|
|
|
|
|
return out.str();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (AstPackArrayDType * arrayp = dtypep->castPackArrayDType()) {
|
|
|
|
|
|
if (AstNodeDType * childTypep = arrayp->subDTypep()) {
|
|
|
|
|
|
ostringstream out;
|
|
|
|
|
|
out<<"[";
|
|
|
|
|
|
int arrayElements = arrayp->elementsConst();
|
|
|
|
|
|
for (int element = 0; element < arrayElements; ++element) {
|
|
|
|
|
|
int width = childTypep->width();
|
|
|
|
|
|
int lsb = width * element;
|
|
|
|
|
|
int msb = lsb + width - 1;
|
|
|
|
|
|
V3Number fieldNum = V3Number(nump->fileline(), width);
|
|
|
|
|
|
fieldNum.opSel(*nump, msb, lsb);
|
|
|
|
|
|
int arrayElem = arrayp->lsb() + element;
|
|
|
|
|
|
out<<arrayElem<<" = "<<prettyNumber(&fieldNum, childTypep);
|
|
|
|
|
|
if (element < arrayElements - 1) out<<", ";
|
|
|
|
|
|
}
|
|
|
|
|
|
out<<"]";
|
|
|
|
|
|
return out.str();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return nump->ascii();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// Checking METHODS
|
|
|
|
|
|
public:
|
2012-05-04 03:59:47 +02:00
|
|
|
|
/// Call other-this function on all new *non-constant* var references
|
2009-07-14 17:24:21 +02:00
|
|
|
|
virtual void varRefCb(AstVarRef* nodep) {}
|
|
|
|
|
|
|
2009-07-17 20:13:11 +02:00
|
|
|
|
void clearOptimizable(AstNode* nodep/*null ok*/, const string& why) {
|
2009-07-21 20:31:16 +02:00
|
|
|
|
// Something bad found. optimizable() will return false,
|
|
|
|
|
|
// and fetchNumber should not be called or it may assert.
|
2009-07-17 20:13:11 +02:00
|
|
|
|
if (!m_whyNotNodep) {
|
2009-07-16 21:30:34 +02:00
|
|
|
|
m_whyNotNodep = nodep;
|
2009-07-14 17:24:21 +02:00
|
|
|
|
if (debug()>=5) {
|
|
|
|
|
|
UINFO(0,"Clear optimizable: "<<why);
|
|
|
|
|
|
if (nodep) cout<<": "<<nodep;
|
|
|
|
|
|
cout<<endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_whyNotOptimizable = why;
|
2017-05-10 00:54:15 +02:00
|
|
|
|
ostringstream stack;
|
|
|
|
|
|
for (deque<SimulateStackNode*>::iterator it=m_callStack.begin(); it !=m_callStack.end(); ++it) {
|
|
|
|
|
|
AstFuncRef* funcp = (*it)->m_funcp;
|
|
|
|
|
|
stack<<"\nCalled from:\n"<<funcp->fileline()<<" "<<funcp->prettyName()<<"() with parameters:";
|
|
|
|
|
|
V3TaskConnects* tconnects = (*it)->m_tconnects;
|
|
|
|
|
|
for (V3TaskConnects::iterator conIt = tconnects->begin(); conIt != tconnects->end(); ++conIt) {
|
|
|
|
|
|
AstVar* portp = conIt->first;
|
|
|
|
|
|
AstNode* pinp = conIt->second->exprp();
|
|
|
|
|
|
AstNodeDType* dtypep = pinp->dtypep();
|
|
|
|
|
|
stack<<"\n "<<portp->prettyName()<<" = "<<prettyNumber(fetchNumber(pinp), dtypep);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
m_whyNotOptimizable += stack.str();
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2009-07-21 20:31:16 +02:00
|
|
|
|
inline bool optimizable() const { return m_whyNotNodep==NULL; }
|
2009-07-17 20:13:11 +02:00
|
|
|
|
string whyNotMessage() const { return m_whyNotOptimizable; }
|
|
|
|
|
|
AstNode* whyNotNodep() const { return m_whyNotNodep; }
|
|
|
|
|
|
|
2009-07-14 17:24:21 +02:00
|
|
|
|
bool isAssignDly() const { return m_anyAssignDly; }
|
|
|
|
|
|
int instrCount() const { return m_instrCount; }
|
|
|
|
|
|
int dataCount() const { return m_dataCount; }
|
|
|
|
|
|
|
|
|
|
|
|
// Simulation METHODS
|
|
|
|
|
|
private:
|
|
|
|
|
|
V3Number* allocNumber(AstNode* nodep, uint32_t value) {
|
|
|
|
|
|
// Save time - kept a list of allocated but unused V3Numbers
|
|
|
|
|
|
// It would be more efficient to do this by size, but the extra accounting
|
|
|
|
|
|
// slows things down more than we gain.
|
|
|
|
|
|
V3Number* nump;
|
|
|
|
|
|
if (!m_numFreeps.empty()) {
|
|
|
|
|
|
//UINFO(7,"Num Reuse "<<nodep->width()<<endl);
|
|
|
|
|
|
nump = m_numFreeps.back(); m_numFreeps.pop_back();
|
|
|
|
|
|
nump->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 "<<nodep->width()<<endl);
|
|
|
|
|
|
nump = new V3Number (nodep->fileline(), nodep->width(), value);
|
|
|
|
|
|
m_numAllps.push_back(nump);
|
|
|
|
|
|
}
|
2012-04-03 03:58:40 +02:00
|
|
|
|
nump->isDouble(nodep->isDouble());
|
2009-07-14 17:24:21 +02:00
|
|
|
|
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);
|
2009-07-17 20:13:11 +02:00
|
|
|
|
return nump;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return (fetchNumber(nodep));
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
V3Number* newOutNumber(AstNode* nodep, uint32_t value=0) {
|
|
|
|
|
|
// Set a constant value for this node
|
2009-07-16 21:30:34 +02:00
|
|
|
|
if (!nodep->user2p()) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
V3Number* nump = allocNumber(nodep, value);
|
|
|
|
|
|
setOutNumber(nodep, nump);
|
2009-07-17 20:13:11 +02:00
|
|
|
|
return nump;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return (fetchOutNumber(nodep));
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
V3Number* fetchNumberNull(AstNode* nodep) {
|
|
|
|
|
|
return ((V3Number*)nodep->user3p());
|
|
|
|
|
|
}
|
|
|
|
|
|
V3Number* fetchOutNumberNull(AstNode* nodep) {
|
2009-07-16 21:30:34 +02:00
|
|
|
|
return ((V3Number*)nodep->user2p());
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
V3Number* fetchNumber(AstNode* nodep) {
|
|
|
|
|
|
V3Number* nump = fetchNumberNull(nodep);
|
|
|
|
|
|
if (!nump) nodep->v3fatalSrc("No value found for node.");
|
2009-07-17 20:13:11 +02:00
|
|
|
|
//UINFO(9," fetch num "<<*nump<<" on "<<nodep<<endl);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
return nump;
|
|
|
|
|
|
}
|
|
|
|
|
|
V3Number* fetchOutNumber(AstNode* nodep) {
|
|
|
|
|
|
V3Number* nump = fetchOutNumberNull(nodep);
|
|
|
|
|
|
if (!nump) nodep->v3fatalSrc("No value found for node.");
|
|
|
|
|
|
return nump;
|
|
|
|
|
|
}
|
|
|
|
|
|
private:
|
2009-07-17 20:13:11 +02:00
|
|
|
|
inline void setNumber(AstNode* nodep, const V3Number* nump) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
UINFO(9," set num "<<*nump<<" on "<<nodep<<endl);
|
2016-11-27 15:40:12 +01:00
|
|
|
|
nodep->user3p((void*)nump);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
2009-07-17 20:13:11 +02:00
|
|
|
|
inline void setOutNumber(AstNode* nodep, const V3Number* nump) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
UINFO(9," set num "<<*nump<<" on "<<nodep<<endl);
|
2016-11-27 15:40:12 +01:00
|
|
|
|
nodep->user2p((void*)nump);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void checkNodeInfo(AstNode* nodep) {
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (m_checkOnly) {
|
|
|
|
|
|
m_instrCount += nodep->instrCount();
|
|
|
|
|
|
m_dataCount += nodep->width();
|
|
|
|
|
|
}
|
2009-07-14 17:24:21 +02:00
|
|
|
|
if (!nodep->isPredictOptimizable()) {
|
|
|
|
|
|
//UINFO(9," !predictopt "<<nodep<<endl);
|
2009-07-16 21:30:34 +02:00
|
|
|
|
clearOptimizable(nodep,"Isn't predictable");
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-07-17 20:13:11 +02:00
|
|
|
|
void badNodeType(AstNode* nodep) {
|
|
|
|
|
|
// Call for default node types, or other node types we don't know how to handle
|
2009-07-21 20:31:16 +02:00
|
|
|
|
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");
|
2009-07-17 20:13:11 +02:00
|
|
|
|
#ifdef VL_DEBUG
|
2009-07-21 20:31:16 +02:00
|
|
|
|
UINFO(0,"Unknown node type in SimulateVisitor: "<<nodep->prettyTypeName()<<endl);
|
2009-07-17 20:13:11 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-07-16 21:30:34 +02:00
|
|
|
|
AstNode* varOrScope(AstVarRef* nodep) {
|
|
|
|
|
|
AstNode* vscp;
|
|
|
|
|
|
if (m_scoped) vscp = nodep->varScopep();
|
|
|
|
|
|
else vscp = nodep->varp();
|
|
|
|
|
|
if (!vscp) nodep->v3fatalSrc("Not linked");
|
|
|
|
|
|
return vscp;
|
|
|
|
|
|
}
|
2009-07-17 20:13:11 +02:00
|
|
|
|
int unrollCount() {
|
|
|
|
|
|
return m_params ? v3Global.opt.unrollCount()*16
|
|
|
|
|
|
: v3Global.opt.unrollCount();
|
|
|
|
|
|
}
|
2010-02-14 16:01:21 +01:00
|
|
|
|
bool jumpingOver(AstNode* nodep) {
|
|
|
|
|
|
// True to jump over this node - all visitors must call this up front
|
|
|
|
|
|
return (m_jumpp && m_jumpp->labelp()!=nodep);
|
|
|
|
|
|
}
|
2015-05-09 20:01:54 +02:00
|
|
|
|
void assignOutNumber(AstNodeAssign* nodep, AstNode* vscp, const V3Number* nump) {
|
|
|
|
|
|
// Don't do setNumber, as value isn't yet visible to following statements
|
|
|
|
|
|
if (nodep->castAssignDly()) {
|
|
|
|
|
|
// Don't do setNumber, as value isn't yet visible to following statements
|
|
|
|
|
|
newOutNumber(vscp)->opAssign(*nump);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newNumber(vscp)->opAssign(*nump);
|
|
|
|
|
|
newOutNumber(vscp)->opAssign(*nump);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-02-14 16:01:21 +01:00
|
|
|
|
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// VISITORS
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstAlways* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-21 20:31:16 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstSenTree* nodep) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstVarRef* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
2015-11-23 02:46:26 +01:00
|
|
|
|
nodep->varp()->iterateChildren(*this);
|
2009-07-16 21:30:34 +02:00
|
|
|
|
AstNode* vscp = varOrScope(nodep);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
|
|
|
|
|
|
// 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.
|
2015-08-13 01:29:06 +02:00
|
|
|
|
if (!nodep->varp()->dtypeSkipRefp()->castBasicDType()
|
2015-09-30 03:02:33 +02:00
|
|
|
|
&& !nodep->varp()->dtypeSkipRefp()->castPackArrayDType()
|
|
|
|
|
|
&& !nodep->varp()->dtypeSkipRefp()->castStructDType())
|
2015-08-13 01:29:06 +02:00
|
|
|
|
clearOptimizable(nodep,"Array references/not basic");
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (nodep->lvalue()) {
|
|
|
|
|
|
if (m_inDlyAssign) {
|
|
|
|
|
|
if (!(vscp->user1() & VU_LVDLY)) {
|
|
|
|
|
|
vscp->user1( vscp->user1() | VU_LVDLY);
|
|
|
|
|
|
if (m_checkOnly) varRefCb (nodep);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
2009-07-21 20:31:16 +02:00
|
|
|
|
} else { // nondly asn
|
|
|
|
|
|
if (!(vscp->user1() & VU_LV)) {
|
|
|
|
|
|
if (!m_params && (vscp->user1() & VU_RV)) clearOptimizable(nodep,"Var read & write");
|
|
|
|
|
|
vscp->user1( vscp->user1() | VU_LV);
|
|
|
|
|
|
if (m_checkOnly) varRefCb (nodep);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2009-07-21 20:31:16 +02:00
|
|
|
|
} else {
|
|
|
|
|
|
if (!(vscp->user1() & VU_RV)) {
|
|
|
|
|
|
if (!m_params && (vscp->user1() & VU_LV)) clearOptimizable(nodep,"Var write & read");
|
|
|
|
|
|
vscp->user1( vscp->user1() | VU_RV);
|
2012-05-04 03:59:47 +02:00
|
|
|
|
bool isConst = nodep->varp()->isParam();
|
2015-11-23 02:46:26 +01:00
|
|
|
|
V3Number* nump = isConst ? fetchNumberNull(nodep->varp()->valuep()) : NULL;
|
|
|
|
|
|
if (isConst && nump) { // Propagate PARAM constants for constant function analysis
|
2012-05-04 03:59:47 +02:00
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
2015-11-23 02:46:26 +01:00
|
|
|
|
newNumber(vscp)->opAssign(*nump);
|
2012-05-04 03:59:47 +02:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (m_checkOnly) varRefCb (nodep);
|
|
|
|
|
|
}
|
2009-07-21 20:31:16 +02:00
|
|
|
|
}
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!m_checkOnly && optimizable()) { // simulating
|
2009-07-14 17:24:21 +02:00
|
|
|
|
if (nodep->lvalue()) {
|
|
|
|
|
|
nodep->v3fatalSrc("LHS varref should be handled in AstAssign visitor.");
|
|
|
|
|
|
} else {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
// Return simulation value - copy by reference instead of value for speed
|
2009-07-14 17:24:21 +02:00
|
|
|
|
V3Number* nump = fetchNumberNull(vscp);
|
2009-07-17 20:13:11 +02:00
|
|
|
|
if (!nump) {
|
|
|
|
|
|
if (m_params) {
|
|
|
|
|
|
clearOptimizable(nodep,"Language violation: reference to non-function-local variable");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->v3fatalSrc("Variable value should have been set before any visitor called.");
|
|
|
|
|
|
}
|
|
|
|
|
|
nump = allocNumber(nodep, 0); // Any value; just so recover from error
|
|
|
|
|
|
}
|
2009-07-14 17:24:21 +02:00
|
|
|
|
setNumber(nodep, nump);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstVarXRef* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
if (m_scoped) { badNodeType(nodep); return; }
|
|
|
|
|
|
else { clearOptimizable(nodep,"Language violation: Dotted hierarchical references not allowed in constant functions"); }
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeFTask* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
if (!m_params) { badNodeType(nodep); return; }
|
2009-12-03 12:55:29 +01:00
|
|
|
|
if (nodep->dpiImport()) { clearOptimizable(nodep,"DPI import functions aren't simulatable"); }
|
2009-07-17 20:13:11 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeIf* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
UINFO(5," IF "<<nodep<<endl);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (m_checkOnly) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->condp()->iterateAndNext(*this);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (optimizable()) {
|
|
|
|
|
|
if (fetchNumber(nodep->condp())->isNeqZero()) {
|
|
|
|
|
|
nodep->ifsp()->iterateAndNext(*this);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->elsesp()->iterateAndNext(*this);
|
|
|
|
|
|
}
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstConst* nodep) {
|
2009-07-21 20:31:16 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
setNumber(nodep, &(nodep->num()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstEnumItemRef* nodep) {
|
2015-10-02 03:15:01 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (!nodep->itemp()) nodep->v3fatalSrc("Not linked");
|
|
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
|
|
|
|
|
AstNode* valuep = nodep->itemp()->valuep();
|
|
|
|
|
|
if (valuep) {
|
|
|
|
|
|
valuep->iterateAndNext(*this);
|
2016-11-30 02:40:58 +01:00
|
|
|
|
if (optimizable()) {
|
|
|
|
|
|
newNumber(nodep)->opAssign(*fetchNumber(valuep));
|
|
|
|
|
|
}
|
2015-10-02 03:15:01 +02:00
|
|
|
|
} else {
|
|
|
|
|
|
clearOptimizable(nodep, "No value found for enum item");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeUniop* nodep) {
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeBiop* nodep) {
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp()), *fetchNumber(nodep->rhsp()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeTriop* nodep) {
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
nodep->numberOperate(*newNumber(nodep),
|
|
|
|
|
|
*fetchNumber(nodep->lhsp()),
|
|
|
|
|
|
*fetchNumber(nodep->rhsp()),
|
|
|
|
|
|
*fetchNumber(nodep->thsp()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstLogAnd* nodep) {
|
2011-12-22 14:33:16 +01:00
|
|
|
|
// Need to short circuit
|
|
|
|
|
|
if (!optimizable()) return; // Accelerate
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (m_checkOnly) {
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->lhsp()->accept(*this);
|
2016-11-30 02:40:58 +01:00
|
|
|
|
if (optimizable()) {
|
|
|
|
|
|
if (fetchNumber(nodep->lhsp())->isNeqZero()) {
|
|
|
|
|
|
nodep->rhsp()->accept(*this);
|
|
|
|
|
|
newNumber(nodep)->opAssign(*fetchNumber(nodep->rhsp()));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newNumber(nodep)->opAssign(*fetchNumber(nodep->lhsp())); // a zero
|
|
|
|
|
|
}
|
2011-12-22 14:33:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstLogOr* nodep) {
|
2011-12-22 14:33:16 +01:00
|
|
|
|
// Need to short circuit
|
|
|
|
|
|
if (!optimizable()) return; // Accelerate
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (m_checkOnly) {
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->lhsp()->accept(*this);
|
2016-11-30 02:40:58 +01:00
|
|
|
|
if (optimizable()) {
|
|
|
|
|
|
if (fetchNumber(nodep->lhsp())->isNeqZero()) {
|
|
|
|
|
|
newNumber(nodep)->opAssign(*fetchNumber(nodep->lhsp())); // a one
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->rhsp()->accept(*this);
|
|
|
|
|
|
newNumber(nodep)->opAssign(*fetchNumber(nodep->rhsp()));
|
|
|
|
|
|
}
|
2011-12-22 14:33:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstLogIf* nodep) {
|
2011-12-22 14:33:16 +01:00
|
|
|
|
// Need to short circuit, same as (!A || B)
|
|
|
|
|
|
if (!optimizable()) return; // Accelerate
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (m_checkOnly) {
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->lhsp()->accept(*this);
|
2016-11-30 02:40:58 +01:00
|
|
|
|
if (optimizable()) {
|
|
|
|
|
|
if (fetchNumber(nodep->lhsp())->isEqZero()) {
|
|
|
|
|
|
newNumber(nodep)->opAssign(V3Number(nodep->fileline(), 1, 1)); // a one
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->rhsp()->accept(*this);
|
|
|
|
|
|
newNumber(nodep)->opAssign(*fetchNumber(nodep->rhsp()));
|
|
|
|
|
|
}
|
2011-12-22 14:33:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeCond* nodep) {
|
2011-12-22 14:33:16 +01:00
|
|
|
|
// We could use above visit(AstNodeTriop), but need to do short circuiting.
|
|
|
|
|
|
// It's also slower even O(n^2) to evaluate both sides when we really only need to evaluate one side.
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (m_checkOnly) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
nodep->condp()->accept(*this);
|
2016-11-30 02:40:58 +01:00
|
|
|
|
if (optimizable()) {
|
|
|
|
|
|
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()));
|
|
|
|
|
|
}
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-11-12 02:49:45 +01:00
|
|
|
|
|
2017-03-31 01:05:55 +02:00
|
|
|
|
void handleAssignSel(AstNodeAssign* nodep, AstSel* selp) {
|
|
|
|
|
|
AstVarRef* varrefp = NULL;
|
|
|
|
|
|
V3Number lsb = V3Number(nodep->fileline());
|
|
|
|
|
|
nodep->rhsp()->iterateAndNext(*this); // Value to assign
|
|
|
|
|
|
handleAssignSelRecurse(nodep, selp, varrefp/*ref*/, lsb/*ref*/, 0);
|
|
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
|
|
|
|
|
if (!varrefp) nodep->v3fatalSrc("Indicated optimizable, but no variable found on RHS of select");
|
|
|
|
|
|
AstNode* vscp = varOrScope(varrefp);
|
|
|
|
|
|
V3Number outnum = V3Number(nodep->fileline());
|
|
|
|
|
|
if (V3Number* vscpnump = fetchOutNumberNull(vscp)) {
|
|
|
|
|
|
outnum = *vscpnump;
|
|
|
|
|
|
} else if (V3Number* vscpnump = fetchNumberNull(vscp)) {
|
|
|
|
|
|
outnum = *vscpnump;
|
|
|
|
|
|
} else { // Assignment to unassigned variable, all bits are X or 0
|
|
|
|
|
|
outnum = V3Number(nodep->fileline(), varrefp->varp()->widthMin());
|
|
|
|
|
|
if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) {
|
|
|
|
|
|
outnum.setAllBits0();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
outnum.setAllBitsX();
|
2015-11-12 02:49:45 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-03-31 01:05:55 +02:00
|
|
|
|
outnum.opSelInto(*fetchNumber(nodep->rhsp()),
|
|
|
|
|
|
lsb,
|
|
|
|
|
|
selp->widthConst());
|
|
|
|
|
|
assignOutNumber(nodep, vscp, &outnum);
|
2015-11-12 02:49:45 +01:00
|
|
|
|
}
|
2017-03-31 01:05:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
void handleAssignSelRecurse (AstNodeAssign* nodep, AstSel* selp,
|
|
|
|
|
|
AstVarRef*& outVarrefpRef, V3Number& lsbRef,
|
|
|
|
|
|
int depth) {
|
|
|
|
|
|
// Recurse down to find final variable being set (outVarrefp), with value to write on nodep->rhsp()
|
|
|
|
|
|
checkNodeInfo(selp);
|
|
|
|
|
|
selp->lsbp()->iterateAndNext(*this); // Bit index
|
|
|
|
|
|
if (AstVarRef* varrefp = selp->fromp()->castVarRef()) {
|
|
|
|
|
|
outVarrefpRef = varrefp;
|
|
|
|
|
|
lsbRef = *fetchNumber(selp->lsbp());
|
|
|
|
|
|
return; // And presumably still optimizable()
|
|
|
|
|
|
} else if (AstSel* subselp = selp->lhsp()->castSel()) {
|
|
|
|
|
|
V3Number sublsb = V3Number(nodep->fileline());
|
|
|
|
|
|
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb/*ref*/, depth+1);
|
2015-11-12 02:49:45 +01:00
|
|
|
|
if (optimizable()) {
|
2017-03-31 01:05:55 +02:00
|
|
|
|
lsbRef = sublsb;
|
|
|
|
|
|
lsbRef.opAdd(sublsb, *fetchNumber(selp->lsbp()));
|
2015-11-12 02:49:45 +01:00
|
|
|
|
}
|
2017-03-31 01:05:55 +02:00
|
|
|
|
} else {
|
|
|
|
|
|
clearOptimizable(nodep, "Select LHS isn't simple variable");
|
2015-11-12 02:49:45 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeAssign* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
|
|
|
|
|
if (nodep->castAssignDly()) {
|
2013-07-30 03:53:43 +02:00
|
|
|
|
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non-dly assigns");
|
2009-07-21 20:31:16 +02:00
|
|
|
|
m_anyAssignDly = true;
|
|
|
|
|
|
m_inDlyAssign = true;
|
|
|
|
|
|
} else {
|
2013-07-30 03:53:43 +02:00
|
|
|
|
if (m_anyAssignDly) clearOptimizable(nodep, "Mix of dly/non-dly assigns");
|
2009-07-21 20:31:16 +02:00
|
|
|
|
m_anyAssignComb = true;
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
2015-11-12 02:49:45 +01:00
|
|
|
|
|
2015-05-09 20:01:54 +02:00
|
|
|
|
if (AstSel* selp = nodep->lhsp()->castSel()) {
|
|
|
|
|
|
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
|
2017-03-31 01:05:55 +02:00
|
|
|
|
handleAssignSel(nodep, selp);
|
2015-05-09 20:01:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
else if (!nodep->lhsp()->castVarRef()) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
clearOptimizable(nodep, "LHS isn't simple variable");
|
|
|
|
|
|
}
|
2009-07-21 20:31:16 +02:00
|
|
|
|
else if (m_checkOnly) {
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (optimizable()) {
|
2009-07-14 17:24:21 +02:00
|
|
|
|
nodep->rhsp()->iterateAndNext(*this);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (optimizable()) {
|
|
|
|
|
|
AstNode* vscp = varOrScope(nodep->lhsp()->castVarRef());
|
2015-05-09 20:01:54 +02:00
|
|
|
|
assignOutNumber(nodep, vscp, fetchNumber(nodep->rhsp()));
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
m_inDlyAssign = false;
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstBegin* nodep) {
|
2009-07-21 20:31:16 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeCase* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
UINFO(5," CASE "<<nodep<<endl);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (m_checkOnly) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
} else if (optimizable()) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
nodep->exprp()->iterateAndNext(*this);
|
|
|
|
|
|
bool hit = false;
|
|
|
|
|
|
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
|
|
|
|
|
if (!itemp->isDefault()) {
|
|
|
|
|
|
for (AstNode* ep = itemp->condsp(); ep; ep=ep->nextp()) {
|
|
|
|
|
|
if (hit) break;
|
|
|
|
|
|
ep->iterateAndNext(*this);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (optimizable()) {
|
|
|
|
|
|
V3Number match (nodep->fileline(), 1);
|
|
|
|
|
|
match.opEq(*fetchNumber(nodep->exprp()), *fetchNumber(ep));
|
|
|
|
|
|
if (match.isNeqZero()) {
|
|
|
|
|
|
itemp->bodysp()->iterateAndNext(*this);
|
|
|
|
|
|
hit = true;
|
|
|
|
|
|
}
|
2009-07-17 20:13:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Else default match
|
|
|
|
|
|
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
|
|
|
|
|
if (hit) break;
|
|
|
|
|
|
if (!hit && itemp->isDefault()) {
|
|
|
|
|
|
itemp->bodysp()->iterateAndNext(*this);
|
|
|
|
|
|
hit = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstCaseItem* nodep) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
// Real handling is in AstNodeCase
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
}
|
2009-07-14 17:24:21 +02:00
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstComment*) {}
|
2009-07-17 20:13:11 +02:00
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstJumpGo* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (!m_checkOnly) {
|
|
|
|
|
|
UINFO(5," JUMP GO "<<nodep<<endl);
|
|
|
|
|
|
m_jumpp = nodep;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstJumpLabel* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
if (m_jumpp && m_jumpp->labelp() == nodep) {
|
|
|
|
|
|
UINFO(5," JUMP DONE "<<nodep<<endl);
|
|
|
|
|
|
m_jumpp = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstStop* nodep) {
|
2015-10-24 00:13:25 +02:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (m_params) { // This message seems better than an obscure $stop
|
|
|
|
|
|
// The spec says $stop is just ignored, it seems evil to ignore assertions
|
|
|
|
|
|
clearOptimizable(nodep,"$stop executed during function constification; maybe indicates assertion firing");
|
|
|
|
|
|
}
|
|
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNodeFor* nodep) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
// Doing lots of Whiles is slow, so only for parameters
|
|
|
|
|
|
UINFO(5," FOR "<<nodep<<endl);
|
|
|
|
|
|
if (!m_params) { badNodeType(nodep); return; }
|
2009-07-21 20:31:16 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (m_checkOnly) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
} else if (optimizable()) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
int loops = 0;
|
|
|
|
|
|
nodep->initsp()->iterateAndNext(*this);
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
UINFO(5," FOR-ITER "<<nodep<<endl);
|
|
|
|
|
|
nodep->condp()->iterateAndNext(*this);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!optimizable()) break;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
if (!fetchNumber(nodep->condp())->isNeqZero()) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
nodep->bodysp()->iterateAndNext(*this);
|
|
|
|
|
|
nodep->incsp()->iterateAndNext(*this);
|
|
|
|
|
|
if (loops++ > unrollCount()*16) {
|
|
|
|
|
|
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstWhile* nodep) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
// Doing lots of Whiles is slow, so only for parameters
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
UINFO(5," WHILE "<<nodep<<endl);
|
|
|
|
|
|
if (!m_params) { badNodeType(nodep); return; }
|
2009-07-21 20:31:16 +02:00
|
|
|
|
checkNodeInfo(nodep);
|
|
|
|
|
|
if (m_checkOnly) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
2009-07-21 20:31:16 +02:00
|
|
|
|
} else if (optimizable()) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
int loops = 0;
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
UINFO(5," WHILE-ITER "<<nodep<<endl);
|
|
|
|
|
|
nodep->precondsp()->iterateAndNext(*this);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) break;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
nodep->condp()->iterateAndNext(*this);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) break;
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!optimizable()) break;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
if (!fetchNumber(nodep->condp())->isNeqZero()) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
nodep->bodysp()->iterateAndNext(*this);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) break;
|
|
|
|
|
|
nodep->incsp()->iterateAndNext(*this);
|
|
|
|
|
|
if (jumpingOver(nodep)) break;
|
|
|
|
|
|
|
|
|
|
|
|
// Prep for next loop
|
2009-07-17 20:13:11 +02:00
|
|
|
|
if (loops++ > unrollCount()*16) {
|
|
|
|
|
|
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstFuncRef* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2016-11-30 02:40:58 +01:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
2009-07-17 20:13:11 +02:00
|
|
|
|
UINFO(5," FUNCREF "<<nodep<<endl);
|
|
|
|
|
|
if (!m_params) { badNodeType(nodep); return; }
|
2009-12-03 12:55:29 +01:00
|
|
|
|
AstNodeFTask* funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
2015-10-04 19:16:35 +02:00
|
|
|
|
if (m_params) { V3Width::widthParamsEdit(funcp); } VL_DANGLING(funcp); // Make sure we've sized the function
|
2009-12-03 12:55:29 +01:00
|
|
|
|
funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
2009-07-17 20:13:11 +02:00
|
|
|
|
// Apply function call values to function
|
2009-12-01 00:36:31 +01:00
|
|
|
|
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
|
2013-10-18 13:06:32 +02:00
|
|
|
|
// Must do this in two steps, eval all params, then apply them
|
|
|
|
|
|
// Otherwise chained functions may have the wrong results
|
2009-12-01 00:36:31 +01:00
|
|
|
|
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
|
|
|
|
|
|
AstVar* portp = it->first;
|
2013-08-18 02:34:49 +02:00
|
|
|
|
AstNode* pinp = it->second->exprp();
|
2013-10-18 13:06:32 +02:00
|
|
|
|
if (pinp) { // Else too few arguments in function call - ignore it
|
2009-12-01 00:36:31 +01:00
|
|
|
|
if (portp->isOutput()) {
|
|
|
|
|
|
clearOptimizable(portp,"Language violation: Outputs not allowed in constant functions");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Evaluate pin value
|
|
|
|
|
|
pinp->accept(*this);
|
2013-10-18 13:06:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
|
|
|
|
|
|
AstVar* portp = it->first;
|
|
|
|
|
|
AstNode* pinp = it->second->exprp();
|
|
|
|
|
|
if (pinp) { // Else too few arguments in function call - ignore it
|
2009-12-01 00:36:31 +01:00
|
|
|
|
// Apply value to the function
|
|
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
|
|
|
|
|
newNumber(portp)->opAssign(*fetchNumber(pinp));
|
2009-07-17 20:13:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-05-10 00:54:15 +02:00
|
|
|
|
SimulateStackNode stackNode(nodep, &tconnects);
|
|
|
|
|
|
m_callStack.push_front(&stackNode);
|
2009-07-17 20:13:11 +02:00
|
|
|
|
// Evaluate the function
|
|
|
|
|
|
funcp->accept(*this);
|
2017-05-10 00:54:15 +02:00
|
|
|
|
m_callStack.pop_front();
|
2009-07-21 20:31:16 +02:00
|
|
|
|
if (!m_checkOnly && optimizable()) {
|
2009-12-03 12:55:29 +01:00
|
|
|
|
// Grab return value from output variable (if it's a function)
|
|
|
|
|
|
if (!funcp->fvarp()) nodep->v3fatalSrc("Function reference points at non-function");
|
2009-07-17 20:13:11 +02:00
|
|
|
|
newNumber(nodep)->opAssign(*fetchNumber(funcp->fvarp()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstVar* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
if (!m_params) { badNodeType(nodep); return; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-03-17 23:40:16 +01:00
|
|
|
|
virtual void visit(AstScopeName *nodep) {
|
|
|
|
|
|
if (jumpingOver(nodep)) return;
|
|
|
|
|
|
if (!m_params) { badNodeType(nodep); return; }
|
|
|
|
|
|
// Ignore
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstSFormatF *nodep) {
|
2015-10-24 00:13:25 +02:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2016-11-30 02:40:58 +01:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
2015-10-24 00:13:25 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
if (m_params) {
|
|
|
|
|
|
AstNode* nextArgp = nodep->exprsp();
|
|
|
|
|
|
|
|
|
|
|
|
string result = "";
|
|
|
|
|
|
string format = nodep->text();
|
|
|
|
|
|
string::const_iterator pos = format.begin();
|
|
|
|
|
|
bool inPct = false;
|
|
|
|
|
|
for (; pos != format.end(); ++pos) {
|
|
|
|
|
|
if (!inPct && pos[0] == '%') {
|
|
|
|
|
|
inPct = true;
|
|
|
|
|
|
} else if (!inPct) { // Normal text
|
|
|
|
|
|
result += *pos;
|
|
|
|
|
|
} else { // Format character
|
|
|
|
|
|
inPct = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (V3Number::displayedFmtLegal(tolower(pos[0]))) {
|
2017-03-17 23:40:16 +01:00
|
|
|
|
AstNode* argp = nextArgp;
|
|
|
|
|
|
nextArgp = nextArgp->nextp();
|
2015-10-24 00:13:25 +02:00
|
|
|
|
V3Number* nump = fetchNumberNull(argp);
|
|
|
|
|
|
if (!nump) {
|
|
|
|
|
|
clearOptimizable(nodep, "Argument for $display like statement is not constant");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
string format = string("%") + pos[0];
|
2015-11-11 03:12:15 +01:00
|
|
|
|
result += nump->displayed(nodep->fileline(), format);
|
2015-10-24 00:13:25 +02:00
|
|
|
|
} else {
|
|
|
|
|
|
switch (tolower(pos[0])) {
|
|
|
|
|
|
case '%':
|
|
|
|
|
|
result += "%";
|
|
|
|
|
|
break;
|
2017-03-17 23:40:16 +01:00
|
|
|
|
case 'm':
|
|
|
|
|
|
// This happens prior to AstScope so we don't know the scope name. Leave the %m in place.
|
|
|
|
|
|
result += "%m";
|
|
|
|
|
|
break;
|
2015-10-24 00:13:25 +02:00
|
|
|
|
default:
|
|
|
|
|
|
clearOptimizable(nodep, "Unknown $display-like format code.");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-03-17 23:40:16 +01:00
|
|
|
|
|
|
|
|
|
|
V3Number* resultNump = new V3Number(V3Number::String(), nodep->fileline(), result);
|
|
|
|
|
|
setNumber(nodep, resultNump);
|
|
|
|
|
|
m_stringNumbersp.push_back(resultNump);
|
|
|
|
|
|
|
2015-10-24 00:13:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstDisplay *nodep) {
|
2015-10-24 00:13:25 +02:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2016-11-30 02:40:58 +01:00
|
|
|
|
if (!optimizable()) return; // Accelerate
|
2015-10-24 00:13:25 +02:00
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
|
if (m_params) {
|
2017-03-17 23:40:16 +01:00
|
|
|
|
V3Number* textp = fetchNumber(nodep->fmtp());
|
2015-10-24 00:13:25 +02:00
|
|
|
|
switch (nodep->displayType()) {
|
|
|
|
|
|
case AstDisplayType::DT_DISPLAY: // FALLTHRU
|
|
|
|
|
|
case AstDisplayType::DT_INFO:
|
2017-03-17 23:40:16 +01:00
|
|
|
|
v3warn(USERINFO, textp->toString());
|
2015-10-24 00:13:25 +02:00
|
|
|
|
break;
|
|
|
|
|
|
case AstDisplayType::DT_ERROR:
|
2017-03-17 23:40:16 +01:00
|
|
|
|
v3warn(USERERROR, textp->toString());
|
2015-10-24 00:13:25 +02:00
|
|
|
|
break;
|
|
|
|
|
|
case AstDisplayType::DT_WARNING:
|
2017-03-17 23:40:16 +01:00
|
|
|
|
v3warn(USERWARN, textp->toString());
|
2015-10-24 00:13:25 +02:00
|
|
|
|
break;
|
|
|
|
|
|
case AstDisplayType::DT_FATAL:
|
2017-03-17 23:40:16 +01:00
|
|
|
|
v3warn(USERFATAL, textp->toString());
|
2015-10-24 00:13:25 +02:00
|
|
|
|
break;
|
|
|
|
|
|
case AstDisplayType::DT_WRITE: // FALLTHRU
|
|
|
|
|
|
default:
|
|
|
|
|
|
clearOptimizable(nodep, "Unexpected display type");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// default
|
|
|
|
|
|
// These types are definately not reducable
|
2015-10-24 00:13:25 +02:00
|
|
|
|
// AstCoverInc, AstArraySel, AstFinish,
|
2009-07-14 17:24:21 +02:00
|
|
|
|
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
2016-11-27 14:11:38 +01:00
|
|
|
|
virtual void visit(AstNode* nodep) {
|
2010-02-14 16:01:21 +01:00
|
|
|
|
if (jumpingOver(nodep)) return;
|
2009-07-17 20:13:11 +02:00
|
|
|
|
badNodeType(nodep);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-02-14 16:01:21 +01:00
|
|
|
|
private:
|
|
|
|
|
|
// MEMBERS - called by constructor
|
|
|
|
|
|
void setMode(bool scoped, bool checkOnly, bool params) {
|
|
|
|
|
|
m_checkOnly = checkOnly;
|
|
|
|
|
|
m_scoped = scoped;
|
|
|
|
|
|
m_params = params;
|
|
|
|
|
|
}
|
|
|
|
|
|
void mainGuts(AstNode* nodep) {
|
|
|
|
|
|
nodep->accept(*this);
|
|
|
|
|
|
if (m_jumpp) {
|
|
|
|
|
|
m_jumpp->v3fatalSrc("JumpGo branched to label that wasn't found");
|
|
|
|
|
|
m_jumpp = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2009-07-14 17:24:21 +02:00
|
|
|
|
public:
|
|
|
|
|
|
// CONSTRUCTORS
|
2009-07-17 20:13:11 +02:00
|
|
|
|
SimulateVisitor() {
|
|
|
|
|
|
setMode(false,false,false);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
clear(); // We reuse this structure in the main loop, so put initializers inside clear()
|
|
|
|
|
|
}
|
|
|
|
|
|
void clear() {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
m_whyNotOptimizable = "";
|
2009-07-16 21:30:34 +02:00
|
|
|
|
m_whyNotNodep = NULL;
|
2009-07-14 17:24:21 +02:00
|
|
|
|
m_anyAssignComb = false;
|
|
|
|
|
|
m_anyAssignDly = false;
|
|
|
|
|
|
m_inDlyAssign = false;
|
|
|
|
|
|
m_instrCount = 0;
|
|
|
|
|
|
m_dataCount = 0;
|
2010-02-14 16:01:21 +01:00
|
|
|
|
m_jumpp = NULL;
|
2009-07-14 17:24:21 +02:00
|
|
|
|
|
|
|
|
|
|
AstNode::user1ClearTree(); // user1p() used on entire tree
|
2009-07-16 21:30:34 +02:00
|
|
|
|
AstNode::user2ClearTree(); // user2p() used on entire tree
|
2009-07-14 17:24:21 +02:00
|
|
|
|
AstNode::user3ClearTree(); // user3p() used on entire tree
|
|
|
|
|
|
|
|
|
|
|
|
// Move all allocated numbers to the free pool
|
|
|
|
|
|
m_numFreeps = m_numAllps;
|
|
|
|
|
|
}
|
2016-01-22 01:00:19 +01:00
|
|
|
|
void mainTableCheck (AstNode* nodep) {
|
2009-07-17 20:13:11 +02:00
|
|
|
|
setMode(true/*scoped*/,true/*checking*/, false/*params*/);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
mainGuts(nodep);
|
2009-07-17 20:13:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
void mainTableEmulate (AstNode* nodep) {
|
|
|
|
|
|
setMode(true/*scoped*/,false/*checking*/, false/*params*/);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
mainGuts(nodep);
|
2009-07-17 20:13:11 +02:00
|
|
|
|
}
|
2016-01-22 01:00:19 +01:00
|
|
|
|
void mainCheckTree (AstNode* nodep) {
|
|
|
|
|
|
setMode(false/*scoped*/,true/*checking*/, false/*params*/);
|
|
|
|
|
|
mainGuts(nodep);
|
|
|
|
|
|
}
|
2009-07-17 20:13:11 +02:00
|
|
|
|
void mainParamEmulate (AstNode* nodep) {
|
|
|
|
|
|
setMode(false/*scoped*/,false/*checking*/, true/*params*/);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
mainGuts(nodep);
|
2009-07-14 17:24:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
virtual ~SimulateVisitor() {
|
|
|
|
|
|
for (deque<V3Number*>::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) {
|
|
|
|
|
|
delete (*it);
|
|
|
|
|
|
}
|
2017-03-17 23:40:16 +01:00
|
|
|
|
for (deque<V3Number*>::iterator it = m_stringNumbersp.begin(); it != m_stringNumbersp.end(); ++it) {
|
|
|
|
|
|
delete (*it);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_stringNumbersp.clear();
|
2009-07-14 17:24:21 +02:00
|
|
|
|
m_numFreeps.clear();
|
|
|
|
|
|
m_numAllps.clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif // Guard
|