blob: 6e5fd2212ca56b1a802c97717e2da2ded2447710 [file] [log] [blame]
/**CFile****************************************************************
FileName [cecSynth.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Combinational equivalence checking.]
Synopsis [Partitioned sequential synthesis.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: cecSynth.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "cecInt.h"
#include "aig/gia/giaAig.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Populate sequential synthesis parameters.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Cec_SeqSynthesisSetDefaultParams( Cec_ParSeq_t * p )
{
memset( p, 0, sizeof(Cec_ParSeq_t) );
p->fUseLcorr = 0; // enables latch correspondence
p->fUseScorr = 0; // enables signal correspondence
p->nBTLimit = 1000; // (scorr/lcorr) conflict limit at a node
p->nFrames = 1; // (scorr only) the number of timeframes
p->nLevelMax = -1; // (scorr only) the max number of levels
p->fConsts = 1; // (scl only) merging constants
p->fEquivs = 1; // (scl only) merging equivalences
p->fUseMiniSat = 0; // enables MiniSat in lcorr/scorr
p->nMinDomSize = 100; // the size of minimum clock domain
p->fVeryVerbose = 0; // verbose stats
p->fVerbose = 0; // verbose stats
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Cec_SeqReadMinDomSize( Cec_ParSeq_t * p )
{
return p->nMinDomSize;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Cec_SeqReadVerbose( Cec_ParSeq_t * p )
{
return p->fVerbose;
}
/**Function*************************************************************
Synopsis [Computes partitioning of registers.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Gia_Man_t * Gia_ManRegCreatePart( Gia_Man_t * p, Vec_Int_t * vPart, int * pnCountPis, int * pnCountRegs, int ** ppMapBack )
{
Gia_Man_t * pNew;
Gia_Obj_t * pObj;
Vec_Int_t * vNodes, * vRoots;
int i, iOut, nCountPis, nCountRegs;
int * pMapBack;
// collect/mark nodes/PIs in the DFS order from the roots
Gia_ManIncrementTravId( p );
vRoots = Vec_IntAlloc( Vec_IntSize(vPart) );
Vec_IntForEachEntry( vPart, iOut, i )
Vec_IntPush( vRoots, Gia_ObjId(p, Gia_ManCo(p, Gia_ManPoNum(p)+iOut)) );
vNodes = Gia_ManCollectNodesCis( p, Vec_IntArray(vRoots), Vec_IntSize(vRoots) );
Vec_IntFree( vRoots );
// unmark register outputs
Vec_IntForEachEntry( vPart, iOut, i )
Gia_ObjSetTravIdPrevious( p, Gia_ManCi(p, Gia_ManPiNum(p)+iOut) );
// count pure PIs
nCountPis = nCountRegs = 0;
Gia_ManForEachPi( p, pObj, i )
nCountPis += Gia_ObjIsTravIdCurrent(p, pObj);
// count outputs of other registers
Gia_ManForEachRo( p, pObj, i )
nCountRegs += Gia_ObjIsTravIdCurrent(p, pObj); // should be !Gia_... ???
if ( pnCountPis )
*pnCountPis = nCountPis;
if ( pnCountRegs )
*pnCountRegs = nCountRegs;
// clean old manager
Gia_ManFillValue(p);
Gia_ManConst0(p)->Value = 0;
// create the new manager
pNew = Gia_ManStart( Vec_IntSize(vNodes) );
// create the PIs
Gia_ManForEachCi( p, pObj, i )
if ( Gia_ObjIsTravIdCurrent(p, pObj) )
pObj->Value = Gia_ManAppendCi(pNew);
// add variables for the register outputs
// create fake POs to hold the register outputs
Vec_IntForEachEntry( vPart, iOut, i )
{
pObj = Gia_ManCi(p, Gia_ManPiNum(p)+iOut);
pObj->Value = Gia_ManAppendCi(pNew);
Gia_ManAppendCo( pNew, pObj->Value );
Gia_ObjSetTravIdCurrent( p, pObj ); // added
}
// create the nodes
Gia_ManForEachObjVec( vNodes, p, pObj, i )
if ( Gia_ObjIsAnd(pObj) )
pObj->Value = Gia_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) );
// add real POs for the registers
Vec_IntForEachEntry( vPart, iOut, i )
{
pObj = Gia_ManCo( p, Gia_ManPoNum(p)+iOut );
Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) );
}
Gia_ManSetRegNum( pNew, Vec_IntSize(vPart) );
// create map
if ( ppMapBack )
{
pMapBack = ABC_FALLOC( int, Gia_ManObjNum(pNew) );
// map constant nodes
pMapBack[0] = 0;
// logic cones of register outputs
Gia_ManForEachObjVec( vNodes, p, pObj, i )
{
// pObjNew = Aig_Regular(pObj->pData);
// pMapBack[pObjNew->Id] = pObj->Id;
assert( Abc_Lit2Var(Gia_ObjValue(pObj)) >= 0 );
assert( Abc_Lit2Var(Gia_ObjValue(pObj)) < Gia_ManObjNum(pNew) );
pMapBack[ Abc_Lit2Var(Gia_ObjValue(pObj)) ] = Gia_ObjId(p, pObj);
}
// map register outputs
Vec_IntForEachEntry( vPart, iOut, i )
{
pObj = Gia_ManCi(p, Gia_ManPiNum(p)+iOut);
// pObjNew = pObj->pData;
// pMapBack[pObjNew->Id] = pObj->Id;
assert( Abc_Lit2Var(Gia_ObjValue(pObj)) >= 0 );
assert( Abc_Lit2Var(Gia_ObjValue(pObj)) < Gia_ManObjNum(pNew) );
pMapBack[ Abc_Lit2Var(Gia_ObjValue(pObj)) ] = Gia_ObjId(p, pObj);
}
*ppMapBack = pMapBack;
}
Vec_IntFree( vNodes );
return pNew;
}
/**Function*************************************************************
Synopsis [Transfers the classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Gia_TransferMappedClasses( Gia_Man_t * pPart, int * pMapBack, int * pReprs )
{
Gia_Obj_t * pObj;
int i, Id1, Id2, nClasses;
if ( pPart->pReprs == NULL )
return 0;
nClasses = 0;
Gia_ManForEachObj( pPart, pObj, i )
{
if ( Gia_ObjRepr(pPart, i) == GIA_VOID )
continue;
assert( i < Gia_ManObjNum(pPart) );
assert( Gia_ObjRepr(pPart, i) < Gia_ManObjNum(pPart) );
Id1 = pMapBack[ i ];
Id2 = pMapBack[ Gia_ObjRepr(pPart, i) ];
if ( Id1 == Id2 )
continue;
if ( Id1 < Id2 )
pReprs[Id2] = Id1;
else
pReprs[Id1] = Id2;
nClasses++;
}
return nClasses;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Gia_ManFindRepr_rec( int * pReprs, int Id )
{
if ( pReprs[Id] == 0 )
return 0;
if ( pReprs[Id] == ~0 )
return Id;
return Gia_ManFindRepr_rec( pReprs, pReprs[Id] );
}
/**Function*************************************************************
Synopsis [Normalizes equivalences.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Gia_ManNormalizeEquivalences( Gia_Man_t * p, int * pReprs )
{
int i, iRepr;
assert( p->pReprs == NULL );
assert( p->pNexts == NULL );
p->pReprs = ABC_CALLOC( Gia_Rpr_t, Gia_ManObjNum(p) );
for ( i = 0; i < Gia_ManObjNum(p); i++ )
Gia_ObjSetRepr( p, i, GIA_VOID );
for ( i = 0; i < Gia_ManObjNum(p); i++ )
{
if ( pReprs[i] == ~0 )
continue;
iRepr = Gia_ManFindRepr_rec( pReprs, i );
Gia_ObjSetRepr( p, i, iRepr );
}
p->pNexts = Gia_ManDeriveNexts( p );
}
/**Function*************************************************************
Synopsis [Partitioned sequential synthesis.]
Description [Returns AIG annotated with equivalence classes.]
SideEffects []
SeeAlso []
***********************************************************************/
int Cec_SequentialSynthesisPart( Gia_Man_t * p, Cec_ParSeq_t * pPars )
{
int fPrintParts = 0;
char Buffer[100];
Gia_Man_t * pTemp;
Vec_Ptr_t * vParts = (Vec_Ptr_t *)p->vClockDoms;
Vec_Int_t * vPart;
int * pMapBack, * pReprs;
int i, nCountPis, nCountRegs;
int nClasses;
abctime clk = Abc_Clock();
// save parameters
if ( fPrintParts )
{
// print partitions
Abc_Print( 1, "The following clock domains are used:\n" );
Vec_PtrForEachEntry( Vec_Int_t *, vParts, vPart, i )
{
pTemp = Gia_ManRegCreatePart( p, vPart, &nCountPis, &nCountRegs, NULL );
sprintf( Buffer, "part%03d.aig", i );
Gia_AigerWrite( pTemp, Buffer, 0, 0 );
Abc_Print( 1, "part%03d.aig : Reg = %4d. PI = %4d. (True = %4d. Regs = %4d.) And = %5d.\n",
i, Vec_IntSize(vPart), Gia_ManCiNum(pTemp)-Vec_IntSize(vPart), nCountPis, nCountRegs, Gia_ManAndNum(pTemp) );
Gia_ManStop( pTemp );
}
}
// perform sequential synthesis for clock domains
pReprs = ABC_FALLOC( int, Gia_ManObjNum(p) );
Vec_PtrForEachEntry( Vec_Int_t *, vParts, vPart, i )
{
pTemp = Gia_ManRegCreatePart( p, vPart, &nCountPis, &nCountRegs, &pMapBack );
if ( nCountPis > 0 )
{
if ( pPars->fUseScorr )
{
Cec_ParCor_t CorPars, * pCorPars = &CorPars;
Cec_ManCorSetDefaultParams( pCorPars );
pCorPars->nBTLimit = pPars->nBTLimit;
pCorPars->nLevelMax = pPars->nLevelMax;
pCorPars->fVerbose = pPars->fVeryVerbose;
pCorPars->fUseCSat = 1;
Cec_ManLSCorrespondenceClasses( pTemp, pCorPars );
}
else if ( pPars->fUseLcorr )
{
Cec_ParCor_t CorPars, * pCorPars = &CorPars;
Cec_ManCorSetDefaultParams( pCorPars );
pCorPars->fLatchCorr = 1;
pCorPars->nBTLimit = pPars->nBTLimit;
pCorPars->fVerbose = pPars->fVeryVerbose;
pCorPars->fUseCSat = 1;
Cec_ManLSCorrespondenceClasses( pTemp, pCorPars );
}
else
{
// pNew = Gia_ManSeqStructSweep( pTemp, pPars->fConsts, pPars->fEquivs, pPars->fVerbose );
// Gia_ManStop( pNew );
Gia_ManSeqCleanupClasses( pTemp, pPars->fConsts, pPars->fEquivs, pPars->fVerbose );
}
//Abc_Print( 1, "Part equivalences = %d.\n", Gia_ManEquivCountLitsAll(pTemp) );
nClasses = Gia_TransferMappedClasses( pTemp, pMapBack, pReprs );
if ( pPars->fVerbose )
{
Abc_Print( 1, "%3d : Reg = %4d. PI = %4d. (True = %4d. Regs = %4d.) And = %5d. Cl = %5d.\n",
i, Vec_IntSize(vPart), Gia_ManCiNum(pTemp)-Vec_IntSize(vPart), nCountPis, nCountRegs, Gia_ManAndNum(pTemp), nClasses );
}
}
Gia_ManStop( pTemp );
ABC_FREE( pMapBack );
}
// generate resulting equivalences
Gia_ManNormalizeEquivalences( p, pReprs );
//Abc_Print( 1, "Total equivalences = %d.\n", Gia_ManEquivCountLitsAll(p) );
ABC_FREE( pReprs );
if ( pPars->fVerbose )
{
Abc_PrintTime( 1, "Total time", Abc_Clock() - clk );
}
return 1;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Gia_ManTestOnePair_rec( sat_solver * pSat, Gia_Man_t * p, int iObj, Vec_Int_t * vSatVar )
{
Gia_Obj_t * pObj;
int iVar, iVar0, iVar1;
if ( Vec_IntEntry(vSatVar, iObj) >= 0 )
return Vec_IntEntry(vSatVar, iObj);
iVar = sat_solver_addvar(pSat);
Vec_IntWriteEntry( vSatVar, iObj, iVar );
pObj = Gia_ManObj( p, iObj );
if ( Gia_ObjIsAnd(pObj) )
{
iVar0 = Gia_ManTestOnePair_rec( pSat, p, Gia_ObjFaninId0(pObj, iObj), vSatVar );
iVar1 = Gia_ManTestOnePair_rec( pSat, p, Gia_ObjFaninId1(pObj, iObj), vSatVar );
sat_solver_add_and( pSat, iVar, iVar0, iVar1, Gia_ObjFaninC0(pObj), Gia_ObjFaninC1(pObj), 0 );
}
return iVar;
}
int Gia_ManTestOnePair( Gia_Man_t * p, int iObj1, int iObj2, int fPhase )
{
int Lits[2] = {1}, status;
sat_solver * pSat = sat_solver_new();
Vec_Int_t * vSatVar = Vec_IntStartFull( Gia_ManObjNum(p) );
Vec_IntWriteEntry( vSatVar, 0, sat_solver_addvar(pSat) );
sat_solver_addclause( pSat, Lits, Lits + 1 );
Gia_ManTestOnePair_rec( pSat, p, iObj1, vSatVar );
Gia_ManTestOnePair_rec( pSat, p, iObj2, vSatVar );
Lits[0] = Abc_Var2Lit( Vec_IntEntry(vSatVar, iObj1), 1 );
Lits[1] = Abc_Var2Lit( Vec_IntEntry(vSatVar, iObj2), fPhase );
status = sat_solver_solve( pSat, Lits, Lits + 2, 0, 0, 0, 0 );
if ( status == l_False )
{
Lits[0] = Abc_LitNot( Lits[0] );
Lits[1] = Abc_LitNot( Lits[1] );
status = sat_solver_solve( pSat, Lits, Lits + 2, 0, 0, 0, 0 );
}
Vec_IntFree( vSatVar );
sat_solver_delete( pSat );
return status;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END