mirror of https://github.com/YosysHQ/abc.git
568 lines
18 KiB
C
568 lines
18 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [seqMaxMeanCycle.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Construction and manipulation of sequential AIGs.]
|
|
|
|
Synopsis [Efficient computation of maximum mean cycle times.]
|
|
|
|
Author [Aaron P. Hurst]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - May 15, 2006.]
|
|
|
|
Revision [$Id: seqMaxMeanCycle.c,v 1.00 2005/05/15 00:00:00 ahurst Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "seqInt.h"
|
|
#include "hash.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
struct Abc_ManTime_t_
|
|
{
|
|
Abc_Time_t tArrDef;
|
|
Abc_Time_t tReqDef;
|
|
Vec_Ptr_t * vArrs;
|
|
Vec_Ptr_t * vReqs;
|
|
};
|
|
|
|
typedef struct Seq_HowardData_t_
|
|
{
|
|
char visited;
|
|
int mark;
|
|
int policy;
|
|
float cycle;
|
|
float skew;
|
|
float delay;
|
|
} Seq_HowardData_t;
|
|
|
|
// accessing the arrival and required times of a node
|
|
static inline Abc_Time_t * Abc_NodeArrival( Abc_Obj_t * pNode ) { return pNode->pNtk->pManTime->vArrs->pArray[pNode->Id]; }
|
|
static inline Abc_Time_t * Abc_NodeRequired( Abc_Obj_t * pNode ) { return pNode->pNtk->pManTime->vReqs->pArray[pNode->Id]; }
|
|
|
|
Hash_Ptr_t * Seq_NtkPathDelays( Abc_Ntk_t * pNtk, int fVerbose );
|
|
void Seq_NtkMergePios( Abc_Ntk_t * pNtk, Hash_Ptr_t * hFwdDelays, int fVerbose );
|
|
|
|
void Seq_NtkHowardLoop( Abc_Ntk_t * pNtk, Hash_Ptr_t * hFwdDelays,
|
|
Hash_Ptr_t * hNodeData, int node,
|
|
int *howardDepth, float *howardDelay, int *howardSink,
|
|
float *maxMeanCycle);
|
|
void Abc_NtkDfsReverse_rec2( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes, Vec_Ptr_t * vEndpoints );
|
|
|
|
#define Seq_NtkGetPathDelay( hFwdDelays, from, to ) \
|
|
(Hash_PtrExists(hFwdDelays, from)?Hash_FltEntry( ((Hash_Flt_t *)Hash_PtrEntry(hFwdDelays, from, 0)), to, 0):0 )
|
|
|
|
#define HOWARD_EPSILON 1e-3
|
|
#define ZERO_SLOP 1e-5
|
|
#define REMOVE_ZERO_SLOP( x ) \
|
|
(x = (x > -ZERO_SLOP && x < ZERO_SLOP)?0:x)
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes maximum mean cycle time.]
|
|
|
|
Description [Uses Howard's algorithm.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
float Seq_NtkHoward( Abc_Ntk_t * pNtk, int fVerbose ) {
|
|
|
|
Abc_Obj_t * pObj;
|
|
Hash_Ptr_t * hFwdDelays;
|
|
Hash_Flt_t * hOutgoing;
|
|
Hash_Ptr_Entry_t * pSourceEntry, * pNodeEntry;
|
|
Hash_Flt_Entry_t * pSinkEntry;
|
|
int i, j, iteration = 0;
|
|
int source, sink;
|
|
int fChanged;
|
|
int howardDepth, howardSink = 0;
|
|
float delay, howardDelay, t;
|
|
float maxMeanCycle = -ABC_INFINITY;
|
|
Hash_Ptr_t * hNodeData;
|
|
Seq_HowardData_t * pNodeData, * pSourceData, * pSinkData;
|
|
|
|
// gather timing constraints
|
|
hFwdDelays = Seq_NtkPathDelays( pNtk, fVerbose );
|
|
Seq_NtkMergePios( pNtk, hFwdDelays, fVerbose );
|
|
|
|
// initialize data, create initial policy
|
|
hNodeData = Hash_PtrAlloc( hFwdDelays->nSize );
|
|
Hash_PtrForEachEntry( hFwdDelays, pSourceEntry, i ) {
|
|
Hash_PtrWriteEntry( hNodeData, pSourceEntry->key,
|
|
(pNodeData = ALLOC(Seq_HowardData_t, 1)) );
|
|
pNodeData->skew = 0.0;
|
|
pNodeData->policy = 0;
|
|
hOutgoing = (Hash_Flt_t *)(pSourceEntry->data);
|
|
assert(hOutgoing);
|
|
|
|
Hash_FltForEachEntry( hOutgoing, pSinkEntry, j ) {
|
|
sink = pSinkEntry->key;
|
|
delay = pSinkEntry->data;
|
|
if (delay > pNodeData->skew) {
|
|
pNodeData->policy = sink;
|
|
pNodeData->skew = delay;
|
|
}
|
|
}
|
|
}
|
|
|
|
// iteratively refine policy
|
|
do {
|
|
iteration++;
|
|
fChanged = 0;
|
|
howardDelay = 0.0;
|
|
howardDepth = 0;
|
|
|
|
// reset data
|
|
Hash_PtrForEachEntry( hNodeData, pNodeEntry, i ) {
|
|
pNodeData = (Seq_HowardData_t *)pNodeEntry->data;
|
|
pNodeData->skew = -ABC_INFINITY;
|
|
pNodeData->cycle = -ABC_INFINITY;
|
|
pNodeData->mark = 0;
|
|
pNodeData->visited = 0;
|
|
}
|
|
|
|
// find loops in policy graph
|
|
Hash_PtrForEachEntry( hNodeData, pNodeEntry, i ) {
|
|
pNodeData = (Seq_HowardData_t *)(pNodeEntry->data);
|
|
assert(pNodeData);
|
|
if (!pNodeData->visited)
|
|
Seq_NtkHowardLoop( pNtk, hFwdDelays,
|
|
hNodeData, pNodeEntry->key,
|
|
&howardDepth, &howardDelay, &howardSink, &maxMeanCycle);
|
|
}
|
|
|
|
if (!howardSink) {
|
|
return -1;
|
|
}
|
|
|
|
// improve policy by tightening loops
|
|
Hash_PtrForEachEntry( hFwdDelays, pSourceEntry, i ) {
|
|
source = pSourceEntry->key;
|
|
pSourceData = (Seq_HowardData_t *)Hash_PtrEntry( hNodeData, source, 0 );
|
|
assert(pSourceData);
|
|
hOutgoing = (Hash_Flt_t *)(pSourceEntry->data);
|
|
assert(hOutgoing);
|
|
Hash_FltForEachEntry( hOutgoing, pSinkEntry, j ) {
|
|
sink = pSinkEntry->key;
|
|
pSinkData = (Seq_HowardData_t *)Hash_PtrEntry( hNodeData, sink, 0 );
|
|
assert(pSinkData);
|
|
delay = pSinkEntry->data;
|
|
|
|
if (pSinkData->cycle > pSourceData->cycle + HOWARD_EPSILON) {
|
|
fChanged = 1;
|
|
pSourceData->cycle = pSinkData->cycle;
|
|
pSourceData->policy = sink;
|
|
}
|
|
}
|
|
}
|
|
|
|
// improve policy by correcting skews
|
|
if (!fChanged) {
|
|
Hash_PtrForEachEntry( hFwdDelays, pSourceEntry, i ) {
|
|
source = pSourceEntry->key;
|
|
pSourceData = (Seq_HowardData_t *)Hash_PtrEntry( hNodeData, source, 0 );
|
|
assert(pSourceData);
|
|
hOutgoing = (Hash_Flt_t *)(pSourceEntry->data);
|
|
assert(hOutgoing);
|
|
Hash_FltForEachEntry( hOutgoing, pSinkEntry, j ) {
|
|
sink = pSinkEntry->key;
|
|
pSinkData = (Seq_HowardData_t *)Hash_PtrEntry( hNodeData, sink, 0 );
|
|
assert(pSinkData);
|
|
delay = pSinkEntry->data;
|
|
|
|
if (pSinkData->cycle < 0.0 || pSinkData->cycle < pSourceData->cycle)
|
|
continue;
|
|
|
|
t = delay - pSinkData->cycle + pSinkData->skew;
|
|
if (t > pSourceData->skew + HOWARD_EPSILON) {
|
|
fChanged = 1;
|
|
pSourceData->skew = t;
|
|
pSourceData->policy = sink;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fVerbose) printf("Iteration %d \t Period = %.2f\n", iteration, maxMeanCycle);
|
|
} while (fChanged);
|
|
|
|
// set global skew, mmct
|
|
pNodeData = Hash_PtrEntry( hNodeData, -1, 0 );
|
|
pNtk->globalSkew = -pNodeData->skew;
|
|
pNtk->maxMeanCycle = maxMeanCycle;
|
|
|
|
// set endpoint skews
|
|
Vec_FltGrow( pNtk->vSkews, Abc_NtkLatchNum( pNtk ) );
|
|
pNtk->vSkews->nSize = Abc_NtkLatchNum( pNtk );
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) {
|
|
pNodeData = Hash_PtrEntry( hNodeData, pObj->Id, 0 );
|
|
// skews are set based on latch # NOT id #
|
|
Abc_NtkSetLatSkew( pNtk, i, pNodeData->skew );
|
|
}
|
|
|
|
// free node data
|
|
Hash_PtrForEachEntry( hNodeData, pNodeEntry, i ) {
|
|
pNodeData = (Seq_HowardData_t *)(pNodeEntry->data);
|
|
FREE( pNodeData );
|
|
}
|
|
Hash_PtrFree(hNodeData);
|
|
|
|
// free delay data
|
|
Hash_PtrForEachEntry( hFwdDelays, pSourceEntry, i ) {
|
|
Hash_FltFree( (Hash_Flt_t *)(pSourceEntry->data) );
|
|
}
|
|
Hash_PtrFree(hFwdDelays);
|
|
|
|
return maxMeanCycle;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the mean cycle times of current policy graph.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NtkHowardLoop( Abc_Ntk_t * pNtk, Hash_Ptr_t * hFwdDelays,
|
|
Hash_Ptr_t * hNodeData, int node,
|
|
int *howardDepth, float *howardDelay, int *howardSink,
|
|
float *maxMeanCycle) {
|
|
|
|
Seq_HowardData_t * pNodeData, *pToData;
|
|
float delay, t;
|
|
|
|
pNodeData = (Seq_HowardData_t *)Hash_PtrEntry( hNodeData, node, 0 );
|
|
assert(pNodeData);
|
|
pNodeData->visited = 1;
|
|
pNodeData->mark = ++(*howardDepth);
|
|
pNodeData->delay = (*howardDelay);
|
|
if (pNodeData->policy) {
|
|
pToData = (Seq_HowardData_t *)Hash_PtrEntry( hNodeData, pNodeData->policy, 0 );
|
|
assert(pToData);
|
|
delay = Seq_NtkGetPathDelay( hFwdDelays, node, pNodeData->policy );
|
|
assert(delay > 0.0);
|
|
(*howardDelay) += delay;
|
|
if (pToData->mark) {
|
|
t = (*howardDelay - pToData->delay) / (*howardDepth - pToData->mark + 1);
|
|
pNodeData->cycle = t;
|
|
pNodeData->skew = 0.0;
|
|
if (*maxMeanCycle < t) {
|
|
*maxMeanCycle = t;
|
|
*howardSink = pNodeData->policy;
|
|
}
|
|
} else {
|
|
if(!pToData->visited) {
|
|
Seq_NtkHowardLoop(pNtk, hFwdDelays, hNodeData, pNodeData->policy,
|
|
howardDepth, howardDelay, howardSink, maxMeanCycle);
|
|
}
|
|
if(pToData->cycle > 0) {
|
|
t = delay - pToData->cycle + pToData->skew;
|
|
pNodeData->skew = t;
|
|
pNodeData->cycle = pToData->cycle;
|
|
}
|
|
}
|
|
}
|
|
*howardDelay = pNodeData->delay;
|
|
pNodeData->mark = 0;
|
|
--(*howardDepth);
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the register-to-register delays.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Hash_Ptr_t * Seq_NtkPathDelays( Abc_Ntk_t * pNtk, int fVerbose ) {
|
|
|
|
Abc_Time_t * pTime, ** ppTimes;
|
|
Abc_Obj_t * pObj, * pDriver, * pStart, * pFanout;
|
|
Vec_Ptr_t * vNodes, * vEndpoints;
|
|
int i, j, nPaths = 0;
|
|
Hash_Flt_t * hOutgoing;
|
|
Hash_Ptr_t * hFwdDelays;
|
|
float nMaxPath = 0, nSumPath = 0;
|
|
|
|
extern void Abc_NtkTimePrepare( Abc_Ntk_t * pNtk );
|
|
extern void Abc_NodeDelayTraceArrival( Abc_Obj_t * pNode );
|
|
|
|
if (fVerbose) printf("Gathering path delays...\n");
|
|
|
|
hFwdDelays = Hash_PtrAlloc( Abc_NtkCiNum( pNtk ) );
|
|
|
|
assert( Abc_NtkIsMappedLogic(pNtk) );
|
|
|
|
Abc_NtkTimePrepare( pNtk );
|
|
ppTimes = (Abc_Time_t **)pNtk->pManTime->vArrs->pArray;
|
|
vNodes = Vec_PtrAlloc( 100 );
|
|
vEndpoints = Vec_PtrAlloc( 100 );
|
|
|
|
// set the initial times (i.e. ignore all inputs)
|
|
Abc_NtkForEachObj( pNtk, pObj, i) {
|
|
pTime = ppTimes[pObj->Id];
|
|
pTime->Fall = pTime->Rise = pTime->Worst = -ABC_INFINITY;
|
|
}
|
|
|
|
// starting at each Ci, compute timing forward
|
|
Abc_NtkForEachCi( pNtk, pStart, j ) {
|
|
|
|
hOutgoing = Hash_FltAlloc( 10 );
|
|
Hash_PtrWriteEntry( hFwdDelays, pStart->Id, (void *)(hOutgoing) );
|
|
|
|
// seed the starting point of interest
|
|
pTime = ppTimes[pStart->Id];
|
|
pTime->Fall = pTime->Rise = pTime->Worst = 0.0;
|
|
|
|
// find a DFS ordering from the start
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NodeSetTravIdCurrent( pStart );
|
|
pObj = Abc_ObjFanout0Ntk(pStart);
|
|
Abc_ObjForEachFanout( pObj, pFanout, i )
|
|
Abc_NtkDfsReverse_rec2( pFanout, vNodes, vEndpoints );
|
|
if ( Abc_ObjIsCo( pStart ) )
|
|
Vec_PtrPush( vEndpoints, pStart );
|
|
|
|
// do timing analysis
|
|
for ( i = vNodes->nSize-1; i >= 0; --i )
|
|
Abc_NodeDelayTraceArrival( vNodes->pArray[i] );
|
|
|
|
// there is a path to each set of Co endpoints
|
|
Vec_PtrForEachEntry( vEndpoints, pObj, i )
|
|
{
|
|
assert(pObj);
|
|
assert( Abc_ObjIsCo( pObj ) );
|
|
pDriver = Abc_ObjFanin0(pObj);
|
|
pTime = Abc_NodeArrival(pDriver);
|
|
if ( pTime->Worst > 0 ) {
|
|
Hash_FltWriteEntry( hOutgoing, pObj->Id, pTime->Worst );
|
|
nPaths++;
|
|
// if (fVerbose) printf("\tpath %d,%d delay = %f\n", pStart->Id, pObj->Id, pTime->Worst);
|
|
nSumPath += pTime->Worst;
|
|
if (pTime->Worst > nMaxPath)
|
|
nMaxPath = pTime->Worst;
|
|
}
|
|
}
|
|
|
|
// clear the times that were altered
|
|
for ( i = 0; i < vNodes->nSize; i++ ) {
|
|
pObj = (Abc_Obj_t *)(vNodes->pArray[i]);
|
|
pTime = ppTimes[pObj->Id];
|
|
pTime->Fall = pTime->Rise = pTime->Worst = -ABC_INFINITY;
|
|
}
|
|
pTime = ppTimes[pStart->Id];
|
|
pTime->Fall = pTime->Rise = pTime->Worst = -ABC_INFINITY;
|
|
|
|
Vec_PtrClear( vNodes );
|
|
Vec_PtrClear( vEndpoints );
|
|
}
|
|
|
|
Vec_PtrFree( vNodes );
|
|
|
|
// rezero Cis (note: these should be restored to values if they were nonzero)
|
|
Abc_NtkForEachCi( pNtk, pObj, i) {
|
|
pTime = ppTimes[pObj->Id];
|
|
pTime->Fall = pTime->Rise = pTime->Worst = 0.0;
|
|
}
|
|
|
|
if (fVerbose) printf("Num. paths = %d\tMax. Path Delay = %.2f\tAvg. Path Delay = %.2f\n", nPaths, nMaxPath, nSumPath / nPaths);
|
|
return hFwdDelays;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Merges all the Pios together into one ID = -1.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NtkMergePios( Abc_Ntk_t * pNtk, Hash_Ptr_t * hFwdDelays,
|
|
int fVerbose ) {
|
|
|
|
Abc_Obj_t * pObj;
|
|
Hash_Flt_Entry_t * pSinkEntry;
|
|
Hash_Ptr_Entry_t * pSourceEntry;
|
|
Hash_Flt_t * hOutgoing, * hPioSource;
|
|
int i, j;
|
|
int source, sink, nMerges = 0;
|
|
float delay = 0, max_delay = 0;
|
|
Vec_Int_t * vFreeList;
|
|
|
|
vFreeList = Vec_IntAlloc( 10 );
|
|
|
|
// create a new "-1" source entry for the Pios
|
|
hPioSource = Hash_FltAlloc( 100 );
|
|
Hash_PtrWriteEntry( hFwdDelays, -1, (void *)(hPioSource) );
|
|
|
|
// merge all edges with a Pio as a source
|
|
Abc_NtkForEachPi( pNtk, pObj, i ) {
|
|
source = pObj->Id;
|
|
hOutgoing = (Hash_Flt_t *)Hash_PtrEntry( hFwdDelays, source, 0 );
|
|
if (!hOutgoing) continue;
|
|
|
|
Hash_PtrForEachEntry( hOutgoing, pSinkEntry, j ) {
|
|
nMerges++;
|
|
sink = pSinkEntry->key;
|
|
delay = pSinkEntry->data;
|
|
if (Hash_FltEntry( hPioSource, sink, 1 ) < delay) {
|
|
Hash_FltWriteEntry( hPioSource, sink, delay );
|
|
}
|
|
}
|
|
|
|
Hash_FltFree( hOutgoing );
|
|
Hash_PtrRemove( hFwdDelays, source );
|
|
}
|
|
|
|
// merge all edges with a Pio as a sink
|
|
Hash_PtrForEachEntry( hFwdDelays, pSourceEntry, i ) {
|
|
hOutgoing = (Hash_Flt_t *)(pSourceEntry->data);
|
|
Hash_FltForEachEntry( hOutgoing, pSinkEntry, j ) {
|
|
sink = pSinkEntry->key;
|
|
delay = pSinkEntry->data;
|
|
|
|
max_delay = -ABC_INFINITY;
|
|
if (Abc_ObjIsPo( Abc_NtkObj( pNtk, sink ) )) {
|
|
nMerges++;
|
|
if (delay > max_delay)
|
|
max_delay = delay;
|
|
Vec_IntPush( vFreeList, sink );
|
|
}
|
|
}
|
|
if (max_delay != -ABC_INFINITY)
|
|
Hash_FltWriteEntry( hOutgoing, -1, delay );
|
|
// do freeing
|
|
while( vFreeList->nSize > 0 ) {
|
|
Hash_FltRemove( hOutgoing, Vec_IntPop( vFreeList ) );
|
|
}
|
|
}
|
|
|
|
if (fVerbose) printf("Merged %d paths into one Pio node\n", nMerges);
|
|
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [This is a modification of routine from abcDfs.c]
|
|
|
|
Description [Recursive DFS from a starting point. Keeps the endpoints.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDfsReverse_rec2( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes, Vec_Ptr_t * vEndpoints )
|
|
{
|
|
Abc_Obj_t * pFanout;
|
|
int i;
|
|
assert( !Abc_ObjIsNet(pNode) );
|
|
// if this node is already visited, skip
|
|
if ( Abc_NodeIsTravIdCurrent( pNode ) )
|
|
return;
|
|
// mark the node as visited
|
|
Abc_NodeSetTravIdCurrent( pNode );
|
|
// terminate at the Co
|
|
if ( Abc_ObjIsCo(pNode) ) {
|
|
Vec_PtrPush( vEndpoints, pNode );
|
|
return;
|
|
}
|
|
assert( Abc_ObjIsNode( pNode ) );
|
|
// visit the transitive fanin of the node
|
|
pNode = Abc_ObjFanout0Ntk(pNode);
|
|
Abc_ObjForEachFanout( pNode, pFanout, i )
|
|
Abc_NtkDfsReverse_rec2( pFanout, vNodes, vEndpoints );
|
|
// add the node after the fanins have been added
|
|
Vec_PtrPush( vNodes, pNode );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Converts all skews into forward skews 0<skew<T.]
|
|
|
|
Description [Can also minimize total skew by changing global skew.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NtkSkewForward( Abc_Ntk_t * pNtk, float period, int fMinimize ) {
|
|
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
float skew;
|
|
float currentSum = 0, bestSum = ABC_INFINITY;
|
|
float currentOffset = 0, nextStep, bestOffset = 0;
|
|
|
|
assert( pNtk->vSkews->nSize >= Abc_NtkLatchNum( pNtk )-1 );
|
|
|
|
if (fMinimize) {
|
|
// search all offsets for the one that minimizes sum of skews
|
|
while(currentOffset < period) {
|
|
currentSum = 0;
|
|
nextStep = period;
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) {
|
|
skew = Abc_NtkGetLatSkew( pNtk, i ) + currentOffset;
|
|
skew = (float)(skew - period*floor(skew/period));
|
|
currentSum += skew;
|
|
if (skew > ZERO_SLOP && skew < nextStep) {
|
|
nextStep = skew;
|
|
}
|
|
}
|
|
|
|
if (currentSum < bestSum) {
|
|
bestSum = currentSum;
|
|
bestOffset = currentOffset;
|
|
}
|
|
currentOffset += nextStep;
|
|
}
|
|
printf("Offseting all skews by %.2f\n", bestOffset);
|
|
}
|
|
|
|
// convert global skew into forward skew
|
|
pNtk->globalSkew = pNtk->globalSkew - bestOffset;
|
|
pNtk->globalSkew = (float)(pNtk->globalSkew - period*floor(pNtk->globalSkew/period));
|
|
assert(pNtk->globalSkew>= 0 && pNtk->globalSkew < period);
|
|
|
|
// convert endpoint skews into forward skews
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) {
|
|
skew = Abc_NtkGetLatSkew( pNtk, i ) + bestOffset;
|
|
skew = (float)(skew - period*floor(skew/period));
|
|
REMOVE_ZERO_SLOP( skew );
|
|
assert(skew >=0 && skew < period);
|
|
|
|
Abc_NtkSetLatSkew( pNtk, i, skew );
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|