mirror of https://github.com/YosysHQ/abc.git
446 lines
14 KiB
C
446 lines
14 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [sswPart.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Inductive prover with constraints.]
|
|
|
|
Synopsis [Partitioned signal correspondence.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - September 1, 2008.]
|
|
|
|
Revision [$Id: sswPart.c,v 1.00 2008/09/01 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "sswInt.h"
|
|
#include "aig/ioa/ioa.h"
|
|
#include "aig/gia/giaAig.h"
|
|
#include "proof/cec/cec.h"
|
|
|
|
#ifdef ABC_USE_PTHREADS
|
|
|
|
#ifdef _WIN32
|
|
#include "../lib/pthread.h"
|
|
#else
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
#include <atomic>
|
|
using namespace std;
|
|
#else
|
|
#include <stdatomic.h>
|
|
#include <stdbool.h>
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performing SAT sweeping for the array of AIGs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Ssw_SignalCorrespondenceArray1( Vec_Ptr_t * vGias, Ssw_Pars_t * pPars )
|
|
{
|
|
Gia_Man_t * pGia; int i;
|
|
Cec_ParCor_t CorPars, * pCorPars = &CorPars;
|
|
Cec_ManCorSetDefaultParams( pCorPars );
|
|
pCorPars->nBTLimit = pPars->nBTLimit;
|
|
pCorPars->fVerbose = pPars->fVerbose;
|
|
pCorPars->fUseCSat = 1;
|
|
Vec_PtrForEachEntry( Gia_Man_t *, vGias, pGia, i )
|
|
if ( Gia_ManPiNum(pGia) > 0 )
|
|
Cec_ManLSCorrespondenceClasses( pGia, pCorPars );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performing SAT sweeping for the array of AIGs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
#ifndef ABC_USE_PTHREADS
|
|
|
|
void Ssw_SignalCorrespondenceArray( Vec_Ptr_t * vGias, Ssw_Pars_t * pPars )
|
|
{
|
|
Ssw_SignalCorrespondenceArray1( vGias, pPars );
|
|
}
|
|
|
|
#else // pthreads are used
|
|
|
|
|
|
#define PAR_THR_MAX 100
|
|
typedef struct Par_ScorrThData_t_
|
|
{
|
|
Cec_ParCor_t CorPars;
|
|
Gia_Man_t * p;
|
|
int * pMap;
|
|
int iThread;
|
|
int nTimeOut;
|
|
atomic_bool fWorking;
|
|
} Par_ScorrThData_t;
|
|
|
|
void * Ssw_GiaWorkerThread( void * pArg )
|
|
{
|
|
struct timespec pause_duration;
|
|
pause_duration.tv_sec = 0;
|
|
pause_duration.tv_nsec = 10000000L; // 10 milliseconds
|
|
|
|
Par_ScorrThData_t * pThData = (Par_ScorrThData_t *)pArg;
|
|
while ( 1 )
|
|
{
|
|
while ( !atomic_load_explicit((atomic_bool *)&pThData->fWorking, memory_order_acquire) )
|
|
nanosleep(&pause_duration, NULL);
|
|
if ( pThData->p == NULL )
|
|
{
|
|
pthread_exit( NULL );
|
|
assert( 0 );
|
|
return NULL;
|
|
}
|
|
Cec_ManLSCorrespondenceClasses( pThData->p, &pThData->CorPars );
|
|
atomic_store_explicit(&pThData->fWorking, false, memory_order_release);
|
|
}
|
|
assert( 0 );
|
|
return NULL;
|
|
}
|
|
|
|
void Ssw_SignalCorrespondenceArray( Vec_Ptr_t * vGias, Ssw_Pars_t * pPars )
|
|
{
|
|
//abctime clkTotal = Abc_Clock();
|
|
Par_ScorrThData_t ThData[PAR_THR_MAX];
|
|
pthread_t WorkerThread[PAR_THR_MAX];
|
|
int i, status, nProcs = pPars->nProcs;
|
|
Vec_Ptr_t * vStack;
|
|
Cec_ParCor_t CorPars, * pCorPars = &CorPars;
|
|
Cec_ManCorSetDefaultParams( pCorPars );
|
|
if ( pPars->fVerbose )
|
|
printf( "Running concurrent &scorr with %d processes.\n", nProcs );
|
|
fflush( stdout );
|
|
if ( pPars->nProcs < 2 )
|
|
return Ssw_SignalCorrespondenceArray1( vGias, pPars );
|
|
// subtract manager thread
|
|
nProcs--;
|
|
assert( nProcs >= 1 && nProcs <= PAR_THR_MAX );
|
|
// start threads
|
|
for ( i = 0; i < nProcs; i++ )
|
|
{
|
|
ThData[i].CorPars = *pCorPars;
|
|
ThData[i].iThread = i;
|
|
atomic_store_explicit(&ThData[i].fWorking, false, memory_order_release);
|
|
status = pthread_create( WorkerThread + i, NULL, Ssw_GiaWorkerThread, (void *)(ThData + i) ); assert( status == 0 );
|
|
}
|
|
|
|
struct timespec pause_duration;
|
|
pause_duration.tv_sec = 0;
|
|
pause_duration.tv_nsec = 10000000L; // 10 milliseconds
|
|
|
|
// look at the threads
|
|
vStack = Vec_PtrDup( vGias );
|
|
while ( Vec_PtrSize(vStack) > 0 )
|
|
{
|
|
for ( i = 0; i < nProcs; i++ )
|
|
{
|
|
if ( atomic_load_explicit(&ThData[i].fWorking, memory_order_acquire) )
|
|
continue;
|
|
ThData[i].p = (Gia_Man_t*)Vec_PtrPop( vStack );
|
|
atomic_store_explicit(&ThData[i].fWorking, true, memory_order_release);
|
|
break;
|
|
}
|
|
}
|
|
Vec_PtrFree( vStack );
|
|
// wait till threads finish
|
|
for ( i = 0; i < nProcs; i++ )
|
|
{
|
|
if ( atomic_load_explicit(&ThData[i].fWorking, memory_order_acquire) )
|
|
i = -1; // Start from the beginning again
|
|
nanosleep(&pause_duration, NULL);
|
|
}
|
|
|
|
// stop threads
|
|
for ( i = 0; i < nProcs; i++ )
|
|
{
|
|
ThData[i].p = NULL;
|
|
atomic_store_explicit(&ThData[i].fWorking, true, memory_order_release);
|
|
}
|
|
|
|
// Join threads
|
|
for ( i = 0; i < nProcs; i++ )
|
|
pthread_join( WorkerThread[i], NULL );
|
|
}
|
|
|
|
#endif // pthreads are used
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs partitioned sequential SAT sweeping.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Man_t * Ssw_SignalCorrespondencePart( Aig_Man_t * pAig, Ssw_Pars_t * pPars )
|
|
{
|
|
int fPrintParts = 1;
|
|
char Buffer[100];
|
|
Aig_Man_t * pTemp, * pNew;
|
|
Vec_Ptr_t * vResult;
|
|
Vec_Int_t * vPart;
|
|
int * pMapBack;
|
|
int i, nCountPis, nCountRegs;
|
|
int nClasses, nPartSize, fVerbose;
|
|
abctime clk = Abc_Clock();
|
|
if ( pPars->fConstrs )
|
|
{
|
|
Abc_Print( 1, "Cannot use partitioned computation with constraints.\n" );
|
|
return NULL;
|
|
}
|
|
// save parameters
|
|
nPartSize = pPars->nPartSize; pPars->nPartSize = 0;
|
|
fVerbose = pPars->fVerbose; pPars->fVerbose = 0;
|
|
// generate partitions
|
|
if ( pAig->vClockDoms )
|
|
{
|
|
// divide large clock domains into separate partitions
|
|
vResult = Vec_PtrAlloc( 100 );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, (Vec_Ptr_t *)pAig->vClockDoms, vPart, i )
|
|
{
|
|
if ( nPartSize && Vec_IntSize(vPart) > nPartSize )
|
|
Aig_ManPartDivide( vResult, vPart, nPartSize, pPars->nOverSize );
|
|
else
|
|
Vec_PtrPush( vResult, Vec_IntDup(vPart) );
|
|
}
|
|
}
|
|
else
|
|
vResult = Aig_ManRegPartitionSimple( pAig, nPartSize, pPars->nOverSize );
|
|
// vResult = Aig_ManPartitionSmartRegisters( pAig, nPartSize, 0 );
|
|
// vResult = Aig_ManRegPartitionSmart( pAig, nPartSize );
|
|
if ( fPrintParts )
|
|
{
|
|
// print partitions
|
|
Abc_Print( 1, "Simple partitioning. %d partitions are saved:\n", Vec_PtrSize(vResult) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vResult, vPart, i )
|
|
{
|
|
// extern void Ioa_WriteAiger( Aig_Man_t * pMan, char * pFileName, int fWriteSymbols, int fCompact );
|
|
sprintf( Buffer, "part%03d.aig", i );
|
|
pTemp = Aig_ManRegCreatePart( pAig, vPart, &nCountPis, &nCountRegs, NULL );
|
|
Ioa_WriteAiger( 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), Aig_ManCiNum(pTemp)-Vec_IntSize(vPart), nCountPis, nCountRegs, Aig_ManNodeNum(pTemp) );
|
|
Aig_ManStop( pTemp );
|
|
}
|
|
}
|
|
|
|
// perform SSW with partitions
|
|
Aig_ManReprStart( pAig, Aig_ManObjNumMax(pAig) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vResult, vPart, i )
|
|
{
|
|
pTemp = Aig_ManRegCreatePart( pAig, vPart, &nCountPis, &nCountRegs, &pMapBack );
|
|
Aig_ManSetRegNum( pTemp, pTemp->nRegs );
|
|
// create the projection of 1-hot registers
|
|
if ( pAig->vOnehots )
|
|
pTemp->vOnehots = Aig_ManRegProjectOnehots( pAig, pTemp, pAig->vOnehots, fVerbose );
|
|
// run SSW
|
|
if (nCountPis>0) {
|
|
pNew = Ssw_SignalCorrespondence( pTemp, pPars );
|
|
nClasses = Aig_TransferMappedClasses( pAig, pTemp, pMapBack );
|
|
if ( fVerbose )
|
|
Abc_Print( 1, "%3d : Reg = %4d. PI = %4d. (True = %4d. Regs = %4d.) And = %5d. It = %3d. Cl = %5d.\n",
|
|
i, Vec_IntSize(vPart), Aig_ManCiNum(pTemp)-Vec_IntSize(vPart), nCountPis, nCountRegs, Aig_ManNodeNum(pTemp), pPars->nIters, nClasses );
|
|
Aig_ManStop( pNew );
|
|
}
|
|
Aig_ManStop( pTemp );
|
|
ABC_FREE( pMapBack );
|
|
}
|
|
// remap the AIG
|
|
pNew = Aig_ManDupRepr( pAig, 0 );
|
|
Aig_ManSeqCleanup( pNew );
|
|
// Aig_ManPrintStats( pAig );
|
|
// Aig_ManPrintStats( pNew );
|
|
Vec_VecFree( (Vec_Vec_t *)vResult );
|
|
pPars->nPartSize = nPartSize;
|
|
pPars->fVerbose = fVerbose;
|
|
if ( fVerbose )
|
|
{
|
|
ABC_PRT( "Total time", Abc_Clock() - clk );
|
|
}
|
|
return pNew;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs partitioned sequential SAT sweeping.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Aig_Man_t * Ssw_SignalCorrespondencePart2( Aig_Man_t * pAig, Ssw_Pars_t * pPars )
|
|
{
|
|
int fPrintParts = 1;
|
|
//char Buffer[100];
|
|
Aig_Man_t * pTemp, * pNew;
|
|
Vec_Ptr_t * vAigs;
|
|
Vec_Ptr_t * vGias;
|
|
Vec_Ptr_t * vMaps;
|
|
Vec_Ptr_t * vResult;
|
|
Vec_Int_t * vPart;
|
|
int * pMapBack = NULL;
|
|
int i, nCountPis, nCountRegs;
|
|
int nClasses, nPartSize, fVerbose;
|
|
abctime clk = Abc_Clock();
|
|
if ( pPars->fConstrs )
|
|
{
|
|
Abc_Print( 1, "Cannot use partitioned computation with constraints.\n" );
|
|
return NULL;
|
|
}
|
|
// save parameters
|
|
nPartSize = pPars->nPartSize; pPars->nPartSize = 0;
|
|
fVerbose = pPars->fVerbose; pPars->fVerbose = 0;
|
|
// generate partitions
|
|
if ( pAig->vClockDoms )
|
|
{
|
|
// divide large clock domains into separate partitions
|
|
vResult = Vec_PtrAlloc( 100 );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, (Vec_Ptr_t *)pAig->vClockDoms, vPart, i )
|
|
{
|
|
if ( nPartSize && Vec_IntSize(vPart) > nPartSize )
|
|
Aig_ManPartDivide( vResult, vPart, nPartSize, pPars->nOverSize );
|
|
else
|
|
Vec_PtrPush( vResult, Vec_IntDup(vPart) );
|
|
}
|
|
}
|
|
else
|
|
vResult = Aig_ManRegPartitionSimple( pAig, nPartSize, pPars->nOverSize );
|
|
// vResult = Aig_ManPartitionSmartRegisters( pAig, nPartSize, 0 );
|
|
// vResult = Aig_ManRegPartitionSmart( pAig, nPartSize );
|
|
// collect partitions
|
|
vAigs = Vec_PtrAlloc( 100 );
|
|
vGias = Vec_PtrAlloc( 100 );
|
|
vMaps = Vec_PtrAlloc( 100 );
|
|
if ( fPrintParts )
|
|
Abc_Print( 1, "Simple partitioning. %d partitions are saved:\n", Vec_PtrSize(vResult) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vResult, vPart, i )
|
|
{
|
|
pTemp = Aig_ManRegCreatePart( pAig, vPart, &nCountPis, &nCountRegs, &pMapBack );
|
|
Aig_ManSetRegNum( pTemp, pTemp->nRegs );
|
|
Vec_PtrPush( vAigs, pTemp );
|
|
Vec_PtrPush( vGias, Gia_ManFromAigSimple(pTemp) );
|
|
Vec_PtrPush( vMaps, pMapBack );
|
|
//sprintf( Buffer, "part%03d.aig", i );
|
|
//Ioa_WriteAiger( pTemp, Buffer, 0, 0 );
|
|
if ( fPrintParts )
|
|
Abc_Print( 1, "part%03d.aig : Reg = %4d. PI = %4d. (True = %4d. Regs = %4d.) And = %5d.\n",
|
|
i, Vec_IntSize(vPart), Aig_ManCiNum(pTemp)-Vec_IntSize(vPart), nCountPis, nCountRegs, Aig_ManNodeNum(pTemp) );
|
|
}
|
|
// solve partitions
|
|
Ssw_SignalCorrespondenceArray( vGias, pPars );
|
|
// collect the results
|
|
Aig_ManReprStart( pAig, Aig_ManObjNumMax(pAig) );
|
|
Vec_PtrForEachEntry( Vec_Int_t *, vResult, vPart, i )
|
|
{
|
|
int * pMapBack = (int *)Vec_PtrEntry( vMaps, i );
|
|
Gia_Man_t * pGia = (Gia_Man_t *)Vec_PtrEntry( vGias, i );
|
|
Aig_Man_t * pTemp2 = Gia_ManToAigSimple( pGia );
|
|
pTemp = (Aig_Man_t *)Vec_PtrEntry( vAigs, i );
|
|
Gia_ManReprToAigRepr2( pTemp2, pGia );
|
|
// remap back
|
|
nClasses = Aig_TransferMappedClasses( pAig, pTemp2, pMapBack );
|
|
if ( fVerbose )
|
|
Abc_Print( 1, "%3d : Reg = %4d. PI = %4d. (True = %4d. Regs = %4d.) And = %5d. It = %3d. Cl = %5d.\n",
|
|
i, Vec_IntSize(vPart), Aig_ManCiNum(pTemp)-Vec_IntSize(vPart), 0, 0, Aig_ManNodeNum(pTemp), 0, nClasses );
|
|
Aig_ManStop( pTemp );
|
|
Aig_ManStop( pTemp2 );
|
|
Gia_ManStop( pGia );
|
|
ABC_FREE( pMapBack );
|
|
}
|
|
Vec_PtrFree( vAigs );
|
|
Vec_PtrFree( vGias );
|
|
Vec_PtrFree( vMaps );
|
|
|
|
// remap the AIG
|
|
pNew = Aig_ManDupRepr( pAig, 0 );
|
|
Aig_ManSeqCleanup( pNew );
|
|
// Aig_ManPrintStats( pAig );
|
|
// Aig_ManPrintStats( pNew );
|
|
Vec_VecFree( (Vec_Vec_t *)vResult );
|
|
pPars->nPartSize = nPartSize;
|
|
pPars->fVerbose = fVerbose;
|
|
if ( fVerbose )
|
|
{
|
|
ABC_PRT( "Total time", Abc_Clock() - clk );
|
|
}
|
|
return pNew;
|
|
}
|
|
void Gia_ManRestoreNodeMapping( Aig_Man_t * pAig, Gia_Man_t * pGia )
|
|
{
|
|
Aig_Obj_t * pObjAig; int i;
|
|
assert( Gia_ManObjNum(pGia) == Aig_ManObjNum(pAig) );
|
|
Aig_ManForEachObj( pAig, pObjAig, i )
|
|
pObjAig->iData = Abc_Var2Lit(i, 0);
|
|
}
|
|
Gia_Man_t * Gia_SignalCorrespondencePart( Gia_Man_t * p, Cec_ParCor_t * pPars )
|
|
{
|
|
Gia_Man_t * pRes = NULL;
|
|
Aig_Man_t * pNew = NULL;
|
|
Aig_Man_t * pAig = Gia_ManToAigSimple(p);
|
|
Ssw_Pars_t SswPars, * pSswPars = &SswPars;
|
|
assert( pPars->nProcs > 0 );
|
|
assert( pPars->nPartSize > 0 );
|
|
Ssw_ManSetDefaultParams( pSswPars );
|
|
pSswPars->nBTLimit = pPars->nBTLimit;
|
|
pSswPars->nProcs = pPars->nProcs;
|
|
pSswPars->nPartSize = pPars->nPartSize;
|
|
pSswPars->fVerbose = pPars->fVerbose;
|
|
pNew = Ssw_SignalCorrespondencePart2( pAig, pSswPars );
|
|
Gia_ManRestoreNodeMapping( pAig, p );
|
|
Gia_ManReprFromAigRepr2( pAig, p );
|
|
pRes = Gia_ManFromAigSimple(pNew);
|
|
Aig_ManStop( pNew );
|
|
Aig_ManStop( pAig );
|
|
return pRes;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|