| /**CFile**************************************************************** |
| |
| FileName [abcDsd.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Network and node package.] |
| |
| Synopsis [Decomposes the network using disjoint-support decomposition.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: abcDsd.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" |
| #include "bdd/dsd/dsd.h" |
| #endif |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| #ifdef ABC_USE_CUDD |
| |
| static Abc_Ntk_t * Abc_NtkDsdInternal( Abc_Ntk_t * pNtk, int fVerbose, int fPrint, int fShort ); |
| static void Abc_NtkDsdConstruct( Dsd_Manager_t * pManDsd, Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew ); |
| static Abc_Obj_t * Abc_NtkDsdConstructNode( Dsd_Manager_t * pManDsd, Dsd_Node_t * pNodeDsd, Abc_Ntk_t * pNtkNew, int * pCounters ); |
| |
| static Vec_Ptr_t * Abc_NtkCollectNodesForDsd( Abc_Ntk_t * pNtk ); |
| static void Abc_NodeDecompDsdAndMux( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes, Dsd_Manager_t * pManDsd, int fRecursive, int * pCounters ); |
| static int Abc_NodeIsForDsd( Abc_Obj_t * pNode ); |
| static int Abc_NodeFindMuxVar( DdManager * dd, DdNode * bFunc, int nVars ); |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Derives the DSD network.] |
| |
| Description [Takes the strashed network (pNtk), derives global BDDs for |
| the combinational outputs of this network, and decomposes these BDDs using |
| disjoint support decomposition. Finally, constructs and return a new |
| network, which is topologically equivalent to the decomposition tree. |
| Allocates and frees a new BDD manager and a new DSD manager.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkDsdGlobal( Abc_Ntk_t * pNtk, int fVerbose, int fPrint, int fShort ) |
| { |
| DdManager * dd; |
| Abc_Ntk_t * pNtkNew; |
| assert( Abc_NtkIsStrash(pNtk) ); |
| dd = (DdManager *)Abc_NtkBuildGlobalBdds( pNtk, 10000000, 1, 1, fVerbose ); |
| if ( dd == NULL ) |
| return NULL; |
| if ( fVerbose ) |
| printf( "Shared BDD size = %6d nodes.\n", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); |
| // transform the result of mapping into a BDD network |
| pNtkNew = Abc_NtkDsdInternal( pNtk, fVerbose, fPrint, fShort ); |
| Extra_StopManager( dd ); |
| if ( pNtkNew == NULL ) |
| return NULL; |
| // copy EXDC network |
| if ( pNtk->pExdc ) |
| pNtkNew->pExdc = Abc_NtkDup( pNtk->pExdc ); |
| if ( !Abc_NtkCheck( pNtkNew ) ) |
| { |
| printf( "Abc_NtkDsdGlobal: The network check has failed.\n" ); |
| Abc_NtkDelete( pNtkNew ); |
| return NULL; |
| } |
| return pNtkNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Constructs the decomposed network.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkDsdInternal( Abc_Ntk_t * pNtk, int fVerbose, int fPrint, int fShort ) |
| { |
| char ** ppNamesCi, ** ppNamesCo; |
| Vec_Ptr_t * vFuncsGlob; |
| Dsd_Manager_t * pManDsd; |
| Abc_Ntk_t * pNtkNew; |
| DdManager * dd; |
| Abc_Obj_t * pObj; |
| int i; |
| |
| // complement the global functions |
| vFuncsGlob = Vec_PtrAlloc( Abc_NtkCoNum(pNtk) ); |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| Vec_PtrPush( vFuncsGlob, Cudd_NotCond(Abc_ObjGlobalBdd(pObj), Abc_ObjFaninC0(pObj)) ); |
| |
| // perform the decomposition |
| dd = (DdManager *)Abc_NtkGlobalBddMan(pNtk); |
| pManDsd = Dsd_ManagerStart( dd, Abc_NtkCiNum(pNtk), fVerbose ); |
| if ( pManDsd == NULL ) |
| { |
| Vec_PtrFree( vFuncsGlob ); |
| Cudd_Quit( dd ); |
| return NULL; |
| } |
| Dsd_Decompose( pManDsd, (DdNode **)vFuncsGlob->pArray, Abc_NtkCoNum(pNtk) ); |
| Vec_PtrFree( vFuncsGlob ); |
| Abc_NtkFreeGlobalBdds( pNtk, 0 ); |
| |
| // start the new network |
| pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC, ABC_FUNC_BDD ); |
| // make sure the new manager has enough inputs |
| Cudd_bddIthVar( (DdManager *)pNtkNew->pManFunc, dd->size-1 ); |
| // put the results into the new network (save new CO drivers in old CO drivers) |
| Abc_NtkDsdConstruct( pManDsd, pNtk, pNtkNew ); |
| // finalize the new network |
| Abc_NtkFinalize( pNtk, pNtkNew ); |
| // fix the problem with complemented and duplicated CO edges |
| Abc_NtkLogicMakeSimpleCos( pNtkNew, 0 ); |
| if ( fPrint ) |
| { |
| ppNamesCi = Abc_NtkCollectCioNames( pNtk, 0 ); |
| ppNamesCo = Abc_NtkCollectCioNames( pNtk, 1 ); |
| if ( fVerbose ) |
| Dsd_TreePrint( stdout, pManDsd, ppNamesCi, ppNamesCo, fShort, -1 ); |
| else |
| Dsd_TreePrint2( stdout, pManDsd, ppNamesCi, ppNamesCo, -1 ); |
| ABC_FREE( ppNamesCi ); |
| ABC_FREE( ppNamesCo ); |
| } |
| |
| // stop the DSD manager |
| Dsd_ManagerStop( pManDsd ); |
| return pNtkNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Constructs the decomposed network.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkDsdConstruct( Dsd_Manager_t * pManDsd, Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew ) |
| { |
| Dsd_Node_t ** ppNodesDsd; |
| Dsd_Node_t * pNodeDsd; |
| Abc_Obj_t * pNode, * pNodeNew, * pDriver; |
| int i, nNodesDsd; |
| |
| // save the CI nodes in the DSD nodes |
| Abc_AigConst1(pNtk)->pCopy = pNodeNew = Abc_NtkCreateNodeConst1(pNtkNew); |
| Dsd_NodeSetMark( Dsd_ManagerReadConst1(pManDsd), (int)(ABC_PTRINT_T)pNodeNew ); |
| Abc_NtkForEachCi( pNtk, pNode, i ) |
| { |
| pNodeDsd = Dsd_ManagerReadInput( pManDsd, i ); |
| Dsd_NodeSetMark( pNodeDsd, (int)(ABC_PTRINT_T)pNode->pCopy ); |
| } |
| |
| // collect DSD nodes in DFS order (leaves and const1 are not collected) |
| ppNodesDsd = Dsd_TreeCollectNodesDfs( pManDsd, &nNodesDsd ); |
| for ( i = 0; i < nNodesDsd; i++ ) |
| Abc_NtkDsdConstructNode( pManDsd, ppNodesDsd[i], pNtkNew, NULL ); |
| ABC_FREE( ppNodesDsd ); |
| |
| // set the pointers to the CO drivers |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| { |
| pDriver = Abc_ObjFanin0( pNode ); |
| if ( !Abc_ObjIsNode(pDriver) ) |
| continue; |
| if ( !Abc_AigNodeIsAnd(pDriver) ) |
| continue; |
| pNodeDsd = Dsd_ManagerReadRoot( pManDsd, i ); |
| pNodeNew = (Abc_Obj_t *)(ABC_PTRINT_T)Dsd_NodeReadMark( Dsd_Regular(pNodeDsd) ); |
| assert( !Abc_ObjIsComplement(pNodeNew) ); |
| pDriver->pCopy = Abc_ObjNotCond( pNodeNew, Dsd_IsComplement(pNodeDsd) ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs DSD using the manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Obj_t * Abc_NtkDsdConstructNode( Dsd_Manager_t * pManDsd, Dsd_Node_t * pNodeDsd, Abc_Ntk_t * pNtkNew, int * pCounters ) |
| { |
| DdManager * ddDsd = Dsd_ManagerReadDd( pManDsd ); |
| DdManager * ddNew = (DdManager *)pNtkNew->pManFunc; |
| Dsd_Node_t * pFaninDsd; |
| Abc_Obj_t * pNodeNew, * pFanin; |
| DdNode * bLocal = NULL, * bTemp, * bVar; |
| Dsd_Type_t Type; |
| int i, nDecs; |
| |
| // create the new node |
| pNodeNew = Abc_NtkCreateNode( pNtkNew ); |
| // add the fanins |
| Type = Dsd_NodeReadType( pNodeDsd ); |
| nDecs = Dsd_NodeReadDecsNum( pNodeDsd ); |
| assert( nDecs > 1 ); |
| for ( i = 0; i < nDecs; i++ ) |
| { |
| pFaninDsd = Dsd_NodeReadDec( pNodeDsd, i ); |
| pFanin = (Abc_Obj_t *)(ABC_PTRINT_T)Dsd_NodeReadMark(Dsd_Regular(pFaninDsd)); |
| Abc_ObjAddFanin( pNodeNew, pFanin ); |
| assert( Type == DSD_NODE_OR || !Dsd_IsComplement(pFaninDsd) ); |
| } |
| |
| // create the local function depending on the type of the node |
| ddNew = (DdManager *)pNtkNew->pManFunc; |
| switch ( Type ) |
| { |
| case DSD_NODE_CONST1: |
| { |
| bLocal = ddNew->one; Cudd_Ref( bLocal ); |
| break; |
| } |
| case DSD_NODE_OR: |
| { |
| bLocal = Cudd_Not(ddNew->one); Cudd_Ref( bLocal ); |
| for ( i = 0; i < nDecs; i++ ) |
| { |
| pFaninDsd = Dsd_NodeReadDec( pNodeDsd, i ); |
| bVar = Cudd_NotCond( ddNew->vars[i], Dsd_IsComplement(pFaninDsd) ); |
| bLocal = Cudd_bddOr( ddNew, bTemp = bLocal, bVar ); Cudd_Ref( bLocal ); |
| Cudd_RecursiveDeref( ddNew, bTemp ); |
| } |
| break; |
| } |
| case DSD_NODE_EXOR: |
| { |
| bLocal = Cudd_Not(ddNew->one); Cudd_Ref( bLocal ); |
| for ( i = 0; i < nDecs; i++ ) |
| { |
| bLocal = Cudd_bddXor( ddNew, bTemp = bLocal, ddNew->vars[i] ); Cudd_Ref( bLocal ); |
| Cudd_RecursiveDeref( ddNew, bTemp ); |
| } |
| break; |
| } |
| case DSD_NODE_PRIME: |
| { |
| if ( pCounters ) |
| { |
| if ( nDecs < 10 ) |
| pCounters[nDecs]++; |
| else |
| pCounters[10]++; |
| } |
| bLocal = Dsd_TreeGetPrimeFunction( ddDsd, pNodeDsd ); Cudd_Ref( bLocal ); |
| bLocal = Extra_TransferLevelByLevel( ddDsd, ddNew, bTemp = bLocal ); Cudd_Ref( bLocal ); |
| /* |
| if ( nDecs == 3 ) |
| { |
| Extra_bddPrint( ddDsd, bTemp ); |
| printf( "\n" ); |
| } |
| */ |
| Cudd_RecursiveDeref( ddDsd, bTemp ); |
| // bLocal is now in the new BDD manager |
| break; |
| } |
| default: |
| { |
| assert( 0 ); |
| break; |
| } |
| } |
| pNodeNew->pData = bLocal; |
| Dsd_NodeSetMark( pNodeDsd, (int)(ABC_PTRINT_T)pNodeNew ); |
| return pNodeNew; |
| } |
| |
| |
| |
| |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Recursively decomposes internal nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkDsdLocal( Abc_Ntk_t * pNtk, int fVerbose, int fRecursive ) |
| { |
| Dsd_Manager_t * pManDsd; |
| DdManager * dd = (DdManager *)pNtk->pManFunc; |
| Vec_Ptr_t * vNodes; |
| int i; |
| int pCounters[11] = {0}; |
| |
| assert( Abc_NtkIsBddLogic(pNtk) ); |
| |
| // make the network minimum base |
| Abc_NtkMinimumBase( pNtk ); |
| |
| // start the DSD manager |
| pManDsd = Dsd_ManagerStart( dd, dd->size, 0 ); |
| |
| // collect nodes for decomposition |
| vNodes = Abc_NtkCollectNodesForDsd( pNtk ); |
| for ( i = 0; i < vNodes->nSize; i++ ) |
| Abc_NodeDecompDsdAndMux( (Abc_Obj_t *)vNodes->pArray[i], vNodes, pManDsd, fRecursive, pCounters ); |
| Vec_PtrFree( vNodes ); |
| |
| if ( fVerbose ) |
| { |
| printf( "Number of non-decomposable functions:\n" ); |
| for ( i = 3; i < 10; i++ ) |
| printf( "Inputs = %d. Functions = %6d.\n", i, pCounters[i] ); |
| printf( "Inputs > %d. Functions = %6d.\n", 9, pCounters[10] ); |
| } |
| |
| // stop the DSD manager |
| Dsd_ManagerStop( pManDsd ); |
| |
| // make sure everything is okay |
| if ( !Abc_NtkCheck( pNtk ) ) |
| { |
| printf( "Abc_NtkDsdRecursive: The network check has failed.\n" ); |
| return 0; |
| } |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Collects the nodes that may need decomposition.] |
| |
| Description [The nodes that do not need decomposition are those |
| whose BDD has more internal nodes than the support size.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Ptr_t * Abc_NtkCollectNodesForDsd( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t * vNodes; |
| Abc_Obj_t * pNode; |
| int i; |
| vNodes = Vec_PtrAlloc( 100 ); |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| if ( Abc_NodeIsForDsd(pNode) ) |
| Vec_PtrPush( vNodes, pNode ); |
| } |
| return vNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs decomposition of one node.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NodeDecompDsdAndMux( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes, Dsd_Manager_t * pManDsd, int fRecursive, int * pCounters ) |
| { |
| DdManager * dd = (DdManager *)pNode->pNtk->pManFunc; |
| Abc_Obj_t * pRoot = NULL, * pFanin, * pNode1, * pNode2, * pNodeC; |
| Dsd_Node_t ** ppNodesDsd, * pNodeDsd, * pFaninDsd; |
| int i, nNodesDsd, iVar, fCompl; |
| |
| // try disjoint support decomposition |
| pNodeDsd = Dsd_DecomposeOne( pManDsd, (DdNode *)pNode->pData ); |
| fCompl = Dsd_IsComplement( pNodeDsd ); |
| pNodeDsd = Dsd_Regular( pNodeDsd ); |
| |
| // determine what decomposition to use |
| if ( !fRecursive || Dsd_NodeReadDecsNum(pNodeDsd) != Abc_ObjFaninNum(pNode) ) |
| { // perform DSD |
| |
| // set the inputs |
| Abc_ObjForEachFanin( pNode, pFanin, i ) |
| { |
| pFaninDsd = Dsd_ManagerReadInput( pManDsd, i ); |
| Dsd_NodeSetMark( pFaninDsd, (int)(ABC_PTRINT_T)pFanin ); |
| } |
| |
| // construct the intermediate nodes |
| ppNodesDsd = Dsd_TreeCollectNodesDfsOne( pManDsd, pNodeDsd, &nNodesDsd ); |
| for ( i = 0; i < nNodesDsd; i++ ) |
| { |
| pRoot = Abc_NtkDsdConstructNode( pManDsd, ppNodesDsd[i], pNode->pNtk, pCounters ); |
| if ( Abc_NodeIsForDsd(pRoot) && fRecursive ) |
| Vec_PtrPush( vNodes, pRoot ); |
| } |
| ABC_FREE( ppNodesDsd ); |
| assert(pRoot); |
| |
| // remove the current fanins |
| Abc_ObjRemoveFanins( pNode ); |
| // add fanin to the root |
| Abc_ObjAddFanin( pNode, pRoot ); |
| // update the function to be that of buffer |
| Cudd_RecursiveDeref( dd, (DdNode *)pNode->pData ); |
| pNode->pData = Cudd_NotCond( (DdNode *)dd->vars[0], fCompl ); Cudd_Ref( (DdNode *)pNode->pData ); |
| } |
| else // perform MUX-decomposition |
| { |
| // get the cofactoring variable |
| iVar = Abc_NodeFindMuxVar( dd, (DdNode *)pNode->pData, Abc_ObjFaninNum(pNode) ); |
| pNodeC = Abc_ObjFanin( pNode, iVar ); |
| |
| // get the negative cofactor |
| pNode1 = Abc_NtkCloneObj( pNode ); |
| pNode1->pData = Cudd_Cofactor( dd, (DdNode *)pNode->pData, Cudd_Not(dd->vars[iVar]) ); Cudd_Ref( (DdNode *)pNode1->pData ); |
| Abc_NodeMinimumBase( pNode1 ); |
| if ( Abc_NodeIsForDsd(pNode1) ) |
| Vec_PtrPush( vNodes, pNode1 ); |
| |
| // get the positive cofactor |
| pNode2 = Abc_NtkCloneObj( pNode ); |
| pNode2->pData = Cudd_Cofactor( dd, (DdNode *)pNode->pData, dd->vars[iVar] ); Cudd_Ref( (DdNode *)pNode2->pData ); |
| Abc_NodeMinimumBase( pNode2 ); |
| if ( Abc_NodeIsForDsd(pNode2) ) |
| Vec_PtrPush( vNodes, pNode2 ); |
| |
| // remove the current fanins |
| Abc_ObjRemoveFanins( pNode ); |
| // add new fanins |
| Abc_ObjAddFanin( pNode, pNodeC ); |
| Abc_ObjAddFanin( pNode, pNode2 ); |
| Abc_ObjAddFanin( pNode, pNode1 ); |
| // update the function to be that of MUX |
| Cudd_RecursiveDeref( dd, (DdNode *)pNode->pData ); |
| pNode->pData = Cudd_bddIte( dd, dd->vars[0], dd->vars[1], dd->vars[2] ); Cudd_Ref( (DdNode *)pNode->pData ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if the node should be decomposed by DSD.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NodeIsForDsd( Abc_Obj_t * pNode ) |
| { |
| // DdManager * dd = pNode->pNtk->pManFunc; |
| // DdNode * bFunc, * bFunc0, * bFunc1; |
| assert( Abc_ObjIsNode(pNode) ); |
| // if ( Cudd_DagSize(pNode->pData)-1 > Abc_ObjFaninNum(pNode) ) |
| // return 1; |
| // return 0; |
| |
| /* |
| // this does not catch things like a(b+c), which should be decomposed |
| for ( bFunc = Cudd_Regular(pNode->pData); !cuddIsConstant(bFunc); ) |
| { |
| bFunc0 = Cudd_Regular( cuddE(bFunc) ); |
| bFunc1 = cuddT(bFunc); |
| if ( bFunc0 == b1 ) |
| bFunc = bFunc1; |
| else if ( bFunc1 == b1 || bFunc0 == bFunc1 ) |
| bFunc = bFunc0; |
| else |
| return 1; |
| } |
| */ |
| if ( Abc_ObjFaninNum(pNode) > 2 ) |
| return 1; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Determines a cofactoring variable.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NodeFindMuxVar( DdManager * dd, DdNode * bFunc, int nVars ) |
| { |
| DdNode * bVar, * bCof0, * bCof1; |
| int SuppSumMin = 1000000; |
| int i, nSSD, nSSQ, iVar; |
| |
| // printf( "\n\nCofactors:\n\n" ); |
| iVar = -1; |
| for ( i = 0; i < nVars; i++ ) |
| { |
| bVar = dd->vars[i]; |
| |
| bCof0 = Cudd_Cofactor( dd, bFunc, Cudd_Not(bVar) ); Cudd_Ref( bCof0 ); |
| bCof1 = Cudd_Cofactor( dd, bFunc, bVar ); Cudd_Ref( bCof1 ); |
| |
| // nodD = Cudd_DagSize(bCof0); |
| // nodQ = Cudd_DagSize(bCof1); |
| // printf( "+%02d: D=%2d. Q=%2d. ", i, nodD, nodQ ); |
| // printf( "S=%2d. D=%2d. ", nodD + nodQ, abs(nodD-nodQ) ); |
| |
| nSSD = Cudd_SupportSize( dd, bCof0 ); |
| nSSQ = Cudd_SupportSize( dd, bCof1 ); |
| |
| // printf( "SD=%2d. SQ=%2d. ", nSSD, nSSQ ); |
| // printf( "S=%2d. D=%2d. ", nSSD + nSSQ, abs(nSSD - nSSQ) ); |
| // printf( "Cost=%3d. ", Cost(nodD,nodQ,nSSD,nSSQ) ); |
| // printf( "\n" ); |
| |
| Cudd_RecursiveDeref( dd, bCof0 ); |
| Cudd_RecursiveDeref( dd, bCof1 ); |
| |
| if ( SuppSumMin > nSSD + nSSQ ) |
| { |
| SuppSumMin = nSSD + nSSQ; |
| iVar = i; |
| } |
| } |
| return iVar; |
| } |
| |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Computes the positive polarty cube composed of the first vars in the array.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ******************************************************************************/ |
| DdNode * Extra_bddComputeSum( DdManager * dd, DdNode ** pbCubes, int nCubes ) |
| { |
| DdNode * bRes, * bTemp; |
| int i; |
| bRes = b0; Cudd_Ref( bRes ); |
| for ( i = 0; i < nCubes; i++ ) |
| { |
| bRes = Cudd_bddOr( dd, bTemp = bRes, pbCubes[i] ); Cudd_Ref( bRes ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| } |
| Cudd_Deref( bRes ); |
| return bRes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Derives network with the given percentage of on-set and off-set minterms.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Abc_NtkSparsifyInternalOne( DdManager * ddNew, DdNode * bFunc, int nFanins, int nPerc ) |
| { |
| int nSpace = (int)Cudd_CountMinterm( ddNew, bFunc, nFanins ); |
| int i, nMints = Abc_MaxInt( 1, (int)(0.01 * nPerc * nSpace) ); |
| DdNode ** pbMints = Cudd_bddPickArbitraryMinterms( ddNew, bFunc, ddNew->vars, nFanins, nMints ); |
| DdNode * bRes; |
| for ( i = 0; i < nMints; i++ ) |
| Cudd_Ref( pbMints[i] ); |
| bRes = Extra_bddComputeSum( ddNew, pbMints, nMints ); Cudd_Ref( bRes ); |
| for ( i = 0; i < nMints; i++ ) |
| Cudd_RecursiveDeref( ddNew, pbMints[i] ); |
| Cudd_Deref( bRes ); |
| ABC_FREE( pbMints ); |
| return bRes; |
| } |
| Abc_Ntk_t * Abc_NtkSparsifyInternal( Abc_Ntk_t * pNtk, int nPerc, int fVerbose ) |
| { |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pObj, * pDriver, * pFanin; |
| DdNode * bFunc, * bFuncOld; |
| DdManager * ddNew; |
| int i, k, c; |
| // start the new network |
| pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_BDD, 1 ); |
| Abc_NtkForEachCi( pNtk, pObj, i ) |
| Abc_NtkDupObj( pNtkNew, pObj, 1 ); |
| // duplicate the name and the spec |
| pNtkNew->pName = Extra_UtilStrsav(pNtk->pName); |
| pNtkNew->pSpec = Extra_UtilStrsav(pNtk->pSpec); |
| // make sure the new manager has enough inputs |
| ddNew = (DdManager *)pNtkNew->pManFunc; |
| Cudd_bddIthVar( ddNew, Abc_NtkCiNum(pNtk)-1 ); |
| // go through the outputs |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| { |
| pDriver = Abc_ObjFanin0( pObj ); |
| if ( Abc_ObjIsCi(pDriver) ) |
| { |
| Abc_NtkDupObj( pNtkNew, pObj, 0 ); |
| Abc_ObjAddFanin( pObj->pCopy, Abc_ObjNotCond(pDriver->pCopy, Abc_ObjFaninC0(pObj)) ); |
| Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), "_on" ); |
| |
| Abc_NtkDupObj( pNtkNew, pObj, 0 ); |
| Abc_ObjAddFanin( pObj->pCopy, Abc_ObjNotCond(pDriver->pCopy, !Abc_ObjFaninC0(pObj)) ); |
| Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), "_off" ); |
| continue; |
| } |
| if ( Abc_ObjFaninNum(pDriver) == 0 ) |
| { |
| Abc_NtkDupObj( pNtkNew, pObj, 0 ); |
| Abc_ObjAddFanin( pObj->pCopy, Abc_ObjFaninC0(pObj) ? Abc_NtkCreateNodeConst0(pNtkNew) : Abc_NtkCreateNodeConst1(pNtkNew) ); |
| Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), "_on" ); |
| |
| Abc_NtkDupObj( pNtkNew, pObj, 0 ); |
| Abc_ObjAddFanin( pObj->pCopy, Abc_ObjFaninC0(pObj) ? Abc_NtkCreateNodeConst1(pNtkNew) : Abc_NtkCreateNodeConst0(pNtkNew) ); |
| Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), "_off" ); |
| continue; |
| } |
| assert( Abc_ObjFaninNum(pObj) > 0 ); |
| // onset/offset |
| for ( c = 0; c < 2; c++ ) |
| { |
| Cudd_Srandom( 0 ); |
| Abc_NtkDupObj( pNtkNew, pDriver, 0 ); |
| Abc_ObjForEachFanin( pDriver, pFanin, k ) |
| Abc_ObjAddFanin( pDriver->pCopy, pFanin->pCopy ); |
| bFuncOld = Cudd_NotCond( (DdNode *)pDriver->pCopy->pData, c ); |
| bFunc = Abc_NtkSparsifyInternalOne( ddNew, bFuncOld, Abc_ObjFaninNum(pDriver), nPerc ); Cudd_Ref( bFunc ); |
| Cudd_RecursiveDeref( ddNew, bFuncOld ); |
| pDriver->pCopy->pData = bFunc; |
| Abc_NtkDupObj( pNtkNew, pObj, 0 ); |
| Abc_ObjAddFanin( pObj->pCopy, pDriver->pCopy ); |
| Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), (char*)(c ? "_off" : "_on") ); |
| } |
| } |
| Abc_NtkLogicMakeSimpleCos( pNtkNew, 0 ); |
| return pNtkNew; |
| } |
| Abc_Ntk_t * Abc_NtkSparsify( Abc_Ntk_t * pNtk, int nPerc, int fVerbose ) |
| { |
| Abc_Ntk_t * pNtkNew; |
| assert( Abc_NtkIsComb(pNtk) ); |
| assert( Abc_NtkIsBddLogic(pNtk) ); |
| pNtkNew = Abc_NtkSparsifyInternal( pNtk, nPerc, fVerbose ); |
| if ( pNtkNew == NULL ) |
| return NULL; |
| if ( !Abc_NtkCheck( pNtkNew ) ) |
| { |
| printf( "Abc_NtkSparsify: The network check has failed.\n" ); |
| Abc_NtkDelete( pNtkNew ); |
| return NULL; |
| } |
| return pNtkNew; |
| } |
| |
| #else |
| |
| Abc_Ntk_t * Abc_NtkSparsify( Abc_Ntk_t * pNtk, int nPerc, int fVerbose ) { return NULL; } |
| Abc_Ntk_t * Abc_NtkDsdGlobal( Abc_Ntk_t * pNtk, int fVerbose, int fPrint, int fShort ) { return NULL; } |
| int Abc_NtkDsdLocal( Abc_Ntk_t * pNtk, int fVerbose, int fRecursive ) { return 0; } |
| |
| #endif |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |