mirror of https://github.com/YosysHQ/abc.git
1899 lines
64 KiB
C
1899 lines
64 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [abcPart.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network and node package.]
|
|
|
|
Synopsis [Output partitioning package.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: abcPart.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "base/abc/abc.h"
|
|
#include "base/main/main.h"
|
|
#include "base/cmd/cmd.h"
|
|
#include "map/mio/mio.h"
|
|
|
|
#ifdef WIN32
|
|
#include <process.h>
|
|
#define unlink _unlink
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct Supp_Man_t_ Supp_Man_t;
|
|
struct Supp_Man_t_
|
|
{
|
|
int nChunkSize; // the size of one chunk of memory (~1 MB)
|
|
int nStepSize; // the step size in saving memory (~64 bytes)
|
|
char * pFreeBuf; // the pointer to free memory
|
|
int nFreeSize; // the size of remaining free memory
|
|
Vec_Ptr_t * vMemory; // the memory allocated
|
|
Vec_Ptr_t * vFree; // the vector of free pieces of memory
|
|
};
|
|
|
|
typedef struct Supp_One_t_ Supp_One_t;
|
|
struct Supp_One_t_
|
|
{
|
|
int nRefs; // the number of references
|
|
int nOuts; // the number of outputs
|
|
int nOutsAlloc; // the array size
|
|
int pOuts[0]; // the array of outputs
|
|
};
|
|
|
|
static inline int Supp_SizeType( int nSize, int nStepSize ) { return nSize / nStepSize + ((nSize % nStepSize) > 0); }
|
|
static inline char * Supp_OneNext( char * pPart ) { return *((char **)pPart); }
|
|
static inline void Supp_OneSetNext( char * pPart, char * pNext ) { *((char **)pPart) = pNext; }
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Start the memory manager.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Supp_Man_t * Supp_ManStart( int nChunkSize, int nStepSize )
|
|
{
|
|
Supp_Man_t * p;
|
|
p = ABC_ALLOC( Supp_Man_t, 1 );
|
|
memset( p, 0, sizeof(Supp_Man_t) );
|
|
p->nChunkSize = nChunkSize;
|
|
p->nStepSize = nStepSize;
|
|
p->vMemory = Vec_PtrAlloc( 1000 );
|
|
p->vFree = Vec_PtrAlloc( 1000 );
|
|
return p;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Stops the memory manager.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Supp_ManStop( Supp_Man_t * p )
|
|
{
|
|
void * pMemory;
|
|
int i;
|
|
Vec_PtrForEachEntry( void *, p->vMemory, pMemory, i )
|
|
ABC_FREE( pMemory );
|
|
Vec_PtrFree( p->vMemory );
|
|
Vec_PtrFree( p->vFree );
|
|
ABC_FREE( p );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Fetches the memory entry of the given size.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
char * Supp_ManFetch( Supp_Man_t * p, int nSize )
|
|
{
|
|
int Type, nSizeReal;
|
|
char * pMemory;
|
|
assert( nSize > 0 );
|
|
Type = Supp_SizeType( nSize, p->nStepSize );
|
|
Vec_PtrFillExtra( p->vFree, Type + 1, NULL );
|
|
if ( (pMemory = (char *)Vec_PtrEntry( p->vFree, Type )) )
|
|
{
|
|
Vec_PtrWriteEntry( p->vFree, Type, Supp_OneNext(pMemory) );
|
|
return pMemory;
|
|
}
|
|
nSizeReal = p->nStepSize * Type;
|
|
if ( p->nFreeSize < nSizeReal )
|
|
{
|
|
p->pFreeBuf = ABC_ALLOC( char, p->nChunkSize );
|
|
p->nFreeSize = p->nChunkSize;
|
|
Vec_PtrPush( p->vMemory, p->pFreeBuf );
|
|
}
|
|
assert( p->nFreeSize >= nSizeReal );
|
|
pMemory = p->pFreeBuf;
|
|
p->pFreeBuf += nSizeReal;
|
|
p->nFreeSize -= nSizeReal;
|
|
return pMemory;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Recycles the memory entry of the given size.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Supp_ManRecycle( Supp_Man_t * p, char * pMemory, int nSize )
|
|
{
|
|
int Type;
|
|
Type = Supp_SizeType( nSize, p->nStepSize );
|
|
Vec_PtrFillExtra( p->vFree, Type + 1, NULL );
|
|
Supp_OneSetNext( pMemory, (char *)Vec_PtrEntry(p->vFree, Type) );
|
|
Vec_PtrWriteEntry( p->vFree, Type, pMemory );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Fetches the memory entry of the given size.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline Supp_One_t * Supp_ManFetchEntry( Supp_Man_t * p, int nWords, int nRefs )
|
|
{
|
|
Supp_One_t * pPart;
|
|
pPart = (Supp_One_t *)Supp_ManFetch( p, sizeof(Supp_One_t) + sizeof(int) * nWords );
|
|
pPart->nRefs = nRefs;
|
|
pPart->nOuts = 0;
|
|
pPart->nOutsAlloc = nWords;
|
|
return pPart;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Recycles the memory entry of the given size.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline void Supp_ManRecycleEntry( Supp_Man_t * p, Supp_One_t * pEntry )
|
|
{
|
|
assert( pEntry->nOuts <= pEntry->nOutsAlloc );
|
|
assert( pEntry->nOuts >= pEntry->nOutsAlloc/2 );
|
|
Supp_ManRecycle( p, (char *)pEntry, sizeof(Supp_One_t) + sizeof(int) * pEntry->nOutsAlloc );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Merges two entries.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Supp_One_t * Supp_ManMergeEntry( Supp_Man_t * pMan, Supp_One_t * p1, Supp_One_t * p2, int nRefs )
|
|
{
|
|
Supp_One_t * p = Supp_ManFetchEntry( pMan, p1->nOuts + p2->nOuts, nRefs );
|
|
int * pBeg1 = p1->pOuts;
|
|
int * pBeg2 = p2->pOuts;
|
|
int * pBeg = p->pOuts;
|
|
int * pEnd1 = p1->pOuts + p1->nOuts;
|
|
int * pEnd2 = p2->pOuts + p2->nOuts;
|
|
while ( pBeg1 < pEnd1 && pBeg2 < pEnd2 )
|
|
{
|
|
if ( *pBeg1 == *pBeg2 )
|
|
*pBeg++ = *pBeg1++, pBeg2++;
|
|
else if ( *pBeg1 < *pBeg2 )
|
|
*pBeg++ = *pBeg1++;
|
|
else
|
|
*pBeg++ = *pBeg2++;
|
|
}
|
|
while ( pBeg1 < pEnd1 )
|
|
*pBeg++ = *pBeg1++;
|
|
while ( pBeg2 < pEnd2 )
|
|
*pBeg++ = *pBeg2++;
|
|
p->nOuts = pBeg - p->pOuts;
|
|
assert( p->nOuts <= p->nOutsAlloc );
|
|
assert( p->nOuts >= p1->nOuts );
|
|
assert( p->nOuts >= p2->nOuts );
|
|
return p;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Tranfers the entry.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Int_t * Supp_ManTransferEntry( Supp_One_t * p )
|
|
{
|
|
Vec_Int_t * vSupp;
|
|
int i;
|
|
vSupp = Vec_IntAlloc( p->nOuts );
|
|
for ( i = 0; i < p->nOuts; i++ )
|
|
Vec_IntPush( vSupp, p->pOuts[i] );
|
|
return vSupp;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes supports of the POs in the multi-output AIG.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkDfsNatural( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vNodes;
|
|
Abc_Obj_t * pObj, * pNext;
|
|
int i, k;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
vNodes = Vec_PtrAlloc( Abc_NtkObjNum(pNtk) );
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
// add the constant-1 nodes
|
|
pObj = Abc_AigConst1(pNtk);
|
|
Abc_NodeSetTravIdCurrent( pObj );
|
|
Vec_PtrPush( vNodes, pObj );
|
|
// add the CIs/nodes/COs in the topological order
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
{
|
|
// check the fanins and add CIs
|
|
Abc_ObjForEachFanin( pObj, pNext, k )
|
|
if ( Abc_ObjIsCi(pNext) && !Abc_NodeIsTravIdCurrent(pNext) )
|
|
{
|
|
Abc_NodeSetTravIdCurrent( pNext );
|
|
Vec_PtrPush( vNodes, pNext );
|
|
}
|
|
// add the node
|
|
Vec_PtrPush( vNodes, pObj );
|
|
// check the fanouts and add COs
|
|
Abc_ObjForEachFanout( pObj, pNext, k )
|
|
if ( Abc_ObjIsCo(pNext) && !Abc_NodeIsTravIdCurrent(pNext) )
|
|
{
|
|
Abc_NodeSetTravIdCurrent( pNext );
|
|
Vec_PtrPush( vNodes, pNext );
|
|
}
|
|
}
|
|
return vNodes;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes supports of the POs.]
|
|
|
|
Description [Returns the ptr-vector of int-vectors.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkComputeSupportsSmart( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vSupports;
|
|
Vec_Ptr_t * vNodes;
|
|
Vec_Int_t * vSupp;
|
|
Supp_Man_t * p;
|
|
Supp_One_t * pPart0, * pPart1;
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
// set the number of PIs/POs
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
pObj->pNext = (Abc_Obj_t *)(ABC_PTRINT_T)i;
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
pObj->pNext = (Abc_Obj_t *)(ABC_PTRINT_T)i;
|
|
// start the support computation manager
|
|
p = Supp_ManStart( 1 << 20, 1 << 6 );
|
|
// consider objects in the topological order
|
|
vSupports = Vec_PtrAlloc( Abc_NtkCoNum(pNtk) );
|
|
Abc_NtkCleanCopy(pNtk);
|
|
// order the nodes so that the PIs and POs follow naturally
|
|
vNodes = Abc_NtkDfsNatural( pNtk );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
|
|
{
|
|
if ( Abc_ObjIsNode(pObj) )
|
|
{
|
|
pPart0 = (Supp_One_t *)Abc_ObjFanin0(pObj)->pCopy;
|
|
pPart1 = (Supp_One_t *)Abc_ObjFanin1(pObj)->pCopy;
|
|
pObj->pCopy = (Abc_Obj_t *)Supp_ManMergeEntry( p, pPart0, pPart1, Abc_ObjFanoutNum(pObj) );
|
|
assert( pPart0->nRefs > 0 );
|
|
if ( --pPart0->nRefs == 0 )
|
|
Supp_ManRecycleEntry( p, pPart0 );
|
|
assert( pPart1->nRefs > 0 );
|
|
if ( --pPart1->nRefs == 0 )
|
|
Supp_ManRecycleEntry( p, pPart1 );
|
|
continue;
|
|
}
|
|
if ( Abc_ObjIsCo(pObj) )
|
|
{
|
|
pPart0 = (Supp_One_t *)Abc_ObjFanin0(pObj)->pCopy;
|
|
// only save the CO if it is non-trivial
|
|
if ( Abc_ObjIsNode(Abc_ObjFanin0(pObj)) )
|
|
{
|
|
vSupp = Supp_ManTransferEntry(pPart0);
|
|
Vec_IntPush( vSupp, (int)(ABC_PTRINT_T)pObj->pNext );
|
|
Vec_PtrPush( vSupports, vSupp );
|
|
}
|
|
assert( pPart0->nRefs > 0 );
|
|
if ( --pPart0->nRefs == 0 )
|
|
Supp_ManRecycleEntry( p, pPart0 );
|
|
continue;
|
|
}
|
|
if ( Abc_ObjIsCi(pObj) )
|
|
{
|
|
if ( Abc_ObjFanoutNum(pObj) )
|
|
{
|
|
pPart0 = (Supp_One_t *)Supp_ManFetchEntry( p, 1, Abc_ObjFanoutNum(pObj) );
|
|
pPart0->pOuts[ pPart0->nOuts++ ] = (int)(ABC_PTRINT_T)pObj->pNext;
|
|
pObj->pCopy = (Abc_Obj_t *)pPart0;
|
|
}
|
|
continue;
|
|
}
|
|
if ( pObj == Abc_AigConst1(pNtk) )
|
|
{
|
|
if ( Abc_ObjFanoutNum(pObj) )
|
|
pObj->pCopy = (Abc_Obj_t *)Supp_ManFetchEntry( p, 0, Abc_ObjFanoutNum(pObj) );
|
|
continue;
|
|
}
|
|
assert( 0 );
|
|
}
|
|
Vec_PtrFree( vNodes );
|
|
//printf( "Memory usage = %d MB.\n", Vec_PtrSize(p->vMemory) * p->nChunkSize / (1<<20) );
|
|
Supp_ManStop( p );
|
|
// sort supports by size
|
|
Vec_VecSort( (Vec_Vec_t *)vSupports, 1 );
|
|
// clear the number of PIs/POs
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
pObj->pNext = NULL;
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
pObj->pNext = NULL;
|
|
/*
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vSupports, vSupp, i )
|
|
printf( "%d ", Vec_IntSize(vSupp) );
|
|
printf( "\n" );
|
|
*/
|
|
return vSupports;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes supports of the POs using naive method.]
|
|
|
|
Description [Returns the ptr-vector of int-vectors.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkComputeSupportsNaive( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vSupp, * vSupports;
|
|
Vec_Int_t * vSuppI;
|
|
Abc_Obj_t * pObj, * pTemp;
|
|
int i, k;
|
|
// set the PI numbers
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
pObj->pNext = (Abc_Obj_t *)(ABC_PTRINT_T)i;
|
|
// save the CI numbers
|
|
vSupports = Vec_PtrAlloc( Abc_NtkCoNum(pNtk) );
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
{
|
|
if ( !Abc_ObjIsNode(Abc_ObjFanin0(pObj)) )
|
|
continue;
|
|
vSupp = Abc_NtkNodeSupport( pNtk, &pObj, 1 );
|
|
vSuppI = (Vec_Int_t *)vSupp;
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vSupp, pTemp, k )
|
|
Vec_IntWriteEntry( vSuppI, k, (int)(ABC_PTRINT_T)pTemp->pNext );
|
|
Vec_IntSort( vSuppI, 0 );
|
|
// append the number of this output
|
|
Vec_IntPush( vSuppI, i );
|
|
// save the support in the vector
|
|
Vec_PtrPush( vSupports, vSuppI );
|
|
}
|
|
// clean the CI numbers
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
pObj->pNext = NULL;
|
|
// sort supports by size
|
|
Vec_VecSort( (Vec_Vec_t *)vSupports, 1 );
|
|
/*
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vSupports, vSuppI, i )
|
|
printf( "%d ", Vec_IntSize(vSuppI) );
|
|
printf( "\n" );
|
|
*/
|
|
return vSupports;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Start bitwise support representation.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
unsigned * Abc_NtkSuppCharStart( Vec_Int_t * vOne, int nPis )
|
|
{
|
|
unsigned * pBuffer;
|
|
int i, Entry;
|
|
int nWords = Abc_BitWordNum(nPis);
|
|
pBuffer = ABC_ALLOC( unsigned, nWords );
|
|
memset( pBuffer, 0, sizeof(unsigned) * nWords );
|
|
Vec_IntForEachEntry( vOne, Entry, i )
|
|
{
|
|
assert( Entry < nPis );
|
|
Abc_InfoSetBit( pBuffer, Entry );
|
|
}
|
|
return pBuffer;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Add to bitwise support representation.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkSuppCharAdd( unsigned * pBuffer, Vec_Int_t * vOne, int nPis )
|
|
{
|
|
int i, Entry;
|
|
Vec_IntForEachEntry( vOne, Entry, i )
|
|
{
|
|
assert( Entry < nPis );
|
|
Abc_InfoSetBit( pBuffer, Entry );
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Find the common variables using bitwise support representation.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkSuppCharCommon( unsigned * pBuffer, Vec_Int_t * vOne )
|
|
{
|
|
int i, Entry, nCommon = 0;
|
|
Vec_IntForEachEntry( vOne, Entry, i )
|
|
nCommon += Abc_InfoHasBit(pBuffer, Entry);
|
|
return nCommon;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Find the best partition.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkPartitionSmartFindPart( Vec_Ptr_t * vPartSuppsAll, Vec_Ptr_t * vPartsAll, Vec_Ptr_t * vPartSuppsChar, int nSuppSizeLimit, Vec_Int_t * vOne )
|
|
{
|
|
/*
|
|
Vec_Int_t * vPartSupp, * vPart;
|
|
double Attract, Repulse, Cost, CostBest;
|
|
int i, nCommon, iBest;
|
|
iBest = -1;
|
|
CostBest = 0.0;
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vPartSupp, i )
|
|
{
|
|
vPart = Vec_PtrEntry( vPartsAll, i );
|
|
if ( nPartSizeLimit > 0 && Vec_IntSize(vPart) >= nPartSizeLimit )
|
|
continue;
|
|
nCommon = Vec_IntTwoCountCommon( vPartSupp, vOne );
|
|
if ( nCommon == 0 )
|
|
continue;
|
|
if ( nCommon == Vec_IntSize(vOne) )
|
|
return i;
|
|
Attract = 1.0 * nCommon / Vec_IntSize(vOne);
|
|
if ( Vec_IntSize(vPartSupp) < 100 )
|
|
Repulse = 1.0;
|
|
else
|
|
Repulse = log10( Vec_IntSize(vPartSupp) / 10.0 );
|
|
Cost = pow( Attract, pow(Repulse, 5.0) );
|
|
if ( CostBest < Cost )
|
|
{
|
|
CostBest = Cost;
|
|
iBest = i;
|
|
}
|
|
}
|
|
if ( CostBest < 0.6 )
|
|
return -1;
|
|
return iBest;
|
|
*/
|
|
|
|
Vec_Int_t * vPartSupp;//, * vPart;
|
|
int Attract, Repulse, Value, ValueBest;
|
|
int i, nCommon, iBest;
|
|
// int nCommon2;
|
|
iBest = -1;
|
|
ValueBest = 0;
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vPartSupp, i )
|
|
{
|
|
// skip partitions with too many outputs
|
|
// vPart = Vec_PtrEntry( vPartsAll, i );
|
|
// if ( nSuppSizeLimit > 0 && Vec_IntSize(vPart) >= nSuppSizeLimit )
|
|
// continue;
|
|
// find the number of common variables between this output and the partitions
|
|
// nCommon2 = Vec_IntTwoCountCommon( vPartSupp, vOne );
|
|
nCommon = Abc_NtkSuppCharCommon( (unsigned *)Vec_PtrEntry(vPartSuppsChar, i), vOne );
|
|
// assert( nCommon2 == nCommon );
|
|
// if no common variables, continue searching
|
|
if ( nCommon == 0 )
|
|
continue;
|
|
// if all variables are common, the best partition if found
|
|
if ( nCommon == Vec_IntSize(vOne) )
|
|
return i;
|
|
// skip partitions whose size exceeds the limit
|
|
if ( nSuppSizeLimit > 0 && Vec_IntSize(vPartSupp) >= 2 * nSuppSizeLimit )
|
|
continue;
|
|
// figure out might be the good partition for this one
|
|
Attract = 1000 * nCommon / Vec_IntSize(vOne);
|
|
if ( Vec_IntSize(vPartSupp) < 100 )
|
|
Repulse = 1;
|
|
else
|
|
Repulse = 1+Abc_Base2Log(Vec_IntSize(vPartSupp)-100);
|
|
Value = Attract/Repulse;
|
|
if ( ValueBest < Value )
|
|
{
|
|
ValueBest = Value;
|
|
iBest = i;
|
|
}
|
|
}
|
|
if ( ValueBest < 75 )
|
|
return -1;
|
|
return iBest;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Perform the smart partitioning.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkPartitionPrint( Abc_Ntk_t * pNtk, Vec_Ptr_t * vPartsAll, Vec_Ptr_t * vPartSuppsAll )
|
|
{
|
|
Vec_Int_t * vOne;
|
|
int i, nOutputs, Counter;
|
|
|
|
Counter = 0;
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vOne, i )
|
|
{
|
|
nOutputs = Vec_IntSize((Vec_Int_t *)Vec_PtrEntry(vPartsAll, i));
|
|
printf( "%d=(%d,%d) ", i, Vec_IntSize(vOne), nOutputs );
|
|
Counter += nOutputs;
|
|
if ( i == Vec_PtrSize(vPartsAll) - 1 )
|
|
break;
|
|
}
|
|
// assert( Counter == Abc_NtkCoNum(pNtk) );
|
|
printf( "\nTotal = %d. Outputs = %d.\n", Counter, Abc_NtkCoNum(pNtk) );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Perform the smart partitioning.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkPartitionCompact( Vec_Ptr_t * vPartsAll, Vec_Ptr_t * vPartSuppsAll, int nSuppSizeLimit )
|
|
{
|
|
Vec_Int_t * vOne, * vPart, * vPartSupp, * vTemp;
|
|
int i, iPart;
|
|
|
|
if ( nSuppSizeLimit == 0 )
|
|
nSuppSizeLimit = 200;
|
|
|
|
// pack smaller partitions into larger blocks
|
|
iPart = 0;
|
|
vPart = vPartSupp = NULL;
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vOne, i )
|
|
{
|
|
if ( Vec_IntSize(vOne) < nSuppSizeLimit )
|
|
{
|
|
if ( vPartSupp == NULL )
|
|
{
|
|
assert( vPart == NULL );
|
|
vPartSupp = Vec_IntDup(vOne);
|
|
vPart = (Vec_Int_t *)Vec_PtrEntry(vPartsAll, i);
|
|
}
|
|
else
|
|
{
|
|
vPartSupp = Vec_IntTwoMerge( vTemp = vPartSupp, vOne );
|
|
Vec_IntFree( vTemp );
|
|
vPart = Vec_IntTwoMerge( vTemp = vPart, (Vec_Int_t *)Vec_PtrEntry(vPartsAll, i) );
|
|
Vec_IntFree( vTemp );
|
|
Vec_IntFree( (Vec_Int_t *)Vec_PtrEntry(vPartsAll, i) );
|
|
}
|
|
if ( Vec_IntSize(vPartSupp) < nSuppSizeLimit )
|
|
continue;
|
|
}
|
|
else
|
|
vPart = (Vec_Int_t *)Vec_PtrEntry(vPartsAll, i);
|
|
// add the partition
|
|
Vec_PtrWriteEntry( vPartsAll, iPart, vPart );
|
|
vPart = NULL;
|
|
if ( vPartSupp )
|
|
{
|
|
Vec_IntFree( (Vec_Int_t *)Vec_PtrEntry(vPartSuppsAll, iPart) );
|
|
Vec_PtrWriteEntry( vPartSuppsAll, iPart, vPartSupp );
|
|
vPartSupp = NULL;
|
|
}
|
|
iPart++;
|
|
}
|
|
// add the last one
|
|
if ( vPart )
|
|
{
|
|
Vec_PtrWriteEntry( vPartsAll, iPart, vPart );
|
|
vPart = NULL;
|
|
|
|
assert( vPartSupp != NULL );
|
|
Vec_IntFree( (Vec_Int_t *)Vec_PtrEntry(vPartSuppsAll, iPart) );
|
|
Vec_PtrWriteEntry( vPartSuppsAll, iPart, vPartSupp );
|
|
vPartSupp = NULL;
|
|
iPart++;
|
|
}
|
|
Vec_PtrShrink( vPartsAll, iPart );
|
|
Vec_PtrShrink( vPartsAll, iPart );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Perform the smart partitioning.]
|
|
|
|
Description [Returns the ptr-vector of int-vectors.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkPartitionSmart( Abc_Ntk_t * pNtk, int nSuppSizeLimit, int fVerbose )
|
|
{
|
|
ProgressBar * pProgress;
|
|
Vec_Ptr_t * vPartSuppsChar;
|
|
Vec_Ptr_t * vSupps, * vPartsAll, * vPartsAll2, * vPartSuppsAll;
|
|
Vec_Int_t * vOne, * vPart, * vPartSupp, * vTemp;
|
|
int i, iPart, iOut, timeFind = 0;
|
|
abctime clk, clk2;
|
|
|
|
// compute the supports for all outputs
|
|
clk = Abc_Clock();
|
|
// vSupps = Abc_NtkComputeSupportsNaive( pNtk );
|
|
vSupps = Abc_NtkComputeSupportsSmart( pNtk );
|
|
if ( fVerbose )
|
|
{
|
|
ABC_PRT( "Supps", Abc_Clock() - clk );
|
|
}
|
|
// start char-based support representation
|
|
vPartSuppsChar = Vec_PtrAlloc( 1000 );
|
|
|
|
// create partitions
|
|
clk = Abc_Clock();
|
|
vPartsAll = Vec_PtrAlloc( 256 );
|
|
vPartSuppsAll = Vec_PtrAlloc( 256 );
|
|
pProgress = Extra_ProgressBarStart( stdout, Vec_PtrSize(vSupps) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vSupps, vOne, i )
|
|
{
|
|
Extra_ProgressBarUpdate( pProgress, i, NULL );
|
|
// if ( i % 1000 == 0 )
|
|
// printf( "CIs = %6d. COs = %6d. Processed = %6d (out of %6d). Parts = %6d.\r",
|
|
// Abc_NtkCiNum(pNtk), Abc_NtkCoNum(pNtk), i, Vec_PtrSize(vSupps), Vec_PtrSize(vPartsAll) );
|
|
// get the output number
|
|
iOut = Vec_IntPop(vOne);
|
|
// find closely matching part
|
|
clk2 = Abc_Clock();
|
|
iPart = Abc_NtkPartitionSmartFindPart( vPartSuppsAll, vPartsAll, vPartSuppsChar, nSuppSizeLimit, vOne );
|
|
timeFind += Abc_Clock() - clk2;
|
|
if ( iPart == -1 )
|
|
{
|
|
// create new partition
|
|
vPart = Vec_IntAlloc( 32 );
|
|
Vec_IntPush( vPart, iOut );
|
|
// create new partition support
|
|
vPartSupp = Vec_IntDup( vOne );
|
|
// add this partition and its support
|
|
Vec_PtrPush( vPartsAll, vPart );
|
|
Vec_PtrPush( vPartSuppsAll, vPartSupp );
|
|
|
|
Vec_PtrPush( vPartSuppsChar, Abc_NtkSuppCharStart(vOne, Abc_NtkCiNum(pNtk)) );
|
|
}
|
|
else
|
|
{
|
|
// add output to this partition
|
|
vPart = (Vec_Int_t *)Vec_PtrEntry( vPartsAll, iPart );
|
|
Vec_IntPush( vPart, iOut );
|
|
// merge supports
|
|
vPartSupp = (Vec_Int_t *)Vec_PtrEntry( vPartSuppsAll, iPart );
|
|
vPartSupp = Vec_IntTwoMerge( vTemp = vPartSupp, vOne );
|
|
Vec_IntFree( vTemp );
|
|
// reinsert new support
|
|
Vec_PtrWriteEntry( vPartSuppsAll, iPart, vPartSupp );
|
|
|
|
Abc_NtkSuppCharAdd( (unsigned *)Vec_PtrEntry(vPartSuppsChar, iPart), vOne, Abc_NtkCiNum(pNtk) );
|
|
}
|
|
}
|
|
Extra_ProgressBarStop( pProgress );
|
|
|
|
// stop char-based support representation
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsChar, vTemp, i )
|
|
ABC_FREE( vTemp );
|
|
Vec_PtrFree( vPartSuppsChar );
|
|
|
|
//printf( "\n" );
|
|
if ( fVerbose )
|
|
{
|
|
ABC_PRT( "Parts", Abc_Clock() - clk );
|
|
//ABC_PRT( "Find ", timeFind );
|
|
}
|
|
|
|
clk = Abc_Clock();
|
|
// remember number of supports
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vOne, i )
|
|
Vec_IntPush( vOne, i );
|
|
// sort the supports in the decreasing order
|
|
Vec_VecSort( (Vec_Vec_t *)vPartSuppsAll, 1 );
|
|
// reproduce partitions
|
|
vPartsAll2 = Vec_PtrAlloc( 256 );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vOne, i )
|
|
Vec_PtrPush( vPartsAll2, Vec_PtrEntry(vPartsAll, Vec_IntPop(vOne)) );
|
|
Vec_PtrFree( vPartsAll );
|
|
vPartsAll = vPartsAll2;
|
|
|
|
// compact small partitions
|
|
// Abc_NtkPartitionPrint( pNtk, vPartsAll, vPartSuppsAll );
|
|
Abc_NtkPartitionCompact( vPartsAll, vPartSuppsAll, nSuppSizeLimit );
|
|
|
|
if ( fVerbose )
|
|
{
|
|
ABC_PRT( "Comps", Abc_Clock() - clk );
|
|
}
|
|
if ( fVerbose )
|
|
printf( "Created %d partitions.\n", Vec_PtrSize(vPartsAll) );
|
|
// Abc_NtkPartitionPrint( pNtk, vPartsAll, vPartSuppsAll );
|
|
|
|
// cleanup
|
|
Vec_VecFree( (Vec_Vec_t *)vSupps );
|
|
Vec_VecFree( (Vec_Vec_t *)vPartSuppsAll );
|
|
/*
|
|
// converts from intergers to nodes
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vPartsAll, vPart, iPart )
|
|
{
|
|
vPartPtr = Vec_PtrAlloc( Vec_IntSize(vPart) );
|
|
Vec_IntForEachEntry( vPart, iOut, i )
|
|
Vec_PtrPush( vPartPtr, Abc_NtkCo(pNtk, iOut) );
|
|
Vec_IntFree( vPart );
|
|
Vec_PtrWriteEntry( vPartsAll, iPart, vPartPtr );
|
|
}
|
|
*/
|
|
return vPartsAll;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Perform the naive partitioning.]
|
|
|
|
Description [Returns the ptr-vector of int-vectors.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkPartitionNaive( Abc_Ntk_t * pNtk, int nPartSize )
|
|
{
|
|
Vec_Ptr_t * vParts;
|
|
Abc_Obj_t * pObj;
|
|
int nParts, i;
|
|
nParts = (Abc_NtkCoNum(pNtk) / nPartSize) + ((Abc_NtkCoNum(pNtk) % nPartSize) > 0);
|
|
vParts = (Vec_Ptr_t *)Vec_VecStart( nParts );
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
Vec_IntPush( (Vec_Int_t *)Vec_PtrEntry(vParts, i / nPartSize), i );
|
|
return vParts;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Converts from intergers to pointers for the given network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkConvertCos( Abc_Ntk_t * pNtk, Vec_Int_t * vOuts, Vec_Ptr_t * vOutsPtr )
|
|
{
|
|
int Out, i;
|
|
Vec_PtrClear( vOutsPtr );
|
|
Vec_IntForEachEntry( vOuts, Out, i )
|
|
Vec_PtrPush( vOutsPtr, Abc_NtkCo(pNtk, Out) );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns representative of the given node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Abc_NtkPartStitchFindRepr_rec( Vec_Ptr_t * vEquiv, Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pRepr;
|
|
pRepr = (Abc_Obj_t *)Vec_PtrEntry( vEquiv, pObj->Id );
|
|
if ( pRepr == NULL || pRepr == pObj )
|
|
return pObj;
|
|
return Abc_NtkPartStitchFindRepr_rec( vEquiv, pRepr );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns the representative of the fanin.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline Abc_Obj_t * Abc_NtkPartStitchCopy0( Vec_Ptr_t * vEquiv, Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pFan = Abc_ObjFanin0( pObj );
|
|
Abc_Obj_t * pRepr = Abc_NtkPartStitchFindRepr_rec( vEquiv, pFan );
|
|
return Abc_ObjNotCond( pRepr->pCopy, pRepr->fPhase ^ pFan->fPhase ^ (int)Abc_ObjFaninC1(pObj) );
|
|
}
|
|
static inline Abc_Obj_t * Abc_NtkPartStitchCopy1( Vec_Ptr_t * vEquiv, Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pFan = Abc_ObjFanin1( pObj );
|
|
Abc_Obj_t * pRepr = Abc_NtkPartStitchFindRepr_rec( vEquiv, pFan );
|
|
return Abc_ObjNotCond( pRepr->pCopy, pRepr->fPhase ^ pFan->fPhase ^ (int)Abc_ObjFaninC1(pObj) );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis []
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline Hop_Obj_t * Hop_ObjChild0Next( Abc_Obj_t * pObj ) { return Hop_NotCond( (Hop_Obj_t *)Abc_ObjFanin0(pObj)->pNext, Abc_ObjFaninC0(pObj) ); }
|
|
static inline Hop_Obj_t * Hop_ObjChild1Next( Abc_Obj_t * pObj ) { return Hop_NotCond( (Hop_Obj_t *)Abc_ObjFanin1(pObj)->pNext, Abc_ObjFaninC1(pObj) ); }
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Stitches together several networks with choice nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Hop_Man_t * Abc_NtkPartStartHop( Abc_Ntk_t * pNtk )
|
|
{
|
|
Hop_Man_t * pMan;
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
// start the HOP package
|
|
pMan = Hop_ManStart();
|
|
pMan->vObjs = Vec_PtrAlloc( Abc_NtkObjNumMax(pNtk) + 1 );
|
|
Vec_PtrPush( pMan->vObjs, Hop_ManConst1(pMan) );
|
|
// map constant node and PIs
|
|
Abc_AigConst1(pNtk)->pNext = (Abc_Obj_t *)Hop_ManConst1(pMan);
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
pObj->pNext = (Abc_Obj_t *)Hop_ObjCreatePi(pMan);
|
|
// map the internal nodes
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
{
|
|
pObj->pNext = (Abc_Obj_t *)Hop_And( pMan, Hop_ObjChild0Next(pObj), Hop_ObjChild1Next(pObj) );
|
|
assert( !Abc_ObjIsComplement(pObj->pNext) );
|
|
}
|
|
// set the choice nodes
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
{
|
|
if ( pObj->pCopy )
|
|
((Hop_Obj_t *)pObj->pNext)->pData = pObj->pCopy->pNext;
|
|
}
|
|
// transfer the POs
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
Hop_ObjCreatePo( pMan, Hop_ObjChild0Next(pObj) );
|
|
// check the new manager
|
|
if ( !Hop_ManCheck(pMan) )
|
|
printf( "Abc_NtkPartStartHop: HOP manager check has failed.\n" );
|
|
return pMan;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Stitches together several networks with choice nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkPartStitchChoices( Abc_Ntk_t * pNtk, Vec_Ptr_t * vParts )
|
|
{
|
|
extern Abc_Ntk_t * Abc_NtkHopRemoveLoops( Abc_Ntk_t * pNtk, Hop_Man_t * pMan );
|
|
Hop_Man_t * pMan;
|
|
Vec_Ptr_t * vNodes;
|
|
Abc_Ntk_t * pNtkNew, * pNtkTemp;
|
|
Abc_Obj_t * pObj, * pFanin;
|
|
int i, k, iNodeId;
|
|
|
|
// start a new network similar to the original one
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG );
|
|
|
|
// annotate parts to point to the new network
|
|
Vec_PtrForEachEntry( Abc_Ntk_t *, vParts, pNtkTemp, i )
|
|
{
|
|
assert( Abc_NtkIsStrash(pNtkTemp) );
|
|
Abc_NtkCleanCopy( pNtkTemp );
|
|
|
|
// map the CI nodes
|
|
Abc_AigConst1(pNtkTemp)->pCopy = Abc_AigConst1(pNtkNew);
|
|
Abc_NtkForEachCi( pNtkTemp, pObj, k )
|
|
{
|
|
iNodeId = Nm_ManFindIdByNameTwoTypes( pNtkNew->pManName, Abc_ObjName(pObj), ABC_OBJ_PI, ABC_OBJ_BO );
|
|
if ( iNodeId == -1 )
|
|
{
|
|
printf( "Cannot find CI node %s in the original network.\n", Abc_ObjName(pObj) );
|
|
return NULL;
|
|
}
|
|
pObj->pCopy = Abc_NtkObj( pNtkNew, iNodeId );
|
|
}
|
|
|
|
// add the internal nodes while saving representatives
|
|
vNodes = Abc_AigDfs( pNtkTemp, 1, 0 );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, k )
|
|
{
|
|
pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
assert( !Abc_ObjIsComplement(pObj->pCopy) );
|
|
if ( Abc_AigNodeIsChoice(pObj) )
|
|
for ( pFanin = (Abc_Obj_t *)pObj->pData; pFanin; pFanin = (Abc_Obj_t *)pFanin->pData )
|
|
pFanin->pCopy->pCopy = pObj->pCopy;
|
|
}
|
|
Vec_PtrFree( vNodes );
|
|
|
|
// map the CO nodes
|
|
Abc_NtkForEachCo( pNtkTemp, pObj, k )
|
|
{
|
|
iNodeId = Nm_ManFindIdByNameTwoTypes( pNtkNew->pManName, Abc_ObjName(pObj), ABC_OBJ_PO, ABC_OBJ_BI );
|
|
if ( iNodeId == -1 )
|
|
{
|
|
printf( "Cannot find CO node %s in the original network.\n", Abc_ObjName(pObj) );
|
|
return NULL;
|
|
}
|
|
pObj->pCopy = Abc_NtkObj( pNtkNew, iNodeId );
|
|
Abc_ObjAddFanin( pObj->pCopy, Abc_ObjChild0Copy(pObj) );
|
|
}
|
|
}
|
|
|
|
// connect the remaining POs
|
|
/*
|
|
Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
pObj->pCopy = Abc_NtkCi( pNtkNew, i );
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
pObj->pCopy = Abc_NtkCo( pNtkNew, i );
|
|
*/
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
{
|
|
if ( Abc_ObjFaninNum(pObj->pCopy) == 0 )
|
|
Abc_ObjAddFanin( pObj->pCopy, Abc_ObjChild0Copy(pObj) );
|
|
}
|
|
|
|
// transform into the HOP manager
|
|
pMan = Abc_NtkPartStartHop( pNtkNew );
|
|
pNtkNew = Abc_NtkHopRemoveLoops( pNtkTemp = pNtkNew, pMan );
|
|
Abc_NtkDelete( pNtkTemp );
|
|
|
|
// check correctness of the new network
|
|
if ( !Abc_NtkCheck( pNtkNew ) )
|
|
{
|
|
printf( "Abc_NtkPartStitchChoices: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkNew );
|
|
return NULL;
|
|
}
|
|
return pNtkNew;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Stitches together several networks with choice nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkFraigPartitioned( Vec_Ptr_t * vStore, void * pParams )
|
|
{
|
|
Vec_Ptr_t * vParts, * vFraigs, * vOnePtr;
|
|
Vec_Int_t * vOne;
|
|
Abc_Ntk_t * pNtk, * pNtk2, * pNtkAig, * pNtkFraig;
|
|
int i, k;
|
|
|
|
// perform partitioning
|
|
pNtk = (Abc_Ntk_t *)Vec_PtrEntry( vStore, 0 );
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
// vParts = Abc_NtkPartitionNaive( pNtk, 20 );
|
|
vParts = Abc_NtkPartitionSmart( pNtk, 300, 0 );
|
|
|
|
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "unset progressbar" );
|
|
|
|
// fraig each partition
|
|
vOnePtr = Vec_PtrAlloc( 1000 );
|
|
vFraigs = Vec_PtrAlloc( Vec_PtrSize(vParts) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vParts, vOne, i )
|
|
{
|
|
// start the partition
|
|
Abc_NtkConvertCos( pNtk, vOne, vOnePtr );
|
|
pNtkAig = Abc_NtkCreateConeArray( pNtk, vOnePtr, 0 );
|
|
// add nodes to the partition
|
|
Vec_PtrForEachEntryStart( Abc_Ntk_t *, vStore, pNtk2, k, 1 )
|
|
{
|
|
Abc_NtkConvertCos( pNtk2, vOne, vOnePtr );
|
|
Abc_NtkAppendToCone( pNtkAig, pNtk2, vOnePtr );
|
|
}
|
|
printf( "Fraiging part %4d (out of %4d) PI = %5d. PO = %5d. And = %6d. Lev = %4d.\r",
|
|
i+1, Vec_PtrSize(vParts), Abc_NtkPiNum(pNtkAig), Abc_NtkPoNum(pNtkAig),
|
|
Abc_NtkNodeNum(pNtkAig), Abc_AigLevel(pNtkAig) );
|
|
// fraig the partition
|
|
pNtkFraig = Abc_NtkFraig( pNtkAig, pParams, 1, 0 );
|
|
Vec_PtrPush( vFraigs, pNtkFraig );
|
|
Abc_NtkDelete( pNtkAig );
|
|
}
|
|
printf( " \r" );
|
|
Vec_VecFree( (Vec_Vec_t *)vParts );
|
|
|
|
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "set progressbar" );
|
|
|
|
// derive the final network
|
|
pNtkFraig = Abc_NtkPartStitchChoices( pNtk, vFraigs );
|
|
Vec_PtrForEachEntry( Abc_Ntk_t *, vFraigs, pNtkAig, i )
|
|
Abc_NtkDelete( pNtkAig );
|
|
Vec_PtrFree( vFraigs );
|
|
Vec_PtrFree( vOnePtr );
|
|
return pNtkFraig;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Stitches together several networks with choice nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkFraigPartitionedTime( Abc_Ntk_t * pNtk, void * pParams )
|
|
{
|
|
Vec_Ptr_t * vParts, * vFraigs, * vOnePtr;
|
|
Vec_Int_t * vOne;
|
|
Abc_Ntk_t * pNtkAig, * pNtkFraig;
|
|
int i;
|
|
abctime clk = Abc_Clock();
|
|
|
|
// perform partitioning
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
// vParts = Abc_NtkPartitionNaive( pNtk, 20 );
|
|
vParts = Abc_NtkPartitionSmart( pNtk, 300, 0 );
|
|
|
|
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "unset progressbar" );
|
|
|
|
// fraig each partition
|
|
vOnePtr = Vec_PtrAlloc( 1000 );
|
|
vFraigs = Vec_PtrAlloc( Vec_PtrSize(vParts) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vParts, vOne, i )
|
|
{
|
|
Abc_NtkConvertCos( pNtk, vOne, vOnePtr );
|
|
pNtkAig = Abc_NtkCreateConeArray( pNtk, vOnePtr, 0 );
|
|
pNtkFraig = Abc_NtkFraig( pNtkAig, pParams, 0, 0 );
|
|
Vec_PtrPush( vFraigs, pNtkFraig );
|
|
Abc_NtkDelete( pNtkAig );
|
|
|
|
printf( "Finished part %5d (out of %5d)\r", i+1, Vec_PtrSize(vParts) );
|
|
}
|
|
Vec_VecFree( (Vec_Vec_t *)vParts );
|
|
|
|
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "set progressbar" );
|
|
|
|
// derive the final network
|
|
Vec_PtrForEachEntry( Abc_Ntk_t *, vFraigs, pNtkAig, i )
|
|
Abc_NtkDelete( pNtkAig );
|
|
Vec_PtrFree( vFraigs );
|
|
Vec_PtrFree( vOnePtr );
|
|
ABC_PRT( "Partitioned fraiging time", Abc_Clock() - clk );
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Optimization.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkStochSynthesis( Vec_Ptr_t * vWins, char * pScript )
|
|
{
|
|
Abc_Ntk_t * pNtk, * pNew; int i;
|
|
Vec_PtrForEachEntry( Abc_Ntk_t *, vWins, pNtk, i )
|
|
{
|
|
Abc_FrameReplaceCurrentNetwork( Abc_FrameGetGlobalFrame(), Abc_NtkDupDfs(pNtk) );
|
|
if ( Abc_FrameIsBatchMode() )
|
|
{
|
|
if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), pScript) )
|
|
{
|
|
Abc_Print( 1, "Something did not work out with the command \"%s\".\n", pScript );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Abc_FrameSetBatchMode( 1 );
|
|
if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), pScript) )
|
|
{
|
|
Abc_Print( 1, "Something did not work out with the command \"%s\".\n", pScript );
|
|
Abc_FrameSetBatchMode( 0 );
|
|
return;
|
|
}
|
|
Abc_FrameSetBatchMode( 0 );
|
|
}
|
|
pNew = Abc_FrameReadNtk(Abc_FrameGetGlobalFrame());
|
|
if ( Abc_NtkIsMappedLogic(pNew) && Abc_NtkIsMappedLogic(pNtk) )
|
|
{
|
|
if ( Abc_NtkGetMappedArea(pNew) < Abc_NtkGetMappedArea(pNtk) )
|
|
{
|
|
Abc_NtkDelete( pNtk );
|
|
pNtk = Abc_NtkDupDfs( pNew );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( Abc_NtkNodeNum(pNew) < Abc_NtkNodeNum(pNtk) )
|
|
{
|
|
Abc_NtkDelete( pNtk );
|
|
pNtk = Abc_NtkDupDfs( pNew );
|
|
}
|
|
}
|
|
Vec_PtrWriteEntry( vWins, i, pNtk );
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Generic concurrent processing.]
|
|
|
|
Description [User-defined problem-specific data and the way to process it.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
|
|
typedef struct StochSynData_t_
|
|
{
|
|
Abc_Ntk_t * pIn;
|
|
Abc_Ntk_t * pOut;
|
|
char * pScript;
|
|
int Rand;
|
|
int TimeOut;
|
|
} StochSynData_t;
|
|
|
|
Abc_Ntk_t * Abc_NtkStochProcessOne( Abc_Ntk_t * p, char * pScript0, int Rand, int TimeSecs )
|
|
{
|
|
extern int Abc_NtkWriteToFile( char * pFileName, Abc_Ntk_t * pNtk );
|
|
extern Abc_Ntk_t * Abc_NtkReadFromFile( char * pFileName );
|
|
Abc_Ntk_t * pNew, * pTemp;
|
|
char FileName[100], Command[1000], PreCommand[500] = {0};
|
|
char * pLibFileName = Abc_NtkIsMappedLogic(p) ? Mio_LibraryReadFileName((Mio_Library_t *)p->pManFunc) : NULL;
|
|
if ( pLibFileName ) sprintf( PreCommand, "read_genlib %s; ", pLibFileName );
|
|
sprintf( FileName, "%06x.mm", Rand );
|
|
Abc_NtkWriteToFile( FileName, p );
|
|
char * pScript = Abc_UtilStrsav( pScript0 );
|
|
sprintf( Command, "./abc -q \"%sread_mm %s; %s; write_mm %s\"", PreCommand[0] ? PreCommand : "", FileName, pScript, FileName );
|
|
#if defined(__wasm)
|
|
if ( 1 )
|
|
#else
|
|
if ( system( (char *)Command ) )
|
|
#endif
|
|
{
|
|
fprintf( stderr, "The following command has returned non-zero exit status:\n" );
|
|
fprintf( stderr, "\"%s\"\n", (char *)Command );
|
|
fprintf( stderr, "Sorry for the inconvenience.\n" );
|
|
fflush( stdout );
|
|
unlink( FileName );
|
|
ABC_FREE( pScript );
|
|
return Abc_NtkDupDfs(p);
|
|
}
|
|
ABC_FREE( pScript );
|
|
pNew = Abc_NtkReadFromFile( FileName );
|
|
unlink( FileName );
|
|
if ( pNew && Abc_NtkGetMappedArea(pNew) < Abc_NtkGetMappedArea(p) ) {
|
|
pNew = Abc_NtkDupDfs( pTemp = pNew );
|
|
Abc_NtkDelete( pTemp );
|
|
return pNew;
|
|
}
|
|
if ( pNew ) Abc_NtkDelete( pNew );
|
|
return Abc_NtkDupDfs(p);
|
|
}
|
|
|
|
int Abc_NtkStochProcess1( void * p )
|
|
{
|
|
StochSynData_t * pData = (StochSynData_t *)p;
|
|
assert( pData->pIn != NULL );
|
|
assert( pData->pOut == NULL );
|
|
pData->pOut = Abc_NtkStochProcessOne( pData->pIn, pData->pScript, pData->Rand, pData->TimeOut );
|
|
return 1;
|
|
}
|
|
|
|
Vec_Ptr_t * Abc_NtkStochProcess( Vec_Ptr_t * vWins, char * pScript, int nProcs, int TimeSecs, int fVerbose )
|
|
{
|
|
if ( nProcs <= 2 ) {
|
|
Abc_NtkStochSynthesis( vWins, pScript );
|
|
return NULL;
|
|
}
|
|
StochSynData_t * pData = ABC_CALLOC( StochSynData_t, Vec_PtrSize(vWins) );
|
|
Vec_Ptr_t * vData = Vec_PtrAlloc( Vec_PtrSize(vWins) );
|
|
Abc_Ntk_t * pNtk; int i;
|
|
Abc_Random(1);
|
|
Vec_PtrForEachEntry( Abc_Ntk_t *, vWins, pNtk, i ) {
|
|
pData[i].pIn = pNtk;
|
|
pData[i].pOut = NULL;
|
|
pData[i].pScript = pScript;
|
|
pData[i].Rand = Abc_Random(0) % 0x1000000;
|
|
pData[i].TimeOut = TimeSecs;
|
|
Vec_PtrPush( vData, pData+i );
|
|
}
|
|
Util_ProcessThreads( Abc_NtkStochProcess1, vData, nProcs, TimeSecs, fVerbose );
|
|
// replace old AIGs by new AIGs
|
|
Vec_PtrForEachEntry( Abc_Ntk_t *, vWins, pNtk, i ) {
|
|
Abc_NtkDelete( pNtk );
|
|
Vec_PtrWriteEntry( vWins, i, pData[i].pOut );
|
|
}
|
|
Vec_PtrFree( vData );
|
|
ABC_FREE( pData );
|
|
return NULL;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns 1 if this window has a topo error (forward path from an output to an input).]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkWindowCheckTopoError_rec( Abc_Obj_t * pObj )
|
|
{
|
|
if ( !Abc_ObjIsNode(pObj) )
|
|
return 0;
|
|
if ( Abc_NodeIsTravIdPrevious(pObj) )
|
|
return 1; // there is an error
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return 0; // there is no error; visited this node before
|
|
Abc_NodeSetTravIdPrevious(pObj);
|
|
Abc_Obj_t * pFanin; int i;
|
|
Abc_ObjForEachFanin( pObj, pFanin, i )
|
|
if ( Abc_NtkWindowCheckTopoError_rec(pFanin) )
|
|
return 1;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
return 0;
|
|
}
|
|
int Abc_NtkWindowCheckTopoError( Abc_Ntk_t * p, Vec_Int_t * vIns, Vec_Int_t * vOuts )
|
|
{
|
|
Abc_Obj_t * pObj; int i, fError = 0;
|
|
// outputs should be internal nodes
|
|
Abc_NtkForEachObjVec( vOuts, p, pObj, i )
|
|
assert(Abc_ObjIsNode(pObj));
|
|
// mark outputs
|
|
Abc_NtkIncrementTravId( p );
|
|
Abc_NtkForEachObjVec( vOuts, p, pObj, i )
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// start from inputs and make sure we do not reach any of the outputs
|
|
Abc_NtkIncrementTravId( p );
|
|
Abc_NtkForEachObjVec( vIns, p, pObj, i )
|
|
fError |= Abc_NtkWindowCheckTopoError_rec(pObj);
|
|
return fError;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Updates the AIG after multiple windows have been optimized.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkCreateNodeMapped( Abc_Ntk_t * pNew, Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pObjNew = Abc_NtkDupObj( pNew, pObj, 0 );
|
|
Abc_Obj_t * pFanin; int i;
|
|
Abc_ObjForEachFanin( pObj, pFanin, i )
|
|
Abc_ObjAddFanin( pObjNew, pFanin->pCopy );
|
|
}
|
|
void Abc_NtkInsertPartitions_rec( Abc_Ntk_t * pNew, Abc_Obj_t * pObj, Vec_Int_t * vMap, Vec_Ptr_t * vvIns, Vec_Ptr_t * vvOuts, Vec_Ptr_t * vWins )
|
|
{
|
|
if ( pObj->pCopy )
|
|
return;
|
|
assert( Abc_ObjIsNode(pObj) );
|
|
if ( Vec_IntEntry(vMap, Abc_ObjId(pObj)) == -1 ) // this is a regular node
|
|
{
|
|
Abc_Obj_t * pFanin; int i;
|
|
Abc_ObjForEachFanin( pObj, pFanin, i )
|
|
Abc_NtkInsertPartitions_rec( pNew, pFanin, vMap, vvIns, vvOuts, vWins );
|
|
Abc_NtkCreateNodeMapped( pNew, pObj );
|
|
return;
|
|
}
|
|
// this node is an output of a window
|
|
int iWin = Vec_IntEntry(vMap, Abc_ObjId(pObj));
|
|
Vec_Int_t * vIns = (Vec_Int_t *)Vec_PtrEntry(vvIns, iWin);
|
|
Vec_Int_t * vOuts = (Vec_Int_t *)Vec_PtrEntry(vvOuts, iWin);
|
|
Abc_Ntk_t * pWin = (Abc_Ntk_t *)Vec_PtrEntry(vWins, iWin);
|
|
// build transinvite fanins of window inputs
|
|
Abc_Obj_t * pNode; int i;
|
|
Abc_NtkForEachObjVec( vIns, pObj->pNtk, pNode, i ) {
|
|
Abc_NtkInsertPartitions_rec( pNew, pNode, vMap, vvIns, vvOuts, vWins );
|
|
Abc_NtkPi(pWin, i)->pCopy = pNode->pCopy;
|
|
}
|
|
// add window nodes
|
|
Vec_Ptr_t * vNodes = Abc_NtkDfs( pWin, 0 );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i )
|
|
Abc_NtkCreateNodeMapped( pNew, pNode );
|
|
Vec_PtrFree( vNodes );
|
|
// transfer to window outputs
|
|
Abc_NtkForEachObjVec( vOuts, pObj->pNtk, pNode, i )
|
|
pNode->pCopy = Abc_ObjFanin0(Abc_NtkPo(pWin, i))->pCopy;
|
|
assert( pObj->pCopy );
|
|
}
|
|
Abc_Ntk_t * Abc_NtkInsertPartitions( Abc_Ntk_t * p, Vec_Ptr_t * vvIns, Vec_Ptr_t * vvOuts, Vec_Ptr_t * vWins )
|
|
{
|
|
if ( vvIns == NULL ) {
|
|
assert( vvOuts == NULL );
|
|
assert( Vec_PtrSize(vWins) == 1 );
|
|
return Abc_NtkDupDfs( (Abc_Ntk_t *)Vec_PtrEntry(vWins, 0) );
|
|
}
|
|
// check consistency of input data
|
|
Abc_Ntk_t * pNew, * pTemp; Abc_Obj_t * pObj; int i, k, iNode;
|
|
Vec_PtrForEachEntry( Abc_Ntk_t *, vWins, pTemp, i ) {
|
|
Vec_Int_t * vIns = (Vec_Int_t *)Vec_PtrEntry(vvIns, i);
|
|
Vec_Int_t * vOuts = (Vec_Int_t *)Vec_PtrEntry(vvOuts, i);
|
|
assert( Vec_IntSize(vIns) == Abc_NtkPiNum(pTemp) );
|
|
assert( Vec_IntSize(vOuts) == Abc_NtkPoNum(pTemp) );
|
|
assert( !Abc_NtkWindowCheckTopoError(p, vIns, vOuts) );
|
|
}
|
|
// create mapping of window outputs into window IDs
|
|
Vec_Int_t * vMap = Vec_IntStartFull( Abc_NtkObjNumMax(p) ), * vOuts;
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vvOuts, vOuts, i )
|
|
Vec_IntForEachEntry( vOuts, iNode, k ) {
|
|
assert( Vec_IntEntry(vMap, iNode) == -1 );
|
|
Vec_IntWriteEntry( vMap, iNode, i );
|
|
}
|
|
Abc_NtkCleanCopy( p );
|
|
pNew = Abc_NtkStartFrom( p, p->ntkType, p->ntkFunc );
|
|
pNew->pManFunc = p->pManFunc;
|
|
Abc_NtkForEachCo( p, pObj, i )
|
|
Abc_NtkInsertPartitions_rec( pNew, Abc_ObjFanin0(pObj), vMap, vvIns, vvOuts, vWins );
|
|
Abc_NtkForEachCo( p, pObj, i )
|
|
Abc_ObjAddFanin( Abc_NtkCo(pNew, i), Abc_ObjFanin0(pObj)->pCopy );
|
|
Vec_IntFree( vMap );
|
|
return pNew;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Partitioning.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_ObjDfsMark_rec( Abc_Obj_t * p )
|
|
{
|
|
Abc_Obj_t * pFanin; int i;
|
|
assert( !p->fMarkA );
|
|
if ( Abc_NodeIsTravIdCurrent( p ) )
|
|
return;
|
|
Abc_NodeSetTravIdCurrent( p );
|
|
Abc_ObjForEachFanin( p, pFanin, i )
|
|
Abc_ObjDfsMark_rec( pFanin );
|
|
}
|
|
void Abc_ObjDfsMark2_rec( Abc_Obj_t * p )
|
|
{
|
|
Abc_Obj_t * pFanout; int i;
|
|
assert( !p->fMarkA );
|
|
if ( Abc_NodeIsTravIdCurrent( p ) )
|
|
return;
|
|
Abc_NodeSetTravIdCurrent( p );
|
|
Abc_ObjForEachFanout( p, pFanout, i )
|
|
Abc_ObjDfsMark2_rec( pFanout );
|
|
}
|
|
Vec_Int_t * Abc_NtkDeriveWinNodes( Abc_Ntk_t * pNtk, Vec_Int_t * vIns, Vec_Wec_t * vStore )
|
|
{
|
|
Vec_Int_t * vLevel, * vNodes = Vec_IntAlloc( 100 );
|
|
Abc_Obj_t * pObj, * pNext; int i, k, iLevel;
|
|
Vec_WecForEachLevel( vStore, vLevel, i )
|
|
Vec_IntClear( vLevel );
|
|
// mark the TFI cones of the inputs
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NtkForEachObjVec( vIns, pNtk, pObj, i )
|
|
Abc_ObjDfsMark_rec( pObj );
|
|
// add unrelated fanouts of the inputs to storage
|
|
Abc_NtkForEachObjVec( vIns, pNtk, pObj, i )
|
|
Abc_ObjForEachFanout( pObj, pNext, k )
|
|
if ( Abc_ObjIsNode(pNext) && !Abc_NodeIsTravIdCurrent(pNext) && !pNext->fMarkA ) {
|
|
pNext->fMarkA = 1;
|
|
Vec_WecPush( vStore, Abc_ObjLevel(pNext), Abc_ObjId(pNext) );
|
|
}
|
|
// mark the inputs
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NtkForEachObjVec( vIns, pNtk, pObj, i )
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// collect those fanouts that are completely supported by the inputs
|
|
Vec_WecForEachLevel( vStore, vLevel, iLevel )
|
|
Abc_NtkForEachObjVec( vLevel, pNtk, pObj, i ) {
|
|
assert( !Abc_NodeIsTravIdCurrent(pObj) );
|
|
assert( pObj->fMarkA );
|
|
pObj->fMarkA = 0;
|
|
Abc_ObjForEachFanin( pObj, pNext, k )
|
|
if ( !Abc_NodeIsTravIdCurrent(pNext) )
|
|
break;
|
|
if ( k < Abc_ObjFaninNum(pObj) )
|
|
continue;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
Vec_IntPush( vNodes, Abc_ObjId(pObj) );
|
|
assert( Abc_ObjIsNode(pObj) );
|
|
// add fanouts of this node to storage
|
|
Abc_ObjForEachFanout( pObj, pNext, k )
|
|
if ( Abc_ObjIsNode(pNext) && !Abc_NodeIsTravIdCurrent(pNext) && !pNext->fMarkA ) {
|
|
pNext->fMarkA = 1;
|
|
assert( Abc_ObjLevel(pNext) > iLevel );
|
|
Vec_WecPush( vStore, Abc_ObjLevel(pNext), Abc_ObjId(pNext) );
|
|
}
|
|
}
|
|
Vec_IntSort( vNodes, 0 );
|
|
return vNodes;
|
|
}
|
|
Vec_Ptr_t * Abc_NtkDeriveWinNodesAll( Abc_Ntk_t * pNtk, Vec_Ptr_t * vvIns, Vec_Wec_t * vStore )
|
|
{
|
|
Vec_Int_t * vIns; int i;
|
|
Vec_Ptr_t * vvNodes = Vec_PtrAlloc( Vec_PtrSize(vvIns) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vvIns, vIns, i )
|
|
Vec_PtrPush( vvNodes, Abc_NtkDeriveWinNodes(pNtk, vIns, vStore) );
|
|
return vvNodes;
|
|
}
|
|
Vec_Int_t * Abc_NtkDeriveWinOuts( Abc_Ntk_t * pNtk, Vec_Int_t * vNodes )
|
|
{
|
|
Vec_Int_t * vOuts = Vec_IntAlloc( 100 );
|
|
Abc_Obj_t * pObj, * pNext; int i, k;
|
|
// mark the nodes in the window
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NtkForEachObjVec( vNodes, pNtk, pObj, i )
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// collect nodes that have unmarked fanouts
|
|
Abc_NtkForEachObjVec( vNodes, pNtk, pObj, i ) {
|
|
Abc_ObjForEachFanout( pObj, pNext, k )
|
|
if ( !Abc_NodeIsTravIdCurrent(pNext) )
|
|
break;
|
|
if ( k < Abc_ObjFanoutNum(pObj) )
|
|
Vec_IntPush( vOuts, Abc_ObjId(pObj) );
|
|
}
|
|
if ( Vec_IntSize(vOuts) == 0 )
|
|
printf( "Window with %d internal nodes has no outputs (are these dangling nodes?).\n", Vec_IntSize(vNodes) );
|
|
return vOuts;
|
|
}
|
|
Vec_Ptr_t * Abc_NtkDeriveWinOutsAll( Abc_Ntk_t * pNtk, Vec_Ptr_t * vvNodes )
|
|
{
|
|
Vec_Int_t * vNodes; int i;
|
|
Vec_Ptr_t * vvOuts = Vec_PtrAlloc( Vec_PtrSize(vvNodes) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vvNodes, vNodes, i )
|
|
Vec_PtrPush( vvOuts, Abc_NtkDeriveWinOuts(pNtk, vNodes) );
|
|
return vvOuts;
|
|
}
|
|
void Abc_NtkPermuteLevel( Abc_Ntk_t * pNtk, int Level )
|
|
{
|
|
Abc_Obj_t * pObj, * pNext; int i, k;
|
|
Abc_NtkForEachNode( pNtk, pObj, i ) {
|
|
int LevelMin = Abc_ObjLevel(pObj), LevelMax = Level + 1;
|
|
Abc_ObjForEachFanout( pObj, pNext, k )
|
|
if ( Abc_ObjIsNode(pNext) )
|
|
LevelMax = Abc_MinInt( LevelMax, Abc_ObjLevel(pNext) );
|
|
assert( LevelMin < LevelMax );
|
|
// randomly set level between LevelMin and LevelMax-1
|
|
pObj->Level = LevelMin + (Abc_Random(0) % (LevelMax - LevelMin));
|
|
assert( pObj->Level < LevelMax );
|
|
}
|
|
}
|
|
Vec_Int_t * Abc_NtkCollectObjectsPointedTo( Abc_Ntk_t * pNtk, int Level )
|
|
{
|
|
Vec_Int_t * vRes = Vec_IntAlloc( 100 );
|
|
Abc_Obj_t * pObj, * pFanin; int i, k;
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NtkForEachNode( pNtk, pObj, i ) {
|
|
if ( Abc_ObjLevel(pObj) <= Level )
|
|
continue;
|
|
Abc_ObjForEachFanin( pObj, pFanin, k )
|
|
if ( Abc_ObjLevel(pFanin) <= Level && !Abc_NodeIsTravIdCurrent(pFanin) ) {
|
|
Abc_NodeSetTravIdCurrent(pFanin);
|
|
Vec_IntPush( vRes, Abc_ObjId(pFanin) );
|
|
}
|
|
}
|
|
Abc_NtkForEachCo( pNtk, pObj, i ) {
|
|
pFanin = Abc_ObjFanin0(pObj);
|
|
if ( Abc_ObjLevel(pFanin) <= Level && !Abc_NodeIsTravIdCurrent(pFanin) && Abc_ObjFaninNum(pFanin) > 0 ) {
|
|
Abc_NodeSetTravIdCurrent(pFanin);
|
|
Vec_IntPush( vRes, Abc_ObjId(pFanin) );
|
|
}
|
|
}
|
|
Vec_IntSort( vRes, 0 );
|
|
return vRes;
|
|
}
|
|
Vec_Wec_t * Abc_NtkCollectObjectsWithSuppLimit( Abc_Ntk_t * pNtk, int Level, int nSuppMax )
|
|
{
|
|
Vec_Wec_t * vResSupps = NULL;
|
|
Vec_Int_t * vBelow = Abc_NtkCollectObjectsPointedTo( pNtk, Level );
|
|
Vec_Wec_t * vSupps = Vec_WecStart( Vec_IntSize(vBelow) );
|
|
Vec_Int_t * vSuppIds = Vec_IntStartFull( Abc_NtkObjNumMax(pNtk)+1 );
|
|
Vec_Int_t * vTemp[2] = { Vec_IntAlloc(100), Vec_IntAlloc(100) };
|
|
Abc_Obj_t * pObj, * pFanin; int i, k, Count = 0;
|
|
Abc_NtkForEachObjVec( vBelow, pNtk, pObj, i ) {
|
|
Vec_IntWriteEntry( vSuppIds, Abc_ObjId(pObj), i );
|
|
Vec_IntPush( Vec_WecEntry(vSupps, i), Abc_ObjId(pObj) );
|
|
}
|
|
Abc_NtkForEachNode( pNtk, pObj, i ) {
|
|
if ( Abc_ObjLevel(pObj) <= Level )
|
|
continue;
|
|
Vec_IntClear( vTemp[0] );
|
|
Abc_ObjForEachFanin( pObj, pFanin, k ) {
|
|
int iSuppId = Vec_IntEntry( vSuppIds, Abc_ObjId(pFanin) );
|
|
if ( iSuppId == -1 )
|
|
break;
|
|
Vec_IntTwoMerge2( Vec_WecEntry(vSupps, iSuppId), vTemp[0], vTemp[1] );
|
|
ABC_SWAP( Vec_Int_t *, vTemp[0], vTemp[1] );
|
|
}
|
|
if ( k < Abc_ObjFaninNum(pObj) || Vec_IntSize(vTemp[0]) > nSuppMax ) {
|
|
Count++;
|
|
continue;
|
|
}
|
|
Vec_IntWriteEntry( vSuppIds, Abc_ObjId(pObj), Vec_WecSize(vSupps) );
|
|
Vec_IntAppend( Vec_WecPushLevel(vSupps), vTemp[0] );
|
|
}
|
|
// remove those supported nodes that are in the TFI cones of others
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
if ( Abc_ObjLevel(pObj) > Level && Vec_IntEntry(vSuppIds, i) >= 0 && !Abc_NodeIsTravIdCurrent(pObj) ) {
|
|
Abc_ObjDfsMark_rec(pObj);
|
|
Abc_NodeSetTravIdPrevious(pObj);
|
|
}
|
|
// create the result
|
|
vResSupps = Vec_WecAlloc( 100 );
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
if ( Abc_ObjLevel(pObj) > Level && Vec_IntEntry(vSuppIds, i) >= 0 && !Abc_NodeIsTravIdCurrent(pObj) ) {
|
|
Vec_Int_t * vSupp = Vec_WecEntry( vSupps, Vec_IntEntry(vSuppIds, i) );
|
|
if ( Vec_IntSize(vSupp) < 4 )
|
|
continue;
|
|
Vec_Int_t * vThis = Vec_WecPushLevel( vResSupps );
|
|
Vec_IntGrow( vThis, Vec_IntSize(vSupp) + 1 );
|
|
Vec_IntAppend( vThis, vSupp );
|
|
//Vec_IntPush( vThis, Abc_ObjId(pObj) );
|
|
}
|
|
//printf( "Inputs = %d. Nodes with %d-support = %d. Nodes with larger support = %d. Selected outputs = %d.\n",
|
|
// Vec_IntSize(vBelow), nSuppMax, Vec_WecSize(vSupps), Count, Vec_WecSize(vResSupps) );
|
|
Vec_WecFree( vSupps );
|
|
Vec_IntFree( vSuppIds );
|
|
Vec_IntFree( vBelow );
|
|
Vec_IntFree( vTemp[0] );
|
|
Vec_IntFree( vTemp[1] );
|
|
return vResSupps;
|
|
}
|
|
// removes all supports that overlap with this one
|
|
void Abc_NtKSelectRemove( Vec_Wec_t * vSupps, Vec_Int_t * vOne )
|
|
{
|
|
Vec_Int_t * vLevel; int i;
|
|
Vec_WecForEachLevel( vSupps, vLevel, i )
|
|
if ( Vec_IntTwoCountCommon(vLevel, vOne) > 0 )
|
|
Vec_IntClear( vLevel );
|
|
Vec_WecRemoveEmpty( vSupps );
|
|
}
|
|
// removes all supports that overlap with the TFI/TFO cones of this one
|
|
void Abc_NtKSelectRemove2( Vec_Wec_t * vSupps, Vec_Int_t * vOne, Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Int_t * vLevel; int i, k; Abc_Obj_t * pObj;
|
|
Abc_NtkForEachObjVec( vOne, pNtk, pObj, i ) {
|
|
Abc_NodeSetTravIdPrevious(pObj);
|
|
Abc_ObjDfsMark_rec( pObj );
|
|
Abc_NodeSetTravIdPrevious(pObj);
|
|
Abc_ObjDfsMark2_rec( pObj );
|
|
}
|
|
Vec_WecForEachLevel( vSupps, vLevel, i ) {
|
|
Abc_NtkForEachObjVec( vLevel, pNtk, pObj, k )
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
break;
|
|
if ( k < Vec_IntSize(vLevel) )
|
|
Vec_IntClear( vLevel );
|
|
}
|
|
Vec_WecRemoveEmpty( vSupps );
|
|
}
|
|
Vec_Ptr_t * Abc_NtkDeriveWinInsAll( Vec_Wec_t * vSupps, int nSuppMax, Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vRes = Vec_PtrAlloc( 100 );
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
while ( Vec_WecSize(vSupps) > 0 ) {
|
|
int i, Item, iRand = Abc_Random(0) % Vec_WecSize(vSupps);
|
|
Vec_Int_t * vLevel, * vLevel2 = Vec_WecEntry( vSupps, iRand );
|
|
Vec_Int_t * vCopy = Vec_IntDup( vLevel2 );
|
|
if ( Vec_IntSize(vLevel2) == nSuppMax ) {
|
|
Vec_PtrPush( vRes, vCopy );
|
|
Abc_NtKSelectRemove2( vSupps, vCopy, pNtk );
|
|
continue;
|
|
}
|
|
// find another support, which maximizes the union but does not exceed nSuppMax
|
|
int iBest = iRand, nUnion = Vec_IntSize(vCopy);
|
|
Vec_WecForEachLevel( vSupps, vLevel, i ) {
|
|
if ( i == iRand ) continue;
|
|
int nCommon = Vec_IntTwoCountCommon(vLevel, vCopy);
|
|
int nUnionCur = Vec_IntSize(vLevel) + Vec_IntSize(vCopy) - nCommon;
|
|
if ( nUnionCur <= nSuppMax && nUnion < nUnionCur ) {
|
|
nUnion = nUnionCur;
|
|
iBest = i;
|
|
}
|
|
}
|
|
vLevel = Vec_WecEntry( vSupps, iBest );
|
|
Vec_IntForEachEntry( vLevel, Item, i )
|
|
Vec_IntPushUniqueOrder( vCopy, Item );
|
|
Vec_PtrPush( vRes, vCopy );
|
|
Abc_NtKSelectRemove2( vSupps, vCopy, pNtk );
|
|
}
|
|
return vRes;
|
|
}
|
|
Abc_Ntk_t * Abc_NtkDupWindow( Abc_Ntk_t * p, Vec_Int_t * vIns, Vec_Int_t * vNodes, Vec_Int_t * vOuts )
|
|
{
|
|
Abc_Ntk_t * pNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_MAP, 0 );
|
|
pNew->pName = Abc_UtilStrsav( p->pName );
|
|
pNew->pSpec = Abc_UtilStrsav( p->pSpec );
|
|
pNew->pManFunc = p->pManFunc;
|
|
Abc_Obj_t * pObj; int i;
|
|
Abc_NtkForEachObjVec( vIns, p, pObj, i )
|
|
pObj->pCopy = Abc_NtkCreatePi(pNew);
|
|
Abc_NtkForEachObjVec( vOuts, p, pObj, i )
|
|
Abc_NtkCreatePo( pNew );
|
|
Abc_NtkForEachObjVec( vNodes, p, pObj, i )
|
|
Abc_NtkCreateNodeMapped( pNew, pObj );
|
|
Abc_NtkForEachObjVec( vOuts, p, pObj, i )
|
|
Abc_ObjAddFanin( Abc_NtkCo(pNew, i), pObj->pCopy );
|
|
Abc_NtkForEachObjVec( vIns, p, pObj, i )
|
|
pObj->pCopy = NULL;
|
|
Abc_NtkForEachObjVec( vNodes, p, pObj, i )
|
|
pObj->pCopy = NULL;
|
|
Abc_NtkAddDummyPiNames( pNew );
|
|
Abc_NtkAddDummyPoNames( pNew );
|
|
return pNew;
|
|
}
|
|
Vec_Ptr_t * Abc_NtkDupWindows( Abc_Ntk_t * pNtk, Vec_Ptr_t * vvIns, Vec_Ptr_t * vvNodes, Vec_Ptr_t * vvOuts )
|
|
{
|
|
Vec_Int_t * vNodes; int i;
|
|
Vec_Ptr_t * vWins = Vec_PtrAlloc( Vec_PtrSize(vvIns) );
|
|
assert( Vec_PtrSize(vvIns) == Vec_PtrSize(vvNodes) );
|
|
assert( Vec_PtrSize(vvOuts) == Vec_PtrSize(vvNodes) );
|
|
Abc_NtkCleanCopy( pNtk );
|
|
Abc_NtkCleanMarkABC( pNtk );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vvNodes, vNodes, i ) {
|
|
Vec_Int_t * vIns = (Vec_Int_t *)Vec_PtrEntry(vvIns, i);
|
|
Vec_Int_t * vOuts = (Vec_Int_t *)Vec_PtrEntry(vvOuts, i);
|
|
Abc_Ntk_t * pNew = Abc_NtkDupWindow( pNtk, vIns, vNodes, vOuts );
|
|
Vec_PtrPush( vWins, pNew );
|
|
}
|
|
return vWins;
|
|
}
|
|
Vec_Ptr_t * Abc_NtkExtractPartitions( Abc_Ntk_t * pNtk, int Iter, int nSuppMax, Vec_Ptr_t ** pvIns, Vec_Ptr_t ** pvOuts, Vec_Ptr_t ** pvNodes )
|
|
{
|
|
if ( Abc_NtkCiNum(pNtk) <= nSuppMax ) {
|
|
Vec_Ptr_t * vWins = Vec_PtrAlloc( 1 );
|
|
Vec_PtrPush( vWins, Abc_NtkDupDfs(pNtk) );
|
|
*pvIns = *pvOuts = *pvNodes = NULL;
|
|
return vWins;
|
|
}
|
|
int iUseRevL = Iter % 3 == 0 ? 0 : Abc_Random(0) & 1;
|
|
int LevelMax = iUseRevL ? Abc_NtkLevelR(pNtk) : Abc_NtkLevel(pNtk);
|
|
int LevelCut = Iter % 3 == 0 ? 0 : LevelMax > 8 ? 2 + (Abc_Random(0) % (LevelMax - 4)) : 0;
|
|
//printf( "Using %s cut level %d (out of %d)\n", iUseRevL ? "reverse": "direct", LevelCut, LevelMax );
|
|
Abc_NtkPermuteLevel( pNtk, LevelMax );
|
|
Vec_Wec_t * vStore = Vec_WecStart( LevelMax+1 );
|
|
Vec_Wec_t * vSupps = Abc_NtkCollectObjectsWithSuppLimit( pNtk, LevelCut, nSuppMax );
|
|
Vec_Ptr_t * vIns = Abc_NtkDeriveWinInsAll( vSupps, nSuppMax, pNtk );
|
|
Vec_Ptr_t * vNodes = Abc_NtkDeriveWinNodesAll( pNtk, vIns, vStore );
|
|
Vec_Ptr_t * vOuts = Abc_NtkDeriveWinOutsAll( pNtk, vNodes );
|
|
Vec_Ptr_t * vWins = Abc_NtkDupWindows( pNtk, vIns, vNodes, vOuts );
|
|
Vec_WecFree( vSupps );
|
|
Vec_WecFree( vStore );
|
|
*pvIns = vIns;
|
|
*pvOuts = vOuts;
|
|
*pvNodes = vNodes;
|
|
return vWins;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs stochastic mapping.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkStochMap( int nSuppMax, int nIters, int TimeOut, int Seed, int fVerbose, char * pScript, int nProcs )
|
|
{
|
|
abctime clkStart = Abc_Clock(); int i;
|
|
abctime nTimeToStop = TimeOut ? Abc_Clock() + TimeOut * CLOCKS_PER_SEC : 0;
|
|
float aEnd, aBeg = Abc_NtkGetMappedArea(Abc_FrameReadNtk(Abc_FrameGetGlobalFrame()));
|
|
assert( Abc_NtkIsMappedLogic(Abc_FrameReadNtk(Abc_FrameGetGlobalFrame())) );
|
|
Abc_Random(1);
|
|
for ( i = 0; i < 10+Seed; i++ )
|
|
Abc_Random(0);
|
|
if ( fVerbose ) {
|
|
printf( "Running %d iterations of the script \"%s\"", nIters, pScript );
|
|
if ( nProcs > 2 )
|
|
printf( " using %d concurrent threads.\n", nProcs-1 );
|
|
else
|
|
printf( " without concurrency.\n" );
|
|
fflush(stdout);
|
|
}
|
|
Vec_Ptr_t * vIns = NULL, * vOuts = NULL, * vNodes = NULL;
|
|
for ( i = 0; i < nIters; i++ )
|
|
{
|
|
abctime clk = Abc_Clock();
|
|
Abc_Ntk_t * pNtk = Abc_NtkDupDfs(Abc_FrameReadNtk(Abc_FrameGetGlobalFrame()));
|
|
Vec_Ptr_t * vWins = Abc_NtkExtractPartitions( pNtk, i, nSuppMax, &vIns, &vOuts, &vNodes );
|
|
Vec_Ptr_t * vOpts = Abc_NtkStochProcess( vWins, pScript, nProcs, 0, 0 );
|
|
Abc_Ntk_t * pNew = Abc_NtkInsertPartitions( pNtk, vIns, vOuts, vWins );
|
|
Abc_FrameReplaceCurrentNetwork( Abc_FrameGetGlobalFrame(), pNew );
|
|
if ( fVerbose )
|
|
printf( "Iteration %3d : Using %3d partitions. Reducing area from %.2f to %.2f. ",
|
|
i, Vec_PtrSize(vWins), Abc_NtkGetMappedArea(pNtk), Abc_NtkGetMappedArea(pNew) );
|
|
if ( fVerbose )
|
|
Abc_PrintTime( 0, "Time", Abc_Clock() - clk );
|
|
// cleanup
|
|
Abc_NtkDelete( pNtk );
|
|
Vec_PtrFreeFunc( vWins, (void (*)(void *)) Abc_NtkDelete );
|
|
//Vec_PtrFreeFunc( vOpts, (void (*)(void *)) Abc_NtkDelete );
|
|
vOpts = NULL;
|
|
if ( vIns ) Vec_PtrFreeFunc( vIns, (void (*)(void *)) Vec_IntFree );
|
|
if ( vOuts ) Vec_PtrFreeFunc( vOuts, (void (*)(void *)) Vec_IntFree );
|
|
if ( vNodes ) Vec_PtrFreeFunc( vNodes, (void (*)(void *)) Vec_IntFree );
|
|
if ( nTimeToStop && Abc_Clock() > nTimeToStop )
|
|
{
|
|
printf( "Runtime limit (%d sec) is reached after %d iterations.\n", TimeOut, i );
|
|
break;
|
|
}
|
|
}
|
|
aEnd = Abc_NtkGetMappedArea(Abc_FrameReadNtk(Abc_FrameGetGlobalFrame()));
|
|
if ( fVerbose )
|
|
printf( "Cumulatively reduced area by %.2f %% after %d iterations. ", 100.0*(aBeg - aEnd)/aBeg, nIters );
|
|
if ( fVerbose )
|
|
Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|