| /**CFile**************************************************************** |
| |
| FileName [abcQuant.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Network and node package.] |
| |
| Synopsis [AIG-based variable quantification.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: abcQuant.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "base/abc/abc.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs fast synthesis.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkSynthesize( Abc_Ntk_t ** ppNtk, int fMoreEffort ) |
| { |
| extern Abc_Ntk_t * Abc_NtkIvyFraig( Abc_Ntk_t * pNtk, int nConfLimit, int fDoSparse, int fProve, int fTransfer, int fVerbose ); |
| |
| Abc_Ntk_t * pNtk, * pNtkTemp; |
| |
| pNtk = *ppNtk; |
| |
| Abc_NtkRewrite( pNtk, 0, 0, 0, 0, 0 ); |
| Abc_NtkRefactor( pNtk, 10, 16, 0, 0, 0, 0 ); |
| pNtk = Abc_NtkBalance( pNtkTemp = pNtk, 0, 0, 0 ); |
| Abc_NtkDelete( pNtkTemp ); |
| |
| if ( fMoreEffort ) |
| { |
| Abc_NtkRewrite( pNtk, 0, 0, 0, 0, 0 ); |
| Abc_NtkRefactor( pNtk, 10, 16, 0, 0, 0, 0 ); |
| pNtk = Abc_NtkBalance( pNtkTemp = pNtk, 0, 0, 0 ); |
| Abc_NtkDelete( pNtkTemp ); |
| |
| pNtk = Abc_NtkIvyFraig( pNtkTemp = pNtk, 100, 1, 0, 0, 0 ); |
| Abc_NtkDelete( pNtkTemp ); |
| } |
| |
| *ppNtk = pNtk; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Existentially quantifies one variable.] |
| |
| Description [] |
| |
| SideEffects [This procedure creates dangling nodes in the AIG.] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkQuantify( Abc_Ntk_t * pNtk, int fUniv, int iVar, int fVerbose ) |
| { |
| Vec_Ptr_t * vNodes; |
| Abc_Obj_t * pObj, * pNext, * pFanin; |
| int i; |
| assert( Abc_NtkIsStrash(pNtk) ); |
| assert( iVar < Abc_NtkCiNum(pNtk) ); |
| |
| // collect the internal nodes |
| pObj = Abc_NtkCi( pNtk, iVar ); |
| vNodes = Abc_NtkDfsReverseNodes( pNtk, &pObj, 1 ); |
| |
| // assign the cofactors of the CI node to be constants |
| pObj->pCopy = Abc_ObjNot( Abc_AigConst1(pNtk) ); |
| pObj->pData = Abc_AigConst1(pNtk); |
| |
| // quantify the nodes |
| Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) |
| { |
| for ( pNext = pObj? pObj->pCopy : pObj; pObj; pObj = pNext, pNext = pObj? pObj->pCopy : pObj ) |
| { |
| pFanin = Abc_ObjFanin0(pObj); |
| if ( !Abc_NodeIsTravIdCurrent(pFanin) ) |
| { |
| pFanin->pCopy = pFanin; |
| pFanin->pData = pFanin; |
| } |
| pFanin = Abc_ObjFanin1(pObj); |
| if ( !Abc_NodeIsTravIdCurrent(pFanin) ) |
| { |
| pFanin->pCopy = pFanin; |
| pFanin->pData = pFanin; |
| } |
| pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtk->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) ); |
| pObj->pData = Abc_AigAnd( (Abc_Aig_t *)pNtk->pManFunc, Abc_ObjChild0Data(pObj), Abc_ObjChild1Data(pObj) ); |
| } |
| } |
| Vec_PtrFree( vNodes ); |
| |
| // update the affected COs |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| { |
| if ( !Abc_NodeIsTravIdCurrent(pObj) ) |
| continue; |
| pFanin = Abc_ObjFanin0(pObj); |
| // get the result of quantification |
| if ( fUniv ) |
| pNext = Abc_AigAnd( (Abc_Aig_t *)pNtk->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild0Data(pObj) ); |
| else |
| pNext = Abc_AigOr( (Abc_Aig_t *)pNtk->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild0Data(pObj) ); |
| pNext = Abc_ObjNotCond( pNext, Abc_ObjFaninC0(pObj) ); |
| if ( Abc_ObjRegular(pNext) == pFanin ) |
| continue; |
| // update the fanins of the CO |
| Abc_ObjPatchFanin( pObj, pFanin, pNext ); |
| // if ( Abc_ObjFanoutNum(pFanin) == 0 ) |
| // Abc_AigDeleteNode( pNtk->pManFunc, pFanin ); |
| } |
| |
| // make sure the node has no fanouts |
| // pObj = Abc_NtkCi( pNtk, iVar ); |
| // assert( Abc_ObjFanoutNum(pObj) == 0 ); |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Constructs the transition relation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkTransRel( Abc_Ntk_t * pNtk, int fInputs, int fVerbose ) |
| { |
| char Buffer[1000]; |
| Vec_Ptr_t * vPairs; |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pObj, * pMiter; |
| int i, nLatches; |
| int fSynthesis = 1; |
| |
| assert( Abc_NtkIsStrash(pNtk) ); |
| assert( Abc_NtkLatchNum(pNtk) ); |
| nLatches = Abc_NtkLatchNum(pNtk); |
| // start the network |
| pNtkNew = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 ); |
| // duplicate the name and the spec |
| sprintf( Buffer, "%s_TR", pNtk->pName ); |
| pNtkNew->pName = Extra_UtilStrsav(pNtk->pName); |
| // pNtkNew->pSpec = Extra_UtilStrsav(pNtk->pSpec); |
| Abc_NtkCleanCopy( pNtk ); |
| // create current state variables |
| Abc_NtkForEachLatchOutput( pNtk, pObj, i ) |
| { |
| pObj->pCopy = Abc_NtkCreatePi(pNtkNew); |
| Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL ); |
| } |
| // create next state variables |
| Abc_NtkForEachLatchInput( pNtk, pObj, i ) |
| Abc_ObjAssignName( Abc_NtkCreatePi(pNtkNew), Abc_ObjName(pObj), NULL ); |
| // create PI variables |
| Abc_NtkForEachPi( pNtk, pObj, i ) |
| Abc_NtkDupObj( pNtkNew, pObj, 1 ); |
| // create the PO |
| Abc_NtkCreatePo( pNtkNew ); |
| // restrash the nodes (assuming a topological order of the old network) |
| Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew); |
| Abc_NtkForEachNode( pNtk, pObj, i ) |
| pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) ); |
| // create the function of the primary output |
| assert( Abc_NtkBoxNum(pNtk) == Abc_NtkLatchNum(pNtk) ); |
| vPairs = Vec_PtrAlloc( 2*nLatches ); |
| Abc_NtkForEachLatchInput( pNtk, pObj, i ) |
| { |
| Vec_PtrPush( vPairs, Abc_ObjChild0Copy(pObj) ); |
| Vec_PtrPush( vPairs, Abc_NtkPi(pNtkNew, i+nLatches) ); |
| } |
| pMiter = Abc_AigMiter( (Abc_Aig_t *)pNtkNew->pManFunc, vPairs, 0 ); |
| Vec_PtrFree( vPairs ); |
| // add the primary output |
| Abc_ObjAddFanin( Abc_NtkPo(pNtkNew,0), Abc_ObjNot(pMiter) ); |
| Abc_ObjAssignName( Abc_NtkPo(pNtkNew,0), "rel", NULL ); |
| |
| // quantify inputs |
| if ( fInputs ) |
| { |
| assert( Abc_NtkPiNum(pNtkNew) == Abc_NtkPiNum(pNtk) + 2*nLatches ); |
| for ( i = Abc_NtkPiNum(pNtkNew) - 1; i >= 2*nLatches; i-- ) |
| // for ( i = 2*nLatches; i < Abc_NtkPiNum(pNtkNew); i++ ) |
| { |
| Abc_NtkQuantify( pNtkNew, 0, i, fVerbose ); |
| // if ( fSynthesis && (i % 3 == 2) ) |
| if ( fSynthesis ) |
| { |
| Abc_NtkCleanData( pNtkNew ); |
| Abc_AigCleanup( (Abc_Aig_t *)pNtkNew->pManFunc ); |
| Abc_NtkSynthesize( &pNtkNew, 1 ); |
| } |
| // printf( "Var = %3d. Nodes = %6d. ", Abc_NtkPiNum(pNtkNew) - 1 - i, Abc_NtkNodeNum(pNtkNew) ); |
| // printf( "Var = %3d. Nodes = %6d. ", i - 2*nLatches, Abc_NtkNodeNum(pNtkNew) ); |
| } |
| // printf( "\n" ); |
| Abc_NtkCleanData( pNtkNew ); |
| Abc_AigCleanup( (Abc_Aig_t *)pNtkNew->pManFunc ); |
| for ( i = Abc_NtkPiNum(pNtkNew) - 1; i >= 2*nLatches; i-- ) |
| { |
| pObj = Abc_NtkPi( pNtkNew, i ); |
| assert( Abc_ObjFanoutNum(pObj) == 0 ); |
| Abc_NtkDeleteObj( pObj ); |
| } |
| } |
| |
| // check consistency of the network |
| if ( !Abc_NtkCheck( pNtkNew ) ) |
| { |
| printf( "Abc_NtkTransRel: The network check has failed.\n" ); |
| Abc_NtkDelete( pNtkNew ); |
| return NULL; |
| } |
| return pNtkNew; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs one image computation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkInitialState( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pMiter; |
| int i, nVars = Abc_NtkPiNum(pNtk)/2; |
| assert( Abc_NtkIsStrash(pNtk) ); |
| // start the new network |
| pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG ); |
| // compute the all-zero state in terms of the CS variables |
| pMiter = Abc_AigConst1(pNtkNew); |
| for ( i = 0; i < nVars; i++ ) |
| pMiter = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, pMiter, Abc_ObjNot( Abc_NtkPi(pNtkNew, i) ) ); |
| // add the PO |
| Abc_ObjAddFanin( Abc_NtkPo(pNtkNew,0), pMiter ); |
| return pNtkNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Swaps current state and next state variables.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkSwapVariables( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pMiter, * pObj, * pObj0, * pObj1; |
| int i, nVars = Abc_NtkPiNum(pNtk)/2; |
| assert( Abc_NtkIsStrash(pNtk) ); |
| // start the new network |
| pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG ); |
| // update the PIs |
| for ( i = 0; i < nVars; i++ ) |
| { |
| pObj0 = Abc_NtkPi( pNtk, i ); |
| pObj1 = Abc_NtkPi( pNtk, i+nVars ); |
| pMiter = pObj0->pCopy; |
| pObj0->pCopy = pObj1->pCopy; |
| pObj1->pCopy = pMiter; |
| } |
| // restrash |
| Abc_NtkForEachNode( pNtk, pObj, i ) |
| pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) ); |
| // add the PO |
| pMiter = Abc_ObjChild0Copy( Abc_NtkPo(pNtk,0) ); |
| Abc_ObjAddFanin( Abc_NtkPo(pNtkNew,0), pMiter ); |
| return pNtkNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs reachability analisys.] |
| |
| Description [Assumes that the input is the transition relation.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkReachability( Abc_Ntk_t * pNtkRel, int nIters, int fVerbose ) |
| { |
| Abc_Obj_t * pObj; |
| Abc_Ntk_t * pNtkFront, * pNtkReached, * pNtkNext, * pNtkTemp; |
| int i, v, nVars, nNodesOld, nNodesNew, nNodesPrev; |
| int fFixedPoint = 0; |
| int fSynthesis = 1; |
| int fMoreEffort = 1; |
| abctime clk; |
| |
| assert( Abc_NtkIsStrash(pNtkRel) ); |
| assert( Abc_NtkLatchNum(pNtkRel) == 0 ); |
| assert( Abc_NtkPiNum(pNtkRel) % 2 == 0 ); |
| |
| // compute the network composed of the initial states |
| pNtkFront = Abc_NtkInitialState( pNtkRel ); |
| pNtkReached = Abc_NtkDup( pNtkFront ); |
| //Abc_NtkShow( pNtkReached, 0, 0, 0 ); |
| |
| // if ( fVerbose ) |
| // printf( "Transition relation = %6d.\n", Abc_NtkNodeNum(pNtkRel) ); |
| |
| // perform iterations of reachability analysis |
| nNodesPrev = Abc_NtkNodeNum(pNtkFront); |
| nVars = Abc_NtkPiNum(pNtkRel)/2; |
| for ( i = 0; i < nIters; i++ ) |
| { |
| clk = Abc_Clock(); |
| // get the set of next states |
| pNtkNext = Abc_NtkMiterAnd( pNtkRel, pNtkFront, 0, 0 ); |
| Abc_NtkDelete( pNtkFront ); |
| // quantify the current state variables |
| for ( v = 0; v < nVars; v++ ) |
| { |
| Abc_NtkQuantify( pNtkNext, 0, v, fVerbose ); |
| if ( fSynthesis && (v % 3 == 2) ) |
| { |
| Abc_NtkCleanData( pNtkNext ); |
| Abc_AigCleanup( (Abc_Aig_t *)pNtkNext->pManFunc ); |
| Abc_NtkSynthesize( &pNtkNext, fMoreEffort ); |
| } |
| } |
| Abc_NtkCleanData( pNtkNext ); |
| Abc_AigCleanup( (Abc_Aig_t *)pNtkNext->pManFunc ); |
| if ( fSynthesis ) |
| Abc_NtkSynthesize( &pNtkNext, 1 ); |
| // map the next states into the current states |
| pNtkNext = Abc_NtkSwapVariables( pNtkTemp = pNtkNext ); |
| Abc_NtkDelete( pNtkTemp ); |
| // check the termination condition |
| if ( Abc_ObjFanin0(Abc_NtkPo(pNtkNext,0)) == Abc_AigConst1(pNtkNext) ) |
| { |
| fFixedPoint = 1; |
| printf( "Fixed point is reached!\n" ); |
| Abc_NtkDelete( pNtkNext ); |
| break; |
| } |
| // compute new front |
| pNtkFront = Abc_NtkMiterAnd( pNtkNext, pNtkReached, 0, 1 ); |
| Abc_NtkDelete( pNtkNext ); |
| // add the reached states |
| pNtkReached = Abc_NtkMiterAnd( pNtkTemp = pNtkReached, pNtkFront, 1, 0 ); |
| Abc_NtkDelete( pNtkTemp ); |
| // compress the size of Front |
| nNodesOld = Abc_NtkNodeNum(pNtkFront); |
| if ( fSynthesis ) |
| { |
| Abc_NtkSynthesize( &pNtkFront, fMoreEffort ); |
| Abc_NtkSynthesize( &pNtkReached, fMoreEffort ); |
| } |
| nNodesNew = Abc_NtkNodeNum(pNtkFront); |
| // print statistics |
| if ( fVerbose ) |
| { |
| printf( "I = %3d : Reach = %6d Fr = %6d FrM = %6d %7.2f %% ", |
| i + 1, Abc_NtkNodeNum(pNtkReached), nNodesOld, nNodesNew, 100.0*(nNodesNew-nNodesPrev)/nNodesPrev ); |
| ABC_PRT( "T", Abc_Clock() - clk ); |
| } |
| nNodesPrev = Abc_NtkNodeNum(pNtkFront); |
| } |
| if ( !fFixedPoint ) |
| fprintf( stdout, "Reachability analysis stopped after %d iterations.\n", nIters ); |
| |
| // complement the output to represent the set of unreachable states |
| Abc_ObjXorFaninC( Abc_NtkPo(pNtkReached,0), 0 ); |
| |
| // remove next state variables |
| for ( i = 2*nVars - 1; i >= nVars; i-- ) |
| { |
| pObj = Abc_NtkPi( pNtkReached, i ); |
| assert( Abc_ObjFanoutNum(pObj) == 0 ); |
| Abc_NtkDeleteObj( pObj ); |
| } |
| |
| // check consistency of the network |
| if ( !Abc_NtkCheck( pNtkReached ) ) |
| { |
| printf( "Abc_NtkReachability: The network check has failed.\n" ); |
| Abc_NtkDelete( pNtkReached ); |
| return NULL; |
| } |
| return pNtkReached; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |