mirror of https://github.com/YosysHQ/abc.git
1434 lines
51 KiB
C
1434 lines
51 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [abcRec2.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network and node package.]
|
|
|
|
Synopsis [Record of semi-canonical AIG subgraphs.]
|
|
|
|
Author [Allan Yang, Alan Mishchenko]
|
|
|
|
Affiliation [Fudan University in Shanghai, 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 "base/abc/abc.h"
|
|
#include "map/if/if.h"
|
|
#include "bool/kit/kit.h"
|
|
#include "aig/gia/giaAig.h"
|
|
#include "misc/vec/vecMem.h"
|
|
#include "opt/dau/dau.h"
|
|
#include "misc/util/utilTruth.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
#define LMS_VAR_MAX 16 // LMS_VAR_MAX >= 6
|
|
#define LMS_MAX_WORD (1<<(LMS_VAR_MAX-6))
|
|
//#define LMS_USE_OLD_FORM
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
This LMS manager can be used in two modes:
|
|
- library constuction
|
|
- AIG level minimization
|
|
To switch from library construction to AIG level minimization
|
|
LSM manager should be restarted by dumping GIA (rec_dump3 <file>.aig)
|
|
and starting LMS manager again (rec_start3 <file>.aig).
|
|
*/
|
|
|
|
typedef struct Lms_Man_t_ Lms_Man_t;
|
|
struct Lms_Man_t_
|
|
{
|
|
// parameters
|
|
int nVars; // the number of variables
|
|
int nWords; // the number of TT words
|
|
int nCuts; // the max number of cuts to use
|
|
int fFuncOnly; // record only functions
|
|
int fLibConstr; // this manager is used for library construction
|
|
// internal data for library construction
|
|
Gia_Man_t * pGia; // the record
|
|
Vec_Mem_t * vTtMem; // truth table memory and hash table
|
|
// Vec_Mem_t * vTtMem2; // truth table memory and hash table
|
|
Vec_Int_t * vTruthIds; // truth table IDs of each PO
|
|
// internal data for AIG level minimization (allocated the first time it is called)
|
|
Vec_Int_t * vTruthPo; // first PO where this canonicized truth table was seen
|
|
Vec_Wrd_t * vDelays; // pin-to-pin delays of each PO
|
|
Vec_Str_t * vAreas; // number of AND gates in each PO
|
|
Vec_Int_t * vFreqs; // subgraph usage frequencies
|
|
Vec_Int_t * vTruthFreqs; // truth table usage frequencies
|
|
// temporaries
|
|
Vec_Ptr_t * vNodes; // the temporary nodes
|
|
Vec_Ptr_t * vLabelsP; // temporary storage for HOP node labels
|
|
Vec_Int_t * vLabels; // temporary storage for AIG node labels
|
|
Vec_Str_t * vSupps; // used temporarily by TT dumping
|
|
word pTemp1[LMS_MAX_WORD]; // copy of the truth table
|
|
word pTemp2[LMS_MAX_WORD]; // copy of the truth table
|
|
// statistics
|
|
int nTried;
|
|
int nFilterSize;
|
|
int nFilterRedund;
|
|
int nFilterVolume;
|
|
int nFilterTruth;
|
|
int nFilterError;
|
|
int nFilterSame;
|
|
int nAdded;
|
|
int nAddedFuncs;
|
|
int nHoleInTheWall;
|
|
// runtime
|
|
abctime timeTruth;
|
|
abctime timeCanon;
|
|
abctime timeBuild;
|
|
abctime timeCheck;
|
|
abctime timeInsert;
|
|
abctime timeOther;
|
|
abctime timeTotal;
|
|
};
|
|
|
|
static Lms_Man_t * s_pMan3 = NULL;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Compute delay/area profiles of POs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline int Lms_DelayGet( word D, int v ) { assert(v >= 0 && v < LMS_VAR_MAX); return (int)((D >> (v << 2)) & 0xF); }
|
|
static inline void Lms_DelaySet( word * pD, int v, int d ) { assert(v >= 0 && v < LMS_VAR_MAX); assert(d >= 0 && d < LMS_VAR_MAX); *pD |= ((word)d << (v << 2)); }
|
|
static inline word Lms_DelayInit( int v ) { assert(v >= 0 && v < LMS_VAR_MAX); return (word)1 << (v << 2); }
|
|
static inline word Lms_DelayMax( word D1, word D2, int nVars )
|
|
{
|
|
int v, Max;
|
|
word D = 0;
|
|
for ( v = 0; v < nVars; v++ )
|
|
if ( (Max = Abc_MaxInt(Lms_DelayGet(D1, v), Lms_DelayGet(D2, v))) )
|
|
Lms_DelaySet( &D, v, Abc_MinInt(Max + 1, 15) );
|
|
return D;
|
|
}
|
|
static inline word Lms_DelayDecrement( word D1, int nVars )
|
|
{
|
|
int v;
|
|
word D = 0;
|
|
for ( v = 0; v < nVars; v++ )
|
|
if ( Lms_DelayGet(D1, v) )
|
|
Lms_DelaySet( &D, v, Lms_DelayGet(D1, v) - 1 );
|
|
return D;
|
|
}
|
|
static inline int Lms_DelayEqual( word D1, word D2, int nVars ) // returns 1 if D1 has the same delays than D2
|
|
{
|
|
int v;
|
|
for ( v = 0; v < nVars; v++ )
|
|
if ( Lms_DelayGet(D1, v) != Lms_DelayGet(D2, v) )
|
|
return 0;
|
|
return 1;
|
|
}
|
|
static inline int Lms_DelayDom( word D1, word D2, int nVars ) // returns 1 if D1 has the same or smaller delays than D2
|
|
{
|
|
int v;
|
|
for ( v = 0; v < nVars; v++ )
|
|
if ( Lms_DelayGet(D1, v) > Lms_DelayGet(D2, v) )
|
|
return 0;
|
|
return 1;
|
|
}
|
|
static inline void Lms_DelayPrint( word D, int nVars )
|
|
{
|
|
int v;
|
|
printf( "Delay profile = {" );
|
|
for ( v = 0; v < nVars; v++ )
|
|
printf( " %d", Lms_DelayGet(D, v) );
|
|
printf( " }\n" );
|
|
}
|
|
Vec_Wrd_t * Lms_GiaDelays( Gia_Man_t * p )
|
|
{
|
|
Vec_Wrd_t * vDelays, * vResult;
|
|
Gia_Obj_t * pObj;
|
|
int i;
|
|
// compute delay profiles of all objects
|
|
vDelays = Vec_WrdAlloc( Gia_ManObjNum(p) );
|
|
Vec_WrdPush( vDelays, 0 ); // const 0
|
|
Gia_ManForEachObj1( p, pObj, i )
|
|
{
|
|
if ( Gia_ObjIsAnd(pObj) )
|
|
Vec_WrdPush( vDelays, Lms_DelayMax( Vec_WrdEntry(vDelays, Gia_ObjFaninId0(pObj, i)), Vec_WrdEntry(vDelays, Gia_ObjFaninId1(pObj, i)), Gia_ManCiNum(p) ) );
|
|
else if ( Gia_ObjIsCo(pObj) )
|
|
Vec_WrdPush( vDelays, Lms_DelayDecrement( Vec_WrdEntry(vDelays, Gia_ObjFaninId0(pObj, i)), Gia_ManCiNum(p) ) );
|
|
else if ( Gia_ObjIsCi(pObj) )
|
|
Vec_WrdPush( vDelays, Lms_DelayInit( Gia_ObjCioId(pObj) ) );
|
|
else assert( 0 );
|
|
}
|
|
// collect delay profiles of COs only
|
|
vResult = Vec_WrdAlloc( Gia_ManCoNum(p) );
|
|
Gia_ManForEachCo( p, pObj, i )
|
|
Vec_WrdPush( vResult, Vec_WrdEntry(vDelays, Gia_ObjId(p, pObj)) );
|
|
Vec_WrdFree( vDelays );
|
|
return vResult;
|
|
}
|
|
void Lms_ObjAreaMark_rec( Gia_Obj_t * pObj )
|
|
{
|
|
if ( pObj->fMark0 || Gia_ObjIsCi(pObj) )
|
|
return;
|
|
pObj->fMark0 = 1;
|
|
Lms_ObjAreaMark_rec( Gia_ObjFanin0(pObj) );
|
|
Lms_ObjAreaMark_rec( Gia_ObjFanin1(pObj) );
|
|
}
|
|
int Lms_ObjAreaUnmark_rec( Gia_Obj_t * pObj )
|
|
{
|
|
if ( !pObj->fMark0 || Gia_ObjIsCi(pObj) )
|
|
return 0;
|
|
pObj->fMark0 = 0;
|
|
return 1 + Lms_ObjAreaUnmark_rec( Gia_ObjFanin0(pObj) )
|
|
+ Lms_ObjAreaUnmark_rec( Gia_ObjFanin1(pObj) );
|
|
}
|
|
int Lms_ObjArea( Gia_Obj_t * pObj )
|
|
{
|
|
assert( Gia_ObjIsAnd(pObj) );
|
|
Lms_ObjAreaMark_rec( pObj );
|
|
return Lms_ObjAreaUnmark_rec( pObj );
|
|
}
|
|
Vec_Str_t * Lms_GiaAreas( Gia_Man_t * p )
|
|
{
|
|
Vec_Str_t * vAreas;
|
|
Gia_Obj_t * pObj;
|
|
int i;
|
|
vAreas = Vec_StrAlloc( Gia_ManCoNum(p) );
|
|
Gia_ManForEachCo( p, pObj, i )
|
|
Vec_StrPush( vAreas, (char)(Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) ? Lms_ObjArea(Gia_ObjFanin0(pObj)) : 0) );
|
|
return vAreas;
|
|
}
|
|
Vec_Str_t * Lms_GiaSuppSizes( Gia_Man_t * p )
|
|
{
|
|
Vec_Str_t * vResult;
|
|
Vec_Str_t * vSupps;
|
|
Gia_Obj_t * pObj;
|
|
int i;
|
|
vSupps = Vec_StrAlloc( Gia_ManObjNum(p) );
|
|
Vec_StrPush( vSupps, 0 );
|
|
Gia_ManForEachObj1( p, pObj, i )
|
|
{
|
|
if ( Gia_ObjIsAnd(pObj) )
|
|
Vec_StrPush( vSupps, (char)Abc_MaxInt( Vec_StrEntry(vSupps, Gia_ObjFaninId0(pObj, i)), Vec_StrEntry(vSupps, Gia_ObjFaninId1(pObj, i)) ) );
|
|
else if ( Gia_ObjIsCo(pObj) )
|
|
Vec_StrPush( vSupps, Vec_StrEntry(vSupps, Gia_ObjFaninId0(pObj, i)) );
|
|
else if ( Gia_ObjIsCi(pObj) )
|
|
Vec_StrPush( vSupps, (char)(Gia_ObjCioId(pObj)+1) );
|
|
else assert( 0 );
|
|
}
|
|
assert( Vec_StrSize(vSupps) == Gia_ManObjNum(p) );
|
|
vResult = Vec_StrAlloc( Gia_ManCoNum(p) );
|
|
Gia_ManForEachCo( p, pObj, i )
|
|
Vec_StrPush( vResult, Vec_StrEntry(vSupps, Gia_ObjId(p, pObj)) );
|
|
Vec_StrFree( vSupps );
|
|
return vResult;
|
|
}
|
|
void Lms_GiaProfilesPrint( Gia_Man_t * p )
|
|
{
|
|
Gia_Obj_t * pObj;
|
|
int i;
|
|
Vec_Wrd_t * vDelays;
|
|
Vec_Str_t * vAreas;
|
|
vDelays = Lms_GiaDelays( p );
|
|
vAreas = Lms_GiaAreas( p );
|
|
Gia_ManForEachPo( p, pObj, i )
|
|
{
|
|
printf( "%6d : ", i );
|
|
printf( "A = %2d ", Vec_StrEntry(vAreas, i) );
|
|
Lms_DelayPrint( Vec_WrdEntry(vDelays, i), Gia_ManPiNum(p) );
|
|
// Lms_GiaPrintSubgraph( p, pObj );
|
|
// printf( "\n" );
|
|
}
|
|
Vec_WrdFree( vDelays );
|
|
Vec_StrFree( vAreas );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Prints one GIA subgraph.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Lms_GiaPrintSubgraph_rec( Gia_Man_t * p, Gia_Obj_t * pObj )
|
|
{
|
|
if ( !pObj->fMark0 || Gia_ObjIsCi(pObj) )
|
|
return;
|
|
pObj->fMark0 = 0;
|
|
assert( Gia_ObjIsAnd(pObj) );
|
|
Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin0(pObj) );
|
|
Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin1(pObj) );
|
|
Gia_ObjPrint( p, pObj );
|
|
}
|
|
void Lms_GiaPrintSubgraph( Gia_Man_t * p, Gia_Obj_t * pObj )
|
|
{
|
|
assert( Gia_ObjIsCo(pObj) );
|
|
if ( Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) )
|
|
{
|
|
Lms_ObjAreaMark_rec( Gia_ObjFanin0(pObj) );
|
|
Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin0(pObj) );
|
|
}
|
|
else
|
|
Gia_ObjPrint( p, Gia_ObjFanin0(pObj) );
|
|
Gia_ObjPrint( p, pObj );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis []
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Lms_Man_t * Lms_ManStart( Gia_Man_t * pGia, int nVars, int nCuts, int fFuncOnly, int fVerbose )
|
|
{
|
|
Lms_Man_t * p;
|
|
abctime clk, clk2 = Abc_Clock();
|
|
// if GIA is given, use the number of variables from GIA
|
|
nVars = pGia ? Gia_ManCiNum(pGia) : nVars;
|
|
assert( nVars >= 6 && nVars <= LMS_VAR_MAX );
|
|
// allocate manager
|
|
p = ABC_CALLOC( Lms_Man_t, 1 );
|
|
// parameters
|
|
p->nVars = nVars;
|
|
p->nCuts = nCuts;
|
|
p->nWords = Abc_Truth6WordNum( nVars );
|
|
p->fFuncOnly = fFuncOnly;
|
|
// internal data for library construction
|
|
p->vTtMem = Vec_MemAlloc( p->nWords, 12 ); // 32 KB/page for 6-var functions
|
|
// p->vTtMem2 = Vec_MemAlloc( p->nWords, 12 ); // 32 KB/page for 6-var functions
|
|
Vec_MemHashAlloc( p->vTtMem, 10000 );
|
|
// Vec_MemHashAlloc( p->vTtMem2, 10000 );
|
|
if ( fFuncOnly )
|
|
return p;
|
|
p->vTruthIds = Vec_IntAlloc( 10000 );
|
|
if ( pGia == NULL )
|
|
{
|
|
int i;
|
|
p->pGia = Gia_ManStart( 10000 );
|
|
p->pGia->pName = Abc_UtilStrsav( "record" );
|
|
for ( i = 0; i < nVars; i++ )
|
|
Gia_ManAppendCi( p->pGia );
|
|
}
|
|
else
|
|
{
|
|
Gia_Obj_t * pObj;
|
|
word * pTruth;
|
|
int i, Index, Prev = -1;
|
|
p->pGia = pGia;
|
|
// populate the manager with subgraphs present in GIA
|
|
p->nAdded = Gia_ManCoNum( p->pGia );
|
|
Gia_ManForEachCo( p->pGia, pObj, i )
|
|
{
|
|
clk = Abc_Clock();
|
|
pTruth = Gia_ObjComputeTruthTable( p->pGia, pObj );
|
|
p->timeTruth += Abc_Clock() - clk;
|
|
clk = Abc_Clock();
|
|
Index = Vec_MemHashInsert( p->vTtMem, pTruth );
|
|
p->timeInsert += Abc_Clock() - clk;
|
|
assert( Index == Prev || Index == Prev + 1 ); // GIA subgraphs should be ordered
|
|
Vec_IntPush( p->vTruthIds, Index );
|
|
Prev = Index;
|
|
}
|
|
}
|
|
// temporaries
|
|
p->vNodes = Vec_PtrAlloc( 1000 );
|
|
p->vLabelsP = Vec_PtrAlloc( 1000 );
|
|
p->vLabels = Vec_IntAlloc( 1000 );
|
|
p->timeTotal += Abc_Clock() - clk2;
|
|
return p;
|
|
}
|
|
void Lms_ManStop( Lms_Man_t * p )
|
|
{
|
|
// temporaries
|
|
Vec_IntFreeP( &p->vLabels );
|
|
Vec_PtrFreeP( &p->vLabelsP );
|
|
Vec_PtrFreeP( &p->vNodes );
|
|
// internal data for AIG level minimization
|
|
Vec_IntFreeP( &p->vTruthPo );
|
|
Vec_WrdFreeP( &p->vDelays );
|
|
Vec_StrFreeP( &p->vAreas );
|
|
Vec_IntFreeP( &p->vFreqs );
|
|
Vec_IntFreeP( &p->vTruthFreqs );
|
|
// internal data for library construction
|
|
Vec_IntFreeP( &p->vTruthIds );
|
|
Vec_MemHashFree( p->vTtMem );
|
|
// Vec_MemHashFree( p->vTtMem2 );
|
|
Vec_MemFree( p->vTtMem );
|
|
// Vec_MemFree( p->vTtMem2 );
|
|
Gia_ManStopP( &p->pGia );
|
|
ABC_FREE( p );
|
|
}
|
|
void Lms_ManPrepare( Lms_Man_t * p )
|
|
{
|
|
// compute the first PO for each semi-canonical form
|
|
int i, Entry;
|
|
assert( !p->fLibConstr );
|
|
assert( p->vTruthPo == NULL );
|
|
p->vTruthPo = Vec_IntStartFull( Vec_MemEntryNum(p->vTtMem)+1 );
|
|
assert( Vec_IntFindMin(p->vTruthIds) >= 0 );
|
|
assert( Vec_IntFindMax(p->vTruthIds) < Vec_MemEntryNum(p->vTtMem) );
|
|
Vec_IntForEachEntry( p->vTruthIds, Entry, i )
|
|
if ( Vec_IntEntry(p->vTruthPo, Entry) == -1 )
|
|
Vec_IntWriteEntry( p->vTruthPo, Entry, i );
|
|
Vec_IntWriteEntry( p->vTruthPo, Vec_MemEntryNum(p->vTtMem), Gia_ManCoNum(p->pGia) );
|
|
// compute delay/area and init frequency
|
|
assert( p->vDelays == NULL );
|
|
assert( p->vAreas == NULL );
|
|
assert( p->vFreqs == NULL );
|
|
p->vDelays = Lms_GiaDelays( p->pGia );
|
|
p->vAreas = Lms_GiaAreas( p->pGia );
|
|
p->vFreqs = Vec_IntStart( Gia_ManCoNum(p->pGia) );
|
|
}
|
|
void Lms_ManPrintFuncStats( Lms_Man_t * p )
|
|
{
|
|
Vec_Str_t * vSupps;
|
|
int Counters[LMS_VAR_MAX+1] = {0}, CountersS[LMS_VAR_MAX+1] = {0};
|
|
int i, Entry, Next;
|
|
if ( p->pGia == NULL )
|
|
return;
|
|
if ( p->fLibConstr )
|
|
return;
|
|
if ( p->vTruthPo == NULL )
|
|
Lms_ManPrepare( p );
|
|
vSupps = Lms_GiaSuppSizes( p->pGia );
|
|
Vec_IntForEachEntry( p->vTruthPo, Entry, i )
|
|
{
|
|
if ( i == Vec_IntSize(p->vTruthPo) - 1 )
|
|
break;
|
|
Next = Vec_IntEntry( p->vTruthPo, i+1 );
|
|
Counters[(int)Vec_StrEntry(vSupps, Entry)]++;
|
|
CountersS[(int)Vec_StrEntry(vSupps, Entry)] += Next - Entry;
|
|
}
|
|
for ( i = 0; i <= LMS_VAR_MAX; 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] );
|
|
Vec_StrFree( vSupps );
|
|
}
|
|
void Lms_ManPrintFreqStats( Lms_Man_t * p )
|
|
{
|
|
int CountDsdNpn[3] = {0}; // full/part/none
|
|
int CountDsdAll[3] = {0}; // full/part/none
|
|
int CountStepNpn[3] = {0}; // full/1step/complex
|
|
int CountStepAll[3] = {0}; // full/1step/complex
|
|
char pBuffer[1000];
|
|
int nSuppSize;
|
|
int nNonDecSize;
|
|
word * pTruth;
|
|
int i, Freq, Status;
|
|
printf( "Cuts = %10d. ", p->nTried );
|
|
// printf( "Funcs = %10d (%6.2f %%). ", Vec_MemEntryNum(p->vTtMem2), 100.0*Vec_MemEntryNum(p->vTtMem2)/p->nTried );
|
|
printf( "Class = %10d (%6.2f %%). ", Vec_MemEntryNum(p->vTtMem), 100.0*Vec_MemEntryNum(p->vTtMem)/p->nTried );
|
|
printf( "\n" );
|
|
// return;
|
|
|
|
Vec_IntForEachEntry( p->vTruthFreqs, Freq, i )
|
|
{
|
|
pTruth = Vec_MemReadEntry(p->vTtMem, i);
|
|
/*
|
|
printf( "%6d -- %6d : ", i, Freq );
|
|
Kit_DsdWriteFromTruth( pBuffer, (unsigned *)pTruth, p->nVars );
|
|
printf( "%s\n", pBuffer );
|
|
*/
|
|
nSuppSize = Abc_TtSupportSize( pTruth, p->nVars );
|
|
nNonDecSize = Dau_DsdDecompose( pTruth, p->nVars, 0, 0, pBuffer );
|
|
if ( nNonDecSize == 0 )
|
|
{
|
|
CountDsdNpn[0]++;
|
|
CountDsdAll[0] += Freq;
|
|
}
|
|
else if ( nNonDecSize < nSuppSize )
|
|
{
|
|
CountDsdNpn[1]++;
|
|
CountDsdAll[1] += Freq;
|
|
}
|
|
else // non-dec
|
|
{
|
|
CountDsdNpn[2]++;
|
|
CountDsdAll[2] += Freq;
|
|
}
|
|
|
|
if ( nNonDecSize == 0 )
|
|
{
|
|
CountStepNpn[0]++;
|
|
CountStepAll[0] += Freq;
|
|
continue;
|
|
}
|
|
|
|
// check the non dec core
|
|
Status = Dau_DsdCheck1Step( NULL, pTruth, nNonDecSize, NULL );
|
|
if ( Status >= 0 )
|
|
{
|
|
CountStepNpn[1]++;
|
|
CountStepAll[1] += Freq;
|
|
}
|
|
else
|
|
{
|
|
assert( Status == -2 );
|
|
CountStepNpn[2]++;
|
|
CountStepAll[2] += Freq;
|
|
}
|
|
}
|
|
|
|
// print the results
|
|
printf( "NPN: " );
|
|
printf( "Full = %6.2f %% ", 100.0 * CountDsdNpn[0] / Vec_MemEntryNum(p->vTtMem) );
|
|
printf( "Part = %6.2f %% ", 100.0 * CountDsdNpn[1] / Vec_MemEntryNum(p->vTtMem) );
|
|
printf( "None = %6.2f %% ", 100.0 * CountDsdNpn[2] / Vec_MemEntryNum(p->vTtMem) );
|
|
// printf( "\n" );
|
|
printf( " " );
|
|
// print the results
|
|
printf( "All: " );
|
|
printf( "Full = %6.2f %% ", 100.0 * CountDsdAll[0] / p->nTried );
|
|
printf( "Part = %6.2f %% ", 100.0 * CountDsdAll[1] / p->nTried );
|
|
printf( "None = %6.2f %% ", 100.0 * CountDsdAll[2] / p->nTried );
|
|
printf( "\n" );
|
|
|
|
// print the results
|
|
printf( "NPN: " );
|
|
printf( "Full = %6.2f %% ", 100.0 * CountStepNpn[0] / Vec_MemEntryNum(p->vTtMem) );
|
|
printf( "1stp = %6.2f %% ", 100.0 * CountStepNpn[1] / Vec_MemEntryNum(p->vTtMem) );
|
|
printf( "Comp = %6.2f %% ", 100.0 * CountStepNpn[2] / Vec_MemEntryNum(p->vTtMem) );
|
|
// printf( "\n" );
|
|
printf( " " );
|
|
// print the results
|
|
printf( "All: " );
|
|
printf( "Full = %6.2f %% ", 100.0 * CountStepAll[0] / p->nTried );
|
|
printf( "1stp = %6.2f %% ", 100.0 * CountStepAll[1] / p->nTried );
|
|
printf( "Comp = %6.2f %% ", 100.0 * CountStepAll[2] / p->nTried );
|
|
printf( "\n" );
|
|
|
|
}
|
|
void Lms_ManPrint( Lms_Man_t * p )
|
|
{
|
|
// Gia_ManPrintStats( p->pGia, 0, 0 );
|
|
printf( "Library with %d vars has %d classes and %d AIG subgraphs with %d AND nodes.\n",
|
|
p->nVars, Vec_MemEntryNum(p->vTtMem), p->nAdded, p->pGia ? Gia_ManAndNum(p->pGia) : 0 );
|
|
|
|
// Lms_ManPrintFreqStats( p );
|
|
Lms_ManPrintFuncStats( p );
|
|
|
|
p->nAddedFuncs = Vec_MemEntryNum(p->vTtMem);
|
|
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 );
|
|
if ( p->nHoleInTheWall )
|
|
printf( "Cuts whose logic structure has a hole = %10d. (%6.2f %%)\n", p->nHoleInTheWall, !p->nTried? 0 : 100.0*p->nHoleInTheWall/p->nTried );
|
|
|
|
p->timeOther = p->timeTotal - p->timeTruth - p->timeCanon - p->timeBuild - p->timeCheck - p->timeInsert;
|
|
ABC_PRTP( "Runtime: Truth ", p->timeTruth, p->timeTotal );
|
|
ABC_PRTP( "Runtime: Canon ", p->timeCanon, p->timeTotal );
|
|
ABC_PRTP( "Runtime: Build ", p->timeBuild, p->timeTotal );
|
|
ABC_PRTP( "Runtime: Check ", p->timeCheck, p->timeTotal );
|
|
ABC_PRTP( "Runtime: Insert", p->timeInsert, p->timeTotal );
|
|
ABC_PRTP( "Runtime: Other ", p->timeOther, p->timeTotal );
|
|
ABC_PRTP( "Runtime: TOTAL ", p->timeTotal, p->timeTotal );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Recanonicizes the library and add it to the current library.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecLibMerge3( Gia_Man_t * pLib )
|
|
{
|
|
int fCheck = 0;
|
|
Lms_Man_t * p = s_pMan3;
|
|
Gia_Man_t * pGia = p->pGia;
|
|
Vec_Str_t * vSupps;
|
|
char pCanonPerm[LMS_VAR_MAX];
|
|
unsigned uCanonPhase;
|
|
word * pTruth;
|
|
int i, k, Index, iFanin0, iFanin1, nLeaves;
|
|
Gia_Obj_t * pObjPo, * pDriver, * pTemp = NULL;
|
|
abctime clk, clk2 = Abc_Clock();
|
|
|
|
if ( Gia_ManCiNum(pLib) != Gia_ManCiNum(pGia) )
|
|
{
|
|
printf( "The number of Library inputs (%d) differs from the number of Gia inputs (%d).\n", Gia_ManCiNum(pLib), Gia_ManCiNum(pGia) );
|
|
return;
|
|
}
|
|
assert( Gia_ManCiNum(pLib) == Gia_ManCiNum(pGia) );
|
|
|
|
// create hash table if not available
|
|
if ( pGia->pHTable == NULL )
|
|
Gia_ManHashStart( pGia );
|
|
|
|
// add AIG subgraphs
|
|
vSupps = Lms_GiaSuppSizes( pLib );
|
|
Gia_ManForEachCo( pLib, pObjPo, k )
|
|
{
|
|
// get support size
|
|
nLeaves = Vec_StrEntry(vSupps, k);
|
|
assert( nLeaves > 1 );
|
|
|
|
// compute the truth table
|
|
clk = Abc_Clock();
|
|
pTruth = Gia_ObjComputeTruthTable( pLib, Gia_ObjFanin0(pObjPo) );
|
|
p->timeTruth += Abc_Clock() - clk;
|
|
// semi-canonicize
|
|
clk = Abc_Clock();
|
|
memcpy( p->pTemp1, pTruth, p->nWords * sizeof(word) );
|
|
#ifdef LMS_USE_OLD_FORM
|
|
uCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm );
|
|
#else
|
|
uCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm );
|
|
#endif
|
|
Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars );
|
|
p->timeCanon += Abc_Clock() - clk;
|
|
// pCanonPerm and uCanonPhase show what was the variable corresponding to each var in the current truth
|
|
if ( nLeaves == 2 && Abc_TtSupportSize(pTruth, 2) != 2 )
|
|
continue;
|
|
|
|
clk = Abc_Clock();
|
|
// map cut leaves into elementary variables of GIA
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
Gia_ManCi( pLib, pCanonPerm[i] )->Value = Abc_Var2Lit( Gia_ObjId(pGia, Gia_ManPi(pGia, i)), (uCanonPhase >> i) & 1 );
|
|
// build internal nodes
|
|
assert( Vec_IntSize(pLib->vTtNodes) > 0 );
|
|
Gia_ManForEachObjVec( pLib->vTtNodes, pLib, pTemp, i )
|
|
{
|
|
iFanin0 = Abc_LitNotCond( Gia_ObjFanin0(pTemp)->Value, Gia_ObjFaninC0(pTemp) );
|
|
iFanin1 = Abc_LitNotCond( Gia_ObjFanin1(pTemp)->Value, Gia_ObjFaninC1(pTemp) );
|
|
pTemp->Value = Gia_ManHashAnd( pGia, iFanin0, iFanin1 );
|
|
}
|
|
p->timeBuild += Abc_Clock() - clk;
|
|
|
|
// check if this node is already driving a PO
|
|
assert( Gia_ObjIsAnd(pTemp) );
|
|
pDriver = Gia_ManObj(pGia, Abc_Lit2Var(pTemp->Value));
|
|
if ( pDriver->fMark1 )
|
|
{
|
|
p->nFilterSame++;
|
|
continue;
|
|
}
|
|
pDriver->fMark1 = 1;
|
|
// create output
|
|
Gia_ManAppendCo( pGia, Abc_LitNotCond( pTemp->Value, (uCanonPhase >> nLeaves) & 1 ) );
|
|
|
|
// verify truth table
|
|
if ( fCheck )
|
|
{
|
|
clk = Abc_Clock();
|
|
pTemp = Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1);
|
|
pTruth = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1) );
|
|
p->timeCheck += Abc_Clock() - clk;
|
|
if ( memcmp( p->pTemp1, pTruth, p->nWords * sizeof(word) ) != 0 )
|
|
{
|
|
|
|
Kit_DsdPrintFromTruth( (unsigned *)pTruth, nLeaves ); printf( "\n" );
|
|
Kit_DsdPrintFromTruth( (unsigned *)p->pTemp1, nLeaves ); printf( "\n" );
|
|
printf( "Truth table verification has failed.\n" );
|
|
|
|
// drive PO with constant
|
|
Gia_ManPatchCoDriver( pGia, Gia_ManCoNum(pGia)-1, 0 );
|
|
// save truth table ID
|
|
Vec_IntPush( p->vTruthIds, -1 );
|
|
p->nFilterTruth++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
clk = Abc_Clock();
|
|
// add the resulting truth table to the hash table
|
|
Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 );
|
|
// save truth table ID
|
|
Vec_IntPush( p->vTruthIds, Index );
|
|
assert( Gia_ManCoNum(pGia) == Vec_IntSize(p->vTruthIds) );
|
|
p->nAdded++;
|
|
p->timeInsert += Abc_Clock() - clk;
|
|
}
|
|
Vec_StrFree( vSupps );
|
|
p->timeTotal += Abc_Clock() - clk2;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Evaluates one cut during library construction.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecAddCut3( If_Man_t * pIfMan, If_Obj_t * pRoot, If_Cut_t * pCut )
|
|
{
|
|
Lms_Man_t * p = s_pMan3;
|
|
char pCanonPerm[LMS_VAR_MAX];
|
|
unsigned uCanonPhase;
|
|
int i, Index, iFanin0, iFanin1, fHole;
|
|
int nLeaves = If_CutLeaveNum(pCut);
|
|
Vec_Ptr_t * vNodes = p->vNodes;
|
|
Gia_Man_t * pGia = p->pGia;
|
|
Gia_Obj_t * pDriver;
|
|
If_Obj_t * pIfObj = NULL;
|
|
word * pTruth;
|
|
abctime clk;
|
|
p->nTried++;
|
|
|
|
// skip small cuts
|
|
assert( p->nVars == (int)pCut->nLimit );
|
|
if ( nLeaves < 2 || (nLeaves == 2 && Abc_TtSupportSize(If_CutTruthW(pIfMan, pCut), 2) != 2) )
|
|
{
|
|
p->nFilterSize++;
|
|
return 1;
|
|
}
|
|
|
|
// if ( p->vTtMem2 )
|
|
// Vec_MemHashInsert( p->vTtMem2, If_CutTruthW(pCut) );
|
|
|
|
// semi-canonicize truth table
|
|
clk = Abc_Clock();
|
|
memcpy( p->pTemp1, If_CutTruthW(pIfMan, pCut), p->nWords * sizeof(word) );
|
|
#ifdef LMS_USE_OLD_FORM
|
|
uCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm );
|
|
#else
|
|
uCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm );
|
|
#endif
|
|
Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars );
|
|
p->timeCanon += Abc_Clock() - clk;
|
|
// pCanonPerm and uCanonPhase show what was the variable corresponding to each var in the current truth
|
|
|
|
if ( p->pGia == NULL )
|
|
{
|
|
clk = Abc_Clock();
|
|
// add the resulting truth table to the hash table
|
|
Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 );
|
|
/*
|
|
if ( p->vTruthFreqs == NULL )
|
|
p->vTruthFreqs = Vec_IntAlloc( 1000 );
|
|
assert( Index <= Vec_IntSize(p->vTruthFreqs) );
|
|
if ( Index < Vec_IntSize(p->vTruthFreqs) )
|
|
Vec_IntAddToEntry( p->vTruthFreqs, Index, 1 );
|
|
else
|
|
Vec_IntPush( p->vTruthFreqs, 1 );
|
|
*/
|
|
p->nAdded++;
|
|
p->timeInsert += Abc_Clock() - clk;
|
|
return 1;
|
|
}
|
|
|
|
// collect internal nodes and skip redundant cuts
|
|
clk = Abc_Clock();
|
|
If_CutTraverse( pIfMan, pRoot, pCut, vNodes );
|
|
p->timeTruth += Abc_Clock() - clk;
|
|
if ( Vec_PtrSize(vNodes) > 253 )
|
|
{
|
|
p->nFilterSize++;
|
|
return 1;
|
|
}
|
|
|
|
clk = Abc_Clock();
|
|
// map cut leaves into elementary variables of GIA
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
If_ManObj( pIfMan, pCut->pLeaves[(int)pCanonPerm[i]] )->iCopy = Abc_Var2Lit( Gia_ObjId(pGia, Gia_ManPi(pGia, i)), (uCanonPhase >> i) & 1 );
|
|
// build internal nodes
|
|
fHole = 0;
|
|
assert( Vec_PtrSize(vNodes) > 0 );
|
|
Vec_PtrForEachEntryStart( If_Obj_t *, vNodes, pIfObj, i, nLeaves )
|
|
{
|
|
if ( If_ObjIsCi(pIfObj) )
|
|
{
|
|
pIfObj->iCopy = 0;
|
|
fHole = 1;
|
|
continue;
|
|
}
|
|
iFanin0 = Abc_LitNotCond( If_ObjFanin0(pIfObj)->iCopy, If_ObjFaninC0(pIfObj) );
|
|
iFanin1 = Abc_LitNotCond( If_ObjFanin1(pIfObj)->iCopy, If_ObjFaninC1(pIfObj) );
|
|
pIfObj->iCopy = Gia_ManHashAnd( pGia, iFanin0, iFanin1 );
|
|
}
|
|
p->nHoleInTheWall += fHole;
|
|
p->timeBuild += Abc_Clock() - clk;
|
|
|
|
// check if this node is already driving a PO
|
|
assert( If_ObjIsAnd(pIfObj) );
|
|
pDriver = Gia_ManObj(pGia, Abc_Lit2Var(pIfObj->iCopy));
|
|
if ( pDriver->fMark1 )
|
|
{
|
|
p->nFilterSame++;
|
|
return 1;
|
|
}
|
|
pDriver->fMark1 = 1;
|
|
// create output
|
|
Gia_ManAppendCo( pGia, Abc_LitNotCond( pIfObj->iCopy, (uCanonPhase >> nLeaves) & 1 ) );
|
|
|
|
// verify truth table
|
|
clk = Abc_Clock();
|
|
pTruth = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1) );
|
|
p->timeCheck += Abc_Clock() - clk;
|
|
if ( memcmp( p->pTemp1, pTruth, p->nWords * sizeof(word) ) != 0 )
|
|
{
|
|
/*
|
|
Kit_DsdPrintFromTruth( pTruth, nLeaves ); printf( "\n" );
|
|
Kit_DsdPrintFromTruth( (unsigned *)p->pTemp1, nLeaves ); printf( "\n" );
|
|
printf( "Truth table verification has failed.\n" );
|
|
*/
|
|
// drive PO with constant
|
|
Gia_ManPatchCoDriver( pGia, Gia_ManCoNum(pGia)-1, 0 );
|
|
// save truth table ID
|
|
Vec_IntPush( p->vTruthIds, -1 );
|
|
p->nFilterTruth++;
|
|
return 1;
|
|
}
|
|
|
|
clk = Abc_Clock();
|
|
// add the resulting truth table to the hash table
|
|
Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 );
|
|
// save truth table ID
|
|
Vec_IntPush( p->vTruthIds, Index );
|
|
assert( Gia_ManCoNum(pGia) == Vec_IntSize(p->vTruthIds) );
|
|
p->nAdded++;
|
|
p->timeInsert += Abc_Clock() - clk;
|
|
return 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Top level procedure for library construction.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkRecAdd3( Abc_Ntk_t * pNtk, int fUseSOPB )
|
|
{
|
|
extern Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars );
|
|
If_Par_t Pars, * pPars = &Pars;
|
|
Abc_Ntk_t * pNtkNew;
|
|
int clk = Abc_Clock();
|
|
if ( Abc_NtkGetChoiceNum( pNtk ) )
|
|
printf( "Performing recoding structures with choices.\n" );
|
|
// remember that the manager was used for library construction
|
|
s_pMan3->fLibConstr = 1;
|
|
// create hash table if not available
|
|
if ( s_pMan3->pGia && s_pMan3->pGia->pHTable == NULL )
|
|
Gia_ManHashStart( s_pMan3->pGia );
|
|
|
|
// set defaults
|
|
memset( pPars, 0, sizeof(If_Par_t) );
|
|
// user-controlable paramters
|
|
pPars->nLutSize = s_pMan3->nVars;
|
|
pPars->nCutsMax = s_pMan3->nCuts;
|
|
pPars->DelayTarget = -1;
|
|
pPars->Epsilon = (float)0.005;
|
|
pPars->fArea = 1;
|
|
// internal parameters
|
|
if ( fUseSOPB )
|
|
{
|
|
pPars->fTruth = 1;
|
|
pPars->fCutMin = 0;
|
|
pPars->fUsePerm = 1;
|
|
pPars->fDelayOpt = 1;
|
|
}
|
|
else
|
|
{
|
|
pPars->fTruth = 1;
|
|
pPars->fCutMin = 1;
|
|
pPars->fUsePerm = 0;
|
|
pPars->fDelayOpt = 0;
|
|
}
|
|
pPars->fSkipCutFilter = 0;
|
|
pPars->pFuncCost = NULL;
|
|
pPars->pFuncUser = Abc_NtkRecAddCut3;
|
|
// perform recording
|
|
pNtkNew = Abc_NtkIf( pNtk, pPars );
|
|
Abc_NtkDelete( pNtkNew );
|
|
s_pMan3->timeTotal += Abc_Clock() - clk;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns min AIG level at the output fo the cut using the library.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline int If_CutComputeDelay( If_Man_t * p, If_Cut_t * pCut, char * pCanonPerm, word DelayProfile )
|
|
{
|
|
If_Obj_t* pLeaf;
|
|
int nLeaves = If_CutLeaveNum(pCut);
|
|
int i, delayTemp, delayMax = -ABC_INFINITY;
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
{
|
|
pLeaf = If_ManObj(p, (pCut)->pLeaves[(int)pCanonPerm[i]]);
|
|
delayTemp = If_ObjCutBest(pLeaf)->Delay + Lms_DelayGet(DelayProfile, i);
|
|
delayMax = Abc_MaxInt( delayMax, delayTemp );
|
|
}
|
|
return delayMax;
|
|
}
|
|
static inline int If_CutFindBestStruct( If_Man_t * pIfMan, If_Cut_t * pCut, char * pCanonPerm, unsigned * puCanonPhase, int * pBestPo )
|
|
{
|
|
Lms_Man_t * p = s_pMan3;
|
|
int i, * pTruthId, iFirstPo, iFirstPoNext, iBestPo;
|
|
int BestDelay = ABC_INFINITY, BestArea = ABC_INFINITY, Delay, Area;
|
|
int uSupport, nLeaves = If_CutLeaveNum( pCut );
|
|
char * pPerm = If_CutPerm( pCut );
|
|
word DelayProfile;
|
|
abctime clk;
|
|
pCut->fUser = 1;
|
|
// compute support
|
|
uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves );
|
|
if ( uSupport == 0 )
|
|
{
|
|
pCut->Cost = 1;
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
pPerm[i] = IF_BIG_CHAR;
|
|
return 0;
|
|
}
|
|
if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 )
|
|
{
|
|
assert( Abc_TtSuppOnlyOne(uSupport) );
|
|
pCut->Cost = 1;
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
pPerm[i] = IF_BIG_CHAR;
|
|
pPerm[Abc_TtSuppFindFirst(uSupport)] = 0;
|
|
return If_ObjCutBest(If_ManObj(pIfMan, pCut->pLeaves[Abc_TtSuppFindFirst(uSupport)]))->Delay;
|
|
}
|
|
assert( Gia_WordCountOnes(uSupport) == nLeaves );
|
|
|
|
// semicanonicize the function
|
|
clk = Abc_Clock();
|
|
memcpy( p->pTemp1, If_CutTruthW(pIfMan, pCut), p->nWords * sizeof(word) );
|
|
#ifdef LMS_USE_OLD_FORM
|
|
*puCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm );
|
|
#else
|
|
*puCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm );
|
|
#endif
|
|
Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars );
|
|
p->timeCanon += Abc_Clock() - clk;
|
|
|
|
// get TT ID for the given class
|
|
pTruthId = Vec_MemHashLookup( p->vTtMem, p->pTemp1 );
|
|
if ( *pTruthId == -1 )
|
|
{
|
|
pCut->Cost = IF_COST_MAX;
|
|
pCut->fUseless = 1;
|
|
return ABC_INFINITY;
|
|
}
|
|
|
|
// note that array p->vTruthPo contains the first PO for the given truth table
|
|
// other POs belonging to the same equivalence class follow immediately after this one
|
|
// to iterate through the POs, we need to perform the following steps
|
|
|
|
// find the first PO of this class
|
|
iFirstPo = Vec_IntEntry( p->vTruthPo, *pTruthId );
|
|
// find the first PO of the next class
|
|
iFirstPoNext = Vec_IntEntry( p->vTruthPo, *pTruthId+1 );
|
|
// iterate through the subgraphs of this class
|
|
iBestPo = -1;
|
|
for ( i = iFirstPo; i < iFirstPoNext; i++ )
|
|
{
|
|
Delay = If_CutComputeDelay( pIfMan, pCut, pCanonPerm, Vec_WrdEntry(p->vDelays, i) );
|
|
Area = Vec_StrEntry(p->vAreas, i);
|
|
if ( iBestPo == -1 || BestDelay > Delay || (BestDelay == Delay && BestArea > Area) )
|
|
{
|
|
iBestPo = i;
|
|
BestDelay = Delay;
|
|
BestArea = Area;
|
|
}
|
|
}
|
|
if ( pBestPo )
|
|
*pBestPo = iBestPo;
|
|
|
|
// mark as user cut.
|
|
DelayProfile = Vec_WrdEntry(p->vDelays, iBestPo);
|
|
pCut->Cost = Vec_StrEntry(p->vAreas, iBestPo);
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
pPerm[(int)pCanonPerm[i]] = Lms_DelayGet(DelayProfile, i);
|
|
if ( 0 )
|
|
{
|
|
int Max = 0, Two = 0, pTimes[16];
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
pTimes[i] = (int)If_ObjCutBest(If_CutLeaf(pIfMan, pCut, i))->Delay;
|
|
for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
|
|
Max = Abc_MaxInt( Max, pTimes[i] );
|
|
for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
|
|
if ( pTimes[i] != Max )
|
|
Two = Abc_MaxInt( Two, pTimes[i] );
|
|
if ( Two + 2 < Max && Max + 3 < BestDelay )
|
|
{
|
|
for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
|
|
printf( "%3d ", pTimes[i] );
|
|
for ( ; i < pIfMan->pPars->nLutSize; i++ )
|
|
printf( " " );
|
|
printf( "-> %3d ", BestDelay );
|
|
Dau_DsdPrintFromTruth( If_CutTruthW(pIfMan, pCut), If_CutLeaveNum(pCut) );
|
|
}
|
|
}
|
|
return BestDelay;
|
|
}
|
|
int If_CutDelayRecCost3( If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pObj )
|
|
{
|
|
Lms_Man_t * p = s_pMan3;
|
|
char pCanonPerm[LMS_VAR_MAX];
|
|
unsigned uCanonPhase = 0;
|
|
// make sure the cut functions match the library
|
|
assert( p->nVars == (int)pCut->nLimit );
|
|
// if this assertion fires, it means that LMS manager was used for library construction
|
|
// in this case, GIA has to be written out and the manager restarted as described above
|
|
assert( !p->fLibConstr );
|
|
if ( p->vTruthPo == NULL )
|
|
Lms_ManPrepare( p );
|
|
// return the delay of the best structure
|
|
return If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, NULL );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Reexpresses the best structure of the cut in the HOP manager.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Hop_Obj_t * Abc_RecToHop3( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj )
|
|
{
|
|
Lms_Man_t * p = s_pMan3;
|
|
char pCanonPerm[LMS_VAR_MAX];
|
|
unsigned uCanonPhase = 0;
|
|
Hop_Obj_t * pFan0, * pFan1, * pHopObj;
|
|
Gia_Man_t * pGia = p->pGia;
|
|
Gia_Obj_t * pGiaPo, * pGiaTemp = NULL;
|
|
int i, uSupport, BestPo = -1, nLeaves = If_CutLeaveNum(pCut);
|
|
assert( pIfMan->pPars->fCutMin == 1 );
|
|
|
|
// compute support
|
|
uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves );
|
|
if ( uSupport == 0 )
|
|
return Hop_NotCond( Hop_ManConst0(pMan), If_CutTruthIsCompl(pCut) );
|
|
if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 )
|
|
{
|
|
assert( Abc_TtSuppOnlyOne(uSupport) );
|
|
return Hop_NotCond( Hop_IthVar(pMan, Abc_TtSuppFindFirst(uSupport)), If_CutTruthIsCompl(pCut) );
|
|
}
|
|
assert( Gia_WordCountOnes(uSupport) == nLeaves );
|
|
|
|
// get the best output for this node
|
|
If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, &BestPo );
|
|
assert( BestPo >= 0 );
|
|
pGiaPo = Gia_ManCo( pGia, BestPo );
|
|
// collect internal nodes into pGia->vTtNodes
|
|
if ( pGia->vTtNodes == NULL )
|
|
pGia->vTtNodes = Vec_IntAlloc( 256 );
|
|
assert( Gia_ObjIsAnd( Gia_ObjFanin0(pGiaPo) ) );
|
|
Gia_ObjCollectInternal( pGia, Gia_ObjFanin0(pGiaPo) );
|
|
assert( Vec_IntSize(pGia->vTtNodes) > 0 );
|
|
|
|
// collect HOP nodes for leaves
|
|
Vec_PtrClear( p->vLabelsP );
|
|
for ( i = 0; i < nLeaves; i++ )
|
|
Vec_PtrPush( p->vLabelsP, Hop_NotCond(Hop_IthVar(pMan, pCanonPerm[i]), (uCanonPhase >> i) & 1) );
|
|
|
|
// compute HOP nodes for internal nodes
|
|
Gia_ManForEachObjVec( pGia->vTtNodes, pGia, pGiaTemp, i )
|
|
{
|
|
pGiaTemp->fMark0 = 0; // unmark node marked by Gia_ObjCollectInternal()
|
|
if ( Gia_ObjIsAnd(Gia_ObjFanin0(pGiaTemp)) )
|
|
pFan0 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, Gia_ObjFanin0(pGiaTemp)) + nLeaves);
|
|
else
|
|
pFan0 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjCioId(Gia_ObjFanin0(pGiaTemp)));
|
|
pFan0 = Hop_NotCond(pFan0, Gia_ObjFaninC0(pGiaTemp));
|
|
if ( Gia_ObjIsAnd(Gia_ObjFanin1(pGiaTemp)) )
|
|
pFan1 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, Gia_ObjFanin1(pGiaTemp)) + nLeaves);
|
|
else
|
|
pFan1 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjCioId(Gia_ObjFanin1(pGiaTemp)));
|
|
pFan1 = Hop_NotCond(pFan1, Gia_ObjFaninC1(pGiaTemp));
|
|
|
|
pHopObj = Hop_And(pMan, pFan0, pFan1);
|
|
Vec_PtrPush(p->vLabelsP, pHopObj);
|
|
}
|
|
// get the final result
|
|
assert( Gia_ObjIsAnd(pGiaTemp) );
|
|
pHopObj = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, pGiaTemp) + nLeaves);
|
|
// complement the result if needed
|
|
return Hop_NotCond( pHopObj, Gia_ObjFaninC0(pGiaPo) ^ ((uCanonPhase >> nLeaves) & 1) );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Reexpresses the best structure of the cut in the GIA manager.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_RecToGia3( Gia_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, Vec_Int_t * vLeaves, int fHash )
|
|
{
|
|
Lms_Man_t * p = s_pMan3;
|
|
char pCanonPerm[LMS_VAR_MAX];
|
|
unsigned uCanonPhase;
|
|
int iFan0, iFan1, iGiaObj;
|
|
Gia_Man_t * pGia = p->pGia;
|
|
Gia_Obj_t * pGiaPo, * pGiaTemp = NULL;
|
|
int i, uSupport, BestPo = -1, nLeaves = If_CutLeaveNum(pCut);
|
|
assert( pIfMan->pPars->fCutMin == 1 );
|
|
assert( nLeaves == Vec_IntSize(vLeaves) );
|
|
|
|
// compute support
|
|
uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves );
|
|
if ( uSupport == 0 )
|
|
return Abc_LitNotCond( 0, If_CutTruthIsCompl(pCut) );
|
|
if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 )
|
|
{
|
|
assert( Abc_TtSuppOnlyOne(uSupport) );
|
|
return Abc_LitNotCond( Vec_IntEntry(vLeaves, Abc_TtSuppFindFirst(uSupport)), If_CutTruthIsCompl(pCut) );
|
|
}
|
|
assert( Gia_WordCountOnes(uSupport) == nLeaves );
|
|
|
|
// get the best output for this node
|
|
If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, &BestPo );
|
|
assert( BestPo >= 0 );
|
|
pGiaPo = Gia_ManCo( pGia, BestPo );
|
|
|
|
// collect internal nodes into pGia->vTtNodes
|
|
if ( pGia->vTtNodes == NULL )
|
|
pGia->vTtNodes = Vec_IntAlloc( 256 );
|
|
assert( Gia_ObjIsAnd( Gia_ObjFanin0(pGiaPo) ) );
|
|
Gia_ObjCollectInternal( pGia, Gia_ObjFanin0(pGiaPo) );
|
|
assert( Vec_IntSize(pGia->vTtNodes) > 0 );
|
|
|
|
// collect GIA nodes for leaves
|
|
Vec_IntClear( p->vLabels );
|
|
for (i = 0; i < nLeaves; i++)
|
|
Vec_IntPush( p->vLabels, Abc_LitNotCond(Vec_IntEntry(vLeaves, pCanonPerm[i]), (uCanonPhase >> i) & 1) );
|
|
|
|
// compute HOP nodes for internal nodes
|
|
Gia_ManForEachObjVec( pGia->vTtNodes, pGia, pGiaTemp, i )
|
|
{
|
|
pGiaTemp->fMark0 = 0; // unmark node marked by Gia_ObjCollectInternal()
|
|
if ( Gia_ObjIsAnd(Gia_ObjFanin0(pGiaTemp)) )
|
|
iFan0 = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, Gia_ObjFanin0(pGiaTemp)) + nLeaves);
|
|
else
|
|
iFan0 = Vec_IntEntry(p->vLabels, Gia_ObjCioId(Gia_ObjFanin0(pGiaTemp)));
|
|
iFan0 = Abc_LitNotCond(iFan0, Gia_ObjFaninC0(pGiaTemp));
|
|
if ( Gia_ObjIsAnd(Gia_ObjFanin1(pGiaTemp)) )
|
|
iFan1 = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, Gia_ObjFanin1(pGiaTemp)) + nLeaves);
|
|
else
|
|
iFan1 = Vec_IntEntry(p->vLabels, Gia_ObjCioId(Gia_ObjFanin1(pGiaTemp)));
|
|
iFan1 = Abc_LitNotCond(iFan1, Gia_ObjFaninC1(pGiaTemp));
|
|
if ( fHash )
|
|
iGiaObj = Gia_ManHashAnd(pMan, iFan0, iFan1);
|
|
else
|
|
iGiaObj = Gia_ManAppendAnd(pMan, iFan0, iFan1);
|
|
Vec_IntPush(p->vLabels, iGiaObj);
|
|
}
|
|
// get the final result
|
|
assert( Gia_ObjIsAnd(pGiaTemp) );
|
|
iGiaObj = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, pGiaTemp) + nLeaves);
|
|
// complement the result if needed
|
|
return Abc_LitNotCond( iGiaObj, Gia_ObjFaninC0(pGiaPo) ^ ((uCanonPhase >> nLeaves) & 1) ^ pCut->fCompl );
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Reduces GIA to contain only useful COs and internal nodes.]
|
|
|
|
Description [During library construction, redundant nodes are added.
|
|
Some COs are found to be useless because their TT does not match the
|
|
(semi-canonicized TT) of the cut, etc. This procedure reduces GIA
|
|
to contains only useful (non-redundant, non-dominated) COs and the
|
|
corresponding internal nodes. This procedure replaces GIA by a new GIA
|
|
and creates new vTruthIds. The COs with the same truth table have
|
|
adjacent IDs. This procedure does not change the truth tables.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
// count how many times TT occurs
|
|
Vec_Int_t * Lms_GiaCountTruths( Lms_Man_t * p )
|
|
{
|
|
Vec_Int_t * vCounts = Vec_IntStart( Vec_MemEntryNum(p->vTtMem) );
|
|
int i, Entry;
|
|
Vec_IntForEachEntry( p->vTruthIds, Entry, i )
|
|
if ( Entry >= 0 )
|
|
Vec_IntAddToEntry( vCounts, Entry, 1 );
|
|
return vCounts;
|
|
}
|
|
// collect PO indexes worth visiting
|
|
Vec_Int_t * Lms_GiaCollectUsefulCos( Lms_Man_t * p )
|
|
{
|
|
Vec_Int_t * vBegins = Vec_IntAlloc( Vec_MemEntryNum(p->vTtMem) );
|
|
Vec_Int_t * vUseful = Vec_IntStartFull( Gia_ManCoNum(p->pGia) + Vec_MemEntryNum(p->vTtMem) );
|
|
Vec_Int_t * vCounts = Lms_GiaCountTruths( p );
|
|
int i, Entry, * pPlace, SumTotal = 0;
|
|
// mark up the place for POs
|
|
Vec_IntForEachEntry( vCounts, Entry, i )
|
|
{
|
|
assert( Entry > 0 );
|
|
Vec_IntPush( vBegins, SumTotal );
|
|
SumTotal += Entry + 1;
|
|
// printf( "%d ", Entry );
|
|
}
|
|
Vec_IntPush( vBegins, SumTotal );
|
|
// fill out POs in their places
|
|
Vec_IntFill( vCounts, Vec_IntSize(vCounts), 0 );
|
|
Vec_IntForEachEntry( p->vTruthIds, Entry, i )
|
|
{
|
|
if ( Entry < 0 )
|
|
continue;
|
|
pPlace = Vec_IntEntryP( vUseful, Vec_IntEntry(vBegins, Entry) + Vec_IntEntry(vCounts, Entry) );
|
|
assert( *pPlace == -1 );
|
|
*pPlace = i;
|
|
Vec_IntAddToEntry( vCounts, Entry, 1 );
|
|
}
|
|
Vec_IntFree( vBegins );
|
|
Vec_IntFree( vCounts );
|
|
return vUseful;
|
|
}
|
|
// collect non-dominated COs
|
|
Vec_Int_t * Lms_GiaFindNonRedundantCos( Lms_Man_t * p )
|
|
{
|
|
Vec_Int_t * vRemain;
|
|
Vec_Int_t * vUseful;
|
|
Vec_Wrd_t * vDelays;
|
|
int i, k, EntryI, EntryK;
|
|
word D1, D2;
|
|
vDelays = Lms_GiaDelays( p->pGia );
|
|
vUseful = Lms_GiaCollectUsefulCos( p );
|
|
Vec_IntForEachEntry( vUseful, EntryI, i )
|
|
{
|
|
if ( EntryI < 0 )
|
|
continue;
|
|
D1 = Vec_WrdEntry(vDelays, EntryI);
|
|
assert( D1 > 0 );
|
|
Vec_IntForEachEntryStart( vUseful, EntryK, k, i+1 )
|
|
{
|
|
if ( EntryK == -1 )
|
|
break;
|
|
if ( EntryK == -2 )
|
|
continue;
|
|
D2 = Vec_WrdEntry(vDelays, EntryK);
|
|
assert( D2 > 0 );
|
|
if ( Lms_DelayDom(D1, D2, Gia_ManCiNum(p->pGia)) ) // D1 dominate D2
|
|
{
|
|
Vec_IntWriteEntry( vUseful, k, -2 );
|
|
continue;
|
|
}
|
|
if ( Lms_DelayDom(D2, D1, Gia_ManCiNum(p->pGia)) ) // D2 dominate D1
|
|
{
|
|
Vec_IntWriteEntry( vUseful, i, -2 );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
vRemain = Vec_IntAlloc( 1000 );
|
|
Vec_IntForEachEntry( vUseful, EntryI, i )
|
|
if ( EntryI >= 0 )
|
|
Vec_IntPush( vRemain, EntryI );
|
|
Vec_IntFree( vUseful );
|
|
Vec_WrdFree( vDelays );
|
|
return vRemain;
|
|
}
|
|
// replace GIA and vTruthIds by filtered ones
|
|
void Lms_GiaNormalize( Lms_Man_t * p )
|
|
{
|
|
Gia_Man_t * pGiaNew;
|
|
Gia_Obj_t * pObj;
|
|
Vec_Int_t * vRemain;
|
|
Vec_Int_t * vTruthIdsNew;
|
|
int i, Entry, Prev = -1, Next;
|
|
// collect non-redundant COs
|
|
vRemain = Lms_GiaFindNonRedundantCos( p );
|
|
// change these to be useful literals
|
|
vTruthIdsNew = Vec_IntAlloc( Vec_IntSize(vRemain) );
|
|
Vec_IntForEachEntry( vRemain, Entry, i )
|
|
{
|
|
pObj = Gia_ManCo(p->pGia, Entry);
|
|
assert( Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) );
|
|
Vec_IntWriteEntry( vRemain, i, Gia_ObjFaninLit0p(p->pGia, pObj) );
|
|
// create new truth IDs
|
|
Next = Vec_IntEntry(p->vTruthIds, Gia_ObjCioId(pObj));
|
|
assert( Prev <= Next );
|
|
Vec_IntPush( vTruthIdsNew, Next );
|
|
Prev = Next;
|
|
}
|
|
// create a new GIA
|
|
Gia_ManForEachObj( p->pGia, pObj, i )
|
|
assert( pObj->fMark0 == 0 );
|
|
for ( i = 0; i < Gia_ManCoNum(p->pGia); i++ )
|
|
Gia_ManPatchCoDriver( p->pGia, i, 0 );
|
|
Vec_IntForEachEntry( vRemain, Entry, i )
|
|
Gia_ManAppendCo( p->pGia, Entry );
|
|
// pGiaNew = Gia_ManCleanup( p->pGia );
|
|
pGiaNew = Gia_ManCleanupOutputs( p->pGia, Gia_ManCoNum(p->pGia) - Vec_IntSize(vRemain) );
|
|
Gia_ManStop( p->pGia );
|
|
p->pGia = pGiaNew;
|
|
Vec_IntFree( vRemain );
|
|
// update truth IDs
|
|
Vec_IntFree( p->vTruthIds );
|
|
p->vTruthIds = vTruthIdsNew;
|
|
// Vec_IntPrint( vTruthIdsNew );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis []
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecTruthCompare( int * p1, int * p2 )
|
|
{
|
|
int Diff = Vec_StrEntry( s_pMan3->vSupps, *p1 ) - Vec_StrEntry( s_pMan3->vSupps, *p2 );
|
|
if ( Diff )
|
|
return Diff;
|
|
return memcmp( Vec_MemReadEntry(s_pMan3->vTtMem, *p1), Vec_MemReadEntry(s_pMan3->vTtMem, *p2), sizeof(word) * s_pMan3->nWords );
|
|
}
|
|
void Abc_NtkRecDumpTt3( char * pFileName, int fBinary )
|
|
{
|
|
FILE * pFile;
|
|
char pBuffer[1000];
|
|
Lms_Man_t * p = s_pMan3;
|
|
Vec_Int_t * vEntries;
|
|
word * pTruth;
|
|
int i, Entry, nVars = p->nVars;
|
|
int nEntries = Vec_MemEntryNum(p->vTtMem);
|
|
if ( nEntries == 0 )
|
|
{
|
|
printf( "There is not truth tables.\n" );
|
|
return;
|
|
}
|
|
pFile = fopen( pFileName, "wb" );
|
|
if ( pFile == NULL )
|
|
{
|
|
printf( "The file cannot be opened.\n" );
|
|
return;
|
|
}
|
|
p->vSupps = Vec_StrAlloc( nEntries );
|
|
Vec_MemForEachEntry( p->vTtMem, pTruth, i )
|
|
Vec_StrPush( p->vSupps, (char)Abc_TtSupportSize(pTruth, nVars) );
|
|
vEntries = Vec_IntStartNatural( nEntries );
|
|
qsort( (void *)Vec_IntArray(vEntries), nEntries, sizeof(int), (int(*)(const void *,const void *))Abc_NtkRecTruthCompare );
|
|
Vec_StrFreeP( &p->vSupps );
|
|
// write the file
|
|
Vec_IntForEachEntry( vEntries, Entry, i )
|
|
{
|
|
pTruth = Vec_MemReadEntry(p->vTtMem, Entry);
|
|
if ( fBinary )
|
|
{
|
|
fwrite( pTruth, 1, sizeof(word) * p->nWords, pFile );
|
|
continue;
|
|
}
|
|
Extra_PrintHex( pFile, (unsigned *)pTruth, nVars );
|
|
fprintf( pFile, " " );
|
|
// Kit_DsdWriteFromTruth( pBuffer, (unsigned *)pTruth, nVars );
|
|
Dau_DsdDecompose( pTruth, p->nVars, 0, (int)(nVars <= 10), pBuffer );
|
|
fprintf( pFile, "%s\n", pBuffer );
|
|
}
|
|
fclose( pFile );
|
|
Vec_IntFree( vEntries );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis []
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRecInputNum3()
|
|
{
|
|
return Gia_ManCiNum(s_pMan3->pGia);
|
|
}
|
|
int Abc_NtkRecIsRunning3()
|
|
{
|
|
return s_pMan3 != NULL;
|
|
}
|
|
Gia_Man_t * Abc_NtkRecGetGia3()
|
|
{
|
|
abctime clk = Abc_Clock();
|
|
printf( "Before normalizing: Library has %d classes and %d AIG subgraphs with %d AND nodes.\n",
|
|
Vec_MemEntryNum(s_pMan3->vTtMem), Gia_ManPoNum(s_pMan3->pGia), Gia_ManAndNum(s_pMan3->pGia) );
|
|
Lms_GiaNormalize( s_pMan3 );
|
|
printf( "After normalizing: Library has %d classes and %d AIG subgraphs with %d AND nodes.\n",
|
|
Vec_MemEntryNum(s_pMan3->vTtMem), Gia_ManPoNum(s_pMan3->pGia), Gia_ManAndNum(s_pMan3->pGia) );
|
|
Abc_PrintTime( 1, "Normalization runtime", Abc_Clock() - clk );
|
|
s_pMan3->fLibConstr = 0;
|
|
return s_pMan3->pGia;
|
|
}
|
|
void Abc_NtkRecPs3(int fPrintLib)
|
|
{
|
|
Lms_ManPrint( s_pMan3 );
|
|
}
|
|
void Abc_NtkRecStart3( Gia_Man_t * p, int nVars, int nCuts, int fFuncOnly, int fVerbose )
|
|
{
|
|
assert( s_pMan3 == NULL );
|
|
s_pMan3 = Lms_ManStart( p, nVars, nCuts, fFuncOnly, fVerbose );
|
|
}
|
|
|
|
void Abc_NtkRecStop3()
|
|
{
|
|
assert( s_pMan3 != NULL );
|
|
Lms_ManStop( s_pMan3 );
|
|
s_pMan3 = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|