mirror of https://github.com/YosysHQ/abc.git
1020 lines
32 KiB
C
1020 lines
32 KiB
C
/**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
|
|
|