blob: 1d1dcbe2a599e58b0b25ebaea79579382e77751f [file] [log] [blame]
/**CFile****************************************************************
FileName [ioaReadAiger.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Command processing package.]
Synopsis [Procedures to read binary AIGER format developed by
Armin Biere, Johannes Kepler University (http://fmv.jku.at/)]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - December 16, 2006.]
Revision [$Id: ioaReadAiger.c,v 1.00 2006/12/16 00:00:00 alanmi Exp $]
***********************************************************************/
#include "ioa.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Extracts one unsigned AIG edge from the input buffer.]
Description [This procedure is a slightly modified version of Armin Biere's
procedure "unsigned decode (FILE * file)". ]
SideEffects [Updates the current reading position.]
SeeAlso []
***********************************************************************/
unsigned Ioa_ReadAigerDecode( char ** ppPos )
{
unsigned x = 0, i = 0;
unsigned char ch;
// while ((ch = getnoneofch (file)) & 0x80)
while ((ch = *(*ppPos)++) & 0x80)
x |= (ch & 0x7f) << (7 * i++);
return x | (ch << (7 * i));
}
/**Function*************************************************************
Synopsis [Decodes the encoded array of literals.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Int_t * Ioa_WriteDecodeLiterals( char ** ppPos, int nEntries )
{
Vec_Int_t * vLits;
int Lit, LitPrev, Diff, i;
vLits = Vec_IntAlloc( nEntries );
LitPrev = Ioa_ReadAigerDecode( ppPos );
Vec_IntPush( vLits, LitPrev );
for ( i = 1; i < nEntries; i++ )
{
// Diff = Lit - LitPrev;
// Diff = (Lit < LitPrev)? -Diff : Diff;
// Diff = ((2 * Diff) << 1) | (int)(Lit < LitPrev);
Diff = Ioa_ReadAigerDecode( ppPos );
Diff = (Diff & 1)? -(Diff >> 1) : Diff >> 1;
Lit = Diff + LitPrev;
Vec_IntPush( vLits, Lit );
LitPrev = Lit;
}
return vLits;
}
/**Function*************************************************************
Synopsis [Reads the AIG in from the memory buffer.]
Description [The buffer constains the AIG in AIGER format. The size gives
the number of bytes in the buffer. The buffer is allocated by the user
and not deallocated by this procedure.]
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Ioa_ReadAigerFromMemory( char * pContents, int nFileSize, int fCheck )
{
Vec_Int_t * vLits = NULL;
Vec_Ptr_t * vNodes, * vDrivers;//, * vTerms;
Aig_Obj_t * pObj, * pNode0, * pNode1;
Aig_Man_t * pNew;
int nTotal, nInputs, nOutputs, nLatches, nAnds, i;//, iTerm, nDigits;
int nBad = 0, nConstr = 0, nJust = 0, nFair = 0;
char * pDrivers, * pSymbols, * pCur;//, * pType;
unsigned uLit0, uLit1, uLit;
// check if the input file format is correct
if ( strncmp(pContents, "aig", 3) != 0 || (pContents[3] != ' ' && pContents[3] != '2') )
{
fprintf( stdout, "Wrong input file format.\n" );
return NULL;
}
// read the parameters (M I L O A + B C J F)
pCur = pContents; while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of objects
nTotal = atoi( pCur ); while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of inputs
nInputs = atoi( pCur ); while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of latches
nLatches = atoi( pCur ); while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of outputs
nOutputs = atoi( pCur ); while ( *pCur != ' ' ) pCur++; pCur++;
// read the number of nodes
nAnds = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
if ( *pCur == ' ' )
{
assert( nOutputs == 0 );
// read the number of properties
pCur++;
nBad = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
nOutputs += nBad;
}
if ( *pCur == ' ' )
{
// read the number of properties
pCur++;
nConstr = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
nOutputs += nConstr;
}
if ( *pCur == ' ' )
{
// read the number of properties
pCur++;
nJust = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
nOutputs += nJust;
}
if ( *pCur == ' ' )
{
// read the number of properties
pCur++;
nFair = atoi( pCur ); while ( *pCur != ' ' && *pCur != '\n' ) pCur++;
nOutputs += nFair;
}
if ( *pCur != '\n' )
{
fprintf( stdout, "The parameter line is in a wrong format.\n" );
return NULL;
}
pCur++;
// check the parameters
if ( nTotal != nInputs + nLatches + nAnds )
{
fprintf( stdout, "The number of objects does not match.\n" );
return NULL;
}
if ( nJust || nFair )
{
fprintf( stdout, "Reading AIGER files with liveness properties are currently not supported.\n" );
return NULL;
}
if ( nConstr )
{
if ( nConstr == 1 )
fprintf( stdout, "Warning: The last output is interpreted as a constraint.\n" );
else
fprintf( stdout, "Warning: The last %d outputs are interpreted as constraints.\n", nConstr );
}
// allocate the empty AIG
pNew = Aig_ManStart( nAnds );
pNew->nConstrs = nConstr;
// prepare the array of nodes
vNodes = Vec_PtrAlloc( 1 + nInputs + nLatches + nAnds );
Vec_PtrPush( vNodes, Aig_ManConst0(pNew) );
// create the PIs
for ( i = 0; i < nInputs + nLatches; i++ )
{
pObj = Aig_ObjCreateCi(pNew);
Vec_PtrPush( vNodes, pObj );
}
/*
// create the POs
for ( i = 0; i < nOutputs + nLatches; i++ )
{
pObj = Aig_ObjCreateCo(pNew);
}
*/
// create the latches
pNew->nRegs = nLatches;
/*
nDigits = Ioa_Base10Log( nLatches );
for ( i = 0; i < nLatches; i++ )
{
pObj = Aig_ObjCreateLatch(pNew);
Aig_LatchSetInit0( pObj );
pNode0 = Aig_ObjCreateBi(pNew);
pNode1 = Aig_ObjCreateBo(pNew);
Aig_ObjAddFanin( pObj, pNode0 );
Aig_ObjAddFanin( pNode1, pObj );
Vec_PtrPush( vNodes, pNode1 );
// assign names to latch and its input
// Aig_ObjAssignName( pObj, Aig_ObjNameDummy("_L", i, nDigits), NULL );
// printf( "Creating latch %s with input %d and output %d.\n", Aig_ObjName(pObj), pNode0->Id, pNode1->Id );
}
*/
// remember the beginning of latch/PO literals
pDrivers = pCur;
if ( pContents[3] == ' ' ) // standard AIGER
{
// scroll to the beginning of the binary data
for ( i = 0; i < nLatches + nOutputs; )
if ( *pCur++ == '\n' )
i++;
}
else // modified AIGER
{
vLits = Ioa_WriteDecodeLiterals( &pCur, nLatches + nOutputs );
}
// create the AND gates
// pProgress = Bar_ProgressStart( stdout, nAnds );
for ( i = 0; i < nAnds; i++ )
{
// Bar_ProgressUpdate( pProgress, i, NULL );
uLit = ((i + 1 + nInputs + nLatches) << 1);
uLit1 = uLit - Ioa_ReadAigerDecode( &pCur );
uLit0 = uLit1 - Ioa_ReadAigerDecode( &pCur );
// assert( uLit1 > uLit0 );
pNode0 = Aig_NotCond( (Aig_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), uLit0 & 1 );
pNode1 = Aig_NotCond( (Aig_Obj_t *)Vec_PtrEntry(vNodes, uLit1 >> 1), uLit1 & 1 );
assert( Vec_PtrSize(vNodes) == i + 1 + nInputs + nLatches );
Vec_PtrPush( vNodes, Aig_And(pNew, pNode0, pNode1) );
}
// Bar_ProgressStop( pProgress );
// remember the place where symbols begin
pSymbols = pCur;
// read the latch driver literals
vDrivers = Vec_PtrAlloc( nLatches + nOutputs );
if ( pContents[3] == ' ' ) // standard AIGER
{
pCur = pDrivers;
for ( i = 0; i < nLatches; i++ )
{
uLit0 = atoi( pCur ); while ( *pCur++ != '\n' );
pNode0 = Aig_NotCond( (Aig_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), (uLit0 & 1) );//^ (uLit0 < 2) );
Vec_PtrPush( vDrivers, pNode0 );
}
// read the PO driver literals
for ( i = 0; i < nOutputs; i++ )
{
uLit0 = atoi( pCur ); while ( *pCur++ != '\n' );
pNode0 = Aig_NotCond( (Aig_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), (uLit0 & 1) );//^ (uLit0 < 2) );
Vec_PtrPush( vDrivers, pNode0 );
}
}
else
{
// read the latch driver literals
for ( i = 0; i < nLatches; i++ )
{
uLit0 = Vec_IntEntry( vLits, i );
pNode0 = Aig_NotCond( (Aig_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), (uLit0 & 1) );//^ (uLit0 < 2) );
Vec_PtrPush( vDrivers, pNode0 );
}
// read the PO driver literals
for ( i = 0; i < nOutputs; i++ )
{
uLit0 = Vec_IntEntry( vLits, i+nLatches );
pNode0 = Aig_NotCond( (Aig_Obj_t *)Vec_PtrEntry(vNodes, uLit0 >> 1), (uLit0 & 1) );//^ (uLit0 < 2) );
Vec_PtrPush( vDrivers, pNode0 );
}
Vec_IntFree( vLits );
}
// create the POs
for ( i = 0; i < nOutputs; i++ )
Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Vec_PtrEntry(vDrivers, nLatches + i) );
for ( i = 0; i < nLatches; i++ )
Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Vec_PtrEntry(vDrivers, i) );
Vec_PtrFree( vDrivers );
/*
// read the names if present
pCur = pSymbols;
if ( *pCur != 'c' )
{
int Counter = 0;
while ( pCur < pContents + nFileSize && *pCur != 'c' )
{
// get the terminal type
pType = pCur;
if ( *pCur == 'i' )
vTerms = pNew->vPis;
else if ( *pCur == 'l' )
vTerms = pNew->vBoxes;
else if ( *pCur == 'o' )
vTerms = pNew->vPos;
else
{
fprintf( stdout, "Wrong terminal type.\n" );
return NULL;
}
// get the terminal number
iTerm = atoi( ++pCur ); while ( *pCur++ != ' ' );
// get the node
if ( iTerm >= Vec_PtrSize(vTerms) )
{
fprintf( stdout, "The number of terminal is out of bound.\n" );
return NULL;
}
pObj = Vec_PtrEntry( vTerms, iTerm );
if ( *pType == 'l' )
pObj = Aig_ObjFanout0(pObj);
// assign the name
pName = pCur; while ( *pCur++ != '\n' );
// assign this name
*(pCur-1) = 0;
Aig_ObjAssignName( pObj, pName, NULL );
if ( *pType == 'l' )
{
Aig_ObjAssignName( Aig_ObjFanin0(pObj), Aig_ObjName(pObj), "L" );
Aig_ObjAssignName( Aig_ObjFanin0(Aig_ObjFanin0(pObj)), Aig_ObjName(pObj), "_in" );
}
// mark the node as named
pObj->pCopy = (Aig_Obj_t *)Aig_ObjName(pObj);
}
// assign the remaining names
Aig_ManForEachCi( pNew, pObj, i )
{
if ( pObj->pCopy ) continue;
Aig_ObjAssignName( pObj, Aig_ObjName(pObj), NULL );
Counter++;
}
Aig_ManForEachLatchOutput( pNew, pObj, i )
{
if ( pObj->pCopy ) continue;
Aig_ObjAssignName( pObj, Aig_ObjName(pObj), NULL );
Aig_ObjAssignName( Aig_ObjFanin0(pObj), Aig_ObjName(pObj), "L" );
Aig_ObjAssignName( Aig_ObjFanin0(Aig_ObjFanin0(pObj)), Aig_ObjName(pObj), "_in" );
Counter++;
}
Aig_ManForEachCo( pNew, pObj, i )
{
if ( pObj->pCopy ) continue;
Aig_ObjAssignName( pObj, Aig_ObjName(pObj), NULL );
Counter++;
}
if ( Counter )
printf( "Ioa_ReadAiger(): Added %d default names for nameless I/O/register objects.\n", Counter );
}
else
{
// printf( "Ioa_ReadAiger(): I/O/register names are not given. Generating short names.\n" );
Aig_ManShortNames( pNew );
}
*/
pCur = pSymbols;
if ( pCur + 1 < pContents + nFileSize && *pCur == 'c' )
{
pCur++;
if ( *pCur == 'n' )
{
pCur++;
// read model name
ABC_FREE( pNew->pName );
pNew->pName = Abc_UtilStrsav( pCur );
}
}
// skipping the comments
Vec_PtrFree( vNodes );
// remove the extra nodes
Aig_ManCleanup( pNew );
Aig_ManSetRegNum( pNew, Aig_ManRegNum(pNew) );
// update polarity of the additional outputs
if ( nBad || nConstr || nJust || nFair )
Aig_ManInvertConstraints( pNew );
// check the result
if ( fCheck && !Aig_ManCheck( pNew ) )
{
printf( "Ioa_ReadAiger: The network check has failed.\n" );
Aig_ManStop( pNew );
return NULL;
}
return pNew;
}
/**Function*************************************************************
Synopsis [Reads the AIG in the binary AIGER format.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Ioa_ReadAiger( char * pFileName, int fCheck )
{
FILE * pFile;
Aig_Man_t * pNew;
char * pName, * pContents;
int nFileSize, RetValue;
// read the file into the buffer
nFileSize = Ioa_FileSize( pFileName );
pFile = fopen( pFileName, "rb" );
pContents = ABC_ALLOC( char, nFileSize );
RetValue = fread( pContents, nFileSize, 1, pFile );
fclose( pFile );
pNew = Ioa_ReadAigerFromMemory( pContents, nFileSize, fCheck );
ABC_FREE( pContents );
if ( pNew )
{
pName = Ioa_FileNameGeneric( pFileName );
ABC_FREE( pNew->pName );
pNew->pName = Abc_UtilStrsav( pName );
pNew->pSpec = Abc_UtilStrsav( pFileName );
ABC_FREE( pName );
}
return pNew;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END