/**CFile**************************************************************** FileName [ifSelect.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [FPGA mapping based on priority cuts.] Synopsis [Cut selection procedures.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - November 21, 2006.] Revision [$Id: ifSelect.c,v 1.00 2006/11/21 00:00:00 alanmi Exp $] ***********************************************************************/ #include "if.h" #include "sat/bsat/satSolver.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Prints the logic cone with choices.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void If_ObjConePrint_rec( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Ptr_t * vVisited ) { If_Cut_t * pCut; pCut = If_ObjCutBest(pIfObj); if ( If_CutDataInt(pCut) ) return; Vec_PtrPush( vVisited, pCut ); // insert the worst case If_CutSetDataInt( pCut, ~0 ); // skip in case of primary input if ( If_ObjIsCi(pIfObj) ) return; // compute the functions of the children if ( pIfObj->pEquiv ) If_ObjConePrint_rec( pIfMan, pIfObj->pEquiv, vVisited ); If_ObjConePrint_rec( pIfMan, pIfObj->pFanin0, vVisited ); If_ObjConePrint_rec( pIfMan, pIfObj->pFanin1, vVisited ); printf( "%5d = %5d & %5d | %5d\n", pIfObj->Id, pIfObj->pFanin0->Id, pIfObj->pFanin1->Id, pIfObj->pEquiv ? pIfObj->pEquiv->Id : 0 ); } void If_ObjConePrint( If_Man_t * pIfMan, If_Obj_t * pIfObj ) { If_Cut_t * pCut; If_Obj_t * pLeaf; int i; Vec_PtrClear( pIfMan->vTemp ); If_ObjConePrint_rec( pIfMan, pIfObj, pIfMan->vTemp ); Vec_PtrForEachEntry( If_Cut_t *, pIfMan->vTemp, pCut, i ) If_CutSetDataInt( pCut, 0 ); // print the leaf variables printf( "Cut " ); pCut = If_ObjCutBest(pIfObj); If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) printf( "%d ", pLeaf->Id ); printf( "\n" ); } /**Function************************************************************* Synopsis [Recursively derives local AIG for the cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int If_ManNodeShapeMap_rec( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Ptr_t * vVisited, Vec_Int_t * vShape ) { If_Cut_t * pCut; If_Obj_t * pTemp; int i, iFunc0, iFunc1; // get the best cut pCut = If_ObjCutBest(pIfObj); // if the cut is visited, return the result if ( If_CutDataInt(pCut) ) return If_CutDataInt(pCut); // mark the node as visited Vec_PtrPush( vVisited, pCut ); // insert the worst case If_CutSetDataInt( pCut, ~0 ); // skip in case of primary input if ( If_ObjIsCi(pIfObj) ) return If_CutDataInt(pCut); // compute the functions of the children for ( i = 0, pTemp = pIfObj; pTemp; pTemp = pTemp->pEquiv, i++ ) { iFunc0 = If_ManNodeShapeMap_rec( pIfMan, pTemp->pFanin0, vVisited, vShape ); if ( iFunc0 == ~0 ) continue; iFunc1 = If_ManNodeShapeMap_rec( pIfMan, pTemp->pFanin1, vVisited, vShape ); if ( iFunc1 == ~0 ) continue; // both branches are solved Vec_IntPush( vShape, pIfObj->Id ); Vec_IntPush( vShape, pTemp->Id ); If_CutSetDataInt( pCut, 1 ); break; } return If_CutDataInt(pCut); } int If_ManNodeShapeMap( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Int_t * vShape ) { If_Cut_t * pCut; If_Obj_t * pLeaf; int i, iRes; // get the best cut pCut = If_ObjCutBest(pIfObj); assert( pCut->nLeaves > 1 ); // set the leaf variables If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) { assert( If_CutDataInt( If_ObjCutBest(pLeaf) ) == 0 ); If_CutSetDataInt( If_ObjCutBest(pLeaf), 1 ); } // recursively compute the function while collecting visited cuts Vec_IntClear( vShape ); Vec_PtrClear( pIfMan->vTemp ); iRes = If_ManNodeShapeMap_rec( pIfMan, pIfObj, pIfMan->vTemp, vShape ); if ( iRes == ~0 ) { Abc_Print( -1, "If_ManNodeShapeMap(): Computing local AIG has failed.\n" ); return 0; } // clean the cuts If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) If_CutSetDataInt( If_ObjCutBest(pLeaf), 0 ); Vec_PtrForEachEntry( If_Cut_t *, pIfMan->vTemp, pCut, i ) If_CutSetDataInt( pCut, 0 ); return 1; } /**Function************************************************************* Synopsis [Recursively derives the local AIG for the cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline int If_WordCountOnes( unsigned uWord ) { uWord = (uWord & 0x55555555) + ((uWord>>1) & 0x55555555); uWord = (uWord & 0x33333333) + ((uWord>>2) & 0x33333333); uWord = (uWord & 0x0F0F0F0F) + ((uWord>>4) & 0x0F0F0F0F); uWord = (uWord & 0x00FF00FF) + ((uWord>>8) & 0x00FF00FF); return (uWord & 0x0000FFFF) + (uWord>>16); } int If_ManNodeShapeMap2_rec( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Ptr_t * vVisited, Vec_Int_t * vShape ) { If_Cut_t * pCut; If_Obj_t * pTemp, * pTempBest = NULL; int i, iFunc, iFunc0, iFunc1, iBest = 0; // get the best cut pCut = If_ObjCutBest(pIfObj); // if the cut is visited, return the result if ( If_CutDataInt(pCut) ) return If_CutDataInt(pCut); // mark the node as visited Vec_PtrPush( vVisited, pCut ); // insert the worst case If_CutSetDataInt( pCut, ~0 ); // skip in case of primary input if ( If_ObjIsCi(pIfObj) ) return If_CutDataInt(pCut); // compute the functions of the children for ( i = 0, pTemp = pIfObj; pTemp; pTemp = pTemp->pEquiv, i++ ) { iFunc0 = If_ManNodeShapeMap2_rec( pIfMan, pTemp->pFanin0, vVisited, vShape ); if ( iFunc0 == ~0 ) continue; iFunc1 = If_ManNodeShapeMap2_rec( pIfMan, pTemp->pFanin1, vVisited, vShape ); if ( iFunc1 == ~0 ) continue; iFunc = iFunc0 | iFunc1; // if ( If_WordCountOnes(iBest) <= If_WordCountOnes(iFunc) ) if ( iBest < iFunc ) { iBest = iFunc; pTempBest = pTemp; } } if ( pTempBest ) { Vec_IntPush( vShape, pIfObj->Id ); Vec_IntPush( vShape, pTempBest->Id ); If_CutSetDataInt( pCut, iBest ); } return If_CutDataInt(pCut); } int If_ManNodeShapeMap2( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Int_t * vShape ) { If_Cut_t * pCut; If_Obj_t * pLeaf; int i, iRes; // get the best cut pCut = If_ObjCutBest(pIfObj); assert( pCut->nLeaves > 1 ); // set the leaf variables If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) If_CutSetDataInt( If_ObjCutBest(pLeaf), (1 << i) ); // recursively compute the function while collecting visited cuts Vec_IntClear( vShape ); Vec_PtrClear( pIfMan->vTemp ); iRes = If_ManNodeShapeMap2_rec( pIfMan, pIfObj, pIfMan->vTemp, vShape ); if ( iRes == ~0 ) { Abc_Print( -1, "If_ManNodeShapeMap2(): Computing local AIG has failed.\n" ); return 0; } // clean the cuts If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) If_CutSetDataInt( If_ObjCutBest(pLeaf), 0 ); Vec_PtrForEachEntry( If_Cut_t *, pIfMan->vTemp, pCut, i ) If_CutSetDataInt( pCut, 0 ); return 1; } /**Function************************************************************* Synopsis [Collects logic cone with choices] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int If_ManConeCollect_rec( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Ptr_t * vVisited, Vec_Ptr_t * vCone ) { If_Cut_t * pCut; If_Obj_t * pTemp; int iFunc0, iFunc1; int fRootAdded = 0; int fNodeAdded = 0; // get the best cut pCut = If_ObjCutBest(pIfObj); // if the cut is visited, return the result if ( If_CutDataInt(pCut) ) return If_CutDataInt(pCut); // mark the node as visited Vec_PtrPush( vVisited, pCut ); // insert the worst case If_CutSetDataInt( pCut, ~0 ); // skip in case of primary input if ( If_ObjIsCi(pIfObj) ) return If_CutDataInt(pCut); // compute the functions of the children for ( pTemp = pIfObj; pTemp; pTemp = pTemp->pEquiv ) { iFunc0 = If_ManConeCollect_rec( pIfMan, pTemp->pFanin0, vVisited, vCone ); if ( iFunc0 == ~0 ) continue; iFunc1 = If_ManConeCollect_rec( pIfMan, pTemp->pFanin1, vVisited, vCone ); if ( iFunc1 == ~0 ) continue; fNodeAdded = 1; If_CutSetDataInt( pCut, 1 ); Vec_PtrPush( vCone, pTemp ); if ( fRootAdded == 0 && pTemp == pIfObj ) fRootAdded = 1; } if ( fNodeAdded && !fRootAdded ) Vec_PtrPush( vCone, pIfObj ); return If_CutDataInt(pCut); } Vec_Ptr_t * If_ManConeCollect( If_Man_t * pIfMan, If_Obj_t * pIfObj, If_Cut_t * pCut ) { Vec_Ptr_t * vCone; If_Obj_t * pLeaf; int i, RetValue; // set the leaf variables If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) { assert( If_CutDataInt( If_ObjCutBest(pLeaf) ) == 0 ); If_CutSetDataInt( If_ObjCutBest(pLeaf), 1 ); } // recursively compute the function while collecting visited cuts vCone = Vec_PtrAlloc( 100 ); Vec_PtrClear( pIfMan->vTemp ); RetValue = If_ManConeCollect_rec( pIfMan, pIfObj, pIfMan->vTemp, vCone ); assert( RetValue ); // clean the cuts If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) If_CutSetDataInt( If_ObjCutBest(pLeaf), 0 ); Vec_PtrForEachEntry( If_Cut_t *, pIfMan->vTemp, pCut, i ) If_CutSetDataInt( pCut, 0 ); return vCone; } /**Function************************************************************* Synopsis [Adding clauses.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline void sat_solver_add_choice( sat_solver * pSat, int iVar, Vec_Int_t * vVars ) { int * pVars = Vec_IntArray(vVars); int nVars = Vec_IntSize(vVars); int i, k, Lits[2], Value; assert( Vec_IntSize(vVars) < Vec_IntCap(vVars) ); // create literals for ( i = 0; i < nVars; i++ ) pVars[i] = Abc_Var2Lit( pVars[i], 0 ); pVars[i] = Abc_Var2Lit( iVar, 1 ); // add clause Value = sat_solver_addclause( pSat, pVars, pVars + nVars + 1 ); assert( Value ); // undo literals for ( i = 0; i < nVars; i++ ) pVars[i] = Abc_Lit2Var( pVars[i] ); // add !out => !in Lits[0] = Abc_Var2Lit( iVar, 0 ); for ( i = 0; i < nVars; i++ ) { Lits[1] = Abc_Var2Lit( pVars[i], 1 ); Value = sat_solver_addclause( pSat, Lits, Lits + 2 ); assert( Value ); } // add excluvisity for ( i = 0; i < nVars; i++ ) for ( k = i+1; k < nVars; k++ ) { Lits[0] = Abc_Var2Lit( pVars[i], 1 ); Lits[1] = Abc_Var2Lit( pVars[k], 1 ); Value = sat_solver_addclause( pSat, Lits, Lits + 2 ); assert( Value ); } } static inline int If_ObjSatVar( If_Obj_t * pIfObj ) { return If_CutDataInt(If_ObjCutBest(pIfObj)); } static inline void If_ObjSetSatVar( If_Obj_t * pIfObj, int v ) { If_CutSetDataInt( If_ObjCutBest(pIfObj), v ); } /**Function************************************************************* Synopsis [Recursively derives the local AIG for the cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void If_ManNodeShape2_rec( sat_solver * pSat, If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Int_t * vShape ) { If_Obj_t * pTemp; assert( sat_solver_var_value(pSat, If_ObjSatVar(pIfObj)) == 1 ); if ( pIfObj->fMark ) return; pIfObj->fMark = 1; for ( pTemp = pIfObj; pTemp; pTemp = pTemp->pEquiv ) if ( sat_solver_var_value(pSat, If_ObjSatVar(pTemp)+1) == 1 ) break; assert( pTemp != NULL ); If_ManNodeShape2_rec( pSat, pIfMan, pTemp->pFanin0, vShape ); If_ManNodeShape2_rec( pSat, pIfMan, pTemp->pFanin1, vShape ); Vec_IntPush( vShape, pIfObj->Id ); Vec_IntPush( vShape, pTemp->Id ); } /**Function************************************************************* Synopsis [Solve the problem of selecting choices for the given cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int If_ManNodeShapeSat( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Int_t * vShape ) { sat_solver * pSat; If_Cut_t * pCut; Vec_Ptr_t * vCone; Vec_Int_t * vFanins; If_Obj_t * pObj, * pTemp; int i, Lit, Status; // get best cut pCut = If_ObjCutBest(pIfObj); assert( pCut->nLeaves > 1 ); // collect the cone vCone = If_ManConeCollect( pIfMan, pIfObj, pCut ); // assign SAT variables // EXTERNAL variable is even numbered // INTERNAL variable is odd numbered If_CutForEachLeaf( pIfMan, pCut, pObj, i ) { assert( If_ObjSatVar(pObj) == 0 ); If_ObjSetSatVar( pObj, 2*(i+1) ); } Vec_PtrForEachEntry( If_Obj_t *, vCone, pObj, i ) { assert( If_ObjSatVar(pObj) == 0 ); If_ObjSetSatVar( pObj, 2*(i+1+pCut->nLeaves) ); } // start SAT solver pSat = sat_solver_new(); sat_solver_setnvars( pSat, 2 * (pCut->nLeaves + Vec_PtrSize(vCone) + 1) ); // add constraints vFanins = Vec_IntAlloc( 100 ); Vec_PtrForEachEntry( If_Obj_t *, vCone, pObj, i ) { assert( If_ObjIsAnd(pObj) ); Vec_IntClear( vFanins ); for ( pTemp = pObj; pTemp; pTemp = pTemp->pEquiv ) if ( If_ObjSatVar(pTemp) ) Vec_IntPush( vFanins, If_ObjSatVar(pTemp)+1 ); // internal assert( Vec_IntSize(vFanins) > 0 ); sat_solver_add_choice( pSat, If_ObjSatVar(pObj), vFanins ); // external assert( If_ObjSatVar(pObj) > 0 ); // sat_solver_add_and( pSat, If_ObjSatVar(pObj)+1, If_ObjSatVar(pObj->pFanin0), If_ObjSatVar(pObj->pFanin1), 0, 0, 0 ); if ( If_ObjSatVar(pObj->pFanin0) > 0 && If_ObjSatVar(pObj->pFanin1) > 0 ) { int Lits[2]; Lits[0] = Abc_Var2Lit( If_ObjSatVar(pObj)+1, 1 ); Lits[1] = Abc_Var2Lit( If_ObjSatVar(pObj->pFanin0), 0 ); Status = sat_solver_addclause( pSat, Lits, Lits + 2 ); assert( Status ); Lits[0] = Abc_Var2Lit( If_ObjSatVar(pObj)+1, 1 ); Lits[1] = Abc_Var2Lit( If_ObjSatVar(pObj->pFanin1), 0 ); Status = sat_solver_addclause( pSat, Lits, Lits + 2 ); assert( Status ); } } Vec_IntFree( vFanins ); // set cut variables to 1 pCut = If_ObjCutBest(pIfObj); If_CutForEachLeaf( pIfMan, pCut, pObj, i ) { Lit = Abc_Var2Lit( If_ObjSatVar(pObj), 0 ); // external Status = sat_solver_addclause( pSat, &Lit, &Lit + 1 ); assert( Status ); } // set output variable to 1 Lit = Abc_Var2Lit( If_ObjSatVar(pIfObj), 0 ); // external Status = sat_solver_addclause( pSat, &Lit, &Lit + 1 ); assert( Status ); // solve the problem Status = sat_solver_solve( pSat, NULL, NULL, 0, 0, 0, 0 ); assert( Status == l_True ); // mark cut nodes If_CutForEachLeaf( pIfMan, pCut, pObj, i ) { assert( pObj->fMark == 0 ); pObj->fMark = 1; } // select the node's shape Vec_IntClear( vShape ); assert( pIfObj->fMark == 0 ); If_ManNodeShape2_rec( pSat, pIfMan, pIfObj, vShape ); // cleanup sat_solver_delete( pSat ); If_CutForEachLeaf( pIfMan, pCut, pObj, i ) { If_ObjSetSatVar( pObj, 0 ); pObj->fMark = 0; } Vec_PtrForEachEntry( If_Obj_t *, vCone, pObj, i ) { If_ObjSetSatVar( pObj, 0 ); pObj->fMark = 0; } Vec_PtrFree( vCone ); return 1; } /**Function************************************************************* Synopsis [Verify that the shape is correct.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int If_ManCheckShape( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Int_t * vShape ) { If_Cut_t * pCut; If_Obj_t * pLeaf; int i, Entry1, Entry2, RetValue = 1; // check that the marks are not set pCut = If_ObjCutBest(pIfObj); If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) assert( pLeaf->fMark == 0 ); // set the marks of the shape Vec_IntForEachEntryDouble( vShape, Entry1, Entry2, i ) { pLeaf = If_ManObj(pIfMan, Entry2); pLeaf->pFanin0->fMark = 1; pLeaf->pFanin1->fMark = 1; } // check that the leaves are marked If_CutForEachLeaf( pIfMan, pCut, pLeaf, i ) if ( pLeaf->fMark == 0 ) RetValue = 0; else pLeaf->fMark = 0; // clean the inner marks Vec_IntForEachEntryDouble( vShape, Entry1, Entry2, i ) { pLeaf = If_ManObj(pIfMan, Entry2); pLeaf->pFanin0->fMark = 0; pLeaf->pFanin1->fMark = 0; } return RetValue; } /**Function************************************************************* Synopsis [Recursively compute the set of nodes supported by the cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int If_ManNodeShape( If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Int_t * vShape, int fExact ) { int RetValue; // if ( pIfMan->nChoices == 0 ) { RetValue = If_ManNodeShapeMap( pIfMan, pIfObj, vShape ); assert( RetValue ); if ( !fExact || If_ManCheckShape(pIfMan, pIfObj, vShape) ) return 1; } // if ( pIfObj->Id == 1254 && If_ObjCutBest(pIfObj)->nLeaves == 7 ) // If_ObjConePrint( pIfMan, pIfObj ); RetValue = If_ManNodeShapeMap2( pIfMan, pIfObj, vShape ); assert( RetValue ); RetValue = If_ManCheckShape(pIfMan, pIfObj, vShape); // assert( RetValue ); // printf( "%d", RetValue ); return 1; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END