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

  FileName    [cbaPrsBuild.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Hierarchical word-level netlist.]

  Synopsis    [Parse tree to netlist transformation.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - November 29, 2014.]

  Revision    [$Id: cbaPrsBuild.c,v 1.00 2014/11/29 00:00:00 alanmi Exp $]

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

#include "cba.h"
#include "cbaPrs.h"

ABC_NAMESPACE_IMPL_START

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

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

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Prs_ManVecFree( Vec_Ptr_t * vPrs )
{
    Prs_Ntk_t * pNtk; int i;
    Vec_PtrForEachEntry( Prs_Ntk_t *, vPrs, pNtk, i )
        Prs_NtkFree( pNtk );
    Vec_PtrFree( vPrs );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Prs_NtkCountObjects( Prs_Ntk_t * pNtk )
{
    Vec_Int_t * vFanins; 
    int i, Count = Prs_NtkObjNum(pNtk);
    Prs_NtkForEachBox( pNtk, vFanins, i )
        Count += Prs_BoxIONum(pNtk, i);
    return Count;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
// replaces NameIds of formal names by their index in the box model
void Prs_ManRemapOne( Vec_Int_t * vSigs, Prs_Ntk_t * pNtkBox, Vec_Int_t * vMap )
{
    int i, NameId;
    // map formal names into I/O indexes
    Prs_NtkForEachPi( pNtkBox, NameId, i )
    {
        assert( Vec_IntEntry(vMap, NameId) == -1 );
        Vec_IntWriteEntry( vMap, NameId, i + 1 ); // +1 to keep 1st form input non-zero
    }
    Prs_NtkForEachPo( pNtkBox, NameId, i )
    {
        assert( Vec_IntEntry(vMap, NameId) == -1 );
        Vec_IntWriteEntry( vMap, NameId, Prs_NtkPiNum(pNtkBox) + i + 1 ); // +1 to keep 1st form input non-zero
    }
    // remap box
    assert( Vec_IntSize(vSigs) % 2 == 0 );
    Vec_IntForEachEntry( vSigs, NameId, i )
    {
        assert( Vec_IntEntry(vMap, NameId) != -1 );
        Vec_IntWriteEntry( vSigs, i++, Vec_IntEntry(vMap, NameId) );
    }
    // unmap formal inputs
    Prs_NtkForEachPi( pNtkBox, NameId, i )
        Vec_IntWriteEntry( vMap, NameId, -1 );
    Prs_NtkForEachPo( pNtkBox, NameId, i )
        Vec_IntWriteEntry( vMap, NameId, -1 );
}
void Prs_ManRemapBoxes( Cba_Man_t * pNew, Vec_Ptr_t * vDes, Prs_Ntk_t * pNtk, Vec_Int_t * vMap )
{
    Vec_Int_t * vSigs; int iBox;
    Prs_NtkForEachBox( pNtk, vSigs, iBox )
        if ( !Prs_BoxIsNode(pNtk, iBox) )
        {
            int NtkId = Prs_BoxNtk( pNtk, iBox );
            int NtkIdNew = Cba_ManNtkFindId( pNew, Prs_NtkStr(pNtk, NtkId) );
            Prs_BoxSetNtk( pNtk, iBox, NtkIdNew );
            Prs_ManRemapOne( vSigs, Prs_ManNtk(vDes, NtkIdNew), vMap );
        }
}
void Prs_ManCleanMap( Prs_Ntk_t * pNtk, Vec_Int_t * vMap )
{
    Vec_Int_t * vSigs; 
    int i, k, NameId, Sig;
    Prs_NtkForEachPi( pNtk, NameId, i )
        Vec_IntWriteEntry( vMap, NameId, -1 );
    Prs_NtkForEachBox( pNtk, vSigs, i )
        Vec_IntForEachEntryDouble( vSigs, NameId, Sig, k )
            Vec_IntWriteEntry( vMap, Prs_NtkSigName(pNtk, Sig), -1 );
    Prs_NtkForEachPo( pNtk, NameId, i )
        Vec_IntWriteEntry( vMap, NameId, -1 );
}
// create maps of NameId and boxes
void Prs_ManBuildNtk( Cba_Ntk_t * pNew, Vec_Ptr_t * vDes, Prs_Ntk_t * pNtk, Vec_Int_t * vMap, Vec_Int_t * vBoxes )
{
    Prs_Ntk_t * pNtkBox; Vec_Int_t * vSigs; int iBox;
    int i, Index, NameId, iObj, iConst0, iTerm;
    int iNonDriven = -1, nNonDriven = 0;
    assert( Prs_NtkPioNum(pNtk) == 0 );
    Prs_ManRemapBoxes( pNew->pDesign, vDes, pNtk, vMap );
    Cba_NtkStartNames( pNew );
    // create primary inputs 
    Prs_NtkForEachPi( pNtk, NameId, i )
    {
        if ( Vec_IntEntry(vMap, NameId) != -1 )
            printf( "Primary inputs %d and %d have the same name.\n", Vec_IntEntry(vMap, NameId), i );
        iObj = Cba_ObjAlloc( pNew, CBA_OBJ_PI, -1, -1 );
        Cba_ObjSetName( pNew, iObj, NameId );
        Vec_IntWriteEntry( vMap, NameId, iObj );
    }
    // create box outputs
    Vec_IntClear( vBoxes );
    Prs_NtkForEachBox( pNtk, vSigs, iBox )
        if ( !Prs_BoxIsNode(pNtk, iBox) )
        {
            pNtkBox = Prs_ManNtk( vDes, Prs_BoxNtk(pNtk, iBox) );
            iObj = Cba_BoxAlloc( pNew, CBA_OBJ_BOX, Prs_NtkPiNum(pNtkBox), Prs_NtkPoNum(pNtkBox), Prs_BoxNtk(pNtk, iBox) );
            Cba_ObjSetName( pNew, iObj, Prs_BoxName(pNtk, iBox) );
            Vec_IntForEachEntry( vSigs, Index, i )
            {
                i++;
                if ( --Index < Prs_NtkPiNum(pNtkBox) )
                    continue;
                assert( Index - Prs_NtkPiNum(pNtkBox) < Prs_NtkPoNum(pNtkBox) );
                // consider box output 
                NameId = Vec_IntEntry( vSigs, i );
                NameId = Prs_NtkSigName( pNtk, NameId );
                if ( Vec_IntEntry(vMap, NameId) != -1 )
                    printf( "Box output name %d is already driven.\n", NameId );
                iTerm = Cba_BoxBo( pNew, iObj, Index - Prs_NtkPiNum(pNtkBox) );
                Cba_ObjSetName( pNew, iTerm, NameId );
                Vec_IntWriteEntry( vMap, NameId, iTerm );
            }
            // remember box
            Vec_IntPush( vBoxes, iObj );
        }
        else
        {
            iObj = Cba_BoxAlloc( pNew, Prs_BoxNtk(pNtk, iBox), Prs_BoxIONum(pNtk, iBox)-1, 1, -1 );
            // consider box output 
            NameId = Vec_IntEntryLast( vSigs );
            NameId = Prs_NtkSigName( pNtk, NameId );
            if ( Vec_IntEntry(vMap, NameId) != -1 )
                printf( "Node output name %d is already driven.\n", NameId );
            iTerm = Cba_BoxBo( pNew, iObj, 0 );
            Cba_ObjSetName( pNew, iTerm, NameId );
            Vec_IntWriteEntry( vMap, NameId, iTerm );
            // remember box
            Vec_IntPush( vBoxes, iObj );
        }
    // add fanins for box inputs
    Prs_NtkForEachBox( pNtk, vSigs, iBox )
        if ( !Prs_BoxIsNode(pNtk, iBox) )
        {
            pNtkBox = Prs_ManNtk( vDes, Prs_BoxNtk(pNtk, iBox) );
            iObj = Vec_IntEntry( vBoxes, iBox );
            Vec_IntForEachEntry( vSigs, Index, i )
            {
                i++;
                if ( --Index >= Prs_NtkPiNum(pNtkBox) )
                    continue;
                NameId = Vec_IntEntry( vSigs, i );
                NameId = Prs_NtkSigName( pNtk, NameId );
                iTerm = Cba_BoxBi( pNew, iObj, Index );
                if ( Vec_IntEntry(vMap, NameId) == -1 )
                {
                    iConst0 = Cba_BoxAlloc( pNew, CBA_BOX_C0, 0, 1, -1 );
                    Vec_IntWriteEntry( vMap, NameId, iConst0+1 );
                    if ( iNonDriven == -1 )
                        iNonDriven = NameId;
                    nNonDriven++;
                }
                Cba_ObjSetFanin( pNew, iTerm, Vec_IntEntry(vMap, NameId) );
                Cba_ObjSetName( pNew, iTerm, NameId );
            }
        }
        else
        {
            iObj = Vec_IntEntry( vBoxes, iBox );
            Vec_IntForEachEntryStop( vSigs, Index, i, Vec_IntSize(vSigs)-2 )
            {
                NameId = Vec_IntEntry( vSigs, ++i );
                NameId = Prs_NtkSigName( pNtk, NameId );
                iTerm = Cba_BoxBi( pNew, iObj, i/2 );
                if ( Vec_IntEntry(vMap, NameId) == -1 )
                {
                    iConst0 = Cba_BoxAlloc( pNew, CBA_BOX_C0, 0, 1, -1 );
                    Vec_IntWriteEntry( vMap, NameId, iConst0+1 );
                    if ( iNonDriven == -1 )
                        iNonDriven = NameId;
                    nNonDriven++;
                }
                Cba_ObjSetFanin( pNew, iTerm, Vec_IntEntry(vMap, NameId) );
                Cba_ObjSetName( pNew, iTerm, NameId );
            }
        }
    // add fanins for primary outputs
    Prs_NtkForEachPo( pNtk, NameId, i )
        if ( Vec_IntEntry(vMap, NameId) == -1 )
        {
            iConst0 = Cba_BoxAlloc( pNew, CBA_BOX_C0, 0, 1, -1 );
            Vec_IntWriteEntry( vMap, NameId, iConst0+1 );
            if ( iNonDriven == -1 )
                iNonDriven = NameId;
            nNonDriven++;
        }
    Prs_NtkForEachPo( pNtk, NameId, i )
    {
        iObj = Cba_ObjAlloc( pNew, CBA_OBJ_PO, -1, Vec_IntEntry(vMap, NameId) );
        Cba_ObjSetName( pNew, iObj, NameId );
    }
    if ( nNonDriven )
        printf( "Module %s has %d non-driven nets (for example, %s).\n", Prs_NtkName(pNtk), nNonDriven, Prs_NtkStr(pNtk, iNonDriven) );
    Prs_ManCleanMap( pNtk, vMap );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Cba_Man_t * Prs_ManBuildCba( char * pFileName, Vec_Ptr_t * vDes )
{
    Prs_Ntk_t * pNtk = Prs_ManRoot( vDes );  int i;
    Cba_Man_t * pNew = Cba_ManAlloc( pFileName, Vec_PtrSize(vDes) );
    Vec_Int_t * vMap = Vec_IntStartFull( Abc_NamObjNumMax(pNtk->pStrs) + 1 );
    Vec_Int_t * vTmp = Vec_IntAlloc( Prs_NtkBoxNum(pNtk) );
    Abc_NamDeref( pNew->pStrs );
    pNew->pStrs = Abc_NamRef( pNtk->pStrs );  
    Vec_PtrForEachEntry( Prs_Ntk_t *, vDes, pNtk, i )
        Cba_NtkAlloc( Cba_ManNtk(pNew, i), Prs_NtkId(pNtk), Prs_NtkPiNum(pNtk), Prs_NtkPoNum(pNtk), Prs_NtkCountObjects(pNtk) );
    Vec_PtrForEachEntry( Prs_Ntk_t *, vDes, pNtk, i )
        Prs_ManBuildNtk( Cba_ManNtk(pNew, i), vDes, pNtk, vMap, vTmp );
    assert( Vec_IntCountEntry(vMap, -1) == Vec_IntSize(vMap) );
    Vec_IntFree( vMap );
    Vec_IntFree( vTmp );
    return pNew;
}

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


ABC_NAMESPACE_IMPL_END

