giaMfs.c 18 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/**CFile****************************************************************

  FileName    [giaMfs.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Scalable AIG package.]

  Synopsis    [Interface with the MFS package.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - June 20, 2005.]

  Revision    [$Id: giaMfs.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]

***********************************************************************/

#include "gia.h"
#include "opt/sfm/sfm.h"
#include "misc/tim/tim.h"
24
#include "misc/util/utilTruth.h"
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

ABC_NAMESPACE_IMPL_START

////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
47
Sfm_Ntk_t * Gia_ManExtractMfs( Gia_Man_t * p )
48
{
49 50 51 52 53 54 55 56
    word uTruth, uTruths6[6] = {
        ABC_CONST(0xAAAAAAAAAAAAAAAA),
        ABC_CONST(0xCCCCCCCCCCCCCCCC),
        ABC_CONST(0xF0F0F0F0F0F0F0F0),
        ABC_CONST(0xFF00FF00FF00FF00),
        ABC_CONST(0xFFFF0000FFFF0000),
        ABC_CONST(0xFFFFFFFF00000000)
    };
57 58 59 60 61
    Gia_Obj_t * pObj, * pObjExtra;
    Vec_Wec_t * vFanins; // mfs data
    Vec_Str_t * vFixed;  // mfs data 
    Vec_Str_t * vEmpty;  // mfs data
    Vec_Wrd_t * vTruths; // mfs data
62
    Vec_Int_t * vArray;
63
    Vec_Int_t * vLeaves;
64
    Tim_Man_t * pManTime = (Tim_Man_t *)p->pManTime;
65
    int nBoxes   = Gia_ManBoxNum(p), nVars;
66 67
    int nRealPis = nBoxes ? Tim_ManPiNum(pManTime) : Gia_ManPiNum(p);
    int nRealPos = nBoxes ? Tim_ManPoNum(pManTime) : Gia_ManPoNum(p);
68
    int i, j, k, curCi, curCo, nBoxIns, nBoxOuts;
69
    int Id, iFan, nMfsVars, nBbIns = 0, nBbOuts = 0, Counter = 0;
70
    assert( !p->pAigExtra || Gia_ManPiNum(p->pAigExtra) <= 6 );
71
    if ( pManTime ) Tim_ManBlackBoxIoNum( pManTime, &nBbIns, &nBbOuts );
72 73
    // skip PIs due to box outputs
    Counter += nBbOuts;
74
    // prepare storage
75
    nMfsVars = Gia_ManCiNum(p) + 1 + Gia_ManLutNum(p) + Gia_ManCoNum(p) + nBbIns + nBbOuts;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
    vFanins  = Vec_WecStart( nMfsVars );
    vFixed   = Vec_StrStart( nMfsVars );
    vEmpty   = Vec_StrStart( nMfsVars );
    vTruths  = Vec_WrdStart( nMfsVars );
    // set internal PIs
    Gia_ManCleanCopyArray( p );
    Gia_ManForEachCiId( p, Id, i )
        Gia_ObjSetCopyArray( p, Id, Counter++ );
    // set constant node
    Vec_StrWriteEntry( vFixed, Counter, (char)1 );
    Vec_WrdWriteEntry( vTruths, Counter, (word)0 );
    Gia_ObjSetCopyArray( p, 0, Counter++ );
    // set internal LUTs
    vLeaves = Vec_IntAlloc( 6 );
    Gia_ObjComputeTruthTableStart( p, 6 );
    Gia_ManForEachLut( p, Id )
92
    {
93 94 95 96
        Vec_IntClear( vLeaves );
        vArray = Vec_WecEntry( vFanins, Counter );
        Vec_IntGrow( vArray, Gia_ObjLutSize(p, Id) );
        Gia_LutForEachFanin( p, Id, iFan, k )
97
        {
98 99 100
            assert( Gia_ObjCopyArray(p, iFan) >= 0 );
            Vec_IntPush( vArray, Gia_ObjCopyArray(p, iFan) );
            Vec_IntPush( vLeaves, iFan );
101
        }
102 103 104
        assert( Vec_IntSize(vLeaves) <= 6 );
        assert( Vec_IntSize(vLeaves) == Gia_ObjLutSize(p, Id) );
        uTruth = *Gia_ObjComputeTruthTableCut( p, Gia_ManObj(p, Id), vLeaves );
105 106
        nVars = Abc_Tt6MinBase( &uTruth, Vec_IntArray(vArray), Vec_IntSize(vArray) );
        Vec_IntShrink( vArray, nVars );
107 108
        Vec_WrdWriteEntry( vTruths, Counter, uTruth );
        Gia_ObjSetCopyArray( p, Id, Counter++ );
109
    }
110 111 112
    Gia_ObjComputeTruthTableStop( p );
    // set all POs
    Gia_ManForEachCo( p, pObj, i )
113
    {
114 115 116 117 118
        iFan = Gia_ObjFaninId0p( p, pObj );
        assert( Gia_ObjCopyArray(p, iFan) >= 0 );
        vArray = Vec_WecEntry( vFanins, Counter );
        Vec_IntFill( vArray, 1, Gia_ObjCopyArray(p, iFan) );
        if ( i < Gia_ManCoNum(p) - nRealPos ) // internal PO
119
        {
120 121
            Vec_StrWriteEntry( vFixed, Counter, (char)1 );
            Vec_StrWriteEntry( vEmpty, Counter, (char)1 );
122
            uTruth = Gia_ObjFaninC0(pObj) ? ~uTruths6[0]: uTruths6[0];
123
            Vec_WrdWriteEntry( vTruths, Counter, uTruth );
124
        }
125 126
        Gia_ObjSetCopyArray( p, Gia_ObjId(p, pObj), Counter++ );
    }
127 128
    // skip POs due to box inputs
    Counter += nBbIns;
129 130 131 132
    assert( Counter == nMfsVars );
    // add functions of the boxes
    if ( p->pAigExtra )
    {
133
        int iBbIn = 0, iBbOut = 0;
134 135 136
        Gia_ObjComputeTruthTableStart( p->pAigExtra, 6 );
        curCi = nRealPis;
        curCo = 0;
137
        for ( k = 0; k < nBoxes; k++ )
138
        {
139 140
            nBoxIns = Tim_ManBoxInputNum( pManTime, k );
            nBoxOuts = Tim_ManBoxOutputNum( pManTime, k );
141 142
            // collect truth table leaves
            Vec_IntClear( vLeaves );
143 144
            for ( i = 0; i < nBoxIns; i++ )
                Vec_IntPush( vLeaves, Gia_ObjId(p->pAigExtra, Gia_ManCi(p->pAigExtra, i)) );
145
            // iterate through box outputs
146
            if ( !Tim_ManBoxIsBlack(pManTime, k) )
147
            {
148 149 150 151 152
                for ( j = 0; j < nBoxOuts; j++ )
                {
                    // CI corresponding to the box outputs
                    pObj = Gia_ManCi( p, curCi + j );
                    Counter = Gia_ObjCopyArray( p, Gia_ObjId(p, pObj) );
153 154 155 156 157 158 159 160 161 162
                    // add box inputs (POs of the AIG) as fanins
                    vArray = Vec_WecEntry( vFanins, Counter );
                    Vec_IntGrow( vArray, nBoxIns );
                    for ( i = 0; i < nBoxIns; i++ )
                    {
                        iFan = Gia_ObjId( p, Gia_ManCo(p, curCo + i) );
                        assert( Gia_ObjCopyArray(p, iFan) >= 0 );
                        Vec_IntPush( vArray, Gia_ObjCopyArray(p, iFan) );
                    }
                    Vec_StrWriteEntry( vFixed, Counter, (char)1 );
163 164 165 166 167 168 169 170 171 172
                    // box output in the extra manager
                    pObjExtra = Gia_ManCo( p->pAigExtra, curCi - nRealPis + j );
                    // compute truth table
                    if ( Gia_ObjFaninId0p(p->pAigExtra, pObjExtra) == 0 )
                        uTruth = 0;
                    else if ( Gia_ObjIsCi(Gia_ObjFanin0(pObjExtra)) )
                        uTruth = uTruths6[Gia_ObjCioId(Gia_ObjFanin0(pObjExtra))];
                    else
                        uTruth = *Gia_ObjComputeTruthTableCut( p->pAigExtra, Gia_ObjFanin0(pObjExtra), vLeaves );
                    uTruth = Gia_ObjFaninC0(pObjExtra) ? ~uTruth : uTruth;
173 174 175
                    //Dau_DsdPrintFromTruth( &uTruth, Vec_IntSize(vArray) );
                    nVars = Abc_Tt6MinBase( &uTruth, Vec_IntArray(vArray), Vec_IntSize(vArray) );
                    Vec_IntShrink( vArray, nVars );
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
                    Vec_WrdWriteEntry( vTruths, Counter, uTruth );
                }
            }
            else // create buffers for black box inputs and outputs
            {
                for ( j = 0; j < nBoxOuts; j++ )
                {
                    // CI corresponding to the box outputs
                    pObj = Gia_ManCi( p, curCi + j );
                    Counter = Gia_ObjCopyArray( p, Gia_ObjId(p, pObj) );
                    // connect it with the special primary input (iBbOut)
                    vArray = Vec_WecEntry( vFanins, Counter );
                    assert( Vec_IntSize(vArray) == 0 );
                    Vec_IntFill( vArray, 1, iBbOut++ );
                    Vec_StrWriteEntry( vFixed, Counter, (char)1 );
                    Vec_StrWriteEntry( vEmpty, Counter, (char)1 );
                    Vec_WrdWriteEntry( vTruths, Counter, uTruths6[0] );
                }
194
                for ( i = 0; i < nBoxIns; i++ )
195
                {
196 197 198 199 200 201 202
                    // CO corresponding to the box inputs
                    pObj = Gia_ManCo( p, curCo + i );
                    Counter = Gia_ObjCopyArray( p, Gia_ObjId(p, pObj) );
                    // connect it with the special primary output (iBbIn)
                    vArray = Vec_WecEntry( vFanins, nMfsVars - nBbIns + iBbIn++ );
                    assert( Vec_IntSize(vArray) == 0 );
                    Vec_IntFill( vArray, 1, Counter );
203
                }
204
            }
205
            // set internal POs pointing directly to internal PIs as no-delay
206
            for ( i = 0; i < nBoxIns; i++ )
207
            {
208
                pObj = Gia_ManCo( p, curCo + i );
209 210 211 212 213 214 215
                if ( !Gia_ObjIsCi( Gia_ObjFanin0(pObj) ) )
                    continue;
                Counter = Gia_ObjCopyArray( p, Gia_ObjFaninId0p(p, pObj) );
                Vec_StrWriteEntry( vEmpty, Counter, (char)1 );
            }
            curCo += nBoxIns;
            curCi += nBoxOuts;
216
        }
217 218 219 220 221 222
        curCo += nRealPos;
        Gia_ObjComputeTruthTableStop( p->pAigExtra );
        // verify counts
        assert( curCi == Gia_ManCiNum(p) );
        assert( curCo == Gia_ManCoNum(p) );
        assert( curCi - nRealPis == Gia_ManCoNum(p->pAigExtra) );
223 224
        assert( iBbIn  == nBbIns );
        assert( iBbOut == nBbOuts );
225
    }
226 227
    // finalize 
    Vec_IntFree( vLeaves );
228
    return Sfm_NtkConstruct( vFanins, nBbOuts + nRealPis, nRealPos + nBbIns, vFixed, vEmpty, vTruths );
229 230 231 232 233 234 235 236 237 238 239 240 241
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
242
Gia_Man_t * Gia_ManInsertMfs( Gia_Man_t * p, Sfm_Ntk_t * pNtk, int fAllBoxes )
243
{
244 245 246 247 248 249 250
    extern int Gia_ManFromIfLogicCreateLut( Gia_Man_t * pNew, word * pRes, Vec_Int_t * vLeaves, Vec_Int_t * vCover, Vec_Int_t * vMapping, Vec_Int_t * vMapping2 );
    Gia_Man_t * pNew;  Gia_Obj_t * pObj;
    Tim_Man_t * pManTime = (Tim_Man_t *)p->pManTime;
    int nBoxes   = Gia_ManBoxNum(p);
    int nRealPis = nBoxes ? Tim_ManPiNum(pManTime) : Gia_ManPiNum(p);
    int nRealPos = nBoxes ? Tim_ManPoNum(pManTime) : Gia_ManPoNum(p);
    int i, k, Id, curCi, curCo, nBoxIns, nBoxOuts, iLitNew, iMfsId, iGroup, Fanin;
251
    int nMfsNodes;
252 253
    word * pTruth, uTruthVar = ABC_CONST(0xAAAAAAAAAAAAAAAA);
    Vec_Wec_t * vGroups = Vec_WecStart( nBoxes );
254 255
    Vec_Int_t * vMfs2Gia;
    Vec_Int_t * vGroupMap;
256 257 258
    Vec_Int_t * vMfsTopo, * vCover, * vBoxesLeft;
    Vec_Int_t * vArray, * vLeaves;
    Vec_Int_t * vMapping, * vMapping2;
259
    int nBbIns = 0, nBbOuts = 0;
260
    if ( pManTime ) Tim_ManBlackBoxIoNum( pManTime, &nBbIns, &nBbOuts );
261 262 263
    nMfsNodes = 1 + Gia_ManCiNum(p) + Gia_ManLutNum(p) + Gia_ManCoNum(p) + nBbIns + nBbOuts;
    vMfs2Gia  = Vec_IntStartFull( nMfsNodes );
    vGroupMap = Vec_IntStartFull( nMfsNodes );
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    // collect nodes
    curCi = nRealPis;
    curCo = 0;
    for ( i = 0; i < nBoxes; i++ )
    {
        nBoxIns = Tim_ManBoxInputNum( pManTime, i );
        nBoxOuts = Tim_ManBoxOutputNum( pManTime, i );
        vArray = Vec_WecEntry( vGroups, i );
        for ( k = 0; k < nBoxIns; k++ )
        {
            pObj = Gia_ManCo( p, curCo + k );
            iMfsId = Gia_ObjCopyArray( p, Gia_ObjId(p, pObj) );
            assert( iMfsId > 0 );
            Vec_IntPush( vArray, iMfsId );
            Vec_IntWriteEntry( vGroupMap, iMfsId, Abc_Var2Lit(i,0) );
        }
        for ( k = 0; k < nBoxOuts; k++ )
        {
            pObj = Gia_ManCi( p, curCi + k );
            iMfsId = Gia_ObjCopyArray( p, Gia_ObjId(p, pObj) );
            assert( iMfsId > 0 );
            Vec_IntPush( vArray, iMfsId );
            Vec_IntWriteEntry( vGroupMap, iMfsId, Abc_Var2Lit(i,1) );
        }
        curCo += nBoxIns;
        curCi += nBoxOuts;
    }
    curCo += nRealPos;
    assert( curCi == Gia_ManCiNum(p) );
    assert( curCo == Gia_ManCoNum(p) );

    // collect nodes in the given order
    vBoxesLeft = Vec_IntAlloc( nBoxes );
297
    vMfsTopo = Sfm_NtkDfs( pNtk, vGroups, vGroupMap, vBoxesLeft, fAllBoxes );
298 299 300
    assert( Vec_IntSize(vBoxesLeft) <= nBoxes );
    assert( Vec_IntSize(vMfsTopo) > 0 );

301 302 303 304
    // start new GIA
    pNew = Gia_ManStart( Gia_ManObjNum(p) );
    pNew->pName = Abc_UtilStrsav( p->pName );
    pNew->pSpec = Abc_UtilStrsav( p->pSpec );
305 306 307 308 309 310 311 312 313 314 315

    // start mapping
    vMapping  = Vec_IntStart( Gia_ManObjNum(p) );
    vMapping2 = Vec_IntStart( 1 );
    // create const LUT
    Vec_IntWriteEntry( vMapping, 0, Vec_IntSize(vMapping2) );
    Vec_IntPush( vMapping2, 0 );
    Vec_IntPush( vMapping2, 0 );

    // map constant
    Vec_IntWriteEntry( vMfs2Gia, Gia_ObjCopyArray(p, 0), 0 );
316
    // map primary inputs
317 318 319
    Gia_ManForEachCiId( p, Id, i )
        if ( i < nRealPis )
            Vec_IntWriteEntry( vMfs2Gia, Gia_ObjCopyArray(p, Id), Gia_ManAppendCi(pNew) );
320
    // map internal nodes
321
    vLeaves = Vec_IntAlloc( 6 );
322 323 324 325
    vCover = Vec_IntAlloc( 1 << 16 );
    Vec_IntForEachEntry( vMfsTopo, iMfsId, i )
    {
        pTruth = Sfm_NodeReadTruth( pNtk, iMfsId );
326
        iGroup = Vec_IntEntry( vGroupMap, iMfsId );
327
        vArray = Sfm_NodeReadFanins( pNtk, iMfsId ); // belongs to pNtk
328 329 330 331 332 333 334 335
        if ( Vec_IntSize(vArray) == 1 && Vec_IntEntry(vArray,0) < nBbOuts ) // skip unreal inputs
        {
            // create CI for the output of black box
            assert( Abc_LitIsCompl(iGroup) );
            iLitNew = Gia_ManAppendCi( pNew );
            Vec_IntWriteEntry( vMfs2Gia, iMfsId, iLitNew );
            continue;
        }
336
        Vec_IntClear( vLeaves );
337 338
        Vec_IntForEachEntry( vArray, Fanin, k )
        {
339 340 341 342 343 344 345
            iLitNew = Vec_IntEntry( vMfs2Gia, Fanin );  assert( iLitNew >= 0 );
            Vec_IntPush( vLeaves, iLitNew );            
        }
        if ( iGroup == -1 ) // internal node
        {
            assert( Sfm_NodeReadUsed(pNtk, iMfsId) );
            iLitNew = Gia_ManFromIfLogicCreateLut( pNew, pTruth, vLeaves, vCover, vMapping, vMapping2 );
346
        }
347
        else if ( Abc_LitIsCompl(iGroup) ) // internal CI
348 349
        {
            //Dau_DsdPrintFromTruth( pTruth, Vec_IntSize(vLeaves) );
350
            iLitNew = Gia_ManAppendCi( pNew );
351
        }
352 353
        else // internal CO
        {
354
            assert( pTruth[0] == uTruthVar || pTruth[0] == ~uTruthVar );
355 356 357 358
            iLitNew = Gia_ManAppendCo( pNew, Abc_LitNotCond(Vec_IntEntry(vLeaves, 0), pTruth[0] == ~uTruthVar) );
            //printf("Group = %d. po = %d\n", iGroup>>1, iMfsId );
        }
        Vec_IntWriteEntry( vMfs2Gia, iMfsId, iLitNew );
359 360
    }
    Vec_IntFree( vCover );
361 362 363
    Vec_IntFree( vLeaves );

    // map primary outputs
364 365
    Gia_ManForEachCo( p, pObj, i )
    {
366 367 368 369 370 371 372 373 374 375 376 377
        if ( i < Gia_ManCoNum(p) - nRealPos ) // internal COs
        {
            iMfsId = Gia_ObjCopyArray( p, Gia_ObjId(p, pObj) );
            iGroup = Vec_IntEntry( vGroupMap, iMfsId );
            if ( Vec_IntFind(vMfsTopo, iGroup) >= 0 )
            {
                iLitNew = Vec_IntEntry( vMfs2Gia, iMfsId );
                assert( iLitNew >= 0 );
            }
            continue;
        }
        iLitNew = Vec_IntEntry( vMfs2Gia, Gia_ObjCopyArray(p, Gia_ObjFaninId0p(p, pObj)) );
378
        assert( iLitNew >= 0 );
379
        Gia_ManAppendCo( pNew, Abc_LitNotCond(iLitNew, Gia_ObjFaninC0(pObj)) );
380
    }
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397

    // finish mapping 
    if ( Vec_IntSize(vMapping) > Gia_ManObjNum(pNew) )
        Vec_IntShrink( vMapping, Gia_ManObjNum(pNew) );
    else
        Vec_IntFillExtra( vMapping, Gia_ManObjNum(pNew), 0 );
    assert( Vec_IntSize(vMapping) == Gia_ManObjNum(pNew) );
    Vec_IntForEachEntry( vMapping, iLitNew, i )
        if ( iLitNew > 0 )
            Vec_IntAddToEntry( vMapping, i, Gia_ManObjNum(pNew) );
    Vec_IntAppend( vMapping, vMapping2 );
    Vec_IntFree( vMapping2 );
    assert( pNew->vMapping == NULL );
    pNew->vMapping = vMapping;

    // create new timing manager and extra AIG
    if ( pManTime )
398
        pNew->pManTime = Gia_ManUpdateTimMan2( p, vBoxesLeft, 0 );
399 400 401
    // update extra STG
    if ( p->pAigExtra )
        pNew->pAigExtra = Gia_ManUpdateExtraAig2( p->pManTime, p->pAigExtra, vBoxesLeft );
402 403 404
    // duplicated flops
    if ( p->vRegClasses )
        pNew->vRegClasses = Vec_IntDup( p->vRegClasses );
405 406 407
    // duplicated initial state
    if ( p->vRegInits )
        pNew->vRegInits = Vec_IntDup( p->vRegInits );
408 409 410

    // cleanup
    Vec_WecFree( vGroups );
411
    Vec_IntFree( vMfsTopo );
412 413 414
    Vec_IntFree( vGroupMap );
    Vec_IntFree( vMfs2Gia );
    Vec_IntFree( vBoxesLeft );
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    return pNew;
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Gia_Man_t * Gia_ManPerformMfs( Gia_Man_t * p, Sfm_Par_t * pPars )
{
    Sfm_Ntk_t * pNtk;
    Gia_Man_t * pNew;
    int nFaninMax, nNodes;
    assert( Gia_ManRegNum(p) == 0 );
    assert( p->vMapping != NULL );
    if ( p->pManTime != NULL && p->pAigExtra == NULL )
    {
        Abc_Print( 1, "Timing manager is given but there is no GIA of boxes.\n" );
        return NULL;
    }
    // count fanouts
    nFaninMax = Gia_ManLutSizeMax( p );
    if ( nFaninMax > 6 )
    {
        Abc_Print( 1, "Currently \"&mfs\" cannot process the network containing nodes with more than 6 fanins.\n" );
        return NULL;
    }
    // collect information
449
    pNtk = Gia_ManExtractMfs( p );
450 451 452 453
    // perform optimization
    nNodes = Sfm_NtkPerform( pNtk, pPars );
    if ( nNodes == 0 )
    {
454
        if ( p->pManTime )
455 456 457
        Abc_Print( 1, "The network is not changed by \"&mfs\".\n" );
        pNew = Gia_ManDup( p );
        pNew->vMapping = Vec_IntDup( p->vMapping );
458
        Gia_ManTransferTiming( pNew, p );
459 460 461
    }
    else
    {
462
        pNew = Gia_ManInsertMfs( p, pNtk, pPars->fAllBoxes );
463 464
        if( pPars->fVerbose )
            Abc_Print( 1, "The network has %d nodes changed by \"&mfs\".\n", nNodes );
465 466
        // check integrity
        //Gia_ManCheckIntegrityWithBoxes( pNew );
467 468 469 470 471 472 473 474 475 476 477
    }
    Sfm_NtkFree( pNtk );
    return pNew;
}

////////////////////////////////////////////////////////////////////////
///                       END OF FILE                                ///
////////////////////////////////////////////////////////////////////////

ABC_NAMESPACE_IMPL_END