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:
Geza Lore 2020-05-09 11:38:32 +01:00
parent 85de3048a5
commit 12b95f6b93
4 changed files with 225 additions and 238 deletions

View File

@ -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)

View File

@ -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");

View File

@ -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;

View File

@ -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;