summaryrefslogtreecommitdiffstats
path: root/src/base/cba/cbaReadVer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/cba/cbaReadVer.c')
-rw-r--r--src/base/cba/cbaReadVer.c528
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
+