blob: 8d8c7c6b6b0c263373e3a89bd834201e8eb2eaff [file] [log] [blame]
/**CFile****************************************************************
FileName [bmcICheck.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [SAT-based bounded model checking.]
Synopsis [Performs specialized check.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: bmcICheck.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "bmc.h"
#include "sat/cnf/cnf.h"
#include "sat/bsat/satStore.h"
#include "aig/gia/giaAig.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline Cnf_Dat_t * Cnf_DeriveGiaRemapped( Gia_Man_t * p )
{
Cnf_Dat_t * pCnf;
Aig_Man_t * pAig = Gia_ManToAigSimple( p );
pAig->nRegs = 0;
pCnf = Cnf_Derive( pAig, Aig_ManCoNum(pAig) );
Aig_ManStop( pAig );
return pCnf;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline void Cnf_DataLiftGia( Cnf_Dat_t * p, Gia_Man_t * pGia, int nVarsPlus )
{
Gia_Obj_t * pObj;
int v;
Gia_ManForEachObj( pGia, pObj, v )
if ( p->pVarNums[Gia_ObjId(pGia, pObj)] >= 0 )
p->pVarNums[Gia_ObjId(pGia, pObj)] += nVarsPlus;
for ( v = 0; v < p->nLiterals; v++ )
p->pClauses[0][v] += 2*nVarsPlus;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
sat_solver * Bmc_DeriveSolver( Gia_Man_t * p, Gia_Man_t * pMiter, Cnf_Dat_t * pCnf, int nFramesMax, int nTimeOut, int fVerbose )
{
sat_solver * pSat;
Vec_Int_t * vLits;
Gia_Obj_t * pObj, * pObj0, * pObj1;
int i, k, iVar0, iVar1, iVarOut;
int VarShift = 0;
// start the SAT solver
pSat = sat_solver_new();
sat_solver_setnvars( pSat, Gia_ManRegNum(p) + Gia_ManCoNum(p) + pCnf->nVars * (nFramesMax + 1) );
sat_solver_set_runtime_limit( pSat, nTimeOut ? nTimeOut * CLOCKS_PER_SEC + Abc_Clock(): 0 );
// add one large OR clause
vLits = Vec_IntAlloc( Gia_ManCoNum(p) );
Gia_ManForEachCo( p, pObj, i )
Vec_IntPush( vLits, Abc_Var2Lit(Gia_ManRegNum(p) + i, 0) );
sat_solver_addclause( pSat, Vec_IntArray(vLits), Vec_IntArray(vLits) + Vec_IntSize(vLits) );
// load the last timeframe
Cnf_DataLiftGia( pCnf, pMiter, Gia_ManRegNum(p) + Gia_ManCoNum(p) );
VarShift += Gia_ManRegNum(p) + Gia_ManCoNum(p);
// add XOR clauses
Gia_ManForEachPo( p, pObj, i )
{
pObj0 = Gia_ManPo( pMiter, 2*i+0 );
pObj1 = Gia_ManPo( pMiter, 2*i+1 );
iVar0 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj0)];
iVar1 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj1)];
iVarOut = Gia_ManRegNum(p) + i;
sat_solver_add_xor( pSat, iVar0, iVar1, iVarOut, 0 );
}
Gia_ManForEachRi( p, pObj, i )
{
pObj0 = Gia_ManRi( pMiter, i );
pObj1 = Gia_ManRi( pMiter, i + Gia_ManRegNum(p) );
iVar0 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj0)];
iVar1 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj1)];
iVarOut = Gia_ManRegNum(p) + Gia_ManPoNum(p) + i;
sat_solver_add_xor_and( pSat, iVarOut, iVar0, iVar1, i );
}
// add timeframe clauses
for ( i = 0; i < pCnf->nClauses; i++ )
if ( !sat_solver_addclause( pSat, pCnf->pClauses[i], pCnf->pClauses[i+1] ) )
assert( 0 );
// add other timeframes
for ( k = 0; k < nFramesMax; k++ )
{
// collect variables of the RO nodes
Vec_IntClear( vLits );
Gia_ManForEachRo( pMiter, pObj, i )
Vec_IntPush( vLits, pCnf->pVarNums[Gia_ObjId(pMiter, pObj)] );
// lift CNF again
Cnf_DataLiftGia( pCnf, pMiter, pCnf->nVars );
VarShift += pCnf->nVars;
// stitch the clauses
Gia_ManForEachRi( pMiter, pObj, i )
{
iVar0 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj)];
iVar1 = Vec_IntEntry( vLits, i );
if ( iVar1 == -1 )
continue;
sat_solver_add_buffer( pSat, iVar0, iVar1, 0 );
}
// add equality clauses for the COs
Gia_ManForEachPo( p, pObj, i )
{
pObj0 = Gia_ManPo( pMiter, 2*i+0 );
pObj1 = Gia_ManPo( pMiter, 2*i+1 );
iVar0 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj0)];
iVar1 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj1)];
sat_solver_add_buffer( pSat, iVar0, iVar1, 0 );
}
Gia_ManForEachRi( p, pObj, i )
{
pObj0 = Gia_ManRi( pMiter, i );
pObj1 = Gia_ManRi( pMiter, i + Gia_ManRegNum(p) );
iVar0 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj0)];
iVar1 = pCnf->pVarNums[Gia_ObjId(pMiter, pObj1)];
sat_solver_add_buffer_enable( pSat, iVar0, iVar1, i, 0 );
}
// add timeframe clauses
for ( i = 0; i < pCnf->nClauses; i++ )
if ( !sat_solver_addclause( pSat, pCnf->pClauses[i], pCnf->pClauses[i+1] ) )
assert( 0 );
}
// sat_solver_compress( pSat );
Cnf_DataLiftGia( pCnf, pMiter, -VarShift );
Vec_IntFree( vLits );
return pSat;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Bmc_PerformICheck( Gia_Man_t * p, int nFramesMax, int nTimeOut, int fEmpty, int fVerbose )
{
int fUseOldCnf = 0;
Gia_Man_t * pMiter, * pTemp;
Cnf_Dat_t * pCnf;
sat_solver * pSat;
Vec_Int_t * vLits, * vUsed;
int i, status, Lit;
int nLitsUsed, nLits, * pLits;
abctime clkStart = Abc_Clock();
assert( nFramesMax > 0 );
assert( Gia_ManRegNum(p) > 0 );
if ( fVerbose )
printf( "Solving M-inductiveness for design %s with %d AND nodes and %d flip-flops:\n",
Gia_ManName(p), Gia_ManAndNum(p), Gia_ManRegNum(p) );
// create miter
pTemp = Gia_ManDup( p );
pMiter = Gia_ManMiter( p, pTemp, 0, 1, 1, 0, 0 );
Gia_ManStop( pTemp );
assert( Gia_ManPoNum(pMiter) == 2 * Gia_ManPoNum(p) );
assert( Gia_ManRegNum(pMiter) == 2 * Gia_ManRegNum(p) );
// derive CNF
if ( fUseOldCnf )
pCnf = Cnf_DeriveGiaRemapped( pMiter );
else
{
pMiter = Jf_ManDeriveCnf( pTemp = pMiter, 0 );
Gia_ManStop( pTemp );
pCnf = (Cnf_Dat_t *)pMiter->pData; pMiter->pData = NULL;
}
// collect positive literals
vLits = Vec_IntAlloc( Gia_ManCoNum(p) );
for ( i = 0; i < Gia_ManRegNum(p); i++ )
Vec_IntPush( vLits, Abc_Var2Lit(i, fEmpty) );
// iteratively compute a minimal M-inductive set of next-state functions
nLitsUsed = fEmpty ? 0 : Vec_IntSize(vLits);
vUsed = Vec_IntAlloc( Vec_IntSize(vLits) );
while ( 1 )
{
int fChanges = 0;
// derive SAT solver
pSat = Bmc_DeriveSolver( p, pMiter, pCnf, nFramesMax, nTimeOut, fVerbose );
// sat_solver_bookmark( pSat );
status = sat_solver_solve( pSat, Vec_IntArray(vLits), Vec_IntArray(vLits) + Vec_IntSize(vLits), (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 );
if ( status == l_Undef )
{
printf( "Timeout reached after %d seconds.\n", nTimeOut );
break;
}
if ( status == l_True )
{
printf( "The problem is satisfiable (the current set is not M-inductive).\n" );
break;
}
assert( status == l_False );
// call analize_final
nLits = sat_solver_final( pSat, &pLits );
// mark used literals
Vec_IntFill( vUsed, Vec_IntSize(vLits), 0 );
for ( i = 0; i < nLits; i++ )
Vec_IntWriteEntry( vUsed, Abc_Lit2Var(pLits[i]), 1 );
// check if there are any positive unused
Vec_IntForEachEntry( vLits, Lit, i )
{
assert( i == Abc_Lit2Var(Lit) );
if ( Abc_LitIsCompl(Lit) )
continue;
if ( Vec_IntEntry(vUsed, i) )
continue;
// positive literal became unused
Vec_IntWriteEntry( vLits, i, Abc_LitNot(Lit) );
nLitsUsed--;
fChanges = 1;
}
// report the results
if ( fVerbose )
printf( "M =%4d : AIG =%8d. SAT vars =%8d. SAT conf =%8d. S =%6d. (%6.2f %%) ",
nFramesMax, (nFramesMax+1) * Gia_ManAndNum(pMiter),
Gia_ManRegNum(p) + Gia_ManCoNum(p) + sat_solver_nvars(pSat),
sat_solver_nconflicts(pSat), nLitsUsed, 100.0 * nLitsUsed / Gia_ManRegNum(p) );
if ( fVerbose )
Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart );
// count the number of negative literals
sat_solver_delete( pSat );
if ( !fChanges || fEmpty )
break;
// break;
// sat_solver_rollback( pSat );
}
Cnf_DataFree( pCnf );
Gia_ManStop( pMiter );
Vec_IntFree( vLits );
Vec_IntFree( vUsed );
}
/**Function*************************************************************
Synopsis [Collect flops starting from the POs.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Bmc_PerformFindFlopOrder_rec( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Int_t * vRegs )
{
if ( Gia_ObjIsTravIdCurrent(p, pObj) )
return;
Gia_ObjSetTravIdCurrent(p, pObj);
if ( Gia_ObjIsCi(pObj) )
{
if ( Gia_ObjIsRo(p, pObj) )
Vec_IntPush( vRegs, Gia_ObjId(p, pObj) );
return;
}
assert( Gia_ObjIsAnd(pObj) );
Bmc_PerformFindFlopOrder_rec( p, Gia_ObjFanin0(pObj), vRegs );
Bmc_PerformFindFlopOrder_rec( p, Gia_ObjFanin1(pObj), vRegs );
}
void Bmc_PerformFindFlopOrder( Gia_Man_t * p, Vec_Int_t * vRegs )
{
Gia_Obj_t * pObj;
int i, iReg, k = 0;
// start with POs
Vec_IntClear( vRegs );
Gia_ManForEachPo( p, pObj, i )
Vec_IntPush( vRegs, Gia_ObjId(p, pObj) );
// add flop outputs in the B
Gia_ManIncrementTravId( p );
Gia_ObjSetTravIdCurrent( p, Gia_ManConst0(p) );
Gia_ManForEachObjVec( vRegs, p, pObj, i )
{
assert( Gia_ObjIsPo(p, pObj) || Gia_ObjIsRo(p, pObj) );
if ( Gia_ObjIsRo(p, pObj) )
pObj = Gia_ObjRoToRi( p, pObj );
Bmc_PerformFindFlopOrder_rec( p, Gia_ObjFanin0(pObj), vRegs );
}
// add dangling flops
Gia_ManForEachRo( p, pObj, i )
if ( !Gia_ObjIsTravIdCurrent(p, pObj) )
Vec_IntPush( vRegs, Gia_ObjId(p, pObj) );
// remove POs; keep flop outputs only; remap ObjId into CiId
assert( Vec_IntSize(vRegs) == Gia_ManCoNum(p) );
Gia_ManForEachObjVec( vRegs, p, pObj, i )
{
if ( i < Gia_ManPoNum(p) )
continue;
iReg = Gia_ObjCioId(pObj) - Gia_ManPiNum(p);
assert( iReg >= 0 && iReg < Gia_ManRegNum(p) );
Vec_IntWriteEntry( vRegs, k++, iReg );
}
Vec_IntShrink( vRegs, k );
assert( Vec_IntSize(vRegs) == Gia_ManRegNum(p) );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Bmc_PerformISearchOne( Gia_Man_t * p, int nFramesMax, int nTimeOut, int fReverse, int fBackTopo, int fVerbose, Vec_Int_t * vLits )
{
int fUseOldCnf = 0;
Gia_Man_t * pMiter, * pTemp;
Cnf_Dat_t * pCnf;
sat_solver * pSat;
Vec_Int_t * vRegs = NULL;
// Vec_Int_t * vLits;
int i, Iter, status;
int nLitsUsed, RetValue = 0;
abctime clkStart = Abc_Clock();
assert( nFramesMax > 0 );
assert( Gia_ManRegNum(p) > 0 );
// create miter
pTemp = Gia_ManDup( p );
pMiter = Gia_ManMiter( p, pTemp, 0, 1, 1, 0, 0 );
Gia_ManStop( pTemp );
assert( Gia_ManPoNum(pMiter) == 2 * Gia_ManPoNum(p) );
assert( Gia_ManRegNum(pMiter) == 2 * Gia_ManRegNum(p) );
// derive CNF
if ( fUseOldCnf )
pCnf = Cnf_DeriveGiaRemapped( pMiter );
else
{
//pMiter = Jf_ManDeriveCnf( pTemp = pMiter, 0 );
//Gia_ManStop( pTemp );
//pCnf = (Cnf_Dat_t *)pMiter->pData; pMiter->pData = NULL;
pCnf = (Cnf_Dat_t *)Mf_ManGenerateCnf( pMiter, 8, 0, 0, 0, 0 );
}
/*
// collect positive literals
vLits = Vec_IntAlloc( Gia_ManCoNum(p) );
for ( i = 0; i < Gia_ManRegNum(p); i++ )
Vec_IntPush( vLits, Abc_Var2Lit(i, 0) );
*/
// derive SAT solver
pSat = Bmc_DeriveSolver( p, pMiter, pCnf, nFramesMax, nTimeOut, fVerbose );
status = sat_solver_solve( pSat, Vec_IntArray(vLits), Vec_IntArray(vLits) + Vec_IntSize(vLits), (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 );
if ( status == l_True )
{
printf( "I = %4d : ", nFramesMax );
printf( "Problem is satisfiable.\n" );
sat_solver_delete( pSat );
Cnf_DataFree( pCnf );
Gia_ManStop( pMiter );
return 1;
}
if ( status == l_Undef )
{
printf( "ICheck: Timeout reached after %d seconds. \n", nTimeOut );
RetValue = 1;
goto cleanup;
}
assert( status == l_False );
// count the number of positive literals
nLitsUsed = 0;
for ( i = 0; i < Gia_ManRegNum(p); i++ )
if ( !Abc_LitIsCompl(Vec_IntEntry(vLits, i)) )
nLitsUsed++;
// try removing variables
vRegs = Vec_IntStartNatural( Gia_ManRegNum(p) );
if ( fBackTopo )
Bmc_PerformFindFlopOrder( p, vRegs );
if ( fReverse )
Vec_IntReverseOrder( vRegs );
// for ( Iter = 0; Iter < Gia_ManRegNum(p); Iter++ )
Vec_IntForEachEntry( vRegs, i, Iter )
{
// i = fReverse ? Gia_ManRegNum(p) - 1 - Iter : Iter;
if ( Abc_LitIsCompl(Vec_IntEntry(vLits, i)) )
continue;
Vec_IntWriteEntry( vLits, i, Abc_LitNot(Vec_IntEntry(vLits, i)) );
status = sat_solver_solve( pSat, Vec_IntArray(vLits), Vec_IntArray(vLits) + Vec_IntSize(vLits), (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 );
if ( status == l_Undef )
{
printf( "ICheck: Timeout reached after %d seconds. \n", nTimeOut );
RetValue = 1;
goto cleanup;
}
if ( status == l_True )
Vec_IntWriteEntry( vLits, i, Abc_LitNot(Vec_IntEntry(vLits, i)) );
else if ( status == l_False )
nLitsUsed--;
else assert( 0 );
// report the results
//printf( "Round %d: ", o );
if ( fVerbose )
{
printf( "I = %4d : AIG =%8d. SAT vars =%8d. SAT conf =%8d. S =%6d. (%6.2f %%) ",
i, (nFramesMax+1) * Gia_ManAndNum(pMiter),
Gia_ManRegNum(p) + Gia_ManCoNum(p) + sat_solver_nvars(pSat),
sat_solver_nconflicts(pSat), nLitsUsed, 100.0 * nLitsUsed / Gia_ManRegNum(p) );
ABC_PRTr( "Time", Abc_Clock() - clkStart );
fflush( stdout );
}
}
// report the results
//printf( "Round %d: ", o );
if ( fVerbose )
{
printf( "M = %4d : AIG =%8d. SAT vars =%8d. SAT conf =%8d. S =%6d. (%6.2f %%) ",
nFramesMax, (nFramesMax+1) * Gia_ManAndNum(pMiter),
Gia_ManRegNum(p) + Gia_ManCoNum(p) + sat_solver_nvars(pSat),
sat_solver_nconflicts(pSat), nLitsUsed, 100.0 * nLitsUsed / Gia_ManRegNum(p) );
Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart );
fflush( stdout );
}
cleanup:
// cleanup
sat_solver_delete( pSat );
Cnf_DataFree( pCnf );
Gia_ManStop( pMiter );
Vec_IntFree( vRegs );
// Vec_IntFree( vLits );
return RetValue;
}
Vec_Int_t * Bmc_PerformISearch( Gia_Man_t * p, int nFramesMax, int nTimeOut, int fReverse, int fBackTopo, int fDump, int fVerbose )
{
Vec_Int_t * vLits, * vFlops;
int i, f;
if ( fVerbose )
printf( "Solving M-inductiveness for design %s with %d AND nodes and %d flip-flops with %s %s flop order:\n",
Gia_ManName(p), Gia_ManAndNum(p), Gia_ManRegNum(p), fReverse ? "reverse":"direct", fBackTopo ? "backward":"natural" );
fflush( stdout );
// collect positive literals
vLits = Vec_IntAlloc( Gia_ManCoNum(p) );
for ( i = 0; i < Gia_ManRegNum(p); i++ )
Vec_IntPush( vLits, Abc_Var2Lit(i, 0) );
for ( f = 1; f <= nFramesMax; f++ )
if ( Bmc_PerformISearchOne( p, f, nTimeOut, fReverse, fBackTopo, fVerbose, vLits ) )
{
Vec_IntFree( vLits );
return NULL;
}
// dump the numbers of the flops
if ( fDump )
{
int nLitsUsed = 0;
for ( i = 0; i < Gia_ManRegNum(p); i++ )
if ( !Abc_LitIsCompl(Vec_IntEntry(vLits, i)) )
nLitsUsed++;
printf( "The set contains %d (out of %d) next-state functions with 0-based numbers:\n", nLitsUsed, Gia_ManRegNum(p) );
for ( i = 0; i < Gia_ManRegNum(p); i++ )
if ( !Abc_LitIsCompl(Vec_IntEntry(vLits, i)) )
printf( "%d ", i );
printf( "\n" );
}
// save flop indexes
vFlops = Vec_IntAlloc( Gia_ManRegNum(p) );
for ( i = 0; i < Gia_ManRegNum(p); i++ )
if ( !Abc_LitIsCompl(Vec_IntEntry(vLits, i)) )
Vec_IntPush( vFlops, 1 );
else
Vec_IntPush( vFlops, 0 );
Vec_IntFree( vLits );
return vFlops;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END