| /**CFile**************************************************************** |
| |
| FileName [sclLoad.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Standard-cell library representation.] |
| |
| Synopsis [Wire/gate load computations.] |
| |
| Author [Alan Mishchenko, Niklas Een] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - August 24, 2012.] |
| |
| Revision [$Id: sclLoad.c,v 1.0 2012/08/24 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "sclSize.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns estimated wire capacitances for each fanout count.] |
| |
| Description [] |
| |
| SideEffects []` |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Flt_t * Abc_SclFindWireCaps( SC_WireLoad * pWL, int nFanoutMax ) |
| { |
| Vec_Flt_t * vCaps = NULL; |
| float EntryPrev, EntryCur, Slope; |
| int i, iPrev, k, Entry, EntryMax; |
| assert( pWL != NULL ); |
| // find the biggest fanout count |
| EntryMax = 0; |
| Vec_IntForEachEntry( &pWL->vFanout, Entry, i ) |
| EntryMax = Abc_MaxInt( EntryMax, Entry ); |
| // create the array |
| vCaps = Vec_FltStart( Abc_MaxInt(nFanoutMax, EntryMax) + 1 ); |
| Vec_IntForEachEntry( &pWL->vFanout, Entry, i ) |
| Vec_FltWriteEntry( vCaps, Entry, Vec_FltEntry(&pWL->vLen, i) * pWL->cap ); |
| if ( Vec_FltEntry(vCaps, 1) == 0 ) |
| return vCaps; |
| // interpolate between the values |
| assert( Vec_FltEntry(vCaps, 1) != 0 ); |
| iPrev = 1; |
| EntryPrev = Vec_FltEntry(vCaps, 1); |
| Vec_FltForEachEntryStart( vCaps, EntryCur, i, 2 ) |
| { |
| if ( EntryCur == 0 ) |
| continue; |
| Slope = (EntryCur - EntryPrev) / (i - iPrev); |
| for ( k = iPrev + 1; k < i; k++ ) |
| Vec_FltWriteEntry( vCaps, k, EntryPrev + Slope * (k - iPrev) ); |
| EntryPrev = EntryCur; |
| iPrev = i; |
| } |
| // extrapolate after the largest value |
| Slope = pWL->cap * pWL->slope; |
| for ( k = iPrev + 1; k < i; k++ ) |
| Vec_FltWriteEntry( vCaps, k, EntryPrev + Slope * (k - iPrev) ); |
| // show |
| // Vec_FltForEachEntry( vCaps, EntryCur, i ) |
| // printf( "%3d : %f\n", i, EntryCur ); |
| return vCaps; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes load for all nodes in the network.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| float Abc_SclFindWireLoad( Vec_Flt_t * vWireCaps, int nFans ) |
| { |
| if ( vWireCaps == NULL ) |
| return 0; |
| return Vec_FltEntry( vWireCaps, Abc_MinInt(nFans, Vec_FltSize(vWireCaps)-1) ); |
| } |
| void Abc_SclAddWireLoad( SC_Man * p, Abc_Obj_t * pObj, int fSubtr ) |
| { |
| float Load = Abc_SclFindWireLoad( p->vWireCaps, Abc_ObjFanoutNum(pObj) ); |
| Abc_SclObjLoad(p, pObj)->rise += fSubtr ? -Load : Load; |
| Abc_SclObjLoad(p, pObj)->fall += fSubtr ? -Load : Load; |
| } |
| void Abc_SclComputeLoad( SC_Man * p ) |
| { |
| Abc_Obj_t * pObj, * pFanin; |
| int i, k; |
| // clear load storage |
| Abc_NtkForEachObj( p->pNtk, pObj, i ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| if ( !Abc_ObjIsPo(pObj) ) |
| pLoad->rise = pLoad->fall = 0.0; |
| } |
| // add cell load |
| Abc_NtkForEachNode1( p->pNtk, pObj, i ) |
| { |
| SC_Cell * pCell = Abc_SclObjCell( pObj ); |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pFanin ); |
| SC_Pin * pPin = SC_CellPin( pCell, k ); |
| pLoad->rise += pPin->rise_cap; |
| pLoad->fall += pPin->fall_cap; |
| } |
| } |
| // add PO load |
| Abc_NtkForEachCo( p->pNtk, pObj, i ) |
| { |
| SC_Pair * pLoadPo = Abc_SclObjLoad( p, pObj ); |
| SC_Pair * pLoad = Abc_SclObjLoad( p, Abc_ObjFanin0(pObj) ); |
| pLoad->rise += pLoadPo->rise; |
| pLoad->fall += pLoadPo->fall; |
| } |
| // add wire load |
| if ( p->pWLoadUsed != NULL ) |
| { |
| if ( p->vWireCaps == NULL ) |
| p->vWireCaps = Abc_SclFindWireCaps( p->pWLoadUsed, Abc_NtkGetFanoutMax(p->pNtk) ); |
| Abc_NtkForEachNode1( p->pNtk, pObj, i ) |
| Abc_SclAddWireLoad( p, pObj, 0 ); |
| Abc_NtkForEachPi( p->pNtk, pObj, i ) |
| Abc_SclAddWireLoad( p, pObj, 0 ); |
| } |
| // check input loads |
| if ( p->vInDrive != NULL ) |
| { |
| Abc_NtkForEachPi( p->pNtk, pObj, i ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| if ( Abc_SclObjInDrive(p, pObj) != 0 && (pLoad->rise > Abc_SclObjInDrive(p, pObj) || pLoad->fall > Abc_SclObjInDrive(p, pObj)) ) |
| printf( "Maximum input drive strength is exceeded at primary input %d.\n", i ); |
| } |
| } |
| /* |
| // transfer load from barbufs |
| Abc_NtkForEachBarBuf( p->pNtk, pObj, i ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| SC_Pair * pLoadF = Abc_SclObjLoad( p, Abc_ObjFanin(pObj, 0) ); |
| SC_PairAdd( pLoadF, pLoad ); |
| } |
| */ |
| // calculate average load |
| // if ( p->EstLoadMax ) |
| { |
| double TotalLoad = 0; |
| int nObjs = 0; |
| Abc_NtkForEachNode1( p->pNtk, pObj, i ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| TotalLoad += 0.5 * pLoad->fall + 0.5 * pLoad->rise; |
| nObjs++; |
| } |
| Abc_NtkForEachPi( p->pNtk, pObj, i ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); |
| TotalLoad += 0.5 * pLoad->fall + 0.5 * pLoad->rise; |
| nObjs++; |
| } |
| p->EstLoadAve = (float)(TotalLoad / nObjs); |
| // printf( "Average load = %.2f\n", p->EstLoadAve ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Updates load of the node's fanins.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_SclUpdateLoad( SC_Man * p, Abc_Obj_t * pObj, SC_Cell * pOld, SC_Cell * pNew ) |
| { |
| Abc_Obj_t * pFanin; |
| int k; |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| { |
| SC_Pair * pLoad = Abc_SclObjLoad( p, pFanin ); |
| SC_Pin * pPinOld = SC_CellPin( pOld, k ); |
| SC_Pin * pPinNew = SC_CellPin( pNew, k ); |
| pLoad->rise += pPinNew->rise_cap - pPinOld->rise_cap; |
| pLoad->fall += pPinNew->fall_cap - pPinOld->fall_cap; |
| } |
| } |
| void Abc_SclUpdateLoadSplit( SC_Man * p, Abc_Obj_t * pBuffer, Abc_Obj_t * pFanout ) |
| { |
| SC_Pin * pPin; |
| SC_Pair * pLoad; |
| int iFanin = Abc_NodeFindFanin( pFanout, pBuffer ); |
| assert( iFanin >= 0 ); |
| assert( Abc_ObjFaninNum(pBuffer) == 1 ); |
| pPin = SC_CellPin( Abc_SclObjCell(pFanout), iFanin ); |
| // update load of the buffer |
| pLoad = Abc_SclObjLoad( p, pBuffer ); |
| pLoad->rise -= pPin->rise_cap; |
| pLoad->fall -= pPin->fall_cap; |
| // update load of the fanin |
| pLoad = Abc_SclObjLoad( p, Abc_ObjFanin0(pBuffer) ); |
| pLoad->rise += pPin->rise_cap; |
| pLoad->fall += pPin->fall_cap; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |