blob: 1c4d31df878041c339d603c63d7929eec13e70c3 [file] [log] [blame]
/**CFile****************************************************************
FileName [liveness.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Liveness property checking.]
Synopsis [Main implementation module.]
Author [Sayak Ray]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - January 1, 2009.]
Revision [$Id: liveness.c,v 1.00 2009/01/01 00:00:00 alanmi Exp $]
***********************************************************************/
#include <stdio.h>
#include "base/main/main.h"
#include "aig/aig/aig.h"
#include "aig/saig/saig.h"
#include <string.h>
#include "base/main/mainInt.h"
ABC_NAMESPACE_IMPL_START
#define PROPAGATE_NAMES
#define MULTIPLE_LTL_FORMULA
#define ALLOW_SAFETY_PROPERTIES
#define FULL_BIERE_MODE 0
#define IGNORE_LIVENESS_KEEP_SAFETY_MODE 1
#define IGNORE_SAFETY_KEEP_LIVENESS_MODE 2
#define IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE 3
#define FULL_BIERE_ONE_LOOP_MODE 4
//#define DUPLICATE_CKT_DEBUG
extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters );
extern Abc_Ntk_t * Abc_NtkFromAigPhase( Aig_Man_t * pMan );
//char *strdup(const char *string);
//******************************************
//external functions defined in ltl_parser.c
//******************************************
typedef struct ltlNode_t ltlNode;
extern ltlNode *readLtlFormula( char *formula );
extern void traverseAbstractSyntaxTree( ltlNode *node );
extern ltlNode *parseFormulaCreateAST( char *inputFormula );
extern int isWellFormed( ltlNode *topNode );
extern int checkSignalNameExistence( Abc_Ntk_t *pNtk, ltlNode *topASTNode );
extern void populateBoolWithAigNodePtr( Abc_Ntk_t *pNtk, Aig_Man_t *pAigOld, Aig_Man_t *pAigNew, ltlNode *topASTNode );
extern int checkAllBoolHaveAIGPointer( ltlNode *topASTNode );
extern void populateAigPointerUnitGF( Aig_Man_t *pAigNew, ltlNode *topASTNode, Vec_Ptr_t *vSignal, Vec_Vec_t *vAigGFMap );
extern void setAIGNodePtrOfGloballyNode( ltlNode *astNode, Aig_Obj_t *pObjLo );
extern Aig_Obj_t *buildLogicFromLTLNode( Aig_Man_t *pAig, ltlNode *pLtlNode );
extern Aig_Obj_t *retriveAIGPointerFromLTLNode( ltlNode *astNode );
extern void traverseAbstractSyntaxTree_postFix( ltlNode *node );
//**********************************
//external function declaration ends
//**********************************
/*******************************************************************
LAYOUT OF PI VECTOR:
+------------------------------------------------------------------------------------------------------------------------------------+
| TRUE ORIGINAL PI (n) | SAVE(PI) (1) | ORIGINAL LO (k) | SAVED(LO) (1) | SHADOW_ORIGINAL LO (k) | LIVENESS LO (l) | FAIRNESS LO (f) |
+------------------------------------------------------------------------------------------------------------------------------------+
<------------True PI----------------->|<----------------------------LO--------------------------------------------------------------->
LAYOUT OF PO VECTOR:
+-----------------------------------------------------------------------------------------------------------+
| SOLE PO (1) | ORIGINAL LI (k) | SAVED LI (1) | SHADOW_ORIGINAL LI (k) | LIVENESS LI (l) | FAIRNESS LI (f) |
+-----------------------------------------------------------------------------------------------------------+
<--True PO--->|<--------------------------------------LI---------------------------------------------------->
********************************************************************/
static int nodeName_starts_with( Abc_Obj_t *pNode, const char *prefix )
{
if( strstr( Abc_ObjName( pNode ), prefix ) == Abc_ObjName( pNode ) )
return 1;
else
return 0;
}
void printVecPtrOfString( Vec_Ptr_t *vec )
{
int i;
for( i=0; i< Vec_PtrSize( vec ); i++ )
{
printf("vec[%d] = %s\n", i, (char *)Vec_PtrEntry(vec, i) );
}
}
int getPoIndex( Aig_Man_t *pAig, Aig_Obj_t *pPivot )
{
int i;
Aig_Obj_t *pObj;
Saig_ManForEachPo( pAig, pObj, i )
{
if( pObj == pPivot )
return i;
}
return -1;
}
char * retrieveTruePiName( Abc_Ntk_t *pNtkOld, Aig_Man_t *pAigOld, Aig_Man_t *pAigNew, Aig_Obj_t *pObjPivot )
{
Aig_Obj_t *pObjOld, *pObj;
Abc_Obj_t *pNode;
int index;
assert( Saig_ObjIsPi( pAigNew, pObjPivot ) );
Aig_ManForEachCi( pAigNew, pObj, index )
if( pObj == pObjPivot )
break;
assert( index < Aig_ManCiNum( pAigNew ) - Aig_ManRegNum( pAigNew ) );
if( index == Saig_ManPiNum( pAigNew ) - 1 )
return "SAVE_BIERE";
else
{
pObjOld = Aig_ManCi( pAigOld, index );
pNode = Abc_NtkPi( pNtkOld, index );
assert( pObjOld->pData == pObjPivot );
return Abc_ObjName( pNode );
}
}
char * retrieveLOName( Abc_Ntk_t *pNtkOld, Aig_Man_t *pAigOld, Aig_Man_t *pAigNew, Aig_Obj_t *pObjPivot, Vec_Ptr_t *vLive, Vec_Ptr_t * vFair )
{
Aig_Obj_t *pObjOld, *pObj;
Abc_Obj_t *pNode;
int index, oldIndex, originalLatchNum = Saig_ManRegNum(pAigOld), strMatch, i;
char *dummyStr = (char *)malloc( sizeof(char) * 50 );
assert( Saig_ObjIsLo( pAigNew, pObjPivot ) );
Saig_ManForEachLo( pAigNew, pObj, index )
if( pObj == pObjPivot )
break;
if( index < originalLatchNum )
{
oldIndex = Saig_ManPiNum( pAigOld ) + index;
pObjOld = Aig_ManCi( pAigOld, oldIndex );
pNode = Abc_NtkCi( pNtkOld, oldIndex );
assert( pObjOld->pData == pObjPivot );
return Abc_ObjName( pNode );
}
else if( index == originalLatchNum )
return "SAVED_LO";
else if( index > originalLatchNum && index < 2 * originalLatchNum + 1 )
{
oldIndex = Saig_ManPiNum( pAigOld ) + index - originalLatchNum - 1;
pObjOld = Aig_ManCi( pAigOld, oldIndex );
pNode = Abc_NtkCi( pNtkOld, oldIndex );
sprintf( dummyStr, "%s__%s", Abc_ObjName( pNode ), "SHADOW");
return dummyStr;
}
else if( index >= 2 * originalLatchNum + 1 && index < 2 * originalLatchNum + 1 + Vec_PtrSize( vLive ) )
{
oldIndex = index - 2 * originalLatchNum - 1;
strMatch = 0;
dummyStr[0] = '\0';
Saig_ManForEachPo( pAigOld, pObj, i )
{
pNode = Abc_NtkPo( pNtkOld, i );
//if( strstr( Abc_ObjName( pNode ), "assert_fair" ) != NULL )
if( nodeName_starts_with( pNode, "assert_fair" ) )
{
if( strMatch == oldIndex )
{
sprintf( dummyStr, "%s__%s", Abc_ObjName( pNode ), "LIVENESS");
//return dummyStr;
break;
}
else
strMatch++;
}
}
assert( dummyStr[0] != '\0' );
return dummyStr;
}
else if( index >= 2 * originalLatchNum + 1 + Vec_PtrSize( vLive ) && index < 2 * originalLatchNum + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) )
{
oldIndex = index - 2 * originalLatchNum - 1 - Vec_PtrSize( vLive );
strMatch = 0;
dummyStr[0] = '\0';
Saig_ManForEachPo( pAigOld, pObj, i )
{
pNode = Abc_NtkPo( pNtkOld, i );
//if( strstr( Abc_ObjName( pNode ), "assume_fair" ) != NULL )
if( nodeName_starts_with( pNode, "assume_fair" ) )
{
if( strMatch == oldIndex )
{
sprintf( dummyStr, "%s__%s", Abc_ObjName( pNode ), "FAIRNESS");
//return dummyStr;
break;
}
else
strMatch++;
}
}
assert( dummyStr[0] != '\0' );
return dummyStr;
}
else
return "UNKNOWN";
}
Vec_Ptr_t *vecPis, *vecPiNames;
Vec_Ptr_t *vecLos, *vecLoNames;
int Aig_ManCiCleanupBiere( Aig_Man_t * p )
{
int nPisOld = Aig_ManCiNum(p);
p->nObjs[AIG_OBJ_CI] = Vec_PtrSize( p->vCis );
if ( Aig_ManRegNum(p) )
p->nTruePis = Aig_ManCiNum(p) - Aig_ManRegNum(p);
return nPisOld - Aig_ManCiNum(p);
}
int Aig_ManCoCleanupBiere( Aig_Man_t * p )
{
int nPosOld = Aig_ManCoNum(p);
p->nObjs[AIG_OBJ_CO] = Vec_PtrSize( p->vCos );
if ( Aig_ManRegNum(p) )
p->nTruePos = Aig_ManCoNum(p) - Aig_ManRegNum(p);
return nPosOld - Aig_ManCoNum(p);
}
Aig_Man_t * LivenessToSafetyTransformation( int mode, Abc_Ntk_t * pNtk, Aig_Man_t * p,
Vec_Ptr_t *vLive, Vec_Ptr_t *vFair, Vec_Ptr_t *vAssertSafety, Vec_Ptr_t *vAssumeSafety )
{
Aig_Man_t * pNew;
int i, nRegCount;
Aig_Obj_t * pObjSavePi = NULL;
Aig_Obj_t *pObjSavedLo = NULL, *pObjSavedLi = NULL;
Aig_Obj_t *pObj, *pMatch;
Aig_Obj_t *pObjSaveOrSaved = NULL, *pObjSaveAndNotSaved = NULL, *pObjSavedLoAndEquality;
Aig_Obj_t *pObjShadowLo, *pObjShadowLi, *pObjShadowLiDriver;
Aig_Obj_t *pObjXor, *pObjXnor, *pObjAndAcc;
Aig_Obj_t *pObjLive, *pObjFair, *pObjSafetyGate;
Aig_Obj_t *pObjSafetyPropertyOutput = NULL;
Aig_Obj_t *pObjOriginalSafetyPropertyOutput;
Aig_Obj_t *pDriverImage, *pArgument, *collectiveAssertSafety, *collectiveAssumeSafety;
char *nodeName;
int piCopied = 0, liCopied = 0, loCopied = 0, liCreated = 0, loCreated = 0, liveLatch = 0, fairLatch = 0;
vecPis = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
vecPiNames = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
vecLos = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
vecLoNames = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
//****************************************************************
// Step1: create the new manager
// Note: The new manager is created with "2 * Aig_ManObjNumMax(p)"
// nodes, but this selection is arbitrary - need to be justified
//****************************************************************
pNew = Aig_ManStart( 2 * Aig_ManObjNumMax(p) );
pNew->pName = (char *)malloc( strlen( pNtk->pName ) + strlen("_l2s") + 1 );
sprintf(pNew->pName, "%s_%s", pNtk->pName, "l2s");
pNew->pSpec = NULL;
//****************************************************************
// Step 2: map constant nodes
//****************************************************************
pObj = Aig_ManConst1( p );
pObj->pData = Aig_ManConst1( pNew );
//****************************************************************
// Step 3: create true PIs
//****************************************************************
Saig_ManForEachPi( p, pObj, i )
{
piCopied++;
pObj->pData = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vecPis, pObj->pData );
nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkPi( pNtk, i ) ));
Vec_PtrPush( vecPiNames, nodeName );
}
//****************************************************************
// Step 4: create the special Pi corresponding to SAVE
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
pObjSavePi = Aig_ObjCreateCi( pNew );
nodeName = "SAVE_BIERE",
Vec_PtrPush( vecPiNames, nodeName );
}
//****************************************************************
// Step 5: create register outputs
//****************************************************************
Saig_ManForEachLo( p, pObj, i )
{
loCopied++;
pObj->pData = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vecLos, pObj->pData );
nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ));
Vec_PtrPush( vecLoNames, nodeName );
}
//****************************************************************
// Step 6: create "saved" register output
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
loCreated++;
pObjSavedLo = Aig_ObjCreateCi( pNew );
Vec_PtrPush( vecLos, pObjSavedLo );
nodeName = "SAVED_LO";
Vec_PtrPush( vecLoNames, nodeName );
}
//****************************************************************
// Step 7: create the OR gate and the AND gate directly fed by "SAVE" Pi
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
pObjSaveOrSaved = Aig_Or( pNew, pObjSavePi, pObjSavedLo );
pObjSaveAndNotSaved = Aig_And( pNew, pObjSavePi, Aig_Not(pObjSavedLo) );
}
//********************************************************************
// Step 8: create internal nodes
//********************************************************************
Aig_ManForEachNode( p, pObj, i )
{
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
}
//********************************************************************
// Step 8.x : create PO for each safety assertions
// NOTE : Here the output is purposely inverted as it will be thrown to
// dprove
//********************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
{
if( Vec_PtrSize( vAssertSafety ) != 0 && Vec_PtrSize( vAssumeSafety ) == 0 )
{
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
pObjOriginalSafetyPropertyOutput = Aig_ObjCreateCo( pNew, Aig_Not(pObjAndAcc) );
}
else if( Vec_PtrSize( vAssertSafety ) != 0 && Vec_PtrSize( vAssumeSafety ) != 0 )
{
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
collectiveAssertSafety = pObjAndAcc;
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssumeSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
collectiveAssumeSafety = pObjAndAcc;
pObjOriginalSafetyPropertyOutput = Aig_ObjCreateCo( pNew, Aig_And( pNew, Aig_Not(collectiveAssertSafety), collectiveAssumeSafety ) );
}
else
{
printf("WARNING!! No safety property is found, a new (negated) constant 1 output is created\n");
pObjOriginalSafetyPropertyOutput = Aig_ObjCreateCo( pNew, Aig_Not( Aig_ManConst1(pNew) ) );
}
}
//********************************************************************
// Step 9: create the safety property output gate for the liveness properties
// discuss with Sat/Alan for an alternative implementation
//********************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
pObjSafetyPropertyOutput = Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
}
// create register inputs for the original registers
nRegCount = 0;
Saig_ManForEachLo( p, pObj, i )
{
pMatch = Saig_ObjLoToLi( p, pObj );
Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)Aig_ObjFanin0(pMatch)->pData, Aig_ObjFaninC0( pMatch ) ) );
nRegCount++;
liCopied++;
}
// create register input corresponding to the register "saved"
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
#ifndef DUPLICATE_CKT_DEBUG
pObjSavedLi = Aig_ObjCreateCo( pNew, pObjSaveOrSaved );
nRegCount++;
liCreated++;
//Changed on October 13, 2009
//pObjAndAcc = NULL;
pObjAndAcc = Aig_ManConst1( pNew );
// create the family of shadow registers, then create the cascade of Xnor and And gates for the comparator
Saig_ManForEachLo( p, pObj, i )
{
pObjShadowLo = Aig_ObjCreateCi( pNew );
#ifdef PROPAGATE_NAMES
Vec_PtrPush( vecLos, pObjShadowLo );
nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ) ) + 10 );
sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ), "SHADOW" );
Vec_PtrPush( vecLoNames, nodeName );
#endif
pObjShadowLiDriver = Aig_Mux( pNew, pObjSaveAndNotSaved, (Aig_Obj_t *)pObj->pData, pObjShadowLo );
pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
nRegCount++;
loCreated++; liCreated++;
pObjXor = Aig_Exor( pNew, (Aig_Obj_t *)pObj->pData, pObjShadowLo );
pObjXnor = Aig_Not( pObjXor );
pObjAndAcc = Aig_And( pNew, pObjXnor, pObjAndAcc );
}
// create the AND gate whose output will be the signal "looped"
pObjSavedLoAndEquality = Aig_And( pNew, pObjSavedLo, pObjAndAcc );
// create the master AND gate and corresponding AND and OR logic for the liveness properties
pObjAndAcc = Aig_ManConst1( pNew );
if( vLive == NULL || Vec_PtrSize( vLive ) == 0 )
{
printf("Circuit without any liveness property\n");
}
else
{
Vec_PtrForEachEntry( Aig_Obj_t *, vLive, pObj, i )
{
liveLatch++;
pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
pObjShadowLo = Aig_ObjCreateCi( pNew );
#ifdef PROPAGATE_NAMES
Vec_PtrPush( vecLos, pObjShadowLo );
nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ) ) + 12 );
sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ), "LIVENESS" );
Vec_PtrPush( vecLoNames, nodeName );
#endif
pObjShadowLiDriver = Aig_Or( pNew, pObjShadowLo, Aig_And( pNew, pDriverImage, pObjSaveOrSaved ) );
pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
nRegCount++;
loCreated++; liCreated++;
pObjAndAcc = Aig_And( pNew, pObjShadowLo, pObjAndAcc );
}
}
pObjLive = pObjAndAcc;
pObjAndAcc = Aig_ManConst1( pNew );
if( vFair == NULL || Vec_PtrSize( vFair ) == 0 )
printf("Circuit without any fairness property\n");
else
{
Vec_PtrForEachEntry( Aig_Obj_t *, vFair, pObj, i )
{
fairLatch++;
pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
pObjShadowLo = Aig_ObjCreateCi( pNew );
#ifdef PROPAGATE_NAMES
Vec_PtrPush( vecLos, pObjShadowLo );
nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ) ) + 12 );
sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ), "FAIRNESS" );
Vec_PtrPush( vecLoNames, nodeName );
#endif
pObjShadowLiDriver = Aig_Or( pNew, pObjShadowLo, Aig_And( pNew, pDriverImage, pObjSaveOrSaved ) );
pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
nRegCount++;
loCreated++; liCreated++;
pObjAndAcc = Aig_And( pNew, pObjShadowLo, pObjAndAcc );
}
}
pObjFair = pObjAndAcc;
//pObjSafetyGate = Aig_Exor( pNew, Aig_Not(Aig_ManConst1( pNew )), Aig_And( pNew, pObjSavedLoAndEquality, Aig_And( pNew, pObjFair, Aig_Not( pObjLive ) ) ) );
//Following is the actual Biere translation
pObjSafetyGate = Aig_And( pNew, pObjSavedLoAndEquality, Aig_And( pNew, pObjFair, Aig_Not( pObjLive ) ) );
Aig_ObjPatchFanin0( pNew, pObjSafetyPropertyOutput, pObjSafetyGate );
#endif
}
Aig_ManSetRegNum( pNew, nRegCount );
Aig_ManCiCleanupBiere( pNew );
Aig_ManCoCleanupBiere( pNew );
Aig_ManCleanup( pNew );
assert( Aig_ManCheck( pNew ) );
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
assert((Aig_Obj_t *)Vec_PtrEntry(pNew->vCos, Saig_ManPoNum(pNew)+Aig_ObjCioId(pObjSavedLo)-Saig_ManPiNum(p)-1) == pObjSavedLi);
assert( Saig_ManPiNum( p ) + 1 == Saig_ManPiNum( pNew ) );
assert( Saig_ManRegNum( pNew ) == Saig_ManRegNum( p ) * 2 + 1 + liveLatch + fairLatch );
}
return pNew;
}
Aig_Man_t * LivenessToSafetyTransformationAbs( int mode, Abc_Ntk_t * pNtk, Aig_Man_t * p, Vec_Int_t *vFlops,
Vec_Ptr_t *vLive, Vec_Ptr_t *vFair, Vec_Ptr_t *vAssertSafety, Vec_Ptr_t *vAssumeSafety )
{
Aig_Man_t * pNew;
int i, nRegCount, iEntry;
Aig_Obj_t * pObjSavePi = NULL;
Aig_Obj_t *pObjSavedLi = NULL, *pObjSavedLo = NULL;
Aig_Obj_t *pObj, *pMatch;
Aig_Obj_t *pObjSavedLoAndEquality, *pObjSaveOrSaved = NULL, *pObjSaveAndNotSaved = NULL;
Aig_Obj_t *pObjShadowLo, *pObjShadowLi, *pObjShadowLiDriver;
Aig_Obj_t *pObjXor, *pObjXnor, *pObjAndAcc;
Aig_Obj_t *pObjLive, *pObjFair, *pObjSafetyGate;
Aig_Obj_t *pObjSafetyPropertyOutput = NULL;
Aig_Obj_t *pDriverImage, *pArgument, *collectiveAssertSafety, *collectiveAssumeSafety;
char *nodeName;
int piCopied = 0, liCopied = 0, loCopied = 0, liCreated = 0, loCreated = 0, liveLatch = 0, fairLatch = 0;//, piVecIndex = 0;
vecPis = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
vecPiNames = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
vecLos = Vec_PtrAlloc( Saig_ManRegNum( p ) + Vec_IntSize( vFlops ) + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
vecLoNames = Vec_PtrAlloc( Saig_ManRegNum( p ) + Vec_IntSize( vFlops ) + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
//****************************************************************
// Step1: create the new manager
// Note: The new manager is created with "2 * Aig_ManObjNumMax(p)"
// nodes, but this selection is arbitrary - need to be justified
//****************************************************************
pNew = Aig_ManStart( 2 * Aig_ManObjNumMax(p) );
pNew->pName = (char *)malloc( strlen( pNtk->pName ) + strlen("_l2s") + 1 );
sprintf(pNew->pName, "%s_%s", pNtk->pName, "l2s");
pNew->pSpec = NULL;
//****************************************************************
// Step 2: map constant nodes
//****************************************************************
pObj = Aig_ManConst1( p );
pObj->pData = Aig_ManConst1( pNew );
//****************************************************************
// Step 3: create true PIs
//****************************************************************
Saig_ManForEachPi( p, pObj, i )
{
piCopied++;
pObj->pData = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vecPis, pObj->pData );
nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkPi( pNtk, i ) ));
Vec_PtrPush( vecPiNames, nodeName );
}
//****************************************************************
// Step 4: create the special Pi corresponding to SAVE
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
pObjSavePi = Aig_ObjCreateCi( pNew );
nodeName = "SAVE_BIERE",
Vec_PtrPush( vecPiNames, nodeName );
}
//****************************************************************
// Step 5: create register outputs
//****************************************************************
Saig_ManForEachLo( p, pObj, i )
{
loCopied++;
pObj->pData = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vecLos, pObj->pData );
nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ));
Vec_PtrPush( vecLoNames, nodeName );
}
//****************************************************************
// Step 6: create "saved" register output
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
loCreated++;
pObjSavedLo = Aig_ObjCreateCi( pNew );
Vec_PtrPush( vecLos, pObjSavedLo );
nodeName = "SAVED_LO";
Vec_PtrPush( vecLoNames, nodeName );
}
//****************************************************************
// Step 7: create the OR gate and the AND gate directly fed by "SAVE" Pi
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
pObjSaveOrSaved = Aig_Or( pNew, pObjSavePi, pObjSavedLo );
pObjSaveAndNotSaved = Aig_And( pNew, pObjSavePi, Aig_Not(pObjSavedLo) );
}
//********************************************************************
// Step 8: create internal nodes
//********************************************************************
Aig_ManForEachNode( p, pObj, i )
{
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
}
//********************************************************************
// Step 8.x : create PO for each safety assertions
// NOTE : Here the output is purposely inverted as it will be thrown to
// dprove
//********************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
{
if( Vec_PtrSize( vAssertSafety ) != 0 && Vec_PtrSize( vAssumeSafety ) == 0 )
{
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
Aig_ObjCreateCo( pNew, Aig_Not(pObjAndAcc) );
}
else if( Vec_PtrSize( vAssertSafety ) != 0 && Vec_PtrSize( vAssumeSafety ) != 0 )
{
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
collectiveAssertSafety = pObjAndAcc;
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssumeSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
collectiveAssumeSafety = pObjAndAcc;
Aig_ObjCreateCo( pNew, Aig_And( pNew, Aig_Not(collectiveAssertSafety), collectiveAssumeSafety ) );
}
else
{
printf("WARNING!! No safety property is found, a new (negated) constant 1 output is created\n");
Aig_ObjCreateCo( pNew, Aig_Not( Aig_ManConst1(pNew) ) );
}
}
//********************************************************************
// Step 9: create the safety property output gate for the liveness properties
// discuss with Sat/Alan for an alternative implementation
//********************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
pObjSafetyPropertyOutput = Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
}
// create register inputs for the original registers
nRegCount = 0;
Saig_ManForEachLo( p, pObj, i )
{
pMatch = Saig_ObjLoToLi( p, pObj );
Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)Aig_ObjFanin0(pMatch)->pData, Aig_ObjFaninC0( pMatch ) ) );
nRegCount++;
liCopied++;
}
// create register input corresponding to the register "saved"
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
#ifndef DUPLICATE_CKT_DEBUG
pObjSavedLi = Aig_ObjCreateCo( pNew, pObjSaveOrSaved );
nRegCount++;
liCreated++;
//Changed on October 13, 2009
//pObjAndAcc = NULL;
pObjAndAcc = Aig_ManConst1( pNew );
// create the family of shadow registers, then create the cascade of Xnor and And gates for the comparator
//Saig_ManForEachLo( p, pObj, i )
Saig_ManForEachLo( p, pObj, i )
{
printf("Flop[%d] = %s\n", i, Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ) );
}
Vec_IntForEachEntry( vFlops, iEntry, i )
{
pObjShadowLo = Aig_ObjCreateCi( pNew );
pObj = Aig_ManLo( p, iEntry );
#ifdef PROPAGATE_NAMES
Vec_PtrPush( vecLos, pObjShadowLo );
nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + iEntry ) ) ) + 10 );
sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + iEntry ) ), "SHADOW" );
printf("Flop copied [%d] = %s\n", iEntry, nodeName );
Vec_PtrPush( vecLoNames, nodeName );
#endif
pObjShadowLiDriver = Aig_Mux( pNew, pObjSaveAndNotSaved, (Aig_Obj_t *)pObj->pData, pObjShadowLo );
pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
nRegCount++;
loCreated++; liCreated++;
pObjXor = Aig_Exor( pNew, (Aig_Obj_t *)pObj->pData, pObjShadowLo );
pObjXnor = Aig_Not( pObjXor );
pObjAndAcc = Aig_And( pNew, pObjXnor, pObjAndAcc );
}
// create the AND gate whose output will be the signal "looped"
pObjSavedLoAndEquality = Aig_And( pNew, pObjSavedLo, pObjAndAcc );
// create the master AND gate and corresponding AND and OR logic for the liveness properties
pObjAndAcc = Aig_ManConst1( pNew );
if( vLive == NULL || Vec_PtrSize( vLive ) == 0 )
{
printf("Circuit without any liveness property\n");
}
else
{
Vec_PtrForEachEntry( Aig_Obj_t *, vLive, pObj, i )
{
liveLatch++;
pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
pObjShadowLo = Aig_ObjCreateCi( pNew );
#ifdef PROPAGATE_NAMES
Vec_PtrPush( vecLos, pObjShadowLo );
nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ) ) + 12 );
sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ), "LIVENESS" );
Vec_PtrPush( vecLoNames, nodeName );
#endif
pObjShadowLiDriver = Aig_Or( pNew, pObjShadowLo, Aig_And( pNew, pDriverImage, pObjSaveOrSaved ) );
pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
nRegCount++;
loCreated++; liCreated++;
pObjAndAcc = Aig_And( pNew, pObjShadowLo, pObjAndAcc );
}
}
pObjLive = pObjAndAcc;
pObjAndAcc = Aig_ManConst1( pNew );
if( vFair == NULL || Vec_PtrSize( vFair ) == 0 )
printf("Circuit without any fairness property\n");
else
{
Vec_PtrForEachEntry( Aig_Obj_t *, vFair, pObj, i )
{
fairLatch++;
pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
pObjShadowLo = Aig_ObjCreateCi( pNew );
#ifdef PROPAGATE_NAMES
Vec_PtrPush( vecLos, pObjShadowLo );
nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ) ) + 12 );
sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ), "FAIRNESS" );
Vec_PtrPush( vecLoNames, nodeName );
#endif
pObjShadowLiDriver = Aig_Or( pNew, pObjShadowLo, Aig_And( pNew, pDriverImage, pObjSaveOrSaved ) );
pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
nRegCount++;
loCreated++; liCreated++;
pObjAndAcc = Aig_And( pNew, pObjShadowLo, pObjAndAcc );
}
}
pObjFair = pObjAndAcc;
//pObjSafetyGate = Aig_Exor( pNew, Aig_Not(Aig_ManConst1( pNew )), Aig_And( pNew, pObjSavedLoAndEquality, Aig_And( pNew, pObjFair, Aig_Not( pObjLive ) ) ) );
//Following is the actual Biere translation
pObjSafetyGate = Aig_And( pNew, pObjSavedLoAndEquality, Aig_And( pNew, pObjFair, Aig_Not( pObjLive ) ) );
Aig_ObjPatchFanin0( pNew, pObjSafetyPropertyOutput, pObjSafetyGate );
#endif
}
Aig_ManSetRegNum( pNew, nRegCount );
Aig_ManCiCleanupBiere( pNew );
Aig_ManCoCleanupBiere( pNew );
Aig_ManCleanup( pNew );
assert( Aig_ManCheck( pNew ) );
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
assert((Aig_Obj_t *)Vec_PtrEntry(pNew->vCos, Saig_ManPoNum(pNew)+Aig_ObjCioId(pObjSavedLo)-Saig_ManPiNum(p)-1) == pObjSavedLi);
assert( Saig_ManPiNum( p ) + 1 == Saig_ManPiNum( pNew ) );
assert( Saig_ManRegNum( pNew ) == Saig_ManRegNum( p ) + Vec_IntSize( vFlops ) + 1 + liveLatch + fairLatch );
}
return pNew;
}
Aig_Man_t * LivenessToSafetyTransformationOneStepLoop( int mode, Abc_Ntk_t * pNtk, Aig_Man_t * p,
Vec_Ptr_t *vLive, Vec_Ptr_t *vFair, Vec_Ptr_t *vAssertSafety, Vec_Ptr_t *vAssumeSafety )
{
Aig_Man_t * pNew;
int i, nRegCount;
Aig_Obj_t * pObjSavePi = NULL;
Aig_Obj_t *pObj, *pMatch;
Aig_Obj_t *pObjSavedLoAndEquality;
Aig_Obj_t *pObjXor, *pObjXnor, *pObjAndAcc, *pObjAndAccDummy;
Aig_Obj_t *pObjLive, *pObjFair, *pObjSafetyGate;
Aig_Obj_t *pObjSafetyPropertyOutput = NULL;
Aig_Obj_t *pDriverImage;
Aig_Obj_t *pObjCorrespondingLi;
Aig_Obj_t *pArgument;
Aig_Obj_t *collectiveAssertSafety, *collectiveAssumeSafety;
char *nodeName;
int piCopied = 0, liCopied = 0, loCopied = 0;//, liCreated = 0, loCreated = 0, piVecIndex = 0;
if( Aig_ManRegNum( p ) == 0 )
{
printf("The input AIG contains no register, returning the original AIG as it is\n");
return p;
}
vecPis = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
vecPiNames = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
vecLos = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
vecLoNames = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
//****************************************************************
// Step1: create the new manager
// Note: The new manager is created with "2 * Aig_ManObjNumMax(p)"
// nodes, but this selection is arbitrary - need to be justified
//****************************************************************
pNew = Aig_ManStart( 2 * Aig_ManObjNumMax(p) );
pNew->pName = Abc_UtilStrsav( "live2safe" );
pNew->pSpec = NULL;
//****************************************************************
// Step 2: map constant nodes
//****************************************************************
pObj = Aig_ManConst1( p );
pObj->pData = Aig_ManConst1( pNew );
//****************************************************************
// Step 3: create true PIs
//****************************************************************
Saig_ManForEachPi( p, pObj, i )
{
piCopied++;
pObj->pData = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vecPis, pObj->pData );
nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkPi( pNtk, i ) ));
Vec_PtrPush( vecPiNames, nodeName );
}
//****************************************************************
// Step 4: create the special Pi corresponding to SAVE
//****************************************************************
if( mode == FULL_BIERE_ONE_LOOP_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE )
{
pObjSavePi = Aig_ObjCreateCi( pNew );
nodeName = "SAVE_BIERE",
Vec_PtrPush( vecPiNames, nodeName );
}
//****************************************************************
// Step 5: create register outputs
//****************************************************************
Saig_ManForEachLo( p, pObj, i )
{
loCopied++;
pObj->pData = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vecLos, pObj->pData );
nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ));
Vec_PtrPush( vecLoNames, nodeName );
}
//****************************************************************
// Step 6: create "saved" register output
//****************************************************************
#if 0
loCreated++;
pObjSavedLo = Aig_ObjCreateCi( pNew );
Vec_PtrPush( vecLos, pObjSavedLo );
nodeName = "SAVED_LO";
Vec_PtrPush( vecLoNames, nodeName );
#endif
//****************************************************************
// Step 7: create the OR gate and the AND gate directly fed by "SAVE" Pi
//****************************************************************
#if 0
pObjSaveOrSaved = Aig_Or( pNew, pObjSavePi, pObjSavedLo );
pObjSaveAndNotSaved = Aig_And( pNew, pObjSavePi, Aig_Not(pObjSavedLo) );
#endif
//********************************************************************
// Step 8: create internal nodes
//********************************************************************
Aig_ManForEachNode( p, pObj, i )
{
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
}
#if 0
//********************************************************************
// Step 8.x : create PO for each safety assertions
//********************************************************************
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
pObj->pData = Aig_ObjCreateCo( pNew, Aig_NotCond(Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) ) );
}
#endif
if( mode == FULL_BIERE_ONE_LOOP_MODE || mode == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
{
if( Vec_PtrSize( vAssertSafety ) != 0 && Vec_PtrSize( vAssumeSafety ) == 0 )
{
pObjAndAcc = NULL;
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
//pObj->pData = Aig_ObjCreateCo( pNew, Aig_NotCond(Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) ) );
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
if( pObjAndAcc == NULL )
pObjAndAcc = pArgument;
else
{
pObjAndAccDummy = pObjAndAcc;
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAccDummy );
}
}
Aig_ObjCreateCo( pNew, Aig_Not(pObjAndAcc) );
}
else if( Vec_PtrSize( vAssertSafety ) != 0 && Vec_PtrSize( vAssumeSafety ) != 0 )
{
pObjAndAcc = NULL;
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
//pObj->pData = Aig_ObjCreateCo( pNew, Aig_NotCond(Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) ) );
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
if( pObjAndAcc == NULL )
pObjAndAcc = pArgument;
else
{
pObjAndAccDummy = pObjAndAcc;
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAccDummy );
}
}
collectiveAssertSafety = pObjAndAcc;
pObjAndAcc = NULL;
Vec_PtrForEachEntry( Aig_Obj_t *, vAssumeSafety, pObj, i )
{
//pObj->pData = Aig_ObjCreateCo( pNew, Aig_NotCond(Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) ) );
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
if( pObjAndAcc == NULL )
pObjAndAcc = pArgument;
else
{
pObjAndAccDummy = pObjAndAcc;
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAccDummy );
}
}
collectiveAssumeSafety = pObjAndAcc;
Aig_ObjCreateCo( pNew, Aig_And( pNew, Aig_Not(collectiveAssertSafety), collectiveAssumeSafety ) );
}
else
printf("No safety property is specified, hence no safety gate is created\n");
}
//********************************************************************
// Step 9: create the safety property output gate
// create the safety property output gate, this will be the sole true PO
// of the whole circuit, discuss with Sat/Alan for an alternative implementation
//********************************************************************
if( mode == FULL_BIERE_ONE_LOOP_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE )
{
pObjSafetyPropertyOutput = Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
}
// create register inputs for the original registers
nRegCount = 0;
Saig_ManForEachLo( p, pObj, i )
{
pMatch = Saig_ObjLoToLi( p, pObj );
//Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pMatch) );
Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)Aig_ObjFanin0(pMatch)->pData, Aig_ObjFaninC0( pMatch ) ) );
nRegCount++;
liCopied++;
}
#if 0
// create register input corresponding to the register "saved"
pObjSavedLi = Aig_ObjCreateCo( pNew, pObjSaveOrSaved );
nRegCount++;
liCreated++;7
#endif
pObjAndAcc = NULL;
//****************************************************************************************************
//For detection of loop of length 1 we do not need any shadow register, we only need equality detector
//between Lo_j and Li_j and then a cascade of AND gates
//****************************************************************************************************
if( mode == FULL_BIERE_ONE_LOOP_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE )
{
Saig_ManForEachLo( p, pObj, i )
{
pObjCorrespondingLi = Saig_ObjLoToLi( p, pObj );
pObjXor = Aig_Exor( pNew, (Aig_Obj_t *)pObj->pData, Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0( pObjCorrespondingLi )->pData, Aig_ObjFaninC0( pObjCorrespondingLi ) ) );
pObjXnor = Aig_Not( pObjXor );
if( pObjAndAcc == NULL )
pObjAndAcc = pObjXnor;
else
{
pObjAndAccDummy = pObjAndAcc;
pObjAndAcc = Aig_And( pNew, pObjXnor, pObjAndAccDummy );
}
}
// create the AND gate whose output will be the signal "looped"
pObjSavedLoAndEquality = Aig_And( pNew, pObjSavePi, pObjAndAcc );
// create the master AND gate and corresponding AND and OR logic for the liveness properties
pObjAndAcc = NULL;
if( vLive == NULL || Vec_PtrSize( vLive ) == 0 )
printf("Circuit without any liveness property\n");
else
{
Vec_PtrForEachEntry( Aig_Obj_t *, vLive, pObj, i )
{
pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
if( pObjAndAcc == NULL )
pObjAndAcc = pDriverImage;
else
{
pObjAndAccDummy = pObjAndAcc;
pObjAndAcc = Aig_And( pNew, pDriverImage, pObjAndAccDummy );
}
}
}
if( pObjAndAcc != NULL )
pObjLive = pObjAndAcc;
else
pObjLive = Aig_ManConst1( pNew );
// create the master AND gate and corresponding AND and OR logic for the fairness properties
pObjAndAcc = NULL;
if( vFair == NULL || Vec_PtrSize( vFair ) == 0 )
printf("Circuit without any fairness property\n");
else
{
Vec_PtrForEachEntry( Aig_Obj_t *, vFair, pObj, i )
{
pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
if( pObjAndAcc == NULL )
pObjAndAcc = pDriverImage;
else
{
pObjAndAccDummy = pObjAndAcc;
pObjAndAcc = Aig_And( pNew, pDriverImage, pObjAndAccDummy );
}
}
}
if( pObjAndAcc != NULL )
pObjFair = pObjAndAcc;
else
pObjFair = Aig_ManConst1( pNew );
pObjSafetyGate = Aig_And( pNew, pObjSavedLoAndEquality, Aig_And( pNew, pObjFair, Aig_Not( pObjLive ) ) );
Aig_ObjPatchFanin0( pNew, pObjSafetyPropertyOutput, pObjSafetyGate );
}
Aig_ManSetRegNum( pNew, nRegCount );
//printf("\nSaig_ManPiNum = %d, Reg Num = %d, before everything, before Pi cleanup\n", Vec_PtrSize( pNew->vPis ), pNew->nRegs );
Aig_ManCiCleanupBiere( pNew );
Aig_ManCoCleanupBiere( pNew );
Aig_ManCleanup( pNew );
assert( Aig_ManCheck( pNew ) );
return pNew;
}
Vec_Ptr_t * populateLivenessVector( Abc_Ntk_t *pNtk, Aig_Man_t *pAig )
{
Abc_Obj_t * pNode;
int i, liveCounter = 0;
Vec_Ptr_t * vLive;
vLive = Vec_PtrAlloc( 100 );
Abc_NtkForEachPo( pNtk, pNode, i )
//if( strstr( Abc_ObjName( pNode ), "assert_fair") != NULL )
if( nodeName_starts_with( pNode, "assert_fair" ) )
{
Vec_PtrPush( vLive, Aig_ManCo( pAig, i ) );
liveCounter++;
}
printf("Number of liveness property found = %d\n", liveCounter);
return vLive;
}
Vec_Ptr_t * populateFairnessVector( Abc_Ntk_t *pNtk, Aig_Man_t *pAig )
{
Abc_Obj_t * pNode;
int i, fairCounter = 0;
Vec_Ptr_t * vFair;
vFair = Vec_PtrAlloc( 100 );
Abc_NtkForEachPo( pNtk, pNode, i )
//if( strstr( Abc_ObjName( pNode ), "assume_fair") != NULL )
if( nodeName_starts_with( pNode, "assume_fair" ) )
{
Vec_PtrPush( vFair, Aig_ManCo( pAig, i ) );
fairCounter++;
}
printf("Number of fairness property found = %d\n", fairCounter);
return vFair;
}
Vec_Ptr_t * populateSafetyAssertionVector( Abc_Ntk_t *pNtk, Aig_Man_t *pAig )
{
Abc_Obj_t * pNode;
int i, assertSafetyCounter = 0;
Vec_Ptr_t * vAssertSafety;
vAssertSafety = Vec_PtrAlloc( 100 );
Abc_NtkForEachPo( pNtk, pNode, i )
//if( strstr( Abc_ObjName( pNode ), "Assert") != NULL )
if( nodeName_starts_with( pNode, "assert_safety" ) || nodeName_starts_with( pNode, "Assert" ))
{
Vec_PtrPush( vAssertSafety, Aig_ManCo( pAig, i ) );
assertSafetyCounter++;
}
printf("Number of safety property found = %d\n", assertSafetyCounter);
return vAssertSafety;
}
Vec_Ptr_t * populateSafetyAssumptionVector( Abc_Ntk_t *pNtk, Aig_Man_t *pAig )
{
Abc_Obj_t * pNode;
int i, assumeSafetyCounter = 0;
Vec_Ptr_t * vAssumeSafety;
vAssumeSafety = Vec_PtrAlloc( 100 );
Abc_NtkForEachPo( pNtk, pNode, i )
//if( strstr( Abc_ObjName( pNode ), "Assert") != NULL )
if( nodeName_starts_with( pNode, "assume_safety" ) || nodeName_starts_with( pNode, "Assume" ))
{
Vec_PtrPush( vAssumeSafety, Aig_ManCo( pAig, i ) );
assumeSafetyCounter++;
}
printf("Number of assume_safety property found = %d\n", assumeSafetyCounter);
return vAssumeSafety;
}
void updateNewNetworkNameManager( Abc_Ntk_t *pNtk, Aig_Man_t *pAig, Vec_Ptr_t *vPiNames, Vec_Ptr_t *vLoNames )
{
Aig_Obj_t *pObj;
Abc_Obj_t *pNode;
int i, ntkObjId;
pNtk->pManName = Nm_ManCreate( Abc_NtkCiNum( pNtk ) );
if( vPiNames )
{
Saig_ManForEachPi( pAig, pObj, i )
{
ntkObjId = Abc_NtkCi( pNtk, i )->Id;
//printf("Pi %d, Saved Name = %s, id = %d\n", i, Nm_ManStoreIdName( pNtk->pManName, ntkObjId, Aig_ObjType(pObj), Vec_PtrEntry(vPiNames, i), NULL ), ntkObjId);
Nm_ManStoreIdName( pNtk->pManName, ntkObjId, Aig_ObjType(pObj), (char *)Vec_PtrEntry(vPiNames, i), NULL );
}
}
if( vLoNames )
{
Saig_ManForEachLo( pAig, pObj, i )
{
ntkObjId = Abc_NtkCi( pNtk, Saig_ManPiNum( pAig ) + i )->Id;
//printf("Lo %d, Saved name = %s, id = %d\n", i, Nm_ManStoreIdName( pNtk->pManName, ntkObjId, Aig_ObjType(pObj), Vec_PtrEntry(vLoNames, i), NULL ), ntkObjId);
Nm_ManStoreIdName( pNtk->pManName, ntkObjId, Aig_ObjType(pObj), (char *)Vec_PtrEntry(vLoNames, i), NULL );
}
}
Abc_NtkForEachPo(pNtk, pNode, i)
{
Abc_ObjAssignName(pNode, "assert_safety_", Abc_ObjName(pNode) );
}
// assign latch input names
Abc_NtkForEachLatch(pNtk, pNode, i)
if ( Nm_ManFindNameById(pNtk->pManName, Abc_ObjFanin0(pNode)->Id) == NULL )
Abc_ObjAssignName( Abc_ObjFanin0(pNode), Abc_ObjName(Abc_ObjFanin0(pNode)), NULL );
}
int Abc_CommandAbcLivenessToSafety( Abc_Frame_t * pAbc, int argc, char ** argv )
{
FILE * pOut, * pErr;
Abc_Ntk_t * pNtk, * pNtkTemp, *pNtkNew, *pNtkOld;
Aig_Man_t * pAig, *pAigNew = NULL;
int c;
Vec_Ptr_t * vLive, * vFair, *vAssertSafety, *vAssumeSafety;
int directive = -1;
pNtk = Abc_FrameReadNtk(pAbc);
pOut = Abc_FrameReadOut(pAbc);
pErr = Abc_FrameReadErr(pAbc);
if( argc == 1 )
{
assert( directive == -1 );
directive = FULL_BIERE_MODE;
}
else
{
Extra_UtilGetoptReset();
while ( ( c = Extra_UtilGetopt( argc, argv, "1slh" ) ) != EOF )
{
switch( c )
{
case '1':
if( directive == -1 )
directive = FULL_BIERE_ONE_LOOP_MODE;
else
{
assert( directive == IGNORE_LIVENESS_KEEP_SAFETY_MODE || directive == IGNORE_SAFETY_KEEP_LIVENESS_MODE );
if( directive == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
else
directive = IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE;
}
break;
case 's':
if( directive == -1 )
directive = IGNORE_SAFETY_KEEP_LIVENESS_MODE;
else
{
if( directive != FULL_BIERE_ONE_LOOP_MODE )
goto usage;
assert(directive == FULL_BIERE_ONE_LOOP_MODE);
directive = IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE;
}
break;
case 'l':
if( directive == -1 )
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
else
{
if( directive != FULL_BIERE_ONE_LOOP_MODE )
goto usage;
assert(directive == FULL_BIERE_ONE_LOOP_MODE);
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
}
break;
case 'h':
goto usage;
default:
goto usage;
}
}
}
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
switch( directive )
{
case FULL_BIERE_MODE:
//if( Vec_PtrSize(vLive) == 0 && Vec_PtrSize(vAssertSafety) == 0 )
//{
// printf("Input circuit has NO safety and NO liveness property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformation( FULL_BIERE_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t2 POs - one for safety and one for liveness.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created if the original circuit is combinational\n\tnon-property POs are suppressed\n");
break;
//}
case FULL_BIERE_ONE_LOOP_MODE:
//if( Vec_PtrSize(vLive) == 0 && Vec_PtrSize(vAssertSafety) == 0 )
//{
// printf("Input circuit has NO safety and NO liveness property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformationOneStepLoop( FULL_BIERE_ONE_LOOP_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t2 POs - one for safety and one for liveness.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created\n\tnon-property POs are suppressed\n");
break;
//}
case IGNORE_LIVENESS_KEEP_SAFETY_MODE:
//if( Vec_PtrSize(vAssertSafety) == 0 )
//{
// printf("Input circuit has NO safety property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformation( IGNORE_LIVENESS_KEEP_SAFETY_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t1 PO - only for safety property; liveness properties are ignored, if any.\n\tno additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created\n\tnon-property POs are suppressed\n");
break;
//}
case IGNORE_SAFETY_KEEP_LIVENESS_MODE:
//if( Vec_PtrSize(vLive) == 0 )
//{
// printf("Input circuit has NO liveness property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformation( IGNORE_SAFETY_KEEP_LIVENESS_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t1 PO - only for liveness property; safety properties are ignored, if any.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created if the original circuit is combinational\n\tnon-property POs are suppressed\n");
break;
//}
case IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE:
//if( Vec_PtrSize(vLive) == 0 )
//{
// printf("Input circuit has NO liveness property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformationOneStepLoop( IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced ignoring safety outputs!\nOnly liveness and fairness outputs are considered.\nShadow registers are not created\n");
break;
//}
}
#if 0
if( argc == 1 )
{
pAigNew = LivenessToSafetyTransformation( FULL_BIERE_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced considering all safety, liveness and fairness outputs.\nBiere's logic is created\n");
}
else
{
Extra_UtilGetoptReset();
c = Extra_UtilGetopt( argc, argv, "1lsh" );
if( c == '1' )
{
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
pAigNew = LivenessToSafetyTransformationOneStepLoop( pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
}
else if( c == 'l' )
{
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
pAigNew = LivenessToSafetyTransformation( IGNORE_LIVENESS_KEEP_SAFETY_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced ignoring liveness outputs!\nOnly safety outputs are kept.\nBiere's logic is not created\n");
}
else if( c == 's' )
{
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
pAigNew = LivenessToSafetyTransformation( IGNORE_SAFETY_KEEP_LIVENESS_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced ignoring safety outputs!\nOnly liveness and fairness outputs are considered.\nBiere's logic is created\n");
}
else if( c == 'h' )
goto usage;
else
goto usage;
}
#endif
#if 0
Aig_ManPrintStats( pAigNew );
printf("\nDetail statistics*************************************\n");
printf("Number of true primary inputs = %d\n", Saig_ManPiNum( pAigNew ));
printf("Number of true primary outputs = %d\n", Saig_ManPoNum( pAigNew ));
printf("Number of true latch outputs = %d\n", Saig_ManCiNum( pAigNew ) - Saig_ManPiNum( pAigNew ));
printf("Number of true latch inputs = %d\n", Saig_ManCoNum( pAigNew ) - Saig_ManPoNum( pAigNew ));
printf("Numer of registers = %d\n", Saig_ManRegNum( pAigNew ) );
printf("\n*******************************************************\n");
#endif
pNtkNew = Abc_NtkFromAigPhase( pAigNew );
pNtkNew->pName = Abc_UtilStrsav( pAigNew->pName );
if ( !Abc_NtkCheck( pNtkNew ) )
fprintf( stdout, "Abc_NtkCreateCone(): Network check has failed.\n" );
updateNewNetworkNameManager( pNtkNew, pAigNew, vecPiNames, vecLoNames );
Abc_FrameSetCurrentNetwork( pAbc, pNtkNew );
#if 0
#ifndef DUPLICATE_CKT_DEBUG
Saig_ManForEachPi( pAigNew, pObj, i )
assert( strcmp( (char *)Vec_PtrEntry(vecPiNames, i), retrieveTruePiName( pNtk, pAig, pAigNew, pObj ) ) == 0 );
//printf("Name of %d-th Pi = %s, %s\n", i, retrieveTruePiName( pNtk, pAig, pAigNew, pObj ), (char *)Vec_PtrEntry(vecPiNames, i) );
Saig_ManForEachLo( pAigNew, pObj, i )
assert( strcmp( (char *)Vec_PtrEntry(vecLoNames, i), retrieveLOName( pNtk, pAig, pAigNew, pObj, vLive, vFair ) ) == 0 );
#endif
#endif
return 0;
usage:
fprintf( stdout, "usage: l2s [-1lsh]\n" );
fprintf( stdout, "\t performs Armin Biere's live-to-safe transformation\n" );
fprintf( stdout, "\t-1 : no shadow logic, presume all loops are self loops\n");
fprintf( stdout, "\t-l : ignore liveness and fairness outputs\n");
fprintf( stdout, "\t-s : ignore safety assertions and assumptions\n");
fprintf( stdout, "\t-h : print command usage\n");
return 1;
}
Vec_Int_t * prepareFlopVector( Aig_Man_t * pAig, int vectorLength )
{
Vec_Int_t *vFlops;
int i;
vFlops = Vec_IntAlloc( vectorLength );
for( i=0; i<vectorLength; i++ )
Vec_IntPush( vFlops, i );
#if 0
Vec_IntPush( vFlops, 19 );
Vec_IntPush( vFlops, 20 );
Vec_IntPush( vFlops, 23 );
Vec_IntPush( vFlops, 24 );
//Vec_IntPush( vFlops, 2 );
//Vec_IntPush( vFlops, 3 );
//Vec_IntPush( vFlops, 4 );
//Vec_IntPush( vFlops, 5 );
//Vec_IntPush( vFlops, 8 );
//Vec_IntPush( vFlops, 9 );
//Vec_IntPush( vFlops, 10 );
//Vec_IntPush( vFlops, 11 );
//Vec_IntPush( vFlops, 0 );
//Vec_IntPush( vFlops, 0 );
#endif
return vFlops;
}
int Abc_CommandAbcLivenessToSafetyAbstraction( Abc_Frame_t * pAbc, int argc, char ** argv )
{
FILE * pOut, * pErr;
Abc_Ntk_t * pNtk, * pNtkTemp, *pNtkNew, *pNtkOld;
Aig_Man_t * pAig, *pAigNew = NULL;
int c;
Vec_Ptr_t * vLive, * vFair, *vAssertSafety, *vAssumeSafety;
int directive = -1;
Vec_Int_t * vFlops;
pNtk = Abc_FrameReadNtk(pAbc);
pOut = Abc_FrameReadOut(pAbc);
pErr = Abc_FrameReadErr(pAbc);
if( argc == 1 )
{
assert( directive == -1 );
directive = FULL_BIERE_MODE;
}
else
{
Extra_UtilGetoptReset();
while ( ( c = Extra_UtilGetopt( argc, argv, "1slh" ) ) != EOF )
{
switch( c )
{
case '1':
if( directive == -1 )
directive = FULL_BIERE_ONE_LOOP_MODE;
else
{
assert( directive == IGNORE_LIVENESS_KEEP_SAFETY_MODE || directive == IGNORE_SAFETY_KEEP_LIVENESS_MODE );
if( directive == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
else
directive = IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE;
}
break;
case 's':
if( directive == -1 )
directive = IGNORE_SAFETY_KEEP_LIVENESS_MODE;
else
{
if( directive != FULL_BIERE_ONE_LOOP_MODE )
goto usage;
assert(directive == FULL_BIERE_ONE_LOOP_MODE);
directive = IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE;
}
break;
case 'l':
if( directive == -1 )
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
else
{
if( directive != FULL_BIERE_ONE_LOOP_MODE )
goto usage;
assert(directive == FULL_BIERE_ONE_LOOP_MODE);
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
}
break;
case 'h':
goto usage;
default:
goto usage;
}
}
}
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
vFlops = prepareFlopVector( pAig, Aig_ManRegNum(pAig)%2 == 0? Aig_ManRegNum(pAig)/2 : (Aig_ManRegNum(pAig)-1)/2);
//vFlops = prepareFlopVector( pAig, 100 );
switch( directive )
{
case FULL_BIERE_MODE:
//if( Vec_PtrSize(vLive) == 0 && Vec_PtrSize(vAssertSafety) == 0 )
//{
// printf("Input circuit has NO safety and NO liveness property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformationAbs( FULL_BIERE_MODE, pNtk, pAig, vFlops, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t2 POs - one for safety and one for liveness.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created if the original circuit is combinational\n\tnon-property POs are suppressed\n");
break;
//}
case FULL_BIERE_ONE_LOOP_MODE:
//if( Vec_PtrSize(vLive) == 0 && Vec_PtrSize(vAssertSafety) == 0 )
//{
// printf("Input circuit has NO safety and NO liveness property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformationOneStepLoop( FULL_BIERE_ONE_LOOP_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t2 POs - one for safety and one for liveness.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created\n\tnon-property POs are suppressed\n");
break;
//}
case IGNORE_LIVENESS_KEEP_SAFETY_MODE:
//if( Vec_PtrSize(vAssertSafety) == 0 )
//{
// printf("Input circuit has NO safety property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformationAbs( IGNORE_LIVENESS_KEEP_SAFETY_MODE, pNtk, pAig, vFlops, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t1 PO - only for safety property; liveness properties are ignored, if any.\n\tno additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created\n\tnon-property POs are suppressed\n");
break;
//}
case IGNORE_SAFETY_KEEP_LIVENESS_MODE:
//if( Vec_PtrSize(vLive) == 0 )
//{
// printf("Input circuit has NO liveness property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformationAbs( IGNORE_SAFETY_KEEP_LIVENESS_MODE, pNtk, pAig, vFlops, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t1 PO - only for liveness property; safety properties are ignored, if any.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created if the original circuit is combinational\n\tnon-property POs are suppressed\n");
break;
//}
case IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE:
//if( Vec_PtrSize(vLive) == 0 )
//{
// printf("Input circuit has NO liveness property, original network is not disturbed\n");
// return 1;
//}
//else
//{
pAigNew = LivenessToSafetyTransformationOneStepLoop( IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced ignoring safety outputs!\nOnly liveness and fairness outputs are considered.\nShadow registers are not created\n");
break;
//}
}
pNtkNew = Abc_NtkFromAigPhase( pAigNew );
pNtkNew->pName = Abc_UtilStrsav( pAigNew->pName );
if ( !Abc_NtkCheck( pNtkNew ) )
fprintf( stdout, "Abc_NtkCreateCone(): Network check has failed.\n" );
updateNewNetworkNameManager( pNtkNew, pAigNew, vecPiNames,vecLoNames );
Abc_FrameSetCurrentNetwork( pAbc, pNtkNew );
#if 0
#ifndef DUPLICATE_CKT_DEBUG
Saig_ManForEachPi( pAigNew, pObj, i )
assert( strcmp( (char *)Vec_PtrEntry(vecPiNames, i), retrieveTruePiName( pNtk, pAig, pAigNew, pObj ) ) == 0 );
//printf("Name of %d-th Pi = %s, %s\n", i, retrieveTruePiName( pNtk, pAig, pAigNew, pObj ), (char *)Vec_PtrEntry(vecPiNames, i) );
Saig_ManForEachLo( pAigNew, pObj, i )
assert( strcmp( (char *)Vec_PtrEntry(vecLoNames, i), retrieveLOName( pNtk, pAig, pAigNew, pObj, vLive, vFair ) ) == 0 );
#endif
#endif
return 0;
usage:
fprintf( stdout, "usage: l2s [-1lsh]\n" );
fprintf( stdout, "\t performs Armin Biere's live-to-safe transformation\n" );
fprintf( stdout, "\t-1 : no shadow logic, presume all loops are self loops\n");
fprintf( stdout, "\t-l : ignore liveness and fairness outputs\n");
fprintf( stdout, "\t-s : ignore safety assertions and assumptions\n");
fprintf( stdout, "\t-h : print command usage\n");
return 1;
}
Aig_Man_t * LivenessToSafetyTransformationWithLTL( int mode, Abc_Ntk_t * pNtk, Aig_Man_t * p,
Vec_Ptr_t *vLive, Vec_Ptr_t *vFair, Vec_Ptr_t *vAssertSafety, Vec_Ptr_t *vAssumeSafety,
int *numLtlProcessed, Vec_Ptr_t *ltlBuffer )
{
Aig_Man_t * pNew;
int i, ii, iii, nRegCount;
Aig_Obj_t * pObjSavePi = NULL;
Aig_Obj_t *pObjSavedLo = NULL, *pObjSavedLi = NULL;
Aig_Obj_t *pObj, *pMatch;
Aig_Obj_t *pObjSaveOrSaved = NULL, *pObjSaveAndNotSaved = NULL, *pObjSavedLoAndEquality;
Aig_Obj_t *pObjShadowLo, *pObjShadowLi, *pObjShadowLiDriver;
Aig_Obj_t *pObjXor, *pObjXnor, *pObjAndAcc;
Aig_Obj_t *pObjLive, *pObjSafetyGate;
Aig_Obj_t *pObjSafetyPropertyOutput;
Aig_Obj_t *pObjOriginalSafetyPropertyOutput;
Aig_Obj_t *pDriverImage, *pArgument, *collectiveAssertSafety, *collectiveAssumeSafety;
Aig_Obj_t *pNegatedSafetyConjunction = NULL;
Aig_Obj_t *pObjSafetyAndLiveToSafety;
char *nodeName, *pFormula;
int piCopied = 0, liCopied = 0, loCopied = 0, liCreated = 0, loCreated = 0, liveLatch = 0;//, piVecIndex = 0, fairLatch = 0;
Vec_Ptr_t *vSignal, *vTopASTNodeArray = NULL;
ltlNode *pEnrtyGLOBALLY;
ltlNode *topNodeOfAST, *tempTopASTNode;
Vec_Vec_t *vAigGFMap;
Vec_Ptr_t *vSignalMemory, *vGFFlopMemory, *vPoForLtlProps = NULL;
Vec_Ptr_t *vecInputLtlFormulae;
vecPis = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
vecPiNames = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
vecLos = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
vecLoNames = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
//****************************************************************
//step0: Parsing the LTL formula
//****************************************************************
//Vec_PtrForEachEntry( char *, pNtk->vLtlProperties, pFormula, i )
// printf("\ninput LTL formula [%d] = %s\n", i, pFormula );
#ifdef MULTIPLE_LTL_FORMULA
//***************************************************************************
//Reading input LTL formulae from Ntk data-structure and creating
//AST for them, Steps involved:
// parsing -> AST creation -> well-formedness check -> signal name check
//***************************************************************************
//resetting numLtlProcessed
*numLtlProcessed = 0;
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
//if( ltlBuffer )
vecInputLtlFormulae = ltlBuffer;
//vecInputLtlFormulae = pNtk->vLtlProperties;
if( vecInputLtlFormulae )
{
vTopASTNodeArray = Vec_PtrAlloc( Vec_PtrSize( vecInputLtlFormulae ) );
printf("\n");
Vec_PtrForEachEntry( char *, vecInputLtlFormulae, pFormula, i )
{
tempTopASTNode = parseFormulaCreateAST( pFormula );
//traverseAbstractSyntaxTree_postFix( tempTopASTNode );
if( tempTopASTNode )
{
printf("Formula %d: AST is created, ", i+1);
if( isWellFormed( tempTopASTNode ) )
printf("Well-formedness check PASSED, ");
else
{
printf("Well-formedness check FAILED!!\n");
printf("AST will be ignored for formula %d, no extra logic will be added for this formula\n", i+1 );
//do memory management to free the created AST
continue;
}
if( checkSignalNameExistence( pNtk, tempTopASTNode ) )
printf("Signal check PASSED\n");
else
{
printf("Signal check FAILED!!");
printf("AST will be ignored for formula %d, no extra logic will be added for this formula\n", i+1 );
//do memory management to free the created AST
continue;
}
Vec_PtrPush( vTopASTNodeArray, tempTopASTNode );
(*numLtlProcessed)++;
}
else
printf("\nNo AST has been created for formula %d, no extra logic will be added\n", i+1 );
}
}
printf("\n");
if( Vec_PtrSize( vTopASTNodeArray ) == 0 )
{
//printf("\nNo AST has been created for any formula; hence the circuit is left untouched\n");
printf("\nCurrently aborting, need to take care when Vec_PtrSize( vTopASTNodeArray ) == 0\n");
exit(0);
}
}
//****************************************************************
// Step1: create the new manager
// Note: The new manager is created with "2 * Aig_ManObjNumMax(p)"
// nodes, but this selection is arbitrary - need to be justified
//****************************************************************
pNew = Aig_ManStart( 2 * Aig_ManObjNumMax(p) );
pNew->pName = (char *)malloc( strlen( pNtk->pName ) + strlen("_l3s") + 1 );
sprintf(pNew->pName, "%s_%s", pNtk->pName, "l3s");
pNew->pSpec = NULL;
//****************************************************************
// Step 2: map constant nodes
//****************************************************************
pObj = Aig_ManConst1( p );
pObj->pData = Aig_ManConst1( pNew );
//****************************************************************
// Step 3: create true PIs
//****************************************************************
Saig_ManForEachPi( p, pObj, i )
{
piCopied++;
pObj->pData = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vecPis, pObj->pData );
nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkPi( pNtk, i ) ));
Vec_PtrPush( vecPiNames, nodeName );
}
//****************************************************************
// Step 4: create the special Pi corresponding to SAVE
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
pObjSavePi = Aig_ObjCreateCi( pNew );
nodeName = "SAVE_BIERE",
Vec_PtrPush( vecPiNames, nodeName );
}
//****************************************************************
// Step 5: create register outputs
//****************************************************************
Saig_ManForEachLo( p, pObj, i )
{
loCopied++;
pObj->pData = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vecLos, pObj->pData );
nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ));
Vec_PtrPush( vecLoNames, nodeName );
}
//****************************************************************
// Step 6: create "saved" register output
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
loCreated++;
pObjSavedLo = Aig_ObjCreateCi( pNew );
Vec_PtrPush( vecLos, pObjSavedLo );
nodeName = "SAVED_LO";
Vec_PtrPush( vecLoNames, nodeName );
}
//****************************************************************
// Step 7: create the OR gate and the AND gate directly fed by "SAVE" Pi
//****************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
pObjSaveOrSaved = Aig_Or( pNew, pObjSavePi, pObjSavedLo );
pObjSaveAndNotSaved = Aig_And( pNew, pObjSavePi, Aig_Not(pObjSavedLo) );
}
//********************************************************************
// Step 8: create internal nodes
//********************************************************************
Aig_ManForEachNode( p, pObj, i )
{
pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
}
//********************************************************************
// Step 8.x : create PO for each safety assertions
// NOTE : Here the output is purposely inverted as it will be thrown to
// dprove
//********************************************************************
assert( pNegatedSafetyConjunction == NULL );
if( mode == FULL_BIERE_MODE || mode == IGNORE_LIVENESS_KEEP_SAFETY_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE)
{
if( Vec_PtrSize( vAssertSafety ) != 0 && Vec_PtrSize( vAssumeSafety ) == 0 )
{
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
pNegatedSafetyConjunction = Aig_Not(pObjAndAcc);
if( mode == FULL_BIERE_MODE || mode == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
pObjOriginalSafetyPropertyOutput = Aig_ObjCreateCo( pNew, Aig_Not(pObjAndAcc) );
}
else if( Vec_PtrSize( vAssertSafety ) != 0 && Vec_PtrSize( vAssumeSafety ) != 0 )
{
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssertSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
collectiveAssertSafety = pObjAndAcc;
pObjAndAcc = Aig_ManConst1( pNew );
Vec_PtrForEachEntry( Aig_Obj_t *, vAssumeSafety, pObj, i )
{
pArgument = Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0( pObj ) );
pObjAndAcc = Aig_And( pNew, pArgument, pObjAndAcc );
}
collectiveAssumeSafety = pObjAndAcc;
pNegatedSafetyConjunction = Aig_And( pNew, Aig_Not(collectiveAssertSafety), collectiveAssumeSafety );
if( mode == FULL_BIERE_MODE || mode == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
pObjOriginalSafetyPropertyOutput = Aig_ObjCreateCo( pNew, Aig_And( pNew, Aig_Not(collectiveAssertSafety), collectiveAssumeSafety ) );
}
else
{
printf("WARNING!! No safety property is found, a new (negated) constant 1 output is created\n");
pNegatedSafetyConjunction = Aig_Not( Aig_ManConst1(pNew) );
if( mode == FULL_BIERE_MODE || mode == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
pObjOriginalSafetyPropertyOutput = Aig_ObjCreateCo( pNew, Aig_Not( Aig_ManConst1(pNew) ) );
}
}
assert( pNegatedSafetyConjunction != NULL );
//********************************************************************
// Step 9: create the safety property output gate for the liveness properties
// discuss with Sat/Alan for an alternative implementation
//********************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
vPoForLtlProps = Vec_PtrAlloc( Vec_PtrSize( vTopASTNodeArray ) );
if( Vec_PtrSize( vTopASTNodeArray ) )
{
//no effective AST for any input LTL property
//must do something graceful
}
for( i=0; i<Vec_PtrSize( vTopASTNodeArray ); i++ )
{
pObjSafetyPropertyOutput = Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
Vec_PtrPush( vPoForLtlProps, pObjSafetyPropertyOutput );
}
}
//*************************************************************************************
// Step 10: Placeholder PO's were created for Liveness property outputs in the
// last step. FYI, # of new liveness property outputs = # of LTL properties in the circuit
// It is time for creation of loop LI's and other stuff
// Now creating register inputs for the original flops
//*************************************************************************************
nRegCount = 0;
Saig_ManForEachLo( p, pObj, i )
{
pMatch = Saig_ObjLoToLi( p, pObj );
Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)Aig_ObjFanin0(pMatch)->pData, Aig_ObjFaninC0( pMatch ) ) );
nRegCount++;
liCopied++;
}
//*************************************************************************************
// Step 11: create register input corresponding to the register "saved"
//*************************************************************************************
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
#ifndef DUPLICATE_CKT_DEBUG
pObjSavedLi = Aig_ObjCreateCo( pNew, pObjSaveOrSaved );
nRegCount++;
liCreated++;
pObjAndAcc = Aig_ManConst1( pNew );
//*************************************************************************************
// Step 11: create the family of shadow registers, then create the cascade of Xnor
// and And gates for the comparator
//*************************************************************************************
Saig_ManForEachLo( p, pObj, i )
{
//printf("\nKEMON RENDY = %s", Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i )) );
//top|route0_target0_queue_with_credit0_queue0
//top|route0_master0_queue2
// if( strcmp( Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ), "top|route0_queue1_num[0]" ) == 0
// || strcmp( Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ), "top|route0_queue1_num[1]" ) == 0 || strcmp( Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ), "top|route0_queue1_num[2]" ) == 0 )
{
pObjShadowLo = Aig_ObjCreateCi( pNew );
#ifdef PROPAGATE_NAMES
Vec_PtrPush( vecLos, pObjShadowLo );
nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ) ) + 10 );
sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ), "SHADOW" );
Vec_PtrPush( vecLoNames, nodeName );
#endif
pObjShadowLiDriver = Aig_Mux( pNew, pObjSaveAndNotSaved, (Aig_Obj_t *)pObj->pData, pObjShadowLo );
pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
nRegCount++;
loCreated++; liCreated++;
pObjXor = Aig_Exor( pNew, (Aig_Obj_t *)pObj->pData, pObjShadowLo );
pObjXnor = Aig_Not( pObjXor );
pObjAndAcc = Aig_And( pNew, pObjXnor, pObjAndAcc );
}
}
// create the AND gate whose output will be the signal "looped"
pObjSavedLoAndEquality = Aig_And( pNew, pObjSavedLo, pObjAndAcc );
// create the master AND gate and corresponding AND and OR logic for the liveness properties
//*************************************************************************************
// Step 11: logic for LTL properties:- (looped & ~theta) where theta is the input ltl
// property
// Description of some data-structure:
//-------------------------------------------------------------------------------------
// Name | Type | Purpose
//-------------------------------------------------------------------------------------
// vSignalMemory | Vec_Ptr_t * | A vector across all ASTs of the LTL properties
// | | It remembers if OR+Latch for GF node has already been
// | | created for a particular signal.
// | |
// vGFFlopMemory | Vec_Ptr_t * | A vector across all ASTs of the LTL properties
// | | remembers if OR+Latch of a GF node has already been created
// | |
// vSignal | Vec_Ptr_t * | vector for each AST; contains pointers from GF nodes
// | | to AIG signals
// | |
// vAigGFMap | Vec_Vec_t * | vAigGFMap[ index ] = vector of GF nodes pointing to
// | | the same AIG node; "index" is the index of that
// | | AIG node in the vector vSignal
//*************************************************************************************
vSignalMemory = Vec_PtrAlloc(10);
vGFFlopMemory = Vec_PtrAlloc(10);
Vec_PtrForEachEntry( ltlNode *, vTopASTNodeArray, topNodeOfAST, iii )
{
vSignal = Vec_PtrAlloc( 10 );
vAigGFMap = Vec_VecAlloc( 10 );
//*************************************************************************************
//Step 11a: for the current AST, find out the leaf level Boolean signal pointers from
// the NEW aig.
//*************************************************************************************
populateBoolWithAigNodePtr( pNtk, p, pNew, topNodeOfAST );
assert( checkAllBoolHaveAIGPointer( topNodeOfAST ) );
//*************************************************************************************
//Step 11b: for each GF node, compute the pointer in AIG that it should point to
// In particular, if the subtree below GF is some Boolean crown (including the case
// of simple negation, create new logic and populate the AIG pointer in GF node
// accordingly
//*************************************************************************************
populateAigPointerUnitGF( pNew, topNodeOfAST, vSignal, vAigGFMap );
//*************************************************************************************
//Step 11c: everything below GF are computed. Now, it is time to create logic for individual
// GF nodes (i.e. the OR gate and the latch and the Boolean crown of the AST
//*************************************************************************************
Vec_PtrForEachEntry( Aig_Obj_t *, vSignal, pObj, i )
{
//*********************************************************
// Step 11c.1: if the OR+Latch of the particular signal is
// not already created, create it. It may have already been
// created from another property, so check it before creation
//*********************************************************
if( Vec_PtrFind( vSignalMemory, pObj ) == -1 )
{
liveLatch++;
pDriverImage = pObj;
pObjShadowLo = Aig_ObjCreateCi( pNew );
pObjShadowLiDriver = Aig_Or( pNew, pObjShadowLo, Aig_And( pNew, pDriverImage, pObjSaveOrSaved ) );
pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
nRegCount++;
loCreated++; liCreated++;
Vec_PtrPush( vSignalMemory, pObj );
Vec_PtrPush( vGFFlopMemory, pObjShadowLo );
#if 1
#ifdef PROPAGATE_NAMES
Vec_PtrPush( vecLos, pObjShadowLo );
//nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ) ) + 12 );
//sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ), "LIVENESS" );
nodeName = (char *)malloc( 20 );
sprintf( nodeName, "n%d__%s", Aig_ObjId(pObjShadowLo), "GF_flop" );
Vec_PtrPush( vecLoNames, nodeName );
#endif
#endif
}
else
pObjShadowLo = (Aig_Obj_t *)Vec_PtrEntry( vGFFlopMemory, Vec_PtrFind( vSignalMemory, pObj ) );
Vec_VecForEachEntryLevel( ltlNode *, vAigGFMap, pEnrtyGLOBALLY, ii, i )
setAIGNodePtrOfGloballyNode( pEnrtyGLOBALLY, pObjShadowLo);
//#ifdef PROPAGATE_NAMES
// Vec_PtrPush( vecLos, pObjShadowLo );
// nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ) ) + 12 );
// sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ), "LIVENESS" );
// Vec_PtrPush( vecLoNames, nodeName );
//#endif
}
//*********************************************************
//Step 11c.2: creating the Boolean crown
//*********************************************************
buildLogicFromLTLNode( pNew, topNodeOfAST );
//*********************************************************
//Step 11c.3: creating logic for (looped & ~theta) and patching
// it with the proper PO
//Note: if ALLOW_SAFETY_PROPERTIES is defined then the final AND
//gate is a conjunction of safety & liveness, i.e. SAFETY & (looped => theta)
//since ABC convention demands a NOT gate at the end, the property logic
//becomes !( SAFETY & (looped => theta) ) = !SAFETY + (looped & !theta)
//*********************************************************
pObjLive = retriveAIGPointerFromLTLNode( topNodeOfAST );
pObjSafetyGate = Aig_And( pNew, pObjSavedLoAndEquality, Aig_Not(pObjLive) );
#ifdef ALLOW_SAFETY_PROPERTIES
printf("liveness output is conjoined with safety assertions\n");
pObjSafetyAndLiveToSafety = Aig_Or( pNew, pObjSafetyGate, pNegatedSafetyConjunction );
pObjSafetyPropertyOutput = (Aig_Obj_t *)Vec_PtrEntry( vPoForLtlProps, iii );
Aig_ObjPatchFanin0( pNew, pObjSafetyPropertyOutput, pObjSafetyAndLiveToSafety );
#else
pObjSafetyPropertyOutput = Vec_PtrEntry( vPoForLtlProps, iii );
Aig_ObjPatchFanin0( pNew, pObjSafetyPropertyOutput, pObjSafetyGate );
#endif
//refreshing vSignal and vAigGFMap arrays
Vec_PtrFree( vSignal );
Vec_VecFree( vAigGFMap );
}
#endif
}
#endif
Aig_ManSetRegNum( pNew, nRegCount );
Aig_ManCiCleanupBiere( pNew );
Aig_ManCoCleanupBiere( pNew );
Aig_ManCleanup( pNew );
assert( Aig_ManCheck( pNew ) );
if( mode == FULL_BIERE_MODE || mode == IGNORE_SAFETY_KEEP_LIVENESS_MODE )
{
assert((Aig_Obj_t *)Vec_PtrEntry(pNew->vCos, Saig_ManPoNum(pNew)+Aig_ObjCioId(pObjSavedLo)-Saig_ManPiNum(p)-1) == pObjSavedLi);
assert( Saig_ManPiNum( p ) + 1 == Saig_ManPiNum( pNew ) );
//assert( Saig_ManRegNum( pNew ) == Saig_ManRegNum( p ) * 2 + 1 + liveLatch + fairLatch );
}
return pNew;
}
int Abc_CommandAbcLivenessToSafetyWithLTL( Abc_Frame_t * pAbc, int argc, char ** argv )
{
FILE * pOut, * pErr;
Abc_Ntk_t * pNtk, * pNtkTemp, *pNtkNew, *pNtkOld;
Aig_Man_t * pAig, *pAigNew = NULL;
int c;
Vec_Ptr_t * vLive, * vFair, *vAssertSafety, *vAssumeSafety;
int directive = -1;
// char *ltfFormulaString = NULL;
int numOfLtlPropOutput;//, LTL_FLAG = 0;
Vec_Ptr_t *ltlBuffer;
pNtk = Abc_FrameReadNtk(pAbc);
pOut = Abc_FrameReadOut(pAbc);
pErr = Abc_FrameReadErr(pAbc);
if( argc == 1 )
{
assert( directive == -1 );
directive = FULL_BIERE_MODE;
}
else
{
Extra_UtilGetoptReset();
while ( ( c = Extra_UtilGetopt( argc, argv, "1slhf" ) ) != EOF )
{
switch( c )
{
case '1':
if( directive == -1 )
directive = FULL_BIERE_ONE_LOOP_MODE;
else
{
assert( directive == IGNORE_LIVENESS_KEEP_SAFETY_MODE || directive == IGNORE_SAFETY_KEEP_LIVENESS_MODE );
if( directive == IGNORE_LIVENESS_KEEP_SAFETY_MODE )
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
else
directive = IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE;
}
break;
case 's':
if( directive == -1 )
directive = IGNORE_SAFETY_KEEP_LIVENESS_MODE;
else
{
if( directive != FULL_BIERE_ONE_LOOP_MODE )
goto usage;
assert(directive == FULL_BIERE_ONE_LOOP_MODE);
directive = IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE;
}
break;
case 'l':
if( directive == -1 )
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
else
{
if( directive != FULL_BIERE_ONE_LOOP_MODE )
goto usage;
assert(directive == FULL_BIERE_ONE_LOOP_MODE);
directive = IGNORE_LIVENESS_KEEP_SAFETY_MODE;
}
break;
case 'f':
//assert( argc >= 3 );
//vecLtlFormula = Vec_PtrAlloc( argc - 2 );
//if( argc >= 3 )
//{
// for( t=3; t<=argc; t++ )
// {
// printf("argv[%d] = %s\n", t-1, argv[t-1]);
// Vec_PtrPush( vecLtlFormula, argv[t-1] );
// }
//}
//printf("argv[argc] = %s\n", argv[argc-1]);
//ltfFormulaString = argv[2];
//LTL_FLAG = 1;
printf("\nILLEGAL FLAG: aborting....\n");
exit(0);
break;
case 'h':
goto usage;
default:
goto usage;
}
}
}
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
if( pAbc->vLTLProperties_global != NULL )
ltlBuffer = pAbc->vLTLProperties_global;
else
ltlBuffer = NULL;
switch( directive )
{
case FULL_BIERE_MODE:
pAigNew = LivenessToSafetyTransformationWithLTL( FULL_BIERE_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety, &numOfLtlPropOutput, ltlBuffer );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t%d POs - one for safety and %d for liveness.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created if the original circuit is combinational\n\tnon-property POs are suppressed\n", numOfLtlPropOutput+1, numOfLtlPropOutput);
break;
case FULL_BIERE_ONE_LOOP_MODE:
pAigNew = LivenessToSafetyTransformationOneStepLoop( FULL_BIERE_ONE_LOOP_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t2 POs - one for safety and one for liveness.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created\n\tnon-property POs are suppressed\n");
break;
case IGNORE_LIVENESS_KEEP_SAFETY_MODE:
pAigNew = LivenessToSafetyTransformationWithLTL( IGNORE_LIVENESS_KEEP_SAFETY_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety, &numOfLtlPropOutput, ltlBuffer );
assert( numOfLtlPropOutput == 0 );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t1 PO - only for safety property; liveness properties are ignored, if any.\n\tno additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created\n\tnon-property POs are suppressed\n");
break;
case IGNORE_SAFETY_KEEP_LIVENESS_MODE:
pAigNew = LivenessToSafetyTransformationWithLTL( IGNORE_SAFETY_KEEP_LIVENESS_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety, &numOfLtlPropOutput, ltlBuffer );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("A new circuit is produced with\n\t%d PO - only for liveness property; safety properties are ignored, if any.\n\tone additional input is added (due to Biere's nondeterminism)\n\tshadow flops are not created if the original circuit is combinational\n\tnon-property POs are suppressed\n", numOfLtlPropOutput);
break;
case IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE:
pAigNew = LivenessToSafetyTransformationOneStepLoop( IGNORE_SAFETY_KEEP_LIVENESS_ONE_LOOP_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced ignoring safety outputs!\nOnly liveness and fairness outputs are considered.\nShadow registers are not created\n");
break;
}
#if 0
if( argc == 1 )
{
pAigNew = LivenessToSafetyTransformation( FULL_BIERE_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced considering all safety, liveness and fairness outputs.\nBiere's logic is created\n");
}
else
{
Extra_UtilGetoptReset();
c = Extra_UtilGetopt( argc, argv, "1lsh" );
if( c == '1' )
{
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
pAigNew = LivenessToSafetyTransformationOneStepLoop( pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
}
else if( c == 'l' )
{
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
pAigNew = LivenessToSafetyTransformation( IGNORE_LIVENESS_KEEP_SAFETY_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced ignoring liveness outputs!\nOnly safety outputs are kept.\nBiere's logic is not created\n");
}
else if( c == 's' )
{
if ( pNtk == NULL )
{
fprintf( pErr, "Empty network.\n" );
return 1;
}
if( !Abc_NtkIsStrash( pNtk ) )
{
printf("The input network was not strashed, strashing....\n");
pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
pNtkOld = pNtkTemp;
pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
else
{
pAig = Abc_NtkToDar( pNtk, 0, 1 );
pNtkOld = pNtk;
vLive = populateLivenessVector( pNtk, pAig );
vFair = populateFairnessVector( pNtk, pAig );
vAssertSafety = populateSafetyAssertionVector( pNtk, pAig );
vAssumeSafety = populateSafetyAssumptionVector( pNtk, pAig );
}
pAigNew = LivenessToSafetyTransformation( IGNORE_SAFETY_KEEP_LIVENESS_MODE, pNtk, pAig, vLive, vFair, vAssertSafety, vAssumeSafety );
if( Aig_ManRegNum(pAigNew) != 0 )
printf("New circuit is produced ignoring safety outputs!\nOnly liveness and fairness outputs are considered.\nBiere's logic is created\n");
}
else if( c == 'h' )
goto usage;
else
goto usage;
}
#endif
#if 0
Aig_ManPrintStats( pAigNew );
printf("\nDetail statistics*************************************\n");
printf("Number of true primary inputs = %d\n", Saig_ManPiNum( pAigNew ));
printf("Number of true primary outputs = %d\n", Saig_ManPoNum( pAigNew ));
printf("Number of true latch outputs = %d\n", Saig_ManCiNum( pAigNew ) - Saig_ManPiNum( pAigNew ));
printf("Number of true latch inputs = %d\n", Saig_ManCoNum( pAigNew ) - Saig_ManPoNum( pAigNew ));
printf("Numer of registers = %d\n", Saig_ManRegNum( pAigNew ) );
printf("\n*******************************************************\n");
#endif
pNtkNew = Abc_NtkFromAigPhase( pAigNew );
pNtkNew->pName = Abc_UtilStrsav( pAigNew->pName );
if ( !Abc_NtkCheck( pNtkNew ) )
fprintf( stdout, "Abc_NtkCreateCone(): Network check has failed.\n" );
updateNewNetworkNameManager( pNtkNew, pAigNew, vecPiNames, vecLoNames );
Abc_FrameSetCurrentNetwork( pAbc, pNtkNew );
#if 0
#ifndef DUPLICATE_CKT_DEBUG
Saig_ManForEachPi( pAigNew, pObj, i )
assert( strcmp( (char *)Vec_PtrEntry(vecPiNames, i), retrieveTruePiName( pNtk, pAig, pAigNew, pObj ) ) == 0 );
//printf("Name of %d-th Pi = %s, %s\n", i, retrieveTruePiName( pNtk, pAig, pAigNew, pObj ), (char *)Vec_PtrEntry(vecPiNames, i) );
Saig_ManForEachLo( pAigNew, pObj, i )
assert( strcmp( (char *)Vec_PtrEntry(vecLoNames, i), retrieveLOName( pNtk, pAig, pAigNew, pObj, vLive, vFair ) ) == 0 );
#endif
#endif
return 0;
usage:
fprintf( stdout, "usage: l3s [-1lsh]\n" );
fprintf( stdout, "\t performs Armin Biere's live-to-safe transformation\n" );
fprintf( stdout, "\t-1 : no shadow logic, presume all loops are self loops\n");
fprintf( stdout, "\t-l : ignore liveness and fairness outputs\n");
fprintf( stdout, "\t-s : ignore safety assertions and assumptions\n");
fprintf( stdout, "\t-h : print command usage\n");
return 1;
}
ABC_NAMESPACE_IMPL_END