/**CFile**************************************************************** FileName [sclDnsize.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Standard-cell library representation.] Synopsis [Selective decrease of gate sizes.] Author [Alan Mishchenko, Niklas Een] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - August 24, 2012.] Revision [$Id: sclDnsize.c,v 1.0 2012/08/24 00:00:00 alanmi Exp $] ***********************************************************************/ #include "sclSize.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Find the array of nodes to be updated.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_SclFindWindow( Abc_Obj_t * pPivot, Vec_Int_t ** pvNodes, Vec_Int_t ** pvEvals ) { Abc_Ntk_t * p = Abc_ObjNtk(pPivot); Abc_Obj_t * pObj, * pNext, * pNext2; Vec_Int_t * vNodes = *pvNodes; Vec_Int_t * vEvals = *pvEvals; int i, k; assert( Abc_ObjIsNode(pPivot) ); // collect fanins, node, and fanouts Vec_IntClear( vNodes ); Abc_ObjForEachFanin( pPivot, pNext, i ) // if ( Abc_ObjIsNode(pNext) && Abc_ObjFaninNum(pNext) > 0 ) if ( Abc_ObjIsCi(pNext) || Abc_ObjFaninNum(pNext) > 0 ) Vec_IntPush( vNodes, Abc_ObjId(pNext) ); Vec_IntPush( vNodes, Abc_ObjId(pPivot) ); Abc_ObjForEachFanout( pPivot, pNext, i ) if ( Abc_ObjIsNode(pNext) ) { Vec_IntPush( vNodes, Abc_ObjId(pNext) ); Abc_ObjForEachFanout( pNext, pNext2, k ) if ( Abc_ObjIsNode(pNext2) ) Vec_IntPush( vNodes, Abc_ObjId(pNext2) ); } Vec_IntUniqify( vNodes ); // label nodes Abc_NtkForEachObjVec( vNodes, p, pObj, i ) { assert( pObj->fMarkB == 0 ); pObj->fMarkB = 1; } // collect nodes visible from the critical paths Vec_IntClear( vEvals ); Abc_NtkForEachObjVec( vNodes, p, pObj, i ) Abc_ObjForEachFanout( pObj, pNext, k ) if ( !pNext->fMarkB ) { assert( pObj->fMarkB ); Vec_IntPush( vEvals, Abc_ObjId(pObj) ); break; } assert( Vec_IntSize(vEvals) > 0 ); // label nodes Abc_NtkForEachObjVec( vNodes, p, pObj, i ) pObj->fMarkB = 0; } /**Function************************************************************* Synopsis [Returns 1 if the node can be improved.] Description [Updated the node to have a new gate.] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_SclCheckImprovement( SC_Man * p, Abc_Obj_t * pObj, Vec_Int_t * vNodes, Vec_Int_t * vEvals, int Notches, int DelayGap ) { Abc_Obj_t * pTemp; SC_Cell * pCellOld, * pCellNew; float dGain, dGainBest; int i, k, gateBest; abctime clk; clk = Abc_Clock(); // printf( "%d -> %d\n", Vec_IntSize(vNodes), Vec_IntSize(vEvals) ); // save old gate, timing, fanin load pCellOld = Abc_SclObjCell( pObj ); Abc_SclConeStore( p, vNodes ); Abc_SclEvalStore( p, vEvals ); Abc_SclLoadStore( p, pObj ); // try different gate sizes for this node gateBest = -1; dGainBest = -DelayGap; SC_RingForEachCellRev( pCellOld, pCellNew, i ) { if ( pCellNew->area >= pCellOld->area ) continue; if ( i > Notches ) break; // set new cell Abc_SclObjSetCell( pObj, pCellNew ); Abc_SclUpdateLoad( p, pObj, pCellOld, pCellNew ); // recompute timing Abc_SclTimeCone( p, vNodes ); // set old cell Abc_SclObjSetCell( pObj, pCellOld ); Abc_SclLoadRestore( p, pObj ); // evaluate gain dGain = Abc_SclEvalPerformLegal( p, vEvals, p->MaxDelay0 ); if ( dGain == -1 ) continue; // save best gain if ( dGainBest < dGain ) { dGainBest = dGain; gateBest = pCellNew->Id; } } // put back old cell and timing Abc_SclObjSetCell( pObj, pCellOld ); Abc_SclConeRestore( p, vNodes ); p->timeSize += Abc_Clock() - clk; if ( gateBest >= 0 ) { pCellNew = SC_LibCell( p->pLib, gateBest ); Abc_SclObjSetCell( pObj, pCellNew ); p->SumArea += pCellNew->area - pCellOld->area; // printf( "%f %f -> %f\n", pCellNew->area - pCellOld->area, p->SumArea - (pCellNew->area - pCellOld->area), p->SumArea ); // printf( "%6d %20s -> %20s %f -> %f\n", Abc_ObjId(pObj), pCellOld->pName, pCellNew->pName, pCellOld->area, pCellNew->area ); // mark used nodes with the current trav ID Abc_NtkForEachObjVec( vNodes, p->pNtk, pTemp, k ) Abc_NodeSetTravIdCurrent( pTemp ); // update load and timing... Abc_SclUpdateLoad( p, pObj, pCellOld, pCellNew ); Abc_SclTimeIncInsert( p, pObj ); return 1; } return 0; } /**Function************************************************************* Synopsis [Collect nodes by area.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkCollectNodesByArea( SC_Man * p, Abc_Ntk_t * pNtk ) { Abc_Obj_t * pObj; int i; assert( Vec_QueSize(p->vNodeByGain) == 0 ); Vec_QueClear( p->vNodeByGain ); Abc_NtkForEachNode( pNtk, pObj, i ) if ( Abc_ObjFaninNum(pObj) > 0 ) { Vec_FltWriteEntry( p->vNode2Gain, Abc_ObjId(pObj), Abc_SclObjCell(pObj)->area ); Vec_QuePush( p->vNodeByGain, Abc_ObjId(pObj) ); } } int Abc_SclCheckOverlap( Abc_Ntk_t * pNtk, Vec_Int_t * vNodes ) { Abc_Obj_t * pObj; int i; Abc_NtkForEachObjVec( vNodes, pNtk, pObj, i ) if ( Abc_NodeIsTravIdCurrent(pObj) ) return 1; return 0; } /**Function************************************************************* Synopsis [Print cumulative statistics.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_SclDnsizePrint( SC_Man * p, int Iter, int nAttempts, int nOverlaps, int nChanges, int fVerbose ) { if ( Iter == -1 ) printf( "Total : " ); else printf( "%5d : ", Iter ); printf( "Try =%6d ", nAttempts ); printf( "Over =%6d ", nOverlaps ); printf( "Fail =%6d ", nAttempts-nOverlaps-nChanges ); printf( "Win =%6d ", nChanges ); printf( "A: " ); printf( "%.2f ", p->SumArea ); printf( "(%+5.1f %%) ", 100.0 * (p->SumArea - p->SumArea0)/ p->SumArea0 ); printf( "D: " ); printf( "%.2f ps ", p->MaxDelay ); printf( "(%+5.1f %%) ", 100.0 * (p->MaxDelay - p->MaxDelay0)/ p->MaxDelay0 ); printf( "%8.2f sec ", 1.0*(Abc_Clock() - p->timeTotal)/(CLOCKS_PER_SEC) ); printf( "%c", fVerbose ? '\n' : '\r' ); } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_SclDnsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars ) { SC_Man * p; Abc_Obj_t * pObj; Vec_Int_t * vNodes, * vEvals, * vTryLater; abctime clk, nRuntimeLimit = pPars->TimeOut ? pPars->TimeOut * CLOCKS_PER_SEC + Abc_Clock() : 0; int i, k; if ( pPars->fVerbose ) { printf( "Parameters: " ); printf( "Iters =%5d. ", pPars->nIters ); printf( "UseDept =%2d. ", pPars->fUseDept ); printf( "UseWL =%2d. ", pPars->fUseWireLoads ); printf( "Target =%5d ps. ", pPars->DelayUser ); printf( "DelayGap =%3d ps. ", pPars->DelayGap ); printf( "Timeout =%4d sec", pPars->TimeOut ); printf( "\n" ); } // prepare the manager; collect init stats p = Abc_SclManStart( pLib, pNtk, pPars->fUseWireLoads, pPars->fUseDept, pPars->DelayUser, pPars->BuffTreeEst ); p->timeTotal = Abc_Clock(); assert( p->vGatesBest == NULL ); p->vGatesBest = Vec_IntDup( p->pNtk->vGates ); // perform upsizing vNodes = Vec_IntAlloc( 1000 ); vEvals = Vec_IntAlloc( 1000 ); vTryLater = Vec_IntAlloc( 1000 ); for ( i = 0; i < pPars->nIters; i++ ) { int nRounds = 0; int nAttemptAll = 0, nOverlapAll = 0, nChangesAll = 0; Abc_NtkCollectNodesByArea( p, pNtk ); while ( Vec_QueSize(p->vNodeByGain) > 0 ) { int nAttempt = 0, nOverlap = 0, nChanges = 0; Vec_IntClear( vTryLater ); Abc_NtkIncrementTravId( pNtk ); while ( Vec_QueSize(p->vNodeByGain) > 0 ) { clk = Abc_Clock(); pObj = Abc_NtkObj( p->pNtk, Vec_QuePop(p->vNodeByGain) ); Abc_SclFindWindow( pObj, &vNodes, &vEvals ); p->timeCone += Abc_Clock() - clk; if ( Abc_SclCheckOverlap( p->pNtk, vNodes ) ) nOverlap++, Vec_IntPush( vTryLater, Abc_ObjId(pObj) ); else nChanges += Abc_SclCheckImprovement( p, pObj, vNodes, vEvals, pPars->Notches, pPars->DelayGap ); nAttempt++; } Abc_NtkForEachObjVec( vTryLater, pNtk, pObj, k ) Vec_QuePush( p->vNodeByGain, Abc_ObjId(pObj) ); clk = Abc_Clock(); if ( Vec_IntSize(p->vChanged) ) Abc_SclTimeIncUpdate( p ); else Abc_SclTimeNtkRecompute( p, &p->SumArea, &p->MaxDelay, pPars->fUseDept, pPars->DelayUser ); p->timeTime += Abc_Clock() - clk; p->MaxDelay = Abc_SclReadMaxDelay( p ); if ( pPars->fUseDept && pPars->DelayUser > 0 && p->MaxDelay < pPars->DelayUser ) p->MaxDelay = pPars->DelayUser; Abc_SclDnsizePrint( p, nRounds++, nAttempt, nOverlap, nChanges, pPars->fVeryVerbose ); nAttemptAll += nAttempt; nOverlapAll += nOverlap; nChangesAll += nChanges; if ( nRuntimeLimit && Abc_Clock() > nRuntimeLimit ) break; } // recompute // Abc_SclTimeNtkRecompute( p, &p->SumArea, &p->MaxDelay, pPars->fUseDept, pPars->DelayUser ); if ( pPars->fVerbose ) Abc_SclDnsizePrint( p, -1, nAttemptAll, nOverlapAll, nChangesAll, 1 ); if ( nRuntimeLimit && Abc_Clock() > nRuntimeLimit ) break; if ( nAttemptAll == 0 ) break; } Vec_IntFree( vNodes ); Vec_IntFree( vEvals ); Vec_IntFree( vTryLater ); if ( !pPars->fVerbose ) printf( " \r" ); // report runtime p->timeTotal = Abc_Clock() - p->timeTotal; if ( pPars->fVerbose ) { p->timeOther = p->timeTotal - p->timeCone - p->timeSize - p->timeTime; ABC_PRTP( "Runtime: Critical path", p->timeCone, p->timeTotal ); ABC_PRTP( "Runtime: Sizing eval ", p->timeSize, p->timeTotal ); ABC_PRTP( "Runtime: Timing update", p->timeTime, p->timeTotal ); ABC_PRTP( "Runtime: Other ", p->timeOther, p->timeTotal ); ABC_PRTP( "Runtime: TOTAL ", p->timeTotal, p->timeTotal ); } if ( pPars->fDumpStats ) Abc_SclDumpStats( p, "stats2.txt", p->timeTotal ); if ( nRuntimeLimit && Abc_Clock() > nRuntimeLimit ) printf( "Gate sizing timed out at %d seconds.\n", pPars->TimeOut ); // save the result and quit Abc_SclSclGates2MioGates( pLib, pNtk ); // updates gate pointers Abc_SclManFree( p ); // Abc_NtkCleanMarkAB( pNtk ); } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_SclDnsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars ) { Abc_Ntk_t * pNtkNew = pNtk; if ( pNtk->nBarBufs2 > 0 ) pNtkNew = Abc_NtkDupDfsNoBarBufs( pNtk ); Abc_SclDnsizePerformInt( pLib, pNtkNew, pPars ); if ( pNtk->nBarBufs2 > 0 ) Abc_SclTransferGates( pNtk, pNtkNew ); if ( pNtk->nBarBufs2 > 0 ) Abc_NtkDelete( pNtkNew ); } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END