/**CFile**************************************************************** FileName [wlcAbs2.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Verilog parser.] Synopsis [Abstraction for word-level networks.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - August 22, 2014.] Revision [$Id: wlcAbs2.c,v 1.00 2014/09/12 00:00:00 alanmi Exp $] ***********************************************************************/ #include "wlc.h" #include "proof/pdr/pdr.h" #include "aig/gia/giaAig.h" #include "sat/bmc/bmc.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Mark operators that meet the abstraction criteria.] Description [This procedure returns the array of objects (vLeaves) that should be abstracted because of their high bit-width. It uses input array (vUnmark) to not abstract those objects that have been refined in the previous rounds.] SideEffects [] SeeAlso [] ***********************************************************************/ static Vec_Bit_t * Wlc_NtkAbsMarkOpers( Wlc_Ntk_t * p, Wlc_Par_t * pPars, Vec_Bit_t * vUnmark, int fVerbose ) { Vec_Bit_t * vLeaves = Vec_BitStart( Wlc_NtkObjNumMax(p) ); Wlc_Obj_t * pObj; int i, Count[4] = {0}; Wlc_NtkForEachObj( p, pObj, i ) { if ( vUnmark && Vec_BitEntry(vUnmark, i) ) // not allow this object to be abstracted away continue; if ( pObj->Type == WLC_OBJ_ARI_ADD || pObj->Type == WLC_OBJ_ARI_SUB || pObj->Type == WLC_OBJ_ARI_MINUS ) { if ( Wlc_ObjRange(pObj) >= pPars->nBitsAdd ) Vec_BitWriteEntry( vLeaves, Wlc_ObjId(p, pObj), 1 ), Count[0]++; continue; } if ( pObj->Type == WLC_OBJ_ARI_MULTI || pObj->Type == WLC_OBJ_ARI_DIVIDE || pObj->Type == WLC_OBJ_ARI_REM || pObj->Type == WLC_OBJ_ARI_MODULUS ) { if ( Wlc_ObjRange(pObj) >= pPars->nBitsMul ) Vec_BitWriteEntry( vLeaves, Wlc_ObjId(p, pObj), 1 ), Count[1]++; continue; } if ( pObj->Type == WLC_OBJ_MUX ) { if ( Wlc_ObjRange(pObj) >= pPars->nBitsMux ) Vec_BitWriteEntry( vLeaves, Wlc_ObjId(p, pObj), 1 ), Count[2]++; continue; } if ( Wlc_ObjIsCi(pObj) && !Wlc_ObjIsPi(pObj) ) { if ( Wlc_ObjRange(pObj) >= pPars->nBitsFlop ) Vec_BitWriteEntry( vLeaves, Wlc_ObjId(p, pObj), 1 ), Count[3]++; continue; } } if ( fVerbose ) printf( "Abstraction engine marked %d adds/subs, %d muls/divs, %d muxes, and %d flops to be abstracted away.\n", Count[0], Count[1], Count[2], Count[3] ); return vLeaves; } /**Function************************************************************* Synopsis [Marks nodes to be included in the abstracted network.] Description [Marks all objects that will be included in the abstracted model. Stops at the objects (vLeaves) that are abstracted away. Returns three arrays: a subset of original PIs (vPisOld), a subset of pseudo-PIs (vPisNew) and the set of flops present as flops in the abstracted network.] SideEffects [] SeeAlso [] ***********************************************************************/ static void Wlc_NtkAbsMarkNodes_rec( Wlc_Ntk_t * p, Wlc_Obj_t * pObj, Vec_Bit_t * vLeaves, Vec_Int_t * vPisOld, Vec_Int_t * vPisNew, Vec_Int_t * vFlops ) { int i, iFanin; if ( pObj->Mark ) return; pObj->Mark = 1; if ( Vec_BitEntry(vLeaves, Wlc_ObjId(p, pObj)) ) { assert( !Wlc_ObjIsPi(pObj) ); Vec_IntPush( vPisNew, Wlc_ObjId(p, pObj) ); return; } if ( Wlc_ObjIsCi(pObj) ) { if ( Wlc_ObjIsPi(pObj) ) Vec_IntPush( vPisOld, Wlc_ObjId(p, pObj) ); else Vec_IntPush( vFlops, Wlc_ObjId(p, pObj) ); return; } Wlc_ObjForEachFanin( pObj, iFanin, i ) Wlc_NtkAbsMarkNodes_rec( p, Wlc_NtkObj(p, iFanin), vLeaves, vPisOld, vPisNew, vFlops ); } static void Wlc_NtkAbsMarkNodes( Wlc_Ntk_t * p, Vec_Bit_t * vLeaves, Vec_Int_t * vPisOld, Vec_Int_t * vPisNew, Vec_Int_t * vFlops ) { Wlc_Obj_t * pObj; int i, Count = 0; Wlc_NtkCleanMarks( p ); Wlc_NtkForEachCo( p, pObj, i ) Wlc_NtkAbsMarkNodes_rec( p, pObj, vLeaves, vPisOld, vPisNew, vFlops ); Wlc_NtkForEachObjVec( vFlops, p, pObj, i ) Wlc_NtkAbsMarkNodes_rec( p, Wlc_ObjFo2Fi(p, pObj), vLeaves, vPisOld, vPisNew, vFlops ); Wlc_NtkForEachObj( p, pObj, i ) Count += pObj->Mark; // printf( "Collected %d old PIs, %d new PIs, %d flops, and %d other objects.\n", // Vec_IntSize(vPisOld), Vec_IntSize(vPisNew), Vec_IntSize(vFlops), // Count - Vec_IntSize(vPisOld) - Vec_IntSize(vPisNew) - Vec_IntSize(vFlops) ); Vec_IntSort( vPisOld, 0 ); Vec_IntSort( vPisNew, 0 ); Vec_IntSort( vFlops, 0 ); Wlc_NtkCleanMarks( p ); } /**Function************************************************************* Synopsis [Derive word-level abstracted model based on the parameter values.] Description [Retuns the word-level abstracted network and the set of pseudo-PIs (vPisNew), which were created during abstraction. If the abstraction is satisfiable, some of the pseudo-PIs will be un-abstracted. These pseudo-PIs and their MFFC cones will be listed in the array (vUnmark), which will force the abstraction to not stop at these pseudo-PIs in the future.] SideEffects [] SeeAlso [] ***********************************************************************/ static Wlc_Ntk_t * Wlc_NtkAbs( Wlc_Ntk_t * p, Wlc_Par_t * pPars, Vec_Bit_t * vUnmark, Vec_Int_t ** pvPisNew, int fVerbose ) { Wlc_Ntk_t * pNtkNew = NULL; Vec_Int_t * vPisOld = Vec_IntAlloc( 100 ); Vec_Int_t * vPisNew = Vec_IntAlloc( 100 ); Vec_Int_t * vFlops = Vec_IntAlloc( 100 ); Vec_Bit_t * vLeaves = Wlc_NtkAbsMarkOpers( p, pPars, vUnmark, fVerbose ); Wlc_NtkAbsMarkNodes( p, vLeaves, vPisOld, vPisNew, vFlops ); Vec_BitFree( vLeaves ); pNtkNew = Wlc_NtkDupDfsAbs( p, vPisOld, vPisNew, vFlops ); Vec_IntFree( vPisOld ); Vec_IntFree( vFlops ); if ( pvPisNew ) *pvPisNew = vPisNew; else Vec_IntFree( vPisNew ); return pNtkNew; } /**Function************************************************************* Synopsis [Find what objects need to be un-abstracted.] Description [Returns a subset of pseudo-PIs (vPisNew), which will be prevented from being abstracted in the future rounds of abstraction. The AIG manager (pGia) is a bit-level view of the abstracted model. The counter-example (pCex) is used to find waht PPIs to refine.] SideEffects [] SeeAlso [] ***********************************************************************/ static Vec_Int_t * Wlc_NtkAbsRefinement( Wlc_Ntk_t * p, Gia_Man_t * pGia, Abc_Cex_t * pCex, Vec_Int_t * vPisNew ) { Vec_Int_t * vRefine = Vec_IntAlloc( 100 ); Abc_Cex_t * pCexCare; Wlc_Obj_t * pObj; // count the number of bit-level PPIs and map them into word-level objects they were derived from int f, i, b, nRealPis, nPpiBits = 0; Vec_Int_t * vMap = Vec_IntStartFull( pCex->nPis ); Wlc_NtkForEachObjVec( vPisNew, p, pObj, i ) for ( b = 0; b < Wlc_ObjRange(pObj); b++ ) Vec_IntWriteEntry( vMap, nPpiBits++, Wlc_ObjId(p, pObj) ); // since PPIs are ordered last, the previous bits are real PIs nRealPis = pCex->nPis - nPpiBits; // find the care-set pCexCare = Bmc_CexCareMinimizeAig( pGia, nRealPis, pCex, 1, 0, 0 ); assert( pCexCare->nPis == pCex->nPis ); // detect care PPIs for ( f = 0; f <= pCexCare->iFrame; f++ ) for ( i = nRealPis; i < pCexCare->nPis; i++ ) if ( Abc_InfoHasBit(pCexCare->pData, pCexCare->nRegs + pCexCare->nPis * f + i) ) Vec_IntPushUniqueOrder( vRefine, Vec_IntEntry(vMap, i-nRealPis) ); Abc_CexFree( pCexCare ); Vec_IntFree( vMap ); if ( Vec_IntSize(vRefine) == 0 )// real CEX Vec_IntFreeP( &vRefine ); return vRefine; } /**Function************************************************************* Synopsis [Mark MFFC cones of the un-abstracted objects.] Description [The MFFC cones of the objects in vRefine are traversed and all their nodes are marked in vUnmark.] SideEffects [] SeeAlso [] ***********************************************************************/ static int Wlc_NtkNodeDeref_rec( Wlc_Ntk_t * p, Wlc_Obj_t * pNode, Vec_Bit_t * vUnmark ) { int i, Fanin, Counter = 1; if ( Wlc_ObjIsCi(pNode) ) return 0; Vec_BitWriteEntry( vUnmark, Wlc_ObjId(p, pNode), 1 ); Wlc_ObjForEachFanin( pNode, Fanin, i ) { Vec_IntAddToEntry( &p->vRefs, Fanin, -1 ); if ( Vec_IntEntry(&p->vRefs, Fanin) == 0 ) Counter += Wlc_NtkNodeDeref_rec( p, Wlc_NtkObj(p, Fanin), vUnmark ); } return Counter; } static int Wlc_NtkNodeRef_rec( Wlc_Ntk_t * p, Wlc_Obj_t * pNode ) { int i, Fanin, Counter = 1; if ( Wlc_ObjIsCi(pNode) ) return 0; Wlc_ObjForEachFanin( pNode, Fanin, i ) { if ( Vec_IntEntry(&p->vRefs, Fanin) == 0 ) Counter += Wlc_NtkNodeRef_rec( p, Wlc_NtkObj(p, Fanin) ); Vec_IntAddToEntry( &p->vRefs, Fanin, 1 ); } return Counter; } static int Wlc_NtkMarkMffc( Wlc_Ntk_t * p, Wlc_Obj_t * pNode, Vec_Bit_t * vUnmark ) { int Count1, Count2; // if this is a flop output, compute MFFC of the corresponding flop input while ( Wlc_ObjIsCi(pNode) ) { Vec_BitWriteEntry( vUnmark, Wlc_ObjId(p, pNode), 1 ); pNode = Wlc_ObjFo2Fi(p, pNode); } assert( !Wlc_ObjIsCi(pNode) ); // dereference the node (and set the bits in vUnmark) Count1 = Wlc_NtkNodeDeref_rec( p, pNode, vUnmark ); // reference it back Count2 = Wlc_NtkNodeRef_rec( p, pNode ); assert( Count1 == Count2 ); return Count1; } static int Wlc_NtkRemoveFromAbstraction( Wlc_Ntk_t * p, Vec_Int_t * vRefine, Vec_Bit_t * vUnmark ) { Wlc_Obj_t * pObj; int i, nNodes = 0; if ( Vec_IntSize(&p->vRefs) == 0 ) Wlc_NtkSetRefs( p ); Wlc_NtkForEachObjVec( vRefine, p, pObj, i ) nNodes += Wlc_NtkMarkMffc( p, pObj, vUnmark ); return nNodes; } /**Function************************************************************* Synopsis [Performs abstraction.] Description [Derives initial abstraction based on user-specified parameter values, which tell what is the smallest bit-width of a primitive that is being abstracted away. Currently only add/sub, mul/div, mux, and flop are supported with individual parameters. The second step is to refine the initial abstraction until the point when the property is proved.] SideEffects [] SeeAlso [] ***********************************************************************/ int Wlc_NtkAbsCore2( Wlc_Ntk_t * p, Wlc_Par_t * pPars ) { abctime clk = Abc_Clock(); int nIters, nNodes, nDcFlops, RetValue = -1; // start the bitmap to mark objects that cannot be abstracted because of refinement // currently, this bitmap is empty because abstraction begins without refinement Vec_Bit_t * vUnmark = Vec_BitStart( Wlc_NtkObjNumMax(p) ); // set up parameters to run PDR Pdr_Par_t PdrPars, * pPdrPars = &PdrPars; Pdr_ManSetDefaultParams( pPdrPars ); pPdrPars->fUseAbs = 1; // use 'pdr -t' (on-the-fly abstraction) pPdrPars->fCtgs = 1; // use 'pdr -nc' (improved generalization) pPdrPars->fSkipDown = 0; // use 'pdr -nc' (improved generalization) //pPdrPars->nRestLimit = 500; // reset queue or proof-obligations when it gets larger than this pPdrPars->fVerbose = pPars->fPdrVerbose; // perform refinement iterations for ( nIters = 1; nIters < pPars->nIterMax; nIters++ ) { Aig_Man_t * pAig; Abc_Cex_t * pCex; Vec_Int_t * vPisNew, * vRefine; Gia_Man_t * pGia, * pTemp; Wlc_Ntk_t * pAbs; if ( pPars->fVerbose ) printf( "\nIteration %d:\n", nIters ); // get abstracted GIA and the set of pseudo-PIs (vPisNew) pAbs = Wlc_NtkAbs( p, pPars, vUnmark, &vPisNew, pPars->fVerbose ); pGia = Wlc_NtkBitBlast( pAbs, NULL ); // if the abstraction has flops with DC-init state, // new PIs were introduced by bit-blasting at the end of the PI list // here we move these variables to be *before* PPIs, because // PPIs are supposed to be at the end of the PI list for refinement nDcFlops = Wlc_NtkDcFlopNum(pAbs); if ( nDcFlops > 0 ) // DC-init flops are present { pGia = Gia_ManPermuteInputs( pTemp = pGia, Wlc_NtkCountObjBits(p, vPisNew), nDcFlops ); Gia_ManStop( pTemp ); } // if the word-level outputs have to be XORs, this is a place to do it if ( pPars->fXorOutput ) { pGia = Gia_ManTransformMiter2( pTemp = pGia ); Gia_ManStop( pTemp ); } if ( pPars->fVerbose ) { printf( "Derived abstraction with %d objects and %d PPIs. Bit-blasted AIG stats are:\n", Wlc_NtkObjNum(pAbs), Vec_IntSize(vPisNew) ); Gia_ManPrintStats( pGia, NULL ); } Wlc_NtkFree( pAbs ); // try to prove abstracted GIA by converting it to AIG and calling PDR pAig = Gia_ManToAigSimple( pGia ); RetValue = Pdr_ManSolve( pAig, pPdrPars ); pCex = pAig->pSeqModel; pAig->pSeqModel = NULL; Aig_ManStop( pAig ); // consider outcomes if ( pCex == NULL ) { assert( RetValue ); // proved or undecided Gia_ManStop( pGia ); Vec_IntFree( vPisNew ); break; } // perform refinement vRefine = Wlc_NtkAbsRefinement( p, pGia, pCex, vPisNew ); Gia_ManStop( pGia ); Vec_IntFree( vPisNew ); if ( vRefine == NULL ) // real CEX { Abc_CexFree( pCex ); // return CEX in the future break; } // update the set of objects to be un-abstracted nNodes = Wlc_NtkRemoveFromAbstraction( p, vRefine, vUnmark ); if ( pPars->fVerbose ) printf( "Refinement of CEX in frame %d came up with %d un-abstacted PPIs, whose MFFCs include %d objects.\n", pCex->iFrame, Vec_IntSize(vRefine), nNodes ); Vec_IntFree( vRefine ); Abc_CexFree( pCex ); } Vec_BitFree( vUnmark ); // report the result if ( pPars->fVerbose ) printf( "\n" ); printf( "Abstraction " ); if ( RetValue == 0 ) printf( "resulted in a real CEX" ); else if ( RetValue == 1 ) printf( "is successfully proved" ); else printf( "timed out" ); printf( " after %d iterations. ", nIters ); Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); return RetValue; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END