blob: fcace105176aa848ca0c32aed2c1b0eadeb55006 [file] [log] [blame]
/**CFile****************************************************************
FileName [abcLatch.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Network and node package.]
Synopsis [Procedures working with latches.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: abcLatch.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "abc.h"
#ifdef ABC_USE_CUDD
#include "bdd/extrab/extraBdd.h"
#endif
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Checks if latches form self-loop.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkLatchIsSelfFeed_rec( Abc_Obj_t * pLatch, Abc_Obj_t * pLatchRoot )
{
Abc_Obj_t * pFanin;
assert( Abc_ObjIsLatch(pLatch) );
if ( pLatch == pLatchRoot )
return 1;
pFanin = Abc_ObjFanin0(Abc_ObjFanin0(pLatch));
if ( !Abc_ObjIsBo(pFanin) || !Abc_ObjIsLatch(Abc_ObjFanin0(pFanin)) )
return 0;
return Abc_NtkLatchIsSelfFeed_rec( Abc_ObjFanin0(pFanin), pLatch );
}
/**Function*************************************************************
Synopsis [Checks if latches form self-loop.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkLatchIsSelfFeed( Abc_Obj_t * pLatch )
{
Abc_Obj_t * pFanin;
assert( Abc_ObjIsLatch(pLatch) );
pFanin = Abc_ObjFanin0(Abc_ObjFanin0(pLatch));
if ( !Abc_ObjIsBo(pFanin) || !Abc_ObjIsLatch(Abc_ObjFanin0(pFanin)) )
return 0;
return Abc_NtkLatchIsSelfFeed_rec( Abc_ObjFanin0(pFanin), pLatch );
}
/**Function*************************************************************
Synopsis [Checks if latches form self-loop.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkCountSelfFeedLatches( Abc_Ntk_t * pNtk )
{
Abc_Obj_t * pLatch;
int i, Counter;
Counter = 0;
Abc_NtkForEachLatch( pNtk, pLatch, i )
{
// if ( Abc_NtkLatchIsSelfFeed(pLatch) && Abc_ObjFanoutNum(pLatch) > 1 )
// printf( "Fanouts = %d.\n", Abc_ObjFanoutNum(pLatch) );
Counter += Abc_NtkLatchIsSelfFeed( pLatch );
}
return Counter;
}
/**Function*************************************************************
Synopsis [Replaces self-feeding latches by latches with constant inputs.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkRemoveSelfFeedLatches( Abc_Ntk_t * pNtk )
{
Abc_Obj_t * pLatch, * pConst1;
int i, Counter;
Counter = 0;
Abc_NtkForEachLatch( pNtk, pLatch, i )
{
if ( Abc_NtkLatchIsSelfFeed( pLatch ) )
{
if ( Abc_NtkIsStrash(pNtk) )
pConst1 = Abc_AigConst1(pNtk);
else
pConst1 = Abc_NtkCreateNodeConst1(pNtk);
Abc_ObjPatchFanin( Abc_ObjFanin0(pLatch), Abc_ObjFanin0(Abc_ObjFanin0(pLatch)), pConst1 );
Counter++;
}
}
return Counter;
}
/**Function*************************************************************
Synopsis [Pipelines the network with latches.]
Description []
SideEffects [Does not check the names of the added latches!!!]
SeeAlso []
***********************************************************************/
void Abc_NtkLatchPipe( Abc_Ntk_t * pNtk, int nLatches )
{
Vec_Ptr_t * vNodes;
Abc_Obj_t * pObj, * pLatch, * pFanin, * pFanout;
int i, k, nTotal, nDigits;
if ( nLatches < 1 )
return;
nTotal = nLatches * Abc_NtkPiNum(pNtk);
nDigits = Abc_Base10Log( nTotal );
vNodes = Vec_PtrAlloc( 100 );
Abc_NtkForEachPi( pNtk, pObj, i )
{
// remember current fanins of the PI
Abc_NodeCollectFanouts( pObj, vNodes );
// create the latches
for ( pFanin = pObj, k = 0; k < nLatches; k++, pFanin = pLatch )
{
pLatch = Abc_NtkCreateLatch( pNtk );
Abc_ObjAddFanin( pLatch, pFanin );
Abc_LatchSetInitDc( pLatch );
// create the name of the new latch
Abc_ObjAssignName( pLatch, Abc_ObjNameDummy("LL", i*nLatches + k, nDigits), NULL );
}
// patch the PI fanouts
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pFanout, k )
Abc_ObjPatchFanin( pFanout, pObj, pFanin );
}
Vec_PtrFree( vNodes );
Abc_NtkLogicMakeSimpleCos( pNtk, 0 );
}
/**Function*************************************************************
Synopsis [Strashes one logic node using its SOP.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Int_t * Abc_NtkCollectLatchValues( Abc_Ntk_t * pNtk )
{
Vec_Int_t * vValues;
Abc_Obj_t * pLatch;
int i;
vValues = Vec_IntAlloc( Abc_NtkLatchNum(pNtk) );
Abc_NtkForEachLatch( pNtk, pLatch, i )
Vec_IntPush( vValues, Abc_LatchIsInit1(pLatch) );
return vValues;
}
/**Function*************************************************************
Synopsis [Derives latch init string.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
char * Abc_NtkCollectLatchValuesStr( Abc_Ntk_t * pNtk )
{
char * pInits;
Abc_Obj_t * pLatch;
int i;
pInits = ABC_ALLOC( char, Abc_NtkLatchNum(pNtk) + 1 );
Abc_NtkForEachLatch( pNtk, pLatch, i )
{
if ( Abc_LatchIsInit0(pLatch) )
pInits[i] = '0';
else if ( Abc_LatchIsInit1(pLatch) )
pInits[i] = '1';
else if ( Abc_LatchIsInitDc(pLatch) )
pInits[i] = 'x';
else
assert( 0 );
}
pInits[i] = 0;
return pInits;
}
/**Function*************************************************************
Synopsis [Strashes one logic node using its SOP.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkInsertLatchValues( Abc_Ntk_t * pNtk, Vec_Int_t * vValues )
{
Abc_Obj_t * pLatch;
int i;
Abc_NtkForEachLatch( pNtk, pLatch, i )
pLatch->pData = (void *)(ABC_PTRINT_T)(vValues? (Vec_IntEntry(vValues,i)? ABC_INIT_ONE : ABC_INIT_ZERO) : ABC_INIT_DC);
}
/**Function*************************************************************
Synopsis [Creates latch with the given initial value.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Obj_t * Abc_NtkAddLatch( Abc_Ntk_t * pNtk, Abc_Obj_t * pDriver, Abc_InitType_t Init )
{
Abc_Obj_t * pLatchOut, * pLatch, * pLatchIn;
pLatchOut = Abc_NtkCreateBo(pNtk);
pLatch = Abc_NtkCreateLatch(pNtk);
pLatchIn = Abc_NtkCreateBi(pNtk);
Abc_ObjAssignName( pLatchOut, Abc_ObjName(pLatch), "_lo" );
Abc_ObjAssignName( pLatchIn, Abc_ObjName(pLatch), "_li" );
Abc_ObjAddFanin( pLatchOut, pLatch );
Abc_ObjAddFanin( pLatch, pLatchIn );
if ( pDriver )
Abc_ObjAddFanin( pLatchIn, pDriver );
pLatch->pData = (void *)Init;
return pLatchOut;
}
/**Function*************************************************************
Synopsis [Creates MUX.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkNodeConvertToMux( Abc_Ntk_t * pNtk, Abc_Obj_t * pNodeC, Abc_Obj_t * pNode1, Abc_Obj_t * pNode0, Abc_Obj_t * pMux )
{
assert( Abc_NtkIsLogic(pNtk) );
Abc_ObjAddFanin( pMux, pNodeC );
Abc_ObjAddFanin( pMux, pNode1 );
Abc_ObjAddFanin( pMux, pNode0 );
if ( Abc_NtkHasSop(pNtk) )
pMux->pData = Abc_SopRegister( (Mem_Flex_t *)pNtk->pManFunc, "11- 1\n0-1 1\n" );
#ifdef ABC_USE_CUDD
else if ( Abc_NtkHasBdd(pNtk) )
pMux->pData = Cudd_bddIte((DdManager *)pNtk->pManFunc,Cudd_bddIthVar((DdManager *)pNtk->pManFunc,0),Cudd_bddIthVar((DdManager *)pNtk->pManFunc,1),Cudd_bddIthVar((DdManager *)pNtk->pManFunc,2)), Cudd_Ref( (DdNode *)pMux->pData );
#endif
else if ( Abc_NtkHasAig(pNtk) )
pMux->pData = Hop_Mux((Hop_Man_t *)pNtk->pManFunc,Hop_IthVar((Hop_Man_t *)pNtk->pManFunc,0),Hop_IthVar((Hop_Man_t *)pNtk->pManFunc,1),Hop_IthVar((Hop_Man_t *)pNtk->pManFunc,2));
else
assert( 0 );
}
/**Function*************************************************************
Synopsis [Converts registers with DC values into additional PIs.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkConvertDcLatches( Abc_Ntk_t * pNtk )
{
Abc_Obj_t * pCtrl, * pLatch, * pMux, * pPi;
Abc_InitType_t Init = ABC_INIT_ZERO;
int i, fFound = 0, Counter;
// check if there are latches with DC values
Abc_NtkForEachLatch( pNtk, pLatch, i )
if ( Abc_LatchIsInitDc(pLatch) )
{
fFound = 1;
break;
}
if ( !fFound )
return;
// add control latch
pCtrl = Abc_NtkAddLatch( pNtk, Abc_NtkCreateNodeConst1(pNtk), Init );
// add fanouts for each latch with DC values
Counter = 0;
Abc_NtkForEachLatch( pNtk, pLatch, i )
{
if ( !Abc_LatchIsInitDc(pLatch) )
continue;
// change latch value
pLatch->pData = (void *)Init;
// if the latch output has the same name as a PO, rename it
if ( Abc_NodeFindCoFanout( Abc_ObjFanout0(pLatch) ) )
{
Nm_ManDeleteIdName( pLatch->pNtk->pManName, Abc_ObjFanout0(pLatch)->Id );
Abc_ObjAssignName( Abc_ObjFanout0(pLatch), Abc_ObjName(pLatch), "_lo" );
}
// create new PIs
pPi = Abc_NtkCreatePi( pNtk );
Abc_ObjAssignName( pPi, Abc_ObjName(pLatch), "_pi" );
// create a new node and transfer fanout from latch output to the new node
pMux = Abc_NtkCreateNode( pNtk );
Abc_ObjTransferFanout( Abc_ObjFanout0(pLatch), pMux );
// convert the node into a mux
Abc_NtkNodeConvertToMux( pNtk, pCtrl, Abc_ObjFanout0(pLatch), pPi, pMux );
Counter++;
}
printf( "The number of converted latches with DC values = %d.\n", Counter );
}
/**Function*************************************************************
Synopsis [Transfors the array of latch names into that of latch numbers.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkConverLatchNamesIntoNumbers( Abc_Ntk_t * pNtk )
{
Vec_Ptr_t * vResult, * vNames;
Vec_Int_t * vNumbers;
Abc_Obj_t * pObj;
char * pName;
int i, k, Num;
if ( pNtk->vOnehots == NULL )
return NULL;
// set register numbers
Abc_NtkForEachLatch( pNtk, pObj, i )
pObj->pNext = (Abc_Obj_t *)(ABC_PTRINT_T)i;
// add the numbers
vResult = Vec_PtrAlloc( Vec_PtrSize(pNtk->vOnehots) );
Vec_PtrForEachEntry( Vec_Ptr_t *, pNtk->vOnehots, vNames, i )
{
vNumbers = Vec_IntAlloc( Vec_PtrSize(vNames) );
Vec_PtrForEachEntry( char *, vNames, pName, k )
{
Num = Nm_ManFindIdByName( pNtk->pManName, pName, ABC_OBJ_BO );
if ( Num < 0 )
continue;
pObj = Abc_NtkObj( pNtk, Num );
if ( Abc_ObjFaninNum(pObj) != 1 || !Abc_ObjIsLatch(Abc_ObjFanin0(pObj)) )
continue;
Vec_IntPush( vNumbers, (int)(ABC_PTRINT_T)pObj->pNext );
}
if ( Vec_IntSize( vNumbers ) > 1 )
{
Vec_PtrPush( vResult, vNumbers );
printf( "Converted %d one-hot registers.\n", Vec_IntSize(vNumbers) );
}
else
Vec_IntFree( vNumbers );
}
// clean the numbers
Abc_NtkForEachLatch( pNtk, pObj, i )
pObj->pNext = NULL;
return vResult;
}
/**Function*************************************************************
Synopsis [Converts registers with DC values into additional PIs.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Ntk_t * Abc_NtkConvertOnehot( Abc_Ntk_t * pNtk )
{
Vec_Ptr_t * vNodes;
Abc_Ntk_t * pNtkNew;
Abc_Obj_t * pObj, * pFanin, * pObjNew, * pObjLiNew, * pObjLoNew;
int i, k, nFlops, nStates, iState, pfCompl[32];
assert( Abc_NtkIsLogic(pNtk) );
nFlops = Abc_NtkLatchNum(pNtk);
if ( nFlops == 0 )
return Abc_NtkDup( pNtk );
if ( nFlops > 16 )
{
printf( "Cannot reencode %d flops because it will lead to 2^%d states.\n", nFlops, nFlops );
return NULL;
}
// check if there are latches with DC values
iState = 0;
Abc_NtkForEachLatch( pNtk, pObj, i )
{
if ( Abc_LatchIsInitDc(pObj) )
{
printf( "Cannot process logic network with don't-care init values. Run \"zero\".\n" );
return NULL;
}
if ( Abc_LatchIsInit1(pObj) )
iState |= (1 << i);
}
// transfer logic to SOPs
Abc_NtkToSop( pNtk, -1, ABC_INFINITY );
// create new network
pNtkNew = Abc_NtkStartFromNoLatches( pNtk, pNtk->ntkType, pNtk->ntkFunc );
nStates = (1 << nFlops);
for ( i = 0; i < nStates; i++ )
{
pObjNew = Abc_NtkCreateLatch( pNtkNew );
pObjLiNew = Abc_NtkCreateBi( pNtkNew );
pObjLoNew = Abc_NtkCreateBo( pNtkNew );
Abc_ObjAddFanin( pObjNew, pObjLiNew );
Abc_ObjAddFanin( pObjLoNew, pObjNew );
if ( i == iState )
Abc_LatchSetInit1( pObjNew );
else
Abc_LatchSetInit0( pObjNew );
}
Abc_NtkAddDummyBoxNames( pNtkNew );
assert( Abc_NtkLatchNum(pNtkNew) == nStates );
assert( Abc_NtkPiNum(pNtkNew) == Abc_NtkPiNum(pNtk) );
assert( Abc_NtkPoNum(pNtkNew) == Abc_NtkPoNum(pNtk) );
assert( Abc_NtkCiNum(pNtkNew) == Abc_NtkPiNum(pNtkNew) + nStates );
assert( Abc_NtkCoNum(pNtkNew) == Abc_NtkPoNum(pNtkNew) + nStates );
assert( Abc_NtkCiNum(pNtk) == Abc_NtkPiNum(pNtk) + nFlops );
assert( Abc_NtkCoNum(pNtk) == Abc_NtkPoNum(pNtk) + nFlops );
// create hot-to-log transformers
for ( i = 0; i < nFlops; i++ )
{
pObjNew = Abc_NtkCreateNode( pNtkNew );
for ( k = 0; k < nStates; k++ )
if ( (k >> i) & 1 )
Abc_ObjAddFanin( pObjNew, Abc_NtkCi(pNtkNew, Abc_NtkPiNum(pNtkNew)+k) );
assert( Abc_ObjFaninNum(pObjNew) == nStates/2 );
pObjNew->pData = Abc_SopCreateOr( (Mem_Flex_t *)pNtkNew->pManFunc, nStates/2, NULL );
// save the new flop
pObj = Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i );
pObj->pCopy = pObjNew;
}
// duplicate the nodes
vNodes = Abc_NtkDfs( pNtk, 0 );
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
{
pObj->pCopy = Abc_NtkDupObj( pNtkNew, pObj, 1 );
Abc_ObjForEachFanin( pObj, pFanin, k )
Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
}
Vec_PtrFree( vNodes );
// connect the POs
Abc_NtkForEachPo( pNtk, pObj, i )
Abc_ObjAddFanin( pObj->pCopy, Abc_ObjNotCond(Abc_ObjFanin0(pObj)->pCopy, Abc_ObjFaninC0(pObj)) );
// write entries into the nodes
Abc_NtkForEachCo( pNtk, pObj, i )
pObj->pCopy = Abc_ObjNotCond(Abc_ObjFanin0(pObj)->pCopy, Abc_ObjFaninC0(pObj));
// create log-to-hot transformers
for ( k = 0; k < nStates; k++ )
{
pObjNew = Abc_NtkCreateNode( pNtkNew );
for ( i = 0; i < nFlops; i++ )
{
pObj = Abc_NtkCo( pNtk, Abc_NtkPoNum(pNtk) + i );
Abc_ObjAddFanin( pObjNew, Abc_ObjRegular(pObj->pCopy) );
pfCompl[i] = Abc_ObjIsComplement(pObj->pCopy) ^ !((k >> i) & 1);
}
pObjNew->pData = Abc_SopCreateAnd( (Mem_Flex_t *)pNtkNew->pManFunc, nFlops, pfCompl );
// connect it to the flop input
Abc_ObjAddFanin( Abc_NtkCo(pNtkNew, Abc_NtkPoNum(pNtkNew)+k), pObjNew );
}
if ( !Abc_NtkCheck( pNtkNew ) )
fprintf( stdout, "Abc_NtkConvertOnehot(): Network check has failed.\n" );
return pNtkNew;
}
ABC_NAMESPACE_IMPL_END
#include "aig/gia/giaAig.h"
ABC_NAMESPACE_IMPL_START
/**Function*************************************************************
Synopsis [Performs retiming with classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Abc_NtkRetimeWithClassesAig( Aig_Man_t * pMan, Vec_Int_t * vClasses, Vec_Int_t ** pvClasses, int fVerbose )
{
Aig_Man_t * pManNew;
Gia_Man_t * pGia, * pGiaNew;
pGia = Gia_ManFromAigSimple( pMan );
assert( Gia_ManRegNum(pGia) == Vec_IntSize(vClasses) );
pGia->vFlopClasses = vClasses;
pGiaNew = Gia_ManRetimeForward( pGia, 10, fVerbose );
*pvClasses = pGiaNew->vFlopClasses;
pGiaNew->vFlopClasses = NULL;
pManNew = Gia_ManToAig( pGiaNew, 0 );
Gia_ManStop( pGiaNew );
Gia_ManStop( pGia );
return pManNew;
}
/**Function*************************************************************
Synopsis [Performs retiming with classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Ntk_t * Abc_NtkRetimeWithClassesNtk( Abc_Ntk_t * pNtk, Vec_Int_t * vClasses, Vec_Int_t ** pvClasses, int fVerbose )
{
extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters );
extern Abc_Ntk_t * Abc_NtkFromDarSeqSweep( Abc_Ntk_t * pNtkOld, Aig_Man_t * pMan );
Abc_Ntk_t * pNtkAig, * pNtkAigRet, * pNtkRes;
Aig_Man_t * pMan, * pManNew;
pNtkAig = Abc_NtkStrash( pNtk, 0, 1, 0 );
pMan = Abc_NtkToDar( pNtkAig, 0, 1 );
pManNew = Abc_NtkRetimeWithClassesAig( pMan, vClasses, pvClasses, fVerbose );
pNtkAigRet = Abc_NtkFromDarSeqSweep( pNtkAig, pManNew );
pNtkRes = Abc_NtkToLogic( pNtkAigRet );
Abc_NtkDelete( pNtkAigRet );
Abc_NtkDelete( pNtkAig );
Aig_ManStop( pManNew );
Aig_ManStop( pMan );
return pNtkRes;
}
/**Function*************************************************************
Synopsis [Returns self-loops back into the network.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkTransformBack( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtkNew, Vec_Ptr_t * vControls, Vec_Int_t * vClasses )
{
Abc_Obj_t * pObj, * pNodeNew, * pCtrl, * pDriver;
int i, Class;
assert( Abc_NtkPoNum(pNtkOld) == Abc_NtkPoNum(pNtkNew) );
// match the POs of the old into new
Abc_NtkForEachPo( pNtkOld, pObj, i )
pObj->pCopy = Abc_NtkPo( pNtkNew, i );
// remap the flops
Vec_PtrForEachEntry( Abc_Obj_t *, vControls, pObj, i )
{
assert( Abc_ObjIsPo(pObj) && pObj->pNtk == pNtkOld );
Vec_PtrWriteEntry( vControls, i, pObj->pCopy );
}
// create self-loops
assert( Abc_NtkLatchNum(pNtkNew) == Vec_IntSize(vClasses) );
Abc_NtkForEachLatch( pNtkNew, pObj, i )
{
Class = Vec_IntEntry( vClasses, i );
if ( Class == -1 )
continue;
pDriver = Abc_ObjFanin0(Abc_ObjFanin0(pObj));
pCtrl = (Abc_Obj_t *)Vec_PtrEntry( vControls, Class );
pCtrl = Abc_ObjFanin0( pCtrl );
pNodeNew = Abc_NtkCreateNode( pNtkNew );
Abc_ObjAddFanin( pNodeNew, pCtrl );
Abc_ObjAddFanin( pNodeNew, pDriver );
Abc_ObjAddFanin( pNodeNew, Abc_ObjFanout0(pObj) );
Abc_ObjSetData( pNodeNew, Abc_SopRegister((Mem_Flex_t *)pNtkNew->pManFunc, "0-1 1\n11- 1\n") );
Abc_ObjPatchFanin( Abc_ObjFanin0(pObj), pDriver, pNodeNew );
}
// remove the useless POs
Vec_PtrForEachEntry( Abc_Obj_t *, vControls, pObj, i )
Abc_NtkDeleteObj( pObj );
}
/**Function*************************************************************
Synopsis [Classify flops.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Ntk_t * Abc_NtkCRetime( Abc_Ntk_t * pNtk, int fVerbose )
{
Abc_Ntk_t * pNtkNew;
Vec_Ptr_t * vControls;
Vec_Int_t * vFlopClasses, * vFlopClassesNew;
Abc_Obj_t * pObj, * pDriver, * pFlopOut, * pObjPo;
int i, iFlop, CountN = 0, Count2 = 0, Count1 = 0, Count0 = 0;
// duplicate the AIG
pNtk = Abc_NtkDup( pNtk );
// update registers
vControls = Vec_PtrAlloc( 100 );
vFlopClasses = Vec_IntAlloc( 100 );
Abc_NtkForEachLatch( pNtk, pObj, i )
{
pFlopOut = Abc_ObjFanout0(pObj);
pDriver = Abc_ObjFanin0( Abc_ObjFanin0(pObj) );
if ( Abc_ObjFaninNum(pDriver) != 3 )
{
Vec_IntPush( vFlopClasses, -1 );
CountN++;
continue;
}
if ( Abc_ObjFanin(pDriver, 1) != pFlopOut && Abc_ObjFanin(pDriver, 2) != pFlopOut )
{
Vec_IntPush( vFlopClasses, -1 );
Count2++;
continue;
}
if ( Abc_ObjFanin(pDriver, 1) == pFlopOut )
{
Vec_IntPush( vFlopClasses, -1 );
Count1++;
continue;
}
assert( Abc_ObjFanin(pDriver, 2) == pFlopOut );
Count0++;
Vec_PtrPushUnique( vControls, Abc_ObjFanin0(pDriver) );
// set the flop class
iFlop = Vec_PtrFind( vControls, Abc_ObjFanin0(pDriver) );
Vec_IntPush( vFlopClasses, iFlop );
// update
Abc_ObjPatchFanin( Abc_ObjFanin0(pObj), pDriver, Abc_ObjFanin(pDriver, 1) );
}
if ( Count1 )
printf( "Opposite phase enable is present in %d flops (out of %d).\n", Count1, Abc_NtkLatchNum(pNtk) );
if ( fVerbose )
printf( "CountN = %4d. Count2 = %4d. Count1 = %4d. Count0 = %4d. Ctrls = %d.\n",
CountN, Count2, Count1, Count0, Vec_PtrSize(vControls) );
// add the controls to the list of POs
Vec_PtrForEachEntry( Abc_Obj_t *, vControls, pObj, i )
{
pObjPo = Abc_NtkCreatePo( pNtk );
Abc_ObjAddFanin( pObjPo, pObj );
Abc_ObjAssignName( pObjPo, Abc_ObjName(pObjPo), NULL );
Vec_PtrWriteEntry( vControls, i, pObjPo );
}
Abc_NtkOrderCisCos( pNtk );
Abc_NtkCleanup( pNtk, fVerbose );
// performs retiming with classes
pNtkNew = Abc_NtkRetimeWithClassesNtk( pNtk, vFlopClasses, &vFlopClassesNew, fVerbose );
Abc_NtkTransformBack( pNtk, pNtkNew, vControls, vFlopClassesNew );
// assert( Abc_NtkPoNum(pNtkNew) == Abc_NtkPoNum(pNtk) );
Abc_NtkDelete( pNtk );
Vec_PtrFree( vControls );
// Vec_IntFree( vFlopClasses );
Vec_IntFree( vFlopClassesNew );
return pNtkNew;
}
/**Function*************************************************************
Synopsis [Resimulates CEX and return the ID of the PO that failed.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkVerifyCex( Abc_Ntk_t * pNtk, Abc_Cex_t * p )
{
Abc_Obj_t * pObj;
int RetValue, i, k, iBit = 0;
assert( Abc_NtkIsStrash(pNtk) );
assert( p->nPis == Abc_NtkPiNum(pNtk) );
// assert( p->nRegs == Abc_NtkLatchNum(pNtk) );
Abc_NtkCleanMarkC( pNtk );
Abc_AigConst1(pNtk)->fMarkC = 1;
// initialize flops
Abc_NtkForEachLatch( pNtk, pObj, i )
Abc_ObjFanout0(pObj)->fMarkC = Abc_InfoHasBit(p->pData, iBit++);
// simulate timeframes
iBit = p->nRegs;
for ( i = 0; i <= p->iFrame; i++ )
{
Abc_NtkForEachPi( pNtk, pObj, k )
pObj->fMarkC = Abc_InfoHasBit(p->pData, iBit++);
Abc_NtkForEachNode( pNtk, pObj, k )
pObj->fMarkC = (Abc_ObjFanin0(pObj)->fMarkC ^ Abc_ObjFaninC0(pObj)) &
(Abc_ObjFanin1(pObj)->fMarkC ^ Abc_ObjFaninC1(pObj));
Abc_NtkForEachCo( pNtk, pObj, k )
pObj->fMarkC = Abc_ObjFanin0(pObj)->fMarkC ^ Abc_ObjFaninC0(pObj);
Abc_NtkForEachLatch( pNtk, pObj, k )
Abc_ObjFanout0(pObj)->fMarkC = Abc_ObjFanin0(pObj)->fMarkC;
}
assert( iBit == p->nBits );
// figure out the number of failed output
RetValue = -1;
Abc_NtkForEachPo( pNtk, pObj, i )
{
if ( pObj->fMarkC )
{
RetValue = i;
break;
}
}
Abc_NtkCleanMarkC( pNtk );
return RetValue;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END