/**CFile**************************************************************** FileName [mfsCore.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [The good old minimization with complete don't-cares.] Synopsis [Core procedures of this package.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 20, 2005.] Revision [$Id: mfsCore.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] ***********************************************************************/ #include "mfsInt.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// extern int Abc_NtkMfsSolveSatResub( Mfs_Man_t * p, Abc_Obj_t * pNode, int iFanin, int fOnlyRemove, int fSkipUpdate ); //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkMfsParsDefault( Mfs_Par_t * pPars ) { memset( pPars, 0, sizeof(Mfs_Par_t) ); pPars->nWinTfoLevs = 2; pPars->nFanoutsMax = 30; pPars->nDepthMax = 20; pPars->nWinMax = 300; pPars->nGrowthLevel = 0; pPars->nBTLimit = 5000; pPars->fRrOnly = 0; pPars->fResub = 1; pPars->fArea = 0; pPars->fMoreEffort = 0; pPars->fSwapEdge = 0; pPars->fOneHotness = 0; pPars->fVerbose = 0; pPars->fVeryVerbose = 0; } /* int Abc_NtkMfsEdgePower( Mfs_Man_t * p, Abc_Obj_t * pNode ) { Abc_Obj_t * pFanin; int i; // try replacing area critical fanins Abc_ObjForEachFanin( pNode, pFanin, i ) { if ( Abc_MfsObjProb(p, pFanin) >= 0.4 ) { if ( Abc_NtkMfsSolveSatResub( p, pNode, i, 0, 0 ) ) return 1; } else if ( Abc_MfsObjProb(p, pFanin) >= 0.3 ) { if ( Abc_NtkMfsSolveSatResub( p, pNode, i, 1, 0 ) ) return 1; } } return 0; } */ int Abc_WinNode(Mfs_Man_t * p, Abc_Obj_t *pNode) { // abctime clk; // Abc_Obj_t * pFanin; // int i; p->nNodesTried++; // prepare data structure for this node Mfs_ManClean( p ); // compute window roots, window support, and window nodes p->vRoots = Abc_MfsComputeRoots( pNode, p->pPars->nWinTfoLevs, p->pPars->nFanoutsMax ); p->vSupp = Abc_NtkNodeSupport( p->pNtk, (Abc_Obj_t **)Vec_PtrArray(p->vRoots), Vec_PtrSize(p->vRoots) ); p->vNodes = Abc_NtkDfsNodes( p->pNtk, (Abc_Obj_t **)Vec_PtrArray(p->vRoots), Vec_PtrSize(p->vRoots) ); if ( p->pPars->nWinMax && Vec_PtrSize(p->vNodes) > p->pPars->nWinMax ) return 1; // compute the divisors of the window p->vDivs = Abc_MfsComputeDivisors( p, pNode, Abc_ObjRequiredLevel(pNode) - 1 ); p->nTotalDivs += Vec_PtrSize(p->vDivs) - Abc_ObjFaninNum(pNode); // construct AIG for the window p->pAigWin = Abc_NtkConstructAig( p, pNode ); // translate it into CNF p->pCnf = Cnf_DeriveSimple( p->pAigWin, 1 + Vec_PtrSize(p->vDivs) ); // create the SAT problem p->pSat = Abc_MfsCreateSolverResub( p, NULL, 0, 0 ); if ( p->pSat == NULL ) { p->nNodesBad++; return 1; } return 0; } /* int Abc_NtkMfsPowerResubNode( Mfs_Man_t * p, Abc_Obj_t * pNode ) { abctime clk; Abc_Obj_t * pFanin; int i; if (Abc_WinNode(p, pNode) // something wrong return 1; // solve the SAT problem // Abc_NtkMfsEdgePower( p, pNode ); // try replacing area critical fanins Abc_ObjForEachFanin( pNode, pFanin, i ) if ( Abc_MfsObjProb(p, pFanin) >= 0.37 && Abc_NtkMfsSolveSatResub( p, pNode, i, 0, 0 ) ) return 1; Abc_ObjForEachFanin( pNode, pFanin, i ) if ( Abc_MfsObjProb(p, pFanin) >= 0.1 && Abc_NtkMfsSolveSatResub( p, pNode, i, 1, 0 ) ) return 1; if ( Abc_ObjFaninNum(pNode) == p->nFaninMax ) return 0; // try replacing area critical fanins while adding two new fanins Abc_ObjForEachFanin( pNode, pFanin, i ) if ( Abc_MfsObjProb(p, pFanin) >= 0.37 && Abc_NtkMfsSolveSatResub2( p, pNode, i, -1 ) ) return 1; } return 0; return 1; } */ void Abc_NtkMfsPowerResub( Mfs_Man_t * p, Mfs_Par_t * pPars) { int i, k; Abc_Obj_t *pFanin, *pNode; Abc_Ntk_t *pNtk = p->pNtk; int nFaninMax = Abc_NtkGetFaninMax(p->pNtk); Abc_NtkForEachNode( pNtk, pNode, k ) { if ( p->pPars->nDepthMax && (int)pNode->Level > p->pPars->nDepthMax ) continue; if ( Abc_ObjFaninNum(pNode) < 2 || Abc_ObjFaninNum(pNode) > nFaninMax ) continue; if (Abc_WinNode(p, pNode) ) // something wrong continue; // solve the SAT problem // Abc_NtkMfsEdgePower( p, pNode ); // try replacing area critical fanins Abc_ObjForEachFanin( pNode, pFanin, i ) if ( Abc_MfsObjProb(p, pFanin) >= 0.35 && Abc_NtkMfsSolveSatResub( p, pNode, i, 0, 0 ) ) continue; } Abc_NtkForEachNode( pNtk, pNode, k ) { if ( p->pPars->nDepthMax && (int)pNode->Level > p->pPars->nDepthMax ) continue; if ( Abc_ObjFaninNum(pNode) < 2 || Abc_ObjFaninNum(pNode) > nFaninMax ) continue; if (Abc_WinNode(p, pNode) ) // something wrong continue; // solve the SAT problem // Abc_NtkMfsEdgePower( p, pNode ); // try replacing area critical fanins Abc_ObjForEachFanin( pNode, pFanin, i ) if ( Abc_MfsObjProb(p, pFanin) >= 0.35 && Abc_NtkMfsSolveSatResub( p, pNode, i, 0, 0 ) ) continue; } Abc_NtkForEachNode( pNtk, pNode, k ) { if ( p->pPars->nDepthMax && (int)pNode->Level > p->pPars->nDepthMax ) continue; if ( Abc_ObjFaninNum(pNode) < 2 || Abc_ObjFaninNum(pNode) > nFaninMax ) continue; if (Abc_WinNode(p, pNode) ) // something wrong continue; Abc_ObjForEachFanin( pNode, pFanin, i ) if ( Abc_MfsObjProb(p, pFanin) >= 0.2 && Abc_NtkMfsSolveSatResub( p, pNode, i, 1, 0 ) ) continue; } /* Abc_NtkForEachNode( pNtk, pNode, k ) { if ( p->pPars->nDepthMax && (int)pNode->Level > p->pPars->nDepthMax ) continue; if ( Abc_ObjFaninNum(pNode) < 2 || Abc_ObjFaninNum(pNode) > nFaninMax - 2) continue; if (Abc_WinNode(p, pNode) ) // something wrong continue; Abc_ObjForEachFanin( pNode, pFanin, i ) if ( Abc_MfsObjProb(p, pFanin) >= 0.37 && Abc_NtkMfsSolveSatResub2( p, pNode, i, -1 ) ) continue; } */ } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkMfsResub( Mfs_Man_t * p, Abc_Obj_t * pNode ) { abctime clk; p->nNodesTried++; // prepare data structure for this node Mfs_ManClean( p ); // compute window roots, window support, and window nodes clk = Abc_Clock(); p->vRoots = Abc_MfsComputeRoots( pNode, p->pPars->nWinTfoLevs, p->pPars->nFanoutsMax ); p->vSupp = Abc_NtkNodeSupport( p->pNtk, (Abc_Obj_t **)Vec_PtrArray(p->vRoots), Vec_PtrSize(p->vRoots) ); p->vNodes = Abc_NtkDfsNodes( p->pNtk, (Abc_Obj_t **)Vec_PtrArray(p->vRoots), Vec_PtrSize(p->vRoots) ); p->timeWin += Abc_Clock() - clk; if ( p->pPars->nWinMax && Vec_PtrSize(p->vNodes) > p->pPars->nWinMax ) { p->nMaxDivs++; return 1; } // compute the divisors of the window clk = Abc_Clock(); p->vDivs = Abc_MfsComputeDivisors( p, pNode, Abc_ObjRequiredLevel(pNode) - 1 ); p->nTotalDivs += Vec_PtrSize(p->vDivs) - Abc_ObjFaninNum(pNode); p->timeDiv += Abc_Clock() - clk; // construct AIG for the window clk = Abc_Clock(); p->pAigWin = Abc_NtkConstructAig( p, pNode ); p->timeAig += Abc_Clock() - clk; // translate it into CNF clk = Abc_Clock(); p->pCnf = Cnf_DeriveSimple( p->pAigWin, 1 + Vec_PtrSize(p->vDivs) ); p->timeCnf += Abc_Clock() - clk; // create the SAT problem clk = Abc_Clock(); p->pSat = Abc_MfsCreateSolverResub( p, NULL, 0, 0 ); if ( p->pSat == NULL ) { p->nNodesBad++; return 1; } //clk = Abc_Clock(); // if ( p->pPars->fGiaSat ) // Abc_NtkMfsConstructGia( p ); //p->timeGia += Abc_Clock() - clk; // solve the SAT problem if ( p->pPars->fPower ) Abc_NtkMfsEdgePower( p, pNode ); else if ( p->pPars->fSwapEdge ) Abc_NtkMfsEdgeSwapEval( p, pNode ); else { Abc_NtkMfsResubNode( p, pNode ); if ( p->pPars->fMoreEffort ) Abc_NtkMfsResubNode2( p, pNode ); } p->timeSat += Abc_Clock() - clk; // if ( p->pPars->fGiaSat ) // Abc_NtkMfsDeconstructGia( p ); return 1; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkMfsNode( Mfs_Man_t * p, Abc_Obj_t * pNode ) { Hop_Obj_t * pObj; int RetValue; float dProb; extern Hop_Obj_t * Abc_NodeIfNodeResyn( Bdc_Man_t * p, Hop_Man_t * pHop, Hop_Obj_t * pRoot, int nVars, Vec_Int_t * vTruth, unsigned * puCare, float dProb ); int nGain; abctime clk; p->nNodesTried++; // prepare data structure for this node Mfs_ManClean( p ); // compute window roots, window support, and window nodes clk = Abc_Clock(); p->vRoots = Abc_MfsComputeRoots( pNode, p->pPars->nWinTfoLevs, p->pPars->nFanoutsMax ); p->vSupp = Abc_NtkNodeSupport( p->pNtk, (Abc_Obj_t **)Vec_PtrArray(p->vRoots), Vec_PtrSize(p->vRoots) ); p->vNodes = Abc_NtkDfsNodes( p->pNtk, (Abc_Obj_t **)Vec_PtrArray(p->vRoots), Vec_PtrSize(p->vRoots) ); p->timeWin += Abc_Clock() - clk; // count the number of patterns // p->dTotalRatios += Abc_NtkConstraintRatio( p, pNode ); // construct AIG for the window clk = Abc_Clock(); p->pAigWin = Abc_NtkConstructAig( p, pNode ); p->timeAig += Abc_Clock() - clk; // translate it into CNF clk = Abc_Clock(); p->pCnf = Cnf_DeriveSimple( p->pAigWin, Abc_ObjFaninNum(pNode) ); p->timeCnf += Abc_Clock() - clk; // create the SAT problem clk = Abc_Clock(); p->pSat = (sat_solver *)Cnf_DataWriteIntoSolver( p->pCnf, 1, 0 ); if ( p->pSat && p->pPars->fOneHotness ) Abc_NtkAddOneHotness( p ); if ( p->pSat == NULL ) return 0; // solve the SAT problem RetValue = Abc_NtkMfsSolveSat( p, pNode ); p->nTotConfLevel += p->pSat->stats.conflicts; p->timeSat += Abc_Clock() - clk; if ( RetValue == 0 ) { p->nTimeOutsLevel++; p->nTimeOuts++; return 0; } // minimize the local function of the node using bi-decomposition assert( p->nFanins == Abc_ObjFaninNum(pNode) ); dProb = p->pPars->fPower? ((float *)p->vProbs->pArray)[pNode->Id] : -1.0; pObj = Abc_NodeIfNodeResyn( p->pManDec, (Hop_Man_t *)pNode->pNtk->pManFunc, (Hop_Obj_t *)pNode->pData, p->nFanins, p->vTruth, p->uCare, dProb ); nGain = Hop_DagSize((Hop_Obj_t *)pNode->pData) - Hop_DagSize(pObj); if ( nGain >= 0 ) { p->nNodesDec++; p->nNodesGained += nGain; p->nNodesGainedLevel += nGain; pNode->pData = pObj; } return 1; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkMfs( Abc_Ntk_t * pNtk, Mfs_Par_t * pPars ) { extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters ); Bdc_Par_t Pars = {0}, * pDecPars = &Pars; ProgressBar * pProgress; Mfs_Man_t * p; Abc_Obj_t * pObj; Vec_Vec_t * vLevels; Vec_Ptr_t * vNodes; int i, k, nNodes, nFaninMax; abctime clk = Abc_Clock(), clk2; int nTotalNodesBeg = Abc_NtkNodeNum(pNtk); int nTotalEdgesBeg = Abc_NtkGetTotalFanins(pNtk); assert( Abc_NtkIsLogic(pNtk) ); nFaninMax = Abc_NtkGetFaninMax(pNtk); if ( pPars->fResub ) { if ( nFaninMax > 8 ) { printf( "Nodes with more than %d fanins will not be processed.\n", 8 ); nFaninMax = 8; } } else { if ( nFaninMax > MFS_FANIN_MAX ) { printf( "Nodes with more than %d fanins will not be processed.\n", MFS_FANIN_MAX ); nFaninMax = MFS_FANIN_MAX; } } // perform the network sweep // Abc_NtkSweep( pNtk, 0 ); // convert into the AIG if ( !Abc_NtkToAig(pNtk) ) { fprintf( stdout, "Converting to AIGs has failed.\n" ); return 0; } assert( Abc_NtkHasAig(pNtk) ); // start the manager p = Mfs_ManAlloc( pPars ); p->pNtk = pNtk; p->nFaninMax = nFaninMax; // precomputer power-aware metrics if ( pPars->fPower ) { extern Vec_Int_t * Abc_NtkPowerEstimate( Abc_Ntk_t * pNtk, int fProbOne ); if ( pPars->fResub ) p->vProbs = Abc_NtkPowerEstimate( pNtk, 0 ); else p->vProbs = Abc_NtkPowerEstimate( pNtk, 1 ); #if 0 printf( "Total switching before = %7.2f.\n", Abc_NtkMfsTotalSwitching(pNtk) ); #else p->TotalSwitchingBeg = Abc_NtkMfsTotalSwitching(pNtk); #endif } if ( pNtk->pExcare ) { Abc_Ntk_t * pTemp; if ( Abc_NtkPiNum((Abc_Ntk_t *)pNtk->pExcare) != Abc_NtkCiNum(pNtk) ) printf( "The PI count of careset (%d) and logic network (%d) differ. Careset is not used.\n", Abc_NtkPiNum((Abc_Ntk_t *)pNtk->pExcare), Abc_NtkCiNum(pNtk) ); else { pTemp = Abc_NtkStrash( (Abc_Ntk_t *)pNtk->pExcare, 0, 0, 0 ); p->pCare = Abc_NtkToDar( pTemp, 0, 0 ); Abc_NtkDelete( pTemp ); p->vSuppsInv = Aig_ManSupportsInverse( p->pCare ); } } if ( p->pCare != NULL ) printf( "Performing optimization with %d external care clauses.\n", Aig_ManCoNum(p->pCare) ); // prepare the BDC manager if ( !pPars->fResub ) { pDecPars->nVarsMax = (nFaninMax < 3) ? 3 : nFaninMax; pDecPars->fVerbose = pPars->fVerbose; p->vTruth = Vec_IntAlloc( 0 ); p->pManDec = Bdc_ManAlloc( pDecPars ); } // label the register outputs if ( p->pCare ) { Abc_NtkForEachCi( pNtk, pObj, i ) pObj->pData = (void *)(ABC_PTRUINT_T)i; } // compute levels Abc_NtkLevel( pNtk ); Abc_NtkStartReverseLevels( pNtk, pPars->nGrowthLevel ); // compute don't-cares for each node nNodes = 0; p->nTotalNodesBeg = nTotalNodesBeg; p->nTotalEdgesBeg = nTotalEdgesBeg; if ( pPars->fResub ) { #if 0 printf( "TotalSwitching (%7.2f --> ", Abc_NtkMfsTotalSwitching(pNtk) ); #endif if (pPars->fPower) { Abc_NtkMfsPowerResub( p, pPars); } else { pProgress = Extra_ProgressBarStart( stdout, Abc_NtkObjNumMax(pNtk) ); Abc_NtkForEachNode( pNtk, pObj, i ) { if ( p->pPars->nDepthMax && (int)pObj->Level > p->pPars->nDepthMax ) continue; if ( Abc_ObjFaninNum(pObj) < 2 || Abc_ObjFaninNum(pObj) > nFaninMax ) continue; if ( !p->pPars->fVeryVerbose ) Extra_ProgressBarUpdate( pProgress, i, NULL ); if ( pPars->fResub ) Abc_NtkMfsResub( p, pObj ); else Abc_NtkMfsNode( p, pObj ); } Extra_ProgressBarStop( pProgress ); #if 0 printf( " %7.2f )\n", Abc_NtkMfsTotalSwitching(pNtk) ); #endif } } else { #if 0 printf( "Total switching before = %7.2f, ----> ", Abc_NtkMfsTotalSwitching(pNtk) ); #endif pProgress = Extra_ProgressBarStart( stdout, Abc_NtkNodeNum(pNtk) ); vLevels = Abc_NtkLevelize( pNtk ); Vec_VecForEachLevelStart( vLevels, vNodes, k, 1 ) { if ( !p->pPars->fVeryVerbose ) Extra_ProgressBarUpdate( pProgress, nNodes, NULL ); p->nNodesGainedLevel = 0; p->nTotConfLevel = 0; p->nTimeOutsLevel = 0; clk2 = Abc_Clock(); Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) { if ( p->pPars->nDepthMax && (int)pObj->Level > p->pPars->nDepthMax ) break; if ( Abc_ObjFaninNum(pObj) < 2 || Abc_ObjFaninNum(pObj) > nFaninMax ) continue; if ( pPars->fResub ) Abc_NtkMfsResub( p, pObj ); else Abc_NtkMfsNode( p, pObj ); } nNodes += Vec_PtrSize(vNodes); if ( pPars->fVerbose ) { /* printf( "Lev = %2d. Node = %5d. Ave gain = %5.2f. Ave conf = %5.2f. T/o = %6.2f %% ", k, Vec_PtrSize(vNodes), 1.0*p->nNodesGainedLevel/Vec_PtrSize(vNodes), 1.0*p->nTotConfLevel/Vec_PtrSize(vNodes), 100.0*p->nTimeOutsLevel/Vec_PtrSize(vNodes) ); ABC_PRT( "Time", Abc_Clock() - clk2 ); */ } } Extra_ProgressBarStop( pProgress ); Vec_VecFree( vLevels ); #if 0 printf( " %7.2f.\n", Abc_NtkMfsTotalSwitching(pNtk) ); #endif } Abc_NtkStopReverseLevels( pNtk ); // perform the sweeping if ( !pPars->fResub ) { extern void Abc_NtkBidecResyn( Abc_Ntk_t * pNtk, int fVerbose ); // Abc_NtkSweep( pNtk, 0 ); // Abc_NtkBidecResyn( pNtk, 0 ); } p->nTotalNodesEnd = Abc_NtkNodeNum(pNtk); p->nTotalEdgesEnd = Abc_NtkGetTotalFanins(pNtk); // undo labesl if ( p->pCare ) { Abc_NtkForEachCi( pNtk, pObj, i ) pObj->pData = NULL; } if ( pPars->fPower ) { #if 1 p->TotalSwitchingEnd = Abc_NtkMfsTotalSwitching(pNtk); // printf( "Total switching after = %7.2f.\n", Abc_NtkMfsTotalSwitching(pNtk) ); #else printf( "Total switching after = %7.2f.\n", Abc_NtkMfsTotalSwitching(pNtk) ); #endif } // free the manager p->timeTotal = Abc_Clock() - clk; Mfs_ManStop( p ); return 1; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END