summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2016-10-06 18:34:48 +0200
committerRuben Undheim <ruben.undheim@gmail.com>2016-10-06 18:34:48 +0200
commitf8a8647330f1d9b1216d7b485783e4819ef0f502 (patch)
tree2240bee6af575eb40313681a60b0a318ed57ad0f /src
parent74357fe050d06744339b6c87ec6ff67d8d4eb261 (diff)
Squashed commit of the following:
commit dc3fd38c211f20185d4ddc834675bfe5906409d1 Merge: 7e4ea8a 64c1647 Author: Tim Edwards <tim@opencircuitdesign.com> Date: Mon Sep 19 08:57:53 2016 -0400 Merge branch 'master' into work commit 64c164786167c99d866efd197f10020f846163dd Author: Tim Edwards <tim@vivaldi.tim.linglan.net> Date: Mon Sep 19 08:57:53 2016 -0400 Update at Mon Sep 19 08:57:53 EDT 2016 by tim commit 7e4ea8a20d6cf368f06ab5dca57a7f84252ce9a9 Author: Tim Edwards <tim@opencircuitdesign.com> Date: Mon Sep 19 08:57:05 2016 -0400 Applied patch by Risto Bell for Bugzilla bug 138. commit e0cf18353ee42a42eec97dbf443e4df6a58eb070 Author: Tim Edwards <tim@opencircuitdesign.com> Date: Sun Sep 18 22:17:54 2016 -0400 Corrected error in vesta that causes crash if no delay file is specified. commit 63b2233c4f5ae8f3453e59f839f140365b3d97ca Author: Tim Edwards <tim@opencircuitdesign.com> Date: Sun Sep 18 22:09:19 2016 -0400 Swapped the reading of <techname>.sh and project_vars.sh, so that values in project_vars.sh may override those in <techname>.sh, specifically for option strings passed to applications (like blifFanout). commit dbfe2219a3957e5f0770466d04a796bff991f129 Author: Tim Edwards <tim@opencircuitdesign.com> Date: Sun Sep 18 21:53:47 2016 -0400 Fixed help text of blifFanout so that MaxFanout, which is integer, is not printed with %g, and so that where values set by the command line were referred to as 'default', these values are now referred to as 'value', and the actual default value is also given. commit 94d20b55ffd9104c99bce1d76f2a0eb46a3d1899 Merge: 3cb0d32 6b689d5 Author: Tim Edwards <tim@opencircuitdesign.com> Date: Sun Sep 18 21:45:31 2016 -0400 Merge branch 'master' into work commit 6b689d535ef4f1ebf3293c9f1de384d176654e34 Author: Tim Edwards <tim@vivaldi.tim.linglan.net> Date: Sun Sep 18 21:45:30 2016 -0400 Update at Sun Sep 18 21:45:29 EDT 2016 by tim commit 3cb0d32a4ff634056cb9ab0e439ca4507adf4dab Author: Tim Edwards <tim@opencircuitdesign.com> Date: Sun Sep 18 21:44:17 2016 -0400 Corrected qflow script to use "tcsh -f" instead of "tcsh" in the first line of scripts generated for use in running qflow (e.g., qflow_exec.sh). commit b09c09d83a0d30f0c883873a318589b98d3b52c1 Merge: cab0547 e0110d9 Author: Tim Edwards <tim@opencircuitdesign.com> Date: Thu Sep 8 21:26:06 2016 -0400 Merge branch 'master' into work commit e0110d94b21f58bcbd72939b8a03d780fd1bf258 Author: Tim Edwards <tim@vivaldi.tim.linglan.net> Date: Thu Sep 8 21:26:04 2016 -0400 Update at Thu Sep 8 21:26:04 EDT 2016 by tim commit cab0547183f795a21eb03d5d294381d0d415597c Author: Tim Edwards <tim@opencircuitdesign.com> Date: Thu Sep 8 21:24:27 2016 -0400 Added code for interconnect delay calculations from Russell Friesenhahn. commit 4d14dc5b35140e9cd2e47a4034b50fb865d65fc0 Author: Tim Edwards <tim@opencircuitdesign.com> Date: Thu Jun 9 22:54:57 2016 -0400 Updated display script to generate a load script and run this from the magic command-line, in conjunction with changes to magic to allow scripts to be specified on the command line. commit 2f33cdccdf19c40f57ce37e1ea3ba05af5f34cb1 Merge: bbda854 90c31df Author: Tim Edwards <tim@opencircuitdesign.com> Date: Thu Jun 9 08:55:48 2016 -0400 Merge branch 'master' into work commit 90c31df4db7b38b723004c64470dce08180652c6 Author: Tim Edwards <tim@vivaldi.tim.linglan.net> Date: Thu Jun 9 08:55:47 2016 -0400 Update at Thu Jun 9 08:55:47 EDT 2016 by tim commit bbda854cabf54b28987ac4c848fb9c97e3f69e5b Author: Tim Edwards <tim@opencircuitdesign.com> Date: Thu Jun 9 08:55:13 2016 -0400 Corrected typo in display.sh; thanks to Santiago Rubio for pointing it out. commit 0f33d164b480fdfe221f0f073cb55942628ced3e Merge: 696e8f4 709d00e Author: Tim Edwards <tim@opencircuitdesign.com> Date: Tue Jun 7 08:33:10 2016 -0400 Merge branch 'master' into work commit 709d00e016c5605ea7ba5c101ff6004a55666391 Author: Tim Edwards <tim@vivaldi.tim.linglan.net> Date: Tue Jun 7 08:33:09 2016 -0400 Update at Tue Jun 7 08:33:09 EDT 2016 by tim commit 696e8f42f30335a4f9e5233926478d9021c7299b Author: Tim Edwards <tim@opencircuitdesign.com> Date: Tue Jun 7 08:31:38 2016 -0400 Corrected display script, as the embedded newline is not interpreted correctly in the "lef read" command, and needs to be split into two separate commands. Thanks to Santiago Rubio for the patch. commit 0cb31415d634961e063f2b041b437fcae64b794f Merge: dcb1baf 4c9d9f7 Author: Tim Edwards <tim@opencircuitdesign.com> Date: Mon Apr 18 21:24:21 2016 -0400 Merge branch 'master' into work commit 4c9d9f7df33d7eff9c467cf203692f69f9a864e7 Author: Tim Edwards <tim@vivaldi.tim.linglan.net> Date: Mon Apr 18 21:24:20 2016 -0400 Update at Mon Apr 18 21:24:20 EDT 2016 by tim commit dcb1bafa159647992b91a34f0b5e178f31602eea Author: Tim Edwards <tim@opencircuitdesign.com> Date: Mon Apr 18 21:18:54 2016 -0400 Modified the osu018 technology to use SCN6M_SUBM.10 instead of SCN6M_DEEP.09; thanks to Shimon for pointing out that the OSU standard cells matched the SUBM tech and not the DEEP. Otherwise, reading the GDS files from the OSU018 standard cell set into magic under SCN6M_DEEP.09 will generate large numbers of DRC errors. Note, however, that the LEF files from OSU018 do not specify metal extensions on the vias, and so stacked vias m1-m3 will cause minimum metal violations on metal2. The way around this is to specify via stacks = 1 to qrouter, so that every metal layer must route for at least 1 track width, which satisfies the minimum metal requirement.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile5
-rw-r--r--src/Makefile.in5
-rw-r--r--src/blifFanout.c10
-rw-r--r--src/hash.c2
-rw-r--r--src/readliberty.c72
-rw-r--r--src/readliberty.h3
-rw-r--r--src/spice2delay.c768
-rw-r--r--src/vesta.c4879
8 files changed, 3347 insertions, 2397 deletions
diff --git a/src/Makefile b/src/Makefile
index dca79aa..4f2124b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -21,7 +21,7 @@ HAVE_ABC = @HAVE_ABC@
HAVE_YOSYS = 1
HAVE_ODIN_II = @HAVE_ODIN_II@
-OBJECTS = blif2BSpice.o blif2Verilog.o blifFanout.o vesta.o
+OBJECTS = blif2BSpice.o blif2Verilog.o blifFanout.o vesta.o spice2delay.o
HASHLIB = hash.o
LIBERTYLIB = readliberty.o
SOURCES := $(patsubst %.o,%.c,$(OBJECTS))
@@ -44,6 +44,9 @@ blif2Verilog$(EXEEXT): blif2Verilog.o
vesta$(EXEEXT): vesta.o $(HASHLIB)
$(CC) $(LDFLAGS) vesta.o $(HASHLIB) -o $@ $(LIBS)
+spice2delay$(EXEEXT): spice2delay.o $(HASHLIB) $(LIBERTYLIB)
+ $(CC) $(LDFLAGS) spice2delay.o $(HASHLIB) $(LIBERTYLIB) -o $@ $(LIBS)
+
install: $(TARGETS)
@echo "Installing verilog and BDNET file format handlers"
$(INSTALL) -d $(DESTDIR)${BININSTALL}
diff --git a/src/Makefile.in b/src/Makefile.in
index 03bc2fd..8712df9 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -21,7 +21,7 @@ HAVE_ABC = @HAVE_ABC@
HAVE_YOSYS = @HAVE_YOSYS@
HAVE_ODIN_II = @HAVE_ODIN_II@
-OBJECTS = blif2BSpice.o blif2Verilog.o blifFanout.o vesta.o
+OBJECTS = blif2BSpice.o blif2Verilog.o blifFanout.o vesta.o spice2delay.o
HASHLIB = hash.o
LIBERTYLIB = readliberty.o
SOURCES := $(patsubst %.o,%.c,$(OBJECTS))
@@ -44,6 +44,9 @@ blif2Verilog$(EXEEXT): blif2Verilog.o
vesta$(EXEEXT): vesta.o $(HASHLIB)
$(CC) $(LDFLAGS) vesta.o $(HASHLIB) -o $@ $(LIBS)
+spice2delay$(EXEEXT): spice2delay.o $(HASHLIB) $(LIBERTYLIB)
+ $(CC) $(LDFLAGS) spice2delay.o $(HASHLIB) $(LIBERTYLIB) -o $@ $(LIBS)
+
install: $(TARGETS)
@echo "Installing verilog and BDNET file format handlers"
$(INSTALL) -d $(DESTDIR)${BININSTALL}
diff --git a/src/blifFanout.c b/src/blifFanout.c
index d812aeb..8df27c6 100644
--- a/src/blifFanout.c
+++ b/src/blifFanout.c
@@ -1416,16 +1416,16 @@ void helpmessage(void)
printf("\t-g\t\tDebug mode: parse and print the gate.cfg table\n");
printf("\t-n\t\tDebug mode: parse and print the node list\n");
printf("\t-v\t\tDebug mode: verbose output\n");
- printf("\t-l latency\tSet the maximum variable latency (ps). (default %g)\n",
- MaxLatency);
- printf("\t-F value\tSet the maximum fanout per node (default %g)\n",
+ printf("\t-l latency\tSet the maximum variable latency (ps). "
+ "(value %g, default 1000.0)\n", MaxLatency);
+ printf("\t-F value\tSet the maximum fanout per node (value %d, default 16)\n",
MaxFanout);
printf("\t-b buffername\tSet the name of a buffer gate\n");
printf("\t-i pin_name\tSet the name of the buffer gate input pin (used with -b)\n");
printf("\t-o pin_name\tSet the name of the buffer gate output pin (used with -b)\n");
printf("\t-s separator\tGate names have \"separator\" before drive strength\n");
- printf("\t-c value\tSet the maximum output capacitance (fF). (default %g)\n",
- MaxOutputCap);
+ printf("\t-c value\tSet the maximum output capacitance (fF). "
+ "(value %g, default 30.0)\n", MaxOutputCap);
printf("\t-p filepath\tSpecify an alternate path and filename for gate.cfg\n");
printf("\t-I filepath\tSpecify a path and filename for list of nets to ignore\n");
printf("\t-h\t\tprint this help message\n\n");
diff --git a/src/hash.c b/src/hash.c
index 1f78ac8..92fbec2 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -260,7 +260,7 @@ struct hashlist *HashIntPtrInstall(char *name, int value, void *ptr,
/* destroy a hash table, freeing associated memory */
/*----------------------------------------------------------------------*/
-void *HashKill(struct hashlist **hashtab)
+void HashKill(struct hashlist **hashtab)
{
struct hashlist *np, *p;
int i;
diff --git a/src/readliberty.c b/src/readliberty.c
index 991a28f..037a17f 100644
--- a/src/readliberty.c
+++ b/src/readliberty.c
@@ -1233,3 +1233,75 @@ get_pintype(Cell *curcell, char *pinname)
}
/*--------------------------------------------------------------------*/
+
+Cell *
+get_cell_by_name(Cell *cell, char *name)
+{
+ Cell *currcell, *newcell;
+
+ for (currcell = cell; currcell; currcell = currcell->next) {
+ if (!strcasecmp(currcell->name, name)) {
+ return currcell;
+ }
+ }
+ fprintf(stderr, "Did not find standard cell \"%s\" in list of cells\n", name);
+ return NULL;
+}
+
+Pin *
+get_pin_by_name(Cell *curcell, char *pinname)
+{
+ Pin *curpin;
+
+ for (curpin = curcell->pins; curpin; curpin = curpin->next) {
+ if (!strcmp(curpin->name, pinname)) {
+ printf("found pin %s\n", pinname);
+ return curpin;
+ }
+ }
+ printf("did not find pin %s\n", pinname);
+ return NULL;
+}
+
+void delete_Cell(Cell *cell) {
+ free(cell->name);
+ free(cell->function);
+ free(cell->times);
+ free(cell->caps);
+ free(cell->values);
+
+ Pin *curpin = cell->pins;
+ Pin *tmppin;
+
+ while (curpin != NULL) {
+ tmppin = curpin->next;
+ free(curpin->name);
+ free(curpin);
+ curpin = tmppin;
+ }
+
+ LUTable *curlut = cell->reftable;
+ LUTable *tmplut;
+
+ while (curlut != NULL) {
+ tmplut = curlut->next;
+ /*free(curlut->name);*/
+ /*free(curlut);*/
+ curlut = tmplut;
+ }
+ free(cell);
+}
+
+void
+delete_cell_list(Cell *cell)
+{
+ Cell *currcell = cell;
+ Cell *tmpcell;
+
+ while (currcell != NULL) {
+ tmpcell = currcell->next;
+ delete_Cell(currcell);
+ currcell = tmpcell;
+ }
+
+}
diff --git a/src/readliberty.h b/src/readliberty.h
index dbef6ee..b7c9407 100644
--- a/src/readliberty.h
+++ b/src/readliberty.h
@@ -80,5 +80,8 @@ extern int get_pintype(Cell *curcell, char *pinname);
extern int get_pincap(Cell *curcell, char *pinname, double *retcap);
extern int get_values(Cell *curcell, double *retdelay, double *retcap);
extern Cell *read_liberty(char *libfile, char *pattern);
+extern Cell *get_cell_by_name(Cell *cell, char *name);
+extern Pin *get_pin_by_name(Cell *curcell, char *pinname);
+extern void delete_cell_list(Cell *cell);
/*--------------------------------------------------------------*/
diff --git a/src/spice2delay.c b/src/spice2delay.c
new file mode 100644
index 0000000..c7cdf96
--- /dev/null
+++ b/src/spice2delay.c
@@ -0,0 +1,768 @@
+// spice2delay
+//
+//
+//
+//
+//
+//
+//
+// Todo
+// 2) double check all read in c and r values for units
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hash.h"
+#include "readliberty.h" /* liberty file database */
+
+#define SRC 0x01 // node is a driver
+#define SNK 0x02 // node is a receiver
+#define INT 0x03 // node is internal to an interconnect
+
+typedef struct _cell_io *cell_io_ptr;
+
+typedef struct _cell_io {
+ char *name;
+ pinptr *pins;
+ cell_io_ptr next;
+} cell_io;
+
+typedef struct _r *rptr;
+typedef struct _node *nodeptr;
+
+typedef struct _r {
+ char *name;
+ nodeptr node1;
+ nodeptr node2;
+ double rval;
+} r;
+
+typedef struct _ritem* ritemptr;
+
+typedef struct _ritem {
+ rptr r;
+ ritemptr next;
+} ritem;
+
+
+typedef struct _node {
+ char* name;
+ int type;
+ ritemptr rlist;
+ double nodeCap;
+ double totCapDownstream;
+ short visited;
+} node;
+
+typedef struct _node_item *node_item_ptr;
+
+typedef struct _node_item {
+ nodeptr node;
+ node_item_ptr next;
+} node_item;
+
+typedef struct _snk* snkptr;
+
+typedef struct _snk {
+ nodeptr snknode;
+ double delay;
+ snkptr next;
+} snk;
+
+typedef struct _elmdly* elmdlyptr;
+
+typedef struct _elmdly {
+ nodeptr src;
+ snkptr snklist;
+} elmdly;
+
+void print_help () {
+}
+
+char** tokenize_line (char *line, const char *delims, char*** tokens_ptr, int *num_toks) {
+ int buff_sz = 4;
+
+ char **tokens = calloc(buff_sz, sizeof(char*));
+
+ int i = 0;
+
+ tokens[i] = strtok(line, delims);
+ i++;
+
+ for (i = 1; tokens[i-1] != NULL; i++) {
+ if (i == buff_sz) {
+ buff_sz *= 2;
+ tokens = realloc(tokens, sizeof(char*) * buff_sz);
+ }
+ *num_toks = i;
+ tokens[i] = strtok(NULL, delims);
+ }
+
+ /**tokens_ptr = tokens;*/
+ return tokens;
+}
+
+void process_subckt_def(char **tokens, int num_toks, Cell *cells, cell_io_ptr *cell_io_ptrptr) {
+
+ int i;
+
+ Cell *cell;
+
+ cell_io_ptr new_cell_io = calloc(1, sizeof(cell_io));
+
+ new_cell_io->name = calloc((strlen(tokens[1]) + 1), sizeof(char));
+ new_cell_io->next = NULL;
+ strcpy(new_cell_io->name, tokens[1]);
+
+ new_cell_io->pins = calloc((num_toks - 2), sizeof(Pin*));
+
+ cell = get_cell_by_name(cells, tokens[1]);
+
+ for (i = 2; i < num_toks; i++) {
+ new_cell_io->pins[i-2] = get_pin_by_name(cell, tokens[i]);
+ }
+
+ if (*cell_io_ptrptr == NULL) {
+ *cell_io_ptrptr = new_cell_io;
+ } else {
+ cell_io_ptr curr_cell_io = (*cell_io_ptrptr);
+
+ while (curr_cell_io->next != NULL) {
+ curr_cell_io = curr_cell_io->next;
+ }
+ curr_cell_io->next = new_cell_io;
+ }
+}
+
+nodeptr create_node (char *name, int type, double nodeCap) {
+ nodeptr new_node = calloc(1, sizeof(node));
+
+ new_node->name = calloc(strlen(name) + 1, sizeof(char));
+ strcpy(new_node->name, name);
+ new_node->type = type;
+ new_node->nodeCap = nodeCap;
+
+ return new_node;
+}
+
+void add_ritem (ritemptr *ritem_list_ptr, rptr r) {
+ ritemptr next = calloc(1, sizeof(ritem));
+ next->r = r;
+
+ // list has no items
+ if (*ritem_list_ptr == NULL) {
+
+ *ritem_list_ptr = next;
+
+ } else {
+
+ // list has some items, we need to find the end
+
+ ritemptr i;
+
+ for (i = *ritem_list_ptr; i->next != NULL; i = i->next);
+
+ i->next = next;
+ }
+
+}
+void process_subckt_inst(char **tokens, int num_toks, cell_io_ptr cell_io, struct hashlist **Nodehash, node_item_ptr **last_driver_ptr, int *numDrivers) {
+
+ nodeptr curr_node = NULL;
+ node_item_ptr next_src_item = NULL;
+
+ int pin_type = 0;
+
+ // find cell name in cell_io_list to know about pin order
+ while(strcmp(cell_io->name, tokens[num_toks-1])) {
+ cell_io = cell_io->next;
+
+ if (cell_io == NULL) {
+ fprintf(stderr, "Did not find stdcell %s in cell IO linked list.\n", tokens[num_toks-1]);
+ exit(1);
+ }
+ }
+
+ // Iterate over list of pins processing ones that were found in Liberty file
+ // foreach pin
+ // -if not in hash, create and add to hash
+ // -if in hash, update connections, verify polarity / pin type correct, etc
+ int i;
+ // skip instance name (first token) and std cell name (last token)
+ for (i = 1; i < num_toks-1; i++) {
+ if (cell_io->pins[i-1] != NULL) {
+ curr_node = HashLookup(tokens[i], Nodehash);
+
+ if (cell_io->pins[i-1]->type == PIN_INPUT) {
+ pin_type = SNK;
+ } else if (cell_io->pins[i-1]->type == PIN_OUTPUT) {
+ pin_type = SRC;
+ } else {
+ fprintf(stderr, "Pin type is not recognized\n");
+ }
+
+ if (curr_node == NULL) {
+ // this is a new node we need to create and add to hash
+ curr_node = create_node(tokens[i], pin_type, cell_io->pins[i-1]->cap);
+ HashPtrInstall(curr_node->name, curr_node, Nodehash);
+ printf("install new node\n");
+ curr_node = NULL;
+ curr_node = HashLookup(tokens[i], Nodehash);
+ } else {
+ if ( ((curr_node->type == SRC) && (pin_type == SNK))
+ || ((curr_node->type == SNK) && (pin_type == SRC))
+ ) {
+ fprintf(stderr, "Pin type for node %s changed polarity!\n", curr_node->name);
+ }
+
+ curr_node->type = pin_type;
+
+ fprintf(stdout, "Node capacitance changed from %f to %f\n", curr_node->nodeCap, curr_node->nodeCap + cell_io->pins[i-1]->cap);
+ curr_node->nodeCap += cell_io->pins[i-1]->cap;
+
+ }
+
+ // add node to list of drivers if the node is a SRC
+ if (curr_node->type == SRC) {
+ printf("found driver\n");
+ next_src_item = calloc(1, sizeof(node_item));
+ next_src_item->node = curr_node;
+ **last_driver_ptr = next_src_item;
+ *last_driver_ptr = &next_src_item->next;
+ *numDrivers = *numDrivers + 1;
+ }
+ }
+ }
+}
+
+double spiceValtoD(char *string) {
+ char *endptr = string;
+
+ double rtrnVal = 0;
+ double suffix = 1;
+
+ // find end of numbers
+ int i = 0;
+
+ while (string[i] != 0) {
+
+ if ( string[i] == '.'
+ || (string[i] >= 0x30 && string[i] <= 0x39)
+ ) {
+ i++;
+ } else {
+ i--;
+ break;
+ }
+ }
+
+ endptr += i * sizeof(char);
+
+ rtrnVal = strtod(string, &endptr);
+
+ if (endptr[0] == 'f') {
+ suffix = 1E-15;
+ } else if (endptr[0] == 'p') {
+ suffix = 1E-12;
+ } else if (endptr[0] == 'n') {
+ suffix = 1E-9;
+ } else if (endptr[0] == 'u') {
+ suffix = 1E-6;
+ } else if (endptr[0] == 'm') {
+ suffix = 1E-3;
+ } else if (endptr[0] == 'k') {
+ suffix = 1E3;
+ } else {
+ suffix = 1;
+ }
+
+ rtrnVal *= suffix;
+
+ return rtrnVal;
+}
+
+void process_r(char **tokens, int num_toks, struct hashlist **Nodehash, ritemptr *fullrlist) {
+ // create ritem which captures the resistor and the connection between two nodes
+ // for each node
+ // if node does not exist, create it
+ // add resistor to each node's list of resistors (connections to other nodes)
+ // add resistor to global list of resistors
+
+ rptr curr_r = NULL;
+ nodeptr curr_node = NULL;
+
+
+ curr_r = calloc(1, sizeof(r));
+ curr_r->name = calloc(strlen(tokens[0]) + 1, sizeof(char));
+ strcpy(curr_r->name, tokens[0]);
+ curr_r->rval = spiceValtoD(tokens[num_toks-1]);
+
+ int i;
+ // skip instance name (first token) and resistance value (last token)
+ for (i = 1; i < num_toks-1; i++) {
+ curr_node = HashLookup(tokens[i], Nodehash);
+
+ if (curr_node == NULL) {
+ // this is a new node we need to create and add to hash
+ curr_node = create_node(tokens[i], INT, 0);
+ HashPtrInstall(curr_node->name, curr_node, Nodehash);
+ printf("install new node\n");
+ curr_node = NULL;
+ curr_node = HashLookup(tokens[i], Nodehash);
+ }
+
+ if (i == 1) {
+ curr_r->node1 = curr_node;
+ } else {
+ curr_r->node2 = curr_node;
+ }
+ add_ritem(&curr_node->rlist, curr_r);
+ }
+
+ add_ritem(fullrlist, curr_r);
+}
+
+void process_c(char **tokens, int num_toks, struct hashlist **Nodehash) {
+ //
+ // change capacitance units to farads
+ //
+ // for each node
+ // if node does not exist, create it
+ // add capacitance value to node capacitance total
+
+ nodeptr curr_node = NULL;
+ // keep all capacitance values in fF to match readliberty.c
+ double cVal = spiceValtoD(tokens[num_toks-1]) * 1E15;
+
+ int i;
+ // skip instance name (first token) and capacitance value (last token)
+ for (i = 1; i < num_toks-1; i++) {
+ curr_node = HashLookup(tokens[i], Nodehash);
+
+ if (curr_node == NULL) {
+ // this is a new node we need to create and add to hash
+ curr_node = create_node(tokens[i], INT, 0);
+ HashPtrInstall(curr_node->name, curr_node, Nodehash);
+ printf("install new node\n");
+ curr_node = NULL;
+ curr_node = HashLookup(tokens[i], Nodehash);
+ }
+
+ curr_node->nodeCap += cVal;
+ }
+}
+
+// for multi-driver nets, must not recurse finding another driver
+void sum_downstream_cap(nodeptr curr_node, nodeptr prev_node, short breadcrumbVal) {
+
+ ritemptr curr_ritem = curr_node->rlist;
+
+ while (curr_ritem != NULL) {
+ // make sure to not backtrack to previous node
+ // make sure to not recurse on the current node
+ if ( (curr_ritem->r->node1 != prev_node)
+ && (curr_ritem->r->node1 != curr_node)
+ ) {
+
+ sum_downstream_cap(curr_ritem->r->node1, curr_node, breadcrumbVal);
+ curr_node->totCapDownstream += (curr_ritem->r->node1->totCapDownstream + curr_ritem->r->node1->nodeCap);
+
+ } else if ( (curr_ritem->r->node2 != prev_node)
+ && (curr_ritem->r->node2 != curr_node)
+ ) {
+
+ sum_downstream_cap(curr_ritem->r->node2, curr_node, breadcrumbVal);
+ curr_node->totCapDownstream += (curr_ritem->r->node2->totCapDownstream + curr_ritem->r->node2->nodeCap);
+
+ }
+
+ curr_ritem = curr_ritem->next;
+ }
+}
+
+void add_snk (snkptr *snk_list_ptr, snkptr snk) {
+
+ // list has no items
+ if (*snk_list_ptr == NULL) {
+
+ *snk_list_ptr = snk;
+
+ } else {
+
+ // list has some items, we need to find the end
+
+ snkptr i;
+
+ for (i = *snk_list_ptr; i->next != NULL; i = i->next);
+
+ i->next = snk;
+ }
+
+}
+
+void calculate_elmore_delay (
+ nodeptr curr_node,
+ nodeptr prev_node,
+ rptr prev_r, // the connection used to get curr_node
+ elmdlyptr curr_elmdly,
+ /*snkptr curr_snk,*/
+ double firstR,
+ double elmdly,
+ short breadcrumbVal
+ ) {
+
+ // -recursively walk each branch of nodes
+ // -accumulate delay on each branch
+ // -append to Elmore Delay list when sink node reached
+
+ // accumulate delay
+ // -first node uses a model resistor based on typical output drive strengths
+ // of stdcell librarie
+ // -subsequent nodes us the resistor that was traveled to arrive at current
+ // node
+ if (curr_node->type == SRC) {
+ elmdly = firstR * (curr_node->nodeCap + curr_node->totCapDownstream);
+ } else {
+ elmdly = prev_r->rval * (curr_node->nodeCap + curr_node->totCapDownstream);
+ }
+
+ // -if current node is an input to another cell, this is an endpoint and the
+ // current delay value needs to be saved
+ // -there still might be other connections though that need to be traversed
+ // to find other endpoints
+ if (curr_node->type == SNK) {
+
+ printf("Found SNK node %s with delay to it of %d\n", curr_node->name, elmdly);
+ snkptr curr_snk = calloc(1, sizeof(snk));
+
+ curr_snk->snknode = curr_node;
+ curr_snk->delay = elmdly;
+
+ add_snk(&curr_elmdly->snklist, curr_snk);
+ }
+
+ ritemptr curr_ritem = curr_node->rlist;
+
+ while (curr_ritem != NULL) {
+ // make sure to not backtrack to previous node
+ // make sure to not recurse on the current node
+ if ( (curr_ritem->r->node1 != prev_node)
+ && (curr_ritem->r->node1 != curr_node)
+ ) {
+
+ calculate_elmore_delay(curr_ritem->r->node1, curr_node, curr_ritem->r, curr_elmdly, firstR, elmdly, breadcrumbVal);
+
+ } else if ( (curr_ritem->r->node2 != prev_node)
+ && (curr_ritem->r->node2 != curr_node)
+ ) {
+
+ calculate_elmore_delay(curr_ritem->r->node2, curr_node, curr_ritem->r, curr_elmdly, firstR, elmdly, breadcrumbVal);
+
+ }
+
+ curr_ritem = curr_ritem->next;
+ }
+}
+
+int main (int argc, char* argv[]) {
+
+ FILE* outfile = NULL;
+ FILE* libfile = NULL;
+ FILE* spcfile = NULL;
+
+ int i, opt;
+ int verbose = 0;
+
+ Cell *cells, *newcell;
+ Pin *newpin;
+ char* libfilename;
+
+ nodeptr currnode = NULL;
+ // -Maintain a list of all nodes that are outputs / drivers.
+ // -Iterate over the list to walk each interconnect to calculate
+ // Elmore Delay
+ node_item_ptr drivers = NULL;
+ node_item_ptr *last_driver = &drivers;
+ int numDrivers = 0;
+
+ // list of all Rs for debugging and to easily free them at end
+ ritemptr allrs = NULL;
+
+ struct hashlist *Nodehash[OBJHASHSIZE];
+
+ /* See hash.c for these routines and variables */
+ hashfunc = hash;
+ matchfunc = match;
+
+ /* Initialize net hash table */
+ InitializeHashTable(Nodehash);
+
+ // create first item in cell io list
+ cell_io_ptr cell_io_list = NULL;
+
+ while ((opt = getopt(argc, argv, "s:l:o:v:")) != -1) {
+ switch (opt) {
+
+ case 's':
+ spcfile = fopen(optarg, "r");
+
+ if (!spcfile) {
+ fprintf(stderr, "Can't open outfile`%s': %s\n", optarg, strerror(errno));
+ }
+ break;
+
+ case 'l':
+ libfile = fopen(optarg, "r");
+ libfilename = strdup(optarg);
+
+ if (!libfile) {
+ fprintf(stderr, "Can't open outfile`%s': %s\n", optarg, strerror(errno));
+ }
+ break;
+
+ case 'o':
+ if (!strcmp(optarg, "-")) {
+ outfile = stdout;
+ } else {
+ outfile = fopen(optarg, "w");
+ }
+ if (!outfile) {
+ fprintf(stderr, "Can't open outfile`%s': %s\n", optarg, strerror(errno));
+ }
+ break;
+
+ case 'v':
+ verbose = atoi(optarg);
+ break;
+
+ default:
+ print_help();
+ break;
+ }
+ }
+
+
+ // Read in Liberty File
+ printf("%s\n", libfilename);
+ cells = read_liberty(libfilename, 0);
+
+ if (verbose > 0) {
+ for (newcell = cells; newcell; newcell = newcell->next) {
+ fprintf(stdout, "Cell: %s\n", newcell->name);
+ fprintf(stdout, " Function: %s\n", newcell->function);
+ for (newpin = newcell->pins; newpin; newpin = newpin->next) {
+ fprintf(stdout, " Pin: %s cap=%g\n", newpin->name, newpin->cap);
+ }
+ fprintf(stdout, "\n");
+ }
+ }
+
+ char *line;
+ size_t nbytes = LIB_LINE_MAX;
+ line = calloc(1, LIB_LINE_MAX);
+ int bytesRead = 0;
+
+ const char delims[3] = " \n";
+
+ char **tokens;
+ int num_toks = 0;
+
+ bytesRead = getline(&line, &nbytes, spcfile);
+
+ while (bytesRead > 0) {
+
+ // skip blank lines
+ if (bytesRead > 2) {
+ tokens = tokenize_line(line, delims, &tokens, &num_toks);
+ /*tokenize_line(line, delims, &tokens, &num_toks);*/
+
+ if (!(strncmp(line, "R", 1))) {
+
+ printf("located resistor line\n");
+ process_r(tokens, num_toks, Nodehash, &allrs);
+
+ } else if (!(strncmp(line, "C", 1))) {
+
+ printf("located capacitor line\n");
+ process_c(tokens, num_toks, Nodehash);
+
+ } else if (!(strncmp(line, "X", 1))) {
+
+ printf("located subckt instantiation line\n");
+ printf("number of hash entries %d\n", RecurseHashTable(Nodehash, CountHashTableEntries));
+ process_subckt_inst(tokens, num_toks, cell_io_list, Nodehash, &last_driver, &numDrivers);
+ printf("number of hash entries %d\n", RecurseHashTable(Nodehash, CountHashTableEntries));
+
+ } else if (!(strncmp(line, ".subckt", 7))) {
+ printf("located subckt definition line\n");
+
+ process_subckt_def(tokens, num_toks, cells, &cell_io_list);
+
+ /*free(tokens);*/
+
+ // read through the rest of the subckt definition
+ while (strncmp(line, ".ends", 4)) { getline(&line, &nbytes, spcfile); }
+
+ /*break;*/
+ } else if (!(strncmp(line, "*", 1))) {
+ printf("located comment line\n");
+ }
+ }
+
+ /*free(tokens);*/
+ bytesRead = getline(&line, &nbytes, spcfile);
+ }
+
+ // Walk each interconnect to calculate downstream capacitance at each node
+ node_item_ptr curr_node_item = drivers;
+ short breadcrumbVal = 1;
+
+ elmdlyptr delays = calloc(numDrivers, sizeof(elmdly));
+
+ int driverIndex = 0;
+
+ printf("Number of drivers is %d\n", numDrivers);
+ printf("Sum downstream capacitance for each node\n");
+ printf("Calculate Elmore Delay for each driver\n");
+
+ while (curr_node_item != NULL) {
+ sum_downstream_cap(curr_node_item->node, NULL, breadcrumbVal);
+
+ if (curr_node_item->node->type == SRC) {
+
+ (&delays[driverIndex])->src = curr_node_item->node;
+
+ calculate_elmore_delay(
+ curr_node_item->node,
+ NULL,
+ NULL,
+ &delays[driverIndex],
+ /*NULL,*/
+ 1,
+ 0,
+ breadcrumbVal
+ );
+ driverIndex++;
+ }
+
+ breadcrumbVal++;
+ curr_node_item = curr_node_item->next;
+ }
+
+ currnode = HashFirst(Nodehash);
+
+ while (currnode != NULL) {
+ printf("%s\t\t%f\t%f\n", currnode->name, currnode->nodeCap, currnode->totCapDownstream);
+ currnode = HashNext(Nodehash);
+ }
+
+
+ node_item_ptr curr_driver = drivers;
+
+ while (curr_driver != NULL) {
+
+ curr_driver = curr_driver->next;
+ }
+
+ elmdlyptr curr_elmdly = NULL;
+ snkptr tmp_snk = NULL;
+ snkptr curr_snk = NULL;
+
+ for (driverIndex = 0; driverIndex < numDrivers; driverIndex++) {
+
+ curr_elmdly = &delays[driverIndex];
+
+ printf("%s\n%s %f\n", curr_elmdly->src->name, curr_elmdly->src->name, curr_elmdly->src->nodeCap + curr_elmdly->src->totCapDownstream);
+
+ fprintf(outfile, "%s\n%s %f\n", curr_elmdly->src->name, curr_elmdly->src->name, curr_elmdly->src->nodeCap + curr_elmdly->src->totCapDownstream);
+
+ curr_snk = curr_elmdly->snklist;
+
+ while(curr_snk != NULL) {
+ printf("%s %f\n", curr_snk->snknode->name, curr_snk->delay);
+ fprintf(outfile, "%s %f\n", curr_snk->snknode->name, curr_snk->delay);
+ curr_snk = curr_snk->next;
+ }
+
+ printf("\n");
+ fprintf(outfile, "\n");
+
+ }
+
+ // Cleanup
+ for (driverIndex = 0; driverIndex < numDrivers; driverIndex++) {
+
+ curr_elmdly = &delays[driverIndex];
+
+ curr_snk = curr_elmdly->snklist;
+
+ while(curr_snk != NULL) {
+ tmp_snk = curr_snk->next;
+ free(curr_snk);
+ curr_snk = tmp_snk;
+ }
+ }
+
+ free(delays);
+
+ ritemptr tmp_ritem = allrs;
+ rptr tmp_r = NULL;
+ int numRs = 0;
+
+ while(allrs != NULL) {
+ numRs++;
+ tmp_ritem = allrs->next;
+ free(allrs->r->name);
+ free(allrs->r);
+ free(allrs);
+ allrs = tmp_ritem;
+ }
+ printf("Number of Rs: %d\n", numRs);
+
+ currnode = HashFirst(Nodehash);
+ int numNodes = 0;
+
+ while (currnode != NULL) {
+ numNodes++;
+ numRs = 0;
+
+ while(currnode->rlist != NULL) {
+ numRs++;
+ tmp_ritem = currnode->rlist->next;
+ free(currnode->rlist);
+ currnode->rlist = tmp_ritem;
+ }
+
+ printf("Node %s had %d Rs attached\n", currnode->name, numRs);
+ free(currnode->name);
+ free(currnode);
+ currnode = HashNext(Nodehash);
+ }
+ printf("Number of nodes: %d\n", numNodes);
+
+ free(line);
+
+ while(drivers != NULL) {
+ curr_driver = drivers->next;
+ free(drivers);
+ drivers = curr_driver;
+ }
+
+ cell_io_ptr tmp_cell_io;
+ while(cell_io_list != NULL) {
+ tmp_cell_io = cell_io_list->next;
+ free(cell_io_list->name);
+ free(cell_io_list->pins);
+ free(cell_io_list);
+ cell_io_list = tmp_cell_io;
+ }
+ delete_cell_list(cells);
+ fclose(spcfile);
+ fclose(libfile);
+ fclose(outfile);
+
+ return 0;
+}
diff --git a/src/vesta.c b/src/vesta.c
index 65d7046..12dd718 100644
--- a/src/vesta.c
+++ b/src/vesta.c
@@ -1,48 +1,50 @@
/*--------------------------------------------------------------*/
-/* vesta.c --- */
-/* */
-/* This file reads two files: (1) A verilog netlist file */
-/* of a circuit (structural verilog, that is, gate-level */
-/* information only), and (2) a liberty format file */
-/* containing timing information for the standard cell */
-/* macros instantiated in the verilog netlist. In */
-/* addition, it may take an optional third file containing */
-/* information about the resistance and capacitance of the */
-/* wiring (see below). */
-/* */
-/* Options are supplied as command-line arguments: */
-/* */
-/* -d <delay_file> Wiring delays (see below) */
-/* -p <value> Clock period, in ps */
-/* -l <value> Output load, in fF */
-/* -v <level> set verbose mode */
-/* -V report version number */
-/* -e exhaustive search */
-/* */
-/* Currently the only output this tool generates is a */
-/* list of paths with negative slack. If no paths have */
-/* negative slack, then the 20 paths with the smallest */
-/* positive slack are output, following a "success" */
-/* message. If no clock period is supplied, then the */
-/* clock period is set to equal the delay of the longest */
-/* delay path, and the 20 paths with the smallest positive */
-/* slack are output, following a statement indicated the */
-/* computed minimum clock period. */
+/* vesta.c --- */
+/* */
+/* This file reads two files: (1) A verilog netlist file */
+/* of a circuit (structural verilog, that is, gate-level */
+/* information only), and (2) a liberty format file */
+/* containing timing information for the standard cell */
+/* macros instantiated in the verilog netlist. In */
+/* addition, it may take an optional third file containing */
+/* information about the resistance and capacitance of the */
+/* wiring (see below). */
+/* */
+/* Options are supplied as command-line arguments: */
+/* */
+/* -d <delay_file> Wiring delays (see below) */
+/* -p <value> Clock period, in ps */
+/* -l <value> Output load, in fF */
+/* -v <level> set verbose mode */
+/* -V report version number */
+/* -e exhaustive search */
+/* */
+/* Currently the only output this tool generates is a */
+/* list of paths with negative slack. If no paths have */
+/* negative slack, then the 20 paths with the smallest */
+/* positive slack are output, following a "success" */
+/* message. If no clock period is supplied, then the */
+/* clock period is set to equal the delay of the longest */
+/* delay path, and the 20 paths with the smallest positive */
+/* slack are output, following a statement indicated the */
+/* computed minimum clock period. */
/*--------------------------------------------------------------*/
/*--------------------------------------------------------------*/
-/* Wiring delay file: */
-/* For qflow, the wiring delay is generated by the tool */
-/* "def2delays". The file format is as follows: */
-/* */
-/* <net_name> */
-/* <output_terminal> [<net_capacitance>] */
-/* <input_terminal_1> <delay_1> */
-/* ... */
-/* <input_terminal_N> <delay_N> */
-/* */
-/* Optional value <net_capacitance> is in fF */
-/* Values <delay_i> are in ps */
+/* Wiring delay file: */
+/* For qflow, the wiring delay is generated by the tool */
+/* "def2delays". The file format is as follows: */
+/* */
+/* <net_name> */
+/* <output_terminal> <net_capacitance> */
+/* <input_terminal_1> <delay_1> */
+/* ... */
+/* <input_terminal_N> <delay_N> */
+/* */
+/* -<net_capacitance> is in fF */
+/* -Values <delay_i> are in ps */
+/* -<input_terminal_N> line *must* be following by a blank */
+/* line */
/*--------------------------------------------------------------*/
#include <stdio.h>
@@ -51,9 +53,9 @@
#include <string.h>
#include <errno.h>
#include <stdarg.h>
-#include <math.h> // Temporary, for fabs()
-#include "hash.h" // For net hash table
-
+#include <math.h> // Temporary, for fabs()
+#include "hash.h" // For net hash table
+
#define LIB_LINE_MAX 65535
int fileCurrentLine;
@@ -63,158 +65,158 @@ int fileCurrentLine;
// versa, so it is necessary that these have TRUE/FALSE
// values.
-#define MINIMUM_TIME 0
-#define MAXIMUM_TIME 1
+#define MINIMUM_TIME 0
+#define MAXIMUM_TIME 1
// Multiple-use definition
-#define UNKNOWN -1
+#define UNKNOWN -1
// Sections of liberty file
-#define INIT 0
-#define LIBBLOCK 1
-#define CELLDEF 2
-#define PINDEF 3
-#define FLOPDEF 4
-#define LATCHDEF 5
-#define TIMING 6
+#define INIT 0
+#define LIBBLOCK 1
+#define CELLDEF 2
+#define PINDEF 3
+#define FLOPDEF 4
+#define LATCHDEF 5
+#define TIMING 6
// Sections of verilog file
-#define MODULE 0
-#define IOLIST 1
-#define GATELIST 2
-#define INSTANCE 3
-#define INSTPIN 4
-#define PINCONN 5
+#define MODULE 0
+#define IOLIST 1
+#define GATELIST 2
+#define INSTANCE 3
+#define INSTPIN 4
+#define PINCONN 5
// Pin types (these are masks---e.g., a pin can be an INPUT and a CLOCK)
-#define INPUT 0x01 // The default
-#define OUTPUT 0x02
-#define DFFCLK 0x04
-#define DFFIN 0x08 // Flop input
-#define DFFOUT 0x10 // Flop output
-#define DFFSET 0x20 // Flop set (preset)
-#define DFFRST 0x40 // Flop reset (clear)
-#define LATCHIN 0x80 // Latch input
-#define LATCHEN 0x100 // Latch enable
-#define LATCHOUT 0x200 // Latch output
+#define INPUT 0x01 // The default
+#define OUTPUT 0x02
+#define DFFCLK 0x04
+#define DFFIN 0x08 // Flop input
+#define DFFOUT 0x10 // Flop output
+#define DFFSET 0x20 // Flop set (preset)
+#define DFFRST 0x40 // Flop reset (clear)
+#define LATCHIN 0x80 // Latch input
+#define LATCHEN 0x100 // Latch enable
+#define LATCHOUT 0x200 // Latch output
// Timing type (for tables)
-#define TIMING_PROP_TRANS 0
-#define TIMING_HOLD 1
-#define TIMING_SETUP 2
-#define TIMING_SET_RESET 3
-#define TIMING_RECOVERY 4
-#define TIMING_REMOVAL 5
-#define TIMING_TRISTATE 6
+#define TIMING_PROP_TRANS 0
+#define TIMING_HOLD 1
+#define TIMING_SETUP 2
+#define TIMING_SET_RESET 3
+#define TIMING_RECOVERY 4
+#define TIMING_REMOVAL 5
+#define TIMING_TRISTATE 6
// A few short-hand definitions
-#define DFF_ALL_IN (DFFCLK | DFFIN | DFFSET | DFFRST)
-#define LATCH_ALL_IN (LATCHIN | LATCHEN)
+#define DFF_ALL_IN (DFFCLK | DFFIN | DFFSET | DFFRST)
+#define LATCH_ALL_IN (LATCHIN | LATCHEN)
-#define DFF_IN_NOT_CLK (DFFIN | DFFSET | DFFRST)
-#define LATCH_IN_NOT_EN (LATCHIN)
+#define DFF_IN_NOT_CLK (DFFIN | DFFSET | DFFRST)
+#define LATCH_IN_NOT_EN (LATCHIN)
-#define REGISTER_IN (DFF_ALL_IN | LATCH_ALL_IN)
-#define REG_IN_NOT_CLK (DFF_IN_NOT_CLK | LATCH_IN_NOT_EN)
+#define REGISTER_IN (DFF_ALL_IN | LATCH_ALL_IN)
+#define REG_IN_NOT_CLK (DFF_IN_NOT_CLK | LATCH_IN_NOT_EN)
-#define IOMASK 0x03
-#define DFFMASK 0x7c
-#define LATCHMASK 0x180
+#define IOMASK 0x03
+#define DFFMASK 0x7c
+#define LATCHMASK 0x180
// Pin sense
-#define SENSE_UNKNOWN 0 // Sense unknown
-#define SENSE_NONE 1 // Non-unate
-#define SENSE_POSITIVE 2 // Positive-unate
-#define SENSE_NEGATIVE 3 // Negative-unate
+#define SENSE_UNKNOWN 0 // Sense unknown
+#define SENSE_NONE 1 // Non-unate
+#define SENSE_POSITIVE 2 // Positive-unate
+#define SENSE_NEGATIVE 3 // Negative-unate
// Signal transition direction
-#define EDGE_UNKNOWN 0
-#define RISING 1
-#define FALLING 2
-#define EITHER 3
+#define EDGE_UNKNOWN 0
+#define RISING 1
+#define FALLING 2
+#define EITHER 3
// Function translation
-#define GROUPBEGIN 1
-#define GROUPEND 2
-#define SIGNAL 3
-#define OPERATOR 4
-#define XOPERATOR 5
-#define SEPARATOR 6
+#define GROUPBEGIN 1
+#define GROUPEND 2
+#define SIGNAL 3
+#define OPERATOR 4
+#define XOPERATOR 5
+#define SEPARATOR 6
// Net types
-#define NET 0x00 // Ordinary net (default)
-#define CLOCK 0x01 // Clock net (path start)
-#define OUTTERM 0x02 // Module output
-#define ASYNC 0x04 // Asynchronous set/reset
-#define TERMINAL 0x08 // DFF input (path terminal)
-#define LATCHTERM 0x10 // Latch input (dependent path terminal)
-#define ENABLE 0x20 // Latch enable (path start)
+#define NET 0x00 // Ordinary net (default)
+#define CLOCK 0x01 // Clock net (path start)
+#define OUTTERM 0x02 // Module output
+#define ASYNC 0x04 // Asynchronous set/reset
+#define TERMINAL 0x08 // DFF input (path terminal)
+#define LATCHTERM 0x10 // Latch input (dependent path terminal)
+#define ENABLE 0x20 // Latch enable (path start)
// Cell types
-#define GATE 0x00 // Combinatorial gate (default)
-#define DFF 0x01 // Flip-flop (shared bit field)
-#define CLK_SENSE_MASK 0x02 // Clock edge mask (0=positive, 1=negative)
-#define RST_MASK 0x04 // Reset mask (0=no reset, 1=reset)
-#define RST_SENSE_MASK 0x08 // Reset edge mask (0=positive, 1=negative)
-#define SET_MASK 0x10 // Set mask (0=no set, 1=set)
-#define SET_SENSE_MASK 0x20 // Set edge mask (0=positive, 1=negative)
-#define LATCH 0x40 // Latch type
-#define EN_SENSE_MASK 0x80 // Latch enable edge mask (0=positive, 1=negative)
+#define GATE 0x00 // Combinatorial gate (default)
+#define DFF 0x01 // Flip-flop (shared bit field)
+#define CLK_SENSE_MASK 0x02 // Clock edge mask (0=positive, 1=negative)
+#define RST_MASK 0x04 // Reset mask (0=no reset, 1=reset)
+#define RST_SENSE_MASK 0x08 // Reset edge mask (0=positive, 1=negative)
+#define SET_MASK 0x10 // Set mask (0=no set, 1=set)
+#define SET_SENSE_MASK 0x20 // Set edge mask (0=positive, 1=negative)
+#define LATCH 0x40 // Latch type
+#define EN_SENSE_MASK 0x80 // Latch enable edge mask (0=positive, 1=negative)
// Some names for cell types based on masks
-#define DFFCP 0x01 // Pos clock
-#define DFFCN 0x03 // Neg clock
-#define DFFCPRP 0x05 // Pos clock, Pos reset
-#define DFFCNRP 0x07 // Neg clock, Pos reset
-#define DFFCPRN 0x0d // Pos clock, Neg reset
-#define DFFCNRN 0x0f // Neg clock, Neg reset
-#define DFFCPSP 0x11 // Pos clock, Pos set
-#define DFFCNSP 0x13 // Neg clock, Pos set
-#define DFFCPRPSP 0x15 // Pos clock, Pos reset, Pos set
-#define DFFCNRPSP 0x17 // Neg clock, Pos reset, Pos set
-#define DFFCPRNSP 0x1d // Pos clock, Neg reset, Pos set
-#define DFFCNRNSP 0x1f // Neg clock, Neg reset, Pos set
-#define DFFCPSN 0x31 // Pos clock, Neg set
-#define DFFCNSN 0x33 // Neg clock, Neg set
-#define DFFCPRPSN 0x35 // Pos clock, Pos reset, Neg set
-#define DFFCNRPSN 0x37 // Neg clock, Pos reset, Neg set
-#define DFFCPRNSN 0x3d // Pos clock, Neg reset, Neg set
-#define DFFCNRNSN 0x3f // Neg clock, Neg reset, Neg set
+#define DFFCP 0x01 // Pos clock
+#define DFFCN 0x03 // Neg clock
+#define DFFCPRP 0x05 // Pos clock, Pos reset
+#define DFFCNRP 0x07 // Neg clock, Pos reset
+#define DFFCPRN 0x0d // Pos clock, Neg reset
+#define DFFCNRN 0x0f // Neg clock, Neg reset
+#define DFFCPSP 0x11 // Pos clock, Pos set
+#define DFFCNSP 0x13 // Neg clock, Pos set
+#define DFFCPRPSP 0x15 // Pos clock, Pos reset, Pos set
+#define DFFCNRPSP 0x17 // Neg clock, Pos reset, Pos set
+#define DFFCPRNSP 0x1d // Pos clock, Neg reset, Pos set
+#define DFFCNRNSP 0x1f // Neg clock, Neg reset, Pos set
+#define DFFCPSN 0x31 // Pos clock, Neg set
+#define DFFCNSN 0x33 // Neg clock, Neg set
+#define DFFCPRPSN 0x35 // Pos clock, Pos reset, Neg set
+#define DFFCNRPSN 0x37 // Neg clock, Pos reset, Neg set
+#define DFFCPRNSN 0x3d // Pos clock, Neg reset, Neg set
+#define DFFCNRNSN 0x3f // Neg clock, Neg reset, Neg set
/*--------------------------------------------------------------*/
-/* Liberty file database */
+/* Liberty file database */
/*--------------------------------------------------------------*/
// Types of array
// Array type 1: Propagation time
-#define OUTPUT_CAP 0
-#define TRANSITION_TIME 1
+#define OUTPUT_CAP 0
+#define TRANSITION_TIME 1
// Array type 2: Setup, hold, recovery, removal times
-#define RELATED_TIME 2
-#define CONSTRAINED_TIME 3
+#define RELATED_TIME 2
+#define CONSTRAINED_TIME 3
typedef struct _lutable *lutableptr;
typedef struct _lutable {
char *name;
- char invert; // 0 if times x caps, 1 if caps x times
- int var1; // Type of array in index1
- int var2; // Type of array in index2
- int size1; // Number of entries in time array
- int size2; // Number of entries in cap (or constrained timing) array
+ char invert; // 0 if times x caps, 1 if caps x times
+ int var1; // Type of array in index1
+ int var2; // Type of array in index2
+ int size1; // Number of entries in time array
+ int size2; // Number of entries in cap (or constrained timing) array
union {
- double *times; // Time array (units ps)
- double *rel; // Related pin transition time array (units ps)
+ double *times; // Time array (units ps)
+ double *rel; // Related pin transition time array (units ps)
} idx1;
union {
- double *caps; // Cap array (units fF)
- double *cons; // Constrained pin transition time array (units ps)
+ double *caps; // Cap array (units fF)
+ double *cons; // Constrained pin transition time array (units ps)
} idx2;
- double *values; // Matrix of values (used locally, not for templates)
+ double *values; // Matrix of values (used locally, not for templates)
lutableptr next;
} lutable;
@@ -225,16 +227,16 @@ typedef struct _pin {
char *name;
short type;
- double capr; // Capacitance for rising input
- double capf; // Capacitance for falling input (optional)
+ double capr; // Capacitance for rising input
+ double capf; // Capacitance for falling input (optional)
- short sense; // Sense (positive-unate, negative-unate, non-unate)
- lutable *propdelr; // Reference table for rising output prop delay relative to driver
- lutable *propdelf; // Reference table for falling output prop delay relative to driver
- lutable *transr; // Reference table for transition rise time
- lutable *transf; // Reference table for transition fall time
+ short sense; // Sense (positive-unate, negative-unate, non-unate)
+ lutable *propdelr; // Reference table for rising output prop delay relative to driver
+ lutable *propdelf; // Reference table for falling output prop delay relative to driver
+ lutable *transr; // Reference table for transition rise time
+ lutable *transf; // Reference table for transition fall time
- cellptr refcell; // Pointer back to parent cell
+ cellptr refcell; // Pointer back to parent cell
pinptr next;
} pin;
@@ -243,15 +245,15 @@ typedef struct _cell {
short type;
char *name;
char *function;
- pin *pins; /* List of input pins with timing info */
+ pin *pins; /* List of input pins with timing info */
double area;
- double maxtrans; /* Maximum transition time */
- double maxcap; /* Maximum allowable load */
+ double maxtrans; /* Maximum transition time */
+ double maxcap; /* Maximum allowable load */
cellptr next;
} cell;
/*--------------------------------------------------------------*/
-/* Verilog netlist database */
+/* Verilog netlist database */
/*--------------------------------------------------------------*/
typedef struct _net *netptr;
@@ -264,23 +266,24 @@ typedef struct _net {
short type;
int fanout;
connptr *receivers;
- double loadr; /* Total load capacitance for rising input */
- double loadf; /* Total load capacitance for falling input */
+ double loadr; /* Total load capacitance for rising input */
+ double loadf; /* Total load capacitance for falling input */
netptr next;
} net;
typedef struct _instance *instptr;
typedef struct _connect {
- double metric; /* Delay metric at connection */
+ double metric; /* Delay metric at connection */
+ double icDelay; /* interconnect delay in ps */
instptr refinst;
pinptr refpin;
netptr refnet;
- ddataptr tag; /* Tag value for checking for loops and endpoints */
- double *prvector; /* Prop delay rising (at load condition) vector */
- double *pfvector; /* Prop delay falling (at load condition) vector */
- double *trvector; /* Transition time rising (at load condition) vector */
- double *tfvector; /* Transition time falling (at load condition) vector */
+ ddataptr tag; /* Tag value for checking for loops and endpoints */
+ double *prvector; /* Prop delay rising (at load condition) vector */
+ double *pfvector; /* Prop delay falling (at load condition) vector */
+ double *trvector; /* Transition time rising (at load condition) vector */
+ double *tfvector; /* Transition time falling (at load condition) vector */
connptr next;
} connect;
@@ -297,19 +300,19 @@ typedef struct _instance {
typedef struct _btdata *btptr;
typedef struct _btdata {
- double delay; /* Propagation delay to this point */
- double trans; /* Transition time at this point */
- short dir; /* Edge direction at this point */
- connptr receiver; /* Receiver connection at end of path */
- int refcnt; /* Reference counter for backtrace data */
- btptr next; /* Path of propagation */
+ double delay; /* Propagation delay to this point */
+ double trans; /* Transition time at this point */
+ short dir; /* Edge direction at this point */
+ connptr receiver; /* Receiver connection at end of path */
+ int refcnt; /* Reference counter for backtrace data */
+ btptr next; /* Path of propagation */
} btdata;
// Linked list of backtrace records
typedef struct _delaydata {
- double delay; /* Total delay, including setup and clock skew */
- double trans; /* Transition time at destination, used to find setup */
+ double delay; /* Total delay, including setup and clock skew */
+ double trans; /* Transition time at destination, used to find setup */
btptr backtrace;
ddataptr next;
} delaydata;
@@ -326,12 +329,12 @@ typedef struct _connlist {
/* Global variables */
-unsigned char verbose; /* Level of debug output generated */
-unsigned char exhaustive; /* Exhaustive search mode */
+unsigned char verbose; /* Level of debug output generated */
+unsigned char exhaustive; /* Exhaustive search mode */
/*--------------------------------------------------------------*/
-/* Grab a token from the input */
-/* Return the token, or NULL if we have reached end-of-file. */
+/* Grab a token from the input */
+/* Return the token, or NULL if we have reached end-of-file. */
/*--------------------------------------------------------------*/
char *
@@ -349,109 +352,109 @@ advancetoken(FILE *flib, char delimiter)
commentblock = 0;
concat = 0;
nest = 0;
- while (1) { /* Keep processing until we get a token or hit EOF */
-
- if (lineptr != NULL && *lineptr == '/' && *(lineptr + 1) == '*') {
- commentblock = 1;
- }
-
- if (commentblock == 1) {
- if ((lptr = strstr(lineptr, "*/")) != NULL) {
- lineptr = lptr + 2;
- commentblock = 0;
- }
- else lineptr = NULL;
- }
-
- if (lineptr == NULL || *lineptr == '\n' || *lineptr == '\0') {
- result = fgets(line, LIB_LINE_MAX, flib);
- fileCurrentLine++;
- if (result == NULL) return NULL;
-
- /* Keep pulling stuff in if the line ends with a continuation character */
- lptr = line;
- while (*lptr != '\n' && *lptr != '\0') {
- if (*lptr == '\\') {
- // To be considered a line continuation marker, there must be
- // only whitespace or newline between the backslash and the
- // end of the string.
- char *eptr = lptr + 1;
- while (isspace(*eptr)) eptr++;
- if (*eptr == '\0') {
- result = fgets(lptr, LIB_LINE_MAX - (lptr - line), flib);
- fileCurrentLine++;
- if (result == NULL) break;
- }
- else
- lptr++;
- }
- else
- lptr++;
- }
- if (result == NULL) return NULL;
- lineptr = line;
- }
-
- if (commentblock == 1) continue;
-
- while (isspace(*lineptr)) lineptr++;
- if (concat == 0)
- tptr = token;
-
- // Find the next token and return just the token. Update linepos
- // to the position just beyond the token. All delimiters like
- // parentheses, quotes, etc., are returned as single tokens
-
- // If delimiter is declared, then we stop when we reach the
- // delimiter character, and return all the text preceding it
- // as the token. If delimiter is 0, then we look for standard
- // delimiters, and separate them out and return them as tokens
- // if found.
-
- while (1) {
- if (*lineptr == '\n' || *lineptr == '\0')
- break;
- if (*lineptr == '/' && *(lineptr + 1) == '*')
- break;
- if (delimiter != 0 && *lineptr == delimiter) {
- if (nest > 0)
- nest--;
- else
- break;
- }
-
- // Watch for nested delimiters!
- if (delimiter == '}' && *lineptr == '{') nest++;
- if (delimiter == ')' && *lineptr == '(') nest++;
-
- if (delimiter == 0)
- if (*lineptr == ' ' || *lineptr == '\t')
- break;
-
- if (delimiter == 0) {
- if (*lineptr == '(' || *lineptr == ')') {
- if (tptr == token) *tptr++ = *lineptr++;
- break;
- }
- if (*lineptr == '{' || *lineptr == '}') {
- if (tptr == token) *tptr++ = *lineptr++;
- break;
- }
- if (*lineptr == '\"' || *lineptr == ':' || *lineptr == ';') {
- if (tptr == token) *tptr++ = *lineptr++;
- break;
- }
- }
-
- *tptr++ = *lineptr++;
- }
- *tptr = '\0';
- if ((delimiter != 0) && (*lineptr != delimiter))
- concat = 1;
- else if ((delimiter != 0) && (*lineptr == delimiter))
- break;
- else if (tptr > token)
- break;
+ while (1) { /* Keep processing until we get a token or hit EOF */
+
+ if (lineptr != NULL && *lineptr == '/' && *(lineptr + 1) == '*') {
+ commentblock = 1;
+ }
+
+ if (commentblock == 1) {
+ if ((lptr = strstr(lineptr, "*/")) != NULL) {
+ lineptr = lptr + 2;
+ commentblock = 0;
+ }
+ else lineptr = NULL;
+ }
+
+ if (lineptr == NULL || *lineptr == '\n' || *lineptr == '\0') {
+ result = fgets(line, LIB_LINE_MAX, flib);
+ fileCurrentLine++;
+ if (result == NULL) return NULL;
+
+ /* Keep pulling stuff in if the line ends with a continuation character */
+ lptr = line;
+ while (*lptr != '\n' && *lptr != '\0') {
+ if (*lptr == '\\') {
+ // To be considered a line continuation marker, there must be
+ // only whitespace or newline between the backslash and the
+ // end of the string.
+ char *eptr = lptr + 1;
+ while (isspace(*eptr)) eptr++;
+ if (*eptr == '\0') {
+ result = fgets(lptr, LIB_LINE_MAX - (lptr - line), flib);
+ fileCurrentLine++;
+ if (result == NULL) break;
+ }
+ else
+ lptr++;
+ }
+ else
+ lptr++;
+ }
+ if (result == NULL) return NULL;
+ lineptr = line;
+ }
+
+ if (commentblock == 1) continue;
+
+ while (isspace(*lineptr)) lineptr++;
+ if (concat == 0)
+ tptr = token;
+
+ // Find the next token and return just the token. Update linepos
+ // to the position just beyond the token. All delimiters like
+ // parentheses, quotes, etc., are returned as single tokens
+
+ // If delimiter is declared, then we stop when we reach the
+ // delimiter character, and return all the text preceding it
+ // as the token. If delimiter is 0, then we look for standard
+ // delimiters, and separate them out and return them as tokens
+ // if found.
+
+ while (1) {
+ if (*lineptr == '\n' || *lineptr == '\0')
+ break;
+ if (*lineptr == '/' && *(lineptr + 1) == '*')
+ break;
+ if (delimiter != 0 && *lineptr == delimiter) {
+ if (nest > 0)
+ nest--;
+ else
+ break;
+ }
+
+ // Watch for nested delimiters!
+ if (delimiter == '}' && *lineptr == '{') nest++;
+ if (delimiter == ')' && *lineptr == '(') nest++;
+
+ if (delimiter == 0)
+ if (*lineptr == ' ' || *lineptr == '\t')
+ break;
+
+ if (delimiter == 0) {
+ if (*lineptr == '(' || *lineptr == ')') {
+ if (tptr == token) *tptr++ = *lineptr++;
+ break;
+ }
+ if (*lineptr == '{' || *lineptr == '}') {
+ if (tptr == token) *tptr++ = *lineptr++;
+ break;
+ }
+ if (*lineptr == '\"' || *lineptr == ':' || *lineptr == ';') {
+ if (tptr == token) *tptr++ = *lineptr++;
+ break;
+ }
+ }
+
+ *tptr++ = *lineptr++;
+ }
+ *tptr = '\0';
+ if ((delimiter != 0) && (*lineptr != delimiter))
+ concat = 1;
+ else if ((delimiter != 0) && (*lineptr == delimiter))
+ break;
+ else if (tptr > token)
+ break;
}
if (delimiter != 0) lineptr++;
@@ -461,17 +464,17 @@ advancetoken(FILE *flib, char delimiter)
// Final: Remove trailing whitespace
tptr = token + strlen(token) - 1;
while (isspace(*tptr)) {
- *tptr = '\0';
- tptr--;
+ *tptr = '\0';
+ tptr--;
}
return token;
}
/*--------------------------------------------------------------*/
-/* Parse a pin name. Check if the cell has a pin of that name, */
-/* and if not, add the pin to the cell, giving it default */
-/* values. The pin name may contain quotes, parentheses, or */
-/* negations ("!" or "'"); these should be ignored. */
+/* Parse a pin name. Check if the cell has a pin of that name, */
+/* and if not, add the pin to the cell, giving it default */
+/* values. The pin name may contain quotes, parentheses, or */
+/* negations ("!" or "'"); these should be ignored. */
/*--------------------------------------------------------------*/
pinptr parse_pin(cellptr newcell, char *token, short sense_predef)
@@ -483,17 +486,17 @@ pinptr parse_pin(cellptr newcell, char *token, short sense_predef)
pinname = token;
while (isspace(*pinname) || (*pinname == '\'') || (*pinname == '\"') ||
- (*pinname == '!') || (*pinname == '(') || (*pinname == ')'))
- pinname++;
+ (*pinname == '!') || (*pinname == '(') || (*pinname == ')'))
+ pinname++;
sptr = pinname;
while (*sptr != '\0') {
- if (isspace(*sptr) || (*sptr == '\'') || (*sptr == '\"') ||
- (*sptr == '!') || (*sptr == '(') || (*sptr == ')')) {
- *sptr = '\0';
- break;
- }
- sptr++;
+ if (isspace(*sptr) || (*sptr == '\'') || (*sptr == '\"') ||
+ (*sptr == '!') || (*sptr == '(') || (*sptr == ')')) {
+ *sptr = '\0';
+ break;
+ }
+ sptr++;
}
// Check if pin was already defined
@@ -501,10 +504,10 @@ pinptr parse_pin(cellptr newcell, char *token, short sense_predef)
lastpin = NULL;
newpin = newcell->pins;
while (newpin) {
- lastpin = newpin;
- if (!strcmp(newpin->name, pinname))
- return newpin;
- newpin = newpin->next;
+ lastpin = newpin;
+ if (!strcmp(newpin->name, pinname))
+ return newpin;
+ newpin = newpin->next;
}
// Pin was not defined, so create a new one and add it to the cell
@@ -515,11 +518,11 @@ pinptr parse_pin(cellptr newcell, char *token, short sense_predef)
newpin->next = NULL;
if (lastpin != NULL)
- lastpin->next = newpin;
+ lastpin->next = newpin;
else
- newcell->pins = newpin;
+ newcell->pins = newpin;
- newpin->type = INPUT; // The default; modified later, if not an input
+ newpin->type = INPUT; // The default; modified later, if not an input
newpin->capr = 0.0;
newpin->capf = 0.0;
newpin->sense = sense_predef; // Again, modified later if not true.
@@ -527,12 +530,12 @@ pinptr parse_pin(cellptr newcell, char *token, short sense_predef)
newpin->propdelf = NULL;
newpin->transr = NULL;
newpin->transf = NULL;
- newpin->refcell = newcell; // Create link back to cell
+ newpin->refcell = newcell; // Create link back to cell
return newpin;
}
/*--------------------------------------------------------------*/
-/* Create a new net record */
+/* Create a new net record */
/*--------------------------------------------------------------*/
netptr create_net(netptr *netlist) {
@@ -554,8 +557,8 @@ netptr create_net(netptr *netlist) {
}
/*----------------------------------------------------------------------*/
-/* Interpolate or extrapolate a vector from a time vs. capacitance */
-/* lookup table. */
+/* Interpolate or extrapolate a vector from a time vs. capacitance */
+/* lookup table. */
/*----------------------------------------------------------------------*/
double *table_collapse(lutableptr tableptr, double load)
@@ -569,7 +572,7 @@ double *table_collapse(lutableptr tableptr, double load)
// If the table is 1-dimensional, then just return a copy of the table.
if (tableptr->size2 <= 1) {
for (i = 0; i < tableptr->size1; i++) {
- *(vector + i) = *(tableptr->values + i);
+ *(vector + i) = *(tableptr->values + i);
}
return vector;
}
@@ -578,33 +581,33 @@ double *table_collapse(lutableptr tableptr, double load)
// entries, if extrapolating
if (load < tableptr->idx2.caps[0])
- j = 1;
+ j = 1;
else if (load >= tableptr->idx2.caps[tableptr->size2 - 1])
- j = tableptr->size2 - 1;
+ j = tableptr->size2 - 1;
else {
- for (j = 0; j < tableptr->size2; j++)
- if (tableptr->idx2.caps[j] > load)
- break;
+ for (j = 0; j < tableptr->size2; j++)
+ if (tableptr->idx2.caps[j] > load)
+ break;
}
cfrac = (load - tableptr->idx2.caps[j - 1]) /
- (tableptr->idx2.caps[j] - tableptr->idx2.caps[j - 1]);
+ (tableptr->idx2.caps[j] - tableptr->idx2.caps[j - 1]);
for (i = 0; i < tableptr->size1; i++) {
- // Interpolate value at cap load for each transition value
+ // Interpolate value at cap load for each transition value
- vlow = *(tableptr->values + i * tableptr->size1 + (j - 1));
- vhigh = *(tableptr->values + i * tableptr->size1 + j);
- *(vector + i) = vlow + (vhigh - vlow) * cfrac;
+ vlow = *(tableptr->values + i * tableptr->size1 + (j - 1));
+ vhigh = *(tableptr->values + i * tableptr->size1 + j);
+ *(vector + i) = vlow + (vhigh - vlow) * cfrac;
}
return vector;
}
/*----------------------------------------------------------------------*/
-/* Interpolate/extrapolate a delay or transition value from a vector of */
-/* values at a known output load. The original full 2D table contains */
-/* the transition time index values. */
+/* Interpolate/extrapolate a delay or transition value from a vector of */
+/* values at a known output load. The original full 2D table contains */
+/* the transition time index values. */
/*----------------------------------------------------------------------*/
double vector_get_value(lutableptr tableptr, double *vector, double trans)
@@ -616,20 +619,20 @@ double vector_get_value(lutableptr tableptr, double *vector, double trans)
// entries, if extrapolating
if (trans < tableptr->idx1.times[0])
- i = 1;
+ i = 1;
else if (trans >= tableptr->idx1.times[tableptr->size1 - 1])
- i = tableptr->size1 - 1;
+ i = tableptr->size1 - 1;
else {
- for (i = 0; i < tableptr->size1; i++)
- if (tableptr->idx1.times[i] > trans)
- break;
+ for (i = 0; i < tableptr->size1; i++)
+ if (tableptr->idx1.times[i] > trans)
+ break;
}
// Compute transition time as a fraction of the nearest table indexes
// for transition times
tfrac = (trans - tableptr->idx1.times[i - 1]) /
- (tableptr->idx1.times[i] - tableptr->idx1.times[i - 1]);
+ (tableptr->idx1.times[i] - tableptr->idx1.times[i - 1]);
// Interpolate value
vlow = *(vector + (i - 1));
@@ -639,8 +642,8 @@ double vector_get_value(lutableptr tableptr, double *vector, double trans)
}
/*----------------------------------------------------------------------*/
-/* Interpolate or extrapolate a value from a related time vs. */
-/* constrained time lookup table. */
+/* Interpolate or extrapolate a value from a related time vs. */
+/* constrained time lookup table. */
/*----------------------------------------------------------------------*/
double binomial_get_value(lutableptr tableptr, double rtrans, double ctrans)
@@ -648,54 +651,54 @@ double binomial_get_value(lutableptr tableptr, double rtrans, double ctrans)
int i, j;
double rfrac, cfrac, vlow, vhigh, valuel, valueh, value;
- /* Tables have been arranged such that idx1 is related time, */
+ /* Tables have been arranged such that idx1 is related time, */
/* idx2 is constrained time */
// Find time index entries bounding "rtrans", or the two nearest
// entries, if extrapolating
if (rtrans < tableptr->idx1.rel[0])
- i = 1;
+ i = 1;
else if (rtrans >= tableptr->idx1.rel[tableptr->size1 - 1])
- i = tableptr->size1 - 1;
+ i = tableptr->size1 - 1;
else {
- for (i = 0; i < tableptr->size1; i++)
- if (tableptr->idx1.rel[i] > rtrans)
- break;
+ for (i = 0; i < tableptr->size1; i++)
+ if (tableptr->idx1.rel[i] > rtrans)
+ break;
}
// Compute transition time as a fraction of the nearest table indexes
// for transition times
rfrac = (rtrans - tableptr->idx1.rel[i - 1]) /
- (tableptr->idx1.rel[i] - tableptr->idx1.rel[i - 1]);
+ (tableptr->idx1.rel[i] - tableptr->idx1.rel[i - 1]);
// 1-dimensional computation, if this table is 1-dimensional
if (tableptr->size2 == 0) {
- vlow = *(tableptr->values + (i - 1));
- vhigh = *(tableptr->values + i);
- value = vlow + (vhigh - vlow) * rfrac;
- return value;
+ vlow = *(tableptr->values + (i - 1));
+ vhigh = *(tableptr->values + i);
+ value = vlow + (vhigh - vlow) * rfrac;
+ return value;
}
// Find cons index entries bounding "ctrans", or the two nearest
// entries, if extrapolating
if (ctrans < tableptr->idx2.cons[0])
- j = 1;
+ j = 1;
else if (ctrans >= tableptr->idx2.cons[tableptr->size2 - 1])
- j = tableptr->size2 - 1;
+ j = tableptr->size2 - 1;
else {
- for (j = 0; j < tableptr->size2; j++)
- if (tableptr->idx2.cons[j] > ctrans)
- break;
+ for (j = 0; j < tableptr->size2; j++)
+ if (tableptr->idx2.cons[j] > ctrans)
+ break;
}
// Compute cons transition as a fraction of the nearest table indexes for cons
cfrac = (ctrans - tableptr->idx2.cons[j - 1]) /
- (tableptr->idx2.cons[j] - tableptr->idx2.cons[j - 1]);
+ (tableptr->idx2.cons[j] - tableptr->idx2.cons[j - 1]);
// Interpolate value at cons lower bound
vlow = *(tableptr->values + (i - 1) * tableptr->size1 + (j - 1));
@@ -713,13 +716,13 @@ double binomial_get_value(lutableptr tableptr, double rtrans, double ctrans)
}
/*----------------------------------------------------------------------*/
-/* Determine how the sense of a signal changes going from a gate's */
-/* input to its output. If the gate's input pin is positive unate */
-/* relative to the gate output, then the signal sense remains the same. */
-/* If it is negative unate, then the signal sense inverts. If it is */
-/* non-unate, then the signal sense becomes non-unate, and we calculate */
-/* timing for both edges from that point forward, always accepting the */
-/* maximum time. */
+/* Determine how the sense of a signal changes going from a gate's */
+/* input to its output. If the gate's input pin is positive unate */
+/* relative to the gate output, then the signal sense remains the same. */
+/* If it is negative unate, then the signal sense inverts. If it is */
+/* non-unate, then the signal sense becomes non-unate, and we calculate */
+/* timing for both edges from that point forward, always accepting the */
+/* maximum time. */
/*----------------------------------------------------------------------*/
short calc_dir(pinptr testpin, short dir)
@@ -730,44 +733,44 @@ short calc_dir(pinptr testpin, short dir)
if (testpin == NULL) return dir;
switch(dir) {
- case RISING:
- if (testpin->sense == SENSE_POSITIVE)
- outdir = RISING; /* rising input, rising output */
- else if (testpin->sense = SENSE_NEGATIVE)
- outdir = FALLING; /* rising input, falling output */
- else
- outdir = EITHER; /* output can be rising or falling */
- break;
- case FALLING:
- if (testpin->sense == SENSE_POSITIVE)
- outdir = FALLING; /* falling input, falling output */
- else if (testpin->sense = SENSE_NEGATIVE)
- outdir = RISING; /* falling input, rising output */
- else
- outdir = EITHER; /* output can be rising or falling */
- break;
- case EITHER:
- outdir = EITHER; /* output can be rising or falling */
- break;
+ case RISING:
+ if (testpin->sense == SENSE_POSITIVE)
+ outdir = RISING; /* rising input, rising output */
+ else if (testpin->sense = SENSE_NEGATIVE)
+ outdir = FALLING; /* rising input, falling output */
+ else
+ outdir = EITHER; /* output can be rising or falling */
+ break;
+ case FALLING:
+ if (testpin->sense == SENSE_POSITIVE)
+ outdir = FALLING; /* falling input, falling output */
+ else if (testpin->sense = SENSE_NEGATIVE)
+ outdir = RISING; /* falling input, rising output */
+ else
+ outdir = EITHER; /* output can be rising or falling */
+ break;
+ case EITHER:
+ outdir = EITHER; /* output can be rising or falling */
+ break;
}
return outdir;
}
/*----------------------------------------------------------------------*/
-/* Calculate the propagation delay from "testpin" to the output */
-/* of the gate to which "testpin" is an input. */
-/* */
-/* "sense" is a pointer to the sense at the input. SENSE_POSITIVE */
-/* indicates a rising edge at the pin, SENSE_NEGATIVE indicates a */
-/* falling edge at the pin. "sense" is updated to indicate if the */
-/* output transition is rising, falling, or unknown (SENSE_NONE). */
-/* */
-/* "loadnet" is a pointer to the net connected to the cell instance's */
-/* output pin. Load values will be taken from this net, depending on */
-/* the sense of the output. */
-/* */
-/* "testpin" is the pin receiving the input signal, and the pin record */
-/* containing the relevant timing tables. */
+/* Calculate the propagation delay from "testpin" to the output */
+/* of the gate to which "testpin" is an input. */
+/* */
+/* "sense" is a pointer to the sense at the input. SENSE_POSITIVE */
+/* indicates a rising edge at the pin, SENSE_NEGATIVE indicates a */
+/* falling edge at the pin. "sense" is updated to indicate if the */
+/* output transition is rising, falling, or unknown (SENSE_NONE). */
+/* */
+/* "loadnet" is a pointer to the net connected to the cell instance's */
+/* output pin. Load values will be taken from this net, depending on */
+/* the sense of the output. */
+/* */
+/* "testpin" is the pin receiving the input signal, and the pin record */
+/* containing the relevant timing tables. */
/*----------------------------------------------------------------------*/
double calc_prop_delay(double trans, connptr testconn, short sense, char minmax)
@@ -782,28 +785,28 @@ double calc_prop_delay(double trans, connptr testconn, short sense, char minmax)
if (testpin == NULL) return 0.0;
if (sense != SENSE_NEGATIVE) {
- if (testconn->prvector)
- propdelayr = vector_get_value(testpin->propdelr, testconn->prvector, trans);
- if (sense == SENSE_POSITIVE) return propdelayr;
+ if (testconn->prvector)
+ propdelayr = vector_get_value(testpin->propdelr, testconn->prvector, trans);
+ if (sense == SENSE_POSITIVE) return propdelayr;
}
if (sense != SENSE_POSITIVE) {
- if (testconn->pfvector)
- propdelayf = vector_get_value(testpin->propdelf, testconn->pfvector, trans);
- if (sense == SENSE_NEGATIVE) return propdelayf;
+ if (testconn->pfvector)
+ propdelayf = vector_get_value(testpin->propdelf, testconn->pfvector, trans);
+ if (sense == SENSE_NEGATIVE) return propdelayf;
}
if (minmax == MAXIMUM_TIME)
- return (propdelayr > propdelayf) ? propdelayr : propdelayf;
+ return (propdelayr > propdelayf) ? propdelayr : propdelayf;
else
- return (propdelayr < propdelayf) ? propdelayr : propdelayf;
+ return (propdelayr < propdelayf) ? propdelayr : propdelayf;
}
/*----------------------------------------------------------------------*/
-/* Calculate the transition time from "testpin" to the output */
-/* of the gate to which "testpin" is an input. This is equivalent to */
-/* the propagation delay calculation routine above, apart from using */
-/* the lookup tables for transition time instead of propagation delay. */
+/* Calculate the transition time from "testpin" to the output */
+/* of the gate to which "testpin" is an input. This is equivalent to */
+/* the propagation delay calculation routine above, apart from using */
+/* the lookup tables for transition time instead of propagation delay. */
/*----------------------------------------------------------------------*/
double calc_transition(double trans, connptr testconn, short sense, char minmax)
@@ -818,33 +821,33 @@ double calc_transition(double trans, connptr testconn, short sense, char minmax)
transf = 0.0;
if (sense != SENSE_NEGATIVE) {
- if (testconn->trvector)
- transr = vector_get_value(testpin->transr, testconn->trvector, trans);
- if (sense == SENSE_POSITIVE) return transr;
+ if (testconn->trvector)
+ transr = vector_get_value(testpin->transr, testconn->trvector, trans);
+ if (sense == SENSE_POSITIVE) return transr;
}
if (sense != SENSE_POSITIVE) {
- if (testconn->tfvector)
- transf = vector_get_value(testpin->transf, testconn->tfvector, trans);
- if (sense == SENSE_NEGATIVE) return transf;
+ if (testconn->tfvector)
+ transf = vector_get_value(testpin->transf, testconn->tfvector, trans);
+ if (sense == SENSE_NEGATIVE) return transf;
}
if (minmax == MAXIMUM_TIME)
- return (transr > transf) ? transr : transf;
+ return (transr > transf) ? transr : transf;
else
- return (transr < transf) ? transr : transf;
+ return (transr < transf) ? transr : transf;
}
/*----------------------------------------------------------------------*/
-/* Calculate the hold time for a flop input "testpin" relative to the */
-/* flop clock, where "trans" is the transition time of the signal at */
-/* "testpin", and "clktrans" is the transition time of the clock */
-/* signal at the clock pin. "sense" is the sense of the input signal */
-/* at "testpin". */
+/* Calculate the hold time for a flop input "testpin" relative to the */
+/* flop clock, where "trans" is the transition time of the signal at */
+/* "testpin", and "clktrans" is the transition time of the clock */
+/* signal at the clock pin. "sense" is the sense of the input signal */
+/* at "testpin". */
/*----------------------------------------------------------------------*/
double calc_hold_time(double trans, pinptr testpin, double clktrans, short sense,
- char minmax)
+ char minmax)
{
double holdr, holdf;
@@ -854,33 +857,33 @@ double calc_hold_time(double trans, pinptr testpin, double clktrans, short sense
holdf = 0.0;
if (sense != SENSE_NEGATIVE) {
- if (testpin->transr)
- holdr = binomial_get_value(testpin->transr, trans, clktrans);
- if (sense == SENSE_POSITIVE) return holdr;
+ if (testpin->transr)
+ holdr = binomial_get_value(testpin->transr, trans, clktrans);
+ if (sense == SENSE_POSITIVE) return holdr;
}
if (sense != SENSE_POSITIVE) {
- if (testpin->transf)
- holdf = binomial_get_value(testpin->transf, trans, clktrans);
- if (sense == SENSE_NEGATIVE) return holdf;
+ if (testpin->transf)
+ holdf = binomial_get_value(testpin->transf, trans, clktrans);
+ if (sense == SENSE_NEGATIVE) return holdf;
}
if (minmax == MAXIMUM_TIME)
- return (holdr > holdf) ? holdr : holdf;
+ return (holdr > holdf) ? holdr : holdf;
else
- return (holdr < holdf) ? holdr : holdf;
+ return (holdr < holdf) ? holdr : holdf;
}
/*----------------------------------------------------------------------*/
-/* Calculate the setup time for a flop input "testpin" relative to the */
-/* flop clock, where "trans" is the transition time of the signal at */
-/* "testpin", and "clktrans" is the transition time of the clock */
-/* signal at the clock pin. "sense" is the sense of the input signal */
-/* at "testpin". */
+/* Calculate the setup time for a flop input "testpin" relative to the */
+/* flop clock, where "trans" is the transition time of the signal at */
+/* "testpin", and "clktrans" is the transition time of the clock */
+/* signal at the clock pin. "sense" is the sense of the input signal */
+/* at "testpin". */
/*----------------------------------------------------------------------*/
double calc_setup_time(double trans, pinptr testpin, double clktrans, short sense,
- char minmax)
+ char minmax)
{
double setupr, setupf;
@@ -890,27 +893,27 @@ double calc_setup_time(double trans, pinptr testpin, double clktrans, short sens
setupf = 0.0;
if (sense != SENSE_NEGATIVE) {
- if (testpin->propdelr)
- setupr = binomial_get_value(testpin->propdelr, trans, clktrans);
- if (sense == SENSE_POSITIVE) return setupr;
+ if (testpin->propdelr)
+ setupr = binomial_get_value(testpin->propdelr, trans, clktrans);
+ if (sense == SENSE_POSITIVE) return setupr;
}
if (sense != SENSE_POSITIVE) {
- if (testpin->propdelf)
- setupf = binomial_get_value(testpin->propdelf, trans, clktrans);
- if (sense == SENSE_NEGATIVE) return setupf;
+ if (testpin->propdelf)
+ setupf = binomial_get_value(testpin->propdelf, trans, clktrans);
+ if (sense == SENSE_NEGATIVE) return setupf;
}
if (minmax == MAXIMUM_TIME)
- return (setupr > setupf) ? setupr : setupf;
+ return (setupr > setupf) ? setupr : setupf;
else
- return (setupr < setupf) ? setupr : setupf;
+ return (setupr < setupf) ? setupr : setupf;
}
/*--------------------------------------------------------------*/
-/* Find the path from a clock back to all inputs or flop */
-/* outputs. This list will be used to find nodes that are */
-/* common to other clocks. */
+/* Find the path from a clock back to all inputs or flop */
+/* outputs. This list will be used to find nodes that are */
+/* common to other clocks. */
/*--------------------------------------------------------------*/
void
@@ -935,23 +938,23 @@ find_clock_source(connptr testlink, btptr *clocklist, short dir)
clknet = testlink->refnet;
driver = clknet->driver;
- if (driver == NULL) return; /* Reached a module input */
+ if (driver == NULL) return; /* Reached a module input */
iupstream = driver->refinst;
- if (iupstream == NULL) return; /* Not supposed to happen? */
- if (driver->refpin->type & DFFOUT) return; /* Reached a flop output */
+ if (iupstream == NULL) return; /* Not supposed to happen? */
+ if (driver->refpin->type & DFFOUT) return; /* Reached a flop output */
if (driver->refpin->type & LATCHOUT) return; /* Reached a latch output */
for (iinput = iupstream->in_connects; iinput; iinput = iinput->next) {
- newdir = calc_dir(iinput->refpin, dir);
- find_clock_source(iinput, clocklist, newdir);
+ newdir = calc_dir(iinput->refpin, dir);
+ find_clock_source(iinput, clocklist, newdir);
}
}
/*--------------------------------------------------------------*/
-/* Find a net that is common to both "clocklist" and */
-/* "clock2list". If one exists, return a pointer to the */
-/* connection. */
+/* Find a net that is common to both "clocklist" and */
+/* "clock2list". If one exists, return a pointer to the */
+/* connection. */
/*--------------------------------------------------------------*/
netptr find_common_clock(btptr clocklist, btptr clock2list)
@@ -960,30 +963,30 @@ netptr find_common_clock(btptr clocklist, btptr clock2list)
for (srch1ptr = clocklist; srch1ptr; srch1ptr = srch1ptr->next)
for (srch2ptr = clock2list; srch2ptr; srch2ptr = srch2ptr->next)
- if (srch1ptr->receiver->refnet == srch2ptr->receiver->refnet)
- return srch1ptr->receiver->refnet;
+ if (srch1ptr->receiver->refnet == srch2ptr->receiver->refnet)
+ return srch1ptr->receiver->refnet;
return NULL;
}
/*--------------------------------------------------------------*/
-/* Determine the delay to a clock pin from the farthest point */
-/* back in the network, either to an input pin or the output of */
-/* another flop (e.g., a ripple counter). If there is more */
-/* than one such source (which can happen with, say, a gated */
-/* clock, because this routine will not differentiate between */
-/* the clock signal and the gating signal), then all sources */
-/* recorded (it is only necessary to find a common root of all */
-/* other related clocks downstream). */
-/* */
-/* This is a recursive routine, continuing to find all delays */
-/* through the circuit until it reaches "terminal". The */
-/* "delaylist" linked list is not modified by this routine. */
+/* Determine the delay to a clock pin from the farthest point */
+/* back in the network, either to an input pin or the output of */
+/* another flop (e.g., a ripple counter). If there is more */
+/* than one such source (which can happen with, say, a gated */
+/* clock, because this routine will not differentiate between */
+/* the clock signal and the gating signal), then all sources */
+/* recorded (it is only necessary to find a common root of all */
+/* other related clocks downstream). */
+/* */
+/* This is a recursive routine, continuing to find all delays */
+/* through the circuit until it reaches "terminal". The */
+/* "delaylist" linked list is not modified by this routine. */
/*--------------------------------------------------------------*/
void
find_clock_delay(int dir, double delay, double trans, connptr receiver,
- btptr clocklist, connptr terminal, char minmax) {
+ btptr clocklist, connptr terminal, char minmax) {
pinptr testpin;
netptr loadnet;
@@ -992,7 +995,7 @@ find_clock_delay(int dir, double delay, double trans, connptr receiver,
btptr testbtdata, newbtdata;
double newdelayr, newdelayf, newtransr, newtransf;
short outdir;
- int i;
+ int i;
testpin = receiver->refpin;
@@ -1000,85 +1003,85 @@ find_clock_delay(int dir, double delay, double trans, connptr receiver,
if (receiver != terminal) {
- testinst = receiver->refinst;
- testcell = (testpin) ? testpin->refcell : NULL;
-
- // Don't follow signal through any DFF pins
- if (testcell && (testcell->type & DFF)) return;
-
- // Compute delay from gate input to output
-
- outdir = calc_dir(testpin, dir);
- if (outdir & RISING) {
- newdelayr = delay + calc_prop_delay(trans, receiver, RISING, minmax);
- newtransr = calc_transition(trans, receiver, RISING, minmax);
- }
- if (outdir & FALLING) {
- newdelayf = delay + calc_prop_delay(trans, receiver, FALLING, minmax);
- newtransf = calc_transition(trans, receiver, FALLING, minmax);
- }
-
- loadnet = (testinst) ? testinst->out_connects->refnet : NULL;
- if (loadnet != NULL) {
- for (i = 0; i < loadnet->fanout; i++) {
- if (outdir & RISING)
- find_clock_delay(RISING, newdelayr, newtransr, loadnet->receivers[i],
- clocklist, terminal, minmax);
- if (outdir & FALLING)
- find_clock_delay(FALLING, newdelayf, newtransf, loadnet->receivers[i],
- clocklist, terminal, minmax);
- }
- }
+ testinst = receiver->refinst;
+ testcell = (testpin) ? testpin->refcell : NULL;
+
+ // Don't follow signal through any DFF pins
+ if (testcell && (testcell->type & DFF)) return;
+
+ // Compute delay from gate input to output
+
+ outdir = calc_dir(testpin, dir);
+ if (outdir & RISING) {
+ newdelayr = delay + calc_prop_delay(trans, receiver, RISING, minmax);
+ newtransr = calc_transition(trans, receiver, RISING, minmax);
+ }
+ if (outdir & FALLING) {
+ newdelayf = delay + calc_prop_delay(trans, receiver, FALLING, minmax);
+ newtransf = calc_transition(trans, receiver, FALLING, minmax);
+ }
+
+ loadnet = (testinst) ? testinst->out_connects->refnet : NULL;
+ if (loadnet != NULL) {
+ for (i = 0; i < loadnet->fanout; i++) {
+ if (outdir & RISING)
+ find_clock_delay(RISING, newdelayr, newtransr, loadnet->receivers[i],
+ clocklist, terminal, minmax);
+ if (outdir & FALLING)
+ find_clock_delay(FALLING, newdelayf, newtransf, loadnet->receivers[i],
+ clocklist, terminal, minmax);
+ }
+ }
}
else {
- /* Determine if receiver is in clocklist */
- for (testbtdata = clocklist; testbtdata; testbtdata = testbtdata->next) {
- if (testbtdata->receiver == receiver) {
- /* Is delay greater than that already recorded? If so, replace it */
- if (minmax == MAXIMUM_TIME) {
- if (delay > testbtdata->delay) {
- testbtdata->delay = delay;
- testbtdata->trans = trans;
- testbtdata->dir = dir;
- }
- }
- else {
- if (delay < testbtdata->delay) {
- testbtdata->delay = delay;
- testbtdata->trans = trans;
- testbtdata->dir = dir;
- }
- }
- break;
- }
- }
+ /* Determine if receiver is in clocklist */
+ for (testbtdata = clocklist; testbtdata; testbtdata = testbtdata->next) {
+ if (testbtdata->receiver == receiver) {
+ /* Is delay greater than that already recorded? If so, replace it */
+ if (minmax == MAXIMUM_TIME) {
+ if (delay > testbtdata->delay) {
+ testbtdata->delay = delay;
+ testbtdata->trans = trans;
+ testbtdata->dir = dir;
+ }
+ }
+ else {
+ if (delay < testbtdata->delay) {
+ testbtdata->delay = delay;
+ testbtdata->trans = trans;
+ testbtdata->dir = dir;
+ }
+ }
+ break;
+ }
+ }
}
}
/*--------------------------------------------------------------*/
-/* Determine the delay from input to output through a gate */
-/* */
-/* This is a recursive routine, continuing to find all delays */
-/* through the circuit until it reaches a terminal or flop */
-/* input. It is similar to find_clock_delay, but stops on all */
-/* terminal points found in the path, rather than stopping on */
-/* a specific connection. */
-/* */
-/* Also unlike find_clock_delay, the routine keeps a running */
-/* record of the path followed from the source, as a character */
-/* string. When a terminal is found, the path and delay are */
-/* saved and added to "delaylist". After the recursive search, */
-/* "delaylist" contains a list of all paths starting from the */
-/* original connection "receiver" and ending on a clock or an */
-/* output pin. Where multiple paths exist between source and */
-/* destination, only the path with the longest delay is kept. */
-/* */
-/* Return the number of new paths recorded. */
+/* Determine the delay from input to output through a gate */
+/* */
+/* This is a recursive routine, continuing to find all delays */
+/* through the circuit until it reaches a terminal or flop */
+/* input. It is similar to find_clock_delay, but stops on all */
+/* terminal points found in the path, rather than stopping on */
+/* a specific connection. */
+/* */
+/* Also unlike find_clock_delay, the routine keeps a running */
+/* record of the path followed from the source, as a character */
+/* string. When a terminal is found, the path and delay are */
+/* saved and added to "delaylist". After the recursive search, */
+/* "delaylist" contains a list of all paths starting from the */
+/* original connection "receiver" and ending on a clock or an */
+/* output pin. Where multiple paths exist between source and */
+/* destination, only the path with the longest delay is kept. */
+/* */
+/* Return the number of new paths recorded. */
/*--------------------------------------------------------------*/
int find_path_delay(int dir, double delay, double trans, connptr receiver,
- btptr backtrace, ddataptr *delaylist, char minmax) {
+ btptr backtrace, ddataptr *delaylist, char minmax) {
pinptr testpin;
netptr loadnet;
@@ -1089,7 +1092,7 @@ int find_path_delay(int dir, double delay, double trans, connptr receiver,
double newdelayr, newdelayf, newtransr, newtransf;
short outdir;
char replace;
- int i, numpaths;
+ int i, numpaths;
numpaths = 0;
testpin = receiver->refpin;
@@ -1106,14 +1109,14 @@ int find_path_delay(int dir, double delay, double trans, connptr receiver,
// although it will typically vary by less than an average gate delay.
if (!exhaustive) {
- if (minmax == MAXIMUM_TIME) {
- if (delay <= receiver->metric)
- return numpaths;
- }
- else {
- if (delay >= receiver->metric)
- return numpaths;
- }
+ if (minmax == MAXIMUM_TIME) {
+ if (delay <= receiver->metric)
+ return numpaths;
+ }
+ else {
+ if (delay >= receiver->metric)
+ return numpaths;
+ }
}
// Check for a logic loop, and truncate the path to avoid infinite
@@ -1125,10 +1128,10 @@ int find_path_delay(int dir, double delay, double trans, connptr receiver,
// Record this position and delay/transition information
newbtdata = (btptr)malloc(sizeof(btdata));
- newbtdata->delay = delay;
+ newbtdata->receiver = receiver;
+ newbtdata->delay = delay + newbtdata->receiver->icDelay;
newbtdata->trans = trans;
newbtdata->dir = dir;
- newbtdata->receiver = receiver;
newbtdata->refcnt = 1;
newbtdata->next = backtrace;
@@ -1138,93 +1141,93 @@ int find_path_delay(int dir, double delay, double trans, connptr receiver,
if ((backtrace == NULL) || (testpin && ((testpin->type & REGISTER_IN) == 0))) {
- testinst = receiver->refinst;
- testcell = (testpin) ? testpin->refcell : NULL;
-
- // Compute delay from gate input to output
-
- outdir = calc_dir(testpin, dir);
- if (outdir & RISING) {
- newdelayr = delay + calc_prop_delay(trans, receiver, RISING, minmax);
- newtransr = calc_transition(trans, receiver, RISING, minmax);
- }
- if (outdir & FALLING) {
- newdelayf = delay + calc_prop_delay(trans, receiver, FALLING, minmax);
- newtransf = calc_transition(trans, receiver, FALLING, minmax);
- }
-
- loadnet = (testinst) ? testinst->out_connects->refnet : receiver->refnet;
- for (i = 0; i < loadnet->fanout; i++) {
- if (outdir & RISING)
- numpaths += find_path_delay(RISING, newdelayr, newtransr,
- loadnet->receivers[i], newbtdata, delaylist, minmax);
- if (outdir & FALLING)
- numpaths += find_path_delay(FALLING, newdelayf, newtransf,
- loadnet->receivers[i], newbtdata, delaylist, minmax);
- }
- receiver->tag = NULL;
+ testinst = receiver->refinst;
+ testcell = (testpin) ? testpin->refcell : NULL;
+
+ // Compute delay from gate input to output
+
+ outdir = calc_dir(testpin, dir);
+ if (outdir & RISING) {
+ newdelayr = delay + calc_prop_delay(trans, receiver, RISING, minmax);
+ newtransr = calc_transition(trans, receiver, RISING, minmax);
+ }
+ if (outdir & FALLING) {
+ newdelayf = delay + calc_prop_delay(trans, receiver, FALLING, minmax);
+ newtransf = calc_transition(trans, receiver, FALLING, minmax);
+ }
+
+ loadnet = (testinst) ? testinst->out_connects->refnet : receiver->refnet;
+ for (i = 0; i < loadnet->fanout; i++) {
+ if (outdir & RISING)
+ numpaths += find_path_delay(RISING, newdelayr, newtransr,
+ loadnet->receivers[i], newbtdata, delaylist, minmax);
+ if (outdir & FALLING)
+ numpaths += find_path_delay(FALLING, newdelayf, newtransf,
+ loadnet->receivers[i], newbtdata, delaylist, minmax);
+ }
+ receiver->tag = NULL;
}
else {
- /* Is receiver already in delaylist? */
- if ((receiver->tag != (ddataptr)(-1)) && (receiver->tag != NULL)) {
-
- /* Position in delaylist is recorded in tag field */
- testddata = receiver->tag;
-
- if (testddata->backtrace->receiver == receiver) {
- replace = 0;
- if (minmax == MAXIMUM_TIME) {
- /* Is delay greater than that already recorded? If so, replace it */
- if (delay > testddata->backtrace->delay)
- replace = 1;
- }
- else {
- /* Is delay less than that already recorded? If so, replace it */
- if (delay < testddata->backtrace->delay)
- replace = 1;
- }
- if (replace) {
-
- /* Remove the existing path record and replace it */
- while (testddata->backtrace != NULL) {
- freebt = testddata->backtrace;
- testddata->backtrace = testddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt <= 0) free(freebt);
- }
- testddata->backtrace = newbtdata;
-
- /* Increment the refcounts along the backtrace */
- for (testbt = newbtdata; testbt; testbt = testbt->next)
- testbt->refcnt++;
- }
- }
- else
- fprintf(stderr, "ERROR: Bad endpoint tag!\n");
- }
- else
- testddata = NULL;
-
- // If we have found a propagation path from source to dest,
- // record it in delaylist.
-
- if (testddata == NULL) {
- numpaths++;
- newddata = (ddataptr)malloc(sizeof(delaydata));
- newddata->delay = 0.0;
- newddata->trans = 0.0;
- newddata->backtrace = newbtdata;
- newddata->next = *delaylist;
- *delaylist = newddata;
-
- /* Mark the receiver as having been visited */
- receiver->tag = *delaylist;
-
- /* Increment the refcounts along the backtrace */
- for (testbt = newbtdata; testbt; testbt = testbt->next)
- testbt->refcnt++;
- }
+ /* Is receiver already in delaylist? */
+ if ((receiver->tag != (ddataptr)(-1)) && (receiver->tag != NULL)) {
+
+ /* Position in delaylist is recorded in tag field */
+ testddata = receiver->tag;
+
+ if (testddata->backtrace->receiver == receiver) {
+ replace = 0;
+ if (minmax == MAXIMUM_TIME) {
+ /* Is delay greater than that already recorded? If so, replace it */
+ if (delay > testddata->backtrace->delay)
+ replace = 1;
+ }
+ else {
+ /* Is delay less than that already recorded? If so, replace it */
+ if (delay < testddata->backtrace->delay)
+ replace = 1;
+ }
+ if (replace) {
+
+ /* Remove the existing path record and replace it */
+ while (testddata->backtrace != NULL) {
+ freebt = testddata->backtrace;
+ testddata->backtrace = testddata->backtrace->next;
+ freebt->refcnt--;
+ if (freebt->refcnt <= 0) free(freebt);
+ }
+ testddata->backtrace = newbtdata;
+
+ /* Increment the refcounts along the backtrace */
+ for (testbt = newbtdata; testbt; testbt = testbt->next)
+ testbt->refcnt++;
+ }
+ }
+ else
+ fprintf(stderr, "ERROR: Bad endpoint tag!\n");
+ }
+ else
+ testddata = NULL;
+
+ // If we have found a propagation path from source to dest,
+ // record it in delaylist.
+
+ if (testddata == NULL) {
+ numpaths++;
+ newddata = (ddataptr)malloc(sizeof(delaydata));
+ newddata->delay = 0.0;
+ newddata->trans = 0.0;
+ newddata->backtrace = newbtdata;
+ newddata->next = *delaylist;
+ *delaylist = newddata;
+
+ /* Mark the receiver as having been visited */
+ receiver->tag = *delaylist;
+
+ /* Increment the refcounts along the backtrace */
+ for (testbt = newbtdata; testbt; testbt = testbt->next)
+ testbt->refcnt++;
+ }
}
@@ -1235,12 +1238,12 @@ int find_path_delay(int dir, double delay, double trans, connptr receiver,
}
/*--------------------------------------------------------------*/
-/* Search the list "clocklist" for all points that are module */
-/* inputs or flop outputs, and compute the worst-case */
-/* transition time downstream at testlink. */
-/* */
-/* Return a pointer to the ddataptr entry that contains the */
-/* worst-case transition time. */
+/* Search the list "clocklist" for all points that are module */
+/* inputs or flop outputs, and compute the worst-case */
+/* transition time downstream at testlink. */
+/* */
+/* Return a pointer to the ddataptr entry that contains the */
+/* worst-case transition time. */
/*--------------------------------------------------------------*/
btptr find_clock_transition(btptr clocklist, connptr testlink, short dir, char minmax)
@@ -1252,18 +1255,18 @@ btptr find_clock_transition(btptr clocklist, connptr testlink, short dir, char m
// Find out where testlink is in clocklist, and save the position.
for (testclock = clocklist; testclock; testclock = testclock->next) {
- if (testclock->receiver == testlink) {
- testlinkptr = testclock;
- break;
- }
+ if (testclock->receiver == testlink) {
+ testlinkptr = testclock;
+ break;
+ }
}
- if (testclock == NULL) return NULL; // Error---testlink wasn't in clocklist!
+ if (testclock == NULL) return NULL; // Error---testlink wasn't in clocklist!
for (testclock = clocklist; testclock; testclock = testclock->next) {
- testconn = testclock->receiver;
- tdriver = 0.0; // to-do: set to default input transition time
- find_clock_delay(testlinkptr->dir, 0.0, tdriver, testconn, clocklist, testlink,
- minmax);
+ testconn = testclock->receiver;
+ tdriver = 0.0; // to-do: set to default input transition time
+ find_clock_delay(testlinkptr->dir, 0.0, tdriver, testconn, clocklist, testlink,
+ minmax);
}
// Return the linkptr containing the recorded transition time from
@@ -1273,9 +1276,9 @@ btptr find_clock_transition(btptr clocklist, connptr testlink, short dir, char m
}
/*--------------------------------------------------------------*/
-/* Given an instance record, find the pin of the instance that */
-/* is the clock, if the instance is a flop. If the instance is */
-/* not a flop, return NULL. */
+/* Given an instance record, find the pin of the instance that */
+/* is the clock, if the instance is a flop. If the instance is */
+/* not a flop, return NULL. */
/*--------------------------------------------------------------*/
connptr find_register_clock(instptr testinst)
@@ -1283,16 +1286,16 @@ connptr find_register_clock(instptr testinst)
connptr testconn;
for (testconn = testinst->in_connects; testconn; testconn = testconn->next)
- if (testconn->refpin && (testconn->refpin->type & DFFCLK))
- return testconn;
+ if (testconn->refpin && (testconn->refpin->type & DFFCLK))
+ return testconn;
return NULL;
}
/*--------------------------------------------------------------*/
-/* Given an edge direction (RISING or FALLING) at a source net, */
-/* and given a destination net, find the sense of the signal */
-/* when it arrives at the destination net. */
+/* Given an edge direction (RISING or FALLING) at a source net, */
+/* and given a destination net, find the sense of the signal */
+/* when it arrives at the destination net. */
/*--------------------------------------------------------------*/
short find_edge_dir(short dir, netptr sourcenet, netptr destnet) {
@@ -1303,53 +1306,53 @@ short find_edge_dir(short dir, netptr sourcenet, netptr destnet) {
netptr nextnet;
for (i = 0; i < sourcenet->fanout; i++) {
- testconn = sourcenet->receivers[i];
- testinst = testconn->refinst;
- if (testinst == NULL) continue;
- if (testconn->refpin == NULL) continue;
- if ((testconn->refpin->type & REGISTER_IN) != 0) continue;
- nextconn = testinst->out_connects;
- nextnet = nextconn->refnet;
- outdir = calc_dir(testconn->refpin, dir);
- if (nextnet == destnet) return outdir;
-
- rdir = find_edge_dir(outdir, nextnet, destnet);
- if (rdir != 0) return rdir;
+ testconn = sourcenet->receivers[i];
+ testinst = testconn->refinst;
+ if (testinst == NULL) continue;
+ if (testconn->refpin == NULL) continue;
+ if ((testconn->refpin->type & REGISTER_IN) != 0) continue;
+ nextconn = testinst->out_connects;
+ nextnet = nextconn->refnet;
+ outdir = calc_dir(testconn->refpin, dir);
+ if (nextnet == destnet) return outdir;
+
+ rdir = find_edge_dir(outdir, nextnet, destnet);
+ if (rdir != 0) return rdir;
}
return 0;
}
/*--------------------------------------------------------------*/
-/* Search all paths from the clocked data outputs of */
-/* "clockedlist" to either output pins or data inputs of other */
-/* flops. */
-/* */
-/* Return a master list of all backtraces in "masterlist". */
-/* */
-/* Return value is the number of paths recorded in masterlist. */
-/* */
-/* If minmax == MAXIMUM_TIME, return the maximum delay. */
-/* If minmax == MINIMUM_TIME, return the minimum delay. */
+/* Search all paths from the clocked data outputs of */
+/* "clockedlist" to either output pins or data inputs of other */
+/* flops. */
+/* */
+/* Return a master list of all backtraces in "masterlist". */
+/* */
+/* Return value is the number of paths recorded in masterlist. */
+/* */
+/* If minmax == MAXIMUM_TIME, return the maximum delay. */
+/* If minmax == MINIMUM_TIME, return the minimum delay. */
/*--------------------------------------------------------------*/
int find_clock_to_term_paths(connlistptr clockedlist, ddataptr *masterlist, netptr netlist,
- char minmax)
+ char minmax)
{
- netptr commonclock, testnet;
+ netptr commonclock, testnet;
connptr testconn, thisconn;
connlistptr testlink;
pinptr testpin;
cellptr testcell;
instptr testinst;
- btptr clocklist, clock2list, backtrace, freebt;
- btptr selectedsource, selecteddest;
+ btptr clocklist, clock2list, backtrace, freebt;
+ btptr selectedsource, selecteddest;
ddataptr delaylist, testddata;
- ddataptr freeddata;
+ ddataptr freeddata;
- short srcdir, destdir; // Signal direction in/out
- double tdriver, setupdelay, holddelay;
- char clk_sense_inv, clk_invert;
- int numpaths, n, i;
+ short srcdir, destdir; // Signal direction in/out
+ double tdriver, setupdelay, holddelay;
+ char clk_sense_inv, clk_invert;
+ int numpaths, n, i;
delaylist = NULL;
clocklist = NULL;
@@ -1358,264 +1361,264 @@ int find_clock_to_term_paths(connlistptr clockedlist, ddataptr *masterlist, netp
numpaths = 0;
for (testlink = clockedlist; testlink; testlink = testlink->next) {
- // Remove all tags and reset delay metrics before each run
-
- for (testnet = netlist; testnet; testnet = testnet->next) {
- for (i = 0; i < testnet->fanout; i++) {
- testconn = testnet->receivers[i];
- testconn->tag = NULL;
- if (minmax == MAXIMUM_TIME)
- testconn->metric = -1.0;
- else
- testconn->metric = 1E50;
- }
- }
-
- thisconn = testlink->connection;
- testpin = thisconn->refpin;
- if (testpin) {
- testcell = testpin->refcell;
-
- // Sense is positive for rising edge-triggered flops, negative for
- // falling edge-triggered flops
- srcdir = (testcell->type & CLK_SENSE_MASK) ? FALLING : RISING;
-
- // Find the sources of the clock at the path start
- find_clock_source(thisconn, &clocklist, srcdir);
-
- // Find the clock source with the worst-case transition time at testlink
- // (Note: For maximum path delay, find minimum clock transistion, and vice versa)
- selectedsource = find_clock_transition(clocklist, thisconn, srcdir, ~minmax);
- if (selectedsource == NULL)
- tdriver = 0.0;
- else
- tdriver = selectedsource->trans;
-
- // Report on paths and their maximum delays
- if (verbose > 0)
- fprintf(stdout, "Paths starting at flop \"%s\" clock:\n\n",
- thisconn->refinst->name);
-
- }
- else {
- // Connection is an input pin; must calculate both rising and falling edges.
- srcdir = EITHER;
- tdriver = 0.0; // To-do: use designated input transition time
-
- // Report on paths and their maximum delays
- if (verbose > 0)
- fprintf(stdout, "Paths starting at input pin \"%s\"\n\n",
- thisconn->refnet->name);
- }
-
- if (verbose > 0) fflush(stdout);
-
- // Find all paths from "thisconn" to output or a flop input, and compute delay
- n = find_path_delay(srcdir, 0.0, tdriver, thisconn, NULL, &delaylist, minmax);
- numpaths += n;
-
- if (verbose > 0) fprintf(stdout, "%d paths traced (%d total).\n\n", n, numpaths);
-
- for (testddata = delaylist; testddata; testddata = testddata->next) {
- // Copy last backtrace delay to testddata.
- testddata->delay = testddata->backtrace->delay;
- testddata->trans = testddata->backtrace->trans;
- testinst = testddata->backtrace->receiver->refinst;
-
- if (testinst != NULL) {
- // Find the sources of the clock at the path end
- destdir = (testinst->refcell->type & CLK_SENSE_MASK) ? FALLING : RISING;
- testconn = find_register_clock(testinst);
- // If testconn is NULL, this is not a register (latch, maybe?)
- if (testconn == NULL) continue;
- find_clock_source(testconn, &clock2list, destdir);
- selecteddest = find_clock_transition(clock2list, testconn, destdir, ~minmax);
-
- // Find the connection that is common to both clocks
- commonclock = find_common_clock(clocklist, clock2list);
- if (commonclock == NULL) {
- // Warn about asynchronous clock sources
- if (verbose > 0) {
- fflush(stdout);
- fprintf(stderr, "Independent clock nets \"%s\" and \"%s\""
- " drive related gates!\n",
- testconn->refnet->name, thisconn->refnet->name);
- }
- clk_invert = -1;
- }
- else {
- // Add or subtract difference in arrival times between source and
- // destination clocks
-
- if (selecteddest != NULL && selectedsource != NULL) {
- testddata->delay += selecteddest->delay;
- testddata->delay -= selectedsource->delay;
-
- /* Check if the clock signal arrives at both flops with the */
- /* same edge type (both rising or both falling). */
-
- clk_invert = (find_edge_dir(RISING, commonclock,
- selectedsource->receiver->refnet) ==
- find_edge_dir(RISING, commonclock,
- selecteddest->receiver->refnet)) ? 0 : 1;
- }
-
- if (minmax == MAXIMUM_TIME) {
- // Add setup time for destination clocks
- setupdelay = calc_setup_time(testddata->trans,
- testddata->backtrace->receiver->refpin,
- selecteddest->trans,
- testddata->backtrace->dir, minmax);
- testddata->delay += setupdelay;
- }
- else {
- // Subtract hold time for destination clocks
- holddelay = calc_hold_time(testddata->trans,
- testddata->backtrace->receiver->refpin,
- selecteddest->trans,
- testddata->backtrace->dir, minmax);
- testddata->delay -= holddelay;
- }
-
- if (verbose > 0)
- fprintf(stdout, "Path terminated on flop \"%s\" input with max delay %g ps\n",
- testconn->refinst->name, testddata->delay);
-
- for (backtrace = testddata->backtrace; backtrace->next;
- backtrace = backtrace->next) {
- if (verbose > 0)
- fprintf(stdout, " %g (%s) %s/%s -> %s/%s\n",
- backtrace->delay,
- backtrace->receiver->refnet->name,
- backtrace->receiver->refnet->driver->refinst->name,
- backtrace->receiver->refnet->driver->refpin->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refpin->name);
- }
- if (verbose > 0)
- fprintf(stdout, " 000.000 (%s) %s/%s -> %s/%s\n",
- backtrace->receiver->refnet->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refpin->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refinst->out_connects->refpin->name);
-
- if (selecteddest != NULL && selectedsource != NULL) {
- if (verbose > 0) {
- if (selectedsource->receiver->refnet != selecteddest->receiver->refnet) {
- fprintf(stdout, " %g %s to %s clock skew\n",
- selecteddest->delay - selectedsource->delay,
- selectedsource->receiver->refnet->name,
- selecteddest->receiver->refnet->name);
- }
- }
-
- /* Check if the flops have the same clock sense */
- /* (both are clock rising edge or both are clock falling edge type) */
-
- if ((testinst->refcell->type & CLK_SENSE_MASK) !=
- (backtrace->receiver->refinst->refcell->type
- & CLK_SENSE_MASK))
- clk_sense_inv = 1;
- else
- clk_sense_inv = 0;
-
- /* If the two flops don't clock at the same time, then issue a */
- /* warning that the slack time loses half a clock period. */
-
- if ((verbose > 0) && (clk_invert != -1) && (clk_sense_inv != clk_invert)) {
- fprintf(stdout, " Clocks are inverted relative to one another,\n");
- fprintf(stdout, " implying a maximum propagation delay of 1/2 period.\n");
- }
- }
- if (selecteddest != NULL && selectedsource != NULL) {
- if (verbose > 0) {
- if (minmax == MAXIMUM_TIME)
- fprintf(stdout, " %g setup time at destination\n", setupdelay);
- else
- fprintf(stdout, " %g hold time at destination\n", holddelay);
- }
- }
-
- if (verbose > 0) fprintf(stdout, "\n");
- }
- }
- else if (verbose > 0) {
- fprintf(stdout, "Path terminated on output \"%s\" with max delay %g ps\n",
- testddata->backtrace->receiver->refnet->name, testddata->delay);
-
- backtrace = testddata->backtrace;
- fprintf(stdout, " %g (%s) %s/%s -> [output pin]\n",
- backtrace->delay,
- backtrace->receiver->refnet->name,
- backtrace->receiver->refnet->driver->refinst->name,
- backtrace->receiver->refnet->driver->refpin->name);
-
- for (backtrace = backtrace->next; backtrace->next; backtrace = backtrace->next) {
- fprintf(stdout, " %g (%s) %s/%s -> %s/%s\n",
- backtrace->delay,
- backtrace->receiver->refnet->name,
- backtrace->receiver->refnet->driver->refinst->name,
- backtrace->receiver->refnet->driver->refpin->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refpin->name);
- }
- fprintf(stdout, " 000.000 (%s) %s/%s -> %s/%s\n\n",
- backtrace->receiver->refnet->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refpin->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refinst->out_connects->refpin->name);
- }
-
- // Clean up clock2list
- while (clock2list != NULL) {
- freebt = clock2list;
- clock2list = clock2list->next;
- free(freebt);
- }
- }
-
- // Link delaylist data to the beginning of masterlist, and null out
- // delaylist for the next set of paths.
-
- if (delaylist) {
- for (testddata = delaylist; testddata->next; testddata = testddata->next);
- testddata->next = *masterlist;
- *masterlist = delaylist;
- delaylist = NULL;
- }
-
- // Free up clocklist
- while (clocklist != NULL) {
- freebt = clocklist;
- clocklist = clocklist->next;
- free(freebt);
- }
+ // Remove all tags and reset delay metrics before each run
+
+ for (testnet = netlist; testnet; testnet = testnet->next) {
+ for (i = 0; i < testnet->fanout; i++) {
+ testconn = testnet->receivers[i];
+ testconn->tag = NULL;
+ if (minmax == MAXIMUM_TIME)
+ testconn->metric = -1.0;
+ else
+ testconn->metric = 1E50;
+ }
+ }
+
+ thisconn = testlink->connection;
+ testpin = thisconn->refpin;
+ if (testpin) {
+ testcell = testpin->refcell;
+
+ // Sense is positive for rising edge-triggered flops, negative for
+ // falling edge-triggered flops
+ srcdir = (testcell->type & CLK_SENSE_MASK) ? FALLING : RISING;
+
+ // Find the sources of the clock at the path start
+ find_clock_source(thisconn, &clocklist, srcdir);
+
+ // Find the clock source with the worst-case transition time at testlink
+ // (Note: For maximum path delay, find minimum clock transistion, and vice versa)
+ selectedsource = find_clock_transition(clocklist, thisconn, srcdir, ~minmax);
+ if (selectedsource == NULL)
+ tdriver = 0.0;
+ else
+ tdriver = selectedsource->trans;
+
+ // Report on paths and their maximum delays
+ if (verbose > 0)
+ fprintf(stdout, "Paths starting at flop \"%s\" clock:\n\n",
+ thisconn->refinst->name);
+
+ }
+ else {
+ // Connection is an input pin; must calculate both rising and falling edges.
+ srcdir = EITHER;
+ tdriver = 0.0; // To-do: use designated input transition time
+
+ // Report on paths and their maximum delays
+ if (verbose > 0)
+ fprintf(stdout, "Paths starting at input pin \"%s\"\n\n",
+ thisconn->refnet->name);
+ }
+
+ if (verbose > 0) fflush(stdout);
+
+ // Find all paths from "thisconn" to output or a flop input, and compute delay
+ n = find_path_delay(srcdir, 0.0, tdriver, thisconn, NULL, &delaylist, minmax);
+ numpaths += n;
+
+ if (verbose > 0) fprintf(stdout, "%d paths traced (%d total).\n\n", n, numpaths);
+
+ for (testddata = delaylist; testddata; testddata = testddata->next) {
+ // Copy last backtrace delay to testddata.
+ testddata->delay = testddata->backtrace->delay;
+ testddata->trans = testddata->backtrace->trans;
+ testinst = testddata->backtrace->receiver->refinst;
+
+ if (testinst != NULL) {
+ // Find the sources of the clock at the path end
+ destdir = (testinst->refcell->type & CLK_SENSE_MASK) ? FALLING : RISING;
+ testconn = find_register_clock(testinst);
+ // If testconn is NULL, this is not a register (latch, maybe?)
+ if (testconn == NULL) continue;
+ find_clock_source(testconn, &clock2list, destdir);
+ selecteddest = find_clock_transition(clock2list, testconn, destdir, ~minmax);
+
+ // Find the connection that is common to both clocks
+ commonclock = find_common_clock(clocklist, clock2list);
+ if (commonclock == NULL) {
+ // Warn about asynchronous clock sources
+ if (verbose > 0) {
+ fflush(stdout);
+ fprintf(stderr, "Independent clock nets \"%s\" and \"%s\""
+ " drive related gates!\n",
+ testconn->refnet->name, thisconn->refnet->name);
+ }
+ clk_invert = -1;
+ }
+ else {
+ // Add or subtract difference in arrival times between source and
+ // destination clocks
+
+ if (selecteddest != NULL && selectedsource != NULL) {
+ testddata->delay += selecteddest->delay;
+ testddata->delay -= selectedsource->delay;
+
+ /* Check if the clock signal arrives at both flops with the */
+ /* same edge type (both rising or both falling). */
+
+ clk_invert = (find_edge_dir(RISING, commonclock,
+ selectedsource->receiver->refnet) ==
+ find_edge_dir(RISING, commonclock,
+ selecteddest->receiver->refnet)) ? 0 : 1;
+ }
+
+ if (minmax == MAXIMUM_TIME) {
+ // Add setup time for destination clocks
+ setupdelay = calc_setup_time(testddata->trans,
+ testddata->backtrace->receiver->refpin,
+ selecteddest->trans,
+ testddata->backtrace->dir, minmax);
+ testddata->delay += setupdelay;
+ }
+ else {
+ // Subtract hold time for destination clocks
+ holddelay = calc_hold_time(testddata->trans,
+ testddata->backtrace->receiver->refpin,
+ selecteddest->trans,
+ testddata->backtrace->dir, minmax);
+ testddata->delay -= holddelay;
+ }
+
+ if (verbose > 0)
+ fprintf(stdout, "Path terminated on flop \"%s\" input with max delay %g ps\n",
+ testconn->refinst->name, testddata->delay);
+
+ for (backtrace = testddata->backtrace; backtrace->next;
+ backtrace = backtrace->next) {
+ if (verbose > 0)
+ fprintf(stdout, " %g (%s) %s/%s -> %s/%s\n",
+ backtrace->delay,
+ backtrace->receiver->refnet->name,
+ backtrace->receiver->refnet->driver->refinst->name,
+ backtrace->receiver->refnet->driver->refpin->name,
+ backtrace->receiver->refinst->name,
+ backtrace->receiver->refpin->name);
+ }
+ if (verbose > 0)
+ fprintf(stdout, " 000.000 (%s) %s/%s -> %s/%s\n",
+ backtrace->receiver->refnet->name,
+ backtrace->receiver->refinst->name,
+ backtrace->receiver->refpin->name,
+ backtrace->receiver->refinst->name,
+ backtrace->receiver->refinst->out_connects->refpin->name);
+
+ if (selecteddest != NULL && selectedsource != NULL) {
+ if (verbose > 0) {
+ if (selectedsource->receiver->refnet != selecteddest->receiver->refnet) {
+ fprintf(stdout, " %g %s to %s clock skew\n",
+ selecteddest->delay - selectedsource->delay,
+ selectedsource->receiver->refnet->name,
+ selecteddest->receiver->refnet->name);
+ }
+ }
+
+ /* Check if the flops have the same clock sense */
+ /* (both are clock rising edge or both are clock falling edge type) */
+
+ if ((testinst->refcell->type & CLK_SENSE_MASK) !=
+ (backtrace->receiver->refinst->refcell->type
+ & CLK_SENSE_MASK))
+ clk_sense_inv = 1;
+ else
+ clk_sense_inv = 0;
+
+ /* If the two flops don't clock at the same time, then issue a */
+ /* warning that the slack time loses half a clock period. */
+
+ if ((verbose > 0) && (clk_invert != -1) && (clk_sense_inv != clk_invert)) {
+ fprintf(stdout, " Clocks are inverted relative to one another,\n");
+ fprintf(stdout, " implying a maximum propagation delay of 1/2 period.\n");
+ }
+ }
+ if (selecteddest != NULL && selectedsource != NULL) {
+ if (verbose > 0) {
+ if (minmax == MAXIMUM_TIME)
+ fprintf(stdout, " %g setup time at destination\n", setupdelay);
+ else
+ fprintf(stdout, " %g hold time at destination\n", holddelay);
+ }
+ }
+
+ if (verbose > 0) fprintf(stdout, "\n");
+ }
+ }
+ else if (verbose > 0) {
+ fprintf(stdout, "Path terminated on output \"%s\" with max delay %g ps\n",
+ testddata->backtrace->receiver->refnet->name, testddata->delay);
+
+ backtrace = testddata->backtrace;
+ fprintf(stdout, " %g (%s) %s/%s -> [output pin]\n",
+ backtrace->delay,
+ backtrace->receiver->refnet->name,
+ backtrace->receiver->refnet->driver->refinst->name,
+ backtrace->receiver->refnet->driver->refpin->name);
+
+ for (backtrace = backtrace->next; backtrace->next; backtrace = backtrace->next) {
+ fprintf(stdout, " %g (%s) %s/%s -> %s/%s\n",
+ backtrace->delay,
+ backtrace->receiver->refnet->name,
+ backtrace->receiver->refnet->driver->refinst->name,
+ backtrace->receiver->refnet->driver->refpin->name,
+ backtrace->receiver->refinst->name,
+ backtrace->receiver->refpin->name);
+ }
+ fprintf(stdout, " 000.000 (%s) %s/%s -> %s/%s\n\n",
+ backtrace->receiver->refnet->name,
+ backtrace->receiver->refinst->name,
+ backtrace->receiver->refpin->name,
+ backtrace->receiver->refinst->name,
+ backtrace->receiver->refinst->out_connects->refpin->name);
+ }
+
+ // Clean up clock2list
+ while (clock2list != NULL) {
+ freebt = clock2list;
+ clock2list = clock2list->next;
+ free(freebt);
+ }
+ }
+
+ // Link delaylist data to the beginning of masterlist, and null out
+ // delaylist for the next set of paths.
+
+ if (delaylist) {
+ for (testddata = delaylist; testddata->next; testddata = testddata->next);
+ testddata->next = *masterlist;
+ *masterlist = delaylist;
+ delaylist = NULL;
+ }
+
+ // Free up clocklist
+ while (clocklist != NULL) {
+ freebt = clocklist;
+ clocklist = clocklist->next;
+ free(freebt);
+ }
}
return numpaths;
}
/*--------------------------------------------------------------*/
-/* Parse a table variable type from a liberty format file */
+/* Parse a table variable type from a liberty format file */
/*--------------------------------------------------------------*/
int get_table_type(char *token) {
if (!strcasecmp(token, "input_net_transition"))
- return TRANSITION_TIME;
+ return TRANSITION_TIME;
else if (!strcasecmp(token, "total_output_net_capacitance"))
- return OUTPUT_CAP;
+ return OUTPUT_CAP;
else if (!strcasecmp(token, "related_pin_transition"))
- return RELATED_TIME;
+ return RELATED_TIME;
else if (!strcasecmp(token, "constrained_pin_transition"))
- return CONSTRAINED_TIME;
+ return CONSTRAINED_TIME;
else
- return UNKNOWN;
+ return UNKNOWN;
}
/*--------------------------------------------------------------*/
-/* Read a liberty format file and collect information about */
-/* the timing properties of each standard cell. */
+/* Read a liberty format file and collect information about */
+/* the timing properties of each standard cell. */
/*--------------------------------------------------------------*/
void
@@ -1625,8 +1628,8 @@ libertyRead(FILE *flib, lutable **tablelist, cell **celllist)
char *libname = NULL;
int section = INIT;
- double time_unit = 1.0; // Time unit multiplier, to get ps
- double cap_unit = 1.0; // Capacitive unit multiplier, to get fF
+ double time_unit = 1.0; // Time unit multiplier, to get ps
+ double cap_unit = 1.0; // Capacitive unit multiplier, to get fF
pinptr testpin;
lutable *tableptr;
@@ -1648,885 +1651,885 @@ libertyRead(FILE *flib, lutable **tablelist, cell **celllist)
while (token != NULL) {
- switch (section) {
- case INIT:
- if (!strcasecmp(token, "library")) {
- token = advancetoken(flib, 0);
- if (strcmp(token, "("))
- fprintf(stderr, "Library not followed by name\n");
- else
- token = advancetoken(flib, ')');
- fprintf(stderr, "Parsing library \"%s\"\n", token);
- libname = strdup(token);
- token = advancetoken(flib, 0);
- if (strcmp(token, "{")) {
- fprintf(stderr, "Did not find opening brace "
- "on library block\n");
- exit(1);
- }
- section = LIBBLOCK;
- }
- else
- fprintf(stderr, "Unknown input \"%s\", looking for "
- "\"library\"\n", token);
- break;
-
- case LIBBLOCK:
- // Here we check for the main blocks, again not rigorously. . .
-
- if (!strcasecmp(token, "}")) {
- fprintf(stdout, "End of library at line %d\n", fileCurrentLine);
- section = INIT; // End of library block
- }
- else if (!strcasecmp(token, "delay_model")) {
- token = advancetoken(flib, 0);
- if (strcmp(token, ":"))
- fprintf(stderr, "Input missing colon\n");
- token = advancetoken(flib, ';');
- if (strcasecmp(token, "table_lookup")) {
- fprintf(stderr, "Sorry, only know how to "
- "handle table lookup!\n");
- exit(1);
- }
- }
- else if (!strcasecmp(token, "lu_table_template") ||
- !strcasecmp(token, "power_lut_template")) {
- // Read in template information;
- newtable = (lutable *)malloc(sizeof(lutable));
- newtable->name = NULL;
- newtable->invert = 0;
- newtable->var1 = UNKNOWN;
- newtable->var2 = UNKNOWN;
- newtable->size1 = 0;
- newtable->size2 = 0;
- newtable->idx1.times = NULL;
- newtable->idx2.caps = NULL;
- newtable->values = NULL;
- newtable->next = *tablelist;
- *tablelist = newtable;
-
- token = advancetoken(flib, 0);
- if (strcmp(token, "("))
- fprintf(stderr, "Input missing open parens\n");
- else
- token = advancetoken(flib, ')');
- newtable->name = strdup(token);
- while (*token != '}') {
- token = advancetoken(flib, 0);
- if (!strcasecmp(token, "variable_1")) {
- token = advancetoken(flib, 0);
- token = advancetoken(flib, ';');
- newtable->var1 = get_table_type(token);
- if (newtable->var1 == OUTPUT_CAP || newtable->var1 == CONSTRAINED_TIME)
- newtable->invert = 1;
- }
- else if (!strcasecmp(token, "variable_2")) {
- token = advancetoken(flib, 0);
- token = advancetoken(flib, ';');
- newtable->var2 = get_table_type(token);
- if (newtable->var2 == TRANSITION_TIME || newtable->var2 == RELATED_TIME)
- newtable->invert = 1;
- }
- else if (!strcasecmp(token, "index_1")) {
- token = advancetoken(flib, 0); // Open parens
- token = advancetoken(flib, 0); // Quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
-
- if (newtable->invert == 1) {
- // Count entries
- iptr = token;
- newtable->size2 = 1;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size2++;
- }
- newtable->idx2.caps = (double *)malloc(newtable->size2 *
- sizeof(double));
- newtable->size2 = 0;
- iptr = token;
- sscanf(iptr, "%lg", &newtable->idx2.caps[0]);
- if (newtable->var2 == OUTPUT_CAP)
- newtable->idx2.caps[0] *= cap_unit;
- else
- newtable->idx2.caps[0] *= time_unit;
-
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size2++;
- sscanf(iptr, "%lg",
- &newtable->idx2.caps[newtable->size2]);
- if (newtable->var2 == OUTPUT_CAP)
- newtable->idx2.caps[newtable->size2] *= cap_unit;
- else
- newtable->idx2.cons[newtable->size2] *= time_unit;
- }
- newtable->size2++;
- }
- else { // newtable->invert = 0
- // Count entries
- iptr = token;
- newtable->size1 = 1;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size1++;
- }
- newtable->idx1.times = (double *)malloc(newtable->size1 *
- sizeof(double));
- newtable->size1 = 0;
- iptr = token;
- sscanf(iptr, "%lg", &newtable->idx1.times[0]);
- newtable->idx1.times[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size1++;
- sscanf(iptr, "%lg",
- &newtable->idx1.times[newtable->size1]);
- newtable->idx1.times[newtable->size1] *= time_unit;
- }
- newtable->size1++;
- }
-
- token = advancetoken(flib, ';'); // EOL semicolon
- }
- else if (!strcasecmp(token, "index_2")) {
- token = advancetoken(flib, 0); // Open parens
- token = advancetoken(flib, 0); // Quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
-
- if (newtable->invert == 0) {
- // Count entries
- iptr = token;
- newtable->size2 = 1;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size2++;
- }
- newtable->idx2.caps = (double *)malloc(newtable->size2 *
- sizeof(double));
- newtable->size2 = 0;
- iptr = token;
- sscanf(iptr, "%lg", &newtable->idx2.caps[0]);
- if (newtable->var2 == OUTPUT_CAP)
- newtable->idx2.caps[0] *= cap_unit;
- else
- newtable->idx2.cons[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size2++;
- sscanf(iptr, "%lg",
- &newtable->idx2.caps[newtable->size2]);
- if (newtable->var2 == OUTPUT_CAP)
- newtable->idx2.caps[newtable->size2] *= cap_unit;
- else
- newtable->idx2.cons[newtable->size2] *= time_unit;
- }
- newtable->size2++;
- }
- else { // newtable->invert == 1
- // Count entries
- iptr = token;
- newtable->size1 = 1;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size1++;
- }
- newtable->idx1.times = (double *)malloc(newtable->size1 *
- sizeof(double));
- newtable->size1 = 0;
- iptr = token;
- sscanf(iptr, "%lg", &newtable->idx1.times[0]);
- newtable->idx1.times[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size1++;
- sscanf(iptr, "%lg",
- &newtable->idx1.times[newtable->size1]);
- newtable->idx1.times[newtable->size1] *= time_unit;
- }
- newtable->size1++;
- }
-
- token = advancetoken(flib, ';'); // EOL semicolon
- }
- }
- }
- else if (!strcasecmp(token, "cell")) {
- newcell = (cell *)malloc(sizeof(cell));
- newcell->next = NULL;
- if (lastcell != NULL)
- lastcell->next = newcell;
- else
- *celllist = newcell;
- lastcell = newcell;
- token = advancetoken(flib, 0); // Open parens
- if (!strcmp(token, "("))
- token = advancetoken(flib, ')'); // Cellname
- newcell->name = strdup(token);
- token = advancetoken(flib, 0); // Find start of block
- if (strcmp(token, "{"))
- fprintf(stderr, "Error: failed to find start of block\n");
- newcell->type = GATE; // Default type
- newcell->function = NULL;
- newcell->pins = NULL;
- newcell->area = 1.0;
- newcell->maxtrans = 0.0;
- newcell->maxcap = 0.0;
- section = CELLDEF;
- }
- else if (!strcasecmp(token, "time_unit")) {
- char *metric;
-
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ":")) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- }
- if (!strcmp(token, "\"")) {
- token = advancetoken(flib, '\"');
- if (token == NULL) break;
- }
- time_unit = strtod(token, &metric);
- if (*metric != '\0') {
- if (!strcmp(metric, "ns"))
- time_unit *= 1E3;
- else if (!strcmp(metric, "us"))
- time_unit *= 1E6;
- else if (!strcmp(metric, "fs"))
- time_unit *= 1E-3;
- else if (strcmp(metric, "ps"))
- fprintf(stderr, "Don't understand time units \"%s\"\n",
- token);
- }
- else {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, "ns"))
- time_unit *= 1E3;
- else if (!strcmp(token, "us"))
- time_unit *= 1E6;
- else if (!strcmp(token, "fs"))
- time_unit *= 1E-3;
- else if (strcmp(token, "ps"))
- fprintf(stderr, "Don't understand time units \"%s\"\n",
- token);
- }
- token = advancetoken(flib, ';');
- }
- else if (!strcasecmp(token, "capacitive_load_unit")) {
- char *metric;
-
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, "(")) {
- token = advancetoken(flib, ')');
- if (token == NULL) break;
- }
- cap_unit = strtod(token, &metric);
- if (*metric != '\0') {
- while (isspace(*metric)) metric++;
- if (*metric == ',') metric++;
- while ((*metric != '\0') && isspace(*metric)) metric++;
- if (!strcasecmp(metric, "af"))
- cap_unit *= 1E-3;
- else if (!strcasecmp(metric, "pf"))
- cap_unit *= 1000;
- else if (!strcasecmp(metric, "nf"))
- cap_unit *= 1E6;
- else if (!strcasecmp(metric, "uf"))
- cap_unit *= 1E9;
- else if (strcasecmp(metric, "ff"))
- fprintf(stderr, "Don't understand capacitive units \"%s\"\n",
- token);
- }
- else {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcasecmp(token, "af"))
- cap_unit *= 1E-3;
- else if (!strcasecmp(token, "pf"))
- cap_unit *= 1000;
- else if (!strcasecmp(token, "nf"))
- cap_unit *= 1E6;
- else if (!strcasecmp(token, "uf"))
- cap_unit *= 1E9;
- else if (strcasecmp(token, "ff"))
- fprintf(stderr, "Don't understand capacitive units \"%s\"\n",
- token);
- }
- token = advancetoken(flib, ';');
- }
- else {
- // For unhandled tokens, read in tokens. If it is
- // a definition or function, read to end-of-line. If
- // it is a block definition, read to end-of-block.
- while (1) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ";")) break;
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
- if (!strcmp(token, "{")) {
- token = advancetoken(flib, '}');
- break;
- }
- }
- }
- break;
-
- case CELLDEF:
-
- if (!strcmp(token, "}")) {
- section = LIBBLOCK; // End of cell def
- }
- else if (!strcasecmp(token, "pin")) {
- token = advancetoken(flib, 0); // Open parens
- if (!strcmp(token, "("))
- token = advancetoken(flib, ')'); // Close parens
-
- newpin = parse_pin(newcell, token, SENSE_NONE);
-
- token = advancetoken(flib, 0); // Find start of block
- if (strcmp(token, "{"))
- fprintf(stderr, "Error: failed to find start of block\n");
- section = PINDEF;
- }
- else if (!strcasecmp(token, "area")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newcell->area);
- }
- else if (!strcasecmp(token, "ff")) {
- newcell->type |= DFF;
- token = advancetoken(flib, '{');
- section = FLOPDEF;
- }
- else if (!strcasecmp(token, "latch")) {
- newcell->type |= LATCH;
- token = advancetoken(flib, '{');
- section = LATCHDEF;
- }
- else {
- // For unhandled tokens, read in tokens. If it is
- // a definition or function, read to end-of-line. If
- // it is a block definition, read to end-of-block.
- while (1) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ";")) break;
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
- if (!strcmp(token, "("))
- token = advancetoken(flib, ')');
- if (!strcmp(token, "{")) {
- token = advancetoken(flib, '}');
- break;
- }
- }
- }
- break;
-
- case FLOPDEF:
-
- if (!strcmp(token, "}")) {
- section = CELLDEF; // End of flop def
- }
- else if (!strcasecmp(token, "next_state")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= DFFIN;
- }
- else if (!strcasecmp(token, "clocked_on")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- if (strchr(token, '\'') != NULL)
- newcell->type |= CLK_SENSE_MASK;
- else if (strchr(token, '!') != NULL)
- newcell->type |= CLK_SENSE_MASK;
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= DFFCLK;
- }
- else if (!strcasecmp(token, "clear")) {
- newcell->type |= RST_MASK;
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- if (strchr(token, '\'') != NULL)
- newcell->type |= RST_SENSE_MASK;
- else if (strchr(token, '!') != NULL)
- newcell->type |= RST_SENSE_MASK;
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= DFFRST;
- }
- else if (!strcasecmp(token, "preset")) {
- newcell->type |= SET_MASK;
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- if (strchr(token, '\'') != NULL)
- newcell->type |= SET_SENSE_MASK;
- else if (strchr(token, '!') != NULL)
- newcell->type |= SET_SENSE_MASK;
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= DFFSET;
- }
- else
- token = advancetoken(flib, ';'); // Read to end-of-statement
-
- break;
-
- case LATCHDEF:
-
- if (!strcmp(token, "}")) {
- section = CELLDEF; // End of flop def
- }
- else if (!strcasecmp(token, "data_in")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= LATCHIN;
- }
- else if (!strcasecmp(token, "enable")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- if (strchr(token, '\'') != NULL)
- newcell->type |= EN_SENSE_MASK;
- else if (strchr(token, '!') != NULL)
- newcell->type |= EN_SENSE_MASK;
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= LATCHEN;
- }
- else
- token = advancetoken(flib, ';'); // Read to end-of-statement
-
- break;
-
- case PINDEF:
-
- if (!strcmp(token, "}")) {
- section = CELLDEF; // End of pin def
- }
- else if (!strcasecmp(token, "capacitance")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newpin->capr);
- newpin->capr *= cap_unit;
- }
- else if (!strcasecmp(token, "rise_capacitance")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newpin->capr);
- newpin->capr *= cap_unit;
- }
- else if (!strcasecmp(token, "fall_capacitance")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newpin->capf);
- newpin->capf *= cap_unit;
- }
- else if (!strcasecmp(token, "function")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, 0); // Open quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"'); // Find function string
- if (newpin->type & OUTPUT) {
- newcell->function = strdup(token);
- }
- token = advancetoken(flib, 0);
- if (strcmp(token, ";")) {
- if (!strcmp(token, "}"))
- section = CELLDEF; // End of pin def
- else
- fprintf(stderr, "Expected end-of-statement.\n");
- }
- }
- else if (!strcasecmp(token, "direction")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';');
- if (!strcasecmp(token, "input")) {
- newpin->type |= INPUT;
- }
- else if (!strcasecmp(token, "output")) {
- newpin->type |= OUTPUT;
- if (newcell->type & DFF) newpin->type |= DFFOUT;
- if (newcell->type & LATCH) newpin->type |= LATCHOUT;
- }
- }
- else if (!strcasecmp(token, "max_transition")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newcell->maxtrans);
- newcell->maxtrans *= time_unit;
- }
- else if (!strcasecmp(token, "max_capacitance")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newcell->maxcap);
- newcell->maxcap *= cap_unit;
- }
- else if (!strcasecmp(token, "timing")) {
- token = advancetoken(flib, 0); // Arguments, if any
- if (strcmp(token, "("))
- fprintf(stderr, "Error: failed to find start of block\n");
- else
- token = advancetoken(flib, ')'); // Arguments, if any
- token = advancetoken(flib, 0); // Find start of block
- if (strcmp(token, "{"))
- fprintf(stderr, "Error: failed to find start of block\n");
- testpin = NULL;
- sense_type = SENSE_NONE;
- section = TIMING;
- }
- else {
- // For unhandled tokens, read in tokens. If it is
- // a definition or function, read to end-of-line. If
- // it is a block definition, read to end-of-block.
- while (1) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ";")) break;
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
- if (!strcmp(token, "{")) {
- token = advancetoken(flib, '}');
- break;
- }
- }
- }
- break;
-
- case TIMING:
-
- if (!strcmp(token, "}")) {
- section = PINDEF; // End of timing def
- }
- else if (!strcasecmp(token, "related_pin")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // Read to end of statement
- // Create the related pin if needed
- testpin = parse_pin(newcell, token, sense_type);
- }
- else if (!strcasecmp(token, "timing_sense")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // Read to end of statement
- if (!strcasecmp(token, "positive_unate")) {
- if (testpin)
- testpin->sense = SENSE_POSITIVE;
- else
- sense_type = SENSE_POSITIVE;
- }
- else if (!strcasecmp(token, "negative_unate")) {
- if (testpin)
- testpin->sense = SENSE_NEGATIVE;
- else
- sense_type = SENSE_NEGATIVE;
- }
- else if (!strcasecmp(token, "non_unate")) {
- if (testpin)
- testpin->sense = SENSE_NONE;
- else
- sense_type = SENSE_NONE;
- }
- }
- else if (!strcasecmp(token, "timing_type")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // Read to end of statement
-
- // Note: Timing type is apparently redundant information;
- // e.g., "falling_edge" can be determined by "clocked_on : !CLK"
- // in the ff {} block. How reliable is this?
-
- if (!strcasecmp(token, "rising_edge"))
- timing_type = TIMING_PROP_TRANS;
- else if (!strcasecmp(token, "falling_edge"))
- timing_type = TIMING_PROP_TRANS;
- else if (!strcasecmp(token, "hold_rising"))
- timing_type = TIMING_HOLD;
- else if (!strcasecmp(token, "hold_falling"))
- timing_type = TIMING_HOLD;
- else if (!strcasecmp(token, "setup_rising"))
- timing_type = TIMING_SETUP;
- else if (!strcasecmp(token, "setup_falling"))
- timing_type = TIMING_SETUP;
- else if (!strcasecmp(token, "clear"))
- timing_type = TIMING_SET_RESET;
- else if (!strcasecmp(token, "preset"))
- timing_type = TIMING_SET_RESET;
- else if (!strcasecmp(token, "recovery_rising"))
- timing_type = TIMING_RECOVERY;
- else if (!strcasecmp(token, "recovery_falling"))
- timing_type = TIMING_RECOVERY;
- else if (!strcasecmp(token, "removal_rising"))
- timing_type = TIMING_REMOVAL;
- else if (!strcasecmp(token, "removal_falling"))
- timing_type = TIMING_REMOVAL;
- else if (!strcasecmp(token, "three_state_enable"))
- timing_type = TIMING_TRISTATE;
- else if (!strcasecmp(token, "three_state_disable"))
- timing_type = TIMING_TRISTATE;
- }
- else if ((!strcasecmp(token, "cell_rise")) ||
- (!strcasecmp(token, "cell_fall")) ||
- (!strcasecmp(token, "rise_transition")) ||
- (!strcasecmp(token, "fall_transition")) ||
- (!strcasecmp(token, "rise_constraint")) ||
- (!strcasecmp(token, "fall_constraint"))) {
-
- tableptr = (lutable *)malloc(sizeof(lutable));
- tableptr->name = NULL; // Not used
- tableptr->invert = 0;
- tableptr->var1 = UNKNOWN;
- tableptr->var2 = UNKNOWN;
- tableptr->size1 = 0;
- tableptr->size2 = 0;
- tableptr->idx1.times = NULL;
- tableptr->idx2.caps = NULL;
- tableptr->values = NULL;
- tableptr->next = NULL; // Not used
-
- // Note that propagation delays (cell rise, cell fall) and
- // transition times (rise transition, fall transition) have
- // their lookup tables stored in the "related pin" pin record.
- // Setup and hold times (rise constraint, fall constraint)
- // have their lookup tables stored in the original pin record.
- // These should not overlap.
-
- // Recovery and removal tables are not yet handled. . .
-
- if (!strcasecmp(token, "cell_rise"))
- testpin->propdelr = tableptr;
- else if (!strcasecmp(token, "cell_fall"))
- testpin->propdelf = tableptr;
- else if (!strcasecmp(token, "rise_transition"))
- testpin->transr = tableptr;
- else if (!strcasecmp(token, "fall_transition"))
- testpin->transf = tableptr;
- else if (!strcasecmp(token, "rise_constraint")) {
- if (timing_type == TIMING_SETUP)
- newpin->propdelr = tableptr;
- else if (timing_type == TIMING_HOLD)
- newpin->transr = tableptr;
- }
- else if (!strcasecmp(token, "fall_constraint")) {
- if (timing_type == TIMING_SETUP)
- newpin->propdelf = tableptr;
- else if (timing_type == TIMING_HOLD)
- newpin->transf = tableptr;
- }
-
- token = advancetoken(flib, 0); // Open parens
- if (!strcmp(token, "("))
- token = advancetoken(flib, ')');
-
- for (reftable = *tablelist; reftable; reftable = reftable->next)
- if (!strcmp(reftable->name, token))
- break;
- if (reftable == NULL)
- fprintf(stderr, "Failed to find a valid table \"%s\"\n",
- token);
- else {
- // Fill in default values from template reftable
- tableptr->invert = reftable->invert;
- if (reftable->size1 > 0) {
- tableptr->var1 = reftable->var1;
- tableptr->size1 = reftable->size1;
- tableptr->idx1.times = (double *)malloc(tableptr->size1 * sizeof(double));
- memcpy(tableptr->idx1.times, reftable->idx1.times,
- tableptr->size1 * sizeof(double));
- }
- if (reftable->size2 > 0) {
- tableptr->var2 = reftable->var2;
- tableptr->size2 = reftable->size2;
- tableptr->idx2.caps = (double *)malloc(tableptr->size2 * sizeof(double));
- memcpy(tableptr->idx2.caps, reftable->idx2.caps,
- tableptr->size2 * sizeof(double));
- }
- }
-
- token = advancetoken(flib, 0);
- if (strcmp(token, "{"))
- fprintf(stderr, "Failed to find start of timing block\n");
-
- while (*token != '}') {
- token = advancetoken(flib, 0);
- if (!strcasecmp(token, "index_1")) {
-
- // Local index values override those in the template
-
- token = advancetoken(flib, 0); // Open parens
- token = advancetoken(flib, 0); // Quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
-
- //-------------------------
-
- if (reftable && (reftable->invert == 1)) {
- // Entries had better match the ref table
- iptr = token;
- i = 0;
- sscanf(iptr, "%lg", &tableptr->idx2.caps[0]);
- if (tableptr->var2 == OUTPUT_CAP)
- tableptr->idx2.caps[0] *= cap_unit;
- else
- tableptr->idx2.cons[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- i++;
- sscanf(iptr, "%lg", &tableptr->idx2.caps[i]);
- if (tableptr->var2 == OUTPUT_CAP)
- tableptr->idx2.caps[i] *= cap_unit;
- else
- tableptr->idx2.cons[i] *= time_unit;
- }
- }
- else if (reftable && (reftable->invert == 0)) {
- iptr = token;
- i = 0;
- sscanf(iptr, "%lg", &tableptr->idx1.times[0]);
- tableptr->idx1.times[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- i++;
- sscanf(iptr, "%lg", &tableptr->idx1.times[i]);
- tableptr->idx1.times[i] *= time_unit;
- }
- }
-
- token = advancetoken(flib, ')'); // Close paren
- token = advancetoken(flib, ';'); // EOL semicolon
- }
- else if (!strcasecmp(token, "index_2")) {
-
- // Local index values override those in the template
-
- token = advancetoken(flib, 0); // Open parens
- token = advancetoken(flib, 0); // Quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
-
- //-------------------------
-
- if (reftable && (reftable->invert == 1)) {
- // Entries had better match the ref table
- iptr = token;
- i = 0;
- sscanf(iptr, "%lg", &tableptr->idx1.times[0]);
- tableptr->idx1.times[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- i++;
- sscanf(iptr, "%lg", &tableptr->idx1.times[i]);
- tableptr->idx1.times[i] *= time_unit;
- }
- }
- else if (reftable && (reftable->invert == 0)) {
- iptr = token;
- i = 0;
- sscanf(iptr, "%lg", &tableptr->idx2.caps[0]);
- tableptr->idx2.caps[0] *= cap_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- i++;
- sscanf(iptr, "%lg", &tableptr->idx2.caps[i]);
- tableptr->idx2.caps[i] *= cap_unit;
- }
- }
-
- token = advancetoken(flib, ')'); // Close paren
- token = advancetoken(flib, ';'); // EOL semicolon
- }
- else if (!strcasecmp(token, "values")) {
- token = advancetoken(flib, 0);
- if (strcmp(token, "("))
- fprintf(stderr, "Failed to find start of"
- " value table\n");
- token = advancetoken(flib, ')');
-
- // Parse the string of values and enter it into the
- // table "values", which is size size2 x size1
-
- if (reftable && reftable->size1 > 0) {
- int locsize2;
- locsize2 = (reftable->size2 > 0) ? reftable->size2 : 1;
- if (reftable->invert) {
- tableptr->values = (double *)malloc(locsize2 *
- reftable->size1 * sizeof(double));
- iptr = token;
- for (i = 0; i < reftable->size1; i++) {
- for (j = 0; j < locsize2; j++) {
- while (*iptr == ' ' || *iptr == '\"' ||
- *iptr == ',')
- iptr++;
- sscanf(iptr, "%lg", &gval);
- *(tableptr->values + j * reftable->size1
- + i) = gval * time_unit;
- while (*iptr != ' ' && *iptr != '\"' &&
- *iptr != ',')
- iptr++;
- }
- }
- }
- else {
- tableptr->values = (double *)malloc(locsize2 *
- reftable->size1 * sizeof(double));
- iptr = token;
- for (j = 0; j < locsize2; j++) {
- for (i = 0; i < reftable->size1; i++) {
- while (*iptr == ' ' || *iptr == '\"' ||
- *iptr == ',')
- iptr++;
- sscanf(iptr, "%lg", &gval);
- *(tableptr->values + j * reftable->size1
- + i) = gval * time_unit;
- while (*iptr != ' ' && *iptr != '\"' &&
- *iptr != ',')
- iptr++;
- }
- }
- }
- }
-
- token = advancetoken(flib, 0);
- if (strcmp(token, ";"))
- fprintf(stderr, "Failed to find end of value table\n");
- token = advancetoken(flib, 0);
-
- }
- else if (strcmp(token, "{"))
- fprintf(stderr, "Failed to find end of timing block\n");
- }
- }
- else {
- // For unhandled tokens, read in tokens. If it is
- // a definition or function, read to end-of-line. If
- // it is a block definition, read to end-of-block.
- while (1) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ";")) break;
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
- if (!strcmp(token, "{")) {
- token = advancetoken(flib, '}');
- break;
- }
- }
- }
- break;
- }
- token = advancetoken(flib, 0);
+ switch (section) {
+ case INIT:
+ if (!strcasecmp(token, "library")) {
+ token = advancetoken(flib, 0);
+ if (strcmp(token, "("))
+ fprintf(stderr, "Library not followed by name\n");
+ else
+ token = advancetoken(flib, ')');
+ fprintf(stderr, "Parsing library \"%s\"\n", token);
+ libname = strdup(token);
+ token = advancetoken(flib, 0);
+ if (strcmp(token, "{")) {
+ fprintf(stderr, "Did not find opening brace "
+ "on library block\n");
+ exit(1);
+ }
+ section = LIBBLOCK;
+ }
+ else
+ fprintf(stderr, "Unknown input \"%s\", looking for "
+ "\"library\"\n", token);
+ break;
+
+ case LIBBLOCK:
+ // Here we check for the main blocks, again not rigorously. . .
+
+ if (!strcasecmp(token, "}")) {
+ fprintf(stdout, "End of library at line %d\n", fileCurrentLine);
+ section = INIT; // End of library block
+ }
+ else if (!strcasecmp(token, "delay_model")) {
+ token = advancetoken(flib, 0);
+ if (strcmp(token, ":"))
+ fprintf(stderr, "Input missing colon\n");
+ token = advancetoken(flib, ';');
+ if (strcasecmp(token, "table_lookup")) {
+ fprintf(stderr, "Sorry, only know how to "
+ "handle table lookup!\n");
+ exit(1);
+ }
+ }
+ else if (!strcasecmp(token, "lu_table_template") ||
+ !strcasecmp(token, "power_lut_template")) {
+ // Read in template information;
+ newtable = (lutable *)malloc(sizeof(lutable));
+ newtable->name = NULL;
+ newtable->invert = 0;
+ newtable->var1 = UNKNOWN;
+ newtable->var2 = UNKNOWN;
+ newtable->size1 = 0;
+ newtable->size2 = 0;
+ newtable->idx1.times = NULL;
+ newtable->idx2.caps = NULL;
+ newtable->values = NULL;
+ newtable->next = *tablelist;
+ *tablelist = newtable;
+
+ token = advancetoken(flib, 0);
+ if (strcmp(token, "("))
+ fprintf(stderr, "Input missing open parens\n");
+ else
+ token = advancetoken(flib, ')');
+ newtable->name = strdup(token);
+ while (*token != '}') {
+ token = advancetoken(flib, 0);
+ if (!strcasecmp(token, "variable_1")) {
+ token = advancetoken(flib, 0);
+ token = advancetoken(flib, ';');
+ newtable->var1 = get_table_type(token);
+ if (newtable->var1 == OUTPUT_CAP || newtable->var1 == CONSTRAINED_TIME)
+ newtable->invert = 1;
+ }
+ else if (!strcasecmp(token, "variable_2")) {
+ token = advancetoken(flib, 0);
+ token = advancetoken(flib, ';');
+ newtable->var2 = get_table_type(token);
+ if (newtable->var2 == TRANSITION_TIME || newtable->var2 == RELATED_TIME)
+ newtable->invert = 1;
+ }
+ else if (!strcasecmp(token, "index_1")) {
+ token = advancetoken(flib, 0); // Open parens
+ token = advancetoken(flib, 0); // Quote
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"');
+
+ if (newtable->invert == 1) {
+ // Count entries
+ iptr = token;
+ newtable->size2 = 1;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ newtable->size2++;
+ }
+ newtable->idx2.caps = (double *)malloc(newtable->size2 *
+ sizeof(double));
+ newtable->size2 = 0;
+ iptr = token;
+ sscanf(iptr, "%lg", &newtable->idx2.caps[0]);
+ if (newtable->var2 == OUTPUT_CAP)
+ newtable->idx2.caps[0] *= cap_unit;
+ else
+ newtable->idx2.caps[0] *= time_unit;
+
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ newtable->size2++;
+ sscanf(iptr, "%lg",
+ &newtable->idx2.caps[newtable->size2]);
+ if (newtable->var2 == OUTPUT_CAP)
+ newtable->idx2.caps[newtable->size2] *= cap_unit;
+ else
+ newtable->idx2.cons[newtable->size2] *= time_unit;
+ }
+ newtable->size2++;
+ }
+ else { // newtable->invert = 0
+ // Count entries
+ iptr = token;
+ newtable->size1 = 1;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ newtable->size1++;
+ }
+ newtable->idx1.times = (double *)malloc(newtable->size1 *
+ sizeof(double));
+ newtable->size1 = 0;
+ iptr = token;
+ sscanf(iptr, "%lg", &newtable->idx1.times[0]);
+ newtable->idx1.times[0] *= time_unit;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ newtable->size1++;
+ sscanf(iptr, "%lg",
+ &newtable->idx1.times[newtable->size1]);
+ newtable->idx1.times[newtable->size1] *= time_unit;
+ }
+ newtable->size1++;
+ }
+
+ token = advancetoken(flib, ';'); // EOL semicolon
+ }
+ else if (!strcasecmp(token, "index_2")) {
+ token = advancetoken(flib, 0); // Open parens
+ token = advancetoken(flib, 0); // Quote
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"');
+
+ if (newtable->invert == 0) {
+ // Count entries
+ iptr = token;
+ newtable->size2 = 1;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ newtable->size2++;
+ }
+ newtable->idx2.caps = (double *)malloc(newtable->size2 *
+ sizeof(double));
+ newtable->size2 = 0;
+ iptr = token;
+ sscanf(iptr, "%lg", &newtable->idx2.caps[0]);
+ if (newtable->var2 == OUTPUT_CAP)
+ newtable->idx2.caps[0] *= cap_unit;
+ else
+ newtable->idx2.cons[0] *= time_unit;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ newtable->size2++;
+ sscanf(iptr, "%lg",
+ &newtable->idx2.caps[newtable->size2]);
+ if (newtable->var2 == OUTPUT_CAP)
+ newtable->idx2.caps[newtable->size2] *= cap_unit;
+ else
+ newtable->idx2.cons[newtable->size2] *= time_unit;
+ }
+ newtable->size2++;
+ }
+ else { // newtable->invert == 1
+ // Count entries
+ iptr = token;
+ newtable->size1 = 1;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ newtable->size1++;
+ }
+ newtable->idx1.times = (double *)malloc(newtable->size1 *
+ sizeof(double));
+ newtable->size1 = 0;
+ iptr = token;
+ sscanf(iptr, "%lg", &newtable->idx1.times[0]);
+ newtable->idx1.times[0] *= time_unit;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ newtable->size1++;
+ sscanf(iptr, "%lg",
+ &newtable->idx1.times[newtable->size1]);
+ newtable->idx1.times[newtable->size1] *= time_unit;
+ }
+ newtable->size1++;
+ }
+
+ token = advancetoken(flib, ';'); // EOL semicolon
+ }
+ }
+ }
+ else if (!strcasecmp(token, "cell")) {
+ newcell = (cell *)malloc(sizeof(cell));
+ newcell->next = NULL;
+ if (lastcell != NULL)
+ lastcell->next = newcell;
+ else
+ *celllist = newcell;
+ lastcell = newcell;
+ token = advancetoken(flib, 0); // Open parens
+ if (!strcmp(token, "("))
+ token = advancetoken(flib, ')'); // Cellname
+ newcell->name = strdup(token);
+ token = advancetoken(flib, 0); // Find start of block
+ if (strcmp(token, "{"))
+ fprintf(stderr, "Error: failed to find start of block\n");
+ newcell->type = GATE; // Default type
+ newcell->function = NULL;
+ newcell->pins = NULL;
+ newcell->area = 1.0;
+ newcell->maxtrans = 0.0;
+ newcell->maxcap = 0.0;
+ section = CELLDEF;
+ }
+ else if (!strcasecmp(token, "time_unit")) {
+ char *metric;
+
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ if (!strcmp(token, ":")) {
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ }
+ if (!strcmp(token, "\"")) {
+ token = advancetoken(flib, '\"');
+ if (token == NULL) break;
+ }
+ time_unit = strtod(token, &metric);
+ if (*metric != '\0') {
+ if (!strcmp(metric, "ns"))
+ time_unit *= 1E3;
+ else if (!strcmp(metric, "us"))
+ time_unit *= 1E6;
+ else if (!strcmp(metric, "fs"))
+ time_unit *= 1E-3;
+ else if (strcmp(metric, "ps"))
+ fprintf(stderr, "Don't understand time units \"%s\"\n",
+ token);
+ }
+ else {
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ if (!strcmp(token, "ns"))
+ time_unit *= 1E3;
+ else if (!strcmp(token, "us"))
+ time_unit *= 1E6;
+ else if (!strcmp(token, "fs"))
+ time_unit *= 1E-3;
+ else if (strcmp(token, "ps"))
+ fprintf(stderr, "Don't understand time units \"%s\"\n",
+ token);
+ }
+ token = advancetoken(flib, ';');
+ }
+ else if (!strcasecmp(token, "capacitive_load_unit")) {
+ char *metric;
+
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ if (!strcmp(token, "(")) {
+ token = advancetoken(flib, ')');
+ if (token == NULL) break;
+ }
+ cap_unit = strtod(token, &metric);
+ if (*metric != '\0') {
+ while (isspace(*metric)) metric++;
+ if (*metric == ',') metric++;
+ while ((*metric != '\0') && isspace(*metric)) metric++;
+ if (!strcasecmp(metric, "af"))
+ cap_unit *= 1E-3;
+ else if (!strcasecmp(metric, "pf"))
+ cap_unit *= 1000;
+ else if (!strcasecmp(metric, "nf"))
+ cap_unit *= 1E6;
+ else if (!strcasecmp(metric, "uf"))
+ cap_unit *= 1E9;
+ else if (strcasecmp(metric, "ff"))
+ fprintf(stderr, "Don't understand capacitive units \"%s\"\n",
+ token);
+ }
+ else {
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ if (!strcasecmp(token, "af"))
+ cap_unit *= 1E-3;
+ else if (!strcasecmp(token, "pf"))
+ cap_unit *= 1000;
+ else if (!strcasecmp(token, "nf"))
+ cap_unit *= 1E6;
+ else if (!strcasecmp(token, "uf"))
+ cap_unit *= 1E9;
+ else if (strcasecmp(token, "ff"))
+ fprintf(stderr, "Don't understand capacitive units \"%s\"\n",
+ token);
+ }
+ token = advancetoken(flib, ';');
+ }
+ else {
+ // For unhandled tokens, read in tokens. If it is
+ // a definition or function, read to end-of-line. If
+ // it is a block definition, read to end-of-block.
+ while (1) {
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ if (!strcmp(token, ";")) break;
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"');
+ if (!strcmp(token, "{")) {
+ token = advancetoken(flib, '}');
+ break;
+ }
+ }
+ }
+ break;
+
+ case CELLDEF:
+
+ if (!strcmp(token, "}")) {
+ section = LIBBLOCK; // End of cell def
+ }
+ else if (!strcasecmp(token, "pin")) {
+ token = advancetoken(flib, 0); // Open parens
+ if (!strcmp(token, "("))
+ token = advancetoken(flib, ')'); // Close parens
+
+ newpin = parse_pin(newcell, token, SENSE_NONE);
+
+ token = advancetoken(flib, 0); // Find start of block
+ if (strcmp(token, "{"))
+ fprintf(stderr, "Error: failed to find start of block\n");
+ section = PINDEF;
+ }
+ else if (!strcasecmp(token, "area")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ sscanf(token, "%lg", &newcell->area);
+ }
+ else if (!strcasecmp(token, "ff")) {
+ newcell->type |= DFF;
+ token = advancetoken(flib, '{');
+ section = FLOPDEF;
+ }
+ else if (!strcasecmp(token, "latch")) {
+ newcell->type |= LATCH;
+ token = advancetoken(flib, '{');
+ section = LATCHDEF;
+ }
+ else {
+ // For unhandled tokens, read in tokens. If it is
+ // a definition or function, read to end-of-line. If
+ // it is a block definition, read to end-of-block.
+ while (1) {
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ if (!strcmp(token, ";")) break;
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"');
+ if (!strcmp(token, "("))
+ token = advancetoken(flib, ')');
+ if (!strcmp(token, "{")) {
+ token = advancetoken(flib, '}');
+ break;
+ }
+ }
+ }
+ break;
+
+ case FLOPDEF:
+
+ if (!strcmp(token, "}")) {
+ section = CELLDEF; // End of flop def
+ }
+ else if (!strcasecmp(token, "next_state")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ newpin = parse_pin(newcell, token, SENSE_NONE);
+ newpin->type |= DFFIN;
+ }
+ else if (!strcasecmp(token, "clocked_on")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ if (strchr(token, '\'') != NULL)
+ newcell->type |= CLK_SENSE_MASK;
+ else if (strchr(token, '!') != NULL)
+ newcell->type |= CLK_SENSE_MASK;
+ newpin = parse_pin(newcell, token, SENSE_NONE);
+ newpin->type |= DFFCLK;
+ }
+ else if (!strcasecmp(token, "clear")) {
+ newcell->type |= RST_MASK;
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ if (strchr(token, '\'') != NULL)
+ newcell->type |= RST_SENSE_MASK;
+ else if (strchr(token, '!') != NULL)
+ newcell->type |= RST_SENSE_MASK;
+ newpin = parse_pin(newcell, token, SENSE_NONE);
+ newpin->type |= DFFRST;
+ }
+ else if (!strcasecmp(token, "preset")) {
+ newcell->type |= SET_MASK;
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ if (strchr(token, '\'') != NULL)
+ newcell->type |= SET_SENSE_MASK;
+ else if (strchr(token, '!') != NULL)
+ newcell->type |= SET_SENSE_MASK;
+ newpin = parse_pin(newcell, token, SENSE_NONE);
+ newpin->type |= DFFSET;
+ }
+ else
+ token = advancetoken(flib, ';'); // Read to end-of-statement
+
+ break;
+
+ case LATCHDEF:
+
+ if (!strcmp(token, "}")) {
+ section = CELLDEF; // End of flop def
+ }
+ else if (!strcasecmp(token, "data_in")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ newpin = parse_pin(newcell, token, SENSE_NONE);
+ newpin->type |= LATCHIN;
+ }
+ else if (!strcasecmp(token, "enable")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ if (strchr(token, '\'') != NULL)
+ newcell->type |= EN_SENSE_MASK;
+ else if (strchr(token, '!') != NULL)
+ newcell->type |= EN_SENSE_MASK;
+ newpin = parse_pin(newcell, token, SENSE_NONE);
+ newpin->type |= LATCHEN;
+ }
+ else
+ token = advancetoken(flib, ';'); // Read to end-of-statement
+
+ break;
+
+ case PINDEF:
+
+ if (!strcmp(token, "}")) {
+ section = CELLDEF; // End of pin def
+ }
+ else if (!strcasecmp(token, "capacitance")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ sscanf(token, "%lg", &newpin->capr);
+ newpin->capr *= cap_unit;
+ }
+ else if (!strcasecmp(token, "rise_capacitance")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ sscanf(token, "%lg", &newpin->capr);
+ newpin->capr *= cap_unit;
+ }
+ else if (!strcasecmp(token, "fall_capacitance")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ sscanf(token, "%lg", &newpin->capf);
+ newpin->capf *= cap_unit;
+ }
+ else if (!strcasecmp(token, "function")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, 0); // Open quote
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"'); // Find function string
+ if (newpin->type & OUTPUT) {
+ newcell->function = strdup(token);
+ }
+ token = advancetoken(flib, 0);
+ if (strcmp(token, ";")) {
+ if (!strcmp(token, "}"))
+ section = CELLDEF; // End of pin def
+ else
+ fprintf(stderr, "Expected end-of-statement.\n");
+ }
+ }
+ else if (!strcasecmp(token, "direction")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';');
+ if (!strcasecmp(token, "input")) {
+ newpin->type |= INPUT;
+ }
+ else if (!strcasecmp(token, "output")) {
+ newpin->type |= OUTPUT;
+ if (newcell->type & DFF) newpin->type |= DFFOUT;
+ if (newcell->type & LATCH) newpin->type |= LATCHOUT;
+ }
+ }
+ else if (!strcasecmp(token, "max_transition")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ sscanf(token, "%lg", &newcell->maxtrans);
+ newcell->maxtrans *= time_unit;
+ }
+ else if (!strcasecmp(token, "max_capacitance")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // To end-of-statement
+ sscanf(token, "%lg", &newcell->maxcap);
+ newcell->maxcap *= cap_unit;
+ }
+ else if (!strcasecmp(token, "timing")) {
+ token = advancetoken(flib, 0); // Arguments, if any
+ if (strcmp(token, "("))
+ fprintf(stderr, "Error: failed to find start of block\n");
+ else
+ token = advancetoken(flib, ')'); // Arguments, if any
+ token = advancetoken(flib, 0); // Find start of block
+ if (strcmp(token, "{"))
+ fprintf(stderr, "Error: failed to find start of block\n");
+ testpin = NULL;
+ sense_type = SENSE_NONE;
+ section = TIMING;
+ }
+ else {
+ // For unhandled tokens, read in tokens. If it is
+ // a definition or function, read to end-of-line. If
+ // it is a block definition, read to end-of-block.
+ while (1) {
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ if (!strcmp(token, ";")) break;
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"');
+ if (!strcmp(token, "{")) {
+ token = advancetoken(flib, '}');
+ break;
+ }
+ }
+ }
+ break;
+
+ case TIMING:
+
+ if (!strcmp(token, "}")) {
+ section = PINDEF; // End of timing def
+ }
+ else if (!strcasecmp(token, "related_pin")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // Read to end of statement
+ // Create the related pin if needed
+ testpin = parse_pin(newcell, token, sense_type);
+ }
+ else if (!strcasecmp(token, "timing_sense")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // Read to end of statement
+ if (!strcasecmp(token, "positive_unate")) {
+ if (testpin)
+ testpin->sense = SENSE_POSITIVE;
+ else
+ sense_type = SENSE_POSITIVE;
+ }
+ else if (!strcasecmp(token, "negative_unate")) {
+ if (testpin)
+ testpin->sense = SENSE_NEGATIVE;
+ else
+ sense_type = SENSE_NEGATIVE;
+ }
+ else if (!strcasecmp(token, "non_unate")) {
+ if (testpin)
+ testpin->sense = SENSE_NONE;
+ else
+ sense_type = SENSE_NONE;
+ }
+ }
+ else if (!strcasecmp(token, "timing_type")) {
+ token = advancetoken(flib, 0); // Colon
+ token = advancetoken(flib, ';'); // Read to end of statement
+
+ // Note: Timing type is apparently redundant information;
+ // e.g., "falling_edge" can be determined by "clocked_on : !CLK"
+ // in the ff {} block. How reliable is this?
+
+ if (!strcasecmp(token, "rising_edge"))
+ timing_type = TIMING_PROP_TRANS;
+ else if (!strcasecmp(token, "falling_edge"))
+ timing_type = TIMING_PROP_TRANS;
+ else if (!strcasecmp(token, "hold_rising"))
+ timing_type = TIMING_HOLD;
+ else if (!strcasecmp(token, "hold_falling"))
+ timing_type = TIMING_HOLD;
+ else if (!strcasecmp(token, "setup_rising"))
+ timing_type = TIMING_SETUP;
+ else if (!strcasecmp(token, "setup_falling"))
+ timing_type = TIMING_SETUP;
+ else if (!strcasecmp(token, "clear"))
+ timing_type = TIMING_SET_RESET;
+ else if (!strcasecmp(token, "preset"))
+ timing_type = TIMING_SET_RESET;
+ else if (!strcasecmp(token, "recovery_rising"))
+ timing_type = TIMING_RECOVERY;
+ else if (!strcasecmp(token, "recovery_falling"))
+ timing_type = TIMING_RECOVERY;
+ else if (!strcasecmp(token, "removal_rising"))
+ timing_type = TIMING_REMOVAL;
+ else if (!strcasecmp(token, "removal_falling"))
+ timing_type = TIMING_REMOVAL;
+ else if (!strcasecmp(token, "three_state_enable"))
+ timing_type = TIMING_TRISTATE;
+ else if (!strcasecmp(token, "three_state_disable"))
+ timing_type = TIMING_TRISTATE;
+ }
+ else if ((!strcasecmp(token, "cell_rise")) ||
+ (!strcasecmp(token, "cell_fall")) ||
+ (!strcasecmp(token, "rise_transition")) ||
+ (!strcasecmp(token, "fall_transition")) ||
+ (!strcasecmp(token, "rise_constraint")) ||
+ (!strcasecmp(token, "fall_constraint"))) {
+
+ tableptr = (lutable *)malloc(sizeof(lutable));
+ tableptr->name = NULL; // Not used
+ tableptr->invert = 0;
+ tableptr->var1 = UNKNOWN;
+ tableptr->var2 = UNKNOWN;
+ tableptr->size1 = 0;
+ tableptr->size2 = 0;
+ tableptr->idx1.times = NULL;
+ tableptr->idx2.caps = NULL;
+ tableptr->values = NULL;
+ tableptr->next = NULL; // Not used
+
+ // Note that propagation delays (cell rise, cell fall) and
+ // transition times (rise transition, fall transition) have
+ // their lookup tables stored in the "related pin" pin record.
+ // Setup and hold times (rise constraint, fall constraint)
+ // have their lookup tables stored in the original pin record.
+ // These should not overlap.
+
+ // Recovery and removal tables are not yet handled. . .
+
+ if (!strcasecmp(token, "cell_rise"))
+ testpin->propdelr = tableptr;
+ else if (!strcasecmp(token, "cell_fall"))
+ testpin->propdelf = tableptr;
+ else if (!strcasecmp(token, "rise_transition"))
+ testpin->transr = tableptr;
+ else if (!strcasecmp(token, "fall_transition"))
+ testpin->transf = tableptr;
+ else if (!strcasecmp(token, "rise_constraint")) {
+ if (timing_type == TIMING_SETUP)
+ newpin->propdelr = tableptr;
+ else if (timing_type == TIMING_HOLD)
+ newpin->transr = tableptr;
+ }
+ else if (!strcasecmp(token, "fall_constraint")) {
+ if (timing_type == TIMING_SETUP)
+ newpin->propdelf = tableptr;
+ else if (timing_type == TIMING_HOLD)
+ newpin->transf = tableptr;
+ }
+
+ token = advancetoken(flib, 0); // Open parens
+ if (!strcmp(token, "("))
+ token = advancetoken(flib, ')');
+
+ for (reftable = *tablelist; reftable; reftable = reftable->next)
+ if (!strcmp(reftable->name, token))
+ break;
+ if (reftable == NULL)
+ fprintf(stderr, "Failed to find a valid table \"%s\"\n",
+ token);
+ else {
+ // Fill in default values from template reftable
+ tableptr->invert = reftable->invert;
+ if (reftable->size1 > 0) {
+ tableptr->var1 = reftable->var1;
+ tableptr->size1 = reftable->size1;
+ tableptr->idx1.times = (double *)malloc(tableptr->size1 * sizeof(double));
+ memcpy(tableptr->idx1.times, reftable->idx1.times,
+ tableptr->size1 * sizeof(double));
+ }
+ if (reftable->size2 > 0) {
+ tableptr->var2 = reftable->var2;
+ tableptr->size2 = reftable->size2;
+ tableptr->idx2.caps = (double *)malloc(tableptr->size2 * sizeof(double));
+ memcpy(tableptr->idx2.caps, reftable->idx2.caps,
+ tableptr->size2 * sizeof(double));
+ }
+ }
+
+ token = advancetoken(flib, 0);
+ if (strcmp(token, "{"))
+ fprintf(stderr, "Failed to find start of timing block\n");
+
+ while (*token != '}') {
+ token = advancetoken(flib, 0);
+ if (!strcasecmp(token, "index_1")) {
+
+ // Local index values override those in the template
+
+ token = advancetoken(flib, 0); // Open parens
+ token = advancetoken(flib, 0); // Quote
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"');
+
+ //-------------------------
+
+ if (reftable && (reftable->invert == 1)) {
+ // Entries had better match the ref table
+ iptr = token;
+ i = 0;
+ sscanf(iptr, "%lg", &tableptr->idx2.caps[0]);
+ if (tableptr->var2 == OUTPUT_CAP)
+ tableptr->idx2.caps[0] *= cap_unit;
+ else
+ tableptr->idx2.cons[0] *= time_unit;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ i++;
+ sscanf(iptr, "%lg", &tableptr->idx2.caps[i]);
+ if (tableptr->var2 == OUTPUT_CAP)
+ tableptr->idx2.caps[i] *= cap_unit;
+ else
+ tableptr->idx2.cons[i] *= time_unit;
+ }
+ }
+ else if (reftable && (reftable->invert == 0)) {
+ iptr = token;
+ i = 0;
+ sscanf(iptr, "%lg", &tableptr->idx1.times[0]);
+ tableptr->idx1.times[0] *= time_unit;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ i++;
+ sscanf(iptr, "%lg", &tableptr->idx1.times[i]);
+ tableptr->idx1.times[i] *= time_unit;
+ }
+ }
+
+ token = advancetoken(flib, ')'); // Close paren
+ token = advancetoken(flib, ';'); // EOL semicolon
+ }
+ else if (!strcasecmp(token, "index_2")) {
+
+ // Local index values override those in the template
+
+ token = advancetoken(flib, 0); // Open parens
+ token = advancetoken(flib, 0); // Quote
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"');
+
+ //-------------------------
+
+ if (reftable && (reftable->invert == 1)) {
+ // Entries had better match the ref table
+ iptr = token;
+ i = 0;
+ sscanf(iptr, "%lg", &tableptr->idx1.times[0]);
+ tableptr->idx1.times[0] *= time_unit;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ i++;
+ sscanf(iptr, "%lg", &tableptr->idx1.times[i]);
+ tableptr->idx1.times[i] *= time_unit;
+ }
+ }
+ else if (reftable && (reftable->invert == 0)) {
+ iptr = token;
+ i = 0;
+ sscanf(iptr, "%lg", &tableptr->idx2.caps[0]);
+ tableptr->idx2.caps[0] *= cap_unit;
+ while ((iptr = strchr(iptr, ',')) != NULL) {
+ iptr++;
+ i++;
+ sscanf(iptr, "%lg", &tableptr->idx2.caps[i]);
+ tableptr->idx2.caps[i] *= cap_unit;
+ }
+ }
+
+ token = advancetoken(flib, ')'); // Close paren
+ token = advancetoken(flib, ';'); // EOL semicolon
+ }
+ else if (!strcasecmp(token, "values")) {
+ token = advancetoken(flib, 0);
+ if (strcmp(token, "("))
+ fprintf(stderr, "Failed to find start of"
+ " value table\n");
+ token = advancetoken(flib, ')');
+
+ // Parse the string of values and enter it into the
+ // table "values", which is size size2 x size1
+
+ if (reftable && reftable->size1 > 0) {
+ int locsize2;
+ locsize2 = (reftable->size2 > 0) ? reftable->size2 : 1;
+ if (reftable->invert) {
+ tableptr->values = (double *)malloc(locsize2 *
+ reftable->size1 * sizeof(double));
+ iptr = token;
+ for (i = 0; i < reftable->size1; i++) {
+ for (j = 0; j < locsize2; j++) {
+ while (*iptr == ' ' || *iptr == '\"' ||
+ *iptr == ',')
+ iptr++;
+ sscanf(iptr, "%lg", &gval);
+ *(tableptr->values + j * reftable->size1
+ + i) = gval * time_unit;
+ while (*iptr != ' ' && *iptr != '\"' &&
+ *iptr != ',')
+ iptr++;
+ }
+ }
+ }
+ else {
+ tableptr->values = (double *)malloc(locsize2 *
+ reftable->size1 * sizeof(double));
+ iptr = token;
+ for (j = 0; j < locsize2; j++) {
+ for (i = 0; i < reftable->size1; i++) {
+ while (*iptr == ' ' || *iptr == '\"' ||
+ *iptr == ',')
+ iptr++;
+ sscanf(iptr, "%lg", &gval);
+ *(tableptr->values + j * reftable->size1
+ + i) = gval * time_unit;
+ while (*iptr != ' ' && *iptr != '\"' &&
+ *iptr != ',')
+ iptr++;
+ }
+ }
+ }
+ }
+
+ token = advancetoken(flib, 0);
+ if (strcmp(token, ";"))
+ fprintf(stderr, "Failed to find end of value table\n");
+ token = advancetoken(flib, 0);
+
+ }
+ else if (strcmp(token, "{"))
+ fprintf(stderr, "Failed to find end of timing block\n");
+ }
+ }
+ else {
+ // For unhandled tokens, read in tokens. If it is
+ // a definition or function, read to end-of-line. If
+ // it is a block definition, read to end-of-block.
+ while (1) {
+ token = advancetoken(flib, 0);
+ if (token == NULL) break;
+ if (!strcmp(token, ";")) break;
+ if (!strcmp(token, "\""))
+ token = advancetoken(flib, '\"');
+ if (!strcmp(token, "{")) {
+ token = advancetoken(flib, '}');
+ break;
+ }
+ }
+ }
+ break;
+ }
+ token = advancetoken(flib, 0);
}
}
/*--------------------------------------------------------------*/
-/* Read a verilog netlist and collect information about the */
-/* cells instantiated and the network structure */
+/* Read a verilog netlist and collect information about the */
+/* cells instantiated and the network structure */
/*--------------------------------------------------------------*/
void
verilogRead(FILE *fsrc, cell *cells, net **netlist, instance **instlist,
- connect **inputlist, connect **outputlist)
+ connect **inputlist, connect **outputlist, struct hashlist **Nethash)
{
char *token;
char *modname = NULL;
@@ -2539,246 +2542,236 @@ verilogRead(FILE *fsrc, cell *cells, net **netlist, instance **instlist,
pinptr testpin;
int vstart, vend, vtarget, isinput;
- struct hashlist *Nethash[OBJHASHSIZE];
-
- /* See hash.c for these routines and variables */
- hashfunc = hash;
- matchfunc = match;
-
- /* Initialize net hash table */
- InitializeHashTable(Nethash);
/* Read tokens off of the line */
token = advancetoken(fsrc, 0);
while (token != NULL) {
- switch (section) {
- case MODULE:
- if (!strcasecmp(token, "module")) {
- token = advancetoken(fsrc, 0);
- fprintf(stderr, "Parsing module \"%s\"\n", token);
-
- token = advancetoken(fsrc, 0);
- if (strcmp(token, "("))
- fprintf(stderr, "Module not followed by pin list\n");
- else
- token = advancetoken(fsrc, ')');
- token = advancetoken(fsrc, ';'); // Get end-of-line
-
- // Ignore the pin list, go straight to the input/output declarations
- section = IOLIST;
- }
- break;
-
- case IOLIST:
- if (!strcasecmp(token, "input") || !strcasecmp(token, "output")) {
-
- testconn = NULL;
- vstart = vend = 0;
-
- if (!strcasecmp(token, "input")) {
- isinput = 1;
- }
- else { // output
- isinput = 0;
- }
-
- token = advancetoken(fsrc, 0);
- if (*token == '[') {
- sscanf(token + 1, "%d", &vstart);
- token = advancetoken(fsrc, ':');
- token = advancetoken(fsrc, ']'); // Read to end of vector
- sscanf(token, "%d", &vend);
- token = advancetoken(fsrc, 0); // Read signal name
- }
-
- // Create a net entry for the input or output, add to the list of nets
-
- if (vstart == 0 && vend == 0) {
- newnet = create_net(netlist);
- newnet->name = strdup(token);
- HashPtrInstall(newnet->name, newnet, Nethash);
-
- testconn = (connptr)malloc(sizeof(connect));
- testconn->refnet = newnet;
- testconn->refpin = NULL; // No associated pin
- testconn->refinst = NULL; // No associated instance
- testconn->tag = NULL;
- testconn->metric = -1.0;
- testconn->prvector = NULL;
- testconn->pfvector = NULL;
- testconn->trvector = NULL;
- testconn->tfvector = NULL;
-
- if (isinput) { // driver (input)
- testconn->next = *inputlist;
- *inputlist = testconn;
- }
- else { // receiver (output)
- testconn->next = *outputlist;
- *outputlist = testconn;
- }
- }
- else {
- vtarget = vend + (vstart < vend) ? 1 : -1;
- while (vstart != vtarget) {
- newnet = create_net(netlist);
- newnet->name = (char *)malloc(strlen(token) + 6);
- sprintf(newnet->name, "%s[%d]", token, vstart);
- HashPtrInstall(newnet->name, newnet, Nethash);
-
- vstart += (vtarget > vend) ? 1 : -1;
-
- testconn = (connptr)malloc(sizeof(connect));
- testconn->refnet = newnet;
- testconn->refpin = NULL; // No associated pin
- testconn->refinst = NULL; // No associated instance
- testconn->tag = NULL;
- testconn->metric = -1.0;
- testconn->prvector = NULL;
- testconn->pfvector = NULL;
- testconn->trvector = NULL;
- testconn->tfvector = NULL;
-
- if (isinput) { // driver (input)
- testconn->next = *inputlist;
- *inputlist = testconn;
- }
- else { // receiver (output)
- testconn->next = *outputlist;
- *outputlist = testconn;
- }
- }
- }
- token = advancetoken(fsrc, ';'); // Get rest of input/output entry
- break;
- }
-
- /* Drop through on anything that isn't an input, output, or blank line */
-
- case GATELIST:
-
- if (!strcasecmp(token, "endmodule")) {
- section = MODULE;
- break;
- }
-
- /* Confirm that the token is a known cell, and continue parsing line if so */
- /* Otherwise, parse to semicolon line end and continue */
-
- for (testcell = cells; testcell; testcell = testcell->next)
- if (!strcasecmp(testcell->name, token))
- break;
-
- if (testcell != NULL) {
- section = INSTANCE;
- newinst = (instptr)malloc(sizeof(instance));
- newinst->next = *instlist;
- *instlist = newinst;
- newinst->refcell = testcell;
- newinst->in_connects = NULL;
- newinst->out_connects = NULL;
- }
- else {
- /* Ignore all wire and assign statements */
- /* Qflow does not generate these, but other */
- /* synthesis tools may. */
-
- if (!strcasecmp(token, "assign") && (verbose > 0)) {
- fprintf(stdout, "Wire assignments are not handled!\n");
- }
- else if (strcasecmp(token, "wire") && (verbose > 0)) {
- fprintf(stdout, "Unknown cell \"%s\" instanced.\n",
- token);
- }
- token = advancetoken(fsrc, ';'); // Get rest of entry, and ignore
- }
- break;
-
- case INSTANCE:
- newinst->name = strdup(token);
- token = advancetoken(fsrc, '('); // Find beginning of pin list
- section = INSTPIN;
- break;
-
- case INSTPIN:
- if (*token == '.') {
- newconn = (connptr)malloc(sizeof(connect));
- // Pin name is in (token + 1)
- for (testpin = testcell->pins; testpin; testpin = testpin->next) {
- if (!strcmp(testpin->name, token + 1))
- break;
- }
- // Sanity check
- if (testpin == NULL) {
- fprintf(stderr, "No such pin \"%s\" in cell \"%s\"!\n",
- token + 1, testcell->name);
- }
- else {
- if (testpin->type & OUTPUT) {
- newconn->next = newinst->out_connects;
- newinst->out_connects = newconn;
- }
- else {
- newconn->next = newinst->in_connects;
- newinst->in_connects = newconn;
- }
- }
- newconn->refinst = newinst;
- newconn->refpin = testpin;
- newconn->refnet = NULL;
- newconn->tag = NULL;
- newconn->metric = -1.0;
- newconn->prvector = NULL;
- newconn->pfvector = NULL;
- newconn->trvector = NULL;
- newconn->tfvector = NULL;
- token = advancetoken(fsrc, '('); // Read to beginning of pin name
- section = PINCONN;
- }
- else if (*token == ';') {
- // End of instance record
- section = GATELIST;
- }
- else if (*token != ',' && *token != ')') {
- fprintf(stderr, "Unexpected entry in instance pin connection list!\n");
- token = advancetoken(fsrc, ';'); // Read to end-of-line
- section = GATELIST;
- }
- break;
-
- case PINCONN:
- // Token is net name
- testnet = (netptr)HashLookup(token, Nethash);
- if (testnet == NULL) {
- // This is a new net, and we need to record it
- newnet = create_net(netlist);
- newnet->name = strdup(token);
- HashPtrInstall(newnet->name, newnet, Nethash);
- newconn->refnet = newnet;
- }
- else
- newconn->refnet = testnet;
- section = INSTPIN;
- break;
- }
- if (section == PINCONN)
- token = advancetoken(fsrc, ')'); // Name token parsing
- else
- token = advancetoken(fsrc, 0);
+ switch (section) {
+ case MODULE:
+ if (!strcasecmp(token, "module")) {
+ token = advancetoken(fsrc, 0);
+ fprintf(stderr, "Parsing module \"%s\"\n", token);
+
+ token = advancetoken(fsrc, 0);
+ if (strcmp(token, "("))
+ fprintf(stderr, "Module not followed by pin list\n");
+ else
+ token = advancetoken(fsrc, ')');
+ token = advancetoken(fsrc, ';'); // Get end-of-line
+
+ // Ignore the pin list, go straight to the input/output declarations
+ section = IOLIST;
+ }
+ break;
+
+ case IOLIST:
+ if (!strcasecmp(token, "input") || !strcasecmp(token, "output")) {
+
+ testconn = NULL;
+ vstart = vend = 0;
+
+ if (!strcasecmp(token, "input")) {
+ isinput = 1;
+ }
+ else { // output
+ isinput = 0;
+ }
+
+ token = advancetoken(fsrc, 0);
+ if (*token == '[') {
+ sscanf(token + 1, "%d", &vstart);
+ token = advancetoken(fsrc, ':');
+ token = advancetoken(fsrc, ']'); // Read to end of vector
+ sscanf(token, "%d", &vend);
+ token = advancetoken(fsrc, 0); // Read signal name
+ }
+
+ // Create a net entry for the input or output, add to the list of nets
+
+ if (vstart == 0 && vend == 0) {
+ newnet = create_net(netlist);
+ newnet->name = strdup(token);
+ HashPtrInstall(newnet->name, newnet, Nethash);
+
+ testconn = (connptr)malloc(sizeof(connect));
+ testconn->refnet = newnet;
+ testconn->refpin = NULL; // No associated pin
+ testconn->refinst = NULL; // No associated instance
+ testconn->tag = NULL;
+ testconn->metric = -1.0;
+ testconn->prvector = NULL;
+ testconn->pfvector = NULL;
+ testconn->trvector = NULL;
+ testconn->tfvector = NULL;
+
+ if (isinput) { // driver (input)
+ testconn->next = *inputlist;
+ *inputlist = testconn;
+ }
+ else { // receiver (output)
+ testconn->next = *outputlist;
+ *outputlist = testconn;
+ }
+ }
+ else {
+ vtarget = vend + (vstart < vend) ? 1 : -1;
+ while (vstart != vtarget) {
+ newnet = create_net(netlist);
+ newnet->name = (char *)malloc(strlen(token) + 6);
+ sprintf(newnet->name, "%s[%d]", token, vstart);
+ HashPtrInstall(newnet->name, newnet, Nethash);
+
+ vstart += (vtarget > vend) ? 1 : -1;
+
+ testconn = (connptr)malloc(sizeof(connect));
+ testconn->refnet = newnet;
+ testconn->refpin = NULL; // No associated pin
+ testconn->refinst = NULL; // No associated instance
+ testconn->tag = NULL;
+ testconn->metric = -1.0;
+ testconn->prvector = NULL;
+ testconn->pfvector = NULL;
+ testconn->trvector = NULL;
+ testconn->tfvector = NULL;
+
+ if (isinput) { // driver (input)
+ testconn->next = *inputlist;
+ *inputlist = testconn;
+ }
+ else { // receiver (output)
+ testconn->next = *outputlist;
+ *outputlist = testconn;
+ }
+ }
+ }
+ token = advancetoken(fsrc, ';'); // Get rest of input/output entry
+ break;
+ }
+
+ /* Drop through on anything that isn't an input, output, or blank line */
+
+ case GATELIST:
+
+ if (!strcasecmp(token, "endmodule")) {
+ section = MODULE;
+ break;
+ }
+
+ /* Confirm that the token is a known cell, and continue parsing line if so */
+ /* Otherwise, parse to semicolon line end and continue */
+
+ for (testcell = cells; testcell; testcell = testcell->next)
+ if (!strcasecmp(testcell->name, token))
+ break;
+
+ if (testcell != NULL) {
+ section = INSTANCE;
+ newinst = (instptr)malloc(sizeof(instance));
+ newinst->next = *instlist;
+ *instlist = newinst;
+ newinst->refcell = testcell;
+ newinst->in_connects = NULL;
+ newinst->out_connects = NULL;
+ }
+ else {
+ /* Ignore all wire and assign statements */
+ /* Qflow does not generate these, but other */
+ /* synthesis tools may. */
+
+ if (!strcasecmp(token, "assign") && (verbose > 0)) {
+ fprintf(stdout, "Wire assignments are not handled!\n");
+ }
+ else if (strcasecmp(token, "wire") && (verbose > 0)) {
+ fprintf(stdout, "Unknown cell \"%s\" instanced.\n",
+ token);
+ }
+ token = advancetoken(fsrc, ';'); // Get rest of entry, and ignore
+ }
+ break;
+
+ case INSTANCE:
+ newinst->name = strdup(token);
+ token = advancetoken(fsrc, '('); // Find beginning of pin list
+ section = INSTPIN;
+ break;
+
+ case INSTPIN:
+ if (*token == '.') {
+ newconn = (connptr)malloc(sizeof(connect));
+ // Pin name is in (token + 1)
+ for (testpin = testcell->pins; testpin; testpin = testpin->next) {
+ if (!strcmp(testpin->name, token + 1))
+ break;
+ }
+ // Sanity check
+ if (testpin == NULL) {
+ fprintf(stderr, "No such pin \"%s\" in cell \"%s\"!\n",
+ token + 1, testcell->name);
+ }
+ else {
+ if (testpin->type & OUTPUT) {
+ newconn->next = newinst->out_connects;
+ newinst->out_connects = newconn;
+ }
+ else {
+ newconn->next = newinst->in_connects;
+ newinst->in_connects = newconn;
+ }
+ }
+ newconn->refinst = newinst;
+ newconn->refpin = testpin;
+ newconn->refnet = NULL;
+ newconn->tag = NULL;
+ newconn->metric = -1.0;
+ newconn->prvector = NULL;
+ newconn->pfvector = NULL;
+ newconn->trvector = NULL;
+ newconn->tfvector = NULL;
+ token = advancetoken(fsrc, '('); // Read to beginning of pin name
+ section = PINCONN;
+ }
+ else if (*token == ';') {
+ // End of instance record
+ section = GATELIST;
+ }
+ else if (*token != ',' && *token != ')') {
+ fprintf(stderr, "Unexpected entry in instance pin connection list!\n");
+ token = advancetoken(fsrc, ';'); // Read to end-of-line
+ section = GATELIST;
+ }
+ break;
+
+ case PINCONN:
+ // Token is net name
+ testnet = (netptr)HashLookup(token, Nethash);
+ if (testnet == NULL) {
+ // This is a new net, and we need to record it
+ newnet = create_net(netlist);
+ newnet->name = strdup(token);
+ HashPtrInstall(newnet->name, newnet, Nethash);
+ newconn->refnet = newnet;
+ }
+ else
+ newconn->refnet = testnet;
+ section = INSTPIN;
+ break;
+ }
+ if (section == PINCONN)
+ token = advancetoken(fsrc, ')'); // Name token parsing
+ else
+ token = advancetoken(fsrc, 0);
}
- /* Hash table no longer needed */
- HashKill(Nethash);
}
/*--------------------------------------------------------------*/
-/* For each net, go through the list of receivers and add the */
-/* contributions of each to the total load. This is either */
-/* the input pin capacitance, if the receiver is a pin, or the */
-/* designated output load (given on the command line), if the */
-/* receiver is an output pin. */
+/* For each net, go through the list of receivers and add the */
+/* contributions of each to the total load. This is either */
+/* the input pin capacitance, if the receiver is a pin, or the */
+/* designated output load (given on the command line), if the */
+/* receiver is an output pin. */
/*--------------------------------------------------------------*/
void
@@ -2791,18 +2784,18 @@ computeLoads(netptr netlist, instptr instlist, double out_load)
int i;
for (testnet = netlist; testnet; testnet = testnet->next) {
- for (i = 0; i < testnet->fanout; i++) {
- testconn = testnet->receivers[i];
- testpin = testconn->refpin;
- if (testpin == NULL) {
- testnet->loadr += out_load;
- testnet->loadf += out_load;
- }
- else {
- testnet->loadr += testpin->capr;
- testnet->loadf += testpin->capf;
- }
- }
+ for (i = 0; i < testnet->fanout; i++) {
+ testconn = testnet->receivers[i];
+ testpin = testconn->refpin;
+ if (testpin == NULL) {
+ testnet->loadr += out_load;
+ testnet->loadf += out_load;
+ }
+ else {
+ testnet->loadr += testpin->capr;
+ testnet->loadf += testpin->capf;
+ }
+ }
}
// For each instance input pin, collapse the pin's lookup table
@@ -2811,31 +2804,31 @@ computeLoads(netptr netlist, instptr instlist, double out_load)
// record for the pin.
for (testinst = instlist; testinst; testinst = testinst->next) {
- loadnet = testinst->out_connects->refnet;
- for (testconn = testinst->in_connects; testconn; testconn = testconn->next) {
- testpin = testconn->refpin;
-
- if (testpin->propdelr)
- testconn->prvector = table_collapse(testpin->propdelr, loadnet->loadr);
- if (testpin->propdelf)
- testconn->pfvector = table_collapse(testpin->propdelf, loadnet->loadf);
- if (testpin->transr)
- testconn->trvector = table_collapse(testpin->transr, loadnet->loadr);
- if (testpin->transf)
- testconn->tfvector = table_collapse(testpin->transf, loadnet->loadf);
- }
+ loadnet = testinst->out_connects->refnet;
+ for (testconn = testinst->in_connects; testconn; testconn = testconn->next) {
+ testpin = testconn->refpin;
+
+ if (testpin->propdelr)
+ testconn->prvector = table_collapse(testpin->propdelr, loadnet->loadr);
+ if (testpin->propdelf)
+ testconn->pfvector = table_collapse(testpin->propdelf, loadnet->loadf);
+ if (testpin->transr)
+ testconn->trvector = table_collapse(testpin->transr, loadnet->loadr);
+ if (testpin->transf)
+ testconn->tfvector = table_collapse(testpin->transf, loadnet->loadf);
+ }
}
}
/*--------------------------------------------------------------*/
-/* Assign types to each net. This identifies which nets are */
-/* clock inputs, which are latch enable inputs, and which are */
-/* asynchronous set/reset inputs,. */
-/* */
-/* Whenever a clock input to a flop is found, add the */
-/* connection record to clockedlist */
-/* */
-/* For diagnostics, return the number of entries in clockedlist */
+/* Assign types to each net. This identifies which nets are */
+/* clock inputs, which are latch enable inputs, and which are */
+/* asynchronous set/reset inputs,. */
+/* */
+/* Whenever a clock input to a flop is found, add the */
+/* connection record to clockedlist */
+/* */
+/* For diagnostics, return the number of entries in clockedlist */
/*--------------------------------------------------------------*/
int assign_net_types(netptr netlist, connlistptr *clockedlist)
@@ -2849,62 +2842,62 @@ int assign_net_types(netptr netlist, connlistptr *clockedlist)
numterms = 0;
for (testnet = netlist; testnet; testnet = testnet->next) {
- for (i = 0; i < testnet->fanout; i++) {
- testrcvr = testnet->receivers[i];
- testpin = testrcvr->refpin;
- if (testpin == NULL)
- testnet->type |= OUTTERM;
- else {
- switch (testpin->type & (DFFMASK | LATCHMASK)) {
- case DFFCLK:
- testnet->type |= CLOCK;
- newclocked = (connlistptr)malloc(sizeof(connlist));
- newclocked->connection = testrcvr;
- newclocked->next = *clockedlist;
- *clockedlist = newclocked;
- numterms++;
- break;
- case DFFIN:
- testnet->type |= TERMINAL;
- break;
- case DFFSET:
- case DFFRST:
- testnet->type |= ASYNC;
- break;
- case LATCHIN:
- testnet->type |= LATCHTERM;
- break;
- case LATCHEN:
- testnet->type |= ENABLE;
- break;
- }
- }
- }
+ for (i = 0; i < testnet->fanout; i++) {
+ testrcvr = testnet->receivers[i];
+ testpin = testrcvr->refpin;
+ if (testpin == NULL)
+ testnet->type |= OUTTERM;
+ else {
+ switch (testpin->type & (DFFMASK | LATCHMASK)) {
+ case DFFCLK:
+ testnet->type |= CLOCK;
+ newclocked = (connlistptr)malloc(sizeof(connlist));
+ newclocked->connection = testrcvr;
+ newclocked->next = *clockedlist;
+ *clockedlist = newclocked;
+ numterms++;
+ break;
+ case DFFIN:
+ testnet->type |= TERMINAL;
+ break;
+ case DFFSET:
+ case DFFRST:
+ testnet->type |= ASYNC;
+ break;
+ case LATCHIN:
+ testnet->type |= LATCHTERM;
+ break;
+ case LATCHEN:
+ testnet->type |= ENABLE;
+ break;
+ }
+ }
+ }
}
return numterms;
}
/*--------------------------------------------------------------*/
-/* Create the links representing the netlist connections. */
-/* */
-/* The verilogRead() routine added all nets and instances, and */
-/* for each instance, generated a list of net connections to */
-/* each pin. To make the netlist easily traversible, this */
-/* routine does the following: */
-/* */
-/* For each instance, work through the list of pin */
-/* connections. If the pin is an output, then add the */
-/* connection as the net's driver entry. If the pin is */
-/* an input, then add the connection to the list of the */
-/* net's receivers, and increment the net's fanout. */
-/* */
-/* For each module input, add the input connection as the */
-/* net's driver (flag an error if the net already has a */
-/* driver). */
-/* */
-/* For each module output, add the output connection as one of */
-/* the net's receivers (it may be the only one). */
-/* */
+/* Create the links representing the netlist connections. */
+/* */
+/* The verilogRead() routine added all nets and instances, and */
+/* for each instance, generated a list of net connections to */
+/* each pin. To make the netlist easily traversible, this */
+/* routine does the following: */
+/* */
+/* For each instance, work through the list of pin */
+/* connections. If the pin is an output, then add the */
+/* connection as the net's driver entry. If the pin is */
+/* an input, then add the connection to the list of the */
+/* net's receivers, and increment the net's fanout. */
+/* */
+/* For each module input, add the input connection as the */
+/* net's driver (flag an error if the net already has a */
+/* driver). */
+/* */
+/* For each module output, add the output connection as one of */
+/* the net's receivers (it may be the only one). */
+/* */
/*--------------------------------------------------------------*/
void
@@ -2915,51 +2908,51 @@ createLinks(netptr netlist, instptr instlist, connptr inputlist, connptr outputl
connptr testconn;
for (testinst = instlist; testinst; testinst = testinst->next) {
- for (testconn = testinst->in_connects; testconn; testconn = testconn->next) {
- testnet = testconn->refnet;
- testnet->fanout++;
- if (testnet->receivers == NULL)
- testnet->receivers = (connptr *)malloc(sizeof(connptr));
-
- else
- testnet->receivers = (connptr *)realloc(testnet->receivers,
- testnet->fanout * sizeof(connptr));
-
- testnet->receivers[testnet->fanout - 1] = testconn;
- }
-
- for (testconn = testinst->out_connects; testconn; testconn = testconn->next) {
- testnet = testconn->refnet;
- testnet->driver = testconn;
- }
+ for (testconn = testinst->in_connects; testconn; testconn = testconn->next) {
+ testnet = testconn->refnet;
+ testnet->fanout++;
+ if (testnet->receivers == NULL)
+ testnet->receivers = (connptr *)malloc(sizeof(connptr));
+
+ else
+ testnet->receivers = (connptr *)realloc(testnet->receivers,
+ testnet->fanout * sizeof(connptr));
+
+ testnet->receivers[testnet->fanout - 1] = testconn;
+ }
+
+ for (testconn = testinst->out_connects; testconn; testconn = testconn->next) {
+ testnet = testconn->refnet;
+ testnet->driver = testconn;
+ }
}
for (testconn = inputlist; testconn; testconn = testconn->next) {
- testnet = testconn->refnet;
- if (testnet->driver != NULL)
- fprintf(stderr, "Error: Input pin \"%s\" has an internal driver!\n",
- testnet->name);
- // else
- // testnet->driver = testconn; // Don't do this, makes connectivity circular
+ testnet = testconn->refnet;
+ if (testnet->driver != NULL)
+ fprintf(stderr, "Error: Input pin \"%s\" has an internal driver!\n",
+ testnet->name);
+ // else
+ // testnet->driver = testconn; // Don't do this, makes connectivity circular
}
for (testconn = outputlist; testconn; testconn = testconn->next) {
- testnet = testconn->refnet;
- testnet->fanout++;
- if (testnet->receivers == NULL)
- testnet->receivers = (connptr *)malloc(sizeof(connptr));
+ testnet = testconn->refnet;
+ testnet->fanout++;
+ if (testnet->receivers == NULL)
+ testnet->receivers = (connptr *)malloc(sizeof(connptr));
- else
- testnet->receivers = (connptr *)realloc(testnet->receivers,
- testnet->fanout * sizeof(connptr));
+ else
+ testnet->receivers = (connptr *)realloc(testnet->receivers,
+ testnet->fanout * sizeof(connptr));
- testnet->receivers[testnet->fanout - 1] = testconn;
+ testnet->receivers[testnet->fanout - 1] = testconn;
}
}
/*--------------------------------------------------------------*/
-/* Delay comparison used by qsort() to sort paths in order from */
-/* longest to shortest propagation delay. */
+/* Delay comparison used by qsort() to sort paths in order from */
+/* longest to shortest propagation delay. */
/*--------------------------------------------------------------*/
int
@@ -2969,14 +2962,93 @@ compdelay(ddataptr *a, ddataptr *b)
ddataptr q = *b;
if (p->delay < q->delay)
- return (1);
+ return (1);
if (p->delay > q->delay)
- return (-1);
+ return (-1);
return (0);
}
+void
+delayRead(FILE *fdly, struct hashlist **Nethash)
+{
+ fprintf(stdout, "delayRead\n");
+ char c[128];
+ char d[128];
+ char *token;
+
+ netptr newnet, testnet;
+ connptr testconn;
+ pinptr testpin;
+ int i;
+ int numRxers;
+
+ token = advancetoken(fdly, 0);
+
+ while (token != NULL) {
+
+ numRxers = 0;
+ testnet = (netptr)HashLookup(token, Nethash);
+
+ char *saveptr;
+ char *saveptr2;
+
+ // Read driver of interconnect and total interconnect capacitance
+ fgets(c, 128, fdly);
+ //fprintf(stdout, "\tDriver Inst: %s\n", strtok_r(c, "/", &saveptr));
+ //fprintf(stdout, "\tDriver Pin: %s\n", strtok_r(NULL, " ", &saveptr));
+ //fprintf(stdout, "\tTotC: %f\n", strtof(saveptr, NULL));
+
+ testnet->loadr = (strtod(saveptr, NULL)) / 1e3;
+ testnet->loadf = testnet->loadr;
+
+ fgets(c, 128, fdly);
+
+ while (c[0] != '\n') {
+ //if (debug > 0) fprintf(stdout, "\t%s\n", c);
+
+ //separate receiver name and delay value
+ strtok_r(c, " ", &saveptr);
+ //fprintf(stdout, "\tDelay: %s\n", saveptr);
+ //fprintf(stdout, "\tRxer Name: %s\n", c);
+ strtok_r(c, "/", &saveptr2);
+ //fprintf(stdout, "\tRxer Name: %s\n", c);
+ //fprintf(stdout, "\tRxer Name: %s\n", saveptr2);
+ //fprintf(stdout, "\tDelay: %f\n", strtof(saveptr, NULL));
+
+ for (i = 0; i < testnet->fanout; i++) {
+
+ testconn = testnet->receivers[i];
+
+ if (testnet->type == OUTTERM) {
+ fprintf(stdout, "\tNet connects to output and has no receiving instance pin\n");
+ testconn->icDelay = strtof(saveptr, NULL);
+ } else {
+ fprintf(stdout, "\trefinstname: %s\n", testconn->refinst->name);
+
+ if (!strcmp(testconn->refinst->name, c)) {
+
+ testconn->icDelay = strtof(saveptr, NULL);
+ break;
+ }
+ }
+ //fprintf(stdout, "\tName: %s\n", c);
+ }
+
+ fgets(c, 128, fdly);
+ numRxers += 1;
+ }
+
+ if (numRxers != testnet->fanout) {
+ fprintf(stderr, "ERROR: Net %s did not have a number of receivers in delay file equal to the fanout of %d", testnet->name, testnet->fanout);
+ exit(-1);
+ }
+
+ token = advancetoken(fdly, 0);
+ }
+}
+
/*--------------------------------------------------------------*/
-/* Main program */
+/* Main program */
/*--------------------------------------------------------------*/
int
@@ -2984,6 +3056,7 @@ main(int objc, char *argv[])
{
FILE *flib;
FILE *fsrc;
+ FILE *fdly;
double period = 0.0;
double outLoad = 0.0;
double inTrans = 0.0;
@@ -3006,86 +3079,86 @@ main(int objc, char *argv[])
connptr outputlist = NULL;
// Timing path database
- ddataptr pathlist = NULL;
- ddataptr freeddata, testddata, *orderedpaths;
- btptr freebt, testbt;
- int numpaths, numterms, i;
- char badtiming;
- double slack;
+ ddataptr pathlist = NULL;
+ ddataptr freeddata, testddata, *orderedpaths;
+ btptr freebt, testbt;
+ int numpaths, numterms, i;
+ char badtiming;
+ double slack;
verbose = 0;
exhaustive = 0;
while ((firstarg < objc) && (*argv[firstarg] == '-')) {
if (!strcmp(argv[firstarg], "-d") || !strcmp(argv[firstarg], "--delay")) {
- delayfile = strdup(argv[firstarg + 1]);
- firstarg += 2;
+ delayfile = strdup(argv[firstarg + 1]);
+ firstarg += 2;
}
else if (!strcmp(argv[firstarg], "-p") || !strcmp(argv[firstarg], "--period")) {
- period = strtod(argv[firstarg + 1], NULL);
- firstarg += 2;
+ period = strtod(argv[firstarg + 1], NULL);
+ firstarg += 2;
}
else if (!strcmp(argv[firstarg], "-l") || !strcmp(argv[firstarg], "--load")) {
- outLoad = strtod(argv[firstarg + 1], NULL);
- firstarg += 2;
+ outLoad = strtod(argv[firstarg + 1], NULL);
+ firstarg += 2;
}
else if (!strcmp(argv[firstarg], "-t") || !strcmp(argv[firstarg], "--trans")) {
- inTrans = strtod(argv[firstarg + 1], NULL);
- firstarg += 2;
+ inTrans = strtod(argv[firstarg + 1], NULL);
+ firstarg += 2;
}
else if (!strcmp(argv[firstarg], "-v") || !strcmp(argv[firstarg], "--verbose")) {
- sscanf(argv[firstarg + 1], "%d", &ival);
- verbose = (unsigned char)ival;
- firstarg += 2;
+ sscanf(argv[firstarg + 1], "%d", &ival);
+ verbose = (unsigned char)ival;
+ firstarg += 2;
}
else if (!strcmp(argv[firstarg], "-e") || !strcmp(argv[firstarg], "--exhaustive")) {
- exhaustive = 1;
- firstarg++;
+ exhaustive = 1;
+ firstarg++;
}
else if (!strcmp(argv[firstarg], "-V") || !strcmp(argv[firstarg], "--version")) {
- fprintf(stderr, "Vesta Static Timing Analzyer version 0.2\n");
- exit(0);
+ fprintf(stderr, "Vesta Static Timing Analzyer version 0.2\n");
+ exit(0);
}
else {
- fprintf(stderr, "Unknown option \"%s\"\n", argv[firstarg]);
- firstarg++;
+ fprintf(stderr, "Unknown option \"%s\"\n", argv[firstarg]);
+ firstarg++;
}
}
if (objc - firstarg != 2) {
- fprintf(stderr, "Usage: vesta [options] <name.v> <name.lib>\n");
- fprintf(stderr, "Options:\n");
- fprintf(stderr, "--delay <delay_file> or -d <delay_file>\n");
- fprintf(stderr, "--period <period> or -p <period>\n");
- fprintf(stderr, "--load <load> or -l <load>\n");
- fprintf(stderr, "--verbose <level> or -v <level>\n");
- fprintf(stderr, "--exhaustive or -e\n");
- fprintf(stderr, "--version or -V\n");
- exit (1);
+ fprintf(stderr, "Usage: vesta [options] <name.v> <name.lib>\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, "--delay <delay_file> or -d <delay_file>\n");
+ fprintf(stderr, "--period <period> or -p <period>\n");
+ fprintf(stderr, "--load <load> or -l <load>\n");
+ fprintf(stderr, "--verbose <level> or -v <level>\n");
+ fprintf(stderr, "--exhaustive or -e\n");
+ fprintf(stderr, "--version or -V\n");
+ exit (1);
}
else {
- fflush(stdout);
- fprintf(stdout, "-----------------------------------------\n");
- fprintf(stdout, "Vesta static timing analysis tool\n");
- fprintf(stdout, "(c) 2013 Tim Edwards, Open Circuit Design\n");
- fprintf(stdout, "-----------------------------------------\n\n");
- fflush(stdout);
+ fflush(stdout);
+ fprintf(stdout, "-----------------------------------------\n");
+ fprintf(stdout, "Vesta static timing analysis tool\n");
+ fprintf(stdout, "(c) 2013 Tim Edwards, Open Circuit Design\n");
+ fprintf(stdout, "-----------------------------------------\n\n");
+ fflush(stdout);
}
fsrc = fopen(argv[firstarg], "r");
if (fsrc == NULL) {
- fprintf(stderr, "Cannot open %s for reading\n", argv[firstarg]);
- exit (1);
+ fprintf(stderr, "Cannot open %s for reading\n", argv[firstarg]);
+ exit (1);
}
flib = fopen(argv[firstarg + 1], "r");
if (flib == NULL) {
- fprintf(stderr, "Cannot open %s for reading\n", argv[firstarg + 1]);
- exit (1);
+ fprintf(stderr, "Cannot open %s for reading\n", argv[firstarg + 1]);
+ exit (1);
}
/*------------------------------------------------------------------*/
- /* Generate one table template for the "scalar" case */
+ /* Generate one table template for the "scalar" case */
/*------------------------------------------------------------------*/
scalar = (lutable *)malloc(sizeof(lutable));
@@ -3107,7 +3180,7 @@ main(int objc, char *argv[])
tables = scalar;
/*------------------------------------------------------------------*/
- /* Read the liberty format file. This is not a rigorous parser! */
+ /* Read the liberty format file. This is not a rigorous parser! */
/*------------------------------------------------------------------*/
fileCurrentLine = 0;
@@ -3117,68 +3190,88 @@ main(int objc, char *argv[])
if (flib != NULL) fclose(flib);
/*--------------------------------------------------*/
- /* Debug: Print summary of liberty database */
+ /* Debug: Print summary of liberty database */
/*--------------------------------------------------*/
if (verbose > 2) {
- lutable *newtable;
- cell *newcell;
- pin *newpin;
-
- for (newtable = tables; newtable; newtable = newtable->next) {
- fprintf(stdout, "Table: %s\n", newtable->name);
- }
-
- for (newcell = cells; newcell; newcell = newcell->next) {
- fprintf(stdout, "Cell: %s\n", newcell->name);
- fprintf(stdout, " Function: %s\n", newcell->function);
- for (newpin = newcell->pins; newpin; newpin = newpin->next) {
- if (newpin->type == INPUT)
- fprintf(stdout, " Pin: %s cap=%g\n", newpin->name, newpin->capr);
- }
- fprintf(stdout, "\n");
- }
+ lutable *newtable;
+ cell *newcell;
+ pin *newpin;
+
+ for (newtable = tables; newtable; newtable = newtable->next) {
+ fprintf(stdout, "Table: %s\n", newtable->name);
+ }
+
+ for (newcell = cells; newcell; newcell = newcell->next) {
+ fprintf(stdout, "Cell: %s\n", newcell->name);
+ fprintf(stdout, " Function: %s\n", newcell->function);
+ for (newpin = newcell->pins; newpin; newpin = newpin->next) {
+ if (newpin->type == INPUT)
+ fprintf(stdout, " Pin: %s cap=%g\n", newpin->name, newpin->capr);
+ }
+ fprintf(stdout, "\n");
+ }
}
/*------------------------------------------------------------------*/
- /* Read verilog netlist. This is also not a rigorous parser! */
+ /* Read verilog netlist. This is also not a rigorous parser! */
/*------------------------------------------------------------------*/
+ struct hashlist *Nethash[OBJHASHSIZE];
+
+ /* See hash.c for these routines and variables */
+ hashfunc = hash;
+ matchfunc = match;
+
+ /* Initialize net hash table */
+ InitializeHashTable(Nethash);
+
fileCurrentLine = 0;
- verilogRead(fsrc, cells, &netlist, &instlist, &inputlist, &outputlist);
+
+ verilogRead(fsrc, cells, &netlist, &instlist, &inputlist, &outputlist, Nethash);
+
+ if (delayfile != NULL) {
+ fdly = fopen(delayfile, "r");
+
+ if (fdly == NULL) {
+ fprintf(stderr, "Cannot open %s for reading\n", delayfile);
+ exit (1);
+ }
+ }
+
fflush(stdout);
fprintf(stdout, "Verilog netlist read: Processed %d lines.\n", fileCurrentLine);
if (fsrc != NULL) fclose(fsrc);
/*--------------------------------------------------*/
- /* Debug: Print summary of verilog source */
+ /* Debug: Print summary of verilog source */
/*--------------------------------------------------*/
if (verbose > 1) {
- connect *testoutput;
- connect *testinput;
- net *testnet;
- instance *testinst;
-
- for (testinput = inputlist; testinput; testinput = testinput->next) {
- if (testinput->refnet)
- fprintf(stdout, " Input: %s\n", testinput->refnet->name);
- }
- for (testoutput = outputlist; testoutput; testoutput = testoutput->next) {
- if (testoutput->refnet)
- fprintf(stdout, " Output: %s\n", testoutput->refnet->name);
- }
- for (testnet = netlist; testnet; testnet = testnet->next) {
- fprintf(stdout, " Net: %s\n", testnet->name);
- }
- for (testinst = instlist; testinst; testinst = testinst->next) {
- fprintf(stdout, " Gate: %s\n", testinst->name);
- }
+ connect *testoutput;
+ connect *testinput;
+ net *testnet;
+ instance *testinst;
+
+ for (testinput = inputlist; testinput; testinput = testinput->next) {
+ if (testinput->refnet)
+ fprintf(stdout, " Input: %s\n", testinput->refnet->name);
+ }
+ for (testoutput = outputlist; testoutput; testoutput = testoutput->next) {
+ if (testoutput->refnet)
+ fprintf(stdout, " Output: %s\n", testoutput->refnet->name);
+ }
+ for (testnet = netlist; testnet; testnet = testnet->next) {
+ fprintf(stdout, " Net: %s\n", testnet->name);
+ }
+ for (testinst = instlist; testinst; testinst = testinst->next) {
+ fprintf(stdout, " Gate: %s\n", testinst->name);
+ }
}
/*--------------------------------------------------*/
- /* Generate internal links representing the network */
+ /* Generate internal links representing the network */
/*--------------------------------------------------*/
createLinks(netlist, instlist, inputlist, outputlist);
@@ -3186,39 +3279,47 @@ main(int objc, char *argv[])
/* Generate a connection list from inputlist */
for (testconn = inputlist; testconn; testconn = testconn->next) {
- newinputconn = (connlistptr)malloc(sizeof(connlist));
- newinputconn->connection = testconn;
- newinputconn->next = inputconnlist;
- inputconnlist = newinputconn;
+ newinputconn = (connlistptr)malloc(sizeof(connlist));
+ newinputconn->connection = testconn;
+ newinputconn->next = inputconnlist;
+ inputconnlist = newinputconn;
}
/*--------------------------------------------------*/
- /* Calculate total load on each net */
- /* To do: Add wire models or computed wire delays */
+ /* Assign net types, mainly to identify clocks */
+ /* Return a list of clock nets */
/*--------------------------------------------------*/
- computeLoads(netlist, instlist, outLoad);
+ numterms = assign_net_types(netlist, &clockconnlist);
+
+ if (verbose > 1)
+ fprintf(stdout, "Number of terminals to check: %d\n", numterms);
/*--------------------------------------------------*/
- /* Assign net types, mainly to identify clocks */
- /* Return a list of clock nets */
+ /* Calculate total load on each net */
+ /* To do: Add wire models or computed wire delays */
/*--------------------------------------------------*/
- numterms = assign_net_types(netlist, &clockconnlist);
+ if (fdly != NULL) {
+ delayRead(fdly, Nethash);
+ fclose(fdly);
+ }
- if (verbose > 1)
- fprintf(stdout, "Number of terminals to check: %d\n", numterms);
+ /* Hash table no longer needed */
+ HashKill(Nethash);
+
+ computeLoads(netlist, instlist, outLoad);
/*--------------------------------------------------*/
- /* Identify all clock-to-terminal paths */
+ /* Identify all clock-to-terminal paths */
/*--------------------------------------------------*/
numpaths = find_clock_to_term_paths(clockconnlist, &pathlist, netlist, MAXIMUM_TIME);
fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
/*--------------------------------------------------*/
- /* Collect paths into a non-linked array so that */
- /* they can be sorted by delay time */
+ /* Collect paths into a non-linked array so that */
+ /* they can be sorted by delay time */
/*--------------------------------------------------*/
orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
@@ -3232,82 +3333,82 @@ main(int objc, char *argv[])
qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
/*--------------------------------------------------*/
- /* Report on top 20 maximum delay paths */
+ /* Report on top 20 maximum delay paths */
/*--------------------------------------------------*/
fprintf(stdout, "\nTop %d maximum delay paths:\n", (numpaths >= 20) ? 20 : numpaths);
badtiming = 0;
for (i = 0; ((i < 20) && (i < numpaths)); i++) {
- testddata = orderedpaths[i];
- for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
-
- if (testddata->backtrace->receiver->refinst != NULL) {
- fprintf(stdout, "Path %s/%s to %s/%s delay %g ps",
- testbt->receiver->refinst->name,
- testbt->receiver->refpin->name,
- testddata->backtrace->receiver->refinst->name,
- testddata->backtrace->receiver->refpin->name,
- testddata->delay);
- }
- else {
- fprintf(stdout, "Path %s/%s to output pin %s delay %g ps",
- testbt->receiver->refinst->name,
- testbt->receiver->refpin->name,
- testddata->backtrace->receiver->refnet->name,
- testddata->delay);
- }
-
- if (period > 0.0) {
- slack = period - testddata->delay;
- fprintf(stdout, " Slack = %g ps", slack);
- if (slack < 0.0) badtiming = 1;
- }
- fprintf(stdout, "\n");
+ testddata = orderedpaths[i];
+ for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
+
+ if (testddata->backtrace->receiver->refinst != NULL) {
+ fprintf(stdout, "Path %s/%s to %s/%s delay %g ps",
+ testbt->receiver->refinst->name,
+ testbt->receiver->refpin->name,
+ testddata->backtrace->receiver->refinst->name,
+ testddata->backtrace->receiver->refpin->name,
+ testddata->delay);
+ }
+ else {
+ fprintf(stdout, "Path %s/%s to output pin %s delay %g ps",
+ testbt->receiver->refinst->name,
+ testbt->receiver->refpin->name,
+ testddata->backtrace->receiver->refnet->name,
+ testddata->delay);
+ }
+
+ if (period > 0.0) {
+ slack = period - testddata->delay;
+ fprintf(stdout, " Slack = %g ps", slack);
+ if (slack < 0.0) badtiming = 1;
+ }
+ fprintf(stdout, "\n");
}
if (period > 0.0) {
- if (badtiming) {
- fprintf(stdout, "ERROR: Design fails timing requirements.\n");
- }
- else {
- fprintf(stdout, "Design meets timing requirements.\n");
- }
+ if (badtiming) {
+ fprintf(stdout, "ERROR: Design fails timing requirements.\n");
+ }
+ else {
+ fprintf(stdout, "Design meets timing requirements.\n");
+ }
}
else if (orderedpaths[0] != NULL) {
- fprintf(stdout, "Computed maximum clock frequency (zero slack) = %g MHz\n",
- (1.0E6 / orderedpaths[0]->delay));
+ fprintf(stdout, "Computed maximum clock frequency (zero slack) = %g MHz\n",
+ (1.0E6 / orderedpaths[0]->delay));
}
fprintf(stdout, "-----------------------------------------\n\n");
fflush(stdout);
/*--------------------------------------------------*/
- /* Clean up the path list */
+ /* Clean up the path list */
/*--------------------------------------------------*/
while (pathlist != NULL) {
- freeddata = pathlist;
- pathlist = pathlist->next;
- while (freeddata->backtrace != NULL) {
- freebt = freeddata->backtrace;
- freeddata->backtrace = freeddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt == 0) free(freebt);
- }
- free(freeddata);
+ freeddata = pathlist;
+ pathlist = pathlist->next;
+ while (freeddata->backtrace != NULL) {
+ freebt = freeddata->backtrace;
+ freeddata->backtrace = freeddata->backtrace->next;
+ freebt->refcnt--;
+ if (freebt->refcnt == 0) free(freebt);
+ }
+ free(freeddata);
}
free(orderedpaths);
/*--------------------------------------------------*/
- /* Now calculate minimum delay paths */
+ /* Now calculate minimum delay paths */
/*--------------------------------------------------*/
numpaths = find_clock_to_term_paths(clockconnlist, &pathlist, netlist, MINIMUM_TIME);
fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
/*--------------------------------------------------*/
- /* Collect paths into a non-linked array so that */
- /* they can be sorted by delay time */
+ /* Collect paths into a non-linked array so that */
+ /* they can be sorted by delay time */
/*--------------------------------------------------*/
orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
@@ -3321,74 +3422,74 @@ main(int objc, char *argv[])
qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
/*--------------------------------------------------*/
- /* Report on top 20 minimum delay paths */
+ /* Report on top 20 minimum delay paths */
/*--------------------------------------------------*/
fprintf(stdout, "\nTop %d minimum delay paths:\n", (numpaths >= 20) ? 20 : numpaths);
badtiming = 0;
for (i = numpaths; (i > (numpaths - 20)) && (i > 0); i--) {
- testddata = orderedpaths[i - 1];
- for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
-
- if (testddata->backtrace->receiver->refinst != NULL) {
- fprintf(stdout, "Path %s/%s to %s/%s delay %g ps\n",
- testbt->receiver->refinst->name,
- testbt->receiver->refpin->name,
- testddata->backtrace->receiver->refinst->name,
- testddata->backtrace->receiver->refpin->name,
- testddata->delay);
- }
- else {
- fprintf(stdout, "Path %s/%s to output pin %s delay %g ps\n",
- testbt->receiver->refinst->name,
- testbt->receiver->refpin->name,
- testddata->backtrace->receiver->refnet->name,
- testddata->delay);
- }
-
- if (testddata->delay < 0.0) badtiming = 1;
+ testddata = orderedpaths[i - 1];
+ for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
+
+ if (testddata->backtrace->receiver->refinst != NULL) {
+ fprintf(stdout, "Path %s/%s to %s/%s delay %g ps\n",
+ testbt->receiver->refinst->name,
+ testbt->receiver->refpin->name,
+ testddata->backtrace->receiver->refinst->name,
+ testddata->backtrace->receiver->refpin->name,
+ testddata->delay);
+ }
+ else {
+ fprintf(stdout, "Path %s/%s to output pin %s delay %g ps\n",
+ testbt->receiver->refinst->name,
+ testbt->receiver->refpin->name,
+ testddata->backtrace->receiver->refnet->name,
+ testddata->delay);
+ }
+
+ if (testddata->delay < 0.0) badtiming = 1;
}
if (badtiming)
- fprintf(stdout, "ERROR: Design fails minimum hold timing.\n");
+ fprintf(stdout, "ERROR: Design fails minimum hold timing.\n");
else
- fprintf(stdout, "Design meets minimum hold timing.\n");
+ fprintf(stdout, "Design meets minimum hold timing.\n");
fprintf(stdout, "-----------------------------------------\n\n");
fflush(stdout);
/*--------------------------------------------------*/
- /* Clean up the path list */
+ /* Clean up the path list */
/*--------------------------------------------------*/
while (pathlist != NULL) {
- freeddata = pathlist;
- pathlist = pathlist->next;
- while (freeddata->backtrace != NULL) {
- freebt = freeddata->backtrace;
- freeddata->backtrace = freeddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt == 0) free(freebt);
- }
- free(freeddata);
+ freeddata = pathlist;
+ pathlist = pathlist->next;
+ while (freeddata->backtrace != NULL) {
+ freebt = freeddata->backtrace;
+ freeddata->backtrace = freeddata->backtrace->next;
+ freebt->refcnt--;
+ if (freebt->refcnt == 0) free(freebt);
+ }
+ free(freeddata);
}
free(orderedpaths);
for (testconn = inputlist; testconn; testconn = testconn->next) {
- testconn->tag = NULL;
- testconn->metric = -1;
+ testconn->tag = NULL;
+ testconn->metric = -1;
}
/*--------------------------------------------------*/
- /* Identify all input-to-terminal paths */
+ /* Identify all input-to-terminal paths */
/*--------------------------------------------------*/
numpaths = find_clock_to_term_paths(inputconnlist, &pathlist, netlist, MAXIMUM_TIME);
fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
/*--------------------------------------------------*/
- /* Collect paths into a non-linked array so that */
- /* they can be sorted by delay time */
+ /* Collect paths into a non-linked array so that */
+ /* they can be sorted by delay time */
/*--------------------------------------------------*/
orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
@@ -3402,65 +3503,65 @@ main(int objc, char *argv[])
qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
/*--------------------------------------------------*/
- /* Report on top 20 maximum delay paths */
+ /* Report on top 20 maximum delay paths */
/*--------------------------------------------------*/
fprintf(stdout, "\nTop %d maximum delay paths:\n", (numpaths >= 20) ? 20 : numpaths);
for (i = 0; ((i < 20) && (i < numpaths)); i++) {
- testddata = orderedpaths[i];
- for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
-
- if (testddata->backtrace->receiver->refinst != NULL) {
- fprintf(stdout, "Path input pin %s to %s/%s delay %g ps\n",
- testbt->receiver->refnet->name,
- testddata->backtrace->receiver->refinst->name,
- testddata->backtrace->receiver->refpin->name,
- testddata->delay);
- }
- else {
- fprintf(stdout, "Path input pin %s to output pin %s delay %g ps\n",
- testbt->receiver->refnet->name,
- testddata->backtrace->receiver->refnet->name,
- testddata->delay);
- }
+ testddata = orderedpaths[i];
+ for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
+
+ if (testddata->backtrace->receiver->refinst != NULL) {
+ fprintf(stdout, "Path input pin %s to %s/%s delay %g ps\n",
+ testbt->receiver->refnet->name,
+ testddata->backtrace->receiver->refinst->name,
+ testddata->backtrace->receiver->refpin->name,
+ testddata->delay);
+ }
+ else {
+ fprintf(stdout, "Path input pin %s to output pin %s delay %g ps\n",
+ testbt->receiver->refnet->name,
+ testddata->backtrace->receiver->refnet->name,
+ testddata->delay);
+ }
}
fprintf(stdout, "-----------------------------------------\n\n");
fflush(stdout);
/*--------------------------------------------------*/
- /* Clean up the path list */
+ /* Clean up the path list */
/*--------------------------------------------------*/
while (pathlist != NULL) {
- freeddata = pathlist;
- pathlist = pathlist->next;
- while (freeddata->backtrace != NULL) {
- freebt = freeddata->backtrace;
- freeddata->backtrace = freeddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt == 0) free(freebt);
- }
- free(freeddata);
+ freeddata = pathlist;
+ pathlist = pathlist->next;
+ while (freeddata->backtrace != NULL) {
+ freebt = freeddata->backtrace;
+ freeddata->backtrace = freeddata->backtrace->next;
+ freebt->refcnt--;
+ if (freebt->refcnt == 0) free(freebt);
+ }
+ free(freeddata);
}
free(orderedpaths);
for (testconn = inputlist; testconn; testconn = testconn->next) {
- testconn->tag = NULL;
- testconn->metric = 1E50;
+ testconn->tag = NULL;
+ testconn->metric = 1E50;
}
/*--------------------------------------------------*/
- /* Now calculate minimum delay paths from inputs */
+ /* Now calculate minimum delay paths from inputs */
/*--------------------------------------------------*/
numpaths = find_clock_to_term_paths(inputconnlist, &pathlist, netlist, MINIMUM_TIME);
fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
/*--------------------------------------------------*/
- /* Collect paths into a non-linked array so that */
- /* they can be sorted by delay time */
+ /* Collect paths into a non-linked array so that */
+ /* they can be sorted by delay time */
/*--------------------------------------------------*/
orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
@@ -3474,46 +3575,46 @@ main(int objc, char *argv[])
qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
/*--------------------------------------------------*/
- /* Report on top 20 minimum delay paths */
+ /* Report on top 20 minimum delay paths */
/*--------------------------------------------------*/
fprintf(stdout, "\nTop %d minimum delay paths:\n", (numpaths >= 20) ? 20 : numpaths);
for (i = numpaths; (i > (numpaths - 20)) && (i > 0); i--) {
- testddata = orderedpaths[i - 1];
- for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
-
- if (testddata->backtrace->receiver->refinst != NULL) {
- fprintf(stdout, "Path input pin %s to %s/%s delay %g ps\n",
- testbt->receiver->refnet->name,
- testddata->backtrace->receiver->refinst->name,
- testddata->backtrace->receiver->refpin->name,
- testddata->delay);
- }
- else {
- fprintf(stdout, "Path input pin %s to output pin %s delay %g ps\n",
- testbt->receiver->refnet->name,
- testddata->backtrace->receiver->refnet->name,
- testddata->delay);
- }
+ testddata = orderedpaths[i - 1];
+ for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
+
+ if (testddata->backtrace->receiver->refinst != NULL) {
+ fprintf(stdout, "Path input pin %s to %s/%s delay %g ps\n",
+ testbt->receiver->refnet->name,
+ testddata->backtrace->receiver->refinst->name,
+ testddata->backtrace->receiver->refpin->name,
+ testddata->delay);
+ }
+ else {
+ fprintf(stdout, "Path input pin %s to output pin %s delay %g ps\n",
+ testbt->receiver->refnet->name,
+ testddata->backtrace->receiver->refnet->name,
+ testddata->delay);
+ }
}
fprintf(stdout, "-----------------------------------------\n\n");
fflush(stdout);
/*--------------------------------------------------*/
- /* Clean up the path list */
+ /* Clean up the path list */
/*--------------------------------------------------*/
while (pathlist != NULL) {
- freeddata = pathlist;
- pathlist = pathlist->next;
- while (freeddata->backtrace != NULL) {
- freebt = freeddata->backtrace;
- freeddata->backtrace = freeddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt == 0) free(freebt);
- }
- free(freeddata);
+ freeddata = pathlist;
+ pathlist = pathlist->next;
+ while (freeddata->backtrace != NULL) {
+ freebt = freeddata->backtrace;
+ freeddata->backtrace = freeddata->backtrace->next;
+ freebt->refcnt--;
+ if (freebt->refcnt == 0) free(freebt);
+ }
+ free(freeddata);
}
free(orderedpaths);