/**CFile****************************************************************

  FileName    [ntlExtract.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Netlist representation.]

  Synopsis    [Netlist SOP to AIG conversion.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "ntl.h"
#include "dec.h"
#include "kit.h"

ABC_NAMESPACE_IMPL_START


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

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

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

  Synopsis    [Strashes one logic node using its SOP.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Obj_t * Ntl_ConvertSopToAigInternal( Aig_Man_t * pMan, Ntl_Obj_t * pNode, char * pSop )
{
    Ntl_Net_t * pNet;
    Aig_Obj_t * pAnd, * pSum;
    int i, Value, nFanins;
    char * pCube;
    // get the number of variables
    nFanins = Kit_PlaGetVarNum(pSop);
    // go through the cubes of the node's SOP
    pSum = Aig_ManConst0(pMan);
    Kit_PlaForEachCube( pSop, nFanins, pCube )
    {
        // create the AND of literals
        pAnd = Aig_ManConst1(pMan);
        Kit_PlaCubeForEachVar( pCube, Value, i )
        {
            pNet = Ntl_ObjFanin( pNode, i );
            if ( Value == '1' )
                pAnd = Aig_And( pMan, pAnd, (Aig_Obj_t *)pNet->pCopy );
            else if ( Value == '0' )
                pAnd = Aig_And( pMan, pAnd, Aig_Not((Aig_Obj_t *)pNet->pCopy) );
        }
        // add to the sum of cubes
        pSum = Aig_Or( pMan, pSum, pAnd );
    }
    // decide whether to complement the result
    if ( Kit_PlaIsComplement(pSop) )
        pSum = Aig_Not(pSum);
    return pSum;
}

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

  Synopsis    [Transforms the decomposition graph into the AIG.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Obj_t * Ntl_GraphToNetworkAig( Aig_Man_t * pMan, Dec_Graph_t * pGraph )
{
    Dec_Node_t * pNode = NULL; // Suppress "might be used uninitialized"
    Aig_Obj_t * pAnd0, * pAnd1;
    int i;
    // check for constant function
    if ( Dec_GraphIsConst(pGraph) )
        return Aig_NotCond( Aig_ManConst1(pMan), Dec_GraphIsComplement(pGraph) );
    // check for a literal
    if ( Dec_GraphIsVar(pGraph) )
        return Aig_NotCond( (Aig_Obj_t *)Dec_GraphVar(pGraph)->pFunc, Dec_GraphIsComplement(pGraph) );
    // build the AIG nodes corresponding to the AND gates of the graph
    Dec_GraphForEachNode( pGraph, pNode, i )
    {
        pAnd0 = Aig_NotCond( (Aig_Obj_t *)Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl ); 
        pAnd1 = Aig_NotCond( (Aig_Obj_t *)Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl ); 
        pNode->pFunc = Aig_And( pMan, pAnd0, pAnd1 );
    }
    // complement the result if necessary
    return Aig_NotCond( (Aig_Obj_t *)pNode->pFunc, Dec_GraphIsComplement(pGraph) );
}

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

  Synopsis    [Converts the network from AIG to BDD representation.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Obj_t * Ntl_ManBuildNodeAig( Ntl_Man_t * p, Ntl_Obj_t * pNode )
{
    int fUseFactor = 1;
    // consider the constant node
    if ( Kit_PlaGetVarNum(pNode->pSop) == 0 )
        return Aig_NotCond( Aig_ManConst1(p->pAig), Kit_PlaIsConst0(pNode->pSop) );
    // decide when to use factoring
    if ( fUseFactor && Kit_PlaGetVarNum(pNode->pSop) > 2 && Kit_PlaGetCubeNum(pNode->pSop) > 1 )
    {
        Dec_Graph_t * pFForm;
        Dec_Node_t * pFFNode;
        Aig_Obj_t * pFunc;
        int i;
        // perform factoring
        pFForm = Dec_Factor( pNode->pSop );
        // collect the fanins
        Dec_GraphForEachLeaf( pFForm, pFFNode, i )
            pFFNode->pFunc = Ntl_ObjFanin(pNode, i)->pCopy;
        // perform strashing
        pFunc = Ntl_GraphToNetworkAig( p->pAig, pFForm );
        Dec_GraphFree( pFForm );
        return pFunc;
    }
    return Ntl_ConvertSopToAigInternal( p->pAig, pNode, pNode->pSop );
}

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

  Synopsis    [Collects the nodes in a topological order.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ManExtract_rec( Ntl_Man_t * p, Ntl_Net_t * pNet )
{
    Ntl_Obj_t * pObj;
    Ntl_Net_t * pNetFanin;
    int i;
    // skip visited
    if ( pNet->nVisits == 2 ) 
        return 1;
    // if the node is on the path, this is a combinational loop
    if ( pNet->nVisits == 1 )
        return 0; 
    // mark the node as the one on the path
    pNet->nVisits = 1;
    // derive the box
    pObj = pNet->pDriver;
    assert( Ntl_ObjIsNode(pObj) || Ntl_ObjIsBox(pObj) );
    // visit the input nets of the box
    Ntl_ObjForEachFanin( pObj, pNetFanin, i )
        if ( !Ntl_ManExtract_rec( p, pNetFanin ) )
            return 0;
    // add box inputs/outputs to COs/CIs
    if ( Ntl_ObjIsBox(pObj) ) 
    {
        int LevelCur, LevelMax = -TIM_ETERNITY;
        assert( Ntl_BoxIsComb(pObj) );
        assert( Ntl_ModelLatchNum(pObj->pImplem) == 0 );
        assert( pObj->pImplem->vDelays != NULL );
        Vec_IntPush( p->vBox1Cios, Aig_ManPoNum(p->pAig) );
        Ntl_ObjForEachFanin( pObj, pNetFanin, i )
        {
            LevelCur = Aig_ObjLevel( Aig_Regular((Aig_Obj_t *)pNetFanin->pCopy) );
            LevelMax = ABC_MAX( LevelMax, LevelCur );
            Vec_PtrPush( p->vCos, pNetFanin );
            Aig_ObjCreatePo( p->pAig, (Aig_Obj_t *)pNetFanin->pCopy );
        }
        Ntl_ObjForEachFanout( pObj, pNetFanin, i )
        {
            Vec_PtrPush( p->vCis, pNetFanin );
            pNetFanin->pCopy = Aig_ObjCreatePi( p->pAig );
            Aig_ObjSetLevel( (Aig_Obj_t *)pNetFanin->pCopy, LevelMax + 1 );
        }
    }
    Vec_PtrPush( p->vVisNodes, pObj );
    if ( Ntl_ObjIsNode(pObj) )
        pNet->pCopy = Ntl_ManBuildNodeAig( p, pObj );
    pNet->nVisits = 2;
    return 1;
}

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

  Synopsis    [Performs DFS.]

  Description [Checks for combinational loops. Collects PI/PO nets.
  Collects nodes in the topological order.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Ntl_ManExtract( Ntl_Man_t * p )
{
    Aig_Man_t * pAig;
    Ntl_Mod_t * pRoot;
    Ntl_Obj_t * pObj;
    Ntl_Net_t * pNet;
    int i, k, nUselessObjects;
    Ntl_ManCleanup( p );
    Vec_PtrClear( p->vCis );
    Vec_PtrClear( p->vCos );
    Vec_PtrClear( p->vVisNodes );
    Vec_IntClear( p->vBox1Cios );
    // start the AIG manager
    assert( p->pAig == NULL );
    p->pAig = Aig_ManStart( 10000 );
    p->pAig->pName = Aig_UtilStrsav( p->pName );
    p->pAig->pSpec = Aig_UtilStrsav( p->pSpec );
    // get the root model
    pRoot = Ntl_ManRootModel( p );
    assert( Ntl_ModelLatchNum(pRoot) == 0 );
    // clear net visited flags
    Ntl_ModelClearNets( pRoot );
    // collect mapping leafs
    Ntl_ModelForEachMapLeaf( pRoot, pObj, i )
    {
        assert( !Ntl_ObjIsBox(pObj) || Ntl_BoxIsBlack(pObj) || Ntl_ModelLatchNum(pObj->pImplem) > 0 );
        Ntl_ObjForEachFanout( pObj, pNet, k )
        {
            Vec_PtrPush( p->vCis, pNet );
            pNet->pCopy = Aig_ObjCreatePi( p->pAig );
            if ( pNet->nVisits )
            {
                printf( "Ntl_ManExtract(): Seq leaf is duplicated or defined as a primary input.\n" );
                return 0;
            }
            pNet->nVisits = 2;
        }
    }
    p->iLastCi = Aig_ManPiNum(p->pAig);
    // collect mapping roots
    Ntl_ModelForEachMapRoot( pRoot, pObj, i )
    {
        Ntl_ObjForEachFanin( pObj, pNet, k )
        {
            if ( !Ntl_ManExtract_rec( p, pNet ) )
            {
                printf( "Ntl_ManExtract(): Error: Combinational loop is detected.\n" );
                return 0;
            }
            Vec_PtrPush( p->vCos, pNet );
            Aig_ObjCreatePo( p->pAig, (Aig_Obj_t *)pNet->pCopy );
        }
    }
    // visit dangling boxes
    Ntl_ModelForEachBox( pRoot, pObj, i )
    {
        pNet = Ntl_ObjFanout0(pObj);
        if ( !Ntl_ManExtract_rec( p, pNet ) )
        {
            printf( "Ntl_ManExtract(): Error: Combinational loop is detected.\n" );
            return 0;
        }
    }
    // report the number of dangling objects
    nUselessObjects = Ntl_ModelNodeNum(pRoot) + Ntl_ModelLut1Num(pRoot) + Ntl_ModelBoxNum(pRoot) - Vec_PtrSize(p->vVisNodes);
//    if ( nUselessObjects )
//        printf( "The number of dangling objects = %d.\n", nUselessObjects );
    // cleanup the AIG
    Aig_ManCleanup( p->pAig );
    // extract the timing manager
    assert( p->pManTime == NULL );
    p->pManTime = Ntl_ManCreateTiming( p );
    // discretize timing info
    p->pAig->pManTime = Tim_ManDup( p->pManTime, 1 );
    pAig = p->pAig; p->pAig = NULL;
    return pAig;    
}




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

  Synopsis    [Collects the nodes in a topological order.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ManCollapseBoxComb_rec( Ntl_Man_t * p, Ntl_Obj_t * pBox )
{
    extern int Ntl_ManCollapse_rec( Ntl_Man_t * p, Ntl_Net_t * pNet );
    Ntl_Mod_t * pModel = pBox->pImplem;
    Ntl_Obj_t * pObj;
    Ntl_Net_t * pNet, * pNetBox;
    int i;
    assert( Ntl_ObjFaninNum(pBox) == Ntl_ModelPiNum(pModel) );
    assert( Ntl_ObjFanoutNum(pBox) == Ntl_ModelPoNum(pModel) );
    // clear net visited flags
    Ntl_ModelClearNets( pModel );
    // transfer from the box to the PIs of the model
    Ntl_ModelForEachPi( pModel, pObj, i )
    {
        pNet = Ntl_ObjFanout0(pObj);
        pNetBox = Ntl_ObjFanin( pBox, i );
        pNet->pCopy = pNetBox->pCopy;
        pNet->nVisits = 2;
    }
    // compute AIG for the internal nodes
    Ntl_ModelForEachPo( pModel, pObj, i )
    {
        pNet = Ntl_ObjFanin0(pObj);
        if ( !Ntl_ManCollapse_rec( p, pNet ) )
            return 0;
        pNetBox = Ntl_ObjFanout( pBox, i );
        pNetBox->pCopy = pNet->pCopy;
    }
    return 1;
}

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

  Synopsis    [Collects the nodes in a topological order.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ManCollapseBoxSeq1_rec( Ntl_Man_t * p, Ntl_Obj_t * pBox )
{
    extern int Ntl_ManCollapse_rec( Ntl_Man_t * p, Ntl_Net_t * pNet );
    Ntl_Mod_t * pModel = pBox->pImplem;
    Ntl_Obj_t * pObj;
    Ntl_Net_t * pNet, * pNetBox;
    int i;
    assert( Ntl_ModelLatchNum(pModel) > 0 );
    assert( Ntl_ObjFaninNum(pBox) == Ntl_ModelPiNum(pModel) );
    assert( Ntl_ObjFanoutNum(pBox) == Ntl_ModelPoNum(pModel) );
    // clear net visited flags
    Ntl_ModelClearNets( pModel );
    // initialize the registers
    Ntl_ModelForEachLatch( pModel, pObj, i )
    {
        pNet = Ntl_ObjFanout0(pObj);
        pNet->pCopy = Aig_ObjCreatePi( p->pAig );
        if ( Ntl_ObjIsInit1( pObj ) )
            pNet->pCopy = Aig_Not((Aig_Obj_t *)pNet->pCopy);
        pNet->nVisits = 2;
        // remember the class of this register
        Vec_IntPush( p->vRegClasses, p->pNal ? pBox->iTemp : pObj->LatchId.regClass );
        Vec_IntPush( p->vRstClasses, p->pNal ? pBox->Reset : -1 );
    }
    // compute AIG for the internal nodes
    Ntl_ModelForEachPo( pModel, pObj, i )
    {
        pNet = Ntl_ObjFanin0(pObj);
        if ( !Ntl_ManCollapse_rec( p, pNet ) )
            return 0;
        pNetBox = Ntl_ObjFanout( pBox, i );
        pNetBox->pCopy = pNet->pCopy;
    }
    return 1;
}

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

  Synopsis    [Collects the nodes in a topological order.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ManCollapseBoxSeq2_rec( Ntl_Man_t * p, Ntl_Obj_t * pBox, int iFirstPi )
{
    extern int Ntl_ManCollapse_rec( Ntl_Man_t * p, Ntl_Net_t * pNet );
    Ntl_Mod_t * pModel = pBox->pImplem;
    Ntl_Obj_t * pObj;
    Ntl_Net_t * pNet, * pNetBox;
    int i;
    assert( Ntl_ModelLatchNum(pModel) > 0 );
    assert( Ntl_ObjFaninNum(pBox) == Ntl_ModelPiNum(pModel) );
    assert( Ntl_ObjFanoutNum(pBox) == Ntl_ModelPoNum(pModel) );
    // clear net visited flags
    Ntl_ModelClearNets( pModel );
    // transfer from the box to the PIs of the model
    Ntl_ModelForEachPi( pModel, pObj, i )
    {
        pNet = Ntl_ObjFanout0(pObj);
        pNetBox = Ntl_ObjFanin( pBox, i );
        pNet->pCopy = pNetBox->pCopy;
        pNet->nVisits = 2;
    }
    // initialize the registers
    Ntl_ModelForEachLatch( pModel, pObj, i )
    {
        pNet = Ntl_ObjFanout0(pObj);
        pNet->pCopy = Aig_ManPi( p->pAig, iFirstPi++ );
        if ( Ntl_ObjIsInit1( pObj ) )
            pNet->pCopy = Aig_Not((Aig_Obj_t *)pNet->pCopy);
        pNet->nVisits = 2;
    }
    // compute AIGs for the registers
    Ntl_ModelForEachLatch( pModel, pObj, i )
    {
        pNet = Ntl_ObjFanin0(pObj);
        if ( !Ntl_ManCollapse_rec( p, pNet ) )
            return 0;
        if ( Ntl_ObjIsInit1( pObj ) )
            Aig_ObjCreatePo( p->pAig, Aig_Not((Aig_Obj_t *)pNet->pCopy) );
        else
            Aig_ObjCreatePo( p->pAig, (Aig_Obj_t *)pNet->pCopy );
    }
    return 1;
}

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

  Synopsis    [Collects the nodes in a topological order.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ManCollapse_rec( Ntl_Man_t * p, Ntl_Net_t * pNet )
{
    Ntl_Obj_t * pObj;
    Ntl_Net_t * pNetFanin;
    int i;
    // skip visited
    if ( pNet->nVisits == 2 ) 
        return 1;
    // if the node is on the path, this is a combinational loop
    if ( pNet->nVisits == 1 )
        return 0; 
    // mark the node as the one on the path
    pNet->nVisits = 1;
    // derive the box
    pObj = pNet->pDriver;
    assert( Ntl_ObjIsNode(pObj) || Ntl_ObjIsBox(pObj) );
    // visit the input nets of the box
    Ntl_ObjForEachFanin( pObj, pNetFanin, i )
        if ( !Ntl_ManCollapse_rec( p, pNetFanin ) )
            return 0;
    // add box inputs/outputs to COs/CIs
    if ( Ntl_ObjIsBox(pObj) )
    {
        assert( Ntl_BoxIsWhite(pObj) && Ntl_BoxIsComb(pObj) );
        if ( !Ntl_ManCollapseBoxComb_rec( p, pObj ) )
            return 0;
    }
    if ( Ntl_ObjIsNode(pObj) )
        pNet->pCopy = Ntl_ManBuildNodeAig( p, pObj );
    pNet->nVisits = 2;
    return 1;
}

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

  Synopsis    [Performs DFS.]

  Description [Checks for combinational loops. Collects PI/PO nets.
  Collects nodes in the topological order.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Ntl_ManCollapse( Ntl_Man_t * p, int fSeq )
{
    Aig_Man_t * pAig;
    Ntl_Mod_t * pRoot;
    Ntl_Obj_t * pBox;
    Ntl_Net_t * pNet;
    int i, k, nTruePis, nTruePos, iBox = 0;
    assert( Vec_PtrSize(p->vCis) != 0 );
    assert( Vec_PtrSize(p->vCos) != 0 );
    Vec_IntClear( p->vBox1Cios );
    Vec_IntClear( p->vRegClasses );
    Vec_IntClear( p->vRstClasses );
    // clear net visited flags
    pRoot = Ntl_ManRootModel(p);
    assert( Ntl_ModelLatchNum(pRoot) == 0 );
    Ntl_ModelClearNets( pRoot );
    // create the manager
    p->pAig = Aig_ManStart( 10000 );
    p->pAig->pName = Aig_UtilStrsav( p->pName );
    p->pAig->pSpec = Aig_UtilStrsav( p->pSpec );
    // set the inputs
    Ntl_ManForEachCiNet( p, pNet, i )
    {
        pNet->pCopy = Aig_ObjCreatePi( p->pAig );
        if ( pNet->nVisits )
        {
            printf( "Ntl_ManCollapse(): Primary input appears twice in the list.\n" );
            return 0;
        }
        pNet->nVisits = 2;
    }
    nTruePis = Aig_ManPiNum(p->pAig);
    // create inputs of seq boxes
    if ( fSeq ) {
      Ntl_ModelForEachBox( pRoot, pBox, i )
      {
          if ( !(Ntl_BoxIsSeq(pBox) && Ntl_BoxIsWhite(pBox)) )
              continue;
          Vec_IntPush( p->vBox1Cios, Aig_ManPiNum(p->pAig) );
          Ntl_ManCollapseBoxSeq1_rec( p, pBox );
          Ntl_ObjForEachFanout( pBox, pNet, k )
              pNet->nVisits = 2;
      }
    }
    // derive the outputs
    Ntl_ManForEachCoNet( p, pNet, i )
    {
        if ( !Ntl_ManCollapse_rec( p, pNet ) )
        {
            printf( "Ntl_ManCollapse(): Error: Combinational loop is detected.\n" );
            return 0;
        }
        Aig_ObjCreatePo( p->pAig, (Aig_Obj_t *)pNet->pCopy );
    }
    nTruePos = Aig_ManPoNum(p->pAig);
    // create outputs of seq boxes
    if ( fSeq ) {
      Ntl_ModelForEachBox( pRoot, pBox, i )
      {
          if ( !(Ntl_BoxIsSeq(pBox) && Ntl_BoxIsWhite(pBox)) )
              continue;
          Ntl_ObjForEachFanin( pBox, pNet, k )
              if ( !Ntl_ManCollapse_rec( p, pNet ) )
              {
                  printf( "Ntl_ManCollapse(): Error: Combinational loop is detected.\n" );
                  return 0;
              }
          Ntl_ManCollapseBoxSeq2_rec( p, pBox, Vec_IntEntry(p->vBox1Cios, iBox++) );
      }
    }
    // make sure registers are added correctly
    if ( Aig_ManPiNum(p->pAig) - nTruePis != Aig_ManPoNum(p->pAig) - nTruePos )
    {
        printf( "Ntl_ManCollapse(): Error: Registers are created incorrectly.\n" );
        return 0;
    }
    // cleanup the AIG
    Aig_ManSetRegNum( p->pAig, Aig_ManPiNum(p->pAig) - nTruePis );
    Aig_ManCleanup( p->pAig );
    pAig = p->pAig; p->pAig = NULL;
    return pAig;    
}


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

  Synopsis    [Collapses the netlist combinationally.]

  Description [Checks for combinational loops. Collects PI/PO nets.
  Collects nodes in the topological order.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Ntl_ManCollapseComb( Ntl_Man_t * p )
{
    Ntl_Mod_t * pRoot;
    Ntl_Obj_t * pObj;
    Ntl_Net_t * pNet;
    int i, k;
    Vec_PtrClear( p->vCis );
    Vec_PtrClear( p->vCos );
    // prepare the model
    pRoot = Ntl_ManRootModel(p);
    // collect the leaves for this traversal
    Ntl_ModelForEachCombLeaf( pRoot, pObj, i )
        Ntl_ObjForEachFanout( pObj, pNet, k )
            Vec_PtrPush( p->vCis, pNet );
    // collect the roots for this traversal
    Ntl_ModelForEachCombRoot( pRoot, pObj, i )
        Ntl_ObjForEachFanin( pObj, pNet, k )
            Vec_PtrPush( p->vCos, pNet );
    // perform the traversal
    return Ntl_ManCollapse( p, 0 );
}

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

  Synopsis    [Collapses the netlist combinationally.]

  Description [Checks for combinational loops. Collects PI/PO nets.
  Collects nodes in the topological order.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Ntl_ManCollapseSeq( Ntl_Man_t * p, int nMinDomSize, int fVerbose )
{
    Aig_Man_t * pAig;
    Ntl_Mod_t * pRoot;
    Ntl_Obj_t * pObj;
    Ntl_Net_t * pNet;
    int i, k;
    Vec_PtrClear( p->vCis );
    Vec_PtrClear( p->vCos );
    // prepare the model
    pRoot = Ntl_ManRootModel(p);
    // collect the leaves for this traversal
    Ntl_ModelForEachSeqLeaf( pRoot, pObj, i )
        Ntl_ObjForEachFanout( pObj, pNet, k )
            Vec_PtrPush( p->vCis, pNet );
    // collect the roots for this traversal
    Ntl_ModelForEachSeqRoot( pRoot, pObj, i )
        Ntl_ObjForEachFanin( pObj, pNet, k )
            Vec_PtrPush( p->vCos, pNet );
    // perform the traversal
    pAig = Ntl_ManCollapse( p, 1 );
    // check if there are register classes
    pAig->vClockDoms = Ntl_ManTransformRegClasses( p, nMinDomSize, fVerbose );
    if ( pAig->vClockDoms )
    {
        if ( Vec_VecSize(pAig->vClockDoms) == 0 )
        {
            printf( "Register classes are below the limit (%d). Seq synthesis is not performed.\n", nMinDomSize );
            Aig_ManStop( pAig );
            pAig = NULL;
        }
        else if ( fVerbose )
            printf( "Performing seq synthesis for %d register classes.\n", Vec_VecSize(pAig->vClockDoms) );
        if ( fVerbose )
            printf( "\n" );
    }
    return pAig;
}



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

  Synopsis    [Increments reference counter of the net.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline void Ntl_NetIncrementRefs( Ntl_Net_t * pNet )
{
    int nRefs = (int)(long)pNet->pCopy;
    pNet->pCopy = (void *)(long)(nRefs + 1);
}

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

  Synopsis    [Extracts logic newtork out of the netlist.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Nwk_Obj_t * Ntl_ManExtractNwk_rec( Ntl_Man_t * p, Ntl_Net_t * pNet, Nwk_Man_t * pNtk, Vec_Int_t * vCover, Vec_Int_t * vMemory )
{
    extern Hop_Obj_t * Kit_CoverToHop( Hop_Man_t * pMan, Vec_Int_t * vCover, int nVars, Vec_Int_t * vMemory );
    Ntl_Net_t * pFaninNet;
    Nwk_Obj_t * pNode;
    int i;
    if ( pNet->fMark )
        return (Nwk_Obj_t *)pNet->pCopy2;
    pNet->fMark = 1;
    pNode = Nwk_ManCreateNode( pNtk, Ntl_ObjFaninNum(pNet->pDriver), (int)(long)pNet->pCopy );
    Ntl_ObjForEachFanin( pNet->pDriver, pFaninNet, i )
    {
        Ntl_ManExtractNwk_rec( p, pFaninNet, pNtk, vCover, vMemory );
        Nwk_ObjAddFanin( pNode, (Nwk_Obj_t *)pFaninNet->pCopy2 );
    }
    if ( Ntl_ObjFaninNum(pNet->pDriver) == 0 || Kit_PlaGetVarNum(pNet->pDriver->pSop) == 0 )
        pNode->pFunc = Hop_NotCond( Hop_ManConst1(pNtk->pManHop), Kit_PlaIsConst0(pNet->pDriver->pSop) );
    else
    {
        Kit_PlaToIsop( pNet->pDriver->pSop, vCover );
        pNode->pFunc = Kit_CoverToHop( pNtk->pManHop, vCover, Ntl_ObjFaninNum(pNet->pDriver), vMemory );
        if ( Kit_PlaIsComplement(pNet->pDriver->pSop) )
            pNode->pFunc = Hop_Not(pNode->pFunc);
    }
    return (Nwk_Obj_t *)(pNet->pCopy2 = pNode);
}

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

  Synopsis    [Extracts logic network out of the netlist.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Nwk_Man_t * Ntl_ManExtractNwk( Ntl_Man_t * p, Aig_Man_t * pAig, Tim_Man_t * pManTime )
{
    Nwk_Man_t * pNtk;
    Nwk_Obj_t * pNode;
    Ntl_Mod_t * pRoot;
    Ntl_Net_t * pNet, * pNetSimple;
    Ntl_Obj_t * pObj;
    Aig_Obj_t * pAnd;
    Vec_Int_t * vCover, * vMemory;
    int i, k;
    pRoot = Ntl_ManRootModel( p );
    if ( Ntl_ModelGetFaninMax(pRoot) > 6 )
    {
        printf( "The network contains logic nodes with more than 6 inputs.\n" );
        return NULL;
    }
    vCover = Vec_IntAlloc( 100 );
    vMemory = Vec_IntAlloc( 1 << 16 );
    // count the number of fanouts of each net
    Ntl_ModelClearNets( pRoot );
    Ntl_ModelForEachObj( pRoot, pObj, i )
        Ntl_ObjForEachFanin( pObj, pNet, k )
            Ntl_NetIncrementRefs( pNet );
    // remember netlist objects int the AIG nodes
    if ( pManTime != NULL ) // logic netlist
    {
        assert( Ntl_ModelPiNum(pRoot) == Aig_ManPiNum(pAig) );
        assert( Ntl_ModelPoNum(pRoot) == Aig_ManPoNum(pAig) );
        Aig_ManForEachPi( pAig, pAnd, i )
            pAnd->pData = Ntl_ObjFanout0( Ntl_ModelPi(pRoot, i) );
        Aig_ManForEachPo( pAig, pAnd, i )
            pAnd->pData = Ntl_ObjFanin0(Ntl_ModelPo(pRoot, i) );
    }
    else // real netlist
    {
        assert( p->vCis && p->vCos );
        Aig_ManForEachPi( pAig, pAnd, i )
            pAnd->pData = Vec_PtrEntry( p->vCis, i );
        Aig_ManForEachPo( pAig, pAnd, i )
            pAnd->pData = Vec_PtrEntry( p->vCos, i );
    }
    // construct the network
    pNtk = Nwk_ManAlloc();
    pNtk->pName = Aig_UtilStrsav( pAig->pName );
    pNtk->pSpec = Aig_UtilStrsav( pAig->pSpec );
    Aig_ManForEachObj( pAig, pAnd, i )
    {
        if ( Aig_ObjIsPi(pAnd) )
        {
            pNet = (Ntl_Net_t *)pAnd->pData;
            pNet->fMark = 1;
            pNet->pCopy2 = Nwk_ManCreateCi( pNtk, (int)(long)pNet->pCopy ); 
        }
        else if ( Aig_ObjIsPo(pAnd) )
        {
            pNet = (Ntl_Net_t *)pAnd->pData;
            pNode = Nwk_ManCreateCo( pNtk );
            if ( (pNetSimple = Ntl_ModelFindSimpleNet( pNet )) )
            {
                pNetSimple->pCopy2 = Ntl_ManExtractNwk_rec( p, pNetSimple, pNtk, vCover, vMemory ); 
                Nwk_ObjAddFanin( pNode, (Nwk_Obj_t *)pNetSimple->pCopy2 );
                pNode->fInvert = Kit_PlaIsInv( pNet->pDriver->pSop );
            }
            else
            {
                pNet->pCopy2 = Ntl_ManExtractNwk_rec( p, pNet, pNtk, vCover, vMemory ); 
                Nwk_ObjAddFanin( pNode, (Nwk_Obj_t *)pNet->pCopy2 );
                pNode->fInvert = (Nwk_ObjFanin0(pNode)->pFunc == Hop_ManConst0(pNtk->pManHop)); // fixed on June 7, 2009
            }
        }
    }
    Ntl_ModelClearNets( pRoot );
    Vec_IntFree( vCover );
    Vec_IntFree( vMemory );
    // create timing manager from the current design
    if ( pManTime )
        pNtk->pManTime = Tim_ManDup( pManTime, 0 );
    else
        pNtk->pManTime = Tim_ManDup( p->pManTime, 0 );
    Nwk_ManRemoveDupFanins( pNtk, 0 );
    assert( Nwk_ManCheck( pNtk ) );
    return pNtk;
}

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

  Synopsis    [Extracts logic newtork out of the netlist.]
 
  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Nwk_Man_t * Ntl_ManReadNwk( char * pFileName, Aig_Man_t * pAig, Tim_Man_t * pManTime )
{
    Nwk_Man_t * pNtk;
    Ntl_Man_t * pNtl;
    Ntl_Mod_t * pRoot;
    pNtl = Ntl_ManReadBlif( pFileName, 1 );
    if ( pNtl == NULL )
    {
        printf( "Ntl_ManReadNwk(): Reading BLIF has failed.\n" );
        return NULL;
    }
    pRoot = Ntl_ManRootModel( pNtl );
    if ( Ntl_ModelLatchNum(pRoot) != 0 )
    {
        printf( "Ntl_ManReadNwk(): The input network has %d registers.\n", Ntl_ModelLatchNum(pRoot) );
        return NULL;
    }
    if ( Ntl_ModelBoxNum(pRoot) != 0 )
    {
        printf( "Ntl_ManReadNwk(): The input network has %d boxes.\n", Ntl_ModelBoxNum(pRoot) );
        return NULL;
    }
    if ( Ntl_ModelPiNum(pRoot) != Aig_ManPiNum(pAig) )
    {
        printf( "Ntl_ManReadNwk(): The number of primary inputs does not match (%d and %d).\n",
            Ntl_ModelPiNum(pRoot), Aig_ManPiNum(pAig) );
        return NULL;
    }
    if ( Ntl_ModelPoNum(pRoot) != Aig_ManPoNum(pAig) )
    {
        printf( "Ntl_ManReadNwk(): The number of primary outputs does not match (%d and %d).\n",
            Ntl_ModelPoNum(pRoot), Aig_ManPoNum(pAig) );
        return NULL;
    }
    pNtk = Ntl_ManExtractNwk( pNtl, pAig, pManTime );
    Ntl_ManFree( pNtl );
    return pNtk;
}

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


ABC_NAMESPACE_IMPL_END

