| /**CFile**************************************************************** |
| |
| FileName [cswCut.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Cut sweeping.] |
| |
| Synopsis [] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - July 11, 2007.] |
| |
| Revision [$Id: cswCut.c,v 1.00 2007/07/11 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "cswInt.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Compute the cost of the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Csw_CutFindCost( Csw_Man_t * p, Csw_Cut_t * pCut ) |
| { |
| Aig_Obj_t * pLeaf; |
| int i, Cost = 0; |
| assert( pCut->nFanins > 0 ); |
| Csw_CutForEachLeaf( p->pManRes, pCut, pLeaf, i ) |
| { |
| // Cost += pLeaf->nRefs; |
| Cost += Csw_ObjRefs( p, pLeaf ); |
| // printf( "%d ", pLeaf->nRefs ); |
| } |
| //printf( "\n" ); |
| return Cost * 100 / pCut->nFanins; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Compute the cost of the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline float Csw_CutFindCost2( Csw_Man_t * p, Csw_Cut_t * pCut ) |
| { |
| Aig_Obj_t * pLeaf; |
| float Cost = 0.0; |
| int i; |
| assert( pCut->nFanins > 0 ); |
| Csw_CutForEachLeaf( p->pManRes, pCut, pLeaf, i ) |
| Cost += (float)1.0/pLeaf->nRefs; |
| return 1/Cost; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the next free cut to use.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline Csw_Cut_t * Csw_CutFindFree( Csw_Man_t * p, Aig_Obj_t * pObj ) |
| { |
| Csw_Cut_t * pCut, * pCutMax; |
| int i; |
| pCutMax = NULL; |
| Csw_ObjForEachCut( p, pObj, pCut, i ) |
| { |
| if ( pCut->nFanins == 0 ) |
| return pCut; |
| if ( pCutMax == NULL || pCutMax->Cost < pCut->Cost ) |
| pCutMax = pCut; |
| } |
| assert( pCutMax != NULL ); |
| pCutMax->nFanins = 0; |
| return pCutMax; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes the stretching phase of the cut w.r.t. the merged cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline unsigned Cut_TruthPhase( Csw_Cut_t * pCut, Csw_Cut_t * pCut1 ) |
| { |
| unsigned uPhase = 0; |
| int i, k; |
| for ( i = k = 0; i < pCut->nFanins; i++ ) |
| { |
| if ( k == pCut1->nFanins ) |
| break; |
| if ( pCut->pFanins[i] < pCut1->pFanins[k] ) |
| continue; |
| assert( pCut->pFanins[i] == pCut1->pFanins[k] ); |
| uPhase |= (1 << i); |
| k++; |
| } |
| return uPhase; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs truth table computation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| unsigned * Csw_CutComputeTruth( Csw_Man_t * p, Csw_Cut_t * pCut, Csw_Cut_t * pCut0, Csw_Cut_t * pCut1, int fCompl0, int fCompl1 ) |
| { |
| // permute the first table |
| if ( fCompl0 ) |
| Kit_TruthNot( p->puTemp[0], Csw_CutTruth(pCut0), p->nLeafMax ); |
| else |
| Kit_TruthCopy( p->puTemp[0], Csw_CutTruth(pCut0), p->nLeafMax ); |
| Kit_TruthStretch( p->puTemp[2], p->puTemp[0], pCut0->nFanins, p->nLeafMax, Cut_TruthPhase(pCut, pCut0), 0 ); |
| // permute the second table |
| if ( fCompl1 ) |
| Kit_TruthNot( p->puTemp[1], Csw_CutTruth(pCut1), p->nLeafMax ); |
| else |
| Kit_TruthCopy( p->puTemp[1], Csw_CutTruth(pCut1), p->nLeafMax ); |
| Kit_TruthStretch( p->puTemp[3], p->puTemp[1], pCut1->nFanins, p->nLeafMax, Cut_TruthPhase(pCut, pCut1), 0 ); |
| // produce the resulting table |
| Kit_TruthAnd( Csw_CutTruth(pCut), p->puTemp[2], p->puTemp[3], p->nLeafMax ); |
| // assert( pCut->nFanins >= Kit_TruthSupportSize( Csw_CutTruth(pCut), p->nLeafMax ) ); |
| return Csw_CutTruth(pCut); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs support minimization for the truth table.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Csw_CutSupportMinimize( Csw_Man_t * p, Csw_Cut_t * pCut ) |
| { |
| unsigned * pTruth; |
| int uSupp, nFansNew, i, k; |
| // get truth table |
| pTruth = Csw_CutTruth( pCut ); |
| // get support |
| uSupp = Kit_TruthSupport( pTruth, p->nLeafMax ); |
| // get the new support size |
| nFansNew = Kit_WordCountOnes( uSupp ); |
| // check if there are redundant variables |
| if ( nFansNew == pCut->nFanins ) |
| return nFansNew; |
| assert( nFansNew < pCut->nFanins ); |
| // minimize support |
| Kit_TruthShrink( p->puTemp[0], pTruth, nFansNew, p->nLeafMax, uSupp, 1 ); |
| for ( i = k = 0; i < pCut->nFanins; i++ ) |
| if ( uSupp & (1 << i) ) |
| pCut->pFanins[k++] = pCut->pFanins[i]; |
| assert( k == nFansNew ); |
| pCut->nFanins = nFansNew; |
| // assert( nFansNew == Kit_TruthSupportSize( pTruth, p->nLeafMax ) ); |
| //Extra_PrintBinary( stdout, pTruth, (1<<p->nLeafMax) ); printf( "\n" ); |
| return nFansNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if pDom is contained in pCut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Csw_CutCheckDominance( Csw_Cut_t * pDom, Csw_Cut_t * pCut ) |
| { |
| int i, k; |
| for ( i = 0; i < (int)pDom->nFanins; i++ ) |
| { |
| for ( k = 0; k < (int)pCut->nFanins; k++ ) |
| if ( pDom->pFanins[i] == pCut->pFanins[k] ) |
| break; |
| if ( k == (int)pCut->nFanins ) // node i in pDom is not contained in pCut |
| return 0; |
| } |
| // every node in pDom is contained in pCut |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if the cut is contained.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Csw_CutFilter( Csw_Man_t * p, Aig_Obj_t * pObj, Csw_Cut_t * pCut ) |
| { |
| Csw_Cut_t * pTemp; |
| int i; |
| // go through the cuts of the node |
| Csw_ObjForEachCut( p, pObj, pTemp, i ) |
| { |
| if ( pTemp->nFanins < 2 ) |
| continue; |
| if ( pTemp == pCut ) |
| continue; |
| if ( pTemp->nFanins > pCut->nFanins ) |
| { |
| // skip the non-contained cuts |
| if ( (pTemp->uSign & pCut->uSign) != pCut->uSign ) |
| continue; |
| // check containment seriously |
| if ( Csw_CutCheckDominance( pCut, pTemp ) ) |
| { |
| // remove contained cut |
| pTemp->nFanins = 0; |
| } |
| } |
| else |
| { |
| // skip the non-contained cuts |
| if ( (pTemp->uSign & pCut->uSign) != pTemp->uSign ) |
| continue; |
| // check containment seriously |
| if ( Csw_CutCheckDominance( pTemp, pCut ) ) |
| { |
| // remove the given |
| pCut->nFanins = 0; |
| return 1; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Merges two cuts.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Csw_CutMergeOrdered( Csw_Man_t * p, Csw_Cut_t * pC0, Csw_Cut_t * pC1, Csw_Cut_t * pC ) |
| { |
| int i, k, c; |
| assert( pC0->nFanins >= pC1->nFanins ); |
| // the case of the largest cut sizes |
| if ( pC0->nFanins == p->nLeafMax && pC1->nFanins == p->nLeafMax ) |
| { |
| for ( i = 0; i < pC0->nFanins; i++ ) |
| if ( pC0->pFanins[i] != pC1->pFanins[i] ) |
| return 0; |
| for ( i = 0; i < pC0->nFanins; i++ ) |
| pC->pFanins[i] = pC0->pFanins[i]; |
| pC->nFanins = pC0->nFanins; |
| return 1; |
| } |
| // the case when one of the cuts is the largest |
| if ( pC0->nFanins == p->nLeafMax ) |
| { |
| for ( i = 0; i < pC1->nFanins; i++ ) |
| { |
| for ( k = pC0->nFanins - 1; k >= 0; k-- ) |
| if ( pC0->pFanins[k] == pC1->pFanins[i] ) |
| break; |
| if ( k == -1 ) // did not find |
| return 0; |
| } |
| for ( i = 0; i < pC0->nFanins; i++ ) |
| pC->pFanins[i] = pC0->pFanins[i]; |
| pC->nFanins = pC0->nFanins; |
| return 1; |
| } |
| |
| // compare two cuts with different numbers |
| i = k = 0; |
| for ( c = 0; c < p->nLeafMax; c++ ) |
| { |
| if ( k == pC1->nFanins ) |
| { |
| if ( i == pC0->nFanins ) |
| { |
| pC->nFanins = c; |
| return 1; |
| } |
| pC->pFanins[c] = pC0->pFanins[i++]; |
| continue; |
| } |
| if ( i == pC0->nFanins ) |
| { |
| if ( k == pC1->nFanins ) |
| { |
| pC->nFanins = c; |
| return 1; |
| } |
| pC->pFanins[c] = pC1->pFanins[k++]; |
| continue; |
| } |
| if ( pC0->pFanins[i] < pC1->pFanins[k] ) |
| { |
| pC->pFanins[c] = pC0->pFanins[i++]; |
| continue; |
| } |
| if ( pC0->pFanins[i] > pC1->pFanins[k] ) |
| { |
| pC->pFanins[c] = pC1->pFanins[k++]; |
| continue; |
| } |
| pC->pFanins[c] = pC0->pFanins[i++]; |
| k++; |
| } |
| if ( i < pC0->nFanins || k < pC1->nFanins ) |
| return 0; |
| pC->nFanins = c; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prepares the object for FPGA mapping.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Csw_CutMerge( Csw_Man_t * p, Csw_Cut_t * pCut0, Csw_Cut_t * pCut1, Csw_Cut_t * pCut ) |
| { |
| assert( p->nLeafMax > 0 ); |
| // merge the nodes |
| if ( pCut0->nFanins < pCut1->nFanins ) |
| { |
| if ( !Csw_CutMergeOrdered( p, pCut1, pCut0, pCut ) ) |
| return 0; |
| } |
| else |
| { |
| if ( !Csw_CutMergeOrdered( p, pCut0, pCut1, pCut ) ) |
| return 0; |
| } |
| pCut->uSign = pCut0->uSign | pCut1->uSign; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Consider cut with more than 2 fanins having 2 true variables.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Aig_Obj_t * Csw_ObjTwoVarCut( Csw_Man_t * p, Csw_Cut_t * pCut ) |
| { |
| Aig_Obj_t * pRes, * pIn0, * pIn1; |
| int nVars, uTruth, fCompl = 0; |
| assert( pCut->nFanins > 2 ); |
| // minimize support of this cut |
| nVars = Csw_CutSupportMinimize( p, pCut ); |
| assert( nVars == 2 ); |
| // get the fanins |
| pIn0 = Aig_ManObj( p->pManRes, pCut->pFanins[0] ); |
| pIn1 = Aig_ManObj( p->pManRes, pCut->pFanins[1] ); |
| // derive the truth table |
| uTruth = 0xF & *Csw_CutTruth(pCut); |
| if ( uTruth == 14 || uTruth == 13 || uTruth == 11 || uTruth == 7 ) |
| { |
| uTruth = 0xF & ~uTruth; |
| fCompl = 1; |
| } |
| // compute the result |
| pRes = NULL; |
| if ( uTruth == 1 ) // 0001 // 1110 14 |
| pRes = Aig_And( p->pManRes, Aig_Not(pIn0), Aig_Not(pIn1) ); |
| if ( uTruth == 2 ) // 0010 // 1101 13 |
| pRes = Aig_And( p->pManRes, pIn0 , Aig_Not(pIn1) ); |
| if ( uTruth == 4 ) // 0100 // 1011 11 |
| pRes = Aig_And( p->pManRes, Aig_Not(pIn0), pIn1 ); |
| if ( uTruth == 8 ) // 1000 // 0111 7 |
| pRes = Aig_And( p->pManRes, pIn0 , pIn1 ); |
| if ( pRes ) |
| pRes = Aig_NotCond( pRes, fCompl ); |
| return pRes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Csw_Cut_t * Csw_ObjPrepareCuts( Csw_Man_t * p, Aig_Obj_t * pObj, int fTriv ) |
| { |
| Csw_Cut_t * pCutSet, * pCut; |
| int i; |
| // create the cutset of the node |
| pCutSet = (Csw_Cut_t *)Aig_MmFixedEntryFetch( p->pMemCuts ); |
| Csw_ObjSetCuts( p, pObj, pCutSet ); |
| Csw_ObjForEachCut( p, pObj, pCut, i ) |
| { |
| pCut->nFanins = 0; |
| pCut->iNode = pObj->Id; |
| pCut->nCutSize = p->nCutSize; |
| pCut->nLeafMax = p->nLeafMax; |
| } |
| // add unit cut if needed |
| if ( fTriv ) |
| { |
| pCut = pCutSet; |
| pCut->Cost = 0; |
| pCut->iNode = pObj->Id; |
| pCut->nFanins = 1; |
| pCut->pFanins[0] = pObj->Id; |
| pCut->uSign = Aig_ObjCutSign( pObj->Id ); |
| memset( Csw_CutTruth(pCut), 0xAA, sizeof(unsigned) * p->nTruthWords ); |
| } |
| return pCutSet; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Derives cuts for one node and sweeps this node.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Aig_Obj_t * Csw_ObjSweep( Csw_Man_t * p, Aig_Obj_t * pObj, int fTriv ) |
| { |
| int fUseResub = 1; |
| Csw_Cut_t * pCut0, * pCut1, * pCut, * pCutSet; |
| Aig_Obj_t * pFanin0 = Aig_ObjFanin0(pObj); |
| Aig_Obj_t * pFanin1 = Aig_ObjFanin1(pObj); |
| Aig_Obj_t * pObjNew; |
| unsigned * pTruth; |
| int i, k, nVars, nFanins, iVar; |
| abctime clk; |
| |
| assert( !Aig_IsComplement(pObj) ); |
| if ( !Aig_ObjIsNode(pObj) ) |
| return pObj; |
| if ( Csw_ObjCuts(p, pObj) ) |
| return pObj; |
| // the node is not processed yet |
| assert( Csw_ObjCuts(p, pObj) == NULL ); |
| assert( Aig_ObjIsNode(pObj) ); |
| |
| // set up the first cut |
| pCutSet = Csw_ObjPrepareCuts( p, pObj, fTriv ); |
| |
| // compute pair-wise cut combinations while checking table |
| Csw_ObjForEachCut( p, pFanin0, pCut0, i ) |
| if ( pCut0->nFanins > 0 ) |
| Csw_ObjForEachCut( p, pFanin1, pCut1, k ) |
| if ( pCut1->nFanins > 0 ) |
| { |
| // make sure K-feasible cut exists |
| if ( Kit_WordCountOnes(pCut0->uSign | pCut1->uSign) > p->nLeafMax ) |
| continue; |
| // get the next cut of this node |
| pCut = Csw_CutFindFree( p, pObj ); |
| clk = Abc_Clock(); |
| // assemble the new cut |
| if ( !Csw_CutMerge( p, pCut0, pCut1, pCut ) ) |
| { |
| assert( pCut->nFanins == 0 ); |
| continue; |
| } |
| // check containment |
| if ( Csw_CutFilter( p, pObj, pCut ) ) |
| { |
| assert( pCut->nFanins == 0 ); |
| continue; |
| } |
| // create its truth table |
| pTruth = Csw_CutComputeTruth( p, pCut, pCut0, pCut1, Aig_ObjFaninC0(pObj), Aig_ObjFaninC1(pObj) ); |
| // support minimize the truth table |
| nFanins = pCut->nFanins; |
| // nVars = Csw_CutSupportMinimize( p, pCut ); // leads to quality degradation |
| nVars = Kit_TruthSupportSize( pTruth, p->nLeafMax ); |
| p->timeCuts += Abc_Clock() - clk; |
| |
| // check for trivial truth tables |
| if ( nVars == 0 ) |
| { |
| p->nNodesTriv0++; |
| return Aig_NotCond( Aig_ManConst1(p->pManRes), !(pTruth[0] & 1) ); |
| } |
| if ( nVars == 1 ) |
| { |
| p->nNodesTriv1++; |
| iVar = Kit_WordFindFirstBit( Kit_TruthSupport(pTruth, p->nLeafMax) ); |
| assert( iVar < pCut->nFanins ); |
| return Aig_NotCond( Aig_ManObj(p->pManRes, pCut->pFanins[iVar]), (pTruth[0] & 1) ); |
| } |
| if ( nVars == 2 && nFanins > 2 && fUseResub ) |
| { |
| if ( (pObjNew = Csw_ObjTwoVarCut( p, pCut )) ) |
| { |
| p->nNodesTriv2++; |
| return pObjNew; |
| } |
| } |
| |
| // check if an equivalent node with the same cut exists |
| clk = Abc_Clock(); |
| pObjNew = pCut->nFanins > 2 ? Csw_TableCutLookup( p, pCut ) : NULL; |
| p->timeHash += Abc_Clock() - clk; |
| if ( pObjNew ) |
| { |
| p->nNodesCuts++; |
| return pObjNew; |
| } |
| |
| // assign the cost |
| pCut->Cost = Csw_CutFindCost( p, pCut ); |
| assert( pCut->nFanins > 0 ); |
| assert( pCut->Cost > 0 ); |
| } |
| p->nNodesTried++; |
| |
| // load the resulting cuts into the table |
| clk = Abc_Clock(); |
| Csw_ObjForEachCut( p, pObj, pCut, i ) |
| { |
| if ( pCut->nFanins > 2 ) |
| { |
| assert( pCut->Cost > 0 ); |
| Csw_TableCutInsert( p, pCut ); |
| } |
| } |
| p->timeHash += Abc_Clock() - clk; |
| |
| // return the node if could not replace it |
| return pObj; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |