/**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"

////////////////////////////////////////////////////////////////////////
///                        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, Ver_SignalType_t SigType );
static int  Ver_ParseAssign( Ver_Man_t * p );
static int  Ver_ParseAlways( Ver_Man_t * p );
static int  Ver_ParseInitial( Ver_Man_t * p );
static int  Ver_ParseGate( Ver_Man_t * p, Abc_Ntk_t * pNtkGate );
static int  Ver_ParseGateStandard( Ver_Man_t * pMan, Ver_GateType_t GateType );

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 );

////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////
 
/**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->fCheck     = fCheck;
    p->fUseMemMan = fUseMemMan;
    // 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    [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 );
    p->Output    = stdout;
    p->pProgress = Extra_ProgressBarStart( stdout, Ver_StreamGetFileSize(p->pReader) );
    p->vNames    = Vec_PtrAlloc( 100 );
    p->vStackFn  = Vec_PtrAlloc( 100 );
    p->vStackOp  = Vec_IntAlloc( 100 );
    // create the design library and assign the technology library
    p->pDesign   = Abc_LibCreate( pFileName );
    p->pDesign->pLibrary = pGateLib;
    return p;
}

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

  Synopsis    [Stop parser.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseStop( Ver_Man_t * p )
{
    assert( p->pNtkCur == NULL );
    Ver_StreamFree( p->pReader );
    Extra_ProgressBarStop( p->pProgress );
    Vec_PtrFree( p->vNames   );
    Vec_PtrFree( p->vStackFn );
    Vec_IntFree( p->vStackOp );
    free( p );
}

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

  Synopsis    [File parser.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseInternal( Ver_Man_t * pMan )
{
    char * pToken;
    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;

        // check the network for correctness
        if ( pMan->fCheck && !Abc_NtkCheckRead( pMan->pNtkCur ) )
        {
            pMan->fTopLevel = 1;
            sprintf( pMan->sError, "The network check has failed.", pMan->pNtkCur->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return;
        }
        // add the module to the hash table
        if ( st_is_member( pMan->pDesign->tModules, pMan->pNtkCur->pName ) )
        {
            pMan->fTopLevel = 1;
            sprintf( pMan->sError, "Module \"%s\" is defined more than once.", pMan->pNtkCur->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return;
        }
        Vec_PtrPush( pMan->pDesign->vModules, pMan->pNtkCur );
        st_insert( pMan->pDesign->tModules, pMan->pNtkCur->pName, (char *)pMan->pNtkCur );
        pMan->pNtkCur = NULL;
    }
}

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

  Synopsis    [File parser.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ver_ParseFreeData( Ver_Man_t * p )
{
    if ( p->pNtkCur )
    {
        p->pNtkCur->pManFunc = NULL;
        Abc_NtkDelete( p->pNtkCur );
        p->pNtkCur = NULL;
    }
    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    [Parses one Verilog module.]

  Description []
               
  SideEffects []

  SeeAlso     []

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

    // start the current network
    assert( pMan->pNtkCur == NULL );
    pNtk = pMan->pNtkCur = Abc_NtkAlloc( ABC_NTK_NETLIST, ABC_FUNC_BLACKBOX, pMan->fUseMemMan );
    pNtk->ntkFunc  = ABC_FUNC_AIG;
    pNtk->pManFunc = pMan->pDesign->pManFunc;

    // get the network name
    pWord = Ver_ParseGetName( pMan );
    pNtk->pName = Extra_UtilStrsav( pWord );
    pNtk->pSpec = NULL;

    // create constant nets
    Abc_NtkFindOrCreateNet( pNtk, "1\'b0" );
    Abc_NtkFindOrCreateNet( pNtk, "1\'b1" );

    // make sure we stopped at the opening paranthesis
    if ( Ver_StreamPopChar(p) != '(' )
    {
        sprintf( pMan->sError, "Cannot find \"(\" after \"module\".", 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);
    assert( Symbol == ';' );

    // 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, VER_SIG_INPUT );
        else if ( !strcmp( pWord, "output" ) )
            RetValue = Ver_ParseSignal( pMan, VER_SIG_OUTPUT );
        else if ( !strcmp( pWord, "reg" ) )
            RetValue = Ver_ParseSignal( pMan, VER_SIG_REG );
        else if ( !strcmp( pWord, "wire" ) )
            RetValue = Ver_ParseSignal( pMan, VER_SIG_WIRE );
        else if ( !strcmp( pWord, "inout" ) )
            RetValue = Ver_ParseSignal( pMan, 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, VER_GATE_AND );
        else if ( !strcmp( pWord, "or" ) )
            RetValue = Ver_ParseGateStandard( pMan, VER_GATE_OR );
        else if ( !strcmp( pWord, "xor" ) )
            RetValue = Ver_ParseGateStandard( pMan, VER_GATE_XOR );
        else if ( !strcmp( pWord, "buf" ) )
            RetValue = Ver_ParseGateStandard( pMan, VER_GATE_BUF );
        else if ( !strcmp( pWord, "nand" ) )
            RetValue = Ver_ParseGateStandard( pMan, VER_GATE_NAND );
        else if ( !strcmp( pWord, "nor" ) )
            RetValue = Ver_ParseGateStandard( pMan, VER_GATE_NOR );
        else if ( !strcmp( pWord, "xnor" ) )
            RetValue = Ver_ParseGateStandard( pMan, VER_GATE_XNOR );
        else if ( !strcmp( pWord, "not" ) )
            RetValue = Ver_ParseGateStandard( pMan, VER_GATE_NOT );

        else if ( !strcmp( pWord, "assign" ) )
            RetValue = Ver_ParseAssign( pMan );
        else if ( !strcmp( pWord, "always" ) )
            RetValue = Ver_ParseAlways( pMan );
        else if ( !strcmp( pWord, "initial" ) )
            RetValue = Ver_ParseInitial( pMan );
        else if ( !strcmp( pWord, "endmodule" ) )
            break;
        else if ( pMan->pDesign->pLibrary && st_lookup(pMan->pDesign->pLibrary->tModules, pWord, (char**)&pNtkTemp) ) // gate library
            RetValue = Ver_ParseGate( pMan, pNtkTemp );
        else if ( pMan->pDesign && st_lookup(pMan->pDesign->tModules, pWord, (char**)&pNtkTemp) ) // current design
            RetValue = Ver_ParseGate( pMan, pNtkTemp );
        else
        {
            printf( "Cannot find \"%s\".\n", pWord );
            Ver_StreamSkipToChars( p, ";" );
            Ver_StreamPopChar(p);

//            sprintf( pMan->sError, "Cannot find \"%s\" in the library.", pWord );
//            Ver_ParsePrintErrorMessage( pMan );
//            return 0;
        }
        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;
    }

    // check if constant 0 net is used
    pNet = Abc_NtkFindOrCreateNet( pNtk, "1\'b0" );
    if ( Abc_ObjFanoutNum(pNet) == 0 )
        Abc_NtkDeleteObj(pNet);
    else
        Abc_ObjAddFanin( pNet, Abc_NtkCreateNodeConst0(pNtk) );
    // check if constant 1 net is used
    pNet = Abc_NtkFindOrCreateNet( pNtk, "1\'b1" );
    if ( Abc_ObjFanoutNum(pNet) == 0 )
        Abc_NtkDeleteObj(pNet);
    else
        Abc_ObjAddFanin( pNet, Abc_NtkCreateNodeConst1(pNtk) );

    // check the functionality to blackbox if insides are not defined
    if ( Abc_NtkNodeNum(pNtk) == 0 && Abc_NtkBoxNum(pNtk) == 0 )
    {
        pNtk->ntkFunc = ABC_FUNC_BLACKBOX;
        pNtk->pManFunc = NULL;
    }

    // fix the dangling nets
    Abc_NtkFinalizeRead( pNtk );
    return 1;
}

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

  Synopsis    [Parses one directive.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseSignal( Ver_Man_t * pMan, Ver_SignalType_t SigType )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Ntk_t * pNtk = pMan->pNtkCur;
    char Buffer[1000];
    int Lower, Upper, i;
    char * pWord;
    char Symbol;
    while ( 1 )
    {
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
        if ( pWord[0] == '[' && !pMan->fNameLast )
        {
            Lower = 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 == ']' )
                Upper = Lower;
            else
            {
                Upper = atoi( pWord + 1 );
                if ( Lower > Upper )
                    i = Lower, Lower = Upper, Upper = i;
                // 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 == ']' );
            }
            // check the case of no space between bracket and the next word
            if ( *(pWord+1) != 0 )
                pWord++;
            else
            {
                // get the signal name
                pWord = Ver_ParseGetName( pMan );
                if ( pWord == NULL )
                    return 0;
            }
            for ( i = Lower; i <= Upper; i++ )
            {
                sprintf( Buffer, "%s[%d]", pWord, i );
                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 );
            }
        }
        else
        {
            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 );
        }
        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_ParseAssign( Ver_Man_t * pMan )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Ntk_t * pNtk = pMan->pNtkCur;
    Abc_Obj_t * pNode, * pNet;
    char * pWord, * pName, * pEquation;
    Hop_Obj_t * pFunc;
    char Symbol;
    int i, Length, fReduction;

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

    // convert from the mapped netlist into the BDD netlist
    if ( pNtk->ntkFunc == ABC_FUNC_BLACKBOX )
    {
        pNtk->ntkFunc = ABC_FUNC_AIG;
        assert( pNtk->pManFunc == NULL );
        pNtk->pManFunc = pMan->pDesign->pManFunc;
    }
    else if ( pNtk->ntkFunc != ABC_FUNC_AIG )
    {
        sprintf( pMan->sError, "The network %s appears to mapped gates and assign statements. Currently such network are not allowed. One way to fix this problem is to replace assigns by buffers from the library.", pMan->pNtkCur );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }

    while ( 1 )
    {
        // get the name of the output signal
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
        // 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 = Abc_NtkFindNet( 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;
        }

        // parse the formula
        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( pMan->pNtkCur );
        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 = Abc_NtkFindNet( pNtk, pName );
            if ( pNet == NULL )
            {
                sprintf( pMan->sError, "Cannot read the assign statement for %s (input wire %d 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_ParseAlways( Ver_Man_t * pMan )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Ntk_t * pNtk = pMan->pNtkCur;
    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 = Abc_NtkFindNet( 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 = Abc_NtkFindNet( pNtk, pWord2+1 );
            pNet2 = Ver_ParseCreateInv( pNtk, pNet2 );
        }
        else
            pNet2 = Abc_NtkFindNet( 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 )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Ntk_t * pNtk = pMan->pNtkCur;
    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 = Abc_NtkFindNet( 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_ParseGate( Ver_Man_t * pMan, Abc_Ntk_t * pNtkGate )
{
    Ver_Stream_t * p = pMan->pReader;
    Abc_Ntk_t * pNtk = pMan->pNtkCur;
    Abc_Obj_t * pNetFormal, * pNetActual;
    Abc_Obj_t * pObj, * pNode, * pTerm;
    char * pWord, Symbol, * pGateName;
    int i, fCompl, fComplUsed = 0;
    unsigned * pPolarity;

    // clean the PI/PO pointers
    Abc_NtkForEachPi( pNtkGate, pObj, i )
        pObj->pCopy = NULL;
    Abc_NtkForEachPo( pNtkGate, pObj, i )
        pObj->pCopy = NULL;
    // 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
    pGateName = pWord;
    if ( Ver_StreamPopChar(p) != '(' )
    {
        sprintf( pMan->sError, "Cannot parse gate %s (expected opening paranthesis).", pNtkGate->pName );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }
    // parse pairs of formal/actural inputs
    while ( 1 )
    {
        // process one pair of formal/actual parameters
        if ( Ver_StreamPopChar(p) != '.' )
        {
            sprintf( pMan->sError, "Cannot parse gate %s (expected .).", pNtkGate->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // parse the formal name
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
        // get the formal net
        if ( Abc_NtkIsNetlist(pNtkGate) )
            pNetFormal = Abc_NtkFindNet( pNtkGate, pWord );
        else // if ( Abc_NtkIsStrash(pNtkGate) )
            assert( 0 );
        if ( pNetFormal == NULL )
        {
            sprintf( pMan->sError, "Formal net is missing in gate %s.", pWord );
            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, pNtkGate->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // parse the actual name
        pWord = Ver_ParseGetName( pMan );
        if ( pWord == NULL )
            return 0;
        // check if the name is complemented
        fCompl = (pWord[0] == '~');
        if ( fCompl )
        {
            fComplUsed = 1;
            pWord++;
            if ( pMan->pNtkCur->pData == NULL )
                pMan->pNtkCur->pData = Extra_MmFlexStart();
        }
        // get the actual net
        pNetActual = Abc_NtkFindNet( pMan->pNtkCur, pWord );
        if ( pNetActual == NULL )
        {
            sprintf( pMan->sError, "Actual net is missing in gate %s.", 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, pNtkGate->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // process the pair
        if ( Abc_ObjFaninNum(pNetFormal) > 0 && Abc_ObjIsPi(Abc_ObjFanin0Ntk(pNetFormal)) )  // PI net (with polarity!)
            Abc_ObjFanin0Ntk(pNetFormal)->pCopy = Abc_ObjNotCond( pNetActual, fCompl );
        else if ( Abc_ObjFanoutNum(pNetFormal) > 0 && Abc_ObjIsPo(Abc_ObjFanout0Ntk(pNetFormal)) )  // P0 net
        {
            assert( fCompl == 0 );
            Abc_ObjFanout0Ntk(pNetFormal)->pCopy = pNetActual; // Abc_ObjNotCond( pNetActual, fCompl );
        }
        else
        {
            sprintf( pMan->sError, "Cannot match formal net %s with PI or PO of the gate %s.", pWord, pNtkGate->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }

        // 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, pNtkGate->pName );
            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 gate %s (expected closing semicolumn).", pNtkGate->pName );
        Ver_ParsePrintErrorMessage( pMan );
        return 0;
    }

    // make sure each input net is driven
    Abc_NtkForEachPi( pNtkGate, pObj, i )
        if ( pObj->pCopy == NULL )
        {
            sprintf( pMan->sError, "Formal input %s of gate %s has no actual input.", Abc_ObjName(Abc_ObjFanout0(pObj)), pNtkGate->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
/*
    // make sure each output net is driving something
    Abc_NtkForEachPo( pNtkGate, pObj, i )
        if ( pObj->pCopy == NULL )
        {
            sprintf( pMan->sError, "Formal output %s of gate %s has no actual output.", Abc_ObjName(Abc_ObjFanin0(pObj)), pNtkGate->pName );
            Ver_ParsePrintErrorMessage( pMan );
            return 0;
        }
*/

    // allocate memory to remember the phase
    pPolarity = NULL;
    if ( fComplUsed )
    {
        int nBytes = 4 * Abc_BitWordNum( Abc_NtkPiNum(pNtkGate) );
        pPolarity = (unsigned *)Extra_MmFlexEntryFetch( pMan->pNtkCur->pData, nBytes );
        memset( pPolarity, 0, nBytes );
    }
    // create box to represent this gate
    if ( Abc_NtkHasBlackbox(pNtkGate) )
        pNode = Abc_NtkCreateBlackbox( pMan->pNtkCur );
    else
        pNode = Abc_NtkCreateWhitebox( pMan->pNtkCur );
    pNode->pNext = (Abc_Obj_t *)pPolarity;
    pNode->pData = pNtkGate;
    // connect to fanin nets
    Abc_NtkForEachPi( pNtkGate, pObj, i )
    {
        if ( pPolarity && Abc_ObjIsComplement(pObj->pCopy) )
        {
            Abc_InfoSetBit( pPolarity, i );
            pObj->pCopy = Abc_ObjRegular( pObj->pCopy );
        }
        assert( !Abc_ObjIsComplement(pObj->pCopy) );
//        Abc_ObjAddFanin( pNode, pObj->pCopy );
        pTerm = Abc_NtkCreateBi( pNtk );
        Abc_ObjAddFanin( pTerm, pObj->pCopy );
        Abc_ObjAddFanin( pNode, pTerm );
    }
    // connect to fanout nets
    Abc_NtkForEachPo( pNtkGate, pObj, i )
    {
        if ( pObj->pCopy == NULL )
            pObj->pCopy = Abc_NtkFindOrCreateNet(pNtk, NULL);
//        Abc_ObjAddFanin( pObj->pCopy, pNode );
        pTerm = Abc_NtkCreateBo( pNtk );
        Abc_ObjAddFanin( pTerm, pNode );
        Abc_ObjAddFanin( pObj->pCopy, pTerm );
    }
    return 1;
}


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

  Synopsis    [Parses one directive.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ver_ParseGateStandard( Ver_Man_t * pMan, Ver_GateType_t GateType )
{
    Ver_Stream_t * p = pMan->pReader;
    Hop_Man_t * pAig = pMan->pNtkCur->pManFunc;
    Abc_Obj_t * pNet, * pNode;
    char * pWord, Symbol;
    // 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( pMan->pNtkCur );
    // 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 = Abc_NtkFindNet( pMan->pNtkCur, 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( pAig, Abc_ObjFaninNum(pNode) );
    else if ( GateType == VER_GATE_OR || GateType == VER_GATE_NOR )
        pNode->pData = Hop_CreateOr( pAig, Abc_ObjFaninNum(pNode) );
    else if ( GateType == VER_GATE_XOR || GateType == VER_GATE_XNOR )
        pNode->pData = Hop_CreateExor( pAig, Abc_ObjFaninNum(pNode) );
    else if ( GateType == VER_GATE_BUF || GateType == VER_GATE_NOT )
        pNode->pData = Hop_CreateAnd( pAig, 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    [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  = Abc_NtkFindNet( pNtk, pName );
    if ( pNet )
        printf( "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  = Abc_NtkFindNet( pNtk, pName );
    if ( pNet && Abc_ObjFaninNum(pNet) == 0 )
        printf( "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_NtkCreateObj( pNtk, ABC_OBJ_NET );
    Abc_ObjAddFanin( pNet, pObj );
    return pNet;
}

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


