| /**CFile**************************************************************** |
| |
| FileName [sclSize.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Standard-cell library representation.] |
| |
| Synopsis [Core timing analysis used in gate-sizing.] |
| |
| Author [Alan Mishchenko, Niklas Een] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - August 24, 2012.] |
| |
| Revision [$Id: sclSize.c,v 1.0 2012/08/24 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "sclSize.h" |
| #include "map/mio/mio.h" |
| #include "misc/vec/vecWec.h" |
| #include "base/main/main.h" |
| |
| #ifdef WIN32 |
| #include <windows.h> |
| #endif |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Finding most critical objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Obj_t * Abc_SclFindCriticalCo( SC_Man * p, int * pfRise ) |
| { |
| Abc_Obj_t * pObj, * pPivot = NULL; |
| float fMaxArr = 0; |
| int i; |
| assert( Abc_NtkPoNum(p->pNtk) > 0 ); |
| Abc_NtkForEachCo( p->pNtk, pObj, i ) |
| { |
| SC_Pair * pArr = Abc_SclObjTime( p, pObj ); |
| if ( fMaxArr < pArr->rise ) fMaxArr = pArr->rise, *pfRise = 1, pPivot = pObj; |
| if ( fMaxArr < pArr->fall ) fMaxArr = pArr->fall, *pfRise = 0, pPivot = pObj; |
| } |
| if ( fMaxArr == 0 ) |
| pPivot = Abc_NtkPo(p->pNtk, 0); |
| assert( pPivot != NULL ); |
| return pPivot; |
| } |
| // assumes that slacks are not available (uses arrival times) |
| Abc_Obj_t * Abc_SclFindMostCriticalFanin2( SC_Man * p, int * pfRise, Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pFanin, * pPivot = NULL; |
| float fMaxArr = 0; |
| int i; |
| Abc_ObjForEachFanin( pNode, pFanin, i ) |
| { |
| SC_Pair * pArr = Abc_SclObjTime( p, pFanin ); |
| if ( fMaxArr < pArr->rise ) fMaxArr = pArr->rise, *pfRise = 1, pPivot = pFanin; |
| if ( fMaxArr < pArr->fall ) fMaxArr = pArr->fall, *pfRise = 0, pPivot = pFanin; |
| } |
| return pPivot; |
| } |
| // assumes that slack are available |
| Abc_Obj_t * Abc_SclFindMostCriticalFanin( SC_Man * p, int * pfRise, Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pFanin, * pPivot = NULL; |
| float fMinSlack = ABC_INFINITY; |
| SC_Pair * pArr; |
| int i; |
| *pfRise = 0; |
| // find min-slack node |
| Abc_ObjForEachFanin( pNode, pFanin, i ) |
| if ( fMinSlack > Abc_SclObjGetSlack( p, pFanin, p->MaxDelay0 ) ) |
| { |
| fMinSlack = Abc_SclObjGetSlack( p, pFanin, p->MaxDelay0 ); |
| pPivot = pFanin; |
| } |
| if ( pPivot == NULL ) |
| return NULL; |
| // find its leading phase |
| pArr = Abc_SclObjTime( p, pPivot ); |
| *pfRise = (pArr->rise >= pArr->fall); |
| return pPivot; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Printing timing information for the node/network.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Abc_SclTimeNodePrint( SC_Man * p, Abc_Obj_t * pObj, int fRise, int Length, float maxDelay ) |
| { |
| SC_Cell * pCell = Abc_ObjIsNode(pObj) ? Abc_SclObjCell(pObj) : NULL; |
| printf( "%8d : ", Abc_ObjId(pObj) ); |
| printf( "%d ", Abc_ObjFaninNum(pObj) ); |
| printf( "%4d ", Abc_ObjFanoutNum(pObj) ); |
| printf( "%-*s ", Length, pCell ? pCell->pName : "pi" ); |
| printf( "A =%7.2f ", pCell ? pCell->area : 0.0 ); |
| printf( "D%s =", fRise ? "r" : "f" ); |
| printf( "%6.1f", Abc_SclObjTimeMax(p, pObj) ); |
| printf( "%7.1f ps ", -Abc_AbsFloat(Abc_SclObjTimeOne(p, pObj, 0) - Abc_SclObjTimeOne(p, pObj, 1)) ); |
| printf( "S =%6.1f ps ", Abc_SclObjSlewMax(p, pObj) ); |
| printf( "Cin =%5.1f ff ", pCell ? SC_CellPinCapAve(pCell) : 0.0 ); |
| printf( "Cout =%6.1f ff ", Abc_SclObjLoadMax(p, pObj) ); |
| printf( "Cmax =%6.1f ff ", pCell ? SC_CellPin(pCell, pCell->n_inputs)->max_out_cap : 0.0 ); |
| printf( "G =%5d ", pCell ? (int)(100.0 * Abc_SclObjLoadAve(p, pObj) / SC_CellPinCapAve(pCell)) : 0 ); |
| // printf( "SL =%6.1f ps", Abc_SclObjSlackMax(p, pObj, p->MaxDelay0) ); |
| printf( "\n" ); |
| } |
| void Abc_SclTimeNtkPrint( SC_Man * p, int fShowAll, int fPrintPath ) |
| { |
| int fReversePath = 1; |
| int i, nLength = 0, fRise = 0; |
| Abc_Obj_t * pObj, * pPivot = Abc_SclFindCriticalCo( p, &fRise ); |
| float maxDelay = Abc_SclObjTimeOne( p, pPivot, fRise ); |
| p->ReportDelay = maxDelay; |
| |
| #ifdef WIN32 |
| printf( "WireLoad = \"%s\" ", p->pWLoadUsed ? p->pWLoadUsed->pName : "none" ); |
| SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), 14 ); // yellow |
| printf( "Gates =%7d ", Abc_NtkNodeNum(p->pNtk) ); |
| SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), 7 ); // normal |
| printf( "(%5.1f %%) ", 100.0 * Abc_SclGetBufInvCount(p->pNtk) / Abc_NtkNodeNum(p->pNtk) ); |
| SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), 10 ); // green |
| printf( "Cap =%5.1f ff ", p->EstLoadAve ); |
| SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), 7 ); // normal |
| printf( "(%5.1f %%) ", Abc_SclGetAverageSize(p->pNtk) ); |
| SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), 11 ); // blue |
| printf( "Area =%12.2f ", Abc_SclGetTotalArea(p->pNtk) ); |
| SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), 7 ); // normal |
| printf( "(%5.1f %%) ", 100.0 * Abc_SclCountMinSize(p->pLib, p->pNtk, 0) / Abc_NtkNodeNum(p->pNtk) ); |
| SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), 13 ); // magenta |
| printf( "Delay =%9.2f ps ", maxDelay ); |
| SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), 7 ); // normal |
| printf( "(%5.1f %%) ", 100.0 * Abc_SclCountNearCriticalNodes(p) / Abc_NtkNodeNum(p->pNtk) ); |
| printf( " \n" ); |
| #else |
| Abc_Print( 1, "WireLoad = \"%s\" ", p->pWLoadUsed ? p->pWLoadUsed->pName : "none" ); |
| Abc_Print( 1, "%sGates =%7d%s ", "\033[1;33m", Abc_NtkNodeNum(p->pNtk), "\033[0m" ); // yellow |
| Abc_Print( 1, "(%5.1f %%) ", 100.0 * Abc_SclGetBufInvCount(p->pNtk) / Abc_NtkNodeNum(p->pNtk) ); |
| Abc_Print( 1, "%sCap =%5.1f ff%s ", "\033[1;32m", p->EstLoadAve, "\033[0m" ); // green |
| Abc_Print( 1, "(%5.1f %%) ", Abc_SclGetAverageSize(p->pNtk) ); |
| Abc_Print( 1, "%sArea =%12.2f%s ", "\033[1;36m", Abc_SclGetTotalArea(p->pNtk), "\033[0m" ); // blue |
| Abc_Print( 1, "(%5.1f %%) ", 100.0 * Abc_SclCountMinSize(p->pLib, p->pNtk, 0) / Abc_NtkNodeNum(p->pNtk) ); |
| Abc_Print( 1, "%sDelay =%9.2f ps%s ", "\033[1;35m", maxDelay, "\033[0m" ); // magenta |
| Abc_Print( 1, "(%5.1f %%) ", 100.0 * Abc_SclCountNearCriticalNodes(p) / Abc_NtkNodeNum(p->pNtk) ); |
| Abc_Print( 1, " \n" ); |
| #endif |
| |
| if ( fShowAll ) |
| { |
| // printf( "Timing information for all nodes: \n" ); |
| // find the longest cell name |
| Abc_NtkForEachNodeReverse( p->pNtk, pObj, i ) |
| if ( Abc_ObjFaninNum(pObj) > 0 ) |
| nLength = Abc_MaxInt( nLength, strlen(Abc_SclObjCell(pObj)->pName) ); |
| // print timing |
| Abc_NtkForEachNodeReverse( p->pNtk, pObj, i ) |
| if ( Abc_ObjFaninNum(pObj) > 0 ) |
| Abc_SclTimeNodePrint( p, pObj, -1, nLength, maxDelay ); |
| } |
| if ( fPrintPath ) |
| { |
| Abc_Obj_t * pTemp, * pPrev = NULL; |
| int iStart = -1, iEnd = -1; |
| Vec_Ptr_t * vPath; |
| // printf( "Critical path: \n" ); |
| // find the longest cell name |
| pObj = Abc_ObjFanin0(pPivot); |
| i = 0; |
| while ( pObj && Abc_ObjIsNode(pObj) ) |
| { |
| i++; |
| nLength = Abc_MaxInt( nLength, strlen(Abc_SclObjCell(pObj)->pName) ); |
| pObj = Abc_SclFindMostCriticalFanin( p, &fRise, pObj ); |
| } |
| |
| // print timing |
| if ( !fReversePath ) |
| { |
| // print timing |
| pObj = Abc_ObjFanin0(pPivot); |
| while ( pObj )//&& Abc_ObjIsNode(pObj) ) |
| { |
| printf( "Path%3d --", i-- ); |
| Abc_SclTimeNodePrint( p, pObj, fRise, nLength, maxDelay ); |
| pPrev = pObj; |
| pObj = Abc_SclFindMostCriticalFanin( p, &fRise, pObj ); |
| } |
| } |
| else |
| { |
| // collect path nodes |
| vPath = Vec_PtrAlloc( 100 ); |
| Vec_PtrPush( vPath, pPivot ); |
| pObj = Abc_ObjFanin0(pPivot); |
| while ( pObj )//&& Abc_ObjIsNode(pObj) ) |
| { |
| Vec_PtrPush( vPath, pObj ); |
| pPrev = pObj; |
| pObj = Abc_SclFindMostCriticalFanin( p, &fRise, pObj ); |
| } |
| Vec_PtrForEachEntryReverse( Abc_Obj_t *, vPath, pObj, i ) |
| { |
| printf( "Path%3d --", Vec_PtrSize(vPath)-1-i ); |
| Abc_SclTimeNodePrint( p, pObj, fRise, nLength, maxDelay ); |
| if ( i == 1 ) |
| break; |
| } |
| Vec_PtrFree( vPath ); |
| } |
| // print start-point and end-point |
| Abc_NtkForEachPi( p->pNtk, pTemp, iStart ) |
| if ( pTemp == pPrev ) |
| break; |
| Abc_NtkForEachPo( p->pNtk, pTemp, iEnd ) |
| if ( pTemp == pPivot ) |
| break; |
| printf( "Start-point = pi%0*d. End-point = po%0*d.\n", |
| Abc_Base10Log( Abc_NtkPiNum(p->pNtk) ), iStart, |
| Abc_Base10Log( Abc_NtkPoNum(p->pNtk) ), iEnd ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Timing computation for pin/gate/cone/network.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Abc_SclTimeFanin( SC_Man * p, SC_Timing * pTime, Abc_Obj_t * pObj, Abc_Obj_t * pFanin ) |
| { |
| SC_Pair * pArrIn = Abc_SclObjTime( p, pFanin ); |
| SC_Pair * pSlewIn = Abc_SclObjSlew( p, pFanin ); |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| SC_Pair * pArrOut = Abc_SclObjTime( p, pObj ); // modified |
| SC_Pair * pSlewOut = Abc_SclObjSlew( p, pObj ); // modified |
| Scl_LibPinArrival( pTime, pArrIn, pSlewIn, pLoad, pArrOut, pSlewOut ); |
| } |
| static inline void Abc_SclDeptFanin( SC_Man * p, SC_Timing * pTime, Abc_Obj_t * pObj, Abc_Obj_t * pFanin ) |
| { |
| SC_Pair * pDepIn = Abc_SclObjDept( p, pFanin ); // modified |
| SC_Pair * pSlewIn = Abc_SclObjSlew( p, pFanin ); |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| SC_Pair * pDepOut = Abc_SclObjDept( p, pObj ); |
| Scl_LibPinDeparture( pTime, pDepIn, pSlewIn, pLoad, pDepOut ); |
| } |
| static inline void Abc_SclDeptObj( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| SC_Timing * pTime; |
| Abc_Obj_t * pFanout; |
| int i; |
| SC_PairClean( Abc_SclObjDept(p, pObj) ); |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| { |
| if ( Abc_ObjIsCo(pFanout) || Abc_ObjIsLatch(pFanout) ) |
| continue; |
| pTime = Scl_CellPinTime( Abc_SclObjCell(pFanout), Abc_NodeFindFanin(pFanout, pObj) ); |
| Abc_SclDeptFanin( p, pTime, pFanout, pObj ); |
| } |
| } |
| static inline float Abc_SclObjLoadValue( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| // float Value = Abc_MaxFloat(pLoad->fall, pLoad->rise) / (p->EstLoadAve * p->EstLoadMax); |
| return (0.5 * Abc_SclObjLoad(p, pObj)->fall + 0.5 * Abc_SclObjLoad(p, pObj)->rise) / (p->EstLoadAve * p->EstLoadMax); |
| } |
| static inline void Abc_SclTimeCi( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| if ( p->pPiDrive != NULL ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| SC_Pair * pTime = Abc_SclObjTime( p, pObj ); |
| SC_Pair * pSlew = Abc_SclObjSlew( p, pObj ); |
| Scl_LibHandleInputDriver( p->pPiDrive, pLoad, pTime, pSlew ); |
| } |
| } |
| void Abc_SclTimeNode( SC_Man * p, Abc_Obj_t * pObj, int fDept ) |
| { |
| SC_Timing * pTime; |
| SC_Cell * pCell; |
| int k; |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| float LoadRise = pLoad->rise; |
| float LoadFall = pLoad->fall; |
| float DeptRise = 0; |
| float DeptFall = 0; |
| float Value = p->EstLoadMax ? Abc_SclObjLoadValue( p, pObj ) : 0; |
| Abc_Obj_t * pFanin; |
| if ( Abc_ObjIsCi(pObj) ) |
| { |
| assert( !fDept ); |
| Abc_SclTimeCi( p, pObj ); |
| return; |
| } |
| if ( Abc_ObjIsCo(pObj) ) |
| { |
| if ( !fDept ) |
| { |
| Abc_SclObjDupFanin( p, pObj ); |
| Vec_FltWriteEntry( p->vTimesOut, pObj->iData, Abc_SclObjTimeMax(p, pObj) ); |
| Vec_QueUpdate( p->vQue, pObj->iData ); |
| } |
| return; |
| } |
| assert( Abc_ObjIsNode(pObj) ); |
| // if ( !(Abc_ObjFaninNum(pObj) == 1 && Abc_ObjIsPi(Abc_ObjFanin0(pObj))) && p->EstLoadMax && Value > 1 ) |
| if ( p->EstLoadMax && Value > 1 ) |
| { |
| pLoad->rise = p->EstLoadAve * p->EstLoadMax; |
| pLoad->fall = p->EstLoadAve * p->EstLoadMax; |
| if ( fDept ) |
| { |
| SC_Pair * pDepOut = Abc_SclObjDept( p, pObj ); |
| float EstDelta = p->EstLinear * log( Value ); |
| DeptRise = pDepOut->rise; |
| DeptFall = pDepOut->fall; |
| pDepOut->rise += EstDelta; |
| pDepOut->fall += EstDelta; |
| } |
| p->nEstNodes++; |
| } |
| // get the library cell |
| pCell = Abc_SclObjCell( pObj ); |
| // compute for each fanin |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| { |
| pTime = Scl_CellPinTime( pCell, k ); |
| if ( fDept ) |
| Abc_SclDeptFanin( p, pTime, pObj, pFanin ); |
| else |
| Abc_SclTimeFanin( p, pTime, pObj, pFanin ); |
| } |
| if ( p->EstLoadMax && Value > 1 ) |
| { |
| pLoad->rise = LoadRise; |
| pLoad->fall = LoadFall; |
| if ( fDept ) |
| { |
| SC_Pair * pDepOut = Abc_SclObjDept( p, pObj ); |
| pDepOut->rise = DeptRise; |
| pDepOut->fall = DeptFall; |
| } |
| else |
| { |
| SC_Pair * pArrOut = Abc_SclObjTime( p, pObj ); |
| float EstDelta = p->EstLinear * log( Value ); |
| pArrOut->rise += EstDelta; |
| pArrOut->fall += EstDelta; |
| } |
| } |
| } |
| void Abc_SclTimeCone( SC_Man * p, Vec_Int_t * vCone ) |
| { |
| int fVerbose = 0; |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_SclConeClean( p, vCone ); |
| Abc_NtkForEachObjVec( vCone, p->pNtk, pObj, i ) |
| { |
| if ( fVerbose && Abc_ObjIsNode(pObj) ) |
| printf( " Updating node %d with gate %s\n", Abc_ObjId(pObj), Abc_SclObjCell(pObj)->pName ); |
| if ( fVerbose && Abc_ObjIsNode(pObj) ) |
| printf( " before (%6.1f ps %6.1f ps) ", Abc_SclObjTimeOne(p, pObj, 1), Abc_SclObjTimeOne(p, pObj, 0) ); |
| Abc_SclTimeNode( p, pObj, 0 ); |
| if ( fVerbose && Abc_ObjIsNode(pObj) ) |
| printf( "after (%6.1f ps %6.1f ps)\n", Abc_SclObjTimeOne(p, pObj, 1), Abc_SclObjTimeOne(p, pObj, 0) ); |
| } |
| } |
| void Abc_SclTimeNtkRecompute( SC_Man * p, float * pArea, float * pDelay, int fReverse, float DUser ) |
| { |
| Abc_Obj_t * pObj; |
| float D; |
| int i; |
| Abc_SclComputeLoad( p ); |
| Abc_SclManCleanTime( p ); |
| p->nEstNodes = 0; |
| Abc_NtkForEachCi( p->pNtk, pObj, i ) |
| Abc_SclTimeNode( p, pObj, 0 ); |
| Abc_NtkForEachNode1( p->pNtk, pObj, i ) |
| Abc_SclTimeNode( p, pObj, 0 ); |
| Abc_NtkForEachCo( p->pNtk, pObj, i ) |
| Abc_SclTimeNode( p, pObj, 0 ); |
| D = Abc_SclReadMaxDelay( p ); |
| if ( fReverse && DUser > 0 && D < DUser ) |
| D = DUser; |
| if ( pArea ) |
| *pArea = Abc_SclGetTotalArea(p->pNtk); |
| if ( pDelay ) |
| *pDelay = D; |
| if ( fReverse ) |
| { |
| p->nEstNodes = 0; |
| Abc_NtkForEachNodeReverse1( p->pNtk, pObj, i ) |
| Abc_SclTimeNode( p, pObj, 1 ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Incremental timing update.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Abc_SclTimeIncUpdateClean( SC_Man * p ) |
| { |
| Vec_Int_t * vLevel; |
| Abc_Obj_t * pObj; |
| int i, k; |
| Vec_WecForEachLevel( p->vLevels, vLevel, i ) |
| { |
| Abc_NtkForEachObjVec( vLevel, p->pNtk, pObj, k ) |
| { |
| assert( pObj->fMarkC == 1 ); |
| pObj->fMarkC = 0; |
| } |
| Vec_IntClear( vLevel ); |
| } |
| } |
| static inline void Abc_SclTimeIncAddNode( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| assert( !Abc_ObjIsLatch(pObj) ); |
| assert( pObj->fMarkC == 0 ); |
| pObj->fMarkC = 1; |
| Vec_IntPush( Vec_WecEntry(p->vLevels, Abc_ObjLevel(pObj)), Abc_ObjId(pObj) ); |
| p->nIncUpdates++; |
| } |
| static inline void Abc_SclTimeIncAddFanins( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanin; |
| int i; |
| Abc_ObjForEachFanin( pObj, pFanin, i ) |
| // if ( !pFanin->fMarkC && Abc_ObjIsNode(pFanin) ) |
| if ( !pFanin->fMarkC && !Abc_ObjIsLatch(pFanin) ) |
| Abc_SclTimeIncAddNode( p, pFanin ); |
| } |
| static inline void Abc_SclTimeIncAddFanouts( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| int i; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| if ( !pFanout->fMarkC && !Abc_ObjIsLatch(pFanout) ) |
| Abc_SclTimeIncAddNode( p, pFanout ); |
| } |
| static inline void Abc_SclTimeIncUpdateArrival( SC_Man * p ) |
| { |
| Vec_Int_t * vLevel; |
| SC_Pair ArrOut, SlewOut; |
| SC_Pair * pArrOut, *pSlewOut; |
| Abc_Obj_t * pObj; |
| float E = (float)0.1; |
| int i, k; |
| Vec_WecForEachLevel( p->vLevels, vLevel, i ) |
| { |
| Abc_NtkForEachObjVec( vLevel, p->pNtk, pObj, k ) |
| { |
| if ( Abc_ObjIsCo(pObj) ) |
| { |
| Abc_SclObjDupFanin( p, pObj ); |
| Vec_FltWriteEntry( p->vTimesOut, pObj->iData, Abc_SclObjTimeMax(p, pObj) ); |
| Vec_QueUpdate( p->vQue, pObj->iData ); |
| continue; |
| } |
| pArrOut = Abc_SclObjTime( p, pObj ); |
| pSlewOut = Abc_SclObjSlew( p, pObj ); |
| SC_PairMove( &ArrOut, pArrOut ); |
| SC_PairMove( &SlewOut, pSlewOut ); |
| Abc_SclTimeNode( p, pObj, 0 ); |
| // if ( !SC_PairEqual(&ArrOut, pArrOut) || !SC_PairEqual(&SlewOut, pSlewOut) ) |
| if ( !SC_PairEqualE(&ArrOut, pArrOut, E) || !SC_PairEqualE(&SlewOut, pSlewOut, E) ) |
| Abc_SclTimeIncAddFanouts( p, pObj ); |
| } |
| } |
| p->MaxDelay = Abc_SclReadMaxDelay( p ); |
| } |
| static inline void Abc_SclTimeIncUpdateDeparture( SC_Man * p ) |
| { |
| Vec_Int_t * vLevel; |
| SC_Pair DepOut, * pDepOut; |
| Abc_Obj_t * pObj; |
| float E = (float)0.1; |
| int i, k; |
| Vec_WecForEachLevelReverse( p->vLevels, vLevel, i ) |
| { |
| Abc_NtkForEachObjVec( vLevel, p->pNtk, pObj, k ) |
| { |
| pDepOut = Abc_SclObjDept( p, pObj ); |
| SC_PairMove( &DepOut, pDepOut ); |
| Abc_SclDeptObj( p, pObj ); |
| // if ( !SC_PairEqual(&DepOut, pDepOut) ) |
| if ( !SC_PairEqualE(&DepOut, pDepOut, E) ) |
| Abc_SclTimeIncAddFanins( p, pObj ); |
| } |
| } |
| p->MaxDelay = Abc_SclReadMaxDelay( p ); |
| } |
| void Abc_SclTimeIncCheckLevel( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| if ( (int)pObj->Level != Abc_ObjLevelNew(pObj) ) |
| printf( "Level of node %d is out of date!\n", i ); |
| } |
| int Abc_SclTimeIncUpdate( SC_Man * p ) |
| { |
| Abc_Obj_t * pObj; |
| int i, RetValue; |
| if ( Vec_IntSize(p->vChanged) == 0 ) |
| return 0; |
| // Abc_SclTimeIncCheckLevel( p->pNtk ); |
| Abc_NtkForEachObjVec( p->vChanged, p->pNtk, pObj, i ) |
| { |
| Abc_SclTimeIncAddFanins( p, pObj ); |
| if ( pObj->fMarkC ) |
| continue; |
| Abc_SclTimeIncAddNode( p, pObj ); |
| } |
| Vec_IntClear( p->vChanged ); |
| Abc_SclTimeIncUpdateArrival( p ); |
| Abc_SclTimeIncUpdateDeparture( p ); |
| Abc_SclTimeIncUpdateClean( p ); |
| RetValue = p->nIncUpdates; |
| p->nIncUpdates = 0; |
| return RetValue; |
| } |
| void Abc_SclTimeIncInsert( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| Vec_IntPush( p->vChanged, Abc_ObjId(pObj) ); |
| } |
| void Abc_SclTimeIncUpdateLevel_rec( Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| int i, LevelNew = Abc_ObjLevelNew(pObj); |
| if ( LevelNew == (int)pObj->Level && Abc_ObjIsNode(pObj) && Abc_ObjFaninNum(pObj) > 0 ) |
| return; |
| pObj->Level = LevelNew; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| Abc_SclTimeIncUpdateLevel_rec( pFanout ); |
| } |
| void Abc_SclTimeIncUpdateLevel( Abc_Obj_t * pObj ) |
| { |
| Abc_SclTimeIncUpdateLevel_rec( pObj ); |
| } |
| |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Read input slew and output load.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_SclManReadSlewAndLoad( SC_Man * p, Abc_Ntk_t * pNtk ) |
| { |
| if ( Abc_FrameReadMaxLoad() ) |
| { |
| Abc_Obj_t * pObj; int i; |
| float MaxLoad = Abc_FrameReadMaxLoad(); |
| // printf( "Default output load is specified (%.2f ff).\n", MaxLoad ); |
| Abc_NtkForEachPo( pNtk, pObj, i ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| pLoad->rise = pLoad->fall = MaxLoad; |
| } |
| } |
| if ( Abc_FrameReadDrivingCell() ) |
| { |
| int iCell = Abc_SclCellFind( p->pLib, Abc_FrameReadDrivingCell() ); |
| if ( iCell == -1 ) |
| printf( "Cannot find the default PI driving cell (%s) in the library.\n", Abc_FrameReadDrivingCell() ); |
| else |
| { |
| // printf( "Default PI driving cell is specified (%s).\n", Abc_FrameReadDrivingCell() ); |
| p->pPiDrive = SC_LibCell( p->pLib, iCell ); |
| assert( p->pPiDrive != NULL ); |
| assert( p->pPiDrive->n_inputs == 1 ); |
| } |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prepare timing manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| SC_Man * Abc_SclManStart( SC_Lib * pLib, Abc_Ntk_t * pNtk, int fUseWireLoads, int fDept, float DUser, int nTreeCRatio ) |
| { |
| SC_Man * p = Abc_SclManAlloc( pLib, pNtk ); |
| if ( nTreeCRatio ) |
| { |
| p->EstLoadMax = 0.01 * nTreeCRatio; // max ratio of Cout/Cave when the estimation is used |
| p->EstLinear = 100; // linear coefficient |
| } |
| Abc_SclMioGates2SclGates( pLib, pNtk ); |
| Abc_SclManReadSlewAndLoad( p, pNtk ); |
| if ( fUseWireLoads ) |
| { |
| if ( pNtk->pWLoadUsed == NULL ) |
| { |
| p->pWLoadUsed = Abc_SclFindWireLoadModel( pLib, Abc_SclGetTotalArea(p->pNtk) ); |
| if ( p->pWLoadUsed ) |
| pNtk->pWLoadUsed = Abc_UtilStrsav( p->pWLoadUsed->pName ); |
| } |
| else |
| p->pWLoadUsed = Abc_SclFetchWireLoadModel( pLib, pNtk->pWLoadUsed ); |
| } |
| Abc_SclTimeNtkRecompute( p, &p->SumArea0, &p->MaxDelay0, fDept, DUser ); |
| p->SumArea = p->SumArea0; |
| p->MaxDelay = p->MaxDelay0; |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Printing out timing information for the network.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_SclTimePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, int nTreeCRatio, int fUseWireLoads, int fShowAll, int fPrintPath, int fDumpStats ) |
| { |
| SC_Man * p; |
| p = Abc_SclManStart( pLib, pNtk, fUseWireLoads, 1, 0, nTreeCRatio ); |
| Abc_SclTimeNtkPrint( p, fShowAll, fPrintPath ); |
| if ( fDumpStats ) |
| Abc_SclDumpStats( p, "stats.txt", 0 ); |
| Abc_SclManFree( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_SclTimePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, int nTreeCRatio, int fUseWireLoads, int fShowAll, int fPrintPath, int fDumpStats ) |
| { |
| Abc_Ntk_t * pNtkNew = pNtk; |
| if ( pNtk->nBarBufs2 > 0 ) |
| pNtkNew = Abc_NtkDupDfsNoBarBufs( pNtk ); |
| Abc_SclTimePerformInt( pLib, pNtkNew, nTreeCRatio, fUseWireLoads, fShowAll, fPrintPath, fDumpStats ); |
| if ( pNtk->nBarBufs2 > 0 ) |
| Abc_NtkDelete( pNtkNew ); |
| } |
| |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Printing out fanin information.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_SclCheckCommonInputs( Abc_Obj_t * pObj, Abc_Obj_t * pFanin ) |
| { |
| Abc_Obj_t * pTemp; |
| int i; |
| Abc_ObjForEachFanin( pObj, pTemp, i ) |
| if ( Abc_NodeFindFanin( pFanin, pTemp ) >= 0 ) |
| { |
| printf( "Node %d and its fanin %d have common fanin %d.\n", Abc_ObjId(pObj), Abc_ObjId(pFanin), Abc_ObjId(pTemp) ); |
| |
| printf( "%-16s : ", Mio_GateReadName((Mio_Gate_t *)pObj->pData) ); |
| Abc_ObjPrint( stdout, pObj ); |
| |
| printf( "%-16s : ", Mio_GateReadName((Mio_Gate_t *)pFanin->pData) ); |
| Abc_ObjPrint( stdout, pFanin ); |
| |
| if ( pTemp->pData ) |
| printf( "%-16s : ", Mio_GateReadName((Mio_Gate_t *)pTemp->pData) ); |
| Abc_ObjPrint( stdout, pTemp ); |
| return 1; |
| } |
| return 0; |
| } |
| void Abc_SclPrintFaninPairs( SC_Man * p, Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj, * pFanin; |
| int i, k; |
| Abc_NtkForEachNode( pNtk, pObj, i ) |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| if ( Abc_ObjIsNode(pFanin) && Abc_ObjFanoutNum(pFanin) == 1 ) |
| Abc_SclCheckCommonInputs( pObj, pFanin ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Printing out buffer information.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Abc_ObjIsBuffer( Abc_Obj_t * pObj ) { return Abc_ObjIsNode(pObj) && Abc_ObjFaninNum(pObj) == 1; } |
| int Abc_SclHasBufferFanout( Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| int i; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| if ( Abc_ObjIsBuffer(pFanout) ) |
| return 1; |
| return 0; |
| } |
| int Abc_SclCountBufferFanoutsInt( Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| int i, Counter = 0; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| if ( Abc_ObjIsBuffer(pFanout) ) |
| Counter += Abc_SclCountBufferFanoutsInt( pFanout ); |
| return Counter + Abc_ObjIsBuffer(pObj); |
| } |
| int Abc_SclCountBufferFanouts( Abc_Obj_t * pObj ) |
| { |
| return Abc_SclCountBufferFanoutsInt(pObj) - Abc_ObjIsBuffer(pObj); |
| } |
| int Abc_SclCountNonBufferFanoutsInt( Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| int i, Counter = 0; |
| if ( !Abc_ObjIsBuffer(pObj) ) |
| return 1; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| Counter += Abc_SclCountNonBufferFanoutsInt( pFanout ); |
| return Counter; |
| } |
| int Abc_SclCountNonBufferFanouts( Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| int i, Counter = 0; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| Counter += Abc_SclCountNonBufferFanoutsInt( pFanout ); |
| return Counter; |
| } |
| float Abc_SclCountNonBufferDelayInt( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| float Delay = 0; |
| int i; |
| if ( !Abc_ObjIsBuffer(pObj) ) |
| return Abc_SclObjTimeMax(p, pObj); |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| Delay += Abc_SclCountNonBufferDelayInt( p, pFanout ); |
| return Delay; |
| } |
| float Abc_SclCountNonBufferDelay( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| float Delay = 0; |
| int i; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| Delay += Abc_SclCountNonBufferDelayInt( p, pFanout ); |
| return Delay; |
| } |
| float Abc_SclCountNonBufferLoadInt( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| float Load = 0; |
| int i; |
| if ( !Abc_ObjIsBuffer(pObj) ) |
| return 0; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| Load += Abc_SclCountNonBufferLoadInt( p, pFanout ); |
| Load += 0.5 * Abc_SclObjLoad(p, pObj)->rise + 0.5 * Abc_SclObjLoad(p, pObj)->fall; |
| Load -= 0.5 * SC_CellPin(Abc_SclObjCell(pObj), 0)->rise_cap + 0.5 * SC_CellPin(Abc_SclObjCell(pObj), 0)->fall_cap; |
| return Load; |
| } |
| float Abc_SclCountNonBufferLoad( SC_Man * p, Abc_Obj_t * pObj ) |
| { |
| Abc_Obj_t * pFanout; |
| float Load = 0; |
| int i; |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| Load += Abc_SclCountNonBufferLoadInt( p, pFanout ); |
| Load += 0.5 * Abc_SclObjLoad(p, pObj)->rise + 0.5 * Abc_SclObjLoad(p, pObj)->fall; |
| return Load; |
| } |
| void Abc_SclPrintBuffersOne( SC_Man * p, Abc_Obj_t * pObj, int nOffset ) |
| { |
| int i; |
| for ( i = 0; i < nOffset; i++ ) |
| printf( " " ); |
| printf( "%6d: %-16s (%2d:%3d:%3d) ", |
| Abc_ObjId(pObj), |
| Abc_ObjIsPi(pObj) ? "pi" : Mio_GateReadName((Mio_Gate_t *)pObj->pData), |
| Abc_ObjFanoutNum(pObj), |
| Abc_SclCountBufferFanouts(pObj), |
| Abc_SclCountNonBufferFanouts(pObj) ); |
| for ( ; i < 4; i++ ) |
| printf( " " ); |
| printf( "a =%5.2f ", Abc_ObjIsPi(pObj) ? 0 : Abc_SclObjCell(pObj)->area ); |
| printf( "d = (" ); |
| printf( "%6.0f ps; ", Abc_SclObjTimeOne(p, pObj, 1) ); |
| printf( "%6.0f ps) ", Abc_SclObjTimeOne(p, pObj, 0) ); |
| printf( "l =%5.0f ff ", Abc_SclObjLoadMax(p, pObj) ); |
| printf( "s =%5.0f ps ", Abc_SclObjSlewMax(p, pObj) ); |
| printf( "sl =%5.0f ps ", Abc_SclObjSlackMax(p, pObj, p->MaxDelay0) ); |
| if ( nOffset == 0 ) |
| { |
| printf( "L =%5.0f ff ", Abc_SclCountNonBufferLoad(p, pObj) ); |
| printf( "Lx =%5.0f ff ", 100.0*Abc_SclCountNonBufferLoad(p, pObj)/p->EstLoadAve ); |
| printf( "Dx =%5.0f ps ", Abc_SclCountNonBufferDelay(p, pObj)/Abc_SclCountNonBufferFanouts(pObj) - Abc_SclObjTimeOne(p, pObj, 1) ); |
| printf( "Cx =%5.0f ps", (Abc_SclCountNonBufferDelay(p, pObj)/Abc_SclCountNonBufferFanouts(pObj) - Abc_SclObjTimeOne(p, pObj, 1))/log(Abc_SclCountNonBufferLoad(p, pObj)/p->EstLoadAve) ); |
| } |
| printf( "\n" ); |
| } |
| void Abc_SclPrintBuffersInt( SC_Man * p, Abc_Obj_t * pObj, int nOffset ) |
| { |
| Abc_Obj_t * pFanout; |
| int i; |
| Abc_SclPrintBuffersOne( p, pObj, nOffset ); |
| assert( Abc_ObjIsBuffer(pObj) ); |
| Abc_ObjForEachFanout( pObj, pFanout, i ) |
| if ( Abc_ObjIsBuffer(pFanout) ) |
| Abc_SclPrintBuffersInt( p, pFanout, nOffset + 1 ); |
| } |
| void Abc_SclPrintBufferTrees( SC_Man * p, Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj, * pFanout; |
| int i, k; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| { |
| if ( !Abc_ObjIsBuffer(pObj) && Abc_SclCountBufferFanouts(pObj) > 3 ) |
| { |
| Abc_SclPrintBuffersOne( p, pObj, 0 ); |
| Abc_ObjForEachFanout( pObj, pFanout, k ) |
| if ( Abc_ObjIsBuffer(pFanout) ) |
| Abc_SclPrintBuffersInt( p, pFanout, 1 ); |
| printf( "\n" ); |
| } |
| } |
| } |
| void Abc_SclPrintBuffers( SC_Lib * pLib, Abc_Ntk_t * pNtk, int fVerbose ) |
| { |
| int fUseWireLoads = 0; |
| SC_Man * p; |
| assert( Abc_NtkIsMappedLogic(pNtk) ); |
| p = Abc_SclManStart( pLib, pNtk, fUseWireLoads, 1, 0, 10000 ); |
| Abc_SclPrintBufferTrees( p, pNtk ); |
| // Abc_SclPrintFaninPairs( p, pNtk ); |
| Abc_SclManFree( p ); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |