| /**CFile**************************************************************** |
| |
| FileName [ivyMan.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [And-Inverter Graph package.] |
| |
| Synopsis [AIG manager.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - May 11, 2006.] |
| |
| Revision [$Id: ivy_.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "ivy.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts the AIG manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Ivy_Man_t * Ivy_ManStart() |
| { |
| Ivy_Man_t * p; |
| // start the manager |
| p = ABC_ALLOC( Ivy_Man_t, 1 ); |
| memset( p, 0, sizeof(Ivy_Man_t) ); |
| // perform initializations |
| p->Ghost.Id = -1; |
| p->nTravIds = 1; |
| p->fCatchExor = 1; |
| // allocate arrays for nodes |
| p->vPis = Vec_PtrAlloc( 100 ); |
| p->vPos = Vec_PtrAlloc( 100 ); |
| p->vBufs = Vec_PtrAlloc( 100 ); |
| p->vObjs = Vec_PtrAlloc( 100 ); |
| // prepare the internal memory manager |
| Ivy_ManStartMemory( p ); |
| // create the constant node |
| p->pConst1 = Ivy_ManFetchMemory( p ); |
| p->pConst1->fPhase = 1; |
| Vec_PtrPush( p->vObjs, p->pConst1 ); |
| p->nCreated = 1; |
| // start the table |
| p->nTableSize = 10007; |
| p->pTable = ABC_ALLOC( int, p->nTableSize ); |
| memset( p->pTable, 0, sizeof(int) * p->nTableSize ); |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Duplicates the AIG manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Ivy_Man_t * Ivy_ManStartFrom( Ivy_Man_t * p ) |
| { |
| Ivy_Man_t * pNew; |
| Ivy_Obj_t * pObj; |
| int i; |
| // create the new manager |
| pNew = Ivy_ManStart(); |
| // create the PIs |
| Ivy_ManConst1(p)->pEquiv = Ivy_ManConst1(pNew); |
| Ivy_ManForEachPi( p, pObj, i ) |
| pObj->pEquiv = Ivy_ObjCreatePi(pNew); |
| return pNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Duplicates the AIG manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Ivy_Man_t * Ivy_ManDup( Ivy_Man_t * p ) |
| { |
| Vec_Int_t * vNodes, * vLatches; |
| Ivy_Man_t * pNew; |
| Ivy_Obj_t * pObj; |
| int i; |
| // collect latches and nodes in the DFS order |
| vNodes = Ivy_ManDfsSeq( p, &vLatches ); |
| // create the new manager |
| pNew = Ivy_ManStart(); |
| // create the PIs |
| Ivy_ManConst1(p)->pEquiv = Ivy_ManConst1(pNew); |
| Ivy_ManForEachPi( p, pObj, i ) |
| pObj->pEquiv = Ivy_ObjCreatePi(pNew); |
| // create the fake PIs for latches |
| Ivy_ManForEachNodeVec( p, vLatches, pObj, i ) |
| pObj->pEquiv = Ivy_ObjCreatePi(pNew); |
| // duplicate internal nodes |
| Ivy_ManForEachNodeVec( p, vNodes, pObj, i ) |
| if ( Ivy_ObjIsBuf(pObj) ) |
| pObj->pEquiv = Ivy_ObjChild0Equiv(pObj); |
| else |
| pObj->pEquiv = Ivy_And( pNew, Ivy_ObjChild0Equiv(pObj), Ivy_ObjChild1Equiv(pObj) ); |
| // add the POs |
| Ivy_ManForEachPo( p, pObj, i ) |
| Ivy_ObjCreatePo( pNew, Ivy_ObjChild0Equiv(pObj) ); |
| // transform additional PI nodes into latches and connect them |
| Ivy_ManForEachNodeVec( p, vLatches, pObj, i ) |
| { |
| assert( !Ivy_ObjFaninC0(pObj) ); |
| pObj->pEquiv->Type = IVY_LATCH; |
| pObj->pEquiv->Init = pObj->Init; |
| Ivy_ObjConnect( pNew, pObj->pEquiv, Ivy_ObjChild0Equiv(pObj), NULL ); |
| } |
| // shrink the arrays |
| Vec_PtrShrink( pNew->vPis, Ivy_ManPiNum(p) ); |
| // update the counters of different objects |
| pNew->nObjs[IVY_PI] -= Ivy_ManLatchNum(p); |
| pNew->nObjs[IVY_LATCH] += Ivy_ManLatchNum(p); |
| // free arrays |
| Vec_IntFree( vNodes ); |
| Vec_IntFree( vLatches ); |
| // make sure structural hashing did not change anything |
| assert( Ivy_ManNodeNum(p) == Ivy_ManNodeNum(pNew) ); |
| assert( Ivy_ManLatchNum(p) == Ivy_ManLatchNum(pNew) ); |
| // check the resulting network |
| if ( !Ivy_ManCheck(pNew) ) |
| printf( "Ivy_ManMakeSeq(): The check has failed.\n" ); |
| return pNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Stops the AIG manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Ivy_Man_t * Ivy_ManFrames( Ivy_Man_t * pMan, int nLatches, int nFrames, int fInit, Vec_Ptr_t ** pvMapping ) |
| { |
| Vec_Ptr_t * vMapping; |
| Ivy_Man_t * pNew; |
| Ivy_Obj_t * pObj; |
| int i, f, nPis, nPos, nIdMax; |
| assert( Ivy_ManLatchNum(pMan) == 0 ); |
| assert( nFrames > 0 ); |
| // prepare the mapping |
| nPis = Ivy_ManPiNum(pMan) - nLatches; |
| nPos = Ivy_ManPoNum(pMan) - nLatches; |
| nIdMax = Ivy_ManObjIdMax(pMan); |
| // create the new manager |
| pNew = Ivy_ManStart(); |
| // set the starting values of latch inputs |
| for ( i = 0; i < nLatches; i++ ) |
| Ivy_ManPo(pMan, nPos+i)->pEquiv = fInit? Ivy_Not(Ivy_ManConst1(pNew)) : Ivy_ObjCreatePi(pNew); |
| // add timeframes |
| vMapping = Vec_PtrStart( nIdMax * nFrames + 1 ); |
| for ( f = 0; f < nFrames; f++ ) |
| { |
| // create PIs |
| Ivy_ManConst1(pMan)->pEquiv = Ivy_ManConst1(pNew); |
| for ( i = 0; i < nPis; i++ ) |
| Ivy_ManPi(pMan, i)->pEquiv = Ivy_ObjCreatePi(pNew); |
| // transfer values to latch outputs |
| for ( i = 0; i < nLatches; i++ ) |
| Ivy_ManPi(pMan, nPis+i)->pEquiv = Ivy_ManPo(pMan, nPos+i)->pEquiv; |
| // perform strashing |
| Ivy_ManForEachNode( pMan, pObj, i ) |
| pObj->pEquiv = Ivy_And( pNew, Ivy_ObjChild0Equiv(pObj), Ivy_ObjChild1Equiv(pObj) ); |
| // create POs |
| for ( i = 0; i < nPos; i++ ) |
| Ivy_ManPo(pMan, i)->pEquiv = Ivy_ObjCreatePo( pNew, Ivy_ObjChild0Equiv(Ivy_ManPo(pMan, i)) ); |
| // set the results of latch inputs |
| for ( i = 0; i < nLatches; i++ ) |
| Ivy_ManPo(pMan, nPos+i)->pEquiv = Ivy_ObjChild0Equiv(Ivy_ManPo(pMan, nPos+i)); |
| // save the pointers in this frame |
| Ivy_ManForEachObj( pMan, pObj, i ) |
| Vec_PtrWriteEntry( vMapping, f * nIdMax + i, pObj->pEquiv ); |
| } |
| // connect latches |
| if ( !fInit ) |
| for ( i = 0; i < nLatches; i++ ) |
| Ivy_ObjCreatePo( pNew, Ivy_ManPo(pMan, nPos+i)->pEquiv ); |
| // remove dangling nodes |
| Ivy_ManCleanup(pNew); |
| *pvMapping = vMapping; |
| // check the resulting network |
| if ( !Ivy_ManCheck(pNew) ) |
| printf( "Ivy_ManFrames(): The check has failed.\n" ); |
| return pNew; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Stops the AIG manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManStop( Ivy_Man_t * p ) |
| { |
| if ( p->time1 ) { ABC_PRT( "Update lev ", p->time1 ); } |
| if ( p->time2 ) { ABC_PRT( "Update levR ", p->time2 ); } |
| // Ivy_TableProfile( p ); |
| // if ( p->vFanouts ) Ivy_ManStopFanout( p ); |
| if ( p->vChunks ) Ivy_ManStopMemory( p ); |
| if ( p->vRequired ) Vec_IntFree( p->vRequired ); |
| if ( p->vPis ) Vec_PtrFree( p->vPis ); |
| if ( p->vPos ) Vec_PtrFree( p->vPos ); |
| if ( p->vBufs ) Vec_PtrFree( p->vBufs ); |
| if ( p->vObjs ) Vec_PtrFree( p->vObjs ); |
| ABC_FREE( p->pTable ); |
| ABC_FREE( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Removes nodes without fanout.] |
| |
| Description [Returns the number of dangling nodes removed.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManCleanup( Ivy_Man_t * p ) |
| { |
| Ivy_Obj_t * pNode; |
| int i, nNodesOld; |
| nNodesOld = Ivy_ManNodeNum(p); |
| Ivy_ManForEachObj( p, pNode, i ) |
| if ( Ivy_ObjIsNode(pNode) || Ivy_ObjIsLatch(pNode) || Ivy_ObjIsBuf(pNode) ) |
| if ( Ivy_ObjRefs(pNode) == 0 ) |
| Ivy_ObjDelete_rec( p, pNode, 1 ); |
| //printf( "Cleanup removed %d nodes.\n", nNodesOld - Ivy_ManNodeNum(p) ); |
| return nNodesOld - Ivy_ManNodeNum(p); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Marks nodes reachable from the given one.] |
| |
| Description [Returns the number of dangling nodes removed.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManCleanupSeq_rec( Ivy_Obj_t * pObj ) |
| { |
| if ( Ivy_ObjIsMarkA(pObj) ) |
| return; |
| Ivy_ObjSetMarkA(pObj); |
| if ( pObj->pFanin0 != NULL ) |
| Ivy_ManCleanupSeq_rec( Ivy_ObjFanin0(pObj) ); |
| if ( pObj->pFanin1 != NULL ) |
| Ivy_ManCleanupSeq_rec( Ivy_ObjFanin1(pObj) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Removes logic that does not feed into POs.] |
| |
| Description [Returns the number of dangling nodes removed.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManCleanupSeq( Ivy_Man_t * p ) |
| { |
| Vec_Ptr_t * vNodes; |
| Ivy_Obj_t * pObj; |
| int i, RetValue; |
| // mark the constant and PIs |
| Ivy_ObjSetMarkA( Ivy_ManConst1(p) ); |
| Ivy_ManForEachPi( p, pObj, i ) |
| Ivy_ObjSetMarkA( pObj ); |
| // mark nodes visited from POs |
| Ivy_ManForEachPo( p, pObj, i ) |
| Ivy_ManCleanupSeq_rec( pObj ); |
| // collect unmarked nodes |
| vNodes = Vec_PtrAlloc( 100 ); |
| Ivy_ManForEachObj( p, pObj, i ) |
| { |
| if ( Ivy_ObjIsMarkA(pObj) ) |
| Ivy_ObjClearMarkA(pObj); |
| else |
| Vec_PtrPush( vNodes, pObj ); |
| } |
| if ( Vec_PtrSize(vNodes) == 0 ) |
| { |
| Vec_PtrFree( vNodes ); |
| //printf( "Sequential sweep cleaned out %d nodes.\n", 0 ); |
| return 0; |
| } |
| // disconnect the marked objects |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vNodes, pObj, i ) |
| Ivy_ObjDisconnect( p, pObj ); |
| // remove the dangling objects |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vNodes, pObj, i ) |
| { |
| assert( Ivy_ObjIsNode(pObj) || Ivy_ObjIsLatch(pObj) || Ivy_ObjIsBuf(pObj) ); |
| assert( Ivy_ObjRefs(pObj) == 0 ); |
| // update node counters of the manager |
| p->nObjs[pObj->Type]--; |
| p->nDeleted++; |
| // delete buffer from the array of buffers |
| if ( p->fFanout && Ivy_ObjIsBuf(pObj) ) |
| Vec_PtrRemove( p->vBufs, pObj ); |
| // free the node |
| Vec_PtrWriteEntry( p->vObjs, pObj->Id, NULL ); |
| Ivy_ManRecycleMemory( p, pObj ); |
| } |
| // return the number of nodes freed |
| RetValue = Vec_PtrSize(vNodes); |
| Vec_PtrFree( vNodes ); |
| //printf( "Sequential sweep cleaned out %d nodes.\n", RetValue ); |
| return RetValue; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if latches form self-loop.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManLatchIsSelfFeed_rec( Ivy_Obj_t * pLatch, Ivy_Obj_t * pLatchRoot ) |
| { |
| if ( !Ivy_ObjIsLatch(pLatch) && !Ivy_ObjIsBuf(pLatch) ) |
| return 0; |
| if ( pLatch == pLatchRoot ) |
| return 1; |
| return Ivy_ManLatchIsSelfFeed_rec( Ivy_ObjFanin0(pLatch), pLatchRoot ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if latches form self-loop.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManLatchIsSelfFeed( Ivy_Obj_t * pLatch ) |
| { |
| if ( !Ivy_ObjIsLatch(pLatch) ) |
| return 0; |
| return Ivy_ManLatchIsSelfFeed_rec( Ivy_ObjFanin0(pLatch), pLatch ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the number of dangling nodes removed.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManPropagateBuffers( Ivy_Man_t * p, int fUpdateLevel ) |
| { |
| Ivy_Obj_t * pNode; |
| int LimitFactor = 100; |
| int NodeBeg = Ivy_ManNodeNum(p); |
| int nSteps; |
| for ( nSteps = 0; Vec_PtrSize(p->vBufs) > 0; nSteps++ ) |
| { |
| pNode = (Ivy_Obj_t *)Vec_PtrEntryLast(p->vBufs); |
| while ( Ivy_ObjIsBuf(pNode) ) |
| pNode = Ivy_ObjReadFirstFanout( p, pNode ); |
| // check if this buffer should remain |
| if ( Ivy_ManLatchIsSelfFeed(pNode) ) |
| { |
| Vec_PtrPop(p->vBufs); |
| continue; |
| } |
| //printf( "Propagating buffer %d with input %d and output %d\n", Ivy_ObjFaninId0(pNode), Ivy_ObjFaninId0(Ivy_ObjFanin0(pNode)), pNode->Id ); |
| //printf( "Latch num %d\n", Ivy_ManLatchNum(p) ); |
| Ivy_NodeFixBufferFanins( p, pNode, fUpdateLevel ); |
| if ( nSteps > NodeBeg * LimitFactor ) |
| { |
| printf( "Structural hashing is not finished after %d forward latch moves.\n", NodeBeg * LimitFactor ); |
| printf( "This circuit cannot be forward-retimed completely. Quitting.\n" ); |
| break; |
| } |
| } |
| // printf( "Number of steps = %d. Nodes beg = %d. Nodes end = %d.\n", nSteps, NodeBeg, Ivy_ManNodeNum(p) ); |
| return nSteps; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Stops the AIG manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManPrintStats( Ivy_Man_t * p ) |
| { |
| printf( "PI/PO = %d/%d ", Ivy_ManPiNum(p), Ivy_ManPoNum(p) ); |
| printf( "A = %7d. ", Ivy_ManAndNum(p) ); |
| printf( "L = %5d. ", Ivy_ManLatchNum(p) ); |
| // printf( "X = %d. ", Ivy_ManExorNum(p) ); |
| // printf( "B = %3d. ", Ivy_ManBufNum(p) ); |
| printf( "MaxID = %7d. ", Ivy_ManObjIdMax(p) ); |
| // printf( "Cre = %d. ", p->nCreated ); |
| // printf( "Del = %d. ", p->nDeleted ); |
| printf( "Lev = %3d. ", Ivy_ManLatchNum(p)? -1 : Ivy_ManLevels(p) ); |
| printf( "\n" ); |
| fflush( stdout ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Converts a combinational AIG manager into a sequential one.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManMakeSeq( Ivy_Man_t * p, int nLatches, int * pInits ) |
| { |
| Ivy_Obj_t * pObj, * pLatch; |
| Ivy_Init_t Init; |
| int i; |
| if ( nLatches == 0 ) |
| return; |
| assert( nLatches < Ivy_ManPiNum(p) && nLatches < Ivy_ManPoNum(p) ); |
| assert( Ivy_ManPiNum(p) == Vec_PtrSize(p->vPis) ); |
| assert( Ivy_ManPoNum(p) == Vec_PtrSize(p->vPos) ); |
| assert( Vec_PtrSize( p->vBufs ) == 0 ); |
| // create fanouts |
| if ( p->fFanout == 0 ) |
| Ivy_ManStartFanout( p ); |
| // collect the POs to be converted into latches |
| for ( i = 0; i < nLatches; i++ ) |
| { |
| // get the latch value |
| Init = pInits? (Ivy_Init_t)pInits[i] : IVY_INIT_0; |
| // create latch |
| pObj = Ivy_ManPo( p, Ivy_ManPoNum(p) - nLatches + i ); |
| pLatch = Ivy_Latch( p, Ivy_ObjChild0(pObj), Init ); |
| Ivy_ObjDisconnect( p, pObj ); |
| // recycle the old PO object |
| Vec_PtrWriteEntry( p->vObjs, pObj->Id, NULL ); |
| Ivy_ManRecycleMemory( p, pObj ); |
| // convert the corresponding PI to a buffer and connect it to the latch |
| pObj = Ivy_ManPi( p, Ivy_ManPiNum(p) - nLatches + i ); |
| pObj->Type = IVY_BUF; |
| Ivy_ObjConnect( p, pObj, pLatch, NULL ); |
| // save the buffer |
| Vec_PtrPush( p->vBufs, pObj ); |
| } |
| // shrink the arrays |
| Vec_PtrShrink( p->vPis, Ivy_ManPiNum(p) - nLatches ); |
| Vec_PtrShrink( p->vPos, Ivy_ManPoNum(p) - nLatches ); |
| // update the counters of different objects |
| p->nObjs[IVY_PI] -= nLatches; |
| p->nObjs[IVY_PO] -= nLatches; |
| p->nObjs[IVY_BUF] += nLatches; |
| p->nDeleted -= 2 * nLatches; |
| // remove dangling nodes |
| Ivy_ManCleanup(p); |
| Ivy_ManCleanupSeq(p); |
| /* |
| // check for dangling nodes |
| Ivy_ManForEachObj( p, pObj, i ) |
| if ( !Ivy_ObjIsPi(pObj) && !Ivy_ObjIsPo(pObj) && !Ivy_ObjIsConst1(pObj) ) |
| { |
| assert( Ivy_ObjRefs(pObj) > 0 ); |
| assert( Ivy_ObjRefs(pObj) == Ivy_ObjFanoutNum(p, pObj) ); |
| } |
| */ |
| // perform hashing by propagating the buffers |
| Ivy_ManPropagateBuffers( p, 0 ); |
| if ( Ivy_ManBufNum(p) ) |
| printf( "The number of remaining buffers is %d.\n", Ivy_ManBufNum(p) ); |
| // fix the levels |
| Ivy_ManResetLevels( p ); |
| // check the resulting network |
| if ( !Ivy_ManCheck(p) ) |
| printf( "Ivy_ManMakeSeq(): The check has failed.\n" ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |