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

  FileName    [ntlUtil.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Netlist representation.]

  Synopsis    [Various utilities.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "ntl.h"

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

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

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

  Synopsis    [Counts COs that are connected to the internal nodes through invs/bufs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ModelCountLut1( Ntl_Mod_t * pRoot )
{
    Ntl_Obj_t * pObj;
    int i, Counter = 0;
    Ntl_ModelForEachNode( pRoot, pObj, i )
        if ( Ntl_ObjFaninNum(pObj) == 1 )
            Counter++;
    return Counter;
}

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

  Synopsis    [Reads the maximum number of fanins.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ModelGetFaninMax( Ntl_Mod_t * pRoot )
{
    Ntl_Obj_t * pNode;
    int i, nFaninsMax = 0;
    Ntl_ModelForEachNode( pRoot, pNode, i )
    {
        if ( nFaninsMax < Ntl_ObjFaninNum(pNode) )
            nFaninsMax = Ntl_ObjFaninNum(pNode);
    }
    return nFaninsMax;
}

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

  Synopsis    [If the net is driven by an inv/buf, returns its fanin.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Ntl_Net_t * Ntl_ModelFindSimpleNet( Ntl_Net_t * pNetCo )
{
    // skip the case when the net is not driven by a node
    if ( !Ntl_ObjIsNode(pNetCo->pDriver) )
        return NULL;
    // skip the case when the node is not an inv/buf
    if ( Ntl_ObjFaninNum(pNetCo->pDriver) != 1 )
        return NULL;
    return Ntl_ObjFanin0(pNetCo->pDriver);
}

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

  Synopsis    [Connects COs to the internal nodes other than inv/bufs.]

  Description [Should be called immediately after reading from file.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ManCountSimpleCoDriversOne( Ntl_Net_t * pNetCo )
{
    Ntl_Net_t * pNetFanin;
    // skip the case when the net is not driven by a node
    if ( !Ntl_ObjIsNode(pNetCo->pDriver) )
        return 0;
    // skip the case when the node is not an inv/buf
    if ( Ntl_ObjFaninNum(pNetCo->pDriver) != 1 )
        return 0;
    // skip the case when the second-generation driver is not a node
    pNetFanin = Ntl_ObjFanin0(pNetCo->pDriver);
    if ( !Ntl_ObjIsNode(pNetFanin->pDriver) )
        return 0;
    return 1;
}

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

  Synopsis    [Counts COs that are connected to the internal nodes through invs/bufs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ManCountSimpleCoDrivers( Ntl_Man_t * p )
{
    Ntl_Net_t * pNetCo;
    Ntl_Obj_t * pObj;
    Ntl_Mod_t * pRoot;
    int i, k, Counter;
    Counter = 0;
    pRoot = Ntl_ManRootModel( p );
    Ntl_ModelForEachPo( pRoot, pObj, i )
        Counter += Ntl_ManCountSimpleCoDriversOne( Ntl_ObjFanin0(pObj) );
    Ntl_ModelForEachLatch( pRoot, pObj, i )
        Counter += Ntl_ManCountSimpleCoDriversOne( Ntl_ObjFanin0(pObj) );
    Ntl_ModelForEachBox( pRoot, pObj, i )
        Ntl_ObjForEachFanin( pObj, pNetCo, k )
            Counter += Ntl_ManCountSimpleCoDriversOne( pNetCo );
    return Counter;
}

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

  Synopsis    [Derives the array of CI names.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Ntl_ManCollectCiNames( Ntl_Man_t * p )
{
    Vec_Ptr_t * vNames;
    Ntl_Net_t * pNet;
    int i;
    vNames = Vec_PtrAlloc( 1000 );
    Ntl_ManForEachCiNet( p, pNet, i )
        Vec_PtrPush( vNames, pNet->pName );
    return vNames;
}

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

  Synopsis    [Derives the array of CI names.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Ntl_ManCollectCoNames( Ntl_Man_t * p )
{
    Vec_Ptr_t * vNames;
    Ntl_Net_t * pNet;
    int i;
    vNames = Vec_PtrAlloc( 1000 );
    Ntl_ManForEachCoNet( p, pNet, i )
        Vec_PtrPush( vNames, pNet->pName );
    return vNames;
}

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

  Synopsis    [Marks the CI/CO nets.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ntl_ManMarkCiCoNets( Ntl_Man_t * p )
{
    Ntl_Net_t * pNet;
    int i;
    Ntl_ManForEachCiNet( p, pNet, i )
        pNet->fMark = 1;
    Ntl_ManForEachCoNet( p, pNet, i )
        pNet->fMark = 1;
}

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

  Synopsis    [Unmarks the CI/CO nets.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ntl_ManUnmarkCiCoNets( Ntl_Man_t * p )
{
    Ntl_Net_t * pNet;
    int i;
    Ntl_ManForEachCiNet( p, pNet, i )
        pNet->fMark = 0;
    Ntl_ManForEachCoNet( p, pNet, i )
        pNet->fMark = 0;
}

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

  Synopsis    [Unmarks the CI/CO nets.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ntl_ManCheckNetsAreNotMarked( Ntl_Mod_t * pModel )
{
    Ntl_Net_t * pNet;
    int i;
    Ntl_ModelForEachNet( pModel, pNet, i )
        assert( pNet->fMark == 0 );
    return 1;
}

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

  Synopsis    [Convert initial values of registers to be zero.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ntl_ManSetZeroInitValues( Ntl_Man_t * p )
{
    Ntl_Mod_t * pRoot;
    Ntl_Obj_t * pObj;
    int i;
    pRoot = Ntl_ManRootModel(p);
    Ntl_ModelForEachLatch( pRoot, pObj, i )
        pObj->LatchId &= ~3;
}

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

  Synopsis    [Transforms the netlist to have latches with const-0 init-values.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ntl_ManAddInverters( Ntl_Obj_t * pObj )
{
    char * pStore;
    Ntl_Mod_t * pRoot = pObj->pModel;
    Ntl_Man_t * pMan = pRoot->pMan;
    Ntl_Net_t * pNetLo, * pNetLi, * pNetLoInv, * pNetLiInv;
    Ntl_Obj_t * pNode;
    int nLength, RetValue;
    assert( (pObj->LatchId & 3) == 1 );
    // get the nets
    pNetLi = Ntl_ObjFanin0(pObj);
    pNetLo = Ntl_ObjFanout0(pObj);
    // get storage for net names
    nLength = strlen(pNetLi->pName) + strlen(pNetLo->pName) + 10; 
    pStore = Aig_MmFlexEntryFetch( pMan->pMemSops, nLength );
    // create input interter
    pNode = Ntl_ModelCreateNode( pRoot, 1 );
    pNode->pSop = Ntl_ManStoreSop( pMan->pMemSops, "0 1\n" );
    Ntl_ObjSetFanin( pNode, pNetLi, 0 );
    // create input net
    strcpy( pStore, pNetLi->pName );
    strcat( pStore, "_inv" );
    if ( Ntl_ModelFindNet( pRoot, pStore ) )
    {
        printf( "Ntl_ManTransformInitValues(): Internal error! Cannot create net with LI-name + _inv\n" );
        return;
    }
    pNetLiInv = Ntl_ModelFindOrCreateNet( pRoot, pStore );
    RetValue = Ntl_ModelSetNetDriver( pNode, pNetLiInv );
    assert( RetValue );
    // connect latch to the input net
    Ntl_ObjSetFanin( pObj, pNetLiInv, 0 );
    // disconnect latch from the output net
    RetValue = Ntl_ModelClearNetDriver( pObj, pNetLo );
    assert( RetValue );
    // create the output net
    strcpy( pStore, pNetLo->pName );
    strcat( pStore, "_inv" );
    if ( Ntl_ModelFindNet( pRoot, pStore ) )
    {
        printf( "Ntl_ManTransformInitValues(): Internal error! Cannot create net with LO-name + _inv\n" );
        return;
    }
    pNetLoInv = Ntl_ModelFindOrCreateNet( pRoot, pStore );
    RetValue = Ntl_ModelSetNetDriver( pObj, pNetLoInv );
    assert( RetValue );
    // create output interter
    pNode = Ntl_ModelCreateNode( pRoot, 1 );
    pNode->pSop = Ntl_ManStoreSop( pMan->pMemSops, "0 1\n" );
    Ntl_ObjSetFanin( pNode, pNetLoInv, 0 );
    // redirect the old output net
    RetValue = Ntl_ModelSetNetDriver( pNode, pNetLo );
    assert( RetValue );
}

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

  Synopsis    [Transforms the netlist to have latches with const-0 init-values.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ntl_ManTransformInitValues( Ntl_Man_t * p )
{
    Ntl_Mod_t * pRoot;
    Ntl_Obj_t * pObj;
    int i;
    pRoot = Ntl_ManRootModel(p);
    Ntl_ModelForEachLatch( pRoot, pObj, i )
    {
        if ( (pObj->LatchId & 3) == 1 )
            Ntl_ManAddInverters( pObj );
        pObj->LatchId &= ~3;
    }

}

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


