mirror of https://github.com/YosysHQ/abc.git
803 lines
28 KiB
C
803 lines
28 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [abcVanEijk.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network and node package.]
|
|
|
|
Synopsis [Implementation of van Eijk's method for finding
|
|
signal correspondence: C. A. J. van Eijk. "Sequential equivalence
|
|
checking based on structural similarities", IEEE Trans. CAD,
|
|
vol. 19(7), July 2000, pp. 814-819.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - October 2, 2005.]
|
|
|
|
Revision [$Id: abcVanEijk.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "abc.h"
|
|
#include "fraig.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static Vec_Ptr_t * Abc_NtkVanEijkClasses( Abc_Ntk_t * pNtk, int nFrames, int fVerbose );
|
|
static Vec_Ptr_t * Abc_NtkVanEijkClassesDeriveBase( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCorresp, int nFrames );
|
|
static Vec_Ptr_t * Abc_NtkVanEijkClassesDeriveFirst( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCorresp, int iFrame );
|
|
static int Abc_NtkVanEijkClassesRefine( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCorresp, int iFrame, Vec_Ptr_t * vClasses );
|
|
static void Abc_NtkVanEijkClassesOrder( Vec_Ptr_t * vClasses );
|
|
static int Abc_NtkVanEijkClassesCountPairs( Vec_Ptr_t * vClasses );
|
|
static void Abc_NtkVanEijkClassesTest( Abc_Ntk_t * pNtkSingle, Vec_Ptr_t * vClasses );
|
|
|
|
extern Abc_Ntk_t * Abc_NtkVanEijkFrames( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCorresp, int nFrames, int fAddLast, int fShortNames );
|
|
extern void Abc_NtkVanEijkAddFrame( Abc_Ntk_t * pNtkFrames, Abc_Ntk_t * pNtk, int iFrame, Vec_Ptr_t * vCorresp, Vec_Ptr_t * vOrder, int fShortNames );
|
|
extern Fraig_Man_t * Abc_NtkVanEijkFraig( Abc_Ntk_t * pMulti, int fInit );
|
|
|
|
static Abc_Ntk_t * Abc_NtkVanEijkDeriveExdc( Abc_Ntk_t * pNtk, Vec_Ptr_t * vClasses );
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// INLINED FUNCTIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// sets the correspondence of the node in the frame
|
|
static inline void Abc_NodeVanEijkWriteCorresp( Abc_Obj_t * pNode, Vec_Ptr_t * vCorresp, int iFrame, Abc_Obj_t * pEntry )
|
|
{
|
|
Vec_PtrWriteEntry( vCorresp, iFrame * Abc_NtkObjNumMax(pNode->pNtk) + pNode->Id, pEntry );
|
|
}
|
|
// returns the correspondence of the node in the frame
|
|
static inline Abc_Obj_t * Abc_NodeVanEijkReadCorresp( Abc_Obj_t * pNode, Vec_Ptr_t * vCorresp, int iFrame )
|
|
{
|
|
return Vec_PtrEntry( vCorresp, iFrame * Abc_NtkObjNumMax(pNode->pNtk) + pNode->Id );
|
|
}
|
|
// returns the hash value of the node in the frame
|
|
static inline Abc_Obj_t * Abc_NodeVanEijkHash( Abc_Obj_t * pNode, Vec_Ptr_t * vCorresp, int iFrame )
|
|
{
|
|
return Abc_ObjRegular( Abc_NodeVanEijkReadCorresp(pNode, vCorresp, iFrame)->pCopy );
|
|
}
|
|
// returns the representative node of the class to which the node belongs
|
|
static inline Abc_Obj_t * Abc_NodeVanEijkRepr( Abc_Obj_t * pNode )
|
|
{
|
|
if ( pNode->pNext == NULL )
|
|
return NULL;
|
|
while ( pNode->pNext )
|
|
pNode = pNode->pNext;
|
|
return pNode;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Derives classes of sequentially equivalent nodes.]
|
|
|
|
Description [Performs sequential sweep by combining the equivalent
|
|
nodes. Adds EXDC network to the current network to record the subset
|
|
of unreachable states computed by identifying the equivalent nodes.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkVanEijk( Abc_Ntk_t * pNtk, int nFrames, int fExdc, int fVerbose )
|
|
{
|
|
Fraig_Params_t Params;
|
|
Abc_Ntk_t * pNtkSingle;
|
|
Vec_Ptr_t * vClasses;
|
|
Abc_Ntk_t * pNtkNew;
|
|
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
|
|
// FRAIG the network to get rid of combinational equivalences
|
|
Fraig_ParamsSetDefaultFull( &Params );
|
|
pNtkSingle = Abc_NtkFraig( pNtk, &Params, 0, 0 );
|
|
Abc_AigSetNodePhases( pNtkSingle );
|
|
Abc_NtkCleanNext(pNtkSingle);
|
|
|
|
// get the equivalence classes
|
|
vClasses = Abc_NtkVanEijkClasses( pNtkSingle, nFrames, fVerbose );
|
|
if ( Vec_PtrSize(vClasses) > 0 )
|
|
{
|
|
// transform the network by merging nodes in the equivalence classes
|
|
pNtkNew = Abc_NtkVanEijkFrames( pNtkSingle, NULL, 1, 0, 1 );
|
|
// pNtkNew = Abc_NtkDup( pNtkSingle );
|
|
// derive the EXDC network if asked
|
|
if ( fExdc )
|
|
pNtkNew->pExdc = Abc_NtkVanEijkDeriveExdc( pNtkSingle, vClasses );
|
|
}
|
|
else
|
|
pNtkNew = Abc_NtkDup( pNtkSingle );
|
|
Abc_NtkVanEijkClassesTest( pNtkSingle, vClasses );
|
|
Vec_PtrFree( vClasses );
|
|
|
|
Abc_NtkDelete( pNtkSingle );
|
|
return pNtkNew;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Derives the classes of sequentially equivalent nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkVanEijkClasses( Abc_Ntk_t * pNtkSingle, int nFrames, int fVerbose )
|
|
{
|
|
Fraig_Man_t * pFraig;
|
|
Abc_Ntk_t * pNtkMulti;
|
|
Vec_Ptr_t * vCorresp, * vClasses;
|
|
int nIter, RetValue;
|
|
int nAddFrames = 0;
|
|
|
|
if ( fVerbose )
|
|
printf( "The number of ANDs after FRAIGing = %d.\n", Abc_NtkNodeNum(pNtkSingle) );
|
|
|
|
// get the AIG of the base case
|
|
vCorresp = Vec_PtrAlloc( 100 );
|
|
pNtkMulti = Abc_NtkVanEijkFrames( pNtkSingle, vCorresp, nFrames + nAddFrames, 0, 0 );
|
|
if ( fVerbose )
|
|
printf( "The number of ANDs in %d timeframes = %d.\n", nFrames + nAddFrames, Abc_NtkNodeNum(pNtkMulti) );
|
|
|
|
// FRAIG the initialized frames (labels the nodes of pNtkMulti with FRAIG nodes to be used as hash keys)
|
|
pFraig = Abc_NtkVanEijkFraig( pNtkMulti, 1 );
|
|
Fraig_ManFree( pFraig );
|
|
|
|
// find initial equivalence classes
|
|
vClasses = Abc_NtkVanEijkClassesDeriveBase( pNtkSingle, vCorresp, nFrames + nAddFrames );
|
|
if ( fVerbose )
|
|
printf( "The number of classes in the base case = %5d. Pairs = %8d.\n", Vec_PtrSize(vClasses), Abc_NtkVanEijkClassesCountPairs(vClasses) );
|
|
Abc_NtkDelete( pNtkMulti );
|
|
|
|
// refine the classes using iterative FRAIGing
|
|
for ( nIter = 1; Vec_PtrSize(vClasses) > 0; nIter++ )
|
|
{
|
|
// derive the network with equivalence classes
|
|
Abc_NtkVanEijkClassesOrder( vClasses );
|
|
pNtkMulti = Abc_NtkVanEijkFrames( pNtkSingle, vCorresp, nFrames, 1, 0 );
|
|
// simulate with classes (TO DO)
|
|
|
|
// FRAIG the unitialized frames (labels the nodes of pNtkMulti with FRAIG nodes to be used as hash keys)
|
|
pFraig = Abc_NtkVanEijkFraig( pNtkMulti, 0 );
|
|
Fraig_ManFree( pFraig );
|
|
|
|
// refine the classes
|
|
RetValue = Abc_NtkVanEijkClassesRefine( pNtkSingle, vCorresp, nFrames, vClasses );
|
|
Abc_NtkDelete( pNtkMulti );
|
|
if ( fVerbose )
|
|
printf( "The number of classes after %2d iterations = %5d. Pairs = %8d.\n", nIter, Vec_PtrSize(vClasses), Abc_NtkVanEijkClassesCountPairs(vClasses) );
|
|
// quit if there is no change
|
|
if ( RetValue == 0 )
|
|
break;
|
|
}
|
|
Vec_PtrFree( vCorresp );
|
|
|
|
if ( fVerbose )
|
|
{
|
|
Abc_Obj_t * pObj, * pClass;
|
|
int i, Counter;
|
|
printf( "The classes are: " );
|
|
Vec_PtrForEachEntry( vClasses, pClass, i )
|
|
{
|
|
Counter = 0;
|
|
for ( pObj = pClass; pObj; pObj = pObj->pNext )
|
|
Counter++;
|
|
printf( " %d", Counter );
|
|
/*
|
|
printf( " = {" );
|
|
for ( pObj = pClass; pObj; pObj = pObj->pNext )
|
|
printf( " %d", pObj->Id );
|
|
printf( " } " );
|
|
*/
|
|
}
|
|
printf( "\n" );
|
|
}
|
|
return vClasses;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the equivalence classes of nodes using the base case.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkVanEijkClassesDeriveBase( Abc_Ntk_t * pNtkSingle, Vec_Ptr_t * vCorresp, int nFrames )
|
|
{
|
|
Vec_Ptr_t * vClasses;
|
|
int i, RetValue;
|
|
// derive the classes for the last frame
|
|
vClasses = Abc_NtkVanEijkClassesDeriveFirst( pNtkSingle, vCorresp, nFrames - 1 );
|
|
// refine the classes using other timeframes
|
|
for ( i = 0; i < nFrames - 1; i++ )
|
|
{
|
|
if ( Vec_PtrSize(vClasses) == 0 )
|
|
break;
|
|
RetValue = Abc_NtkVanEijkClassesRefine( pNtkSingle, vCorresp, i, vClasses );
|
|
// if ( RetValue )
|
|
// printf( " yes%s", (i==nFrames-2 ? "\n":"") );
|
|
// else
|
|
// printf( " no%s", (i==nFrames-2 ? "\n":"") );
|
|
}
|
|
return vClasses;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the equivalence classes of nodes.]
|
|
|
|
Description [Original network (pNtk) is mapped into the unfolded frames
|
|
using given array of nodes (vCorresp). Each node in the unfolded frames
|
|
is mapped into a FRAIG node (pNode->pCopy). This procedure uses next
|
|
pointers (pNode->pNext) to combine the nodes into equivalence classes.
|
|
Each class is represented by its representative node with the minimum level.
|
|
Only the last frame is considered.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkVanEijkClassesDeriveFirst( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCorresp, int iFrame )
|
|
{
|
|
Abc_Obj_t * pNode, * pKey, ** ppSlot;
|
|
stmm_table * tTable;
|
|
stmm_generator * gen;
|
|
Vec_Ptr_t * vClasses;
|
|
int i;
|
|
// start the table hashing FRAIG nodes into classes of original network nodes
|
|
tTable = stmm_init_table( st_ptrcmp, st_ptrhash );
|
|
// create the table
|
|
Abc_NtkCleanNext( pNtk );
|
|
Abc_NtkForEachObj( pNtk, pNode, i )
|
|
{
|
|
if ( Abc_ObjIsPo(pNode) )
|
|
continue;
|
|
pKey = Abc_NodeVanEijkHash( pNode, vCorresp, iFrame );
|
|
if ( !stmm_find_or_add( tTable, (char *)pKey, (char ***)&ppSlot ) )
|
|
*ppSlot = NULL;
|
|
pNode->pNext = *ppSlot;
|
|
*ppSlot = pNode;
|
|
}
|
|
// collect only non-trivial classes
|
|
vClasses = Vec_PtrAlloc( 100 );
|
|
stmm_foreach_item( tTable, gen, (char **)&pKey, (char **)&pNode )
|
|
if ( pNode->pNext )
|
|
Vec_PtrPush( vClasses, pNode );
|
|
stmm_free_table( tTable );
|
|
return vClasses;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Refines the classes using one frame.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkVanEijkClassesRefine( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCorresp, int iFrame, Vec_Ptr_t * vClasses )
|
|
{
|
|
Abc_Obj_t * pHeadSame, ** ppTailSame;
|
|
Abc_Obj_t * pHeadDiff, ** ppTailDiff;
|
|
Abc_Obj_t * pNode, * pClass, * pKey;
|
|
int i, k, fChange = 0;
|
|
Vec_PtrForEachEntry( vClasses, pClass, i )
|
|
{
|
|
// assert( pClass->pNext );
|
|
pKey = Abc_NodeVanEijkHash( pClass, vCorresp, iFrame );
|
|
for ( pNode = pClass->pNext; pNode; pNode = pNode->pNext )
|
|
if ( Abc_NodeVanEijkHash(pNode, vCorresp, iFrame) != pKey )
|
|
break;
|
|
if ( pNode == NULL )
|
|
continue;
|
|
fChange = 1;
|
|
// create two classes
|
|
pHeadSame = NULL; ppTailSame = &pHeadSame;
|
|
pHeadDiff = NULL; ppTailDiff = &pHeadDiff;
|
|
for ( pNode = pClass; pNode; pNode = pNode->pNext )
|
|
if ( Abc_NodeVanEijkHash(pNode, vCorresp, iFrame) != pKey )
|
|
*ppTailDiff = pNode, ppTailDiff = &pNode->pNext;
|
|
else
|
|
*ppTailSame = pNode, ppTailSame = &pNode->pNext;
|
|
*ppTailSame = NULL;
|
|
*ppTailDiff = NULL;
|
|
assert( pHeadSame && pHeadDiff );
|
|
// put the updated class back
|
|
Vec_PtrWriteEntry( vClasses, i, pHeadSame );
|
|
// append the new class to be processed later
|
|
Vec_PtrPush( vClasses, pHeadDiff );
|
|
}
|
|
// remove trivial classes
|
|
k = 0;
|
|
Vec_PtrForEachEntry( vClasses, pClass, i )
|
|
if ( pClass->pNext )
|
|
Vec_PtrWriteEntry( vClasses, k++, pClass );
|
|
Vec_PtrShrink( vClasses, k );
|
|
return fChange;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Orders nodes in the equivalence classes.]
|
|
|
|
Description [Finds a min-level representative of each class and puts it last.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkVanEijkClassesOrder( Vec_Ptr_t * vClasses )
|
|
{
|
|
Abc_Obj_t * pClass, * pNode, * pPrev, * pNodeMin, * pPrevMin;
|
|
int i;
|
|
// go through the classes
|
|
Vec_PtrForEachEntry( vClasses, pClass, i )
|
|
{
|
|
assert( pClass->pNext );
|
|
pPrevMin = NULL;
|
|
pNodeMin = pClass;
|
|
for ( pPrev = pClass, pNode = pClass->pNext; pNode; pPrev = pNode, pNode = pNode->pNext )
|
|
if ( pNodeMin->Level >= pNode->Level )
|
|
{
|
|
pPrevMin = pPrev;
|
|
pNodeMin = pNode;
|
|
}
|
|
if ( pNodeMin->pNext == NULL ) // already last
|
|
continue;
|
|
// update the class
|
|
if ( pNodeMin == pClass )
|
|
Vec_PtrWriteEntry( vClasses, i, pNodeMin->pNext );
|
|
else
|
|
pPrevMin->pNext = pNodeMin->pNext;
|
|
// attach the min node
|
|
assert( pPrev->pNext == NULL );
|
|
pPrev->pNext = pNodeMin;
|
|
pNodeMin->pNext = NULL;
|
|
}
|
|
Vec_PtrForEachEntry( vClasses, pClass, i )
|
|
assert( pClass->pNext );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Counts pairs of equivalent nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkVanEijkClassesCountPairs( Vec_Ptr_t * vClasses )
|
|
{
|
|
Abc_Obj_t * pClass, * pNode;
|
|
int i, nPairs = 0;
|
|
Vec_PtrForEachEntry( vClasses, pClass, i )
|
|
{
|
|
assert( pClass->pNext );
|
|
for ( pNode = pClass->pNext; pNode; pNode = pNode->pNext )
|
|
nPairs++;
|
|
}
|
|
return nPairs;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Sanity check for the class representation.]
|
|
|
|
Description [Checks that pNode->pNext is only used in the classes.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkVanEijkClassesTest( Abc_Ntk_t * pNtkSingle, Vec_Ptr_t * vClasses )
|
|
{
|
|
Abc_Obj_t * pClass, * pObj;
|
|
int i;
|
|
Abc_NtkCleanCopy( pNtkSingle );
|
|
Vec_PtrForEachEntry( vClasses, pClass, i )
|
|
for ( pObj = pClass; pObj; pObj = pObj->pNext )
|
|
if ( pObj->pNext )
|
|
pObj->pCopy = (Abc_Obj_t *)1;
|
|
Abc_NtkForEachObj( pNtkSingle, pObj, i )
|
|
assert( (pObj->pCopy != NULL) == (pObj->pNext != NULL) );
|
|
Abc_NtkCleanCopy( pNtkSingle );
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs DFS for one node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkVanEijkDfs_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes )
|
|
{
|
|
Abc_Obj_t * pRepr;
|
|
// skip CI and const
|
|
if ( Abc_ObjFaninNum(pNode) < 2 )
|
|
return;
|
|
// if this node is already visited, skip
|
|
if ( Abc_NodeIsTravIdCurrent( pNode ) )
|
|
return;
|
|
// mark the node as visited
|
|
Abc_NodeSetTravIdCurrent( pNode );
|
|
assert( Abc_ObjIsNode( pNode ) );
|
|
// check if the node belongs to the class
|
|
if ( pRepr = Abc_NodeVanEijkRepr(pNode) )
|
|
Abc_NtkVanEijkDfs_rec( pRepr, vNodes );
|
|
else
|
|
{
|
|
Abc_NtkVanEijkDfs_rec( Abc_ObjFanin0(pNode), vNodes );
|
|
Abc_NtkVanEijkDfs_rec( Abc_ObjFanin1(pNode), vNodes );
|
|
}
|
|
// add the node after the fanins have been added
|
|
Vec_PtrPush( vNodes, pNode );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Finds DFS ordering of nodes using equivalence classes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_NtkVanEijkDfs( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vNodes;
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
vNodes = Vec_PtrAlloc( 100 );
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
Abc_NtkVanEijkDfs_rec( Abc_ObjFanin0(pObj), vNodes );
|
|
return vNodes;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Derives the timeframes of the network.]
|
|
|
|
Description [Returns mapping of the orig nodes into the frame nodes (vCorresp).]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkVanEijkFrames( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCorresp, int nFrames, int fAddLast, int fShortNames )
|
|
{
|
|
char Buffer[100];
|
|
Abc_Ntk_t * pNtkFrames;
|
|
Abc_Obj_t * pLatch, * pLatchNew;
|
|
Vec_Ptr_t * vOrder;
|
|
int i;
|
|
assert( nFrames > 0 );
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
assert( Abc_NtkIsDfsOrdered(pNtk) );
|
|
// clean the array of connections
|
|
if ( vCorresp )
|
|
Vec_PtrFill( vCorresp, (nFrames + fAddLast)*Abc_NtkObjNumMax(pNtk), NULL );
|
|
// start the new network
|
|
pNtkFrames = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG );
|
|
if ( fShortNames )
|
|
{
|
|
pNtkFrames->pName = util_strsav(pNtk->pName);
|
|
pNtkFrames->pSpec = util_strsav(pNtk->pSpec);
|
|
}
|
|
else
|
|
{
|
|
sprintf( Buffer, "%s_%d_frames", pNtk->pName, nFrames + fAddLast );
|
|
pNtkFrames->pName = util_strsav(Buffer);
|
|
}
|
|
// map the constant nodes
|
|
Abc_NtkConst1(pNtk)->pCopy = Abc_NtkConst1(pNtkFrames);
|
|
// create new latches and remember them in the new latches
|
|
Abc_NtkForEachLatch( pNtk, pLatch, i )
|
|
Abc_NtkDupObj( pNtkFrames, pLatch );
|
|
// collect nodes in such a way each class representative goes first
|
|
vOrder = Abc_NtkVanEijkDfs( pNtk );
|
|
// create the timeframes
|
|
for ( i = 0; i < nFrames; i++ )
|
|
Abc_NtkVanEijkAddFrame( pNtkFrames, pNtk, i, vCorresp, vOrder, fShortNames );
|
|
Vec_PtrFree( vOrder );
|
|
// add one more timeframe without class info
|
|
if ( fAddLast )
|
|
Abc_NtkVanEijkAddFrame( pNtkFrames, pNtk, nFrames, vCorresp, NULL, fShortNames );
|
|
// connect the new latches to the outputs of the last frame
|
|
Abc_NtkForEachLatch( pNtk, pLatch, i )
|
|
{
|
|
pLatchNew = Abc_NtkLatch(pNtkFrames, i);
|
|
Abc_ObjAddFanin( pLatchNew, pLatch->pCopy );
|
|
Vec_PtrPush( pNtkFrames->vCis, pLatchNew );
|
|
Vec_PtrPush( pNtkFrames->vCos, pLatchNew );
|
|
Abc_NtkLogicStoreName( pLatchNew, Abc_ObjName(pLatch) );
|
|
pLatch->pNext = NULL;
|
|
}
|
|
// remove dangling nodes
|
|
// Abc_AigCleanup( pNtkFrames->pManFunc );
|
|
// otherwise some external nodes may have dandling pointers
|
|
|
|
// make sure that everything is okay
|
|
if ( !Abc_NtkCheck( pNtkFrames ) )
|
|
printf( "Abc_NtkVanEijkFrames: The network check has failed.\n" );
|
|
return pNtkFrames;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Adds one time frame to the new network.]
|
|
|
|
Description [If the ordering of nodes is given, uses it. Otherwise,
|
|
uses the DSF order of the nodes in the network.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkVanEijkAddFrame( Abc_Ntk_t * pNtkFrames, Abc_Ntk_t * pNtk, int iFrame, Vec_Ptr_t * vCorresp, Vec_Ptr_t * vOrder, int fShortNames )
|
|
{
|
|
char Buffer[10];
|
|
Abc_Obj_t * pNode, * pLatch, * pRepr;
|
|
Vec_Ptr_t * vTemp;
|
|
int i;
|
|
// create the prefix to be added to the node names
|
|
sprintf( Buffer, "_%02d", iFrame );
|
|
// add the new PI nodes
|
|
Abc_NtkForEachPi( pNtk, pNode, i )
|
|
{
|
|
pNode->pCopy = Abc_NtkCreatePi(pNtkFrames);
|
|
if ( fShortNames )
|
|
Abc_NtkLogicStoreName( pNode->pCopy, Abc_ObjName(pNode) );
|
|
else
|
|
Abc_NtkLogicStoreNamePlus( pNode->pCopy, Abc_ObjName(pNode), Buffer );
|
|
}
|
|
// remember the CI mapping
|
|
if ( vCorresp )
|
|
{
|
|
pNode = Abc_NtkConst1(pNtk);
|
|
Abc_NodeVanEijkWriteCorresp( pNode, vCorresp, iFrame, Abc_ObjRegular(pNode->pCopy) );
|
|
Abc_NtkForEachCi( pNtk, pNode, i )
|
|
Abc_NodeVanEijkWriteCorresp( pNode, vCorresp, iFrame, Abc_ObjRegular(pNode->pCopy) );
|
|
}
|
|
// go through the nodes in the given order or in the natural order
|
|
if ( vOrder )
|
|
{
|
|
// add the internal nodes
|
|
Vec_PtrForEachEntry( vOrder, pNode, i )
|
|
{
|
|
if ( pRepr = Abc_NodeVanEijkRepr(pNode) )
|
|
pNode->pCopy = Abc_ObjNotCond( pRepr->pCopy, pNode->fPhase ^ pRepr->fPhase );
|
|
else
|
|
pNode->pCopy = Abc_AigAnd( pNtkFrames->pManFunc, Abc_ObjChild0Copy(pNode), Abc_ObjChild1Copy(pNode) );
|
|
assert( Abc_ObjRegular(pNode->pCopy) != NULL );
|
|
if ( vCorresp )
|
|
Abc_NodeVanEijkWriteCorresp( pNode, vCorresp, iFrame, Abc_ObjRegular(pNode->pCopy) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// add the internal nodes
|
|
Abc_AigForEachAnd( pNtk, pNode, i )
|
|
{
|
|
pNode->pCopy = Abc_AigAnd( pNtkFrames->pManFunc, Abc_ObjChild0Copy(pNode), Abc_ObjChild1Copy(pNode) );
|
|
assert( Abc_ObjRegular(pNode->pCopy) != NULL );
|
|
if ( vCorresp )
|
|
Abc_NodeVanEijkWriteCorresp( pNode, vCorresp, iFrame, Abc_ObjRegular(pNode->pCopy) );
|
|
}
|
|
}
|
|
// add the new POs
|
|
Abc_NtkForEachPo( pNtk, pNode, i )
|
|
{
|
|
pNode->pCopy = Abc_NtkCreatePo(pNtkFrames);
|
|
Abc_ObjAddFanin( pNode->pCopy, Abc_ObjChild0Copy(pNode) );
|
|
if ( fShortNames )
|
|
Abc_NtkLogicStoreName( pNode->pCopy, Abc_ObjName(pNode) );
|
|
else
|
|
Abc_NtkLogicStoreNamePlus( pNode->pCopy, Abc_ObjName(pNode), Buffer );
|
|
}
|
|
// transfer the implementation of the latch drivers to the latches
|
|
vTemp = Vec_PtrAlloc( 100 );
|
|
Abc_NtkForEachLatch( pNtk, pLatch, i )
|
|
Vec_PtrPush( vTemp, Abc_ObjChild0Copy(pLatch) );
|
|
Abc_NtkForEachLatch( pNtk, pLatch, i )
|
|
pLatch->pCopy = Vec_PtrEntry( vTemp, i );
|
|
Vec_PtrFree( vTemp );
|
|
|
|
Abc_AigForEachAnd( pNtk, pNode, i )
|
|
pNode->pCopy = NULL;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Fraigs the network with or without initialization.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Fraig_Man_t * Abc_NtkVanEijkFraig( Abc_Ntk_t * pMulti, int fInit )
|
|
{
|
|
Fraig_Man_t * pMan;
|
|
Fraig_Params_t Params;
|
|
ProgressBar * pProgress;
|
|
Abc_Obj_t * pNode;
|
|
int i;
|
|
assert( Abc_NtkIsStrash(pMulti) );
|
|
// create the FRAIG manager
|
|
Fraig_ParamsSetDefaultFull( &Params );
|
|
pMan = Fraig_ManCreate( &Params );
|
|
// clean the copy fields in the old network
|
|
Abc_NtkCleanCopy( pMulti );
|
|
// map the constant nodes
|
|
Abc_NtkConst1(pMulti)->pCopy = (Abc_Obj_t *)Fraig_ManReadConst1(pMan);
|
|
if ( fInit )
|
|
{
|
|
// map the PI nodes
|
|
Abc_NtkForEachPi( pMulti, pNode, i )
|
|
pNode->pCopy = (Abc_Obj_t *)Fraig_ManReadIthVar(pMan, i);
|
|
// map the latches
|
|
Abc_NtkForEachLatch( pMulti, pNode, i )
|
|
pNode->pCopy = (Abc_Obj_t *)Fraig_NotCond( Fraig_ManReadConst1(pMan), !Abc_LatchIsInit1(pNode) );
|
|
}
|
|
else
|
|
{
|
|
// map the CI nodes
|
|
Abc_NtkForEachCi( pMulti, pNode, i )
|
|
pNode->pCopy = (Abc_Obj_t *)Fraig_ManReadIthVar(pMan, i);
|
|
}
|
|
// perform fraiging
|
|
pProgress = Extra_ProgressBarStart( stdout, Abc_NtkObjNumMax(pMulti) );
|
|
Abc_AigForEachAnd( pMulti, pNode, i )
|
|
{
|
|
Extra_ProgressBarUpdate( pProgress, i, NULL );
|
|
pNode->pCopy = (Abc_Obj_t *)Fraig_NodeAnd( pMan,
|
|
Fraig_NotCond( Abc_ObjFanin0(pNode)->pCopy, Abc_ObjFaninC0(pNode) ),
|
|
Fraig_NotCond( Abc_ObjFanin1(pNode)->pCopy, Abc_ObjFaninC1(pNode) ) );
|
|
}
|
|
Extra_ProgressBarStop( pProgress );
|
|
return pMan;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Create EXDC from the equivalence classes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkVanEijkDeriveExdc( Abc_Ntk_t * pNtk, Vec_Ptr_t * vClasses )
|
|
{
|
|
Abc_Ntk_t * pNtkNew;
|
|
Abc_Obj_t * pClass, * pNode, * pRepr, * pObj;
|
|
Abc_Obj_t * pMiter, * pTotal;
|
|
Vec_Ptr_t * vCone;
|
|
int i, k;
|
|
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
|
|
// start the network
|
|
pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc );
|
|
pNtkNew->pName = util_strsav("exdc");
|
|
pNtkNew->pSpec = NULL;
|
|
|
|
// map the constant nodes
|
|
Abc_NtkConst1(pNtk)->pCopy = Abc_NtkConst1(pNtkNew);
|
|
// for each CI, create PI
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
Abc_NtkLogicStoreName( pObj->pCopy = Abc_NtkCreatePi(pNtkNew), Abc_ObjName(pObj) );
|
|
// cannot add latches here because pLatch->pCopy pointers are used
|
|
|
|
// create the cones for each pair of nodes in an equivalence class
|
|
pTotal = Abc_ObjNot( Abc_NtkConst1(pNtkNew) );
|
|
Vec_PtrForEachEntry( vClasses, pClass, i )
|
|
{
|
|
assert( pClass->pNext );
|
|
// get the cone for the representative node
|
|
pRepr = Abc_NodeVanEijkRepr( pClass );
|
|
if ( Abc_ObjFaninNum(pRepr) == 2 )
|
|
{
|
|
vCone = Abc_NtkDfsNodes( pNtk, &pRepr, 1 );
|
|
Vec_PtrForEachEntry( vCone, pObj, k )
|
|
pObj->pCopy = Abc_AigAnd( pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
Vec_PtrFree( vCone );
|
|
assert( pObj == pRepr );
|
|
}
|
|
// go through the node pairs (representative is last in the list)
|
|
for ( pNode = pClass; pNode != pRepr; pNode = pNode->pNext )
|
|
{
|
|
// get the cone for the node
|
|
assert( Abc_ObjFaninNum(pNode) == 2 );
|
|
vCone = Abc_NtkDfsNodes( pNtk, &pNode, 1 );
|
|
Vec_PtrForEachEntry( vCone, pObj, k )
|
|
pObj->pCopy = Abc_AigAnd( pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
Vec_PtrFree( vCone );
|
|
assert( pObj == pNode );
|
|
// complement if there is phase difference
|
|
pNode->pCopy = Abc_ObjNotCond( pNode->pCopy, pNode->fPhase ^ pRepr->fPhase );
|
|
// add the miter
|
|
pMiter = Abc_AigXor( pNtkNew->pManFunc, pRepr->pCopy, pNode->pCopy );
|
|
}
|
|
// add the miter to the final
|
|
pTotal = Abc_AigOr( pNtkNew->pManFunc, pTotal, pMiter );
|
|
}
|
|
|
|
// for each CO, create PO (skip POs equal to CIs because of name conflict)
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
if ( !Abc_ObjIsCi(Abc_ObjFanin0(pObj)) )
|
|
Abc_NtkLogicStoreName( pObj->pCopy = Abc_NtkCreatePo(pNtkNew), Abc_ObjName(pObj) );
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
Abc_NtkLogicStoreName( pObj->pCopy = Abc_NtkCreatePo(pNtkNew), Abc_ObjNameSuffix( pObj, "_in") );
|
|
|
|
// link to the POs of the network
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
if ( !Abc_ObjIsCi(Abc_ObjFanin0(pObj)) )
|
|
Abc_ObjAddFanin( pObj->pCopy, pTotal );
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
Abc_ObjAddFanin( pObj->pCopy, pTotal );
|
|
|
|
// remove the extra nodes
|
|
Abc_AigCleanup( pNtkNew->pManFunc );
|
|
|
|
// check the result
|
|
if ( !Abc_NtkCheck( pNtkNew ) )
|
|
{
|
|
printf( "Abc_NtkVanEijkDeriveExdc: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkNew );
|
|
return NULL;
|
|
}
|
|
return pNtkNew;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|