blob: 6fa34144c9200b93b4167a65c5c32f54810edd52 [file] [log] [blame]
/**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