--cdc: Report in more typical source to dest order
This commit is contained in:
parent
32c30c34e9
commit
6aec0ce702
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.*',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue