/**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