mirror of https://github.com/YosysHQ/abc.git
919 lines
32 KiB
C
919 lines
32 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [abcStrash.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network and node package.]
|
|
|
|
Synopsis [Strashing of the current network.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: abcStrash.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "base/abc/abc.h"
|
|
#include "bool/dec/dec.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static void Abc_NtkStrashPerform( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew, int fAllNodes, int fRecord );
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Reapplies structural hashing to the AIG.]
|
|
|
|
Description [Because of the structural hashing, this procedure should not
|
|
change the number of nodes. It is useful to detect the bugs in the original AIG.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkRestrash( Abc_Ntk_t * pNtk, int fCleanup )
|
|
{
|
|
// extern int timeRetime;
|
|
Vec_Ptr_t * vNodes;
|
|
Abc_Ntk_t * pNtkAig;
|
|
Abc_Obj_t * pObj;
|
|
int i, nNodes;//, RetValue;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
//timeRetime = Abc_Clock();
|
|
// print warning about choice nodes
|
|
if ( Abc_NtkGetChoiceNum( pNtk ) )
|
|
printf( "Warning: The choice nodes in the original AIG are removed by strashing.\n" );
|
|
// start the new network (constants and CIs of the old network will point to the their counterparts in the new network)
|
|
pNtkAig = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG );
|
|
// restrash the nodes (assuming a topological order of the old network)
|
|
vNodes = Abc_NtkDfs( pNtk, 0 );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
|
|
pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkAig->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
Vec_PtrFree( vNodes );
|
|
// finalize the network
|
|
Abc_NtkFinalize( pNtk, pNtkAig );
|
|
// print warning about self-feed latches
|
|
// if ( Abc_NtkCountSelfFeedLatches(pNtkAig) )
|
|
// printf( "Warning: The network has %d self-feeding latches.\n", Abc_NtkCountSelfFeedLatches(pNtkAig) );
|
|
// perform cleanup if requested
|
|
if ( fCleanup && (nNodes = Abc_AigCleanup((Abc_Aig_t *)pNtkAig->pManFunc)) )
|
|
{
|
|
// printf( "Abc_NtkRestrash(): AIG cleanup removed %d nodes (this is a bug).\n", nNodes );
|
|
}
|
|
// duplicate EXDC
|
|
if ( pNtk->pExdc )
|
|
pNtkAig->pExdc = Abc_NtkDup( pNtk->pExdc );
|
|
// make sure everything is okay
|
|
if ( !Abc_NtkCheck( pNtkAig ) )
|
|
{
|
|
printf( "Abc_NtkStrash: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkAig );
|
|
return NULL;
|
|
}
|
|
//timeRetime = Abc_Clock() - timeRetime;
|
|
// if ( RetValue = Abc_NtkRemoveSelfFeedLatches(pNtkAig) )
|
|
// printf( "Modified %d self-feeding latches. The result may not verify.\n", RetValue );
|
|
return pNtkAig;
|
|
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs structural hashing by generating random number.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRestrashRandom_rec( Abc_Ntk_t * pNtk, Abc_Obj_t * pObj )
|
|
{
|
|
if ( Abc_NodeIsTravIdCurrent( pObj ) )
|
|
return;
|
|
Abc_NodeSetTravIdCurrent( pObj );
|
|
if ( !Abc_ObjIsNode(pObj) )
|
|
return;
|
|
if ( rand() & 1 )
|
|
{
|
|
Abc_NtkRestrashRandom_rec( pNtk, Abc_ObjFanin0(pObj) );
|
|
Abc_NtkRestrashRandom_rec( pNtk, Abc_ObjFanin1(pObj) );
|
|
}
|
|
else
|
|
{
|
|
Abc_NtkRestrashRandom_rec( pNtk, Abc_ObjFanin1(pObj) );
|
|
Abc_NtkRestrashRandom_rec( pNtk, Abc_ObjFanin0(pObj) );
|
|
}
|
|
pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtk->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Reapplies structural hashing to the AIG.]
|
|
|
|
Description [Because of the structural hashing, this procedure should not
|
|
change the number of nodes. It is useful to detect the bugs in the original AIG.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkRestrashRandom( Abc_Ntk_t * pNtk )
|
|
{
|
|
Abc_Ntk_t * pNtkAig;
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
// print warning about choice nodes
|
|
if ( Abc_NtkGetChoiceNum( pNtk ) )
|
|
printf( "Warning: The choice nodes in the original AIG are removed by strashing.\n" );
|
|
// start the new network (constants and CIs of the old network will point to the their counterparts in the new network)
|
|
pNtkAig = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG );
|
|
// restrash the nodes (assuming a topological order of the old network)
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
Abc_NtkRestrashRandom_rec( pNtkAig, Abc_ObjFanin0(pObj) );
|
|
// finalize the network
|
|
Abc_NtkFinalize( pNtk, pNtkAig );
|
|
// duplicate EXDC
|
|
if ( pNtk->pExdc )
|
|
pNtkAig->pExdc = Abc_NtkDup( pNtk->pExdc );
|
|
// make sure everything is okay
|
|
if ( !Abc_NtkCheck( pNtkAig ) )
|
|
{
|
|
printf( "Abc_NtkStrash: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkAig );
|
|
return NULL;
|
|
}
|
|
return pNtkAig;
|
|
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Reapplies structural hashing to the AIG.]
|
|
|
|
Description [Because of the structural hashing, this procedure should not
|
|
change the number of nodes. It is useful to detect the bugs in the original AIG.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkRestrashZero( Abc_Ntk_t * pNtk, int fCleanup )
|
|
{
|
|
// extern int timeRetime;
|
|
Abc_Ntk_t * pNtkAig;
|
|
Abc_Obj_t * pObj;
|
|
int i, nNodes;//, RetValue;
|
|
int Counter = 0;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
//timeRetime = Abc_Clock();
|
|
// print warning about choice nodes
|
|
if ( Abc_NtkGetChoiceNum( pNtk ) )
|
|
printf( "Warning: The choice nodes in the original AIG are removed by strashing.\n" );
|
|
// start the new network (constants and CIs of the old network will point to the their counterparts in the new network)
|
|
pNtkAig = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG );
|
|
// complement the 1-values registers
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
{
|
|
if ( Abc_LatchIsInitDc(pObj) )
|
|
Counter++;
|
|
else if ( Abc_LatchIsInit1(pObj) )
|
|
Abc_ObjFanout0(pObj)->pCopy = Abc_ObjNot(Abc_ObjFanout0(pObj)->pCopy);
|
|
}
|
|
if ( Counter )
|
|
printf( "Converting %d flops from don't-care to zero initial value.\n", Counter );
|
|
// restrash the nodes (assuming a topological order of the old network)
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkAig->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
// finalize the network
|
|
Abc_NtkFinalize( pNtk, pNtkAig );
|
|
// complement the 1-valued registers
|
|
Abc_NtkForEachLatch( pNtkAig, pObj, i )
|
|
if ( Abc_LatchIsInit1(pObj) )
|
|
{
|
|
Abc_ObjXorFaninC( Abc_ObjFanin0(pObj), 0 );
|
|
// if latch has PO as one of its fanouts change latch name
|
|
if ( Abc_NodeFindCoFanout( Abc_ObjFanout0(pObj) ) )
|
|
{
|
|
Nm_ManDeleteIdName( pObj->pNtk->pManName, Abc_ObjFanout0(pObj)->Id );
|
|
Abc_ObjAssignName( Abc_ObjFanout0(pObj), Abc_ObjName(Abc_ObjFanout0(pObj)), "_inv" );
|
|
}
|
|
}
|
|
// set all constant-0 values
|
|
Abc_NtkForEachLatch( pNtkAig, pObj, i )
|
|
Abc_LatchSetInit0( pObj );
|
|
|
|
// print warning about self-feed latches
|
|
// if ( Abc_NtkCountSelfFeedLatches(pNtkAig) )
|
|
// printf( "Warning: The network has %d self-feeding latches.\n", Abc_NtkCountSelfFeedLatches(pNtkAig) );
|
|
// perform cleanup if requested
|
|
if ( fCleanup && (nNodes = Abc_AigCleanup((Abc_Aig_t *)pNtkAig->pManFunc)) )
|
|
printf( "Abc_NtkRestrash(): AIG cleanup removed %d nodes (this is a bug).\n", nNodes );
|
|
// duplicate EXDC
|
|
if ( pNtk->pExdc )
|
|
pNtkAig->pExdc = Abc_NtkDup( pNtk->pExdc );
|
|
// transfer name IDs
|
|
if ( pNtk->vNameIds )
|
|
Abc_NtkTransferNameIds( pNtk, pNtkAig );
|
|
if ( pNtk->vNameIds )
|
|
Abc_NtkUpdateNameIds( pNtkAig );
|
|
// make sure everything is okay
|
|
if ( !Abc_NtkCheck( pNtkAig ) )
|
|
{
|
|
printf( "Abc_NtkStrash: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkAig );
|
|
return NULL;
|
|
}
|
|
//timeRetime = Abc_Clock() - timeRetime;
|
|
// if ( RetValue = Abc_NtkRemoveSelfFeedLatches(pNtkAig) )
|
|
// printf( "Modified %d self-feeding latches. The result may not verify.\n", RetValue );
|
|
return pNtkAig;
|
|
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Transforms logic network into structurally hashed AIG.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkStrash( Abc_Ntk_t * pNtk, int fAllNodes, int fCleanup, int fRecord )
|
|
{
|
|
Abc_Ntk_t * pNtkAig;
|
|
int nNodes;
|
|
assert( Abc_NtkIsLogic(pNtk) || Abc_NtkIsStrash(pNtk) );
|
|
// consider the special case when the network is already structurally hashed
|
|
if ( Abc_NtkIsStrash(pNtk) )
|
|
return Abc_NtkRestrash( pNtk, fCleanup );
|
|
// convert the node representation in the logic network to the AIG form
|
|
if ( !Abc_NtkToAig(pNtk) )
|
|
{
|
|
printf( "Converting to AIGs has failed.\n" );
|
|
return NULL;
|
|
}
|
|
// perform strashing
|
|
// Abc_NtkCleanCopy( pNtk );
|
|
pNtkAig = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG );
|
|
Abc_NtkStrashPerform( pNtk, pNtkAig, fAllNodes, fRecord );
|
|
Abc_NtkFinalize( pNtk, pNtkAig );
|
|
// transfer name IDs
|
|
if ( pNtk->vNameIds )
|
|
Abc_NtkTransferNameIds( pNtk, pNtkAig );
|
|
// print warning about self-feed latches
|
|
// if ( Abc_NtkCountSelfFeedLatches(pNtkAig) )
|
|
// printf( "Warning: The network has %d self-feeding latches.\n", Abc_NtkCountSelfFeedLatches(pNtkAig) );
|
|
// perform cleanup if requested
|
|
nNodes = fCleanup? Abc_AigCleanup((Abc_Aig_t *)pNtkAig->pManFunc) : 0;
|
|
// if ( nNodes )
|
|
// printf( "Warning: AIG cleanup removed %d nodes (this is not a bug).\n", nNodes );
|
|
// duplicate EXDC
|
|
if ( pNtk->pExdc )
|
|
pNtkAig->pExdc = Abc_NtkStrash( pNtk->pExdc, fAllNodes, fCleanup, fRecord );
|
|
// make sure everything is okay
|
|
if ( !Abc_NtkCheck( pNtkAig ) )
|
|
{
|
|
printf( "Abc_NtkStrash: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkAig );
|
|
return NULL;
|
|
}
|
|
return pNtkAig;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Appends the second network to the first.]
|
|
|
|
Description [Modifies the first network by adding the logic of the second.
|
|
Performs structural hashing while appending the networks. Does not change
|
|
the second network. Returns 0 if the appending failed, 1 otherise.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkAppend( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int fAddPos )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
char * pName;
|
|
int i, nNewCis;
|
|
// the first network should be an AIG
|
|
assert( Abc_NtkIsStrash(pNtk1) );
|
|
assert( Abc_NtkIsLogic(pNtk2) || Abc_NtkIsStrash(pNtk2) );
|
|
if ( Abc_NtkIsLogic(pNtk2) && !Abc_NtkToAig(pNtk2) )
|
|
{
|
|
printf( "Converting to AIGs has failed.\n" );
|
|
return 0;
|
|
}
|
|
// check that the networks have the same PIs
|
|
// reorder PIs of pNtk2 according to pNtk1
|
|
if ( !Abc_NtkCompareSignals( pNtk1, pNtk2, 1, 1 ) )
|
|
printf( "Abc_NtkAppend(): The union of the network PIs is computed (warning).\n" );
|
|
// perform strashing
|
|
nNewCis = 0;
|
|
Abc_NtkCleanCopy( pNtk2 );
|
|
if ( Abc_NtkIsStrash(pNtk2) )
|
|
Abc_AigConst1(pNtk2)->pCopy = Abc_AigConst1(pNtk1);
|
|
Abc_NtkForEachCi( pNtk2, pObj, i )
|
|
{
|
|
pName = Abc_ObjName(pObj);
|
|
pObj->pCopy = Abc_NtkFindCi(pNtk1, Abc_ObjName(pObj));
|
|
if ( pObj->pCopy == NULL )
|
|
{
|
|
pObj->pCopy = Abc_NtkDupObj(pNtk1, pObj, 1);
|
|
nNewCis++;
|
|
}
|
|
}
|
|
if ( nNewCis )
|
|
printf( "Warning: Procedure Abc_NtkAppend() added %d new CIs.\n", nNewCis );
|
|
// add pNtk2 to pNtk1 while strashing
|
|
if ( Abc_NtkIsLogic(pNtk2) )
|
|
Abc_NtkStrashPerform( pNtk2, pNtk1, 1, 0 );
|
|
else
|
|
Abc_NtkForEachNode( pNtk2, pObj, i )
|
|
pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtk1->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
// add the COs of the second network
|
|
if ( fAddPos )
|
|
{
|
|
Abc_NtkForEachPo( pNtk2, pObj, i )
|
|
{
|
|
Abc_NtkDupObj( pNtk1, pObj, 0 );
|
|
Abc_ObjAddFanin( pObj->pCopy, Abc_ObjChild0Copy(pObj) );
|
|
Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Abc_Obj_t * pObjOld, * pDriverOld, * pDriverNew;
|
|
int fCompl, iNodeId;
|
|
// OR the choices
|
|
Abc_NtkForEachCo( pNtk2, pObj, i )
|
|
{
|
|
iNodeId = Nm_ManFindIdByNameTwoTypes( pNtk1->pManName, Abc_ObjName(pObj), ABC_OBJ_PO, ABC_OBJ_BI );
|
|
// if ( iNodeId < 0 )
|
|
// continue;
|
|
assert( iNodeId >= 0 );
|
|
pObjOld = Abc_NtkObj( pNtk1, iNodeId );
|
|
// derive the new driver
|
|
pDriverOld = Abc_ObjChild0( pObjOld );
|
|
pDriverNew = Abc_ObjChild0Copy( pObj );
|
|
pDriverNew = Abc_AigOr( (Abc_Aig_t *)pNtk1->pManFunc, pDriverOld, pDriverNew );
|
|
if ( Abc_ObjRegular(pDriverOld) == Abc_ObjRegular(pDriverNew) )
|
|
continue;
|
|
// replace the old driver by the new driver
|
|
fCompl = Abc_ObjRegular(pDriverOld)->fPhase ^ Abc_ObjRegular(pDriverNew)->fPhase;
|
|
Abc_ObjPatchFanin( pObjOld, Abc_ObjRegular(pDriverOld), Abc_ObjNotCond(Abc_ObjRegular(pDriverNew), fCompl) );
|
|
}
|
|
}
|
|
// make sure that everything is okay
|
|
if ( !Abc_NtkCheck( pNtk1 ) )
|
|
{
|
|
printf( "Abc_NtkAppend: The network check has failed.\n" );
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Prepares the network for strashing.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkStrashPerform( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtkNew, int fAllNodes, int fRecord )
|
|
{
|
|
Vec_Ptr_t * vNodes;
|
|
Abc_Obj_t * pNodeOld;
|
|
int i; //, clk = Abc_Clock();
|
|
assert( Abc_NtkIsLogic(pNtkOld) );
|
|
assert( Abc_NtkIsStrash(pNtkNew) );
|
|
// vNodes = Abc_NtkDfs( pNtkOld, fAllNodes );
|
|
vNodes = Abc_NtkDfsIter( pNtkOld, fAllNodes );
|
|
//printf( "Nodes = %d. ", Vec_PtrSize(vNodes) );
|
|
//ABC_PRT( "Time", Abc_Clock() - clk );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNodeOld, i )
|
|
{
|
|
if ( Abc_ObjIsBarBuf(pNodeOld) )
|
|
pNodeOld->pCopy = Abc_ObjChild0Copy(pNodeOld);
|
|
else
|
|
pNodeOld->pCopy = Abc_NodeStrash( pNtkNew, pNodeOld, fRecord );
|
|
}
|
|
Vec_PtrFree( vNodes );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Transfers the AIG from one manager into another.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NodeStrash_rec( Abc_Aig_t * pMan, Hop_Obj_t * pObj )
|
|
{
|
|
assert( !Hop_IsComplement(pObj) );
|
|
if ( !Hop_ObjIsNode(pObj) || Hop_ObjIsMarkA(pObj) )
|
|
return;
|
|
Abc_NodeStrash_rec( pMan, Hop_ObjFanin0(pObj) );
|
|
Abc_NodeStrash_rec( pMan, Hop_ObjFanin1(pObj) );
|
|
pObj->pData = Abc_AigAnd( pMan, (Abc_Obj_t *)Hop_ObjChild0Copy(pObj), (Abc_Obj_t *)Hop_ObjChild1Copy(pObj) );
|
|
assert( !Hop_ObjIsMarkA(pObj) ); // loop detection
|
|
Hop_ObjSetMarkA( pObj );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Strashes one logic node.]
|
|
|
|
Description [Assume the network is in the AIG form]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Abc_NodeStrash( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNodeOld, int fRecord )
|
|
{
|
|
Hop_Man_t * pMan;
|
|
Hop_Obj_t * pRoot;
|
|
Abc_Obj_t * pFanin;
|
|
int i;
|
|
assert( Abc_ObjIsNode(pNodeOld) );
|
|
assert( Abc_NtkHasAig(pNodeOld->pNtk) && !Abc_NtkIsStrash(pNodeOld->pNtk) );
|
|
// get the local AIG manager and the local root node
|
|
pMan = (Hop_Man_t *)pNodeOld->pNtk->pManFunc;
|
|
pRoot = (Hop_Obj_t *)pNodeOld->pData;
|
|
// check the constant case
|
|
if ( Abc_NodeIsConst(pNodeOld) || Hop_Regular(pRoot) == Hop_ManConst1(pMan) )
|
|
return Abc_ObjNotCond( Abc_AigConst1(pNtkNew), Hop_IsComplement(pRoot) );
|
|
// perform special case-strashing using the record of AIG subgraphs
|
|
/*
|
|
if ( fRecord && Abc_NtkRecIsRunning() && Abc_ObjFaninNum(pNodeOld) > 2 && Abc_ObjFaninNum(pNodeOld) <= Abc_NtkRecVarNum() )
|
|
{
|
|
extern Vec_Int_t * Abc_NtkRecMemory();
|
|
extern int Abc_NtkRecStrashNode( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pObj, unsigned * pTruth, int nVars );
|
|
int nVars = Abc_NtkRecVarNum();
|
|
Vec_Int_t * vMemory = Abc_NtkRecMemory();
|
|
unsigned * pTruth = Hop_ManConvertAigToTruth( pMan, Hop_Regular(pRoot), nVars, vMemory, 0 );
|
|
assert( Extra_TruthSupportSize(pTruth, nVars) == Abc_ObjFaninNum(pNodeOld) ); // should be swept
|
|
if ( Hop_IsComplement(pRoot) )
|
|
Extra_TruthNot( pTruth, pTruth, nVars );
|
|
if ( Abc_NtkRecStrashNode( pNtkNew, pNodeOld, pTruth, nVars ) )
|
|
return pNodeOld->pCopy;
|
|
}
|
|
*/
|
|
// set elementary variables
|
|
Abc_ObjForEachFanin( pNodeOld, pFanin, i )
|
|
Hop_IthVar(pMan, i)->pData = pFanin->pCopy;
|
|
// strash the AIG of this node
|
|
Abc_NodeStrash_rec( (Abc_Aig_t *)pNtkNew->pManFunc, Hop_Regular(pRoot) );
|
|
Hop_ConeUnmark_rec( Hop_Regular(pRoot) );
|
|
// return the final node
|
|
return Abc_ObjNotCond( (Abc_Obj_t *)Hop_Regular(pRoot)->pData, Hop_IsComplement(pRoot) );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Copies the topmost levels of the network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Abc_NtkTopmost_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNode, int LevelCut )
|
|
{
|
|
assert( !Abc_ObjIsComplement(pNode) );
|
|
if ( pNode->pCopy )
|
|
return pNode->pCopy;
|
|
if ( pNode->Level <= (unsigned)LevelCut )
|
|
return pNode->pCopy = Abc_NtkCreatePi( pNtkNew );
|
|
Abc_NtkTopmost_rec( pNtkNew, Abc_ObjFanin0(pNode), LevelCut );
|
|
Abc_NtkTopmost_rec( pNtkNew, Abc_ObjFanin1(pNode), LevelCut );
|
|
return pNode->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pNode), Abc_ObjChild1Copy(pNode) );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Copies the topmost levels of the network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkTopmost( Abc_Ntk_t * pNtk, int nLevels )
|
|
{
|
|
Abc_Ntk_t * pNtkNew;
|
|
Abc_Obj_t * pObjNew, * pObj;
|
|
int LevelCut, i;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
// get the cutoff level
|
|
LevelCut = Abc_MaxInt( 0, Abc_AigLevel(pNtk) - nLevels );
|
|
// start the network
|
|
pNtkNew = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 );
|
|
pNtkNew->pName = Extra_UtilStrsav(pNtk->pName);
|
|
// create PIs below the cut and nodes above the cut
|
|
Abc_NtkCleanCopy( pNtk );
|
|
Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
{
|
|
pObjNew = Abc_NtkTopmost_rec( pNtkNew, Abc_ObjFanin0(pObj), LevelCut );
|
|
pObjNew = Abc_ObjNotCond( pObjNew, Abc_ObjFaninC0(pObj) );
|
|
Abc_ObjAddFanin( (pObj->pCopy = Abc_NtkCreatePo(pNtkNew)), pObjNew );
|
|
}
|
|
// add the PO node and name
|
|
Abc_NtkAddDummyPiNames( pNtkNew );
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL );
|
|
// make sure everything is okay
|
|
if ( !Abc_NtkCheck( pNtkNew ) )
|
|
{
|
|
printf( "Abc_NtkTopmost: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkNew );
|
|
return NULL;
|
|
}
|
|
return pNtkNew;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Copies the bottommost levels of the network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Abc_NtkBottommost_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNode, int LevelCut )
|
|
{
|
|
assert( !Abc_ObjIsComplement(pNode) );
|
|
if ( pNode->pCopy )
|
|
return pNode->pCopy;
|
|
Abc_NtkBottommost_rec( pNtkNew, Abc_ObjFanin0(pNode), LevelCut );
|
|
Abc_NtkBottommost_rec( pNtkNew, Abc_ObjFanin1(pNode), LevelCut );
|
|
if ( pNode->Level > (unsigned)LevelCut )
|
|
return NULL;
|
|
return pNode->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pNode), Abc_ObjChild1Copy(pNode) );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Copies the topmost levels of the network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkBottommost( Abc_Ntk_t * pNtk, int nLevels )
|
|
{
|
|
Abc_Ntk_t * pNtkNew;
|
|
Abc_Obj_t * pObj, * pObjNew;
|
|
int i;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
assert( nLevels >= 0 );
|
|
// start the network
|
|
pNtkNew = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 );
|
|
pNtkNew->pName = Extra_UtilStrsav(pNtk->pName);
|
|
// create PIs below the cut and nodes above the cut
|
|
Abc_NtkCleanCopy( pNtk );
|
|
Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
pObj->pCopy = Abc_NtkCreatePi( pNtkNew );
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
Abc_NtkBottommost_rec( pNtkNew, Abc_ObjFanin0(pObj), nLevels );
|
|
// add POs to nodes without fanout
|
|
Abc_NtkForEachNode( pNtkNew, pObjNew, i )
|
|
if ( Abc_ObjFanoutNum(pObjNew) == 0 )
|
|
Abc_ObjAddFanin( Abc_NtkCreatePo(pNtkNew), pObjNew );
|
|
Abc_NtkAddDummyPiNames( pNtkNew );
|
|
Abc_NtkAddDummyPoNames( pNtkNew );
|
|
// make sure everything is okay
|
|
if ( !Abc_NtkCheck( pNtkNew ) )
|
|
{
|
|
printf( "Abc_NtkBottommost: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkNew );
|
|
return NULL;
|
|
}
|
|
return pNtkNew;
|
|
}
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Comparison procedure for two integers.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static int Vec_CompareNodeIds( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 )
|
|
{
|
|
if ( Abc_ObjRegular(*pp1)->Id < Abc_ObjRegular(*pp2)->Id )
|
|
return -1;
|
|
if ( Abc_ObjRegular(*pp1)->Id > Abc_ObjRegular(*pp2)->Id ) //
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Collects the large supergate.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NodeGetSuper( Abc_Obj_t * pNode )
|
|
{
|
|
Vec_Ptr_t * vSuper, * vFront;
|
|
Abc_Obj_t * pAnd, * pFanin;
|
|
int i;
|
|
assert( Abc_ObjIsNode(pNode) && !Abc_ObjIsComplement(pNode) );
|
|
vSuper = Vec_PtrAlloc( 100 );
|
|
// explore the frontier
|
|
vFront = Vec_PtrAlloc( 100 );
|
|
Vec_PtrPush( vFront, pNode );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vFront, pAnd, i )
|
|
{
|
|
pFanin = Abc_ObjChild0(pAnd);
|
|
if ( Abc_ObjIsNode(pFanin) && !Abc_ObjIsComplement(pFanin) && Abc_ObjFanoutNum(pFanin) == 1 )
|
|
Vec_PtrPush( vFront, pFanin );
|
|
else
|
|
Vec_PtrPush( vSuper, pFanin );
|
|
|
|
pFanin = Abc_ObjChild1(pAnd);
|
|
if ( Abc_ObjIsNode(pFanin) && !Abc_ObjIsComplement(pFanin) && Abc_ObjFanoutNum(pFanin) == 1 )
|
|
Vec_PtrPush( vFront, pFanin );
|
|
else
|
|
Vec_PtrPush( vSuper, pFanin );
|
|
}
|
|
Vec_PtrFree( vFront );
|
|
// reverse the array of pointers to start with lower IDs
|
|
vFront = Vec_PtrAlloc( Vec_PtrSize(vSuper) );
|
|
Vec_PtrForEachEntryReverse( Abc_Obj_t *, vSuper, pNode, i )
|
|
Vec_PtrPush( vFront, pNode );
|
|
Vec_PtrFree( vSuper );
|
|
vSuper = vFront;
|
|
// uniquify and return the frontier
|
|
Vec_PtrUniqify( vSuper, (int (*)(const void *, const void *))Vec_CompareNodeIds );
|
|
return vSuper;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Copies the topmost levels of the network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkTopAnd( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vNodes, * vOrder;
|
|
Abc_Ntk_t * pNtkAig;
|
|
Abc_Obj_t * pObj, * pDriver, * pObjPo;
|
|
int i, nNodes;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
// get the first PO
|
|
pObjPo = Abc_NtkPo(pNtk, 0);
|
|
vNodes = Abc_NodeGetSuper( Abc_ObjChild0(pObjPo) );
|
|
assert( Vec_PtrSize(vNodes) >= 2 );
|
|
// start the new network (constants and CIs of the old network will point to the their counterparts in the new network)
|
|
Abc_NtkCleanCopy( pNtk );
|
|
pNtkAig = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 );
|
|
pNtkAig->pName = Extra_UtilStrsav(pNtk->pName);
|
|
pNtkAig->pSpec = Extra_UtilStrsav(pNtk->pSpec);
|
|
Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkAig);
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
Abc_NtkDupObj( pNtkAig, pObj, 1 );
|
|
// restrash the nodes reachable from the roots
|
|
vOrder = Abc_NtkDfsIterNodes( pNtk, vNodes );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vOrder, pObj, i )
|
|
pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkAig->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
Vec_PtrFree( vOrder );
|
|
// finalize the network
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
|
|
{
|
|
pObjPo = Abc_NtkCreatePo(pNtkAig);
|
|
pDriver = Abc_ObjNotCond(Abc_ObjRegular(pObj)->pCopy, Abc_ObjIsComplement(pObj));
|
|
Abc_ObjAddFanin( pObjPo, pDriver );
|
|
Abc_ObjAssignName( pObjPo, Abc_ObjName(pObjPo), NULL );
|
|
}
|
|
Vec_PtrFree( vNodes );
|
|
// perform cleanup if requested
|
|
if ( (nNodes = Abc_AigCleanup((Abc_Aig_t *)pNtkAig->pManFunc)) )
|
|
printf( "Abc_NtkTopAnd(): AIG cleanup removed %d nodes (this is a bug).\n", nNodes );
|
|
// make sure everything is okay
|
|
if ( !Abc_NtkCheck( pNtkAig ) )
|
|
{
|
|
printf( "Abc_NtkStrash: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkAig );
|
|
return NULL;
|
|
}
|
|
return pNtkAig;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Writes the AIG into a file for parsing.]
|
|
|
|
Description [Ordering: c0, pis, ands, pos. ]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkWriteAig( Abc_Ntk_t * pNtk, char * pFileName )
|
|
{
|
|
FILE * pFile;
|
|
Vec_Int_t * vId2Num;
|
|
Abc_Obj_t * pObj;
|
|
int i, iLit;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
assert( Abc_NtkLatchNum(pNtk) == 0 );
|
|
if ( pFileName == NULL )
|
|
pFile = stdout;
|
|
else
|
|
pFile = fopen( pFileName, "w" );
|
|
if ( pFile == NULL )
|
|
{
|
|
printf( "Cannot open output file.\n" );
|
|
return;
|
|
}
|
|
vId2Num = Vec_IntAlloc( 2*Abc_NtkObjNumMax(pNtk) );
|
|
Vec_IntFill( vId2Num, 2*Abc_NtkObjNumMax(pNtk), -1 );
|
|
|
|
iLit = 0;
|
|
Vec_IntWriteEntry( vId2Num, 2*Abc_ObjId(Abc_AigConst1(pNtk))+1, iLit++ );
|
|
Vec_IntWriteEntry( vId2Num, 2*Abc_ObjId(Abc_AigConst1(pNtk))+0, iLit++ );
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
{
|
|
Vec_IntWriteEntry( vId2Num, 2*Abc_ObjId(pObj)+0, iLit++ );
|
|
Vec_IntWriteEntry( vId2Num, 2*Abc_ObjId(pObj)+1, iLit++ );
|
|
}
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
{
|
|
Vec_IntWriteEntry( vId2Num, 2*Abc_ObjId(pObj)+0, iLit++ );
|
|
Vec_IntWriteEntry( vId2Num, 2*Abc_ObjId(pObj)+1, iLit++ );
|
|
}
|
|
fprintf( pFile, "{\n" );
|
|
fprintf( pFile, " \"%s\", ", Abc_NtkName(pNtk) );
|
|
fprintf( pFile, "// pi=%d po=%d and=%d", Abc_NtkPiNum(pNtk), Abc_NtkPoNum(pNtk), Abc_NtkNodeNum(pNtk) );
|
|
fprintf( pFile, "\n" );
|
|
fprintf( pFile, " { " );
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
fprintf( pFile, "\"%s\",", Abc_ObjName(pObj) );
|
|
fprintf( pFile, "NULL },\n" );
|
|
fprintf( pFile, " { " );
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
fprintf( pFile, "\"%s\",", Abc_ObjName(pObj) );
|
|
fprintf( pFile, "NULL },\n" );
|
|
fprintf( pFile, " { " );
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
fprintf( pFile, "%d,", Vec_IntEntry(vId2Num, 2*Abc_ObjFaninId0(pObj) + Abc_ObjFaninC0(pObj)) );
|
|
fprintf( pFile, "0 },\n" );
|
|
fprintf( pFile, " { " );
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
fprintf( pFile, "%d,", Vec_IntEntry(vId2Num, 2*Abc_ObjFaninId1(pObj) + Abc_ObjFaninC1(pObj)) );
|
|
fprintf( pFile, "0 },\n" );
|
|
fprintf( pFile, " { " );
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
fprintf( pFile, "%d,", Vec_IntEntry(vId2Num, 2*Abc_ObjFaninId0(pObj) + Abc_ObjFaninC0(pObj)) );
|
|
fprintf( pFile, "0 },\n" );
|
|
fprintf( pFile, "},\n" );
|
|
if ( pFile != stdout )
|
|
fclose( pFile );
|
|
Vec_IntFree( vId2Num );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis []
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkPutOnTop( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtk2 )
|
|
{
|
|
Vec_Ptr_t * vNodes;
|
|
Abc_Ntk_t * pNtkNew;
|
|
Abc_Obj_t * pObj, * pFanin;
|
|
int i, k;
|
|
assert( Abc_NtkIsLogic(pNtk) );
|
|
assert( Abc_NtkIsLogic(pNtk2) );
|
|
assert( Abc_NtkPoNum(pNtk) == Abc_NtkPiNum(pNtk2) );
|
|
// clean the node copy fields
|
|
Abc_NtkCleanCopy( pNtk );
|
|
Abc_NtkCleanCopy( pNtk2 );
|
|
// duplicate the name and the spec
|
|
pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
|
|
pNtkNew->pName = Extra_UtilStrsav(pNtk->pName);
|
|
pNtkNew->pSpec = Extra_UtilStrsav(pNtk->pSpec);
|
|
// clone CIs/CIs/boxes
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
Abc_NtkDupObj( pNtkNew, pObj, 1 );
|
|
// add internal nodes
|
|
vNodes = Abc_NtkDfs( pNtk, 0 );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
|
|
{
|
|
Abc_NtkDupObj( pNtkNew, pObj, 0 );
|
|
Abc_ObjForEachFanin( pObj, pFanin, k )
|
|
Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
|
|
}
|
|
Vec_PtrFree( vNodes );
|
|
// transfer to the POs
|
|
Abc_NtkForEachPi( pNtk2, pObj, i )
|
|
pObj->pCopy = Abc_ObjChild0Copy( Abc_NtkPo(pNtk, i) );
|
|
// add internal nodes
|
|
vNodes = Abc_NtkDfs( pNtk2, 0 );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
|
|
{
|
|
Abc_NtkDupObj( pNtkNew, pObj, 0 );
|
|
Abc_ObjForEachFanin( pObj, pFanin, k )
|
|
Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
|
|
}
|
|
Vec_PtrFree( vNodes );
|
|
// clone CIs/CIs/boxes
|
|
Abc_NtkForEachPo( pNtk2, pObj, i )
|
|
{
|
|
Abc_NtkDupObj( pNtkNew, pObj, 1 );
|
|
Abc_ObjAddFanin( pObj->pCopy, Abc_ObjChild0Copy(pObj) );
|
|
}
|
|
if ( !Abc_NtkCheck( pNtkNew ) )
|
|
fprintf( stdout, "Abc_NtkPutOnTop(): Network check has failed.\n" );
|
|
return pNtkNew;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|