blob: 9d55fc929f9afb9b76f5df0ec342e24db92cb437 [file] [log] [blame]
/**CFile****************************************************************
FileName [fretTime.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Flow-based retiming package.]
Synopsis [Delay-constrained retiming code.]
Author [Aaron Hurst]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - January 1, 2008.]
Revision [$Id: fretTime.c,v 1.00 2008/01/01 00:00:00 ahurst Exp $]
***********************************************************************/
#include "fretime.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static void Abc_FlowRetime_Dfs_forw( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes );
static void Abc_FlowRetime_Dfs_back( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes );
static void Abc_FlowRetime_ConstrainExact_forw( Abc_Obj_t * pObj );
static void Abc_FlowRetime_ConstrainExact_back( Abc_Obj_t * pObj );
static void Abc_FlowRetime_ConstrainConserv_forw( Abc_Ntk_t * pNtk );
static void Abc_FlowRetime_ConstrainConserv_back( Abc_Ntk_t * pNtk );
void trace2(Abc_Obj_t *pObj) {
Abc_Obj_t *pNext;
int i;
print_node(pObj);
Abc_ObjForEachFanin(pObj, pNext, i)
if (pNext->Level >= pObj->Level - 1) {
trace2(pNext);
break;
}
}
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Initializes timing]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_FlowRetime_InitTiming( Abc_Ntk_t *pNtk ) {
pManMR->nConservConstraints = pManMR->nExactConstraints = 0;
pManMR->vExactNodes = Vec_PtrAlloc(1000);
pManMR->vTimeEdges = ABC_ALLOC( Vec_Ptr_t, Abc_NtkObjNumMax(pNtk)+1 );
assert(pManMR->vTimeEdges);
memset(pManMR->vTimeEdges, 0, (Abc_NtkObjNumMax(pNtk)+1) * sizeof(Vec_Ptr_t) );
}
/**Function*************************************************************
Synopsis [Marks nodes with conservative constraints.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_FlowRetime_ConstrainConserv( Abc_Ntk_t * pNtk ) {
Abc_Obj_t *pObj;
int i;
void *pArray;
// clear all exact constraints
pManMR->nExactConstraints = 0;
while( Vec_PtrSize( pManMR->vExactNodes )) {
pObj = (Abc_Obj_t*)Vec_PtrPop( pManMR->vExactNodes );
if ( Vec_PtrSize( FTIMEEDGES(pObj) )) {
pArray = Vec_PtrReleaseArray( FTIMEEDGES(pObj) );
ABC_FREE( pArray );
}
}
#if !defined(IGNORE_TIMING)
if (pManMR->fIsForward) {
Abc_FlowRetime_ConstrainConserv_forw(pNtk);
} else {
Abc_FlowRetime_ConstrainConserv_back(pNtk);
}
#endif
Abc_NtkForEachObj( pNtk, pObj, i)
assert( !Vec_PtrSize(FTIMEEDGES(pObj)) );
}
void Abc_FlowRetime_ConstrainConserv_forw( Abc_Ntk_t * pNtk ) {
Vec_Ptr_t *vNodes = pManMR->vNodes;
Abc_Obj_t *pObj, *pNext, *pBi, *pBo;
int i, j;
assert(!Vec_PtrSize( vNodes ));
pManMR->nConservConstraints = 0;
// 1. hard constraints
// (i) collect TFO of PIs
Abc_NtkIncrementTravId(pNtk);
Abc_NtkForEachPi(pNtk, pObj, i)
Abc_FlowRetime_Dfs_forw( pObj, vNodes );
// ... propagate values
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->Level = 0;
Abc_ObjForEachFanin( pObj, pNext, j )
{
if ( Abc_NodeIsTravIdCurrent(pNext) &&
pObj->Level < pNext->Level )
pObj->Level = pNext->Level;
}
pObj->Level += Abc_ObjIsNode(pObj) ? 1 : 0;
if ( Abc_ObjIsBi(pObj) )
pObj->fMarkA = 1;
assert((int)pObj->Level <= pManMR->maxDelay);
}
// collect TFO of latches
// seed arrival times from BIs
Vec_PtrClear(vNodes);
Abc_NtkIncrementTravId(pNtk);
Abc_NtkForEachLatch(pNtk, pObj, i) {
pBo = Abc_ObjFanout0( pObj );
pBi = Abc_ObjFanin0( pObj );
Abc_NodeSetTravIdCurrent( pObj );
Abc_FlowRetime_Dfs_forw( pBo, vNodes );
if (pBi->fMarkA) {
pBi->fMarkA = 0;
pObj->Level = pBi->Level;
assert((int)pObj->Level <= pManMR->maxDelay);
} else
pObj->Level = 0;
}
#if defined(DEBUG_CHECK)
// DEBUG: check DFS ordering
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->fMarkB = 1;
Abc_ObjForEachFanin( pObj, pNext, j )
if ( Abc_NodeIsTravIdCurrent(pNext) && !Abc_ObjIsLatch(pNext))
assert(pNext->fMarkB);
}
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i)
pObj->fMarkB = 0;
#endif
// ... propagate values
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->Level = 0;
Abc_ObjForEachFanin( pObj, pNext, j )
{
if ( Abc_NodeIsTravIdCurrent(pNext) &&
pObj->Level < pNext->Level )
pObj->Level = pNext->Level;
}
pObj->Level += Abc_ObjIsNode(pObj) ? 1 : 0;
if ((int)pObj->Level > pManMR->maxDelay) {
FSET(pObj, BLOCK);
}
}
// 2. conservative constraints
// first pass: seed latches with T=0
Abc_NtkForEachLatch(pNtk, pObj, i) {
pObj->Level = 0;
}
// ... propagate values
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->Level = 0;
Abc_ObjForEachFanin( pObj, pNext, j ) {
if ( Abc_NodeIsTravIdCurrent(pNext) &&
pObj->Level < pNext->Level )
pObj->Level = pNext->Level;
}
pObj->Level += Abc_ObjIsNode(pObj) ? 1 : 0;
if ( Abc_ObjIsBi(pObj) )
pObj->fMarkA = 1;
assert((int)pObj->Level <= pManMR->maxDelay);
}
Abc_NtkForEachLatch(pNtk, pObj, i) {
pBo = Abc_ObjFanout0( pObj );
pBi = Abc_ObjFanin0( pObj );
if (pBi->fMarkA) {
pBi->fMarkA = 0;
pObj->Level = pBi->Level;
assert((int)pObj->Level <= pManMR->maxDelay);
} else
pObj->Level = 0;
}
// ... propagate values
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->Level = 0;
Abc_ObjForEachFanin( pObj, pNext, j ) {
if ( Abc_NodeIsTravIdCurrent(pNext) &&
pObj->Level < pNext->Level )
pObj->Level = pNext->Level;
}
pObj->Level += Abc_ObjIsNode(pObj) ? 1 : 0;
// constrained?
if ((int)pObj->Level > pManMR->maxDelay) {
FSET( pObj, CONSERVATIVE );
pManMR->nConservConstraints++;
} else
FUNSET( pObj, CONSERVATIVE );
}
Vec_PtrClear( vNodes );
}
void Abc_FlowRetime_ConstrainConserv_back( Abc_Ntk_t * pNtk ) {
Vec_Ptr_t *vNodes = pManMR->vNodes;
Abc_Obj_t *pObj, *pNext, *pBi, *pBo;
int i, j, l;
assert(!Vec_PtrSize(vNodes));
pManMR->nConservConstraints = 0;
// 1. hard constraints
// (i) collect TFO of POs
Abc_NtkIncrementTravId(pNtk);
Abc_NtkForEachPo(pNtk, pObj, i)
Abc_FlowRetime_Dfs_back( pObj, vNodes );
// ... propagate values
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->Level = 0;
Abc_ObjForEachFanout( pObj, pNext, j )
{
l = pNext->Level + (Abc_ObjIsNode(pObj) ? 1 : 0);
if ( Abc_NodeIsTravIdCurrent(pNext) &&
(int)pObj->Level < l )
pObj->Level = l;
}
if ( Abc_ObjIsBo(pObj) )
pObj->fMarkA = 1;
assert((int)pObj->Level <= pManMR->maxDelay);
}
// collect TFO of latches
// seed arrival times from BIs
Vec_PtrClear(vNodes);
Abc_NtkIncrementTravId(pNtk);
Abc_NtkForEachLatch(pNtk, pObj, i) {
pBo = Abc_ObjFanout0( pObj );
pBi = Abc_ObjFanin0( pObj );
Abc_NodeSetTravIdCurrent( pObj );
Abc_FlowRetime_Dfs_back( pBi, vNodes );
if (pBo->fMarkA) {
pBo->fMarkA = 0;
pObj->Level = pBo->Level;
assert((int)pObj->Level <= pManMR->maxDelay);
} else
pObj->Level = 0;
}
#if defined(DEBUG_CHECK)
// DEBUG: check DFS ordering
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->fMarkB = 1;
Abc_ObjForEachFanout( pObj, pNext, j )
if ( Abc_NodeIsTravIdCurrent(pNext) && !Abc_ObjIsLatch(pNext))
assert(pNext->fMarkB);
}
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i)
pObj->fMarkB = 0;
#endif
// ... propagate values
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->Level = 0;
Abc_ObjForEachFanout( pObj, pNext, j )
{
l = pNext->Level + (Abc_ObjIsNode(pObj) ? 1 : 0);
if ( Abc_NodeIsTravIdCurrent(pNext) &&
(int)pObj->Level < l )
pObj->Level = l;
}
if ((int)pObj->Level + (Abc_ObjIsNode(pObj)?1:0) > pManMR->maxDelay) {
FSET(pObj, BLOCK);
}
}
// 2. conservative constraints
// first pass: seed latches with T=0
Abc_NtkForEachLatch(pNtk, pObj, i) {
pObj->Level = 0;
}
// ... propagate values
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->Level = 0;
Abc_ObjForEachFanout( pObj, pNext, j ) {
l = pNext->Level + (Abc_ObjIsNode(pObj) ? 1 : 0);
if ( Abc_NodeIsTravIdCurrent(pNext) &&
(int)pObj->Level < l )
pObj->Level = l;
}
if ( Abc_ObjIsBo(pObj) ) {
pObj->fMarkA = 1;
}
assert((int)pObj->Level <= pManMR->maxDelay);
}
Abc_NtkForEachLatch(pNtk, pObj, i) {
pBo = Abc_ObjFanout0( pObj );
assert(Abc_ObjIsBo(pBo));
pBi = Abc_ObjFanin0( pObj );
assert(Abc_ObjIsBi(pBi));
if (pBo->fMarkA) {
pBo->fMarkA = 0;
pObj->Level = pBo->Level;
} else
pObj->Level = 0;
}
// ... propagate values
Vec_PtrForEachEntryReverse( Abc_Obj_t *,vNodes, pObj, i) {
pObj->Level = 0;
Abc_ObjForEachFanout( pObj, pNext, j ) {
l = pNext->Level + (Abc_ObjIsNode(pObj) ? 1 : 0);
if ( Abc_NodeIsTravIdCurrent(pNext) &&
(int)pObj->Level < l )
pObj->Level = l;
}
// constrained?
if ((int)pObj->Level > pManMR->maxDelay) {
FSET( pObj, CONSERVATIVE );
pManMR->nConservConstraints++;
} else
FUNSET( pObj, CONSERVATIVE );
}
Vec_PtrClear( vNodes );
}
/**Function*************************************************************
Synopsis [Introduces exact timing constraints for a node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_FlowRetime_ConstrainExact( Abc_Obj_t * pObj ) {
if (FTEST( pObj, CONSERVATIVE )) {
pManMR->nConservConstraints--;
FUNSET( pObj, CONSERVATIVE );
}
#if !defined(IGNORE_TIMING)
if (pManMR->fIsForward) {
Abc_FlowRetime_ConstrainExact_forw(pObj);
} else {
Abc_FlowRetime_ConstrainExact_back(pObj);
}
#endif
}
void Abc_FlowRetime_ConstrainExact_forw_rec( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes, int latch ) {
Abc_Obj_t *pNext;
int i;
// terminate?
if (Abc_ObjIsLatch(pObj)) {
if (latch) return;
latch = 1;
}
// already visited?
if (!latch) {
if (pObj->fMarkA) return;
pObj->fMarkA = 1;
} else {
if (pObj->fMarkB) return;
pObj->fMarkB = 1;
}
// recurse
Abc_ObjForEachFanin(pObj, pNext, i) {
Abc_FlowRetime_ConstrainExact_forw_rec( pNext, vNodes, latch );
}
// add
pObj->Level = 0;
Vec_PtrPush(vNodes, Abc_ObjNotCond(pObj, latch));
}
void Abc_FlowRetime_ConstrainExact_forw( Abc_Obj_t * pObj ) {
Vec_Ptr_t *vNodes = pManMR->vNodes;
Abc_Obj_t *pNext, *pCur, *pReg;
// Abc_Ntk_t *pNtk = pManMR->pNtk;
int i, j;
assert( !Vec_PtrSize(vNodes) );
assert( !Abc_ObjIsLatch(pObj) );
assert( !Vec_PtrSize( FTIMEEDGES(pObj) ));
Vec_PtrPush( pManMR->vExactNodes, pObj );
// rev topo order
Abc_FlowRetime_ConstrainExact_forw_rec( pObj, vNodes, 0 );
Vec_PtrForEachEntryReverse( Abc_Obj_t *, vNodes, pCur, i) {
pReg = Abc_ObjRegular( pCur );
if (pReg == pCur) {
assert(!Abc_ObjIsLatch(pReg));
Abc_ObjForEachFanin(pReg, pNext, j)
pNext->Level = MAX( pNext->Level, pReg->Level + (Abc_ObjIsNode(pReg)?1:0));
assert((int)pReg->Level <= pManMR->maxDelay);
pReg->Level = 0;
pReg->fMarkA = pReg->fMarkB = 0;
}
}
Vec_PtrForEachEntryReverse( Abc_Obj_t *, vNodes, pCur, i) {
pReg = Abc_ObjRegular( pCur );
if (pReg != pCur) {
Abc_ObjForEachFanin(pReg, pNext, j)
if (!Abc_ObjIsLatch(pNext))
pNext->Level = MAX( pNext->Level, pReg->Level + (Abc_ObjIsNode(pReg)?1:0));
if ((int)pReg->Level == pManMR->maxDelay) {
Vec_PtrPush( FTIMEEDGES(pObj), pReg);
pManMR->nExactConstraints++;
}
pReg->Level = 0;
pReg->fMarkA = pReg->fMarkB = 0;
}
}
Vec_PtrClear( vNodes );
}
void Abc_FlowRetime_ConstrainExact_back_rec( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes, int latch ) {
Abc_Obj_t *pNext;
int i;
// terminate?
if (Abc_ObjIsLatch(pObj)) {
if (latch) return;
latch = 1;
}
// already visited?
if (!latch) {
if (pObj->fMarkA) return;
pObj->fMarkA = 1;
} else {
if (pObj->fMarkB) return;
pObj->fMarkB = 1;
}
// recurse
Abc_ObjForEachFanout(pObj, pNext, i) {
Abc_FlowRetime_ConstrainExact_back_rec( pNext, vNodes, latch );
}
// add
pObj->Level = 0;
Vec_PtrPush(vNodes, Abc_ObjNotCond(pObj, latch));
}
void Abc_FlowRetime_ConstrainExact_back( Abc_Obj_t * pObj ) {
Vec_Ptr_t *vNodes = pManMR->vNodes;
Abc_Obj_t *pNext, *pCur, *pReg;
// Abc_Ntk_t *pNtk = pManMR->pNtk;
int i, j;
assert( !Vec_PtrSize( vNodes ));
assert( !Abc_ObjIsLatch(pObj) );
assert( !Vec_PtrSize( FTIMEEDGES(pObj) ));
Vec_PtrPush( pManMR->vExactNodes, pObj );
// rev topo order
Abc_FlowRetime_ConstrainExact_back_rec( pObj, vNodes, 0 );
Vec_PtrForEachEntryReverse( Abc_Obj_t *, vNodes, pCur, i) {
pReg = Abc_ObjRegular( pCur );
if (pReg == pCur) {
assert(!Abc_ObjIsLatch(pReg));
Abc_ObjForEachFanout(pReg, pNext, j)
pNext->Level = MAX( pNext->Level, pReg->Level + (Abc_ObjIsNode(pReg)?1:0));
assert((int)pReg->Level <= pManMR->maxDelay);
pReg->Level = 0;
pReg->fMarkA = pReg->fMarkB = 0;
}
}
Vec_PtrForEachEntryReverse( Abc_Obj_t *, vNodes, pCur, i) {
pReg = Abc_ObjRegular( pCur );
if (pReg != pCur) {
Abc_ObjForEachFanout(pReg, pNext, j)
if (!Abc_ObjIsLatch(pNext))
pNext->Level = MAX( pNext->Level, pReg->Level + (Abc_ObjIsNode(pReg)?1:0));
if ((int)pReg->Level == pManMR->maxDelay) {
Vec_PtrPush( FTIMEEDGES(pObj), pReg);
pManMR->nExactConstraints++;
}
pReg->Level = 0;
pReg->fMarkA = pReg->fMarkB = 0;
}
}
Vec_PtrClear( vNodes );
}
/**Function*************************************************************
Synopsis [Introduces all exact timing constraints in a network]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_FlowRetime_ConstrainExactAll( Abc_Ntk_t * pNtk ) {
int i;
Abc_Obj_t *pObj;
void *pArray;
// free existing constraints
Abc_NtkForEachObj( pNtk, pObj, i )
if ( Vec_PtrSize( FTIMEEDGES(pObj) )) {
pArray = Vec_PtrReleaseArray( FTIMEEDGES(pObj) );
ABC_FREE( pArray );
}
pManMR->nExactConstraints = 0;
// generate all constraints
Abc_NtkForEachObj(pNtk, pObj, i)
if (!Abc_ObjIsLatch(pObj) && FTEST( pObj, CONSERVATIVE ) && !FTEST( pObj, BLOCK ))
if (!Vec_PtrSize( FTIMEEDGES( pObj ) ))
Abc_FlowRetime_ConstrainExact( pObj );
}
/**Function*************************************************************
Synopsis [Deallocates exact constraints.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_FlowRetime_FreeTiming( Abc_Ntk_t *pNtk ) {
Abc_Obj_t *pObj;
void *pArray;
while( Vec_PtrSize( pManMR->vExactNodes )) {
pObj = (Abc_Obj_t*)Vec_PtrPop( pManMR->vExactNodes );
if ( Vec_PtrSize( FTIMEEDGES(pObj) )) {
pArray = Vec_PtrReleaseArray( FTIMEEDGES(pObj) );
ABC_FREE( pArray );
}
}
Vec_PtrFree(pManMR->vExactNodes);
ABC_FREE( pManMR->vTimeEdges );
}
/**Function*************************************************************
Synopsis [DFS order.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_FlowRetime_Dfs_forw( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes ) {
Abc_Obj_t *pNext;
int i;
if (Abc_ObjIsLatch(pObj)) return;
Abc_NodeSetTravIdCurrent( pObj );
Abc_ObjForEachFanout( pObj, pNext, i )
if (!Abc_NodeIsTravIdCurrent( pNext ))
Abc_FlowRetime_Dfs_forw( pNext, vNodes );
Vec_PtrPush( vNodes, pObj );
}
void Abc_FlowRetime_Dfs_back( Abc_Obj_t * pObj, Vec_Ptr_t *vNodes ) {
Abc_Obj_t *pNext;
int i;
if (Abc_ObjIsLatch(pObj)) return;
Abc_NodeSetTravIdCurrent( pObj );
Abc_ObjForEachFanin( pObj, pNext, i )
if (!Abc_NodeIsTravIdCurrent( pNext ))
Abc_FlowRetime_Dfs_back( pNext, vNodes );
Vec_PtrPush( vNodes, pObj );
}
/**Function*************************************************************
Synopsis [Main timing-constrained routine.]
Description [Refines constraints that are limiting area improvement.
These are identified by computing
the min-cuts both with and without the conservative
constraints: these two situation represent an
over- and under-constrained version of the timing.]
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_FlowRetime_RefineConstraints( ) {
Abc_Ntk_t *pNtk = pManMR->pNtk;
int i, flow, count = 0;
Abc_Obj_t *pObj;
int maxTighten = 99999;
vprintf("\t\tsubiter %d : constraints = {cons, exact} = %d, %d\n",
pManMR->subIteration, pManMR->nConservConstraints, pManMR->nExactConstraints);
// 1. overconstrained
pManMR->constraintMask = BLOCK | CONSERVATIVE;
vprintf("\t\trefinement: over ");
fflush(stdout);
flow = Abc_FlowRetime_PushFlows( pNtk, 0 );
vprintf("= %d ", flow);
// remember nodes
if (pManMR->fIsForward) {
Abc_NtkForEachObj( pNtk, pObj, i )
if (!FTEST(pObj, VISITED_R))
pObj->fMarkC = 1;
} else {
Abc_NtkForEachObj( pNtk, pObj, i )
if (!FTEST(pObj, VISITED_E))
pObj->fMarkC = 1;
}
if (pManMR->fConservTimingOnly) {
vprintf(" done\n");
return 0;
}
// 2. underconstrained
pManMR->constraintMask = BLOCK;
Abc_FlowRetime_ClearFlows( 0 );
vprintf("under = ");
fflush(stdout);
flow = Abc_FlowRetime_PushFlows( pNtk, 0 );
vprintf("%d refined nodes = ", flow);
fflush(stdout);
// find area-limiting constraints
if (pManMR->fIsForward) {
Abc_NtkForEachObj( pNtk, pObj, i ) {
if (pObj->fMarkC &&
FTEST(pObj, VISITED_R) &&
FTEST(pObj, CONSERVATIVE) &&
count < maxTighten) {
count++;
Abc_FlowRetime_ConstrainExact( pObj );
}
pObj->fMarkC = 0;
}
} else {
Abc_NtkForEachObj( pNtk, pObj, i ) {
if (pObj->fMarkC &&
FTEST(pObj, VISITED_E) &&
FTEST(pObj, CONSERVATIVE) &&
count < maxTighten) {
count++;
Abc_FlowRetime_ConstrainExact( pObj );
}
pObj->fMarkC = 0;
}
}
vprintf("%d\n", count);
return (count > 0);
}
ABC_NAMESPACE_IMPL_END