/**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; 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 ); } 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; 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; 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 ", 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) ); 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 ( 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