/**CFile**************************************************************** FileName [acbPush.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Hierarchical word-level netlist.] Synopsis [Implementation of logic pushing.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - July 21, 2015.] Revision [$Id: acbPush.c,v 1.00 2014/11/29 00:00:00 alanmi Exp $] ***********************************************************************/ #include "acb.h" #include "misc/util/utilTruth.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Pushing logic to the fanout.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Acb_ObjPushToFanout( Acb_Ntk_t * p, int iObj, int iFaninIndex, int iFanout ) { word c0, uTruthObjNew = 0, uTruthObj = Acb_ObjTruth( p, iObj ), Gate; word c1, uTruthFanNew = 0, uTruthFan = Acb_ObjTruth( p, iFanout ); int DecType = Abc_Tt6CheckOutDec( uTruthObj, iFaninIndex, &uTruthObjNew ); int iFanin = Acb_ObjFanin( p, iObj, iFaninIndex ); int iFanoutObjIndex = Acb_ObjWhatFanin( p, iFanout, iObj ); int iFanoutFaninIndex = Acb_ObjWhatFanin( p, iFanout, iFanin ); if ( iFanoutFaninIndex == -1 ) iFanoutFaninIndex = Acb_ObjFaninNum(p, iFanout); assert( !Acb_ObjIsCio(p, iObj) ); assert( !Acb_ObjIsCio(p, iFanout) ); assert( iFanoutFaninIndex >= 0 ); assert( iFaninIndex < Acb_ObjFaninNum(p, iObj) ); assert( Acb_ObjFanoutNum(p, iObj) == 1 ); // compute new function of the fanout c0 = Abc_Tt6Cofactor0( uTruthFan, iFanoutObjIndex ); c1 = Abc_Tt6Cofactor1( uTruthFan, iFanoutObjIndex ); if ( DecType == 0 ) // F = i * G Gate = s_Truths6[iFanoutFaninIndex] & s_Truths6[iFanoutObjIndex]; else if ( DecType == 1 ) // F = ~i * G Gate = ~s_Truths6[iFanoutFaninIndex] & s_Truths6[iFanoutObjIndex]; else if ( DecType == 2 ) // F = ~i + G Gate = ~s_Truths6[iFanoutFaninIndex] | s_Truths6[iFanoutObjIndex]; else if ( DecType == 3 ) // F = i + G Gate = s_Truths6[iFanoutFaninIndex] | s_Truths6[iFanoutObjIndex]; else if ( DecType == 4 ) // F = i # G Gate = s_Truths6[iFanoutFaninIndex] ^ s_Truths6[iFanoutObjIndex]; else assert( 0 ); uTruthFanNew = (~Gate & c0) | (Gate & c1); // update functions Vec_WrdWriteEntry( &p->vObjTruth, iObj, Abc_Tt6RemoveVar(uTruthObjNew, iFaninIndex) ); Vec_WrdWriteEntry( &p->vObjTruth, iFanout, uTruthFanNew ); // update fanins Acb_ObjRemoveFaninFanoutOne( p, iObj, iFanin ); if ( iFanoutFaninIndex == Acb_ObjFaninNum(p, iFanout) ) // adding new Acb_ObjAddFaninFanoutOne( p, iFanout, iFanin ); } /**Function************************************************************* Synopsis [Pushing logic to the fanin.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Acb_ObjPushToFanin( Acb_Ntk_t * p, int iObj, int iFaninIndex2, int iFanin ) { word uTruthObjNew = 0, uTruthObj = Acb_ObjTruth( p, iObj ); word uTruthFanNew = 0, uTruthFan = Acb_ObjTruth( p, iFanin ); int iFaninIndex = Acb_ObjWhatFanin( p, iObj, iFanin ); int DecType = Abc_TtCheckDsdAnd( uTruthObj, iFaninIndex, iFaninIndex2, &uTruthObjNew ); int iFanin2 = Acb_ObjFanin( p, iObj, iFaninIndex2 ); int iFaninFaninIndex = Acb_ObjWhatFanin( p, iFanin, iFanin2 ); if ( iFaninFaninIndex == -1 ) iFaninFaninIndex = Acb_ObjFaninNum(p, iFanin); assert( !Acb_ObjIsCio(p, iObj) ); assert( !Acb_ObjIsCio(p, iFanin) ); assert( iFaninIndex < Acb_ObjFaninNum(p, iObj) ); assert( iFaninIndex2 < Acb_ObjFaninNum(p, iObj) ); assert( iFaninIndex != iFaninIndex2 ); assert( Acb_ObjFanoutNum(p, iFanin) == 1 ); // compute new function of the fanout if ( DecType == 0 ) // i * j uTruthFanNew = uTruthFan & s_Truths6[iFaninFaninIndex]; else if ( DecType == 1 ) // i * !j uTruthFanNew = ~uTruthFan & s_Truths6[iFaninFaninIndex]; else if ( DecType == 2 ) // !i * j uTruthFanNew = uTruthFan & ~s_Truths6[iFaninFaninIndex]; else if ( DecType == 3 ) // !i * !j uTruthFanNew = ~uTruthFan & ~s_Truths6[iFaninFaninIndex]; else if ( DecType == 4 ) // i # j uTruthFanNew = uTruthFan ^ s_Truths6[iFaninFaninIndex]; else assert( 0 ); // update functions Vec_WrdWriteEntry( &p->vObjTruth, iObj, Abc_Tt6RemoveVar(uTruthObjNew, iFaninIndex2) ); Vec_WrdWriteEntry( &p->vObjTruth, iFanin, uTruthFanNew ); // update fanins Acb_ObjRemoveFaninFanoutOne( p, iObj, iFanin2 ); if ( iFaninFaninIndex == Acb_ObjFaninNum(p, iFanin) ) // adding new Acb_ObjAddFaninFanoutOne( p, iFanin, iFanin2 ); } /**Function************************************************************* Synopsis [Removing constants, buffers, duplicated fanins.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline int Acb_ObjFindNodeFanout( Acb_Ntk_t * p, int iObj ) { int i, iFanout; Acb_ObjForEachFanout( p, iObj, iFanout, i ) if ( !Acb_ObjIsCio(p, iFanout) ) return iFanout; return -1; } int Acb_ObjSuppMin_int( Acb_Ntk_t * p, int iObj ) { int k, iFanin, * pFanins; word uTruth = Acb_ObjTruth( p, iObj ); Acb_ObjForEachFaninFast( p, iObj, pFanins, iFanin, k ) { if ( Abc_Tt6HasVar(uTruth, k) ) continue; Acb_ObjDeleteFaninIndex( p, iObj, k ); Vec_IntRemove( Vec_WecEntry(&p->vFanouts, iFanin), iObj ); Vec_WrdWriteEntry( &p->vObjTruth, iObj, Abc_Tt6RemoveVar(uTruth, k) ); return 1; } return 0; } void Acb_ObjSuppMin( Acb_Ntk_t * p, int iObj ) { while ( Acb_ObjSuppMin_int(p, iObj) ); } void Acb_ObjRemoveDup( Acb_Ntk_t * p, int iObj, int i, int j ) { word c00, c11, uTruthNew, uTruth = Acb_ObjTruth( p, iObj ); assert( !Acb_ObjIsCio(p, iObj) ); assert( Acb_ObjFanin(p, iObj, i) == Acb_ObjFanin(p, iObj, j) ); c00 = Abc_Tt6Cofactor0( Abc_Tt6Cofactor0(uTruth, i), j ); c11 = Abc_Tt6Cofactor1( Abc_Tt6Cofactor1(uTruth, i), j ); uTruthNew = (~s_Truths6[i] & c00) | (s_Truths6[i] & c11); Vec_WrdWriteEntry( &p->vObjTruth, iObj, Abc_Tt6RemoveVar(uTruthNew, j) ); Acb_ObjDeleteFaninIndex( p, iObj, j ); Vec_IntRemove( Vec_WecEntry(&p->vFanouts, iObj), Acb_ObjFanin(p, iObj, j) ); Acb_ObjSuppMin( p, iObj ); } int Acb_ObjRemoveDupFanins_int( Acb_Ntk_t * p, int iObj ) { int i, k, * pFanins = Acb_ObjFanins( p, iObj ); for ( i = 0; i < pFanins[0]; i++ ) for ( k = i+1; k < pFanins[0]; k++ ) { if ( pFanins[1+i] != pFanins[1+k] ) continue; Acb_ObjRemoveDup( p, iObj, i, k ); return 1; } return 0; } void Acb_ObjRemoveDupFanins( Acb_Ntk_t * p, int iObj ) { assert( !Acb_ObjIsCio(p, iObj) ); while ( Acb_ObjRemoveDupFanins_int(p, iObj) ); } void Acb_ObjRemoveConst( Acb_Ntk_t * p, int iObj ) { int iFanout; word uTruth = Acb_ObjTruth( p, iObj ); assert( !Acb_ObjIsCio(p, iObj) ); assert( Acb_ObjFaninNum(p, iObj) == 0 ); assert( uTruth == 0 || ~uTruth == 0 ); while ( (iFanout = Acb_ObjFindNodeFanout(p, iObj)) >= 0 ) { int iObjIndex = Acb_ObjWhatFanin( p, iFanout, iObj ); word uTruthF = Acb_ObjTruth( p, iFanout ); Acb_ObjRemoveFaninFanoutOne( p, iFanout, iObj ); uTruthF = (uTruth & 1) ? Abc_Tt6Cofactor1(uTruthF, iObjIndex) : Abc_Tt6Cofactor0(uTruthF, iObjIndex); Vec_WrdWriteEntry( &p->vObjTruth, iFanout, Abc_Tt6RemoveVar(uTruthF, iObjIndex) ); Acb_ObjSuppMin( p, iFanout ); } if ( Acb_ObjFanoutNum(p, iObj) == 0 ) Acb_ObjCleanType( p, iObj ); } void Acb_ObjRemoveBufInv( Acb_Ntk_t * p, int iObj ) { int iFanout; word uTruth = Acb_ObjTruth( p, iObj ); assert( !Acb_ObjIsCio(p, iObj) ); assert( Acb_ObjFaninNum(p, iObj) == 1 ); assert( uTruth == s_Truths6[0] || ~uTruth == s_Truths6[0] ); while ( (iFanout = Acb_ObjFindNodeFanout(p, iObj)) >= 0 ) { int iFanin = Acb_ObjFanin( p, iObj, 0 ); int iObjIndex = Acb_ObjWhatFanin( p, iFanout, iObj ); Acb_ObjPatchFanin( p, iFanout, iObj, iFanin ); if ( uTruth & 1 ) // inv { word uTruthF = Acb_ObjTruth( p, iFanout ); Vec_WrdWriteEntry( &p->vObjTruth, iFanout, Abc_Tt6Flip(uTruthF, iObjIndex) ); } Acb_ObjRemoveDupFanins( p, iFanout ); } while ( (uTruth & 1) == 0 && Acb_ObjFanoutNum(p, iObj) > 0 ) { int iFanin = Acb_ObjFanin( p, iObj, 0 ); int iFanout = Acb_ObjFanout( p, iObj, 0 ); assert( Acb_ObjIsCo(p, iFanout) ); Acb_ObjPatchFanin( p, iFanout, iObj, iFanin ); } if ( Acb_ObjFanoutNum(p, iObj) == 0 ) { Acb_ObjRemoveFaninFanout( p, iObj ); Acb_ObjRemoveFanins( p, iObj ); Acb_ObjCleanType( p, iObj ); } } /**Function************************************************************* Synopsis [Check if the node can have its logic pushed.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline int Acb_ObjFindFaninPushableIndex( Acb_Ntk_t * p, int iObj, int iFanIndex ) { int k, iFanin, * pFanins; Acb_ObjForEachFaninFast( p, iObj, pFanins, iFanin, k ) if ( k != iFanIndex && Abc_TtCheckDsdAnd(Acb_ObjTruth(p, iObj), k, iFanIndex, NULL) >= 0 ) return k; return -1; } static inline int Acb_ObjFindFanoutPushableIndex( Acb_Ntk_t * p, int iObj ) { int k, iFanin, * pFanins; Acb_ObjForEachFaninFast( p, iObj, pFanins, iFanin, k ) if ( Abc_Tt6CheckOutDec(Acb_ObjTruth(p, iObj), k, NULL) >= 0 ) return k; return -1; } int Acb_ObjPushToFanins( Acb_Ntk_t * p, int iObj, int nLutSize ) { int k, k2, iFanin, * pFanins; if ( Acb_ObjFaninNum(p, iObj) < 2 ) return 0; Acb_ObjForEachFaninFast( p, iObj, pFanins, iFanin, k ) { if ( Acb_ObjIsCi(p, iFanin) ) continue; if ( Acb_ObjFanoutNum(p, iFanin) > 1 ) continue; if ( Acb_ObjFaninNum(p, iFanin) == nLutSize ) continue; if ( (k2 = Acb_ObjFindFaninPushableIndex(p, iObj, k)) == -1 ) continue; //printf( "Object %4d : Pushing fanin %d (%d) into fanin %d.\n", iObj, Acb_ObjFanin(p, iObj, k2), k2, iFanin ); Acb_ObjPushToFanin( p, iObj, k2, iFanin ); return 1; } if ( Acb_ObjFaninNum(p, iObj) == 2 && Acb_ObjFanoutNum(p, iObj) == 1 ) { int iFanout = Acb_ObjFanout( p, iObj, 0 ); if ( !Acb_ObjIsCo(p, iFanout) && Acb_ObjFaninNum(p, iFanout) < nLutSize ) { k2 = Acb_ObjFindFanoutPushableIndex( p, iObj ); //printf( "Object %4d : Pushing fanin %d (%d) into fanout %d.\n", iObj, Acb_ObjFanin(p, iObj, k2), k2, iFanout ); Acb_ObjPushToFanout( p, iObj, k2, iFanout ); return 1; } } return 0; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Acb_NtkPushLogic( Acb_Ntk_t * p, int nLutSize, int fVerbose ) { int n = 0, iObj, nNodes = Acb_NtkNodeNum(p), nPushes = 0; Acb_NtkCreateFanout( p ); // fanout data structure Acb_NtkForEachNodeSupp( p, iObj, 0 ) Acb_ObjRemoveConst( p, iObj ); Acb_NtkForEachNodeSupp( p, iObj, 1 ) Acb_ObjRemoveBufInv( p, iObj ); for ( n = 2; n <= nLutSize; n++ ) Acb_NtkForEachNodeSupp( p, iObj, n ) { while ( Acb_ObjPushToFanins(p, iObj, nLutSize) ) nPushes++; if ( Acb_ObjFaninNum(p, iObj) == 1 ) Acb_ObjRemoveBufInv( p, iObj ); } printf( "Saved %d nodes after %d pushes.\n", nNodes - Acb_NtkNodeNum(p), nPushes ); } /**Function************************************************************* Synopsis [Pushing logic to the fanin.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Acb_NtkPushLogic2( Acb_Ntk_t * p, int nLutSize, int fVerbose ) { int iObj; Acb_NtkCreateFanout( p ); // fanout data structure Acb_NtkForEachObj( p, iObj ) if ( !Acb_ObjIsCio(p, iObj) ) break; Acb_ObjPushToFanout( p, iObj, Acb_ObjFaninNum(p, iObj)-1, Acb_ObjFanout(p, iObj, 0) ); // Acb_ObjPushToFanin( p, Acb_ObjFanout(p, iObj, 0), Acb_ObjFaninNum(p, iObj)-1, iObj ); } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END