/**CFile**************************************************************** FileName [verFormula.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Verilog parser.] Synopsis [Formula parser to read Verilog assign statements.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - August 19, 2006.] Revision [$Id: verFormula.c,v 1.00 2006/08/19 00:00:00 alanmi Exp $] ***********************************************************************/ #include "ver.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// // the list of operation symbols to be used in expressions #define VER_PARSE_SYM_OPEN '(' // opening parenthesis #define VER_PARSE_SYM_CLOSE ')' // closing parenthesis #define VER_PARSE_SYM_CONST0 '0' // constant 0 #define VER_PARSE_SYM_CONST1 '1' // constant 1 #define VER_PARSE_SYM_NEGBEF1 '!' // negation before the variable #define VER_PARSE_SYM_NEGBEF2 '~' // negation before the variable #define VER_PARSE_SYM_AND '&' // logic AND #define VER_PARSE_SYM_OR '|' // logic OR #define VER_PARSE_SYM_XOR '^' // logic XOR #define VER_PARSE_SYM_MUX1 '?' // first symbol of MUX #define VER_PARSE_SYM_MUX2 ':' // second symbol of MUX // the list of opcodes (also specifying operation precedence) #define VER_PARSE_OPER_NEG 7 // negation (highest precedence) #define VER_PARSE_OPER_AND 6 // logic AND #define VER_PARSE_OPER_XOR 5 // logic EXOR (a'b | ab') #define VER_PARSE_OPER_OR 4 // logic OR #define VER_PARSE_OPER_EQU 3 // equvalence (a'b'| ab ) #define VER_PARSE_OPER_MUX 2 // MUX(a,b,c) (ab | a'c ) #define VER_PARSE_OPER_MARK 1 // OpStack token standing for an opening parenthesis // these are values of the internal Flag #define VER_PARSE_FLAG_START 1 // after the opening parenthesis #define VER_PARSE_FLAG_VAR 2 // after operation is received #define VER_PARSE_FLAG_OPER 3 // after operation symbol is received #define VER_PARSE_FLAG_ERROR 4 // when error is detected static Hop_Obj_t * Ver_FormulaParserTopOper( Hop_Man_t * pMan, Vec_Ptr_t * vStackFn, int Oper ); static int Ver_FormulaParserFindVar( char * pString, Vec_Ptr_t * vNames ); //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Parser of the formula encountered in assign statements.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void * Ver_FormulaParser( char * pFormula, void * pMan, Vec_Ptr_t * vNames, Vec_Ptr_t * vStackFn, Vec_Int_t * vStackOp, char * pErrorMessage ) { char * pTemp; Hop_Obj_t * bFunc, * bTemp; int nParans, Flag; int Oper, Oper1, Oper2; int v; // clear the stacks and the names Vec_PtrClear( vNames ); Vec_PtrClear( vStackFn ); Vec_IntClear( vStackOp ); if ( !strcmp(pFormula, "0") || !strcmp(pFormula, "1\'b0") ) return Hop_ManConst0((Hop_Man_t *)pMan); if ( !strcmp(pFormula, "1") || !strcmp(pFormula, "1\'b1") ) return Hop_ManConst1((Hop_Man_t *)pMan); // make sure that the number of opening and closing parentheses is the same nParans = 0; for ( pTemp = pFormula; *pTemp; pTemp++ ) if ( *pTemp == '(' ) nParans++; else if ( *pTemp == ')' ) nParans--; if ( nParans != 0 ) { sprintf( pErrorMessage, "Parse_FormulaParser(): Different number of opening and closing parentheses ()." ); return NULL; } // add parentheses pTemp = pFormula + strlen(pFormula) + 2; *pTemp-- = 0; *pTemp = ')'; while ( --pTemp != pFormula ) *pTemp = *(pTemp - 1); *pTemp = '('; // perform parsing Flag = VER_PARSE_FLAG_START; for ( pTemp = pFormula; *pTemp; pTemp++ ) { switch ( *pTemp ) { // skip all spaces, tabs, and end-of-lines case ' ': case '\t': case '\r': case '\n': continue; /* // treat Constant 0 as a variable case VER_PARSE_SYM_CONST0: Vec_PtrPush( vStackFn, Hop_ManConst0(pMan) ); // Cudd_Ref( Hop_ManConst0(pMan) ); if ( Flag == VER_PARSE_FLAG_VAR ) { sprintf( pErrorMessage, "Parse_FormulaParser(): No operation symbol before constant 0." ); Flag = VER_PARSE_FLAG_ERROR; break; } Flag = VER_PARSE_FLAG_VAR; break; // the same for Constant 1 case VER_PARSE_SYM_CONST1: Vec_PtrPush( vStackFn, Hop_ManConst1(pMan) ); // Cudd_Ref( Hop_ManConst1(pMan) ); if ( Flag == VER_PARSE_FLAG_VAR ) { sprintf( pErrorMessage, "Parse_FormulaParser(): No operation symbol before constant 1." ); Flag = VER_PARSE_FLAG_ERROR; break; } Flag = VER_PARSE_FLAG_VAR; break; */ case VER_PARSE_SYM_NEGBEF1: case VER_PARSE_SYM_NEGBEF2: if ( Flag == VER_PARSE_FLAG_VAR ) {// if NEGBEF follows a variable, AND is assumed sprintf( pErrorMessage, "Parse_FormulaParser(): Variable before negation." ); Flag = VER_PARSE_FLAG_ERROR; break; } Vec_IntPush( vStackOp, VER_PARSE_OPER_NEG ); break; case VER_PARSE_SYM_AND: case VER_PARSE_SYM_OR: case VER_PARSE_SYM_XOR: case VER_PARSE_SYM_MUX1: case VER_PARSE_SYM_MUX2: if ( Flag != VER_PARSE_FLAG_VAR ) { sprintf( pErrorMessage, "Parse_FormulaParser(): There is no variable before AND, EXOR, or OR." ); Flag = VER_PARSE_FLAG_ERROR; break; } if ( *pTemp == VER_PARSE_SYM_AND ) Vec_IntPush( vStackOp, VER_PARSE_OPER_AND ); else if ( *pTemp == VER_PARSE_SYM_OR ) Vec_IntPush( vStackOp, VER_PARSE_OPER_OR ); else if ( *pTemp == VER_PARSE_SYM_XOR ) Vec_IntPush( vStackOp, VER_PARSE_OPER_XOR ); else if ( *pTemp == VER_PARSE_SYM_MUX1 ) Vec_IntPush( vStackOp, VER_PARSE_OPER_MUX ); // else if ( *pTemp == VER_PARSE_SYM_MUX2 ) // Vec_IntPush( vStackOp, VER_PARSE_OPER_MUX ); Flag = VER_PARSE_FLAG_OPER; break; case VER_PARSE_SYM_OPEN: if ( Flag == VER_PARSE_FLAG_VAR ) { sprintf( pErrorMessage, "Parse_FormulaParser(): Variable before a parenthesis." ); Flag = VER_PARSE_FLAG_ERROR; break; } Vec_IntPush( vStackOp, VER_PARSE_OPER_MARK ); // after an opening bracket, it feels like starting over again Flag = VER_PARSE_FLAG_START; break; case VER_PARSE_SYM_CLOSE: if ( Vec_IntSize( vStackOp ) ) { while ( 1 ) { if ( !Vec_IntSize( vStackOp ) ) { sprintf( pErrorMessage, "Parse_FormulaParser(): There is no opening parenthesis\n" ); Flag = VER_PARSE_FLAG_ERROR; break; } Oper = Vec_IntPop( vStackOp ); if ( Oper == VER_PARSE_OPER_MARK ) break; // skip the second MUX operation // if ( Oper == VER_PARSE_OPER_MUX2 ) // { // Oper = Vec_IntPop( vStackOp ); // assert( Oper == VER_PARSE_OPER_MUX1 ); // } // perform the given operation if ( Ver_FormulaParserTopOper( (Hop_Man_t *)pMan, vStackFn, Oper ) == NULL ) { sprintf( pErrorMessage, "Parse_FormulaParser(): Unknown operation\n" ); return NULL; } } } else { sprintf( pErrorMessage, "Parse_FormulaParser(): There is no opening parenthesis\n" ); Flag = VER_PARSE_FLAG_ERROR; break; } if ( Flag != VER_PARSE_FLAG_ERROR ) Flag = VER_PARSE_FLAG_VAR; break; default: // scan the next name v = Ver_FormulaParserFindVar( pTemp, vNames ); if ( *pTemp == '\\' ) pTemp++; pTemp += (int)(ABC_PTRUINT_T)Vec_PtrEntry( vNames, 2*v ) - 1; // assume operation AND, if vars follow one another if ( Flag == VER_PARSE_FLAG_VAR ) { sprintf( pErrorMessage, "Parse_FormulaParser(): Incorrect state." ); return NULL; } bTemp = Hop_IthVar( (Hop_Man_t *)pMan, v ); Vec_PtrPush( vStackFn, bTemp ); // Cudd_Ref( bTemp ); Flag = VER_PARSE_FLAG_VAR; break; } if ( Flag == VER_PARSE_FLAG_ERROR ) break; // error exit else if ( Flag == VER_PARSE_FLAG_START ) continue; // go on parsing else if ( Flag == VER_PARSE_FLAG_VAR ) while ( 1 ) { // check if there are negations in the OpStack if ( !Vec_IntSize(vStackOp) ) break; Oper = Vec_IntPop( vStackOp ); if ( Oper != VER_PARSE_OPER_NEG ) { Vec_IntPush( vStackOp, Oper ); break; } else { // Vec_PtrPush( vStackFn, Cudd_Not(Vec_PtrPop(vStackFn)) ); Vec_PtrPush( vStackFn, Hop_Not((Hop_Obj_t *)Vec_PtrPop(vStackFn)) ); } } else // if ( Flag == VER_PARSE_FLAG_OPER ) while ( 1 ) { // execute all the operations in the OpStack // with precedence higher or equal than the last one Oper1 = Vec_IntPop( vStackOp ); // the last operation if ( !Vec_IntSize(vStackOp) ) { // if it is the only operation, push it back Vec_IntPush( vStackOp, Oper1 ); break; } Oper2 = Vec_IntPop( vStackOp ); // the operation before the last one if ( Oper2 >= Oper1 && !(Oper1 == Oper2 && Oper1 == VER_PARSE_OPER_MUX) ) { // if Oper2 precedence is higher or equal, execute it if ( Ver_FormulaParserTopOper( (Hop_Man_t *)pMan, vStackFn, Oper2 ) == NULL ) { sprintf( pErrorMessage, "Parse_FormulaParser(): Unknown operation\n" ); return NULL; } Vec_IntPush( vStackOp, Oper1 ); // push the last operation back } else { // if Oper2 precedence is lower, push them back and done Vec_IntPush( vStackOp, Oper2 ); Vec_IntPush( vStackOp, Oper1 ); break; } } } if ( Flag != VER_PARSE_FLAG_ERROR ) { if ( Vec_PtrSize(vStackFn) ) { bFunc = (Hop_Obj_t *)Vec_PtrPop(vStackFn); if ( !Vec_PtrSize(vStackFn) ) if ( !Vec_IntSize(vStackOp) ) { // Cudd_Deref( bFunc ); return bFunc; } else sprintf( pErrorMessage, "Parse_FormulaParser(): Something is left in the operation stack\n" ); else sprintf( pErrorMessage, "Parse_FormulaParser(): Something is left in the function stack\n" ); } else sprintf( pErrorMessage, "Parse_FormulaParser(): The input string is empty\n" ); } // Cudd_Ref( bFunc ); // Cudd_RecursiveDeref( dd, bFunc ); return NULL; } /**Function************************************************************* Synopsis [Performs the operation on the top entries in the stack.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Hop_Obj_t * Ver_FormulaParserTopOper( Hop_Man_t * pMan, Vec_Ptr_t * vStackFn, int Oper ) { Hop_Obj_t * bArg0, * bArg1, * bArg2, * bFunc; // perform the given operation bArg2 = (Hop_Obj_t *)Vec_PtrPop( vStackFn ); bArg1 = (Hop_Obj_t *)Vec_PtrPop( vStackFn ); if ( Oper == VER_PARSE_OPER_AND ) bFunc = Hop_And( pMan, bArg1, bArg2 ); else if ( Oper == VER_PARSE_OPER_XOR ) bFunc = Hop_Exor( pMan, bArg1, bArg2 ); else if ( Oper == VER_PARSE_OPER_OR ) bFunc = Hop_Or( pMan, bArg1, bArg2 ); else if ( Oper == VER_PARSE_OPER_EQU ) bFunc = Hop_Not( Hop_Exor( pMan, bArg1, bArg2 ) ); else if ( Oper == VER_PARSE_OPER_MUX ) { bArg0 = (Hop_Obj_t *)Vec_PtrPop( vStackFn ); // bFunc = Cudd_bddIte( dd, bArg0, bArg1, bArg2 ); Cudd_Ref( bFunc ); bFunc = Hop_Mux( pMan, bArg0, bArg1, bArg2 ); // Cudd_RecursiveDeref( dd, bArg0 ); // Cudd_Deref( bFunc ); } else return NULL; // Cudd_Ref( bFunc ); // Cudd_RecursiveDeref( dd, bArg1 ); // Cudd_RecursiveDeref( dd, bArg2 ); Vec_PtrPush( vStackFn, bFunc ); return bFunc; } /**Function************************************************************* Synopsis [Returns the index of the new variable found.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Ver_FormulaParserFindVar( char * pString, Vec_Ptr_t * vNames ) { char * pTemp, * pTemp2; int nLength, nLength2, i; // start the string pTemp = pString; // find the end of the string delimited by other characters if ( *pTemp == '\\' ) { pString++; while ( *pTemp && *pTemp != ' ' ) pTemp++; } else { while ( *pTemp && *pTemp != ' ' && *pTemp != '\t' && *pTemp != '\r' && *pTemp != '\n' && *pTemp != ',' && *pTemp != '}' && *pTemp != VER_PARSE_SYM_OPEN && *pTemp != VER_PARSE_SYM_CLOSE && *pTemp != VER_PARSE_SYM_NEGBEF1 && *pTemp != VER_PARSE_SYM_NEGBEF2 && *pTemp != VER_PARSE_SYM_AND && *pTemp != VER_PARSE_SYM_OR && *pTemp != VER_PARSE_SYM_XOR && *pTemp != VER_PARSE_SYM_MUX1 && *pTemp != VER_PARSE_SYM_MUX2 ) pTemp++; } // look for this string in the array nLength = pTemp - pString; for ( i = 0; i < Vec_PtrSize(vNames)/2; i++ ) { nLength2 = (int)(ABC_PTRUINT_T)Vec_PtrEntry( vNames, 2*i + 0 ); if ( nLength2 != nLength ) continue; pTemp2 = (char *)Vec_PtrEntry( vNames, 2*i + 1 ); if ( strncmp( pString, pTemp2, nLength ) ) continue; return i; } // could not find - add and return the number Vec_PtrPush( vNames, (void *)(ABC_PTRUINT_T)nLength ); Vec_PtrPush( vNames, pString ); return i; } /**Function************************************************************* Synopsis [Returns the AIG representation of the reduction formula.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void * Ver_FormulaReduction( char * pFormula, void * pMan, Vec_Ptr_t * vNames, char * pErrorMessage ) { Hop_Obj_t * pRes = NULL; int v, fCompl; char Symbol; // get the operation Symbol = *pFormula++; fCompl = ( Symbol == '~' ); if ( fCompl ) Symbol = *pFormula++; // check the operation if ( Symbol != '&' && Symbol != '|' && Symbol != '^' ) { sprintf( pErrorMessage, "Ver_FormulaReduction(): Unknown operation (%c)\n", Symbol ); return NULL; } // skip the brace while ( *pFormula++ != '{' ); // parse the names Vec_PtrClear( vNames ); while ( *pFormula != '}' ) { v = Ver_FormulaParserFindVar( pFormula, vNames ); pFormula += (int)(ABC_PTRUINT_T)Vec_PtrEntry( vNames, 2*v ); while ( *pFormula == ' ' || *pFormula == ',' ) pFormula++; } // compute the function if ( Symbol == '&' ) pRes = Hop_CreateAnd( (Hop_Man_t *)pMan, Vec_PtrSize(vNames)/2 ); else if ( Symbol == '|' ) pRes = Hop_CreateOr( (Hop_Man_t *)pMan, Vec_PtrSize(vNames)/2 ); else if ( Symbol == '^' ) pRes = Hop_CreateExor( (Hop_Man_t *)pMan, Vec_PtrSize(vNames)/2 ); return Hop_NotCond( pRes, fCompl ); } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END