blob: 598103de917913195cf39cb79bb60fea59c4f7fc [file] [log] [blame]
/**CFile****************************************************************
FileName [saigMiter.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Sequential AIG package.]
Synopsis [Computes sequential miter of two sequential AIGs.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: saigMiter.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "saig.h"
#include "proof/fra/fra.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Checks the status of the miter.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Sec_MtrStatus_t Sec_MiterStatus( Aig_Man_t * p )
{
Sec_MtrStatus_t Status;
Aig_Obj_t * pObj, * pChild;
int i;
memset( &Status, 0, sizeof(Sec_MtrStatus_t) );
Status.iOut = -1;
Status.nInputs = Saig_ManPiNum( p );
Status.nNodes = Aig_ManNodeNum( p );
Status.nOutputs = Saig_ManPoNum(p);
Saig_ManForEachPo( p, pObj, i )
{
pChild = Aig_ObjChild0(pObj);
// check if the output is constant 0
if ( pChild == Aig_ManConst0(p) )
Status.nUnsat++;
// check if the output is constant 1
else if ( pChild == Aig_ManConst1(p) )
{
Status.nSat++;
if ( Status.iOut == -1 )
Status.iOut = i;
}
// check if the output is a primary input
else if ( Saig_ObjIsPi(p, Aig_Regular(pChild)) )
{
Status.nSat++;
if ( Status.iOut == -1 )
Status.iOut = i;
}
// check if the output is 1 for the 0000 pattern
else if ( Aig_Regular(pChild)->fPhase != (unsigned)Aig_IsComplement(pChild) )
{
Status.nSat++;
if ( Status.iOut == -1 )
Status.iOut = i;
}
else
Status.nUndec++;
}
return Status;
}
/**Function*************************************************************
Synopsis [Creates sequential miter.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Saig_ManCreateMiter( Aig_Man_t * p0, Aig_Man_t * p1, int Oper )
{
Aig_Man_t * pNew;
Aig_Obj_t * pObj;
int i;
assert( Saig_ManRegNum(p0) > 0 || Saig_ManRegNum(p1) > 0 );
assert( Saig_ManPiNum(p0) == Saig_ManPiNum(p1) );
assert( Saig_ManPoNum(p0) == Saig_ManPoNum(p1) );
pNew = Aig_ManStart( Aig_ManObjNumMax(p0) + Aig_ManObjNumMax(p1) );
pNew->pName = Abc_UtilStrsav( "miter" );
Aig_ManCleanData( p0 );
Aig_ManCleanData( p1 );
// map constant nodes
Aig_ManConst1(p0)->pData = Aig_ManConst1(pNew);
Aig_ManConst1(p1)->pData = Aig_ManConst1(pNew);
// map primary inputs
Saig_ManForEachPi( p0, pObj, i )
pObj->pData = Aig_ObjCreateCi( pNew );
Saig_ManForEachPi( p1, pObj, i )
pObj->pData = Aig_ManCi( pNew, i );
// map register outputs
Saig_ManForEachLo( p0, pObj, i )
pObj->pData = Aig_ObjCreateCi( pNew );
Saig_ManForEachLo( p1, pObj, i )
pObj->pData = Aig_ObjCreateCi( pNew );
// map internal nodes
Aig_ManForEachNode( p0, pObj, i )
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
Aig_ManForEachNode( p1, pObj, i )
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
// create primary outputs
Saig_ManForEachPo( p0, pObj, i )
{
if ( Oper == 0 ) // XOR
pObj = Aig_Exor( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild0Copy(Aig_ManCo(p1,i)) );
else if ( Oper == 1 ) // implication is PO(p0) -> PO(p1) ... complement is PO(p0) & !PO(p1)
pObj = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_Not(Aig_ObjChild0Copy(Aig_ManCo(p1,i))) );
else
assert( 0 );
Aig_ObjCreateCo( pNew, pObj );
}
// create register inputs
Saig_ManForEachLi( p0, pObj, i )
pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
Saig_ManForEachLi( p1, pObj, i )
pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
// cleanup
Aig_ManSetRegNum( pNew, Saig_ManRegNum(p0) + Saig_ManRegNum(p1) );
// Aig_ManCleanup( pNew );
return pNew;
}
/**Function*************************************************************
Synopsis [Creates combinational miter.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Saig_ManCreateMiterComb( Aig_Man_t * p0, Aig_Man_t * p1, int Oper )
{
Aig_Man_t * pNew;
Aig_Obj_t * pObj;
int i;
assert( Aig_ManCiNum(p0) == Aig_ManCiNum(p1) );
assert( Aig_ManCoNum(p0) == Aig_ManCoNum(p1) );
pNew = Aig_ManStart( Aig_ManObjNumMax(p0) + Aig_ManObjNumMax(p1) );
pNew->pName = Abc_UtilStrsav( "miter" );
// map constant nodes
Aig_ManConst1(p0)->pData = Aig_ManConst1(pNew);
Aig_ManConst1(p1)->pData = Aig_ManConst1(pNew);
// map primary inputs and register outputs
Aig_ManForEachCi( p0, pObj, i )
pObj->pData = Aig_ObjCreateCi( pNew );
Aig_ManForEachCi( p1, pObj, i )
pObj->pData = Aig_ManCi( pNew, i );
// map internal nodes
Aig_ManForEachNode( p0, pObj, i )
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
Aig_ManForEachNode( p1, pObj, i )
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
// create primary outputs
Aig_ManForEachCo( p0, pObj, i )
{
if ( Oper == 0 ) // XOR
pObj = Aig_Exor( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild0Copy(Aig_ManCo(p1,i)) );
else if ( Oper == 1 ) // implication is PO(p0) -> PO(p1) ... complement is PO(p0) & !PO(p1)
pObj = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_Not(Aig_ObjChild0Copy(Aig_ManCo(p1,i))) );
else
assert( 0 );
Aig_ObjCreateCo( pNew, pObj );
}
// cleanup
Aig_ManSetRegNum( pNew, 0 );
Aig_ManCleanup( pNew );
return pNew;
}
/**Function*************************************************************
Synopsis [Derives dual-rail AIG.]
Description [Orders nodes as follows: PIs, ANDs, POs.]
SideEffects []
SeeAlso []
***********************************************************************/
void Saig_AndDualRail( Aig_Man_t * pNew, Aig_Obj_t * pObj, Aig_Obj_t ** ppData, Aig_Obj_t ** ppNext )
{
Aig_Obj_t * pFanin0 = Aig_ObjFanin0(pObj);
Aig_Obj_t * pFanin1 = Aig_ObjFanin1(pObj);
Aig_Obj_t * p0Data = Aig_ObjFaninC0(pObj)? pFanin0->pNext : (Aig_Obj_t *)pFanin0->pData;
Aig_Obj_t * p0Next = Aig_ObjFaninC0(pObj)? (Aig_Obj_t *)pFanin0->pData : pFanin0->pNext;
Aig_Obj_t * p1Data = Aig_ObjFaninC1(pObj)? pFanin1->pNext : (Aig_Obj_t *)pFanin1->pData;
Aig_Obj_t * p1Next = Aig_ObjFaninC1(pObj)? (Aig_Obj_t *)pFanin1->pData : pFanin1->pNext;
*ppData = Aig_Or( pNew,
Aig_And(pNew, p0Data, Aig_Not(p0Next)),
Aig_And(pNew, p1Data, Aig_Not(p1Next)) );
*ppNext = Aig_And( pNew,
Aig_And(pNew, Aig_Not(p0Data), p0Next),
Aig_And(pNew, Aig_Not(p1Data), p1Next) );
}
/**Function*************************************************************
Synopsis [Derives dual-rail AIG.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Saig_ManDualRail( Aig_Man_t * p, int fMiter )
{
Aig_Man_t * pNew;
Aig_Obj_t * pObj, * pMiter;
int i;
Aig_ManCleanData( p );
Aig_ManCleanNext( p );
// create the new manager
pNew = Aig_ManStart( 4*Aig_ManObjNumMax(p) );
pNew->pName = Abc_UtilStrsav( p->pName );
pNew->pSpec = Abc_UtilStrsav( p->pSpec );
// create the PIs
Aig_ManConst1(p)->pData = Aig_ManConst0(pNew);
Aig_ManConst1(p)->pNext = Aig_ManConst1(pNew);
Aig_ManForEachCi( p, pObj, i )
{
pObj->pData = Aig_ObjCreateCi( pNew );
pObj->pNext = Aig_ObjCreateCi( pNew );
}
// duplicate internal nodes
Aig_ManForEachNode( p, pObj, i )
Saig_AndDualRail( pNew, pObj, (Aig_Obj_t **)&pObj->pData, &pObj->pNext );
// add the POs
if ( fMiter )
{
pMiter = Aig_ManConst1(pNew);
Saig_ManForEachLo( p, pObj, i )
{
pMiter = Aig_And( pNew, pMiter,
Aig_Or(pNew, (Aig_Obj_t *)pObj->pData, pObj->pNext) );
}
Aig_ObjCreateCo( pNew, pMiter );
Saig_ManForEachLi( p, pObj, i )
{
if ( !Aig_ObjFaninC0(pObj) )
{
Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
Aig_ObjCreateCo( pNew, Aig_ObjFanin0(pObj)->pNext );
}
else
{
Aig_ObjCreateCo( pNew, Aig_ObjFanin0(pObj)->pNext );
Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
}
}
}
else
{
Aig_ManForEachCo( p, pObj, i )
{
if ( !Aig_ObjFaninC0(pObj) )
{
Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
Aig_ObjCreateCo( pNew, Aig_ObjFanin0(pObj)->pNext );
}
else
{
Aig_ObjCreateCo( pNew, Aig_ObjFanin0(pObj)->pNext );
Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
}
}
}
Aig_ManSetRegNum( pNew, 2*Aig_ManRegNum(p) );
Aig_ManCleanData( p );
Aig_ManCleanNext( p );
Aig_ManCleanup( pNew );
// check the resulting network
if ( !Aig_ManCheck(pNew) )
printf( "Aig_ManDupSimple(): The check has failed.\n" );
return pNew;
}
/**Function*************************************************************
Synopsis [Create combinational timeframes by unrolling sequential circuits.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Saig_ManUnrollTwo( Aig_Man_t * pBot, Aig_Man_t * pTop, int nFrames )
{
Aig_Man_t * p, * pAig;
Aig_Obj_t * pObj, * pObjLi, * pObjLo;
int i, f;
// assert( nFrames > 1 );
assert( Saig_ManPiNum(pBot) == Saig_ManPiNum(pTop) );
assert( Saig_ManPoNum(pBot) == Saig_ManPoNum(pTop) );
assert( Saig_ManRegNum(pBot) == Saig_ManRegNum(pTop) );
assert( Saig_ManRegNum(pBot) > 0 || Saig_ManRegNum(pTop) > 0 );
// start timeframes
p = Aig_ManStart( nFrames * Abc_MaxInt(Aig_ManObjNumMax(pBot), Aig_ManObjNumMax(pTop)) );
p->pName = Abc_UtilStrsav( "frames" );
// create variables for register outputs
pAig = pBot;
Saig_ManForEachLo( pAig, pObj, i )
pObj->pData = Aig_ObjCreateCi( p );
// add timeframes
for ( f = 0; f < nFrames; f++ )
{
// create PI nodes for this frame
Aig_ManConst1(pAig)->pData = Aig_ManConst1( p );
Saig_ManForEachPi( pAig, pObj, i )
pObj->pData = Aig_ObjCreateCi( p );
// add internal nodes of this frame
Aig_ManForEachNode( pAig, pObj, i )
pObj->pData = Aig_And( p, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
if ( f == nFrames - 1 )
{
// create POs for this frame
Aig_ManForEachCo( pAig, pObj, i )
Aig_ObjCreateCo( p, Aig_ObjChild0Copy(pObj) );
break;
}
// create POs for this frame
Saig_ManForEachPo( pAig, pObj, i )
Aig_ObjCreateCo( p, Aig_ObjChild0Copy(pObj) );
// save register inputs
Saig_ManForEachLi( pAig, pObj, i )
pObj->pData = Aig_ObjChild0Copy(pObj);
// transfer to register outputs
Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i )
pObjLo->pData = pObjLi->pData;
if ( f == 0 )
{
// transfer from pOld to pNew
Saig_ManForEachLo( pAig, pObj, i )
Saig_ManLo(pTop, i)->pData = pObj->pData;
pAig = pTop;
}
}
Aig_ManCleanup( p );
return p;
}
/**Function*************************************************************
Synopsis [Duplicates the AIG while creating POs from the set.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Aig_ManDupNodesAll( Aig_Man_t * p, Vec_Ptr_t * vSet )
{
Aig_Man_t * pNew, * pCopy;
Aig_Obj_t * pObj;
int i;
pNew = Aig_ManStart( Aig_ManObjNumMax(p) );
pNew->pName = Abc_UtilStrsav( p->pName );
Aig_ManConst1(p)->pData = Aig_ManConst1(pNew);
Aig_ManForEachCi( p, pObj, i )
pObj->pData = Aig_ObjCreateCi( pNew );
Aig_ManForEachNode( p, pObj, i )
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
// Saig_ManForEachPo( p, pObj, i )
// pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
Vec_PtrForEachEntry( Aig_Obj_t *, vSet, pObj, i )
Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)Aig_Regular(pObj)->pData, Aig_IsComplement(pObj)) );
Saig_ManForEachLi( p, pObj, i )
pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
Aig_ManSetRegNum( pNew, Saig_ManRegNum(p) );
// cleanup and return a copy
Aig_ManSeqCleanup( pNew );
pCopy = Aig_ManDupSimpleDfs( pNew );
Aig_ManStop( pNew );
return pCopy;
}
/**Function*************************************************************
Synopsis [Duplicates the AIG while creating POs from the set.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Aig_ManDupNodesHalf( Aig_Man_t * p, Vec_Ptr_t * vSet, int iPart )
{
Aig_Man_t * pNew, * pCopy;
Aig_Obj_t * pObj;
int i;
Aig_ManCleanData( p );
pNew = Aig_ManStart( Aig_ManObjNumMax(p) );
pNew->pName = Abc_UtilStrsav( p->pName );
Aig_ManConst1(p)->pData = Aig_ManConst1(pNew);
Saig_ManForEachPi( p, pObj, i )
pObj->pData = Aig_ObjCreateCi( pNew );
if ( iPart == 0 )
{
Saig_ManForEachLo( p, pObj, i )
if ( i < Saig_ManRegNum(p)/2 )
pObj->pData = Aig_ObjCreateCi( pNew );
}
else
{
Saig_ManForEachLo( p, pObj, i )
if ( i >= Saig_ManRegNum(p)/2 )
pObj->pData = Aig_ObjCreateCi( pNew );
}
Aig_ManForEachNode( p, pObj, i )
if ( Aig_ObjFanin0(pObj)->pData && Aig_ObjFanin1(pObj)->pData )
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
// Saig_ManForEachPo( p, pObj, i )
// pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
Vec_PtrForEachEntry( Aig_Obj_t *, vSet, pObj, i )
{
assert( Aig_Regular(pObj)->pData != NULL );
Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)Aig_Regular(pObj)->pData, Aig_IsComplement(pObj)) );
}
if ( iPart == 0 )
{
Saig_ManForEachLi( p, pObj, i )
if ( i < Saig_ManRegNum(p)/2 )
pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
}
else
{
Saig_ManForEachLi( p, pObj, i )
if ( i >= Saig_ManRegNum(p)/2 )
pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
}
Aig_ManSetRegNum( pNew, Saig_ManRegNum(p)/2 );
// cleanup and return a copy
// Aig_ManSeqCleanup( pNew );
Aig_ManCleanup( pNew );
pCopy = Aig_ManDupSimpleDfs( pNew );
Aig_ManStop( pNew );
return pCopy;
}
/**Function*************************************************************
Synopsis [Duplicates the AIG to have constant-0 initial state.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Saig_ManDemiterSimple( Aig_Man_t * p, Aig_Man_t ** ppAig0, Aig_Man_t ** ppAig1 )
{
Vec_Ptr_t * vSet0, * vSet1;
Aig_Obj_t * pObj, * pFanin, * pObj0, * pObj1;
int i, Counter = 0;
assert( Saig_ManRegNum(p) % 2 == 0 );
vSet0 = Vec_PtrAlloc( Saig_ManPoNum(p) );
vSet1 = Vec_PtrAlloc( Saig_ManPoNum(p) );
Saig_ManForEachPo( p, pObj, i )
{
pFanin = Aig_ObjFanin0(pObj);
if ( Aig_ObjIsConst1( pFanin ) )
{
if ( !Aig_ObjFaninC0(pObj) )
printf( "The output number %d of the miter is constant 1.\n", i );
Counter++;
continue;
}
if ( !Aig_ObjIsNode(pFanin) || !Aig_ObjRecognizeExor( pFanin, &pObj0, &pObj1 ) )
{
printf( "The miter cannot be demitered.\n" );
Vec_PtrFree( vSet0 );
Vec_PtrFree( vSet1 );
return 0;
}
if ( Aig_ObjFaninC0(pObj) )
pObj0 = Aig_Not(pObj0);
// printf( "%d %d ", Aig_Regular(pObj0)->Id, Aig_Regular(pObj1)->Id );
if ( Aig_Regular(pObj0)->Id < Aig_Regular(pObj1)->Id )
{
Vec_PtrPush( vSet0, pObj0 );
Vec_PtrPush( vSet1, pObj1 );
}
else
{
Vec_PtrPush( vSet0, pObj1 );
Vec_PtrPush( vSet1, pObj0 );
}
}
// printf( "Miter has %d constant outputs.\n", Counter );
// printf( "\n" );
if ( ppAig0 )
{
*ppAig0 = Aig_ManDupNodesHalf( p, vSet0, 0 );
ABC_FREE( (*ppAig0)->pName );
(*ppAig0)->pName = Abc_UtilStrsav( "part0" );
}
if ( ppAig1 )
{
*ppAig1 = Aig_ManDupNodesHalf( p, vSet1, 1 );
ABC_FREE( (*ppAig1)->pName );
(*ppAig1)->pName = Abc_UtilStrsav( "part1" );
}
Vec_PtrFree( vSet0 );
Vec_PtrFree( vSet1 );
return 1;
}
/**Function*************************************************************
Synopsis [Returns 1 if PO can be demitered.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Saig_ManDemiterMarkPos( Aig_Man_t * p )
{
Aig_Obj_t * pObj;
int i;
Aig_ManCleanMarkAB( p );
Saig_ManForEachLo( p, pObj, i )
if ( i < Saig_ManRegNum(p)/2 )
pObj->fMarkA = 1;
else
pObj->fMarkB = 1;
Aig_ManForEachNode( p, pObj, i )
{
pObj->fMarkA = Aig_ObjFanin0(pObj)->fMarkA | Aig_ObjFanin1(pObj)->fMarkA;
pObj->fMarkB = Aig_ObjFanin0(pObj)->fMarkB | Aig_ObjFanin1(pObj)->fMarkB;
}
}
/**Function*************************************************************
Synopsis [Returns 1 if PO can be demitered.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Saig_ManDemiterCheckPo( Aig_Man_t * p, Aig_Obj_t * pObj, Aig_Obj_t ** ppPo0, Aig_Obj_t ** ppPo1 )
{
Aig_Obj_t * pFanin, * pObj0, * pObj1, * pObjR0, * pObjR1;
assert( Saig_ObjIsPo(p, pObj) );
pFanin = Aig_ObjFanin0( pObj );
if ( Aig_ObjIsConst1(pFanin) )
{
if ( !Aig_ObjFaninC0(pObj) )
return 0;
*ppPo0 = Aig_ManConst0(p);
*ppPo1 = Aig_ManConst0(p);
return 1;
}
if ( !Aig_ObjIsNode(pFanin) )
return 0;
if ( !Aig_ObjRecognizeExor( pFanin, &pObj0, &pObj1 ) )
return 0;
if ( Aig_ObjFaninC0(pObj) )
pObj0 = Aig_Not(pObj0);
// make sure they can reach only one
pObjR0 = Aig_Regular(pObj0);
pObjR1 = Aig_Regular(pObj1);
if ( (pObjR0->fMarkA && pObjR0->fMarkB) || (pObjR1->fMarkA && pObjR1->fMarkB) ||
(pObjR0->fMarkA && pObjR1->fMarkA) || (pObjR0->fMarkB && pObjR1->fMarkB) )
return 0;
if ( pObjR1->fMarkA && !pObjR0->fMarkA )
{
*ppPo0 = pObj1;
*ppPo1 = pObj0;
}
else if ( pObjR0->fMarkA && !pObjR1->fMarkA )
{
*ppPo0 = pObj0;
*ppPo1 = pObj1;
}
else
{
/*
printf( "%d", pObjR0->fMarkA );
printf( "%d", pObjR0->fMarkB );
printf( ":" );
printf( "%d", pObjR1->fMarkA );
printf( "%d", pObjR1->fMarkB );
printf( " " );
*/
if ( Aig_Regular(pObj0)->Id < Aig_Regular(pObj1)->Id )
{
*ppPo0 = pObj0;
*ppPo1 = pObj1;
}
else
{
*ppPo0 = pObj1;
*ppPo1 = pObj0;
}
}
return 1;
}
/**Function*************************************************************
Synopsis [Returns 1 if AIG can be demitered.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Saig_ManDemiterSimpleDiff( Aig_Man_t * p, Aig_Man_t ** ppAig0, Aig_Man_t ** ppAig1 )
{
Vec_Ptr_t * vSet0, * vSet1;
Aig_Obj_t * pObj, * pObj0, * pObj1;
int i;
if ( Aig_ManRegNum(p) == 0 || (Aig_ManRegNum(p) & 1) )
return 0;
Saig_ManDemiterMarkPos( p );
vSet0 = Vec_PtrAlloc( Saig_ManPoNum(p) );
vSet1 = Vec_PtrAlloc( Saig_ManPoNum(p) );
Saig_ManForEachPo( p, pObj, i )
{
if ( !Saig_ManDemiterCheckPo( p, pObj, &pObj0, &pObj1 ) )
{
Vec_PtrFree( vSet0 );
Vec_PtrFree( vSet1 );
Aig_ManCleanMarkAB( p );
return 0;
}
Vec_PtrPush( vSet0, pObj0 );
Vec_PtrPush( vSet1, pObj1 );
}
// create new AIG
*ppAig0 = Aig_ManDupNodesHalf( p, vSet0, 0 );
ABC_FREE( (*ppAig0)->pName );
(*ppAig0)->pName = Abc_UtilStrsav( "part0" );
// create new AIGs
*ppAig1 = Aig_ManDupNodesHalf( p, vSet1, 1 );
ABC_FREE( (*ppAig1)->pName );
(*ppAig1)->pName = Abc_UtilStrsav( "part1" );
// cleanup
Vec_PtrFree( vSet0 );
Vec_PtrFree( vSet1 );
Aig_ManCleanMarkAB( p );
return 1;
}
/**Function*************************************************************
Synopsis [Returns 1 if AIG can be demitered.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Saig_ManDemiterDual( Aig_Man_t * p, Aig_Man_t ** ppAig0, Aig_Man_t ** ppAig1 )
{
Aig_Man_t * pTemp;
Aig_Obj_t * pObj;
int i, k;
if ( p->pFanData )
Aig_ManFanoutStop( p );
k = 0;
pTemp = Aig_ManDupSimple( p );
Saig_ManForEachPo( pTemp, pObj, i )
{
if ( i & 1 )
Aig_ObjDeletePo( pTemp, pObj );
else
Vec_PtrWriteEntry( pTemp->vCos, k++, pObj );
}
Saig_ManForEachLi( pTemp, pObj, i )
Vec_PtrWriteEntry( pTemp->vCos, k++, pObj );
Vec_PtrShrink( pTemp->vCos, k );
pTemp->nTruePos = k - Saig_ManRegNum(pTemp);
Aig_ManSeqCleanup( pTemp );
*ppAig0 = Aig_ManDupSimple( pTemp );
Aig_ManStop( pTemp );
k = 0;
pTemp = Aig_ManDupSimple( p );
Saig_ManForEachPo( pTemp, pObj, i )
{
if ( i & 1 )
Vec_PtrWriteEntry( pTemp->vCos, k++, pObj );
else
Aig_ObjDeletePo( pTemp, pObj );
}
Saig_ManForEachLi( pTemp, pObj, i )
Vec_PtrWriteEntry( pTemp->vCos, k++, pObj );
Vec_PtrShrink( pTemp->vCos, k );
pTemp->nTruePos = k - Saig_ManRegNum(pTemp);
Aig_ManSeqCleanup( pTemp );
*ppAig1 = Aig_ManDupSimple( pTemp );
Aig_ManStop( pTemp );
return 1;
}
/**Function*************************************************************
Synopsis [Duplicates the AIG to have constant-0 initial state.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Saig_ManDemiterSimpleDiff_old( Aig_Man_t * p, Aig_Man_t ** ppAig0, Aig_Man_t ** ppAig1 )
{
Vec_Ptr_t * vSet0, * vSet1;
Aig_Obj_t * pObj, * pFanin, * pObj0, * pObj1;
int i, Counter = 0;
// assert( Saig_ManRegNum(p) % 2 == 0 );
vSet0 = Vec_PtrAlloc( Saig_ManPoNum(p) );
vSet1 = Vec_PtrAlloc( Saig_ManPoNum(p) );
Saig_ManForEachPo( p, pObj, i )
{
pFanin = Aig_ObjFanin0(pObj);
if ( Aig_ObjIsConst1( pFanin ) )
{
if ( !Aig_ObjFaninC0(pObj) )
printf( "The output number %d of the miter is constant 1.\n", i );
Counter++;
continue;
}
if ( !Aig_ObjIsNode(pFanin) || !Aig_ObjRecognizeExor( pFanin, &pObj0, &pObj1 ) )
{
/*
printf( "The miter cannot be demitered.\n" );
Vec_PtrFree( vSet0 );
Vec_PtrFree( vSet1 );
return 0;
*/
printf( "The output number %d cannot be demitered.\n", i );
continue;
}
if ( Aig_ObjFaninC0(pObj) )
pObj0 = Aig_Not(pObj0);
// printf( "%d %d ", Aig_Regular(pObj0)->Id, Aig_Regular(pObj1)->Id );
if ( Aig_Regular(pObj0)->Id < Aig_Regular(pObj1)->Id )
{
Vec_PtrPush( vSet0, pObj0 );
Vec_PtrPush( vSet1, pObj1 );
}
else
{
Vec_PtrPush( vSet0, pObj1 );
Vec_PtrPush( vSet1, pObj0 );
}
}
// printf( "Miter has %d constant outputs.\n", Counter );
// printf( "\n" );
if ( ppAig0 )
{
*ppAig0 = Aig_ManDupNodesAll( p, vSet0 );
ABC_FREE( (*ppAig0)->pName );
(*ppAig0)->pName = Abc_UtilStrsav( "part0" );
}
if ( ppAig1 )
{
*ppAig1 = Aig_ManDupNodesAll( p, vSet1 );
ABC_FREE( (*ppAig1)->pName );
(*ppAig1)->pName = Abc_UtilStrsav( "part1" );
}
Vec_PtrFree( vSet0 );
Vec_PtrFree( vSet1 );
return 1;
}
/**Function*************************************************************
Synopsis [Labels logic reachable from the node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Saig_ManDemiterLabel_rec( Aig_Man_t * p, Aig_Obj_t * pObj, int Value )
{
if ( Aig_ObjIsTravIdCurrent(p, pObj) )
return;
Aig_ObjSetTravIdCurrent(p, pObj);
if ( Value )
pObj->fMarkB = 1;
else
pObj->fMarkA = 1;
if ( Saig_ObjIsPi(p, pObj) )
return;
if ( Saig_ObjIsLo(p, pObj) )
{
Saig_ManDemiterLabel_rec( p, Aig_ObjFanin0( Saig_ObjLoToLi(p, pObj) ), Value );
return;
}
assert( Aig_ObjIsNode(pObj) );
Saig_ManDemiterLabel_rec( p, Aig_ObjFanin0(pObj), Value );
Saig_ManDemiterLabel_rec( p, Aig_ObjFanin1(pObj), Value );
}
/**Function*************************************************************
Synopsis [Returns the first labeled register encountered during traversal.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Obj_t * Saig_ManGetLabeledRegister_rec( Aig_Man_t * p, Aig_Obj_t * pObj )
{
Aig_Obj_t * pResult;
if ( Aig_ObjIsTravIdCurrent(p, pObj) )
return NULL;
Aig_ObjSetTravIdCurrent(p, pObj);
if ( Saig_ObjIsPi(p, pObj) )
return NULL;
if ( Saig_ObjIsLo(p, pObj) )
{
if ( pObj->fMarkA || pObj->fMarkB )
return pObj;
return Saig_ManGetLabeledRegister_rec( p, Aig_ObjFanin0( Saig_ObjLoToLi(p, pObj) ) );
}
assert( Aig_ObjIsNode(pObj) );
pResult = Saig_ManGetLabeledRegister_rec( p, Aig_ObjFanin0(pObj) );
if ( pResult )
return pResult;
return Saig_ManGetLabeledRegister_rec( p, Aig_ObjFanin1(pObj) );
}
/**Function*************************************************************
Synopsis [Duplicates the AIG to have constant-0 initial state.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Saig_ManDemiter( Aig_Man_t * p, Aig_Man_t ** ppAig0, Aig_Man_t ** ppAig1 )
{
Vec_Ptr_t * vPairs, * vSet0, * vSet1;
Aig_Obj_t * pObj, * pObj0, * pObj1, * pFlop0, * pFlop1;
int i, Counter;
assert( Saig_ManRegNum(p) > 0 );
Aig_ManSetCioIds( p );
// check if demitering is possible
vPairs = Vec_PtrAlloc( 2 * Saig_ManPoNum(p) );
Saig_ManForEachPo( p, pObj, i )
{
if ( !Aig_ObjRecognizeExor( Aig_ObjFanin0(pObj), &pObj0, &pObj1 ) )
{
Vec_PtrFree( vPairs );
return 0;
}
Vec_PtrPush( vPairs, pObj0 );
Vec_PtrPush( vPairs, pObj1 );
}
// start array of outputs
vSet0 = Vec_PtrAlloc( Saig_ManPoNum(p) );
vSet1 = Vec_PtrAlloc( Saig_ManPoNum(p) );
// get the first pair of outputs
pObj0 = (Aig_Obj_t *)Vec_PtrEntry( vPairs, 0 );
pObj1 = (Aig_Obj_t *)Vec_PtrEntry( vPairs, 1 );
// label registers reachable from the outputs
Aig_ManIncrementTravId( p );
Saig_ManDemiterLabel_rec( p, Aig_Regular(pObj0), 0 );
Vec_PtrPush( vSet0, pObj0 );
Aig_ManIncrementTravId( p );
Saig_ManDemiterLabel_rec( p, Aig_Regular(pObj1), 1 );
Vec_PtrPush( vSet1, pObj1 );
// find where each output belongs
for ( i = 2; i < Vec_PtrSize(vPairs); i += 2 )
{
pObj0 = (Aig_Obj_t *)Vec_PtrEntry( vPairs, i );
pObj1 = (Aig_Obj_t *)Vec_PtrEntry( vPairs, i+1 );
Aig_ManIncrementTravId( p );
pFlop0 = Saig_ManGetLabeledRegister_rec( p, Aig_Regular(pObj0) );
Aig_ManIncrementTravId( p );
pFlop1 = Saig_ManGetLabeledRegister_rec( p, Aig_Regular(pObj1) );
if ( (pFlop0->fMarkA && pFlop0->fMarkB) || (pFlop1->fMarkA && pFlop1->fMarkB) ||
(pFlop0->fMarkA && pFlop1->fMarkA) || (pFlop0->fMarkB && pFlop1->fMarkB) )
printf( "Ouput pair %4d: Difficult case...\n", i/2 );
if ( pFlop0->fMarkB )
{
Saig_ManDemiterLabel_rec( p, pObj0, 1 );
Vec_PtrPush( vSet0, pObj0 );
}
else // if ( pFlop0->fMarkA ) or none
{
Saig_ManDemiterLabel_rec( p, pObj0, 0 );
Vec_PtrPush( vSet1, pObj0 );
}
if ( pFlop1->fMarkB )
{
Saig_ManDemiterLabel_rec( p, pObj1, 1 );
Vec_PtrPush( vSet0, pObj1 );
}
else // if ( pFlop1->fMarkA ) or none
{
Saig_ManDemiterLabel_rec( p, pObj1, 0 );
Vec_PtrPush( vSet1, pObj1 );
}
}
// check if there are any flops in common
Counter = 0;
Saig_ManForEachLo( p, pObj, i )
if ( pObj->fMarkA && pObj->fMarkB )
Counter++;
if ( Counter > 0 )
printf( "The miters contains %d flops reachable from both AIGs.\n", Counter );
// produce two miters
if ( ppAig0 )
{
assert( 0 );
*ppAig0 = Aig_ManDupNodesHalf( p, vSet0, 0 ); // not ready
ABC_FREE( (*ppAig0)->pName );
(*ppAig0)->pName = Abc_UtilStrsav( "part0" );
}
if ( ppAig1 )
{
assert( 0 );
*ppAig1 = Aig_ManDupNodesHalf( p, vSet1, 1 ); // not ready
ABC_FREE( (*ppAig1)->pName );
(*ppAig1)->pName = Abc_UtilStrsav( "part1" );
}
Vec_PtrFree( vSet0 );
Vec_PtrFree( vSet1 );
Vec_PtrFree( vPairs );
return 1;
}
/**Function*************************************************************
Synopsis [Create specialized miter by unrolling two circuits.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Saig_ManCreateMiterTwo( Aig_Man_t * pOld, Aig_Man_t * pNew, int nFrames )
{
Aig_Man_t * pFrames0, * pFrames1, * pMiter;
// assert( Aig_ManNodeNum(pOld) <= Aig_ManNodeNum(pNew) );
pFrames0 = Saig_ManUnrollTwo( pOld, pOld, nFrames );
pFrames1 = Saig_ManUnrollTwo( pNew, pOld, nFrames );
pMiter = Saig_ManCreateMiterComb( pFrames0, pFrames1, 0 );
Aig_ManStop( pFrames0 );
Aig_ManStop( pFrames1 );
return pMiter;
}
/**Function*************************************************************
Synopsis [Resimulates counter-example and returns the failed output number.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ssw_SecCexResimulate( Aig_Man_t * p, int * pModel, int * pnOutputs )
{
Aig_Obj_t * pObj;
int i, RetValue = -1;
*pnOutputs = 0;
Aig_ManConst1(p)->fMarkA = 1;
Aig_ManForEachCi( p, pObj, i )
pObj->fMarkA = pModel[i];
Aig_ManForEachNode( p, pObj, i )
pObj->fMarkA = ( Aig_ObjFanin0(pObj)->fMarkA ^ Aig_ObjFaninC0(pObj) ) &
( Aig_ObjFanin1(pObj)->fMarkA ^ Aig_ObjFaninC1(pObj) );
Aig_ManForEachCo( p, pObj, i )
pObj->fMarkA = Aig_ObjFanin0(pObj)->fMarkA ^ Aig_ObjFaninC0(pObj);
Aig_ManForEachCo( p, pObj, i )
if ( pObj->fMarkA )
{
if ( RetValue == -1 )
RetValue = i;
(*pnOutputs)++;
}
Aig_ManCleanMarkA(p);
return RetValue;
}
/**Function*************************************************************
Synopsis [Reduces SEC to CEC for the special case of seq synthesis.]
Description [The first circuit (pPart0) should be circuit before synthesis.
The second circuit (pPart1) should be circuit after synthesis.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ssw_SecSpecial( Aig_Man_t * pPart0, Aig_Man_t * pPart1, int nFrames, int fVerbose )
{
// extern int Fra_FraigCec( Aig_Man_t ** ppAig, int nConfLimit, int fVerbose );
int iOut, nOuts;
Aig_Man_t * pMiterCec;
int RetValue;
abctime clkTotal = Abc_Clock();
if ( fVerbose )
{
Aig_ManPrintStats( pPart0 );
Aig_ManPrintStats( pPart1 );
}
// Aig_ManDumpBlif( pPart0, "file0.blif", NULL, NULL );
// Aig_ManDumpBlif( pPart1, "file1.blif", NULL, NULL );
// assert( Aig_ManNodeNum(pPart0) <= Aig_ManNodeNum(pPart1) );
/*
if ( Aig_ManNodeNum(pPart0) >= Aig_ManNodeNum(pPart1) )
{
printf( "Warning: The design after synthesis is smaller!\n" );
printf( "This warning may indicate that the order of designs is changed.\n" );
printf( "The solver expects the original design as first argument and\n" );
printf( "the modified design as the second argument in \"absec\".\n" );
}
*/
// create two-level miter
pMiterCec = Saig_ManCreateMiterTwo( pPart0, pPart1, nFrames );
if ( fVerbose )
{
Aig_ManPrintStats( pMiterCec );
// Aig_ManDumpBlif( pMiterCec, "miter01.blif", NULL, NULL );
// printf( "The new miter is written into file \"%s\".\n", "miter01.blif" );
}
// run CEC on this miter
RetValue = Fra_FraigCec( &pMiterCec, 100000, fVerbose );
// transfer model if given
// if ( pNtk2 == NULL )
// pNtk1->pModel = pMiterCec->pData, pMiterCec->pData = NULL;
// report the miter
if ( RetValue == 1 )
{
printf( "Networks are equivalent. " );
ABC_PRT( "Time", Abc_Clock() - clkTotal );
}
else if ( RetValue == 0 )
{
printf( "Networks are NOT EQUIVALENT. " );
ABC_PRT( "Time", Abc_Clock() - clkTotal );
if ( pMiterCec->pData == NULL )
printf( "Counter-example is not available.\n" );
else
{
iOut = Ssw_SecCexResimulate( pMiterCec, (int *)pMiterCec->pData, &nOuts );
if ( iOut == -1 )
printf( "Counter-example verification has failed.\n" );
else
{
if ( iOut < Saig_ManPoNum(pPart0) * nFrames )
printf( "Primary output %d has failed in frame %d.\n",
iOut%Saig_ManPoNum(pPart0), iOut/Saig_ManPoNum(pPart0) );
else
printf( "Flop input %d has failed in the last frame.\n",
iOut - Saig_ManPoNum(pPart0) * nFrames );
printf( "The counter-example detected %d incorrect POs or flop inputs.\n", nOuts );
}
}
}
else
{
printf( "Networks are UNDECIDED. " );
ABC_PRT( "Time", Abc_Clock() - clkTotal );
}
fflush( stdout );
Aig_ManStop( pMiterCec );
return RetValue;
}
/**Function*************************************************************
Synopsis [Reduces SEC to CEC for the special case of seq synthesis.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ssw_SecSpecialMiter( Aig_Man_t * p0, Aig_Man_t * p1, int nFrames, int fVerbose )
{
Aig_Man_t * pPart0, * pPart1;
int RetValue;
if ( fVerbose )
printf( "Performing sequential verification using combinational A/B miter.\n" );
// consider the case when a miter is given
if ( p1 == NULL )
{
if ( fVerbose )
{
Aig_ManPrintStats( p0 );
}
// demiter the miter
if ( !Saig_ManDemiterSimpleDiff( p0, &pPart0, &pPart1 ) )
{
printf( "Demitering has failed.\n" );
return -1;
}
if ( Aig_ManRegNum(pPart0) != Aig_ManRegNum(pPart1) )
{
Aig_ManStop( pPart0 );
Aig_ManStop( pPart1 );
printf( "After demitering AIGs have different number of flops. Quitting.\n" );
return -1;
}
}
else
{
pPart0 = Aig_ManDupSimple( p0 );
pPart1 = Aig_ManDupSimple( p1 );
}
if ( fVerbose )
{
// Aig_ManPrintStats( pPart0 );
// Aig_ManPrintStats( pPart1 );
if ( p1 == NULL )
{
// Aig_ManDumpBlif( pPart0, "part0.blif", NULL, NULL );
// Aig_ManDumpBlif( pPart1, "part1.blif", NULL, NULL );
// printf( "The result of demitering is written into files \"%s\" and \"%s\".\n", "part0.blif", "part1.blif" );
}
}
assert( Aig_ManRegNum(pPart0) > 0 );
assert( Aig_ManRegNum(pPart1) > 0 );
assert( Saig_ManPiNum(pPart0) == Saig_ManPiNum(pPart1) );
assert( Saig_ManPoNum(pPart0) == Saig_ManPoNum(pPart1) );
assert( Aig_ManRegNum(pPart0) == Aig_ManRegNum(pPart1) );
RetValue = Ssw_SecSpecial( pPart0, pPart1, nFrames, fVerbose );
if ( RetValue != 1 && Aig_ManNodeNum(pPart0) >= Aig_ManNodeNum(pPart1) )
RetValue = Ssw_SecSpecial( pPart1, pPart0, nFrames, fVerbose );
Aig_ManStop( pPart0 );
Aig_ManStop( pPart1 );
return RetValue;
}
/**Function*************************************************************
Synopsis [Performs demitering of the network.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Saig_ManDemiterNew( Aig_Man_t * pMan )
{
Vec_Ptr_t * vSuper, * vSupp0, * vSupp1;
Aig_Obj_t * pObj, * pTemp, * pFan0, * pFan1;
int i, k;
vSuper = Vec_PtrAlloc( 100 );
Saig_ManForEachPo( pMan, pObj, i )
{
if ( pMan->nConstrs && i >= Saig_ManPoNum(pMan) - pMan->nConstrs )
break;
printf( "Output %3d : ", i );
if ( Aig_ObjIsConst1(Aig_ObjFanin0(pObj)) )
{
if ( !Aig_ObjFaninC0(pObj) )
printf( "Const1\n" );
else
printf( "Const0\n" );
continue;
}
if ( !Aig_ObjIsNode(Aig_ObjFanin0(pObj)) )
{
printf( "Terminal\n" );
continue;
}
// check AND
if ( !Aig_ObjFaninC0(pObj) )
{
printf( "AND " );
if ( Aig_ObjRecognizeExor(Aig_ObjFanin0(pObj), &pFan0, &pFan1) )
printf( " Yes" );
else
printf( " No" );
printf( "\n" );
continue;
}
// check OR
Aig_ObjCollectSuper( Aig_ObjFanin0(pObj), vSuper );
printf( "OR with %d inputs ", Vec_PtrSize(vSuper) );
if ( Vec_PtrSize(vSuper) == 2 )
{
if ( Aig_ObjRecognizeExor(Aig_ObjFanin0(pObj), &pFan0, &pFan1) )
{
printf( " Yes" );
printf( "\n" );
vSupp0 = Aig_Support( pMan, Aig_Regular(pFan0) );
Vec_PtrForEachEntry( Aig_Obj_t *, vSupp0, pTemp, k )
if ( Saig_ObjIsLo(pMan, pTemp) )
printf( " %d", Aig_ObjCioId(pTemp) );
printf( "\n" );
Vec_PtrFree( vSupp0 );
vSupp1 = Aig_Support( pMan, Aig_Regular(pFan1) );
Vec_PtrForEachEntry( Aig_Obj_t *, vSupp1, pTemp, k )
if ( Saig_ObjIsLo(pMan, pTemp) )
printf( " %d", Aig_ObjCioId(pTemp) );
printf( "\n" );
Vec_PtrFree( vSupp1 );
}
else
printf( " No" );
printf( "\n" );
continue;
}
/*
Vec_PtrForEachEntry( Aig_Obj_t *, vSuper, pTemp, k )
if ( Aig_ObjRecognizeExor(Aig_Regular(pTemp), &pFan0, &pFan1) )
{
printf( " Yes" );
if ( Aig_IsComplement(pTemp) )
pFan0 = Aig_Not(pFan0);
}
else
printf( " No" );
*/
printf( "\n" );
}
Vec_PtrFree( vSuper );
return 1;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END