--cdc: Report in more typical source to dest order

This commit is contained in:
Wilson Snyder 2010-01-09 09:05:00 -05:00
parent 32c30c34e9
commit 6aec0ce702
5 changed files with 86 additions and 44 deletions

View File

@ -211,8 +211,17 @@ private:
UINFO(6,"New vertex "<<varscp<<endl); UINFO(6,"New vertex "<<varscp<<endl);
vertexp = new CdcVarVertex(&m_graph, m_scopep, varscp); vertexp = new CdcVarVertex(&m_graph, m_scopep, varscp);
varscp->user1p(vertexp); varscp->user1p(vertexp);
if (varscp->varp()->isIO() && varscp->scopep()->isTop()) {}
if (varscp->varp()->isUsedClock()) {} if (varscp->varp()->isUsedClock()) {}
if (varscp->varp()->isPrimaryIO()) {
// Create IO vertex - note it's relative to the pointed to var, not where we are now
// This allows reporting to easily print the input statement
CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
if (varscp->varp()->isInput()) {
new V3GraphEdge(&m_graph, ioVertexp, vertexp, 1);
} else {
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
}
}
} }
if (m_senNumber > 1) vertexp->cntAsyncRst(vertexp->cntAsyncRst()+1); if (m_senNumber > 1) vertexp->cntAsyncRst(vertexp->cntAsyncRst()+1);
return vertexp; return vertexp;
@ -231,9 +240,11 @@ private:
void clearNodeSafe(AstNode* nodep) { void clearNodeSafe(AstNode* nodep) {
// Need to not clear if warnings are off (rather than when report it) // Need to not clear if warnings are off (rather than when report it)
// as bypassing this warning may turn up another path that isn't warning off'ed. // as bypassing this warning may turn up another path that isn't warning off'ed.
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) { if (!m_domainp || m_domainp->hasCombo()) { // Source flop logic in a posedge block is OK for reset (not async though)
UINFO(9,"Clear safe "<<nodep<<endl); if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
m_logicVertexp->clearSafe(nodep); UINFO(9,"Clear safe "<<nodep<<endl);
m_logicVertexp->clearSafe(nodep);
}
} }
} }
@ -283,12 +294,14 @@ private:
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) { CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
// Return vertex of any dangerous stuff attached, or NULL if OK // Return vertex of any dangerous stuff attached, or NULL if OK
// If mark, also mark the output even if nothing dangerous below if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
vertexp->user(m_userGeneration);
CdcEitherVertex* mark_outp = NULL; CdcEitherVertex* mark_outp = NULL;
UINFO(9," Trace: "<<vertexp<<endl); UINFO(9," Trace: "<<vertexp<<endl);
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop // Clear out in prep for marking next path
vertexp->user(m_userGeneration); if (!mark) vertexp->asyncPath(false);
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) { if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Any logic considered bad, at the moment, anyhow // Any logic considered bad, at the moment, anyhow
@ -298,13 +311,20 @@ private:
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) { else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
if (mark) vvertexp->asyncPath(true); if (mark) vvertexp->asyncPath(true);
// If primary I/O, it's ok here back // If primary I/O, it's ok here back
if (vvertexp->varScp()->varp()->isInput()) return false; if (vvertexp->varScp()->varp()->isPrimaryIn()) {
// Show the source "input" statement if it exists
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
eFromVertexp->asyncPath(true);
}
return false;
}
// Also ok if from flop, but partially trace the flop so more obvious to users // Also ok if from flop, but partially trace the flop so more obvious to users
if (vvertexp->fromFlop()) { if (vvertexp->fromFlop()) {
//for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
// CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp(); CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
// eFromVertexp->asyncPath(true); eFromVertexp->asyncPath(true);
//} }
return false; return false;
} }
} }
@ -323,42 +343,49 @@ private:
AstNode* nodep = vertexp->varScp(); AstNode* nodep = vertexp->varScp();
*m_ofp<<"\n"; *m_ofp<<"\n";
*m_ofp<<"\n"; *m_ofp<<"\n";
AstNode* targetp = vertexp->nodep(); CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
if (V3GraphEdge* edgep = vertexp->outBeginp()) { if (V3GraphEdge* edgep = vertexp->outBeginp()) {
CdcEitherVertex* eToVertexp = (CdcEitherVertex*)edgep->top(); CdcEitherVertex* eToVertexp = (CdcEitherVertex*)edgep->top();
targetp = eToVertexp->nodep(); targetp = eToVertexp;
} }
warnAndFile(markp->nodep(),V3ErrorCode::CDCRSTLOGIC,"Logic in path that feeds async reset, via signal: "+nodep->prettyName()); warnAndFile(markp->nodep(),V3ErrorCode::CDCRSTLOGIC,"Logic in path that feeds async reset, via signal: "+nodep->prettyName());
*m_ofp<<"Fanout: "<<vertexp->cntAsyncRst()<<" Target: "<<targetp->fileline()<<endl; dumpAsyncRecurse(targetp, "", " ",0);
dumpAsyncRecurse(vertexp," +--", " | ");
} }
void dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& blank) { bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep, int level) {
// Return true if any dangerous stuff attached // level=0 is special, indicates to dump destination flop
// Return true if printed anything
// If mark, also mark the output even if nothing dangerous below // If mark, also mark the output even if nothing dangerous below
if (vertexp->user()>=m_userGeneration) return; // Processed - prevent loop if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
vertexp->user(m_userGeneration); vertexp->user(m_userGeneration);
if (!vertexp->asyncPath()) return; // Not part of path if (!vertexp->asyncPath() && level!=0) return false; // Not part of path
*m_ofp<<V3OutFile::indentSpaces(40)<<" "<<blank<<"\n"; // Other logic in the path
string cont = prefix+sep;
string nextsep = " ";
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level+1)) {
nextsep = " | ";
}
}
// Dump single variable/logic block // Dump single variable/logic block
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp) // See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
AstNode* nodep = vertexp->nodep(); AstNode* nodep = vertexp->nodep();
string front = pad(40,nodep->fileline()->ascii()+":"); string front = pad(40,nodep->fileline()->ascii()+":")+" "+prefix+" +- ";
front += " "+prefix+" "; if (nodep->castVarScope()) {
if (nodep->castVarScope()) *m_ofp<<front<<"Variable: "<<nodep->prettyName()<<endl; *m_ofp<<front<<"Variable: "<<nodep->prettyName()<<endl;
}
else { else {
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix+" ", true); V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix+" +- ", vertexp->srcDomainp(), true);
if (debug()) { if (debug()) {
CdcDumpVisitor visitor (nodep, m_ofp, front+"DBG: "); CdcDumpVisitor visitor (nodep, m_ofp, front+"DBG: ");
} }
} }
// Now do the other logic in the path nextsep = " | ";
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { if (level) *m_ofp<<V3OutFile::indentSpaces(40)<<" "<<prefix<<nextsep<<"\n";
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp(); return true;
dumpAsyncRecurse(eFromVertexp, blank+" +--", blank+" | ");
}
} }
//---------------------------------------- //----------------------------------------
@ -607,16 +634,16 @@ public:
if (m_ofp->fail()) v3fatalSrc("Can't write "<<filename); if (m_ofp->fail()) v3fatalSrc("Can't write "<<filename);
m_ofFilename = filename; m_ofFilename = filename;
*m_ofp<<"CDC Report for "<<v3Global.opt.prefix()<<endl; *m_ofp<<"CDC Report for "<<v3Global.opt.prefix()<<endl;
*m_ofp<<"Each dump below traces a variable from a flop back through logic.\n"; *m_ofp<<"Each dump below traces logic from inputs/source flops to destination flop(s).\n";
*m_ofp<<"First the variable is listed, then the logic that creates it, then all variables\n"; *m_ofp<<"First source logic is listed, then a variable that logic generates,\n";
*m_ofp<<"feeding that logic, recursively backwards to the sourcing flop(s).\n"; *m_ofp<<"repeating recursively forwards to the destination flop(s).\n";
*m_ofp<<"%% Indicates nodes considered potentially unsafe.\n"; *m_ofp<<"%% Indicates the operator considered potentially unsafe.\n";
nodep->accept(*this); nodep->accept(*this);
analyze(); analyze();
//edgeReport(); // Not useful at the moment //edgeReport(); // Not useful at the moment
if (0) { *m_ofp<<"\nDBG-test-dumper\n"; V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ",true); *m_ofp<<endl; } if (0) { *m_ofp<<"\nDBG-test-dumper\n"; V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ",NULL,true); *m_ofp<<endl; }
} }
virtual ~CdcVisitor() { virtual ~CdcVisitor() {
if (m_ofp) { delete m_ofp; m_ofp = NULL; } if (m_ofp) { delete m_ofp; m_ofp = NULL; }

View File

@ -312,7 +312,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
} }
virtual void visit(AstUCFunc* nodep, AstNUser*) { virtual void visit(AstUCFunc* nodep, AstNUser*) {
putfs(nodep,"$c("); putfs(nodep,"$c(");
nodep->bodysp()->iterateAndNext(*this); puts(")\n"); nodep->bodysp()->iterateAndNext(*this);
puts(")");
} }
// Operators // Operators
@ -488,9 +489,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
} }
public: public:
EmitVBaseVisitor() { EmitVBaseVisitor(AstSenTree* domainp=NULL) { // Domain for printing one a ALWAYS under a ACTIVE
m_suppressSemi = false; m_suppressSemi = false;
m_sensesp = NULL; m_sensesp = domainp;
} }
virtual ~EmitVBaseVisitor() {} virtual ~EmitVBaseVisitor() {}
}; };
@ -597,8 +598,9 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
} }
public: public:
EmitVPrefixedVisitor(AstNode* nodep, ostream& os, const string& prefix, bool user3mark) EmitVPrefixedVisitor(AstNode* nodep, ostream& os, const string& prefix,
: m_formatter(os, prefix), m_user3mark(user3mark) { AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor(domainp), m_formatter(os, prefix), m_user3mark(user3mark) {
if (user3mark) { AstUser3InUse::check(); } if (user3mark) { AstUser3InUse::check(); }
nodep->accept(*this); nodep->accept(*this);
} }
@ -631,6 +633,7 @@ void V3EmitV::verilogForTree(AstNode* nodep, ostream& os) {
EmitVStreamVisitor(nodep, os); EmitVStreamVisitor(nodep, os);
} }
void V3EmitV::verilogPrefixedTree(AstNode* nodep, ostream& os, const string& prefix, bool user3mark) { void V3EmitV::verilogPrefixedTree(AstNode* nodep, ostream& os, const string& prefix,
EmitVPrefixedVisitor(nodep, os, prefix, user3mark); AstSenTree* domainp, bool user3mark) {
EmitVPrefixedVisitor(nodep, os, prefix, domainp, user3mark);
} }

View File

@ -33,7 +33,8 @@ class V3EmitV {
public: public:
static void emitv(); static void emitv();
static void verilogForTree(AstNode* nodep, ostream& os=cout); static void verilogForTree(AstNode* nodep, ostream& os=cout);
static void verilogPrefixedTree(AstNode* nodep, ostream& os, const string& prefix, bool user3percent); static void verilogPrefixedTree(AstNode* nodep, ostream& os, const string& prefix,
AstSenTree* domainp, bool user3percent);
}; };
#endif // Guard #endif // Guard

View File

@ -15,6 +15,8 @@ compile (
'%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: TOP->v.rst2_bad_n '%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: TOP->v.rst2_bad_n
%Warning-CDCRSTLOGIC: Use "/\* verilator lint_off CDCRSTLOGIC \*/" and lint_on around source to disable this message. %Warning-CDCRSTLOGIC: Use "/\* verilator lint_off CDCRSTLOGIC \*/" and lint_on around source to disable this message.
%Warning-CDCRSTLOGIC: See details in obj_dir/t_cdc_async_bad/Vt_cdc_async_bad__cdc.txt %Warning-CDCRSTLOGIC: See details in obj_dir/t_cdc_async_bad/Vt_cdc_async_bad__cdc.txt
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: TOP->v.rst6a_bad_n
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: TOP->v.rst6b_bad_n
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: TOP->v.rst3_bad_n %Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: TOP->v.rst3_bad_n
%Error: Exiting due to.*', %Error: Exiting due to.*',
); );

View File

@ -5,7 +5,7 @@
module t (/*AUTOARG*/ module t (/*AUTOARG*/
// Outputs // Outputs
q0, q1, q2, q3, q4, q5, q0, q1, q2, q3, q4, q5, q6a, q6b,
// Inputs // Inputs
clk, d, rst0_n clk, d, rst0_n
); );
@ -47,6 +47,15 @@ module t (/*AUTOARG*/
output wire q5; output wire q5;
Flop flop5 (.q(q5), .rst_n(rst5_waive_n), .clk(clk), .d(d)); Flop flop5 (.q(q5), .rst_n(rst5_waive_n), .clk(clk), .d(d));
// Bad - for graph test - logic feeds two signals, three destinations
wire rst6_bad_n = rst0_n ^ rst1_n;
wire rst6a_bad_n = rst6_bad_n ^ $c1("0"); // $c prevents optimization
wire rst6b_bad_n = rst6_bad_n ^ $c1("1");
output wire q6a;
output wire q6b;
Flop flop6a (.q(q6a), .rst_n(rst6a_bad_n), .clk(clk), .d(d));
Flop flop6v (.q(q6b), .rst_n(rst6b_bad_n), .clk(clk), .d(d));
initial begin initial begin
$display("%%Error: Not a runnable test"); $display("%%Error: Not a runnable test");
$stop; $stop;