/**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" 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; 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; } 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_SclObjSlack( p, pFanin ) ) { fMinSlack = Abc_SclObjSlack( p, pFanin ); 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(p, pObj) : NULL; printf( "%6d : ", Abc_ObjId(pObj) ); printf( "%d ", Abc_ObjFaninNum(pObj) ); printf( "%2d ", 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( "%5.0f ", Abc_MaxFloat(Abc_SclObjTimePs(p, pObj, 0), Abc_SclObjTimePs(p, pObj, 1)) ); printf( "%4.0f ps ", -Abc_AbsFloat(Abc_SclObjTimePs(p, pObj, 0) - Abc_SclObjTimePs(p, pObj, 1)) ); printf( "S =%5.0f ps ", Abc_SclObjSlewPs(p, pObj, fRise >= 0 ? fRise : 0 ) ); printf( "Cin =%4.0f ff ", pCell ? Abc_SclGatePinCapAve(p->pLib, pCell) : 0.0 ); printf( "Cout =%5.0f ff ", Abc_SclObjLoadFf(p, pObj, fRise >= 0 ? fRise : 0 ) ); printf( "Cmax =%5.0f ff ", pCell ? SC_CellPin(pCell, pCell->n_inputs)->max_out_cap : 0.0 ); printf( "G =%4.1f ", pCell ? Abc_SclObjLoadAve(p, pObj) / SC_CellPinCap(pCell, 0) : 0.0 ); printf( "SL =%5.1f ps", Abc_SclObjSlack(p, pObj) ); printf( "\n" ); } void Abc_SclTimeNtkPrint( SC_Man * p, int fShowAll, int fPrintPath ) { int i, nLength = 0, fRise = 0; Abc_Obj_t * pObj, * pPivot = Abc_SclFindCriticalCo( p, &fRise ); float maxDelay = Abc_SclObjTimePs(p, pPivot, fRise); p->ReportDelay = maxDelay; printf( "WireLoad model = \"%s\". ", p->pWLoadUsed ? p->pWLoadUsed->pName : "none" ); printf( "Gates = %6d. ", Abc_NtkNodeNum(p->pNtk) ); printf( "Area = %12.2f. ", Abc_SclGetTotalArea( p ) ); printf( "Critical delay = %8.2f ps\n", maxDelay ); if ( !fPrintPath ) return; 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(p, pObj)->pName) ); // print timing Abc_NtkForEachNodeReverse( p->pNtk, pObj, i ) if ( Abc_ObjFaninNum(pObj) > 0 ) Abc_SclTimeNodePrint( p, pObj, -1, nLength, maxDelay ); } else { // 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(p, pObj)->pName) ); pObj = Abc_SclFindMostCriticalFanin( p, &fRise, pObj ); } // print timing pObj = Abc_ObjFanin0(pPivot); while ( pObj )//&& Abc_ObjIsNode(pObj) ) { printf( "Path%3d -- ", i-- ); Abc_SclTimeNodePrint( p, pObj, fRise, nLength, maxDelay ); pObj = Abc_SclFindMostCriticalFanin( p, &fRise, pObj ); } } } /**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 ); } void Abc_SclTimeNode( SC_Man * p, Abc_Obj_t * pObj, int fDept ) { SC_Timings * pRTime; SC_Timing * pTime; SC_Pin * pPin; SC_Cell * pCell; int k; if ( Abc_ObjIsCo(pObj) ) { if ( !fDept ) Abc_SclObjDupFanin( p, pObj ); return; } assert( Abc_ObjIsNode(pObj) ); // get the library cell pCell = Abc_SclObjCell( p, pObj ); // get the output pin // assert( pCell->n_outputs == 1 ); pPin = SC_CellPin( pCell, pCell->n_inputs ); // compute timing using each fanin assert( Vec_PtrSize(pPin->vRTimings) == pCell->n_inputs ); SC_PinForEachRTiming( pPin, pRTime, k ) { assert( Vec_PtrSize(pRTime->vTimings) == 1 ); pTime = (SC_Timing *)Vec_PtrEntry( pRTime->vTimings, 0 ); if ( fDept ) Abc_SclDeptFanin( p, pTime, pObj, Abc_ObjFanin(pObj, k) ); else Abc_SclTimeFanin( p, pTime, pObj, Abc_ObjFanin(pObj, k) ); } } void Abc_SclTimeCone( SC_Man * p, Vec_Int_t * vCone ) { int fVerbose = 0; Abc_Obj_t * pObj; int i; Abc_SclConeClear( 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(p, pObj)->pName ); if ( fVerbose && Abc_ObjIsNode(pObj) ) printf( " before (%6.1f ps %6.1f ps) ", Abc_SclObjTimePs(p, pObj, 1), Abc_SclObjTimePs(p, pObj, 0) ); Abc_SclTimeNode( p, pObj, 0 ); if ( fVerbose && Abc_ObjIsNode(pObj) ) printf( "after (%6.1f ps %6.1f ps)\n", Abc_SclObjTimePs(p, pObj, 1), Abc_SclObjTimePs(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 ); Abc_NtkForEachNode1( p->pNtk, pObj, i ) Abc_SclTimeNode( p, pObj, 0 ); Abc_NtkForEachCo( p->pNtk, pObj, i ) { Abc_SclObjDupFanin( p, pObj ); Vec_FltWriteEntry( p->vTimesOut, i, Abc_SclObjTimeMax(p, pObj) ); Vec_QueUpdate( p->vQue, i ); } D = Abc_SclReadMaxDelay( p ); if ( fReverse && DUser > 0 && D < DUser ) D = DUser; if ( pArea ) *pArea = Abc_SclGetTotalArea( p ); if ( pDelay ) *pDelay = D; if ( fReverse ) { Abc_NtkForEachNodeReverse1( p->pNtk, pObj, i ) Abc_SclTimeNode( p, pObj, 1 ); Abc_NtkForEachObj( p->pNtk, pObj, i ) p->pSlack[i] = Abc_MaxFloat( 0.0, Abc_SclObjGetSlack(p, pObj, D) ); } } /**Function************************************************************* Synopsis [Read input slew and output load.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_SclManReadSlewAndLoad( SC_Man * p, Abc_Ntk_t * pNtk ) { Abc_Time_t * pTime; Abc_Obj_t * pObj; int i; if ( pNtk->pManTime == NULL ) return; // read input slew pTime = Abc_NtkReadDefaultInputDrive( pNtk ); if ( Abc_MaxFloat(pTime->Rise, pTime->Fall) != 0 ) { printf( "Default input slew is specified (%.2f ps; %.2f ps).\n", pTime->Rise, pTime->Fall ); Abc_NtkForEachPi( pNtk, pObj, i ) { SC_Pair * pSlew = Abc_SclObjSlew( p, pObj ); pSlew->rise = SC_LibTimeFromPs( p->pLib, pTime->Rise ); pSlew->fall = SC_LibTimeFromPs( p->pLib, pTime->Fall ); } } if ( Abc_NodeReadInputDrive(pNtk, 0) != NULL ) { printf( "Input slews for some primary inputs are specified.\n" ); Abc_NtkForEachPi( pNtk, pObj, i ) { SC_Pair * pSlew = Abc_SclObjSlew( p, pObj ); pTime = Abc_NodeReadInputDrive(pNtk, i); pSlew->rise = SC_LibTimeFromPs( p->pLib, pTime->Rise ); pSlew->fall = SC_LibTimeFromPs( p->pLib, pTime->Fall ); } } // read output load pTime = Abc_NtkReadDefaultOutputLoad( pNtk ); if ( Abc_MaxFloat(pTime->Rise, pTime->Fall) != 0 ) { printf( "Default output load is specified (%.2f ff; %.2f ff).\n", pTime->Rise, pTime->Fall ); Abc_NtkForEachPo( pNtk, pObj, i ) { SC_Pair * pSlew = Abc_SclObjLoad( p, pObj ); pSlew->rise = SC_LibCapFromFf( p->pLib, pTime->Rise ); pSlew->fall = SC_LibCapFromFf( p->pLib, pTime->Fall ); } } if ( Abc_NodeReadOutputLoad(pNtk, 0) != NULL ) { printf( "Output loads for some primary outputs are specified.\n" ); Abc_NtkForEachPo( pNtk, pObj, i ) { SC_Pair * pSlew = Abc_SclObjLoad( p, pObj ); pTime = Abc_NodeReadOutputLoad(pNtk, i); pSlew->rise = SC_LibCapFromFf( p->pLib, pTime->Rise ); pSlew->fall = SC_LibCapFromFf( p->pLib, pTime->Fall ); } } } /**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 ) { SC_Man * p = Abc_SclManAlloc( pLib, pNtk ); assert( p->vGates == NULL ); p->vGates = Abc_SclManFindGates( pLib, pNtk ); Abc_SclManReadSlewAndLoad( p, pNtk ); if ( fUseWireLoads ) p->pWLoadUsed = Abc_SclFindWireLoadModel( pLib, Abc_SclGetTotalArea(p) ); Abc_SclTimeNtkRecompute( p, &p->SumArea0, &p->MaxDelay0, fDept, DUser ); p->SumArea = p->SumArea0; return p; } /**Function************************************************************* Synopsis [Printing out timing information for the network.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_SclTimePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, int fUseWireLoads, int fShowAll, int fPrintPath, int fDumpStats ) { SC_Man * p; p = Abc_SclManStart( pLib, pNtk, fUseWireLoads, 1, 0 ); Abc_SclTimeNtkPrint( p, fShowAll, fPrintPath ); if ( fDumpStats ) Abc_SclDumpStats( p, "stats.txt", 0 ); Abc_SclManFree( p ); } /**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_SclCountNonBufferFanouts( 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_SclCountNonBufferFanouts( pFanout ); return Counter; } 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; } void Abc_SclPrintBuffersInt( SC_Man * p, Abc_Obj_t * pObj, int nOffset ) { // SC_Cell_t * pCell = Abc_SclObjCell(p, pObj); Abc_Obj_t * pFanout; int i; assert( Abc_ObjIsBuffer(pObj) ); for ( i = 0; i < nOffset; i++ ) printf( " " ); printf( "%6d: %-16s (%2d:%3d) ", Abc_ObjId(pObj), Mio_GateReadName((Mio_Gate_t *)pObj->pData), Abc_ObjFanoutNum(pObj), Abc_SclCountNonBufferFanouts(pObj) ); for ( ; i < 4; i++ ) printf( " " ); printf( "a =%5.2f ", Abc_SclObjCell(p, pObj)->area ); printf( "d = (" ); printf( "%7.2f ps; ", Abc_SclObjTimePs(p, pObj, 1) ); printf( "%7.2f ps) ", Abc_SclObjTimePs(p, pObj, 0) ); printf( "l =%6.2f ff ", Abc_SclObjLoadFf(p, pObj, 0 ) ); printf( "s =%6.2f ps ", Abc_SclObjSlewPs(p, pObj, 0 ) ); printf( "sl =%6.2f ps", Abc_SclObjSlack(p, pObj) ); printf( "\n" ); 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; int i; Abc_NtkForEachObj( pNtk, pObj, i ) if ( Abc_ObjIsBuffer(pObj) && Abc_SclHasBufferFanout(pObj) ) Abc_SclPrintBuffersInt( p, pObj, 0 ), 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 ); Abc_SclPrintBufferTrees( p, pNtk ); // Abc_SclPrintFaninPairs( p, pNtk ); Abc_SclManFree( p ); } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END