mirror of https://github.com/YosysHQ/abc.git
389 lines
13 KiB
C
389 lines
13 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [seqShare.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Construction and manipulation of sequential AIGs.]
|
|
|
|
Synopsis [Latch sharing at the fanout stems.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: seqShare.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "seqInt.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static void Seq_NodeShareFanouts( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes );
|
|
static void Seq_NodeShareOne( Abc_Obj_t * pNode, Abc_InitType_t Init, Vec_Ptr_t * vNodes );
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Transforms the sequential AIG to take fanout sharing into account.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NtkShareFanouts( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vNodes;
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
vNodes = Vec_PtrAlloc( 10 );
|
|
// share the PI latches
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
Seq_NodeShareFanouts( pObj, vNodes );
|
|
// share the node latches
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
Seq_NodeShareFanouts( pObj, vNodes );
|
|
Vec_PtrFree( vNodes );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Transforms the node to take fanout sharing into account.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NodeShareFanouts( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes )
|
|
{
|
|
Abc_Obj_t * pFanout;
|
|
Abc_InitType_t Type;
|
|
int nLatches[4], i;
|
|
// skip the node with only one fanout
|
|
if ( Abc_ObjFanoutNum(pNode) < 2 )
|
|
return;
|
|
// clean the the fanout counters
|
|
for ( i = 0; i < 4; i++ )
|
|
nLatches[i] = 0;
|
|
// find the number of fanouts having latches of each type
|
|
Abc_ObjForEachFanout( pNode, pFanout, i )
|
|
{
|
|
if ( Seq_ObjFanoutL(pNode, pFanout) == 0 )
|
|
continue;
|
|
Type = Seq_NodeGetInitLast( pFanout, Abc_ObjFanoutEdgeNum(pNode, pFanout) );
|
|
nLatches[Type]++;
|
|
}
|
|
// decide what to do
|
|
if ( nLatches[ABC_INIT_ZERO] > 1 && nLatches[ABC_INIT_ONE] > 1 ) // 0-group and 1-group
|
|
{
|
|
Seq_NodeShareOne( pNode, ABC_INIT_ZERO, vNodes ); // shares 0 and DC
|
|
Seq_NodeShareOne( pNode, ABC_INIT_ONE, vNodes ); // shares 1 and DC
|
|
}
|
|
else if ( nLatches[ABC_INIT_ZERO] > 1 ) // 0-group
|
|
Seq_NodeShareOne( pNode, ABC_INIT_ZERO, vNodes ); // shares 0 and DC
|
|
else if ( nLatches[ABC_INIT_ONE] > 1 ) // 1-group
|
|
Seq_NodeShareOne( pNode, ABC_INIT_ONE, vNodes ); // shares 1 and DC
|
|
else if ( nLatches[ABC_INIT_DC] > 1 ) // DC-group
|
|
{
|
|
if ( nLatches[ABC_INIT_ZERO] > 0 )
|
|
Seq_NodeShareOne( pNode, ABC_INIT_ZERO, vNodes ); // shares 0 and DC
|
|
else
|
|
Seq_NodeShareOne( pNode, ABC_INIT_ONE, vNodes ); // shares 1 and DC
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Transforms the node to take fanout sharing into account.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NodeShareOne( Abc_Obj_t * pNode, Abc_InitType_t Init, Vec_Ptr_t * vNodes )
|
|
{
|
|
Vec_Int_t * vNums = Seq_ObjLNums( pNode );
|
|
Vec_Ptr_t * vInits = Seq_NodeLats( pNode );
|
|
Abc_Obj_t * pFanout, * pBuffer;
|
|
Abc_InitType_t Type, InitNew;
|
|
int i;
|
|
// collect the fanouts that satisfy the property (have initial value Init or DC)
|
|
InitNew = ABC_INIT_DC;
|
|
Vec_PtrClear( vNodes );
|
|
Abc_ObjForEachFanout( pNode, pFanout, i )
|
|
{
|
|
if ( Seq_ObjFanoutL(pNode, pFanout) == 0 )
|
|
continue;
|
|
Type = Seq_NodeGetInitLast( pFanout, Abc_ObjFanoutEdgeNum(pNode, pFanout) );
|
|
if ( Type == Init )
|
|
InitNew = Init;
|
|
if ( Type == Init || Type == ABC_INIT_DC )
|
|
{
|
|
Vec_PtrPush( vNodes, pFanout );
|
|
Seq_NodeDeleteLast( pFanout, Abc_ObjFanoutEdgeNum(pNode, pFanout) );
|
|
}
|
|
}
|
|
// create the new buffer
|
|
pBuffer = Abc_NtkCreateNode( pNode->pNtk );
|
|
Abc_ObjAddFanin( pBuffer, pNode );
|
|
|
|
// grow storage for initial states
|
|
Vec_PtrGrow( vInits, 2 * pBuffer->Id + 2 );
|
|
for ( i = Vec_PtrSize(vInits); i < 2 * (int)pBuffer->Id + 2; i++ )
|
|
Vec_PtrPush( vInits, NULL );
|
|
// grow storage for numbers of latches
|
|
Vec_IntGrow( vNums, 2 * pBuffer->Id + 2 );
|
|
for ( i = Vec_IntSize(vNums); i < 2 * (int)pBuffer->Id + 2; i++ )
|
|
Vec_IntPush( vNums, 0 );
|
|
// insert the new latch
|
|
Seq_NodeInsertFirst( pBuffer, 0, InitNew );
|
|
|
|
// redirect the fanouts
|
|
Vec_PtrForEachEntry( vNodes, pFanout, i )
|
|
Abc_ObjPatchFanin( pFanout, pNode, pBuffer );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Maps virtual latches into real latches.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline unsigned Seq_NtkShareLatchesKey( Abc_Obj_t * pObj, Abc_InitType_t Init )
|
|
{
|
|
return (pObj->Id << 2) | Init;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Maps virtual latches into real latches.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Seq_NtkShareLatches_rec( Abc_Ntk_t * pNtk, Abc_Obj_t * pObj, Seq_Lat_t * pRing, int nLatch, stmm_table * tLatchMap )
|
|
{
|
|
Abc_Obj_t * pLatch, * pFanin;
|
|
Abc_InitType_t Init;
|
|
unsigned Key;
|
|
if ( nLatch == 0 )
|
|
return pObj;
|
|
assert( pRing->pLatch == NULL );
|
|
// get the latch on the previous level
|
|
pFanin = Seq_NtkShareLatches_rec( pNtk, pObj, Seq_LatNext(pRing), nLatch - 1, tLatchMap );
|
|
|
|
// get the initial state
|
|
Init = Seq_LatInit( pRing );
|
|
// check if the latch with this initial state exists
|
|
Key = Seq_NtkShareLatchesKey( pFanin, Init );
|
|
if ( stmm_lookup( tLatchMap, (char *)Key, (char **)&pLatch ) )
|
|
return pRing->pLatch = pLatch;
|
|
|
|
// does not exist
|
|
if ( Init != ABC_INIT_DC )
|
|
{
|
|
// check if the don't-care exists
|
|
Key = Seq_NtkShareLatchesKey( pFanin, ABC_INIT_DC );
|
|
if ( stmm_lookup( tLatchMap, (char *)Key, (char **)&pLatch ) ) // yes
|
|
{
|
|
// update the table
|
|
stmm_delete( tLatchMap, (char **)&Key, (char **)&pLatch );
|
|
Key = Seq_NtkShareLatchesKey( pFanin, Init );
|
|
stmm_insert( tLatchMap, (char *)Key, (char *)pLatch );
|
|
// change don't-care to the given value
|
|
pLatch->pData = (void *)Init;
|
|
return pRing->pLatch = pLatch;
|
|
}
|
|
|
|
// add the latch with this value
|
|
pLatch = Abc_NtkCreateLatch( pNtk );
|
|
pLatch->pData = (void *)Init;
|
|
Abc_ObjAddFanin( pLatch, pFanin );
|
|
// add it to the table
|
|
Key = Seq_NtkShareLatchesKey( pFanin, Init );
|
|
stmm_insert( tLatchMap, (char *)Key, (char *)pLatch );
|
|
return pRing->pLatch = pLatch;
|
|
}
|
|
// the init value is the don't-care
|
|
|
|
// check if care values exist
|
|
Key = Seq_NtkShareLatchesKey( pFanin, ABC_INIT_ZERO );
|
|
if ( stmm_lookup( tLatchMap, (char *)Key, (char **)&pLatch ) )
|
|
{
|
|
Seq_LatSetInit( pRing, ABC_INIT_ZERO );
|
|
return pRing->pLatch = pLatch;
|
|
}
|
|
Key = Seq_NtkShareLatchesKey( pFanin, ABC_INIT_ONE );
|
|
if ( stmm_lookup( tLatchMap, (char *)Key, (char **)&pLatch ) )
|
|
{
|
|
Seq_LatSetInit( pRing, ABC_INIT_ONE );
|
|
return pRing->pLatch = pLatch;
|
|
}
|
|
|
|
// create the don't-care latch
|
|
pLatch = Abc_NtkCreateLatch( pNtk );
|
|
pLatch->pData = (void *)ABC_INIT_DC;
|
|
Abc_ObjAddFanin( pLatch, pFanin );
|
|
// add it to the table
|
|
Key = Seq_NtkShareLatchesKey( pFanin, ABC_INIT_DC );
|
|
stmm_insert( tLatchMap, (char *)Key, (char *)pLatch );
|
|
return pRing->pLatch = pLatch;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Maps virtual latches into real latches.]
|
|
|
|
Description [Creates new latches and assigns them to virtual latches
|
|
on the edges of a sequential AIG. The nodes of the new network should
|
|
be created before this procedure is called.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NtkShareLatches( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk )
|
|
{
|
|
Abc_Obj_t * pObj, * pFanin;
|
|
stmm_table * tLatchMap;
|
|
int i;
|
|
assert( Abc_NtkIsSeq( pNtk ) );
|
|
tLatchMap = stmm_init_table( stmm_ptrcmp, stmm_ptrhash );
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
{
|
|
pFanin = Abc_ObjFanin0(pObj);
|
|
Seq_NtkShareLatches_rec( pNtkNew, pFanin->pCopy, Seq_NodeGetRing(pObj,0), Seq_NodeCountLats(pObj,0), tLatchMap );
|
|
pFanin = Abc_ObjFanin1(pObj);
|
|
Seq_NtkShareLatches_rec( pNtkNew, pFanin->pCopy, Seq_NodeGetRing(pObj,1), Seq_NodeCountLats(pObj,1), tLatchMap );
|
|
}
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
Seq_NtkShareLatches_rec( pNtkNew, Abc_ObjFanin0(pObj)->pCopy, Seq_NodeGetRing(pObj,0), Seq_NodeCountLats(pObj,0), tLatchMap );
|
|
stmm_free_table( tLatchMap );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Maps virtual latches into real latches.]
|
|
|
|
Description [Creates new latches and assigns them to virtual latches
|
|
on the edges of a sequential AIG. The nodes of the new network should
|
|
be created before this procedure is called.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NtkShareLatchesMapping( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk, Vec_Ptr_t * vMapAnds, int fFpga )
|
|
{
|
|
Seq_Match_t * pMatch;
|
|
Abc_Obj_t * pObj, * pFanout;
|
|
stmm_table * tLatchMap;
|
|
Vec_Ptr_t * vNodes;
|
|
int i, k;
|
|
assert( Abc_NtkIsSeq( pNtk ) );
|
|
|
|
// start the table
|
|
tLatchMap = stmm_init_table( stmm_ptrcmp, stmm_ptrhash );
|
|
|
|
// create the array of all nodes with sharable fanouts
|
|
vNodes = Vec_PtrAlloc( 100 );
|
|
Vec_PtrPush( vNodes, Abc_NtkConst1(pNtk) );
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
Vec_PtrPush( vNodes, pObj );
|
|
if ( fFpga )
|
|
{
|
|
Vec_PtrForEachEntry( vMapAnds, pObj, i )
|
|
Vec_PtrPush( vNodes, pObj );
|
|
}
|
|
else
|
|
{
|
|
Vec_PtrForEachEntry( vMapAnds, pMatch, i )
|
|
Vec_PtrPush( vNodes, pMatch->pAnd );
|
|
}
|
|
|
|
// process nodes used in the mapping
|
|
Vec_PtrForEachEntry( vNodes, pObj, i )
|
|
{
|
|
// make sure the label is clean
|
|
Abc_ObjForEachFanout( pObj, pFanout, k )
|
|
assert( pFanout->fMarkC == 0 );
|
|
Abc_ObjForEachFanout( pObj, pFanout, k )
|
|
{
|
|
if ( pFanout->fMarkC )
|
|
continue;
|
|
pFanout->fMarkC = 1;
|
|
if ( Abc_ObjFaninId0(pFanout) == pObj->Id )
|
|
Seq_NtkShareLatches_rec( pNtkNew, pObj->pCopy, Seq_NodeGetRing(pFanout,0), Seq_NodeCountLats(pFanout,0), tLatchMap );
|
|
if ( Abc_ObjFaninId1(pFanout) == pObj->Id )
|
|
Seq_NtkShareLatches_rec( pNtkNew, pObj->pCopy, Seq_NodeGetRing(pFanout,1), Seq_NodeCountLats(pFanout,1), tLatchMap );
|
|
}
|
|
// clean the label
|
|
Abc_ObjForEachFanout( pObj, pFanout, k )
|
|
pFanout->fMarkC = 0;
|
|
}
|
|
stmm_free_table( tLatchMap );
|
|
// return to the old array
|
|
Vec_PtrFree( vNodes );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Clean the latches after sharing them.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Seq_NtkShareLatchesClean( Abc_Ntk_t * pNtk )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
assert( Abc_NtkIsSeq( pNtk ) );
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
{
|
|
Seq_NodeCleanLats( pObj, 0 );
|
|
Seq_NodeCleanLats( pObj, 1 );
|
|
}
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
Seq_NodeCleanLats( pObj, 0 );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|