diff options
Diffstat (limited to 'src/base/cba/cbaReadVer.c')
-rw-r--r-- | src/base/cba/cbaReadVer.c | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/src/base/cba/cbaReadVer.c b/src/base/cba/cbaReadVer.c new file mode 100644 index 00000000..2000289c --- /dev/null +++ b/src/base/cba/cbaReadVer.c @@ -0,0 +1,528 @@ +/**CFile**************************************************************** + + FileName [cbaReadVer.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 - 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 /// +//////////////////////////////////////////////////////////////////////// + +// Verilog keywords +typedef enum { + CBA_VER_NONE = 0, // 0: unused + CBA_VER_MODULE, // 1: module + CBA_VER_INOUT, // 2: inout + CBA_VER_INPUT, // 3: input + CBA_VER_OUTPUT, // 4: output + CBA_VER_WIRE, // 5: wire + CBA_VER_ASSIGN, // 6: assign + CBA_VER_REG, // 7: reg + CBA_VER_ALWAYS, // 8: always + CBA_VER_DEFPARAM, // 9: always + CBA_VER_BEGIN, // 10: begin + CBA_VER_END, // 11: end + CBA_VER_ENDMODULE, // 12: endmodule + CBA_VER_UNKNOWN // 13: unknown +} Cba_VerType_t; + +const char * s_VerTypes[CBA_VER_UNKNOWN+1] = { + NULL, // 0: unused + "module", // 1: module + "inout", // 2: inout + "input", // 3: input + "output", // 4: output + "wire", // 5: wire + "assign", // 6: assign + "reg", // 7: reg + "always", // 8: always + "defparam", // 9: defparam + "begin", // 10: begin + "end", // 11: end + "endmodule", // 12: endmodule + NULL // 13: unknown +}; + +static inline void Cba_PrsAddVerilogDirectives( Cba_Prs_t * p ) +{ + int i; + for ( i = 1; s_VerTypes[i]; i++ ) + Abc_NamStrFindOrAdd( p->pDesign->pNames, (char *)s_VerTypes[i], NULL ); + assert( Abc_NamObjNumMax(p->pDesign->pNames) == i ); +} + + +// character recognition +static inline int Cba_IsSpace( char c ) { return (c == ' ' || c == '\n' || c == '\t' || c == '\r'); } +static inline int Cba_IsDigit( char c ) { return (c >= '0' && c <= '9'); } +static inline int Cba_IsDigitB( char c ) { return (c >= '0' && c <= '1'); } +static inline int Cba_IsDigitH( char c ) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); } +static inline int Cba_IsChar( char c ) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } +static inline int Cba_IsSymb1( char c ) { return Cba_IsChar(c) || c == '_'; } +static inline int Cba_IsSymb2( char c ) { return Cba_IsSymb1(c) || Cba_IsDigit(c) || c == '$'; } +static inline int Cba_IsSymb( char c ) { return c >= 33 && c <= 126; } +static inline int Cba_IsSymbC( char c ) { return Cba_IsDigit(c) || c == '\'' || c == 'b' || c == 'h' || c == 'd'; } + + +static inline int Cba_PrsOk( Cba_Prs_t * p ) { return p->pCur < p->pLimit && !p->ErrorStr[0]; } +static inline int Cba_PrsIsChar( Cba_Prs_t * p, char c ) { return *p->pCur == c; } +static inline int Cba_PrsIsDigit( Cba_Prs_t * p ) { return Cba_IsDigit(*p->pCur); } + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + +// collect predefined models names +const char * s_KnownModels[100] = { + NULL, + "VERIFIC_", + "reduce_", + "add_", + "mult_", + "Select_", + "LessThan_", + "Decoder_", + "Mux_", + "ReadPort_", + "WritePort_", + "ClockedWritePort_", + NULL +}; + +// check if it is a known module +static inline int Cba_PrsIsKnownModule( Cba_Prs_t * p, char * pName ) +{ + int i; + for ( i = 1; s_KnownModels[i]; i++ ) + if ( !strncmp(pName, s_KnownModels[i], strlen(s_KnownModels[i])) ) + return 1; + return 0; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + +// skip any number of spaces and comments +static inline int Cba_PrsUtilSkipSpaces( Cba_Prs_t * p ) +{ + while ( *p->pCur ) + { + while ( Cba_IsSpace(*p->pCur) ) + p->pCur++; + if ( p->pCur[0] == '/' && p->pCur[1] == '/' ) + { + for ( p->pCur += 2; *p->pCur; p->pCur++ ) + if ( p->pCur[0] == '\n' ) + { p->pCur++; break; } + } + else if ( p->pCur[0] == '/' && p->pCur[1] == '*' ) + { + for ( p->pCur += 2; *p->pCur; p->pCur++ ) + if ( p->pCur[0] == '*' && p->pCur[1] == '/' ) + { p->pCur++; p->pCur++; break; } + } + else return 1; + } + return 0; +} +// skip everything including comments until the given char +static inline int Cba_PrsUtilSkipUntilChar( Cba_Prs_t * p, char c ) +{ + while ( *p->pCur ) + { + if ( *p->pCur == c ) + return 1; + if ( p->pCur[0] == '/' && p->pCur[1] == '/' ) // comment + { + for ( p->pCur += 2; *p->pCur; p->pCur++ ) + if ( p->pCur[0] == '\n' ) + break; + } + else if ( p->pCur[0] == '/' && p->pCur[1] == '*' ) // comment + { + for ( p->pCur += 2; *p->pCur; p->pCur++ ) + if ( p->pCur[0] == '*' && p->pCur[1] == '/' ) + { p->pCur++; break; } + } + else if ( p->pCur[0] == '\\' ) // name + { + for ( p->pCur++; *p->pCur; p->pCur++ ) + if ( p->pCur[0] == ' ' ) + break; + } + if ( *p->pCur == 0 ) + return 0; + p->pCur++; + } + return 0; +} +// skip everything including comments until the given word +static inline int Cba_PrsUtilSkipUntilWord( Cba_Prs_t * p, char * pWord ) +{ + char * pPlace = strstr( p->pCur, pWord ); + if ( pPlace == NULL ) + return 0; + p->pCur = pPlace; + return 1; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + +static inline int Cba_PrsReadName( Cba_Prs_t * p ) +{ + char * pStart = p->pCur; + if ( *p->pCur == '\\' ) // escaped name + { + pStart = ++p->pCur; + while ( !Cba_IsSpace(*p->pCur) ) + p->pCur++; + } + else if ( Cba_IsDigit(*p->pCur) ) // constant + { + while ( Cba_IsDigit(*p->pCur) ) + p->pCur++; + if ( *p->pCur != '\'' ) + return Cba_PrsErrorSet(p, "Cannot read constant.", 0); + p->pCur++; + if ( *p->pCur == 'b' ) + while ( Cba_IsDigitB(*p->pCur) ) + p->pCur++; + else if ( *p->pCur == 'd' ) + while ( Cba_IsDigit(*p->pCur) ) + p->pCur++; + else if ( *p->pCur == 'h' ) + while ( Cba_IsDigitH(*p->pCur) ) + p->pCur++; + else + return Cba_PrsErrorSet(p, "Cannot read radix of constant.", 0); + } + else // simple name + { + if ( !Cba_IsSymb1(*p->pCur) ) + return Cba_PrsErrorSet(p, "Cannot read first character of a name.", 0); + while ( Cba_IsSymb2(*p->pCur) ) + p->pCur++; + } + if ( pStart == p->pCur ) + return Cba_PrsErrorSet(p, "Cannot read name.", 0); + return Abc_NamStrFindOrAddLim( p->pDesign->pNames, pStart, p->pCur, NULL ); +} + +static inline int Cba_PrsReadRange( Cba_Prs_t * p ) +{ + if ( !Cba_PrsIsChar(p, '[') ) + return 0; + Vec_StrClear( p->vCover ); + Vec_StrPush( p->vCover, *p->pCur++ ); + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsIsDigit(p) ) return Cba_PrsErrorSet(p, "Cannot read digit in range specification.", 2); + while ( Cba_PrsIsDigit(p) ) + Vec_StrPush( p->vCover, *p->pCur++ ); + Cba_PrsUtilSkipSpaces( p ); + if ( Cba_PrsIsChar(p, ':') ) + { + Vec_StrPush( p->vCover, *p->pCur++ ); + if ( !Cba_PrsIsDigit(p) ) return Cba_PrsErrorSet(p, "Cannot read digit in range specification.", 2); + while ( Cba_PrsIsDigit(p) ) + Vec_StrPush( p->vCover, *p->pCur++ ); + Cba_PrsUtilSkipSpaces( p ); + } + if ( !Cba_PrsIsChar(p, ']') ) return Cba_PrsErrorSet(p, "Cannot read closing brace in range specification.", 2); + Vec_StrPush( p->vCover, *p->pCur++ ); + return Abc_NamStrFindOrAddLim( p->pDesign->pNames, Vec_StrArray(p->vCover), Vec_StrArray(p->vCover)+Vec_StrSize(p->vCover), NULL ); +} +static inline void Cba_PrsReadSignalList( Cba_Prs_t * p, Vec_Int_t * vTemp ) +{ + int NameId, RangeId; + Vec_IntClear( vTemp ); + while ( 1 ) + { + Cba_PrsUtilSkipSpaces( p ); + NameId = Cba_PrsReadName( p ); + Cba_PrsUtilSkipSpaces( p ); + RangeId = Cba_PrsReadRange( p ); + Vec_IntPushTwo( vTemp, NameId, RangeId ); + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsIsChar(p, ',') ) + break; + p->pCur++; + } +} +static inline int Cba_PrsReadDeclaration( Cba_Prs_t * p, int Type ) +{ + int NameId, RangeId, RangeIdTemp; + Vec_Int_t * vSigs[4] = { p->vInoutsCur, p->vInputsCur, p->vOutputsCur, p->vWiresCur }; + assert( Type >= CBA_VER_INOUT && Type <= CBA_VER_WIRE ); + Cba_PrsUtilSkipSpaces( p ); + RangeId = Cba_PrsReadRange( p ); + Cba_PrsReadSignalList( p, p->vTemp ); + Vec_IntForEachEntryDouble( p->vTemp, NameId, RangeId, RangeIdTemp ) + { + if ( !RangeIdTemp ) return Cba_PrsErrorSet(p, "Range is specified twice in the declaration.", 0); + Vec_IntPushTwo( vSigs[Type - CBA_VER_INOUT], NameId, RangeId ); + } + return 1; +} +static inline int Cba_PrsReadConcat( Cba_Prs_t * p ) +{ + int iToken = Vec_WecSize( p->vFaninsCur ); + assert( Cba_PrsIsChar(p, '{') ); + p->pCur++; + Cba_PrsReadSignalList( p, p->vTemp2 ); + if ( !Cba_PrsIsChar(p, '}') ) return Cba_PrsErrorSet(p, "Cannot read concatenation.", 0); + p->pCur++; + // assign + Vec_IntPush( p->vTypesCur, CBA_PRS_CONCAT ); + Vec_IntPush( p->vFuncsCur, 0 ); + Vec_IntPush( p->vInstIdsCur, 0 ); + Cba_PrsSetupVecInt( p, Vec_WecPushLevel(p->vFaninsCur), p->vTemp2 ); + return iToken; +} + +static inline int Cba_PrsReadInstance( Cba_Prs_t * p, int Func ) +{ + // have to assign Type, Func, InstId, vFanins + int FormId, NameId, RangeId, Type, InstId; + Vec_IntClear( p->vTemp ); + Cba_PrsUtilSkipSpaces( p ); + if ( Cba_PrsIsChar(p, '(') ) // node + { + Type = CBA_PRS_NODE; + InstId = 0; + p->pCur++; + while ( 1 ) + { + Cba_PrsUtilSkipSpaces( p ); + if ( Cba_PrsIsChar(p, '{') ) + { + NameId = 0; + RangeId = Cba_PrsReadConcat( p ); + } + else + { + NameId = Cba_PrsReadName( p ); + RangeId = Cba_PrsReadRange( p ); + } + Vec_IntPushTwo( p->vTemp, NameId, RangeId ); + Cba_PrsUtilSkipSpaces( p ); + if ( Cba_PrsIsChar(p, ')') ) + break; + if ( !Cba_PrsIsChar(p, ',') ) return Cba_PrsErrorSet(p, "Expecting comma in the instance definition.", 2); + p->pCur++; + } + } + else // box + { + Type = CBA_PRS_BOX; + InstId = Cba_PrsReadName( p ); + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsIsChar(p, '(') ) return Cba_PrsErrorSet(p, "Expecting opening paranthesis in the instance definition.", 2); + p->pCur++; + while ( 1 ) + { + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsIsChar(p, '.') ) return Cba_PrsErrorSet(p, "Expecting dot before the formal name.", 2); + p->pCur++; + FormId = Cba_PrsReadName( p ); + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsIsChar(p, '(') ) return Cba_PrsErrorSet(p, "Expecting opening paranthesis after the formal name.", 2); + p->pCur++; + Cba_PrsUtilSkipSpaces( p ); + if ( Cba_PrsIsChar(p, '{') ) + { + NameId = 0; + RangeId = Cba_PrsReadConcat( p ); + } + else + { + NameId = Cba_PrsReadName( p ); + RangeId = Cba_PrsReadRange( p ); + } + Vec_IntPushTwo( p->vTemp, NameId, RangeId ); + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsIsChar(p, ')') ) return Cba_PrsErrorSet(p, "Expecting opening paranthesis after the acctual name.", 2); + p->pCur++; + Cba_PrsUtilSkipSpaces( p ); + if ( Cba_PrsIsChar(p, ')') ) + break; + if ( !Cba_PrsIsChar(p, ',') ) return Cba_PrsErrorSet(p, "Expecting comma in the instance definition.", 2); + p->pCur++; + } + } + // assign + Vec_IntPush( p->vTypesCur, Type ); + Vec_IntPush( p->vFuncsCur, Func ); + Vec_IntPush( p->vInstIdsCur, InstId ); + Cba_PrsSetupVecInt( p, Vec_WecPushLevel(p->vFaninsCur), p->vTemp ); + return 0; +} + +// this procedure can return: +// 0 = reached end-of-file; 1 = successfully parsed; 2 = failed and skipped; 3 = error (failed and could not skip) +static inline int Cba_PrsReadModule( Cba_Prs_t * p ) +{ + int fKnown, iToken, iNameId; + assert( Vec_IntSize(p->vInputsCur) == 0 && Vec_IntSize(p->vOutputsCur) == 0 ); + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsOk(p) ) return 0; + // read keyword + iToken = Cba_PrsReadName( p ); + if (iToken != CBA_VER_MODULE) return Cba_PrsErrorSet(p, "Cannot read \"module\" keyword.", 3); + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsOk(p) ) return Cba_PrsErrorSet(p, "Module declaration ends abruptly.", 3); + // read module name + iToken = iNameId = Cba_PrsReadName( p ); + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsOk(p) ) return Cba_PrsErrorSet(p, "Module declaration ends abruptly.", 3); + // check if module is known + fKnown = Cba_PrsIsKnownModule( p, Abc_NamStr(p->pDesign->pNames, iNameId) ); + // skip arguments + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsOk(p) ) return Cba_PrsErrorSet(p, "Module declaration ends abruptly.", 3); + if ( !Cba_PrsIsChar(p, '(') ) return Cba_PrsErrorSet(p, "Cannot find \"(\" in the argument declaration.", 3); + Cba_PrsUtilSkipUntilChar( p, ')' ); + if ( !Cba_PrsOk(p) ) return Cba_PrsErrorSet(p, "Module declaration ends abruptly.", 3); + assert( *p->pCur == ')' ); + // find semicolumn + p->pCur++; + Cba_PrsUtilSkipSpaces( p ); + if ( !Cba_PrsOk(p) ) return Cba_PrsErrorSet(p, "Module declaration ends abruptly.", 3); + // read declarations and instances + while ( Cba_PrsIsChar(p, ';') ) + { + p->pCur++; + iToken = Cba_PrsReadName( p ); + if ( iToken == CBA_VER_ENDMODULE ) + { + Cba_PrsAddCurrentModel( p, iNameId ); + return 0; + } + if ( iToken == CBA_VER_ALWAYS ) + { + Cba_PrsUtilSkipUntilWord( p, "endmodule" ); + if ( !Cba_PrsOk(p) ) return Cba_PrsErrorSet(p, "Module definition ends abruptly.", 3); + Cba_PrsAddCurrentModel( p, iNameId ); + return 2; + } + if ( iToken >= CBA_VER_INOUT && iToken <= CBA_VER_WIRE ) // declaration + Cba_PrsReadDeclaration( p, iToken ); + else if ( iToken == CBA_VER_REG || iToken == CBA_VER_DEFPARAM ) // unsupported keywords + Cba_PrsUtilSkipUntilChar( p, ';' ); + else if ( !fKnown ) // read instance + Cba_PrsReadInstance( p, iToken ); + else // skip known instance + Cba_PrsUtilSkipUntilChar( p, ';' ); + } + return Cba_PrsErrorSet(p, "Cannot find \";\" in the module definition.", 3); + +} +static inline int Cba_PrsReadDesign( Cba_Prs_t * p ) +{ + while ( 1 ) + { + int RetValue = Cba_PrsReadModule( p ); + if ( RetValue == 0 ) // success + return 1; + if ( RetValue == 1 ) // end of file + continue; + if ( RetValue == 2 ) // failed and skipped + continue; + if ( RetValue == 3 ) // error + return 0; + assert( 0 ); + } + return 0; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cba_Man_t * Cba_PrsReadVerilog( char * pFileName ) +{ + Cba_Man_t * pDesign = NULL; + Cba_Prs_t * p = Cba_PrsAlloc( pFileName ); + if ( p == NULL ) + return NULL; + Cba_PrsAddVerilogDirectives( p ); + Cba_PrsReadDesign( p ); + if ( Cba_PrsErrorPrint(p) ) + ABC_SWAP( Cba_Man_t *, pDesign, p->pDesign ); + Cba_PrsFree( p ); + return pDesign; +} +void Cba_PrsTest( char * pFileName ) +{ + Cba_Man_t * pDes = Cba_PrsReadVerilog( pFileName ); + Cba_PrsWriteVerilog( "__Test__.v", pDes ); + Cba_ManFree( pDes ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + |