mirror of https://github.com/YosysHQ/abc.git
602 lines
21 KiB
C
602 lines
21 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [cgtAig.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Clock gating package.]
|
|
|
|
Synopsis [Creates AIG to compute clock-gating.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: cgtAig.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "cgtInt.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes transitive fanout cone of the node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Cgt_ManDetectCandidates_rec( Aig_Man_t * pAig, Vec_Int_t * vUseful, Aig_Obj_t * pObj, int nLevelMax, Vec_Ptr_t * vCands )
|
|
{
|
|
if ( Aig_ObjIsTravIdCurrent(pAig, pObj) )
|
|
return;
|
|
Aig_ObjSetTravIdCurrent(pAig, pObj);
|
|
if ( Aig_ObjIsNode(pObj) )
|
|
{
|
|
Cgt_ManDetectCandidates_rec( pAig, vUseful, Aig_ObjFanin0(pObj), nLevelMax, vCands );
|
|
Cgt_ManDetectCandidates_rec( pAig, vUseful, Aig_ObjFanin1(pObj), nLevelMax, vCands );
|
|
}
|
|
if ( Aig_ObjLevel(pObj) <= nLevelMax && (vUseful == NULL || Vec_IntEntry(vUseful, Aig_ObjId(pObj))) )
|
|
Vec_PtrPush( vCands, pObj );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes transitive fanout cone of the node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Cgt_ManDetectCandidates( Aig_Man_t * pAig, Vec_Int_t * vUseful, Aig_Obj_t * pObj, int nLevelMax, Vec_Ptr_t * vCands )
|
|
{
|
|
Vec_PtrClear( vCands );
|
|
if ( !Aig_ObjIsNode(pObj) )
|
|
return;
|
|
Aig_ManIncrementTravId( pAig );
|
|
Cgt_ManDetectCandidates_rec( pAig, vUseful, pObj, nLevelMax, vCands );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes transitive fanout cone of the node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Cgt_ManDetectFanout_rec( Aig_Man_t * pAig, Aig_Obj_t * pObj, int nOdcMax, Vec_Ptr_t * vFanout )
|
|
{
|
|
Aig_Obj_t * pFanout;
|
|
int f, iFanout = -1;
|
|
if ( Aig_ObjIsCo(pObj) || Aig_ObjLevel(pObj) > nOdcMax )
|
|
return;
|
|
if ( Aig_ObjIsTravIdCurrent(pAig, pObj) )
|
|
return;
|
|
Aig_ObjSetTravIdCurrent(pAig, pObj);
|
|
Vec_PtrPush( vFanout, pObj );
|
|
Aig_ObjForEachFanout( pAig, pObj, pFanout, iFanout, f )
|
|
Cgt_ManDetectFanout_rec( pAig, pFanout, nOdcMax, vFanout );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes transitive fanout cone of the node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Cgt_ManDetectFanout( Aig_Man_t * pAig, Aig_Obj_t * pObj, int nOdcMax, Vec_Ptr_t * vFanout )
|
|
{
|
|
Aig_Obj_t * pFanout;
|
|
int i, k, f, iFanout = -1;
|
|
// collect visited nodes
|
|
Vec_PtrClear( vFanout );
|
|
Aig_ManIncrementTravId( pAig );
|
|
Cgt_ManDetectFanout_rec( pAig, pObj, nOdcMax, vFanout );
|
|
// remove those nodes whose fanout is included
|
|
k = 0;
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, vFanout, pObj, i )
|
|
{
|
|
// go through the fanouts of this node
|
|
Aig_ObjForEachFanout( pAig, pObj, pFanout, iFanout, f )
|
|
if ( !Aig_ObjIsTravIdCurrent(pAig, pFanout) )
|
|
break;
|
|
if ( f == Aig_ObjRefs(pObj) ) // all fanouts are included
|
|
continue;
|
|
Vec_PtrWriteEntry( vFanout, k++, pObj );
|
|
}
|
|
Vec_PtrShrink( vFanout, k );
|
|
Vec_PtrSort( vFanout, (int (*)(void))Aig_ObjCompareIdIncrease );
|
|
assert( Vec_PtrSize(vFanout) > 0 );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes visited nodes in the topological order.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Cgt_ManCollectVisited_rec( Aig_Man_t * pAig, Aig_Obj_t * pObj, Vec_Ptr_t * vVisited )
|
|
{
|
|
if ( Aig_ObjIsCi(pObj) )
|
|
return;
|
|
if ( Aig_ObjIsTravIdCurrent(pAig, pObj) )
|
|
return;
|
|
Aig_ObjSetTravIdCurrent(pAig, pObj);
|
|
assert( Aig_ObjIsNode(pObj) );
|
|
Cgt_ManCollectVisited_rec( pAig, Aig_ObjFanin0(pObj), vVisited );
|
|
Cgt_ManCollectVisited_rec( pAig, Aig_ObjFanin1(pObj), vVisited );
|
|
Vec_PtrPush( vVisited, pObj );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes visited nodes in the topological order.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Cgt_ManCollectVisited( Aig_Man_t * pAig, Vec_Ptr_t * vFanout, Vec_Ptr_t * vVisited )
|
|
{
|
|
Aig_Obj_t * pObj;
|
|
int i;
|
|
Vec_PtrClear( vVisited );
|
|
Aig_ManIncrementTravId( pAig );
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, vFanout, pObj, i )
|
|
Cgt_ManCollectVisited_rec( pAig, pObj, vVisited );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis []
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline Aig_Obj_t * Aig_ObjChild0CopyVec( Vec_Ptr_t * vCopy, Aig_Obj_t * pObj )
|
|
{ return Aig_NotCond((Aig_Obj_t *)Vec_PtrEntry(vCopy, Aig_ObjFaninId0(pObj)), Aig_ObjFaninC0(pObj)); }
|
|
static inline Aig_Obj_t * Aig_ObjChild1CopyVec( Vec_Ptr_t * vCopy, Aig_Obj_t * pObj )
|
|
{ return Aig_NotCond((Aig_Obj_t *)Vec_PtrEntry(vCopy, Aig_ObjFaninId1(pObj)), Aig_ObjFaninC1(pObj)); }
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Derives miter for clock-gating.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Obj_t * Cgt_ManConstructCareCondition( Cgt_Man_t * p, Aig_Man_t * pNew, Aig_Obj_t * pObjLo, Vec_Ptr_t * vCopy0, Vec_Ptr_t * vCopy1 )
|
|
{
|
|
Aig_Obj_t * pMiter, * pObj, * pTemp;
|
|
int i;
|
|
assert( Aig_ObjIsCi(pObjLo) );
|
|
// detect nodes and their cone
|
|
Cgt_ManDetectFanout( p->pAig, pObjLo, p->pPars->nOdcMax, p->vFanout );
|
|
Cgt_ManCollectVisited( p->pAig, p->vFanout, p->vVisited );
|
|
// add new variables if the observability condition depends on PI variables
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, p->vVisited, pObj, i )
|
|
{
|
|
assert( Aig_ObjIsNode(pObj) );
|
|
if ( Saig_ObjIsPi(p->pAig, Aig_ObjFanin0(pObj)) && Vec_PtrEntry(vCopy0, Aig_ObjFaninId0(pObj)) == NULL )
|
|
{
|
|
pTemp = Aig_ObjCreateCi( pNew );
|
|
Vec_PtrWriteEntry( vCopy0, Aig_ObjFaninId0(pObj), pTemp );
|
|
Vec_PtrWriteEntry( vCopy1, Aig_ObjFaninId0(pObj), pTemp );
|
|
}
|
|
if ( Saig_ObjIsPi(p->pAig, Aig_ObjFanin1(pObj)) && Vec_PtrEntry(vCopy0, Aig_ObjFaninId1(pObj)) == NULL )
|
|
{
|
|
pTemp = Aig_ObjCreateCi( pNew );
|
|
Vec_PtrWriteEntry( vCopy0, Aig_ObjFaninId1(pObj), pTemp );
|
|
Vec_PtrWriteEntry( vCopy1, Aig_ObjFaninId1(pObj), pTemp );
|
|
}
|
|
}
|
|
// construct AIGs for the nodes
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, p->vVisited, pObj, i )
|
|
{
|
|
pTemp = Aig_And( pNew, Aig_ObjChild0CopyVec(vCopy0, pObj), Aig_ObjChild1CopyVec(vCopy0, pObj) );
|
|
Vec_PtrWriteEntry( vCopy0, Aig_ObjId(pObj), pTemp );
|
|
pTemp = Aig_And( pNew, Aig_ObjChild0CopyVec(vCopy1, pObj), Aig_ObjChild1CopyVec(vCopy1, pObj) );
|
|
Vec_PtrWriteEntry( vCopy1, Aig_ObjId(pObj), pTemp );
|
|
}
|
|
// construct the care miter
|
|
pMiter = Aig_ManConst0( pNew );
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, p->vFanout, pObj, i )
|
|
{
|
|
pTemp = Aig_Exor( pNew, (Aig_Obj_t *)Vec_PtrEntry(vCopy0, Aig_ObjId(pObj)), (Aig_Obj_t *)Vec_PtrEntry(vCopy1, Aig_ObjId(pObj)) );
|
|
pMiter = Aig_Or( pNew, pMiter, pTemp );
|
|
}
|
|
return pMiter;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Derives AIG for clock-gating.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Man_t * Cgt_ManDeriveAigForGating( Cgt_Man_t * p )
|
|
{
|
|
Aig_Man_t * pNew;
|
|
Aig_Obj_t * pObj, * pObjLi, * pObjLo, * pCare, * pMiter;
|
|
Vec_Ptr_t * vCopy0, * vCopy1;
|
|
int i;
|
|
assert( Aig_ManRegNum(p->pAig) );
|
|
pNew = Aig_ManStart( Aig_ManObjNumMax(p->pAig) );
|
|
pNew->pName = Abc_UtilStrsav( "CG_miter" );
|
|
// build the first frame
|
|
Aig_ManConst1(p->pAig)->pData = Aig_ManConst1(pNew);
|
|
Aig_ManForEachCi( p->pAig, pObj, i )
|
|
pObj->pData = Aig_ObjCreateCi( pNew );
|
|
Aig_ManForEachNode( p->pAig, pObj, i )
|
|
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
|
|
// Saig_ManForEachPo( p->pAig, pObj, i )
|
|
// pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
|
|
if ( p->pPars->nOdcMax > 0 )
|
|
{
|
|
// create storage for observability conditions
|
|
vCopy0 = Vec_PtrStart( Aig_ManObjNumMax(p->pAig) );
|
|
vCopy1 = Vec_PtrStart( Aig_ManObjNumMax(p->pAig) );
|
|
// initialize register outputs
|
|
Saig_ManForEachLiLo( p->pAig, pObjLi, pObjLo, i )
|
|
{
|
|
Vec_PtrWriteEntry( vCopy0, Aig_ObjId(pObjLo), Aig_ObjChild0Copy(pObjLi) );
|
|
Vec_PtrWriteEntry( vCopy1, Aig_ObjId(pObjLo), Aig_ObjChild0Copy(pObjLi) );
|
|
}
|
|
// compute observability condition for each latch output
|
|
Saig_ManForEachLiLo( p->pAig, pObjLi, pObjLo, i )
|
|
{
|
|
// set the constants
|
|
Vec_PtrWriteEntry( vCopy0, Aig_ObjId(pObjLo), Aig_ManConst0(pNew) );
|
|
Vec_PtrWriteEntry( vCopy1, Aig_ObjId(pObjLo), Aig_ManConst1(pNew) );
|
|
// compute condition
|
|
pCare = Cgt_ManConstructCareCondition( p, pNew, pObjLo, vCopy0, vCopy1 );
|
|
// restore the values
|
|
Vec_PtrWriteEntry( vCopy0, Aig_ObjId(pObjLo), Aig_ObjChild0Copy(pObjLi) );
|
|
Vec_PtrWriteEntry( vCopy1, Aig_ObjId(pObjLo), Aig_ObjChild0Copy(pObjLi) );
|
|
// compute the miter
|
|
pMiter = Aig_Exor( pNew, (Aig_Obj_t *)pObjLo->pData, Aig_ObjChild0Copy(pObjLi) );
|
|
pMiter = Aig_And( pNew, pMiter, pCare );
|
|
pObjLi->pData = Aig_ObjCreateCo( pNew, pMiter );
|
|
}
|
|
Vec_PtrFree( vCopy0 );
|
|
Vec_PtrFree( vCopy1 );
|
|
}
|
|
else
|
|
{
|
|
// construct clock-gating miters for each register input
|
|
Saig_ManForEachLiLo( p->pAig, pObjLi, pObjLo, i )
|
|
{
|
|
pMiter = Aig_Exor( pNew, (Aig_Obj_t *)pObjLo->pData, Aig_ObjChild0Copy(pObjLi) );
|
|
pObjLi->pData = Aig_ObjCreateCo( pNew, pMiter );
|
|
}
|
|
}
|
|
Aig_ManCleanup( pNew );
|
|
Aig_ManSetCioIds( pNew );
|
|
return pNew;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Adds relevant constraints.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Obj_t * Cgt_ManConstructCare_rec( Aig_Man_t * pCare, Aig_Obj_t * pObj, Aig_Man_t * pNew )
|
|
{
|
|
Aig_Obj_t * pObj0, * pObj1;
|
|
if ( Aig_ObjIsTravIdCurrent( pCare, pObj ) )
|
|
return (Aig_Obj_t *)pObj->pData;
|
|
Aig_ObjSetTravIdCurrent( pCare, pObj );
|
|
if ( Aig_ObjIsCi(pObj) )
|
|
return (Aig_Obj_t *)(pObj->pData = NULL);
|
|
pObj0 = Cgt_ManConstructCare_rec( pCare, Aig_ObjFanin0(pObj), pNew );
|
|
if ( pObj0 == NULL )
|
|
return (Aig_Obj_t *)(pObj->pData = NULL);
|
|
pObj1 = Cgt_ManConstructCare_rec( pCare, Aig_ObjFanin1(pObj), pNew );
|
|
if ( pObj1 == NULL )
|
|
return (Aig_Obj_t *)(pObj->pData = NULL);
|
|
pObj0 = Aig_NotCond( pObj0, Aig_ObjFaninC0(pObj) );
|
|
pObj1 = Aig_NotCond( pObj1, Aig_ObjFaninC1(pObj) );
|
|
return (Aig_Obj_t *)(pObj->pData = Aig_And( pNew, pObj0, pObj1 ));
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Builds constraints belonging to the given partition.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Cgt_ManConstructCare( Aig_Man_t * pNew, Aig_Man_t * pCare, Vec_Vec_t * vSuppsInv, Vec_Ptr_t * vLeaves )
|
|
{
|
|
Vec_Int_t * vOuts;
|
|
Aig_Obj_t * pLeaf, * pPi, * pPo, * pObjAig;
|
|
int i, k, iOut;
|
|
// go through the PIs of the partition
|
|
// label the corresponding PIs of the care set
|
|
Aig_ManIncrementTravId( pCare );
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, vLeaves, pLeaf, i )
|
|
{
|
|
pPi = Aig_ManCi( pCare, Aig_ObjCioId(pLeaf) );
|
|
Aig_ObjSetTravIdCurrent( pCare, pPi );
|
|
pPi->pData = pLeaf->pData;
|
|
}
|
|
// construct the constraints
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, vLeaves, pLeaf, i )
|
|
{
|
|
vOuts = Vec_VecEntryInt( vSuppsInv, Aig_ObjCioId(pLeaf) );
|
|
Vec_IntForEachEntry( vOuts, iOut, k )
|
|
{
|
|
pPo = Aig_ManCo( pCare, iOut );
|
|
if ( Aig_ObjIsTravIdCurrent( pCare, pPo ) )
|
|
continue;
|
|
Aig_ObjSetTravIdCurrent( pCare, pPo );
|
|
if ( Aig_ObjFanin0(pPo) == Aig_ManConst1(pCare) )
|
|
continue;
|
|
pObjAig = Cgt_ManConstructCare_rec( pCare, Aig_ObjFanin0(pPo), pNew );
|
|
if ( pObjAig == NULL )
|
|
continue;
|
|
pObjAig = Aig_NotCond( pObjAig, Aig_ObjFaninC0(pPo) );
|
|
Aig_ObjCreateCo( pNew, pObjAig );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Duplicates the AIG recursively.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Obj_t * Cgt_ManDupPartition_rec( Aig_Man_t * pNew, Aig_Man_t * pAig, Aig_Obj_t * pObj, Vec_Ptr_t * vLeaves )
|
|
{
|
|
if ( Aig_ObjIsTravIdCurrent(pAig, pObj) )
|
|
return (Aig_Obj_t *)pObj->pData;
|
|
Aig_ObjSetTravIdCurrent(pAig, pObj);
|
|
if ( Aig_ObjIsCi(pObj) )
|
|
{
|
|
pObj->pData = Aig_ObjCreateCi( pNew );
|
|
Vec_PtrPush( vLeaves, pObj );
|
|
return (Aig_Obj_t *)pObj->pData;
|
|
}
|
|
Cgt_ManDupPartition_rec( pNew, pAig, Aig_ObjFanin0(pObj), vLeaves );
|
|
Cgt_ManDupPartition_rec( pNew, pAig, Aig_ObjFanin1(pObj), vLeaves );
|
|
return (Aig_Obj_t *)(pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) ));
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Duplicates register outputs starting from the given one.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Man_t * Cgt_ManDupPartition( Aig_Man_t * pFrame, int nVarsMin, int nFlopsMin, int iStart, Aig_Man_t * pCare, Vec_Vec_t * vSuppsInv, int * pnOutputs )
|
|
{
|
|
Vec_Ptr_t * vRoots, * vLeaves, * vPos;
|
|
Aig_Man_t * pNew;
|
|
Aig_Obj_t * pObj;
|
|
int i;
|
|
assert( Aig_ManRegNum(pFrame) == 0 );
|
|
vRoots = Vec_PtrAlloc( 100 );
|
|
vLeaves = Vec_PtrAlloc( 100 );
|
|
vPos = Vec_PtrAlloc( 100 );
|
|
pNew = Aig_ManStart( nVarsMin );
|
|
pNew->pName = Abc_UtilStrsav( "partition" );
|
|
Aig_ManIncrementTravId( pFrame );
|
|
Aig_ManConst1(pFrame)->pData = Aig_ManConst1(pNew);
|
|
Aig_ObjSetTravIdCurrent( pFrame, Aig_ManConst1(pFrame) );
|
|
for ( i = iStart; i < iStart + nFlopsMin && i < Aig_ManCoNum(pFrame); i++ )
|
|
{
|
|
pObj = Aig_ManCo( pFrame, i );
|
|
Cgt_ManDupPartition_rec( pNew, pFrame, Aig_ObjFanin0(pObj), vLeaves );
|
|
Vec_PtrPush( vRoots, Aig_ObjChild0Copy(pObj) );
|
|
Vec_PtrPush( vPos, pObj );
|
|
}
|
|
for ( ; Aig_ManObjNum(pNew) < nVarsMin && i < Aig_ManCoNum(pFrame); i++ )
|
|
{
|
|
pObj = Aig_ManCo( pFrame, i );
|
|
Cgt_ManDupPartition_rec( pNew, pFrame, Aig_ObjFanin0(pObj), vLeaves );
|
|
Vec_PtrPush( vRoots, Aig_ObjChild0Copy(pObj) );
|
|
Vec_PtrPush( vPos, pObj );
|
|
}
|
|
assert( nFlopsMin >= Vec_PtrSize(vRoots) || Vec_PtrSize(vRoots) >= nFlopsMin );
|
|
// create constaints
|
|
if ( pCare )
|
|
Cgt_ManConstructCare( pNew, pCare, vSuppsInv, vLeaves );
|
|
// create POs
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, vPos, pObj, i )
|
|
pObj->pData = (Aig_Obj_t *)Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Vec_PtrEntry(vRoots, i) );
|
|
if ( pnOutputs != NULL )
|
|
*pnOutputs = Vec_PtrSize( vPos );
|
|
Vec_PtrFree( vRoots );
|
|
Vec_PtrFree( vLeaves );
|
|
Vec_PtrFree( vPos );
|
|
return pNew;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Implements one clock-gate.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Obj_t * Cgt_ManBuildClockGate( Aig_Man_t * pNew, Vec_Ptr_t * vGates )
|
|
{
|
|
Aig_Obj_t * pGate, * pTotal;
|
|
int i;
|
|
assert( Vec_PtrSize(vGates) > 0 );
|
|
pTotal = Aig_ManConst0(pNew);
|
|
Vec_PtrForEachEntry( Aig_Obj_t *, vGates, pGate, i )
|
|
{
|
|
if ( Aig_Regular(pGate)->pNext )
|
|
pGate = Aig_NotCond( Aig_Regular(pGate)->pNext, Aig_IsComplement(pGate) );
|
|
else
|
|
pGate = Aig_NotCond( (Aig_Obj_t *)Aig_Regular(pGate)->pData, Aig_IsComplement(pGate) );
|
|
pTotal = Aig_Or( pNew, pTotal, pGate );
|
|
}
|
|
return pTotal;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Derives AIG after clock-gating.]
|
|
|
|
Description [The array contains, for each flop, its gate if present.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Man_t * Cgt_ManDeriveGatedAig( Aig_Man_t * pAig, Vec_Vec_t * vGates, int fReduce, int * pnUsedNodes )
|
|
{
|
|
Aig_Man_t * pNew;
|
|
Aig_Obj_t * pObj, * pObjNew, * pObjLi, * pObjLo, * pGateNew;
|
|
Vec_Ptr_t * vOne;
|
|
int i, k;
|
|
Aig_ManCleanNext( pAig );
|
|
// label nodes
|
|
Vec_VecForEachEntry( Aig_Obj_t *, vGates, pObj, i, k )
|
|
{
|
|
if ( Aig_IsComplement(pObj) )
|
|
Aig_Regular(pObj)->fMarkB = 1;
|
|
else
|
|
Aig_Regular(pObj)->fMarkA = 1;
|
|
}
|
|
// construct AIG
|
|
assert( Aig_ManRegNum(pAig) );
|
|
pNew = Aig_ManStart( Aig_ManObjNumMax(pAig) );
|
|
pNew->pName = Abc_UtilStrsav( pAig->pName );
|
|
pNew->pSpec = Abc_UtilStrsav( pAig->pSpec );
|
|
Aig_ManConst1(pAig)->pData = Aig_ManConst1(pNew);
|
|
Aig_ManForEachCi( pAig, pObj, i )
|
|
pObj->pData = Aig_ObjCreateCi( pNew );
|
|
if ( fReduce )
|
|
{
|
|
Aig_ManForEachNode( pAig, pObj, i )
|
|
{
|
|
assert( !(pObj->fMarkA && pObj->fMarkB) );
|
|
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
|
|
if ( pObj->fMarkA )
|
|
{
|
|
pObj->pNext = (Aig_Obj_t *)pObj->pData;
|
|
pObj->pData = Aig_ManConst0(pNew);
|
|
}
|
|
else if ( pObj->fMarkB )
|
|
{
|
|
pObj->pNext = (Aig_Obj_t *)pObj->pData;
|
|
pObj->pData = Aig_ManConst1(pNew);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Aig_ManForEachNode( pAig, pObj, i )
|
|
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
|
|
}
|
|
if ( pnUsedNodes != NULL )
|
|
*pnUsedNodes = Aig_ManNodeNum(pNew);
|
|
Saig_ManForEachPo( pAig, pObj, i )
|
|
pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
|
|
Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i )
|
|
{
|
|
vOne = Vec_VecEntry( vGates, i );
|
|
if ( Vec_PtrSize(vOne) == 0 )
|
|
pObjNew = Aig_ObjChild0Copy(pObjLi);
|
|
else
|
|
{
|
|
// pGateNew = Aig_NotCond( Aig_Regular(pGate)->pData, Aig_IsComplement(pGate) );
|
|
pGateNew = Cgt_ManBuildClockGate( pNew, vOne );
|
|
pObjNew = Aig_Mux( pNew, pGateNew, (Aig_Obj_t *)pObjLo->pData, Aig_ObjChild0Copy(pObjLi) );
|
|
}
|
|
pObjLi->pData = Aig_ObjCreateCo( pNew, pObjNew );
|
|
}
|
|
Aig_ManCleanup( pNew );
|
|
Aig_ManSetRegNum( pNew, Aig_ManRegNum(pAig) );
|
|
// unlabel nodes
|
|
Aig_ManCleanMarkAB( pAig );
|
|
Aig_ManCleanNext( pAig );
|
|
return pNew;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|