blob: a3abee8951b3ec138cc29308cf25dcd32c0cbfb0 [file] [log] [blame]
/**CFile****************************************************************
FileName [abcMulti.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Network and node package.]
Synopsis [Procedures which transform an AIG into multi-input AND-graph.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: abcMulti.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "base/abc/abc.h"
#ifdef ABC_USE_CUDD
#include "bdd/extrab/extraBdd.h"
#endif
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
#ifdef ABC_USE_CUDD
static void Abc_NtkMultiInt( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew );
static Abc_Obj_t * Abc_NtkMulti_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNodeOld );
static DdNode * Abc_NtkMultiDeriveBdd_rec( DdManager * dd, Abc_Obj_t * pNodeOld, Vec_Ptr_t * vFanins );
static DdNode * Abc_NtkMultiDeriveBdd( DdManager * dd, Abc_Obj_t * pNodeOld, Vec_Ptr_t * vFaninsOld );
static void Abc_NtkMultiSetBounds( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax );
static void Abc_NtkMultiSetBoundsCnf( Abc_Ntk_t * pNtk );
static void Abc_NtkMultiSetBoundsMulti( Abc_Ntk_t * pNtk, int nThresh );
static void Abc_NtkMultiSetBoundsSimple( Abc_Ntk_t * pNtk );
static void Abc_NtkMultiSetBoundsFactor( Abc_Ntk_t * pNtk );
static void Abc_NtkMultiCone( Abc_Obj_t * pNode, Vec_Ptr_t * vCone );
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Transforms the AIG into nodes.]
Description [Threhold is the max number of nodes duplicated at a node.]
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Ntk_t * Abc_NtkMulti( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax, int fCnf, int fMulti, int fSimple, int fFactor )
{
Abc_Ntk_t * pNtkNew;
assert( Abc_NtkIsStrash(pNtk) );
assert( nThresh >= 0 );
assert( nFaninMax > 1 );
// print a warning about choice nodes
if ( Abc_NtkGetChoiceNum( pNtk ) )
printf( "Warning: The choice nodes in the AIG are removed by renoding.\n" );
// define the boundary
if ( fCnf )
Abc_NtkMultiSetBoundsCnf( pNtk );
else if ( fMulti )
Abc_NtkMultiSetBoundsMulti( pNtk, nThresh );
else if ( fSimple )
Abc_NtkMultiSetBoundsSimple( pNtk );
else if ( fFactor )
Abc_NtkMultiSetBoundsFactor( pNtk );
else
Abc_NtkMultiSetBounds( pNtk, nThresh, nFaninMax );
// perform renoding for this boundary
pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC, ABC_FUNC_BDD );
Abc_NtkMultiInt( pNtk, pNtkNew );
Abc_NtkFinalize( pNtk, pNtkNew );
// make the network minimum base
Abc_NtkMinimumBase( pNtkNew );
// fix the problem with complemented and duplicated CO edges
Abc_NtkLogicMakeSimpleCos( pNtkNew, 0 );
// report the number of CNF objects
if ( fCnf )
{
// int nClauses = Abc_NtkGetClauseNum(pNtkNew) + 2*Abc_NtkPoNum(pNtkNew) + 2*Abc_NtkLatchNum(pNtkNew);
// printf( "CNF variables = %d. CNF clauses = %d.\n", Abc_NtkNodeNum(pNtkNew), nClauses );
}
//printf( "Maximum fanin = %d.\n", Abc_NtkGetFaninMax(pNtkNew) );
if ( pNtk->pExdc )
pNtkNew->pExdc = Abc_NtkDup( pNtk->pExdc );
// make sure everything is okay
if ( !Abc_NtkCheck( pNtkNew ) )
{
printf( "Abc_NtkMulti: The network check has failed.\n" );
Abc_NtkDelete( pNtkNew );
return NULL;
}
return pNtkNew;
}
/**Function*************************************************************
Synopsis [Transforms the AIG into nodes.]
Description [Threhold is the max number of nodes duplicated at a node.]
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMultiInt( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
{
ProgressBar * pProgress;
Abc_Obj_t * pNode, * pConst1, * pNodeNew;
int i;
// set the constant node
pConst1 = Abc_AigConst1(pNtk);
if ( Abc_ObjFanoutNum(pConst1) > 0 )
{
pNodeNew = Abc_NtkCreateNode( pNtkNew );
pNodeNew->pData = Cudd_ReadOne( (DdManager *)pNtkNew->pManFunc ); Cudd_Ref( (DdNode *)pNodeNew->pData );
pConst1->pCopy = pNodeNew;
}
// perform renoding for POs
pProgress = Extra_ProgressBarStart( stdout, Abc_NtkCoNum(pNtk) );
Abc_NtkForEachCo( pNtk, pNode, i )
{
Extra_ProgressBarUpdate( pProgress, i, NULL );
if ( Abc_ObjIsCi(Abc_ObjFanin0(pNode)) )
continue;
Abc_NtkMulti_rec( pNtkNew, Abc_ObjFanin0(pNode) );
}
Extra_ProgressBarStop( pProgress );
// clean the boundaries and data field in the old network
Abc_NtkForEachObj( pNtk, pNode, i )
{
pNode->fMarkA = 0;
pNode->pData = NULL;
}
}
/**Function*************************************************************
Synopsis [Find the best multi-input node rooted at the given node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Obj_t * Abc_NtkMulti_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNodeOld )
{
Vec_Ptr_t * vCone;
Abc_Obj_t * pNodeNew;
int i;
assert( !Abc_ObjIsComplement(pNodeOld) );
// return if the result if known
if ( pNodeOld->pCopy )
return pNodeOld->pCopy;
assert( Abc_ObjIsNode(pNodeOld) );
assert( !Abc_AigNodeIsConst(pNodeOld) );
assert( pNodeOld->fMarkA );
//printf( "%d ", Abc_NodeMffcSizeSupp(pNodeOld) );
// collect the renoding cone
vCone = Vec_PtrAlloc( 10 );
Abc_NtkMultiCone( pNodeOld, vCone );
// create a new node
pNodeNew = Abc_NtkCreateNode( pNtkNew );
for ( i = 0; i < vCone->nSize; i++ )
Abc_ObjAddFanin( pNodeNew, Abc_NtkMulti_rec(pNtkNew, (Abc_Obj_t *)vCone->pArray[i]) );
// derive the function of this node
pNodeNew->pData = Abc_NtkMultiDeriveBdd( (DdManager *)pNtkNew->pManFunc, pNodeOld, vCone );
Cudd_Ref( (DdNode *)pNodeNew->pData );
Vec_PtrFree( vCone );
// remember the node
pNodeOld->pCopy = pNodeNew;
return pNodeOld->pCopy;
}
/**Function*************************************************************
Synopsis [Derives the local BDD of the node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
DdNode * Abc_NtkMultiDeriveBdd( DdManager * dd, Abc_Obj_t * pNodeOld, Vec_Ptr_t * vFaninsOld )
{
Abc_Obj_t * pFaninOld;
DdNode * bFunc;
int i;
assert( !Abc_AigNodeIsConst(pNodeOld) );
assert( Abc_ObjIsNode(pNodeOld) );
// set the elementary BDD variables for the input nodes
for ( i = 0; i < vFaninsOld->nSize; i++ )
{
pFaninOld = (Abc_Obj_t *)vFaninsOld->pArray[i];
pFaninOld->pData = Cudd_bddIthVar( dd, i ); Cudd_Ref( (DdNode *)pFaninOld->pData );
pFaninOld->fMarkC = 1;
}
// call the recursive BDD computation
bFunc = Abc_NtkMultiDeriveBdd_rec( dd, pNodeOld, vFaninsOld ); Cudd_Ref( bFunc );
// dereference the intermediate nodes
for ( i = 0; i < vFaninsOld->nSize; i++ )
{
pFaninOld = (Abc_Obj_t *)vFaninsOld->pArray[i];
Cudd_RecursiveDeref( dd, (DdNode *)pFaninOld->pData );
pFaninOld->fMarkC = 0;
}
Cudd_Deref( bFunc );
return bFunc;
}
/**Function*************************************************************
Synopsis [Derives the local BDD of the node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
DdNode * Abc_NtkMultiDeriveBdd_rec( DdManager * dd, Abc_Obj_t * pNode, Vec_Ptr_t * vFanins )
{
DdNode * bFunc, * bFunc0, * bFunc1;
assert( !Abc_ObjIsComplement(pNode) );
// if the result is available return
if ( pNode->fMarkC )
{
assert( pNode->pData ); // network has a cycle
return (DdNode *)pNode->pData;
}
// mark the node as visited
pNode->fMarkC = 1;
Vec_PtrPush( vFanins, pNode );
// compute the result for both branches
bFunc0 = Abc_NtkMultiDeriveBdd_rec( dd, Abc_ObjFanin(pNode,0), vFanins ); Cudd_Ref( bFunc0 );
bFunc1 = Abc_NtkMultiDeriveBdd_rec( dd, Abc_ObjFanin(pNode,1), vFanins ); Cudd_Ref( bFunc1 );
bFunc0 = Cudd_NotCond( bFunc0, (long)Abc_ObjFaninC0(pNode) );
bFunc1 = Cudd_NotCond( bFunc1, (long)Abc_ObjFaninC1(pNode) );
// get the final result
bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc );
Cudd_RecursiveDeref( dd, bFunc0 );
Cudd_RecursiveDeref( dd, bFunc1 );
// set the result
pNode->pData = bFunc;
assert( pNode->pData );
return bFunc;
}
/**Function*************************************************************
Synopsis [Limits the cones to be no more than the given size.]
Description [Returns 1 if the last cone was limited. Returns 0 if no changes.]
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMultiLimit_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vCone, int nFaninMax, int fCanStop, int fFirst )
{
int nNodes0, nNodes1;
assert( !Abc_ObjIsComplement(pNode) );
// check if the node should be added to the fanins
if ( !fFirst && (pNode->fMarkA || !Abc_ObjIsNode(pNode)) )
{
Vec_PtrPushUnique( vCone, pNode );
return 0;
}
// if we cannot stop in this branch, collect all nodes
if ( !fCanStop )
{
Abc_NtkMultiLimit_rec( Abc_ObjFanin(pNode,0), vCone, nFaninMax, 0, 0 );
Abc_NtkMultiLimit_rec( Abc_ObjFanin(pNode,1), vCone, nFaninMax, 0, 0 );
return 0;
}
// if we can stop, try the left branch first, and return if we stopped
assert( vCone->nSize == 0 );
if ( Abc_NtkMultiLimit_rec( Abc_ObjFanin(pNode,0), vCone, nFaninMax, 1, 0 ) )
return 1;
// save the number of nodes in the left branch and call for the right branch
nNodes0 = vCone->nSize;
assert( nNodes0 <= nFaninMax );
Abc_NtkMultiLimit_rec( Abc_ObjFanin(pNode,1), vCone, nFaninMax, 0, 0 );
// check the number of nodes
if ( vCone->nSize <= nFaninMax )
return 0;
// the number of nodes exceeds the limit
// get the number of nodes in the right branch
vCone->nSize = 0;
Abc_NtkMultiLimit_rec( Abc_ObjFanin(pNode,1), vCone, nFaninMax, 0, 0 );
// if this number exceeds the limit, solve the problem for this branch
if ( vCone->nSize > nFaninMax )
{
int RetValue;
vCone->nSize = 0;
RetValue = Abc_NtkMultiLimit_rec( Abc_ObjFanin(pNode,1), vCone, nFaninMax, 1, 0 );
assert( RetValue == 1 );
return 1;
}
nNodes1 = vCone->nSize;
assert( nNodes1 <= nFaninMax );
if ( nNodes0 >= nNodes1 )
{ // the left branch is larger - cut it
assert( Abc_ObjFanin(pNode,0)->fMarkA == 0 );
Abc_ObjFanin(pNode,0)->fMarkA = 1;
}
else
{ // the right branch is larger - cut it
assert( Abc_ObjFanin(pNode,1)->fMarkA == 0 );
Abc_ObjFanin(pNode,1)->fMarkA = 1;
}
return 1;
}
/**Function*************************************************************
Synopsis [Limits the cones to be no more than the given size.]
Description [Returns 1 if the last cone was limited. Returns 0 if no changes.]
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMultiLimit( Abc_Obj_t * pNode, Vec_Ptr_t * vCone, int nFaninMax )
{
vCone->nSize = 0;
return Abc_NtkMultiLimit_rec( pNode, vCone, nFaninMax, 1, 1 );
}
/**Function*************************************************************
Synopsis [Sets the expansion boundary for multi-input nodes.]
Description [The boundary includes the set of PIs and all nodes such that
when expanding over the node we duplicate no more than nThresh nodes.]
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMultiSetBounds( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax )
{
Vec_Ptr_t * vCone = Vec_PtrAlloc(10);
Abc_Obj_t * pNode;
int i, nFanouts, nConeSize;
// make sure the mark is not set
Abc_NtkForEachObj( pNtk, pNode, i )
assert( pNode->fMarkA == 0 );
// mark the nodes where expansion stops using pNode->fMarkA
Abc_NtkForEachNode( pNtk, pNode, i )
{
// skip PI/PO nodes
// if ( Abc_NodeIsConst(pNode) )
// continue;
// mark the nodes with multiple fanouts
nFanouts = Abc_ObjFanoutNum(pNode);
nConeSize = Abc_NodeMffcSize(pNode);
if ( (nFanouts - 1) * nConeSize > nThresh )
pNode->fMarkA = 1;
}
// mark the PO drivers
Abc_NtkForEachCo( pNtk, pNode, i )
Abc_ObjFanin0(pNode)->fMarkA = 1;
// make sure the fanin limit is met
Abc_NtkForEachNode( pNtk, pNode, i )
{
// skip PI/PO nodes
// if ( Abc_NodeIsConst(pNode) )
// continue;
if ( pNode->fMarkA == 0 )
continue;
// continue cutting branches until it meets the fanin limit
while ( Abc_NtkMultiLimit(pNode, vCone, nFaninMax) );
assert( vCone->nSize <= nFaninMax );
}
Vec_PtrFree(vCone);
/*
// make sure the fanin limit is met
Abc_NtkForEachNode( pNtk, pNode, i )
{
// skip PI/PO nodes
// if ( Abc_NodeIsConst(pNode) )
// continue;
if ( pNode->fMarkA == 0 )
continue;
Abc_NtkMultiCone( pNode, vCone );
assert( vCone->nSize <= nFaninMax );
}
*/
}
/**Function*************************************************************
Synopsis [Sets the expansion boundary for conversion into CNF.]
Description [The boundary includes the set of PIs, the roots of MUXes,
the nodes with multiple fanouts and the nodes with complemented outputs.]
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMultiSetBoundsCnf( Abc_Ntk_t * pNtk )
{
Abc_Obj_t * pNode;
int i, nMuxes;
// make sure the mark is not set
Abc_NtkForEachObj( pNtk, pNode, i )
assert( pNode->fMarkA == 0 );
// mark the nodes where expansion stops using pNode->fMarkA
Abc_NtkForEachNode( pNtk, pNode, i )
{
// skip PI/PO nodes
// if ( Abc_NodeIsConst(pNode) )
// continue;
// mark the nodes with multiple fanouts
if ( Abc_ObjFanoutNum(pNode) > 1 )
pNode->fMarkA = 1;
// mark the nodes that are roots of MUXes
if ( Abc_NodeIsMuxType( pNode ) )
{
pNode->fMarkA = 1;
Abc_ObjFanin0( Abc_ObjFanin0(pNode) )->fMarkA = 1;
Abc_ObjFanin0( Abc_ObjFanin1(pNode) )->fMarkA = 1;
Abc_ObjFanin1( Abc_ObjFanin0(pNode) )->fMarkA = 1;
Abc_ObjFanin1( Abc_ObjFanin1(pNode) )->fMarkA = 1;
}
else // mark the complemented edges
{
if ( Abc_ObjFaninC0(pNode) )
Abc_ObjFanin0(pNode)->fMarkA = 1;
if ( Abc_ObjFaninC1(pNode) )
Abc_ObjFanin1(pNode)->fMarkA = 1;
}
}
// mark the PO drivers
Abc_NtkForEachCo( pNtk, pNode, i )
Abc_ObjFanin0(pNode)->fMarkA = 1;
// count the number of MUXes
nMuxes = 0;
Abc_NtkForEachNode( pNtk, pNode, i )
{
// skip PI/PO nodes
// if ( Abc_NodeIsConst(pNode) )
// continue;
if ( Abc_NodeIsMuxType(pNode) &&
Abc_ObjFanin0(pNode)->fMarkA == 0 &&
Abc_ObjFanin1(pNode)->fMarkA == 0 )
nMuxes++;
}
// printf( "The number of MUXes detected = %d (%5.2f %% of logic).\n", nMuxes, 300.0*nMuxes/Abc_NtkNodeNum(pNtk) );
}
/**Function*************************************************************
Synopsis [Sets the expansion boundary for conversion into multi-input AND graph.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMultiSetBoundsMulti( Abc_Ntk_t * pNtk, int nThresh )
{
Abc_Obj_t * pNode;
int i, nFanouts, nConeSize;
// make sure the mark is not set
Abc_NtkForEachObj( pNtk, pNode, i )
assert( pNode->fMarkA == 0 );
// mark the nodes where expansion stops using pNode->fMarkA
Abc_NtkForEachNode( pNtk, pNode, i )
{
// skip PI/PO nodes
// if ( Abc_NodeIsConst(pNode) )
// continue;
// mark the nodes with multiple fanouts
// if ( Abc_ObjFanoutNum(pNode) > 1 )
// pNode->fMarkA = 1;
// mark the nodes with multiple fanouts
nFanouts = Abc_ObjFanoutNum(pNode);
nConeSize = Abc_NodeMffcSizeStop(pNode);
if ( (nFanouts - 1) * nConeSize > nThresh )
pNode->fMarkA = 1;
// mark the children if they are pointed by the complemented edges
if ( Abc_ObjFaninC0(pNode) )
Abc_ObjFanin0(pNode)->fMarkA = 1;
if ( Abc_ObjFaninC1(pNode) )
Abc_ObjFanin1(pNode)->fMarkA = 1;
}
// mark the PO drivers
Abc_NtkForEachCo( pNtk, pNode, i )
Abc_ObjFanin0(pNode)->fMarkA = 1;
}
/**Function*************************************************************
Synopsis [Sets a simple boundary.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMultiSetBoundsSimple( Abc_Ntk_t * pNtk )
{
Abc_Obj_t * pNode;
int i;
// make sure the mark is not set
Abc_NtkForEachObj( pNtk, pNode, i )
assert( pNode->fMarkA == 0 );
// mark the nodes where expansion stops using pNode->fMarkA
Abc_NtkForEachNode( pNtk, pNode, i )
pNode->fMarkA = 1;
}
/**Function*************************************************************
Synopsis [Sets a factor-cut boundary.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMultiSetBoundsFactor( Abc_Ntk_t * pNtk )
{
Abc_Obj_t * pNode;
int i;
// make sure the mark is not set
Abc_NtkForEachObj( pNtk, pNode, i )
assert( pNode->fMarkA == 0 );
// mark the nodes where expansion stops using pNode->fMarkA
Abc_NtkForEachNode( pNtk, pNode, i )
pNode->fMarkA = (pNode->vFanouts.nSize > 1 && !Abc_NodeIsMuxControlType(pNode));
// mark the PO drivers
Abc_NtkForEachCo( pNtk, pNode, i )
Abc_ObjFanin0(pNode)->fMarkA = 1;
}
/**Function*************************************************************
Synopsis [Collects the fanins of a large node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMultiCone_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vCone )
{
assert( !Abc_ObjIsComplement(pNode) );
if ( pNode->fMarkA || !Abc_ObjIsNode(pNode) )
{
Vec_PtrPushUnique( vCone, pNode );
return;
}
Abc_NtkMultiCone_rec( Abc_ObjFanin(pNode,0), vCone );
Abc_NtkMultiCone_rec( Abc_ObjFanin(pNode,1), vCone );
}
/**Function*************************************************************
Synopsis [Collects the fanins of a large node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMultiCone( Abc_Obj_t * pNode, Vec_Ptr_t * vCone )
{
assert( !Abc_ObjIsComplement(pNode) );
assert( Abc_ObjIsNode(pNode) );
vCone->nSize = 0;
Abc_NtkMultiCone_rec( Abc_ObjFanin(pNode,0), vCone );
Abc_NtkMultiCone_rec( Abc_ObjFanin(pNode,1), vCone );
}
#else
Abc_Ntk_t * Abc_NtkMulti( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax, int fCnf, int fMulti, int fSimple, int fFactor ) { return NULL; }
#endif
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END