| /**CFile**************************************************************** |
| |
| FileName [ioReadBlifAig.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Command processing package.] |
| |
| Synopsis [Procedures to read BLIF file into AIG.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - December 23, 2006.] |
| |
| Revision [$Id: ioReadBlifAig.c,v 1.00 2006/12/23 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "base/abc/abc.h" |
| #include "misc/vec/vecPtr.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| // latch initial values |
| typedef enum { |
| IO_BLIF_INIT_NONE = 0, // 0: unknown |
| IO_BLIF_INIT_ZERO, // 1: zero |
| IO_BLIF_INIT_ONE, // 2: one |
| IO_BLIF_INIT_DC // 3: don't-care |
| } Io_BlifInit_t; |
| |
| typedef struct Io_BlifObj_t_ Io_BlifObj_t; // parsing object |
| struct Io_BlifObj_t_ |
| { |
| unsigned fPi : 1; // the object is a primary input |
| unsigned fPo : 1; // the object is a primary output |
| unsigned fLi : 1; // the object is a latch input |
| unsigned fLo : 1; // the object is a latch output |
| unsigned fDef : 1; // the object is defined as a table (node, PO, LI) |
| unsigned fLoop : 1; // flag for loop detection |
| unsigned Init : 2; // the latch initial state |
| unsigned Offset : 24; // temporary number |
| char * pName; // the name of this object |
| void * pEquiv; // the AIG node representing this line |
| Io_BlifObj_t * pNext; // the next obj in the hash table |
| }; |
| |
| typedef struct Io_BlifMan_t_ Io_BlifMan_t; // parsing manager |
| struct Io_BlifMan_t_ |
| { |
| // general info about file |
| char * pFileName; // the name of the file |
| char * pBuffer; // the begining of the file buffer |
| Vec_Ptr_t * vLines; // the line beginnings |
| // temporary objects |
| Io_BlifObj_t * pObjects; // the storage for objects |
| int nObjects; // the number of objects allocated |
| int iObjNext; // the next free object |
| // file lines |
| char * pModel; // .model line |
| Vec_Ptr_t * vInputs; // .inputs lines |
| Vec_Ptr_t * vOutputs; // .outputs lines |
| Vec_Ptr_t * vLatches; // .latches lines |
| Vec_Ptr_t * vNames; // .names lines |
| // network objects |
| Vec_Ptr_t * vPis; // the PI structures |
| Vec_Ptr_t * vPos; // the PO structures |
| Vec_Ptr_t * vLis; // the LI structures |
| Vec_Ptr_t * vLos; // the LO structures |
| // mapping of names into objects |
| Io_BlifObj_t ** pTable; // the hash table |
| int nTableSize; // the hash table size |
| // current processing info |
| Abc_Ntk_t * pAig; // the network under construction |
| Vec_Ptr_t * vTokens; // the current tokens |
| char sError[512]; // the error string generated during parsing |
| // statistics |
| int nTablesRead; // the number of processed tables |
| int nTablesLeft; // the number of dangling tables |
| }; |
| |
| // static functions |
| static Io_BlifMan_t * Io_BlifAlloc(); |
| static void Io_BlifFree( Io_BlifMan_t * p ); |
| static char * Io_BlifLoadFile( char * pFileName ); |
| static void Io_BlifReadPreparse( Io_BlifMan_t * p ); |
| static Abc_Ntk_t * Io_BlifParse( Io_BlifMan_t * p ); |
| static int Io_BlifParseModel( Io_BlifMan_t * p, char * pLine ); |
| static int Io_BlifParseInputs( Io_BlifMan_t * p, char * pLine ); |
| static int Io_BlifParseOutputs( Io_BlifMan_t * p, char * pLine ); |
| static int Io_BlifParseLatch( Io_BlifMan_t * p, char * pLine ); |
| static int Io_BlifParseNames( Io_BlifMan_t * p, char * pLine ); |
| static int Io_BlifParseConstruct( Io_BlifMan_t * p ); |
| static int Io_BlifCharIsSpace( char s ) { return s == ' ' || s == '\t' || s == '\r' || s == '\n'; } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the network from the BLIF file as an AIG.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Io_ReadBlifAsAig( char * pFileName, int fCheck ) |
| { |
| FILE * pFile; |
| Io_BlifMan_t * p; |
| Abc_Ntk_t * pAig; |
| |
| // check that the file is available |
| pFile = fopen( pFileName, "rb" ); |
| if ( pFile == NULL ) |
| { |
| printf( "Io_Blif(): The file is unavailable (absent or open).\n" ); |
| return 0; |
| } |
| fclose( pFile ); |
| |
| // start the file reader |
| p = Io_BlifAlloc(); |
| p->pFileName = pFileName; |
| p->pBuffer = Io_BlifLoadFile( pFileName ); |
| if ( p->pBuffer == NULL ) |
| { |
| Io_BlifFree( p ); |
| return NULL; |
| } |
| // prepare the file for parsing |
| Io_BlifReadPreparse( p ); |
| // construct the network |
| pAig = Io_BlifParse( p ); |
| if ( p->sError[0] ) |
| fprintf( stdout, "%s\n", p->sError ); |
| if ( pAig == NULL ) |
| return NULL; |
| Io_BlifFree( p ); |
| |
| // make sure that everything is okay with the network structure |
| if ( fCheck && !Abc_NtkCheckRead( pAig ) ) |
| { |
| printf( "Io_Blif: The network check has failed.\n" ); |
| Abc_NtkDelete( pAig ); |
| return NULL; |
| } |
| return pAig; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Allocates the BLIF parsing structure.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static Io_BlifMan_t * Io_BlifAlloc() |
| { |
| Io_BlifMan_t * p; |
| p = ABC_ALLOC( Io_BlifMan_t, 1 ); |
| memset( p, 0, sizeof(Io_BlifMan_t) ); |
| p->vLines = Vec_PtrAlloc( 512 ); |
| p->vInputs = Vec_PtrAlloc( 512 ); |
| p->vOutputs = Vec_PtrAlloc( 512 ); |
| p->vLatches = Vec_PtrAlloc( 512 ); |
| p->vNames = Vec_PtrAlloc( 512 ); |
| p->vTokens = Vec_PtrAlloc( 512 ); |
| p->vPis = Vec_PtrAlloc( 512 ); |
| p->vPos = Vec_PtrAlloc( 512 ); |
| p->vLis = Vec_PtrAlloc( 512 ); |
| p->vLos = Vec_PtrAlloc( 512 ); |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Frees the BLIF parsing structure.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static void Io_BlifFree( Io_BlifMan_t * p ) |
| { |
| if ( p->pAig ) |
| Abc_NtkDelete( p->pAig ); |
| if ( p->pBuffer ) ABC_FREE( p->pBuffer ); |
| if ( p->pObjects ) ABC_FREE( p->pObjects ); |
| if ( p->pTable ) ABC_FREE( p->pTable ); |
| Vec_PtrFree( p->vLines ); |
| Vec_PtrFree( p->vInputs ); |
| Vec_PtrFree( p->vOutputs ); |
| Vec_PtrFree( p->vLatches ); |
| Vec_PtrFree( p->vNames ); |
| Vec_PtrFree( p->vTokens ); |
| Vec_PtrFree( p->vPis ); |
| Vec_PtrFree( p->vPos ); |
| Vec_PtrFree( p->vLis ); |
| Vec_PtrFree( p->vLos ); |
| ABC_FREE( p ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Hashing for character strings.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static unsigned Io_BlifHashString( char * pName, int TableSize ) |
| { |
| static int s_Primes[10] = { |
| 1291, 1699, 2357, 4177, 5147, |
| 5647, 6343, 7103, 7873, 8147 |
| }; |
| unsigned i, Key = 0; |
| for ( i = 0; pName[i] != '\0'; i++ ) |
| Key ^= s_Primes[i%10]*pName[i]*pName[i]; |
| return Key % TableSize; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if the given name exists in the table.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static Io_BlifObj_t ** Io_BlifHashLookup( Io_BlifMan_t * p, char * pName ) |
| { |
| Io_BlifObj_t ** ppEntry; |
| for ( ppEntry = p->pTable + Io_BlifHashString(pName, p->nTableSize); *ppEntry; ppEntry = &(*ppEntry)->pNext ) |
| if ( !strcmp((*ppEntry)->pName, pName) ) |
| return ppEntry; |
| return ppEntry; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Finds or add the given name to the table.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static Io_BlifObj_t * Io_BlifHashFindOrAdd( Io_BlifMan_t * p, char * pName ) |
| { |
| Io_BlifObj_t ** ppEntry; |
| ppEntry = Io_BlifHashLookup( p, pName ); |
| if ( *ppEntry == NULL ) |
| { |
| assert( p->iObjNext < p->nObjects ); |
| *ppEntry = p->pObjects + p->iObjNext++; |
| (*ppEntry)->pName = pName; |
| } |
| return *ppEntry; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Collects the already split tokens.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static void Io_BlifCollectTokens( Vec_Ptr_t * vTokens, char * pInput, char * pOutput ) |
| { |
| char * pCur; |
| Vec_PtrClear( vTokens ); |
| for ( pCur = pInput; pCur < pOutput; pCur++ ) |
| { |
| if ( *pCur == 0 ) |
| continue; |
| Vec_PtrPush( vTokens, pCur ); |
| while ( *++pCur ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Splits the line into tokens.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static void Io_BlifSplitIntoTokens( Vec_Ptr_t * vTokens, char * pLine, char Stop ) |
| { |
| char * pCur; |
| // clear spaces |
| for ( pCur = pLine; *pCur != Stop; pCur++ ) |
| if ( Io_BlifCharIsSpace(*pCur) ) |
| *pCur = 0; |
| // collect tokens |
| Io_BlifCollectTokens( vTokens, pLine, pCur ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the 1-based number of the line in which the token occurs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifGetLine( Io_BlifMan_t * p, char * pToken ) |
| { |
| char * pLine; |
| int i; |
| Vec_PtrForEachEntry( char *, p->vLines, pLine, i ) |
| if ( pToken < pLine ) |
| return i; |
| return -1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Conservatively estimates the number of primary inputs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifEstimatePiNum( Io_BlifMan_t * p ) |
| { |
| char * pCur; |
| int i, fSpaces; |
| int Counter = 0; |
| Vec_PtrForEachEntry( char *, p->vInputs, pCur, i ) |
| for ( fSpaces = 0; *pCur; pCur++ ) |
| { |
| if ( Io_BlifCharIsSpace(*pCur) ) |
| { |
| if ( !fSpaces ) |
| Counter++; |
| fSpaces = 1; |
| } |
| else |
| fSpaces = 0; |
| } |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Conservatively estimates the number of AIG nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifEstimateAndNum( Io_BlifMan_t * p ) |
| { |
| Io_BlifObj_t * pObj; |
| char * pCur; |
| int i, CounterOne, Counter = 0; |
| for ( i = 0; i < p->iObjNext; i++ ) |
| { |
| pObj = p->pObjects + i; |
| if ( !pObj->fDef ) |
| continue; |
| CounterOne = 0; |
| for ( pCur = pObj->pName + strlen(pObj->pName); *pCur != '.'; pCur++ ) |
| if ( *pCur == '0' || *pCur == '1' ) |
| CounterOne++; |
| if ( CounterOne ) |
| Counter += CounterOne - 1; |
| } |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the file into a character buffer.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static char * Io_BlifLoadFile( char * pFileName ) |
| { |
| FILE * pFile; |
| int nFileSize; |
| char * pContents; |
| int RetValue; |
| pFile = fopen( pFileName, "rb" ); |
| if ( pFile == NULL ) |
| { |
| printf( "Io_BlifLoadFile(): The file is unavailable (absent or open).\n" ); |
| return NULL; |
| } |
| fseek( pFile, 0, SEEK_END ); |
| nFileSize = ftell( pFile ); |
| if ( nFileSize == 0 ) |
| { |
| fclose( pFile ); |
| printf( "Io_BlifLoadFile(): The file is empty.\n" ); |
| return NULL; |
| } |
| pContents = ABC_ALLOC( char, nFileSize + 10 ); |
| rewind( pFile ); |
| RetValue = fread( pContents, nFileSize, 1, pFile ); |
| fclose( pFile ); |
| // finish off the file with the spare .end line |
| // some benchmarks suddenly break off without this line |
| strcpy( pContents + nFileSize, "\n.end\n" ); |
| return pContents; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prepares the parsing.] |
| |
| Description [Performs several preliminary operations: |
| - Cuts the file buffer into separate lines. |
| - Removes comments and line extenders. |
| - Sorts lines by directives. |
| - Estimates the number of objects. |
| - Allocates room for the objects. |
| - Allocates room for the hash table.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static void Io_BlifReadPreparse( Io_BlifMan_t * p ) |
| { |
| char * pCur, * pPrev; |
| int i, fComment = 0; |
| // parse the buffer into lines and remove comments |
| Vec_PtrPush( p->vLines, p->pBuffer ); |
| for ( pCur = p->pBuffer; *pCur; pCur++ ) |
| { |
| if ( *pCur == '\n' ) |
| { |
| *pCur = 0; |
| fComment = 0; |
| Vec_PtrPush( p->vLines, pCur + 1 ); |
| } |
| else if ( *pCur == '#' ) |
| fComment = 1; |
| // remove comments |
| if ( fComment ) |
| *pCur = 0; |
| } |
| |
| // unfold the line extensions and sort lines by directive |
| Vec_PtrForEachEntry( char *, p->vLines, pCur, i ) |
| { |
| if ( *pCur == 0 ) |
| continue; |
| // find previous non-space character |
| for ( pPrev = pCur - 2; pPrev >= p->pBuffer; pPrev-- ) |
| if ( !Io_BlifCharIsSpace(*pPrev) ) |
| break; |
| // if it is the line extender, overwrite it with spaces |
| if ( *pPrev == '\\' ) |
| { |
| for ( ; *pPrev; pPrev++ ) |
| *pPrev = ' '; |
| *pPrev = ' '; |
| continue; |
| } |
| // skip spaces at the beginning of the line |
| while ( Io_BlifCharIsSpace(*pCur++) ); |
| // parse directives |
| if ( *(pCur-1) != '.' ) |
| continue; |
| if ( !strncmp(pCur, "names", 5) ) |
| Vec_PtrPush( p->vNames, pCur ); |
| else if ( !strncmp(pCur, "latch", 5) ) |
| Vec_PtrPush( p->vLatches, pCur ); |
| else if ( !strncmp(pCur, "inputs", 6) ) |
| Vec_PtrPush( p->vInputs, pCur ); |
| else if ( !strncmp(pCur, "outputs", 7) ) |
| Vec_PtrPush( p->vOutputs, pCur ); |
| else if ( !strncmp(pCur, "model", 5) ) |
| p->pModel = pCur; |
| else if ( !strncmp(pCur, "end", 3) || !strncmp(pCur, "exdc", 4) ) |
| break; |
| else |
| { |
| pCur--; |
| if ( pCur[strlen(pCur)-1] == '\r' ) |
| pCur[strlen(pCur)-1] = 0; |
| fprintf( stdout, "Line %d: Skipping line \"%s\".\n", Io_BlifGetLine(p, pCur), pCur ); |
| } |
| } |
| |
| // count the number of objects |
| p->nObjects = Io_BlifEstimatePiNum(p) + Vec_PtrSize(p->vLatches) + Vec_PtrSize(p->vNames) + 512; |
| |
| // allocate memory for objects |
| p->pObjects = ABC_ALLOC( Io_BlifObj_t, p->nObjects ); |
| memset( p->pObjects, 0, p->nObjects * sizeof(Io_BlifObj_t) ); |
| |
| // allocate memory for the hash table |
| p->nTableSize = p->nObjects/2 + 1; |
| p->pTable = ABC_ALLOC( Io_BlifObj_t *, p->nTableSize ); |
| memset( p->pTable, 0, p->nTableSize * sizeof(Io_BlifObj_t *) ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the AIG in the binary AIGER format.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static Abc_Ntk_t * Io_BlifParse( Io_BlifMan_t * p ) |
| { |
| Abc_Ntk_t * pAig; |
| char * pLine; |
| int i; |
| // parse the model |
| if ( !Io_BlifParseModel( p, p->pModel ) ) |
| return NULL; |
| // parse the inputs |
| Vec_PtrForEachEntry( char *, p->vInputs, pLine, i ) |
| if ( !Io_BlifParseInputs( p, pLine ) ) |
| return NULL; |
| // parse the outputs |
| Vec_PtrForEachEntry( char *, p->vOutputs, pLine, i ) |
| if ( !Io_BlifParseOutputs( p, pLine ) ) |
| return NULL; |
| // parse the latches |
| Vec_PtrForEachEntry( char *, p->vLatches, pLine, i ) |
| if ( !Io_BlifParseLatch( p, pLine ) ) |
| return NULL; |
| // parse the nodes |
| Vec_PtrForEachEntry( char *, p->vNames, pLine, i ) |
| if ( !Io_BlifParseNames( p, pLine ) ) |
| return NULL; |
| // reconstruct the network from the parsed data |
| if ( !Io_BlifParseConstruct( p ) ) |
| return NULL; |
| // return the network |
| pAig = p->pAig; |
| p->pAig = NULL; |
| return pAig; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Parses the model line.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifParseModel( Io_BlifMan_t * p, char * pLine ) |
| { |
| char * pToken; |
| Io_BlifSplitIntoTokens( p->vTokens, pLine, '\0' ); |
| pToken = (char *)Vec_PtrEntry( p->vTokens, 0 ); |
| assert( !strcmp(pToken, "model") ); |
| if ( Vec_PtrSize(p->vTokens) != 2 ) |
| { |
| sprintf( p->sError, "Line %d: Model line has %d entries while it should have 2.", Io_BlifGetLine(p, pToken), Vec_PtrSize(p->vTokens) ); |
| return 0; |
| } |
| p->pModel = (char *)Vec_PtrEntry( p->vTokens, 1 ); |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Parses the inputs line.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifParseInputs( Io_BlifMan_t * p, char * pLine ) |
| { |
| Io_BlifObj_t * pObj; |
| char * pToken; |
| int i; |
| Io_BlifSplitIntoTokens( p->vTokens, pLine, '\0' ); |
| pToken = (char *)Vec_PtrEntry(p->vTokens, 0); |
| assert( !strcmp(pToken, "inputs") ); |
| Vec_PtrForEachEntryStart( char *, p->vTokens, pToken, i, 1 ) |
| { |
| pObj = Io_BlifHashFindOrAdd( p, pToken ); |
| if ( pObj->fPi ) |
| { |
| sprintf( p->sError, "Line %d: Primary input (%s) is defined more than once.", Io_BlifGetLine(p, pToken), pToken ); |
| return 0; |
| } |
| pObj->fPi = 1; |
| Vec_PtrPush( p->vPis, pObj ); |
| } |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Parses the outputs line.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifParseOutputs( Io_BlifMan_t * p, char * pLine ) |
| { |
| Io_BlifObj_t * pObj; |
| char * pToken; |
| int i; |
| Io_BlifSplitIntoTokens( p->vTokens, pLine, '\0' ); |
| pToken = (char *)Vec_PtrEntry(p->vTokens, 0); |
| assert( !strcmp(pToken, "outputs") ); |
| Vec_PtrForEachEntryStart( char *, p->vTokens, pToken, i, 1 ) |
| { |
| pObj = Io_BlifHashFindOrAdd( p, pToken ); |
| if ( pObj->fPo ) |
| fprintf( stdout, "Line %d: Primary output (%s) is defined more than once (warning only).\n", Io_BlifGetLine(p, pToken), pToken ); |
| pObj->fPo = 1; |
| Vec_PtrPush( p->vPos, pObj ); |
| } |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Parses the latches line.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifParseLatch( Io_BlifMan_t * p, char * pLine ) |
| { |
| Io_BlifObj_t * pObj; |
| char * pToken; |
| int Init; |
| Io_BlifSplitIntoTokens( p->vTokens, pLine, '\0' ); |
| pToken = (char *)Vec_PtrEntry(p->vTokens,0); |
| assert( !strcmp(pToken, "latch") ); |
| if ( Vec_PtrSize(p->vTokens) < 3 ) |
| { |
| sprintf( p->sError, "Line %d: Latch does not have input name and output name.", Io_BlifGetLine(p, pToken) ); |
| return 0; |
| } |
| // get initial value |
| if ( Vec_PtrSize(p->vTokens) > 3 ) |
| Init = atoi( (char *)Vec_PtrEntry(p->vTokens,3) ); |
| else |
| Init = 2; |
| if ( Init < 0 || Init > 2 ) |
| { |
| sprintf( p->sError, "Line %d: Initial state of the latch is incorrect (%s).", Io_BlifGetLine(p, pToken), (char*)Vec_PtrEntry(p->vTokens,3) ); |
| return 0; |
| } |
| if ( Init == 0 ) |
| Init = IO_BLIF_INIT_ZERO; |
| else if ( Init == 1 ) |
| Init = IO_BLIF_INIT_ONE; |
| else // if ( Init == 2 ) |
| Init = IO_BLIF_INIT_DC; |
| // get latch input |
| pObj = Io_BlifHashFindOrAdd( p, (char *)Vec_PtrEntry(p->vTokens,1) ); |
| pObj->fLi = 1; |
| Vec_PtrPush( p->vLis, pObj ); |
| pObj->Init = Init; |
| // get latch output |
| pObj = Io_BlifHashFindOrAdd( p, (char *)Vec_PtrEntry(p->vTokens,2) ); |
| if ( pObj->fPi ) |
| { |
| sprintf( p->sError, "Line %d: Primary input (%s) is also defined latch output.", Io_BlifGetLine(p, pToken), (char*)Vec_PtrEntry(p->vTokens,2) ); |
| return 0; |
| } |
| if ( pObj->fLo ) |
| { |
| sprintf( p->sError, "Line %d: Latch output (%s) is defined as the output of another latch.", Io_BlifGetLine(p, pToken), (char*)Vec_PtrEntry(p->vTokens,2) ); |
| return 0; |
| } |
| pObj->fLo = 1; |
| Vec_PtrPush( p->vLos, pObj ); |
| pObj->Init = Init; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Parses the nodes line.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifParseNames( Io_BlifMan_t * p, char * pLine ) |
| { |
| Io_BlifObj_t * pObj; |
| char * pName; |
| Io_BlifSplitIntoTokens( p->vTokens, pLine, '\0' ); |
| assert( !strcmp((char *)Vec_PtrEntry(p->vTokens,0), "names") ); |
| pName = (char *)Vec_PtrEntryLast( p->vTokens ); |
| pObj = Io_BlifHashFindOrAdd( p, pName ); |
| if ( pObj->fPi ) |
| { |
| sprintf( p->sError, "Line %d: Primary input (%s) has a table.", Io_BlifGetLine(p, pName), pName ); |
| return 0; |
| } |
| if ( pObj->fLo ) |
| { |
| sprintf( p->sError, "Line %d: Latch output (%s) has a table.", Io_BlifGetLine(p, pName), pName ); |
| return 0; |
| } |
| if ( pObj->fDef ) |
| { |
| sprintf( p->sError, "Line %d: Signal (%s) is defined more than once.", Io_BlifGetLine(p, pName), pName ); |
| return 0; |
| } |
| pObj->fDef = 1; |
| // remember offset to the first fanin name |
| pObj->pName = pName; |
| pObj->Offset = pObj->pName - (char *)Vec_PtrEntry(p->vTokens,1); |
| return 1; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Constructs the AIG from the file parsing info.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static Abc_Obj_t * Io_BlifParseTable( Io_BlifMan_t * p, char * pTable, Vec_Ptr_t * vFanins ) |
| { |
| char * pProduct, * pOutput; |
| Abc_Obj_t * pRes, * pCube; |
| int i, k, Polarity = -1; |
| |
| p->nTablesRead++; |
| // get the tokens |
| Io_BlifSplitIntoTokens( p->vTokens, pTable, '.' ); |
| if ( Vec_PtrSize(p->vTokens) == 0 ) |
| return Abc_ObjNot( Abc_AigConst1(p->pAig) ); |
| if ( Vec_PtrSize(p->vTokens) == 1 ) |
| { |
| pOutput = (char *)Vec_PtrEntry( p->vTokens, 0 ); |
| if ( ((pOutput[0] - '0') & 0x8E) || pOutput[1] ) |
| { |
| sprintf( p->sError, "Line %d: Constant table has wrong output value (%s).", Io_BlifGetLine(p, pOutput), pOutput ); |
| return NULL; |
| } |
| return Abc_ObjNotCond( Abc_AigConst1(p->pAig), pOutput[0] == '0' ); |
| } |
| pProduct = (char *)Vec_PtrEntry( p->vTokens, 0 ); |
| if ( Vec_PtrSize(p->vTokens) % 2 == 1 ) |
| { |
| sprintf( p->sError, "Line %d: Table has odd number of tokens (%d).", Io_BlifGetLine(p, pProduct), Vec_PtrSize(p->vTokens) ); |
| return NULL; |
| } |
| // parse the table |
| pRes = Abc_ObjNot( Abc_AigConst1(p->pAig) ); |
| for ( i = 0; i < Vec_PtrSize(p->vTokens)/2; i++ ) |
| { |
| pProduct = (char *)Vec_PtrEntry( p->vTokens, 2*i + 0 ); |
| pOutput = (char *)Vec_PtrEntry( p->vTokens, 2*i + 1 ); |
| if ( strlen(pProduct) != (unsigned)Vec_PtrSize(vFanins) ) |
| { |
| sprintf( p->sError, "Line %d: Cube (%s) has size different from the fanin count (%d).", Io_BlifGetLine(p, pProduct), pProduct, Vec_PtrSize(vFanins) ); |
| return NULL; |
| } |
| if ( ((pOutput[0] - '0') & 0x8E) || pOutput[1] ) |
| { |
| sprintf( p->sError, "Line %d: Output value (%s) is incorrect.", Io_BlifGetLine(p, pProduct), pOutput ); |
| return NULL; |
| } |
| if ( Polarity == -1 ) |
| Polarity = pOutput[0] - '0'; |
| else if ( Polarity != pOutput[0] - '0' ) |
| { |
| sprintf( p->sError, "Line %d: Output value (%s) differs from the value in the first line of the table (%d).", Io_BlifGetLine(p, pProduct), pOutput, Polarity ); |
| return NULL; |
| } |
| // parse one product product |
| pCube = Abc_AigConst1(p->pAig); |
| for ( k = 0; pProduct[k]; k++ ) |
| { |
| if ( pProduct[k] == '0' ) |
| pCube = Abc_AigAnd( (Abc_Aig_t *)p->pAig->pManFunc, pCube, Abc_ObjNot((Abc_Obj_t *)Vec_PtrEntry(vFanins,k)) ); |
| else if ( pProduct[k] == '1' ) |
| pCube = Abc_AigAnd( (Abc_Aig_t *)p->pAig->pManFunc, pCube, (Abc_Obj_t *)Vec_PtrEntry(vFanins,k) ); |
| else if ( pProduct[k] != '-' ) |
| { |
| sprintf( p->sError, "Line %d: Product term (%s) contains character (%c).", Io_BlifGetLine(p, pProduct), pProduct, pProduct[k] ); |
| return NULL; |
| } |
| } |
| pRes = Abc_AigOr( (Abc_Aig_t *)p->pAig->pManFunc, pRes, pCube ); |
| } |
| pRes = Abc_ObjNotCond( pRes, Polarity == 0 ); |
| return pRes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Constructs the AIG from the file parsing info.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static Abc_Obj_t * Io_BlifParseConstruct_rec( Io_BlifMan_t * p, char * pName ) |
| { |
| Vec_Ptr_t * vFanins; |
| Abc_Obj_t * pFaninAbc; |
| Io_BlifObj_t * pObjIo; |
| char * pNameFanin; |
| int i; |
| // get the IO object with this name |
| pObjIo = *Io_BlifHashLookup( p, pName ); |
| if ( pObjIo == NULL ) |
| { |
| sprintf( p->sError, "Line %d: Signal (%s) is not defined as a table.", Io_BlifGetLine(p, pName), pName ); |
| return NULL; |
| } |
| // loop detection |
| if ( pObjIo->fLoop ) |
| { |
| sprintf( p->sError, "Line %d: Signal (%s) appears twice on a combinational path.", Io_BlifGetLine(p, pName), pName ); |
| return NULL; |
| } |
| // check if the AIG is already constructed |
| if ( pObjIo->pEquiv ) |
| return (Abc_Obj_t *)pObjIo->pEquiv; |
| // mark this node on the path |
| pObjIo->fLoop = 1; |
| // construct the AIGs for the fanins |
| vFanins = Vec_PtrAlloc( 8 ); |
| Io_BlifCollectTokens( vFanins, pObjIo->pName - pObjIo->Offset, pObjIo->pName ); |
| Vec_PtrForEachEntry( char *, vFanins, pNameFanin, i ) |
| { |
| pFaninAbc = Io_BlifParseConstruct_rec( p, pNameFanin ); |
| if ( pFaninAbc == NULL ) |
| { |
| Vec_PtrFree( vFanins ); |
| return NULL; |
| } |
| Vec_PtrWriteEntry( vFanins, i, pFaninAbc ); |
| } |
| // construct the node |
| pObjIo->pEquiv = Io_BlifParseTable( p, pObjIo->pName + strlen(pObjIo->pName), vFanins ); |
| Vec_PtrFree( vFanins ); |
| // unmark this node on the path |
| pObjIo->fLoop = 0; |
| // remember the new node |
| return (Abc_Obj_t *)pObjIo->pEquiv; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Constructs the AIG from the file parsing info.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static int Io_BlifParseConstruct( Io_BlifMan_t * p ) |
| { |
| Abc_Ntk_t * pAig; |
| Io_BlifObj_t * pObjIo, * pObjIoInput; |
| Abc_Obj_t * pObj, * pLatch; |
| int i; |
| // allocate the empty AIG |
| pAig = p->pAig = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 ); |
| pAig->pName = Extra_UtilStrsav( p->pModel ); |
| pAig->pSpec = Extra_UtilStrsav( p->pFileName ); |
| // create PIs |
| Vec_PtrForEachEntry( Io_BlifObj_t *, p->vPis, pObjIo, i ) |
| { |
| pObj = Abc_NtkCreatePi( pAig ); |
| Abc_ObjAssignName( pObj, pObjIo->pName, NULL ); |
| pObjIo->pEquiv = pObj; |
| } |
| // create POs |
| Vec_PtrForEachEntry( Io_BlifObj_t *, p->vPos, pObjIo, i ) |
| { |
| pObj = Abc_NtkCreatePo( pAig ); |
| Abc_ObjAssignName( pObj, pObjIo->pName, NULL ); |
| } |
| // create latches |
| Vec_PtrForEachEntry( Io_BlifObj_t *, p->vLos, pObjIo, i ) |
| { |
| // add the latch input terminal |
| pObj = Abc_NtkCreateBi( pAig ); |
| pObjIoInput = (Io_BlifObj_t *)Vec_PtrEntry( p->vLis, i ); |
| Abc_ObjAssignName( pObj, pObjIoInput->pName, NULL ); |
| |
| // add the latch box |
| pLatch = Abc_NtkCreateLatch( pAig ); |
| pLatch->pData = (void *)(ABC_PTRUINT_T)pObjIo->Init; |
| Abc_ObjAssignName( pLatch, pObjIo->pName, "L" ); |
| Abc_ObjAddFanin( pLatch, pObj ); |
| |
| // add the latch output terminal |
| pObj = Abc_NtkCreateBo( pAig ); |
| Abc_ObjAssignName( pObj, pObjIo->pName, NULL ); |
| Abc_ObjAddFanin( pObj, pLatch ); |
| // set the value of the latch output |
| // pObjIo->pEquiv = Abc_ObjNotCond( pObj, pObjIo->Init ); |
| pObjIo->pEquiv = pObj; |
| } |
| // traverse the nodes from the POs |
| Vec_PtrForEachEntry( Io_BlifObj_t *, p->vPos, pObjIo, i ) |
| { |
| pObj = Io_BlifParseConstruct_rec( p, pObjIo->pName ); |
| if ( pObj == NULL ) |
| return 0; |
| Abc_ObjAddFanin( Abc_NtkPo(p->pAig, i), pObj ); |
| } |
| // traverse the nodes from the latch inputs |
| Vec_PtrForEachEntry( Io_BlifObj_t *, p->vLis, pObjIo, i ) |
| { |
| pObj = Io_BlifParseConstruct_rec( p, pObjIo->pName ); |
| if ( pObj == NULL ) |
| return 0; |
| // pObj = Abc_ObjNotCond( pObj, pObjIo->Init ); |
| Abc_ObjAddFanin( Abc_ObjFanin0(Abc_NtkBox(p->pAig, i)), pObj ); |
| } |
| p->nTablesLeft = Vec_PtrSize(p->vNames) - p->nTablesRead; |
| if ( p->nTablesLeft ) |
| printf( "The number of dangling tables = %d.\n", p->nTablesLeft ); |
| printf( "AND nodes = %6d. Estimate = %6d.\n", Abc_NtkNodeNum(p->pAig), Io_BlifEstimateAndNum(p) ); |
| return 1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |