abc/src/map/scl/sclBufSize.c

396 lines
13 KiB
C
Raw Normal View History

2013-08-09 03:23:00 +02:00
/**CFile****************************************************************
FileName [sclBufSize.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Standard-cell library representation.]
Synopsis [Buffering and sizing combined.]
Author [Alan Mishchenko, Niklas Een]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - August 24, 2012.]
Revision [$Id: sclBufSize.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 ///
////////////////////////////////////////////////////////////////////////
typedef struct Bus_Man_t_ Bus_Man_t;
struct Bus_Man_t_
{
// user data
2013-08-10 06:44:18 +02:00
SC_BusPars * pPars; // parameters
2013-08-09 03:23:00 +02:00
Abc_Ntk_t * pNtk; // user's network
// library
SC_Lib * pLib; // cell library
SC_Cell * pInv; // base interter (largest/average/???)
// internal
Vec_Flt_t * vCins; // input cap for fanouts
Vec_Flt_t * vLoads; // loads for all nodes
Vec_Flt_t * vDepts; // departure times
};
static inline Bus_Man_t * Bus_SclObjMan( Abc_Obj_t * p ) { return (Bus_Man_t *)p->pNtk->pBSMan; }
static inline float Bus_SclObjCin( Abc_Obj_t * p ) { return Vec_FltEntry( Bus_SclObjMan(p)->vCins, Abc_ObjId(p) ); }
2013-08-09 20:15:20 +02:00
static inline void Bus_SclObjSetCin( Abc_Obj_t * p, float cap ) { Vec_FltWriteEntry( Bus_SclObjMan(p)->vCins, Abc_ObjId(p), cap ); }
2013-08-09 03:23:00 +02:00
static inline float Bus_SclObjLoad( Abc_Obj_t * p ) { return Vec_FltEntry( Bus_SclObjMan(p)->vLoads, Abc_ObjId(p) ); }
2013-08-09 20:15:20 +02:00
static inline void Bus_SclObjSetLoad( Abc_Obj_t * p, float cap ) { Vec_FltWriteEntry( Bus_SclObjMan(p)->vLoads, Abc_ObjId(p), cap ); }
2013-08-09 03:23:00 +02:00
static inline float Bus_SclObjDept( Abc_Obj_t * p ) { return Vec_FltEntry( Bus_SclObjMan(p)->vDepts, Abc_ObjId(p) ); }
2013-08-09 20:15:20 +02:00
static inline void Bus_SclObjUpdateDept( Abc_Obj_t * p, float time ) { float *q = Vec_FltEntryP( Bus_SclObjMan(p)->vDepts, Abc_ObjId(p) ); if (*q < time) *q = time; }
2013-08-09 03:23:00 +02:00
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
2013-08-10 06:44:18 +02:00
Bus_Man_t * Bus_ManStart( Abc_Ntk_t * pNtk, SC_Lib * pLib, SC_BusPars * pPars )
2013-08-09 03:23:00 +02:00
{
Bus_Man_t * p;
p = ABC_CALLOC( Bus_Man_t, 1 );
2013-08-10 06:44:18 +02:00
p->pPars = pPars;
2013-08-10 06:05:06 +02:00
p->pNtk = pNtk;
p->pLib = pLib;
2013-08-10 06:44:18 +02:00
p->pInv = Abc_SclFindInvertor(pLib, pPars->fAddBufs)->pAve;
2013-08-10 06:05:06 +02:00
p->vCins = Vec_FltStart( 2*Abc_NtkObjNumMax(pNtk) );
p->vLoads = Vec_FltStart( 2*Abc_NtkObjNumMax(pNtk) );
p->vDepts = Vec_FltStart( 2*Abc_NtkObjNumMax(pNtk) );
2013-08-09 03:23:00 +02:00
pNtk->pBSMan = p;
return p;
}
void Bus_ManStop( Bus_Man_t * p )
{
Vec_FltFree( p->vCins );
Vec_FltFree( p->vLoads );
Vec_FltFree( p->vDepts );
ABC_FREE( p );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Bus_ManReadInOutLoads( Bus_Man_t * p )
{
Abc_Time_t * pTime;
Abc_Obj_t * pObj;
int i;
// read input load
pTime = Abc_NtkReadDefaultInputDrive( p->pNtk );
if ( Abc_MaxFloat(pTime->Rise, pTime->Fall) != 0 )
{
printf( "Default input drive strength is specified (%.2f ff; %.2f ff).\n", pTime->Rise, pTime->Fall );
Abc_NtkForEachPi( p->pNtk, pObj, i )
2013-08-09 20:15:20 +02:00
Bus_SclObjSetCin( pObj, SC_LibCapFromFf(p->pLib, 0.5 * pTime->Rise + 0.5 * pTime->Fall) );
2013-08-09 03:23:00 +02:00
}
if ( Abc_NodeReadInputDrive(p->pNtk, 0) != NULL )
{
printf( "Input drive strengths for some primary inputs are specified.\n" );
Abc_NtkForEachPi( p->pNtk, pObj, i )
{
pTime = Abc_NodeReadInputDrive(p->pNtk, i);
2013-08-09 20:15:20 +02:00
Bus_SclObjSetCin( pObj, SC_LibCapFromFf(p->pLib, 0.5 * pTime->Rise + 0.5 * pTime->Fall) );
2013-08-09 03:23:00 +02:00
}
}
// read output load
pTime = Abc_NtkReadDefaultOutputLoad( p->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( p->pNtk, pObj, i )
2013-08-09 20:15:20 +02:00
Bus_SclObjSetCin( pObj, SC_LibCapFromFf(p->pLib, 0.5 * pTime->Rise + 0.5 * pTime->Fall) );
2013-08-09 03:23:00 +02:00
}
if ( Abc_NodeReadOutputLoad(p->pNtk, 0) != NULL )
{
printf( "Output loads for some primary outputs are specified.\n" );
Abc_NtkForEachPo( p->pNtk, pObj, i )
{
pTime = Abc_NodeReadOutputLoad(p->pNtk, i);
2013-08-09 20:15:20 +02:00
Bus_SclObjSetCin( pObj, SC_LibCapFromFf(p->pLib, 0.5 * pTime->Rise + 0.5 * pTime->Fall) );
2013-08-09 03:23:00 +02:00
}
}
// read arrival/required times
}
/**Function*************************************************************
Synopsis [Compute load and departure times of the node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkComputeFanoutCins( Abc_Obj_t * pObj )
{
Abc_Obj_t * pFanout;
int i;
Abc_ObjForEachFanout( pObj, pFanout, i )
if ( Abc_ObjIsNode(pFanout) )
2013-08-10 06:05:06 +02:00
{
float cap = SC_CellPinCap( Abc_SclObjCell(pFanout), Abc_NodeFindFanin(pFanout, pObj) );
assert( cap > 0 );
Bus_SclObjSetCin( pFanout, cap );
}
2013-08-09 03:23:00 +02:00
}
float Abc_NtkComputeNodeLoad( Abc_Obj_t * pObj )
{
Abc_Obj_t * pFanout;
float Load = 0;
int i;
assert( Bus_SclObjLoad(pObj) == 0 );
Abc_ObjForEachFanout( pObj, pFanout, i )
Load += Bus_SclObjCin( pFanout );
Bus_SclObjSetLoad( pObj, Load );
return Load;
}
2013-08-10 06:44:18 +02:00
float Abc_NtkComputeNodeDept( Abc_Obj_t * pObj, float Slew )
2013-08-09 03:23:00 +02:00
{
Abc_Obj_t * pFanout;
float Load, Dept, Edge;
int i;
assert( Bus_SclObjDept(pObj) == 0 );
Abc_ObjForEachFanout( pObj, pFanout, i )
{
if ( Abc_ObjIsCo(pFanout) ) // add required times here
continue;
Load = Bus_SclObjLoad( pFanout );
Dept = Bus_SclObjDept( pFanout );
2013-08-10 06:44:18 +02:00
Edge = Scl_LibPinArrivalEstimate( Abc_SclObjCell(pFanout), Abc_NodeFindFanin(pFanout, pObj), Slew, Load );
2013-08-09 03:23:00 +02:00
Bus_SclObjUpdateDept( pObj, Dept + Edge );
assert( Edge > 0 );
2013-08-10 06:05:06 +02:00
// assert( Load > 0 );
2013-08-09 03:23:00 +02:00
}
return Bus_SclObjDept( pObj );
}
/*
void Abc_NtkUpdateFaninDeparture( Bus_Man_t * p, Abc_Obj_t * pObj, float Load )
{
SC_Cell * pCell = Abc_SclObjCell( pObj );
Abc_Obj_t * pFanin;
float Dept, Edge;
int i;
Dept = Bus_SclObjDept( pObj );
Abc_ObjForEachFanin( pObj, pFanin, i )
{
2013-08-09 20:15:20 +02:00
Edge = Scl_LibPinArrivalEstimate( pCell, i, Load );
2013-08-09 03:23:00 +02:00
Bus_SclObjUpdateDept( pFanin, Dept + Edge );
}
}
*/
/**Function*************************************************************
Synopsis [Compare two fanouts by their departure times.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Bus_SclCompareFanouts( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 )
{
float Espilon = 10; // 10 ps
if ( Bus_SclObjDept(*pp1) < Bus_SclObjDept(*pp2) - Espilon )
return -1;
if ( Bus_SclObjDept(*pp1) > Bus_SclObjDept(*pp2) + Espilon )
return 1;
if ( Bus_SclObjCin(*pp1) > Bus_SclObjCin(*pp2) - Espilon )
return -1;
if ( Bus_SclObjCin(*pp1) < Bus_SclObjCin(*pp2) + Espilon )
return 1;
return -1;
}
void Bus_SclInsertFanout( Vec_Ptr_t * vFanouts, Abc_Obj_t * pObj )
{
Abc_Obj_t * pCur;
int i, k;
assert( Bus_SclObjDept(pObj) > 0 );
assert( Bus_SclObjLoad(pObj) > 0 );
// compact array
for ( i = k = 0; i < Vec_PtrSize(vFanouts); i++ )
if ( Vec_PtrEntry(vFanouts, i) != NULL )
Vec_PtrWriteEntry( vFanouts, k++, Vec_PtrEntry(vFanouts, i) );
Vec_PtrShrink( vFanouts, k );
// insert new entry
Vec_PtrPush( vFanouts, pObj );
for ( i = Vec_PtrSize(vFanouts) - 1; i > 0; i-- )
{
pCur = (Abc_Obj_t *)Vec_PtrEntry(vFanouts, i-1);
pObj = (Abc_Obj_t *)Vec_PtrEntry(vFanouts, i);
if ( Bus_SclCompareFanouts( &pCur, &pObj ) == -1 )
break;
ABC_SWAP( void *, Vec_PtrArray(vFanouts)[i-1], Vec_PtrArray(vFanouts)[i] );
}
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Obj_t * Abc_SclAddOneInv( Bus_Man_t * p, Abc_Obj_t * pObj, Vec_Ptr_t * vFanouts, float Gain, int Degree )
{
SC_Cell * pCellNew;
Abc_Obj_t * pFanout, * pInv;
2013-08-09 20:15:20 +02:00
float Target = SC_CellPinCap(p->pInv, 0) * Gain;
2013-08-09 03:23:00 +02:00
float Load = 0;
int i, iStop;
Vec_PtrForEachEntryStop( Abc_Obj_t *, vFanouts, pFanout, iStop, Degree )
{
Load += Bus_SclObjCin( pFanout );
if ( Load > Target )
break;
}
// create inverter
2013-08-10 06:44:18 +02:00
if ( p->pPars->fAddBufs )
2013-08-09 20:15:20 +02:00
pInv = Abc_NtkCreateNodeBuf( p->pNtk, NULL );
else
pInv = Abc_NtkCreateNodeInv( p->pNtk, NULL );
2013-08-09 03:23:00 +02:00
assert( (int)Abc_ObjId(pInv) < Vec_FltSize(p->vDepts) );
Vec_PtrForEachEntryStop( Abc_Obj_t *, vFanouts, pFanout, i, iStop )
{
Vec_PtrWriteEntry( vFanouts, i, NULL );
if ( Abc_ObjFanin0(pFanout) == NULL )
Abc_ObjAddFanin( pFanout, pInv );
else
Abc_ObjPatchFanin( pFanout, pObj, pInv );
}
// set the gate
pCellNew = Abc_SclFindSmallestGate( p->pInv, Load / Gain );
Vec_IntSetEntry( p->pNtk->vGates, Abc_ObjId(pInv), pCellNew->Id );
Bus_SclObjSetCin( pInv, SC_CellPinCap(pCellNew, 0) );
// update timing
Abc_NtkComputeNodeLoad( pInv );
2013-08-10 06:44:18 +02:00
Abc_NtkComputeNodeDept( pInv, p->pPars->Slew );
2013-08-09 03:23:00 +02:00
// update phases
if ( p->pNtk->vPhases && Abc_SclIsInv(pInv) )
Abc_NodeInvUpdateFanPolarity( pInv );
return pInv;
}
void Abc_SclBufSize( Bus_Man_t * p )
{
SC_Cell * pCell, * pCellNew;
Vec_Ptr_t * vFanouts;
Abc_Obj_t * pObj, * pInv;
2013-08-10 06:05:06 +02:00
abctime clk = Abc_Clock();
2013-08-10 06:44:18 +02:00
float Gain = 0.01 * p->pPars->GainRatio;
float Load, Cin, Dept, DeptMax = 0;
2013-08-09 03:23:00 +02:00
int i;
vFanouts = Vec_PtrAlloc( 100 );
Abc_SclMioGates2SclGates( p->pLib, p->pNtk );
2013-08-10 06:05:06 +02:00
Abc_NtkForEachNodeReverse1( p->pNtk, pObj, i )
2013-08-09 03:23:00 +02:00
{
// compute load
Abc_NtkComputeFanoutCins( pObj );
Load = Abc_NtkComputeNodeLoad( pObj );
// consider the gate
pCell = Abc_SclObjCell( pObj );
Cin = SC_CellPinCapAve( pCell->pAve );
// consider upsizing the gate
2013-08-10 06:44:18 +02:00
if ( !p->pPars->fSizeOnly && Load > Gain * Cin )
2013-08-09 03:23:00 +02:00
{
// add one or more inverters
Abc_NodeCollectFanouts( pObj, vFanouts );
2013-08-09 03:23:40 +02:00
Vec_PtrSort( vFanouts, (int(*)(void))Bus_SclCompareFanouts );
2013-08-09 03:23:00 +02:00
do
{
2013-08-10 06:44:18 +02:00
pInv = Abc_SclAddOneInv( p, pObj, vFanouts, Gain, p->pPars->nDegree );
2013-08-09 03:23:00 +02:00
Bus_SclInsertFanout( vFanouts, pInv );
Load = Bus_SclObjCin( pInv );
}
2013-08-10 06:44:18 +02:00
while ( Vec_PtrSize(vFanouts) > 1 || Load > Gain * Cin );
2013-08-09 03:23:00 +02:00
// connect last inverter
assert( Abc_ObjFanin0(pInv) == NULL );
Abc_ObjAddFanin( pInv, pObj );
Bus_SclObjSetLoad( pObj, Load );
2013-08-10 06:05:06 +02:00
}
2013-08-09 03:23:00 +02:00
// create cell
2013-08-10 06:44:18 +02:00
pCellNew = Abc_SclFindSmallestGate( pCell, Load / Gain );
2013-08-09 03:23:00 +02:00
Abc_SclObjSetCell( pObj, pCellNew );
2013-08-10 06:44:18 +02:00
Dept = Abc_NtkComputeNodeDept( pObj, p->pPars->Slew );
2013-08-10 06:05:06 +02:00
DeptMax = Abc_MaxFloat( DeptMax, Dept );
2013-08-10 06:44:18 +02:00
if ( p->pPars->fVerbose )
2013-08-10 06:05:06 +02:00
{
printf( "Node %7d : ", i );
printf( "%12s ", pCellNew->pName );
printf( "(%2d/%2d) ", pCellNew->Order, pCellNew->nGates );
2013-08-10 07:55:09 +02:00
printf( "gain =%5d ", (int)(100.0 * Load / SC_CellPinCapAve(pCellNew)) );
2013-08-10 06:05:06 +02:00
printf( "dept =%7.0f ps ", SC_LibTimePs(p->pLib, Dept) );
printf( "\n" );
}
2013-08-09 03:23:00 +02:00
}
Abc_SclSclGates2MioGates( p->pLib, p->pNtk );
Vec_PtrFree( vFanouts );
2013-08-10 06:44:18 +02:00
if ( p->pPars->fVerbose )
2013-08-10 06:05:06 +02:00
{
2013-08-10 06:44:18 +02:00
printf( "Target gain =%5d. Target slew =%5d. Delay =%7.0f ps ",
p->pPars->GainRatio, p->pPars->Slew, SC_LibTimePs(p->pLib, DeptMax) );
2013-08-10 06:05:06 +02:00
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
}
2013-08-09 03:23:00 +02:00
}
2013-08-10 06:44:18 +02:00
Abc_Ntk_t * Abc_SclBufSizePerform( Abc_Ntk_t * pNtk, SC_Lib * pLib, SC_BusPars * pPars )
2013-08-09 03:23:00 +02:00
{
Abc_Ntk_t * pNtkNew;
Bus_Man_t * p;
if ( !Abc_SclCheckNtk( pNtk, 0 ) )
return NULL;
Abc_SclReportDupFanins( pNtk );
2013-08-10 06:44:18 +02:00
p = Bus_ManStart( pNtk, pLib, pPars );
2013-08-09 03:23:00 +02:00
Bus_ManReadInOutLoads( p );
Abc_SclBufSize( p );
Bus_ManStop( p );
2013-08-10 06:05:06 +02:00
if ( pNtk->vPhases )
Vec_IntFillExtra( pNtk->vPhases, Abc_NtkObjNumMax(pNtk), 0 );
2013-08-09 03:23:00 +02:00
pNtkNew = Abc_NtkDupDfs( pNtk );
return pNtkNew;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END