Speed up CDC reset on large netlists; userClearVertices too slow

This commit is contained in:
Wilson Snyder 2010-01-08 11:12:16 -05:00
parent 89234bcd42
commit d903855aa3
2 changed files with 21 additions and 14 deletions

View File

@ -144,6 +144,7 @@ private:
int m_senNumber; // Number of senitems
string m_ofFilename; // Output filename
ofstream* m_ofp; // Output file
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
// METHODS
void iterateNewStmt(AstNode* nodep) {
@ -242,8 +243,9 @@ private:
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
// Scan back to inputs/outputs, flops, and compute clock domain information
UINFO(8,spaces(level)<<" Tracein "<<vertexp<<endl);
if (vertexp->user()) return; // Mid-Processed - prevent loop
vertexp->user(true);
if (vertexp->user()>=m_userGeneration) return; // Mid-Processed - prevent loop
vertexp->user(m_userGeneration);
// Variables from flops already are domained
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 dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& blank);
@ -448,6 +450,7 @@ public:
m_domainp = NULL;
m_inDly = false;
m_senNumber = 0;
m_userGeneration = 0;
// Make report of all signal names and what clock edges they have
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc.txt";
@ -523,17 +526,20 @@ void CdcVisitor::analyze() {
void CdcVisitor::analyzeReset() {
// 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()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (vvertexp->cntAsyncRst()) {
m_graph.userClearVertices(); // user1: bool - was analyzed
m_userGeneration++; // Effectively a userClearVertices()
UINFO(9, " Trace One async: "<<vvertexp<<endl);
// 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
UINFO(9, " Trace One bad! "<<vvertexp<<endl);
traceAsyncRecurse(vvertexp, 2, true);
m_graph.userClearVertices(); // user1: bool - was analyzed
m_userGeneration++; // Effectively a userClearVertices()
traceAsyncRecurse(vvertexp, true);
m_userGeneration++; // Effectively a userClearVertices()
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
// If mark, also mark the output even if nothing dangerous below
CdcEitherVertex* mark_outp = NULL;
UINFO(9," Trace: "<<vertexp<<endl);
if (vertexp->user()>=did_value) return false; // Processed - prevent loop
vertexp->user(did_value);
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
vertexp->user(m_userGeneration);
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// 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()) {
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, did_value, mark);
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, mark);
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) {
// Return true if any dangerous stuff attached
// If mark, also mark the output even if nothing dangerous below
if (vertexp->user()) return; // Processed - prevent loop
vertexp->user(1);
if (vertexp->user()>=m_userGeneration) return; // Processed - prevent loop
vertexp->user(m_userGeneration);
if (!vertexp->asyncPath()) return; // Not part of path
*m_ofp<<V3OutFile::indentSpaces(40)<<" "<<blank<<"\n";

View File

@ -198,7 +198,8 @@ void V3Graph::clear() {
void V3Graph::userClearVertices() {
// Clear user() in all of tree
// 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
// down more than help.
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {