summaryrefslogtreecommitdiff
path: root/qrouter.c
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2017-03-17 13:42:43 +0100
committerRuben Undheim <ruben.undheim@gmail.com>2017-03-17 13:42:43 +0100
commit35fff0dc1518cec0b8ab7062ef14b36095849ac1 (patch)
tree909a59201eb4ee09c4ec92e6071948b3b85494d6 /qrouter.c
parent196d5accdbc60e0202cfe1c5fcf97d0ac8041293 (diff)
Imported Upstream version 1.3.67
Diffstat (limited to 'qrouter.c')
-rw-r--r--qrouter.c1151
1 files changed, 1039 insertions, 112 deletions
diff --git a/qrouter.c b/qrouter.c
index 67debc8..b657089 100644
--- a/qrouter.c
+++ b/qrouter.c
@@ -14,6 +14,10 @@
#include <string.h>
#include <unistd.h>
+#ifdef TCL_QROUTER
+#include <tk.h>
+#endif
+
#include "qrouter.h"
#include "qconfig.h"
#include "node.h"
@@ -56,7 +60,8 @@ u_char mapType = MAP_OBSTRUCT | DRAW_ROUTES;
u_char ripLimit = 10; // Fail net rather than rip up more than
// this number of other nets.
-char DEFfilename[256];
+char *DEFfilename = NULL;
+char *delayfilename = NULL;
ScaleRec Scales; // record of input and output scales
@@ -78,38 +83,86 @@ static void helpmessage(void);
int set_num_channels(void)
{
- int i;
+ int i, glimitx, glimity;
+ NET net;
+ NODE node;
+ DPOINT ctap, ltap, ntap;
- if (NumChannelsX[0] != 0) return 0; /* Already been called */
+ if (NumChannelsX[0] != 0) return 0; /* Already been called */
- for (i = 0; i < Num_layers; i++) {
- if (PitchX[i] == 0.0 || PitchY[i] == 0.0) {
- Fprintf(stderr, "Have a 0 pitch for layer %d (of %d). "
+ for (i = 0; i < Num_layers; i++) {
+ if (PitchX[i] == 0.0 || PitchY[i] == 0.0) {
+ Fprintf(stderr, "Have a 0 pitch for layer %d (of %d). "
"Exit.\n", i + 1, Num_layers);
- return (-3);
- }
- NumChannelsX[i] = (int)(1.5 + (Xupperbound - Xlowerbound) / PitchX[i]);
- NumChannelsY[i] = (int)(1.5 + (Yupperbound - Ylowerbound) / PitchY[i]);
- if ((Verbose > 1) || (NumChannelsX[i] <= 0))
- Fprintf(stdout, "Number of x channels for layer %d is %d\n",
- i, NumChannelsX[i]);
- if ((Verbose > 1) || (NumChannelsY[i] <= 0))
- Fprintf(stdout, "Number of y channels for layer %d is %d\n",
- i, NumChannelsY[i]);
+ return (-3);
+ }
+ NumChannelsX[i] = (int)(1.5 + (Xupperbound - Xlowerbound) / PitchX[i]);
+ NumChannelsY[i] = (int)(1.5 + (Yupperbound - Ylowerbound) / PitchY[i]);
+ if ((Verbose > 1) || (NumChannelsX[i] <= 0))
+ Fprintf(stdout, "Number of x channels for layer %d is %d\n",
+ i, NumChannelsX[i]);
+ if ((Verbose > 1) || (NumChannelsY[i] <= 0))
+ Fprintf(stdout, "Number of y channels for layer %d is %d\n",
+ i, NumChannelsY[i]);
- if (NumChannelsX[i] <= 0) {
- Fprintf(stderr, "Something wrong with layer %d x bounds.\n", i);
- return(-3);
- }
- if (NumChannelsY[i] <= 0) {
- Fprintf(stderr, "Something wrong with layer %d y bounds.\n", i);
- return(-3);
- }
- Flush(stdout);
- }
+ if (NumChannelsX[i] <= 0) {
+ Fprintf(stderr, "Something wrong with layer %d x bounds.\n", i);
+ return(-3);
+ }
+ if (NumChannelsY[i] <= 0) {
+ Fprintf(stderr, "Something wrong with layer %d y bounds.\n", i);
+ return(-3);
+ }
+ Flush(stdout);
+ }
- if (recalc_spacing()) draw_layout();
- return 0;
+ // Go through all nodes and remove any tap or extend entries that are
+ // out of bounds.
+
+ for (i = 0; i < Numnets; i++) {
+ net = Nlnets[i];
+ for (node = net->netnodes; node != NULL; node = node->next) {
+
+ ltap = NULL;
+ for (ctap = node->taps; ctap != NULL; ) {
+ ntap = ctap->next;
+ glimitx = NumChannelsX[ctap->layer];
+ glimity = NumChannelsY[ctap->layer];
+ if (ctap->gridx < 0 || ctap->gridx >= glimitx ||
+ ctap->gridy < 0 || ctap->gridy >= glimity) {
+ /* Remove ctap */
+ if (ltap == NULL)
+ node->taps = ntap;
+ else
+ ltap->next = ntap;
+ }
+ else
+ ltap = ctap;
+ ctap = ntap;
+ }
+
+ ltap = NULL;
+ for (ctap = node->extend; ctap != NULL; ) {
+ ntap = ctap->next;
+ glimitx = NumChannelsX[ctap->layer];
+ glimity = NumChannelsY[ctap->layer];
+ if (ctap->gridx < 0 || ctap->gridx >= glimitx ||
+ ctap->gridy < 0 || ctap->gridy >= glimity) {
+ /* Remove ctap */
+ if (ltap == NULL)
+ node->taps = ntap;
+ else
+ ltap->next = ntap;
+ }
+ else
+ ltap = ctap;
+ ctap = ntap;
+ }
+ }
+ }
+
+ if (recalc_spacing()) draw_layout();
+ return 0;
}
/*--------------------------------------------------------------*/
@@ -168,13 +221,11 @@ runqrouter(int argc, char *argv[])
char *configfile = configdefault;
char *infofile = NULL;
char *dotptr;
- char Filename[256];
+ char *Filename = NULL;
u_char readconfig = FALSE;
Scales.iscale = 1;
Scales.mscale = 100;
- Filename[0] = 0;
- DEFfilename[0] = 0;
/* Parse arguments */
@@ -192,6 +243,7 @@ runqrouter(int argc, char *argv[])
case 'i':
case 'k':
case 'v':
+ case 'd':
case 'p':
case 'g':
case 'r':
@@ -228,6 +280,10 @@ runqrouter(int argc, char *argv[])
case 'i':
infofile = strdup(optarg);
break;
+ case 'd':
+ if (delayfilename != NULL) free(delayfilename);
+ delayfilename = strdup(optarg);
+ break;
case 'p':
vddnet = strdup(optarg);
break;
@@ -263,12 +319,14 @@ runqrouter(int argc, char *argv[])
}
else {
/* Not an option or an option argument, so treat as a filename */
- strcpy( Filename, argv[i] );
+ Filename = strdup(argv[i]);
}
}
- if (infofile != NULL)
+ if (infofile != NULL) {
infoFILEptr = fopen(infofile, "w" );
+ free(infofile);
+ }
else {
infoFILEptr = NULL;
#ifndef TCL_QROUTER
@@ -358,12 +416,14 @@ runqrouter(int argc, char *argv[])
return 1;
}
- if (Filename[0] != '\0') {
+ if (Filename != NULL) {
/* process last non-option string */
dotptr = strrchr(Filename, '.');
if (dotptr != NULL) *dotptr = '\0';
+ if (DEFfilename != NULL) free(DEFfilename);
+ DEFfilename = (char *)malloc(strlen(Filename) + 5);
sprintf(DEFfilename, "%s.def", Filename);
}
else if (readconfig) {
@@ -512,7 +572,7 @@ static int post_def_setup()
int i;
double sreq1, sreq2;
- if (DEFfilename[0] == '\0') {
+ if (DEFfilename == NULL) {
Fprintf(stderr, "No DEF file read, nothing to set up.\n");
return 1;
}
@@ -660,13 +720,16 @@ void read_def(char *filename)
{
double oscale, precis;
- if ((filename == NULL) && (DEFfilename[0] == '\0')) {
+ if ((filename == NULL) && (DEFfilename == NULL)) {
Fprintf(stderr, "No DEF file specified, nothing to read.\n");
return;
}
else if (filename != NULL) {
- if (DEFfilename[0] != '\0') reinitialize();
- strcpy(DEFfilename, filename);
+ if (DEFfilename != NULL) {
+ reinitialize();
+ free(DEFfilename);
+ }
+ DEFfilename = strdup(filename);
}
else reinitialize();
@@ -756,6 +819,7 @@ int dofirststage(u_char graphdebug, int debug_netnum)
}
/*--------------------------------------------------------------*/
+/* Write the output annotated DEF file. */
/*--------------------------------------------------------------*/
int write_def(char *filename)
@@ -763,8 +827,6 @@ int write_def(char *filename)
NET net;
NETLIST nl;
- // Finish up by writing the routes to an annotated DEF file
-
emit_routes((filename == NULL) ? DEFfilename : filename,
Scales.oscale, Scales.iscale);
@@ -864,9 +926,9 @@ pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty,
if ((x != lastx) && (y != lasty)) {
if (horizontal)
- pathto(cmd, x, y, FALSE, x, lasty, invscale);
+ pathto(cmd, lastx, y, FALSE, lastx, lasty, invscale);
else
- pathto(cmd, x, y, TRUE, lastx, y, invscale);
+ pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale);
}
fprintf(cmd, "( ");
@@ -921,7 +983,7 @@ pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty,
// route to the via.
if (x != lastx)
- pathto(cmd, x, y, TRUE, lastx, y, invscale);
+ pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale);
if (y != lasty)
pathto(cmd, x, y, FALSE, x, lasty, invscale);
}
@@ -1456,8 +1518,10 @@ dosecondstage(u_char graphdebug, u_char singlestep)
// Remove routing information for all new routes that have
// not been copied back into Obs[].
- if (rt == NULL)
+ if (rt == NULL) {
rt = net->routes;
+ net->routes = NULL; // remove defunct pointer
+ }
else {
rt2 = rt->next;
rt->next = NULL;
@@ -1470,6 +1534,7 @@ dosecondstage(u_char graphdebug, u_char singlestep)
free(rt->segments);
rt->segments = seg;
}
+ free(rt);
rt = rt2;
}
@@ -2045,6 +2110,26 @@ static void fillMask(u_char value) {
}
/*--------------------------------------------------------------*/
+/* Free memory of an iroute glist and clear the Obs2 */
+/* PR_ON_STACK flag for each location in the list. */
+/*--------------------------------------------------------------*/
+
+void
+free_glist(struct routeinfo_ *iroute)
+{
+ POINT gpoint;
+ PROUTE *Pr;
+
+ while (iroute->glist) {
+ gpoint = iroute->glist;
+ iroute->glist = iroute->glist->next;
+ Pr = &OBS2VAL(gpoint->x1, gpoint->y1, gpoint->layer);
+ Pr->flags &= ~PR_ON_STACK;
+ free(gpoint);
+ }
+}
+
+/*--------------------------------------------------------------*/
/* doroute - basic route call */
/* */
/* stage = 0 is normal routing */
@@ -2137,25 +2222,14 @@ int doroute(NET net, u_char stage, u_char graphdebug)
// For power routing, clear the list of existing pending route
// solutions---they will not be relevant.
- if (iroute.do_pwrbus) {
- while (iroute.glist) {
- gpoint = iroute.glist;
- iroute.glist = iroute.glist->next;
- free(gpoint);
- }
- }
+ if (iroute.do_pwrbus) free_glist(&iroute);
/* Set up for next route and check if routing is done */
result = next_route_setup(&iroute, stage);
}
/* Finished routing (or error occurred) */
-
- while (iroute.glist) {
- gpoint = iroute.glist;
- iroute.glist = iroute.glist->next;
- free(gpoint);
- }
+ free_glist(&iroute);
/* Route failure due to no taps or similar error---Log it */
if ((result < 0) || (unroutable > 0)) {
@@ -2271,11 +2345,7 @@ static int next_route_setup(struct routeinfo_ *iroute, u_char stage)
}
}
- while (iroute->glist) {
- gpoint = iroute->glist;
- iroute->glist = iroute->glist->next;
- free(gpoint);
- }
+ free_glist(iroute);
return 0;
}
@@ -2447,11 +2517,7 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
}
}
- while (iroute->glist) {
- gpoint = iroute->glist;
- iroute->glist = iroute->glist->next;
- free(gpoint);
- }
+ free_glist(iroute);
return 0;
}
@@ -2527,12 +2593,12 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug)
{
- POINT gpoint, gunproc;
+ POINT gpoint, gunproc, newpt;
int i, o;
int pass, maskpass;
u_int forbid;
GRIDP best, curpt;
- int result, rval;
+ int rval;
u_char first = (u_char)1;
u_char check_order[6];
u_char max_reached;
@@ -2573,6 +2639,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
// ignore grid positions that have already been processed
if (Pr->flags & PR_PROCESSED) {
+ Pr->flags &= ~PR_ON_STACK;
free(gpoint);
continue;
}
@@ -2613,6 +2680,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
// Don't continue processing from the target
Pr->flags |= PR_PROCESSED;
+ Pr->flags &= ~PR_ON_STACK;
free(gpoint);
continue;
}
@@ -2640,6 +2708,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
continue;
}
}
+ Pr->flags &= ~PR_ON_STACK;
free(gpoint);
// check east/west/north/south, and bottom to top
@@ -2682,11 +2751,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
case EAST:
predecessor |= PR_PRED_W;
if ((curpt.x + 1) < NumChannelsX[curpt.lay]) {
- if ((result = eval_pt(&curpt, predecessor, stage)) == 1) {
- gpoint = (POINT)malloc(sizeof(struct point_));
- gpoint->x1 = curpt.x + 1;
- gpoint->y1 = curpt.y;
- gpoint->layer = curpt.lay;
+ if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
gpoint->next = iroute->glist;
iroute->glist = gpoint;
}
@@ -2698,11 +2763,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
case WEST:
predecessor |= PR_PRED_E;
if ((curpt.x - 1) >= 0) {
- if ((result = eval_pt(&curpt, predecessor, stage)) == 1) {
- gpoint = (POINT)malloc(sizeof(struct point_));
- gpoint->x1 = curpt.x - 1;
- gpoint->y1 = curpt.y;
- gpoint->layer = curpt.lay;
+ if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
gpoint->next = iroute->glist;
iroute->glist = gpoint;
}
@@ -2714,11 +2775,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
case SOUTH:
predecessor |= PR_PRED_N;
if ((curpt.y - 1) >= 0) {
- if ((result = eval_pt(&curpt, predecessor, stage)) == 1) {
- gpoint = (POINT)malloc(sizeof(struct point_));
- gpoint->x1 = curpt.x;
- gpoint->y1 = curpt.y - 1;
- gpoint->layer = curpt.lay;
+ if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
gpoint->next = iroute->glist;
iroute->glist = gpoint;
}
@@ -2730,11 +2787,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
case NORTH:
predecessor |= PR_PRED_S;
if ((curpt.y + 1) < NumChannelsY[curpt.lay]) {
- if ((result = eval_pt(&curpt, predecessor, stage)) == 1) {
- gpoint = (POINT)malloc(sizeof(struct point_));
- gpoint->x1 = curpt.x;
- gpoint->y1 = curpt.y + 1;
- gpoint->layer = curpt.lay;
+ if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
gpoint->next = iroute->glist;
iroute->glist = gpoint;
}
@@ -2746,11 +2799,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
case DOWN:
predecessor |= PR_PRED_U;
if (curpt.lay > 0) {
- if ((result = eval_pt(&curpt, predecessor, stage)) == 1) {
- gpoint = (POINT)malloc(sizeof(struct point_));
- gpoint->x1 = curpt.x;
- gpoint->y1 = curpt.y;
- gpoint->layer = curpt.lay - 1;
+ if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
gpoint->next = iroute->glist;
iroute->glist = gpoint;
}
@@ -2762,11 +2811,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
case UP:
predecessor |= PR_PRED_D;
if (curpt.lay < (Num_layers - 1)) {
- if ((result = eval_pt(&curpt, predecessor, stage)) == 1) {
- gpoint = (POINT)malloc(sizeof(struct point_));
- gpoint->x1 = curpt.x;
- gpoint->y1 = curpt.y;
- gpoint->layer = curpt.lay + 1;
+ if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
gpoint->next = iroute->glist;
iroute->glist = gpoint;
}
@@ -2780,11 +2825,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
} // while stack is not empty
- while (iroute->glist) {
- gpoint = iroute->glist;
- iroute->glist = iroute->glist->next;
- free(gpoint);
- }
+ free_glist(iroute);
// If we found a route, save it and return
@@ -2838,10 +2879,9 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
rval = -1;
done:
-
+
// Regenerate the stack of unprocessed nodes
- iroute->glist = gunproc;
- gunproc = NULL;
+ if (gunproc != NULL) iroute->glist = gunproc;
return rval;
} /* route_segs() */
@@ -3650,13 +3690,13 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
tdir = OBSVAL(seg->x1 - 1, seg->y1, layer)
& ROUTED_NET_MASK;
- if ((tdir & NO_NET == 0) && (tdir != 0) &&
+ if (((tdir & NO_NET) == 0) && (tdir != 0) &&
(tdir != (net->netnum | ROUTED_NET))) {
if (layer < Num_layers - 1) {
tdirp = OBSVAL(seg->x1 - 1, seg->y1, layer + 1)
& ROUTED_NET_MASK;
- if ((tdirp & NO_NET == 0) && (tdirp != 0) &&
+ if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
(tdirp != (net->netnum | ROUTED_NET))) {
if (layer < Num_layers - 2) {
@@ -3681,13 +3721,13 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
tdir = OBSVAL(seg->x1 + 1, seg->y1, layer)
& ROUTED_NET_MASK;
- if ((tdir & NO_NET == 0) && (tdir != 0) &&
+ if (((tdir & NO_NET) == 0) && (tdir != 0) &&
(tdir != (net->netnum | ROUTED_NET))) {
if (layer < Num_layers - 1) {
tdirp = OBSVAL(seg->x1 + 1, seg->y1, layer + 1)
& ROUTED_NET_MASK;
- if ((tdirp & NO_NET == 0) && (tdirp != 0) &&
+ if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
(tdirp != (net->netnum | ROUTED_NET))) {
if (layer < Num_layers - 2) {
@@ -4160,7 +4200,6 @@ static void emit_routes(char *filename, double oscale, int iscale)
char netname[MAX_NAME_LEN];
NET net = NULL;
ROUTE rt;
- char newDEFfile[256];
FILE *fdef;
u_char errcond = FALSE;
u_char need_cleanup = FALSE;
@@ -4186,6 +4225,7 @@ static void emit_routes(char *filename, double oscale, int iscale)
char *dotptr;
if (filename == DEFfilename) {
+ char *newDEFfile = (char *)malloc(strlen(filename) + 11);
strcpy(newDEFfile, filename);
dotptr = strrchr(newDEFfile, '.');
if (dotptr)
@@ -4194,6 +4234,7 @@ static void emit_routes(char *filename, double oscale, int iscale)
strcat(newDEFfile, "_route.def");
Cmd = fopen(newDEFfile, "w");
+ free(newDEFfile);
}
else
Cmd = fopen(filename, "w");
@@ -4351,6 +4392,891 @@ static void emit_routes(char *filename, double oscale, int iscale)
} /* emit_routes() */
+#ifdef TCL_QROUTER
+
+/*--------------------------------------------------------------*/
+/* Find a node in the node list. */
+/*--------------------------------------------------------------*/
+
+/* Define record holding information pointing to a gate and the */
+/* index into a specific node of that gate. */
+
+typedef struct gatenode_ *GATENODE;
+
+struct gatenode_ {
+ GATE gate;
+ int idx;
+ u_char visited; /* flag for bookkeeping */
+};
+
+GATE
+FindGateNode(Tcl_HashTable *NodeTable, NODE node, int *ridx, u_char *flagptr)
+{
+ GATENODE gn;
+ GATE g;
+ Tcl_HashEntry *entry;
+
+ entry = Tcl_FindHashEntry(NodeTable, node);
+ if (entry) {
+ gn = (GATENODE)Tcl_GetHashValue(entry);
+ *ridx = gn->idx;
+ if (flagptr != NULL) {
+ *flagptr = gn->visited;
+ gn->visited = 1;
+ }
+ return gn->gate;
+ }
+ return NULL;
+}
+
+/*--------------------------------------------------------------*/
+/* Structure to hold information about endpoints of a route. */
+/*--------------------------------------------------------------*/
+
+typedef struct _endpointinfo {
+ ROUTE route;
+ int startx;
+ int starty;
+ int startl;
+ u_char starttype;
+ NODE startnode;
+ int endx;
+ int endy;
+ int endl;
+ u_char endtype;
+ NODE endnode;
+ u_char flags;
+} endpointinfo;
+
+/* Structure to hold R and C information for a path */
+
+typedef struct _rcinfo {
+ double res;
+ double cap;
+} rcinfo;
+
+/* Structure to hold R and C information for a layer/via */
+/* (viares is recorded for the layer number of the via bottom) */
+
+typedef struct _lefrcinfo {
+ double resx; /* Resistance per track in X */
+ double resy; /* Resistance per track in Y */
+ double capx; /* Capacitance per track in X */
+ double capy; /* Capacitance per track in Y */
+ double viares; /* Resistance per via */
+} lefrcinfo;
+
+/* Forward declaration */
+
+void walk_route(int, int, Tcl_HashTable *,
+ endpointinfo *, int, lefrcinfo *, FILE *);
+
+/*--------------------------------------------------------------*/
+/* Check for a route segment that is downstream of the current */
+/* segment (walkseg), and if found, process it. */
+/*--------------------------------------------------------------*/
+
+void
+check_downstream(SEG walkseg, NODE nodeptr, Tcl_HashTable *NodeTable,
+ endpointinfo *eptinfo, int numroutes,
+ lefrcinfo *lefrcvalues, rcinfo *rcvals, FILE *delayFile)
+{
+ int i;
+ int startcompat, endcompat;
+
+ /* At given segment "walkseg", find all routes that connect and walk them */
+ for (i = 0; i < numroutes; i++) {
+ if (eptinfo[i].flags == 1) continue; /* already visited */
+
+ /* Check wire/via layer compatibility */
+
+ if (eptinfo[i].starttype & ST_WIRE) {
+ if (walkseg->segtype & ST_WIRE)
+ startcompat = (walkseg->layer == eptinfo[i].startl);
+ else
+ startcompat = (walkseg->layer == eptinfo[i].startl) ||
+ (walkseg->layer + 1 == eptinfo[i].startl);
+ }
+ else {
+ if (walkseg->segtype & ST_WIRE)
+ startcompat = (walkseg->layer == eptinfo[i].startl) ||
+ (walkseg->layer == eptinfo[i].startl + 1);
+ else
+ startcompat = (walkseg->layer == eptinfo[i].startl) ||
+ (walkseg->layer == eptinfo[i].startl + 1) ||
+ (walkseg->layer + 1 == eptinfo[i].startl);
+ }
+
+ if (eptinfo[i].endtype & ST_WIRE) {
+ if (walkseg->segtype & ST_WIRE)
+ endcompat = (walkseg->layer == eptinfo[i].endl);
+ else
+ endcompat = (walkseg->layer == eptinfo[i].endl) ||
+ (walkseg->layer + 1 == eptinfo[i].endl);
+ }
+ else {
+ if (walkseg->segtype & ST_WIRE)
+ endcompat = (walkseg->layer == eptinfo[i].endl) ||
+ (walkseg->layer == eptinfo[i].endl + 1);
+ else
+ endcompat = (walkseg->layer == eptinfo[i].endl) ||
+ (walkseg->layer == eptinfo[i].endl + 1) ||
+ (walkseg->layer + 1 == eptinfo[i].endl);
+ }
+
+ if ((walkseg->x2 == eptinfo[i].startx) &&
+ (walkseg->y2 == eptinfo[i].starty) && startcompat) {
+ Fprintf(stdout, "Connects to %d, %d, %d\n",
+ eptinfo[i].startx, eptinfo[i].starty, eptinfo[i].startl);
+ /* Recursive walk */
+ eptinfo[i].flags = 1;
+ fprintf(delayFile, "(%g %g ", rcvals->res, rcvals->cap);
+ walk_route(i, 0, NodeTable, eptinfo,
+ numroutes, lefrcvalues, delayFile);
+ fprintf(delayFile, "), ");
+ }
+ else if ((walkseg->x2 == eptinfo[i].endx) &&
+ (walkseg->y2 == eptinfo[i].endy) && endcompat) {
+ Fprintf(stdout, "Connects to %d, %d, %d\n",
+ eptinfo[i].endx, eptinfo[i].endy, eptinfo[i].endl);
+ /* If this is a node, output it now */
+ /* Recursive walk */
+ eptinfo[i].flags = 1;
+ fprintf(delayFile, "(%g %g ", rcvals->res, rcvals->cap);
+ walk_route(i, 1, NodeTable, eptinfo,
+ numroutes, lefrcvalues, delayFile);
+ fprintf(delayFile, "), ");
+ }
+ }
+
+ /* If "nodeptr" is non-null, then walk any path that connects to */
+ /* the same node. This catches instances in which a two paths may */
+ /* connect to a node at two different locations. */
+
+ if (nodeptr != NULL) {
+ for (i = 0; i < numroutes; i++) {
+ if (eptinfo[i].flags == 1) continue; /* already visited */
+ if (eptinfo[i].startnode == nodeptr) {
+ eptinfo[i].flags = 1;
+ fprintf(delayFile, "(%g %g ", rcvals->res, rcvals->cap);
+ walk_route(i, 0, NodeTable, eptinfo,
+ numroutes, lefrcvalues, delayFile);
+ fprintf(delayFile, "), ");
+ }
+ else if (eptinfo[i].endnode == nodeptr) {
+ eptinfo[i].flags = 1;
+ fprintf(delayFile, "(%g %g ", rcvals->res, rcvals->cap);
+ walk_route(i, 1, NodeTable, eptinfo,
+ numroutes, lefrcvalues, delayFile);
+ fprintf(delayFile, "), ");
+ }
+ }
+ }
+}
+
+/*--------------------------------------------------------------*/
+/* Recursively walk a route to all endpoints, computing the */
+/* path R and C values along the way. */
+/* */
+/* rt is the current route being walked */
+/* driverend is the upstream endpoint of that route */
+/* (0 = start of segment, 1 = end of segment). */
+/* eptinfo contains the endpoints of all the routes. */
+/* numroutes is te number of entries in eptinfo. */
+/* delayFile is the output file to write to. */
+/* */
+/* Return the R and C values for the segment */
+/*--------------------------------------------------------------*/
+
+void
+walk_route(int eidx, int driverend,
+ Tcl_HashTable *NodeTable,
+ endpointinfo *eptinfo, int numroutes,
+ lefrcinfo *lefrcvalues, FILE *delayFile)
+{
+ SEG firstseg, lastseg;
+ SEG walkseg, newseg, testseg;
+ SEG seg, nseg;
+ GATE g;
+ NODE node;
+ rcinfo rcvals;
+ int i;
+ u_char f;
+ ROUTE rt;
+
+ /* Always walk the segment from upstream to downstream. */
+ /* If the upstream side is the end of the segment linked */
+ /* list, then create a reversed copy of the route to make */
+ /* it easier to work through the linked list. */
+
+ rt = eptinfo[eidx].route;
+
+ if (driverend == 1) {
+ firstseg = NULL;
+ for (seg = rt->segments; seg; seg = seg->next) {
+ newseg = (SEG)malloc(sizeof(struct seg_));
+ newseg->layer = seg->layer;
+ newseg->x1 = seg->x2;
+ newseg->x2 = seg->x1;
+ newseg->y1 = seg->y2;
+ newseg->y2 = seg->y1;
+ newseg->segtype = seg->segtype;
+ newseg->next = firstseg;
+ firstseg = newseg;
+ }
+ }
+ else
+ firstseg = rt->segments;
+
+ /* Walk the route segment and accumulate R and C */
+
+ rcvals.res = 0.0;
+ rcvals.cap = 0.0;
+
+ for (walkseg = firstseg; walkseg; walkseg = walkseg->next) {
+ int rlength;
+
+ /* Accumulate C and R */
+ if (walkseg->segtype & ST_VIA) {
+ rcvals.res += lefrcvalues[walkseg->layer].viares;
+ }
+ else if (walkseg->x1 == walkseg->x2) { /* Vertical route */
+ rlength = (walkseg->y2 > walkseg->y1) ?
+ (walkseg->y2 - walkseg->y1 + 1) :
+ (walkseg->y1 - walkseg->y2 + 1);
+
+ rcvals.res += lefrcvalues[walkseg->layer].resy * rlength;
+ rcvals.cap += lefrcvalues[walkseg->layer].capy * rlength;
+ }
+ else { /* Horizontal route */
+ rlength = (walkseg->x2 > walkseg->x1) ?
+ (walkseg->x2 - walkseg->x1 + 1) :
+ (walkseg->x1 - walkseg->x2 + 1);
+
+ rcvals.res += lefrcvalues[walkseg->layer].resx * rlength;
+ rcvals.cap += lefrcvalues[walkseg->layer].capx * rlength;
+ }
+ if (walkseg->next == NULL) lastseg = walkseg;
+ }
+
+ /* If the first segment connects to a node, generate output */
+
+ node = (driverend == 0) ? eptinfo[eidx].startnode : eptinfo[eidx].endnode;
+
+ if (node != NULL) {
+ /* Look up the gate */
+ g = FindGateNode(NodeTable, node, &i, &f);
+ /* Output delay */
+ if (f == 0)
+ fprintf(delayFile, "(%g %g %s/%s), ",
+ rcvals.res, rcvals.cap,
+ g->gatename, g->gatetype->node[i]);
+
+ Fprintf(stdout, "Connects to endpoint %s/%s\n",
+ g->gatename, g->gatetype->node[i]);
+ }
+
+ /* Check for downstream nodes from the first route point */
+ check_downstream(firstseg, node, NodeTable, eptinfo,
+ numroutes, lefrcvalues, &rcvals, delayFile);
+
+ node = (driverend == 0) ? eptinfo[eidx].endnode : eptinfo[eidx].startnode;
+
+ /* Check for downstream nodes from the last route point */
+ check_downstream(lastseg, node, NodeTable, eptinfo,
+ numroutes, lefrcvalues, &rcvals, delayFile);
+
+ /* If the last segment connects to a node, generate output */
+
+ if (node != NULL) {
+ /* Look up the gate */
+ g = FindGateNode(NodeTable, node, &i, &f);
+ /* Output delay */
+ if (f == 0)
+ fprintf(delayFile, "(%g %g %s/%s), ",
+ rcvals.res, rcvals.cap,
+ g->gatename, g->gatetype->node[i]);
+
+ Fprintf(stdout, "Connects to endpoint %s/%s\n",
+ g->gatename, g->gatetype->node[i]);
+ }
+
+ if (driverend == 1) {
+ /* Free the reversed segment */
+ for (seg = firstseg; seg; ) {
+ nseg = seg->next;
+ free(seg);
+ seg = nseg;
+ }
+ }
+}
+
+/*--------------------------------------------------------------*/
+/* Write an output file of the calculated R, C for every route */
+/* branch. Because the qrouter algorithm is agnostic about the */
+/* direction of the signaling of routes, this has to be */
+/* discovered from the information at hand. The routes for */
+/* each net are reorganized into directed segments, and the */
+/* whole directed tree walked from beginning to every endpoint. */
+/* The routing algorithm is also unaware of any details of the */
+/* nodes it routes to, so it is necessary to create a table of */
+/* all nodes, referenced by the pointer address found in the */
+/* nodeinfo array. */
+/*--------------------------------------------------------------*/
+
+int write_delays(char *filename)
+{
+ FILE *delayFile;
+ NET net;
+ ROUTE rt, nxroute;
+ ROUTE droutes, newroute, lastroute;
+ NODEINFO nodeptr;
+ NODE drivernode;
+ SEG seg, newseg, lastseg, nxseg;
+ GATE g, drivergate;
+ int i, n, new, driverend;
+ int drivernodeidx, driveridx;
+ int nroute, numroutes;
+ endpointinfo *eptinfo;
+ rcinfo rcvals;
+ lefrcinfo *lefrcvalues;
+ u_char f;
+
+ Tcl_HashTable NodeTable;
+ Tcl_HashEntry *entry;
+
+ if (!strcmp(filename, "stdout"))
+ delayFile = stdout;
+ else if (filename == NULL)
+ delayFile = fopen(delayfilename, "w");
+ else
+ delayFile = fopen(filename, "w");
+
+ if (!delayFile) {
+ Fprintf(stderr, "write_delays(): Couldn't open output delay file.\n");
+ return -1;
+ }
+
+ /* Build a hash table of nodes; key = node record address, */
+ /* record = pointer to gate and index of the node in its noderec. */
+
+ Tcl_InitHashTable(&NodeTable, TCL_ONE_WORD_KEYS);
+
+ for (g = Nlgates; g; g = g->next) {
+ for (i = 0; i < g->nodes; i++) {
+ GATENODE gn;
+ gn = (GATENODE)malloc(sizeof(struct gatenode_));
+ gn->idx = i;
+ gn->gate = g;
+ gn->visited = (u_char)0;
+ entry = Tcl_CreateHashEntry(&NodeTable, *(g->noderec + i), &new);
+ Tcl_SetHashValue(entry, gn);
+ }
+ }
+
+ /* Fill in the record of R and C values per layer, for efficiency */
+
+ lefrcvalues = (lefrcinfo *)malloc(Num_layers * sizeof(lefrcinfo));
+ for (i = 0; i < Num_layers; i++) {
+ double areacap, edgecap;
+ double respersq, respervia;
+ double width, sqx, sqy;
+
+ LefGetRouteRCvalues(i, &areacap, &edgecap, &respersq);
+ width = LefGetRouteWidth(i);
+
+ lefrcvalues[i].resx = (PitchX[i] / width) * respersq;
+ lefrcvalues[i].resy = (PitchY[i] / width) * respersq;
+
+ lefrcvalues[i].capx = (PitchX[i] * width) * areacap + (PitchX[i] * edgecap);
+ lefrcvalues[i].capy = (PitchY[i] * width) * areacap + (PitchY[i] * edgecap);
+
+ if (i < (Num_layers - 1))
+ LefGetViaResistance(i, &(lefrcvalues[i].viares));
+ else
+ lefrcvalues[i].viares = 0.0; /* Not used */
+ }
+
+ /* Each net is output independently. Loop through all nets. */
+
+ for (n = 0; n < Numnets; n++) {
+ net = Nlnets[n];
+
+ if ((net->netnum == VDD_NET) || (net->netnum == GND_NET)) continue;
+
+
+ /* Marked as one driver node. Not handling more than one driver yet. */
+ fprintf(delayFile, "%s 1", net->netname);
+
+ /* Determine the driver node, as determined by the node with */
+ /* LEF direction 'OUTPUT'. */
+ /* (For now, if a net has multiple tristate drivers, just use */
+ /* the first one and treat the rest as receivers.) */
+
+ /* Count number of net routes */
+ numroutes = 0;
+ for (rt = net->routes; rt; rt = rt->next) numroutes++;
+
+ /* Allocate space for endpoint info */
+ eptinfo = (endpointinfo *)malloc(numroutes * sizeof(endpointinfo));
+
+ /* Fill in initial endpoint information */
+ nroute = 0;
+ for (rt = net->routes; rt; rt = rt->next) {
+ eptinfo[nroute].route = rt;
+ eptinfo[nroute].flags = (u_char)0;
+ /* Segment start */
+ seg = rt->segments;
+ eptinfo[nroute].startx = seg->x1;
+ eptinfo[nroute].starty = seg->y1;
+ eptinfo[nroute].startl = seg->layer;
+ eptinfo[nroute].starttype = seg->segtype;
+ eptinfo[nroute].startnode = NULL;
+
+ /* Segment end */
+ for (seg = rt->segments; seg && seg->next; seg = seg->next);
+ eptinfo[nroute].endx = seg->x2;
+ eptinfo[nroute].endy = seg->y2;
+ eptinfo[nroute].endl = seg->layer;
+ eptinfo[nroute].endtype = seg->segtype;
+ eptinfo[nroute].endnode = NULL;
+
+ nroute++;
+ }
+
+ /* Copy net->routes into droutes, and update eptinfo */
+
+ droutes = (ROUTE)NULL;
+ lastroute = (ROUTE)NULL;
+ i = 0;
+ for (rt = net->routes; rt; rt = rt->next) {
+ newroute = (ROUTE)malloc(sizeof(struct route_));
+ newroute->next = NULL;
+ if (lastroute == NULL)
+ droutes = newroute;
+ else
+ lastroute->next = newroute;
+ lastroute = newroute;
+ newroute->flags = (u_char)0;
+ newroute->netnum = rt->netnum;
+ eptinfo[i].route = newroute;
+
+ lastseg = (SEG)NULL;
+ for (seg = rt->segments; seg; seg = seg->next) {
+ newseg = (SEG)malloc(sizeof(struct seg_));
+ if (lastseg == NULL)
+ newroute->segments = newseg;
+ else
+ lastseg->next = newseg;
+ lastseg = newseg;
+ newseg->x1 = seg->x1;
+ newseg->x2 = seg->x2;
+ newseg->y1 = seg->y1;
+ newseg->y2 = seg->y2;
+ newseg->layer = seg->layer;
+ newseg->segtype = seg->segtype;
+ newseg->next = (SEG)NULL;
+ }
+ i++;
+ }
+
+ /* Check each point of each route against the endpoints of the */
+ /* other routes, and break routes at connection points, so that */
+ /* each route is an independent segment for calculating Elmore */
+ /* delay. */
+
+ for (rt = droutes; rt; rt = rt->next) {
+ ROUTE testroute;
+ int startx, starty, startl, starttype;
+ int endx, endy, endl, endtype;
+ int brkx, brky, startcompat, endcompat;
+ int initial, final;
+ int x1, y1, x2, y2;
+
+ /* Check all segments (but not the endpoints) */
+ for (seg = rt->segments; seg; seg = seg->next) {
+ initial = (seg == rt->segments) ? 1 : 0;
+ final = (seg->next == NULL) ? 1 : 0;
+
+ if (initial && (seg->segtype & ST_VIA)) continue;
+ if (final && (seg->segtype & ST_VIA)) continue;
+
+ x1 = seg->x1;
+ x2 = seg->x2;
+ y1 = seg->y1;
+ y2 = seg->y2;
+
+ if (initial) {
+ if (y1 == y2) {
+ if (x1 > x2)
+ x1--;
+ else if (x1 < x2)
+ x1++;
+ else
+ continue; /* shouldn't happen */
+ }
+ else {
+ if (y1 > y2)
+ y1--;
+ else if (y1 < y2)
+ y1++;
+ else
+ continue; /* shouldn't happen */
+ }
+ }
+ if (final) {
+ if (y1 == y2) {
+ if (x1 > x2)
+ x2++;
+ else if (x1 < x2)
+ x2--;
+ else
+ continue; /* shouldn't happen */
+ }
+ else {
+ if (y1 > y2)
+ y2++;
+ else if (y1 < y2)
+ y2--;
+ else
+ continue; /* shouldn't happen */
+ }
+ }
+
+ /* Compare against endpoints of all other routes */
+ for (i = 0; i < numroutes; i++) {
+ if (eptinfo[i].route == rt) continue;
+
+ /* Check for start/end points connecting on same layer */
+ startx = eptinfo[i].startx;
+ starty = eptinfo[i].starty;
+ startl = eptinfo[i].startl;
+ starttype = eptinfo[i].starttype;
+ endx = eptinfo[i].endx;
+ endy = eptinfo[i].endy;
+ endl = eptinfo[i].endl;
+ endtype = eptinfo[i].endtype;
+
+ /* Check various combinations of wire and via layers */
+ if (seg->segtype & ST_WIRE) {
+ if (starttype & ST_WIRE)
+ startcompat = (startl == seg->layer);
+ else
+ startcompat = (startl == seg->layer)
+ || (startl + 1 == seg->layer);
+
+ if (endtype & ST_WIRE)
+ endcompat = (endl == seg->layer);
+ else
+ endcompat = (endl == seg->layer)
+ || (endl + 1 == seg->layer);
+ }
+ else {
+ if (starttype & ST_WIRE)
+ startcompat = (startl == seg->layer)
+ || (startl == seg->layer + 1);
+ else
+ startcompat = (startl == seg->layer)
+ || (startl == seg->layer + 1)
+ || (startl + 1 == seg->layer);
+
+ if (endtype & ST_WIRE)
+ endcompat = (endl == seg->layer)
+ || (endl == seg->layer + 1);
+ else
+ endcompat = (endl == seg->layer)
+ || (endl == seg->layer + 1)
+ || (endl + 1 == seg->layer);
+ }
+
+ if (x1 == x2) {
+ if (startcompat && (startx == x1)) {
+ if (y1 > y2) {
+ if (starty >= y2 &&
+ starty <= y1) {
+ brkx = startx;
+ brky = starty;
+ /* Disable this endpoint */
+ eptinfo[i].startl = -2;
+ break;
+ }
+ }
+ else {
+ if (starty >= y1 &&
+ starty <= y2) {
+ brkx = startx;
+ brky = starty;
+ /* Disable this endpoint */
+ eptinfo[i].startl = -2;
+ break;
+ }
+ }
+ }
+ if (endcompat && (endx == x2)) {
+ if (y1 > y2) {
+ if (endy >= y2 &&
+ endy <= y1) {
+ brkx = endx;
+ brky = endy;
+ /* Disable this endpoint */
+ eptinfo[i].endl = -2;
+ break;
+ }
+ }
+ else {
+ if (endy >= y1 &&
+ endy <= y2) {
+ brkx = endx;
+ brky = endy;
+ /* Disable this endpoint */
+ eptinfo[i].endl = -2;
+ break;
+ }
+ }
+ }
+ }
+ else if (y1 == y2) {
+ if (startcompat && (starty == y1)) {
+ if (x1 > x2) {
+ if (startx >= x2 &&
+ startx <= x1) {
+ brkx = startx;
+ brky = starty;
+ /* Disable this endpoint */
+ eptinfo[i].startl = -2;
+ break;
+ }
+ }
+ else {
+ if (startx >= x1 &&
+ startx <= x2) {
+ brkx = startx;
+ brky = starty;
+ /* Disable this endpoint */
+ eptinfo[i].startl = -2;
+ break;
+ }
+ }
+ }
+ if (endcompat && (endy == y2)) {
+ if (x1 > x2) {
+ if (endx >= x2 &&
+ endx <= x1) {
+ brkx = endx;
+ brky = endy;
+ /* Disable this endpoint */
+ eptinfo[i].endl = -2;
+ break;
+ }
+ }
+ else {
+ if (endx >= x1 &&
+ endx <= x2) {
+ brkx = endx;
+ brky = endy;
+ /* Disable this endpoint */
+ eptinfo[i].endl = -2;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (i < numroutes) {
+ /* Break route at this point */
+ /* Make a copy of the segment where the break occurs */
+ newroute = (ROUTE)malloc(sizeof(struct route_));
+ newseg = (SEG)malloc(sizeof(struct seg_));
+ newseg->segtype = seg->segtype;
+ newseg->x1 = brkx;
+ newseg->y1 = brky;
+ newseg->x2 = seg->x2;
+ newseg->y2 = seg->y2;
+ newseg->layer = seg->layer;
+
+ newseg->next = seg->next;
+ seg->next = NULL;
+ seg->x2 = brkx;
+ seg->y2 = brky;
+
+ newroute->segments = newseg;
+ newroute->netnum = rt->netnum;
+ newroute->flags = (u_char)0;
+ newroute->next = rt->next;
+ rt->next = newroute;
+
+ /* Update eptinfo[i].route to point to new split */
+ for (i = 0; i < numroutes; i++) {
+ if (eptinfo[i].route == rt) {
+ eptinfo[i].route = newroute;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Regenerate endpoint information */
+ free(eptinfo);
+ numroutes = 0;
+ for (rt = droutes; rt; rt = rt->next) numroutes++;
+ eptinfo = (endpointinfo *)malloc(numroutes * sizeof(endpointinfo));
+
+ /* Determine the driver and fill in endpoint information */
+ nroute = 0;
+ drivergate = NULL;
+ drivernodeidx = -1;
+ driveridx = -1;
+ for (rt = droutes; rt; rt = rt->next) {
+ eptinfo[nroute].route = rt;
+ eptinfo[nroute].flags = (u_char)0;
+ /* Segment start */
+ seg = rt->segments;
+ eptinfo[nroute].startx = seg->x1;
+ eptinfo[nroute].starty = seg->y1;
+ eptinfo[nroute].startl = seg->layer;
+ eptinfo[nroute].starttype = seg->segtype;
+ nodeptr = (seg->layer < Pinlayers) ?
+ NODEIPTR(seg->x1, seg->y1, seg->layer) : NULL;
+ eptinfo[nroute].startnode = nodeptr ? nodeptr->nodesav : NULL;
+
+ /* Look up node */
+ if (nodeptr) {
+ g = FindGateNode(&NodeTable, nodeptr->nodesav, &i, NULL);
+ if (g && (g->gatetype->direction[i] == PORT_CLASS_OUTPUT)) {
+ drivernodeidx = i;
+ driveridx = nroute;
+ drivergate = g;
+ driverend = 0;
+ }
+ else if (g && (g->gatetype->direction[i] != PORT_CLASS_INPUT)) {
+ if (drivernodeidx == -1) {
+ drivernodeidx = i;
+ driveridx = nroute;
+ drivergate = g;
+ driverend = 0;
+ }
+ }
+ else if (g == NULL) {
+ /* should not happen? */
+ if (nodeptr->nodesav->netname == NULL)
+ Fprintf(stderr, "Cannot find recorded node of netnum %d\n",
+ nodeptr->nodesav->netnum);
+ else
+ Fprintf(stderr, "Cannot find recorded node of net %s\n",
+ nodeptr->nodesav->netname);
+ }
+ }
+
+ /* Segment end */
+ lastseg = NULL;
+ for (seg = rt->segments; seg && seg->next; seg = seg->next)
+ lastseg = seg;
+ eptinfo[nroute].endx = seg->x2;
+ eptinfo[nroute].endy = seg->y2;
+ eptinfo[nroute].endl = seg->layer;
+ eptinfo[nroute].endtype = seg->segtype;
+ nodeptr = (seg->layer < Pinlayers) ?
+ NODEIPTR(seg->x2, seg->y2, seg->layer) : NULL;
+ eptinfo[nroute].endnode = nodeptr ? nodeptr->nodesav : NULL;
+
+ /* Look up node */
+ if (nodeptr) {
+ g = FindGateNode(&NodeTable, nodeptr->nodesav, &i, NULL);
+ if (g && (g->gatetype->direction[i] == PORT_CLASS_OUTPUT)) {
+ drivernodeidx = i;
+ driveridx = nroute;
+ drivergate = g;
+ driverend = 1;
+ break;
+ }
+ else if (g && (g->gatetype->direction[i] != PORT_CLASS_INPUT)) {
+ if (drivernodeidx == -1) {
+ drivernodeidx = i;
+ driveridx = nroute;
+ drivergate = g;
+ driverend = 1;
+ }
+ }
+ else if (g == NULL) {
+ /* should not happen? */
+ if (nodeptr->nodesav->netname == NULL)
+ Fprintf(stderr, "Cannot find recorded node of netnum %d\n",
+ nodeptr->nodesav->netnum);
+ else
+ Fprintf(stderr, "Cannot find recorded node of net %s\n",
+ nodeptr->nodesav->netname);
+ }
+ }
+ nroute++;
+ }
+
+ /* Write output terminal and cap value */
+
+ if ((drivernodeidx != -1) && (driveridx != -1)) {
+ Fprintf(stdout, "Walking net %s.\n", net->netname);
+ Fprintf(stdout, "Has %d nodes.\n", net->numnodes);
+ Fprintf(stdout, "After segmenting, has %d routes.\n", numroutes);
+ Fprintf(stdout, "Driver node %s/%s\n",
+ drivergate->gatename,
+ drivergate->gatetype->node[drivernodeidx]);
+ fprintf(delayFile, " %s/%s %d (",
+ drivergate->gatename,
+ drivergate->gatetype->node[drivernodeidx],
+ net->numnodes - 1);
+
+ /* Mark driver node as visited */
+ drivernode = (driverend == 0) ? eptinfo[drivernodeidx].startnode :
+ eptinfo[drivernodeidx].endnode;
+ FindGateNode(&NodeTable, drivernode, &i, &f);
+
+ walk_route(driveridx, driverend, &NodeTable,
+ eptinfo, numroutes, lefrcvalues, delayFile);
+
+ fprintf(delayFile, ")\n");
+
+ /* Diagnostic: There should be no unhandled segments if */
+ /* everything went right. */
+
+ for (i = 0; i < numroutes; i++) {
+ if (eptinfo[i].flags == (u_char)0) {
+ Fprintf(stderr, "Route segment %d was not walked!\n", i);
+ }
+ }
+ }
+ else {
+ if (net->netname == NULL)
+ Fprintf(stderr, "No driver for netnum %d\n", net->netnum);
+ else
+ Fprintf(stderr, "No driver for net %s\n", net->netname);
+ }
+
+ /* Free up allocated information */
+
+ for (rt = droutes; rt; ) {
+ for (seg = rt->segments; seg; ) {
+ nxseg = seg->next;
+ free(seg);
+ seg = nxseg;
+ }
+ nxroute = rt->next;
+ free(rt);
+ rt = nxroute;
+ }
+ free(eptinfo);
+ }
+ fclose(delayFile);
+
+ free(lefrcvalues);
+
+ Tcl_DeleteHashTable(&NodeTable);
+
+ return 0;
+}
+
+#endif /* TCL_QROUTER */
+
/*--------------------------------------------------------------*/
/* helpmessage - tell user how to use the program */
/* */
@@ -4373,6 +5299,7 @@ static void helpmessage(void)
Fprintf(stdout, "usage: qrouter [-switches] design_name\n\n");
Fprintf(stdout, "switches:\n");
Fprintf(stdout, "\t-c <file>\t\t\tConfiguration file name if not route.cfg.\n");
+ Fprintf(stdout, "\t-d <file>\t\t\tGenerate delay information output.\n");
Fprintf(stdout, "\t-v <level>\t\t\tVerbose output level.\n");
Fprintf(stdout, "\t-i <file>\t\t\tPrint route names and pitches and exit.\n");
Fprintf(stdout, "\t-p <name>\t\t\tSpecify global power bus name.\n");