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

  FileName    [cbaReadVer.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Hierarchical word-level netlist.]

  Synopsis    [BLIF writer.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

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

ABC_NAMESPACE_IMPL_START

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

static const char * s_VerTypes[PRS_VER_UNKNOWN+1] = {
    NULL,              // 0:  unused
    "input",           // 1:  input
    "output",          // 2:  output
    "inout",           // 3:  inout
    "wire",            // 4:  wire
    "reg",             // 5:  reg
    "module",          // 6:  module
    "assign",          // 7:  assign
    "always",          // 8:  always
    "function",        // 9:  function
    "defparam",        // 10: defparam
    "begin",           // 11: begin
    "end",             // 12: end
    "case",            // 13: case
    "endcase",         // 14: endcase
    "signed",          // 15: signed
    "endmodule",       // 16: endmodule
    NULL               // 17: unknown 
};

void Prs_NtkAddVerilogDirectives( Prs_Man_t * p )
{
    int i;
    for ( i = 1; s_VerTypes[i]; i++ )
        Abc_NamStrFindOrAdd( p->pStrs, (char *)s_VerTypes[i],   NULL );
    assert( Abc_NamObjNumMax(p->pStrs) == i );
}


// character recognition 
static inline int Prs_CharIsSpace( char c )   { return (c == ' ' || c == '\t' || c == '\r' || c == '\n');                           }
static inline int Prs_CharIsDigit( char c )   { return (c >= '0' && c <= '9');                                                      }
static inline int Prs_CharIsDigitB( char c )  { return (c == '0' || c == '1'  || c == 'x' || c == 'z');                             }
static inline int Prs_CharIsDigitH( char c )  { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');  }
static inline int Prs_CharIsChar( char c )    { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');                            }
static inline int Prs_CharIsSymb1( char c )   { return Prs_CharIsChar(c) || c == '_';                                               }
static inline int Prs_CharIsSymb2( char c )   { return Prs_CharIsSymb1(c) || Prs_CharIsDigit(c) || c == '$';                        }

static inline int Prs_ManIsChar( Prs_Man_t * p, char c )    { return p->pCur[0] == c;                        }
static inline int Prs_ManIsChar1( Prs_Man_t * p, char c )   { return p->pCur[1] == c;                        }
static inline int Prs_ManIsDigit( Prs_Man_t * p )           { return Prs_CharIsDigit(*p->pCur);              }

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

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

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

// predefined primitives
typedef struct Prs_VerPrim_t_ Prs_VerPrim_t;
struct Prs_VerPrim_t_
{
    int    Type;
    char * pName;
};
static const Prs_VerPrim_t s_VerilogPrims[16] = 
{
    {CBA_BOX_BUF,  "buf"   },   
    {CBA_BOX_INV,  "not"   },   
    {CBA_BOX_AND,  "and"   },   
    {CBA_BOX_NAND, "nand"  },  
    {CBA_BOX_OR,   "or"    },    
    {CBA_BOX_NOR,  "nor"   },   
    {CBA_BOX_XOR,  "xor"   },   
    {CBA_BOX_XNOR, "xnor"  },  
    {CBA_BOX_TRI,  "bufif1"},  
    {0}
};

// predefined operator names
static const char * s_VerNames[100] = 
{
    NULL,
    "VERIFIC_",
    "add_",                  
    "mult_",                 
    "div_",                  
    "mod_",                  
    "rem_",                  
    "shift_left_",           
    "shift_right_",          
    "rotate_left_",          
    "rotate_right_",         
    "reduce_and_",           
    "reduce_or_",            
    "reduce_xor_",           
    "reduce_nand_",          
    "reduce_nor_",           
    "reduce_xnor_",          
    "LessThan_",             
    "Mux_",                  
    "Select_",               
    "Decoder_",              
    "EnabledDecoder_",       
    "PrioSelect_",           
    "DualPortRam_",          
    "ReadPort_",             
    "WritePort_",            
    "ClockedWritePort_",     
    "lut",                   
    "and_",                  
    "or_",                   
    "xor_",                  
    "nand_",                 
    "nor_",                  
    "xnor_",                 
    "buf_",                  
    "inv_",                  
    "tri_",                  
    "sub_",                  
    "unary_minus_",          
    "equal_",                
    "not_equal_",            
    "mux_",                  
    "wide_mux_",             
    "wide_select_",          
    "wide_dff_",             
    "wide_dlatch_",          
    "wide_dffrs_",           
    "wide_dlatchrs_",        
    "wide_prio_select_",     
    "pow_",                  
    "PrioEncoder_",          
    "abs_",
    "CPL_NMACROFF",
    "CPL_MACROFF",
    "CPL_FF",
    NULL
};

typedef struct Prs_VerInfo_t_ Prs_VerInfo_t;
struct Prs_VerInfo_t_
{
    int    Type;
    int    nInputs;
    char * pTypeName;
    char * pSigNames[6];
};
static const Prs_VerInfo_t s_VerInfo[100] = 
{
    {-1,              0, NULL,                     /* "PRIM_NONE"               */ {NULL}},
    {CBA_BOX_CT,      0, "VERIFIC_PWR",            /* "PRIM_PWR"                */ {"o"}},
    {CBA_BOX_CF,      0, "VERIFIC_GND",            /* "PRIM_GND"                */ {"o"}},
    {CBA_BOX_CX,      0, "VERIFIC_X",              /* "PRIM_X"                  */ {"o"}},
    {CBA_BOX_CZ,      0, "VERIFIC_Z",              /* "PRIM_Z"                  */ {"o"}},
    {CBA_BOX_INV,     1, "VERIFIC_INV",            /* "PRIM_INV"                */ {"i","o"}},
    {CBA_BOX_BUF,     1, "VERIFIC_BUF",            /* "PRIM_BUF"                */ {"i","o"}},
    {CBA_BOX_AND,     1, "VERIFIC_AND",            /* "PRIM_AND"                */ {"a0","a1","o"}},
    {CBA_BOX_NAND,    2, "VERIFIC_NAND",           /* "PRIM_NAND"               */ {"a0","a1","o"}},
    {CBA_BOX_OR,      2, "VERIFIC_OR",             /* "PRIM_OR"                 */ {"a0","a1","o"}},
    {CBA_BOX_NOR,     2, "VERIFIC_NOR",            /* "PRIM_NOR"                */ {"a0","a1","o"}},
    {CBA_BOX_XOR,     2, "VERIFIC_XOR",            /* "PRIM_XOR"                */ {"a0","a1","o"}},
    {CBA_BOX_XNOR,    2, "VERIFIC_XNOR",           /* "PRIM_XNOR"               */ {"a0","a1","o"}},
    {CBA_BOX_MUX,     3, "VERIFIC_MUX",            /* "PRIM_MUX"                */ {"c","a1","a0","o"}}, // changed order
    {-1,              0, "VERIFIC_PULLUP",         /* "PRIM_PULLUP"             */ {"o"}},
    {-1,              0, "VERIFIC_PULLDOWN",       /* "PRIM_PULLDOWN"           */ {"o"}},
    {CBA_BOX_TRI,     3, "VERIFIC_TRI",            /* "PRIM_TRI"                */ {"i","c","o"}},
    {CBA_BOX_LATCHRS, 4, "VERIFIC_DLATCHRS",       /* "PRIM_DLATCHRS"           */ {"d","s","r","gate","q"}},                  // changed order
    {CBA_BOX_LATCH,   4, "VERIFIC_DLATCH",         /* "PRIM_DLATCH"             */ {"d","async_val","async_cond","gate","q"}}, // changed order
    {CBA_BOX_DFFRS,   4, "VERIFIC_DFFRS",          /* "PRIM_DFFRS"              */ {"d","s","r","clk","q"}},                   // changed order
    {CBA_BOX_DFF,     4, "VERIFIC_DFF",            /* "PRIM_DFF"                */ {"d","async_val","async_cond","clk","q"}},  // changed order
    {-1,              2, "VERIFIC_NMOS",           /* "PRIM_NMOS"               */ {"c","d","o"}},
    {-1,              2, "VERIFIC_PMOS",           /* "PRIM_PMOS"               */ {"c","d","o"}},
    {-1,              3, "VERIFIC_CMOS",           /* "PRIM_CMOS"               */ {"d","nc","pc","o"}},
    {-1,              2, "VERIFIC_TRAN",           /* "PRIM_TRAN"               */ {"inout1","inout2","control"}},
    {CBA_BOX_ADD,     3, "VERIFIC_FADD",           /* "PRIM_FADD"               */ {"cin","a","b","o","cout"}},
    {-1,              3, "VERIFIC_RCMOS",          /* "PRIM_RCMOS"              */ {"d","nc","pc","o"}},
    {-1,              2, "VERIFIC_RNMOS",          /* "PRIM_RNMOS"              */ {"c","d","o"}},
    {-1,              2, "VERIFIC_RPMOS",          /* "PRIM_RPMOS"              */ {"c","d","o"}},
    {-1,              2, "VERIFIC_RTRAN",          /* "PRIM_RTRAN"              */ {"inout1","inout2","control"}},
    {-1,              0, "VERIFIC_HDL_ASSERTION",  /* "PRIM_HDL_ASSERTION"      */ {"condition"}},
    {CBA_BOX_ADD,     3, "add_",                   /* "OPER_ADDER"              */ {"cin","a","b","o","cout"}},
    {CBA_BOX_MUL,     2, "mult_",                  /* "OPER_MULTIPLIER"         */ {"a","b","o"}},
    {CBA_BOX_DIV,     2, "div_",                   /* "OPER_DIVIDER"            */ {"a","b","o"}},
    {CBA_BOX_MOD,     2, "mod_",                   /* "OPER_MODULO"             */ {"a","b","o"}},
    {CBA_BOX_REM,     2, "rem_",                   /* "OPER_REMAINDER"          */ {"a","b","o"}},
    {CBA_BOX_SHIL,    3, "shift_left_",            /* "OPER_SHIFT_LEFT"         */ {"cin","a","amount","o"}},
    {CBA_BOX_SHIR,    3, "shift_right_",           /* "OPER_SHIFT_RIGHT"        */ {"cin","a","amount","o"}},
    {CBA_BOX_ROTL,    2, "rotate_left_",           /* "OPER_ROTATE_LEFT"        */ {"a","amount","o"}},
    {CBA_BOX_ROTR,    2, "rotate_right_",          /* "OPER_ROTATE_RIGHT"       */ {"a","amount","o"}},
    {CBA_BOX_RAND,    1, "reduce_and_",            /* "OPER_REDUCE_AND"         */ {"a","o"}},
    {CBA_BOX_ROR,     1, "reduce_or_",             /* "OPER_REDUCE_OR"          */ {"a","o"}},
    {CBA_BOX_RXOR,    1, "reduce_xor_",            /* "OPER_REDUCE_XOR"         */ {"a","o"}},
    {CBA_BOX_RNAND,   1, "reduce_nand_",           /* "OPER_REDUCE_NAND"        */ {"a","o"}},
    {CBA_BOX_RNOR,    1, "reduce_nor_",            /* "OPER_REDUCE_NOR"         */ {"a","o"}},
    {CBA_BOX_RXNOR,   1, "reduce_xnor_",           /* "OPER_REDUCE_XNOR"        */ {"a","o"}},
    {CBA_BOX_LTHAN,   3, "LessThan_",              /* "OPER_LESSTHAN"           */ {"cin","a","b","o"}},
    {CBA_BOX_NMUX,    2, "Mux_",                   /* "OPER_NTO1MUX"            */ {"sel","data","o"}},
    {CBA_BOX_SEL,     2, "Select_",                /* "OPER_SELECTOR"           */ {"sel","data","o"}},
    {CBA_BOX_DEC,     1, "Decoder_",               /* "OPER_DECODER"            */ {"a","o"}},
    {CBA_BOX_EDEC,    2, "EnabledDecoder_",        /* "OPER_ENABLED_DECODER"    */ {"en","i","o"}},
    {CBA_BOX_PSEL,    3, "PrioSelect_",            /* "OPER_PRIO_SELECTOR"      */ {"cin","sel","data","o"}},
    {CBA_BOX_RAM,     4, "DualPortRam_",           /* "OPER_DUAL_PORT_RAM"      */ {"write_enable","write_address","write_data","read_address","read_data"}},
    {CBA_BOX_RAMR,    3, "ReadPort_",              /* "OPER_READ_PORT"          */ {"read_enable", "read_address", "Ram", "read_data" }},
    {CBA_BOX_RAMW,    3, "WritePort_",             /* "OPER_WRITE_PORT"         */ {"write_enable","write_address","write_data", "Ram"}},
    {CBA_BOX_RAMWC,   4, "ClockedWritePort_",      /* "OPER_CLOCKED_WRITE_PORT" */ {"clk","write_enable","write_address","write_data", "Ram"}},
    {CBA_BOX_LUT,     1, "lut",                    /* "OPER_LUT"                */ {"i","o"}},
    {CBA_BOX_AND,     2, "and_",                   /* "OPER_WIDE_AND"           */ {"a","b","o"}},
    {CBA_BOX_OR,      2, "or_",                    /* "OPER_WIDE_OR"            */ {"a","b","o"}},
    {CBA_BOX_XOR,     2, "xor_",                   /* "OPER_WIDE_XOR"           */ {"a","b","o"}},
    {CBA_BOX_NAND,    2, "nand_",                  /* "OPER_WIDE_NAND"          */ {"a","b","o"}},
    {CBA_BOX_NOR,     2, "nor_",                   /* "OPER_WIDE_NOR"           */ {"a","b","o"}},
    {CBA_BOX_XNOR,    2, "xnor_",                  /* "OPER_WIDE_XNOR"          */ {"a","b","o"}},
    {CBA_BOX_BUF,     1, "buf_",                   /* "OPER_WIDE_BUF"           */ {"i","o"}},
    {CBA_BOX_INV,     1, "inv_",                   /* "OPER_WIDE_INV"           */ {"i","o"}},
    {CBA_BOX_TRI,     2, "tri_",                   /* "OPER_WIDE_TRI"           */ {"i","c","o"}},
    {CBA_BOX_SUB,     2, "sub_",                   /* "OPER_MINUS"              */ {"a","b","o"}},
    {CBA_BOX_MIN,     1, "unary_minus_",           /* "OPER_UMINUS"             */ {"i","o"}},
    {CBA_BOX_EQU,     2, "equal_",                 /* "OPER_EQUAL"              */ {"a","b","o"}},
    {CBA_BOX_NEQU,    2, "not_equal_",             /* "OPER_NEQUAL"             */ {"a","b","o"}},
    {CBA_BOX_MUX,     3, "mux_",                   /* "OPER_WIDE_MUX"           */ {"cond","d1","d0","o"}}, // changed order
    {CBA_BOX_NMUX,    2, "wide_mux_",              /* "OPER_WIDE_NTO1MUX"       */ {"sel","data","o"}},
    {CBA_BOX_SEL,     2, "wide_select_",           /* "OPER_WIDE_SELECTOR"      */ {"sel","data","o"}},
    {CBA_BOX_DFF,     4, "wide_dff_",              /* "OPER_WIDE_DFF"           */ {"d","async_val","async_cond","clock","q"}},
    {CBA_BOX_DFFRS,   4, "wide_dffrs_",            /* "OPER_WIDE_DFFRS"         */ {"d","set","reset","clock","q"}},
    {CBA_BOX_LATCHRS, 4, "wide_dlatchrs_",         /* "OPER_WIDE_DLATCHRS"      */ {"d","set","reset","clock","q"}},
    {CBA_BOX_LATCH,   4, "wide_dlatch_",           /* "OPER_WIDE_DLATCH"        */ {"d","async_val","async_cond","clock","q"}},
    {CBA_BOX_PSEL,    3, "wide_prio_select_",      /* "OPER_WIDE_PRIO_SELECTOR" */ {"sel","data","carry_in","o"}},
    {CBA_BOX_POW,     2, "pow_",                   /* "OPER_POW"                */ {"a","b","o"}},
    {CBA_BOX_PENC,    1, "PrioEncoder_",           /* "OPER_PRIO_ENCODER"       */ {"sel","o"}},
    {CBA_BOX_ABS,     1, "abs_",                   /* "OPER_ABS"                */ {"i","o"}},
    {CBA_BOX_DFFCPL,  4, "CPL_FF",                 /* "OPER_WIDE_DFF - 2"       */ {"d","arstval","arst","clk","q","qbar"}},
    {-1,              0, NULL,                     /* "PRIM_END"                */ {NULL}}
}; 


// check if it is a Verilog predefined module
static inline int Prs_ManIsVerilogPrim( char * pName )
{
    int i;
    for ( i = 0; s_VerilogPrims[i].pName; i++ )
        if ( !strcmp(pName, s_VerilogPrims[i].pName) )
            return s_VerilogPrims[i].Type;
    return 0;
}
// check if it is a known module
static inline int Prs_ManIsKnownModule( char * pName )
{
    int i, Length;
    for ( i = 1; s_VerNames[i]; i++ )
    {
        Length = strlen(s_VerNames[i]);
//        if ( !strncmp(pName, s_VerNames[i], Length) && (i == 1 || (pName[Length] >= '0' && pName[Length] <= '9')) )
        if ( !strncmp(pName, s_VerNames[i], Length) )
            return i;
    }
    return 0;
}
// check if it is a known module
static inline int Prs_ManFindType( char * pName, int * pInputs, int fOut, char *** ppNames )
{
    int i, Length;
    *pInputs = -1;
    for ( i = 1; s_VerInfo[i].pTypeName; i++ )
    {
        Length = strlen(s_VerInfo[i].pTypeName);
        if ( !strncmp(pName, s_VerInfo[i].pTypeName, Length) )
        {
            *pInputs = s_VerInfo[i].nInputs;
            *ppNames = (char **)s_VerInfo[i].pSigNames + (fOut ? s_VerInfo[i].nInputs : 0);
            return s_VerInfo[i].Type;
        }
    }
    return CBA_OBJ_BOX;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

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

// skips Verilog comments (returns 1 if some comments were skipped)
static inline int Prs_ManUtilSkipComments( Prs_Man_t * p )
{
    if ( !Prs_ManIsChar(p, '/') )
        return 0;
    if ( Prs_ManIsChar1(p, '/') )
    {
        for ( p->pCur += 2; p->pCur < p->pLimit; p->pCur++ )
            if ( Prs_ManIsChar(p, '\n') )
                { p->pCur++; return 1; }
    }
    else if ( Prs_ManIsChar1(p, '*') )
    {
        for ( p->pCur += 2; p->pCur < p->pLimit; p->pCur++ )
            if ( Prs_ManIsChar(p, '*') && Prs_ManIsChar1(p, '/') )
                { p->pCur++; p->pCur++; return 1; }
    }
    return 0;
}
static inline int Prs_ManUtilSkipName( Prs_Man_t * p )
{
    if ( !Prs_ManIsChar(p, '\\') )
        return 0;
    for ( p->pCur++; p->pCur < p->pLimit; p->pCur++ )
        if ( Prs_ManIsChar(p, ' ') )
            { p->pCur++; return 1; }
    return 0;
}

// skip any number of spaces and comments
static inline int Prs_ManUtilSkipSpaces( Prs_Man_t * p )
{
    while ( p->pCur < p->pLimit )
    {
        while ( Prs_CharIsSpace(*p->pCur) ) 
            p->pCur++;
        if ( !*p->pCur )
            return Prs_ManErrorSet(p, "Unexpectedly reached end-of-file.", 1);
        if ( !Prs_ManUtilSkipComments(p) )
            return 0;
    }
    return Prs_ManErrorSet(p, "Unexpectedly reached end-of-file.", 1);
}
// skip everything including comments until the given char
static inline int Prs_ManUtilSkipUntil( Prs_Man_t * p, char c )
{
    while ( p->pCur < p->pLimit )
    {
        if ( Prs_ManIsChar(p, c) )
            return 1;
        if ( Prs_ManUtilSkipComments(p) )
            continue;
        if ( Prs_ManUtilSkipName(p) )
            continue;
        p->pCur++;
    }
    return 0;
}
// skip everything including comments until the given word
static inline int Prs_ManUtilSkipUntilWord( Prs_Man_t * p, char * pWord )
{
    char * pPlace = strstr( p->pCur, pWord );
    if ( pPlace == NULL )  return 1;
    p->pCur = pPlace + strlen(pWord);
    return 0;
}
// detect two symbols on the same line
static inline int Prs_ManUtilDetectTwo( Prs_Man_t * p, char Sym1, char Sym2 )
{
    char * pTemp;
    for ( pTemp = p->pCur; *pTemp != ';'; pTemp++ )
        if ( *pTemp == Sym1 && *pTemp == Sym2 )
            return 1;
    return 0;
}
// find closing paren
static inline char * Prs_ManFindClosingParenthesis( Prs_Man_t * p, char Open, char Close )
{
    char * pTemp;
    int Counter = 0;
    int fNotName = 1;
    assert( Prs_ManIsChar(p, Open) );
    for ( pTemp = p->pCur; *pTemp; pTemp++ )
    {
        if ( fNotName )
        {
            if ( *pTemp == Open )
                Counter++;
            if ( *pTemp == Close )
                Counter--;
            if ( Counter == 0 )
                return pTemp;
        }
        if ( *pTemp == '\\' )
            fNotName = 0;
        else if ( !fNotName && *pTemp == ' ' )
            fNotName = 1;
    }
    return NULL;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline int Prs_ManReadName( Prs_Man_t * p )
{
    char * pStart = p->pCur;
    if ( Prs_ManIsChar(p, '\\') ) // escaped name
    {
        pStart = ++p->pCur;
        while ( !Prs_ManIsChar(p, ' ') ) 
            p->pCur++;
    }    
    else if ( Prs_CharIsSymb1(*p->pCur) ) // simple name
    {
        p->pCur++;
        while ( Prs_CharIsSymb2(*p->pCur) ) 
            p->pCur++;
    }
    else 
        return 0;
    return Abc_NamStrFindOrAddLim( p->pStrs, pStart, p->pCur, NULL );
}
static inline int Prs_ManReadNameList( Prs_Man_t * p, Vec_Int_t * vTemp, char LastSymb )
{
    Vec_IntClear( vTemp );
    while ( 1 )
    {
        int Item = Prs_ManReadName(p);
        if ( Item == 0 )                    return Prs_ManErrorSet(p, "Cannot read name in the list.", 0);
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 1.", 0);
        if ( Item == PRS_VER_WIRE  )
            continue;
        Vec_IntPush( vTemp, Item );
        if ( Prs_ManIsChar(p, LastSymb) )   break;
        if ( !Prs_ManIsChar(p, ',') )       return Prs_ManErrorSet(p, "Expecting comma in the list.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 2.", 0);
    }
    return 1;
}
static inline int Prs_ManReadConstant( Prs_Man_t * p )
{
    char * pStart = p->pCur;
    assert( Prs_ManIsDigit(p) );
    while ( Prs_ManIsDigit(p) ) 
        p->pCur++;
    if ( !Prs_ManIsChar(p, '\'') )
        return Abc_NamStrFindOrAddLim( p->pFuns, pStart, p->pCur, NULL );
    p->pCur++;
    if ( Prs_ManIsChar(p, 's') )
        p->pCur++;
    if ( Prs_ManIsChar(p, 'b') )
    {
        p->pCur++;
        while ( Prs_CharIsDigitB(*p->pCur) ) 
        {
            if ( *p->pCur == '0' )
                p->pNtk->fHasC0s = 1;
            else if ( *p->pCur == '1' )
                p->pNtk->fHasC1s = 1;
            else if ( *p->pCur == 'x' )
                p->pNtk->fHasCXs = 1;
            else if ( *p->pCur == 'z' )
                p->pNtk->fHasCZs = 1;
            p->pCur++;
        }
    }
    else if ( Prs_ManIsChar(p, 'h') )
    {
        p->pCur++;
        p->pNtk->fHasC0s = 1;
        while ( Prs_CharIsDigitH(*p->pCur) ) 
        {
            if ( *p->pCur != '0' )
                p->pNtk->fHasC1s = 1;
            p->pCur++;
        }
    }
    else if ( Prs_ManIsChar(p, 'd') )
    {
        p->pCur++;
        p->pNtk->fHasC0s = 1;
        while ( Prs_ManIsDigit(p) ) 
        {
            if ( *p->pCur != '0' )
                p->pNtk->fHasC1s = 1;
            p->pCur++;
        }
    }
    else                                    return Prs_ManErrorSet(p, "Cannot read radix of constant.", 0);
    return Abc_NamStrFindOrAddLim( p->pFuns, pStart, p->pCur, NULL );
}
static inline int Prs_ManReadRange( Prs_Man_t * p )
{
    int Left, Right;
    assert( Prs_ManIsChar(p, '[') );
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 3.", 0);
    if ( !Prs_ManIsDigit(p) )               return Prs_ManErrorSet(p, "Cannot read digit in range specification.", 0);
    Left = Right = atoi(p->pCur);
    while ( Prs_ManIsDigit(p) ) 
        p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 4.", 0);
    if ( Prs_ManIsChar(p, ':') )
    {
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 5.", 0);
        if ( !Prs_ManIsDigit(p) )           return Prs_ManErrorSet(p, "Cannot read digit in range specification.", 0);
        Right = atoi(p->pCur);
        while ( Prs_ManIsDigit(p) ) 
            p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 6.", 0);
    }
    if ( !Prs_ManIsChar(p, ']') )           return Prs_ManErrorSet(p, "Cannot read closing brace in range specification.", 0);
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 6a.", 0);
    return Hash_Int2ManInsert( p->vHash, Left, Right, 0 );
}
static inline int Prs_ManReadConcat( Prs_Man_t * p, Vec_Int_t * vTemp2 )
{
    extern int Prs_ManReadSignalList( Prs_Man_t * p, Vec_Int_t * vTemp, char LastSymb, int fAddForm );
    assert( Prs_ManIsChar(p, '{') );
    p->pCur++;
    if ( !Prs_ManReadSignalList( p, vTemp2, '}', 0 ) ) return Prs_ManErrorSet(p, "Error number 7.", 0);
    // check final
    assert( Prs_ManIsChar(p, '}') );
    p->pCur++;
    // return special case
    assert( Vec_IntSize(vTemp2) > 0 );
    if ( Vec_IntSize(vTemp2) == 1 )
        return Vec_IntEntry(vTemp2, 0);
    return Abc_Var2Lit2( Prs_NtkAddConcat(p->pNtk, vTemp2), CBA_PRS_CONCAT );
}
static inline int Prs_ManReadSignal( Prs_Man_t * p )
{
    int Item;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 8.", 0);
    if ( Prs_ManIsDigit(p) )
    {
        Item = Prs_ManReadConstant(p);
        if ( Item == 0 )                    return 0;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 10.", 0);
        return Abc_Var2Lit2( Item, CBA_PRS_CONST );
    }
    if ( Prs_ManIsChar(p, '{') )
    {
        if ( Prs_CharIsDigit(p->pCur[1]) )
        {
            p->pCur++;
            if ( Prs_ManIsDigit(p) )
            {
                int i, Num = atoi(p->pCur);
                while ( Prs_ManIsDigit(p) )
                    p->pCur++;
                if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 10.", 0);
                assert( Prs_ManIsChar(p, '{') );
                p->pCur++;
                if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 10.", 0);
                Item = Prs_ManReadSignal( p );
                assert( Prs_ManIsChar(p, '}') );
                p->pCur++;
                if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 10.", 0);
                // add to concat all, expect the last one
                assert( p->fUsingTemp2 );
                for ( i = 0; i < Num-1; i++ )
                    Vec_IntPush( &p->vTemp2, Item );
                if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 10.", 0);
                assert( Prs_ManIsChar(p, '}') );
                p->pCur++;
                if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 10.", 0);
                return Item;
            }
        }
        if ( p->fUsingTemp2 )               return Prs_ManErrorSet(p, "Cannot read nested concatenations.", 0);
        p->fUsingTemp2 = 1;
        Item = Prs_ManReadConcat(p, &p->vTemp2);
        p->fUsingTemp2 = 0;
        if ( Item == 0 )                    return 0;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 12.", 0);
        return Item;
    }
    else
    {
        Item = Prs_ManReadName( p );
        if ( Item == 0 )                    return 1; // no actual name               
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 14.", 0);
        if ( Prs_ManIsChar(p, '[') )
        {
            int Range = Prs_ManReadRange(p);
            if ( Range == 0 )               return Prs_ManErrorSet(p, "Error number 15.", 0);
            if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 16.", 0);
            return Abc_Var2Lit2( Prs_NtkAddSlice(p->pNtk, Item, Range), CBA_PRS_SLICE );
        }
        return Abc_Var2Lit2( Item, CBA_PRS_NAME );
    }
}
int Prs_ManReadSignalList( Prs_Man_t * p, Vec_Int_t * vTemp, char LastSymb, int fAddForm )
{
    Vec_IntClear( vTemp );
    while ( 1 )
    {
        int Item = Prs_ManReadSignal(p);
        if ( Item == 0 )                    return Prs_ManErrorSet(p, "Cannot read signal in the list.", 0);
        if ( fAddForm )
            Vec_IntPush( vTemp, 0 );
        Vec_IntPush( vTemp, Item );
        if ( Prs_ManIsChar(p, LastSymb) )   break;
        if ( !Prs_ManIsChar(p, ',') )       return Prs_ManErrorSet(p, "Expecting comma in the list.", 0);
        p->pCur++;
    }
    return 1;
}
static inline int Prs_ManReadSignalList2( Prs_Man_t * p, Vec_Int_t * vTemp )
{
    int FormId, ActItem;
    Vec_IntClear( vTemp );
    assert( Prs_ManIsChar(p, '.') );
    while ( Prs_ManIsChar(p, '.') )
    {
        p->pCur++;
        FormId = Prs_ManReadName( p );
        if ( FormId == 0 )                  return Prs_ManErrorSet(p, "Cannot read formal name of the instance.", 0);
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 17.", 0);
        if ( !Prs_ManIsChar(p, '(') )       return Prs_ManErrorSet(p, "Cannot read \"(\" in the instance.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 17.", 0);
        ActItem = Prs_ManReadSignal( p );
        if ( ActItem == 0 )                 return Prs_ManErrorSet(p, "Cannot read actual name of an instance.", 0);
        if ( !Prs_ManIsChar(p, ')') )       return Prs_ManErrorSet(p, "Cannot read \")\" in the instance.", 0);
        p->pCur++;
        if ( ActItem != 1 )
            Vec_IntPushTwo( vTemp, FormId, ActItem );
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 18.", 0);
        if ( Prs_ManIsChar(p, ')') )        break;
        if ( !Prs_ManIsChar(p, ',') )       return Prs_ManErrorSet(p, "Expecting comma in the instance.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 19.", 0);
    }
    assert( Vec_IntSize(vTemp) > 0 );
    assert( Vec_IntSize(vTemp) % 2 == 0 );
    return 1;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline int Prs_ManReadFunction( Prs_Man_t * p )
{
    // this is a hack to read functions produced by ABC Verilog writer
    p->FuncNameId = p->FuncRangeId = 0;
    if ( Prs_ManUtilSkipUntilWord( p, "_func_" ) ) return Prs_ManErrorSet(p, "Cannot find \"_func_\" keyword.", 0);
    p->pCur -= 6;
    p->FuncNameId = Prs_ManReadName( p );          
    if ( p->FuncNameId == 0 )                      return Prs_ManErrorSet(p, "Error number 30a.", 0);
    if ( Prs_ManUtilSkipUntilWord( p, "input" ) )  return Prs_ManErrorSet(p, "Cannot find \"input\" keyword.", 0);
    if ( Prs_ManUtilSkipSpaces(p) )                return Prs_ManErrorSet(p, "Error number 30b.", 0);
    if ( Prs_ManIsChar(p, '[') )
        p->FuncRangeId = Prs_ManReadRange(p);
    else if ( Prs_ManReadName(p) == PRS_VER_SIGNED ) 
    {
        if ( Prs_ManUtilSkipSpaces(p) )            return Prs_ManErrorSet(p, "Error number 30c.", 0);
        if ( Prs_ManIsChar(p, '[') )
            p->FuncRangeId = Prs_ManReadRange(p);
    }
    if ( Prs_ManUtilSkipUntilWord( p, "endfunction" ) ) return Prs_ManErrorSet(p, "Cannot find \"endfunction\" keyword.", 0);
    return 1;
}
static inline int Prs_ManReadAlways( Prs_Man_t * p )
{
    // this is a hack to read always-statement representing case-statement
    int iToken;
    char * pClose; 
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23.", 0);
    if ( !Prs_ManIsChar(p, '@') )           return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    if ( !Prs_ManIsChar(p, '(') )           return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
    pClose = Prs_ManFindClosingParenthesis( p, '(', ')' );
    if ( pClose == NULL )
        return Prs_ManErrorSet(p, "Expecting closing parenthesis 1.", 0); 
    p->pCur = pClose;
    if ( !Prs_ManIsChar(p, ')') )           return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
    p->pCur++;
    // read begin
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    iToken = Prs_ManReadName( p );
    if ( iToken != PRS_VER_BEGIN )          return Prs_ManErrorSet(p, "Cannot read \"begin\" keyword.", 0);
    // read case
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    iToken = Prs_ManReadName( p );
    if ( iToken != PRS_VER_CASE )           return Prs_ManErrorSet(p, "Cannot read \"case\" keyword.", 0);
    // read control
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    if ( !Prs_ManIsChar(p, '(') )           return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    iToken = Prs_ManReadSignal( p );
    if ( iToken == 0 )                      return Prs_ManErrorSet(p, "Cannot read output in assign-statement.", 0);
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    if ( !Prs_ManIsChar(p, ')') )           return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
    p->pCur++;
    // save control
    Vec_IntClear( &p->vTemp3 );
    Vec_IntPushTwo( &p->vTemp3, 0, 0 );  // output will go here
    Vec_IntPushTwo( &p->vTemp3, 0, iToken );
    // read conditions
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    if ( !Prs_ManIsDigit(p) )               return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
    while ( Prs_ManIsDigit(p) )
    {
        while ( Prs_ManIsDigit(p) )
            p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 23a.", 0);
        if ( !Prs_ManIsChar(p, ':') )       return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 23a.", 0);
        // read output
        iToken = Prs_ManReadSignal( p );
        if ( iToken == 0 )                  return Prs_ManErrorSet(p, "Cannot read output in assign-statement.", 0);
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 23a.", 0);
        if ( !Prs_ManIsChar(p, '=') )       return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
        p->pCur++;
        // save output
        Vec_IntWriteEntry( &p->vTemp3, 1, iToken );
        // read input
        iToken = Prs_ManReadSignal( p );
        if ( iToken == 0 )                  return Prs_ManErrorSet(p, "Cannot read output in assign-statement.", 0);
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 23a.", 0);
        if ( !Prs_ManIsChar(p, ';') )       return Prs_ManErrorSet(p, "Cannot parse always statement.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 23a.", 0);
        // save input
        Vec_IntPushTwo( &p->vTemp3, 0, iToken );
    }
    // read endcase
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    iToken = Prs_ManReadName( p );
    if ( iToken != PRS_VER_ENDCASE )        return Prs_ManErrorSet(p, "Cannot read \"endcase\" keyword.", 0);
    // read end
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23a.", 0);
    iToken = Prs_ManReadName( p );
    if ( iToken != PRS_VER_END )            return Prs_ManErrorSet(p, "Cannot read \"end\" keyword.", 0);
    // save binary operator
    Prs_NtkAddBox( p->pNtk, CBA_BOX_NMUX, 0, &p->vTemp3 );
    return 1;
}
/*
static inline int Prs_ManReadExpression( Prs_Man_t * p, int OutItem )
{
    int InItem, fCompl = 0, fCompl2 = 0, Oper = 0;
    // read output name
    if ( Prs_ManIsChar(p, '~') ) 
    { 
        fCompl = 1; 
        p->pCur++; 
    }
    // write output name
    Vec_IntClear( &p->vTemp );
    Vec_IntPush( &p->vTemp, 0 );
    Vec_IntPush( &p->vTemp, OutItem );
    // read first name
    InItem = Prs_ManReadSignal( p );
    if ( InItem == 0 )                      return Prs_ManErrorSet(p, "Cannot read first input name in the assign-statement.", 0);
    Vec_IntPush( &p->vTemp, 0 );
    Vec_IntPush( &p->vTemp, InItem );
    // check unary operator
    if ( Prs_ManIsChar(p, ';') )
    {
        Oper = fCompl ? CBA_BOX_INV : CBA_BOX_BUF;
        Prs_NtkAddBox( p->pNtk, Oper, 0, &p->vTemp );
        return 1;
    }
    if ( Prs_ManIsChar(p, '&') ) 
        Oper = CBA_BOX_AND;
    else if ( Prs_ManIsChar(p, '|') ) 
        Oper = CBA_BOX_OR;
    else if ( Prs_ManIsChar(p, '^') ) 
        Oper = CBA_BOX_XOR;
    else if ( Prs_ManIsChar(p, '?') ) 
        Oper = CBA_BOX_MUX;
    else                                    return Prs_ManErrorSet(p, "Unrecognized operator in the assign-statement.", 0);
    p->pCur++; 
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 24.", 0);
    if ( Prs_ManIsChar(p, '~') ) 
    { 
        fCompl2 = 1; 
        p->pCur++; 
    }
    // read second name
    InItem = Prs_ManReadSignal( p );
    if ( InItem == 0 )                      return Prs_ManErrorSet(p, "Cannot read second input name in the assign-statement.", 0);
    Vec_IntPush( &p->vTemp, 0 );
    Vec_IntPush( &p->vTemp, InItem );
    // read third argument
    if ( Oper == CBA_BOX_MUX )
    {
        assert( fCompl == 0 ); 
        if ( !Prs_ManIsChar(p, ':') )       return Prs_ManErrorSet(p, "Expected colon in the MUX assignment.", 0);
        p->pCur++; 
        // read third name
        InItem = Prs_ManReadSignal( p );
        if ( InItem == 0 )                  return Prs_ManErrorSet(p, "Cannot read third input name in the assign-statement.", 0);
        Vec_IntPush( &p->vTemp, 0 );
        Vec_IntPush( &p->vTemp, InItem );
        if ( !Prs_ManIsChar(p, ';') )       return Prs_ManErrorSet(p, "Expected semicolon at the end of the assign-statement.", 0);
    }
    else
    {
        // figure out operator
        if ( Oper == CBA_BOX_AND )
        {
            if ( fCompl && !fCompl2 )
                Oper = CBA_BOX_SHARPL;
            else if ( !fCompl && fCompl2 )
                Oper = CBA_BOX_SHARP;
            else if ( fCompl && fCompl2 )
                Oper = CBA_BOX_NOR;
        }
        else if ( Oper == CBA_BOX_OR )
        {
            if ( fCompl && fCompl2 )
                Oper = CBA_BOX_NAND;
            else assert( !fCompl && !fCompl2 );
        }
        else if ( Oper == CBA_BOX_XOR )
        {
            if ( fCompl && !fCompl2 )
                Oper = CBA_BOX_XNOR;
            else assert( !fCompl && !fCompl2 );
        }
    }
    // save binary operator
    Prs_NtkAddBox( p->pNtk, Oper, 0, &p->vTemp );
    return 1;
}
*/
static inline int Prs_ManReadExpression( Prs_Man_t * p, int OutItem )
{
    char * pClose;
    int Item, Type = CBA_OBJ_NONE;
    int fRotating = 0;

    // write output name
    Vec_IntClear( &p->vTemp );
    Vec_IntPush( &p->vTemp, 0 );
    Vec_IntPush( &p->vTemp, OutItem );
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 24.", 0);
    if ( Prs_ManIsChar(p, '(') )
    {
        // THIS IS A HACK TO DETECT rotating shifters:  try to find both << and >> on the same line
        if ( Prs_ManUtilDetectTwo(p, '>', '>') && Prs_ManUtilDetectTwo(p, '<', '<') )
            fRotating = 1;
        pClose = Prs_ManFindClosingParenthesis( p, '(', ')' );
        if ( pClose == NULL )
            return Prs_ManErrorSet(p, "Expecting closing parenthesis 1.", 0); 
        *p->pCur = *pClose = ' ';
    }
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 24.", 0);
    // read constant or concatenation
    if ( Prs_ManIsDigit(p) || Prs_ManIsChar(p, '{') )
    {
        Item = Prs_ManReadSignal( p );
        // write constant
        Vec_IntPush( &p->vTemp, 0 );
        Vec_IntPush( &p->vTemp, Item );
        Type = CBA_BOX_BUF;
    }
    else if ( Prs_ManIsChar(p, '!') || Prs_ManIsChar(p, '~') || Prs_ManIsChar(p, '@') ||
              Prs_ManIsChar(p, '&') || Prs_ManIsChar(p, '|') || Prs_ManIsChar(p, '^') || Prs_ManIsChar(p, '-') )
    {
        if ( Prs_ManIsChar(p, '!') )
            Type = CBA_BOX_LNOT;
        else if ( Prs_ManIsChar(p, '~') )
            Type = CBA_BOX_INV;
        else if ( Prs_ManIsChar(p, '@') )
            Type = CBA_BOX_SQRT;
        else if ( Prs_ManIsChar(p, '&') )
            Type = CBA_BOX_RAND;
        else if ( Prs_ManIsChar(p, '|') )
            Type = CBA_BOX_ROR;
        else if ( Prs_ManIsChar(p, '^') )
            Type = CBA_BOX_RXOR;
        else if ( Prs_ManIsChar(p, '-') )
            Type = CBA_BOX_MIN;
        else assert( 0 );
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 24.", 0);
        // skip parentheses
        if ( Prs_ManIsChar(p, '(') )
        {
            pClose = Prs_ManFindClosingParenthesis( p, '(', ')' );
            if ( pClose == NULL )
                return Prs_ManErrorSet(p, "Expecting closing parenthesis 2.", 0); 
            *p->pCur = *pClose = ' ';
        }
        if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 24.", 0);
        // read first name
        Item = Prs_ManReadSignal( p );
        if ( Item == 0 )                        return Prs_ManErrorSet(p, "Cannot read name after a unary operator.", 0);
        Vec_IntPush( &p->vTemp, 0 );
        Vec_IntPush( &p->vTemp, Item );
    }
    else
    {
        // read first name
        Item = Prs_ManReadSignal( p );
        if ( Item == 0 )                        return Prs_ManErrorSet(p, "Cannot read name after a binary operator.", 0);
        // check if this is a recent function
        if ( Abc_Lit2Var2(Item) == p->FuncNameId )
        {
            int Status, nInputs, RangeSize;
            if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 24.", 0);
            if ( !Prs_ManIsChar(p, '(') )       return Prs_ManErrorSet(p, "Error number 24.", 0);
            p->pCur++;
            Status = Prs_ManReadSignalList( p, &p->vTemp, ')', 1 );
            nInputs = Vec_IntSize(&p->vTemp)/2;
            RangeSize = p->FuncRangeId ? Ptr_NtkRangeSize(p->pNtk, p->FuncRangeId) : 1;
            p->FuncNameId = p->FuncRangeId = 0;
            if ( Status == 0 )                  return 0;
            if ( nInputs == 1 )
                Type = CBA_BOX_DEC;
            else if ( nInputs == RangeSize + 1 )
                Type = CBA_BOX_SEL;
            else if ( nInputs == (1 << RangeSize) + 1 )
                Type = CBA_BOX_NMUX;
            else                                return Prs_ManErrorSet(p, "Cannot determine word-level operator.", 0);
            p->pCur++;
            if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 24.", 0);
            // save word-level operator
            Vec_IntInsert( &p->vTemp, 0, 0 );
            Vec_IntInsert( &p->vTemp, 1, OutItem );
            Prs_NtkAddBox( p->pNtk, Type, 0, &p->vTemp );
            return 1;
        }
        Vec_IntPush( &p->vTemp, 0 );
        Vec_IntPush( &p->vTemp, Item );
        if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 24.", 0);
        assert( !Prs_ManIsChar(p, '[') );

        // get the next symbol
        if ( Prs_ManIsChar(p, ',') || Prs_ManIsChar(p, ';') )
            Type = CBA_BOX_BUF;
        else if ( Prs_ManIsChar(p, '?') )
        {
            p->pCur++;
            Item = Prs_ManReadSignal( p );
            if ( Item == 0 )                    return 0;
            Vec_IntPush( &p->vTemp, 0 );
            Vec_IntPush( &p->vTemp, Item );
            if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 24.", 0);
            if ( !Prs_ManIsChar(p, ':') )       return Prs_ManErrorSet(p, "MUX lacks the colon symbol (:).", 0);

            p->pCur++;
            Item = Prs_ManReadSignal( p );
            if ( Item == 0 )                    return 0;
            Vec_IntPush( &p->vTemp, 0 );
            Vec_IntPush( &p->vTemp, Item );
            if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 24.", 0);
            assert( Vec_IntSize(&p->vTemp) == 8 );
            //ABC_SWAP( int, Vec_IntArray(&p->vTemp)[3], Vec_IntArray(&p->vTemp)[5] );
            Type = CBA_BOX_MUX;
        }
        else 
        {
                 if ( p->pCur[0] == '>' && p->pCur[1] == '>' && p->pCur[2] != '>' )  p->pCur += 2, Type = fRotating ? CBA_BOX_ROTR : CBA_BOX_SHIR;
            else if ( p->pCur[0] == '>' && p->pCur[1] == '>' && p->pCur[2] == '>' )  p->pCur += 3, Type = CBA_BOX_SHIRA;      
            else if ( p->pCur[0] == '<' && p->pCur[1] == '<' && p->pCur[2] != '<' )  p->pCur += 2, Type = fRotating ? CBA_BOX_ROTL : CBA_BOX_SHIL;
            else if ( p->pCur[0] == '<' && p->pCur[1] == '<' && p->pCur[2] == '<' )  p->pCur += 3, Type = CBA_BOX_SHILA;      
            else if ( p->pCur[0] == '&' && p->pCur[1] != '&'                      )  p->pCur += 1, Type = CBA_BOX_AND;       
            else if ( p->pCur[0] == '|' && p->pCur[1] != '|'                      )  p->pCur += 1, Type = CBA_BOX_OR;        
            else if ( p->pCur[0] == '^' && p->pCur[1] != '^'                      )  p->pCur += 1, Type = CBA_BOX_XOR;       
            else if ( p->pCur[0] == '&' && p->pCur[1] == '&'                      )  p->pCur += 2, Type = CBA_BOX_LAND;     
            else if ( p->pCur[0] == '|' && p->pCur[1] == '|'                      )  p->pCur += 2, Type = CBA_BOX_LOR;      
            else if ( p->pCur[0] == '=' && p->pCur[1] == '='                      )  p->pCur += 2, Type = CBA_BOX_EQU;      
            else if ( p->pCur[0] == '!' && p->pCur[1] == '='                      )  p->pCur += 2, Type = CBA_BOX_NEQU;      
            else if ( p->pCur[0] == '<' && p->pCur[1] != '='                      )  p->pCur += 1, Type = CBA_BOX_LTHAN;     
            else if ( p->pCur[0] == '>' && p->pCur[1] != '='                      )  p->pCur += 1, Type = CBA_BOX_MTHAN;     
            else if ( p->pCur[0] == '<' && p->pCur[1] == '='                      )  p->pCur += 2, Type = CBA_BOX_LETHAN;
            else if ( p->pCur[0] == '>' && p->pCur[1] == '='                      )  p->pCur += 2, Type = CBA_BOX_METHAN;  
            else if ( p->pCur[0] == '+'                                           )  p->pCur += 1, Type = CBA_BOX_ADD;       
            else if ( p->pCur[0] == '-'                                           )  p->pCur += 1, Type = CBA_BOX_SUB;       
            else if ( p->pCur[0] == '*' && p->pCur[1] != '*'                      )  p->pCur += 1, Type = CBA_BOX_MUL;     
            else if ( p->pCur[0] == '/'                                           )  p->pCur += 1, Type = CBA_BOX_DIV;        
            else if ( p->pCur[0] == '%'                                           )  p->pCur += 1, Type = CBA_BOX_MOD;   
            else if ( p->pCur[0] == '*' && p->pCur[1] == '*'                      )  p->pCur += 2, Type = CBA_BOX_POW;
            else return Prs_ManErrorSet(p, "Unsupported operation.", 0);

            Item = Prs_ManReadSignal( p );
            if ( Item == 0 )                    return 0;
            Vec_IntPush( &p->vTemp, 0 );
            Vec_IntPush( &p->vTemp, Item );
            // for adder insert carry-in
            if ( Type == CBA_BOX_ADD )
                Vec_IntInsert( &p->vTemp, 2, 0 );
            if ( Type == CBA_BOX_ADD )
                Vec_IntInsert( &p->vTemp, 3, 0 );
        }
    }
    if ( Prs_ManUtilSkipSpaces(p) )                              return Prs_ManErrorSet(p, "Error number 24.", 0);
    // make sure there is nothing left there
    if ( fRotating )
    {
        Prs_ManUtilSkipUntilWord(p, ";");
        p->pCur--;
    }
    else if ( !Prs_ManIsChar(p, ',') && !Prs_ManIsChar(p, ';') ) return Prs_ManErrorSet(p, "Trailing symbols on this line.", 0);
    // save binary operator
    Prs_NtkAddBox( p->pNtk, Type, 0, &p->vTemp );
    return 1;
}
static inline int Prs_ManReadDeclaration( Prs_Man_t * p, int Type )
{
    int i, Item = 0, NameId, RangeId = 0, fSigned = 0;
    Vec_Int_t * vNames[4]  = { &p->pNtk->vInputs,  &p->pNtk->vOutputs,  &p->pNtk->vInouts,  &p->pNtk->vWires };
    Vec_Int_t * vNamesR[4] = { &p->pNtk->vInputsR, &p->pNtk->vOutputsR, &p->pNtk->vInoutsR, &p->pNtk->vWiresR };
    assert( Type >= PRS_VER_INPUT && Type <= PRS_VER_WIRE );
    // read first word
    if ( Prs_ManUtilSkipSpaces(p) )                                       return Prs_ManErrorSet(p, "Error number 20.", 0);
    if ( Prs_ManIsChar(p, '[') && !(RangeId = Prs_ManReadRange(p)) )      return Prs_ManErrorSet(p, "Error number 21.", 0);
    Item = Prs_ManReadName(p);
    if ( Item == PRS_VER_SIGNED )
    {
        fSigned = 1;
        if ( Prs_ManUtilSkipSpaces(p) )                                   return Prs_ManErrorSet(p, "Error number 20.", 0);
        if ( Prs_ManIsChar(p, '[') && !(RangeId = Prs_ManReadRange(p)) )  return Prs_ManErrorSet(p, "Error number 21.", 0);
        Item = Prs_ManReadName(p);
    }
    if ( Item == PRS_VER_WIRE )
    {
        if ( Prs_ManUtilSkipSpaces(p) )                                   return Prs_ManErrorSet(p, "Error number 20.", 0);
        if ( Prs_ManIsChar(p, '[') && !(RangeId = Prs_ManReadRange(p)) )  return Prs_ManErrorSet(p, "Error number 21.", 0);
        Item = Prs_ManReadName(p);
    }
    // read variable names
    Vec_IntClear( &p->vTemp3 );
    while ( 1 )
    {
        if ( Item == 0 )                    return Prs_ManErrorSet(p, "Cannot read name in the list.", 0);
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 22a", 0);
        if ( Item == PRS_VER_WIRE  )
            continue;
        Vec_IntPush( &p->vTemp3, Item );
        if ( Prs_ManIsChar(p, '=') )
        {
            if ( Type == PRS_VER_INPUT )    return Prs_ManErrorSet(p, "Input cannot be defined", 0);
            p->pCur++;
            if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 23.", 0);
            if ( !Prs_ManReadExpression(p, Abc_Var2Lit2(Item, CBA_PRS_NAME)) ) 
                return 0;
        }
        if ( Prs_ManIsChar(p, ';') )   
            break;
        if ( !Prs_ManIsChar(p, ',') )       return Prs_ManErrorSet(p, "Expecting comma in the list.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 22b.", 0);
        Item = Prs_ManReadName(p);
    }
    Vec_IntForEachEntry( &p->vTemp3, NameId, i )
    {
        Vec_IntPush( vNames[Type - PRS_VER_INPUT],  NameId );
        Vec_IntPush( vNamesR[Type - PRS_VER_INPUT], Abc_Var2Lit(RangeId, fSigned) );
        if ( Type < PRS_VER_WIRE )
            Vec_IntPush( &p->pNtk->vOrder, Abc_Var2Lit2(NameId, Type) );
    }
    return 1;
}
static inline int Prs_ManReadInstance( Prs_Man_t * p, int Func )
{
    int InstId, Status;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 25.", 0);
    if ( Prs_ManIsChar(p, '#') )
    {
        p->pCur++;
        while ( Prs_ManIsDigit(p) )
            p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 25.", 0);
    }
    if ( (InstId = Prs_ManReadName(p)) )
        if (Prs_ManUtilSkipSpaces(p))       return Prs_ManErrorSet(p, "Error number 26.", 0);
    if ( !Prs_ManIsChar(p, '(') )           return Prs_ManErrorSet(p, "Expecting \"(\" in module instantiation.", 0);
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 27.", 0);
    if ( Prs_ManIsChar(p, '.') ) // box
        Status = Prs_ManReadSignalList2(p, &p->vTemp);
    else  // node
    {
        //char * s = Abc_NamStr(p->pStrs, Func);
        // translate elementary gate
        int iFuncNew = Prs_ManIsVerilogPrim(Abc_NamStr(p->pStrs, Func));
        if ( iFuncNew == 0 )                return Prs_ManErrorSet(p, "Cannot find elementary gate.", 0);
        Func = iFuncNew;
        Status = Prs_ManReadSignalList( p, &p->vTemp, ')', 1 );
    }
    if ( Status == 0 )                      return Prs_ManErrorSet(p, "Error number 28.", 0);
    assert( Prs_ManIsChar(p, ')') );
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 29.", 0);
    if ( !Prs_ManIsChar(p, ';') )           return Prs_ManErrorSet(p, "Expecting semicolon in the instance.", 0);
    // add box 
    Prs_NtkAddBox( p->pNtk, Func, InstId, &p->vTemp );
    return 1;
}
static inline int Prs_ManReadArguments( Prs_Man_t * p )
{
    int iRange = 0, iType = -1;
    Vec_Int_t * vSigs[3]  = { &p->pNtk->vInputs,  &p->pNtk->vOutputs,  &p->pNtk->vInouts  };
    Vec_Int_t * vSigsR[3] = { &p->pNtk->vInputsR, &p->pNtk->vOutputsR, &p->pNtk->vInoutsR };
    assert( Prs_ManIsChar(p, '(') );
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )             return Prs_ManErrorSet(p, "Error number 30.", 0);
    if ( Prs_ManIsChar(p, ')') )
        return 1;
    while ( 1 )
    {
        int fEscape = Prs_ManIsChar(p, '\\');
        int iName = Prs_ManReadName( p );
        int fSigned = 0;
        if ( iName == 0 )                       return Prs_ManErrorSet(p, "Error number 31.", 0);
        if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 32.", 0);
        if ( iName >= PRS_VER_INPUT && iName <= PRS_VER_INOUT && !fEscape ) // declaration
        {
            iType = iName;
            if ( Prs_ManIsChar(p, '[') )
            {
                iRange = Prs_ManReadRange(p);
                if ( iRange == 0 )              return Prs_ManErrorSet(p, "Error number 33.", 0);
                if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 34.", 0);
            }
            iName = Prs_ManReadName( p );
            if ( iName == 0 )                   return Prs_ManErrorSet(p, "Error number 35.", 0);
            if ( iName == PRS_VER_SIGNED )
            {
                fSigned = 1;
                if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 32.", 0);
                if ( Prs_ManIsChar(p, '[') )
                {
                    iRange = Prs_ManReadRange(p);
                    if ( iRange == 0 )              return Prs_ManErrorSet(p, "Error number 33.", 0);
                    if ( Prs_ManUtilSkipSpaces(p) ) return Prs_ManErrorSet(p, "Error number 34.", 0);
                }
                iName = Prs_ManReadName( p );
                if ( iName == 0 )               return Prs_ManErrorSet(p, "Error number 35.", 0);
            }
        }
        if ( iType > 0 )
        {
            Vec_IntPush( vSigs[iType - PRS_VER_INPUT], iName );
            Vec_IntPush( vSigsR[iType - PRS_VER_INPUT], Abc_Var2Lit(iRange, fSigned) );
            Vec_IntPush( &p->pNtk->vOrder, Abc_Var2Lit2(iName, iType) );
        }
        if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 36.", 0);
        if ( Prs_ManIsChar(p, ')') )
            break;
        if ( !Prs_ManIsChar(p, ',') )           return Prs_ManErrorSet(p, "Expecting comma in the instance.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 36.", 0);
    }
    // check final
    assert( Prs_ManIsChar(p, ')') );
    return 1;
}
// this procedure can return:
// 0 = reached end-of-file; 1 = successfully parsed; 2 = recognized as primitive; 3 = failed and skipped; 4 = error (failed and could not skip)
static inline int Prs_ManReadModule( Prs_Man_t * p )
{
    int iToken, Status, fAlways = 0;
    if ( p->pNtk != NULL )                  return Prs_ManErrorSet(p, "Parsing previous module is unfinished.", 4);
    if ( Prs_ManUtilSkipSpaces(p) )
    { 
        Prs_ManErrorClear( p );       
        return 0; 
    }
    // read keyword
    while ( Prs_ManIsChar(p, '`') )
    {
        Prs_ManUtilSkipUntilWord(p, "\n");
        if ( Prs_ManUtilSkipSpaces(p) )
        { 
            Prs_ManErrorClear( p );       
            return 0; 
        }
    }
    iToken = Prs_ManReadName( p );
    if ( iToken != PRS_VER_MODULE )         return Prs_ManErrorSet(p, "Cannot read \"module\" keyword.", 4);
    if ( Prs_ManUtilSkipSpaces(p) )         return 4;
    // read module name
    iToken = Prs_ManReadName( p );
    if ( iToken == 0 )                      return Prs_ManErrorSet(p, "Cannot read module name.", 4);
    if ( Prs_ManIsKnownModule(Abc_NamStr(p->pStrs, iToken)) )
    {
        if ( Prs_ManUtilSkipUntilWord( p, "endmodule" ) ) return Prs_ManErrorSet(p, "Cannot find \"endmodule\" keyword.", 4);
        //printf( "Warning! Skipped known module \"%s\".\n", Abc_NamStr(p->pStrs, iToken) );
        Vec_IntPush( &p->vKnown, iToken );
        return 2;
    }
    Prs_ManInitializeNtk( p, iToken, 1 );
    // skip arguments
    if ( Prs_ManUtilSkipSpaces(p) )         return 4;
    if ( !Prs_ManIsChar(p, '(') )           return Prs_ManErrorSet(p, "Cannot find \"(\" in the argument declaration.", 4);
    if ( !Prs_ManReadArguments(p) )         return 4;
    assert( *p->pCur == ')' );
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return 4;
    // read declarations and instances
    while ( Prs_ManIsChar(p, ';') || fAlways )
    {
        if ( !fAlways ) p->pCur++;
        fAlways = 0;
        if ( Prs_ManUtilSkipSpaces(p) )     return 4;
        iToken = Prs_ManReadName( p );
        if ( iToken == PRS_VER_ENDMODULE )
        {
            Vec_IntPush( &p->vSucceeded, p->pNtk->iModuleName );
            Prs_ManFinalizeNtk( p );
            return 1;
        }
        if ( iToken >= PRS_VER_INPUT && iToken <= PRS_VER_REG ) // declaration
            Status = Prs_ManReadDeclaration( p, iToken == PRS_VER_REG ? PRS_VER_WIRE : iToken );
        else if ( iToken == PRS_VER_REG || iToken == PRS_VER_DEFPARAM ) // unsupported keywords
            Status = Prs_ManUtilSkipUntil( p, ';' );
        else // read instance
        {
            if ( iToken == PRS_VER_ASSIGN )
            {
                // read output name
                int OutItem = Prs_ManReadSignal( p );
                if ( OutItem == 0 )                     return Prs_ManErrorSet(p, "Cannot read output in assign-statement.", 0);
                if ( !Prs_ManIsChar(p, '=') )           return Prs_ManErrorSet(p, "Expecting \"=\" in assign-statement.", 0);
                p->pCur++;
                if ( Prs_ManUtilSkipSpaces(p) )         return Prs_ManErrorSet(p, "Error number 23.", 0);
                // read expression
                while ( 1 )
                {
                    if ( !Prs_ManReadExpression(p, OutItem) )    return 0;
                    if ( Prs_ManIsChar(p, ';') )
                        break;
                    assert( Prs_ManIsChar(p, ',') );
                    p->pCur++;
                    if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 23a.", 0);
                    // read output name
                    OutItem = Prs_ManReadSignal( p );
                    if ( OutItem == 0 )                 return Prs_ManErrorSet(p, "Cannot read output in assign-statement.", 0);
                    if ( !Prs_ManIsChar(p, '=') )       return Prs_ManErrorSet(p, "Expecting \"=\" in assign-statement.", 0);
                    p->pCur++;
                    if ( Prs_ManUtilSkipSpaces(p) )     return Prs_ManErrorSet(p, "Error number 23.", 0);
                }
            }
            else if ( iToken == PRS_VER_ALWAYS )
                Status = Prs_ManReadAlways(p), fAlways = 1;
            else if ( iToken == PRS_VER_FUNCTION )
                Status = Prs_ManReadFunction(p), fAlways = 1;
            else
                Status = Prs_ManReadInstance( p, iToken );
            if ( Status == 0 )
            {
                return 4;

                if ( Prs_ManUtilSkipUntilWord( p, "endmodule" ) ) return Prs_ManErrorSet(p, "Cannot find \"endmodule\" keyword.", 4);
                //printf( "Warning! Failed to parse \"%s\". Adding module \"%s\" as blackbox.\n", 
                //    Abc_NamStr(p->pStrs, iToken), Abc_NamStr(p->pStrs, p->pNtk->iModuleName) );
                Vec_IntPush( &p->vFailed, p->pNtk->iModuleName );
                // cleanup
                Vec_IntErase( &p->pNtk->vWires );
                Vec_IntErase( &p->pNtk->vWiresR );
                Vec_IntErase( &p->pNtk->vSlices );
                Vec_IntErase( &p->pNtk->vConcats );
                Vec_IntErase( &p->pNtk->vBoxes );
                Vec_IntErase( &p->pNtk->vObjs );
                p->fUsingTemp2 = 0;
                // add
                Prs_ManFinalizeNtk( p );
                Prs_ManErrorClear( p );
                return 3;
            }
        }
        if ( !Status )                      return 4;
        if ( Prs_ManUtilSkipSpaces(p) )     return 4;
    }
    return Prs_ManErrorSet(p, "Cannot find \";\" in the module definition.", 4);
}
static inline int Prs_ManReadDesign( Prs_Man_t * p )
{
    while ( 1 )
    {
        int RetValue = Prs_ManReadModule( p );
        if ( RetValue == 0 ) // end of file
            break;
        if ( RetValue == 1 ) // successfully parsed
            continue;
        if ( RetValue == 2 ) // recognized as primitive
            continue;
        if ( RetValue == 3 ) // failed and skipped
            continue;
        if ( RetValue == 4 ) // error
            return 0;
        assert( 0 );
    }
    return 1;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Prs_ManPrintModules( Prs_Man_t * p )
{
    char * pName; int i; 
    printf( "Succeeded parsing %d models:\n", Vec_IntSize(&p->vSucceeded) );
    Prs_ManForEachNameVec( &p->vSucceeded, p, pName, i )
        printf( " %s", pName );
    printf( "\n" );
    printf( "Skipped %d known models:\n", Vec_IntSize(&p->vKnown) );
    Prs_ManForEachNameVec( &p->vKnown, p, pName, i )
        printf( " %s", pName );
    printf( "\n" );
    printf( "Skipped %d failed models:\n", Vec_IntSize(&p->vFailed) );
    Prs_ManForEachNameVec( &p->vFailed, p, pName, i )
        printf( " %s", pName );
    printf( "\n" );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Prs_ManReadVerilog( char * pFileName )
{
    Vec_Ptr_t * vPrs = NULL;
    Prs_Man_t * p = Prs_ManAlloc( pFileName );
    if ( p == NULL )
        return NULL;
    Abc_NamStrFindOrAdd( p->pFuns, "1\'b0", NULL );
    Abc_NamStrFindOrAdd( p->pFuns, "1\'b1", NULL );
    Abc_NamStrFindOrAdd( p->pFuns, "1\'bx", NULL );
    Abc_NamStrFindOrAdd( p->pFuns, "1\'bz", NULL );
    Prs_NtkAddVerilogDirectives( p );
    Prs_ManReadDesign( p );   
    Prs_ManPrintModules( p );
    if ( Prs_ManErrorPrint(p) )
        ABC_SWAP( Vec_Ptr_t *, vPrs, p->vNtks );
    Prs_ManFree( p );
    return vPrs;
}

void Prs_ManReadVerilogTest( char * pFileName )
{
    abctime clk = Abc_Clock();
    Vec_Ptr_t * vPrs = Prs_ManReadVerilog( pFileName );
    if ( !vPrs ) return;
    printf( "Finished reading %d networks. ", Vec_PtrSize(vPrs) );
    printf( "NameIDs = %d. ", Abc_NamObjNumMax(Prs_ManNameMan(vPrs)) );
    printf( "Memory = %.2f MB. ", 1.0*Prs_ManMemory(vPrs)/(1<<20) );
    Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
    Prs_ManWriteVerilog( Extra_FileNameGenericAppend(pFileName, "_out.v"), vPrs );
//    Abc_NamPrint( Prs_ManNameMan(vPrs) );
    Prs_ManVecFree( vPrs );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Prs_CreateVerilogFindFon( Cba_Ntk_t * p, int NameId )
{
    int iFon = Cba_NtkGetMap( p, NameId );
    if ( iFon )
        return iFon;
    printf( "Network \"%s\": Signal \"%s\" is not driven.\n", Cba_NtkName(p), Cba_NtkStr(p, NameId) );
    return 0;
}
int Prs_CreateSlice( Cba_Ntk_t * p, int iFon, Prs_Ntk_t * pNtk, int Range )
{
    int iObj, iFonNew, NameId;
    assert( Cba_FonIsReal(iFon) );
    // check existing slice
    NameId = Cba_NtkNewStrId( p, Cba_ManGetSliceName(p, iFon, Range) );
    iFonNew = Cba_NtkGetMap( p, NameId );
    if ( iFonNew )
        return iFonNew;
    // create slice
    iObj = Cba_ObjAlloc( p, CBA_BOX_SLICE, 1, 1 );
    Cba_ObjSetName( p, iObj, NameId );
    Cba_ObjSetFinFon( p, iObj, 0, iFon );
    iFonNew = Cba_ObjFon0(p, iObj);
    Cba_FonSetRange( p, iFonNew, Range );
    Cba_FonSetName( p, iFonNew, NameId );
    Cba_NtkSetMap( p, NameId, iFonNew );
    return iFonNew;        
}
int Prs_CreateCatIn( Cba_Ntk_t * p, Prs_Ntk_t * pNtk, int Con )
{
    extern int Prs_CreateSignalIn( Cba_Ntk_t * p, Prs_Ntk_t * pNtk, int Sig );
    int i, Sig, iObj, iFon, NameId, nBits = 0;
    Vec_Int_t * vSigs = Prs_CatSignals(pNtk, Con);
    // create input concatenation
    iObj = Cba_ObjAlloc( p, CBA_BOX_CONCAT, Vec_IntSize(vSigs), 1 );
    iFon = Cba_ObjFon0(p, iObj);
    //sprintf( Buffer, "_icc%d_", iObj );
    //NameId = Cba_NtkNewStrId( p, Buffer );
    NameId = Cba_NtkNewStrId( p, "_icc%d_", iObj );
    Cba_FonSetName( p, iFon, NameId );
    Cba_NtkSetMap( p, NameId, iFon );
    // set inputs
    Vec_IntForEachEntry( vSigs, Sig, i )
    {
        iFon = Prs_CreateSignalIn( p, pNtk, Sig );
        if ( iFon )
            Cba_ObjSetFinFon( p, iObj, i, iFon );
        if ( iFon )
            nBits += Cba_FonRangeSize( p, iFon );
    }
    iFon = Cba_ObjFon0(p, iObj);
    Cba_FonSetRange( p, iFon, Cba_NtkHashRange(p, nBits-1, 0) );
    return Cba_ObjFon0(p, iObj);
}
int Prs_CreateSignalIn( Cba_Ntk_t * p, Prs_Ntk_t * pNtk, int Sig )
{
    int iFon, Value = Abc_Lit2Var2( Sig );
    Prs_ManType_t Type = (Prs_ManType_t)Abc_Lit2Att2( Sig );
    if ( !Sig ) return 0;
    if ( Type == CBA_PRS_NAME )
        return Prs_CreateVerilogFindFon( p, Cba_NtkNewStrId(p, Prs_NtkStr(pNtk, Value)) );
    if ( Type == CBA_PRS_CONST )
        return Cba_FonFromConst( Value );
    if ( Type == CBA_PRS_SLICE )
    {
        iFon =  Prs_CreateVerilogFindFon( p, Cba_NtkNewStrId(p, Prs_NtkStr(pNtk, Prs_SliceName(pNtk, Value))) );
        if ( !iFon )
            return 0;
        return Prs_CreateSlice( p, iFon, pNtk, Prs_SliceRange(pNtk, Value) );
    }
    assert( Type == CBA_PRS_CONCAT );
    return Prs_CreateCatIn( p, pNtk, Value );
}
int Prs_CreateRange( Cba_Ntk_t * p, int iFon, int NameId )
{
    int RangeId = -Cba_NtkGetMap(p, NameId);
    if ( RangeId < 0 ) // this variable is already created
        return Cba_FonRangeSize( p, -RangeId );
    Cba_NtkUnsetMap( p, NameId );
    Cba_NtkSetMap( p, NameId, iFon );
    if ( RangeId == 0 )
        return 1;
    assert( RangeId > 0 );
    Cba_FonSetRangeSign( p, iFon, RangeId );
    return Cba_FonRangeSize( p, iFon );
}
void Prs_CreateSignalOut( Cba_Ntk_t * p, int iFon, Prs_Ntk_t * pNtk, int Sig )
{
    int i, iFonNew, NameOut, RangeOut, NameId, RangeId, RangeSize, nBits = 0; 
    Prs_ManType_t SigType = (Prs_ManType_t)Abc_Lit2Att2( Sig );
    int SigValue = Abc_Lit2Var2( Sig );
    if ( !Sig ) return;
    if ( SigType == CBA_PRS_NAME )
    {
        NameId = SigValue;
        if ( !strncmp(Cba_NtkStr(p, NameId), "Open_", 5) )
            return;
        Cba_FonSetName( p, iFon, NameId );
        Prs_CreateRange( p, iFon, NameId );
        return;
    }
    // create name for this fan
    NameOut = Cba_NtkNewStrId( p, "_occ%d_", iFon );
    Cba_FonSetName( p, iFon, NameOut );
    Cba_NtkSetMap( p, NameOut, iFon );
    // consider special cases
    if ( SigType == CBA_PRS_SLICE )
    {
        NameId  = Prs_SliceName(pNtk, SigValue);
        RangeId = Prs_SliceRange(pNtk, SigValue);
        nBits   = Cba_NtkRangeSize(p, RangeId);
        // save this slice
        Vec_IntPushThree( &p->vArray0, NameId, RangeId, iFon );
    }
    else if ( SigType == CBA_PRS_CONCAT )
    {
        Vec_Int_t * vSigs = Prs_CatSignals(pNtk, SigValue);
        Vec_IntReverseOrder( vSigs );
        Vec_IntForEachEntry( vSigs, Sig, i )
        {
            SigType = (Prs_ManType_t)Abc_Lit2Att2( Sig );
            SigValue = Abc_Lit2Var2( Sig );
            if ( SigType == CBA_PRS_NAME )
            {
                int iObjBuf, iFonBuf;
                // create buffer
                NameId = SigValue;
                if ( !strncmp(Cba_NtkStr(p, NameId), "Open_", 5) )
                {
                    nBits++;
                    continue;
                }
                iObjBuf   = Cba_ObjAlloc( p, CBA_BOX_BUF, 1, 1 );
                iFonBuf   = Cba_ObjFon0(p, iObjBuf);
                Cba_FonSetName( p, iFonBuf, NameId );
                RangeSize = Prs_CreateRange( p, iFonBuf, NameId );
                RangeOut  = Cba_NtkHashRange(p, nBits+RangeSize-1, nBits);
                // create slice
                iFonNew   = Prs_CreateSlice( p, iFon, pNtk, RangeOut );
                Cba_ObjSetFinFon( p, iObjBuf, 0, iFonNew );
            }
            else if ( SigType == CBA_PRS_SLICE )
            {
                NameId    = Prs_SliceName(pNtk, SigValue);
                RangeId   = Prs_SliceRange(pNtk, SigValue);
                RangeSize = Cba_NtkRangeSize(p, RangeId);
                RangeOut  = Cba_NtkHashRange(p, nBits+RangeSize-1, nBits);
                // create slice
                iFonNew   = Prs_CreateSlice( p, iFon, pNtk, RangeOut );
                // save this slice
                Vec_IntPushThree( &p->vArray0, NameId, RangeId, iFonNew );
            }
            else assert( 0 );
            // increment complete range
            nBits += RangeSize;
        }
        Vec_IntReverseOrder( vSigs );
    }
    else assert( 0 );
    // set the range for the output
    Cba_FonHashRange( p, iFon, nBits-1, 0 );
}

void Prs_CreateOutConcat( Cba_Ntk_t * p, int * pSlices, int nSlices )
{
    Vec_Int_t * vBits = &p->vArray1;
    int NameId    = pSlices[0];
    int RangeId   = -Cba_NtkGetMap(p, NameId);
    int LeftId    = Cba_NtkRangeLeft( p, RangeId );
    int RightId   = Cba_NtkRangeRight( p, RangeId );
    int BotId     = Abc_MinInt( LeftId, RightId );
    int TopId     = Abc_MaxInt( LeftId, RightId );
    int i, k, iObj, iFon, nParts, Prev, nBits;
    assert( RangeId > 0 );
    Vec_IntFill( vBits, Abc_MaxInt(LeftId, RightId) + 1, 0 );
    // fill up with slices
    for ( i = 0; i < nSlices; i++ )
    {
        int Range = pSlices[3*i+1];
        int iFon  = pSlices[3*i+2];
        int Left  = Cba_NtkRangeLeft( p, Range );
        int Right = Cba_NtkRangeRight( p, Range );
        int Bot   = Abc_MinInt( Left, Right );
        int Top   = Abc_MaxInt( Left, Right );
        assert( NameId == pSlices[3*i+0] && iFon > 0 );
        assert( BotId <= Bot && Top <= TopId );
        for ( k = Bot; k <= Top; k++ )
        {
            assert( Vec_IntEntry(vBits, k) == 0 );
            Vec_IntWriteEntry( vBits, k, iFon );
        }
    }
    // check how many parts we have
    Prev = -1; nParts = 0; 
    Vec_IntForEachEntryStartStop( vBits, iFon, i, BotId, TopId+1 )
    {
        if ( Prev != iFon )
            nParts++;
        Prev = iFon;
    }
    // create new concatenation
    iObj = Cba_ObjAlloc( p, CBA_BOX_CONCAT, nParts, 1 );
    iFon = Cba_ObjFon0(p, iObj);
    Cba_FonSetName( p, iFon, NameId );
    Prs_CreateRange( p, iFon, NameId );
    // set inputs
    k = 0; Prev = -1; nBits = 0;
    Vec_IntForEachEntryStartStop( vBits, iFon, i, BotId, TopId+1 )
    {
        if ( Prev == -1 || Prev == iFon )
            nBits++;
        else
        {
            if ( Prev == 0 ) // create constant
                Prev = Cba_ManNewConstZero( p, nBits );
            assert( nBits == Cba_FonRangeSize(p, Prev) );
            Cba_ObjSetFinFon( p, iObj, nParts-1-k++, Prev );
            nBits = 1;
        }
        Prev = iFon;         
    }
    assert( nBits == Cba_FonRangeSize(p, Prev) );
    Cba_ObjSetFinFon( p, iObj, nParts-1-k++, Prev );
    assert( k == nParts );
}

// looks at multi-bit signal; if one bit is repeated, returns this bit; otherwise, returns -1
int Prs_CreateBitSignal( Prs_Ntk_t * pNtk, int Sig )
{
    Vec_Int_t * vSigs;
    int i, SigTemp, SigOne = -1, Value = Abc_Lit2Var2( Sig );
    Prs_ManType_t Type = (Prs_ManType_t)Abc_Lit2Att2( Sig );
    if ( Type == CBA_PRS_NAME || Type == CBA_PRS_SLICE )
        return -1;
    if ( Type == CBA_PRS_CONST )
    {
        int fOnly0 = 1, fOnly1 = 1;
        char * pConst = Prs_NtkConst(pNtk, Value);
        pConst = strchr( pConst, '\'' ) + 1;
        assert( *pConst == 'b' );
        while ( *++pConst )
            if ( *pConst == '0' )
                fOnly1 = 0;
            else if ( *pConst == '1' )
                fOnly0 = 0;
        if ( fOnly0 )
            return Abc_Var2Lit2( 1, CBA_PRS_CONST ); // const0
        if ( fOnly1 )
            return Abc_Var2Lit2( 2, CBA_PRS_CONST ); // const1
        return -1;
    }
    assert( Type == CBA_PRS_CONCAT );
    vSigs = Prs_CatSignals( pNtk, Value );
    Vec_IntForEachEntry( vSigs, SigTemp, i )
    {
        Value = Abc_Lit2Var2( SigTemp );
        Type = (Prs_ManType_t)Abc_Lit2Att2( SigTemp );
        if ( Type != CBA_PRS_NAME )
            return -1;
        if ( SigOne == -1 )
            SigOne = Value;
        else if ( SigOne != Value )
            return -1;
    }
    assert( SigOne >= 0 );
    return Abc_Var2Lit2( SigOne, CBA_PRS_NAME );
}

int Prs_CreateFlopSetReset( Cba_Ntk_t * p, Prs_Ntk_t * pNtk, Vec_Int_t * vBox, int * pIndexSet, int * pIndexRst, int * pBitSet, int * pBitRst )
{
    int iSigSet = -1, iSigRst = -1;
    int IndexSet = -1, IndexRst = -1;
    int FormId, ActId, k;
    // mark set and reset
    Cba_NtkCleanMap2( p );
    Cba_NtkSetMap2( p, Cba_NtkStrId(p, "set"), 1 );
    Cba_NtkSetMap2( p, Cba_NtkStrId(p, "reset"), 2 );
    // check the inputs
    Vec_IntForEachEntryDouble( vBox, FormId, ActId, k )
        if ( Cba_NtkGetMap2(p, FormId) == 1 ) // set
            iSigSet = ActId, IndexSet = k+1;
        else if ( Cba_NtkGetMap2(p, FormId) == 2 ) // reset
            iSigRst = ActId, IndexRst = k+1;
    assert( iSigSet >= 0 && iSigRst >= 0 );
    if ( pIndexSet ) *pBitSet = 0;
    if ( pIndexRst ) *pBitRst = 0;
    if ( pBitSet )   *pBitSet = 0;
    if ( pBitRst )   *pBitRst = 0;
    if ( iSigSet == -1 || iSigRst == -1 )
        return 0;
    iSigSet = Prs_CreateBitSignal(pNtk, iSigSet);
    iSigRst = Prs_CreateBitSignal(pNtk, iSigRst);
    if ( iSigSet == -1 || iSigRst == -1 )
        return 0;
    if ( pIndexSet ) *pIndexSet = IndexSet;
    if ( pIndexRst ) *pIndexRst = IndexRst;
    if ( pBitSet )   *pBitSet = iSigSet;
    if ( pBitRst )   *pBitRst = iSigRst;
    return 1;
}
char * Prs_CreateDetectRamPort( Prs_Ntk_t * pNtk, Vec_Int_t * vBox, int NameRamId )
{
    int i, FormId, ActId;
    Vec_IntForEachEntryDouble( vBox, FormId, ActId, i )
        if ( FormId == NameRamId )
            return Abc_NamStr(pNtk->pStrs, Abc_Lit2Var2(ActId));
    return NULL;
}
int Prs_CreateGetMemSize( char * pName )
{
    char * pPtr1 = strchr( pName, '_' );
    char * pPtr2 = strchr( pPtr1+1, '_' );
    int Num1 = atoi( pPtr1 + 1 );
    int Num2 = atoi( pPtr2 + 1 );
    assert( Num1 + Abc_Base2Log(Num2) < 32 );
    return (1 << Num1) * Num2;
}
Vec_Ptr_t * Prs_CreateDetectRams( Prs_Ntk_t * pNtk )
{
    Vec_Ptr_t * vAllRams = NULL, * vRam; 
    Vec_Int_t * vBox, * vBoxCopy; 
    char * pNtkName, * pRamName;
    int NameRamId = Abc_NamStrFind( pNtk->pStrs, "Ram" );
    int i, k, fWrite;
    Prs_NtkForEachBox( pNtk, vBox, i )
    {
        if ( Prs_BoxIsNode(pNtk, i) ) // node
            continue;
        pNtkName = Prs_NtkStr(pNtk, Prs_BoxNtk(pNtk, i));
        fWrite = !strncmp(pNtkName, "ClockedWritePort_", strlen("ClockedWritePort_"));
        if ( fWrite || !strncmp(pNtkName, "ReadPort_", strlen("ReadPort_")) )
        {
            pRamName = Prs_CreateDetectRamPort( pNtk, vBox, NameRamId ); assert( pRamName );
            if ( vAllRams == NULL )
                vAllRams = Vec_PtrAlloc( 4 );
            Vec_PtrForEachEntry( Vec_Ptr_t *, vAllRams, vRam, k )
                if ( pRamName == (char *)Vec_PtrEntry(vRam, 0) )
                {
                    if ( fWrite )
                    {
                        vBoxCopy = Vec_IntDup(vBox);
                        Vec_IntPush( vBoxCopy, i );
                        Vec_PtrPush( vRam, vBoxCopy );
                    }
                    break;
                }
            if ( k < Vec_PtrSize(vAllRams) )
                continue;
            vRam = Vec_PtrAlloc( 4 );
            Vec_PtrPush( vRam, pRamName );
            Vec_PtrPush( vRam, Abc_Int2Ptr(Prs_CreateGetMemSize(pNtkName)) );
            if ( fWrite )
            {
                vBoxCopy = Vec_IntDup(vBox);
                Vec_IntPush( vBoxCopy, i );
                Vec_PtrPush( vRam, vBoxCopy );
            }
            Vec_PtrPush( vAllRams, vRam );
        }
    }
    return vAllRams;
}
void Prs_CreateVerilogPio( Cba_Ntk_t * p, Prs_Ntk_t * pNtk )
{
    int i, NameId, RangeId, iObj, iFon;
    Cba_NtkCleanObjFuncs( p );
    Cba_NtkCleanObjNames( p );
    Cba_NtkCleanFonNames( p );
    Cba_NtkCleanFonRanges( p );
    // create inputs
    Cba_NtkCleanMap( p );
    assert( Vec_IntSize(&pNtk->vInouts) == 0 );
    Vec_IntForEachEntryTwo( &pNtk->vInputs, &pNtk->vInputsR, NameId, RangeId, i )
    {
        iObj = Cba_ObjAlloc( p, CBA_OBJ_PI, 0, 1 );
        Cba_ObjSetName( p, iObj, NameId ); // direct name
        iFon = Cba_ObjFon0(p, iObj);
        Cba_FonSetRangeSign( p, iFon, RangeId );
        Cba_FonSetName( p, iFon, NameId );
        Cba_NtkSetMap( p, NameId, iObj );
    }
    // create outputs
    Vec_IntForEachEntryTwo( &pNtk->vOutputs, &pNtk->vOutputsR, NameId, RangeId, i )
    {
        iObj = Cba_ObjAlloc( p, CBA_OBJ_PO, 1, 0 );
        Cba_ObjSetName( p, iObj, NameId ); // direct name
        Cba_NtkSetMap( p, NameId, iObj );
    }
    // create order
    Vec_IntForEachEntry( &pNtk->vOrder, NameId, i )
    {
        iObj = Prs_CreateVerilogFindFon( p, Abc_Lit2Var2(NameId) ); // labeled name
        if ( iObj )
            Vec_IntPush( &p->vOrder, iObj );
    }
}
int Prs_CreateVerilogNtk( Cba_Ntk_t * p, Prs_Ntk_t * pNtk )
{
    Vec_Int_t * vBox2Obj = Vec_IntStart( Prs_NtkBoxNum(pNtk) );
    Vec_Int_t * vBox;  Vec_Ptr_t * vAllRams, * vRam;
    int i, k, iObj, iTerm, iFon, FormId, ActId, RangeId, NameId, Type;
    // map inputs
    Cba_NtkCleanMap( p );
    Cba_NtkForEachPi( p, iObj, i )
        Cba_NtkSetMap( p, Cba_ObjName(p, iObj), Cba_ObjFon0(p, iObj) );

    // map wire names into their rangeID
    Vec_IntForEachEntryTwo( &pNtk->vWires, &pNtk->vWiresR, NameId, RangeId, i )
        Cba_NtkSetMap( p, NameId, -RangeId );
    Vec_IntForEachEntryTwo( &pNtk->vOutputs, &pNtk->vOutputsR, NameId, RangeId, i )
        Cba_NtkSetMap( p, NameId, -RangeId );

    // collect RAMs and create boxes
    vAllRams = Prs_CreateDetectRams( pNtk );
    if ( vAllRams )
    Vec_PtrForEachEntry( Vec_Ptr_t *, vAllRams, vRam, i )
    {
        char * pRamName = (char *)Vec_PtrEntry( vRam, 0 );
        int MemSize = Abc_Ptr2Int( (char *)Vec_PtrEntry( vRam, 1 ) );
        //char Buffer[1000]; sprintf( Buffer, "%s_box", pRamName );
        //NameId = Cba_NtkNewStrId( p, Buffer ); 
        NameId = Cba_NtkNewStrId( p, "%s_box", pRamName );
        // create RAM object
        iObj = Cba_ObjAlloc( p, CBA_BOX_RAMBOX, Vec_PtrSize(vRam)-2, 1 );
        Cba_ObjSetName( p, iObj, NameId );
        iFon = Cba_ObjFon0(p, iObj);
        NameId = Cba_NtkNewStrId( p, pRamName ); 
        Cba_FonSetName( p, iFon, NameId );
        Prs_CreateRange( p, iFon, NameId );
        assert( Cba_FonLeft(p, iFon) <= MemSize-1 );
        assert( Cba_FonRight(p, iFon) == 0 );
        //Cba_VerificSaveLineFile( p, iObj, pNet->Linefile() );
        // create write ports feeding into this object
        Vec_PtrForEachEntryStart( Vec_Int_t *, vRam, vBox, k, 2 )
        {
            int iObjNew = Cba_ObjAlloc( p, CBA_BOX_RAMWC, 4, 1 );
            int Line = Vec_IntPop( vBox );
            Vec_IntWriteEntry( vBox2Obj, Line, iObjNew );
            if ( Prs_BoxName(pNtk, Line) )
                Cba_ObjSetName( p, iObjNew, Prs_BoxName(pNtk, Line) );
            //Cba_VerificSaveLineFile( p, iObjNew, pInst->Linefile() );
            // connect output
            iFon = Cba_ObjFon0(p, iObjNew);
            Cba_FonSetRange( p, iFon, Cba_NtkHashRange(p, MemSize-1, 0) );
            //sprintf( Buffer, "%s_wp%d", pRamName, k-2 );
            //NameId = Cba_NtkNewStrId( p, Buffer ); 
            NameId = Cba_NtkNewStrId( p, "%s_wp%d", pRamName, k-2 );
            Cba_FonSetName( p, iFon, NameId );
            Cba_NtkSetMap( p, NameId, iFon );
            // connet to RAM object
            Cba_ObjSetFinFon( p, iObj, (k++)-2, iFon );
            Vec_IntFree( vBox );
        }
        Vec_PtrFree( vRam );
    }
    Vec_PtrFreeP( &vAllRams );

    // create objects
    Vec_IntClear( &p->vArray0 );
    Prs_NtkForEachBox( pNtk, vBox, i )
    {
        if ( Prs_BoxIsNode(pNtk, i) ) // node
        {
            Type = Prs_BoxNtk(pNtk, i);
            iObj = Cba_ObjAlloc( p, (Cba_ObjType_t)Type, Prs_BoxIONum(pNtk, i)-1, Type == CBA_BOX_ADD ? 2 : 1 );
            Prs_CreateSignalOut( p, Cba_ObjFon0(p, iObj), pNtk, Vec_IntEntry(vBox, 1) ); // node output
        }
        else // box
        {
            Cba_Ntk_t * pBox = NULL; int nInputs, nOutputs = 1;
            char ** pOutNames = NULL, * pNtkName = Prs_NtkStr(pNtk, Prs_BoxNtk(pNtk, i));
            Type = Prs_ManFindType( pNtkName, &nInputs, 1, &pOutNames );
            if ( Type == CBA_BOX_RAMWC )
                continue;
            if ( Type == CBA_OBJ_BOX )
            {
                pBox = Cba_ManNtkFind( p->pDesign, pNtkName );
                if ( pBox == NULL )
                {
                    printf( "Fatal error: Cannot find module \"%s\".\n", pNtkName );
                    continue;
                }
                nInputs = Cba_NtkPiNum(pBox);
                nOutputs = Cba_NtkPoNum(pBox);
            }
            else if ( Type == CBA_BOX_ADD || Type == CBA_BOX_DFFCPL )
                nOutputs = 2;
            else if ( Type == CBA_BOX_NMUX )
            {
                if ( !strncmp(pNtkName, "wide_mux_", strlen("wide_mux_")) )
                    nInputs = 1 + (1 << atoi(pNtkName+strlen("wide_mux_")));
                else if ( !strncmp(pNtkName, "Mux_", strlen("Mux_")) )
                    nInputs = 1 + (1 << atoi(pNtkName+strlen("Mux_")));
                else assert( 0 );
            }
            else if ( Type == CBA_BOX_SEL )
            {
                if ( !strncmp(pNtkName, "wide_select_", strlen("wide_select_")) )
                    nInputs = 1 + atoi(pNtkName+strlen("wide_select_"));
                else if ( !strncmp(pNtkName, "Select_", strlen("Select_")) )
                    nInputs = 1 + atoi(pNtkName+strlen("Select_"));
                else assert( 0 );
            }
            else if ( (Type == CBA_BOX_DFFRS || Type == CBA_BOX_LATCHRS) && !strncmp(pNtkName, "wide_", strlen("wide_")) && !Prs_CreateFlopSetReset(p, pNtk, vBox, NULL, NULL, NULL, NULL) )
                nInputs = atoi(pNtkName+strlen(Type == CBA_BOX_DFFRS ? "wide_dffrs_" : "wide_latchrs_")), nOutputs = 1, Type = CBA_BOX_CONCAT;
            // create object
            iObj = Cba_ObjAlloc( p, (Cba_ObjType_t)Type, nInputs, nOutputs );
            if ( pBox ) Cba_ObjSetFunc( p, iObj, Cba_NtkId(pBox) );
            // mark PO objects
            Cba_NtkCleanMap2( p );
            if ( pBox )
                Cba_NtkForEachPo( pBox, iTerm, k )
                    Cba_NtkSetMap2( p, Cba_ObjName(pBox, iTerm), k+1 );
            else
                for ( k = 0; k < nOutputs; k++ )
                    Cba_NtkSetMap2( p, Cba_NtkStrId(p, pOutNames[k]), k+1 );
            // map box fons
            Vec_IntForEachEntryDouble( vBox, FormId, ActId, k )
                if ( Cba_NtkGetMap2(p, FormId) )
                {
                    iFon = Cba_ObjFon(p, iObj, Cba_NtkGetMap2(p, FormId)-1);
                    Prs_CreateSignalOut( p, iFon, pNtk, ActId );
                }
        }
        Vec_IntWriteEntry( vBox2Obj, i, iObj );
        if ( Prs_BoxName(pNtk, i) )
            Cba_ObjSetName( p, iObj, Prs_BoxName(pNtk, i) );
        //Cba_VerificSaveLineFile( p, iObj, pInst->Linefile() );
    }

    // create concatenations for split signals
    if ( Vec_IntSize(&p->vArray0) )
    {
        int Prev = -1, Index = 0;
        Vec_IntSortMulti( &p->vArray0, 3, 0 );
        Vec_IntForEachEntryTriple( &p->vArray0, NameId, RangeId, iFon, i )
        {
            if ( Prev != -1 && Prev != NameId )
                Prs_CreateOutConcat( p, Vec_IntArray(&p->vArray0) + Index, (i - Index)/3 ), Index = i;
            Prev = NameId;         
        }
        Prs_CreateOutConcat( p, Vec_IntArray(&p->vArray0) + Index, (i - Index)/3 ), Index = i;
        //Cba_VerificSaveLineFile( p, iObj, pInst->Linefile() );
    }

    // connect objects
    Prs_NtkForEachBox( pNtk, vBox, i )
    {
        iObj = Vec_IntEntry( vBox2Obj, i );
        if ( Prs_BoxIsNode(pNtk, i) ) // node
        {
            Type = Prs_BoxNtk(pNtk, i);
            Vec_IntForEachEntryDoubleStart( vBox, FormId, ActId, k, 2 )
            {
                iFon = Prs_CreateSignalIn( p, pNtk, ActId );
                if ( iFon )
                    Cba_ObjSetFinFon( p, iObj, k/2-1, iFon ); 
            }
        }
        else // box
        {
            int nInputs = -1;
            char ** pInNames = NULL, * pNtkName = Prs_NtkStr(pNtk, Prs_BoxNtk(pNtk, i));
            Type = Prs_ManFindType( pNtkName, &nInputs, 0, &pInNames );
            if ( (Type == CBA_BOX_DFFRS || Type == CBA_BOX_LATCHRS) && !strncmp(pNtkName, "wide_", strlen("wide_")) )
            {
                int IndexSet = -1, IndexRst = -1,  iBitSet = -1, iBitRst = -1;
                int Status = Prs_CreateFlopSetReset( p, pNtk, vBox, &IndexSet, &IndexRst, &iBitSet, &iBitRst );
                if ( Status )
                {
                    Vec_IntWriteEntry( vBox, IndexSet, iBitSet );
                    Vec_IntWriteEntry( vBox, IndexRst, iBitRst );
                    // updated box should be fine
                }
                else
                {
                    int w, Width = atoi( pNtkName + strlen(Type == CBA_BOX_DFFRS ? "wide_dffrs_" : "wide_latchrs_") );
                    assert( Cba_ObjType(p, iObj) == CBA_BOX_CONCAT );
                    // prepare inputs
                    assert( nInputs >= 0 );
                    Cba_NtkCleanMap2( p );
                    for ( k = 0; k < nInputs; k++ )
                        Cba_NtkSetMap2( p, Cba_NtkStrId(p, pInNames[k]), k+1 );
                    // create bit-level objects
                    for ( w = 0; w < Width; w++ )
                    {
                        // create bit-level flop
                        int iObjNew = Cba_ObjAlloc( p, (Cba_ObjType_t)Type, 4, 1 );
                        if ( Prs_BoxName(pNtk, i) )
                        {
                            NameId = Cba_NtkNewStrId( p, "%s[%d]", Prs_NtkStr(pNtk, Prs_BoxName(pNtk, i)), w );
                            Cba_ObjSetName( p, iObjNew, NameId );
                        }
                        //Cba_VerificSaveLineFile( p, iObjNew, pInst->Linefile() );
                        // set output fon
                        iFon = Cba_ObjFon0(p, iObjNew);
                        {
                            NameId = Cba_NtkNewStrId( p, "%s[%d]", Cba_FonNameStr(p, Cba_ObjFon0(p, iObj)), w );
                            Cba_FonSetName( p, iFon, NameId );
                        }
                        // no need to map this name because it may be produced elsewhere
                        //Cba_NtkSetMap( p, NameId, iFon );
                        // add the flop
                        Cba_ObjSetFinFon( p, iObj, Width-1-w, iFon );
                        // create bit-level flops
                        Vec_IntForEachEntryDouble( vBox, FormId, ActId, k )
                            if ( Cba_NtkGetMap2(p, FormId) )
                            {
                                int Index = Cba_NtkGetMap2(p, FormId)-1;
                                iFon = Prs_CreateSignalIn( p, pNtk, ActId );  assert( iFon );
                                // create bit-select node for data/set/reset (but not for clock)
                                if ( Index < 3 ) // not clock
                                    iFon = Prs_CreateSlice( p, iFon, pNtk, 0 );
                                Cba_ObjSetFinFon( p, iObjNew, Index, iFon );
                            }
                    }
                    continue;
                }
            }
            assert( Type == Cba_ObjType(p, iObj) );
            //assert( nInputs == -1 || nInputs == Cba_ObjFinNum(p, iObj) );
            // mark PI objects
            Cba_NtkCleanMap2( p );
            if ( Type == CBA_OBJ_BOX )
            {
                Cba_Ntk_t * pBox = Cba_ObjNtk(p, iObj);
                assert( Cba_NtkPiNum(pBox) == Cba_ObjFinNum(p, iObj) );
                assert( Cba_NtkPoNum(pBox) == Cba_ObjFonNum(p, iObj) );
                Cba_NtkForEachPi( pBox, iTerm, k )
                    Cba_NtkSetMap2( p, Cba_ObjName(pBox, iTerm), k+1 );
            }
            else
            {
                assert( nInputs >= 0 );
                for ( k = 0; k < nInputs; k++ )
                    Cba_NtkSetMap2( p, Cba_NtkStrId(p, pInNames[k]), k+1 );
            }
            // connect box fins
            Vec_IntForEachEntryDouble( vBox, FormId, ActId, k )
                if ( Cba_NtkGetMap2(p, FormId) )
                {
                    int Index = Cba_NtkGetMap2(p, FormId)-1;
                    int nBits = Cba_ObjFinNum(p, iObj);
                    assert( Index < nBits );
                    iFon = Prs_CreateSignalIn( p, pNtk, ActId );
                    if ( iFon )
                        Cba_ObjSetFinFon( p, iObj, Index, iFon );
                }
            // special cases
            if ( Type == CBA_BOX_NMUX || Type == CBA_BOX_SEL )
            {
                int FonCat = Cba_ObjFinFon( p, iObj, 1 );
                int nBits  = Cba_FonRangeSize( p, FonCat );
                int nParts = Cba_ObjFinNum(p, iObj) - 1;
                int Slice  = nBits / nParts;
                int nFins = Cba_ObjFinNum(p, iObj);
                assert( Cba_ObjFinNum(p, iObj) >= 2 );
                assert( Slice * nParts == nBits );
                assert( nFins == 1 + nParts );
                Cba_ObjCleanFinFon( p, iObj, 1 );
                // create buffer for the constant
                if ( FonCat < 0 ) 
                {
                    int iObjNew = Cba_ObjAlloc( p, CBA_BOX_BUF, 1, 1 );
                    Cba_ObjSetFinFon( p, iObjNew, 0, FonCat );
                    FonCat = Cba_ObjFon0( p, iObjNew );
                    NameId = Cba_NtkNewStrId( p, "_buf_const_%d", iObjNew );
                    Cba_FonSetName( p, FonCat, NameId );
                    Cba_FonSetRange( p, FonCat, Cba_NtkHashRange(p, nBits-1, 0) );
                }
                for ( k = 0; k < nParts; k++ )
                {
//                    iFon = Prs_CreateSlice( p, FonCat, pNtk, Cba_NtkHashRange(p, (nParts-1-k)*Slice+Slice-1, (nParts-1-k)*Slice) );
                    iFon = Prs_CreateSlice( p, FonCat, pNtk, Cba_NtkHashRange(p, k*Slice+Slice-1, k*Slice) );
                    Cba_ObjSetFinFon( p, iObj, k+1, iFon );
                }
            }
        }
        // if carry-in is not supplied, use constant 0
        if ( Type == CBA_BOX_ADD && Cba_ObjFinFon(p, iObj, 0) == 0 )
            Cba_ObjSetFinFon( p, iObj, 0, Cba_FonFromConst(1) );
        // if set or reset are not supplied, use constant 0
        if ( Type == CBA_BOX_DFFRS && Cba_ObjFinFon(p, iObj, 1) == 0 )
            Cba_ObjSetFinFon( p, iObj, 1, Cba_FonFromConst(1) );
        if ( Type == CBA_BOX_DFFRS && Cba_ObjFinFon(p, iObj, 2) == 0 )
            Cba_ObjSetFinFon( p, iObj, 2, Cba_FonFromConst(1) );
    }
    Vec_IntFree( vBox2Obj );
    // connect outputs
    Vec_IntForEachEntryTwo( &pNtk->vOutputs, &pNtk->vOutputsR, NameId, RangeId, i )
    {
        iObj = Cba_NtkPo( p, i );
        assert( NameId == Cba_ObjName(p, iObj) ); // direct name
        iFon = Prs_CreateVerilogFindFon( p, NameId );
        if ( !iFon ) 
            continue;
        Cba_ObjSetFinFon( p, iObj, 0, iFon );
        if ( RangeId )
        {
            assert( Cba_NtkRangeLeft(p, Abc_Lit2Var(RangeId))  == Cba_FonLeft(p, iFon) );
            assert( Cba_NtkRangeRight(p, Abc_Lit2Var(RangeId)) == Cba_FonRight(p, iFon) );
        }
    }
    return 0;
}
Cba_Man_t * Prs_ManBuildCbaVerilog( char * pFileName, Vec_Ptr_t * vDes )
{
    Prs_Ntk_t * pPrsNtk; int i, fError = 0;
    Prs_Ntk_t * pPrsRoot = Prs_ManRoot(vDes);
    // start the manager
    Abc_Nam_t * pStrs = Abc_NamRef(pPrsRoot->pStrs);
    Abc_Nam_t * pFuns = Abc_NamRef(pPrsRoot->pFuns);
    Abc_Nam_t * pMods = Abc_NamStart( 100, 24 );
    Cba_Man_t * p = Cba_ManAlloc( pFileName, Vec_PtrSize(vDes), pStrs, pFuns, pMods, Hash_IntManRef(pPrsRoot->vHash) );
    // initialize networks
    Vec_PtrForEachEntry( Prs_Ntk_t *, vDes, pPrsNtk, i )
    {
        Cba_Ntk_t * pNtk = Cba_NtkAlloc( p, Prs_NtkId(pPrsNtk), Prs_NtkPiNum(pPrsNtk), Prs_NtkPoNum(pPrsNtk), Prs_NtkObjNum(pPrsNtk), 100, 100 );
        Prs_CreateVerilogPio( pNtk, pPrsNtk );
        Cba_NtkAdd( p, pNtk );
    }
    // create networks
    Vec_PtrForEachEntry( Prs_Ntk_t *, vDes, pPrsNtk, i )
    {
        printf( "Building module \"%s\"...\n", Prs_NtkName(pPrsNtk) );
        fError = Prs_CreateVerilogNtk( Cba_ManNtk(p, i+1), pPrsNtk );
        if ( fError )
            break;
    }
    if ( fError )
        printf( "Quitting because of errors.\n" );
    else
        Cba_ManPrepareSeq( p );
    return p;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Cba_Man_t * Cba_ManReadVerilog( char * pFileName )
{
    Cba_Man_t * p = NULL;
    Vec_Ptr_t * vDes = Prs_ManReadVerilog( pFileName );
    if ( vDes && Vec_PtrSize(vDes) )
        p = Prs_ManBuildCbaVerilog( pFileName, vDes );
    if ( vDes )
        Prs_ManVecFree( vDes );
    return p;
}

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


ABC_NAMESPACE_IMPL_END

