mirror of https://github.com/YosysHQ/abc.git
967 lines
33 KiB
C
967 lines
33 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [abcMap.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network and node package.]
|
|
|
|
Synopsis [Interface with the SC mapping package.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: abcMap.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "base/abc/abc.h"
|
|
#include "base/main/main.h"
|
|
#include "map/mio/mio.h"
|
|
#include "map/mapper/mapper.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static Map_Man_t * Abc_NtkToMap( Abc_Ntk_t * pNtk, double DelayTarget, int fRecovery, float * pSwitching, int fVerbose );
|
|
static Abc_Ntk_t * Abc_NtkFromMap( Map_Man_t * pMan, Abc_Ntk_t * pNtk );
|
|
static Abc_Obj_t * Abc_NodeFromMap_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, int fPhase );
|
|
static Abc_Obj_t * Abc_NodeFromMapPhase_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, int fPhase );
|
|
|
|
static Abc_Ntk_t * Abc_NtkFromMapSuperChoice( Map_Man_t * pMan, Abc_Ntk_t * pNtk );
|
|
static void Abc_NodeSuperChoice( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNode );
|
|
static void Abc_NodeFromMapCutPhase( Abc_Ntk_t * pNtkNew, Map_Cut_t * pCut, int fPhase );
|
|
static Abc_Obj_t * Abc_NodeFromMapSuperChoice_rec( Abc_Ntk_t * pNtkNew, Map_Super_t * pSuper, Abc_Obj_t * pNodePis[], int nNodePis );
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Interface with the mapping package.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkMap( Abc_Ntk_t * pNtk, double DelayTarget, double AreaMulti, double DelayMulti, float LogFan, float Slew, float Gain, int nGatesMin, int fRecovery, int fSwitching, int fVerbose )
|
|
{
|
|
static int fUseMulti = 0;
|
|
int fShowSwitching = 1;
|
|
Abc_Ntk_t * pNtkNew;
|
|
Map_Man_t * pMan;
|
|
Vec_Int_t * vSwitching = NULL;
|
|
float * pSwitching = NULL;
|
|
abctime clk, clkTotal = Abc_Clock();
|
|
Mio_Library_t * pLib = (Mio_Library_t *)Abc_FrameReadLibGen();
|
|
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
// derive library from SCL
|
|
// if the library is created here, it will be deleted when pSuperLib is deleted in Map_SuperLibFree()
|
|
if ( Abc_FrameReadLibScl() && Abc_SclHasDelayInfo( Abc_FrameReadLibScl() ) )
|
|
{
|
|
pLib = Abc_SclDeriveGenlib( Abc_FrameReadLibScl(), Slew, Gain, nGatesMin, fVerbose );
|
|
if ( Abc_FrameReadLibGen() )
|
|
Mio_LibraryTransferDelays( (Mio_Library_t *)Abc_FrameReadLibGen(), pLib );
|
|
// remove supergate library
|
|
Map_SuperLibFree( (Map_SuperLib_t *)Abc_FrameReadLibSuper() );
|
|
Abc_FrameSetLibSuper( NULL );
|
|
}
|
|
// quit if there is no library
|
|
if ( pLib == NULL )
|
|
{
|
|
printf( "The current library is not available.\n" );
|
|
return 0;
|
|
}
|
|
if ( AreaMulti != 0.0 )
|
|
fUseMulti = 1, printf( "The cell areas are multiplied by the factor: <num_fanins> ^ (%.2f).\n", AreaMulti );
|
|
if ( DelayMulti != 0.0 )
|
|
fUseMulti = 1, printf( "The cell delays are multiplied by the factor: <num_fanins> ^ (%.2f).\n", DelayMulti );
|
|
|
|
// penalize large gates by increasing their area
|
|
if ( AreaMulti != 0.0 )
|
|
Mio_LibraryMultiArea( pLib, AreaMulti );
|
|
if ( DelayMulti != 0.0 )
|
|
Mio_LibraryMultiDelay( pLib, DelayMulti );
|
|
|
|
// derive the supergate library
|
|
if ( fUseMulti || Abc_FrameReadLibSuper() == NULL )
|
|
{
|
|
if ( fVerbose )
|
|
printf( "Converting \"%s\" into supergate library \"%s\".\n",
|
|
Mio_LibraryReadName(pLib), Extra_FileNameGenericAppend(Mio_LibraryReadName(pLib), ".super") );
|
|
// compute supergate library to be used for mapping
|
|
Map_SuperLibDeriveFromGenlib( pLib, fVerbose );
|
|
}
|
|
|
|
// return the library to normal
|
|
if ( AreaMulti != 0.0 )
|
|
Mio_LibraryMultiArea( (Mio_Library_t *)Abc_FrameReadLibGen(), -AreaMulti );
|
|
if ( DelayMulti != 0.0 )
|
|
Mio_LibraryMultiDelay( (Mio_Library_t *)Abc_FrameReadLibGen(), -DelayMulti );
|
|
|
|
// print a warning about choice nodes
|
|
if ( fVerbose && Abc_NtkGetChoiceNum( pNtk ) )
|
|
printf( "Performing mapping with choices.\n" );
|
|
|
|
// compute switching activity
|
|
fShowSwitching |= fSwitching;
|
|
if ( fShowSwitching )
|
|
{
|
|
extern Vec_Int_t * Sim_NtkComputeSwitching( Abc_Ntk_t * pNtk, int nPatterns );
|
|
vSwitching = Sim_NtkComputeSwitching( pNtk, 4096 );
|
|
pSwitching = (float *)vSwitching->pArray;
|
|
}
|
|
|
|
// perform the mapping
|
|
pMan = Abc_NtkToMap( pNtk, DelayTarget, fRecovery, pSwitching, fVerbose );
|
|
if ( pSwitching ) Vec_IntFree( vSwitching );
|
|
if ( pMan == NULL )
|
|
return NULL;
|
|
clk = Abc_Clock();
|
|
Map_ManSetSwitching( pMan, fSwitching );
|
|
if ( LogFan != 0 )
|
|
Map_ManCreateNodeDelays( pMan, LogFan );
|
|
if ( !Map_Mapping( pMan ) )
|
|
{
|
|
Map_ManFree( pMan );
|
|
return NULL;
|
|
}
|
|
// Map_ManPrintStatsToFile( pNtk->pSpec, Map_ManReadAreaFinal(pMan), Map_ManReadRequiredGlo(pMan), Abc_Clock()-clk );
|
|
|
|
// reconstruct the network after mapping
|
|
pNtkNew = Abc_NtkFromMap( pMan, pNtk );
|
|
Map_ManFree( pMan );
|
|
if ( pNtkNew == NULL )
|
|
return NULL;
|
|
|
|
if ( pNtk->pExdc )
|
|
pNtkNew->pExdc = Abc_NtkDup( pNtk->pExdc );
|
|
if ( fVerbose )
|
|
{
|
|
ABC_PRT( "Total runtime", Abc_Clock() - clkTotal );
|
|
}
|
|
|
|
// make sure that everything is okay
|
|
if ( !Abc_NtkCheck( pNtkNew ) )
|
|
{
|
|
printf( "Abc_NtkMap: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkNew );
|
|
return NULL;
|
|
}
|
|
return pNtkNew;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Load the network into manager.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Map_Time_t * Abc_NtkMapCopyCiArrival( Abc_Ntk_t * pNtk, Abc_Time_t * ppTimes )
|
|
{
|
|
Map_Time_t * p;
|
|
int i;
|
|
p = ABC_CALLOC( Map_Time_t, Abc_NtkCiNum(pNtk) );
|
|
for ( i = 0; i < Abc_NtkCiNum(pNtk); i++ )
|
|
{
|
|
p->Fall = ppTimes[i].Fall;
|
|
p->Rise = ppTimes[i].Rise;
|
|
p->Worst = Abc_MaxFloat( p->Fall, p->Rise );
|
|
}
|
|
ABC_FREE( ppTimes );
|
|
return p;
|
|
}
|
|
Map_Time_t * Abc_NtkMapCopyCoRequired( Abc_Ntk_t * pNtk, Abc_Time_t * ppTimes )
|
|
{
|
|
Map_Time_t * p;
|
|
int i;
|
|
p = ABC_CALLOC( Map_Time_t, Abc_NtkCoNum(pNtk) );
|
|
for ( i = 0; i < Abc_NtkCoNum(pNtk); i++ )
|
|
{
|
|
p->Fall = ppTimes[i].Fall;
|
|
p->Rise = ppTimes[i].Rise;
|
|
p->Worst = Abc_MaxFloat( p->Fall, p->Rise );
|
|
}
|
|
ABC_FREE( ppTimes );
|
|
return p;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Load the network into manager.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Map_Man_t * Abc_NtkToMap( Abc_Ntk_t * pNtk, double DelayTarget, int fRecovery, float * pSwitching, int fVerbose )
|
|
{
|
|
Map_Man_t * pMan;
|
|
Map_Node_t * pNodeMap;
|
|
Vec_Ptr_t * vNodes;
|
|
Abc_Obj_t * pNode, * pFanin, * pPrev;
|
|
int i;
|
|
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
|
|
// start the mapping manager and set its parameters
|
|
pMan = Map_ManCreate( Abc_NtkPiNum(pNtk) + Abc_NtkLatchNum(pNtk) - pNtk->nBarBufs, Abc_NtkPoNum(pNtk) + Abc_NtkLatchNum(pNtk) - pNtk->nBarBufs, fVerbose );
|
|
if ( pMan == NULL )
|
|
return NULL;
|
|
Map_ManSetAreaRecovery( pMan, fRecovery );
|
|
Map_ManSetOutputNames( pMan, Abc_NtkCollectCioNames(pNtk, 1) );
|
|
Map_ManSetDelayTarget( pMan, (float)DelayTarget );
|
|
Map_ManSetInputArrivals( pMan, Abc_NtkMapCopyCiArrival(pNtk, Abc_NtkGetCiArrivalTimes(pNtk)) );
|
|
Map_ManSetOutputRequireds( pMan, Abc_NtkMapCopyCoRequired(pNtk, Abc_NtkGetCoRequiredTimes(pNtk)) );
|
|
|
|
// create PIs and remember them in the old nodes
|
|
Abc_NtkCleanCopy( pNtk );
|
|
Abc_AigConst1(pNtk)->pCopy = (Abc_Obj_t *)Map_ManReadConst1(pMan);
|
|
Abc_NtkForEachCi( pNtk, pNode, i )
|
|
{
|
|
if ( i == Abc_NtkCiNum(pNtk) - pNtk->nBarBufs )
|
|
break;
|
|
pNodeMap = Map_ManReadInputs(pMan)[i];
|
|
pNode->pCopy = (Abc_Obj_t *)pNodeMap;
|
|
if ( pSwitching )
|
|
Map_NodeSetSwitching( pNodeMap, pSwitching[pNode->Id] );
|
|
}
|
|
|
|
// load the AIG into the mapper
|
|
vNodes = Abc_AigDfsMap( pNtk );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i )
|
|
{
|
|
if ( Abc_ObjIsLatch(pNode) )
|
|
{
|
|
pFanin = Abc_ObjFanin0(pNode);
|
|
pNodeMap = Map_NodeBuf( pMan, Map_NotCond( Abc_ObjFanin0(pFanin)->pCopy, (int)Abc_ObjFaninC0(pFanin) ) );
|
|
Abc_ObjFanout0(pNode)->pCopy = (Abc_Obj_t *)pNodeMap;
|
|
continue;
|
|
}
|
|
assert( Abc_ObjIsNode(pNode) );
|
|
// add the node to the mapper
|
|
pNodeMap = Map_NodeAnd( pMan,
|
|
Map_NotCond( Abc_ObjFanin0(pNode)->pCopy, (int)Abc_ObjFaninC0(pNode) ),
|
|
Map_NotCond( Abc_ObjFanin1(pNode)->pCopy, (int)Abc_ObjFaninC1(pNode) ) );
|
|
assert( pNode->pCopy == NULL );
|
|
// remember the node
|
|
pNode->pCopy = (Abc_Obj_t *)pNodeMap;
|
|
if ( pSwitching )
|
|
Map_NodeSetSwitching( pNodeMap, pSwitching[pNode->Id] );
|
|
// set up the choice node
|
|
if ( Abc_AigNodeIsChoice( pNode ) )
|
|
for ( pPrev = pNode, pFanin = (Abc_Obj_t *)pNode->pData; pFanin; pPrev = pFanin, pFanin = (Abc_Obj_t *)pFanin->pData )
|
|
{
|
|
Map_NodeSetNextE( (Map_Node_t *)pPrev->pCopy, (Map_Node_t *)pFanin->pCopy );
|
|
Map_NodeSetRepr( (Map_Node_t *)pFanin->pCopy, (Map_Node_t *)pNode->pCopy );
|
|
}
|
|
}
|
|
assert( Map_ManReadBufNum(pMan) == pNtk->nBarBufs );
|
|
Vec_PtrFree( vNodes );
|
|
|
|
// set the primary outputs in the required phase
|
|
Abc_NtkForEachCo( pNtk, pNode, i )
|
|
{
|
|
if ( i == Abc_NtkCoNum(pNtk) - pNtk->nBarBufs )
|
|
break;
|
|
Map_ManReadOutputs(pMan)[i] = Map_NotCond( (Map_Node_t *)Abc_ObjFanin0(pNode)->pCopy, (int)Abc_ObjFaninC0(pNode) );
|
|
}
|
|
return pMan;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Creates the mapped network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Abc_NodeFromMapSuper_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, Map_Super_t * pSuper, Abc_Obj_t * pNodePis[], int nNodePis )
|
|
{
|
|
Mio_Library_t * pLib = (Mio_Library_t *)Abc_FrameReadLibGen();
|
|
Mio_Gate_t * pRoot;
|
|
Map_Super_t ** ppFanins;
|
|
Abc_Obj_t * pNodeNew, * pNodeFanin;
|
|
int nFanins, Number, i;
|
|
|
|
// get the parameters of the supergate
|
|
pRoot = Map_SuperReadRoot(pSuper);
|
|
if ( pRoot == NULL )
|
|
{
|
|
Number = Map_SuperReadNum(pSuper);
|
|
if ( Number < nNodePis )
|
|
{
|
|
return pNodePis[Number];
|
|
}
|
|
else
|
|
{
|
|
// assert( 0 );
|
|
/* It might happen that a super gate with 5 inputs is constructed that
|
|
* actually depends only on the first four variables; i.e the fifth is a
|
|
* don't care -- in that case we connect constant node for the fifth
|
|
* (since the cut only has 4 variables). An interesting question is what
|
|
* if the first variable (and not the fifth one is the redundant one;
|
|
* can that happen?) */
|
|
return Abc_NtkCreateNodeConst0(pNtkNew);
|
|
}
|
|
}
|
|
pRoot = Mio_LibraryReadGateByName( pLib, Mio_GateReadName(pRoot), NULL );
|
|
|
|
// get information about the fanins of the supergate
|
|
nFanins = Map_SuperReadFaninNum( pSuper );
|
|
ppFanins = Map_SuperReadFanins( pSuper );
|
|
// create a new node with these fanins
|
|
pNodeNew = Abc_NtkCreateNode( pNtkNew );
|
|
for ( i = 0; i < nFanins; i++ )
|
|
{
|
|
pNodeFanin = Abc_NodeFromMapSuper_rec( pNtkNew, pNodeMap, ppFanins[i], pNodePis, nNodePis );
|
|
Abc_ObjAddFanin( pNodeNew, pNodeFanin );
|
|
}
|
|
pNodeNew->pData = pRoot;
|
|
return pNodeNew;
|
|
}
|
|
Abc_Obj_t * Abc_NodeFromMapPhase_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, int fPhase )
|
|
{
|
|
Abc_Obj_t * pNodePIs[10];
|
|
Abc_Obj_t * pNodeNew;
|
|
Map_Node_t ** ppLeaves;
|
|
Map_Cut_t * pCutBest;
|
|
Map_Super_t * pSuperBest;
|
|
unsigned uPhaseBest;
|
|
int i, fInvPin, nLeaves;
|
|
|
|
// make sure the node can be implemented in this phase
|
|
assert( Map_NodeReadCutBest(pNodeMap, fPhase) != NULL || Map_NodeIsConst(pNodeMap) );
|
|
// check if the phase is already implemented
|
|
pNodeNew = (Abc_Obj_t *)Map_NodeReadData( pNodeMap, fPhase );
|
|
if ( pNodeNew )
|
|
return pNodeNew;
|
|
|
|
// get the information about the best cut
|
|
pCutBest = Map_NodeReadCutBest( pNodeMap, fPhase );
|
|
pSuperBest = Map_CutReadSuperBest( pCutBest, fPhase );
|
|
uPhaseBest = Map_CutReadPhaseBest( pCutBest, fPhase );
|
|
nLeaves = Map_CutReadLeavesNum( pCutBest );
|
|
ppLeaves = Map_CutReadLeaves( pCutBest );
|
|
|
|
// collect the PI nodes
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
{
|
|
fInvPin = ((uPhaseBest & (1 << i)) > 0);
|
|
pNodePIs[i] = Abc_NodeFromMap_rec( pNtkNew, ppLeaves[i], !fInvPin );
|
|
assert( pNodePIs[i] != NULL );
|
|
}
|
|
|
|
// implement the supergate
|
|
pNodeNew = Abc_NodeFromMapSuper_rec( pNtkNew, pNodeMap, pSuperBest, pNodePIs, nLeaves );
|
|
Map_NodeSetData( pNodeMap, fPhase, (char *)pNodeNew );
|
|
return pNodeNew;
|
|
}
|
|
Abc_Obj_t * Abc_NodeFromMap_rec( Abc_Ntk_t * pNtkNew, Map_Node_t * pNodeMap, int fPhase )
|
|
{
|
|
Abc_Obj_t * pNodeNew, * pNodeInv;
|
|
|
|
// check the case of constant node
|
|
if ( Map_NodeIsConst(pNodeMap) )
|
|
{
|
|
pNodeNew = fPhase? Abc_NtkCreateNodeConst1(pNtkNew) : Abc_NtkCreateNodeConst0(pNtkNew);
|
|
if ( pNodeNew->pData == NULL )
|
|
printf( "Error creating mapped network: Library does not have a constant %d gate.\n", fPhase );
|
|
return pNodeNew;
|
|
}
|
|
|
|
// check if the phase is already implemented
|
|
pNodeNew = (Abc_Obj_t *)Map_NodeReadData( pNodeMap, fPhase );
|
|
if ( pNodeNew )
|
|
return pNodeNew;
|
|
|
|
// implement the node if the best cut is assigned
|
|
if ( Map_NodeReadCutBest(pNodeMap, fPhase) != NULL )
|
|
return Abc_NodeFromMapPhase_rec( pNtkNew, pNodeMap, fPhase );
|
|
|
|
// if the cut is not assigned, implement the node
|
|
assert( Map_NodeReadCutBest(pNodeMap, !fPhase) != NULL || Map_NodeIsConst(pNodeMap) );
|
|
pNodeNew = Abc_NodeFromMapPhase_rec( pNtkNew, pNodeMap, !fPhase );
|
|
|
|
// add the inverter
|
|
pNodeInv = Abc_NtkCreateNode( pNtkNew );
|
|
Abc_ObjAddFanin( pNodeInv, pNodeNew );
|
|
pNodeInv->pData = Mio_LibraryReadInv(Map_ManReadGenLib(Map_NodeReadMan(pNodeMap)));
|
|
|
|
// set the inverter
|
|
Map_NodeSetData( pNodeMap, fPhase, (char *)pNodeInv );
|
|
return pNodeInv;
|
|
}
|
|
Abc_Ntk_t * Abc_NtkFromMap( Map_Man_t * pMan, Abc_Ntk_t * pNtk )
|
|
{
|
|
Abc_Ntk_t * pNtkNew;
|
|
Map_Node_t * pNodeMap;
|
|
Abc_Obj_t * pNode, * pNodeNew;
|
|
int i, nDupGates;
|
|
assert( Map_ManReadBufNum(pMan) == pNtk->nBarBufs );
|
|
// create the new network
|
|
pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC, ABC_FUNC_MAP );
|
|
// make the mapper point to the new network
|
|
Map_ManCleanData( pMan );
|
|
Abc_NtkForEachCi( pNtk, pNode, i )
|
|
{
|
|
if ( i >= Abc_NtkCiNum(pNtk) - pNtk->nBarBufs )
|
|
break;
|
|
Map_NodeSetData( Map_ManReadInputs(pMan)[i], 1, (char *)pNode->pCopy );
|
|
}
|
|
Abc_NtkForEachCi( pNtk, pNode, i )
|
|
{
|
|
if ( i < Abc_NtkCiNum(pNtk) - pNtk->nBarBufs )
|
|
continue;
|
|
Map_NodeSetData( Map_ManReadBufs(pMan)[i - (Abc_NtkCiNum(pNtk) - pNtk->nBarBufs)], 1, (char *)pNode->pCopy );
|
|
}
|
|
// assign the mapping of the required phase to the POs
|
|
Abc_NtkForEachCo( pNtk, pNode, i )
|
|
{
|
|
if ( i < Abc_NtkCoNum(pNtk) - pNtk->nBarBufs )
|
|
continue;
|
|
pNodeMap = Map_ManReadBufDriver( pMan, i - (Abc_NtkCoNum(pNtk) - pNtk->nBarBufs) );
|
|
pNodeNew = Abc_NodeFromMap_rec( pNtkNew, Map_Regular(pNodeMap), !Map_IsComplement(pNodeMap) );
|
|
assert( !Abc_ObjIsComplement(pNodeNew) );
|
|
Abc_ObjAddFanin( pNode->pCopy, pNodeNew );
|
|
}
|
|
Abc_NtkForEachCo( pNtk, pNode, i )
|
|
{
|
|
if ( i >= Abc_NtkCoNum(pNtk) - pNtk->nBarBufs )
|
|
break;
|
|
pNodeMap = Map_ManReadOutputs(pMan)[i];
|
|
pNodeNew = Abc_NodeFromMap_rec( pNtkNew, Map_Regular(pNodeMap), !Map_IsComplement(pNodeMap) );
|
|
assert( !Abc_ObjIsComplement(pNodeNew) );
|
|
Abc_ObjAddFanin( pNode->pCopy, pNodeNew );
|
|
}
|
|
// decouple the PO driver nodes to reduce the number of levels
|
|
nDupGates = Abc_NtkLogicMakeSimpleCos( pNtkNew, 1 );
|
|
// if ( nDupGates && Map_ManReadVerbose(pMan) )
|
|
// printf( "Duplicated %d gates to decouple the CO drivers.\n", nDupGates );
|
|
return pNtkNew;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Interface with the mapping package.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkSuperChoice( Abc_Ntk_t * pNtk )
|
|
{
|
|
Abc_Ntk_t * pNtkNew;
|
|
|
|
Map_Man_t * pMan;
|
|
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
|
|
// check that the library is available
|
|
if ( Abc_FrameReadLibGen() == NULL )
|
|
{
|
|
printf( "The current library is not available.\n" );
|
|
return 0;
|
|
}
|
|
|
|
// derive the supergate library
|
|
if ( Abc_FrameReadLibSuper() == NULL && Abc_FrameReadLibGen() )
|
|
{
|
|
// printf( "A simple supergate library is derived from gate library \"%s\".\n",
|
|
// Mio_LibraryReadName((Mio_Library_t *)Abc_FrameReadLibGen()) );
|
|
Map_SuperLibDeriveFromGenlib( (Mio_Library_t *)Abc_FrameReadLibGen(), 0 );
|
|
}
|
|
|
|
// print a warning about choice nodes
|
|
if ( Abc_NtkGetChoiceNum( pNtk ) )
|
|
printf( "Performing mapping with choices.\n" );
|
|
|
|
// perform the mapping
|
|
pMan = Abc_NtkToMap( pNtk, -1, 1, NULL, 0 );
|
|
if ( pMan == NULL )
|
|
return NULL;
|
|
if ( !Map_Mapping( pMan ) )
|
|
{
|
|
Map_ManFree( pMan );
|
|
return NULL;
|
|
}
|
|
|
|
// reconstruct the network after mapping
|
|
pNtkNew = Abc_NtkFromMapSuperChoice( pMan, pNtk );
|
|
if ( pNtkNew == NULL )
|
|
return NULL;
|
|
Map_ManFree( pMan );
|
|
|
|
// make sure that everything is okay
|
|
if ( !Abc_NtkCheck( pNtkNew ) )
|
|
{
|
|
printf( "Abc_NtkMap: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkNew );
|
|
return NULL;
|
|
}
|
|
return pNtkNew;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Creates the mapped network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkFromMapSuperChoice( Map_Man_t * pMan, Abc_Ntk_t * pNtk )
|
|
{
|
|
extern Abc_Ntk_t * Abc_NtkMulti( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax, int fCnf, int fMulti, int fSimple, int fFactor );
|
|
ProgressBar * pProgress;
|
|
Abc_Ntk_t * pNtkNew, * pNtkNew2;
|
|
Abc_Obj_t * pNode;
|
|
int i;
|
|
|
|
// save the pointer to the mapped nodes
|
|
Abc_NtkForEachCi( pNtk, pNode, i )
|
|
pNode->pNext = pNode->pCopy;
|
|
Abc_NtkForEachPo( pNtk, pNode, i )
|
|
pNode->pNext = pNode->pCopy;
|
|
Abc_NtkForEachNode( pNtk, pNode, i )
|
|
pNode->pNext = pNode->pCopy;
|
|
|
|
// duplicate the network
|
|
pNtkNew2 = Abc_NtkDup( pNtk );
|
|
pNtkNew = Abc_NtkMulti( pNtkNew2, 0, 20, 0, 0, 1, 0 );
|
|
if ( !Abc_NtkBddToSop( pNtkNew, 0 ) )
|
|
{
|
|
printf( "Abc_NtkFromMapSuperChoice(): Converting to SOPs has failed.\n" );
|
|
return NULL;
|
|
}
|
|
|
|
// set the old network to point to the new network
|
|
Abc_NtkForEachCi( pNtk, pNode, i )
|
|
pNode->pCopy = pNode->pCopy->pCopy;
|
|
Abc_NtkForEachPo( pNtk, pNode, i )
|
|
pNode->pCopy = pNode->pCopy->pCopy;
|
|
Abc_NtkForEachNode( pNtk, pNode, i )
|
|
pNode->pCopy = pNode->pCopy->pCopy;
|
|
Abc_NtkDelete( pNtkNew2 );
|
|
|
|
// set the pointers from the mapper to the new nodes
|
|
Abc_NtkForEachCi( pNtk, pNode, i )
|
|
{
|
|
Map_NodeSetData( Map_ManReadInputs(pMan)[i], 0, (char *)Abc_NtkCreateNodeInv(pNtkNew,pNode->pCopy) );
|
|
Map_NodeSetData( Map_ManReadInputs(pMan)[i], 1, (char *)pNode->pCopy );
|
|
}
|
|
Abc_NtkForEachNode( pNtk, pNode, i )
|
|
{
|
|
// if ( Abc_NodeIsConst(pNode) )
|
|
// continue;
|
|
Map_NodeSetData( (Map_Node_t *)pNode->pNext, 0, (char *)Abc_NtkCreateNodeInv(pNtkNew,pNode->pCopy) );
|
|
Map_NodeSetData( (Map_Node_t *)pNode->pNext, 1, (char *)pNode->pCopy );
|
|
}
|
|
|
|
// assign the mapping of the required phase to the POs
|
|
pProgress = Extra_ProgressBarStart( stdout, Abc_NtkObjNumMax(pNtk) );
|
|
Abc_NtkForEachNode( pNtk, pNode, i )
|
|
{
|
|
Extra_ProgressBarUpdate( pProgress, i, NULL );
|
|
// if ( Abc_NodeIsConst(pNode) )
|
|
// continue;
|
|
Abc_NodeSuperChoice( pNtkNew, pNode );
|
|
}
|
|
Extra_ProgressBarStop( pProgress );
|
|
return pNtkNew;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Creates the mapped network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NodeSuperChoice( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNode )
|
|
{
|
|
Map_Node_t * pMapNode = (Map_Node_t *)pNode->pNext;
|
|
Map_Cut_t * pCuts, * pTemp;
|
|
|
|
pCuts = Map_NodeReadCuts(pMapNode);
|
|
for ( pTemp = Map_CutReadNext(pCuts); pTemp; pTemp = Map_CutReadNext(pTemp) )
|
|
{
|
|
Abc_NodeFromMapCutPhase( pNtkNew, pTemp, 0 );
|
|
Abc_NodeFromMapCutPhase( pNtkNew, pTemp, 1 );
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Constructs the nodes corrresponding to one node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NodeFromMapCutPhase( Abc_Ntk_t * pNtkNew, Map_Cut_t * pCut, int fPhase )
|
|
{
|
|
Abc_Obj_t * pNodePIs[10];
|
|
Map_Node_t ** ppLeaves;
|
|
Map_Super_t * pSuperBest;
|
|
unsigned uPhaseBest;
|
|
int i, fInvPin, nLeaves;
|
|
|
|
pSuperBest = Map_CutReadSuperBest( pCut, fPhase );
|
|
if ( pSuperBest == NULL )
|
|
return;
|
|
|
|
// get the information about the best cut
|
|
uPhaseBest = Map_CutReadPhaseBest( pCut, fPhase );
|
|
nLeaves = Map_CutReadLeavesNum( pCut );
|
|
ppLeaves = Map_CutReadLeaves( pCut );
|
|
|
|
// collect the PI nodes
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
{
|
|
fInvPin = ((uPhaseBest & (1 << i)) > 0);
|
|
pNodePIs[i] = (Abc_Obj_t *)Map_NodeReadData( ppLeaves[i], !fInvPin );
|
|
assert( pNodePIs[i] != NULL );
|
|
}
|
|
|
|
// implement the supergate
|
|
Abc_NodeFromMapSuperChoice_rec( pNtkNew, pSuperBest, pNodePIs, nLeaves );
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Constructs the nodes corrresponding to one supergate.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Abc_NodeFromMapSuperChoice_rec( Abc_Ntk_t * pNtkNew, Map_Super_t * pSuper, Abc_Obj_t * pNodePis[], int nNodePis )
|
|
{
|
|
Mio_Library_t * pLib = (Mio_Library_t *)Abc_FrameReadLibGen();
|
|
Mio_Gate_t * pRoot;
|
|
Map_Super_t ** ppFanins;
|
|
Abc_Obj_t * pNodeNew, * pNodeFanin;
|
|
int nFanins, Number, i;
|
|
|
|
// get the parameters of the supergate
|
|
pRoot = Map_SuperReadRoot(pSuper);
|
|
if ( pRoot == NULL )
|
|
{
|
|
Number = Map_SuperReadNum(pSuper);
|
|
if ( Number < nNodePis )
|
|
{
|
|
return pNodePis[Number];
|
|
}
|
|
else
|
|
{
|
|
// assert( 0 );
|
|
/* It might happen that a super gate with 5 inputs is constructed that
|
|
* actually depends only on the first four variables; i.e the fifth is a
|
|
* don't care -- in that case we connect constant node for the fifth
|
|
* (since the cut only has 4 variables). An interesting question is what
|
|
* if the first variable (and not the fifth one is the redundant one;
|
|
* can that happen?) */
|
|
return Abc_NtkCreateNodeConst0(pNtkNew);
|
|
}
|
|
}
|
|
pRoot = Mio_LibraryReadGateByName( pLib, Mio_GateReadName(pRoot), NULL );
|
|
|
|
// get information about the fanins of the supergate
|
|
nFanins = Map_SuperReadFaninNum( pSuper );
|
|
ppFanins = Map_SuperReadFanins( pSuper );
|
|
// create a new node with these fanins
|
|
pNodeNew = Abc_NtkCreateNode( pNtkNew );
|
|
for ( i = 0; i < nFanins; i++ )
|
|
{
|
|
pNodeFanin = Abc_NodeFromMapSuperChoice_rec( pNtkNew, ppFanins[i], pNodePis, nNodePis );
|
|
Abc_ObjAddFanin( pNodeNew, pNodeFanin );
|
|
}
|
|
pNodeNew->pData = Abc_SopRegister( (Mem_Flex_t *)pNtkNew->pManFunc, Mio_GateReadSop(pRoot) );
|
|
return pNodeNew;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns the twin node if it exists.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Abc_NtkFetchTwinNode( Abc_Obj_t * pNode )
|
|
{
|
|
Abc_Obj_t * pNode2;
|
|
Mio_Gate_t * pGate = (Mio_Gate_t *)pNode->pData;
|
|
assert( Abc_NtkHasMapping(pNode->pNtk) );
|
|
if ( pGate == NULL || Mio_GateReadTwin(pGate) == NULL )
|
|
return NULL;
|
|
// assuming the twin node is following next
|
|
if ( (int)Abc_ObjId(pNode) == Abc_NtkObjNumMax(pNode->pNtk) - 1 )
|
|
return NULL;
|
|
pNode2 = Abc_NtkObj( pNode->pNtk, Abc_ObjId(pNode) + 1 );
|
|
if ( pNode2 == NULL || !Abc_ObjIsNode(pNode2) || Abc_ObjFaninNum(pNode) != Abc_ObjFaninNum(pNode2) )
|
|
return NULL;
|
|
if ( Mio_GateReadTwin(pGate) != (Mio_Gate_t *)pNode2->pData )
|
|
return NULL;
|
|
return pNode2;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Dumps mapped network in the mini-mapped format.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Int_t * Abc_NtkWriteMiniMapping( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vNodes;
|
|
Vec_Int_t * vMapping;
|
|
Vec_Str_t * vGates;
|
|
Abc_Obj_t * pObj, * pFanin;
|
|
int i, k, nNodes, nFanins, nExtra, * pArray;
|
|
assert( Abc_NtkHasMapping(pNtk) );
|
|
// collect nodes in the DFS order
|
|
vNodes = Abc_NtkDfs( pNtk, 0 );
|
|
// assign unique numbers
|
|
nNodes = nFanins = 0;
|
|
Abc_NtkForEachCi( pNtk, pObj, i )
|
|
pObj->iTemp = nNodes++;
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
|
|
pObj->iTemp = nNodes++, nFanins += Abc_ObjFaninNum(pObj);
|
|
// allocate attay to store mapping (4 counters + fanins for each node + PO drivers + gate names)
|
|
vMapping = Vec_IntAlloc( 4 + Abc_NtkNodeNum(pNtk) + nFanins + Abc_NtkCoNum(pNtk) + 10000 );
|
|
// write the numbers of CI/CO/Node/FF
|
|
Vec_IntPush( vMapping, Abc_NtkCiNum(pNtk) );
|
|
Vec_IntPush( vMapping, Abc_NtkCoNum(pNtk) );
|
|
Vec_IntPush( vMapping, Abc_NtkNodeNum(pNtk) );
|
|
Vec_IntPush( vMapping, Abc_NtkLatchNum(pNtk) );
|
|
// write the nodes
|
|
vGates = Vec_StrAlloc( 10000 );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
|
|
{
|
|
Vec_IntPush( vMapping, Abc_ObjFaninNum(pObj) );
|
|
Abc_ObjForEachFanin( pObj, pFanin, k )
|
|
Vec_IntPush( vMapping, pFanin->iTemp );
|
|
// remember this gate (to be added to the mapping later)
|
|
Vec_StrPrintStr( vGates, Mio_GateReadName((Mio_Gate_t *)pObj->pData) );
|
|
Vec_StrPush( vGates, '\0' );
|
|
}
|
|
// write the COs literals
|
|
Abc_NtkForEachCo( pNtk, pObj, i )
|
|
Vec_IntPush( vMapping, Abc_ObjFanin0(pObj)->iTemp );
|
|
// finish off the array
|
|
nExtra = 4 - Vec_StrSize(vGates) % 4;
|
|
for ( i = 0; i < nExtra; i++ )
|
|
Vec_StrPush( vGates, '\0' );
|
|
// add gates to the array
|
|
assert( Vec_StrSize(vGates) % 4 == 0 );
|
|
nExtra = Vec_StrSize(vGates) / 4;
|
|
pArray = (int *)Vec_StrArray(vGates);
|
|
for ( i = 0; i < nExtra; i++ )
|
|
Vec_IntPush( vMapping, pArray[i] );
|
|
// cleanup and return
|
|
Vec_PtrFree( vNodes );
|
|
Vec_StrFree( vGates );
|
|
return vMapping;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Prints mapped network represented in mini-mapped format.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkPrintMiniMapping( int * pArray )
|
|
{
|
|
int nCis, nCos, nNodes, nFlops;
|
|
int i, k, nLeaves, Pos = 4;
|
|
char * pBuffer, * pName;
|
|
nCis = pArray[0];
|
|
nCos = pArray[1];
|
|
nNodes = pArray[2];
|
|
nFlops = pArray[3];
|
|
printf( "Mapped network has %d CIs, %d COs, %d gates, and %d flops.\n", nCis, nCos, nNodes, nFlops );
|
|
printf( "The first %d object IDs (from 0 to %d) are reserved for the CIs.\n", nCis, nCis - 1 );
|
|
for ( i = 0; i < nNodes; i++ )
|
|
{
|
|
printf( "Node %d has fanins {", nCis + i );
|
|
nLeaves = pArray[Pos++];
|
|
for ( k = 0; k < nLeaves; k++ )
|
|
printf( " %d", pArray[Pos++] );
|
|
printf( " }\n" );
|
|
}
|
|
for ( i = 0; i < nCos; i++ )
|
|
printf( "CO %d is driven by node %d\n", i, pArray[Pos++] );
|
|
pBuffer = (char *)(pArray + Pos);
|
|
for ( i = 0; i < nNodes; i++ )
|
|
{
|
|
pName = pBuffer;
|
|
pBuffer += strlen(pName) + 1;
|
|
printf( "Node %d has gate \"%s\"\n", nCis + i, pName );
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [This procedure outputs an array representing mini-mapped network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int * Abc_NtkOutputMiniMapping( void * pAbc0 )
|
|
{
|
|
Abc_Frame_t * pAbc = (Abc_Frame_t *)pAbc0;
|
|
Abc_Ntk_t * pNtk;
|
|
Vec_Int_t * vMapping;
|
|
int * pArray;
|
|
if ( pAbc == NULL )
|
|
printf( "ABC framework is not initialized by calling Abc_Start()\n" );
|
|
pNtk = Abc_FrameReadNtk( pAbc );
|
|
if ( pNtk == NULL )
|
|
printf( "Current network in ABC framework is not defined.\n" );
|
|
if ( !Abc_NtkHasMapping(pNtk) )
|
|
printf( "Current network in ABC framework is not mapped.\n" );
|
|
// derive mini-mapping
|
|
vMapping = Abc_NtkWriteMiniMapping( pNtk );
|
|
pArray = Vec_IntArray( vMapping );
|
|
ABC_FREE( vMapping );
|
|
// print mini-mapping (optional)
|
|
// Abc_NtkPrintMiniMapping( pArray );
|
|
// return the array representation of mini-mapping
|
|
return pArray;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Test for mini-mapped format.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkTestMiniMapping( Abc_Ntk_t * p )
|
|
{
|
|
Vec_Int_t * vMapping;
|
|
vMapping = Abc_NtkWriteMiniMapping( p );
|
|
Abc_NtkPrintMiniMapping( Vec_IntArray(vMapping) );
|
|
printf( "Array has size %d ints.\n", Vec_IntSize(vMapping) );
|
|
Vec_IntFree( vMapping );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [These APIs set arriva/required times of CIs/COs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkSetCiArrivalTime( void * pAbc0, int iCi, float Rise, float Fall )
|
|
{
|
|
Abc_Frame_t * pAbc = (Abc_Frame_t *)pAbc0;
|
|
Abc_Ntk_t * pNtk;
|
|
Abc_Obj_t * pNode;
|
|
if ( pAbc == NULL )
|
|
printf( "ABC framework is not initialized by calling Abc_Start()\n" );
|
|
pNtk = Abc_FrameReadNtk( pAbc );
|
|
if ( pNtk == NULL )
|
|
printf( "Current network in ABC framework is not defined.\n" );
|
|
if ( iCi < 0 || iCi >= Abc_NtkCiNum(pNtk) )
|
|
printf( "CI index is not valid.\n" );
|
|
pNode = Abc_NtkCi( pNtk, iCi );
|
|
Abc_NtkTimeSetArrival( pNtk, Abc_ObjId(pNode), Rise, Fall );
|
|
}
|
|
void Abc_NtkSetCoRequiredTime( void * pAbc0, int iCo, float Rise, float Fall )
|
|
{
|
|
Abc_Frame_t * pAbc = (Abc_Frame_t *)pAbc0;
|
|
Abc_Ntk_t * pNtk;
|
|
Abc_Obj_t * pNode;
|
|
if ( pAbc == NULL )
|
|
printf( "ABC framework is not initialized by calling Abc_Start()\n" );
|
|
pNtk = Abc_FrameReadNtk( pAbc );
|
|
if ( pNtk == NULL )
|
|
printf( "Current network in ABC framework is not defined.\n" );
|
|
if ( iCo < 0 || iCo >= Abc_NtkCoNum(pNtk) )
|
|
printf( "CO index is not valid.\n" );
|
|
pNode = Abc_NtkCo( pNtk, iCo );
|
|
Abc_NtkTimeSetRequired( pNtk, Abc_ObjId(pNode), Rise, Fall );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|