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

  FileName    [verCore.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Verilog parser.]

  Synopsis    [Parses several flavors of structural Verilog.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - August 19, 2006.]

  Revision    [$Id: verCore.c,v 1.00 2006/08/19 00:00:00 alanmi Exp $]

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

#include "ver.h"
#include "mio.h"
#include "main.h"

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

// types of verilog signals
typedef enum { 
    VER_SIG_NONE = 0,
    VER_SIG_INPUT,
    VER_SIG_OUTPUT,
    VER_SIG_INOUT,
    VER_SIG_REG,
    VER_SIG_WIRE
} Ver_SignalType_t;

// types of verilog gates
typedef enum { 
    VER_GATE_AND = 0,
    VER_GATE_OR,
    VER_GATE_XOR,
    VER_GATE_BUF,
    VER_GATE_NAND,
    VER_GATE_NOR,
    VER_GATE_XNOR,
    VER_GATE_NOT
} Ver_GateType_t;

static Ver_Man_t * Ver_ParseStart( char * pFileName, Abc_Lib_t * pGateLib );
static void Ver_ParseStop( Ver_Man_t * p );
static void Ver_ParseFreeData( Ver_Man_t * p );
static void Ver_ParseInternal( Ver_Man_t * p );
static int  Ver_ParseModule( Ver_Man_t * p );
static int  Ver_ParseSignal( Ver_Man_t * p, Abc_Ntk_t * pNtk, Ver_SignalType_t SigType );
static int  Ver_ParseAlways( Ver_Man_t * p, Abc_Ntk_t * pNtk );
static int  Ver_ParseInitial( Ver_Man_t * p, Abc_Ntk_t * pNtk );
static int  Ver_ParseAssign( Ver_Man_t * p, Abc_Ntk_t * pNtk );
static int  Ver_ParseGateStandard( Ver_Man_t * pMan, Abc_Ntk_t * pNtk, Ver_GateType_t GateType );
static int  Ver_ParseGate( Ver_Man_t * p, Abc_Ntk_t * pNtk, Mio_Gate_t * pGate );
static int  Ver_ParseBox( Ver_Man_t * pMan, Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkBox );
static int  Ver_ParseConnectBox( Ver_Man_t * pMan, Abc_Obj_t * pBox );
static int  Ver_ParseAttachBoxes( Ver_Man_t * pMan );

static Abc_Obj_t * Ver_ParseCreatePi( Abc_Ntk_t * pNtk, char * pName );
static Abc_Obj_t * Ver_ParseCreatePo( Abc_Ntk_t * pNtk, char * pName );
static Abc_Obj_t * Ver_ParseCreateLatch( Abc_Ntk_t * pNtk, Abc_Obj_t * pNetLI, Abc_Obj_t * pNetLO );
static Abc_Obj_t * Ver_ParseCreateInv( Abc_Ntk_t * pNtk, Abc_Obj_t * pNet );

static void Ver_ParseRemoveSuffixTable( Ver_Man_t * pMan );

static inline int Ver_NtkIsDefined( Abc_Ntk_t * pNtkBox )  { assert( pNtkBox->pName );     return Abc_NtkPiNum(pNtkBox) || Abc_NtkPoNum(pNtkBox);  }
static inline int Ver_ObjIsConnected( Abc_Obj_t * pObj )   { assert( Abc_ObjIsBox(pObj) ); return Abc_ObjFaninNum(pObj) || Abc_ObjFanoutNum(pObj); }

int glo_fMapped = 0; // this is bad!

typedef struct Ver_Bundle_t_    Ver_Bundle_t;
struct Ver_Bundle_t_
{
    char *          pNameFormal;   // the name of the formal net
    Vec_Ptr_t *     vNetsActual;   // the vector of actual nets (MSB to LSB)
};

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

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

  Synopsis    [Start parser.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Ver_Man_t * Ver_ParseStart( char * pFileName, Abc_Lib_t * pGateLib )
{
    Ver_Man_t * p;
    p = ALLOC( Ver_Man_t, 1 );
    memset( p, 0, sizeof(Ver_Man_t) );
    p->pFileName = pFileName;
    p->pReader   = Ver_StreamAlloc( pFileName );
    if ( p->pReader == NULL )
        return NULL;
    p->Output    = outStream;
    p->vNames    = Vec_PtrAlloc( 100 );
    p->vStackFn  = Vec_PtrAlloc( 100 );
    p->vStackOp  = Vec_IntAlloc( 100 );
    p->vPerm     = Vec_IntAlloc( 100 );
    // create the design library and assign the technology library
    p->pDesign   = Abc_LibCreate( pFileName );
    p->pDesign->pLibrary = pGateLib;
    p->pDesign->pGenlib = Abc_FrameReadLibGen();
    return p;
}

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

  Synopsis    [Stop parser.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseStop( Ver_Man_t * p )
{
    if ( p->pProgress )
        Extra_ProgressBarStop( p->pProgress );
    Ver_StreamFree( p->pReader );
    Vec_PtrFree( p->vNames   );
    Vec_PtrFree( p->vStackFn );
    Vec_IntFree( p->vStackOp );
    Vec_IntFree( p->vPerm );
    free( p );
}
 
/**Function*************************************************************

  Synopsis    [File parser.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Lib_t * Ver_ParseFile( char * pFileName, Abc_Lib_t * pGateLib, int fCheck, int fUseMemMan )
{
    Ver_Man_t * p;
    Abc_Lib_t * pDesign;
    // start the parser
    p = Ver_ParseStart( pFileName, pGateLib );
    p->fMapped    = glo_fMapped;
    p->fCheck     = fCheck;
    p->fUseMemMan = fUseMemMan;
    if ( glo_fMapped )
    {
        Hop_ManStop(p->pDesign->pManFunc);
        p->pDesign->pManFunc = NULL;
    }
    // parse the file
    Ver_ParseInternal( p );
    // save the result
    pDesign = p->pDesign;
    p->pDesign = NULL;
    // stop the parser
    Ver_ParseStop( p );
    return pDesign;
}

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

  Synopsis    [File parser.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseInternal( Ver_Man_t * pMan )
{
    Abc_Ntk_t * pNtk;
    char * pToken;
    int i;

    // preparse the modeles
    pMan->pProgress = Extra_ProgressBarStart( outStream, Ver_StreamGetFileSize(pMan->pReader) );
    while ( 1 )
    {
        // get the next token
        pToken = Ver_ParseGetName( pMan );
        if ( pToken == NULL )
            break;
        if ( strcmp( pToken, "module" ) )
        {
            sprintf( pMan->sError, "Cannot read \"module\" directive." );
            Ver_ParsePrintErrorMessage( pMan );
            return;
        }
        // parse the module
        if ( !Ver_ParseModule(pMan) )
            return;
    }
    Extra_ProgressBarStop( pMan->pProgress );
    pMan->pProgress = NULL;

    // process defined and undefined boxes
    if ( !Ver_ParseAttachBoxes( pMan ) )
        return;

    // connect the boxes and check
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
    {
        // fix the dangling nets
        Abc_NtkFinalizeRead( pNtk );
        // check the network for correctness
        if ( pMan->fCheck && !Abc_NtkCheckRead( pNtk ) )
        {
            pMan->fTopLevel = 1;
            sprintf( pMan->sError, "The network check has failed for network %s.", pNtk->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return;
        }
    }
}

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

  Synopsis    [File parser.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseFreeData( Ver_Man_t * p )
{
    if ( p->pDesign )
    {
        Abc_LibFree( p->pDesign, NULL );
        p->pDesign = NULL;
    }
}

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

  Synopsis    [Prints the error message including the file name and line number.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParsePrintErrorMessage( Ver_Man_t * p )
{
    p->fError = 1;
    if ( p->fTopLevel ) // the line number is not given
        fprintf( p->Output, "%s: %s\n", p->pFileName, p->sError );
    else // print the error message with the line number
        fprintf( p->Output, "%s (line %d): %s\n", 
            p->pFileName, Ver_StreamGetLineNumber(p->pReader), p->sError );
    // free the data
    Ver_ParseFreeData( p );
}

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

  Synopsis    [Finds the network by name or create a new blackbox network.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Ver_ParseFindOrCreateNetwork( Ver_Man_t * pMan, char * pName )
{
    Abc_Ntk_t * pNtkNew;
    // check if the network exists
    if ( pNtkNew = Abc_LibFindModelByName( pMan->pDesign, pName ) )
        return pNtkNew;
//fprintf(outStream,  "Creating network %s.\n", pName );
    // create new network
    pNtkNew = Abc_NtkAlloc( ABC_NTK_NETLIST, ABC_FUNC_BLACKBOX, pMan->fUseMemMan );
    pNtkNew->pName = Extra_UtilStrsav( pName );
    pNtkNew->pSpec = NULL;
    // add module to the design
    Abc_LibAddModel( pMan->pDesign, pNtkNew );
    return pNtkNew;
}

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

  Synopsis    [Finds the network by name or create a new blackbox network.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Obj_t * Ver_ParseFindNet( Abc_Ntk_t * pNtk, char * pName )
{
    Abc_Obj_t * pObj;
    if ( pObj = Abc_NtkFindNet(pNtk, pName) )
        return pObj;
    if ( !strcmp( pName, "1\'b0" ) || !strcmp( pName, "1\'bx" ) )
        return Abc_NtkFindOrCreateNet( pNtk, "1\'b0" );
    if ( !strcmp( pName, "1\'b1" ) )
        return Abc_NtkFindOrCreateNet( pNtk, "1\'b1" );
    return NULL;
}

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

  Synopsis    [Converts the network from the blackbox type into a different one.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseConvertNetwork( Ver_Man_t * pMan, Abc_Ntk_t * pNtk, int fMapped )
{
    if ( fMapped )
    {
        // convert from the blackbox into the network with local functions representated by AIGs
        if ( pNtk->ntkFunc == ABC_FUNC_BLACKBOX )
        {
            // change network type
            assert( pNtk->pManFunc == NULL );
            pNtk->ntkFunc = ABC_FUNC_MAP;
            pNtk->pManFunc = pMan->pDesign->pGenlib;
        }
        else if ( pNtk->ntkFunc != ABC_FUNC_MAP )
        {
            sprintf( pMan->sError, "The network %s appears to have both gates and assign statements. Currently such network are not allowed. One way to fix this problem might be to replace assigns by buffers from the library.", pNtk->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
    }
    else
    {
        // convert from the blackbox into the network with local functions representated by AIGs
        if ( pNtk->ntkFunc == ABC_FUNC_BLACKBOX )
        {
            // change network type
            assert( pNtk->pManFunc == NULL );
            pNtk->ntkFunc = ABC_FUNC_AIG;
            pNtk->pManFunc = pMan->pDesign->pManFunc;
        }
        else if ( pNtk->ntkFunc != ABC_FUNC_AIG )
        {
            sprintf( pMan->sError, "The network %s appears to have both gates and assign statements. Currently such network are not allowed. One way to fix this problem might be to replace assigns by buffers from the library.", pNtk->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
    }
    return 1;
}

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

  Synopsis    [Parses one Verilog module.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseModule( Ver_Man_t * pMan )
{
    Mio_Gate_t * pGate;
    Ver_Stream_t * p = pMan->pReader;
    Abc_Ntk_t * pNtk, * pNtkTemp;
    char * pWord, Symbol;
    int RetValue;

    // get the network name
    pWord = Ver_ParseGetName( pMan );

    // get the network with this name
    pNtk = Ver_ParseFindOrCreateNetwork( pMan, pWord );

    // make sure we stopped at the opening paranthesis
    if ( Ver_StreamPopChar(p) != '(' )
    {
        sprintf( pMan->sError, "Cannot find \"(\" after \"module\" in network %s.", pNtk->pName );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }

    // skip to the end of parantheses
    do {
        if ( Ver_ParseGetName( pMan ) == NULL )
            return 0;
        Symbol = Ver_StreamPopChar(p);
    } while ( Symbol == ',' );
    assert( Symbol == ')' );
    if ( !Ver_ParseSkipComments( pMan ) )
        return 0;
    Symbol = Ver_StreamPopChar(p);
    if ( Symbol != ';' )
    {
        sprintf( pMan->sError, "Expected closing paranthesis after \"module\"." );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }

    // parse the inputs/outputs/registers/wires/inouts
    while ( 1 )
    {
        Extra_ProgressBarUpdate( pMan->pProgress, Ver_StreamGetCurPosition(p), NULL );
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
        if ( !strcmp( pWord, "input" ) )
            RetValue = Ver_ParseSignal( pMan, pNtk, VER_SIG_INPUT );
        else if ( !strcmp( pWord, "output" ) )
            RetValue = Ver_ParseSignal( pMan, pNtk, VER_SIG_OUTPUT );
        else if ( !strcmp( pWord, "reg" ) )
            RetValue = Ver_ParseSignal( pMan, pNtk, VER_SIG_REG );
        else if ( !strcmp( pWord, "wire" ) )
            RetValue = Ver_ParseSignal( pMan, pNtk, VER_SIG_WIRE );
        else if ( !strcmp( pWord, "inout" ) )
            RetValue = Ver_ParseSignal( pMan, pNtk, VER_SIG_INOUT );
        else 
            break;
        if ( RetValue == 0 )
            return 0;
    }

    // parse the remaining statements
    while ( 1 )
    {
        Extra_ProgressBarUpdate( pMan->pProgress, Ver_StreamGetCurPosition(p), NULL );

        if ( !strcmp( pWord, "and" ) )
            RetValue = Ver_ParseGateStandard( pMan, pNtk, VER_GATE_AND );
        else if ( !strcmp( pWord, "or" ) )
            RetValue = Ver_ParseGateStandard( pMan, pNtk, VER_GATE_OR );
        else if ( !strcmp( pWord, "xor" ) )
            RetValue = Ver_ParseGateStandard( pMan, pNtk, VER_GATE_XOR );
        else if ( !strcmp( pWord, "buf" ) )
            RetValue = Ver_ParseGateStandard( pMan, pNtk, VER_GATE_BUF );
        else if ( !strcmp( pWord, "nand" ) )
            RetValue = Ver_ParseGateStandard( pMan, pNtk, VER_GATE_NAND );
        else if ( !strcmp( pWord, "nor" ) )
            RetValue = Ver_ParseGateStandard( pMan, pNtk, VER_GATE_NOR );
        else if ( !strcmp( pWord, "xnor" ) )
            RetValue = Ver_ParseGateStandard( pMan, pNtk, VER_GATE_XNOR );
        else if ( !strcmp( pWord, "not" ) )
            RetValue = Ver_ParseGateStandard( pMan, pNtk, VER_GATE_NOT );

        else if ( !strcmp( pWord, "assign" ) )
            RetValue = Ver_ParseAssign( pMan, pNtk );
        else if ( !strcmp( pWord, "always" ) )
            RetValue = Ver_ParseAlways( pMan, pNtk );
        else if ( !strcmp( pWord, "initial" ) )
            RetValue = Ver_ParseInitial( pMan, pNtk );
        else if ( !strcmp( pWord, "endmodule" ) )
            break;
        else if ( pMan->pDesign->pGenlib && (pGate = Mio_LibraryReadGateByName(pMan->pDesign->pGenlib, pWord)) ) // current design
            RetValue = Ver_ParseGate( pMan, pNtk, pGate );
//        else if ( pMan->pDesign->pLibrary && st_lookup(pMan->pDesign->pLibrary->tModules, pWord, (char**)&pNtkTemp) ) // gate library
//            RetValue = Ver_ParseGate( pMan, pNtkTemp );
        else // assume this is the box used in the current design
        {
            pNtkTemp = Ver_ParseFindOrCreateNetwork( pMan, pWord );
            RetValue = Ver_ParseBox( pMan, pNtk, pNtkTemp );
        }
        if ( RetValue == 0 )
            return 0;
        // skip the comments
        if ( !Ver_ParseSkipComments( pMan ) )
            return 0;
        // get new word
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
    }

    // convert from the blackbox into the network with local functions representated by AIGs
    if ( pNtk->ntkFunc == ABC_FUNC_BLACKBOX )
    {
        if ( Abc_NtkNodeNum(pNtk) > 0 || Abc_NtkBoxNum(pNtk) > 0 )
        {
            if ( !Ver_ParseConvertNetwork( pMan, pNtk, pMan->fMapped ) )
                return 0;
        }
        else
        {
            Abc_Obj_t * pObj, * pBox, * pTerm;
            int i; 
            pBox = Abc_NtkCreateBlackbox(pNtk);
            Abc_NtkForEachPi( pNtk, pObj, i )
            {
                pTerm = Abc_NtkCreateBi(pNtk);
                Abc_ObjAddFanin( pTerm, Abc_ObjFanout0(pObj) );
                Abc_ObjAddFanin( pBox, pTerm );
            }
            Abc_NtkForEachPo( pNtk, pObj, i )
            {
                pTerm = Abc_NtkCreateBo(pNtk);
                Abc_ObjAddFanin( pTerm, pBox );
                Abc_ObjAddFanin( Abc_ObjFanin0(pObj), pTerm );
            }
        }
    }

    // remove the table if needed
    Ver_ParseRemoveSuffixTable( pMan );
    return 1;
}


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

  Synopsis    [Lookups the suffix of the signal of the form [m:n].]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseLookupSuffix( Ver_Man_t * pMan, char * pWord, int * pnMsb, int * pnLsb )
{
    unsigned Value;
    *pnMsb = *pnLsb = -1;
    if ( pMan->tName2Suffix == NULL )
        return 1;
    if ( !st_lookup( pMan->tName2Suffix, (char *)pWord, (char **)&Value ) )
        return 1;
    *pnMsb = (Value >> 8) & 0xff;
    *pnLsb = Value & 0xff;
    return 1;
}

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

  Synopsis    [Lookups the suffix of the signal of the form [m:n].]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseInsertsSuffix( Ver_Man_t * pMan, char * pWord, int nMsb, int nLsb )
{
    unsigned Value;
    if ( pMan->tName2Suffix == NULL )
        pMan->tName2Suffix = st_init_table( strcmp, st_strhash );
    if ( st_is_member( pMan->tName2Suffix, pWord ) )
        return 1;
    assert( nMsb >= 0 && nMsb < 128 );
    assert( nLsb >= 0 && nLsb < 128 );
    Value = (nMsb << 8) | nLsb;
    st_insert( pMan->tName2Suffix, Extra_UtilStrsav(pWord), (char *)Value );
    return 1;
}

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

  Synopsis    [Lookups the suffic of the signal of the form [m:n].]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseRemoveSuffixTable( Ver_Man_t * pMan )
{
    st_generator * gen;
    char * pKey, * pValue;
    if ( pMan->tName2Suffix == NULL )
        return;
    st_foreach_item( pMan->tName2Suffix, gen, (char **)&pKey, (char **)&pValue )
        free( pKey );
    st_free_table( pMan->tName2Suffix );
    pMan->tName2Suffix = NULL;
}

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

  Synopsis    [Determine signal prefix of the form [Beg:End].]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseSignalPrefix( Ver_Man_t * pMan, char ** ppWord, int * pnMsb, int * pnLsb )
{
    char * pWord = *ppWord;
    int nMsb, nLsb;
    assert( pWord[0] == '[' );
    // get the beginning
    nMsb = atoi( pWord + 1 );
    // find the splitter
    while ( *pWord && *pWord != ':' && *pWord != ']' )
        pWord++;
    if ( *pWord == 0 )
    {
        sprintf( pMan->sError, "Cannot find closing bracket in this line." );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    if ( *pWord == ']' )
        nLsb = nMsb;
    else
    {
        assert( *pWord == ':' );
        nLsb = atoi( pWord + 1 );
        // find the closing paranthesis
        while ( *pWord && *pWord != ']' )
            pWord++;
        if ( *pWord == 0 )
        {
            sprintf( pMan->sError, "Cannot find closing bracket in this line." );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        assert( *pWord == ']' );
        pWord++;
    }
    assert( nMsb >= 0 && nLsb >= 0 );
    // return
    *ppWord = pWord;
    *pnMsb = nMsb;
    *pnLsb = nLsb;
    return 1;
}

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

  Synopsis    [Determine signal suffix of the form [m:n].]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseSignalSuffix( Ver_Man_t * pMan, char * pWord, int * pnMsb, int * pnLsb )
{
    char * pCur;
    int Length;
    Length = strlen(pWord);
    assert( pWord[Length-1] == ']' );
    // walk backward
    for ( pCur = pWord + Length - 2; pCur != pWord; pCur-- )
        if ( *pCur == ':' || *pCur == '[' )
            break;
    if ( pCur == pWord )
    {
        sprintf( pMan->sError, "Cannot find opening bracket in signal name %s.", pWord );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    if ( *pCur == '[' )
    {
        *pnMsb = *pnLsb = atoi(pCur+1);
        *pCur = 0;
        return 1;
    }
    assert( *pCur == ':' );
    // get the end of the interval
    *pnLsb = atoi(pCur+1);
    // find the beginning
    for ( pCur = pWord + Length - 2; pCur != pWord; pCur-- )
        if ( *pCur == '[' )
            break;
    if ( pCur == pWord )
    {
        sprintf( pMan->sError, "Cannot find opening bracket in signal name %s.", pWord );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    assert( *pCur == '[' );
    // get the beginning of the interval
    *pnMsb = atoi(pCur+1);
    // cut the word
    *pCur = 0;
    return 1;
}

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

  Synopsis    [Returns the values of constant bits.]

  Description [The resulting bits are in MSB to LSB order.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseConstant( Ver_Man_t * pMan, char * pWord )
{
    int nBits, i;
    assert( pWord[0] >= '1' && pWord[1] <= '9' );
    nBits = atoi(pWord);
    // find the next symbol \'
    while ( *pWord && *pWord != '\'' )
        pWord++;
    if ( *pWord == 0 )
    {
        sprintf( pMan->sError, "Cannot find symbol \' in the constant." );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    assert( *pWord == '\'' );
    pWord++;
    if ( *pWord != 'b' )
    {
        sprintf( pMan->sError, "Currently can only handle binary constants." );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    pWord++;
    // scan the bits
    Vec_PtrClear( pMan->vNames );
    for ( i = 0; i < nBits; i++ )
    {
      if ( pWord[i] != '0' && pWord[i] != '1' && pWord[i] != 'x' )
      {
         sprintf( pMan->sError, "Having problem parsing the binary constant." );
         Ver_ParsePrintErrorMessage( pMan );
         return 0;
      }
      if ( pWord[i] == 'x' ) 
          Vec_PtrPush( pMan->vNames, (void *)0 );
      else 
          Vec_PtrPush( pMan->vNames, (void *)(pWord[i]-'0') );
    }
    return 1;
}

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

  Synopsis    [Parses one directive.]

  Description [The signals are added in the order from LSB to MSB.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseSignal( Ver_Man_t * pMan, Abc_Ntk_t * pNtk, Ver_SignalType_t SigType )
{
    Ver_Stream_t * p = pMan->pReader;
    char Buffer[1000], Symbol, * pWord;
    int nMsb, nLsb, Bit, Limit, i;
    nMsb = nLsb = -1;
    while ( 1 )
    {
        // get the next word
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;

        // check if the range is specified
        if ( pWord[0] == '[' && !pMan->fNameLast )
        {
            assert( nMsb == -1 && nLsb == -1 );
            Ver_ParseSignalPrefix( pMan, &pWord, &nMsb, &nLsb );
            // check the case when there is space between bracket and the next word
            if ( *pWord == 0 )
            {
                // get the signal name
                pWord = Ver_ParseGetName( pMan );
                if ( pWord == NULL )
                    return 0;
            }
        }

        // create signals
        if ( nMsb == -1 && nLsb == -1 )
        {
            if ( SigType == VER_SIG_INPUT || SigType == VER_SIG_INOUT )
                Ver_ParseCreatePi( pNtk, pWord );
            if ( SigType == VER_SIG_OUTPUT || SigType == VER_SIG_INOUT )
                Ver_ParseCreatePo( pNtk, pWord );
            if ( SigType == VER_SIG_WIRE || SigType == VER_SIG_REG )
                Abc_NtkFindOrCreateNet( pNtk, pWord );
        }
        else
        {
            assert( nMsb >= 0 && nLsb >= 0 );
            // add to the hash table
            Ver_ParseInsertsSuffix( pMan, pWord, nMsb, nLsb );
            // add signals from Lsb to Msb
            Limit = nMsb > nLsb? nMsb - nLsb + 1: nLsb - nMsb + 1;
            for ( i = 0, Bit = nLsb; i < Limit; i++, Bit = nMsb > nLsb ? Bit + 1: Bit - 1  )
            {
                sprintf( Buffer, "%s[%d]", pWord, Bit );
                if ( SigType == VER_SIG_INPUT || SigType == VER_SIG_INOUT )
                    Ver_ParseCreatePi( pNtk, Buffer );
                if ( SigType == VER_SIG_OUTPUT || SigType == VER_SIG_INOUT )
                    Ver_ParseCreatePo( pNtk, Buffer );
                if ( SigType == VER_SIG_WIRE || SigType == VER_SIG_REG )
                    Abc_NtkFindOrCreateNet( pNtk, Buffer );
            }
        }

        Symbol = Ver_StreamPopChar(p);
        if ( Symbol == ',' )
            continue;
        if ( Symbol == ';' )
            return 1;
        break;
    }
    sprintf( pMan->sError, "Cannot parse signal line (expected , or ;)." );
    Ver_ParsePrintErrorMessage( pMan );
    return 0;
}

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

  Synopsis    [Parses one directive.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseAlways( Ver_Man_t * pMan, Abc_Ntk_t * pNtk )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Obj_t * pNet, * pNet2;
    int fStopAfterOne;
    char * pWord, * pWord2;
    char Symbol;
    // parse the directive 
    pWord = Ver_ParseGetName( pMan );
    if ( pWord == NULL )
        return 0;
    if ( pWord[0] == '@' )
    {
        Ver_StreamSkipToChars( p, ")" );
        Ver_StreamPopChar(p);
        // parse the directive 
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
    }
    // decide how many statements to parse
    fStopAfterOne = 0;
    if ( strcmp( pWord, "begin" ) )
        fStopAfterOne = 1;
    // iterate over the initial states
    while ( 1 )
    {
        if ( !fStopAfterOne )
        {
            // get the name of the output signal
            pWord = Ver_ParseGetName( pMan );
            if ( pWord == NULL )
                return 0;
            // look for the end of directive
            if ( !strcmp( pWord, "end" ) )
                break;
        }
        // get the fanout net
        pNet = Ver_ParseFindNet( pNtk, pWord );
        if ( pNet == NULL )
        {
            sprintf( pMan->sError, "Cannot read the always statement for %s (output wire is not defined).", pWord );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        // get the equality sign
        Symbol = Ver_StreamPopChar(p);
        if ( Symbol != '<' && Symbol != '=' )
        {
            sprintf( pMan->sError, "Cannot read the assign statement for %s (expected <= or =).", pWord );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        if ( Symbol == '<' )
            Ver_StreamPopChar(p);
        // skip the comments
        if ( !Ver_ParseSkipComments( pMan ) )
            return 0;
        // get the second name
        pWord2 = Ver_ParseGetName( pMan );
        if ( pWord2 == NULL )
            return 0;
        // check if the name is complemented
        if ( pWord2[0] == '~' )
        {
            pNet2 = Ver_ParseFindNet( pNtk, pWord2+1 );
            pNet2 = Ver_ParseCreateInv( pNtk, pNet2 );
        }
        else
            pNet2 = Ver_ParseFindNet( pNtk, pWord2 );
        if ( pNet2 == NULL )
        {
            sprintf( pMan->sError, "Cannot read the always statement for %s (input wire is not defined).", pWord2 );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        // create the latch
        Ver_ParseCreateLatch( pNtk, pNet2, pNet );
        // remove the last symbol
        Symbol = Ver_StreamPopChar(p);
        assert( Symbol == ';' );
        // quit if only one directive
        if ( fStopAfterOne )
            break;
    }
    return 1;
}

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

  Synopsis    [Parses one directive.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseInitial( Ver_Man_t * pMan, Abc_Ntk_t * pNtk )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Obj_t * pNode, * pNet;
    int fStopAfterOne;
    char * pWord, * pEquation;
    char Symbol;
    // parse the directive 
    pWord = Ver_ParseGetName( pMan );
    if ( pWord == NULL )
        return 0;
    // decide how many statements to parse
    fStopAfterOne = 0;
    if ( strcmp( pWord, "begin" ) )
        fStopAfterOne = 1;
    // iterate over the initial states
    while ( 1 )
    {
        if ( !fStopAfterOne )
        {
            // get the name of the output signal
            pWord = Ver_ParseGetName( pMan );
            if ( pWord == NULL )
                return 0;
            // look for the end of directive
            if ( !strcmp( pWord, "end" ) )
                break;
        }
        // get the fanout net
        pNet = Ver_ParseFindNet( pNtk, pWord );
        if ( pNet == NULL )
        {
            sprintf( pMan->sError, "Cannot read the initial statement for %s (output wire is not defined).", pWord );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        // get the equality sign
        Symbol = Ver_StreamPopChar(p);
        if ( Symbol != '<' && Symbol != '=' )
        {
            sprintf( pMan->sError, "Cannot read the assign statement for %s (expected <= or =).", pWord );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        if ( Symbol == '<' )
            Ver_StreamPopChar(p);
        // skip the comments
        if ( !Ver_ParseSkipComments( pMan ) )
            return 0;
        // get the second name
        pEquation = Ver_StreamGetWord( p, ";" );
        if ( pEquation == NULL )
            return 0;
        // find the corresponding latch
        if ( Abc_ObjFaninNum(pNet) == 0 )
        {
            sprintf( pMan->sError, "Cannot find the latch to assign the initial value." );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        pNode = Abc_ObjFanin0(Abc_ObjFanin0(pNet));
        assert( Abc_ObjIsLatch(pNode) );
        // set the initial state
        if ( !strcmp(pEquation, "0") || !strcmp(pEquation, "1\'b0") )
            Abc_LatchSetInit0( pNode );
        else if ( !strcmp(pEquation, "1") || !strcmp(pEquation, "1\'b1") )
            Abc_LatchSetInit1( pNode );
//        else if ( !strcmp(pEquation, "2") )
//            Abc_LatchSetInitDc( pNode );
        else 
        {
            sprintf( pMan->sError, "Incorrect initial value of the latch %s.", Abc_ObjName(pNet) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        // remove the last symbol
        Symbol = Ver_StreamPopChar(p);
        assert( Symbol == ';' );
        // quit if only one directive
        if ( fStopAfterOne )
            break;
    }
    return 1;
}

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

  Synopsis    [Parses one directive.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseAssign( Ver_Man_t * pMan, Abc_Ntk_t * pNtk )
{
    char Buffer[1000], Buffer2[1000];
    Ver_Stream_t * p = pMan->pReader;
    Abc_Obj_t * pNode, * pNet;
    char * pWord, * pName, * pEquation;
    Hop_Obj_t * pFunc;
    char Symbol;
    int i, Bit, Limit, Length, fReduction;
    int nMsb, nLsb;

//    if ( Ver_StreamGetLineNumber(p) == 2756 )
//    {
//        int x = 0;
//    }

    // convert from the blackbox into the network with local functions representated by AIGs
    if ( !Ver_ParseConvertNetwork( pMan, pNtk, pMan->fMapped ) )
        return 0;

    while ( 1 )
    {
        // get the name of the output signal
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
        // check for vector-inputs
        if ( !Ver_ParseLookupSuffix( pMan, pWord, &nMsb, &nLsb ) )
            return 0;
        // handle special case of constant assignment
        if ( nMsb >= 0 && nLsb >= 0 )
        {
            // save the fanout name
            strcpy( Buffer, pWord );
            // get the equality sign
            if ( Ver_StreamPopChar(p) != '=' )
            {
                sprintf( pMan->sError, "Cannot read the assign statement for %s (expected equality sign).", pWord );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
            // get the constant
            pWord = Ver_ParseGetName( pMan );
            if ( pWord == NULL )
                return 0;
            // check if it is indeed a constant
            if ( !(pWord[0] >= '0' && pWord[0] <= '9') )
            {
                sprintf( pMan->sError, "Currently can only assign vector-signal \"%s\" to be a constant.", Buffer );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }

            // get individual bits of the constant
            if ( !Ver_ParseConstant( pMan, pWord ) )
                return 0;
            // check that the constant has the same size
            Limit = nMsb > nLsb? nMsb - nLsb + 1: nLsb - nMsb + 1;
            if ( Limit != Vec_PtrSize(pMan->vNames) )
            {
                sprintf( pMan->sError, "The constant size (%d) is different from the signal\"%s\" size (%d).", 
                    Vec_PtrSize(pMan->vNames), Buffer, Limit );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
            // iterate through the bits
            for ( i = 0, Bit = nLsb; i < Limit; i++, Bit = nMsb > nLsb ? Bit + 1: Bit - 1  )
            {
                // get the fanin net
                if ( Vec_PtrEntry( pMan->vNames, Limit-1-i ) )
                    pNet = Ver_ParseFindNet( pNtk, "1\'b1" );
                else
                    pNet = Ver_ParseFindNet( pNtk, "1\'b0" );
                assert( pNet != NULL );

                // create the buffer
                pNode = Abc_NtkCreateNodeBuf( pNtk, pNet );

                // get the fanout net
                sprintf( Buffer2, "%s[%d]", Buffer, Bit );
                pNet = Ver_ParseFindNet( pNtk, Buffer2 );
                if ( pNet == NULL )
                {
                    sprintf( pMan->sError, "Cannot read the assign statement for %s (output wire is not defined).", pWord );
                    Ver_ParsePrintErrorMessage( pMan );
                    return 0;
                }
                Abc_ObjAddFanin( pNet, pNode );
            }
            // go to the end of the line
            Ver_ParseSkipComments( pMan );
        }
        else
        {
            // consider the case of reduction operations
            fReduction = 0;
            if ( pWord[0] == '{' && !pMan->fNameLast )
                fReduction = 1;
            if ( fReduction )
            {
                pWord++;
                pWord[strlen(pWord)-1] = 0;
                assert( pWord[0] != '\\' );
            }
            // get the fanout net
            pNet = Ver_ParseFindNet( pNtk, pWord );
            if ( pNet == NULL )
            {
                sprintf( pMan->sError, "Cannot read the assign statement for %s (output wire is not defined).", pWord );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
            // get the equality sign
            if ( Ver_StreamPopChar(p) != '=' )
            {
                sprintf( pMan->sError, "Cannot read the assign statement for %s (expected equality sign).", pWord );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
            // skip the comments
            if ( !Ver_ParseSkipComments( pMan ) )
                return 0;
            // get the second name
            if ( fReduction )
                pEquation = Ver_StreamGetWord( p, ";" );
            else
                pEquation = Ver_StreamGetWord( p, ",;" );
            if ( pEquation == NULL )
            {
                sprintf( pMan->sError, "Cannot read the equation for %s.", Abc_ObjName(pNet) );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }

            // consider the case of mapped network
            Vec_PtrClear( pMan->vNames );
            if ( pMan->fMapped )
            {
                if ( !strcmp( pEquation, "1\'b0" ) )
                    pFunc = (Hop_Obj_t *)Mio_LibraryReadConst0(Abc_FrameReadLibGen());
                else if ( !strcmp( pEquation, "1\'b1" ) )
                    pFunc = (Hop_Obj_t *)Mio_LibraryReadConst1(Abc_FrameReadLibGen());
                else
                {
                    // "assign foo = \bar ;"
                    if ( *pEquation == '\\' )
                    {
                        pEquation++;
                        pEquation[strlen(pEquation) - 1] = 0;
                    }
                    if ( Ver_ParseFindNet(pNtk, pEquation) == NULL )
                    {
                        sprintf( pMan->sError, "Cannot read Verilog with non-trivial assignments in the mapped netlist." );
                        Ver_ParsePrintErrorMessage( pMan );
                        return 0;
                    }
                    Vec_PtrPush( pMan->vNames, (void *)strlen(pEquation) );
                    Vec_PtrPush( pMan->vNames, pEquation );
                    // get the buffer
                    pFunc = (Hop_Obj_t *)Mio_LibraryReadBuf(Abc_FrameReadLibGen());
                    if ( pFunc == NULL )
                    {
                        sprintf( pMan->sError, "Reading assign statement for node %s has failed because the genlib library has no buffer.", Abc_ObjName(pNet) );
                        Ver_ParsePrintErrorMessage( pMan );
                        return 0;
                    }
                }
            }
            else
            {
                if ( !strcmp(pEquation, "0") || !strcmp(pEquation, "1\'b0") || !strcmp(pEquation, "1\'bx") )
                    pFunc = Hop_ManConst0(pNtk->pManFunc);
                else if ( !strcmp(pEquation, "1") || !strcmp(pEquation, "1\'b1") )
                    pFunc = Hop_ManConst1(pNtk->pManFunc);
                else if ( fReduction )
                    pFunc = Ver_FormulaReduction( pEquation, pNtk->pManFunc, pMan->vNames, pMan->sError );  
                else
                    pFunc = Ver_FormulaParser( pEquation, pNtk->pManFunc, pMan->vNames, pMan->vStackFn, pMan->vStackOp, pMan->sError );  
                if ( pFunc == NULL )
                {
                    Ver_ParsePrintErrorMessage( pMan );
                    return 0;
                }
            }

            // create the node with the given inputs
            pNode = Abc_NtkCreateNode( pNtk );
            pNode->pData = pFunc;
            Abc_ObjAddFanin( pNet, pNode );
            // connect to fanin nets
            for ( i = 0; i < Vec_PtrSize(pMan->vNames)/2; i++ )
            {
                // get the name of this signal
                Length = (int)Vec_PtrEntry( pMan->vNames, 2*i );
                pName  = Vec_PtrEntry( pMan->vNames, 2*i + 1 );
                pName[Length] = 0;
                // find the corresponding net
                pNet = Ver_ParseFindNet( pNtk, pName );
                if ( pNet == NULL )
                {
                    sprintf( pMan->sError, "Cannot read the assign statement for %s (input wire %s is not defined).", pWord, pName );
                    Ver_ParsePrintErrorMessage( pMan );
                    return 0;
                }
                Abc_ObjAddFanin( pNode, pNet );
            }
        }

        Symbol = Ver_StreamPopChar(p);
        if ( Symbol == ',' )
            continue;
        if ( Symbol == ';' )
            return 1;
    }
    return 1;
}

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

  Synopsis    [Parses one directive.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseGateStandard( Ver_Man_t * pMan, Abc_Ntk_t * pNtk, Ver_GateType_t GateType )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Obj_t * pNet, * pNode;
    char * pWord, Symbol;

    // convert from the blackbox into the network with local functions representated by AIGs
    if ( !Ver_ParseConvertNetwork( pMan, pNtk, pMan->fMapped ) )
        return 0;

    // this is gate name - throw it away
    if ( Ver_StreamPopChar(p) != '(' )
    {
        sprintf( pMan->sError, "Cannot parse a standard gate (expected opening paranthesis)." );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    Ver_ParseSkipComments( pMan );

    // create the node
    pNode = Abc_NtkCreateNode( pNtk );

    // parse pairs of formal/actural inputs
    while ( 1 )
    {
        // parse the output name
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
        // get the net corresponding to this output
        pNet = Ver_ParseFindNet( pNtk, pWord );
        if ( pNet == NULL )
        {
            sprintf( pMan->sError, "Net is missing in gate %s.", pWord );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        // if this is the first net, add it as an output
        if ( Abc_ObjFanoutNum(pNode) == 0 )
            Abc_ObjAddFanin( pNet, pNode );
        else
            Abc_ObjAddFanin( pNode, pNet );
        // check if it is the end of gate
        Ver_ParseSkipComments( pMan );
        Symbol = Ver_StreamPopChar(p);
        if ( Symbol == ')' )
            break;
        // skip comma
        if ( Symbol != ',' )
        {
            sprintf( pMan->sError, "Cannot parse a standard gate %s (expected closing paranthesis).", Abc_ObjName(Abc_ObjFanout0(pNode)) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        Ver_ParseSkipComments( pMan );
    }
    if ( (GateType == VER_GATE_BUF || GateType == VER_GATE_NOT) && Abc_ObjFaninNum(pNode) != 1 )
    {
        sprintf( pMan->sError, "Buffer or interver with multiple fanouts %s (currently not supported).", Abc_ObjName(Abc_ObjFanout0(pNode)) );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }

    // check if it is the end of gate
    Ver_ParseSkipComments( pMan );
    if ( Ver_StreamPopChar(p) != ';' )
    {
        sprintf( pMan->sError, "Cannot read standard gate %s (expected closing semicolumn).", Abc_ObjName(Abc_ObjFanout0(pNode)) );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    // add logic function
    if ( GateType == VER_GATE_AND || GateType == VER_GATE_NAND )
        pNode->pData = Hop_CreateAnd( pNtk->pManFunc, Abc_ObjFaninNum(pNode) );
    else if ( GateType == VER_GATE_OR || GateType == VER_GATE_NOR )
        pNode->pData = Hop_CreateOr( pNtk->pManFunc, Abc_ObjFaninNum(pNode) );
    else if ( GateType == VER_GATE_XOR || GateType == VER_GATE_XNOR )
        pNode->pData = Hop_CreateExor( pNtk->pManFunc, Abc_ObjFaninNum(pNode) );
    else if ( GateType == VER_GATE_BUF || GateType == VER_GATE_NOT )
        pNode->pData = Hop_CreateAnd( pNtk->pManFunc, Abc_ObjFaninNum(pNode) );
    if ( GateType == VER_GATE_NAND || GateType == VER_GATE_NOR || GateType == VER_GATE_XNOR || GateType == VER_GATE_NOT )
        pNode->pData = Hop_Not( pNode->pData );
    return 1;
}

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

  Synopsis    [Returns the index of the given pin the gate.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_FindGateInput( Mio_Gate_t * pGate, char * pName )
{
    Mio_Pin_t * pGatePin;
    int i;
    for ( i = 0, pGatePin = Mio_GateReadPins(pGate); pGatePin != NULL; pGatePin = Mio_PinReadNext(pGatePin), i++ )
        if ( strcmp(pName, Mio_PinReadName(pGatePin)) == 0 )
            return i;
    if ( strcmp(pName, Mio_GateReadOutName(pGate)) == 0 )
        return i;
    return -1;
}

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

  Synopsis    [Parses one directive.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseGate( Ver_Man_t * pMan, Abc_Ntk_t * pNtk, Mio_Gate_t * pGate )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Obj_t * pNetActual, * pNode;
    char * pWord, Symbol;
    int Input, i, nFanins = Mio_GateReadInputs(pGate);

    // convert from the blackbox into the network with local functions representated by gates
    if ( 1 != pMan->fMapped )
    {
        sprintf( pMan->sError, "The network appears to be mapped. Use \"r -m\" to read mapped Verilog." );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }

    // update the network type if needed
    if ( !Ver_ParseConvertNetwork( pMan, pNtk, 1 ) )
        return 0;

    // parse the directive and set the pointers to the PIs/POs of the gate
    pWord = Ver_ParseGetName( pMan );
    if ( pWord == NULL )
        return 0;
    // this is gate name - throw it away
    if ( Ver_StreamPopChar(p) != '(' )
    {
        sprintf( pMan->sError, "Cannot parse gate %s (expected opening paranthesis).", Mio_GateReadName(pGate) );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    Ver_ParseSkipComments( pMan );

    // start the node
    pNode = Abc_NtkCreateNode( pNtk );
    pNode->pData = pGate;

    // parse pairs of formal/actural inputs
    Vec_IntClear( pMan->vPerm );
    while ( 1 )
    {
        // process one pair of formal/actual parameters
        if ( Ver_StreamPopChar(p) != '.' )
        {
            sprintf( pMan->sError, "Cannot parse gate %s (expected .).", Mio_GateReadName(pGate) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // parse the formal name
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;

        // find the corresponding pin of the gate
        Input = Ver_FindGateInput( pGate, pWord );
        if ( Input == -1 )
        {
            sprintf( pMan->sError, "Formal input name %s cannot be found in the gate %s.", pWord, Mio_GateReadOutName(pGate) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // open the paranthesis
        if ( Ver_StreamPopChar(p) != '(' )
        {
            sprintf( pMan->sError, "Cannot formal parameter %s of gate %s (expected opening paranthesis).", pWord, Mio_GateReadName(pGate) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // parse the actual name
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
        // check if the name is complemented
        assert( pWord[0] != '~' );
/*
        fCompl = (pWord[0] == '~');
        if ( fCompl )
        {
            fComplUsed = 1;
            pWord++;
            if ( pNtk->pData == NULL )
                pNtk->pData = Extra_MmFlexStart();
        }
*/
        // get the actual net
        pNetActual = Ver_ParseFindNet( pNtk, pWord );
        if ( pNetActual == NULL )
        {
            sprintf( pMan->sError, "Actual net %s is missing.", pWord );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // close the paranthesis
        if ( Ver_StreamPopChar(p) != ')' )
        {
            sprintf( pMan->sError, "Cannot formal parameter %s of gate %s (expected closing paranthesis).", pWord, Mio_GateReadName(pGate) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // add the fanin
        if ( Input < nFanins )
        {
            Vec_IntPush( pMan->vPerm, Input );
            Abc_ObjAddFanin( pNode, pNetActual ); // fanin
        }
        else
            Abc_ObjAddFanin( pNetActual, pNode ); // fanout

        // check if it is the end of gate
        Ver_ParseSkipComments( pMan );
        Symbol = Ver_StreamPopChar(p);
        if ( Symbol == ')' )
            break;

        // skip comma
        if ( Symbol != ',' )
        {
            sprintf( pMan->sError, "Cannot formal parameter %s of gate %s (expected closing paranthesis).", pWord, Mio_GateReadName(pGate) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        Ver_ParseSkipComments( pMan );
    }

    // check that the gate as the same number of input
    if ( !(Abc_ObjFaninNum(pNode) == nFanins && Abc_ObjFanoutNum(pNode) == 1) )
    {
        sprintf( pMan->sError, "Parsing of gate %s has failed.", Mio_GateReadName(pGate) );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }

    // check if it is the end of gate
    Ver_ParseSkipComments( pMan );
    if ( Ver_StreamPopChar(p) != ';' )
    {
        sprintf( pMan->sError, "Cannot read gate %s (expected closing semicolumn).", Mio_GateReadName(pGate) );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    
    // check if we need to permute the inputs
    Vec_IntForEachEntry( pMan->vPerm, Input, i )
        if ( Input != i )
            break;
    if ( i < Vec_IntSize(pMan->vPerm) )
    {
        // add the fanin numnbers to the end of the permuation array
        for ( i = 0; i < nFanins; i++ )
            Vec_IntPush( pMan->vPerm, Abc_ObjFaninId(pNode, i) );
        // write the fanin numbers into their corresponding places (according to the gate) 
        for ( i = 0; i < nFanins; i++ )
            Vec_IntWriteEntry( &pNode->vFanins, Vec_IntEntry(pMan->vPerm, i), Vec_IntEntry(pMan->vPerm, i+nFanins) );
    }
    return 1;
}

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

  Synopsis    [Parses one directive.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseBox( Ver_Man_t * pMan, Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkBox )
{
    char Buffer[1000];
    Ver_Stream_t * p = pMan->pReader;
    Ver_Bundle_t * pBundle;
    Vec_Ptr_t * vBundles;
    Abc_Obj_t * pNetActual; 
    Abc_Obj_t * pNode;
    char * pWord, Symbol;
    int fCompl, fFormalIsGiven;
    int i, k, Bit, Limit, nMsb, nLsb, fQuit, flag;

    // gate the name of the box
    pWord = Ver_ParseGetName( pMan );
    if ( pWord == NULL )
        return 0;

    // create a box with this name
    pNode = Abc_NtkCreateBlackbox( pNtk );
    pNode->pData = pNtkBox;
    Abc_ObjAssignName( pNode, pWord, NULL );

    // continue parsing the box
    if ( Ver_StreamPopChar(p) != '(' )
    {
        sprintf( pMan->sError, "Cannot parse box %s (expected opening paranthesis).", Abc_ObjName(pNode) );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    Ver_ParseSkipComments( pMan );
 
    // parse pairs of formal/actual inputs
    vBundles = Vec_PtrAlloc( 16 );
    pNode->pCopy = (Abc_Obj_t *)vBundles;
    while ( 1 )
    {
        // allocate the bundle (formal name + array of actual nets)
        pBundle = ALLOC( Ver_Bundle_t, 1 );
        pBundle->pNameFormal = NULL;
        pBundle->vNetsActual = Vec_PtrAlloc( 4 );
        Vec_PtrPush( vBundles, pBundle );

        // process one pair of formal/actual parameters
        fFormalIsGiven = 0;
        if ( Ver_StreamScanChar(p) == '.' )
        {
            fFormalIsGiven = 1;
            if ( Ver_StreamPopChar(p) != '.' )
            {
                sprintf( pMan->sError, "Cannot parse box %s (expected .).", Abc_ObjName(pNode) );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }

            // parse the formal name
            pWord = Ver_ParseGetName( pMan );
            if ( pWord == NULL )
                return 0;

            // save the name
            pBundle->pNameFormal = Extra_UtilStrsav( pWord );

            // open the paranthesis
            if ( Ver_StreamPopChar(p) != '(' )
            {
                sprintf( pMan->sError, "Cannot formal parameter %s of box %s (expected opening paranthesis).", pWord, Abc_ObjName(pNode));
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
            Ver_ParseSkipComments( pMan );
        }

        // check if this is the beginning of {} expression
        Symbol = Ver_StreamScanChar(p);

        // consider the case of vector-inputs
        if ( Symbol == '{' )
        {
            // skip this char
            Ver_StreamPopChar(p);

            // read actual names
            i = 0;
            fQuit = 0;
            while ( 1 )
            {
                // parse the formal name
                Ver_ParseSkipComments( pMan );
                pWord = Ver_ParseGetName( pMan );
                if ( pWord == NULL )
                    return 0;

                // check if the last char is a closing brace
                if ( pWord[strlen(pWord)-1] == '}' )
                {
                    pWord[strlen(pWord)-1] = 0;
                    fQuit = 1;
                }
                if ( pWord[0] == 0 )
                    break;

                // check for constant
                if ( pWord[0] >= '1' && pWord[0] <= '9' )
                {
                    if ( !Ver_ParseConstant( pMan, pWord ) )
                        return 0;
                    // add constant MSB to LSB
                    for ( k = 0; k < Vec_PtrSize(pMan->vNames); k++, i++ )
                    {
                        // get the actual net
                        sprintf( Buffer, "1\'b%d", (int)(Vec_PtrEntry(pMan->vNames,k) != NULL) );
                        pNetActual = Ver_ParseFindNet( pNtk, Buffer );
                        if ( pNetActual == NULL )
                        {
                            sprintf( pMan->sError, "Actual net \"%s\" is missing in gate \"%s\".", Buffer, Abc_ObjName(pNode) );
                            Ver_ParsePrintErrorMessage( pMan );
                            return 0;
                        }
                        Vec_PtrPush( pBundle->vNetsActual, pNetActual );
                    }
                }
                else
                {
                    // get the suffix of the form [m:n]
                    if ( pWord[strlen(pWord)-1] == ']' && !pMan->fNameLast )
                        Ver_ParseSignalSuffix( pMan, pWord, &nMsb, &nLsb );
                    else
                        Ver_ParseLookupSuffix( pMan, pWord, &nMsb, &nLsb );

                    // generate signals
                    if ( nMsb == -1 && nLsb == -1 )
                    {
                        // get the actual net
                        pNetActual = Ver_ParseFindNet( pNtk, pWord );
                        if ( pNetActual == NULL )
                        {
                            if ( !strncmp(pWord, "Open_", 5) ||
                                !strncmp(pWord, "dct_unconnected", 15) ) 
                                pNetActual = Abc_NtkCreateNet( pNtk );
                            else
                            {
                                sprintf( pMan->sError, "Actual net \"%s\" is missing in box \"%s\".", pWord, Abc_ObjName(pNode) );
                                Ver_ParsePrintErrorMessage( pMan );
                                return 0;
                            }
                        }
                        Vec_PtrPush( pBundle->vNetsActual, pNetActual );
                        i++;
                    }
                    else
                    {
                        // go from MSB to LSB
                        assert( nMsb >= 0 && nLsb >= 0 );
                        Limit = (nMsb > nLsb) ? nMsb - nLsb + 1: nLsb - nMsb + 1;  
                        for ( Bit = nMsb, k = Limit - 1; k >= 0; Bit = (nMsb > nLsb ? Bit - 1: Bit + 1), k--, i++ )
                        {
                            // get the actual net
                            sprintf( Buffer, "%s[%d]", pWord, Bit );
                            pNetActual = Ver_ParseFindNet( pNtk, Buffer );
                            if ( pNetActual == NULL )
                            {
                                if ( !strncmp(pWord, "Open_", 5) ||
                                    !strncmp(pWord, "dct_unconnected", 15) ) 
                                    pNetActual = Abc_NtkCreateNet( pNtk );
                                else
                                {
                                    sprintf( pMan->sError, "Actual net \"%s\" is missing in box \"%s\".", pWord, Abc_ObjName(pNode) );
                                    Ver_ParsePrintErrorMessage( pMan );
                                    return 0;
                                }
                            }
                            Vec_PtrPush( pBundle->vNetsActual, pNetActual );
                        }
                    }
                }

                if ( fQuit )
                    break;

                // skip comma
                Ver_ParseSkipComments( pMan );
                Symbol = Ver_StreamPopChar(p);
                if ( Symbol == '}' )
                    break;
                if ( Symbol != ',' )
                {
                    sprintf( pMan->sError, "Cannot parse formal parameter %s of gate %s (expected comma).", pWord, Abc_ObjName(pNode) );
                    Ver_ParsePrintErrorMessage( pMan );
                    return 0;
                }
            }
        }
        else
        {
            // get the next word
            pWord = Ver_ParseGetName( pMan );
            if ( pWord == NULL )
                return 0;
            // consider the case of empty name
            fCompl = 0;
            if ( pWord[0] == 0 )
            {
                pNetActual = Abc_NtkCreateNet( pNtk );
		        Vec_PtrPush( pBundle->vNetsActual, Abc_ObjNotCond( pNetActual, fCompl ) );
            }
            else
            {
                // get the actual net
                flag=0;
                pNetActual = Ver_ParseFindNet( pNtk, pWord );
                if ( pNetActual == NULL ) 
                {
                    Ver_ParseLookupSuffix( pMan, pWord, &nMsb, &nLsb );
                    if ( nMsb == -1 && nLsb == -1 ) 
                    {
                        Ver_ParseSignalSuffix( pMan, pWord, &nMsb, &nLsb );
                        if ( nMsb == -1 && nLsb == -1 ) 
                        {
                            if ( !strncmp(pWord, "Open_", 5) ||
                                !strncmp(pWord, "dct_unconnected", 15) ) 
                            {
                                pNetActual = Abc_NtkCreateNet( pNtk );
                                Vec_PtrPush( pBundle->vNetsActual, pNetActual );
                            } 
                            else 
                            {
                                sprintf( pMan->sError, "Actual net \"%s\" is missing in box \"%s\".", pWord, Abc_ObjName(pNode) );
                                Ver_ParsePrintErrorMessage( pMan );
                                return 0;
                            }
                        } 
                        else 
                        {
                            flag=1;
                        }
                    } 
                    else 
                    {
                        flag=1;
                    }
                    if (flag) 
                    {
                        Limit = (nMsb > nLsb) ? nMsb - nLsb + 1: nLsb - nMsb + 1;  
                        for ( Bit = nMsb, k = Limit - 1; k >= 0; Bit = (nMsb > nLsb ? Bit - 1: Bit + 1), k--)
                        {
                            // get the actual net
                            sprintf( Buffer, "%s[%d]", pWord, Bit );
                            pNetActual = Ver_ParseFindNet( pNtk, Buffer );
                            if ( pNetActual == NULL )
                            {
                                if ( !strncmp(pWord, "Open_", 5) ||
                                    !strncmp(pWord, "dct_unconnected", 15)) 
                                    pNetActual = Abc_NtkCreateNet( pNtk );
                                else
                                {
                                    sprintf( pMan->sError, "Actual net \"%s\" is missing in box \"%s\".", pWord, Abc_ObjName(pNode) );
                                    Ver_ParsePrintErrorMessage( pMan );
                                    return 0;
                                }
                            }
                            Vec_PtrPush( pBundle->vNetsActual, pNetActual );
                        }
                    }
                } 
                else 
                {
                    Vec_PtrPush( pBundle->vNetsActual, Abc_ObjNotCond( pNetActual, fCompl ) );
                }
            }
        }

        if ( fFormalIsGiven )
        {
            // close the paranthesis
            Ver_ParseSkipComments( pMan );
            if ( Ver_StreamPopChar(p) != ')' )
            {
                sprintf( pMan->sError, "Cannot parse formal parameter %s of box %s (expected closing paranthesis).", pWord, Abc_ObjName(pNode) );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
            Ver_ParseSkipComments( pMan );
        }

        // check if it is the end of gate
        Symbol = Ver_StreamPopChar(p);
        if ( Symbol == ')' )
            break;
        // skip comma
        if ( Symbol != ',' )
        {
            sprintf( pMan->sError, "Cannot parse formal parameter %s of box %s (expected comma).", pWord, Abc_ObjName(pNode) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        Ver_ParseSkipComments( pMan );
    }

    // check if it is the end of gate
    Ver_ParseSkipComments( pMan );
    if ( Ver_StreamPopChar(p) != ';' )
    {
        sprintf( pMan->sError, "Cannot read box %s (expected closing semicolumn).", Abc_ObjName(pNode) );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }

    return 1;
}

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

  Synopsis    [Connects one box to the network]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseFreeBundle( Ver_Bundle_t * pBundle )
{
    FREE( pBundle->pNameFormal );
    Vec_PtrFree( pBundle->vNetsActual );
    free( pBundle );
}

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

  Synopsis    [Connects one box to the network]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseConnectBox( Ver_Man_t * pMan, Abc_Obj_t * pBox )
{
    Vec_Ptr_t * vBundles = (Vec_Ptr_t *)pBox->pCopy;
    Abc_Ntk_t * pNtk = pBox->pNtk;
    Abc_Ntk_t * pNtkBox = pBox->pData;
    Abc_Obj_t * pTerm, * pTermNew, * pNetAct;
    Ver_Bundle_t * pBundle;
    char * pNameFormal;
    int i, k, j, iBundle, Length;

    assert( !Ver_ObjIsConnected(pBox) );
    assert( Ver_NtkIsDefined(pNtkBox) );
    assert( !Abc_NtkHasBlackbox(pNtkBox) || Abc_NtkBoxNum(pNtkBox) == 1 );
/*
    // clean the PI/PO nets
    Abc_NtkForEachPi( pNtkBox, pTerm, i )
        Abc_ObjFanout0(pTerm)->pCopy = NULL;
    Abc_NtkForEachPo( pNtkBox, pTerm, i )
        Abc_ObjFanin0(pTerm)->pCopy = NULL;
*/
    // check if some of them do not have formal names
    Vec_PtrForEachEntry( vBundles, pBundle, k )
        if ( pBundle->pNameFormal == NULL )
            break;
    if ( k < Vec_PtrSize(vBundles) )
    {
        fprintf(outStream,  "Warning: The instance %s of network %s will be connected without using formal names.\n", pNtkBox->pName, Abc_ObjName(pBox) );
        // add all actual nets in the bundles
        iBundle = 0;
        Vec_PtrForEachEntry( vBundles, pBundle, j )
            iBundle += Vec_PtrSize(pBundle->vNetsActual);

        // check the number of actual nets is the same as the number of formal nets
        if ( iBundle != Abc_NtkPiNum(pNtkBox) + Abc_NtkPoNum(pNtkBox) )
        {
            sprintf( pMan->sError, "The number of actual IOs (%d) is different from the number of formal IOs (%d) when instantiating network %s in box %s.", 
                Vec_PtrSize(vBundles), Abc_NtkPiNum(pNtkBox) + Abc_NtkPoNum(pNtkBox), pNtkBox->pName, Abc_ObjName(pBox) );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
        // connect bundles in the natural order
        iBundle = 0;
        Abc_NtkForEachPi( pNtkBox, pTerm, i )
        {
            pBundle = Vec_PtrEntry( vBundles, iBundle++ );
            // the bundle is found - add the connections - using order LSB to MSB
            Vec_PtrForEachEntryReverse( pBundle->vNetsActual, pNetAct, k )
            {
                pTermNew = Abc_NtkCreateBi( pNtk );
                Abc_ObjAddFanin( pBox, pTermNew );
                Abc_ObjAddFanin( pTermNew, pNetAct );
                i++;
            }
            i--;
        }
        // create fanins of the box
        Abc_NtkForEachPo( pNtkBox, pTerm, i )
        {
            pBundle = Vec_PtrEntry( vBundles, iBundle++ );
            // the bundle is found - add the connections - using order LSB to MSB
            Vec_PtrForEachEntryReverse( pBundle->vNetsActual, pNetAct, k )
            {
                pTermNew = Abc_NtkCreateBo( pNtk );
                Abc_ObjAddFanin( pTermNew, pBox );
                Abc_ObjAddFanin( pNetAct, pTermNew );
                i++;
            }
            i--;
        }

        // free the bundling
        Vec_PtrForEachEntry( vBundles, pBundle, k )
            Ver_ParseFreeBundle( pBundle );
        Vec_PtrFree( vBundles );
        pBox->pCopy = NULL;
        return 1;
    }

    // bundles arrive in any order - but inside each bundle the order is MSB to LSB
    // make sure every formal PI has a corresponding net
    Abc_NtkForEachPi( pNtkBox, pTerm, i )
    {
        // get the name of this formal net
        pNameFormal = Abc_ObjName( Abc_ObjFanout0(pTerm) );
        // try to find the bundle with this formal net
        pBundle = NULL;
        Vec_PtrForEachEntry( vBundles, pBundle, k )
            if ( !strcmp(pBundle->pNameFormal, pNameFormal) )
                break;
        assert( pBundle != NULL );
        // if the bundle is not found, try without parantheses
        if ( k == Vec_PtrSize(vBundles) )
        {
            pBundle = NULL;
            Length = strlen(pNameFormal);
            if ( pNameFormal[Length-1] == ']' )
            {
                // find the opening brace
                for ( Length--; Length >= 0; Length-- )
                    if ( pNameFormal[Length] == '[' )
                        break;
                // compare names before brace
                if ( Length > 0 )
                {
                    Vec_PtrForEachEntry( vBundles, pBundle, j )
                        if ( !strncmp(pBundle->pNameFormal, pNameFormal, Length) )
                            break;
                    if ( j == Vec_PtrSize(vBundles) )
                        pBundle = NULL;
                }
            }
            if ( pBundle == NULL )
            {
                sprintf( pMan->sError, "Cannot find an actual net for the formal net %s when instantiating network %s in box %s.", 
                    pNameFormal, pNtkBox->pName, Abc_ObjName(pBox) );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
        }
        // the bundle is found - add the connections - using order LSB to MSB
        Vec_PtrForEachEntryReverse( pBundle->vNetsActual, pNetAct, k )
        {
            pTermNew = Abc_NtkCreateBi( pNtk );
            Abc_ObjAddFanin( pBox, pTermNew );
            Abc_ObjAddFanin( pTermNew, pNetAct );
            i++;
        }
        i--;
    }

    // connect those formal POs that do have nets
    Abc_NtkForEachPo( pNtkBox, pTerm, i )
    {
        // get the name of this PI
        pNameFormal = Abc_ObjName( Abc_ObjFanin0(pTerm) );
        // try to find this formal net in the bundle
        pBundle = NULL;
        Vec_PtrForEachEntry( vBundles, pBundle, k )
            if ( !strcmp(pBundle->pNameFormal, pNameFormal) )
                break;
        assert( pBundle != NULL );
        // if the name is not found, try without parantheses
        if ( k == Vec_PtrSize(vBundles) )
        {
            pBundle = NULL;
            Length = strlen(pNameFormal);
            if ( pNameFormal[Length-1] == ']' )
            {
                // find the opening brace
                for ( Length--; Length >= 0; Length-- )
                    if ( pNameFormal[Length] == '[' )
                        break;
                // compare names before brace
                if ( Length > 0 )
                {
                    Vec_PtrForEachEntry( vBundles, pBundle, j )
                        if ( !strncmp(pBundle->pNameFormal, pNameFormal, Length) )
                            break;
                    if ( j == Vec_PtrSize(vBundles) )
                        pBundle = NULL;
                }
            }
            if ( pBundle == NULL )
            {
//                fprintf(outStream,  "Warning: The formal output %s is not driven when instantiating network %s in box %s.", 
//                    pNameFormal, pNtkBox->pName, Abc_ObjName(pBox) );
                continue;
            }
        }
        // the bundle is found - add the connections
        Vec_PtrForEachEntryReverse( pBundle->vNetsActual, pNetAct, k )
        {
            if ( !strcmp(Abc_ObjName(pNetAct), "1\'b0") || !strcmp(Abc_ObjName(pNetAct), "1\'b1") )
            {
                sprintf( pMan->sError, "It looks like formal output %s is driving a constant net (%s) when instantiating network %s in box %s.", 
                    pBundle->pNameFormal, Abc_ObjName(pNetAct), pNtkBox->pName, Abc_ObjName(pBox) );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
            pTermNew = Abc_NtkCreateBo( pNtk );
            Abc_ObjAddFanin( pTermNew, pBox );
            Abc_ObjAddFanin( pNetAct, pTermNew );
            i++;
        }
        i--;
    }

    // free the bundling
    Vec_PtrForEachEntry( vBundles, pBundle, k )
        Ver_ParseFreeBundle( pBundle );
    Vec_PtrFree( vBundles );
    pBox->pCopy = NULL;
    return 1;
}


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

  Synopsis    [Connects the defined boxes.]

  Description [Returns 2 if there are any undef boxes.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseConnectDefBoxes( Ver_Man_t * pMan )
{
    Abc_Ntk_t * pNtk;
    Abc_Obj_t * pBox;
    int i, k, RetValue = 1;
    // go through all the modules
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
    {
        // go through all the boxes of this module
        Abc_NtkForEachBox( pNtk, pBox, k )
        {
            if ( Abc_ObjIsLatch(pBox) )
                continue;
            // skip internal boxes of the blackboxes
            if ( pBox->pData == NULL )
                continue;
            // if the network is undefined, it will be connected later
            if ( !Ver_NtkIsDefined(pBox->pData) )
            {
                RetValue = 2;
                continue;
            }
            // connect the box
            if ( !Ver_ParseConnectBox( pMan, pBox ) )
                return 0;
            // if the network is a true blackbox, skip
            if ( Abc_NtkHasBlackbox(pBox->pData) )
                continue;
            // convert the box to the whitebox
            Abc_ObjBlackboxToWhitebox( pBox );
        }
    }
    return RetValue;
}

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

  Synopsis    [Collects the undef boxes and maps them into their instances.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Ver_ParseCollectUndefBoxes( Ver_Man_t * pMan )
{
    Vec_Ptr_t * vUndefs;
    Abc_Ntk_t * pNtk, * pNtkBox;
    Abc_Obj_t * pBox;
    int i, k;
    // clear the module structures
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
        pNtk->pData = NULL;
    // go through all the blackboxes
    vUndefs = Vec_PtrAlloc( 16 );
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
    {
        Abc_NtkForEachBlackbox( pNtk, pBox, k )
        {
            pNtkBox = pBox->pData;
            if ( pNtkBox == NULL )
                continue;
            if ( Ver_NtkIsDefined(pNtkBox) )
                continue;
            if ( pNtkBox->pData == NULL )
            {
                // save the box
                Vec_PtrPush( vUndefs, pNtkBox );
                pNtkBox->pData = Vec_PtrAlloc( 16 );
            }
            // save the instance
            Vec_PtrPush( pNtkBox->pData, pBox );
        }
    }
    return vUndefs;
}

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

  Synopsis    [Reports how many times each type of undefined box occurs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseReportUndefBoxes( Ver_Man_t * pMan )
{
    Abc_Ntk_t * pNtk;
    Abc_Obj_t * pBox;
    int i, k, nBoxes;
    // clean 
    nBoxes = 0;
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
    {
        pNtk->fHiePath = 0;
        if ( !Ver_NtkIsDefined(pNtk) )
            nBoxes++;
    }
    // count
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
        Abc_NtkForEachBlackbox( pNtk, pBox, k )
            if ( pBox->pData && !Ver_NtkIsDefined(pBox->pData) )
                ((Abc_Ntk_t *)pBox->pData)->fHiePath++;
    // print the stats
    fprintf(outStream,  "Warning: The design contains %d undefined objects interpreted as blackboxes:\n", nBoxes );
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
        if ( !Ver_NtkIsDefined(pNtk) )
            fprintf(outStream,  "%s (%d)  ", Abc_NtkName(pNtk), pNtk->fHiePath );
    fprintf(outStream,  "\n" );
    // clean 
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
        pNtk->fHiePath = 0;
}

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

  Synopsis    [Returns 1 if there are non-driven nets.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseCheckNondrivenNets( Vec_Ptr_t * vUndefs )
{
    Abc_Ntk_t * pNtk;
    Ver_Bundle_t * pBundle;
    Abc_Obj_t * pBox, * pNet;
    int i, k, j, m;
    // go through undef box types
    Vec_PtrForEachEntry( vUndefs, pNtk, i )
        // go through instances of this type
        Vec_PtrForEachEntry( pNtk->pData, pBox, k )
            // go through the bundles of this instance
            Vec_PtrForEachEntryReverse( (Vec_Ptr_t *)pBox->pCopy, pBundle, j )
                // go through the actual nets of this bundle
                if ( pBundle )
                Vec_PtrForEachEntry( pBundle->vNetsActual, pNet, m )
                {
                    char * pName = Abc_ObjName(pNet);
                    if ( Abc_ObjFaninNum(pNet) == 0 ) // non-driven
                        if ( strcmp(Abc_ObjName(pNet), "1\'b0") && strcmp(Abc_ObjName(pNet), "1\'b1") ) // diff from a const
                            return 1;
                }
    return 0;
}

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

  Synopsis    [Checks if formal nets with the given name are driven in any of the instances of undef boxes.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseFormalNetsAreDriven( Abc_Ntk_t * pNtk, char * pNameFormal )
{
    Ver_Bundle_t * pBundle;
    Abc_Obj_t * pBox, * pNet;
    int k, j, m;
    // go through instances of this type
    Vec_PtrForEachEntry( pNtk->pData, pBox, k )
    {
        // find a bundle with the given name in this instance
        Vec_PtrForEachEntryReverse( (Vec_Ptr_t *)pBox->pCopy, pBundle, j )
            if ( pBundle && !strcmp( pBundle->pNameFormal, pNameFormal ) )
                break;
        // skip non-driven bundles
        if ( j == Vec_PtrSize((Vec_Ptr_t *)pBox->pCopy) )
            continue;
        // check if all nets are driven in this bundle
        Vec_PtrForEachEntry( pBundle->vNetsActual, pNet, m )
            if ( Abc_ObjFaninNum(pNet) > 0 )
                return 1;
    }
    return 0;
}

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

  Synopsis    [Returns the non-driven bundle that is given distance from the end.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Ver_Bundle_t * Ver_ParseGetNondrivenBundle( Abc_Ntk_t * pNtk, int Counter )
{
    Ver_Bundle_t * pBundle;
    Abc_Obj_t * pBox, * pNet;
    int k, m;
    // go through instances of this type
    Vec_PtrForEachEntry( pNtk->pData, pBox, k )
    {
        if ( Counter >= Vec_PtrSize((Vec_Ptr_t *)pBox->pCopy) )
            continue;
        // get the bundle given distance away
        pBundle = Vec_PtrEntry( (Vec_Ptr_t *)pBox->pCopy, Vec_PtrSize((Vec_Ptr_t *)pBox->pCopy) - 1 - Counter );
        if ( pBundle == NULL )
            continue;
        // go through the actual nets of this bundle
        Vec_PtrForEachEntry( pBundle->vNetsActual, pNet, m )
            if ( !Abc_ObjFaninNum(pNet) && !Ver_ParseFormalNetsAreDriven(pNtk, pBundle->pNameFormal) ) // non-driven
                return pBundle;
    }
    return NULL;
}

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

  Synopsis    [Drives the bundle in the given undef box.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseDriveFormal( Ver_Man_t * pMan, Abc_Ntk_t * pNtk, Ver_Bundle_t * pBundle0 )
{
    char Buffer[200];
    char * pName;
    Ver_Bundle_t * pBundle;
    Abc_Obj_t * pBox, * pTerm, * pTermNew, * pNetAct, * pNetFormal;
    int k, j, m;

    // drive this net in the undef box
    Vec_PtrForEachEntry( pBundle0->vNetsActual, pNetAct, m )
    {
        // create the formal net
        if ( Vec_PtrSize(pBundle0->vNetsActual) == 1 )
            sprintf( Buffer, "%s", pBundle0->pNameFormal );
        else
            sprintf( Buffer, "%s[%d]", pBundle0->pNameFormal, m );
        assert( Abc_NtkFindNet( pNtk, Buffer ) == NULL );
        pNetFormal = Abc_NtkFindOrCreateNet( pNtk, Buffer );
        // connect it to the box
        pTerm = Abc_NtkCreateBo( pNtk );
        assert( Abc_NtkBoxNum(pNtk) <= 1 );
        pBox = Abc_NtkBoxNum(pNtk)? Abc_NtkBox(pNtk,0) : Abc_NtkCreateBlackbox(pNtk);
        Abc_ObjAddFanin( Abc_NtkCreatePo(pNtk), pNetFormal );
        Abc_ObjAddFanin( pNetFormal, pTerm );
        Abc_ObjAddFanin( pTerm, pBox );
    }

    // go through instances of this type
    pName = Extra_UtilStrsav(pBundle0->pNameFormal);
    Vec_PtrForEachEntry( pNtk->pData, pBox, k )
    {
        // find a bundle with the given name in this instance
        Vec_PtrForEachEntryReverse( (Vec_Ptr_t *)pBox->pCopy, pBundle, j )
            if ( pBundle && !strcmp( pBundle->pNameFormal, pName ) )
                break;
        // skip non-driven bundles
        if ( j == Vec_PtrSize((Vec_Ptr_t *)pBox->pCopy) )
            continue;
        // check if any nets are driven in this bundle
        Vec_PtrForEachEntry( pBundle->vNetsActual, pNetAct, m )
            if ( Abc_ObjFaninNum(pNetAct) > 0 )
            {
                sprintf( pMan->sError, "Internal error while trying to connect undefined boxes. It is likely that the algorithm currently used has its limitations." );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
        // drive the nets by the undef box
        Vec_PtrForEachEntryReverse( pBundle->vNetsActual, pNetAct, m )
        {
            pTermNew = Abc_NtkCreateBo( pNetAct->pNtk );
            Abc_ObjAddFanin( pTermNew, pBox );
            Abc_ObjAddFanin( pNetAct, pTermNew );
        }
        // remove the bundle
        Ver_ParseFreeBundle( pBundle );
        Vec_PtrWriteEntry( (Vec_Ptr_t *)pBox->pCopy, j, NULL );
    }
    free( pName );
    return 1;
}


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

  Synopsis    [Drives the bundle in the given undef box.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseDriveInputs( Ver_Man_t * pMan, Vec_Ptr_t * vUndefs )
{
    char Buffer[200];
    Ver_Bundle_t * pBundle;
    Abc_Ntk_t * pNtk;
    Abc_Obj_t * pBox, * pBox2, * pTerm, * pTermNew, * pNetFormal, * pNetAct;
    int i, k, j, m, CountCur, CountTotal = -1;
    // iterate through the undef boxes
    Vec_PtrForEachEntry( vUndefs, pNtk, i )
    {
        // count the number of unconnected bundles for instances of this type of box
        CountTotal = -1;
        Vec_PtrForEachEntry( pNtk->pData, pBox, k )
        {
            CountCur = 0;
            Vec_PtrForEachEntry( (Vec_Ptr_t *)pBox->pCopy, pBundle, j )
                CountCur += (pBundle != NULL);
            if ( CountTotal == -1 )
                CountTotal = CountCur;
            else if ( CountTotal != CountCur )
            {
                sprintf( pMan->sError, "The number of formal inputs (%d) is different from the expected one (%d) when instantiating network %s in box %s.", 
                    CountCur, CountTotal, pNtk->pName, Abc_ObjName(pBox) );
                Ver_ParsePrintErrorMessage( pMan );
                return 0;
            }
        }

        // create formals
        pBox = Vec_PtrEntry( pNtk->pData, 0 );
        Vec_PtrForEachEntry( (Vec_Ptr_t *)pBox->pCopy, pBundle, j )
        {
            if ( pBundle == NULL )
                continue;
            Vec_PtrForEachEntry( pBundle->vNetsActual, pNetAct, m )
            {
                // find create the formal net
                if ( Vec_PtrSize(pBundle->vNetsActual) == 1 )
                    sprintf( Buffer, "%s", pBundle->pNameFormal );
                else
                    sprintf( Buffer, "%s[%d]", pBundle->pNameFormal, m );
                assert( Abc_NtkFindNet( pNtk, Buffer ) == NULL );
                pNetFormal = Abc_NtkFindOrCreateNet( pNtk, Buffer );
                // connect
                pTerm = Abc_NtkCreateBi( pNtk );
                assert( Abc_NtkBoxNum(pNtk) <= 1 );
                pBox2 = Abc_NtkBoxNum(pNtk)? Abc_NtkBox(pNtk,0) : Abc_NtkCreateBlackbox(pNtk);
                Abc_ObjAddFanin( pNetFormal, Abc_NtkCreatePi(pNtk) );
                Abc_ObjAddFanin( pTerm, pNetFormal );
                Abc_ObjAddFanin( pBox2, pTerm );
            }
        }

        // go through all the boxes
        Vec_PtrForEachEntry( pNtk->pData, pBox, k )
        {
            // go through all the bundles
            Vec_PtrForEachEntry( (Vec_Ptr_t *)pBox->pCopy, pBundle, j )
            {
                if ( pBundle == NULL )
                    continue;
                // drive the nets by the undef box
                Vec_PtrForEachEntryReverse( pBundle->vNetsActual, pNetAct, m )
                {
                    pTermNew = Abc_NtkCreateBi( pNetAct->pNtk );
                    Abc_ObjAddFanin( pBox, pTermNew );
                    Abc_ObjAddFanin( pTermNew, pNetAct );
                }
                // remove the bundle
                Ver_ParseFreeBundle( pBundle );
                Vec_PtrWriteEntry( (Vec_Ptr_t *)pBox->pCopy, j, NULL );
            }

            // free the bundles
            Vec_PtrFree( (Vec_Ptr_t *)pBox->pCopy );
            pBox->pCopy = NULL;
        }
    }
    return 1;
}


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

  Synopsis    [Returns the max size of any undef box.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseMaxBoxSize( Vec_Ptr_t * vUndefs )
{
    Abc_Ntk_t * pNtk;
    Abc_Obj_t * pBox;
    int i, k, nMaxSize = 0;
    // go through undef box types
    Vec_PtrForEachEntry( vUndefs, pNtk, i )
        // go through instances of this type
        Vec_PtrForEachEntry( pNtk->pData, pBox, k )
            // check the number of bundles of this instance
            if ( nMaxSize < Vec_PtrSize((Vec_Ptr_t *)pBox->pCopy) )
                nMaxSize = Vec_PtrSize((Vec_Ptr_t *)pBox->pCopy);
    return nMaxSize;
}

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

  Synopsis    [Prints the comprehensive report into a log file.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParsePrintLog( Ver_Man_t * pMan )
{
    Abc_Ntk_t * pNtk, * pNtkBox;
    Abc_Obj_t * pBox;
    FILE * pFile;
    char * pNameGeneric;
    char Buffer[1000];
    int i, k;

    // open the log file
    pNameGeneric = Extra_FileNameGeneric( pMan->pFileName );
    sprintf( Buffer, "%s.log", pNameGeneric );
    free( pNameGeneric );
    pFile = fopen( Buffer, "w" );

    // count the total number of instances and how many times they occur
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
        pNtk->fHieVisited = 0;
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
        Abc_NtkForEachBox( pNtk, pBox, k )
        {
            if ( Abc_ObjIsLatch(pBox) )
                continue;
            pNtkBox = pBox->pData;
            if ( pNtkBox == NULL )
                continue;
            pNtkBox->fHieVisited++;
        }
    // print each box and its stats
    fprintf( pFile, "The hierarhical design %s contains %d modules:\n", pMan->pFileName, Vec_PtrSize(pMan->pDesign->vModules) );
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
    {
        fprintf( pFile, "%-24s : ", Abc_NtkName(pNtk) );
        if ( !Ver_NtkIsDefined(pNtk) )
            fprintf( pFile, "undefbox" );
        else if ( Abc_NtkHasBlackbox(pNtk) )
            fprintf( pFile, "blackbox" );
        else
            fprintf( pFile, "logicbox" );
        fprintf( pFile, " instantiated %6d times ", pNtk->fHieVisited );
//        fprintf( pFile, "\n   " );
        fprintf( pFile, " pi = %4d", Abc_NtkPiNum(pNtk) );
        fprintf( pFile, " po = %4d", Abc_NtkPiNum(pNtk) );
        fprintf( pFile, " nd = %8d",  Abc_NtkNodeNum(pNtk) );
        fprintf( pFile, " lat = %6d",  Abc_NtkLatchNum(pNtk) );
        fprintf( pFile, " box = %6d", Abc_NtkBoxNum(pNtk)-Abc_NtkLatchNum(pNtk) );
        fprintf( pFile, "\n" );
    }
    Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
        pNtk->fHieVisited = 0;

    // report instances with dangling outputs
    if ( Vec_PtrSize(pMan->pDesign->vModules) > 1 )
    {
        Vec_Ptr_t * vBundles;
        Ver_Bundle_t * pBundle;
        int j, nActNets, Counter = 0, CounterBoxes = 0;
        // count the number of instances with dangling outputs
        Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
        {
            Abc_NtkForEachBox( pNtk, pBox, k )
            {
                if ( Abc_ObjIsLatch(pBox) )
                    continue;
                vBundles = (Vec_Ptr_t *)pBox->pCopy;
                pNtkBox = pBox->pData;
                if ( pNtkBox == NULL )
                    continue;
                if ( !Ver_NtkIsDefined(pNtkBox) )
                    continue;
                // count the number of actual nets
                nActNets = 0;
                Vec_PtrForEachEntry( vBundles, pBundle, j )
                    nActNets += Vec_PtrSize(pBundle->vNetsActual);
                // the box is defined and will be connected
                if ( nActNets != Abc_NtkPiNum(pNtkBox) + Abc_NtkPoNum(pNtkBox) )
                    Counter++;
            }
        }
        if ( Counter == 0 )
            fprintf( pFile, "The outputs of all box instances are connected.\n" );
        else
        {
            fprintf( pFile, "\n" );
            fprintf( pFile, "The outputs of %d box instances are not connected:\n", Counter );
            // enumerate through the boxes
            Vec_PtrForEachEntry( pMan->pDesign->vModules, pNtk, i )
            {
                Abc_NtkForEachBox( pNtk, pBox, k )
                {
                    if ( Abc_ObjIsLatch(pBox) )
                        continue;
                    vBundles = (Vec_Ptr_t *)pBox->pCopy;
                    pNtkBox = pBox->pData;
                    if ( pNtkBox == NULL )
                        continue;
                    if ( !Ver_NtkIsDefined(pNtkBox) )
                        continue;
                    // count the number of actual nets
                    nActNets = 0;
                    Vec_PtrForEachEntry( vBundles, pBundle, j )
                        nActNets += Vec_PtrSize(pBundle->vNetsActual);
                    // the box is defined and will be connected
                    if ( nActNets != Abc_NtkPiNum(pNtkBox) + Abc_NtkPoNum(pNtkBox) )
                        fprintf( pFile, "In module \"%s\" instance \"%s\" of box \"%s\" has different numbers of actual/formal nets (%d/%d).\n",
                            Abc_NtkName(pNtk), Abc_ObjName(pBox), Abc_NtkName(pNtkBox), nActNets, Abc_NtkPiNum(pNtkBox) + Abc_NtkPoNum(pNtkBox) );
                }
            }
        }
    }
    fclose( pFile );
    fprintf(outStream,  "Hierarchy statistics can be found in log file \"%s\".\n", Buffer );
}


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

  Synopsis    [Attaches the boxes to the network.]

  Description [This procedure is called after the design is parsed. 
  At that point, all the defined models have their PIs present. 
  They are connected first. Next undef boxes are processed (if present).
  Iteratively, one bundle is selected to be driven by the undef boxes in such 
  a way that there is no conflict (if it is driven by an instance of the box,
  no other net will be driven twice by the same formal net of some other instance 
  of the same box). In the end, all the remaining nets that cannot be driven 
  by the undef boxes are connected to the undef boxes as inputs.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseAttachBoxes( Ver_Man_t * pMan )
{
    Abc_Ntk_t * pNtk;
    Ver_Bundle_t * pBundle;
    Vec_Ptr_t * vUndefs;
    int i, RetValue, Counter, nMaxBoxSize;

    // print the log file
    if ( pMan->pDesign->vModules && Vec_PtrSize(pMan->pDesign->vModules) > 1 )
        Ver_ParsePrintLog( pMan );

    // connect defined boxes
    RetValue = Ver_ParseConnectDefBoxes( pMan );
    if ( RetValue < 2 )
        return RetValue;

    // report the boxes
    Ver_ParseReportUndefBoxes( pMan );

    // collect undef box types and their actual instances
    vUndefs = Ver_ParseCollectUndefBoxes( pMan );
    assert( Vec_PtrSize( vUndefs ) > 0 );

    // go through all undef box types
    Counter = 0;
    nMaxBoxSize = Ver_ParseMaxBoxSize( vUndefs );
    while ( Ver_ParseCheckNondrivenNets(vUndefs) && Counter < nMaxBoxSize )
    {
        // go through undef box types
        pBundle = NULL;
        Vec_PtrForEachEntry( vUndefs, pNtk, i )
            if ( pBundle = Ver_ParseGetNondrivenBundle( pNtk, Counter ) )
                break;
        if ( pBundle == NULL )
        {
            Counter++;
            continue;
        }
        // drive this bundle by this box
        if ( !Ver_ParseDriveFormal( pMan, pNtk, pBundle ) )
            return 0;
    }

    // make all the remaining bundles the drivers of undefs
    if ( !Ver_ParseDriveInputs( pMan, vUndefs ) )
        return 0;

    // cleanup
    Vec_PtrForEachEntry( vUndefs, pNtk, i )
    {
        Vec_PtrFree( pNtk->pData );
        pNtk->pData = NULL;
    }
    Vec_PtrFree( vUndefs ); 
    return 1;
}


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

  Synopsis    [Creates PI terminal and net.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Obj_t * Ver_ParseCreatePi( Abc_Ntk_t * pNtk, char * pName )
{
    Abc_Obj_t * pNet, * pTerm;
    // get the PI net
//    pNet  = Ver_ParseFindNet( pNtk, pName );
//    if ( pNet )
//        fprintf(outStream,  "Warning: PI \"%s\" appears twice in the list.\n", pName );
    pNet  = Abc_NtkFindOrCreateNet( pNtk, pName );
    // add the PI node
    pTerm = Abc_NtkCreatePi( pNtk );
    Abc_ObjAddFanin( pNet, pTerm );
    return pTerm;
}

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

  Synopsis    [Creates PO terminal and net.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Obj_t * Ver_ParseCreatePo( Abc_Ntk_t * pNtk, char * pName )
{
    Abc_Obj_t * pNet, * pTerm;
    // get the PO net
//    pNet  = Ver_ParseFindNet( pNtk, pName );
//    if ( pNet && Abc_ObjFaninNum(pNet) == 0 )
//        fprintf(outStream,  "Warning: PO \"%s\" appears twice in the list.\n", pName );
    pNet  = Abc_NtkFindOrCreateNet( pNtk, pName );
    // add the PO node
    pTerm = Abc_NtkCreatePo( pNtk );
    Abc_ObjAddFanin( pTerm, pNet );
    return pTerm;
}

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

  Synopsis    [Create a latch with the given input/output.]

  Description [By default, the latch value is a don't-care.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Obj_t * Ver_ParseCreateLatch( Abc_Ntk_t * pNtk, Abc_Obj_t * pNetLI, Abc_Obj_t * pNetLO )
{
    Abc_Obj_t * pLatch, * pTerm;
    // add the BO terminal
    pTerm = Abc_NtkCreateBi( pNtk );
    Abc_ObjAddFanin( pTerm, pNetLI );
    // add the latch box
    pLatch = Abc_NtkCreateLatch( pNtk );
    Abc_ObjAddFanin( pLatch, pTerm  );
    // add the BI terminal
    pTerm = Abc_NtkCreateBo( pNtk );
    Abc_ObjAddFanin( pTerm, pLatch );
    // get the LO net
    Abc_ObjAddFanin( pNetLO, pTerm );
    // set latch name
    Abc_ObjAssignName( pLatch, Abc_ObjName(pNetLO), "L" );
    Abc_LatchSetInitDc( pLatch );
    return pLatch;
}

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

  Synopsis    [Creates inverter and returns its net.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Obj_t * Ver_ParseCreateInv( Abc_Ntk_t * pNtk, Abc_Obj_t * pNet )
{
    Abc_Obj_t * pObj;
    pObj = Abc_NtkCreateNodeInv( pNtk, pNet );
    pNet = Abc_NtkCreateNet( pNtk );
    Abc_ObjAddFanin( pNet, pObj );
    return pNet;
}


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


