/**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