| /**CFile**************************************************************** |
| |
| FileName [abcReach.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Network and node package.] |
| |
| Synopsis [Performs reachability analysis.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: abcReach.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 /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| #ifdef ABC_USE_CUDD |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes the initial state and sets up the variable map.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Abc_NtkInitStateVarMap( DdManager * dd, Abc_Ntk_t * pNtk, int fVerbose ) |
| { |
| DdNode ** pbVarsX, ** pbVarsY; |
| DdNode * bTemp, * bProd, * bVar; |
| Abc_Obj_t * pLatch; |
| int i; |
| |
| // set the variable mapping for Cudd_bddVarMap() |
| pbVarsX = ABC_ALLOC( DdNode *, dd->size ); |
| pbVarsY = ABC_ALLOC( DdNode *, dd->size ); |
| bProd = b1; Cudd_Ref( bProd ); |
| Abc_NtkForEachLatch( pNtk, pLatch, i ) |
| { |
| pbVarsX[i] = dd->vars[ Abc_NtkPiNum(pNtk) + i ]; |
| pbVarsY[i] = dd->vars[ Abc_NtkCiNum(pNtk) + i ]; |
| // get the initial value of the latch |
| bVar = Cudd_NotCond( pbVarsX[i], !Abc_LatchIsInit1(pLatch) ); |
| bProd = Cudd_bddAnd( dd, bTemp = bProd, bVar ); Cudd_Ref( bProd ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| } |
| Cudd_SetVarMap( dd, pbVarsX, pbVarsY, Abc_NtkLatchNum(pNtk) ); |
| ABC_FREE( pbVarsX ); |
| ABC_FREE( pbVarsY ); |
| |
| Cudd_Deref( bProd ); |
| return bProd; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode ** Abc_NtkCreatePartitions( DdManager * dd, Abc_Ntk_t * pNtk, int fReorder, int fVerbose ) |
| { |
| DdNode ** pbParts; |
| DdNode * bVar; |
| Abc_Obj_t * pNode; |
| int i; |
| |
| // extand the BDD manager to represent NS variables |
| assert( dd->size == Abc_NtkCiNum(pNtk) ); |
| Cudd_bddIthVar( dd, Abc_NtkCiNum(pNtk) + Abc_NtkLatchNum(pNtk) - 1 ); |
| |
| // enable reordering |
| if ( fReorder ) |
| Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); |
| else |
| Cudd_AutodynDisable( dd ); |
| |
| // compute the transition relation |
| pbParts = ABC_ALLOC( DdNode *, Abc_NtkLatchNum(pNtk) ); |
| Abc_NtkForEachLatch( pNtk, pNode, i ) |
| { |
| bVar = Cudd_bddIthVar( dd, Abc_NtkCiNum(pNtk) + i ); |
| pbParts[i] = Cudd_bddXnor( dd, bVar, (DdNode *)Abc_ObjGlobalBdd(Abc_ObjFanin0(pNode)) ); Cudd_Ref( pbParts[i] ); |
| } |
| // free the global BDDs |
| Abc_NtkFreeGlobalBdds( pNtk, 0 ); |
| |
| // reorder and disable reordering |
| if ( fReorder ) |
| { |
| if ( fVerbose ) |
| fprintf( stdout, "BDD nodes in the partitions before reordering %d.\n", Cudd_SharingSize(pbParts,Abc_NtkLatchNum(pNtk)) ); |
| Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); |
| Cudd_AutodynDisable( dd ); |
| if ( fVerbose ) |
| fprintf( stdout, "BDD nodes in the partitions after reordering %d.\n", Cudd_SharingSize(pbParts,Abc_NtkLatchNum(pNtk)) ); |
| } |
| return pbParts; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes the set of unreachable states.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Abc_NtkComputeReachable( DdManager * dd, Abc_Ntk_t * pNtk, DdNode ** pbParts, DdNode * bInitial, DdNode * bOutput, int nBddMax, int nIterMax, int fPartition, int fReorder, int fVerbose ) |
| { |
| int fInternalReorder = 0; |
| Extra_ImageTree_t * pTree = NULL; |
| Extra_ImageTree2_t * pTree2 = NULL; |
| DdNode * bReached, * bCubeCs; |
| DdNode * bCurrent, * bNext = NULL, * bTemp; |
| DdNode ** pbVarsY; |
| Abc_Obj_t * pLatch; |
| int i, nIters, nBddSize; |
| int nThreshold = 10000; |
| |
| // collect the NS variables |
| // set the variable mapping for Cudd_bddVarMap() |
| pbVarsY = ABC_ALLOC( DdNode *, dd->size ); |
| Abc_NtkForEachLatch( pNtk, pLatch, i ) |
| pbVarsY[i] = dd->vars[ Abc_NtkCiNum(pNtk) + i ]; |
| |
| // start the image computation |
| bCubeCs = Extra_bddComputeRangeCube( dd, Abc_NtkPiNum(pNtk), Abc_NtkCiNum(pNtk) ); Cudd_Ref( bCubeCs ); |
| if ( fPartition ) |
| pTree = Extra_bddImageStart( dd, bCubeCs, Abc_NtkLatchNum(pNtk), pbParts, Abc_NtkLatchNum(pNtk), pbVarsY, fVerbose ); |
| else |
| pTree2 = Extra_bddImageStart2( dd, bCubeCs, Abc_NtkLatchNum(pNtk), pbParts, Abc_NtkLatchNum(pNtk), pbVarsY, fVerbose ); |
| ABC_FREE( pbVarsY ); |
| Cudd_RecursiveDeref( dd, bCubeCs ); |
| |
| // perform reachability analisys |
| bCurrent = bInitial; Cudd_Ref( bCurrent ); |
| bReached = bInitial; Cudd_Ref( bReached ); |
| assert( nIterMax > 1 ); // required to not deref uninitialized bNext |
| for ( nIters = 1; nIters <= nIterMax; nIters++ ) |
| { |
| // compute the next states |
| if ( fPartition ) |
| bNext = Extra_bddImageCompute( pTree, bCurrent ); |
| else |
| bNext = Extra_bddImageCompute2( pTree2, bCurrent ); |
| Cudd_Ref( bNext ); |
| Cudd_RecursiveDeref( dd, bCurrent ); |
| // remap these states into the current state vars |
| bNext = Cudd_bddVarMap( dd, bTemp = bNext ); Cudd_Ref( bNext ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| // check if there are any new states |
| if ( Cudd_bddLeq( dd, bNext, bReached ) ) |
| break; |
| // check the BDD size |
| nBddSize = Cudd_DagSize(bNext); |
| if ( nBddSize > nBddMax ) |
| break; |
| // check the result |
| if ( !Cudd_bddLeq( dd, bNext, Cudd_Not(bOutput) ) ) |
| { |
| printf( "The miter is proved REACHABLE in %d iterations. ", nIters ); |
| Cudd_RecursiveDeref( dd, bReached ); |
| bReached = NULL; |
| break; |
| } |
| // get the new states |
| bCurrent = Cudd_bddAnd( dd, bNext, Cudd_Not(bReached) ); Cudd_Ref( bCurrent ); |
| // minimize the new states with the reached states |
| // bCurrent = Cudd_bddConstrain( dd, bTemp = bCurrent, Cudd_Not(bReached) ); Cudd_Ref( bCurrent ); |
| // Cudd_RecursiveDeref( dd, bTemp ); |
| // add to the reached states |
| bReached = Cudd_bddOr( dd, bTemp = bReached, bNext ); Cudd_Ref( bReached ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| Cudd_RecursiveDeref( dd, bNext ); |
| if ( fVerbose ) |
| fprintf( stdout, "Iteration = %3d. BDD = %5d. ", nIters, nBddSize ); |
| if ( fInternalReorder && fReorder && nBddSize > nThreshold ) |
| { |
| if ( fVerbose ) |
| fprintf( stdout, "Reordering... Before = %5d. ", Cudd_DagSize(bReached) ); |
| Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); |
| Cudd_AutodynDisable( dd ); |
| if ( fVerbose ) |
| fprintf( stdout, "After = %5d.\r", Cudd_DagSize(bReached) ); |
| nThreshold *= 2; |
| } |
| if ( fVerbose ) |
| fprintf( stdout, "\r" ); |
| } |
| Cudd_RecursiveDeref( dd, bNext ); |
| // undo the image tree |
| if ( fPartition ) |
| Extra_bddImageTreeDelete( pTree ); |
| else |
| Extra_bddImageTreeDelete2( pTree2 ); |
| if ( bReached == NULL ) |
| return NULL; |
| // report the stats |
| if ( fVerbose ) |
| { |
| double nMints = Cudd_CountMinterm(dd, bReached, Abc_NtkLatchNum(pNtk) ); |
| if ( nIters > nIterMax || Cudd_DagSize(bReached) > nBddMax ) |
| fprintf( stdout, "Reachability analysis is stopped after %d iterations.\n", nIters ); |
| else |
| fprintf( stdout, "Reachability analysis completed in %d iterations.\n", nIters ); |
| fprintf( stdout, "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Abc_NtkLatchNum(pNtk)) ); |
| fflush( stdout ); |
| } |
| //ABC_PRB( dd, bReached ); |
| Cudd_Deref( bReached ); |
| if ( nIters > nIterMax || Cudd_DagSize(bReached) > nBddMax ) |
| printf( "Verified ONLY FOR STATES REACHED in %d iterations. \n", nIters ); |
| printf( "The miter is proved unreachable in %d iteration. ", nIters ); |
| return bReached; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs reachability to see if any .] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkVerifyUsingBdds( Abc_Ntk_t * pNtk, int nBddMax, int nIterMax, int fPartition, int fReorder, int fVerbose ) |
| { |
| DdManager * dd; |
| DdNode ** pbParts; |
| DdNode * bOutput, * bReached, * bInitial; |
| int i; |
| abctime clk = Abc_Clock(); |
| |
| assert( Abc_NtkIsStrash(pNtk) ); |
| assert( Abc_NtkPoNum(pNtk) == 1 ); |
| assert( Abc_ObjFanoutNum(Abc_NtkPo(pNtk,0)) == 0 ); // PO should go first |
| |
| // compute the global BDDs of the latches |
| dd = (DdManager *)Abc_NtkBuildGlobalBdds( pNtk, nBddMax, 1, fReorder, fVerbose ); |
| if ( dd == NULL ) |
| { |
| printf( "The number of intermediate BDD nodes exceeded the limit (%d).\n", nBddMax ); |
| return; |
| } |
| if ( fVerbose ) |
| printf( "Shared BDD size is %6d nodes.\n", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); |
| |
| // save the output BDD |
| bOutput = (DdNode *)Abc_ObjGlobalBdd(Abc_NtkPo(pNtk,0)); Cudd_Ref( bOutput ); |
| |
| // create partitions |
| pbParts = Abc_NtkCreatePartitions( dd, pNtk, fReorder, fVerbose ); |
| |
| // create the initial state and the variable map |
| bInitial = Abc_NtkInitStateVarMap( dd, pNtk, fVerbose ); Cudd_Ref( bInitial ); |
| |
| // check the result |
| if ( !Cudd_bddLeq( dd, bInitial, Cudd_Not(bOutput) ) ) |
| printf( "The miter is proved REACHABLE in the initial state. " ); |
| else |
| { |
| // compute the reachable states |
| bReached = Abc_NtkComputeReachable( dd, pNtk, pbParts, bInitial, bOutput, nBddMax, nIterMax, fPartition, fReorder, fVerbose ); |
| if ( bReached != NULL ) |
| { |
| Cudd_Ref( bReached ); |
| Cudd_RecursiveDeref( dd, bReached ); |
| } |
| } |
| |
| // cleanup |
| Cudd_RecursiveDeref( dd, bOutput ); |
| Cudd_RecursiveDeref( dd, bInitial ); |
| for ( i = 0; i < Abc_NtkLatchNum(pNtk); i++ ) |
| Cudd_RecursiveDeref( dd, pbParts[i] ); |
| ABC_FREE( pbParts ); |
| Extra_StopManager( dd ); |
| |
| // report the runtime |
| ABC_PRT( "Time", Abc_Clock() - clk ); |
| fflush( stdout ); |
| } |
| |
| #endif |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |