mirror of https://github.com/YosysHQ/abc.git
1214 lines
39 KiB
C
1214 lines
39 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [abcRec.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network and node package.]
|
|
|
|
Synopsis [Record of semi-canonical AIG subgraphs.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: abcRec.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "abc.h"
|
|
#include "if.h"
|
|
#include "kit.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct Abc_ManRec_t_ Abc_ManRec_t;
|
|
struct Abc_ManRec_t_
|
|
{
|
|
Abc_Ntk_t * pNtk; // the record
|
|
Vec_Ptr_t * vTtElems; // the elementary truth tables
|
|
Vec_Ptr_t * vTtNodes; // the node truth tables
|
|
Abc_Obj_t ** pBins; // hash table mapping truth tables into nodes
|
|
int nBins; // the number of allocated bins
|
|
int nVars; // the number of variables
|
|
int nVarsInit; // the number of variables requested initially
|
|
int nWords; // the number of TT words
|
|
int nCuts; // the max number of cuts to use
|
|
// temporaries
|
|
int * pBytes; // temporary storage for minterms
|
|
int * pMints; // temporary storage for minterm counters
|
|
unsigned * pTemp1; // temporary truth table
|
|
unsigned * pTemp2; // temporary truth table
|
|
Vec_Ptr_t * vNodes; // the temporary nodes
|
|
Vec_Ptr_t * vTtTemps; // the truth tables for the internal nodes of the cut
|
|
Vec_Ptr_t * vLabels; // temporary storage for AIG node labels
|
|
Vec_Str_t * vCosts; // temporary storage for costs
|
|
Vec_Int_t * vMemory; // temporary memory for truth tables
|
|
// statistics
|
|
int nTried; // the number of cuts tried
|
|
int nFilterSize; // the number of same structures
|
|
int nFilterRedund; // the number of same structures
|
|
int nFilterVolume; // the number of same structures
|
|
int nFilterTruth; // the number of same structures
|
|
int nFilterError; // the number of same structures
|
|
int nFilterSame; // the number of same structures
|
|
int nAdded; // the number of subgraphs added
|
|
int nAddedFuncs; // the number of functions added
|
|
// rewriting
|
|
int nFunsFound; // the found functions
|
|
int nFunsNotFound; // the missing functions
|
|
// runtime
|
|
int timeCollect; // the runtime to canonicize
|
|
int timeTruth; // the runtime to canonicize
|
|
int timeCanon; // the runtime to canonicize
|
|
int timeOther; // the runtime to canonicize
|
|
int timeTotal; // the runtime to canonicize
|
|
};
|
|
|
|
// the truth table is canonicized in such a way that for (00000) its value is 0
|
|
|
|
static Abc_Obj_t ** Abc_NtkRecTableLookup( Abc_ManRec_t * p, unsigned * pTruth, int nVars );
|
|
static int Abc_NtkRecComputeTruth( Abc_Obj_t * pObj, Vec_Ptr_t * vTtNodes, int nVars );
|
|
static int Abc_NtkRecAddCutCheckCycle_rec( Abc_Obj_t * pRoot, Abc_Obj_t * pObj );
|
|
|
|
static Abc_ManRec_t * s_pMan = NULL;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Starts the record for the given network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecIsRunning()
|
|
{
|
|
return s_pMan != NULL;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Starts the record for the given network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecVarNum()
|
|
{
|
|
return (s_pMan != NULL)? s_pMan->nVars : -1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Starts the record for the given network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Int_t * Abc_NtkRecMemory()
|
|
{
|
|
return s_pMan->vMemory;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Starts the record for the given network.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecStart( Abc_Ntk_t * pNtk, int nVars, int nCuts )
|
|
{
|
|
Abc_ManRec_t * p;
|
|
Abc_Obj_t * pObj, ** ppSpot;
|
|
char Buffer[10];
|
|
unsigned * pTruth;
|
|
int i, RetValue;
|
|
int clkTotal = clock(), clk;
|
|
|
|
assert( s_pMan == NULL );
|
|
if ( pNtk == NULL )
|
|
{
|
|
assert( nVars > 2 && nVars <= 16 );
|
|
pNtk = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 );
|
|
pNtk->pName = Extra_UtilStrsav( "record" );
|
|
}
|
|
else
|
|
{
|
|
if ( Abc_NtkGetChoiceNum(pNtk) > 0 )
|
|
{
|
|
printf( "The starting record should be a network without choice nodes.\n" );
|
|
return;
|
|
}
|
|
if ( Abc_NtkPiNum(pNtk) > 16 )
|
|
{
|
|
printf( "The starting record should be a network with no more than %d primary inputs.\n", 16 );
|
|
return;
|
|
}
|
|
if ( Abc_NtkPiNum(pNtk) > nVars )
|
|
printf( "The starting record has %d inputs (warning only).\n", Abc_NtkPiNum(pNtk) );
|
|
pNtk = Abc_NtkDup( pNtk );
|
|
}
|
|
// create the primary inputs
|
|
for ( i = Abc_NtkPiNum(pNtk); i < nVars; i++ )
|
|
{
|
|
pObj = Abc_NtkCreatePi( pNtk );
|
|
Buffer[0] = 'a' + i;
|
|
Buffer[1] = 0;
|
|
Abc_ObjAssignName( pObj, Buffer, NULL );
|
|
}
|
|
Abc_NtkCleanCopy( pNtk );
|
|
Abc_NtkCleanEquiv( pNtk );
|
|
|
|
// start the manager
|
|
p = ABC_ALLOC( Abc_ManRec_t, 1 );
|
|
memset( p, 0, sizeof(Abc_ManRec_t) );
|
|
p->pNtk = pNtk;
|
|
p->nVars = Abc_NtkPiNum(pNtk);
|
|
p->nWords = Kit_TruthWordNum( p->nVars );
|
|
p->nCuts = nCuts;
|
|
p->nVarsInit = nVars;
|
|
|
|
// create elementary truth tables
|
|
p->vTtElems = Vec_PtrAlloc( 0 ); assert( p->vTtElems->pArray == NULL );
|
|
p->vTtElems->nSize = p->nVars;
|
|
p->vTtElems->nCap = p->nVars;
|
|
p->vTtElems->pArray = (void **)Extra_TruthElementary( p->nVars );
|
|
/*
|
|
// allocate room for node truth tables
|
|
if ( Abc_NtkObjNum(pNtk) > (1<<14) )
|
|
p->vTtNodes = Vec_PtrAllocSimInfo( 2 * Abc_NtkObjNum(pNtk), p->nWords );
|
|
else
|
|
p->vTtNodes = Vec_PtrAllocSimInfo( 1<<14, p->nWords );
|
|
*/
|
|
p->vTtNodes = Vec_PtrAlloc( 1000 );
|
|
for ( i = 0; i < Abc_NtkObjNumMax(pNtk); i++ )
|
|
Vec_PtrPush( p->vTtNodes, ABC_ALLOC(unsigned, p->nWords) );
|
|
|
|
// create hash table
|
|
p->nBins = 50011;
|
|
p->pBins = ABC_ALLOC( Abc_Obj_t *, p->nBins );
|
|
memset( p->pBins, 0, sizeof(Abc_Obj_t *) * p->nBins );
|
|
|
|
// set elementary tables
|
|
Kit_TruthFill( (unsigned *)Vec_PtrEntry(p->vTtNodes, 0), p->nVars );
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
Kit_TruthCopy( (unsigned *)Vec_PtrEntry(p->vTtNodes, pObj->Id), (unsigned *)Vec_PtrEntry(p->vTtElems, i), p->nVars );
|
|
|
|
// compute the tables
|
|
clk = clock();
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
{
|
|
RetValue = Abc_NtkRecComputeTruth( pObj, p->vTtNodes, p->nVars );
|
|
assert( RetValue );
|
|
}
|
|
p->timeTruth += clock() - clk;
|
|
|
|
// insert the PO nodes into the table
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
{
|
|
p->nTried++;
|
|
p->nAdded++;
|
|
|
|
pObj = Abc_ObjFanin0(pObj);
|
|
pTruth = (unsigned *)Vec_PtrEntry( p->vTtNodes, pObj->Id );
|
|
|
|
// add the resulting truth table to the hash table
|
|
ppSpot = Abc_NtkRecTableLookup( p, pTruth, p->nVars );
|
|
assert( pObj->pData == NULL );
|
|
assert( pObj->pCopy == NULL );
|
|
if ( *ppSpot == NULL )
|
|
{
|
|
p->nAddedFuncs++;
|
|
*ppSpot = pObj;
|
|
}
|
|
else
|
|
{
|
|
pObj->pData = (*ppSpot)->pData;
|
|
(*ppSpot)->pData = (Hop_Obj_t *)pObj;
|
|
if ( !Abc_NtkRecAddCutCheckCycle_rec(*ppSpot, pObj) )
|
|
printf( "Loop!\n" );
|
|
}
|
|
}
|
|
|
|
// temporaries
|
|
p->pBytes = ABC_ALLOC( int, 4*p->nWords );
|
|
p->pMints = ABC_ALLOC( int, 2*p->nVars );
|
|
p->pTemp1 = ABC_ALLOC( unsigned, p->nWords );
|
|
p->pTemp2 = ABC_ALLOC( unsigned, p->nWords );
|
|
p->vNodes = Vec_PtrAlloc( 100 );
|
|
p->vTtTemps = Vec_PtrAllocSimInfo( 64, p->nWords );
|
|
p->vMemory = Vec_IntAlloc( Abc_TruthWordNum(p->nVars) * 1000 );
|
|
|
|
// set the manager
|
|
s_pMan = p;
|
|
p->timeTotal += clock() - clkTotal;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Dump truth tables into a file.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecDumpTruthTables( Abc_ManRec_t * p )
|
|
{
|
|
FILE * pFile;
|
|
Abc_Obj_t * pObj;
|
|
unsigned * pTruth;
|
|
int i;
|
|
pFile = fopen( "tt16.txt", "wb" );
|
|
for ( i = 0; i < p->nBins; i++ )
|
|
for ( pObj = p->pBins[i]; pObj; pObj = pObj->pCopy )
|
|
{
|
|
pTruth = Vec_PtrEntry(p->vTtNodes, pObj->Id);
|
|
if ( Kit_TruthSupport(pTruth, 16) != (1<<16)-1 )
|
|
continue;
|
|
Extra_PrintHex( pFile, pTruth, 16 );
|
|
fprintf( pFile, " " );
|
|
Kit_DsdPrintFromTruth2( pFile, pTruth, 16 );
|
|
fprintf( pFile, "\n" );
|
|
}
|
|
fclose( pFile );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns the given record.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecStop()
|
|
{
|
|
assert( s_pMan != NULL );
|
|
Abc_NtkRecDumpTruthTables( s_pMan );
|
|
|
|
if ( s_pMan->pNtk )
|
|
Abc_NtkDelete( s_pMan->pNtk );
|
|
// Vec_PtrFree( s_pMan->vTtNodes );
|
|
Vec_PtrFreeFree( s_pMan->vTtNodes );
|
|
Vec_PtrFree( s_pMan->vTtElems );
|
|
ABC_FREE( s_pMan->pBins );
|
|
|
|
// temporaries
|
|
ABC_FREE( s_pMan->pBytes );
|
|
ABC_FREE( s_pMan->pMints );
|
|
ABC_FREE( s_pMan->pTemp1 );
|
|
ABC_FREE( s_pMan->pTemp2 );
|
|
Vec_PtrFree( s_pMan->vNodes );
|
|
Vec_PtrFree( s_pMan->vTtTemps );
|
|
if ( s_pMan->vLabels )
|
|
Vec_PtrFree( s_pMan->vLabels );
|
|
if ( s_pMan->vCosts )
|
|
Vec_StrFree( s_pMan->vCosts );
|
|
Vec_IntFree( s_pMan->vMemory );
|
|
|
|
ABC_FREE( s_pMan );
|
|
s_pMan = NULL;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns the given record.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_NtkRecUse()
|
|
{
|
|
Abc_ManRec_t * p = s_pMan;
|
|
Abc_Ntk_t * pNtk = p->pNtk;
|
|
assert( p != NULL );
|
|
Abc_NtkRecPs();
|
|
p->pNtk = NULL;
|
|
Abc_NtkRecStop();
|
|
Abc_NtkCleanData(pNtk);
|
|
return pNtk;
|
|
}
|
|
|
|
static inline void Abc_ObjSetMax( Abc_Obj_t * pObj, int Value ) { assert( pObj->Level < 0xff ); pObj->Level = (Value << 8) | (pObj->Level & 0xff); }
|
|
static inline void Abc_ObjClearMax( Abc_Obj_t * pObj ) { pObj->Level = (pObj->Level & 0xff); }
|
|
static inline int Abc_ObjGetMax( Abc_Obj_t * pObj ) { return (pObj->Level >> 8) & 0xff; }
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Print statistics about the current record.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecPs()
|
|
{
|
|
int Counter, Counters[17] = {0};
|
|
int CounterS, CountersS[17] = {0};
|
|
Abc_ManRec_t * p = s_pMan;
|
|
Abc_Ntk_t * pNtk = p->pNtk;
|
|
Abc_Obj_t * pObj, * pEntry, * pTemp;
|
|
int i;
|
|
|
|
// set the max PI number
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
Abc_ObjSetMax( pObj, i+1 );
|
|
Abc_AigForEachAnd( pNtk, pObj, i )
|
|
Abc_ObjSetMax( pObj, ABC_MAX( Abc_ObjGetMax(Abc_ObjFanin0(pObj)), Abc_ObjGetMax(Abc_ObjFanin1(pObj)) ) );
|
|
// go through the table
|
|
Counter = CounterS = 0;
|
|
for ( i = 0; i < p->nBins; i++ )
|
|
for ( pEntry = p->pBins[i]; pEntry; pEntry = pEntry->pCopy )
|
|
{
|
|
Counters[ Abc_ObjGetMax(pEntry) ]++;
|
|
Counter++;
|
|
for ( pTemp = pEntry; pTemp; pTemp = (Abc_Obj_t *)pTemp->pData )
|
|
{
|
|
assert( Abc_ObjGetMax(pTemp) == Abc_ObjGetMax(pEntry) );
|
|
CountersS[ Abc_ObjGetMax(pTemp) ]++;
|
|
CounterS++;
|
|
}
|
|
}
|
|
// printf( "Functions = %d. Expected = %d.\n", Counter, p->nAddedFuncs );
|
|
// printf( "Subgraphs = %d. Expected = %d.\n", CounterS, p->nAdded );
|
|
assert( Counter == p->nAddedFuncs );
|
|
assert( CounterS == p->nAdded );
|
|
|
|
// clean
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
{
|
|
Abc_ObjClearMax( pObj );
|
|
}
|
|
|
|
printf( "The record with %d AND nodes in %d subgraphs for %d functions with %d inputs:\n",
|
|
Abc_NtkNodeNum(pNtk), Abc_NtkPoNum(pNtk), p->nAddedFuncs, Abc_NtkPiNum(pNtk) );
|
|
for ( i = 0; i <= 16; i++ )
|
|
{
|
|
if ( Counters[i] )
|
|
printf( "Inputs = %2d. Funcs = %8d. Subgrs = %8d. Ratio = %6.2f.\n", i, Counters[i], CountersS[i], 1.0*CountersS[i]/Counters[i] );
|
|
}
|
|
|
|
printf( "Subgraphs tried = %10d. (%6.2f %%)\n", p->nTried, !p->nTried? 0 : 100.0*p->nTried/p->nTried );
|
|
printf( "Subgraphs filtered by support size = %10d. (%6.2f %%)\n", p->nFilterSize, !p->nTried? 0 : 100.0*p->nFilterSize/p->nTried );
|
|
printf( "Subgraphs filtered by structural redundancy = %10d. (%6.2f %%)\n", p->nFilterRedund, !p->nTried? 0 : 100.0*p->nFilterRedund/p->nTried );
|
|
printf( "Subgraphs filtered by volume = %10d. (%6.2f %%)\n", p->nFilterVolume, !p->nTried? 0 : 100.0*p->nFilterVolume/p->nTried );
|
|
printf( "Subgraphs filtered by TT redundancy = %10d. (%6.2f %%)\n", p->nFilterTruth, !p->nTried? 0 : 100.0*p->nFilterTruth/p->nTried );
|
|
printf( "Subgraphs filtered by error = %10d. (%6.2f %%)\n", p->nFilterError, !p->nTried? 0 : 100.0*p->nFilterError/p->nTried );
|
|
printf( "Subgraphs filtered by isomorphism = %10d. (%6.2f %%)\n", p->nFilterSame, !p->nTried? 0 : 100.0*p->nFilterSame/p->nTried );
|
|
printf( "Subgraphs added = %10d. (%6.2f %%)\n", p->nAdded, !p->nTried? 0 : 100.0*p->nAdded/p->nTried );
|
|
printf( "Functions added = %10d. (%6.2f %%)\n", p->nAddedFuncs, !p->nTried? 0 : 100.0*p->nAddedFuncs/p->nTried );
|
|
|
|
p->timeOther = p->timeTotal - p->timeCollect - p->timeTruth - p->timeCanon;
|
|
ABC_PRTP( "Collecting nodes ", p->timeCollect, p->timeTotal );
|
|
ABC_PRTP( "Computing truth ", p->timeTruth, p->timeTotal );
|
|
ABC_PRTP( "Canonicizing ", p->timeCanon, p->timeTotal );
|
|
ABC_PRTP( "Other ", p->timeOther, p->timeTotal );
|
|
ABC_PRTP( "TOTAL ", p->timeTotal, p->timeTotal );
|
|
if ( p->nFunsFound )
|
|
printf( "During rewriting found = %d and not found = %d functions.\n", p->nFunsFound, p->nFunsNotFound );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Filters the current record.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecFilter( int iVar, int iPlus )
|
|
{
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns the hash key.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline unsigned Abc_NtkRecTableHash( unsigned * pTruth, int nVars, int nBins, int * pPrimes )
|
|
{
|
|
int i, nWords = Kit_TruthWordNum( nVars );
|
|
unsigned uHash = 0;
|
|
for ( i = 0; i < nWords; i++ )
|
|
uHash ^= pTruth[i] * pPrimes[i & 0x7];
|
|
return uHash % nBins;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns the given record.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t ** Abc_NtkRecTableLookup( Abc_ManRec_t * p, unsigned * pTruth, int nVars )
|
|
{
|
|
static int s_Primes[10] = { 1291, 1699, 2357, 4177, 5147, 5647, 6343, 7103, 7873, 8147 };
|
|
Abc_Obj_t ** ppSpot, * pEntry;
|
|
ppSpot = p->pBins + Abc_NtkRecTableHash( pTruth, nVars, p->nBins, s_Primes );
|
|
for ( pEntry = *ppSpot; pEntry; ppSpot = &pEntry->pCopy, pEntry = pEntry->pCopy )
|
|
if ( Kit_TruthIsEqualWithPhase((unsigned *)Vec_PtrEntry(p->vTtNodes, pEntry->Id), pTruth, nVars) )
|
|
return ppSpot;
|
|
return ppSpot;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the truth table of the node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecComputeTruth( Abc_Obj_t * pObj, Vec_Ptr_t * vTtNodes, int nVars )
|
|
{
|
|
unsigned * pTruth, * pTruth0, * pTruth1;
|
|
int RetValue;
|
|
assert( Abc_ObjIsNode(pObj) );
|
|
pTruth = (unsigned *)Vec_PtrEntry( vTtNodes, pObj->Id );
|
|
pTruth0 = (unsigned *)Vec_PtrEntry( vTtNodes, Abc_ObjFaninId0(pObj) );
|
|
pTruth1 = (unsigned *)Vec_PtrEntry( vTtNodes, Abc_ObjFaninId1(pObj) );
|
|
Kit_TruthAndPhase( pTruth, pTruth0, pTruth1, nVars, Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj) );
|
|
assert( (pTruth[0] & 1) == pObj->fPhase );
|
|
RetValue = ((pTruth[0] & 1) == pObj->fPhase);
|
|
return RetValue;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs renoding as technology mapping.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecAdd( Abc_Ntk_t * pNtk )
|
|
{
|
|
extern Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars );
|
|
extern int Abc_NtkRecAddCut( If_Man_t * pIfMan, If_Obj_t * pRoot, If_Cut_t * pCut );
|
|
|
|
If_Par_t Pars, * pPars = &Pars;
|
|
Abc_Ntk_t * pNtkNew;
|
|
int clk = clock();
|
|
|
|
if ( Abc_NtkGetChoiceNum( pNtk ) )
|
|
printf( "Performing renoding with choices.\n" );
|
|
|
|
// set defaults
|
|
memset( pPars, 0, sizeof(If_Par_t) );
|
|
// user-controlable paramters
|
|
pPars->nLutSize = s_pMan->nVarsInit;
|
|
pPars->nCutsMax = s_pMan->nCuts;
|
|
pPars->nFlowIters = 0;
|
|
pPars->nAreaIters = 0;
|
|
pPars->DelayTarget = -1;
|
|
pPars->Epsilon = (float)0.005;
|
|
pPars->fPreprocess = 0;
|
|
pPars->fArea = 1;
|
|
pPars->fFancy = 0;
|
|
pPars->fExpRed = 0;
|
|
pPars->fLatchPaths = 0;
|
|
pPars->fSeqMap = 0;
|
|
pPars->fVerbose = 0;
|
|
// internal parameters
|
|
pPars->fTruth = 0;
|
|
pPars->fUsePerm = 0;
|
|
pPars->nLatches = 0;
|
|
pPars->pLutLib = NULL; // Abc_FrameReadLibLut();
|
|
pPars->pTimesArr = NULL;
|
|
pPars->pTimesArr = NULL;
|
|
pPars->fUseBdds = 0;
|
|
pPars->fUseSops = 0;
|
|
pPars->fUseCnfs = 0;
|
|
pPars->fUseMv = 0;
|
|
pPars->pFuncCost = NULL;
|
|
pPars->pFuncUser = Abc_NtkRecAddCut;
|
|
|
|
// perform recording
|
|
pNtkNew = Abc_NtkIf( pNtk, pPars );
|
|
Abc_NtkDelete( pNtkNew );
|
|
s_pMan->timeTotal += clock() - clk;
|
|
|
|
// if ( !Abc_NtkCheck( s_pMan->pNtk ) )
|
|
// printf( "Abc_NtkRecAdd: The network check has failed.\n" );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Adds the cut function to the internal storage.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecCollectNodes_rec( If_Obj_t * pNode, Vec_Ptr_t * vNodes )
|
|
{
|
|
if ( pNode->fMark )
|
|
return;
|
|
pNode->fMark = 1;
|
|
assert( If_ObjIsAnd(pNode) );
|
|
Abc_NtkRecCollectNodes_rec( If_ObjFanin0(pNode), vNodes );
|
|
Abc_NtkRecCollectNodes_rec( If_ObjFanin1(pNode), vNodes );
|
|
Vec_PtrPush( vNodes, pNode );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Adds the cut function to the internal storage.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecCollectNodes( If_Man_t * pIfMan, If_Obj_t * pRoot, If_Cut_t * pCut, Vec_Ptr_t * vNodes )
|
|
{
|
|
If_Obj_t * pLeaf;
|
|
int i, RetValue = 1;
|
|
|
|
// collect the internal nodes of the cut
|
|
Vec_PtrClear( vNodes );
|
|
If_CutForEachLeaf( pIfMan, pCut, pLeaf, i )
|
|
{
|
|
Vec_PtrPush( vNodes, pLeaf );
|
|
assert( pLeaf->fMark == 0 );
|
|
pLeaf->fMark = 1;
|
|
}
|
|
|
|
// collect other nodes
|
|
Abc_NtkRecCollectNodes_rec( pRoot, vNodes );
|
|
|
|
// check if there are leaves, such that both of their fanins are marked
|
|
// this indicates a redundant cut
|
|
If_CutForEachLeaf( pIfMan, pCut, pLeaf, i )
|
|
{
|
|
if ( !If_ObjIsAnd(pLeaf) )
|
|
continue;
|
|
if ( If_ObjFanin0(pLeaf)->fMark && If_ObjFanin1(pLeaf)->fMark )
|
|
{
|
|
RetValue = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// clean the mark
|
|
Vec_PtrForEachEntry( If_Obj_t *, vNodes, pLeaf, i )
|
|
pLeaf->fMark = 0;
|
|
/*
|
|
if ( pRoot->Id == 2639 )
|
|
{
|
|
// print the cut
|
|
Vec_PtrForEachEntry( If_Obj_t *, vNodes, pLeaf, i )
|
|
{
|
|
if ( If_ObjIsAnd(pLeaf) )
|
|
printf( "%4d = %c%4d & %c%4d\n", pLeaf->Id,
|
|
(If_ObjFaninC0(pLeaf)? '-':'+'), If_ObjFanin0(pLeaf)->Id,
|
|
(If_ObjFaninC1(pLeaf)? '-':'+'), If_ObjFanin1(pLeaf)->Id );
|
|
else
|
|
printf( "%4d = pi\n", pLeaf->Id );
|
|
}
|
|
printf( "\n" );
|
|
}
|
|
*/
|
|
return RetValue;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes truth tables of nodes in the cut.]
|
|
|
|
Description [Returns 0 if the TT does not depend on some cut variables.
|
|
Or if the TT can be expressed simpler using other nodes.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecCutTruth( Vec_Ptr_t * vNodes, int nLeaves, Vec_Ptr_t * vTtTemps, Vec_Ptr_t * vTtElems )
|
|
{
|
|
unsigned * pSims, * pSims0, * pSims1;
|
|
unsigned * pTemp = s_pMan->pTemp2;
|
|
unsigned uWord;
|
|
If_Obj_t * pObj, * pObj2, * pRoot;
|
|
int i, k, nLimit, nInputs = s_pMan->nVars;
|
|
|
|
assert( Vec_PtrSize(vNodes) > nLeaves );
|
|
|
|
// set the elementary truth tables and compute the truth tables of the nodes
|
|
Vec_PtrForEachEntry( If_Obj_t *, vNodes, pObj, i )
|
|
{
|
|
pObj->pCopy = Vec_PtrEntry(vTtTemps, i);
|
|
pSims = (unsigned *)pObj->pCopy;
|
|
if ( i < nLeaves )
|
|
{
|
|
Kit_TruthCopy( pSims, (unsigned *)Vec_PtrEntry(vTtElems, i), nInputs );
|
|
continue;
|
|
}
|
|
assert( If_ObjIsAnd(pObj) );
|
|
// get hold of the simulation information
|
|
pSims0 = (unsigned *)If_ObjFanin0(pObj)->pCopy;
|
|
pSims1 = (unsigned *)If_ObjFanin1(pObj)->pCopy;
|
|
// simulate the node
|
|
Kit_TruthAndPhase( pSims, pSims0, pSims1, nInputs, If_ObjFaninC0(pObj), If_ObjFaninC1(pObj) );
|
|
}
|
|
|
|
// check the support size
|
|
pRoot = (If_Obj_t *)Vec_PtrEntryLast( vNodes );
|
|
pSims = (unsigned *)pRoot->pCopy;
|
|
if ( Kit_TruthSupport(pSims, nInputs) != Kit_BitMask(nLeaves) )
|
|
return 0;
|
|
|
|
// make sure none of the nodes has the same simulation info as the output
|
|
// check pairwise comparisons
|
|
nLimit = Vec_PtrSize(vNodes) - 1;
|
|
Vec_PtrForEachEntryStop( If_Obj_t *, vNodes, pObj, i, nLimit )
|
|
{
|
|
pSims0 = (unsigned *)pObj->pCopy;
|
|
if ( Kit_TruthIsEqualWithPhase(pSims, pSims0, nInputs) )
|
|
return 0;
|
|
Vec_PtrForEachEntryStop( If_Obj_t *, vNodes, pObj2, k, i )
|
|
{
|
|
if ( (If_ObjFanin0(pRoot) == pObj && If_ObjFanin1(pRoot) == pObj2) ||
|
|
(If_ObjFanin1(pRoot) == pObj && If_ObjFanin0(pRoot) == pObj2) )
|
|
continue;
|
|
pSims1 = (unsigned *)pObj2->pCopy;
|
|
|
|
uWord = pSims0[0] & pSims1[0];
|
|
if ( pSims[0] == uWord || pSims[0] == ~uWord )
|
|
{
|
|
Kit_TruthAndPhase( pTemp, pSims0, pSims1, nInputs, 0, 0 );
|
|
if ( Kit_TruthIsEqualWithPhase(pSims, pTemp, nInputs) )
|
|
return 0;
|
|
}
|
|
|
|
uWord = pSims0[0] & ~pSims1[0];
|
|
if ( pSims[0] == uWord || pSims[0] == ~uWord )
|
|
{
|
|
Kit_TruthAndPhase( pTemp, pSims0, pSims1, nInputs, 0, 1 );
|
|
if ( Kit_TruthIsEqualWithPhase(pSims, pTemp, nInputs) )
|
|
return 0;
|
|
}
|
|
|
|
uWord = ~pSims0[0] & pSims1[0];
|
|
if ( pSims[0] == uWord || pSims[0] == ~uWord )
|
|
{
|
|
Kit_TruthAndPhase( pTemp, pSims0, pSims1, nInputs, 1, 0 );
|
|
if ( Kit_TruthIsEqualWithPhase(pSims, pTemp, nInputs) )
|
|
return 0;
|
|
}
|
|
|
|
uWord = ~pSims0[0] & ~pSims1[0];
|
|
if ( pSims[0] == uWord || pSims[0] == ~uWord )
|
|
{
|
|
Kit_TruthAndPhase( pTemp, pSims0, pSims1, nInputs, 1, 1 );
|
|
if ( Kit_TruthIsEqualWithPhase(pSims, pTemp, nInputs) )
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Adds the cut function to the internal storage.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecAddCutCheckCycle_rec( Abc_Obj_t * pRoot, Abc_Obj_t * pObj )
|
|
{
|
|
assert( pRoot->Level > 0 );
|
|
if ( pObj->Level < pRoot->Level )
|
|
return 1;
|
|
if ( pObj == pRoot )
|
|
return 0;
|
|
if ( !Abc_NtkRecAddCutCheckCycle_rec(pRoot, Abc_ObjFanin0(pObj)) )
|
|
return 0;
|
|
if ( !Abc_NtkRecAddCutCheckCycle_rec(pRoot, Abc_ObjFanin1(pObj)) )
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Adds the cut function to the internal storage.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecAddCut( If_Man_t * pIfMan, If_Obj_t * pRoot, If_Cut_t * pCut )
|
|
{
|
|
static int s_MaxSize[16] = { 0 };
|
|
char Buffer[40], Name[20], Truth[20];
|
|
char pCanonPerm[16];
|
|
Abc_Obj_t * pObj = NULL, * pFanin0, * pFanin1, ** ppSpot, * pObjPo;
|
|
Abc_Ntk_t * pAig = s_pMan->pNtk;
|
|
If_Obj_t * pIfObj;
|
|
Vec_Ptr_t * vNodes = s_pMan->vNodes;
|
|
unsigned * pInOut = s_pMan->pTemp1;
|
|
unsigned * pTemp = s_pMan->pTemp2;
|
|
unsigned * pTruth;
|
|
int i, RetValue, nNodes, nNodesBeg, nInputs = s_pMan->nVars, nLeaves = If_CutLeaveNum(pCut);
|
|
unsigned uCanonPhase;
|
|
int clk;
|
|
|
|
assert( nInputs <= 16 );
|
|
assert( nInputs == (int)pCut->nLimit );
|
|
s_pMan->nTried++;
|
|
|
|
// skip small cuts
|
|
if ( nLeaves < 3 )
|
|
{
|
|
s_pMan->nFilterSize++;
|
|
return 1;
|
|
}
|
|
|
|
// collect internal nodes and skip redundant cuts
|
|
clk = clock();
|
|
RetValue = Abc_NtkRecCollectNodes( pIfMan, pRoot, pCut, vNodes );
|
|
s_pMan->timeCollect += clock() - clk;
|
|
if ( !RetValue )
|
|
{
|
|
s_pMan->nFilterRedund++;
|
|
return 1;
|
|
}
|
|
|
|
// skip cuts with very large volume
|
|
if ( Vec_PtrSize(vNodes) > nLeaves + 3*(nLeaves-1) + s_MaxSize[nLeaves] )
|
|
{
|
|
s_pMan->nFilterVolume++;
|
|
return 1;
|
|
}
|
|
|
|
// compute truth table and skip the redundant structures
|
|
clk = clock();
|
|
RetValue = Abc_NtkRecCutTruth( vNodes, nLeaves, s_pMan->vTtTemps, s_pMan->vTtElems );
|
|
s_pMan->timeTruth += clock() - clk;
|
|
if ( !RetValue )
|
|
{
|
|
s_pMan->nFilterTruth++;
|
|
return 1;
|
|
}
|
|
|
|
// copy the truth table
|
|
Kit_TruthCopy( pInOut, (unsigned *)pRoot->pCopy, nInputs );
|
|
|
|
// set permutation
|
|
for ( i = 0; i < nInputs; i++ )
|
|
pCanonPerm[i] = i;
|
|
|
|
// semi-canonicize the truth table
|
|
clk = clock();
|
|
uCanonPhase = Kit_TruthSemiCanonicize( pInOut, pTemp, nInputs, pCanonPerm, (short *)s_pMan->pMints );
|
|
s_pMan->timeCanon += clock() - clk;
|
|
// pCanonPerm and uCanonPhase show what was the variable corresponding to each var in the current truth
|
|
|
|
// go through the variables in the new truth table
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
{
|
|
// get hold of the corresponding leaf
|
|
pIfObj = If_ManObj( pIfMan, pCut->pLeaves[(int)pCanonPerm[i]] );
|
|
// get hold of the corresponding new node
|
|
pObj = Abc_NtkPi( pAig, i );
|
|
pObj = Abc_ObjNotCond( pObj, (uCanonPhase & (1 << i)) );
|
|
// map them
|
|
pIfObj->pCopy = pObj;
|
|
/*
|
|
if ( pRoot->Id == 2639 )
|
|
{
|
|
unsigned uSupp;
|
|
printf( "Node %6d : ", pIfObj->Id );
|
|
printf( "Support " );
|
|
uSupp = Kit_TruthSupport(Vec_PtrEntry( s_pMan->vTtNodes, Abc_ObjRegular(pObj)->Id ), nInputs);
|
|
Extra_PrintBinary( stdout, &uSupp, nInputs );
|
|
printf( " " );
|
|
Extra_PrintBinary( stdout, Vec_PtrEntry( s_pMan->vTtNodes, Abc_ObjRegular(pObj)->Id ), 1<<6 );
|
|
printf( "\n" );
|
|
}
|
|
*/
|
|
}
|
|
|
|
// build the node and compute its truth table
|
|
nNodesBeg = Abc_NtkObjNumMax( pAig );
|
|
Vec_PtrForEachEntryStart( If_Obj_t *, vNodes, pIfObj, i, nLeaves )
|
|
{
|
|
pFanin0 = Abc_ObjNotCond( (Abc_Obj_t *)If_ObjFanin0(pIfObj)->pCopy, If_ObjFaninC0(pIfObj) );
|
|
pFanin1 = Abc_ObjNotCond( (Abc_Obj_t *)If_ObjFanin1(pIfObj)->pCopy, If_ObjFaninC1(pIfObj) );
|
|
|
|
nNodes = Abc_NtkObjNumMax( pAig );
|
|
pObj = Abc_AigAnd( (Abc_Aig_t *)pAig->pManFunc, pFanin0, pFanin1 );
|
|
assert( !Abc_ObjIsComplement(pObj) );
|
|
pIfObj->pCopy = pObj;
|
|
|
|
if ( pObj->Id == nNodes )
|
|
{
|
|
// increase storage for truth tables
|
|
// if ( Vec_PtrSize(s_pMan->vTtNodes) <= pObj->Id )
|
|
// Vec_PtrDoubleSimInfo(s_pMan->vTtNodes);
|
|
while ( Vec_PtrSize(s_pMan->vTtNodes) <= pObj->Id )
|
|
Vec_PtrPush( s_pMan->vTtNodes, ABC_ALLOC(unsigned, s_pMan->nWords) );
|
|
|
|
// compute the truth table
|
|
RetValue = Abc_NtkRecComputeTruth( pObj, s_pMan->vTtNodes, nInputs );
|
|
if ( RetValue == 0 )
|
|
{
|
|
s_pMan->nFilterError++;
|
|
printf( "T" );
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
assert(pObj);
|
|
pTruth = (unsigned *)Vec_PtrEntry( s_pMan->vTtNodes, pObj->Id );
|
|
if ( Kit_TruthSupport(pTruth, nInputs) != Kit_BitMask(nLeaves) )
|
|
{
|
|
s_pMan->nFilterError++;
|
|
printf( "S" );
|
|
return 1;
|
|
}
|
|
|
|
// compare the truth tables
|
|
if ( !Kit_TruthIsEqualWithPhase( pTruth, pInOut, nInputs ) )
|
|
{
|
|
s_pMan->nFilterError++;
|
|
printf( "F" );
|
|
return 1;
|
|
}
|
|
// Extra_PrintBinary( stdout, pInOut, 8 ); printf( "\n" );
|
|
|
|
// if not new nodes were added and the node has a CO fanout
|
|
if ( nNodesBeg == Abc_NtkObjNumMax(pAig) && Abc_NodeFindCoFanout(pObj) != NULL )
|
|
{
|
|
s_pMan->nFilterSame++;
|
|
return 1;
|
|
}
|
|
s_pMan->nAdded++;
|
|
|
|
// create PO for this node
|
|
pObjPo = Abc_NtkCreatePo(pAig);
|
|
Abc_ObjAddFanin( pObjPo, pObj );
|
|
|
|
// assign the name to this PO
|
|
sprintf( Name, "%d_%06d", nLeaves, Abc_NtkPoNum(pAig) );
|
|
if ( (nInputs <= 6) && 0 )
|
|
{
|
|
Extra_PrintHexadecimalString( Truth, pInOut, nInputs );
|
|
sprintf( Buffer, "%s_%s", Name, Truth );
|
|
}
|
|
else
|
|
{
|
|
sprintf( Buffer, "%s", Name );
|
|
}
|
|
Abc_ObjAssignName( pObjPo, Buffer, NULL );
|
|
|
|
// add the resulting truth table to the hash table
|
|
ppSpot = Abc_NtkRecTableLookup( s_pMan, pTruth, nInputs );
|
|
assert( pObj->pData == NULL );
|
|
assert( pObj->pCopy == NULL );
|
|
if ( *ppSpot == NULL )
|
|
{
|
|
s_pMan->nAddedFuncs++;
|
|
*ppSpot = pObj;
|
|
}
|
|
else
|
|
{
|
|
pObj->pData = (*ppSpot)->pData;
|
|
(*ppSpot)->pData = pObj;
|
|
if ( !Abc_NtkRecAddCutCheckCycle_rec(*ppSpot, pObj) )
|
|
printf( "Loop!\n" );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Labels the record AIG with the corresponding new AIG nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Obj_t * Abc_NtkRecStrashNodeLabel_rec( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pObj, int fBuild, Vec_Ptr_t * vLabels )
|
|
{
|
|
Abc_Obj_t * pFanin0New, * pFanin1New, * pLabel;
|
|
assert( !Abc_ObjIsComplement(pObj) );
|
|
// if this node is already visited, skip
|
|
if ( Abc_NodeIsTravIdCurrent( pObj ) )
|
|
return (Abc_Obj_t *)Vec_PtrEntry( vLabels, pObj->Id );
|
|
assert( Abc_ObjIsNode(pObj) );
|
|
// mark the node as visited
|
|
Abc_NodeSetTravIdCurrent( pObj );
|
|
// label the fanins
|
|
pFanin0New = Abc_NtkRecStrashNodeLabel_rec( pNtkNew, Abc_ObjFanin0(pObj), fBuild, vLabels );
|
|
pFanin1New = Abc_NtkRecStrashNodeLabel_rec( pNtkNew, Abc_ObjFanin1(pObj), fBuild, vLabels );
|
|
// label the node if possible
|
|
pLabel = NULL;
|
|
if ( pFanin0New && pFanin1New )
|
|
{
|
|
pFanin0New = Abc_ObjNotCond( pFanin0New, Abc_ObjFaninC0(pObj) );
|
|
pFanin1New = Abc_ObjNotCond( pFanin1New, Abc_ObjFaninC1(pObj) );
|
|
if ( fBuild )
|
|
pLabel = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, pFanin0New, pFanin1New );
|
|
else
|
|
pLabel = Abc_AigAndLookup( (Abc_Aig_t *)pNtkNew->pManFunc, pFanin0New, pFanin1New );
|
|
}
|
|
Vec_PtrWriteEntry( vLabels, pObj->Id, pLabel );
|
|
return pLabel;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Counts the area of the given node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecStrashNodeCount_rec( Abc_Obj_t * pObj, Vec_Str_t * vCosts, Vec_Ptr_t * vLabels )
|
|
{
|
|
int Cost0, Cost1;
|
|
if ( Vec_PtrEntry( vLabels, pObj->Id ) )
|
|
return 0;
|
|
assert( Abc_ObjIsNode(pObj) );
|
|
// if this node is already visited, skip
|
|
if ( Abc_NodeIsTravIdCurrent( pObj ) )
|
|
return Vec_StrEntry( vCosts, pObj->Id );
|
|
// mark the node as visited
|
|
Abc_NodeSetTravIdCurrent( pObj );
|
|
// count for the fanins
|
|
Cost0 = Abc_NtkRecStrashNodeCount_rec( Abc_ObjFanin0(pObj), vCosts, vLabels );
|
|
Cost1 = Abc_NtkRecStrashNodeCount_rec( Abc_ObjFanin1(pObj), vCosts, vLabels );
|
|
Vec_StrWriteEntry( vCosts, pObj->Id, (char)(Cost0 + Cost1 + 1) );
|
|
return Cost0 + Cost1 + 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Strashes the given node using its local function.]
|
|
|
|
Description [Assumes that the fanins are already strashed.
|
|
Returns 0 if the function is not found in the table.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecStrashNode( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pObj, unsigned * pTruth, int nVars )
|
|
{
|
|
char pCanonPerm[16];
|
|
Abc_Ntk_t * pAig = s_pMan->pNtk;
|
|
unsigned * pInOut = s_pMan->pTemp1;
|
|
unsigned * pTemp = s_pMan->pTemp2;
|
|
unsigned * pTruthRec;
|
|
Abc_Obj_t * pCand, * pCandMin, * pLeaf, * pFanin, ** ppSpot;
|
|
unsigned uCanonPhase;
|
|
int i, nLeaves, CostMin, Cost, nOnes, fCompl;
|
|
|
|
// check if the record works
|
|
nLeaves = Abc_ObjFaninNum(pObj);
|
|
assert( nLeaves >= 3 && nLeaves <= s_pMan->nVars );
|
|
pFanin = Abc_ObjFanin0(pObj);
|
|
assert( Abc_ObjRegular(pFanin->pCopy)->pNtk == pNtkNew );
|
|
assert( s_pMan != NULL );
|
|
assert( nVars == s_pMan->nVars );
|
|
|
|
// copy the truth table
|
|
Kit_TruthCopy( pInOut, pTruth, nVars );
|
|
|
|
// set permutation
|
|
for ( i = 0; i < nVars; i++ )
|
|
pCanonPerm[i] = i;
|
|
|
|
// canonicize the truth table
|
|
uCanonPhase = Kit_TruthSemiCanonicize( pInOut, pTemp, nVars, pCanonPerm, (short *)s_pMan->pMints );
|
|
|
|
// get hold of the curresponding class
|
|
ppSpot = Abc_NtkRecTableLookup( s_pMan, pInOut, nVars );
|
|
if ( *ppSpot == NULL )
|
|
{
|
|
s_pMan->nFunsNotFound++;
|
|
// printf( "The class of a function with %d inputs is not found.\n", nLeaves );
|
|
return 0;
|
|
}
|
|
s_pMan->nFunsFound++;
|
|
|
|
// make sure the truth table is the same
|
|
pTruthRec = (unsigned *)Vec_PtrEntry( s_pMan->vTtNodes, (*ppSpot)->Id );
|
|
if ( !Kit_TruthIsEqualWithPhase( pTruthRec, pInOut, nVars ) )
|
|
{
|
|
assert( 0 );
|
|
return 0;
|
|
}
|
|
|
|
|
|
// allocate storage for costs
|
|
if ( s_pMan->vLabels && Vec_PtrSize(s_pMan->vLabels) < Abc_NtkObjNumMax(pAig) )
|
|
{
|
|
Vec_PtrFree( s_pMan->vLabels );
|
|
s_pMan->vLabels = NULL;
|
|
}
|
|
if ( s_pMan->vLabels == NULL )
|
|
s_pMan->vLabels = Vec_PtrStart( Abc_NtkObjNumMax(pAig) );
|
|
|
|
// go through the variables in the new truth table
|
|
Abc_NtkIncrementTravId( pAig );
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
{
|
|
// get hold of the corresponding fanin
|
|
pFanin = Abc_ObjFanin( pObj, pCanonPerm[i] )->pCopy;
|
|
pFanin = Abc_ObjNotCond( pFanin, (uCanonPhase & (1 << i)) );
|
|
// label the PI of the AIG subgraphs with this fanin
|
|
pLeaf = Abc_NtkPi( pAig, i );
|
|
Vec_PtrWriteEntry( s_pMan->vLabels, pLeaf->Id, pFanin );
|
|
Abc_NodeSetTravIdCurrent( pLeaf );
|
|
}
|
|
|
|
// go through the candidates - and recursively label them
|
|
for ( pCand = *ppSpot; pCand; pCand = (Abc_Obj_t *)pCand->pData )
|
|
Abc_NtkRecStrashNodeLabel_rec( pNtkNew, pCand, 0, s_pMan->vLabels );
|
|
|
|
|
|
// allocate storage for costs
|
|
if ( s_pMan->vCosts && Vec_StrSize(s_pMan->vCosts) < Abc_NtkObjNumMax(pAig) )
|
|
{
|
|
Vec_StrFree( s_pMan->vCosts );
|
|
s_pMan->vCosts = NULL;
|
|
}
|
|
if ( s_pMan->vCosts == NULL )
|
|
s_pMan->vCosts = Vec_StrStart( Abc_NtkObjNumMax(pAig) );
|
|
|
|
// find the best subgraph
|
|
CostMin = ABC_INFINITY;
|
|
pCandMin = NULL;
|
|
for ( pCand = *ppSpot; pCand; pCand = (Abc_Obj_t *)pCand->pData )
|
|
{
|
|
// label the leaves
|
|
Abc_NtkIncrementTravId( pAig );
|
|
// count the number of non-labeled nodes
|
|
Cost = Abc_NtkRecStrashNodeCount_rec( pCand, s_pMan->vCosts, s_pMan->vLabels );
|
|
if ( CostMin > Cost )
|
|
{
|
|
// printf( "%d ", Cost );
|
|
CostMin = Cost;
|
|
pCandMin = pCand;
|
|
}
|
|
}
|
|
// printf( "\n" );
|
|
assert( pCandMin != NULL );
|
|
if ( pCandMin == NULL )
|
|
return 0;
|
|
|
|
|
|
// label the leaves
|
|
Abc_NtkIncrementTravId( pAig );
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
Abc_NodeSetTravIdCurrent( Abc_NtkPi(pAig, i) );
|
|
|
|
// implement the subgraph
|
|
pObj->pCopy = Abc_NtkRecStrashNodeLabel_rec( pNtkNew, pCandMin, 1, s_pMan->vLabels );
|
|
assert( Abc_ObjRegular(pObj->pCopy)->pNtk == pNtkNew );
|
|
|
|
// determine phase difference
|
|
nOnes = Kit_TruthCountOnes(pTruth, nVars);
|
|
fCompl = (nOnes > (1<< nVars)/2);
|
|
// assert( fCompl == ((uCanonPhase & (1 << nVars)) > 0) );
|
|
|
|
nOnes = Kit_TruthCountOnes(pTruthRec, nVars);
|
|
fCompl ^= (nOnes > (1<< nVars)/2);
|
|
// complement
|
|
pObj->pCopy = Abc_ObjNotCond( pObj->pCopy, fCompl );
|
|
return 1;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|