Clean up V3TraceDecl & V3Trace. No functional change intended.
- Constify variables - Remove redundancies - [Hopefully] make some code a bit more readable
This commit is contained in:
parent
85de3048a5
commit
12b95f6b93
|
|
@ -4811,33 +4811,33 @@ class AstTraceDecl : public AstNodeStmt {
|
||||||
// Parents: {statement list}
|
// Parents: {statement list}
|
||||||
// Children: none
|
// Children: none
|
||||||
private:
|
private:
|
||||||
string m_showname; // Name of variable
|
|
||||||
uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines
|
uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines
|
||||||
VNumRange m_bitRange; // Property of var the trace details
|
const string m_showname; // Name of variable
|
||||||
VNumRange m_arrayRange; // Property of var the trace details
|
const VNumRange m_bitRange; // Property of var the trace details
|
||||||
uint32_t m_codeInc; // Code increment
|
const VNumRange m_arrayRange; // Property of var the trace details
|
||||||
AstVarType m_varType; // Type of variable (for localparam vs. param)
|
const uint32_t m_codeInc; // Code increment
|
||||||
AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
|
const AstVarType m_varType; // Type of variable (for localparam vs. param)
|
||||||
VDirection m_declDirection; // Declared direction input/output etc
|
const AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
|
||||||
bool m_isScoped; // Uses run-time scope (for interfaces)
|
const VDirection m_declDirection; // Declared direction input/output etc
|
||||||
|
const bool m_isScoped; // Uses run-time scope (for interfaces)
|
||||||
public:
|
public:
|
||||||
AstTraceDecl(FileLine* fl, const string& showname,
|
AstTraceDecl(FileLine* fl, const string& showname,
|
||||||
AstVar* varp, // For input/output state etc
|
AstVar* varp, // For input/output state etc
|
||||||
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange,
|
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange,
|
||||||
bool isScoped)
|
bool isScoped)
|
||||||
: ASTGEN_SUPER(fl)
|
: ASTGEN_SUPER(fl)
|
||||||
|
, m_code(0)
|
||||||
, m_showname(showname)
|
, m_showname(showname)
|
||||||
, m_bitRange(bitRange)
|
, m_bitRange(bitRange)
|
||||||
, m_arrayRange(arrayRange)
|
, m_arrayRange(arrayRange)
|
||||||
|
, m_codeInc(
|
||||||
|
((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords()
|
||||||
|
* (VL_EDATASIZE / 32))) // A code is always 32-bits
|
||||||
|
, m_varType(varp->varType())
|
||||||
|
, m_declKwd(varp->declKwd())
|
||||||
|
, m_declDirection(varp->declDirection())
|
||||||
, m_isScoped(isScoped) {
|
, m_isScoped(isScoped) {
|
||||||
dtypeFrom(valuep);
|
dtypeFrom(valuep);
|
||||||
m_code = 0;
|
|
||||||
m_codeInc
|
|
||||||
= ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords()
|
|
||||||
* (VL_EDATASIZE / (8 * sizeof(uint32_t)))); // A code is always 32-bits
|
|
||||||
m_varType = varp->varType();
|
|
||||||
m_declKwd = varp->declKwd();
|
|
||||||
m_declDirection = varp->declDirection();
|
|
||||||
}
|
}
|
||||||
virtual int instrCount() const { return 100; } // Large...
|
virtual int instrCount() const { return 100; } // Large...
|
||||||
ASTNODE_NODE_FUNCS(TraceDecl)
|
ASTNODE_NODE_FUNCS(TraceDecl)
|
||||||
|
|
|
||||||
|
|
@ -3708,17 +3708,6 @@ class EmitCTrace : EmitCStmts {
|
||||||
puts("if (false && vcdp) {} // Prevent unused\n");
|
puts("if (false && vcdp) {} // Prevent unused\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodep->funcType() == AstCFuncType::TRACE_INIT) {
|
|
||||||
puts("vcdp->module(vlSymsp->name()); // Setup signal names\n");
|
|
||||||
} else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) {
|
|
||||||
} else if (nodep->funcType() == AstCFuncType::TRACE_FULL) {
|
|
||||||
} else if (nodep->funcType() == AstCFuncType::TRACE_FULL_SUB) {
|
|
||||||
} else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE) {
|
|
||||||
} else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE_SUB) {
|
|
||||||
} else {
|
|
||||||
nodep->v3fatalSrc("Bad Case");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodep->initsp()) {
|
if (nodep->initsp()) {
|
||||||
string section;
|
string section;
|
||||||
putsDecoration("// Variables\n");
|
putsDecoration("// Variables\n");
|
||||||
|
|
|
||||||
294
src/V3Trace.cpp
294
src/V3Trace.cpp
|
|
@ -52,7 +52,6 @@
|
||||||
#include "V3Hashed.h"
|
#include "V3Hashed.h"
|
||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
|
@ -183,10 +182,9 @@ private:
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNodeModule* m_topModp; // Module to add variables to
|
AstNodeModule* m_topModp; // Module to add variables to
|
||||||
AstScope* m_highScopep; // Scope to add variables to
|
AstScope* m_topScopep; // Scope to add variables to
|
||||||
AstCFunc* m_funcp; // C function adding to graph
|
AstCFunc* m_funcp; // C function adding to graph
|
||||||
AstTraceInc* m_tracep; // Trace function adding to graph
|
AstTraceInc* m_tracep; // Trace function adding to graph
|
||||||
AstCFunc* m_initFuncp; // Trace function we add statements to
|
|
||||||
AstCFunc* m_fullFuncp; // Trace function we add statements to
|
AstCFunc* m_fullFuncp; // Trace function we add statements to
|
||||||
AstCFunc* m_fullSubFuncp; // Trace function we add statements to (under full)
|
AstCFunc* m_fullSubFuncp; // Trace function we add statements to (under full)
|
||||||
int m_fullSubStmts; // Statements under function being built
|
int m_fullSubStmts; // Statements under function being built
|
||||||
|
|
@ -198,7 +196,7 @@ private:
|
||||||
uint32_t m_activityNumber; // Count of fields in activity variable
|
uint32_t m_activityNumber; // Count of fields in activity variable
|
||||||
uint32_t m_code; // Trace ident code# being assigned
|
uint32_t m_code; // Trace ident code# being assigned
|
||||||
V3Graph m_graph; // Var/CFunc tracking
|
V3Graph m_graph; // Var/CFunc tracking
|
||||||
TraceActivityVertex* m_alwaysVtxp; // "Always trace" vertex
|
TraceActivityVertex* const m_alwaysVtxp; // "Always trace" vertex
|
||||||
bool m_finding; // Pass one of algorithm?
|
bool m_finding; // Pass one of algorithm?
|
||||||
int m_funcNum; // Function number being built
|
int m_funcNum; // Function number being built
|
||||||
|
|
||||||
|
|
@ -214,9 +212,11 @@ private:
|
||||||
// Note uses user4
|
// Note uses user4
|
||||||
V3Hashed hashed; // Duplicate code detection
|
V3Hashed hashed; // Duplicate code detection
|
||||||
// Hash all of the values the traceIncs need
|
// Hash all of the values the traceIncs need
|
||||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
|
||||||
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
itp = itp->verticesNextp()) {
|
||||||
AstTraceInc* nodep = vvertexp->nodep();
|
if (const TraceTraceVertex* const vvertexp
|
||||||
|
= dynamic_cast<const TraceTraceVertex*>(itp)) {
|
||||||
|
const AstTraceInc* const nodep = vvertexp->nodep();
|
||||||
if (nodep->valuep()) {
|
if (nodep->valuep()) {
|
||||||
UASSERT_OBJ(nodep->valuep()->backp() == nodep, nodep,
|
UASSERT_OBJ(nodep->valuep()->backp() == nodep, nodep,
|
||||||
"Trace duplicate back needs consistency,"
|
"Trace duplicate back needs consistency,"
|
||||||
|
|
@ -234,15 +234,15 @@ private:
|
||||||
}
|
}
|
||||||
// Find if there are any duplicates
|
// Find if there are any duplicates
|
||||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||||
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
if (TraceTraceVertex* const vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
||||||
AstTraceInc* nodep = vvertexp->nodep();
|
AstTraceInc* const nodep = vvertexp->nodep();
|
||||||
if (nodep->valuep() && !vvertexp->duplicatep()) {
|
if (nodep->valuep() && !vvertexp->duplicatep()) {
|
||||||
V3Hashed::iterator dupit = hashed.findDuplicate(nodep->valuep());
|
V3Hashed::iterator dupit = hashed.findDuplicate(nodep->valuep());
|
||||||
if (dupit != hashed.end()) {
|
if (dupit != hashed.end()) {
|
||||||
AstTraceInc* dupincp
|
const AstTraceInc* const dupincp
|
||||||
= VN_CAST(hashed.iteratorNodep(dupit)->backp(), TraceInc);
|
= VN_CAST_CONST(hashed.iteratorNodep(dupit)->backp(), TraceInc);
|
||||||
UASSERT_OBJ(dupincp, nodep, "Trace duplicate of wrong type");
|
UASSERT_OBJ(dupincp, nodep, "Trace duplicate of wrong type");
|
||||||
TraceTraceVertex* dupvertexp
|
TraceTraceVertex* const dupvertexp
|
||||||
= dynamic_cast<TraceTraceVertex*>(dupincp->user1u().toGraphVertex());
|
= dynamic_cast<TraceTraceVertex*>(dupincp->user1u().toGraphVertex());
|
||||||
UINFO(8, " Orig " << nodep << endl);
|
UINFO(8, " Orig " << nodep << endl);
|
||||||
UINFO(8, " dup " << dupincp << endl);
|
UINFO(8, " dup " << dupincp << endl);
|
||||||
|
|
@ -260,7 +260,7 @@ private:
|
||||||
// Remove all variable nodes
|
// Remove all variable nodes
|
||||||
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
||||||
nextp = itp->verticesNextp();
|
nextp = itp->verticesNextp();
|
||||||
if (TraceVarVertex* vvertexp = dynamic_cast<TraceVarVertex*>(itp)) {
|
if (TraceVarVertex* const vvertexp = dynamic_cast<TraceVarVertex*>(itp)) {
|
||||||
vvertexp->rerouteEdges(&m_graph);
|
vvertexp->rerouteEdges(&m_graph);
|
||||||
vvertexp->unlinkDelete(&m_graph);
|
vvertexp->unlinkDelete(&m_graph);
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +271,7 @@ private:
|
||||||
// Remove all Cfunc nodes
|
// Remove all Cfunc nodes
|
||||||
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
||||||
nextp = itp->verticesNextp();
|
nextp = itp->verticesNextp();
|
||||||
if (TraceCFuncVertex* vvertexp = dynamic_cast<TraceCFuncVertex*>(itp)) {
|
if (TraceCFuncVertex* const vvertexp = dynamic_cast<TraceCFuncVertex*>(itp)) {
|
||||||
vvertexp->rerouteEdges(&m_graph);
|
vvertexp->rerouteEdges(&m_graph);
|
||||||
vvertexp->unlinkDelete(&m_graph);
|
vvertexp->unlinkDelete(&m_graph);
|
||||||
}
|
}
|
||||||
|
|
@ -281,12 +281,16 @@ private:
|
||||||
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
|
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
|
||||||
|
|
||||||
// If there are any edges from a always, keep only the always
|
// If there are any edges from a always, keep only the always
|
||||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
|
||||||
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
itp = itp->verticesNextp()) {
|
||||||
V3GraphEdge* alwaysEdgep = NULL;
|
if (const TraceTraceVertex* const vvertexp
|
||||||
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
= dynamic_cast<const TraceTraceVertex*>(itp)) {
|
||||||
TraceActivityVertex* actVtxp
|
// Search for the incoming always edge
|
||||||
= dynamic_cast<TraceActivityVertex*>(edgep->fromp());
|
const V3GraphEdge* alwaysEdgep = NULL;
|
||||||
|
for (const V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;
|
||||||
|
edgep = edgep->inNextp()) {
|
||||||
|
const TraceActivityVertex* const actVtxp
|
||||||
|
= dynamic_cast<const TraceActivityVertex*>(edgep->fromp());
|
||||||
UASSERT_OBJ(actVtxp, vvertexp->nodep(),
|
UASSERT_OBJ(actVtxp, vvertexp->nodep(),
|
||||||
"Tracing a node with FROM non activity");
|
"Tracing a node with FROM non activity");
|
||||||
if (actVtxp->activityAlways()) {
|
if (actVtxp->activityAlways()) {
|
||||||
|
|
@ -294,6 +298,7 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If always edge exists, remove all other edges
|
||||||
if (alwaysEdgep) {
|
if (alwaysEdgep) {
|
||||||
for (V3GraphEdge *nextp, *edgep = vvertexp->inBeginp(); edgep; edgep = nextp) {
|
for (V3GraphEdge *nextp, *edgep = vvertexp->inBeginp(); edgep; edgep = nextp) {
|
||||||
nextp = edgep->inNextp();
|
nextp = edgep->inNextp();
|
||||||
|
|
@ -306,17 +311,17 @@ private:
|
||||||
// Activity points with no outputs can be removed
|
// Activity points with no outputs can be removed
|
||||||
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
||||||
nextp = itp->verticesNextp();
|
nextp = itp->verticesNextp();
|
||||||
if (TraceActivityVertex* vvertexp = dynamic_cast<TraceActivityVertex*>(itp)) {
|
if (TraceActivityVertex* const vvertexp = dynamic_cast<TraceActivityVertex*>(itp)) {
|
||||||
if (!vvertexp->outBeginp()) { vvertexp->unlinkDelete(&m_graph); }
|
if (!vvertexp->outBeginp()) { vvertexp->unlinkDelete(&m_graph); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void assignActivity() {
|
void assignActivity() {
|
||||||
// Select activity numbers and put into each CFunc vertex
|
// Select activity numbers and put into each activity vertex
|
||||||
m_activityNumber = 1; // Note 0 indicates "slow"
|
m_activityNumber = 1; // Note 0 indicates "slow"
|
||||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||||
if (TraceActivityVertex* vvertexp = dynamic_cast<TraceActivityVertex*>(itp)) {
|
if (TraceActivityVertex* const vvertexp = dynamic_cast<TraceActivityVertex*>(itp)) {
|
||||||
if (!vvertexp->activityCodeValid()) {
|
if (!vvertexp->activityCodeValid()) {
|
||||||
if (vvertexp->slow()) {
|
if (vvertexp->slow()) {
|
||||||
// If all functions in the calls are slow, we'll share the same code.
|
// If all functions in the calls are slow, we'll share the same code.
|
||||||
|
|
@ -329,6 +334,8 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileLine* const flp = m_chgFuncp->fileline();
|
||||||
|
|
||||||
AstVar* newvarp;
|
AstVar* newvarp;
|
||||||
if (v3Global.opt.mtasks()) {
|
if (v3Global.opt.mtasks()) {
|
||||||
// Create a vector of bytes, not bits, for the tracing vector,
|
// Create a vector of bytes, not bits, for the tracing vector,
|
||||||
|
|
@ -338,32 +345,32 @@ private:
|
||||||
// chain of packed MTasks, but we haven't packed the MTasks yet.
|
// chain of packed MTasks, but we haven't packed the MTasks yet.
|
||||||
// If we support fully threaded tracing in the future, it would
|
// If we support fully threaded tracing in the future, it would
|
||||||
// make sense to improve this at that time.
|
// make sense to improve this at that time.
|
||||||
AstNodeDType* newScalarDtp
|
AstNodeDType* const newScalarDtp = new AstBasicDType(flp, VFlagLogicPacked(), 1);
|
||||||
= new AstBasicDType(m_chgFuncp->fileline(), VFlagLogicPacked(), 1);
|
|
||||||
v3Global.rootp()->typeTablep()->addTypesp(newScalarDtp);
|
v3Global.rootp()->typeTablep()->addTypesp(newScalarDtp);
|
||||||
AstNodeDType* newArrDtp = new AstUnpackArrayDType(
|
AstRange* const newArange
|
||||||
m_chgFuncp->fileline(), newScalarDtp,
|
= new AstRange(flp, VNumRange(m_activityNumber - 1, 0, false));
|
||||||
new AstRange(m_chgFuncp->fileline(), VNumRange(m_activityNumber - 1, 0, false)));
|
AstNodeDType* const newArrDtp = new AstUnpackArrayDType(flp, newScalarDtp, newArange);
|
||||||
v3Global.rootp()->typeTablep()->addTypesp(newArrDtp);
|
v3Global.rootp()->typeTablep()->addTypesp(newArrDtp);
|
||||||
newvarp = new AstVar(m_chgFuncp->fileline(), AstVarType::MODULETEMP,
|
newvarp = new AstVar(flp, AstVarType::MODULETEMP, "__Vm_traceActivity", newArrDtp);
|
||||||
"__Vm_traceActivity", newArrDtp);
|
|
||||||
} else {
|
} else {
|
||||||
// For tighter code; round to next word point.
|
// For tighter code; round to next word point.
|
||||||
int activityBits = VL_WORDS_I(m_activityNumber) * VL_EDATASIZE;
|
const int activityBits = VL_WORDS_I(m_activityNumber) * VL_EDATASIZE;
|
||||||
newvarp = new AstVar(m_chgFuncp->fileline(), AstVarType::MODULETEMP,
|
newvarp = new AstVar(flp, AstVarType::MODULETEMP, "__Vm_traceActivity",
|
||||||
"__Vm_traceActivity", VFlagBitPacked(), activityBits);
|
VFlagBitPacked(), activityBits);
|
||||||
}
|
}
|
||||||
m_topModp->addStmtp(newvarp);
|
m_topModp->addStmtp(newvarp);
|
||||||
AstVarScope* newvscp = new AstVarScope(newvarp->fileline(), m_highScopep, newvarp);
|
AstVarScope* const newvscp = new AstVarScope(flp, m_topScopep, newvarp);
|
||||||
m_highScopep->addVarp(newvscp);
|
m_topScopep->addVarp(newvscp);
|
||||||
m_activityVscp = newvscp;
|
m_activityVscp = newvscp;
|
||||||
|
|
||||||
// Insert activity setter
|
// Insert activity setter
|
||||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
|
||||||
if (TraceActivityVertex* vvertexp = dynamic_cast<TraceActivityVertex*>(itp)) {
|
itp = itp->verticesNextp()) {
|
||||||
|
if (const TraceActivityVertex* const vvertexp
|
||||||
|
= dynamic_cast<const TraceActivityVertex*>(itp)) {
|
||||||
if (!vvertexp->activityAlways()) {
|
if (!vvertexp->activityAlways()) {
|
||||||
FileLine* fl = vvertexp->insertp()->fileline();
|
FileLine* const fl = vvertexp->insertp()->fileline();
|
||||||
uint32_t acode = vvertexp->activityCode();
|
const uint32_t acode = vvertexp->activityCode();
|
||||||
vvertexp->insertp()->addNextHere(
|
vvertexp->insertp()->addNextHere(
|
||||||
new AstAssign(fl, selectActivity(fl, acode, true),
|
new AstAssign(fl, selectActivity(fl, acode, true),
|
||||||
new AstConst(fl, AstConst::LogicTrue())));
|
new AstConst(fl, AstConst::LogicTrue())));
|
||||||
|
|
@ -391,6 +398,7 @@ private:
|
||||||
UINFO(5, " Newfunc " << funcp << endl);
|
UINFO(5, " Newfunc " << funcp << endl);
|
||||||
return funcp;
|
return funcp;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstCFunc* newCFuncSub(AstCFunc* basep, AstNode* callfromp) {
|
AstCFunc* newCFuncSub(AstCFunc* basep, AstNode* callfromp) {
|
||||||
string name = basep->name() + "__" + cvtToStr(++m_funcNum);
|
string name = basep->name() + "__" + cvtToStr(++m_funcNum);
|
||||||
AstCFunc* funcp = NULL;
|
AstCFunc* funcp = NULL;
|
||||||
|
|
@ -412,6 +420,66 @@ private:
|
||||||
}
|
}
|
||||||
return funcp;
|
return funcp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t assignDeclCode(AstTraceDecl* nodep) {
|
||||||
|
if (!nodep->code()) {
|
||||||
|
nodep->code(m_code);
|
||||||
|
m_code += nodep->codeInc();
|
||||||
|
m_statUniqCodes += nodep->codeInc();
|
||||||
|
++m_statUniqSigs;
|
||||||
|
}
|
||||||
|
return nodep->code();
|
||||||
|
}
|
||||||
|
|
||||||
|
AstTraceInc* assignTraceCode(const TraceTraceVertex* vvertexp, bool needChg) {
|
||||||
|
// Assign trace code, add to tree, return node for change tree or null
|
||||||
|
|
||||||
|
AstTraceInc*const nodep = vvertexp->nodep();
|
||||||
|
|
||||||
|
// Find non-duplicated node;
|
||||||
|
const TraceTraceVertex*const dupvertexp = vvertexp->duplicatep();
|
||||||
|
if (dupvertexp) {
|
||||||
|
UINFO(9, " dupOf " << cvtToHex(dupvertexp) << " " << cvtToHex(dupvertexp->nodep())
|
||||||
|
<< " " << dupvertexp << endl);
|
||||||
|
UASSERT_OBJ(!dupvertexp->duplicatep(), dupvertexp->nodep(),
|
||||||
|
"Original node was marked as a duplicate");
|
||||||
|
UASSERT_OBJ(dupvertexp != vvertexp, dupvertexp->nodep(),
|
||||||
|
"Node was marked as duplicate of itself");
|
||||||
|
// It's an exact copy. We'll assign the code to the master on
|
||||||
|
// the first one we hit; the later ones will share the code.
|
||||||
|
const uint32_t code = assignDeclCode(dupvertexp->nodep()->declp());
|
||||||
|
nodep->declp()->code(code);
|
||||||
|
} else {
|
||||||
|
assignDeclCode(nodep->declp());
|
||||||
|
}
|
||||||
|
UINFO(8, " Created code=" << nodep->declp()->code() << " "
|
||||||
|
<< (dupvertexp ? "[PREASS]" : "") << " "
|
||||||
|
<< (needChg ? "[CHG]" : "") << " " << nodep << endl);
|
||||||
|
|
||||||
|
AstTraceInc* incAddp = NULL;
|
||||||
|
if (!dupvertexp) {
|
||||||
|
// Add to trace cfuncs
|
||||||
|
if (needChg) {
|
||||||
|
++m_statChgSigs;
|
||||||
|
incAddp = nodep->cloneTree(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_fullSubFuncp
|
||||||
|
|| (m_fullSubStmts && v3Global.opt.outputSplitCTrace()
|
||||||
|
&& m_fullSubStmts > v3Global.opt.outputSplitCTrace())) {
|
||||||
|
m_fullSubFuncp = newCFuncSub(m_fullFuncp, m_fullFuncp);
|
||||||
|
m_fullSubStmts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fullSubFuncp->addStmtsp(nodep);
|
||||||
|
m_fullSubStmts += EmitCBaseCounterVisitor(nodep).count();
|
||||||
|
} else {
|
||||||
|
// Duplicates don't need a TraceInc
|
||||||
|
pushDeletep(nodep);
|
||||||
|
}
|
||||||
|
return incAddp;
|
||||||
|
}
|
||||||
|
|
||||||
void addToChgSub(AstNode* underp, AstNode* stmtsp) {
|
void addToChgSub(AstNode* underp, AstNode* stmtsp) {
|
||||||
if (!m_chgSubFuncp || (m_chgSubParentp != underp)
|
if (!m_chgSubFuncp || (m_chgSubParentp != underp)
|
||||||
|| (m_chgSubStmts && v3Global.opt.outputSplitCTrace()
|
|| (m_chgSubStmts && v3Global.opt.outputSplitCTrace()
|
||||||
|
|
@ -428,22 +496,26 @@ private:
|
||||||
// Form a sorted list of the traces we are interested in
|
// Form a sorted list of the traces we are interested in
|
||||||
UINFO(9, "Making trees\n");
|
UINFO(9, "Making trees\n");
|
||||||
|
|
||||||
typedef std::set<uint32_t> ActCodeSet; // All activity numbers applying to a given trace
|
// All activity numbers applying to a given trace
|
||||||
typedef std::multimap<ActCodeSet, TraceTraceVertex*>
|
typedef std::set<uint32_t> ActCodeSet;
|
||||||
TraceVec; // For activity set, what traces apply
|
// For activity set, what traces apply
|
||||||
|
typedef std::multimap<ActCodeSet, const TraceTraceVertex*> TraceVec;
|
||||||
TraceVec traces;
|
TraceVec traces;
|
||||||
|
|
||||||
// Form sort structure
|
// Form sort structure
|
||||||
// If a trace doesn't have activity, it's constant, and we don't
|
// If a trace doesn't have activity, it's constant, and we don't
|
||||||
// need to track changes on it.
|
// need to track changes on it.
|
||||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
|
||||||
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
itp = itp->verticesNextp()) {
|
||||||
|
if (const TraceTraceVertex* const vvertexp
|
||||||
|
= dynamic_cast<const TraceTraceVertex*>(itp)) {
|
||||||
ActCodeSet actset;
|
ActCodeSet actset;
|
||||||
UINFO(9, " Add to sort: " << vvertexp << endl);
|
UINFO(9, " Add to sort: " << vvertexp << endl);
|
||||||
if (debug() >= 9) vvertexp->nodep()->dumpTree(cout, "- trnode: ");
|
if (debug() >= 9) vvertexp->nodep()->dumpTree(cout, "- trnode: ");
|
||||||
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
for (const V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;
|
||||||
TraceActivityVertex* cfvertexp
|
edgep = edgep->inNextp()) {
|
||||||
= dynamic_cast<TraceActivityVertex*>(edgep->fromp());
|
const TraceActivityVertex* const cfvertexp
|
||||||
|
= dynamic_cast<const TraceActivityVertex*>(edgep->fromp());
|
||||||
UASSERT_OBJ(cfvertexp, vvertexp->nodep(),
|
UASSERT_OBJ(cfvertexp, vvertexp->nodep(),
|
||||||
"Should have been function pointing to this trace");
|
"Should have been function pointing to this trace");
|
||||||
UINFO(9, " Activity: " << cfvertexp << endl);
|
UINFO(9, " Activity: " << cfvertexp << endl);
|
||||||
|
|
@ -453,8 +525,7 @@ private:
|
||||||
actset.insert(TraceActivityVertex::ACTIVITY_ALWAYS);
|
actset.insert(TraceActivityVertex::ACTIVITY_ALWAYS);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
uint32_t acode = cfvertexp->activityCode();
|
actset.insert(cfvertexp->activityCode());
|
||||||
actset.insert(acode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If a trace doesn't have activity, it's constant, and we
|
// If a trace doesn't have activity, it's constant, and we
|
||||||
|
|
@ -475,19 +546,14 @@ private:
|
||||||
AstNode* ifnodep = NULL;
|
AstNode* ifnodep = NULL;
|
||||||
for (TraceVec::iterator it = traces.begin(); it != traces.end(); ++it) {
|
for (TraceVec::iterator it = traces.begin(); it != traces.end(); ++it) {
|
||||||
const ActCodeSet& actset = it->first;
|
const ActCodeSet& actset = it->first;
|
||||||
TraceTraceVertex* vvertexp = it->second;
|
const TraceTraceVertex* const vvertexp = it->second;
|
||||||
UINFO(9, " Done sort: " << vvertexp << endl);
|
UINFO(9, " Done sort: " << vvertexp << endl);
|
||||||
bool needChg = true;
|
// Activity needed; it's not a constant value or only set in initial block
|
||||||
if (actset.find(TraceActivityVertex::ACTIVITY_NEVER) != actset.end()) {
|
const bool needChg = actset.count(TraceActivityVertex::ACTIVITY_NEVER) == 0;
|
||||||
// No activity needed; it's a constant value or only set in initial block
|
AstTraceInc* const addp = assignTraceCode(vvertexp, needChg);
|
||||||
needChg = false;
|
|
||||||
}
|
|
||||||
AstNode* addp = assignTraceCode(vvertexp, vvertexp->nodep(), needChg);
|
|
||||||
if (addp) { // Else no activity or duplicate
|
if (addp) { // Else no activity or duplicate
|
||||||
if (actset.find(TraceActivityVertex::ACTIVITY_NEVER) != actset.end()) {
|
UASSERT_OBJ(needChg, addp, "needChg=0 and shouldn't need to add.");
|
||||||
vvertexp->nodep()->v3fatalSrc(
|
if (actset.count(TraceActivityVertex::ACTIVITY_ALWAYS) != 0) {
|
||||||
"If never, needChg=0 and shouldn't need to add.");
|
|
||||||
} else if (actset.find(TraceActivityVertex::ACTIVITY_ALWAYS) != actset.end()) {
|
|
||||||
// Must always set it; add to base of function
|
// Must always set it; add to base of function
|
||||||
addToChgSub(m_chgFuncp, addp);
|
addToChgSub(m_chgFuncp, addp);
|
||||||
} else if (lastactp && actset == *lastactp && ifnodep) {
|
} else if (lastactp && actset == *lastactp && ifnodep) {
|
||||||
|
|
@ -520,7 +586,7 @@ private:
|
||||||
// Set in initializer
|
// Set in initializer
|
||||||
|
|
||||||
// Clear activity after tracing completes
|
// Clear activity after tracing completes
|
||||||
FileLine* fl = m_chgFuncp->fileline();
|
FileLine*const fl = m_chgFuncp->fileline();
|
||||||
if (v3Global.opt.mtasks()) {
|
if (v3Global.opt.mtasks()) {
|
||||||
for (uint32_t i = 0; i < m_activityNumber; ++i) {
|
for (uint32_t i = 0; i < m_activityNumber; ++i) {
|
||||||
AstNode* clrp = new AstAssign(fl, selectActivity(fl, i, true),
|
AstNode* clrp = new AstAssign(fl, selectActivity(fl, i, true),
|
||||||
|
|
@ -537,67 +603,6 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t assignDeclCode(AstTraceDecl* nodep) {
|
|
||||||
if (!nodep->code()) {
|
|
||||||
nodep->code(m_code);
|
|
||||||
m_code += nodep->codeInc();
|
|
||||||
m_statUniqCodes += nodep->codeInc();
|
|
||||||
++m_statUniqSigs;
|
|
||||||
}
|
|
||||||
return nodep->code();
|
|
||||||
}
|
|
||||||
|
|
||||||
AstNode* assignTraceCode(TraceTraceVertex* vvertexp, AstTraceInc* nodep, bool needChg) {
|
|
||||||
// Assign trace code, add to tree, return node for change tree or null
|
|
||||||
// Look for identical copies
|
|
||||||
uint32_t codePreassigned = 0;
|
|
||||||
// if (debug() >= 9) nodep->dumpTree(cout, "- assnnode: ");
|
|
||||||
// Find non-duplicated node; note some nodep's maybe null, as they were deleted below
|
|
||||||
TraceTraceVertex* dupvertexp = vvertexp;
|
|
||||||
if (dupvertexp->duplicatep()) {
|
|
||||||
dupvertexp = dupvertexp->duplicatep();
|
|
||||||
UINFO(9, " dupOf " << cvtToHex(dupvertexp) << " " << cvtToHex(dupvertexp->nodep())
|
|
||||||
<< " " << dupvertexp << endl);
|
|
||||||
UASSERT_OBJ(!dupvertexp->duplicatep(), dupvertexp->nodep(),
|
|
||||||
"Original node was marked as a duplicate");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dupvertexp != vvertexp) {
|
|
||||||
// It's an exact copy. We'll assign the code to the master on
|
|
||||||
// the first one we hit; the later ones will share the code.
|
|
||||||
codePreassigned = assignDeclCode(dupvertexp->nodep()->declp());
|
|
||||||
nodep->declp()->code(codePreassigned);
|
|
||||||
} else {
|
|
||||||
assignDeclCode(nodep->declp());
|
|
||||||
}
|
|
||||||
UINFO(8, " Created code=" << nodep->declp()->code() << " "
|
|
||||||
<< (codePreassigned ? "[PREASS]" : "") << " "
|
|
||||||
<< (needChg ? "[CHG]" : "") << " " << nodep << endl);
|
|
||||||
|
|
||||||
AstNode* incAddp = NULL;
|
|
||||||
if (!codePreassigned) {
|
|
||||||
// Add to trace cfuncs
|
|
||||||
if (needChg) {
|
|
||||||
++m_statChgSigs;
|
|
||||||
incAddp = nodep->cloneTree(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_fullSubFuncp
|
|
||||||
|| (m_fullSubStmts && v3Global.opt.outputSplitCTrace()
|
|
||||||
&& m_fullSubStmts > v3Global.opt.outputSplitCTrace())) {
|
|
||||||
m_fullSubFuncp = newCFuncSub(m_fullFuncp, m_fullFuncp);
|
|
||||||
m_fullSubStmts = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_fullSubFuncp->addStmtsp(nodep);
|
|
||||||
m_fullSubStmts += EmitCBaseCounterVisitor(nodep).count();
|
|
||||||
} else {
|
|
||||||
// Duplicates don't need a TraceInc
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
||||||
}
|
|
||||||
return incAddp;
|
|
||||||
}
|
|
||||||
|
|
||||||
TraceCFuncVertex* getCFuncVertexp(AstCFunc* nodep) {
|
TraceCFuncVertex* getCFuncVertexp(AstCFunc* nodep) {
|
||||||
TraceCFuncVertex* vertexp
|
TraceCFuncVertex* vertexp
|
||||||
= dynamic_cast<TraceCFuncVertex*>(nodep->user1u().toGraphVertex());
|
= dynamic_cast<TraceCFuncVertex*>(nodep->user1u().toGraphVertex());
|
||||||
|
|
@ -623,9 +628,6 @@ private:
|
||||||
m_code = 1; // Multiple TopScopes will require fixing how code#s
|
m_code = 1; // Multiple TopScopes will require fixing how code#s
|
||||||
// are assigned as duplicate varscopes must result in the same tracing code#.
|
// are assigned as duplicate varscopes must result in the same tracing code#.
|
||||||
|
|
||||||
// Make a always vertex
|
|
||||||
m_alwaysVtxp = new TraceActivityVertex(&m_graph, TraceActivityVertex::ACTIVITY_ALWAYS);
|
|
||||||
|
|
||||||
// Add vertexes for all TRACES, and edges from VARs each trace looks at
|
// Add vertexes for all TRACES, and edges from VARs each trace looks at
|
||||||
m_finding = false;
|
m_finding = false;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
@ -643,8 +645,10 @@ private:
|
||||||
graphSimplify();
|
graphSimplify();
|
||||||
if (debug() >= 6) m_graph.dumpDotFilePrefixed("trace_opt");
|
if (debug() >= 6) m_graph.dumpDotFilePrefixed("trace_opt");
|
||||||
|
|
||||||
// Create new TRACEINCs
|
// Create the activity flags
|
||||||
assignActivity();
|
assignActivity();
|
||||||
|
|
||||||
|
//
|
||||||
putTracesIntoTree();
|
putTracesIntoTree();
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||||
|
|
@ -652,9 +656,9 @@ private:
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||||
AstScope* scopep = nodep->scopep();
|
AstScope* const scopep = nodep->scopep();
|
||||||
UASSERT_OBJ(scopep, nodep, "No scope found on top level");
|
UASSERT_OBJ(scopep, nodep, "No scope found on top level");
|
||||||
m_highScopep = scopep;
|
m_topScopep = scopep;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||||
|
|
@ -662,12 +666,13 @@ private:
|
||||||
if (!m_finding && !nodep->user2()) {
|
if (!m_finding && !nodep->user2()) {
|
||||||
// See if there are other calls in same statement list;
|
// See if there are other calls in same statement list;
|
||||||
// If so, all funcs might share the same activity code
|
// If so, all funcs might share the same activity code
|
||||||
TraceActivityVertex* activityVtxp = getActivityVertexp(nodep, nodep->funcp()->slow());
|
TraceActivityVertex* const activityVtxp
|
||||||
|
= getActivityVertexp(nodep, nodep->funcp()->slow());
|
||||||
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
|
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
|
||||||
if (AstCCall* ccallp = VN_CAST(nextp, CCall)) {
|
if (AstCCall* const ccallp = VN_CAST(nextp, CCall)) {
|
||||||
ccallp->user2(true); // Processed
|
ccallp->user2(true); // Processed
|
||||||
UINFO(8, " SubCCALL " << ccallp << endl);
|
UINFO(8, " SubCCALL " << ccallp << endl);
|
||||||
V3GraphVertex* ccallFuncVtxp = getCFuncVertexp(ccallp->funcp());
|
V3GraphVertex* const ccallFuncVtxp = getCFuncVertexp(ccallp->funcp());
|
||||||
activityVtxp->slow(ccallp->funcp()->slow());
|
activityVtxp->slow(ccallp->funcp()->slow());
|
||||||
new V3GraphEdge(&m_graph, activityVtxp, ccallFuncVtxp, 1);
|
new V3GraphEdge(&m_graph, activityVtxp, ccallFuncVtxp, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -677,22 +682,22 @@ private:
|
||||||
}
|
}
|
||||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||||
UINFO(8, " CFUNC " << nodep << endl);
|
UINFO(8, " CFUNC " << nodep << endl);
|
||||||
if (nodep->funcType() == AstCFuncType::TRACE_INIT) {
|
if (nodep->funcType() == AstCFuncType::TRACE_FULL) {
|
||||||
m_initFuncp = nodep;
|
|
||||||
} else if (nodep->funcType() == AstCFuncType::TRACE_FULL) {
|
|
||||||
m_fullFuncp = nodep;
|
m_fullFuncp = nodep;
|
||||||
} else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE) {
|
} else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE) {
|
||||||
m_chgFuncp = nodep;
|
m_chgFuncp = nodep;
|
||||||
}
|
}
|
||||||
V3GraphVertex* funcVtxp = getCFuncVertexp(nodep);
|
V3GraphVertex* const funcVtxp = getCFuncVertexp(nodep);
|
||||||
if (!m_finding) { // If public, we need a unique activity code to allow for sets directly
|
if (!m_finding) { // If public, we need a unique activity code to allow for sets directly
|
||||||
// in this func
|
// in this func
|
||||||
if (nodep->funcPublic() || nodep->dpiExport() || nodep == v3Global.rootp()->evalp()) {
|
if (nodep->funcPublic() || nodep->dpiExport() || nodep == v3Global.rootp()->evalp()) {
|
||||||
// Need a non-null place to remember to later add a statement; make one
|
// Need a non-null place to remember to later add a statement; make one
|
||||||
if (!nodep->stmtsp())
|
if (!nodep->stmtsp()) {
|
||||||
nodep->addStmtsp(
|
nodep->addStmtsp(
|
||||||
new AstComment(nodep->fileline(), "Tracing activity check", true));
|
new AstComment(nodep->fileline(), "Tracing activity check", true));
|
||||||
V3GraphVertex* activityVtxp = getActivityVertexp(nodep->stmtsp(), nodep->slow());
|
}
|
||||||
|
V3GraphVertex* const activityVtxp
|
||||||
|
= getActivityVertexp(nodep->stmtsp(), nodep->slow());
|
||||||
new V3GraphEdge(&m_graph, activityVtxp, funcVtxp, 1);
|
new V3GraphEdge(&m_graph, activityVtxp, funcVtxp, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -705,7 +710,7 @@ private:
|
||||||
UASSERT_OBJ(!m_finding, nodep, "Traces should have been removed in prev step.");
|
UASSERT_OBJ(!m_finding, nodep, "Traces should have been removed in prev step.");
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
|
|
||||||
V3GraphVertex* vertexp = new TraceTraceVertex(&m_graph, nodep);
|
V3GraphVertex* const vertexp = new TraceTraceVertex(&m_graph, nodep);
|
||||||
nodep->user1p(vertexp);
|
nodep->user1p(vertexp);
|
||||||
|
|
||||||
UASSERT_OBJ(m_funcp && m_chgFuncp && m_fullFuncp, nodep, "Trace not under func");
|
UASSERT_OBJ(m_funcp && m_chgFuncp && m_fullFuncp, nodep, "Trace not under func");
|
||||||
|
|
@ -722,7 +727,7 @@ private:
|
||||||
varVtxp = new TraceVarVertex(&m_graph, nodep->varScopep());
|
varVtxp = new TraceVarVertex(&m_graph, nodep->varScopep());
|
||||||
nodep->varScopep()->user1p(varVtxp);
|
nodep->varScopep()->user1p(varVtxp);
|
||||||
}
|
}
|
||||||
V3GraphVertex* traceVtxp = m_tracep->user1u().toGraphVertex();
|
V3GraphVertex* const traceVtxp = m_tracep->user1u().toGraphVertex();
|
||||||
new V3GraphEdge(&m_graph, varVtxp, traceVtxp, 1);
|
new V3GraphEdge(&m_graph, varVtxp, traceVtxp, 1);
|
||||||
if (nodep->varp()->isPrimaryInish() // Always need to trace primary inputs
|
if (nodep->varp()->isPrimaryInish() // Always need to trace primary inputs
|
||||||
|| nodep->varp()->isSigPublic()) { // Or ones user can change
|
|| nodep->varp()->isSigPublic()) { // Or ones user can change
|
||||||
|
|
@ -730,8 +735,8 @@ private:
|
||||||
}
|
}
|
||||||
} else if (m_funcp && m_finding && nodep->lvalue()) {
|
} else if (m_funcp && m_finding && nodep->lvalue()) {
|
||||||
UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?");
|
UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?");
|
||||||
V3GraphVertex* funcVtxp = getCFuncVertexp(m_funcp);
|
V3GraphVertex* const funcVtxp = getCFuncVertexp(m_funcp);
|
||||||
V3GraphVertex* varVtxp = nodep->varScopep()->user1u().toGraphVertex();
|
V3GraphVertex* const varVtxp = nodep->varScopep()->user1u().toGraphVertex();
|
||||||
if (varVtxp) { // else we're not tracing this signal
|
if (varVtxp) { // else we're not tracing this signal
|
||||||
new V3GraphEdge(&m_graph, funcVtxp, varVtxp, 1);
|
new V3GraphEdge(&m_graph, funcVtxp, varVtxp, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -742,15 +747,14 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
explicit TraceVisitor(AstNetlist* nodep) {
|
explicit TraceVisitor(AstNetlist* nodep)
|
||||||
|
: m_alwaysVtxp(new TraceActivityVertex(&m_graph, TraceActivityVertex::ACTIVITY_ALWAYS)) {
|
||||||
m_funcp = NULL;
|
m_funcp = NULL;
|
||||||
m_tracep = NULL;
|
m_tracep = NULL;
|
||||||
m_topModp = NULL;
|
m_topModp = NULL;
|
||||||
m_highScopep = NULL;
|
m_topScopep = NULL;
|
||||||
m_finding = false;
|
m_finding = false;
|
||||||
m_activityVscp = NULL;
|
m_activityVscp = NULL;
|
||||||
m_alwaysVtxp = NULL;
|
|
||||||
m_initFuncp = NULL;
|
|
||||||
m_fullFuncp = NULL;
|
m_fullFuncp = NULL;
|
||||||
m_fullSubFuncp = NULL;
|
m_fullSubFuncp = NULL;
|
||||||
m_fullSubStmts = 0;
|
m_fullSubStmts = 0;
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@
|
||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// TraceDecl state, as a visitor of each AstNode
|
// TraceDecl state, as a visitor of each AstNode
|
||||||
|
|
||||||
|
|
@ -42,7 +40,6 @@ private:
|
||||||
AstCFunc* m_initFuncp; // Trace function being built
|
AstCFunc* m_initFuncp; // Trace function being built
|
||||||
AstCFunc* m_initSubFuncp; // Trace function being built (under m_init)
|
AstCFunc* m_initSubFuncp; // Trace function being built (under m_init)
|
||||||
int m_initSubStmts; // Number of statements in function
|
int m_initSubStmts; // Number of statements in function
|
||||||
AstCFunc* m_fullFuncp; // Trace function being built
|
|
||||||
AstCFunc* m_chgFuncp; // Trace function being built
|
AstCFunc* m_chgFuncp; // Trace function being built
|
||||||
int m_funcNum; // Function number being built
|
int m_funcNum; // Function number being built
|
||||||
AstVarScope* m_traVscp; // Signal being trace constructed
|
AstVarScope* m_traVscp; // Signal being trace constructed
|
||||||
|
|
@ -56,16 +53,16 @@ private:
|
||||||
// METHODS
|
// METHODS
|
||||||
VL_DEBUG_FUNC; // Declare debug()
|
VL_DEBUG_FUNC; // Declare debug()
|
||||||
|
|
||||||
const char* vscIgnoreTrace(AstVarScope* nodep) {
|
const char* vscIgnoreTrace(const AstVarScope* nodep) {
|
||||||
// Return true if this shouldn't be traced
|
// Return true if this shouldn't be traced
|
||||||
// See also similar rule in V3Coverage::varIgnoreToggle
|
// See also similar rule in V3Coverage::varIgnoreToggle
|
||||||
AstVar* varp = nodep->varp();
|
const AstVar* const varp = nodep->varp();
|
||||||
if (!varp->isTrace()) {
|
if (!varp->isTrace()) {
|
||||||
return "Verilator trace_off";
|
return "Verilator trace_off";
|
||||||
} else if (!nodep->isTrace()) {
|
} else if (!nodep->isTrace()) {
|
||||||
return "Verilator cell trace_off";
|
return "Verilator cell trace_off";
|
||||||
} else if (!v3Global.opt.traceUnderscore()) {
|
} else if (!v3Global.opt.traceUnderscore()) {
|
||||||
string prettyName = varp->prettyName();
|
const string prettyName = varp->prettyName();
|
||||||
if (!prettyName.empty() && prettyName[0] == '_') return "Leading underscore";
|
if (!prettyName.empty() && prettyName[0] == '_') return "Leading underscore";
|
||||||
if (prettyName.find("._") != string::npos) return "Inlined leading underscore";
|
if (prettyName.find("._") != string::npos) return "Inlined leading underscore";
|
||||||
}
|
}
|
||||||
|
|
@ -73,14 +70,22 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
AstCFunc* newCFunc(AstCFuncType type, const string& name, bool slow) {
|
AstCFunc* newCFunc(AstCFuncType type, const string& name, bool slow) {
|
||||||
AstCFunc* funcp = new AstCFunc(m_scopetopp->fileline(), name, m_scopetopp);
|
FileLine* const flp = m_scopetopp->fileline();
|
||||||
|
AstCFunc* const funcp = new AstCFunc(flp, name, m_scopetopp);
|
||||||
funcp->slow(slow);
|
funcp->slow(slow);
|
||||||
string argTypes(EmitCBaseVisitor::symClassVar() + ", " + v3Global.opt.traceClassBase()
|
string argTypes;
|
||||||
+ "* vcdp, uint32_t code");
|
argTypes += EmitCBaseVisitor::symClassVar();
|
||||||
|
argTypes += ", " + v3Global.opt.traceClassBase() + "* vcdp";
|
||||||
|
argTypes += ", uint32_t code";
|
||||||
if (m_interface) argTypes += ", const char* scopep";
|
if (m_interface) argTypes += ", const char* scopep";
|
||||||
funcp->argTypes(argTypes);
|
funcp->argTypes(argTypes);
|
||||||
funcp->funcType(type);
|
funcp->funcType(type);
|
||||||
funcp->symProlog(true);
|
funcp->symProlog(true);
|
||||||
|
if (type == AstCFuncType::TRACE_INIT) {
|
||||||
|
// Setup signal names
|
||||||
|
const string str = "vcdp->module(vlSymsp->name());\n";
|
||||||
|
funcp->addStmtsp(new AstCStmt(flp, str));
|
||||||
|
}
|
||||||
m_scopetopp->addActivep(funcp);
|
m_scopetopp->addActivep(funcp);
|
||||||
UINFO(5, " Newfunc " << funcp << endl);
|
UINFO(5, " Newfunc " << funcp << endl);
|
||||||
return funcp;
|
return funcp;
|
||||||
|
|
@ -92,14 +97,11 @@ private:
|
||||||
basep->addStmtsp(callp);
|
basep->addStmtsp(callp);
|
||||||
}
|
}
|
||||||
AstCFunc* newCFuncSub(AstCFunc* basep) {
|
AstCFunc* newCFuncSub(AstCFunc* basep) {
|
||||||
string name = basep->name() + "__" + cvtToStr(++m_funcNum);
|
UASSERT_OBJ(basep->funcType() == AstCFuncType::TRACE_INIT
|
||||||
AstCFunc* funcp = NULL;
|
|| basep->funcType() == AstCFuncType::TRACE_INIT_SUB,
|
||||||
if (basep->funcType() == AstCFuncType::TRACE_INIT
|
basep, "Strange base function type");
|
||||||
|| basep->funcType() == AstCFuncType::TRACE_INIT_SUB) {
|
const string name = basep->name() + "__" + cvtToStr(++m_funcNum);
|
||||||
funcp = newCFunc(AstCFuncType::TRACE_INIT_SUB, name, basep->slow());
|
AstCFunc* const funcp = newCFunc(AstCFuncType::TRACE_INIT_SUB, name, basep->slow());
|
||||||
} else {
|
|
||||||
basep->v3fatalSrc("Strange base function type");
|
|
||||||
}
|
|
||||||
if (!m_interface) callCFuncSub(basep, funcp, NULL);
|
if (!m_interface) callCFuncSub(basep, funcp, NULL);
|
||||||
return funcp;
|
return funcp;
|
||||||
}
|
}
|
||||||
|
|
@ -107,13 +109,12 @@ private:
|
||||||
int widthOverride) { // If !=0, is packed struct/array where basicp size
|
int widthOverride) { // If !=0, is packed struct/array where basicp size
|
||||||
// misreflects one element
|
// misreflects one element
|
||||||
VNumRange bitRange;
|
VNumRange bitRange;
|
||||||
AstBasicDType* bdtypep = m_traValuep->dtypep()->basicp();
|
|
||||||
if (widthOverride) {
|
if (widthOverride) {
|
||||||
bitRange = VNumRange(widthOverride - 1, 0, false);
|
bitRange = VNumRange(widthOverride - 1, 0, false);
|
||||||
} else if (bdtypep) {
|
} else if (const AstBasicDType* const bdtypep = m_traValuep->dtypep()->basicp()) {
|
||||||
bitRange = bdtypep->nrange();
|
bitRange = bdtypep->nrange();
|
||||||
}
|
}
|
||||||
AstTraceDecl* declp
|
AstTraceDecl* const declp
|
||||||
= new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traVscp->varp(),
|
= new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traVscp->varp(),
|
||||||
m_traValuep, bitRange, arrayRange, m_interface);
|
m_traValuep, bitRange, arrayRange, m_interface);
|
||||||
UINFO(9, "Decl " << declp << endl);
|
UINFO(9, "Decl " << declp << endl);
|
||||||
|
|
@ -142,7 +143,7 @@ private:
|
||||||
m_scopetopp = nodep->scopep();
|
m_scopetopp = nodep->scopep();
|
||||||
// Make containers for TRACEDECLs first
|
// Make containers for TRACEDECLs first
|
||||||
m_initFuncp = newCFunc(AstCFuncType::TRACE_INIT, "traceInitThis", true);
|
m_initFuncp = newCFunc(AstCFuncType::TRACE_INIT, "traceInitThis", true);
|
||||||
m_fullFuncp = newCFunc(AstCFuncType::TRACE_FULL, "traceFullThis", true);
|
/*fullFuncp*/ newCFunc(AstCFuncType::TRACE_FULL, "traceFullThis", true);
|
||||||
m_chgFuncp = newCFunc(AstCFuncType::TRACE_CHANGE, "traceChgThis", false);
|
m_chgFuncp = newCFunc(AstCFuncType::TRACE_CHANGE, "traceChgThis", false);
|
||||||
//
|
//
|
||||||
m_initSubFuncp = newCFuncSub(m_initFuncp);
|
m_initSubFuncp = newCFuncSub(m_initFuncp);
|
||||||
|
|
@ -150,28 +151,28 @@ private:
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||||
AstCell* cellp = VN_CAST(nodep->aboveCellp(), Cell);
|
AstCell* const cellp = VN_CAST(nodep->aboveCellp(), Cell);
|
||||||
if (cellp && VN_IS(cellp->modp(), Iface)) {
|
if (cellp && VN_IS(cellp->modp(), Iface)) {
|
||||||
AstCFunc* origSubFunc = m_initSubFuncp;
|
AstCFunc* const origSubFunc = m_initSubFuncp;
|
||||||
int origSubStmts = m_initSubStmts;
|
int origSubStmts = m_initSubStmts;
|
||||||
{
|
{
|
||||||
m_interface = true;
|
m_interface = true;
|
||||||
m_initSubFuncp = newCFuncSub(origSubFunc);
|
m_initSubFuncp = newCFuncSub(origSubFunc);
|
||||||
string scopeName = nodep->prettyName();
|
string scopeName = nodep->prettyName();
|
||||||
size_t lastDot = scopeName.find_last_of('.');
|
const size_t lastDot = scopeName.find_last_of('.');
|
||||||
UASSERT_OBJ(lastDot != string::npos, nodep,
|
UASSERT_OBJ(lastDot != string::npos, nodep,
|
||||||
"Expected an interface scope name to have at least one dot");
|
"Expected an interface scope name to have at least one dot");
|
||||||
scopeName = scopeName.substr(0, lastDot + 1);
|
scopeName = scopeName.substr(0, lastDot + 1);
|
||||||
size_t scopeLen = scopeName.length();
|
const size_t scopeLen = scopeName.length();
|
||||||
|
|
||||||
AstIntfRef* nextIrp = cellp->intfRefp();
|
AstIntfRef* nextIrp = cellp->intfRefp();
|
||||||
// While instead of for loop because interface references will
|
// While instead of for loop because interface references will
|
||||||
// be unlinked as we go
|
// be unlinked as we go
|
||||||
while (nextIrp) {
|
while (nextIrp) {
|
||||||
AstIntfRef* irp = nextIrp;
|
AstIntfRef* const irp = nextIrp;
|
||||||
nextIrp = VN_CAST(irp->nextp(), IntfRef);
|
nextIrp = VN_CAST(irp->nextp(), IntfRef);
|
||||||
|
|
||||||
string irpName = irp->prettyName();
|
const string irpName = irp->prettyName();
|
||||||
if (scopeLen > irpName.length()) continue;
|
if (scopeLen > irpName.length()) continue;
|
||||||
string intfScopeName = irpName.substr(0, scopeLen);
|
string intfScopeName = irpName.substr(0, scopeLen);
|
||||||
if (scopeName != intfScopeName) continue;
|
if (scopeName != intfScopeName) continue;
|
||||||
|
|
@ -196,8 +197,8 @@ private:
|
||||||
if ((!nodep->varp()->isTemp() || nodep->varp()->isTrace())
|
if ((!nodep->varp()->isTemp() || nodep->varp()->isTrace())
|
||||||
&& !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) {
|
&& !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) {
|
||||||
UINFO(5, " vsc " << nodep << endl);
|
UINFO(5, " vsc " << nodep << endl);
|
||||||
AstVar* varp = nodep->varp();
|
const AstVar* const varp = nodep->varp();
|
||||||
AstScope* scopep = nodep->scopep();
|
const AstScope* const scopep = nodep->scopep();
|
||||||
// Compute show name
|
// Compute show name
|
||||||
// This code assumes SPTRACEVCDC_VERSION >= 1330;
|
// This code assumes SPTRACEVCDC_VERSION >= 1330;
|
||||||
// it uses spaces to separate hierarchy components.
|
// it uses spaces to separate hierarchy components.
|
||||||
|
|
@ -205,14 +206,13 @@ private:
|
||||||
m_traShowname = AstNode::vcdName(varp->name());
|
m_traShowname = AstNode::vcdName(varp->name());
|
||||||
} else {
|
} else {
|
||||||
m_traShowname = AstNode::vcdName(scopep->name() + " " + varp->name());
|
m_traShowname = AstNode::vcdName(scopep->name() + " " + varp->name());
|
||||||
if (m_traShowname.substr(0, 4) == "TOP ") m_traShowname.replace(0, 4, "");
|
if (m_traShowname.substr(0, 4) == "TOP ") m_traShowname.erase(0, 4);
|
||||||
}
|
}
|
||||||
UASSERT_OBJ(m_initSubFuncp, nodep, "NULL");
|
UASSERT_OBJ(m_initSubFuncp, nodep, "NULL");
|
||||||
|
|
||||||
m_traVscp = nodep;
|
m_traVscp = nodep;
|
||||||
m_traValuep = NULL;
|
if (const char* const ignoreReasonp = vscIgnoreTrace(nodep)) {
|
||||||
if (vscIgnoreTrace(nodep)) {
|
addIgnore(ignoreReasonp);
|
||||||
addIgnore(vscIgnoreTrace(nodep));
|
|
||||||
} else {
|
} else {
|
||||||
++m_statSigs;
|
++m_statSigs;
|
||||||
if (nodep->valuep()) {
|
if (nodep->valuep()) {
|
||||||
|
|
@ -220,15 +220,12 @@ private:
|
||||||
} else {
|
} else {
|
||||||
m_traValuep = new AstVarRef(nodep->fileline(), nodep, false);
|
m_traValuep = new AstVarRef(nodep->fileline(), nodep, false);
|
||||||
}
|
}
|
||||||
{
|
// Recurse into data type of the signal; the visitors will call addTraceDecl()
|
||||||
// Recurse into data type of the signal; the visitors will call addTraceDecl()
|
iterate(varp->dtypep()->skipRefToEnump());
|
||||||
iterate(varp->dtypep()->skipRefToEnump());
|
|
||||||
}
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
if (m_traValuep) VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = NULL);
|
if (m_traValuep) VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = NULL);
|
||||||
}
|
}
|
||||||
m_traVscp = NULL;
|
m_traVscp = NULL;
|
||||||
m_traValuep = NULL;
|
|
||||||
m_traShowname = "";
|
m_traShowname = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -257,10 +254,10 @@ private:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Unroll now, as have no other method to get right signal names
|
// Unroll now, as have no other method to get right signal names
|
||||||
AstNodeDType* subtypep = nodep->subDTypep()->skipRefToEnump();
|
AstNodeDType*const subtypep = nodep->subDTypep()->skipRefToEnump();
|
||||||
for (int i = nodep->lsb(); i <= nodep->msb(); ++i) {
|
for (int i = nodep->lsb(); i <= nodep->msb(); ++i) {
|
||||||
string oldShowname = m_traShowname;
|
const string oldShowname = m_traShowname;
|
||||||
AstNode* oldValuep = m_traValuep;
|
AstNode*const oldValuep = m_traValuep;
|
||||||
{
|
{
|
||||||
m_traShowname += string("(") + cvtToStr(i) + string(")");
|
m_traShowname += string("(") + cvtToStr(i) + string(")");
|
||||||
m_traValuep = new AstArraySel(
|
m_traValuep = new AstArraySel(
|
||||||
|
|
@ -284,10 +281,10 @@ private:
|
||||||
// a much faster way to trace
|
// a much faster way to trace
|
||||||
addTraceDecl(VNumRange(), nodep->width());
|
addTraceDecl(VNumRange(), nodep->width());
|
||||||
} else {
|
} else {
|
||||||
AstNodeDType* subtypep = nodep->subDTypep()->skipRefToEnump();
|
AstNodeDType*const subtypep = nodep->subDTypep()->skipRefToEnump();
|
||||||
for (int i = nodep->lsb(); i <= nodep->msb(); ++i) {
|
for (int i = nodep->lsb(); i <= nodep->msb(); ++i) {
|
||||||
string oldShowname = m_traShowname;
|
const string oldShowname = m_traShowname;
|
||||||
AstNode* oldValuep = m_traValuep;
|
AstNode* const oldValuep = m_traValuep;
|
||||||
{
|
{
|
||||||
m_traShowname += string("(") + cvtToStr(i) + string(")");
|
m_traShowname += string("(") + cvtToStr(i) + string(")");
|
||||||
m_traValuep = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
|
m_traValuep = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
|
||||||
|
|
@ -310,31 +307,29 @@ private:
|
||||||
// This may not be the nicest for user presentation, but is
|
// This may not be the nicest for user presentation, but is
|
||||||
// a much faster way to trace
|
// a much faster way to trace
|
||||||
addTraceDecl(VNumRange(), nodep->width());
|
addTraceDecl(VNumRange(), nodep->width());
|
||||||
|
} else if (!nodep->packed()) {
|
||||||
|
addIgnore("Unsupported: Unpacked struct/union");
|
||||||
} else {
|
} else {
|
||||||
if (!nodep->packed()) {
|
for (const AstMemberDType* itemp = nodep->membersp(); itemp;
|
||||||
addIgnore("Unsupported: Unpacked struct/union");
|
itemp = VN_CAST_CONST(itemp->nextp(), MemberDType)) {
|
||||||
} else {
|
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump();
|
||||||
for (AstMemberDType* itemp = nodep->membersp(); itemp;
|
const string oldShowname = m_traShowname;
|
||||||
itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
AstNode* const oldValuep = m_traValuep;
|
||||||
AstNodeDType* subtypep = itemp->subDTypep()->skipRefToEnump();
|
{
|
||||||
string oldShowname = m_traShowname;
|
m_traShowname += string(" ") + itemp->prettyName();
|
||||||
AstNode* oldValuep = m_traValuep;
|
if (VN_IS(nodep, StructDType)) {
|
||||||
{
|
m_traValuep
|
||||||
m_traShowname += string(" ") + itemp->prettyName();
|
= new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
|
||||||
if (VN_IS(nodep, StructDType)) {
|
itemp->lsb(), subtypep->width());
|
||||||
m_traValuep
|
m_traValuep->dtypep(subtypep);
|
||||||
= new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
|
iterate(subtypep);
|
||||||
itemp->lsb(), subtypep->width());
|
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = NULL);
|
||||||
m_traValuep->dtypep(subtypep);
|
} else { // Else union, replicate fields
|
||||||
iterate(subtypep);
|
iterate(subtypep);
|
||||||
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = NULL);
|
|
||||||
} else { // Else union, replicate fields
|
|
||||||
iterate(subtypep);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_traShowname = oldShowname;
|
|
||||||
m_traValuep = oldValuep;
|
|
||||||
}
|
}
|
||||||
|
m_traShowname = oldShowname;
|
||||||
|
m_traValuep = oldValuep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +360,6 @@ public:
|
||||||
m_initFuncp = NULL;
|
m_initFuncp = NULL;
|
||||||
m_initSubFuncp = NULL;
|
m_initSubFuncp = NULL;
|
||||||
m_initSubStmts = 0;
|
m_initSubStmts = 0;
|
||||||
m_fullFuncp = NULL;
|
|
||||||
m_chgFuncp = NULL;
|
m_chgFuncp = NULL;
|
||||||
m_funcNum = 0;
|
m_funcNum = 0;
|
||||||
m_traVscp = NULL;
|
m_traVscp = NULL;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue