/**CFile**************************************************************** FileName [fretTime.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Flow-based retiming package.] Synopsis [Delay-constrained retiming code.] Author [Aaron Hurst] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - January 1, 2008.] Revision [$Id: fretTime.c,v 1.00 2008/01/01 00:00:00 ahurst Exp $] ***********************************************************************/ #include "abc.h" #include "vec.h" #include "fretime.h" //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// static void Abc_FlowRetime_Dfs_forw( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes ); static void Abc_FlowRetime_Dfs_back( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes ); static void Abc_FlowRetime_ConstrainExact_forw( Abc_Obj_t * pObj ); static void Abc_FlowRetime_ConstrainExact_back( Abc_Obj_t * pObj ); static void Abc_FlowRetime_ConstrainConserv_forw( Abc_Ntk_t * pNtk ); static void Abc_FlowRetime_ConstrainConserv_back( Abc_Ntk_t * pNtk ); void trace2(Abc_Obj_t *pObj) { Abc_Obj_t *pNext; int i; print_node(pObj); Abc_ObjForEachFanin(pObj, pNext, i) if (pNext->Level >= pObj->Level - 1) { trace2(pNext); break; } } //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Initializes timing] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_InitTiming( Abc_Ntk_t *pNtk ) { pManMR->nConservConstraints = pManMR->nExactConstraints = 0; pManMR->vExactNodes = Vec_PtrAlloc(1000); pManMR->vTimeEdges = ALLOC( Vec_Ptr_t, Abc_NtkObjNumMax(pNtk)+1 ); assert(pManMR->vTimeEdges); memset(pManMR->vTimeEdges, 0, (Abc_NtkObjNumMax(pNtk)+1) * sizeof(Vec_Ptr_t) ); } /**Function************************************************************* Synopsis [Marks nodes with conservative constraints.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_ConstrainConserv( Abc_Ntk_t * pNtk ) { Abc_Obj_t *pObj; int i; void *pArray; // clear all exact constraints pManMR->nExactConstraints = 0; while( Vec_PtrSize( pManMR->vExactNodes )) { pObj = Vec_PtrPop( pManMR->vExactNodes ); if ( Vec_PtrSize( FTIMEEDGES(pObj) )) { pArray = Vec_PtrReleaseArray( FTIMEEDGES(pObj) ); FREE( pArray ); } } #if !defined(IGNORE_TIMING) if (pManMR->fIsForward) { Abc_FlowRetime_ConstrainConserv_forw(pNtk); } else { Abc_FlowRetime_ConstrainConserv_back(pNtk); } #endif Abc_NtkForEachObj( pNtk, pObj, i) assert( !Vec_PtrSize(FTIMEEDGES(pObj)) ); } void Abc_FlowRetime_ConstrainConserv_forw( Abc_Ntk_t * pNtk ) { Vec_Ptr_t *vNodes = pManMR->vNodes; Abc_Obj_t *pObj, *pNext, *pBi, *pBo; int i, j; assert(!Vec_PtrSize( vNodes )); pManMR->nConservConstraints = 0; // 1. hard constraints // (i) collect TFO of PIs Abc_NtkIncrementTravId(pNtk); Abc_NtkForEachPi(pNtk, pObj, i) Abc_FlowRetime_Dfs_forw( pObj, vNodes ); // ... propagate values Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->Level = 0; Abc_ObjForEachFanin( pObj, pNext, j ) { if ( Abc_NodeIsTravIdCurrent(pNext) && pObj->Level < pNext->Level ) pObj->Level = pNext->Level; } pObj->Level += Abc_ObjIsNode(pObj) ? 1 : 0; if ( Abc_ObjIsBi(pObj) ) pObj->fMarkA = 1; assert(pObj->Level <= pManMR->maxDelay); } // collect TFO of latches // seed arrival times from BIs Vec_PtrClear(vNodes); Abc_NtkIncrementTravId(pNtk); Abc_NtkForEachLatch(pNtk, pObj, i) { pBo = Abc_ObjFanout0( pObj ); pBi = Abc_ObjFanin0( pObj ); Abc_NodeSetTravIdCurrent( pObj ); Abc_FlowRetime_Dfs_forw( pBo, vNodes ); if (pBi->fMarkA) { pBi->fMarkA = 0; pObj->Level = pBi->Level; assert(pObj->Level <= pManMR->maxDelay); } else pObj->Level = 0; } #if defined(DEBUG_CHECK) // DEBUG: check DFS ordering Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->fMarkB = 1; Abc_ObjForEachFanin( pObj, pNext, j ) if ( Abc_NodeIsTravIdCurrent(pNext) && !Abc_ObjIsLatch(pNext)) assert(pNext->fMarkB); } Vec_PtrForEachEntryReverse(vNodes, pObj, i) pObj->fMarkB = 0; #endif // ... propagate values Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->Level = 0; Abc_ObjForEachFanin( pObj, pNext, j ) { if ( Abc_NodeIsTravIdCurrent(pNext) && pObj->Level < pNext->Level ) pObj->Level = pNext->Level; } pObj->Level += Abc_ObjIsNode(pObj) ? 1 : 0; if (pObj->Level > pManMR->maxDelay) { FSET(pObj, BLOCK); } } // 2. conservative constraints // first pass: seed latches with T=0 Abc_NtkForEachLatch(pNtk, pObj, i) { pObj->Level = 0; } // ... propagate values Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->Level = 0; Abc_ObjForEachFanin( pObj, pNext, j ) { if ( Abc_NodeIsTravIdCurrent(pNext) && pObj->Level < pNext->Level ) pObj->Level = pNext->Level; } pObj->Level += Abc_ObjIsNode(pObj) ? 1 : 0; if ( Abc_ObjIsBi(pObj) ) pObj->fMarkA = 1; assert(pObj->Level <= pManMR->maxDelay); } Abc_NtkForEachLatch(pNtk, pObj, i) { pBo = Abc_ObjFanout0( pObj ); pBi = Abc_ObjFanin0( pObj ); if (pBi->fMarkA) { pBi->fMarkA = 0; pObj->Level = pBi->Level; assert(pObj->Level <= pManMR->maxDelay); } else pObj->Level = 0; } // ... propagate values Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->Level = 0; Abc_ObjForEachFanin( pObj, pNext, j ) { if ( Abc_NodeIsTravIdCurrent(pNext) && pObj->Level < pNext->Level ) pObj->Level = pNext->Level; } pObj->Level += Abc_ObjIsNode(pObj) ? 1 : 0; // constrained? if (pObj->Level > pManMR->maxDelay) { FSET( pObj, CONSERVATIVE ); pManMR->nConservConstraints++; } else FUNSET( pObj, CONSERVATIVE ); } Vec_PtrClear( vNodes ); } void Abc_FlowRetime_ConstrainConserv_back( Abc_Ntk_t * pNtk ) { Vec_Ptr_t *vNodes = pManMR->vNodes; Abc_Obj_t *pObj, *pNext, *pBi, *pBo; int i, j, l; assert(!Vec_PtrSize(vNodes)); pManMR->nConservConstraints = 0; // 1. hard constraints // (i) collect TFO of POs Abc_NtkIncrementTravId(pNtk); Abc_NtkForEachPo(pNtk, pObj, i) Abc_FlowRetime_Dfs_back( pObj, vNodes ); // ... propagate values Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->Level = 0; Abc_ObjForEachFanout( pObj, pNext, j ) { l = pNext->Level + (Abc_ObjIsNode(pObj) ? 1 : 0); if ( Abc_NodeIsTravIdCurrent(pNext) && pObj->Level < l ) pObj->Level = l; } if ( Abc_ObjIsBo(pObj) ) pObj->fMarkA = 1; assert(pObj->Level <= pManMR->maxDelay); } // collect TFO of latches // seed arrival times from BIs Vec_PtrClear(vNodes); Abc_NtkIncrementTravId(pNtk); Abc_NtkForEachLatch(pNtk, pObj, i) { pBo = Abc_ObjFanout0( pObj ); pBi = Abc_ObjFanin0( pObj ); Abc_NodeSetTravIdCurrent( pObj ); Abc_FlowRetime_Dfs_back( pBi, vNodes ); if (pBo->fMarkA) { pBo->fMarkA = 0; pObj->Level = pBo->Level; assert(pObj->Level <= pManMR->maxDelay); } else pObj->Level = 0; } #if defined(DEBUG_CHECK) // DEBUG: check DFS ordering Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->fMarkB = 1; Abc_ObjForEachFanout( pObj, pNext, j ) if ( Abc_NodeIsTravIdCurrent(pNext) && !Abc_ObjIsLatch(pNext)) assert(pNext->fMarkB); } Vec_PtrForEachEntryReverse(vNodes, pObj, i) pObj->fMarkB = 0; #endif // ... propagate values Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->Level = 0; Abc_ObjForEachFanout( pObj, pNext, j ) { l = pNext->Level + (Abc_ObjIsNode(pObj) ? 1 : 0); if ( Abc_NodeIsTravIdCurrent(pNext) && pObj->Level < l ) pObj->Level = l; } if (pObj->Level + (Abc_ObjIsNode(pObj)?1:0) > pManMR->maxDelay) { FSET(pObj, BLOCK); } } // 2. conservative constraints // first pass: seed latches with T=0 Abc_NtkForEachLatch(pNtk, pObj, i) { pObj->Level = 0; } // ... propagate values Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->Level = 0; Abc_ObjForEachFanout( pObj, pNext, j ) { l = pNext->Level + (Abc_ObjIsNode(pObj) ? 1 : 0); if ( Abc_NodeIsTravIdCurrent(pNext) && pObj->Level < l ) pObj->Level = l; } if ( Abc_ObjIsBo(pObj) ) { pObj->fMarkA = 1; } assert(pObj->Level <= pManMR->maxDelay); } Abc_NtkForEachLatch(pNtk, pObj, i) { pBo = Abc_ObjFanout0( pObj ); assert(Abc_ObjIsBo(pBo)); pBi = Abc_ObjFanin0( pObj ); assert(Abc_ObjIsBi(pBi)); if (pBo->fMarkA) { pBo->fMarkA = 0; pObj->Level = pBo->Level; } else pObj->Level = 0; } // ... propagate values Vec_PtrForEachEntryReverse(vNodes, pObj, i) { pObj->Level = 0; Abc_ObjForEachFanout( pObj, pNext, j ) { l = pNext->Level + (Abc_ObjIsNode(pObj) ? 1 : 0); if ( Abc_NodeIsTravIdCurrent(pNext) && pObj->Level < l ) pObj->Level = l; } // constrained? if (pObj->Level > pManMR->maxDelay) { FSET( pObj, CONSERVATIVE ); pManMR->nConservConstraints++; } else FUNSET( pObj, CONSERVATIVE ); } Vec_PtrClear( vNodes ); } /**Function************************************************************* Synopsis [Introduces exact timing constraints for a node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_ConstrainExact( Abc_Obj_t * pObj ) { if (FTEST( pObj, CONSERVATIVE )) { pManMR->nConservConstraints--; FUNSET( pObj, CONSERVATIVE ); } #if !defined(IGNORE_TIMING) if (pManMR->fIsForward) { Abc_FlowRetime_ConstrainExact_forw(pObj); } else { Abc_FlowRetime_ConstrainExact_back(pObj); } #endif } void Abc_FlowRetime_ConstrainExact_forw_rec( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes, int latch ) { Abc_Obj_t *pNext; int i; // terminate? if (Abc_ObjIsLatch(pObj)) { if (latch) return; latch = 1; } // already visited? if (!latch) { if (pObj->fMarkA) return; pObj->fMarkA = 1; } else { if (pObj->fMarkB) return; pObj->fMarkB = 1; } // recurse Abc_ObjForEachFanin(pObj, pNext, i) { Abc_FlowRetime_ConstrainExact_forw_rec( pNext, vNodes, latch ); } // add pObj->Level = 0; Vec_PtrPush(vNodes, Abc_ObjNotCond(pObj, latch)); } void Abc_FlowRetime_ConstrainExact_forw( Abc_Obj_t * pObj ) { Vec_Ptr_t *vNodes = pManMR->vNodes; Abc_Obj_t *pNext, *pCur, *pReg; // Abc_Ntk_t *pNtk = pManMR->pNtk; int i, j; assert( !Vec_PtrSize(vNodes) ); assert( !Abc_ObjIsLatch(pObj) ); assert( !Vec_PtrSize( FTIMEEDGES(pObj) )); Vec_PtrPush( pManMR->vExactNodes, pObj ); // rev topo order Abc_FlowRetime_ConstrainExact_forw_rec( pObj, vNodes, 0 ); Vec_PtrForEachEntryReverse( vNodes, pCur, i) { pReg = Abc_ObjRegular( pCur ); if (pReg == pCur) { assert(!Abc_ObjIsLatch(pReg)); Abc_ObjForEachFanin(pReg, pNext, j) pNext->Level = MAX( pNext->Level, pReg->Level + (Abc_ObjIsNode(pReg)?1:0)); assert(pReg->Level <= pManMR->maxDelay); pReg->Level = 0; pReg->fMarkA = pReg->fMarkB = 0; } } Vec_PtrForEachEntryReverse( vNodes, pCur, i) { pReg = Abc_ObjRegular( pCur ); if (pReg != pCur) { Abc_ObjForEachFanin(pReg, pNext, j) if (!Abc_ObjIsLatch(pNext)) pNext->Level = MAX( pNext->Level, pReg->Level + (Abc_ObjIsNode(pReg)?1:0)); if (pReg->Level == pManMR->maxDelay) { Vec_PtrPush( FTIMEEDGES(pObj), pReg); pManMR->nExactConstraints++; } pReg->Level = 0; pReg->fMarkA = pReg->fMarkB = 0; } } Vec_PtrClear( vNodes ); } void Abc_FlowRetime_ConstrainExact_back_rec( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes, int latch ) { Abc_Obj_t *pNext; int i; // terminate? if (Abc_ObjIsLatch(pObj)) { if (latch) return; latch = 1; } // already visited? if (!latch) { if (pObj->fMarkA) return; pObj->fMarkA = 1; } else { if (pObj->fMarkB) return; pObj->fMarkB = 1; } // recurse Abc_ObjForEachFanout(pObj, pNext, i) { Abc_FlowRetime_ConstrainExact_back_rec( pNext, vNodes, latch ); } // add pObj->Level = 0; Vec_PtrPush(vNodes, Abc_ObjNotCond(pObj, latch)); } void Abc_FlowRetime_ConstrainExact_back( Abc_Obj_t * pObj ) { Vec_Ptr_t *vNodes = pManMR->vNodes; Abc_Obj_t *pNext, *pCur, *pReg; // Abc_Ntk_t *pNtk = pManMR->pNtk; int i, j; assert( !Vec_PtrSize( vNodes )); assert( !Abc_ObjIsLatch(pObj) ); assert( !Vec_PtrSize( FTIMEEDGES(pObj) )); Vec_PtrPush( pManMR->vExactNodes, pObj ); // rev topo order Abc_FlowRetime_ConstrainExact_back_rec( pObj, vNodes, 0 ); Vec_PtrForEachEntryReverse( vNodes, pCur, i) { pReg = Abc_ObjRegular( pCur ); if (pReg == pCur) { assert(!Abc_ObjIsLatch(pReg)); Abc_ObjForEachFanout(pReg, pNext, j) pNext->Level = MAX( pNext->Level, pReg->Level + (Abc_ObjIsNode(pReg)?1:0)); assert(pReg->Level <= pManMR->maxDelay); pReg->Level = 0; pReg->fMarkA = pReg->fMarkB = 0; } } Vec_PtrForEachEntryReverse( vNodes, pCur, i) { pReg = Abc_ObjRegular( pCur ); if (pReg != pCur) { Abc_ObjForEachFanout(pReg, pNext, j) if (!Abc_ObjIsLatch(pNext)) pNext->Level = MAX( pNext->Level, pReg->Level + (Abc_ObjIsNode(pReg)?1:0)); if (pReg->Level == pManMR->maxDelay) { Vec_PtrPush( FTIMEEDGES(pObj), pReg); pManMR->nExactConstraints++; } pReg->Level = 0; pReg->fMarkA = pReg->fMarkB = 0; } } Vec_PtrClear( vNodes ); } /**Function************************************************************* Synopsis [Introduces all exact timing constraints in a network] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_ConstrainExactAll( Abc_Ntk_t * pNtk ) { int i; Abc_Obj_t *pObj; void *pArray; // free existing constraints Abc_NtkForEachObj( pNtk, pObj, i ) if ( Vec_PtrSize( FTIMEEDGES(pObj) )) { pArray = Vec_PtrReleaseArray( FTIMEEDGES(pObj) ); FREE( pArray ); } pManMR->nExactConstraints = 0; // generate all constraints Abc_NtkForEachObj(pNtk, pObj, i) if (!Abc_ObjIsLatch(pObj) && FTEST( pObj, CONSERVATIVE ) && !FTEST( pObj, BLOCK )) if (!Vec_PtrSize( FTIMEEDGES( pObj ) )) Abc_FlowRetime_ConstrainExact( pObj ); } /**Function************************************************************* Synopsis [Deallocates exact constraints.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_FreeTiming( Abc_Ntk_t *pNtk ) { Abc_Obj_t *pObj; void *pArray; while( Vec_PtrSize( pManMR->vExactNodes )) { pObj = Vec_PtrPop( pManMR->vExactNodes ); if ( Vec_PtrSize( FTIMEEDGES(pObj) )) { pArray = Vec_PtrReleaseArray( FTIMEEDGES(pObj) ); FREE( pArray ); } } Vec_PtrFree(pManMR->vExactNodes); FREE( pManMR->vTimeEdges ); } /**Function************************************************************* Synopsis [DFS order.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_FlowRetime_Dfs_forw( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes ) { Abc_Obj_t *pNext; int i; if (Abc_ObjIsLatch(pObj)) return; Abc_NodeSetTravIdCurrent( pObj ); Abc_ObjForEachFanout( pObj, pNext, i ) if (!Abc_NodeIsTravIdCurrent( pNext )) Abc_FlowRetime_Dfs_forw( pNext, vNodes ); Vec_PtrPush( vNodes, pObj ); } void Abc_FlowRetime_Dfs_back( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes ) { Abc_Obj_t *pNext; int i; if (Abc_ObjIsLatch(pObj)) return; Abc_NodeSetTravIdCurrent( pObj ); Abc_ObjForEachFanin( pObj, pNext, i ) if (!Abc_NodeIsTravIdCurrent( pNext )) Abc_FlowRetime_Dfs_back( pNext, vNodes ); Vec_PtrPush( vNodes, pObj ); } /**Function************************************************************* Synopsis [Main timing-constrained routine.] Description [Refines constraints that are limiting area improvement. These are identified by computing the min-cuts both with and without the conservative constraints: these two situation represent an over- and under-constrained version of the timing.] SideEffects [] SeeAlso [] ***********************************************************************/ bool Abc_FlowRetime_RefineConstraints( ) { Abc_Ntk_t *pNtk = pManMR->pNtk; int i, flow, count = 0; Abc_Obj_t *pObj; int maxTighten = 99999; vprintf("\t\tsubiter %d : constraints = {cons, exact} = %d, %d\n", pManMR->subIteration, pManMR->nConservConstraints, pManMR->nExactConstraints); // 1. overconstrained pManMR->constraintMask = BLOCK | CONSERVATIVE; vprintf("\t\trefinement: over "); fflush(stdout); flow = Abc_FlowRetime_PushFlows( pNtk, 0 ); vprintf("= %d ", flow); // remember nodes if (pManMR->fIsForward) { Abc_NtkForEachObj( pNtk, pObj, i ) if (!FTEST(pObj, VISITED_R)) pObj->fMarkC = 1; } else { Abc_NtkForEachObj( pNtk, pObj, i ) if (!FTEST(pObj, VISITED_E)) pObj->fMarkC = 1; } if (pManMR->fConservTimingOnly) { vprintf(" done\n"); return 0; } // 2. underconstrained pManMR->constraintMask = BLOCK; Abc_FlowRetime_ClearFlows( 0 ); vprintf("under = "); fflush(stdout); flow = Abc_FlowRetime_PushFlows( pNtk, 0 ); vprintf("%d refined nodes = ", flow); fflush(stdout); // find area-limiting constraints if (pManMR->fIsForward) { Abc_NtkForEachObj( pNtk, pObj, i ) { if (pObj->fMarkC && FTEST(pObj, VISITED_R) && FTEST(pObj, CONSERVATIVE) && count < maxTighten) { count++; Abc_FlowRetime_ConstrainExact( pObj ); } pObj->fMarkC = 0; } } else { Abc_NtkForEachObj( pNtk, pObj, i ) { if (pObj->fMarkC && FTEST(pObj, VISITED_E) && FTEST(pObj, CONSERVATIVE) && count < maxTighten) { count++; Abc_FlowRetime_ConstrainExact( pObj ); } pObj->fMarkC = 0; } } vprintf("%d\n", count); return (count > 0); }