mirror of https://github.com/YosysHQ/abc.git
790 lines
24 KiB
C
790 lines
24 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [retFlow.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network and node package.]
|
|
|
|
Synopsis [Implementation of maximum flow (min-area retiming).]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - Oct 31, 2006.]
|
|
|
|
Revision [$Id: retFlow.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "retInt.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static inline int Abc_ObjSetPath( Abc_Obj_t * pObj, Abc_Obj_t * pNext ) { pObj->pCopy = pNext; return 1; }
|
|
static inline Abc_Obj_t * Abc_ObjGetPath( Abc_Obj_t * pObj ) { return pObj->pCopy; }
|
|
static inline Abc_Obj_t * Abc_ObjGetFanoutPath( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pFanout;
|
|
int i;
|
|
assert( Abc_ObjGetPath(pObj) );
|
|
Abc_ObjForEachFanout( pObj, pFanout, i )
|
|
if ( Abc_ObjGetPath(pFanout) == pObj )
|
|
return pFanout;
|
|
return NULL;
|
|
}
|
|
static inline Abc_Obj_t * Abc_ObjGetFaninPath( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pFanin;
|
|
int i;
|
|
assert( Abc_ObjGetPath(pObj) );
|
|
Abc_ObjForEachFanin( pObj, pFanin, i )
|
|
if ( Abc_ObjGetPath(pFanin) == pObj )
|
|
return pFanin;
|
|
return NULL;
|
|
}
|
|
static inline Abc_Obj_t * Abc_ObjGetPredecessorBwd( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pNext;
|
|
int i;
|
|
Abc_ObjForEachFanout( pObj, pNext, i )
|
|
if ( Abc_ObjGetPath(pNext) == pObj )
|
|
return pNext;
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
if ( Abc_ObjGetPath(pNext) == pObj )
|
|
return pNext;
|
|
return NULL;
|
|
}
|
|
static inline Abc_Obj_t * Abc_ObjGetPredecessorFwd( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pNext;
|
|
int i;
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
if ( Abc_ObjGetPath(pNext) == pObj )
|
|
return pNext;
|
|
Abc_ObjForEachFanout( pObj, pNext, i )
|
|
if ( Abc_ObjGetPath(pNext) == pObj )
|
|
return pNext;
|
|
return NULL;
|
|
}
|
|
|
|
static int Abc_NtkMaxFlowBwdPath_rec( Abc_Obj_t * pObj );
|
|
static int Abc_NtkMaxFlowFwdPath_rec( Abc_Obj_t * pObj );
|
|
static int Abc_NtkMaxFlowBwdPath2_rec( Abc_Obj_t * pObj );
|
|
static int Abc_NtkMaxFlowFwdPath2_rec( Abc_Obj_t * pObj );
|
|
//static int Abc_NtkMaxFlowBwdPath3_rec( Abc_Obj_t * pObj );
|
|
static int Abc_NtkMaxFlowFwdPath3_rec( Abc_Obj_t * pObj, Abc_Obj_t * pPrev, int fFanin );
|
|
static Vec_Ptr_t * Abc_NtkMaxFlowMinCut( Abc_Ntk_t * pNtk, int fForward );
|
|
static void Abc_NtkMaxFlowMinCutUpdate( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward );
|
|
static int Abc_NtkMaxFlowVerifyCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward );
|
|
static void Abc_NtkMaxFlowPrintCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut );
|
|
static void Abc_NtkMaxFlowPrintFlow( Abc_Ntk_t * pNtk, int fForward );
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Test-bench for the max-flow computation.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkMaxFlowTest( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vMinCut;
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
|
|
// forward flow
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
pObj->fMarkA = 1;
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
pObj->fMarkA = Abc_ObjFanin0(pObj)->fMarkA = 1;
|
|
// Abc_ObjFanin0(pObj)->fMarkA = 1;
|
|
vMinCut = Abc_NtkMaxFlow( pNtk, 1, 1 );
|
|
Vec_PtrFree( vMinCut );
|
|
Abc_NtkCleanMarkA( pNtk );
|
|
|
|
// backward flow
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
pObj->fMarkA = 1;
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
pObj->fMarkA = Abc_ObjFanout0(pObj)->fMarkA = 1;
|
|
// Abc_ObjFanout0(pObj)->fMarkA = 1;
|
|
vMinCut = Abc_NtkMaxFlow( pNtk, 0, 1 );
|
|
Vec_PtrFree( vMinCut );
|
|
Abc_NtkCleanMarkA( pNtk );
|
|
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Implementation of max-flow/min-cut computation.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkMaxFlow( Abc_Ntk_t * pNtk, int fForward, int fVerbose )
|
|
{
|
|
Vec_Ptr_t * vMinCut;
|
|
Abc_Obj_t * pLatch;
|
|
int Flow, FlowCur, RetValue, i;
|
|
abctime clk = Abc_Clock();
|
|
int fUseDirectedFlow = 1;
|
|
|
|
// find the max-flow
|
|
Abc_NtkCleanCopy( pNtk );
|
|
Flow = 0;
|
|
Abc_NtkIncrementTravId(pNtk);
|
|
Abc_NtkForEachLatch( pNtk, pLatch, i )
|
|
{
|
|
if ( fForward )
|
|
{
|
|
// assert( !Abc_ObjFanout0(pLatch)->fMarkA );
|
|
FlowCur = Abc_NtkMaxFlowFwdPath2_rec( Abc_ObjFanout0(pLatch) );
|
|
// FlowCur = Abc_NtkMaxFlowFwdPath3_rec( Abc_ObjFanout0(pLatch), pLatch, 1 );
|
|
Flow += FlowCur;
|
|
}
|
|
else
|
|
{
|
|
assert( !Abc_ObjFanin0(pLatch)->fMarkA );
|
|
FlowCur = Abc_NtkMaxFlowBwdPath2_rec( Abc_ObjFanin0(pLatch) );
|
|
Flow += FlowCur;
|
|
}
|
|
if ( FlowCur )
|
|
Abc_NtkIncrementTravId(pNtk);
|
|
}
|
|
|
|
if ( !fUseDirectedFlow )
|
|
{
|
|
Abc_NtkIncrementTravId(pNtk);
|
|
Abc_NtkForEachLatch( pNtk, pLatch, i )
|
|
{
|
|
if ( fForward )
|
|
{
|
|
// assert( !Abc_ObjFanout0(pLatch)->fMarkA );
|
|
FlowCur = Abc_NtkMaxFlowFwdPath_rec( Abc_ObjFanout0(pLatch) );
|
|
Flow += FlowCur;
|
|
}
|
|
else
|
|
{
|
|
assert( !Abc_ObjFanin0(pLatch)->fMarkA );
|
|
FlowCur = Abc_NtkMaxFlowBwdPath_rec( Abc_ObjFanin0(pLatch) );
|
|
Flow += FlowCur;
|
|
}
|
|
if ( FlowCur )
|
|
Abc_NtkIncrementTravId(pNtk);
|
|
}
|
|
}
|
|
// Abc_NtkMaxFlowPrintFlow( pNtk, fForward );
|
|
|
|
// mark the nodes reachable from the latches
|
|
Abc_NtkIncrementTravId(pNtk);
|
|
Abc_NtkForEachLatch( pNtk, pLatch, i )
|
|
{
|
|
if ( fForward )
|
|
{
|
|
// assert( !Abc_ObjFanout0(pLatch)->fMarkA );
|
|
if ( fUseDirectedFlow )
|
|
RetValue = Abc_NtkMaxFlowFwdPath2_rec( Abc_ObjFanout0(pLatch) );
|
|
// RetValue = Abc_NtkMaxFlowFwdPath3_rec( Abc_ObjFanout0(pLatch), pLatch, 1 );
|
|
else
|
|
RetValue = Abc_NtkMaxFlowFwdPath_rec( Abc_ObjFanout0(pLatch) );
|
|
}
|
|
else
|
|
{
|
|
assert( !Abc_ObjFanin0(pLatch)->fMarkA );
|
|
if ( fUseDirectedFlow )
|
|
RetValue = Abc_NtkMaxFlowBwdPath2_rec( Abc_ObjFanin0(pLatch) );
|
|
else
|
|
RetValue = Abc_NtkMaxFlowBwdPath_rec( Abc_ObjFanin0(pLatch) );
|
|
}
|
|
assert( RetValue == 0 );
|
|
}
|
|
|
|
// find the min-cut with the smallest volume
|
|
vMinCut = Abc_NtkMaxFlowMinCut( pNtk, fForward );
|
|
// verify the cut
|
|
if ( !Abc_NtkMaxFlowVerifyCut(pNtk, vMinCut, fForward) )
|
|
printf( "Abc_NtkMaxFlow() error! The computed min-cut is not a cut!\n" );
|
|
// make the cut retimable
|
|
Abc_NtkMaxFlowMinCutUpdate( pNtk, vMinCut, fForward );
|
|
|
|
// report the results
|
|
if ( fVerbose )
|
|
{
|
|
printf( "L = %6d. %s max-flow = %6d. Min-cut = %6d. ",
|
|
Abc_NtkLatchNum(pNtk), fForward? "Forward " : "Backward", Flow, Vec_PtrSize(vMinCut) );
|
|
ABC_PRT( "Time", Abc_Clock() - clk );
|
|
}
|
|
|
|
// Abc_NtkMaxFlowPrintCut( pNtk, vMinCut );
|
|
return vMinCut;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Tries to find an augmenting path originating in this node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkMaxFlowBwdPath_rec( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pNext, * pPred;
|
|
int i;
|
|
// skip visited nodes
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return 0;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// get the predecessor
|
|
pPred = Abc_ObjGetPredecessorBwd( pObj );
|
|
// process node without flow
|
|
if ( !Abc_ObjGetPath(pObj) )
|
|
{
|
|
// start the path if we reached a terminal node
|
|
if ( pObj->fMarkA )
|
|
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
|
|
// explore the fanins
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec(pNext) )
|
|
return Abc_ObjSetPath( pObj, pNext );
|
|
Abc_ObjForEachFanout( pObj, pNext, i )
|
|
if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec(pNext) )
|
|
return Abc_ObjSetPath( pObj, pNext );
|
|
return 0;
|
|
}
|
|
// pObj has flow - find the fanout with flow
|
|
if ( pPred == NULL )
|
|
return 0;
|
|
// go through the successors of the predecessor
|
|
Abc_ObjForEachFanin( pPred, pNext, i )
|
|
if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec( pNext ) )
|
|
return Abc_ObjSetPath( pPred, pNext );
|
|
Abc_ObjForEachFanout( pPred, pNext, i )
|
|
if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec( pNext ) )
|
|
return Abc_ObjSetPath( pPred, pNext );
|
|
// try the fanout
|
|
if ( Abc_NtkMaxFlowBwdPath_rec( pPred ) )
|
|
return Abc_ObjSetPath( pPred, NULL );
|
|
return 0;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Tries to find an augmenting path originating in this node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkMaxFlowFwdPath_rec( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pNext, * pPred;
|
|
int i;
|
|
// skip visited nodes
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return 0;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// get the predecessor
|
|
pPred = Abc_ObjGetPredecessorFwd( pObj );
|
|
// process node without flow
|
|
if ( !Abc_ObjGetPath(pObj) )
|
|
{
|
|
// start the path if we reached a terminal node
|
|
if ( pObj->fMarkA )
|
|
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
|
|
// explore the fanins
|
|
Abc_ObjForEachFanout( pObj, pNext, i )
|
|
if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec(pNext) )
|
|
return Abc_ObjSetPath( pObj, pNext );
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec(pNext) )
|
|
return Abc_ObjSetPath( pObj, pNext );
|
|
return 0;
|
|
}
|
|
// pObj has flow - find the fanout with flow
|
|
if ( pPred == NULL )
|
|
return 0;
|
|
// go through the successors of the predecessor
|
|
Abc_ObjForEachFanout( pPred, pNext, i )
|
|
if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec( pNext ) )
|
|
return Abc_ObjSetPath( pPred, pNext );
|
|
Abc_ObjForEachFanin( pPred, pNext, i )
|
|
if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec( pNext ) )
|
|
return Abc_ObjSetPath( pPred, pNext );
|
|
// try the fanout
|
|
if ( Abc_NtkMaxFlowFwdPath_rec( pPred ) )
|
|
return Abc_ObjSetPath( pPred, NULL );
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Tries to find an augmenting path originating in this edge.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkMaxFlowFwdPath3_rec( Abc_Obj_t * pObj, Abc_Obj_t * pPrev, int fFanin )
|
|
{
|
|
Abc_Obj_t * pFanin, * pFanout;
|
|
int i;
|
|
// skip visited nodes
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return 0;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// skip the fanin which already has flow
|
|
if ( fFanin && Abc_ObjGetPath(pPrev) )
|
|
return 0;
|
|
// if the node has no flow, try to push through the fanouts
|
|
if ( !Abc_ObjGetPath(pObj) )
|
|
{
|
|
// start the path if we reached a terminal node
|
|
if ( pObj->fMarkA )
|
|
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
|
|
// try to push flow through the fanouts
|
|
Abc_ObjForEachFanout( pObj, pFanout, i )
|
|
if ( Abc_NtkMaxFlowFwdPath3_rec(pFanout, pObj, 1) )
|
|
return fFanin? Abc_ObjSetPath(pPrev, pObj) : 1;
|
|
}
|
|
// try to push through the fanins
|
|
Abc_ObjForEachFanin( pObj, pFanin, i )
|
|
if ( !Abc_ObjIsLatch(pFanin) && Abc_NtkMaxFlowFwdPath3_rec(pFanin, pObj, 0) )
|
|
return Abc_ObjSetPath( pFanin, NULL );
|
|
return 0;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Tries to find an augmenting path originating in this node.]
|
|
|
|
Description [This procedure works for directed graphs only!]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkMaxFlowBwdPath2_rec( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pFanout, * pFanin;
|
|
int i;
|
|
// skip visited nodes
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return 0;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// process node without flow
|
|
if ( !Abc_ObjGetPath(pObj) )
|
|
{
|
|
// start the path if we reached a terminal node
|
|
if ( pObj->fMarkA )
|
|
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
|
|
// explore the fanins
|
|
Abc_ObjForEachFanin( pObj, pFanin, i )
|
|
if ( Abc_NtkMaxFlowBwdPath2_rec(pFanin) )
|
|
return Abc_ObjSetPath( pObj, pFanin );
|
|
return 0;
|
|
}
|
|
// pObj has flow - find the fanout with flow
|
|
pFanout = Abc_ObjGetFanoutPath( pObj );
|
|
if ( pFanout == NULL )
|
|
return 0;
|
|
// go through the fanins of the fanout with flow
|
|
Abc_ObjForEachFanin( pFanout, pFanin, i )
|
|
if ( Abc_NtkMaxFlowBwdPath2_rec( pFanin ) )
|
|
return Abc_ObjSetPath( pFanout, pFanin );
|
|
// try the fanout
|
|
if ( Abc_NtkMaxFlowBwdPath2_rec( pFanout ) )
|
|
return Abc_ObjSetPath( pFanout, NULL );
|
|
return 0;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Tries to find an augmenting path originating in this node.]
|
|
|
|
Description [This procedure works for directed graphs only!]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkMaxFlowFwdPath2_rec( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pFanout, * pFanin;
|
|
int i;
|
|
// skip visited nodes
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return 0;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// process node without flow
|
|
if ( !Abc_ObjGetPath(pObj) )
|
|
{
|
|
// start the path if we reached a terminal node
|
|
if ( pObj->fMarkA )
|
|
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
|
|
// explore the fanins
|
|
Abc_ObjForEachFanout( pObj, pFanout, i )
|
|
if ( Abc_NtkMaxFlowFwdPath2_rec(pFanout) )
|
|
return Abc_ObjSetPath( pObj, pFanout );
|
|
return 0;
|
|
}
|
|
// pObj has flow - find the fanout with flow
|
|
pFanin = Abc_ObjGetFaninPath( pObj );
|
|
if ( pFanin == NULL )
|
|
return 0;
|
|
// go through the fanins of the fanout with flow
|
|
Abc_ObjForEachFanout( pFanin, pFanout, i )
|
|
if ( Abc_NtkMaxFlowFwdPath2_rec( pFanout ) )
|
|
return Abc_ObjSetPath( pFanin, pFanout );
|
|
// try the fanout
|
|
if ( Abc_NtkMaxFlowFwdPath2_rec( pFanin ) )
|
|
return Abc_ObjSetPath( pFanin, NULL );
|
|
return 0;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Find minimum-volume minumum cut.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkMaxFlowMinCut( Abc_Ntk_t * pNtk, int fForward )
|
|
{
|
|
Vec_Ptr_t * vMinCut;
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
// collect the cut nodes
|
|
vMinCut = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) );
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
{
|
|
// node without flow is not a cut node
|
|
if ( !Abc_ObjGetPath(pObj) )
|
|
continue;
|
|
// unvisited node is below the cut
|
|
if ( !Abc_NodeIsTravIdCurrent(pObj) )
|
|
continue;
|
|
// add terminal with flow or node whose path is not visited
|
|
if ( pObj->fMarkA || !Abc_NodeIsTravIdCurrent( Abc_ObjGetPath(pObj) ) )
|
|
Vec_PtrPush( vMinCut, pObj );
|
|
}
|
|
return vMinCut;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Marks the TFI cone with MarkA.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkMaxFlowMarkCut_rec( Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pNext;
|
|
int i;
|
|
if ( pObj->fMarkA )
|
|
return;
|
|
pObj->fMarkA = 1;
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
Abc_NtkMaxFlowMarkCut_rec( pNext );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Visits the TFI up to marked nodes and collects marked nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkMaxFlowCollectCut_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vNodes )
|
|
{
|
|
Abc_Obj_t * pNext;
|
|
int i;
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
if ( pObj->fMarkA )
|
|
{
|
|
Vec_PtrPush( vNodes, pObj );
|
|
return;
|
|
}
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
Abc_NtkMaxFlowCollectCut_rec( pNext, vNodes );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Updates the minimum cut to be retimable.]
|
|
|
|
Description [This procedure also labels the nodes reachable from
|
|
the latches to the cut with fMarkA.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkMaxFlowMinCutUpdate( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward )
|
|
{
|
|
Abc_Obj_t * pObj, * pNext;
|
|
int i, k;
|
|
// clean marks
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
pObj->fMarkA = 0;
|
|
// set latch outputs
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
Abc_ObjFanout0(pObj)->fMarkA = 1;
|
|
// traverse from cut nodes
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vMinCut, pObj, i )
|
|
Abc_NtkMaxFlowMarkCut_rec( pObj );
|
|
if ( fForward )
|
|
{
|
|
// change mincut to be nodes with unmarked fanouts
|
|
Vec_PtrClear( vMinCut );
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
{
|
|
if ( !pObj->fMarkA )
|
|
continue;
|
|
Abc_ObjForEachFanout( pObj, pNext, k )
|
|
{
|
|
if ( pNext->fMarkA )
|
|
continue;
|
|
Vec_PtrPush( vMinCut, pObj );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// change mincut to be marked fanins of the unmarked nodes
|
|
Vec_PtrClear( vMinCut );
|
|
Abc_NtkIncrementTravId(pNtk);
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
Abc_NtkMaxFlowCollectCut_rec( Abc_ObjFanin0(pObj), vMinCut );
|
|
// transfer the attribute
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
pObj->fMarkA = Abc_NodeIsTravIdCurrent(pObj);
|
|
// unmark the cut nodes
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vMinCut, pObj, i )
|
|
pObj->fMarkA = 0;
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Verifies the min-cut is indeed a cut.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkMaxFlowVerifyCut_rec( Abc_Obj_t * pObj, int fForward )
|
|
{
|
|
Abc_Obj_t * pNext;
|
|
int i;
|
|
// skip visited nodes
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return 1;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// visit the node
|
|
if ( fForward )
|
|
{
|
|
if ( Abc_ObjIsCo(pObj) )
|
|
return 0;
|
|
// explore the fanouts
|
|
Abc_ObjForEachFanout( pObj, pNext, i )
|
|
if ( !Abc_NtkMaxFlowVerifyCut_rec(pNext, fForward) )
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ( Abc_ObjIsCi(pObj) )
|
|
return 0;
|
|
// explore the fanins
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
if ( !Abc_NtkMaxFlowVerifyCut_rec(pNext, fForward) )
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Verifies the min-cut is indeed a cut.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkMaxFlowVerifyCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
// mark the cut with the current traversal ID
|
|
Abc_NtkIncrementTravId(pNtk);
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vMinCut, pObj, i )
|
|
Abc_NodeSetTravIdCurrent( pObj );
|
|
// search from the latches for a path to the COs/CIs
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
{
|
|
if ( fForward )
|
|
{
|
|
if ( !Abc_NtkMaxFlowVerifyCut_rec( Abc_ObjFanout0(pObj), fForward ) )
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ( !Abc_NtkMaxFlowVerifyCut_rec( Abc_ObjFanin0(pObj), fForward ) )
|
|
return 0;
|
|
}
|
|
}
|
|
/*
|
|
{
|
|
// count the volume of the cut
|
|
int Counter = 0;
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
Counter += Abc_NodeIsTravIdCurrent( pObj );
|
|
printf( "Volume = %d.\n", Counter );
|
|
}
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Prints the flows.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkMaxFlowPrintFlow( Abc_Ntk_t * pNtk, int fForward )
|
|
{
|
|
Abc_Obj_t * pLatch, * pNext;
|
|
Abc_Obj_t * pPrev = NULL; // Suppress "might be used uninitialized"
|
|
int i;
|
|
if ( fForward )
|
|
{
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, pNtk->vBoxes, pLatch, i )
|
|
{
|
|
assert( !Abc_ObjFanout0(pLatch)->fMarkA );
|
|
if ( Abc_ObjGetPath(Abc_ObjFanout0(pLatch)) == NULL ) // no flow through this latch
|
|
continue;
|
|
printf( "Path = " );
|
|
for ( pNext = Abc_ObjFanout0(pLatch); pNext != (void *)1; pNext = Abc_ObjGetPath(pNext) )
|
|
{
|
|
printf( "%s(%d) ", Abc_ObjName(pNext), pNext->Id );
|
|
pPrev = pNext;
|
|
}
|
|
if ( !Abc_ObjIsPo(pPrev) )
|
|
printf( "%s(%d) ", Abc_ObjName(Abc_ObjFanout0(pPrev)), Abc_ObjFanout0(pPrev)->Id );
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, pNtk->vBoxes, pLatch, i )
|
|
{
|
|
assert( !Abc_ObjFanin0(pLatch)->fMarkA );
|
|
if ( Abc_ObjGetPath(Abc_ObjFanin0(pLatch)) == NULL ) // no flow through this latch
|
|
continue;
|
|
printf( "Path = " );
|
|
for ( pNext = Abc_ObjFanin0(pLatch); pNext != (void *)1; pNext = Abc_ObjGetPath(pNext) )
|
|
{
|
|
printf( "%s(%d) ", Abc_ObjName(pNext), pNext->Id );
|
|
pPrev = pNext;
|
|
}
|
|
if ( !Abc_ObjIsPi(pPrev) )
|
|
printf( "%s(%d) ", Abc_ObjName(Abc_ObjFanin0(pPrev)), Abc_ObjFanin0(pPrev)->Id );
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Prints the min-cut.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkMaxFlowPrintCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
printf( "Min-cut: " );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vMinCut, pObj, i )
|
|
printf( "%s(%d) ", Abc_ObjName(pObj), pObj->Id );
|
|
printf( "\n" );
|
|
printf( "Marked nodes: " );
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
if ( pObj->fMarkA )
|
|
printf( "%s(%d) ", Abc_ObjName(pObj), pObj->Id );
|
|
printf( "\n" );
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|