mirror of https://github.com/YosysHQ/abc.git
500 lines
18 KiB
C
500 lines
18 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [mioParse.c]
|
|
|
|
PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
|
|
|
|
Synopsis [Parsing Boolean expressions.]
|
|
|
|
Author [MVSIS Group]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - September 8, 2003.]
|
|
|
|
Revision [$Id: mioParse.c,v 1.4 2004/06/28 14:20:25 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "mioInt.h"
|
|
#include "exp.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// the list of operation symbols to be used in expressions
|
|
#define MIO_EQN_SYM_OPEN '(' // opening paranthesis
|
|
#define MIO_EQN_SYM_CLOSE ')' // closing paranthesis
|
|
#define MIO_EQN_SYM_CONST0 '0' // constant 0
|
|
#define MIO_EQN_SYM_CONST1 '1' // constant 1
|
|
#define MIO_EQN_SYM_NEG '!' // negation before the variable
|
|
#define MIO_EQN_SYM_NEGAFT '\'' // negation after the variable
|
|
#define MIO_EQN_SYM_AND '*' // logic AND
|
|
#define MIO_EQN_SYM_AND2 '&' // logic AND
|
|
#define MIO_EQN_SYM_XOR '^' // logic XOR
|
|
#define MIO_EQN_SYM_OR '+' // logic OR
|
|
#define MIO_EQN_SYM_OR2 '|' // logic OR
|
|
|
|
// the list of opcodes (also specifying operation precedence)
|
|
#define MIO_EQN_OPER_NEG 10 // negation
|
|
#define MIO_EQN_OPER_AND 9 // logic AND
|
|
#define MIO_EQN_OPER_XOR 8 // logic XOR
|
|
#define MIO_EQN_OPER_OR 7 // logic OR
|
|
#define MIO_EQN_OPER_MARK 1 // OpStack token standing for an opening paranthesis
|
|
|
|
// these are values of the internal Flag
|
|
#define MIO_EQN_FLAG_START 1 // after the opening parenthesis
|
|
#define MIO_EQN_FLAG_VAR 2 // after operation is received
|
|
#define MIO_EQN_FLAG_OPER 3 // after operation symbol is received
|
|
#define MIO_EQN_FLAG_ERROR 4 // when error is detected
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs the operation on the top entries in the stack.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Int_t * Mio_ParseFormulaOper( int * pMan, int nVars, Vec_Ptr_t * pStackFn, int Oper )
|
|
{
|
|
Vec_Int_t * gArg1, * gArg2, * gFunc;
|
|
// perform the given operation
|
|
gArg2 = (Vec_Int_t *)Vec_PtrPop( pStackFn );
|
|
gArg1 = (Vec_Int_t *)Vec_PtrPop( pStackFn );
|
|
if ( Oper == MIO_EQN_OPER_AND )
|
|
gFunc = Exp_And( pMan, nVars, gArg1, gArg2, 0, 0 );
|
|
else if ( Oper == MIO_EQN_OPER_OR )
|
|
gFunc = Exp_Or( pMan, nVars, gArg1, gArg2 );
|
|
else if ( Oper == MIO_EQN_OPER_XOR )
|
|
gFunc = Exp_Xor( pMan, nVars, gArg1, gArg2 );
|
|
else
|
|
return NULL;
|
|
// Cudd_Ref( gFunc );
|
|
// Cudd_RecursiveDeref( dd, gArg1 );
|
|
// Cudd_RecursiveDeref( dd, gArg2 );
|
|
Vec_IntFree( gArg1 );
|
|
Vec_IntFree( gArg2 );
|
|
Vec_PtrPush( pStackFn, gFunc );
|
|
return gFunc;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Derives the AIG corresponding to the equation.]
|
|
|
|
Description [Takes the stream to output messages, the formula, the vector
|
|
of variable names and the AIG manager.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Int_t * Mio_ParseFormula( char * pFormInit, char ** ppVarNames, int nVars )
|
|
{
|
|
char * pFormula;
|
|
int Man = nVars, * pMan = &Man;
|
|
Vec_Ptr_t * pStackFn;
|
|
Vec_Int_t * pStackOp;
|
|
Vec_Int_t * gFunc;
|
|
char * pTemp, * pName;
|
|
int nParans, fFound, Flag;
|
|
int Oper, Oper1, Oper2;
|
|
int i, v;
|
|
|
|
// make sure that the number of opening and closing parantheses is the same
|
|
nParans = 0;
|
|
for ( pTemp = pFormInit; *pTemp; pTemp++ )
|
|
if ( *pTemp == '(' )
|
|
nParans++;
|
|
else if ( *pTemp == ')' )
|
|
nParans--;
|
|
if ( nParans != 0 )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): Different number of opening and closing parantheses ().\n" );
|
|
return NULL;
|
|
}
|
|
|
|
// copy the formula
|
|
pFormula = ABC_ALLOC( char, strlen(pFormInit) + 3 );
|
|
sprintf( pFormula, "(%s)", pFormInit );
|
|
|
|
// start the stacks
|
|
pStackFn = Vec_PtrAlloc( 100 );
|
|
pStackOp = Vec_IntAlloc( 100 );
|
|
|
|
Flag = MIO_EQN_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;
|
|
case MIO_EQN_SYM_CONST0:
|
|
Vec_PtrPush( pStackFn, Exp_Const0() ); // Cudd_Ref( b0 );
|
|
if ( Flag == MIO_EQN_FLAG_VAR )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): No operation symbol before constant 0.\n" );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
Flag = MIO_EQN_FLAG_VAR;
|
|
break;
|
|
case MIO_EQN_SYM_CONST1:
|
|
Vec_PtrPush( pStackFn, Exp_Const1() ); // Cudd_Ref( b1 );
|
|
if ( Flag == MIO_EQN_FLAG_VAR )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): No operation symbol before constant 1.\n" );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
Flag = MIO_EQN_FLAG_VAR;
|
|
break;
|
|
case MIO_EQN_SYM_NEG:
|
|
if ( Flag == MIO_EQN_FLAG_VAR )
|
|
{// if NEGBEF follows a variable, AND is assumed
|
|
Vec_IntPush( pStackOp, MIO_EQN_OPER_AND );
|
|
Flag = MIO_EQN_FLAG_OPER;
|
|
}
|
|
Vec_IntPush( pStackOp, MIO_EQN_OPER_NEG );
|
|
break;
|
|
case MIO_EQN_SYM_NEGAFT:
|
|
if ( Flag != MIO_EQN_FLAG_VAR )
|
|
{// if there is no variable before NEGAFT, it is an error
|
|
fprintf( stdout, "Mio_ParseFormula(): No variable is specified before the negation suffix.\n" );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
else // if ( Flag == PARSE_FLAG_VAR )
|
|
Vec_PtrPush( pStackFn, Exp_Not( (Vec_Int_t *)Vec_PtrPop(pStackFn) ) );
|
|
break;
|
|
case MIO_EQN_SYM_AND:
|
|
case MIO_EQN_SYM_AND2:
|
|
case MIO_EQN_SYM_OR:
|
|
case MIO_EQN_SYM_OR2:
|
|
case MIO_EQN_SYM_XOR:
|
|
if ( Flag != MIO_EQN_FLAG_VAR )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): There is no variable before AND, EXOR, or OR.\n" );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
if ( *pTemp == MIO_EQN_SYM_AND || *pTemp == MIO_EQN_SYM_AND2 )
|
|
Vec_IntPush( pStackOp, MIO_EQN_OPER_AND );
|
|
else if ( *pTemp == MIO_EQN_SYM_OR || *pTemp == MIO_EQN_SYM_OR2 )
|
|
Vec_IntPush( pStackOp, MIO_EQN_OPER_OR );
|
|
else //if ( *pTemp == MIO_EQN_SYM_XOR )
|
|
Vec_IntPush( pStackOp, MIO_EQN_OPER_XOR );
|
|
Flag = MIO_EQN_FLAG_OPER;
|
|
break;
|
|
case MIO_EQN_SYM_OPEN:
|
|
if ( Flag == MIO_EQN_FLAG_VAR )
|
|
{
|
|
Vec_IntPush( pStackOp, MIO_EQN_OPER_AND );
|
|
// fprintf( stdout, "Mio_ParseFormula(): An opening paranthesis follows a var without operation sign.\n" );
|
|
// Flag = MIO_EQN_FLAG_ERROR;
|
|
// break;
|
|
}
|
|
Vec_IntPush( pStackOp, MIO_EQN_OPER_MARK );
|
|
// after an opening bracket, it feels like starting over again
|
|
Flag = MIO_EQN_FLAG_START;
|
|
break;
|
|
case MIO_EQN_SYM_CLOSE:
|
|
if ( Vec_IntSize( pStackOp ) != 0 )
|
|
{
|
|
while ( 1 )
|
|
{
|
|
if ( Vec_IntSize( pStackOp ) == 0 )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): There is no opening paranthesis\n" );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
Oper = Vec_IntPop( pStackOp );
|
|
if ( Oper == MIO_EQN_OPER_MARK )
|
|
break;
|
|
|
|
// perform the given operation
|
|
if ( Mio_ParseFormulaOper( pMan, nVars, pStackFn, Oper ) == NULL )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): Unknown operation\n" );
|
|
ABC_FREE( pFormula );
|
|
Vec_PtrFreeP( &pStackFn );
|
|
Vec_IntFreeP( &pStackOp );
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): There is no opening paranthesis\n" );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
if ( Flag != MIO_EQN_FLAG_ERROR )
|
|
Flag = MIO_EQN_FLAG_VAR;
|
|
break;
|
|
|
|
|
|
default:
|
|
// scan the next name
|
|
for ( i = 0; pTemp[i] &&
|
|
pTemp[i] != ' ' && pTemp[i] != '\t' && pTemp[i] != '\r' && pTemp[i] != '\n' &&
|
|
pTemp[i] != MIO_EQN_SYM_AND && pTemp[i] != MIO_EQN_SYM_AND2 && pTemp[i] != MIO_EQN_SYM_OR && pTemp[i] != MIO_EQN_SYM_OR2 &&
|
|
pTemp[i] != MIO_EQN_SYM_XOR && pTemp[i] != MIO_EQN_SYM_NEGAFT && pTemp[i] != MIO_EQN_SYM_CLOSE;
|
|
i++ )
|
|
{
|
|
if ( pTemp[i] == MIO_EQN_SYM_NEG || pTemp[i] == MIO_EQN_SYM_OPEN )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): The negation sign or an opening paranthesis inside the variable name.\n" );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
// variable name is found
|
|
fFound = 0;
|
|
// Vec_PtrForEachEntry( char *, vVarNames, pName, v )
|
|
for ( v = 0; v < nVars; v++ )
|
|
{
|
|
pName = ppVarNames[v];
|
|
if ( strncmp(pTemp, pName, i) == 0 && strlen(pName) == (unsigned)i )
|
|
{
|
|
pTemp += i-1;
|
|
fFound = 1;
|
|
break;
|
|
}
|
|
}
|
|
if ( !fFound )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): The parser cannot find var \"%s\" in the input var list.\n", pTemp );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
/*
|
|
if ( Flag == MIO_EQN_FLAG_VAR )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): The variable name \"%s\" follows another var without operation sign.\n", pTemp );
|
|
Flag = MIO_EQN_FLAG_ERROR;
|
|
break;
|
|
}
|
|
*/
|
|
if ( Flag == MIO_EQN_FLAG_VAR )
|
|
Vec_IntPush( pStackOp, MIO_EQN_OPER_AND );
|
|
|
|
Vec_PtrPush( pStackFn, Exp_Var(v) ); // Cudd_Ref( pbVars[v] );
|
|
Flag = MIO_EQN_FLAG_VAR;
|
|
break;
|
|
}
|
|
|
|
if ( Flag == MIO_EQN_FLAG_ERROR )
|
|
break; // error exit
|
|
else if ( Flag == MIO_EQN_FLAG_START )
|
|
continue; // go on parsing
|
|
else if ( Flag == MIO_EQN_FLAG_VAR )
|
|
while ( 1 )
|
|
{ // check if there are negations in the OpStack
|
|
if ( Vec_IntSize( pStackOp ) == 0 )
|
|
break;
|
|
Oper = Vec_IntPop( pStackOp );
|
|
if ( Oper != MIO_EQN_OPER_NEG )
|
|
{
|
|
Vec_IntPush( pStackOp, Oper );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Vec_PtrPush( pStackFn, Exp_Not((Vec_Int_t *)Vec_PtrPop(pStackFn)) );
|
|
}
|
|
}
|
|
else // if ( Flag == MIO_EQN_FLAG_OPER )
|
|
while ( 1 )
|
|
{ // execute all the operations in the OpStack
|
|
// with precedence higher or equal than the last one
|
|
Oper1 = Vec_IntPop( pStackOp ); // the last operation
|
|
if ( Vec_IntSize( pStackOp ) == 0 )
|
|
{ // if it is the only operation, push it back
|
|
Vec_IntPush( pStackOp, Oper1 );
|
|
break;
|
|
}
|
|
Oper2 = Vec_IntPop( pStackOp ); // the operation before the last one
|
|
if ( Oper2 >= Oper1 )
|
|
{ // if Oper2 precedence is higher or equal, execute it
|
|
if ( Mio_ParseFormulaOper( pMan, nVars, pStackFn, Oper2 ) == NULL )
|
|
{
|
|
fprintf( stdout, "Mio_ParseFormula(): Unknown operation\n" );
|
|
ABC_FREE( pFormula );
|
|
Vec_PtrFreeP( &pStackFn );
|
|
Vec_IntFreeP( &pStackOp );
|
|
return NULL;
|
|
}
|
|
Vec_IntPush( pStackOp, Oper1 ); // push the last operation back
|
|
}
|
|
else
|
|
{ // if Oper2 precedence is lower, push them back and done
|
|
Vec_IntPush( pStackOp, Oper2 );
|
|
Vec_IntPush( pStackOp, Oper1 );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Flag != MIO_EQN_FLAG_ERROR )
|
|
{
|
|
if ( Vec_PtrSize(pStackFn) != 0 )
|
|
{
|
|
gFunc = (Vec_Int_t *)Vec_PtrPop(pStackFn);
|
|
if ( Vec_PtrSize(pStackFn) == 0 )
|
|
if ( Vec_IntSize( pStackOp ) == 0 )
|
|
{
|
|
// Cudd_Deref( gFunc );
|
|
ABC_FREE( pFormula );
|
|
Vec_PtrFreeP( &pStackFn );
|
|
Vec_IntFreeP( &pStackOp );
|
|
return Exp_Reverse(gFunc);
|
|
}
|
|
else
|
|
fprintf( stdout, "Mio_ParseFormula(): Something is left in the operation stack\n" );
|
|
else
|
|
fprintf( stdout, "Mio_ParseFormula(): Something is left in the function stack\n" );
|
|
}
|
|
else
|
|
fprintf( stdout, "Mio_ParseFormula(): The input string is empty\n" );
|
|
}
|
|
ABC_FREE( pFormula );
|
|
Vec_PtrFreeP( &pStackFn );
|
|
Vec_IntFreeP( &pStackOp );
|
|
return NULL;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Derives the TT corresponding to the equation.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Wrd_t * Mio_ParseFormulaTruth( char * pFormInit, char ** ppVarNames, int nVars )
|
|
{
|
|
Vec_Int_t * vExpr;
|
|
Vec_Wrd_t * vTruth;
|
|
// derive expression
|
|
vExpr = Mio_ParseFormula( pFormInit, ppVarNames, nVars );
|
|
// convert it into a truth table
|
|
vTruth = Vec_WrdStart( Abc_Truth6WordNum(nVars) );
|
|
Exp_Truth( nVars, vExpr, Vec_WrdArray(vTruth) );
|
|
Vec_IntFree( vExpr );
|
|
return vTruth;
|
|
}
|
|
void Mio_ParseFormulaTruthTest( char * pFormInit, char ** ppVarNames, int nVars )
|
|
{
|
|
Vec_Wrd_t * vTruth;
|
|
vTruth = Mio_ParseFormulaTruth( pFormInit, ppVarNames, nVars );
|
|
// Kit_DsdPrintFromTruth( (unsigned *)Vec_WrdArray(vTruth), nVars ); printf( "\n" );
|
|
Vec_WrdFree( vTruth );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Checks if the gate's formula essentially depends on all variables.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Mio_ParseCheckName( Mio_Gate_t * pGate, char ** ppStr )
|
|
{
|
|
Mio_Pin_t * pPin;
|
|
int i;
|
|
for ( pPin = Mio_GateReadPins(pGate), i = 0; pPin; pPin = Mio_PinReadNext(pPin), i++ )
|
|
if ( !strncmp( *ppStr, Mio_PinReadName(pPin), strlen(Mio_PinReadName(pPin)) ) )
|
|
{
|
|
*ppStr += strlen(Mio_PinReadName(pPin)) - 1;
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
int Mio_ParseCheckFormula( Mio_Gate_t * pGate, char * pForm )
|
|
{
|
|
Mio_Pin_t * pPin;
|
|
char * pStr;
|
|
int i, iPin, fVisit[32] = {0};
|
|
if ( Mio_GateReadPins(pGate) == NULL || !strcmp(Mio_PinReadName(Mio_GateReadPins(pGate)), "*") )
|
|
return 1;
|
|
/*
|
|
// find the equality sign
|
|
pForm = strstr( pForm, "=" );
|
|
if ( pForm == NULL )
|
|
{
|
|
printf( "Skipping gate \"%s\" because formula \"%s\" has not equality sign (=).\n", pGate->pName, pForm );
|
|
return 0;
|
|
}
|
|
*/
|
|
//printf( "Checking gate %s\n", pGate->pName );
|
|
|
|
for ( pStr = pForm; *pStr; pStr++ )
|
|
{
|
|
if ( *pStr == ' ' ||
|
|
*pStr == MIO_EQN_SYM_OPEN ||
|
|
*pStr == MIO_EQN_SYM_CLOSE ||
|
|
*pStr == MIO_EQN_SYM_CONST0 ||
|
|
*pStr == MIO_EQN_SYM_CONST1 ||
|
|
*pStr == MIO_EQN_SYM_NEG ||
|
|
*pStr == MIO_EQN_SYM_NEGAFT ||
|
|
*pStr == MIO_EQN_SYM_AND ||
|
|
*pStr == MIO_EQN_SYM_AND2 ||
|
|
*pStr == MIO_EQN_SYM_XOR ||
|
|
*pStr == MIO_EQN_SYM_OR ||
|
|
*pStr == MIO_EQN_SYM_OR2
|
|
)
|
|
continue;
|
|
// return the number of the pin which has this name
|
|
iPin = Mio_ParseCheckName( pGate, &pStr );
|
|
if ( iPin == -1 )
|
|
{
|
|
printf( "Skipping gate \"%s\" because substring \"%s\" does not match with a pin name.\n", pGate->pName, pStr );
|
|
return 0;
|
|
}
|
|
assert( iPin < 32 );
|
|
fVisit[iPin] = 1;
|
|
}
|
|
// check that all pins are used
|
|
for ( pPin = Mio_GateReadPins(pGate), i = 0; pPin; pPin = Mio_PinReadNext(pPin), i++ )
|
|
if ( fVisit[i] == 0 )
|
|
{
|
|
// printf( "Skipping gate \"%s\" because pin \"%s\" does not appear in the formula \"%s\".\n", pGate->pName, Mio_PinReadName(pPin), pForm );
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|