/**CFile**************************************************************** FileName [wlcReadVer.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Verilog parser.] Synopsis [Parses several flavors of word-level Verilog.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - August 22, 2014.] Revision [$Id: wlcReadVer.c,v 1.00 2014/09/12 00:00:00 alanmi Exp $] ***********************************************************************/ #include "wlc.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// // Word-level Verilog file parser #define WLV_PRS_MAX_LINE 1000 typedef struct Wlc_Prs_t_ Wlc_Prs_t; struct Wlc_Prs_t_ { int nFileSize; char * pFileName; char * pBuffer; Vec_Int_t * vLines; Vec_Int_t * vStarts; Vec_Int_t * vFanins; Wlc_Ntk_t * pNtk; Mem_Flex_t * pMemTable; Vec_Ptr_t * vTables; int nConsts; char sError[WLV_PRS_MAX_LINE]; }; static inline int Wlc_PrsOffset( Wlc_Prs_t * p, char * pStr ) { return pStr - p->pBuffer; } static inline char * Wlc_PrsStr( Wlc_Prs_t * p, int iOffset ) { return p->pBuffer + iOffset; } static inline int Wlc_PrsStrCmp( char * pStr, char * pWhat ) { return !strncmp( pStr, pWhat, strlen(pWhat)); } #define Wlc_PrsForEachLine( p, pLine, i ) \ for ( i = 0; (i < Vec_IntSize((p)->vStarts)) && ((pLine) = Wlc_PrsStr(p, Vec_IntEntry((p)->vStarts, i))); i++ ) #define Wlc_PrsForEachLineStart( p, pLine, i, Start ) \ for ( i = Start; (i < Vec_IntSize((p)->vStarts)) && ((pLine) = Wlc_PrsStr(p, Vec_IntEntry((p)->vStarts, i))); i++ ) //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Wlc_Prs_t * Wlc_PrsStart( char * pFileName ) { Wlc_Prs_t * p; if ( !Extra_FileCheck( pFileName ) ) return NULL; p = ABC_CALLOC( Wlc_Prs_t, 1 ); p->pFileName = pFileName; p->pBuffer = Extra_FileReadContents( pFileName ); p->nFileSize = strlen(p->pBuffer); assert( p->nFileSize > 0 ); p->vLines = Vec_IntAlloc( p->nFileSize / 50 ); p->vStarts = Vec_IntAlloc( p->nFileSize / 50 ); p->vFanins = Vec_IntAlloc( 100 ); p->vTables = Vec_PtrAlloc( 1000 ); p->pMemTable = Mem_FlexStart(); return p; } void Wlc_PrsStop( Wlc_Prs_t * p ) { if ( p->pNtk ) Wlc_NtkFree( p->pNtk ); if ( p->pMemTable ) Mem_FlexStop( p->pMemTable, 0 ); Vec_PtrFreeP( &p->vTables ); Vec_IntFree( p->vLines ); Vec_IntFree( p->vStarts ); Vec_IntFree( p->vFanins ); ABC_FREE( p->pBuffer ); ABC_FREE( p ); } /**Function************************************************************* Synopsis [Prints the error message including the file name and line number.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Wlc_PrsWriteErrorMessage( Wlc_Prs_t * p, char * pCur, const char * format, ... ) { char * pMessage; // derive message va_list args; va_start( args, format ); pMessage = vnsprintf( format, args ); va_end( args ); // print messsage assert( strlen(pMessage) < WLV_PRS_MAX_LINE - 100 ); assert( p->sError[0] == 0 ); if ( pCur == NULL ) // the line number is not given sprintf( p->sError, "%s: %s\n", p->pFileName, pMessage ); else // print the error message with the line number { int Entry, iLine = 0; Vec_IntForEachEntry( p->vLines, Entry, iLine ) if ( Entry > pCur - p->pBuffer ) break; sprintf( p->sError, "%s (line %d): %s\n", p->pFileName, iLine+1, pMessage ); } ABC_FREE( pMessage ); return 0; } void Wlc_PrsPrintErrorMessage( Wlc_Prs_t * p ) { if ( p->sError[0] == 0 ) return; fprintf( stdout, "%s", p->sError ); } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline int Wlc_PrsIsDigit( char * pStr ) { return (pStr[0] >= '0' && pStr[0] <= '9'); } static inline int Wlc_PrsIsChar( char * pStr ) { return (pStr[0] >= 'a' && pStr[0] <= 'z') || (pStr[0] >= 'A' && pStr[0] <= 'Z') || (pStr[0] >= '0' && pStr[0] <= '9') || pStr[0] == '_' || pStr[0] == '$' || pStr[0] == '\\'; } static inline char * Wlc_PrsSkipSpaces( char * pStr ) { while ( *pStr && *pStr == ' ' ) pStr++; return pStr; } static inline char * Wlc_PrsFindSymbol( char * pStr, char Symb ) { int fNotName = 1; for ( ; *pStr; pStr++ ) { if ( fNotName && *pStr == Symb ) return pStr; if ( pStr[0] == '\\' ) fNotName = 0; else if ( !fNotName && *pStr == ' ' ) fNotName = 1; } return NULL; } static inline char * Wlc_PrsFindSymbolTwo( char * pStr, char Symb, char Symb2 ) { for ( ; pStr[1]; pStr++ ) if ( pStr[0] == Symb && pStr[1] == Symb2 ) return pStr; return NULL; } static inline char * Wlc_PrsFindClosingParenthesis( char * pStr, char Open, char Close ) { int Counter = 0; int fNotName = 1; assert( *pStr == Open ); for ( ; *pStr; pStr++ ) { if ( fNotName ) { if ( *pStr == Open ) Counter++; if ( *pStr == Close ) Counter--; if ( Counter == 0 ) return pStr; } if ( *pStr == '\\' ) fNotName = 0; else if ( !fNotName && *pStr == ' ' ) fNotName = 1; } return NULL; } int Wlc_PrsRemoveComments( Wlc_Prs_t * p ) { int fSpecifyFound = 0; char * pCur, * pNext, * pEnd = p->pBuffer + p->nFileSize; for ( pCur = p->pBuffer; pCur < pEnd; pCur++ ) { // regular comment (//) if ( *pCur == '/' && pCur[1] == '/' ) { if ( pCur + 5 < pEnd && pCur[2] == 'a' && pCur[3] == 'b' && pCur[4] == 'c' && pCur[5] == '2' ) pCur[0] = pCur[1] = pCur[2] = pCur[3] = pCur[4] = pCur[5] = ' '; else { pNext = Wlc_PrsFindSymbol( pCur, '\n' ); if ( pNext == NULL ) return Wlc_PrsWriteErrorMessage( p, pCur, "Cannot find end-of-line after symbols \"//\"." ); for ( ; pCur < pNext; pCur++ ) *pCur = ' '; } } // skip preprocessor directive (`timescale, `celldefine, etc) else if ( *pCur == '`' ) { pNext = Wlc_PrsFindSymbol( pCur, '\n' ); if ( pNext == NULL ) return Wlc_PrsWriteErrorMessage( p, pCur, "Cannot find end-of-line after symbols \"`\"." ); for ( ; pCur < pNext; pCur++ ) *pCur = ' '; } // regular comment (/* ... */) else if ( *pCur == '/' && pCur[1] == '*' ) { pNext = Wlc_PrsFindSymbolTwo( pCur, '*', '/' ); if ( pNext == NULL ) return Wlc_PrsWriteErrorMessage( p, pCur, "Cannot find symbols \"*/\" after symbols \"/*\"." ); // overwrite comment for ( ; pCur < pNext + 2; pCur++ ) *pCur = ' '; } // 'specify' treated as comments else if ( *pCur == 's' && pCur[1] == 'p' && pCur[2] == 'e' && !strncmp(pCur, "specify", 7) ) { for ( pNext = pCur; pNext < pEnd - 10; pNext++ ) if ( *pNext == 'e' && pNext[1] == 'n' && pNext[2] == 'd' && !strncmp(pNext, "endspecify", 10) ) { // overwrite comment for ( ; pCur < pNext + 10; pCur++ ) *pCur = ' '; if ( fSpecifyFound == 0 ) Abc_Print( 0, "Ignoring specify/endspecify directives.\n" ); fSpecifyFound = 1; break; } } // insert semicolons else if ( *pCur == 'e' && pCur[1] == 'n' && pCur[2] == 'd' && !strncmp(pCur, "endmodule", 9) ) pCur[strlen("endmodule")] = ';'; // overwrite end-of-lines with spaces (less checking to do later on) if ( *pCur == '\n' || *pCur == '\r' || *pCur == '\t' ) *pCur = ' '; } return 1; } int Wlc_PrsPrepare( Wlc_Prs_t * p ) { int fPrettyPrint = 0; int fNotName = 1; char * pTemp, * pPrev, * pThis; // collect info about lines assert( Vec_IntSize(p->vLines) == 0 ); for ( pTemp = p->pBuffer; *pTemp; pTemp++ ) if ( *pTemp == '\n' ) Vec_IntPush( p->vLines, pTemp - p->pBuffer ); // delete comments and insert breaks if ( !Wlc_PrsRemoveComments( p ) ) return 0; // collect info about breaks assert( Vec_IntSize(p->vStarts) == 0 ); for ( pPrev = pThis = p->pBuffer; *pThis; pThis++ ) { if ( fNotName && *pThis == ';' ) { *pThis = 0; Vec_IntPush( p->vStarts, Wlc_PrsOffset(p, Wlc_PrsSkipSpaces(pPrev)) ); pPrev = pThis + 1; } if ( *pThis == '\\' ) fNotName = 0; else if ( !fNotName && *pThis == ' ' ) fNotName = 1; } if ( fPrettyPrint ) { int i, k; // print the line types Wlc_PrsForEachLine( p, pTemp, i ) { if ( Wlc_PrsStrCmp( pTemp, "module" ) ) printf( "\n" ); if ( !Wlc_PrsStrCmp( pTemp, "module" ) && !Wlc_PrsStrCmp( pTemp, "endmodule" ) ) printf( " " ); printf( "%c", pTemp[0] ); for ( k = 1; pTemp[k]; k++ ) if ( pTemp[k] != ' ' || pTemp[k-1] != ' ' ) printf( "%c", pTemp[k] ); printf( ";\n" ); } /* // print the line types Wlc_PrsForEachLine( p, pTemp, i ) { int k; if ( !Wlc_PrsStrCmp( pTemp, "module" ) ) continue; printf( "%3d : ", i ); for ( k = 0; k < 40; k++ ) printf( "%c", pTemp[k] ? pTemp[k] : ' ' ); printf( "\n" ); } */ } return 1; } /**Function************************************************************* Synopsis [Modified version of strtok().] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ char * Wlc_PrsStrtok( char * s, const char * delim ) { const char *spanp; int c, sc; char *tok; static char *last; if (s == NULL && (s = last) == NULL) return NULL; // skip leading delimiters cont: c = *s++; for (spanp = delim; (sc = *spanp++) != 0;) if (c == sc) goto cont; if (c == 0) // no non-delimiter characters return (last = NULL); // tok = s - 1; if ( c != '\\' ) tok = s - 1; else tok = s - 1; // go back to the first non-delimiter character s--; // find the token for (;;) { c = *s++; if ( c == '\\' ) // skip blind characters { while ( c != ' ' ) c = *s++; c = *s++; } spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; last = s; return (tok); } } while (sc != 0); } // not reached return NULL; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ char * Wlc_PrsConvertInitValues( Wlc_Ntk_t * p ) { Wlc_Obj_t * pObj; int i, k, Value, * pInits; char * pResult; Vec_Str_t * vStr = Vec_StrAlloc( 1000 ); Vec_IntForEachEntry( p->vInits, Value, i ) { if ( Value < 0 ) { for ( k = 0; k < -Value; k++ ) Vec_StrPush( vStr, '0' ); continue; } pObj = Wlc_NtkObj( p, Value ); Value = Wlc_ObjRange(pObj); while ( pObj->Type == WLC_OBJ_BUF ) pObj = Wlc_NtkObj( p, Wlc_ObjFaninId0(pObj) ); pInits = pObj->Type == WLC_OBJ_CONST ? Wlc_ObjConstValue(pObj) : NULL; for ( k = 0; k < Abc_MinInt(Value, Wlc_ObjRange(pObj)); k++ ) Vec_StrPush( vStr, (char)(pInits ? '0' + Abc_InfoHasBit((unsigned *)pInits, k) : 'X') ); // extend values with zero, in case the init value signal has different range compared to constant used for ( ; k < Value; k++ ) Vec_StrPush( vStr, '0' ); // update vInits to contain either number of values or PI index Vec_IntWriteEntry( p->vInits, i, pInits ? -Value : Wlc_ObjCiId(pObj) ); } Vec_StrPush( vStr, '\0' ); pResult = Vec_StrReleaseArray( vStr ); Vec_StrFree( vStr ); return pResult; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline char * Wlc_PrsFindRange( char * pStr, int * End, int * Beg ) { *End = *Beg = 0; pStr = Wlc_PrsSkipSpaces( pStr ); if ( pStr[0] != '[' ) return pStr; pStr = Wlc_PrsSkipSpaces( pStr+1 ); if ( !Wlc_PrsIsDigit(pStr) ) return NULL; *End = *Beg = atoi( pStr ); if ( Wlc_PrsFindSymbol( pStr, ':' ) == NULL ) { pStr = Wlc_PrsFindSymbol( pStr, ']' ); if ( pStr == NULL ) return NULL; } else { pStr = Wlc_PrsFindSymbol( pStr, ':' ); pStr = Wlc_PrsSkipSpaces( pStr+1 ); if ( !Wlc_PrsIsDigit(pStr) ) return NULL; *Beg = atoi( pStr ); pStr = Wlc_PrsFindSymbol( pStr, ']' ); if ( pStr == NULL ) return NULL; } assert( *End >= *Beg ); return pStr + 1; } static inline char * Wlc_PrsFindWord( char * pStr, char * pWord, int * fFound ) { *fFound = 0; pStr = Wlc_PrsSkipSpaces( pStr ); if ( !Wlc_PrsStrCmp(pStr, pWord) ) return pStr; *fFound = 1; return pStr + strlen(pWord); } static inline char * Wlc_PrsFindName( char * pStr, char ** ppPlace ) { static char Buffer[WLV_PRS_MAX_LINE]; char * pThis = *ppPlace = Buffer; int fNotName = 1; pStr = Wlc_PrsSkipSpaces( pStr ); if ( !Wlc_PrsIsChar(pStr) ) return NULL; // while ( Wlc_PrsIsChar(pStr) ) // *pThis++ = *pStr++; while ( *pStr ) { if ( fNotName && !Wlc_PrsIsChar(pStr) ) break; if ( *pStr == '\\' ) fNotName = 0; else if ( !fNotName && *pStr == ' ' ) fNotName = 1; *pThis++ = *pStr++; } *pThis = 0; return pStr; } static inline char * Wlc_PrsReadConstant( Wlc_Prs_t * p, char * pStr, Vec_Int_t * vFanins, int * pRange, int * pSigned ) { int i, nDigits, nBits = atoi( pStr ); *pRange = -1; *pSigned = 0; pStr = Wlc_PrsSkipSpaces( pStr ); if ( Wlc_PrsFindSymbol( pStr, '\'' ) == NULL ) { // handle decimal number int Number = atoi( pStr ); *pRange = Abc_Base2Log( Number+1 ); assert( *pRange < 32 ); while ( Wlc_PrsIsDigit(pStr) ) pStr++; Vec_IntFill( vFanins, 1, Number ); return pStr; } pStr = Wlc_PrsFindSymbol( pStr, '\'' ); if ( pStr[1] == 's' ) { *pSigned = 1; pStr++; } if ( pStr[1] == 'b' ) { Vec_IntFill( vFanins, Abc_BitWordNum(nBits), 0 ); for ( i = 0; i < nBits; i++ ) if ( pStr[2+i] == '1' ) Abc_InfoSetBit( (unsigned *)Vec_IntArray(vFanins), nBits-1-i ); else if ( pStr[2+i] != '0' ) return (char *)(ABC_PTRINT_T)Wlc_PrsWriteErrorMessage( p, pStr, "Wrong digit in binary constant \"%c\".", pStr[2+i] ); *pRange = nBits; pStr += 2 + nBits; return pStr; } if ( pStr[1] != 'h' ) return (char *)(ABC_PTRINT_T)Wlc_PrsWriteErrorMessage( p, pStr, "Expecting hexadecimal constant and not \"%c\".", pStr[1] ); Vec_IntFill( vFanins, Abc_BitWordNum(nBits), 0 ); nDigits = Abc_TtReadHexNumber( (word *)Vec_IntArray(vFanins), pStr+2 ); if ( nDigits != (nBits + 3)/4 ) { // return (char *)(ABC_PTRINT_T)Wlc_PrsWriteErrorMessage( p, pStr, "The length of a constant does not match." ); // printf( "Warning: The length of a constant (%d hex digits) does not match the number of bits (%d).\n", nDigits, nBits ); } *pRange = nBits; pStr += 2; while ( Wlc_PrsIsChar(pStr) ) pStr++; return pStr; } static inline char * Wlc_PrsReadName( Wlc_Prs_t * p, char * pStr, Vec_Int_t * vFanins ) { int NameId, fFound, iObj; pStr = Wlc_PrsSkipSpaces( pStr ); if ( Wlc_PrsIsDigit(pStr) ) { char Buffer[100]; int Range, Signed; Vec_Int_t * vFanins = Vec_IntAlloc(0); pStr = Wlc_PrsReadConstant( p, pStr, vFanins, &Range, &Signed ); if ( pStr == NULL ) { Vec_IntFree( vFanins ); return 0; } // create new node iObj = Wlc_ObjAlloc( p->pNtk, WLC_OBJ_CONST, Signed, Range-1, 0 ); Wlc_ObjAddFanins( p->pNtk, Wlc_NtkObj(p->pNtk, iObj), vFanins ); Vec_IntFree( vFanins ); // add node's name sprintf( Buffer, "_c%d_", p->nConsts++ ); NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, Buffer, &fFound ); if ( fFound ) return (char *)(ABC_PTRINT_T)Wlc_PrsWriteErrorMessage( p, pStr, "Name %s is already used.", Buffer ); assert( iObj == NameId ); } else { char * pName; pStr = Wlc_PrsFindName( pStr, &pName ); if ( pStr == NULL ) return (char *)(ABC_PTRINT_T)Wlc_PrsWriteErrorMessage( p, pStr, "Cannot read name in assign-statement." ); NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); if ( !fFound ) return (char *)(ABC_PTRINT_T)Wlc_PrsWriteErrorMessage( p, pStr, "Name %s is used but not declared.", pName ); } Vec_IntPush( vFanins, NameId ); return Wlc_PrsSkipSpaces( pStr ); } static inline int Wlc_PrsFindDefinition( Wlc_Prs_t * p, char * pStr, Vec_Int_t * vFanins ) { char * pName; int Type = WLC_OBJ_NONE; int fRotating = 0; Vec_IntClear( vFanins ); pStr = Wlc_PrsSkipSpaces( pStr ); if ( pStr[0] != '=' ) return 0; pStr = Wlc_PrsSkipSpaces( pStr+1 ); if ( pStr[0] == '(' ) { // consider rotating shifter if ( Wlc_PrsFindSymbolTwo(pStr, '>', '>') && Wlc_PrsFindSymbolTwo(pStr, '<', '<') ) { // THIS IS A HACK TO DETECT rotating shifters char * pClose = Wlc_PrsFindClosingParenthesis( pStr, '(', ')' ); if ( pClose == NULL ) return Wlc_PrsWriteErrorMessage( p, pStr, "Expecting closing parenthesis." ); *pStr = ' '; *pClose = 0; pStr = Wlc_PrsSkipSpaces( pStr ); fRotating = 1; } else { char * pClose = Wlc_PrsFindClosingParenthesis( pStr, '(', ')' ); if ( pClose == NULL ) return Wlc_PrsWriteErrorMessage( p, pStr, "Expecting closing parenthesis." ); *pStr = *pClose = ' '; pStr = Wlc_PrsSkipSpaces( pStr ); } } if ( Wlc_PrsIsDigit(pStr) ) { int Range, Signed; pStr = Wlc_PrsReadConstant( p, pStr, vFanins, &Range, &Signed ); if ( pStr == NULL ) return 0; Type = WLC_OBJ_CONST; } else if ( pStr[0] == '!' || pStr[0] == '~' ) { if ( pStr[0] == '!' ) Type = WLC_OBJ_LOGIC_NOT; else if ( pStr[0] == '~' ) Type = WLC_OBJ_BIT_NOT; else assert( 0 ); // skip parentheses pStr = Wlc_PrsSkipSpaces( pStr+1 ); if ( pStr[0] == '(' ) { char * pClose = Wlc_PrsFindClosingParenthesis( pStr, '(', ')' ); if ( pClose == NULL ) return Wlc_PrsWriteErrorMessage( p, pStr, "Expecting closing parenthesis." ); *pStr = *pClose = ' '; } if ( !(pStr = Wlc_PrsReadName(p, pStr, vFanins)) ) return Wlc_PrsWriteErrorMessage( p, pStr, "Cannot read name after !." ); } else if ( pStr[0] == '&' || pStr[0] == '|' || pStr[0] == '^' || pStr[0] == '-' ) { if ( pStr[0] == '&' ) Type = WLC_OBJ_REDUCT_AND; else if ( pStr[0] == '|' ) Type = WLC_OBJ_REDUCT_OR; else if ( pStr[0] == '^' ) Type = WLC_OBJ_REDUCT_XOR; else if ( pStr[0] == '-' ) Type = WLC_OBJ_ARI_MINUS; else assert( 0 ); if ( !(pStr = Wlc_PrsReadName(p, pStr+1, vFanins)) ) return Wlc_PrsWriteErrorMessage( p, pStr, "Cannot read name after a unary operator." ); } else if ( pStr[0] == '{' ) { // THIS IS A HACK TO DETECT zero padding AND sign extension if ( Wlc_PrsFindSymbol(pStr+1, '{') ) { if ( Wlc_PrsFindSymbol(pStr+1, '\'') ) Type = WLC_OBJ_BIT_ZEROPAD; else Type = WLC_OBJ_BIT_SIGNEXT; pStr = Wlc_PrsFindSymbol(pStr+1, ','); if ( pStr == NULL ) return Wlc_PrsWriteErrorMessage( p, pStr, "Expecting one comma in this line." ); if ( !(pStr = Wlc_PrsReadName(p, pStr+1, vFanins)) ) return Wlc_PrsWriteErrorMessage( p, pStr, "Cannot read name in sign-extension." ); pStr = Wlc_PrsSkipSpaces( pStr ); if ( pStr[0] != '}' ) return Wlc_PrsWriteErrorMessage( p, pStr, "There is no closing brace (})." ); } else // concatenation { while ( 1 ) { pStr = Wlc_PrsSkipSpaces( pStr+1 ); if ( !(pStr = Wlc_PrsReadName(p, pStr, vFanins)) ) return Wlc_PrsWriteErrorMessage( p, pStr, "Cannot read name in concatenation." ); if ( pStr[0] == '}' ) break; if ( pStr[0] != ',' ) return Wlc_PrsWriteErrorMessage( p, pStr, "Expected comma (,) in this place." ); } Type = WLC_OBJ_BIT_CONCAT; } assert( pStr[0] == '}' ); pStr++; } else { if ( !(pStr = Wlc_PrsReadName(p, pStr, vFanins)) ) return 0; // get the next symbol if ( pStr[0] == 0 ) Type = WLC_OBJ_BUF; else if ( pStr[0] == '?' ) { if ( !(pStr = Wlc_PrsReadName(p, pStr+1, vFanins)) ) return Wlc_PrsWriteErrorMessage( p, pStr, "Cannot read name in MUX." ); if ( pStr[0] != ':' ) return Wlc_PrsWriteErrorMessage( p, pStr, "MUX lacks the colon symbol (:)." ); if ( !(pStr = Wlc_PrsReadName(p, pStr+1, vFanins)) ) return Wlc_PrsWriteErrorMessage( p, pStr, "Cannot read name in MUX." ); assert( Vec_IntSize(vFanins) == 3 ); ABC_SWAP( int, Vec_IntArray(vFanins)[1], Vec_IntArray(vFanins)[2] ); Type = WLC_OBJ_MUX; } else if ( pStr[0] == '[' ) { int End, Beg; pStr = Wlc_PrsFindRange( pStr, &End, &Beg ); Vec_IntPush( vFanins, (End << 16) | Beg ); Type = WLC_OBJ_BIT_SELECT; } else { if ( pStr[0] == '>' && pStr[1] == '>' && pStr[2] != '>' ) pStr += 2, Type = fRotating ? WLC_OBJ_ROTATE_R : WLC_OBJ_SHIFT_R; else if ( pStr[0] == '>' && pStr[1] == '>' && pStr[2] == '>' ) pStr += 3, Type = WLC_OBJ_SHIFT_RA; else if ( pStr[0] == '<' && pStr[1] == '<' && pStr[2] != '<' ) pStr += 2, Type = fRotating ? WLC_OBJ_ROTATE_L : WLC_OBJ_SHIFT_L; else if ( pStr[0] == '<' && pStr[1] == '<' && pStr[2] == '<' ) pStr += 3, Type = WLC_OBJ_SHIFT_LA; else if ( pStr[0] == '&' && pStr[1] != '&' ) pStr += 1, Type = WLC_OBJ_BIT_AND; else if ( pStr[0] == '|' && pStr[1] != '|' ) pStr += 1, Type = WLC_OBJ_BIT_OR; else if ( pStr[0] == '^' && pStr[1] != '^' ) pStr += 1, Type = WLC_OBJ_BIT_XOR; else if ( pStr[0] == '&' && pStr[1] == '&' ) pStr += 2, Type = WLC_OBJ_LOGIC_AND; else if ( pStr[0] == '|' && pStr[1] == '|' ) pStr += 2, Type = WLC_OBJ_LOGIC_OR; else if ( pStr[0] == '=' && pStr[1] == '=' ) pStr += 2, Type = WLC_OBJ_COMP_EQU; else if ( pStr[0] == '!' && pStr[1] == '=' ) pStr += 2, Type = WLC_OBJ_COMP_NOTEQU; else if ( pStr[0] == '<' && pStr[1] != '=' ) pStr += 1, Type = WLC_OBJ_COMP_LESS; else if ( pStr[0] == '>' && pStr[1] != '=' ) pStr += 1, Type = WLC_OBJ_COMP_MORE; else if ( pStr[0] == '<' && pStr[1] == '=' ) pStr += 2, Type = WLC_OBJ_COMP_LESSEQU; else if ( pStr[0] == '>' && pStr[1] == '=' ) pStr += 2, Type = WLC_OBJ_COMP_MOREEQU; else if ( pStr[0] == '+' ) pStr += 1, Type = WLC_OBJ_ARI_ADD; else if ( pStr[0] == '-' ) pStr += 1, Type = WLC_OBJ_ARI_SUB; else if ( pStr[0] == '*' && pStr[1] != '*' ) pStr += 1, Type = WLC_OBJ_ARI_MULTI; else if ( pStr[0] == '/' ) pStr += 1, Type = WLC_OBJ_ARI_DIVIDE; else if ( pStr[0] == '%' ) pStr += 1, Type = WLC_OBJ_ARI_MODULUS; else if ( pStr[0] == '*' && pStr[1] == '*' ) pStr += 2, Type = WLC_OBJ_ARI_POWER; else return Wlc_PrsWriteErrorMessage( p, pStr, "Unsupported operation (%c).", pStr[0] ); if ( !(pStr = Wlc_PrsReadName(p, pStr+1, vFanins)) ) return 0; } } // make sure there is nothing left there if ( pStr ) { pStr = Wlc_PrsFindName( pStr, &pName ); if ( pStr != NULL ) return Wlc_PrsWriteErrorMessage( p, pStr, "Name %s is left at the end of the line.", pName ); } return Type; } int Wlc_PrsReadDeclaration( Wlc_Prs_t * p, char * pStart ) { int fFound = 0, Type = WLC_OBJ_NONE, iObj; int Signed = 0, Beg = 0, End = 0, NameId, fIsPo = 0; if ( Wlc_PrsStrCmp( pStart, "input" ) ) pStart += strlen("input"), Type = WLC_OBJ_PI; else if ( Wlc_PrsStrCmp( pStart, "output" ) ) pStart += strlen("output"), fIsPo = 1; pStart = Wlc_PrsSkipSpaces( pStart ); if ( Wlc_PrsStrCmp( pStart, "wire" ) ) pStart += strlen("wire"); else if ( Wlc_PrsStrCmp( pStart, "reg" ) ) pStart += strlen("reg"); // read 'signed' pStart = Wlc_PrsFindWord( pStart, "signed", &Signed ); // read range pStart = Wlc_PrsFindRange( pStart, &End, &Beg ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read range." ); while ( 1 ) { char * pName; // read name pStart = Wlc_PrsFindName( pStart, &pName ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name in declaration." ); NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); if ( fFound ) return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is declared more than once.", pName ); iObj = Wlc_ObjAlloc( p->pNtk, Type, Signed, End, Beg ); if ( fIsPo ) Wlc_ObjSetCo( p->pNtk, Wlc_NtkObj(p->pNtk, iObj), 0 ); assert( iObj == NameId ); // check next definition pStart = Wlc_PrsSkipSpaces( pStart ); if ( pStart[0] == ',' ) { pStart++; continue; } // check definition Type = Wlc_PrsFindDefinition( p, pStart, p->vFanins ); if ( Type ) { Wlc_Obj_t * pObj = Wlc_NtkObj( p->pNtk, iObj ); Wlc_ObjUpdateType( p->pNtk, pObj, Type ); Wlc_ObjAddFanins( p->pNtk, pObj, p->vFanins ); } break; } return 1; } int Wlc_PrsDerive( Wlc_Prs_t * p ) { Wlc_Obj_t * pObj; char * pStart, * pName; int i; // go through the directives Wlc_PrsForEachLine( p, pStart, i ) { startword: if ( Wlc_PrsStrCmp( pStart, "module" ) ) { // get module name pName = Wlc_PrsStrtok( pStart + strlen("module"), " \r\n\t(,)" ); if ( pName == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read model name." ); // THIS IS A HACK to skip definitions of modules beginning with "CPL_" if ( Wlc_PrsStrCmp( pName, "CPL_" ) ) { while ( ++i < Vec_IntSize(p->vStarts) ) { pStart = Wlc_PrsStr(p, Vec_IntEntry(p->vStarts, i)); pStart = strstr( pStart, "endmodule" ); if ( pStart != NULL ) break; } continue; } if ( Wlc_PrsStrCmp( pName, "table" ) ) { // THIS IS A HACK to detect table module descriptions int Width1 = -1, Width2 = -1; int v, b, Value, nBits, nInts; unsigned * pTable; Vec_Int_t * vValues = Vec_IntAlloc( 256 ); Wlc_PrsForEachLineStart( p, pStart, i, i+1 ) { if ( Wlc_PrsStrCmp( pStart, "endcase" ) ) break; pStart = Wlc_PrsFindSymbol( pStart, '\'' ); if ( pStart == NULL ) continue; Width1 = atoi(pStart-1); pStart = Wlc_PrsFindSymbol( pStart+2, '\'' ); if ( pStart == NULL ) continue; Width2 = atoi(pStart-1); Value = 0; Abc_TtReadHexNumber( (word *)&Value, pStart+2 ); Vec_IntPush( vValues, Value ); } //Vec_IntPrint( vValues ); nBits = Abc_Base2Log( Vec_IntSize(vValues) ); if ( Vec_IntSize(vValues) != (1 << nBits) ) { Vec_IntFree( vValues ); return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read module \"%s\".", pName ); } assert( Width1 == nBits ); // create bitmap nInts = Abc_BitWordNum( Width2 * Vec_IntSize(vValues) ); pTable = (unsigned *)Mem_FlexEntryFetch( p->pMemTable, nInts * sizeof(unsigned) ); memset( pTable, 0, nInts * sizeof(unsigned) ); Vec_IntForEachEntry( vValues, Value, v ) for ( b = 0; b < Width2; b++ ) if ( (Value >> b) & 1 ) Abc_InfoSetBit( pTable, v * Width2 + b ); Vec_PtrPush( p->vTables, pTable ); Vec_IntFree( vValues ); continue; } if ( p->pNtk != NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Network is already defined." ); p->pNtk = Wlc_NtkAlloc( pName, Vec_IntSize(p->vStarts) ); p->pNtk->pManName = Abc_NamStart( Vec_IntSize(p->vStarts), 20 ); p->pNtk->pMemTable = p->pMemTable; p->pMemTable = NULL; p->pNtk->vTables = p->vTables; p->vTables = NULL; // read the argument definitions while ( (pName = Wlc_PrsStrtok( NULL, "(,)" )) ) { pName = Wlc_PrsSkipSpaces( pName ); if ( Wlc_PrsStrCmp( pName, "input" ) || Wlc_PrsStrCmp( pName, "output" ) || Wlc_PrsStrCmp( pName, "wire" ) ) { if ( !Wlc_PrsReadDeclaration( p, pName ) ) return 0; } } } else if ( Wlc_PrsStrCmp( pStart, "endmodule" ) ) { Vec_Int_t * vTemp = Vec_IntStartNatural( Wlc_NtkObjNumMax(p->pNtk) ); Vec_IntAppend( &p->pNtk->vNameIds, vTemp ); Vec_IntFree( vTemp ); if ( p->pNtk->vInits ) { // move FO/FI to be part of CI/CO assert( (Vec_IntSize(&p->pNtk->vFfs) & 1) == 0 ); assert( Vec_IntSize(&p->pNtk->vFfs) == 2 * Vec_IntSize(p->pNtk->vInits) ); Wlc_NtkForEachFf( p->pNtk, pObj, i ) if ( i & 1 ) Wlc_ObjSetCo( p->pNtk, pObj, 1 ); else Wlc_ObjSetCi( p->pNtk, pObj ); Vec_IntClear( &p->pNtk->vFfs ); // convert init values into binary string //Vec_IntPrint( &p->pNtk->vInits ); p->pNtk->pInits = Wlc_PrsConvertInitValues( p->pNtk ); //printf( "%s", p->pNtk->pInits ); } break; } // these are read as part of the interface else if ( Wlc_PrsStrCmp( pStart, "input" ) || Wlc_PrsStrCmp( pStart, "output" ) || Wlc_PrsStrCmp( pStart, "wire" ) || Wlc_PrsStrCmp( pStart, "reg" ) ) { if ( !Wlc_PrsReadDeclaration( p, pStart ) ) return 0; } else if ( Wlc_PrsStrCmp( pStart, "assign" ) ) { int Type, NameId, fFound; pStart += strlen("assign"); // read name pStart = Wlc_PrsFindName( pStart, &pName ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name after assign." ); NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); if ( !fFound ) return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName ); // read definition Type = Wlc_PrsFindDefinition( p, pStart, p->vFanins ); if ( Type ) { pObj = Wlc_NtkObj( p->pNtk, NameId ); Wlc_ObjUpdateType( p->pNtk, pObj, Type ); Wlc_ObjAddFanins( p->pNtk, pObj, p->vFanins ); } else return 0; } else if ( Wlc_PrsStrCmp( pStart, "table" ) ) { // THIS IS A HACK to detect tables int NameId, fFound, iTable = atoi( pStart + strlen("table") ); // find opening pStart = Wlc_PrsFindSymbol( pStart, '(' ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read table." ); // read input pStart = Wlc_PrsFindName( pStart+1, &pName ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name after assign." ); NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); if ( !fFound ) return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName ); // save inputs Vec_IntClear( p->vFanins ); Vec_IntPush( p->vFanins, NameId ); Vec_IntPush( p->vFanins, iTable ); // find comma pStart = Wlc_PrsFindSymbol( pStart, ',' ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read table." ); // read output pStart = Wlc_PrsFindName( pStart+1, &pName ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name after assign." ); NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); if ( !fFound ) return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName ); pObj = Wlc_NtkObj( p->pNtk, NameId ); Wlc_ObjUpdateType( p->pNtk, pObj, WLC_OBJ_TABLE ); Wlc_ObjAddFanins( p->pNtk, pObj, p->vFanins ); } else if ( Wlc_PrsStrCmp( pStart, "always" ) ) { // THIS IS A HACK to detect always statement representing combinational MUX int NameId, NameIdOut = -1, fFound; // find control pStart = Wlc_PrsFindWord( pStart, "case", &fFound ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read case statement." ); // read the name pStart = Wlc_PrsFindSymbol( pStart, '(' ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read table." ); pStart = Wlc_PrsFindSymbol( pStart+1, '(' ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read table." ); pStart = Wlc_PrsFindName( pStart+1, &pName ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name after case." ); NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); if ( !fFound ) return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName ); Vec_IntClear( p->vFanins ); Vec_IntPush( p->vFanins, NameId ); // read data inputs while ( 1 ) { // find opening pStart = Wlc_PrsFindSymbol( pStart, ':' ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot find colon in the case statement." ); // find output name pStart = Wlc_PrsFindName( pStart+1, &pName ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name after case." ); NameIdOut = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); if ( !fFound ) return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName ); // find equality pStart = Wlc_PrsFindSymbol( pStart, '=' ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot find equality in the case statement." ); // find input name pStart = Wlc_PrsSkipSpaces( pStart+1 ); pStart = Wlc_PrsReadName( p, pStart, p->vFanins ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name inside case statement." ); // get next line and check its opening character pStart = Wlc_PrsStr(p, Vec_IntEntry(p->vStarts, ++i)); pStart = Wlc_PrsSkipSpaces( pStart ); if ( Wlc_PrsIsDigit(pStart) ) continue; if ( Wlc_PrsStrCmp( pStart, "default" ) ) { printf( "Ignoring default in Line %d.\n", i ); pStart = Wlc_PrsStr(p, Vec_IntEntry(p->vStarts, ++i)); } // find closing pStart = Wlc_PrsFindWord( pStart, "endcase", &fFound ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read case statement." ); // find closing pStart = Wlc_PrsFindWord( pStart, "end", &fFound ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read case statement." ); pStart = Wlc_PrsSkipSpaces( pStart ); break; } // check range of the control pObj = Wlc_NtkObj( p->pNtk, Vec_IntEntry(p->vFanins, 0) ); if ( (1 << Wlc_ObjRange(pObj)) != Vec_IntSize(p->vFanins) - 1 ) return Wlc_PrsWriteErrorMessage( p, pStart, "The number of values in the case statement is wrong.", pName ); pObj = Wlc_NtkObj( p->pNtk, NameIdOut ); Wlc_ObjUpdateType( p->pNtk, pObj, WLC_OBJ_MUX ); Wlc_ObjAddFanins( p->pNtk, pObj, p->vFanins ); goto startword; } else if ( Wlc_PrsStrCmp( pStart, "CPL_FF" ) ) { int NameId = -1, NameIdIn = -1, NameIdOut = -1, fFound, nBits = 1, fFlopIn, fFlopOut; pStart += strlen("CPL_FF"); if ( pStart[0] == '#' ) nBits = atoi(pStart+1); // read names while ( 1 ) { pStart = Wlc_PrsFindSymbol( pStart, '.' ); if ( pStart == NULL ) break; pStart = Wlc_PrsSkipSpaces( pStart+1 ); if ( pStart[0] != 'd' && (pStart[0] != 'q' || pStart[1] == 'b') && strncmp(pStart, "arstval", 7) ) continue; fFlopIn = (pStart[0] == 'd'); fFlopOut = (pStart[0] == 'q'); pStart = Wlc_PrsFindSymbol( pStart, '(' ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read opening parenthesis in the flop description." ); pStart = Wlc_PrsFindName( pStart+1, &pName ); if ( pStart == NULL ) return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read name inside flop description." ); if ( fFlopIn ) NameIdIn = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); else if ( fFlopOut ) NameIdOut = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); else NameId = Abc_NamStrFindOrAdd( p->pNtk->pManName, pName, &fFound ); if ( !fFound ) return Wlc_PrsWriteErrorMessage( p, pStart, "Name %s is not declared.", pName ); } if ( NameIdIn == -1 || NameIdOut == -1 ) return Wlc_PrsWriteErrorMessage( p, pStart, "Name of flop input or flop output is missing." ); // create flop output pObj = Wlc_NtkObj( p->pNtk, NameIdOut ); Wlc_ObjUpdateType( p->pNtk, pObj, WLC_OBJ_FO ); Vec_IntPush( &p->pNtk->vFfs, NameIdOut ); if ( nBits != Wlc_ObjRange(pObj) ) printf( "Warning! Flop input has bit-width (%d) that differs from the flop declaration (%d)\n", Wlc_ObjRange(pObj), nBits ); // create flop input pObj = Wlc_NtkObj( p->pNtk, NameIdIn ); Vec_IntPush( &p->pNtk->vFfs, NameIdIn ); if ( nBits != Wlc_ObjRange(pObj) ) printf( "Warning! Flop output has bit-width (%d) that differs from the flop declaration (%d)\n", Wlc_ObjRange(pObj), nBits ); // save flop init value if ( NameId == -1 ) printf( "Initial value of flop \"%s\" is not specified. Zero is assumed.\n", Abc_NamStr(p->pNtk->pManName, NameIdOut) ); else { pObj = Wlc_NtkObj( p->pNtk, NameId ); if ( nBits != Wlc_ObjRange(pObj) ) printf( "Warning! Flop init signal bit-width (%d) is different from the flop declaration (%d)\n", Wlc_ObjRange(pObj), nBits ); } if ( p->pNtk->vInits == NULL ) p->pNtk->vInits = Vec_IntAlloc( 100 ); Vec_IntPush( p->pNtk->vInits, NameId > 0 ? NameId : -nBits ); } else if ( pStart[0] != '`' ) { pStart = Wlc_PrsFindName( pStart, &pName ); return Wlc_PrsWriteErrorMessage( p, pStart, "Cannot read line beginning with %s.", pName ); } } return 1; } Wlc_Ntk_t * Wlc_ReadVer( char * pFileName ) { Wlc_Prs_t * p; Wlc_Ntk_t * pNtk = NULL; // start the parser p = Wlc_PrsStart( pFileName ); if ( p == NULL ) return NULL; // detect lines if ( !Wlc_PrsPrepare( p ) ) goto finish; // parse models if ( !Wlc_PrsDerive( p ) ) goto finish; // derive topological order pNtk = Wlc_NtkDupDfs( p->pNtk ); Wlc_NtkTransferNames( pNtk, p->pNtk ); finish: Wlc_PrsPrintErrorMessage( p ); Wlc_PrsStop( p ); return pNtk; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Io_ReadWordTest( char * pFileName ) { Gia_Man_t * pNew; Wlc_Ntk_t * pNtk = Wlc_ReadVer( pFileName ); if ( pNtk == NULL ) return; Wlc_WriteVer( pNtk, "test.v" ); pNew = Wlc_NtkBitBlast( pNtk, NULL ); Gia_AigerWrite( pNew, "test.aig", 0, 0 ); Gia_ManStop( pNew ); Wlc_NtkFree( pNtk ); } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END