mirror of https://github.com/YosysHQ/abc.git
1133 lines
37 KiB
C
1133 lines
37 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [abcOdc.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network and node package.]
|
|
|
|
Synopsis [Scalable computation of observability don't-cares.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: abcOdc.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "base/abc/abc.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#define ABC_DC_MAX_NODES (1<<15)
|
|
|
|
typedef unsigned short Odc_Lit_t;
|
|
|
|
typedef struct Odc_Obj_t_ Odc_Obj_t; // 16 bytes
|
|
struct Odc_Obj_t_
|
|
{
|
|
Odc_Lit_t iFan0; // first fanin
|
|
Odc_Lit_t iFan1; // second fanin
|
|
Odc_Lit_t iNext; // next node in the hash table
|
|
unsigned short TravId; // the traversal ID
|
|
unsigned uData; // the computed data
|
|
unsigned uMask; // the variable mask
|
|
};
|
|
|
|
struct Odc_Man_t_
|
|
{
|
|
// dont'-care parameters
|
|
int nVarsMax; // the max number of cut variables
|
|
int nLevels; // the number of ODC levels
|
|
int fVerbose; // the verbosiness flag
|
|
int fVeryVerbose;// the verbosiness flag to print per-node stats
|
|
int nPercCutoff; // cutoff percentage
|
|
|
|
// windowing
|
|
Abc_Obj_t * pNode; // the node for windowing
|
|
Vec_Ptr_t * vLeaves; // the number of the cut
|
|
Vec_Ptr_t * vRoots; // the roots of the cut
|
|
Vec_Ptr_t * vBranches; // additional inputs
|
|
|
|
// internal AIG package
|
|
// objects
|
|
int nPis; // number of PIs (nVarsMax + 32)
|
|
int nObjs; // number of objects (Const1, PIs, ANDs)
|
|
int nObjsAlloc; // number of objects allocated
|
|
Odc_Obj_t * pObjs; // objects
|
|
Odc_Lit_t iRoot; // the root object
|
|
unsigned short nTravIds; // the number of travIDs
|
|
// structural hashing
|
|
Odc_Lit_t * pTable; // hash table
|
|
int nTableSize; // hash table size
|
|
Vec_Int_t * vUsedSpots; // the used spots
|
|
|
|
// truth tables
|
|
int nBits; // the number of bits
|
|
int nWords; // the number of words
|
|
Vec_Ptr_t * vTruths; // truth tables for each node
|
|
Vec_Ptr_t * vTruthsElem; // elementary truth tables for the PIs
|
|
unsigned * puTruth; // the place where the resulting truth table does
|
|
|
|
// statistics
|
|
int nWins; // the number of windows processed
|
|
int nWinsEmpty; // the number of empty windows
|
|
int nSimsEmpty; // the number of empty simulation infos
|
|
int nQuantsOver; // the number of quantification overflows
|
|
int nWinsFinish; // the number of windows that finished
|
|
int nTotalDcs; // total percentage of DCs
|
|
|
|
// runtime
|
|
clock_t timeClean; // windowing
|
|
clock_t timeWin; // windowing
|
|
clock_t timeMiter; // computing the miter
|
|
clock_t timeSim; // simulation
|
|
clock_t timeQuant; // quantification
|
|
clock_t timeTruth; // truth table
|
|
clock_t timeTotal; // useful runtime
|
|
clock_t timeAbort; // aborted runtime
|
|
};
|
|
|
|
|
|
// quantity of different objects
|
|
static inline int Odc_PiNum( Odc_Man_t * p ) { return p->nPis; }
|
|
static inline int Odc_NodeNum( Odc_Man_t * p ) { return p->nObjs - p->nPis - 1; }
|
|
static inline int Odc_ObjNum( Odc_Man_t * p ) { return p->nObjs; }
|
|
|
|
// complemented attributes of objects
|
|
static inline int Odc_IsComplement( Odc_Lit_t Lit ) { return Lit & (Odc_Lit_t)1; }
|
|
static inline Odc_Lit_t Odc_Regular( Odc_Lit_t Lit ) { return Lit & ~(Odc_Lit_t)1; }
|
|
static inline Odc_Lit_t Odc_Not( Odc_Lit_t Lit ) { return Lit ^ (Odc_Lit_t)1; }
|
|
static inline Odc_Lit_t Odc_NotCond( Odc_Lit_t Lit, int c ) { return Lit ^ (Odc_Lit_t)(c!=0); }
|
|
|
|
// specialized Literals
|
|
static inline Odc_Lit_t Odc_Const0() { return 1; }
|
|
static inline Odc_Lit_t Odc_Const1() { return 0; }
|
|
static inline Odc_Lit_t Odc_Var( Odc_Man_t * p, int i ) { assert( i >= 0 && i < p->nPis ); return (i+1) << 1; }
|
|
static inline int Odc_IsConst( Odc_Lit_t Lit ) { return Lit < (Odc_Lit_t)2; }
|
|
static inline int Odc_IsTerm( Odc_Man_t * p, Odc_Lit_t Lit ) { return (int)(Lit>>1) <= p->nPis; }
|
|
|
|
// accessing internal storage
|
|
static inline Odc_Obj_t * Odc_ObjNew( Odc_Man_t * p ) { assert( p->nObjs < p->nObjsAlloc ); return p->pObjs + p->nObjs++; }
|
|
static inline Odc_Lit_t Odc_Obj2Lit( Odc_Man_t * p, Odc_Obj_t * pObj ) { assert( pObj ); return (pObj - p->pObjs) << 1; }
|
|
static inline Odc_Obj_t * Odc_Lit2Obj( Odc_Man_t * p, Odc_Lit_t Lit ) { assert( !(Lit & 1) && (int)(Lit>>1) < p->nObjs ); return p->pObjs + (Lit>>1); }
|
|
|
|
// fanins and their complements
|
|
static inline Odc_Lit_t Odc_ObjChild0( Odc_Obj_t * pObj ) { return pObj->iFan0; }
|
|
static inline Odc_Lit_t Odc_ObjChild1( Odc_Obj_t * pObj ) { return pObj->iFan1; }
|
|
static inline Odc_Lit_t Odc_ObjFanin0( Odc_Obj_t * pObj ) { return Odc_Regular(pObj->iFan0); }
|
|
static inline Odc_Lit_t Odc_ObjFanin1( Odc_Obj_t * pObj ) { return Odc_Regular(pObj->iFan1); }
|
|
static inline int Odc_ObjFaninC0( Odc_Obj_t * pObj ) { return Odc_IsComplement(pObj->iFan0); }
|
|
static inline int Odc_ObjFaninC1( Odc_Obj_t * pObj ) { return Odc_IsComplement(pObj->iFan1); }
|
|
|
|
// traversal IDs
|
|
static inline void Odc_ManIncrementTravId( Odc_Man_t * p ) { p->nTravIds++; }
|
|
static inline void Odc_ObjSetTravIdCurrent( Odc_Man_t * p, Odc_Obj_t * pObj ) { pObj->TravId = p->nTravIds; }
|
|
static inline int Odc_ObjIsTravIdCurrent( Odc_Man_t * p, Odc_Obj_t * pObj ) { return (int )((int)pObj->TravId == p->nTravIds); }
|
|
|
|
// truth tables
|
|
static inline unsigned * Odc_ObjTruth( Odc_Man_t * p, Odc_Lit_t Lit ) { assert( !(Lit & 1) ); return (unsigned *) Vec_PtrEntry(p->vTruths, Lit >> 1); }
|
|
|
|
// iterators
|
|
#define Odc_ForEachPi( p, Lit, i ) \
|
|
for ( i = 0; (i < Odc_PiNum(p)) && (((Lit) = Odc_Var(p, i)), 1); i++ )
|
|
#define Odc_ForEachAnd( p, pObj, i ) \
|
|
for ( i = 1 + Odc_CiNum(p); (i < Odc_ObjNum(p)) && ((pObj) = (p)->pObjs + i); i++ )
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Allocates the don't-care manager.]
|
|
|
|
Description [The parameters are the max number of cut variables,
|
|
the number of fanout levels used for the ODC computation, and verbosiness.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Odc_Man_t * Abc_NtkDontCareAlloc( int nVarsMax, int nLevels, int fVerbose, int fVeryVerbose )
|
|
{
|
|
Odc_Man_t * p;
|
|
unsigned * pData;
|
|
int i, k;
|
|
p = ABC_ALLOC( Odc_Man_t, 1 );
|
|
memset( p, 0, sizeof(Odc_Man_t) );
|
|
assert( nVarsMax > 4 && nVarsMax < 16 );
|
|
assert( nLevels > 0 && nLevels < 10 );
|
|
|
|
srand( 0xABC );
|
|
|
|
// dont'-care parameters
|
|
p->nVarsMax = nVarsMax;
|
|
p->nLevels = nLevels;
|
|
p->fVerbose = fVerbose;
|
|
p->fVeryVerbose = fVeryVerbose;
|
|
p->nPercCutoff = 10;
|
|
|
|
// windowing
|
|
p->vRoots = Vec_PtrAlloc( 128 );
|
|
p->vBranches = Vec_PtrAlloc( 128 );
|
|
|
|
// internal AIG package
|
|
// allocate room for objects
|
|
p->nObjsAlloc = ABC_DC_MAX_NODES;
|
|
p->pObjs = ABC_ALLOC( Odc_Obj_t, p->nObjsAlloc * sizeof(Odc_Obj_t) );
|
|
p->nPis = nVarsMax + 32;
|
|
p->nObjs = 1 + p->nPis;
|
|
memset( p->pObjs, 0, p->nObjs * sizeof(Odc_Obj_t) );
|
|
// set the PI masks
|
|
for ( i = 0; i < 32; i++ )
|
|
p->pObjs[1 + p->nVarsMax + i].uMask = (1 << i);
|
|
// allocate hash table
|
|
p->nTableSize = p->nObjsAlloc/3 + 1;
|
|
p->pTable = ABC_ALLOC( Odc_Lit_t, p->nTableSize * sizeof(Odc_Lit_t) );
|
|
memset( p->pTable, 0, p->nTableSize * sizeof(Odc_Lit_t) );
|
|
p->vUsedSpots = Vec_IntAlloc( 1000 );
|
|
|
|
// truth tables
|
|
p->nWords = Abc_TruthWordNum( p->nVarsMax );
|
|
p->nBits = p->nWords * 8 * sizeof(unsigned);
|
|
p->vTruths = Vec_PtrAllocSimInfo( p->nObjsAlloc, p->nWords );
|
|
p->vTruthsElem = Vec_PtrAllocSimInfo( p->nVarsMax, p->nWords );
|
|
|
|
// set elementary truth tables
|
|
Abc_InfoFill( (unsigned *)Vec_PtrEntry(p->vTruths, 0), p->nWords );
|
|
for ( k = 0; k < p->nVarsMax; k++ )
|
|
{
|
|
// pData = Odc_ObjTruth( p, Odc_Var(p, k) );
|
|
pData = (unsigned *)Vec_PtrEntry( p->vTruthsElem, k );
|
|
Abc_InfoClear( pData, p->nWords );
|
|
for ( i = 0; i < p->nBits; i++ )
|
|
if ( i & (1 << k) )
|
|
pData[i>>5] |= (1 << (i&31));
|
|
}
|
|
|
|
// set random truth table for the additional inputs
|
|
for ( k = p->nVarsMax; k < p->nPis; k++ )
|
|
{
|
|
pData = Odc_ObjTruth( p, Odc_Var(p, k) );
|
|
Abc_InfoRandom( pData, p->nWords );
|
|
}
|
|
|
|
// set the miter to the unused value
|
|
p->iRoot = 0xffff;
|
|
return p;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Clears the manager.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareClear( Odc_Man_t * p )
|
|
{
|
|
clock_t clk = clock();
|
|
// clean the structural hashing table
|
|
if ( Vec_IntSize(p->vUsedSpots) > p->nTableSize/3 ) // more than one third
|
|
memset( p->pTable, 0, sizeof(Odc_Lit_t) * p->nTableSize );
|
|
else
|
|
{
|
|
int iSpot, i;
|
|
Vec_IntForEachEntry( p->vUsedSpots, iSpot, i )
|
|
p->pTable[iSpot] = 0;
|
|
}
|
|
Vec_IntClear( p->vUsedSpots );
|
|
// reset the number of nodes
|
|
p->nObjs = 1 + p->nPis;
|
|
// reset the root node
|
|
p->iRoot = 0xffff;
|
|
|
|
p->timeClean += clock() - clk;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Frees the don't-care manager.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareFree( Odc_Man_t * p )
|
|
{
|
|
if ( p->fVerbose )
|
|
{
|
|
printf( "Wins = %5d. Empty = %5d. SimsEmpty = %5d. QuantOver = %5d. WinsFinish = %5d.\n",
|
|
p->nWins, p->nWinsEmpty, p->nSimsEmpty, p->nQuantsOver, p->nWinsFinish );
|
|
printf( "Ave DCs per window = %6.2f %%. Ave DCs per finished window = %6.2f %%.\n",
|
|
1.0*p->nTotalDcs/p->nWins, 1.0*p->nTotalDcs/p->nWinsFinish );
|
|
printf( "Runtime stats of the ODC manager:\n" );
|
|
ABC_PRT( "Cleaning ", p->timeClean );
|
|
ABC_PRT( "Windowing ", p->timeWin );
|
|
ABC_PRT( "Miter ", p->timeMiter );
|
|
ABC_PRT( "Simulation ", p->timeSim );
|
|
ABC_PRT( "Quantifying ", p->timeQuant );
|
|
ABC_PRT( "Truth table ", p->timeTruth );
|
|
ABC_PRT( "TOTAL ", p->timeTotal );
|
|
ABC_PRT( "Aborted ", p->timeAbort );
|
|
}
|
|
Vec_PtrFree( p->vRoots );
|
|
Vec_PtrFree( p->vBranches );
|
|
Vec_PtrFree( p->vTruths );
|
|
Vec_PtrFree( p->vTruthsElem );
|
|
Vec_IntFree( p->vUsedSpots );
|
|
ABC_FREE( p->pObjs );
|
|
ABC_FREE( p->pTable );
|
|
ABC_FREE( p );
|
|
}
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Marks the TFO of the collected nodes up to the given level.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareWinSweepLeafTfo_rec( Abc_Obj_t * pObj, int nLevelLimit, Abc_Obj_t * pNode )
|
|
{
|
|
Abc_Obj_t * pFanout;
|
|
int i;
|
|
if ( Abc_ObjIsCo(pObj) || (int)pObj->Level > nLevelLimit || pObj == pNode )
|
|
return;
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return;
|
|
Abc_NodeSetTravIdCurrent( pObj );
|
|
////////////////////////////////////////
|
|
// try to reduce the runtime
|
|
if ( Abc_ObjFanoutNum(pObj) > 100 )
|
|
return;
|
|
////////////////////////////////////////
|
|
Abc_ObjForEachFanout( pObj, pFanout, i )
|
|
Abc_NtkDontCareWinSweepLeafTfo_rec( pFanout, nLevelLimit, pNode );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Marks the TFO of the collected nodes up to the given level.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareWinSweepLeafTfo( Odc_Man_t * p )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
Abc_NtkIncrementTravId( p->pNode->pNtk );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pObj, i )
|
|
Abc_NtkDontCareWinSweepLeafTfo_rec( pObj, p->pNode->Level + p->nLevels, p->pNode );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Recursively collects the roots.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareWinCollectRoots_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vRoots )
|
|
{
|
|
Abc_Obj_t * pFanout;
|
|
int i;
|
|
assert( Abc_ObjIsNode(pObj) );
|
|
assert( Abc_NodeIsTravIdCurrent(pObj) );
|
|
// check if the node has all fanouts marked
|
|
Abc_ObjForEachFanout( pObj, pFanout, i )
|
|
if ( !Abc_NodeIsTravIdCurrent(pFanout) )
|
|
break;
|
|
// if some of the fanouts are unmarked, add the node to the root
|
|
if ( i < Abc_ObjFanoutNum(pObj) )
|
|
{
|
|
Vec_PtrPushUnique( vRoots, pObj );
|
|
return;
|
|
}
|
|
// otherwise, call recursively
|
|
Abc_ObjForEachFanout( pObj, pFanout, i )
|
|
Abc_NtkDontCareWinCollectRoots_rec( pFanout, vRoots );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Collects the roots of the window.]
|
|
|
|
Description [Roots of the window are the nodes that have at least
|
|
one fanout that it not in the TFO of the leaves.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareWinCollectRoots( Odc_Man_t * p )
|
|
{
|
|
assert( !Abc_NodeIsTravIdCurrent(p->pNode) );
|
|
// mark the node with the old traversal ID
|
|
Abc_NodeSetTravIdCurrent( p->pNode );
|
|
// collect the roots
|
|
Vec_PtrClear( p->vRoots );
|
|
Abc_NtkDontCareWinCollectRoots_rec( p->pNode, p->vRoots );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Recursively adds missing nodes and leaves.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareWinAddMissing_rec( Odc_Man_t * p, Abc_Obj_t * pObj )
|
|
{
|
|
Abc_Obj_t * pFanin;
|
|
int i;
|
|
// skip the already collected leaves and branches
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return 1;
|
|
// if this is not an internal node - make it a new branch
|
|
if ( !Abc_NodeIsTravIdPrevious(pObj) || Abc_ObjIsCi(pObj) ) //|| (int)pObj->Level <= p->nLevLeaves )
|
|
{
|
|
Abc_NodeSetTravIdCurrent( pObj );
|
|
Vec_PtrPush( p->vBranches, pObj );
|
|
return Vec_PtrSize(p->vBranches) <= 32;
|
|
}
|
|
// visit the fanins of the node
|
|
Abc_ObjForEachFanin( pObj, pFanin, i )
|
|
if ( !Abc_NtkDontCareWinAddMissing_rec( p, pFanin ) )
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Adds to the window nodes and leaves in the TFI of the roots.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareWinAddMissing( Odc_Man_t * p )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
// set the leaves
|
|
Abc_NtkIncrementTravId( p->pNode->pNtk );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pObj, i )
|
|
Abc_NodeSetTravIdCurrent( pObj );
|
|
// explore from the roots
|
|
Vec_PtrClear( p->vBranches );
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, p->vRoots, pObj, i )
|
|
if ( !Abc_NtkDontCareWinAddMissing_rec( p, pObj ) )
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes window for the node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareWindow( Odc_Man_t * p )
|
|
{
|
|
// mark the TFO of the collected nodes up to the given level (p->pNode->Level + p->nWinTfoMax)
|
|
Abc_NtkDontCareWinSweepLeafTfo( p );
|
|
// find the roots of the window
|
|
Abc_NtkDontCareWinCollectRoots( p );
|
|
if ( Vec_PtrSize(p->vRoots) == 1 && Vec_PtrEntry(p->vRoots, 0) == p->pNode )
|
|
{
|
|
// printf( "Empty window\n" );
|
|
return 0;
|
|
}
|
|
// add the nodes in the TFI of the roots that are not yet in the window
|
|
if ( !Abc_NtkDontCareWinAddMissing( p ) )
|
|
{
|
|
// printf( "Too many branches (%d)\n", Vec_PtrSize(p->vBranches) );
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performing hashing of two AIG Literals.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline unsigned Odc_HashKey( Odc_Lit_t iFan0, Odc_Lit_t iFan1, int TableSize )
|
|
{
|
|
unsigned Key = 0;
|
|
Key ^= Odc_Regular(iFan0) * 7937;
|
|
Key ^= Odc_Regular(iFan1) * 2971;
|
|
Key ^= Odc_IsComplement(iFan0) * 911;
|
|
Key ^= Odc_IsComplement(iFan1) * 353;
|
|
return Key % TableSize;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Checks if the given name node already exists in the table.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline Odc_Lit_t * Odc_HashLookup( Odc_Man_t * p, Odc_Lit_t iFan0, Odc_Lit_t iFan1 )
|
|
{
|
|
Odc_Obj_t * pObj;
|
|
Odc_Lit_t * pEntry;
|
|
unsigned uHashKey;
|
|
assert( iFan0 < iFan1 );
|
|
// get the hash key for this node
|
|
uHashKey = Odc_HashKey( iFan0, iFan1, p->nTableSize );
|
|
// remember the spot in the hash table that will be used
|
|
if ( p->pTable[uHashKey] == 0 )
|
|
Vec_IntPush( p->vUsedSpots, uHashKey );
|
|
// find the entry
|
|
for ( pEntry = p->pTable + uHashKey; *pEntry; pEntry = &pObj->iNext )
|
|
{
|
|
pObj = Odc_Lit2Obj( p, *pEntry );
|
|
if ( pObj->iFan0 == iFan0 && pObj->iFan1 == iFan1 )
|
|
return pEntry;
|
|
}
|
|
return pEntry;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Finds node by structural hashing or creates a new node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline Odc_Lit_t Odc_And( Odc_Man_t * p, Odc_Lit_t iFan0, Odc_Lit_t iFan1 )
|
|
{
|
|
Odc_Obj_t * pObj;
|
|
Odc_Lit_t * pEntry;
|
|
unsigned uMask0, uMask1;
|
|
int Temp;
|
|
// consider trivial cases
|
|
if ( iFan0 == iFan1 )
|
|
return iFan0;
|
|
if ( iFan0 == Odc_Not(iFan1) )
|
|
return Odc_Const0();
|
|
if ( Odc_Regular(iFan0) == Odc_Const1() )
|
|
return iFan0 == Odc_Const1() ? iFan1 : Odc_Const0();
|
|
if ( Odc_Regular(iFan1) == Odc_Const1() )
|
|
return iFan1 == Odc_Const1() ? iFan0 : Odc_Const0();
|
|
// canonicize the fanin order
|
|
if ( iFan0 > iFan1 )
|
|
Temp = iFan0, iFan0 = iFan1, iFan1 = Temp;
|
|
// check if a node with these fanins exists
|
|
pEntry = Odc_HashLookup( p, iFan0, iFan1 );
|
|
if ( *pEntry )
|
|
return *pEntry;
|
|
// create a new node
|
|
pObj = Odc_ObjNew( p );
|
|
pObj->iFan0 = iFan0;
|
|
pObj->iFan1 = iFan1;
|
|
pObj->iNext = 0;
|
|
pObj->TravId = 0;
|
|
// set the mask
|
|
uMask0 = Odc_Lit2Obj(p, Odc_Regular(iFan0))->uMask;
|
|
uMask1 = Odc_Lit2Obj(p, Odc_Regular(iFan1))->uMask;
|
|
pObj->uMask = uMask0 | uMask1;
|
|
// add to the table
|
|
*pEntry = Odc_Obj2Lit( p, pObj );
|
|
return *pEntry;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Boolean OR.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline Odc_Lit_t Odc_Or( Odc_Man_t * p, Odc_Lit_t iFan0, Odc_Lit_t iFan1 )
|
|
{
|
|
return Odc_Not( Odc_And(p, Odc_Not(iFan0), Odc_Not(iFan1)) );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Boolean XOR.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static inline Odc_Lit_t Odc_Xor( Odc_Man_t * p, Odc_Lit_t iFan0, Odc_Lit_t iFan1 )
|
|
{
|
|
return Odc_Or( p, Odc_And(p, iFan0, Odc_Not(iFan1)), Odc_And(p, Odc_Not(iFan0), iFan1) );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Transfers the window into the AIG package.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void * Abc_NtkDontCareTransfer_rec( Odc_Man_t * p, Abc_Obj_t * pNode, Abc_Obj_t * pPivot )
|
|
{
|
|
unsigned uData0, uData1;
|
|
Odc_Lit_t uLit0, uLit1, uRes0, uRes1;
|
|
assert( !Abc_ObjIsComplement(pNode) );
|
|
// skip visited objects
|
|
if ( Abc_NodeIsTravIdCurrent(pNode) )
|
|
return pNode->pCopy;
|
|
Abc_NodeSetTravIdCurrent(pNode);
|
|
assert( Abc_ObjIsNode(pNode) );
|
|
// consider the case when the node is the pivot
|
|
if ( pNode == pPivot )
|
|
return pNode->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)((Odc_Const1() << 16) | Odc_Const0());
|
|
// compute the cofactors
|
|
uData0 = (unsigned)(ABC_PTRUINT_T)Abc_NtkDontCareTransfer_rec( p, Abc_ObjFanin0(pNode), pPivot );
|
|
uData1 = (unsigned)(ABC_PTRUINT_T)Abc_NtkDontCareTransfer_rec( p, Abc_ObjFanin1(pNode), pPivot );
|
|
// find the 0-cofactor
|
|
uLit0 = Odc_NotCond( (Odc_Lit_t)(uData0 & 0xffff), Abc_ObjFaninC0(pNode) );
|
|
uLit1 = Odc_NotCond( (Odc_Lit_t)(uData1 & 0xffff), Abc_ObjFaninC1(pNode) );
|
|
uRes0 = Odc_And( p, uLit0, uLit1 );
|
|
// find the 1-cofactor
|
|
uLit0 = Odc_NotCond( (Odc_Lit_t)(uData0 >> 16), Abc_ObjFaninC0(pNode) );
|
|
uLit1 = Odc_NotCond( (Odc_Lit_t)(uData1 >> 16), Abc_ObjFaninC1(pNode) );
|
|
uRes1 = Odc_And( p, uLit0, uLit1 );
|
|
// find the result
|
|
return pNode->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)((uRes1 << 16) | uRes0);
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Transfers the window into the AIG package.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareTransfer( Odc_Man_t * p )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
Odc_Lit_t uRes0, uRes1;
|
|
Odc_Lit_t uLit;
|
|
unsigned uData;
|
|
int i;
|
|
Abc_NtkIncrementTravId( p->pNode->pNtk );
|
|
// set elementary variables at the leaves
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pObj, i )
|
|
{
|
|
uLit = Odc_Var( p, i );
|
|
pObj->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)((uLit << 16) | uLit);
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
}
|
|
// set elementary variables at the branched
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, p->vBranches, pObj, i )
|
|
{
|
|
uLit = Odc_Var( p, i+p->nVarsMax );
|
|
pObj->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)((uLit << 16) | uLit);
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
}
|
|
// compute the AIG for the window
|
|
p->iRoot = Odc_Const0();
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, p->vRoots, pObj, i )
|
|
{
|
|
uData = (unsigned)(ABC_PTRUINT_T)Abc_NtkDontCareTransfer_rec( p, pObj, p->pNode );
|
|
// get the cofactors
|
|
uRes0 = uData & 0xffff;
|
|
uRes1 = uData >> 16;
|
|
// compute the miter
|
|
// assert( uRes0 != uRes1 ); // may be false if the node is redundant w.r.t. this root
|
|
uLit = Odc_Xor( p, uRes0, uRes1 );
|
|
p->iRoot = Odc_Or( p, p->iRoot, uLit );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Recursively computes the pair of cofactors.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
unsigned Abc_NtkDontCareCofactors_rec( Odc_Man_t * p, Odc_Lit_t Lit, unsigned uMask )
|
|
{
|
|
Odc_Obj_t * pObj;
|
|
unsigned uData0, uData1;
|
|
Odc_Lit_t uLit0, uLit1, uRes0, uRes1;
|
|
assert( !Odc_IsComplement(Lit) );
|
|
// skip visited objects
|
|
pObj = Odc_Lit2Obj( p, Lit );
|
|
if ( Odc_ObjIsTravIdCurrent(p, pObj) )
|
|
return pObj->uData;
|
|
Odc_ObjSetTravIdCurrent(p, pObj);
|
|
// skip objects out of the cone
|
|
if ( (pObj->uMask & uMask) == 0 )
|
|
return pObj->uData = ((Lit << 16) | Lit);
|
|
// consider the case when the node is the var
|
|
if ( pObj->uMask == uMask && Odc_IsTerm(p, Lit) )
|
|
return pObj->uData = ((Odc_Const1() << 16) | Odc_Const0());
|
|
// compute the cofactors
|
|
uData0 = Abc_NtkDontCareCofactors_rec( p, Odc_ObjFanin0(pObj), uMask );
|
|
uData1 = Abc_NtkDontCareCofactors_rec( p, Odc_ObjFanin1(pObj), uMask );
|
|
// find the 0-cofactor
|
|
uLit0 = Odc_NotCond( (Odc_Lit_t)(uData0 & 0xffff), Odc_ObjFaninC0(pObj) );
|
|
uLit1 = Odc_NotCond( (Odc_Lit_t)(uData1 & 0xffff), Odc_ObjFaninC1(pObj) );
|
|
uRes0 = Odc_And( p, uLit0, uLit1 );
|
|
// find the 1-cofactor
|
|
uLit0 = Odc_NotCond( (Odc_Lit_t)(uData0 >> 16), Odc_ObjFaninC0(pObj) );
|
|
uLit1 = Odc_NotCond( (Odc_Lit_t)(uData1 >> 16), Odc_ObjFaninC1(pObj) );
|
|
uRes1 = Odc_And( p, uLit0, uLit1 );
|
|
// find the result
|
|
return pObj->uData = ((uRes1 << 16) | uRes0);
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Quantifies the branch variables.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareQuantify( Odc_Man_t * p )
|
|
{
|
|
Odc_Lit_t uRes0, uRes1;
|
|
unsigned uData;
|
|
int i;
|
|
assert( p->iRoot < 0xffff );
|
|
assert( Vec_PtrSize(p->vBranches) <= 32 ); // the mask size
|
|
for ( i = 0; i < Vec_PtrSize(p->vBranches); i++ )
|
|
{
|
|
// compute the cofactors w.r.t. this variable
|
|
Odc_ManIncrementTravId( p );
|
|
uData = Abc_NtkDontCareCofactors_rec( p, Odc_Regular(p->iRoot), (1 << i) );
|
|
uRes0 = Odc_NotCond( (Odc_Lit_t)(uData & 0xffff), Odc_IsComplement(p->iRoot) );
|
|
uRes1 = Odc_NotCond( (Odc_Lit_t)(uData >> 16), Odc_IsComplement(p->iRoot) );
|
|
// quantify this variable existentially
|
|
p->iRoot = Odc_Or( p, uRes0, uRes1 );
|
|
// check the limit
|
|
if ( Odc_ObjNum(p) > ABC_DC_MAX_NODES/2 )
|
|
return 0;
|
|
}
|
|
assert( p->nObjs <= p->nObjsAlloc );
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Set elementary truth tables for PIs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareSimulateSetElem2( Odc_Man_t * p )
|
|
{
|
|
unsigned * pData;
|
|
int i, k;
|
|
for ( k = 0; k < p->nVarsMax; k++ )
|
|
{
|
|
pData = Odc_ObjTruth( p, Odc_Var(p, k) );
|
|
Abc_InfoClear( pData, p->nWords );
|
|
for ( i = 0; i < p->nBits; i++ )
|
|
if ( i & (1 << k) )
|
|
pData[i>>5] |= (1 << (i&31));
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Set elementary truth tables for PIs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareSimulateSetElem( Odc_Man_t * p )
|
|
{
|
|
unsigned * pData, * pData2;
|
|
int k;
|
|
for ( k = 0; k < p->nVarsMax; k++ )
|
|
{
|
|
pData = Odc_ObjTruth( p, Odc_Var(p, k) );
|
|
pData2 = (unsigned *)Vec_PtrEntry( p->vTruthsElem, k );
|
|
Abc_InfoCopy( pData, pData2, p->nWords );
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Set random simulation words for PIs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareSimulateSetRand( Odc_Man_t * p )
|
|
{
|
|
unsigned * pData;
|
|
int w, k, Number;
|
|
for ( w = 0; w < p->nWords; w++ )
|
|
{
|
|
Number = rand();
|
|
for ( k = 0; k < p->nVarsMax; k++ )
|
|
{
|
|
pData = Odc_ObjTruth( p, Odc_Var(p, k) );
|
|
pData[w] = (Number & (1<<k)) ? ~0 : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Set random simulation words for PIs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareCountMintsWord( Odc_Man_t * p, unsigned * puTruth )
|
|
{
|
|
int w, Counter = 0;
|
|
for ( w = 0; w < p->nWords; w++ )
|
|
if ( puTruth[w] )
|
|
Counter++;
|
|
return Counter;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Simulates one node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareTruthOne( Odc_Man_t * p, Odc_Lit_t Lit )
|
|
{
|
|
Odc_Obj_t * pObj;
|
|
unsigned * pInfo, * pInfo1, * pInfo2;
|
|
int k, fComp1, fComp2;
|
|
assert( !Odc_IsComplement( Lit ) );
|
|
assert( !Odc_IsTerm( p, Lit ) );
|
|
// get the truth tables
|
|
pObj = Odc_Lit2Obj( p, Lit );
|
|
pInfo = Odc_ObjTruth( p, Lit );
|
|
pInfo1 = Odc_ObjTruth( p, Odc_ObjFanin0(pObj) );
|
|
pInfo2 = Odc_ObjTruth( p, Odc_ObjFanin1(pObj) );
|
|
fComp1 = Odc_ObjFaninC0( pObj );
|
|
fComp2 = Odc_ObjFaninC1( pObj );
|
|
// simulate
|
|
if ( fComp1 && fComp2 )
|
|
for ( k = 0; k < p->nWords; k++ )
|
|
pInfo[k] = ~pInfo1[k] & ~pInfo2[k];
|
|
else if ( fComp1 && !fComp2 )
|
|
for ( k = 0; k < p->nWords; k++ )
|
|
pInfo[k] = ~pInfo1[k] & pInfo2[k];
|
|
else if ( !fComp1 && fComp2 )
|
|
for ( k = 0; k < p->nWords; k++ )
|
|
pInfo[k] = pInfo1[k] & ~pInfo2[k];
|
|
else // if ( fComp1 && fComp2 )
|
|
for ( k = 0; k < p->nWords; k++ )
|
|
pInfo[k] = pInfo1[k] & pInfo2[k];
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the truth table.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_NtkDontCareSimulate_rec( Odc_Man_t * p, Odc_Lit_t Lit )
|
|
{
|
|
Odc_Obj_t * pObj;
|
|
assert( !Odc_IsComplement(Lit) );
|
|
// skip terminals
|
|
if ( Odc_IsTerm(p, Lit) )
|
|
return;
|
|
// skip visited objects
|
|
pObj = Odc_Lit2Obj( p, Lit );
|
|
if ( Odc_ObjIsTravIdCurrent(p, pObj) )
|
|
return;
|
|
Odc_ObjSetTravIdCurrent(p, pObj);
|
|
// call recursively
|
|
Abc_NtkDontCareSimulate_rec( p, Odc_ObjFanin0(pObj) );
|
|
Abc_NtkDontCareSimulate_rec( p, Odc_ObjFanin1(pObj) );
|
|
// construct the truth table
|
|
Abc_NtkDontCareTruthOne( p, Lit );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the truth table of the care set.]
|
|
|
|
Description [Returns the number of ones in the simulation info.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareSimulate( Odc_Man_t * p, unsigned * puTruth )
|
|
{
|
|
Odc_ManIncrementTravId( p );
|
|
Abc_NtkDontCareSimulate_rec( p, Odc_Regular(p->iRoot) );
|
|
Abc_InfoCopy( puTruth, Odc_ObjTruth(p, Odc_Regular(p->iRoot)), p->nWords );
|
|
if ( Odc_IsComplement(p->iRoot) )
|
|
Abc_InfoNot( puTruth, p->nWords );
|
|
return Extra_TruthCountOnes( puTruth, p->nVarsMax );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the truth table of the care set.]
|
|
|
|
Description [Returns the number of ones in the simulation info.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareSimulateBefore( Odc_Man_t * p, unsigned * puTruth )
|
|
{
|
|
int nIters = 2;
|
|
int nRounds, Counter, r;
|
|
// decide how many rounds to simulate
|
|
nRounds = p->nBits / p->nWords;
|
|
Counter = 0;
|
|
for ( r = 0; r < nIters; r++ )
|
|
{
|
|
Abc_NtkDontCareSimulateSetRand( p );
|
|
Abc_NtkDontCareSimulate( p, puTruth );
|
|
Counter += Abc_NtkDontCareCountMintsWord( p, puTruth );
|
|
}
|
|
// normalize
|
|
Counter = Counter * nRounds / nIters;
|
|
return Counter;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes ODCs for the node in terms of the cut variables.]
|
|
|
|
Description [Returns the number of don't care minterms in the truth table.
|
|
In particular, this procedure returns 0 if there is no don't-cares.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkDontCareCompute( Odc_Man_t * p, Abc_Obj_t * pNode, Vec_Ptr_t * vLeaves, unsigned * puTruth )
|
|
{
|
|
int nMints, RetValue;
|
|
clock_t clk, clkTotal = clock();
|
|
|
|
p->nWins++;
|
|
|
|
// set the parameters
|
|
assert( !Abc_ObjIsComplement(pNode) );
|
|
assert( Abc_ObjIsNode(pNode) );
|
|
assert( Vec_PtrSize(vLeaves) <= p->nVarsMax );
|
|
p->vLeaves = vLeaves;
|
|
p->pNode = pNode;
|
|
|
|
// compute the window
|
|
clk = clock();
|
|
RetValue = Abc_NtkDontCareWindow( p );
|
|
p->timeWin += clock() - clk;
|
|
if ( !RetValue )
|
|
{
|
|
p->timeAbort += clock() - clkTotal;
|
|
Abc_InfoFill( puTruth, p->nWords );
|
|
p->nWinsEmpty++;
|
|
return 0;
|
|
}
|
|
|
|
if ( p->fVeryVerbose )
|
|
{
|
|
printf( " %5d : ", pNode->Id );
|
|
printf( "Leaf = %2d ", Vec_PtrSize(p->vLeaves) );
|
|
printf( "Root = %2d ", Vec_PtrSize(p->vRoots) );
|
|
printf( "Bran = %2d ", Vec_PtrSize(p->vBranches) );
|
|
printf( " | " );
|
|
}
|
|
|
|
// transfer the window into the AIG package
|
|
clk = clock();
|
|
Abc_NtkDontCareTransfer( p );
|
|
p->timeMiter += clock() - clk;
|
|
|
|
// simulate to estimate the amount of don't-cares
|
|
clk = clock();
|
|
nMints = Abc_NtkDontCareSimulateBefore( p, puTruth );
|
|
p->timeSim += clock() - clk;
|
|
if ( p->fVeryVerbose )
|
|
{
|
|
printf( "AIG = %5d ", Odc_NodeNum(p) );
|
|
printf( "%6.2f %% ", 100.0 * (p->nBits - nMints) / p->nBits );
|
|
}
|
|
|
|
// if there is less then the given percentage of don't-cares, skip
|
|
if ( 100.0 * (p->nBits - nMints) / p->nBits < 1.0 * p->nPercCutoff )
|
|
{
|
|
p->timeAbort += clock() - clkTotal;
|
|
if ( p->fVeryVerbose )
|
|
printf( "Simulation cutoff.\n" );
|
|
Abc_InfoFill( puTruth, p->nWords );
|
|
p->nSimsEmpty++;
|
|
return 0;
|
|
}
|
|
|
|
// quantify external variables
|
|
clk = clock();
|
|
RetValue = Abc_NtkDontCareQuantify( p );
|
|
p->timeQuant += clock() - clk;
|
|
if ( !RetValue )
|
|
{
|
|
p->timeAbort += clock() - clkTotal;
|
|
if ( p->fVeryVerbose )
|
|
printf( "=== Overflow! ===\n" );
|
|
Abc_InfoFill( puTruth, p->nWords );
|
|
p->nQuantsOver++;
|
|
return 0;
|
|
}
|
|
|
|
// get the truth table
|
|
clk = clock();
|
|
Abc_NtkDontCareSimulateSetElem( p );
|
|
nMints = Abc_NtkDontCareSimulate( p, puTruth );
|
|
p->timeTruth += clock() - clk;
|
|
if ( p->fVeryVerbose )
|
|
{
|
|
printf( "AIG = %5d ", Odc_NodeNum(p) );
|
|
printf( "%6.2f %% ", 100.0 * (p->nBits - nMints) / p->nBits );
|
|
printf( "\n" );
|
|
}
|
|
p->timeTotal += clock() - clkTotal;
|
|
p->nWinsFinish++;
|
|
p->nTotalDcs += (int)(100.0 * (p->nBits - nMints) / p->nBits);
|
|
return nMints;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|