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}
// Children: none
private:
string m_showname; // Name of variable
uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines
VNumRange m_bitRange; // Property of var the trace details
VNumRange m_arrayRange; // Property of var the trace details
uint32_t m_codeInc; // Code increment
AstVarType m_varType; // Type of variable (for localparam vs. param)
AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
VDirection m_declDirection; // Declared direction input/output etc
bool m_isScoped; // Uses run-time scope (for interfaces)
const string m_showname; // Name of variable
const VNumRange m_bitRange; // Property of var the trace details
const VNumRange m_arrayRange; // Property of var the trace details
const uint32_t m_codeInc; // Code increment
const AstVarType m_varType; // Type of variable (for localparam vs. param)
const AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
const VDirection m_declDirection; // Declared direction input/output etc
const bool m_isScoped; // Uses run-time scope (for interfaces)
public:
AstTraceDecl(FileLine* fl, const string& showname,
AstVar* varp, // For input/output state etc
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange,
bool isScoped)
: ASTGEN_SUPER(fl)
, m_code(0)
, m_showname(showname)
, m_bitRange(bitRange)
, 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) {
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...
ASTNODE_NODE_FUNCS(TraceDecl)

View File

@ -3708,17 +3708,6 @@ class EmitCTrace : EmitCStmts {
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()) {
string section;
putsDecoration("// Variables\n");

View File

@ -52,7 +52,6 @@
#include "V3Hashed.h"
#include "V3Stats.h"
#include <cstdarg>
#include <map>
#include <set>
@ -183,10 +182,9 @@ private:
// STATE
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
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_fullSubFuncp; // Trace function we add statements to (under full)
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_code; // Trace ident code# being assigned
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?
int m_funcNum; // Function number being built
@ -214,9 +212,11 @@ private:
// Note uses user4
V3Hashed hashed; // Duplicate code detection
// Hash all of the values the traceIncs need
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
AstTraceInc* nodep = vvertexp->nodep();
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
itp = itp->verticesNextp()) {
if (const TraceTraceVertex* const vvertexp
= dynamic_cast<const TraceTraceVertex*>(itp)) {
const AstTraceInc* const nodep = vvertexp->nodep();
if (nodep->valuep()) {
UASSERT_OBJ(nodep->valuep()->backp() == nodep, nodep,
"Trace duplicate back needs consistency,"
@ -234,15 +234,15 @@ private:
}
// Find if there are any duplicates
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
AstTraceInc* nodep = vvertexp->nodep();
if (TraceTraceVertex* const vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
AstTraceInc* const nodep = vvertexp->nodep();
if (nodep->valuep() && !vvertexp->duplicatep()) {
V3Hashed::iterator dupit = hashed.findDuplicate(nodep->valuep());
if (dupit != hashed.end()) {
AstTraceInc* dupincp
= VN_CAST(hashed.iteratorNodep(dupit)->backp(), TraceInc);
const AstTraceInc* const dupincp
= VN_CAST_CONST(hashed.iteratorNodep(dupit)->backp(), TraceInc);
UASSERT_OBJ(dupincp, nodep, "Trace duplicate of wrong type");
TraceTraceVertex* dupvertexp
TraceTraceVertex* const dupvertexp
= dynamic_cast<TraceTraceVertex*>(dupincp->user1u().toGraphVertex());
UINFO(8, " Orig " << nodep << endl);
UINFO(8, " dup " << dupincp << endl);
@ -260,7 +260,7 @@ private:
// Remove all variable nodes
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
nextp = itp->verticesNextp();
if (TraceVarVertex* vvertexp = dynamic_cast<TraceVarVertex*>(itp)) {
if (TraceVarVertex* const vvertexp = dynamic_cast<TraceVarVertex*>(itp)) {
vvertexp->rerouteEdges(&m_graph);
vvertexp->unlinkDelete(&m_graph);
}
@ -271,7 +271,7 @@ private:
// Remove all Cfunc nodes
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
nextp = itp->verticesNextp();
if (TraceCFuncVertex* vvertexp = dynamic_cast<TraceCFuncVertex*>(itp)) {
if (TraceCFuncVertex* const vvertexp = dynamic_cast<TraceCFuncVertex*>(itp)) {
vvertexp->rerouteEdges(&m_graph);
vvertexp->unlinkDelete(&m_graph);
}
@ -281,12 +281,16 @@ private:
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
// If there are any edges from a always, keep only the always
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
V3GraphEdge* alwaysEdgep = NULL;
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
TraceActivityVertex* actVtxp
= dynamic_cast<TraceActivityVertex*>(edgep->fromp());
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
itp = itp->verticesNextp()) {
if (const TraceTraceVertex* const vvertexp
= dynamic_cast<const TraceTraceVertex*>(itp)) {
// Search for the incoming always edge
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(),
"Tracing a node with FROM non activity");
if (actVtxp->activityAlways()) {
@ -294,6 +298,7 @@ private:
break;
}
}
// If always edge exists, remove all other edges
if (alwaysEdgep) {
for (V3GraphEdge *nextp, *edgep = vvertexp->inBeginp(); edgep; edgep = nextp) {
nextp = edgep->inNextp();
@ -306,17 +311,17 @@ private:
// Activity points with no outputs can be removed
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
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); }
}
}
}
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"
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->slow()) {
// 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;
if (v3Global.opt.mtasks()) {
// 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.
// If we support fully threaded tracing in the future, it would
// make sense to improve this at that time.
AstNodeDType* newScalarDtp
= new AstBasicDType(m_chgFuncp->fileline(), VFlagLogicPacked(), 1);
AstNodeDType* const newScalarDtp = new AstBasicDType(flp, VFlagLogicPacked(), 1);
v3Global.rootp()->typeTablep()->addTypesp(newScalarDtp);
AstNodeDType* newArrDtp = new AstUnpackArrayDType(
m_chgFuncp->fileline(), newScalarDtp,
new AstRange(m_chgFuncp->fileline(), VNumRange(m_activityNumber - 1, 0, false)));
AstRange* const newArange
= new AstRange(flp, VNumRange(m_activityNumber - 1, 0, false));
AstNodeDType* const newArrDtp = new AstUnpackArrayDType(flp, newScalarDtp, newArange);
v3Global.rootp()->typeTablep()->addTypesp(newArrDtp);
newvarp = new AstVar(m_chgFuncp->fileline(), AstVarType::MODULETEMP,
"__Vm_traceActivity", newArrDtp);
newvarp = new AstVar(flp, AstVarType::MODULETEMP, "__Vm_traceActivity", newArrDtp);
} else {
// For tighter code; round to next word point.
int activityBits = VL_WORDS_I(m_activityNumber) * VL_EDATASIZE;
newvarp = new AstVar(m_chgFuncp->fileline(), AstVarType::MODULETEMP,
"__Vm_traceActivity", VFlagBitPacked(), activityBits);
const int activityBits = VL_WORDS_I(m_activityNumber) * VL_EDATASIZE;
newvarp = new AstVar(flp, AstVarType::MODULETEMP, "__Vm_traceActivity",
VFlagBitPacked(), activityBits);
}
m_topModp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(newvarp->fileline(), m_highScopep, newvarp);
m_highScopep->addVarp(newvscp);
AstVarScope* const newvscp = new AstVarScope(flp, m_topScopep, newvarp);
m_topScopep->addVarp(newvscp);
m_activityVscp = newvscp;
// Insert activity setter
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (TraceActivityVertex* vvertexp = dynamic_cast<TraceActivityVertex*>(itp)) {
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
itp = itp->verticesNextp()) {
if (const TraceActivityVertex* const vvertexp
= dynamic_cast<const TraceActivityVertex*>(itp)) {
if (!vvertexp->activityAlways()) {
FileLine* fl = vvertexp->insertp()->fileline();
uint32_t acode = vvertexp->activityCode();
FileLine* const fl = vvertexp->insertp()->fileline();
const uint32_t acode = vvertexp->activityCode();
vvertexp->insertp()->addNextHere(
new AstAssign(fl, selectActivity(fl, acode, true),
new AstConst(fl, AstConst::LogicTrue())));
@ -391,6 +398,7 @@ private:
UINFO(5, " Newfunc " << funcp << endl);
return funcp;
}
AstCFunc* newCFuncSub(AstCFunc* basep, AstNode* callfromp) {
string name = basep->name() + "__" + cvtToStr(++m_funcNum);
AstCFunc* funcp = NULL;
@ -412,6 +420,66 @@ private:
}
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) {
if (!m_chgSubFuncp || (m_chgSubParentp != underp)
|| (m_chgSubStmts && v3Global.opt.outputSplitCTrace()
@ -428,22 +496,26 @@ private:
// Form a sorted list of the traces we are interested in
UINFO(9, "Making trees\n");
typedef std::set<uint32_t> ActCodeSet; // All activity numbers applying to a given trace
typedef std::multimap<ActCodeSet, TraceTraceVertex*>
TraceVec; // For activity set, what traces apply
// All activity numbers applying to a given trace
typedef std::set<uint32_t> ActCodeSet;
// For activity set, what traces apply
typedef std::multimap<ActCodeSet, const TraceTraceVertex*> TraceVec;
TraceVec traces;
// Form sort structure
// If a trace doesn't have activity, it's constant, and we don't
// need to track changes on it.
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
itp = itp->verticesNextp()) {
if (const TraceTraceVertex* const vvertexp
= dynamic_cast<const TraceTraceVertex*>(itp)) {
ActCodeSet actset;
UINFO(9, " Add to sort: " << vvertexp << endl);
if (debug() >= 9) vvertexp->nodep()->dumpTree(cout, "- trnode: ");
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
TraceActivityVertex* cfvertexp
= dynamic_cast<TraceActivityVertex*>(edgep->fromp());
for (const V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;
edgep = edgep->inNextp()) {
const TraceActivityVertex* const cfvertexp
= dynamic_cast<const TraceActivityVertex*>(edgep->fromp());
UASSERT_OBJ(cfvertexp, vvertexp->nodep(),
"Should have been function pointing to this trace");
UINFO(9, " Activity: " << cfvertexp << endl);
@ -453,8 +525,7 @@ private:
actset.insert(TraceActivityVertex::ACTIVITY_ALWAYS);
break;
} else {
uint32_t acode = cfvertexp->activityCode();
actset.insert(acode);
actset.insert(cfvertexp->activityCode());
}
}
// If a trace doesn't have activity, it's constant, and we
@ -475,19 +546,14 @@ private:
AstNode* ifnodep = NULL;
for (TraceVec::iterator it = traces.begin(); it != traces.end(); ++it) {
const ActCodeSet& actset = it->first;
TraceTraceVertex* vvertexp = it->second;
const TraceTraceVertex* const vvertexp = it->second;
UINFO(9, " Done sort: " << vvertexp << endl);
bool needChg = true;
if (actset.find(TraceActivityVertex::ACTIVITY_NEVER) != actset.end()) {
// No activity needed; it's a constant value or only set in initial block
needChg = false;
}
AstNode* addp = assignTraceCode(vvertexp, vvertexp->nodep(), needChg);
// Activity needed; it's not a constant value or only set in initial block
const bool needChg = actset.count(TraceActivityVertex::ACTIVITY_NEVER) == 0;
AstTraceInc* const addp = assignTraceCode(vvertexp, needChg);
if (addp) { // Else no activity or duplicate
if (actset.find(TraceActivityVertex::ACTIVITY_NEVER) != actset.end()) {
vvertexp->nodep()->v3fatalSrc(
"If never, needChg=0 and shouldn't need to add.");
} else if (actset.find(TraceActivityVertex::ACTIVITY_ALWAYS) != actset.end()) {
UASSERT_OBJ(needChg, addp, "needChg=0 and shouldn't need to add.");
if (actset.count(TraceActivityVertex::ACTIVITY_ALWAYS) != 0) {
// Must always set it; add to base of function
addToChgSub(m_chgFuncp, addp);
} else if (lastactp && actset == *lastactp && ifnodep) {
@ -520,7 +586,7 @@ private:
// Set in initializer
// Clear activity after tracing completes
FileLine* fl = m_chgFuncp->fileline();
FileLine*const fl = m_chgFuncp->fileline();
if (v3Global.opt.mtasks()) {
for (uint32_t i = 0; i < m_activityNumber; ++i) {
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* vertexp
= dynamic_cast<TraceCFuncVertex*>(nodep->user1u().toGraphVertex());
@ -623,9 +628,6 @@ private:
m_code = 1; // Multiple TopScopes will require fixing how code#s
// 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
m_finding = false;
iterateChildren(nodep);
@ -643,8 +645,10 @@ private:
graphSimplify();
if (debug() >= 6) m_graph.dumpDotFilePrefixed("trace_opt");
// Create new TRACEINCs
// Create the activity flags
assignActivity();
//
putTracesIntoTree();
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
@ -652,9 +656,9 @@ private:
iterateChildren(nodep);
}
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");
m_highScopep = scopep;
m_topScopep = scopep;
iterateChildren(nodep);
}
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
@ -662,12 +666,13 @@ private:
if (!m_finding && !nodep->user2()) {
// See if there are other calls in same statement list;
// 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()) {
if (AstCCall* ccallp = VN_CAST(nextp, CCall)) {
if (AstCCall* const ccallp = VN_CAST(nextp, CCall)) {
ccallp->user2(true); // Processed
UINFO(8, " SubCCALL " << ccallp << endl);
V3GraphVertex* ccallFuncVtxp = getCFuncVertexp(ccallp->funcp());
V3GraphVertex* const ccallFuncVtxp = getCFuncVertexp(ccallp->funcp());
activityVtxp->slow(ccallp->funcp()->slow());
new V3GraphEdge(&m_graph, activityVtxp, ccallFuncVtxp, 1);
}
@ -677,22 +682,22 @@ private:
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
UINFO(8, " CFUNC " << nodep << endl);
if (nodep->funcType() == AstCFuncType::TRACE_INIT) {
m_initFuncp = nodep;
} else if (nodep->funcType() == AstCFuncType::TRACE_FULL) {
if (nodep->funcType() == AstCFuncType::TRACE_FULL) {
m_fullFuncp = nodep;
} else if (nodep->funcType() == AstCFuncType::TRACE_CHANGE) {
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
// in this func
if (nodep->funcPublic() || nodep->dpiExport() || nodep == v3Global.rootp()->evalp()) {
// Need a non-null place to remember to later add a statement; make one
if (!nodep->stmtsp())
if (!nodep->stmtsp()) {
nodep->addStmtsp(
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);
}
}
@ -705,7 +710,7 @@ private:
UASSERT_OBJ(!m_finding, nodep, "Traces should have been removed in prev step.");
nodep->unlinkFrBack();
V3GraphVertex* vertexp = new TraceTraceVertex(&m_graph, nodep);
V3GraphVertex* const vertexp = new TraceTraceVertex(&m_graph, nodep);
nodep->user1p(vertexp);
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());
nodep->varScopep()->user1p(varVtxp);
}
V3GraphVertex* traceVtxp = m_tracep->user1u().toGraphVertex();
V3GraphVertex* const traceVtxp = m_tracep->user1u().toGraphVertex();
new V3GraphEdge(&m_graph, varVtxp, traceVtxp, 1);
if (nodep->varp()->isPrimaryInish() // Always need to trace primary inputs
|| nodep->varp()->isSigPublic()) { // Or ones user can change
@ -730,8 +735,8 @@ private:
}
} else if (m_funcp && m_finding && nodep->lvalue()) {
UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?");
V3GraphVertex* funcVtxp = getCFuncVertexp(m_funcp);
V3GraphVertex* varVtxp = nodep->varScopep()->user1u().toGraphVertex();
V3GraphVertex* const funcVtxp = getCFuncVertexp(m_funcp);
V3GraphVertex* const varVtxp = nodep->varScopep()->user1u().toGraphVertex();
if (varVtxp) { // else we're not tracing this signal
new V3GraphEdge(&m_graph, funcVtxp, varVtxp, 1);
}
@ -742,15 +747,14 @@ private:
public:
// CONSTRUCTORS
explicit TraceVisitor(AstNetlist* nodep) {
explicit TraceVisitor(AstNetlist* nodep)
: m_alwaysVtxp(new TraceActivityVertex(&m_graph, TraceActivityVertex::ACTIVITY_ALWAYS)) {
m_funcp = NULL;
m_tracep = NULL;
m_topModp = NULL;
m_highScopep = NULL;
m_topScopep = NULL;
m_finding = false;
m_activityVscp = NULL;
m_alwaysVtxp = NULL;
m_initFuncp = NULL;
m_fullFuncp = NULL;
m_fullSubFuncp = NULL;
m_fullSubStmts = 0;

View File

@ -28,8 +28,6 @@
#include "V3EmitCBase.h"
#include "V3Stats.h"
#include <cstdarg>
//######################################################################
// TraceDecl state, as a visitor of each AstNode
@ -42,7 +40,6 @@ private:
AstCFunc* m_initFuncp; // Trace function being built
AstCFunc* m_initSubFuncp; // Trace function being built (under m_init)
int m_initSubStmts; // Number of statements in function
AstCFunc* m_fullFuncp; // Trace function being built
AstCFunc* m_chgFuncp; // Trace function being built
int m_funcNum; // Function number being built
AstVarScope* m_traVscp; // Signal being trace constructed
@ -56,16 +53,16 @@ private:
// METHODS
VL_DEBUG_FUNC; // Declare debug()
const char* vscIgnoreTrace(AstVarScope* nodep) {
const char* vscIgnoreTrace(const AstVarScope* nodep) {
// Return true if this shouldn't be traced
// See also similar rule in V3Coverage::varIgnoreToggle
AstVar* varp = nodep->varp();
const AstVar* const varp = nodep->varp();
if (!varp->isTrace()) {
return "Verilator trace_off";
} else if (!nodep->isTrace()) {
return "Verilator cell trace_off";
} else if (!v3Global.opt.traceUnderscore()) {
string prettyName = varp->prettyName();
const string prettyName = varp->prettyName();
if (!prettyName.empty() && prettyName[0] == '_') return "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* 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);
string argTypes(EmitCBaseVisitor::symClassVar() + ", " + v3Global.opt.traceClassBase()
+ "* vcdp, uint32_t code");
string argTypes;
argTypes += EmitCBaseVisitor::symClassVar();
argTypes += ", " + v3Global.opt.traceClassBase() + "* vcdp";
argTypes += ", uint32_t code";
if (m_interface) argTypes += ", const char* scopep";
funcp->argTypes(argTypes);
funcp->funcType(type);
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);
UINFO(5, " Newfunc " << funcp << endl);
return funcp;
@ -92,14 +97,11 @@ private:
basep->addStmtsp(callp);
}
AstCFunc* newCFuncSub(AstCFunc* basep) {
string name = basep->name() + "__" + cvtToStr(++m_funcNum);
AstCFunc* funcp = NULL;
if (basep->funcType() == AstCFuncType::TRACE_INIT
|| basep->funcType() == AstCFuncType::TRACE_INIT_SUB) {
funcp = newCFunc(AstCFuncType::TRACE_INIT_SUB, name, basep->slow());
} else {
basep->v3fatalSrc("Strange base function type");
}
UASSERT_OBJ(basep->funcType() == AstCFuncType::TRACE_INIT
|| basep->funcType() == AstCFuncType::TRACE_INIT_SUB,
basep, "Strange base function type");
const string name = basep->name() + "__" + cvtToStr(++m_funcNum);
AstCFunc* const funcp = newCFunc(AstCFuncType::TRACE_INIT_SUB, name, basep->slow());
if (!m_interface) callCFuncSub(basep, funcp, NULL);
return funcp;
}
@ -107,13 +109,12 @@ private:
int widthOverride) { // If !=0, is packed struct/array where basicp size
// misreflects one element
VNumRange bitRange;
AstBasicDType* bdtypep = m_traValuep->dtypep()->basicp();
if (widthOverride) {
bitRange = VNumRange(widthOverride - 1, 0, false);
} else if (bdtypep) {
} else if (const AstBasicDType* const bdtypep = m_traValuep->dtypep()->basicp()) {
bitRange = bdtypep->nrange();
}
AstTraceDecl* declp
AstTraceDecl* const declp
= new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traVscp->varp(),
m_traValuep, bitRange, arrayRange, m_interface);
UINFO(9, "Decl " << declp << endl);
@ -142,7 +143,7 @@ private:
m_scopetopp = nodep->scopep();
// Make containers for TRACEDECLs first
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_initSubFuncp = newCFuncSub(m_initFuncp);
@ -150,28 +151,28 @@ private:
iterateChildren(nodep);
}
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)) {
AstCFunc* origSubFunc = m_initSubFuncp;
AstCFunc* const origSubFunc = m_initSubFuncp;
int origSubStmts = m_initSubStmts;
{
m_interface = true;
m_initSubFuncp = newCFuncSub(origSubFunc);
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,
"Expected an interface scope name to have at least one dot");
scopeName = scopeName.substr(0, lastDot + 1);
size_t scopeLen = scopeName.length();
const size_t scopeLen = scopeName.length();
AstIntfRef* nextIrp = cellp->intfRefp();
// While instead of for loop because interface references will
// be unlinked as we go
while (nextIrp) {
AstIntfRef* irp = nextIrp;
AstIntfRef* const irp = nextIrp;
nextIrp = VN_CAST(irp->nextp(), IntfRef);
string irpName = irp->prettyName();
const string irpName = irp->prettyName();
if (scopeLen > irpName.length()) continue;
string intfScopeName = irpName.substr(0, scopeLen);
if (scopeName != intfScopeName) continue;
@ -196,8 +197,8 @@ private:
if ((!nodep->varp()->isTemp() || nodep->varp()->isTrace())
&& !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) {
UINFO(5, " vsc " << nodep << endl);
AstVar* varp = nodep->varp();
AstScope* scopep = nodep->scopep();
const AstVar* const varp = nodep->varp();
const AstScope* const scopep = nodep->scopep();
// Compute show name
// This code assumes SPTRACEVCDC_VERSION >= 1330;
// it uses spaces to separate hierarchy components.
@ -205,14 +206,13 @@ private:
m_traShowname = AstNode::vcdName(varp->name());
} else {
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");
m_traVscp = nodep;
m_traValuep = NULL;
if (vscIgnoreTrace(nodep)) {
addIgnore(vscIgnoreTrace(nodep));
if (const char* const ignoreReasonp = vscIgnoreTrace(nodep)) {
addIgnore(ignoreReasonp);
} else {
++m_statSigs;
if (nodep->valuep()) {
@ -220,15 +220,12 @@ private:
} else {
m_traValuep = new AstVarRef(nodep->fileline(), nodep, false);
}
{
// Recurse into data type of the signal; the visitors will call addTraceDecl()
iterate(varp->dtypep()->skipRefToEnump());
}
// Recurse into data type of the signal; the visitors will call addTraceDecl()
iterate(varp->dtypep()->skipRefToEnump());
// Cleanup
if (m_traValuep) VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = NULL);
}
m_traVscp = NULL;
m_traValuep = NULL;
m_traShowname = "";
}
}
@ -257,10 +254,10 @@ private:
}
} else {
// 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) {
string oldShowname = m_traShowname;
AstNode* oldValuep = m_traValuep;
const string oldShowname = m_traShowname;
AstNode*const oldValuep = m_traValuep;
{
m_traShowname += string("(") + cvtToStr(i) + string(")");
m_traValuep = new AstArraySel(
@ -284,10 +281,10 @@ private:
// a much faster way to trace
addTraceDecl(VNumRange(), nodep->width());
} else {
AstNodeDType* subtypep = nodep->subDTypep()->skipRefToEnump();
AstNodeDType*const subtypep = nodep->subDTypep()->skipRefToEnump();
for (int i = nodep->lsb(); i <= nodep->msb(); ++i) {
string oldShowname = m_traShowname;
AstNode* oldValuep = m_traValuep;
const string oldShowname = m_traShowname;
AstNode* const oldValuep = m_traValuep;
{
m_traShowname += string("(") + cvtToStr(i) + string(")");
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
// a much faster way to trace
addTraceDecl(VNumRange(), nodep->width());
} else if (!nodep->packed()) {
addIgnore("Unsupported: Unpacked struct/union");
} else {
if (!nodep->packed()) {
addIgnore("Unsupported: Unpacked struct/union");
} else {
for (AstMemberDType* itemp = nodep->membersp(); itemp;
itemp = VN_CAST(itemp->nextp(), MemberDType)) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefToEnump();
string oldShowname = m_traShowname;
AstNode* oldValuep = m_traValuep;
{
m_traShowname += string(" ") + itemp->prettyName();
if (VN_IS(nodep, StructDType)) {
m_traValuep
= new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
itemp->lsb(), subtypep->width());
m_traValuep->dtypep(subtypep);
iterate(subtypep);
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = NULL);
} else { // Else union, replicate fields
iterate(subtypep);
}
for (const AstMemberDType* itemp = nodep->membersp(); itemp;
itemp = VN_CAST_CONST(itemp->nextp(), MemberDType)) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump();
const string oldShowname = m_traShowname;
AstNode* const oldValuep = m_traValuep;
{
m_traShowname += string(" ") + itemp->prettyName();
if (VN_IS(nodep, StructDType)) {
m_traValuep
= new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
itemp->lsb(), subtypep->width());
m_traValuep->dtypep(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_initSubFuncp = NULL;
m_initSubStmts = 0;
m_fullFuncp = NULL;
m_chgFuncp = NULL;
m_funcNum = 0;
m_traVscp = NULL;