/*--------------------------------------------------------------*/ /* qconfig.c -- .cfg file read/write for route */ /*--------------------------------------------------------------*/ /* Written by Steve Beccue 2003 */ /*--------------------------------------------------------------*/ /* Modified by Tim Edwards, June 2011. The route.cfg file is */ /* no longer the main configuration file but is supplementary */ /* to the LEF and DEF files. Various configuration items that */ /* do not appear in the LEF and DEF formats, such as route */ /* costing, appear in this file, as well as a filename pointer */ /* to the LEF file with information on standard cell macros. */ /*--------------------------------------------------------------*/ #define _GNU_SOURCE // for strcasestr(), see man page #include #include #include #include #include #include "qrouter.h" #include "qconfig.h" #include "lef.h" int CurrentPin = 0; int Firstcall = TRUE; int PinNumber = 0; int Num_layers = MAX_LAYERS; // layers to use to route double PathWidth[MAX_LAYERS]; // width of the paths int GDSLayer[MAX_TYPES]; // GDS layer number int GDSCommentLayer = 1; // for dummy wires, etc. char CIFLayer[MAX_TYPES][50]; // CIF layer name double PitchX; // Horizontal wire pitch of layer double PitchY; // Vertical wire pitch of layer int NumChannelsX; // number of wire channels in X on layer int NumChannelsY; // number of wire channels in Y on layer int Vert[MAX_LAYERS]; // 1 if vertical, 0 if horizontal int Numpasses = 10; // number of times to iterate in route_segs char StackedContacts = MAX_LAYERS; // Value is number of contacts that may // be stacked on top of each other. double Xlowerbound=0.0; // Bounding Box of routes, in microns double Xupperbound=0.0; double Ylowerbound=10.0; double Yupperbound=10.0; int SegCost = 1; // Route cost of a segment int ViaCost = 5; // Cost of via between adjacent layers int JogCost = 10; // Cost of 1 grid off-direction jog int XverCost = 4; // Cost of a crossover int BlockCost = 25; // Cost of a crossover when node has // only one tap point int OffsetCost = 50; // Cost per micron of a node offset int ConflictCost = 50; // Cost of shorting another route // during the rip-up and reroute stage char *ViaXX[MAX_LAYERS]; char *ViaXY[MAX_LAYERS]; char *ViaYX[MAX_LAYERS]; char *ViaYY[MAX_LAYERS]; /*--------------------------------------------------------------*/ /* init_config --- */ /* */ /* Initialize arrays */ /*--------------------------------------------------------------*/ void init_config() { int i; for (i = 0; i < MAX_LAYERS; i++) { ViaXX[i] = NULL; ViaXY[i] = NULL; ViaYX[i] = NULL; ViaYY[i] = NULL; } } /*--------------------------------------------------------------*/ /* post_config --- */ /* */ /* Resolve PitchX and PitchY, which are the minimum pitches */ /* that determine the underlying route grid. */ /* */ /* If "noprint" is TRUE, then do not print diagnostic info. */ /*--------------------------------------------------------------*/ void post_config(u_char noprint) { int i, h, v; double rpitchx, rpitchy; // Make sure that Num_layers does not exceed the number of // routing layers defined by the LEF file (or the config // file). i = LefGetMaxRouteLayer(); if (i < Num_layers) Num_layers = i; // Make sure all layers have a pitch in both X and Y even if not // specified separately in the configuration or def files. for (i = 0; i < Num_layers; i++) { rpitchx = LefGetRoutePitchX(i); rpitchy = LefGetRoutePitchY(i); if ((PitchX == 0.0) || ((rpitchx != 0.0) && (rpitchx + EPS < PitchX))) PitchX = rpitchx; if ((PitchY == 0.0) || ((rpitchy != 0.0) && (rpitchy + EPS < PitchY))) PitchY = rpitchy; } // This is mostly arbitrary. Generally, all route layer // pitches except for the smallest X and Y pitches will // be ignored, and the actual route pitches will be multiples // of the smallest value, and determined by width and spacing // rules rather than using any value in the technology LEF. for (i = 0; i < Num_layers; i++) { if (LefGetRoutePitchX(i) == 0.0) { if (Vert[i]) LefSetRoutePitchX(i, PitchX); else if (i > 0) LefSetRoutePitchX(i, LefGetRoutePitchX(i - 1)); else LefSetRoutePitchX(i, LefGetRoutePitchX(i + 1)); } if (LefGetRoutePitchY(i) == 0.0) { if (!Vert[i]) LefSetRoutePitchY(i, PitchY); else if (i > 0) LefSetRoutePitchY(i, LefGetRoutePitchY(i - 1)); else LefSetRoutePitchY(i, LefGetRoutePitchY(i + 1)); } } if (noprint == FALSE) { for (i = 0; i < Num_layers; i++) { rpitchx = LefGetRoutePitchX(i); rpitchy = LefGetRoutePitchY(i); if ((PitchX != 0.0) && (PitchX + EPS < rpitchx)) { Fprintf(stdout, "Vertical route layer at non-minimum pitch" " %g. Using smaller pitch %g, will route on" " 1-of-%d tracks for layer %s.\n", rpitchx, PitchX, (int)(ceil(rpitchx / PitchX)), LefGetRouteName(i)); } if ((PitchY != 0.0) && (PitchY + EPS < rpitchy)) { Fprintf(stdout, "Horizontal route layer at non-minimum pitch" " %g. Using smaller pitch %g, will route on" " 1-of-%d tracks for layer %s.\n", rpitchy, PitchY, (int)(ceil(rpitchy / PitchY)), LefGetRouteName(i)); } } } } /* post_config() */ /*--------------------------------------------------------------*/ /* Append to a string */ /*--------------------------------------------------------------*/ void string_list_append(STRING *lst, const char *s) { STRING n, strl; n = (STRING)malloc(sizeof(struct string_)); n->name = strdup(s); n->next = NULL; while (*lst) lst = &(*lst)->next; *lst = n; } /*--------------------------------------------------------------*/ /* read_config - read in the config file */ /* */ /* ARGS: the filename (normally route.cfg) */ /* RETURNS: number of lines successfully read */ /* SIDE EFFECTS: loads Global configuration variables */ /* */ /* "is_info" indicates if qrouter was called with the -i option */ /* in which case the config file read should stop before any */ /* def file is read. */ /*--------------------------------------------------------------*/ int read_config(FILE *fconfig, int is_info) { int count, lines, i, OK; int iarg, iarg2; char carg; double darg, darg2, darg3, darg4; char sarg[MAX_LINE_LEN]; char line[MAX_LINE_LEN]; char *lineptr; STRING dnr; // Do Not Route nets STRING cn; // critical nets STRING strl; GATE gateinfo = NULL; // gate information, pin location, etc DSEG drect; if (Firstcall) { for (i = 0; i < MAX_LAYERS; i++) { sprintf(line, "via%d%d", i + 1, i + 2); ViaXX[i] = strdup(line); ViaXY[i] = NULL; ViaYX[i] = NULL; ViaYY[i] = NULL; } DontRoute = (STRING)NULL; CriticalNet = (STRING)NULL; GateInfo = (GATE)NULL; Nlgates = (GATE)NULL; UserObs = (DSEG)NULL; PitchX = PitchY = 0.0; Firstcall = 0; } if (!fconfig) return -1; count = 0; lines = 0; while (!feof(fconfig)) { if (fgets(line, MAX_LINE_LEN, fconfig) == NULL) break; lines++; lineptr = line; while (isspace(*lineptr)) lineptr++; if (!strncasecmp(lineptr, "lef", 3) || !strncmp(lineptr, "read_lef", 8)) { int mscale; if ((i = sscanf(lineptr, "%*s %s\n", sarg)) == 1) { // Argument is a filename of a LEF file from which we // should get the information about gate pins & obstructions OK = 1; mscale = LefRead(sarg); update_mscale(mscale); } } // The remainder of the statements is not case sensitive. for (i = 0; line[i] && i < MAX_LINE_LEN - 1; i++) { line[i] = (char)tolower(line[i]); } if ((i = sscanf(lineptr, "num_layers %d", &iarg)) == 1) { OK = 1; Num_layers = iarg; } else if ((i = sscanf(lineptr, "layers %d", &iarg)) == 1) { OK = 1; Num_layers = iarg; } if ((i = sscanf(lineptr, "layer_%d_name %s", &iarg2, sarg)) == 2) { if (iarg2 > 0 && iarg2 <= MAX_LAYERS) { OK = 1; strcpy(CIFLayer[iarg2 - 1], sarg); } } if ((i = sscanf(lineptr, "gds_layer_%d %d", &iarg2, &iarg)) == 2) { if (iarg2 > 0 && iarg2 <= MAX_TYPES) { OK = 1; GDSLayer[iarg2 - 1] = iarg; } } if ((i = sscanf(lineptr, "gds_comment_layer %d", &iarg)) == 1) { OK = 1; GDSCommentLayer = iarg; } if ((i = sscanf(lineptr, "layer_1_width %lf", &darg)) == 1) { OK = 1; PathWidth[0] = darg; } if ((i = sscanf(lineptr, "layer_2_width %lf", &darg)) == 1) { OK = 1; PathWidth[1] = darg; } if ((i = sscanf(lineptr, "layer_3_width %lf", &darg)) == 1) { OK = 1; PathWidth[2] = darg; } if ((i = sscanf(lineptr, "layer_4_width %lf", &darg)) == 1) { OK = 1; PathWidth[3] = darg; } if ((i = sscanf(lineptr, "layer_5_width %lf", &darg)) == 1) { OK = 1; PathWidth[4] = darg; } if ((i = sscanf(lineptr, "layer_6_width %lf", &darg)) == 1) { OK = 1; PathWidth[5] = darg; } if ((i = sscanf(lineptr, "layer_7_width %lf", &darg)) == 1) { OK = 1; PathWidth[6] = darg; } if ((i = sscanf(lineptr, "layer_8_width %lf", &darg)) == 1) { OK = 1; PathWidth[7] = darg; } if ((i = sscanf(lineptr, "layer_9_width %lf", &darg)) == 1) { OK = 1; PathWidth[8] = darg; } if ((i = sscanf(lineptr, "x lower bound %lf", &darg)) == 1) { OK = 1; Xlowerbound = darg; } if ((i = sscanf(lineptr, "x upper bound %lf", &darg)) == 1) { OK = 1; Xupperbound = darg; } if ((i = sscanf(lineptr, "y lower bound %lf", &darg)) == 1) { OK = 1; Ylowerbound = darg; } if ((i = sscanf(lineptr, "y upper bound %lf", &darg)) == 1) { OK = 1; Yupperbound = darg; } if ((i = sscanf(lineptr, "layer %d wire pitch %lf\n", &iarg, &darg)) == 2) { OK = 1; if (Vert[iarg - 1]) { if ((PitchX == 0) || (darg < PitchX)) PitchX = darg; } else { if ((PitchY == 0) || (darg < PitchY)) PitchY = darg; } } else if (i == 1) { if ((i = sscanf(lineptr, "layer %*d vertical %d\n", &iarg2)) == 1) { OK = 1; Vert[iarg - 1] = iarg2; } else if ((i = sscanf(lineptr, "layer %*d %c\n", &carg)) == 1) { if (tolower(carg) == 'v') { OK = 1; Vert[iarg - 1] = 1; } else if (tolower(carg) == 'h') { OK = 1; Vert[iarg - 1] = 0; } } } if ((i = sscanf(lineptr, "num passes %d\n", &iarg)) == 1) { OK = 1; Numpasses = iarg; } else if ((i = sscanf(lineptr, "passes %d\n", &iarg)) == 1) { OK = 1; Numpasses = iarg; } if ((i = sscanf(lineptr, "route segment cost %d", &iarg)) == 1) { OK = 1; SegCost = iarg; } if ((i = sscanf(lineptr, "route via cost %d", &iarg)) == 1) { OK = 1; ViaCost = iarg; } if ((i = sscanf(lineptr, "route jog cost %d", &iarg)) == 1) { OK = 1; JogCost = iarg; } if ((i = sscanf(lineptr, "route crossover cost %d", &iarg)) == 1) { OK = 1; XverCost = iarg; } if ((i = sscanf(lineptr, "route offset cost %d", &iarg)) == 1) { OK = 1; OffsetCost = iarg; } if ((i = sscanf(lineptr, "route block cost %d", &iarg)) == 1) { OK = 1; BlockCost = iarg; } if ((i = sscanf(lineptr, "do not route node %s\n", sarg)) == 1) { OK = 1; string_list_append(&DontRoute, sarg); } if ((i = sscanf(lineptr, "route priority %s\n", sarg)) == 1) { OK = 1; string_list_append(&CriticalNet, sarg); } if ((i = sscanf(lineptr, "critical net %s\n", sarg)) == 1) { OK = 1; string_list_append(&CriticalNet, sarg); } // Search for "no stack". This allows variants like "no stacked // contacts", "no stacked vias", or just "no stacking", "no stacks", // etc. if (strcasestr(lineptr, "no stack") != NULL) { OK = 1; StackedContacts = 1; } // Search for "stack N", where "N" is the largest number of vias // that can be stacked upon each other. Values 0 and 1 are both // equivalent to specifying "no stack". if ((i = sscanf(lineptr, "stack %d", &iarg)) == 1) { OK = 1; StackedContacts = iarg; // Can't let StackedContacts be zero because qrouter would // believe that all contacts are disallowed, leading to a // lot of wasted processing time while it determines that's // not possible. . . if (StackedContacts == 0) StackedContacts = 1; } else if ((i = sscanf(lineptr, "via stack %d", &iarg)) == 1) { OK = 1; StackedContacts = iarg; if (StackedContacts == 0) StackedContacts = 1; } if ((i = sscanf(lineptr, "obstruction %lf %lf %lf %lf %s\n", &darg, &darg2, &darg3, &darg4, sarg)) == 5) { OK = 1; drect = (DSEG)malloc(sizeof(struct dseg_)); drect->x1 = darg; drect->y1 = darg2; drect->x2 = darg3; drect->y2 = darg4; drect->layer = LefFindLayerNum(sarg); if (drect->layer < 0) { if ((i = sscanf(sarg, "%lf", &darg)) == 1) { i = (int)(darg + EPS); if (i >= 0 && i < Num_layers) { drect->layer = i; } } } if (drect->layer >= 0) { drect->next = UserObs; UserObs = drect; } else { free(drect); } } if ((i = sscanf(lineptr, "gate %s %lf %lf\n", sarg, &darg, &darg2)) == 3) { OK = 1; CurrentPin = 0; gateinfo = (GATE)malloc(sizeof(struct gate_)); gateinfo->gatename = strdup(sarg); gateinfo->gatetype = NULL; gateinfo->width = darg; gateinfo->height = darg2; gateinfo->placedX = 0.0; // implicit cell origin gateinfo->placedY = 0.0; gateinfo->nodes = 0; gateinfo->next = GateInfo; // prepend to linked gate list // Allocate memory for up to 10 pins gateinfo->taps = (DSEG *)malloc(10 * sizeof(DSEG)); gateinfo->noderec = (NODE *)malloc(10 * sizeof(NODE)); gateinfo->netnum = (int *)malloc(10 * sizeof(int)); gateinfo->node = (char **)malloc(10 * sizeof(char *)); // Initialize first entry gateinfo->taps[0] = NULL; gateinfo->noderec[0] = NULL; gateinfo->netnum[0] = -1; gateinfo->node[0] = NULL; GateInfo = gateinfo; } if ((i = sscanf(lineptr, "endgate %s\n", sarg)) == 1) { OK = 1; gateinfo->nodes = CurrentPin; // This syntax does not include declaration of obstructions gateinfo->obs = (DSEG)NULL; CurrentPin = 0; } if ((i = sscanf(lineptr, "pin %s %lf %lf\n", sarg, &darg, &darg2)) == 3) { OK = 1; gateinfo->node[CurrentPin] = strdup(sarg); // These style gates have only one tap per gate; LEF file reader // allows multiple taps per gate node. drect = (DSEG)malloc(sizeof(struct dseg_)); gateinfo->taps[CurrentPin] = drect; drect->x1 = drect->x2 = darg; drect->y1 = drect->y2 = darg2; // This syntax always defines pins on layer 0; LEF file reader // allows pins on all layers. drect->layer = 0; drect->next = (DSEG)NULL; CurrentPin++; if (CurrentPin % 10 == 0) { // Allocate memory for 10 more pins gateinfo->taps = (DSEG *)realloc(gateinfo->taps, (CurrentPin + 10) * sizeof(DSEG)); gateinfo->noderec = (NODE *)realloc(gateinfo->noderec, (CurrentPin + 10) * sizeof(NODE)); gateinfo->netnum = (int *)realloc(gateinfo->netnum, (CurrentPin + 10) * sizeof(int)); gateinfo->node = (char **)realloc(gateinfo->node, (CurrentPin + 10) * sizeof(char *)); } } if (OK == 0) { if (!(lineptr[0] == '\n' || lineptr[0] == '#' || lineptr[0] == 0)) { if (!is_info) // Don't report errors on info file generation Fprintf(stderr, "line not understood: %s\n", line); } } OK = 0; line[0] = line[1] = '\0'; } post_config(FALSE); return count; } /* read_config() */