| /**CFile**************************************************************** |
| |
| FileName [ivyHaig.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [And-Inverter Graph package.] |
| |
| Synopsis [HAIG management procedures.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - May 11, 2006.] |
| |
| Revision [$Id: ivyHaig.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "ivy.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /* |
| HAIGing rules in working AIG: |
| - Each node in the working AIG has a pointer to the corresponding node in HAIG |
| (this node is not necessarily the representative of the equivalence class of HAIG nodes) |
| - This pointer is complemented if the AIG node and its corresponding HAIG node have different phase |
| |
| Choice node rules in HAIG: |
| - Equivalent nodes are linked into a ring |
| - Exactly one node in the ring has fanouts (this node is called the representative) |
| - The pointer going from a node to the next node in the ring is complemented |
| if the first node is complemented, compared to the representative node of the equivalence class |
| - (consequence of the above) The representative node always has non-complemented pointer to the next node |
| - New nodes are inserted into the ring immediately after the representative node |
| */ |
| |
| // returns the representative node of the given HAIG node |
| static inline Ivy_Obj_t * Ivy_HaigObjRepr( Ivy_Obj_t * pObj ) |
| { |
| Ivy_Obj_t * pTemp; |
| assert( !Ivy_IsComplement(pObj) ); |
| // if the node has no equivalent node or has fanout, it is representative |
| if ( pObj->pEquiv == NULL || Ivy_ObjRefs(pObj) > 0 ) |
| return pObj; |
| // the node belongs to a class and is not a representative |
| // complemented edge (pObj->pEquiv) tells if it is complemented w.r.t. the repr |
| for ( pTemp = Ivy_Regular(pObj->pEquiv); pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) ) |
| if ( Ivy_ObjRefs(pTemp) > 0 ) |
| break; |
| // return the representative node |
| assert( Ivy_ObjRefs(pTemp) > 0 ); |
| return Ivy_NotCond( pTemp, Ivy_IsComplement(pObj->pEquiv) ); |
| } |
| |
| // counts the number of nodes in the equivalence class |
| static inline int Ivy_HaigObjCountClass( Ivy_Obj_t * pObj ) |
| { |
| Ivy_Obj_t * pTemp; |
| int Counter; |
| assert( !Ivy_IsComplement(pObj) ); |
| assert( Ivy_ObjRefs(pObj) > 0 ); |
| if ( pObj->pEquiv == NULL ) |
| return 1; |
| assert( !Ivy_IsComplement(pObj->pEquiv) ); |
| Counter = 1; |
| for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) ) |
| Counter++; |
| return Counter; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts HAIG for the manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManHaigStart( Ivy_Man_t * p, int fVerbose ) |
| { |
| Vec_Int_t * vLatches; |
| Ivy_Obj_t * pObj; |
| int i; |
| assert( p->pHaig == NULL ); |
| p->pHaig = Ivy_ManDup( p ); |
| |
| if ( fVerbose ) |
| { |
| printf( "Starting : " ); |
| Ivy_ManPrintStats( p->pHaig ); |
| } |
| |
| // collect latches of design D and set their values to be DC |
| vLatches = Vec_IntAlloc( 100 ); |
| Ivy_ManForEachLatch( p->pHaig, pObj, i ) |
| { |
| pObj->Init = IVY_INIT_DC; |
| Vec_IntPush( vLatches, pObj->Id ); |
| } |
| p->pHaig->pData = vLatches; |
| /* |
| { |
| int x; |
| Ivy_ManShow( p, 0, NULL ); |
| Ivy_ManShow( p->pHaig, 1, NULL ); |
| x = 0; |
| } |
| */ |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Transfers the HAIG to the newly created manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManHaigTrasfer( Ivy_Man_t * p, Ivy_Man_t * pNew ) |
| { |
| Ivy_Obj_t * pObj; |
| int i; |
| assert( p->pHaig != NULL ); |
| Ivy_ManConst1(pNew)->pEquiv = Ivy_ManConst1(p)->pEquiv; |
| Ivy_ManForEachPi( pNew, pObj, i ) |
| pObj->pEquiv = Ivy_ManPi( p, i )->pEquiv; |
| pNew->pHaig = p->pHaig; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Stops HAIG for the manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManHaigStop( Ivy_Man_t * p ) |
| { |
| Ivy_Obj_t * pObj; |
| int i; |
| assert( p->pHaig != NULL ); |
| Vec_IntFree( (Vec_Int_t *)p->pHaig->pData ); |
| Ivy_ManStop( p->pHaig ); |
| p->pHaig = NULL; |
| // remove dangling pointers to the HAIG objects |
| Ivy_ManForEachObj( p, pObj, i ) |
| pObj->pEquiv = NULL; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Creates a new node in HAIG.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManHaigCreateObj( Ivy_Man_t * p, Ivy_Obj_t * pObj ) |
| { |
| Ivy_Obj_t * pEquiv0, * pEquiv1; |
| assert( p->pHaig != NULL ); |
| assert( !Ivy_IsComplement(pObj) ); |
| if ( Ivy_ObjType(pObj) == IVY_BUF ) |
| pObj->pEquiv = Ivy_ObjChild0Equiv(pObj); |
| else if ( Ivy_ObjType(pObj) == IVY_LATCH ) |
| { |
| // pObj->pEquiv = Ivy_Latch( p->pHaig, Ivy_ObjChild0Equiv(pObj), pObj->Init ); |
| pEquiv0 = Ivy_ObjChild0Equiv(pObj); |
| pEquiv0 = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pEquiv0)), Ivy_IsComplement(pEquiv0) ); |
| pObj->pEquiv = Ivy_Latch( p->pHaig, pEquiv0, (Ivy_Init_t)pObj->Init ); |
| } |
| else if ( Ivy_ObjType(pObj) == IVY_AND ) |
| { |
| // pObj->pEquiv = Ivy_And( p->pHaig, Ivy_ObjChild0Equiv(pObj), Ivy_ObjChild1Equiv(pObj) ); |
| pEquiv0 = Ivy_ObjChild0Equiv(pObj); |
| pEquiv0 = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pEquiv0)), Ivy_IsComplement(pEquiv0) ); |
| pEquiv1 = Ivy_ObjChild1Equiv(pObj); |
| pEquiv1 = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pEquiv1)), Ivy_IsComplement(pEquiv1) ); |
| pObj->pEquiv = Ivy_And( p->pHaig, pEquiv0, pEquiv1 ); |
| } |
| else assert( 0 ); |
| // make sure the node points to the representative |
| // pObj->pEquiv = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pObj->pEquiv)), Ivy_IsComplement(pObj->pEquiv) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if the old node is in the TFI of the new node.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ObjIsInTfi_rec( Ivy_Obj_t * pObjNew, Ivy_Obj_t * pObjOld, int Levels ) |
| { |
| if ( pObjNew == pObjOld ) |
| return 1; |
| if ( Levels == 0 || Ivy_ObjIsCi(pObjNew) || Ivy_ObjIsConst1(pObjNew) ) |
| return 0; |
| if ( Ivy_ObjIsInTfi_rec( Ivy_ObjFanin0(pObjNew), pObjOld, Levels - 1 ) ) |
| return 1; |
| if ( Ivy_ObjIsNode(pObjNew) && Ivy_ObjIsInTfi_rec( Ivy_ObjFanin1(pObjNew), pObjOld, Levels - 1 ) ) |
| return 1; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Sets the pair of equivalent nodes in HAIG.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManHaigCreateChoice( Ivy_Man_t * p, Ivy_Obj_t * pObjOld, Ivy_Obj_t * pObjNew ) |
| { |
| Ivy_Obj_t * pObjOldHaig, * pObjNewHaig; |
| Ivy_Obj_t * pObjOldHaigR, * pObjNewHaigR; |
| int fCompl; |
| //printf( "\nCreating choice for %d and %d in AIG\n", pObjOld->Id, Ivy_Regular(pObjNew)->Id ); |
| |
| assert( p->pHaig != NULL ); |
| assert( !Ivy_IsComplement(pObjOld) ); |
| // get pointers to the representatives of pObjOld and pObjNew |
| pObjOldHaig = pObjOld->pEquiv; |
| pObjNewHaig = Ivy_NotCond( Ivy_Regular(pObjNew)->pEquiv, Ivy_IsComplement(pObjNew) ); |
| // get the classes |
| pObjOldHaig = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pObjOldHaig)), Ivy_IsComplement(pObjOldHaig) ); |
| pObjNewHaig = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pObjNewHaig)), Ivy_IsComplement(pObjNewHaig) ); |
| // get regular pointers |
| pObjOldHaigR = Ivy_Regular(pObjOldHaig); |
| pObjNewHaigR = Ivy_Regular(pObjNewHaig); |
| // check if there is phase difference between them |
| fCompl = (Ivy_IsComplement(pObjOldHaig) != Ivy_IsComplement(pObjNewHaig)); |
| // if the class is the same, nothing to do |
| if ( pObjOldHaigR == pObjNewHaigR ) |
| return; |
| // if the second node belongs to a class, do not merge classes (for the time being) |
| if ( Ivy_ObjRefs(pObjOldHaigR) == 0 || pObjNewHaigR->pEquiv != NULL || |
| Ivy_ObjRefs(pObjNewHaigR) > 0 ) //|| Ivy_ObjIsInTfi_rec(pObjNewHaigR, pObjOldHaigR, 10) ) |
| { |
| /* |
| if ( pObjNewHaigR->pEquiv != NULL ) |
| printf( "c" ); |
| if ( Ivy_ObjRefs(pObjNewHaigR) > 0 ) |
| printf( "f" ); |
| printf( " " ); |
| */ |
| p->pHaig->nClassesSkip++; |
| return; |
| } |
| |
| // add this node to the class of pObjOldHaig |
| assert( Ivy_ObjRefs(pObjOldHaigR) > 0 ); |
| assert( !Ivy_IsComplement(pObjOldHaigR->pEquiv) ); |
| if ( pObjOldHaigR->pEquiv == NULL ) |
| pObjNewHaigR->pEquiv = Ivy_NotCond( pObjOldHaigR, fCompl ); |
| else |
| pObjNewHaigR->pEquiv = Ivy_NotCond( pObjOldHaigR->pEquiv, fCompl ); |
| pObjOldHaigR->pEquiv = pObjNewHaigR; |
| //printf( "Setting choice node %d -> %d.\n", pObjOldHaigR->Id, pObjNewHaigR->Id ); |
| // update the class of the new node |
| // Ivy_Regular(pObjNew)->pEquiv = Ivy_NotCond( pObjOldHaigR, fCompl ^ Ivy_IsComplement(pObjNew) ); |
| //printf( "Creating choice for %d and %d in HAIG\n", pObjOldHaigR->Id, pObjNewHaigR->Id ); |
| |
| // if ( pObjOldHaigR->Id == 13 ) |
| // { |
| // Ivy_ManShow( p, 0 ); |
| // Ivy_ManShow( p->pHaig, 1 ); |
| // } |
| // if ( !Ivy_ManIsAcyclic( p->pHaig ) ) |
| // printf( "HAIG contains a cycle\n" ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Count the number of choices and choice nodes in HAIG.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManHaigCountChoices( Ivy_Man_t * p, int * pnChoices ) |
| { |
| Ivy_Obj_t * pObj; |
| int nChoices, nChoiceNodes, Counter, i; |
| assert( p->pHaig != NULL ); |
| nChoices = nChoiceNodes = 0; |
| Ivy_ManForEachObj( p->pHaig, pObj, i ) |
| { |
| if ( Ivy_ObjIsTerm(pObj) || i == 0 ) |
| continue; |
| if ( Ivy_ObjRefs(pObj) == 0 ) |
| continue; |
| Counter = Ivy_HaigObjCountClass( pObj ); |
| nChoiceNodes += (int)(Counter > 1); |
| nChoices += Counter - 1; |
| // if ( Counter > 1 ) |
| // printf( "Choice node %d %s\n", pObj->Id, Ivy_ObjIsLatch(pObj)? "(latch)": "" ); |
| } |
| *pnChoices = nChoices; |
| return nChoiceNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints statistics of the HAIG.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManHaigPostprocess( Ivy_Man_t * p, int fVerbose ) |
| { |
| int nChoices, nChoiceNodes; |
| |
| assert( p->pHaig != NULL ); |
| |
| if ( fVerbose ) |
| { |
| printf( "Final : " ); |
| Ivy_ManPrintStats( p ); |
| printf( "HAIG : " ); |
| Ivy_ManPrintStats( p->pHaig ); |
| |
| // print choice node stats |
| nChoiceNodes = Ivy_ManHaigCountChoices( p, &nChoices ); |
| printf( "Total choice nodes = %d. Total choices = %d. Skipped classes = %d.\n", |
| nChoiceNodes, nChoices, p->pHaig->nClassesSkip ); |
| } |
| |
| if ( Ivy_ManIsAcyclic( p->pHaig ) ) |
| { |
| if ( fVerbose ) |
| printf( "HAIG is acyclic\n" ); |
| } |
| else |
| printf( "HAIG contains a cycle\n" ); |
| |
| // if ( fVerbose ) |
| // Ivy_ManHaigSimulate( p ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Applies the simulation rules.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline Ivy_Init_t Ivy_ManHaigSimulateAnd( Ivy_Init_t In0, Ivy_Init_t In1 ) |
| { |
| assert( In0 != IVY_INIT_NONE && In1 != IVY_INIT_NONE ); |
| if ( In0 == IVY_INIT_DC || In1 == IVY_INIT_DC ) |
| return IVY_INIT_DC; |
| if ( In0 == IVY_INIT_1 && In1 == IVY_INIT_1 ) |
| return IVY_INIT_1; |
| return IVY_INIT_0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Applies the simulation rules.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline Ivy_Init_t Ivy_ManHaigSimulateChoice( Ivy_Init_t In0, Ivy_Init_t In1 ) |
| { |
| assert( In0 != IVY_INIT_NONE && In1 != IVY_INIT_NONE ); |
| if ( (In0 == IVY_INIT_0 && In1 == IVY_INIT_1) || (In0 == IVY_INIT_1 && In1 == IVY_INIT_0) ) |
| { |
| printf( "Compatibility fails.\n" ); |
| return IVY_INIT_0; |
| } |
| if ( In0 == IVY_INIT_DC && In1 == IVY_INIT_DC ) |
| return IVY_INIT_DC; |
| if ( In0 != IVY_INIT_DC ) |
| return In0; |
| return In1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Simulate HAIG using modified 3-valued simulation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManHaigSimulate( Ivy_Man_t * p ) |
| { |
| Vec_Int_t * vNodes, * vLatches, * vLatchesD; |
| Ivy_Obj_t * pObj, * pTemp; |
| Ivy_Init_t In0, In1; |
| int i, k, Counter; |
| int fVerbose = 0; |
| |
| // check choices |
| Ivy_ManCheckChoices( p ); |
| |
| // switch to HAIG |
| assert( p->pHaig != NULL ); |
| p = p->pHaig; |
| |
| if ( fVerbose ) |
| Ivy_ManForEachPi( p, pObj, i ) |
| printf( "Setting PI %d\n", pObj->Id ); |
| |
| // collect latches and nodes in the DFS order |
| vNodes = Ivy_ManDfsSeq( p, &vLatches ); |
| |
| if ( fVerbose ) |
| Ivy_ManForEachNodeVec( p, vNodes, pObj, i ) |
| printf( "Collected node %d with fanins %d and %d\n", pObj->Id, Ivy_ObjFanin0(pObj)->Id, Ivy_ObjFanin1(pObj)->Id ); |
| |
| // set the PI values |
| Ivy_ManConst1(p)->Init = IVY_INIT_1; |
| Ivy_ManForEachPi( p, pObj, i ) |
| pObj->Init = IVY_INIT_0; |
| |
| // set the latch values |
| Ivy_ManForEachNodeVec( p, vLatches, pObj, i ) |
| pObj->Init = IVY_INIT_DC; |
| // set the latches of D to be determinate |
| vLatchesD = (Vec_Int_t *)p->pData; |
| Ivy_ManForEachNodeVec( p, vLatchesD, pObj, i ) |
| pObj->Init = IVY_INIT_0; |
| |
| // perform several rounds of simulation |
| for ( k = 0; k < 10; k++ ) |
| { |
| // count the number of non-determinate values |
| Counter = 0; |
| Ivy_ManForEachNodeVec( p, vLatches, pObj, i ) |
| Counter += ( pObj->Init == IVY_INIT_DC ); |
| printf( "Iter %d : Non-determinate = %d\n", k, Counter ); |
| |
| // simulate the internal nodes |
| Ivy_ManForEachNodeVec( p, vNodes, pObj, i ) |
| { |
| if ( fVerbose ) |
| printf( "Processing node %d with fanins %d and %d\n", pObj->Id, Ivy_ObjFanin0(pObj)->Id, Ivy_ObjFanin1(pObj)->Id ); |
| In0 = Ivy_InitNotCond( (Ivy_Init_t)Ivy_ObjFanin0(pObj)->Init, Ivy_ObjFaninC0(pObj) ); |
| In1 = Ivy_InitNotCond( (Ivy_Init_t)Ivy_ObjFanin1(pObj)->Init, Ivy_ObjFaninC1(pObj) ); |
| pObj->Init = Ivy_ManHaigSimulateAnd( In0, In1 ); |
| // simulate the equivalence class if the node is a representative |
| if ( pObj->pEquiv && Ivy_ObjRefs(pObj) > 0 ) |
| { |
| if ( fVerbose ) |
| printf( "Processing choice node %d\n", pObj->Id ); |
| In0 = (Ivy_Init_t)pObj->Init; |
| assert( !Ivy_IsComplement(pObj->pEquiv) ); |
| for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) ) |
| { |
| if ( fVerbose ) |
| printf( "Processing secondary node %d\n", pTemp->Id ); |
| In1 = Ivy_InitNotCond( (Ivy_Init_t)pTemp->Init, Ivy_IsComplement(pTemp->pEquiv) ); |
| In0 = Ivy_ManHaigSimulateChoice( In0, In1 ); |
| } |
| pObj->Init = In0; |
| } |
| } |
| |
| // simulate the latches |
| Ivy_ManForEachNodeVec( p, vLatches, pObj, i ) |
| { |
| pObj->Level = Ivy_ObjFanin0(pObj)->Init; |
| if ( fVerbose ) |
| printf( "Using latch %d with fanin %d\n", pObj->Id, Ivy_ObjFanin0(pObj)->Id ); |
| } |
| Ivy_ManForEachNodeVec( p, vLatches, pObj, i ) |
| pObj->Init = pObj->Level, pObj->Level = 0; |
| } |
| // free arrays |
| Vec_IntFree( vNodes ); |
| Vec_IntFree( vLatches ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |