| /**CFile**************************************************************** | |
| FileName [fretFlow.c] | |
| SystemName [ABC: Logic synthesis and verification system.] | |
| PackageName [Flow-based retiming package.] | |
| Synopsis [Max-flow computation.] | |
| Author [Aaron Hurst] | |
| Affiliation [UC Berkeley] | |
| Date [Ver. 1.0. Started - January 1, 2008.] | |
| Revision [$Id: fretFlow.c,v 1.00 2008/01/01 00:00:00 ahurst Exp $] | |
| ***********************************************************************/ | |
| #include "fretime.h" | |
| ABC_NAMESPACE_IMPL_START | |
| //////////////////////////////////////////////////////////////////////// | |
| /// DECLARATIONS /// | |
| //////////////////////////////////////////////////////////////////////// | |
| static void dfsfast_e_retreat( Abc_Obj_t *pObj ); | |
| static void dfsfast_r_retreat( Abc_Obj_t *pObj ); | |
| #define FDIST(xn, xe, yn, ye) (FDATA(xn)->xe##_dist == (FDATA(yn)->ye##_dist + 1)) | |
| //////////////////////////////////////////////////////////////////////// | |
| /// FUNCTION DEFINITIONS /// | |
| //////////////////////////////////////////////////////////////////////// | |
| /**Function************************************************************* | |
| Synopsis [Fast DFS.] | |
| Description [Uses sink-distance-histogram heuristic. May not find all | |
| flow paths: this occurs in a small number of cases where | |
| the flow predecessor points to a non-adjacent node and | |
| the distance ordering is perturbed.] | |
| SideEffects [] | |
| SeeAlso [] | |
| ***********************************************************************/ | |
| void dfsfast_preorder( Abc_Ntk_t *pNtk ) { | |
| Abc_Obj_t *pObj, *pNext; | |
| Vec_Ptr_t *vTimeIn, *qn = Vec_PtrAlloc(Abc_NtkObjNum(pNtk)); | |
| Vec_Int_t *qe = Vec_IntAlloc(Abc_NtkObjNum(pNtk)); | |
| int i, j, d = 0, end; | |
| int qpos = 0; | |
| // create reverse timing edges for backward traversal | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay) { | |
| Abc_NtkForEachObj( pNtk, pObj, i ) { | |
| Vec_PtrForEachEntry( Abc_Obj_t *, FTIMEEDGES(pObj), pNext, j ) { | |
| vTimeIn = FDATA(pNext)->vNodes; | |
| if (!vTimeIn) { | |
| vTimeIn = FDATA(pNext)->vNodes = Vec_PtrAlloc(2); | |
| } | |
| Vec_PtrPush(vTimeIn, pObj); | |
| } | |
| } | |
| } | |
| #endif | |
| // clear histogram | |
| assert(pManMR->vSinkDistHist); | |
| memset(Vec_IntArray(pManMR->vSinkDistHist), 0, sizeof(int)*Vec_IntSize(pManMR->vSinkDistHist)); | |
| // seed queue : latches, PIOs, and blocks | |
| Abc_NtkForEachObj( pNtk, pObj, i ) | |
| if (Abc_ObjIsPo(pObj) || | |
| Abc_ObjIsLatch(pObj) || | |
| (pManMR->fIsForward && FTEST(pObj, BLOCK_OR_CONS) & pManMR->constraintMask)) { | |
| Vec_PtrPush(qn, pObj); | |
| Vec_IntPush(qe, 'r'); | |
| FDATA(pObj)->r_dist = 1; | |
| } else if (Abc_ObjIsPi(pObj) || | |
| (!pManMR->fIsForward && FTEST(pObj, BLOCK_OR_CONS) & pManMR->constraintMask)) { | |
| Vec_PtrPush(qn, pObj); | |
| Vec_IntPush(qe, 'e'); | |
| FDATA(pObj)->e_dist = 1; | |
| } | |
| // until queue is empty... | |
| while(qpos < Vec_PtrSize(qn)) { | |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(qn, qpos); | |
| assert(pObj); | |
| end = Vec_IntEntry(qe, qpos); | |
| qpos++; | |
| if (end == 'r') { | |
| d = FDATA(pObj)->r_dist; | |
| // 1. structural edges | |
| if (pManMR->fIsForward) { | |
| Abc_ObjForEachFanin( pObj, pNext, i ) | |
| if (!FDATA(pNext)->e_dist) { | |
| FDATA(pNext)->e_dist = d+1; | |
| Vec_PtrPush(qn, pNext); | |
| Vec_IntPush(qe, 'e'); | |
| } | |
| } else | |
| Abc_ObjForEachFanout( pObj, pNext, i ) | |
| if (!FDATA(pNext)->e_dist) { | |
| FDATA(pNext)->e_dist = d+1; | |
| Vec_PtrPush(qn, pNext); | |
| Vec_IntPush(qe, 'e'); | |
| } | |
| if (d == 1) continue; | |
| // 2. reverse edges (forward retiming only) | |
| if (pManMR->fIsForward) { | |
| Abc_ObjForEachFanout( pObj, pNext, i ) | |
| if (!FDATA(pNext)->r_dist && !Abc_ObjIsLatch(pNext)) { | |
| FDATA(pNext)->r_dist = d+1; | |
| Vec_PtrPush(qn, pNext); | |
| Vec_IntPush(qe, 'r'); | |
| } | |
| // 3. timimg edges (forward retiming only) | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay && FDATA(pObj)->vNodes) | |
| Vec_PtrForEachEntry(Abc_Obj_t *, FDATA(pObj)->vNodes, pNext, i ) { | |
| if (!FDATA(pNext)->r_dist) { | |
| FDATA(pNext)->r_dist = d+1; | |
| Vec_PtrPush(qn, pNext); | |
| Vec_IntPush(qe, 'r'); | |
| } | |
| } | |
| #endif | |
| } | |
| } else { // if 'e' | |
| if (Abc_ObjIsLatch(pObj)) continue; | |
| d = FDATA(pObj)->e_dist; | |
| // 1. through node | |
| if (!FDATA(pObj)->r_dist) { | |
| FDATA(pObj)->r_dist = d+1; | |
| Vec_PtrPush(qn, pObj); | |
| Vec_IntPush(qe, 'r'); | |
| } | |
| // 2. reverse edges (backward retiming only) | |
| if (!pManMR->fIsForward) { | |
| Abc_ObjForEachFanin( pObj, pNext, i ) | |
| if (!FDATA(pNext)->e_dist && !Abc_ObjIsLatch(pNext)) { | |
| FDATA(pNext)->e_dist = d+1; | |
| Vec_PtrPush(qn, pNext); | |
| Vec_IntPush(qe, 'e'); | |
| } | |
| // 3. timimg edges (backward retiming only) | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay && FDATA(pObj)->vNodes) | |
| Vec_PtrForEachEntry(Abc_Obj_t *, FDATA(pObj)->vNodes, pNext, i ) { | |
| if (!FDATA(pNext)->e_dist) { | |
| FDATA(pNext)->e_dist = d+1; | |
| Vec_PtrPush(qn, pNext); | |
| Vec_IntPush(qe, 'e'); | |
| } | |
| } | |
| #endif | |
| } | |
| } | |
| } | |
| // free time edges | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay) { | |
| Abc_NtkForEachObj( pNtk, pObj, i ) { | |
| vTimeIn = FDATA(pObj)->vNodes; | |
| if (vTimeIn) { | |
| Vec_PtrFree(vTimeIn); | |
| FDATA(pObj)->vNodes = 0; | |
| } | |
| } | |
| } | |
| #endif | |
| Abc_NtkForEachObj( pNtk, pObj, i ) { | |
| Vec_IntAddToEntry(pManMR->vSinkDistHist, FDATA(pObj)->r_dist, 1); | |
| Vec_IntAddToEntry(pManMR->vSinkDistHist, FDATA(pObj)->e_dist, 1); | |
| #ifdef DEBUG_PREORDER | |
| printf("node %d\t: r=%d\te=%d\n", Abc_ObjId(pObj), FDATA(pObj)->r_dist, FDATA(pObj)->e_dist); | |
| #endif | |
| } | |
| // printf("\t\tpre-ordered (max depth=%d)\n", d+1); | |
| // deallocate | |
| Vec_PtrFree( qn ); | |
| Vec_IntFree( qe ); | |
| } | |
| int dfsfast_e( Abc_Obj_t *pObj, Abc_Obj_t *pPred ) { | |
| int i; | |
| Abc_Obj_t *pNext; | |
| if (pManMR->fSinkDistTerminate) return 0; | |
| // have we reached the sink? | |
| if(FTEST(pObj, BLOCK_OR_CONS) & pManMR->constraintMask || | |
| Abc_ObjIsPi(pObj)) { | |
| assert(pPred); | |
| assert(!pManMR->fIsForward); | |
| return 1; | |
| } | |
| FSET(pObj, VISITED_E); | |
| #ifdef DEBUG_VISITED | |
| printf("(%de=%d) ", Abc_ObjId(pObj), FDATA(pObj)->e_dist); | |
| #endif | |
| // 1. structural edges | |
| if (pManMR->fIsForward) | |
| Abc_ObjForEachFanout( pObj, pNext, i ) { | |
| if (!FTEST(pNext, VISITED_R) && | |
| FDIST(pObj, e, pNext, r) && | |
| dfsfast_r(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("o"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| else | |
| Abc_ObjForEachFanin( pObj, pNext, i ) { | |
| if (!FTEST(pNext, VISITED_R) && | |
| FDIST(pObj, e, pNext, r) && | |
| dfsfast_r(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("o"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| if (Abc_ObjIsLatch(pObj)) | |
| goto not_found; | |
| // 2. reverse edges (backward retiming only) | |
| if (!pManMR->fIsForward) { | |
| Abc_ObjForEachFanout( pObj, pNext, i ) { | |
| if (!FTEST(pNext, VISITED_E) && | |
| FDIST(pObj, e, pNext, e) && | |
| dfsfast_e(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("i"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| // 3. timing edges (backward retiming only) | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay) | |
| Vec_PtrForEachEntry(Abc_Obj_t *, FTIMEEDGES(pObj), pNext, i) { | |
| if (!FTEST(pNext, VISITED_E) && | |
| FDIST(pObj, e, pNext, e) && | |
| dfsfast_e(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("o"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| #endif | |
| } | |
| // unwind | |
| if (FTEST(pObj, FLOW) && | |
| !FTEST(pObj, VISITED_R) && | |
| FDIST(pObj, e, pObj, r) && | |
| dfsfast_r(pObj, FGETPRED(pObj))) { | |
| FUNSET(pObj, FLOW); | |
| FSETPRED(pObj, NULL); | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("u"); | |
| #endif | |
| goto found; | |
| } | |
| not_found: | |
| FUNSET(pObj, VISITED_E); | |
| dfsfast_e_retreat(pObj); | |
| return 0; | |
| found: | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("%d ", Abc_ObjId(pObj)); | |
| #endif | |
| FUNSET(pObj, VISITED_E); | |
| return 1; | |
| } | |
| int dfsfast_r( Abc_Obj_t *pObj, Abc_Obj_t *pPred ) { | |
| int i; | |
| Abc_Obj_t *pNext, *pOldPred; | |
| if (pManMR->fSinkDistTerminate) return 0; | |
| #ifdef DEBUG_VISITED | |
| printf("(%dr=%d) ", Abc_ObjId(pObj), FDATA(pObj)->r_dist); | |
| #endif | |
| // have we reached the sink? | |
| if (Abc_ObjIsLatch(pObj) || | |
| (pManMR->fIsForward && Abc_ObjIsPo(pObj)) || | |
| (pManMR->fIsForward && FTEST(pObj, BLOCK_OR_CONS) & pManMR->constraintMask)) { | |
| assert(pPred); | |
| return 1; | |
| } | |
| FSET(pObj, VISITED_R); | |
| if (FTEST(pObj, FLOW)) { | |
| pOldPred = FGETPRED(pObj); | |
| if (pOldPred && | |
| !FTEST(pOldPred, VISITED_E) && | |
| FDIST(pObj, r, pOldPred, e) && | |
| dfsfast_e(pOldPred, pOldPred)) { | |
| FSETPRED(pObj, pPred); | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("fr"); | |
| #endif | |
| goto found; | |
| } | |
| } else { | |
| if (!FTEST(pObj, VISITED_E) && | |
| FDIST(pObj, r, pObj, e) && | |
| dfsfast_e(pObj, pObj)) { | |
| FSET(pObj, FLOW); | |
| FSETPRED(pObj, pPred); | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("f"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| // 2. reverse edges (forward retiming only) | |
| if (pManMR->fIsForward) { | |
| Abc_ObjForEachFanin( pObj, pNext, i ) { | |
| if (!FTEST(pNext, VISITED_R) && | |
| FDIST(pObj, r, pNext, r) && | |
| !Abc_ObjIsLatch(pNext) && | |
| dfsfast_r(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("i"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| // 3. timing edges (forward retiming only) | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay) | |
| Vec_PtrForEachEntry(Abc_Obj_t*, FTIMEEDGES(pObj), pNext, i) { | |
| if (!FTEST(pNext, VISITED_R) && | |
| FDIST(pObj, r, pNext, r) && | |
| dfsfast_r(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("o"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| #endif | |
| } | |
| FUNSET(pObj, VISITED_R); | |
| dfsfast_r_retreat(pObj); | |
| return 0; | |
| found: | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("%d ", Abc_ObjId(pObj)); | |
| #endif | |
| FUNSET(pObj, VISITED_R); | |
| return 1; | |
| } | |
| void | |
| dfsfast_e_retreat(Abc_Obj_t *pObj) { | |
| Abc_Obj_t *pNext; | |
| int i, *h; | |
| int old_dist = FDATA(pObj)->e_dist; | |
| int adj_dist, min_dist = MAX_DIST; | |
| // 1. structural edges | |
| if (pManMR->fIsForward) | |
| Abc_ObjForEachFanout( pObj, pNext, i ) { | |
| adj_dist = FDATA(pNext)->r_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| else | |
| Abc_ObjForEachFanin( pObj, pNext, i ) { | |
| adj_dist = FDATA(pNext)->r_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| if (Abc_ObjIsLatch(pObj)) goto update; | |
| // 2. through | |
| if (FTEST(pObj, FLOW)) { | |
| adj_dist = FDATA(pObj)->r_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| // 3. reverse edges (backward retiming only) | |
| if (!pManMR->fIsForward) { | |
| Abc_ObjForEachFanout( pObj, pNext, i ) { | |
| adj_dist = FDATA(pNext)->e_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| // 4. timing edges (backward retiming only) | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay) | |
| Vec_PtrForEachEntry(Abc_Obj_t*, FTIMEEDGES(pObj), pNext, i) { | |
| adj_dist = FDATA(pNext)->e_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| #endif | |
| } | |
| update: | |
| ++min_dist; | |
| if (min_dist >= MAX_DIST) min_dist = 0; | |
| // printf("[%de=%d->%d] ", Abc_ObjId(pObj), old_dist, min_dist+1); | |
| FDATA(pObj)->e_dist = min_dist; | |
| assert(min_dist < Vec_IntSize(pManMR->vSinkDistHist)); | |
| h = Vec_IntArray(pManMR->vSinkDistHist); | |
| h[old_dist]--; | |
| h[min_dist]++; | |
| if (!h[old_dist]) { | |
| pManMR->fSinkDistTerminate = 1; | |
| } | |
| } | |
| void | |
| dfsfast_r_retreat(Abc_Obj_t *pObj) { | |
| Abc_Obj_t *pNext; | |
| int i, *h; | |
| int old_dist = FDATA(pObj)->r_dist; | |
| int adj_dist, min_dist = MAX_DIST; | |
| // 1. through or pred | |
| if (FTEST(pObj, FLOW)) { | |
| if (FGETPRED(pObj)) { | |
| adj_dist = FDATA(FGETPRED(pObj))->e_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| } else { | |
| adj_dist = FDATA(pObj)->e_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| // 2. reverse edges (forward retiming only) | |
| if (pManMR->fIsForward) { | |
| Abc_ObjForEachFanin( pObj, pNext, i ) | |
| if (!Abc_ObjIsLatch(pNext)) { | |
| adj_dist = FDATA(pNext)->r_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| // 3. timing edges (forward retiming only) | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay) | |
| Vec_PtrForEachEntry(Abc_Obj_t*, FTIMEEDGES(pObj), pNext, i) { | |
| adj_dist = FDATA(pNext)->r_dist; | |
| if (adj_dist) min_dist = MIN(min_dist, adj_dist); | |
| } | |
| #endif | |
| } | |
| ++min_dist; | |
| if (min_dist >= MAX_DIST) min_dist = 0; | |
| //printf("[%dr=%d->%d] ", Abc_ObjId(pObj), old_dist, min_dist+1); | |
| FDATA(pObj)->r_dist = min_dist; | |
| assert(min_dist < Vec_IntSize(pManMR->vSinkDistHist)); | |
| h = Vec_IntArray(pManMR->vSinkDistHist); | |
| h[old_dist]--; | |
| h[min_dist]++; | |
| if (!h[old_dist]) { | |
| pManMR->fSinkDistTerminate = 1; | |
| } | |
| } | |
| /**Function************************************************************* | |
| Synopsis [Plain DFS.] | |
| Description [Does not use sink-distance-histogram heuristic.] | |
| SideEffects [] | |
| SeeAlso [] | |
| ***********************************************************************/ | |
| int dfsplain_e( Abc_Obj_t *pObj, Abc_Obj_t *pPred ) { | |
| int i; | |
| Abc_Obj_t *pNext; | |
| if (FTEST(pObj, BLOCK_OR_CONS) & pManMR->constraintMask || | |
| Abc_ObjIsPi(pObj)) { | |
| assert(pPred); | |
| assert(!pManMR->fIsForward); | |
| return 1; | |
| } | |
| FSET(pObj, VISITED_E); | |
| // printf(" %de\n", Abc_ObjId(pObj)); | |
| // 1. structural edges | |
| if (pManMR->fIsForward) | |
| Abc_ObjForEachFanout( pObj, pNext, i ) { | |
| if (!FTEST(pNext, VISITED_R) && | |
| dfsplain_r(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("o"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| else | |
| Abc_ObjForEachFanin( pObj, pNext, i ) { | |
| if (!FTEST(pNext, VISITED_R) && | |
| dfsplain_r(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("o"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| if (Abc_ObjIsLatch(pObj)) | |
| return 0; | |
| // 2. reverse edges (backward retiming only) | |
| if (!pManMR->fIsForward) { | |
| Abc_ObjForEachFanout( pObj, pNext, i ) { | |
| if (!FTEST(pNext, VISITED_E) && | |
| dfsplain_e(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("i"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| // 3. timing edges (backward retiming only) | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay) | |
| Vec_PtrForEachEntry(Abc_Obj_t*, FTIMEEDGES(pObj), pNext, i) { | |
| if (!FTEST(pNext, VISITED_E) && | |
| dfsplain_e(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("o"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| #endif | |
| } | |
| // unwind | |
| if (FTEST(pObj, FLOW) && | |
| !FTEST(pObj, VISITED_R) && | |
| dfsplain_r(pObj, FGETPRED(pObj))) { | |
| FUNSET(pObj, FLOW); | |
| FSETPRED(pObj, NULL); | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("u"); | |
| #endif | |
| goto found; | |
| } | |
| return 0; | |
| found: | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("%d ", Abc_ObjId(pObj)); | |
| #endif | |
| return 1; | |
| } | |
| int dfsplain_r( Abc_Obj_t *pObj, Abc_Obj_t *pPred ) { | |
| int i; | |
| Abc_Obj_t *pNext, *pOldPred; | |
| // have we reached the sink? | |
| if (Abc_ObjIsLatch(pObj) || | |
| (pManMR->fIsForward && Abc_ObjIsPo(pObj)) || | |
| (pManMR->fIsForward && FTEST(pObj, BLOCK_OR_CONS) & pManMR->constraintMask)) { | |
| assert(pPred); | |
| return 1; | |
| } | |
| FSET(pObj, VISITED_R); | |
| // printf(" %dr\n", Abc_ObjId(pObj)); | |
| if (FTEST(pObj, FLOW)) { | |
| pOldPred = FGETPRED(pObj); | |
| if (pOldPred && | |
| !FTEST(pOldPred, VISITED_E) && | |
| dfsplain_e(pOldPred, pOldPred)) { | |
| FSETPRED(pObj, pPred); | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("fr"); | |
| #endif | |
| goto found; | |
| } | |
| } else { | |
| if (!FTEST(pObj, VISITED_E) && | |
| dfsplain_e(pObj, pObj)) { | |
| FSET(pObj, FLOW); | |
| FSETPRED(pObj, pPred); | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("f"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| // 2. follow reverse edges | |
| if (pManMR->fIsForward) { // forward retiming only | |
| Abc_ObjForEachFanin( pObj, pNext, i ) { | |
| if (!FTEST(pNext, VISITED_R) && | |
| !Abc_ObjIsLatch(pNext) && | |
| dfsplain_r(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("i"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| // 3. timing edges (forward only) | |
| #if !defined(IGNORE_TIMING) | |
| if (pManMR->maxDelay) | |
| Vec_PtrForEachEntry(Abc_Obj_t*, FTIMEEDGES(pObj), pNext, i) { | |
| if (!FTEST(pNext, VISITED_R) && | |
| dfsplain_r(pNext, pPred)) { | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("o"); | |
| #endif | |
| goto found; | |
| } | |
| } | |
| #endif | |
| } | |
| return 0; | |
| found: | |
| #ifdef DEBUG_PRINT_FLOWS | |
| printf("%d ", Abc_ObjId(pObj)); | |
| #endif | |
| return 1; | |
| } | |
| ABC_NAMESPACE_IMPL_END | |