1 /*--------------------------------------------------------------*/
2 /* vesta.c --- */
3 /* */
4 /* This file reads two files: (1) A verilog netlist file */
5 /* of a circuit (structural verilog, that is, gate-level */
6 /* information only), and (2) a liberty format file */
7 /* containing timing information for the standard cell */
8 /* macros instantiated in the verilog netlist. In */
9 /* addition, it may take an optional third file containing */
10 /* information about the resistance and capacitance of the */
11 /* wiring (see below). */
12 /* */
13 /* Options are supplied as command-line arguments: */
14 /* */
15 /* -d <delay_file> Wiring delays (see below) */
16 /* -p <value> Clock period, in ps */
17 /* -l <value> Output load, in fF */
18 /* -v <level> set verbose mode */
19 /* -D <level> set debug mode */
20 /* -V report version number */
21 /* -n <number> number of paths to print */
22 /* -L Long format (print paths) */
23 /* -e exhaustive search */
24 /* -s <file> summary file or directory */
25 /* -c cleanup of net name syntax */
26 /* */
27 /* Currently the only output this tool generates is a */
28 /* list of paths with negative slack. If no paths have */
29 /* negative slack, then the 20 paths with the smallest */
30 /* positive slack are output, following a "success" */
31 /* message. If no clock period is supplied, then the */
32 /* clock period is set to equal the delay of the longest */
33 /* delay path, and the 20 paths with the smallest positive */
34 /* slack are output, following a statement indicated the */
35 /* computed minimum clock period. */
36 /* */
37 /* Debug level (developer diagnostics): */
38 /* Not cumulative. Each number does something unique. */
39 /* 1: Print delay file parsing information */
40 /* 2: Print liberty file parsing information */
41 /* */
42 /* Verbose level (user diagnostics): */
43 /* Cumulative. The higher the number, the more */
44 /* output is generated. */
45 /* 1: Report on total lines processed. */
46 /* 2: Report on each path processed. */
47 /* 3: Report on verilog source file */
48 /* 4: Report on liberty file */
49 /*--------------------------------------------------------------*/
50 /* (c) 2013-2019 Tim Edwards, Open Circuit Design */
51 /* Released under GPL as part of the qflow package */
52 /*--------------------------------------------------------------*/
53
54 /*--------------------------------------------------------------*/
55 /* Wiring delay file: */
56 /* For qflow, the wiring delay is generated by the tool */
57 /* "def2delays". The file format is as follows: */
58 /* */
59 /* <net_name> */
60 /* <output_terminal> <net_capacitance> */
61 /* <input_terminal_1> <delay_1> */
62 /* ... */
63 /* <input_terminal_N> <delay_N> */
64 /* */
65 /* -<net_capacitance> is in pF */
66 /* -Values <delay_i> are in ps */
67 /* -<input_terminal_N> line *must* be following by a blank */
68 /* line */
69 /*--------------------------------------------------------------*/
70
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <ctype.h>
74 #include <string.h>
75 #include <errno.h>
76 #include <stdarg.h>
77 #include <sys/types.h> // For mkdir()
78 #include <sys/stat.h> // For mkdir()
79 #include <math.h> // Temporary, for fabs()
80 #include "hash.h" // For net hash table
81 #include "readverilog.h"
82
83 #define LIB_LINE_MAX 65535
84
85 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
86 // Linux defines a comparison function prototype, the Mac doesn't. . .
87 typedef int (*__compar_fn_t)(const void *, const void *);
88 #endif
89
90 int fileCurrentLine;
91
92 // Analysis types --- note that maximum flop-to-flop delay
93 // requires calculating minimum clock skew time, and vice
94 // versa, so it is necessary that these have TRUE/FALSE
95 // values.
96
97 #define MINIMUM_TIME 0
98 #define MAXIMUM_TIME 1
99
100 #define INITVAL -1.0E50 /* Value to detect uninitialized delay */
101
102 // Multiple-use definition
103 #define UNKNOWN -1
104
105 // Sections of liberty file
106 #define INIT 0
107 #define LIBBLOCK 1
108 #define CELLDEF 2
109 #define PINDEF 3
110 #define FLOPDEF 4
111 #define LATCHDEF 5
112 #define TIMING 6
113
114 // Sections of verilog file
115 #define MODULE 0
116 #define IOINLINE 1
117 #define IOLIST 2
118 #define GATELIST 3
119 #define INSTANCE 4
120 #define INSTPIN 5
121 #define PINCONN 6
122
123 // Pin types (these are masks---e.g., a pin can be an INPUT and a CLOCK)
124 #define INPUT 0x01 // The default
125 #define OUTPUT 0x02
126 #define DFFCLK 0x04
127 #define DFFIN 0x08 // Flop input
128 #define DFFOUT 0x10 // Flop output
129 #define DFFSET 0x20 // Flop set (preset)
130 #define DFFRST 0x40 // Flop reset (clear)
131 #define LATCHIN 0x80 // Latch input
132 #define LATCHEN 0x100 // Latch enable
133 #define LATCHOUT 0x200 // Latch output
134
135 // Timing type (for tables)
136
137 #define TIMING_PROP_TRANS 0
138 #define TIMING_HOLD 1
139 #define TIMING_SETUP 2
140 #define TIMING_SET_RESET 3
141 #define TIMING_RECOVERY 4
142 #define TIMING_REMOVAL 5
143 #define TIMING_TRISTATE 6
144
145 // A few short-hand definitions
146 #define DFF_ALL_IN (DFFCLK | DFFIN | DFFSET | DFFRST)
147 #define LATCH_ALL_IN (LATCHIN | LATCHEN)
148
149 #define DFF_IN_NOT_CLK (DFFIN | DFFSET | DFFRST)
150 #define LATCH_IN_NOT_EN (LATCHIN)
151
152 #define REGISTER_IN (DFF_ALL_IN | LATCH_ALL_IN)
153 #define REG_IN_NOT_CLK (DFF_IN_NOT_CLK | LATCH_IN_NOT_EN)
154
155 #define IOMASK 0x03
156 #define DFFMASK 0x7c
157 #define LATCHMASK 0x180
158
159 // Pin sense
160 #define SENSE_UNKNOWN 0 // Sense unknown
161 #define SENSE_NONE 1 // Non-unate
162 #define SENSE_POSITIVE 2 // Positive-unate
163 #define SENSE_NEGATIVE 3 // Negative-unate
164
165 // Signal transition direction
166 #define EDGE_UNKNOWN 0
167 #define RISING 1
168 #define FALLING 2
169 #define EITHER 3
170
171 // Function translation
172 #define GROUPBEGIN 1
173 #define GROUPEND 2
174 #define SIGNAL 3
175 #define OPERATOR 4
176 #define XOPERATOR 5
177 #define SEPARATOR 6
178
179 // Net types
180 #define NET 0x00 // Ordinary net (default)
181 #define CLOCK 0x01 // Clock net (path start)
182 #define OUTTERM 0x02 // Module output
183 #define ASYNC 0x04 // Asynchronous set/reset
184 #define TERMINAL 0x08 // DFF input (path terminal)
185 #define LATCHTERM 0x10 // Latch input (dependent path terminal)
186 #define ENABLE 0x20 // Latch enable (path start)
187
188 // Cell types
189 #define GATE 0x00 // Combinatorial gate (default)
190 #define DFF 0x01 // Flip-flop (shared bit field)
191 #define CLK_SENSE_MASK 0x02 // Clock edge mask (0=positive, 1=negative)
192 #define RST_MASK 0x04 // Reset mask (0=no reset, 1=reset)
193 #define RST_SENSE_MASK 0x08 // Reset edge mask (0=positive, 1=negative)
194 #define SET_MASK 0x10 // Set mask (0=no set, 1=set)
195 #define SET_SENSE_MASK 0x20 // Set edge mask (0=positive, 1=negative)
196 #define LATCH 0x40 // Latch type
197 #define EN_SENSE_MASK 0x80 // Latch enable edge mask (0=positive, 1=negative)
198
199 // Some names for cell types based on masks
200
201 #define DFFCP 0x01 // Pos clock
202 #define DFFCN 0x03 // Neg clock
203 #define DFFCPRP 0x05 // Pos clock, Pos reset
204 #define DFFCNRP 0x07 // Neg clock, Pos reset
205 #define DFFCPRN 0x0d // Pos clock, Neg reset
206 #define DFFCNRN 0x0f // Neg clock, Neg reset
207 #define DFFCPSP 0x11 // Pos clock, Pos set
208 #define DFFCNSP 0x13 // Neg clock, Pos set
209 #define DFFCPRPSP 0x15 // Pos clock, Pos reset, Pos set
210 #define DFFCNRPSP 0x17 // Neg clock, Pos reset, Pos set
211 #define DFFCPRNSP 0x1d // Pos clock, Neg reset, Pos set
212 #define DFFCNRNSP 0x1f // Neg clock, Neg reset, Pos set
213 #define DFFCPSN 0x31 // Pos clock, Neg set
214 #define DFFCNSN 0x33 // Neg clock, Neg set
215 #define DFFCPRPSN 0x35 // Pos clock, Pos reset, Neg set
216 #define DFFCNRPSN 0x37 // Neg clock, Pos reset, Neg set
217 #define DFFCPRNSN 0x3d // Pos clock, Neg reset, Neg set
218 #define DFFCNRNSN 0x3f // Neg clock, Neg reset, Neg set
219
220 /*--------------------------------------------------------------*/
221 /* Liberty file database */
222 /*--------------------------------------------------------------*/
223
224 // Types of array
225
226 // Array type 1: Propagation time
227 #define OUTPUT_CAP 0
228 #define TRANSITION_TIME 1
229
230 // Array type 2: Setup, hold, recovery, removal times
231 #define RELATED_TIME 2
232 #define CONSTRAINED_TIME 3
233
234 typedef struct _lutable *lutableptr;
235
236 typedef struct _lutable {
237 char *name;
238 char invert; // 0 if times x caps, 1 if caps x times
239 int var1; // Type of array in index1
240 int var2; // Type of array in index2
241 int size1; // Number of entries in time array
242 int size2; // Number of entries in cap (or constrained timing) array
243 union {
244 double *times; // Time array (units ps)
245 double *rel; // Related pin transition time array (units ps)
246 } idx1;
247 union {
248 double *caps; // Cap array (units fF)
249 double *cons; // Constrained pin transition time array (units ps)
250 } idx2;
251 double *values; // Matrix of values (used locally, not for templates)
252 lutableptr next;
253 } lutable;
254
255 typedef struct _bustype *bustypeptr;
256 typedef struct _pin *pinptr;
257 typedef struct _cell *cellptr;
258
259 typedef struct _bustype {
260 char *name;
261 int from;
262 int to;
263 bustypeptr next;
264 } bus;
265
266 typedef struct _pin {
267 char *name;
268 short type;
269
270 double capr; // Capacitance for rising input
271 double capf; // Capacitance for falling input (optional)
272
273 short sense; // Sense (positive-unate, negative-unate, non-unate)
274 lutable *propdelr; // Reference table for rising output prop delay relative to driver
275 lutable *propdelf; // Reference table for falling output prop delay relative to driver
276 lutable *transr; // Reference table for transition rise time
277 lutable *transf; // Reference table for transition fall time
278
279 cellptr refcell; // Pointer back to parent cell
280
281 pinptr next;
282 } pin;
283
284 typedef struct _cell {
285 short type;
286 char *name;
287 char *function;
288 pin *pins; /* List of input pins with timing info */
289 double area;
290 double maxtrans; /* Maximum transition time */
291 double maxcap; /* Maximum allowable load */
292 cellptr next;
293 } cell;
294
295 /*--------------------------------------------------------------*/
296 /* Verilog netlist database */
297 /*--------------------------------------------------------------*/
298
299 typedef struct _net *netptr;
300 typedef struct _connect *connptr;
301 typedef struct _delaydata *ddataptr;
302
303 typedef struct _net {
304 char *name;
305 connptr driver;
306 short type;
307 int fanout;
308 connptr *receivers;
309 double loadr; /* Total load capacitance for rising input */
310 double loadf; /* Total load capacitance for falling input */
311 netptr next;
312 } net;
313
314 typedef struct _instance *instptr;
315
316 typedef struct _connect {
317 double metric; /* Delay metric at connection */
318 double icDelay; /* interconnect delay in ps */
319 instptr refinst;
320 pinptr refpin;
321 netptr refnet;
322 unsigned char visited; /* To check for common clock points */
323 ddataptr tag; /* Tag value for checking for loops and endpoints */
324 double *prvector; /* Prop delay rising (at load condition) vector */
325 double *pfvector; /* Prop delay falling (at load condition) vector */
326 double *trvector; /* Transition time rising (at load condition) vector */
327 double *tfvector; /* Transition time falling (at load condition) vector */
328 connptr next;
329 } connect;
330
331 typedef struct _instance {
332 char *name;
333 cellptr refcell;
334 connptr in_connects;
335 connptr out_connects;
336 instptr next;
337 } instance;
338
339 // Linked list of delays (backtrace to source)
340
341 typedef struct _btdata *btptr;
342
343 typedef struct _btdata {
344 double delay; /* Propagation delay to this point */
345 double trans; /* Transition time at this point */
346 short dir; /* Edge direction at this point */
347 connptr receiver; /* Receiver connection at end of path */
348 int refcnt; /* Reference counter for backtrace data */
349 btptr next; /* Path of propagation */
350 } btdata;
351
352 // Linked list of backtrace records
353
354 typedef struct _delaydata {
355 double delay; /* Total delay, including setup and clock skew */
356 double skew; /* Part of total delay attributed to clock skew */
357 double setup; /* Part of total delay attributed to setup (+) or hold (-) */
358 double trans; /* Transition time at destination, used to find setup */
359 btptr backtrace;
360 ddataptr next;
361 } delaydata;
362
363 // Linked list of connection pointers
364 // (Much like delaydata, but without all the timing information)
365
366 typedef struct _connlist *connlistptr;
367
368 typedef struct _connlist {
369 connptr connection;
370 connlistptr next;
371 } connlist;
372
373 /* Global variables */
374
375 unsigned char verbose; /* Level of user output generated */
376 unsigned char debug; /* Level of debug output generated */
377 unsigned char exhaustive; /* Exhaustive search mode */
378 unsigned char cleanup; /* Clean up net name syntax */
379
380 /*--------------------------------------------------------------*/
381 /* Grab a token from the input */
382 /* Return the token, or NULL if we have reached end-of-file. */
383 /*--------------------------------------------------------------*/
384
385 char *
advancetoken0(FILE * flib,char delimiter,char nocontline)386 advancetoken0(FILE *flib, char delimiter, char nocontline)
387 {
388 static char *token = NULL;
389 static char line[LIB_LINE_MAX];
390 static char *linepos = NULL;
391 static int token_max_length = LIB_LINE_MAX - 5;
392
393 char *lineptr = linepos;
394 char *lptr, *tptr;
395 char *result;
396 int commentblock, concat, nest;
397
398 if (token == NULL) token = (char *)malloc(LIB_LINE_MAX);
399
400 commentblock = 0;
401 concat = 0;
402 nest = 0;
403 while (1) { /* Keep processing until we get a token or hit EOF */
404
405 if (lineptr != NULL && *lineptr == '/' && *(lineptr + 1) == '*') {
406 commentblock = 1;
407 }
408
409 if (commentblock == 1) {
410 if ((lptr = strstr(lineptr, "*/")) != NULL) {
411 lineptr = lptr + 2;
412 commentblock = 0;
413 }
414 else lineptr = NULL;
415 }
416
417 // Sloppy liberty spec was supposed to have ';' terminating
418 // lines but it allows them to go missing. Fix this by adding
419 // semicolons to statements missing them.
420
421 if (lineptr && *lineptr == '\n' && delimiter == ';') *lineptr = ';';
422
423 if (lineptr == NULL || *lineptr == '\n' || *lineptr == '\0') {
424 result = fgets(line, LIB_LINE_MAX, flib);
425 fileCurrentLine++;
426 if (verbose > 0) {
427 if ((fileCurrentLine % 10000) == 0) {
428 fprintf(stdout, "Processed %d lines.\n", fileCurrentLine);
429 fflush(stdout);
430 }
431 }
432 if (result == NULL) return NULL;
433
434 /* Keep pulling stuff in if the line ends with a continuation character */
435 lptr = line;
436 while (*lptr != '\n' && *lptr != '\0') {
437 if ((*lptr == '\\') && (nocontline == 0)) {
438 // To be considered a line continuation marker, there must be
439 // only whitespace or newline between the backslash and the
440 // end of the string.
441 char *eptr = lptr + 1;
442 while (isblank(*eptr)) eptr++;
443 if (*eptr == '\n') {
444 result = fgets(lptr, LIB_LINE_MAX - (lptr - line), flib);
445 fileCurrentLine++;
446 if (result == NULL) break;
447 }
448 else
449 lptr++;
450 }
451 else
452 lptr++;
453 }
454 if (result == NULL) return NULL;
455 lineptr = line;
456 }
457
458 if (commentblock == 1) continue;
459
460 while (isblank(*lineptr)) lineptr++;
461 if (concat == 0)
462 tptr = token;
463
464 // Find the next token and return just the token. Update linepos
465 // to the position just beyond the token. All delimiters like
466 // parentheses, quotes, etc., are returned as single tokens
467
468 // If delimiter is declared, then we stop when we reach the
469 // delimiter character, and return all the text preceding it
470 // as the token. If delimiter is 0, then we look for standard
471 // delimiters, and separate them out and return them as tokens
472 // if found.
473
474 while (1) {
475 if (*lineptr == '\n' || *lineptr == '\0')
476 break;
477 if (*lineptr == '/' && *(lineptr + 1) == '*')
478 break;
479 if (delimiter != 0 && *lineptr == delimiter) {
480 if (nest > 0)
481 nest--;
482 else
483 break;
484 }
485
486 // Watch for overruns, and allocate more memory
487 // for the token if needed.
488
489 if ((tptr - token) > token_max_length) {
490 char *tsave = token;
491 token_max_length <<= 1;
492 token = (char *)realloc(token, token_max_length);
493 tptr += (token - tsave);
494 }
495
496 // Watch for nested delimiters!
497 if (delimiter == '}' && *lineptr == '{') nest++;
498 if (delimiter == ')' && *lineptr == '(') nest++;
499
500 if (delimiter == 0)
501 if (*lineptr == ' ' || *lineptr == '\t')
502 break;
503
504 if (delimiter == 0) {
505 if (*lineptr == '(' || *lineptr == ')') {
506 if (tptr == token) *tptr++ = *lineptr++;
507 break;
508 }
509 if (*lineptr == '{' || *lineptr == '}') {
510 if (tptr == token) *tptr++ = *lineptr++;
511 break;
512 }
513 if (*lineptr == '\"' || *lineptr == ':' || *lineptr == ';') {
514 if (tptr == token) *tptr++ = *lineptr++;
515 break;
516 }
517 }
518
519 *tptr++ = *lineptr++;
520 }
521 *tptr = '\0';
522 if ((delimiter != 0) && (*lineptr != delimiter))
523 concat = 1;
524 else if ((delimiter != 0) && (*lineptr == delimiter))
525 break;
526 else if (tptr > token)
527 break;
528 }
529 if (delimiter != 0) lineptr++;
530
531 while (isblank(*lineptr)) lineptr++;
532 linepos = lineptr;
533
534 // Final: Remove trailing whitespace
535 tptr = token + strlen(token) - 1;
536 while ((tptr > token) && isblank(*tptr)) {
537 *tptr = '\0';
538 tptr--;
539 }
540 return token;
541 }
542
543 /*--------------------------------------------------------------*/
544 /* Wrapper for advancetoken0(): Default nocontline = 0 */
545 /*--------------------------------------------------------------*/
546
547 char *
advancetoken(FILE * flib,char delimiter)548 advancetoken(FILE *flib, char delimiter)
549 {
550 return advancetoken0(flib, delimiter, 0);
551 }
552
553 /*--------------------------------------------------------------*/
554 /* Wrapper for advancetoken0(): nocontline = 1 for delay file */
555 /*--------------------------------------------------------------*/
556
557 char *
advancetokennocont(FILE * flib,char delimiter)558 advancetokennocont(FILE *flib, char delimiter)
559 {
560 return advancetoken0(flib, delimiter, 1);
561 }
562
563 /*--------------------------------------------------------------*/
564 /* Wrapper around strdup() to remove any quotes from around the */
565 /* text being copied. */
566 /*--------------------------------------------------------------*/
567
568 char *
tokendup(char * token)569 tokendup(char *token)
570 {
571 char *ss, *sf, *result;
572
573 ss = token;
574 sf = NULL;
575 while (*ss == '\"') ss++;
576 if (ss != token) {
577 sf = ss + 1;
578 while (*sf && (*sf != '\"')) sf++;
579 if (*sf == '\"')
580 *sf = '\0';
581 else
582 sf = NULL;
583 }
584
585 result = strdup(ss);
586
587 if (sf != NULL) *sf = '\"';
588
589 return result;
590 }
591
592
593 /*--------------------------------------------------------------*/
594 /* Parse a pin name. Check if the cell has a pin of that name, */
595 /* and if not, add the pin to the cell, giving it default */
596 /* values. The pin name may contain quotes, parentheses, or */
597 /* negations ("!" or "'"); these should be ignored. */
598 /*--------------------------------------------------------------*/
599
parse_pin(cellptr newcell,char * token)600 pinptr parse_pin(cellptr newcell, char *token)
601 {
602 pinptr newpin, lastpin;
603 char *pinname, *sptr;
604
605 // Advance to first legal pin name character
606
607 pinname = token;
608 while (isblank(*pinname) || (*pinname == '\'') || (*pinname == '\"') ||
609 (*pinname == '!') || (*pinname == '(') || (*pinname == ')'))
610 pinname++;
611
612 sptr = pinname;
613 while (*sptr != '\0') {
614 if (isblank(*sptr) || (*sptr == '\'') || (*sptr == '\"') ||
615 (*sptr == '!') || (*sptr == '(') || (*sptr == ')')) {
616 *sptr = '\0';
617 break;
618 }
619 sptr++;
620 }
621
622 // Check if pin was already defined
623
624 lastpin = NULL;
625 newpin = newcell->pins;
626 while (newpin) {
627 lastpin = newpin;
628 if (!strcmp(newpin->name, pinname))
629 return newpin;
630 newpin = newpin->next;
631 }
632
633 // Pin was not defined, so create a new one and add it to the cell
634 // at the end of the cell's pin list.
635
636 newpin = (pin *)malloc(sizeof(pin));
637 newpin->name = tokendup(pinname);
638 newpin->next = NULL;
639
640 if (lastpin != NULL)
641 lastpin->next = newpin;
642 else
643 newcell->pins = newpin;
644
645 newpin->type = INPUT; // The default; modified later, if not an input
646 newpin->capr = 0.0;
647 newpin->capf = 0.0;
648 newpin->sense = SENSE_NONE;
649 newpin->propdelr = NULL;
650 newpin->propdelf = NULL;
651 newpin->transr = NULL;
652 newpin->transf = NULL;
653 newpin->refcell = newcell; // Create link back to cell
654 return newpin;
655 }
656
657 /*--------------------------------------------------------------*/
658 /* Create a new net record */
659 /*--------------------------------------------------------------*/
660
create_net(netptr * netlist)661 netptr create_net(netptr *netlist) {
662
663 netptr newnet;
664
665 newnet = (netptr)malloc(sizeof(net));
666 newnet->name = NULL;
667 newnet->next = *netlist;
668 *netlist = newnet;
669 newnet->driver = NULL;
670 newnet->fanout = 0;
671 newnet->receivers = NULL;
672 newnet->loadr = 0.0;
673 newnet->loadf = 0.0;
674 newnet->type = NET;
675
676 return newnet;
677 }
678
679 /*----------------------------------------------------------------------*/
680 /* Interpolate or extrapolate a vector from a time vs. capacitance */
681 /* lookup table. */
682 /*----------------------------------------------------------------------*/
683
table_collapse(lutableptr tableptr,double load)684 double *table_collapse(lutableptr tableptr, double load)
685 {
686 double *vector;
687 double cfrac, vlow, vhigh;
688 int i, j;
689
690 vector = (double *)malloc(tableptr->size1 * sizeof(double));
691
692 // If the table is 1-dimensional, then just return a copy of the table.
693 if (tableptr->size2 <= 1) {
694 for (i = 0; i < tableptr->size1; i++) {
695 *(vector + i) = *(tableptr->values + i);
696 }
697 return vector;
698 }
699
700 // Find cap load index entries bounding "load", or the two nearest
701 // entries, if extrapolating
702
703 if (load < tableptr->idx2.caps[0])
704 j = 1;
705 else if (load >= tableptr->idx2.caps[tableptr->size2 - 1])
706 j = tableptr->size2 - 1;
707 else {
708 for (j = 0; j < tableptr->size2; j++)
709 if (tableptr->idx2.caps[j] > load)
710 break;
711 }
712
713 cfrac = (load - tableptr->idx2.caps[j - 1]) /
714 (tableptr->idx2.caps[j] - tableptr->idx2.caps[j - 1]);
715
716 for (i = 0; i < tableptr->size1; i++) {
717
718 // Interpolate value at cap load for each transition value
719
720 vlow = *(tableptr->values + i * tableptr->size2 + (j - 1));
721 vhigh = *(tableptr->values + i * tableptr->size2 + j);
722 *(vector + i) = vlow + (vhigh - vlow) * cfrac;
723 }
724 return vector;
725 }
726
727 /*----------------------------------------------------------------------*/
728 /* Interpolate/extrapolate a delay or transition value from a vector of */
729 /* values at a known output load. The original full 2D table contains */
730 /* the transition time index values. */
731 /*----------------------------------------------------------------------*/
732
vector_get_value(lutableptr tableptr,double * vector,double trans)733 double vector_get_value(lutableptr tableptr, double *vector, double trans)
734 {
735 int i;
736 double tfrac, vlow, vhigh, value;
737
738 // Find time index entries bounding "trans", or the two nearest
739 // entries, if extrapolating
740
741 if (trans < tableptr->idx1.times[0])
742 i = 1;
743 else if (trans >= tableptr->idx1.times[tableptr->size1 - 1])
744 i = tableptr->size1 - 1;
745 else {
746 for (i = 0; i < tableptr->size1; i++)
747 if (tableptr->idx1.times[i] > trans)
748 break;
749 }
750
751 // Compute transition time as a fraction of the nearest table indexes
752 // for transition times
753
754 tfrac = (trans - tableptr->idx1.times[i - 1]) /
755 (tableptr->idx1.times[i] - tableptr->idx1.times[i - 1]);
756
757 // Interpolate value
758 vlow = *(vector + (i - 1));
759 vhigh = *(vector + i);
760 value = vlow + (vhigh - vlow) * tfrac;
761 return value;
762 }
763
764 /*----------------------------------------------------------------------*/
765 /* Interpolate or extrapolate a value from a related time vs. */
766 /* constrained time lookup table. */
767 /*----------------------------------------------------------------------*/
768
binomial_get_value(lutableptr tableptr,double rtrans,double ctrans)769 double binomial_get_value(lutableptr tableptr, double rtrans, double ctrans)
770 {
771 int i, j;
772 double rfrac, cfrac, vlow, vhigh, valuel, valueh, value;
773
774 /* Tables have been arranged such that idx1 is related time, */
775 /* idx2 is constrained time */
776
777 // Find time index entries bounding "rtrans", or the two nearest
778 // entries, if extrapolating
779
780 if (rtrans < tableptr->idx1.rel[0])
781 i = 1;
782 else if (rtrans >= tableptr->idx1.rel[tableptr->size1 - 1])
783 i = tableptr->size1 - 1;
784 else {
785 for (i = 0; i < tableptr->size1; i++)
786 if (tableptr->idx1.rel[i] > rtrans)
787 break;
788 }
789
790 // Compute transition time as a fraction of the nearest table indexes
791 // for transition times
792
793 rfrac = (rtrans - tableptr->idx1.rel[i - 1]) /
794 (tableptr->idx1.rel[i] - tableptr->idx1.rel[i - 1]);
795
796 // 1-dimensional computation, if this table is 1-dimensional
797
798 if (tableptr->size2 == 0) {
799 vlow = *(tableptr->values + (i - 1));
800 vhigh = *(tableptr->values + i);
801 value = vlow + (vhigh - vlow) * rfrac;
802 return value;
803 }
804
805 // Find cons index entries bounding "ctrans", or the two nearest
806 // entries, if extrapolating
807
808 if (ctrans < tableptr->idx2.cons[0])
809 j = 1;
810 else if (ctrans >= tableptr->idx2.cons[tableptr->size2 - 1])
811 j = tableptr->size2 - 1;
812 else {
813 for (j = 0; j < tableptr->size2; j++)
814 if (tableptr->idx2.cons[j] > ctrans)
815 break;
816 }
817
818 // Compute cons transition as a fraction of the nearest table indexes for cons
819
820 cfrac = (ctrans - tableptr->idx2.cons[j - 1]) /
821 (tableptr->idx2.cons[j] - tableptr->idx2.cons[j - 1]);
822
823 // Interpolate value at cons lower bound
824 vlow = *(tableptr->values + (i - 1) * tableptr->size1 + (j - 1));
825 vhigh = *(tableptr->values + i * tableptr->size1 + (j - 1));
826 valuel = vlow + (vhigh - vlow) * rfrac;
827
828 // Interpolate value at cons upper bound
829 vlow = *(tableptr->values + (i - 1) * tableptr->size1 + j);
830 vhigh = *(tableptr->values + i * tableptr->size1 + j);
831 valueh = vlow + (vhigh - vlow) * rfrac;
832
833 // Final interpolation (binomial interpolation)
834 value = valuel + (valueh - valuel) * cfrac;
835 return value;
836 }
837
838 /*----------------------------------------------------------------------*/
839 /* Determine how the sense of a signal changes going from a gate's */
840 /* input to its output. If the gate's input pin is positive unate */
841 /* relative to the gate output, then the signal sense remains the same. */
842 /* If it is negative unate, then the signal sense inverts. If it is */
843 /* non-unate, then the signal sense becomes non-unate, and we calculate */
844 /* timing for both edges from that point forward, always accepting the */
845 /* maximum time. */
846 /*----------------------------------------------------------------------*/
847
calc_dir(pinptr testpin,short dir)848 short calc_dir(pinptr testpin, short dir)
849 {
850 short outdir;
851
852 outdir = UNKNOWN;
853 if (testpin == NULL) return dir;
854
855 switch(dir) {
856 case RISING:
857 if (testpin->sense == SENSE_POSITIVE)
858 outdir = RISING; /* rising input, rising output */
859 else if (testpin->sense == SENSE_NEGATIVE)
860 outdir = FALLING; /* rising input, falling output */
861 else
862 outdir = EITHER; /* output can be rising or falling */
863 break;
864 case FALLING:
865 if (testpin->sense == SENSE_POSITIVE)
866 outdir = FALLING; /* falling input, falling output */
867 else if (testpin->sense == SENSE_NEGATIVE)
868 outdir = RISING; /* falling input, rising output */
869 else
870 outdir = EITHER; /* output can be rising or falling */
871 break;
872 case EITHER:
873 outdir = EITHER; /* output can be rising or falling */
874 break;
875 }
876 return outdir;
877 }
878
879 /*----------------------------------------------------------------------*/
880 /* Calculate the propagation delay from "testpin" to the output */
881 /* of the gate to which "testpin" is an input. */
882 /* */
883 /* "sense" is a pointer to the sense at the input. SENSE_POSITIVE */
884 /* indicates a rising edge at the pin, SENSE_NEGATIVE indicates a */
885 /* falling edge at the pin. "sense" is updated to indicate if the */
886 /* output transition is rising, falling, or unknown (SENSE_NONE). */
887 /* */
888 /* "loadnet" is a pointer to the net connected to the cell instance's */
889 /* output pin. Load values will be taken from this net, depending on */
890 /* the sense of the output. */
891 /* */
892 /* "testpin" is the pin receiving the input signal, and the pin record */
893 /* containing the relevant timing tables. */
894 /*----------------------------------------------------------------------*/
895
calc_prop_delay(double trans,connptr testconn,short sense,char minmax)896 double calc_prop_delay(double trans, connptr testconn, short sense, char minmax)
897 {
898 pinptr testpin;
899 double propdelayr, propdelayf;
900
901 propdelayr = 0.0;
902 propdelayf = 0.0;
903
904 testpin = testconn->refpin;
905 if (testpin == NULL) return 0.0;
906
907 if (sense != SENSE_NEGATIVE) {
908 if (testconn->prvector)
909 propdelayr = vector_get_value(testpin->propdelr, testconn->prvector, trans);
910 if (propdelayr < 0.0) propdelayr = 0.0;
911 if (sense == SENSE_POSITIVE) return propdelayr;
912 }
913
914 if (sense != SENSE_POSITIVE) {
915 if (testconn->pfvector)
916 propdelayf = vector_get_value(testpin->propdelf, testconn->pfvector, trans);
917 if (propdelayf < 0.0) propdelayf = 0.0;
918 if (sense == SENSE_NEGATIVE) return propdelayf;
919 }
920
921 if (minmax == MAXIMUM_TIME)
922 return (propdelayr > propdelayf) ? propdelayr : propdelayf;
923 else
924 return (propdelayr < propdelayf) ? propdelayr : propdelayf;
925 }
926
927 /*----------------------------------------------------------------------*/
928 /* Calculate the transition time from "testpin" to the output */
929 /* of the gate to which "testpin" is an input. This is equivalent to */
930 /* the propagation delay calculation routine above, apart from using */
931 /* the lookup tables for transition time instead of propagation delay. */
932 /*----------------------------------------------------------------------*/
933
calc_transition(double trans,connptr testconn,short sense,char minmax)934 double calc_transition(double trans, connptr testconn, short sense, char minmax)
935 {
936 pinptr testpin;
937 double transr, transf;
938
939 testpin = testconn->refpin;
940 if (testpin == NULL) return 0.0;
941
942 transr = 0.0;
943 transf = 0.0;
944
945 if (sense != SENSE_NEGATIVE) {
946 if (testconn->trvector)
947 transr = vector_get_value(testpin->transr, testconn->trvector, trans);
948 if (transr < 0.0) transr = 0.0;
949 if (sense == SENSE_POSITIVE) return transr;
950 }
951
952 if (sense != SENSE_POSITIVE) {
953 if (testconn->tfvector)
954 transf = vector_get_value(testpin->transf, testconn->tfvector, trans);
955 if (transf < 0.0) transf = 0.0;
956 if (sense == SENSE_NEGATIVE) return transf;
957 }
958
959 if (minmax == MAXIMUM_TIME)
960 return (transr > transf) ? transr : transf;
961 else
962 return (transr < transf) ? transr : transf;
963 }
964
965 /*----------------------------------------------------------------------*/
966 /* Calculate the hold time for a flop input "testpin" relative to the */
967 /* flop clock, where "trans" is the transition time of the signal at */
968 /* "testpin", and "clktrans" is the transition time of the clock */
969 /* signal at the clock pin. "sense" is the sense of the input signal */
970 /* at "testpin". */
971 /*----------------------------------------------------------------------*/
972
calc_hold_time(double trans,pinptr testpin,double clktrans,short sense,char minmax)973 double calc_hold_time(double trans, pinptr testpin, double clktrans, short sense,
974 char minmax)
975 {
976 double holdr, holdf;
977
978 if (testpin == NULL) return 0.0;
979
980 holdr = 0.0;
981 holdf = 0.0;
982
983 if (sense != SENSE_NEGATIVE) {
984 if (testpin->transr)
985 holdr = binomial_get_value(testpin->transr, trans, clktrans);
986 if (sense == SENSE_POSITIVE) return holdr;
987 }
988
989 if (sense != SENSE_POSITIVE) {
990 if (testpin->transf)
991 holdf = binomial_get_value(testpin->transf, trans, clktrans);
992 if (sense == SENSE_NEGATIVE) return holdf;
993 }
994
995 if (minmax == MAXIMUM_TIME)
996 return (holdr < holdf) ? holdr : holdf;
997 else
998 return (holdr > holdf) ? holdr : holdf;
999 }
1000
1001 /*----------------------------------------------------------------------*/
1002 /* Calculate the setup time for a flop input "testpin" relative to the */
1003 /* flop clock, where "trans" is the transition time of the signal at */
1004 /* "testpin", and "clktrans" is the transition time of the clock */
1005 /* signal at the clock pin. "sense" is the sense of the input signal */
1006 /* at "testpin". */
1007 /*----------------------------------------------------------------------*/
1008
calc_setup_time(double trans,pinptr testpin,double clktrans,short sense,char minmax)1009 double calc_setup_time(double trans, pinptr testpin, double clktrans, short sense,
1010 char minmax)
1011 {
1012 double setupr, setupf;
1013
1014 if (testpin == NULL) return 0.0;
1015
1016 setupr = 0.0;
1017 setupf = 0.0;
1018
1019 if (sense != SENSE_NEGATIVE) {
1020 if (testpin->propdelr)
1021 setupr = binomial_get_value(testpin->propdelr, trans, clktrans);
1022 if (sense == SENSE_POSITIVE) return setupr;
1023 }
1024
1025 if (sense != SENSE_POSITIVE) {
1026 if (testpin->propdelf)
1027 setupf = binomial_get_value(testpin->propdelf, trans, clktrans);
1028 if (sense == SENSE_NEGATIVE) return setupf;
1029 }
1030
1031 if (minmax == MAXIMUM_TIME)
1032 return (setupr > setupf) ? setupr : setupf;
1033 else
1034 return (setupr < setupf) ? setupr : setupf;
1035 }
1036
1037 /*--------------------------------------------------------------*/
1038 /* Find the path from a clock back to all inputs or flop */
1039 /* outputs. This list will be used to find nodes that are */
1040 /* common to other clocks. */
1041 /* */
1042 /* For each pair of registers involved in a delay path */
1043 /* calculation, this routine is called once for both devices. */
1044 /* Set mode = 0 for the first device, and the connections are */
1045 /* marked when found. Set mode = 1 for the second device, and */
1046 /* the search stops when a marked connection is found---this is */
1047 /* the common clock net between the devices. If no common */
1048 /* clock is found, then return NULL---these endpoints are */
1049 /* asynchronously clocked. */
1050 /* */
1051 /* Modified 5/23/2019: Cascaded clocks should be traced */
1052 /* through a flop. i.e., if a clock is found to come from a */
1053 /* DFF output, then add the clock-to-Q delay and keep tracing */
1054 /* from the DFF clock. */
1055 /* */
1056 /* If mode == 2, return TRUE if the search ended on a */
1057 /* connection found in a mode 1 search. Otherwise, return */
1058 /* FALSE. */
1059 /*--------------------------------------------------------------*/
1060
1061 unsigned char
find_clock_source(connptr testlink,ddataptr * clocklist,btptr btrace,short dir,unsigned char mode)1062 find_clock_source(connptr testlink, ddataptr *clocklist, btptr btrace, short dir,
1063 unsigned char mode)
1064 {
1065 netptr clknet;
1066 connptr driver, iinput;
1067 instptr iupstream;
1068 btptr newclock;
1069 ddataptr newdataptr;
1070 short newdir;
1071 unsigned char result = 0;
1072
1073 /* Add this connection record to the backtrace */
1074
1075 newclock = (btptr)malloc(sizeof(btdata));
1076 newclock->delay = -1.0E50; /* Initialization constant */
1077 newclock->trans = 0.0;
1078 newclock->dir = dir;
1079 newclock->refcnt = 0;
1080 newclock->receiver = testlink;
1081 newclock->next = btrace;
1082 if (btrace) btrace->refcnt++;
1083
1084 /* On mode 2, stop when a node marked 1 is reached. */
1085 if ((mode == (unsigned char)2) && (testlink->visited == (unsigned char)1)) {
1086 result = (unsigned char)1;
1087 goto makehead;
1088 }
1089
1090 /* Mark connection as visited */
1091 testlink->visited = mode;
1092
1093 clknet = testlink->refnet;
1094 driver = clknet->driver;
1095 if (driver == NULL) goto makehead; /* Reached a module input */
1096 iupstream = driver->refinst;
1097
1098 if (iupstream == NULL) goto makehead; /* Not supposed to happen? */
1099
1100 /* If a flop or latch output is reached, add the clock-to-output delay */
1101 /* and continue tracing from the DFF clock or LATCH input. */
1102
1103 if (driver->refpin->type & DFFOUT) {
1104 for (iinput = driver->refinst->in_connects; iinput; iinput = iinput->next) {
1105 if (iinput->refpin->type & DFFCLK) {
1106 newdir = calc_dir(iinput->refpin, dir);
1107 result = find_clock_source(iinput, clocklist, newclock, newdir, mode);
1108 if (result == (unsigned char)1) return result;
1109 }
1110 }
1111 }
1112 else if (driver->refpin->type & LATCHOUT) {
1113 for (iinput = driver->refinst->in_connects; iinput; iinput = iinput->next) {
1114 if (iinput->refpin->type & LATCHIN) {
1115 newdir = calc_dir(iinput->refpin, dir);
1116 result = find_clock_source(iinput, clocklist, newclock, newdir, mode);
1117 if (result == (unsigned char)1) return result;
1118 }
1119 }
1120 }
1121 else {
1122 for (iinput = iupstream->in_connects; iinput; iinput = iinput->next) {
1123 newdir = calc_dir(iinput->refpin, dir);
1124 result = find_clock_source(iinput, clocklist, newclock, newdir, mode);
1125 if (result == (unsigned char)1) return result;
1126 }
1127 }
1128 return (unsigned char)0;
1129
1130 makehead:
1131 /* Reached the head of a clock tree, so save the position */
1132 /* in the list of backtraces. */
1133
1134 newdataptr = (ddataptr)malloc(sizeof(delaydata));
1135 newdataptr->backtrace = newclock;
1136 if (newclock) newclock->refcnt++;
1137 newdataptr->delay = 0.0;
1138 newdataptr->skew = 0.0;
1139 newdataptr->setup = 0.0;
1140 newdataptr->trans = 0.0;
1141 newdataptr->next = *clocklist;
1142 *clocklist = newdataptr;
1143
1144 return result;
1145 }
1146
1147 /*--------------------------------------------------------------*/
1148 /* Determine the delay to a clock pin from the farthest point */
1149 /* back in the network, either to an input pin or the output of */
1150 /* another flop (e.g., a ripple counter). If there is more */
1151 /* than one such source (which can happen with, say, a gated */
1152 /* clock, because this routine will not differentiate between */
1153 /* the clock signal and the gating signal), then all sources */
1154 /* recorded (it is only necessary to find a common root of all */
1155 /* other related clocks downstream). */
1156 /* */
1157 /* This is a recursive routine, continuing to find all delays */
1158 /* through the circuit until it reaches "terminal". The */
1159 /* "delaylist" linked list is not modified by this routine. */
1160 /* However, it depends on routine find_clock_source marking */
1161 /* each connection as visited, so that the search is restricted */
1162 /* to the space visited on the upstream search, so it is not */
1163 /* blindly recursive. */
1164 /*--------------------------------------------------------------*/
1165
find_clock_delay(int dir,double delay,double trans,btptr backtrace,connptr terminal,char minmax,unsigned char mode)1166 void find_clock_delay(int dir, double delay, double trans,
1167 btptr backtrace, connptr terminal, char minmax,
1168 unsigned char mode) {
1169
1170 pinptr testpin;
1171 netptr loadnet;
1172 cellptr testcell;
1173 connptr receiver;
1174 connptr nextrcvr;
1175 instptr testinst;
1176 btptr testbtdata, newbtdata;
1177 double newdelayr, newdelayf, newtransr, newtransf;
1178 short outdir;
1179 int i;
1180
1181 receiver = backtrace->receiver;
1182
1183 if (minmax == MAXIMUM_TIME) {
1184 /* Is delay greater than that already recorded? If so, replace it */
1185 if ((delay > backtrace->delay) || (backtrace->delay == INITVAL)) {
1186 backtrace->delay = delay;
1187 backtrace->trans = trans;
1188 backtrace->dir = dir;
1189 }
1190 }
1191 else {
1192 /* Is delay less than that already recorded? If so, replace it */
1193 if ((delay < backtrace->delay) || (backtrace->delay == INITVAL)) {
1194 backtrace->delay = delay;
1195 backtrace->trans = trans;
1196 backtrace->dir = dir;
1197 }
1198 }
1199
1200 // Stop when receiver matches terminal.
1201
1202 if (receiver != terminal) {
1203
1204 // Don't follow signal through any DFF pins
1205 testpin = receiver->refpin;
1206 testinst = receiver->refinst;
1207 testcell = (testpin) ? testpin->refcell : NULL;
1208 if (testcell && (testcell->type & DFF)) return;
1209
1210 // Compute delay from gate input to output
1211
1212 outdir = calc_dir(testpin, dir);
1213 if (outdir & RISING) {
1214 newdelayr = backtrace->delay +
1215 calc_prop_delay(trans, receiver, RISING, minmax);
1216 newtransr = calc_transition(trans, receiver, RISING, minmax);
1217 }
1218 if (outdir & FALLING) {
1219 newdelayf = backtrace->delay +
1220 calc_prop_delay(trans, receiver, FALLING, minmax);
1221 newtransf = calc_transition(trans, receiver, FALLING, minmax);
1222 }
1223
1224 /* Continue calculating down the backtrace */
1225
1226 if (outdir & RISING)
1227 find_clock_delay(RISING, newdelayr, newtransr, backtrace->next,
1228 terminal, minmax, mode);
1229 if (outdir & FALLING)
1230 find_clock_delay(FALLING, newdelayf, newtransf, backtrace->next,
1231 terminal, minmax, mode);
1232 }
1233 }
1234
1235 /*--------------------------------------------------------------*/
1236 /* Determine the delay from input to output through a gate */
1237 /* */
1238 /* This is a recursive routine, continuing to find all delays */
1239 /* through the circuit until it reaches a terminal or flop */
1240 /* input. It is similar to find_clock_delay, but stops on all */
1241 /* terminal points found in the path, rather than stopping on */
1242 /* a specific connection. */
1243 /* */
1244 /* Also unlike find_clock_delay, the routine keeps a running */
1245 /* record of the path followed from the source, as a character */
1246 /* string. When a terminal is found, the path and delay are */
1247 /* saved and added to "delaylist". After the recursive search, */
1248 /* "delaylist" contains a list of all paths starting from the */
1249 /* original connection "receiver" and ending on a clock or an */
1250 /* output pin. Where multiple paths exist between source and */
1251 /* destination, only the path with the longest delay is kept. */
1252 /* */
1253 /* Return the number of new paths recorded. */
1254 /*--------------------------------------------------------------*/
1255
find_path_delay(int dir,double delay,double trans,connptr receiver,btptr backtrace,ddataptr * delaylist,char minmax)1256 int find_path_delay(int dir, double delay, double trans, connptr receiver,
1257 btptr backtrace, ddataptr *delaylist, char minmax) {
1258
1259 pinptr testpin;
1260 netptr loadnet;
1261 cellptr testcell;
1262 instptr testinst;
1263 btptr newbtdata, freebt, testbt;
1264 ddataptr testddata, newddata;
1265 double newdelayr, newdelayf, newtransr, newtransf;
1266 short outdir;
1267 char replace;
1268 int i, numpaths;
1269
1270 numpaths = 0;
1271 testpin = receiver->refpin;
1272
1273 // Prevent exhaustive search by stopping on a metric. Note that the
1274 // nonlinear table-based delay data requires an exhaustive search;
1275 // generally, the tables can be assumed to be monotonic, in which case
1276 // we can stop if the delay is less than the greatest delay recorded
1277 // at this point AND the transition time is less than the transition
1278 // time recorded along with that delay. A more relaxed metric is to
1279 // use the delay plus the transition time, and an even more relaxed
1280 // metric is to use only the delay. Any relaxing of the metric
1281 // implies that the final result may not be the absolute maximum delay,
1282 // although it will typically vary by less than an average gate delay.
1283
1284 if (!exhaustive) {
1285 if (minmax == MAXIMUM_TIME) {
1286 if (delay <= receiver->metric)
1287 return numpaths;
1288 }
1289 else {
1290 if (delay >= receiver->metric)
1291 return numpaths;
1292 }
1293 }
1294
1295 // Check for a logic loop, and truncate the path to avoid infinite
1296 // looping in the path search.
1297
1298 if (receiver->tag == (ddataptr)(-1)) return numpaths;
1299 else if (receiver->tag == NULL) receiver->tag = (ddataptr)(-1);
1300
1301 // Record this position and delay/transition information
1302
1303 newbtdata = (btptr)malloc(sizeof(btdata));
1304 newbtdata->receiver = receiver;
1305 newbtdata->delay = delay + newbtdata->receiver->icDelay;
1306 newbtdata->trans = trans;
1307 newbtdata->dir = dir;
1308 newbtdata->refcnt = 0;
1309 newbtdata->next = backtrace;
1310 if (backtrace) backtrace->refcnt++;
1311
1312 // Stop when we hit a module output pin or any flop/latch input.
1313 // We must allow the routine to pass through the 1st register clock (on the first
1314 // time through, backtrace is NULL).
1315
1316 if ((backtrace == NULL) || (testpin && ((testpin->type & REGISTER_IN) == 0))) {
1317
1318 testinst = receiver->refinst;
1319 testcell = (testpin) ? testpin->refcell : NULL;
1320
1321 // Compute delay from gate input to output
1322
1323 outdir = calc_dir(testpin, dir);
1324 if (outdir & RISING) {
1325 newdelayr = delay + calc_prop_delay(trans, receiver, RISING, minmax);
1326 newtransr = calc_transition(trans, receiver, RISING, minmax);
1327 }
1328 if (outdir & FALLING) {
1329 newdelayf = delay + calc_prop_delay(trans, receiver, FALLING, minmax);
1330 newtransf = calc_transition(trans, receiver, FALLING, minmax);
1331 }
1332
1333 if (!testinst || testinst->out_connects) {
1334 loadnet = (testinst) ? testinst->out_connects->refnet : receiver->refnet;
1335 for (i = 0; i < loadnet->fanout; i++) {
1336 if (outdir & RISING)
1337 numpaths += find_path_delay(RISING, newdelayr, newtransr,
1338 loadnet->receivers[i], newbtdata, delaylist, minmax);
1339 if (outdir & FALLING)
1340 numpaths += find_path_delay(FALLING, newdelayf, newtransf,
1341 loadnet->receivers[i], newbtdata, delaylist, minmax);
1342 }
1343 }
1344 receiver->tag = NULL;
1345 }
1346 else {
1347
1348 /* Is receiver already in delaylist? */
1349 if ((receiver->tag != (ddataptr)(-1)) && (receiver->tag != NULL)) {
1350
1351 /* Position in delaylist is recorded in tag field */
1352 testddata = receiver->tag;
1353
1354 if (testddata->backtrace->receiver == receiver) {
1355 replace = 0;
1356 if (minmax == MAXIMUM_TIME) {
1357 /* Is delay greater than that already recorded? If so, replace it */
1358 if (delay > testddata->backtrace->delay)
1359 replace = 1;
1360 }
1361 else {
1362 /* Is delay less than that already recorded? If so, replace it */
1363 if (delay < testddata->backtrace->delay)
1364 replace = 1;
1365 }
1366 if (replace) {
1367
1368 /* Remove the existing path record and replace it */
1369 while (testddata->backtrace != NULL) {
1370 freebt = testddata->backtrace;
1371 testddata->backtrace = testddata->backtrace->next;
1372 freebt->refcnt--;
1373 if (freebt->refcnt == 0) free(freebt);
1374 else break;
1375 }
1376 testddata->backtrace = newbtdata;
1377 if (newbtdata) newbtdata->refcnt++;
1378
1379 /* Update the delay at testddata */
1380 testddata->delay = newbtdata->delay + testddata->setup
1381 + testddata->skew;
1382 }
1383 }
1384 else
1385 fprintf(stderr, "ERROR: Bad endpoint tag!\n");
1386 }
1387 else
1388 testddata = NULL;
1389
1390 // If we have found a propagation path from source to dest,
1391 // record it in delaylist.
1392
1393 if (testddata == NULL) {
1394 numpaths++;
1395 newddata = (ddataptr)malloc(sizeof(delaydata));
1396 newddata->delay = 0.0;
1397 newddata->setup = 0.0;
1398 newddata->skew = 0.0;
1399 newddata->trans = 0.0;
1400 newddata->backtrace = newbtdata;
1401 if (newbtdata) newbtdata->refcnt++;
1402 newddata->next = *delaylist;
1403 *delaylist = newddata;
1404
1405 /* Mark the receiver as having been visited */
1406 receiver->tag = *delaylist;
1407 }
1408 }
1409
1410 receiver->metric = delay;
1411 if (newbtdata->refcnt <= 0) free(newbtdata);
1412 return numpaths;
1413 }
1414
1415 /*--------------------------------------------------------------*/
1416 /* Search the list "clocklist" for all points that are module */
1417 /* inputs or flop outputs, and compute the worst-case */
1418 /* transition time downstream at testlink. */
1419 /* */
1420 /* Upon return, the worst-case transition time is held in */
1421 /* returned backtrace pointer. */
1422 /* */
1423 /* If mode is non-zero, then only trace paths marked visited == */
1424 /* mode. This restricts the computation to nodes that were */
1425 /* found on the upstream search find_clock_source(). */
1426 /*--------------------------------------------------------------*/
1427
find_clock_transition(ddataptr clocklist,connptr testlink,short dir,char minmax,unsigned char mode)1428 void find_clock_transition(ddataptr clocklist, connptr testlink, short dir,
1429 char minmax, unsigned char mode)
1430 {
1431 ddataptr testclock;
1432 btptr backtrace;
1433 double tdriver, ddelay;
1434
1435 ddelay = 0.0;
1436 for (testclock = clocklist; testclock; testclock = testclock->next) {
1437 backtrace = testclock->backtrace;
1438 tdriver = 0.0; // to-do: set to default input transition time
1439 find_clock_delay(RISING, ddelay, tdriver, backtrace, testlink,
1440 minmax, mode);
1441 find_clock_delay(FALLING, ddelay, tdriver, backtrace, testlink,
1442 minmax, mode);
1443
1444 // In mode 2, only check timing from 1st item in the list
1445 if (mode == (unsigned char)2) break;
1446 }
1447 }
1448
1449 /*--------------------------------------------------------------*/
1450 /* Find the common point between two clock lists (it has */
1451 /* already been determined that a common point exists). */
1452 /* The 1st record of clock2list points to the connection */
1453 /* record that is the common point. What is needed is to find */
1454 /* the backtrace record in clocklist that points to the same */
1455 /* connection record. */
1456 /*--------------------------------------------------------------*/
1457
1458 btptr
find_common_clock(ddataptr clock2list,ddataptr clocklist)1459 find_common_clock(ddataptr clock2list, ddataptr clocklist)
1460 {
1461 ddataptr ddsearch;
1462 btptr btsearch;
1463 connptr ccommon;
1464
1465 ccommon = clock2list->backtrace->receiver;
1466
1467 for (ddsearch = clocklist; ddsearch; ddsearch = ddsearch->next)
1468 for (btsearch = ddsearch->backtrace; btsearch; btsearch = btsearch->next)
1469 if (btsearch->receiver == ccommon)
1470 return btsearch;
1471
1472 return NULL;
1473 }
1474
1475 /*--------------------------------------------------------------*/
1476 /* Given an instance record, find the pin of the instance that */
1477 /* is the clock, if the instance is a flop. If the instance is */
1478 /* not a flop, return NULL. */
1479 /*--------------------------------------------------------------*/
1480
find_register_clock(instptr testinst)1481 connptr find_register_clock(instptr testinst)
1482 {
1483 connptr testconn;
1484
1485 for (testconn = testinst->in_connects; testconn; testconn = testconn->next)
1486 if (testconn->refpin && (testconn->refpin->type & DFFCLK))
1487 return testconn;
1488
1489 return NULL;
1490 }
1491
1492 /*--------------------------------------------------------------*/
1493 /* Given an edge direction (RISING or FALLING) at a source net, */
1494 /* and given a destination net, find the sense of the signal */
1495 /* when it arrives at the destination net. */
1496 /*--------------------------------------------------------------*/
1497
find_edge_dir(short dir,netptr sourcenet,netptr destnet)1498 short find_edge_dir(short dir, netptr sourcenet, netptr destnet) {
1499 int i;
1500 short outdir, rdir;
1501 connptr testconn, nextconn;
1502 instptr testinst;
1503 netptr nextnet;
1504
1505 for (i = 0; i < sourcenet->fanout; i++) {
1506 testconn = sourcenet->receivers[i];
1507 testinst = testconn->refinst;
1508 if (testinst == NULL) continue;
1509 if (testconn->refpin == NULL) continue;
1510 if ((testconn->refpin->type & REGISTER_IN) != 0) continue;
1511 nextconn = testinst->out_connects;
1512 nextnet = nextconn->refnet;
1513 outdir = calc_dir(testconn->refpin, dir);
1514 if (nextnet == destnet) return outdir;
1515
1516 rdir = find_edge_dir(outdir, nextnet, destnet);
1517 if (rdir != 0) return rdir;
1518 }
1519 return 0;
1520 }
1521
1522 /*--------------------------------------------------------------*/
1523 /* Reset all entries in the whole network. Use sparingly. */
1524 /*--------------------------------------------------------------*/
1525
1526 void
reset_all(netptr netlist,char minmax)1527 reset_all(netptr netlist, char minmax)
1528 {
1529 netptr testnet;
1530 connptr testconn;
1531 int i;
1532 double metric;
1533
1534 metric = (minmax == MAXIMUM_TIME) ? -1.0 : 1.0E50;
1535
1536 for (testnet = netlist; testnet; testnet = testnet->next) {
1537 for (i = 0; i < testnet->fanout; i++) {
1538 testconn = testnet->receivers[i];
1539 testconn->tag = NULL;
1540 testconn->metric = metric;
1541 }
1542 }
1543 }
1544
1545 /*--------------------------------------------------------------*/
1546 /* Reset all entries in the feed-forward tree from connection */
1547 /* testconn (recursively). Resets the tag entry, "visited" */
1548 /* flag, and stop metric. */
1549 /*--------------------------------------------------------------*/
1550
1551 void
reset_path(connptr testconn,double metric)1552 reset_path(connptr testconn, double metric)
1553 {
1554 int i;
1555 instptr testinst;
1556 netptr loadnet;
1557 connptr nextconn;
1558
1559 testconn->tag = NULL;
1560 testconn->visited = (unsigned char)0;
1561 testconn->metric = metric;
1562
1563 testinst = testconn->refinst;
1564 loadnet = (testinst) ? testinst->out_connects->refnet : testconn->refnet;
1565
1566 for (i = 0; i < loadnet->fanout; i++) {
1567 nextconn = loadnet->receivers[i];
1568 if (nextconn->tag != NULL)
1569 reset_path(loadnet->receivers[i], metric);
1570 }
1571 }
1572
1573 /*--------------------------------------------------------------*/
1574 /* Search all paths from the clocked data outputs of */
1575 /* "clockedlist" to either output pins or data inputs of other */
1576 /* flops. */
1577 /* */
1578 /* Return a master list of all backtraces in "masterlist". */
1579 /* */
1580 /* Return value is the number of paths recorded in masterlist. */
1581 /* */
1582 /* If minmax == MAXIMUM_TIME, return the maximum delay. */
1583 /* If minmax == MINIMUM_TIME, return the minimum delay. */
1584 /*--------------------------------------------------------------*/
1585
find_clock_to_term_paths(connlistptr clockedlist,ddataptr * masterlist,netptr netlist,char minmax)1586 int find_clock_to_term_paths(connlistptr clockedlist, ddataptr *masterlist, netptr netlist,
1587 char minmax)
1588 {
1589 netptr testnet;
1590 connptr testconn, thisconn;
1591 connlistptr testlink;
1592 pinptr testpin;
1593 cellptr testcell;
1594 instptr testinst;
1595 btptr backtrace, freebt;
1596 ddataptr delaylist, testddata, freeddata;
1597
1598 short srcdir, destdir; // Signal direction in/out
1599 double tdriver, setupdelay, holddelay, ddelay;
1600 int numpaths, n, i, t, j;
1601 unsigned char result;
1602
1603 delaylist = NULL;
1604
1605 t = j = 0;
1606 if (verbose > 0) {
1607 for (testlink = clockedlist; testlink; testlink = testlink->next)
1608 t++;
1609 fprintf(stdout, "Length of list of clocked nets = %d\n", t);
1610 fflush(stdout);
1611 }
1612
1613 numpaths = 0;
1614 for (testlink = clockedlist; testlink; testlink = testlink->next) {
1615 if (verbose > 0) {
1616 j++;
1617 if ((j % 100) == 0) {
1618 fprintf(stdout, "Completed %d traces (%3.1f%%).\n",
1619 j, 100.0 * ((float)j / (float)t));
1620 fflush(stdout);
1621 }
1622 }
1623
1624 // Remove all tags and reset delay metrics in testlink tree
1625 // before each run
1626
1627 reset_path(testlink->connection, (minmax == MAXIMUM_TIME) ? -1.0 : 1E50);
1628
1629 thisconn = testlink->connection;
1630 testpin = thisconn->refpin;
1631 if (testpin) {
1632 testcell = testpin->refcell;
1633
1634 // Sense is positive for rising edge-triggered flops, negative for
1635 // falling edge-triggered flops
1636 srcdir = (testcell->type & CLK_SENSE_MASK) ? FALLING : RISING;
1637
1638 // Report on paths and their maximum delays
1639 if (verbose > 1)
1640 fprintf(stdout, "Paths starting at flop \"%s\" clock:\n\n",
1641 thisconn->refinst->name);
1642 }
1643 else {
1644 // Connection is an input pin; must calculate both rising and falling edges.
1645 srcdir = EITHER;
1646
1647 // Report on paths and their maximum delays
1648 if (verbose > 1)
1649 fprintf(stdout, "Paths starting at input pin \"%s\"\n\n",
1650 thisconn->refnet->name);
1651 }
1652
1653 if (verbose > 1) fflush(stdout);
1654
1655 // Find all paths from "thisconn" to output or a flop input, and compute delay
1656 n = find_path_delay(srcdir, 0.0, 0.0, thisconn, NULL, &delaylist, minmax);
1657 numpaths += n;
1658
1659 if (verbose > 1) fprintf(stdout, "%d paths traced (%d total).\n\n", n, numpaths);
1660
1661 // Link delaylist data to the beginning of masterlist, and null out
1662 // delaylist for the next set of paths.
1663
1664 if (delaylist) {
1665 for (testddata = delaylist; testddata->next; testddata = testddata->next);
1666 testddata->next = *masterlist;
1667 *masterlist = delaylist;
1668 delaylist = NULL;
1669 }
1670
1671 }
1672 return numpaths;
1673 }
1674
1675 /*--------------------------------------------------------------*/
1676 /* A version of strcasecmp() with a built-in check for */
1677 /* surrounding quotes (which are ignored). Quotes are only */
1678 /* checked in str1. */
1679 /*--------------------------------------------------------------*/
1680
1681 int
tokencasecmp(char * str1,char * str2)1682 tokencasecmp(char *str1, char *str2)
1683 {
1684 char *ss1, *sf1;
1685 int result;
1686
1687 ss1 = str1;
1688 sf1 = NULL;
1689 while (*ss1 == '\"') ss1++;
1690 if (ss1 != str1) {
1691 sf1 = ss1 + 1;
1692 while (*sf1 && (*sf1 != '\"')) sf1++;
1693 if (*sf1 == '\"')
1694 *sf1 = '\0';
1695 else
1696 sf1 = NULL;
1697 }
1698
1699 result = strcasecmp(ss1, str2);
1700
1701 if (sf1 != NULL) *sf1 = '\"';
1702
1703 return result;
1704 }
1705
1706 /*--------------------------------------------------------------*/
1707 /* Parse a table variable type from a liberty format file */
1708 /*--------------------------------------------------------------*/
1709
get_table_type(char * token)1710 int get_table_type(char *token) {
1711 if (!tokencasecmp(token, "input_net_transition"))
1712 return TRANSITION_TIME;
1713 else if (!tokencasecmp(token, "total_output_net_capacitance"))
1714 return OUTPUT_CAP;
1715 else if (!tokencasecmp(token, "related_pin_transition"))
1716 return RELATED_TIME;
1717 else if (!tokencasecmp(token, "constrained_pin_transition"))
1718 return CONSTRAINED_TIME;
1719 else
1720 return UNKNOWN;
1721 }
1722
1723 /*--------------------------------------------------------------*/
1724 /* Expand a bus into individual pins. */
1725 /*--------------------------------------------------------------*/
1726
1727 void
expand_buses(pin * curpin,bus * curbus,char * busformat)1728 expand_buses(pin *curpin, bus *curbus, char *busformat)
1729 {
1730 pin *newpin;
1731 char *rootname;
1732 int low, high, i;
1733 char busbit[1024];
1734
1735 rootname = curpin->name;
1736
1737 if (curbus == NULL) {
1738 fprintf(stderr, "Error: Pin %s is a bus, but no bus definition exists!\n",
1739 curpin->name);
1740 return;
1741 }
1742 if (curbus->from > curbus->to) {
1743 low = curbus->to;
1744 high = curbus->from;
1745 }
1746 else {
1747 low = curbus->from;
1748 high = curbus->to;
1749 }
1750
1751 for (i = low; i <= high; i++) {
1752 sprintf(busbit, busformat, rootname, i);
1753
1754 if (i == low)
1755 newpin = curpin;
1756 else
1757 newpin = (pin *)malloc(sizeof(pin));
1758 newpin->name = tokendup(busbit);
1759 newpin->next = NULL;
1760 if (i != low) {
1761 curpin->next = newpin;
1762
1763 /* Copy all pin properties from the old pin to the new pin */
1764 newpin->type = curpin->type;
1765 newpin->capr = curpin->capr;
1766 newpin->capf = curpin->capf;
1767 newpin->sense = curpin->sense;
1768 newpin->transr = curpin->transr;
1769 newpin->transf = curpin->transf;
1770 newpin->propdelr = curpin->propdelr;
1771 newpin->propdelf = curpin->propdelf;
1772 newpin->refcell = curpin->refcell;
1773
1774 curpin = newpin;
1775 }
1776 }
1777 free(rootname);
1778 }
1779
1780 /*--------------------------------------------------------------*/
1781 /* Read a liberty format file and collect information about */
1782 /* the timing properties of each standard cell. */
1783 /*--------------------------------------------------------------*/
1784
1785 void
libertyRead(FILE * flib,lutable ** tablelist,cell ** celllist)1786 libertyRead(FILE *flib, lutable **tablelist, cell **celllist)
1787 {
1788 char *token;
1789 char *libname = NULL;
1790 int section = INIT;
1791
1792 double time_unit = 1.0; // Time unit multiplier, to get ps
1793 double cap_unit = 1.0; // Capacitive unit multiplier, to get fF
1794
1795 pinptr testpin;
1796 lutable *tableptr;
1797
1798 pin proxypin;
1799 int i, j;
1800 double gval;
1801 char *iptr;
1802 char *busformat;
1803 short timing_type;
1804
1805 lutable *newtable, *reftable;
1806 cell *newcell, *lastcell;
1807 pin *newpin;
1808 bus *buses = NULL, *newbus, *curbus = NULL;
1809
1810 lastcell = NULL;
1811 timing_type = UNKNOWN;
1812
1813 /* Set up pin placeholder */
1814 proxypin.name = NULL;
1815 proxypin.type = GATE;
1816 proxypin.capr = 0.0;
1817 proxypin.capf = 0.0;
1818 proxypin.sense = SENSE_NONE;
1819 proxypin.propdelr = NULL;
1820 proxypin.propdelf = NULL;
1821 proxypin.transr = NULL;
1822 proxypin.transf = NULL;
1823 proxypin.refcell = NULL;
1824 proxypin.next = NULL;
1825
1826 /* Set default bus format (verilog style) */
1827 busformat = strdup("%s[%d]");
1828
1829 /* Read tokens off of the line */
1830 token = advancetoken(flib, 0);
1831
1832 while (token != NULL) {
1833
1834 switch (section) {
1835 case INIT:
1836 if (debug == 2) fprintf(stdout, "INIT: %s\n", token);
1837 if (!tokencasecmp(token, "library")) {
1838 token = advancetoken(flib, 0);
1839 if (strcmp(token, "("))
1840 fprintf(stderr, "Library not followed by name\n");
1841 else
1842 token = advancetoken(flib, ')');
1843 /* Diagnostic */
1844 fprintf(stdout, "Parsing library \"%s\"\n", token);
1845 libname = tokendup(token);
1846 token = advancetoken(flib, 0);
1847 if (strcmp(token, "{")) {
1848 fprintf(stderr, "Did not find opening brace "
1849 "on library block\n");
1850 exit(1);
1851 }
1852 section = LIBBLOCK;
1853 }
1854 else
1855 fprintf(stderr, "Unknown input \"%s\", looking for "
1856 "\"library\"\n", token);
1857 break;
1858
1859 case LIBBLOCK:
1860 // Here we check for the main blocks, again not rigorously. . .
1861
1862 if (debug == 2) fprintf(stdout, "LIBBLOCK: %s\n", token);
1863 if (!strcasecmp(token, "}")) {
1864 fprintf(stdout, "End of library at line %d\n", fileCurrentLine);
1865 section = INIT; // End of library block
1866 }
1867 else if (!tokencasecmp(token, "delay_model")) {
1868 token = advancetoken(flib, 0);
1869 if (strcmp(token, ":"))
1870 fprintf(stderr, "Input missing colon\n");
1871 token = advancetoken(flib, ';');
1872 if (tokencasecmp(token, "table_lookup")) {
1873 fprintf(stderr, "Sorry, only know how to "
1874 "handle table lookup!\n");
1875 exit(1);
1876 }
1877 }
1878 else if (!tokencasecmp(token, "lu_table_template") ||
1879 !tokencasecmp(token, "power_lut_template")) {
1880 // Read in template information;
1881 newtable = (lutable *)malloc(sizeof(lutable));
1882 newtable->name = NULL;
1883 newtable->invert = 0;
1884 newtable->var1 = UNKNOWN;
1885 newtable->var2 = UNKNOWN;
1886 newtable->size1 = 0;
1887 newtable->size2 = 0;
1888 newtable->idx1.times = NULL;
1889 newtable->idx2.caps = NULL;
1890 newtable->values = NULL;
1891 newtable->next = *tablelist;
1892 *tablelist = newtable;
1893
1894 token = advancetoken(flib, 0);
1895 if (strcmp(token, "("))
1896 fprintf(stderr, "Input missing open parens\n");
1897 else
1898 token = advancetoken(flib, ')');
1899 newtable->name = tokendup(token);
1900 while (*token != '}') {
1901 token = advancetoken(flib, 0);
1902 if (!tokencasecmp(token, "variable_1")) {
1903 token = advancetoken(flib, 0);
1904 token = advancetoken(flib, ';');
1905 newtable->var1 = get_table_type(token);
1906 if (newtable->var1 == OUTPUT_CAP || newtable->var1 == CONSTRAINED_TIME)
1907 newtable->invert = 1;
1908 }
1909 else if (!tokencasecmp(token, "variable_2")) {
1910 token = advancetoken(flib, 0);
1911 token = advancetoken(flib, ';');
1912 newtable->var2 = get_table_type(token);
1913 if (newtable->var2 == TRANSITION_TIME || newtable->var2 == RELATED_TIME)
1914 newtable->invert = 1;
1915 }
1916 else if (!tokencasecmp(token, "index_1")) {
1917 char dnum = ',';
1918
1919 token = advancetoken(flib, 0); // Open parens
1920 token = advancetoken(flib, 0); // Quote
1921 if (!strcmp(token, "\""))
1922 token = advancetoken(flib, '\"');
1923
1924 iptr = token;
1925
1926 // Check if table is space or comma separated
1927 if (strchr(iptr, dnum) == NULL)
1928 if (strchr(iptr, ' ') != NULL)
1929 dnum = ' ';
1930
1931 if (newtable->invert == 1) {
1932 // Count entries
1933 newtable->size2 = 1;
1934 while ((iptr = strchr(iptr, dnum)) != NULL) {
1935 iptr++;
1936 newtable->size2++;
1937 }
1938 newtable->idx2.caps = (double *)malloc(newtable->size2 *
1939 sizeof(double));
1940 newtable->size2 = 0;
1941 iptr = token;
1942 sscanf(iptr, "%lg", &newtable->idx2.caps[0]);
1943 if (newtable->var2 == OUTPUT_CAP)
1944 newtable->idx2.caps[0] *= cap_unit;
1945 else
1946 newtable->idx2.caps[0] *= time_unit;
1947
1948 while ((iptr = strchr(iptr, dnum)) != NULL) {
1949 iptr++;
1950 newtable->size2++;
1951 sscanf(iptr, "%lg",
1952 &newtable->idx2.caps[newtable->size2]);
1953 if (newtable->var2 == OUTPUT_CAP)
1954 newtable->idx2.caps[newtable->size2] *= cap_unit;
1955 else
1956 newtable->idx2.cons[newtable->size2] *= time_unit;
1957 }
1958 newtable->size2++;
1959 }
1960 else { // newtable->invert = 0
1961 // Count entries
1962 newtable->size1 = 1;
1963 while ((iptr = strchr(iptr, dnum)) != NULL) {
1964 iptr++;
1965 newtable->size1++;
1966 }
1967 newtable->idx1.times = (double *)malloc(newtable->size1 *
1968 sizeof(double));
1969 newtable->size1 = 0;
1970 iptr = token;
1971 sscanf(iptr, "%lg", &newtable->idx1.times[0]);
1972 newtable->idx1.times[0] *= time_unit;
1973 while ((iptr = strchr(iptr, dnum)) != NULL) {
1974 iptr++;
1975 newtable->size1++;
1976 sscanf(iptr, "%lg",
1977 &newtable->idx1.times[newtable->size1]);
1978 newtable->idx1.times[newtable->size1] *= time_unit;
1979 }
1980 newtable->size1++;
1981 }
1982
1983 token = advancetoken(flib, ';'); // EOL semicolon
1984 }
1985 else if (!tokencasecmp(token, "index_2")) {
1986 char dnum = ',';
1987
1988 token = advancetoken(flib, 0); // Open parens
1989 token = advancetoken(flib, 0); // Quote
1990 if (!strcmp(token, "\""))
1991 token = advancetoken(flib, '\"');
1992
1993 iptr = token;
1994
1995 // Check if table is space or comma separated
1996 if (strchr(iptr, dnum) == NULL)
1997 if (strchr(iptr, ' ') != NULL)
1998 dnum = ' ';
1999
2000 if (newtable->invert == 0) {
2001 // Count entries
2002 newtable->size2 = 1;
2003 while ((iptr = strchr(iptr, dnum)) != NULL) {
2004 iptr++;
2005 newtable->size2++;
2006 }
2007 newtable->idx2.caps = (double *)malloc(newtable->size2 *
2008 sizeof(double));
2009 newtable->size2 = 0;
2010 iptr = token;
2011 sscanf(iptr, "%lg", &newtable->idx2.caps[0]);
2012 if (newtable->var2 == OUTPUT_CAP)
2013 newtable->idx2.caps[0] *= cap_unit;
2014 else
2015 newtable->idx2.cons[0] *= time_unit;
2016 while ((iptr = strchr(iptr, dnum)) != NULL) {
2017 iptr++;
2018 newtable->size2++;
2019 sscanf(iptr, "%lg",
2020 &newtable->idx2.caps[newtable->size2]);
2021 if (newtable->var2 == OUTPUT_CAP)
2022 newtable->idx2.caps[newtable->size2] *= cap_unit;
2023 else
2024 newtable->idx2.cons[newtable->size2] *= time_unit;
2025 }
2026 newtable->size2++;
2027 }
2028 else { // newtable->invert == 1
2029 // Count entries
2030 newtable->size1 = 1;
2031 while ((iptr = strchr(iptr, dnum)) != NULL) {
2032 iptr++;
2033 newtable->size1++;
2034 }
2035 newtable->idx1.times = (double *)malloc(newtable->size1 *
2036 sizeof(double));
2037 newtable->size1 = 0;
2038 iptr = token;
2039 sscanf(iptr, "%lg", &newtable->idx1.times[0]);
2040 newtable->idx1.times[0] *= time_unit;
2041 while ((iptr = strchr(iptr, dnum)) != NULL) {
2042 iptr++;
2043 newtable->size1++;
2044 sscanf(iptr, "%lg",
2045 &newtable->idx1.times[newtable->size1]);
2046 newtable->idx1.times[newtable->size1] *= time_unit;
2047 }
2048 newtable->size1++;
2049 }
2050
2051 token = advancetoken(flib, ';'); // EOL semicolon
2052 }
2053 }
2054 }
2055 else if (!strcasecmp(token, "cell")) {
2056 newcell = (cell *)malloc(sizeof(cell));
2057 newcell->next = NULL;
2058 if (lastcell != NULL)
2059 lastcell->next = newcell;
2060 else
2061 *celllist = newcell;
2062 lastcell = newcell;
2063 token = advancetoken(flib, 0); // Open parens
2064 if (!strcmp(token, "("))
2065 token = advancetoken(flib, ')'); // Cellname
2066 if (debug == 2) fprintf(stdout, " cell = %s\n", token);
2067 newcell->name = tokendup(token);
2068 token = advancetoken(flib, 0); // Find start of block
2069 if (strcmp(token, "{"))
2070 fprintf(stderr, "Error: failed to find start of block\n");
2071 newcell->type = GATE; // Default type
2072 newcell->function = NULL;
2073 newcell->pins = NULL;
2074 newcell->area = 1.0;
2075 newcell->maxtrans = 0.0;
2076 newcell->maxcap = 0.0;
2077 section = CELLDEF;
2078 }
2079 else if (!strcasecmp(token, "time_unit")) {
2080 char *metric;
2081
2082 token = advancetoken(flib, 0);
2083 if (token == NULL) break;
2084 if (!strcmp(token, ":")) {
2085 token = advancetoken(flib, 0);
2086 if (token == NULL) break;
2087 }
2088 if (!strcmp(token, "\"")) {
2089 token = advancetoken(flib, '\"');
2090 if (token == NULL) break;
2091 }
2092 time_unit = strtod(token, &metric);
2093 if (*metric != '\0') {
2094 if (!strcmp(metric, "ns"))
2095 time_unit *= 1E3;
2096 else if (!strcmp(metric, "us"))
2097 time_unit *= 1E6;
2098 else if (!strcmp(metric, "fs"))
2099 time_unit *= 1E-3;
2100 else if (strcmp(metric, "ps"))
2101 fprintf(stderr, "Don't understand time units \"%s\"\n",
2102 token);
2103 }
2104 else {
2105 token = advancetoken(flib, 0);
2106 if (token == NULL) break;
2107 if (!strcmp(token, "ns"))
2108 time_unit *= 1E3;
2109 else if (!strcmp(token, "us"))
2110 time_unit *= 1E6;
2111 else if (!strcmp(token, "fs"))
2112 time_unit *= 1E-3;
2113 else if (strcmp(token, "ps"))
2114 fprintf(stderr, "Don't understand time units \"%s\"\n",
2115 token);
2116 }
2117 token = advancetoken(flib, ';');
2118 }
2119 else if (!strcasecmp(token, "capacitive_load_unit")) {
2120 char *metric;
2121
2122 token = advancetoken(flib, 0);
2123 if (token == NULL) break;
2124 if (!strcmp(token, "(")) {
2125 token = advancetoken(flib, ')');
2126 if (token == NULL) break;
2127 }
2128 cap_unit = strtod(token, &metric);
2129 if (*metric != '\0') {
2130 while (isblank(*metric)) metric++;
2131 if (*metric == ',') metric++;
2132 while ((*metric != '\0') && isblank(*metric)) metric++;
2133 if (*metric == '\"') {
2134 char *qptr;
2135 metric++;
2136 qptr = metric;
2137 while ((*qptr != '\"') && (*qptr != '\0')) qptr++;
2138 *qptr = '\0';
2139 }
2140 if (!tokencasecmp(metric, "af"))
2141 cap_unit *= 1E-3;
2142 else if (!tokencasecmp(metric, "pf"))
2143 cap_unit *= 1000;
2144 else if (!tokencasecmp(metric, "nf"))
2145 cap_unit *= 1E6;
2146 else if (!tokencasecmp(metric, "uf"))
2147 cap_unit *= 1E9;
2148 else if (tokencasecmp(metric, "ff"))
2149 fprintf(stderr, "Don't understand capacitive units \"%s\"\n",
2150 token);
2151 }
2152 else {
2153 token = advancetoken(flib, 0);
2154 if (token == NULL) break;
2155 if (!tokencasecmp(token, "af"))
2156 cap_unit *= 1E-3;
2157 else if (!tokencasecmp(token, "pf"))
2158 cap_unit *= 1000;
2159 else if (!tokencasecmp(token, "nf"))
2160 cap_unit *= 1E6;
2161 else if (!tokencasecmp(token, "uf"))
2162 cap_unit *= 1E9;
2163 else if (tokencasecmp(token, "ff"))
2164 fprintf(stderr, "Don't understand capacitive units \"%s\"\n",
2165 token);
2166 }
2167 token = advancetoken(flib, ';');
2168 }
2169 else if (!strcasecmp(token, "bus_naming_style")) {
2170 token = advancetoken(flib, 0);
2171 if (token == NULL) break;
2172 if (!strcmp(token, ":")) {
2173 token = advancetoken(flib, 0);
2174 if (token == NULL) break;
2175 }
2176 if (!strcmp(token, "\"")) {
2177 token = advancetoken(flib, '\"');
2178 if (token == NULL) break;
2179 }
2180 free(busformat);
2181 busformat = tokendup(token);
2182 token = advancetoken(flib, ';');
2183 }
2184 else if (!strcasecmp(token, "type")) {
2185 newbus = (bus *)malloc(sizeof(bus));
2186 newbus->from = 0;
2187 newbus->to = 0;
2188 newbus->next = buses;
2189 buses = newbus;
2190
2191 token = advancetoken(flib, 0);
2192 if (strcmp(token, "("))
2193 fprintf(stderr, "Input missing open parenthesis.\n");
2194 else
2195 token = advancetoken(flib, ')');
2196 newbus->name = tokendup(token);
2197 while (*token != '}') {
2198 token = advancetoken(flib, 0);
2199 if (!strcasecmp(token, "bit_from")) {
2200 token = advancetoken(flib, 0);
2201 token = advancetoken(flib, ';');
2202 sscanf(token, "%d", &newbus->from);
2203 }
2204 else if (!strcasecmp(token, "bit_to")) {
2205 token = advancetoken(flib, 0);
2206 token = advancetoken(flib, ';');
2207 sscanf(token, "%d", &newbus->to);
2208 }
2209 else if (!strcasecmp(token, "{")) {
2210 /* All entries are <name> : <value> */
2211 /* Ignore unhandled tokens. */
2212 token = advancetoken(flib, 0);
2213 token = advancetoken(flib, ';');
2214 }
2215 }
2216 }
2217 else {
2218 // For unhandled tokens, read in tokens. If it is
2219 // a definition or function, read to end-of-line. If
2220 // it is a block definition, read to end-of-block.
2221 while (1) {
2222 token = advancetoken(flib, 0);
2223 if (token == NULL) break;
2224 if (!strcmp(token, ";")) break;
2225 if (!strcmp(token, "\""))
2226 token = advancetoken(flib, '\"');
2227 if (!strcmp(token, "{")) {
2228 token = advancetoken(flib, '}');
2229 break;
2230 }
2231 }
2232 }
2233 break;
2234
2235 case CELLDEF:
2236
2237 if (debug == 2) fprintf(stdout, "CELLDEF: %s\n", token);
2238 if (!strcmp(token, "}")) {
2239 section = LIBBLOCK; // End of cell def
2240 }
2241 else if (!strcasecmp(token, "pin") ||
2242 !strcasecmp(token, "bus")) {
2243 token = advancetoken(flib, 0); // Open parens
2244 if (!strcmp(token, "("))
2245 token = advancetoken(flib, ')'); // Close parens
2246
2247 newpin = parse_pin(newcell, token);
2248 if (debug == 2) fprintf(stdout, " pin = %s\n", token);
2249
2250 token = advancetoken(flib, 0); // Find start of block
2251 if (strcmp(token, "{"))
2252 fprintf(stderr, "Error: failed to find start of block\n");
2253 section = PINDEF;
2254 }
2255 else if (!strcasecmp(token, "area")) {
2256 token = advancetoken(flib, 0); // Colon
2257 token = advancetoken(flib, ';'); // To end-of-statement
2258 sscanf(token, "%lg", &newcell->area);
2259 }
2260 else if (!strcasecmp(token, "ff")) {
2261 newcell->type |= DFF;
2262 token = advancetoken(flib, '{');
2263 section = FLOPDEF;
2264 }
2265 else if (!strcasecmp(token, "latch")) {
2266 newcell->type |= LATCH;
2267 token = advancetoken(flib, '{');
2268 section = LATCHDEF;
2269 }
2270 else {
2271 // For unhandled tokens, read in tokens. If it is
2272 // a definition or function, read to end-of-line. If
2273 // it is a block definition, read to end-of-block.
2274 while (1) {
2275 token = advancetoken(flib, 0);
2276 if (token == NULL) break;
2277 if (!strcmp(token, ";")) break;
2278 if (!strcmp(token, "\""))
2279 token = advancetoken(flib, '\"');
2280 if (!strcmp(token, "("))
2281 token = advancetoken(flib, ')');
2282 if (!strcmp(token, "{")) {
2283 token = advancetoken(flib, '}');
2284 break;
2285 }
2286 }
2287 }
2288 break;
2289
2290 case FLOPDEF:
2291
2292 if (debug == 2) fprintf(stdout, "FLOPDEF: %s\n", token);
2293 if (!strcmp(token, "}")) {
2294 section = CELLDEF; // End of flop def
2295 }
2296 else if (!strcasecmp(token, "next_state")) {
2297 token = advancetoken(flib, 0); // Colon
2298 token = advancetoken(flib, ';'); // To end-of-statement
2299 newpin = parse_pin(newcell, token);
2300 newpin->type |= DFFIN;
2301 }
2302 else if (!strcasecmp(token, "clocked_on")) {
2303 token = advancetoken(flib, 0); // Colon
2304 token = advancetoken(flib, ';'); // To end-of-statement
2305 if (strchr(token, '\'') != NULL)
2306 newcell->type |= CLK_SENSE_MASK;
2307 else if (strchr(token, '!') != NULL)
2308 newcell->type |= CLK_SENSE_MASK;
2309 newpin = parse_pin(newcell, token);
2310 newpin->type |= DFFCLK;
2311 }
2312 else if (!strcasecmp(token, "clear")) {
2313 newcell->type |= RST_MASK;
2314 token = advancetoken(flib, 0); // Colon
2315 token = advancetoken(flib, ';'); // To end-of-statement
2316 if (strchr(token, '\'') != NULL)
2317 newcell->type |= RST_SENSE_MASK;
2318 else if (strchr(token, '!') != NULL)
2319 newcell->type |= RST_SENSE_MASK;
2320 newpin = parse_pin(newcell, token);
2321 newpin->type |= DFFRST;
2322 }
2323 else if (!strcasecmp(token, "preset")) {
2324 newcell->type |= SET_MASK;
2325 token = advancetoken(flib, 0); // Colon
2326 token = advancetoken(flib, ';'); // To end-of-statement
2327 if (strchr(token, '\'') != NULL)
2328 newcell->type |= SET_SENSE_MASK;
2329 else if (strchr(token, '!') != NULL)
2330 newcell->type |= SET_SENSE_MASK;
2331 newpin = parse_pin(newcell, token);
2332 newpin->type |= DFFSET;
2333 }
2334 else
2335 token = advancetoken(flib, ';'); // Read to end-of-statement
2336
2337 break;
2338
2339 case LATCHDEF:
2340
2341 if (debug == 2) fprintf(stdout, "LATCHDEF: %s\n", token);
2342 if (!strcmp(token, "}")) {
2343 section = CELLDEF; // End of flop def
2344 }
2345 else if (!strcasecmp(token, "data_in")) {
2346 token = advancetoken(flib, 0); // Colon
2347 token = advancetoken(flib, ';'); // To end-of-statement
2348 newpin = parse_pin(newcell, token);
2349 newpin->type |= LATCHIN;
2350 }
2351 else if (!strcasecmp(token, "enable")) {
2352 token = advancetoken(flib, 0); // Colon
2353 token = advancetoken(flib, ';'); // To end-of-statement
2354 if (strchr(token, '\'') != NULL)
2355 newcell->type |= EN_SENSE_MASK;
2356 else if (strchr(token, '!') != NULL)
2357 newcell->type |= EN_SENSE_MASK;
2358 newpin = parse_pin(newcell, token);
2359 newpin->type |= LATCHEN;
2360 }
2361 else
2362 token = advancetoken(flib, ';'); // Read to end-of-statement
2363
2364 break;
2365
2366 case PINDEF:
2367
2368 if (debug == 2) fprintf(stdout, "PINDEF: %s\n", token);
2369 if (!strcmp(token, "}")) {
2370 if (curbus != NULL)
2371 expand_buses(newpin, curbus, busformat);
2372 curbus = NULL;
2373 section = CELLDEF; // End of pin def
2374 }
2375 else if (!strcasecmp(token, "capacitance")) {
2376 token = advancetoken(flib, 0); // Colon
2377 token = advancetoken(flib, ';'); // To end-of-statement
2378 sscanf(token, "%lg", &newpin->capr);
2379 newpin->capr *= cap_unit;
2380 }
2381 else if (!strcasecmp(token, "rise_capacitance")) {
2382 token = advancetoken(flib, 0); // Colon
2383 token = advancetoken(flib, ';'); // To end-of-statement
2384 sscanf(token, "%lg", &newpin->capr);
2385 newpin->capr *= cap_unit;
2386 }
2387 else if (!strcasecmp(token, "fall_capacitance")) {
2388 token = advancetoken(flib, 0); // Colon
2389 token = advancetoken(flib, ';'); // To end-of-statement
2390 sscanf(token, "%lg", &newpin->capf);
2391 newpin->capf *= cap_unit;
2392 }
2393 else if (!strcasecmp(token, "function")) {
2394 token = advancetoken(flib, 0); // Colon
2395 token = advancetoken(flib, 0); // Open quote
2396 if (!strcmp(token, "\""))
2397 token = advancetoken(flib, '\"'); // Find function string
2398 if (newpin->type & OUTPUT) {
2399 newcell->function = tokendup(token);
2400 }
2401 token = advancetoken(flib, 0);
2402 if (strcmp(token, ";")) {
2403 if (!strcmp(token, "}"))
2404 section = CELLDEF; // End of pin def
2405 else
2406 fprintf(stderr, "Expected end-of-statement.\n");
2407 }
2408 }
2409 else if (!strcasecmp(token, "bus_type")) {
2410 token = advancetoken(flib, 0); // Colon
2411 token = advancetoken(flib, ';');
2412 /* Find the bus definition */
2413 for (curbus = buses; curbus; curbus = curbus->next)
2414 if (!tokencasecmp(token, curbus->name))
2415 break;
2416 if (curbus == NULL)
2417 fprintf(stderr, "Failed to find a valid bus type \"%s\"\n",
2418 token);
2419 }
2420 else if (!strcasecmp(token, "direction")) {
2421 token = advancetoken(flib, 0); // Colon
2422 token = advancetoken(flib, ';');
2423 if (!tokencasecmp(token, "input")) {
2424 newpin->type |= INPUT;
2425 }
2426 else if (!tokencasecmp(token, "output")) {
2427 newpin->type |= OUTPUT;
2428 if (newcell->type & DFF) newpin->type |= DFFOUT;
2429 if (newcell->type & LATCH) newpin->type |= LATCHOUT;
2430 }
2431 }
2432 else if (!strcasecmp(token, "max_transition")) {
2433 token = advancetoken(flib, 0); // Colon
2434 token = advancetoken(flib, ';'); // To end-of-statement
2435 sscanf(token, "%lg", &newcell->maxtrans);
2436 newcell->maxtrans *= time_unit;
2437 }
2438 else if (!strcasecmp(token, "max_capacitance")) {
2439 token = advancetoken(flib, 0); // Colon
2440 token = advancetoken(flib, ';'); // To end-of-statement
2441 sscanf(token, "%lg", &newcell->maxcap);
2442 newcell->maxcap *= cap_unit;
2443 }
2444 else if (!strcasecmp(token, "timing")) {
2445 token = advancetoken(flib, 0); // Arguments, if any
2446 if (strcmp(token, "("))
2447 fprintf(stderr, "Error: failed to find start of block\n");
2448 else
2449 token = advancetoken(flib, ')'); // Arguments, if any
2450 token = advancetoken(flib, 0); // Find start of block
2451 if (strcmp(token, "{"))
2452 fprintf(stderr, "Error: failed to find start of block\n");
2453 testpin = &proxypin; /* Placeholder */
2454 section = TIMING;
2455 }
2456 else {
2457 // For unhandled tokens, read in tokens. If it is
2458 // a definition or function, read to end-of-line. If
2459 // it is a block definition, read to end-of-block.
2460 while (1) {
2461 token = advancetoken(flib, 0);
2462 if (token == NULL) break;
2463 if (!strcmp(token, ";")) break;
2464 if (!strcmp(token, "\""))
2465 token = advancetoken(flib, '\"');
2466 if (!strcmp(token, "{")) {
2467 token = advancetoken(flib, '}');
2468 break;
2469 }
2470 }
2471 }
2472 break;
2473
2474 case TIMING:
2475
2476 if (debug == 2) fprintf(stdout, "TIMING: %s\n", token);
2477 if (!strcmp(token, "}")) {
2478 section = PINDEF; // End of timing def
2479 }
2480 else if (!strcasecmp(token, "related_pin")) {
2481 token = advancetoken(flib, 0); // Colon
2482 token = advancetoken(flib, ';'); // Read to end of statement
2483 if (testpin != &proxypin) {
2484 fprintf(stderr, "Error: Record already created"
2485 " for related_pin");
2486 free(testpin);
2487 }
2488 // Create the related pin
2489 testpin = parse_pin(newcell, token);
2490 // Copy any records from the placeholder
2491 testpin->sense = proxypin.sense;
2492 testpin->propdelr = proxypin.propdelr;
2493 testpin->propdelf = proxypin.propdelf;
2494 testpin->transr = proxypin.transr;
2495 testpin->transf = proxypin.transf;
2496 // Reset the placeholder records
2497 proxypin.sense = SENSE_NONE;
2498 proxypin.propdelr = NULL;
2499 proxypin.propdelf = NULL;
2500 proxypin.transr = NULL;
2501 proxypin.transf = NULL;
2502 }
2503 else if (!strcasecmp(token, "timing_sense")) {
2504 token = advancetoken(flib, 0); // Colon
2505 token = advancetoken(flib, ';'); // Read to end of statement
2506 if (!tokencasecmp(token, "positive_unate"))
2507 testpin->sense = SENSE_POSITIVE;
2508 else if (!tokencasecmp(token, "negative_unate"))
2509 testpin->sense = SENSE_NEGATIVE;
2510 else if (!tokencasecmp(token, "non_unate"))
2511 testpin->sense = SENSE_NONE;
2512 }
2513 else if (!strcasecmp(token, "timing_type")) {
2514 token = advancetoken(flib, 0); // Colon
2515 token = advancetoken(flib, ';'); // Read to end of statement
2516
2517 // Note: Timing type is apparently redundant information;
2518 // e.g., "falling_edge" can be determined by "clocked_on : !CLK"
2519 // in the ff {} block. How reliable is this?
2520
2521 if (!tokencasecmp(token, "rising_edge"))
2522 timing_type = TIMING_PROP_TRANS;
2523 else if (!tokencasecmp(token, "falling_edge"))
2524 timing_type = TIMING_PROP_TRANS;
2525 else if (!tokencasecmp(token, "hold_rising"))
2526 timing_type = TIMING_HOLD;
2527 else if (!tokencasecmp(token, "hold_falling"))
2528 timing_type = TIMING_HOLD;
2529 else if (!tokencasecmp(token, "setup_rising"))
2530 timing_type = TIMING_SETUP;
2531 else if (!tokencasecmp(token, "setup_falling"))
2532 timing_type = TIMING_SETUP;
2533 else if (!tokencasecmp(token, "clear"))
2534 timing_type = TIMING_SET_RESET;
2535 else if (!tokencasecmp(token, "preset"))
2536 timing_type = TIMING_SET_RESET;
2537 else if (!tokencasecmp(token, "recovery_rising"))
2538 timing_type = TIMING_RECOVERY;
2539 else if (!tokencasecmp(token, "recovery_falling"))
2540 timing_type = TIMING_RECOVERY;
2541 else if (!tokencasecmp(token, "removal_rising"))
2542 timing_type = TIMING_REMOVAL;
2543 else if (!tokencasecmp(token, "removal_falling"))
2544 timing_type = TIMING_REMOVAL;
2545 else if (!tokencasecmp(token, "three_state_enable"))
2546 timing_type = TIMING_TRISTATE;
2547 else if (!tokencasecmp(token, "three_state_disable"))
2548 timing_type = TIMING_TRISTATE;
2549 }
2550 else if ((!strcasecmp(token, "cell_rise")) ||
2551 (!strcasecmp(token, "cell_fall")) ||
2552 (!strcasecmp(token, "rise_transition")) ||
2553 (!strcasecmp(token, "fall_transition")) ||
2554 (!strcasecmp(token, "rise_constraint")) ||
2555 (!strcasecmp(token, "fall_constraint"))) {
2556
2557 tableptr = (lutable *)malloc(sizeof(lutable));
2558 tableptr->name = NULL; // Not used
2559 tableptr->invert = 0;
2560 tableptr->var1 = UNKNOWN;
2561 tableptr->var2 = UNKNOWN;
2562 tableptr->size1 = 0;
2563 tableptr->size2 = 0;
2564 tableptr->idx1.times = NULL;
2565 tableptr->idx2.caps = NULL;
2566 tableptr->values = NULL;
2567 tableptr->next = NULL; // Not used
2568
2569 // Note that propagation delays (cell rise, cell fall) and
2570 // transition times (rise transition, fall transition) have
2571 // their lookup tables stored in the "related pin" pin record.
2572 // Setup and hold times (rise constraint, fall constraint)
2573 // have their lookup tables stored in the original pin record.
2574 // These should not overlap.
2575
2576 // Recovery and removal tables are not yet handled. . .
2577
2578 if (!strcasecmp(token, "cell_rise"))
2579 testpin->propdelr = tableptr;
2580 else if (!strcasecmp(token, "cell_fall"))
2581 testpin->propdelf = tableptr;
2582 else if (!strcasecmp(token, "rise_transition"))
2583 testpin->transr = tableptr;
2584 else if (!strcasecmp(token, "fall_transition"))
2585 testpin->transf = tableptr;
2586 else if (!strcasecmp(token, "rise_constraint")) {
2587 if (timing_type == TIMING_SETUP)
2588 newpin->propdelr = tableptr;
2589 else if (timing_type == TIMING_HOLD)
2590 newpin->transr = tableptr;
2591 }
2592 else if (!strcasecmp(token, "fall_constraint")) {
2593 if (timing_type == TIMING_SETUP)
2594 newpin->propdelf = tableptr;
2595 else if (timing_type == TIMING_HOLD)
2596 newpin->transf = tableptr;
2597 }
2598
2599 token = advancetoken(flib, 0); // Open parens
2600 if (!strcmp(token, "("))
2601 token = advancetoken(flib, ')');
2602
2603 for (reftable = *tablelist; reftable; reftable = reftable->next)
2604 if (!tokencasecmp(token, reftable->name))
2605 break;
2606 if (reftable == NULL)
2607 fprintf(stderr, "Failed to find a valid table \"%s\"\n",
2608 token);
2609 else {
2610 // Fill in default values from template reftable
2611 tableptr->invert = reftable->invert;
2612 if (reftable->size1 > 0) {
2613 tableptr->var1 = reftable->var1;
2614 tableptr->size1 = reftable->size1;
2615 tableptr->idx1.times = (double *)malloc(tableptr->size1 * sizeof(double));
2616 memcpy(tableptr->idx1.times, reftable->idx1.times,
2617 tableptr->size1 * sizeof(double));
2618 }
2619 if (reftable->size2 > 0) {
2620 tableptr->var2 = reftable->var2;
2621 tableptr->size2 = reftable->size2;
2622 tableptr->idx2.caps = (double *)malloc(tableptr->size2 * sizeof(double));
2623 memcpy(tableptr->idx2.caps, reftable->idx2.caps,
2624 tableptr->size2 * sizeof(double));
2625 }
2626 }
2627
2628 token = advancetoken(flib, 0);
2629 if (strcmp(token, "{"))
2630 fprintf(stderr, "Failed to find start of timing block\n");
2631
2632 while (*token != '}') {
2633 token = advancetoken(flib, 0);
2634 if (!tokencasecmp(token, "index_1")) {
2635 char dnum = ',';
2636
2637 // Local index values override those in the template
2638
2639 token = advancetoken(flib, 0); // Open parens
2640 token = advancetoken(flib, 0); // Quote
2641 if (!strcmp(token, "\""))
2642 token = advancetoken(flib, '\"');
2643
2644 iptr = token;
2645
2646 // Check if table is space or comma separated
2647 if (strchr(iptr, dnum) == NULL)
2648 if (strchr(iptr, ' ') != NULL)
2649 dnum = ' ';
2650
2651 //-------------------------
2652
2653 if (reftable && (reftable->invert == 1)) {
2654 // Entries had better match the ref table
2655 i = 0;
2656 sscanf(iptr, "%lg", &tableptr->idx2.caps[0]);
2657 if (tableptr->var2 == OUTPUT_CAP)
2658 tableptr->idx2.caps[0] *= cap_unit;
2659 else
2660 tableptr->idx2.cons[0] *= time_unit;
2661 while ((iptr = strchr(iptr, dnum)) != NULL) {
2662 iptr++;
2663 i++;
2664 sscanf(iptr, "%lg", &tableptr->idx2.caps[i]);
2665 if (tableptr->var2 == OUTPUT_CAP)
2666 tableptr->idx2.caps[i] *= cap_unit;
2667 else
2668 tableptr->idx2.cons[i] *= time_unit;
2669 }
2670 }
2671 else if (reftable && (reftable->invert == 0)) {
2672 iptr = token;
2673 i = 0;
2674 sscanf(iptr, "%lg", &tableptr->idx1.times[0]);
2675 tableptr->idx1.times[0] *= time_unit;
2676 while ((iptr = strchr(iptr, dnum)) != NULL) {
2677 iptr++;
2678 i++;
2679 sscanf(iptr, "%lg", &tableptr->idx1.times[i]);
2680 tableptr->idx1.times[i] *= time_unit;
2681 }
2682 }
2683
2684 token = advancetoken(flib, ')'); // Close paren
2685 token = advancetoken(flib, ';'); // EOL semicolon
2686 }
2687 else if (!tokencasecmp(token, "index_2")) {
2688 char dnum = ',';
2689
2690 // Local index values override those in the template
2691
2692 token = advancetoken(flib, 0); // Open parens
2693 token = advancetoken(flib, 0); // Quote
2694 if (!strcmp(token, "\""))
2695 token = advancetoken(flib, '\"');
2696
2697 iptr = token;
2698
2699 // Check if table is space or comma separated
2700 if (strchr(iptr, dnum) == NULL)
2701 if (strchr(iptr, ' ') != NULL)
2702 dnum = ' ';
2703
2704 //-------------------------
2705
2706 if (reftable && (reftable->invert == 1)) {
2707 // Entries had better match the ref table
2708 i = 0;
2709 sscanf(iptr, "%lg", &tableptr->idx1.times[0]);
2710 tableptr->idx1.times[0] *= time_unit;
2711 while ((iptr = strchr(iptr, dnum)) != NULL) {
2712 iptr++;
2713 i++;
2714 sscanf(iptr, "%lg", &tableptr->idx1.times[i]);
2715 tableptr->idx1.times[i] *= time_unit;
2716 }
2717 }
2718 else if (reftable && (reftable->invert == 0)) {
2719 iptr = token;
2720 i = 0;
2721 sscanf(iptr, "%lg", &tableptr->idx2.caps[0]);
2722 tableptr->idx2.caps[0] *= cap_unit;
2723 while ((iptr = strchr(iptr, dnum)) != NULL) {
2724 iptr++;
2725 i++;
2726 sscanf(iptr, "%lg", &tableptr->idx2.caps[i]);
2727 tableptr->idx2.caps[i] *= cap_unit;
2728 }
2729 }
2730
2731 token = advancetoken(flib, ')'); // Close paren
2732 token = advancetoken(flib, ';'); // EOL semicolon
2733 }
2734 else if (!tokencasecmp(token, "values")) {
2735 token = advancetoken(flib, 0);
2736 if (strcmp(token, "("))
2737 fprintf(stderr, "Failed to find start of"
2738 " value table\n");
2739 token = advancetoken(flib, ')');
2740
2741 // Parse the string of values and enter it into the
2742 // table "values", which is size size2 x size1
2743
2744 if (reftable && reftable->size1 > 0) {
2745 int locsize2;
2746 locsize2 = (reftable->size2 > 0) ? reftable->size2 : 1;
2747 if (reftable->invert) {
2748 tableptr->values = (double *)malloc(locsize2 *
2749 reftable->size1 * sizeof(double));
2750 iptr = token;
2751 for (i = 0; i < reftable->size1; i++) {
2752 for (j = 0; j < locsize2; j++) {
2753 while (*iptr == ' ' || *iptr == '\"' ||
2754 *iptr == ',' || *iptr == '\\')
2755 iptr++;
2756 sscanf(iptr, "%lg", &gval);
2757 *(tableptr->values + j * reftable->size1
2758 + i) = gval * time_unit;
2759 while (*iptr != ' ' && *iptr != '\"' &&
2760 *iptr != ',' || *iptr == '\\')
2761 iptr++;
2762 }
2763 }
2764 }
2765 else {
2766 tableptr->values = (double *)malloc(locsize2 *
2767 reftable->size1 * sizeof(double));
2768 iptr = token;
2769 for (j = 0; j < locsize2; j++) {
2770 for (i = 0; i < reftable->size1; i++) {
2771 while (*iptr == ' ' || *iptr == '\"' ||
2772 *iptr == ',' || *iptr == '\\')
2773 iptr++;
2774 sscanf(iptr, "%lg", &gval);
2775 *(tableptr->values + j * reftable->size1
2776 + i) = gval * time_unit;
2777 while (*iptr != ' ' && *iptr != '\"' &&
2778 *iptr != ',' || *iptr == '\\')
2779 iptr++;
2780 }
2781 }
2782 }
2783 }
2784
2785 token = advancetoken(flib, 0);
2786 if (strcmp(token, ";"))
2787 fprintf(stderr, "Failed to find end of value table\n");
2788 }
2789 else if (!tokencasecmp(token, "ecsm_waveform")) {
2790 /* Not handled: this takes the form of index_1 */
2791 /* key : value or index_2 key : value and */
2792 /* values key : value. */
2793 token = advancetoken(flib, 0); // Open parens
2794 token = advancetoken(flib, ')'); // Close parens
2795 token = advancetoken(flib, '{'); // Open brace
2796 token = advancetoken(flib, '}'); // Close brace
2797 }
2798 else if (!tokencasecmp(token, "ecsm_capacitance")) {
2799 /* Not handled: this takes the form of index_1 */
2800 /* key : value or index_2 key : value and */
2801 /* values key : value. */
2802 token = advancetoken(flib, 0); // Open parens
2803 token = advancetoken(flib, ')'); // Close parens
2804 token = advancetoken(flib, '{'); // Open brace
2805 token = advancetoken(flib, '}'); // Close brace
2806 }
2807 else if (strcmp(token, "{") && strcmp(token, "}")) {
2808 fprintf(stderr, "Unhandled feature %s at line %d\n",
2809 token, fileCurrentLine);
2810 token = advancetoken(flib, 0);
2811 if (!strcmp(token, "(")) { // Open parens
2812 token = advancetoken(flib, ')'); // Close parens
2813 token = advancetoken(flib, 0);
2814 }
2815 if (!strcmp(token, "{")) // Open brace
2816 token = advancetoken(flib, '}'); // Close brace
2817 }
2818 }
2819 }
2820 else {
2821 // For unhandled tokens, read in tokens. If it is
2822 // a definition or function, read to end-of-line. If
2823 // it is a block definition, read to end-of-block.
2824 while (1) {
2825 token = advancetoken(flib, 0);
2826 if (token == NULL) break;
2827 if (!strcmp(token, ";")) break;
2828 if (!strcmp(token, "\""))
2829 token = advancetoken(flib, '\"');
2830 if (!strcmp(token, "{")) {
2831 token = advancetoken(flib, '}');
2832 break;
2833 }
2834 }
2835 }
2836 break;
2837 }
2838 token = advancetoken(flib, 0);
2839 }
2840 }
2841
2842 /*--------------------------------------------------------------*/
2843 /* Read a verilog netlist and collect information about the */
2844 /* cells instantiated and the network structure */
2845 /*--------------------------------------------------------------*/
2846
2847 void
verilogRead(char * filename,cell * cells,net ** netlist,instance ** instlist,connect ** inputlist,connect ** outputlist,struct hashtable * Nethash)2848 verilogRead(char *filename, cell *cells, net **netlist, instance **instlist,
2849 connect **inputlist, connect **outputlist, struct hashtable *Nethash)
2850 {
2851 struct portrec *port;
2852 struct instance *inst;
2853 struct cellrec *topcell;
2854 struct netrec *net;
2855
2856 connptr newconn, testconn;
2857 instptr newinst;
2858 pinptr testpin;
2859 netptr newnet, testnet;
2860 cellptr testcell;
2861
2862 int vstart, vtarget;
2863
2864 /* Get verilog netlist structure using routines in readverilog.c */
2865 topcell = ReadVerilog(filename);
2866 if (topcell && topcell->name) {
2867 fprintf(stdout, "Parsing module \"%s\"\n", topcell->name);
2868 }
2869
2870 /* Build local connection lists from returned netlist structure */
2871
2872 for (port = topcell->portlist; port; port = port->next) {
2873 testconn = NULL;
2874
2875 // Create a net entry for the input or output, add to the list of nets
2876
2877 net = HashLookup(port->name, &topcell->nets);
2878 if (net->start == 0 && net->end == 0) {
2879 newnet = create_net(netlist);
2880 newnet->name = tokendup(port->name);
2881 HashPtrInstall(newnet->name, newnet, Nethash);
2882
2883 testconn = (connptr)malloc(sizeof(connect));
2884 testconn->refnet = newnet;
2885 testconn->refpin = NULL; // No associated pin
2886 testconn->refinst = NULL; // No associated instance
2887 testconn->tag = NULL;
2888 testconn->metric = -1.0;
2889 testconn->icDelay = 0.0;
2890 testconn->visited = (unsigned char)0;
2891 testconn->prvector = NULL;
2892 testconn->pfvector = NULL;
2893 testconn->trvector = NULL;
2894 testconn->tfvector = NULL;
2895
2896 if (port->direction == PORT_INPUT) { // driver (input)
2897 testconn->next = *inputlist;
2898 *inputlist = testconn;
2899 }
2900 else { // receiver (output)
2901 testconn->next = *outputlist;
2902 *outputlist = testconn;
2903 }
2904 }
2905 else {
2906 vtarget = net->end + ((net->start < net->end) ? 1 : -1);
2907 vstart = net->start;
2908 while (vstart != vtarget) {
2909 newnet = create_net(netlist);
2910 newnet->name = (char *)malloc(strlen(port->name) + 6);
2911 sprintf(newnet->name, "%s[%d]", port->name, vstart);
2912 HashPtrInstall(newnet->name, newnet, Nethash);
2913
2914 vstart += (vtarget > net->end) ? 1 : -1;
2915
2916 testconn = (connptr)malloc(sizeof(connect));
2917 testconn->refnet = newnet;
2918 testconn->refpin = NULL; // No associated pin
2919 testconn->refinst = NULL; // No associated instance
2920 testconn->tag = NULL;
2921 testconn->metric = -1.0;
2922 testconn->icDelay = 0.0;
2923 testconn->visited = (unsigned char)0;
2924 testconn->prvector = NULL;
2925 testconn->pfvector = NULL;
2926 testconn->trvector = NULL;
2927 testconn->tfvector = NULL;
2928
2929 if (port->direction == PORT_INPUT) { // driver (input)
2930 testconn->next = *inputlist;
2931 *inputlist = testconn;
2932 }
2933 else { // receiver (output)
2934 testconn->next = *outputlist;
2935 *outputlist = testconn;
2936 }
2937 }
2938 }
2939 }
2940
2941 for (inst = topcell->instlist; inst; inst = inst->next) {
2942 for (testcell = cells; testcell; testcell = testcell->next)
2943 if (!strcasecmp(testcell->name, inst->cellname))
2944 break;
2945
2946 // NOTE: testcell may be NULL for non-functional cells like
2947 // filler cells which have no I/O and so have no timing. Only
2948 // report cells that are relevant to timing and do not show up
2949 // in the liberty database (portlist is non-NULL).
2950
2951 if ((testcell == NULL) && (inst->portlist != NULL)) {
2952 fprintf(stderr, "Cell \"%s\" was not in the liberty database!\n",
2953 inst->cellname);
2954 continue;
2955 }
2956
2957 newinst = (instptr)malloc(sizeof(instance));
2958 newinst->next = *instlist;
2959 *instlist = newinst;
2960 newinst->refcell = testcell;
2961 newinst->in_connects = NULL;
2962 newinst->out_connects = NULL;
2963 newinst->name = tokendup(inst->instname);
2964
2965 for (port = inst->portlist; port; port = port->next) {
2966 newconn = (connptr)malloc(sizeof(connect));
2967 for (testpin = testcell->pins; testpin; testpin = testpin->next) {
2968 if (!strcmp(testpin->name, port->name))
2969 break;
2970 }
2971 // Sanity check
2972 if (testpin == NULL) {
2973 fprintf(stderr, "No such pin \"%s\" in cell \"%s\"!\n",
2974 port->name, testcell->name);
2975 }
2976 else {
2977 if (testpin->type & OUTPUT) {
2978 newconn->next = newinst->out_connects;
2979 newinst->out_connects = newconn;
2980 }
2981 else {
2982 newconn->next = newinst->in_connects;
2983 newinst->in_connects = newconn;
2984 }
2985 }
2986 newconn->refinst = newinst;
2987 newconn->refpin = testpin;
2988 newconn->refnet = NULL;
2989 newconn->tag = NULL;
2990 newconn->metric = -1.0;
2991 newconn->icDelay = 0.0;
2992 newconn->visited = (unsigned char)0;
2993 newconn->prvector = NULL;
2994 newconn->pfvector = NULL;
2995 newconn->trvector = NULL;
2996 newconn->tfvector = NULL;
2997
2998 testnet = (netptr)HashLookup(port->net, Nethash);
2999 if (testnet == NULL) {
3000 // This is a new net, and we need to record it
3001 newnet = create_net(netlist);
3002 newnet->name = tokendup(port->net);
3003 HashPtrInstall(newnet->name, newnet, Nethash);
3004 newconn->refnet = newnet;
3005 }
3006 else
3007 newconn->refnet = testnet;
3008 }
3009 }
3010 FreeVerilog(topcell); // All structures transferred
3011 }
3012
3013 /*--------------------------------------------------------------*/
3014 /* For each net, go through the list of receivers and add the */
3015 /* contributions of each to the total load. This is either */
3016 /* the input pin capacitance, if the receiver is a pin, or the */
3017 /* designated output load (given on the command line), if the */
3018 /* receiver is an output pin. */
3019 /*--------------------------------------------------------------*/
3020
3021 void
computeLoads(netptr netlist,instptr instlist,double out_load)3022 computeLoads(netptr netlist, instptr instlist, double out_load)
3023 {
3024 instptr testinst;
3025 pinptr testpin;
3026 netptr testnet, driver, loadnet;
3027 connptr testconn;
3028 int i;
3029
3030 for (testnet = netlist; testnet; testnet = testnet->next) {
3031 for (i = 0; i < testnet->fanout; i++) {
3032 testconn = testnet->receivers[i];
3033 testpin = testconn->refpin;
3034 if (testpin == NULL) {
3035 testnet->loadr += out_load;
3036 testnet->loadf += out_load;
3037 }
3038 else {
3039 testnet->loadr += testpin->capr;
3040 testnet->loadf += testpin->capf;
3041 }
3042 }
3043 }
3044
3045 // For each instance input pin, collapse the pin's lookup table
3046 // to a vector by interpolating/extrapolating the table at the
3047 // calculated output load. Save this vector in the connection
3048 // record for the pin.
3049
3050 for (testinst = instlist; testinst; testinst = testinst->next) {
3051 double loadr, loadf;
3052 if (testinst->out_connects != NULL) {
3053 loadnet = testinst->out_connects->refnet;
3054 loadr = loadnet->loadr;
3055 loadf = loadnet->loadf;
3056 }
3057 else {
3058 loadr = 0.0;
3059 loadf = 0.0;
3060 }
3061
3062 for (testconn = testinst->in_connects; testconn; testconn = testconn->next) {
3063 testpin = testconn->refpin;
3064
3065 if (testpin->propdelr)
3066 testconn->prvector = table_collapse(testpin->propdelr, loadr);
3067 if (testpin->propdelf)
3068 testconn->pfvector = table_collapse(testpin->propdelf, loadf);
3069 if (testpin->transr)
3070 testconn->trvector = table_collapse(testpin->transr, loadr);
3071 if (testpin->transf)
3072 testconn->tfvector = table_collapse(testpin->transf, loadf);
3073 }
3074 }
3075 }
3076
3077 /*--------------------------------------------------------------*/
3078 /* Assign types to each net. This identifies which nets are */
3079 /* clock inputs, which are latch enable inputs, and which are */
3080 /* asynchronous set/reset inputs,. */
3081 /* */
3082 /* Whenever a clock input to a flop is found, add the */
3083 /* connection record to clockedlist */
3084 /* */
3085 /* For diagnostics, return the number of entries in clockedlist */
3086 /*--------------------------------------------------------------*/
3087
assign_net_types(netptr netlist,connlistptr * clockedlist)3088 int assign_net_types(netptr netlist, connlistptr *clockedlist)
3089 {
3090 int i, numterms;
3091 netptr testnet;
3092 connptr testrcvr;
3093 pinptr testpin;
3094 connlistptr newclocked;
3095
3096 numterms = 0;
3097
3098 for (testnet = netlist; testnet; testnet = testnet->next) {
3099 /* Nets with no fanout are by definition module outputs */
3100 if (testnet->fanout == 0) testnet->type |= OUTTERM;
3101 for (i = 0; i < testnet->fanout; i++) {
3102 testrcvr = testnet->receivers[i];
3103 testpin = testrcvr->refpin;
3104 if (testpin == NULL)
3105 testnet->type |= OUTTERM;
3106 else {
3107 switch (testpin->type & (DFFMASK | LATCHMASK)) {
3108 case DFFCLK:
3109 testnet->type |= CLOCK;
3110 newclocked = (connlistptr)malloc(sizeof(connlist));
3111 newclocked->connection = testrcvr;
3112 newclocked->next = *clockedlist;
3113 *clockedlist = newclocked;
3114 numterms++;
3115 break;
3116 case DFFIN:
3117 testnet->type |= TERMINAL;
3118 break;
3119 case DFFSET:
3120 case DFFRST:
3121 testnet->type |= ASYNC;
3122 break;
3123 case LATCHIN:
3124 testnet->type |= LATCHTERM;
3125 break;
3126 case LATCHEN:
3127 testnet->type |= ENABLE;
3128 break;
3129 }
3130 }
3131 }
3132 }
3133 return numterms;
3134 }
3135
3136 /*--------------------------------------------------------------*/
3137 /* Create the links representing the netlist connections. */
3138 /* */
3139 /* The verilogRead() routine added all nets and instances, and */
3140 /* for each instance, generated a list of net connections to */
3141 /* each pin. To make the netlist easily traversible, this */
3142 /* routine does the following: */
3143 /* */
3144 /* For each instance, work through the list of pin */
3145 /* connections. If the pin is an output, then add the */
3146 /* connection as the net's driver entry. If the pin is */
3147 /* an input, then add the connection to the list of the */
3148 /* net's receivers, and increment the net's fanout. */
3149 /* */
3150 /* For each module input, add the input connection as the */
3151 /* net's driver (flag an error if the net already has a */
3152 /* driver). */
3153 /* */
3154 /* For each module output, add the output connection as one of */
3155 /* the net's receivers (it may be the only one). */
3156 /* */
3157 /*--------------------------------------------------------------*/
3158
3159 void
createLinks(netptr netlist,instptr instlist,connptr inputlist,connptr outputlist)3160 createLinks(netptr netlist, instptr instlist, connptr inputlist, connptr outputlist)
3161 {
3162 netptr testnet;
3163 instptr testinst;
3164 connptr testconn;
3165
3166 for (testinst = instlist; testinst; testinst = testinst->next) {
3167 for (testconn = testinst->in_connects; testconn; testconn = testconn->next) {
3168 testnet = testconn->refnet;
3169 testnet->fanout++;
3170 if (testnet->receivers == NULL)
3171 testnet->receivers = (connptr *)malloc(sizeof(connptr));
3172
3173 else
3174 testnet->receivers = (connptr *)realloc(testnet->receivers,
3175 testnet->fanout * sizeof(connptr));
3176
3177 testnet->receivers[testnet->fanout - 1] = testconn;
3178 }
3179
3180 for (testconn = testinst->out_connects; testconn; testconn = testconn->next) {
3181 testnet = testconn->refnet;
3182 testnet->driver = testconn;
3183 }
3184 }
3185
3186 for (testconn = inputlist; testconn; testconn = testconn->next) {
3187 testnet = testconn->refnet;
3188 if (testnet->driver != NULL)
3189 fprintf(stderr, "Error: Input pin \"%s\" has an internal driver!\n",
3190 testnet->name);
3191 // else
3192 // testnet->driver = testconn; // Don't do this, makes connectivity circular
3193 }
3194
3195 for (testconn = outputlist; testconn; testconn = testconn->next) {
3196 testnet = testconn->refnet;
3197 testnet->fanout++;
3198 if (testnet->receivers == NULL)
3199 testnet->receivers = (connptr *)malloc(sizeof(connptr));
3200
3201 else
3202 testnet->receivers = (connptr *)realloc(testnet->receivers,
3203 testnet->fanout * sizeof(connptr));
3204
3205 testnet->receivers[testnet->fanout - 1] = testconn;
3206 }
3207 }
3208
3209 /*--------------------------------------------------------------*/
3210 /* Delay comparison used by qsort() to sort paths in order from */
3211 /* longest to shortest propagation delay. */
3212 /*--------------------------------------------------------------*/
3213
3214 int
compdelay(ddataptr * a,ddataptr * b)3215 compdelay(ddataptr *a, ddataptr *b)
3216 {
3217 ddataptr p = *a;
3218 ddataptr q = *b;
3219
3220 if (p->delay < q->delay)
3221 return (1);
3222 if (p->delay > q->delay)
3223 return (-1);
3224 return (0);
3225 }
3226
3227 void
delayRead(FILE * fdly,struct hashtable * Nethash)3228 delayRead(FILE *fdly, struct hashtable *Nethash)
3229 {
3230 char c[128];
3231 char d[128];
3232 char *token;
3233 char *result;
3234 char *tokencopy = NULL;
3235
3236 netptr newnet, testnet;
3237 connptr testconn;
3238 pinptr testpin;
3239 int i;
3240 int numRxers;
3241
3242 if (debug == 1)
3243 fprintf(stdout, "delayRead\n");
3244
3245 /* NOTE: Do not use 0 for delimiter, or else ':' is considered to */
3246 /* be a standard delimiter, breaking up certain yosys-generated */
3247 /* net names. */
3248
3249 token = advancetokennocont(fdly, '\n');
3250 result = token;
3251
3252 while (token != NULL) {
3253
3254 char *saveptr;
3255 char *saveptr2;
3256
3257 numRxers = 0;
3258 testnet = (netptr)HashLookup(token, Nethash);
3259
3260 /* Syntax cleanup for net renaming between various */
3261 /* netlist formats. */
3262
3263 if ((testnet == NULL) && cleanup) {
3264 char *mchr, *dchr;
3265 /* Handle the insane backslash-escape names in verilog.
3266 * To make these compatible with SPICE, qflow opts to
3267 * replace the ending space character with another
3268 * backslash. The 2nd backslash has to be replaced by
3269 * the original space character to match the original
3270 * verilog net name.
3271 */
3272
3273 if (*token == '\\') {
3274 if ((mchr = strchr(token + 1, '\\')) != NULL) {
3275 dchr = strchr(token + 1, ' ');
3276 if ((dchr == NULL) || (dchr > mchr)) *mchr = ' ';
3277 }
3278 }
3279 testnet = (netptr)HashLookup(token, Nethash);
3280
3281 /* Other, legacy stuff. */
3282 if (testnet == NULL) {
3283 tokencopy = strdup(token);
3284 if ((mchr = strrchr(tokencopy, '<')) != NULL) {
3285 if ((dchr = strrchr(tokencopy, '>')) != NULL) {
3286 if (mchr < dchr) {
3287 *mchr = '[';
3288 *dchr = ']';
3289 }
3290 }
3291 }
3292 testnet = (netptr)HashLookup(tokencopy, Nethash);
3293 }
3294
3295 if (testnet == NULL) {
3296 for (mchr = tokencopy; *mchr != '\0'; mchr++) {
3297 if ((*mchr == ':') || (*mchr == '.') || (*mchr == '$')
3298 || (*mchr == '<') || (*mchr == '>'))
3299 *mchr = '_';
3300 }
3301 testnet = (netptr)HashLookup(tokencopy, Nethash);
3302 }
3303
3304 if (testnet == NULL) {
3305 for (mchr = tokencopy; *mchr != '\0'; mchr++) {
3306 if ((*mchr == '[') || (*mchr == ']'))
3307 *mchr = '_';
3308 }
3309 testnet = (netptr)HashLookup(tokencopy, Nethash);
3310 }
3311 }
3312 if (tokencopy != NULL) free(tokencopy);
3313
3314 if (testnet == NULL) {
3315 fprintf(stderr, "ERROR: Net %s not found in hash table\n", token);
3316 exit(-1);
3317 }
3318
3319 // Read driver of interconnect and total interconnect capacitance
3320 result = fgets(c, 128, fdly);
3321 if (result == NULL) break;
3322
3323 strtok_r(c, "/", &saveptr);
3324 if (debug == 1)
3325 fprintf(stdout, "\tDriver Inst: %s\n", saveptr);
3326 strtok_r(NULL, " ", &saveptr);
3327 if (debug == 1) {
3328 fprintf(stdout, "\tDriver Pin: %s\n", saveptr);
3329 fprintf(stdout, "\tTotC: %f\n", strtof(saveptr, NULL));
3330 }
3331
3332 if (c[1] == '\0') {
3333 fprintf(stderr, "ERROR: Driver not found for net %s\n", testnet->name);
3334 }
3335
3336 /* Load in .dly file is in pF, but we keep fF in loadr/loadf */
3337 testnet->loadr = (strtod(saveptr, NULL)) * 1e3;
3338 testnet->loadf = testnet->loadr;
3339
3340 result = fgets(c, 128, fdly);
3341 if (result == NULL) break;
3342
3343 while (c[0] != '\n') {
3344 if (debug == 1) fprintf(stdout, "\t%s\n", c);
3345
3346 //separate receiver name and delay value
3347 strtok_r(c, " ", &saveptr);
3348 if (debug == 1) {
3349 fprintf(stdout, "\tDelay: %s\n", saveptr);
3350 fprintf(stdout, "\tRxer Name: %s\n", c);
3351 }
3352 strtok_r(c, "/", &saveptr2);
3353 if (debug == 1) {
3354 fprintf(stdout, "\tRxer Name: %s\n", c);
3355 fprintf(stdout, "\tRxer Name: %s\n", saveptr2);
3356 fprintf(stdout, "\tDelay: %f\n", strtof(saveptr, NULL));
3357 }
3358
3359 for (i = 0; i < testnet->fanout; i++) {
3360
3361 testconn = testnet->receivers[i];
3362
3363 if (testnet->type == OUTTERM) {
3364 if (debug == 1)
3365 fprintf(stdout, "\tNet connects to output and has no "
3366 "receiving instance pin\n");
3367 testconn->icDelay = strtod(saveptr, NULL);
3368 } else {
3369 if (debug == 1)
3370 fprintf(stdout, "\trefinstname: %s\n", testconn->refinst->name);
3371
3372 if (!strcmp(testconn->refinst->name, c)) {
3373
3374 testconn->icDelay = strtod(saveptr, NULL);
3375 break;
3376 }
3377 }
3378 if (debug == 1)
3379 fprintf(stdout, "\tName: %s\n", c);
3380 }
3381
3382 result = fgets(c, 128, fdly);
3383 if (result == NULL) break;
3384 numRxers += 1;
3385 }
3386 if (result == NULL) break;
3387
3388 if (numRxers != testnet->fanout) {
3389 if (numRxers != 1 || testnet->fanout > 0 || testnet->type != OUTTERM)
3390 fprintf(stderr, "ERROR: Net %s had %d receiver%s in delay file, "
3391 " but expected a fanout of %d\n", testnet->name,
3392 numRxers, (numRxers == 1) ? "" : "s",
3393 testnet->fanout);
3394 }
3395
3396 token = advancetokennocont(fdly, '\n');
3397 }
3398 if (result == NULL) {
3399 fprintf(stderr, "ERROR: Unexpected end-of-file while reading delay file.\n");
3400 }
3401 }
3402
3403 /*--------------------------------------------------------------*/
3404 /* Print a path component */
3405 /* (code contributed by Karl-Filip Faxen) */
3406 /*--------------------------------------------------------------*/
3407
3408 void
print_path_component(int netFWidth,int instFWidth,int pinFWidth,int recvFWidth,btptr backtrace,FILE * file)3409 print_path_component(int netFWidth, int instFWidth, int pinFWidth, int recvFWidth,
3410 btptr backtrace, FILE *file)
3411 {
3412 // Return immediately if we have niether a driver or a receiver instance
3413 if (backtrace->receiver->refnet->driver == NULL &&
3414 backtrace->receiver->refinst == NULL) return;
3415
3416 fprintf(file, " %8.1f ps", backtrace->delay);
3417 if (backtrace->receiver->refnet != NULL) {
3418 netptr net = backtrace->receiver->refnet;
3419 fprintf(file, " %*s: ", netFWidth, net->name);
3420 if (net->driver != NULL) { // If the driver exists, it has a refinst
3421 fprintf(file, "%*s/%*s",
3422 instFWidth, net->driver->refinst->name,
3423 -pinFWidth, net->driver->refpin->name);
3424 }
3425 else {
3426 fprintf(file, "%*s", instFWidth + pinFWidth + 1, "");
3427 }
3428 }
3429 fprintf(file, " -> ");
3430 if (backtrace->receiver->refinst != NULL) {
3431 fprintf(file, "%*s/%s",
3432 recvFWidth, backtrace->receiver->refinst->name,
3433 backtrace->receiver->refpin->name);
3434 }
3435 else if (backtrace->receiver->refnet)
3436 fprintf(file, "%s", backtrace->receiver->refnet->name);
3437
3438 fprintf(file, "\n");
3439 }
3440
3441 /*--------------------------------------------------------------*/
3442 /* Print a path */
3443 /* (code contributed by Karl-Filip Faxen) */
3444 /*--------------------------------------------------------------*/
3445
3446 void
print_path(btptr backtrace,FILE * file)3447 print_path(btptr backtrace, FILE *file)
3448 {
3449 int netFWidth = 0;
3450 int instFWidth = 0;
3451 int pinFWidth = 0;
3452 int recvFWidth = 0;
3453 btptr curr = backtrace, prev = NULL;
3454
3455 // The back trace is last entry first, so we do one pointer reversal to
3456 // get it in first entry first order, then we reverse it back again.
3457
3458 while (curr != NULL) {
3459 // Find max length of net name, inst name and pin name
3460 netptr net = curr->receiver->refnet;
3461 if (net != NULL) {
3462 int namelen = strlen(net->name);
3463 if (namelen > netFWidth) netFWidth = namelen;
3464 if (net->driver != NULL) { // If driver exists, it has an instance
3465 int instlen = strlen(net->driver->refinst->name);
3466 if (instlen > instFWidth) instFWidth = instlen;
3467 int pinlen = strlen(net->driver->refpin->name);
3468 if (pinlen > pinFWidth) pinFWidth = pinlen;
3469 }
3470 }
3471 // Find max length of receiving inst name
3472 if (curr->receiver->refinst != NULL) {
3473 int instlen = strlen(curr->receiver->refinst->name);
3474 if (instlen > recvFWidth) recvFWidth = instlen;
3475 }
3476 // Do the first pointer reversal
3477 btptr tmp = curr->next;
3478 curr->next = prev;
3479 prev = curr;
3480 curr = tmp;
3481 }
3482
3483 curr = prev;
3484 prev = NULL;
3485
3486 while (curr != NULL) {
3487 print_path_component(netFWidth, instFWidth, pinFWidth, recvFWidth, curr, file);
3488 // Do the second pointer reversal
3489 btptr tmp = curr->next;
3490 curr->next = prev;
3491 prev = curr;
3492 curr = tmp;
3493 }
3494 fprintf(file, "\n");
3495 }
3496
3497 /*--------------------------------------------------------------*/
3498 /* Given a list of paths, find the clock at the source and the */
3499 /* destination (if neither is a pin), and compute the clock */
3500 /* skew between them. Also compute the setup or hold at the */
3501 /* destination. Save these values in the path record. */
3502 /*--------------------------------------------------------------*/
3503
3504 void
find_clock_skews(ddataptr pathlist,char minmax)3505 find_clock_skews(ddataptr pathlist, char minmax)
3506 {
3507 connptr testconn, thisconn;
3508 instptr testinst;
3509
3510 ddataptr testddata, srcddata, freeddata;
3511 ddataptr clocklist, clock2list;
3512 btptr backtrace, freebt, pathbt, btcommon;
3513 btptr selectedsource, selecteddest;
3514
3515 short srcdir, destdir; // Signal direction in/out
3516 double setupdelay, holddelay;
3517 unsigned char result;
3518 char clk_invert, clk_sense_inv;
3519
3520 clocklist = NULL;
3521 clock2list = NULL;
3522
3523 for (testddata = pathlist; testddata; testddata = testddata->next) {
3524
3525 // Find the end of the linked list, which is the path start.
3526 for (pathbt = testddata->backtrace; pathbt->next; pathbt = pathbt->next);
3527 thisconn = pathbt->receiver;
3528
3529 if (thisconn && thisconn->refpin) {
3530 // Find the sources of the clock at the path start. Create
3531 // a tree of backtraces from thisconn to all clock sources,
3532 // and return clocklist, which is a list of the sources.
3533
3534 find_clock_source(thisconn, &clocklist, NULL, srcdir, (unsigned char)1);
3535
3536 // Calculate the worst-case transition times to testlink on
3537 // each clocklist backtrace.
3538
3539 find_clock_transition(clocklist, thisconn, srcdir, minmax,
3540 (unsigned char)1);
3541 }
3542
3543 // Copy last backtrace delay to testddata.
3544 testddata->delay = testddata->backtrace->delay;
3545 testddata->trans = testddata->backtrace->trans;
3546 testinst = testddata->backtrace->receiver->refinst;
3547 selecteddest = selectedsource = NULL;
3548
3549 if (testinst != NULL) {
3550 // Find the sources of the clock at the path end
3551 destdir = (testinst->refcell->type & CLK_SENSE_MASK) ? FALLING : RISING;
3552 testconn = find_register_clock(testinst);
3553 // If testconn is NULL, this is not a register (latch, maybe?)
3554 if (testconn == NULL) continue;
3555
3556 // Find the connection that is common to both clocks
3557 result = find_clock_source(testconn, &clock2list, NULL, destdir,
3558 (unsigned char)2);
3559
3560 if ((result == (unsigned char)0) && (clocklist != NULL)) {
3561 // If both paths end on the same input net, then there
3562 // is no connection pointer, so deal with that separately.
3563
3564 if (clocklist->backtrace->receiver->refnet !=
3565 clock2list->backtrace->receiver->refnet) {
3566
3567 // Warn about asynchronous clock sources
3568 if (verbose > 1) {
3569 fflush(stdout);
3570 fprintf(stderr, "Independent clock nets \"%s\" and \"%s\""
3571 " drive related gates!\n",
3572 testconn->refnet->name,
3573 thisconn->refnet->name);
3574 }
3575 clk_invert = -1;
3576 }
3577 }
3578
3579 // If clocklist is NULL then this is an input and there is
3580 // no way to compute relative to a common clock, because
3581 // there is no common clock.
3582
3583 if (clocklist != NULL) {
3584 // Find clock arrival times from common clock point. Note that
3585 // the check is opposite to what is computed for the source; if
3586 // maximum time was used to find clock-to-source, then minimum
3587 // time is used to find clock-to-destination.
3588
3589 btcommon = find_common_clock(clock2list, clocklist);
3590 find_clock_transition(clock2list, testconn,
3591 (btcommon) ? btcommon->dir : RISING,
3592 ~minmax, (unsigned char)2);
3593
3594 // selectedsource is the end of the btcommon backtrace
3595 for (selectedsource = (btcommon) ? btcommon : clocklist->backtrace;
3596 selectedsource->next;
3597 selectedsource = selectedsource->next);
3598 // selecteddest is the end of the clock2list backtrace
3599 for (selecteddest = clock2list->backtrace; selecteddest->next;
3600 selecteddest = selecteddest->next);
3601
3602 // Add or subtract difference in arrival times between source and
3603 // destination clocks
3604
3605 testddata->skew = selectedsource->delay - selecteddest->delay -
3606 ((btcommon) ? btcommon->delay : 0.0);
3607 testddata->delay += testddata->skew;
3608 }
3609 else if (clock2list) {
3610 // Still need to know destination's clock source to
3611 // calculate setup or hold time.
3612 for (selecteddest = clock2list->backtrace; selecteddest->next;
3613 selecteddest = selecteddest->next);
3614 testddata->skew = 0.0;
3615 }
3616
3617 if (minmax == MAXIMUM_TIME) {
3618 // Add setup time for destination clocks
3619 setupdelay = calc_setup_time(testddata->trans,
3620 testddata->backtrace->receiver->refpin,
3621 selecteddest->trans,
3622 testddata->backtrace->dir, minmax);
3623 testddata->setup = setupdelay;
3624 }
3625 else {
3626 // Subtract hold time for destination clocks (note that hold times
3627 // are defined as typically negative values in the liberty format)
3628 holddelay = calc_hold_time(testddata->trans,
3629 testddata->backtrace->receiver->refpin,
3630 selecteddest->trans,
3631 testddata->backtrace->dir, minmax);
3632 testddata->setup = holddelay;
3633 }
3634 testddata->delay += testddata->setup;
3635
3636 if (verbose > 1)
3637 fprintf(stdout, "Path terminated on flop \"%s\" input with max delay %g ps\n",
3638 testconn->refinst->name, testddata->delay);
3639
3640 for (backtrace = testddata->backtrace; backtrace->next;
3641 backtrace = backtrace->next) {
3642 if (verbose > 1)
3643 fprintf(stdout, " %g (%s) %s/%s -> %s/%s\n",
3644 backtrace->delay,
3645 backtrace->receiver->refnet->name,
3646 backtrace->receiver->refnet->driver->refinst->name,
3647 backtrace->receiver->refnet->driver->refpin->name,
3648 backtrace->receiver->refinst->name,
3649 backtrace->receiver->refpin->name);
3650 }
3651 if (verbose > 1)
3652 fprintf(stdout, " 000.000 (%s) %s/%s -> %s/%s\n",
3653 backtrace->receiver->refnet->name,
3654 backtrace->receiver->refinst->name,
3655 backtrace->receiver->refpin->name,
3656 backtrace->receiver->refinst->name,
3657 backtrace->receiver->refinst->out_connects->refpin->name);
3658
3659 if (selecteddest != NULL && selectedsource != NULL) {
3660 if (verbose > 1) {
3661 if (selectedsource->receiver->refnet != selecteddest->receiver->refnet) {
3662 fprintf(stdout, " %g %s to %s clock skew\n",
3663 selecteddest->delay - selectedsource->delay
3664 + ((btcommon) ? btcommon->delay : 0.0),
3665 selectedsource->receiver->refnet->name,
3666 selecteddest->receiver->refnet->name);
3667 }
3668 }
3669
3670 /* Check if the flops have the same clock sense */
3671 /* (both are clock rising edge or both are clock falling edge type) */
3672
3673 if (backtrace->receiver->refinst == NULL)
3674 clk_sense_inv = 1;
3675 else if ((testinst->refcell->type & CLK_SENSE_MASK) !=
3676 (backtrace->receiver->refinst->refcell->type
3677 & CLK_SENSE_MASK))
3678 clk_sense_inv = 1;
3679 else
3680 clk_sense_inv = 0;
3681
3682 /* If the two flops don't clock at the same time, then issue a */
3683 /* warning that the slack time loses half a clock period. */
3684
3685 if ((verbose > 1) && (clk_invert != -1) && (clk_sense_inv != clk_invert)) {
3686 fprintf(stdout, " Clocks are inverted relative to one another,\n");
3687 fprintf(stdout, " implying a maximum propagation delay of 1/2 period.\n");
3688 }
3689 }
3690 if (thisconn != NULL && testconn != NULL) {
3691 if (verbose > 1) {
3692 if (minmax == MAXIMUM_TIME)
3693 fprintf(stdout, " %g setup time at destination\n", setupdelay);
3694 else
3695 fprintf(stdout, " %g hold time at destination\n", holddelay);
3696 }
3697 }
3698
3699 if (verbose > 1) fprintf(stdout, "\n");
3700 }
3701 else if (verbose > 1) {
3702 fprintf(stdout, "Path terminated on output \"%s\" with max delay %g ps\n",
3703 testddata->backtrace->receiver->refnet->name, testddata->delay);
3704
3705 backtrace = testddata->backtrace;
3706 fprintf(stdout, " %g (%s) %s/%s -> [output pin]\n",
3707 backtrace->delay,
3708 backtrace->receiver->refnet->name,
3709 backtrace->receiver->refnet->driver->refinst->name,
3710 backtrace->receiver->refnet->driver->refpin->name);
3711
3712 for (backtrace = backtrace->next; backtrace->next; backtrace = backtrace->next) {
3713 fprintf(stdout, " %g (%s) %s/%s -> %s/%s\n",
3714 backtrace->delay,
3715 backtrace->receiver->refnet->name,
3716 backtrace->receiver->refnet->driver->refinst->name,
3717 backtrace->receiver->refnet->driver->refpin->name,
3718 backtrace->receiver->refinst->name,
3719 backtrace->receiver->refpin->name);
3720 }
3721 fprintf(stdout, " 000.000 (%s) %s/%s -> %s/%s\n\n",
3722 backtrace->receiver->refnet->name,
3723 backtrace->receiver->refinst->name,
3724 backtrace->receiver->refpin->name,
3725 backtrace->receiver->refinst->name,
3726 backtrace->receiver->refinst->out_connects->refpin->name);
3727 }
3728
3729 // Clean up clock2list backtraces
3730 for (freeddata = clock2list; freeddata; freeddata = freeddata->next) {
3731 while (freeddata->backtrace != NULL) {
3732 freebt = freeddata->backtrace;
3733 testconn = freebt->receiver;
3734 freeddata->backtrace = freeddata->backtrace->next;
3735 freebt->refcnt--;
3736 if (freebt->refcnt == 0) free(freebt);
3737 else break;
3738 if (testconn->visited != (unsigned char)2)
3739 break;
3740 testconn->visited = (unsigned char)0;
3741 }
3742 }
3743
3744 // Clean up clock2list
3745 while (clock2list != NULL) {
3746 freeddata = clock2list;
3747 clock2list = clock2list->next;
3748 free(freeddata);
3749 }
3750
3751 // Free up clocklist backtraces
3752 for (freeddata = clocklist; freeddata; freeddata = freeddata->next) {
3753 while (freeddata->backtrace != NULL) {
3754 freebt = freeddata->backtrace;
3755 testconn = freebt->receiver;
3756 freeddata->backtrace = freeddata->backtrace->next;
3757 freebt->refcnt--;
3758 if (freebt->refcnt == 0) free(freebt);
3759 else break;
3760 if (testconn->visited != (unsigned char)1)
3761 break;
3762 testconn->visited = (unsigned char)0;
3763 }
3764 }
3765
3766 // Free up clocklist
3767 while (clocklist != NULL) {
3768 freeddata = clocklist;
3769 clocklist = clocklist->next;
3770 free(freeddata);
3771 }
3772 }
3773 }
3774
3775 /*--------------------------------------------------------------*/
3776 /* Main program */
3777 /*--------------------------------------------------------------*/
3778
3779 int
main(int objc,char * argv[])3780 main(int objc, char *argv[])
3781 {
3782 FILE *flib;
3783 FILE *fsrc;
3784 FILE *fdly;
3785 FILE *fsum;
3786 double period = 0.0;
3787 double outLoad = 0.0;
3788 double inTrans = 0.0;
3789 char *delayfile = NULL;
3790 char *summaryfile = NULL;
3791 char *summarydir = NULL;
3792 int ival, firstarg = 1;
3793 int longFormat = 0; // Is the long format option present
3794 int numReportPaths = 20;
3795
3796 // Liberty database
3797
3798 lutable *tables = NULL;
3799 cell *cells = NULL;
3800 lutable *scalar;
3801
3802 // Verilog netlist database
3803
3804 instptr instlist = NULL;
3805 netptr netlist = NULL;
3806 connlistptr clockconnlist = NULL;
3807 connlistptr newinputconn, inputconnlist = NULL;
3808 connptr testconn, inputlist = NULL;
3809 connptr outputlist = NULL;
3810
3811 // Timing path database
3812 ddataptr pathlist = NULL;
3813 ddataptr freeddata, testddata, *orderedpaths;
3814 btptr freebt, testbt;
3815 int numpaths, numterms, i;
3816 char badtiming;
3817 double slack;
3818
3819 // Net name hash table
3820 struct hashtable Nethash;
3821
3822 verbose = 0;
3823 exhaustive = 0;
3824 cleanup = 0;
3825
3826 while ((firstarg < objc) && (*argv[firstarg] == '-')) {
3827 if (!strcmp(argv[firstarg], "-d") || !strcmp(argv[firstarg], "--delay")) {
3828 delayfile = strdup(argv[firstarg + 1]);
3829 firstarg += 2;
3830 }
3831 else if (!strcmp(argv[firstarg], "-p") || !strcmp(argv[firstarg], "--period")) {
3832 period = strtod(argv[firstarg + 1], NULL);
3833 firstarg += 2;
3834 }
3835 else if (!strcmp(argv[firstarg], "-l") || !strcmp(argv[firstarg], "--load")) {
3836 outLoad = strtod(argv[firstarg + 1], NULL);
3837 firstarg += 2;
3838 }
3839 else if (!strcmp(argv[firstarg], "-t") || !strcmp(argv[firstarg], "--trans")) {
3840 inTrans = strtod(argv[firstarg + 1], NULL);
3841 firstarg += 2;
3842 }
3843 else if (!strcmp(argv[firstarg], "-L") || !strcmp(argv[firstarg], "--long")) {
3844 longFormat = 1;
3845 firstarg++;
3846 }
3847 else if (!strcmp(argv[firstarg], "-n") || !strcmp(argv[firstarg], "--num-paths")) {
3848 numReportPaths = strtod(argv[firstarg + 1], NULL);
3849 firstarg += 2;
3850 }
3851 else if (!strcmp(argv[firstarg], "-s") || !strcmp(argv[firstarg], "--summary")) {
3852 summaryfile = strdup(argv[firstarg + 1]);
3853 /* Rule: If argument has a file extension, then treat it as a single */
3854 /* file and dump all output to it. If not, then treat it as a */
3855 /* directory and create individual files for each timing check. */
3856 if (strrchr(summaryfile, '.') == NULL) {
3857 summarydir = summaryfile;
3858 summaryfile = NULL;
3859 /* Make directory if it doesn't exist */
3860 mkdir(summarydir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
3861 }
3862 firstarg += 2;
3863 }
3864 else if (!strcmp(argv[firstarg], "-v") || !strcmp(argv[firstarg], "--verbose")) {
3865 sscanf(argv[firstarg + 1], "%d", &ival);
3866 verbose = (unsigned char)ival;
3867 firstarg += 2;
3868 }
3869 else if (!strcmp(argv[firstarg], "-D") || !strcmp(argv[firstarg], "--debug")) {
3870 sscanf(argv[firstarg + 1], "%d", &ival);
3871 debug = (unsigned char)ival;
3872 firstarg += 2;
3873 }
3874 else if (!strcmp(argv[firstarg], "-e") || !strcmp(argv[firstarg], "--exhaustive")) {
3875 exhaustive = 1;
3876 firstarg++;
3877 }
3878 else if (!strcmp(argv[firstarg], "-c") || !strcmp(argv[firstarg], "--cleanup")) {
3879 cleanup = 1;
3880 firstarg++;
3881 }
3882 else if (!strcmp(argv[firstarg], "-V") || !strcmp(argv[firstarg], "--version")) {
3883 fprintf(stderr, "Vesta Static Timing Analyzer version 0.3\n");
3884 exit(0);
3885 }
3886 else {
3887 fprintf(stderr, "Unknown option \"%s\"\n", argv[firstarg]);
3888 firstarg++;
3889 }
3890 }
3891
3892 if (objc - firstarg < 2) {
3893 fprintf(stderr, "Usage: vesta [options] <name.v> <name.lib> [...]\n");
3894 fprintf(stderr, "Options:\n");
3895 fprintf(stderr, "--delay <delay_file> or -d <delay_file>\n");
3896 fprintf(stderr, "--period <period> or -p <period>\n");
3897 fprintf(stderr, "--load <load> or -l <load>\n");
3898 fprintf(stderr, "--num-paths <numPaths> or -n <numPaths>\n");
3899 fprintf(stderr, "--long or -L\n");
3900 fprintf(stderr, "--verbose <level> or -v <level>\n");
3901 fprintf(stderr, "--exhaustive or -e\n");
3902 fprintf(stderr, "--cleanup or -c\n");
3903 fprintf(stderr, "--version or -V\n");
3904 exit (1);
3905 }
3906 else {
3907 fflush(stdout);
3908 fprintf(stdout, "----------------------------------------------\n");
3909 fprintf(stdout, "Vesta static timing analysis tool\n");
3910 fprintf(stdout, "for qflow " QFLOW_VERSION "." QFLOW_REVISION "\n");
3911 fprintf(stdout, "(c) 2013-2018 Tim Edwards, Open Circuit Design\n");
3912 fprintf(stdout, "----------------------------------------------\n\n");
3913 fflush(stdout);
3914 }
3915
3916 fsrc = fopen(argv[firstarg], "r");
3917 if (fsrc == NULL) {
3918 fprintf(stderr, "Cannot open %s for reading\n", argv[firstarg]);
3919 exit (1);
3920 }
3921 fclose(fsrc);
3922
3923 /*------------------------------------------------------------------*/
3924 /* Generate one table template for the "scalar" case */
3925 /*------------------------------------------------------------------*/
3926
3927 scalar = (lutable *)malloc(sizeof(lutable));
3928 scalar->name = strdup("scalar");
3929 scalar->invert = 0;
3930 scalar->var1 = CONSTRAINED_TIME;
3931 scalar->var2 = OUTPUT_CAP;
3932 scalar->size1 = 1;
3933 scalar->size2 = 1;
3934 scalar->idx1.times = (double *)malloc(sizeof(double));
3935 scalar->idx2.caps = (double *)malloc(sizeof(double));
3936 scalar->values = (double *)malloc(sizeof(double));
3937
3938 scalar->idx1.times[0] = 0.0;
3939 scalar->idx2.caps[0] = 0.0;
3940 scalar->values[0] = 0.0;
3941
3942 scalar->next = NULL;
3943 tables = scalar;
3944
3945 /*------------------------------------------------------------------*/
3946 /* Read all liberty format files (everything on the command line */
3947 /* after the verilog source file). */
3948 /*------------------------------------------------------------------*/
3949
3950 for (i = 1; firstarg + i < objc; i++) {
3951
3952 flib = fopen(argv[firstarg + i], "r");
3953 if (flib == NULL) {
3954 fprintf(stderr, "Cannot open %s for reading\n", argv[firstarg + i]);
3955 exit (1);
3956 }
3957
3958 /*------------------------------------------------------------------*/
3959 /* Read the liberty format file. This is not a rigorous parser! */
3960 /*------------------------------------------------------------------*/
3961
3962 fileCurrentLine = 0;
3963 libertyRead(flib, &tables, &cells);
3964 fflush(stdout);
3965 fprintf(stdout, "Lib read %s: Processed %d lines.\n", argv[firstarg + i],
3966 fileCurrentLine);
3967 if (flib != NULL) fclose(flib);
3968 }
3969
3970 /*--------------------------------------------------*/
3971 /* Debug: Print summary of liberty database */
3972 /*--------------------------------------------------*/
3973
3974 if (verbose > 3) {
3975
3976 lutable *newtable;
3977 cell *newcell;
3978 pin *newpin;
3979
3980 for (newtable = tables; newtable; newtable = newtable->next) {
3981 fprintf(stdout, "Table: %s\n", newtable->name);
3982 }
3983
3984 for (newcell = cells; newcell; newcell = newcell->next) {
3985 fprintf(stdout, "Cell: %s\n", newcell->name);
3986 fprintf(stdout, " Function: %s\n", newcell->function);
3987 for (newpin = newcell->pins; newpin; newpin = newpin->next) {
3988 if (newpin->type == INPUT)
3989 fprintf(stdout, " Pin: %s cap=%g\n", newpin->name, newpin->capr);
3990 }
3991 fprintf(stdout, "\n");
3992 }
3993 }
3994
3995 /*------------------------------------------------------------------*/
3996 /* Read verilog netlist. This is also not a rigorous parser! */
3997 /*------------------------------------------------------------------*/
3998
3999 /* See hash.c for these routines and variables */
4000 hashfunc = hash;
4001 matchfunc = match;
4002
4003 /* Initialize net hash table */
4004 InitializeHashTable(&Nethash, LARGEHASHSIZE);
4005
4006 fileCurrentLine = 0;
4007
4008 verilogRead(argv[firstarg], cells, &netlist, &instlist, &inputlist, &outputlist,
4009 &Nethash);
4010
4011 if (delayfile != NULL) {
4012 fdly = fopen(delayfile, "r");
4013
4014 if (fdly == NULL) {
4015 fprintf(stderr, "Cannot open %s for reading\n", delayfile);
4016 exit (1);
4017 }
4018 }
4019 else
4020 fdly = NULL;
4021
4022 fflush(stdout);
4023 fprintf(stdout, "Verilog netlist read: Processed %d lines.\n", vlinenum);
4024
4025 /*--------------------------------------------------*/
4026 /* Debug: Print summary of verilog source */
4027 /*--------------------------------------------------*/
4028
4029 if (verbose > 2) {
4030 connect *testoutput;
4031 connect *testinput;
4032 net *testnet;
4033 instance *testinst;
4034
4035 for (testinput = inputlist; testinput; testinput = testinput->next) {
4036 if (testinput->refnet)
4037 fprintf(stdout, " Input: %s\n", testinput->refnet->name);
4038 }
4039 for (testoutput = outputlist; testoutput; testoutput = testoutput->next) {
4040 if (testoutput->refnet)
4041 fprintf(stdout, " Output: %s\n", testoutput->refnet->name);
4042 }
4043 for (testnet = netlist; testnet; testnet = testnet->next) {
4044 fprintf(stdout, " Net: %s\n", testnet->name);
4045 }
4046 for (testinst = instlist; testinst; testinst = testinst->next) {
4047 fprintf(stdout, " Gate: %s\n", testinst->name);
4048 }
4049 }
4050
4051 /*--------------------------------------------------*/
4052 /* Generate internal links representing the network */
4053 /*--------------------------------------------------*/
4054
4055 createLinks(netlist, instlist, inputlist, outputlist);
4056
4057 /* Generate a connection list from inputlist */
4058
4059 for (testconn = inputlist; testconn; testconn = testconn->next) {
4060 newinputconn = (connlistptr)malloc(sizeof(connlist));
4061 newinputconn->connection = testconn;
4062 newinputconn->next = inputconnlist;
4063 inputconnlist = newinputconn;
4064 }
4065
4066 /*--------------------------------------------------*/
4067 /* Assign net types, mainly to identify clocks */
4068 /* Return a list of clock nets */
4069 /*--------------------------------------------------*/
4070
4071 numterms = assign_net_types(netlist, &clockconnlist);
4072
4073 if (verbose > 2)
4074 fprintf(stdout, "Number of terminals to check: %d\n", numterms);
4075
4076 /*--------------------------------------------------*/
4077 /* Calculate total load on each net */
4078 /* To do: Add wire models or computed wire delays */
4079 /*--------------------------------------------------*/
4080
4081 if (fdly != NULL) {
4082 delayRead(fdly, &Nethash);
4083 fclose(fdly);
4084 }
4085
4086 /* Hash table no longer needed */
4087 HashKill(&Nethash);
4088
4089 computeLoads(netlist, instlist, outLoad);
4090
4091 /*--------------------------------------------------*/
4092 /* Identify all clock-to-terminal paths */
4093 /*--------------------------------------------------*/
4094
4095 if (verbose > 0) {
4096 fprintf(stdout, "Starting timing analysis.\n");
4097 fflush(stdout);
4098 }
4099 numpaths = find_clock_to_term_paths(clockconnlist, &pathlist, netlist, MAXIMUM_TIME);
4100 fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
4101 fflush(stdout);
4102
4103 /* For each terminal path, find the source and destination clocks */
4104 /* (where they exist) and compute clock skew. Also compute setup */
4105 /* or hold at the destination. */
4106
4107 find_clock_skews(pathlist, MAXIMUM_TIME);
4108
4109 /*--------------------------------------------------*/
4110 /* Collect paths into a non-linked array so that */
4111 /* they can be sorted by delay time */
4112 /*--------------------------------------------------*/
4113
4114 orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
4115
4116 i = 0;
4117 for (testddata = pathlist; testddata; testddata = testddata->next) {
4118 orderedpaths[i] = testddata;
4119 i++;
4120 }
4121
4122 qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
4123
4124 /*----------------------------------------------------*/
4125 /* Report on top <numReportPaths> maximum delay paths */
4126 /*----------------------------------------------------*/
4127
4128 if (summarydir != NULL) {
4129 summaryfile = (char *)malloc(256);
4130 sprintf(summaryfile, "%s/reg_to_reg_max.log", summarydir);
4131 }
4132 if (summaryfile != NULL) {
4133 fsum = fopen(summaryfile, "w");
4134 if (fsum == NULL) {
4135 fprintf(stderr, "Cannot open %s for writing\n", summaryfile);
4136 if (summarydir == NULL) {
4137 free(summaryfile);
4138 summaryfile = NULL;
4139 }
4140 }
4141 }
4142 else
4143 fsum = NULL;
4144 if (fsum)
4145 fprintf(fsum, "Vesta static timing analysis, "
4146 "register-to-register maximum timing\n");
4147
4148 fprintf(stdout, "\nTop %d maximum delay paths:\n", (numpaths >= numReportPaths)
4149 ? numReportPaths : numpaths);
4150 if (fsum)
4151 fprintf(fsum, "\nTop %d maximum delay paths:\n", (numpaths >= numReportPaths)
4152 ? numReportPaths : numpaths);
4153 badtiming = 0;
4154 for (i = 0; ((i < numReportPaths) && (i < numpaths)); i++) {
4155 testddata = orderedpaths[i];
4156 for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
4157
4158 if (testddata->backtrace->receiver->refinst != NULL) {
4159 fprintf(stdout, "Path %s/%s to %s/%s delay %g ps",
4160 testbt->receiver->refinst->name,
4161 testbt->receiver->refpin->name,
4162 testddata->backtrace->receiver->refinst->name,
4163 testddata->backtrace->receiver->refpin->name,
4164 testddata->delay);
4165 if (fsum) fprintf(fsum, "Path %s/%s to %s/%s delay %g ps",
4166 testbt->receiver->refinst->name,
4167 testbt->receiver->refpin->name,
4168 testddata->backtrace->receiver->refinst->name,
4169 testddata->backtrace->receiver->refpin->name,
4170 testddata->delay);
4171 }
4172 else {
4173 fprintf(stdout, "Path %s/%s to output pin %s delay %g ps",
4174 testbt->receiver->refinst->name,
4175 testbt->receiver->refpin->name,
4176 testddata->backtrace->receiver->refnet->name,
4177 testddata->delay);
4178 if (fsum) fprintf(fsum, "Path %s/%s to output pin %s delay %g ps",
4179 testbt->receiver->refinst->name,
4180 testbt->receiver->refpin->name,
4181 testddata->backtrace->receiver->refnet->name,
4182 testddata->delay);
4183 }
4184
4185 if (period > 0.0) {
4186 slack = period - testddata->delay;
4187 fprintf(stdout, " Slack = %g ps", slack);
4188 if (fsum) fprintf(fsum, " Slack = %g ps", slack);
4189 if (slack < 0.0) badtiming = 1;
4190 }
4191 fprintf(stdout, "\n");
4192 if (fsum) fprintf(fsum, "\n");
4193 if (longFormat) print_path(testddata->backtrace, stdout);
4194 if (fsum) print_path(testddata->backtrace, fsum);
4195
4196 if (testddata->backtrace->receiver->refinst != NULL) {
4197 if (longFormat) {
4198 fprintf(stdout, " clock skew at destination = %g\n", testddata->skew);
4199 fprintf(stdout, " setup at destination = %g\n", testddata->setup);
4200 fprintf(stdout, "\n");
4201 }
4202 if (fsum) {
4203 fprintf(fsum, " clock skew at destination = %g\n", testddata->skew);
4204 fprintf(fsum, " setup at destination = %g\n", testddata->setup);
4205 fprintf(fsum, "\n");
4206 }
4207 }
4208 }
4209
4210 if (period > 0.0) {
4211 if (badtiming) {
4212 fprintf(stdout, "ERROR: Design fails timing requirements.\n");
4213 if (fsum) fprintf(fsum, "ERROR: Design fails timing requirements.\n");
4214 }
4215 else {
4216 fprintf(stdout, "Design meets timing requirements.\n");
4217 if (fsum) fprintf(fsum, "Design meets timing requirements.\n");
4218 }
4219 }
4220 else if ((numpaths > 0) && (orderedpaths[0] != NULL)) {
4221 fprintf(stdout, "Computed maximum clock frequency (zero margin) = %g MHz\n",
4222 (1.0E6 / orderedpaths[0]->delay));
4223 if (fsum) fprintf(fsum, "Computed maximum clock frequency "
4224 "(zero margin) = %g MHz\n",
4225 (1.0E6 / orderedpaths[0]->delay));
4226 }
4227 fprintf(stdout, "-----------------------------------------\n\n");
4228 if (fsum) fprintf(fsum, "-----------------------------------------\n\n");
4229 fflush(stdout);
4230
4231 /*--------------------------------------------------*/
4232 /* Clean up the path list */
4233 /*--------------------------------------------------*/
4234
4235 while (pathlist != NULL) {
4236 freeddata = pathlist;
4237 pathlist = pathlist->next;
4238 while (freeddata->backtrace != NULL) {
4239 freebt = freeddata->backtrace;
4240 freeddata->backtrace = freeddata->backtrace->next;
4241 freebt->refcnt--;
4242 if (freebt->refcnt == 0) free(freebt);
4243 else break;
4244 }
4245 free(freeddata);
4246 }
4247
4248 free(orderedpaths);
4249
4250 /*--------------------------------------------------*/
4251 /* Now calculate minimum delay paths */
4252 /*--------------------------------------------------*/
4253
4254 reset_all(netlist, MINIMUM_TIME);
4255 numpaths = find_clock_to_term_paths(clockconnlist, &pathlist, netlist, MINIMUM_TIME);
4256 fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
4257 fflush(stdout);
4258
4259 find_clock_skews(pathlist, MINIMUM_TIME);
4260
4261 /*--------------------------------------------------*/
4262 /* Collect paths into a non-linked array so that */
4263 /* they can be sorted by delay time */
4264 /*--------------------------------------------------*/
4265
4266 orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
4267
4268 i = 0;
4269 for (testddata = pathlist; testddata; testddata = testddata->next) {
4270 orderedpaths[i] = testddata;
4271 i++;
4272 }
4273
4274 qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
4275
4276 /*----------------------------------------------------*/
4277 /* Report on top <numReportPaths> minimum delay paths */
4278 /*----------------------------------------------------*/
4279
4280 if (summarydir != NULL) {
4281 if (fsum != NULL) fclose(fsum);
4282 sprintf(summaryfile, "%s/reg_to_reg_min.log", summarydir);
4283 fsum = fopen(summaryfile, "w");
4284 if (fsum == NULL) {
4285 fprintf(stderr, "Cannot open %s for writing\n", summaryfile);
4286 }
4287 }
4288 if (fsum)
4289 fprintf(fsum, "Vesta static timing analysis, "
4290 "register-to-register minimum timing\n");
4291
4292 fprintf(stdout, "\nTop %d minimum delay paths:\n", (numpaths >= numReportPaths) ?
4293 numReportPaths : numpaths);
4294 if (fsum) fprintf(fsum, "\nTop %d minimum delay paths:\n",
4295 (numpaths >= numReportPaths) ? numReportPaths : numpaths);
4296 badtiming = 0;
4297 for (i = numpaths; (i > (numpaths - numReportPaths)) && (i > 0); i--) {
4298 testddata = orderedpaths[i - 1];
4299 for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
4300
4301 if (testddata->backtrace->receiver->refinst != NULL) {
4302 fprintf(stdout, "Path %s/%s to %s/%s delay %g ps\n",
4303 testbt->receiver->refinst->name,
4304 testbt->receiver->refpin->name,
4305 testddata->backtrace->receiver->refinst->name,
4306 testddata->backtrace->receiver->refpin->name,
4307 testddata->delay);
4308 if (fsum) fprintf(fsum, "Path %s/%s to %s/%s delay %g ps\n",
4309 testbt->receiver->refinst->name,
4310 testbt->receiver->refpin->name,
4311 testddata->backtrace->receiver->refinst->name,
4312 testddata->backtrace->receiver->refpin->name,
4313 testddata->delay);
4314 }
4315 else {
4316 fprintf(stdout, "Path %s/%s to output pin %s delay %g ps\n",
4317 testbt->receiver->refinst->name,
4318 testbt->receiver->refpin->name,
4319 testddata->backtrace->receiver->refnet->name,
4320 testddata->delay);
4321 if (fsum) fprintf(fsum, "Path %s/%s to output pin %s delay %g ps\n",
4322 testbt->receiver->refinst->name,
4323 testbt->receiver->refpin->name,
4324 testddata->backtrace->receiver->refnet->name,
4325 testddata->delay);
4326 }
4327 if (longFormat) print_path(testddata->backtrace, stdout);
4328 if (fsum) print_path(testddata->backtrace, fsum);
4329
4330 /* Print skew and hold unless destination is a pin */
4331 if (testddata->backtrace->receiver->refinst != NULL) {
4332 if (longFormat) {
4333 fprintf(stdout, " clock skew at destination = %g\n", testddata->skew);
4334 fprintf(stdout, " hold at destination = %g\n", testddata->setup);
4335 fprintf(stdout, "\n");
4336 }
4337 if (fsum) {
4338 fprintf(fsum, " clock skew at destination = %g\n", testddata->skew);
4339 fprintf(fsum, " hold at destination = %g\n", testddata->setup);
4340 fprintf(fsum, "\n");
4341 }
4342 }
4343
4344 if (testddata->delay < 0.0) badtiming = 1;
4345 }
4346 if (badtiming) {
4347 fprintf(stdout, "ERROR: Design fails minimum hold timing.\n");
4348 if (fsum) fprintf(fsum, "ERROR: Design fails minimum hold timing.\n");
4349 }
4350 else {
4351 fprintf(stdout, "Design meets minimum hold timing.\n");
4352 if (fsum) fprintf(fsum, "Design meets minimum hold timing.\n");
4353 }
4354
4355 fprintf(stdout, "-----------------------------------------\n\n");
4356 if (fsum) fprintf(fsum, "-----------------------------------------\n\n");
4357 fflush(stdout);
4358
4359 /*--------------------------------------------------*/
4360 /* Clean up the path list */
4361 /*--------------------------------------------------*/
4362
4363 while (pathlist != NULL) {
4364 freeddata = pathlist;
4365 pathlist = pathlist->next;
4366 while (freeddata->backtrace != NULL) {
4367 freebt = freeddata->backtrace;
4368 freeddata->backtrace = freeddata->backtrace->next;
4369 freebt->refcnt--;
4370 if (freebt->refcnt == 0) free(freebt);
4371 else break;
4372 }
4373 free(freeddata);
4374 }
4375
4376 free(orderedpaths);
4377
4378 for (testconn = inputlist; testconn; testconn = testconn->next) {
4379 testconn->tag = NULL;
4380 testconn->metric = -1;
4381 }
4382
4383 /*--------------------------------------------------*/
4384 /* Identify all input-to-terminal paths */
4385 /*--------------------------------------------------*/
4386
4387 reset_all(netlist, MAXIMUM_TIME);
4388 numpaths = find_clock_to_term_paths(inputconnlist, &pathlist, netlist, MAXIMUM_TIME);
4389 fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
4390 fflush(stdout);
4391
4392 find_clock_skews(pathlist, MAXIMUM_TIME);
4393
4394 /*--------------------------------------------------*/
4395 /* Collect paths into a non-linked array so that */
4396 /* they can be sorted by delay time */
4397 /*--------------------------------------------------*/
4398
4399 orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
4400
4401 i = 0;
4402 for (testddata = pathlist; testddata; testddata = testddata->next) {
4403 orderedpaths[i] = testddata;
4404 i++;
4405 }
4406
4407 qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
4408
4409 /*----------------------------------------------------*/
4410 /* Report on top <numReportPaths> maximum delay paths */
4411 /*----------------------------------------------------*/
4412
4413 if (summarydir != NULL) {
4414 if (fsum != NULL) fclose(fsum);
4415 sprintf(summaryfile, "%s/pin_to_reg_max.log", summarydir);
4416 fsum = fopen(summaryfile, "w");
4417 if (fsum == NULL) {
4418 fprintf(stderr, "Cannot open %s for writing\n", summaryfile);
4419 }
4420 }
4421 if (fsum)
4422 fprintf(fsum, "Vesta static timing analysis, "
4423 "pin-to-register and register-to-pin maximum timing\n");
4424
4425 fprintf(stdout, "\nTop %d maximum delay paths:\n", (numpaths >= numReportPaths) ?
4426 numReportPaths : numpaths);
4427 if (fsum) fprintf(fsum, "\nTop %d maximum delay paths:\n",
4428 (numpaths >= numReportPaths) ?
4429 numReportPaths : numpaths);
4430 for (i = 0; ((i < numReportPaths) && (i < numpaths)); i++) {
4431 testddata = orderedpaths[i];
4432 for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
4433
4434 if (testddata->backtrace->receiver->refinst != NULL) {
4435 fprintf(stdout, "Path input pin %s to %s/%s delay %g ps\n",
4436 testbt->receiver->refnet->name,
4437 testddata->backtrace->receiver->refinst->name,
4438 testddata->backtrace->receiver->refpin->name,
4439 testddata->delay);
4440 if (fsum) fprintf(fsum, "Path input pin %s to %s/%s delay %g ps\n",
4441 testbt->receiver->refnet->name,
4442 testddata->backtrace->receiver->refinst->name,
4443 testddata->backtrace->receiver->refpin->name,
4444 testddata->delay);
4445 }
4446 else {
4447 fprintf(stdout, "Path input pin %s to output pin %s delay %g ps\n",
4448 testbt->receiver->refnet->name,
4449 testddata->backtrace->receiver->refnet->name,
4450 testddata->delay);
4451 if (fsum) fprintf(fsum, "Path input pin %s to output pin %s delay %g ps\n",
4452 testbt->receiver->refnet->name,
4453 testddata->backtrace->receiver->refnet->name,
4454 testddata->delay);
4455 }
4456 if (longFormat) print_path(testddata->backtrace, stdout);
4457 if (fsum) print_path(testddata->backtrace, fsum);
4458
4459 if (testddata->backtrace->receiver->refinst != NULL) {
4460 if (longFormat) {
4461 fprintf(stdout, " setup at destination = %g\n", testddata->setup);
4462 fprintf(stdout, "\n");
4463 }
4464 if (fsum) {
4465 fprintf(fsum, " setup at destination = %g\n", testddata->setup);
4466 fprintf(fsum, "\n");
4467 }
4468 }
4469 }
4470
4471 fprintf(stdout, "-----------------------------------------\n\n");
4472 if (fsum) fprintf(fsum, "-----------------------------------------\n\n");
4473 fflush(stdout);
4474
4475 /*--------------------------------------------------*/
4476 /* Clean up the path list */
4477 /*--------------------------------------------------*/
4478
4479 while (pathlist != NULL) {
4480 freeddata = pathlist;
4481 pathlist = pathlist->next;
4482 while (freeddata->backtrace != NULL) {
4483 freebt = freeddata->backtrace;
4484 freeddata->backtrace = freeddata->backtrace->next;
4485 freebt->refcnt--;
4486 if (freebt->refcnt == 0) free(freebt);
4487 else break;
4488 }
4489 free(freeddata);
4490 }
4491
4492 free(orderedpaths);
4493
4494 for (testconn = inputlist; testconn; testconn = testconn->next) {
4495 testconn->tag = NULL;
4496 testconn->metric = 1E50;
4497 }
4498
4499 /*--------------------------------------------------*/
4500 /* Now calculate minimum delay paths from inputs */
4501 /*--------------------------------------------------*/
4502
4503 reset_all(netlist, MINIMUM_TIME);
4504 numpaths = find_clock_to_term_paths(inputconnlist, &pathlist, netlist, MINIMUM_TIME);
4505 fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
4506 fflush(stdout);
4507
4508 find_clock_skews(pathlist, MINIMUM_TIME);
4509
4510 /*--------------------------------------------------*/
4511 /* Collect paths into a non-linked array so that */
4512 /* they can be sorted by delay time */
4513 /*--------------------------------------------------*/
4514
4515 orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
4516
4517 i = 0;
4518 for (testddata = pathlist; testddata; testddata = testddata->next) {
4519 orderedpaths[i] = testddata;
4520 i++;
4521 }
4522
4523 qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
4524
4525 /*----------------------------------------------------*/
4526 /* Report on top <numReportPaths> minimum delay paths */
4527 /*----------------------------------------------------*/
4528
4529 if (summarydir != NULL) {
4530 if (fsum != NULL) fclose(fsum);
4531 sprintf(summaryfile, "%s/pin_to_reg_min.log", summarydir);
4532 fsum = fopen(summaryfile, "w");
4533 if (fsum == NULL) {
4534 fprintf(stderr, "Cannot open %s for writing\n", summaryfile);
4535 }
4536 }
4537 if (fsum)
4538 fprintf(fsum, "Vesta static timing analysis, "
4539 "pin-to-register and register-to-pin minimum timing\n");
4540
4541 fprintf(stdout, "\nTop %d minimum delay paths:\n", (numpaths >= numReportPaths) ?
4542 numReportPaths : numpaths);
4543 if (fsum) fprintf(fsum, "\nTop %d minimum delay paths:\n",
4544 (numpaths >= numReportPaths) ?
4545 numReportPaths : numpaths);
4546 for (i = numpaths; (i > (numpaths - numReportPaths)) && (i > 0); i--) {
4547 testddata = orderedpaths[i - 1];
4548 for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
4549
4550 if (testddata->backtrace->receiver->refinst != NULL) {
4551 fprintf(stdout, "Path input pin %s to %s/%s delay %g ps\n",
4552 testbt->receiver->refnet->name,
4553 testddata->backtrace->receiver->refinst->name,
4554 testddata->backtrace->receiver->refpin->name,
4555 testddata->delay);
4556 if (fsum) fprintf(fsum, "Path input pin %s to %s/%s delay %g ps\n",
4557 testbt->receiver->refnet->name,
4558 testddata->backtrace->receiver->refinst->name,
4559 testddata->backtrace->receiver->refpin->name,
4560 testddata->delay);
4561 }
4562 else {
4563 fprintf(stdout, "Path input pin %s to output pin %s delay %g ps\n",
4564 testbt->receiver->refnet->name,
4565 testddata->backtrace->receiver->refnet->name,
4566 testddata->delay);
4567 if (fsum) fprintf(fsum, "Path input pin %s to output pin %s delay %g ps\n",
4568 testbt->receiver->refnet->name,
4569 testddata->backtrace->receiver->refnet->name,
4570 testddata->delay);
4571 }
4572 if (longFormat) print_path(testddata->backtrace, stdout);
4573 if (fsum) print_path(testddata->backtrace, fsum);
4574
4575 if (testddata->backtrace->receiver->refinst != NULL) {
4576 if (longFormat) {
4577 fprintf(stdout, " hold at destination = %g\n", testddata->setup);
4578 fprintf(stdout, "\n");
4579 }
4580 if (fsum) {
4581 fprintf(fsum, " hold at destination = %g\n", testddata->setup);
4582 fprintf(fsum, "\n");
4583 }
4584 }
4585 }
4586
4587 fprintf(stdout, "-----------------------------------------\n\n");
4588 if (fsum) fprintf(fsum, "-----------------------------------------\n\n");
4589 fflush(stdout);
4590
4591 if (fsum != NULL) fclose(fsum);
4592 if (summaryfile != NULL) free(summaryfile);
4593 if (summarydir != NULL) free(summarydir);
4594
4595 /*--------------------------------------------------*/
4596 /* Clean up the path list */
4597 /*--------------------------------------------------*/
4598
4599 while (pathlist != NULL) {
4600 freeddata = pathlist;
4601 pathlist = pathlist->next;
4602 while (freeddata->backtrace != NULL) {
4603 freebt = freeddata->backtrace;
4604 freeddata->backtrace = freeddata->backtrace->next;
4605 freebt->refcnt--;
4606 if (freebt->refcnt == 0) free(freebt);
4607 else break;
4608 }
4609 free(freeddata);
4610 }
4611
4612 free(orderedpaths);
4613
4614 return 0;
4615 }
4616