| /**CFile**************************************************************** |
| |
| FileName [sclLiberty.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Standard-cell library representation.] |
| |
| Synopsis [Liberty parser.] |
| |
| Author [Alan Mishchenko, Niklas Een] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - August 24, 2012.] |
| |
| Revision [$Id: sclLiberty.c,v 1.0 2012/08/24 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "sclLib.h" |
| #include "misc/st/st.h" |
| #include "map/mio/mio.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| #define ABC_MAX_LIB_STR_LEN 5000 |
| |
| // entry types |
| typedef enum { |
| SCL_LIBERTY_NONE = 0, // 0: unknown |
| SCL_LIBERTY_PROC, // 1: procedure : key(head){body} |
| SCL_LIBERTY_EQUA, // 2: equation : key:head; |
| SCL_LIBERTY_LIST // 3: list : key(head) |
| } Scl_LibertyType_t; |
| |
| typedef struct Scl_Pair_t_ Scl_Pair_t; |
| struct Scl_Pair_t_ |
| { |
| int Beg; // item beginning |
| int End; // item end |
| }; |
| |
| typedef struct Scl_Item_t_ Scl_Item_t; |
| struct Scl_Item_t_ |
| { |
| int Type; // Scl_LibertyType_t |
| int iLine; // file line where the item's spec begins |
| Scl_Pair_t Key; // key part |
| Scl_Pair_t Head; // head part |
| Scl_Pair_t Body; // body part |
| int Next; // next item in the list |
| int Child; // first child item |
| }; |
| |
| typedef struct Scl_Tree_t_ Scl_Tree_t; |
| struct Scl_Tree_t_ |
| { |
| char * pFileName; // input Liberty file name |
| char * pContents; // file contents |
| int nContents; // file size |
| int nLines; // line counter |
| int nItems; // number of items |
| int nItermAlloc; // number of items allocated |
| Scl_Item_t * pItems; // the items |
| char * pError; // the error string |
| abctime clkStart; // beginning time |
| }; |
| |
| static inline Scl_Item_t * Scl_LibertyRoot( Scl_Tree_t * p ) { return p->pItems; } |
| static inline Scl_Item_t * Scl_LibertyItem( Scl_Tree_t * p, int v ) { assert( v < p->nItems ); return v < 0 ? NULL : p->pItems + v; } |
| static inline int Scl_LibertyCompare( Scl_Tree_t * p, Scl_Pair_t Pair, char * pStr ) { return strncmp( p->pContents+Pair.Beg, pStr, Pair.End-Pair.Beg ) || ((int)strlen(pStr) != Pair.End-Pair.Beg); } |
| static inline void Scl_PrintWord( FILE * pFile, Scl_Tree_t * p, Scl_Pair_t Pair ) { char * pBeg = p->pContents+Pair.Beg, * pEnd = p->pContents+Pair.End; while ( pBeg < pEnd ) fputc( *pBeg++, pFile ); } |
| static inline void Scl_PrintSpace( FILE * pFile, int nOffset ) { int i; for ( i = 0; i < nOffset; i++ ) fputc(' ', pFile); } |
| static inline int Scl_LibertyItemId( Scl_Tree_t * p, Scl_Item_t * pItem ) { return pItem - p->pItems; } |
| |
| #define Scl_ItemForEachChild( p, pItem, pChild ) \ |
| for ( pChild = Scl_LibertyItem(p, pItem->Child); pChild; pChild = Scl_LibertyItem(p, pChild->Next) ) |
| #define Scl_ItemForEachChildName( p, pItem, pChild, pName ) \ |
| for ( pChild = Scl_LibertyItem(p, pItem->Child); pChild; pChild = Scl_LibertyItem(p, pChild->Next) ) if ( Scl_LibertyCompare(p, pChild->Key, pName) ) {} else |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints parse tree in Liberty format.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Scl_LibertyParseDumpItem( FILE * pFile, Scl_Tree_t * p, Scl_Item_t * pItem, int nOffset ) |
| { |
| if ( pItem->Type == SCL_LIBERTY_PROC ) |
| { |
| Scl_PrintSpace( pFile, nOffset ); |
| Scl_PrintWord( pFile, p, pItem->Key ); |
| fprintf( pFile, "(" ); |
| Scl_PrintWord( pFile, p, pItem->Head ); |
| fprintf( pFile, ") {\n" ); |
| if ( Scl_LibertyItem(p, pItem->Child) ) |
| Scl_LibertyParseDumpItem( pFile, p, Scl_LibertyItem(p, pItem->Child), nOffset + 2 ); |
| Scl_PrintSpace( pFile, nOffset ); |
| fprintf( pFile, "}\n" ); |
| } |
| else if ( pItem->Type == SCL_LIBERTY_EQUA ) |
| { |
| Scl_PrintSpace( pFile, nOffset ); |
| Scl_PrintWord( pFile, p, pItem->Key ); |
| fprintf( pFile, " : " ); |
| Scl_PrintWord( pFile, p, pItem->Head ); |
| fprintf( pFile, ";\n" ); |
| } |
| else if ( pItem->Type == SCL_LIBERTY_LIST ) |
| { |
| Scl_PrintSpace( pFile, nOffset ); |
| Scl_PrintWord( pFile, p, pItem->Key ); |
| fprintf( pFile, "(" ); |
| Scl_PrintWord( pFile, p, pItem->Head ); |
| fprintf( pFile, ");\n" ); |
| } |
| else assert( 0 ); |
| if ( Scl_LibertyItem(p, pItem->Next) ) |
| Scl_LibertyParseDumpItem( pFile, p, Scl_LibertyItem(p, pItem->Next), nOffset ); |
| } |
| int Scl_LibertyParseDump( Scl_Tree_t * p, char * pFileName ) |
| { |
| FILE * pFile; |
| if ( pFileName == NULL ) |
| pFile = stdout; |
| else |
| { |
| pFile = fopen( pFileName, "w" ); |
| if ( pFile == NULL ) |
| { |
| printf( "Scl_LibertyParseDump(): The output file is unavailable (absent or open).\n" ); |
| return 0; |
| } |
| } |
| Scl_LibertyParseDumpItem( pFile, p, Scl_LibertyRoot(p), 0 ); |
| if ( pFile != stdout ) |
| fclose( pFile ); |
| return 1; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Gets the name to write.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Scl_LibertyCountItems( char * pBeg, char * pEnd ) |
| { |
| int Counter = 0; |
| for ( ; pBeg < pEnd; pBeg++ ) |
| Counter += (*pBeg == '(' || *pBeg == ':'); |
| return Counter; |
| } |
| // removes C-style comments |
| /* |
| void Scl_LibertyWipeOutComments( char * pBeg, char * pEnd ) |
| { |
| char * pCur, * pStart; |
| for ( pCur = pBeg; pCur < pEnd; pCur++ ) |
| if ( pCur[0] == '/' && pCur[1] == '*' ) |
| for ( pStart = pCur; pCur < pEnd; pCur++ ) |
| if ( pCur[0] == '*' && pCur[1] == '/' ) |
| { |
| for ( ; pStart < pCur + 2; pStart++ ) |
| if ( *pStart != '\n' ) *pStart = ' '; |
| break; |
| } |
| } |
| */ |
| void Scl_LibertyWipeOutComments( char * pBeg, char * pEnd ) |
| { |
| char * pCur, * pStart; |
| for ( pCur = pBeg; pCur < pEnd-1; pCur++ ) |
| if ( pCur[0] == '/' && pCur[1] == '*' ) |
| { |
| for ( pStart = pCur; pCur < pEnd-1; pCur++ ) |
| if ( pCur[0] == '*' && pCur[1] == '/' ) |
| { |
| for ( ; pStart < pCur + 2; pStart++ ) |
| if ( *pStart != '\n' ) *pStart = ' '; |
| break; |
| } |
| } |
| else if ( pCur[0] == '/' && pCur[1] == '/' ) |
| { |
| for ( pStart = pCur; pCur < pEnd; pCur++ ) |
| if ( pCur[0] == '\n' || pCur == pEnd-1 ) |
| { |
| for ( ; pStart < pCur; pStart++ ) *pStart = ' '; |
| break; |
| } |
| } |
| } |
| static inline int Scl_LibertyCharIsSpace( char c ) |
| { |
| return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\\'; |
| } |
| static inline int Scl_LibertySkipSpaces( Scl_Tree_t * p, char ** ppPos, char * pEnd, int fStopAtNewLine ) |
| { |
| char * pPos = *ppPos; |
| for ( ; pPos < pEnd; pPos++ ) |
| { |
| if ( *pPos == '\n' ) |
| { |
| p->nLines++; |
| if ( fStopAtNewLine ) |
| break; |
| } |
| if ( !Scl_LibertyCharIsSpace(*pPos) ) |
| break; |
| } |
| *ppPos = pPos; |
| return pPos == pEnd; |
| } |
| // skips entry delimited by " :;(){}" and returns 1 if reached the end |
| static inline int Scl_LibertySkipEntry( char ** ppPos, char * pEnd ) |
| { |
| char * pPos = *ppPos; |
| if ( *pPos == '\"' ) |
| { |
| for ( pPos++; pPos < pEnd; pPos++ ) |
| if ( *pPos == '\"' ) |
| { |
| pPos++; |
| break; |
| } |
| } |
| else |
| { |
| for ( ; pPos < pEnd; pPos++ ) |
| if ( *pPos == ' ' || *pPos == '\r' || *pPos == '\n' || *pPos == '\t' || |
| *pPos == ':' || *pPos == ';' || |
| *pPos == '(' || *pPos == ')' || |
| *pPos == '{' || *pPos == '}' ) |
| break; |
| } |
| *ppPos = pPos; |
| return pPos == pEnd; |
| } |
| // finds the matching closing symbol |
| static inline char * Scl_LibertyFindMatch( char * pPos, char * pEnd ) |
| { |
| int Counter = 0; |
| assert( *pPos == '(' || *pPos == '{' ); |
| if ( *pPos == '(' ) |
| { |
| for ( ; pPos < pEnd; pPos++ ) |
| { |
| if ( *pPos == '(' ) |
| Counter++; |
| if ( *pPos == ')' ) |
| Counter--; |
| if ( Counter == 0 ) |
| break; |
| } |
| } |
| else |
| { |
| for ( ; pPos < pEnd; pPos++ ) |
| { |
| if ( *pPos == '{' ) |
| Counter++; |
| if ( *pPos == '}' ) |
| Counter--; |
| if ( Counter == 0 ) |
| break; |
| } |
| } |
| assert( *pPos == ')' || *pPos == '}' ); |
| return pPos; |
| } |
| // trims spaces around the head |
| static inline Scl_Pair_t Scl_LibertyUpdateHead( Scl_Tree_t * p, Scl_Pair_t Head ) |
| { |
| Scl_Pair_t Res; |
| char * pBeg = p->pContents + Head.Beg; |
| char * pEnd = p->pContents + Head.End; |
| char * pFirstNonSpace = NULL; |
| char * pLastNonSpace = NULL; |
| char * pChar; |
| for ( pChar = pBeg; pChar < pEnd; pChar++ ) |
| { |
| if ( *pChar == '\n' ) |
| p->nLines++; |
| if ( Scl_LibertyCharIsSpace(*pChar) ) |
| continue; |
| pLastNonSpace = pChar; |
| if ( pFirstNonSpace == NULL ) |
| pFirstNonSpace = pChar; |
| } |
| if ( pFirstNonSpace == NULL || pLastNonSpace == NULL ) |
| return Head; |
| assert( pFirstNonSpace && pLastNonSpace ); |
| Res.Beg = pFirstNonSpace - p->pContents; |
| Res.End = pLastNonSpace - p->pContents + 1; |
| return Res; |
| } |
| // returns new item |
| static inline Scl_Item_t * Scl_LibertyNewItem( Scl_Tree_t * p, int Type ) |
| { |
| p->pItems[p->nItems].iLine = p->nLines; |
| p->pItems[p->nItems].Type = Type; |
| p->pItems[p->nItems].Child = -1; |
| p->pItems[p->nItems].Next = -1; |
| return p->pItems + p->nItems++; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Gets the name to write.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| char * Scl_LibertyReadString( Scl_Tree_t * p, Scl_Pair_t Pair ) |
| { |
| static char Buffer[ABC_MAX_LIB_STR_LEN]; |
| assert( Pair.End-Pair.Beg < ABC_MAX_LIB_STR_LEN ); |
| strncpy( Buffer, p->pContents+Pair.Beg, Pair.End-Pair.Beg ); |
| if ( Pair.Beg < Pair.End && Buffer[0] == '\"' ) |
| { |
| assert( Buffer[Pair.End-Pair.Beg-1] == '\"' ); |
| Buffer[Pair.End-Pair.Beg-1] = 0; |
| return Buffer + 1; |
| } |
| Buffer[Pair.End-Pair.Beg] = 0; |
| return Buffer; |
| } |
| int Scl_LibertyItemNum( Scl_Tree_t * p, Scl_Item_t * pRoot, char * pName ) |
| { |
| Scl_Item_t * pItem; |
| int Counter = 0; |
| Scl_ItemForEachChildName( p, pRoot, pItem, pName ) |
| Counter++; |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns free item.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Scl_LibertyBuildItem( Scl_Tree_t * p, char ** ppPos, char * pEnd ) |
| { |
| Scl_Item_t * pItem; |
| Scl_Pair_t Key, Head, Body; |
| char * pNext, * pStop; |
| Key.End = 0; |
| if ( Scl_LibertySkipSpaces( p, ppPos, pEnd, 0 ) ) |
| return -2; |
| Key.Beg = *ppPos - p->pContents; |
| if ( Scl_LibertySkipEntry( ppPos, pEnd ) ) |
| goto exit; |
| Key.End = *ppPos - p->pContents; |
| if ( Scl_LibertySkipSpaces( p, ppPos, pEnd, 0 ) ) |
| goto exit; |
| pNext = *ppPos; |
| if ( *pNext == ':' ) |
| { |
| *ppPos = pNext + 1; |
| if ( Scl_LibertySkipSpaces( p, ppPos, pEnd, 0 ) ) |
| goto exit; |
| Head.Beg = *ppPos - p->pContents; |
| if ( Scl_LibertySkipEntry( ppPos, pEnd ) ) |
| goto exit; |
| Head.End = *ppPos - p->pContents; |
| if ( Scl_LibertySkipSpaces( p, ppPos, pEnd, 1 ) ) |
| goto exit; |
| pNext = *ppPos; |
| while ( *pNext == '+' || *pNext == '-' || *pNext == '*' || *pNext == '/' ) |
| { |
| (*ppPos) += 1; |
| if ( Scl_LibertySkipSpaces( p, ppPos, pEnd, 0 ) ) |
| goto exit; |
| if ( Scl_LibertySkipEntry( ppPos, pEnd ) ) |
| goto exit; |
| Head.End = *ppPos - p->pContents; |
| if ( Scl_LibertySkipSpaces( p, ppPos, pEnd, 1 ) ) |
| goto exit; |
| pNext = *ppPos; |
| } |
| if ( *pNext != ';' && *pNext != '\n' ) |
| goto exit; |
| *ppPos = pNext + 1; |
| // end of equation |
| pItem = Scl_LibertyNewItem( p, SCL_LIBERTY_EQUA ); |
| pItem->Key = Key; |
| pItem->Head = Scl_LibertyUpdateHead( p, Head ); |
| pItem->Next = Scl_LibertyBuildItem( p, ppPos, pEnd ); |
| if ( pItem->Next == -1 ) |
| goto exit; |
| return Scl_LibertyItemId( p, pItem ); |
| } |
| if ( *pNext == '(' ) |
| { |
| pStop = Scl_LibertyFindMatch( pNext, pEnd ); |
| Head.Beg = pNext - p->pContents + 1; |
| Head.End = pStop - p->pContents; |
| *ppPos = pStop + 1; |
| if ( Scl_LibertySkipSpaces( p, ppPos, pEnd, 0 ) ) |
| { |
| // end of list |
| pItem = Scl_LibertyNewItem( p, SCL_LIBERTY_LIST ); |
| pItem->Key = Key; |
| pItem->Head = Scl_LibertyUpdateHead( p, Head ); |
| return Scl_LibertyItemId( p, pItem ); |
| } |
| pNext = *ppPos; |
| if ( *pNext == '{' ) // beginning of body |
| { |
| pStop = Scl_LibertyFindMatch( pNext, pEnd ); |
| Body.Beg = pNext - p->pContents + 1; |
| Body.End = pStop - p->pContents; |
| // end of body |
| pItem = Scl_LibertyNewItem( p, SCL_LIBERTY_PROC ); |
| pItem->Key = Key; |
| pItem->Head = Scl_LibertyUpdateHead( p, Head ); |
| pItem->Body = Body; |
| *ppPos = pNext + 1; |
| pItem->Child = Scl_LibertyBuildItem( p, ppPos, pStop ); |
| if ( pItem->Child == -1 ) |
| goto exit; |
| *ppPos = pStop + 1; |
| pItem->Next = Scl_LibertyBuildItem( p, ppPos, pEnd ); |
| if ( pItem->Next == -1 ) |
| goto exit; |
| return Scl_LibertyItemId( p, pItem ); |
| } |
| // end of list |
| if ( *pNext == ';' ) |
| *ppPos = pNext + 1; |
| pItem = Scl_LibertyNewItem( p, SCL_LIBERTY_LIST ); |
| pItem->Key = Key; |
| pItem->Head = Scl_LibertyUpdateHead( p, Head ); |
| pItem->Next = Scl_LibertyBuildItem( p, ppPos, pEnd ); |
| if ( pItem->Next == -1 ) |
| goto exit; |
| return Scl_LibertyItemId( p, pItem ); |
| } |
| if ( *pNext == ';' ) |
| { |
| *ppPos = pNext + 1; |
| return Scl_LibertyBuildItem(p, ppPos, pEnd); |
| } |
| exit: |
| if ( p->pError == NULL ) |
| { |
| p->pError = ABC_ALLOC( char, 1000 ); |
| sprintf( p->pError, "File \"%s\". Line %6d. Failed to parse entry \"%s\".\n", |
| p->pFileName, p->nLines, Scl_LibertyReadString(p, Key) ); |
| } |
| return -1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [File management.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Scl_LibertyFixFileName( char * pFileName ) |
| { |
| char * pHead; |
| for ( pHead = pFileName; *pHead; pHead++ ) |
| if ( *pHead == '>' ) |
| *pHead = '\\'; |
| } |
| int Scl_LibertyFileSize( char * pFileName ) |
| { |
| FILE * pFile; |
| int nFileSize; |
| pFile = fopen( pFileName, "rb" ); |
| if ( pFile == NULL ) |
| { |
| printf( "Scl_LibertyFileSize(): The input file is unavailable (absent or open).\n" ); |
| return 0; |
| } |
| fseek( pFile, 0, SEEK_END ); |
| nFileSize = ftell( pFile ); |
| fclose( pFile ); |
| return nFileSize; |
| } |
| char * Scl_LibertyFileContents( char * pFileName, int nContents ) |
| { |
| FILE * pFile = fopen( pFileName, "rb" ); |
| char * pContents = ABC_ALLOC( char, nContents+1 ); |
| int RetValue = 0; |
| RetValue = fread( pContents, nContents, 1, pFile ); |
| fclose( pFile ); |
| pContents[nContents] = 0; |
| return pContents; |
| } |
| void Scl_LibertyStringDump( char * pFileName, Vec_Str_t * vStr ) |
| { |
| FILE * pFile = fopen( pFileName, "wb" ); |
| int RetValue = 0; |
| if ( pFile == NULL ) |
| { |
| printf( "Scl_LibertyStringDump(): The output file is unavailable.\n" ); |
| return; |
| } |
| RetValue = fwrite( Vec_StrArray(vStr), 1, Vec_StrSize(vStr), pFile ); |
| fclose( pFile ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts the parsing manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Scl_Tree_t * Scl_LibertyStart( char * pFileName ) |
| { |
| Scl_Tree_t * p; |
| int RetValue; |
| // read the file into the buffer |
| Scl_LibertyFixFileName( pFileName ); |
| RetValue = Scl_LibertyFileSize( pFileName ); |
| if ( RetValue == 0 ) |
| return NULL; |
| // start the manager |
| p = ABC_ALLOC( Scl_Tree_t, 1 ); |
| memset( p, 0, sizeof(Scl_Tree_t) ); |
| p->clkStart = Abc_Clock(); |
| p->nContents = RetValue; |
| p->pContents = Scl_LibertyFileContents( pFileName, p->nContents ); |
| // other |
| p->pFileName = Abc_UtilStrsav( pFileName ); |
| p->nItermAlloc = 10 + Scl_LibertyCountItems( p->pContents, p->pContents+p->nContents ); |
| p->pItems = ABC_CALLOC( Scl_Item_t, p->nItermAlloc ); |
| p->nItems = 0; |
| p->nLines = 1; |
| return p; |
| } |
| void Scl_LibertyStop( Scl_Tree_t * p, int fVerbose ) |
| { |
| if ( fVerbose ) |
| { |
| printf( "Memory = %7.2f MB. ", 1.0 * (p->nContents + p->nItermAlloc * sizeof(Scl_Item_t))/(1<<20) ); |
| ABC_PRT( "Time", Abc_Clock() - p->clkStart ); |
| } |
| ABC_FREE( p->pFileName ); |
| ABC_FREE( p->pContents ); |
| ABC_FREE( p->pItems ); |
| ABC_FREE( p->pError ); |
| ABC_FREE( p ); |
| } |
| Scl_Tree_t * Scl_LibertyParse( char * pFileName, int fVerbose ) |
| { |
| Scl_Tree_t * p; |
| char * pPos; |
| if ( (p = Scl_LibertyStart(pFileName)) == NULL ) |
| return NULL; |
| pPos = p->pContents; |
| Scl_LibertyWipeOutComments( p->pContents, p->pContents+p->nContents ); |
| if ( (!Scl_LibertyBuildItem( p, &pPos, p->pContents + p->nContents )) == 0 ) |
| { |
| if ( p->pError ) printf( "%s", p->pError ); |
| printf( "Parsing failed. " ); |
| Abc_PrintTime( 1, "Parsing time", Abc_Clock() - p->clkStart ); |
| } |
| else if ( fVerbose ) |
| { |
| printf( "Parsing finished successfully. " ); |
| Abc_PrintTime( 1, "Parsing time", Abc_Clock() - p->clkStart ); |
| } |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Fetching attributes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Scl_LibertyReadCellIsFlop( Scl_Tree_t * p, Scl_Item_t * pCell ) |
| { |
| Scl_Item_t * pAttr; |
| Scl_ItemForEachChild( p, pCell, pAttr ) |
| if ( !Scl_LibertyCompare(p, pAttr->Key, "ff") || |
| !Scl_LibertyCompare(p, pAttr->Key, "latch") ) |
| return 1; |
| return 0; |
| } |
| char * Scl_LibertyReadCellArea( Scl_Tree_t * p, Scl_Item_t * pCell ) |
| { |
| Scl_Item_t * pArea; |
| Scl_ItemForEachChildName( p, pCell, pArea, "area" ) |
| return Scl_LibertyReadString(p, pArea->Head); |
| return 0; |
| } |
| char * Scl_LibertyReadCellLeakage( Scl_Tree_t * p, Scl_Item_t * pCell ) |
| { |
| Scl_Item_t * pItem, * pChild; |
| Scl_ItemForEachChildName( p, pCell, pItem, "cell_leakage_power" ) |
| return Scl_LibertyReadString(p, pItem->Head); |
| // look for another type |
| Scl_ItemForEachChildName( p, pCell, pItem, "leakage_power" ) |
| { |
| Scl_ItemForEachChildName( p, pItem, pChild, "when" ) |
| break; |
| if ( pChild && !Scl_LibertyCompare(p, pChild->Key, "when") ) |
| continue; |
| Scl_ItemForEachChildName( p, pItem, pChild, "value" ) |
| return Scl_LibertyReadString(p, pChild->Head); |
| } |
| return 0; |
| } |
| char * Scl_LibertyReadPinFormula( Scl_Tree_t * p, Scl_Item_t * pPin ) |
| { |
| Scl_Item_t * pFunc; |
| Scl_ItemForEachChildName( p, pPin, pFunc, "function" ) |
| return Scl_LibertyReadString(p, pFunc->Head); |
| return NULL; |
| } |
| int Scl_LibertyReadCellIsThreeState( Scl_Tree_t * p, Scl_Item_t * pCell ) |
| { |
| Scl_Item_t * pPin, * pItem; |
| Scl_ItemForEachChildName( p, pCell, pPin, "pin" ) |
| Scl_ItemForEachChildName( p, pPin, pItem, "three_state" ) |
| return 1; |
| return 0; |
| } |
| int Scl_LibertyReadCellOutputNum( Scl_Tree_t * p, Scl_Item_t * pCell ) |
| { |
| Scl_Item_t * pPin; |
| int Counter = 0; |
| Scl_ItemForEachChildName( p, pCell, pPin, "pin" ) |
| if ( Scl_LibertyReadPinFormula(p, pPin) ) |
| Counter++; |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Parses the standard cell library in Liberty format.] |
| |
| Description [Writes the resulting file in Genlib format.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Str_t * Scl_LibertyReadGenlibStr( Scl_Tree_t * p, int fVerbose ) |
| { |
| Vec_Str_t * vStr; |
| Scl_Item_t * pCell, * pOutput, * pInput; |
| char * pFormula; |
| vStr = Vec_StrAlloc( 1000 ); |
| Vec_StrPrintStr( vStr, "GATE _const0_ 0.000000 z=CONST0;\n" ); |
| Vec_StrPrintStr( vStr, "GATE _const1_ 0.000000 z=CONST1;\n" ); |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pCell, "cell" ) |
| { |
| if ( Scl_LibertyReadCellIsFlop(p, pCell) ) |
| { |
| if ( fVerbose ) printf( "Scl_LibertyReadGenlib() skipped sequential cell \"%s\".\n", Scl_LibertyReadString(p, pCell->Head) ); |
| continue; |
| } |
| if ( Scl_LibertyReadCellIsThreeState(p, pCell) ) |
| { |
| if ( fVerbose ) printf( "Scl_LibertyReadGenlib() skipped three-state cell \"%s\".\n", Scl_LibertyReadString(p, pCell->Head) ); |
| continue; |
| } |
| if ( Scl_LibertyReadCellOutputNum(p, pCell) == 0 ) |
| { |
| if ( fVerbose ) printf( "Scl_LibertyReadGenlib() skipped cell \"%s\" without logic function.\n", Scl_LibertyReadString(p, pCell->Head) ); |
| continue; |
| } |
| // iterate through output pins |
| Scl_ItemForEachChildName( p, pCell, pOutput, "pin" ) |
| { |
| if ( (pFormula = Scl_LibertyReadPinFormula(p, pOutput)) ) |
| continue; |
| if ( !strcmp(pFormula, "0") || !strcmp(pFormula, "1") ) |
| { |
| if ( fVerbose ) printf( "Scl_LibertyReadGenlib() skipped cell \"%s\" with constant formula \"%s\".\n", Scl_LibertyReadString(p, pCell->Head), pFormula ); |
| break; |
| } |
| Vec_StrPrintStr( vStr, "GATE " ); |
| Vec_StrPrintStr( vStr, Scl_LibertyReadString(p, pCell->Head) ); |
| Vec_StrPrintStr( vStr, " " ); |
| Vec_StrPrintStr( vStr, Scl_LibertyReadCellArea(p, pCell) ); |
| Vec_StrPrintStr( vStr, " " ); |
| Vec_StrPrintStr( vStr, Scl_LibertyReadString(p, pOutput->Head) ); |
| Vec_StrPrintStr( vStr, "=" ); |
| Vec_StrPrintStr( vStr, pFormula ); |
| Vec_StrPrintStr( vStr, ";\n" ); |
| // iterate through input pins |
| Scl_ItemForEachChildName( p, pCell, pInput, "pin" ) |
| { |
| if ( Scl_LibertyReadPinFormula(p, pInput) == NULL ) |
| continue; |
| Vec_StrPrintStr( vStr, " PIN " ); |
| Vec_StrPrintStr( vStr, Scl_LibertyReadString(p, pInput->Head) ); |
| Vec_StrPrintStr( vStr, " UNKNOWN 1 999 1.00 0.00 1.00 0.00\n" ); |
| } |
| } |
| } |
| Vec_StrPrintStr( vStr, "\n.end\n" ); |
| Vec_StrPush( vStr, '\0' ); |
| // printf( "%s", Vec_StrArray(vStr) ); |
| return vStr; |
| } |
| Vec_Str_t * Scl_LibertyParseGenlibStr( char * pFileName, int fVerbose ) |
| { |
| Scl_Tree_t * p; |
| Vec_Str_t * vStr; |
| p = Scl_LibertyParse( pFileName, fVerbose ); |
| if ( p == NULL ) |
| return NULL; |
| // Scl_LibertyRead( p, "temp_.lib" ); |
| vStr = Scl_LibertyReadGenlibStr( p, fVerbose ); |
| Scl_LibertyStop( p, fVerbose ); |
| // Scl_LibertyStringDump( "test_genlib.lib", vStr ); |
| return vStr; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Enabling debug output.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| //#define SCL_DEBUG |
| #ifdef SCL_DEBUG |
| static inline void Vec_StrPutI_( Vec_Str_t * vOut, int Val ) { printf( "%d ", Val ); Vec_StrPutI( vOut, Val ); } |
| static inline void Vec_StrPutW_( Vec_Str_t * vOut, word Val ) { printf( "%lu ", (long)Val ); Vec_StrPutW( vOut, Val ); } |
| static inline void Vec_StrPutF_( Vec_Str_t * vOut, float Val ) { printf( "%f ", Val ); Vec_StrPutF( vOut, Val ); } |
| static inline void Vec_StrPutS_( Vec_Str_t * vOut, char * Val ) { printf( "%s ", Val ); Vec_StrPutS( vOut, Val ); } |
| static inline void Vec_StrPut_( Vec_Str_t * vOut ) { printf( "\n" ); } |
| #else |
| static inline void Vec_StrPutI_( Vec_Str_t * vOut, int Val ) { Vec_StrPutI( vOut, Val ); } |
| static inline void Vec_StrPutW_( Vec_Str_t * vOut, word Val ) { Vec_StrPutW( vOut, Val ); } |
| static inline void Vec_StrPutF_( Vec_Str_t * vOut, float Val ) { Vec_StrPutF( vOut, Val ); } |
| static inline void Vec_StrPutS_( Vec_Str_t * vOut, char * Val ) { Vec_StrPutS( vOut, Val ); } |
| static inline void Vec_StrPut_( Vec_Str_t * vOut ) { } |
| #endif |
| |
| /**Function************************************************************* |
| |
| Synopsis [Parsing Liberty into internal data representation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| char * Scl_LibertyReadDefaultWireLoad( Scl_Tree_t * p ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pItem, "default_wire_load" ) |
| return Scl_LibertyReadString(p, pItem->Head); |
| return ""; |
| } |
| char * Scl_LibertyReadDefaultWireLoadSel( Scl_Tree_t * p ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pItem, "default_wire_load_selection" ) |
| return Scl_LibertyReadString(p, pItem->Head); |
| return ""; |
| } |
| float Scl_LibertyReadDefaultMaxTrans( Scl_Tree_t * p ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pItem, "default_max_transition" ) |
| return atof(Scl_LibertyReadString(p, pItem->Head)); |
| return 0; |
| } |
| int Scl_LibertyReadTimeUnit( Scl_Tree_t * p ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pItem, "time_unit" ) |
| { |
| char * pUnit = Scl_LibertyReadString(p, pItem->Head); |
| // 9=1ns, 10=100ps, 11=10ps, 12=1ps |
| if ( !strcmp(pUnit, "1ns") ) |
| return 9; |
| if ( !strcmp(pUnit, "100ps") ) |
| return 10; |
| if ( !strcmp(pUnit, "10ps") ) |
| return 11; |
| if ( !strcmp(pUnit, "1ps") ) |
| return 12; |
| break; |
| } |
| printf( "Libery parser cannot read \"time_unit\". Assuming time_unit : \"1ns\".\n" ); |
| return 9; |
| } |
| void Scl_LibertyReadLoadUnit( Scl_Tree_t * p, Vec_Str_t * vOut ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pItem, "capacitive_load_unit" ) |
| { |
| // expecting (1.00,ff) or (1, pf) ... 12 or 15 for 'pf' or 'ff' |
| char * pHead = Scl_LibertyReadString(p, pItem->Head); |
| float First = atof(strtok(pHead, " \t\n\r\\\",")); |
| char * pSecond = strtok(NULL, " \t\n\r\\\","); |
| Vec_StrPutF_( vOut, First ); |
| if ( pSecond && !strcmp(pSecond, "pf") ) |
| Vec_StrPutI_( vOut, 12 ); |
| else if ( pSecond && !strcmp(pSecond, "ff") ) |
| Vec_StrPutI_( vOut, 15 ); |
| else break; |
| return; |
| } |
| printf( "Libery parser cannot read \"capacitive_load_unit\". Assuming capacitive_load_unit(1, pf).\n" ); |
| Vec_StrPutF_( vOut, 1.0 ); |
| Vec_StrPutI_( vOut, 12 ); |
| } |
| void Scl_LibertyReadWireLoad( Scl_Tree_t * p, Vec_Str_t * vOut ) |
| { |
| Scl_Item_t * pItem, * pChild; |
| Vec_StrPutI_( vOut, Scl_LibertyItemNum(p, Scl_LibertyRoot(p), "wire_load") ); |
| Vec_StrPut_( vOut ); |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pItem, "wire_load" ) |
| { |
| Vec_StrPutS_( vOut, Scl_LibertyReadString(p, pItem->Head) ); |
| Scl_ItemForEachChildName( p, pItem, pChild, "capacitance" ) |
| Vec_StrPutF_( vOut, atof(Scl_LibertyReadString(p, pChild->Head)) ); |
| Scl_ItemForEachChildName( p, pItem, pChild, "slope" ) |
| Vec_StrPutF_( vOut, atof(Scl_LibertyReadString(p, pChild->Head)) ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPutI_( vOut, Scl_LibertyItemNum(p, pItem, "fanout_length") ); |
| Vec_StrPut_( vOut ); |
| Scl_ItemForEachChildName( p, pItem, pChild, "fanout_length" ) |
| { |
| char * pHead = Scl_LibertyReadString(p, pChild->Head); |
| int First = atoi( strtok(pHead, " ,") ); |
| float Second = atof( strtok(NULL, " ") ); |
| Vec_StrPutI_( vOut, First ); |
| Vec_StrPutF_( vOut, Second ); |
| Vec_StrPut_( vOut ); |
| } |
| Vec_StrPut_( vOut ); |
| } |
| Vec_StrPut_( vOut ); |
| } |
| void Scl_LibertyReadWireLoadSelect( Scl_Tree_t * p, Vec_Str_t * vOut ) |
| { |
| Scl_Item_t * pItem, * pChild; |
| Vec_StrPutI_( vOut, Scl_LibertyItemNum(p, Scl_LibertyRoot(p), "wire_load_selection") ); |
| Vec_StrPut_( vOut ); |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pItem, "wire_load_selection" ) |
| { |
| Vec_StrPutS_( vOut, Scl_LibertyReadString(p, pItem->Head) ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPutI_( vOut, Scl_LibertyItemNum(p, pItem, "wire_load_from_area") ); |
| Vec_StrPut_( vOut ); |
| Scl_ItemForEachChildName( p, pItem, pChild, "wire_load_from_area" ) |
| { |
| char * pHead = Scl_LibertyReadString(p, pChild->Head); |
| float First = atof( strtok(pHead, " ,") ); |
| float Second = atof( strtok(NULL, " ,") ); |
| char * pThird = strtok(NULL, " "); |
| if ( pThird[0] == '\"' ) |
| assert(pThird[strlen(pThird)-1] == '\"'), pThird[strlen(pThird)-1] = 0, pThird++; |
| Vec_StrPutF_( vOut, First ); |
| Vec_StrPutF_( vOut, Second ); |
| Vec_StrPutS_( vOut, pThird ); |
| Vec_StrPut_( vOut ); |
| } |
| Vec_StrPut_( vOut ); |
| } |
| Vec_StrPut_( vOut ); |
| } |
| int Scl_LibertyReadDeriveStrength( Scl_Tree_t * p, Scl_Item_t * pCell ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, pCell, pItem, "drive_strength" ) |
| return atoi(Scl_LibertyReadString(p, pItem->Head)); |
| return 0; |
| } |
| int Scl_LibertyReadPinDirection( Scl_Tree_t * p, Scl_Item_t * pPin ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, pPin, pItem, "direction" ) |
| { |
| char * pToken = Scl_LibertyReadString(p, pItem->Head); |
| if ( !strcmp(pToken, "input") ) |
| return 0; |
| if ( !strcmp(pToken, "output") ) |
| return 1; |
| break; |
| } |
| return -1; |
| } |
| float Scl_LibertyReadPinCap( Scl_Tree_t * p, Scl_Item_t * pPin, char * pName ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, pPin, pItem, pName ) |
| return atof(Scl_LibertyReadString(p, pItem->Head)); |
| return 0; |
| } |
| Scl_Item_t * Scl_LibertyReadPinTiming( Scl_Tree_t * p, Scl_Item_t * pPinOut, char * pNameIn ) |
| { |
| Scl_Item_t * pTiming, * pPinIn; |
| Scl_ItemForEachChildName( p, pPinOut, pTiming, "timing" ) |
| Scl_ItemForEachChildName( p, pTiming, pPinIn, "related_pin" ) |
| if ( !strcmp(Scl_LibertyReadString(p, pPinIn->Head), pNameIn) ) |
| return pTiming; |
| return NULL; |
| } |
| Vec_Ptr_t * Scl_LibertyReadPinTimingAll( Scl_Tree_t * p, Scl_Item_t * pPinOut, char * pNameIn ) |
| { |
| Vec_Ptr_t * vTimings; |
| Scl_Item_t * pTiming, * pPinIn; |
| vTimings = Vec_PtrAlloc( 16 ); |
| Scl_ItemForEachChildName( p, pPinOut, pTiming, "timing" ) |
| Scl_ItemForEachChildName( p, pTiming, pPinIn, "related_pin" ) |
| if ( !strcmp(Scl_LibertyReadString(p, pPinIn->Head), pNameIn) ) |
| Vec_PtrPush( vTimings, pTiming ); |
| return vTimings; |
| } |
| int Scl_LibertyReadTimingSense( Scl_Tree_t * p, Scl_Item_t * pPin ) |
| { |
| Scl_Item_t * pItem; |
| Scl_ItemForEachChildName( p, pPin, pItem, "timing_sense" ) |
| { |
| char * pToken = Scl_LibertyReadString(p, pItem->Head); |
| if ( !strcmp(pToken, "positive_unate") ) |
| return sc_ts_Pos; |
| if ( !strcmp(pToken, "negative_unate") ) |
| return sc_ts_Neg; |
| if ( !strcmp(pToken, "non_unate") ) |
| return sc_ts_Non; |
| break; |
| } |
| return sc_ts_Non; |
| } |
| Vec_Flt_t * Scl_LibertyReadFloatVec( char * pName ) |
| { |
| char * pToken; |
| Vec_Flt_t * vValues = Vec_FltAlloc( 100 ); |
| for ( pToken = strtok(pName, " \t\n\r\\\","); pToken; pToken = strtok(NULL, " \t\n\r\\\",") ) |
| Vec_FltPush( vValues, atof(pToken) ); |
| return vValues; |
| } |
| |
| void Scl_LibertyDumpTables( Vec_Str_t * vOut, Vec_Flt_t * vInd1, Vec_Flt_t * vInd2, Vec_Flt_t * vValues ) |
| { |
| int i; float Entry; |
| // write entries |
| Vec_StrPutI_( vOut, Vec_FltSize(vInd1) ); |
| Vec_FltForEachEntry( vInd1, Entry, i ) |
| Vec_StrPutF_( vOut, Entry ); |
| Vec_StrPut_( vOut ); |
| // write entries |
| Vec_StrPutI_( vOut, Vec_FltSize(vInd2) ); |
| Vec_FltForEachEntry( vInd2, Entry, i ) |
| Vec_StrPutF_( vOut, Entry ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| // write entries |
| assert( Vec_FltSize(vInd1) * Vec_FltSize(vInd2) == Vec_FltSize(vValues) ); |
| Vec_FltForEachEntry( vValues, Entry, i ) |
| { |
| Vec_StrPutF_( vOut, Entry ); |
| if ( i % Vec_FltSize(vInd2) == Vec_FltSize(vInd2)-1 ) |
| Vec_StrPut_( vOut ); |
| } |
| // dump approximations |
| Vec_StrPut_( vOut ); |
| for ( i = 0; i < 3; i++ ) |
| Vec_StrPutF_( vOut, 0 ); |
| for ( i = 0; i < 4; i++ ) |
| Vec_StrPutF_( vOut, 0 ); |
| for ( i = 0; i < 6; i++ ) |
| Vec_StrPutF_( vOut, 0 ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| } |
| int Scl_LibertyScanTable( Scl_Tree_t * p, Vec_Ptr_t * vOut, Scl_Item_t * pTiming, char * pName, Vec_Ptr_t * vTemples ) |
| { |
| Vec_Flt_t * vIndex1 = NULL; |
| Vec_Flt_t * vIndex2 = NULL; |
| Vec_Flt_t * vValues = NULL; |
| Vec_Flt_t * vInd1, * vInd2; |
| Scl_Item_t * pItem, * pTable = NULL; |
| char * pThis, * pTempl = NULL; |
| int iPlace, i; |
| float Entry; |
| // find the table |
| Scl_ItemForEachChildName( p, pTiming, pTable, pName ) |
| break; |
| if ( pTable == NULL ) |
| return 0; |
| // find the template |
| pTempl = Scl_LibertyReadString(p, pTable->Head); |
| if ( pTempl == NULL || pTempl[0] == 0 ) |
| { |
| // read the numbers |
| Scl_ItemForEachChild( p, pTable, pItem ) |
| { |
| if ( !Scl_LibertyCompare(p, pItem->Key, "index_1") ) |
| assert(vIndex1 == NULL), vIndex1 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "index_2") ) |
| assert(vIndex2 == NULL), vIndex2 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "values") ) |
| assert(vValues == NULL), vValues = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| } |
| if ( vIndex1 == NULL || vIndex2 == NULL || vValues == NULL ) |
| { printf( "Incomplete table specification\n" ); return 0; } |
| // dump the table |
| vInd1 = vIndex1; |
| vInd2 = vIndex2; |
| // write entries |
| Vec_PtrPush( vOut, vInd1 ); |
| Vec_PtrPush( vOut, vInd2 ); |
| Vec_PtrPush( vOut, vValues ); |
| } |
| else if ( !strcmp(pTempl, "scalar") ) |
| { |
| Scl_ItemForEachChild( p, pTable, pItem ) |
| if ( !Scl_LibertyCompare(p, pItem->Key, "values") ) |
| { |
| assert(vValues == NULL); |
| vValues = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| assert( Vec_FltSize(vValues) == 1 ); |
| // write entries |
| Vec_PtrPush( vOut, Vec_IntStart(1) ); |
| Vec_PtrPush( vOut, Vec_IntStart(1) ); |
| Vec_PtrPush( vOut, vValues ); |
| break; |
| } |
| else |
| { printf( "Cannot read \"scalar\" template\n" ); return 0; } |
| } |
| else |
| { |
| // fetch the template |
| iPlace = -1; |
| Vec_PtrForEachEntry( char *, vTemples, pThis, i ) |
| if ( i % 4 == 0 && !strcmp(pTempl, pThis) ) |
| { |
| iPlace = i; |
| break; |
| } |
| if ( iPlace == -1 ) |
| { printf( "Template cannot be found in the template library\n" ); return 0; } |
| // read the numbers |
| Scl_ItemForEachChild( p, pTable, pItem ) |
| { |
| if ( !Scl_LibertyCompare(p, pItem->Key, "index_1") ) |
| assert(vIndex1 == NULL), vIndex1 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "index_2") ) |
| assert(vIndex2 == NULL), vIndex2 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "values") ) |
| assert(vValues == NULL), vValues = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| } |
| // check the template style |
| vInd1 = (Vec_Flt_t *)Vec_PtrEntry( vTemples, iPlace + 2 ); // slew |
| vInd2 = (Vec_Flt_t *)Vec_PtrEntry( vTemples, iPlace + 3 ); // load |
| if ( Vec_PtrEntry(vTemples, iPlace + 1) == NULL ) // normal order (vIndex1 is slew; vIndex2 is load) |
| { |
| assert( !vIndex1 || Vec_FltSize(vIndex1) == Vec_FltSize(vInd1) ); |
| assert( !vIndex2 || Vec_FltSize(vIndex2) == Vec_FltSize(vInd2) ); |
| vInd1 = vIndex1 ? vIndex1 : vInd1; |
| vInd2 = vIndex2 ? vIndex2 : vInd2; |
| // write entries |
| Vec_PtrPush( vOut, Vec_FltDup(vInd1) ); |
| Vec_PtrPush( vOut, Vec_FltDup(vInd2) ); |
| Vec_PtrPush( vOut, Vec_FltDup(vValues) ); |
| } |
| else // reverse order (vIndex2 is slew; vIndex1 is load) |
| { |
| Vec_Flt_t * vValues2 = Vec_FltAlloc( Vec_FltSize(vValues) ); |
| assert( !vIndex2 || Vec_FltSize(vIndex2) == Vec_FltSize(vInd1) ); |
| assert( !vIndex1 || Vec_FltSize(vIndex1) == Vec_FltSize(vInd2) ); |
| vInd1 = vIndex2 ? vIndex2 : vInd1; |
| vInd2 = vIndex1 ? vIndex1 : vInd2; |
| // write entries -- transpose |
| assert( Vec_FltSize(vInd1) * Vec_FltSize(vInd2) == Vec_FltSize(vValues) ); |
| Vec_FltForEachEntry( vValues, Entry, i ) |
| { |
| int x = i % Vec_FltSize(vInd2); |
| int y = i / Vec_FltSize(vInd2); |
| Entry = Vec_FltEntry( vValues, x * Vec_FltSize(vInd1) + y ); |
| Vec_FltPush( vValues2, Entry ); |
| } |
| assert( Vec_FltSize(vValues) == Vec_FltSize(vValues2) ); |
| // write entries |
| Vec_PtrPush( vOut, Vec_FltDup(vInd1) ); |
| Vec_PtrPush( vOut, Vec_FltDup(vInd2) ); |
| Vec_PtrPush( vOut, vValues2 ); |
| } |
| Vec_FltFreeP( &vIndex1 ); |
| Vec_FltFreeP( &vIndex2 ); |
| Vec_FltFreeP( &vValues ); |
| } |
| return 1; |
| } |
| int Scl_LibertyComputeWorstCase( Vec_Ptr_t * vTables, Vec_Flt_t ** pvInd0, Vec_Flt_t ** pvInd1, Vec_Flt_t ** pvValues ) |
| { |
| Vec_Flt_t * vInd0, * vInd1, * vValues; |
| Vec_Flt_t * vind0, * vind1, * vvalues; |
| int i, k, nTriples = Vec_PtrSize(vTables) / 3; |
| float Entry; |
| assert( Vec_PtrSize(vTables) > 0 && Vec_PtrSize(vTables) % 3 == 0 ); |
| if ( nTriples == 1 ) |
| { |
| *pvInd0 = (Vec_Flt_t *)Vec_PtrEntry(vTables, 0); |
| *pvInd1 = (Vec_Flt_t *)Vec_PtrEntry(vTables, 1); |
| *pvValues = (Vec_Flt_t *)Vec_PtrEntry(vTables, 2); |
| Vec_PtrShrink( vTables, 0 ); |
| return 1; |
| } |
| vInd0 = Vec_FltDup( (Vec_Flt_t *)Vec_PtrEntry(vTables, 0) ); |
| vInd1 = Vec_FltDup( (Vec_Flt_t *)Vec_PtrEntry(vTables, 1) ); |
| vValues = Vec_FltDup( (Vec_Flt_t *)Vec_PtrEntry(vTables, 2) ); |
| for ( i = 1; i < nTriples; i++ ) |
| { |
| vind0 = (Vec_Flt_t *)Vec_PtrEntry(vTables, i*3+0); |
| vind1 = (Vec_Flt_t *)Vec_PtrEntry(vTables, i*3+1); |
| vvalues = (Vec_Flt_t *)Vec_PtrEntry(vTables, i*3+2); |
| // check equality of indexes |
| if ( !Vec_FltEqual(vind0, vInd0) ) |
| continue;//return 0; |
| if ( !Vec_FltEqual(vind1, vInd1) ) |
| continue;//return 0; |
| // Vec_FltForEachEntry( vvalues, Entry, k ) |
| // Vec_FltAddToEntry( vValues, k, Entry ); |
| Vec_FltForEachEntry( vvalues, Entry, k ) |
| if ( Vec_FltEntry(vValues, k) < Entry ) |
| Vec_FltWriteEntry( vValues, k, Entry ); |
| } |
| // Vec_FltForEachEntry( vValues, Entry, k ) |
| // Vec_FltWriteEntry( vValues, k, Entry/nTriples ); |
| // return the result |
| *pvInd0 = vInd0; |
| *pvInd1 = vInd1; |
| *pvValues = vValues; |
| return 1; |
| } |
| |
| int Scl_LibertyReadTable( Scl_Tree_t * p, Vec_Str_t * vOut, Scl_Item_t * pTiming, char * pName, Vec_Ptr_t * vTemples ) |
| { |
| Vec_Flt_t * vIndex1 = NULL; |
| Vec_Flt_t * vIndex2 = NULL; |
| Vec_Flt_t * vValues = NULL; |
| Vec_Flt_t * vInd1, * vInd2; |
| Scl_Item_t * pItem, * pTable = NULL; |
| char * pThis, * pTempl = NULL; |
| int iPlace, i; |
| float Entry; |
| // find the table |
| Scl_ItemForEachChildName( p, pTiming, pTable, pName ) |
| break; |
| if ( pTable == NULL ) |
| return 0; |
| // find the template |
| pTempl = Scl_LibertyReadString(p, pTable->Head); |
| if ( pTempl == NULL || pTempl[0] == 0 ) |
| { |
| // read the numbers |
| Scl_ItemForEachChild( p, pTable, pItem ) |
| { |
| if ( !Scl_LibertyCompare(p, pItem->Key, "index_1") ) |
| assert(vIndex1 == NULL), vIndex1 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "index_2") ) |
| assert(vIndex2 == NULL), vIndex2 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "values") ) |
| assert(vValues == NULL), vValues = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| } |
| if ( vIndex1 == NULL || vIndex2 == NULL || vValues == NULL ) |
| { printf( "Incomplete table specification\n" ); return 0; } |
| // dump the table |
| vInd1 = vIndex1; |
| vInd2 = vIndex2; |
| // write entries |
| Vec_StrPutI_( vOut, Vec_FltSize(vInd1) ); |
| Vec_FltForEachEntry( vInd1, Entry, i ) |
| Vec_StrPutF_( vOut, Entry ); |
| Vec_StrPut_( vOut ); |
| // write entries |
| Vec_StrPutI_( vOut, Vec_FltSize(vInd2) ); |
| Vec_FltForEachEntry( vInd2, Entry, i ) |
| Vec_StrPutF_( vOut, Entry ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| // write entries |
| assert( Vec_FltSize(vInd1) * Vec_FltSize(vInd2) == Vec_FltSize(vValues) ); |
| Vec_FltForEachEntry( vValues, Entry, i ) |
| { |
| Vec_StrPutF_( vOut, Entry ); |
| if ( i % Vec_FltSize(vInd2) == Vec_FltSize(vInd2)-1 ) |
| Vec_StrPut_( vOut ); |
| } |
| } |
| else |
| { |
| // fetch the template |
| iPlace = -1; |
| Vec_PtrForEachEntry( char *, vTemples, pThis, i ) |
| if ( i % 4 == 0 && !strcmp(pTempl, pThis) ) |
| { |
| iPlace = i; |
| break; |
| } |
| if ( iPlace == -1 ) |
| { printf( "Template cannot be found in the template library\n" ); return 0; } |
| // read the numbers |
| Scl_ItemForEachChild( p, pTable, pItem ) |
| { |
| if ( !Scl_LibertyCompare(p, pItem->Key, "index_1") ) |
| assert(vIndex1 == NULL), vIndex1 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "index_2") ) |
| assert(vIndex2 == NULL), vIndex2 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "values") ) |
| assert(vValues == NULL), vValues = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| } |
| // check the template style |
| vInd1 = (Vec_Flt_t *)Vec_PtrEntry( vTemples, iPlace + 2 ); // slew |
| vInd2 = (Vec_Flt_t *)Vec_PtrEntry( vTemples, iPlace + 3 ); // load |
| if ( Vec_PtrEntry(vTemples, iPlace + 1) == NULL ) // normal order (vIndex1 is slew; vIndex2 is load) |
| { |
| assert( !vIndex1 || Vec_FltSize(vIndex1) == Vec_FltSize(vInd1) ); |
| assert( !vIndex2 || Vec_FltSize(vIndex2) == Vec_FltSize(vInd2) ); |
| vInd1 = vIndex1 ? vIndex1 : vInd1; |
| vInd2 = vIndex2 ? vIndex2 : vInd2; |
| // write entries |
| Vec_StrPutI_( vOut, Vec_FltSize(vInd1) ); |
| Vec_FltForEachEntry( vInd1, Entry, i ) |
| Vec_StrPutF_( vOut, Entry ); |
| Vec_StrPut_( vOut ); |
| // write entries |
| Vec_StrPutI_( vOut, Vec_FltSize(vInd2) ); |
| Vec_FltForEachEntry( vInd2, Entry, i ) |
| Vec_StrPutF_( vOut, Entry ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| // write entries |
| assert( Vec_FltSize(vInd1) * Vec_FltSize(vInd2) == Vec_FltSize(vValues) ); |
| Vec_FltForEachEntry( vValues, Entry, i ) |
| { |
| Vec_StrPutF_( vOut, Entry ); |
| if ( i % Vec_FltSize(vInd2) == Vec_FltSize(vInd2)-1 ) |
| Vec_StrPut_( vOut ); |
| } |
| } |
| else // reverse order (vIndex2 is slew; vIndex1 is load) |
| { |
| assert( !vIndex2 || Vec_FltSize(vIndex2) == Vec_FltSize(vInd1) ); |
| assert( !vIndex1 || Vec_FltSize(vIndex1) == Vec_FltSize(vInd2) ); |
| vInd1 = vIndex2 ? vIndex2 : vInd1; |
| vInd2 = vIndex1 ? vIndex1 : vInd2; |
| // write entries |
| Vec_StrPutI_( vOut, Vec_FltSize(vInd1) ); |
| Vec_FltForEachEntry( vInd1, Entry, i ) |
| Vec_StrPutF_( vOut, Entry ); |
| Vec_StrPut_( vOut ); |
| // write entries |
| Vec_StrPutI_( vOut, Vec_FltSize(vInd2) ); |
| Vec_FltForEachEntry( vInd2, Entry, i ) |
| Vec_StrPutF_( vOut, Entry ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| // write entries -- transpose |
| assert( Vec_FltSize(vInd1) * Vec_FltSize(vInd2) == Vec_FltSize(vValues) ); |
| Vec_FltForEachEntry( vValues, Entry, i ) |
| { |
| int x = i % Vec_FltSize(vInd2); |
| int y = i / Vec_FltSize(vInd2); |
| Entry = Vec_FltEntry( vValues, x * Vec_FltSize(vInd1) + y ); |
| Vec_StrPutF_( vOut, Entry ); |
| if ( i % Vec_FltSize(vInd2) == Vec_FltSize(vInd2)-1 ) |
| Vec_StrPut_( vOut ); |
| } |
| } |
| } |
| Vec_StrPut_( vOut ); |
| for ( i = 0; i < 3; i++ ) |
| Vec_StrPutF_( vOut, 0 ); |
| for ( i = 0; i < 4; i++ ) |
| Vec_StrPutF_( vOut, 0 ); |
| for ( i = 0; i < 6; i++ ) |
| Vec_StrPutF_( vOut, 0 ); |
| Vec_FltFreeP( &vIndex1 ); |
| Vec_FltFreeP( &vIndex2 ); |
| Vec_FltFreeP( &vValues ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| return 1; |
| } |
| void Scl_LibertyPrintTemplates( Vec_Ptr_t * vRes ) |
| { |
| Vec_Flt_t * vArray; int i; |
| assert( Vec_PtrSize(vRes) % 4 == 0 ); |
| printf( "There are %d slew/load templates\n", Vec_PtrSize(vRes) % 4 ); |
| Vec_PtrForEachEntry( Vec_Flt_t *, vRes, vArray, i ) |
| { |
| if ( i % 4 == 0 ) |
| printf( "%s\n", (char *)vArray ); |
| else if ( i % 4 == 1 ) |
| printf( "%d\n", (int)(vArray != NULL) ); |
| else if ( i % 4 == 2 || i % 4 == 3 ) |
| Vec_FltPrint( vArray ); |
| if ( i % 4 == 3 ) |
| printf( "\n" ); |
| } |
| } |
| Vec_Ptr_t * Scl_LibertyReadTemplates( Scl_Tree_t * p ) |
| { |
| Vec_Ptr_t * vRes = NULL; |
| Vec_Flt_t * vIndex1, * vIndex2; |
| Scl_Item_t * pTempl, * pItem; |
| char * pVar1, * pVar2; |
| int fFlag0, fFlag1; |
| vRes = Vec_PtrAlloc( 100 ); |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pTempl, "lu_table_template" ) |
| { |
| pVar1 = pVar2 = NULL; |
| vIndex1 = vIndex2 = NULL; |
| Scl_ItemForEachChild( p, pTempl, pItem ) |
| { |
| if ( !Scl_LibertyCompare(p, pItem->Key, "index_1") ) |
| assert(vIndex1 == NULL), vIndex1 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "index_2") ) |
| assert(vIndex2 == NULL), vIndex2 = Scl_LibertyReadFloatVec( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "variable_1") ) |
| assert(pVar1 == NULL), pVar1 = Abc_UtilStrsav( Scl_LibertyReadString(p, pItem->Head) ); |
| else if ( !Scl_LibertyCompare(p, pItem->Key, "variable_2") ) |
| assert(pVar2 == NULL), pVar2 = Abc_UtilStrsav( Scl_LibertyReadString(p, pItem->Head) ); |
| } |
| if ( pVar1 == NULL || pVar2 == NULL ) |
| { |
| ABC_FREE( pVar1 ); |
| ABC_FREE( pVar2 ); |
| Vec_FltFreeP( &vIndex1 ); |
| Vec_FltFreeP( &vIndex2 ); |
| continue; |
| } |
| assert( pVar1 != NULL && pVar2 != NULL ); |
| fFlag0 = (!strcmp(pVar1, "input_net_transition") && !strcmp(pVar2, "total_output_net_capacitance")); |
| fFlag1 = (!strcmp(pVar2, "input_net_transition") && !strcmp(pVar1, "total_output_net_capacitance")); |
| ABC_FREE( pVar1 ); |
| ABC_FREE( pVar2 ); |
| if ( !fFlag0 && !fFlag1 ) |
| { |
| Vec_FltFreeP( &vIndex1 ); |
| Vec_FltFreeP( &vIndex2 ); |
| continue; |
| } |
| Vec_PtrPush( vRes, Abc_UtilStrsav( Scl_LibertyReadString(p, pTempl->Head) ) ); |
| Vec_PtrPush( vRes, fFlag0 ? NULL : (void *)(ABC_PTRINT_T)1 ); |
| Vec_PtrPush( vRes, fFlag0 ? vIndex1 : vIndex2 ); |
| Vec_PtrPush( vRes, fFlag0 ? vIndex2 : vIndex1 ); |
| } |
| if ( Vec_PtrSize(vRes) == 0 ) |
| Abc_Print( 0, "Templates are not defined.\n" ); |
| // print templates |
| // printf( "Found %d templates\n", Vec_PtrSize(vRes)/4 ); |
| // Scl_LibertyPrintTemplates( vRes ); |
| return vRes; |
| } |
| Vec_Str_t * Scl_LibertyReadSclStr( Scl_Tree_t * p, int fVerbose, int fVeryVerbose ) |
| { |
| int fUseFirstTable = 0; |
| Vec_Str_t * vOut; |
| Vec_Ptr_t * vNameIns, * vTemples = NULL; |
| Scl_Item_t * pCell, * pPin, * pTiming; |
| Vec_Wrd_t * vTruth; |
| char * pFormula, * pName; |
| int i, k, Counter, nOutputs, nCells; |
| int nSkipped[3] = {0}; |
| |
| // read delay-table templates |
| vTemples = Scl_LibertyReadTemplates( p ); |
| |
| // start the library |
| vOut = Vec_StrAlloc( 10000 ); |
| Vec_StrPutI_( vOut, ABC_SCL_CUR_VERSION ); |
| |
| // top level information |
| Vec_StrPut_( vOut ); |
| Vec_StrPutS_( vOut, Scl_LibertyReadString(p, Scl_LibertyRoot(p)->Head) ); |
| Vec_StrPutS_( vOut, Scl_LibertyReadDefaultWireLoad(p) ); |
| Vec_StrPutS_( vOut, Scl_LibertyReadDefaultWireLoadSel(p) ); |
| Vec_StrPutF_( vOut, Scl_LibertyReadDefaultMaxTrans(p) ); |
| Vec_StrPutI_( vOut, Scl_LibertyReadTimeUnit(p) ); |
| Scl_LibertyReadLoadUnit( p, vOut ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| |
| // read wire loads |
| Scl_LibertyReadWireLoad( p, vOut ); |
| Scl_LibertyReadWireLoadSelect( p, vOut ); |
| |
| // count cells |
| nCells = 0; |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pCell, "cell" ) |
| { |
| if ( Scl_LibertyReadCellIsFlop(p, pCell) ) |
| { |
| if ( fVeryVerbose ) printf( "Scl_LibertyReadGenlib() skipped sequential cell \"%s\".\n", Scl_LibertyReadString(p, pCell->Head) ); |
| nSkipped[0]++; |
| continue; |
| } |
| if ( Scl_LibertyReadCellIsThreeState(p, pCell) ) |
| { |
| if ( fVeryVerbose ) printf( "Scl_LibertyReadGenlib() skipped three-state cell \"%s\".\n", Scl_LibertyReadString(p, pCell->Head) ); |
| nSkipped[1]++; |
| continue; |
| } |
| if ( (Counter = Scl_LibertyReadCellOutputNum(p, pCell)) == 0 ) |
| { |
| if ( fVeryVerbose ) printf( "Scl_LibertyReadGenlib() skipped cell \"%s\" without logic function.\n", Scl_LibertyReadString(p, pCell->Head) ); |
| nSkipped[2]++; |
| continue; |
| } |
| nCells++; |
| } |
| // read cells |
| Vec_StrPutI_( vOut, nCells ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| Scl_ItemForEachChildName( p, Scl_LibertyRoot(p), pCell, "cell" ) |
| { |
| if ( Scl_LibertyReadCellIsFlop(p, pCell) ) |
| continue; |
| if ( Scl_LibertyReadCellIsThreeState(p, pCell) ) |
| continue; |
| if ( (Counter = Scl_LibertyReadCellOutputNum(p, pCell)) == 0 ) |
| continue; |
| // top level information |
| Vec_StrPutS_( vOut, Scl_LibertyReadString(p, pCell->Head) ); |
| pName = Scl_LibertyReadCellArea(p, pCell); |
| Vec_StrPutF_( vOut, pName ? atof(pName) : 1 ); |
| pName = Scl_LibertyReadCellLeakage(p, pCell); |
| Vec_StrPutF_( vOut, pName ? atof(pName) : 0 ); |
| Vec_StrPutI_( vOut, Scl_LibertyReadDeriveStrength(p, pCell) ); |
| // pin count |
| nOutputs = Scl_LibertyReadCellOutputNum( p, pCell ); |
| Vec_StrPutI_( vOut, Scl_LibertyItemNum(p, pCell, "pin") - nOutputs ); |
| Vec_StrPutI_( vOut, nOutputs ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| |
| // input pins |
| vNameIns = Vec_PtrAlloc( 16 ); |
| Scl_ItemForEachChildName( p, pCell, pPin, "pin" ) |
| { |
| float CapOne, CapRise, CapFall; |
| if ( Scl_LibertyReadPinFormula(p, pPin) != NULL ) // skip output pin |
| continue; |
| assert( Scl_LibertyReadPinDirection(p, pPin) == 0 ); |
| pName = Scl_LibertyReadString(p, pPin->Head); |
| Vec_PtrPush( vNameIns, Abc_UtilStrsav(pName) ); |
| Vec_StrPutS_( vOut, pName ); |
| CapOne = Scl_LibertyReadPinCap( p, pPin, "capacitance" ); |
| CapRise = Scl_LibertyReadPinCap( p, pPin, "rise_capacitance" ); |
| CapFall = Scl_LibertyReadPinCap( p, pPin, "fall_capacitance" ); |
| if ( CapRise == 0 ) |
| CapRise = CapOne; |
| if ( CapFall == 0 ) |
| CapFall = CapOne; |
| Vec_StrPutF_( vOut, CapRise ); |
| Vec_StrPutF_( vOut, CapFall ); |
| Vec_StrPut_( vOut ); |
| } |
| Vec_StrPut_( vOut ); |
| // output pins |
| Scl_ItemForEachChildName( p, pCell, pPin, "pin" ) |
| { |
| if ( !Scl_LibertyReadPinFormula(p, pPin) ) // skip input pin |
| continue; |
| assert( Scl_LibertyReadPinDirection(p, pPin) == 1 ); |
| pName = Scl_LibertyReadString(p, pPin->Head); |
| Vec_StrPutS_( vOut, pName ); |
| Vec_StrPutF_( vOut, Scl_LibertyReadPinCap( p, pPin, "max_capacitance" ) ); |
| Vec_StrPutF_( vOut, Scl_LibertyReadPinCap( p, pPin, "max_transition" ) ); |
| Vec_StrPutI_( vOut, Vec_PtrSize(vNameIns) ); |
| pFormula = Scl_LibertyReadPinFormula(p, pPin); |
| Vec_StrPutS_( vOut, pFormula ); |
| // write truth table |
| vTruth = Mio_ParseFormulaTruth( pFormula, (char **)Vec_PtrArray(vNameIns), Vec_PtrSize(vNameIns) ); |
| if ( vTruth == NULL ) |
| return NULL; |
| for ( i = 0; i < Abc_Truth6WordNum(Vec_PtrSize(vNameIns)); i++ ) |
| Vec_StrPutW_( vOut, Vec_WrdEntry(vTruth, i) ); |
| Vec_WrdFree( vTruth ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| |
| // write the delay tables |
| if ( fUseFirstTable ) |
| { |
| Vec_PtrForEachEntry( char *, vNameIns, pName, i ) |
| { |
| pTiming = Scl_LibertyReadPinTiming( p, pPin, pName ); |
| Vec_StrPutS_( vOut, pName ); |
| Vec_StrPutI_( vOut, (int)(pTiming != NULL) ); |
| if ( pTiming == NULL ) // output does not depend on input |
| continue; |
| Vec_StrPutI_( vOut, Scl_LibertyReadTimingSense(p, pTiming) ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| // some cells only have 'rise' or 'fall' but not both - here we work around this |
| if ( !Scl_LibertyReadTable( p, vOut, pTiming, "cell_rise", vTemples ) ) |
| if ( !Scl_LibertyReadTable( p, vOut, pTiming, "cell_fall", vTemples ) ) |
| { printf( "Table cannot be found\n" ); return NULL; } |
| if ( !Scl_LibertyReadTable( p, vOut, pTiming, "cell_fall", vTemples ) ) |
| if ( !Scl_LibertyReadTable( p, vOut, pTiming, "cell_rise", vTemples ) ) |
| { printf( "Table cannot be found\n" ); return NULL; } |
| if ( !Scl_LibertyReadTable( p, vOut, pTiming, "rise_transition", vTemples ) ) |
| if ( !Scl_LibertyReadTable( p, vOut, pTiming, "fall_transition", vTemples ) ) |
| { printf( "Table cannot be found\n" ); return NULL; } |
| if ( !Scl_LibertyReadTable( p, vOut, pTiming, "fall_transition", vTemples ) ) |
| if ( !Scl_LibertyReadTable( p, vOut, pTiming, "rise_transition", vTemples ) ) |
| { printf( "Table cannot be found\n" ); return NULL; } |
| } |
| continue; |
| } |
| |
| // write the timing tables |
| Vec_PtrForEachEntry( char *, vNameIns, pName, i ) |
| { |
| Vec_Ptr_t * vTables[4]; |
| Vec_Ptr_t * vTimings; |
| vTimings = Scl_LibertyReadPinTimingAll( p, pPin, pName ); |
| Vec_StrPutS_( vOut, pName ); |
| Vec_StrPutI_( vOut, (int)(Vec_PtrSize(vTimings) != 0) ); |
| if ( Vec_PtrSize(vTimings) == 0 ) // output does not depend on input |
| { |
| Vec_PtrFree( vTimings ); |
| continue; |
| } |
| Vec_StrPutI_( vOut, Scl_LibertyReadTimingSense(p, (Scl_Item_t *)Vec_PtrEntry(vTimings, 0)) ); |
| Vec_StrPut_( vOut ); |
| Vec_StrPut_( vOut ); |
| // collect the timing tables |
| for ( k = 0; k < 4; k++ ) |
| vTables[k] = Vec_PtrAlloc( 16 ); |
| Vec_PtrForEachEntry( Scl_Item_t *, vTimings, pTiming, k ) |
| { |
| // some cells only have 'rise' or 'fall' but not both - here we work around this |
| if ( !Scl_LibertyScanTable( p, vTables[0], pTiming, "cell_rise", vTemples ) ) |
| if ( !Scl_LibertyScanTable( p, vTables[0], pTiming, "cell_fall", vTemples ) ) |
| { printf( "Table cannot be found\n" ); return NULL; } |
| if ( !Scl_LibertyScanTable( p, vTables[1], pTiming, "cell_fall", vTemples ) ) |
| if ( !Scl_LibertyScanTable( p, vTables[1], pTiming, "cell_rise", vTemples ) ) |
| { printf( "Table cannot be found\n" ); return NULL; } |
| if ( !Scl_LibertyScanTable( p, vTables[2], pTiming, "rise_transition", vTemples ) ) |
| if ( !Scl_LibertyScanTable( p, vTables[2], pTiming, "fall_transition", vTemples ) ) |
| { printf( "Table cannot be found\n" ); return NULL; } |
| if ( !Scl_LibertyScanTable( p, vTables[3], pTiming, "fall_transition", vTemples ) ) |
| if ( !Scl_LibertyScanTable( p, vTables[3], pTiming, "rise_transition", vTemples ) ) |
| { printf( "Table cannot be found\n" ); return NULL; } |
| } |
| Vec_PtrFree( vTimings ); |
| // compute worse case of the tables |
| for ( k = 0; k < 4; k++ ) |
| { |
| Vec_Flt_t * vInd0, * vInd1, * vValues; |
| if ( !Scl_LibertyComputeWorstCase( vTables[k], &vInd0, &vInd1, &vValues ) ) |
| { printf( "Table indexes have different values\n" ); return NULL; } |
| Vec_VecFree( (Vec_Vec_t *)vTables[k] ); |
| Scl_LibertyDumpTables( vOut, vInd0, vInd1, vValues ); |
| Vec_FltFree( vInd0 ); |
| Vec_FltFree( vInd1 ); |
| Vec_FltFree( vValues ); |
| } |
| } |
| } |
| Vec_StrPut_( vOut ); |
| Vec_PtrFreeFree( vNameIns ); |
| } |
| // free templates |
| if ( vTemples ) |
| { |
| Vec_Flt_t * vArray; |
| assert( Vec_PtrSize(vTemples) % 4 == 0 ); |
| Vec_PtrForEachEntry( Vec_Flt_t *, vTemples, vArray, i ) |
| { |
| if ( vArray == NULL ) |
| continue; |
| if ( i % 4 == 0 ) |
| ABC_FREE( vArray ); |
| else if ( i % 4 == 2 || i % 4 == 3 ) |
| Vec_FltFree( vArray ); |
| } |
| Vec_PtrFree( vTemples ); |
| } |
| if ( fVerbose ) |
| { |
| printf( "Library \"%s\" from \"%s\" has %d cells ", |
| Scl_LibertyReadString(p, Scl_LibertyRoot(p)->Head), p->pFileName, nCells ); |
| printf( "(%d skipped: %d seq; %d tri-state; %d no func). ", |
| nSkipped[0]+nSkipped[1]+nSkipped[2], nSkipped[0], nSkipped[1], nSkipped[2] ); |
| Abc_PrintTime( 1, "Time", Abc_Clock() - p->clkStart ); |
| } |
| return vOut; |
| } |
| SC_Lib * Abc_SclReadLiberty( char * pFileName, int fVerbose, int fVeryVerbose ) |
| { |
| SC_Lib * pLib; |
| Scl_Tree_t * p; |
| Vec_Str_t * vStr; |
| p = Scl_LibertyParse( pFileName, fVeryVerbose ); |
| if ( p == NULL ) |
| return NULL; |
| // Scl_LibertyParseDump( p, "temp_.lib" ); |
| // collect relevant data |
| vStr = Scl_LibertyReadSclStr( p, fVerbose, fVeryVerbose ); |
| Scl_LibertyStop( p, fVeryVerbose ); |
| if ( vStr == NULL ) |
| return NULL; |
| // construct SCL data-structure |
| pLib = Abc_SclReadFromStr( vStr ); |
| if ( pLib == NULL ) |
| return NULL; |
| pLib->pFileName = Abc_UtilStrsav( pFileName ); |
| Abc_SclLibNormalize( pLib ); |
| Vec_StrFree( vStr ); |
| // printf( "Average slew = %.2f ps\n", Abc_SclComputeAverageSlew(pLib) ); |
| return pLib; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Experiments with Liberty parsing.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Scl_LibertyTest() |
| { |
| char * pFileName = "bwrc.lib"; |
| int fVerbose = 1; |
| int fVeryVerbose = 0; |
| Scl_Tree_t * p; |
| Vec_Str_t * vStr; |
| // return; |
| p = Scl_LibertyParse( pFileName, fVeryVerbose ); |
| if ( p == NULL ) |
| return; |
| // Scl_LibertyParseDump( p, "temp_.lib" ); |
| vStr = Scl_LibertyReadSclStr( p, fVerbose, fVeryVerbose ); |
| Scl_LibertyStringDump( "test_scl.lib", vStr ); |
| Vec_StrFree( vStr ); |
| Scl_LibertyStop( p, fVerbose ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |