mirror of
https://github.com/verilator/verilator.git
synced 2025-04-30 04:26:55 +00:00
Speed up CDC reset on large netlists; userClearVertices too slow
This commit is contained in:
parent
89234bcd42
commit
d903855aa3
@ -144,6 +144,7 @@ private:
|
|||||||
int m_senNumber; // Number of senitems
|
int m_senNumber; // Number of senitems
|
||||||
string m_ofFilename; // Output filename
|
string m_ofFilename; // Output filename
|
||||||
ofstream* m_ofp; // Output file
|
ofstream* m_ofp; // Output file
|
||||||
|
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void iterateNewStmt(AstNode* nodep) {
|
void iterateNewStmt(AstNode* nodep) {
|
||||||
@ -242,8 +243,9 @@ private:
|
|||||||
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
|
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
|
||||||
// Scan back to inputs/outputs, flops, and compute clock domain information
|
// Scan back to inputs/outputs, flops, and compute clock domain information
|
||||||
UINFO(8,spaces(level)<<" Tracein "<<vertexp<<endl);
|
UINFO(8,spaces(level)<<" Tracein "<<vertexp<<endl);
|
||||||
if (vertexp->user()) return; // Mid-Processed - prevent loop
|
if (vertexp->user()>=m_userGeneration) return; // Mid-Processed - prevent loop
|
||||||
vertexp->user(true);
|
vertexp->user(m_userGeneration);
|
||||||
|
|
||||||
// Variables from flops already are domained
|
// Variables from flops already are domained
|
||||||
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) return; // Fully computed
|
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) return; // Fully computed
|
||||||
|
|
||||||
@ -309,7 +311,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, uint32_t did_value, bool mark);
|
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark);
|
||||||
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp);
|
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp);
|
||||||
void dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& blank);
|
void dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& blank);
|
||||||
|
|
||||||
@ -448,6 +450,7 @@ public:
|
|||||||
m_domainp = NULL;
|
m_domainp = NULL;
|
||||||
m_inDly = false;
|
m_inDly = false;
|
||||||
m_senNumber = 0;
|
m_senNumber = 0;
|
||||||
|
m_userGeneration = 0;
|
||||||
|
|
||||||
// Make report of all signal names and what clock edges they have
|
// Make report of all signal names and what clock edges they have
|
||||||
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc.txt";
|
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc.txt";
|
||||||
@ -523,17 +526,20 @@ void CdcVisitor::analyze() {
|
|||||||
|
|
||||||
void CdcVisitor::analyzeReset() {
|
void CdcVisitor::analyzeReset() {
|
||||||
// Find all async reset wires, and trace backwards
|
// Find all async reset wires, and trace backwards
|
||||||
|
// userClearVertices is very slow, so we use a generation count instead
|
||||||
|
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
|
||||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||||
if (vvertexp->cntAsyncRst()) {
|
if (vvertexp->cntAsyncRst()) {
|
||||||
m_graph.userClearVertices(); // user1: bool - was analyzed
|
m_userGeneration++; // Effectively a userClearVertices()
|
||||||
UINFO(9, " Trace One async: "<<vvertexp<<endl);
|
UINFO(9, " Trace One async: "<<vvertexp<<endl);
|
||||||
// Twice, as we need to detect, then propagate
|
// Twice, as we need to detect, then propagate
|
||||||
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, 1, false);
|
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
|
||||||
if (markp) { // Mark is non-NULL if something bad on this path
|
if (markp) { // Mark is non-NULL if something bad on this path
|
||||||
UINFO(9, " Trace One bad! "<<vvertexp<<endl);
|
UINFO(9, " Trace One bad! "<<vvertexp<<endl);
|
||||||
traceAsyncRecurse(vvertexp, 2, true);
|
m_userGeneration++; // Effectively a userClearVertices()
|
||||||
m_graph.userClearVertices(); // user1: bool - was analyzed
|
traceAsyncRecurse(vvertexp, true);
|
||||||
|
m_userGeneration++; // Effectively a userClearVertices()
|
||||||
dumpAsync(vvertexp, markp);
|
dumpAsync(vvertexp, markp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,14 +547,14 @@ void CdcVisitor::analyzeReset() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CdcEitherVertex* CdcVisitor::traceAsyncRecurse(CdcEitherVertex* vertexp, uint32_t did_value, bool mark) {
|
CdcEitherVertex* CdcVisitor::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 mark, also mark the output even if nothing dangerous below
|
||||||
CdcEitherVertex* mark_outp = NULL;
|
CdcEitherVertex* mark_outp = NULL;
|
||||||
UINFO(9," Trace: "<<vertexp<<endl);
|
UINFO(9," Trace: "<<vertexp<<endl);
|
||||||
|
|
||||||
if (vertexp->user()>=did_value) return false; // Processed - prevent loop
|
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
|
||||||
vertexp->user(did_value);
|
vertexp->user(m_userGeneration);
|
||||||
|
|
||||||
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
|
||||||
@ -565,7 +571,7 @@ CdcEitherVertex* CdcVisitor::traceAsyncRecurse(CdcEitherVertex* vertexp, uint32_
|
|||||||
|
|
||||||
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();
|
||||||
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, did_value, mark);
|
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, mark);
|
||||||
if (submarkp && !mark_outp) mark_outp = submarkp;
|
if (submarkp && !mark_outp) mark_outp = submarkp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -592,8 +598,8 @@ void CdcVisitor::dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
|
|||||||
void CdcVisitor::dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& blank) {
|
void CdcVisitor::dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& blank) {
|
||||||
// Return true if any dangerous stuff attached
|
// Return true if any dangerous stuff attached
|
||||||
// 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()) return; // Processed - prevent loop
|
if (vertexp->user()>=m_userGeneration) return; // Processed - prevent loop
|
||||||
vertexp->user(1);
|
vertexp->user(m_userGeneration);
|
||||||
if (!vertexp->asyncPath()) return; // Not part of path
|
if (!vertexp->asyncPath()) return; // Not part of path
|
||||||
|
|
||||||
*m_ofp<<V3OutFile::indentSpaces(40)<<" "<<blank<<"\n";
|
*m_ofp<<V3OutFile::indentSpaces(40)<<" "<<blank<<"\n";
|
||||||
|
@ -198,7 +198,8 @@ void V3Graph::clear() {
|
|||||||
void V3Graph::userClearVertices() {
|
void V3Graph::userClearVertices() {
|
||||||
// Clear user() in all of tree
|
// Clear user() in all of tree
|
||||||
// We may use the userCnt trick in V3Ast later... (but gblCnt would be
|
// We may use the userCnt trick in V3Ast later... (but gblCnt would be
|
||||||
// in V3Graph instead of static) For now we don't call this often, and
|
// in V3Graph instead of static - which has the complication of finding
|
||||||
|
// the graph pointer given a vertex.) For now we don't call this often, and
|
||||||
// the extra code on each read of user() would probably slow things
|
// the extra code on each read of user() would probably slow things
|
||||||
// down more than help.
|
// down more than help.
|
||||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user