1 /**CFile****************************************************************
2
3 FileName [sclLibUtil.c]
4
5 SystemName [ABC: Logic synthesis and verification system.]
6
7 PackageName [Standard-cell library representation.]
8
9 Synopsis [Various library utilities.]
10
11 Author [Alan Mishchenko, Niklas Een]
12
13 Affiliation [UC Berkeley]
14
15 Date [Ver. 1.0. Started - August 24, 2012.]
16
17 Revision [$Id: sclLibUtil.c,v 1.0 2012/08/24 00:00:00 alanmi Exp $]
18
19 ***********************************************************************/
20
21 #include "sclLib.h"
22 #include "misc/st/st.h"
23 #include "map/mio/mio.h"
24 #include "bool/kit/kit.h"
25
26 ABC_NAMESPACE_IMPL_START
27
28
29 ////////////////////////////////////////////////////////////////////////
30 /// DECLARATIONS ///
31 ////////////////////////////////////////////////////////////////////////
32
33 ////////////////////////////////////////////////////////////////////////
34 /// FUNCTION DEFINITIONS ///
35 ////////////////////////////////////////////////////////////////////////
36
37 /**Function*************************************************************
38
39 Synopsis [Reading library from file.]
40
41 Description []
42
43 SideEffects []
44
45 SeeAlso []
46
47 ***********************************************************************/
Abc_SclHashString(char * pName,int TableSize)48 static unsigned Abc_SclHashString( char * pName, int TableSize )
49 {
50 static int s_Primes[10] = { 1291, 1699, 2357, 4177, 5147, 5647, 6343, 7103, 7873, 8147 };
51 unsigned i, Key = 0;
52 for ( i = 0; pName[i] != '\0'; i++ )
53 Key += s_Primes[i%10]*pName[i]*pName[i];
54 return Key % TableSize;
55 }
Abc_SclHashLookup(SC_Lib * p,char * pName)56 int * Abc_SclHashLookup( SC_Lib * p, char * pName )
57 {
58 int i;
59 for ( i = Abc_SclHashString(pName, p->nBins); i < p->nBins; i = (i + 1) % p->nBins )
60 if ( p->pBins[i] == -1 || !strcmp(pName, SC_LibCell(p, p->pBins[i])->pName) )
61 return p->pBins + i;
62 assert( 0 );
63 return NULL;
64 }
Abc_SclHashCells(SC_Lib * p)65 void Abc_SclHashCells( SC_Lib * p )
66 {
67 SC_Cell * pCell;
68 int i, * pPlace;
69 assert( p->nBins == 0 );
70 p->nBins = Abc_PrimeCudd( 5 * SC_LibCellNum(p) );
71 p->pBins = ABC_FALLOC( int, p->nBins );
72 SC_LibForEachCell( p, pCell, i )
73 {
74 pPlace = Abc_SclHashLookup( p, pCell->pName );
75 assert( *pPlace == -1 );
76 *pPlace = i;
77 }
78 }
Abc_SclCellFind(SC_Lib * p,char * pName)79 int Abc_SclCellFind( SC_Lib * p, char * pName )
80 {
81 int *pPlace = Abc_SclHashLookup( p, pName );
82 return pPlace ? *pPlace : -1;
83 }
Abc_SclClassCellNum(SC_Cell * pClass)84 int Abc_SclClassCellNum( SC_Cell * pClass )
85 {
86 SC_Cell * pCell;
87 int i, Count = 0;
88 SC_RingForEachCell( pClass, pCell, i )
89 if ( !pCell->fSkip )
90 Count++;
91 return Count;
92 }
Abc_SclLibClassNum(SC_Lib * pLib)93 int Abc_SclLibClassNum( SC_Lib * pLib )
94 {
95 SC_Cell * pRepr;
96 int i, Count = 0;
97 SC_LibForEachCellClass( pLib, pRepr, i )
98 Count++;
99 return Count;
100 }
101
102 /**Function*************************************************************
103
104 Synopsis [Change cell names and pin names.]
105
106 Description []
107
108 SideEffects []
109
110 SeeAlso []
111
112 ***********************************************************************/
Abc_SclIsChar(char c)113 static inline int Abc_SclIsChar( char c )
114 {
115 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
116 }
Abc_SclIsName(char c)117 static inline int Abc_SclIsName( char c )
118 {
119 return Abc_SclIsChar(c) || (c >= '0' && c <= '9');
120 }
Abc_SclFindLimit(char * pName)121 static inline char * Abc_SclFindLimit( char * pName )
122 {
123 assert( Abc_SclIsChar(*pName) );
124 while ( Abc_SclIsName(*pName) )
125 pName++;
126 return pName;
127 }
Abc_SclAreEqual(char * pBase,char * pName,char * pLimit)128 static inline int Abc_SclAreEqual( char * pBase, char * pName, char * pLimit )
129 {
130 return !strncmp( pBase, pName, pLimit - pName );
131 }
Abc_SclShortFormula(SC_Cell * pCell,char * pForm,char * pBuffer)132 void Abc_SclShortFormula( SC_Cell * pCell, char * pForm, char * pBuffer )
133 {
134 SC_Pin * pPin; int i;
135 char * pTemp, * pLimit;
136 for ( pTemp = pForm; *pTemp; )
137 {
138 if ( !Abc_SclIsChar(*pTemp) )
139 {
140 *pBuffer++ = *pTemp++;
141 continue;
142 }
143 pLimit = Abc_SclFindLimit( pTemp );
144 SC_CellForEachPinIn( pCell, pPin, i )
145 if ( Abc_SclAreEqual( pPin->pName, pTemp, pLimit ) )
146 {
147 *pBuffer++ = 'a' + i;
148 break;
149 }
150 assert( i < pCell->n_inputs );
151 pTemp = pLimit;
152 }
153 *pBuffer++ = 0;
154 }
Abc_SclTimingUpdate(SC_Cell * pCell,SC_Timing * p,char * Buffer)155 static inline void Abc_SclTimingUpdate( SC_Cell * pCell, SC_Timing * p, char * Buffer )
156 {
157 SC_Pin * pPin; int i;
158 SC_CellForEachPinIn( pCell, pPin, i )
159 if ( p->related_pin && !strcmp(p->related_pin, pPin->pName) )
160 {
161 ABC_FREE( p->related_pin );
162 sprintf( Buffer, "%c", 'a'+i );
163 p->related_pin = Abc_UtilStrsav( Buffer );
164 }
165 }
Abc_SclTimingsUpdate(SC_Cell * pCell,SC_Timings * p,char * Buffer)166 static inline void Abc_SclTimingsUpdate( SC_Cell * pCell, SC_Timings * p, char * Buffer )
167 {
168 SC_Timing * pTemp; int i;
169 Vec_PtrForEachEntry( SC_Timing *, &p->vTimings, pTemp, i )
170 Abc_SclTimingUpdate( pCell, pTemp, Buffer );
171 }
Abc_SclPinUpdate(SC_Cell * pCell,SC_Pin * p,char * Buffer)172 static inline void Abc_SclPinUpdate( SC_Cell * pCell, SC_Pin * p, char * Buffer )
173 {
174 // update pin names in the timing
175 SC_Timings * pTemp; int i;
176 SC_PinForEachRTiming( p, pTemp, i )
177 {
178 SC_Pin * pPin; int k;
179 Abc_SclTimingsUpdate( pCell, pTemp, Buffer );
180 SC_CellForEachPinIn( pCell, pPin, k )
181 if ( pTemp->pName && !strcmp(pTemp->pName, pPin->pName) )
182 {
183 ABC_FREE( pTemp->pName );
184 sprintf( Buffer, "%c", 'a'+k );
185 pTemp->pName = Abc_UtilStrsav( Buffer );
186 }
187 }
188 // update formula
189 Abc_SclShortFormula( pCell, p->func_text, Buffer );
190 ABC_FREE( p->func_text );
191 p->func_text = Abc_UtilStrsav( Buffer );
192 }
Abc_SclShortNames(SC_Lib * p)193 void Abc_SclShortNames( SC_Lib * p )
194 {
195 char Buffer[10000];
196 SC_Cell * pClass, * pCell; SC_Pin * pPin;
197 int i, k, n, nClasses = Abc_SclLibClassNum(p);
198 int nDigits = Abc_Base10Log( nClasses );
199 // itereate through classes
200 SC_LibForEachCellClass( p, pClass, i )
201 {
202 int nDigits2 = Abc_Base10Log( Abc_SclClassCellNum(pClass) );
203 SC_RingForEachCell( pClass, pCell, k )
204 {
205 ABC_FREE( pCell->pName );
206 sprintf( Buffer, "g%0*d_%0*d", nDigits, i, nDigits2, k );
207 pCell->pName = Abc_UtilStrsav( Buffer );
208 // formula
209 SC_CellForEachPinOut( pCell, pPin, n )
210 Abc_SclPinUpdate( pCell, pPin, Buffer );
211 // pin names
212 SC_CellForEachPinIn( pCell, pPin, n )
213 {
214 ABC_FREE( pPin->pName );
215 sprintf( Buffer, "%c", 'a'+n );
216 pPin->pName = Abc_UtilStrsav( Buffer );
217 }
218 SC_CellForEachPinOut( pCell, pPin, n )
219 {
220 ABC_FREE( pPin->pName );
221 sprintf( Buffer, "%c", 'z'-n+pCell->n_inputs );
222 pPin->pName = Abc_UtilStrsav( Buffer );
223 }
224 }
225 }
226 p->nBins = 0;
227 ABC_FREE( p->pBins );
228 Abc_SclHashCells( p );
229 // update library name
230 printf( "Renaming library \"%s\" into \"%s%d\".\n", p->pName, "lib", SC_LibCellNum(p) );
231 ABC_FREE( p->pName );
232 sprintf( Buffer, "lib%d", SC_LibCellNum(p) );
233 p->pName = Abc_UtilStrsav( Buffer );
234 }
235 /**Function*************************************************************
236
237 Synopsis [Links equal gates into rings while sorting them by area.]
238
239 Description []
240
241 SideEffects []
242
243 SeeAlso []
244
245 ***********************************************************************/
Abc_SclCompareCells(SC_Cell ** pp1,SC_Cell ** pp2)246 static int Abc_SclCompareCells( SC_Cell ** pp1, SC_Cell ** pp2 )
247 {
248 if ( (*pp1)->n_inputs < (*pp2)->n_inputs )
249 return -1;
250 if ( (*pp1)->n_inputs > (*pp2)->n_inputs )
251 return 1;
252 // if ( (*pp1)->area < (*pp2)->area )
253 // return -1;
254 // if ( (*pp1)->area > (*pp2)->area )
255 // return 1;
256 if ( SC_CellPinCapAve(*pp1) < SC_CellPinCapAve(*pp2) )
257 return -1;
258 if ( SC_CellPinCapAve(*pp1) > SC_CellPinCapAve(*pp2) )
259 return 1;
260 return strcmp( (*pp1)->pName, (*pp2)->pName );
261 }
Abc_SclLinkCells(SC_Lib * p)262 void Abc_SclLinkCells( SC_Lib * p )
263 {
264 Vec_Ptr_t * vList;
265 SC_Cell * pCell, * pRepr = NULL;
266 int i, k;
267 assert( Vec_PtrSize(&p->vCellClasses) == 0 );
268 SC_LibForEachCell( p, pCell, i )
269 {
270 // find gate with the same function
271 SC_LibForEachCellClass( p, pRepr, k )
272 if ( pCell->n_inputs == pRepr->n_inputs &&
273 pCell->n_outputs == pRepr->n_outputs &&
274 Vec_WrdEqual(SC_CellFunc(pCell), SC_CellFunc(pRepr)) )
275 break;
276 if ( k == Vec_PtrSize(&p->vCellClasses) )
277 {
278 Vec_PtrPush( &p->vCellClasses, pCell );
279 pCell->pNext = pCell->pPrev = pCell;
280 continue;
281 }
282 // add it to the list before the cell
283 pRepr->pPrev->pNext = pCell; pCell->pNext = pRepr;
284 pCell->pPrev = pRepr->pPrev; pRepr->pPrev = pCell;
285 }
286 // sort cells by size then by name
287 qsort( (void *)Vec_PtrArray(&p->vCellClasses), Vec_PtrSize(&p->vCellClasses), sizeof(void *), (int(*)(const void *,const void *))Abc_SclCompareCells );
288 // sort cell lists
289 vList = Vec_PtrAlloc( 100 );
290 SC_LibForEachCellClass( p, pRepr, k )
291 {
292 Vec_PtrClear( vList );
293 SC_RingForEachCell( pRepr, pCell, i )
294 Vec_PtrPush( vList, pCell );
295 qsort( (void *)Vec_PtrArray(vList), (size_t)Vec_PtrSize(vList), sizeof(void *), (int(*)(const void *,const void *))Abc_SclCompareCells );
296 // create new representative
297 pRepr = (SC_Cell *)Vec_PtrEntry( vList, 0 );
298 pRepr->pNext = pRepr->pPrev = pRepr;
299 pRepr->pRepr = pRepr;
300 pRepr->pAve = (SC_Cell *)Vec_PtrEntry( vList, Vec_PtrSize(vList)/2 );
301 pRepr->Order = 0;
302 pRepr->nGates = Vec_PtrSize(vList);
303 // relink cells
304 Vec_PtrForEachEntryStart( SC_Cell *, vList, pCell, i, 1 )
305 {
306 pRepr->pPrev->pNext = pCell; pCell->pNext = pRepr;
307 pCell->pPrev = pRepr->pPrev; pRepr->pPrev = pCell;
308 pCell->pRepr = pRepr;
309 pCell->pAve = (SC_Cell *)Vec_PtrEntry( vList, Vec_PtrSize(vList)/2 );
310 pCell->Order = i;
311 pCell->nGates = Vec_PtrSize(vList);
312 }
313 // update list
314 Vec_PtrWriteEntry( &p->vCellClasses, k, pRepr );
315 }
316 Vec_PtrFree( vList );
317 }
318
319 /**Function*************************************************************
320
321 Synopsis [Returns the largest inverter.]
322
323 Description []
324
325 SideEffects []
326
327 SeeAlso []
328
329 ***********************************************************************/
Abc_SclFindInvertor(SC_Lib * p,int fFindBuff)330 SC_Cell * Abc_SclFindInvertor( SC_Lib * p, int fFindBuff )
331 {
332 SC_Cell * pCell = NULL;
333 word Truth = fFindBuff ? ABC_CONST(0xAAAAAAAAAAAAAAAA) : ABC_CONST(0x5555555555555555);
334 int k;
335 SC_LibForEachCellClass( p, pCell, k )
336 if ( pCell->n_inputs == 1 && Vec_WrdEntry(&SC_CellPin(pCell, 1)->vFunc, 0) == Truth )
337 break;
338 // take representative
339 return pCell ? pCell->pRepr : NULL;
340 }
Abc_SclFindSmallestGate(SC_Cell * p,float CinMin)341 SC_Cell * Abc_SclFindSmallestGate( SC_Cell * p, float CinMin )
342 {
343 SC_Cell * pRes = NULL;
344 int i;
345 SC_RingForEachCell( p->pRepr, pRes, i )
346 if ( SC_CellPinCapAve(pRes) > CinMin )
347 return pRes;
348 // take the largest gate
349 return p->pRepr->pPrev;
350 }
351
352 /**Function*************************************************************
353
354 Synopsis [Returns the wireload model for the given area.]
355
356 Description []
357
358 SideEffects []
359
360 SeeAlso []
361
362 ***********************************************************************/
Abc_SclFetchWireLoadModel(SC_Lib * p,char * pWLoadUsed)363 SC_WireLoad * Abc_SclFetchWireLoadModel( SC_Lib * p, char * pWLoadUsed )
364 {
365 SC_WireLoad * pWL = NULL;
366 int i;
367 // Get the actual table and reformat it for 'wire_cap' output:
368 assert( pWLoadUsed != NULL );
369 SC_LibForEachWireLoad( p, pWL, i )
370 if ( !strcmp(pWL->pName, pWLoadUsed) )
371 break;
372 if ( i == Vec_PtrSize(&p->vWireLoads) )
373 {
374 Abc_Print( -1, "Cannot find wire load model \"%s\".\n", pWLoadUsed );
375 exit(1);
376 }
377 // printf( "Using wireload model \"%s\".\n", pWL->pName );
378 return pWL;
379 }
Abc_SclFindWireLoadModel(SC_Lib * p,float Area)380 SC_WireLoad * Abc_SclFindWireLoadModel( SC_Lib * p, float Area )
381 {
382 char * pWLoadUsed = NULL;
383 int i;
384 if ( p->default_wire_load_sel && strlen(p->default_wire_load_sel) )
385 {
386 SC_WireLoadSel * pWLS = NULL;
387 SC_LibForEachWireLoadSel( p, pWLS, i )
388 if ( !strcmp(pWLS->pName, p->default_wire_load_sel) )
389 break;
390 if ( i == Vec_PtrSize(&p->vWireLoadSels) )
391 {
392 Abc_Print( -1, "Cannot find wire load selection model \"%s\".\n", p->default_wire_load_sel );
393 exit(1);
394 }
395 for ( i = 0; i < Vec_FltSize(&pWLS->vAreaFrom); i++)
396 if ( Area >= Vec_FltEntry(&pWLS->vAreaFrom, i) && Area < Vec_FltEntry(&pWLS->vAreaTo, i) )
397 {
398 pWLoadUsed = (char *)Vec_PtrEntry(&pWLS->vWireLoadModel, i);
399 break;
400 }
401 if ( i == Vec_FltSize(&pWLS->vAreaFrom) )
402 pWLoadUsed = (char *)Vec_PtrEntryLast(&pWLS->vWireLoadModel);
403 }
404 else if ( p->default_wire_load && strlen(p->default_wire_load) )
405 pWLoadUsed = p->default_wire_load;
406 else
407 {
408 // Abc_Print( 0, "No wire model given.\n" );
409 return NULL;
410 }
411 return Abc_SclFetchWireLoadModel( p, pWLoadUsed );
412 }
413
414 /**Function*************************************************************
415
416 Synopsis [Returns 1 if the library has delay info.]
417
418 Description []
419
420 SideEffects []
421
422 SeeAlso []
423
424 ***********************************************************************/
Abc_SclHasDelayInfo(void * pScl)425 int Abc_SclHasDelayInfo( void * pScl )
426 {
427 SC_Lib * p = (SC_Lib *)pScl;
428 SC_Cell * pCell;
429 SC_Timing * pTime;
430 pCell = Abc_SclFindInvertor(p, 0);
431 if ( pCell == NULL )
432 return 0;
433 pTime = Scl_CellPinTime( pCell, 0 );
434 if ( pTime == NULL )
435 return 0;
436 return 1;
437 }
438
439 /**Function*************************************************************
440
441 Synopsis [Returns "average" slew.]
442
443 Description []
444
445 SideEffects []
446
447 SeeAlso []
448
449 ***********************************************************************/
Abc_SclComputeAverageSlew(SC_Lib * p)450 float Abc_SclComputeAverageSlew( SC_Lib * p )
451 {
452 SC_Cell * pCell;
453 SC_Timing * pTime;
454 Vec_Flt_t * vIndex;
455 pCell = Abc_SclFindInvertor(p, 0);
456 if ( pCell == NULL )
457 return 0;
458 pTime = Scl_CellPinTime( pCell, 0 );
459 if ( pTime == NULL )
460 return 0;
461 vIndex = &pTime->pCellRise.vIndex0; // slew
462 return Vec_FltEntry( vIndex, Vec_FltSize(vIndex)/3 );
463 }
464
465 /**Function*************************************************************
466
467 Synopsis [Compute delay parameters of pin/cell/class.]
468
469 Description []
470
471 SideEffects []
472
473 SeeAlso []
474
475 ***********************************************************************/
Abc_SclComputeParametersPin(SC_Lib * p,SC_Cell * pCell,int iPin,float Slew,float * pLD,float * pPD)476 int Abc_SclComputeParametersPin( SC_Lib * p, SC_Cell * pCell, int iPin, float Slew, float * pLD, float * pPD )
477 {
478 SC_Pair Load0, Load1, Load2;
479 SC_Pair ArrIn = { 0.0, 0.0 };
480 SC_Pair SlewIn = { Slew, Slew };
481 SC_Pair ArrOut0 = { 0.0, 0.0 };
482 SC_Pair ArrOut1 = { 0.0, 0.0 };
483 SC_Pair ArrOut2 = { 0.0, 0.0 };
484 SC_Pair SlewOut = { 0.0, 0.0 };
485 SC_Timing * pTime = Scl_CellPinTime( pCell, iPin );
486 Vec_Flt_t * vIndex = pTime ? &pTime->pCellRise.vIndex1 : NULL; // capacitance
487 if ( vIndex == NULL )
488 return 0;
489 // handle constant table
490 if ( Vec_FltSize(vIndex) == 1 )
491 {
492 *pLD = 0;
493 *pPD = Vec_FltEntry( (Vec_Flt_t *)Vec_PtrEntry(&pTime->pCellRise.vData, 0), 0 );
494 return 1;
495 }
496 // get load points
497 Load0.rise = Load0.fall = 0.0;
498 Load1.rise = Load1.fall = Vec_FltEntry( vIndex, 0 );
499 Load2.rise = Load2.fall = Vec_FltEntry( vIndex, Vec_FltSize(vIndex) - 2 );
500 // compute delay
501 Scl_LibPinArrival( pTime, &ArrIn, &SlewIn, &Load0, &ArrOut0, &SlewOut );
502 Scl_LibPinArrival( pTime, &ArrIn, &SlewIn, &Load1, &ArrOut1, &SlewOut );
503 Scl_LibPinArrival( pTime, &ArrIn, &SlewIn, &Load2, &ArrOut2, &SlewOut );
504 ArrOut0.rise = 0.5 * ArrOut0.rise + 0.5 * ArrOut0.fall;
505 ArrOut1.rise = 0.5 * ArrOut1.rise + 0.5 * ArrOut1.fall;
506 ArrOut2.rise = 0.5 * ArrOut2.rise + 0.5 * ArrOut2.fall;
507 // get tangent
508 *pLD = (ArrOut2.rise - ArrOut1.rise) / ((Load2.rise - Load1.rise) / SC_CellPinCap(pCell, iPin));
509 // get constant
510 *pPD = ArrOut0.rise;
511 return 1;
512 }
Abc_SclComputeParametersCell(SC_Lib * p,SC_Cell * pCell,float Slew,float * pLD,float * pPD)513 int Abc_SclComputeParametersCell( SC_Lib * p, SC_Cell * pCell, float Slew, float * pLD, float * pPD )
514 {
515 SC_Pin * pPin;
516 float LD, PD, ld, pd;
517 int i;
518 LD = PD = ld = pd = 0;
519 SC_CellForEachPinIn( pCell, pPin, i )
520 {
521 if ( !Abc_SclComputeParametersPin( p, pCell, i, Slew, &ld, &pd ) )
522 return 0;
523 LD += ld; PD += pd;
524 }
525 *pLD = LD / Abc_MaxInt(1, pCell->n_inputs);
526 *pPD = PD / Abc_MaxInt(1, pCell->n_inputs);
527 return 1;
528 }
Abc_SclComputeParametersClass(SC_Lib * p,SC_Cell * pRepr,float Slew,float * pLD,float * pPD)529 void Abc_SclComputeParametersClass( SC_Lib * p, SC_Cell * pRepr, float Slew, float * pLD, float * pPD )
530 {
531 SC_Cell * pCell;
532 float LD, PD, ld, pd;
533 int i, Count = 0;
534 LD = PD = ld = pd = 0;
535 SC_RingForEachCell( pRepr, pCell, i )
536 {
537 Abc_SclComputeParametersCell( p, pCell, Slew, &ld, &pd );
538 LD += ld; PD += pd;
539 Count++;
540 }
541 *pLD = LD / Abc_MaxInt(1, Count);
542 *pPD = PD / Abc_MaxInt(1, Count);
543 }
Abc_SclComputeParametersClassPin(SC_Lib * p,SC_Cell * pRepr,int iPin,float Slew,float * pLD,float * pPD)544 void Abc_SclComputeParametersClassPin( SC_Lib * p, SC_Cell * pRepr, int iPin, float Slew, float * pLD, float * pPD )
545 {
546 SC_Cell * pCell;
547 float LD, PD, ld, pd;
548 int i, Count = 0;
549 LD = PD = ld = pd = 0;
550 SC_RingForEachCell( pRepr, pCell, i )
551 {
552 Abc_SclComputeParametersPin( p, pCell, iPin, Slew, &ld, &pd );
553 LD += ld; PD += pd;
554 Count++;
555 }
556 *pLD = LD / Abc_MaxInt(1, Count);
557 *pPD = PD / Abc_MaxInt(1, Count);
558 }
Abc_SclComputeDelayCellPin(SC_Lib * p,SC_Cell * pCell,int iPin,float Slew,float Gain)559 float Abc_SclComputeDelayCellPin( SC_Lib * p, SC_Cell * pCell, int iPin, float Slew, float Gain )
560 {
561 float LD = 0, PD = 0;
562 Abc_SclComputeParametersPin( p, pCell, iPin, Slew, &LD, &PD );
563 return 0.01 * LD * Gain + PD;
564 }
Abc_SclComputeDelayClassPin(SC_Lib * p,SC_Cell * pRepr,int iPin,float Slew,float Gain)565 float Abc_SclComputeDelayClassPin( SC_Lib * p, SC_Cell * pRepr, int iPin, float Slew, float Gain )
566 {
567 SC_Cell * pCell;
568 float Delay = 0;
569 int i, Count = 0;
570 SC_RingForEachCell( pRepr, pCell, i )
571 {
572 if ( pCell->fSkip )
573 continue;
574 // if ( pRepr == pCell ) // skip the first gate
575 // continue;
576 Delay += Abc_SclComputeDelayCellPin( p, pCell, iPin, Slew, Gain );
577 Count++;
578 }
579 return Delay / Abc_MaxInt(1, Count);
580 }
Abc_SclComputeAreaClass(SC_Cell * pRepr)581 float Abc_SclComputeAreaClass( SC_Cell * pRepr )
582 {
583 SC_Cell * pCell;
584 float Area = 0;
585 int i, Count = 0;
586 SC_RingForEachCell( pRepr, pCell, i )
587 {
588 if ( pCell->fSkip )
589 continue;
590 Area += pCell->area;
591 Count++;
592 }
593 return Area / Abc_MaxInt(1, Count);
594 }
595
596 /**Function*************************************************************
597
598 Synopsis [Print cells]
599
600 Description []
601
602 SideEffects []
603
604 SeeAlso []
605
606 ***********************************************************************/
Abc_SclMarkSkippedCells(SC_Lib * p)607 void Abc_SclMarkSkippedCells( SC_Lib * p )
608 {
609 char FileName[1000];
610 char Buffer[1000], * pName;
611 SC_Cell * pCell;
612 FILE * pFile;
613 int CellId, nSkipped = 0;
614 sprintf( FileName, "%s.skip", p->pName );
615 pFile = fopen( FileName, "rb" );
616 if ( pFile == NULL )
617 return;
618 while ( fgets( Buffer, 999, pFile ) != NULL )
619 {
620 pName = strtok( Buffer, "\r\n\t " );
621 if ( pName == NULL )
622 continue;
623 CellId = Abc_SclCellFind( p, pName );
624 if ( CellId == -1 )
625 {
626 printf( "Cannot find cell \"%s\" in the library \"%s\".\n", pName, p->pName );
627 continue;
628 }
629 pCell = SC_LibCell( p, CellId );
630 pCell->fSkip = 1;
631 nSkipped++;
632 }
633 fclose( pFile );
634 printf( "Marked %d cells for skipping in the library \"%s\".\n", nSkipped, p->pName );
635 }
Abc_SclPrintCells(SC_Lib * p,float SlewInit,float Gain,int fInvOnly,int fShort)636 void Abc_SclPrintCells( SC_Lib * p, float SlewInit, float Gain, int fInvOnly, int fShort )
637 {
638 SC_Cell * pCell, * pRepr;
639 SC_Pin * pPin;
640 int i, j, k, nLength = 0;
641 float Slew = (SlewInit == 0) ? Abc_SclComputeAverageSlew(p) : SlewInit;
642 float LD = 0, PD = 0;
643 assert( Vec_PtrSize(&p->vCellClasses) > 0 );
644 printf( "Library \"%s\" ", p->pName );
645 printf( "has %d cells in %d classes. ",
646 Vec_PtrSize(&p->vCells), Vec_PtrSize(&p->vCellClasses) );
647 if ( !fShort )
648 printf( "Delay estimate is based on slew %.2f ps and gain %.2f.", Slew, Gain );
649 printf( "\n" );
650 Abc_SclMarkSkippedCells( p );
651 // find the longest name
652 SC_LibForEachCellClass( p, pRepr, k )
653 SC_RingForEachCell( pRepr, pCell, i )
654 nLength = Abc_MaxInt( nLength, strlen(pRepr->pName) );
655 // print cells
656 SC_LibForEachCellClass( p, pRepr, k )
657 {
658 if ( fInvOnly && pRepr->n_inputs != 1 )
659 continue;
660 SC_CellForEachPinOut( pRepr, pPin, i )
661 {
662 if ( i == pRepr->n_inputs )
663 {
664 printf( "Class%4d : ", k );
665 printf( "Cells =%3d ", Abc_SclClassCellNum(pRepr) );
666 printf( "Ins =%2d ", pRepr->n_inputs );
667 printf( "Outs =%2d ", pRepr->n_outputs );
668 }
669 else
670 printf( " " );
671 if ( pPin->func_text )
672 printf( "%-30s", pPin->func_text );
673 printf( " " );
674 Kit_DsdPrintFromTruth( (unsigned *)Vec_WrdArray(&pPin->vFunc), pRepr->n_inputs );
675 printf( "\n" );
676 if ( fShort )
677 continue;
678 SC_RingForEachCell( pRepr, pCell, j )
679 {
680 printf( " %3d ", j+1 );
681 printf( "%s", pCell->fSkip ? "s" : " " );
682 printf( " : " );
683 printf( "%-*s ", nLength, pCell->pName );
684 printf( "%2d ", pCell->drive_strength );
685 printf( "A =%8.2f ", pCell->area );
686 printf( "L =%8.2f ", pCell->leakage );
687 if ( pCell->n_outputs == 1 )
688 {
689 if ( Abc_SclComputeParametersCell( p, pCell, Slew, &LD, &PD ) )
690 {
691 printf( "D =%6.1f ps ", 0.01 * Gain * LD + PD );
692 printf( "LD =%6.1f ps ", LD );
693 printf( "PD =%6.1f ps ", PD );
694 printf( "C =%5.1f ff ", SC_CellPinCapAve(pCell) );
695 printf( "Cm =%5.0f ff ", SC_CellPin(pCell, pCell->n_inputs)->max_out_cap );
696 printf( "Sm =%5.1f ps ", SC_CellPin(pCell, pCell->n_inputs)->max_out_slew );
697 }
698 }
699 printf( "\n" );
700 }
701 break;
702 }
703 }
704 }
705
706 /**Function*************************************************************
707
708 Synopsis []
709
710 Description []
711
712 SideEffects []
713
714 SeeAlso []
715
716 ***********************************************************************/
Abc_SclConvertLeakageIntoArea(SC_Lib * p,float A,float B)717 void Abc_SclConvertLeakageIntoArea( SC_Lib * p, float A, float B )
718 {
719 SC_Cell * pCell; int i;
720 SC_LibForEachCell( p, pCell, i )
721 pCell->area = A * pCell->area + B * pCell->leakage;
722 }
723
724
725 /**Function*************************************************************
726
727 Synopsis [Print cells]
728
729 Description []
730
731 SideEffects []
732
733 SeeAlso []
734
735 ***********************************************************************/
Abc_SclLibNormalizeSurface(SC_Surface * p,float Time,float Load)736 void Abc_SclLibNormalizeSurface( SC_Surface * p, float Time, float Load )
737 {
738 Vec_Flt_t * vArray;
739 int i, k; float Entry;
740 Vec_FltForEachEntry( &p->vIndex0, Entry, i ) // slew
741 Vec_FltWriteEntry( &p->vIndex0, i, Time * Entry );
742 Vec_FltForEachEntry( &p->vIndex1, Entry, i ) // load
743 Vec_FltWriteEntry( &p->vIndex1, i, Load * Entry );
744 Vec_PtrForEachEntry( Vec_Flt_t *, &p->vData, vArray, k )
745 Vec_FltForEachEntry( vArray, Entry, i ) // delay/slew
746 Vec_FltWriteEntry( vArray, i, Time * Entry );
747 }
Abc_SclLibNormalize(SC_Lib * p)748 void Abc_SclLibNormalize( SC_Lib * p )
749 {
750 SC_WireLoad * pWL;
751 SC_Cell * pCell;
752 SC_Pin * pPin;
753 SC_Timings * pTimings;
754 SC_Timing * pTiming;
755 int i, k, m, n;
756 float Time = 1.0 * pow(10.0, 12 - p->unit_time);
757 float Load = p->unit_cap_fst * pow(10.0, 15 - p->unit_cap_snd);
758 if ( Time == 1 && Load == 1 )
759 return;
760 p->unit_time = 12;
761 p->unit_cap_fst = 1;
762 p->unit_cap_snd = 15;
763 p->default_max_out_slew *= Time;
764 SC_LibForEachWireLoad( p, pWL, i )
765 pWL->cap *= Load;
766 SC_LibForEachCell( p, pCell, i )
767 SC_CellForEachPin( pCell, pPin, k )
768 {
769 pPin->cap *= Load;
770 pPin->rise_cap *= Load;
771 pPin->fall_cap *= Load;
772 pPin->max_out_cap *= Load;
773 pPin->max_out_slew *= Time;
774 SC_PinForEachRTiming( pPin, pTimings, m )
775 Vec_PtrForEachEntry( SC_Timing *, &pTimings->vTimings, pTiming, n )
776 {
777 Abc_SclLibNormalizeSurface( &pTiming->pCellRise, Time, Load );
778 Abc_SclLibNormalizeSurface( &pTiming->pCellFall, Time, Load );
779 Abc_SclLibNormalizeSurface( &pTiming->pRiseTrans, Time, Load );
780 Abc_SclLibNormalizeSurface( &pTiming->pFallTrans, Time, Load );
781 }
782 }
783 }
784
785 /**Function*************************************************************
786
787 Synopsis [Derives simple GENLIB library.]
788
789 Description []
790
791 SideEffects []
792
793 SeeAlso []
794
795 ***********************************************************************/
Abc_SclProduceGenlibStrSimple(SC_Lib * p)796 Vec_Str_t * Abc_SclProduceGenlibStrSimple( SC_Lib * p )
797 {
798 char Buffer[200];
799 Vec_Str_t * vStr;
800 SC_Cell * pCell;
801 SC_Pin * pPin, * pPinOut;
802 int i, j, k, Count = 2;
803 // mark skipped cells
804 // Abc_SclMarkSkippedCells( p );
805 vStr = Vec_StrAlloc( 1000 );
806 Vec_StrPrintStr( vStr, "GATE _const0_ 0.00 z=CONST0;\n" );
807 Vec_StrPrintStr( vStr, "GATE _const1_ 0.00 z=CONST1;\n" );
808 SC_LibForEachCell( p, pCell, i )
809 {
810 if ( pCell->n_inputs == 0 )
811 continue;
812 assert( strlen(pCell->pName) < 200 );
813 SC_CellForEachPinOut( pCell, pPinOut, j )
814 {
815 Vec_StrPrintStr( vStr, "GATE " );
816 sprintf( Buffer, "%-16s", pCell->pName );
817 Vec_StrPrintStr( vStr, Buffer );
818 Vec_StrPrintStr( vStr, " " );
819 sprintf( Buffer, "%7.2f", pCell->area );
820 Vec_StrPrintStr( vStr, Buffer );
821 Vec_StrPrintStr( vStr, " " );
822 Vec_StrPrintStr( vStr, pPinOut->pName );
823 Vec_StrPrintStr( vStr, "=" );
824 Vec_StrPrintStr( vStr, pPinOut->func_text ? pPinOut->func_text : "?" );
825 Vec_StrPrintStr( vStr, ";\n" );
826 SC_CellForEachPinIn( pCell, pPin, k )
827 {
828 Vec_StrPrintStr( vStr, " PIN " );
829 sprintf( Buffer, "%-4s", pPin->pName );
830 Vec_StrPrintStr( vStr, Buffer );
831 sprintf( Buffer, " UNKNOWN 1 999 1.00 0.00 1.00 0.00\n" );
832 Vec_StrPrintStr( vStr, Buffer );
833 }
834 Count++;
835 }
836 }
837 Vec_StrPrintStr( vStr, "\n.end\n" );
838 Vec_StrPush( vStr, '\0' );
839 // printf( "GENLIB library with %d gates is produced:\n", Count );
840 // printf( "%s", Vec_StrArray(vStr) );
841 return vStr;
842 }
Abc_SclDeriveGenlibSimple(void * pScl)843 Mio_Library_t * Abc_SclDeriveGenlibSimple( void * pScl )
844 {
845 SC_Lib * p = (SC_Lib *)pScl;
846 Vec_Str_t * vStr = Abc_SclProduceGenlibStrSimple( p );
847 Mio_Library_t * pLib = Mio_LibraryRead( p->pFileName, Vec_StrArray(vStr), NULL, 0 );
848 Vec_StrFree( vStr );
849 if ( pLib )
850 printf( "Derived GENLIB library \"%s\" with %d gates.\n", p->pName, SC_LibCellNum(p) );
851 else
852 printf( "Reading library has filed.\n" );
853 return pLib;
854 }
855
856
857 /**Function*************************************************************
858
859 Synopsis [Derive GENLIB library.]
860
861 Description []
862
863 SideEffects []
864
865 SeeAlso []
866
867 ***********************************************************************/
Abc_SclProduceGenlibStr(SC_Lib * p,float Slew,float Gain,int nGatesMin,int * pnCellCount)868 Vec_Str_t * Abc_SclProduceGenlibStr( SC_Lib * p, float Slew, float Gain, int nGatesMin, int * pnCellCount )
869 {
870 char Buffer[200];
871 Vec_Str_t * vStr;
872 SC_Cell * pRepr;
873 SC_Pin * pPin;
874 int i, k, Count = 2, nClassMax = 0;
875 // find the largest number of cells in a class
876 SC_LibForEachCellClass( p, pRepr, i )
877 if ( pRepr->n_outputs == 1 )
878 nClassMax = Abc_MaxInt( nClassMax, Abc_SclClassCellNum(pRepr) );
879 // update the number
880 if ( nGatesMin && nGatesMin >= nClassMax )
881 nGatesMin = 0;
882 // mark skipped cells
883 Abc_SclMarkSkippedCells( p );
884 vStr = Vec_StrAlloc( 1000 );
885 Vec_StrPrintStr( vStr, "GATE _const0_ 0.00 z=CONST0;\n" );
886 Vec_StrPrintStr( vStr, "GATE _const1_ 0.00 z=CONST1;\n" );
887 SC_LibForEachCellClass( p, pRepr, i )
888 {
889 if ( pRepr->n_inputs == 0 )
890 continue;
891 if ( pRepr->n_outputs > 1 )
892 continue;
893 if ( nGatesMin && pRepr->n_inputs > 2 && Abc_SclClassCellNum(pRepr) < nGatesMin )
894 continue;
895 assert( strlen(pRepr->pName) < 200 );
896 Vec_StrPrintStr( vStr, "GATE " );
897 sprintf( Buffer, "%-16s", pRepr->pName );
898 Vec_StrPrintStr( vStr, Buffer );
899 Vec_StrPrintStr( vStr, " " );
900 // sprintf( Buffer, "%7.2f", Abc_SclComputeAreaClass(pRepr) );
901 sprintf( Buffer, "%7.2f", pRepr->area );
902 Vec_StrPrintStr( vStr, Buffer );
903 Vec_StrPrintStr( vStr, " " );
904 Vec_StrPrintStr( vStr, SC_CellPinName(pRepr, pRepr->n_inputs) );
905 Vec_StrPrintStr( vStr, "=" );
906 Vec_StrPrintStr( vStr, SC_CellPinOutFunc(pRepr, 0) ? SC_CellPinOutFunc(pRepr, 0) : "?" );
907 Vec_StrPrintStr( vStr, ";\n" );
908 SC_CellForEachPinIn( pRepr, pPin, k )
909 {
910 float Delay = Abc_SclComputeDelayClassPin( p, pRepr, k, Slew, Gain );
911 assert( Delay > 0 );
912 Vec_StrPrintStr( vStr, " PIN " );
913 sprintf( Buffer, "%-4s", pPin->pName );
914 Vec_StrPrintStr( vStr, Buffer );
915 sprintf( Buffer, " UNKNOWN 1 999 %7.2f 0.00 %7.2f 0.00\n", Delay, Delay );
916 Vec_StrPrintStr( vStr, Buffer );
917 }
918 Count++;
919 }
920 Vec_StrPrintStr( vStr, "\n.end\n" );
921 Vec_StrPush( vStr, '\0' );
922 // printf( "GENLIB library with %d gates is produced:\n", Count );
923 // printf( "%s", Vec_StrArray(vStr) );
924 if ( pnCellCount )
925 *pnCellCount = Count;
926 return vStr;
927 }
Abc_SclProduceGenlibStrProfile(SC_Lib * p,Mio_Library_t * pLib,float Slew,float Gain,int nGatesMin,int * pnCellCount)928 Vec_Str_t * Abc_SclProduceGenlibStrProfile( SC_Lib * p, Mio_Library_t * pLib, float Slew, float Gain, int nGatesMin, int * pnCellCount )
929 {
930 char Buffer[200];
931 Vec_Str_t * vStr;
932 SC_Cell * pRepr;
933 SC_Pin * pPin;
934 int i, k, Count = 2, nClassMax = 0;
935 // find the largest number of cells in a class
936 SC_LibForEachCellClass( p, pRepr, i )
937 if ( pRepr->n_outputs == 1 )
938 nClassMax = Abc_MaxInt( nClassMax, Abc_SclClassCellNum(pRepr) );
939 // update the number
940 if ( nGatesMin && nGatesMin >= nClassMax )
941 nGatesMin = 0;
942 // mark skipped cells
943 Abc_SclMarkSkippedCells( p );
944 vStr = Vec_StrAlloc( 1000 );
945 Vec_StrPrintStr( vStr, "GATE _const0_ 0.00 z=CONST0;\n" );
946 Vec_StrPrintStr( vStr, "GATE _const1_ 0.00 z=CONST1;\n" );
947 SC_LibForEachCell( p, pRepr, i )
948 {
949 if ( pRepr->n_inputs == 0 )
950 continue;
951 if ( pRepr->n_outputs > 1 )
952 continue;
953 if ( nGatesMin && pRepr->n_inputs > 2 && Abc_SclClassCellNum(pRepr) < nGatesMin )
954 continue;
955 // check if the gate is in the profile
956 if ( pRepr->n_inputs > 1 )
957 {
958 Mio_Gate_t * pGate = Mio_LibraryReadGateByName( pLib, pRepr->pName, NULL );
959 if ( pGate == NULL || Mio_GateReadProfile(pGate) == 0 )
960 continue;
961 }
962 // process gate
963 assert( strlen(pRepr->pName) < 200 );
964 Vec_StrPrintStr( vStr, "GATE " );
965 sprintf( Buffer, "%-16s", pRepr->pName );
966 Vec_StrPrintStr( vStr, Buffer );
967 Vec_StrPrintStr( vStr, " " );
968 // sprintf( Buffer, "%7.2f", Abc_SclComputeAreaClass(pRepr) );
969 sprintf( Buffer, "%7.2f", pRepr->area );
970 Vec_StrPrintStr( vStr, Buffer );
971 Vec_StrPrintStr( vStr, " " );
972 Vec_StrPrintStr( vStr, SC_CellPinName(pRepr, pRepr->n_inputs) );
973 Vec_StrPrintStr( vStr, "=" );
974 Vec_StrPrintStr( vStr, SC_CellPinOutFunc(pRepr, 0) ? SC_CellPinOutFunc(pRepr, 0) : "?" );
975 Vec_StrPrintStr( vStr, ";\n" );
976 SC_CellForEachPinIn( pRepr, pPin, k )
977 {
978 float Delay = Abc_SclComputeDelayClassPin( p, pRepr, k, Slew, Gain );
979 assert( Delay > 0 );
980 Vec_StrPrintStr( vStr, " PIN " );
981 sprintf( Buffer, "%-4s", pPin->pName );
982 Vec_StrPrintStr( vStr, Buffer );
983 sprintf( Buffer, " UNKNOWN 1 999 %7.2f 0.00 %7.2f 0.00\n", Delay, Delay );
984 Vec_StrPrintStr( vStr, Buffer );
985 }
986 Count++;
987 }
988 Vec_StrPrintStr( vStr, "\n.end\n" );
989 Vec_StrPush( vStr, '\0' );
990 // printf( "GENLIB library with %d gates is produced:\n", Count );
991 // printf( "%s", Vec_StrArray(vStr) );
992 if ( pnCellCount )
993 *pnCellCount = Count;
994 return vStr;
995 }
Abc_SclDumpGenlib(char * pFileName,SC_Lib * p,float SlewInit,float Gain,int nGatesMin)996 void Abc_SclDumpGenlib( char * pFileName, SC_Lib * p, float SlewInit, float Gain, int nGatesMin )
997 {
998 int nCellCount = 0;
999 char FileName[1000];
1000 float Slew = (SlewInit == 0) ? Abc_SclComputeAverageSlew(p) : SlewInit;
1001 Vec_Str_t * vStr;
1002 FILE * pFile;
1003 if ( pFileName == NULL )
1004 sprintf( FileName, "%s_s%03d_g%03d_m%d.genlib", p->pName, (int)Slew, (int)Gain, nGatesMin );
1005 else
1006 sprintf( FileName, "%s", pFileName );
1007 pFile = fopen( FileName, "wb" );
1008 if ( pFile == NULL )
1009 {
1010 printf( "Cannot open file \"%s\" for writing.\n", FileName );
1011 return;
1012 }
1013 vStr = Abc_SclProduceGenlibStr( p, Slew, Gain, nGatesMin, &nCellCount );
1014 fprintf( pFile, "%s", Vec_StrArray(vStr) );
1015 Vec_StrFree( vStr );
1016 fclose( pFile );
1017 printf( "Written GENLIB library with %d gates into file \"%s\".\n", nCellCount, FileName );
1018 }
Abc_SclDeriveGenlib(void * pScl,void * pMio,float SlewInit,float Gain,int nGatesMin,int fVerbose)1019 Mio_Library_t * Abc_SclDeriveGenlib( void * pScl, void * pMio, float SlewInit, float Gain, int nGatesMin, int fVerbose )
1020 {
1021 int nCellCount = 0;
1022 SC_Lib * p = (SC_Lib *)pScl;
1023 float Slew = (SlewInit == 0) ? Abc_SclComputeAverageSlew(p) : SlewInit;
1024 Vec_Str_t * vStr;
1025 Mio_Library_t * pLib;
1026 if ( pMio == NULL )
1027 vStr = Abc_SclProduceGenlibStr( p, Slew, Gain, nGatesMin, &nCellCount );
1028 else
1029 vStr = Abc_SclProduceGenlibStrProfile( p, (Mio_Library_t *)pMio, Slew, Gain, nGatesMin, &nCellCount );
1030 pLib = Mio_LibraryRead( p->pFileName, Vec_StrArray(vStr), NULL, 0 );
1031 Vec_StrFree( vStr );
1032 if ( !pLib )
1033 printf( "Reading library has filed.\n" );
1034 else if ( fVerbose )
1035 printf( "Derived GENLIB library \"%s\" with %d gates using slew %.2f ps and gain %.2f.\n", p->pName, nCellCount, Slew, Gain );
1036 return pLib;
1037 }
1038
1039 /**Function*************************************************************
1040
1041 Synopsis [Install library.]
1042
1043 Description []
1044
1045 SideEffects []
1046
1047 SeeAlso []
1048
1049 ***********************************************************************/
Abc_SclInstallGenlib(void * pScl,float SlewInit,float Gain,int nGatesMin)1050 void Abc_SclInstallGenlib( void * pScl, float SlewInit, float Gain, int nGatesMin )
1051 {
1052 SC_Lib * p = (SC_Lib *)pScl;
1053 Vec_Str_t * vStr, * vStr2;
1054 float Slew = (SlewInit == 0) ? Abc_SclComputeAverageSlew(p) : SlewInit;
1055 int RetValue, nGateCount = SC_LibCellNum(p);
1056 if ( Gain == 0 )
1057 vStr = Abc_SclProduceGenlibStrSimple(p);
1058 else
1059 vStr = Abc_SclProduceGenlibStr( p, Slew, Gain, nGatesMin, &nGateCount );
1060 vStr2 = Vec_StrDup( vStr );
1061 RetValue = Mio_UpdateGenlib2( vStr, vStr2, p->pName, 0 );
1062 Vec_StrFree( vStr );
1063 Vec_StrFree( vStr2 );
1064 if ( !RetValue )
1065 printf( "Reading library has filed.\n" );
1066 else if ( Gain != 0 )
1067 printf( "Derived GENLIB library \"%s\" with %d gates using slew %.2f ps and gain %.2f.\n", p->pName, nGateCount, Slew, Gain );
1068 // else
1069 // printf( "Derived unit-delay GENLIB library \"%s\" with %d gates.\n", p->pName, nGateCount );
1070 }
1071
1072 ////////////////////////////////////////////////////////////////////////
1073 /// END OF FILE ///
1074 ////////////////////////////////////////////////////////////////////////
1075
1076
1077 ABC_NAMESPACE_IMPL_END
1078
1079