blob: 19e4b30c74992cb5a2bc72bd9f1956a47c9c6a35 [file] [log] [blame]
/**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