blob: c137a65902d583ef73d0942c760d5eba15749482 [file] [log] [blame]
/**CFile****************************************************************
FileName [ivyMulti.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [And-Inverter Graph package.]
Synopsis [Constructing multi-input AND/EXOR gates.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - May 11, 2006.]
Revision [$Id: ivyMulti.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
***********************************************************************/
#include "ivy.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
#define IVY_EVAL_LIMIT 128
typedef struct Ivy_Eva_t_ Ivy_Eva_t;
struct Ivy_Eva_t_
{
Ivy_Obj_t * pArg; // the argument node
unsigned Mask; // the mask of covered nodes
int Weight; // the number of covered nodes
};
static void Ivy_MultiPrint( Ivy_Man_t * p, Ivy_Eva_t * pEvals, int nLeaves, int nEvals );
static int Ivy_MultiCover( Ivy_Man_t * p, Ivy_Eva_t * pEvals, int nLeaves, int nEvals, int nLimit, Vec_Ptr_t * vSols );
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Constructs a balanced tree while taking sharing into account.]
Description [Returns 1 if the implementation exists.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_MultiPlus( Ivy_Man_t * p, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone, Ivy_Type_t Type, int nLimit, Vec_Ptr_t * vSols )
{
static Ivy_Eva_t pEvals[IVY_EVAL_LIMIT];
Ivy_Eva_t * pEval, * pFan0, * pFan1;
Ivy_Obj_t * pObj = NULL; // Suppress "might be used uninitialized"
Ivy_Obj_t * pTemp;
int nEvals, nEvalsOld, i, k, x, nLeaves;
unsigned uMaskAll;
// consider special cases
nLeaves = Vec_PtrSize(vLeaves);
assert( nLeaves > 2 );
if ( nLeaves > 32 || nLeaves + Vec_PtrSize(vCone) > IVY_EVAL_LIMIT )
return 0;
// if ( nLeaves == 1 )
// return Vec_PtrEntry( vLeaves, 0 );
// if ( nLeaves == 2 )
// return Ivy_Oper( Vec_PtrEntry(vLeaves, 0), Vec_PtrEntry(vLeaves, 1), Type );
// set the leaf entries
uMaskAll = ((1 << nLeaves) - 1);
nEvals = 0;
Vec_PtrForEachEntry( Ivy_Obj_t *, vLeaves, pObj, i )
{
pEval = pEvals + nEvals;
pEval->pArg = pObj;
pEval->Mask = (1 << nEvals);
pEval->Weight = 1;
// mark the leaf
Ivy_Regular(pObj)->TravId = nEvals;
nEvals++;
}
// propagate masks through the cone
Vec_PtrForEachEntry( Ivy_Obj_t *, vCone, pObj, i )
{
pObj->TravId = nEvals + i;
if ( Ivy_ObjIsBuf(pObj) )
pEvals[pObj->TravId].Mask = pEvals[Ivy_ObjFanin0(pObj)->TravId].Mask;
else
pEvals[pObj->TravId].Mask = pEvals[Ivy_ObjFanin0(pObj)->TravId].Mask | pEvals[Ivy_ObjFanin1(pObj)->TravId].Mask;
}
// set the internal entries
Vec_PtrForEachEntry( Ivy_Obj_t *, vCone, pObj, i )
{
if ( i == Vec_PtrSize(vCone) - 1 )
break;
// skip buffers
if ( Ivy_ObjIsBuf(pObj) )
continue;
// skip nodes without external fanout
if ( Ivy_ObjRefs(pObj) == 0 )
continue;
assert( !Ivy_IsComplement(pObj) );
pEval = pEvals + nEvals;
pEval->pArg = pObj;
pEval->Mask = pEvals[pObj->TravId].Mask;
pEval->Weight = Extra_WordCountOnes(pEval->Mask);
// mark the node
pObj->TravId = nEvals;
nEvals++;
}
// find the available nodes
nEvalsOld = nEvals;
for ( i = 1; i < nEvals; i++ )
for ( k = 0; k < i; k++ )
{
pFan0 = pEvals + i;
pFan1 = pEvals + k;
pTemp = Ivy_TableLookup(p, Ivy_ObjCreateGhost(p, pFan0->pArg, pFan1->pArg, Type, IVY_INIT_NONE));
// skip nodes in the cone
if ( pTemp == NULL || pTemp->fMarkB )
continue;
// skip the leaves
for ( x = 0; x < nLeaves; x++ )
if ( pTemp == Ivy_Regular((Ivy_Obj_t *)vLeaves->pArray[x]) )
break;
if ( x < nLeaves )
continue;
pEval = pEvals + nEvals;
pEval->pArg = pTemp;
pEval->Mask = pFan0->Mask | pFan1->Mask;
pEval->Weight = (pFan0->Mask & pFan1->Mask) ? Extra_WordCountOnes(pEval->Mask) : pFan0->Weight + pFan1->Weight;
// save the argument
pObj->TravId = nEvals;
nEvals++;
// quit if the number of entries exceeded the limit
if ( nEvals == IVY_EVAL_LIMIT )
goto Outside;
// quit if we found an acceptable implementation
if ( pEval->Mask == uMaskAll )
goto Outside;
}
Outside:
// Ivy_MultiPrint( pEvals, nLeaves, nEvals );
if ( !Ivy_MultiCover( p, pEvals, nLeaves, nEvals, nLimit, vSols ) )
return 0;
assert( Vec_PtrSize( vSols ) > 0 );
return 1;
}
/**Function*************************************************************
Synopsis [Computes how many uncovered ones this one covers.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_MultiPrint( Ivy_Man_t * p, Ivy_Eva_t * pEvals, int nLeaves, int nEvals )
{
Ivy_Eva_t * pEval;
int i, k;
for ( i = nLeaves; i < nEvals; i++ )
{
pEval = pEvals + i;
printf( "%2d (id = %5d) : |", i-nLeaves, Ivy_ObjId(pEval->pArg) );
for ( k = 0; k < nLeaves; k++ )
{
if ( pEval->Mask & (1 << k) )
printf( "+" );
else
printf( " " );
}
printf( "| Lev = %d.\n", Ivy_ObjLevel(pEval->pArg) );
}
}
/**Function*************************************************************
Synopsis [Computes how many uncovered ones this one covers.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Ivy_MultiWeight( unsigned uMask, int nMaskOnes, unsigned uFound )
{
assert( uMask & ~uFound );
if ( (uMask & uFound) == 0 )
return nMaskOnes;
return Extra_WordCountOnes( uMask & ~uFound );
}
/**Function*************************************************************
Synopsis [Finds the cover.]
Description [Returns 1 if the cover is found.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_MultiCover( Ivy_Man_t * p, Ivy_Eva_t * pEvals, int nLeaves, int nEvals, int nLimit, Vec_Ptr_t * vSols )
{
int fVerbose = 0;
Ivy_Eva_t * pEval;
Ivy_Eva_t * pEvalBest = NULL; // Suppress "might be used uninitialized"
unsigned uMaskAll, uFound, uTemp;
int i, k, BestK;
int WeightBest = -1; // Suppress "might be used uninitialized"
int WeightCur;
int LevelBest = -1; // Suppress "might be used uninitialized"
int LevelCur;
uMaskAll = (nLeaves == 32)? (~(unsigned)0) : ((1 << nLeaves) - 1);
uFound = 0;
// solve the covering problem
if ( fVerbose )
printf( "Solution: " );
Vec_PtrClear( vSols );
for ( i = 0; i < nLimit; i++ )
{
BestK = -1;
for ( k = nEvals - 1; k >= 0; k-- )
{
pEval = pEvals + k;
if ( (pEval->Mask & ~uFound) == 0 )
continue;
if ( BestK == -1 )
{
BestK = k;
pEvalBest = pEval;
WeightBest = Ivy_MultiWeight( pEvalBest->Mask, pEvalBest->Weight, uFound );
LevelBest = Ivy_ObjLevel( Ivy_Regular(pEvalBest->pArg) );
continue;
}
// compare BestK and the new one (k)
WeightCur = Ivy_MultiWeight( pEval->Mask, pEval->Weight, uFound );
LevelCur = Ivy_ObjLevel( Ivy_Regular(pEval->pArg) );
if ( WeightBest < WeightCur ||
(WeightBest == WeightCur && LevelBest > LevelCur) )
{
BestK = k;
pEvalBest = pEval;
WeightBest = WeightCur;
LevelBest = LevelCur;
}
}
assert( BestK != -1 );
// if the cost is only 1, take the leaf
if ( WeightBest == 1 && BestK >= nLeaves )
{
uTemp = (pEvalBest->Mask & ~uFound);
for ( k = 0; k < nLeaves; k++ )
if ( uTemp & (1 << k) )
break;
assert( k < nLeaves );
BestK = k;
pEvalBest = pEvals + BestK;
}
if ( fVerbose )
{
if ( BestK < nLeaves )
printf( "L(%d) ", BestK );
else
printf( "%d ", BestK - nLeaves );
}
// update the found set
Vec_PtrPush( vSols, pEvalBest->pArg );
uFound |= pEvalBest->Mask;
if ( uFound == uMaskAll )
break;
}
if ( uFound == uMaskAll )
{
if ( fVerbose )
printf( " Found \n\n" );
return 1;
}
else
{
if ( fVerbose )
printf( " Not found \n\n" );
return 0;
}
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END