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

  FileName    [cbaWriteVer.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Hierarchical word-level netlist.]

  Synopsis    [Verilog writer.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "cba.h"
#include "cbaPrs.h"
#include "map/mio/mio.h"
#include "base/main/main.h"

ABC_NAMESPACE_IMPL_START

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

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

/**Function*************************************************************
  
  Synopsis    []  
  
  Description []  
                 
  SideEffects []  
  
  SeeAlso     []  
  
***********************************************************************/
void Cba_ManCreatePrimMap( char ** pMap )
{
    memset( pMap, 0, sizeof(char *) * CBA_BOX_LAST );

    pMap[ CBA_BOX_SLICE  ] = "sli";
    pMap[ CBA_BOX_CONCAT ] = "icc";

    pMap[ CBA_BOX_BUF    ] = "";
    pMap[ CBA_BOX_INV    ] = "~";
    pMap[ CBA_BOX_AND    ] = "&"; 
    pMap[ CBA_BOX_NAND   ] = "&"; 
    pMap[ CBA_BOX_OR     ] = "|"; 
    pMap[ CBA_BOX_NOR    ] = "|"; 
    pMap[ CBA_BOX_XOR    ] = "^"; 
    pMap[ CBA_BOX_XNOR   ] = "^"; 
    pMap[ CBA_BOX_SHARP  ] = "&"; 
    pMap[ CBA_BOX_SHARPL ] = "&"; 
    pMap[ CBA_BOX_MUX    ] = "?"; 
    pMap[ CBA_BOX_MAJ    ] = "maj"; 
    pMap[ CBA_BOX_RAND   ] = "&"; 
    pMap[ CBA_BOX_RNAND  ] = "~&"; 
    pMap[ CBA_BOX_ROR    ] = "|"; 
    pMap[ CBA_BOX_RNOR   ] = "~|"; 
    pMap[ CBA_BOX_RXOR   ] = "^"; 
    pMap[ CBA_BOX_RXNOR  ] = "~^"; 
    pMap[ CBA_BOX_LNOT   ] = "!"; 
    pMap[ CBA_BOX_LAND   ] = "&&"; 
    pMap[ CBA_BOX_LNAND  ] = "logic nand"; 
    pMap[ CBA_BOX_LOR    ] = "||"; 
    pMap[ CBA_BOX_LNOR   ] = "logic nor"; 
    pMap[ CBA_BOX_LXOR   ] = "^^"; 
    pMap[ CBA_BOX_LXNOR  ] = "logic xnor"; 
    pMap[ CBA_BOX_NMUX   ] = "nmux"; 
    pMap[ CBA_BOX_SEL    ] = "sel"; 
    pMap[ CBA_BOX_PSEL   ] = "prio-select"; 
    pMap[ CBA_BOX_ENC    ] = "enc"; 
    pMap[ CBA_BOX_PENC   ] = "prio-enc"; 
    pMap[ CBA_BOX_DEC    ] = "dec"; 
    pMap[ CBA_BOX_EDEC   ] = "enable-dec"; 
    pMap[ CBA_BOX_ADD    ] = "+"; 
    pMap[ CBA_BOX_SUB    ] = "-"; 
    pMap[ CBA_BOX_MUL    ] = "*"; 
    pMap[ CBA_BOX_DIV    ] = "/"; 
    pMap[ CBA_BOX_MOD    ] = "%"; 
    pMap[ CBA_BOX_REM    ] = "%"; 
    pMap[ CBA_BOX_POW    ] = "**"; 
    pMap[ CBA_BOX_MIN    ] = "-"; 
    pMap[ CBA_BOX_SQRT   ] = "@"; 
    pMap[ CBA_BOX_ABS    ] = "abs"; 
    pMap[ CBA_BOX_LTHAN  ] = "<"; 
    pMap[ CBA_BOX_LETHAN ] = "<="; 
    pMap[ CBA_BOX_METHAN ] = ">="; 
    pMap[ CBA_BOX_MTHAN  ] = ">"; 
    pMap[ CBA_BOX_EQU    ] = "=="; 
    pMap[ CBA_BOX_NEQU   ] = "!="; 
    pMap[ CBA_BOX_SHIL   ] = "<<"; 
    pMap[ CBA_BOX_SHIR   ] = ">>"; 
    pMap[ CBA_BOX_SHILA  ] = "<<<"; 
    pMap[ CBA_BOX_SHIRA  ] = ">>>"; 
    pMap[ CBA_BOX_ROTL   ] = "rotL"; 
    pMap[ CBA_BOX_ROTR   ] = "rotR"; 

    pMap[ CBA_BOX_TRI    ] = "tri";
    pMap[ CBA_BOX_RAM    ] = "ram";
    pMap[ CBA_BOX_RAMR   ] = "ramR";
    pMap[ CBA_BOX_RAMW   ] = "ramW";
    pMap[ CBA_BOX_RAMWC  ] = "ramWC";
    pMap[ CBA_BOX_RAMBOX ] = "ramBox";

    pMap[ CBA_BOX_LATCH  ] = "lat";
    pMap[ CBA_BOX_LATCHRS] = "latrs";
    pMap[ CBA_BOX_DFF    ] = "dff";
    pMap[ CBA_BOX_DFFRS  ] = "dffrs";
}

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

  Synopsis    [Writing parser state into a file.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline int Prs_NameIsLegalInVerilog( char * pName, int NameId )
{
    // identifier ::= simple_identifier | escaped_identifier
    // simple_identifier ::= [a-zA-Z_][a-zA-Z0-9_$]
    // escaped_identifier ::= \ {Any_ASCII_character_except_white_space} white_space
    // white_space ::= space | tab | newline
    assert( pName != NULL && *pName != '\0' );
    if ( *pName == '\\' )
        return 1;
    if ( NameId < 13 ) // see PRS_VER_UNKNOWN in cbaReadVer.c
        return 0;
    if ( (*pName < 'a' || *pName > 'z') && (*pName < 'A' || *pName > 'Z') && *pName != '_' )
        return 0;
    while ( *(++pName) )
        if ( (*pName < 'a' || *pName > 'z') && (*pName < 'A' || *pName > 'Z') && (*pName < '0' || *pName > '9') && *pName != '_' && *pName != '$' ) 
            return 0;
    return 1;
}
char * Prs_ObjGetName( Prs_Ntk_t * p, int NameId )
{
    char * pName = Prs_NtkStr(p, NameId);
    if ( pName == NULL )
        return pName;
    if ( Prs_NameIsLegalInVerilog(pName, NameId) )
        return pName;
    return Vec_StrPrintF( Abc_NamBuffer(p->pStrs), "\\%s ", pName );
}
static inline char * Prs_ManWriteRange( Prs_Ntk_t * p, int RangeId, int fSlice )
{
    int Left  = RangeId ? Hash_IntObjData0( p->vHash, RangeId ) : 0;
    int Right = RangeId ? Hash_IntObjData1( p->vHash, RangeId ) : 0;
    if ( Left == Right && fSlice )
        return Vec_StrPrintF( Abc_NamBuffer(p->pStrs), "[%d]", Right );
    else
        return Vec_StrPrintF( Abc_NamBuffer(p->pStrs), "[%d:%d]", Left, Right );
}
static void Prs_ManWriteVerilogConcat( FILE * pFile, Prs_Ntk_t * p, int Con )
{
    extern void Prs_ManWriteVerilogArray( FILE * pFile, Prs_Ntk_t * p, Vec_Int_t * vSigs, int fOdd );
    Vec_Int_t * vSigs = Prs_CatSignals(p, Con);
    fprintf( pFile, "{" );
    Prs_ManWriteVerilogArray( pFile, p, vSigs, 0 );
    fprintf( pFile, "}" );
}
static void Prs_ManWriteVerilogSignal( FILE * pFile, Prs_Ntk_t * p, int Sig )
{
    int Value = Abc_Lit2Var2( Sig );
    Prs_ManType_t Type = (Prs_ManType_t)Abc_Lit2Att2( Sig );
    if ( Type == CBA_PRS_NAME )
        fprintf( pFile, "%s", Prs_ObjGetName(p, Value) );
    else if ( Type == CBA_PRS_CONST )
        fprintf( pFile, "%s", Prs_NtkConst(p, Value) );
    else if ( Type == CBA_PRS_SLICE )
        fprintf( pFile, "%s%s", Prs_ObjGetName(p, Prs_SliceName(p, Value)), Prs_ManWriteRange(p, Prs_SliceRange(p, Value), 1) );
    else if ( Type == CBA_PRS_CONCAT )
        Prs_ManWriteVerilogConcat( pFile, p, Value );
    else assert( 0 );
}
void Prs_ManWriteVerilogArray( FILE * pFile, Prs_Ntk_t * p, Vec_Int_t * vSigs, int fOdd )
{
    int i, Sig, fFirst = 1;
    assert( Vec_IntSize(vSigs) > 0 );
    Vec_IntForEachEntry( vSigs, Sig, i )
    {
        if ( fOdd && !(i & 1) )
            continue;
        fprintf( pFile, "%s", fFirst ? "" : ", " );
        Prs_ManWriteVerilogSignal( pFile, p, Sig );
        fFirst = 0;
    }
}
static void Prs_ManWriteVerilogArray2( FILE * pFile, Prs_Ntk_t * p, Vec_Int_t * vSigs )
{
    int i, FormId, ActSig;
    assert( Vec_IntSize(vSigs) % 2 == 0 );
    Vec_IntForEachEntryDouble( vSigs, FormId, ActSig, i )
    {
        fprintf( pFile, "." );
        fprintf( pFile, "%s", Prs_ObjGetName(p, FormId) );
        fprintf( pFile, "(" );
        Prs_ManWriteVerilogSignal( pFile, p, ActSig );
        fprintf( pFile, ")%s", (i == Vec_IntSize(vSigs) - 2) ? "" : ", " );
    }
}
static void Prs_ManWriteVerilogMux( FILE * pFile, Prs_Ntk_t * p, Vec_Int_t * vSigs )
{
    int i, FormId, ActSig;
    char * pStrs[4] = { " = ", " ? ", " : ", ";\n" };
    assert( Vec_IntSize(vSigs) == 8 );
    fprintf( pFile, "  assign " );
    Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vSigs, 1) );
    fprintf( pFile, "%s", pStrs[0] );
    Vec_IntForEachEntryDoubleStart( vSigs, FormId, ActSig, i, 2 )
    {
        Prs_ManWriteVerilogSignal( pFile, p, ActSig );
        fprintf( pFile, "%s", pStrs[i/2] );
    }
}
static void Prs_ManWriteVerilogBoxes( FILE * pFile, Prs_Ntk_t * p, char ** pTypeNames )
{
    Vec_Int_t * vBox; int i, k;
    Prs_NtkForEachBox( p, vBox, i )
    {
        Cba_ObjType_t NtkId = Prs_BoxNtk(p, i);
        //char * pNtkName = Prs_ObjGetName(p, Prs_BoxName(p, i));
        if ( NtkId == CBA_BOX_MUX && Prs_BoxIsNode(p, i) )
            Prs_ManWriteVerilogMux( pFile, p, vBox );
        else if ( Prs_BoxIsNode(p, i) ) // node
        {
            fprintf( pFile, "  assign " );
            Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, 1) );
            fprintf( pFile, " = " );
            if ( Cba_TypeIsUnary(NtkId) )
            {
                fprintf( pFile, "%s", pTypeNames[NtkId] );
                Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, 3) );
            }
            else if ( NtkId == CBA_BOX_NMUX )
            {
                Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, 3) );
                fprintf( pFile, " ? " );
                for ( k = 5; k < Vec_IntSize(vBox); k += 2 )
                {
                    if ( k > 5 ) fprintf( pFile, " : " );
                    Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, k) );
                }
            }
            else if ( NtkId == CBA_BOX_ADD )
            {
                if ( Vec_IntEntry(vBox, 3) )
                {
                    Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, 3) );
                    fprintf( pFile, " %s ", pTypeNames[NtkId] );
                }
                Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, 5) );
                fprintf( pFile, " %s ", pTypeNames[NtkId] );
                Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, 7) );
            }
            else
            {
                Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, 3) );
                fprintf( pFile, " %s ", pTypeNames[NtkId] );
                Prs_ManWriteVerilogSignal( pFile, p, Vec_IntEntry(vBox, 5) );
            }
            fprintf( pFile, ";\n" );
        }
        else // box
        {
            fprintf( pFile, "  %s %s ( ", Prs_ObjGetName(p, NtkId), Prs_BoxName(p, i) ? Prs_ObjGetName(p, Prs_BoxName(p, i)) : "" );
            Prs_ManWriteVerilogArray2( pFile, p, vBox );
            fprintf( pFile, " );\n" );
        }
    }
}
static void Prs_ManWriteVerilogIos( FILE * pFile, Prs_Ntk_t * p, int SigType )
{
    int NameId, RangeId, i;
    char * pSigNames[4]   = { "inout", "input", "output", "wire" }; 
    Vec_Int_t * vSigs[4]  = { &p->vInouts,  &p->vInputs,  &p->vOutputs,  &p->vWires };
    Vec_Int_t * vSigsR[4] = { &p->vInoutsR, &p->vInputsR, &p->vOutputsR, &p->vWiresR };
    if ( SigType == 3 )
        fprintf( pFile, "\n" );
    Vec_IntForEachEntryTwo( vSigs[SigType], vSigsR[SigType], NameId, RangeId, i )
    {
        fprintf( pFile, "  %s %s%s", pSigNames[SigType], Abc_LitIsCompl(RangeId) ? "signed " : "", RangeId ? Prs_ManWriteRange(p, Abc_Lit2Var(RangeId), 0) : "" );
        fprintf( pFile, "%s;\n", Prs_ObjGetName(p, NameId) );
    }
}
static void Prs_ManWriteVerilogIoOrder( FILE * pFile, Prs_Ntk_t * p, Vec_Int_t * vOrder )
{
    int i, NameId;
    Vec_IntForEachEntry( vOrder, NameId, i )
        fprintf( pFile, "%s%s", Prs_ObjGetName(p, Abc_Lit2Var2(NameId)), i == Vec_IntSize(vOrder) - 1 ? "" : ", " );
}
static void Prs_ManWriteVerilogNtk( FILE * pFile, Prs_Ntk_t * p, char ** pTypeNames )
{
    int s;
    // write header
    fprintf( pFile, "module %s (\n    ", Prs_ObjGetName(p, p->iModuleName) );
    Prs_ManWriteVerilogIoOrder( pFile, p, &p->vOrder );
    fprintf( pFile, "\n  );\n" );
    // write declarations
    for ( s = 0; s < 4; s++ )
        Prs_ManWriteVerilogIos( pFile, p, s );
    fprintf( pFile, "\n" );
    // write objects
    Prs_ManWriteVerilogBoxes( pFile, p, pTypeNames );
    fprintf( pFile, "endmodule\n\n" );
}
void Prs_ManWriteVerilog( char * pFileName, Vec_Ptr_t * vPrs )
{
    char * pTypeNames[CBA_BOX_LAST];
    Prs_Ntk_t * pNtk = Prs_ManRoot(vPrs); int i;
    FILE * pFile = fopen( pFileName, "wb" );
    if ( pFile == NULL )
    {
        printf( "Cannot open output file \"%s\".\n", pFileName );
        return;
    }
    Cba_ManCreatePrimMap( pTypeNames );
    fprintf( pFile, "// Design \"%s\" written by ABC on %s\n\n", Prs_NtkStr(pNtk, pNtk->iModuleName), Extra_TimeStamp() );
    Vec_PtrForEachEntry( Prs_Ntk_t *, vPrs, pNtk, i )
        Prs_ManWriteVerilogNtk( pFile, pNtk, pTypeNames );
    fclose( pFile );
}





static inline int Cba_NameIsLegalInVerilog( char * pName, int NameId )
{
    // identifier ::= simple_identifier | escaped_identifier
    // simple_identifier ::= [a-zA-Z_][a-zA-Z0-9_$]
    // escaped_identifier ::= \ {Any_ASCII_character_except_white_space} white_space
    // white_space ::= space | tab | newline
    assert( pName != NULL && *pName != '\0' );
    if ( *pName == '\\' )
        return 1;
    if ( NameId < 13 ) // see PRS_VER_UNKNOWN in cbaReadVer.c
        return 0;
    if ( (*pName < 'a' || *pName > 'z') && (*pName < 'A' || *pName > 'Z') && *pName != '_' )
        return 0;
    while ( *(++pName) )
        if ( (*pName < 'a' || *pName > 'z') && (*pName < 'A' || *pName > 'Z') && (*pName < '0' || *pName > '9') && *pName != '_' && *pName != '$' ) 
            return 0;
    return 1;
}
char * Cba_ObjGetName( Cba_Ntk_t * p, int i )
{
    char * pName = Cba_ObjNameStr(p, i);
    if ( pName == NULL )
        return pName;
    if ( Cba_NameIsLegalInVerilog(pName, Cba_ObjName(p, i)) )
        return pName;
    return Vec_StrPrintF( Abc_NamBuffer(Cba_NtkNam(p)), "\\%s ", pName );
}
char * Cba_FonGetName( Cba_Ntk_t * p, int i )
{
    char * pName = Cba_FonNameStr(p, i);
    if ( pName == NULL )
        return pName;
    if ( Cba_ObjType(p, Cba_FonObj(p, i)) == CBA_BOX_SLICE )
        return pName;
    if ( Cba_NameIsLegalInVerilog(pName, Cba_FonName(p, i)) )
        return pName;
    return Vec_StrPrintF( Abc_NamBuffer(Cba_NtkNam(p)), "\\%s ", pName );
}
char * Cba_ManGetSliceName( Cba_Ntk_t * p, int iFon, int RangeId )
{
    int Left  = Cba_NtkRangeLeft(p, RangeId);
    int Right = Cba_NtkRangeRight(p, RangeId);
    char * pName = Cba_FonNameStr(p, iFon);
    if ( Cba_NameIsLegalInVerilog(pName, Cba_FonName(p, iFon)) )
        if ( Left == Right )
            return Vec_StrPrintF( Abc_NamBuffer(Cba_NtkNam(p)), "%s[%d]", pName, Right );
        else
            return Vec_StrPrintF( Abc_NamBuffer(Cba_NtkNam(p)), "%s[%d:%d]", pName, Left, Right );
    else
        if ( Left == Right )
            return Vec_StrPrintF( Abc_NamBuffer(Cba_NtkNam(p)), "\\%s [%d]", pName, Right );
        else
            return Vec_StrPrintF( Abc_NamBuffer(Cba_NtkNam(p)), "\\%s [%d:%d]", pName, Left, Right );
}

void Cba_ManWriteFonRange( Cba_Ntk_t * p, int iFon )
{
    Vec_Str_t * vStr = &p->pDesign->vOut;
    if ( !iFon || Cba_FonIsConst(iFon) || (Cba_FonRangeSize(p, iFon) == 1 && Cba_FonRight(p, iFon) == 0) )
        return;
    if ( Cba_FonSigned(p, iFon) )
        Vec_StrPrintF( vStr, "signed " );
    Vec_StrPrintF( vStr, "[%d:%d] ", Cba_FonLeft(p, iFon), Cba_FonRight(p, iFon) );
}
void Cba_ManWriteFonName( Cba_Ntk_t * p, int iFon, int fInlineConcat, int fInput )
{
    extern void Cba_ManWriteConcat( Cba_Ntk_t * p, int iObj );
    Vec_Str_t * vStr = &p->pDesign->vOut;
    if ( !iFon || (!Cba_FonIsConst(iFon) && !Cba_FonName(p, iFon)) ) 
        Vec_StrPrintF( vStr, "Open_%d", Cba_NtkMan(p)->nOpens++ );
//        Vec_StrPrintF( vStr, "1\'b0" );
    else if ( fInlineConcat && !Cba_FonIsConst(iFon) && Cba_ObjIsConcat(p, Cba_FonObj(p, iFon)) )
        Cba_ManWriteConcat( p, Cba_FonObj(p, iFon) );
    else
    {
        int Range = fInput ? Cba_FonRangeSize( p, iFon ) : 0;
        if ( fInput && Range > 1 )
            Vec_StrPush( vStr, '{' );
        Vec_StrPrintStr( vStr, Cba_FonIsConst(iFon) ? Cba_NtkConst(p, Cba_FonConst(iFon)) : Cba_FonGetName(p, iFon) );
        if ( fInput && Range > 1 )
            Vec_StrPush( vStr, '}' );
    }
}
void Cba_ManWriteConcat( Cba_Ntk_t * p, int iObj )
{
    int i, iFin, iFon;
    Vec_Str_t * vStr = &p->pDesign->vOut;
    assert( Cba_ObjIsConcat(p, iObj) );
    Vec_StrPush( vStr, '{' );
    Cba_ObjForEachFinFon( p, iObj, iFin, iFon, i )
    {
        Vec_StrPrintStr( vStr, i ? ", " : "" );
        Cba_ManWriteFonName( p, iFon, 1, 0 );
    }
    Vec_StrPush( vStr, '}' );
}
int Cba_ManWriteLineFile( Cba_Ntk_t * p, int iObj, int FileAttr, int LineAttr )
{
    Vec_Str_t * vStr = &p->pDesign->vOut;
    int FileId = 0, LineId = 0;
    if ( FileAttr && (FileId = Cba_ObjAttrValue(p, iObj, FileAttr)) )
    {
        LineId = Cba_ObjAttrValue(p, iObj, LineAttr);
        Vec_StrPrintF( vStr, "  // %s(%d)", Cba_NtkStr(p, FileId), LineId );
        return 1;
    }
    return 0;
}
void Cba_ManWriteVerilogNtk( Cba_Ntk_t * p, int fInlineConcat )
{
    Vec_Str_t * vStr = &p->pDesign->vOut;
    int i, k, iObj, iFin, iFon, StartPos, Status;
    int FileAttr = Cba_NtkStrId( p, "file" );
    int LineAttr = Cba_NtkStrId( p, "line" );
    int fUseNewLine = (int)(Cba_NtkPioNum(p) > 5);
    // mark PO fons
    Vec_Bit_t * vPoFons = Vec_BitStart( Cba_NtkFonNum(p)+1 );
    Cba_NtkForEachPoDriverFon( p, iObj, iFon, i )
        if ( Cba_FonIsReal(iFon) && Cba_FonName(p, iFon) == Cba_ObjName(p, iObj) )
            Vec_BitWriteEntry( vPoFons, iFon, 1 );
    // write header
    Vec_StrPrintStr( vStr, "module " );
    Vec_StrPrintStr( vStr, Cba_NtkName(p) );
    Vec_StrPrintStr( vStr, fUseNewLine ? " (\n    " : " ( " );
    StartPos = Vec_StrSize(vStr);
    Cba_NtkForEachPioOrder( p, iObj, i )
    {
        Vec_StrPrintStr( vStr, i ? ", " : "" );
        if ( Vec_StrSize(vStr) > StartPos + 70 )
        {
            StartPos = Vec_StrSize(vStr);
            Vec_StrPrintStr( vStr, "\n    " );
        }
        Vec_StrPrintStr( vStr, Cba_ObjGetName(p, iObj) );
    }
    Vec_StrPrintStr( vStr, fUseNewLine ? "\n  );" : " );" );
    Cba_ManWriteLineFile( p, 0, FileAttr, LineAttr );
    Vec_StrPrintStr( vStr, fUseNewLine ? "\n" : "\n\n" );
    // write inputs/outputs
    Cba_NtkForEachPioOrder( p, iObj, i )
    {
        int Offset = Vec_StrSize(vStr);
        Vec_StrPrintStr( vStr, "  " );
        Vec_StrPrintStr( vStr, Cba_ObjIsPi(p, iObj) ? "input " : "output " );
        Cba_ManWriteFonRange( p, Cba_ObjIsPi(p, iObj) ? Cba_ObjFon0(p, iObj) : Cba_ObjFinFon(p, iObj, 0) );
        Vec_StrPrintStr( vStr, Cba_ObjGetName(p, iObj) );
        Vec_StrPrintF( vStr, ";%*s", Offset + 40 - Vec_StrSize(vStr), "" );
        Cba_ManWriteLineFile( p, iObj, FileAttr, LineAttr );
        Vec_StrPush( vStr, '\n' );
    }
    Vec_StrPrintStr( vStr, "\n" );
    // write objects
    Cba_NtkForEachBox( p, iObj )
    {
//        char * pNameNtk = Cba_NtkName(p);
//        char * pNameInst = Cba_ObjGetName(p, iObj);
        int Type = Cba_ObjType(p, iObj);
        if ( Cba_ObjIsSlice(p, iObj) )
            continue;
        if ( fInlineConcat && Cba_ObjIsConcat(p, iObj) )
            continue;
        if ( Cba_ObjIsBoxUser(p, iObj) )
        {
            Cba_Ntk_t * pNtk = Cba_ObjNtk(p, iObj);
            // write output wire declarations
            Cba_ObjForEachFon( p, iObj, iFon, i )
            {
                if ( Vec_BitEntry(vPoFons, iFon) )
                    continue;
                Vec_StrPrintStr( vStr, "  wire " );
                Cba_ManWriteFonRange( p, iFon );
                Cba_ManWriteFonName( p, iFon, 0, 0 );
                Vec_StrPrintStr( vStr, ";\n" );
            }
            // write box
            Vec_StrPrintStr( vStr, "  " );
            Vec_StrPrintStr( vStr, Cba_NtkName(pNtk) );
            Vec_StrPush( vStr, ' ' );
            if ( Cba_ObjName(p, iObj) )
                Vec_StrPrintF( vStr, "%s ", Cba_ObjGetName(p, iObj) );
            // write input binding
            Vec_StrPrintStr( vStr, "( " );
            Cba_ObjForEachFinFon( p, iObj, iFin, iFon, i )
            {
                Vec_StrPrintF( vStr, "%s.%s(", i ? ", " : "", Cba_ObjGetName(pNtk, Cba_NtkPi(pNtk, i)) );
                Cba_ManWriteFonName( p, iFon, fInlineConcat, 1 );
                Vec_StrPush( vStr, ')' );
            }
            // write output binding
            Cba_ObjForEachFon( p, iObj, iFon, i )
            {
                Vec_StrPrintF( vStr, "%s.%s(", Cba_ObjFinNum(p, iObj) ? ", " : "", Cba_ObjGetName(pNtk, Cba_NtkPo(pNtk, i)) );
                Cba_ManWriteFonName( p, iFon, 0, 1 );
                Vec_StrPush( vStr, ')' );
            }
            Vec_StrPrintStr( vStr, ");" );
        }
        else if ( Type == CBA_BOX_RAMWC || Type == CBA_BOX_RAMBOX || Type == CBA_BOX_RAMR )
        {
            int Num = (Type == CBA_BOX_RAMWC) ? 0 : (Type == CBA_BOX_RAMR ? 1 : 2); // write / read / box
            char * pBoxName[3] = { "RAM_WRITE", "RAM_READ", "RAM_BOX" };
            char * pOutputs[3] = { "ram", "rdata", "out" };
            char * pInputs[3][4] = {  {"clk", "wen", "waddr", "wdata"},  {"ren", "raddr", "ram"},   {"in0", "in1", "in2", "in3"} };
            // write declaration for the output
            int iFonOut = Cba_ObjFon0(p, iObj);
            if ( Vec_BitEntry(vPoFons, iFonOut) ) 
                Vec_StrPrintStr( vStr, "  assign " );
            else
            {
                Vec_StrPrintStr( vStr, "  wire " );
                Cba_ManWriteFonRange( p, iFonOut );
            }
            Cba_ManWriteFonName( p, iFonOut, 0, 0 );
            Vec_StrPrintStr( vStr, ";\n" );
            // write box
            Vec_StrPrintF( vStr, "  %s( ", pBoxName[Num] );
            Cba_ObjForEachFinFon( p, iObj, iFin, iFon, i )
            {
                Vec_StrPrintF( vStr, "%s.%s(", i ? ", " : "", pInputs[Num][i] );
                Cba_ManWriteFonName( p, iFon, fInlineConcat, 1 );
                Vec_StrPush( vStr, ')' );
            }
            Vec_StrPrintF( vStr, "%s.%s(", Cba_ObjFinNum(p, iObj) ? ", " : "", pOutputs[Num] );
            Cba_ManWriteFonName( p, iFonOut, 0, 1 );
            Vec_StrPrintStr( vStr, ") );" );
        }
        else if ( Type == CBA_BOX_NMUX || Type == CBA_BOX_SEL )
        {
            int fUseSel = Type == CBA_BOX_SEL;
            int nBits   = fUseSel ? Cba_ObjFinNum(p, iObj) - 1 : Abc_Base2Log(Cba_ObjFinNum(p, iObj) - 1);
            int iFonIn  = Cba_ObjFinFon(p, iObj, 0);
            int iFonOut = Cba_ObjFon0(p, iObj);
            // function [15:0] res;
            Vec_StrPrintStr( vStr, "  function " );
            Cba_ManWriteFonRange( p, iFonOut );
            Vec_StrPrintStr( vStr, "_func_" );
            Cba_ManWriteFonName( p, iFonOut, 0, 0 );
            Vec_StrPrintStr( vStr, ";\n" );
            // input [1:0] s;
            Vec_StrPrintStr( vStr, "    input " );
            Cba_ManWriteFonRange( p, iFonIn );
            Vec_StrPrintStr( vStr, "s;\n" );
            // input [15:0] d0, d1, d2, d3;
            Vec_StrPrintStr( vStr, "    input " );
            Cba_ManWriteFonRange( p, iFonOut );
            Cba_ObjForEachFinFon( p, iObj, iFin, iFon, i )
            {
                if ( i == 0 ) continue;
                Vec_StrPrintF( vStr, "%sd%d", i > 1 ? ", " : "", i-1 );
            }
            Vec_StrPrintStr( vStr, ";\n" );
            // casez (s)
            Vec_StrPrintStr( vStr, "    casez(s)" );
            if ( fUseSel )
                Vec_StrPrintStr( vStr, "  // synopsys full_case parallel_case" );
            Vec_StrPrintStr( vStr, "\n" );
            // 2'b00: res = b[15:0];
            Cba_ObjForEachFinFon( p, iObj, iFin, iFon, i )
            {
                if ( i == 0 ) continue;
                Vec_StrPrintF( vStr, "      %d\'b", nBits );
                if ( fUseSel )
                {
                    Vec_StrFillExtra( vStr, Vec_StrSize(vStr) + nBits, '?' );
                    Vec_StrWriteEntry( vStr, Vec_StrSize(vStr) - i, '1' );
                }
                else
                {
                    for ( k = nBits-1; k >= 0; k-- )
                        Vec_StrPrintNum( vStr, ((i-1) >> k) & 1 );
                }
                Vec_StrPrintStr( vStr, ": _func_" );
                Cba_ManWriteFonName( p, iFonOut, 0, 0 );
                Vec_StrPrintF( vStr, " = d%d;\n", i-1 );
            }
            Vec_StrPrintStr( vStr, "    endcase\n" );
            Vec_StrPrintStr( vStr, "  endfunction\n" );
            // assign z = res(a, b, s);
            if ( Vec_BitEntry(vPoFons, iFonOut) ) 
                Vec_StrPrintStr( vStr, "  assign " );
            else
            {
                Vec_StrPrintStr( vStr, "  wire " );
                Cba_ManWriteFonRange( p, iFonOut );
            }
            Cba_ManWriteFonName( p, iFonOut, fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, " = _func_" );
            Cba_ManWriteFonName( p, iFonOut, 0, 0 );
            Vec_StrPrintStr( vStr, " ( " );
            Cba_ObjForEachFinFon( p, iObj, iFin, iFon, i )
            {
                Vec_StrPrintStr( vStr, i ? ", " : "" );
                Cba_ManWriteFonName( p, iFon, fInlineConcat, 0 );
            }
            Vec_StrPrintStr( vStr, " );" );
        }
        else if ( Type == CBA_BOX_DEC )
        {
            int iFonIn   = Cba_ObjFinFon(p, iObj, 0);
            int iFonOut  = Cba_ObjFon0(p, iObj);
            int nBitsIn  = Cba_FonRangeSize(p, iFonIn);
            int nBitsOut = Cba_FonRangeSize(p, iFonOut);
            assert( (1 << nBitsIn) == nBitsOut );
            // function [15:0] res;
            Vec_StrPrintStr( vStr, "  function " );
            Cba_ManWriteFonRange( p, iFonOut );
            Vec_StrPrintStr( vStr, "_func_" );
            Cba_ManWriteFonName( p, iFonOut, 0, 0 );
            Vec_StrPrintStr( vStr, ";\n" );
            // input [1:0] i;
            Vec_StrPrintStr( vStr, "    input " );
            Cba_ManWriteFonRange( p, iFonIn );
            Vec_StrPrintStr( vStr, "i;\n" );
            // casez (i)
            Vec_StrPrintStr( vStr, "    casez(i)\n" );
            // 2'b00: res = 4'b0001;
            for ( i = 0; i < (1 << nBitsIn); i++ )
            {
                Vec_StrPrintF( vStr, "      %d\'b", nBitsIn );
                for ( k = nBitsIn-1; k >= 0; k-- )
                    Vec_StrPrintNum( vStr, (i >> k) & 1 );
                Vec_StrPrintStr( vStr, ": _func_" );
                Cba_ManWriteFonName( p, iFonOut, 0, 0 );
                Vec_StrPrintF( vStr, " = %d\'b%0*d;\n", nBitsOut, nBitsOut, 0 );
                Vec_StrWriteEntry( vStr, Vec_StrSize(vStr) - i - 3, '1' );
            }
            Vec_StrPrintStr( vStr, "    endcase\n" );
            Vec_StrPrintStr( vStr, "  endfunction\n" );
            // assign z = res(i, o);
            if ( Vec_BitEntry(vPoFons, iFonOut) ) 
                Vec_StrPrintStr( vStr, "  assign " );
            else
            {
                Vec_StrPrintStr( vStr, "  wire " );
                Cba_ManWriteFonRange( p, iFonOut );
            }
            Cba_ManWriteFonName( p, iFonOut, fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, " = _func_" );
            Cba_ManWriteFonName( p, iFonOut, 0, 0 );
            Vec_StrPrintStr( vStr, " ( " );
            Cba_ManWriteFonName( p, iFonIn, fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, " );" );
         }
        else if ( Type == CBA_BOX_DFFRS || Type == CBA_BOX_LATCHRS )
        {
            int fUseFlop = Type == CBA_BOX_DFFRS;
            int iFonQ    = Cba_ObjFon0(p, iObj);
            int iFonD    = Cba_ObjFinFon(p, iObj, 0);
            int iFonSet  = Cba_ObjFinFon(p, iObj, 1);
            int iFonRst  = Cba_ObjFinFon(p, iObj, 2);
            int iFonC    = Cba_ObjFinFon(p, iObj, 3);
            int Range    = Cba_FonRangeSize( p, iFonQ );
            assert( Cba_FonRangeSize(p, iFonSet) == 1 && Cba_FonRangeSize(p, iFonRst) == 1 );
            // reg    [3:0] Q;
            Vec_StrPrintStr( vStr, "  reg " );
            Cba_ManWriteFonRange( p, iFonQ );
            Cba_ManWriteFonName( p, iFonQ, 0, 0 );
            Vec_StrPrintStr( vStr, ";\n" );
            // always @(posedge C or posedge PRE)
            Vec_StrPrintStr( vStr, "  always @(" );
            if ( fUseFlop )
                Vec_StrPrintStr( vStr, "posedge " );
            Cba_ManWriteFonName( p, iFonC, 0, 0 );
            if ( !fUseFlop )
            {
                Vec_StrPrintStr( vStr, " or " );
                Cba_ManWriteFonName( p, iFonD, 0, 0 );
            }
            if ( iFonSet > 0 )
            {
                Vec_StrPrintStr( vStr, " or " );
                if ( fUseFlop )
                    Vec_StrPrintStr( vStr, "posedge " );
                Cba_ManWriteFonName( p, iFonSet, 0, 0 );
            }
            if ( iFonRst > 0 )
            {
                Vec_StrPrintStr( vStr, " or " );
                if ( fUseFlop )
                    Vec_StrPrintStr( vStr, "posedge " );
                Cba_ManWriteFonName( p, iFonRst, 0, 0 );
            }
            Vec_StrPrintStr( vStr, ")\n" );
            //  if (Set)  Q <= 4'b1111;
            if ( iFonSet > 0 )
            {
                Vec_StrPrintStr( vStr, "    if (" );
                Cba_ManWriteFonName( p, iFonSet, 0, 0 );
                Vec_StrPrintStr( vStr, ")  " );
                Cba_ManWriteFonName( p, iFonQ, 0, 0 );
                Vec_StrPrintStr( vStr, fUseFlop ? " <= " : " = " );
                // value 1
                Vec_StrPrintNum( vStr, Range );
                Vec_StrPrintStr( vStr, "\'b" );
                Vec_StrFillExtra( vStr, Vec_StrSize(vStr) + Range, '1' );
                Vec_StrPrintStr( vStr, ";\n" );
//                Vec_StrPrintF( vStr, "\'b1" );
            }
            if ( iFonRst > 0 )
            {
                Vec_StrPrintStr( vStr, iFonSet > 0 ? "    else if (" : "    if (" );
                Cba_ManWriteFonName( p, iFonRst, 0, 0 );
                Vec_StrPrintStr( vStr, ")  " );
                Cba_ManWriteFonName( p, iFonQ, 0, 0 );
                Vec_StrPrintStr( vStr, fUseFlop ? " <= " : " = " );
                // value 0
                Vec_StrPrintNum( vStr, Range );
                Vec_StrPrintStr( vStr, "\'b" );
                Vec_StrFillExtra( vStr, Vec_StrSize(vStr) + Range, '0' );
                Vec_StrPrintStr( vStr, ";\n" );
//                Vec_StrPrintF( vStr, "\'b0" );
            }
            Vec_StrPrintStr( vStr, (iFonSet > 0 || iFonRst > 0) ? "    else " : "    " );
            if ( !fUseFlop )
            {
                Vec_StrPrintStr( vStr, "    if (" );
                Cba_ManWriteFonName( p, iFonC, 0, 0 );
                Vec_StrPrintStr( vStr, ")  " );
            }
            Cba_ManWriteFonName( p, iFonQ, 0, 0 );
            Vec_StrPrintStr( vStr, fUseFlop ? " <= " : " = " );
            Cba_ManWriteFonName( p, iFonD, fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, ";" );
        }
        else if ( Type == CBA_BOX_DFFCPL )
        {
            // CPL_FF#32 inst_reg( .d(s1), .arstval(s2), .arst(s3), .clk(s4), .q(s5), .qbar(s6) );
            int iFon0 = Cba_ObjFon0(p, iObj);
            int iFon1 = Cba_ObjFon(p, iObj, 1);
            int Range = Cba_FonRangeSize( p, iFon0 );
            if ( !Vec_BitEntry(vPoFons, iFon0) )
            {
                Vec_StrPrintStr( vStr, "  wire " );
                Cba_ManWriteFonRange( p, iFon0 );
                Cba_ManWriteFonName( p, iFon0, 0, 0 );
                Vec_StrPrintStr( vStr, ";\n" );
            }
            if ( !Vec_BitEntry(vPoFons, iFon1) && Cba_FonName(p, iFon1) )
            {
                Vec_StrPrintStr( vStr, "  wire " );
                Cba_ManWriteFonRange( p, iFon1 );
                Cba_ManWriteFonName( p, iFon1, 0, 0 );
                Vec_StrPrintStr( vStr, ";\n" );
            }
            Vec_StrPrintStr( vStr, "  CPL_FF" );
            if ( Range > 1 )
                Vec_StrPrintF( vStr, "#%d", Range );
            Vec_StrPrintStr( vStr, " " );
            if ( Cba_ObjName(p, iObj) )
                Vec_StrPrintStr( vStr, Cba_ObjGetName(p, iObj) );
            Vec_StrPrintStr( vStr, " ( .d(" );
            Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 0), fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, "), .arstval(" );
            Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 1), fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, "), .arst(" );
            Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 2), fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, "), .clk(" );
            Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 3), fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, "), .q(" );
            Cba_ManWriteFonName( p, iFon0, fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, "), .qbar(" );
            if ( Cba_FonName(p, iFon1) )
                Cba_ManWriteFonName( p, iFon1, fInlineConcat, 0 );
            Vec_StrPrintStr( vStr, ") );" );
        }
        else if ( Type == CBA_BOX_ADD )
        {
            int iFon0 = Cba_ObjFon0(p, iObj);
            int iFon1 = Cba_ObjFon(p, iObj, 1);
            // write outputs
            if ( Cba_FonName(p, iFon1) )
            {
                if ( !Vec_BitEntry(vPoFons, iFon0) )
                {
                    Vec_StrPrintStr( vStr, "  wire " );
                    Cba_ManWriteFonRange( p, iFon0 );
                    Cba_ManWriteFonName( p, iFon0, 0, 0 );
                    Vec_StrPrintStr( vStr, ";\n" );
                }
                if ( !Vec_BitEntry(vPoFons, iFon1) )
                {
                    Vec_StrPrintStr( vStr, "  wire " );
                    Cba_ManWriteFonRange( p, iFon1 );
                    Cba_ManWriteFonName( p, iFon1, 0, 0 );
                    Vec_StrPrintStr( vStr, ";\n" );
                }
                Vec_StrPrintStr( vStr, "  assign {" );
                Cba_ManWriteFonName( p, iFon1, 0, 0 );
                Vec_StrPrintStr( vStr, ", " );
                Cba_ManWriteFonName( p, iFon0, 0, 0 );
                Vec_StrPrintStr( vStr, "} = " );
            }
            else
            {
                if ( Vec_BitEntry(vPoFons, iFon0) ) 
                    Vec_StrPrintStr( vStr, "  assign " );
                else
                {
                    Vec_StrPrintStr( vStr, "  wire " );
                    Cba_ManWriteFonRange( p, iFon0 );
                }
                Cba_ManWriteFonName( p, iFon0, 0, 0 );
                Vec_StrPrintStr( vStr, " = " );
            }
            // write carry-in
            if ( Cba_ObjFinFon(p, iObj, 0) && Cba_ObjFinFon(p, iObj, 0) != Cba_FonFromConst(1) )
            {
                Vec_StrPush( vStr, ' ' );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 0), fInlineConcat, 0 );
                Vec_StrPush( vStr, ' ' );
                Vec_StrPrintStr( vStr, "+" );
            }
            Vec_StrPush( vStr, ' ' );
            Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 1), fInlineConcat, 0 );
            Vec_StrPush( vStr, ' ' );
            Vec_StrPrintStr( vStr, "+" );
            Vec_StrPush( vStr, ' ' );
            Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 2), fInlineConcat, 0 );
            Vec_StrPush( vStr, ';' );
        }
        else
        {
            if ( Vec_BitEntry(vPoFons, Cba_ObjFon0(p, iObj)) ) 
                Vec_StrPrintStr( vStr, "  assign " );
            else
            {
                Vec_StrPrintStr( vStr, "  wire " );
                Cba_ManWriteFonRange( p, Cba_ObjFon0(p, iObj) );
            }
            Cba_ManWriteFonName( p, Cba_ObjFon0(p, iObj), 0, 0 );
            Vec_StrPrintStr( vStr, " = " );
            if ( Cba_ObjIsConcat(p, iObj) )
                Cba_ManWriteConcat( p, iObj );
            else if ( Type == CBA_BOX_MUX )
            {
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 0), fInlineConcat, 0 );
                Vec_StrPrintStr( vStr, " ? " );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 1), fInlineConcat, 0 );
                Vec_StrPrintStr( vStr, " : " );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 2), fInlineConcat, 0 );
            }
            else if ( Type == CBA_BOX_ROTL || Type == CBA_BOX_ROTR )
            {
                //  wire [27:0] s4960 = (s57 >> 17) | (s57 << 11);
                int Range = Cba_FonRangeSize( p, Cba_ObjFon0(p, iObj) );
                int iFinFon1 = Cba_ObjFinFon(p, iObj, 1);
                Vec_StrPush( vStr, '(' );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 0), fInlineConcat, 0 );
                Vec_StrPrintStr( vStr, Type == CBA_BOX_ROTL ? " << " : " >> " );
                if ( Cba_FonIsConst(iFinFon1) )
                    Vec_StrPrintNum( vStr, Cba_FonConst(iFinFon1) );
                else
                    Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 1), fInlineConcat, 0 );
                Vec_StrPrintStr( vStr, ") | (" );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 0), fInlineConcat, 0 );
                Vec_StrPrintStr( vStr, Type == CBA_BOX_ROTL ? " >> " : " << " );
                if ( Cba_FonIsConst(iFinFon1) )
                    Vec_StrPrintNum( vStr, Range - Cba_FonConst(iFinFon1) );
                else
                {
                    Vec_StrPush( vStr, '(' );
                    Vec_StrPrintNum( vStr, Range );
                    Vec_StrPrintStr( vStr, " - " );
                    Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 1), fInlineConcat, 0 );
                    Vec_StrPush( vStr, ')' );
                }
                Vec_StrPush( vStr, ')' );
            }
            else if ( Type == CBA_BOX_LTHAN )
            {
                int fLessThan = (Cba_ObjFinFon(p, iObj, 0) == Cba_FonFromConst(1)); // const0
                Vec_StrPush( vStr, ' ' );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 1), fInlineConcat, 0 );
                Vec_StrPush( vStr, ' ' );
                Vec_StrPrintStr( vStr, fLessThan ? "<" : "<=" );
                Vec_StrPush( vStr, ' ' );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 2), fInlineConcat, 0 );
            }
            else if ( Cba_TypeIsUnary(Type) )
            {
                Vec_StrPrintStr( vStr, Cba_NtkTypeName(p, Type) );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 0), fInlineConcat, 0 );
            }
            else if ( Cba_NtkTypeName(p, Type) ) // binary operation
            {
                int fCompl = (Type == CBA_BOX_NAND || Type == CBA_BOX_NOR || Type == CBA_BOX_XNOR);
                if ( fCompl )
                    Vec_StrPrintStr( vStr, "!(" );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 0), fInlineConcat, 0 );
                Vec_StrPush( vStr, ' ' );
                Vec_StrPrintStr( vStr, Cba_NtkTypeName(p, Type) );
                Vec_StrPush( vStr, ' ' );
                Cba_ManWriteFonName( p, Cba_ObjFinFon(p, iObj, 1), fInlineConcat, 0 );
                if ( fCompl )
                    Vec_StrPrintStr( vStr, ")" );
            }
            else // unknown
            {
                char * pName = Cba_FonGetName(p, Cba_ObjFon0(p, iObj));
                Vec_StrPrintStr( vStr, "<unknown operator>" );
                printf( "Cba_ManWriteVerilog(): In module \"%s\", cannot write object \"%s\" with output name \"%s\".\n", Cba_NtkName(p), Cba_ObjGetName(p, iObj), pName );
            }
            Vec_StrPush( vStr, ';' );
        }
        // write attributes
        Status = Cba_ManWriteLineFile( p, iObj, FileAttr, LineAttr );
        if ( !Cba_ObjIsBoxUser(p, iObj) && Cba_ObjName(p, iObj) )
        {
            if ( !Status )
                Vec_StrPrintStr( vStr, "  //" );
            Vec_StrPrintStr( vStr, " name=" );
            Vec_StrPrintStr( vStr, Cba_ObjGetName(p, iObj) );
        }
        Vec_StrPush( vStr, '\n' );
    }
    // write remaining outputs
    Cba_NtkForEachPo( p, iObj, i )
    {
        iFon = Cba_ObjFinFon(p, iObj, 0);
        if ( !iFon || (!Cba_FonIsConst(iFon) && Cba_FonName(p, iFon) == Cba_ObjName(p, iObj)) ) // already written
            continue;
        Vec_StrPrintStr( vStr, "  assign " );
        Vec_StrPrintStr( vStr, Cba_ObjGetName(p, iObj) );
        Vec_StrPrintStr( vStr, " = " );
        Cba_ManWriteFonName( p, iFon, fInlineConcat, 0 );
        Vec_StrPush( vStr, ';' );
        Vec_StrPush( vStr, '\n' );
    }
    Vec_StrPrintStr( vStr, "\n" );
    Vec_StrPrintStr( vStr, "endmodule\n\n" );
    Vec_BitFree( vPoFons );
}
void Cba_ManWriteVerilog( char * pFileName, Cba_Man_t * p, int fInlineConcat )
{
    Cba_Ntk_t * pNtk; int i;
    // check the library
    if ( p->pMioLib && p->pMioLib != Abc_FrameReadLibGen() )
    {
        printf( "Genlib library used in the mapped design is not longer a current library.\n" );
        return;
    }
    Cba_ManCreatePrimMap( p->pTypeNames );
    // derive the stream
    p->nOpens = 1;
    Vec_StrClear( &p->vOut );
    Vec_StrClear( &p->vOut2 );
    Vec_StrPrintStr( &p->vOut, "// Design \"" );
    Vec_StrPrintStr( &p->vOut, Cba_ManName(p) );
    Vec_StrPrintStr( &p->vOut, "\" written via CBA package in ABC on " );
    Vec_StrPrintStr( &p->vOut, Extra_TimeStamp() );
    Vec_StrPrintStr( &p->vOut, "\n\n" );
    Cba_ManForEachNtk( p, pNtk, i )
        Cba_ManWriteVerilogNtk( pNtk, fInlineConcat );
    // dump into file
    if ( Vec_StrSize(&p->vOut) > 0 )
    {
        FILE * pFile = fopen( pFileName, "wb" );
        if ( pFile == NULL )
            printf( "Cannot open file \"%s\" for writing.\n", pFileName );
        else
        {
            fwrite( Vec_StrArray(&p->vOut), 1, Vec_StrSize(&p->vOut), pFile );
            fclose( pFile );
        }
    }
}

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


ABC_NAMESPACE_IMPL_END