--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);
vertexp = new CdcVarVertex(&m_graph, m_scopep, varscp);
varscp->user1p(vertexp);
if (varscp->varp()->isIO() && varscp->scopep()->isTop()) {}
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);
return vertexp;
@ -231,9 +240,11 @@ private:
void clearNodeSafe(AstNode* nodep) {
// 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.
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
UINFO(9,"Clear safe "<<nodep<<endl);
m_logicVertexp->clearSafe(nodep);
if (!m_domainp || m_domainp->hasCombo()) { // Source flop logic in a posedge block is OK for reset (not async though)
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
UINFO(9,"Clear safe "<<nodep<<endl);
m_logicVertexp->clearSafe(nodep);
}
}
}
@ -283,12 +294,14 @@ private:
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
// 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;
UINFO(9," Trace: "<<vertexp<<endl);
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
vertexp->user(m_userGeneration);
// Clear out in prep for marking next path
if (!mark) vertexp->asyncPath(false);
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Any logic considered bad, at the moment, anyhow
@ -298,13 +311,20 @@ private:
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
if (mark) vvertexp->asyncPath(true);
// 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
if (vvertexp->fromFlop()) {
//for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
// CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
// eFromVertexp->asyncPath(true);
//}
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
eFromVertexp->asyncPath(true);
}
return false;
}
}
@ -323,42 +343,49 @@ private:
AstNode* nodep = vertexp->varScp();
*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()) {
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());
*m_ofp<<"Fanout: "<<vertexp->cntAsyncRst()<<" Target: "<<targetp->fileline()<<endl;
dumpAsyncRecurse(vertexp," +--", " | ");
dumpAsyncRecurse(targetp, "", " ",0);
}
void dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& blank) {
// Return true if any dangerous stuff attached
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep, int level) {
// 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 (vertexp->user()>=m_userGeneration) return; // Processed - prevent loop
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
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
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
AstNode* nodep = vertexp->nodep();
string front = pad(40,nodep->fileline()->ascii()+":");
front += " "+prefix+" ";
if (nodep->castVarScope()) *m_ofp<<front<<"Variable: "<<nodep->prettyName()<<endl;
string front = pad(40,nodep->fileline()->ascii()+":")+" "+prefix+" +- ";
if (nodep->castVarScope()) {
*m_ofp<<front<<"Variable: "<<nodep->prettyName()<<endl;
}
else {
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix+" ", true);
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix+" +- ", vertexp->srcDomainp(), true);
if (debug()) {
CdcDumpVisitor visitor (nodep, m_ofp, front+"DBG: ");
}
}
// Now do the other logic in the path
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
dumpAsyncRecurse(eFromVertexp, blank+" +--", blank+" | ");
}
nextsep = " | ";
if (level) *m_ofp<<V3OutFile::indentSpaces(40)<<" "<<prefix<<nextsep<<"\n";
return true;
}
//----------------------------------------
@ -607,16 +634,16 @@ public:
if (m_ofp->fail()) v3fatalSrc("Can't write "<<filename);
m_ofFilename = filename;
*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<<"First the variable is listed, then the logic that creates it, then all variables\n";
*m_ofp<<"feeding that logic, recursively backwards to the sourcing flop(s).\n";
*m_ofp<<"%% Indicates nodes considered potentially unsafe.\n";
*m_ofp<<"Each dump below traces logic from inputs/source flops to destination flop(s).\n";
*m_ofp<<"First source logic is listed, then a variable that logic generates,\n";
*m_ofp<<"repeating recursively forwards to the destination flop(s).\n";
*m_ofp<<"%% Indicates the operator considered potentially unsafe.\n";
nodep->accept(*this);
analyze();
//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() {
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*) {
putfs(nodep,"$c(");
nodep->bodysp()->iterateAndNext(*this); puts(")\n");
nodep->bodysp()->iterateAndNext(*this);
puts(")");
}
// Operators
@ -488,9 +489,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
public:
EmitVBaseVisitor() {
EmitVBaseVisitor(AstSenTree* domainp=NULL) { // Domain for printing one a ALWAYS under a ACTIVE
m_suppressSemi = false;
m_sensesp = NULL;
m_sensesp = domainp;
}
virtual ~EmitVBaseVisitor() {}
};
@ -597,8 +598,9 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
}
public:
EmitVPrefixedVisitor(AstNode* nodep, ostream& os, const string& prefix, bool user3mark)
: m_formatter(os, prefix), m_user3mark(user3mark) {
EmitVPrefixedVisitor(AstNode* nodep, ostream& os, const string& prefix,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor(domainp), m_formatter(os, prefix), m_user3mark(user3mark) {
if (user3mark) { AstUser3InUse::check(); }
nodep->accept(*this);
}
@ -631,6 +633,7 @@ void V3EmitV::verilogForTree(AstNode* nodep, ostream& os) {
EmitVStreamVisitor(nodep, os);
}
void V3EmitV::verilogPrefixedTree(AstNode* nodep, ostream& os, const string& prefix, bool user3mark) {
EmitVPrefixedVisitor(nodep, os, prefix, user3mark);
void V3EmitV::verilogPrefixedTree(AstNode* nodep, ostream& os, const string& prefix,
AstSenTree* domainp, bool user3mark) {
EmitVPrefixedVisitor(nodep, os, prefix, domainp, user3mark);
}

View File

@ -33,7 +33,8 @@ class V3EmitV {
public:
static void emitv();
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

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: 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: 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
%Error: Exiting due to.*',
);

View File

@ -5,7 +5,7 @@
module t (/*AUTOARG*/
// Outputs
q0, q1, q2, q3, q4, q5,
q0, q1, q2, q3, q4, q5, q6a, q6b,
// Inputs
clk, d, rst0_n
);
@ -47,6 +47,15 @@ module t (/*AUTOARG*/
output wire q5;
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
$display("%%Error: Not a runnable test");
$stop;