/**CFile**************************************************************** FileName [abcOdc.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Network and node package.] Synopsis [Scalable computation of observability don't-cares.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 20, 2005.] Revision [$Id: abcOdc.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] ***********************************************************************/ #include "base/abc/abc.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// #define ABC_DC_MAX_NODES (1<<15) typedef unsigned short Odc_Lit_t; typedef struct Odc_Obj_t_ Odc_Obj_t; // 16 bytes struct Odc_Obj_t_ { Odc_Lit_t iFan0; // first fanin Odc_Lit_t iFan1; // second fanin Odc_Lit_t iNext; // next node in the hash table unsigned short TravId; // the traversal ID unsigned uData; // the computed data unsigned uMask; // the variable mask }; struct Odc_Man_t_ { // dont'-care parameters int nVarsMax; // the max number of cut variables int nLevels; // the number of ODC levels int fVerbose; // the verbosiness flag int fVeryVerbose;// the verbosiness flag to print per-node stats int nPercCutoff; // cutoff percentage // windowing Abc_Obj_t * pNode; // the node for windowing Vec_Ptr_t * vLeaves; // the number of the cut Vec_Ptr_t * vRoots; // the roots of the cut Vec_Ptr_t * vBranches; // additional inputs // internal AIG package // objects int nPis; // number of PIs (nVarsMax + 32) int nObjs; // number of objects (Const1, PIs, ANDs) int nObjsAlloc; // number of objects allocated Odc_Obj_t * pObjs; // objects Odc_Lit_t iRoot; // the root object unsigned short nTravIds; // the number of travIDs // structural hashing Odc_Lit_t * pTable; // hash table int nTableSize; // hash table size Vec_Int_t * vUsedSpots; // the used spots // truth tables int nBits; // the number of bits int nWords; // the number of words Vec_Ptr_t * vTruths; // truth tables for each node Vec_Ptr_t * vTruthsElem; // elementary truth tables for the PIs unsigned * puTruth; // the place where the resulting truth table does // statistics int nWins; // the number of windows processed int nWinsEmpty; // the number of empty windows int nSimsEmpty; // the number of empty simulation infos int nQuantsOver; // the number of quantification overflows int nWinsFinish; // the number of windows that finished int nTotalDcs; // total percentage of DCs // runtime abctime timeClean; // windowing abctime timeWin; // windowing abctime timeMiter; // computing the miter abctime timeSim; // simulation abctime timeQuant; // quantification abctime timeTruth; // truth table abctime timeTotal; // useful runtime abctime timeAbort; // aborted runtime }; // quantity of different objects static inline int Odc_PiNum( Odc_Man_t * p ) { return p->nPis; } static inline int Odc_NodeNum( Odc_Man_t * p ) { return p->nObjs - p->nPis - 1; } static inline int Odc_ObjNum( Odc_Man_t * p ) { return p->nObjs; } // complemented attributes of objects static inline int Odc_IsComplement( Odc_Lit_t Lit ) { return Lit & (Odc_Lit_t)1; } static inline Odc_Lit_t Odc_Regular( Odc_Lit_t Lit ) { return Lit & ~(Odc_Lit_t)1; } static inline Odc_Lit_t Odc_Not( Odc_Lit_t Lit ) { return Lit ^ (Odc_Lit_t)1; } static inline Odc_Lit_t Odc_NotCond( Odc_Lit_t Lit, int c ) { return Lit ^ (Odc_Lit_t)(c!=0); } // specialized Literals static inline Odc_Lit_t Odc_Const0() { return 1; } static inline Odc_Lit_t Odc_Const1() { return 0; } static inline Odc_Lit_t Odc_Var( Odc_Man_t * p, int i ) { assert( i >= 0 && i < p->nPis ); return (i+1) << 1; } static inline int Odc_IsConst( Odc_Lit_t Lit ) { return Lit < (Odc_Lit_t)2; } static inline int Odc_IsTerm( Odc_Man_t * p, Odc_Lit_t Lit ) { return (int)(Lit>>1) <= p->nPis; } // accessing internal storage static inline Odc_Obj_t * Odc_ObjNew( Odc_Man_t * p ) { assert( p->nObjs < p->nObjsAlloc ); return p->pObjs + p->nObjs++; } static inline Odc_Lit_t Odc_Obj2Lit( Odc_Man_t * p, Odc_Obj_t * pObj ) { assert( pObj ); return (pObj - p->pObjs) << 1; } static inline Odc_Obj_t * Odc_Lit2Obj( Odc_Man_t * p, Odc_Lit_t Lit ) { assert( !(Lit & 1) && (int)(Lit>>1) < p->nObjs ); return p->pObjs + (Lit>>1); } // fanins and their complements static inline Odc_Lit_t Odc_ObjChild0( Odc_Obj_t * pObj ) { return pObj->iFan0; } static inline Odc_Lit_t Odc_ObjChild1( Odc_Obj_t * pObj ) { return pObj->iFan1; } static inline Odc_Lit_t Odc_ObjFanin0( Odc_Obj_t * pObj ) { return Odc_Regular(pObj->iFan0); } static inline Odc_Lit_t Odc_ObjFanin1( Odc_Obj_t * pObj ) { return Odc_Regular(pObj->iFan1); } static inline int Odc_ObjFaninC0( Odc_Obj_t * pObj ) { return Odc_IsComplement(pObj->iFan0); } static inline int Odc_ObjFaninC1( Odc_Obj_t * pObj ) { return Odc_IsComplement(pObj->iFan1); } // traversal IDs static inline void Odc_ManIncrementTravId( Odc_Man_t * p ) { p->nTravIds++; } static inline void Odc_ObjSetTravIdCurrent( Odc_Man_t * p, Odc_Obj_t * pObj ) { pObj->TravId = p->nTravIds; } static inline int Odc_ObjIsTravIdCurrent( Odc_Man_t * p, Odc_Obj_t * pObj ) { return (int )((int)pObj->TravId == p->nTravIds); } // truth tables static inline unsigned * Odc_ObjTruth( Odc_Man_t * p, Odc_Lit_t Lit ) { assert( !(Lit & 1) ); return (unsigned *) Vec_PtrEntry(p->vTruths, Lit >> 1); } // iterators #define Odc_ForEachPi( p, Lit, i ) \ for ( i = 0; (i < Odc_PiNum(p)) && (((Lit) = Odc_Var(p, i)), 1); i++ ) #define Odc_ForEachAnd( p, pObj, i ) \ for ( i = 1 + Odc_CiNum(p); (i < Odc_ObjNum(p)) && ((pObj) = (p)->pObjs + i); i++ ) //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Allocates the don't-care manager.] Description [The parameters are the max number of cut variables, the number of fanout levels used for the ODC computation, and verbosiness.] SideEffects [] SeeAlso [] ***********************************************************************/ Odc_Man_t * Abc_NtkDontCareAlloc( int nVarsMax, int nLevels, int fVerbose, int fVeryVerbose ) { Odc_Man_t * p; unsigned * pData; int i, k; p = ABC_ALLOC( Odc_Man_t, 1 ); memset( p, 0, sizeof(Odc_Man_t) ); assert( nVarsMax > 4 && nVarsMax < 16 ); assert( nLevels > 0 && nLevels < 10 ); srand( 0xABC ); // dont'-care parameters p->nVarsMax = nVarsMax; p->nLevels = nLevels; p->fVerbose = fVerbose; p->fVeryVerbose = fVeryVerbose; p->nPercCutoff = 10; // windowing p->vRoots = Vec_PtrAlloc( 128 ); p->vBranches = Vec_PtrAlloc( 128 ); // internal AIG package // allocate room for objects p->nObjsAlloc = ABC_DC_MAX_NODES; p->pObjs = ABC_ALLOC( Odc_Obj_t, p->nObjsAlloc * sizeof(Odc_Obj_t) ); p->nPis = nVarsMax + 32; p->nObjs = 1 + p->nPis; memset( p->pObjs, 0, p->nObjs * sizeof(Odc_Obj_t) ); // set the PI masks for ( i = 0; i < 32; i++ ) p->pObjs[1 + p->nVarsMax + i].uMask = (1 << i); // allocate hash table p->nTableSize = p->nObjsAlloc/3 + 1; p->pTable = ABC_ALLOC( Odc_Lit_t, p->nTableSize * sizeof(Odc_Lit_t) ); memset( p->pTable, 0, p->nTableSize * sizeof(Odc_Lit_t) ); p->vUsedSpots = Vec_IntAlloc( 1000 ); // truth tables p->nWords = Abc_TruthWordNum( p->nVarsMax ); p->nBits = p->nWords * 8 * sizeof(unsigned); p->vTruths = Vec_PtrAllocSimInfo( p->nObjsAlloc, p->nWords ); p->vTruthsElem = Vec_PtrAllocSimInfo( p->nVarsMax, p->nWords ); // set elementary truth tables Abc_InfoFill( (unsigned *)Vec_PtrEntry(p->vTruths, 0), p->nWords ); for ( k = 0; k < p->nVarsMax; k++ ) { // pData = Odc_ObjTruth( p, Odc_Var(p, k) ); pData = (unsigned *)Vec_PtrEntry( p->vTruthsElem, k ); Abc_InfoClear( pData, p->nWords ); for ( i = 0; i < p->nBits; i++ ) if ( i & (1 << k) ) pData[i>>5] |= (1 << (i&31)); } // set random truth table for the additional inputs for ( k = p->nVarsMax; k < p->nPis; k++ ) { pData = Odc_ObjTruth( p, Odc_Var(p, k) ); Abc_InfoRandom( pData, p->nWords ); } // set the miter to the unused value p->iRoot = 0xffff; return p; } /**Function************************************************************* Synopsis [Clears the manager.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareClear( Odc_Man_t * p ) { abctime clk = Abc_Clock(); // clean the structural hashing table if ( Vec_IntSize(p->vUsedSpots) > p->nTableSize/3 ) // more than one third memset( p->pTable, 0, sizeof(Odc_Lit_t) * p->nTableSize ); else { int iSpot, i; Vec_IntForEachEntry( p->vUsedSpots, iSpot, i ) p->pTable[iSpot] = 0; } Vec_IntClear( p->vUsedSpots ); // reset the number of nodes p->nObjs = 1 + p->nPis; // reset the root node p->iRoot = 0xffff; p->timeClean += Abc_Clock() - clk; } /**Function************************************************************* Synopsis [Frees the don't-care manager.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareFree( Odc_Man_t * p ) { if ( p->fVerbose ) { printf( "Wins = %5d. Empty = %5d. SimsEmpty = %5d. QuantOver = %5d. WinsFinish = %5d.\n", p->nWins, p->nWinsEmpty, p->nSimsEmpty, p->nQuantsOver, p->nWinsFinish ); printf( "Ave DCs per window = %6.2f %%. Ave DCs per finished window = %6.2f %%.\n", 1.0*p->nTotalDcs/p->nWins, 1.0*p->nTotalDcs/p->nWinsFinish ); printf( "Runtime stats of the ODC manager:\n" ); ABC_PRT( "Cleaning ", p->timeClean ); ABC_PRT( "Windowing ", p->timeWin ); ABC_PRT( "Miter ", p->timeMiter ); ABC_PRT( "Simulation ", p->timeSim ); ABC_PRT( "Quantifying ", p->timeQuant ); ABC_PRT( "Truth table ", p->timeTruth ); ABC_PRT( "TOTAL ", p->timeTotal ); ABC_PRT( "Aborted ", p->timeAbort ); } Vec_PtrFree( p->vRoots ); Vec_PtrFree( p->vBranches ); Vec_PtrFree( p->vTruths ); Vec_PtrFree( p->vTruthsElem ); Vec_IntFree( p->vUsedSpots ); ABC_FREE( p->pObjs ); ABC_FREE( p->pTable ); ABC_FREE( p ); } /**Function************************************************************* Synopsis [Marks the TFO of the collected nodes up to the given level.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareWinSweepLeafTfo_rec( Abc_Obj_t * pObj, int nLevelLimit, Abc_Obj_t * pNode ) { Abc_Obj_t * pFanout; int i; if ( Abc_ObjIsCo(pObj) || (int)pObj->Level > nLevelLimit || pObj == pNode ) return; if ( Abc_NodeIsTravIdCurrent(pObj) ) return; Abc_NodeSetTravIdCurrent( pObj ); //////////////////////////////////////// // try to reduce the runtime if ( Abc_ObjFanoutNum(pObj) > 100 ) return; //////////////////////////////////////// Abc_ObjForEachFanout( pObj, pFanout, i ) Abc_NtkDontCareWinSweepLeafTfo_rec( pFanout, nLevelLimit, pNode ); } /**Function************************************************************* Synopsis [Marks the TFO of the collected nodes up to the given level.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareWinSweepLeafTfo( Odc_Man_t * p ) { Abc_Obj_t * pObj; int i; Abc_NtkIncrementTravId( p->pNode->pNtk ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pObj, i ) Abc_NtkDontCareWinSweepLeafTfo_rec( pObj, p->pNode->Level + p->nLevels, p->pNode ); } /**Function************************************************************* Synopsis [Recursively collects the roots.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareWinCollectRoots_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vRoots ) { Abc_Obj_t * pFanout; int i; assert( Abc_ObjIsNode(pObj) ); assert( Abc_NodeIsTravIdCurrent(pObj) ); // check if the node has all fanouts marked Abc_ObjForEachFanout( pObj, pFanout, i ) if ( !Abc_NodeIsTravIdCurrent(pFanout) ) break; // if some of the fanouts are unmarked, add the node to the root if ( i < Abc_ObjFanoutNum(pObj) ) { Vec_PtrPushUnique( vRoots, pObj ); return; } // otherwise, call recursively Abc_ObjForEachFanout( pObj, pFanout, i ) Abc_NtkDontCareWinCollectRoots_rec( pFanout, vRoots ); } /**Function************************************************************* Synopsis [Collects the roots of the window.] Description [Roots of the window are the nodes that have at least one fanout that it not in the TFO of the leaves.] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareWinCollectRoots( Odc_Man_t * p ) { assert( !Abc_NodeIsTravIdCurrent(p->pNode) ); // mark the node with the old traversal ID Abc_NodeSetTravIdCurrent( p->pNode ); // collect the roots Vec_PtrClear( p->vRoots ); Abc_NtkDontCareWinCollectRoots_rec( p->pNode, p->vRoots ); } /**Function************************************************************* Synopsis [Recursively adds missing nodes and leaves.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkDontCareWinAddMissing_rec( Odc_Man_t * p, Abc_Obj_t * pObj ) { Abc_Obj_t * pFanin; int i; // skip the already collected leaves and branches if ( Abc_NodeIsTravIdCurrent(pObj) ) return 1; // if this is not an internal node - make it a new branch if ( !Abc_NodeIsTravIdPrevious(pObj) || Abc_ObjIsCi(pObj) ) //|| (int)pObj->Level <= p->nLevLeaves ) { Abc_NodeSetTravIdCurrent( pObj ); Vec_PtrPush( p->vBranches, pObj ); return Vec_PtrSize(p->vBranches) <= 32; } // visit the fanins of the node Abc_ObjForEachFanin( pObj, pFanin, i ) if ( !Abc_NtkDontCareWinAddMissing_rec( p, pFanin ) ) return 0; return 1; } /**Function************************************************************* Synopsis [Adds to the window nodes and leaves in the TFI of the roots.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkDontCareWinAddMissing( Odc_Man_t * p ) { Abc_Obj_t * pObj; int i; // set the leaves Abc_NtkIncrementTravId( p->pNode->pNtk ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pObj, i ) Abc_NodeSetTravIdCurrent( pObj ); // explore from the roots Vec_PtrClear( p->vBranches ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vRoots, pObj, i ) if ( !Abc_NtkDontCareWinAddMissing_rec( p, pObj ) ) return 0; return 1; } /**Function************************************************************* Synopsis [Computes window for the node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkDontCareWindow( Odc_Man_t * p ) { // mark the TFO of the collected nodes up to the given level (p->pNode->Level + p->nWinTfoMax) Abc_NtkDontCareWinSweepLeafTfo( p ); // find the roots of the window Abc_NtkDontCareWinCollectRoots( p ); if ( Vec_PtrSize(p->vRoots) == 1 && Vec_PtrEntry(p->vRoots, 0) == p->pNode ) { // printf( "Empty window\n" ); return 0; } // add the nodes in the TFI of the roots that are not yet in the window if ( !Abc_NtkDontCareWinAddMissing( p ) ) { // printf( "Too many branches (%d)\n", Vec_PtrSize(p->vBranches) ); return 0; } return 1; } /**Function************************************************************* Synopsis [Performing hashing of two AIG Literals.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline unsigned Odc_HashKey( Odc_Lit_t iFan0, Odc_Lit_t iFan1, int TableSize ) { unsigned Key = 0; Key ^= Odc_Regular(iFan0) * 7937; Key ^= Odc_Regular(iFan1) * 2971; Key ^= Odc_IsComplement(iFan0) * 911; Key ^= Odc_IsComplement(iFan1) * 353; return Key % TableSize; } /**Function************************************************************* Synopsis [Checks if the given name node already exists in the table.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline Odc_Lit_t * Odc_HashLookup( Odc_Man_t * p, Odc_Lit_t iFan0, Odc_Lit_t iFan1 ) { Odc_Obj_t * pObj; Odc_Lit_t * pEntry; unsigned uHashKey; assert( iFan0 < iFan1 ); // get the hash key for this node uHashKey = Odc_HashKey( iFan0, iFan1, p->nTableSize ); // remember the spot in the hash table that will be used if ( p->pTable[uHashKey] == 0 ) Vec_IntPush( p->vUsedSpots, uHashKey ); // find the entry for ( pEntry = p->pTable + uHashKey; *pEntry; pEntry = &pObj->iNext ) { pObj = Odc_Lit2Obj( p, *pEntry ); if ( pObj->iFan0 == iFan0 && pObj->iFan1 == iFan1 ) return pEntry; } return pEntry; } /**Function************************************************************* Synopsis [Finds node by structural hashing or creates a new node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline Odc_Lit_t Odc_And( Odc_Man_t * p, Odc_Lit_t iFan0, Odc_Lit_t iFan1 ) { Odc_Obj_t * pObj; Odc_Lit_t * pEntry; unsigned uMask0, uMask1; int Temp; // consider trivial cases if ( iFan0 == iFan1 ) return iFan0; if ( iFan0 == Odc_Not(iFan1) ) return Odc_Const0(); if ( Odc_Regular(iFan0) == Odc_Const1() ) return iFan0 == Odc_Const1() ? iFan1 : Odc_Const0(); if ( Odc_Regular(iFan1) == Odc_Const1() ) return iFan1 == Odc_Const1() ? iFan0 : Odc_Const0(); // canonicize the fanin order if ( iFan0 > iFan1 ) Temp = iFan0, iFan0 = iFan1, iFan1 = Temp; // check if a node with these fanins exists pEntry = Odc_HashLookup( p, iFan0, iFan1 ); if ( *pEntry ) return *pEntry; // create a new node pObj = Odc_ObjNew( p ); pObj->iFan0 = iFan0; pObj->iFan1 = iFan1; pObj->iNext = 0; pObj->TravId = 0; // set the mask uMask0 = Odc_Lit2Obj(p, Odc_Regular(iFan0))->uMask; uMask1 = Odc_Lit2Obj(p, Odc_Regular(iFan1))->uMask; pObj->uMask = uMask0 | uMask1; // add to the table *pEntry = Odc_Obj2Lit( p, pObj ); return *pEntry; } /**Function************************************************************* Synopsis [Boolean OR.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline Odc_Lit_t Odc_Or( Odc_Man_t * p, Odc_Lit_t iFan0, Odc_Lit_t iFan1 ) { return Odc_Not( Odc_And(p, Odc_Not(iFan0), Odc_Not(iFan1)) ); } /**Function************************************************************* Synopsis [Boolean XOR.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline Odc_Lit_t Odc_Xor( Odc_Man_t * p, Odc_Lit_t iFan0, Odc_Lit_t iFan1 ) { return Odc_Or( p, Odc_And(p, iFan0, Odc_Not(iFan1)), Odc_And(p, Odc_Not(iFan0), iFan1) ); } /**Function************************************************************* Synopsis [Transfers the window into the AIG package.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void * Abc_NtkDontCareTransfer_rec( Odc_Man_t * p, Abc_Obj_t * pNode, Abc_Obj_t * pPivot ) { unsigned uData0, uData1; Odc_Lit_t uLit0, uLit1, uRes0, uRes1; assert( !Abc_ObjIsComplement(pNode) ); // skip visited objects if ( Abc_NodeIsTravIdCurrent(pNode) ) return pNode->pCopy; Abc_NodeSetTravIdCurrent(pNode); assert( Abc_ObjIsNode(pNode) ); // consider the case when the node is the pivot if ( pNode == pPivot ) return pNode->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)((Odc_Const1() << 16) | Odc_Const0()); // compute the cofactors uData0 = (unsigned)(ABC_PTRUINT_T)Abc_NtkDontCareTransfer_rec( p, Abc_ObjFanin0(pNode), pPivot ); uData1 = (unsigned)(ABC_PTRUINT_T)Abc_NtkDontCareTransfer_rec( p, Abc_ObjFanin1(pNode), pPivot ); // find the 0-cofactor uLit0 = Odc_NotCond( (Odc_Lit_t)(uData0 & 0xffff), Abc_ObjFaninC0(pNode) ); uLit1 = Odc_NotCond( (Odc_Lit_t)(uData1 & 0xffff), Abc_ObjFaninC1(pNode) ); uRes0 = Odc_And( p, uLit0, uLit1 ); // find the 1-cofactor uLit0 = Odc_NotCond( (Odc_Lit_t)(uData0 >> 16), Abc_ObjFaninC0(pNode) ); uLit1 = Odc_NotCond( (Odc_Lit_t)(uData1 >> 16), Abc_ObjFaninC1(pNode) ); uRes1 = Odc_And( p, uLit0, uLit1 ); // find the result return pNode->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)((uRes1 << 16) | uRes0); } /**Function************************************************************* Synopsis [Transfers the window into the AIG package.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkDontCareTransfer( Odc_Man_t * p ) { Abc_Obj_t * pObj; Odc_Lit_t uRes0, uRes1; Odc_Lit_t uLit; unsigned uData; int i; Abc_NtkIncrementTravId( p->pNode->pNtk ); // set elementary variables at the leaves Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pObj, i ) { uLit = Odc_Var( p, i ); pObj->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)((uLit << 16) | uLit); Abc_NodeSetTravIdCurrent(pObj); } // set elementary variables at the branched Vec_PtrForEachEntry( Abc_Obj_t *, p->vBranches, pObj, i ) { uLit = Odc_Var( p, i+p->nVarsMax ); pObj->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)((uLit << 16) | uLit); Abc_NodeSetTravIdCurrent(pObj); } // compute the AIG for the window p->iRoot = Odc_Const0(); Vec_PtrForEachEntry( Abc_Obj_t *, p->vRoots, pObj, i ) { uData = (unsigned)(ABC_PTRUINT_T)Abc_NtkDontCareTransfer_rec( p, pObj, p->pNode ); // get the cofactors uRes0 = uData & 0xffff; uRes1 = uData >> 16; // compute the miter // assert( uRes0 != uRes1 ); // may be false if the node is redundant w.r.t. this root uLit = Odc_Xor( p, uRes0, uRes1 ); p->iRoot = Odc_Or( p, p->iRoot, uLit ); } return 1; } /**Function************************************************************* Synopsis [Recursively computes the pair of cofactors.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ unsigned Abc_NtkDontCareCofactors_rec( Odc_Man_t * p, Odc_Lit_t Lit, unsigned uMask ) { Odc_Obj_t * pObj; unsigned uData0, uData1; Odc_Lit_t uLit0, uLit1, uRes0, uRes1; assert( !Odc_IsComplement(Lit) ); // skip visited objects pObj = Odc_Lit2Obj( p, Lit ); if ( Odc_ObjIsTravIdCurrent(p, pObj) ) return pObj->uData; Odc_ObjSetTravIdCurrent(p, pObj); // skip objects out of the cone if ( (pObj->uMask & uMask) == 0 ) return pObj->uData = ((Lit << 16) | Lit); // consider the case when the node is the var if ( pObj->uMask == uMask && Odc_IsTerm(p, Lit) ) return pObj->uData = ((Odc_Const1() << 16) | Odc_Const0()); // compute the cofactors uData0 = Abc_NtkDontCareCofactors_rec( p, Odc_ObjFanin0(pObj), uMask ); uData1 = Abc_NtkDontCareCofactors_rec( p, Odc_ObjFanin1(pObj), uMask ); // find the 0-cofactor uLit0 = Odc_NotCond( (Odc_Lit_t)(uData0 & 0xffff), Odc_ObjFaninC0(pObj) ); uLit1 = Odc_NotCond( (Odc_Lit_t)(uData1 & 0xffff), Odc_ObjFaninC1(pObj) ); uRes0 = Odc_And( p, uLit0, uLit1 ); // find the 1-cofactor uLit0 = Odc_NotCond( (Odc_Lit_t)(uData0 >> 16), Odc_ObjFaninC0(pObj) ); uLit1 = Odc_NotCond( (Odc_Lit_t)(uData1 >> 16), Odc_ObjFaninC1(pObj) ); uRes1 = Odc_And( p, uLit0, uLit1 ); // find the result return pObj->uData = ((uRes1 << 16) | uRes0); } /**Function************************************************************* Synopsis [Quantifies the branch variables.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkDontCareQuantify( Odc_Man_t * p ) { Odc_Lit_t uRes0, uRes1; unsigned uData; int i; assert( p->iRoot < 0xffff ); assert( Vec_PtrSize(p->vBranches) <= 32 ); // the mask size for ( i = 0; i < Vec_PtrSize(p->vBranches); i++ ) { // compute the cofactors w.r.t. this variable Odc_ManIncrementTravId( p ); uData = Abc_NtkDontCareCofactors_rec( p, Odc_Regular(p->iRoot), (1 << i) ); uRes0 = Odc_NotCond( (Odc_Lit_t)(uData & 0xffff), Odc_IsComplement(p->iRoot) ); uRes1 = Odc_NotCond( (Odc_Lit_t)(uData >> 16), Odc_IsComplement(p->iRoot) ); // quantify this variable existentially p->iRoot = Odc_Or( p, uRes0, uRes1 ); // check the limit if ( Odc_ObjNum(p) > ABC_DC_MAX_NODES/2 ) return 0; } assert( p->nObjs <= p->nObjsAlloc ); return 1; } /**Function************************************************************* Synopsis [Set elementary truth tables for PIs.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareSimulateSetElem2( Odc_Man_t * p ) { unsigned * pData; int i, k; for ( k = 0; k < p->nVarsMax; k++ ) { pData = Odc_ObjTruth( p, Odc_Var(p, k) ); Abc_InfoClear( pData, p->nWords ); for ( i = 0; i < p->nBits; i++ ) if ( i & (1 << k) ) pData[i>>5] |= (1 << (i&31)); } } /**Function************************************************************* Synopsis [Set elementary truth tables for PIs.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareSimulateSetElem( Odc_Man_t * p ) { unsigned * pData, * pData2; int k; for ( k = 0; k < p->nVarsMax; k++ ) { pData = Odc_ObjTruth( p, Odc_Var(p, k) ); pData2 = (unsigned *)Vec_PtrEntry( p->vTruthsElem, k ); Abc_InfoCopy( pData, pData2, p->nWords ); } } /**Function************************************************************* Synopsis [Set random simulation words for PIs.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareSimulateSetRand( Odc_Man_t * p ) { unsigned * pData; int w, k, Number; for ( w = 0; w < p->nWords; w++ ) { Number = rand(); for ( k = 0; k < p->nVarsMax; k++ ) { pData = Odc_ObjTruth( p, Odc_Var(p, k) ); pData[w] = (Number & (1<nWords; w++ ) if ( puTruth[w] ) Counter++; return Counter; } /**Function************************************************************* Synopsis [Simulates one node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareTruthOne( Odc_Man_t * p, Odc_Lit_t Lit ) { Odc_Obj_t * pObj; unsigned * pInfo, * pInfo1, * pInfo2; int k, fComp1, fComp2; assert( !Odc_IsComplement( Lit ) ); assert( !Odc_IsTerm( p, Lit ) ); // get the truth tables pObj = Odc_Lit2Obj( p, Lit ); pInfo = Odc_ObjTruth( p, Lit ); pInfo1 = Odc_ObjTruth( p, Odc_ObjFanin0(pObj) ); pInfo2 = Odc_ObjTruth( p, Odc_ObjFanin1(pObj) ); fComp1 = Odc_ObjFaninC0( pObj ); fComp2 = Odc_ObjFaninC1( pObj ); // simulate if ( fComp1 && fComp2 ) for ( k = 0; k < p->nWords; k++ ) pInfo[k] = ~pInfo1[k] & ~pInfo2[k]; else if ( fComp1 && !fComp2 ) for ( k = 0; k < p->nWords; k++ ) pInfo[k] = ~pInfo1[k] & pInfo2[k]; else if ( !fComp1 && fComp2 ) for ( k = 0; k < p->nWords; k++ ) pInfo[k] = pInfo1[k] & ~pInfo2[k]; else // if ( fComp1 && fComp2 ) for ( k = 0; k < p->nWords; k++ ) pInfo[k] = pInfo1[k] & pInfo2[k]; } /**Function************************************************************* Synopsis [Computes the truth table.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDontCareSimulate_rec( Odc_Man_t * p, Odc_Lit_t Lit ) { Odc_Obj_t * pObj; assert( !Odc_IsComplement(Lit) ); // skip terminals if ( Odc_IsTerm(p, Lit) ) return; // skip visited objects pObj = Odc_Lit2Obj( p, Lit ); if ( Odc_ObjIsTravIdCurrent(p, pObj) ) return; Odc_ObjSetTravIdCurrent(p, pObj); // call recursively Abc_NtkDontCareSimulate_rec( p, Odc_ObjFanin0(pObj) ); Abc_NtkDontCareSimulate_rec( p, Odc_ObjFanin1(pObj) ); // construct the truth table Abc_NtkDontCareTruthOne( p, Lit ); } /**Function************************************************************* Synopsis [Computes the truth table of the care set.] Description [Returns the number of ones in the simulation info.] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkDontCareSimulate( Odc_Man_t * p, unsigned * puTruth ) { Odc_ManIncrementTravId( p ); Abc_NtkDontCareSimulate_rec( p, Odc_Regular(p->iRoot) ); Abc_InfoCopy( puTruth, Odc_ObjTruth(p, Odc_Regular(p->iRoot)), p->nWords ); if ( Odc_IsComplement(p->iRoot) ) Abc_InfoNot( puTruth, p->nWords ); return Extra_TruthCountOnes( puTruth, p->nVarsMax ); } /**Function************************************************************* Synopsis [Computes the truth table of the care set.] Description [Returns the number of ones in the simulation info.] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkDontCareSimulateBefore( Odc_Man_t * p, unsigned * puTruth ) { int nIters = 2; int nRounds, Counter, r; // decide how many rounds to simulate nRounds = p->nBits / p->nWords; Counter = 0; for ( r = 0; r < nIters; r++ ) { Abc_NtkDontCareSimulateSetRand( p ); Abc_NtkDontCareSimulate( p, puTruth ); Counter += Abc_NtkDontCareCountMintsWord( p, puTruth ); } // normalize Counter = Counter * nRounds / nIters; return Counter; } /**Function************************************************************* Synopsis [Computes ODCs for the node in terms of the cut variables.] Description [Returns the number of don't care minterms in the truth table. In particular, this procedure returns 0 if there is no don't-cares.] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkDontCareCompute( Odc_Man_t * p, Abc_Obj_t * pNode, Vec_Ptr_t * vLeaves, unsigned * puTruth ) { int nMints, RetValue; abctime clk, clkTotal = Abc_Clock(); p->nWins++; // set the parameters assert( !Abc_ObjIsComplement(pNode) ); assert( Abc_ObjIsNode(pNode) ); assert( Vec_PtrSize(vLeaves) <= p->nVarsMax ); p->vLeaves = vLeaves; p->pNode = pNode; // compute the window clk = Abc_Clock(); RetValue = Abc_NtkDontCareWindow( p ); p->timeWin += Abc_Clock() - clk; if ( !RetValue ) { p->timeAbort += Abc_Clock() - clkTotal; Abc_InfoFill( puTruth, p->nWords ); p->nWinsEmpty++; return 0; } if ( p->fVeryVerbose ) { printf( " %5d : ", pNode->Id ); printf( "Leaf = %2d ", Vec_PtrSize(p->vLeaves) ); printf( "Root = %2d ", Vec_PtrSize(p->vRoots) ); printf( "Bran = %2d ", Vec_PtrSize(p->vBranches) ); printf( " | " ); } // transfer the window into the AIG package clk = Abc_Clock(); Abc_NtkDontCareTransfer( p ); p->timeMiter += Abc_Clock() - clk; // simulate to estimate the amount of don't-cares clk = Abc_Clock(); nMints = Abc_NtkDontCareSimulateBefore( p, puTruth ); p->timeSim += Abc_Clock() - clk; if ( p->fVeryVerbose ) { printf( "AIG = %5d ", Odc_NodeNum(p) ); printf( "%6.2f %% ", 100.0 * (p->nBits - nMints) / p->nBits ); } // if there is less then the given percentage of don't-cares, skip if ( 100.0 * (p->nBits - nMints) / p->nBits < 1.0 * p->nPercCutoff ) { p->timeAbort += Abc_Clock() - clkTotal; if ( p->fVeryVerbose ) printf( "Simulation cutoff.\n" ); Abc_InfoFill( puTruth, p->nWords ); p->nSimsEmpty++; return 0; } // quantify external variables clk = Abc_Clock(); RetValue = Abc_NtkDontCareQuantify( p ); p->timeQuant += Abc_Clock() - clk; if ( !RetValue ) { p->timeAbort += Abc_Clock() - clkTotal; if ( p->fVeryVerbose ) printf( "=== Overflow! ===\n" ); Abc_InfoFill( puTruth, p->nWords ); p->nQuantsOver++; return 0; } // get the truth table clk = Abc_Clock(); Abc_NtkDontCareSimulateSetElem( p ); nMints = Abc_NtkDontCareSimulate( p, puTruth ); p->timeTruth += Abc_Clock() - clk; if ( p->fVeryVerbose ) { printf( "AIG = %5d ", Odc_NodeNum(p) ); printf( "%6.2f %% ", 100.0 * (p->nBits - nMints) / p->nBits ); printf( "\n" ); } p->timeTotal += Abc_Clock() - clkTotal; p->nWinsFinish++; p->nTotalDcs += (int)(100.0 * (p->nBits - nMints) / p->nBits); return nMints; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END