forked from github/verilator
--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);
|
||||
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; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.*',
|
||||
);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user