diff options
author | Ruben Undheim <ruben.undheim@gmail.com> | 2017-03-17 13:42:43 +0100 |
---|---|---|
committer | Ruben Undheim <ruben.undheim@gmail.com> | 2017-03-17 13:42:43 +0100 |
commit | 35fff0dc1518cec0b8ab7062ef14b36095849ac1 (patch) | |
tree | 909a59201eb4ee09c4ec92e6071948b3b85494d6 /qrouter.c | |
parent | 196d5accdbc60e0202cfe1c5fcf97d0ac8041293 (diff) |
Imported Upstream version 1.3.67
Diffstat (limited to 'qrouter.c')
-rw-r--r-- | qrouter.c | 1151 |
1 files changed, 1039 insertions, 112 deletions
@@ -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"); |