qrouter-1.4.88/0000755000175000017510000000000014677160545012663 5ustar nileshnileshqrouter-1.4.88/tclqrouter.c0000644000175000017510000026524613625043307015236 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* tclqrouter.c: */ /* Tcl routines for qrouter command-line functions */ /* Copyright (c) 2013 Tim Edwards, Open Circuit Design, Inc. */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include #include #include /* for round() */ #include #include #include #include "qrouter.h" #include "mask.h" #include "maze.h" #include "qconfig.h" #include "lef.h" #include "def.h" #include "graphics.h" #include "node.h" #include "output.h" #include "tkSimple.h" /* Global variables */ Tcl_HashTable QrouterTagTable; Tcl_Interp *qrouterinterp; Tcl_Interp *consoleinterp; int stepnet = -1; int batchmode = 0; /* Command structure */ typedef struct { const char *cmdstr; int (*func)(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); } cmdstruct; /* Forward declarations of commands */ static int qrouter_map( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_start( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_stage1( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_stage2( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_stage3( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_cleanup( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_writedef( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_writefailed( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_writedelays( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_antenna( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_readdef( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_readlef( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_readconfig( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_failing( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_cost( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_tag( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_remove( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_obs( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_layerinfo( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_priority( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_ignore( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_via( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_resolution( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_congested( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_layers( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_drc( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_query( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_passes( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_vdd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_gnd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_verbose( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_print( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_quit( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_pitchx( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_pitchy( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int qrouter_unblock( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static cmdstruct qrouter_commands[] = { {"tag", qrouter_tag}, {"start", qrouter_start}, {"stage1", qrouter_stage1}, {"stage2", qrouter_stage2}, {"stage3", qrouter_stage3}, {"cleanup", qrouter_cleanup}, {"write_def", qrouter_writedef}, {"read_def", qrouter_readdef}, {"read_lef", qrouter_readlef}, {"read_config", qrouter_readconfig}, {"write_delays", qrouter_writedelays}, {"antenna", qrouter_antenna}, {"write_failed", qrouter_writefailed}, {"layer_info", qrouter_layerinfo}, {"obstruction", qrouter_obs}, {"ignore", qrouter_ignore}, {"priority", qrouter_priority}, {"pitchx", qrouter_pitchx}, {"pitchy", qrouter_pitchy}, {"unblock", qrouter_unblock}, {"via", qrouter_via}, {"resolution", qrouter_resolution}, {"congested", qrouter_congested}, {"layers", qrouter_layers}, {"drc", qrouter_drc}, {"passes", qrouter_passes}, {"query", qrouter_query}, {"vdd", qrouter_vdd}, {"gnd", qrouter_gnd}, {"failing", qrouter_failing}, {"remove", qrouter_remove}, {"cost", qrouter_cost}, {"map", qrouter_map}, {"verbose", qrouter_verbose}, {"redraw", redraw}, {"print", qrouter_print}, {"quit", qrouter_quit}, {"", NULL} /* sentinel */ }; /*-----------------------*/ /* Tcl 8.4 compatibility */ /*-----------------------*/ #ifndef CONST84 #define CONST84 #endif /*----------------------------------------------------------------------*/ /* Deal with systems which don't define va_copy(). */ /*----------------------------------------------------------------------*/ #ifndef HAVE_VA_COPY #ifdef HAVE___VA_COPY #define va_copy(a, b) __va_copy(a, b) #else #define va_copy(a, b) a = b #endif #endif #ifdef ASG extern int SetDebugLevel(int *level); #endif /*----------------------------------------------------------------------*/ /* Reimplement strdup() to use Tcl_Alloc(). */ /*----------------------------------------------------------------------*/ char *Tcl_Strdup(const char *s) { char *snew; int slen; slen = 1 + strlen(s); snew = Tcl_Alloc(slen); if (snew != NULL) memcpy(snew, s, slen); return snew; } /*----------------------------------------------------------------------*/ /* Reimplement vfprintf() as a call to Tcl_Eval(). */ /* */ /* Since the string goes through the interpreter, we need to escape */ /* various characters like brackets, braces, dollar signs, etc., that */ /* will otherwise be modified by the interpreter. */ /*----------------------------------------------------------------------*/ void tcl_vprintf(FILE *f, const char *fmt, va_list args_in) { va_list args; static char outstr[128] = "puts -nonewline std"; char *outptr, *bigstr = NULL, *finalstr = NULL; int i, nchars, escapes = 0; /* If we are printing an error message, we want to bring attention */ /* to it by mapping the console window and raising it, as necessary. */ /* I'd rather do this internally than by Tcl_Eval(), but I can't */ /* find the right window ID to map! */ if ((f == stderr) && (consoleinterp != qrouterinterp)) { Tk_Window tkwind; tkwind = Tk_MainWindow(consoleinterp); if ((tkwind != NULL) && (!Tk_IsMapped(tkwind))) Tcl_Eval(consoleinterp, "wm deiconify .\n"); Tcl_Eval(consoleinterp, "raise .\n"); } strcpy (outstr + 19, (f == stderr) ? "err \"" : "out \""); outptr = outstr; /* This mess circumvents problems with systems which do not have */ /* va_copy() defined. Some define __va_copy(); otherwise we must */ /* assume that args = args_in is valid. */ va_copy(args, args_in); nchars = vsnprintf(outptr + 24, 102, fmt, args); va_end(args); if (nchars >= 102) { va_copy(args, args_in); bigstr = Tcl_Alloc(nchars + 26); strncpy(bigstr, outptr, 24); outptr = bigstr; vsnprintf(outptr + 24, nchars + 2, fmt, args); va_end(args); } else if (nchars == -1) nchars = 126; for (i = 24; *(outptr + i) != '\0'; i++) { if (*(outptr + i) == '\"' || *(outptr + i) == '[' || *(outptr + i) == ']' || *(outptr + i) == '\\' || *(outptr + i) == '$') escapes++; } if (escapes > 0) { finalstr = Tcl_Alloc(nchars + escapes + 26); strncpy(finalstr, outptr, 24); escapes = 0; for (i = 24; *(outptr + i) != '\0'; i++) { if (*(outptr + i) == '\"' || *(outptr + i) == '[' || *(outptr + i) == ']' || *(outptr + i) == '\\' || *(outptr + i) == '$') { *(finalstr + i + escapes) = '\\'; escapes++; } *(finalstr + i + escapes) = *(outptr + i); } outptr = finalstr; } *(outptr + 24 + nchars + escapes) = '\"'; *(outptr + 25 + nchars + escapes) = '\0'; Tcl_Eval(consoleinterp, outptr); if (bigstr != NULL) Tcl_Free(bigstr); if (finalstr != NULL) Tcl_Free(finalstr); } /*------------------------------------------------------*/ /* Console output flushing which goes along with the */ /* routine tcl_vprintf() above. */ /*------------------------------------------------------*/ void tcl_stdflush(FILE *f) { Tcl_SavedResult state; static char stdstr[] = "::flush stdxxx"; char *stdptr = stdstr + 11; Tcl_SaveResult(qrouterinterp, &state); strncpy(stdptr, (f == stderr) ? "err" : "out", 3); Tcl_Eval(qrouterinterp, stdstr); Tcl_RestoreResult(qrouterinterp, &state); } /*----------------------------------------------------------------------*/ /* Reimplement fprintf() as a call to Tcl_Eval(). */ /*----------------------------------------------------------------------*/ void tcl_printf(FILE *f, const char *format, ...) { va_list ap; va_start(ap, format); tcl_vprintf(f, format, ap); va_end(ap); } /*----------------------------------------------------------------------*/ /* Implement tag callbacks on functions */ /* Find any tags associated with a command and execute them. */ /*----------------------------------------------------------------------*/ int QrouterTagCallback(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int objidx, result = TCL_OK; char *postcmd, *substcmd, *newcmd, *sptr, *sres; char *croot = Tcl_GetString(objv[0]); Tcl_HashEntry *entry; Tcl_SavedResult state; int reset = FALSE; int i, llen; entry = Tcl_FindHashEntry(&QrouterTagTable, croot); postcmd = (entry) ? (char *)Tcl_GetHashValue(entry) : NULL; if (postcmd) { substcmd = (char *)Tcl_Alloc(strlen(postcmd) + 1); strcpy(substcmd, postcmd); sptr = substcmd; /*--------------------------------------------------------------*/ /* Parse "postcmd" for Tk-substitution escapes */ /* Allowed escapes are: */ /* %W substitute the tk path of the calling window */ /* %r substitute the previous Tcl result string */ /* %R substitute the previous Tcl result string and */ /* reset the Tcl result. */ /* %[0-5] substitute the argument to the original command */ /* %N substitute all arguments as a list */ /* %% substitute a single percent character */ /* %* (all others) no action: print as-is. */ /*--------------------------------------------------------------*/ while ((sptr = strchr(sptr, '%')) != NULL) { switch (*(sptr + 1)) { case 'W': { char *tkpath = NULL; Tk_Window tkwind = Tk_MainWindow(interp); if (tkwind != NULL) tkpath = Tk_PathName(tkwind); if (tkpath == NULL) newcmd = (char *)Tcl_Alloc(strlen(substcmd)); else newcmd = (char *)Tcl_Alloc(strlen(substcmd) + strlen(tkpath)); strcpy(newcmd, substcmd); if (tkpath == NULL) strcpy(newcmd + (int)(sptr - substcmd), sptr + 2); else { strcpy(newcmd + (int)(sptr - substcmd), tkpath); strcat(newcmd, sptr + 2); } Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; } break; case 'R': reset = TRUE; case 'r': sres = (char *)Tcl_GetStringResult(interp); newcmd = (char *)Tcl_Alloc(strlen(substcmd) + strlen(sres) + 1); strcpy(newcmd, substcmd); sprintf(newcmd + (int)(sptr - substcmd), "\"%s\"", sres); strcat(newcmd, sptr + 2); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; break; case '0': case '1': case '2': case '3': case '4': case '5': objidx = (int)(*(sptr + 1) - '0'); if ((objidx >= 0) && (objidx < objc)) { newcmd = (char *)Tcl_Alloc(strlen(substcmd) + strlen(Tcl_GetString(objv[objidx]))); strcpy(newcmd, substcmd); strcpy(newcmd + (int)(sptr - substcmd), Tcl_GetString(objv[objidx])); strcat(newcmd, sptr + 2); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; } else if (objidx >= objc) { newcmd = (char *)Tcl_Alloc(strlen(substcmd) + 1); strcpy(newcmd, substcmd); strcpy(newcmd + (int)(sptr - substcmd), sptr + 2); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; } else sptr++; break; case 'N': llen = 1; for (i = 1; i < objc; i++) llen += (1 + strlen(Tcl_GetString(objv[i]))); newcmd = (char *)Tcl_Alloc(strlen(substcmd) + llen); strcpy(newcmd, substcmd); strcpy(newcmd + (int)(sptr - substcmd), "{"); for (i = 1; i < objc; i++) { strcat(newcmd, Tcl_GetString(objv[i])); if (i < (objc - 1)) strcat(newcmd, " "); } strcat(newcmd, "}"); strcat(newcmd, sptr + 2); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; break; case '%': newcmd = (char *)Tcl_Alloc(strlen(substcmd) + 1); strcpy(newcmd, substcmd); strcpy(newcmd + (int)(sptr - substcmd), sptr + 1); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; break; default: break; } } /* Fprintf(stderr, "Substituted tag callback is \"%s\"\n", substcmd); */ /* Flush(stderr); */ Tcl_SaveResult(interp, &state); result = Tcl_Eval(interp, substcmd); if ((result == TCL_OK) && (reset == FALSE)) Tcl_RestoreResult(interp, &state); else Tcl_DiscardResult(&state); Tcl_Free(substcmd); } return result; } /*--------------------------------------------------------------*/ /* Add a command tag callback */ /*--------------------------------------------------------------*/ static int qrouter_tag(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_HashEntry *entry; char *hstring; int new; if (objc != 2 && objc != 3) return TCL_ERROR; entry = Tcl_CreateHashEntry(&QrouterTagTable, Tcl_GetString(objv[1]), &new); if (entry == NULL) return TCL_ERROR; hstring = (char *)Tcl_GetHashValue(entry); if (objc == 2) { Tcl_SetResult(interp, hstring, NULL); return TCL_OK; } if (strlen(Tcl_GetString(objv[2])) == 0) { Tcl_DeleteHashEntry(entry); } else { hstring = Tcl_Strdup(Tcl_GetString(objv[2])); Tcl_SetHashValue(entry, hstring); } return TCL_OK; } /*--------------------------------------------------------------*/ /* Initialization procedure for Tcl/Tk */ /*--------------------------------------------------------------*/ int Qrouter_Init(Tcl_Interp *interp) { int cmdidx; char command[256]; char version_string[20]; Tk_Window tktop; char *nullgvar; /* Interpreter sanity checks */ if (interp == NULL) return TCL_ERROR; /* Remember the interpreter */ qrouterinterp = interp; if (Tcl_InitStubs(interp, "8.5", 0) == NULL) return TCL_ERROR; strcpy(command, "qrouter::"); /* NOTE: Qrouter makes calls to Tk routines that may or may not */ /* exist, depending on whether qrouter was called with or without */ /* graphics. We depend on the Tcl/Tk stubs methods to allow */ /* qrouter to run without linking to Tk libraries. */ nullgvar = (char *)Tcl_GetVar(interp, "no_graphics_mode", TCL_GLOBAL_ONLY); if ((nullgvar == NULL) || !strcasecmp(nullgvar, "false")) { if (Tk_InitStubs(interp, "8.5", 0) == NULL) return TCL_ERROR; tktop = Tk_MainWindow(interp); batchmode = 0; } else { tktop = NULL; batchmode = 1; } /* Create all of the commands (except "simple") */ for (cmdidx = 0; qrouter_commands[cmdidx].func != NULL; cmdidx++) { sprintf(command + 9, "%s", qrouter_commands[cmdidx].cmdstr); Tcl_CreateObjCommand(interp, command, (Tcl_ObjCmdProc *)qrouter_commands[cmdidx].func, (ClientData)tktop, (Tcl_CmdDeleteProc *) NULL); } if (tktop != NULL) { Tcl_CreateObjCommand(interp, "simple", (Tcl_ObjCmdProc *)Tk_SimpleObjCmd, (ClientData)tktop, (Tcl_CmdDeleteProc *) NULL); } Tcl_Eval(interp, "lappend auto_path ."); sprintf(version_string, "%s", VERSION); Tcl_SetVar(interp, "QROUTER_VERSION", version_string, TCL_GLOBAL_ONLY); Tcl_Eval(interp, "namespace eval qrouter namespace export *"); Tcl_PkgProvide(interp, "Qrouter", version_string); /* Initialize the console interpreter, if there is one. */ if ((consoleinterp = Tcl_GetMaster(interp)) == NULL) consoleinterp = interp; /* Initialize the command tag table */ Tcl_InitHashTable(&QrouterTagTable, TCL_STRING_KEYS); return TCL_OK; } /*------------------------------------------------------*/ /* Command "start" */ /*------------------------------------------------------*/ static int qrouter_start(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int i, result, argc; char *scriptfile = NULL; char **argv; /* For compatibility with the original C code, convert Tcl */ /* object arguments to strings. Handle "-s ", */ /* which is not handled by runqrouter(), and source the */ /* script between runqrouter() and read_def(). */ argv = (char **)malloc((objc - 1) * sizeof(char *)); argc = 0; for (i = 1; i < objc; i++) { if (!strcmp(Tcl_GetString(objv[i]), "-s")) scriptfile = strdup(Tcl_GetString(objv[i + 1])); argv[argc++] = strdup(Tcl_GetString(objv[i])); } init_config(); result = runqrouter(argc, argv); if ((result == 0) && (batchmode == 0)) GUI_init(interp); for (i = 0; i < argc; i++) free(argv[i]); free(argv); if (scriptfile != NULL) { /* First check that the script file exists. If not, */ /* then generate an error here. */ FILE *scriptf = fopen(scriptfile, "r"); if (scriptf == NULL) { Fprintf(stderr, "Script file \"%s\" unavaliable or unreadable.\n", scriptfile); Tcl_SetResult(interp, "Script file unavailable or unreadable.", NULL); result = TCL_ERROR; } else { fclose(scriptf); result = Tcl_EvalFile(interp, scriptfile); } /* The script file should determine whether or not to */ /* exit by including the "quit" command. But if there */ /* is an error in the script, then always quit. */ /* If tkcon console is in use and there is an error in */ /* the script, then print the error message to the */ /* terminal, not the console, or else it vanishes. */ if (result != TCL_OK) { if (consoleinterp == interp) Fprintf(stderr, "Script file \"%s\" failed with result \'%s\'\n", scriptfile, Tcl_GetStringResult(interp)); else fprintf(stderr, "Script file \"%s\" failed with result \'%s\'\n", scriptfile, Tcl_GetStringResult(interp)); free(scriptfile); /* Make sure Tcl has generated all output */ while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0); /* And exit gracefully */ qrouter_quit(clientData, interp, 1, objv); } else free(scriptfile); } if ((DEFfilename != NULL) && (Nlgates == NULL)) { read_def(NULL); draw_layout(); } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command: qrouter_quit */ /* */ /* Call tkcon's exit routine, which will make sure */ /* the history file is updated before final exit. */ /*------------------------------------------------------*/ int qrouter_quit(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, "(no arguments)"); return TCL_ERROR; } /* Free up failed net list */ remove_failed(); /* Should be doing other cleanup tasks here. . . */ if (consoleinterp == interp) Tcl_Exit(TCL_OK); else Tcl_Eval(interp, "catch {tkcon eval exit}\n"); return TCL_OK; /* Not reached */ } /*------------------------------------------------------*/ /* Command "map" */ /* */ /* Specify what to draw in the graphics window */ /* */ /* map obstructions draw routes (normal) */ /* map congestion draw actual congestion */ /* map estimate draw estimated congestion */ /* map none route background is plain */ /* map routes draw routes over map */ /* map noroutes don't draw routes over map */ /* map unrouted draw unrouted nets over map */ /* map nounrouted don't draw unrouted nets */ /*------------------------------------------------------*/ static int qrouter_map(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int idx, result; static char *subCmds[] = { "obstructions", "congestion", "estimate", "none", "routes", "noroutes", "unrouted", "nounrouted", NULL }; enum SubIdx { ObsIdx, CongIdx, EstIdx, NoneIdx, RouteIdx, NoRouteIdx, UnroutedIdx, NoUnroutedIdx }; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } else if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case ObsIdx: if ((mapType & MAP_MASK) != MAP_OBSTRUCT) { mapType &= ~MAP_MASK; mapType |= MAP_OBSTRUCT; draw_layout(); } break; case CongIdx: if ((mapType & MAP_MASK) != MAP_CONGEST) { mapType &= ~MAP_MASK; mapType |= MAP_CONGEST; draw_layout(); } break; case EstIdx: if ((mapType & MAP_MASK) != MAP_ESTIMATE) { mapType &= ~MAP_MASK; mapType |= MAP_ESTIMATE; draw_layout(); } break; case NoneIdx: if ((mapType & MAP_MASK) != MAP_NONE) { mapType &= ~MAP_MASK; mapType |= MAP_NONE; draw_layout(); } break; case RouteIdx: mapType |= DRAW_ROUTES; draw_layout(); break; case NoRouteIdx: mapType &= ~DRAW_ROUTES; draw_layout(); break; case UnroutedIdx: mapType |= DRAW_UNROUTED; draw_layout(); break; case NoUnroutedIdx: mapType &= ~DRAW_UNROUTED; draw_layout(); } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Find the net with number "number" in the list of */ /* nets and return a pointer to it. */ /* */ /* NOTE: This could be hashed like net names, but is */ /* only used in one place, and router performance does */ /* not depend on it. */ /*------------------------------------------------------*/ NET LookupNetNr(int number) { NET net; int i; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->netnum == number) return net; } return NULL; } /*------------------------------------------------------*/ /* Command "stage1" */ /* */ /* Execute stage1 routing. This works through the */ /* entire netlist, routing as much as possible but not */ /* doing any rip-up and re-route. Nets that fail to */ /* route are put in the "FailedNets" list. */ /* */ /* The interpreter result is set to the number of */ /* failed routes at the end of the first stage. */ /* */ /* Options: */ /* */ /* stage1 debug Draw the area being searched in */ /* real-time. This slows down the */ /* algorithm and is intended only */ /* for diagnostic use. */ /* stage1 step Single-step stage one. */ /* stage1 mask none Don't limit the search area */ /* stage1 mask auto Select the mask automatically */ /* stage1 mask bbox Use the net bbox as a mask */ /* stage1 mask Set the mask size to , */ /* an integer typ. 0 and up. */ /* stage1 route Route net named only. */ /* */ /* stage1 force Force a terminal to be routable */ /*------------------------------------------------------*/ static int qrouter_stage1(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { u_char dodebug; u_char dostep; u_char saveForce, saveOverhead; int i, idx, idx2, val, result, failcount = 0; NET net = NULL; static char *subCmds[] = { "debug", "mask", "route", "force", "step", NULL }; enum SubIdx { DebugIdx, MaskIdx, RouteIdx, ForceIdx, StepIdx }; static char *maskSubCmds[] = { "none", "auto", "bbox", NULL }; enum maskSubIdx { NoneIdx, AutoIdx, BboxIdx }; // Command defaults dodebug = FALSE; dostep = FALSE; maskMode = MASK_AUTO; // Mask mode is auto unless specified // Save these global defaults in case they are locally changed saveForce = forceRoutable; if (objc >= 2) { for (i = 1; i < objc; i++) { if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case DebugIdx: dodebug = TRUE; break; case StepIdx: dostep = TRUE; break; case ForceIdx: forceRoutable = TRUE; break; case RouteIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "route ?net?"); return TCL_ERROR; } i++; net = DefFindNet(Tcl_GetString(objv[i])); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); return TCL_ERROR; } break; case MaskIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "mask ?type?"); return TCL_ERROR; } i++; if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)maskSubCmds, "type", 0, &idx2)) != TCL_OK) { Tcl_ResetResult(interp); result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; else if (val < 0 || val > 200) { Tcl_SetResult(interp, "Bad mask value", NULL); return TCL_ERROR; } maskMode = (u_char)val; } else { switch(idx2) { case NoneIdx: maskMode = MASK_NONE; break; case AutoIdx: maskMode = MASK_AUTO; break; case BboxIdx: maskMode = MASK_BBOX; break; } } break; } } } if (dostep == FALSE) stepnet = -1; else stepnet++; if (net == NULL) failcount = dofirststage(dodebug, stepnet); else { if ((net != NULL) && (net->netnodes != NULL)) { result = doroute(net, (u_char)0, dodebug); failcount = (result == 0) ? 0 : 1; /* Remove from FailedNets list if routing */ /* was successful */ if (result == 0 && FailedNets != NULL) { NETLIST fnet, lnet = NULL; for (fnet = FailedNets; fnet != NULL; fnet = fnet->next) { if (fnet->net == net) { if (lnet == NULL) FailedNets = fnet->next; else lnet->next = fnet->next; free(fnet); break; } lnet = fnet; } } } } Tcl_SetObjResult(interp, Tcl_NewIntObj(failcount)); if (stepnet >= (Numnets - 1)) stepnet = -1; // Restore global defaults in case they were locally changed forceRoutable = saveForce; return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "stage2" */ /* */ /* Execute stage2 routing. This stage works through */ /* the "FailedNets" list, routing with collisions, and */ /* then ripping up the colliding nets and appending */ /* them to the "FailedNets" list. */ /* */ /* The interpreter result is set to the number of */ /* failed routes at the end of the second stage. */ /* */ /* Options: */ /* */ /* stage2 debug Draw the area being searched in */ /* real-time. This slows down the */ /* algorithm and is intended only */ /* for diagnostic use. */ /* stage2 step Single-step stage two */ /* stage2 mask none Don't limit the search area */ /* stage2 mask auto Select the mask automatically */ /* stage2 mask bbox Use the net bbox as a mask */ /* stage2 mask Set the mask size to , */ /* an integer typ. 0 and up. */ /* stage2 limit Fail route if solution collides */ /* with more than nets. */ /* stage2 route Route net named only. */ /* */ /* stage2 force Force a terminal to be routable */ /* stage2 break Only rip up colliding segment */ /* stage2 effort Level of effort (default 100) */ /*------------------------------------------------------*/ static int qrouter_stage2(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { u_int effort; u_char dodebug; u_char dostep; u_char onlybreak; u_char saveForce, saveOverhead; int i, idx, idx2, val, result, failcount; NET net = NULL; static char *subCmds[] = { "debug", "mask", "limit", "route", "force", "tries", "step", "break", "effort", NULL }; enum SubIdx { DebugIdx, MaskIdx, LimitIdx, RouteIdx, ForceIdx, TriesIdx, StepIdx, BreakIdx, EffortIdx }; static char *maskSubCmds[] = { "none", "auto", "bbox", NULL }; enum maskSubIdx { NoneIdx, AutoIdx, BboxIdx }; // Command defaults dodebug = FALSE; dostep = FALSE; onlybreak = FALSE; maskMode = MASK_AUTO; // Mask mode is auto unless specified // Save these global defaults in case they are locally changed saveForce = forceRoutable; ripLimit = 10; // Rip limit is 10 unless specified effort = 100; // Moderate to high effort if (objc >= 2) { for (i = 1; i < objc; i++) { if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case DebugIdx: dodebug = TRUE; break; case StepIdx: dostep = TRUE; break; case BreakIdx: onlybreak = TRUE; break; case ForceIdx: forceRoutable = TRUE; break; case EffortIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "effort ?num?"); return TCL_ERROR; } i++; result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; effort = (u_int)val; break; case TriesIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "tries ?num?"); return TCL_ERROR; } i++; result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; Tcl_SetResult(interp, "\"tries\" deprecated, " "use \"effort\" instead.", NULL); effort = (u_char)val * 100; break; case RouteIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "route ?net?"); return TCL_ERROR; } i++; net = DefFindNet(Tcl_GetString(objv[i])); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); return TCL_ERROR; } break; case LimitIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "limit ?num?"); return TCL_ERROR; } i++; result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; ripLimit = (u_char)val; break; case MaskIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "mask ?type?"); return TCL_ERROR; } i++; if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)maskSubCmds, "type", 0, &idx2)) != TCL_OK) { Tcl_ResetResult(interp); result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; else if (val < 0 || val > 200) { Tcl_SetResult(interp, "Bad mask value", NULL); return TCL_ERROR; } maskMode = (u_char)val; } else { switch(idx2) { case NoneIdx: maskMode = MASK_NONE; break; case AutoIdx: maskMode = MASK_AUTO; break; case BboxIdx: maskMode = MASK_BBOX; break; } } break; } } } if (net == NULL) failcount = dosecondstage(dodebug, dostep, onlybreak, effort); else failcount = route_net_ripup(net, dodebug, onlybreak); Tcl_SetObjResult(interp, Tcl_NewIntObj(failcount)); draw_layout(); // Restore global defaults in case they were locally changed forceRoutable = saveForce; return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "stage3" */ /* */ /* Execute stage3 routing. This works through the */ /* entire netlist, ripping up each route in turn and */ /* re-routing it. */ /* */ /* The interpreter result is set to the number of */ /* failed routes at the end of the first stage. */ /* */ /* Options: */ /* */ /* stage3 debug Draw the area being searched in */ /* real-time. This slows down the */ /* algorithm and is intended only */ /* for diagnostic use. */ /* stage3 step Single-step stage three. */ /* stage3 mask none Don't limit the search area */ /* stage3 mask auto Select the mask automatically */ /* stage3 mask bbox Use the net bbox as a mask */ /* stage3 mask Set the mask size to , */ /* an integer typ. 0 and up. */ /* stage3 route Route net named only. */ /* */ /* stage3 force Force a terminal to be routable */ /* stage3 effort Level of effort (default 100) */ /*------------------------------------------------------*/ static int qrouter_stage3(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { u_int effort; u_char dodebug; u_char dostep; u_char saveForce, saveOverhead; int i, idx, idx2, val, result, failcount = 0; NET net = NULL; static char *subCmds[] = { "debug", "mask", "route", "force", "step", "effort", NULL }; enum SubIdx { DebugIdx, MaskIdx, RouteIdx, ForceIdx, StepIdx, EffortIdx }; static char *maskSubCmds[] = { "none", "auto", "bbox", NULL }; enum maskSubIdx { NoneIdx, AutoIdx, BboxIdx }; // Command defaults dodebug = FALSE; dostep = FALSE; maskMode = MASK_AUTO; // Mask mode is auto unless specified effort = 100; // Moderate to high effort // Save these global defaults in case they are locally changed saveForce = forceRoutable; if (objc >= 2) { for (i = 1; i < objc; i++) { if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case DebugIdx: dodebug = TRUE; break; case StepIdx: dostep = TRUE; break; case ForceIdx: forceRoutable = TRUE; break; case EffortIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "effort ?num?"); return TCL_ERROR; } i++; result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; effort = (u_int)val; break; case RouteIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "route ?net?"); return TCL_ERROR; } i++; net = DefFindNet(Tcl_GetString(objv[i])); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); return TCL_ERROR; } break; case MaskIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "mask ?type?"); return TCL_ERROR; } i++; if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)maskSubCmds, "type", 0, &idx2)) != TCL_OK) { Tcl_ResetResult(interp); result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; else if (val < 0 || val > 200) { Tcl_SetResult(interp, "Bad mask value", NULL); return TCL_ERROR; } maskMode = (u_char)val; } else { switch(idx2) { case NoneIdx: maskMode = MASK_NONE; break; case AutoIdx: maskMode = MASK_AUTO; break; case BboxIdx: maskMode = MASK_BBOX; break; } } break; } } } if (dostep == FALSE) stepnet = -1; else stepnet++; if (net == NULL) failcount = dothirdstage(dodebug, stepnet, effort); else { /* To do: Duplicate behavior of dothirdstage(), which */ /* is to retain the original route solution and restore */ /* it in case the routing fails. */ if ((net != NULL) && (net->netnodes != NULL)) { result = doroute(net, (u_char)0, dodebug); failcount = (result == 0) ? 0 : 1; /* Remove from FailedNets list if routing */ /* was successful */ if (result == 0 && FailedNets != NULL) { NETLIST fnet, lnet = NULL; for (fnet = FailedNets; fnet != NULL; fnet = fnet->next) { if (fnet->net == net) { if (lnet == NULL) FailedNets = fnet->next; else lnet->next = fnet->next; free(fnet); break; } lnet = fnet; } } } } Tcl_SetObjResult(interp, Tcl_NewIntObj(failcount)); if (stepnet >= (Numnets - 1)) stepnet = -1; // Restore global defaults in case they were locally changed forceRoutable = saveForce; return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "cleanup" */ /* */ /* Clean up the nets by removing adjacent vias where */ /* such adjacent vias would cause a DRC violation. */ /* Note that this must be done between the last */ /* routing stage but before finding antenna */ /* violations, output, and delay writing, as all of */ /* these can be dependent on topology changes caused */ /* by the cleanup. */ /* */ /* Options: */ /* */ /* cleanup all Clean up all nets in the design */ /* cleanup net [...] */ /* Clean up the named net(s) */ /*------------------------------------------------------*/ static int qrouter_cleanup(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, idx, i; NET net; static char *subCmds[] = { "all", "net", NULL }; enum SubIdx { AllIdx, NetIdx }; if (objc < 2) { Tcl_WrongNumArgs(interp, 0, objv, "?option?"); return TCL_ERROR; } else { if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; // Quick check to see if cleanup_net can be avoided completely. for (i = 0; i < Num_layers; i++) if (needblock[i] & (VIABLOCKX | VIABLOCKY)) break; if (i == Num_layers) return TCL_OK; /* No cleanup needed */ switch (idx) { case AllIdx: for (i = 0; i < Numnets; i++) { net = Nlnets[i]; cleanup_net(net); } break; case NetIdx: for (i = 2; i < objc; i++) { net = DefFindNet(Tcl_GetString(objv[i])); if (net != NULL) cleanup_net(net); } break; } } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "remove" */ /* */ /* Remove a net or nets, or all nets, from the */ /* design. */ /* */ /* Options: */ /* */ /* remove all Remove all nets from the design */ /* remove net [...] */ /* Remove the named net(s) from */ /* the design. */ /*------------------------------------------------------*/ static int qrouter_remove(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, idx, i; NET net; static char *subCmds[] = { "all", "net", NULL }; enum SubIdx { AllIdx, NetIdx }; if (objc < 2) { Tcl_WrongNumArgs(interp, 0, objv, "?option?"); return TCL_ERROR; } else { if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case AllIdx: for (i = 0; i < Numnets; i++) { net = Nlnets[i]; ripup_net(net, (u_char)1, (u_char)1, (u_char)0); } draw_layout(); break; case NetIdx: for (i = 2; i < objc; i++) { net = DefFindNet(Tcl_GetString(objv[i])); if (net != NULL) ripup_net(net, (u_char)1, (u_char)1, (u_char)0); } draw_layout(); break; } } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "failing" */ /* */ /* List the nets that have failed routing. */ /* */ /* Options: */ /* */ /* failing all Move all nets to FailedNets */ /* ordered by the standard metric */ /* failing unordered Move all nets to FailedNets, */ /* as originally ordered */ /* failing summary List of failed and total nets */ /*------------------------------------------------------*/ static int qrouter_failing(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_Obj *lobj; NETLIST nl, nlast; NET net; int i, failcount; if (objc == 2) { if (!strncmp(Tcl_GetString(objv[1]), "unorder", 7)) { // Free up FailedNets list and then move all // nets to FailedNets while (FailedNets != NULL) { nl = FailedNets->next; FailedNets = FailedNets->next; free(nl); } nlast = NULL; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; nl = (NETLIST)malloc(sizeof(struct netlist_)); nl->net = net; nl->next = NULL; if (nlast == NULL) FailedNets = nl; else nlast->next = nl; nlast = nl; } } else if (!strncmp(Tcl_GetString(objv[1]), "all", 3)) { while (FailedNets != NULL) { nl = FailedNets->next; FailedNets = FailedNets->next; free(nl); } create_netorder(0); nlast = NULL; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; nl = (NETLIST)malloc(sizeof(struct netlist_)); nl->net = net; nl->next = NULL; if (nlast == NULL) FailedNets = nl; else nlast->next = nl; nlast = nl; } } else if (!strncmp(Tcl_GetString(objv[1]), "summary", 7)) { failcount = countlist(FailedNets); lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewIntObj(failcount)); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewIntObj(Numnets)); Tcl_SetObjResult(interp, lobj); } else { Tcl_WrongNumArgs(interp, 0, objv, "all or unordered"); return TCL_ERROR; } } else { lobj = Tcl_NewListObj(0, NULL); for (nl = FailedNets; nl; nl = nl->next) { Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(nl->net->netname, -1)); } Tcl_SetObjResult(interp, lobj); } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "read_lef" */ /*------------------------------------------------------*/ static int qrouter_readlef(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *LEFfile; int mscale; int i; if (objc != 2) { Tcl_SetResult(interp, "No LEF filename specified!", NULL); return TCL_ERROR; } LEFfile = Tcl_GetString(objv[1]); mscale = LefRead(LEFfile); update_mscale(mscale); for (i = 0; i < Num_layers; i++) { /* Set Vert from route info since this gets called a lot */ /* (e.g., from eval_pt() and is more convenient to pull */ /* from an array than calling a subroutine every time. */ Vert[i] = (1 - LefGetRouteOrientation(i)); } /* Resolve the base horizontal and vertical pitches */ post_config(FALSE); /* Set DRC blockage behavior based on via and route widths */ apply_drc_blocks(-1, 0.0, 0.0); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "read_def" */ /*------------------------------------------------------*/ static int qrouter_readdef(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *argv; u_char abort_on_error = FALSE; int result; /* Parse out options */ while (objc > 0) { argv = Tcl_GetString(objv[objc - 1]); if (*argv == '-') { if (!strncmp(argv + 1, "abort", 5)) abort_on_error = TRUE; objc--; } else break; } if ((DEFfilename == NULL) && (objc != 2)) { Tcl_SetResult(interp, "No DEF filename specified!", NULL); return TCL_ERROR; } if (objc == 2) result = read_def(Tcl_GetString(objv[1])); else result = read_def(NULL); if ((result != (u_char)0) && (abort_on_error == TRUE)) { Tcl_SetResult(interp, "Errors in input DEF file; aborting.", NULL); return TCL_ERROR; } // Redisplay draw_layout(); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "write_def" */ /*------------------------------------------------------*/ static int qrouter_writedef(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *DEFoutfile = NULL; if (objc == 2) DEFoutfile = Tcl_GetString(objv[1]); else if (DEFfilename == NULL) { Tcl_SetResult(interp, "No DEF filename specified!", NULL); return TCL_ERROR; } else DEFoutfile = DEFfilename; write_def(DEFoutfile); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "antenna" */ /* Use: */ /* antenna init */ /* antenna check */ /* antenna fix */ /* */ /* Calculate and handle antenna violations. Option */ /* "init" declares the cellname that is an antenna */ /* anchoring cell. This must be declared before */ /* routing. "antenna check" can be called at any time */ /* and reports the number of antenna violations at each */ /* metal layer. "antenna fix" attempts to fix all */ /* antenna violations by anchoring each antenna to an */ /* available antenna cell tap. */ /*------------------------------------------------------*/ static int qrouter_antenna(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *option; u_char do_fix = (u_char)0; if (objc >= 2) { option = Tcl_GetString(objv[1]); if (objc == 3) antenna_cell = strdup(Tcl_GetString(objv[2])); if (!strcmp(option, "init")) { if (objc != 3) { if (antenna_cell != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj(antenna_cell, -1)); } else { Tcl_SetResult(interp, "No antenna cell name specified.", NULL); return TCL_ERROR; } } } else if (!strcmp(option, "check")) { resolve_antenna(antenna_cell, (u_char)0); } else if (!strcmp(option, "fix")) { resolve_antenna(antenna_cell, (u_char)1); } else { antenna_cell = Tcl_GetString(objv[1]); } } else { Tcl_SetResult(interp, "Usage: antenna init|check|fix [cellname]", NULL); return TCL_ERROR; } if (antenna_cell == NULL) { Tcl_SetResult(interp, "No antenna cell specified!", NULL); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "write_failed" */ /*------------------------------------------------------*/ static int qrouter_writefailed(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *outfile = NULL; if (objc == 2) outfile = Tcl_GetString(objv[1]); else if (outfile == NULL) { Tcl_SetResult(interp, "No output filename specified!", NULL); return TCL_ERROR; } write_failed(outfile); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "write_delays" */ /*------------------------------------------------------*/ static int qrouter_writedelays(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *delayoutfile = NULL; if (objc == 2) delayoutfile = Tcl_GetString(objv[1]); else if (delayfilename == NULL) { Tcl_SetResult(interp, "No delay filename specified!", NULL); return TCL_ERROR; } else delayoutfile = delayfilename; write_delays(delayoutfile); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "read_config" */ /*------------------------------------------------------*/ static int qrouter_readconfig(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { FILE *configFILE; char *configname = NULL; if (objc == 2) configname = Tcl_GetString(objv[1]); else { Tcl_SetResult(interp, "No configuration filename specified!", NULL); return TCL_ERROR; } configFILE = fopen(configname, "r"); if (configFILE == NULL) { Tcl_SetResult(interp, "Failed to open configuration file.", NULL); return TCL_ERROR; } read_config(configFILE, FALSE); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "obstruction" */ /* */ /* Create an obstruction manually by specifying a */ /* rectangular bounding box and layer of the obstructed */ /* area. Without options, returns a list of the */ /* defined user obstruction areas. */ /* */ /* Options: */ /* */ /* obstruction */ /* obstruction */ /*------------------------------------------------------*/ static int qrouter_obs(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_Obj *lobj; Tcl_Obj *oobj; LefList lefl; char *layername; DSEG obs; int layer, result; double x1, x2, y1, y2; if (objc == 1) { lobj = Tcl_NewListObj(0, NULL); for (obs = UserObs; obs; obs = obs->next) { lefl = LefFindLayerByNum(obs->layer); if (lefl == NULL) continue; oobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewDoubleObj(obs->x1)); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewDoubleObj(obs->x2)); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewDoubleObj(obs->y1)); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewDoubleObj(obs->y2)); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewStringObj(lefl->lefName, -1)); Tcl_ListObjAppendElement(interp, lobj, oobj); } Tcl_SetObjResult(interp, lobj); } else if (objc != 6) { Tcl_WrongNumArgs(interp, 1, objv, "x1 x2 y1 y2 layer"); return TCL_ERROR; } else { layername = Tcl_GetString(objv[5]); layer = LefFindLayerNum(layername); if (layer < 0) { Tcl_SetResult(interp, "No such layer name", NULL); return TCL_ERROR; } else { result = Tcl_GetDoubleFromObj(interp, objv[1], &x1); if (result != TCL_OK) return result; result = Tcl_GetDoubleFromObj(interp, objv[2], &y1); if (result != TCL_OK) return result; result = Tcl_GetDoubleFromObj(interp, objv[3], &x2); if (result != TCL_OK) return result; result = Tcl_GetDoubleFromObj(interp, objv[4], &y2); if (result != TCL_OK) return result; obs = (DSEG)malloc(sizeof(struct dseg_)); obs->x1 = x1; obs->x2 = x2; obs->y1 = y1; obs->y2 = y2; obs->layer = layer; obs->next = UserObs; UserObs = obs; } } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "ignore" */ /* */ /* Specify one or more net names to be ignored by the */ /* router. With no options, returns a list of nets */ /* being ignored by the router. */ /* */ /* Options: */ /* */ /* ignore [ ...] */ /*------------------------------------------------------*/ static int qrouter_ignore(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int i; NET net; Tcl_Obj *lobj; if (objc == 1) { lobj = Tcl_NewListObj(0, NULL); for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->flags & NET_IGNORED) { Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(net->netname, -1)); } } Tcl_SetObjResult(interp, lobj); } else { for (i = 1; i < objc; i++) { net = DefFindNet(Tcl_GetString(objv[i])); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); return TCL_ERROR; } net->flags |= NET_IGNORED; } } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "priority" */ /* */ /* Specify one or more net names to be routed first by */ /* the router. With no options, returns a list of */ /* nets prioritized by the router. */ /* */ /* Options: */ /* */ /* priority [ ...] */ /*------------------------------------------------------*/ static int qrouter_priority(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int i, j; char *netname; NET net; STRING cn, ctest; Tcl_Obj *lobj; if (objc == 1) { lobj = Tcl_NewListObj(0, NULL); for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->flags & NET_CRITICAL) { Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(net->netname, -1)); } } Tcl_SetObjResult(interp, lobj); } else if (Nlnets == NULL) { Tcl_SetResult(interp, "Must read nets from DEF file before setting priority.", NULL); return TCL_ERROR; } else { /* Find the highest-numbered existing critical net so that */ /* repeated calls to "priority" will work. */ j = -1; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->flags & NET_CRITICAL) if (net->netorder > j) j = net->netorder; } j++; for (i = 1; i < objc; i++) { netname = Tcl_GetString(objv[i]); net = DefFindNet(netname); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); } else if (!(net->flags & NET_CRITICAL)) { net->flags |= NET_CRITICAL; net->netorder = j++; /* NOTE: CriticalNet is left over from the old config */ /* file format. Normally it will remain NULL. If the */ /* old config file format is used, then remove items */ /* from it that match nets in the Tcl priority command. */ for (cn = CriticalNet; cn && cn->next; cn = cn->next) { if (!cn->next) break; if (!strcmp(cn->next->name, netname)) { ctest = cn->next; cn->next = cn->next->next; ctest->next = CriticalNet; CriticalNet = ctest; } } } } create_netorder(0); } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "layer_info" */ /* */ /* Provide information gleaned from the LEF technology */ /* file or files */ /* */ /* Options: */ /* */ /* layer_info [all] */ /* layer_info | */ /* layer_info | width */ /* layer_info | pitch */ /* layer_info | orientation */ /* layer_info | offset */ /* layer_info | spacing */ /* layer_info maxlayer */ /* */ /* all: generate a list summary of route information */ /* in the format of the info file generated with */ /* the "-i" command-line switch. */ /* : generate a list summary of information for */ /* the specified route layer , format the */ /* same as for option "all". */ /* pitch: Return the layer pitch value. */ /* orientation: Return the layer orientation. */ /* offset: Return the layer offset value. */ /* spacing: Return the layer minimum spacing */ /* value. */ /* maxlayer: Return the maximum number of route layers */ /* defined by the technology. */ /* */ /* No option is the same as option "layer_info all" */ /*------------------------------------------------------*/ static int qrouter_layerinfo(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_Obj *lobj, *oobj; int i, idx, idx2, val, result, layer = -1; char *layername; static char *subCmds[] = { "all", "maxlayer", NULL }; enum SubIdx { AllIdx, MaxLayerIdx }; static char *layerSubCmds[] = { "width", "pitch", "orientation", "offset", "spacing", NULL }; enum layerSubIdx { WidthIdx, PitchIdx, OrientIdx, OffsetIdx, SpacingIdx }; idx = idx2 = -1; if (objc < 2) { idx = AllIdx; } else { layername = Tcl_GetString(objv[1]); layer = LefFindLayerNum(layername); if (layer == -1) { if ((result = Tcl_GetIntFromObj(interp, objv[1], &val)) == TCL_OK) { layer = val; } else { Tcl_ResetResult(interp); if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) { return result; } } } else if (objc >= 3) { if ((result = Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)layerSubCmds, "option", 0, &idx2)) != TCL_OK) { return result; } layer = LefFindLayerNum(layername); } else { layer = LefFindLayerNum(layername); } } if (idx == -1 && layer == -1) { Tcl_SetResult(interp, "Bad layer", NULL); return TCL_ERROR; } if (layer < 0 || layer >= Num_layers) { Tcl_SetResult(interp, "Bad layer", NULL); return TCL_ERROR; } switch (idx) { case AllIdx: oobj = Tcl_NewListObj(0, NULL); for (i = 0; i < Num_layers; i++) { lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(LefGetRouteName(i), -1)); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewDoubleObj(LefGetRoutePitch(i))); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewDoubleObj(LefGetRouteWidth(i))); if (LefGetRouteOrientation(i) == 1) Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj("horizontal", -1)); else Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj("vertical", -1)); Tcl_ListObjAppendElement(interp, oobj, lobj); } Tcl_SetObjResult(interp, oobj); break; case MaxLayerIdx: Tcl_SetObjResult(interp, Tcl_NewIntObj(Num_layers)); break; } switch (idx2) { case WidthIdx: Tcl_SetObjResult(interp, Tcl_NewDoubleObj(LefGetRouteWidth(layer))); break; case PitchIdx: Tcl_SetObjResult(interp, Tcl_NewDoubleObj(LefGetRoutePitch(layer))); break; case OrientIdx: if (LefGetRouteOrientation(layer) == (u_char)0) Tcl_SetObjResult(interp, Tcl_NewStringObj("vertical", -1)); else Tcl_SetObjResult(interp, Tcl_NewStringObj("horizontal", -1)); break; case OffsetIdx: Tcl_SetObjResult(interp, Tcl_NewDoubleObj(LefGetRouteOffset(layer))); break; case SpacingIdx: Tcl_SetObjResult(interp, Tcl_NewDoubleObj(LefGetRouteSpacing(layer))); break; default: if (idx != -1) break; lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(LefGetRouteName(layer), -1)); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewDoubleObj(LefGetRoutePitch(layer))); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewDoubleObj(LefGetRouteWidth(layer))); if (LefGetRouteOrientation(layer) == 1) Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj("horizontal", -1)); else Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj("vertical", -1)); Tcl_SetObjResult(interp, lobj); break; } return TCL_OK; } /*------------------------------------------------------*/ /* Command "via" */ /* */ /* Various via configuration options for qrouter. */ /* */ /* stack: Value is the maximum number of vias that may */ /* be stacked directly on top of each other at */ /* a single point. Value "none", "0", and "1" */ /* all mean the same thing. */ /* */ /* via_pattern: (deprecated) */ /* */ /* use: List of names of vias to use. If any via not */ /* in this list is found when reading a .lef file */ /* it will be ignored. */ /* */ /* Options: */ /* */ /* via stack [none|all|] */ /* via pattern [normal|inverted] */ /* via use [ ...] */ /*------------------------------------------------------*/ static int qrouter_via(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int idx, idx2, result, value, i; char *vname; Tcl_Obj *lobj; LinkedStringPtr viaName, newVia; static char *subCmds[] = { "stack", "pattern", "use", NULL }; enum SubIdx { StackIdx, PatternIdx, UseIdx }; static char *stackSubCmds[] = { "none", "all", NULL }; enum stackSubIdx { NoneIdx, AllIdx }; static char *patternSubCmds[] = { "none", "normal", "inverted", NULL }; enum patternSubIdx { PatNoneIdx, PatNormalIdx, PatInvertIdx }; if (objc >= 2) { if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; if (objc == 2) { switch (idx) { case StackIdx: Tcl_SetObjResult(interp, Tcl_NewIntObj(StackedContacts)); break; case PatternIdx: Tcl_SetObjResult(interp, Tcl_NewStringObj("deprecated", -1)); break; case UseIdx: /* Return list of vias to use */ lobj = Tcl_NewListObj(0, NULL); for (viaName = AllowedVias; viaName; viaName = viaName->next) { Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(viaName->name, -1)); } Tcl_SetObjResult(interp, lobj); break; } } else { switch (idx) { case StackIdx: result = Tcl_GetIntFromObj(interp, objv[2], &value); if (result == TCL_OK) { if (value <= 0) value = 1; else if (value >= Num_layers) value = Num_layers - 1; StackedContacts = value; break; } Tcl_ResetResult(interp); if ((result = Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)stackSubCmds, "option", 0, &idx2)) != TCL_OK) return result; switch (idx2) { case NoneIdx: StackedContacts = 1; break; case AllIdx: StackedContacts = Num_layers - 1; break; } break; case PatternIdx: if ((result = Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)patternSubCmds, "option", 0, &idx2)) != TCL_OK) return result; break; case UseIdx: /* Create list of vias to use */ for (i = 2; i < objc; i++) { vname = Tcl_GetString(objv[i]); /* First check if name is in list already */ for (viaName = AllowedVias; viaName; viaName = viaName->next) { if (!strcmp(vname, viaName->name)) break; } if (viaName != NULL) continue; newVia = (LinkedStringPtr)malloc(sizeof(LinkedString)); newVia->name = strdup(vname); newVia->next = AllowedVias; AllowedVias = newVia; } /* Regenerate the ViaXX, etc., lists */ LefAssignLayerVias(); break; } } } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "verbose" */ /* */ /* Set the level of how much output to print to the */ /* console. 0 is minimal output, 4 is maximum output */ /* With no argument, return the level of verbose. */ /* */ /* Options: */ /* */ /* resolution [] */ /*------------------------------------------------------*/ static int qrouter_verbose(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Verbose)); } else if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value < 0 || value > 255) { Tcl_SetResult(interp, "Verbose level out of range", NULL); return TCL_ERROR; } Verbose = (u_char)value; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "resolution" */ /* */ /* Set the level of resolution of the output relative */ /* to the base units of centimicrons. The default */ /* value of 1 rounds all output values to the nearest */ /* centimicron; value 10 is to the nearest nanometer, */ /* and so forth. */ /* With no argument, return the value of the output */ /* resolution. */ /* */ /* Options: */ /* */ /* resolution [] */ /*------------------------------------------------------*/ static int qrouter_resolution(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Scales.iscale)); } else if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value < 1) { Tcl_SetResult(interp, "Resolution out of range", NULL); return TCL_ERROR; } Scales.iscale = value; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "query" */ /* */ /* Print information about a specific grid point, */ /* instance, node, or net. Option "watch" indicates to */ /* monitor the position during DEF read-in and print */ /* information when the node information changes, */ /* especially if the grid position is disabled. */ /* */ /* Options: */ /* */ /* query grid [watch] */ /* query position [watch] */ /* query instance */ /* query node / */ /* query net */ /* */ /* may be either a layer name or integer index. */ /* and should be given in microns. and */ /* are integer indexes. All other arguments are */ /* strings. */ /*------------------------------------------------------*/ static int qrouter_query(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *layername, *instname, *netname, *pinname; int idx, result, layer; int gridx, gridy; double dx, dy; unsigned char is_index, do_watch, do_unwatch; static char *subCmds[] = { "grid", "position", "instance", "node", "net", NULL }; enum SubIdx { GridIdx, PosIdx, InstIdx, NodeIdx, NetIdx }; if (objc < 2) { Fprintf(stderr, "Usage:\n"); Fprintf(stderr, " query position [watch]\n"); Fprintf(stderr, " query grid [watch]\n"); Fprintf(stderr, " query instance \n"); Fprintf(stderr, " query node /\n"); Fprintf(stderr, " query net \n"); Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } else if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; do_watch = do_unwatch = FALSE; switch (idx) { case GridIdx: case PosIdx: if (objc == 6) { if (!strcmp(Tcl_GetString(objv[5]), "watch")) { do_watch = TRUE; objc--; } else if (!strcmp(Tcl_GetString(objv[5]), "unwatch")) { do_unwatch = TRUE; objc--; } } if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } is_index = (idx == GridIdx) ? TRUE : FALSE; layername = Tcl_GetString(objv[4]); layer = LefFindLayerNum(layername); if (layer < 0) { result = Tcl_GetIntFromObj(interp, objv[4], &layer); if (result != TCL_OK) { Tcl_SetResult(interp, "No such layer name.\n", NULL); return result; } } if (layer >= Num_layers) { Tcl_SetResult(interp, "Bad layer number.\n", NULL); return result; } if (is_index) { result = Tcl_GetIntFromObj(interp, objv[2], &gridx); if (result != TCL_OK) { Tcl_SetResult(interp, "Cannot parse grid X index\n", NULL); return result; } result = Tcl_GetIntFromObj(interp, objv[3], &gridy); if (result != TCL_OK) { Tcl_SetResult(interp, "Cannot parse grid Y index\n", NULL); return result; } /* Translate gridx, gridy into dx, dy */ dx = (gridx * PitchX) + Xlowerbound; dy = (gridy * PitchY) + Ylowerbound; } else { result = Tcl_GetDoubleFromObj(interp, objv[2], &dx); if (result != TCL_OK) { Tcl_SetResult(interp, "Cannot parse grid X position\n", NULL); return result; } result = Tcl_GetDoubleFromObj(interp, objv[3], &dy); if (result != TCL_OK) { Tcl_SetResult(interp, "Cannot parse grid Y position\n", NULL); return result; } /* Translate dx, dy into nearest gridx, gridy */ gridx = (int)(round((dx - Xlowerbound) / PitchX)); gridy = (int)(round((dy - Ylowerbound) / PitchY)); Fprintf(stdout, "Grid position index is (%d %d)\n", gridx, gridy); } if (gridx < 0) { Tcl_SetResult(interp, "Grid X position must not be negative.\n", NULL); return result; } if (gridy < 0) { Tcl_SetResult(interp, "Grid Y position must not be negative.\n", NULL); return result; } if (do_watch) { DPOINT newtest; newtest = (DPOINT)malloc(sizeof(struct dpoint_)); newtest->layer = layer; newtest->next = testpoint; if (idx == GridIdx) { newtest->gridx = gridx; newtest->gridy = gridy; newtest->x = 0; newtest->y = 0; Fprintf(stdout, "Watching grid position index (%d %d)" " layer %d.\n", gridx, gridy, layer); } else { newtest->x = dx; newtest->y = dy; newtest->gridx = -1; newtest->gridy = -1; Fprintf(stdout, "Watching grid position (%g %g)um" " layer %d.\n", dx, dy, layer); } testpoint = newtest; } else if (do_unwatch) { DPOINT ptest, ltest; ltest = NULL; for (ptest = testpoint; ptest; ptest = ptest->next) { if (ptest->x == dx && ptest->y == dy && ptest->layer == layer) { if (ltest == NULL) { testpoint = testpoint->next; free(ptest); } else { ltest->next = ptest->next; free(ptest); } Fprintf(stdout, "No longer watching grid position (%g %g)um" " index (%d %d) layer %d.\n", dx, dy, gridx, gridy, layer); break; } ltest = ptest; } if (ptest == NULL) { Fprintf(stdout, "Grid position (%g %g)um index (%d %d)" " layer %d is not on the watch list.\n", dx, dy, gridx, gridy, layer); } } else if (gridx >= NumChannelsX) { Tcl_SetResult(interp, "Grid X position is larger than the number" " of horizontal route tracks.\n", NULL); return result; } else if (gridy >= NumChannelsY) { Tcl_SetResult(interp, "Grid Y position is larger than the number" " of vertical route tracks.\n", NULL); return result; } else { Fprintf(stdout, "Querying grid position (%g %g)um index (%d %d)" " layer %d:\n", dx, dy, gridx, gridy, layer); print_grid_information(gridx, gridy, layer); } break; case InstIdx: if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } instname = Tcl_GetString(objv[2]); print_instance_information(instname); break; case NodeIdx: if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } instname = Tcl_GetString(objv[2]); print_node_information(instname); break; case NetIdx: if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } netname = Tcl_GetString(objv[2]); print_net_information(netname); break; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "drc" */ /* */ /* Set qrouter options related to handling of DRC */ /* violations. */ /* */ /* Options: */ /* */ /* drc |all */ /* */ /* Allow exceptions to DRC handling. Normally qrouter */ /* enforces DRC distance between a via and route or */ /* between two vias on adjacent tracks, forcing a */ /* keep-out area around a placed route if needed. */ /* "layer" is the name of a route layer. (value */ /* in microns) will limit the enforcement if the DRC */ /* violation is less than the indicated distance. */ /* The first value is for via-to-via distance, and the */ /* second value is for route-to-via distance. A value */ /* of zero means that the behavior is unchanged from */ /* what is automatically calculated from defined */ /* route and via width and spacing values. A positive */ /* distance value loosens the DRC rule, while a */ /* negative distance value tightens it. */ /* */ /* Ignoring DRC errors is generally discouraged but */ /* may be necessary in some cases if the pitch is tight */ /* and assumes routes may be offset to clear vias, */ /* which is something qrouter does not know how to do. */ /* Only use this if routability is being impacted by */ /* DRC enforcement. */ /*------------------------------------------------------*/ static int qrouter_drc(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *layername; int result, layer; double routedist, viadist; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } layername = Tcl_GetString(objv[1]); if (!strcasecmp(layername, "all")) { layer = -1; } else { layer = LefFindLayerNum(layername); if (layer < 0) { result = Tcl_GetIntFromObj(interp, objv[1], &layer); if (result != TCL_OK) { Tcl_SetResult(interp, "No such layer name.\n", NULL); return result; } } if ((layer < -1) || (layer >= LefGetMaxRouteLayer())) { Tcl_SetResult(interp, "Layer number out of range.\n", NULL); return TCL_ERROR; } } result = Tcl_GetDoubleFromObj(interp, objv[2], &viadist); if (result != TCL_OK) return result; result = Tcl_GetDoubleFromObj(interp, objv[3], &routedist); if (result != TCL_OK) return result; apply_drc_blocks(layer, viadist, routedist); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "layers" */ /* */ /* Set the number of layers used for routing */ /* independently of the number defined in the */ /* technology LEF file. Without an argument, return */ /* the number of layers being used (this is not the */ /* same as "layer_info maxlayer") */ /* */ /* Options: */ /* */ /* layers [] */ /*------------------------------------------------------*/ static int qrouter_layers(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Num_layers)); } else if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value <= 0 || value > LefGetMaxRouteLayer()) { Tcl_SetResult(interp, "Number of layers out of range," " setting to max.", NULL); Num_layers = LefGetMaxRouteLayer(); return TCL_ERROR; } Num_layers = value; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "passes" */ /* */ /* Set the maximum number of attempted passes of the */ /* route search algorithm, where the routing */ /* constraints (maximum cost and route area mask) are */ /* relaxed on each pass. */ /* With no argument, return the value for the maximum */ /* number of passes. */ /* The default number of passes is 10 and normally */ /* there is no reason for the user to change it. */ /* */ /* Options: */ /* */ /* passes [] */ /*------------------------------------------------------*/ static int qrouter_passes(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Numpasses)); } else if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value <= 0) { Tcl_SetResult(interp, "Number of passes out of range", NULL); return TCL_ERROR; } Numpasses = value; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "vdd" */ /* */ /* Set the name of the net used for VDD power routing */ /* With no argument, return the name of the power */ /* net. */ /* */ /* Options: */ /* */ /* vdd [] */ /*------------------------------------------------------*/ static int qrouter_vdd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if (objc == 1) { if (vddnet == NULL) Tcl_SetObjResult(interp, Tcl_NewStringObj("(none)", -1)); else Tcl_SetObjResult(interp, Tcl_NewStringObj(vddnet, -1)); } else if (objc == 2) { if (vddnet != NULL) free(vddnet); vddnet = strdup(Tcl_GetString(objv[1])); } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "gnd" */ /* */ /* Set the name of the net used for ground routing. */ /* With no argument, return the name of the ground */ /* net. */ /* */ /* Options: */ /* */ /* gnd [] */ /*------------------------------------------------------*/ static int qrouter_gnd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if (objc == 1) { if (gndnet == NULL) Tcl_SetObjResult(interp, Tcl_NewStringObj("(none)", -1)); else Tcl_SetObjResult(interp, Tcl_NewStringObj(gndnet, -1)); } else if (objc == 2) { if (gndnet != NULL) free(gndnet); gndnet = strdup(Tcl_GetString(objv[1])); } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "cost" */ /* */ /* Query or set the value of a cost function */ /* */ /* Options: */ /* */ /* cost segment */ /* cost via */ /* cost jog */ /* cost crossover */ /* cost block */ /* cost offset */ /* cost conflict */ /*------------------------------------------------------*/ static int qrouter_cost(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int idx, result, value; static char *subCmds[] = { "segment", "via", "jog", "crossover", "block", "offset", "conflict", NULL }; enum SubIdx { SegIdx, ViaIdx, JogIdx, XOverIdx, BlockIdx, OffsetIdx, ConflictIdx }; value = 0; if (objc == 3) { result = Tcl_GetIntFromObj(interp, objv[2], &value); if (result != TCL_OK) return result; // Disallow negative costs. if (value < 0) { Tcl_SetResult(interp, "Bad cost value", NULL); return TCL_ERROR; } } else if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case SegIdx: case ViaIdx: case ConflictIdx: // Segment, via, and conflict costs must not be zero or // bad things happen. if (value <= 0) { Tcl_SetResult(interp, "Bad cost value", NULL); return TCL_ERROR; } } switch (idx) { case SegIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(SegCost)); else SegCost = value; break; case ViaIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(ViaCost)); else ViaCost = value; break; case JogIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(JogCost)); else JogCost = value; break; case XOverIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(XverCost)); else XverCost = value; break; case OffsetIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(OffsetCost)); else OffsetCost = value; break; case BlockIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(BlockCost)); else BlockCost = value; break; case ConflictIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(ConflictCost)); else ConflictCost = value; break; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ typedef struct clist_ *CLIST; typedef struct clist_ { GATE gate; double congestion; } Clist; /*------------------------------------------------------*/ /* Compare function for qsort() */ /*------------------------------------------------------*/ int compcong(CLIST *a, CLIST *b) { CLIST p = *a; CLIST q = *b; if (p->congestion < q->congestion) return (1); else if (p->congestion > q->congestion) return (-1); else return (0); } /*------------------------------------------------------*/ /* Command "congested" */ /* */ /* Return a list of instances, ranked by congestion. */ /* This list can be passed back to a placement tool to */ /* direct it to add padding around these cells to ease */ /* congestion and make the layout more routable. */ /* */ /* Options: */ /* */ /* congested List the top congested */ /* gates in the design. */ /*------------------------------------------------------*/ static int qrouter_congested(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { NET net; int i, x, y, nwidth, nheight, area, length; int entries, numgates, result; float density, *Congestion; CLIST *cgates, csrch; GATE gsrch; struct seg_ bbox; double dx, dy, cavg; Tcl_Obj *lobj, *dobj; if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &entries); if (result != TCL_OK) return result; if (entries <= 0) { Tcl_SetResult(interp, "List size must be > 0", NULL); return TCL_ERROR; } } else entries = 0; Congestion = (float *)calloc(NumChannelsX * NumChannelsY, sizeof(float)); // Use net bounding boxes to estimate congestion for (i = 0; i < Numnets; i++) { net = Nlnets[i]; nwidth = (net->xmax - net->xmin + 1); nheight = (net->ymax - net->ymin + 1); area = nwidth * nheight; if (nwidth > nheight) { length = nwidth + (nheight >> 1) * net->numnodes; } else { length = nheight + (nwidth >> 1) * net->numnodes; } density = (float)length / (float)area; for (x = net->xmin; x < net->xmax; x++) for (y = net->ymin; y < net->ymax; y++) if (x >= 0 && x < NumChannelsX && y >= 0 && y < NumChannelsY) CONGEST(x, y) += density; } // Use instance bounding boxes to estimate average congestion // in the area of an instance. numgates = 0; for (gsrch = Nlgates; gsrch; gsrch = gsrch->next) numgates++; cgates = (CLIST *)malloc(numgates * sizeof(CLIST)); i = 0; for (gsrch = Nlgates; gsrch; gsrch = gsrch->next) { // Ignore pins, as the point of congestion planning // is to add padding to the core instances; including // pins just makes it harder for the placement script // to process the information. if (gsrch->gatetype == PinMacro) continue; cgates[i] = (CLIST)malloc(sizeof(Clist)); dx = gsrch->placedX; dy = gsrch->placedY; bbox.x1 = (int)((dx - Xlowerbound) / PitchX) - 1; bbox.y1 = (int)((dy - Ylowerbound) / PitchY) - 1; dx = gsrch->placedX + gsrch->width; dy = gsrch->placedY + gsrch->height; bbox.x2 = (int)((dx - Xlowerbound) / PitchX) - 1; bbox.y2 = (int)((dy - Ylowerbound) / PitchY) - 1; cavg = 0.0; for (x = bbox.x1; x <= bbox.x2; x++) { for (y = bbox.y1; y <= bbox.y2; y++) { cavg += CONGEST(x, y); } } cavg /= (bbox.x2 - bbox.x1 + 1); cavg /= (bbox.y2 - bbox.y1 + 1); cgates[i]->gate = gsrch; cgates[i++]->congestion = cavg / Num_layers; } // Re-set "numgates", because we have rejected pins from the // original count. numgates = i; // Order Clist and copy contents back to the interpreter as a list qsort((char *)cgates, numgates, (int)sizeof(CLIST), (__compar_fn_t)compcong); lobj = Tcl_NewListObj(0, NULL); if (entries == 0) entries = numgates; else if (entries > numgates) entries = numgates; for (i = 0; i < entries; i++) { csrch = cgates[i]; gsrch = csrch->gate; dobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, dobj, Tcl_NewStringObj(gsrch->gatename, -1)); Tcl_ListObjAppendElement(interp, dobj, Tcl_NewDoubleObj(csrch->congestion)); Tcl_ListObjAppendElement(interp, lobj, dobj); } Tcl_SetObjResult(interp, lobj); // Cleanup free(Congestion); for (i = 0; i < numgates; i++) free(cgates[i]); free(cgates); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "print" */ /* */ /* print an object */ /* */ /* Options: */ /* */ /* print net */ /* print netnr */ /* print gate */ /*------------------------------------------------------*/ static int qrouter_print(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int idx, result, value; NET net; GATE gate; static char *subCmds[] = { "net", "netnr", "gate", NULL }; enum SubIdx { NetIdx, NetNrIdx, GateIdx }; value = 0; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case NetIdx: net = DefFindNet(Tcl_GetString(objv[2])); if (net == NULL) { Tcl_SetResult(interp, "Net not found", NULL); return TCL_ERROR; } print_net(net); break; case NetNrIdx: result = Tcl_GetIntFromObj(interp, objv[2], &value); if (result != TCL_OK) return result; net = LookupNetNr(value); if (net == NULL) { Tcl_SetResult(interp, "Net not found", NULL); return TCL_ERROR; } print_net(net); break; case GateIdx: gate = DefFindGate(Tcl_GetString(objv[2])); if (gate == NULL) { Tcl_SetResult(interp, "Gate not found", NULL); return TCL_ERROR; } print_gate(gate); } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "pitchx" */ /* */ /* Set the base pitch for vertical routing layers. */ /* Values larger than current value will be ignored. */ /* Without an argument, current value is returned. */ /* */ /* Options: */ /* */ /* pitchx [] */ /*------------------------------------------------------*/ static int qrouter_pitchx(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result; double value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewDoubleObj(PitchX)); } else if (objc == 2) { result = Tcl_GetDoubleFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value <= 0.0) { Tcl_SetResult(interp, "PitchX value has to be a positive value" "; ignored", NULL); return TCL_ERROR; } else if ((PitchX > 0.0) && (value > PitchX)) { Tcl_SetResult(interp, "PitchX is larger than current value" "; ignored", NULL); } else { PitchX = value; } } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "pitchy" */ /* */ /* Set the base pitch for horizontal routing layers. */ /* Values larger than current value will be ignored. */ /* Without an argument, current value is returned. */ /* */ /* Options: */ /* */ /* pitchy [] */ /*------------------------------------------------------*/ static int qrouter_pitchy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result; double value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewDoubleObj(PitchY)); } else if (objc == 2) { result = Tcl_GetDoubleFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value <= 0.0) { Tcl_SetResult(interp, "PitchY value has to be a positive value" "; ignored", NULL); return TCL_ERROR; } else if ((PitchY > 0.0) && (value > PitchY)) { Tcl_SetResult(interp, "PitchY is larger than current value" "; ignored", NULL); } else { PitchY = value; } } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "unblock" */ /* */ /* Set the unblocking flag, which indicates to qrouter */ /* that all grid points that lie cleanly inside pin */ /* geometry should be marked routable. This command */ /* must be issued before read_def to be effective. */ /* */ /* Options: */ /* */ /* unblock [true|false] */ /*------------------------------------------------------*/ static int qrouter_unblock(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(unblockAll)); } else if (objc == 2) { result = Tcl_GetBooleanFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; unblockAll = (value == 0) ? FALSE : TRUE; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ qrouter-1.4.88/console.tcl0000644000175000017510000000065713625043307015025 0ustar nileshnilesh# Tcl commands to run in the console before qrouter is initialized slave alias qrouter::consoledown wm withdraw . slave alias qrouter::consoleup wm deiconify . slave alias qrouter::consoleontop raise . # NOTE: This is not recommended for qrouter, where everything runs # off of the console. If the console is closed, then the program # should exit. # # wm protocol . WM_DELETE_WINDOW {tkcon slave slave qrouter::lowerconsole} qrouter-1.4.88/tkSimple.c0000644000175000017510000003272213625043307014611 0ustar nileshnilesh/* *----------------------------------------------------------------------- * tkSimple.c -- * * Implementation of a Very simple window which relies on C code for * almost all of its event handlers. * *----------------------------------------------------------------------- */ #include #include #include #include #include "graphics.h" /* Backwards compatibility to tk8.3 and earlier */ #if TK_MAJOR_VERSION == 8 #if TK_MINOR_VERSION <= 3 #define Tk_SetClassProcs(a,b,c) TkSetClassProcs(a,b,c) #endif #endif #ifndef CONST84 #define CONST84 #endif /* * A data structure of the following type is kept for each * simple that currently exists for this process: */ typedef struct { Tk_Window tkwin; /* Window that embodies the simple. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up. */ Display *display; /* Display containing widget. Used, among * other things, so that resources can be * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. Used * to delete widget command. */ Tcl_Command widgetCmd; /* Token for simple's widget command. */ char *className; /* Class name for widget (from configuration * option). Malloc-ed. */ int width; /* Width to request for window. <= 0 means * don't request any size. */ int height; /* Height to request for window. <= 0 means * don't request any size. */ char *exitProc; /* Callback procedure upon window deletion. */ char *mydata; /* This space for hire. */ int flags; /* Various flags; see below for * definitions. */ } Simple; /* * Flag bits for simples: * * GOT_FOCUS: non-zero means this widget currently has the input focus. */ #define GOT_FOCUS 1 static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_PIXELS, "-height", "height", "Height", "0", Tk_Offset(Simple, height), 0}, {TK_CONFIG_PIXELS, "-width", "width", "Width", "0", Tk_Offset(Simple, width), 0}, {TK_CONFIG_STRING, "-exitproc", "exitproc", "ExitProc", "", Tk_Offset(Simple, exitProc), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-data", "data", "Data", "", Tk_Offset(Simple, mydata), TK_CONFIG_NULL_OK}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; /* * Forward declarations for procedures defined later in this file: */ static int ConfigureSimple _ANSI_ARGS_((Tcl_Interp *interp, Simple *simplePtr, int objc, Tcl_Obj *CONST objv[], int flags)); static void DestroySimple _ANSI_ARGS_((char *memPtr)); static void SimpleCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void SimpleEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int SimpleWidgetObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); /* *-------------------------------------------------------------- * * Tk_SimpleObjCmd -- * * This procedure is invoked to process the "simple" * Tcl command. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. These procedures are just wrappers; * they call ButtonCreate to do all of the real work. * *-------------------------------------------------------------- */ int Tk_SimpleObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tk_Window tkwin = (Tk_Window) clientData; Simple *simplePtr; Tk_Window new = NULL; char *arg; int i, c; size_t length; unsigned int mask; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } /* * Pre-process the argument list. Scan through it to find * "-main" option. If the "-main" option is selected, then * the application will exit if this window is deleted. */ for (i = 2; i < objc; i += 2) { arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } c = arg[1]; /* No arguments parsed */ } /* * Create the window */ if (tkwin != NULL) { new = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(objv[1]), NULL); } if (new == NULL) { goto error; } Tk_SetClass(new, "Simple"); /* * Create the widget record, process configuration options, and * create event handlers. Then fill in a few additional fields * in the widget record from the special options. */ simplePtr = (Simple *) ckalloc(sizeof(Simple)); simplePtr->tkwin = new; simplePtr->display = Tk_Display(new); simplePtr->interp = interp; simplePtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(new), SimpleWidgetObjCmd, (ClientData) simplePtr, SimpleCmdDeletedProc); simplePtr->className = NULL; simplePtr->width = 0; simplePtr->height = 0; simplePtr->exitProc = NULL; simplePtr->flags = 0; simplePtr->mydata = NULL; /* * Store backreference to simple widget in window structure. */ Tk_SetClassProcs(new, NULL, (ClientData) simplePtr); /* We only handle focus and structure events, and even that might change. */ mask = StructureNotifyMask|FocusChangeMask|NoEventMask; Tk_CreateEventHandler(new, mask, SimpleEventProc, (ClientData) simplePtr); if (ConfigureSimple(interp, simplePtr, objc-2, objv+2, 0) != TCL_OK) { goto error; } Tcl_SetResult(interp, Tk_PathName(new), TCL_STATIC); return TCL_OK; error: if (new != NULL) { Tk_DestroyWindow(new); } return TCL_ERROR; } /* *-------------------------------------------------------------- * * SimpleWidgetObjCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a simple widget. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int SimpleWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about simple widget. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { static char *simpleOptions[] = { "cget", "configure", (char *) NULL }; enum options { SIMPLE_CGET, SIMPLE_CONFIGURE }; register Simple *simplePtr = (Simple *) clientData; int result = TCL_OK, index; size_t length; int c, i; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)simpleOptions, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve((ClientData) simplePtr); switch ((enum options) index) { case SIMPLE_CGET: { if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "option"); result = TCL_ERROR; goto done; } result = Tk_ConfigureValue(interp, simplePtr->tkwin, configSpecs, (char *) simplePtr, Tcl_GetString(objv[2]), 0); break; } case SIMPLE_CONFIGURE: { if (objc == 2) { result = Tk_ConfigureInfo(interp, simplePtr->tkwin, configSpecs, (char *) simplePtr, (char *) NULL, 0); } else if (objc == 3) { result = Tk_ConfigureInfo(interp, simplePtr->tkwin, configSpecs, (char *) simplePtr, Tcl_GetString(objv[2]), 0); } else { for (i = 2; i < objc; i++) { char *arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } c = arg[1]; /* No options parsed */ } result = ConfigureSimple(interp, simplePtr, objc-2, objv+2, TK_CONFIG_ARGV_ONLY); } break; } } done: Tcl_Release((ClientData) simplePtr); return result; } /* *---------------------------------------------------------------------- * * DestroySimple -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a simple at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the simple is freed up. * *---------------------------------------------------------------------- */ static void DestroySimple(memPtr) char *memPtr; /* Info about simple widget. */ { register Simple *simplePtr = (Simple *) memPtr; Tk_FreeOptions(configSpecs, (char *) simplePtr, simplePtr->display, TK_CONFIG_USER_BIT); if (simplePtr->exitProc != NULL) { /* Call the exit procedure */ Tcl_EvalEx(simplePtr->interp, simplePtr->exitProc, -1, 0); } ckfree((char *) simplePtr); } /* *---------------------------------------------------------------------- * * ConfigureSimple -- * * This procedure is called to process an objv/objc list, plus * the Tk option database, in order to configure (or * reconfigure) a simple widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for simplePtr; old resources get freed, if there * were any. * *---------------------------------------------------------------------- */ static int ConfigureSimple(interp, simplePtr, objc, objv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Simple *simplePtr; /* Information about widget; may or may * not already have values for some fields. */ int objc; /* Number of valid entries in objv. */ Tcl_Obj *CONST objv[]; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { if (Tk_ConfigureWidget(interp, simplePtr->tkwin, configSpecs, objc, (CONST84 char **) objv, (char *) simplePtr, flags | TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } if ((simplePtr->width > 0) || (simplePtr->height > 0)) { Tk_GeometryRequest(simplePtr->tkwin, simplePtr->width, simplePtr->height); resize(simplePtr->tkwin, simplePtr->width, simplePtr->height); } return TCL_OK; } /* *-------------------------------------------------------------- * * SimpleEventProc -- * * This procedure is invoked by the Tk dispatcher on * structure changes to a simple. For simples with 3D * borders, this procedure is also invoked for exposures. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void SimpleEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ register XEvent *eventPtr; /* Information about event. */ { register Simple *simplePtr = (Simple *) clientData; if (eventPtr->type == DestroyNotify) { if (simplePtr->tkwin != NULL) { /* * If this window is a container, then this event could be * coming from the embedded application, in which case * Tk_DestroyWindow hasn't been called yet. When Tk_DestroyWindow * is called later, then another destroy event will be generated. * We need to be sure we ignore the second event, since the simple * could be gone by then. To do so, delete the event handler * explicitly (normally it's done implicitly by Tk_DestroyWindow). */ Tk_DeleteEventHandler(simplePtr->tkwin, StructureNotifyMask | FocusChangeMask, SimpleEventProc, (ClientData) simplePtr); simplePtr->tkwin = NULL; Tcl_DeleteCommandFromToken(simplePtr->interp, simplePtr->widgetCmd); } Tcl_EventuallyFree((ClientData) simplePtr, DestroySimple); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { simplePtr->flags |= GOT_FOCUS; } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { simplePtr->flags &= ~GOT_FOCUS; } } else if (eventPtr->type == ConfigureNotify) { XConfigureEvent *configEventPtr = (XConfigureEvent *)eventPtr; simplePtr->width = configEventPtr->width; simplePtr->height = configEventPtr->height; resize(simplePtr->tkwin, simplePtr->width, simplePtr->height); } else if (eventPtr->type == MapNotify || eventPtr->type == UnmapNotify) { expose(simplePtr->tkwin); } else { fprintf(stderr, "Warning: Event type %d not handled!\n", eventPtr->type); } return; } /* *---------------------------------------------------------------------- * * SimpleCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void SimpleCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Simple *simplePtr = (Simple *) clientData; Tk_Window tkwin = simplePtr->tkwin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { simplePtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } qrouter-1.4.88/graphics.h0000644000175000017510000000153413625043307014623 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* graphics.h -- graphics routines */ /*--------------------------------------------------------------*/ #ifndef GRAPHICS_H #include /* TODO: Can we make this include independent from qrouter.h ? */ #include "qrouter.h" void highlight(int, int); void highlight_source(void); void highlight_dest(void); void highlight_starts(POINT glist); void highlight_mask(void); void draw_net(NET net, u_char single, int *lastlayer); void draw_layout(void); int GUI_init(Tcl_Interp *interp); void expose(Tk_Window tkwind); int redraw(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int recalc_spacing(void); void resize(Tk_Window tkwind, int locwidth, int locheight); #define GRAPHICS_H #endif qrouter-1.4.88/qrouterexec.c0000644000175000017510000000275313625043307015370 0ustar nileshnilesh/*----------------------------------------------------------------------*/ /* qrouterexec.c */ /*----------------------------------------------------------------------*/ #include #include #include /*----------------------------------------------------------------------*/ /* Application initiation. This is exactly like the AppInit routine */ /* for "wish", minus the cruft, but with "tcl_rcFileName" set to */ /* "qrouter.tcl" instead of "~/.wishrc". */ /*----------------------------------------------------------------------*/ int qrouter_AppInit(interp) Tcl_Interp *interp; { if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } // Ignore Tk_Init return code---maybe can attempt to run in // a non-graphics mode. if (Tk_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); /* This is where we replace the home ".wishrc" file with */ /* qrouter's startup script. */ Tcl_SetVar(interp, "tcl_rcFileName", QROUTER_PATH "/qrouter.tcl", TCL_GLOBAL_ONLY); return TCL_OK; } /*----------------------------------------------------------------------*/ /* The main procedure; replacement for "wish". */ /*----------------------------------------------------------------------*/ int main(argc, argv) int argc; char **argv; { Tk_Main(argc, argv, qrouter_AppInit); return 0; } /*----------------------------------------------------------------------*/ qrouter-1.4.88/graphics.c0000644000175000017510000005264513625043307014627 0ustar nileshnilesh/*------------------------------------------------------*/ /* Graphics routines for qrouter */ /*------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include "qrouter.h" #include "qconfig.h" #include "node.h" #include "maze.h" #include "lef.h" /*------------------------------*/ /* Type declarations */ /*------------------------------*/ static void load_font(XFontStruct **); static void createGC(Window, GC *, XFontStruct *); /*----------------------------------*/ /* Global variables for X11 drawing */ /*----------------------------------*/ XFontStruct *font_info; Pixmap buffer = (Pixmap)0; Display *dpy = NULL; Window win; Colormap cmap; GC gc; Dimension width, height; #define SHORTSPAN 10 #define LONGSPAN 127 int spacing; int bluepix, greenpix, redpix, cyanpix, orangepix, goldpix; int blackpix, whitepix, graypix, ltgraypix, yellowpix; int tealpix, mauvepix, tanpix; int magentapix, purplepix, greenyellowpix; int brownvector[SHORTSPAN]; int bluevector[LONGSPAN]; /*--------------------------------------------------------------*/ /* Highlight a position on the graph. Do this on the actual */ /* screen, not the buffer. */ /*--------------------------------------------------------------*/ void highlight(int x, int y) { int i, xspc, yspc, hspc; PROUTE *Pr; if (dpy == NULL) return; // If Obs2[] at x, y is a source or dest, don't highlight // Do this only for layer 0; it doesn't have to be rigorous. for (i = 0; i < Num_layers; i++) { Pr = &OBS2VAL(x, y, i); if (Pr->flags & (PR_SOURCE | PR_TARGET)) return; } hspc = spacing >> 1; if (hspc == 0) hspc = 1; xspc = (x + 1) * spacing - hspc; yspc = height - (y + 1) * spacing - hspc; XSetForeground(dpy, gc, yellowpix); XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing); XFlush(dpy); } /*--------------------------------------*/ /* Highlight source (in magenta) */ /*--------------------------------------*/ void highlight_source() { int xspc, yspc, hspc; int i, x, y; PROUTE *Pr; if (dpy == NULL) return; if (Obs2[0] == NULL) return; // Determine the number of routes per width and height, if // it has not yet been computed hspc = spacing >> 1; if (hspc == 0) hspc = 1; // Draw source pins as magenta squares XSetForeground(dpy, gc, magentapix); for (i = 0; i < Num_layers; i++) { for (x = 0; x < NumChannelsX; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY; y++) { Pr = &OBS2VAL(x, y, i); if (Pr->flags & PR_SOURCE) { yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing); } } } } XFlush(dpy); } /*--------------------------------------*/ /* Highlight destination (in purple) */ /*--------------------------------------*/ void highlight_dest() { int xspc, yspc, hspc, dspc; int i, x, y; PROUTE *Pr; if (dpy == NULL) return; if (Obs2[0] == NULL) return; // Determine the number of routes per width and height, if // it has not yet been computed dspc = spacing + 4; // Make target more visible hspc = dspc >> 1; // Draw destination pins as purple squares XSetForeground(dpy, gc, purplepix); for (i = 0; i < Num_layers; i++) { for (x = 0; x < NumChannelsX; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY; y++) { Pr = &OBS2VAL(x, y, i); if (Pr->flags & PR_TARGET) { yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, win, gc, xspc, yspc, dspc, dspc); } } } } XFlush(dpy); } /*----------------------------------------------*/ /* Highlight all the search starting points */ /*----------------------------------------------*/ void highlight_starts(POINT glist) { int xspc, yspc, hspc; POINT gpoint; if (dpy == NULL) return; // Determine the number of routes per width and height, if // it has not yet been computed hspc = spacing >> 1; XSetForeground(dpy, gc, greenyellowpix); for (gpoint = glist; gpoint; gpoint = gpoint->next) { xspc = (gpoint->x1 + 1) * spacing - hspc; yspc = height - (gpoint->y1 + 1) * spacing - hspc; XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing); } XFlush(dpy); } /*--------------------------------------*/ /* Highlight mask (in tan) */ /*--------------------------------------*/ void highlight_mask(void) { int xspc, yspc, hspc; int x, y; if (RMask == NULL) return; // Determine the number of routes per width and height, if // it has not yet been computed if (dpy == NULL) return; hspc = spacing >> 1; // Draw destination pins as tan squares for (x = 0; x < NumChannelsX; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY; y++) { XSetForeground(dpy, gc, brownvector[RMASK(x, y)]); yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing); } } XFlush(dpy); } /*----------------------------------------------*/ /* Draw a map of obstructions and pins */ /*----------------------------------------------*/ static void map_obstruction() { int xspc, yspc, hspc; int i, x, y; if (dpy == NULL) return; hspc = spacing >> 1; // Draw obstructions as light gray squares XSetForeground(dpy, gc, ltgraypix); for (i = 0; i < Num_layers; i++) { for (x = 0; x < NumChannelsX; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY; y++) { if (OBSVAL(x, y, i) & NO_NET) { yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing); } } } } // Draw pins as gray squares XSetForeground(dpy, gc, graypix); for (i = 0; i < Pinlayers; i++) { for (x = 0; x < NumChannelsX; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY; y++) { if (NODEIPTR(x, y, i) != NULL) { yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing); } } } } } /*----------------------------------------------*/ /* Draw a map of actual route congestion */ /*----------------------------------------------*/ static void map_congestion() { int xspc, yspc, hspc; int i, x, y, n, norm; u_char *Congestion; u_char value, maxval; if (dpy == NULL) return; hspc = spacing >> 1; Congestion = (u_char *)calloc(NumChannelsX * NumChannelsY, sizeof(u_char)); // Analyze Obs[] array for congestion for (i = 0; i < Num_layers; i++) { for (x = 0; x < NumChannelsX; x++) { for (y = 0; y < NumChannelsY; y++) { value = (u_char)0; n = OBSVAL(x, y, i); if (n & ROUTED_NET) value++; if (n & BLOCKED_MASK) value++; if (n & NO_NET) value++; if (n & PINOBSTRUCTMASK) value++; CONGEST(x, y) += value; } } } maxval = 0; for (x = 0; x < NumChannelsX; x++) { for (y = 0; y < NumChannelsY; y++) { value = CONGEST(x, y); if (value > maxval) maxval = value; } } norm = (LONGSPAN - 1) / maxval; // Draw destination pins as blue squares for (x = 0; x < NumChannelsX; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY; y++) { XSetForeground(dpy, gc, bluevector[norm * CONGEST(x, y)]); yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing); } } // Cleanup free(Congestion); } /*----------------------------------------------------------------------*/ /* Draw a map of route congestion estimated from net bounding boxes */ /*----------------------------------------------------------------------*/ static void map_estimate() { NET net; int xspc, yspc, hspc; int i, x, y, nwidth, nheight, area, length, value; float density, *Congestion, norm, maxval; if (dpy == NULL) return; hspc = spacing >> 1; Congestion = (float *)calloc(NumChannelsX * NumChannelsY, sizeof(float)); // Use net bounding boxes to estimate congestion for (i = 0; i < Numnets; i++) { net = Nlnets[i]; nwidth = (net->xmax - net->xmin + 1); nheight = (net->ymax - net->ymin + 1); area = nwidth * nheight; if (nwidth > nheight) { length = nwidth + (nheight >> 1) * net->numnodes; } else { length = nheight + (nwidth >> 1) * net->numnodes; } density = (float)length / (float)area; for (x = net->xmin; x < net->xmax; x++) for (y = net->ymin; y < net->ymax; y++) CONGEST(x, y) += density; } maxval = 0.0; for (x = 0; x < NumChannelsX; x++) { for (y = 0; y < NumChannelsY; y++) { density = CONGEST(x, y); if (density > maxval) maxval = density; } } norm = (float)(LONGSPAN - 1) / maxval; // Draw destination pins as blue squares for (x = 0; x < NumChannelsX; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY; y++) { value = (int)(norm * CONGEST(x, y)); XSetForeground(dpy, gc, bluevector[value]); yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing); } } // Cleanup free(Congestion); } /*--------------------------------------*/ /* Draw one net on the display */ /*--------------------------------------*/ void draw_net(NET net, u_char single, int *lastlayer) { int layer; SEG seg; ROUTE rt; if (dpy == NULL) return; // Draw all nets, much like "emit_routes" does when writing // routes to the DEF file. rt = net->routes; if (single && rt) for (rt = net->routes; rt->next; rt = rt->next); for (; rt; rt = rt->next) { for (seg = rt->segments; seg; seg = seg->next) { layer = seg->layer; if (layer != *lastlayer) { *lastlayer = layer; switch(layer) { case 0: XSetForeground(dpy, gc, bluepix); break; case 1: XSetForeground(dpy, gc, redpix); break; case 2: XSetForeground(dpy, gc, cyanpix); break; case 3: XSetForeground(dpy, gc, goldpix); break; case 4: XSetForeground(dpy, gc, orangepix); break; case 5: XSetForeground(dpy, gc, tealpix); break; case 6: XSetForeground(dpy, gc, mauvepix); break; case 7: XSetForeground(dpy, gc, tanpix); break; default: XSetForeground(dpy, gc, greenpix); break; } } XDrawLine(dpy, buffer, gc, spacing * (seg->x1 + 1), height - spacing * (seg->y1 + 1), spacing * (seg->x2 + 1), height - spacing * (seg->y2 + 1)); if (single) XDrawLine(dpy, win, gc, spacing * (seg->x1 + 1), height - spacing * (seg->y1 + 1), spacing * (seg->x2 + 1), height - spacing * (seg->y2 + 1)); } } if (single) { // The following line to be removed XCopyArea(dpy, buffer, win, gc, 0, 0, width, height, 0, 0); XFlush(dpy); } } /*--------------------------------------*/ /* Draw one unrouted net on the display */ /*--------------------------------------*/ static void draw_net_nodes(NET net) { NODE node; SEG bboxlist = NULL; /* bbox list of all the nodes in the net */ SEG lastbbox, bboxit; DPOINT tap; int first, w, h, n; if (dpy == NULL) return; /* Compute bbox for each node and draw it */ for (node = net->netnodes, n = 0; node != NULL; node = node->next, n++) { if (bboxlist == NULL) { lastbbox = bboxlist = (SEG)malloc(sizeof(struct seg_)); } else { lastbbox->next = (SEG)malloc(sizeof(struct seg_)); lastbbox = lastbbox->next; } lastbbox->next = NULL; for (tap = node->taps, first = TRUE; tap != NULL; tap = tap->next, first = FALSE) { if (first) { lastbbox->x1 = lastbbox->x2 = tap->gridx; lastbbox->y1 = lastbbox->y2 = tap->gridy; } else { lastbbox->x1 = MIN(lastbbox->x1, tap->gridx); lastbbox->x2 = MAX(lastbbox->x2, tap->gridx); lastbbox->y1 = MIN(lastbbox->y1, tap->gridy); lastbbox->y2 = MAX(lastbbox->y2, tap->gridy); } } /* Convert to X coordinates */ lastbbox->x1 = spacing * (lastbbox->x1 + 1); lastbbox->y1 = height - spacing * (lastbbox->y1 + 1); lastbbox->x2 = spacing * (lastbbox->x2 + 1); lastbbox->y2 = height - spacing * (lastbbox->y2 + 1); /* Draw the bbox */ w = lastbbox->x2 - lastbbox->x1; h = lastbbox->y1 - lastbbox->y2; XDrawRectangle(dpy, buffer, gc, lastbbox->x1, lastbbox->y1, w, h ); } /* if net->numnodes == 1 don't draw a wire */ if (n == 2) { XDrawLine( dpy, buffer, gc, (bboxlist->x1 + bboxlist->x2)/2, (bboxlist->y1 + bboxlist->y2)/2, (lastbbox->x1 + lastbbox->x2)/2, (lastbbox->y1 + lastbbox->y2)/2 ); } else if (n > 2) { /* Compute center point */ POINT midpoint = (POINT)malloc(sizeof(struct point_)); midpoint->x1 = midpoint->y1 = 0; for (bboxit = bboxlist; bboxit != NULL; bboxit = bboxit->next) { midpoint->x1 += (bboxit->x1 + bboxit->x2)/2; midpoint->y1 += (bboxit->y1 + bboxit->y2)/2; } midpoint->x1 /= n; midpoint->y1 /= n; for (bboxit = bboxlist; bboxit != NULL; bboxit = bboxit->next) { XDrawLine( dpy, buffer, gc, midpoint->x1, midpoint->y1, (bboxit->x1 + bboxit->x2)/2, (bboxit->y1 + bboxit->y2)/2 ); } free(midpoint); } for (bboxit = bboxlist; bboxit != NULL; bboxit = lastbbox) { lastbbox = bboxit->next; free(bboxit); } } /*--------------------------------------*/ /* Graphical display of the layout */ /*--------------------------------------*/ void draw_layout() { int lastlayer; int i; NET net; if (dpy == NULL) return; else if (buffer == (Pixmap)NULL) return; XSetForeground(dpy, gc, whitepix); XFillRectangle(dpy, buffer, gc, 0, 0, width, height); // Check if a netlist even exists if (Obs[0] == NULL) { XCopyArea(dpy, buffer, win, gc, 0, 0, width, height, 0, 0); return; } switch (mapType & MAP_MASK) { case MAP_OBSTRUCT: map_obstruction(); break; case MAP_CONGEST: map_congestion(); break; case MAP_ESTIMATE: map_estimate(); break; } // Draw all nets, much like "emit_routes" does when writing // routes to the DEF file. if ((mapType & DRAW_ROUTES) != 0) { lastlayer = -1; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; draw_net(net, FALSE, &lastlayer); } } // Draw unrouted nets if ((mapType & DRAW_UNROUTED) != 0) { XSetForeground(dpy, gc, blackpix); for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (strcmp(net->netname, gndnet) != 0 && strcmp(net->netname, vddnet) != 0 &&net->routes == NULL) { draw_net_nodes(net); } } } /* Copy double-buffer onto display window */ XCopyArea(dpy, buffer, win, gc, 0, 0, width, height, 0, 0); } /*--------------------------------------*/ /* GUI initialization */ /*--------------------------------------*/ int GUI_init(Tcl_Interp *interp) { Tk_Window tkwind, tktop; static char *qrouterdrawdefault = ".qrouter"; char *qrouterdrawwin, *waitcmd; XColor cvcolor, cvexact; int i; float frac; tktop = Tk_MainWindow(interp); if (tktop == NULL) { tcl_printf(stderr, "No Top-level Tk window available. . .\n"); return TCL_ERROR; } qrouterdrawwin = (char *)Tcl_GetVar(interp, "drawwindow", TCL_GLOBAL_ONLY); if (qrouterdrawwin == NULL) qrouterdrawwin = qrouterdrawdefault; tkwind = Tk_NameToWindow(interp, qrouterdrawwin, tktop); if (tkwind == NULL) { tcl_printf(stderr, "The Tk window hierarchy must be rooted at " ".qrouter or $drawwindow must point to the drawing window\n"); return TCL_ERROR; } Tk_MapWindow(tkwind); dpy = Tk_Display(tkwind); win = Tk_WindowId(tkwind); cmap = DefaultColormap (dpy, Tk_ScreenNumber(tkwind)); load_font(&font_info); /* create GC for text and drawing */ createGC(win, &gc, font_info); /* Initialize colors */ XAllocNamedColor(dpy, cmap, "blue", &cvcolor, &cvexact); bluepix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "cyan", &cvcolor, &cvexact); cyanpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "green", &cvcolor, &cvexact); greenpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "red", &cvcolor, &cvexact); redpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "orange", &cvcolor, &cvexact); orangepix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "gold", &cvcolor, &cvexact); goldpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "gray70", &cvcolor, &cvexact); ltgraypix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "gray50", &cvcolor, &cvexact); graypix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "yellow", &cvcolor, &cvexact); yellowpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "purple", &cvcolor, &cvexact); purplepix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "magenta", &cvcolor, &cvexact); magentapix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "GreenYellow", &cvcolor, &cvexact); greenyellowpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "teal", &cvcolor, &cvexact); tealpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "MediumVioletRed", &cvcolor, &cvexact); mauvepix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "tan1", &cvcolor, &cvexact); tanpix = cvcolor.pixel; blackpix = BlackPixel(dpy,DefaultScreen(dpy)); whitepix = WhitePixel(dpy,DefaultScreen(dpy)); cvcolor.flags = DoRed | DoGreen | DoBlue; for (i = 0; i < SHORTSPAN; i++) { frac = (float)i / (float)(SHORTSPAN - 1); /* gamma correction */ frac = pow(frac, 0.5); cvcolor.green = (int)(53970 * frac); cvcolor.blue = (int)(46260 * frac); cvcolor.red = (int)(35980 * frac); XAllocColor(dpy, cmap, &cvcolor); brownvector[i] = cvcolor.pixel; } cvcolor.green = 0; cvcolor.red = 0; for (i = 0; i < LONGSPAN; i++) { frac = (float)i / (float)(LONGSPAN - 1); /* gamma correction */ frac = pow(frac, 0.5); cvcolor.blue = (int)(65535 * frac); XAllocColor(dpy, cmap, &cvcolor); bluevector[i] = cvcolor.pixel; } /* Wait on window to be created */ waitcmd = (char *)malloc(strlen(qrouterdrawwin) + 20); sprintf(waitcmd, "tkwait visibility %s", qrouterdrawwin); Tcl_Eval(interp, waitcmd); free(waitcmd); return TCL_OK; /* proceed to interpreter */ } /*----------------------------------------------------------------*/ static void load_font(XFontStruct **font_info) { char *fontname = "9x15"; /* Load font and get font information structure. */ if ((*font_info = XLoadQueryFont (dpy,fontname)) == NULL) { (void) Fprintf (stderr, "Cannot open 9x15 font\n"); // exit(1); } } /*----------------------------------------------------------------*/ static void createGC(Window win, GC *gc, XFontStruct *font_info) { unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */ XGCValues values; unsigned int line_width = 1; int line_style = LineSolid; int cap_style = CapRound; int join_style = JoinRound; /* Create default Graphics Context */ *gc = XCreateGC(dpy, win, valuemask, &values); /* specify font */ if (font_info != NULL) XSetFont(dpy, *gc, font_info->fid); /* specify black foreground since default window background is * white and default foreground is undefined. */ XSetForeground(dpy, *gc, blackpix); /* set line, fill attributes */ XSetLineAttributes(dpy, *gc, line_width, line_style, cap_style, join_style); XSetFillStyle(dpy, *gc, FillSolid); XSetArcMode(dpy, *gc, ArcPieSlice); } /*----------------------------------------------------------------*/ void expose(Tk_Window tkwind) { if (Tk_WindowId(tkwind) == 0) return; if (dpy == NULL) return; draw_layout(); } /*----------------------------------------------------------------*/ int redraw(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *objv[]) { draw_layout(); return TCL_OK; } /*------------------------------------------------------*/ /* Call to recalculate the spacing if NumChannelsX */ /* or NumChannelsY changes. */ /* */ /* Return 1 if the spacing changed, 0 otherwise. */ /*------------------------------------------------------*/ int recalc_spacing() { int xspc, yspc; int oldspacing = spacing; xspc = width / (NumChannelsX + 1); yspc = height / (NumChannelsY + 1); spacing = (xspc < yspc) ? xspc : yspc; if (spacing == 0) spacing = 1; return (spacing == oldspacing) ? 0 : 1; } /*----------------------------------------------------------------*/ void resize(Tk_Window tkwind, int locwidth, int locheight) { if ((locwidth == 0) || (locheight == 0)) return; if (buffer != (Pixmap)0) XFreePixmap (Tk_Display(tkwind), buffer); if (Tk_WindowId(tkwind) == 0) Tk_MapWindow(tkwind); buffer = XCreatePixmap (Tk_Display(tkwind), Tk_WindowId(tkwind), locwidth, locheight, DefaultDepthOfScreen(Tk_Screen(tkwind))); width = locwidth; height = locheight; recalc_spacing(); if (dpy) draw_layout(); } /*----------------------------------------------------------------*/ qrouter-1.4.88/tkcon.tcl0000755000175000017510000047605113625043307014511 0ustar nileshnilesh#!/bin/sh # \ exec ${QROUTER_WISH:=wish} "$0" ${1+"$@"} # ## tkcon.tcl ## Enhanced Tk Console, part of the VerTcl system ## ## Originally based off Brent Welch's Tcl Shell Widget ## (from "Practical Programming in Tcl and Tk") ## ## Thanks to the following (among many) for early bug reports & code ideas: ## Steven Wahl , Jan Nijtmans ## Crimmins , Wart ## ## Copyright 1995-2001 Jeffrey Hobbs ## Initiated: Thu Aug 17 15:36:47 PDT 1995 ## ## jeff.hobbs@acm.org, jeff@hobbs.org ## ## source standard_disclaimer.tcl ## source bourbon_ware.tcl ## # Proxy support for retrieving the current version of Tkcon. # # Mon Jun 25 12:19:56 2001 - Pat Thoyts # # In your tkcon.cfg or .tkconrc file put your proxy details into the # `proxy' member of the `PRIV' array. e.g.: # # set ::tkcon::PRIV(proxy) wwwproxy:8080 # # If you want to be prompted for proxy authentication details (eg for # an NT proxy server) make the second element of this variable non-nil - eg: # # set ::tkcon::PRIV(proxy) {wwwproxy:8080 1} # # Or you can set the above variable from within tkcon by calling # # tkcon master set ::tkcon:PRIV(proxy) wwwproxy:8080 # if {$tcl_version < 8.0} { return -code error "tkcon requires at least Tcl/Tk8" } else { package require Tk $tcl_version } catch {package require bogus-package-name} foreach pkg [info loaded {}] { set file [lindex $pkg 0] set name [lindex $pkg 1] if {![catch {set version [package require $name]}]} { if {[string match {} [package ifneeded $name $version]]} { package ifneeded $name $version [list load $file $name] } } } catch {unset pkg file name version} # Tk 8.4 makes previously exposed stuff private. # FIX: Update tkcon to not rely on the private Tk code. # if {![llength [info globals tkPriv]]} { ::tk::unsupported::ExposePrivateVariable tkPriv } foreach cmd {SetCursor UpDownLine Transpose ScrollPages} { if {![llength [info commands tkText$cmd]]} { ::tk::unsupported::ExposePrivateCommand tkText$cmd } } # Initialize the ::tkcon namespace # namespace eval ::tkcon { # The OPT variable is an array containing most of the optional # info to configure. COLOR has the color data. variable OPT variable COLOR # PRIV is used for internal data that only tkcon should fiddle with. variable PRIV set PRIV(WWW) [info exists embed_args] } ## ::tkcon::Init - inits tkcon # # Calls: ::tkcon::InitUI # Outputs: errors found in tkcon's resource file ## proc ::tkcon::Init {} { variable OPT variable COLOR variable PRIV global tcl_platform env argc argv tcl_interactive errorInfo if {![info exists argv]} { set argv {} set argc 0 } set tcl_interactive 1 if {[info exists PRIV(name)]} { set title $PRIV(name) } else { MainInit # some main initialization occurs later in this proc, # to go after the UI init set MainInit 1 set title Main } ## ## When setting up all the default values, we always check for ## prior existence. This allows users who embed tkcon to modify ## the initial state before tkcon initializes itself. ## # bg == {} will get bg color from the main toplevel (in InitUI) foreach {key default} { bg {} blink \#FFFF00 cursor \#000000 disabled \#4D4D4D proc \#008800 var \#FFC0D0 prompt \#8F4433 stdin \#000000 stdout \#0000FF stderr \#FF0000 } { if {![info exists COLOR($key)]} { set COLOR($key) $default } } foreach {key default} { autoload {} blinktime 500 blinkrange 1 buffer 512 calcmode 0 cols 80 debugPrompt {(level \#$level) debug [history nextid] > } dead {} expandorder {Pathname Variable Procname} font {} history 48 hoterrors 1 library {} lightbrace 1 lightcmd 1 maineval {} maxmenu 15 nontcl 0 prompt1 {ignore this, it's set below} rows 20 scrollypos right showmenu 1 showmultiple 1 showstatusbar 0 slaveeval {} slaveexit close subhistory 1 gc-delay 60000 gets {congets} usehistory 1 exec slave } { if {![info exists OPT($key)]} { set OPT($key) $default } } foreach {key default} { app {} appname {} apptype slave namesp :: cmd {} cmdbuf {} cmdsave {} event 1 deadapp 0 deadsock 0 debugging 0 displayWin . histid 0 find {} find,case 0 find,reg 0 errorInfo {} showOnStartup 1 slavealias { edit more less tkcon } slaveprocs { alias clear dir dump echo idebug lremove tkcon_puts tkcon_gets observe observe_var unalias which what } version 2.3 RCS {RCS: @(#) $Id: tkcon.tcl,v 1.1.1.1 2011/04/10 21:15:05 tim Exp $} HEADURL {http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/tkcon/tkcon/tkcon.tcl?rev=HEAD} docs "http://tkcon.sourceforge.net/" email {jeff@hobbs.org} root . } { if {![info exists PRIV($key)]} { set PRIV($key) $default } } ## NOTES FOR STAYING IN PRIMARY INTERPRETER: ## ## If you set ::tkcon::OPT(exec) to {}, then instead of a multiple ## interp model, you get tkcon operating in the main interp by default. ## This can be useful when attaching to programs that like to operate ## in the main interpter (for example, based on special wish'es). ## You can set this from the command line with -exec "" ## A side effect is that all tkcon command line args will be used ## by the first console only. #set OPT(exec) {} if {$PRIV(WWW)} { lappend PRIV(slavealias) history set OPT(prompt1) {[history nextid] % } } else { lappend PRIV(slaveprocs) tcl_unknown unknown set OPT(prompt1) {([file tail [pwd]]) [history nextid] % } } ## If we are using the default '.' toplevel, and there appear to be ## children of '.', then make sure we use a disassociated toplevel. if {$PRIV(root) == "." && [llength [winfo children .]]} { set PRIV(root) .tkcon } ## Do platform specific configuration here, other than defaults ### Use tkcon.cfg filename for resource filename on non-unix systems ### Determine what directory the resource file should be in switch $tcl_platform(platform) { macintosh { if {![interp issafe]} {cd [file dirname [info script]]} set envHome PREF_FOLDER set rcfile tkcon.cfg set histfile qrouter_tkcon.hst catch {console hide} } windows { set envHome HOME set rcfile tkcon.cfg set histfile qrouter_tkcon.hst } unix { set envHome HOME set rcfile .tkconrc set histfile .qrouter_tkcon_hst } } if {[info exists env($envHome)]} { if {![info exists PRIV(rcfile)]} { set PRIV(rcfile) [file join $env($envHome) $rcfile] } if {![info exists PRIV(histfile)]} { set PRIV(histfile) [file join $env($envHome) $histfile] } } ## Handle command line arguments before sourcing resource file to ## find if resource file is being specified (let other args pass). if {[set i [lsearch -exact $argv -rcfile]] != -1} { set PRIV(rcfile) [lindex $argv [incr i]] } if {!$PRIV(WWW) && [file exists $PRIV(rcfile)]} { set code [catch {uplevel \#0 [list source $PRIV(rcfile)]} err] } if {[info exists env(TK_CON_LIBRARY)]} { lappend ::auto_path $env(TK_CON_LIBRARY) } else { lappend ::auto_path $OPT(library) } if {![info exists ::tcl_pkgPath]} { set dir [file join [file dirname [info nameofexec]] lib] if {[llength [info commands @scope]]} { set dir [file join $dir itcl] } catch {source [file join $dir pkgIndex.tcl]} } catch {tclPkgUnknown dummy-name dummy-version} ## Handle rest of command line arguments after sourcing resource file ## and slave is created, but before initializing UI or setting packages. set slaveargs {} set slavefiles {} set truth {^(1|yes|true|on)$} for {set i 0} {$i < $argc} {incr i} { set arg [lindex $argv $i] if {[string match {-*} $arg]} { set val [lindex $argv [incr i]] ## Handle arg based options switch -glob -- $arg { -- - -argv { set argv [concat -- [lrange $argv $i end]] set argc [llength $argv] break } -color-* { set COLOR([string range $arg 7 end]) $val } -exec { set OPT(exec) $val } -main - -e - -eval { append OPT(maineval) \n$val\n } -package - -load { lappend OPT(autoload) $val } -slave { append OPT(slaveeval) \n$val\n } -nontcl { set OPT(nontcl) [regexp -nocase $truth $val]} -root { set PRIV(root) $val } -font { set OPT(font) $val } -rcfile {} default { lappend slaveargs $arg; incr i -1 } } } elseif {[file isfile $arg]} { lappend slavefiles $arg } else { lappend slaveargs $arg } } ## Create slave executable if {[string compare {} $OPT(exec)]} { uplevel \#0 ::tkcon::InitSlave $OPT(exec) $slaveargs } else { set argc [llength $slaveargs] set argv $slaveargs uplevel \#0 $slaveargs } ## Attach to the slave, EvalAttached will then be effective Attach $PRIV(appname) $PRIV(apptype) InitUI $title ## swap puts and gets with the tkcon versions to make sure all ## input and output is handled by tkcon if {![catch {rename ::puts ::tkcon_tcl_puts}]} { interp alias {} ::puts {} ::tkcon_puts } if {($OPT(gets) != "") && ![catch {rename ::gets ::tkcon_tcl_gets}]} { interp alias {} ::gets {} ::tkcon_gets } EvalSlave history keep $OPT(history) if {[info exists MainInit]} { # Source history file only for the main console, as all slave # consoles will adopt from the main's history, but still # keep separate histories if {!$PRIV(WWW) && $OPT(usehistory) && [file exists $PRIV(histfile)]} { puts -nonewline "loading history file ... " # The history file is built to be loaded in and # understood by tkcon if {[catch {uplevel \#0 [list source $PRIV(histfile)]} herr]} { puts stderr "error:\n$herr" append PRIV(errorInfo) $errorInfo\n } set PRIV(event) [EvalSlave history nextid] puts "[expr {$PRIV(event)-1}] events added" } } ## Autoload specified packages in slave set pkgs [EvalSlave package names] foreach pkg $OPT(autoload) { puts -nonewline "autoloading package \"$pkg\" ... " if {[lsearch -exact $pkgs $pkg]>-1} { if {[catch {EvalSlave package require [list $pkg]} pkgerr]} { puts stderr "error:\n$pkgerr" append PRIV(errorInfo) $errorInfo\n } else { puts "OK" } } else { puts stderr "error: package does not exist" } } ## Evaluate maineval in slave if {[string compare {} $OPT(maineval)] && \ [catch {uplevel \#0 $OPT(maineval)} merr]} { puts stderr "error in eval:\n$merr" append PRIV(errorInfo) $errorInfo\n } ## Source extra command line argument files into slave executable foreach fn $slavefiles { puts -nonewline "slave sourcing \"$fn\" ... " if {[catch {EvalSlave source [list $fn]} fnerr]} { puts stderr "error:\n$fnerr" append PRIV(errorInfo) $errorInfo\n } else { puts "OK" } } ## Evaluate slaveeval in slave if {[string compare {} $OPT(slaveeval)] && \ [catch {interp eval $OPT(exec) $OPT(slaveeval)} serr]} { puts stderr "error in slave eval:\n$serr" append PRIV(errorInfo) $errorInfo\n } ## Output any error/output that may have been returned from rcfile if {[info exists code] && $code && [string compare {} $err]} { puts stderr "error in $PRIV(rcfile):\n$err" append PRIV(errorInfo) $errorInfo } if {[string compare {} $OPT(exec)]} { StateCheckpoint [concat $PRIV(name) $OPT(exec)] slave } StateCheckpoint $PRIV(name) slave Prompt "$title console display active (Tcl$::tcl_patchLevel / Tk$::tk_patchLevel)\n" } ## ::tkcon::InitSlave - inits the slave by placing key procs and aliases in it ## It's arg[cv] are based on passed in options, while argv0 is the same as ## the master. tcl_interactive is the same as the master as well. # ARGS: slave - name of slave to init. If it does not exist, it is created. # args - args to pass to a slave as argv/argc ## proc ::tkcon::InitSlave {slave args} { variable OPT variable COLOR variable PRIV global argv0 tcl_interactive tcl_library env auto_path if {[string match {} $slave]} { return -code error "Don't init the master interpreter, goofball" } if {![interp exists $slave]} { interp create $slave } if {[interp eval $slave info command source] == ""} { $slave alias source SafeSource $slave $slave alias load SafeLoad $slave $slave alias open SafeOpen $slave $slave alias file file interp eval $slave [dump var -nocomplain tcl_library auto_path env] interp eval $slave { catch {source [file join $tcl_library init.tcl]} } interp eval $slave { catch unknown } } $slave alias exit exit interp eval $slave { # Do package require before changing around puts/gets catch {package require bogus-package-name} catch {rename ::puts ::tkcon_tcl_puts} } foreach cmd $PRIV(slaveprocs) { $slave eval [dump proc $cmd] } foreach cmd $PRIV(slavealias) { $slave alias $cmd $cmd } interp alias $slave ::ls $slave ::dir -full interp alias $slave ::puts $slave ::tkcon_puts if {$OPT(gets) != ""} { interp eval $slave { catch {rename ::gets ::tkcon_tcl_gets} } interp alias $slave ::gets $slave ::tkcon_gets } if {[info exists argv0]} {interp eval $slave [list set argv0 $argv0]} interp eval $slave set tcl_interactive $tcl_interactive \; \ set auto_path [list $auto_path] \; \ set argc [llength $args] \; \ set argv [list $args] \; { if {![llength [info command bgerror]]} { proc bgerror err { global errorInfo set body [info body bgerror] rename ::bgerror {} if {[auto_load bgerror]} { return [bgerror $err] } proc bgerror err $body tkcon bgerror $err $errorInfo } } } foreach pkg [lremove [package names] Tcl] { foreach v [package versions $pkg] { interp eval $slave [list package ifneeded $pkg $v \ [package ifneeded $pkg $v]] } } } ## ::tkcon::InitInterp - inits an interpreter by placing key ## procs and aliases in it. # ARGS: name - interp name # type - interp type (slave|interp) ## proc ::tkcon::InitInterp {name type} { variable OPT variable PRIV ## Don't allow messing up a local master interpreter if {[string match namespace $type] || ([string match slave $type] && \ [regexp {^([Mm]ain|Slave[0-9]+)$} $name])} return set old [Attach] set oldname $PRIV(namesp) catch { Attach $name $type EvalAttached { catch {rename ::puts ::tkcon_tcl_puts} } foreach cmd $PRIV(slaveprocs) { EvalAttached [dump proc $cmd] } switch -exact $type { slave { foreach cmd $PRIV(slavealias) { Main interp alias $name ::$cmd $PRIV(name) ::$cmd } } interp { set thistkcon [tk appname] foreach cmd $PRIV(slavealias) { EvalAttached "proc $cmd args { send [list $thistkcon] $cmd \$args }" } } } ## Catch in case it's a 7.4 (no 'interp alias') interp EvalAttached { catch {interp alias {} ::ls {} ::dir -full} if {[catch {interp alias {} ::puts {} ::tkcon_puts}]} { catch {rename ::tkcon_puts ::puts} } } if {$OPT(gets) != ""} { EvalAttached { catch {rename ::gets ::tkcon_tcl_gets} if {[catch {interp alias {} ::gets {} ::tkcon_gets}]} { catch {rename ::tkcon_gets ::gets} } } } return } {err} eval Attach $old AttachNamespace $oldname if {[string compare {} $err]} { return -code error $err } } ## ::tkcon::InitUI - inits UI portion (console) of tkcon ## Creates all elements of the console window and sets up the text tags # ARGS: root - widget pathname of the tkcon console root # title - title for the console root and main (.) windows # Calls: ::tkcon::InitMenus, ::tkcon::Prompt ## proc ::tkcon::InitUI {title} { variable OPT variable PRIV variable COLOR set root $PRIV(root) if {[string match . $root]} { set w {} } else { set w [toplevel $root] } if {!$PRIV(WWW)} { wm withdraw $root wm protocol $root WM_DELETE_WINDOW exit } set PRIV(base) $w ## Text Console set PRIV(console) [set con $w.text] text $con -wrap char -yscrollcommand [list $w.sy set] \ -foreground $COLOR(stdin) \ -insertbackground $COLOR(cursor) $con mark set output 1.0 $con mark set limit 1.0 if {[string compare {} $COLOR(bg)]} { $con configure -background $COLOR(bg) } set COLOR(bg) [$con cget -background] if {[string compare {} $OPT(font)]} { ## Set user-requested font, if any $con configure -font $OPT(font) } else { ## otherwise make sure the font is monospace set font [$con cget -font] if {![font metrics $font -fixed]} { font create tkconfixed -family Courier -size 12 $con configure -font tkconfixed } } set OPT(font) [$con cget -font] if {!$PRIV(WWW)} { $con configure -setgrid 1 -width $OPT(cols) -height $OPT(rows) } bindtags $con [list $con TkConsole TkConsolePost $root all] ## Menus ## catch against use in plugin if {[catch {menu $w.mbar} PRIV(menubar)]} { set PRIV(menubar) [frame $w.mbar -relief raised -bd 1] } ## Scrollbar set PRIV(scrolly) [scrollbar $w.sy -takefocus 0 -bd 1 \ -command [list $con yview]] InitMenus $PRIV(menubar) $title Bindings if {$OPT(showmenu)} { $root configure -menu $PRIV(menubar) } pack $w.sy -side $OPT(scrollypos) -fill y pack $con -fill both -expand 1 set PRIV(statusbar) [set sbar [frame $w.sbar]] label $sbar.attach -relief sunken -bd 1 -anchor w \ -textvariable ::tkcon::PRIV(StatusAttach) label $sbar.mode -relief sunken -bd 1 -anchor w \ -textvariable ::tkcon::PRIV(StatusMode) label $sbar.cursor -relief sunken -bd 1 -anchor w -width 6 \ -textvariable ::tkcon::PRIV(StatusCursor) grid $sbar.attach $sbar.mode $sbar.cursor -sticky news -padx 1 grid columnconfigure $sbar 0 -weight 1 grid columnconfigure $sbar 1 -weight 1 grid columnconfigure $sbar 2 -weight 0 if {$OPT(showstatusbar)} { pack $sbar -side bottom -fill x -before $::tkcon::PRIV(scrolly) } foreach col {prompt stdout stderr stdin proc} { $con tag configure $col -foreground $COLOR($col) } $con tag configure var -background $COLOR(var) $con tag raise sel $con tag configure blink -background $COLOR(blink) $con tag configure find -background $COLOR(blink) if {!$PRIV(WWW)} { wm title $root "tkcon $PRIV(version) $title" bind $con { scan [wm geometry [winfo toplevel %W]] "%%dx%%d" \ ::tkcon::OPT(cols) ::tkcon::OPT(rows) } if {$PRIV(showOnStartup)} { wm deiconify $root } } if {$PRIV(showOnStartup)} { focus -force $PRIV(console) } if {$OPT(gc-delay)} { after $OPT(gc-delay) ::tkcon::GarbageCollect } } ## ::tkcon::GarbageCollect - do various cleanup ops periodically to our setup ## proc ::tkcon::GarbageCollect {} { variable OPT variable PRIV set w $PRIV(console) ## Remove error tags that no longer span anything ## Make sure the tag pattern matches the unique tag prefix foreach tag [$w tag names] { if {[string match _tag* $tag] && ![llength [$w tag ranges $tag]]} { $w tag delete $tag } } if {$OPT(gc-delay)} { after $OPT(gc-delay) ::tkcon::GarbageCollect } } ## ::tkcon::Eval - evaluates commands input into console window ## This is the first stage of the evaluating commands in the console. ## They need to be broken up into consituent commands (by ::tkcon::CmdSep) in ## case a multiple commands were pasted in, then each is eval'ed (by ## ::tkcon::EvalCmd) in turn. Any uncompleted command will not be eval'ed. # ARGS: w - console text widget # Calls: ::tkcon::CmdGet, ::tkcon::CmdSep, ::tkcon::EvalCmd ## proc ::tkcon::Eval {w} { set incomplete [CmdSep [CmdGet $w] cmds last] $w mark set insert end-1c $w insert end \n if {[llength $cmds]} { foreach c $cmds {EvalCmd $w $c} $w insert insert $last {} } elseif {!$incomplete} { EvalCmd $w $last } $w see insert } ## ::tkcon::EvalCmd - evaluates a single command, adding it to history # ARGS: w - console text widget # cmd - the command to evaluate # Calls: ::tkcon::Prompt # Outputs: result of command to stdout (or stderr if error occured) # Returns: next event number ## proc ::tkcon::EvalCmd {w cmd} { variable OPT variable PRIV $w mark set output end if {[string compare {} $cmd]} { set code 0 if {$OPT(subhistory)} { set ev [EvalSlave history nextid] incr ev -1 if {[string match !! $cmd]} { set code [catch {EvalSlave history event $ev} cmd] if {!$code} {$w insert output $cmd\n stdin} } elseif {[regexp {^!(.+)$} $cmd dummy event]} { ## Check last event because history event is broken set code [catch {EvalSlave history event $ev} cmd] if {!$code && ![string match ${event}* $cmd]} { set code [catch {EvalSlave history event $event} cmd] } if {!$code} {$w insert output $cmd\n stdin} } elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $cmd dummy old new]} { set code [catch {EvalSlave history event $ev} cmd] if {!$code} { regsub -all -- $old $cmd $new cmd $w insert output $cmd\n stdin } } elseif {$OPT(calcmode) && ![catch {expr $cmd} err]} { EvalSlave history add $cmd set cmd $err set code -1 } } if {$code} { $w insert output $cmd\n stderr } else { ## We are about to evaluate the command, so move the limit ## mark to ensure that further s don't cause double ## evaluation of this command - for cases like the command ## has a vwait or something in it $w mark set limit end if {$OPT(nontcl) && [string match interp $PRIV(apptype)]} { set code [catch {EvalSend $cmd} res] if {$code == 1} { set PRIV(errorInfo) "Non-Tcl errorInfo not available" } } elseif {[string match socket $PRIV(apptype)]} { set code [catch {EvalSocket $cmd} res] if {$code == 1} { set PRIV(errorInfo) "Socket-based errorInfo not available" } } else { set code [catch {EvalAttached $cmd} res] if {$code == 1} { if {[catch {EvalAttached [list set errorInfo]} err]} { set PRIV(errorInfo) "Error getting errorInfo:\n$err" } else { set PRIV(errorInfo) $err } } } EvalSlave history add $cmd if {$code} { if {$OPT(hoterrors)} { set tag [UniqueTag $w] $w insert output $res [list stderr $tag] \n stderr $w tag bind $tag \ [list $w tag configure $tag -underline 1] $w tag bind $tag \ [list $w tag configure $tag -underline 0] $w tag bind $tag \ "if {!\[info exists tkPriv(mouseMoved)\] || !\$tkPriv(mouseMoved)} \ {[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}" } else { $w insert output $res\n stderr } } elseif {[string compare {} $res]} { $w insert output $res\n stdout } } } Prompt set PRIV(event) [EvalSlave history nextid] } ## ::tkcon::EvalSlave - evaluates the args in the associated slave ## args should be passed to this procedure like they would be at ## the command line (not like to 'eval'). # ARGS: args - the command and args to evaluate ## proc ::tkcon::EvalSlave args { interp eval $::tkcon::OPT(exec) $args } ## ::tkcon::EvalOther - evaluate a command in a foreign interp or slave ## without attaching to it. No check for existence is made. # ARGS: app - interp/slave name # type - (slave|interp) ## proc ::tkcon::EvalOther { app type args } { if {[string compare slave $type]==0} { return [Slave $app $args] } else { return [uplevel 1 send [list $app] $args] } } ## ::tkcon::EvalSend - sends the args to the attached interpreter ## Varies from 'send' by determining whether attachment is dead ## when an error is received # ARGS: cmd - the command string to send across # Returns: the result of the command ## proc ::tkcon::EvalSend cmd { variable OPT variable PRIV if {$PRIV(deadapp)} { if {[lsearch -exact [winfo interps] $PRIV(app)]<0} { return } else { set PRIV(appname) [string range $PRIV(appname) 5 end] set PRIV(deadapp) 0 Prompt "\n\"$PRIV(app)\" alive\n" [CmdGet $PRIV(console)] } } set code [catch {send -displayof $PRIV(displayWin) $PRIV(app) $cmd} result] if {$code && [lsearch -exact [winfo interps] $PRIV(app)]<0} { ## Interpreter disappeared if {[string compare leave $OPT(dead)] && \ ([string match ignore $OPT(dead)] || \ [tk_dialog $PRIV(base).dead "Dead Attachment" \ "\"$PRIV(app)\" appears to have died.\ \nReturn to primary slave interpreter?" questhead 0 OK No])} { set PRIV(appname) "DEAD:$PRIV(appname)" set PRIV(deadapp) 1 } else { set err "Attached Tk interpreter \"$PRIV(app)\" died." Attach {} set PRIV(deadapp) 0 EvalSlave set errorInfo $err } Prompt \n [CmdGet $PRIV(console)] } return -code $code $result } ## ::tkcon::EvalSocket - sends the string to an interpreter attached via ## a tcp/ip socket ## ## In the EvalSocket case, ::tkcon::PRIV(app) is the socket id ## ## Must determine whether socket is dead when an error is received # ARGS: cmd - the data string to send across # Returns: the result of the command ## proc ::tkcon::EvalSocket cmd { variable OPT variable PRIV global tcl_version if {$PRIV(deadapp)} { if {![info exists PRIV(app)] || \ [catch {eof $PRIV(app)} eof] || $eof} { return } else { set PRIV(appname) [string range $PRIV(appname) 5 end] set PRIV(deadapp) 0 Prompt "\n\"$PRIV(app)\" alive\n" [CmdGet $PRIV(console)] } } # Sockets get \'s interpreted, so that users can # send things like \n\r or explicit hex values set cmd [subst -novariables -nocommands $cmd] #puts [list $PRIV(app) $cmd] set code [catch {puts $PRIV(app) $cmd ; flush $PRIV(app)} result] if {$code && [eof $PRIV(app)]} { ## Interpreter died or disappeared puts "$code eof [eof $PRIV(app)]" EvalSocketClosed } return -code $code $result } ## ::tkcon::EvalSocketEvent - fileevent command for an interpreter attached ## via a tcp/ip socket ## Must determine whether socket is dead when an error is received # ARGS: args - the args to send across # Returns: the result of the command ## proc ::tkcon::EvalSocketEvent {} { variable PRIV if {[gets $PRIV(app) line] == -1} { if {[eof $PRIV(app)]} { EvalSocketClosed } return } puts $line } ## ::tkcon::EvalSocketClosed - takes care of handling a closed eval socket ## # ARGS: args - the args to send across # Returns: the result of the command ## proc ::tkcon::EvalSocketClosed {} { variable OPT variable PRIV catch {close $PRIV(app)} if {[string compare leave $OPT(dead)] && \ ([string match ignore $OPT(dead)] || \ [tk_dialog $PRIV(base).dead "Dead Attachment" \ "\"$PRIV(app)\" appears to have died.\ \nReturn to primary slave interpreter?" questhead 0 OK No])} { set PRIV(appname) "DEAD:$PRIV(appname)" set PRIV(deadapp) 1 } else { set err "Attached Tk interpreter \"$PRIV(app)\" died." Attach {} set PRIV(deadapp) 0 EvalSlave set errorInfo $err } Prompt \n [CmdGet $PRIV(console)] } ## ::tkcon::EvalNamespace - evaluates the args in a particular namespace ## This is an override for ::tkcon::EvalAttached for when the user wants ## to attach to a particular namespace of the attached interp # ARGS: attached # namespace the namespace to evaluate in # args the args to evaluate # RETURNS: the result of the command ## proc ::tkcon::EvalNamespace { attached namespace args } { if {[llength $args]} { uplevel \#0 $attached \ [list [concat [list namespace eval $namespace] $args]] } } ## ::tkcon::Namespaces - return all the namespaces descendent from $ns ## # ## proc ::tkcon::Namespaces {{ns ::} {l {}}} { if {[string compare {} $ns]} { lappend l $ns } foreach i [EvalAttached [list namespace children $ns]] { set l [Namespaces $i $l] } return $l } ## ::tkcon::CmdGet - gets the current command from the console widget # ARGS: w - console text widget # Returns: text which compromises current command line ## proc ::tkcon::CmdGet w { if {![llength [$w tag nextrange prompt limit end]]} { $w tag add stdin limit end-1c return [$w get limit end-1c] } } ## ::tkcon::CmdSep - separates multiple commands into a list and remainder # ARGS: cmd - (possible) multiple command to separate # list - varname for the list of commands that were separated. # last - varname of any remainder (like an incomplete final command). # If there is only one command, it's placed in this var. # Returns: constituent command info in varnames specified by list & rmd. ## proc ::tkcon::CmdSep {cmd list last} { upvar 1 $list cmds $last inc set inc {} set cmds {} foreach c [split [string trimleft $cmd] \n] { if {[string compare $inc {}]} { append inc \n$c } else { append inc [string trimleft $c] } if {[info complete $inc] && ![regexp {[^\\]\\$} $inc]} { if {[regexp "^\[^#\]" $inc]} {lappend cmds $inc} set inc {} } } set i [string compare $inc {}] if {!$i && [string compare $cmds {}] && ![string match *\n $cmd]} { set inc [lindex $cmds end] set cmds [lreplace $cmds end end] } return $i } ## ::tkcon::CmdSplit - splits multiple commands into a list # ARGS: cmd - (possible) multiple command to separate # Returns: constituent commands in a list ## proc ::tkcon::CmdSplit {cmd} { set inc {} set cmds {} foreach cmd [split [string trimleft $cmd] \n] { if {[string compare {} $inc]} { append inc \n$cmd } else { append inc [string trimleft $cmd] } if {[info complete $inc] && ![regexp {[^\\]\\$} $inc]} { #set inc [string trimright $inc] if {[regexp "^\[^#\]" $inc]} {lappend cmds $inc} set inc {} } } if {[regexp "^\[^#\]" $inc]} {lappend cmds $inc} return $cmds } ## ::tkcon::UniqueTag - creates a uniquely named tag, reusing names ## Called by ::tkcon::EvalCmd # ARGS: w - text widget # Outputs: tag name guaranteed unique in the widget ## proc ::tkcon::UniqueTag {w} { set tags [$w tag names] set idx 0 while {[lsearch -exact $tags _tag[incr idx]] != -1} {} return _tag$idx } ## ::tkcon::ConstrainBuffer - This limits the amount of data in the text widget ## Called by ::tkcon::Prompt and in tkcon proc buffer/console switch cases # ARGS: w - console text widget # size - # of lines to constrain to # Outputs: may delete data in console widget ## proc ::tkcon::ConstrainBuffer {w size} { if {[$w index end] > $size} { $w delete 1.0 [expr {int([$w index end])-$size}].0 } } ## ::tkcon::Prompt - displays the prompt in the console widget # ARGS: w - console text widget # Outputs: prompt (specified in ::tkcon::OPT(prompt1)) to console ## proc ::tkcon::Prompt {{pre {}} {post {}} {prompt {}}} { variable OPT variable PRIV set w $PRIV(console) if {[string compare {} $pre]} { $w insert end $pre stdout } set i [$w index end-1c] if {!$OPT(showstatusbar)} { if {[string compare {} $PRIV(appname)]} { $w insert end ">$PRIV(appname)< " prompt } if {[string compare :: $PRIV(namesp)]} { $w insert end "<$PRIV(namesp)> " prompt } } if {[string compare {} $prompt]} { $w insert end $prompt prompt } else { $w insert end [EvalSlave subst $OPT(prompt1)] prompt } $w mark set output $i $w mark set insert end $w mark set limit insert $w mark gravity limit left if {[string compare {} $post]} { $w insert end $post stdin } ConstrainBuffer $w $OPT(buffer) set ::tkcon::PRIV(StatusCursor) [$w index insert] $w see end } ## ::tkcon::About - gives about info for tkcon ## proc ::tkcon::About {} { variable OPT variable PRIV variable COLOR set w $PRIV(base).about if {[winfo exists $w]} { wm deiconify $w } else { global tk_patchLevel tcl_patchLevel tcl_version toplevel $w wm title $w "About tkcon v$PRIV(version)" button $w.b -text Dismiss -command [list wm withdraw $w] text $w.text -height 9 -bd 1 -width 60 \ -foreground $COLOR(stdin) \ -background $COLOR(bg) \ -font $OPT(font) pack $w.b -fill x -side bottom pack $w.text -fill both -side left -expand 1 $w.text tag config center -justify center $w.text tag config title -justify center -font {Courier -18 bold} # strip down the RCS info displayed in the about box regexp {,v ([0-9\./: ]*)} $PRIV(RCS) -> RCS $w.text insert 1.0 "About tkcon v$PRIV(version)" title \ "\n\nCopyright 1995-2001 Jeffrey Hobbs, $PRIV(email)\ \nRelease Info: v$PRIV(version), CVS v$RCS\ \nDocumentation available at:\n$PRIV(docs)\ \nUsing: Tcl v$tcl_patchLevel / Tk v$tk_patchLevel" center $w.text config -state disabled } } ## ::tkcon::InitMenus - inits the menubar and popup for the console # ARGS: w - console text widget ## proc ::tkcon::InitMenus {w title} { variable OPT variable PRIV variable COLOR global tcl_platform if {[catch {menu $w.pop -tearoff 0}]} { label $w.label -text "Menus not available in plugin mode" pack $w.label return } menu $w.context -tearoff 0 -disabledforeground $COLOR(disabled) set PRIV(context) $w.context set PRIV(popup) $w.pop proc MenuButton {w m l} { $w add cascade -label $m -underline 0 -menu $w.$l return $w.$l } foreach m [list File Console Edit Interp Prefs History Help] { set l [string tolower $m] MenuButton $w $m $l $w.pop add cascade -label $m -underline 0 -menu $w.pop.$l } ## File Menu ## foreach m [list [menu $w.file -disabledforeground $COLOR(disabled)] \ [menu $w.pop.file -disabledforeground $COLOR(disabled)]] { $m add command -label "Load File" -underline 0 -command ::tkcon::Load $m add cascade -label "Save ..." -underline 0 -menu $m.save $m add separator $m add command -label "Quit" -underline 0 -accel Ctrl-q -command exit ## Save Menu ## set s $m.save menu $s -disabledforeground $COLOR(disabled) -tearoff 0 $s add command -label "All" -underline 0 \ -command {::tkcon::Save {} all} $s add command -label "History" -underline 0 \ -command {::tkcon::Save {} history} $s add command -label "Stdin" -underline 3 \ -command {::tkcon::Save {} stdin} $s add command -label "Stdout" -underline 3 \ -command {::tkcon::Save {} stdout} $s add command -label "Stderr" -underline 3 \ -command {::tkcon::Save {} stderr} } ## Console Menu ## foreach m [list [menu $w.console -disabledfore $COLOR(disabled)] \ [menu $w.pop.console -disabledfore $COLOR(disabled)]] { $m add command -label "$title Console" -state disabled $m add command -label "New Console" -underline 0 -accel Ctrl-N \ -command ::tkcon::New $m add command -label "Close Console" -underline 0 -accel Ctrl-w \ -command ::tkcon::Destroy $m add command -label "Clear Console" -underline 1 -accel Ctrl-l \ -command { clear; ::tkcon::Prompt } if {[string match unix $tcl_platform(platform)]} { $m add separator $m add command -label "Make Xauth Secure" -und 5 \ -command ::tkcon::XauthSecure } $m add separator $m add cascade -label "Attach To ..." -underline 0 -menu $m.attach ## Attach Console Menu ## set sub [menu $m.attach -disabledforeground $COLOR(disabled)] $sub add cascade -label "Interpreter" -underline 0 -menu $sub.apps $sub add cascade -label "Namespace" -underline 1 -menu $sub.name $sub add cascade -label "Socket" -underline 1 -menu $sub.sock \ -state [expr {([info tclversion] < 8.3)?"disabled":"normal"}] ## Attach Console Menu ## menu $sub.apps -disabledforeground $COLOR(disabled) \ -postcommand [list ::tkcon::AttachMenu $sub.apps] ## Attach Namespace Menu ## menu $sub.name -disabledforeground $COLOR(disabled) -tearoff 0 \ -postcommand [list ::tkcon::NamespaceMenu $sub.name] if {$::tcl_version >= 8.3} { # This uses [file channels] to create the menu, so we only # want it for newer versions of Tcl. ## Attach Socket Menu ## menu $sub.sock -disabledforeground $COLOR(disabled) -tearoff 0 \ -postcommand [list ::tkcon::SocketMenu $sub.sock] } ## Attach Display Menu ## if {![string compare "unix" $tcl_platform(platform)]} { $sub add cascade -label "Display" -und 1 -menu $sub.disp menu $sub.disp -disabledforeground $COLOR(disabled) \ -tearoff 0 \ -postcommand [list ::tkcon::DisplayMenu $sub.disp] } } ## Edit Menu ## set text $PRIV(console) foreach m [list [menu $w.edit] [menu $w.pop.edit]] { $m add command -label "Cut" -underline 2 -accel Ctrl-x \ -command [list ::tkcon::Cut $text] $m add command -label "Copy" -underline 0 -accel Ctrl-c \ -command [list ::tkcon::Copy $text] $m add command -label "Paste" -underline 0 -accel Ctrl-v \ -command [list ::tkcon::Paste $text] $m add separator $m add command -label "Find" -underline 0 -accel Ctrl-F \ -command [list ::tkcon::FindBox $text] } ## Interp Menu ## foreach m [list $w.interp $w.pop.interp] { menu $m -disabledforeground $COLOR(disabled) \ -postcommand [list ::tkcon::InterpMenu $m] } ## Prefs Menu ## foreach m [list [menu $w.prefs] [menu $w.pop.prefs]] { $m add check -label "Brace Highlighting" \ -underline 0 -variable ::tkcon::OPT(lightbrace) $m add check -label "Command Highlighting" \ -underline 0 -variable ::tkcon::OPT(lightcmd) $m add check -label "History Substitution" \ -underline 0 -variable ::tkcon::OPT(subhistory) $m add check -label "Hot Errors" \ -underline 0 -variable ::tkcon::OPT(hoterrors) $m add check -label "Non-Tcl Attachments" \ -underline 0 -variable ::tkcon::OPT(nontcl) $m add check -label "Calculator Mode" \ -underline 1 -variable ::tkcon::OPT(calcmode) $m add check -label "Show Multiple Matches" \ -underline 0 -variable ::tkcon::OPT(showmultiple) $m add check -label "Show Menubar" \ -underline 5 -variable ::tkcon::OPT(showmenu) \ -command {$::tkcon::PRIV(root) configure -menu [expr \ {$::tkcon::OPT(showmenu) ? $::tkcon::PRIV(menubar) : {}}]} $m add check -label "Show Statusbar" \ -underline 5 -variable ::tkcon::OPT(showstatusbar) \ -command { if {$::tkcon::OPT(showstatusbar)} { pack $::tkcon::PRIV(statusbar) -side bottom -fill x \ -before $::tkcon::PRIV(scrolly) } else { pack forget $::tkcon::PRIV(statusbar) } } $m add cascade -label "Scrollbar" -underline 2 -menu $m.scroll ## Scrollbar Menu ## set m [menu $m.scroll -tearoff 0] $m add radio -label "Left" -value left \ -variable ::tkcon::OPT(scrollypos) \ -command { pack config $::tkcon::PRIV(scrolly) -side left } $m add radio -label "Right" -value right \ -variable ::tkcon::OPT(scrollypos) \ -command { pack config $::tkcon::PRIV(scrolly) -side right } } ## History Menu ## foreach m [list $w.history $w.pop.history] { menu $m -disabledforeground $COLOR(disabled) \ -postcommand [list ::tkcon::HistoryMenu $m] } ## Help Menu ## foreach m [list [menu $w.help] [menu $w.pop.help]] { $m add command -label "About " -underline 0 -accel Ctrl-A \ -command ::tkcon::About $m add command -label "Retrieve Latest Version" -underline 0 \ -command ::tkcon::Retrieve } } ## ::tkcon::HistoryMenu - dynamically build the menu for attached interpreters ## # ARGS: m - menu widget ## proc ::tkcon::HistoryMenu m { variable PRIV if {![winfo exists $m]} return set id [EvalSlave history nextid] if {$PRIV(histid)==$id} return set PRIV(histid) $id $m delete 0 end while {($id>1) && ($id>$PRIV(histid)-10) && \ ![catch {EvalSlave history event [incr id -1]} tmp]} { set lbl $tmp if {[string len $lbl]>32} { set lbl [string range $tmp 0 28]... } $m add command -label "$id: $lbl" -command " $::tkcon::PRIV(console) delete limit end $::tkcon::PRIV(console) insert limit [list $tmp] $::tkcon::PRIV(console) see end ::tkcon::Eval $::tkcon::PRIV(console)" } } ## ::tkcon::InterpMenu - dynamically build the menu for attached interpreters ## # ARGS: w - menu widget ## proc ::tkcon::InterpMenu w { variable OPT variable PRIV variable COLOR if {![winfo exists $w]} return $w delete 0 end foreach {app type} [Attach] break $w add command -label "[string toupper $type]: $app" -state disabled if {($OPT(nontcl) && [string match interp $type]) || $PRIV(deadapp)} { $w add separator $w add command -state disabled -label "Communication disabled to" $w add command -state disabled -label "dead or non-Tcl interps" return } ## Show Last Error ## $w add separator $w add command -label "Show Last Error" \ -command [list tkcon error $app $type] ## Packages Cascaded Menu ## $w add separator $w add cascade -label Packages -underline 0 -menu $w.pkg set m $w.pkg if {![winfo exists $m]} { menu $m -tearoff no -disabledforeground $COLOR(disabled) \ -postcommand [list ::tkcon::PkgMenu $m $app $type] } ## State Checkpoint/Revert ## $w add separator $w add command -label "Checkpoint State" \ -command [list ::tkcon::StateCheckpoint $app $type] $w add command -label "Revert State" \ -command [list ::tkcon::StateRevert $app $type] $w add command -label "View State Change" \ -command [list ::tkcon::StateCompare $app $type] ## Init Interp ## $w add separator $w add command -label "Send tkcon Commands" \ -command [list ::tkcon::InitInterp $app $type] } ## ::tkcon::PkgMenu - fill in in the applications sub-menu ## with a list of all the applications that currently exist. ## proc ::tkcon::PkgMenu {m app type} { # just in case stuff has been added to the auto_path # we have to make sure that the errorInfo doesn't get screwed up EvalAttached { set __tkcon_error $errorInfo catch {package require bogus-package-name} set errorInfo ${__tkcon_error} unset __tkcon_error } $m delete 0 end foreach pkg [EvalAttached [list info loaded {}]] { set loaded([lindex $pkg 1]) [package provide $pkg] } foreach pkg [lremove [EvalAttached {package names}] Tcl] { set version [EvalAttached [list package provide $pkg]] if {[string compare {} $version]} { set loaded($pkg) $version } elseif {![info exists loaded($pkg)]} { set loadable($pkg) [list package require $pkg] } } foreach pkg [EvalAttached {info loaded}] { set pkg [lindex $pkg 1] if {![info exists loaded($pkg)] && ![info exists loadable($pkg)]} { set loadable($pkg) [list load {} $pkg] } } set npkg 0 foreach pkg [lsort -dictionary [array names loadable]] { foreach v [EvalAttached [list package version $pkg]] { set brkcol [expr {([incr npkg]%16)==0}] $m add command -label "Load $pkg ($v)" -command \ "::tkcon::EvalOther [list $app] $type $loadable($pkg) $v" \ -columnbreak $brkcol } } if {[info exists loaded] && [info exists loadable]} { $m add separator } foreach pkg [lsort -dictionary [array names loaded]] { $m add command -label "${pkg}$loaded($pkg) Loaded" -state disabled } } ## ::tkcon::AttachMenu - fill in in the applications sub-menu ## with a list of all the applications that currently exist. ## proc ::tkcon::AttachMenu m { variable OPT variable PRIV array set interps [set tmp [Interps]] foreach {i j} $tmp { set tknames($j) {} } $m delete 0 end set cmd {::tkcon::Prompt \n [::tkcon::CmdGet $::tkcon::PRIV(console)]} $m add radio -label {None (use local slave) } -accel Ctrl-1 \ -variable ::tkcon::PRIV(app) \ -value [concat $::tkcon::PRIV(name) $::tkcon::OPT(exec)] \ -command "::tkcon::Attach {}; $cmd" $m add separator $m add command -label "Foreign Tk Interpreters" -state disabled foreach i [lsort [lremove [winfo interps] [array names tknames]]] { $m add radio -label $i -variable ::tkcon::PRIV(app) -value $i \ -command "::tkcon::Attach [list $i] interp; $cmd" } $m add separator $m add command -label "tkcon Interpreters" -state disabled foreach i [lsort [array names interps]] { if {[string match {} $interps($i)]} { set interps($i) "no Tk" } if {[regexp {^Slave[0-9]+} $i]} { set opts [list -label "$i ($interps($i))" \ -variable ::tkcon::PRIV(app) -value $i \ -command "::tkcon::Attach [list $i] slave; $cmd"] if {[string match $PRIV(name) $i]} { append opts " -accel Ctrl-2" } eval $m add radio $opts } else { set name [concat Main $i] if {[string match Main $name]} { $m add radio -label "$name ($interps($i))" -accel Ctrl-3 \ -variable ::tkcon::PRIV(app) -value Main \ -command "::tkcon::Attach [list $name] slave; $cmd" } else { $m add radio -label "$name ($interps($i))" \ -variable ::tkcon::PRIV(app) -value $i \ -command "::tkcon::Attach [list $name] slave; $cmd" } } } } ## Displays Cascaded Menu ## proc ::tkcon::DisplayMenu m { $m delete 0 end set cmd {::tkcon::Prompt \n [::tkcon::CmdGet $::tkcon::PRIV(console)]} $m add command -label "New Display" -command ::tkcon::NewDisplay foreach disp [Display] { $m add separator $m add command -label $disp -state disabled set res [Display $disp] set win [lindex $res 0] foreach i [lsort [lindex $res 1]] { $m add radio -label $i -variable ::tkcon::PRIV(app) -value $i \ -command "::tkcon::Attach [list $i] [list dpy:$win]; $cmd" } } } ## Sockets Cascaded Menu ## proc ::tkcon::SocketMenu m { $m delete 0 end set cmd {::tkcon::Prompt \n [::tkcon::CmdGet $::tkcon::PRIV(console)]} $m add command -label "Create Connection" \ -command "::tkcon::NewSocket; $cmd" foreach sock [file channels sock*] { $m add radio -label $sock -variable ::tkcon::PRIV(app) -value $sock \ -command "::tkcon::Attach $sock socket; $cmd" } } ## Namepaces Cascaded Menu ## proc ::tkcon::NamespaceMenu m { variable PRIV variable OPT $m delete 0 end if {($PRIV(deadapp) || [string match socket $PRIV(apptype)] || \ ($OPT(nontcl) && [string match interp $PRIV(apptype)]))} { $m add command -label "No Namespaces" -state disabled return } ## Same command as for ::tkcon::AttachMenu items set cmd {::tkcon::Prompt \n [::tkcon::CmdGet $::tkcon::PRIV(console)]} set names [lsort [Namespaces ::]] if {[llength $names] > $OPT(maxmenu)} { $m add command -label "Attached to $PRIV(namesp)" -state disabled $m add command -label "List Namespaces" \ -command [list ::tkcon::NamespacesList $names] } else { foreach i $names { if {[string match :: $i]} { $m add radio -label "Main" -value $i \ -variable ::tkcon::PRIV(namesp) \ -command "::tkcon::AttachNamespace [list $i]; $cmd" } else { $m add radio -label $i -value $i \ -variable ::tkcon::PRIV(namesp) \ -command "::tkcon::AttachNamespace [list $i]; $cmd" } } } } ## Namepaces List ## proc ::tkcon::NamespacesList {names} { variable PRIV set f $PRIV(base).namespaces catch {destroy $f} toplevel $f listbox $f.names -width 30 -height 15 -selectmode single \ -yscrollcommand [list $f.scrollv set] \ -xscrollcommand [list $f.scrollh set] scrollbar $f.scrollv -command [list $f.names yview] scrollbar $f.scrollh -command [list $f.names xview] -orient horizontal frame $f.buttons button $f.cancel -text "Cancel" -command [list destroy $f] grid $f.names $f.scrollv -sticky nesw grid $f.scrollh -sticky ew grid $f.buttons -sticky nesw grid $f.cancel -in $f.buttons -pady 6 grid columnconfigure $f 0 -weight 1 grid rowconfigure $f 0 -weight 1 #fill the listbox foreach i $names { if {[string match :: $i]} { $f.names insert 0 Main } else { $f.names insert end $i } } #Bindings bind $f.names { ## Catch in case the namespace disappeared on us catch { ::tkcon::AttachNamespace [%W get [%W nearest %y]] } ::tkcon::Prompt "\n" [::tkcon::CmdGet $::tkcon::PRIV(console)] destroy [winfo toplevel %W] } } # ::tkcon::XauthSecure -- # # This removes all the names in the xhost list, and secures # the display for Tk send commands. Of course, this prevents # what might have been otherwise allowable X connections # # Arguments: # none # Results: # Returns nothing # proc ::tkcon::XauthSecure {} { global tcl_platform if {[string compare unix $tcl_platform(platform)]} { # This makes no sense outside of Unix return } set hosts [exec xhost] # the first line is info only foreach host [lrange [split $hosts \n] 1 end] { exec xhost -$host } exec xhost - tk_messageBox -title "Xhost secured" -message "Xhost secured" -icon info } ## ::tkcon::FindBox - creates minimal dialog interface to ::tkcon::Find # ARGS: w - text widget # str - optional seed string for ::tkcon::PRIV(find) ## proc ::tkcon::FindBox {w {str {}}} { variable PRIV set base $PRIV(base).find if {![winfo exists $base]} { toplevel $base wm withdraw $base wm title $base "tkcon Find" pack [frame $base.f] -fill x -expand 1 label $base.f.l -text "Find:" entry $base.f.e -textvariable ::tkcon::PRIV(find) pack [frame $base.opt] -fill x checkbutton $base.opt.c -text "Case Sensitive" \ -variable ::tkcon::PRIV(find,case) checkbutton $base.opt.r -text "Use Regexp" -variable ::tkcon::PRIV(find,reg) pack $base.f.l -side left pack $base.f.e $base.opt.c $base.opt.r -side left -fill both -expand 1 pack [frame $base.sep -bd 2 -relief sunken -height 4] -fill x pack [frame $base.btn] -fill both button $base.btn.fnd -text "Find" -width 6 button $base.btn.clr -text "Clear" -width 6 button $base.btn.dis -text "Dismiss" -width 6 eval pack [winfo children $base.btn] -padx 4 -pady 2 \ -side left -fill both focus $base.f.e bind $base.f.e [list $base.btn.fnd invoke] bind $base.f.e [list $base.btn.dis invoke] } $base.btn.fnd config -command "::tkcon::Find [list $w] \$::tkcon::PRIV(find) \ -case \$::tkcon::PRIV(find,case) -reg \$::tkcon::PRIV(find,reg)" $base.btn.clr config -command " [list $w] tag remove find 1.0 end set ::tkcon::PRIV(find) {} " $base.btn.dis config -command " [list $w] tag remove find 1.0 end wm withdraw [list $base] " if {[string compare {} $str]} { set PRIV(find) $str $base.btn.fnd invoke } if {[string compare normal [wm state $base]]} { wm deiconify $base } else { raise $base } $base.f.e select range 0 end } ## ::tkcon::Find - searches in text widget $w for $str and highlights it ## If $str is empty, it just deletes any highlighting # ARGS: w - text widget # str - string to search for # -case TCL_BOOLEAN whether to be case sensitive DEFAULT: 0 # -regexp TCL_BOOLEAN whether to use $str as pattern DEFAULT: 0 ## proc ::tkcon::Find {w str args} { $w tag remove find 1.0 end set truth {^(1|yes|true|on)$} set opts {} foreach {key val} $args { switch -glob -- $key { -c* { if {[regexp -nocase $truth $val]} { set case 1 } } -r* { if {[regexp -nocase $truth $val]} { lappend opts -regexp } } default { return -code error "Unknown option $key" } } } if {![info exists case]} { lappend opts -nocase } if {[string match {} $str]} return $w mark set findmark 1.0 while {[string compare {} [set ix [eval $w search $opts -count numc -- \ [list $str] findmark end]]]} { $w tag add find $ix ${ix}+${numc}c $w mark set findmark ${ix}+1c } $w tag configure find -background $::tkcon::COLOR(blink) catch {$w see find.first} return [expr {[llength [$w tag ranges find]]/2}] } ## ::tkcon::Attach - called to attach tkcon to an interpreter # ARGS: name - application name to which tkcon sends commands # This is either a slave interperter name or tk appname. # type - (slave|interp) type of interpreter we're attaching to # slave means it's a tkcon interpreter # interp means we'll need to 'send' to it. # Results: ::tkcon::EvalAttached is recreated to evaluate in the # appropriate interpreter ## proc ::tkcon::Attach {{name } {type slave}} { variable PRIV variable OPT if {[llength [info level 0]] == 1} { # no args were specified, return the attach info instead if {[string match {} $PRIV(appname)]} { return [list [concat $PRIV(name) $OPT(exec)] $PRIV(apptype)] } else { return [list $PRIV(appname) $PRIV(apptype)] } } set path [concat $PRIV(name) $OPT(exec)] set PRIV(displayWin) . if {[string match namespace $type]} { return [uplevel 1 ::tkcon::AttachNamespace $name] } elseif {[string match dpy:* $type]} { set PRIV(displayWin) [string range $type 4 end] } elseif {[string match sock* $type]} { global tcl_version if {[catch {eof $name} res]} { return -code error "No known channel \"$name\"" } elseif {$res} { catch {close $name} return -code error "Channel \"$name\" returned EOF" } set app $name set type socket } elseif {[string compare {} $name]} { array set interps [Interps] if {[string match {[Mm]ain} [lindex $name 0]]} { set name [lrange $name 1 end] } if {[string match $path $name]} { set name {} set app $path set type slave } elseif {[info exists interps($name)]} { if {[string match {} $name]} { set name Main; set app Main } set type slave } elseif {[interp exists $name]} { set name [concat $PRIV(name) $name] set type slave } elseif {[interp exists [concat $OPT(exec) $name]]} { set name [concat $path $name] set type slave } elseif {[lsearch -exact [winfo interps] $name] > -1} { if {[EvalSlave info exists tk_library] \ && [string match $name [EvalSlave tk appname]]} { set name {} set app $path set type slave } elseif {[set i [lsearch -exact \ [Main set ::tkcon::PRIV(interps)] $name]] != -1} { set name [lindex [Main set ::tkcon::PRIV(slaves)] $i] if {[string match {[Mm]ain} $name]} { set app Main } set type slave } else { set type interp } } else { return -code error "No known interpreter \"$name\"" } } else { set app $path } if {![info exists app]} { set app $name } array set PRIV [list app $app appname $name apptype $type deadapp 0] ## ::tkcon::EvalAttached - evaluates the args in the attached interp ## args should be passed to this procedure as if they were being ## passed to the 'eval' procedure. This procedure is dynamic to ## ensure evaluation occurs in the right interp. # ARGS: args - the command and args to evaluate ## switch -glob -- $type { slave { if {[string match {} $name]} { interp alias {} ::tkcon::EvalAttached {} \ ::tkcon::EvalSlave uplevel \#0 } elseif {[string match Main $PRIV(app)]} { interp alias {} ::tkcon::EvalAttached {} ::tkcon::Main } elseif {[string match $PRIV(name) $PRIV(app)]} { interp alias {} ::tkcon::EvalAttached {} uplevel \#0 } else { interp alias {} ::tkcon::EvalAttached {} \ ::tkcon::Slave $::tkcon::PRIV(app) } } sock* { interp alias {} ::tkcon::EvalAttached {} \ ::tkcon::EvalSlave uplevel \#0 # The file event will just puts whatever data is found # into the interpreter fconfigure $name -buffering line -blocking 0 fileevent $name readable ::tkcon::EvalSocketEvent } dpy:* - interp { if {$OPT(nontcl)} { interp alias {} ::tkcon::EvalAttached {} ::tkcon::EvalSlave set PRIV(namesp) :: } else { interp alias {} ::tkcon::EvalAttached {} ::tkcon::EvalSend } } default { return -code error "[lindex [info level 0] 0] did not specify\ a valid type: must be slave or interp" } } if {[string match slave $type] || \ (!$OPT(nontcl) && [regexp {^(interp|dpy)} $type])} { set PRIV(namesp) :: } set PRIV(StatusAttach) "$PRIV(app) ($PRIV(apptype))" return } ## ::tkcon::AttachNamespace - called to attach tkcon to a namespace # ARGS: name - namespace name in which tkcon should eval commands # Results: ::tkcon::EvalAttached will be modified ## proc ::tkcon::AttachNamespace { name } { variable PRIV variable OPT if {($OPT(nontcl) && [string match interp $PRIV(apptype)]) \ || [string match socket $PRIV(apptype)] \ || $PRIV(deadapp)} { return -code error "can't attach to namespace in attached environment" } if {[string match Main $name]} {set name ::} if {[string compare {} $name] && \ [lsearch [Namespaces ::] $name] == -1} { return -code error "No known namespace \"$name\"" } if {[regexp {^(|::)$} $name]} { ## If name=={} || ::, we want the primary namespace set alias [interp alias {} ::tkcon::EvalAttached] if {[string match ::tkcon::EvalNamespace* $alias]} { eval [list interp alias {} ::tkcon::EvalAttached {}] \ [lindex $alias 1] } set name :: } else { interp alias {} ::tkcon::EvalAttached {} ::tkcon::EvalNamespace \ [interp alias {} ::tkcon::EvalAttached] [list $name] } set PRIV(namesp) $name set PRIV(StatusAttach) "$PRIV(app) $PRIV(namesp) ($PRIV(apptype))" } ## ::tkcon::NewSocket - called to create a socket to connect to # ARGS: none # Results: It will create a socket, and attach if requested ## proc ::tkcon::NewSocket {} { variable PRIV set t $PRIV(base).newsock if {![winfo exists $t]} { toplevel $t wm withdraw $t wm title $t "tkcon Create Socket" label $t.lhost -text "Host: " entry $t.host -width 20 label $t.lport -text "Port: " entry $t.port -width 4 button $t.ok -text "OK" -command {set ::tkcon::PRIV(grab) 1} bind $t.host [list focus $t.port] bind $t.port [list focus $t.ok] bind $t.ok [list $t.ok invoke] grid $t.lhost $t.host $t.lport $t.port -sticky ew grid $t.ok - - - -sticky ew grid columnconfig $t 1 -weight 1 grid rowconfigure $t 1 -weight 1 wm transient $t $PRIV(root) wm geometry $t +[expr {([winfo screenwidth $t]-[winfo \ reqwidth $t]) / 2}]+[expr {([winfo \ screenheight $t]-[winfo reqheight $t]) / 2}] } #$t.host delete 0 end #$t.port delete 0 end wm deiconify $t raise $t grab $t focus $t.host vwait ::tkcon::PRIV(grab) grab release $t wm withdraw $t set host [$t.host get] set port [$t.port get] if {$host == ""} { return } if {[catch { set sock [socket $host $port] } err]} { tk_messageBox -title "Socket Connection Error" \ -message "Unable to connect to \"$host:$port\":\n$err" \ -icon error -type ok } else { Attach $sock socket } } ## ::tkcon::Load - sources a file into the console ## The file is actually sourced in the currently attached's interp # ARGS: fn - (optional) filename to source in # Returns: selected filename ({} if nothing was selected) ## proc ::tkcon::Load { {fn ""} } { set types { {{Tcl Files} {.tcl .tk}} {{Text Files} {.txt}} {{All Files} *} } if { [string match {} $fn] && ([catch {tk_getOpenFile -filetypes $types \ -title "Source File"} fn] || [string match {} $fn]) } { return } EvalAttached [list source $fn] } ## ::tkcon::Save - saves the console or other widget buffer to a file ## This does not eval in a slave because it's not necessary # ARGS: w - console text widget # fn - (optional) filename to save to ## proc ::tkcon::Save { {fn ""} {type ""} {opt ""} {mode w} } { variable PRIV if {![regexp -nocase {^(all|history|stdin|stdout|stderr|widget)$} $type]} { array set s { 0 All 1 History 2 Stdin 3 Stdout 4 Stderr 5 Cancel } ## Allow user to specify what kind of stuff to save set type [tk_dialog $PRIV(base).savetype "Save Type" \ "What part of the text do you want to save?" \ questhead 0 $s(0) $s(1) $s(2) $s(3) $s(4) $s(5)] if {$type == 5 || $type == -1} return set type $s($type) } if {[string match {} $fn]} { set types { {{Tcl Files} {.tcl .tk}} {{Text Files} {.txt}} {{All Files} *} } if {[catch {tk_getSaveFile -defaultextension .tcl -filetypes $types \ -title "Save $type"} fn] || [string match {} $fn]} return } set type [string tolower $type] switch $type { stdin - stdout - stderr { set data {} foreach {first last} [$PRIV(console) tag ranges $type] { lappend data [$PRIV(console) get $first $last] } set data [join $data \n] } history { set data [tkcon history] } all - default { set data [$PRIV(console) get 1.0 end-1c] } widget { set data [$opt get 1.0 end-1c] } } if {[catch {open $fn $mode} fid]} { return -code error "Save Error: Unable to open '$fn' for writing\n$fid" } puts -nonewline $fid $data close $fid } ## ::tkcon::MainInit ## This is only called for the main interpreter to include certain procs ## that we don't want to include (or rather, just alias) in slave interps. ## proc ::tkcon::MainInit {} { variable PRIV if {![info exists PRIV(slaves)]} { array set PRIV [list slave 0 slaves Main name {} \ interps [list [tk appname]]] } interp alias {} ::tkcon::Main {} ::tkcon::InterpEval Main interp alias {} ::tkcon::Slave {} ::tkcon::InterpEval proc ::tkcon::GetSlaveNum {} { set i -1 while {[interp exists Slave[incr i]]} { # oh my god, an empty loop! } return $i } ## ::tkcon::New - create new console window ## Creates a slave interpreter and sources in this script. ## All other interpreters also get a command to eval function in the ## new interpreter. ## proc ::tkcon::New {} { variable PRIV global argv0 argc argv set tmp [interp create Slave[GetSlaveNum]] lappend PRIV(slaves) $tmp load {} Tk $tmp lappend PRIV(interps) [$tmp eval [list tk appname \ "[tk appname] $tmp"]] if {[info exist argv0]} {$tmp eval [list set argv0 $argv0]} $tmp eval set argc $argc $tmp eval [list set argv $argv] $tmp eval [list namespace eval ::tkcon {}] $tmp eval [list set ::tkcon::PRIV(name) $tmp] $tmp eval [list set ::tkcon::PRIV(SCRIPT) $::tkcon::PRIV(SCRIPT)] $tmp alias exit ::tkcon::Exit $tmp $tmp alias ::tkcon::Destroy ::tkcon::Destroy $tmp $tmp alias ::tkcon::New ::tkcon::New $tmp alias ::tkcon::Main ::tkcon::InterpEval Main $tmp alias ::tkcon::Slave ::tkcon::InterpEval $tmp alias ::tkcon::Interps ::tkcon::Interps $tmp alias ::tkcon::NewDisplay ::tkcon::NewDisplay $tmp alias ::tkcon::Display ::tkcon::Display $tmp alias ::tkcon::StateCheckpoint ::tkcon::StateCheckpoint $tmp alias ::tkcon::StateCleanup ::tkcon::StateCleanup $tmp alias ::tkcon::StateCompare ::tkcon::StateCompare $tmp alias ::tkcon::StateRevert ::tkcon::StateRevert $tmp eval { if [catch {source -rsrc tkcon}] { source $::tkcon::PRIV(SCRIPT) } } return $tmp } ## ::tkcon::Exit - full exit OR destroy slave console ## This proc should only be called in the main interpreter from a slave. ## The master determines whether we do a full exit or just kill the slave. ## proc ::tkcon::Exit {slave args} { variable PRIV variable OPT ## Slave interpreter exit request if {[string match exit $OPT(slaveexit)]} { ## Only exit if it specifically is stated to do so uplevel 1 exit $args } ## Otherwise we will delete the slave interp and associated data set name [InterpEval $slave] set PRIV(interps) [lremove $PRIV(interps) [list $name]] set PRIV(slaves) [lremove $PRIV(slaves) [list $slave]] interp delete $slave StateCleanup $slave return } ## ::tkcon::Destroy - destroy console window ## This proc should only be called by the main interpreter. If it is ## called from there, it will ask before exiting tkcon. All others ## (slaves) will just have their slave interpreter deleted, closing them. ## proc ::tkcon::Destroy {{slave {}}} { variable PRIV if {[string match {} $slave]} { ## Main interpreter close request if {[tk_dialog $PRIV(base).destroyme {Quit tkcon?} \ {Closing the Main console will quit tkcon} \ warning 0 "Don't Quit" "Quit tkcon"]} exit } else { ## Slave interpreter close request set name [InterpEval $slave] set PRIV(interps) [lremove $PRIV(interps) [list $name]] set PRIV(slaves) [lremove $PRIV(slaves) [list $slave]] interp delete $slave } StateCleanup $slave return } ## We want to do a couple things before exiting... if {[catch {rename ::exit ::tkcon::FinalExit} err]} { puts stderr "tkcon might panic:\n$err" } proc ::exit args { if {$::tkcon::OPT(usehistory)} { if {[catch {open $::tkcon::PRIV(histfile) w} fid]} { puts stderr "unable to save history file:\n$fid" # pause a moment, because we are about to die finally... after 1000 } else { set max [::tkcon::EvalSlave history nextid] set id [expr {$max - $::tkcon::OPT(history)}] if {$id < 1} { set id 1 } ## FIX: This puts history in backwards!! while {($id < $max) && \ ![catch {::tkcon::EvalSlave history event $id} cmd]} { if {[string compare {} $cmd]} { puts $fid "::tkcon::EvalSlave history add [list $cmd]" } incr id } close $fid } } uplevel 1 ::tkcon::FinalExit $args } ## ::tkcon::InterpEval - passes evaluation to another named interpreter ## If the interpreter is named, but no args are given, it returns the ## [tk appname] of that interps master (not the associated eval slave). ## proc ::tkcon::InterpEval {{slave {}} args} { variable PRIV if {[string match {} $slave]} { return $PRIV(slaves) } elseif {[string match {[Mm]ain} $slave]} { set slave {} } if {[llength $args]} { return [interp eval $slave uplevel \#0 $args] } else { return [interp eval $slave tk appname] } } proc ::tkcon::Interps {{ls {}} {interp {}}} { if {[string match {} $interp]} { lappend ls {} [tk appname] } foreach i [interp slaves $interp] { if {[string compare {} $interp]} { set i "$interp $i" } if {[string compare {} [interp eval $i package provide Tk]]} { lappend ls $i [interp eval $i tk appname] } else { lappend ls $i {} } set ls [Interps $ls $i] } return $ls } proc ::tkcon::Display {{disp {}}} { variable DISP set res {} if {$disp != ""} { if {![info exists DISP($disp)]} { return } return [list $DISP($disp) [winfo interps -displayof $DISP($disp)]] } return [lsort -dictionary [array names DISP]] } proc ::tkcon::NewDisplay {} { variable PRIV variable DISP set t $PRIV(base).newdisp if {![winfo exists $t]} { toplevel $t wm withdraw $t wm title $t "tkcon Attach to Display" label $t.gets -text "New Display: " entry $t.data -width 32 button $t.ok -text "OK" -command {set ::tkcon::PRIV(grab) 1} bind $t.data [list $t.ok invoke] bind $t.ok [list $t.ok invoke] grid $t.gets $t.data -sticky ew grid $t.ok - -sticky ew grid columnconfig $t 1 -weight 1 grid rowconfigure $t 1 -weight 1 wm transient $t $PRIV(root) wm geometry $t +[expr {([winfo screenwidth $t]-[winfo \ reqwidth $t]) / 2}]+[expr {([winfo \ screenheight $t]-[winfo reqheight $t]) / 2}] } $t.data delete 0 end wm deiconify $t raise $t grab $t focus $t.data vwait ::tkcon::PRIV(grab) grab release $t wm withdraw $t set disp [$t.data get] if {$disp == ""} { return } regsub -all {\.} [string tolower $disp] ! dt set dt $PRIV(base).$dt destroy $dt if {[catch { toplevel $dt -screen $disp set interps [winfo interps -displayof $dt] if {![llength $interps]} { error "No other Tk interpreters on $disp" } send -displayof $dt [lindex $interps 0] [list info tclversion] } err]} { global env if {[info exists env(DISPLAY)]} { set myd $env(DISPLAY) } else { set myd "myDisplay:0" } tk_messageBox -title "Display Connection Error" \ -message "Unable to connect to \"$disp\":\n$err\ \nMake sure you have xauth-based permissions\ (xauth add $myd . `mcookie`), and xhost is disabled\ (xhost -) on \"$disp\"" \ -icon error -type ok destroy $dt return } set DISP($disp) $dt wm withdraw $dt bind $dt [subst {catch {unset ::tkcon::DISP($disp)}}] tk_messageBox -title "$disp Connection" \ -message "Connected to \"$disp\", found:\n[join $interps \n]" \ -type ok } ## ## The following state checkpoint/revert procedures are very sketchy ## and prone to problems. They do not track modifications to currently ## existing procedures/variables, and they can really screw things up ## if you load in libraries (especially Tk) between checkpoint and ## revert. Only with this knowledge in mind should you use these. ## ## ::tkcon::StateCheckpoint - checkpoints the current state of the system ## This allows you to return to this state with ::tkcon::StateRevert # ARGS: ## proc ::tkcon::StateCheckpoint {app type} { variable CPS variable PRIV if {[info exists CPS($type,$app,cmd)] && \ [tk_dialog $PRIV(base).warning "Overwrite Previous State?" \ "Are you sure you want to lose previously checkpointed\ state of $type \"$app\"?" questhead 1 "Do It" "Cancel"]} return set CPS($type,$app,cmd) [EvalOther $app $type info commands *] set CPS($type,$app,var) [EvalOther $app $type info vars *] return } ## ::tkcon::StateCompare - compare two states and output difference # ARGS: ## proc ::tkcon::StateCompare {app type {verbose 0}} { variable CPS variable PRIV variable OPT variable COLOR if {![info exists CPS($type,$app,cmd)]} { return -code error \ "No previously checkpointed state for $type \"$app\"" } set w $PRIV(base).compare if {[winfo exists $w]} { $w.text config -state normal $w.text delete 1.0 end } else { toplevel $w frame $w.btn scrollbar $w.sy -takefocus 0 -bd 1 -command [list $w.text yview] text $w.text -yscrollcommand [list $w.sy set] -height 12 \ -foreground $COLOR(stdin) \ -background $COLOR(bg) \ -insertbackground $COLOR(cursor) \ -font $OPT(font) pack $w.btn -side bottom -fill x pack $w.sy -side right -fill y pack $w.text -fill both -expand 1 button $w.btn.close -text "Dismiss" -width 11 \ -command [list destroy $w] button $w.btn.check -text "Recheckpoint" -width 11 button $w.btn.revert -text "Revert" -width 11 button $w.btn.expand -text "Verbose" -width 11 button $w.btn.update -text "Update" -width 11 pack $w.btn.check $w.btn.revert $w.btn.expand $w.btn.update \ $w.btn.close -side left -fill x -padx 4 -pady 2 -expand 1 $w.text tag config red -foreground red } wm title $w "Compare State: $type [list $app]" $w.btn.check config \ -command "::tkcon::StateCheckpoint [list $app] $type; \ ::tkcon::StateCompare [list $app] $type $verbose" $w.btn.revert config \ -command "::tkcon::StateRevert [list $app] $type; \ ::tkcon::StateCompare [list $app] $type $verbose" $w.btn.update config -command [info level 0] if {$verbose} { $w.btn.expand config -text Brief \ -command [list ::tkcon::StateCompare $app $type 0] } else { $w.btn.expand config -text Verbose \ -command [list ::tkcon::StateCompare $app $type 1] } ## Don't allow verbose mode unless 'dump' exists in $app ## We're assuming this is tkcon's dump command set hasdump [llength [EvalOther $app $type info commands dump]] if {$hasdump} { $w.btn.expand config -state normal } else { $w.btn.expand config -state disabled } set cmds [lremove [EvalOther $app $type info commands *] \ $CPS($type,$app,cmd)] set vars [lremove [EvalOther $app $type info vars *] \ $CPS($type,$app,var)] if {$hasdump && $verbose} { set cmds [EvalOther $app $type eval dump c -nocomplain $cmds] set vars [EvalOther $app $type eval dump v -nocomplain $vars] } $w.text insert 1.0 "NEW COMMANDS IN \"$app\":\n" red \ $cmds {} "\n\nNEW VARIABLES IN \"$app\":\n" red $vars {} raise $w $w.text config -state disabled } ## ::tkcon::StateRevert - reverts interpreter to previous state # ARGS: ## proc ::tkcon::StateRevert {app type} { variable CPS variable PRIV if {![info exists CPS($type,$app,cmd)]} { return -code error \ "No previously checkpointed state for $type \"$app\"" } if {![tk_dialog $PRIV(base).warning "Revert State?" \ "Are you sure you want to revert the state in $type \"$app\"?"\ questhead 1 "Do It" "Cancel"]} { foreach i [lremove [EvalOther $app $type info commands *] \ $CPS($type,$app,cmd)] { catch {EvalOther $app $type rename $i {}} } foreach i [lremove [EvalOther $app $type info vars *] \ $CPS($type,$app,var)] { catch {EvalOther $app $type unset $i} } } } ## ::tkcon::StateCleanup - cleans up state information in master array # ## proc ::tkcon::StateCleanup {args} { variable CPS if {![llength $args]} { foreach state [array names CPS slave,*] { if {![interp exists [string range $state 6 end]]} { unset CPS($state) } } } else { set app [lindex $args 0] set type [lindex $args 1] if {[regexp {^(|slave)$} $type]} { foreach state [array names CPS "slave,$app\[, \]*"] { if {![interp exists [string range $state 6 end]]} { unset CPS($state) } } } else { catch {unset CPS($type,$app)} } } } } ## ::tkcon::Event - get history event, search if string != {} ## look forward (next) if $int>0, otherwise look back (prev) # ARGS: W - console widget ## proc ::tkcon::Event {int {str {}}} { if {!$int} return variable PRIV set w $PRIV(console) set nextid [EvalSlave history nextid] if {[string compare {} $str]} { ## String is not empty, do an event search set event $PRIV(event) if {$int < 0 && $event == $nextid} { set PRIV(cmdbuf) $str } set len [string len $PRIV(cmdbuf)] incr len -1 if {$int > 0} { ## Search history forward while {$event < $nextid} { if {[incr event] == $nextid} { $w delete limit end $w insert limit $PRIV(cmdbuf) break } elseif { ![catch {EvalSlave history event $event} res] && [set p [string first $PRIV(cmdbuf) $res]] > -1 } { set p2 [expr {$p + [string length $PRIV(cmdbuf)]}] $w delete limit end $w insert limit $res Blink $w "limit + $p c" "limit + $p2 c" break } } set PRIV(event) $event } else { ## Search history reverse while {![catch {EvalSlave history event [incr event -1]} res]} { if {[set p [string first $PRIV(cmdbuf) $res]] > -1} { set p2 [expr {$p + [string length $PRIV(cmdbuf)]}] $w delete limit end $w insert limit $res set PRIV(event) $event Blink $w "limit + $p c" "limit + $p2 c" break } } } } else { ## String is empty, just get next/prev event if {$int > 0} { ## Goto next command in history if {$PRIV(event) < $nextid} { $w delete limit end if {[incr PRIV(event)] == $nextid} { $w insert limit $PRIV(cmdbuf) } else { $w insert limit [EvalSlave history event $PRIV(event)] } } } else { ## Goto previous command in history if {$PRIV(event) == $nextid} { set PRIV(cmdbuf) [CmdGet $w] } if {[catch {EvalSlave history event [incr PRIV(event) -1]} res]} { incr PRIV(event) } else { $w delete limit end $w insert limit $res } } } $w mark set insert end $w see end } ## ::tkcon::ErrorHighlight - magic error highlighting ## beware: voodoo included # ARGS: ## proc ::tkcon::ErrorHighlight w { variable COLOR ## do voodoo here set app [Attach] # we have to pull the text out, because text regexps are screwed on \n's. set info [$w get 1.0 end-1c] # Check for specific line error in a proc set exp(proc) "\"(\[^\"\]+)\"\n\[\t \]+\\\(procedure \"(\[^\"\]+)\"" # Check for too few args to a proc set exp(param) "parameter \"(\[^\"\]+)\" to \"(\[^\"\]+)\"" set start 1.0 while { [regexp -indices -- $exp(proc) $info junk what cmd] || [regexp -indices -- $exp(param) $info junk what cmd] } { foreach {w0 w1} $what {c0 c1} $cmd {break} set what [string range $info $w0 $w1] set cmd [string range $info $c0 $c1] if {[string match *::* $cmd]} { set res [uplevel 1 ::tkcon::EvalOther $app namespace eval \ [list [namespace qualifiers $cmd] \ [list info procs [namespace tail $cmd]]]] } else { set res [uplevel 1 ::tkcon::EvalOther $app info procs [list $cmd]] } if {[llength $res]==1} { set tag [UniqueTag $w] $w tag add $tag $start+${c0}c $start+1c+${c1}c $w tag configure $tag -foreground $COLOR(stdout) $w tag bind $tag [list $w tag configure $tag -underline 1] $w tag bind $tag [list $w tag configure $tag -underline 0] $w tag bind $tag "if {!\$tkPriv(mouseMoved)} \ {[list edit -attach $app -type proc -find $what -- $cmd]}" } set info [string range $info $c1 end] set start [$w index $start+${c1}c] } ## Next stage, check for procs that start a line set start 1.0 set exp(cmd) "^\"\[^\" \t\n\]+" while { [string compare {} [set ix \ [$w search -regexp -count numc -- $exp(cmd) $start end]]] } { set start [$w index $ix+${numc}c] # +1c to avoid the first quote set cmd [$w get $ix+1c $start] if {[string match *::* $cmd]} { set res [uplevel 1 ::tkcon::EvalOther $app namespace eval \ [list [namespace qualifiers $cmd] \ [list info procs [namespace tail $cmd]]]] } else { set res [uplevel 1 ::tkcon::EvalOther $app info procs [list $cmd]] } if {[llength $res]==1} { set tag [UniqueTag $w] $w tag add $tag $ix+1c $start $w tag configure $tag -foreground $COLOR(proc) $w tag bind $tag [list $w tag configure $tag -underline 1] $w tag bind $tag [list $w tag configure $tag -underline 0] $w tag bind $tag "if {!\$tkPriv(mouseMoved)} \ {[list edit -attach $app -type proc -- $cmd]}" } } } ## tkcon - command that allows control over the console ## This always exists in the main interpreter, and is aliased into ## other connected interpreters # ARGS: totally variable, see internal comments ## proc tkcon {cmd args} { global errorInfo switch -glob -- $cmd { buf* { ## 'buffer' Sets/Query the buffer size if {[llength $args]} { if {[regexp {^[1-9][0-9]*$} $args]} { set ::tkcon::OPT(buffer) $args # catch in case the console doesn't exist yet catch {::tkcon::ConstrainBuffer $::tkcon::PRIV(console) \ $::tkcon::OPT(buffer)} } else { return -code error "buffer must be a valid integer" } } return $::tkcon::OPT(buffer) } bg* { ## 'bgerror' Brings up an error dialog set errorInfo [lindex $args 1] bgerror [lindex $args 0] } cl* { ## 'close' Closes the console ::tkcon::Destroy } cons* { ## 'console' - passes the args to the text widget of the console. set result [uplevel 1 $::tkcon::PRIV(console) $args] ::tkcon::ConstrainBuffer $::tkcon::PRIV(console) \ $::tkcon::OPT(buffer) return $result } congets { ## 'congets' a replacement for [gets stdin] # Use the 'gets' alias of 'tkcon_gets' command instead of # calling the *get* methods directly for best compatability if {[llength $args] > 1} { return -code error "wrong # args: must be \"tkcon congets [pfix]\"" } tkcon show set old [bind TkConsole <>] bind TkConsole <> { set ::tkcon::PRIV(wait) 0 } set w $::tkcon::PRIV(console) # Make sure to move the limit to get the right data $w mark set insert end if {[llength $args]} { $w mark set limit insert $w insert end $args } else { $w mark set limit insert } $w see end vwait ::tkcon::PRIV(wait) set line [::tkcon::CmdGet $w] $w insert end \n bind TkConsole <> $old return $line } getc* { ## 'getcommand' a replacement for [gets stdin] ## This forces a complete command to be input though if {[llength $args]} { return -code error "wrong # args: must be \"tkcon getcommand\"" } tkcon show set old [bind TkConsole <>] bind TkConsole <> { set ::tkcon::PRIV(wait) 0 } set w $::tkcon::PRIV(console) # Make sure to move the limit to get the right data $w mark set insert end $w mark set limit insert $w see end vwait ::tkcon::PRIV(wait) set line [::tkcon::CmdGet $w] $w insert end \n while {![info complete $line] || [regexp {[^\\]\\$} $line]} { vwait ::tkcon::PRIV(wait) set line [::tkcon::CmdGet $w] $w insert end \n $w see end } bind TkConsole <> $old return $line } get - gets { ## 'gets' - a replacement for [gets stdin] ## This pops up a text widget to be used for stdin (local grabbed) if {[llength $args]} { return -code error "wrong # args: should be \"tkcon gets\"" } set t $::tkcon::PRIV(base).gets if {![winfo exists $t]} { toplevel $t wm withdraw $t wm title $t "tkcon gets stdin request" label $t.gets -text "\"gets stdin\" request:" text $t.data -width 32 -height 5 -wrap none \ -xscrollcommand [list $t.sx set] \ -yscrollcommand [list $t.sy set] scrollbar $t.sx -orient h -takefocus 0 -highlightthick 0 \ -command [list $t.data xview] scrollbar $t.sy -orient v -takefocus 0 -highlightthick 0 \ -command [list $t.data yview] button $t.ok -text "OK" -command {set ::tkcon::PRIV(grab) 1} bind $t.ok { %W invoke } grid $t.gets - -sticky ew grid $t.data $t.sy -sticky news grid $t.sx -sticky ew grid $t.ok - -sticky ew grid columnconfig $t 0 -weight 1 grid rowconfig $t 1 -weight 1 wm transient $t $::tkcon::PRIV(root) wm geometry $t +[expr {([winfo screenwidth $t]-[winfo \ reqwidth $t]) / 2}]+[expr {([winfo \ screenheight $t]-[winfo reqheight $t]) / 2}] } $t.data delete 1.0 end wm deiconify $t raise $t grab $t focus $t.data vwait ::tkcon::PRIV(grab) grab release $t wm withdraw $t return [$t.data get 1.0 end-1c] } err* { ## Outputs stack caused by last error. ## error handling with pizazz (but with pizza would be nice too) if {[llength $args]==2} { set app [lindex $args 0] set type [lindex $args 1] if {[catch {::tkcon::EvalOther $app $type set errorInfo} info]} { set info "error getting info from $type $app:\n$info" } } else { set info $::tkcon::PRIV(errorInfo) } if {[string match {} $info]} { set info "errorInfo empty" } ## If args is empty, the -attach switch just ignores it edit -attach $args -type error -- $info } fi* { ## 'find' string ::tkcon::Find $::tkcon::PRIV(console) $args } fo* { ## 'font' ?fontname? - gets/sets the font of the console if {[llength $args]} { if {[info exists ::tkcon::PRIV(console)] && \ [winfo exists $::tkcon::PRIV(console)]} { $::tkcon::PRIV(console) config -font $args set ::tkcon::OPT(font) [$::tkcon::PRIV(console) cget -font] } else { set ::tkcon::OPT(font) $args } } return $::tkcon::OPT(font) } hid* - with* { ## 'hide' 'withdraw' - hides the console. wm withdraw $::tkcon::PRIV(root) } his* { ## 'history' set sub {\2} if {[string match -new* $args]} { append sub "\n"} set h [::tkcon::EvalSlave history] regsub -all "( *\[0-9\]+ |\t)(\[^\n\]*\n?)" $h $sub h return $h } ico* { ## 'iconify' - iconifies the console with 'iconify'. wm iconify $::tkcon::PRIV(root) } mas* - eval { ## 'master' - evals contents in master interpreter uplevel \#0 $args } set { ## 'set' - set (or get, or unset) simple vars (not whole arrays) ## from the master console interpreter ## possible formats: ## tkcon set ## tkcon set ## tkcon set w ## tkcon set u ## tkcon set r if {[llength $args]==5} { ## This is for use w/ 'tkcon upvar' and only works with slaves foreach {var i var1 var2 op} $args break if {[string compare {} $var2]} { append var1 "($var2)" } switch $op { u { uplevel \#0 [list unset $var] } w { return [uplevel \#0 [list set $var \ [interp eval $i [list set $var1]]]] } r { return [interp eval $i [list set $var1 \ [uplevel \#0 [list set $var]]]] } } } elseif {[llength $args] == 1} { upvar \#0 [lindex $args 0] var if {[array exists var]} { return [array get var] } else { return $var } } return [uplevel \#0 set $args] } append { ## Modify a var in the master environment using append return [uplevel \#0 append $args] } lappend { ## Modify a var in the master environment using lappend return [uplevel \#0 lappend $args] } sh* - dei* { ## 'show|deiconify' - deiconifies the console. wm deiconify $::tkcon::PRIV(root) raise $::tkcon::PRIV(root) focus -force $::tkcon::PRIV(console) } ti* { ## 'title' ?title? - gets/sets the console's title if {[llength $args]} { return [wm title $::tkcon::PRIV(root) [join $args]] } else { return [wm title $::tkcon::PRIV(root)] } } upv* { ## 'upvar' masterVar slaveVar ## link slave variable slaveVar to the master variable masterVar ## only works masters<->slave set masterVar [lindex $args 0] set slaveVar [lindex $args 1] if {[info exists $masterVar]} { interp eval $::tkcon::OPT(exec) \ [list set $slaveVar [set $masterVar]] } else { catch {interp eval $::tkcon::OPT(exec) [list unset $slaveVar]} } interp eval $::tkcon::OPT(exec) \ [list trace variable $slaveVar rwu \ [list tkcon set $masterVar $::tkcon::OPT(exec)]] return } v* { return $::tkcon::PRIV(version) } default { ## tries to determine if the command exists, otherwise throws error set new ::tkcon::[string toupper \ [string index $cmd 0]][string range $cmd 1 end] if {[llength [info command $new]]} { uplevel \#0 $new $args } else { return -code error "bad option \"$cmd\": must be\ [join [lsort [list attach close console destroy \ font hide iconify load main master new save show \ slave deiconify version title bgerror]] {, }]" } } } } ## ## Some procedures to make up for lack of built-in shell commands ## ## tkcon_puts - ## This allows me to capture all stdout/stderr to the console window ## This will be renamed to 'puts' at the appropriate time during init ## # ARGS: same as usual # Outputs: the string with a color-coded text tag ## proc tkcon_puts args { set len [llength $args] foreach {arg1 arg2 arg3} $args { break } if {$len == 1} { set sarg $arg1 set nl 1 set farg stdout } elseif {$len == 2} { if {![string compare $arg1 -nonewline]} { set sarg $arg2 set farg stdout set nl 0 } elseif {![string compare $arg1 stdout] \ || ![string compare $arg1 stderr]} { set sarg $arg2 set farg $arg1 set nl 1 } else { set len 0 } } elseif {$len == 3} { if {![string compare $arg1 -nonewline] \ && (![string compare $arg2 stdout] \ || ![string compare $arg2 stderr])} { set sarg $arg3 set farg $arg2 set nl 0 } elseif {(![string compare $arg1 stdout] \ || ![string compare $arg1 stderr]) \ && ![string compare $arg3 nonewline]} { set sarg $arg2 set farg $arg1 set nl 0 } else { set len 0 } } else { set len 0 } ## $len == 0 means it wasn't handled by tkcon above. ## if {$len != 0} { ## "poor man's" \r substitution---erase everything on the output ## line and print from character after the \r set rpt [string last \r $sarg] if {$rpt >= 0} { tkcon console delete "insert linestart" "insert lineend" set sarg [string range $sarg [expr {$rpt + 1}] end] } set bpt [string first \b $sarg] if {$bpt >= 0} { set narg [string range $sarg [expr {$bpt + 1}] end] set sarg [string range $sarg 0 [expr {$bpt - 1}]] set nl 0 } if {$nl == 0} { tkcon console insert output $sarg $farg } else { tkcon console insert output "$sarg\n" $farg } if {$bpt >= 0} { tkcon console delete "insert -1 char" insert if {$nl == 0} { tkcon_puts $farg $narg nonewline } else { tkcon_puts $farg $narg } } } else { global errorCode errorInfo if {[catch "tkcon_tcl_puts $args" msg]} { regsub tkcon_tcl_puts $msg puts msg regsub -all tkcon_tcl_puts $errorInfo puts errorInfo return -code error $msg } return $msg } ## WARNING: This update should behave well because it uses idletasks, ## however, if there are weird looping problems with events, or ## hanging in waits, try commenting this out. if {$len} { tkcon console see output update idletasks } } ## tkcon_gets - ## This allows me to capture all stdin input without needing to stdin ## This will be renamed to 'gets' at the appropriate time during init ## # ARGS: same as gets # Outputs: same as gets ## proc tkcon_gets args { set len [llength $args] if {$len != 1 && $len != 2} { return -code error \ "wrong # args: should be \"gets channelId ?varName?\"" } if {[string compare stdin [lindex $args 0]]} { return [uplevel 1 tkcon_tcl_gets $args] } set gtype [tkcon set ::tkcon::OPT(gets)] if {$gtype == ""} { set gtype congets } set data [tkcon $gtype] if {$len == 2} { upvar 1 [lindex $args 1] var set var $data return [string length $data] } return $data } ## edit - opens a file/proc/var for reading/editing ## # Arguments: # type proc/file/var # what the actual name of the item # Returns: nothing ## proc edit {args} { array set opts {-find {} -type {} -attach {}} while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -f* { set opts(-find) [lindex $args 1] } -a* { set opts(-attach) [lindex $args 1] } -t* { set opts(-type) [lindex $args 1] } -- { set args [lreplace $args 0 0]; break } default {return -code error "unknown option \"[lindex $args 0]\""} } set args [lreplace $args 0 1] } # determine who we are dealing with if {[llength $opts(-attach)]} { foreach {app type} $opts(-attach) {break} } else { foreach {app type} [tkcon attach] {break} } set word [lindex $args 0] if {[string match {} $opts(-type)]} { if {[llength [::tkcon::EvalOther $app $type info commands [list $word]]]} { set opts(-type) "proc" } elseif {[llength [::tkcon::EvalOther $app $type info vars [list $word]]]} { set opts(-type) "var" } elseif {[::tkcon::EvalOther $app $type file isfile [list $word]]} { set opts(-type) "file" } } if {[string compare $opts(-type) {}]} { # Create unique edit window toplevel set w $::tkcon::PRIV(base).__edit set i 0 while {[winfo exists $w[incr i]]} {} append w $i toplevel $w wm withdraw $w if {[string length $word] > 12} { wm title $w "tkcon Edit: [string range $word 0 9]..." } else { wm title $w "tkcon Edit: $word" } text $w.text -wrap none \ -xscrollcommand [list $w.sx set] \ -yscrollcommand [list $w.sy set] \ -foreground $::tkcon::COLOR(stdin) \ -background $::tkcon::COLOR(bg) \ -insertbackground $::tkcon::COLOR(cursor) \ -font $::tkcon::OPT(font) scrollbar $w.sx -orient h -takefocus 0 -bd 1 \ -command [list $w.text xview] scrollbar $w.sy -orient v -takefocus 0 -bd 1 \ -command [list $w.text yview] set menu [menu $w.mbar] $w configure -menu $menu ## File Menu ## set m [menu [::tkcon::MenuButton $menu File file]] $m add command -label "Save As..." -underline 0 \ -command [list ::tkcon::Save {} widget $w.text] $m add command -label "Append To..." -underline 0 \ -command [list ::tkcon::Save {} widget $w.text a+] $m add separator $m add command -label "Dismiss" -underline 0 -accel "Ctrl-w" \ -command [list destroy $w] bind $w [list destroy $w] bind $w <$::tkcon::PRIV(meta)-w> [list destroy $w] ## Edit Menu ## set text $w.text set m [menu [::tkcon::MenuButton $menu Edit edit]] $m add command -label "Cut" -underline 2 \ -command [list tk_textCut $text] $m add command -label "Copy" -underline 0 \ -command [list tk_textCopy $text] $m add command -label "Paste" -underline 0 \ -command [list tk_textPaste $text] $m add separator $m add command -label "Find" -underline 0 \ -command [list ::tkcon::FindBox $text] ## Send To Menu ## set m [menu [::tkcon::MenuButton $menu "Send To..." send]] $m add command -label "Send To $app" -underline 0 \ -command "::tkcon::EvalOther [list $app] $type \ eval \[$w.text get 1.0 end-1c\]" set other [tkcon attach] if {[string compare $other [list $app $type]]} { $m add command -label "Send To [lindex $other 0]" \ -command "::tkcon::EvalOther $other \ eval \[$w.text get 1.0 end-1c\]" } grid $w.text - $w.sy -sticky news grid $w.sx - -sticky ew grid columnconfigure $w 0 -weight 1 grid columnconfigure $w 1 -weight 1 grid rowconfigure $w 0 -weight 1 } else { return -code error "unrecognized type '$word'" } switch -glob -- $opts(-type) { proc* { $w.text insert 1.0 \ [::tkcon::EvalOther $app $type dump proc [list $word]] } var* { $w.text insert 1.0 \ [::tkcon::EvalOther $app $type dump var [list $word]] } file { $w.text insert 1.0 [::tkcon::EvalOther $app $type eval \ [subst -nocommands { set __tkcon(fid) [open $word r] set __tkcon(data) [read \$__tkcon(fid)] close \$__tkcon(fid) after 1000 unset __tkcon return \$__tkcon(data) } ]] } error* { $w.text insert 1.0 [join $args \n] ::tkcon::ErrorHighlight $w.text } default { $w.text insert 1.0 [join $args \n] } } wm deiconify $w focus $w.text if {[string compare $opts(-find) {}]} { ::tkcon::Find $w.text $opts(-find) -case 1 } } interp alias {} ::more {} ::edit interp alias {} ::less {} ::edit ## echo ## Relaxes the one string restriction of 'puts' # ARGS: any number of strings to output to stdout ## proc echo args { puts [concat $args] } ## clear - clears the buffer of the console (not the history though) ## This is executed in the parent interpreter ## proc clear {{pcnt 100}} { if {![regexp {^[0-9]*$} $pcnt] || $pcnt < 1 || $pcnt > 100} { return -code error \ "invalid percentage to clear: must be 1-100 (100 default)" } elseif {$pcnt == 100} { tkcon console delete 1.0 end } else { set tmp [expr {$pcnt/100.0*[tkcon console index end]}] tkcon console delete 1.0 "$tmp linestart" } } ## alias - akin to the csh alias command ## If called with no args, then it dumps out all current aliases ## If called with one arg, returns the alias of that arg (or {} if none) # ARGS: newcmd - (optional) command to bind alias to # args - command and args being aliased ## proc alias {{newcmd {}} args} { if {[string match {} $newcmd]} { set res {} foreach a [interp aliases] { lappend res [list $a -> [interp alias {} $a]] } return [join $res \n] } elseif {![llength $args]} { interp alias {} $newcmd } else { eval interp alias [list {} $newcmd {}] $args } } ## unalias - unaliases an alias'ed command # ARGS: cmd - command to unbind as an alias ## proc unalias {cmd} { interp alias {} $cmd {} } ## dump - outputs variables/procedure/widget info in source'able form. ## Accepts glob style pattern matching for the names # # ARGS: type - type of thing to dump: must be variable, procedure, widget # # OPTS: -nocomplain # don't complain if no items of the specified type are found # -filter pattern # specifies a glob filter pattern to be used by the variable # method as an array filter pattern (it filters down for # nested elements) and in the widget method as a config # option filter pattern # -- forcibly ends options recognition # # Returns: the values of the requested items in a 'source'able form ## proc dump {type args} { set whine 1 set code ok if {![llength $args]} { ## If no args, assume they gave us something to dump and ## we'll try anything set args $type set type any } while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -n* { set whine 0; set args [lreplace $args 0 0] } -f* { set fltr [lindex $args 1]; set args [lreplace $args 0 1] } -- { set args [lreplace $args 0 0]; break } default {return -code error "unknown option \"[lindex $args 0]\""} } } if {$whine && ![llength $args]} { return -code error "wrong \# args: [lindex [info level 0] 0] type\ ?-nocomplain? ?-filter pattern? ?--? pattern ?pattern ...?" } set res {} switch -glob -- $type { c* { # command # outputs commands by figuring out, as well as possible, what it is # this does not attempt to auto-load anything foreach arg $args { if {[llength [set cmds [info commands $arg]]]} { foreach cmd [lsort $cmds] { if {[lsearch -exact [interp aliases] $cmd] > -1} { append res "\#\# ALIAS: $cmd =>\ [interp alias {} $cmd]\n" } elseif { [llength [info procs $cmd]] || ([string match *::* $cmd] && [llength [namespace eval [namespace qual $cmd] \ info procs [namespace tail $cmd]]]) } { if {[catch {dump p -- $cmd} msg] && $whine} { set code error } append res $msg\n } else { append res "\#\# COMMAND: $cmd\n" } } } elseif {$whine} { append res "\#\# No known command $arg\n" set code error } } } v* { # variable # outputs variables value(s), whether array or simple. if {![info exists fltr]} { set fltr * } foreach arg $args { if {![llength [set vars [uplevel 1 info vars [list $arg]]]]} { if {[uplevel 1 info exists $arg]} { set vars $arg } elseif {$whine} { append res "\#\# No known variable $arg\n" set code error continue } else { continue } } foreach var [lsort $vars] { if {[uplevel 1 [list info locals $var]] == ""} { # use the proper scope of the var, but # namespace which won't id locals correctly set var [uplevel 1 \ [list namespace which -variable $var]] } upvar 1 $var v if {[array exists v] || [catch {string length $v}]} { set nst {} append res "array set [list $var] \{\n" if {[array size v]} { foreach i [lsort [array names v $fltr]] { upvar 0 v\($i\) __a if {[array exists __a]} { append nst "\#\# NESTED ARRAY ELEM: $i\n" append nst "upvar 0 [list $var\($i\)] __a;\ [dump v -filter $fltr __a]\n" } else { append res " [list $i]\t[list $v($i)]\n" } } } else { ## empty array append res " empty array\n" append nst "unset [list $var](empty)\n" } append res "\}\n$nst" } else { append res [list set $var $v]\n } } } } p* { # procedure foreach arg $args { if { ![llength [set procs [info proc $arg]]] && ([string match *::* $arg] && [llength [set ps [namespace eval \ [namespace qualifier $arg] \ info procs [namespace tail $arg]]]]) } { set procs {} set namesp [namespace qualifier $arg] foreach p $ps { lappend procs ${namesp}::$p } } if {[llength $procs]} { foreach p [lsort $procs] { set as {} foreach a [info args $p] { if {[info default $p $a tmp]} { lappend as [list $a $tmp] } else { lappend as $a } } append res [list proc $p $as [info body $p]]\n } } elseif {$whine} { append res "\#\# No known proc $arg\n" set code error } } } w* { # widget ## The user should have Tk loaded if {![llength [info command winfo]]} { return -code error "winfo not present, cannot dump widgets" } if {![info exists fltr]} { set fltr .* } foreach arg $args { if {[llength [set ws [info command $arg]]]} { foreach w [lsort $ws] { if {[winfo exists $w]} { if {[catch {$w configure} cfg]} { append res "\#\# Widget $w\ does not support configure method" set code error } else { append res "\#\# [winfo class $w]\ $w\n$w configure" foreach c $cfg { if {[llength $c] != 5} continue ## Check to see that the option does ## not match the default, then check ## the item against the user filter if {[string compare [lindex $c 3] \ [lindex $c 4]] && \ [regexp -nocase -- $fltr $c]} { append res " \\\n\t[list [lindex $c 0]\ [lindex $c 4]]" } } append res \n } } } } elseif {$whine} { append res "\#\# No known widget $arg\n" set code error } } } a* { ## see if we recognize it, other complain if {[regexp {(var|com|proc|widget)} \ [set types [uplevel 1 what $args]]]} { foreach type $types { if {[regexp {(var|com|proc|widget)} $type]} { append res "[uplevel 1 dump $type $args]\n" } } } else { set res "dump was unable to resolve type for \"$args\"" set code error } } default { return -code error "bad [lindex [info level 0] 0] option\ \"$type\": must be variable, command, procedure,\ or widget" } } return -code $code [string trimright $res \n] } ## idebug - interactive debugger # # idebug body ?level? # # Prints out the body of the command (if it is a procedure) at the # specified level. level defaults to the current level. # # idebug break # # Creates a breakpoint within a procedure. This will only trigger # if idebug is on and the id matches the pattern. If so, TkCon will # pop to the front with the prompt changed to an idebug prompt. You # are given the basic ability to observe the call stack an query/set # variables or execute Tcl commands at any level. A separate history # is maintained in debugging mode. # # idebug echo|{echo ?id?} ?args? # # Behaves just like "echo", but only triggers when idebug is on. # You can specify an optional id to further restrict triggering. # If no id is specified, it defaults to the name of the command # in which the call was made. # # idebug id ?id? # # Query or set the idebug id. This id is used by other idebug # methods to determine if they should trigger or not. The idebug # id can be a glob pattern and defaults to *. # # idebug off # # Turns idebug off. # # idebug on ?id? # # Turns idebug on. If 'id' is specified, it sets the id to it. # # idebug puts|{puts ?id?} args # # Behaves just like "puts", but only triggers when idebug is on. # You can specify an optional id to further restrict triggering. # If no id is specified, it defaults to the name of the command # in which the call was made. # # idebug show type ?level? ?VERBOSE? # # 'type' must be one of vars, locals or globals. This method # will output the variables/locals/globals present in a particular # level. If VERBOSE is added, then it actually 'dump's out the # values as well. 'level' defaults to the level in which this # method was called. # # idebug trace ?level? # # Prints out the stack trace from the specified level up to the top # level. 'level' defaults to the current level. # ## proc idebug {opt args} { global IDEBUG if {![info exists IDEBUG(on)]} { array set IDEBUG { on 0 id * debugging 0 } } set level [expr {[info level]-1}] switch -glob -- $opt { on { if {[llength $args]} { set IDEBUG(id) $args } return [set IDEBUG(on) 1] } off { return [set IDEBUG(on) 0] } id { if {![llength $args]} { return $IDEBUG(id) } else { return [set IDEBUG(id) $args] } } break { if {!$IDEBUG(on) || $IDEBUG(debugging) || \ ([llength $args] && \ ![string match $IDEBUG(id) $args]) || [info level]<1} { return } set IDEBUG(debugging) 1 puts stderr "idebug at level \#$level: [lindex [info level -1] 0]" set tkcon [llength [info command tkcon]] if {$tkcon} { tkcon master eval set ::tkcon::OPT(prompt2) \$::tkcon::OPT(prompt1) tkcon master eval set ::tkcon::OPT(prompt1) \$::tkcon::OPT(debugPrompt) set slave [tkcon set ::tkcon::OPT(exec)] set event [tkcon set ::tkcon::PRIV(event)] tkcon set ::tkcon::OPT(exec) [tkcon master interp create debugger] tkcon set ::tkcon::PRIV(event) 1 } set max $level while 1 { set err {} if {$tkcon} { # tkcon's overload of gets is advanced enough to not need # this, but we get a little better control this way. tkcon evalSlave set level $level tkcon prompt set line [tkcon getcommand] tkcon console mark set output end } else { puts -nonewline stderr "(level \#$level) debug > " gets stdin line while {![info complete $line]} { puts -nonewline "> " append line "\n[gets stdin]" } } if {[string match {} $line]} continue set key [lindex $line 0] if {![regexp {^([#-]?[0-9]+)} [lreplace $line 0 0] lvl]} { set lvl \#$level } set res {}; set c 0 switch -- $key { + { ## Allow for jumping multiple levels if {$level < $max} { idebug trace [incr level] $level 0 VERBOSE } } - { ## Allow for jumping multiple levels if {$level > 1} { idebug trace [incr level -1] $level 0 VERBOSE } } . { set c [catch {idebug trace $level $level 0 VERBOSE} res] } v { set c [catch {idebug show vars $lvl } res] } V { set c [catch {idebug show vars $lvl VERBOSE} res] } l { set c [catch {idebug show locals $lvl } res] } L { set c [catch {idebug show locals $lvl VERBOSE} res] } g { set c [catch {idebug show globals $lvl } res] } G { set c [catch {idebug show globals $lvl VERBOSE} res] } t { set c [catch {idebug trace 1 $max $level } res] } T { set c [catch {idebug trace 1 $max $level VERBOSE} res]} b { set c [catch {idebug body $lvl} res] } o { set res [set IDEBUG(on) [expr {!$IDEBUG(on)}]] } h - ? { puts stderr " + Move down in call stack - Move up in call stack . Show current proc name and params v Show names of variables currently in scope V Show names of variables currently in scope with values l Show names of local (transient) variables L Show names of local (transient) variables with values g Show names of declared global variables G Show names of declared global variables with values t Show a stack trace T Show a verbose stack trace b Show body of current proc o Toggle on/off any further debugging c,q Continue regular execution (Quit debugger) h,? Print this help default Evaluate line at current level (\#$level)" } c - q break default { set c [catch {uplevel \#$level $line} res] } } if {$tkcon} { tkcon set ::tkcon::PRIV(event) \ [tkcon evalSlave eval history add [list $line]\ \; history nextid] } if {$c} { puts stderr $res } elseif {[string compare {} $res]} { puts $res } } set IDEBUG(debugging) 0 if {$tkcon} { tkcon master interp delete debugger tkcon master eval set ::tkcon::OPT(prompt1) \$::tkcon::OPT(prompt2) tkcon set ::tkcon::OPT(exec) $slave tkcon set ::tkcon::PRIV(event) $event tkcon prompt } } bo* { if {[regexp {^([#-]?[0-9]+)} $args level]} { return [uplevel $level {dump c -no [lindex [info level 0] 0]}] } } t* { if {[llength $args]<2} return set min [set max [set lvl $level]] set exp {^#?([0-9]+)? ?#?([0-9]+) ?#?([0-9]+)? ?(VERBOSE)?} if {![regexp $exp $args junk min max lvl verbose]} return for {set i $max} { $i>=$min && ![catch {uplevel \#$i info level 0} info] } {incr i -1} { if {$i==$lvl} { puts -nonewline stderr "* \#$i:\t" } else { puts -nonewline stderr " \#$i:\t" } set name [lindex $info 0] if {[string compare VERBOSE $verbose] || \ ![llength [info procs $name]]} { puts $info } else { puts "proc $name {[info args $name]} { ... }" set idx 0 foreach arg [info args $name] { if {[string match args $arg]} { puts "\t$arg = [lrange $info [incr idx] end]" break } else { puts "\t$arg = [lindex $info [incr idx]]" } } } } } s* { #var, local, global set level \#$level if {![regexp {^([vgl][^ ]*) ?([#-]?[0-9]+)? ?(VERBOSE)?} \ $args junk type level verbose]} return switch -glob -- $type { v* { set vars [uplevel $level {lsort [info vars]}] } l* { set vars [uplevel $level {lsort [info locals]}] } g* { set vars [lremove [uplevel $level {info vars}] \ [uplevel $level {info locals}]] } } if {[string match VERBOSE $verbose]} { return [uplevel $level dump var -nocomplain $vars] } else { return $vars } } e* - pu* { if {[llength $opt]==1 && [catch {lindex [info level -1] 0} id]} { set id [lindex [info level 0] 0] } else { set id [lindex $opt 1] } if {$IDEBUG(on) && [string match $IDEBUG(id) $id]} { if {[string match e* $opt]} { puts [concat $args] } else { eval puts $args } } } default { return -code error "bad [lindex [info level 0] 0] option \"$opt\",\ must be: [join [lsort [list on off id break print body\ trace show puts echo]] {, }]" } } } ## observe - like trace, but not # ARGS: opt - option # name - name of variable or command ## proc observe {opt name args} { global tcl_observe switch -glob -- $opt { co* { if {[regexp {^(catch|lreplace|set|puts|for|incr|info|uplevel)$} \ $name]} { return -code error "cannot observe \"$name\":\ infinite eval loop will occur" } set old ${name}@ while {[llength [info command $old]]} { append old @ } rename $name $old set max 4 regexp {^[0-9]+} $args max ## idebug trace could be used here proc $name args " for {set i \[info level\]; set max \[expr \[info level\]-$max\]} { \$i>=\$max && !\[catch {uplevel \#\$i info level 0} info\] } {incr i -1} { puts -nonewline stderr \" \#\$i:\t\" puts \$info } uplevel \[lreplace \[info level 0\] 0 0 $old\] " set tcl_observe($name) $old } cd* { if {[info exists tcl_observe($name)] && [catch { rename $name {} rename $tcl_observe($name) $name unset tcl_observe($name) } err]} { return -code error $err } } ci* { ## What a useless method... if {[info exists tcl_observe($name)]} { set i $tcl_observe($name) set res "\"$name\" observes true command \"$i\"" while {[info exists tcl_observe($i)]} { append res "\n\"$name\" observes true command \"$i\"" set i $tcl_observe($name) } return $res } } va* - vd* { set type [lindex $args 0] set args [lrange $args 1 end] if {![regexp {^[rwu]} $type type]} { return -code error "bad [lindex [info level 0] 0] $opt type\ \"$type\", must be: read, write or unset" } if {![llength $args]} { set args observe_var } uplevel 1 [list trace $opt $name $type $args] } vi* { uplevel 1 [list trace vinfo $name] } default { return -code error "bad [lindex [info level 0] 0] option\ \"[lindex $args 0]\", must be: [join [lsort \ [list command cdelete cinfo variable vdelete vinfo]] {, }]" } } } ## observe_var - auxilary function for observing vars, called by trace ## via observe # ARGS: name - variable name # el - array element name, if any # op - operation type (rwu) ## proc observe_var {name el op} { if {[string match u $op]} { if {[string compare {} $el]} { puts "unset \"${name}($el)\"" } else { puts "unset \"$name\"" } } else { upvar 1 $name $name if {[info exists ${name}($el)]} { puts [dump v ${name}($el)] } else { puts [dump v $name] } } } ## which - tells you where a command is found # ARGS: cmd - command name # Returns: where command is found (internal / external / unknown) ## proc which cmd { ## This tries to auto-load a command if not recognized set types [uplevel 1 [list what $cmd 1]] if {[llength $types]} { set out {} foreach type $types { switch -- $type { alias { set res "$cmd: aliased to [alias $cmd]" } procedure { set res "$cmd: procedure" } command { set res "$cmd: internal command" } executable { lappend out [auto_execok $cmd] } variable { lappend out "$cmd: $type" } } if {[info exists res]} { global auto_index if {[info exists auto_index($cmd)]} { ## This tells you where the command MIGHT have come from - ## not true if the command was redefined interactively or ## existed before it had to be auto_loaded. This is just ## provided as a hint at where it MAY have come from append res " ($auto_index($cmd))" } lappend out $res unset res } } return [join $out \n] } else { return -code error "$cmd: command not found" } } ## what - tells you what a string is recognized as # ARGS: str - string to id # Returns: id types of command as list ## proc what {str {autoload 0}} { set types {} if {[llength [info commands $str]] || ($autoload && \ [auto_load $str] && [llength [info commands $str]])} { if {[lsearch -exact [interp aliases] $str] > -1} { lappend types "alias" } elseif { [llength [info procs $str]] || ([string match *::* $str] && [llength [namespace eval [namespace qualifier $str] \ info procs [namespace tail $str]]]) } { lappend types "procedure" } else { lappend types "command" } } if {[llength [uplevel 1 info vars $str]]} { upvar 1 $str var if {[array exists var]} { lappend types array variable } else { lappend types scalar variable } } if {[file isdirectory $str]} { lappend types "directory" } if {[file isfile $str]} { lappend types "file" } if {[llength [info commands winfo]] && [winfo exists $str]} { lappend types "widget" } if {[string compare {} [auto_execok $str]]} { lappend types "executable" } return $types } ## dir - directory list # ARGS: args - names/glob patterns of directories to list # OPTS: -all - list hidden files as well (Unix dot files) # -long - list in full format "permissions size date filename" # -full - displays / after directories and link paths for links # Returns: a directory listing ## proc dir {args} { array set s { all 0 full 0 long 0 0 --- 1 --x 2 -w- 3 -wx 4 r-- 5 r-x 6 rw- 7 rwx } while {[string match \-* [lindex $args 0]]} { set str [lindex $args 0] set args [lreplace $args 0 0] switch -glob -- $str { -a* {set s(all) 1} -f* {set s(full) 1} -l* {set s(long) 1} -- break default { return -code error "unknown option \"$str\",\ should be one of: -all, -full, -long" } } } set sep [string trim [file join . .] .] if {![llength $args]} { set args . } if {$::tcl_version >= 8.3} { # Newer glob args allow safer dir processing. The user may still # want glob chars, but really only for file matching. foreach arg $args { if {[file isdirectory $arg]} { if {$s(all)} { lappend out [list $arg [lsort \ [glob -nocomplain -directory $arg .* *]]] } else { lappend out [list $arg [lsort \ [glob -nocomplain -directory $arg *]]] } } else { set dir [file dirname $arg] lappend out [list $dir$sep [lsort \ [glob -nocomplain -directory $dir [file tail $arg]]]] } } } else { foreach arg $args { if {[file isdirectory $arg]} { set arg [string trimright $arg $sep]$sep if {$s(all)} { lappend out [list $arg [lsort [glob -nocomplain -- $arg.* $arg*]]] } else { lappend out [list $arg [lsort [glob -nocomplain -- $arg*]]] } } else { lappend out [list [file dirname $arg]$sep \ [lsort [glob -nocomplain -- $arg]]] } } } if {$s(long)} { set old [clock scan {1 year ago}] set fmt "%s%9d %s %s\n" foreach o $out { set d [lindex $o 0] append res $d:\n foreach f [lindex $o 1] { file lstat $f st set f [file tail $f] if {$s(full)} { switch -glob $st(type) { d* { append f $sep } l* { append f "@ -> [file readlink $d$sep$f]" } default { if {[file exec $d$sep$f]} { append f * } } } } if {[string match file $st(type)]} { set mode - } else { set mode [string index $st(type) 0] } foreach j [split [format %03o [expr {$st(mode)&0777}]] {}] { append mode $s($j) } if {$st(mtime)>$old} { set cfmt {%b %d %H:%M} } else { set cfmt {%b %d %Y} } append res [format $fmt $mode $st(size) \ [clock format $st(mtime) -format $cfmt] $f] } append res \n } } else { foreach o $out { set d [lindex $o 0] append res "$d:\n" set i 0 foreach f [lindex $o 1] { if {[string len [file tail $f]] > $i} { set i [string len [file tail $f]] } } set i [expr {$i+2+$s(full)}] set j 80 ## This gets the number of cols in the tkcon console widget if {[llength [info commands tkcon]]} { set j [expr {[tkcon master set ::tkcon::OPT(cols)]/$i}] } set k 0 foreach f [lindex $o 1] { set f [file tail $f] if {$s(full)} { switch -glob [file type $d$sep$f] { d* { append f $sep } l* { append f @ } default { if {[file exec $d$sep$f]} { append f * } } } } append res [format "%-${i}s" $f] if {$j == 0 || [incr k]%$j == 0} { set res [string trimright $res]\n } } append res \n\n } } return [string trimright $res] } interp alias {} ::ls {} ::dir -full ## lremove - remove items from a list # OPTS: # -all remove all instances of each item # -glob remove all instances matching glob pattern # -regexp remove all instances matching regexp pattern # ARGS: l a list to remove items from # args items to remove (these are 'join'ed together) ## proc lremove {args} { array set opts {-all 0 pattern -exact} while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -a* { set opts(-all) 1 } -g* { set opts(pattern) -glob } -r* { set opts(pattern) -regexp } -- { set args [lreplace $args 0 0]; break } default {return -code error "unknown option \"[lindex $args 0]\""} } set args [lreplace $args 0 0] } set l [lindex $args 0] foreach i [join [lreplace $args 0 0]] { if {[set ix [lsearch $opts(pattern) $l $i]] == -1} continue set l [lreplace $l $ix $ix] if {$opts(-all)} { while {[set ix [lsearch $opts(pattern) $l $i]] != -1} { set l [lreplace $l $ix $ix] } } } return $l } if {!$::tkcon::PRIV(WWW)} {; ## Unknown changed to get output into tkcon window # unknown: # Invoked automatically whenever an unknown command is encountered. # Works through a list of "unknown handlers" that have been registered # to deal with unknown commands. Extensions can integrate their own # handlers into the 'unknown' facility via 'unknown_handler'. # # If a handler exists that recognizes the command, then it will # take care of the command action and return a valid result or a # Tcl error. Otherwise, it should return "-code continue" (=2) # and responsibility for the command is passed to the next handler. # # Arguments: # args - A list whose elements are the words of the original # command, including the command name. proc unknown args { global unknown_handler_order unknown_handlers errorInfo errorCode # # Be careful to save error info now, and restore it later # for each handler. Some handlers generate their own errors # and disrupt handling. # set savedErrorCode $errorCode set savedErrorInfo $errorInfo if {![info exists unknown_handler_order] || \ ![info exists unknown_handlers]} { set unknown_handlers(tcl) tcl_unknown set unknown_handler_order tcl } foreach handler $unknown_handler_order { set status [catch {uplevel 1 $unknown_handlers($handler) $args} result] if {$status == 1} { # # Strip the last five lines off the error stack (they're # from the "uplevel" command). # set new [split $errorInfo \n] set new [join [lrange $new 0 [expr {[llength $new]-6}]] \n] return -code $status -errorcode $errorCode \ -errorinfo $new $result } elseif {$status != 4} { return -code $status $result } set errorCode $savedErrorCode set errorInfo $savedErrorInfo } set name [lindex $args 0] return -code error "invalid command name \"$name\"" } # tcl_unknown: # Invoked when a Tcl command is invoked that doesn't exist in the # interpreter: # # 1. See if the autoload facility can locate the command in a # Tcl script file. If so, load it and execute it. # 2. If the command was invoked interactively at top-level: # (a) see if the command exists as an executable UNIX program. # If so, "exec" the command. # (b) see if the command requests csh-like history substitution # in one of the common forms !!, !, or ^old^new. If # so, emulate csh's history substitution. # (c) see if the command is a unique abbreviation for another # command. If so, invoke the command. # # Arguments: # args - A list whose elements are the words of the original # command, including the command name. proc tcl_unknown args { global auto_noexec auto_noload env unknown_pending tcl_interactive global errorCode errorInfo # If the command word has the form "namespace inscope ns cmd" # then concatenate its arguments onto the end and evaluate it. set cmd [lindex $args 0] if {[regexp "^namespace\[ \t\n\]+inscope" $cmd] && [llength $cmd] == 4} { set arglist [lrange $args 1 end] set ret [catch {uplevel 1 $cmd $arglist} result] if {$ret == 0} { return $result } else { return -code $ret -errorcode $errorCode $result } } # CAD tools special: # Check for commands which were renamed to tcl_(command) if {[lsearch [info commands] tcl_$cmd] >= 0} { set arglist [concat tcl_$cmd [lrange $args 1 end]] set ret [catch {eval $arglist} result] if {$ret == 0} { return $result } else { return -code $ret -errorcode $errorCode $result } } # Save the values of errorCode and errorInfo variables, since they # may get modified if caught errors occur below. The variables will # be restored just before re-executing the missing command. set savedErrorCode $errorCode set savedErrorInfo $errorInfo set name [lindex $args 0] if {![info exists auto_noload]} { # # Make sure we're not trying to load the same proc twice. # if {[info exists unknown_pending($name)]} { return -code error "self-referential recursion in \"unknown\" for command \"$name\"" } set unknown_pending($name) pending if {[llength [info args auto_load]]==1} { set ret [catch {auto_load $name} msg] } else { set ret [catch {auto_load $name [uplevel 1 {namespace current}]} msg] } unset unknown_pending($name) if {$ret} { return -code $ret -errorcode $errorCode \ "error while autoloading \"$name\": $msg" } # # Avoid problems with renaming "array"! (for tcl-based magic only) # set arraycmd array if {[lsearch [info commands] tcl_array] >= 0} {set arraycmd tcl_array} if {![$arraycmd size unknown_pending]} { unset unknown_pending } if {$msg} { set errorCode $savedErrorCode set errorInfo $savedErrorInfo set code [catch {uplevel 1 $args} msg] if {$code == 1} { # # Strip the last five lines off the error stack (they're # from the "uplevel" command). # set new [split $errorInfo \n] set new [join [lrange $new 0 [expr {[llength $new]-6}]] \n] return -code error -errorcode $errorCode \ -errorinfo $new $msg } else { return -code $code $msg } } } if {[info level] == 1 && [string match {} [info script]] \ && [info exists tcl_interactive] && $tcl_interactive} { if {![info exists auto_noexec]} { set new [auto_execok $name] if {[string compare {} $new]} { set errorCode $savedErrorCode set errorInfo $savedErrorInfo return [uplevel 1 exec $new [lrange $args 1 end]] #return [uplevel exec >&@stdout <@stdin $new [lrange $args 1 end]] } } set errorCode $savedErrorCode set errorInfo $savedErrorInfo ## ## History substitution moved into ::tkcon::EvalCmd ## set ret [catch {set cmds [info commands $name*]} msg] if {[string compare $name "::"] == 0} { set name "" } if {$ret != 0} { return -code $ret -errorcode $errorCode \ "error in unknown while checking if \"$name\" is a unique command abbreviation: $msg" } set cmds [info commands $name*] if {[llength $cmds] == 1} { return [uplevel 1 [lreplace $args 0 0 $cmds]] } if {[llength $cmds]} { if {$name == ""} { return -code error "empty command name \"\"" } else { return -code error \ "ambiguous command name \"$name\": [lsort $cmds]" } } ## We've got nothing so far ## Check and see if Tk wasn't loaded, but it appears to be a Tk cmd if {![uplevel \#0 info exists tk_version]} { lappend tkcmds bell bind bindtags button \ canvas checkbutton clipboard destroy \ entry event focus font frame grab grid image \ label listbox lower menu menubutton message \ option pack place radiobutton raise \ scale scrollbar selection send spinbox \ text tk tkwait toplevel winfo wm if {[lsearch -exact $tkcmds $name] >= 0 && \ [tkcon master tk_messageBox -icon question -parent . \ -title "Load Tk?" -type retrycancel -default retry \ -message "This appears to be a Tk command, but Tk\ has not yet been loaded. Shall I retry the command\ with loading Tk first?"] == "retry"} { return [uplevel 1 "load {} Tk; $args"] } } } return -code continue } } ; # end exclusionary code for WWW proc ::tkcon::Bindings {} { variable PRIV global tcl_platform tk_version #----------------------------------------------------------------------- # Elements of tkPriv that are used in this file: # # char - Character position on the line; kept in order # to allow moving up or down past short lines while # still remembering the desired position. # mouseMoved - Non-zero means the mouse has moved a significant # amount since the button went down (so, for example, # start dragging out a selection). # prevPos - Used when moving up or down lines via the keyboard. # Keeps track of the previous insert position, so # we can distinguish a series of ups and downs, all # in a row, from a new up or down. # selectMode - The style of selection currently underway: # char, word, or line. # x, y - Last known mouse coordinates for scanning # and auto-scanning. #----------------------------------------------------------------------- switch -glob $tcl_platform(platform) { win* { set PRIV(meta) Alt } mac* { set PRIV(meta) Command } default { set PRIV(meta) Meta } } ## Get all Text bindings into TkConsole foreach ev [bind Text] { bind TkConsole $ev [bind Text $ev] } ## We really didn't want the newline insertion bind TkConsole {} bind TkConsole <> {} bind TkConsole <> {} ## Now make all our virtual event bindings foreach {ev key} [subst -nocommand -noback { <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <$PRIV(meta)-i> <> <> <$PRIV(meta)-o> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> }] { event add $ev $key ## Make sure the specific key won't be defined bind TkConsole $key {} } ## Make the ROOT bindings bind $PRIV(root) <> exit bind $PRIV(root) <> { ::tkcon::New } bind $PRIV(root) <> { ::tkcon::Destroy } bind $PRIV(root) <> { ::tkcon::About } bind $PRIV(root) <> { ::tkcon::Help } bind $PRIV(root) <> { ::tkcon::FindBox $::tkcon::PRIV(console) } bind $PRIV(root) <> { ::tkcon::Attach {} ::tkcon::Prompt "\n" [::tkcon::CmdGet $::tkcon::PRIV(console)] } bind $PRIV(root) <> { if {[string compare {} $::tkcon::PRIV(name)]} { ::tkcon::Attach $::tkcon::PRIV(name) } else { ::tkcon::Attach Main } ::tkcon::Prompt "\n" [::tkcon::CmdGet $::tkcon::PRIV(console)] } bind $PRIV(root) <> { ::tkcon::Attach Main ::tkcon::Prompt "\n" [::tkcon::CmdGet $::tkcon::PRIV(console)] } bind $PRIV(root) <> { ::tkcon::PopupMenu %X %Y } ## Menu items need null TkConsolePost bindings to avoid the TagProc ## foreach ev [bind $PRIV(root)] { bind TkConsolePost $ev { # empty } } # ::tkcon::ClipboardKeysyms -- # This procedure is invoked to identify the keys that correspond to # the copy, cut, and paste functions for the clipboard. # # Arguments: # copy - Name of the key (keysym name plus modifiers, if any, # such as "Meta-y") used for the copy operation. # cut - Name of the key used for the cut operation. # paste - Name of the key used for the paste operation. proc ::tkcon::ClipboardKeysyms {copy cut paste} { bind TkConsole <$copy> {::tkcon::Copy %W} bind TkConsole <$cut> {::tkcon::Cut %W} bind TkConsole <$paste> {::tkcon::Paste %W} } proc ::tkcon::GetSelection {w} { if { ![catch {selection get -displayof $w -type UTF8_STRING} txt] || ![catch {selection get -displayof $w} txt] || ![catch {selection get -displayof $w -selection CLIPBOARD} txt] } { return $txt } return -code error "could not find default selection" } proc ::tkcon::Cut w { if {[string match $w [selection own -displayof $w]]} { clipboard clear -displayof $w catch { set txt [selection get -displayof $w] clipboard append -displayof $w $txt if {[$w compare sel.first >= limit]} { $w delete sel.first sel.last } } } } proc ::tkcon::Copy w { if {[string match $w [selection own -displayof $w]]} { clipboard clear -displayof $w catch { set txt [selection get -displayof $w] clipboard append -displayof $w $txt } } } proc ::tkcon::Paste w { if {![catch {GetSelection $w} txt]} { if {[$w compare insert < limit]} { $w mark set insert end } $w insert insert $txt $w see insert if {[string match *\n* $txt]} { ::tkcon::Eval $w } } } ## Redefine for TkConsole what we need ## event delete <> ::tkcon::ClipboardKeysyms bind TkConsole { catch { ::tkcon::Insert %W [::tkcon::GetSelection %W] } } bind TkConsole {+ catch { eval %W tag remove sel [%W tag nextrange prompt sel.first sel.last] eval %W tag remove sel sel.last-1c %W mark set insert sel.first } } ## binding editor needed ## binding for .tkconrc bind TkConsole <> { if {[%W compare insert > limit]} {::tkcon::Expand %W path} break } bind TkConsole <> { if {[%W compare insert > limit]} {::tkcon::Expand %W proc} } bind TkConsole <> { if {[%W compare insert > limit]} {::tkcon::Expand %W var} } bind TkConsole <> { if {[%W compare insert > limit]} {::tkcon::Expand %W} } bind TkConsole <> { if {[%W compare insert >= limit]} { ::tkcon::Insert %W \t } } bind TkConsole <> { if {[%W compare insert >= limit]} { ::tkcon::Insert %W \n } } bind TkConsole <> { ::tkcon::Eval %W } bind TkConsole { if {[llength [%W tag nextrange sel 1.0 end]] \ && [%W compare sel.first >= limit]} { %W delete sel.first sel.last } elseif {[%W compare insert >= limit]} { %W delete insert %W see insert } } bind TkConsole { if {[llength [%W tag nextrange sel 1.0 end]] \ && [%W compare sel.first >= limit]} { %W delete sel.first sel.last } elseif {[%W compare insert != 1.0] && [%W compare insert > limit]} { %W delete insert-1c %W see insert } } bind TkConsole [bind TkConsole ] bind TkConsole { ::tkcon::Insert %W %A } bind TkConsole { if {[%W compare {limit linestart} == {insert linestart}]} { tkTextSetCursor %W limit } else { tkTextSetCursor %W {insert linestart} } } bind TkConsole [bind TkConsole ] bind TkConsole { if {[%W compare insert < limit]} break %W delete insert } bind TkConsole { if {[%W compare insert < limit]} break if {[%W compare insert == {insert lineend}]} { %W delete insert } else { %W delete insert {insert lineend} } } bind TkConsole <> { ## Clear console buffer, without losing current command line input set ::tkcon::PRIV(tmp) [::tkcon::CmdGet %W] clear ::tkcon::Prompt {} $::tkcon::PRIV(tmp) } bind TkConsole <> { if {[%W compare {insert linestart} != {limit linestart}]} { tkTextSetCursor %W [tkTextUpDownLine %W -1] } else { ::tkcon::Event -1 } } bind TkConsole <> { if {[%W compare {insert linestart} != {end-1c linestart}]} { tkTextSetCursor %W [tkTextUpDownLine %W 1] } else { ::tkcon::Event 1 } } bind TkConsole <> { ::tkcon::Event 1 } bind TkConsole <> { ::tkcon::Event -1 } bind TkConsole <> { ::tkcon::Event -1 [::tkcon::CmdGet %W] } bind TkConsole <> { ::tkcon::Event 1 [::tkcon::CmdGet %W] } bind TkConsole <> { ## Transpose current and previous chars if {[%W compare insert > "limit+1c"]} { tkTextTranspose %W } } bind TkConsole <> { ## Clear command line (Unix shell staple) %W delete limit end } bind TkConsole <> { ## Save command buffer (swaps with current command) set ::tkcon::PRIV(tmp) $::tkcon::PRIV(cmdsave) set ::tkcon::PRIV(cmdsave) [::tkcon::CmdGet %W] if {[string match {} $::tkcon::PRIV(cmdsave)]} { set ::tkcon::PRIV(cmdsave) $::tkcon::PRIV(tmp) } else { %W delete limit end-1c } ::tkcon::Insert %W $::tkcon::PRIV(tmp) %W see end } catch {bind TkConsole { tkTextScrollPages %W -1 }} catch {bind TkConsole { tkTextScrollPages %W -1 }} catch {bind TkConsole { tkTextScrollPages %W 1 }} catch {bind TkConsole { tkTextScrollPages %W 1 }} bind TkConsole <$PRIV(meta)-d> { if {[%W compare insert >= limit]} { %W delete insert {insert wordend} } } bind TkConsole <$PRIV(meta)-BackSpace> { if {[%W compare {insert -1c wordstart} >= limit]} { %W delete {insert -1c wordstart} insert } } bind TkConsole <$PRIV(meta)-Delete> { if {[%W compare insert >= limit]} { %W delete insert {insert wordend} } } bind TkConsole { if { (!$tkPriv(mouseMoved) || $tk_strictMotif) && ![catch {::tkcon::GetSelection %W} ::tkcon::PRIV(tmp)] } { if {[%W compare @%x,%y < limit]} { %W insert end $::tkcon::PRIV(tmp) } else { %W insert @%x,%y $::tkcon::PRIV(tmp) } if {[string match *\n* $::tkcon::PRIV(tmp)]} {::tkcon::Eval %W} } } ## ## End TkConsole bindings ## ## ## Bindings for doing special things based on certain keys ## bind TkConsolePost { if {$::tkcon::OPT(lightbrace) && $::tkcon::OPT(blinktime)>99 && \ [string compare \\ [%W get insert-2c]]} { ::tkcon::MatchPair %W \( \) limit } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { if {$::tkcon::OPT(lightbrace) && $::tkcon::OPT(blinktime)>99 && \ [string compare \\ [%W get insert-2c]]} { ::tkcon::MatchPair %W \[ \] limit } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { if {$::tkcon::OPT(lightbrace) && $::tkcon::OPT(blinktime)>99 && \ [string compare \\ [%W get insert-2c]]} { ::tkcon::MatchPair %W \{ \} limit } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { if {$::tkcon::OPT(lightbrace) && $::tkcon::OPT(blinktime)>99 && \ [string compare \\ [%W get insert-2c]]} { ::tkcon::MatchQuote %W limit } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { if {$::tkcon::OPT(lightcmd) && [string compare {} %A]} { ::tkcon::TagProc %W } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { set ::tkcon::PRIV(StatusCursor) [%W index insert] } } ## # ::tkcon::PopupMenu - what to do when the popup menu is requested ## proc ::tkcon::PopupMenu {X Y} { variable PRIV set w $PRIV(console) if {[string compare $w [winfo containing $X $Y]]} { tk_popup $PRIV(popup) $X $Y return } set x [expr {$X-[winfo rootx $w]}] set y [expr {$Y-[winfo rooty $w]}] if {[llength [set tags [$w tag names @$x,$y]]]} { if {[lsearch -exact $tags "proc"] >= 0} { lappend type "proc" foreach {first last} [$w tag prevrange proc @$x,$y] { set word [$w get $first $last]; break } } if {[lsearch -exact $tags "var"] >= 0} { lappend type "var" foreach {first last} [$w tag prevrange var @$x,$y] { set word [$w get $first $last]; break } } } if {![info exists type]} { set exp "(^|\[^\\\\\]\[ \t\n\r\])" set exp2 "\[\[\\\\\\?\\*\]" set i [$w search -backwards -regexp $exp @$x,$y "@$x,$y linestart"] if {[string compare {} $i]} { if {![string match *.0 $i]} {append i +2c} if {[string compare {} \ [set j [$w search -regexp $exp $i "$i lineend"]]]} { append j +1c } else { set j "$i lineend" } regsub -all $exp2 [$w get $i $j] {\\\0} word set word [string trim $word {\"$[]{}',?#*}] if {[llength [EvalAttached [list info commands $word]]]} { lappend type "proc" } if {[llength [EvalAttached [list info vars $word]]]} { lappend type "var" } if {[EvalAttached [list file isfile $word]]} { lappend type "file" } } } if {![info exists type] || ![info exists word]} { tk_popup $PRIV(popup) $X $Y return } $PRIV(context) delete 0 end $PRIV(context) add command -label "$word" -state disabled $PRIV(context) add separator set app [Attach] if {[lsearch $type proc] != -1} { $PRIV(context) add command -label "View Procedure" \ -command [list edit -attach $app -type proc -- $word] } if {[lsearch $type var] != -1} { $PRIV(context) add command -label "View Variable" \ -command [list edit -attach $app -type var -- $word] } if {[lsearch $type file] != -1} { $PRIV(context) add command -label "View File" \ -command [list edit -attach $app -type file -- $word] } tk_popup $PRIV(context) $X $Y } ## ::tkcon::TagProc - tags a procedure in the console if it's recognized ## This procedure is not perfect. However, making it perfect wastes ## too much CPU time... ## proc ::tkcon::TagProc w { set exp "\[^\\\\\]\[\[ \t\n\r\;{}\"\$\]" set i [$w search -backwards -regexp $exp insert-1c limit-1c] if {[string compare {} $i]} {append i +2c} else {set i limit} regsub -all "\[\[\\\\\\?\\*\]" [$w get $i "insert-1c wordend"] {\\\0} c if {[llength [EvalAttached [list info commands $c]]]} { $w tag add proc $i "insert-1c wordend" } else { $w tag remove proc $i "insert-1c wordend" } if {[llength [EvalAttached [list info vars $c]]]} { $w tag add var $i "insert-1c wordend" } else { $w tag remove var $i "insert-1c wordend" } } ## ::tkcon::MatchPair - blinks a matching pair of characters ## c2 is assumed to be at the text index 'insert'. ## This proc is really loopy and took me an hour to figure out given ## all possible combinations with escaping except for escaped \'s. ## It doesn't take into account possible commenting... Oh well. If ## anyone has something better, I'd like to see/use it. This is really ## only efficient for small contexts. # ARGS: w - console text widget # c1 - first char of pair # c2 - second char of pair # Calls: ::tkcon::Blink ## proc ::tkcon::MatchPair {w c1 c2 {lim 1.0}} { if {[string compare {} [set ix [$w search -back $c1 insert $lim]]]} { while { [string match {\\} [$w get $ix-1c]] && [string compare {} [set ix [$w search -back $c1 $ix-1c $lim]]] } {} set i1 insert-1c while {[string compare {} $ix]} { set i0 $ix set j 0 while {[string compare {} [set i0 [$w search $c2 $i0 $i1]]]} { append i0 +1c if {[string match {\\} [$w get $i0-2c]]} continue incr j } if {!$j} break set i1 $ix while {$j && [string compare {} \ [set ix [$w search -back $c1 $ix $lim]]]} { if {[string match {\\} [$w get $ix-1c]]} continue incr j -1 } } if {[string match {} $ix]} { set ix [$w index $lim] } } else { set ix [$w index $lim] } if {$::tkcon::OPT(blinkrange)} { Blink $w $ix [$w index insert] } else { Blink $w $ix $ix+1c [$w index insert-1c] [$w index insert] } } ## ::tkcon::MatchQuote - blinks between matching quotes. ## Blinks just the quote if it's unmatched, otherwise blinks quoted string ## The quote to match is assumed to be at the text index 'insert'. # ARGS: w - console text widget # Calls: ::tkcon::Blink ## proc ::tkcon::MatchQuote {w {lim 1.0}} { set i insert-1c set j 0 while {[string compare [set i [$w search -back \" $i $lim]] {}]} { if {[string match {\\} [$w get $i-1c]]} continue if {!$j} {set i0 $i} incr j } if {$j&1} { if {$::tkcon::OPT(blinkrange)} { Blink $w $i0 [$w index insert] } else { Blink $w $i0 $i0+1c [$w index insert-1c] [$w index insert] } } else { Blink $w [$w index insert-1c] [$w index insert] } } ## ::tkcon::Blink - blinks between n index pairs for a specified duration. # ARGS: w - console text widget # i1 - start index to blink region # i2 - end index of blink region # dur - duration in usecs to blink for # Outputs: blinks selected characters in $w ## proc ::tkcon::Blink {w args} { eval [list $w tag add blink] $args after $::tkcon::OPT(blinktime) [list $w] tag remove blink $args return } ## ::tkcon::Insert ## Insert a string into a text console at the point of the insertion cursor. ## If there is a selection in the text, and it covers the point of the ## insertion cursor, then delete the selection before inserting. # ARGS: w - text window in which to insert the string # s - string to insert (usually just a single char) # Outputs: $s to text widget ## proc ::tkcon::Insert {w s} { if {[string match {} $s] || [string match disabled [$w cget -state]]} { return } if {[$w comp insert < limit]} { $w mark set insert end } if {[llength [$w tag ranges sel]] && \ [$w comp sel.first <= insert] && [$w comp sel.last >= insert]} { $w delete sel.first sel.last } $w insert insert $s $w see insert } ## ::tkcon::Expand - # ARGS: w - text widget in which to expand str # type - type of expansion (path / proc / variable) # Calls: ::tkcon::Expand(Pathname|Procname|Variable) # Outputs: The string to match is expanded to the longest possible match. # If ::tkcon::OPT(showmultiple) is non-zero and the user longest # match equaled the string to expand, then all possible matches # are output to stdout. Triggers bell if no matches are found. # Returns: number of matches found ## proc ::tkcon::Expand {w {type ""}} { set exp "\[^\\\\\]\[\[ \t\n\r\\\{\"$\]" set tmp [$w search -backwards -regexp $exp insert-1c limit-1c] if {[string compare {} $tmp]} {append tmp +2c} else {set tmp limit} if {[$w compare $tmp >= insert]} return set str [$w get $tmp insert] switch -glob $type { pa* { set res [ExpandPathname $str] } pr* { set res [ExpandProcname $str] } v* { set res [ExpandVariable $str] } default { set res {} foreach t $::tkcon::OPT(expandorder) { if {![catch {Expand$t $str} res] && \ [string compare {} $res]} break } } } set len [llength $res] if {$len} { $w delete $tmp insert $w insert $tmp [lindex $res 0] if {$len > 1} { if {$::tkcon::OPT(showmultiple) && \ ![string compare [lindex $res 0] $str]} { puts stdout [lsort [lreplace $res 0 0]] } } } else { bell } return [incr len -1] } ## ::tkcon::ExpandPathname - expand a file pathname based on $str ## This is based on UNIX file name conventions # ARGS: str - partial file pathname to expand # Calls: ::tkcon::ExpandBestMatch # Returns: list containing longest unique match followed by all the # possible further matches ## proc ::tkcon::ExpandPathname str { set pwd [EvalAttached pwd] # Cause a string like {C:/Program\ Files/} to become "C:/Program Files/" regsub -all {\\([][ ])} $str {\1} str if {[catch {EvalAttached [list cd [file dirname $str]]} err]} { return -code error $err } set dir [file tail $str] ## Check to see if it was known to be a directory and keep the trailing ## slash if so (file tail cuts it off) if {[string match */ $str]} { append dir / } # Create a safely glob-able name regsub -all {([][])} $dir {\\\1} safedir if {[catch {lsort [EvalAttached [list glob $safedir*]]} m]} { set match {} } else { if {[llength $m] > 1} { global tcl_platform if {[string match windows $tcl_platform(platform)]} { ## Windows is screwy because it's case insensitive set tmp [ExpandBestMatch [string tolower $m] \ [string tolower $dir]] ## Don't change case if we haven't changed the word if {[string length $dir]==[string length $tmp]} { set tmp $dir } } else { set tmp [ExpandBestMatch $m $dir] } if {[string match */* $str]} { set tmp [string trimright [file dirname $str] /]/$tmp } regsub -all {([^\\])([][ ])} $tmp {\1\\\2} tmp set match [linsert $m 0 $tmp] } else { ## This may look goofy, but it handles spaces in path names eval append match $m if {[file isdirectory $match]} {append match /} if {[string match */* $str]} { set match [string trimright [file dirname $str] /]/$match } regsub -all {([^\\])([][ ])} $match {\1\\\2} match ## Why is this one needed and the ones below aren't!! set match [list $match] } } EvalAttached [list cd $pwd] return $match } ## ::tkcon::ExpandProcname - expand a tcl proc name based on $str # ARGS: str - partial proc name to expand # Calls: ::tkcon::ExpandBestMatch # Returns: list containing longest unique match followed by all the # possible further matches ## proc ::tkcon::ExpandProcname str { set match [EvalAttached [list info commands $str*]] if {[llength $match] == 0} { set ns [EvalAttached \ "namespace children \[namespace current\] [list $str*]"] if {[llength $ns]==1} { set match [EvalAttached [list info commands ${ns}::*]] } else { set match $ns } } if {[llength $match] > 1} { regsub -all {([^\\]) } [ExpandBestMatch $match $str] {\1\\ } str set match [linsert $match 0 $str] } else { regsub -all {([^\\]) } $match {\1\\ } match } return $match } ## ::tkcon::ExpandVariable - expand a tcl variable name based on $str # ARGS: str - partial tcl var name to expand # Calls: ::tkcon::ExpandBestMatch # Returns: list containing longest unique match followed by all the # possible further matches ## proc ::tkcon::ExpandVariable str { if {[regexp {([^\(]*)\((.*)} $str junk ary str]} { ## Looks like they're trying to expand an array. set match [EvalAttached [list array names $ary $str*]] if {[llength $match] > 1} { set vars $ary\([ExpandBestMatch $match $str] foreach var $match {lappend vars $ary\($var\)} return $vars } else {set match $ary\($match\)} ## Space transformation avoided for array names. } else { set match [EvalAttached [list info vars $str*]] if {[llength $match] > 1} { regsub -all {([^\\]) } [ExpandBestMatch $match $str] {\1\\ } str set match [linsert $match 0 $str] } else { regsub -all {([^\\]) } $match {\1\\ } match } } return $match } ## ::tkcon::ExpandBestMatch2 - finds the best unique match in a list of names ## Improves upon the speed of the below proc only when $l is small ## or $e is {}. $e is extra for compatibility with proc below. # ARGS: l - list to find best unique match in # Returns: longest unique match in the list ## proc ::tkcon::ExpandBestMatch2 {l {e {}}} { set s [lindex $l 0] if {[llength $l]>1} { set i [expr {[string length $s]-1}] foreach l $l { while {$i>=0 && [string first $s $l]} { set s [string range $s 0 [incr i -1]] } } } return $s } ## ::tkcon::ExpandBestMatch - finds the best unique match in a list of names ## The extra $e in this argument allows us to limit the innermost loop a ## little further. This improves speed as $l becomes large or $e becomes long. # ARGS: l - list to find best unique match in # e - currently best known unique match # Returns: longest unique match in the list ## proc ::tkcon::ExpandBestMatch {l {e {}}} { set ec [lindex $l 0] if {[llength $l]>1} { set e [string length $e]; incr e -1 set ei [string length $ec]; incr ei -1 foreach l $l { while {$ei>=$e && [string first $ec $l]} { set ec [string range $ec 0 [incr ei -1]] } } } return $ec } # Here is a group of functions that is only used when Tkcon is # executed in a safe interpreter. It provides safe versions of # missing functions. For example: # # - "tk appname" returns "tkcon.tcl" but cannot be set # - "toplevel" is equivalent to 'frame', only it is automatically # packed. # - The 'source', 'load', 'open', 'file' and 'exit' functions are # mapped to corresponding functions in the parent interpreter. # # Further on, Tk cannot be really loaded. Still the safe 'load' # provedes a speciall case. The Tk can be divided into 4 groups, # that each has a safe handling procedure. # # - "::tkcon::SafeItem" handles commands like 'button', 'canvas' ...... # Each of these functions has the window name as first argument. # - "::tkcon::SafeManage" handles commands like 'pack', 'place', 'grid', # 'winfo', which can have multiple window names as arguments. # - "::tkcon::SafeWindow" handles all windows, such as '.'. For every # window created, a new alias is formed which also is handled by # this function. # - Other (e.g. bind, bindtag, image), which need their own function. # ## These functions courtesy Jan Nijtmans (nijtmans@nici.kun.nl) ## if {[string compare [info command tk] tk]} { proc tk {option args} { if {![string match app* $option]} { error "wrong option \"$option\": should be appname" } return "tkcon.tcl" } } if {[string compare [info command toplevel] toplevel]} { proc toplevel {name args} { eval frame $name $args pack $name } } proc ::tkcon::SafeSource {i f} { set fd [open $f r] set r [read $fd] close $fd if {[catch {interp eval $i $r} msg]} { error $msg } } proc ::tkcon::SafeOpen {i f {m r}} { set fd [open $f $m] interp transfer {} $fd $i return $fd } proc ::tkcon::SafeLoad {i f p} { global tk_version tk_patchLevel tk_library auto_path if {[string compare $p Tk]} { load $f $p $i } else { foreach command {button canvas checkbutton entry frame label listbox message radiobutton scale scrollbar spinbox text toplevel} { $i alias $command ::tkcon::SafeItem $i $command } $i alias image ::tkcon::SafeImage $i foreach command {pack place grid destroy winfo} { $i alias $command ::tkcon::SafeManage $i $command } if {[llength [info command event]]} { $i alias event ::tkcon::SafeManage $i $command } frame .${i}_dot -width 300 -height 300 -relief raised pack .${i}_dot -side left $i alias tk tk $i alias bind ::tkcon::SafeBind $i $i alias bindtags ::tkcon::SafeBindtags $i $i alias . ::tkcon::SafeWindow $i {} foreach var {tk_version tk_patchLevel tk_library auto_path} { $i eval set $var [list [set $var]] } $i eval { package provide Tk $tk_version if {[lsearch -exact $auto_path $tk_library] < 0} { lappend auto_path $tk_library } } return "" } } proc ::tkcon::SafeSubst {i a} { set arg1 "" foreach {arg value} $a { if {![string compare $arg -textvariable] || ![string compare $arg -variable]} { set newvalue "[list $i] $value" global $newvalue if {[interp eval $i info exists $value]} { set $newvalue [interp eval $i set $value] } else { catch {unset $newvalue} } $i eval trace variable $value rwu \{[list tkcon set $newvalue $i]\} set value $newvalue } elseif {![string compare $arg -command]} { set value [list $i eval $value] } lappend arg1 $arg $value } return $arg1 } proc ::tkcon::SafeItem {i command w args} { set args [::tkcon::SafeSubst $i $args] set code [catch "$command [list .${i}_dot$w] $args" msg] $i alias $w ::tkcon::SafeWindow $i $w regsub -all .${i}_dot $msg {} msg return -code $code $msg } proc ::tkcon::SafeManage {i command args} { set args1 "" foreach arg $args { if {[string match . $arg]} { set arg .${i}_dot } elseif {[string match .* $arg]} { set arg ".${i}_dot$arg" } lappend args1 $arg } set code [catch "$command $args1" msg] regsub -all .${i}_dot $msg {} msg return -code $code $msg } # # FIX: this function doesn't work yet if the binding starts with '+'. # proc ::tkcon::SafeBind {i w args} { if {[string match . $w]} { set w .${i}_dot } elseif {[string match .* $w]} { set w ".${i}_dot$w" } if {[llength $args] > 1} { set args [list [lindex $args 0] \ "[list $i] eval [list [lindex $args 1]]"] } set code [catch "bind $w $args" msg] if {[llength $args] <2 && $code == 0} { set msg [lindex $msg 3] } return -code $code $msg } proc ::tkcon::SafeImage {i option args} { set code [catch "image $option $args" msg] if {[string match cr* $option]} { $i alias $msg $msg } return -code $code $msg } proc ::tkcon::SafeBindtags {i w {tags {}}} { if {[string match . $w]} { set w .${i}_dot } elseif {[string match .* $w]} { set w ".${i}_dot$w" } set newtags {} foreach tag $tags { if {[string match . $tag]} { lappend newtags .${i}_dot } elseif {[string match .* $tag]} { lappend newtags ".${i}_dot$tag" } else { lappend newtags $tag } } if {[string match $tags {}]} { set code [catch {bindtags $w} msg] regsub -all \\.${i}_dot $msg {} msg } else { set code [catch {bindtags $w $newtags} msg] } return -code $code $msg } proc ::tkcon::SafeWindow {i w option args} { if {[string match conf* $option] && [llength $args] > 1} { set args [::tkcon::SafeSubst $i $args] } elseif {[string match itemco* $option] && [llength $args] > 2} { set args "[list [lindex $args 0]] [::tkcon::SafeSubst $i [lrange $args 1 end]]" } elseif {[string match cr* $option]} { if {[llength $args]%2} { set args "[list [lindex $args 0]] [::tkcon::SafeSubst $i [lrange $args 1 end]]" } else { set args [::tkcon::SafeSubst $i $args] } } elseif {[string match bi* $option] && [llength $args] > 2} { set args [list [lindex $args 0] [lindex $args 1] "[list $i] eval [list [lindex $args 2]]"] } set code [catch ".${i}_dot$w $option $args" msg] if {$code} { regsub -all .${i}_dot $msg {} msg } elseif {[string match conf* $option] || [string match itemco* $option]} { if {[llength $args] == 1} { switch -- $args { -textvariable - -variable { set msg "[lrange $msg 0 3] [list [lrange [lindex $msg 4] 1 end]]" } -command - updatecommand { set msg "[lrange $msg 0 3] [list [lindex [lindex $msg 4] 2]]" } } } elseif {[llength $args] == 0} { set args1 "" foreach el $msg { switch -- [lindex $el 0] { -textvariable - -variable { set el "[lrange $el 0 3] [list [lrange [lindex $el 4] 1 end]]" } -command - updatecommand { set el "[lrange $el 0 3] [list [lindex [lindex $el 4] 2]]" } } lappend args1 $el } set msg $args1 } } elseif {[string match cg* $option] || [string match itemcg* $option]} { switch -- $args { -textvariable - -variable { set msg [lrange $msg 1 end] } -command - updatecommand { set msg [lindex $msg 2] } } } elseif {[string match bi* $option]} { if {[llength $args] == 2 && $code == 0} { set msg [lindex $msg 2] } } return -code $code $msg } proc ::tkcon::RetrieveFilter {host} { variable PRIV set result {} if {[info exists PRIV(proxy)]} { if {![regexp "^(localhost|127\.0\.0\.1)" $host]} { set result [lrange [split [lindex $PRIV(proxy) 0] :] 0 1] } } return $result } proc ::tkcon::RetrieveAuthentication {} { package require Tk if {[catch {package require base64}]} { if {[catch {package require Trf}]} { error "base64 support not available" } else { set local64 "base64 -mode enc" } } else { set local64 "base64::encode" } set dlg [toplevel .auth] wm title $dlg "Authenticating Proxy Configuration" set f1 [frame ${dlg}.f1] set f2 [frame ${dlg}.f2] button $f2.b -text "OK" -command "destroy $dlg" pack $f2.b -side right label $f1.l2 -text "Username" label $f1.l3 -text "Password" entry $f1.e2 -textvariable "[namespace current]::conf_userid" entry $f1.e3 -textvariable "[namespace current]::conf_passwd" -show * grid $f1.l2 -column 0 -row 0 -sticky e grid $f1.l3 -column 0 -row 1 -sticky e grid $f1.e2 -column 1 -row 0 -sticky news grid $f1.e3 -column 1 -row 1 -sticky news grid columnconfigure $f1 1 -weight 1 pack $f2 -side bottom -fill x pack $f1 -side top -anchor n -fill both -expand 1 tkwait window $dlg set result {} if {[info exists [namespace current]::conf_userid]} { set data [subst $[namespace current]::conf_userid] append data : [subst $[namespace current]::conf_passwd] set data [$local64 $data] set result [list "Proxy-Authorization" "Basic $data"] } unset [namespace current]::conf_passwd return $result } proc ::tkcon::Retrieve {} { # A little bit'o'magic to grab the latest tkcon from CVS and # save it locally. It doesn't support proxies though... variable PRIV set defExt "" if {[string match "windows" $::tcl_platform(platform)]} { set defExt ".tcl" } set file [tk_getSaveFile -title "Save Latest tkcon to ..." \ -defaultextension $defExt \ -initialdir [file dirname $PRIV(SCRIPT)] \ -initialfile [file tail $PRIV(SCRIPT)] \ -parent $PRIV(root) \ -filetypes {{"Tcl Files" {.tcl .tk}} {"All Files" {*.*}}}] if {[string compare $file ""]} { package require http 2 set token [::http::geturl $PRIV(HEADURL) -timeout 30000] ::http::wait $token set code [catch { if {[::http::status $token] == "ok"} { set fid [open $file w] # We don't want newline mode to change fconfigure $fid -translation binary set data [::http::data $token] puts -nonewline $fid $data close $fid regexp {Id: tkcon.tcl,v (\d+\.\d+)} $data -> rcsVersion regexp {version\s+(\d+\.\d[^\n]*)} $data -> tkconVersion } } err] ::http::cleanup $token if {$code} { return -code error $err } elseif {[tk_messageBox -type yesno -icon info -parent $PRIV(root) \ -title "Retrieved tkcon v$tkconVersion, RCS $rcsVersion" \ -message "Successfully retrieved tkcon v$tkconVersion,\ RCS $rcsVersion. Shall I resource (not restart) this\ version now?"] == "yes"} { set PRIV(SCRIPT) $file set PRIV(version) $tkconVersion.$rcsVersion ::tkcon::Resource } } } ## ::tkcon::Resource - re'source's this script into current console ## Meant primarily for my development of this program. It follows ## links until the ultimate source is found. ## set ::tkcon::PRIV(SCRIPT) [info script] if {!$::tkcon::PRIV(WWW) && [string compare $::tkcon::PRIV(SCRIPT) {}]} { # we use a catch here because some wrap apps choke on 'file type' # because TclpLstat wasn't wrappable until 8.4. catch { while {[string match link [file type $::tkcon::PRIV(SCRIPT)]]} { set link [file readlink $::tkcon::PRIV(SCRIPT)] if {[string match relative [file pathtype $link]]} { set ::tkcon::PRIV(SCRIPT) \ [file join [file dirname $::tkcon::PRIV(SCRIPT)] $link] } else { set ::tkcon::PRIV(SCRIPT) $link } } catch {unset link} if {[string match relative [file pathtype $::tkcon::PRIV(SCRIPT)]]} { set ::tkcon::PRIV(SCRIPT) [file join [pwd] $::tkcon::PRIV(SCRIPT)] } } } proc ::tkcon::Resource {} { uplevel \#0 { if {[catch {source -rsrc tkcon}]} { source $::tkcon::PRIV(SCRIPT) } } Bindings InitSlave $::tkcon::OPT(exec) } ## Initialize only if we haven't yet ## if {![info exists ::tkcon::PRIV(root)] || \ ![winfo exists $::tkcon::PRIV(root)]} { ::tkcon::Init } qrouter-1.4.88/qconfig.h0000644000175000017510000000421013625043307014443 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* qconfig.h -- general purpose autorouter */ /* configuration file read/writer */ /*--------------------------------------------------------------*/ /* Written by Steve Beccue, 2003 */ /*--------------------------------------------------------------*/ /* Modified by Tim Edwards, June 2011, to separate Pitch */ /* information in X and Y dimensions. */ /*--------------------------------------------------------------*/ #ifndef QCONFIG_H extern int Num_layers; extern double PathWidth[MAX_LAYERS]; // width of the paths extern int GDSLayer[MAX_TYPES]; // GDS layer number extern int GDSCommentLayer; // for dummy wires, etc. extern char CIFLayer[MAX_TYPES][50]; // CIF layer name extern double PitchX; // base horizontal wire pitch extern double PitchY; // base vertical wire pitch extern int NumChannelsX; extern int NumChannelsY; extern int Vert[MAX_LAYERS]; // 1 if verticle, 0 if horizontal extern int Numpasses; // number of times to iterate in route_segs extern char StackedContacts; // Number of vias that can be stacked together extern double Xlowerbound; // Bounding Box of routes extern double Xupperbound; extern double Ylowerbound; extern double Yupperbound; extern int SegCost; extern int ViaCost; extern int JogCost; extern int XverCost; extern int BlockCost; extern int OffsetCost; extern int ConflictCost; // If vias are non-square, then they can have up to four orientations, // with the top and/or bottom metal layers oriented with the longest // dimension along either the X or the Y axis. extern char *ViaXX[MAX_LAYERS]; // Top and bottom horizontal extern char *ViaXY[MAX_LAYERS]; // Bottom horizontal, top vertical extern char *ViaYX[MAX_LAYERS]; // Bottom vertial, top horizontal extern char *ViaYY[MAX_LAYERS]; // Top and bottom vertical int read_config(FILE *configfileptr, int is_info); void post_config(u_char noprint); void init_config(); #define QCONFIG_H #endif /* end of qconfig.h */ qrouter-1.4.88/README0000644000175000017510000002140413625043307013530 0ustar nileshnilesh------------------------------------------------- Qrouter version 1.4 Detail netlist router for ASICs (c) 2017 by Tim Edwards Released under Gnu Public License ---------------------------------------------- ---------------------------------------------- Release notes: ---------------------------------------------- Version 1.4 ------------ Branch created April 25, 2017 mainly for the purpose of making the existing version 1.3 the stable branch, particularly as version 1.3 is required for qflow. Version 1.3 ------------ Branch created September 16, 2014 and slowly developed for more robust and DRC-clean output, along with numerous bugfixes. The underlying algorithm is essentially unchanged from version 1.2. Version 1.2 ------------ Branch of 1.1 that puts qrouter in a Tcl/Tk environment and includes routines to generate and draw into a graphics window. Code reorganized into three main sections that are called from the Tcl command line as "stage1", "stage2", and "write_def". The front-end process of reading in the LEF and DEF files and configuring the routing environment will be added to the command set, eventually. Based on analysis from the visualization of the router, the code has been rewritten to speed up the routing during multi-tap (more than 2 connections) nets, so that previous search results remain in place after each route, avoiding redundant searching. This speeds up qrouter by a factor of about 2x. A masking function that limits routes to a specific defined portion of the layout speeds up qrouter by a factor of about 30x. Version 1.1 ------------ Second major release. Revised the "proute" structure so that its position information refers to the position of the structure itself and not of the predecessor. This requires setting up proute structures for every point on the source net, but makes it possible to specify one or more alternate predecessors for each potential route position. Added handling of routes with larger size and pitch on the higher layers. Added handling of technologies that do not allow contacts to be stacked arbitrarily. Some preliminary work in search optimization. Finding a viable route (any viable route) quickly is the key to setting a bound on cost early and prevent multiple passes over many points. Added code for detailed analysis of port geometry and taking steps necessary to avoid generating DRC errors. Redesigned internal structures so that nodes are not in an independent list, but only listed under their assigned net. Routes are assigned to nets, not to nodes. Added the ability to read in existing route geometry and add it to the database. Version 1.0 ------------ First release. This is work in progess on a professional-grade multi-layer maze router. First release implements the standard Lee algorithm. However, a modified Lee algorithm is used that presents all nodes of the network (other than the source node) as targets. As each target node is reached, in order of lowest cost, the target node and its route to the source are added to the source node, and the process repeated until there are no more target nodes. The implementation is geometry-aware, to the extent that all node and obstruction geometry is present in the LEF file used to define the standard cell macros. The implementation uses the open standard LEF and DEF formats. Standard cell definitions and routing layer definitions are read in from the LEF file, and cell placement information and an unrouted network are read from the DEF file. Output is a copy of the original input DEF file, annotated with the physical routes. ---------------------------------------------- Compilation & installation: ---------------------------------------------- The system runs under autoconf, and so has the standard compile and install sequence: ./configure make make install For FreeBSD, use 'gmake' instead of 'make'. Options to configure: --prefix= overrides the standard install location of /usr/local --with-libdir= overrides the standard search location for configuration files, /usr/local/share/qrouter --with-tcl= path to tclConfig.sh file. --with-tk= path to tkConfig.sh file. ---------------------------------------------- Usage: ---------------------------------------------- qrouter [-noc] [-s ] This is the normal invocation, where a Tcl-script specified by contains all of the configuration information, specifies where to read LEF and DEF files, how to perform the routing, and where to write the output DEF file. All commands in the script can alternatively be entered on the Tcl command line after starting qrouter. The "-noc" option does not invoke the Tk console on startup, which is best for batch operation, as text output to the console can slow down the routing process. qrouter [-c ] [options] where is without an extension. File .def is assumed to exist and to define cell placement and netlist information. File is assumed to exist and contains basic routing parameters, or points to a LEF file containing detailed routing parameters. If this option is not specified, then the default configuration file name of "route.cfg" is used. ---------------------------------------------- Completed development tasks: ---------------------------------------------- 1. New algorithm for routing nodes of a network, in which route_segs calculates costs out from source to any node in the network, settling on the minimum, and this continues until there are no nodes left to route. 2. Need to compute obstruction areas around nodes and mark them (e.g., with a flag) so that they can interpreted as obstructions when routing a different net, and available space when routing the node's net. 3. Rework the crossover cost method. Currently it does not account for the vertical layer, and so gives a high crossover cost to layers that are more than one route level above a node and would not block it. 4. Stub routing to nodes from unobstructed positions smaller than the route pitch but outside of the tap geometry. 5. Crossover costing removed for all terminals on completed routes. 6. Replace linked list code with simpler linked lists, no dependency on non-open-source linked-list code. 7. Added the ability to specify additional obstruction areas in the route.cfg file. 8. Increased the route width to the width of a via where the distance between a via and a terminal is less than the route metal's spacing rule. This cannot be done with normal routes in a DEF file, so it is added on as a "specialnets" section. 9. Collect all unroutable nets and route them with other nets marked as high-cost instead of obstructions. Analyze all the resultant collisions between nets, and proceed with an iterative rip-up and reroute algorithm. 10. When a net is ripped up to remove it from the path of a net being routed in the 2nd stage, the ripped-up net is added to a list in the routed net so that it will not be ripped up to make way for that net again. This prevents infinite looping in the 2nd stage. 11. Clean up the DEF file reader with a proper parser ported from magic, like the LEF file reader was. 12. Add a Tcl/Tk command-line interface for interactive routing and display. 13. Recast the config file as a set of Tcl command-line commands to execute. All original setup options have corresponding commands in the Tcl interpreter. The config file and its parsing is retained for backwards compatibility. 14. Vias can be larger than metal routes. Need to identify positions as obstructions to vias only. 15. Make Euclidean geometry checks instead of Manhattan geometry checks. ---------------------------------------------- Development to do: ---------------------------------------------- 1. Handle nets in the input DEF file that are already routed by adding them as obstructions to the route grid. 2. Final stage should rip up and reroute each network in turn, with all crossover costing removed, so that each route will be cleaner (to be done by Tcl commands acting on individual routes. Can be run as a simple Tcl script). 3. Need to normalize the segment and jog costs to the track pitch, so that costs do not give preference to the route layers with the widest track pitch. 4. Need a command-line switch (and/or Tcl command) to disable the specialnets section. 5. Sort trunk lines so no trunk lines overlap prior to routing. 6. Apply costing to terminals, giving higher cost to terminals with offsets and the lowest cost to simple on-grid contacts. ------------------------------------------------- qrouter-1.4.88/point.c0000644000175000017510000000476213625043307014155 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* point.c -- */ /* */ /* Memory mapped point allocation */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, April 2017, based on code from Magic */ /*--------------------------------------------------------------*/ #include #include #include #include #include "qrouter.h" #include "point.h" #ifdef HAVE_SYS_MMAN_H POINT POINTStoreFreeList = NULL; POINT POINTStoreFreeList_end = NULL; /* The memory mapped POINT Allocation scheme */ static void *_block_begin = NULL; static void *_current_ptr = NULL; static void *_block_end = NULL; /* MMAP the point store */ static signed char mmapPOINTStore() { int prot = PROT_READ | PROT_WRITE; int flags = MAP_ANON | MAP_PRIVATE; u_long map_len = POINT_STORE_BLOCK_SIZE; _block_begin = mmap(NULL, map_len, prot, flags, -1, 0); if (_block_begin == MAP_FAILED) { fprintf(stderr, "mmapPOINTStore: Unable to mmap ANON SEGMENT\n"); exit(1); } _block_end = (void *) ((unsigned long) _block_begin + map_len); _current_ptr = _block_begin; return 0; } POINT allocPOINT() { POINT _return_point = NULL; if (!_block_begin && !_block_end) mmapPOINTStore(); /* Check if we can get the point from the * Free list */ if (POINTStoreFreeList) { _return_point = POINTStoreFreeList; POINTStoreFreeList = (POINT)POINTStoreFreeList->next; return _return_point; } /* Get it from the mmap */ if (((unsigned long)_current_ptr + sizeof(struct point_)) > (unsigned long)_block_end) mmapPOINTStore(); _current_ptr = (void *)((unsigned long)_current_ptr + sizeof(struct point_)); if ((unsigned long)_current_ptr > (unsigned long) _block_end) { fprintf(stderr, "allocPOINT(): internal assertion failure."); exit(1); } return (POINT)((unsigned long)_current_ptr - sizeof(struct point_)); } void freePOINT(POINT gp) { if (!POINTStoreFreeList_end || !POINTStoreFreeList) { POINTStoreFreeList_end = gp; gp->next = (POINT)NULL; POINTStoreFreeList = POINTStoreFreeList_end; } else { POINTStoreFreeList_end->next = gp; POINTStoreFreeList_end = gp; POINTStoreFreeList_end->next = (POINT)NULL; } } #else POINT allocPOINT() { POINT newpoint; newpoint = (POINT)malloc((unsigned)(sizeof(struct point_))); return (newpoint); } void freePOINT(POINT gp) { free((char *)gp); } #endif /* !HAVE_SYS_MMAN_H */ qrouter-1.4.88/.gitignore0000644000175000017510000000016313625043307014637 0ustar nileshnileshqrouter config.cache config.status config.log Makefile qrouterexec qrouternullg qrouter.sh qrouter.tcl *.o *.so *~ qrouter-1.4.88/def.c0000644000175000017510000016255313625043307013565 0ustar nileshnilesh/* * def.c -- * * This module incorporates the LEF/DEF format for standard-cell place and * route. * * Version 0.1 (September 26, 2003): DEF input of designs. * * Written by Tim Edwards, Open Circuit Design * Modified April 2013 for use with qrouter * * It is assumed that the LEF files have been read in prior to this, and * layer information is already known. The DEF file should have information * primarily on die are, track placement, pins, components, and nets. * * Routed nets have their routes dropped into track obstructions, and the * nets are ignored. */ #include #include #include #include #include #include #include /* for roundf() function, if std=c99 */ #include "qrouter.h" #include "node.h" #include "qconfig.h" #include "maze.h" #include "lef.h" #include "def.h" TRACKS *Tracks = NULL; int numSpecial = 0; /* Tracks number of specialnets */ #ifndef TCL_QROUTER /* Find an instance in the instance list. If qrouter */ /* is compiled with Tcl support, then this routine */ /* uses Tcl hash tables, greatly speeding up the */ /* read-in of large DEF files. */ GATE DefFindGate(char *name) { GATE ginst; for (ginst = Nlgates; ginst; ginst = ginst->next) { if (!strcasecmp(ginst->gatename, name)) return ginst; } return NULL; } /* Find a net in the list of nets. If qrouter is */ /* compiled with Tcl support, then this routine */ /* uses Tcl hash tables, greatly speeding up the */ /* read-in of large DEF files. */ NET DefFindNet(char *name) { int i; NET net; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (!strcasecmp(net->netname, name)) return net; } return NULL; } /* For the non-Tcl version, these are empty placeholders */ static void DefHashInit(void) { } static void DefHashInstance(GATE gateginfo) { } static void DefHashNet(NET net) { } #else /* The versions using TCL hash tables */ #include /* These hash tables speed up DEF file reading */ static Tcl_HashTable InstanceTable; static Tcl_HashTable NetTable; /*--------------------------------------------------------------*/ /* Cell macro lookup based on the hash table */ /*--------------------------------------------------------------*/ static void DefHashInit(void) { /* Initialize the macro hash table */ Tcl_InitHashTable(&InstanceTable, TCL_STRING_KEYS); Tcl_InitHashTable(&NetTable, TCL_STRING_KEYS); } GATE DefFindGate(char *name) { GATE ginst; Tcl_HashEntry *entry; entry = Tcl_FindHashEntry(&InstanceTable, name); ginst = (entry) ? (GATE)Tcl_GetHashValue(entry) : NULL; return ginst; } NET DefFindNet(char *name) { NET net; Tcl_HashEntry *entry; // Guard against calls to find nets before DEF file is read if (Numnets == 0) return NULL; entry = Tcl_FindHashEntry(&NetTable, name); net = (entry) ? (NET)Tcl_GetHashValue(entry) : NULL; return net; } /*--------------------------------------------------------------*/ /* Cell macro hash table generation */ /* Given an instance record, create an entry in the hash table */ /* for the instance name, with the record entry pointing to the */ /* instance record. */ /*--------------------------------------------------------------*/ static void DefHashInstance(GATE gateginfo) { int new; Tcl_HashEntry *entry; entry = Tcl_CreateHashEntry(&InstanceTable, gateginfo->gatename, &new); if (entry != NULL) Tcl_SetHashValue(entry, (ClientData)gateginfo); } /*--------------------------------------------------------------*/ /* Net hash table generation */ /* Given a net record, create an entry in the hash table for */ /* the net name, with the record entry pointing to the net */ /* record. */ /*--------------------------------------------------------------*/ static void DefHashNet(NET net) { int new; Tcl_HashEntry *entry; entry = Tcl_CreateHashEntry(&NetTable, net->netname, &new); if (entry != NULL) Tcl_SetHashValue(entry, (ClientData)net); } #endif /* TCL_QROUTER */ /* *------------------------------------------------------------ * * DefGetTracks -- * * Get tracks information for the given layer. * If no TRACKS were specified for the layer, NULL will be * returned. * *------------------------------------------------------------ */ TRACKS DefGetTracks(int layer) { if (Tracks) return Tracks[layer]; else return NULL; } /* *------------------------------------------------------------ * * DefAddRoutes -- * * Parse a network route statement from the DEF file. * If "special" is 1, then, add the geometry to the * list of obstructions. If "special" is 0, then read * the geometry into a route structure for the net. * * Results: * Returns the last token encountered. * * Side Effects: * Reads from input stream; * Adds information to the layout database. * *------------------------------------------------------------ */ static char * DefAddRoutes(FILE *f, float oscale, NET net, char special) { char *token; SEG newRoute = NULL; DSEG lr, drect; struct point_ refp; char valid = FALSE; /* is there a valid reference point? */ char noobstruct; char initial = TRUE; struct dseg_ locarea; double x, y, lx, ly, w, hw, s; int routeLayer = -1, paintLayer; LefList lefl; ROUTE routednet = NULL; refp.x1 = 0; refp.y1 = 0; /* Don't create obstructions or routes on routed specialnets inputs */ /* except for power and ground nets. */ noobstruct = ((special == (char)1) && (!(net->flags & NET_IGNORED)) && (net->netnum != VDD_NET) && (net->netnum != GND_NET)) ? TRUE : FALSE; while (initial || (token = LefNextToken(f, TRUE)) != NULL) { /* Get next point, token "NEW", or via name */ if (initial || !strcmp(token, "NEW") || !strcmp(token, "new")) { /* initial pass is like a NEW record, but has no NEW keyword */ initial = FALSE; /* invalidate reference point */ valid = FALSE; token = LefNextToken(f, TRUE); routeLayer = LefFindLayerNum(token); if (routeLayer < 0) { LefError(DEF_ERROR, "Unknown layer type \"%s\" for NEW route\n", token); continue; } else if (routeLayer >= Num_layers) { LefError(DEF_ERROR, "DEF file contains layer \"%s\" which is" " not allowed by the layer limit setting of %d\n", token, Num_layers); continue; } paintLayer = routeLayer; if (special == (char)1) { /* SPECIALNETS has the additional width */ token = LefNextToken(f, TRUE); if (sscanf(token, "%lg", &w) != 1) { LefError(DEF_ERROR, "Bad width in special net\n"); continue; } if (w != 0) w /= oscale; else w = LefGetRouteWidth(paintLayer); } else w = LefGetRouteWidth(paintLayer); // Create a new route record, add to the 1st node if (special == (char)0) { routednet = (ROUTE)malloc(sizeof(struct route_)); routednet->next = net->routes; net->routes = routednet; routednet->netnum = net->netnum; routednet->segments = NULL; routednet->flags = (u_char)0; routednet->start.route = NULL; routednet->end.route = NULL; } } else if (*token != '(') /* via name */ { /* A '+' or ';' record ends the route */ if (*token == ';' || *token == '+') break; else if (valid == FALSE) { LefError(DEF_ERROR, "Route has via name \"%s\" but no points!\n", token); continue; } lefl = LefFindLayer(token); if (lefl != NULL) { /* The area to paint is derived from the via definitions. */ if (lefl != NULL) { if (lefl->lefClass == CLASS_VIA) { // Note: layers may be defined in any order, metal or cut. // Check both via.area and via.lr layers, and reject those // that exceed the number of metal layers (those are cuts). paintLayer = Num_layers - 1; routeLayer = -1; if (lefl->info.via.area.layer < Num_layers) { routeLayer = lefl->info.via.area.layer; if (routeLayer < paintLayer) paintLayer = routeLayer; if ((routeLayer >= 0) && (special == (char)1) && (valid == TRUE) && (noobstruct == FALSE)) { s = LefGetRouteSpacing(routeLayer); drect = (DSEG)malloc(sizeof(struct dseg_)); drect->x1 = x + (lefl->info.via.area.x1 / 2.0) - s; drect->x2 = x + (lefl->info.via.area.x2 / 2.0) + s; drect->y1 = y + (lefl->info.via.area.y1 / 2.0) - s; drect->y2 = y + (lefl->info.via.area.y2 / 2.0) + s; drect->layer = routeLayer; drect->next = UserObs; UserObs = drect; } } for (lr = lefl->info.via.lr; lr; lr = lr->next) { if (lr->layer >= Num_layers) continue; routeLayer = lr->layer; if (routeLayer < paintLayer) paintLayer = routeLayer; if ((routeLayer >= 0) && (special == (char)1) && (valid == TRUE) && (noobstruct == FALSE)) { s = LefGetRouteSpacing(routeLayer); drect = (DSEG)malloc(sizeof(struct dseg_)); drect->x1 = x + (lr->x1 / 2.0) - s; drect->x2 = x + (lr->x2 / 2.0) + s; drect->y1 = y + (lr->y1 / 2.0) - s; drect->y2 = y + (lr->y2 / 2.0) + s; drect->layer = routeLayer; drect->next = UserObs; UserObs = drect; } } if (routeLayer == -1) paintLayer = lefl->type; } else { paintLayer = lefl->type; if (special == (char)1) s = LefGetRouteSpacing(paintLayer); } } else { LefError(DEF_ERROR, "Error: Via \"%s\" named but undefined.\n", token); paintLayer = routeLayer; } if ((special == (char)0) && (paintLayer >= 0) && (paintLayer < (Num_layers - 1))) { newRoute = (SEG)malloc(sizeof(struct seg_)); newRoute->segtype = ST_VIA; newRoute->x1 = refp.x1; newRoute->x2 = refp.x1; newRoute->y1 = refp.y1; newRoute->y2 = refp.y1; newRoute->layer = paintLayer; if (routednet == NULL) { routednet = (ROUTE)malloc(sizeof(struct route_)); routednet->next = net->routes; net->routes = routednet; routednet->netnum = net->netnum; routednet->segments = NULL; routednet->flags = (u_char)0; routednet->start.route = NULL; routednet->end.route = NULL; } newRoute->next = routednet->segments; routednet->segments = newRoute; } else { if (paintLayer >= (Num_layers - 1)) /* Not necessarily an error to have predefined geometry */ /* above the route layer limit. */ LefError(DEF_WARNING, "Via \"%s\" exceeds layer " "limit setting.\n", token); else if (special == (char)0) LefError(DEF_ERROR, "Via \"%s\" does not define a" " metal layer!\n", token); } } else LefError(DEF_ERROR, "Via name \"%s\" unknown in route.\n", token); } else { /* Revert to the routing layer type, in case we painted a via */ paintLayer = routeLayer; /* Record current reference point */ locarea.x1 = refp.x1; locarea.y1 = refp.y1; lx = x; ly = y; /* Read an (X Y) point */ token = LefNextToken(f, TRUE); /* read X */ if (*token == '*') { if (valid == FALSE) { LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n"); goto endCoord; } } else if (sscanf(token, "%lg", &x) == 1) { x /= oscale; // In microns /* Note: offsets and stubs are always less than half a pitch, */ /* so round to the nearest integer grid point. */ refp.x1 = (int)(0.5 + ((x - Xlowerbound + EPS) / PitchX)); /* Flag offsets that are more than 1/3 track pitch, as they */ /* need careful analyzing (in route_set_connections()) to */ /* separate the main route from the stub route or offest. */ if ((special == (char)0) && ABSDIFF((double)refp.x1, (x - Xlowerbound) / PitchX) > 0.33) { if (routednet) routednet->flags |= RT_CHECK; } } else { LefError(DEF_ERROR, "Cannot parse X coordinate.\n"); goto endCoord; } token = LefNextToken(f, TRUE); /* read Y */ if (*token == '*') { if (valid == FALSE) { LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n"); if (newRoute != NULL) { free(newRoute); newRoute = NULL; } goto endCoord; } } else if (sscanf(token, "%lg", &y) == 1) { y /= oscale; // In microns refp.y1 = (int)(0.5 + ((y - Ylowerbound + EPS) / PitchY)); if ((special == (u_char)0) && ABSDIFF((double)refp.y1, (y - Ylowerbound) / PitchY) > 0.33) { if (routednet) routednet->flags |= RT_CHECK; } } else { LefError(DEF_ERROR, "Cannot parse Y coordinate.\n"); goto endCoord; } /* Indicate that we have a valid reference point */ if (valid == FALSE) { valid = TRUE; } else if ((locarea.x1 != refp.x1) && (locarea.y1 != refp.y1)) { /* Skip over nonmanhattan segments, reset the reference */ /* point, and output a warning. */ LefError(DEF_ERROR, "Can't deal with nonmanhattan geometry in route.\n"); locarea.x1 = refp.x1; locarea.y1 = refp.y1; lx = x; ly = y; } else { locarea.x2 = refp.x1; locarea.y2 = refp.y1; if (special != (char)0) { if ((valid == TRUE) && (noobstruct == FALSE)) { s = LefGetRouteSpacing(routeLayer); hw = w / 2; drect = (DSEG)malloc(sizeof(struct dseg_)); if (lx > x) { drect->x1 = x - s; drect->x2 = lx + s; } else if (lx < x) { drect->x1 = lx - s; drect->x2 = x + s; } else { drect->x1 = x - hw - s; drect->x2 = x + hw + s; } if (ly > y) { drect->y1 = y - s; drect->y2 = ly + s; } else if (ly < y) { drect->y1 = ly - s; drect->y2 = y + s; } else { drect->y1 = y - hw - s; drect->y2 = y + hw + s; } drect->layer = routeLayer; drect->next = UserObs; UserObs = drect; } } else if ((paintLayer >= 0) && (paintLayer < Num_layers)) { newRoute = (SEG)malloc(sizeof(struct seg_)); newRoute->segtype = ST_WIRE; // NOTE: Segments are added at the front of the linked // list, so they are backwards from the entry in the // DEF file. Therefore the first and second coordinates // must be swapped, or the segments become disjoint. newRoute->x1 = locarea.x2; newRoute->x2 = locarea.x1; newRoute->y1 = locarea.y2; newRoute->y2 = locarea.y1; newRoute->layer = paintLayer; if (routednet == NULL) { routednet = (ROUTE)malloc(sizeof(struct route_)); routednet->next = net->routes; net->routes = routednet; routednet->netnum = net->netnum; routednet->segments = NULL; routednet->flags = (u_char)0; routednet->start.route = NULL; routednet->end.route = NULL; } newRoute->next = routednet->segments; routednet->segments = newRoute; } else if (paintLayer >= Num_layers) { LefError(DEF_ERROR, "Route layer exceeds layer limit setting!\n"); } } endCoord: /* Find the closing parenthesis for the coordinate pair */ while (*token != ')') token = LefNextToken(f, TRUE); } } /* Remove routes that are less than 1 track long; these are stub */ /* routes to terminals that did not require a specialnets entry. */ if (routednet && (net->routes == routednet) && (routednet->flags & RT_CHECK)) { int ix, iy; SEG seg; seg = routednet->segments; if (seg && seg->next == NULL) { ix = ABSDIFF(seg->x1, seg->x2); iy = ABSDIFF(seg->y1, seg->y2); if ((ix == 0 && iy == 1) || (ix == 1 && iy == 0)) remove_top_route(net); } } return token; /* Pass back the last token found */ } /* *------------------------------------------------------------ * * DefReadGatePin --- * * Given a gate name and a pin name in a net from the * DEF file NETS section, find the position of the * gate, then the position of the pin within the gate, * and add pin and obstruction information to the grid * network. * *------------------------------------------------------------ */ static void DefReadGatePin(NET net, NODE node, char *instname, char *pinname, double *home) { int i; GATE gateginfo; DSEG drect; GATE g; double dx, dy; int gridx, gridy; DPOINT dp; g = DefFindGate(instname); if (g) { gateginfo = g->gatetype; if (!gateginfo) { LefError(DEF_ERROR, "Endpoint %s/%s of net %s not found\n", instname, pinname, net->netname); return; } for (i = 0; i < gateginfo->nodes; i++) { if (!strcasecmp(gateginfo->node[i], pinname)) { node->taps = (DPOINT)NULL; node->extend = (DPOINT)NULL; for (drect = g->taps[i]; drect; drect = drect->next) { // Add all routing gridpoints that fall inside // the rectangle. Much to do here: // (1) routable area should extend 1/2 route width // to each side, as spacing to obstructions allows. // (2) terminals that are wide enough to route to // but not centered on gridpoints should be marked // in some way, and handled appropriately. gridx = (int)((drect->x1 - Xlowerbound) / PitchX) - 1; if (gridx < 0) gridx = 0; while (1) { if (gridx >= NumChannelsX) break; dx = (gridx * PitchX) + Xlowerbound; if (dx > drect->x2 + home[drect->layer] - EPS) break; if (dx < drect->x1 - home[drect->layer] + EPS) { gridx++; continue; } gridy = (int)((drect->y1 - Ylowerbound) / PitchY) - 1; if (gridy < 0) gridy = 0; while (1) { if (gridy >= NumChannelsY) break; dy = (gridy * PitchY) + Ylowerbound; if (dy > drect->y2 + home[drect->layer] - EPS) break; if (dy < drect->y1 - home[drect->layer] + EPS) { gridy++; continue; } // Routing grid point is an interior point // of a gate port. Record the position dp = (DPOINT)malloc(sizeof(struct dpoint_)); dp->layer = drect->layer; dp->x = dx; dp->y = dy; dp->gridx = gridx; dp->gridy = gridy; if ((dy >= drect->y1 - EPS) && (dx >= drect->x1 - EPS) && (dy <= drect->y2 + EPS) && (dx <= drect->x2 + EPS)) { dp->next = node->taps; node->taps = dp; } else { dp->next = node->extend; node->extend = dp; } gridy++; } gridx++; } } node->netnum = net->netnum; g->netnum[i] = net->netnum; g->noderec[i] = node; node->netname = net->netname; node->next = net->netnodes; net->netnodes = node; break; } } if (i < gateginfo->nodes) return; } } /* *------------------------------------------------------------ * * DefReadNets -- * * Read a NETS or SPECIALNETS section from a DEF file. * * Results: * Return the total number of fixed or cover nets, * excluding power and ground nets. This gives the * base number of nets to be copied verbatim from * input to output (used only for SPECIALNETS, as * regular nets are tracked with the NET_IGNORED flag). * * Side Effects: * Many. Networks are created, and geometry may be * painted into the database top-level cell. * *------------------------------------------------------------ */ enum def_net_keys {DEF_NET_START = 0, DEF_NET_END}; enum def_netprop_keys { DEF_NETPROP_USE = 0, DEF_NETPROP_ROUTED, DEF_NETPROP_FIXED, DEF_NETPROP_COVER, DEF_NETPROP_SHAPE, DEF_NETPROP_SOURCE, DEF_NETPROP_WEIGHT, DEF_NETPROP_PROPERTY}; static int DefReadNets(FILE *f, char *sname, float oscale, char special, int total) { char *token; int keyword, subkey; int i, processed = 0; int nodeidx; int fixed = 0; char instname[MAX_NAME_LEN], pinname[MAX_NAME_LEN]; u_char is_new; NET net; int netidx; NODE node; double home[MAX_LAYERS]; static char *net_keys[] = { "-", "END", NULL }; static char *net_property_keys[] = { "USE", "ROUTED", "FIXED", "COVER", "SHAPE", "SOURCE", "WEIGHT", "PROPERTY", NULL }; /* Set pitches and allocate memory for Obs[] if we haven't yet. */ set_num_channels(); if (Numnets == 0) { // Initialize net and node records netidx = MIN_NET_NUMBER; Nlnets = (NET *)malloc(total * sizeof(NET)); for (i = 0; i < total; i++) Nlnets[i] = NULL; // Compute distance for keepout halo for each route layer // NOTE: This must match the definition for the keepout halo // used in nodes.c! for (i = 0; i < Num_layers; i++) { home[i] = LefGetViaWidth(i, i, 0) / 2.0 + LefGetRouteSpacing(i); } } else { netidx = Numnets; Nlnets = (NET *)realloc(Nlnets, (Numnets + total) * sizeof(NET)); for (i = Numnets; i < (Numnets + total); i++) Nlnets[i] = NULL; } while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, net_keys); if (keyword < 0) { LefError(DEF_WARNING, "Unknown keyword \"%s\" in NET " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_NET_START: /* Get net name */ token = LefNextToken(f, TRUE); net = DefFindNet(token); if (net == NULL) { net = (NET)malloc(sizeof(struct net_)); Nlnets[Numnets++] = net; net->netorder = 0; net->numnodes = 0; net->flags = 0; net->netname = strdup(token); net->netnodes = (NODE)NULL; net->noripup = (NETLIST)NULL; net->routes = (ROUTE)NULL; net->xmin = net->ymin = 0; net->xmax = net->ymax = 0; // Net numbers start at MIN_NET_NUMBER for regular nets, // use VDD_NET and GND_NET for power and ground, and 0 // is not a valid net number. if (vddnet && !strcmp(token, vddnet)) net->netnum = VDD_NET; else if (gndnet && !strcmp(token, gndnet)) net->netnum = GND_NET; else net->netnum = netidx++; DefHashNet(net); nodeidx = 0; is_new = TRUE; } else { nodeidx = net->numnodes; is_new = FALSE; } /* Update the record of the number of nets processed */ /* and spit out a message for every 5% finished. */ processed++; /* Get next token; will be '(' if this is a netlist */ token = LefNextToken(f, TRUE); /* Process all properties */ while (token && (*token != ';')) { /* Find connections for the net */ if (*token == '(') { token = LefNextToken(f, TRUE); /* get pin or gate */ strcpy(instname, token); token = LefNextToken(f, TRUE); /* get node name */ if (!strcasecmp(instname, "pin")) { strcpy(instname, token); strcpy(pinname, "pin"); } else strcpy(pinname, token); node = (NODE)calloc(1, sizeof(struct node_)); node->nodenum = nodeidx++; DefReadGatePin(net, node, instname, pinname, home); token = LefNextToken(f, TRUE); /* should be ')' */ continue; } else if (*token != '+') { token = LefNextToken(f, TRUE); /* Not a property */ continue; /* Ignore it, whatever it is */ } else token = LefNextToken(f, TRUE); subkey = Lookup(token, net_property_keys); if (subkey < 0) { LefError(DEF_WARNING, "Unknown net property \"%s\" in " "NET definition; ignoring.\n", token); continue; } switch (subkey) { case DEF_NETPROP_USE: /* Presently, we ignore this */ break; case DEF_NETPROP_SHAPE: /* Ignore this too, along with the next keyword */ token = LefNextToken(f, TRUE); break; case DEF_NETPROP_FIXED: case DEF_NETPROP_COVER: /* Read in fixed nets like regular nets but mark * them as NET_IGNORED. HOWEVER, if the net * already exists and is not marked NET_IGNORED, * then don't force it to be ignored. That is * particularly an issue for a net like power or * ground, which may need to be routed like a * regular net but also has fixed portions. */ if (is_new) { net->flags |= NET_IGNORED; fixed++; } // fall through case DEF_NETPROP_ROUTED: // Read in the route; qrouter now takes // responsibility for this route. while (token && (*token != ';')) token = DefAddRoutes(f, oscale, net, special); // Treat power and ground nets in specialnets as fixed if ((subkey == DEF_NETPROP_ROUTED || subkey == DEF_NETPROP_FIXED) && special == (char)1) { if (net->netnum == VDD_NET || net->netnum == GND_NET) fixed++; } break; } } break; case DEF_NET_END: if (!LefParseEndStatement(f, sname)) { LefError(DEF_ERROR, "Net END statement missing.\n"); keyword = -1; } break; } if (keyword == DEF_NET_END) break; } // Set the number of nodes per net for each node on the net if (special == FALSE) { // Fill in the netnodes list for each net, needed for checking // for isolated routed groups within a net. for (i = 0; i < Numnets; i++) { net = Nlnets[i]; for (node = net->netnodes; node; node = node->next) net->numnodes++; for (node = net->netnodes; node; node = node->next) node->numnodes = net->numnodes; } } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d%s nets total (%d fixed).\n", processed, (special) ? " special" : "", fixed); } else LefError(DEF_WARNING, "Warning: Number of nets read (%d) does not match " "the number declared (%d).\n", processed, total); return fixed; } /* *------------------------------------------------------------ * * DefReadUseLocation -- * * Read location and orientation of a cell use * Syntax: ( X Y ) O * * Results: * 0 on success, -1 on failure * * Side Effects: * GATE definition for the use has the placedX, placedY, * and orient values filled. *------------------------------------------------------------ */ enum def_orient {DEF_NORTH, DEF_SOUTH, DEF_EAST, DEF_WEST, DEF_FLIPPED_NORTH, DEF_FLIPPED_SOUTH, DEF_FLIPPED_EAST, DEF_FLIPPED_WEST}; static int DefReadLocation(gate, f, oscale) GATE gate; FILE *f; float oscale; { int keyword; char *token; float x, y; char mxflag, myflag, r90flag; static char *orientations[] = { "N", "S", "E", "W", "FN", "FS", "FE", "FW" }; token = LefNextToken(f, TRUE); if (*token != '(') goto parse_error; token = LefNextToken(f, TRUE); if (sscanf(token, "%f", &x) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (sscanf(token, "%f", &y) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (*token != ')') goto parse_error; token = LefNextToken(f, TRUE); keyword = Lookup(token, orientations); if (keyword < 0) { LefError(DEF_ERROR, "Unknown macro orientation \"%s\".\n", token); return -1; } mxflag = myflag = r90flag = (char)0; switch (keyword) { case DEF_NORTH: break; case DEF_SOUTH: mxflag = 1; myflag = 1; break; case DEF_FLIPPED_NORTH: mxflag = 1; break; case DEF_FLIPPED_SOUTH: myflag = 1; break; case DEF_EAST: r90flag = 1; break; case DEF_WEST: r90flag = 1; mxflag = 1; myflag = 1; break; case DEF_FLIPPED_EAST: r90flag = 1; mxflag = 1; break; case DEF_FLIPPED_WEST: r90flag = 1; myflag = 1; break; } if (gate) { gate->placedX = x / oscale; gate->placedY = y / oscale; gate->orient = MNONE; if (mxflag) gate->orient |= MX; if (myflag) gate->orient |= MY; if (r90flag) gate->orient |= R90; } return 0; parse_error: LefError(DEF_ERROR, "Cannot parse location: must be ( X Y ) orient\n"); return -1; } /* *------------------------------------------------------------ * * DefReadPins -- * * Read a PINS section from a DEF file. * * Results: * None. * * Side Effects: * Generates paint and labels in the layout. * *------------------------------------------------------------ */ enum def_pins_keys {DEF_PINS_START = 0, DEF_PINS_END}; enum def_pins_prop_keys { DEF_PINS_PROP_NET = 0, DEF_PINS_PROP_DIR, DEF_PINS_PROP_LAYER, DEF_PINS_PROP_PLACED, DEF_PINS_PROP_USE, DEF_PINS_PROP_FIXED, DEF_PINS_PROP_COVER}; static void DefReadPins(FILE *f, char *sname, float oscale, int total) { char *token; char pinname[MAX_NAME_LEN]; int keyword, subkey; int processed = 0; DSEG currect, drect; GATE gate; int curlayer; double hwidth; u_char pin_use; static char *pin_keys[] = { "-", "END", NULL }; static char *pin_property_keys[] = { "NET", "DIRECTION", "LAYER", "PLACED", "USE", "FIXED", "COVER", NULL }; static char *pin_classes[] = { "DEFAULT", "INPUT", "OUTPUT TRISTATE", "OUTPUT", "INOUT", "FEEDTHRU", NULL }; static char *pin_uses[] = { "DEFAULT", "SIGNAL", "ANALOG", "POWER", "GROUND", "CLOCK", "TIEOFF", "SCAN", "RESET", NULL }; pin_use = PORT_USE_DEFAULT; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, pin_keys); if (keyword < 0) { LefError(DEF_WARNING, "Unknown keyword \"%s\" in PINS " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_PINS_START: /* "-" keyword */ /* Update the record of the number of pins */ /* processed and spit out a message for every 5% done. */ processed++; /* Get pin name */ token = LefNextToken(f, TRUE); if (sscanf(token, "%2047s", pinname) != 1) { LefError(DEF_ERROR, "Bad pin statement: Need pin name\n"); LefEndStatement(f); break; } /* Create the pin record */ gate = (GATE)malloc(sizeof(struct gate_)); gate->gatetype = PinMacro; gate->gatename = NULL; /* Use NET, but if none, use */ /* the pin name, set at end. */ gate->width = gate->height = 0; curlayer = -1; /* Pin record has one node; allocate memory for it */ gate->taps = (DSEG *)malloc(sizeof(DSEG)); gate->noderec = (NODE *)malloc(sizeof(NODE)); gate->direction = (u_char *)malloc(sizeof(u_char)); gate->area = (float *)malloc(sizeof(float)); gate->netnum = (int *)malloc(sizeof(int)); gate->node = (char **)malloc(sizeof(char *)); gate->taps[0] = NULL; gate->noderec[0] = NULL; gate->netnum[0] = -1; gate->node[0] = NULL; gate->direction[0] = PORT_CLASS_DEFAULT; gate->area[0] = 0.0; /* Now do a search through the line for "+" entries */ /* And process each. */ while ((token = LefNextToken(f, TRUE)) != NULL) { if (*token == ';') break; if (*token != '+') continue; token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_property_keys); if (subkey < 0) { LefError(DEF_WARNING, "Unknown pin property \"%s\" in " "PINS definition; ignoring.\n", token); continue; } switch (subkey) { case DEF_PINS_PROP_NET: /* Get the net name */ token = LefNextToken(f, TRUE); gate->gatename = strdup(token); gate->node[0] = strdup(token); break; case DEF_PINS_PROP_DIR: token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_classes); if (subkey < 0) LefError(DEF_ERROR, "Unknown pin class %s\n", token); else gate->direction[0] = subkey; break; case DEF_PINS_PROP_LAYER: curlayer = LefReadLayer(f, FALSE); currect = LefReadRect(f, curlayer, oscale); /* Warn if pin is on layer above routing layer limit? */ if (currect) { gate->width = currect->x2 - currect->x1; gate->height = currect->y2 - currect->y1; } break; case DEF_PINS_PROP_USE: token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_uses); if (subkey < 0) LefError(DEF_ERROR, "Unknown pin use %s\n", token); else pin_use = subkey; break; case DEF_PINS_PROP_PLACED: case DEF_PINS_PROP_FIXED: case DEF_PINS_PROP_COVER: DefReadLocation(gate, f, oscale); break; } } if (curlayer >= 0 && curlayer < Num_layers) { /* If no NET was declared for pin, use pinname */ if (gate->gatename == NULL) gate->gatename = strdup(pinname); /* Make sure pin is at least the size of the route layer */ drect = (DSEG)malloc(sizeof(struct dseg_)); gate->taps[0] = drect; drect->next = (DSEG)NULL; hwidth = LefGetRouteWidth(curlayer); if (gate->width < hwidth) gate->width = hwidth; if (gate->height < hwidth) gate->height = hwidth; hwidth /= 2.0; drect->x1 = gate->placedX - hwidth; drect->y1 = gate->placedY - hwidth; drect->x2 = gate->placedX + hwidth; drect->y2 = gate->placedY + hwidth; drect->layer = curlayer; gate->obs = (DSEG)NULL; gate->nodes = 1; gate->next = Nlgates; Nlgates = gate; // Used by Tcl version of qrouter DefHashInstance(gate); } else { LefError(DEF_ERROR, "Pin %s is defined outside of route " "layer area!\n", pinname); free(gate->taps); free(gate->noderec); free(gate->direction); free(gate->netnum); free(gate->node); free(gate); } break; case DEF_PINS_END: if (!LefParseEndStatement(f, sname)) { LefError(DEF_ERROR, "Pins END statement missing.\n"); keyword = -1; } if (pin_use != PORT_USE_DEFAULT && gate->direction[0] == PORT_CLASS_DEFAULT) { /* Derive pin use from pin class, if needed */ switch (pin_use) { case PORT_USE_SIGNAL: case PORT_USE_RESET: case PORT_USE_CLOCK: case PORT_USE_SCAN: gate->direction[0] = PORT_CLASS_INPUT; break; case PORT_USE_POWER: case PORT_USE_GROUND: case PORT_USE_TIEOFF: case PORT_USE_ANALOG: gate->direction[0] = PORT_CLASS_BIDIRECTIONAL; break; } } break; } if (keyword == DEF_PINS_END) break; } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d pins total.\n", processed); } else LefError(DEF_WARNING, "Warning: Number of pins read (%d) does not match " "the number declared (%d).\n", processed, total); } /* *------------------------------------------------------------ * * DefReadVias -- * * Read a VIAS section from a DEF file. * * Results: * None. * * Side Effects: * Technically, this routine should be creating a cell for * each defined via. For now, it just computes the bounding * rectangle and layer. * *------------------------------------------------------------ */ enum def_vias_keys {DEF_VIAS_START = 0, DEF_VIAS_END}; enum def_vias_prop_keys { DEF_VIAS_PROP_RECT = 0}; static void DefReadVias(f, sname, oscale, total) FILE *f; char *sname; float oscale; int total; { char *token; char vianame[LEF_LINE_MAX]; int keyword, subkey; int processed = 0; int curlayer; LefList lefl; static char *via_keys[] = { "-", "END", NULL }; static char *via_property_keys[] = { "RECT", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, via_keys); if (keyword < 0) { LefError(DEF_WARNING, "Unknown keyword \"%s\" in VIAS " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_VIAS_START: /* "-" keyword */ /* Update the record of the number of vias */ /* processed and spit out a message for every 5% done. */ processed++; /* Get via name */ token = LefNextToken(f, TRUE); if (sscanf(token, "%2047s", vianame) != 1) { LefError(DEF_ERROR, "Bad via statement: Need via name\n"); LefEndStatement(f); break; } lefl = LefFindLayer(token); if (lefl == NULL) { lefl = (LefList)calloc(1, sizeof(lefLayer)); lefl->type = -1; lefl->obsType = -1; lefl->lefClass = CLASS_VIA; lefl->info.via.area.x1 = 0.0; lefl->info.via.area.y1 = 0.0; lefl->info.via.area.x2 = 0.0; lefl->info.via.area.y2 = 0.0; lefl->info.via.area.layer = -1; lefl->info.via.cell = (GATE)NULL; lefl->info.via.lr = (DSEG)NULL; /* Note: "generated" flag only refers to vias that */ /* are internally generated by qrouter. All others */ /* in the DEF file are read/written verbatim. */ lefl->info.via.generated = FALSE; lefl->lefName = strdup(token); lefl->next = LefInfo; LefInfo = lefl; } else { LefError(DEF_WARNING, "Warning: Composite via \"%s\" " "redefined.\n", vianame); lefl = LefRedefined(lefl, vianame); } /* Now do a search through the line for "+" entries */ /* And process each. */ while ((token = LefNextToken(f, TRUE)) != NULL) { if (*token == ';') break; if (*token != '+') continue; token = LefNextToken(f, TRUE); subkey = Lookup(token, via_property_keys); if (subkey < 0) { LefError(DEF_WARNING, "Unknown via property \"%s\" in " "VIAS definition; ignoring.\n", token); continue; } switch (subkey) { case DEF_VIAS_PROP_RECT: curlayer = LefReadLayer(f, FALSE); LefAddViaGeometry(f, lefl, curlayer, oscale); break; } } break; case DEF_VIAS_END: if (!LefParseEndStatement(f, sname)) { LefError(DEF_ERROR, "Vias END statement missing.\n"); keyword = -1; } break; } if (keyword == DEF_VIAS_END) break; } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d vias total.\n", processed); } else LefError(DEF_WARNING, "Warning: Number of vias read (%d) does not match " "the number declared (%d).\n", processed, total); } /* *------------------------------------------------------------ * * DefReadBlockages -- * * Read a BLOCKAGES section from a DEF file. * * Results: * None. * * Side Effects: * UserObs list is updated with the additional * obstructions. * *------------------------------------------------------------ */ enum def_block_keys {DEF_BLOCK_START = 0, DEF_BLOCK_END}; static void DefReadBlockages(FILE *f, char *sname, float oscale, int total) { char *token; int keyword; int processed = 0; DSEG drect, rsrch; LefList lefl; static char *blockage_keys[] = { "-", "END", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, blockage_keys); if (keyword < 0) { LefError(DEF_WARNING, "Unknown keyword \"%s\" in BLOCKAGE " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_BLOCK_START: /* "-" keyword */ /* Update the record of the number of components */ /* processed and spit out a message for every 5% done. */ processed++; /* Get layer name */ token = LefNextToken(f, TRUE); lefl = LefFindLayer(token); if (lefl != NULL) { drect = LefReadGeometry(NULL, f, oscale); if (UserObs == NULL) UserObs = drect; else { for (rsrch = UserObs; rsrch->next; rsrch = rsrch->next); rsrch->next = drect; } } else { LefError(DEF_ERROR, "Bad blockage statement: Need layer name\n"); LefEndStatement(f); break; } break; case DEF_BLOCK_END: if (!LefParseEndStatement(f, sname)) { LefError(DEF_ERROR, "Blockage END statement missing.\n"); keyword = -1; } break; } if (keyword == DEF_BLOCK_END) break; } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d blockages total.\n", processed); } else LefError(DEF_WARNING, "Warning: Number of blockages read (%d) does not match " "the number declared (%d).\n", processed, total); } /* *------------------------------------------------------------ * * DefReadComponents -- * * Read a COMPONENTS section from a DEF file. * * Results: * 0 on success, 1 on fatal error. * * Side Effects: * Many. Cell instances are created and added to * the database. * *------------------------------------------------------------ */ enum def_comp_keys {DEF_COMP_START = 0, DEF_COMP_END}; enum def_prop_keys { DEF_PROP_FIXED = 0, DEF_PROP_COVER, DEF_PROP_PLACED, DEF_PROP_UNPLACED, DEF_PROP_SOURCE, DEF_PROP_WEIGHT, DEF_PROP_FOREIGN, DEF_PROP_REGION, DEF_PROP_GENERATE, DEF_PROP_PROPERTY, DEF_PROP_EEQMASTER}; static int DefReadComponents(FILE *f, char *sname, float oscale, int total) { GATE gateginfo; GATE gate = NULL; char *token; char usename[512]; int keyword, subkey, i; int processed = 0; char OK; DSEG drect, newrect; double tmp; int err_fatal = 0; static char *component_keys[] = { "-", "END", NULL }; static char *property_keys[] = { "FIXED", "COVER", "PLACED", "UNPLACED", "SOURCE", "WEIGHT", "FOREIGN", "REGION", "GENERATE", "PROPERTY", "EEQMASTER", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, component_keys); if (keyword < 0) { LefError(DEF_WARNING, "Unknown keyword \"%s\" in COMPONENT " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_COMP_START: /* "-" keyword */ /* Update the record of the number of components */ /* processed and spit out a message for every 5% done. */ processed++; /* Get use and macro names */ token = LefNextToken(f, TRUE); if (sscanf(token, "%511s", usename) != 1) { LefError(DEF_ERROR, "Bad component statement: Need use " "and macro names\n"); LefEndStatement(f); err_fatal++; break; } token = LefNextToken(f, TRUE); /* Find the corresponding macro */ OK = 0; for (gateginfo = GateInfo; gateginfo; gateginfo = gateginfo->next) { if (!strcasecmp(gateginfo->gatename, token)) { OK = 1; break; } } if (!OK) { LefError(DEF_ERROR, "Could not find a macro definition for \"%s\"\n", token); gate = NULL; err_fatal++; } else { gate = (GATE)malloc(sizeof(struct gate_)); gate->gatename = strdup(usename); gate->gatetype = gateginfo; } /* Now do a search through the line for "+" entries */ /* And process each. */ while ((token = LefNextToken(f, TRUE)) != NULL) { if (*token == ';') break; if (*token != '+') continue; token = LefNextToken(f, TRUE); subkey = Lookup(token, property_keys); if (subkey < 0) { LefError(DEF_WARNING, "Unknown component property \"%s\" in " "COMPONENT definition; ignoring.\n", token); continue; } switch (subkey) { case DEF_PROP_PLACED: case DEF_PROP_UNPLACED: case DEF_PROP_FIXED: case DEF_PROP_COVER: DefReadLocation(gate, f, oscale); break; case DEF_PROP_SOURCE: case DEF_PROP_WEIGHT: case DEF_PROP_FOREIGN: case DEF_PROP_REGION: case DEF_PROP_GENERATE: case DEF_PROP_PROPERTY: case DEF_PROP_EEQMASTER: token = LefNextToken(f, TRUE); break; } } if (gate != NULL) { /* Process the gate */ gate->width = gateginfo->width; gate->height = gateginfo->height; gate->nodes = gateginfo->nodes; gate->obs = (DSEG)NULL; gate->taps = (DSEG *)malloc(gate->nodes * sizeof(DSEG)); gate->noderec = (NODE *)malloc(gate->nodes * sizeof(NODE)); gate->direction = (u_char *)malloc(gate->nodes * sizeof(u_char)); gate->area = (float *)malloc(gate->nodes * sizeof(float)); gate->netnum = (int *)malloc(gate->nodes * sizeof(int)); gate->node = (char **)malloc(gate->nodes * sizeof(char *)); for (i = 0; i < gate->nodes; i++) { /* Let the node names point to the master cell; */ /* this is just diagnostic; allows us, for */ /* instance, to identify vdd and gnd nodes, so */ /* we don't complain about them being */ /* disconnected. */ gate->node[i] = gateginfo->node[i]; /* copy pointer */ gate->direction[i] = gateginfo->direction[i]; /* copy */ gate->area[i] = gateginfo->area[i]; gate->taps[i] = (DSEG)NULL; /* Global power/ground bus check */ if (vddnet && gate->node[i] && !strcmp(gate->node[i], vddnet)) { /* Create a placeholder node with no taps */ gate->netnum[i] = VDD_NET; gate->noderec[i] = (NODE)calloc(1, sizeof(struct node_)); gate->noderec[i]->netnum = VDD_NET; } else if (gndnet && gate->node[i] && !strcmp(gate->node[i], gndnet)) { /* Create a placeholder node with no taps */ gate->netnum[i] = GND_NET; gate->noderec[i] = (NODE)calloc(1, sizeof(struct node_)); gate->noderec[i]->netnum = GND_NET; } else { gate->netnum[i] = 0; /* Until we read NETS */ gate->noderec[i] = NULL; } /* Make a copy of the gate nodes and adjust for */ /* instance position and number of layers */ for (drect = gateginfo->taps[i]; drect; drect = drect->next) { if (drect->layer < Num_layers) { newrect = (DSEG)malloc(sizeof(struct dseg_)); *newrect = *drect; newrect->next = gate->taps[i]; gate->taps[i] = newrect; } } for (drect = gate->taps[i]; drect; drect = drect->next) { // handle offset from gate origin drect->x1 -= gateginfo->placedX; drect->x2 -= gateginfo->placedX; drect->y1 -= gateginfo->placedY; drect->y2 -= gateginfo->placedY; // handle rotations and orientations here if (gate->orient & R90) { tmp = drect->y1; drect->y1 = -drect->x1; drect->y1 += gateginfo->width; drect->x1 = tmp; tmp = drect->y2; drect->y2 = -drect->x2; drect->y2 += gateginfo->width; drect->x2 = tmp; } if (gate->orient & MX) { tmp = drect->x1; drect->x1 = -drect->x2; drect->x1 += gate->placedX + gateginfo->width; drect->x2 = -tmp; drect->x2 += gate->placedX + gateginfo->width; } else { drect->x1 += gate->placedX; drect->x2 += gate->placedX; } if (gate->orient & MY) { tmp = drect->y1; drect->y1 = -drect->y2; drect->y1 += gate->placedY + gateginfo->height; drect->y2 = -tmp; drect->y2 += gate->placedY + gateginfo->height; } else { drect->y1 += gate->placedY; drect->y2 += gate->placedY; } } } /* Make a copy of the gate obstructions and adjust */ /* for instance position */ for (drect = gateginfo->obs; drect; drect = drect->next) { if (drect->layer < Num_layers) { newrect = (DSEG)malloc(sizeof(struct dseg_)); *newrect = *drect; newrect->next = gate->obs; gate->obs = newrect; } } for (drect = gate->obs; drect; drect = drect->next) { drect->x1 -= gateginfo->placedX; drect->x2 -= gateginfo->placedX; drect->y1 -= gateginfo->placedY; drect->y2 -= gateginfo->placedY; // handle rotations and orientations here if (gate->orient & R90) { tmp = drect->y1; drect->y1 = -drect->x1; drect->y1 += gateginfo->width; drect->x1 = tmp; tmp = drect->y2; drect->y2 = -drect->x2; drect->y2 += gateginfo->width; drect->x2 = tmp; } if (gate->orient & MX) { tmp = drect->x1; drect->x1 = -drect->x2; drect->x1 += gate->placedX + gateginfo->width; drect->x2 = -tmp; drect->x2 += gate->placedX + gateginfo->width; } else { drect->x1 += gate->placedX; drect->x2 += gate->placedX; } if (gate->orient & MY) { tmp = drect->y1; drect->y1 = -drect->y2; drect->y1 += gate->placedY + gateginfo->height; drect->y2 = -tmp; drect->y2 += gate->placedY + gateginfo->height; } else { drect->y1 += gate->placedY; drect->y2 += gate->placedY; } } gate->next = Nlgates; Nlgates = gate; // Used by Tcl version of qrouter DefHashInstance(gate); } break; case DEF_COMP_END: if (!LefParseEndStatement(f, sname)) { LefError(DEF_ERROR, "Component END statement missing.\n"); keyword = -1; err_fatal++; } /* Finish final call by placing the cell use */ if ((total > 0) && (gate != NULL)) { // Nothing to do. . . gate has already been placed in list. gate = NULL; } break; } if (keyword == DEF_COMP_END) break; } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d subcell instances total.\n", processed); } else LefError(DEF_WARNING, "Warning: Number of subcells read (%d) does not match " "the number declared (%d).\n", processed, total); return err_fatal; } /* *------------------------------------------------------------ * * DefRead -- * * Read a .def file and parse die area, track positions, * components, pins, and nets. * * Results: * Returns the units scale, so the routed output can be * scaled to match the DEF file header. * * Side Effects: * Many. * *------------------------------------------------------------ */ /* Enumeration of sections defined in DEF files */ enum def_sections {DEF_VERSION = 0, DEF_NAMESCASESENSITIVE, DEF_UNITS, DEF_DESIGN, DEF_REGIONS, DEF_ROW, DEF_TRACKS, DEF_GCELLGRID, DEF_DIVIDERCHAR, DEF_BUSBITCHARS, DEF_PROPERTYDEFINITIONS, DEF_DEFAULTCAP, DEF_TECHNOLOGY, DEF_HISTORY, DEF_DIEAREA, DEF_COMPONENTS, DEF_VIAS, DEF_PINS, DEF_PINPROPERTIES, DEF_SPECIALNETS, DEF_NETS, DEF_IOTIMINGS, DEF_SCANCHAINS, DEF_BLOCKAGES, DEF_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION, DEF_END}; int DefRead(char *inName, float *retscale) { FILE *f; char filename[256]; char *token; int keyword, dscale, total; int curlayer = -1, channels; int i; int err_fatal = 0; float oscale; double start, step; double llx, lly, urx, ury, locpitch; double dXlowerbound, dYlowerbound, dXupperbound, dYupperbound; char corient = '.'; DSEG diearea; static char *sections[] = { "VERSION", "NAMESCASESENSITIVE", "UNITS", "DESIGN", "REGIONS", "ROW", "TRACKS", "GCELLGRID", "DIVIDERCHAR", "BUSBITCHARS", "PROPERTYDEFINITIONS", "DEFAULTCAP", "TECHNOLOGY", "HISTORY", "DIEAREA", "COMPONENTS", "VIAS", "PINS", "PINPROPERTIES", "SPECIALNETS", "NETS", "IOTIMINGS", "SCANCHAINS", "BLOCKAGES", "CONSTRAINTS", "GROUPS", "BEGINEXT", "END", NULL }; if (!strrchr(inName, '.')) sprintf(filename, "%s.def", inName); else strcpy(filename, inName); f = fopen(filename, "r"); if (f == NULL) { Fprintf(stderr, "Cannot open input file: "); perror(filename); *retscale = (float)0.0; return 1; } /* Initialize */ if (Verbose > 0) { Fprintf(stdout, "Reading DEF data from file %s.\n", filename); Flush(stdout); } oscale = 1; lefCurrentLine = 0; DefHashInit(); /* Read file contents */ while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, sections); if (keyword < 0) { LefError(DEF_WARNING, "Unknown keyword \"%s\" in DEF file; " "ignoring.\n", token); LefEndStatement(f); continue; } if (keyword != DEF_TRACKS) corient = '.'; switch (keyword) { case DEF_VERSION: LefEndStatement(f); break; case DEF_NAMESCASESENSITIVE: LefEndStatement(f); break; case DEF_TECHNOLOGY: token = LefNextToken(f, TRUE); if (Verbose > 0) Fprintf(stdout, "Diagnostic: DEF file technology: \"%s\"\n", token); LefEndStatement(f); break; case DEF_REGIONS: LefSkipSection(f, sections[DEF_REGIONS]); break; case DEF_DESIGN: token = LefNextToken(f, TRUE); if (Verbose > 0) Fprintf(stdout, "Diagnostic: Design name: \"%s\"\n", token); LefEndStatement(f); break; case DEF_UNITS: token = LefNextToken(f, TRUE); token = LefNextToken(f, TRUE); token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &dscale) != 1) { LefError(DEF_ERROR, "Invalid syntax for UNITS statement.\n"); LefError(DEF_WARNING, "Assuming default value of 100\n"); dscale = 100; } /* We don't care if the scale is 100, 200, 1000, or 2000. */ /* Do we need to deal with numeric roundoff issues? */ oscale *= (float)dscale; LefEndStatement(f); break; case DEF_ROW: LefEndStatement(f); break; case DEF_TRACKS: token = LefNextToken(f, TRUE); if (strlen(token) != 1) { LefError(DEF_ERROR, "Problem parsing track orientation (X or Y).\n"); } corient = tolower(token[0]); // X or Y token = LefNextToken(f, TRUE); if (sscanf(token, "%lg", &start) != 1) { LefError(DEF_ERROR, "Problem parsing track start position.\n"); err_fatal++; } token = LefNextToken(f, TRUE); if (strcmp(token, "DO")) { LefError(DEF_ERROR, "TRACKS missing DO loop.\n"); err_fatal++; } token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &channels) != 1) { LefError(DEF_ERROR, "Problem parsing number of track channels.\n"); err_fatal++; } token = LefNextToken(f, TRUE); if (strcmp(token, "STEP")) { LefError(DEF_ERROR, "TRACKS missing STEP size.\n"); err_fatal++; } token = LefNextToken(f, TRUE); if (sscanf(token, "%lg", &step) != 1) { LefError(DEF_ERROR, "Problem parsing track step size.\n"); err_fatal++; } token = LefNextToken(f, TRUE); if (!strcmp(token, "LAYER")) { curlayer = LefReadLayer(f, FALSE); } if (curlayer < 0) { LefError(DEF_ERROR, "Failed to read layer; cannot parse TRACKS."); LefEndStatement(f); break; } else if (curlayer >= Num_layers) { LefError(DEF_WARNING, "Ignoring TRACKS above number of " "specified route layers."); LefEndStatement(f); break; } if (Tracks && (Tracks[curlayer] != NULL)) { LefError(DEF_ERROR, "Only one TRACKS line per layer allowed; " "last one is used."); } else { if (Tracks == NULL) Tracks = (TRACKS *)calloc(Num_layers, sizeof(TRACKS)); Tracks[curlayer] = (TRACKS)malloc(sizeof(struct tracks_)); } Tracks[curlayer]->start = start / oscale; Tracks[curlayer]->ntracks = channels; Tracks[curlayer]->pitch = step / oscale; if (corient == 'x') { Vert[curlayer] = 1; locpitch = step / oscale; if ((PitchX == 0.0) || (locpitch < PitchX)) PitchX = locpitch; llx = start; urx = start + step * channels; if ((llx / oscale) < Xlowerbound) Xlowerbound = llx / oscale; if ((urx / oscale) > Xupperbound) Xupperbound = urx / oscale; } else { Vert[curlayer] = 0; locpitch = step / oscale; if ((PitchY == 0.0) || (locpitch < PitchY)) PitchY = locpitch; lly = start; ury = start + step * channels; if ((lly / oscale) < Ylowerbound) Ylowerbound = lly / oscale; if ((ury / oscale) > Yupperbound) Yupperbound = ury / oscale; } LefEndStatement(f); break; case DEF_GCELLGRID: LefEndStatement(f); break; case DEF_DIVIDERCHAR: LefEndStatement(f); break; case DEF_BUSBITCHARS: LefEndStatement(f); break; case DEF_HISTORY: LefEndStatement(f); break; case DEF_DIEAREA: diearea = LefReadRect(f, 0, oscale); // no current layer, use 0 dXlowerbound = diearea->x1; dYlowerbound = diearea->y1; dXupperbound = diearea->x2; dYupperbound = diearea->y2; /* Seed actual lower/upper bounds with the midpoint */ Xlowerbound = (diearea->x1 + diearea->x2) / 2; Ylowerbound = (diearea->y1 + diearea->y2) / 2; Xupperbound = Xlowerbound; Yupperbound = Ylowerbound; LefEndStatement(f); break; case DEF_PROPERTYDEFINITIONS: LefSkipSection(f, sections[DEF_PROPERTYDEFINITIONS]); break; case DEF_DEFAULTCAP: LefSkipSection(f, sections[DEF_DEFAULTCAP]); break; case DEF_COMPONENTS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); err_fatal += DefReadComponents(f, sections[DEF_COMPONENTS], oscale, total); break; case DEF_BLOCKAGES: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); DefReadBlockages(f, sections[DEF_BLOCKAGES], oscale, total); break; case DEF_VIAS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); DefReadVias(f, sections[DEF_VIAS], oscale, total); break; case DEF_PINS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); DefReadPins(f, sections[DEF_PINS], oscale, total); break; case DEF_PINPROPERTIES: LefSkipSection(f, sections[DEF_PINPROPERTIES]); break; case DEF_SPECIALNETS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); numSpecial = DefReadNets(f, sections[DEF_SPECIALNETS], oscale, TRUE, total); break; case DEF_NETS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); if (total > MAX_NETNUMS) { LefError(DEF_WARNING, "Number of nets in design (%d) exceeds " "maximum (%d)\n", total, MAX_NETNUMS); } DefReadNets(f, sections[DEF_NETS], oscale, FALSE, total); break; case DEF_IOTIMINGS: LefSkipSection(f, sections[DEF_IOTIMINGS]); break; case DEF_SCANCHAINS: LefSkipSection(f, sections[DEF_SCANCHAINS]); break; case DEF_CONSTRAINTS: LefSkipSection(f, sections[DEF_CONSTRAINTS]); break; case DEF_GROUPS: LefSkipSection(f, sections[DEF_GROUPS]); break; case DEF_EXTENSION: LefSkipSection(f, sections[DEF_EXTENSION]); break; case DEF_END: if (!LefParseEndStatement(f, "DESIGN")) { LefError(DEF_ERROR, "END statement out of context.\n"); keyword = -1; } break; } if (keyword == DEF_END) break; } if (Verbose > 0) Fprintf(stdout, "DEF read: Processed %d lines.\n", lefCurrentLine); LefError(DEF_ERROR, NULL); /* print statement of errors, if any, and reset */ /* If there were no TRACKS statements, then use the DIEAREA */ if (Xlowerbound == Xupperbound) { Xlowerbound = dXlowerbound; Xupperbound = dXupperbound; } if (Ylowerbound == Yupperbound) { Ylowerbound = dYlowerbound; Yupperbound = dYupperbound; } /* Cleanup */ if (f != NULL) fclose(f); *retscale = oscale; return err_fatal; } qrouter-1.4.88/configure0000755000175000017510000057706713625043307014604 0ustar nileshnilesh#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="VERSION" ac_unique_file="Makefile.in" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS QROUTER_LIB_DIR DIST_DIR INSTALL_TARGET ALL_TARGET STDLIBS LD_RUN_PATH SHLIB_CFLAGS WISH_EXE TK_LIB_DIR TCL_LIB_DIR LIB_SPECS_NOSTUB LIB_SPECS INC_SPECS EXTRA_LIB_SPECS stub_defs SHLIB_LIB_SPECS LDDL_FLAGS LD SHLIB_LD SHDLIB_EXT X_EXTRA_LIBS X_LIBS X_PRE_LIBS X_CFLAGS XMKMF EGREP GREP RM CP AUTOCONF RANLIB INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC REVISION VERSION target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_gnu_ld with_libdir with_distdir with_tcl with_tk with_tclincls with_tkincls with_tcllibs with_tklibs enable_memdebug with_x ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP XMKMF' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-memdebug enable memory debugging Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-libdir=DIR path to qrouter default config files --with-distdir=DIR install into location DIR for distribution --with-tcl=DIR Find tclConfig.sh in DIR --with-tk=DIR Find tkConfig.sh in DIR --with-tclincls=DIR Find tcl.h in DIR --with-tkincls=DIR Find tk.h in DIR --with-tcllibs=DIR Find Tcl library in DIR --with-tklibs=DIR Find Tk library in DIR --with-x use the X Window System Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Determine the host and build type. # =========================================================================== ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- PACKAGE=qrouter VERSION=`cat ./VERSION | cut -d. -f1-2` REVISION=`cat ./VERSION | cut -d. -f3` test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # Required programs # =========================================================================== ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 $as_echo_n "checking for library containing strerror... " >&6; } if ${ac_cv_search_strerror+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strerror (); int main () { return strerror (); ; return 0; } _ACEOF for ac_lib in '' cposix; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_strerror=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_strerror+:} false; then : break fi done if ${ac_cv_search_strerror+:} false; then : else ac_cv_search_strerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 $as_echo "$ac_cv_search_strerror" >&6; } ac_res=$ac_cv_search_strerror if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi if test "x$U" != "x"; then as_fn_error $? "Compiler not ANSI compliant" "$LINENO" 5 fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Extract the first word of "autoconf", so it can be a program name with args. set dummy autoconf; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AUTOCONF+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AUTOCONF"; then ac_cv_prog_AUTOCONF="$AUTOCONF" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AUTOCONF="autoconf" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_AUTOCONF" && ac_cv_prog_AUTOCONF=":" fi fi AUTOCONF=$ac_cv_prog_AUTOCONF if test -n "$AUTOCONF"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOCONF" >&5 $as_echo "$AUTOCONF" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "cp", so it can be a program name with args. set dummy cp; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CP"; then ac_cv_prog_CP="$CP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CP="cp" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CP" && ac_cv_prog_CP=":" fi fi CP=$ac_cv_prog_CP if test -n "$CP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CP" >&5 $as_echo "$CP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RM"; then ac_cv_prog_RM="$RM" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RM="rm" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_RM" && ac_cv_prog_RM=":" fi fi RM=$ac_cv_prog_RM if test -n "$RM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 $as_echo "$RM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi for ac_func in setenv putenv do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # Linker # ========================================= #------------------------------------------------------------ # AC_PROG_LD - find the path to the GNU or non-GNU linker # (This stuff ripped from libtool) #------------------------------------------------------------ # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 $as_echo_n "checking for ld used by GCC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case "$ac_prog" in # Accept absolute paths. [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${ac_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ac_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then test "$with_gnu_ld" != no && break else test "$with_gnu_ld" != yes && break fi fi done IFS="$ac_save_ifs" else ac_cv_path_LD="$LD" # Let the user override the test with a path. fi fi LD="$ac_cv_path_LD" if test -n "$LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${ac_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU ld's only accept -v. if $LD -v 2>&1 &5; then ac_cv_prog_gnu_ld=yes else ac_cv_prog_gnu_ld=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gnu_ld" >&5 $as_echo "$ac_cv_prog_gnu_ld" >&6; } with_gnu_ld=$ac_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for va_copy" >&5 $as_echo_n "checking for va_copy... " >&6; } if ${ac_cv_c_va_copy+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { va_list ap1, ap2; va_copy(ap1,ap2); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_c_va_copy="yes" else ac_cv_c_va_copy="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_va_copy" >&5 $as_echo "$ac_cv_c_va_copy" >&6; } if test "$ac_cv_c_va_copy" = "yes" then $as_echo "#define HAVE_VA_COPY 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __va_copy" >&5 $as_echo_n "checking for __va_copy... " >&6; } if ${ac_cv_c___va_copy+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { va_list ap1, ap2; __va_copy(ap1,ap2); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_c___va_copy="yes" else ac_cv_c___va_copy="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c___va_copy" >&5 $as_echo "$ac_cv_c___va_copy" >&6; } if test "$ac_cv_c___va_copy" = "yes" then $as_echo "#define HAVE___VA_COPY 1" >>confdefs.h fi # Options # ========================================= QROUTER_LIB_DIR="share/qrouter" # Check whether --with-libdir was given. if test "${with_libdir+set}" = set; then : withval=$with_libdir; QROUTER_LIB_DIR=$withval fi # Force warnings to stop compilation. Use # this only for development cleanup. # ========================================= # if test "$GCC" = "yes" ; then # CFLAGS="${CFLAGS} -Wall -Werror" # fi # Interpreter Options # ========================================= qrouter_with_tcl="yes" qrouter_with_tk="yes" qrouter_with_tcl_includes="" qrouter_with_tk_includes="" qrouter_with_tcl_libraries="" qrouter_with_tk_libraries="" usingTcl=1 stub_defs="" # For distributed installs, where the run-time files are installed in a # place that is a temporary staging area, like DESTDIR, but unlike DESTDIR, # the prefix is replaced by the destination directory, rather than appended # to it. DIST_DIR="\${exec_prefix}" # Check whether --with-distdir was given. if test "${with_distdir+set}" = set; then : withval=$with_distdir; if test "$withval" = "no" -o "$withval" = "NO" ; then DIST_DIR="\${exec_prefix}" else DIST_DIR=${withval} fi fi # Check whether --with-tcl was given. if test "${with_tcl+set}" = set; then : withval=$with_tcl; qrouter_with_tcl=$withval if test "$withval" = "no" -o "$withval" = "NO"; then usingTcl= fi fi #----------------------------------------------------- # SHDLIB_EXT needs to be defined outside of the # Tcl/Tk environment, otherwise the Makefile # target can't differentiate between qrouter and # qrouter.so #----------------------------------------------------- case $target in *-hpux*) SHDLIB_EXT=".sl" SHDLIB_EXT_ALT=".sl" ;; *cygwin*) SHDLIB_EXT=".dll" SHDLIB_EXT_ALT=".dll.a" ;; *darwin*) SHDLIB_EXT=".dylib" SHDLIB_EXT_ALT=".dylib" ;; *) SHDLIB_EXT=".so" SHDLIB_EXT_ALT=".so" ;; esac # Check whether --with-tk was given. if test "${with_tk+set}" = set; then : withval=$with_tk; qrouter_with_tk=$withval fi # Check whether --with-tclincls was given. if test "${with_tclincls+set}" = set; then : withval=$with_tclincls; qrouter_with_tcl_includes=$withval fi # Check whether --with-tkincls was given. if test "${with_tkincls+set}" = set; then : withval=$with_tkincls; qrouter_with_tk_includes=$withval fi # Check whether --with-tcllibs was given. if test "${with_tcllibs+set}" = set; then : withval=$with_tcllibs; qrouter_with_tcl_libraries=$withval fi # Check whether --with-tklibs was given. if test "${with_tklibs+set}" = set; then : withval=$with_tklibs; qrouter_with_tk_libraries=$withval fi # ----------------------------------------------------------------------- # Find the Tcl build configuration file "tclConfig.sh" # ----------------------------------------------------------------------- if test $usingTcl ; then TCL_INC_DIR="." TK_INC_DIR="." { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclConfig.sh" >&5 $as_echo_n "checking for tclConfig.sh... " >&6; } tcl_config_sh="" if test "$qrouter_with_tcl" = "no" ; then qrouter_with_tcl="" elif test "$qrouter_with_tcl" != "yes" ; then # # Verify that a tclConfig.sh file exists in the directory specified # by --with-tcl. # for dir in \ $qrouter_with_tcl do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/unix/tclConfig.sh" ; then tcl_config_sh="$dir/unix/tclConfig.sh" break fi done else # # Otherwise, search for Tcl configuration file. # # 1. Search previously named locations. for dir in \ $ac_default_prefix \ $exec_prefix do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/unix/tclConfig.sh" ; then tcl_config_sh="$dir/unix/tclConfig.sh" break fi done # 2. Search standard locations. if test "x$tcl_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[7-9].[0-9]* 2>/dev/null` \ /usr/local/tcl \ /usr/local/lib \ /usr/local \ `ls -dr /usr/lib/tcl[7-9].[0-9]* 2>/dev/null` \ `ls -dr /usr/share/tcltk/tcl[7-9].[0-9]* 2>/dev/null` \ /sw/lib \ /usr/lib \ /usr/lib64 \ /usr do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break fi done fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_config_sh}" >&5 $as_echo "${tcl_config_sh}" >&6; } if test "x$tcl_config_sh" = "x" ; then echo "Can't find Tcl configuration script \"tclConfig.sh\"" echo "Reverting to non-Tcl compilation" usingTcl= fi fi # ----------------------------------------------------------------------- # Find the Tk build configuration file "tkConfig.sh" # ----------------------------------------------------------------------- if test $usingTcl ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tkConfig.sh" >&5 $as_echo_n "checking for tkConfig.sh... " >&6; } tk_config_sh="" if test "$qrouter_with_tk" != "yes"; then # # Verify that a tkConfig.sh file exists in the directory specified # by --with-tcl or --with-tk. # for dir in \ $qrouter_with_tk \ $qrouter_with_tcl do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/unix/tkConfig.sh" ; then tk_config_sh="$dir/unix/tkConfig.sh" break fi done else # # Search for Tk configuration file. # # # 1. Search previously named locations. # for dir in \ $ac_default_prefix \ $exec_prefix do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/unix/tkConfig.sh" ; then tk_config_sh="$dir/unix/tkConfig.sh" break fi done # # 2. Search standard locations. # if test "x$tk_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[7-9].[0-9]* 2>/dev/null` \ `ls -dr /usr/local/tk/tk[7-9].[0-9]* 2>/dev/null` \ /usr/local/tcl \ /usr/local/lib \ /sw/lib \ /usr/local \ `ls -dr /usr/share/tcltk/tk[7-9].[0-9]* 2>/dev/null` \ `ls -dr /usr/lib/tcl[7-9].[0-9]* 2>/dev/null` \ `ls -dr /usr/lib/tk[7-9].[0-9]* 2>/dev/null` \ ${x_libraries} \ /usr/lib \ /usr/lib64 \ /usr do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break fi done fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tk_config_sh}" >&5 $as_echo "${tk_config_sh}" >&6; } if test "x$tk_config_sh" = "x" ; then echo "can't find Tk configuration script \"tkConfig.sh\"" echo "Reverting to non-Tcl compilation" usingTcl= fi fi # ----------------------------------------------------------------------- # Source in the Tcl/Tk configuration scripts. # ----------------------------------------------------------------------- if test $usingTcl ; then . $tcl_config_sh . $tk_config_sh # Should probably trust the config file contents, but this configure # file checks the Tcl and Tk include and lib directories. Since # the config file doesn't separate out the libraries from the strings # passed to the compiler/linker, do it manually here. # # Extract TCL_LIB_DIR from TCL_LIB_SPEC # Extract TK_LIB_DIR from TK_LIB_SPEC # Extract TCL_INC_DIR from TCL_INCLUDE_SPEC # Extract TK_INC_DIR from TK_INCLUDE_SPEC # # These will be the defaults unless overridden by configure command line tmpstr=${TCL_LIB_SPEC#*-L} TCL_LIB_DIR=${tmpstr% -l*} tmpstr=${TK_LIB_SPEC#*-L} TK_LIB_DIR=${tmpstr% -l*} TCL_INC_DIR=${TCL_INCLUDE_SPEC#*-I} TK_INC_DIR=${TK_INCLUDE_SPEC#*-I} if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then : elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then : elif test "$TCL_VERSION" = "$TK_VERSION" ; then : else echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" echo "Reverting to non-Tcl compile" usingTcl= fi fi if test $usingTcl ; then if test "x${qrouter_with_tcl_includes}" != "x" ; then if test -r "${qrouter_with_tcl_includes}/tcl.h" ; then TCL_INC_DIR=${qrouter_with_tcl_includes} else echo "Can't find tcl.h in \"${qrouter_with_tcl_includes}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for dir in \ ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ ${TCL_PREFIX}/include \ ${TCL_SRC_DIR}/generic \ ${TCL_INC_DIR} do if test -r "$dir/tcl.h" ; then TCL_INC_DIR=$dir break fi done if test "x${TCL_INC_DIR}" = "x" ; then echo "Can't find tcl.h header file" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then if test "x${qrouter_with_tk_includes}" != "x" ; then if test -r "${qrouter_with_tk_includes}/tk.h" ; then TK_INC_DIR=${qrouter_with_tk_includes} else echo "Can't find tk.h in \"${qrouter_with_tk_includes}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for dir in \ ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ ${TK_PREFIX}/include \ ${TK_SRC_DIR}/generic \ ${TK_INC_DIR} \ ${TCL_INC_DIR} do if test -r "$dir/tk.h" ; then TK_INC_DIR=$dir break fi done if test "x${TK_INC_DIR}" = "x" ; then echo "Can't find tk.h header file" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then case $target in *-sunos4*|*-*-netbsd|NetBSD-*|FreeBSD-*|OpenBSD-*) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" ;; *) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" ;; esac loclib=`echo ${TCL_LIB_SPEC} | sed -e 's/.*-L//' -e 's/ .*//'` if test "x${TCL_LIB_SPEC}" = "x" ; then TCL_LIB_SPEC="-l${TCL_LIB_NAME}" fi if test "x${TK_LIB_SPEC}" = "x" ; then TK_LIB_SPEC="-l${TK_LIB_NAME}" fi # Find the version of "wish" that corresponds to TCL_EXEC_PREFIX # We really ought to run "ldd" to confirm that the linked libraries match. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wish executable" >&5 $as_echo_n "checking for wish executable... " >&6; } for dir in \ ${TK_EXEC_PREFIX}/bin \ ${TK_EXEC_PREFIX} do for wishexe in \ wish \ wish${TK_VERSION} \ wish.exe \ wish${TK_VERSION}.exe do if test -r "$dir/$wishexe" ; then WISH_EXE=$dir/$wishexe break fi done if test "x${WISH_EXE}" != "x" ; then break fi done if test "x${WISH_EXE}" = "x" ; then echo "Warning: Can't find executable for \"wish\". You may have to" echo "manually set the value for WISH_EXE in the netgen startup script." { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${WISH_EXE}" >&5 $as_echo "${WISH_EXE}" >&6; } fi if test "x${qrouter_with_tcl_libraries}" != "x" ; then for libname in \ "${qrouter_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ "${qrouter_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" do if test -r "$libname" ; then TCL_LIB_DIR="${qrouter_with_tcl_libraries}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library in \"${qrouter_with_tcl_libraries}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for libpfix in "lib64" "lib" do libname1="${TCL_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" libname2="${TCL_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" if test -r "$libname1" -o -r "$libname2" ; then TCL_LIB_DIR="${TCL_EXEC_PREFIX}/${libpfix}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then if test "x${qrouter_with_tk_libraries}" != "x" ; then for libname in \ "${qrouter_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ "${qrouter_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" do if test -r "$libname" ; then TK_LIB_DIR="${qrouter_with_tk_libraries}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library in \"${qrouter_with_tk_libraries}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for libpfix in "lib64" "lib" do libname1="${TK_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TK_LIB_NAME}${SHDLIB_EXT}" libname2="${TK_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" if test -r "$libname1" -o -r "$libname2" ; then TK_LIB_DIR="${TK_EXEC_PREFIX}/${libpfix}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi # Check whether --enable-memdebug was given. if test "${enable_memdebug+set}" = set; then : enableval=$enable_memdebug; if test "x$qrouter_with_tcl" = "x" ; then LIBS="${LIBS} -lefence" else $as_echo "#define TCL_MEM_DEBUG 1" >>confdefs.h fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. $as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" # For Solaris; some versions of Sun CC require a space after -R and # others require no space. Words are not sufficient . . . . { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 $as_echo_n "checking whether -R must be followed by a space... " >&6; } ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" ac_xsave_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } X_LIBS="$X_LIBS -R$x_libraries" else LIBS="$ac_xsave_LIBS -R $x_libraries" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } X_LIBS="$X_LIBS -R $x_libraries" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 $as_echo "neither works" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_c_werror_flag=$ac_xsave_c_werror_flag LIBS=$ac_xsave_LIBS fi # Check for system-dependent libraries X programs must link with. # Do this before checking for the system-independent R6 libraries # (-lICE), since we may need -lsocket or whatever for X linking. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn Johnson says this is needed for Ultrix, if the X # libraries were built with DECnet support. And Karl Berry says # the Alpha needs dnet_stub (dnet does not exist). ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XOpenDisplay (); int main () { return XOpenDisplay (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_dnet_ntoa=yes else ac_cv_lib_dnet_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet_stub $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_stub_dnet_ntoa=yes else ac_cv_lib_dnet_stub_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_xsave_LIBS" # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) # needs -lnsl. # The nsl library prevents programs from opening the X display # on Irix 5.2, according to T.E. Dickey. # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = xyes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if ${ac_cv_lib_bsd_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_gethostbyname=yes else ac_cv_lib_bsd_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary # on later versions), says Simon Leinen: it contains gethostby* # variants that don't use the name server (or something). -lsocket # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes; then : fi if test $ac_cv_func_connect = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if ${ac_cv_lib_socket_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect=yes else ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes; then : X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi fi # Guillermo Gomez says -lposix is necessary on A/UX. ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" if test "x$ac_cv_func_remove" = xyes; then : fi if test $ac_cv_func_remove = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } if ${ac_cv_lib_posix_remove+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); int main () { return remove (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_posix_remove=yes else ac_cv_lib_posix_remove=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } if test "x$ac_cv_lib_posix_remove" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" if test "x$ac_cv_func_shmat" = xyes; then : fi if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } if ${ac_cv_lib_ipc_shmat+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lipc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); int main () { return shmat (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ipc_shmat=yes else ac_cv_lib_ipc_shmat=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } if test "x$ac_cv_lib_ipc_shmat" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS=$LDFLAGS test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # John Interrante, Karl Berry { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char IceConnectionNumber (); int main () { return IceConnectionNumber (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ICE_IceConnectionNumber=yes else ac_cv_lib_ICE_IceConnectionNumber=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi LDFLAGS=$ac_save_LDFLAGS fi if test "x$no_x" = "x"; then usingX11=1 else echo Cannot find X11---will compile anyway. echo Graphics will be disabled if test $usingTcl ; then echo "Cannot compile TCL version without X11, disabling." usingTcl= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XtToolkitInitialize in -lXt" >&5 $as_echo_n "checking for XtToolkitInitialize in -lXt... " >&6; } if ${ac_cv_lib_Xt_XtToolkitInitialize+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XtToolkitInitialize (); int main () { return XtToolkitInitialize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xt_XtToolkitInitialize=yes else ac_cv_lib_Xt_XtToolkitInitialize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xt_XtToolkitInitialize" >&5 $as_echo "$ac_cv_lib_Xt_XtToolkitInitialize" >&6; } if test "x$ac_cv_lib_Xt_XtToolkitInitialize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBXT 1 _ACEOF LIBS="-lXt $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XtDisplayInitialize in -lXt" >&5 $as_echo_n "checking for XtDisplayInitialize in -lXt... " >&6; } if ${ac_cv_lib_Xt_XtDisplayInitialize+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXt -lSM -lICE -lXpm -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XtDisplayInitialize (); int main () { return XtDisplayInitialize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xt_XtDisplayInitialize=yes else ac_cv_lib_Xt_XtDisplayInitialize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xt_XtDisplayInitialize" >&5 $as_echo "$ac_cv_lib_Xt_XtDisplayInitialize" >&6; } if test "x$ac_cv_lib_Xt_XtDisplayInitialize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBXT 1 _ACEOF LIBS="-lXt $LIBS" fi fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/mman.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mman_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_MMAN_H 1 _ACEOF fi done if test $usingTcl ; then ALL_TARGET="tcl" INSTALL_TARGET="install-tcl" $as_echo "#define TCL_QROUTER 1" >>confdefs.h stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS" else ALL_TARGET="nointerp" INSTALL_TARGET="install-nointerp" programs="$programs qrouter" fi case $target in *-linux*) $as_echo "#define LINUX 1" >>confdefs.h $as_echo "#define SYSV 1" >>confdefs.h case $target in *x86_64*) CPPFLAGS="$CPPFLAGS -m64 -fPIC" ;; esac ;; *solaris*) $as_echo "#define SYSV 1" >>confdefs.h ;; *irix*) $as_echo "#define SYSV 1" >>confdefs.h $as_echo "#define IRIX 1" >>confdefs.h $as_echo "#define _BSD_SIGNALS 1" >>confdefs.h ;; *sysv*) $as_echo "#define SYSV 1" >>confdefs.h ;; *cygwin*) $as_echo "#define CYGWIN 1" >>confdefs.h $as_echo "#define i386 1" >>confdefs.h ;; *darwin*) if test "$CPP" = "cc -E" ; then CPPFLAGS="$CPPFLAGS -no-cpp-precomp" fi ;; esac # ----------------------------------------------------------------------- # Tcl/Tk configuration # ----------------------------------------------------------------------- if test $usingTcl ; then LIB_SPECS_NOSTUB="${LIB_SPECS}" # ----------------------------------------------------------------------- # # Tk libraries and header files # # ----------------------------------------------------------------------- if test "${TK_INC_DIR}" != "/usr/include" ; then INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" fi if test "${TK_LIB_DIR}" = "/usr/lib" -o \ "${TK_LIB_DIR}" = "/usr/lib64" ; then LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} ${TK_LIB_SPEC}" LIB_SPECS="${LIB_SPECS} ${TK_STUB_LIB_SPEC}" else LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_STUB_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TK_LIB_DIR}" else loader_run_path="${TK_LIB_DIR}:${loader_run_path}" fi fi # ----------------------------------------------------------------------- # # Tcl libraries and header files # # Add a header file directory specification only if the Tcl headers reside # in a different directory from Tk's. # ## ----------------------------------------------------------------------- if test "${TCL_INC_DIR}" != "/usr/include" -a \ "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" fi if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ "${TCL_LIB_DIR}" = "/usr/lib64" -o \ "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} ${TCL_LIB_SPEC}" LIB_SPECS="${LIB_SPECS} ${TCL_STUB_LIB_SPEC}" else LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_STUB_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TCL_LIB_DIR}" else loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" fi fi #-------------------------------------------------------------------- # # Check if we can generate shared libraries on this system. Set flags # to generate shared libraries for systems that we know about. Start # with the values found in tclConfig.sh, make changes as we know about # the different systems. # #-------------------------------------------------------------------- # Initialize shared library build variables SHLIB_LD="" LDDL_FLAGS="-shared" SHDLIB_EXT=".so" EXTRA_LIB_SPECS="" build_shared="yes" case $target in *-bsdi2*|*-bsdi3*) LD="shlicc" LDDL_FLAGS="-r" EXTRA_LIB_SPECS="-ldl" ;; *darwin*) SHDLIB_EXT=".dylib" LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" LDFLAGS="${LDFLAGS} ${LIB_SPECS}" CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" ;; *cygwin*) SHDLIB_EXT=".dll" $as_echo "#define USE_DL_IMPORT 1" >>confdefs.h LDDL_FLAGS='-shared -Wl,--enable-auto-image-base' if test "x${loader_run_path}" != "x" ; then LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" fi ld_extra_libs=${LIB_SPECS} sub_extra_libs='-L${QROUTERDIR}/qrouter -ltclqrouter' ;; *-bsdi4*) SHLIB_CFLAGS="-export-dynamic -fPIC" LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@' ;; *-linux*) LDDL_FLAGS='-shared -Wl,-soname,$@' if test "x${loader_run_path}" != "x" ; then LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" fi LDFLAGS="" EXTRA_LIB_SPECS="-ldl" ;; *-freebsd*) # Not available on all versions: check for include file. SHLIB_CFLAGS="-fPIC" LDDL_FLAGS="-shared ${LIB_SPECS}" CFLAGS="${CFLAGS} -L/usr/X11R6/include" ;; *-openbsd*) SHLIB_CFLAGS="-fpic" LDDL_FLAGS="-shared ${LIB_SPECS}" CFLAGS="${CFLAGS} -I${X11BASE}/include" ;; *-netbsd*) # Not available on all versions: check for include file. ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = xyes; then : test_ok=yes else test_ok=no fi if test "$test_ok" = yes; then SHLIB_CFLAGS="-fpic" LDDL_FLAGS="-Bshareable -x ${LIB_SPEC}" fi ;; esac # If we're running gcc, then set SHLIB_CFLAGS flags for compiling # shared libraries for gcc, instead of those of the vendor's compiler. if test "$GCC" = "yes" ; then case $target in *cygwin*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$with_gnu_ld" = "yes" ; then case $target in *-openbsd*) ;; *) LDDL_FLAGS="${LDDL_FLAGS} -Wl,--version-script=symbol.map" ;; esac fi fi cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define REVISION "$REVISION" _ACEOF ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi qrouter-1.4.88/lib/0000755000175000017510000000000013625043307013415 5ustar nileshnileshqrouter-1.4.88/lib/route.cfg0000644000175000017510000000212613625043307015235 0ustar nileshnilesh# Route configuration file for OSU035 gate library # # Values are largely ignored in favor of those in the LEF file. # Cost information is required. Num_layers 3 Layer_1_name M1 Layer_2_name M2 Layer_3_name M3 Layer_1_width 0.8 Layer_2_width 0.8 Layer_3_width 0.8 Allow Adjacent Vias 1 layer 1 wire pitch 2.0 layer 2 wire pitch 1.6 layer 3 wire pitch 2.0 layer 1 horizontal layer 2 vertical layer 3 horizontal Num Passes 3 # Make sure 2 * Via Cost + Segment Cost > Jog Cost. # That prevents switching layers to move over one track position Route Segment Cost 2 Route Via Cost 10 Route Jog Cost 20 Route Crossover Cost 8 Route Block Cost 50 #Do not route these nets! (Perhaps power, clock ...) Do not route node vss Do not route node vdd #Route these nets first! Critical net! #Route Priority netxxx #Bounds for routes. This may not be the same as the gate boundries. X upper bound 1000.0 X lower bound 0 Y upper bound 1000.0 Y lower bound 0 # Complete gate information can be found here: lef ../lib/osu035_stdcells.lef qrouter-1.4.88/lib/osu035_stdcells.lef0000644000175000017510000023251713625043307017052 0ustar nileshnilesh# LEF file generated by Abstract Generator version 5.5.10 on Jul 30 14:47:58 2004 # # Contains LEF for all bins. # Options: [x] Antenna # [x] Geometry # [x] Technology VERSION 5.4 ; NAMESCASESENSITIVE ON ; BUSBITCHARS "[]" ; DIVIDERCHAR "/" ; UNITS DATABASE MICRONS 1000 ; END UNITS USEMINSPACING OBS ON ; USEMINSPACING PIN OFF ; CLEARANCEMEASURE EUCLIDEAN ; MANUFACTURINGGRID 0.1 ; LAYER nwell TYPE MASTERSLICE ; END nwell LAYER nactive TYPE MASTERSLICE ; END nactive LAYER pactive TYPE MASTERSLICE ; END pactive LAYER poly TYPE MASTERSLICE ; END poly LAYER cc TYPE CUT ; SPACING 0.9 ; END cc LAYER metal1 TYPE ROUTING ; DIRECTION HORIZONTAL ; PITCH 2 ; WIDTH 0.6 ; SPACING 0.6 ; RESISTANCE RPERSQ 0.07 ; CAPACITANCE CPERSQDIST 3e-05 ; END metal1 LAYER via TYPE CUT ; SPACING 0.6 ; END via LAYER metal2 TYPE ROUTING ; DIRECTION VERTICAL ; PITCH 1.6 ; WIDTH 0.6 ; SPACING 0.6 ; RESISTANCE RPERSQ 0.07 ; CAPACITANCE CPERSQDIST 1.7e-05 ; END metal2 LAYER via2 TYPE CUT ; SPACING 0.6 ; END via2 LAYER metal3 TYPE ROUTING ; DIRECTION HORIZONTAL ; PITCH 2 ; WIDTH 0.6 ; SPACING 0.6 ; RESISTANCE RPERSQ 0.07 ; CAPACITANCE CPERSQDIST 7e-06 ; END metal3 LAYER via3 TYPE CUT ; SPACING 0.8 ; END via3 LAYER metal4 TYPE ROUTING ; DIRECTION VERTICAL ; PITCH 3.2 ; WIDTH 1.2 ; SPACING 1.2 ; RESISTANCE RPERSQ 0.04 ; CAPACITANCE CPERSQDIST 4e-06 ; END metal4 VIA M2_M1 DEFAULT LAYER metal1 ; RECT -0.400 -0.400 0.400 0.400 ; LAYER via1 ; RECT -0.200 -0.200 0.200 0.200 ; LAYER metal2 ; RECT -0.400 -0.400 0.400 0.400 ; END M2_M1 VIA M3_M2 DEFAULT LAYER metal2 ; RECT -0.400 -0.400 0.400 0.400 ; LAYER via2 ; RECT -0.200 -0.200 0.200 0.200 ; LAYER metal3 ; RECT -0.400 -0.400 0.400 0.400 ; END M3_M2 VIA M4_M3 DEFAULT LAYER metal3 ; RECT -0.400 -0.400 0.400 0.400 ; LAYER via3 ; RECT -0.200 -0.200 0.200 0.200 ; LAYER metal4 ; RECT -0.600 -0.600 0.600 0.600 ; END M4_M3 VIARULE viagen21 GENERATE LAYER metal1 ; DIRECTION HORIZONTAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.2 ; METALOVERHANG 0 ; LAYER metal2 ; DIRECTION VERTICAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.2 ; METALOVERHANG 0 ; LAYER via1 ; RECT -0.2 -0.2 0.2 0.2 ; SPACING 1 BY 1 ; END viagen21 VIARULE viagen32 GENERATE LAYER metal3 ; DIRECTION HORIZONTAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.2 ; METALOVERHANG 0 ; LAYER metal2 ; DIRECTION VERTICAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.2 ; METALOVERHANG 0 ; LAYER via2 ; RECT -0.2 -0.2 0.2 0.2 ; SPACING 1 BY 1 ; END viagen32 VIARULE viagen43 GENERATE LAYER metal3 ; DIRECTION HORIZONTAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.4 ; METALOVERHANG 0 ; LAYER metal4 ; DIRECTION VERTICAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.4 ; METALOVERHANG 0 ; LAYER via3 ; RECT -0.2 -0.2 0.2 0.2 ; SPACING 1.2 BY 1.2 ; END viagen43 VIARULE TURN1 GENERATE LAYER metal1 ; DIRECTION HORIZONTAL ; LAYER metal1 ; DIRECTION VERTICAL ; END TURN1 VIARULE TURN2 GENERATE LAYER metal2 ; DIRECTION HORIZONTAL ; LAYER metal2 ; DIRECTION VERTICAL ; END TURN2 VIARULE TURN3 GENERATE LAYER metal3 ; DIRECTION HORIZONTAL ; LAYER metal3 ; DIRECTION VERTICAL ; END TURN3 VIARULE TURN4 GENERATE LAYER metal4 ; DIRECTION HORIZONTAL ; LAYER metal4 ; DIRECTION VERTICAL ; END TURN4 SITE corner CLASS PAD ; SYMMETRY R90 Y ; SIZE 300.000 BY 300.000 ; END corner SITE IO CLASS PAD ; SYMMETRY Y ; SIZE 90.000 BY 300.000 ; END IO SITE core CLASS CORE ; SYMMETRY Y ; SIZE 1.600 BY 20.000 ; END core MACRO FILL CLASS CORE ; FOREIGN FILL 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 1.600 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT -0.400 -0.600 2.000 0.600 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT -0.400 19.400 2.000 20.600 ; END END vdd END FILL MACRO AND2X1 CLASS CORE ; FOREIGN AND2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.600 9.800 3.400 11.400 ; RECT 2.000 10.600 3.400 11.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.000 -0.600 3.800 5.200 ; RECT -0.400 -0.600 6.800 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 12.600 6.000 13.400 ; RECT 5.200 14.800 6.000 18.800 ; RECT 5.400 3.200 6.000 18.800 ; RECT 4.600 1.200 5.400 3.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 3.600 14.800 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 5.200 ; RECT 0.600 5.200 2.400 5.800 ; RECT 1.800 5.200 2.400 6.600 ; RECT 4.000 5.800 4.800 6.600 ; RECT 1.800 6.000 4.800 6.600 ; RECT 4.000 5.800 4.600 14.200 ; RECT 2.200 13.600 4.600 14.200 ; RECT 2.200 13.600 2.800 18.800 ; RECT 2.000 14.800 2.800 18.800 ; END END AND2X1 MACRO AND2X2 CLASS CORE ; FOREIGN AND2X2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.200 7.200 2.800 9.400 ; RECT 2.400 7.000 3.200 7.800 ; RECT 2.000 8.600 2.800 9.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.000 -0.600 3.800 5.000 ; RECT -0.400 -0.600 6.800 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 8.600 6.000 9.400 ; RECT 5.200 10.800 6.000 18.800 ; RECT 5.400 4.200 6.000 18.800 ; RECT 4.600 1.200 5.400 5.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 3.600 11.200 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 5.200 ; RECT 0.600 1.200 1.200 6.000 ; RECT 0.600 5.400 2.400 6.000 ; RECT 1.800 5.800 4.800 6.400 ; RECT 4.000 5.800 4.800 6.600 ; RECT 4.000 5.800 4.600 10.600 ; RECT 2.200 10.000 4.600 10.600 ; RECT 2.200 10.000 2.800 18.800 ; RECT 2.000 14.800 2.800 18.800 ; END END AND2X2 MACRO AOI21X1 CLASS CORE ; FOREIGN AOI21X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 8.600 1.200 9.400 ; RECT 1.200 8.800 2.000 9.800 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 6.600 2.800 8.200 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 5.000 3.800 5.800 4.600 ; RECT 5.200 4.600 6.000 5.400 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 1.000 -0.600 1.800 5.200 ; RECT -0.400 -0.600 6.800 0.600 ; RECT 5.200 -0.600 6.000 3.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 1.200 4.200 9.400 ; RECT 5.200 10.800 6.000 18.800 ; RECT 3.600 8.800 6.000 9.400 ; RECT 5.200 8.600 6.000 9.400 ; RECT 5.200 8.600 5.800 18.800 ; RECT 3.600 1.200 4.400 5.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 6.800 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 10.800 4.400 11.400 ; RECT 0.400 10.800 1.200 18.800 ; RECT 3.600 10.800 4.400 18.800 ; END END AOI21X1 MACRO AOI22X1 CLASS CORE ; FOREIGN AOI22X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 8.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 8.600 1.200 9.400 ; RECT 1.200 8.800 2.000 9.800 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 6.600 2.800 8.200 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 6.800 8.600 7.600 10.200 ; END END C PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 5.200 6.600 5.800 8.600 ; RECT 5.200 6.600 6.000 7.400 ; RECT 5.000 7.800 5.800 8.600 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.800 -0.600 1.600 5.200 ; RECT -0.400 -0.600 8.400 0.600 ; RECT 6.800 -0.600 7.600 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 8.600 4.400 9.400 ; RECT 5.200 10.800 6.000 17.600 ; RECT 5.200 9.600 5.800 17.600 ; RECT 3.800 9.600 5.800 10.200 ; RECT 3.400 1.200 5.000 5.200 ; RECT 3.800 1.200 4.400 10.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 8.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 10.800 4.400 11.400 ; RECT 3.600 10.800 4.400 18.800 ; RECT 0.400 10.800 1.200 18.800 ; RECT 6.800 10.800 7.600 18.800 ; RECT 3.600 18.200 7.600 18.800 ; END END AOI22X1 MACRO BUFX2 CLASS CORE ; FOREIGN BUFX2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 4.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 7.800 1.200 9.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 5.200 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 1.200 4.400 8.600 ; RECT 3.600 10.800 4.400 18.800 ; RECT 3.800 1.200 4.400 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 5.200 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 6.400 ; RECT 0.400 5.800 2.600 6.400 ; RECT 2.000 9.400 3.200 10.200 ; RECT 2.000 5.800 2.600 11.400 ; RECT 0.400 10.800 2.600 11.400 ; RECT 0.400 10.800 1.200 18.800 ; END END BUFX2 MACRO BUFX4 CLASS CORE ; FOREIGN BUFX4 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.600 7.800 1.400 9.400 ; RECT 0.400 8.600 1.400 9.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 6.800 0.600 ; RECT 5.200 -0.600 6.000 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 1.200 4.400 5.200 ; RECT 4.000 4.600 4.600 11.800 ; RECT 3.600 10.800 4.400 18.800 ; RECT 3.600 6.600 4.600 7.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 5.200 10.800 6.000 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 6.400 ; RECT 0.400 5.800 3.000 6.400 ; RECT 2.400 8.000 3.400 8.800 ; RECT 2.400 5.800 3.000 11.400 ; RECT 0.400 10.800 3.000 11.400 ; RECT 0.400 10.800 1.200 18.800 ; END END BUFX4 MACRO DFFNEGX1 CLASS CORE ; FOREIGN DFFNEGX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 19.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN Q DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 14.600 9.400 15.400 10.200 ; RECT 18.000 1.200 18.800 18.800 ; RECT 14.600 9.600 18.800 10.200 ; RECT 15.000 5.600 18.800 6.200 ; RECT 15.000 5.400 15.800 6.200 ; END END Q PIN CLK DIRECTION INPUT ; PORT LAYER metal2 ; RECT 5.200 6.800 6.000 13.400 ; LAYER via1 ; RECT 5.400 12.800 5.800 13.200 ; RECT 5.400 7.000 5.800 7.400 ; LAYER metal1 ; RECT 5.200 12.600 6.000 13.400 ; RECT 1.200 6.800 12.800 7.400 ; RECT 12.000 6.600 12.800 7.400 ; RECT 5.200 6.800 6.000 7.600 ; RECT 4.200 4.600 5.000 5.400 ; RECT 4.000 5.400 4.800 7.400 ; RECT 1.200 6.600 2.800 7.400 ; RECT 5.400 13.400 6.200 14.200 ; END END CLK PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.800 8.400 3.600 9.200 ; RECT 6.800 8.600 7.600 9.400 ; RECT 2.800 8.600 7.600 9.200 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 19.600 0.600 ; RECT 16.400 -0.600 17.200 5.000 ; RECT 10.800 -0.600 11.600 3.200 ; RECT 7.400 -0.600 8.400 3.200 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 11.000 2.800 20.600 ; RECT -0.400 19.400 19.600 20.600 ; RECT 16.400 10.800 17.200 20.600 ; RECT 10.800 14.800 11.600 20.600 ; RECT 7.600 14.800 8.400 20.600 ; END END vdd OBS LAYER metal2 ; RECT 0.400 5.200 1.200 10.800 ; RECT 3.600 3.200 4.400 10.000 ; RECT 3.600 3.200 4.200 14.800 ; RECT 3.600 10.800 4.400 14.800 ; RECT 13.200 3.200 14.000 11.400 ; RECT 13.200 3.200 13.800 14.800 ; RECT 13.200 12.200 14.000 14.800 ; LAYER metal1 ; RECT 0.400 1.200 1.200 6.000 ; RECT 3.600 14.000 4.400 15.400 ; RECT 3.600 14.800 5.600 15.400 ; RECT 4.800 14.800 5.600 18.800 ; RECT 4.800 1.200 5.600 3.200 ; RECT 3.600 2.600 5.600 3.200 ; RECT 3.600 2.600 4.400 4.000 ; RECT 3.600 11.400 9.000 12.000 ; RECT 3.600 11.400 4.400 12.200 ; RECT 8.200 11.400 9.000 12.200 ; RECT 9.200 1.200 10.000 3.200 ; RECT 9.200 1.200 9.800 4.400 ; RECT 7.000 3.800 9.800 4.400 ; RECT 7.000 3.800 7.800 4.600 ; RECT 7.000 13.400 7.800 14.200 ; RECT 9.800 13.400 10.600 14.200 ; RECT 7.000 13.600 10.600 14.200 ; RECT 9.200 13.600 9.800 18.800 ; RECT 9.200 14.800 10.000 18.800 ; RECT 13.200 14.000 14.000 14.800 ; RECT 13.400 14.800 14.600 18.800 ; RECT 0.400 9.800 5.000 10.400 ; RECT 4.200 10.200 11.400 10.800 ; RECT 10.800 10.200 11.400 12.200 ; RECT 10.800 11.400 14.600 12.000 ; RECT 10.800 11.400 11.800 12.200 ; RECT 13.800 11.400 14.600 12.200 ; RECT 0.400 9.800 1.200 18.800 ; RECT 13.400 1.200 14.600 3.200 ; RECT 13.200 2.600 14.000 4.000 ; RECT 13.200 8.000 14.000 8.800 ; RECT 13.200 8.200 17.000 8.800 ; RECT 16.200 8.200 17.000 9.000 ; LAYER via1 ; RECT 0.600 10.200 1.000 10.600 ; RECT 0.600 5.400 1.000 5.800 ; RECT 3.800 14.200 4.200 14.600 ; RECT 3.800 11.600 4.200 12.000 ; RECT 3.800 3.400 4.200 3.800 ; RECT 13.400 14.200 13.800 14.600 ; RECT 13.400 8.200 13.800 8.600 ; RECT 13.400 3.400 13.800 3.800 ; END END DFFNEGX1 MACRO NOR3X1 CLASS CORE ; FOREIGN NOR3X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 12.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 4.600 3.800 5.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 6.600 5.200 7.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 5.200 8.600 6.800 9.400 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 3.200 ; RECT -0.400 -0.600 13.200 0.600 ; RECT 5.200 -0.600 6.000 2.800 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 1.200 4.400 3.200 ; RECT 10.000 12.000 10.800 17.600 ; RECT 10.000 10.600 10.800 11.400 ; RECT 10.000 10.600 10.600 17.600 ; RECT 7.400 10.600 10.800 11.200 ; RECT 7.400 3.200 8.000 11.200 ; RECT 6.800 1.200 7.600 4.000 ; RECT 4.000 3.400 8.000 4.000 ; RECT 4.000 2.600 4.600 4.000 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.800 2.800 20.600 ; RECT -0.400 19.400 13.200 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.600 11.600 4.200 12.200 ; RECT 3.600 11.600 4.200 18.800 ; RECT 3.600 12.800 4.400 18.800 ; RECT 0.600 11.600 1.200 18.800 ; RECT 0.400 12.800 1.200 18.800 ; RECT 6.800 13.000 7.600 18.800 ; RECT 3.600 18.200 7.600 18.800 ; RECT 5.400 11.800 9.000 12.400 ; RECT 5.400 11.800 6.000 17.600 ; RECT 5.200 12.800 6.000 17.600 ; RECT 8.400 12.000 9.200 18.000 ; RECT 11.600 12.000 12.400 18.000 ; RECT 8.600 12.000 9.200 18.800 ; RECT 11.600 12.000 12.200 18.800 ; RECT 8.600 18.200 12.200 18.800 ; END END NOR3X1 MACRO DFFPOSX1 CLASS CORE ; FOREIGN DFFPOSX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 19.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN Q DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 14.600 9.400 15.400 10.200 ; RECT 18.000 1.200 18.800 18.800 ; RECT 14.600 9.600 18.800 10.200 ; RECT 15.000 5.600 18.800 6.200 ; RECT 15.000 5.400 15.800 6.200 ; END END Q PIN CLK DIRECTION INPUT ; PORT LAYER metal1 ; RECT 1.200 6.600 2.800 7.400 ; RECT 13.400 12.200 14.800 13.000 ; RECT 13.400 10.600 14.000 13.000 ; RECT 11.600 10.600 14.000 11.200 ; RECT 11.600 6.800 12.200 11.200 ; RECT 11.000 6.600 11.800 7.400 ; RECT 1.200 6.800 12.200 7.400 ; RECT 5.400 3.800 6.000 7.400 ; RECT 5.200 3.800 6.000 4.600 ; RECT 4.200 6.800 5.000 7.600 ; END END CLK PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.600 8.400 3.400 9.200 ; RECT 6.800 8.600 7.600 9.400 ; RECT 2.600 8.600 7.600 9.200 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 19.600 0.600 ; RECT 16.400 -0.600 17.200 5.000 ; RECT 10.800 -0.600 11.600 3.200 ; RECT 7.400 -0.600 8.400 3.200 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 11.000 2.800 20.600 ; RECT -0.400 19.400 19.600 20.600 ; RECT 16.400 10.800 17.200 20.600 ; RECT 10.800 14.800 11.600 20.600 ; RECT 7.600 14.800 8.400 20.600 ; END END vdd OBS LAYER metal2 ; RECT 0.400 5.200 1.200 10.800 ; RECT 3.600 3.200 4.400 14.800 ; RECT 13.200 3.200 14.000 14.800 ; LAYER metal1 ; RECT 0.400 1.200 1.200 6.000 ; RECT 3.600 14.000 4.400 15.400 ; RECT 3.600 14.800 5.600 15.400 ; RECT 4.800 14.800 5.600 18.800 ; RECT 4.800 1.200 5.600 3.200 ; RECT 3.600 2.600 5.600 3.200 ; RECT 3.600 2.600 4.400 4.000 ; RECT 3.600 11.400 9.000 12.000 ; RECT 3.600 11.400 4.400 12.200 ; RECT 8.200 11.400 9.000 12.200 ; RECT 9.200 1.200 10.000 3.200 ; RECT 9.200 1.200 9.800 4.400 ; RECT 7.000 3.800 9.800 4.400 ; RECT 7.000 3.800 7.800 4.600 ; RECT 7.000 13.400 7.800 14.200 ; RECT 9.800 13.400 10.600 14.200 ; RECT 7.000 13.600 10.600 14.200 ; RECT 9.200 13.600 9.800 18.800 ; RECT 9.200 14.800 10.000 18.800 ; RECT 0.400 10.000 6.200 10.400 ; RECT 0.400 9.800 6.000 10.400 ; RECT 5.400 10.200 10.200 10.800 ; RECT 9.600 10.200 10.200 12.600 ; RECT 11.000 11.800 11.800 12.600 ; RECT 9.600 12.000 11.800 12.600 ; RECT 0.400 9.800 1.200 18.800 ; RECT 13.200 14.000 14.000 14.800 ; RECT 13.400 14.800 14.600 18.800 ; RECT 13.400 1.200 14.600 3.200 ; RECT 13.200 2.600 14.000 4.000 ; RECT 13.200 8.000 14.000 8.800 ; RECT 13.200 8.200 17.000 8.800 ; RECT 16.200 8.200 17.000 9.000 ; LAYER via1 ; RECT 0.600 10.200 1.000 10.600 ; RECT 0.600 5.400 1.000 5.800 ; RECT 3.800 14.200 4.200 14.600 ; RECT 3.800 11.600 4.200 12.000 ; RECT 3.800 3.400 4.200 3.800 ; RECT 13.400 14.200 13.800 14.600 ; RECT 13.400 8.200 13.800 8.600 ; RECT 13.400 3.400 13.800 3.800 ; END END DFFPOSX1 MACRO FAX1 CLASS CORE ; FOREIGN FAX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 24.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN YC DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 22.800 1.200 23.600 3.200 ; RECT 22.800 14.800 23.600 18.800 ; RECT 23.000 1.200 23.600 18.800 ; RECT 22.800 6.600 23.600 7.400 ; END END YC PIN YS DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 19.600 1.200 20.400 3.200 ; RECT 20.800 4.600 22.000 5.400 ; RECT 19.400 9.200 21.400 9.800 ; RECT 20.800 3.800 21.400 9.800 ; RECT 19.800 3.800 21.400 4.400 ; RECT 19.600 14.800 20.400 18.800 ; RECT 19.800 1.200 20.400 4.400 ; RECT 19.400 9.200 20.000 15.400 ; END END YS PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.600 6.000 2.000 6.600 ; RECT 17.800 6.800 18.600 7.600 ; RECT 17.800 5.600 18.400 7.600 ; RECT 7.400 5.600 18.400 6.200 ; RECT 0.600 6.000 8.200 6.400 ; RECT 1.200 5.800 18.400 6.200 ; RECT 0.400 6.600 1.200 7.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.200 7.200 2.800 9.400 ; RECT 16.000 6.800 16.800 7.600 ; RECT 9.400 6.800 16.800 7.400 ; RECT 2.200 7.200 10.200 7.600 ; RECT 2.800 7.000 16.800 7.400 ; RECT 5.800 7.000 6.600 7.800 ; RECT 2.200 7.200 3.600 7.800 ; RECT 2.000 8.600 2.800 9.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 8.600 5.200 9.400 ; RECT 14.400 8.000 15.200 8.800 ; RECT 10.400 8.200 15.200 8.800 ; RECT 3.600 8.600 11.800 9.000 ; RECT 3.600 8.600 11.000 9.200 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 4.000 ; RECT -0.400 -0.600 24.400 0.600 ; RECT 21.200 -0.600 22.000 3.200 ; RECT 18.000 -0.600 18.800 5.000 ; RECT 11.000 -0.600 11.800 3.800 ; RECT 7.800 -0.600 8.600 4.800 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 24.400 20.600 ; RECT 21.200 14.800 22.000 20.600 ; RECT 18.000 9.200 18.800 20.600 ; RECT 11.000 12.800 11.800 20.600 ; RECT 7.800 10.800 8.600 20.600 ; END END vdd OBS LAYER metal2 ; RECT 14.400 4.200 15.200 5.000 ; RECT 14.600 7.800 20.200 8.400 ; RECT 19.400 7.800 20.200 8.600 ; RECT 14.600 4.200 15.200 10.200 ; RECT 14.400 9.400 15.200 10.200 ; RECT 5.200 4.400 6.000 5.200 ; RECT 12.000 9.600 12.800 11.400 ; RECT 20.800 10.600 21.600 11.400 ; RECT 5.200 10.800 21.600 11.400 ; RECT 5.400 4.400 6.000 11.600 ; RECT 5.200 10.800 6.000 11.600 ; LAYER metal1 ; RECT 0.400 10.800 4.400 11.400 ; RECT 0.400 10.800 1.200 18.800 ; RECT 3.600 10.800 4.400 18.800 ; RECT 0.400 1.200 1.200 5.200 ; RECT 3.600 1.200 4.400 5.200 ; RECT 0.400 4.600 4.400 5.200 ; RECT 5.200 10.800 6.000 18.800 ; RECT 5.200 1.200 6.000 5.200 ; RECT 9.400 11.600 13.400 12.200 ; RECT 9.400 10.800 10.200 18.800 ; RECT 12.600 11.600 13.400 18.800 ; RECT 9.400 1.200 10.200 5.000 ; RECT 12.600 1.200 13.400 5.000 ; RECT 9.400 4.400 13.400 5.000 ; RECT 12.800 9.400 13.600 10.200 ; RECT 12.000 9.600 12.800 10.400 ; RECT 14.400 9.400 15.200 18.800 ; RECT 14.200 10.200 15.200 18.800 ; RECT 14.200 1.200 15.200 4.200 ; RECT 14.400 1.200 15.200 5.000 ; RECT 19.400 7.000 20.200 8.600 ; RECT 20.800 10.600 22.400 11.400 ; LAYER via1 ; RECT 5.400 11.000 5.800 11.400 ; RECT 5.400 4.600 5.800 5.000 ; RECT 12.200 9.800 12.600 10.200 ; RECT 14.600 9.600 15.000 10.000 ; RECT 14.600 4.400 15.000 4.800 ; RECT 19.600 8.000 20.000 8.400 ; RECT 21.000 10.800 21.400 11.200 ; END END FAX1 MACRO HAX1 CLASS CORE ; FOREIGN HAX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 16.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN YC DIRECTION OUTPUT ; PORT LAYER metal2 ; RECT 4.600 3.200 6.000 4.000 ; RECT 5.200 8.400 6.000 9.200 ; RECT 5.400 3.200 6.000 9.200 ; LAYER via1 ; RECT 4.800 3.400 5.200 3.800 ; RECT 5.400 8.600 5.800 9.000 ; LAYER metal1 ; RECT 4.600 1.200 5.400 4.000 ; RECT 5.200 8.400 6.000 18.800 ; END END YC PIN YS DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 13.200 10.600 14.000 11.400 ; RECT 14.200 14.800 15.000 18.800 ; RECT 14.400 13.600 15.000 18.800 ; RECT 13.400 4.000 15.000 4.600 ; RECT 14.400 1.200 15.000 4.600 ; RECT 13.400 13.600 15.000 14.200 ; RECT 14.200 1.200 15.000 3.200 ; RECT 13.400 4.000 14.000 14.200 ; END END YS PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.000 1.200 7.400 ; RECT 10.000 6.600 10.800 7.400 ; RECT 8.400 6.600 10.800 7.200 ; RECT 0.400 6.000 9.000 6.600 ; RECT 0.800 5.800 1.600 6.600 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.200 8.000 3.000 8.600 ; RECT 8.400 7.800 9.200 8.600 ; RECT 7.200 7.800 9.200 8.400 ; RECT 2.400 7.200 7.800 7.800 ; RECT 2.400 7.200 3.200 8.000 ; RECT 2.000 8.600 2.800 9.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 16.400 0.600 ; RECT 12.600 -0.600 13.400 3.200 ; RECT 6.200 -0.600 7.000 5.000 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 15.200 2.800 20.600 ; RECT -0.400 19.400 16.400 20.600 ; RECT 12.600 14.800 13.400 20.600 ; RECT 11.000 10.800 11.800 20.600 ; RECT 6.800 14.800 7.600 20.600 ; END END vdd OBS LAYER metal2 ; RECT 3.800 4.600 4.600 5.400 ; RECT 3.800 4.600 4.400 9.200 ; RECT 3.800 8.400 4.600 9.200 ; LAYER metal1 ; RECT 3.800 8.400 4.600 9.200 ; RECT 0.600 14.000 4.400 14.600 ; RECT 0.600 14.000 1.200 18.800 ; RECT 0.400 14.800 1.200 18.800 ; RECT 3.800 8.400 4.400 18.800 ; RECT 3.600 14.000 4.400 18.800 ; RECT 3.000 1.200 3.800 5.200 ; RECT 3.800 4.600 5.600 5.400 ; RECT 7.800 1.200 11.800 1.800 ; RECT 11.000 1.200 11.800 4.800 ; RECT 7.800 1.200 8.600 5.200 ; RECT 9.400 2.400 10.200 5.200 ; RECT 9.600 2.400 10.200 6.000 ; RECT 9.600 5.400 12.600 6.000 ; RECT 11.400 5.400 12.600 6.200 ; RECT 11.400 5.400 12.000 10.200 ; RECT 8.600 9.600 12.000 10.200 ; RECT 8.600 9.600 9.200 18.800 ; RECT 8.400 10.800 9.200 18.800 ; LAYER via1 ; RECT 4.000 8.600 4.400 9.000 ; RECT 4.000 4.800 4.400 5.200 ; END END HAX1 MACRO INVX1 CLASS CORE ; FOREIGN INVX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 3.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 3.800 1.200 5.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 3.600 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 3.600 20.600 ; END END vdd END INVX1 MACRO INVX2 CLASS CORE ; FOREIGN INVX2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 3.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.200 7.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 3.600 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 3.600 20.600 ; END END vdd END INVX2 MACRO INVX4 CLASS CORE ; FOREIGN INVX4 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 4.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.200 7.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 5.200 0.600 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 5.200 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd END INVX4 MACRO INVX8 CLASS CORE ; FOREIGN INVX8 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 8.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.200 7.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 8.400 0.600 ; RECT 6.800 -0.600 7.600 5.200 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 6.600 ; RECT 5.200 1.200 6.000 18.800 ; RECT 2.000 9.400 6.000 10.200 ; RECT 2.000 5.800 6.000 6.600 ; RECT 2.000 9.400 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 8.400 20.600 ; RECT 6.800 10.800 7.600 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd END INVX8 MACRO NAND2X1 CLASS CORE ; FOREIGN NAND2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 4.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.200 7.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 10.600 4.400 12.200 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 5.200 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 4.600 2.800 18.800 ; RECT 2.000 4.600 3.800 5.200 ; RECT 3.000 1.200 3.800 5.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 5.200 20.600 ; RECT 3.600 14.800 4.400 20.600 ; END END vdd END NAND2X1 MACRO NAND3X1 CLASS CORE ; FOREIGN NAND3X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 9.800 1.200 11.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 8.600 3.600 9.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 11.800 4.400 13.400 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 7.200 ; RECT -0.400 -0.600 6.800 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.200 14.000 2.800 18.800 ; RECT 5.200 14.800 6.000 18.800 ; RECT 5.200 10.600 6.000 11.400 ; RECT 5.200 6.800 5.800 18.800 ; RECT 2.200 14.000 5.800 14.600 ; RECT 4.200 6.800 5.800 7.400 ; RECT 4.000 1.200 4.800 7.200 ; RECT 2.000 14.800 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 3.600 15.200 4.400 20.600 ; END END vdd END NAND3X1 MACRO NOR2X1 CLASS CORE ; FOREIGN NOR2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 4.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 3.800 1.200 5.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 8.600 4.400 10.200 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 5.200 0.600 ; RECT 3.600 -0.600 4.400 3.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 3.200 ; RECT 3.000 10.800 3.800 18.800 ; RECT 2.000 10.800 3.800 11.600 ; RECT 2.200 1.200 2.800 11.600 ; RECT 2.000 6.600 2.800 7.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 5.200 20.600 ; END END vdd END NOR2X1 MACRO OAI21X1 CLASS CORE ; FOREIGN OAI21X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 7.400 ; RECT 1.200 6.200 2.000 7.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 7.800 2.800 9.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 4.600 10.800 5.200 13.400 ; RECT 5.200 10.600 6.000 11.400 ; RECT 4.400 12.600 5.200 13.400 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 4.400 ; RECT -0.400 -0.600 6.800 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.000 10.800 3.800 18.800 ; RECT 3.400 6.600 6.000 7.400 ; RECT 5.200 1.200 6.000 5.200 ; RECT 5.200 1.200 5.800 7.400 ; RECT 3.400 6.600 4.000 11.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 4.600 14.800 5.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 5.200 ; RECT 3.600 1.200 4.400 5.200 ; RECT 0.600 5.000 4.200 5.600 ; END END OAI21X1 MACRO OAI22X1 CLASS CORE ; FOREIGN OAI22X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 8.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 7.400 ; RECT 1.200 6.200 2.000 7.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 7.800 2.800 9.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 6.800 6.600 7.600 8.200 ; END END C PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 5.200 7.800 6.000 9.400 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 4.400 ; RECT -0.400 -0.600 8.400 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 6.600 4.200 18.800 ; RECT 3.600 6.600 6.000 7.200 ; RECT 5.400 2.400 6.000 7.200 ; RECT 5.200 2.400 6.000 5.200 ; RECT 3.000 10.800 5.000 18.800 ; RECT 3.600 6.600 4.400 7.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 8.400 20.600 ; RECT 6.800 10.800 7.600 20.600 ; END END vdd OBS LAYER metal1 ; RECT 3.600 1.200 7.600 1.800 ; RECT 0.400 1.200 1.200 5.200 ; RECT 3.600 1.200 4.400 5.200 ; RECT 6.800 1.200 7.600 5.200 ; RECT 0.600 5.000 4.200 5.600 ; END END OAI22X1 MACRO OR2X1 CLASS CORE ; FOREIGN OR2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 3.800 1.200 5.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 6.600 2.800 7.400 ; RECT 2.200 5.800 3.600 6.600 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 6.800 0.600 ; RECT 3.600 -0.600 4.400 3.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 1.200 6.000 3.200 ; RECT 5.400 1.200 6.000 14.800 ; RECT 4.600 14.800 5.400 18.800 ; RECT 4.800 14.200 6.000 14.800 ; RECT 5.200 8.600 6.000 9.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.000 10.800 3.800 20.600 ; RECT -0.400 19.400 6.800 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 3.200 ; RECT 2.200 1.200 2.800 4.800 ; RECT 2.200 4.200 4.800 4.800 ; RECT 4.200 4.200 4.800 7.800 ; RECT 3.800 7.200 4.400 10.200 ; RECT 3.800 9.400 4.600 10.200 ; RECT 0.400 9.600 4.600 10.200 ; RECT 0.400 9.600 1.200 18.800 ; END END OR2X1 MACRO OR2X2 CLASS CORE ; FOREIGN OR2X2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 3.800 1.200 5.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 6.600 3.000 7.400 ; RECT 2.400 7.400 3.200 8.200 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 6.800 0.600 ; RECT 3.600 -0.600 4.400 4.800 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 1.200 6.000 5.200 ; RECT 5.400 1.200 6.000 11.400 ; RECT 4.600 10.800 5.400 18.800 ; RECT 5.200 8.600 6.000 9.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.000 10.800 3.800 20.600 ; RECT -0.400 19.400 6.800 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 3.200 ; RECT 2.200 1.200 2.800 6.000 ; RECT 2.200 5.400 4.600 6.000 ; RECT 3.800 9.000 4.600 9.800 ; RECT 4.000 5.400 4.600 9.800 ; RECT 0.400 9.600 4.400 10.200 ; RECT 0.400 9.600 1.200 18.800 ; END END OR2X2 MACRO TBUFX1 CLASS CORE ; FOREIGN TBUFX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 8.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 6.000 6.600 7.600 7.400 ; END END A PIN EN DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 12.600 2.000 13.400 ; END END EN PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 8.400 0.600 ; RECT 6.400 -0.600 7.200 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.800 1.200 4.600 5.200 ; RECT 3.800 10.800 4.600 18.800 ; RECT 4.000 1.200 4.600 18.800 ; RECT 3.600 8.600 4.600 9.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 8.400 20.600 ; RECT 6.400 10.800 7.200 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 3.200 ; RECT 2.600 6.600 3.400 7.400 ; RECT 2.600 2.400 3.200 8.000 ; RECT 2.400 7.400 3.000 10.600 ; RECT 2.600 10.000 3.200 15.400 ; RECT 2.000 14.800 2.800 18.800 ; END END TBUFX1 MACRO TBUFX2 CLASS CORE ; FOREIGN TBUFX2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 11.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 9.000 6.600 10.800 7.400 ; END END A PIN EN DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.000 10.200 ; RECT 0.400 5.800 1.400 6.600 ; RECT 0.400 8.600 1.200 10.200 ; END END EN PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 11.600 0.600 ; RECT 8.400 -0.600 9.200 4.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 2.400 5.800 17.600 ; RECT 5.200 10.800 6.000 17.600 ; RECT 5.200 8.600 6.000 9.400 ; RECT 5.200 2.400 6.000 5.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 11.600 20.600 ; RECT 8.400 12.200 9.200 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 5.200 ; RECT 2.000 8.200 2.800 9.000 ; RECT 2.000 1.200 2.600 18.800 ; RECT 2.000 10.800 2.800 18.800 ; RECT 6.800 10.800 10.800 11.600 ; RECT 3.600 10.800 4.400 18.800 ; RECT 6.800 10.800 7.600 18.800 ; RECT 3.600 18.200 7.600 18.800 ; RECT 10.000 10.800 10.800 18.800 ; RECT 3.600 1.200 7.600 1.800 ; RECT 10.000 1.200 10.800 4.600 ; RECT 6.800 1.200 7.600 5.800 ; RECT 3.600 1.200 4.400 5.200 ; RECT 10.200 1.200 10.800 5.800 ; RECT 6.800 5.200 10.800 5.800 ; END END TBUFX2 MACRO XOR2X1 CLASS CORE ; FOREIGN XOR2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 11.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 2.000 7.400 ; RECT 4.000 7.000 4.800 7.800 ; RECT 2.000 7.000 4.800 7.600 ; RECT 0.400 6.800 2.600 7.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 9.200 6.600 10.800 7.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.200 -0.600 3.000 4.600 ; RECT -0.400 -0.600 11.600 0.600 ; RECT 8.200 -0.600 9.200 4.600 ; RECT 2.000 1.200 3.000 4.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 8.600 6.000 9.400 ; RECT 4.800 10.800 6.400 18.800 ; RECT 5.800 1.200 6.400 7.400 ; RECT 5.400 6.800 6.000 18.800 ; RECT 4.800 1.200 6.400 4.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.200 3.000 18.800 ; RECT -0.400 19.400 11.600 20.600 ; RECT 8.200 12.200 9.200 20.600 ; RECT 2.200 12.200 3.000 20.600 ; END END vdd OBS LAYER metal2 ; RECT 2.200 5.200 3.000 6.000 ; RECT 2.200 5.400 7.800 6.000 ; RECT 3.600 5.400 4.400 6.200 ; RECT 7.000 5.400 7.800 6.200 ; RECT 2.200 5.200 2.800 11.600 ; RECT 2.200 10.800 3.000 11.600 ; RECT 8.400 5.200 9.200 6.000 ; RECT 3.600 6.800 9.200 7.400 ; RECT 3.600 6.800 4.200 9.600 ; RECT 3.400 8.800 4.200 9.600 ; RECT 8.600 5.200 9.200 11.600 ; RECT 8.400 10.800 9.200 11.600 ; LAYER metal1 ; RECT 0.400 10.800 3.000 11.400 ; RECT 2.200 10.800 3.000 11.600 ; RECT 0.400 10.800 1.200 18.800 ; RECT 0.400 1.200 1.200 5.800 ; RECT 0.400 5.200 3.000 5.800 ; RECT 2.200 5.200 3.000 6.000 ; RECT 2.600 8.600 3.400 9.400 ; RECT 3.400 8.800 4.200 9.600 ; RECT 3.600 5.400 5.200 6.200 ; RECT 7.000 5.400 7.800 6.200 ; RECT 7.200 5.400 7.800 7.400 ; RECT 7.200 6.600 8.000 7.400 ; RECT 8.400 10.800 10.800 11.400 ; RECT 8.400 10.800 9.200 11.600 ; RECT 10.000 10.800 10.800 18.800 ; RECT 10.000 1.200 10.800 5.800 ; RECT 8.400 5.200 10.800 5.800 ; RECT 8.400 5.200 9.200 6.000 ; LAYER via1 ; RECT 2.400 11.000 2.800 11.400 ; RECT 2.400 5.400 2.800 5.800 ; RECT 3.600 9.000 4.000 9.400 ; RECT 3.800 5.600 4.200 6.000 ; RECT 7.200 5.600 7.600 6.000 ; RECT 8.600 11.000 9.000 11.400 ; RECT 8.600 5.400 9.000 5.800 ; END END XOR2X1 MACRO MUX2X1 CLASS CORE ; FOREIGN MUX2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 9.600 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 6.800 8.600 7.600 10.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 7.800 2.800 9.400 ; END END B PIN S DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 7.800 1.200 9.400 ; END END S PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.600 ; RECT -0.400 -0.600 10.000 0.600 ; RECT 7.200 -0.600 8.000 6.000 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 4.600 2.000 5.400 5.600 ; RECT 5.600 6.600 7.600 7.400 ; RECT 4.600 11.200 6.200 11.800 ; RECT 5.600 5.000 6.200 11.800 ; RECT 5.400 5.000 6.200 6.000 ; RECT 4.600 11.200 5.400 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 11.200 2.800 20.600 ; RECT -0.400 19.400 10.000 20.600 ; RECT 7.200 10.800 8.000 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 2.000 1.200 4.000 ; RECT 0.400 2.000 1.000 6.800 ; RECT 0.400 6.200 4.600 6.800 ; RECT 3.600 6.200 4.600 8.000 ; RECT 3.600 7.200 5.000 8.000 ; RECT 3.600 6.200 4.200 10.600 ; RECT 0.400 10.000 4.200 10.600 ; RECT 0.400 10.000 1.000 18.000 ; RECT 0.400 14.000 1.200 18.000 ; END END MUX2X1 MACRO XNOR2X1 CLASS CORE ; FOREIGN XNOR2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 11.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal2 ; RECT 3.600 5.400 4.400 6.200 ; RECT 7.000 5.400 7.800 6.200 ; RECT 3.600 5.400 7.800 6.000 ; LAYER via1 ; RECT 3.800 5.600 4.200 6.000 ; RECT 7.200 5.600 7.600 6.000 ; LAYER metal1 ; RECT 0.400 6.600 2.000 7.400 ; RECT 7.200 6.600 8.000 7.400 ; RECT 7.200 5.400 7.800 7.400 ; RECT 7.000 5.400 7.800 6.200 ; RECT 3.600 5.400 5.200 6.200 ; RECT 0.400 6.600 3.800 7.200 ; RECT 3.200 5.600 3.800 7.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 9.200 6.600 10.800 7.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.200 -0.600 3.000 4.600 ; RECT -0.400 -0.600 11.600 0.600 ; RECT 8.200 -0.600 9.200 4.600 ; RECT 2.000 1.200 3.000 4.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 4.800 1.200 6.400 4.800 ; RECT 6.200 8.600 7.600 9.400 ; RECT 6.200 8.200 6.800 11.400 ; RECT 4.800 10.800 6.400 18.800 ; RECT 5.800 1.200 6.400 8.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.200 3.000 18.800 ; RECT -0.400 19.400 11.600 20.600 ; RECT 8.200 12.200 9.200 20.600 ; RECT 2.200 12.200 3.000 20.600 ; END END vdd OBS LAYER metal2 ; RECT 1.800 5.200 2.600 6.000 ; RECT 1.800 5.200 2.400 11.600 ; RECT 1.800 10.800 2.600 11.600 ; RECT 8.400 5.200 9.200 6.000 ; RECT 4.400 6.800 9.200 7.400 ; RECT 4.400 6.800 5.200 7.600 ; RECT 8.600 5.200 9.200 11.600 ; RECT 8.400 10.800 9.200 11.600 ; LAYER metal1 ; RECT 0.400 1.200 1.200 5.800 ; RECT 0.400 5.200 2.600 5.800 ; RECT 1.800 5.200 2.600 6.000 ; RECT 4.400 6.800 5.200 7.600 ; RECT 4.400 6.800 5.000 8.800 ; RECT 2.400 8.200 5.000 8.800 ; RECT 2.400 8.200 3.200 9.000 ; RECT 4.600 9.400 5.400 10.200 ; RECT 2.000 9.600 5.400 10.200 ; RECT 0.400 10.800 2.600 11.400 ; RECT 2.000 9.600 2.600 11.600 ; RECT 1.800 10.800 2.600 11.600 ; RECT 0.400 10.800 1.200 18.800 ; RECT 8.400 10.800 10.800 11.400 ; RECT 8.400 10.800 9.200 11.600 ; RECT 10.000 10.800 10.800 18.800 ; RECT 10.000 1.200 10.800 5.800 ; RECT 8.400 5.200 10.800 5.800 ; RECT 8.400 5.200 9.200 6.000 ; LAYER via1 ; RECT 2.000 11.000 2.400 11.400 ; RECT 2.000 5.400 2.400 5.800 ; RECT 4.600 7.000 5.000 7.400 ; RECT 8.600 11.000 9.000 11.400 ; RECT 8.600 5.400 9.000 5.800 ; END END XNOR2X1 MACRO LATCH CLASS CORE ; FOREIGN LATCH 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 11.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN Q DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 7.400 7.600 10.800 8.400 ; RECT 10.000 1.200 10.800 18.800 ; END END Q PIN CLK DIRECTION INPUT ; PORT LAYER metal1 ; RECT 1.200 6.600 2.800 7.400 ; RECT 5.800 6.600 6.600 8.200 ; RECT 1.200 6.600 6.600 7.200 ; RECT 4.400 4.600 5.200 7.200 ; END END CLK PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.600 9.400 4.400 10.200 ; RECT 3.600 9.400 4.400 11.400 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 11.600 0.600 ; RECT 8.400 -0.600 9.200 5.200 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 10.800 2.800 20.600 ; RECT -0.400 19.400 11.600 20.600 ; RECT 8.400 10.800 9.200 20.600 ; END END vdd OBS LAYER metal2 ; RECT 0.400 5.200 1.200 10.800 ; RECT 5.200 3.200 6.000 14.800 ; LAYER metal1 ; RECT 0.400 9.800 1.200 18.800 ; RECT 0.400 1.200 1.200 6.000 ; RECT 0.400 8.000 5.000 8.600 ; RECT 0.400 8.000 1.200 8.800 ; RECT 4.200 8.000 5.000 8.800 ; RECT 5.200 14.000 6.000 18.800 ; RECT 5.000 14.800 6.200 18.800 ; RECT 5.000 1.200 6.200 3.200 ; RECT 5.200 1.200 6.000 4.000 ; RECT 5.200 9.400 9.400 10.200 ; LAYER via1 ; RECT 0.600 10.200 1.000 10.600 ; RECT 0.600 8.200 1.000 8.600 ; RECT 0.600 5.400 1.000 5.800 ; RECT 5.400 14.200 5.800 14.600 ; RECT 5.400 9.600 5.800 10.000 ; RECT 5.400 3.400 5.800 3.800 ; END END LATCH MACRO DFFSR CLASS CORE ; FOREIGN DFFSR 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 35.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN Q DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 32.400 1.200 33.200 5.800 ; RECT 32.600 5.000 33.400 11.000 ; RECT 32.400 10.200 33.200 18.800 ; END END Q PIN CLK DIRECTION INPUT ; PORT LAYER metal1 ; RECT 16.400 4.600 18.000 5.400 ; END END CLK PIN R DIRECTION INPUT ; PORT LAYER metal1 ; RECT 1.800 8.800 2.600 9.600 ; RECT 1.800 9.000 25.200 9.600 ; RECT 24.400 8.400 25.200 9.600 ; RECT 6.800 8.600 7.600 9.600 ; END END R PIN S DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 10.200 4.400 11.400 ; RECT 3.600 10.200 30.600 10.800 ; RECT 29.800 10.000 30.600 10.800 ; RECT 7.000 10.200 7.800 11.000 ; END END S PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 13.200 5.800 14.000 7.400 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.600 -0.600 4.400 5.200 ; RECT -0.400 -0.600 35.600 0.600 ; RECT 34.000 -0.600 34.800 3.200 ; RECT 27.600 -0.600 28.400 5.200 ; RECT 16.400 -0.600 17.200 3.200 ; RECT 13.200 -0.600 14.000 3.200 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 35.600 20.600 ; RECT 34.000 14.800 34.800 20.600 ; RECT 30.800 14.800 31.600 20.600 ; RECT 27.600 14.800 28.400 20.600 ; RECT 24.400 14.800 25.200 20.600 ; RECT 16.400 14.800 17.200 20.600 ; RECT 13.200 14.800 14.000 20.600 ; RECT 6.800 14.800 7.600 20.600 ; RECT 3.600 14.800 4.400 20.600 ; END END vdd OBS LAYER metal2 ; RECT 8.400 3.200 9.200 16.800 ; RECT 10.000 3.200 10.800 16.800 ; RECT 11.600 3.200 12.400 14.800 ; RECT 14.800 3.200 15.600 14.800 ; RECT 18.000 3.200 18.800 14.800 ; RECT 19.600 3.200 20.400 16.800 ; RECT 21.200 3.200 22.000 16.800 ; RECT 22.800 3.200 23.600 16.800 ; LAYER metal1 ; RECT 6.800 1.200 7.600 5.200 ; RECT 5.000 4.400 7.600 5.200 ; RECT 5.000 4.400 5.800 6.600 ; RECT 2.800 5.800 5.800 6.600 ; RECT 8.400 16.000 9.200 18.800 ; RECT 0.400 7.200 9.200 8.000 ; RECT 0.400 1.200 1.200 14.200 ; RECT 0.400 13.600 2.400 14.200 ; RECT 1.800 13.600 2.400 15.400 ; RECT 2.000 14.800 2.800 18.800 ; RECT 8.400 1.200 9.200 4.000 ; RECT 10.000 16.000 10.800 18.800 ; RECT 5.400 11.600 10.800 12.200 ; RECT 10.000 11.400 10.800 12.200 ; RECT 4.600 12.000 6.000 12.800 ; RECT 10.000 1.200 10.800 4.000 ; RECT 11.600 14.000 12.400 18.800 ; RECT 11.600 1.200 12.400 4.000 ; RECT 14.800 14.000 15.600 18.800 ; RECT 13.000 12.600 15.600 13.400 ; RECT 11.000 4.600 15.600 5.200 ; RECT 14.800 4.600 15.600 5.400 ; RECT 11.000 4.600 11.800 8.400 ; RECT 9.800 7.600 11.800 8.400 ; RECT 14.800 1.200 15.600 4.000 ; RECT 18.000 12.600 18.800 18.800 ; RECT 15.600 7.600 18.800 8.400 ; RECT 18.000 1.200 18.800 4.000 ; RECT 14.800 6.000 15.600 6.800 ; RECT 14.800 6.200 19.200 6.800 ; RECT 18.400 6.200 19.200 7.000 ; RECT 19.600 16.000 20.400 18.800 ; RECT 11.800 11.400 20.400 12.000 ; RECT 19.600 11.400 20.400 12.200 ; RECT 2.000 12.200 3.600 13.000 ; RECT 3.000 12.200 3.600 14.200 ; RECT 6.600 12.800 12.400 13.400 ; RECT 11.800 11.400 12.400 13.400 ; RECT 3.000 13.400 7.200 14.200 ; RECT 5.200 13.400 6.000 18.800 ; RECT 19.600 1.200 20.400 4.000 ; RECT 21.200 16.000 22.000 18.800 ; RECT 21.000 4.600 22.000 5.400 ; RECT 21.200 4.600 22.000 8.200 ; RECT 21.200 1.200 22.000 4.000 ; RECT 22.800 16.000 23.600 18.800 ; RECT 22.800 1.200 23.600 4.000 ; RECT 21.200 13.400 25.400 14.200 ; RECT 26.000 12.600 28.600 13.400 ; RECT 26.000 12.600 26.800 18.800 ; RECT 24.400 1.200 25.200 5.200 ; RECT 24.400 4.400 26.800 5.200 ; RECT 26.000 4.400 26.800 6.400 ; RECT 26.000 5.800 27.800 6.400 ; RECT 27.000 5.800 27.800 8.400 ; RECT 27.000 7.600 30.800 8.400 ; RECT 30.800 1.200 31.600 7.000 ; RECT 31.400 6.400 32.000 9.600 ; RECT 22.800 11.400 31.800 12.000 ; RECT 22.800 11.400 23.600 12.200 ; RECT 31.200 9.000 31.800 14.200 ; RECT 29.200 13.600 31.800 14.200 ; RECT 29.200 13.600 30.000 18.800 ; LAYER via1 ; RECT 8.600 16.200 9.000 16.600 ; RECT 8.600 7.400 9.000 7.800 ; RECT 8.600 3.400 9.000 3.800 ; RECT 10.200 16.200 10.600 16.600 ; RECT 10.200 11.600 10.600 12.000 ; RECT 10.200 3.400 10.600 3.800 ; RECT 11.800 14.200 12.200 14.600 ; RECT 11.800 3.400 12.200 3.800 ; RECT 15.000 14.200 15.400 14.600 ; RECT 15.000 12.800 15.400 13.200 ; RECT 15.000 6.200 15.400 6.600 ; RECT 15.000 3.400 15.400 3.800 ; RECT 18.200 14.200 18.600 14.600 ; RECT 18.200 7.800 18.600 8.200 ; RECT 18.200 3.400 18.600 3.800 ; RECT 19.800 16.200 20.200 16.600 ; RECT 19.800 11.600 20.200 12.000 ; RECT 19.800 3.400 20.200 3.800 ; RECT 21.400 16.200 21.800 16.600 ; RECT 21.400 13.600 21.800 14.000 ; RECT 21.400 3.400 21.800 3.800 ; RECT 23.000 16.200 23.400 16.600 ; RECT 23.000 11.600 23.400 12.000 ; RECT 23.000 3.400 23.400 3.800 ; END END DFFSR MACRO CLKBUF1 CLASS CORE ; FOREIGN CLKBUF1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 14.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.000 ; RECT 0.400 7.200 2.200 8.000 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 14.800 0.600 ; RECT 13.200 -0.600 14.000 5.200 ; RECT 10.000 -0.600 10.800 5.200 ; RECT 6.800 -0.600 7.600 5.200 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 11.600 1.200 12.400 6.600 ; RECT 11.600 9.400 14.000 10.200 ; RECT 13.200 5.800 14.000 10.200 ; RECT 11.600 5.800 14.000 6.600 ; RECT 11.600 9.400 12.400 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 14.800 20.600 ; RECT 13.200 10.800 14.000 20.600 ; RECT 10.000 10.800 10.800 20.600 ; RECT 6.800 10.800 7.600 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 6.600 ; RECT 2.000 5.800 3.800 6.600 ; RECT 3.000 7.200 5.600 8.000 ; RECT 3.000 5.800 3.800 10.200 ; RECT 2.000 9.400 3.800 10.200 ; RECT 2.000 9.400 2.800 18.800 ; RECT 5.200 1.200 6.000 6.600 ; RECT 5.200 5.800 7.400 6.600 ; RECT 6.600 7.200 9.000 8.000 ; RECT 6.600 5.800 7.400 10.200 ; RECT 5.200 9.400 7.400 10.200 ; RECT 5.200 9.400 6.000 18.800 ; RECT 8.400 1.200 9.200 6.600 ; RECT 8.400 5.800 10.600 6.600 ; RECT 9.800 7.200 12.400 8.000 ; RECT 9.800 5.800 10.600 10.200 ; RECT 8.400 9.400 10.600 10.200 ; RECT 8.400 9.400 9.200 18.800 ; END END CLKBUF1 MACRO CLKBUF2 CLASS CORE ; FOREIGN CLKBUF2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 20.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.000 ; RECT 0.400 7.200 2.200 8.000 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 21.200 0.600 ; RECT 19.600 -0.600 20.400 5.200 ; RECT 16.400 -0.600 17.200 5.200 ; RECT 13.200 -0.600 14.000 5.200 ; RECT 10.000 -0.600 10.800 5.200 ; RECT 6.800 -0.600 7.600 5.200 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 18.000 1.200 18.800 6.600 ; RECT 18.000 9.400 20.400 10.200 ; RECT 19.600 5.800 20.400 10.200 ; RECT 18.000 5.800 20.400 6.600 ; RECT 18.000 9.400 18.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 21.200 20.600 ; RECT 19.600 10.800 20.400 20.600 ; RECT 16.400 10.800 17.200 20.600 ; RECT 13.200 10.800 14.000 20.600 ; RECT 10.000 10.800 10.800 20.600 ; RECT 6.800 10.800 7.600 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 6.600 ; RECT 2.000 5.800 3.800 6.600 ; RECT 3.000 7.200 5.600 8.000 ; RECT 3.000 5.800 3.800 10.200 ; RECT 2.000 9.400 3.800 10.200 ; RECT 2.000 9.400 2.800 18.800 ; RECT 5.200 1.200 6.000 6.600 ; RECT 5.200 5.800 7.400 6.600 ; RECT 6.600 7.200 9.000 8.000 ; RECT 6.600 5.800 7.400 10.200 ; RECT 5.200 9.400 7.400 10.200 ; RECT 5.200 9.400 6.000 18.800 ; RECT 8.400 1.200 9.200 6.600 ; RECT 8.400 5.800 10.600 6.600 ; RECT 9.800 7.200 12.400 8.000 ; RECT 9.800 5.800 10.600 10.200 ; RECT 8.400 9.400 10.600 10.200 ; RECT 8.400 9.400 9.200 18.800 ; RECT 11.600 1.200 12.400 6.600 ; RECT 11.600 5.800 14.000 6.600 ; RECT 13.200 7.200 15.000 8.000 ; RECT 13.200 5.800 14.000 10.200 ; RECT 11.600 9.400 14.000 10.200 ; RECT 11.600 9.400 12.400 18.800 ; RECT 14.800 1.200 15.600 6.600 ; RECT 14.800 5.800 16.600 6.600 ; RECT 15.800 7.200 18.400 8.000 ; RECT 15.800 5.800 16.600 10.200 ; RECT 14.800 9.400 16.600 10.200 ; RECT 14.800 9.400 15.600 18.800 ; END END CLKBUF2 MACRO CLKBUF3 CLASS CORE ; FOREIGN CLKBUF3 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 27.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.000 ; RECT 0.400 7.200 2.200 8.000 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 27.600 0.600 ; RECT 26.000 -0.600 26.800 5.200 ; RECT 22.800 -0.600 23.600 5.200 ; RECT 19.600 -0.600 20.400 5.200 ; RECT 16.400 -0.600 17.200 5.200 ; RECT 13.200 -0.600 14.000 5.200 ; RECT 10.000 -0.600 10.800 5.200 ; RECT 6.800 -0.600 7.600 5.200 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 24.400 1.200 25.200 6.600 ; RECT 24.400 9.400 26.800 10.200 ; RECT 26.000 5.800 26.800 10.200 ; RECT 24.400 5.800 26.800 6.600 ; RECT 24.400 9.400 25.200 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 27.600 20.600 ; RECT 26.000 10.800 26.800 20.600 ; RECT 22.800 10.800 23.600 20.600 ; RECT 19.600 10.800 20.400 20.600 ; RECT 16.400 10.800 17.200 20.600 ; RECT 13.200 10.800 14.000 20.600 ; RECT 10.000 10.800 10.800 20.600 ; RECT 6.800 10.800 7.600 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 6.600 ; RECT 2.000 5.800 3.800 6.600 ; RECT 3.000 7.200 5.600 8.000 ; RECT 3.000 5.800 3.800 10.200 ; RECT 2.000 9.400 3.800 10.200 ; RECT 2.000 9.400 2.800 18.800 ; RECT 5.200 1.200 6.000 6.600 ; RECT 5.200 5.800 7.400 6.600 ; RECT 6.600 7.200 9.000 8.000 ; RECT 6.600 5.800 7.400 10.200 ; RECT 5.200 9.400 7.400 10.200 ; RECT 5.200 9.400 6.000 18.800 ; RECT 8.400 1.200 9.200 6.600 ; RECT 8.400 5.800 10.600 6.600 ; RECT 9.800 7.200 12.400 8.000 ; RECT 9.800 5.800 10.600 10.200 ; RECT 8.400 9.400 10.600 10.200 ; RECT 8.400 9.400 9.200 18.800 ; RECT 11.600 1.200 12.400 6.600 ; RECT 11.600 5.800 14.000 6.600 ; RECT 13.200 7.200 15.000 8.000 ; RECT 13.200 5.800 14.000 10.200 ; RECT 11.600 9.400 14.000 10.200 ; RECT 11.600 9.400 12.400 18.800 ; RECT 14.800 1.200 15.600 6.600 ; RECT 14.800 5.800 16.600 6.600 ; RECT 15.800 7.200 18.400 8.000 ; RECT 15.800 5.800 16.600 10.200 ; RECT 14.800 9.400 16.600 10.200 ; RECT 14.800 9.400 15.600 18.800 ; RECT 18.000 1.200 18.800 6.600 ; RECT 18.000 5.800 20.200 6.600 ; RECT 19.400 7.200 21.800 8.000 ; RECT 19.400 5.800 20.200 10.200 ; RECT 18.000 9.400 20.200 10.200 ; RECT 18.000 9.400 18.800 18.800 ; RECT 21.200 1.200 22.000 6.600 ; RECT 21.200 5.800 23.400 6.600 ; RECT 22.600 7.200 25.200 8.000 ; RECT 22.600 5.800 23.400 10.200 ; RECT 21.200 9.400 23.400 10.200 ; RECT 21.200 9.400 22.000 18.800 ; END END CLKBUF3 MACRO PADFC CLASS ENDCAP TOPLEFT ; FOREIGN PADFC 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 300.000 BY 300.000 ; SYMMETRY X Y R90 ; SITE corner ; OBS LAYER metal4 ; RECT 0.600 0.600 299.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 299.400 299.400 ; LAYER metal2 ; RECT 98.000 0.000 170.400 299.400 ; RECT 174.800 0.000 195.800 299.400 ; RECT 202.200 0.000 223.200 299.400 ; RECT 227.600 0.000 300.000 72.400 ; RECT 0.600 76.800 300.000 97.800 ; RECT 0.600 104.000 300.000 125.200 ; RECT 0.600 129.600 300.000 202.000 ; RECT 0.600 0.600 299.400 299.400 ; LAYER metal1 ; RECT 98.000 0.000 195.800 299.400 ; RECT 202.200 0.000 300.000 97.800 ; RECT 0.600 104.000 300.000 202.000 ; RECT 0.600 0.600 299.400 299.400 ; END END PADFC MACRO PADGND CLASS PAD ; FOREIGN PADGND 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 37.400 254.800 51.200 269.800 ; END END YPAD PIN gnd DIRECTION INOUT ; USE GROUND ; PORT CLASS CORE ; LAYER metal1 ; RECT 34.800 0.000 54.800 0.800 ; END END gnd OBS LAYER metal4 ; RECT 0.600 0.600 89.400 253.000 ; RECT 0.600 271.600 89.400 299.000 ; RECT 0.600 0.600 35.600 299.400 ; RECT 53.000 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 90.000 72.400 ; RECT 0.600 76.600 89.600 97.800 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; RECT 6.000 0.000 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 34.200 97.800 ; RECT 55.600 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 1.800 89.400 299.400 ; RECT 6.000 1.800 84.000 300.000 ; END END PADGND MACRO PADVDD CLASS PAD ; FOREIGN PADVDD 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 42.200 266.000 44.400 268.400 ; END END YPAD PIN vdd DIRECTION INOUT ; USE POWER ; PORT CLASS CORE ; LAYER metal1 ; RECT 35.400 0.000 54.600 0.800 ; END END vdd OBS LAYER metal4 ; RECT 0.600 0.600 89.400 264.200 ; RECT 0.600 270.200 89.400 299.000 ; RECT 0.600 0.600 40.400 299.400 ; RECT 46.200 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 34.400 72.400 ; RECT 35.400 0.000 54.600 300.000 ; RECT 55.600 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 1.800 89.400 299.400 ; RECT 6.000 1.800 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 34.400 97.800 ; RECT 55.600 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 1.800 89.400 299.400 ; RECT 6.000 1.800 84.000 300.000 ; END END PADVDD MACRO PADINC CLASS PAD ; FOREIGN PADINC 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 42.200 266.000 44.400 268.400 ; END END YPAD PIN DI DIRECTION OUTPUT ; PORT LAYER metal2 ; RECT 82.200 -0.400 83.000 0.400 ; RECT 81.600 0.000 83.400 0.400 ; END END DI OBS LAYER metal4 ; RECT 0.600 0.600 89.400 264.200 ; RECT 0.600 270.200 89.400 299.000 ; RECT 0.600 0.600 40.400 299.400 ; RECT 46.200 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 80.600 299.400 ; RECT 84.400 0.600 89.400 299.400 ; RECT 0.600 1.400 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 34.400 72.400 ; RECT 35.400 0.000 54.600 300.000 ; RECT 55.600 0.000 78.200 300.000 ; RECT 79.000 0.000 80.800 300.000 ; RECT 0.000 0.600 80.800 72.400 ; RECT 84.200 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 1.400 89.400 299.400 ; RECT 6.000 1.400 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; RECT 6.000 0.000 84.000 300.000 ; END END PADINC MACRO PADINOUT CLASS PAD ; FOREIGN PADINOUT 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 42.200 266.000 44.400 268.400 ; END END YPAD PIN DO DIRECTION INPUT ; PORT LAYER metal2 ; RECT 8.200 -0.400 9.000 0.400 ; RECT 7.600 0.000 9.400 0.400 ; END END DO PIN DI DIRECTION OUTPUT ; PORT LAYER metal2 ; RECT 82.200 -0.400 83.000 0.400 ; RECT 81.600 0.000 83.400 0.400 ; END END DI PIN OEN DIRECTION INPUT ; PORT LAYER metal2 ; RECT 2.600 -0.400 3.400 0.400 ; RECT 2.200 0.000 4.000 0.400 ; END END OEN OBS LAYER metal4 ; RECT 0.600 0.600 89.400 264.200 ; RECT 0.600 270.200 89.400 299.000 ; RECT 0.600 0.600 40.400 299.400 ; RECT 46.200 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 1.200 299.400 ; RECT 5.000 0.600 6.600 299.400 ; RECT 10.400 0.600 80.600 299.400 ; RECT 84.400 0.600 89.400 299.400 ; RECT 0.600 1.400 89.400 299.400 ; LAYER metal2 ; RECT 10.200 0.000 34.400 300.000 ; RECT 35.400 0.000 54.600 300.000 ; RECT 55.600 0.000 78.200 300.000 ; RECT 0.000 0.000 1.400 72.400 ; RECT 4.800 0.000 6.800 299.400 ; RECT 79.000 0.000 80.800 300.000 ; RECT 10.200 0.600 80.800 300.000 ; RECT 84.200 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 1.400 89.400 299.400 ; RECT 6.000 1.400 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; RECT 6.000 0.000 84.000 300.000 ; END END PADINOUT MACRO PADNC CLASS PAD ; FOREIGN PADNC 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; OBS LAYER metal4 ; RECT 0.600 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; LAYER metal1 ; RECT 0.000 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; END END PADNC MACRO PADOUT CLASS PAD ; FOREIGN PADOUT 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 42.200 266.000 44.400 268.400 ; END END YPAD PIN DO DIRECTION INPUT ; PORT LAYER metal2 ; RECT 8.200 -0.400 9.000 0.400 ; RECT 7.600 0.000 9.400 0.400 ; END END DO OBS LAYER metal4 ; RECT 0.600 0.600 89.400 264.200 ; RECT 0.600 270.200 89.400 299.000 ; RECT 0.600 0.600 40.400 299.400 ; RECT 46.200 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 6.600 299.400 ; RECT 10.400 0.600 89.400 299.400 ; RECT 0.600 1.400 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 1.400 72.400 ; RECT 2.200 0.000 4.000 299.400 ; RECT 4.800 0.000 6.800 299.400 ; RECT 10.200 0.000 34.400 300.000 ; RECT 35.400 0.000 54.600 300.000 ; RECT 55.600 0.000 78.200 300.000 ; RECT 79.000 0.000 80.800 300.000 ; RECT 81.600 0.000 83.400 300.000 ; RECT 0.000 0.600 6.800 72.400 ; RECT 10.200 0.600 90.000 72.400 ; RECT 84.200 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 1.400 89.400 299.400 ; RECT 6.000 1.400 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; RECT 6.000 0.000 84.000 300.000 ; END END PADOUT END LIBRARY qrouter-1.4.88/qrouter.sh.in0000644000175000017510000000336513625043307015320 0ustar nileshnilesh#!/bin/sh # # For installation, put this file (qrouter.sh) in a standard executable path. # Put startup script "qrouter.tcl" and shared library "qrouter.so" # in ${QROUTER_LIB_DIR}. # # This script starts qrouter under the Tcl interpreter, # reading commands from script qrouter.tcl which launches qrouter # and retains the Tcl interactive interpreter. # Parse for the argument "-noc[onsole]". If it exists, run qrouter # without the TkCon console. Strip this argument from the argument list. loclibdir=${QROUTER_LIB_DIR:=LIBDIR} export QROUTER_LIB_DIR QROUTER_WISH=WISH_EXE export QROUTER_WISH # Hacks for Cygwin if [ ${TERM:=""} = "cygwin" ]; then export PATH="$PATH:$loclibdir" export DISPLAY=${DISPLAY:=":0"} fi # Don't use the console if "-noc[onsole]" was specified. # Also, if "-i", "-h", or "-c" is specified, then this is # a batch-mode operation and the console should be ignored. TKCON=true NULLG= ARGS="" for i in $@ ; do case $i in -noc*) TKCON= ;; -nog*) NULLG=true TKCON= ;; -c*) TKCON= ARGS="$ARGS $i" ;; -i* | -h*) NULLG=true TKCON= ARGS="$ARGS $i" ;; *) ARGS="$ARGS $i" ;; esac done set -- junk $ARGS shift if [ $TKCON ]; then exec ${loclibdir}/tkcon.tcl \ -eval "source ${loclibdir}/console.tcl" \ -slave "package require Tk; set argc $#; set argv [list $*]; \ source ${loclibdir}/qrouter.tcl" else # # Run the stand-in for wish (qrouterexec), which acts exactly like "wish" # except that it replaces ~/.wishrc with qrouter.tcl. This executable is # *only* needed when running without the console; the console itself is # capable of sourcing the startup script. # if [ $NULLG ]; then exec ${loclibdir}/qrouternullg -- $@ else exec ${loclibdir}/qrouterexec -- $@ fi fi qrouter-1.4.88/node.h0000644000175000017510000000215013625043307013743 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* node.h -- general purpose autorouter */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, based on code by Steve Beccue, 2003 */ /*--------------------------------------------------------------*/ #ifndef NODE_H #define GND_NET 1 #define VDD_NET 2 #define ANTENNA_NET 3 #define MIN_NET_NUMBER 4 void find_bounding_box(NET net); void defineRouteTree(NET); DPOINT is_testpoint(int, int, GATE, int, DSEG); void count_reachable_taps(u_char); void check_variable_pitch(int, int *, int *); void create_obstructions_from_variable_pitch(void); void count_pinlayers(void); void create_obstructions_from_gates(void); void expand_tap_geometry(void); void create_obstructions_inside_nodes(void); void create_obstructions_outside_nodes(void); void tap_to_tap_interactions(void); void make_routable(NODE node); void adjust_stub_lengths(void); void block_route(int x, int y, int lay, u_char dir); void find_route_blocks(); void clip_gate_taps(void); #define NODE_H #endif /* end of node.h */ qrouter-1.4.88/maze.c0000644000175000017510000025743213625043307013764 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* maze.c -- general purpose maze router routines. */ /* */ /* This file contains the main cost evaluation routine, */ /* the route segment generator, and a routine to search */ /* the database for all parts of a routed network. */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June 2011, based on code by Steve */ /* Beccue */ /*--------------------------------------------------------------*/ #include #include #include #include #define MAZE #include "qrouter.h" #include "qconfig.h" #include "point.h" #include "node.h" #include "maze.h" #include "lef.h" extern int TotalRoutes; /*--------------------------------------------------------------*/ /* find_unrouted_node() -- */ /* */ /* On a power bus, the nodes are routed individually, using the */ /* entire power bus as the destination. So to find out if a */ /* node is already routed or not, the only way is to check the */ /* routes recorded for the net and determine if any net */ /* endpoint is on a node. */ /* */ /* Return the first node found that is not connected to any */ /* route endpoint. If all nodes are routed, then return NULL */ /*--------------------------------------------------------------*/ NODE find_unrouted_node(NET net) { int i, numroutes; u_char *routednode; NODE node; ROUTE rt; SEG seg1, seg2; DPOINT tap; // Quick check: If the number of routes == number of nodes, // then return NULL and we're done. numroutes = 0; for (rt = net->routes; rt; rt = rt->next) numroutes++; if (numroutes == net->numnodes) return NULL; routednode = (u_char *)malloc(net->numnodes * sizeof(u_char)); for (i = 0; i < net->numnodes; i++) routednode[i] = 0; // Otherwise, we don't know which nodes have been routed, // so check each one individually. for (rt = net->routes; rt; rt = rt->next) { seg1 = rt->segments; if (seg1 == NULL) continue; seg2 = seg1; while (seg2->next) seg2 = seg2->next; for (node = net->netnodes; node; node = node->next) { if (routednode[node->nodenum] == 1) continue; for (tap = node->taps; tap; tap = tap->next) { if (seg1->x1 == tap->gridx && seg1->y1 == tap->gridy && seg1->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg1->x2 == tap->gridx && seg1->y2 == tap->gridy && seg1->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg2->x1 == tap->gridx && seg2->y1 == tap->gridy && seg2->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg2->x2 == tap->gridx && seg2->y2 == tap->gridy && seg2->layer == tap->layer) { routednode[node->nodenum] = 1; break; } } if (tap == NULL) { for (tap = node->extend; tap; tap = tap->next) { seg1 = rt->segments; seg2 = seg1; while (seg2->next) seg2 = seg2->next; if (seg1->x1 == tap->gridx && seg1->y1 == tap->gridy && seg1->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg1->x2 == tap->gridx && seg1->y2 == tap->gridy && seg1->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg2->x1 == tap->gridx && seg2->y1 == tap->gridy && seg2->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg2->x2 == tap->gridx && seg2->y2 == tap->gridy && seg2->layer == tap->layer) { routednode[node->nodenum] = 1; break; } } } } } for (node = net->netnodes; node; node = node->next) { if (routednode[node->nodenum] == 0) { free(routednode); return node; } } free(routednode); return NULL; /* Statement should never be reached */ } /*--------------------------------------------------------------*/ /* set_powerbus_to_net() */ /* If we have a power or ground net, go through the entire Obs */ /* array and mark all points matching the net as TARGET in Obs2 */ /* */ /* We do this after the call to PR_SOURCE, before the calls */ /* to set PR_TARGET. */ /* */ /* If any grid position was marked as TARGET, return 1, else */ /* return 0 (meaning the net has been routed already). */ /*--------------------------------------------------------------*/ int set_powerbus_to_net(int netnum) { int x, y, lay, rval; PROUTE *Pr; rval = 0; if ((netnum == VDD_NET) || (netnum == GND_NET) || (netnum == ANTENNA_NET)) { for (lay = 0; lay < Num_layers; lay++) for (x = 0; x < NumChannelsX; x++) for (y = 0; y < NumChannelsY; y++) if ((OBSVAL(x, y, lay) & NETNUM_MASK) == netnum) { Pr = &OBS2VAL(x, y, lay); // Skip locations that have been purposefully disabled if (!(Pr->flags & PR_COST) && (Pr->prdata.net == MAXNETNUM)) continue; else if (!(Pr->flags & PR_SOURCE)) { Pr->flags |= (PR_TARGET | PR_COST); Pr->prdata.cost = MAXRT; rval = 1; } } } return rval; } /*--------------------------------------------------------------*/ /* clear_non_source_targets -- */ /* */ /* Look at all target nodes of a net. For any that are not */ /* marked as SOURCE, but have terminal points marked as */ /* PROCESSED, remove the PROCESSED flag and put the position */ /* back on the stack for visiting on the next round. */ /*--------------------------------------------------------------*/ void clear_non_source_targets(NET net, POINT *pushlist) { NODE node; DPOINT ntap; PROUTE *Pr; POINT gpoint; int lay, x, y; for (node = net->netnodes; node; node = node->next) { for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &OBS2VAL(x, y, lay); if (Pr->flags & PR_TARGET) { if (Pr->flags & PR_PROCESSED) { Pr->flags &= ~PR_PROCESSED; if (~(Pr->flags & PR_ON_STACK)) { Pr->flags |= PR_ON_STACK; gpoint = allocPOINT(); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = *pushlist; *pushlist = gpoint; } } } } if (ntap == NULL) { // Try extended tap areas for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &OBS2VAL(x, y, lay); if (Pr->flags & PR_TARGET) { if (Pr->flags & PR_PROCESSED) { Pr->flags &= ~PR_PROCESSED; if (~(Pr->flags & PR_ON_STACK)) { Pr->flags |= PR_ON_STACK; gpoint = allocPOINT(); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = pushlist[1]; pushlist[1] = gpoint; } } } } } } } /*--------------------------------------------------------------*/ /* clear_target_node -- */ /* */ /* Remove PR_TARGET flags from all points belonging to a node */ /*--------------------------------------------------------------*/ void clear_target_node(NODE node) { int x, y, lay; NODEINFO lnode; DPOINT ntap; PROUTE *Pr; /* Process tap points of the node */ for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; if ((lay < Pinlayers) && (((lnode = NODEIPTR(x, y, lay)) == NULL) || (lnode->nodesav == NULL))) continue; Pr = &OBS2VAL(x, y, lay); Pr->flags = 0; Pr->prdata.net = node->netnum; } for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; if (lay < Pinlayers) { lnode = NODEIPTR(x, y, lay); if (lnode == NULL) continue; if (lnode->nodesav != node) continue; } Pr = &OBS2VAL(x, y, lay); Pr->flags = 0; Pr->prdata.net = node->netnum; } } /*--------------------------------------------------------------*/ /* count_targets() --- */ /* */ /* Count the number of nodes of a net that are still marked as */ /* TARGET. */ /*--------------------------------------------------------------*/ int count_targets(NET net) { NODE node; PROUTE *Pr; DPOINT ntap; int lay, x, y; int count = 0; for (node = net->netnodes; node; node = node->next) { for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &OBS2VAL(x, y, lay); if (Pr->flags & PR_TARGET) { count++; break; } } if (ntap == NULL) { // Try extended tap areas for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &OBS2VAL(x, y, lay); if (Pr->flags & PR_TARGET) { count++; break; } } } } return count; } /*--------------------------------------------------------------*/ /* set_node_to_net() --- */ /* */ /* Change the Obs2[][] flag values to "newflags" for all tap */ /* positions of route terminal "node". */ /* */ /* Return value is 1 if at least one terminal of the node */ /* is already marked as PR_SOURCE, indicating that the node */ /* has already been routed. Otherwise, the return value is */ /* zero if no error occured, and -1 if any point was found to */ /* be unoccupied by any net, which should not happen. */ /* */ /* If "bbox" is non-null, record the grid extents of the node */ /* in the x1, x2, y1, y2 values */ /* */ /* If "stage" is 1 (rip-up and reroute), then don't let an */ /* existing route prevent us from adding terminals. However, */ /* the area will be first checked for any part of the terminal */ /* that is routable, only resorting to overwriting colliding */ /* nets if there are no other available taps. Defcon stage 3 */ /* indicates desperation due to a complete lack of routable */ /* taps. This happens if, for example, a port is offset from */ /* the routing grid and tightly boxed in by obstructions. In */ /* such case, we allow routing on an obstruction, but flag the */ /* point. In the output stage, the stub route information will */ /* be used to reposition the contact on the port and away from */ /* the obstruction. */ /* */ /* If we completely fail to find a tap point under any */ /* condition, then return -2. This is a fatal error; there */ /* will be no way to route the net. */ /*--------------------------------------------------------------*/ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char stage) { int x, y, lay, rank, base, obsnet = 0; int result = 0; u_char found_one = FALSE; NODEINFO lnode; POINT gpoint; DPOINT ntap; PROUTE *Pr; /* If called from set_routes_to_net, the node has no taps, and the */ /* net is a power bus, just return. */ if ((node->taps == NULL) && (node->extend == NULL)) { if ((node->netnum == VDD_NET) || (node->netnum == GND_NET) || (node->netnum == ANTENNA_NET)) return result; } /* Process tap points of the node */ for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &OBS2VAL(x, y, lay); if ((Pr->flags & (newflags | PR_COST)) == PR_COST) { Fprintf(stderr, "Error: Tap position %d, %d layer %d not " "marked as source!\n", x, y, lay); return -1; // This should not happen. } if (Pr->flags & PR_SOURCE) { if (!found_one) return 1; // Node is already connected! else continue; // May be duplicate tap position } else if ((Pr->flags & PR_TARGET) && (newflags & PR_TARGET)) { if (!found_one) return 1; else continue; } else if (((Pr->prdata.net == node->netnum) || (stage == (u_char)2)) && !(Pr->flags & newflags)) { // If we got here, we're on the rip-up stage, and there // is an existing route completely blocking the terminal. // So we will route over it and flag it as a collision. if (Pr->prdata.net != node->netnum) { if ((Pr->prdata.net == (NO_NET | OBSTRUCT_MASK)) || (Pr->prdata.net == NO_NET)) continue; else Pr->flags |= PR_CONFLICT; } // Do the source and dest nodes need to be marked routable? Pr->flags |= (newflags == PR_SOURCE) ? newflags : (newflags | PR_COST); Pr->prdata.cost = (newflags == PR_SOURCE) ? 0 : MAXRT; // Rank the position according to how difficult it is to route to: // // 0: no restrictions // 1: requires a stub route // 2: inside the halo // 3: requires an offset // 4: requires an offset and a stub route rank = 0; if (lay < Pinlayers) { if (lnode = NODEIPTR(x, y, lay)) { if (lnode->flags & NI_OFFSET_MASK) rank = 2; if (lnode->flags & NI_STUB_MASK) rank++; } } // push this point on the stack to process if (pushlist != NULL) { if (~(Pr->flags & PR_ON_STACK)) { Pr->flags |= PR_ON_STACK; gpoint = allocPOINT(); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = pushlist[rank]; pushlist[rank] = gpoint; } } found_one = TRUE; // record extents if (bbox) { if (x < bbox->x1) bbox->x1 = x; if (x > bbox->x2) bbox->x2 = x; if (y < bbox->y1) bbox->y1 = y; if (y > bbox->y2) bbox->y2 = y; } } else if ((Pr->prdata.net < MAXNETNUM) && (Pr->prdata.net > 0)) obsnet++; } // Do the same for point in the halo around the tap, but only if // they have been attached to the net during a past routing run. for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; // Don't process extended areas if they coincide with other nodes, // or those that are out-of-bounds base = 0; if (lay < Pinlayers) { lnode = NODEIPTR(x, y, lay); if (lnode == NULL) continue; if (lnode->nodesav != node) continue; // Otherwise, rank according to ease of reaching the tap. if (lnode->flags & NI_OFFSET_MASK) base = 2; if (lnode->flags & NI_STUB_MASK) base++; } Pr = &OBS2VAL(x, y, lay); if (Pr->flags & PR_SOURCE) { if (!found_one) return 1; // Node is already connected! else continue; // May be duplicate tap record } else if ((Pr->flags & PR_TARGET) && (newflags & PR_TARGET)) { if (!found_one) return 1; else continue; } else if ( !(Pr->flags & newflags) && ((Pr->prdata.net == node->netnum) || (stage == (u_char)2 && Pr->prdata.net < MAXNETNUM) || (stage == (u_char)3))) { if (Pr->prdata.net != node->netnum) Pr->flags |= PR_CONFLICT; Pr->flags |= (newflags == PR_SOURCE) ? newflags : (newflags | PR_COST); Pr->prdata.cost = (newflags == PR_SOURCE) ? 0 : MAXRT; // push this point on the stack to process if (pushlist != NULL) { if (~(Pr->flags & PR_ON_STACK)) { Pr->flags |= PR_ON_STACK; gpoint = allocPOINT(); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; rank = (found_one == TRUE) ? 2 + base : base; gpoint->next = pushlist[rank]; pushlist[rank] = gpoint; } } found_one = TRUE; // record extents if (bbox) { if (x < bbox->x1) bbox->x1 = x; if (x > bbox->x2) bbox->x2 = x; if (y < bbox->y1) bbox->y1 = y; if (y > bbox->y2) bbox->y2 = y; } } else if ((Pr->prdata.net < MAXNETNUM) && (Pr->prdata.net > 0)) obsnet++; } // In the case that no valid tap points were found, if we're on the // rip-up and reroute section, try again, ignoring existing routes that // are in the way of the tap point. If that fails, then we will // route over obstructions and shift the contact when committing the // route solution. And if that fails, we're basically hosed. // // Make sure to check for the case that the tap point is simply not // reachable from any grid point, in the first stage, so we don't // wait until the rip-up and reroute stage to route them. if ((result == 0) && (!found_one)) { if (stage == (u_char)1) return set_node_to_net(node, newflags, pushlist, bbox, (u_char)2); else if (stage == (u_char)2) return set_node_to_net(node, newflags, pushlist, bbox, (u_char)3); else if ((stage == (u_char)0) && (obsnet == 0)) return set_node_to_net(node, newflags, pushlist, bbox, (u_char)3); else return -2; } return result; } /*--------------------------------------------------------------*/ /* Set all taps of node "node" to MAXNETNUM, so that it will */ /* not be routed to. */ /*--------------------------------------------------------------*/ int disable_node_nets(NODE node) { int x, y, lay; int result = 0; DPOINT ntap; PROUTE *Pr; /* Process tap points of the node */ for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &OBS2VAL(x, y, lay); if (Pr->flags & PR_SOURCE || Pr->flags & PR_TARGET || Pr->flags & PR_COST) { result = 1; } else if (Pr->prdata.net == node->netnum) { Pr->prdata.net = MAXNETNUM; } } // Do the same for point in the halo around the tap, but only if // they have been attached to the net during a past routing run. for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &OBS2VAL(x, y, lay); if (Pr->flags & PR_SOURCE || Pr->flags & PR_TARGET || Pr->flags & PR_COST) { result = 1; } else if (Pr->prdata.net == node->netnum) { Pr->prdata.net = MAXNETNUM; } } return result; } /*--------------------------------------------------------------*/ /* That which is already routed (routes should be attached to */ /* source nodes) is routable by definition. . . */ /*--------------------------------------------------------------*/ int set_route_to_net(NET net, ROUTE rt, int newflags, POINT *pushlist, SEG bbox, u_char stage) { int x, y, lay; int result = 0; NODEINFO lnode; POINT gpoint; SEG seg; NODE n2; PROUTE *Pr; if (rt && rt->segments) { for (seg = rt->segments; seg; seg = seg->next) { lay = seg->layer; x = seg->x1; y = seg->y1; while (1) { Pr = &OBS2VAL(x, y, lay); Pr->flags = (newflags == PR_SOURCE) ? newflags : (newflags | PR_COST); // Conflicts should not happen (check for this?) // if (Pr->prdata.net != node->netnum) Pr->flags |= PR_CONFLICT; Pr->prdata.cost = (newflags == PR_SOURCE) ? 0 : MAXRT; // push this point on the stack to process if (pushlist != NULL) { if (~(Pr->flags & PR_ON_STACK)) { Pr->flags |= PR_ON_STACK; gpoint = allocPOINT(); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = *pushlist; *pushlist = gpoint; } } // record extents if (bbox) { if (x < bbox->x1) bbox->x1 = x; if (x > bbox->x2) bbox->x2 = x; if (y < bbox->y1) bbox->y1 = y; if (y > bbox->y2) bbox->y2 = y; } // If we found another node connected to the route, // then process it, too. lnode = (lay >= Pinlayers) ? NULL : NODEIPTR(x, y, lay); n2 = (lnode) ? lnode->nodesav : NULL; if ((n2 != (NODE)NULL) && (n2 != net->netnodes)) { if (newflags == PR_SOURCE) clear_target_node(n2); result = set_node_to_net(n2, newflags, pushlist, bbox, stage); // On error, continue processing } // Process top part of via if (seg->segtype & ST_VIA) { if (lay != seg->layer) break; lay++; continue; } // Move to next grid position in segment if (x == seg->x2 && y == seg->y2) break; if (seg->x2 > seg->x1) x++; else if (seg->x2 < seg->x1) x--; if (seg->y2 > seg->y1) y++; else if (seg->y2 < seg->y1) y--; } } } return result; } /*--------------------------------------------------------------*/ /* Process a route and all routes that connect to it. Works */ /* like the routine above, but searches the route endpoints for */ /* connecting nodes and routes, and then recursively calls */ /* itself on the connecting routes, and other routes that */ /* connect do the nodes. */ /*--------------------------------------------------------------*/ int set_route_to_net_recursive(NET net, ROUTE rt, int newflags, POINT *pushlist, SEG bbox, u_char stage) { ROUTE route; int result; /* If route has been marked, return */ if (rt->flags & RT_VISITED) return 0; rt->flags |= RT_VISITED; /* First mark this route */ result = set_route_to_net(net, rt, newflags, pushlist, bbox, stage); if (result < 0) return result; /* Recursively mark the routes connected to the nodes of */ /* the endpoints or connected directly to the endpoints. */ if (rt->flags & RT_START_NODE) { for (route = net->routes; route; route = route->next) { if (!(route->flags & RT_START_NODE) && (route->start.route == rt)) { result = set_route_to_net_recursive(net, route, newflags, pushlist, bbox, stage); if (result < 0) return result; } if (!(route->flags & RT_END_NODE) && (route->end.route == rt)) { result = set_route_to_net_recursive(net, route, newflags, pushlist, bbox, stage); if (result < 0) return result; } } } else if (rt->start.route) { result = set_route_to_net_recursive(net, rt->start.route, newflags, pushlist, bbox, stage); if (result < 0) return result; } else Fprintf(stderr, "Error: Route start information not recorded, cannot walk.\n"); if (rt->flags & RT_END_NODE) { for (route = net->routes; route; route = route->next) { if (!(route->flags & RT_START_NODE) && (route->start.route == rt)) { result = set_route_to_net_recursive(net, route, newflags, pushlist, bbox, stage); if (result < 0) return result; } if (!(route->flags & RT_END_NODE) && (route->end.route == rt)) { result = set_route_to_net_recursive(net, route, newflags, pushlist, bbox, stage); if (result < 0) return result; } } } else if (rt->end.route) { result = set_route_to_net_recursive(net, rt->end.route, newflags, pushlist, bbox, stage); if (result < 0) return result; } else Fprintf(stderr, "Error: Route end information not recorded, cannot walk.\n"); return result; } /*--------------------------------------------------------------*/ /* Process all routes of a net that are connected in some way */ /* node "node", and set their routed positions to the value of */ /* "newflags" (PR_SOURCE or PR_DEST) in Obs2[]. */ /*--------------------------------------------------------------*/ int set_routes_to_net(NODE node, NET net, int newflags, POINT *pushlist, SEG bbox, u_char stage) { ROUTE rt; int result = 0; /* Clear marks on all routes */ for (rt = net->routes; rt; rt = rt->next) rt->flags &= ~RT_VISITED; /* Find any route that has node as an endpoint */ for (rt = net->routes; rt; rt = rt->next) { if ((rt->flags & RT_START_NODE) && (rt->start.node == node)) result = set_route_to_net_recursive(net, rt, newflags, pushlist, bbox, stage); else if ((rt->flags & RT_END_NODE) && (rt->end.node == node)) result = set_route_to_net_recursive(net, rt, newflags, pushlist, bbox, stage); if (result < 0) return result; } return result; } /*--------------------------------------------------------------*/ /* Used by find_colliding() (see below). Save net "netnum" */ /* to the list of colliding nets if it is not already in the */ /* list. Return 1 if the list got longer, 0 otherwise. */ /* Find the route of the net that includes the point of */ /* collision, and mark it for rip-up. */ /*--------------------------------------------------------------*/ static int addcollidingnet(NETLIST *nlptr, int netnum, int x, int y, int lay) { ROUTE rt; NETLIST cnl; NET fnet; SEG seg; int i; int sx, sy; u_char found; for (cnl = *nlptr; cnl; cnl = cnl->next) if (cnl->net->netnum == netnum) return 0; for (i = 0; i < Numnets; i++) { fnet = Nlnets[i]; if (fnet->netnum == netnum) { cnl = (NETLIST)malloc(sizeof(struct netlist_)); cnl->net = fnet; cnl->next = *nlptr; *nlptr = cnl; /* If there are no routes then we're done. */ if (fnet->routes == NULL) return 0; /* If there is only one route then there is no need */ /* to search or shuffle. */ if (fnet->routes->next == NULL) { fnet->routes->flags |= RT_RIP; return 1; } for (rt = fnet->routes; rt; rt = rt->next) { found = 0; for (seg = rt->segments; seg; seg = seg->next) { if ((seg->layer == lay) || ((seg->segtype & ST_VIA) && ((seg->layer + 1) == lay))) { sx = seg->x1; sy = seg->y1; while (1) { if ((sx == x) && (sy == y)) { found = 1; break; } if ((sx == seg->x2) && (sy == seg->y2)) break; if (sx < seg->x2) sx++; else if (sx > seg->x2) sx--; if (sy < seg->y2) sy++; else if (sy > seg->y2) sy--; } if (found) break; } } if (found) rt->flags |= RT_RIP; } return 1; } } return 0; } /*--------------------------------------------------------------*/ /* Find nets that are colliding with the given net "net", and */ /* create and return a list of them. */ /*--------------------------------------------------------------*/ NETLIST find_colliding(NET net, int *ripnum) { NETLIST nl = (NETLIST)NULL, cnl; ROUTE rt; SEG seg; int lay, x, y, orignet, rnum; /* Scan the routed points for recorded collisions. */ rnum = 0; for (rt = net->routes; rt; rt = rt->next) { if (rt->segments) { for (seg = rt->segments; seg; seg = seg->next) { lay = seg->layer; x = seg->x1; y = seg->y1; // The following skips over vias, which is okay, since // those positions are covered by segments on both layers // or are terminal positions that by definition can't // belong to a different net. while (1) { orignet = OBSVAL(x, y, lay) & ROUTED_NET_MASK; if ((orignet & DRC_BLOCKAGE) == DRC_BLOCKAGE) { /* If original position was a DRC-related blockage, */ /* find out which net or nets would be in conflict. */ if (needblock[lay] & (ROUTEBLOCKX | VIABLOCKX)) { if (x < NumChannelsX - 1) { orignet = OBSVAL(x + 1, y, lay) & ROUTED_NET_MASK; if (!(orignet & NO_NET)) { orignet &= NETNUM_MASK; if ((orignet != 0) && (orignet != net->netnum)) rnum += addcollidingnet(&nl, orignet, x, y, lay); } } if (x > 0) { orignet = OBSVAL(x - 1, y, lay) & ROUTED_NET_MASK; if (!(orignet & NO_NET)) { orignet &= NETNUM_MASK; if ((orignet != 0) && (orignet != net->netnum)) rnum += addcollidingnet(&nl, orignet, x, y, lay); } } } if (needblock[lay] & (ROUTEBLOCKY | VIABLOCKY)) { if (y < NumChannelsY - 1) { orignet = OBSVAL(x, y + 1, lay) & ROUTED_NET_MASK; if (!(orignet & NO_NET)) { orignet &= NETNUM_MASK; if ((orignet != 0) && (orignet != net->netnum)) rnum += addcollidingnet(&nl, orignet, x, y, lay); } } if (y > 0) { orignet = OBSVAL(x, y - 1, lay) & ROUTED_NET_MASK; if (!(orignet & NO_NET)) { orignet &= NETNUM_MASK; if ((orignet != 0) && (orignet != net->netnum)) rnum += addcollidingnet(&nl, orignet, x, y, lay); } } } } else { orignet &= NETNUM_MASK; if ((orignet != net->netnum) && (orignet != 0)) rnum += addcollidingnet(&nl, orignet, x, y, lay); } if ((x == seg->x2) && (y == seg->y2)) break; if (x < seg->x2) x++; else if (x > seg->x2) x--; if (y < seg->y2) y++; else if (y > seg->y2) y--; } } } } /* Diagnostic */ if ((nl != NULL) && (Verbose > 0)) { Fprintf(stdout, "Best route of %s collides with net%s: ", net->netname, (rnum > 1) ? "s" : ""); for (cnl = nl; cnl; cnl = cnl->next) { Fprintf(stdout, "%s ", cnl->net->netname); } Fprintf(stdout, "\n"); } if (ripnum) *ripnum = rnum; return nl; } /*--------------------------------------------------------------*/ /* ripup_dependent --- */ /* */ /* If a set of routes is being ripped out of a net (marked by */ /* RT_RIP in the flags), check if any routes below them have */ /* endpoints landing on a ripped-out net. If so, flag those */ /* nets for being ripped out as well. Repeat recursively. */ /*--------------------------------------------------------------*/ void ripup_dependent(NET net) { ROUTE rt, route; u_char rerun = TRUE; while (rerun) { rerun = FALSE; for (rt = net->routes; rt; rt = rt->next) { if (rt->flags & RT_RIP) continue; if (!(rt->flags & RT_START_NODE)) { route = rt->start.route; // route should not be NULL here. . . if (route && (route->flags & RT_RIP)) { rt->flags |= RT_RIP; rerun = TRUE; } } if (!(rt->flags & RT_END_NODE)) { route = rt->end.route; // route should not be NULL here. . . if (route && (route->flags & RT_RIP)) { rt->flags |= RT_RIP; rerun = TRUE; } } } } } /*--------------------------------------------------------------*/ /* Failure analysis (debug procedure) */ /* Occasionally when ripping up a net or net route, the Obs */ /* array shows a different net in the position that is being */ /* ripped, which should not happen. This routine does a quick */ /* analysis to determine if the position is orphaned. If so, */ /* it just returns and ripup_net will overwrite the position. */ /* If it appears to be connected to a valid route, it will find */ /* the net and route segment and run rip-up on it. */ /*--------------------------------------------------------------*/ void analyze_route_overwrite(int x, int y, int lay, int netnum) { u_char is_valid = FALSE; int i, sx, sy, l; NET fnet; ROUTE rt; SEG seg; /* Check on all sides to see if position is orphaned */ if ((x < NumChannelsX - 1) && (OBSVAL(x + 1, y, lay) & NETNUM_MASK) == netnum) is_valid = TRUE; else if ((x > 0) && (OBSVAL(x - 1, y, lay) & NETNUM_MASK) == netnum) is_valid = TRUE; else if ((y < NumChannelsY - 1) && (OBSVAL(x, y + 1, lay) & NETNUM_MASK) == netnum) is_valid = TRUE; else if ((y > 0) && (OBSVAL(x, y - 1, lay) & NETNUM_MASK) == netnum) is_valid = TRUE; else if ((lay < Num_layers - 1) && (OBSVAL(x, y, lay + 1) & NETNUM_MASK) == netnum) is_valid = TRUE; else if ((lay > 0) && (OBSVAL(x, y, lay - 1) & NETNUM_MASK) == netnum) is_valid = TRUE; if (is_valid == FALSE) { Fprintf(stderr, "Net position %d %d %d appears to be orphaned.\n", x, y, lay); return; /* No action, just overwrite */ } for (i = 0; i < Numnets; i++) { fnet = Nlnets[i]; if (fnet->netnum == netnum) { for (rt = fnet->routes; rt; rt = rt->next) { for (seg = rt->segments; seg; seg = seg->next) { sx = seg->x1; sy = seg->y1; l = seg->layer; while (1) { if ((sx == x) && (sy == y) && (l == lay)) { Fprintf(stderr, "Net position %d %d %d appears to " "belong to a valid network route.\n", x, y, lay); /* Found the route containing this position, */ /* so rip up the net now. */ Fprintf(stderr, "Taking evasive action against net " "%d\n", netnum); ripup_net(fnet, TRUE, FALSE, FALSE); return; } if ((sx == seg->x2) && (sy == seg->y2)) { if ((seg->segtype == ST_WIRE) || (l >= (lay + 1))) break; else l++; } else { if (seg->x2 > seg->x1) sx++; else if (seg->x2 < seg->x1) sx--; if (seg->y2 > seg->y1) sy++; else if (seg->y2 < seg->y1) sy--; } } } } break; } } } /*--------------------------------------------------------------*/ /* Remove all route records from a net. */ /*--------------------------------------------------------------*/ void remove_routes(ROUTE netroutes, u_char flagged) { ROUTE rt, rsave, rlast; SEG seg; /* Remove all flagged routing information from this net */ /* if "flagged" is true, otherwise remove all routing */ /* information. */ if (flagged && (netroutes != NULL)) { rlast = NULL; rsave = netroutes; while (rsave) { if (rsave->flags & RT_RIP) { rt = rsave; if (rlast == NULL) netroutes = rsave->next; else rlast->next = rsave->next; rsave = rsave->next; while (rt->segments) { seg = rt->segments->next; free(rt->segments); rt->segments = seg; } free(rt); } else { rlast = rsave; rsave = rsave->next; } } } else { while (netroutes) { rt = netroutes; netroutes = rt->next; while (rt->segments) { seg = rt->segments->next; free(rt->segments); rt->segments = seg; } free(rt); } } } /*--------------------------------------------------------------*/ /* Clear a DRC blockage. Normally, just remove the */ /* DRC_BLOCKAGE flag from Obs[]. However, more than one net */ /* may set a block on the position, so the lower four bits */ /* (OBSTRUCT_MASK) holds the reference count. */ /*--------------------------------------------------------------*/ void clear_drc_blockage(x, y, lay) { int blockcount; blockcount = OBSVAL(x, y, lay) & OBSTRUCT_MASK; OBSVAL(x, y, lay) &= ~OBSTRUCT_MASK; if (blockcount > 0) OBSVAL(x, y, lay) |= (blockcount - 1); else OBSVAL(x, y, lay) &= ~DRC_BLOCKAGE; } /*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/ void set_drc_blockage(x, y, lay) { int blockcount, obsval; obsval = OBSVAL(x, y, lay); if ((obsval & DRC_BLOCKAGE) == DRC_BLOCKAGE) { blockcount = OBSVAL(x, y, lay) & OBSTRUCT_MASK; OBSVAL(x, y, lay) &= ~OBSTRUCT_MASK; OBSVAL(x, y, lay) |= (blockcount + 1); } else if ((obsval & NETNUM_MASK) == 0) { OBSVAL(x, y, lay) &= ~OBSTRUCT_MASK; OBSVAL(x, y, lay) |= DRC_BLOCKAGE; } } /*--------------------------------------------------------------*/ /* ripup_net --- */ /* */ /* Rip up the entire network located at position x, y, lay. */ /* */ /* If argument "restore" is TRUE, then at each node, restore */ /* the crossover cost by attaching the node back to the */ /* Nodeinfo array. */ /* */ /* If argument "flagged" is TRUE, then only remove routes */ /* that have been flagged with RT_RIP. */ /* */ /* If argument "retain" is TRUE, then do not remove the route */ /* records from the net. This assumes that the calling routine */ /* will retain them for possible replacement in case of route */ /* failure. */ /*--------------------------------------------------------------*/ u_char ripup_net(NET net, u_char restore, u_char flagged, u_char retain) { int thisnet, oldnet, x, y, lay, dir; NODEINFO lnode; NODE node; ROUTE rt; SEG seg; DPOINT ntap; if (flagged) ripup_dependent(net); thisnet = net->netnum; for (rt = net->routes; rt; rt = rt->next) { if (flagged && !(rt->flags & RT_RIP)) continue; if (rt->segments) { for (seg = rt->segments; seg; seg = seg->next) { lay = seg->layer; x = seg->x1; y = seg->y1; while (1) { oldnet = OBSVAL(x, y, lay) & NETNUM_MASK; if ((oldnet > 0) && (oldnet < MAXNETNUM)) { if (oldnet != thisnet) { Fprintf(stderr, "Error: position %d %d layer %d has net " "%d not %d!\n", x, y, lay, oldnet, thisnet); // Stop-gap: Need to analyze the root of this problem. // However, a reasonable action is to try to find the // net and route associated with the incorrect net. analyze_route_overwrite(x, y, lay, oldnet); if ((rt == NULL) || (rt->segments == NULL)) return FALSE; // Something went wrong } // Reset the net number to zero along this route for // every point that is not a node tap. Points that // were routed over obstructions to reach off-grid // taps are returned to obstructions. if ((lay >= Pinlayers) || ((lnode = NODEIPTR(x, y, lay)) == NULL) || (lnode->nodesav == NULL)) { dir = OBSVAL(x, y, lay) & PINOBSTRUCTMASK; if (dir == 0) OBSVAL(x, y, lay) = OBSVAL(x, y, lay) & BLOCKED_MASK; else OBSVAL(x, y, lay) = NO_NET | dir; } else { // Clear routed mask bit OBSVAL(x, y, lay) &= ~ROUTED_NET; } // Routes which had blockages added on the sides due // to spacing constraints have DRC_BLOCKAGE set; // these flags should be removed. if (needblock[lay] & (ROUTEBLOCKX | VIABLOCKX)) { if ((x > 0) && ((OBSVAL(x - 1, y, lay) & DRC_BLOCKAGE) == DRC_BLOCKAGE)) clear_drc_blockage(x - 1, y, lay); else if ((x < NumChannelsX - 1) && ((OBSVAL(x + 1, y, lay) & DRC_BLOCKAGE) == DRC_BLOCKAGE)) clear_drc_blockage(x + 1, y, lay); } if (needblock[lay] & (ROUTEBLOCKY | VIABLOCKY)) { if ((y > 0) && ((OBSVAL(x, y - 1, lay) & DRC_BLOCKAGE) == DRC_BLOCKAGE)) clear_drc_blockage(x, y - 1, lay); else if ((y < NumChannelsY - 1) && ((OBSVAL(x, y + 1, lay) & DRC_BLOCKAGE) == DRC_BLOCKAGE)) clear_drc_blockage(x, y + 1, lay); } } // Check for and handle via end on last route segment. if ((x == seg->x2) && (y == seg->y2)) { if (seg->segtype & ST_VIA) { if (lay == seg->layer) lay++; else break; } else break; } if (x < seg->x2) x++; else if (x > seg->x2) x--; if (y < seg->y2) y++; else if (y > seg->y2) y--; } } } } // For each net node tap, restore the node pointer on Nodeinfo->nodeloc // so that crossover costs are again applied to routes over this node // tap. if (restore != 0) { if (flagged) { for (rt = net->routes; rt; rt = rt->next) { if (!(rt->flags & RT_RIP)) continue; for (seg = rt->segments; seg; seg = seg->next) { lay = seg->layer; if (lay >= Pinlayers) continue; x = seg->x1; y = seg->y1; lnode = NODEIPTR(x, y, lay); if (lnode && lnode->nodesav) lnode->nodeloc = lnode->nodesav; } } } else { for (node = net->netnodes; node; node = node->next) { for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; if (lay < Pinlayers) { lnode = NODEIPTR(x, y, lay); if (lnode) lnode->nodeloc = lnode->nodesav; } } } } } if (retain == FALSE) { remove_routes(net->routes, flagged); net->routes = NULL; // If we just ripped out a few of the routes, make sure all the // other net routes have not been overwritten. if (flagged) writeback_all_routes(net); } // If this was a specialnet (numnodes set to 0), then routes are // considered fixed obstructions and cannot be removed. return (net->numnodes == 0) ? FALSE : TRUE; } /*--------------------------------------------------------------*/ /* eval_pt - evaluate cost to get from given point to */ /* current point. Current point is passed in "ept", and */ /* the direction from the new point to the current point */ /* is indicated by "flags". */ /* */ /* ONLY consider the cost of the single step itself. */ /* */ /* If "stage" is nonzero, then this is a second stage */ /* routing, where we should consider other nets to be a */ /* high cost to short to, rather than a blockage. This */ /* will allow us to finish the route, but with a minimum */ /* number of collisions with other nets. Then, we rip up */ /* those nets, add them to the "failed" stack, and re- */ /* route this one. */ /* */ /* ARGS: none */ /* RETURNS: pointer to a new POINT record to put on the stack */ /* if the node needs to be (re)processed and isn't already */ /* on the stack, NULL otherwise. */ /* SIDE EFFECTS: none (get this right or else) */ /*--------------------------------------------------------------*/ POINT eval_pt(GRIDP *ept, u_char flags, u_char stage) { int thiscost = 0; int netnum; NODE node; NODEINFO nodeptr, lnode; NETLIST nl; PROUTE *Pr, *Pt; GRIDP newpt; POINT ptret = NULL; newpt = *ept; // ConflictCost is passed in flags if "force" option is set // and this route crosses a prohibited boundary. This allows // the prohibited move but gives it a high cost. if (flags & PR_CONFLICT) { thiscost = ConflictCost * 10; flags &= ~PR_CONFLICT; } switch (flags) { case PR_PRED_N: newpt.y--; break; case PR_PRED_S: newpt.y++; break; case PR_PRED_E: newpt.x--; break; case PR_PRED_W: newpt.x++; break; case PR_PRED_U: newpt.lay--; break; case PR_PRED_D: newpt.lay++; break; } Pr = &OBS2VAL(newpt.x, newpt.y, newpt.lay); nodeptr = (newpt.lay < Pinlayers) ? NODEIPTR(newpt.x, newpt.y, newpt.lay) : NULL; if (!(Pr->flags & (PR_COST | PR_SOURCE))) { // 2nd stage allows routes to cross existing routes netnum = Pr->prdata.net; if (stage && (netnum < MAXNETNUM)) { if ((newpt.lay < Pinlayers) && nodeptr && (nodeptr->nodesav != NULL)) return NULL; // But cannot route over terminals! // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) { if (nl->net->netnum == netnum) return NULL; } // In case of a collision, we change the grid point to be routable // but flag it as a point of collision so we can later see what // were the net numbers of the interfering routes by cross-referencing // the Obs[][] array. Pr->flags |= (PR_CONFLICT | PR_COST); Pr->prdata.cost = MAXRT; thiscost += ConflictCost; } else if (stage && ((netnum & DRC_BLOCKAGE) == DRC_BLOCKAGE)) { if ((newpt.lay < Pinlayers) && nodeptr && (nodeptr->nodesav != NULL)) return NULL; // But cannot route over terminals! // Position does not contain the net number, so we have to // go looking for it. Fortunately this is a fairly rare // occurrance. But it is necessary to find all neighboring // nets that might have created the blockage, and refuse to // route here if any of them are on the noripup list. if (needblock[newpt.lay] & (ROUTEBLOCKX | VIABLOCKX)) { if (newpt.x < NumChannelsX - 1) { netnum = OBSVAL(newpt.x + 1, newpt.y, newpt.lay) & ROUTED_NET_MASK; if (!(netnum & NO_NET)) { netnum &= NETNUM_MASK; if ((netnum != 0) && (netnum != CurNet->netnum)) // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) if (nl->net->netnum == netnum) return NULL; } } if (newpt.x > 0) { netnum = OBSVAL(newpt.x - 1, newpt.y, newpt.lay) & ROUTED_NET_MASK; if (!(netnum & NO_NET)) { netnum &= NETNUM_MASK; if ((netnum != 0) && (netnum != CurNet->netnum)) // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) if (nl->net->netnum == netnum) return NULL; } } } if (needblock[newpt.lay] & (ROUTEBLOCKY | VIABLOCKY)) { if (newpt.y < NumChannelsY - 1) { netnum = OBSVAL(newpt.x, newpt.y + 1, newpt.lay) & ROUTED_NET_MASK; if (!(netnum & NO_NET)) { netnum &= NETNUM_MASK; if ((netnum != 0) && (netnum != CurNet->netnum)) // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) if (nl->net->netnum == netnum) return NULL; } } if (newpt.y > 0) { netnum = OBSVAL(newpt.x, newpt.y - 1, newpt.lay) & ROUTED_NET_MASK; if (!(netnum & NO_NET)) { netnum &= NETNUM_MASK; if ((netnum != 0) && (netnum != CurNet->netnum)) // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) if (nl->net->netnum == netnum) return NULL; } } } // In case of a collision, we change the grid point to be routable // but flag it as a point of collision so we can later see what // were the net numbers of the interfering routes by cross-referencing // the Obs[][] array. Pr->flags |= (PR_CONFLICT | PR_COST); Pr->prdata.cost = MAXRT; thiscost += ConflictCost; } else return NULL; // Position is not routeable } // Compute the cost to step from the current point to the new point. // "BlockCost" is used if the node has only one point to connect to, // so that routing over it could block it entirely. if ((newpt.lay > 0) && (newpt.lay < Pinlayers)) { if (((lnode = NODEIPTR(newpt.x, newpt.y, newpt.lay - 1)) != (NODEINFO)NULL) && ((node = lnode->nodeloc) != NULL)) { Pt = &OBS2VAL(newpt.x, newpt.y, newpt.lay - 1); if (!(Pt->flags & PR_TARGET) && !(Pt->flags & PR_SOURCE)) { if (node->taps && (node->taps->next == NULL)) thiscost += BlockCost; // Cost to block out a tap else if (node->taps == NULL) { if (node->extend != NULL) { if (node->extend->next == NULL) // Node has only one extended access point: Try // very hard to avoid routing over it thiscost += 10 * BlockCost; else thiscost += BlockCost; } // If both node->taps and node->extend are NULL, then // the node has no access and will never be routed, so // don't bother costing it. } else thiscost += XverCost; // Cross-under cost } } } if (((newpt.lay + 1) < Pinlayers) && (newpt.lay < Num_layers - 1)) { if (((lnode = NODEIPTR(newpt.x, newpt.y, newpt.lay + 1)) != (NODEINFO)NULL) && ((node = lnode->nodeloc) != NULL)) { Pt = &OBS2VAL(newpt.x, newpt.y, newpt.lay + 1); if (!(Pt->flags & PR_TARGET) && !(Pt->flags & PR_SOURCE)) { if (node->taps && (node->taps->next == NULL)) thiscost += BlockCost; // Cost to block out a tap else thiscost += XverCost; // Cross-over cost } } } if (ept->lay != newpt.lay) thiscost += ViaCost; if (Vert[newpt.lay]) thiscost += (ept->x == newpt.x) ? SegCost : JogCost; else thiscost += (ept->y == newpt.y) ? SegCost : JogCost; // Add the cost to the cost of the original position thiscost += ept->cost; // Routes that reach nodes are given a cost based on the "quality" // of the node location: higher cost given to stub routes and // offset positions. if (nodeptr != NULL) { thiscost += (int)(fabsf(nodeptr->stub) * (float)OffsetCost); } // Replace node information if cost is minimum if (Pr->flags & PR_CONFLICT) thiscost += ConflictCost; // For 2nd stage routes if (thiscost < Pr->prdata.cost) { Pr->flags &= ~PR_PRED_DMASK; Pr->flags |= flags; Pr->prdata.cost = thiscost; Pr->flags &= ~PR_PROCESSED; // Need to reprocess this node if (Verbose > 3) { Fprintf(stdout, "New cost %d at (%d %d %d)\n", thiscost, newpt.x, newpt.y, newpt.lay); } if (~(Pr->flags & PR_ON_STACK)) { Pr->flags |= PR_ON_STACK; ptret = allocPOINT(); ptret->x1 = newpt.x; ptret->y1 = newpt.y; ptret->layer = newpt.lay; ptret->next = NULL; return ptret; } } return NULL; // New position did not get a lower cost } /* eval_pt() */ /*------------------------------------------------------*/ /* writeback_segment() --- */ /* */ /* Copy information from a single segment back */ /* the Obs[] array. */ /* */ /* NOTE: "needblock" is used to handle */ /* cases where the existence of a route prohibits any */ /* routing on adjacent tracks on the same plane due to */ /* DRC restrictions (i.e., metal is too wide for single */ /* track spacing). Be sure to check the value of */ /* adjacent positions in Obs against the mask */ /* NETNUM_MASK, because NETNUM_MASK includes NO_NET. */ /* By replacing only empty and routable positions with */ /* the unique flag combination DRC_BLOCKAGE, it */ /* is possible to detect and remove the same if that */ /* net is ripped up, without touching any position */ /* originally marked NO_NET. */ /* */ /* Another NOTE: Tap offsets can cause the position */ /* in front of the offset to be unroutable. So if the */ /* segment is on a tap offset, mark the position in */ /* front as unroutable. If the segment neighbors an */ /* offset tap, then mark the tap unroutable. */ /*------------------------------------------------------*/ void writeback_segment(SEG seg, int netnum) { double dist; int i, layer, dir; u_int sobs; NODEINFO lnode; if (seg->segtype & ST_VIA) { /* Preserve blocking information */ dir = OBSVAL(seg->x1, seg->y1, seg->layer + 1) & (BLOCKED_MASK | PINOBSTRUCTMASK); OBSVAL(seg->x1, seg->y1, seg->layer + 1) = netnum | dir; if (needblock[seg->layer + 1] & VIABLOCKX) { if (seg->x1 < (NumChannelsX - 1)) set_drc_blockage(seg->x1 + 1, seg->y1, seg->layer + 1); if (seg->x1 > 0) set_drc_blockage(seg->x1 - 1, seg->y1, seg->layer + 1); } if (needblock[seg->layer + 1] & VIABLOCKY) { if (seg->y1 < (NumChannelsY - 1)) set_drc_blockage(seg->x1, seg->y1 + 1, seg->layer + 1); if (seg->y1 > 0) set_drc_blockage(seg->x1, seg->y1 - 1, seg->layer + 1); } // If position itself is an offset route, then make the route position // on the forward side of the offset unroutable, on both via layers. // (Like the above code, there is no check for whether the offset // distance is enough to cause a DRC violation.) layer = (seg->layer == 0) ? 0 : seg->layer - 1; sobs = OBSVAL(seg->x1, seg->y1, seg->layer); if (sobs & OFFSET_TAP) { lnode = NODEIPTR(seg->x1, seg->y1, seg->layer); dist = lnode->offset; if (lnode->flags & NI_OFFSET_EW) { if ((dist > 0) && (seg->x1 < (NumChannelsX - 1))) { set_drc_blockage(seg->x1 + 1, seg->y1, seg->layer); set_drc_blockage(seg->x1 + 1, seg->y1, seg->layer + 1); } if ((dist < 0) && (seg->x1 > 0)) { set_drc_blockage(seg->x1 - 1, seg->y1, seg->layer); set_drc_blockage(seg->x1 - 1, seg->y1, seg->layer + 1); } } else if (lnode->flags & NI_OFFSET_NS) { if ((dist > 0) && (seg->y1 < (NumChannelsY - 1))) { set_drc_blockage(seg->x1, seg->y1 + 1, seg->layer); set_drc_blockage(seg->x1, seg->y1 + 1, seg->layer + 1); } if ((dist < 0) && (seg->y1 > 0)) { set_drc_blockage(seg->x1, seg->y1 - 1, seg->layer); set_drc_blockage(seg->x1, seg->y1 - 1, seg->layer + 1); } } } } for (i = seg->x1; ; i += (seg->x2 > seg->x1) ? 1 : -1) { dir = OBSVAL(i, seg->y1, seg->layer) & (BLOCKED_MASK | PINOBSTRUCTMASK); OBSVAL(i, seg->y1, seg->layer) = netnum | dir; if (needblock[seg->layer] & ROUTEBLOCKY) { if (seg->y1 < (NumChannelsY - 1)) set_drc_blockage(i, seg->y1 + 1, seg->layer); if (seg->y1 > 0) set_drc_blockage(i, seg->y1 - 1, seg->layer); } // Check position on each side for an offset tap on a different net, and // mark the position unroutable. // // NOTE: This is a bit conservative, as it will block positions next to // an offset tap without checking if the offset distance is enough to // cause a DRC error. Could be refined. . . layer = (seg->layer == 0) ? 0 : seg->layer - 1; if (seg->y1 < (NumChannelsY - 1)) { sobs = OBSVAL(i, seg->y1 + 1, layer); if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) { lnode = NODEIPTR(i, seg->y1 + 1, layer); if (lnode->flags & NI_OFFSET_NS) { dist = lnode->offset; if (dist < 0) { set_drc_blockage(i, seg->y1 + 1, layer); } } } } if (seg->y1 > 0) { sobs = OBSVAL(i, seg->y1 - 1, layer); if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) { lnode = NODEIPTR(i, seg->y1 - 1, layer); if (lnode->flags & NI_OFFSET_NS) { dist = lnode->offset; if (dist > 0) { set_drc_blockage(i, seg->y1 - 1, layer); } } } } if (i == seg->x2) break; } /* Check top of route for vertical routes */ if (seg->y1 != seg->y2) { dir = OBSVAL(seg->x2, seg->y2, seg->layer) & (BLOCKED_MASK | PINOBSTRUCTMASK); OBSVAL(seg->x2, seg->y2, seg->layer) = netnum | dir; if (needblock[seg->layer] & ROUTEBLOCKY) { if (seg->y2 < (NumChannelsY - 1)) set_drc_blockage(seg->x2, seg->y2 + 1, seg->layer); if (seg->y2 > 0) set_drc_blockage(seg->x2, seg->y2 - 1, seg->layer); } } for (i = seg->y1; ; i += (seg->y2 > seg->y1) ? 1 : -1) { dir = OBSVAL(seg->x1, i, seg->layer) & (BLOCKED_MASK | PINOBSTRUCTMASK); OBSVAL(seg->x1, i, seg->layer) = netnum | dir; if (needblock[seg->layer] & ROUTEBLOCKX) { if (seg->x1 < (NumChannelsX - 1)) set_drc_blockage(seg->x1 + 1, i, seg->layer); if (seg->x1 > 0) set_drc_blockage(seg->x1 - 1, i, seg->layer); } // Check position on each side for an offset tap on a different net, and // mark the position unroutable (see above). layer = (seg->layer == 0) ? 0 : seg->layer - 1; if (seg->x1 < (NumChannelsX - 1)) { sobs = OBSVAL(seg->x1 + 1, i, layer); if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) { lnode = NODEIPTR(seg->x1 + 1, i, layer); if (lnode->flags & NI_OFFSET_EW) { dist = lnode->offset; if (dist < 0) { set_drc_blockage(seg->x1 + 1, i, layer); } } } } if (seg->x1 > 0) { sobs = OBSVAL(seg->x1 - 1, i, layer); if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) { lnode = NODEIPTR(seg->x1 - 1, i, layer); if (lnode->flags & NI_OFFSET_EW) { dist = lnode->offset; if (dist > 0) { set_drc_blockage(seg->x1 - 1, i, layer); } } } } if (i == seg->y2) break; } /* Check end of route for horizontal routes */ if (seg->x1 != seg->x2) { dir = OBSVAL(seg->x2, seg->y2, seg->layer) & (BLOCKED_MASK | PINOBSTRUCTMASK); OBSVAL(seg->x2, seg->y2, seg->layer) = netnum | dir; if (needblock[seg->layer] & ROUTEBLOCKX) { if (seg->x2 < (NumChannelsX - 1)) set_drc_blockage(seg->x2 + 1, seg->y2, seg->layer); if (seg->x2 > 0) set_drc_blockage(seg->x2 - 1, seg->y2, seg->layer); } } } /*--------------------------------------------------------------*/ /* Set the endpoint information for the route. Look at the */ /* first and last points of the route, determine if they */ /* connect to a node or another route, and set the "start" and */ /* "end" records of the route, and the flags accordingly. */ /*--------------------------------------------------------------*/ void route_set_connections(net, route) NET net; ROUTE route; { SEG seg, s; ROUTE nr; NODEINFO lnode; u_char found, match; int x, y; /* Reset start/end node flags */ route->flags &= ~(RT_START_NODE | RT_END_NODE); /* Does first route segment connect to a node? */ seg = route->segments; found = FALSE; if (seg->layer < Pinlayers) { lnode = NODEIPTR(seg->x1, seg->y1, seg->layer); if ((lnode != NULL) && (lnode->nodesav != NULL)) { route->start.node = lnode->nodesav; route->flags |= RT_START_NODE; found = TRUE; } } /* For routes that were just imported from DEF, check if the */ /* route overshot a pin terminal by rounding off a non-grid */ /* coordinate. */ if (!found && (route->flags & RT_CHECK) && (seg->layer < Pinlayers)) { if (seg->x1 == seg->x2) { x = seg->x1; if (seg->y1 < seg->y2) y = seg->y1 + 1; else y = seg->y1 - 1; } else { y = seg->y1; if (seg->x1 < seg->x2) x = seg->x1 + 1; else x = seg->x1 - 1; } lnode = NODEIPTR(x, y, seg->layer); if ((lnode != NULL) && (lnode->nodesav != NULL) && (lnode->nodesav->netnum == net->netnum) && ((x != seg->x2) || (y != seg->y2))) { route->start.node = lnode->nodesav; route->flags |= RT_START_NODE; found = TRUE; /* Diagnostic */ Fprintf(stderr, "Coordinate %d %d corrected to %d %d\n", seg->x1, seg->y1, x, y); seg->x1 = x; seg->y1 = y; } } /* Does first route segment connect to a route? */ if (!found) { for (nr = net->routes; nr; nr = nr->next) { if (nr == route) continue; for (s = nr->segments; s; s = s->next) { match = FALSE; if (seg->layer == s->layer) match = TRUE; else if ((seg->segtype & ST_VIA) && ((seg->layer + 1) == s->layer)) match = TRUE; else if ((s->segtype & ST_VIA) && ((s->layer + 1) == seg->layer)) match = TRUE; if (!match) continue; x = s->x1; y = s->y1; if (x == seg->x1 && y == seg->y1) { found = TRUE; route->start.route = nr; break; } while (TRUE) { if (s->x2 != s->x1) x += ((s->x2 > s->x1) ? 1 : -1); if (s->y2 != s->y1) y += ((s->y2 > s->y1) ? 1 : -1); if (x == seg->x1 && y == seg->y1) { found = TRUE; route->start.route = nr; break; } if (x == s->x2 && y == s->y2) break; } if (found) break; } if (found) break; } } if (!found) { Fprintf(stderr, "Error: Failure to find route start node/route on net %s!\n", net->netname); } /* Does last route segment connect to a node? */ /* NOTE: Avoid the case where the route is exactly one via connecting */ /* a node to a route directly above, in which case the following code */ /* would flag the node twice, incorrectly. */ found = FALSE; if ((seg->next != NULL) || !(seg->segtype & ST_VIA)) { for (; seg->next; seg = seg->next); if (seg->layer < Pinlayers) { lnode = NODEIPTR(seg->x2, seg->y2, seg->layer); if ((lnode != NULL) && (lnode->nodesav != NULL)) { route->end.node = lnode->nodesav; route->flags |= RT_END_NODE; found = TRUE; } } /* For routes that were just imported from DEF, check if */ /* the route overshot a pin terminal by rounding off a */ /* non-grid coordinate. */ if (!found && (route->flags & RT_CHECK) && (seg->layer < Pinlayers)) { if (seg->x1 == seg->x2) { x = seg->x2; if (seg->y1 < seg->y2) y = seg->y2 - 1; else y = seg->y2 + 1; } else { y = seg->y2; if (seg->x1 < seg->x2) x = seg->x2 - 1; else x = seg->x2 + 1; } lnode = NODEIPTR(x, y, seg->layer); if ((lnode != NULL) && (lnode->nodesav != NULL) && (lnode->nodesav->netnum == net->netnum) && ((x != seg->x1) || (y != seg->y1))) { route->start.node = lnode->nodesav; route->flags |= RT_END_NODE; found = TRUE; /* Diagnostic */ Fprintf(stderr, "Coordinate %d %d corrected to %d %d\n", seg->x2, seg->y2, x, y); seg->x2 = x; seg->y2 = y; } } } /* Does last route segment connect to a route? */ if (!found) { for (nr = net->routes; nr; nr = nr->next) { if (nr == route) continue; for (s = nr->segments; s; s = s->next) { match = FALSE; if (seg->layer == s->layer) match = TRUE; else if ((seg->segtype & ST_VIA) && ((seg->layer + 1) == s->layer)) match = TRUE; else if ((s->segtype & ST_VIA) && ((s->layer + 1) == seg->layer)) match = TRUE; if (!match) continue; x = s->x1; y = s->y1; if (x == seg->x2 && y == seg->y2 && nr != route->start.route) { found = TRUE; route->end.route = nr; break; } while (TRUE) { if (s->x2 != s->x1) x += ((s->x2 > s->x1) ? 1 : -1); if (s->y2 != s->y1) y += ((s->y2 > s->y1) ? 1 : -1); if (x == seg->x2 && y == seg->y2 && nr != route->start.route) { found = TRUE; route->end.route = nr; break; } if (x == s->x2 && y == s->y2) break; } if (found) break; } if (found) break; } } if (!found) { Fprintf(stderr, "Error: Failure to find route end node/route on net %s!\n", net->netname); } /* Clear RT_CHECK flag after processing */ if (route->flags & RT_CHECK) route->flags &= ~RT_CHECK; } /*--------------------------------------------------------------*/ /* commit_proute - turn the potential route into an actual */ /* route by generating the route segments */ /* */ /* ARGS: route structure to fill; "stage" is 1 if we're on */ /* second stage routing, in which case we fill the */ /* route structure but don't modify the Obs array. */ /* */ /* RETURNS: 1 on success, 0 on stacked via failure, and */ /* -1 on failure to find a terminal. On a stacked */ /* via failure, the route is committed anyway. */ /* */ /* SIDE EFFECTS: Obs update, RT llseg added */ /*--------------------------------------------------------------*/ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage) { SEG seg, lseg; NODEINFO lnode1, lnode2; int lay2, rval; int dx = -1, dy = -1, dl; u_int netnum, netobs1, netobs2, dir1, dir2; u_char first = (u_char)1; u_char dmask; u_char pflags, p2flags; PROUTE *Pr; POINT newlr, newlr2, lrtop, lrend, lrnext, lrcur, lrprev; if (Verbose > 1) { Flush(stdout); Fprintf(stdout, "\nCommit: TotalRoutes = %d\n", TotalRoutes); } netnum = rt->netnum; Pr = &OBS2VAL(ept->x, ept->y, ept->lay); if (!(Pr->flags & PR_COST)) { Fprintf(stderr, "commit_proute(): impossible - terminal is not routable!\n"); return -1; } // Generate an indexed route, recording the series of predecessors and their // positions. lrtop = (POINT)malloc(sizeof(struct point_)); lrtop->x1 = ept->x; lrtop->y1 = ept->y; lrtop->layer = ept->lay; lrtop->next = NULL; lrend = lrtop; while (1) { Pr = &OBS2VAL(lrend->x1, lrend->y1, lrend->layer); dmask = Pr->flags & PR_PRED_DMASK; if (dmask == PR_PRED_NONE) break; newlr = (POINT)malloc(sizeof(struct point_)); newlr->x1 = lrend->x1; newlr->y1 = lrend->y1; newlr->layer = lrend->layer; lrend->next = newlr; newlr->next = NULL; switch (dmask) { case PR_PRED_N: (newlr->y1)++; break; case PR_PRED_S: (newlr->y1)--; break; case PR_PRED_E: (newlr->x1)++; break; case PR_PRED_W: (newlr->x1)--; break; case PR_PRED_U: (newlr->layer)++; break; case PR_PRED_D: (newlr->layer)--; break; } lrend = newlr; } lrend = lrtop; // TEST: Walk through the solution, and look for stacked vias. When // found, look for an alternative path that avoids the stack. rval = 1; if (StackedContacts < (Num_layers - 1)) { POINT lrppre; POINT a, b; PROUTE *pri, *pri2; int stacks = 1, stackheight; int cx, cy, cl; int mincost, minx = -1, miny = -1, collide, cost; while (stacks != 0) { // Keep doing until all illegal stacks are gone stacks = 0; lrcur = lrend; lrprev = lrend->next; while (lrprev != NULL) { lrppre = lrprev->next; if (lrppre == NULL) break; stackheight = 0; /* Advance lrcur if jogs were inserted */ while (lrprev != lrcur->next) lrcur = lrcur->next; a = lrcur; b = lrprev; while (a->layer != b->layer) { stackheight++; a = b; b = a->next; if (b == NULL) break; } collide = FALSE; while (stackheight > StackedContacts) { // Illegal stack found stacks++; // Try to move the second contact in the path cx = lrprev->x1; cy = lrprev->y1; cl = lrprev->layer; mincost = MAXRT; dl = lrppre->layer; // Check all four positions around the contact for the // lowest cost, and make sure the position below that // is available. if (cx < NumChannelsX - 1) { dx = cx + 1; // Check to the right pri = &OBS2VAL(dx, cy, cl); pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { pri2 = &OBS2VAL(dx, cy, dl); p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = cost; minx = dx; miny = cy; } } else if (collide && !(p2flags & (PR_COST | PR_SOURCE)) && (pri2->prdata.net < MAXNETNUM) && ((cost + ConflictCost) < mincost)) { mincost = cost + ConflictCost; minx = dx; miny = dy; } } } } if (cx > 0) { dx = cx - 1; // Check to the left pri = &OBS2VAL(dx, cy, cl); pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { pri2 = &OBS2VAL(dx, cy, dl); p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = cost; minx = dx; miny = cy; } } else if (collide && !(p2flags & (PR_COST | PR_SOURCE)) && (pri2->prdata.net < MAXNETNUM) && ((cost + ConflictCost) < mincost)) { mincost = cost + ConflictCost; minx = dx; miny = dy; } } } } if (cy < NumChannelsY - 1) { dy = cy + 1; // Check north pri = &OBS2VAL(cx, dy, cl); pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { pri2 = &OBS2VAL(cx, dy, dl); p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = cost; minx = cx; miny = dy; } } else if (collide && !(p2flags & (PR_COST | PR_SOURCE)) && (pri2->prdata.net < MAXNETNUM) && ((cost + ConflictCost) < mincost)) { mincost = cost + ConflictCost; minx = dx; miny = dy; } } } } if (cy > 0) { dy = cy - 1; // Check south pri = &OBS2VAL(cx, dy, cl); pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { pri2 = &OBS2VAL(cx, dy, dl); p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = cost; minx = cx; miny = dy; } } else if (collide && !(p2flags & (PR_COST | PR_SOURCE)) && (pri2->prdata.net < MAXNETNUM) && ((cost + ConflictCost) < mincost)) { mincost = cost + ConflictCost; minx = dx; miny = dy; } } } } // Was there an available route? If so, modify // records to route through this alternate path. If not, // then try to move the first contact instead. if (mincost < MAXRT) { pri = &OBS2VAL(minx, miny, cl); newlr = (POINT)malloc(sizeof(struct point_)); newlr->x1 = minx; newlr->y1 = miny; newlr->layer = cl; pri2 = &OBS2VAL(minx, miny, dl); newlr2 = (POINT)malloc(sizeof(struct point_)); newlr2->x1 = minx; newlr2->y1 = miny; newlr2->layer = dl; lrprev->next = newlr; newlr->next = newlr2; // Check if point at pri2 is equal to position of // lrppre->next. If so, bypass lrppre. if ((lrnext = lrppre->next) != NULL) { if (lrnext->x1 == minx && lrnext->y1 == miny && lrnext->layer == dl) { newlr->next = lrnext; free(lrppre); free(newlr2); lrppre = lrnext; // ? } else newlr2->next = lrppre; } else newlr2->next = lrppre; break; // Found a solution; we're done. } else { // If we couldn't offset lrprev position, then try // offsetting lrcur. cx = lrcur->x1; cy = lrcur->y1; cl = lrcur->layer; mincost = MAXRT; dl = lrprev->layer; if (cx < NumChannelsX - 1) { dx = cx + 1; // Check to the right pri = &OBS2VAL(dx, cy, cl); pflags = pri->flags; if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && pri->prdata.cost < mincost) { pri2 = &OBS2VAL(dx, cy, dl); p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = pri->prdata.cost; minx = dx; miny = cy; } } } } } if (cx > 0) { dx = cx - 1; // Check to the left pri = &OBS2VAL(dx, cy, cl); pflags = pri->flags; if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && pri->prdata.cost < mincost) { pri2 = &OBS2VAL(dx, cy, dl); p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = pri->prdata.cost; minx = dx; miny = cy; } } } } } if (cy < NumChannelsY - 1) { dy = cy + 1; // Check north pri = &OBS2VAL(cx, dy, cl); pflags = pri->flags; if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && pri->prdata.cost < mincost) { pri2 = &OBS2VAL(cx, dy, dl); p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = pri->prdata.cost; minx = cx; miny = dy; } } } } } if (cy > 0) { dy = cy - 1; // Check south pri = &OBS2VAL(cx, dy, cl); pflags = pri->flags; if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && pri->prdata.cost < mincost) { pri2 = &OBS2VAL(cx, dy, dl); p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = pri->prdata.cost; minx = cx; miny = dy; } } } } } if (mincost < MAXRT) { newlr = (POINT)malloc(sizeof(struct point_)); newlr->x1 = minx; newlr->y1 = miny; newlr->layer = cl; newlr2 = (POINT)malloc(sizeof(struct point_)); newlr2->x1 = minx; newlr2->y1 = miny; newlr2->layer = dl; // If newlr is a source or target, then make it // the endpoint, because we have just moved the // endpoint along the source or target, and the // original endpoint position is not needed. pri = &OBS2VAL(minx, miny, cl); pri2 = &OBS2VAL(lrcur->x1, lrcur->y1, lrcur->layer); if ((((pri->flags & PR_SOURCE) && (pri2->flags & PR_SOURCE)) || ((pri->flags & PR_TARGET) && (pri2->flags & PR_TARGET))) && (lrcur == lrtop) ) { lrtop = newlr; lrend = newlr; free(lrcur); lrcur = newlr; } else lrcur->next = newlr; newlr->next = newlr2; // Check if point at pri2 is equal to position of // lrprev->next. If so, bypass lrprev. if (lrppre->x1 == minx && lrppre->y1 == miny && lrppre->layer == dl) { newlr->next = lrppre; free(lrprev); free(newlr2); lrprev = lrcur; } else newlr2->next = lrprev; break; // Found a solution; we're done. } else if (stage == 0) { // On the first stage, we call it an error and move // on to the next net. This is a bit conservative, // but it works because failing to remove a stacked // via is a rare occurrance. if (Verbose > 0) Fprintf(stderr, "Failed to remove stacked via " "at grid point %d %d.\n", lrcur->x1, lrcur->y1); stacks = 0; rval = 0; goto cleanup; } else { if (collide == TRUE) { Fprintf(stderr, "Failed to remove stacked via " "at grid point %d %d; position may " "not be routable.\n", lrcur->x1, lrcur->y1); stacks = 0; rval = 0; goto cleanup; } // On the second stage, we will run through the // search again, but allow overwriting other // nets, which will be treated like other colliding // nets in the regular route path search. collide = TRUE; } } } lrcur = lrprev; lrprev = lrppre; } } } /* Handle minimum metal area rule for stacked contacts */ else if (StackedContacts > 0) { /* Search for all stacked contacts. For each via position inside */ /* a stack, excluding top and bottom, determine if a minimum */ /* metal area is violated. If so, then find an unused */ /* neighboring grid and extend to that side. If no unused */ /* neighboring grids exist, then fail. */ POINT lrppre; PROUTE *pri, *pri2; int violations = 1, checks; int i, cx, cy, cl, o, orient; int mincost, minx = -1, miny = -1, collide, cost; double min_area[MAX_LAYERS]; u_char need_check[MAX_LAYERS]; /* Register the minimum metal area rule for each via base layer */ checks = 0; for (i = 0; i < Num_layers; i++) { min_area[i] = LefGetRouteMinArea(i); if (i == Num_layers - 1) { if (min_area[i] <= LefGetViaWidth(i - 1, i, 0) * LefGetViaWidth(i - 1, i, 1)) need_check[i] = (u_char)0; else { need_check[i] = (u_char)1; checks++; } } else { if (min_area[i] <= LefGetViaWidth(i, i, 0) * LefGetViaWidth(i, i, 1)) need_check[i] = (u_char)0; else { need_check[i] = (u_char)1; checks++; } } } if (checks == 0) violations = 0; // No minimum area violations possible. while (violations != 0) { // Keep doing until all min. area violations are gone violations = 0; lrcur = lrend; lrprev = lrend->next; while (lrprev != NULL) { lrppre = lrprev->next; if (lrppre == NULL) break; collide = FALSE; while ((lrcur->layer != lrprev->layer) && (lrprev->layer != lrppre->layer) && (need_check[lrprev->layer] == (u_char)1)) { // Isolated via inside stack found violations++; cx = lrprev->x1; cy = lrprev->y1; cl = lrprev->layer; mincost = MAXRT; // Check all four positions around the contact for a // free position to occupy. Positions in the preferred // direction of the route layer take precedence. o = LefGetRouteOrientation(cl); for (orient = 0; orient < 2; orient++) { if (o == orient) { if (cy < NumChannelsY - 1) { dy = cy + 1; // Check north pri = &OBS2VAL(cx, dy, cl); pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { mincost = cost; minx = cx; miny = dy; } } } if (cy > 0) { dy = cy - 1; // Check south pri = &OBS2VAL(cx, dy, cl); pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { mincost = cost; minx = cx; miny = dy; } } } } else { if (cx < NumChannelsX - 1) { dx = cx + 1; // Check to the right pri = &OBS2VAL(dx, cy, cl); pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { mincost = cost; minx = dx; miny = cy; } } } if (cx > 0) { dx = cx - 1; // Check to the left pri = &OBS2VAL(dx, cy, cl); pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { mincost = cost; minx = dx; miny = cy; } } } } } // Was there an available position? If so, modify // records to route to and from this position. if (mincost < MAXRT) { newlr = (POINT)malloc(sizeof(struct point_)); newlr->x1 = minx; newlr->y1 = miny; newlr->layer = cl; newlr2 = (POINT)malloc(sizeof(struct point_)); newlr2->x1 = cx; newlr2->y1 = cy; newlr2->layer = cl; lrprev->next = newlr; newlr->next = newlr2; newlr2->next = lrppre; break; /* Found a solution; done. */ } else if (stage == 0) { // On the first stage, we call it an error and move // on to the next net. This is a bit conservative, // but it happens rarely. if (Verbose > 0) Fprintf(stderr, "Failed to reserve sufficient area " "at grid point %d %d.\n", lrcur->x1, lrcur->y1); violations = 0; rval = 0; goto cleanup; } else { if (collide == TRUE) { Fprintf(stderr, "Failed to reserve sufficient area " "at grid point %d %d; position may " "not be routable.\n", lrcur->x1, lrcur->y1); violations = 0; rval = 0; goto cleanup; } // On the second stage, we will run through the // search again, but allow overwriting other // nets, which will be treated like other colliding // nets in the regular route path search. collide = TRUE; } } lrcur = lrprev; lrprev = lrppre; } } } /* Done handling stacked contacts */ lrend = lrtop; lrcur = lrtop; lrprev = lrcur->next; lseg = (SEG)NULL; while (1) { seg = (SEG)malloc(sizeof(struct seg_)); seg->next = NULL; seg->segtype = (lrcur->layer == lrprev->layer) ? ST_WIRE : ST_VIA; seg->x1 = lrcur->x1; seg->y1 = lrcur->y1; seg->layer = MIN(lrcur->layer, lrprev->layer); seg->x2 = lrprev->x1; seg->y2 = lrprev->y1; dx = seg->x2 - seg->x1; dy = seg->y2 - seg->y1; // segments are in order---place final segment at end of list if (rt->segments == NULL) rt->segments = seg; else lseg->next = seg; // Continue processing predecessors as long as the direction is the same, // so we get a single long wire segment. This minimizes the number of // segments produced. Vias have to be handled one at a time, as we make // no assumptions about stacked vias. if (seg->segtype & ST_WIRE) { while ((lrnext = lrprev->next) != NULL) { lrnext = lrprev->next; if (((lrnext->x1 - lrprev->x1) == dx) && ((lrnext->y1 - lrprev->y1) == dy) && (lrnext->layer == lrprev->layer)) { lrcur = lrprev; lrprev = lrnext; seg->x2 = lrprev->x1; seg->y2 = lrprev->y1; } else break; } } if (Verbose > 3) { Fprintf(stdout, "commit: index = %d, net = %d\n", Pr->prdata.net, netnum); if (seg->segtype & ST_WIRE) { Fprintf(stdout, "commit: wire layer %d, (%d,%d) to (%d,%d)\n", seg->layer, seg->x1, seg->y1, seg->x2, seg->y2); } else { Fprintf(stdout, "commit: via %d to %d\n", seg->layer, seg->layer + 1); } Flush(stdout); } // now fill in the Obs structure with this route.... lay2 = (seg->segtype & ST_VIA) ? seg->layer + 1 : seg->layer; netobs1 = OBSVAL(seg->x1, seg->y1, seg->layer); netobs2 = OBSVAL(seg->x2, seg->y2, lay2); lnode1 = (seg->layer < Pinlayers) ? NODEIPTR(seg->x1, seg->y1, seg->layer) : NULL; lnode2 = (lay2 < Pinlayers) ? NODEIPTR(seg->x2, seg->y2, lay2) : NULL; dir1 = netobs1 & PINOBSTRUCTMASK; dir2 = netobs2 & PINOBSTRUCTMASK; netobs1 &= NETNUM_MASK; netobs2 &= NETNUM_MASK; netnum |= ROUTED_NET; // Write back segment, but not on stage 2 or else the // collision information will be lost. Stage 2 uses // writeback_route to call writeback_segment after the // colliding nets have been ripped up. if (stage == (u_char)0) writeback_segment(seg, netnum); // If Obs shows this position as an obstruction, then this was a port with // no taps in reach of a grid point. This will be dealt with by moving // the via off-grid and onto the port position in emit_routes(). if (stage == (u_char)0) { if (first && dir1) { first = (u_char)0; } else if (first && dir2 && (seg->segtype & ST_VIA) && lrprev && (lrprev->layer != lay2)) { // This also applies to vias at the beginning of a route // if the path goes down instead of up (can happen on pins, // in particular) OBSVAL(seg->x1, seg->y1, lay2) |= dir2; } } // Keep stub information on obstructions that have been routed // over, so that in the rip-up stage, we can return them to obstructions. OBSVAL(seg->x1, seg->y1, seg->layer) |= dir1; OBSVAL(seg->x2, seg->y2, lay2) |= dir2; // An offset route end on the previous segment, if it is a via, needs // to carry over to this one, if it is a wire route. if (lseg && ((lseg->segtype & (ST_VIA | ST_OFFSET_END)) == (ST_VIA | ST_OFFSET_END))) if ((seg->segtype != ST_VIA) && (lnode1 != NULL)) if (((seg->x1 == seg->x2) && (lnode1->flags & NI_OFFSET_NS)) || ((seg->y1 == seg->y2) && (lnode1->flags & NI_OFFSET_EW))) seg->segtype |= ST_OFFSET_START; // Check if the route ends are offset. If so, add flags. The segment // entries are integer grid points, so offsets need to be made when // the location is output. This is only for offsets that are in the // same direction as the route, to make sure that the route reaches // the offset via, and does not extend past it. if (dir1 & OFFSET_TAP) { if (lnode1 != NULL) if (((seg->x1 == seg->x2) && (lnode1->flags & NI_OFFSET_NS)) || ((seg->y1 == seg->y2) && (lnode1->flags & NI_OFFSET_EW))) seg->segtype |= ST_OFFSET_START; // An offset on a via needs to be applied to the previous route // segment as well, if that route is a wire, and the offset is // in the same direction as the wire. if (lseg && (seg->segtype & ST_VIA) && !(lseg->segtype & ST_VIA) && (lnode2 != NULL)) if (((lseg->x1 == lseg->x2) && (lnode2->flags & NI_OFFSET_NS)) || ((lseg->y1 == lseg->y2) && (lnode2->flags & NI_OFFSET_EW))) lseg->segtype |= ST_OFFSET_END; } if (dir2 & OFFSET_TAP) seg->segtype |= ST_OFFSET_END; lrend = lrcur; // Save the last route position lrend->x1 = lrcur->x1; lrend->y1 = lrcur->y1; lrend->layer = lrcur->layer; lrcur = lrprev; // Move to the next route position lrcur->x1 = seg->x2; lrcur->y1 = seg->y2; lrprev = lrcur->next; if (lrprev == NULL) { if (dir2 && (stage == (u_char)0)) { OBSVAL(seg->x2, seg->y2, lay2) |= dir2; } else if (dir1 && (seg->segtype & ST_VIA)) { // This also applies to vias at the end of a route OBSVAL(seg->x1, seg->y1, seg->layer) |= dir1; } // Before returning, set *ept to the endpoint // position. This is for diagnostic purposes only. ept->x = lrend->x1; ept->y = lrend->y1; ept->lay = lrend->layer; // Clean up allocated memory for the route. . . while (lrtop != NULL) { lrnext = lrtop->next; free(lrtop); lrtop = lrnext; } return rval; // Success } lseg = seg; // Move to next segment position } cleanup: while (lrtop != NULL) { lrnext = lrtop->next; free(lrtop); lrtop = lrnext; } return 0; } /* commit_proute() */ /*------------------------------------------------------*/ /* writeback_route() --- */ /* */ /* This routine is the last part of the routine */ /* above. It copies the net defined by the segments */ /* in the route structure "rt" into the Obs array. */ /* This is used only for stage 2, when the writeback */ /* is not done by commit_proute because we want to */ /* rip up nets first, and also done prior to routing */ /* for any pre-defined net routes. */ /*------------------------------------------------------*/ int writeback_route(ROUTE rt) { SEG seg; int lay2; u_int netnum, dir1, dir2; u_char first = (u_char)1; netnum = rt->netnum | ROUTED_NET; for (seg = rt->segments; seg; seg = seg->next) { /* Save stub route information at segment ends. */ /* NOTE: Where segment end is a via, make sure we are */ /* placing the segment end on the right metal layer! */ lay2 = (seg->segtype & ST_VIA) ? seg->layer + 1 : seg->layer; dir1 = OBSVAL(seg->x1, seg->y1, seg->layer) & PINOBSTRUCTMASK; if (lay2 < Num_layers) dir2 = OBSVAL(seg->x2, seg->y2, lay2) & PINOBSTRUCTMASK; else dir2 = 0; writeback_segment(seg, netnum); if (first) { first = (u_char)0; if (dir1) OBSVAL(seg->x1, seg->y1, seg->layer) |= dir1; else if (dir2) OBSVAL(seg->x2, seg->y2, lay2) |= dir2; } else if (!seg->next) { if (dir1) OBSVAL(seg->x1, seg->y1, seg->layer) |= dir1; else if (dir2) OBSVAL(seg->x2, seg->y2, lay2) |= dir2; } } return TRUE; } /*------------------------------------------------------*/ /* Writeback all routes belonging to a net */ /*------------------------------------------------------*/ int writeback_all_routes(NET net) { ROUTE rt; int result = TRUE; for (rt = net->routes; rt; rt = rt->next) { if (writeback_route(rt) == FALSE) result = FALSE; } return result; } /* end of maze.c */ qrouter-1.4.88/mask.c0000644000175000017510000005735613625043307013766 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* mask.c -- qrouter general purpose autorouter */ /* Route mask generation */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June 2011, based on code by Steve */ /* Beccue, 2003 */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include #include #ifdef TCL_QROUTER #include #endif #include "qrouter.h" #include "qconfig.h" #include "point.h" #include "node.h" #include "maze.h" #include "mask.h" #include "output.h" #include "lef.h" #include "def.h" #include "graphics.h" u_char *RMask; // mask out best area to route /*--------------------------------------------------------------*/ /* Comparison routine used for qsort. Sort nets by number of */ /* nodes. */ /*--------------------------------------------------------------*/ int compNets(NET *a, NET *b) { NET p = *a; NET q = *b; // NULL nets get shoved up front if (p == NULL) return ((q == NULL) ? 0 : -1); if (q == NULL) return 1; // Sort critical nets at the front by assigned order if ((p->flags & NET_CRITICAL) || (q->flags & NET_CRITICAL)) { if (!(p->flags & NET_CRITICAL)) return 1; else if (!(q->flags & NET_CRITICAL)) return -1; else return (p->netorder < q->netorder) ? -1 : 1; } // Otherwise sort by number of nodes if (p->numnodes < q->numnodes) return 1; if (p->numnodes > q->numnodes) return -1; return 0; } /*--------------------------------------------------------------*/ /* Alternative net comparison used for qsort. Sort nets by */ /* minimum dimension of the bounding box, and if equal, by the */ /* number of nodes in the net. Bounding box dimensions are */ /* ordered smallest to largest, and number of nodes are ordered */ /* largest to smallest. */ /*--------------------------------------------------------------*/ int altCompNets(NET *a, NET *b) { NET p = *a; NET q = *b; int pwidth, qwidth, pheight, qheight, pdim, qdim; // Any NULL nets get shoved up front if (p == NULL) return ((q == NULL) ? 0 : -1); if (q == NULL) return 1; // Sort critical nets at the front by assigned order if ((p->flags & NET_CRITICAL) || (q->flags & NET_CRITICAL)) { if (!(p->flags & NET_CRITICAL)) return 1; else if (!(q->flags & NET_CRITICAL)) return -1; else return (p->netorder < q->netorder) ? -1 : 1; } // Otherwise sort as described above. pwidth = p->xmax - p->xmin; pheight = p->ymax - p->ymin; pdim = (pwidth > pheight) ? pheight : pwidth; qwidth = q->xmax - q->xmin; qheight = q->ymax - q->ymin; qdim = (qwidth > qheight) ? qheight : qwidth; if (pdim < qdim) return (-1); else if (pdim > qdim) return (1); else { if (p->numnodes < q->numnodes) return (1); if (p->numnodes > q->numnodes) return (-1); return (0); } } /*--------------------------------------------------------------*/ /* create_netorder --- assign indexes to net->netorder */ /* Re-sort Nlnets according to net order. Since Nlnets is a */ /* global variable, nothing is returned from this routine. */ /* */ /* method = 0 */ /* Nets are ordered simply from those with the most nodes */ /* to those with the fewest. However, any nets marked */ /* critical in the configuration or critical net files */ /* will be given precedence. */ /* */ /* method = 1 */ /* Nets are ordered by minimum bounding box dimension. */ /* This is based on the principle that small or narrow */ /* nets have little room to be moved around without */ /* greatly increasing the net length. If these are put */ /* down first, then remaining nets can route around them. */ /*--------------------------------------------------------------*/ void create_netorder(u_char method) { int i, j; NET net; STRING cn; i = 1; for (cn = CriticalNet; cn; cn = cn->next) { if (Verbose > 1) Fprintf(stdout, "critical net %s\n", cn->name); net = DefFindNet(cn->name); if (net) { net->netorder = i++; net->flags |= NET_CRITICAL; } } switch (method) { case 0: qsort((char *)Nlnets, Numnets, (int)sizeof(NET), (__compar_fn_t)compNets); break; case 1: qsort((char *)Nlnets, Numnets, (int)sizeof(NET), (__compar_fn_t)altCompNets); break; } for (i = 0; i < Numnets; i++) { net = Nlnets[i]; net->netorder = i++; } } /* create_netorder() */ /*--------------------------------------------------------------*/ /* Measure and record the bounding box of a net. */ /* This is preparatory to generating a mask for the net. */ /* Find the bounding box of each node, and record that */ /* information, at the same time computing the whole net's */ /* bounding box as the area bounding all of the nodes. */ /* Determine if the bounding box is more horizontal or */ /* vertical, and specify a direction for the net's trunk line. */ /* Initialize the trunk line as the midpoint between all of the */ /* nodes, extending the width (or height) of the bounding box. */ /* Initialize the node branch position as the line extending */ /* from the middle of the node's bounding box to the trunk */ /* line. These positions (trunk and branches) will be sorted */ /* and readjusted by "create_nodeorder()". */ /*--------------------------------------------------------------*/ void find_bounding_box(NET net) { NODE n1, n2; DPOINT d1tap, d2tap, dtap, mintap; int mindist, dist, dx, dy; if (net->numnodes == 2) { n1 = (NODE)net->netnodes; n2 = (NODE)net->netnodes->next; // Simple 2-pass---pick up first tap on n1, find closest tap on n2, // then find closest tap on n1. d1tap = (n1->taps == NULL) ? n1->extend : n1->taps; if (d1tap == NULL) return; d2tap = (n2->taps == NULL) ? n2->extend : n2->taps; if (d2tap == NULL) return; dx = d2tap->gridx - d1tap->gridx; dy = d2tap->gridy - d1tap->gridy; mindist = dx * dx + dy * dy; mintap = d2tap; for (d2tap = d2tap->next; d2tap != NULL; d2tap = d2tap->next) { dx = d2tap->gridx - d1tap->gridx; dy = d2tap->gridy - d1tap->gridy; dist = dx * dx + dy * dy; if (dist < mindist) { mindist = dist; mintap = d2tap; } } d2tap = mintap; d1tap = (n1->taps == NULL) ? n1->extend : n1->taps; dx = d2tap->gridx - d1tap->gridx; dy = d2tap->gridy - d1tap->gridy; mindist = dx * dx + dy * dy; mintap = d1tap; for (d1tap = d1tap->next; d1tap != NULL; d1tap = d1tap->next) { dx = d2tap->gridx - d1tap->gridx; dy = d2tap->gridy - d1tap->gridy; dist = dx * dx + dy * dy; if (dist < mindist) { mindist = dist; mintap = d1tap; } } d1tap = mintap; net->xmin = (d1tap->gridx < d2tap->gridx) ? d1tap->gridx : d2tap->gridx; net->xmax = (d1tap->gridx < d2tap->gridx) ? d2tap->gridx : d1tap->gridx; net->ymin = (d1tap->gridy < d2tap->gridy) ? d1tap->gridy : d2tap->gridy; net->ymax = (d1tap->gridy < d2tap->gridy) ? d2tap->gridy : d1tap->gridy; } else { // Net with more than 2 nodes // Use the first tap point for each node to get a rough bounding box and // centroid of all taps net->xmax = net->ymax = -(MAXRT); net->xmin = net->ymin = MAXRT; for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) { dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (dtap) { if (dtap->gridx > net->xmax) net->xmax = dtap->gridx; if (dtap->gridx < net->xmin) net->xmin = dtap->gridx; if (dtap->gridy > net->ymax) net->ymax = dtap->gridy; if (dtap->gridy < net->ymin) net->ymin = dtap->gridy; } } } } /*--------------------------------------------------------------*/ /* defineRouteTree() --- */ /* */ /* Define a trunk-and-branches potential best route for a net. */ /* */ /* The net is analyzed for aspect ratio, and is determined if */ /* it will have a horizontal or vertical trunk. Then, each */ /* node will define a branch line extending from the node */ /* position to the trunk. Trunk position is recorded in the */ /* net record, and branch positions are recorded in the node */ /* records. */ /* */ /* To do: */ /* Trunk and branch lines will be analyzed for immediate */ /* collisions and sorted to help ensure a free track exists for */ /* each net's trunk line. */ /*--------------------------------------------------------------*/ void defineRouteTree(NET net) { NODE n1; DPOINT dtap; int xcent, ycent, xmin, ymin, xmax, ymax; // This is called after create_bounding_box(), so bounds have // been calculated. xmin = net->xmin; xmax = net->xmax; ymin = net->ymin; ymax = net->ymax; if (net->numnodes == 2) { // For 2-node nets, record the initial position as // one horizontal trunk + one branch for one "L" of // the bounding box, and one vertical trunk + one // branch for the other "L" of the bounding box. net->trunkx = xmin; net->trunky = ymin; } else if (net->numnodes > 0) { // Use the first tap point for each node to get a rough // centroid of all taps xcent = ycent = 0; for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) { dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (dtap == NULL) continue; xcent += dtap->gridx; ycent += dtap->gridy; } xcent /= net->numnodes; ycent /= net->numnodes; // Record the trunk line in the net record net->trunkx = xcent; net->trunky = ycent; } if (xmax - xmin > ymax - ymin) { // Horizontal trunk preferred net->flags &= ~NET_VERTICAL_TRUNK; } else { // Vertical trunk preferred net->flags |= NET_VERTICAL_TRUNK; } // Set the branch line positions to the node tap points for (n1 = net->netnodes; n1; n1 = n1->next) { dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (!dtap) continue; n1->branchx = dtap->gridx; n1->branchy = dtap->gridy; } } /*--------------------------------------------------------------*/ /* initMask() --- */ /*--------------------------------------------------------------*/ void initMask(void) { RMask = (u_char *)calloc(NumChannelsX * NumChannelsY, sizeof(u_char)); if (!RMask) { fprintf(stderr, "Out of memory 3.\n"); exit(3); } } /*--------------------------------------------------------------*/ /* Fill mask around the area of a vertical line */ /*--------------------------------------------------------------*/ void create_vbranch_mask(int x, int y1, int y2, u_char slack, u_char halo) { int gx1, gx2, gy1, gy2; int i, j, v; u_char m; gx1 = x - slack; gx2 = x + slack; if (y1 > y2) { gy1 = y2 - slack; gy2 = y1 + slack; } else { gy1 = y1 - slack; gy2 = y2 + slack; } if (gx1 < 0) gx1 = 0; if (gx2 >= NumChannelsX) gx2 = NumChannelsX - 1; if (gy1 < 0) gy1 = 0; if (gy2 >= NumChannelsY) gy2 = NumChannelsY - 1; for (i = gx1; i <= gx2; i++) for (j = gy1; j <= gy2; j++) RMASK(i, j) = (u_char)0; for (v = 1; v < halo; v++) { if (gx1 > 0) gx1--; if (gx2 < NumChannelsX - 1) gx2++; if (y1 > y2) { if (gy1 < NumChannelsY - 1) gy1++; if (gy2 < NumChannelsY - 1) gy2++; } else { if (gy1 > 0) gy1--; if (gy2 > 0) gy2--; } for (i = gx1; i <= gx2; i++) for (j = gy1; j <= gy2; j++) { m = RMASK(i, j); if (m > v) RMASK(i, j) = (u_char)v; } } } /*--------------------------------------------------------------*/ /* Fill mask around the area of a horizontal line */ /*--------------------------------------------------------------*/ void create_hbranch_mask(int y, int x1, int x2, u_char slack, u_char halo) { int gx1, gx2, gy1, gy2; int i, j, v; u_char m; gy1 = y - slack; gy2 = y + slack; if (x1 > x2) { gx1 = x2 - slack; gx2 = x1 + slack; } else { gx1 = x1 - slack; gx2 = x2 + slack; } if (gx1 < 0) gx1 = 0; if (gx2 >= NumChannelsX) gx2 = NumChannelsX - 1; if (gy1 < 0) gy1 = 0; if (gy2 >= NumChannelsY) gy2 = NumChannelsY - 1; for (i = gx1; i <= gx2; i++) for (j = gy1; j <= gy2; j++) RMASK(i, j) = (u_char)0; for (v = 1; v < halo; v++) { if (gy1 > 0) gy1--; if (gy2 < NumChannelsY - 1) gy2++; if (x1 > x2) { if (gx1 < NumChannelsX - 1) gx1++; if (gx2 < NumChannelsX - 1) gx2++; } else { if (gx1 > 0) gx1--; if (gx2 > 0) gx2--; } for (i = gx1; i <= gx2; i++) for (j = gy1; j <= gy2; j++) { m = RMASK(i, j); if (m > v) RMASK(i, j) = (u_char)v; } } } /*--------------------------------------------------------------*/ /* setBboxCurrent() --- */ /* */ /* Alter the net's bounding box information to include the */ /* existing bounding box around all net route segments. This */ /* allows stage 3 routing to minimize the search area. */ /* */ /*--------------------------------------------------------------*/ void setBboxCurrent(NET net) { ROUTE rt; SEG seg; // If net is routed, increase the bounding box to // include the current route solution. for (rt = net->routes; rt; rt = rt->next) for (seg = rt->segments; seg; seg = seg->next) { if (seg->x1 < net->xmin) net->xmin = seg->x1; else if (seg->x1 > net->xmax) net->xmax = seg->x1; if (seg->x2 < net->xmin) net->xmin = seg->x2; else if (seg->x2 > net->xmax) net->xmax = seg->x2; if (seg->y1 < net->ymin) net->ymin = seg->y1; else if (seg->y1 > net->ymax) net->ymax = seg->y1; if (seg->y2 < net->ymin) net->ymin = seg->y2; else if (seg->y2 > net->ymax) net->ymax = seg->y2; } } /*--------------------------------------------------------------*/ /* createBboxMask() --- */ /* */ /* Create mask limiting the area to search for routing */ /* */ /* The bounding box mask generates an area including the */ /* bounding box as defined in the net record, includes all pin */ /* positions in the mask, and increases the mask area by one */ /* route track for each pass, up to "halo". */ /*--------------------------------------------------------------*/ void createBboxMask(NET net, u_char halo) { int xmin, ymin, xmax, ymax; int i, j, gx1, gy1, gx2, gy2; fillMask((u_char)halo); xmin = net->xmin; xmax = net->xmax; ymin = net->ymin; ymax = net->ymax; for (gx1 = xmin; gx1 <= xmax; gx1++) for (gy1 = ymin; gy1 <= ymax; gy1++) RMASK(gx1, gy1) = (u_char)0; for (i = 1; i <= halo; i++) { gx1 = xmin - i; if (gx1 >= 0 && gx1 < NumChannelsX) for (j = ymin - i; j <= ymax + i; j++) if (j >= 0 && j < NumChannelsY) RMASK(gx1, j) = (u_char)i; gx2 = xmax + i; if (gx2 >= 0 && gx2 < NumChannelsX) for (j = ymin - i; j <= ymax + i; j++) if (j >= 0 && j < NumChannelsY) RMASK(gx2, j) = (u_char)i; gy1 = ymin - i; if (gy1 >= 0 && gy1 < NumChannelsY) for (j = xmin - i; j <= xmax + i; j++) if (j >= 0 && j < NumChannelsX) RMASK(j, gy1) = (u_char)i; gy2 = ymax + i; if (gy2 >= 0 && gy2 < NumChannelsY) for (j = xmin - i; j <= xmax + i; j++) if (j >= 0 && j < NumChannelsX) RMASK(j, gy2) = (u_char)i; } } /*--------------------------------------------------------------*/ /* analyzeCongestion() --- */ /* */ /* Given a trunk route at ycent, between ymin and ymax, score */ /* the neighboring positions as a function of congestion and */ /* offset from the ideal location. Return the position of the */ /* best location for the trunk route. */ /*--------------------------------------------------------------*/ int analyzeCongestion(int ycent, int ymin, int ymax, int xmin, int xmax) { int x, y, i, minidx = -1, sidx, n; int *score, minscore; score = (int *)malloc((ymax - ymin + 1) * sizeof(int)); for (y = ymin; y <= ymax; y++) { sidx = y - ymin; score[sidx] = ABSDIFF(ycent, y) * Num_layers; for (x = xmin; x <= xmax; x++) { for (i = 0; i < Num_layers; i++) { n = OBSVAL(x, y, i); if (n & ROUTED_NET) score[sidx]++; if (n & NO_NET) score[sidx]++; if (n & PINOBSTRUCTMASK) score[sidx]++; } } } minscore = MAXRT; for (i = 0; i < (ymax - ymin + 1); i++) { if (score[i] < minscore) { minscore = score[i]; minidx = i + ymin; } } free(score); return minidx; } /*--------------------------------------------------------------*/ /* createMask() --- */ /* */ /* Create mask limiting the area to search for routing */ /* */ /* For 2-node routes, find the two L-shaped routes between the */ /* two closest points of the nodes. */ /* For multi-node (>2) routes, find the best trunk line that */ /* passes close to all nodes, and generate stems to the closest */ /* point on each node. */ /* */ /* Optimizations: (1) multi-node routes that are in a small */ /* enough area, just mask the bounding box. (2) Where nodes */ /* at the end of two branches are closer to each other than to */ /* the trunk, mask an additional cross-connection between the */ /* two branches. */ /* */ /* Values are "halo" where there is no mask, 0 on the */ /* closest "slack" routes to the ideal (typically 1), and */ /* values increasing out to a distance of "halo" tracks away */ /* from the ideal. This allows a greater search area as the */ /* number of passes of the search algorithm increases. */ /* */ /* To do: Choose the position of trunk line based on */ /* congestion analysis. */ /*--------------------------------------------------------------*/ void createMask(NET net, u_char slack, u_char halo) { NODE n1, n2; DPOINT dtap; int i, j, orient; int dx, dy, gx1, gx2, gy1, gy2; int xcent, ycent, xmin, ymin, xmax, ymax; int oxmin, oymin, oxmax, oymax; fillMask((u_char)halo); oxmin = net->xmin; oxmax = net->xmax; oymin = net->ymin; oymax = net->ymax; xcent = net->trunkx; ycent = net->trunky; orient = 0; // Construct the trunk line mask if (!(net->flags & NET_VERTICAL_TRUNK) || (net->numnodes == 2)) { // Horizontal trunk orient |= 1; ycent = analyzeCongestion(net->trunky, oymin, oymax, oxmin, oxmax); ymin = ymax = ycent; xmin = oxmin; xmax = oxmax; // Avoid faulting if the min/max values were never set if (xmin > xmax) { xmin = 0; xmax = NumChannelsX - 1; } for (i = xmin - slack; i <= xmax + slack; i++) { if (i < 0 || i >= NumChannelsX) continue; for (j = ycent - slack; j <= ycent + slack; j++) { if (j < 0 || j >= NumChannelsY) continue; RMASK(i, j) = (u_char)0; } } for (i = 1; i < halo; i++) { gy1 = ycent - slack - i; gy2 = ycent + slack + i; for (j = xmin - slack - i; j <= xmax + slack + i; j++) { if (j < 0 || j >= NumChannelsX) continue; if (gy1 >= 0) RMASK(j, gy1) = (u_char)i; if (gy2 < NumChannelsY) RMASK(j, gy2) = (u_char)i; } gx1 = xmin - slack - i; gx2 = xmax + slack + i; for (j = ycent - slack - i; j <= ycent + slack + i; j++) { if (j < 0 || j >= NumChannelsY) continue; if (gx1 >= 0) RMASK(gx1, j) = (u_char)i; if (gx2 < NumChannelsX) RMASK(gx2, j) = (u_char)i; } } } if ((net->flags & NET_VERTICAL_TRUNK) || (net->numnodes == 2)) { // Vertical trunk orient |= 2; xmin = xmax = xcent; ymin = oymin; ymax = oymax; // Avoid faulting if the min/max values were never set if (ymin > ymax) { ymin = 0; ymax = NumChannelsY - 1; } for (i = xcent - slack; i <= xcent + slack; i++) { if (i < 0 || i >= NumChannelsX) continue; for (j = ymin - slack; j <= ymax + slack; j++) { if (j < 0 || j >= NumChannelsY) continue; RMASK(i, j) = (u_char)0; } } for (i = 1; i < halo; i++) { gx1 = xcent - slack - i; gx2 = xcent + slack + i; for (j = ymin - slack - i; j <= ymax + slack + i; j++) { if (j < 0 || j >= NumChannelsY) continue; if (gx1 >= 0) RMASK(gx1, j) = (u_char)i; if (gx2 < NumChannelsX) RMASK(gx2, j) = (u_char)i; } gy1 = ymin - slack - i; gy2 = ymax + slack + i; for (j = xcent - slack - i; j <= xcent + slack + i; j++) { if (j < 0 || j >= NumChannelsX) continue; if (gy1 >= 0) RMASK(j, gy1) = (u_char)i; if (gy2 < NumChannelsY) RMASK(j, gy2) = (u_char)i; } } } // Construct the branch line masks for (n1 = net->netnodes; n1; n1 = n1->next) { dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (!dtap) continue; if (orient & 1) // Horizontal trunk, vertical branches create_vbranch_mask(n1->branchx, n1->branchy, ycent, slack, halo); if (orient & 2) // Vertical trunk, horizontal branches create_hbranch_mask(n1->branchy, n1->branchx, xcent, slack, halo); } // Look for branches that are closer to each other than to the // trunk line. If any are found, make a cross-connection between // the branch end that is closer to the trunk and the branch that // is its nearest neighbor. if (orient & 1) { // Horizontal trunk, vertical branches for (n1 = net->netnodes; n1; n1 = n1->next) { for (n2 = net->netnodes->next; n2; n2 = n2->next) { // Check if both ends are on the same side of the trunk if ((n2->branchy > ycent && n1->branchy > ycent) || (n2->branchy < ycent && n1->branchy < ycent)) { // Check if branches are closer to each other than // the shortest branch is away from the trunk dx = ABSDIFF(n2->branchx, n1->branchx); gy1 = ABSDIFF(n1->branchy, ycent); gy2 = ABSDIFF(n2->branchy, ycent); if ((dx < gy1) && (dx < gy2)) { if (gy1 < gy2) create_hbranch_mask(n1->branchy, n2->branchx, n1->branchx, slack, halo); else create_hbranch_mask(n2->branchy, n2->branchx, n1->branchx, slack, halo); } } } } } if (orient & 2) { // Vertical trunk, horizontal branches for (n1 = net->netnodes; n1; n1 = n1->next) { for (n2 = net->netnodes->next; n2; n2 = n2->next) { // Check if both ends are on the same side of the trunk if ((n2->branchx > xcent && n1->branchx > xcent) || (n2->branchx < xcent && n1->branchx < xcent)) { // Check if branches are closer to each other than // the shortest branch is away from the trunk dy = ABSDIFF(n2->branchy, n1->branchy); gx1 = ABSDIFF(n1->branchx, xcent); gx2 = ABSDIFF(n2->branchx, xcent); if ((dy < gx1) && (dy < gx2)) { if (gx1 < gx2) create_vbranch_mask(n1->branchx, n2->branchy, n1->branchy, slack, halo); else create_vbranch_mask(n2->branchx, n2->branchy, n1->branchy, slack, halo); } } } } } // Allow routes at all tap and extension points for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) { for (dtap = n1->taps; dtap != NULL; dtap = dtap->next) RMASK(dtap->gridx, dtap->gridy) = (u_char)0; for (dtap = n1->extend; dtap != NULL; dtap = dtap->next) RMASK(dtap->gridx, dtap->gridy) = (u_char)0; } if (Verbose > 2) { if (net->numnodes == 2) Fprintf(stdout, "Two-port mask has bounding box (%d %d) to (%d %d)\n", oxmin, oymin, oxmax, oymax); else Fprintf(stdout, "multi-port mask has trunk line (%d %d) to (%d %d)\n", xmin, ymin, xmax, ymax); } } /*--------------------------------------------------------------*/ /* fillMask() fills the Mask[] array with all 1s as a last */ /* resort, ensuring that no valid routes are missed due to a */ /* bad guess about the optimal route positions. */ /*--------------------------------------------------------------*/ void fillMask(u_char value) { memset((void *)RMask, (int)value, (size_t)(NumChannelsX * NumChannelsY * sizeof(u_char))); } /* end of mask.c */ qrouter-1.4.88/antenna.c0000644000175000017510000012100013625043307014431 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* antenna.c -- Compute the metal area to gate area for all */ /* routes and determine where antenna violations occur. Then, */ /* resolve the violations by routing from each violation to an */ /* antenna tap. */ /* */ /* To be done: If there are no antenna cells placed, or if */ /* the antenna route fails, or if the antenna violation is */ /* close to the limit, see if the route can be adjusted by */ /* moving the route to a higher layer near the gate. */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, May 2018 */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include /* This entire file is dependent on the Tcl/Tk version */ #ifdef TCL_QROUTER #include #include "qrouter.h" #include "qconfig.h" #include "mask.h" #include "maze.h" #include "node.h" #include "lef.h" #include "def.h" #include "point.h" /* Node Hash Table routines taken from delay.c */ extern GATE FindGateNode(Tcl_HashTable *, NODE, int *); extern void FreeNodeTable(Tcl_HashTable *); extern int TotalRoutes; /* Structure to hold information about an antenna error. */ typedef struct antennainfo_ *ANTENNAINFO; struct antennainfo_ { ANTENNAINFO next; /* Next antenna violation in the list. */ NET net; /* The net violating an antenna rule */ NODE node; /* A gate-end node that is in violation */ ROUTE route; /* A route that is part of the antenna */ int layer; /* Uppermost metal layer of the antenna */ }; /* Keep the list as a global variable so it can be accessed */ /* from doroute() (in qrouter.c) */ ANTENNAINFO AntennaList; typedef struct annotateinfo_ *ANNOTATEINFO; struct annotateinfo_ { ANNOTATEINFO next; NET net; char *instance; char *pin; int flag; /* Flag for checking output status */ }; ANNOTATEINFO AnnotateList = NULL; #define ANNO_INIT 0 #define ANNO_OUTPUT 1 /*----------------------------------------------------------------------*/ /* Report connection of a fixed antenna violation, given the net. */ /*----------------------------------------------------------------------*/ char *get_annotate_info(NET net, char **pinptr) { ANNOTATEINFO annotate; for (annotate = AnnotateList; annotate; annotate = annotate->next) { if (annotate->net->netnum == net->netnum) { if (annotate->flag == ANNO_INIT) { annotate->flag = ANNO_OUTPUT; /* Mark as having been output */ *pinptr = annotate->pin; return annotate->instance; } } } *pinptr = NULL; return NULL; } /*--------------------------------------------------------------*/ /* Regular expression matching of the given string in */ /* "antennacell" to the string "strtest". If the regular */ /* expression matches and the result is in the first character */ /* position of the string, then return TRUE (match), otherwise */ /* return FALSE (no match). */ /*--------------------------------------------------------------*/ u_char string_match(char *antennacell, char *strtest) { regex_t regex; regmatch_t pmatch; int reti; /* Compile regular expression */ reti = regcomp(®ex, antennacell, 0); if (reti) { /* Assume this is not a regular expression and just run */ /* a straight string match. */ if (!strcasecmp(antennacell, strtest)) return TRUE; else return FALSE; } /* Execute regular expression */ reti = regexec(®ex, strtest, 1, &pmatch, 0); regfree(®ex); if (!reti) { if (pmatch.rm_so == 0) /* Must match beginning of string */ return TRUE; else return FALSE; } else return FALSE; } /*--------------------------------------------------------------*/ /* Find free antenna cells, and collect all the antenna taps */ /* into a single net, much like VDD_NET or GND_NET. */ /* */ /* Return the number of free antenna taps available in the */ /* layout. */ /* */ /* If the name of the antennacell ends in '*', then assume a */ /* wildcard character and match to any string beginning with */ /* the substring of antennacell. */ /*--------------------------------------------------------------*/ void find_free_antenna_taps(char *antennacell) { int numtaps; GATE ginst; GATE gateginfo; NODE noderec; int netnum, i; if (antennacell == NULL) { Fprintf(stderr, "No antenna cell defined!\n"); return; } numtaps = 0; for (ginst = Nlgates; ginst; ginst = ginst->next) { gateginfo = ginst->gatetype; if (string_match(antennacell, gateginfo->gatename)) { /* Find an unassigned node. If there is not one, */ /* this is probably a routed (not free) cell. */ for (i = 0; i < ginst->nodes; i++) { netnum = ginst->netnum[i]; noderec = ginst->noderec[i]; if ((netnum == 0) && (noderec == NULL)) { ginst->netnum[i] = ANTENNA_NET; ginst->noderec[i] = (NODE)calloc(1, sizeof(struct node_)); ginst->noderec[i]->netnum = ANTENNA_NET; } } } } } /*--------------------------------------------------------------*/ /* Similar to the routine above, but just count the free taps. */ /*--------------------------------------------------------------*/ int count_free_antenna_taps(char *antennacell) { int numtaps; GATE ginst; GATE gateginfo; int netnum, i; numtaps = 0; for (ginst = Nlgates; ginst; ginst = ginst->next) { gateginfo = ginst->gatetype; if (string_match(antennacell, gateginfo->gatename)) { /* Find an unassigned node. If there is not one, */ /* this is probably a routed (not free) cell. */ for (i = 0; i < ginst->nodes; i++) { netnum = ginst->netnum[i]; if (netnum == ANTENNA_NET) numtaps++; } } } return numtaps; } /*--------------------------------------------------------------*/ /* After routing, the free antenna taps are all marked with the */ /* net number of the net just routed. To make them free again, */ /* change all but the one that was routed back to ANTENNA_NET. */ /* Identify the unused taps by finding the OBSVAL record with */ /* net set to netnum but not connected to the same node. */ /*--------------------------------------------------------------*/ void revert_antenna_taps(int netnum, NODE node) { int x, y, lay; PROUTE *Pr; NODEINFO lnode = NULL; /* Clear all targets except for the one just routed */ for (lay = 0; lay < Num_layers; lay++) for (x = 0; x < NumChannelsX; x++) for (y = 0; y < NumChannelsY; y++) if ((OBSVAL(x, y, lay) & NETNUM_MASK) == netnum) { Pr = &OBS2VAL(x, y, lay); if (Pr->flags & PR_TARGET) { lnode = NODEIPTR(x, y, lay); if ((lnode == NULL) || (lnode->nodesav != node)) { OBSVAL(x, y, lay) &= ~(NETNUM_MASK | ROUTED_NET); OBSVAL(x, y, lay) |= ANTENNA_NET; } } } } /*--------------------------------------------------------------*/ /* States to track nodes as they are processed: */ /* */ /* NOT_VISITED : Node has not yet been processed. */ /* VISITED : Node was counted on this pass. */ /* PROCESSED : Node was counted on a previous pass. */ /* ANCHOR : Node is a source/drain connection. */ /*--------------------------------------------------------------*/ enum visit_states {NOT_VISITED = 0, VISITED, PROCESSED, ANCHOR}; /* Forward declarations */ float get_route_area_reverse(NET, ROUTE, int, u_char *, u_char, Tcl_HashTable *, struct routeinfo_ *); float get_route_area_forward(NET, ROUTE, int, u_char *, u_char, Tcl_HashTable *, struct routeinfo_ *); float get_route_area_reverse_fromseg(NET, ROUTE, SEG, int, u_char *, u_char, Tcl_HashTable *, struct routeinfo_ *); /*--------------------------------------------------------------*/ /* Determine the amount of metal in the route, starting at the */ /* route start point, and not moving past any point that is */ /* above "layer". Check all other unvisited routes in net to */ /* see if any connect to "rt". If so, check if they connect */ /* to a point that is part of the subnet below or at "layer". */ /* If they do, recursively run get_route_area_forward on that */ /* route. When done, return the total area of the subnet. */ /*--------------------------------------------------------------*/ float get_route_area_forward_fromseg(NET net, ROUTE rt, SEG nseg, int layer, u_char *visited, u_char method, Tcl_HashTable *NodeTable, struct routeinfo_ *iroute) { float area, length, width, thick; int x, y, l, compat; SEG seg, iseg, chkseg; ROUTE rt2; u_char found; if (rt->flags & RT_VISITED) return 0.0; rt->flags |= RT_VISITED; area = 0.0; /* If nseg is NULL then check from the beginning. */ if (nseg == NULL) nseg = rt->segments; /* Check if the route beginning is a node */ if (nseg == rt->segments) { if (rt->flags & RT_START_NODE) { NODE node; GATE g; int i; node = rt->start.node; if (visited) { /* If more than one route is connected to the node, */ /* then this node may have been visited already. */ if (visited[node->nodenum] == NOT_VISITED) { g = FindGateNode(NodeTable, node, &i); if (g->area[i] == 0.0) { /* There's a diffusion diode here! */ visited[node->nodenum] = ANCHOR; return 0.0; } else { /* Add this node to the list of nodes with gates */ /* attached to this antenna area. */ visited[node->nodenum] = VISITED; } } } else if ((method == ANTENNA_ROUTE) && (iroute != NULL)) { set_node_to_net(node, PR_SOURCE, &iroute->glist[0], &iroute->bbox, 0); } /* Walk all other routes that start or end on this node */ for (rt2 = net->routes; rt2; rt2 = rt2->next) { if (rt2->flags & RT_VISITED) continue; if ((rt2->flags & RT_START_NODE) && (rt2->start.node == node)) { /* The start point of rt2 connects to the same node */ area += get_route_area_forward(net, rt2, layer, visited, method, NodeTable, NULL); } else if ((rt2->flags & RT_END_NODE) && (rt2->end.node == node)) { /* The end point of rt2 connects to the same node */ for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next); area += get_route_area_reverse(net, rt2, layer, visited, method, NodeTable, NULL); } } } } for (seg = rt->segments; seg && (seg != nseg); seg = seg->next); if (seg == NULL) return 0.0; for (; seg; seg = seg->next) { /* Once the layer goes above the current check layer, the search stops. */ if (method != ANTENNA_DISABLE) if (seg->layer > layer) break; /* Vias don't contribute to area, at least for now. */ if (seg->segtype & ST_VIA) continue; /* For non-cumulative methods, only count area for */ /* those segments which are on the given check layer. */ if ((method == CALC_AREA) || (method == CALC_SIDEAREA)) if (seg->layer != layer) continue; /* method ANTENNA_ROUTE indicates that this routine was */ /* called as part of antenna routing. So set up this */ /* part of the route in a manner similar to the */ /* set_route_to_net() routine. */ if ((method == ANTENNA_ROUTE) && (iroute != NULL)) { PROUTE *Pr; POINT gpoint; l = seg->layer; x = seg->x1; y = seg->y1; while (1) { Pr = &OBS2VAL(x, y, l); Pr->flags = PR_SOURCE; Pr->prdata.cost = 0; if (~(Pr->flags & PR_ON_STACK)) { Pr->flags |= PR_ON_STACK; gpoint = allocPOINT(); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = l; gpoint->next = iroute->glist[0]; iroute->glist[0] = gpoint; } if (x < iroute->bbox.x1) iroute->bbox.x1 = x; if (x > iroute->bbox.x2) iroute->bbox.x2 = x; if (y < iroute->bbox.y1) iroute->bbox.y1 = y; if (y > iroute->bbox.y2) iroute->bbox.y2 = y; // Move to next grid position in the segment if (x == seg->x2 && y == seg->y2) break; if (seg->x2 > seg->x1) x++; else if (seg->x2 < seg->x1) x--; if (seg->y2 > seg->y1) y++; else if (seg->y2 < seg->y1) y--; } } else if (method == ANTENNA_DISABLE) { PROUTE *Pr; l = seg->layer; x = seg->x1; y = seg->y1; while (1) { Pr = &OBS2VAL(x, y, l); Pr->prdata.net = MAXNETNUM; Pr->flags &= ~(PR_SOURCE | PR_TARGET | PR_COST); // Move to next grid position in the segment if (x == seg->x2 && y == seg->y2) break; if (seg->x2 > seg->x1) x++; else if (seg->x2 < seg->x1) x--; if (seg->y2 > seg->y1) y++; else if (seg->y2 < seg->y1) y--; } } if ((method != ANTENNA_ROUTE) && (method != ANTENNA_DISABLE)) { /* Note that one of x or y is zero, depending on segment orientation */ x = (seg->x2 - seg->x1); y = (seg->y2 - seg->y1); if (x < 0) x = -x; if (y < 0) y = -y; /* Note that "l" is a unitless grid dimension */ if (x == 0) length = (float)y * (float)PitchY; else length = (float)x * (float)PitchX; /* area is either the total top surface of the metal, */ /* or the total side surface of the metal (in um^2) */ width = LefGetRouteWidth(seg->layer); if ((method == CALC_AREA) || (method == CALC_AGG_AREA)) area += (float)(length * width); else if ((method == CALC_SIDEAREA) || (method == CALC_AGG_SIDEAREA)) { thick = LefGetRouteThickness(seg->layer); area += thick * 2.0 * (length + width); } } } /* Check other routes for intersection with this route */ for (rt2 = net->routes; rt2; rt2 = rt2->next) { if (rt2->flags & RT_VISITED) continue; if (!(rt2->flags & RT_START_NODE) && (rt2->start.route == rt)) { /* The start point of rt2 connects somewhere on rt */ iseg = rt2->segments; x = iseg->x1; y = iseg->y1; l = iseg->layer; if (l > layer) continue; } else if (!(rt2->flags & RT_END_NODE) && (rt2->end.route == rt)) { /* The end point of rt2 connects somewhere on rt */ for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next); x = iseg->x2; y = iseg->y2; l = iseg->layer; if (l > layer) continue; } else continue; /* Must determine if rt2 intersects rt within the antenna area */ found = (u_char)0; for (chkseg = rt->segments; chkseg && chkseg != seg; chkseg = chkseg->next) { if (chkseg->segtype & ST_WIRE) { if (iseg->segtype & ST_WIRE) { compat = (l == chkseg->layer); } else { compat = (l == chkseg->layer) || (l + 1 == chkseg->layer); } } else { if (iseg->segtype & ST_WIRE) { compat = (l == chkseg->layer) || (l == chkseg->layer + 1); } else { compat = (l == chkseg->layer) || (l == chkseg->layer + 1) || (l + 1 == chkseg->layer); } } if (!compat) continue; if (chkseg->segtype & ST_VIA) { if ((chkseg->x1 == x) && (chkseg->y1 == y)) { found = (u_char)1; break; } } else if (chkseg->x1 < chkseg->x2) { if (chkseg->y1 == y) { if ((chkseg->x1 <= x) && (chkseg->x2 >= x)) { found = (u_char)1; break; } } } else if (chkseg->x1 > chkseg->x2) { if (chkseg->y1 == y) { if ((chkseg->x1 >= x) && (chkseg->x2 <= x)) { found = (u_char)1; break; } } } else if (chkseg->y1 < chkseg->y2) { if (chkseg->x1 == x) { if ((chkseg->y1 <= y) && (chkseg->y2 >= y)) { found = (u_char)1; break; } } } else if (chkseg->y1 > chkseg->y2) { if (chkseg->x1 == x) { if ((chkseg->y1 >= y) && (chkseg->y2 <= y)) { found = (u_char)1; break; } } } } if (found == (u_char)1) { if (rt2->start.route == rt) area += get_route_area_forward(net, rt2, layer, visited, method, NodeTable, iroute); else area += get_route_area_reverse(net, rt2, layer, visited, method, NodeTable, iroute); } } /* The end of this route may be a node (so record it in visited) or */ /* a route (so walk it). */ if (seg == NULL) { /* If seg != NULL then we didn't reach the route end */ if (rt->flags & RT_END_NODE) { NODE node; GATE g; int i; node = rt->end.node; /* Walk all other routes that start or end on this node */ for (rt2 = net->routes; rt2; rt2 = rt2->next) { if (rt2->flags & RT_VISITED) continue; if ((rt2->flags & RT_START_NODE) && (rt2->start.node == node)) { /* The start point of rt2 connects to the same node */ area += get_route_area_forward(net, rt2, layer, visited, method, NodeTable, NULL); } else if ((rt2->flags & RT_END_NODE) && (rt2->end.node == node)) { /* The end point of rt2 connects to the same node */ for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next); area += get_route_area_reverse(net, rt2, layer, visited, method, NodeTable, NULL); } } g = FindGateNode(NodeTable, node, &i); if (g == NULL) { /* This should not happen */ Fprintf(stderr, "Error: net %s route end marked as node, but" " no node found!\n", net->netname); return 0.0; } if (g->area[i] == 0.0) { /* There's a diffusion diode here! */ if (visited) visited[node->nodenum] = ANCHOR; return 0.0; } else { /* Add this node to the list of nodes with gates */ /* attached to this antenna area. */ if (visited) visited[node->nodenum] = VISITED; } if ((method == ANTENNA_ROUTE) && (iroute != NULL)) { set_node_to_net(node, PR_SOURCE, &iroute->glist[0], &iroute->bbox, 0); } } else { SEG rseg; /* Back up seg to point to the last segment of the route */ for (seg = rt->segments; seg && seg->next; seg = seg->next); x = seg->x2; y = seg->y2; l = seg->layer; /* Find where on rt2 the segment lands, then search rt2 for */ /* antenna area forward and reverse from that segment. */ rt2 = rt->end.route; assert( rt2 != NULL ) ; for (rseg = rt2->segments; rseg; rseg = rseg->next) { if (rseg->segtype & ST_WIRE) { if (seg->segtype & ST_WIRE) { compat = (l == rseg->layer); } else { compat = (l == rseg->layer) || (l + 1 == rseg->layer); } } else { if (seg->segtype & ST_WIRE) { compat = (l == rseg->layer) || (l == rseg->layer + 1); } else { compat = (l == rseg->layer) || (l == rseg->layer + 1) || (l + 1 == rseg->layer); } } if (compat) { if (rseg->segtype & ST_VIA) { if ((rseg->x2 == seg->x2) && (rseg->y2 == seg->y2)) break; } else if (rseg->x1 < rseg->x2) { if (rseg->y2 == seg->y2) { if ((rseg->x1 <= seg->x2) && (rseg->x2 >= seg->x2)) break; } } else if (rseg->x1 > rseg->x2) { if (rseg->y2 == seg->y2) { if ((rseg->x1 >= seg->x2) && (rseg->x2 <= seg->x2)) break; } } else if (rseg->y1 < rseg->y2) { if (rseg->x2 == seg->x2) { if ((rseg->y1 <= seg->y2) && (rseg->y2 >= seg->y2)) break; } } else if (rseg->y1 > rseg->y2) { if (rseg->x2 == seg->x2) { if ((rseg->y1 >= seg->y2) && (rseg->y2 <= seg->y2)) break; } } } } assert( rseg != NULL ) ; if (rseg->next != NULL) area += get_route_area_forward_fromseg(net, rt2, rseg->next, layer, visited, method, NodeTable, iroute); area += get_route_area_reverse_fromseg(net, rt2, rseg, layer, visited, method, NodeTable, iroute); } } return area; } /*--------------------------------------------------------------*/ /* Check route antenna forward from the beginning of the route. */ /*--------------------------------------------------------------*/ float get_route_area_forward(NET net, ROUTE rt, int layer, u_char *visited, u_char method, Tcl_HashTable *NodeTable, struct routeinfo_ *iroute) { float area; area = get_route_area_forward_fromseg(net, rt, NULL, layer, visited, method, NodeTable, iroute); return area; } /*--------------------------------------------------------------*/ /* This is the same as get_route_area_forward_fromseg, but is */ /* searching the path from end to beginning, so reverse the */ /* route first and then call get_route_area_forward_fromseg(). */ /*--------------------------------------------------------------*/ float get_route_area_reverse_fromseg(NET net, ROUTE rt, SEG nseg, int layer, u_char *visited, u_char method, Tcl_HashTable *NodeTable, struct routeinfo_ *iroute) { SEG seg, dseg, newseg, firstseg, saveseg; NODE savestartnode, saveendnode; float area; u_char saveflags; firstseg = NULL; /* Reverse the route */ 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; } saveseg = rt->segments; /* Replace the route segment with the reversed route */ rt->segments = firstseg; /* Reverse the endpoint information */ savestartnode = rt->start.node; saveendnode = rt->end.node; rt->start.node = saveendnode; rt->end.node = savestartnode; /* Reverse the start/end flags */ saveflags = rt->flags & (RT_START_NODE | RT_END_NODE); rt->flags &= ~(RT_START_NODE | RT_END_NODE); if (saveflags & RT_START_NODE) rt->flags |= RT_END_NODE; if (saveflags & RT_END_NODE) rt->flags |= RT_START_NODE; area = get_route_area_forward_fromseg(net, rt, nseg, layer, visited, method, NodeTable, iroute); /* Replace the route segment with the original route */ rt->segments = saveseg; /* Revert the endpoint information */ rt->start.node = savestartnode; rt->end.node = saveendnode; /* Revert the start/end flags */ rt->flags &= ~(RT_START_NODE | RT_END_NODE); rt->flags |= saveflags; /* Free the reversed route */ for (seg = firstseg; seg; ) { dseg = seg->next; free(seg); seg = dseg; } return area; } /*--------------------------------------------------------------*/ /* Walk a route in reverse from end to start. */ /*--------------------------------------------------------------*/ float get_route_area_reverse(NET net, ROUTE rt, int layer, u_char *visited, u_char method, Tcl_HashTable *NodeTable, struct routeinfo_ *iroute) { float area; area = get_route_area_reverse_fromseg(net, rt, NULL, layer, visited, method, NodeTable, iroute); return area; } /*--------------------------------------------------------------*/ /* Find all antenna violations at a specific metal layer */ /*--------------------------------------------------------------*/ int find_layer_antenna_violations(int layer, Tcl_HashTable *NodeTable) { int numerrors, n, nn, numroutes, i, j, new, neterrors; u_char *visited, method; float antenna_ratio, thick; GATE g; NET net; ROUTE rt, saveroute; NODEINFO nodeptr; NODE node, tnode; SEG seg; ANTENNAINFO newantenna; float gate_area, metal_area, ratio, save_gate, save_metal, max_ratio; numerrors = 0; /* Get the metal layer record for this layer and find the metal */ /* area ratio limit and the method to be used for calculating */ /* metal area. */ method = LefGetRouteAntennaMethod(layer); if (method == CALC_NONE) return 0; /* No antenna information in tech */ antenna_ratio = (float)LefGetRouteAreaRatio(layer); thick = (float)LefGetRouteThickness(layer); if (((method == CALC_SIDEAREA) || (method == CALC_AGG_SIDEAREA)) && (thick == 0.0)) return 0; /* Insufficient antenna information in tech */ /* Make a pass through all nets to find antenna violations */ for (n = 0; n < Numnets; n++) { net = Nlnets[n]; if ((net->netnum == VDD_NET) || (net->netnum == GND_NET) || (net->netnum == ANTENNA_NET)) continue; /* Ignore nets with no routes */ numroutes = 0; for (rt = net->routes; rt; rt = rt->next) numroutes++; if (numroutes == 0) continue; /* Consider each terminal as a separate sub-net calculation. */ /* But if multiple terminals belong to the same sub-net, they */ /* are marked visited and ignored on subsequent calculations. */ visited = (u_char *)malloc(net->numnodes * sizeof(u_char)); for (node = net->netnodes; node != NULL; node = node->next) { nn = node->nodenum; visited[nn] = NOT_VISITED; } /* Make a pass through all nodes of the net. Where they are */ /* not connected together at "layer", these are individual */ /* sub-nets. */ neterrors = 0; max_ratio = 0.0; /* For diagnostics only */ for (node = net->netnodes; node != NULL; node = node->next) { nn = node->nodenum; if (visited[nn] >= PROCESSED) continue; /* Already seen */ /* Find the gate area of this node */ g = FindGateNode(NodeTable, node, &i); metal_area = 0.0; if (g->area[i] == 0.0) { visited[nn] = ANCHOR; /* Mark as S/D connection */ continue; /* No gate, so no violation */ } else visited[nn] = VISITED; /* Clear visited flags for routes */ for (rt = net->routes; rt; rt = rt->next) rt->flags &= ~RT_VISITED; /* Find the route or routes that connect to this node */ for (rt = net->routes; rt; rt = rt->next) { if ((rt->flags & RT_START_NODE) && (rt->start.node == node)) { saveroute = rt; metal_area += get_route_area_forward(net, rt, layer, visited, method, NodeTable, NULL); } else if ((rt->flags & RT_END_NODE) && (rt->end.node == node)) { saveroute = rt; metal_area += get_route_area_reverse(net, rt, layer, visited, method, NodeTable, NULL); } else continue; } /* Gate area is combined area of gates visited */ gate_area = 0.0; for (tnode = net->netnodes; tnode != NULL; tnode = tnode->next) { j = tnode->nodenum; if (visited[j] == VISITED) { g = FindGateNode(NodeTable, tnode, &i); if (g->area[i] == 0.0) { visited[j] = ANCHOR; gate_area = 0.0; break; } else gate_area += g->area[i]; } } if (gate_area > 0.0) { ratio = metal_area / gate_area; if (ratio > max_ratio) { max_ratio = ratio; save_gate = gate_area; save_metal = metal_area; } if (ratio > antenna_ratio) { /* Record and report the violation */ numerrors++; neterrors++; if (Verbose > 1) { Fprintf(stderr, "Antenna violation on node %d of net %s at metal%d\n", nn, net->netname, layer + 1); } if (Verbose > 2) { Fprintf(stderr, "Metal area = %f, Gate area = %f, Ratio = %f\n", metal_area, gate_area, ratio); } newantenna = (ANTENNAINFO)malloc(sizeof(struct antennainfo_)); newantenna->net = net; newantenna->node = node; newantenna->layer = layer; newantenna->route = saveroute; newantenna->next = AntennaList; AntennaList = newantenna; } } /* Mark gates as visited on previous pass */ for (tnode = net->netnodes; tnode != NULL; tnode = tnode->next) { j = tnode->nodenum; if (visited[j] == VISITED) visited[j] = PROCESSED; } } free(visited); if (Verbose > 3) { /* Diagnostic */ if (neterrors == 0) { if (max_ratio > 0.0) Fprintf(stderr, "Worst case: Metal area = %f, Gate area = %f, " "Ratio = %f\n", save_metal, save_gate, max_ratio); } } /* Clear route visited flags */ for (rt = net->routes; rt; rt = rt->next) rt->flags &= ~RT_VISITED; } return numerrors; } /*--------------------------------------------------------------*/ /* This routine is a combination of set_node_to_net(), */ /* set_routes_to_net(), and disable_node_nets() (see qrouter.c */ /* and maze.c), but walks the routes in the same manner used */ /* for finding the antenna violations. Set the antenna part of */ /* the net as SOURCE, the free antenna taps as TARGET, and the */ /* non-antenna portion of the net to an unused net number, */ /* which can be converted back after routing. */ /*--------------------------------------------------------------*/ int set_antenna_to_net(int newflags, struct routeinfo_ *iroute, u_char stage, ANTENNAINFO violation, Tcl_HashTable *NodeTable) { int x, y, lay, rval, layer; PROUTE *Pr; ROUTE rt, clrrt; NODE node; NET net; /* Set the node and connected antenna metal routes to PR_SOURCE. */ rt = violation->route; node = violation->node; net = violation->net; layer = violation->layer; if ((rt->flags & RT_START_NODE) && (rt->start.node == node)) get_route_area_forward(net, rt, layer, NULL, ANTENNA_ROUTE, NodeTable, iroute); else if ((rt->flags & RT_END_NODE) && (rt->end.node == node)) get_route_area_reverse(net, rt, layer, NULL, ANTENNA_ROUTE, NodeTable, iroute); else { /* This should not happen */ Fprintf(stderr, "Error: Antenna route and node do not connect!\n"); return 1; } /* Clear route visited flags for next pass */ for (clrrt = iroute->net->routes; clrrt; clrrt = clrrt->next) clrrt->flags &= ~RT_VISITED; /* Disable the remainder of the route */ if ((rt->flags & RT_START_NODE) && (rt->start.node == node)) get_route_area_forward(net, rt, layer, NULL, ANTENNA_DISABLE, NodeTable, iroute); else if ((rt->flags & RT_END_NODE) && (rt->end.node == node)) get_route_area_reverse(net, rt, layer, NULL, ANTENNA_DISABLE, NodeTable, iroute); else { /* This should not happen */ Fprintf(stderr, "Error: Antenna route and node do not connect!\n"); return 1; } /* Done checking routes; clear route visited flags */ for (clrrt = iroute->net->routes; clrrt; clrrt = clrrt->next) clrrt->flags &= ~RT_VISITED; /* Set the antenna taps to the net number. */ /* Routine is similar to set_powerbus_to_net(). */ rval = 0; for (lay = 0; lay < Num_layers; lay++) for (x = 0; x < NumChannelsX; x++) for (y = 0; y < NumChannelsY; y++) if ((OBSVAL(x, y, lay) & NETNUM_MASK) == ANTENNA_NET) { Pr = &OBS2VAL(x, y, lay); // Skip locations that have been purposefully disabled if (!(Pr->flags & PR_COST) && (Pr->prdata.net == MAXNETNUM)) continue; else if (!(Pr->flags & PR_SOURCE)) { Pr->flags |= (PR_TARGET | PR_COST); Pr->prdata.cost = MAXRT; rval = 1; OBSVAL(x, y, lay) &= ~NETNUM_MASK; OBSVAL(x, y, lay) |= net->netnum; } } return rval; } /*--------------------------------------------------------------*/ /* This routine is similar to route_setup() for the normal */ /* stage routes, with changes for the antenna routing. */ /* Set the node in the "violation" record to source, and set */ /* all free antenna taps to destination. Add existing routes */ /* to the source in the same manner as was used to find the */ /* antenna violation in the first place (this is a subnet of */ /* the complete net). Disable the remainder of the net. */ /* Set all free antenna taps to the net number being routed, */ /* then route like stage 1 power routing. */ /*--------------------------------------------------------------*/ int antenna_setup(struct routeinfo_ *iroute, ANTENNAINFO violation, Tcl_HashTable *NodeTable) { int i, j, netnum, rval; PROUTE *Pr; for (i = 0; i < Num_layers; i++) { for (j = 0; j < NumChannelsX * NumChannelsY; j++) { netnum = Obs[i][j] & (~BLOCKED_MASK); Pr = &Obs2[i][j]; if (netnum != 0) { Pr->flags = 0; // Clear all flags if (netnum == DRC_BLOCKAGE) Pr->prdata.net = netnum; else Pr->prdata.net = netnum & NETNUM_MASK; } else { Pr->flags = PR_COST; // This location is routable Pr->prdata.cost = MAXRT; } } } // Fill out route information record iroute->net = violation->net; iroute->rt = NULL; for (i = 0; i < 6; i++) iroute->glist[i] = NULL; iroute->nsrc = violation->node; iroute->nsrctap = iroute->nsrc->taps; iroute->maxcost = MAXRT; iroute->do_pwrbus = TRUE; iroute->pwrbus_src = 0; iroute->bbox.x2 = iroute->bbox.y2 = 0; iroute->bbox.x1 = NumChannelsX; iroute->bbox.y1 = NumChannelsY; rval = set_antenna_to_net(PR_SOURCE, iroute, 0, violation, NodeTable); /* Unlikely that MASK_BBOX would be useful, since one does */ /* not know if an antenna tap is inside the box or not. */ /* Maybe if bounding box is expanded to encompass some */ /* number of taps. . . */ // if (maskMode == MASK_NONE) fillMask((u_char)0); // else if (maskMode == MASK_BBOX) // createBboxMask(iroute->net, (u_char)Numpasses); iroute->maxcost = 20; return rval; } /*--------------------------------------------------------------*/ /* The simplest way to fix an antenna violation is to find */ /* a place in the antenna metal to break the antenna and pull */ /* it up to a higher level of metal. Depending on the severity */ /* of the antenna violation, this may need to be done more than */ /* once. If no place to break the antenna is found, return -1 */ /* for failure. */ /*--------------------------------------------------------------*/ int simpleantennafix(ANTENNAINFO violation, Tcl_HashTable *NodeTable) { return -1; /* Antenna was not fixed */ } /*--------------------------------------------------------------*/ /* Route from nets with antenna violations to the nearest */ /* routable antenna cell tap. */ /* */ /* This routine is essentially the same as doroute() but with */ /* some special handling related to the antenna taps, which */ /* have much in common with VDD and GND taps but significant */ /* differences as well. */ /*--------------------------------------------------------------*/ int doantennaroute(ANTENNAINFO violation, Tcl_HashTable *NodeTable) { NET net; NODE node; ROUTE rt1, lrt; int layer, i, result, savelayers; struct routeinfo_ iroute; net = violation->net; node = violation->node; layer = violation->layer; result = antenna_setup(&iroute, violation, NodeTable); rt1 = createemptyroute(); rt1->netnum = net->netnum; iroute.rt = rt1; /* Force routing to be done at or below the antenna check layer. */ savelayers = Num_layers; Num_layers = violation->layer + 1; result = route_segs(&iroute, 0, (u_char)0); Num_layers = savelayers; if (result < 0) { /* To do: Handle failures? */ Fprintf(stderr, "Antenna anchoring route failed.\n"); free(rt1); } else { TotalRoutes++; if (net->routes) { for (lrt = net->routes; lrt->next; lrt = lrt->next); lrt->next = rt1; } else { /* This should not happen */ Fprintf(stderr, "Error: Net has no routes!\n"); net->routes = rt1; } } /* For power-bus-type routing, glist is not empty after routing */ free_glist(&iroute); /* Put free taps back to ANTENNA_NET */ revert_antenna_taps(net->netnum, rt1->start.node); return result; } /*--------------------------------------------------------------*/ /* Top level routine called from tclqrouter.c */ /*--------------------------------------------------------------*/ void resolve_antenna(char *antennacell, u_char do_fix) { FILE *fout; int numtaps, numerrors, numfixed, result; int layererrors; int layer, i, new; Tcl_HashTable NodeTable; Tcl_HashEntry *entry; GATE g; NET net; ROUTE rt; ANTENNAINFO nextviolation, FixedList = NULL, BadList = NULL; numtaps = count_free_antenna_taps(antennacell); if (Verbose > 3) { Fprintf(stdout, "Number of free antenna taps = %d\n", numtaps); } AntennaList = NULL; numerrors = 0; numfixed = 0; /* Build a hash table of nodes, so the gate area can be found */ /* quickly for any node by hash lookup. */ 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; entry = Tcl_CreateHashEntry(&NodeTable, (char *)(*(g->noderec + i)), &new); Tcl_SetHashValue(entry, gn); } } /* Working from the 1nd layer metal to the top, compute */ /* route metal to gate area ratios. Mark each one when */ /* done, as an antenna violation that has been fixed at, */ /* say, metal2 can no longer be a violation on any higer */ /* layer of metal. */ for (layer = 0; layer < Num_layers; layer++) { layererrors = find_layer_antenna_violations(layer, &NodeTable); numerrors += layererrors; if (Verbose > 2) { Fprintf(stdout, "Number of antenna errors on metal%d = %d\n", layer + 1, layererrors); } /* Fix the violations found on this layer before moving */ /* on to the next layer. */ while (AntennaList != NULL) { nextviolation = AntennaList->next; if (do_fix) { result = simpleantennafix(AntennaList, &NodeTable); if (result == 0) { /* No antenna cell involved, so no backannotation */ /* required. Remove the "route" record. */ AntennaList->route = NULL; } else result = doantennaroute(AntennaList, &NodeTable); if (result >= 0) numfixed++; } /* Move the error information to either the Fixed or Bad lists */ if (result >= 0) { AntennaList->next = FixedList; FixedList = AntennaList; if (AntennaList->route != NULL) { /* Replace the route record with the last route */ /* of the net, which was the route added to fix. */ /* If the net requires more than one antenna */ /* anchor, then routes won't be confused. */ for (rt = AntennaList->net->routes; rt && rt->next; rt = rt->next); AntennaList->route = rt; } } else { AntennaList->next = BadList; BadList = AntennaList; } AntennaList = nextviolation; } } if (Verbose > 0) { Fprintf(stdout, "Total number of antenna errors found = %d\n", numerrors); if (do_fix) Fprintf(stdout, "Total number of antenna errors fixed = %d\n", numfixed); } if (numtaps < numerrors) { if (numtaps == 0) Fprintf(stderr, "There are no antenna taps to use to correct " "antenna errors!\n"); else { Fprintf(stderr, "There are not enough antenna taps to use to " "correct antenna errors!\n"); Fprintf(stderr, "Number of errors = %d, number of taps = %d\n", numerrors, numtaps); Fprintf(stderr, "Increate the amount of unallocated antenna cells" " in the design.\n"); } /* To do: Replace the error message with an ad-hoc solution to */ /* pull routes up to a higher metal layer near the gate causing */ /* the error. */ } /* Output the violation lists. The fixed violations need to be */ /* known so that the additional connection to the net can be added */ /* to the netlist for verification purposes. The unfixed */ /* violations need to be reported so they can be tracked down and */ /* fixed by hand. */ if ((FixedList != NULL) || (BadList != NULL)) fout = fopen("antenna.out", "w"); /* Clear any existing list of instance connections (annotations) */ if (AnnotateList) { ANNOTATEINFO nextannotate; while (AnnotateList != NULL) { nextannotate = AnnotateList->next; free(AnnotateList); AnnotateList = nextannotate; } } if (FixedList != NULL) { ROUTE rt; ANNOTATEINFO newannotate; fprintf(fout, "Revised netlist: New antenna anchor connections\n"); for (nextviolation = FixedList; nextviolation; nextviolation = nextviolation->next) { // NOTE: nextviolation->route was changed from the route that // connects to the gate in violation, to the route that fixes // the antenna error. g = FindGateNode(&NodeTable, nextviolation->route->start.node, &i); fprintf(fout, "Net=%s Instance=%s Cell=%s Pin=%s\n", nextviolation->net->netname, g->gatename, g->gatetype->gatename, g->gatetype->node[i]); // Create an annotation entry for this fixed violation newannotate = (ANNOTATEINFO)malloc(sizeof(struct annotateinfo_)); newannotate->net = nextviolation->net; newannotate->instance = g->gatename; newannotate->pin = g->gatetype->node[i]; newannotate->flag = ANNO_INIT; newannotate->next = AnnotateList; AnnotateList = newannotate; } fprintf(fout, "\n"); } if (BadList != NULL) { fprintf(fout, "Unfixed antenna errors:\n"); for (nextviolation = BadList; nextviolation; nextviolation = nextviolation->next) { g = FindGateNode(&NodeTable, nextviolation->node, &i); fprintf(fout, "Net=%s Instance=%s Cell=%s Pin=%s error on Metal%d\n", nextviolation->net->netname, g->gatename, g->gatetype->gatename, g->gatetype->node[i], nextviolation->layer + 1); } } if ((FixedList != NULL) || (BadList != NULL)) fclose(fout); /* Free up the node hash table */ FreeNodeTable(&NodeTable); Tcl_DeleteHashTable(&NodeTable); /* Free up the violation lists */ if (FixedList != NULL) { while (FixedList != NULL) { nextviolation = FixedList->next; free(FixedList); FixedList = nextviolation; } } while (BadList != NULL) { nextviolation = BadList->next; free(BadList); BadList = nextviolation; } } #endif /* TCL_QROUTER */ /* end of antenna.c */ qrouter-1.4.88/node.c0000644000175000017510000033544313625043307013754 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* node.c -- Generation of detailed network and obstruction */ /* information on the routing grid based on the geometry of the */ /* layout of the standard cell macros. */ /* */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June, 2011, based on work by Steve */ /* Beccue. */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include "qrouter.h" #include "node.h" #include "qconfig.h" #include "lef.h" #include "def.h" #include "output.h" /*--------------------------------------------------------------*/ /* SetNodeinfo -- */ /* Allocate a NODEINFO record and put it in the Nodeinfo */ /* array at position (gridx, gridy, d->layer). Return the */ /* pointer to the location. */ /*--------------------------------------------------------------*/ NODEINFO SetNodeinfo(int gridx, int gridy, int layer, NODE node) { DPOINT dp; NODEINFO *lnodeptr; lnodeptr = &NODEIPTR(gridx, gridy, layer); if (*lnodeptr == NULL) { *lnodeptr = (NODEINFO)calloc(1, sizeof(struct nodeinfo_)); /* Make sure this position is in the list of node's taps. Add */ /* it if it is not there. */ for (dp = (DPOINT)node->taps; dp; dp = dp->next) if (dp->gridx == gridx && dp->gridy == gridy && dp->layer == layer) break; if (dp == NULL) for (dp = (DPOINT)node->extend; dp; dp = dp->next) if (dp->gridx == gridx && dp->gridy == gridy && dp->layer == layer) break; if (dp == NULL) { dp = (DPOINT)malloc(sizeof(struct dpoint_)); dp->gridx = gridx; dp->gridy = gridy; dp->layer = layer; dp->x = (gridx * PitchX) + Xlowerbound; dp->y = (gridy * PitchY) + Ylowerbound; dp->next = node->extend; node->extend = dp; } } return *lnodeptr; } /*--------------------------------------------------------------*/ /* FreeNodeinfo -- */ /* Free a NODEINFO record at array Nodeinfo position */ /* (gridx, gridy, d->layer). Set the position pointer to */ /* NULL. */ /*--------------------------------------------------------------*/ void FreeNodeinfo(int gridx, int gridy, int layer) { NODEINFO *lnodeptr; lnodeptr = &NODEIPTR(gridx, gridy, layer); if (*lnodeptr != NULL) { free(*lnodeptr); *lnodeptr = NULL; } } /*--------------------------------------------------------------*/ /* count_reachable_taps() */ /* */ /* For each grid point in the layout, find if it corresponds */ /* to a node and is unobstructed. If so, increment the node's */ /* count of reachable taps. Then work through the list of */ /* nodes and determine if any are completely unreachable. If */ /* so, then unobstruct any position that is inside tap */ /* geometry that can contain a via. */ /* */ /* NOTE: This routine should check for tap rectangles that */ /* may combine to form an area large enough to place a via; */ /* also, it should check for tap points that are routable */ /* by a wire and not a tap. However, those conditions are */ /* rare and are left unhandled for now. */ /* */ /* If "unblock_all" is 1, then unblock all grid points that */ /* are cleanly routable by being completely inside a pin with */ /* available margins for placing a via, regardless of whether */ /* or not the pin has other available tap points. This should */ /* only be used if obstructions are drawn in the style where */ /* they can abut pins (e.g., part of the pin has been marked */ /* as an obstruction). */ /*--------------------------------------------------------------*/ void count_reachable_taps(u_char unblock_all) { NODE node; NODEINFO lnode; GATE g; DSEG ds; int l, i, j, orient; int gridx, gridy; double deltax, deltay; double dx, dy; for (l = 0; l < Num_layers; l++) { for (j = 0; j < NumChannelsX * NumChannelsY; j++) { if (Nodeinfo[l][j]) { node = Nodeinfo[l][j]->nodeloc; if (node != NULL) { // Redundant check; if Obs has NO_NET set, then // Nodeinfo->nodeloc for that position should already // be NULL if (!(Obs[l][j] & NO_NET)) node->numtaps++; } } } } for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { node = g->noderec[i]; if (node == NULL) continue; if (node->numnodes == 0) continue; // e.g., vdd or gnd bus if ((node->numtaps == 0) || (unblock_all == TRUE)) { /* Will try more than one via if available */ for (orient = 0; orient < 4; orient += 2) { for (ds = g->taps[i]; ds; ds = ds->next) { deltax = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient); deltay = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient); gridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1; if (gridx < 0) gridx = 0; while (1) { dx = (gridx * PitchX) + Xlowerbound; if (dx > ds->x2 || gridx >= NumChannelsX) break; if (((dx - ds->x1 + EPS) > deltax) && ((ds->x2 - dx + EPS) > deltax)) { gridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1; if (gridy < 0) gridy = 0; while (1) { dy = (gridy * PitchY) + Ylowerbound; if (dy > ds->y2 || gridy >= NumChannelsY) break; if (((dy - ds->y1 + EPS) > deltay) && ((ds->y2 - dy + EPS) > deltay)) { if ((ds->layer == Num_layers - 1) || !(OBSVAL(gridx, gridy, ds->layer + 1) & NO_NET)) { // Grid position is clear for placing a via if ((orient == 0) && (Verbose > 1)) Fprintf(stdout, "Tap position (%g, %g)" " appears to be technically routable" " so it is being forced routable.\n", dx, dy); else if (Verbose > 1) Fprintf(stdout, "Tap position (%g, %g)" " appears to be technically routable" " with alternate via, so it is being" " forced routable.\n", dx, dy); OBSVAL(gridx, gridy, ds->layer) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | (u_int)node->netnum; lnode = SetNodeinfo(gridx, gridy, ds->layer, node); lnode->nodeloc = node; lnode->nodesav = node; /* If we got to orient = 2, mark NI_NO_VIAX */ if (orient == 2) lnode->flags |= NI_NO_VIAX; /* This is a bit harsh, but should work */ else lnode->flags |= NI_NO_VIAY; node->numtaps++; } } gridy++; } } gridx++; } } /* If there's a solution, don't go looking at other vias */ if (node->numtaps > 0) break; } } if (node->numtaps == 0) { /* Node wasn't cleanly within tap geometry when centered */ /* on a grid point. But if the via can be offset and is */ /* cleanly within the tap geometry, then allow it. */ double dist, mindist; int dir, mask, tapx, tapy, tapl; /* Will try more than one via if available */ for (orient = 0; orient < 4; orient += 2) { /* Initialize mindist to a large value */ mask = 0; mindist = PitchX + PitchY; dir = 0; /* Indicates no solution found */ for (ds = g->taps[i]; ds; ds = ds->next) { deltax = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient); deltay = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient); gridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1; if (gridx < 0) gridx = 0; while (1) { dx = (gridx * PitchX) + Xlowerbound; if (dx > ds->x2 || gridx >= NumChannelsX) break; if (((dx - ds->x1 + EPS) > -deltax) && ((ds->x2 - dx + EPS) > -deltax)) { gridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1; if (gridy < 0) gridy = 0; while (1) { dy = (gridy * PitchY) + Ylowerbound; if (dy > ds->y2 || gridy >= NumChannelsY) break; // Check that the grid position is inside the // tap rectangle. // NOTE: If the point above the grid is blocked, // then a via cannot be placed here, so skip it. // This currently looks only for completely // obstructed positions. To do: For directionally // obstructed positions, see if the obstruction // is in the opposite direction of the via's // offset and at least the same distance. // Otherwise, it won't clear. if (((ds->layer == Num_layers - 1) || !(OBSVAL(gridx, gridy, ds->layer + 1) & (NO_NET || OBSTRUCT_MASK))) && ((dy - ds->y1 + EPS) > -deltay) && ((ds->y2 - dy + EPS) > -deltay)) { // Grid point is inside tap geometry. // Since it did not pass the simple insideness // test previously, it can be assumed that // one of the edges is closer to the grid point // than 1/2 via width. Find that edge and use // it to determine the offset. // Check right edge if ((ds->x2 - dx + EPS) < deltax) { dist = deltax - ds->x2 + dx; // Confirm other edges if ((dx - dist - deltax + EPS > ds->x1) && (dy - deltay + EPS > ds->y1) && (dy + deltay - EPS < ds->y2)) { if (dist < fabs(mindist)) { mindist = dist; mask = STUBROUTE; dir = NI_STUB_EW; tapx = gridx; tapy = gridy; tapl = ds->layer; } } } // Check left edge if ((dx - ds->x1 + EPS) < deltax) { dist = deltax - dx + ds->x1; // Confirm other edges if ((dx + dist + deltax - EPS < ds->x2) && (dy - deltay + EPS > ds->y1) && (dy + deltay - EPS < ds->y2)) { if (dist < fabs(mindist)) { mindist = -dist; mask = STUBROUTE; dir = NI_STUB_EW; tapx = gridx; tapy = gridy; tapl = ds->layer; } } } // Check top edge if ((ds->y2 - dy + EPS) < deltay) { dist = deltay - ds->y2 + dy; // Confirm other edges if ((dx - deltax + EPS > ds->x1) && (dx + deltax - EPS < ds->x2) && (dy - dist - deltay + EPS > ds->y1)) { if (dist < fabs(mindist)) { mindist = -dist; mask = STUBROUTE; dir = NI_STUB_NS; tapx = gridx; tapy = gridy; tapl = ds->layer; } } } // Check bottom edge if ((dy - ds->y1 + EPS) < deltay) { dist = deltay - dy + ds->y1; // Confirm other edges if ((dx - deltax + EPS > ds->x1) && (dx + deltax - EPS < ds->x2) && (dy + dist + deltay - EPS < ds->y2)) { if (dist < fabs(mindist)) { mindist = dist; mask = STUBROUTE; dir = NI_STUB_NS; tapx = gridx; tapy = gridy; tapl = ds->layer; } } } } gridy++; } } gridx++; } } /* Was a solution found? */ if (mask != 0) { // Grid position is clear for placing a via if (Verbose > 1) Fprintf(stdout, "Tap position (%d, %d) appears to be" " technically routable with an offset, so" " it is being forced routable.\n", tapx, tapy); OBSVAL(tapx, tapy, tapl) = (OBSVAL(tapx, tapy, tapl) & BLOCKED_MASK) | mask | (u_int)node->netnum; lnode = SetNodeinfo(tapx, tapy, tapl, node); lnode->nodeloc = node; lnode->nodesav = node; lnode->stub = dist; lnode->flags |= dir; /* If we got to orient = 2 then mark NI_NO_VIAX */ if (orient == 2) lnode->flags |= NI_NO_VIAX; node->numtaps++; } /* If there's a solution, don't go looking at other vias */ if (node->numtaps > 0) break; } } } } /* Last pass to output error messages for any taps that were not */ /* handled by the code above. */ for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { node = g->noderec[i]; if (node == NULL) continue; if (node->numnodes == 0) continue; // e.g., vdd or gnd bus if (node->numtaps == 0) { Fprintf(stderr, "Error: Node %s of net \"%s\" has no taps!\n", print_node_name(node), node->netname); Fprintf(stderr, "Qrouter will not be able to completely" " route this net.\n"); if (Verbose > 1) { int found_inside, found_inrange; Fprintf(stderr, "Tap position blockage analysis:\n"); /* Unreachable taps are the most common problem with */ /* new processes or buggy code, so make a detailed */ /* report of blockages affecting routing for debugging. */ found_inside = found_inrange = 0; for (ds = g->taps[i]; ds; ds = ds->next) { unsigned char is_inside, is_inrange; deltax = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, 0); deltay = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, 0); Fprintf(stderr, "Tap geometry (%g %g) to (%g %g):\n", ds->x1, ds->y1, ds->x2, ds->y2); gridx = (int)(((ds->x1 - 1) - Xlowerbound) / PitchX) - 1; if (gridx < 0) gridx = 0; while (1) { dx = (gridx * PitchX) + Xlowerbound; if (dx > (ds->x2 + 1) || gridx >= NumChannelsX) break; gridy = (int)(((ds->y1 - 1) - Ylowerbound) / PitchY) - 1; if (gridy < 0) gridy = 0; while (1) { dy = (gridy * PitchY) + Ylowerbound; if (dy > (ds->y2 + 1) || gridy >= NumChannelsY) break; is_inside = (dx >= ds->x1 && dx <= ds->x2 && dy >= ds->y1 && dy <= ds->y2) ? 1 : 0; is_inrange = (dx > ds->x1 - deltax && dx < ds->x2 + deltax && dy > ds->y1 - deltay && dy < ds->y2 + deltay) ? 1 : 0; if (is_inrange) { Fprintf(stderr, "Grid position (%d %d) at (%g %g) " "layer %d is %s tap geometry.\n", gridx, gridy, dx, dy, ds->layer, (is_inside == 1) ? "inside" : "outside"); print_grid_information(gridx, gridy, ds->layer); found_inrange++; if (is_inside) found_inside++; } gridy++; } gridx++; } } if (found_inrange == 0) Fprintf(stderr, "No positions analyzed.\n"); Fprintf(stderr, "%d grid position%s found " "inside tap geometry\n", found_inside, ((found_inside == 1) ? " was" : "s were")); Fprintf(stderr, "%d grid position%s found " "nearby tap geometry\n", found_inrange, ((found_inrange == 1) ? " was" : "s were")); } } } } } /*--------------------------------------------------------------*/ /* check_variable_pitch() */ /* */ /* This routine is used by the routine below it to generate */ /* obstructions that force routes to be placed in 1-of-N */ /* tracks. However, it is also used to determine the same */ /* information for the .info file, so that the effective */ /* pitch is output, not the pitch copied from the LEF file. */ /* Output is the vertical and horizontal pitch multipliers, */ /* passed back through pointers. */ /*--------------------------------------------------------------*/ void check_variable_pitch(int l, int *hptr, int *vptr) { int o, hnum, vnum; double vpitch, hpitch, wvia, wviax, wviay; o = LefGetRouteOrientation(l); // Note that when "horizontal" (o = 1) is passed to LefGetXYViaWidth, // it returns the via width top-to-bottom (orient meaning is // reversed for LefGetXYViaWidth), which is what we want. . . // Try both via orientations and choose the best, assuming that it is // a lot easier to rotate and shift vias around than it is to lose // half the routing grid. if (l == 0) { wviax = LefGetXYViaWidth(l, l, o, 0); wviay = LefGetXYViaWidth(l, l, o, 3); } else { wviax = LefGetXYViaWidth(l - 1, l, o, 0); wviay = LefGetXYViaWidth(l - 1, l, o, 3); } wvia = (wviax < wviay) ? wviax : wviay; if (o == 1) { // Horizontal route vpitch = LefGetRoutePitch(l); // Changed: routes must be able to accomodate the placement // of a via in the track next to it. // hpitch = LefGetRouteWidth(l) + LefGetRouteSpacing(l); hpitch = 0.5 * (LefGetRouteWidth(l) + wvia) + LefGetRouteSpacing(l); } else { // Vertical route hpitch = LefGetRoutePitch(l); // vpitch = LefGetRouteWidth(l) + LefGetRouteSpacing(l); vpitch = 0.5 * (LefGetRouteWidth(l) + wvia) + LefGetRouteSpacing(l); } vnum = (int)((vpitch / PitchY) - EPS) + 1; hnum = (int)((hpitch / PitchX) - EPS) + 1; // To mark blockages, either none of (hnum & vnum) should be // larger than 1, or both of them should be. Further info in // create_obstructions_from_variable_pitch(), below. if (vnum > 1 && hnum == 1) hnum++; if (hnum > 1 && vnum == 1) vnum++; *vptr = vnum; *hptr = hnum; } /*--------------------------------------------------------------*/ /* create_obstructions_from_variable_pitch() */ /* */ /* Although it would be nice to have an algorithm that would */ /* work with any arbitrary pitch, qrouter will work around */ /* having larger pitches on upper metal layers by selecting */ /* 1 out of every N tracks for routing, and placing */ /* obstructions in the interstices. This makes the possibly */ /* unwarranted assumption that the contact down to the layer */ /* below does not cause spacing violations to neighboring */ /* tracks. If that assumption fails, this routine will have */ /* to be revisited. */ /*--------------------------------------------------------------*/ void create_obstructions_from_variable_pitch(void) { int l, vnum, hnum, hoff, voff, x, y; NODEINFO lnode; TRACKS tracksinfo, tracksinfoother; for (l = 0; l < Num_layers; l++) { // check_variable_pitch() guarantees that either hnum // and vnum are both one, or both are larger than 1. check_variable_pitch(l, &hnum, &vnum); if (hnum == 1 && vnum == 1) continue; // No obstructions needed // Compute the offset of the tracks to mark obstructions tracksinfo = DefGetTracks(l); if (tracksinfo == NULL) { // Should look at standard cell placement and LEF offset // to determine offset here. For now, just use 0. hoff = voff = 0; } else { // Use the start position relative to lowerbound to determine // the offset. use the offset of the higher or lower layer // for determining the offset in the opposite direction of // the current layer orientation. if (l < Num_layers - 1) { // If not the top layer, then use the upper layer as the other layer tracksinfoother = DefGetTracks(l + 1); } else if (l > 0) { // Otherwise, use the lower layer tracksinfoother = DefGetTracks(l - 1); } else { // Should not happen, as it means routing is done with one layer. . . tracksinfoother = (TRACKS)NULL; } if (Vert[l]) { hoff = (int)((tracksinfo->start - Xlowerbound) / PitchX + 0.5); voff = (tracksinfoother == (TRACKS)NULL) ? 0 : (int)((tracksinfoother->start - Ylowerbound) / PitchY + 0.5); } else { voff = (int)((tracksinfo->start - Ylowerbound) / PitchY + 0.5); hoff = (tracksinfoother == (TRACKS)NULL) ? 0 : (int)((tracksinfoother->start - Xlowerbound) / PitchX + 0.5); } } // This could be better handled by restricting // access from specific directions rather than // marking a position as NO_NET. Since the // routine below will mark no positions restricted // if either hnum is 1 or vnum is 1, regardless of // the other value, then we force both values to // be at least 2. if (vnum > 1 || hnum > 1) { for (x = 0; x < NumChannelsX; x++) { if ((x - hoff) % hnum == 0) continue; for (y = 0; y < NumChannelsY; y++) { if ((y - voff) % vnum == 0) continue; // If the grid position itself is a node, don't restrict // routing based on variable pitch. if (((lnode = NODEIPTR(x, y, l)) != NULL) && (lnode->nodeloc != NULL)) continue; // If there is a node in an adjacent grid then allow // routing from that direction. if ((x > 0) && ((lnode = NODEIPTR(x - 1, y, l)) != NULL) && (lnode->nodeloc != NULL)) OBSVAL(x, y, l) = BLOCKED_MASK & ~BLOCKED_W; else if ((y > 0) && ((lnode = NODEIPTR(x , y - 1, l)) != NULL) && (lnode->nodeloc != NULL)) OBSVAL(x, y, l) = BLOCKED_MASK & ~BLOCKED_S; else if ((x < NumChannelsX - 1) && ((lnode = NODEIPTR(x + 1, y, l)) != NULL) && (lnode->nodeloc != NULL)) OBSVAL(x, y, l) = BLOCKED_MASK & ~BLOCKED_E; else if ((y < NumChannelsY - 1) && ((lnode = NODEIPTR(x, y + 1, l)) != NULL) && (lnode->nodeloc != NULL)) OBSVAL(x, y, l) = BLOCKED_MASK & ~BLOCKED_N; else OBSVAL(x, y, l) = NO_NET; } } } } } /*--------------------------------------------------------------*/ /* disable_gridpos() --- */ /* Render the position at (x, y, lay) unroutable by */ /* setting its Obs[] entry to NO_NET and removing it from */ /* the Nodeinfo->nodeloc and Nodeinfo->nodesav records. */ /*--------------------------------------------------------------*/ static void disable_gridpos(int x, int y, int lay) { int apos = OGRID(x, y); Obs[lay][apos] = (u_int)(NO_NET | OBSTRUCT_MASK); if (Nodeinfo[lay][apos]) { free(Nodeinfo[lay][apos]); Nodeinfo[lay][apos] = NULL; } } /*--------------------------------------------------------------*/ /* count_pinlayers()--- */ /* Check which layers have non-NULL Nodeinfo entries. */ /* Then set "Pinlayers" and free all the unused layers. */ /* This saves a lot of memory, especially when the number */ /* of routing layers becomes large. */ /*--------------------------------------------------------------*/ void count_pinlayers(void) { int j, l; Pinlayers = 0; for (l = 0; l < Num_layers; l++) { for (j = 0; j < NumChannelsX * NumChannelsY; j++) { if (Nodeinfo[l][j]) { Pinlayers = l + 1; break; } } } for (l = Pinlayers; l < Num_layers; l++) { free(Nodeinfo[l]); Nodeinfo[l] = NULL; } } /*--------------------------------------------------------------*/ /* check_obstruct()--- */ /* Called from create_obstructions_from_gates(), this */ /* routine takes a grid point at (gridx, gridy) (physical */ /* position (dx, dy)) and an obstruction defined by the */ /* rectangle "ds", and sets flags and fills the Obsinfo */ /* array to reflect how the obstruction affects routing to */ /* the grid position. */ /*--------------------------------------------------------------*/ static void check_obstruct(int gridx, int gridy, DSEG ds, double dx, double dy, double delta) { ObsInfoRec *obsinfoptr; u_int *obsptr; u_int origmask; float distx, disty; obsptr = &(OBSVAL(gridx, gridy, ds->layer)); // Grid point is inside obstruction + halo. *obsptr |= NO_NET; // Completely inside obstruction? if (dy > ds->y1 && dy < ds->y2 && dx > ds->x1 && dx < ds->x2) *obsptr |= OBSTRUCT_MASK; else { // Make more detailed checks in each direction. If obstructions // are in multiple directions in X and Y, then mark both. The // Obsinfo array keeps information on one obstruction distance // in X and one in Y. If obstructions are on both X sides or // both Y sides, then the position is marked completely unroutable. // Note that an obstruction at a corner which blocks from two sides is // very different from two obstructions that block from the two sides. // As there is no mechanism in qrouter to offset a tap in both the // X and Y direction, the second case is unroutable. It needs to be // detected and marked blocked if so. Then all other code may assume // that any blockage marked from two directions is catecorner to the // grid position, and the tap may be moved in either direction to // avoid the obstruction. obsinfoptr = &(OBSINFO(gridx, gridy, ds->layer)); // Check for pre-existing conditions disty = obsinfoptr->yoffset; distx = obsinfoptr->xoffset; origmask = *obsptr & OBSTRUCT_MASK; if (dy <= ds->y1) { if ((origmask & ~OBSTRUCT_N) == 0) { if ((disty == 0) || ((ds->y1 - dy) < disty)) obsinfoptr->yoffset = ds->y1 - dy; *obsptr |= OBSTRUCT_N; } else *obsptr |= OBSTRUCT_MASK; } else if (dy >= ds->y2) { if ((origmask & ~OBSTRUCT_S) == 0) { if ((disty == 0) || ((dy - ds->y2) < disty)) obsinfoptr->yoffset = dy - ds->y2; *obsptr |= OBSTRUCT_S; } else *obsptr |= OBSTRUCT_MASK; } if (dx <= ds->x1) { if ((origmask & ~OBSTRUCT_E) == 0) { if ((distx == 0) || ((ds->x1 - dx) < distx)) obsinfoptr->xoffset = ds->x1 - dx; *obsptr |= OBSTRUCT_E; } else *obsptr |= OBSTRUCT_MASK; } else if (dx >= ds->x2) { if ((origmask & ~OBSTRUCT_W) == 0) { if ((distx == 0) || ((dx - ds->x2) < distx)) obsinfoptr->xoffset = dx - ds->x2; *obsptr |= OBSTRUCT_W; } else *obsptr |= OBSTRUCT_MASK; } } } /*--------------------------------------------------------------*/ /* Find the amount of clearance needed between an obstruction */ /* and a route track position. This takes into consideration */ /* whether the obstruction is wide or narrow metal, if the */ /* spacing rules are graded according to metal width, and if a */ /* via placed at the position is or is not symmetric in X and Y */ /* "orient" is the via orientation, of which there are four; */ /* however, as this only concerns the via bottom layer, the */ /* two orientations are represented by orient = 0 and 2. */ /*--------------------------------------------------------------*/ static double get_via_clear(int lay, int horiz, int orient, DSEG rect) { double vdelta, v2delta, mdelta, mwidth; vdelta = LefGetXYViaWidth(lay, lay, 1 - horiz, orient); if (lay > 0) { v2delta = LefGetXYViaWidth(lay - 1, lay, 1 - horiz, orient); if (v2delta > vdelta) vdelta = v2delta; } vdelta = vdelta / 2.0; // Spacing rule is determined by the minimum metal width, // either in X or Y, regardless of the position of the // metal being checked. mwidth = MIN(rect->x2 - rect->x1, rect->y2 - rect->y1); mdelta = LefGetRouteWideSpacing(lay, mwidth); return vdelta + mdelta; } /*--------------------------------------------------------------*/ /* Find the distance from an obstruction to a grid point, */ /* considering only routes which are placed at the position, */ /* not vias. */ /*--------------------------------------------------------------*/ static double get_route_clear(int lay, DSEG rect) { double rdelta, mdelta, mwidth; rdelta = LefGetRouteWidth(lay); rdelta = rdelta / 2.0; // Spacing rule is determined by the minimum metal width, // either in X or Y, regardless of the position of the // metal being checked. mwidth = MIN(rect->x2 - rect->x1, rect->y2 - rect->y1); mdelta = LefGetRouteWideSpacing(lay, mwidth); return rdelta + mdelta; } /*--------------------------------------------------------------*/ /* Truncate gates to the set of tracks. Warn about any gates */ /* with nodes that are clipped entirely outside the routing */ /* area. */ /*--------------------------------------------------------------*/ void clip_gate_taps(void) { NET net; NODE node; DPOINT dp, dpl; int i, lay; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; for (node = net->netnodes; node; node = node->next) { dpl = NULL; for (dp = (DPOINT)node->taps; dp; ) { lay = dp->layer; if (dp->gridx < 0 || dp->gridy < 0 || dp->gridx >= NumChannelsX || dp->gridy >= NumChannelsY) { Fprintf(stderr, "Tap of port of node %d of net %s" " is outside of route area\n", node->nodenum, node->netname); if (dpl == NULL) node->taps = dp->next; else dpl->next = dp->next; free(dp); dp = (dpl == NULL) ? node->taps : dpl->next; } else { dpl = dp; dp = dp->next; } } } } } /*--------------------------------------------------------------*/ /* create_obstructions_from_gates() */ /* */ /* Fills in the Obs[][] grid from obstructions that were */ /* defined for each macro in the technology LEF file and */ /* translated into a list of grid coordinates in each */ /* instance. */ /* */ /* Also, fills in the Obs[][] grid with obstructions that */ /* are defined by nodes of the gate that are unconnected in */ /* this netlist. */ /*--------------------------------------------------------------*/ void create_obstructions_from_gates(void) { GATE g; DSEG ds; int i, gridx, gridy, orient; double deltax, deltay, delta[MAX_LAYERS]; double dx, dy, deltaxy; // Give a single net number to all obstructions, over the range of the // number of known nets, so these positions cannot be routed through. // If a grid position is not wholly inside an obstruction, then we // maintain the direction of the nearest obstruction in Obs and the // distance to it in Obsinfo. This indicates that a route can avoid // the obstruction by moving away from it by the amount in Obsinfo // plus spacing clearance. If another obstruction is found that // prevents such a move, then all direction flags will be set, indicating // that the position is not routable under any condition. for (g = Nlgates; g; g = g->next) { orient = 0; for (ds = g->obs;; ds = ds->next) { // Run through ds list twice, checking against horizontally and // vertically oriented vias. if (ds == NULL) { if (orient == 2) break; else { orient = 2; ds = g->obs; if (ds == NULL) break; } } deltax = get_via_clear(ds->layer, 1, orient, ds); gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX) - 1; while (1) { dx = (gridx * PitchX) + Xlowerbound; if ((dx + EPS) > (ds->x2 + deltax) || gridx >= NumChannelsX) break; else if ((dx - EPS) > (ds->x1 - deltax) && gridx >= 0) { deltay = get_via_clear(ds->layer, 0, orient, ds); gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY) - 1; while (1) { dy = (gridy * PitchY) + Ylowerbound; if ((dy + EPS) > (ds->y2 + deltay) || gridy >= NumChannelsY) break; if ((dy - EPS) > (ds->y1 - deltay) && gridy >= 0) { double s, edist, xp, yp; // Check Euclidean distance measure s = LefGetRouteSpacing(ds->layer); if (dx < (ds->x1 + s - deltax)) { xp = dx + deltax - s; edist = (ds->x1 - xp) * (ds->x1 - xp); } else if (dx > (ds->x2 - s + deltax)) { xp = dx - deltax + s; edist = (xp - ds->x2) * (xp - ds->x2); } else edist = 0; if ((edist > 0) && (dy < (ds->y1 + s - deltay))) { yp = dy + deltay - s; edist += (ds->y1 - yp) * (ds->y1 - yp); } else if ((edist > 0) && (dy > (ds->y2 - s + deltay))) { yp = dy - deltay + s; edist += (yp - ds->y2) * (yp - ds->y2); } else edist = 0; if ((edist + EPS) < (s * s)) { check_obstruct(gridx, gridy, ds, dx, dy, s); if (is_testpoint(gridx, gridy, g, -1, ds) != NULL) Fprintf(stderr, " Position blocked by gate obstruction.\n"); } else edist = 0; // diagnostic break } gridy++; } } gridx++; } } for (i = 0; i < g->nodes; i++) { if (g->netnum[i] == 0) { /* Unconnected node */ // Diagnostic, and power bus handling if (g->node[i]) { // Should we flag a warning if we see something that looks // like a power or ground net here? if (Verbose > 1) Fprintf(stdout, "Gate instance %s unconnected node %s\n", g->gatename, g->node[i]); } else { if (Verbose > 1) Fprintf(stdout, "Gate instance %s unconnected node (%d)\n", g->gatename, i); } for (ds = g->taps[i]; ds; ds = ds->next) { deltax = get_via_clear(ds->layer, 1, orient, ds); gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX) - 1; while (1) { dx = (gridx * PitchX) + Xlowerbound; if (dx > (ds->x2 + deltax) || gridx >= NumChannelsX) break; else if (dx >= (ds->x1 - deltax) && gridx >= 0) { deltay = get_via_clear(ds->layer, 0, orient, ds); gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY) - 1; while (1) { dy = (gridy * PitchY) + Ylowerbound; if ((dy + EPS) > (ds->y2 + deltay) || gridy >= NumChannelsY) break; if ((dy - EPS) >= (ds->y1 - deltay) && gridy >= 0) { double s, edist = 0.0, xp, yp; // Check Euclidean distance measure s = LefGetRouteSpacing(ds->layer); if (dx < (ds->x1 + s - deltax)) { xp = dx + deltax - s; edist += (ds->x1 - xp) * (ds->x1 - xp); } else if (dx > (ds->x2 - s + deltax)) { xp = dx - deltax + s; edist += (xp - ds->x2) * (xp - ds->x2); } else edist = 0; if ((edist > 0) && (dy < (ds->y1 + s - deltay))) { yp = dy + deltay - s; edist += (ds->y1 - yp) * (ds->y1 - yp); } else if ((edist > 0) && (dy > (ds->y2 - s + deltay))) { yp = dy - deltay + s; edist += (yp - ds->y2) * (yp - ds->y2); } else edist = 0; if ((edist + EPS) < (s * s)) { check_obstruct(gridx, gridy, ds, dx, dy, s); if (is_testpoint(gridx, gridy, g, i, ds) != NULL) Fprintf(stderr, " Position blocked by unused" " gate pin.\n"); } } gridy++; } } gridx++; } } } } } // Create additional obstructions from the UserObs list // These obstructions are not considered to be metal layers, // so we don't compute a distance measure. However, we need // to compute a boundary of 1/2 route width to avoid having // the route overlapping the obstruction area. for (i = 0; i < Num_layers; i++) { delta[i] = LefGetRouteWidth(i) / 2.0; } for (ds = UserObs; ds; ds = ds->next) { if (ds->layer >= Num_layers) continue; gridx = (int)((ds->x1 - Xlowerbound - delta[ds->layer]) / PitchX) - 1; while (1) { dx = (gridx * PitchX) + Xlowerbound; if (dx > (ds->x2 + delta[ds->layer]) || gridx >= NumChannelsX) break; else if (dx >= (ds->x1 - delta[ds->layer]) && gridx >= 0) { gridy = (int)((ds->y1 - Ylowerbound - delta[ds->layer]) / PitchY) - 1; while (1) { dy = (gridy * PitchY) + Ylowerbound; if (dy > (ds->y2 + delta[ds->layer]) || gridy >= NumChannelsY) break; if (dy >= (ds->y1 - delta[ds->layer]) && gridy >= 0) { check_obstruct(gridx, gridy, ds, dx, dy, delta[i]); if (is_testpoint(gridx, gridy, NULL, -1, ds) != NULL) Fprintf(stderr, " Position blocked by defined obstruction.\n"); } gridy++; } } gridx++; } } } /*--------------------------------------------------------------*/ /* expand_tap_geometry() */ /* */ /* For each rectangle defining part of a gate terminal, */ /* search the surrounding terminal geometry. If the rectangle */ /* can expand in any direction, then allow it to grow to the */ /* maximum size. This generates overlapping geometry for each */ /* terminal, but avoids bad results for determining how to */ /* route to a terminal point if the terminal is broken up into */ /* numerous nonoverlapping rectangles. */ /* */ /* Note that this is not foolproof. It also needs a number of */ /* enhancements. For example, to expand east, other geometry */ /* should be looked at in order of increasing left edge X */ /* value, and so forth. */ /*--------------------------------------------------------------*/ void expand_tap_geometry(void) { DSEG ds, ds2; GATE g; int i; u_char expanded; for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] == 0) continue; if (g->taps == NULL) continue; for (ds = g->taps[i]; ds; ds = ds->next) { expanded = TRUE; while (expanded == TRUE) { expanded = FALSE; for (ds2 = g->taps[i]; ds2; ds2 = ds2->next) { if (ds == ds2) continue; if (ds->layer != ds2->layer) continue; if ((ds2->y1 <= ds->y1) && (ds2->y2 >= ds->y2)) { // Expand east if ((ds2->x1 > ds->x1) && (ds2->x1 <= ds->x2)) if (ds->x2 < ds2->x2) { ds->x2 = ds2->x2; expanded = TRUE; } // Expand west if ((ds2->x2 < ds->x2) && (ds2->x2 >= ds->x1)) if (ds->x1 > ds2->x1) { ds->x1 = ds2->x1; expanded = TRUE; } } if ((ds2->x1 <= ds->x1) && (ds2->x2 >= ds->x2)) { // Expand north if ((ds2->y1 > ds->y1) && (ds2->y1 <= ds->y2)) if (ds->y2 < ds2->y2) { ds->y2 = ds2->y2; expanded = TRUE; } // Expand south if ((ds2->y2 < ds->y2) && (ds2->y2 >= ds->y1)) if (ds->y1 > ds2->y1) { ds->y1 = ds2->y1; expanded = TRUE; } } } } } } } } /*--------------------------------------------------------------*/ /* is_testpoint() */ /* */ /* Check if a grid position is on the testpoint list. If so, */ /* return the pointer to the testpoint structure. */ /*--------------------------------------------------------------*/ DPOINT is_testpoint(int gridx, int gridy, GATE g, int nidx, DSEG ds) { int layer; DPOINT trypoint; NODE node = NULL, onode; NODEINFO lnode; layer = ds->layer; for (trypoint = testpoint; trypoint; trypoint = trypoint->next) { if (trypoint->gridx == gridx && trypoint->gridy == gridy && trypoint->layer == layer) { Fprintf(stderr, "Watchpoint (%g, %g) layer %d" " grid (%d, %d):\n", trypoint->x, trypoint->y, trypoint->layer, trypoint->gridx, trypoint->gridy); if (g != NULL) { Fprintf(stderr, " Gate instance = \"%s\"\n", g->gatename); if (g->gatetype) Fprintf(stderr, " Gate cell = \"%s\"\n", g->gatetype->gatename); if (nidx >= 0) { Fprintf(stderr, " Gate pin = \"%s\"\n", g->node[nidx]); Fprintf(stderr, " Pin geometry = (%g, %g) to (%g, %g)\n", ds->x1, ds->y1, ds->x2, ds->y2); node = g->noderec[nidx]; Fprintf(stderr, " Connects to net \"%s\"\n", node->netname); } } if (nidx < 0) { Fprintf(stderr, " Obstruction geometry = (%g, %g) to (%g, %g)\n", ds->x1, ds->y1, ds->x2, ds->y2); } lnode = NODEIPTR(gridx, gridy, layer); if (lnode != NULL) { onode = lnode->nodesav; if (onode != NULL) { if (node && (onode->netnum != node->netnum)) { if (onode->netname) Fprintf(stderr, " Position was previously assigned" " to node %s on net %s\n", print_node_name(onode), onode->netname); else Fprintf(stderr, " Position was previously assigned" " to node %s on different net\n", print_node_name(onode)); } else { Fprintf(stderr, " Position was previously assigned" " to node %s on the same net\n", print_node_name(onode)); } } else Fprintf(stderr, " Position was previously assigned" " to a node that has been disabled.\n"); } else Fprintf(stderr, " Position was not previously assigned" " to a node\n"); Fprintf(stderr, "Disabled position because:\n"); return trypoint; } } return NULL; } /*--------------------------------------------------------------*/ /* create_obstructions_inside_nodes() */ /* */ /* Fills in the Obs[][] grid from the position of each node */ /* (net terminal), which may have multiple unconnected */ /* positions. */ /* */ /* Also fills in the Nodeinfo.nodeloc[] grid with the node */ /* number, which causes the router to put a premium on */ /* routing other nets over or under this position, to */ /* discourage boxing in a pin position and making it */ /* unroutable. */ /* */ /* This routine is split into two passes. This pass adds */ /* information for points inside node regions. */ /* */ /* ARGS: none. */ /* RETURNS: nothing */ /* SIDE EFFECTS: none */ /* AUTHOR: Tim Edwards, June 2011, based on code by Steve */ /* Beccue. */ /*--------------------------------------------------------------*/ void create_obstructions_inside_nodes(void) { NODE node; NODEINFO lnode; GATE g; DSEG ds; DPOINT tpoint; u_int dir, mask, k; int i, gridx, gridy; double dx, dy, xdist, vwx, vwy; u_char o0okay, o2okay, duplicate; float dist; // For each node terminal (gate pin), mark each grid position with the // net number. This overrides any obstruction that may be placed at that // point. // For each pin position, we also find the "keepout" area around the // pin where we may not place an unrelated route. For this, we use a // flag bit, so that the position can be ignored when routing the net // associated with the pin. Normal obstructions take precedence. for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] != 0) { // Get the node record associated with this pin. node = g->noderec[i]; if (node == NULL) continue; // First mark all areas inside node geometry boundary. for (ds = g->taps[i]; ds; ds = ds->next) { gridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1; if (gridx < 0) gridx = 0; while (1) { dx = (gridx * PitchX) + Xlowerbound; if (dx > ds->x2 || gridx >= NumChannelsX) break; else if (dx >= ds->x1 && gridx >= 0) { gridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1; if (gridy < 0) gridy = 0; while (1) { dy = (gridy * PitchY) + Ylowerbound; if (dy > ds->y2 || gridy >= NumChannelsY) break; // Area inside defined pin geometry if (dy > ds->y1 && gridy >= 0) { int orignet = OBSVAL(gridx, gridy, ds->layer); duplicate = FALSE; lnode = NULL; if ((orignet & ROUTED_NET_MASK & ~ROUTED_NET) == (u_int)node->netnum) { // Duplicate tap point, or pre-existing route. // Re-process carefully. Check for alternate // restrictions. This geometry may be better // than the last one(s) processed. if (((lnode = NODEIPTR(gridx, gridy, ds->layer)) != NULL) && (lnode->nodeloc != NULL)) duplicate = TRUE; } else if (!(orignet & NO_NET) && ((orignet & ROUTED_NET_MASK) != (u_int)0)) { // Net was assigned to other net, but is inside // this pin's geometry. Declare point to be // unroutable, as it is too close to both pins. // NOTE: This is a conservative rule and could // potentially make a pin unroutable. // Another note: By setting Obs[] to // OBSTRUCT_MASK as well as NO_NET, we ensure // that it falls through on all subsequent // processing. if (is_testpoint(gridx, gridy, g, i, ds) != NULL) Fprintf(stderr, " Position is inside pin but cannot " "be routed without causing violation.\n"); disable_gridpos(gridx, gridy, ds->layer); gridy++; continue; } if (!(orignet & NO_NET)) { // A grid point that is within 1/2 route width // of a tap rectangle corner can violate metal // width rules, and so should declare a stub. mask = 0; dir = 0; dist = 0.0; xdist = 0.5 * LefGetRouteWidth(ds->layer); if (dx >= ds->x2 - xdist) { if (dy > ds->y2 - xdist + EPS) { // Check northeast corner if ((ds->x2 - dx) > (ds->y2 - dy)) { // West-pointing stub mask = STUBROUTE; dir = NI_STUB_EW; dist = ds->x2 - dx - 2.0 * xdist; } else { // South-pointing stub mask = STUBROUTE; dir = NI_STUB_NS; dist = ds->y2 - dy - 2.0 * xdist; } } else if (dy < ds->y1 + xdist - EPS) { // Check southeast corner if ((ds->x2 - dx) > (dy - ds->y1)) { // West-pointing stub mask = STUBROUTE; dir = NI_STUB_EW; dist = ds->x2 - dx - 2.0 * xdist; } else { // North-pointing stub mask = STUBROUTE; dir = NI_STUB_NS; dist = ds->y1 - dy + 2.0 * xdist; } } } else if (dx <= ds->x1 + xdist) { if (dy > ds->y2 - xdist + EPS) { // Check northwest corner if ((dx - ds->x1) > (ds->y2 - dy)) { // East-pointing stub mask = STUBROUTE; dir = NI_STUB_EW; dist = ds->x1 - dx + 2.0 * xdist; } else { // South-pointing stub mask = STUBROUTE; dir = NI_STUB_NS; dist = ds->y2 - dy - 2.0 * xdist; } } else if (dy < ds->y1 + xdist - EPS) { // Check southwest corner if ((dx - ds->x2) > (dy - ds->y1)) { // East-pointing stub mask = STUBROUTE; dir = NI_STUB_EW; dist = ds->x1 - dx + 2.0 * xdist; } else { // North-pointing stub mask = STUBROUTE; dir = NI_STUB_NS; dist = ds->y1 - dy + 2.0 * xdist; } } } if (!duplicate) { OBSVAL(gridx, gridy, ds->layer) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | (u_int)node->netnum | mask; if (!lnode) lnode = SetNodeinfo(gridx, gridy, ds->layer, node); lnode->nodeloc = node; lnode->nodesav = node; lnode->stub = dist; lnode->flags |= dir; } /* If a horizontal or vertical via fits completely */ /* inside the pin but the other orientation */ /* doesn't, then mark as prohibiting the other */ /* orientation. */ vwx = LefGetXYViaWidth(ds->layer, ds->layer, 0, 0) / 2.0; vwy = LefGetXYViaWidth(ds->layer, ds->layer, 1, 0) / 2.0; if ((dx - vwx > ds->x1 - EPS) && (dx + vwx < ds->x2 + EPS) && (dy - vwy > ds->y1 - EPS) && (dy + vwy < ds->y2 + EPS)) { o0okay = TRUE; } else { o0okay = FALSE; } vwx = LefGetXYViaWidth(ds->layer, ds->layer, 0, 2) / 2.0; vwy = LefGetXYViaWidth(ds->layer, ds->layer, 1, 2) / 2.0; if ((dx - vwx > ds->x1 - EPS) && (dx + vwx < ds->x2 + EPS) && (dy - vwy > ds->y1 - EPS) && (dy + vwy < ds->y2 + EPS)) { o2okay = TRUE; } else { o2okay = FALSE; } if ((o0okay == TRUE) && (o2okay == FALSE)) lnode->flags |= NI_NO_VIAY; else if ((o0okay == FALSE) && (o2okay == TRUE)) lnode->flags |= NI_NO_VIAX; } else if ((orignet & NO_NET) && ((orignet & OBSTRUCT_MASK) != OBSTRUCT_MASK)) { /* Handled on next pass */ } // Check that we have not created a PINOBSTRUCT // route directly over this point. if ((!duplicate) && (ds->layer < Num_layers - 1)) { k = OBSVAL(gridx, gridy, ds->layer + 1); if (k & PINOBSTRUCTMASK) { if ((k & ROUTED_NET_MASK) != (u_int)node->netnum) { OBSVAL(gridx, gridy, ds->layer + 1) = NO_NET; FreeNodeinfo(gridx, gridy, ds->layer + 1); } } } } gridy++; } } gridx++; } } } } } } /* void create_obstructions_inside_nodes( void ) */ /*--------------------------------------------------------------*/ /* create_obstructions_outside_nodes() */ /* */ /* Fills in the Obs[][] grid from the position of each node */ /* (net terminal), which may have multiple unconnected */ /* positions. */ /* */ /* Also fills in the Nodeinfo.nodeloc[] grid with the node */ /* number, which causes the router to put a premium on */ /* routing other nets over or under this position, to */ /* discourage boxing in a pin position and making it */ /* unroutable. */ /* */ /* This routine is split into two passes. This pass adds */ /* information for points outside node regions but close */ /* enough to interact with the node. */ /* */ /* ARGS: none. */ /* RETURNS: nothing */ /* SIDE EFFECTS: none */ /* AUTHOR: Tim Edwards, June 2011, based on code by Steve */ /* Beccue. */ /*--------------------------------------------------------------*/ void create_obstructions_outside_nodes(void) { NODE node, n2; NODEINFO lnode; GATE g; DSEG ds; DPOINT tpoint; u_int dir, mask, k; int i, gridx, gridy, orient; double dx, dy, xdist, deltax, deltay; float dist; // For each node terminal (gate pin), mark each grid position with the // net number. This overrides any obstruction that may be placed at that // point. // For each pin position, we also find the "keepout" area around the // pin where we may not place an unrelated route. For this, we use a // flag bit, so that the position can be ignored when routing the net // associated with the pin. Normal obstructions take precedence. for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] != 0) { // Get the node record associated with this pin. node = g->noderec[i]; if (node == NULL) continue; // Repeat this whole exercise for areas in the halo outside // the node geometry. We have to do this after enumerating // all inside areas because the tap rectangles often overlap, // and one rectangle's halo may be inside another tap. orient = 0; for (ds = g->taps[i];; ds = ds->next) { if (ds == NULL) { if (orient == 2) break; else { orient = 2; ds = g->taps[i]; if (ds == NULL) break; } } // Note: Should be handling get_route_clear as a less // restrictive case, as was done above. deltax = get_via_clear(ds->layer, 1, orient, ds); gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX) - 1; if (gridx < 0) gridx = 0; while (1) { dx = (gridx * PitchX) + Xlowerbound; // Check if obstruction position is too close for // a via in either orientation. The position can // be marked as prohibiting one orientation or the // other. if (((dx + EPS) > (ds->x2 + deltax)) || (gridx >= NumChannelsX)) break; else if ((dx - EPS) > (ds->x1 - deltax) && gridx >= 0) { deltay = get_via_clear(ds->layer, 0, orient, ds); gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY) - 1; if (gridy < 0) gridy = 0; while (1) { dy = (gridy * PitchY) + Ylowerbound; if (((dy + EPS) > (ds->y2 + deltay)) || (gridy >= NumChannelsY)) break; // 2nd pass on area inside defined pin geometry, // allowing terminal connections to be made using // an offset tap, where possible. if ((dy >= ds->y1 && gridy >= 0) && (dx >= ds->x1) && (dy <= ds->y2) && (dx <= ds->x2)) { int orignet = OBSVAL(gridx, gridy, ds->layer); if ((orignet & ROUTED_NET_MASK) == (u_int)node->netnum) { // Duplicate tap point. Don't re-process it. gridy++; continue; } if (!(orignet & NO_NET) && ((orignet & ROUTED_NET_MASK) != (u_int)0)) { /* Do nothing; previously handled */ } else if ((orignet & NO_NET) && ((orignet & OBSTRUCT_MASK) != OBSTRUCT_MASK)) { double sdistxx, sdistxy, sdistyx, sdistyy; float offdx, offdy; ObsInfoRec *offdptr; // width of horizontal via sdistxx = LefGetXYViaWidth(ds->layer, ds->layer, 0, 0) / 2.0 + LefGetRouteSpacing(ds->layer); // width of vertical via sdistxy = LefGetXYViaWidth(ds->layer, ds->layer, 0, 2) / 2.0 + LefGetRouteSpacing(ds->layer); // height of horizontal via sdistyx = LefGetXYViaWidth(ds->layer, ds->layer, 1, 0) / 2.0 + LefGetRouteSpacing(ds->layer); // height of vertical via sdistyy = LefGetXYViaWidth(ds->layer, ds->layer, 1, 2) / 2.0 + LefGetRouteSpacing(ds->layer); // Define a maximum offset we can have in X or // Y above which the placement of a via will // cause a DRC violation with a wire in the // adjacent route track in the direction of the // offset. int maxerr = 0; // If a cell is positioned off-grid, then a grid // point may be inside a pin and still be unroutable. // The Obsinfo[] array tells where an obstruction is, // if there was only one obstruction in one direction // blocking the grid point. If so, then we set the // Nodeinfo.stub[] distance to move the tap away from // the obstruction to resolve the DRC error. // Make sure we have marked this as a node. lnode = SetNodeinfo(gridx, gridy, ds->layer, node); lnode->nodeloc = node; lnode->nodesav = node; OBSVAL(gridx, gridy, ds->layer) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | (u_int)node->netnum; offdptr = &(OBSINFO(gridx, gridy, ds->layer)); offdx = offdptr->xoffset; offdy = offdptr->yoffset; // If obstruction is on a corner (NE, SW, etc.) then // only look at the case with the smaller offset // required. if ((orignet & (OBSTRUCT_N | OBSTRUCT_S)) && (orignet & (OBSTRUCT_E | OBSTRUCT_W))) { if (offdy > offdx) orignet &= ~(OBSTRUCT_E | OBSTRUCT_W); else orignet &= ~(OBSTRUCT_N | OBSTRUCT_S); } if (orignet & OBSTRUCT_N) { if (sdistyy - offdy > EPS) { lnode->flags |= NI_NO_VIAY; if (sdistyx - offdy > EPS) { /* Cannot route cleanly, so use offset */ if (offdy - sdistyx > PitchY / 2.0) /* Offset distance is too large */ maxerr = 1; else { OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP; lnode->offset = offdy - sdistyx; lnode->flags |= NI_OFFSET_NS; /* If position above has obstruction, then */ /* add up/down block to prevent vias. */ if ((ds->layer < Num_layers - 1) && (gridy > 0) && (OBSVAL(gridx, gridy - 1, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } } } } } else if (orignet & OBSTRUCT_S) { if (sdistyy - offdy > EPS) { lnode->flags |= NI_NO_VIAY; if (sdistyx - offdy > EPS) { if (offdy - sdistyx > PitchY / 2.0) /* Offset distance is too large */ maxerr = 1; else { OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP; lnode->offset = sdistyx - offdy; lnode->flags |= NI_OFFSET_NS; /* If position above has obstruction, then */ /* add up/down block to prevent vias. */ if ((ds->layer < Num_layers - 1) && (gridy < NumChannelsY - 1) && (OBSVAL(gridx, gridy + 1, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } } } } } else if (orignet & OBSTRUCT_E) { if (sdistxx - offdx > EPS) { lnode->flags |= NI_NO_VIAX; if (sdistxy - offdx > EPS) { if (offdx - sdistxy > PitchX / 2.0) /* Offset distance is too large */ maxerr = 1; else { OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP; lnode->offset = offdx - sdistxy; lnode->flags |= NI_OFFSET_EW; /* If position above has obstruction, then */ /* add up/down block to prevent vias. */ if ((ds->layer < Num_layers - 1) && (gridx > 0) && (OBSVAL(gridx - 1, gridy, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } } } } } else if (orignet & OBSTRUCT_W) { if (sdistxx - offdx > EPS) { lnode->flags |= NI_NO_VIAX; if (sdistxy - offdx > EPS) { if (offdx - sdistxy > PitchX / 2.0) /* Offset distance is too large */ maxerr = 1; else { OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP; lnode->offset = sdistxy - offdx; lnode->flags |= NI_OFFSET_EW; /* If position above has obstruction, then */ /* add up/down block to prevent vias. */ if ((ds->layer < Num_layers - 1) && (gridx < NumChannelsX - 1) && (OBSVAL(gridx + 1, gridy, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } } } } } if (maxerr == 1) { if (is_testpoint(gridx, gridy, g, i, ds) != NULL) Fprintf(stderr, "Attempted to clear obstruction with" " offset, but offset is more than 1/2" " route pitch.\n"); disable_gridpos(gridx, gridy, ds->layer); } // Diagnostic else if (Verbose > 3) Fprintf(stderr, "Port overlaps obstruction" " at grid %d %d, position %g %g\n", gridx, gridy, dx, dy); } } if ((dy - EPS) > (ds->y1 - deltay) && gridy >= 0) { double s, edist, xp, yp; unsigned char epass = 0; // Area inside halo around defined pin geometry. // Exclude areas already processed (areas inside // some pin geometry have been marked with netnum) // Also check that we are not about to define a // route position for a pin on a layer above 0 that // blocks a pin underneath it. // Flag positions that pass a Euclidean distance check. // epass = 1 indicates that position clears a // Euclidean distance measurement. s = LefGetRouteSpacing(ds->layer); if (dx < (ds->x1 + s - deltax)) { xp = dx + deltax - s; edist = (ds->x1 - xp) * (ds->x1 - xp); } else if (dx > (ds->x2 - s + deltax)) { xp = dx - deltax + s; edist = (xp - ds->x2) * (xp - ds->x2); } else edist = 0; if ((edist > 0) && (dy < (ds->y1 + s - deltay))) { yp = dy + deltay - s; edist += (ds->y1 - yp) * (ds->y1 - yp); } else if ((edist > 0) && (dy > (ds->y2 - s + deltay))) { yp = dy - deltay + s; edist += (yp - ds->y2) * (yp - ds->y2); } else edist = 0; if ((edist + EPS) > (s * s)) epass = 1; xdist = 0.5 * LefGetRouteWidth(ds->layer); n2 = NULL; if (ds->layer > 0) { lnode = NODEIPTR(gridx, gridy, ds->layer - 1); n2 = (lnode) ? lnode->nodeloc : NULL; } if (n2 == NULL) { lnode = NODEIPTR(gridx, gridy, ds->layer); n2 = (lnode) ? lnode->nodeloc : NULL; } else { // Watch out for the case where a tap crosses // over a different tap. Don't treat the tap // on top as if it is not there! NODE n3; lnode = NODEIPTR(gridx, gridy, ds->layer); n3 = (lnode) ? lnode->nodeloc : NULL; if (n3 != NULL && n3 != node) n2 = n3; } // Ignore my own node. if (n2 == node) n2 = NULL; k = OBSVAL(gridx, gridy, ds->layer); // In case of a port that is inaccessible from a grid // point, or not completely overlapping it, the // stub information will show how to adjust the // route position to cleanly attach to the port. mask = STUBROUTE; dir = NI_STUB_NS | NI_STUB_EW; dist = 0.0; if (((k & ROUTED_NET_MASK) != (u_int)node->netnum) && (n2 == NULL)) { if ((k & OBSTRUCT_MASK) != 0) { ObsInfoRec *obsinfoptr; float sdistx, sdisty; obsinfoptr = &(OBSINFO(gridx, gridy, ds->layer)); sdistx = obsinfoptr->xoffset; sdisty = obsinfoptr->yoffset; // If the point is marked as close to an // obstruction, we can declare this an // offset tap if we are not on a corner. // Because we cannot define both an offset // and a stub simultaneously, if the distance // to clear the obstruction does not make the // route reach the tap, then we mark the grid // position as unroutable. if (dy >= (ds->y1 - xdist) && dy <= (ds->y2 + xdist)) { if ((dx >= ds->x2) && ((k & OBSTRUCT_MASK) == OBSTRUCT_E)) { dist = sdistx - LefGetRouteKeepout(ds->layer); if ((dx - ds->x2 + dist) < xdist) { mask = OFFSET_TAP; dir = NI_OFFSET_EW; if ((ds->layer < Num_layers - 1) && (gridx > 0) && (OBSVAL(gridx - 1, gridy, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } } } else if ((dx <= ds->x1) && ((k & OBSTRUCT_MASK) == OBSTRUCT_W)) { dist = LefGetRouteKeepout(ds->layer) - sdistx; if ((ds->x1 - dx - dist) < xdist) { mask = OFFSET_TAP; dir = NI_OFFSET_EW; if ((ds->layer < Num_layers - 1) && gridx < (NumChannelsX - 1) && (OBSVAL(gridx + 1, gridy, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } } } } if (dx >= (ds->x1 - xdist) && dx <= (ds->x2 + xdist)) { if ((dy >= ds->y2) && ((k & OBSTRUCT_MASK) == OBSTRUCT_N)) { dist = sdisty - LefGetRouteKeepout(ds->layer); if ((dy - ds->y2 + dist) < xdist) { mask = OFFSET_TAP; dir = NI_OFFSET_NS; if ((ds->layer < Num_layers - 1) && gridy < (NumChannelsY - 1) && (OBSVAL(gridx, gridy - 1, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } } } else if ((dy <= ds->y1) && ((k & OBSTRUCT_MASK) == OBSTRUCT_S)) { dist = LefGetRouteKeepout(ds->layer) - sdisty; if ((ds->y1 - dy - dist) < xdist) { mask = OFFSET_TAP; dir = NI_OFFSET_NS; if ((ds->layer < Num_layers - 1) && (gridy > 0) && (OBSVAL(gridx, gridy + 1, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } } } } // Otherwise, dir is left as NI_STUB_MASK } else { // Cleanly unobstructed area. Define stub // route from point to tap, with a route width // overlap if necessary to avoid a DRC width // violation. if ((dx >= ds->x2) && ((dx - ds->x2) > (dy - ds->y2)) && ((dx - ds->x2) > (ds->y1 - dy))) { // West-pointing stub if ((dy - ds->y2) <= xdist && (ds->y1 - dy) <= xdist) { // Within reach of tap rectangle mask = STUBROUTE; dir = NI_STUB_EW; dist = ds->x2 - dx; if (dy < (ds->y2 - xdist) && dy > (ds->y1 + xdist)) { if (dx < ds->x2 + xdist) dist = 0.0; } else { dist -= 2.0 * xdist; } } } else if ((dx <= ds->x1) && ((ds->x1 - dx) > (dy - ds->y2)) && ((ds->x1 - dx) > (ds->y1 - dy))) { // East-pointing stub if ((dy - ds->y2) <= xdist && (ds->y1 - dy) <= xdist) { // Within reach of tap rectangle mask = STUBROUTE; dir = NI_STUB_EW; dist = ds->x1 - dx; if (dy < (ds->y2 - xdist) && dy > (ds->y1 + xdist)) { if (dx > ds->x1 - xdist) dist = 0.0; } else { dist += 2.0 * xdist; } } } else if ((dy >= ds->y2) && ((dy - ds->y2) > (dx - ds->x2)) && ((dy - ds->y2) > (ds->x1 - dx))) { // South-pointing stub if ((dx - ds->x2) <= xdist && (ds->x1 - dx) <= xdist) { // Within reach of tap rectangle mask = STUBROUTE; dir = NI_STUB_NS; dist = ds->y2 - dy; if (dx < (ds->x2 - xdist) && dx > (ds->x1 + xdist)) { if (dy < ds->y2 + xdist) dist = 0.0; } else { dist -= 2.0 * xdist; } } } else if ((dy <= ds->y1) && ((ds->y1 - dy) > (dx - ds->x2)) && ((ds->y1 - dy) > (ds->x1 - dx))) { // North-pointing stub if ((dx - ds->x2) <= xdist && (ds->x1 - dx) <= xdist) { // Within reach of tap rectangle mask = STUBROUTE; dir = NI_STUB_NS; dist = ds->y1 - dy; if (dx < (ds->x2 - xdist) && dx > (ds->x1 + xdist)) { if (dy > ds->y1 - xdist) dist = 0.0; } else { dist += 2.0 * xdist; } } } if ((mask == STUBROUTE) && (dir == NI_STUB_MASK)) { // Outside of pin at a corner. First, if one // direction is too far away to connect to a // pin, then we must route the other direction. if (dx < ds->x1 - xdist || dx > ds->x2 + xdist) { if (dy >= ds->y1 - xdist && dy <= ds->y2 + xdist) { mask = STUBROUTE; dir = NI_STUB_EW; dist = (float)(((ds->x1 + ds->x2) / 2.0) - dx); } } else if (dy < ds->y1 - xdist || dy > ds->y2 + xdist) { mask = STUBROUTE; dir = NI_STUB_NS; dist = (float)(((ds->y1 + ds->y2) / 2.0) - dy); } // Otherwise we are too far away at a diagonal // to reach the pin by moving in any single // direction. To be pedantic, we could define // some jogged stub, but for now, we just call // the point unroutable (leave dir = NI_STUB_MASK) // To do: Apply offset + stub } } // Additional checks on stub routes // Stub distances of <= 1/2 route width are // unnecessary, so don't create them. if (mask == STUBROUTE && (dir == NI_STUB_NS || dir == NI_STUB_EW) && (fabs(dist) < (xdist + EPS))) { mask = 0; dir = 0; dist = 0.0; } else if (mask == STUBROUTE && (dir == NI_STUB_NS || dir == NI_STUB_EW)) { struct dseg_ de; DSEG ds2; u_char errbox = TRUE; // Additional check: Sometimes the above // checks put stub routes where they are // not needed because the stub is completely // covered by other tap geometry. Take the // stub area and remove parts covered by // other tap rectangles. If the entire // stub is gone, then don't put a stub here. if (dir == NI_STUB_NS) { de.x1 = dx - xdist; de.x2 = dx + xdist; if (dist > 0) { de.y1 = dy + xdist; de.y2 = dy + dist; } else { de.y1 = dy + dist; de.y2 = dy - xdist; } } if (dir == NI_STUB_EW) { de.y1 = dy - xdist; de.y2 = dy + xdist; if (dist > 0) { de.x1 = dx + xdist; de.x2 = dx + dist; } else { de.x1 = dx + dist; de.x2 = dx - xdist; } } // For any tap that overlaps the // stub extension box, remove that // part of the box. for (ds2 = g->taps[i]; ds2; ds2 = ds2->next) { if (ds2 == ds) continue; if (ds2->layer != ds->layer) continue; if (ds2->x1 <= de.x1 && ds2->x2 >= de.x2 && ds2->y1 <= de.y1 && ds2->y2 >= de.y2) { errbox = FALSE; // Completely covered break; } // Look for partial coverage. Note that any // change can cause a change in the original // two conditionals, so we have to keep // evaluating those conditionals. // ds2 covers left side of de if (ds2->x1 < de.x2 && ds2->x2 > de.x1 + EPS) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) if (ds2->x1 < de.x1 + EPS && ds2->x2 < de.x2 - EPS) { de.x1 = ds2->x2; if (de.x1 > de.x2 - EPS) errbox = FALSE; } // ds2 covers right side of de if (ds2->x1 < de.x2 - EPS && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) if (ds2->x2 > de.x2 - EPS && ds2->x1 > de.x1 + EPS) { de.x2 = ds2->x1; if (de.x2 < de.x1 + EPS) errbox = FALSE; } // ds2 covers bottom side of de if (ds2->y1 < de.y2 && ds2->y2 > de.y1 + EPS) if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y1 + EPS && ds2->y2 < de.y2 - EPS) { de.y1 = ds2->y2; if (de.y1 > de.y2 - EPS) errbox = FALSE; } // ds2 covers top side of de if (ds2->y1 < de.y2 - EPS && ds2->y2 > de.y1) if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y2 > de.y2 - EPS && ds2->y1 > de.y1 + EPS) { de.y2 = ds2->y1; if (de.y2 < de.y1 + EPS) errbox = FALSE; } } // If nothing is left of the stub box, // then remove the stub. if (errbox == FALSE) { mask = 0; dir = 0; dist = 0; } } lnode = SetNodeinfo(gridx, gridy, ds->layer, node); lnode->nodeloc = node; lnode->nodesav = node; if ((k < Numnets) && (dir != NI_STUB_MASK)) { OBSVAL(gridx, gridy, ds->layer) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | (u_int)g->netnum[i] | mask; lnode->flags |= dir; } else if ((OBSVAL(gridx, gridy, ds->layer) & NO_NET) != 0) { // Keep showing an obstruction, but add the // direction info and log the stub distance. OBSVAL(gridx, gridy, ds->layer) |= mask; lnode->flags |= dir; } else { OBSVAL(gridx, gridy, ds->layer) |= (mask | (g->netnum[i] & ROUTED_NET_MASK)); lnode->flags |= dir; } if ((mask & STUBROUTE) != 0) { lnode->stub = dist; } else if (((mask & OFFSET_TAP) != 0) || (dist != 0.0)) { lnode->offset = dist; } // Remove entries with NI_STUB_MASK---these // are blocked-in taps that are not routable // without causing DRC violations (formerly // called STUBROUTE_X). if (dir == NI_STUB_MASK) { if (is_testpoint(gridx, gridy, g, i, ds) != NULL) Fprintf(stderr, "Tap point is blocked in " "and cannot be routed without causing " "DRC violations.\n"); disable_gridpos(gridx, gridy, ds->layer); } } else if (epass == 0) { // Position fails euclidean distance check int othernet = (k & ROUTED_NET_MASK); if (othernet != 0 && othernet != (u_int)node->netnum) { // This location is too close to two different // node terminals and should not be used // If there is a stub, then we can't specify // an offset tap, so just disable it. If // there is already an offset, then just // disable it. Otherwise, check if othernet // could be routed using a tap offset. // To avoid having to check all nearby // geometry, place a restriction that the // next grid point in the direction of the // offset must be free (not a tap point of // any net, including this one). That is // still "more restrictive than necessary", // but since the alternative is an efficient // area search for interacting geometry, this // restriction will stand until an example // comes along that requires the detailed // search. // Such an example has come along, leading to // an additional relaxation allowing an offset // if the neighboring channel does not have a // node record. This will probably need // revisiting. if ((k & PINOBSTRUCTMASK) != 0) { if (is_testpoint(gridx, gridy, g, i, ds) != NULL) { if (k & STUBROUTE) Fprintf(stderr, "Position marked as a " "stub route for the net.\n"); else Fprintf(stderr, "Position marked as a " "tap offset for the net.\n"); } // Don't disable unless both via orientations // have been checked. if (orient == 2) disable_gridpos(gridx, gridy, ds->layer); else lnode->flags |= NI_NO_VIAX; } else if ((lnode = NODEIPTR(gridx, gridy, ds->layer)) != NULL && (lnode->nodesav != NULL)) { u_char no_offsets = TRUE; int offset_net; // By how much would a tap need to be moved // to clear the obstructing geometry? // Check tap to right if ((dx > ds->x2) && (gridx < NumChannelsX - 1)) { offset_net = OBSVAL(gridx + 1, gridy, ds->layer); if (offset_net == 0 || offset_net == othernet) { xdist = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient); dist = ds->x2 - dx + xdist + LefGetRouteSpacing(ds->layer); // Only accept an alternative solution if // it has a smaller offset than previously // found. if ((no_offsets == FALSE) || (fabs(lnode->offset) > fabs(dist))) { mask = OFFSET_TAP; dir = NI_OFFSET_EW; OBSVAL(gridx, gridy, ds->layer) |= mask; lnode->offset = dist; lnode->flags &= ~(NI_OFFSET_NS); lnode->flags |= dir; no_offsets = FALSE; if ((ds->layer < Num_layers - 1) && (gridx > 0) && (OBSVAL(gridx + 1, gridy, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } else if ((ds->layer < Num_layers - 1) && (gridx > 0) && (dist > PitchX / 2)) { block_route(gridx, gridy, ds->layer, UP); } } } } // Check tap to left if ((dx < ds->x1) && (gridx > 0)) { offset_net = OBSVAL(gridx - 1, gridy, ds->layer); if (offset_net == 0 || offset_net == othernet) { xdist = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient); dist = ds->x1 - dx - xdist - LefGetRouteSpacing(ds->layer); if ((no_offsets == FALSE) || (fabs(lnode->offset) > fabs(dist))) { mask = OFFSET_TAP; dir = NI_OFFSET_EW; OBSVAL(gridx, gridy, ds->layer) |= mask; lnode->offset = dist; lnode->flags &= ~(NI_OFFSET_NS); lnode->flags |= dir; no_offsets = FALSE; if ((ds->layer < Num_layers - 1) && gridx < (NumChannelsX - 1) && (OBSVAL(gridx - 1, gridy, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } else if ((ds->layer < Num_layers - 1) && gridx < (NumChannelsX - 1) && (dist < -PitchX / 2)) { block_route(gridx, gridy, ds->layer, UP); } } } } // Check tap up if ((dy > ds->y2) && (gridy < NumChannelsY - 1)) { offset_net = OBSVAL(gridx, gridy + 1, ds->layer); if (offset_net == 0 || offset_net == othernet) { xdist = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient); dist = ds->y2 - dy + xdist + LefGetRouteSpacing(ds->layer); if ((no_offsets == FALSE) || (fabs(lnode->offset) > fabs(dist))) { mask = OFFSET_TAP; dir = NI_OFFSET_NS; OBSVAL(gridx, gridy, ds->layer) |= mask; lnode->offset = dist; lnode->flags &= ~(NI_OFFSET_EW); lnode->flags |= dir; no_offsets = FALSE; if ((ds->layer < Num_layers - 1) && (gridy > 0) && (OBSVAL(gridx, gridy + 1, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } else if ((ds->layer < Num_layers - 1) && (gridy > 0) && (dist > PitchY / 2)) { block_route(gridx, gridy, ds->layer, UP); } } } } // Check tap down if ((dy < ds->y1) && (gridy > 0)) { offset_net = OBSVAL(gridx, gridy - 1, ds->layer); if (offset_net == 0 || offset_net == othernet) { xdist = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient); dist = ds->y1 - dy - xdist - LefGetRouteSpacing(ds->layer); if ((no_offsets == FALSE) || (fabs(lnode->offset) > fabs(dist))) { mask = OFFSET_TAP; dir = NI_OFFSET_NS; OBSVAL(gridx, gridy, ds->layer) |= mask; lnode->offset = dist; lnode->flags &= ~(NI_OFFSET_EW); lnode->flags |= dir; no_offsets = FALSE; if ((ds->layer < Num_layers - 1) && gridx < (NumChannelsX - 1) && (OBSVAL(gridx, gridy - 1, ds->layer + 1) & OBSTRUCT_MASK)) { block_route(gridx, gridy, ds->layer, UP); } else if ((ds->layer < Num_layers - 1) && gridx < (NumChannelsX - 1) && (dist < -PitchY / 2)) { block_route(gridx, gridy, ds->layer, UP); } } } } // No offsets were possible. If orient is 0 // then mark as NI_NO_VIAX and try again with // orient 2. If orient is 2 and no offsets // are possible, then disable the position. if (no_offsets == TRUE) { if (orient == 2) { // Maybe no need to revert the flag? lnode->flags &= ~NI_NO_VIAX; if (is_testpoint(gridx, gridy, g, i, ds) != NULL) Fprintf(stderr, "Unable to find " "a viable offset for a tap.\n"); disable_gridpos(gridx, gridy, ds->layer); } else lnode->flags |= NI_NO_VIAX; } } else { if (is_testpoint(gridx, gridy, g, i, ds) != NULL) Fprintf(stderr, "Tap point is too " "close to two different nodes " "and no offsets are possible.\n"); disable_gridpos(gridx, gridy, ds->layer); } } /* If we are on a layer > 0, then this geometry */ /* may block or partially block a pin on layer */ /* zero. Mark this point as belonging to the */ /* net with a stub route to it. */ /* NOTE: This is possibly too restrictive. */ /* May want to force a tap offset for vias on */ /* layer zero. . . */ if ((ds->layer > 0) && (n2 != NULL) && (n2->netnum != node->netnum) && ((othernet == 0) || (othernet == (u_int)node->netnum))) { lnode = NODEIPTR(gridx, gridy, ds->layer); xdist = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient); if ((dy + xdist + LefGetRouteSpacing(ds->layer) > ds->y1) && (dy + xdist < ds->y1)) { if ((dx - xdist < ds->x2) && (dx + xdist > ds->x1) && (lnode == NULL || lnode->stub == 0.0)) { OBSVAL(gridx, gridy, ds->layer) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | node->netnum | STUBROUTE; lnode = SetNodeinfo(gridx, gridy, ds->layer, node); lnode->nodeloc = node; lnode->nodesav = node; lnode->stub = ds->y1 - dy; lnode->flags |= NI_STUB_NS; } } if ((dy - xdist - LefGetRouteSpacing(ds->layer) < ds->y2) && (dy - xdist > ds->y2)) { if ((dx - xdist < ds->x2) && (dx + xdist > ds->x1) && (lnode == NULL || lnode->stub == 0.0)) { OBSVAL(gridx, gridy, ds->layer) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | node->netnum | STUBROUTE; lnode = SetNodeinfo(gridx, gridy, ds->layer, node); lnode->nodeloc = node; lnode->nodesav = node; lnode->stub = ds->y2 - dy; lnode->flags |= NI_STUB_NS; } } xdist = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient); if ((dx + xdist + LefGetRouteSpacing(ds->layer) > ds->x1) && (dx + xdist < ds->x1)) { if ((dy - xdist < ds->y2) && (dy + xdist > ds->y1) && (lnode == NULL || lnode->stub == 0.0)) { OBSVAL(gridx, gridy, ds->layer) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | node->netnum | STUBROUTE; lnode = SetNodeinfo(gridx, gridy, ds->layer, node); lnode->nodeloc = node; lnode->nodesav = node; lnode->stub = ds->x1 - dx; lnode->flags |= NI_STUB_EW; } } if ((dx - xdist - LefGetRouteSpacing(ds->layer) < ds->x2) && (dx - xdist > ds->x2)) { if ((dy - xdist < ds->y2) && (dy + xdist > ds->y1) && (lnode == NULL || lnode->stub == 0.0)) { OBSVAL(gridx, gridy, ds->layer) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | node->netnum | STUBROUTE; lnode = SetNodeinfo(gridx, gridy, ds->layer, node); lnode->nodeloc = node; lnode->nodesav = node; lnode->stub = ds->x2 - dx; lnode->flags |= NI_STUB_EW; } } } } } gridy++; } } gridx++; } } } } } } /* void create_obstructions_outside_nodes( void ) */ /*--------------------------------------------------------------*/ /* tap_to_tap_interactions() */ /* */ /* Similar to create_obstructions_from_nodes(), but looks at */ /* each node's tap geometry, looks at every grid point in a */ /* wider area surrounding the tap. If any other node has an */ /* offset that would place it too close to this node's tap */ /* geometry, then we mark the other node as unroutable at that */ /* grid point. */ /*--------------------------------------------------------------*/ void tap_to_tap_interactions(void) { NODEINFO lnode; GATE g; DSEG ds; DPOINT tpoint; struct dseg_ de; int mingridx, mingridy, maxgridx, maxgridy; int i, gridx, gridy, net, orignet; double dx, dy; float dist; double deltaxx[MAX_LAYERS]; double deltaxy[MAX_LAYERS]; double deltayx[MAX_LAYERS]; double deltayy[MAX_LAYERS]; for (i = 0; i < Num_layers; i++) { deltaxx[i] = 0.5 * LefGetXYViaWidth(i, i, 0, 0) + LefGetRouteSpacing(i); deltayx[i] = 0.5 * LefGetXYViaWidth(i, i, 1, 0) + LefGetRouteSpacing(i); deltaxy[i] = 0.5 * LefGetXYViaWidth(i, i, 0, 2) + LefGetRouteSpacing(i); deltayy[i] = 0.5 * LefGetXYViaWidth(i, i, 1, 2) + LefGetRouteSpacing(i); } for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { net = g->netnum[i]; if (net > 0) { for (ds = g->taps[i]; ds; ds = ds->next) { mingridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1; if (mingridx < 0) mingridx = 0; maxgridx = (int)((ds->x2 - Xlowerbound) / PitchX) + 2; if (maxgridx >= NumChannelsX) maxgridx = NumChannelsX - 1; mingridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1; if (mingridy < 0) mingridy = 0; maxgridy = (int)((ds->y2 - Ylowerbound) / PitchY) + 2; if (maxgridy >= NumChannelsY) maxgridy = NumChannelsY - 1; for (gridx = mingridx; gridx <= maxgridx; gridx++) { for (gridy = mingridy; gridy <= maxgridy; gridy++) { /* Is there an offset tap at this position, and */ /* does it belong to a net that is != net? */ orignet = OBSVAL(gridx, gridy, ds->layer); if (orignet & OFFSET_TAP) { orignet &= ROUTED_NET_MASK; if (orignet != net) { dx = (gridx * PitchX) + Xlowerbound; dy = (gridy * PitchY) + Ylowerbound; lnode = NODEIPTR(gridx, gridy, ds->layer); dist = (lnode) ? lnode->offset : 0.0; /* "de" is the bounding box of a via placed */ /* at (gridx, gridy) and offset as specified. */ /* Expanded by metal spacing requirement. */ de.x1 = dx - deltaxx[ds->layer]; de.x2 = dx + deltaxx[ds->layer]; de.y1 = dy - deltayx[ds->layer]; de.y2 = dy + deltayx[ds->layer]; if (lnode->flags & NI_OFFSET_NS) { de.y1 += dist; de.y2 += dist; } else if (lnode->flags & NI_OFFSET_EW) { de.x1 += dist; de.x2 += dist; } // Shrink by EPS to avoid roundoff errors de.x1 += EPS; de.x2 -= EPS; de.y1 += EPS; de.y2 -= EPS; /* Does the via bounding box interact with */ /* the tap geometry? */ if ((de.x1 < ds->x2) && (ds->x1 < de.x2) && (de.y1 < ds->y2) && (ds->y1 < de.y2)) { if (is_testpoint(gridx, gridy, g, i, ds) != NULL) Fprintf(stderr, "Offset tap interferes " "with position.\n"); disable_gridpos(gridx, gridy, ds->layer); } } } /* Does the distance to the tap prohibit a specific */ /* via orientation? */ if ((orignet & (~(BLOCKED_N | BLOCKED_S | BLOCKED_E | BLOCKED_W))) == 0) { lnode = NODEIPTR(gridx, gridy, ds->layer); /* Positions belonging to nodes should have */ /* already been handled. */ if (lnode == NULL) { dx = (gridx * PitchX) + Xlowerbound; dy = (gridy * PitchY) + Ylowerbound; /* For a horizontally-oriented via on ds->layer */ de.x1 = dx - deltaxx[ds->layer]; de.x2 = dx + deltaxx[ds->layer]; de.y1 = dy - deltayx[ds->layer]; de.y2 = dy + deltayx[ds->layer]; if (ds->x2 > de.x1 && ds->x1 < de.x2) { /* Check north and south */ if ((ds->y1 < de.y2 && ds->y2 > de.y2) || (ds->y2 > de.y1 && ds->y1 < de.y1)) { /* prohibit horizontal via */ lnode = SetNodeinfo(gridx, gridy, ds->layer, g->noderec[i]); lnode->flags |= NI_NO_VIAX; } } if (ds->y2 > de.y1 && ds->y1 < de.y2) { /* Check east and west*/ if ((ds->x1 < de.x2 && ds->x2 > de.x2) || (ds->x2 > de.x1 && ds->x1 < de.x1)) { /* prohibit horizontal via */ lnode = SetNodeinfo(gridx, gridy, ds->layer, g->noderec[i]); lnode->flags |= NI_NO_VIAX; } } /* For a vertically-oriented via on ds->layer */ de.x1 = dx - deltaxy[ds->layer]; de.x2 = dx + deltaxy[ds->layer]; de.y1 = dy - deltayy[ds->layer]; de.y2 = dy + deltayy[ds->layer]; if (ds->x2 > de.x1 && ds->x1 < de.x2) { /* Check north and south */ if ((ds->y1 < de.y2 && ds->y2 > de.y2) || (ds->y2 > de.y1 && ds->y1 < de.y1)) { /* prohibit horizontal via */ lnode = SetNodeinfo(gridx, gridy, ds->layer, g->noderec[i]); lnode->flags |= NI_NO_VIAY; } } if (ds->y2 > de.y1 && ds->y1 < de.y2) { /* Check east and west*/ if ((ds->x1 < de.x2 && ds->x2 > de.x2) || (ds->x2 > de.x1 && ds->x1 < de.x1)) { /* prohibit horizontal via */ lnode = SetNodeinfo(gridx, gridy, ds->layer, g->noderec[i]); lnode->flags |= NI_NO_VIAY; } } } } } } } } } } } /*--------------------------------------------------------------*/ /* make_routable() */ /* */ /* In the case that a node can't be routed because it has no */ /* available tap points, but there is tap geometry recorded */ /* for the node, then take the first available grid location */ /* near the tap. This, of course, bypasses all of qrouter's */ /* DRC checks. But it is only meant to be a stop-gap measure */ /* to get qrouter to complete all routes, and may work in */ /* cases where, say, the tap passes euclidean rules but not */ /* manhattan rules. */ /*--------------------------------------------------------------*/ void make_routable(NODE node) { NODEINFO lnode; GATE g; DSEG ds; int i, gridx, gridy; double dx, dy; /* The database is not organized to find tap points */ /* from nodes, so we have to search for the node. */ /* Fortunately this routine isn't normally called. */ for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->noderec[i] == node) { for (ds = g->taps[i]; ds; ds = ds->next) { gridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1; if (gridx < 0) gridx = 0; while (1) { dx = (gridx * PitchX) + Xlowerbound; if (dx > ds->x2 || gridx >= NumChannelsX) break; else if (dx >= ds->x1 && gridx >= 0) { gridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1; if (gridy < 0) gridy = 0; while (1) { dy = (gridy * PitchY) + Ylowerbound; if (dy > ds->y2 || gridy >= NumChannelsY) break; // Area inside defined pin geometry if (dy > ds->y1 && gridy >= 0) { int orignet = OBSVAL(gridx, gridy, ds->layer); if (orignet & NO_NET) { OBSVAL(gridx, gridy, ds->layer) = g->netnum[i]; lnode = SetNodeinfo(gridx, gridy, ds->layer, g->noderec[i]); lnode->nodeloc = node; lnode->nodesav = node; return; } } gridy++; } } gridx++; } } } } } } /*--------------------------------------------------------------*/ /* adjust_stub_lengths() */ /* */ /* Makes an additional pass through the tap and obstruction */ /* databases, checking geometry against the potential stub */ /* routes for DRC spacing violations. Adjust stub routes as */ /* necessary to resolve the DRC error(s). */ /* */ /* ARGS: none. */ /* RETURNS: nothing */ /* SIDE EFFECTS: none */ /* AUTHOR: Tim Edwards, April 2013 */ /*--------------------------------------------------------------*/ void adjust_stub_lengths(void) { NODE node; NODEINFO lnode; GATE g; DSEG ds, ds2; struct dseg_ dt, de; int i, gridx, gridy, orignet, o; double dx, dy, wx, wy, s; float dist; u_char errbox; int orient = 0; // For each node terminal (gate pin), look at the surrounding grid points. // If any define a stub route or an offset, check if the stub geometry // or offset geometry would create a DRC spacing violation. If so, adjust // the stub route to resolve the error. If the error cannot be resolved, // mark the position as unroutable. If it is the ONLY grid point accessible // to the pin, keep it as-is and flag a warning. // Unlike blockage-finding routines, which look in an area of a size equal // to the DRC interaction distance around a tap rectangle, this routine looks // out one grid pitch in each direction, to catch information about stubs that // may terminate within a DRC interaction distance of the tap rectangle. for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] != 0) { // Get the node record associated with this pin. node = g->noderec[i]; if (node == NULL) continue; // Work through each rectangle in the tap geometry twice. The // second sweep checks for errors created by geometry that // interacts with stub routes created by the first sweep, and // also for geometry that interacts with vias in 90 degree // orientation. orient = 0; for (ds = g->taps[i];; ds = ds->next) { if (ds == NULL) { if (orient == 0) { orient = 2; ds = g->taps[i]; if (ds == NULL) break; } else break; } wx = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient); wy = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient); s = LefGetRouteSpacing(ds->layer); gridx = (int)((ds->x1 - Xlowerbound - PitchX) / PitchX) - 1; while (1) { dx = (gridx * PitchX) + Xlowerbound; if (dx > (ds->x2 + PitchX) || gridx >= NumChannelsX) break; else if (dx >= (ds->x1 - PitchX) && gridx >= 0) { gridy = (int)((ds->y1 - Ylowerbound - PitchY) / PitchY) - 1; while (1) { dy = (gridy * PitchY) + Ylowerbound; if (dy > (ds->y2 + PitchY) || gridy >= NumChannelsY) break; if (dy >= (ds->y1 - PitchY) && gridy >= 0) { orignet = OBSVAL(gridx, gridy, ds->layer); // Ignore this location if it is assigned to another // net, or is assigned to NO_NET. if ((orignet & ROUTED_NET_MASK) != node->netnum) { gridy++; continue; } lnode = NODEIPTR(gridx, gridy, ds->layer); // Even if it's on the same net, we need to check // if the stub is to this node, otherwise it is not // an issue. if ((!lnode) || (lnode->nodesav != node)) { gridy++; continue; } // NI_STUB_MASK are unroutable; leave them alone if (orignet & STUBROUTE) { if ((lnode->flags & NI_OFFSET_MASK) == NI_OFFSET_MASK) { gridy++; continue; } } // define a route box around the grid point errbox = FALSE; dt.x1 = dx - wx; dt.x2 = dx + wx; dt.y1 = dy - wy; dt.y2 = dy + wy; // adjust the route box according to the stub // or offset geometry, provided that the stub // is longer than the route box. if (orignet & OFFSET_TAP) { dist = lnode->offset; if (lnode->flags & NI_OFFSET_EW) { dt.x1 += dist; dt.x2 += dist; } else if (lnode->flags & NI_OFFSET_NS) { dt.y1 += dist; dt.y2 += dist; } } else if (orignet & STUBROUTE) { dist = (double)lnode->stub; if (lnode->flags & NI_STUB_EW) { if (dist > EPS) { if (dx + dist > dt.x2) dt.x2 = dx + dist; } else { if (dx + dist < dt.x1) dt.x1 = dx + dist; } } else if (lnode->flags & NI_STUB_NS) { if (dist > EPS) { if (dy + dist > dt.y2) dt.y2 = dy + dist; } else { if (dy + dist < dt.y1) dt.y1 = dy + dist; } } } de = dt; // check for DRC spacing interactions between // the tap box and the route box if ((dt.y1 - ds->y2) > EPS && (dt.y1 - ds->y2) + EPS < s) { if (ds->x2 > (dt.x1 - s) && ds->x1 < (dt.x2 + s)) { de.y2 = dt.y1; de.y1 = ds->y2; if (ds->x2 + s < dt.x2) de.x2 = ds->x2 + s; if (ds->x1 - s > dt.x1) de.x1 = ds->x1 - s; errbox = TRUE; } } else if ((ds->y1 - dt.y2) > EPS && (ds->y1 - dt.y2) + EPS < s) { if (ds->x2 > (dt.x1 - s) && ds->x1 < (dt.x2 + s)) { de.y1 = dt.y2; de.y2 = ds->y1; if (ds->x2 + s < dt.x2) de.x2 = ds->x2 + s; if (ds->x1 - s > dt.x1) de.x1 = ds->x1 - s; errbox = TRUE; } } if ((dt.x1 - ds->x2) > EPS && (dt.x1 - ds->x2) + EPS < s) { if (ds->y2 > (dt.y1 - s) && ds->y1 < (dt.y2 + s)) { de.x2 = dt.x1; de.x1 = ds->x2; if (ds->y2 + s < dt.y2) de.y2 = ds->y2 + s; if (ds->y1 - s > dt.y1) de.y1 = ds->y1 - s; errbox = TRUE; } } else if ((ds->x1 - dt.x2) > EPS && (ds->x1 - dt.x2) + EPS < s) { if (ds->y2 > (dt.y1 - s) && ds->y1 < (dt.y2 + s)) { de.x1 = dt.x2; de.x2 = ds->x1; if (ds->y2 + s < dt.y2) de.y2 = ds->y2 + s; if (ds->y1 - s > dt.y1) de.y1 = ds->y1 - s; errbox = TRUE; } } if (errbox == TRUE) { // Chop areas off the error box that are covered by // other taps of the same port. for (ds2 = g->taps[i]; ds2; ds2 = ds2->next) { if (ds2 == ds) continue; if (ds2->layer != ds->layer) continue; if (ds2->x1 <= de.x1 && ds2->x2 >= de.x2 && ds2->y1 <= de.y1 && ds2->y2 >= de.y2) { errbox = FALSE; // Completely covered break; } // Look for partial coverage. Note that any // change can cause a change in the original // two conditionals, so we have to keep // evaluating those conditionals. if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) // if (ds2->x1 < de.x1 - EPS && if (ds2->x1 < de.x1 + EPS && ds2->x2 < de.x2 - EPS) { de.x1 = ds2->x2; if (ds2->x2 >= ds->x2) errbox = FALSE; } if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) // if (ds2->x2 > de.x2 + EPS && if (ds2->x2 > de.x2 - EPS && ds2->x1 > de.x1 + EPS) { de.x2 = ds2->x1; if (ds2->x1 <= ds->x1) errbox = FALSE; } if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) // if (ds2->y1 < de.y1 - EPS && if (ds2->y1 < de.y1 + EPS && ds2->y2 < de.y2 - EPS) { de.y1 = ds2->y2; if (ds2->y2 >= ds->y2) errbox = FALSE; } if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) // if (ds2->y2 > de.y2 + EPS && if (ds2->y2 > de.y2 - EPS && ds2->y1 > de.y1 + EPS) { de.y2 = ds2->y1; if (ds2->y1 <= ds->y1) errbox = FALSE; } } } // Any area left over is a potential DRC error. if ((de.x2 <= de.x1) || (de.y2 <= de.y1)) errbox = FALSE; if (errbox == TRUE) { // Create stub route to cover error box, or // if possible, stretch existing stub route // to cover error box. // Allow EW stubs to be changed to NS stubs and // vice versa if the original stub length was less // than a route width. This means the grid position // makes contact without the stub. Moving the stub // to another side should not create an error. // NOTE: error box must touch ds geometry, and by // more than just a point. // 8/31/2016: // If DRC violations are created on two adjacent // sides, then create both a stub route and a tap // offset. Put the stub route in the preferred // metal direction of the layer, and set the tap // offset to prevent the DRC error in the other // direction. // 10/3/2016: The tap offset can be set either // by moving toward the obstructing edge to // remove the gap, or moving away from it to // avoid the DRC spacing error. Choose the one // that offsets by the smaller distance. if ((de.x2 > dt.x2) && (de.y1 < ds->y2) && (de.y2 > ds->y1)) { if ((orignet & STUBROUTE) == 0) { OBSVAL(gridx, gridy, ds->layer) |= STUBROUTE; lnode->stub = de.x2 - dx; lnode->flags |= NI_STUB_EW; errbox = FALSE; } else if ((orignet & STUBROUTE) && (lnode->flags & NI_STUB_EW)) { // Beware, if dist > 0 then this reverses // the stub. For U-shaped ports may need // to have separate E and W stubs. lnode->stub = de.x2 - dx; errbox = FALSE; } else if ((orignet & STUBROUTE) && (lnode->flags & NI_STUB_NS)) { // If preferred route direction is // horizontal, then change the stub OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP; if (LefGetRouteOrientation(ds->layer) == 1) { lnode->flags = NI_OFFSET_NS | NI_STUB_EW; if (lnode->stub > 0) { lnode->offset = lnode->stub - wy; if (lnode->offset < 0) lnode->offset = 0; } else { lnode->offset = lnode->stub + wy; if (lnode->offset > 0) lnode->offset = 0; } lnode->stub = de.x2 - dx; errbox = FALSE; } else { // Add the offset lnode->offset = de.x2 - dx - wx; if (lnode->offset > s - lnode->offset) lnode->offset -= s; lnode->flags |= NI_OFFSET_EW; errbox = FALSE; } } } else if ((de.x1 < dt.x1) && (de.y1 < ds->y2) && (de.y2 > ds->y1)) { if ((orignet & STUBROUTE) == 0) { OBSVAL(gridx, gridy, ds->layer) |= STUBROUTE; lnode->stub = de.x1 - dx; lnode->flags |= NI_STUB_EW; errbox = FALSE; } else if ((orignet & STUBROUTE) && (lnode->flags & NI_STUB_EW)) { // Beware, if dist > 0 then this reverses // the stub. For U-shaped ports may need // to have separate E and W stubs. lnode->stub = de.x1 - dx; errbox = FALSE; } else if ((orignet & STUBROUTE) && (lnode->flags & NI_STUB_NS)) { // If preferred route direction is // horizontal, then change the stub OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP; if (LefGetRouteOrientation(ds->layer) == 1) { lnode->flags = NI_OFFSET_NS | NI_STUB_EW; if (lnode->stub > 0) { lnode->offset = lnode->stub - wy; if (lnode->offset < 0) lnode->offset = 0; } else { lnode->offset = lnode->stub + wy; if (lnode->offset > 0) lnode->offset = 0; } lnode->stub = de.x1 - dx; errbox = FALSE; } else { // Add the offset lnode->offset = de.x1 - dx + wx; if (-lnode->offset > s + lnode->offset) lnode->offset += s; lnode->flags |= NI_OFFSET_EW; errbox = FALSE; } } } else if ((de.y2 > dt.y2) && (de.x1 < ds->x2) && (de.x2 > ds->x1)) { if ((orignet & STUBROUTE) == 0) { OBSVAL(gridx, gridy, ds->layer) |= STUBROUTE; lnode->stub = de.y2 - dy; lnode->flags |= NI_STUB_NS; errbox = FALSE; } else if ((orignet & STUBROUTE) && (lnode->flags & NI_STUB_NS)) { // Beware, if dist > 0 then this reverses // the stub. For C-shaped ports may need // to have separate N and S stubs. lnode->stub = de.y2 - dy; errbox = FALSE; } else if ((orignet & STUBROUTE) && (lnode->flags & NI_STUB_EW)) { // If preferred route direction is // vertical, then change the stub OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP; if (LefGetRouteOrientation(ds->layer) == 0) { lnode->flags = NI_OFFSET_EW | NI_STUB_NS; if (lnode->stub > 0) { lnode->offset = lnode->stub - wx; if (lnode->offset < 0) lnode->offset = 0; } else { lnode->offset = lnode->stub + wx; if (lnode->offset > 0) lnode->offset = 0; } lnode->stub = de.y2 - dy; errbox = FALSE; } else { // Add the offset lnode->offset = de.y2 - dy - wy; if (lnode->offset > s - lnode->offset) lnode->offset -= s; lnode->flags |= NI_OFFSET_NS; errbox = FALSE; } } } else if ((de.y1 < dt.y1) && (de.x1 < ds->x2) && (de.x2 > ds->x1)) { if ((orignet & STUBROUTE) == 0) { OBSVAL(gridx, gridy, ds->layer) |= STUBROUTE; lnode->stub = de.y1 - dy; lnode->flags |= NI_STUB_NS; errbox = FALSE; } else if ((orignet & STUBROUTE) && (lnode->flags & NI_STUB_NS)) { // Beware, if dist > 0 then this reverses // the stub. For C-shaped ports may need // to have separate N and S stubs. lnode->stub = de.y1 - dy; errbox = FALSE; } else if ((orignet & STUBROUTE) && (lnode->flags & NI_STUB_EW)) { // If preferred route direction is // vertical, then change the stub OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP; if (LefGetRouteOrientation(ds->layer) == 0) { lnode->flags = NI_OFFSET_EW | NI_STUB_NS; if (lnode->stub > 0) { lnode->offset = lnode->stub - wx; if (lnode->offset < 0) lnode->offset = 0; } else { lnode->offset = lnode->stub + wx; if (lnode->offset > 0) lnode->offset = 0; } lnode->stub = de.y1 - dy + wy; errbox = FALSE; } else { // Add the offset lnode->offset = de.y1 - dy + wy; if (-lnode->offset > s + lnode->offset) lnode->offset += s; lnode->flags |= NI_OFFSET_NS; errbox = FALSE; } } } // Where the error box did not touch the stub // route, there is assumed to be no error. if (errbox == TRUE) if ((de.x2 > dt.x2) || (de.x1 < dt.x1) || (de.y2 > dt.y2) || (de.y1 < dt.y1)) errbox = FALSE; if (errbox == TRUE) { // Unroutable position, so mark it unroutable OBSVAL(gridx, gridy, ds->layer) |= STUBROUTE; lnode->flags |= NI_STUB_MASK; } } } gridy++; } } gridx++; } } } } } } /* void adjust_stub_lengths() */ /*--------------------------------------------------------------*/ /* block_route() */ /* */ /* Mark a specific length along the route tracks as unroutable */ /* by finding the grid point in the direction indicated, and */ /* setting the appropriate block bit in the Obs[] array for */ /* that position. The original grid point is marked as */ /* unroutable in the opposite direction, for symmetry. */ /*--------------------------------------------------------------*/ void block_route(int x, int y, int lay, u_char dir) { int bx, by, bl, ob; bx = x; by = y; bl = lay; switch (dir) { case NORTH: if (y == NumChannelsY - 1) return; by = y + 1; break; case SOUTH: if (y == 0) return; by = y - 1; break; case EAST: if (x == NumChannelsX - 1) return; bx = x + 1; break; case WEST: if (x == 0) return; bx = x - 1; break; case UP: if (lay == Num_layers - 1) return; bl = lay + 1; break; case DOWN: if (lay == 0) return; bl = lay - 1; break; } ob = OBSVAL(bx, by, bl); if ((ob & NO_NET) != 0) return; switch (dir) { case NORTH: OBSVAL(bx, by, bl) |= BLOCKED_S; OBSVAL(x, y, lay) |= BLOCKED_N; break; case SOUTH: OBSVAL(bx, by, bl) |= BLOCKED_N; OBSVAL(x, y, lay) |= BLOCKED_S; break; case EAST: OBSVAL(bx, by, bl) |= BLOCKED_W; OBSVAL(x, y, lay) |= BLOCKED_E; break; case WEST: OBSVAL(bx, by, bl) |= BLOCKED_E; OBSVAL(x, y, lay) |= BLOCKED_W; break; case UP: OBSVAL(bx, by, bl) |= BLOCKED_D; OBSVAL(x, y, lay) |= BLOCKED_U; break; case DOWN: OBSVAL(bx, by, bl) |= BLOCKED_U; OBSVAL(x, y, lay) |= BLOCKED_D; break; } } /*--------------------------------------------------------------*/ /* find_route_blocks() --- */ /* */ /* Search tap geometry for edges that cause DRC spacing */ /* errors with route edges. This specifically checks */ /* edges of the route tracks, not the intersection points. */ /* If a tap would cause an error with a route segment, */ /* the grid points on either end of the segment are */ /* flagged to prevent generating a route along that */ /* specific segment. */ /*--------------------------------------------------------------*/ void find_route_blocks() { GATE g; NODEINFO lnode; DSEG ds; struct dseg_ dt, lds; int i, gridx, gridy; double dx, dy, w, v, s, u; double dist; int orient = 0; /* Need to check orient = 2! */ for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] != 0) { // Work through each rectangle in the tap geometry for (ds = g->taps[i]; ds; ds = ds->next) { lds = *ds; /* Make local copy of tap rect */ /* Trim to array bounds and reject if out-of-bounds */ gridx = (int)((lds.x1 - Xlowerbound) / PitchX); if (gridx >= NumChannelsX) continue; if (gridx < 0) lds.x1 = Xlowerbound; gridx = (int)((lds.x2 - Xlowerbound) / PitchX); if (gridx < 0) continue; if (gridx >= NumChannelsX) lds.x2 = Xlowerbound + (NumChannelsX * PitchX); gridy = (int)((lds.y1 - Ylowerbound) / PitchY); if (gridy >= NumChannelsY) continue; if (gridy < 0) lds.y1 = Ylowerbound; gridy = (int)((lds.y2 - Ylowerbound) / PitchY); if (gridy < 0) continue; if (gridy >= NumChannelsY) lds.y2 = Ylowerbound + (NumChannelsY * PitchY); w = 0.5 * LefGetRouteWidth(lds.layer); v = 0.5 * LefGetXYViaWidth(lds.layer, lds.layer, 0, orient); s = LefGetRouteSpacing(lds.layer); // Look west gridx = (int)((lds.x1 - Xlowerbound) / PitchX); dx = (gridx * PitchX) + Xlowerbound; dist = lds.x1 - dx - w; if (dist > 0 && dist < s && gridx >= 0) { dt.x1 = dt.x2 = dx; dt.y1 = lds.y1; dt.y2 = lds.y2; // Check for other taps covering this edge // (to do) // Find all grid points affected gridy = (int)((lds.y1 - Ylowerbound - PitchY) / PitchY); dy = (gridy * PitchY) + Ylowerbound; while ((dy < lds.y1 - s) || (gridy < 0)) { dy += PitchY; gridy++; } while (dy < lds.y2 + s) { lnode = NODEIPTR(gridx, gridy, lds.layer); u = ((OBSVAL(gridx, gridy, lds.layer) & STUBROUTE) && (lnode->flags & NI_STUB_EW)) ? v : w; if (dy + EPS < lds.y2 - u) { block_route(gridx, gridy, lds.layer, NORTH); } if (dy - EPS > lds.y1 + u) { block_route(gridx, gridy, lds.layer, SOUTH); } dy += PitchY; gridy++; } } // Look east gridx = (int)(1.0 + (lds.x2 - Xlowerbound) / PitchX); dx = (gridx * PitchX) + Xlowerbound; dist = dx - lds.x2 - w; if (dist > 0 && dist < s && gridx < NumChannelsX) { dt.x1 = dt.x2 = dx; dt.y1 = lds.y1; dt.y2 = lds.y2; // Check for other taps covering this edge // (to do) // Find all grid points affected gridy = (int)((lds.y1 - Ylowerbound - PitchY) / PitchY); dy = (gridy * PitchY) + Ylowerbound; while ((dy < lds.y1 - s) || (gridy < 0)) { dy += PitchY; gridy++; } while (dy < lds.y2 + s) { lnode = NODEIPTR(gridx, gridy, lds.layer); u = ((OBSVAL(gridx, gridy, lds.layer) & STUBROUTE) && (lnode->flags & NI_STUB_EW)) ? v : w; if (dy + EPS < lds.y2 - u) { block_route(gridx, gridy, lds.layer, NORTH); } if (dy - EPS > lds.y1 + u) { block_route(gridx, gridy, lds.layer, SOUTH); } dy += PitchY; gridy++; } } // Look south gridy = (int)((lds.y1 - Ylowerbound) / PitchY); dy = (gridy * PitchY) + Ylowerbound; dist = lds.y1 - dy - w; if (dist > 0 && dist < s && gridy >= 0) { dt.x1 = lds.x1; dt.x2 = lds.x2; dt.y1 = dt.y2 = dy; // Check for other taps covering this edge // (to do) // Find all grid points affected gridx = (int)((lds.x1 - Xlowerbound - PitchX) / PitchX); dx = (gridx * PitchX) + Xlowerbound; while ((dx < lds.x1 - s) || (gridx < 0)) { dx += PitchX; gridx++; } while (dx < lds.x2 + s) { lnode = NODEIPTR(gridx, gridy, lds.layer); u = ((OBSVAL(gridx, gridy, lds.layer) & STUBROUTE) && (lnode->flags & NI_STUB_NS)) ? v : w; if (dx + EPS < lds.x2 - u) { block_route(gridx, gridy, lds.layer, EAST); } if (dx - EPS > lds.x1 + u) { block_route(gridx, gridy, lds.layer, WEST); } dx += PitchX; gridx++; } } // Look north gridy = (int)(1.0 + (lds.y2 - Ylowerbound) / PitchY); dy = (gridy * PitchY) + Ylowerbound; dist = dy - lds.y2 - w; if (dist > 0 && dist < s && gridy < NumChannelsY) { dt.x1 = lds.x1; dt.x2 = lds.x2; dt.y1 = dt.y2 = dy; // Check for other taps covering this edge // (to do) // Find all grid points affected gridx = (int)((lds.x1 - Xlowerbound - PitchX) / PitchX); dx = (gridx * PitchX) + Xlowerbound; while ((dx < lds.x1 - s) || (gridx < 0)) { dx += PitchX; gridx++; } while (dx < lds.x2 + s) { lnode = NODEIPTR(gridx, gridy, lds.layer); u = ((OBSVAL(gridx, gridy, lds.layer) & STUBROUTE) && (lnode->flags & NI_STUB_NS)) ? v : w; if (dx + EPS < lds.x2 - u) { block_route(gridx, gridy, lds.layer, EAST); } if (dx - EPS > lds.x1 + u) { block_route(gridx, gridy, lds.layer, WEST); } dx += PitchX; gridx++; } } } } } } } /* node.c */ qrouter-1.4.88/lef.h0000644000175000017510000001642313625043307013574 0ustar nileshnilesh/* * lef.h -- * * This file defines things that are used by internal LEF routines in * various files. * */ #ifndef _LEFINT_H #define _LEFINT_H /* Some constants for LEF and DEF files */ #define LEF_LINE_MAX 2048 /* Maximum length fixed by LEF/DEF specifications */ #define LEF_MAX_ERRORS 100 /* Max # errors to report; limits output if */ /* something is really wrong about the file */ #define DEFAULT_WIDTH 3 /* Default metal width for routes if undefined */ #define DEFAULT_SPACING 4 /* Default spacing between metal if undefined */ /* Structure holding the counts of regular and special nets */ typedef struct { int regular; int special; u_char has_nets; } NetCount; /* Various modes for writing nets. */ #define DO_REGULAR 0 #define DO_SPECIAL 1 #define ALL_SPECIAL 2 /* treat all nets as SPECIALNETS */ /* Types of error messages */ enum lef_error_types {LEF_ERROR = 0, LEF_WARNING, DEF_ERROR, DEF_WARNING}; /* Port classes */ enum port_classes {PORT_CLASS_DEFAULT = 0, PORT_CLASS_INPUT, PORT_CLASS_OUTPUT, PORT_CLASS_TRISTATE, PORT_CLASS_BIDIRECTIONAL, PORT_CLASS_FEEDTHROUGH}; /* Port uses */ enum port_uses {PORT_USE_DEFAULT = 0, PORT_USE_SIGNAL, PORT_USE_ANALOG, PORT_USE_POWER, PORT_USE_GROUND, PORT_USE_CLOCK, PORT_USE_TIEOFF, PORT_USE_SCAN, PORT_USE_RESET}; /* Structure to hold information about spacing rules */ typedef struct _lefSpacingRule *lefSpacingPtr; typedef struct _lefSpacingRule { lefSpacingPtr next; double width; /* width, in microns */ double spacing; /* minimum spacing rule, in microns */ } lefSpacingRule; /* Area calculation methods for finding antenna ratios. ANTENNA_ROUTE */ /* is not a method but is used to indicate to the antenna search */ /* routine that the search is for routing preparation and not for */ /* calculating error. */ enum area_methods {CALC_NONE = 0, CALC_AREA, CALC_SIDEAREA, CALC_AGG_AREA, CALC_AGG_SIDEAREA, ANTENNA_ROUTE, ANTENNA_DISABLE}; /* Structure used to maintain default routing information for each */ /* routable layer type. */ typedef struct { lefSpacingRule *spacing; /* spacing rules, ordered by width */ double width; /* nominal route width, in microns */ double pitchx; /* route X pitch, in microns */ double pitchy; /* route Y pitch, in microns */ double offsetx; /* route track offset from X origin, in microns */ double offsety; /* route track offset from Y origin, in microns */ double respersq; /* resistance per square */ double areacap; /* area capacitance per square micron */ double edgecap; /* edge capacitance per micron */ double minarea; /* minimum metal area rule */ double thick; /* metal layer thickness, if given */ double antenna; /* antenna area ratio rule */ u_char method; /* antenna rule calculation method */ u_char hdirection; /* horizontal direction preferred */ } lefRoute; /* These values may be used for "hdirection". initialize hdirection */ /* with DIR_UNKNOWN. If the LEF file defines the pitch before the */ /* direction and does not specify both X and Y pitches, then change to */ /* DIR_RESOLVE to indicate that the pitch in the non-preferred */ /* direction should be zeroed when the preferred direction is known. */ #define DIR_VERTICAL (u_char)0 #define DIR_HORIZONTAL (u_char)1 #define DIR_UNKNOWN (u_char)2 #define DIR_RESOLVE (u_char)3 /* Structure used to maintain default generation information for each */ /* via or viarule (contact) type. If "cell" is non-NULL, then the via */ /* is saved in a cell (pointed to by "cell"), and "area" describes the */ /* bounding box. Otherwise, the via is formed by magic type "type" */ /* with a minimum area "area" for a single contact. */ typedef struct { struct dseg_ area; /* Area of single contact, or cell bbox */ /* in units of microns */ GATE cell; /* Cell for fixed via def, or NULL */ DSEG lr; /* Extra information for vias with */ /* more complicated geometry. */ double respervia; /* resistance per via */ int obsType; /* Secondary obstruction type */ char generated; /* Flag indicating via from VIARULE */ } lefVia; /* Defined types for "lefClass" in the lefLayer structure */ /* Note that the first four match TYPE records in the LEF. IGNORE has */ /* a special meaning to qrouter, and VIA is for VIA definitions. */ #define CLASS_ROUTE 0 /* route layer */ #define CLASS_CUT 1 /* cut layer */ #define CLASS_MASTER 2 /* masterslice layer */ #define CLASS_OVERLAP 3 /* overlap layer */ #define CLASS_IGNORE 4 /* inactive layer */ #define CLASS_VIA 5 /* via record */ /* Structure defining a route or via layer and matching it to a magic */ /* layer type. This structure is saved in the LefInfo list. */ typedef struct _lefLayer *LefList; typedef struct _lefLayer { LefList next; /* Next layer in linked list */ char *lefName; /* CIF name of this layer */ int type; /* GDS layer type, or -1 for none */ int obsType; /* GDS type to use if this is an obstruction */ u_char lefClass; /* is this a via, route, or masterslice layer */ union { lefRoute route; /* for route layers */ lefVia via; /* for contacts */ } info; } lefLayer; /* External declaration of global variables */ extern int lefCurrentLine; extern LefList LefInfo; extern LinkedStringPtr AllowedVias; /* Forward declarations */ int Lookup(char *str, char*(table[])); u_char LefParseEndStatement(FILE *f, char *match); void LefSkipSection(FILE *f, char *match); void LefEndStatement(FILE *f); GATE lefFindCell(char *name); char *LefNextToken(FILE *f, u_char ignore_eol); char *LefLower(char *token); DSEG LefReadGeometry(GATE lefMacro, FILE *f, float oscale); LefList LefRedefined(LefList lefl, char *redefname); void LefAddViaGeometry(FILE *f, LefList lefl, int curlayer, float oscale); DSEG LefReadRect(FILE *f, int curlayer, float oscale); int LefReadLayer(FILE *f, u_char obstruct); LefList LefFindLayer(char *token); LefList LefFindLayerByNum(int layer); int LefFindLayerNum(char *token); void LefSetRoutePitchX(int layer, double value); void LefSetRoutePitchY(int layer, double value); double LefGetRouteKeepout(int layer); double LefGetRouteWidth(int layer); double LefGetRouteMinArea(int layer); double LefGetXYViaWidth(int base, int layer, int dir, int orient); double LefGetViaWidth(int base, int layer, int dir); double LefGetRouteSpacing(int layer); double LefGetRouteWideSpacing(int layer, double width); double LefGetRoutePitch(int layer); double LefGetRoutePitchX(int layer); double LefGetRoutePitchY(int layer); double LefGetRouteOffset(int layer); double LefGetRouteThickness(int layer); double LefGetRouteAreaRatio(int layer); u_char LefGetRouteAntennaMethod(int layer); int LefGetRouteRCvalues(int layer, double *areacap, double *edgecap, double *respersq); int LefGetViaResistance(int layer, double *respervia); char *LefGetRouteName(int layer); int LefGetRouteOrientation(int layer); int LefGetMaxRouteLayer(void); int LefGetMaxLayer(void); GATE LefFindInstance(char *name); void LefHashCell(GATE gateginfo); int LefRead(char *inName); void LefAssignLayerVias(); void LefWriteGeneratedVias(FILE *f, double oscale, int defvias); void LefError(int type, char *fmt, ...); /* Variable argument procedure */ /* requires parameter list. */ #endif /* _LEFINT_H */ qrouter-1.4.88/point.h0000644000175000017510000000126713625043307014157 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* point.h -- */ /* */ /* Memory mapped point allocation (header file) */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, April 2017, based on code from Magic */ /*--------------------------------------------------------------*/ #ifdef HAVE_SYS_MMAN_H #include #include /* Page size is 4KB so we mmap a segment equal to 64 pages */ #define POINT_STORE_BLOCK_SIZE (4 * 1024 * 64) extern POINT PointStoreFreeList; extern POINT PointStoreFreeList_end; #endif /* HAVE_SYS_MMAN_H */ extern POINT allocPOINT(); extern void freePOINT(POINT gp); qrouter-1.4.88/COPYRIGHT0000644000175000017510000003630713625043307014153 0ustar nileshnilesh GNU GENERAL PUBLIC LICENSE Version 2, June 1991 --------------------------------------------------------------------- Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. --------------------------------------------------------------------- Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. --------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) --------------------------------------------------------------------- These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. --------------------------------------------------------------------- 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. --------------------------------------------------------------------- 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS qrouter-1.4.88/maze.h0000644000175000017510000000257613625043307013766 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* maze.h -- details of maze router */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June 2011, based on work of Steve */ /* Beccue. */ /*--------------------------------------------------------------*/ #ifndef MAZE_H int set_powerbus_to_net(int netnum); int set_node_to_net(NODE node, int newnet, POINT *pushlist, SEG bbox, u_char stage); int disable_node_nets(NODE node); int set_routes_to_net(NODE node, NET net, int newnet, POINT *pushlist, SEG bbox, u_char stage); NODE find_unrouted_node(NET net); void remove_routes(ROUTE netroutes, u_char flagged); u_char ripup_net(NET net, u_char restore, u_char topmost, u_char retain); POINT eval_pt(GRIDP *ept, u_char flags, u_char stage); int commit_proute(ROUTE rt, GRIDP *ept, u_char stage); void writeback_segment(SEG seg, int netnum); int writeback_route(ROUTE rt); int writeback_all_routes(NET net); NETLIST find_colliding(NET net, int *ripnum); void clear_non_source_targets(NET net, POINT *pushlist); void clear_target_node(NODE node); int count_targets(NET net); int set_route_to_net(NET net, ROUTE rt, int newflags, POINT *pushlist, SEG bbox, u_char stage); void route_set_connections(NET net, ROUTE route); #define MAZE_H #endif /* end of maze.h */ qrouter-1.4.88/lef.c0000644000175000017510000032253214015133015013556 0ustar nileshnilesh/* * lef.c -- * * This module incorporates the LEF/DEF format for standard-cell routing * route. * * Version 0.1 (September 26, 2003): LEF input handling. Includes creation * of cells from macro statements, handling of pins, ports, obstructions, and * associated geometry. * * Written by Tim Edwards, Open Circuit Design * Modified June 2011 for use with qrouter. * * It is assumed that the "route.cfg" file has been called prior to this, and * so the basic linked lists have been created. The contents of the LEF file * will override anything in the route.cfg file, allowing the route.cfg file * to contain a minimum of information, but also allowing for the possibility * that there is no LEF file for the technology, and that all such information * is in the route.cfg file. */ #include #include #include #include #include #include #include #include #include "qrouter.h" #include "node.h" #include "qconfig.h" #include "maze.h" #include "lef.h" /* ---------------------------------------------------------------------*/ /* Current line number for reading */ int lefCurrentLine = 0; /* Information about routing layers */ LefList LefInfo = NULL; /* Information about what vias to use */ LinkedStringPtr AllowedVias = NULL; /* Gate information is in the linked list GateInfo, imported */ /*--------------------------------------------------------- * Lookup -- * Searches a table of strings to find one that matches a given * string. It's useful mostly for command lookup. * * Only the portion of a string in the table up to the first * blank character is considered significant for matching. * * Results: * If str is the same as * or an unambiguous abbreviation for one of the entries * in table, then the index of the matching entry is returned. * If str is not the same as any entry in the table, but * an abbreviation for more than one entry, * then -1 is returned. If str doesn't match any entry, then * -2 is returned. Case differences are ignored. * * NOTE: * Table entries need no longer be in alphabetical order * and they need not be lower case. The irouter command parsing * depends on these features. * * Side Effects: * None. *--------------------------------------------------------- */ int Lookup(str, table) char *str; /* Pointer to a string to be looked up */ char *(table[]); /* Pointer to an array of string pointers * which are the valid commands. * The end of * the table is indicated by a NULL string. */ { int match = -2; /* result, initialized to -2 = no match */ int pos; int ststart = 0; /* search for match */ for (pos=0; table[pos] != NULL; pos++) { char *tabc = table[pos]; char *strc = &(str[ststart]); while (*strc!='\0' && *tabc!=' ' && ((*tabc==*strc) || (isupper(*tabc) && islower(*strc) && (tolower(*tabc)== *strc))|| (islower(*tabc) && isupper(*strc) && (toupper(*tabc)== *strc)) )) { strc++; tabc++; } if (*strc=='\0') { /* entry matches */ if(*tabc==' ' || *tabc=='\0') { /* exact match - record it and terminate search */ match = pos; break; } else if (match == -2) { /* inexact match and no previous match - record this one * and continue search */ match = pos; } else { /* previous match, so string is ambiguous unless exact * match exists. Mark ambiguous for now, and continue * search. */ match = -1; } } } return(match); } /* * ---------------------------------------------------------------------------- * LookupFull -- * * Look up a string in a table of pointers to strings. The last * entry in the string table must be a NULL pointer. * This is much simpler than Lookup() in that it does not * allow abbreviations. It does, however, ignore case. * * Results: * Index of the name supplied in the table, or -1 if the name * is not found. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ int LookupFull(name, table) char *name; char **table; { char **tp; for (tp = table; *tp; tp++) { if (strcmp(name, *tp) == 0) return (tp - table); else { char *sptr, *tptr; for (sptr = name, tptr = *tp; ((*sptr != '\0') && (*tptr != '\0')); sptr++, tptr++) if (toupper(*sptr) != toupper(*tptr)) break; if ((*sptr == '\0') && (*tptr == '\0')) return (tp - table); } } return (-1); } /* *------------------------------------------------------------ * * LefNextToken -- * * Move to the next token in the stream input. * If "ignore_eol" is FALSE, then the end-of-line character * "\n" will be returned as a token when encountered. * Otherwise, end-of-line will be ignored. * * Results: * Pointer to next token to parse * * Side Effects: * May read a new line from the specified file. * * Warnings: * The return result of LefNextToken will be overwritten by * subsequent calls to LefNextToken if more than one line of * input is parsed. * *------------------------------------------------------------ */ char * LefNextToken(FILE *f, u_char ignore_eol) { static char line[LEF_LINE_MAX + 2]; /* input buffer */ static char *nexttoken = NULL; /* pointer to next token */ static char *curtoken; /* pointer to current token */ static char eol_token='\n'; /* Read a new line if necessary */ if (nexttoken == NULL) { for(;;) { if (fgets(line, LEF_LINE_MAX + 1, f) == NULL) return NULL; lefCurrentLine++; curtoken = line; while (isspace(*curtoken) && (*curtoken != '\n') && (*curtoken != '\0')) curtoken++; /* skip leading whitespace */ if ((*curtoken != '#') && (*curtoken != '\n') && (*curtoken != '\0')) { nexttoken = curtoken; break; } } if (!ignore_eol) return &eol_token; } else curtoken = nexttoken; /* Find the next token; set to NULL if none (end-of-line). */ /* Treat quoted material as a single token */ if (*nexttoken == '\"') { nexttoken++; while (((*nexttoken != '\"') || (*(nexttoken - 1) == '\\')) && (*nexttoken != '\0')) { if (*nexttoken == '\n') { if (fgets(nexttoken + 1, LEF_LINE_MAX - (size_t)(nexttoken - line), f) == NULL) return NULL; } nexttoken++; /* skip all in quotes (move past current token) */ } if (*nexttoken == '\"') nexttoken++; } else { while (!isspace(*nexttoken) && (*nexttoken != '\0') && (*nexttoken != '\n')) nexttoken++; /* skip non-whitespace (move past current token) */ } /* Terminate the current token */ if (*nexttoken != '\0') *nexttoken++ = '\0'; while (isspace(*nexttoken) && (*nexttoken != '\0') && (*nexttoken != '\n')) nexttoken++; /* skip any whitespace */ if ((*nexttoken == '#') || (*nexttoken == '\n') || (*nexttoken == '\0')) nexttoken = NULL; return curtoken; } /* *------------------------------------------------------------ * * LefError -- * * Print an error message (via fprintf) giving the line * number of the input file on which the error occurred. * * "type" should be either LEF_ERROR or LEF_WARNING (or DEF_*). * * Results: * None. * * Side Effects: * Prints to the output (stderr). * *------------------------------------------------------------ */ void LefError(int type, char *fmt, ...) { static int fatal = 0; static int nonfatal = 0; char lefordef = 'L'; int errors; va_list args; if (Verbose == 0) return; if ((type == DEF_WARNING) || (type == DEF_ERROR)) lefordef = 'D'; errors = fatal + nonfatal; if (fmt == NULL) /* Special case: report any errors and reset */ { if (errors > 0) { Fprintf(stdout, "%cEF Read: encountered %d error%s and %d warning%s total.\n", lefordef, fatal, (fatal == 1) ? "" : "s", nonfatal, (nonfatal == 1) ? "" : "s"); fatal = 0; nonfatal = 0; } return; } if (errors < LEF_MAX_ERRORS) { Fprintf(stderr, "%cEF Read, Line %d: ", lefordef, lefCurrentLine); va_start(args, fmt); Vprintf(stderr, fmt, args); va_end(args); Flush(stderr); } else if (errors == LEF_MAX_ERRORS) Fprintf(stderr, "%cEF Read: Further errors/warnings will not be reported.\n", lefordef); if ((type == LEF_ERROR) || (type == DEF_ERROR)) fatal++; else if ((type == LEF_WARNING) || (type == DEF_WARNING)) nonfatal++; } /* *------------------------------------------------------------ * * LefParseEndStatement -- * * Check if the string passed in "lineptr" contains the * appropriate matching keyword. Sections in LEF files * should end with "END (keyword)" or "END". To check * against the latter case, "match" should be NULL. * * Results: * TRUE if the line matches the expected end statement, * FALSE if not. * * Side effects: * None. * *------------------------------------------------------------ */ u_char LefParseEndStatement(FILE *f, char *match) { char *token; int keyword; char *match_name[2]; match_name[0] = match; match_name[1] = NULL; token = LefNextToken(f, (match == NULL) ? FALSE : TRUE); if (token == NULL) { LefError(LEF_ERROR, "Bad file read while looking for END statement\n"); return FALSE; } /* END or ENDEXT */ if ((*token == '\n') && (match == NULL)) return TRUE; /* END */ else { keyword = LookupFull(token, match_name); if (keyword == 0) return TRUE; else return FALSE; } } /* *------------------------------------------------------------ * * LefSkipSection -- * * Skip to the "END" record of a LEF input section * String "section" must follow the "END" statement in * the file to be considered a match; however, if * section = NULL, then "END" must have no strings * following. * * Results: * None. * * Side Effects: * Reads input from the specified file. Prints an * error message if the expected END record cannot * be found. * *------------------------------------------------------------ */ void LefSkipSection(FILE *f, char *section) { char *token; int keyword; static char *end_section[] = { "END", "ENDEXT", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { if ((keyword = Lookup(token, end_section)) == 0) { if (LefParseEndStatement(f, section)) return; } else if (keyword == 1) { if (!strcmp(section, "BEGINEXT")) return; } } LefError(LEF_ERROR, "Section %s has no END record!\n", section); return; } /* *------------------------------------------------------------ * * lefFindCell -- * * "name" is the name of the cell to search for. * Returns the GATE entry for the cell from the GateInfo * list. * *------------------------------------------------------------ */ GATE lefFindCell(char *name) { GATE gateginfo; for (gateginfo = GateInfo; gateginfo; gateginfo = gateginfo->next) { if (!strcasecmp(gateginfo->gatename, name)) return gateginfo; } return (GATE)NULL; } /* *------------------------------------------------------------ * * LefLower -- * * Convert a token in a LEF or DEF file to all-lowercase. * *------------------------------------------------------------ */ char * LefLower(char *token) { char *tptr; for (tptr = token; *tptr != '\0'; tptr++) *tptr = tolower(*tptr); return token; } /* *------------------------------------------------------------ * LefRedefined -- * * In preparation for redefining a LEF layer, we need * to first check if there are multiple names associated * with the lefLayer entry. If so, split the entry into * two copies, so that the redefinition doesn't affect * the other LEF names. * * Results: * Pointer to a lefLayer, which may or may not be the * same one presented to the subroutine. * * Side Effects: * May add an entry to the list of LEF layers. * *------------------------------------------------------------ */ LefList LefRedefined(LefList lefl, char *redefname) { LefList slef, newlefl; char *altName; int records; DSEG drect; /* check if more than one entry points to the same */ /* lefLayer record. If so, we will also record the */ /* name of the first type that is not the same as */ /* "redefname". */ records = 0; altName = NULL; for (slef = LefInfo; slef; slef = slef->next) { if (slef == lefl) records++; if (altName == NULL) if (strcmp(slef->lefName, redefname)) altName = (char *)slef->lefName; } if (records == 1) { /* Only one name associated with the record, so */ /* just clear all the allocated information. */ while (lefl->info.via.lr) { drect = lefl->info.via.lr->next; free(lefl->info.via.lr); lefl->info.via.lr = drect; } newlefl = lefl; } else { slef = LefFindLayer(redefname); newlefl = (LefList)malloc(sizeof(lefLayer)); newlefl->lefName = strdup(newlefl->lefName); newlefl->next = LefInfo; LefInfo = newlefl; /* If the canonical name of the original entry */ /* is "redefname", then change it. */ if (!strcmp(slef->lefName, redefname)) if (altName != NULL) slef->lefName = altName; } newlefl->type = -1; newlefl->obsType = -1; newlefl->info.via.area.x1 = 0.0; newlefl->info.via.area.x2 = 0.0; newlefl->info.via.area.y1 = 0.0; newlefl->info.via.area.y2 = 0.0; newlefl->info.via.area.layer = -1; newlefl->info.via.cell = (GATE)NULL; newlefl->info.via.lr = (DSEG)NULL; return newlefl; } /* *------------------------------------------------------------ * Find a layer record in the list of layers *------------------------------------------------------------ */ LefList LefFindLayer(char *token) { LefList lefl, rlefl; if (token == NULL) return NULL; rlefl = (LefList)NULL; for (lefl = LefInfo; lefl; lefl = lefl->next) { if (!strcmp(lefl->lefName, token)) { rlefl = lefl; break; } } return rlefl; } /* *------------------------------------------------------------ * Find a layer record in the list of layers, by layer number *------------------------------------------------------------ */ LefList LefFindLayerByNum(int layer) { LefList lefl, rlefl; rlefl = (LefList)NULL; for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->type == layer) { rlefl = lefl; break; } } return rlefl; } /* *------------------------------------------------------------ * Find a layer record in the list of layers, and return the * layer number. *------------------------------------------------------------ */ int LefFindLayerNum(char *token) { LefList lefl; lefl = LefFindLayer(token); if (lefl) return lefl->type; else return -1; } /* *--------------------------------------------------------------- * Find the maximum layer number defined by the LEF file * This includes layer numbers assigned to both routes and * via cut layers. *--------------------------------------------------------------- */ int LefGetMaxLayer(void) { int maxlayer = -1; LefList lefl; for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->type > maxlayer) maxlayer = lefl->type; } return (maxlayer + 1); } /* *--------------------------------------------------------------- * Find the maximum routing layer number defined by the LEF file *--------------------------------------------------------------- */ int LefGetMaxRouteLayer(void) { int maxlayer = -1; LefList lefl; for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass != CLASS_ROUTE) continue; if (lefl->type > maxlayer) maxlayer = lefl->type; } return (maxlayer + 1); } /* *------------------------------------------------------------ * Return the route keepout area, defined as the route space * plus 1/2 the route width. This is the distance outward * from an obstruction edge within which one cannot place a * route. * * If no route layer is defined, then we pick up the value * from information in the route.cfg file (if any). Here * we define it as the route pitch less 1/2 the route width, * which is the same as above if the route pitch has been * chosen for minimum spacing. * * If all else fails, return zero. *------------------------------------------------------------ */ double LefGetRouteKeepout(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.width / 2.0 + lefl->info.route.spacing->spacing; } } return MIN(PitchX, PitchY) - PathWidth[layer] / 2.0; } /* *------------------------------------------------------------ * Similar routine to the above. Return the route width for * a route layer. Return value in microns. If there is no * LEF file information about the route width, then return * half of the minimum route pitch. *------------------------------------------------------------ */ double LefGetRouteWidth(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.width; } } return MIN(PitchX, PitchY) / 2.0; } /* *------------------------------------------------------------ * Similar routine to the above. Return the route offset for * a route layer. Return value in microns. If there is no * LEF file information about the route offset, then return * half of the minimum route pitch. *------------------------------------------------------------ */ double LefGetRouteOffset(int layer) { LefList lefl; u_char o; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { o = lefl->info.route.hdirection; if (o == TRUE) return lefl->info.route.offsety; else return lefl->info.route.offsetx; } } return MIN(PitchX, PitchY) / 2.0; } double LefGetRouteOffsetX(int layer) { LefList lefl; u_char o; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.offsetx; } } return MIN(PitchX, PitchY) / 2.0; } double LefGetRouteOffsetY(int layer) { LefList lefl; u_char o; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.offsety; } } return PitchY / 2.0; } /* *------------------------------------------------------------ * Find and return the minimum metal area requirement for a * route layer. *------------------------------------------------------------ */ double LefGetRouteMinArea(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.minarea; } } return 0.0; /* Assume no minimum area requirement */ } /* *------------------------------------------------------------ * Determine and return the width of a via. The first layer * is the base (lower) layer of the via (e.g., layer 0, or * metal1, for via12). The second layer is the layer for * which we want the width rule (e.g., 0 or 1, for metal1 * or metal2). If dir = 0, return the side-to-side width, * otherwise, return the top-to-bottom width. This accounts * for non-square vias. * * Note that Via rectangles are stored with x2 dimensions * because the center can be on a half-grid position; so, * return half the value obtained. * * This routine always uses a horizontally oriented via if * available. See the specific LefGetXYViaWidth() routine * for differentiation between via orientations. *------------------------------------------------------------ */ double LefGetViaWidth(int base, int layer, int dir) { return LefGetXYViaWidth(base, layer, dir, 0); } /* *------------------------------------------------------------ * The base routine used by LefGetViaWidth(), with an * additional argument that specifies which via orientation * to use, if an alternative orientation is available. This * is necessary for doing checkerboard via patterning and for * certain standard cells with ports that do not always fit * one orientation of via. * * "orient" is defined as follows: * 0 = XX = both layers horizontal * 1 = XY = bottom layer horizontal, top layer vertical * 2 = YX = bottom layer vertical, top layer horizontal * 3 = YY = both layers vertical. * *------------------------------------------------------------ */ double LefGetXYViaWidth(int base, int layer, int dir, int orient) { DSEG lrect; LefList lefl; double width; char **viatable; switch (orient) { case 0: viatable = ViaXX; break; case 1: viatable = ViaXY; break; case 2: viatable = ViaYX; break; case 3: viatable = ViaYY; break; } if (*viatable == NULL) lefl = NULL; else lefl = LefFindLayer(*(viatable + base)); /* The routine LefAssignLayerVias() should assign all Via** types. */ /* Below are fallback assignments. */ if (!lefl) { switch (orient) { case 0: viatable = ViaXY; break; case 1: viatable = ViaYX; break; case 2: viatable = ViaYY; break; case 3: viatable = ViaYX; break; } lefl = LefFindLayer(*(viatable + base)); } if (!lefl) { switch (orient) { case 0: viatable = ViaYX; break; case 1: viatable = ViaYY; break; case 2: viatable = ViaXX; break; case 3: viatable = ViaXY; break; } lefl = LefFindLayer(*(viatable + base)); } if (!lefl) { switch (orient) { case 0: viatable = ViaYY; break; case 1: viatable = ViaYX; break; case 2: viatable = ViaXY; break; case 3: viatable = ViaXX; break; } lefl = LefFindLayer(*(viatable + base)); } if (lefl) { if (lefl->lefClass == CLASS_VIA) { if (lefl->info.via.area.layer == layer) { if (dir) width = lefl->info.via.area.y2 - lefl->info.via.area.y1; else width = lefl->info.via.area.x2 - lefl->info.via.area.x1; return width / 2.0; } for (lrect = lefl->info.via.lr; lrect; lrect = lrect->next) { if (lrect->layer == layer) { if (dir) width = lrect->y2 - lrect->y1; else width = lrect->x2 - lrect->x1; return width / 2.0; } } } } return MIN(PitchX, PitchY) / 2.0; // Best guess } /* *------------------------------------------------------------ * And another such routine, for route spacing (minimum width) *------------------------------------------------------------ */ double LefGetRouteSpacing(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { if (lefl->info.route.spacing) return lefl->info.route.spacing->spacing; else return 0.0; } } return MIN(PitchX, PitchY) / 2.0; } /* *------------------------------------------------------------ * Find route spacing to a metal layer of specific width *------------------------------------------------------------ */ double LefGetRouteWideSpacing(int layer, double width) { LefList lefl; lefSpacingRule *srule; double spacing; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { // Prepare a default in case of bad values spacing = lefl->info.route.spacing->spacing; for (srule = lefl->info.route.spacing; srule; srule = srule->next) { if (srule->width > width) break; spacing = srule->spacing; } return spacing; } } return MIN(PitchX, PitchY) / 2.0; } /* *----------------------------------------------------------------- * Get the route pitch in the preferred direction for a given layer *----------------------------------------------------------------- */ double LefGetRoutePitch(int layer) { LefList lefl; u_char o; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { o = lefl->info.route.hdirection; if (o == TRUE) return lefl->info.route.pitchy; else return lefl->info.route.pitchx; } } return MIN(PitchX, PitchY); } /* *------------------------------------------------------------ * Get the route pitch in X for a given layer *------------------------------------------------------------ */ double LefGetRoutePitchX(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.pitchx; } } return PitchX; } /* *------------------------------------------------------------ * Get the route pitch in Y for a given layer *------------------------------------------------------------ */ double LefGetRoutePitchY(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.pitchy; } } return PitchY; } /* *------------------------------------------------------------ * Set the route pitch in X for a given layer *------------------------------------------------------------ */ void LefSetRoutePitchX(int layer, double value) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { lefl->info.route.pitchx = value; } } } /* *------------------------------------------------------------ * Set the route pitch in Y for a given layer *------------------------------------------------------------ */ void LefSetRoutePitchY(int layer, double value) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { lefl->info.route.pitchy = value; } } } /* *------------------------------------------------------------ * Get the route name for a given layer *------------------------------------------------------------ */ char * LefGetRouteName(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->lefName; } } return NULL; } /* *------------------------------------------------------------ * Get the route orientation for the given layer, * where the result is 1 for horizontal, 0 for vertical, and * -1 if the layer is not found. *------------------------------------------------------------ */ int LefGetRouteOrientation(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return (int)lefl->info.route.hdirection; } } return -1; } /* *------------------------------------------------------------ * Get the route resistance and capacitance information. * Fill in the pointer values with the relevant information. * Return 0 on success, -1 if the layer is not found. *------------------------------------------------------------ */ int LefGetRouteRCvalues(int layer, double *areacap, double *edgecap, double *respersq) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { *areacap = (double)lefl->info.route.areacap; *edgecap = (double)lefl->info.route.edgecap; *respersq = (double)lefl->info.route.respersq; return 0; } } return -1; } /* *------------------------------------------------------------ * Get the antenna violation area ratio for the given layer. *------------------------------------------------------------ */ double LefGetRouteAreaRatio(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.antenna; } } return 0.0; } /* *------------------------------------------------------------ * Get the antenna violation area calculation method for the * given layer. *------------------------------------------------------------ */ u_char LefGetRouteAntennaMethod(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.method; } } return CALC_NONE; } /* *------------------------------------------------------------ * Get the route metal layer thickness (if any is defined) *------------------------------------------------------------ */ double LefGetRouteThickness(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.thick; } } return 0.0; } /* *------------------------------------------------------------ * Get resistance per via for a via layer. * Return 0 on success, -1 if the layer is not found. * Fill in the pointer value with the resistance. *------------------------------------------------------------ */ int LefGetViaResistance(int layer, double *respervia) { DSEG lrect; LefList lefl; double width; char **viatable = ViaXX; lefl = LefFindLayer(*(viatable + layer)); if (!lefl) { viatable = ViaXY; lefl = LefFindLayer(*(viatable + layer)); } if (!lefl) { viatable = ViaYX; lefl = LefFindLayer(*(viatable + layer)); } if (!lefl) { viatable = ViaYY; lefl = LefFindLayer(*(viatable + layer)); } if (lefl) { if (lefl->lefClass == CLASS_VIA) { *respervia = (double)lefl->info.via.respervia; return 0; } } return -1; } /* *------------------------------------------------------------ * LefReadLayers -- * * Read a LEF "LAYER" record from the file. * If "obstruct" is TRUE, returns the layer mapping * for obstruction geometry as defined in the * technology file (if it exists), and up to two * types are returned (the second in the 3rd argument * pointer). * * Results: * Returns layer number or -1 if no matching type is found. * * Side Effects: * Reads input from file f; * *------------------------------------------------------------ */ int LefReadLayers(f, obstruct, lreturn) FILE *f; u_char obstruct; int *lreturn; { char *token; int curlayer = -1; LefList lefl = NULL; token = LefNextToken(f, TRUE); if (*token == ';') { LefError(LEF_ERROR, "Bad Layer statement\n"); return -1; } else { lefl = LefFindLayer(token); if (lefl) { if (obstruct) { /* Use the obstruction type, if it is defined */ curlayer = lefl->obsType; if ((curlayer < 0) && (lefl->lefClass != CLASS_IGNORE)) curlayer = lefl->type; else if (lefl->lefClass == CLASS_VIA || lefl->lefClass == CLASS_CUT) if (lreturn) *lreturn = lefl->info.via.obsType; } else { if (lefl->lefClass != CLASS_IGNORE) curlayer = lefl->type; } } if ((curlayer < 0) && ((!lefl) || (lefl->lefClass != CLASS_IGNORE))) { /* CLASS_VIA in lefl record is a cut, and the layer */ /* geometry is ignored for the purpose of routing. */ if (lefl && (lefl->lefClass == CLASS_CUT)) { int cuttype; /* By the time a cut layer is being requested, */ /* presumably from a VIA definition, the route */ /* layers should all be defined, so start */ /* assigning layers to cuts. */ /* If a cut layer is found with an unassigned number, */ /* then assign it here. */ cuttype = LefGetMaxLayer(); if (cuttype < MAX_TYPES) { lefl->type = cuttype; curlayer = cuttype; strcpy(CIFLayer[cuttype], lefl->lefName); } else LefError(LEF_WARNING, "Too many cut types; type \"%s\" ignored.\n", token); } else if ((!lefl) || (lefl->lefClass != CLASS_VIA)) LefError(LEF_ERROR, "Don't know how to parse layer \"%s\"\n", token); } } return curlayer; } /* *------------------------------------------------------------ * LefReadLayer -- * * Read a LEF "LAYER" record from the file. * If "obstruct" is TRUE, returns the layer mapping * for obstruction geometry as defined in the * technology file (if it exists). * * Results: * Returns a layer number or -1 if no match is found. * * Side Effects: * Reads input from file f; * *------------------------------------------------------------ */ int LefReadLayer(FILE *f, u_char obstruct) { return LefReadLayers(f, obstruct, (int *)NULL); } /* *------------------------------------------------------------ * LefReadLefPoint -- * * Read a LEF point record from the file, and * return values for X and Y in the pointer arguments. * * Results: * 0 on success, 1 on error. * * Side Effects: * Reads input from file f; * Writes values for the X and Y coordinates into the * pointer arguments. * * Note: * LEF/DEF does NOT define a RECT record as having (...) * pairs, only routes. However, at least one DEF file * contains this syntax, so it is checked. * *------------------------------------------------------------ */ int LefReadLefPoint(FILE *f, float *x, float *y) { char *token; u_char needMatch = FALSE; token = LefNextToken(f, TRUE); if (!token) return 1; else if (*token == '(') { token = LefNextToken(f, TRUE); needMatch = TRUE; } if (!token || sscanf(token, "%f", x) != 1) return 1; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", y) != 1) return 1; if (needMatch) { token = LefNextToken(f, TRUE); if (*token != ')') return 1; } return 0; } /* *------------------------------------------------------------ * LefReadRect -- * * Read a LEF "RECT" record from the file, and * return a Rect in micron coordinates. * * Results: * Returns a pointer to a Rect containing the micron * coordinates, or NULL if an error occurred. * * Side Effects: * Reads input from file f; * * Note: * LEF/DEF does NOT define a RECT record as having (...) * pairs, only routes. However, at least one DEF file * contains this syntax, so it is checked. * *------------------------------------------------------------ */ DSEG LefReadRect(FILE *f, int curlayer, float oscale) { char *token; float llx, lly, urx, ury; static struct dseg_ paintrect; u_char needMatch = FALSE; token = LefNextToken(f, TRUE); if (*token == '(') { token = LefNextToken(f, TRUE); needMatch = TRUE; } if (!token || sscanf(token, "%f", &llx) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &lly) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (needMatch) { if (*token != ')') goto parse_error; else token = LefNextToken(f, TRUE); needMatch = FALSE; } if (*token == '(') { token = LefNextToken(f, TRUE); needMatch = TRUE; } if (!token || sscanf(token, "%f", &urx) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &ury) != 1) goto parse_error; if (needMatch) { token = LefNextToken(f, TRUE); if (*token != ')') goto parse_error; } if (curlayer < 0) { /* Issue warning but keep geometry with negative layer number */ LefError(LEF_WARNING, "No layer defined for RECT.\n"); } /* Scale coordinates (microns to centimicrons) */ paintrect.x1 = llx / oscale; paintrect.y1 = lly / oscale; paintrect.x2 = urx / oscale; paintrect.y2 = ury / oscale; paintrect.layer = curlayer; return (&paintrect); parse_error: LefError(LEF_ERROR, "Bad port geometry: RECT requires 4 values.\n"); return (DSEG)NULL; } /* *------------------------------------------------------------ * LefReadEnclosure -- * * Read a LEF "ENCLOSURE" record from the file, and * return a Rect in micron coordinates, representing * the bounding box of the stated enclosure dimensions * in both directions, centered on the origin. * * Results: * Returns a pointer to a Rect containing the micron * coordinates, or NULL if an error occurred. * * Side Effects: * Reads input from file f * *------------------------------------------------------------ */ DSEG LefReadEnclosure(FILE *f, int curlayer, float oscale) { char *token; float x, y, scale; static struct dseg_ paintrect; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &x) != 1) goto enc_parse_error; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &y) != 1) goto enc_parse_error; if (curlayer < 0) { /* Issue warning but keep geometry with negative layer number */ LefError(LEF_ERROR, "No layer defined for RECT.\n"); } /* Scale coordinates (microns to centimicrons) (doubled) */ scale = oscale / 2.0; paintrect.x1 = -x / scale; paintrect.y1 = -y / scale; paintrect.x2 = x / scale; paintrect.y2 = y / scale; paintrect.layer = curlayer; return (&paintrect); enc_parse_error: LefError(LEF_ERROR, "Bad enclosure geometry: ENCLOSURE requires 2 values.\n"); return (DSEG)NULL; } /* *------------------------------------------------------------ * Support routines for polygon reading *------------------------------------------------------------ */ #define HEDGE 0 /* Horizontal edge */ #define REDGE 1 /* Rising edge */ #define FEDGE -1 /* Falling edge */ /* *------------------------------------------------------------ * lefLowX --- * * Sort routine to find the lowest X coordinate between * two DPOINT structures passed from qsort() *------------------------------------------------------------ */ int lefLowX(DPOINT *a, DPOINT *b) { DPOINT p = *a; DPOINT q = *b; if (p->x < q->x) return (-1); if (p->x > q->x) return (1); return (0); } /* *------------------------------------------------------------ * lefLowY --- * * Sort routine to find the lowest Y coordinate between * two DPOINT structures passed from qsort() *------------------------------------------------------------ */ int lefLowY(DPOINT *a, DPOINT *b) { DPOINT p = *a; DPOINT q = *b; if (p->y < q->y) return (-1); if (p->y > q->y) return (1); return (0); } /* *------------------------------------------------------------ * lefOrient --- * * Assign a direction to each of the edges in a polygon. * * Note that edges have been sorted, but retain the original * linked list pointers, from which we can determine the * path orientation * *------------------------------------------------------------ */ char lefOrient(DPOINT *edges, int nedges, int *dir) { int n; DPOINT p, q; for (n = 0; n < nedges; n++) { p = edges[n]; q = edges[n]->next; if (p->y == q->y) { dir[n] = HEDGE; continue; } if (p->x == q->x) { if (p->y < q->y) { dir[n] = REDGE; continue; } if (p->y > q->y) { dir[n] = FEDGE; continue; } /* Point connects to itself */ dir[n] = HEDGE; continue; } /* It's not Manhattan, folks. */ return (FALSE); } return (TRUE); } /* *------------------------------------------------------------ * lefCross --- * * See if an edge crosses a particular area. * Return TRUE if edge if vertical and if it crosses the * y-range defined by ybot and ytop. Otherwise return * FALSE. *------------------------------------------------------------ */ char lefCross(DPOINT edge, int dir, double ybot, double ytop) { double ebot, etop; switch (dir) { case REDGE: ebot = edge->y; etop = edge->next->y; return (ebot <= ybot && etop >= ytop); case FEDGE: ebot = edge->next->y; etop = edge->y; return (ebot <= ybot && etop >= ytop); } return (FALSE); } /* *------------------------------------------------------------ * LefPolygonToRects -- * * Convert Geometry information from a POLYGON statement * into rectangles. NOTE: For now, this routine * assumes that all points are Manhattan. It will flag * non-Manhattan geometry * * the DSEG pointed to by rectListPtr is updated by * having the list of rectangles appended to it. * *------------------------------------------------------------ */ void LefPolygonToRects(DSEG *rectListPtr, DPOINT pointlist) { DPOINT ptail, p, *pts, *edges; DSEG rtail, rex, new; int npts = 0; int *dir; int curr, wrapno, n; double xbot, xtop, ybot, ytop; if (pointlist == NULL) return; /* Close the path by duplicating 1st point if necessary */ for (ptail = pointlist; ptail->next; ptail = ptail->next); if ((ptail->x != pointlist->x) || (ptail->y != pointlist->y)) { p = (DPOINT)malloc(sizeof(struct dpoint_)); p->x = pointlist->x; p->y = pointlist->y; p->layer = pointlist->layer; p->next = NULL; ptail->next = p; } // To do: Break out non-manhattan parts here. // See CIFMakeManhattanPath in magic-8.0 rex = NULL; for (p = pointlist; p->next; p = p->next, npts++); pts = (DPOINT *)malloc(npts * sizeof(DPOINT)); edges = (DPOINT *)malloc(npts * sizeof(DPOINT)); dir = (int *)malloc(npts * sizeof(int)); npts = 0; for (p = pointlist; p->next; p = p->next, npts++) { // pts and edges are two lists of pointlist entries // that are NOT linked lists and can be shuffled // around by qsort(). The linked list "next" pointers // *must* be retained. pts[npts] = p; edges[npts] = p; } if (npts < 4) { LefError(LEF_ERROR, "Polygon with fewer than 4 points.\n"); goto done; } /* Sort points by low y, edges by low x */ qsort((char *)pts, npts, (int)sizeof(DPOINT), (__compar_fn_t)lefLowY); qsort((char *)edges, npts, (int)sizeof(DPOINT), (__compar_fn_t)lefLowX); /* Find out which direction each edge points */ if (!lefOrient(edges, npts, dir)) { LefError(LEF_ERROR, "I can't handle non-manhattan polygons!\n"); goto done; } /* Scan the polygon from bottom to top. At each step, process * a minimum-sized y-range of the polygon (i.e., a range such that * there are no vertices inside the range). Use wrap numbers * based on the edge orientations to determine how much of the * x-range for this y-range should contain material. */ for (curr = 1; curr < npts; curr++) { /* Find the next minimum-sized y-range. */ ybot = pts[curr - 1]->y; while (ybot == pts[curr]->y) if (++curr >= npts) goto done; ytop = pts[curr]->y; /* Process all the edges that cross the y-range, from left * to right. */ for (wrapno = 0, n = 0; n < npts; n++) { if (wrapno == 0) xbot = edges[n]->x; if (!lefCross(edges[n], dir[n], ybot, ytop)) continue; wrapno += (dir[n] == REDGE) ? 1 : -1; if (wrapno == 0) { xtop = edges[n]->x; if (xbot == xtop) continue; new = (DSEG)malloc(sizeof(struct dseg_)); new->x1 = xbot; new->x2 = xtop; new->y1 = ybot; new->y2 = ytop; new->layer = edges[n]->layer; new->next = rex; rex = new; } } } done: free(edges); free(dir); free(pts); if (*rectListPtr == NULL) *rectListPtr = rex; else { for (rtail = *rectListPtr; rtail->next; rtail = rtail->next); rtail->next = rex; } } /* *------------------------------------------------------------ * LefReadPolygon -- * * Read Geometry information from a POLYGON statement * *------------------------------------------------------------ */ DPOINT LefReadPolygon(FILE *f, int curlayer, float oscale) { DPOINT plist = NULL, newPoint; char *token; double px, py; if (curlayer >= Num_layers) return (DPOINT)NULL; while (1) { token = LefNextToken(f, TRUE); if (token == NULL || *token == ';') break; if (sscanf(token, "%lg", &px) != 1) { LefError(LEF_ERROR, "Bad X value in polygon.\n"); LefEndStatement(f); break; } token = LefNextToken(f, TRUE); if (token == NULL || *token == ';') { LefError(LEF_ERROR, "Missing Y value in polygon point!\n"); break; } if (sscanf(token, "%lg", &py) != 1) { LefError(LEF_ERROR, "Bad Y value in polygon.\n"); LefEndStatement(f); break; } newPoint = (DPOINT)malloc(sizeof(struct dpoint_)); newPoint->x = px / (double)oscale; newPoint->y = py / (double)oscale; newPoint->layer = curlayer; newPoint->next = plist; plist = newPoint; } return plist; } /* *------------------------------------------------------------ * LefReadGeometry -- * * Read Geometry information from a LEF file. * Used for PORT records and OBS statements. * * Results: * Returns a linked list of all areas and types * painted. * * Side Effects: * Reads input from file f; * Paints into the GATE lefMacro. * *------------------------------------------------------------ */ enum lef_geometry_keys {LEF_LAYER = 0, LEF_WIDTH, LEF_PATH, LEF_RECT, LEF_POLYGON, LEF_VIA, LEF_PORT_CLASS, LEF_GEOMETRY_END}; DSEG LefReadGeometry(GATE lefMacro, FILE *f, float oscale) { int curlayer = -1, otherlayer = -1; char *token; int keyword; DSEG rectList = (DSEG)NULL; DSEG paintrect, newRect; DPOINT pointlist; static char *geometry_keys[] = { "LAYER", "WIDTH", "PATH", "RECT", "POLYGON", "VIA", "CLASS", "END", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, geometry_keys); if (keyword < 0) { LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_LAYER: curlayer = LefReadLayers(f, FALSE, &otherlayer); LefEndStatement(f); break; case LEF_WIDTH: LefEndStatement(f); break; case LEF_PATH: LefEndStatement(f); break; case LEF_RECT: paintrect = (curlayer < 0) ? NULL : LefReadRect(f, curlayer, oscale); if (paintrect) { /* Remember the area and layer */ newRect = (DSEG)malloc(sizeof(struct dseg_)); *newRect = *paintrect; newRect->next = rectList; rectList = newRect; } LefEndStatement(f); break; case LEF_POLYGON: pointlist = LefReadPolygon(f, curlayer, oscale); LefPolygonToRects(&rectList, pointlist); break; case LEF_VIA: LefEndStatement(f); break; case LEF_PORT_CLASS: LefEndStatement(f); break; case LEF_GEOMETRY_END: if (!LefParseEndStatement(f, NULL)) { LefError(LEF_ERROR, "Geometry (PORT or OBS) END statement missing.\n"); keyword = -1; } break; } if (keyword == LEF_GEOMETRY_END) break; } return rectList; } /* *------------------------------------------------------------ * LefReadPort -- * * A wrapper for LefReadGeometry, which adds a label * to the last rectangle generated by the geometry * parsing. * * Results: * None. * * Side Effects: * Reads input from file f; * Paints into the GATE lefMacro. * *------------------------------------------------------------ */ void LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, pinArea, oscale) GATE lefMacro; FILE *f; char *pinName; int pinNum, pinDir, pinUse; double pinArea; float oscale; { DSEG rectList, rlist; rectList = LefReadGeometry(lefMacro, f, oscale); if (pinNum >= 0) { int nodealloc, orignodes; if (lefMacro->nodes <= pinNum) { orignodes = lefMacro->nodes; lefMacro->nodes = (pinNum + 1); nodealloc = lefMacro->nodes / 10; if (nodealloc > (orignodes / 10)) { nodealloc++; lefMacro->taps = (DSEG *)realloc(lefMacro->taps, nodealloc * 10 * sizeof(DSEG)); lefMacro->noderec = (NODE *)realloc(lefMacro->noderec, nodealloc * 10 * sizeof(NODE)); lefMacro->direction = (u_char *)realloc(lefMacro->direction, nodealloc * 10 * sizeof(u_char)); lefMacro->area = (float *)realloc(lefMacro->area, nodealloc * 10 * sizeof(float)); lefMacro->netnum = (int *)realloc(lefMacro->netnum, nodealloc * 10 * sizeof(int)); lefMacro->node = (char **)realloc(lefMacro->node, nodealloc * 10 * sizeof(char *)); } } lefMacro->taps[pinNum] = rectList; lefMacro->noderec[pinNum] = NULL; lefMacro->area[pinNum] = 0.0; lefMacro->direction[pinNum] = pinDir; lefMacro->area[pinNum] = pinArea; lefMacro->netnum[pinNum] = -1; if (pinName != NULL) lefMacro->node[pinNum] = strdup(pinName); else lefMacro->node[pinNum] = NULL; } else { while (rectList) { rlist = rectList->next; free(rectList); rectList = rlist; } } } /* *------------------------------------------------------------ * LefReadPin -- * * Read a PIN statement from a LEF file. * * Results: * 0 if the pin had a port (success), 1 if not (indicating * an unused pin that should be ignored). * * Side Effects: * Reads input from file f; * Paints into the GATE lefMacro. * *------------------------------------------------------------ */ enum lef_pin_keys {LEF_DIRECTION = 0, LEF_USE, LEF_PORT, LEF_CAPACITANCE, LEF_ANTENNADIFF, LEF_ANTENNAGATE, LEF_ANTENNAMOD, LEF_ANTENNAPAR, LEF_ANTENNAPARSIDE, LEF_ANTENNAMAX, LEF_ANTENNAMAXSIDE, LEF_SHAPE, LEF_NETEXPR, LEF_PIN_END}; int LefReadPin(lefMacro, f, pinname, pinNum, oscale) GATE lefMacro; FILE *f; char *pinname; int pinNum; float oscale; { char *token; int keyword, subkey; int pinDir = PORT_CLASS_DEFAULT; int pinUse = PORT_USE_DEFAULT; float pinArea = 0.0; int retval = 1; static char *pin_keys[] = { "DIRECTION", "USE", "PORT", "CAPACITANCE", "ANTENNADIFFAREA", "ANTENNAGATEAREA", "ANTENNAMODEL", "ANTENNAPARTIALMETALAREA", "ANTENNAPARTIALMETALSIDEAREA", "ANTENNAMAXAREACAR", "ANTENNAMAXSIDEAREACAR", "SHAPE", "NETEXPR", "END", NULL }; static char *pin_classes[] = { "DEFAULT", "INPUT", "OUTPUT", "OUTPUT TRISTATE", "INOUT", "FEEDTHRU", NULL }; static int lef_class_to_bitmask[] = { PORT_CLASS_DEFAULT, PORT_CLASS_INPUT, PORT_CLASS_OUTPUT, PORT_CLASS_TRISTATE, PORT_CLASS_BIDIRECTIONAL, PORT_CLASS_FEEDTHROUGH }; static char *pin_uses[] = { "DEFAULT", "SIGNAL", "ANALOG", "POWER", "GROUND", "CLOCK", "TIEOFF", "ANALOG", "SCAN", "RESET", NULL }; static int lef_use_to_bitmask[] = { PORT_USE_DEFAULT, PORT_USE_SIGNAL, PORT_USE_ANALOG, PORT_USE_POWER, PORT_USE_GROUND, PORT_USE_CLOCK }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, pin_keys); if (keyword < 0) { LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_DIRECTION: token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_classes); if (subkey < 0) LefError(LEF_ERROR, "Improper DIRECTION statement\n"); else pinDir = lef_class_to_bitmask[subkey]; LefEndStatement(f); break; case LEF_USE: token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_uses); if (subkey < 0) LefError(LEF_ERROR, "Improper USE statement\n"); else pinUse = lef_use_to_bitmask[subkey]; LefEndStatement(f); break; case LEF_PORT: LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse, pinArea, oscale); retval = 0; break; case LEF_ANTENNAGATE: /* Read off the next value as the pin's antenna gate area. */ /* The layers or layers are not recorded. */ token = LefNextToken(f, TRUE); sscanf(token, "%g", &pinArea); LefEndStatement(f); break; case LEF_CAPACITANCE: case LEF_ANTENNADIFF: case LEF_ANTENNAMOD: case LEF_ANTENNAPAR: case LEF_ANTENNAPARSIDE: case LEF_ANTENNAMAX: case LEF_ANTENNAMAXSIDE: case LEF_NETEXPR: case LEF_SHAPE: LefEndStatement(f); /* Ignore. . . */ break; case LEF_PIN_END: if (!LefParseEndStatement(f, pinname)) { LefError(LEF_ERROR, "Pin END statement missing.\n"); keyword = -1; } break; } if (keyword == LEF_PIN_END) break; } return retval; } /* *------------------------------------------------------------ * LefEndStatement -- * * Read file input to EOF or a ';' token (end-of-statement) * If we encounter a quote, make sure we don't terminate * the statement on a semicolon that is part of the * quoted material. * *------------------------------------------------------------ */ void LefEndStatement(FILE *f) { char *token; while ((token = LefNextToken(f, TRUE)) != NULL) if (*token == ';') break; } /* *------------------------------------------------------------ * * LefReadMacro -- * * Read in a MACRO section from a LEF file. * * Results: * None. * * Side Effects: * Creates a new cell definition in the database. * *------------------------------------------------------------ */ enum lef_macro_keys {LEF_CLASS = 0, LEF_SIZE, LEF_ORIGIN, LEF_SYMMETRY, LEF_SOURCE, LEF_SITE, LEF_PIN, LEF_OBS, LEF_TIMING, LEF_FOREIGN, LEF_MACRO_END}; void LefReadMacro(f, mname, oscale) FILE *f; /* LEF file being read */ char *mname; /* name of the macro */ float oscale; /* scale factor to um, usually 1 */ { GATE lefMacro, altMacro; char *token, tsave[128]; int keyword, pinNum; float x, y; u_char has_size, is_imported = FALSE; struct dseg_ lefBBox; static char *macro_keys[] = { "CLASS", "SIZE", "ORIGIN", "SYMMETRY", "SOURCE", "SITE", "PIN", "OBS", "TIMING", "FOREIGN", "END", NULL }; /* Start by creating a new celldef */ lefMacro = (GATE)NULL; for (altMacro = GateInfo; altMacro; altMacro = altMacro->next) { if (!strcmp(altMacro->gatename, mname)) { lefMacro = altMacro; break; } } while (lefMacro) { int suffix; char newname[256]; altMacro = lefMacro; for (suffix = 1; altMacro != NULL; suffix++) { sprintf(newname, "%250s_%d", mname, suffix); for (altMacro = GateInfo; altMacro; altMacro = altMacro->next) if (!strcmp(altMacro->gatename, newname)) break; } LefError(LEF_WARNING, "Cell \"%s\" was already defined in this file. " "Renaming original cell \"%s\"\n", mname, newname); lefMacro->gatename = strdup(newname); lefMacro = lefFindCell(mname); } // Create the new cell lefMacro = (GATE)malloc(sizeof(struct gate_)); lefMacro->gatename = strdup(mname); lefMacro->gatetype = NULL; lefMacro->width = 0.0; lefMacro->height = 0.0; lefMacro->placedX = 0.0; lefMacro->placedY = 0.0; lefMacro->obs = (DSEG)NULL; lefMacro->next = GateInfo; lefMacro->nodes = 0; lefMacro->orient = 0; // Allocate memory for up to 10 pins initially lefMacro->taps = (DSEG *)malloc(10 * sizeof(DSEG)); lefMacro->noderec = (NODE *)malloc(10 * sizeof(NODE)); lefMacro->direction = (u_char *)malloc(10 * sizeof(u_char)); lefMacro->area = (float *)malloc(10 * sizeof(float)); lefMacro->netnum = (int *)malloc(10 * sizeof(int)); lefMacro->node = (char **)malloc(10 * sizeof(char *)); // Fill in 1st entry lefMacro->taps[0] = NULL; lefMacro->noderec[0] = NULL; lefMacro->area[0] = 0.0; lefMacro->node[0] = NULL; lefMacro->netnum[0] = -1; GateInfo = lefMacro; /* Initial values */ pinNum = 0; has_size = FALSE; lefBBox.x2 = lefBBox.x1 = 0.0; lefBBox.y2 = lefBBox.y1 = 0.0; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, macro_keys); if (keyword < 0) { LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_CLASS: token = LefNextToken(f, TRUE); if (*token != '\n') // DBPropPut(lefMacro, "LEFclass", token); ; LefEndStatement(f); break; case LEF_SIZE: token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &x) != 1) goto size_error; token = LefNextToken(f, TRUE); /* skip keyword "BY" */ if (!token) goto size_error; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &y) != 1) goto size_error; lefBBox.x2 = x + lefBBox.x1; lefBBox.y2 = y + lefBBox.y1; has_size = TRUE; LefEndStatement(f); break; size_error: LefError(LEF_ERROR, "Bad macro SIZE; requires values X BY Y.\n"); LefEndStatement(f); break; case LEF_ORIGIN: if (LefReadLefPoint(f, &x, &y) != 0) goto origin_error; lefBBox.x1 = -x; lefBBox.y1 = -y; if (has_size) { lefBBox.x2 += lefBBox.x1; lefBBox.y2 += lefBBox.y1; } LefEndStatement(f); break; origin_error: LefError(LEF_ERROR, "Bad macro ORIGIN; requires 2 values.\n"); LefEndStatement(f); break; case LEF_SYMMETRY: token = LefNextToken(f, TRUE); if (*token != '\n') // DBPropPut(lefMacro, "LEFsymmetry", token + strlen(token) + 1); ; LefEndStatement(f); break; case LEF_SOURCE: token = LefNextToken(f, TRUE); if (*token != '\n') // DBPropPut(lefMacro, "LEFsource", token); ; LefEndStatement(f); break; case LEF_SITE: token = LefNextToken(f, TRUE); if (*token != '\n') // DBPropPut(lefMacro, "LEFsite", token); ; LefEndStatement(f); break; case LEF_PIN: token = LefNextToken(f, TRUE); /* Diagnostic */ /* Fprintf(stdout, " Macro defines pin %s\n", token); */ sprintf(tsave, "%.127s", token); if (is_imported) LefSkipSection(f, tsave); else if (LefReadPin(lefMacro, f, tsave, pinNum, oscale) == 0) pinNum++; break; case LEF_OBS: /* Diagnostic */ /* Fprintf(stdout, " Macro defines obstruction\n"); */ if (is_imported) LefSkipSection(f, NULL); else lefMacro->obs = LefReadGeometry(lefMacro, f, oscale); break; case LEF_TIMING: LefSkipSection(f, macro_keys[LEF_TIMING]); break; case LEF_FOREIGN: LefEndStatement(f); break; case LEF_MACRO_END: if (!LefParseEndStatement(f, mname)) { LefError(LEF_ERROR, "Macro END statement missing.\n"); keyword = -1; } break; } if (keyword == LEF_MACRO_END) break; } /* Finish up creating the cell */ if (lefMacro) { if (has_size) { lefMacro->width = (lefBBox.x2 - lefBBox.x1); lefMacro->height = (lefBBox.y2 - lefBBox.y1); /* "placed" for macros (not instances) corresponds to the */ /* cell origin. */ lefMacro->placedX = lefBBox.x1; lefMacro->placedY = lefBBox.y1; } else { LefError(LEF_ERROR, "Gate %s has no size information!\n", lefMacro->gatename); } } } /* *------------------------------------------------------------ * * LefAddViaGeometry -- * * Read in geometry for a VIA section from a LEF or DEF * file. * * f LEF file being read * lefl pointer to via info * curlayer current tile type * oscale output scaling * * Results: * None. * * Side Effects: * Adds to the lefLayer record for a via definition. * *------------------------------------------------------------ */ void LefAddViaGeometry(FILE *f, LefList lefl, int curlayer, float oscale) { DSEG currect; DSEG viarect; /* Rectangles for vias are read in units of 1/2 lambda */ currect = LefReadRect(f, curlayer, (oscale / 2)); if (currect == NULL) return; /* First rect goes into info.via.area, others go into info.via.lr */ if (lefl->info.via.area.layer < 0) { lefl->info.via.area = *currect; /* If entries exist for info.via.lr, this is a via GENERATE */ /* statement, and metal enclosures have been parsed. Therefore */ /* add the via dimensions to the enclosure rectangles. */ viarect = lefl->info.via.lr; while (viarect != NULL) { viarect->x1 += currect->x1; viarect->x2 += currect->x2; viarect->y1 += currect->y1; viarect->y2 += currect->y2; viarect = viarect->next; } } else { viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *currect; viarect->next = lefl->info.via.lr; lefl->info.via.lr = viarect; } } /* *------------------------------------------------------------ * * LefNewRoute --- * * Allocate space for and fill out default records of a * route layer. * *------------------------------------------------------------ */ LefList LefNewRoute(char *name) { LefList lefl; lefl = (LefList)malloc(sizeof(lefLayer)); lefl->type = -1; lefl->obsType = -1; lefl->lefClass = CLASS_IGNORE; /* For starters */ lefl->lefName = strdup(name); return lefl; } /* *------------------------------------------------------------ * * LefNewVia --- * * Allocate space for and fill out default records of a * via definition. * *------------------------------------------------------------ */ LefList LefNewVia(char *name) { LefList lefl; lefl = (LefList)calloc(1, sizeof(lefLayer)); lefl->type = -1; lefl->obsType = -1; lefl->lefClass = CLASS_VIA; lefl->info.via.area.x1 = 0.0; lefl->info.via.area.y1 = 0.0; lefl->info.via.area.x2 = 0.0; lefl->info.via.area.y2 = 0.0; lefl->info.via.area.layer = -1; lefl->info.via.cell = (GATE)NULL; lefl->info.via.lr = (DSEG)NULL; lefl->info.via.generated = FALSE; lefl->info.via.respervia = 0.0; lefl->lefName = strdup(name); return lefl; } /* Note: Used directly below, as it is passed to variable "mode" * in LefReadLayerSection(). However, mainly used in LefRead(). */ enum lef_sections {LEF_VERSION = 0, LEF_BUSBITCHARS, LEF_DIVIDERCHAR, LEF_MANUFACTURINGGRID, LEF_USEMINSPACING, LEF_CLEARANCEMEASURE, LEF_NOWIREEXTENSIONATPIN, LEF_NAMESCASESENSITIVE, LEF_PROPERTYDEFS, LEF_UNITS, LEF_SECTION_LAYER, LEF_SECTION_VIA, LEF_SECTION_VIARULE, LEF_SECTION_NONDEFAULTRULE, LEF_SECTION_SPACING, LEF_SECTION_SITE, LEF_PROPERTY, LEF_NOISETABLE, LEF_CORRECTIONTABLE, LEF_IRDROP, LEF_ARRAY, LEF_SECTION_TIMING, LEF_EXTENSION, LEF_MACRO, LEF_END}; /* *------------------------------------------------------------ * * LefReadLayerSection -- * * Read in a LAYER, VIA, or VIARULE section from a LEF file. * * Results: * None. * * Side Effects: * Adds to the LEF layer info hash table. * *------------------------------------------------------------ */ enum lef_layer_keys {LEF_LAYER_TYPE=0, LEF_LAYER_WIDTH, LEF_LAYER_MINWIDTH, LEF_LAYER_MAXWIDTH, LEF_LAYER_AREA, LEF_LAYER_SPACING, LEF_LAYER_SPACINGTABLE, LEF_LAYER_PITCH, LEF_LAYER_DIRECTION, LEF_LAYER_OFFSET, LEF_LAYER_FOREIGN, LEF_LAYER_WIREEXT, LEF_LAYER_RES, LEF_LAYER_CAP, LEF_LAYER_EDGECAP, LEF_LAYER_THICKNESS, LEF_LAYER_HEIGHT, LEF_LAYER_MINIMUMCUT, LEF_LAYER_MINDENSITY, LEF_LAYER_ACDENSITY, LEF_LAYER_DCDENSITY, LEF_LAYER_PROPERTY, LEF_LAYER_ANTENNAMODEL, LEF_LAYER_ANTENNA, LEF_LAYER_ANTENNADIFF, LEF_LAYER_ANTENNASIDE, LEF_LAYER_AGG_ANTENNA, LEF_LAYER_AGG_ANTENNADIFF, LEF_LAYER_AGG_ANTENNASIDE, LEF_VIA_DEFAULT, LEF_VIA_LAYER, LEF_VIA_RECT, LEF_VIA_ENCLOSURE, LEF_VIA_PREFERENCLOSURE, LEF_VIARULE_OVERHANG, LEF_VIARULE_METALOVERHANG, LEF_VIARULE_VIA, LEF_VIARULE_GENERATE, LEF_LAYER_END}; enum lef_spacing_keys {LEF_SPACING_RANGE=0, LEF_END_LAYER_SPACING}; void LefReadLayerSection(f, lname, mode, lefl) FILE *f; /* LEF file being read */ char *lname; /* name of the layer */ int mode; /* layer, via, or viarule */ LefList lefl; /* pointer to layer info */ { char *token, *tp; int keyword, typekey = -1, entries, i; struct seg_ viaArea; int curlayer = -1; double dvalue, oscale; LefList altVia; lefSpacingRule *newrule = NULL, *testrule; /* These are defined in the order of CLASS_* in lefInt.h */ static char *layer_type_keys[] = { "ROUTING", "CUT", "MASTERSLICE", "OVERLAP", NULL }; static char *layer_keys[] = { "TYPE", "WIDTH", "MINWIDTH", "MAXWIDTH", "AREA", "SPACING", "SPACINGTABLE", "PITCH", "DIRECTION", "OFFSET", "FOREIGN", "WIREEXTENSION", "RESISTANCE", "CAPACITANCE", "EDGECAPACITANCE", "THICKNESS", "HEIGHT", "MINIMUMCUT", "MINIMUMDENSITY", "ACCURRENTDENSITY", "DCCURRENTDENSITY", "PROPERTY", "ANTENNAMODEL", "ANTENNAAREARATIO", "ANTENNADIFFAREARATIO", "ANTENNASIDEAREARATIO", "ANTENNACUMAREARATIO", "ANTENNACUMDIFFAREARATIO", "ANTENNACUMSIDEAREARATIO", "DEFAULT", "LAYER", "RECT", "ENCLOSURE", "PREFERENCLOSURE", "OVERHANG", "METALOVERHANG", "VIA", "GENERATE", "END", NULL }; static char *spacing_keys[] = { "RANGE", ";", NULL }; /* Database is assumed to be in microns. */ /* If not, we need to parse the UNITS record, which is */ /* currently ignored. */ oscale = 1; viaArea.x1 = viaArea.x2 = 0; viaArea.y1 = viaArea.y2 = 0; viaArea.layer = -1; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, layer_keys); if (keyword < 0) { LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_LAYER_PROPERTY: /* Some kind of forward-compatibility thing. */ LefEndStatement(f); break; case LEF_LAYER_TYPE: token = LefNextToken(f, TRUE); if (*token != '\n') { typekey = Lookup(token, layer_type_keys); if (typekey < 0) LefError(LEF_WARNING, "Unknown layer type \"%s\" in LEF file; " "ignoring.\n", token); } if (lefl->lefClass == CLASS_IGNORE) { lefl->lefClass = typekey; if (typekey == CLASS_ROUTE) { lefl->info.route.width = 0.0; lefl->info.route.spacing = NULL; lefl->info.route.pitchx = 0.0; lefl->info.route.pitchy = 0.0; // Use -1.0 as an indication that offset has not // been specified and needs to be set to default. lefl->info.route.offsetx = -1.0; lefl->info.route.offsety = -1.0; lefl->info.route.hdirection = DIR_UNKNOWN; lefl->info.route.minarea = 0.0; lefl->info.route.thick = 0.0; lefl->info.route.antenna = 0.0; lefl->info.route.method = CALC_NONE; lefl->info.route.areacap = 0.0; lefl->info.route.respersq = 0.0; lefl->info.route.edgecap = 0.0; /* A routing type has been declared. Route */ /* layers are supposed to be in order from */ /* bottom to top in the technology LEF file. */ lefl->type = LefGetMaxRouteLayer(); } else if (typekey == CLASS_CUT || typekey == CLASS_VIA) { lefl->info.via.area.x1 = 0.0; lefl->info.via.area.y1 = 0.0; lefl->info.via.area.x2 = 0.0; lefl->info.via.area.y2 = 0.0; lefl->info.via.area.layer = -1; lefl->info.via.cell = (GATE)NULL; lefl->info.via.lr = (DSEG)NULL; /* Note: lefl->type not set here for cut */ /* layers so that route layers will all be */ /* clustered at the bottom. */ } } else if (lefl->lefClass != typekey) { LefError(LEF_ERROR, "Attempt to reclassify layer %s from %s to %s\n", lname, layer_type_keys[lefl->lefClass], layer_type_keys[typekey]); } LefEndStatement(f); break; case LEF_LAYER_MINWIDTH: // Not handled if width is already defined. if ((lefl->lefClass != CLASS_ROUTE) || (lefl->info.route.width != 0)) { LefEndStatement(f); break; } /* drop through */ case LEF_LAYER_WIDTH: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); if (lefl->lefClass == CLASS_ROUTE) lefl->info.route.width = dvalue / (double)oscale; else if (lefl->lefClass == CLASS_CUT) { double baseval = (dvalue / (double)oscale) / 2.0; lefl->info.via.area.x1 = -baseval; lefl->info.via.area.y1 = -baseval; lefl->info.via.area.x2 = baseval; lefl->info.via.area.y2 = baseval; } LefEndStatement(f); break; case LEF_LAYER_FOREIGN: case LEF_LAYER_MAXWIDTH: // Not handled. LefEndStatement(f); break; case LEF_LAYER_AREA: /* Read minimum area rule value */ token = LefNextToken(f, TRUE); if (lefl->lefClass == CLASS_ROUTE) { sscanf(token, "%lg", &dvalue); // Units of area (length * length) lefl->info.route.minarea = dvalue / (double)oscale / (double)oscale; } LefEndStatement(f); break; case LEF_LAYER_SPACING: // Only parse spacing for routes if (lefl->lefClass != CLASS_ROUTE) { LefEndStatement(f); break; } token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); token = LefNextToken(f, TRUE); typekey = Lookup(token, spacing_keys); newrule = (lefSpacingRule *)malloc(sizeof(lefSpacingRule)); // If no range specified, then the rule goes in front if (typekey != LEF_SPACING_RANGE) { newrule->spacing = dvalue / (double)oscale; newrule->width = 0.0; newrule->next = lefl->info.route.spacing; lefl->info.route.spacing = newrule; } else { // Get range minimum, ignore range maximum, and sort // the spacing order. newrule->spacing = dvalue / (double)oscale; token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); newrule->width = dvalue / (double)oscale; for (testrule = lefl->info.route.spacing; testrule; testrule = testrule->next) if (testrule->next == NULL || testrule->next->width > newrule->width) break; if (!testrule) { newrule->next = NULL; lefl->info.route.spacing = newrule; } else { newrule->next = testrule->next; testrule->next = newrule; } token = LefNextToken(f, TRUE); typekey = Lookup(token, spacing_keys); } if (typekey != LEF_END_LAYER_SPACING) LefEndStatement(f); break; case LEF_LAYER_SPACINGTABLE: // Use the values for the maximum parallel runlength token = LefNextToken(f, TRUE); // "PARALLELRUNLENTTH" entries = 0; while (1) { token = LefNextToken(f, TRUE); if (*token == ';' || !strcmp(token, "WIDTH")) break; else entries++; } while (*token != ';') { token = LefNextToken(f, TRUE); // Minimum width value sscanf(token, "%lg", &dvalue); newrule = (lefSpacingRule *)malloc(sizeof(lefSpacingRule)); newrule->width = dvalue / (double)oscale; for (i = 0; i < entries; i++) { token = LefNextToken(f, TRUE); // Spacing value } sscanf(token, "%lg", &dvalue); newrule->spacing = dvalue / (double)oscale; for (testrule = lefl->info.route.spacing; testrule; testrule = testrule->next) if (testrule->next == NULL || testrule->next->width > newrule->width) break; if (!testrule) { newrule->next = NULL; lefl->info.route.spacing = newrule; } else { newrule->next = testrule->next; testrule->next = newrule; } token = LefNextToken(f, TRUE); if (strcmp(token, "WIDTH")) break; } break; case LEF_LAYER_PITCH: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); lefl->info.route.pitchx = dvalue / (double)oscale; token = LefNextToken(f, TRUE); if (token && (*token != ';')) { sscanf(token, "%lg", &dvalue); lefl->info.route.pitchy = dvalue / (double)oscale; LefEndStatement(f); } else { lefl->info.route.pitchy = lefl->info.route.pitchx; /* If the orientation is known, then zero the pitch */ /* in the opposing direction. If not, then set the */ /* direction to DIR_RESOLVE so that the pitch in */ /* the opposing direction can be zeroed when the */ /* direction is specified. */ if (lefl->info.route.hdirection == DIR_UNKNOWN) lefl->info.route.hdirection = DIR_RESOLVE; else if (lefl->info.route.hdirection == DIR_VERTICAL) lefl->info.route.pitchy = 0.0; else if (lefl->info.route.hdirection == DIR_HORIZONTAL) lefl->info.route.pitchx = 0.0; } /* Offset default is 1/2 the pitch. Offset is */ /* intialized to -1 to tell whether or not the value */ /* has been set by an OFFSET statement. */ if (lefl->info.route.offsetx < 0.0) lefl->info.route.offsetx = lefl->info.route.pitchx / 2.0; if (lefl->info.route.offsety < 0.0) lefl->info.route.offsety = lefl->info.route.pitchy / 2.0; break; case LEF_LAYER_DIRECTION: token = LefNextToken(f, TRUE); LefLower(token); if (lefl->info.route.hdirection == DIR_RESOLVE) { if (token[0] == 'h') lefl->info.route.pitchx = 0.0; else if (token[0] == 'v') lefl->info.route.pitchy = 0.0; } lefl->info.route.hdirection = (token[0] == 'h') ? DIR_HORIZONTAL : DIR_VERTICAL; LefEndStatement(f); break; case LEF_LAYER_OFFSET: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); lefl->info.route.offsetx = dvalue / (double)oscale; token = LefNextToken(f, TRUE); if (token && (*token != ';')) { sscanf(token, "%lg", &dvalue); lefl->info.route.offsety = dvalue / (double)oscale; LefEndStatement(f); } else { lefl->info.route.offsety = lefl->info.route.offsetx; } break; case LEF_LAYER_RES: token = LefNextToken(f, TRUE); if (lefl->lefClass == CLASS_ROUTE) { if (!strcmp(token, "RPERSQ")) { token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); // Units are ohms per square lefl->info.route.respersq = dvalue; } } else if (lefl->lefClass == CLASS_VIA || lefl->lefClass == CLASS_CUT) { sscanf(token, "%lg", &dvalue); lefl->info.via.respervia = dvalue; // Units ohms } LefEndStatement(f); break; case LEF_LAYER_CAP: token = LefNextToken(f, TRUE); if (lefl->lefClass == CLASS_ROUTE) { if (!strcmp(token, "CPERSQDIST")) { token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); // Units are pF per squared unit length lefl->info.route.areacap = dvalue / ((double)oscale * (double)oscale); } } LefEndStatement(f); break; case LEF_LAYER_EDGECAP: token = LefNextToken(f, TRUE); if (lefl->lefClass == CLASS_ROUTE) { sscanf(token, "%lg", &dvalue); // Units are pF per unit length lefl->info.route.edgecap = dvalue / (double)oscale; } LefEndStatement(f); break; case LEF_LAYER_THICKNESS: case LEF_LAYER_HEIGHT: /* Assuming thickness and height are the same thing? */ token = LefNextToken(f, TRUE); if (lefl->lefClass == CLASS_ROUTE) { sscanf(token, "%lg", &dvalue); // Units of length lefl->info.route.thick = dvalue / (double)oscale; } LefEndStatement(f); break; case LEF_LAYER_MINIMUMCUT: /* Not handling minimum cuts for wide wires yet */ LefEndStatement(f); case LEF_LAYER_ANTENNAMODEL: /* Not handling antenna models yet */ LefEndStatement(f); break; case LEF_LAYER_ANTENNA: case LEF_LAYER_ANTENNASIDE: case LEF_LAYER_AGG_ANTENNA: case LEF_LAYER_AGG_ANTENNASIDE: /* NOTE: Assuming that only one of these methods will */ /* be used! If more than one is present, then only the */ /* last one will be recorded and used. */ token = LefNextToken(f, TRUE); if (lefl->lefClass == CLASS_ROUTE) { sscanf(token, "%lg", &dvalue); // Unitless values (ratio) lefl->info.route.antenna = dvalue; } if (keyword == LEF_LAYER_ANTENNA) lefl->info.route.method = CALC_AREA; else if (keyword == LEF_LAYER_ANTENNASIDE) lefl->info.route.method = CALC_SIDEAREA; else if (keyword == LEF_LAYER_AGG_ANTENNA) lefl->info.route.method = CALC_AGG_AREA; else lefl->info.route.method = CALC_AGG_SIDEAREA; LefEndStatement(f); break; case LEF_LAYER_ANTENNADIFF: case LEF_LAYER_AGG_ANTENNADIFF: /* Not specifically handling these antenna types */ /* (antenna ratios for antennas connected to diodes, */ /* which can still blow gates if the diode area is */ /* insufficiently large.) */ LefEndStatement(f); break; case LEF_LAYER_ACDENSITY: /* The idiocy of the LEF format on display. */ token = LefNextToken(f, TRUE); /* value type */ token = LefNextToken(f, TRUE); /* value, FREQUENCY */ if (!strcmp(token, "FREQUENCY")) { LefEndStatement(f); token = LefNextToken(f, TRUE); /* value, FREQUENCY */ if (!strcmp(token, "WIDTH")) /* Optional width */ LefEndStatement(f); /* Additional statement TABLEENTRIES */ } LefEndStatement(f); break; case LEF_LAYER_DCDENSITY: /* The idiocy of the LEF format still on display. */ token = LefNextToken(f, TRUE); /* value type */ token = LefNextToken(f, TRUE); /* value, WIDTH */ if (!strcmp(token, "WIDTH")) LefEndStatement(f); /* Additional statement TABLEENTRIES */ LefEndStatement(f); break; case LEF_LAYER_MINDENSITY: case LEF_LAYER_WIREEXT: /* Not specifically handling these */ LefEndStatement(f); break; case LEF_VIA_DEFAULT: case LEF_VIARULE_GENERATE: /* Do nothing; especially, don't look for end-of-statement! */ break; case LEF_VIA_LAYER: curlayer = LefReadLayer(f, FALSE); LefEndStatement(f); break; case LEF_VIA_RECT: if (curlayer >= 0) LefAddViaGeometry(f, lefl, curlayer, oscale); LefEndStatement(f); break; case LEF_VIA_ENCLOSURE: /* Defines how to draw via metal layers. Ignore unless */ /* this is a VIARULE GENERATE section. */ if (mode == LEF_SECTION_VIARULE) { /* Note that values can interact with ENCLOSURE */ /* values given for the cut layer type. This is */ /* not being handled. */ DSEG viarect, encrect; encrect = LefReadEnclosure(f, curlayer, oscale); viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *encrect; viarect->next = lefl->info.via.lr; lefl->info.via.lr = viarect; lefl->info.via.generated = TRUE; } LefEndStatement(f); break; case LEF_VIARULE_OVERHANG: case LEF_VIARULE_METALOVERHANG: /* These are from older LEF definitions (e.g., 5.4) */ /* and cannot completely specify via geometry. So if */ /* seen, ignore the rest of the via section. Only the */ /* explicitly defined VIA types will be used. */ LefError(LEF_WARNING, "NOTE: Old format VIARULE ignored.\n"); lefl->lefClass == CLASS_IGNORE; LefEndStatement(f); /* LefSkipSection(f, lname); */ /* Continue parsing */ break; case LEF_VIA_PREFERENCLOSURE: /* Ignoring this. */ LefEndStatement(f); break; case LEF_VIARULE_VIA: LefEndStatement(f); break; case LEF_LAYER_END: if (!LefParseEndStatement(f, lname)) { LefError(LEF_ERROR, "Layer END statement missing.\n"); keyword = -1; } break; } if (keyword == LEF_LAYER_END) break; } } /*--------------------------------------------------------------*/ /* If any vias have been built from VIARULE entries, then they */ /* do not appear in the tech LEF and need to be defined in the */ /* DEF file. This routine finds all generated vias and writes */ /* out the entries to the indicated file f. */ /* */ /* "defvias" is the number of vias found in the input DEF file. */ /* If non-zero, they will be written out after the internally */ /* generated vias, so add defvias to the count written after */ /* the VIAS statement, and do not write the "END" statement. */ /*--------------------------------------------------------------*/ void LefWriteGeneratedVias(FILE *f, double oscale, int defvias) { double scale; int numvias; LefList lefl; scale = oscale / 2.0; /* Via dimensions are double */ /* 1st pass---check if any vias are generated. Also check if any */ /* vias have non-route layers (e.g., POLY, or Num_layers and above) */ /* and unmark them. */ numvias = defvias; for (lefl = LefInfo; lefl; lefl = lefl->next) if (lefl->lefClass == CLASS_VIA) if (lefl->info.via.generated) { if (!lefl->info.via.lr || (lefl->info.via.lr->layer < 0) || (lefl->info.via.lr->layer >= Num_layers)) { lefl->info.via.generated = FALSE; continue; } else if (!lefl->info.via.lr->next || (lefl->info.via.lr->next->layer < 0) || (lefl->info.via.lr->next->layer >= Num_layers)) { lefl->info.via.generated = FALSE; continue; } numvias++; } if (numvias == 0) return; /* Nothing to write */ fprintf(f, "\n"); fprintf(f, "VIAS %d ;\n", numvias); /* 2nd pass---output the VIA records. All vias consist of */ /* two metal layers and a cut layer. */ for (lefl = LefInfo; lefl; lefl = lefl->next) if (lefl->lefClass == CLASS_VIA) if (lefl->info.via.generated) { fprintf(f, "- %s\n", lefl->lefName); fprintf(f, "+ RECT %s ( %ld %ld ) ( %ld %ld )", CIFLayer[lefl->info.via.area.layer], (long) (-0.5 + scale * lefl->info.via.area.x1), (long) (-0.5 + scale * lefl->info.via.area.y1), (long) (0.5 + scale * lefl->info.via.area.x2), (long) (0.5 + scale * lefl->info.via.area.y2)); if (lefl->info.via.lr != NULL) { fprintf(f, "\n+ RECT %s ( %ld %ld ) ( %ld %ld )", CIFLayer[lefl->info.via.lr->layer], (long) (-0.5 + scale * lefl->info.via.lr->x1), (long) (-0.5 + scale * lefl->info.via.lr->y1), (long) (0.5 + scale * lefl->info.via.lr->x2), (long) (0.5 + scale * lefl->info.via.lr->y2)); if (lefl->info.via.lr->next != NULL) { fprintf(f, "\n+ RECT %s ( %ld %ld ) ( %ld %ld )", CIFLayer[lefl->info.via.lr->next->layer], (long) (-0.5 + scale * lefl->info.via.lr->next->x1), (long) (-0.5 + scale * lefl->info.via.lr->next->y1), (long) (0.5 + scale * lefl->info.via.lr->next->x2), (long) (0.5 + scale * lefl->info.via.lr->next->y2)); } } fprintf(f, " ;\n"); /* Finish record */ } if (defvias == 0) { fprintf(f, "END VIAS\n", numvias); fprintf(f, "\n"); } } /*--------------------------------------------------------------*/ /* This routine runs through all the defined vias, from last to */ /* first defined. Check the X vs. Y dimension of the base and */ /* top layers. If both base and top layers are longer in X, */ /* then save as ViaXX. If longer in Y, save as ViaYY. If the */ /* base is longer in X and the top is longer in Y, then save as */ /* ViaXY, and if the base is longer in Y and the top is longer */ /* in X, then save as ViaYX. */ /* */ /* If all via types have the same X and Y for the top and/or */ /* bottom layer, then save as both X and Y variants. */ /* */ /* If there is an AllowedVias list, then only assign vias that */ /* are in the list. */ /* */ /* If the layer pair has a VIARULE GENERATE type, then it is */ /* preferred over fixed via definitions. */ /*--------------------------------------------------------------*/ void LefAssignLayerVias() { LefList lefl; int toplayer, baselayer; int minroute, maxroute; double xybdiff, xytdiff; DSEG grect; LinkedStringPtr viaName; char *newViaXX[MAX_LAYERS]; char *newViaXY[MAX_LAYERS]; char *newViaYX[MAX_LAYERS]; char *newViaYY[MAX_LAYERS]; u_char hasGenerate[MAX_LAYERS]; for (baselayer = 0; baselayer < MAX_LAYERS; baselayer++) { newViaXX[baselayer] = newViaXY[baselayer] = NULL; newViaYX[baselayer] = newViaYY[baselayer] = NULL; hasGenerate[baselayer] = FALSE; } /* Determine if there is a VIARULE GENERATE for each base layer */ for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_VIA) { if (lefl->info.via.generated == TRUE) { /* Find the base layer and set hasGenerate[] for that layer */ baselayer = lefl->info.via.area.layer; if (lefl->info.via.lr) { if (lefl->info.via.lr->layer < 0) { lefl->info.via.generated = FALSE; continue; } if ((baselayer < 0) || (lefl->info.via.lr->layer < baselayer)) baselayer = lefl->info.via.lr->layer; } if (lefl->info.via.lr->next) { if (lefl->info.via.lr->next->layer < 0) { lefl->info.via.generated = FALSE; continue; } if ((baselayer < 0) || (lefl->info.via.lr->next->layer < baselayer)) baselayer = lefl->info.via.lr->next->layer; } if ((baselayer >= 0) && (baselayer < MAX_LAYERS)) hasGenerate[baselayer] = TRUE; } } } /* Make sure we know what are the minimum and maximum route layers */ minroute = maxroute = -1; for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_ROUTE) { if (minroute == -1) { minroute = lefl->type; maxroute = lefl->type; } else { if (lefl->type < minroute) minroute = lefl->type; if (lefl->type > maxroute) maxroute = lefl->type; } } } for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_VIA) { if (lefl->info.via.lr) { baselayer = toplayer = MAX_LAYERS; if (lefl->info.via.area.layer >= minroute && lefl->info.via.area.layer <= maxroute) { baselayer = toplayer = lefl->info.via.area.layer; xybdiff = xytdiff = (lefl->info.via.area.x2 - lefl->info.via.area.x1) - (lefl->info.via.area.y2 - lefl->info.via.area.y1); } for (grect = lefl->info.via.lr; grect; grect = grect->next) { if (grect->layer >= minroute && grect->layer <= maxroute) { if (grect->layer < baselayer) { baselayer = grect->layer; xybdiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); } } } toplayer = baselayer; for (grect = lefl->info.via.lr; grect; grect = grect->next) { if (grect->layer >= minroute && grect->layer <= maxroute) { if (grect->layer > toplayer) { toplayer = grect->layer; xytdiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); } } } /* Ignore vias on undefined layers (-1) */ if ((baselayer < MAX_LAYERS) && (toplayer < MAX_LAYERS) && (baselayer >= 0) && (toplayer >= 0)) { /* Assign only to layers in AllowedVias, if it is non-NULL */ if (AllowedVias != NULL) { for (viaName = AllowedVias; viaName; viaName = viaName->next) { if (!strcmp(viaName->name, lefl->lefName)) break; } if (viaName == NULL) continue; } else if (hasGenerate[baselayer] && lefl->info.via.generated == FALSE) continue; /* Check for unexpected via definitions */ if ((toplayer - baselayer) != 1) { LefError(LEF_WARNING, "Via \"%s\" in LEF file is defined " "on non-contiguous route layers!\n", lefl->lefName); } if ((xytdiff > EPS) && (xybdiff < -EPS)) { if (newViaYX[baselayer] != NULL) free(newViaYX[baselayer]); newViaYX[baselayer] = strdup(lefl->lefName); } else if ((xytdiff < -EPS) && (xybdiff > EPS)) { if (newViaXY[baselayer] != NULL) free(newViaXY[baselayer]); newViaXY[baselayer] = strdup(lefl->lefName); } else if ((xytdiff > EPS) && (xybdiff > EPS)) { if (newViaXX[baselayer] != NULL) free(newViaXX[baselayer]); newViaXX[baselayer] = strdup(lefl->lefName); } else if ((xytdiff < -EPS) && (xybdiff < -EPS)) { if (newViaYY[baselayer] != NULL) free(newViaYY[baselayer]); newViaYY[baselayer] = strdup(lefl->lefName); } } } } } /* Run the same thing again, checking for vias that are square on top */ /* or bottom, and so have no preferential direction. If there is no */ /* other via definition for that layer, then save the non-directional */ /* one, copying it into both X and Y positions. */ for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_VIA) { if (lefl->info.via.lr) { baselayer = toplayer = MAX_LAYERS; if (lefl->info.via.area.layer >= minroute && lefl->info.via.area.layer <= maxroute) { baselayer = toplayer = lefl->info.via.area.layer; xybdiff = xytdiff = (lefl->info.via.area.x2 - lefl->info.via.area.x1) - (lefl->info.via.area.y2 - lefl->info.via.area.y1); } for (grect = lefl->info.via.lr; grect; grect = grect->next) { if (grect->layer >= minroute && grect->layer <= maxroute) { if (grect->layer < baselayer) { baselayer = grect->layer; xybdiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); } } } toplayer = baselayer; for (grect = lefl->info.via.lr; grect; grect = grect->next) { if (grect->layer >= minroute && grect->layer <= maxroute) { if (grect->layer > toplayer) { toplayer = grect->layer; xytdiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); } } } /* Ignore vias on undefined layers (-1) */ if ((baselayer < MAX_LAYERS) && (toplayer < MAX_LAYERS) && (baselayer >= 0) && (toplayer >= 0)) { /* Assign only to layers in AllowedVias, if it is non-NULL */ if (AllowedVias != NULL) { for (viaName = AllowedVias; viaName; viaName = viaName->next) { if (!strcmp(viaName->name, lefl->lefName)) break; } if (viaName == NULL) continue; } else if (hasGenerate[baselayer] && lefl->info.via.generated == FALSE) continue; if ((xytdiff < EPS) && (xytdiff > -EPS)) { /* Square on the top */ if (xybdiff > EPS) { if (newViaXX[baselayer] == NULL) newViaXX[baselayer] = strdup(lefl->lefName); if (newViaXY[baselayer] == NULL) newViaXY[baselayer] = strdup(lefl->lefName); } if (xybdiff < -EPS) { if (newViaYX[baselayer] == NULL) newViaYX[baselayer] = strdup(lefl->lefName); if (newViaYY[baselayer] == NULL) newViaYY[baselayer] = strdup(lefl->lefName); } } else if ((xybdiff < EPS) && (xybdiff > -EPS)) { /* Square on the bottom */ if (xytdiff > EPS) { if (newViaXX[baselayer] == NULL) newViaXX[baselayer] = strdup(lefl->lefName); if (newViaYX[baselayer] == NULL) newViaYX[baselayer] = strdup(lefl->lefName); } if (xytdiff < -EPS) { if (newViaXY[baselayer] == NULL) newViaXY[baselayer] = strdup(lefl->lefName); if (newViaYY[baselayer] == NULL) newViaYY[baselayer] = strdup(lefl->lefName); } } } } } } /* Finally, run a third pass to catch any via definitions that are */ /* square on both top and bottom, in positions that have not yet */ /* had a valid via recorded. */ for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_VIA) { if (lefl->info.via.lr) { baselayer = toplayer = MAX_LAYERS; if (lefl->info.via.area.layer >= minroute && lefl->info.via.area.layer <= maxroute) { baselayer = toplayer = lefl->info.via.area.layer; xybdiff = xytdiff = (lefl->info.via.area.x2 - lefl->info.via.area.x1) - (lefl->info.via.area.y2 - lefl->info.via.area.y1); } for (grect = lefl->info.via.lr; grect; grect = grect->next) { if (grect->layer >= minroute && grect->layer <= maxroute) { if (grect->layer < baselayer) { baselayer = grect->layer; xybdiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); } } } toplayer = baselayer; for (grect = lefl->info.via.lr; grect; grect = grect->next) { if (grect->layer >= minroute && grect->layer <= maxroute) { if (grect->layer > toplayer) { toplayer = grect->layer; xytdiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); } } } /* Ignore vias on undefined layers (-1) */ if ((baselayer < MAX_LAYERS) && (toplayer < MAX_LAYERS) && (baselayer >= 0) && (toplayer >= 0)) { /* Assign only to layers in AllowedVias, if it is non-NULL */ if (AllowedVias != NULL) { for (viaName = AllowedVias; viaName; viaName = viaName->next) { if (!strcmp(viaName->name, lefl->lefName)) break; } if (viaName == NULL) continue; } else if (hasGenerate[baselayer] && lefl->info.via.generated == FALSE) continue; if (((xytdiff < EPS) && (xytdiff > -EPS)) && ((xybdiff < EPS) && (xybdiff > -EPS))) { /* Square on the top and bottom */ if (newViaXX[baselayer] == NULL) newViaXX[baselayer] = strdup(lefl->lefName); if (newViaXY[baselayer] == NULL) newViaXY[baselayer] = strdup(lefl->lefName); if (newViaYX[baselayer] == NULL) newViaYX[baselayer] = strdup(lefl->lefName); if (newViaYY[baselayer] == NULL) newViaYY[baselayer] = strdup(lefl->lefName); } } } } } /* Copy newVia** back into via**, making sure that at least */ /* one entry exists for each layer. */ for (baselayer = 0; baselayer < MAX_LAYERS; baselayer++) { if ((newViaXX[baselayer] == NULL) && (newViaXY[baselayer] == NULL) && (newViaYX[baselayer] == NULL) && (newViaYY[baselayer] == NULL)) continue; if (ViaXX[baselayer] != NULL) { free(ViaXX[baselayer]); ViaXX[baselayer] = NULL; } if (ViaXY[baselayer] != NULL) { free(ViaXY[baselayer]); ViaXY[baselayer] = NULL; } if (ViaYX[baselayer] != NULL) { free(ViaYX[baselayer]); ViaYX[baselayer] = NULL; } if (ViaYY[baselayer] != NULL) { free(ViaYY[baselayer]); ViaYY[baselayer] = NULL; } if (newViaXX[baselayer] != NULL) ViaXX[baselayer] = strdup(newViaXX[baselayer]); if (newViaXY[baselayer] != NULL) ViaXY[baselayer] = strdup(newViaXY[baselayer]); if (newViaYX[baselayer] != NULL) ViaYX[baselayer] = strdup(newViaYX[baselayer]); if (newViaYY[baselayer] != NULL) ViaYY[baselayer] = strdup(newViaYY[baselayer]); /* Fallback in case some permutations don't exist */ if (ViaXX[baselayer] == NULL) { if (newViaXY[baselayer] != NULL) ViaXX[baselayer] = strdup(newViaXY[baselayer]); else if (newViaYX[baselayer] != NULL) ViaXX[baselayer] = strdup(newViaYX[baselayer]); else if (newViaYY[baselayer] != NULL) ViaXX[baselayer] = strdup(newViaYY[baselayer]); } if (ViaXY[baselayer] == NULL) { if (newViaXX[baselayer] != NULL) ViaXY[baselayer] = strdup(newViaXX[baselayer]); else if (newViaYY[baselayer] != NULL) ViaXY[baselayer] = strdup(newViaYY[baselayer]); else if (newViaYX[baselayer] != NULL) ViaXY[baselayer] = strdup(newViaYX[baselayer]); } if (ViaYX[baselayer] == NULL) { if (newViaYY[baselayer] != NULL) ViaYX[baselayer] = strdup(newViaYY[baselayer]); else if (newViaXX[baselayer] != NULL) ViaYX[baselayer] = strdup(newViaXX[baselayer]); else if (newViaXY[baselayer] != NULL) ViaYX[baselayer] = strdup(newViaXY[baselayer]); } if (ViaYY[baselayer] == NULL) { if (newViaYX[baselayer] != NULL) ViaYY[baselayer] = strdup(newViaYX[baselayer]); else if (newViaXY[baselayer] != NULL) ViaYY[baselayer] = strdup(newViaXY[baselayer]); else if (newViaXX[baselayer] != NULL) ViaYY[baselayer] = strdup(newViaXX[baselayer]); } } for (baselayer = 0; baselayer < MAX_LAYERS; baselayer++) { if (newViaXX[baselayer] != NULL) free(newViaXX[baselayer]); if (newViaXY[baselayer] != NULL) free(newViaXY[baselayer]); if (newViaYX[baselayer] != NULL) free(newViaYX[baselayer]); if (newViaYY[baselayer] != NULL) free(newViaYY[baselayer]); } } /* *------------------------------------------------------------ * * LefRead -- * * Read a .lef file and generate all routing configuration * structures and values from the LAYER, VIA, and MACRO sections * * Results: * None. * * Side Effects: * Many. Cell definitions are created and added to * the GateInfo database. * *------------------------------------------------------------ */ /* See above for "enum lef_sections {...}" */ int LefRead(inName) char *inName; { FILE *f; char filename[256]; char *token; char tsave[128]; int keyword, layer; int oprecis = 100; // = 1 / manufacturing grid (microns) float oscale; double xydiff, ogrid, minwidth; LefList lefl; DSEG grect; GATE gateginfo; static char *sections[] = { "VERSION", "BUSBITCHARS", "DIVIDERCHAR", "MANUFACTURINGGRID", "USEMINSPACING", "CLEARANCEMEASURE", "NOWIREEXTENSIONATPIN", "NAMESCASESENSITIVE", "PROPERTYDEFINITIONS", "UNITS", "LAYER", "VIA", "VIARULE", "NONDEFAULTRULE", "SPACING", "SITE", "PROPERTY", "NOISETABLE", "CORRECTIONTABLE", "IRDROP", "ARRAY", "TIMING", "BEGINEXT", "MACRO", "END", NULL }; if (!strrchr(inName, '.')) sprintf(filename, "%s.lef", inName); else strcpy(filename, inName); f = fopen(filename, "r"); if (f == NULL) { Fprintf(stderr, "Cannot open input file: "); perror(filename); return 0; } if (Verbose > 0) { Fprintf(stdout, "Reading LEF data from file %s.\n", filename); Flush(stdout); } oscale = 1; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, sections); if (keyword < 0) { LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_VERSION: case LEF_BUSBITCHARS: case LEF_DIVIDERCHAR: case LEF_CLEARANCEMEASURE: case LEF_USEMINSPACING: case LEF_NAMESCASESENSITIVE: case LEF_NOWIREEXTENSIONATPIN: LefEndStatement(f); break; case LEF_MANUFACTURINGGRID: token = LefNextToken(f, TRUE); if (sscanf(token, "%lg", &ogrid) == 1) oprecis = (int)((1.0 / ogrid) + 0.5); LefEndStatement(f); break; case LEF_PROPERTYDEFS: LefSkipSection(f, sections[LEF_PROPERTYDEFS]); break; case LEF_UNITS: LefSkipSection(f, sections[LEF_UNITS]); break; case LEF_SECTION_NONDEFAULTRULE: token = LefNextToken(f, TRUE); sprintf(tsave, "%.127s", token); LefSkipSection(f, tsave); break; case LEF_SECTION_VIA: case LEF_SECTION_VIARULE: token = LefNextToken(f, TRUE); sprintf(tsave, "%.127s", token); lefl = LefFindLayer(token); if (keyword == LEF_SECTION_VIARULE) { char *vianame = (char *)malloc(strlen(token) + 3); sprintf(vianame, "%s_0", token); /* If the following keyword is GENERATE, then */ /* prepare up to four contact types to represent */ /* all possible orientations of top and bottom */ /* metal layers. If no GENERATE keyword, ignore. */ token = LefNextToken(f, TRUE); if (!strcmp(token, "GENERATE")) { lefl = LefNewVia(vianame); lefl->next = LefInfo; LefInfo = lefl; LefReadLayerSection(f, tsave, keyword, lefl); } else { LefSkipSection(f, tsave); } free(vianame); } else if (lefl == NULL) { lefl = LefNewVia(token); lefl->next = LefInfo; LefInfo = lefl; LefReadLayerSection(f, tsave, keyword, lefl); } else { LefError(LEF_WARNING, "Warning: Cut type \"%s\" redefined.\n", token); lefl = LefRedefined(lefl, token); LefReadLayerSection(f, tsave, keyword, lefl); } break; case LEF_SECTION_LAYER: token = LefNextToken(f, TRUE); sprintf(tsave, "%.127s", token); lefl = LefFindLayer(token); if (lefl == (LefList)NULL) { lefl = LefNewRoute(token); lefl->next = LefInfo; LefInfo = lefl; } else { if (lefl && lefl->type < 0) { LefError(LEF_ERROR, "Layer %s is only defined for" " obstructions!\n", token); LefSkipSection(f, tsave); break; } } LefReadLayerSection(f, tsave, keyword, lefl); break; case LEF_SECTION_SPACING: LefSkipSection(f, sections[LEF_SECTION_SPACING]); break; case LEF_SECTION_SITE: token = LefNextToken(f, TRUE); if (Verbose > 0) Fprintf(stdout, "LEF file: Defines site %s (ignored)\n", token); sprintf(tsave, "%.127s", token); LefSkipSection(f, tsave); break; case LEF_PROPERTY: LefSkipSection(f, NULL); break; case LEF_NOISETABLE: LefSkipSection(f, sections[LEF_NOISETABLE]); break; case LEF_CORRECTIONTABLE: LefSkipSection(f, sections[LEF_CORRECTIONTABLE]); break; case LEF_IRDROP: LefSkipSection(f, sections[LEF_IRDROP]); break; case LEF_ARRAY: LefSkipSection(f, sections[LEF_ARRAY]); break; case LEF_SECTION_TIMING: LefSkipSection(f, sections[LEF_SECTION_TIMING]); break; case LEF_EXTENSION: LefSkipSection(f, sections[LEF_EXTENSION]); break; case LEF_MACRO: token = LefNextToken(f, TRUE); /* Diagnostic */ /* Fprintf(stdout, "LEF file: Defines new cell %s\n", token); */ sprintf(tsave, "%.127s", token); LefReadMacro(f, tsave, oscale); break; case LEF_END: if (!LefParseEndStatement(f, "LIBRARY")) { LefError(LEF_ERROR, "END statement out of context.\n"); keyword = -1; } break; } if (keyword == LEF_END) break; } if (Verbose > 0) { Fprintf(stdout, "LEF read: Processed %d lines.\n", lefCurrentLine); LefError(LEF_ERROR, NULL); /* print statement of errors, if any */ } /* Cleanup */ if (f != NULL) fclose(f); /* Make sure that the gate list has one entry called "pin" */ for (gateginfo = GateInfo; gateginfo; gateginfo = gateginfo->next) if (!strcasecmp(gateginfo->gatename, "pin")) break; if (!gateginfo) { /* Add a new GateInfo entry for pseudo-gate "pin" */ gateginfo = (GATE)malloc(sizeof(struct gate_)); gateginfo->gatetype = NULL; gateginfo->gatename = (char *)malloc(4); strcpy(gateginfo->gatename, "pin"); gateginfo->width = 0.0; gateginfo->height = 0.0; gateginfo->placedX = 0.0; gateginfo->placedY = 0.0; gateginfo->nodes = 1; gateginfo->taps = (DSEG *)malloc(sizeof(DSEG)); gateginfo->noderec = (NODE *)malloc(sizeof(NODE)); gateginfo->area = (float *)malloc(sizeof(float)); gateginfo->direction = (u_char *)malloc(sizeof(u_char)); gateginfo->netnum = (int *)malloc(sizeof(int)); gateginfo->node = (char **)malloc(sizeof(char *)); grect = (DSEG)malloc(sizeof(struct dseg_)); grect->x1 = grect->x2 = 0.0; grect->y1 = grect->y2 = 0.0; grect->next = (DSEG)NULL; gateginfo->obs = (DSEG)NULL; gateginfo->next = GateInfo; gateginfo->taps[0] = grect; gateginfo->noderec[0] = NULL; gateginfo->area[0] = 0.0; gateginfo->netnum[0] = -1; gateginfo->node[0] = strdup("pin"); GateInfo = gateginfo; } PinMacro = gateginfo; /* Work through all of the defined layers, and copy the names into */ /* the strings used for route output, overriding any information */ /* that may have been in the route.cfg file. */ for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_ROUTE) { strcpy(CIFLayer[lefl->type], lefl->lefName); } } /* If VIARULE contacts are not square, generate rotated versions. */ /* Also check that VIARULE sizes meet minimum metal width requirements. */ for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_VIA) { if (lefl->info.via.generated == TRUE) { DSEG viarect1, viarect2, viarect; LefList altVia; u_char nsq1, nsq2; char *vianame; viarect1 = lefl->info.via.lr; if (viarect1 == NULL) continue; viarect2 = lefl->info.via.lr->next; minwidth = LefGetRouteWidth(viarect1->layer); if ((viarect1->x2 - viarect1->x1 + EPS) < (2.0 * minwidth)) { viarect1->x2 = minwidth; viarect1->x1 = -minwidth; } if ((viarect1->y2 - viarect1->y1 + EPS) < (2.0 * minwidth)) { viarect1->y2 = minwidth; viarect1->y1 = -minwidth; } minwidth = LefGetRouteWidth(viarect2->layer); if ((viarect2->x2 - viarect2->x1 + EPS) < (2.0 * minwidth)) { viarect2->x2 = minwidth; viarect2->x1 = -minwidth; } if ((viarect2->y2 - viarect2->y1 + EPS) < (2.0 * minwidth)) { viarect2->y2 = minwidth; viarect2->y1 = -minwidth; } nsq1 = (ABSDIFF((viarect1->x2 - viarect1->x1), (viarect1->y2 - viarect1->y1)) > EPS) ? TRUE : FALSE; if (viarect2) nsq2 = (ABSDIFF((viarect2->x2 - viarect2->x1), (viarect2->y2 - viarect2->y1)) > EPS) ? TRUE : FALSE; else nsq2 = FALSE; /* If viarect is not square, then generate a via in the */ /* 90-degree rotated orientation. */ if (nsq1 || nsq2) { vianame = strdup(lefl->lefName); *(vianame + strlen(vianame) - 1) = '1'; altVia = LefFindLayer(vianame); if (altVia != NULL) { Fprintf(stderr, "Warning: Via name %s has already been " "defined!\n", vianame); continue; } altVia = LefNewVia(vianame); altVia->info.via.generated = TRUE; altVia->next = LefInfo; LefInfo = altVia; /* Copy all but lr geometry from original via */ altVia->lefClass = lefl->lefClass; altVia->info.via.respervia = lefl->info.via.respervia; altVia->info.via.area = lefl->info.via.area; /* Create first lr geometry */ viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *viarect1; if (nsq1) { /* Swap X and Y to rotate */ viarect->x1 = viarect1->y1; viarect->x2 = viarect1->y2; viarect->y1 = viarect1->x1; viarect->y2 = viarect1->x2; } viarect->next = altVia->info.via.lr; altVia->info.via.lr = viarect; /* Create second lr geometry (if it exists) */ if (viarect2) { viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *viarect2; if (nsq2) { /* Swap X and Y to rotate */ viarect->x1 = viarect2->y1; viarect->x2 = viarect2->y2; viarect->y1 = viarect2->x1; viarect->y2 = viarect2->x2; } viarect->next = altVia->info.via.lr; altVia->info.via.lr = viarect; } free(vianame); } if (nsq1 && nsq2) { /* If both contact metal layers are non-square, */ /* then create the additional vias with reversed */ /* orientations of the two layers. */ vianame = strdup(lefl->lefName); *(vianame + strlen(vianame) - 1) = '2'; altVia = LefFindLayer(vianame); if (altVia != NULL) { Fprintf(stderr, "Warning: Via name %s has already been " "defined!\n", vianame); continue; } altVia = LefNewVia(vianame); altVia->info.via.generated = TRUE; altVia->next = LefInfo; LefInfo = altVia; /* Copy all but lr geometry from original via */ altVia->lefClass = lefl->lefClass; altVia->info.via.respervia = lefl->info.via.respervia; altVia->info.via.area = lefl->info.via.area; /* Create first lr geometry, not rotated */ viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *lefl->info.via.lr; viarect->next = altVia->info.via.lr; altVia->info.via.lr = viarect; /* Create second lr geometry, rotated */ viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *lefl->info.via.lr->next; /* Swap X and Y to rotate */ viarect->x1 = lefl->info.via.lr->next->y1; viarect->x2 = lefl->info.via.lr->next->y2; viarect->y1 = lefl->info.via.lr->next->x1; viarect->y2 = lefl->info.via.lr->next->x2; viarect->next = altVia->info.via.lr; altVia->info.via.lr = viarect; /* Repeat in the opposite orientation */ *(vianame + strlen(vianame) - 1) = '3'; altVia = LefFindLayer(vianame); if (altVia != NULL) { Fprintf(stderr, "Warning: Via name %s has already been " "defined!\n", vianame); continue; } altVia = LefNewVia(vianame); altVia->info.via.generated = TRUE; altVia->next = LefInfo; LefInfo = altVia; /* Copy all but lr geometry from original via */ altVia->lefClass = lefl->lefClass; altVia->info.via.respervia = lefl->info.via.respervia; altVia->info.via.area = lefl->info.via.area; /* Create first lr geometry, rotated */ viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *lefl->info.via.lr; /* Swap X and Y to rotate */ viarect->x1 = lefl->info.via.lr->y1; viarect->x2 = lefl->info.via.lr->y2; viarect->y1 = lefl->info.via.lr->x1; viarect->y2 = lefl->info.via.lr->x2; viarect->next = altVia->info.via.lr; altVia->info.via.lr = viarect; /* Create second lr geometry, not rotated */ viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *lefl->info.via.lr->next; viarect->next = altVia->info.via.lr; altVia->info.via.lr = viarect; free(vianame); } } } } /* Find the best via(s) to use per route layer and record it (them) */ LefAssignLayerVias(); return oprecis; } qrouter-1.4.88/config.guess0000755000175000017510000012761513625043307015203 0ustar nileshnilesh#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: qrouter-1.4.88/output.c0000644000175000017510000027262613625043307014372 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* output.c -- qrouter general purpose autorouter */ /* output routines for writing DEF file */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June 2011, based on code by Steve */ /* Beccue, 2003 */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include #include #ifdef TCL_QROUTER #include #endif #include "qrouter.h" #include "qconfig.h" #include "point.h" #include "node.h" #include "maze.h" #include "mask.h" #include "output.h" #include "lef.h" #include "def.h" #include "graphics.h" int Pathon = -1; struct _savepath { u_char active; int x; int y; int orient; } path_delayed; /*--------------------------------------------------------------*/ /* Output a list of failed nets. */ /*--------------------------------------------------------------*/ int write_failed(char *filename) { FILE *ffail; NET net; NETLIST nl; int failcount; failcount = countlist(FailedNets); if (failcount == 0) { Fprintf(stdout, "There are no failing net routes.\n"); return 0; } ffail = fopen(filename, "w"); if (ffail == NULL) { Fprintf(stderr, "Could not open file %s for writing.\n", filename); return 1; } fprintf(ffail, "%d nets failed to route:\n", failcount); for (nl = FailedNets; nl; nl = nl->next) { net = nl->net; fprintf(ffail, " %s\n", net->netname); } fclose(ffail); return 0; } /*--------------------------------------------------------------*/ /* Write the output annotated DEF file. */ /*--------------------------------------------------------------*/ int write_def(char *filename) { NET net; NETLIST nl; emit_routes((filename == NULL) ? DEFfilename : filename, Scales.oscale, Scales.iscale); Fprintf(stdout, "----------------------------------------------\n"); Fprintf(stdout, "Final: "); if (FailedNets == (NETLIST)NULL) Fprintf(stdout, "No failed routes!\n"); else { if (FailedNets != (NETLIST)NULL) { Fprintf(stdout, "Failed net routes: %d\n", countlist(FailedNets)); Fprintf(stdout, "List of failed nets follows:\n"); // Output a list of the failed nets for (nl = FailedNets; nl; nl = nl->next) { net = nl->net; Fprintf(stdout, " %s\n", net->netname); } Fprintf(stdout, "\n"); } } Fprintf(stdout, "----------------------------------------------\n"); return 0; } /* write_def() */ /*--------------------------------------------------------------*/ /* pathstart - begin a DEF format route path */ /* */ /* If "special" is true, then this path is in a */ /* SPECIALNETS section, in which each route specifies */ /* a width. */ /*--------------------------------------------------------------*/ static void pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale, double invscale, u_char horizontal, NODEINFO node) { if (Pathon == 1) { Fprintf( stderr, "pathstart(): Major error. Started a new " "path while one is in progress!\n" "Doing it anyway.\n" ); } if (layer >= 0) { if (Pathon == -1) fprintf(cmd, "+ ROUTED "); else fprintf(cmd, "\n NEW "); if (special) { double wvia; int vtype = 0; /* Need to get via type from node record! */ if (node != NULL) { if ((node->flags & NI_NO_VIAX) && (!(node->flags & NI_VIA_X))) vtype = 2; else if (node->flags & NI_VIA_Y) vtype = 2; } else { /* Assume via orientation matches default route direction. */ /* NOTE: Need to mark the actual orientation somehow. . . */ int ob = LefGetRouteOrientation((layer > 0) ? (layer - 1) : layer); if (ob == 1) vtype = 2; } wvia = LefGetXYViaWidth(layer, layer, horizontal, vtype); if (layer > 0) { double wvia2; wvia2 = LefGetXYViaWidth(layer - 1, layer, horizontal, vtype); if (wvia2 > wvia) wvia = wvia2; } fprintf(cmd, "%s %ld ( %ld %ld ) ", CIFLayer[layer], (long)(0.5 + invscale * oscale * wvia), (long)(0.5 + invscale * x), (long)(0.5 + invscale * y)); } else fprintf(cmd, "%s ( %ld %ld ) ", CIFLayer[layer], (long)(0.5 + invscale * x), (long)(0.5 + invscale * y)); } Pathon = 1; } /* pathstart() */ /*--------------------------------------------------------------*/ /* pathto - continue a path to the next point */ /* */ /* ARGS: coordinate pair */ /* RETURNS: */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ static void pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty, double invscale, u_char nextvia) { if (Pathon <= 0) { Fprintf(stderr, "pathto(): Major error. Added to a " "non-existent path!\n" "Doing it anyway.\n"); } /* If the route is not manhattan, then it's because an offset * was added to the last point, and we need to add a small * jog to the route. */ if ((x != lastx) && (y != lasty)) { if (horizontal) pathto(cmd, lastx, y, FALSE, lastx, lasty, invscale, 0); else pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale, 0); } if (nextvia) { /* Punt on output until via is output, because via may have an */ /* offset position that needs to be applied to the route. */ path_delayed.active = 1; path_delayed.x = x; path_delayed.y = y; path_delayed.orient = horizontal; return; } fprintf(cmd, "( "); if (horizontal) fprintf(cmd, "%ld ", (long)(0.5 + invscale * x)); else fprintf(cmd, "* "); if (horizontal) fprintf(cmd, "* "); else fprintf(cmd, "%ld ", (long)(0.5 + invscale * y)); fprintf(cmd, ") "); } /* pathto() */ /*--------------------------------------------------------------*/ /* pathvia - add a via to a path */ /* */ /* ARGS: coord */ /* RETURNS: */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ static void pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty, char *vianame, double invscale) { if (path_delayed.active == 1) { /* Output the last path */ pathto(cmd, path_delayed.x, path_delayed.y, path_delayed.orient, path_delayed.x, path_delayed.y, invscale, 0); path_delayed.active = 0; } if (Pathon <= 0) { if (Pathon == -1) fprintf(cmd, "+ ROUTED "); else fprintf(cmd, "\n NEW "); fprintf(cmd, "%s ( %ld %ld ) ", CIFLayer[layer], (long)(0.5 + invscale * x), (long)(0.5 + invscale * y)); } else { // Normally the path will be manhattan and only one of // these will be true. But if the via gets an offset to // avoid a DRC spacing violation with an adjacent via, // then we may need to apply both paths to make a dog-leg // route to the via. if (x != lastx) pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale, 0); if (y != lasty) pathto(cmd, x, y, FALSE, x, lasty, invscale, 0); } fprintf(cmd, "%s ", vianame); Pathon = 0; } /* pathvia() */ /*--------------------------------------------------------------*/ /* Nodes aren't saved in a way that makes it easy to recall */ /* the name of the cell and pin to which they belong. But */ /* that information doesn't need to be looked up except as a */ /* diagnostic output. This routine does that lookup. */ /*--------------------------------------------------------------*/ char *print_node_name(NODE node) { GATE g; int i; char *nodestr = NULL; for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->noderec[i] == node) { if (nodestr != NULL) free(nodestr); if (!strcmp(g->node[i], "pin")) { nodestr = (char *)malloc(strlen(g->gatename) + 5); sprintf(nodestr, "PIN/%s", g->gatename); } else { nodestr = (char *)malloc(strlen(g->gatename) + strlen(g->node[i]) + 2); sprintf(nodestr, "%s/%s", g->gatename, g->node[i]); } return nodestr; } } } if (nodestr != NULL) free(nodestr); nodestr = (char *)malloc(22); sprintf(nodestr, "(error: no such node)"); return nodestr; } /*--------------------------------------------------------------*/ /* print_nets - print the nets list - created from Nlgates list */ /* */ /* ARGS: filename to list to */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Sat July 26 */ /*--------------------------------------------------------------*/ void print_nets(char *filename) { FILE *o; GATE g; int i; DSEG drect; if (!strcmp(filename, "stdout")) { o = stdout; } else { o = fopen(filename, "w"); } if (!o) { Fprintf(stderr, "route:print_nets. Couldn't open output file\n"); return; } for (g = Nlgates; g; g = g->next) { fprintf(o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename); for (i = 0; i < g->nodes; i++) { // This prints the first tap position only. drect = g->taps[i]; fprintf( o, "%s(%g,%g) ", g->node[i], drect->x1, drect->y1); } } fprintf( o, "\n"); } /* print_nets() */ /*--------------------------------------------------------------*/ /* print_routes - print the routes list */ /* */ /* ARGS: filename to list to */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Sat July 26 */ /*--------------------------------------------------------------*/ void print_routes( char *filename ) { FILE *o; GATE g; int i; if( !strcmp( filename, "stdout" ) ) { o = stdout; } else { o = fopen( filename, "w" ); } if( !o ) { Fprintf( stderr, "route:print_routes. Couldn't open output file\n" ); return; } for (g = Nlgates; g; g = g->next) { fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename ); for( i = 0 ; i < g->nodes; i++ ) { fprintf( o, "%s ", g->node[i] ); } fprintf(o, "\n"); } } /* print_routes() */ /*--------------------------------------------------------------*/ /* print_nlgates - print the nlgate list */ /* */ /* ARGS: filename to list to */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Wed July 23 */ /*--------------------------------------------------------------*/ void print_nlgates( char *filename ) { FILE *o; GATE g; int i; DSEG drect; if( !strcmp( filename, "stdout" ) ) { o = stdout; } else { o = fopen( filename, "w" ); } if( !o ) { Fprintf( stderr, "route:print_nlgates. Couldn't open output file\n" ); return; } for (g = Nlgates; g; g = g->next) { fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename ); for( i = 0 ; i < g->nodes; i++ ) { // This prints the first tap position only. drect = g->taps[i]; fprintf( o, "%s(%g,%g)", g->node[i], drect->x1, drect->y1); } fprintf(o, "\n"); } } /* print_nlgates() */ /*--------------------------------------------------------------*/ /* print_net - print info about the net to stdout */ /* */ /* ARGS: net to print info about */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ void print_net(NET net) { NODE node; DPOINT tap; int i, first; Fprintf(stdout, "Net %d: %s", net->netnum, net->netname); for (node = net->netnodes; node != NULL; node = node->next) { Fprintf(stdout, "\n Node %d (%s): \n Taps: ", node->nodenum, print_node_name(node)); for (tap = node->taps, i = 0, first = TRUE; tap != NULL; tap = tap->next, i = (i + 1) % 4, first = FALSE) { Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)", (i == 0 ? (first ? "" : "\n ") : " "), tap->layer, tap->x, tap->y ); } Fprintf(stdout, "\n Tap extends: "); for (tap = node->extend, i = 0, first = TRUE; tap != NULL; tap = tap->next, i = (i + 1) % 4, first = FALSE) { Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)", (i == 0 ? (first ? "" : "\n ") : " "), tap->layer, tap->x, tap->y ); } } Fprintf(stdout, "\n bbox: (%d,%d)-(%d,%d)\n", net->xmin, net->ymin, net->xmax, net->ymax ); } /*--------------------------------------------------------------*/ /* print_gate - print info about the net to stdout */ /* */ /* ARGS: gate to print info about */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ void print_gate(GATE gate) { int i, j, first; DSEG seg; NODE node; DPOINT tap; Fprintf(stdout, "Gate %s\n", gate->gatename); Fprintf(stdout, " Loc: (%.2lf, %.2lf), WxH: %.2lfx%.2lf\n", gate->placedX, gate->placedY, gate->width, gate->height ); Fprintf(stdout, " Pins"); for (i = 0; i < gate->nodes; i++) { Fprintf(stdout, "\n Pin %s, net %d\n", gate->node[i], gate->netnum[i] ); Fprintf(stdout, " Segs: "); for (seg = gate->taps[i], j = 0, first = TRUE; seg != NULL; seg = seg->next, j = (j + 1) % 3, first = FALSE) { Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)-(%.2lf,%.2lf)", (j == 0 ? (first ? "" : "\n ") : " "), seg->layer, seg->x1, seg->y1, seg->x2, seg->y2 ); } if ((node = gate->noderec[i]) != NULL) { Fprintf(stdout, "\n Taps: "); for (tap = node->taps, j = 0, first = TRUE; tap != NULL; tap = tap->next, j = (j + 1) % 4, first = FALSE) { Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)", (j == 0 ? (first ? "" : "\n ") : " "), tap->layer, tap->x, tap->y ); } Fprintf(stdout, "\n Tap extends: "); for (tap = node->extend, j = 0, first = TRUE; tap != NULL; tap = tap->next, j = (j + 1) % 4, first = FALSE) { Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)", (j == 0 ? (first ? "" : "\n ") : " "), tap->layer, tap->x, tap->y ); } } } Fprintf(stdout, "\n Obstructions: "); for (seg = gate->obs, j = 0, first = TRUE; seg != NULL; seg = seg->next, j = (j + 1) % 3, first = FALSE) { Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)-(%.2lf,%.2lf)", (j == 0 ? (first ? "" : "\n ") : " "), seg->layer, seg->x1, seg->y1, seg->x2, seg->y2 ); } Fprintf(stdout, "\n"); } /*--------------------------------------------------------------*/ /* print_nodes - show the nodes list */ /* */ /* ARGS: filename to print to */ /* RETURNS: nothing */ /* SIDE EFFECTS: none */ /* AUTHOR and DATE: steve beccue Tue Aug 04 2003 */ /*--------------------------------------------------------------*/ void print_nodes(char *filename) { FILE *o; int i; NET net; NODE node; DPOINT dp; if (!strcmp(filename, "stdout")) { o = stdout; } else { o = fopen(filename, "w"); } if (!o) { Fprintf( stderr, "node.c:print_nodes. Couldn't open output file\n" ); return; } for (i = 0; i < Numnets; i++) { net = Nlnets[i]; for (node = net->netnodes; node; node = node->next) { dp = (DPOINT)node->taps; fprintf(o, "%d\t%s\t(%g,%g)(%d,%d) :%d:num=%d netnum=%d\n", node->nodenum, node->netname, // legacy: print only the first point dp->x, dp->y, dp->gridx, dp->gridy, node->netnum, node->numnodes, node->netnum ); /* need to print the routes to this node (deprecated) for (j = 0 ; j < g->nodes; j++) { fprintf(o, "%s(%g,%g) ", g->node[j], *(g->x[j]), *(g->y[j])); } */ } } fclose(o); } /* print_nodes() */ /*--------------------------------------------------------------*/ /* print_nlnets - show the nets */ /* */ /* ARGS: filename to print to */ /* RETURNS: nothing */ /* SIDE EFFECTS: none */ /* AUTHOR and DATE: steve beccue Tue Aug 04 2003 */ /*--------------------------------------------------------------*/ void print_nlnets( char *filename ) { FILE *o; int i; NODE nd; NET net; if (!strcmp(filename, "stdout")) { o = stdout; } else { o = fopen(filename, "w"); } if (!o) { Fprintf(stderr, "node.c:print_nlnets. Couldn't open output file\n"); return; } for (i = 0; i < Numnets; i++) { net = Nlnets[i]; fprintf(o, "%d\t#=%d\t%s \t\n", net->netnum, net->numnodes, net->netname); for (nd = net->netnodes; nd; nd = nd->next) { fprintf(o, "%d ", nd->nodenum); } } fprintf(o, "%d nets\n", Numnets); fflush(o); } /* print_nlnets() */ /*--------------------------------------------------------------*/ /* print_grid_information() */ /* */ /* For help in debugging routing problems, print information */ /* about blockages marked at a specific grid position. */ /*--------------------------------------------------------------*/ void print_grid_information(int gridx, int gridy, int layer) { u_int obsval; int i, apos; double dx, dy; int netidx; NET net; NODE node; NODEINFO lnode; DSEG ds; apos = OGRID(gridx, gridy); obsval = Obs[layer][apos]; lnode = Nodeinfo[layer][apos]; if (lnode != NULL) { node = lnode->nodesav; if (node != NULL) { Fprintf(stdout, "Grid position %d %d is an active node tap.\n", gridx, gridy); if (node->netname) Fprintf(stdout, "Node at grid position is %s and belongs " "to net \"%s\".\n", print_node_name(node), node->netname); else Fprintf(stdout, "Node at grid position is %s and is not routed.\n", print_node_name(node)); if (lnode->nodeloc == NULL) { Fprintf(stdout, "Position temporarily disabled to avoid " "blocking the tap.\n"); } } else Fprintf(stdout, "Grid position %d %d is a disabled node tap.\n", gridx, gridy); if (lnode->flags & NI_VIA_X) Fprintf(stdout, "Via may be placed horizontally on tap.\n"); if (lnode->flags & NI_VIA_Y) Fprintf(stdout, "Via may be placed vertically on tap.\n"); if (lnode->flags & NI_NO_VIAX) Fprintf(stdout, "Horizontal vias are prohibited on tap.\n"); if (lnode->flags & NI_NO_VIAY) Fprintf(stdout, "Vertical vias are prohibited on tap.\n"); if (lnode->flags & NI_OFFSET_EW) { if (lnode->offset > 0.0) Fprintf(stdout, "Tap connection offset to the east %gum\n", lnode->offset); else Fprintf(stdout, "Tap connection offset to the west %gum\n", -lnode->offset); } if (lnode->flags & NI_OFFSET_NS) { if (lnode->offset > 0.0) Fprintf(stdout, "Tap connection offset to the north %gum\n", lnode->offset); else Fprintf(stdout, "Tap connection offset to the south %gum\n", -lnode->offset); } if (lnode->flags & NI_STUB_EW) { if (lnode->stub > 0.0) Fprintf(stdout, "Stub connection to the east length %gum\n", lnode->stub); else Fprintf(stdout, "Stub connection to the west length %gum\n", -lnode->stub); } if (lnode->flags & NI_STUB_NS) { if (lnode->stub > 0.0) Fprintf(stdout, "Stub connection to the north length %gum\n", lnode->stub); else Fprintf(stdout, "Stub connection to the south length %gum\n", -lnode->stub); } if ((lnode->flags == 0) || (lnode->flags == NI_VIA_X | NI_VIA_Y)) Fprintf(stdout, "Node is cleanly routable with no restrictions.\n"); } else Fprintf(stdout, "Grid position is not associated with a node tap.\n"); if (obsval & OFFSET_TAP) Fprintf(stdout, "Grid position requires a route position offset.\n"); if (obsval & STUBROUTE) Fprintf(stdout, "Grid position requires a stub route to reach tap.\n"); if (obsval & ROUTED_NET) Fprintf(stdout, "Grid position is assigned to routed net.\n"); if (obsval & BLOCKED_N) Fprintf(stdout, "Grid position cannot be reached from the north.\n"); if (obsval & BLOCKED_S) Fprintf(stdout, "Grid position cannot be reached from the south.\n"); if (obsval & BLOCKED_E) Fprintf(stdout, "Grid position cannot be reached from the east.\n"); if (obsval & BLOCKED_W) Fprintf(stdout, "Grid position cannot be reached from the west.\n"); if (obsval & BLOCKED_U) Fprintf(stdout, "Grid position cannot be reached from above.\n"); if (obsval & BLOCKED_D) Fprintf(stdout, "Grid position cannot be reached from below.\n"); if ((obsval & (OBSTRUCT_MASK | NO_NET)) == (OBSTRUCT_MASK | NO_NET)) { Fprintf(stdout, "Grid position is completely obstructed\n"); /* Check if grid position is completely obstructed by a UserObs object */ dx = Xlowerbound + gridx * PitchX; dy = Ylowerbound + gridy * PitchY; for (ds = UserObs; ds; ds = ds->next) { if (ds->layer == layer) { if (ds->x1 < dx && ds->x2 > dx && ds->y1 < dy && ds->y2 > dy) { Fprintf(stdout, "Defined obstruction at (%g, %g) to (%g, %g) " "covers the tap point.\n", ds->x1, ds->y1, ds->x2, ds->y2); } } } } else if (obsval & NO_NET) { if ((obsval & OBSTRUCT_MASK != 0) && (lnode == NULL)) { Fprintf(stdout, "Error: Position marked as node obstruction has " "no node assigned!\n"); } else if (lnode != NULL) { if (obsval & OBSTRUCT_N) Fprintf(stdout, "Grid position is obstructed to the north at %gum.\n", lnode->offset); if (obsval & OBSTRUCT_S) Fprintf(stdout, "Grid position is obstructed to the south at %gum.\n", lnode->offset); if (obsval & OBSTRUCT_E) Fprintf(stdout, "Grid position is obstructed to the east at %gum.\n", lnode->offset); if (obsval & OBSTRUCT_W) Fprintf(stdout, "Grid position is obstructed to the west at %gum.\n", lnode->offset); } } if ((obsval & DRC_BLOCKAGE) == DRC_BLOCKAGE) { Fprintf(stdout, "Grid position disabled by neighboring route to prevent" " DRC violations.\n"); } if (((obsval & ROUTED_NET_MASK) != 0) && ((obsval & NO_NET) == 0)) { netidx = obsval & NETNUM_MASK; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->netnum == netidx) break; } if ((netidx > MAX_NETNUMS) || (i >= Numnets)) { Fprintf(stdout, "Error: Grid position marked with a bad net number.\n"); } else { net = Nlnets[i]; Fprintf(stdout, "Grid position assigned to routed net \"%s\".\n", net->netname); } } } /*--------------------------------------------------------------*/ /* print_instance_information() */ /* */ /* For help in debugging routing problems, print information */ /* about an instance. */ /*--------------------------------------------------------------*/ void print_instance_information(char *instname) { NET net; GATE gate; for (gate = Nlgates; gate; gate = gate->next) { if (!strcmp(gate->gatename, instname)) { print_gate(gate); break; } } } /*--------------------------------------------------------------*/ /* print_node_information() */ /* */ /* For help in debugging routing problems, print information */ /* about a node (instance and pin). */ /*--------------------------------------------------------------*/ void print_node_information(char *nodename) { int i, j, k, l, apos; NET net; NODE node; NODEINFO lnode; GATE gate; char *pptr, *instname, *pinname; pptr = strchr(nodename, '/'); if (pptr == NULL) { Fprintf(stderr, "Node name is not in / format!\n"); return; } *pptr = '\0'; instname = nodename; pinname = pptr + 1; for (gate = Nlgates; gate; gate = gate->next) { if (!strcmp(gate->gatename, instname)) { for (i = 0; i < gate->nodes; i++) { if (!strcmp(gate->node[i], pinname)) { node = gate->noderec[i]; Fprintf(stdout, "Instance name is %s\n", gate->gatename); if (gate->gatetype) Fprintf(stdout, "Gate type is %s\n", gate->gatetype->gatename); else Fprintf(stdout, "Node name is %s\n", print_node_name(node)); Fprintf(stdout, "Net connecting to node is %s\n", node->netname); /* Find all grid positions that route to this node */ Fprintf(stdout, "Grid positions assigned to node:\n"); for (j = 0; j < NumChannelsX; j++) { for (k = 0; k < NumChannelsY; k++) { for (l = 0; l < Pinlayers; l++) { apos = OGRID(j, k); lnode = Nodeinfo[l][apos]; if (lnode && lnode->nodesav == node) { Fprintf(stdout, " (%g, %g)um x=%d y=%d layer=%d\n", Xlowerbound + j * PitchX, Ylowerbound + k * PitchY, j, k, l); } } } } break; } } break; } } *pptr = '/'; } /*--------------------------------------------------------------*/ /* print_net_information() */ /* */ /* For help in debugging routing problems, print information */ /* about a net. */ /*--------------------------------------------------------------*/ void print_net_information(char *netname) { int i; NET net; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (!strcmp(net->netname, netname)) { print_net(net); break; } } } /*--------------------------------------------------------------*/ /* link_up_seg --- */ /* */ /* As part of cleanup_net (below), when removing unneeded vias, */ /* it may be necessary to check if a segment is being used to */ /* connect to another route of a net, in which case removing */ /* the segment would break the net. If that is the case, then */ /* keep the segment by linking it to the end of the route that */ /* was connected to it. */ /* */ /* Return 1 (true) if the segment was linked to another route, */ /* so the caller knows whether or not to free the segment. */ /* */ /* "rt" is the route that the segment was connected to. For */ /* the sake of efficiency, it does not need to be checked. */ /*--------------------------------------------------------------*/ u_char link_up_seg(NET net, SEG seg, int viabase, ROUTE srt) { ROUTE rt; SEG segf, segl; int x, y; for (rt = net->routes; rt; rt = rt->next) { if (rt == srt) continue; segf = rt->segments; if ((segf->x1 == seg->x1) && (segf->y1 == seg->y1) && ((segf->layer == viabase) || (segf->layer == viabase + 1))) { /* Reverse seg and prepend it to the route */ seg->next = rt->segments; rt->segments = seg; x = seg->x1; y = seg->y1; seg->x1 = seg->x2; seg->y1 = seg->y2; seg->x2 = x; seg->y2 = y; return (u_char)1; } /* Move to the last segment of the route */ for (segl = segf; segl && segl->next; segl = segl->next); if (segl && (segl->x2 == seg->x1) && (segl->y2 == seg->y1) && ((segl->layer == viabase) || (segl->layer == viabase + 1))) { /* Append seg to the route */ segl->next = seg; return (u_char)1; } } return (u_char)0; } /*--------------------------------------------------------------*/ /* cleanup_net -- */ /* */ /* Special handling for layers where needblock[] is non-zero, */ /* and shows that two vias cannot be placed on adjacent routes. */ /* emit_routed_net() will add specialnets to merge two adjacent */ /* vias on the same route. However, this cannot be used for */ /* adjacent vias that are each in a different route record. It */ /* is easier just to find any such instances and remove them by */ /* eliminating one of the vias and adding a segment to connect */ /* the route to the neighboring via. */ /* */ /* Note that the ensuing change in connectivity can violate */ /* the route endpoints and thereby mess up the delay output */ /* routine and/or the antenna violation finding routine unless */ /* route_set_connections() is re-run on the modified routes. */ /*--------------------------------------------------------------*/ void cleanup_net(NET net) { SEG segf, segl, seg, segp; ROUTE rt, rt2; NODEINFO lnode; int lf, ll, lf2, ll2, viabase; u_char fcheck, lcheck, needfix; u_char xcheckf, ycheckf, xcheckl, ycheckl; lf = ll = lf2 = ll2 = -1; needfix = FALSE; for (rt = net->routes; rt; rt = rt->next) { fcheck = lcheck = FALSE; // This problem will only show up on route endpoints. // segf is the first segment of the route. // segl is the last segment of the route. // lf is the layer at the route start (layer first) // lf2 is the layer of the second segment. // ll is the layer at the route end (layer last) // ll2 is the layer of the next-to-last segment segf = rt->segments; if (segf == NULL) continue; if ((segf->next != NULL) && (segf->segtype == ST_VIA)) { if (segf->next->layer > segf->layer) { lf = segf->layer; lf2 = segf->layer + 1; } else { lf = segf->layer + 1; lf2 = segf->layer; } // Set flag fcheck indicating that segf needs checking fcheck = TRUE; // We're going to remove the contact so it can't be a tap if ((lf < Pinlayers) && ((lnode = NODEIPTR(segf->x1, segf->y1, lf)) != NULL) && (lnode->nodesav != NULL)) fcheck = FALSE; } /* This could be done if vias are always too close when */ /* placed on adjacent tracks. However, that ignores the */ /* problem of vias with offsets, and it ignores the fact */ /* that adjacent vias on the same net are always a */ /* redundancy. */ xcheckf = needblock[lf] & VIABLOCKX; ycheckf = needblock[lf] & VIABLOCKY; if (!xcheckf && !ycheckf) fcheck = FALSE; // Move to the next-to-last segment for (segl = segf->next; segl && segl->next && segl->next->next; segl = segl->next); if (segl && (segl->next != NULL) && (segl->next->segtype == ST_VIA)) { if (segl->next->layer < segl->layer) { ll = segl->next->layer; ll2 = segl->next->layer + 1; } else { ll = segl->next->layer + 1; ll2 = segl->next->layer; } // Move segl to the last segment segl = segl->next; // Set flag lcheck indicating that segl needs checking. lcheck = TRUE; // We're going to remove the contact so it can't be a tap if ((ll < Pinlayers) && ((lnode = NODEIPTR(segl->x1, segl->y1, ll)) != NULL) && (lnode->nodesav != NULL)) lcheck = FALSE; } xcheckl = needblock[ll] & VIABLOCKX; ycheckl = needblock[ll] & VIABLOCKY; if (!xcheckl && !ycheckl) lcheck = FALSE; // For each route rt2 that is not rt, look at every via // and see if it is adjacent to segf or segl. for (rt2 = net->routes; rt2; rt2 = rt2->next) { if ((fcheck == FALSE) && (lcheck == FALSE)) break; if (rt2 == rt) continue; for (seg = rt2->segments; seg; seg = seg->next) { if (seg->segtype & ST_VIA) { if (fcheck) { if ((seg->layer == lf) || ((seg->layer + 1) == lf)) { if (xcheckf && (seg->y1 == segf->y1) && (ABSDIFF(seg->x1, segf->x1) == 1)) { needfix = TRUE; if (seg->layer != segf->layer) { // Adjacent vias are different types. // Deal with it by creating a route between // the vias on their shared layer. This // will later be made into a special net to // avoid notch DRC errors. SEG newseg; newseg = (SEG)malloc(sizeof(struct seg_)); rt->segments = newseg; newseg->next = segf; newseg->layer = lf; newseg->segtype = ST_WIRE; newseg->x1 = segf->x1; newseg->y1 = segf->y1; newseg->x2 = seg->x1; newseg->y2 = seg->y1; } else { // Change via to wire route, connect it to seg, // and make sure it has the same layer type as // the following route. segf->segtype = ST_WIRE; segf->x1 = seg->x1; segf->layer = lf2; } } else if (ycheckf && (seg->x1 == segf->x1) && (ABSDIFF(seg->y1, segf->y1) == 1)) { needfix = TRUE; if (seg->layer != segf->layer) { // Adjacent vias are different types. // Deal with it by creating a route between // the vias on their shared layer. This // will later be made into a special net to // avoid notch DRC errors. SEG newseg; newseg = (SEG)malloc(sizeof(struct seg_)); rt->segments = newseg; newseg->next = segf; newseg->layer = lf; newseg->segtype = ST_WIRE; newseg->x1 = segf->x1; newseg->y1 = segf->y1; newseg->x2 = seg->x1; newseg->y2 = seg->y1; } else { // Change via to wire route, connect it to seg, // and make sure it has the same layer type as // the following route. segf->segtype = ST_WIRE; segf->y1 = seg->y1; segf->layer = lf2; } } } } if (lcheck) { if ((seg->layer == ll) || ((seg->layer + 1) == ll)) { if (xcheckl && (seg->y1 == segl->y1) && (ABSDIFF(seg->x1, segl->x1) == 1)) { needfix = TRUE; if (seg->layer != segl->layer) { // Adjacent vias are different types. // Deal with it by creating a route between // the vias on their shared layer. This // will later be made into a special net to // avoid notch DRC errors. SEG newseg; newseg = (SEG)malloc(sizeof(struct seg_)); segl->next = newseg; newseg->next = NULL; newseg->layer = ll; newseg->segtype = ST_WIRE; newseg->x1 = segl->x1; newseg->y1 = segl->y1; newseg->x2 = seg->x1; newseg->y2 = seg->y1; } else { // Change via to wire route, connect it to seg, // and make sure it has the same layer type as // the previous route. segl->segtype = ST_WIRE; segl->x2 = seg->x2; segl->layer = ll2; } } else if (ycheckl && (seg->x1 == segl->x1) && (ABSDIFF(seg->y1, segl->y1) == 1)) { needfix = TRUE; if (seg->layer != segl->layer) { // Adjacent vias are different types. // Deal with it by creating a route between // the vias on their shared layer. This // will later be made into a special net to // avoid notch DRC errors. SEG newseg; newseg = (SEG)malloc(sizeof(struct seg_)); segl->next = newseg; newseg->next = NULL; newseg->layer = ll; newseg->segtype = ST_WIRE; newseg->x1 = segl->x1; newseg->y1 = segl->y1; newseg->x2 = seg->x1; newseg->y2 = seg->y1; } else { // Change via to wire route, connect it to seg, // and make sure it has the same layer type as // the previous route. segl->segtype = ST_WIRE; segl->y2 = seg->y2; segl->layer = ll2; } } } } } } } /* One case not covered by the checks above: If the second or */ /* penultimate segment is a via and the final segment is one */ /* track in length and connects to a via, then the same */ /* replacement can be made. The other routes do not need to be */ /* checked, as it is sufficient to check that the grid is */ /* occupied at that point on two metal layers with the same net. */ /* NOTE: Another route could be connecting to the via on the */ /* penultimate segment, and removing it would cause an open net. */ /* Check for this case and resolve if needed. */ if ((fcheck == FALSE) && (lcheck == FALSE)) { int wlen, oval0, oval1, oval2; segf = rt->segments; if ((segf == NULL) || (segf->next == NULL)) continue; seg = segf->next; if ((segf->segtype == ST_WIRE) && (seg->segtype == ST_VIA)) { if ((segf->x1 - segf->x2) == 0) { wlen = segf->y1 - segf->y2; if ((wlen == 1) || (wlen == -1)) { oval1 = OBSVAL(segf->x1, segf->y1, seg->layer) & ROUTED_NET_MASK; oval2 = OBSVAL(segf->x1, segf->y1, seg->layer + 1) & ROUTED_NET_MASK; if (oval1 == oval2) { /* Check false case in which (layer + 1) is a min area stub */ segp = seg->next; if (segp && (segp->x2 == segf->x1) && (segp->y2 == segf->y1)) continue; /* Remove via and change wire layer */ needfix = TRUE; segf->next = seg->next; viabase = segf->layer; segf->layer = (viabase == seg->layer) ? seg->layer + 1 : seg->layer; if (!link_up_seg(net, seg, viabase, rt)) free(seg); } } } else if ((segf->y1 - segf->y2) == 0) { wlen = segf->x1 - segf->x2; if ((wlen == 1) || (wlen == -1)) { oval1 = OBSVAL(segf->x1, segf->y1, seg->layer) & ROUTED_NET_MASK; oval2 = OBSVAL(segf->x1, segf->y1, seg->layer + 1) & ROUTED_NET_MASK; if (oval1 == oval2) { /* Check false case in which (layer + 1) is a min area stub */ segp = seg->next; if (segp && (segp->x2 == segf->x1) && (segp->y2 == segf->y1)) continue; /* Remove via and change wire layer */ needfix = TRUE; segf->next = seg->next; viabase = segf->layer; segf->layer = (viabase == seg->layer) ? seg->layer + 1 : seg->layer; if (!link_up_seg(net, seg, viabase, rt)) free(seg); } } } } segp = NULL; for (seg = rt->segments; seg && seg->next && seg->next->next; seg = seg->next) segp = seg; if ((seg == NULL) || (seg->next == NULL)) continue; segl = seg->next; if ((segl->segtype == ST_WIRE) && (seg->segtype == ST_VIA)) { if ((segl->x1 - segl->x2) == 0) { wlen = segl->y1 - segl->y2; if ((wlen == 1) || (wlen == -1)) { oval1 = OBSVAL(segl->x2, segl->y2, seg->layer) & ROUTED_NET_MASK; oval2 = OBSVAL(segl->x2, segl->y2, seg->layer + 1) & ROUTED_NET_MASK; if (oval1 == oval2) { /* Check false case in which (layer + 1) is a min area stub */ if (segp && (segp->x1 == segl->x2) && (segp->y1 == segl->y2)) continue; /* Remove via and change wire layer */ needfix = TRUE; seg->next = NULL; seg->segtype = ST_WIRE; viabase = seg->layer; seg->layer = (viabase == segl->layer) ? viabase + 1 : viabase; seg->x1 = segl->x1; seg->y1 = segl->y1; seg->x2 = segl->x2; seg->y2 = segl->y2; if (!link_up_seg(net, segl, viabase, rt)) free(segl); } } } else if ((segl->y1 - segl->y2) == 0) { wlen = segl->x1 - segl->x2; if ((wlen == 1) || (wlen == -1)) { oval1 = OBSVAL(segl->x2, segl->y2, seg->layer) & ROUTED_NET_MASK; oval2 = OBSVAL(segl->x2, segl->y2, seg->layer + 1) & ROUTED_NET_MASK; if (oval1 == oval2) { /* Check false case in which (layer + 1) is a min area stub */ if (segp && (segp->x1 == segl->x2) && (segp->y1 == segl->y2)) continue; /* Remove via and change wire layer */ needfix = TRUE; viabase = seg->layer; seg->next = NULL; seg->segtype = ST_WIRE; seg->layer = (viabase == segl->layer) ? viabase + 1 : viabase; seg->x1 = segl->x1; seg->y1 = segl->y1; seg->x2 = segl->x2; seg->y2 = segl->y2; if (!link_up_seg(net, segl, viabase, rt)) free(segl); } } } } } } if (needfix == TRUE) for (rt = net->routes; rt; rt = rt->next) route_set_connections(net, rt); } /*--------------------------------------------------------------*/ /* emit_routed_net -- */ /* */ /* Core part of emit_routes(). Dumps the DEF format for a */ /* complete net route to file Cmd. If "special" is TRUE, then */ /* it looks only for stub routes between a grid point and an */ /* off-grid terminal, and dumps only the stub route geometry as */ /* a SPECIALNET, which takes a width parameter. This allows */ /* the stub routes to be given the same width as a via, when */ /* the via is larger than a route width, to avoid DRC notch */ /* errors between the via and the terminal. The SPECIALNETS */ /* are redundant; all routing information is in the NETS */ /* section. The SPECIALNETS only specify a wider route for the */ /* stub connection. */ /*--------------------------------------------------------------*/ static void emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale) { SEG seg, saveseg, lastseg, prevseg; NODEINFO lnode, lnode1, lnode2; ROUTE rt; u_int dir1, dir2, tdir; int layer; int x = 0, y = 0, x2, y2; double dc; int lastx = -1, lasty = -1, lastlay; int horizontal; float offset1, offset2, stub, offset; u_char cancel, segtype, nextvia; double invscale = (double)(1.0 / (double)iscale); /* If the STUB flag is set, then we need to write out the net name */ /* in the SPECIALNETS section. */ if ((special == (u_char)1) && (net->flags & NET_STUB)) { fprintf(Cmd, ";\n- %s\n", net->netname); } Pathon = -1; lastlay = -1; /* Insert routed net here */ for (rt = net->routes; rt; rt = rt->next) { path_delayed.active = 0; if (rt->segments && !(rt->flags & RT_OUTPUT)) { horizontal = FALSE; cancel = FALSE; // Check first position for terminal offsets seg = (SEG)rt->segments; lastseg = saveseg = seg; layer = seg->layer; if (seg) { nextvia = (seg->next) ? ((seg->next->segtype == ST_VIA) ? 1 : 0) : 0; // It is rare but possible to have a stub route off of an // endpoint via, so check this case, and use the layer type // of the via top if needed. if ((seg->segtype & ST_VIA) && seg->next && (seg->next->layer <= seg->layer)) layer++; lnode = (layer < Pinlayers) ? NODEIPTR(seg->x1, seg->y1, layer) : NULL; stub = (lnode) ? lnode->stub : 0.0; if (OBSVAL(seg->x1, seg->y1, layer) & STUBROUTE) { if ((special == (u_char)0) && (Verbose > 2)) Fprintf(stdout, "Stub route distance %g to terminal" " at %d %d (%d)\n", stub, seg->x1, seg->y1, layer); dc = Xlowerbound + (double)seg->x1 * PitchX; x = (int)((REPS(dc)) * oscale); if (lnode->flags & NI_STUB_EW) dc += stub; x2 = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y1 * PitchY; y = (int)((REPS(dc)) * oscale); if (lnode->flags & NI_STUB_NS) dc += stub; y2 = (int)((REPS(dc)) * oscale); if (lnode->flags & NI_STUB_EW) { horizontal = TRUE; // If the gridpoint ahead of the stub has a route // on the same net, and the stub is long enough // to come within a DRC spacing distance of the // other route, then lengthen it to close up the // distance and resolve the error. (NOTE: This // unnecessarily stretches routes to cover taps // that have not been routed to. At least on the // test standard cell set, these rules remove a // handful of DRC errors and don't create any new // ones. If necessary, a flag can be added to // distinguish routes from taps. if ((x < x2) && (seg->x1 < (NumChannelsX - 1))) { tdir = OBSVAL(seg->x1 + 1, seg->y1, layer); if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (stub + LefGetRouteKeepout(layer) >= PitchX) { dc = Xlowerbound + (double)(seg->x1 + 1) * PitchX; x2 = (int)((REPS(dc)) * oscale); } } } else if ((x > x2) && (seg->x1 > 0)) { tdir = OBSVAL(seg->x1 - 1, seg->y1, layer); if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (-stub + LefGetRouteKeepout(layer) >= PitchX) { dc = Xlowerbound + (double)(seg->x1 - 1) * PitchX; x2 = (int)((REPS(dc)) * oscale); } } } dc = oscale * 0.5 * LefGetRouteWidth(layer); if (special == (u_char)0) { // Regular nets include 1/2 route width at // the ends, so subtract from the stub terminus if (x < x2) { x2 -= dc; if (x >= x2) cancel = TRUE; } else { x2 += dc; if (x <= x2) cancel = TRUE; } } else { // Special nets don't include 1/2 route width // at the ends, so add to the route at the grid if (x < x2) x -= dc; else x += dc; // Routes that extend for more than one track // without a bend do not need a wide stub if (seg->x1 != seg->x2) cancel = TRUE; } } else { horizontal = FALSE; // If the gridpoint ahead of the stub has a route // on the same net, and the stub is long enough // to come within a DRC spacing distance of the // other route, then lengthen it to close up the // distance and resolve the error. if ((y < y2) && (seg->y1 < (NumChannelsY - 1))) { tdir = OBSVAL(seg->x1, seg->y1 + 1, layer); if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (stub + LefGetRouteKeepout(layer) >= PitchY) { dc = Ylowerbound + (double)(seg->y1 + 1) * PitchY; y2 = (int)((REPS(dc)) * oscale); } } } else if ((y > y2) && (seg->y1 > 0)) { tdir = OBSVAL(seg->x1, seg->y1 - 1, layer); if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (-stub + LefGetRouteKeepout(layer) >= PitchY) { dc = Ylowerbound + (double)(seg->y1 - 1) * PitchY; y2 = (int)((REPS(dc)) * oscale); } } } dc = oscale * 0.5 * LefGetRouteWidth(layer); if (special == (u_char)0) { // Regular nets include 1/2 route width at // the ends, so subtract from the stub terminus if (y < y2) { y2 -= dc; if (y >= y2) cancel = TRUE; } else { y2 += dc; if (y <= y2) cancel = TRUE; } } else { // Special nets don't include 1/2 route width // at the ends, so add to the route at the grid if (y < y2) y -= dc; else y += dc; // Routes that extend for more than one track // without a bend do not need a wide stub if (seg->y1 != seg->y2) cancel = TRUE; } } if (cancel == FALSE) { net->flags |= NET_STUB; rt->flags |= RT_STUB; pathstart(Cmd, layer, x2, y2, special, oscale, invscale, horizontal, lnode); pathto(Cmd, x, y, horizontal, x2, y2, invscale, nextvia); } lastx = x; lasty = y; lastlay = layer; } } prevseg = NULL; lastseg = NULL; for (seg = rt->segments; seg; seg = seg->next) { nextvia = (seg->next) ? ((seg->next->segtype == ST_VIA) ? 1 : 0) : 0; layer = seg->layer; // Check for offset terminals at either point offset1 = 0.0; offset2 = 0.0; dir1 = 0; dir2 = 0; lnode1 = lnode2 = NULL; if (seg->segtype & ST_OFFSET_START) { dir1 = OBSVAL(seg->x1, seg->y1, seg->layer) & OFFSET_TAP; if ((dir1 == 0) && lastseg) { dir1 = OBSVAL(lastseg->x2, lastseg->y2, lastseg->layer) & OFFSET_TAP; lnode1 = NODEIPTR(lastseg->x2, lastseg->y2, lastseg->layer); offset1 = lnode1->offset; } else { lnode1 = NODEIPTR(seg->x1, seg->y1, seg->layer); offset1 = lnode1->offset; } // Offset was calculated for vias; plain metal routes // typically will need less offset distance, so subtract off // the difference. if (!(seg->segtype & ST_VIA)) { if (offset1 < 0) { offset1 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer, horizontal) - LefGetRouteWidth(seg->layer)); if (offset1 > 0) offset1 = 0; } else if (offset1 > 0) { offset1 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer, horizontal) - LefGetRouteWidth(seg->layer)); if (offset1 < 0) offset1 = 0; } } if (special == (u_char)0) { if ((seg->segtype & ST_VIA) && (Verbose > 2)) Fprintf(stdout, "Offset terminal distance %g to grid" " at %d %d (%d)\n", offset1, seg->x1, seg->y1, layer); } } if (seg->segtype & ST_OFFSET_END) { dir2 = OBSVAL(seg->x2, seg->y2, seg->layer) & OFFSET_TAP; if ((dir2 == 0) && seg->next) { dir2 = OBSVAL(seg->next->x1, seg->next->y1, seg->next->layer) & OFFSET_TAP; lnode2 = NODEIPTR(seg->next->x1, seg->next->y1, seg->next->layer); if (lnode2 != NULL) offset2 = lnode2->offset; } else { lnode2 = NODEIPTR(seg->x2, seg->y2, seg->layer); if (lnode2 != NULL) offset2 = lnode2->offset; } // Offset was calculated for vias; plain metal routes // typically will need less offset distance, so subtract off // the difference. if (!(seg->segtype & ST_VIA)) { if (offset2 < 0) { offset2 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer, horizontal) - LefGetRouteWidth(seg->layer)); if (offset2 > 0) offset2 = 0; } else if (offset2 > 0) { offset2 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer, horizontal) - LefGetRouteWidth(seg->layer)); if (offset2 < 0) offset2 = 0; } } if (special == (u_char)0) { if ((seg->segtype & ST_VIA) && !(seg->segtype & ST_OFFSET_START)) if (Verbose > 2) Fprintf(stdout, "Offset terminal distance %g to grid" " at %d %d (%d)\n", offset2, seg->x2, seg->y2, layer); } } // To do: pick up route layer name from lefInfo. // At the moment, technology names don't even match, // and are redundant between CIFLayer[] from the // config file and lefInfo. dc = Xlowerbound + (double)seg->x1 * PitchX; if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_EW)) dc += offset1; x = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y1 * PitchY; if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_NS)) dc += offset1; y = (int)((REPS(dc)) * oscale); dc = Xlowerbound + (double)seg->x2 * PitchX; if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_EW)) dc += offset2; x2 = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y2 * PitchY; if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_NS)) dc += offset2; y2 = (int)((REPS(dc)) * oscale); segtype = seg->segtype & ~(ST_OFFSET_START | ST_OFFSET_END); switch (segtype) { case ST_WIRE: // Normally layers change only at a via. However, if // a via has been removed and replaced by a 1-track // segment to a neighboring via to avoid DRC errors // (see cleanup_net()), then a layer change may happen // between two ST_WIRE segments, and a new path should // be started. if ((Pathon != -1) && (lastlay != -1) && (lastlay != seg->layer)) Pathon = 0; if (Pathon != 1) { // 1st point of route seg if (x == x2) { horizontal = FALSE; } else if (y == y2) { horizontal = TRUE; } else if (Verbose > 3) { // NOTE: This is a development diagnostic. The // occasional non-Manhanhattan route is due to a // tap offset and is corrected automatically by // making an L-bend in the wire. Flush(stdout); Fprintf(stderr, "Warning: non-Manhattan wire in route" " at (%d, %d) to (%d, %d)\n", x, y, x2, y2); } if (special == (u_char)0) { if (lastseg && (lastseg->segtype & ST_OFFSET_START) && ((lastx != x) || (lasty != y))) { /* Add bend and connect to offset via */ int vertical = (horizontal) ? FALSE : TRUE; pathstart(Cmd, seg->layer, lastx, lasty, special, oscale, invscale, vertical, lnode2); pathto(Cmd, x, y, vertical, lastx, lasty, invscale, nextvia); } else if (lastseg && (lastseg->segtype & ST_VIA) && (lastx != x) && (lasty == y) && (LefGetRouteOrientation(seg->layer) == 1)) { /* Via offset in direction of route (horizontal) */ pathstart(Cmd, seg->layer, lastx, y, special, oscale, invscale, horizontal, lnode2); } else if (lastseg && (lastseg->segtype & ST_VIA) && (lastx == x) && (lasty != y) && (LefGetRouteOrientation(seg->layer) == 0)) { /* Via offset in direction of route (vertical) */ pathstart(Cmd, seg->layer, x, lasty, special, oscale, invscale, horizontal, lnode2); } else { pathstart(Cmd, seg->layer, x, y, special, oscale, invscale, horizontal, lnode2); } lastx = x; lasty = y; lastlay = seg->layer; } } rt->flags |= RT_OUTPUT; if (horizontal && x == x2) { horizontal = FALSE; } if ((!horizontal) && y == y2) { horizontal = TRUE; } if (!(x == x2) && !(y == y2)) { horizontal = FALSE; } if (special == (u_char)0) { pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale, nextvia); lastx = x2; lasty = y2; } // Check for path segments that are used for minimum metal // area requirements so that they do not become false // positives for inter-via special nets. if (lastseg && seg->next && (lastseg->x1 == seg->next->x2) && (lastseg->y1 == seg->next->y2)) seg->segtype |= ST_MINMETAL; // If a segment is 1 track long, there is a via on either // end, and the needblock flag is set for the layer, then // draw a stub route along the length of the track. if (horizontal && needblock[seg->layer] & VIABLOCKX) { if ((ABSDIFF(seg->x2, seg->x1) == 1) && !(seg->segtype & ST_MINMETAL)) { if ((lastseg && lastseg->segtype == ST_VIA) || (seg->next && seg->next->segtype == ST_VIA)) { if (special == (u_char)0) { net->flags |= NET_STUB; rt->flags |= RT_STUB; } else { if (Pathon != -1) Pathon = 0; pathstart(Cmd, layer, x, y, special, oscale, invscale, horizontal, lnode2); pathto(Cmd, x2, y2, horizontal, x, y, invscale, 0); lastlay = layer; } } } } else if (!horizontal && needblock[seg->layer] & VIABLOCKY) { if ((ABSDIFF(seg->y2, seg->y1) == 1) && !(seg->segtype & ST_MINMETAL)) { if ((lastseg && lastseg->segtype == ST_VIA) || (seg->next && seg->next->segtype == ST_VIA)) { if (special == (u_char)0) { net->flags |= NET_STUB; rt->flags |= RT_STUB; } else { if (Pathon != -1) Pathon = 0; pathstart(Cmd, layer, x, y, special, oscale, invscale, horizontal, lnode2); pathto(Cmd, x2, y2, horizontal, x, y, invscale, 0); lastlay = layer; } } } } break; case ST_VIA: rt->flags |= RT_OUTPUT; if (special == (u_char)0) { double viaoffx, viaoffy; double w0, w1, dc, altwx, altwy; float offsetx, offsety; int vx = 0; int vy = 0; int flags; u_int tdirpp, tdirp, tdirn; u_char viaNL, viaNM, viaNU; u_char viaSL, viaSM, viaSU; u_char viaEL, viaEM, viaEU; u_char viaWL, viaWM, viaWU; u_char rteNL, rteNU; u_char rteSL, rteSU; u_char rteEL, rteEU; u_char rteWL, rteWU; char *s; char checkersign; int ob, ot; if (lastseg == NULL) { // Make sure last position is valid lastx = x; lasty = y; } // If vias need to be rotated then they do so on a // checkerboard pattern. checkersign = (char)((seg->x1 + seg->y1) & 0x01); // Get the default orientation of the via ob = LefGetRouteOrientation(layer); ot = LefGetRouteOrientation(layer + 1); if (ob == 0 && ot == 1) s = ViaYX[layer]; else if (ob == 1 && ot == 0) s = ViaXY[layer]; else if (ob == 0 && ot == 0) s = ViaYY[layer]; else s = ViaXX[layer]; // If via is on a pin and rotation is restricted, then // set the rotation accordingly. flags = 0; if (layer < Pinlayers) { if ((lnode = NODEIPTR(seg->x1, seg->y1, layer)) != NULL) { if (lnode->flags & NI_NO_VIAX) { flags = NI_NO_VIAX; if (s == ViaXY[layer]) s = ViaYY[layer]; else if (s == ViaXX[layer]) s = ViaYX[layer]; } if (lnode->flags & NI_NO_VIAY) { flags = NI_NO_VIAY; if (s == ViaYX[layer]) s = ViaXX[layer]; else if (s == ViaYY[layer]) s = ViaXY[layer]; } /* Mark the node with which via direction was used */ if ((s == ViaYY[layer]) || (s == ViaYX[layer])) lnode->flags |= NI_VIA_Y; else lnode->flags |= NI_VIA_X; } } // Check for vias between adjacent but different nets // that need rotation and/or position offsets to avoid // a DRC spacing error viaEL = viaEM = viaEU = 0; viaWL = viaWM = viaWU = 0; viaNL = viaNM = viaNU = 0; viaSL = viaSM = viaSU = 0; rteEL = rteEU = rteWL = rteWU = 0; rteNL = rteNU = rteSL = rteSU = 0; // Check for via/route to west if (seg->x1 > 0) { tdir = OBSVAL(seg->x1 - 1, seg->y1, layer) & ROUTED_NET_MASK; if (((tdir & NO_NET) == 0) && (tdir != 0) && (tdir != (net->netnum | ROUTED_NET))) { rteWL = 1; if (layer > 0) { tdirn = OBSVAL(seg->x1 - 1, seg->y1, layer - 1) & ROUTED_NET_MASK; if (tdir == tdirn) viaWL = 1; } } if (layer < Num_layers - 1) { tdirp = OBSVAL(seg->x1 - 1, seg->y1, layer + 1) & ROUTED_NET_MASK; if (((tdirp & NO_NET) == 0) && (tdirp != 0) && (tdirp != (net->netnum | ROUTED_NET))) { rteWU = 1; if (layer < Num_layers - 2) { tdirpp = OBSVAL(seg->x1 - 1, seg->y1, layer + 2) & ROUTED_NET_MASK; if (tdirp == tdirpp) viaWU = 1; } } if (rteWL && (tdir == tdirp)) viaWM = 1; } } // Check for via/route to east if (seg->x1 < NumChannelsX - 1) { tdir = OBSVAL(seg->x1 + 1, seg->y1, layer) & ROUTED_NET_MASK; if (((tdir & NO_NET) == 0) && (tdir != 0) && (tdir != (net->netnum | ROUTED_NET))) { rteEL = 1; if (layer > 0) { tdirn = OBSVAL(seg->x1 + 1, seg->y1, layer - 1) & ROUTED_NET_MASK; if (tdir == tdirn) viaEL = 1; } } if (layer < Num_layers - 1) { tdirp = OBSVAL(seg->x1 + 1, seg->y1, layer + 1) & ROUTED_NET_MASK; if (((tdirp & NO_NET) == 0) && (tdirp != 0) && (tdirp != (net->netnum | ROUTED_NET))) { rteEU = 1; if (layer < Num_layers - 2) { tdirpp = OBSVAL(seg->x1 + 1, seg->y1, layer + 2) & ROUTED_NET_MASK; if (tdirp == tdirpp) viaEU = 1; } } if (rteEL && (tdir == tdirp)) viaEM = 1; } } // Check for via/route to south if (seg->y1 > 0) { tdir = OBSVAL(seg->x1, seg->y1 - 1, layer) & ROUTED_NET_MASK; if (((tdir & NO_NET) == 0) && (tdir != 0) && (tdir != (net->netnum | ROUTED_NET))) { rteSL = 1; if (layer > 0) { tdirn = OBSVAL(seg->x1, seg->y1 - 1, layer - 1) & ROUTED_NET_MASK; if (tdir == tdirn) viaSL = 1; } } if (layer < Num_layers - 1) { tdirp = OBSVAL(seg->x1, seg->y1 - 1, layer + 1) & ROUTED_NET_MASK; if (((tdirp & NO_NET) == 0) && (tdirp != 0) && (tdirp != (net->netnum | ROUTED_NET))) { rteSU = 1; if (layer < Num_layers - 2) { tdirpp = OBSVAL(seg->x1, seg->y1 - 1, layer + 2) & ROUTED_NET_MASK; if (tdirp == tdirpp) viaSU = 1; } } if (rteSL && (tdir == tdirp)) viaSM = 1; } } // Check for via/route to north if (seg->y1 < NumChannelsY - 1) { tdir = OBSVAL(seg->x1, seg->y1 + 1, layer) & ROUTED_NET_MASK; if (((tdir & NO_NET) == 0) && (tdir != 0) && (tdir != (net->netnum | ROUTED_NET))) { rteNL = 1; if (layer > 0) { tdirn = OBSVAL(seg->x1, seg->y1 + 1, layer - 1) & ROUTED_NET_MASK; if (tdir == tdirn) viaNL = 1; } } if (layer < Num_layers - 1) { tdirp = OBSVAL(seg->x1, seg->y1 + 1, layer + 1) & ROUTED_NET_MASK; if (((tdirp & NO_NET) == 0) && (tdirp != 0) && (tdirp != (net->netnum | ROUTED_NET))) { rteNU = 1; if (layer < Num_layers - 2) { tdirpp = OBSVAL(seg->x1, seg->y1 + 1, layer + 2) & ROUTED_NET_MASK; if (tdirp == tdirpp) viaNU = 1; } } if (rteNL && (tdir == tdirp)) viaNM = 1; } } // Check for any tap offset on the neighboring via, // which needs to be accounted for in the calculations. offsetx = offsety = 0.0; if (viaEL) lnode = (layer < Pinlayers && layer > 0) ? NODEIPTR(seg->x1 + 1, seg->y1, layer - 1) : NULL; else if (viaWL) lnode = (layer < Pinlayers && layer > 0) ? NODEIPTR(seg->x1 - 1, seg->y1, layer - 1) : NULL; else if (viaEM) lnode = (layer < Pinlayers) ? NODEIPTR(seg->x1 + 1, seg->y1, layer) : NULL; else if (viaWM) lnode = (layer < Pinlayers) ? NODEIPTR(seg->x1 - 1, seg->y1, layer) : NULL; else if (viaEU) lnode = (layer < Pinlayers - 1) ? NODEIPTR(seg->x1 + 1, seg->y1, layer + 1) : NULL; else if (viaWU) lnode = (layer < Pinlayers - 1) ? NODEIPTR(seg->x1 - 1, seg->y1, layer + 1) : NULL; if (lnode && (lnode->flags & NI_OFFSET_EW)) { offsetx = lnode->offset; // offsetx defined as positive in the direction away from // the via under consideration. if (viaWL || viaWM || viaWU) offsetx = -offsetx; } if (viaNL) lnode = (layer < Pinlayers && layer > 0) ? NODEIPTR(seg->x1, seg->y1 + 1, layer - 1) : NULL; else if (viaSL) lnode = (layer < Pinlayers && layer > 0) ? NODEIPTR(seg->x1, seg->y1 - 1, layer - 1) : NULL; else if (viaNM) lnode = (layer < Pinlayers) ? NODEIPTR(seg->x1, seg->y1 + 1, layer) : NULL; else if (viaSM) lnode = (layer < Pinlayers) ? NODEIPTR(seg->x1, seg->y1 - 1, layer) : NULL; else if (viaNU) lnode = (layer < Pinlayers - 1) ? NODEIPTR(seg->x1, seg->y1 + 1, layer + 1) : NULL; else if (viaSU) lnode = (layer < Pinlayers - 1) ? NODEIPTR(seg->x1, seg->y1 - 1, layer + 1) : NULL; if (lnode && (lnode->flags & NI_OFFSET_NS)) { offsety = lnode->offset; // offsety defined as positive in the direction away from // the via under consideration. if (viaSL || viaSM || viaSU) offsety = -offsety; } // Actions needed only if a via is on the long side and // has a spacing violation. viaoffx = viaoffy = 0.0; altwx = altwy = 0.0; if (ob == 1) { /* bottom (layer) route is horizontal */ if (viaEM || viaWM) { /* Assume default rotations and calculate spacing */ /* Only take action if there is a spacing violation */ w1 = LefGetXYViaWidth(layer, layer, 0, 0); w0 = w1; dc = LefGetRouteSpacing(layer) + w1; if (dc > PitchX + EPS + offsetx) { /* via on checkerboard may be rotated */ if (checkersign && ((flags & NI_NO_VIAY) == 0)) { /* Check spacing violation to routes N and S */ /* If via being checked is rotated */ if (rteNL || rteSL) dc = LefGetRouteSpacing(layer) + (LefGetXYViaWidth(layer, layer, 1, 2) + LefGetRouteWidth(layer)) / 2; if ((!(rteNL || rteSL)) || (dc <= PitchY + EPS)) { /* Okay to rotate the via bottom */ w0 = LefGetXYViaWidth(layer, layer, 0, 2); s = (ot == 1) ? ViaYX[layer] : ViaYY[layer]; } else if (rteNL || rteSL) altwx = w1 - LefGetXYViaWidth(layer, layer, 0, 2); /* Measure spacing violation to via */ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* Calculate offset */ if (viaEM) viaoffx = PitchX + 2 * offsetx - dc; else viaoffx = dc - PitchX - 2 * offsetx; } } else { /* Measure spacing violation to rotated via */ w0 = LefGetXYViaWidth(layer, layer, 0, 2); dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* Calculate offset */ if (viaEM) viaoffx = PitchX + 2 * offsetx - dc; else viaoffx = dc - PitchX - 2 * offsetx; } } } } else if (viaEL || viaWL) { /* Assume default rotations and calculate spacing */ /* Only take action if there is a spacing violation */ w0 = LefGetXYViaWidth(layer - 1, layer, 0, 0); w1 = LefGetXYViaWidth(layer, layer, 0, 0); dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* via on checkerboard may be rotated */ if (checkersign && ((flags & NI_NO_VIAY) == 0)) { /* Check spacing violation to routes N and S */ /* If via being checked is rotated */ if (rteNL || rteSL) dc = LefGetRouteSpacing(layer) + (LefGetXYViaWidth(layer, layer, 1, 2) + LefGetRouteWidth(layer)) / 2; if ((!(rteNL || rteSL)) || (dc <= PitchY + EPS)) { /* Okay to rotate the via bottom */ w1 = LefGetXYViaWidth(layer, layer, 0, 2); s = (ot == 1) ? ViaYX[layer] : ViaYY[layer]; } else if (rteNL || rteSL) altwx = w1 - LefGetXYViaWidth(layer, layer, 0, 2); /* Measure spacing violation to via */ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* Calculate offset */ if (viaEL) viaoffx = PitchX + 2 * offsetx - dc; else viaoffx = dc - PitchX - 2 * offsetx; } } else { /* Measure spacing violation to rotated via */ w0 = LefGetXYViaWidth(layer - 1, layer, 0, 1); dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* Calculate offset */ if (viaEL) viaoffx = PitchX + 2 * offsetx - dc; else viaoffx = dc - PitchX - 2 * offsetx; } } } } } else { /* bottom route vertical */ if (viaNM || viaSM) { /* Assume default rotations and calculate spacing */ /* Only take action if there is a spacing violation */ w1 = LefGetXYViaWidth(layer, layer, 1, 3); w0 = w1; dc = LefGetRouteSpacing(layer) + w1; if (dc > PitchY + EPS + offsety) { /* via on checkerboard may be rotated */ if (checkersign && ((flags & NI_NO_VIAX) == 0)) { /* Check spacing violation to routes E and W */ /* If via being checked is rotated */ if (rteEL || rteWL) dc = LefGetRouteSpacing(layer) + (LefGetXYViaWidth(layer, layer, 0, 1) + LefGetRouteWidth(layer)) / 2; if ((!(rteEL || rteWL)) || (dc <= PitchX + EPS)) { /* Okay to rotate the via bottom */ w0 = LefGetXYViaWidth(layer, layer, 1, 1); s = (ot == 1) ? ViaXX[layer] : ViaXY[layer]; } else if (rteEL || rteWL) altwy = w1 - LefGetXYViaWidth(layer, layer, 1, 1); /* Measure spacing violation to via */ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* Calculate offset */ if (viaNM) viaoffy = PitchY + 2 * offsety - dc; else viaoffy = dc - PitchY - 2 * offsety; } } else { /* Measure spacing violation to rotated via */ w0 = LefGetXYViaWidth(layer, layer, 1, 1); dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* Calculate offset */ if (viaNM) viaoffy = PitchY + 2 * offsety - dc; else viaoffy = dc - PitchY - 2 * offsety; } } } } else if (viaNL || viaSL) { /* Assume default rotations and calculate spacing */ /* Only take action if there is a spacing violation */ w0 = LefGetXYViaWidth(layer - 1, layer, 1, 3); w1 = LefGetXYViaWidth(layer, layer, 1, 3); dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* via on checkerboard may be rotated */ if (checkersign && ((flags & NI_NO_VIAX) == 0)) { /* Check spacing violation to routes E and W */ /* If via being checked is rotated */ if (rteEL || rteWL) dc = LefGetRouteSpacing(layer) + (LefGetXYViaWidth(layer, layer, 0, 1) + LefGetRouteWidth(layer)) / 2; if ((!(rteEL || rteWL)) || (dc <= PitchX + EPS)) { /* Okay to rotate the via bottom */ w1 = LefGetXYViaWidth(layer, layer, 1, 1); s = (ot == 1) ? ViaXX[layer] : ViaXY[layer]; } else if (rteEL || rteWL) altwy = w1 - LefGetXYViaWidth(layer, layer, 1, 1); /* Measure spacing violation to via */ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* Calculate offset */ if (viaNL) viaoffy = PitchY + 2 * offsety - dc; else viaoffy = dc - PitchY - 2 * offsety; } } else { /* Measure spacing violation to rotated via */ w0 = LefGetXYViaWidth(layer - 1, layer, 1, 2); dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* Calculate offset */ if (viaNL) viaoffy = PitchY + 2 * offsety - dc; else viaoffy = dc - PitchY - 2 * offsety; } } } } } if (ot == 1) { /* top route horizontal */ if (viaEU || viaWU) { /* Assume default rotations and calculate spacing */ /* Only take action if there is a spacing violation */ w0 = LefGetXYViaWidth(layer + 1, layer + 1, 0, 0); w1 = LefGetXYViaWidth(layer, layer + 1, 0, 0); dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* via on checkerboard may be rotated */ if (checkersign) { /* Check spacing violation to routes N and S */ /* If via being checked is rotated */ if (rteNU || rteSU) dc = LefGetRouteSpacing(layer + 1) + (LefGetXYViaWidth(layer, layer + 1, 1, 1) + LefGetRouteWidth(layer + 1)) / 2; if ((!(rteNU || rteSU)) || (dc <= PitchY + EPS)) { /* Okay to rotate the via top */ w1 = LefGetXYViaWidth(layer, layer + 1, 0, 1); s = (s == ViaYX[layer]) ? ViaYY[layer] : ViaXY[layer]; } else if (rteNU || rteSU) altwx = w1 - LefGetXYViaWidth(layer, layer + 1, 0, 1); /* Measure spacing violation to via */ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* Calculate offset */ if (viaEU) viaoffx = PitchX + 2 * offsetx - dc; else viaoffx = dc - PitchX - 2 * offsetx; } } else { /* Measure spacing violation to rotated via */ w0 = LefGetXYViaWidth(layer + 1, layer + 1, 0, 2); dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* Calculate offset */ if (viaEU) viaoffx = PitchX + 2 * offsetx - dc; else viaoffx = dc - PitchX - 2 * offsetx; } } } } else if (viaEM || viaWM) { /* Assume default rotations and calculate spacing */ /* Only take action if there is a spacing violation */ w1 = LefGetXYViaWidth(layer, layer + 1, 0, 0); w0 = w1; dc = LefGetRouteSpacing(layer + 1) + w1; if (dc > PitchX + EPS + offsetx) { /* via on checkerboard may be rotated */ if (checkersign) { /* Check spacing violation to routes N and S */ /* If via being checked is rotated */ if (rteNU || rteSU) dc = LefGetRouteSpacing(layer) + (LefGetXYViaWidth(layer, layer + 1, 1, 1) + LefGetRouteWidth(layer)) / 2; if ((!(rteNU || rteSU)) || (dc <= PitchY + EPS)) { /* Okay to rotate the via top */ w0 = LefGetXYViaWidth(layer, layer + 1, 0, 1); s = (s == ViaYX[layer]) ? ViaYY[layer] : ViaXY[layer]; } else if (rteNU || rteSU) altwx = w1 - LefGetXYViaWidth(layer, layer + 1, 0, 1); /* Measure spacing violation to via */ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* Calculate offset */ if (viaEM) viaoffx = PitchX + 2 * offsetx - dc; else viaoffx = dc - PitchX - 2 * offsetx; } } else { /* Measure spacing violation to rotated via */ w0 = LefGetXYViaWidth(layer, layer + 1, 0, 1); dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchX + EPS + offsetx) { /* Calculate offset */ if (viaEM) viaoffx = PitchX + 2 * offsetx - dc; else viaoffx = dc - PitchX - 2 * offsetx; } } } } } else { /* top route vertical */ if (viaNU || viaSU) { /* Assume default rotations and calculate spacing */ /* Only take action if there is a spacing violation */ w0 = LefGetXYViaWidth(layer + 1, layer + 1, 1, 3); w1 = LefGetXYViaWidth(layer, layer + 1, 1, 3); dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* via on checkerboard may be rotated */ if (checkersign) { /* Check spacing violation to routes E and W */ /* If via being checked is rotated */ if (rteEU || rteWU) dc = LefGetRouteSpacing(layer + 1) + (LefGetXYViaWidth(layer, layer + 1, 0, 2) + LefGetRouteWidth(layer + 1)) / 2; if ((!(rteEU || rteWU)) || (dc <= PitchX + EPS)) { /* Okay to rotate the via top */ w1 = LefGetXYViaWidth(layer, layer + 1, 1, 2); s = (s == ViaYY[layer]) ? ViaYX[layer] : ViaXX[layer]; } else if (rteEU || rteWU) altwy = w1 - LefGetXYViaWidth(layer, layer + 1, 1, 2); /* Measure spacing violation to via */ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* Calculate offset */ if (viaNU) viaoffy = PitchY + 2 * offsety - dc; else viaoffy = dc - PitchY - 2 * offsety; } } else { /* Measure spacing violation to rotated via */ w0 = LefGetXYViaWidth(layer + 1, layer + 1, 1, 1); dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* Calculate offset */ if (viaNU) viaoffy = PitchY + 2 * offsety - dc; else viaoffy = dc - PitchY - 2 * offsety; } } } } else if (viaNM || viaSM) { /* Assume default rotations and calculate spacing */ /* Only take action if there is a spacing violation */ w1 = LefGetXYViaWidth(layer, layer + 1, 1, 3); w0 = w1; dc = LefGetRouteSpacing(layer + 1) + w1; if (dc > PitchY + EPS + offsety) { /* via on checkerboard may be rotated */ if (checkersign) { /* Check spacing violation to routes E and W */ /* If via being checked is rotated */ if (rteEU || rteWU) dc = LefGetRouteSpacing(layer + 1) + (LefGetXYViaWidth(layer, layer + 1, 0, 2) + LefGetRouteWidth(layer + 1)) / 2; if ((!(rteEU || rteWU)) || (dc <= PitchX + EPS)) { /* Okay to rotate the via top */ w1 = LefGetXYViaWidth(layer, layer + 1, 1, 2); s = (s == ViaYY[layer]) ? ViaYX[layer] : ViaXX[layer]; } else if (rteEU || rteWU) altwy = w1 - LefGetXYViaWidth(layer, layer + 1, 1, 2); /* Measure spacing violation to via */ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* Calculate offset */ if (viaNM) viaoffy = PitchY + 2 * offsety - dc; else viaoffy = dc - PitchY - 2 * offsety; } } else { /* Measure spacing violation to rotated via */ w0 = LefGetXYViaWidth(layer, layer + 1, 1, 2); dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2; if (dc > PitchY + EPS + offsety) { /* Calculate offset */ if (viaNM) viaoffy = PitchY + 2 * offsety - dc; else viaoffy = dc - PitchY - 2 * offsety; } } } } } /* If a via is constrained by routes on the side */ /* and cannot be rotated, then the calculations on */ /* the via in the next track will not take that */ /* into consideration, and not leave enough space. */ /* So this via must offset more to make up the */ /* difference. */ if (altwx > 0.0) { if (viaoffx < 0) altwx = -altwx; viaoffx += altwx; } if (altwy > 0.0) { if (viaoffy < 0) altwy = -altwy; viaoffy += altwy; } /* When offset, each via moves by half the distance. */ viaoffx /= 2; viaoffy /= 2; vx = (int)((REPS(viaoffx)) * oscale); vy = (int)((REPS(viaoffy)) * oscale); /* If via is offset in the direction of the last */ /* route segment, then move the last route segment */ /* position to the via center. */ if ((path_delayed.active == 1) && (vy != 0) && (path_delayed.orient == 0)) path_delayed.y = y + vy; else if ((path_delayed.active == 1) && (vx != 0) && (path_delayed.orient == 1)) path_delayed.x = x + vx; pathvia(Cmd, layer, x + vx, y + vy, lastx, lasty, s, invscale); lastx = x + vx; lasty = y + vy; lastlay = -1; } break; default: break; } // Break here on last segment so that seg and lastseg are valid // in the following section of code. if (seg->next == NULL) break; prevseg = lastseg; lastseg = seg; } // For stub routes, reset the path between terminals, since // the stubs are not connected. if (special == (u_char)1 && Pathon != -1) Pathon = 0; // Check last position for terminal offsets if (seg && ((seg != saveseg) || (seg->segtype & ST_WIRE))) { cancel = FALSE; layer = seg->layer; lnode = (layer < Pinlayers) ? NODEIPTR(seg->x2, seg->y2, layer) : NULL; // Look for stub routes and offset taps dir2 = OBSVAL(seg->x2, seg->y2, layer) & (STUBROUTE | OFFSET_TAP); if ((dir2 & OFFSET_TAP) && (seg->segtype & ST_VIA) && prevseg) { // Additional handling for offset taps. When a tap position // is a via and is offset in the direction of the last // route segment, then a DRC violation can be created if // (1) the via is wider than the route width, and (2) the // adjacent track position is another via or a bend in the // route, and (3) the tap offset is large enough to create // a spacing violation between the via and the adjacent via // or perpendicular route. If these three conditions are // satisfied, then generate a stub route the width of the // via and one track pitch in length back toward the last // track position. // Problems only arise when the via width is larger than // the width of the metal route leaving the via. offset = lnode->offset; if (LefGetViaWidth(seg->layer, lastseg->layer, 1 - horizontal) > LefGetRouteWidth(lastseg->layer)) { // Problems only arise when the last segment is exactly // one track long. if ((ABSDIFF(lastseg->x2, lastseg->x1) == 1) || (ABSDIFF(lastseg->y2, lastseg->y1) == 1)) { if (prevseg->segtype & ST_VIA) { dc = Xlowerbound + (double)seg->x1 * PitchX; x = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y1 * PitchY; y = (int)((REPS(dc)) * oscale); dc = Xlowerbound + (double)prevseg->x1 * PitchX; x2 = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)prevseg->y1 * PitchY; y2 = (int)((REPS(dc)) * oscale); // Setup is (via, 1 track route, via with offset) if (prevseg->x1 != seg->x1) { if ((PitchX - 0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) - 0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 1) - (prevseg->x1 - seg->x1) * offset) < LefGetRouteSpacing(lastseg->layer)) { if (special == (u_char)0) { rt->flags |= RT_STUB; net->flags |= NET_STUB; } else { pathstart(Cmd, lastseg->layer, x, y, (u_char)1, oscale, invscale, 1, lnode); pathto(Cmd, x2, y2, 1, x, y, invscale, 0); lastx = x2; lasty = y2; } } } else if (prevseg->y1 != seg->y1) { if ((PitchY - 0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) - 0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 0) - (prevseg->y1 - seg->y1) * offset) < LefGetRouteSpacing(lastseg->layer)) { if (special == (u_char)0) { rt->flags |= RT_STUB; net->flags |= NET_STUB; } else { pathstart(Cmd, lastseg->layer, x, y, (u_char)1, oscale, invscale, 0, lnode); pathto(Cmd, x2, y2, 0, x, y, invscale, 0); lastx = x2; lasty = y2; } } } } else { // Metal route bends at next track if (prevseg->x1 != seg->x1) { if ((PitchX - 0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) - 0.5 * LefGetRouteWidth(prevseg->layer) - (prevseg->x1 - seg->x1) * offset) < LefGetRouteSpacing(lastseg->layer)) { if (special == (u_char)0) { rt->flags |= RT_STUB; net->flags |= NET_STUB; } else { pathstart(Cmd, lastseg->layer, x, y, (u_char)1, oscale, invscale, 1, lnode); pathto(Cmd, x2, y2, 1, x, y, invscale, 0); lastx = x2; lasty = y2; } } } else if (prevseg->y1 != seg->y1) { if ((PitchY - 0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) - 0.5 * LefGetRouteWidth(prevseg->layer) - (prevseg->y1 - seg->y1) * offset) < LefGetRouteSpacing(lastseg->layer)) { if (special == (u_char)0) { rt->flags |= RT_STUB; net->flags |= NET_STUB; } else { pathstart(Cmd, lastseg->layer, x, y, (u_char)1, oscale, invscale, 0, lnode); pathto(Cmd, x2, y2, 0, x, y, invscale, 0); lastx = x2; lasty = y2; } } } } } } } // For stub routes, reset the path between terminals, since // the stubs are not connected. if (special == (u_char)1 && Pathon != -1) Pathon = 0; // Handling of stub routes if (dir2 & STUBROUTE) { stub = lnode->stub; if ((special == (u_char)0) && (Verbose > 2)) Fprintf(stdout, "Stub route distance %g to terminal" " at %d %d (%d)\n", stub, seg->x2, seg->y2, layer); dc = Xlowerbound + (double)seg->x2 * PitchX; if (lnode->flags & NI_OFFSET_EW) dc += offset; x = (int)((REPS(dc)) * oscale); if (lnode->flags & NI_STUB_EW) dc += stub; x2 = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y2 * PitchY; if (lnode->flags & NI_OFFSET_NS) dc += offset; y = (int)((REPS(dc)) * oscale); if (lnode->flags & NI_STUB_NS) dc += stub; y2 = (int)((REPS(dc)) * oscale); if (lnode->flags & NI_STUB_EW) { horizontal = TRUE; // If the gridpoint ahead of the stub has a route // on the same net, and the stub is long enough // to come within a DRC spacing distance of the // other route, then lengthen it to close up the // distance and resolve the error. if ((x < x2) && (seg->x2 < (NumChannelsX - 1))) { tdir = OBSVAL(seg->x2 + 1, seg->y2, layer); if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (stub + LefGetRouteKeepout(layer) >= PitchX) { dc = Xlowerbound + (double)(seg->x2 + 1) * PitchX; x2 = (int)((REPS(dc)) * oscale); } } } else if ((x > x2) && (seg->x2 > 0)) { tdir = OBSVAL(seg->x2 - 1, seg->y2, layer); if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (-stub + LefGetRouteKeepout(layer) >= PitchX) { dc = Xlowerbound + (double)(seg->x2 - 1) * PitchX; x2 = (int)((REPS(dc)) * oscale); } } } dc = oscale * 0.5 * LefGetRouteWidth(layer); if (special == (u_char)0) { // Regular nets include 1/2 route width at // the ends, so subtract from the stub terminus if (x < x2) { x2 -= dc; if (x >= x2) cancel = TRUE; } else { x2 += dc; if (x <= x2) cancel = TRUE; } } else { // Special nets don't include 1/2 route width // at the ends, so add to the route at the grid if (x < x2) x -= dc; else x += dc; // Routes that extend for more than one track // without a bend do not need a wide stub if (seg->x1 != seg->x2) cancel = TRUE; } } else { /* lnode->flags & NI_STUB_EW implied */ horizontal = FALSE; // If the gridpoint ahead of the stub has a route // on the same net, and the stub is long enough // to come within a DRC spacing distance of the // other route, then lengthen it to close up the // distance and resolve the error. if ((y < y2) && (seg->y2 < (NumChannelsY - 1))) { tdir = OBSVAL(seg->x2, seg->y2 + 1, layer); if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (stub + LefGetRouteKeepout(layer) >= PitchY) { dc = Ylowerbound + (double)(seg->y2 + 1) * PitchY; y2 = (int)((REPS(dc)) * oscale); } } } else if ((y > y2) && (seg->y2 > 0)) { tdir = OBSVAL(seg->x2, seg->y2 - 1, layer); if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (-stub + LefGetRouteKeepout(layer) >= PitchY) { dc = Ylowerbound + (double)(seg->y2 - 1) * PitchY; y2 = (int)((REPS(dc)) * oscale); } } } dc = oscale * 0.5 * LefGetRouteWidth(layer); if (special == (u_char)0) { // Regular nets include 1/2 route width at // the ends, so subtract from the stub terminus if (y < y2) { y2 -= dc; if (y >= y2) cancel = TRUE; } else { y2 += dc; if (y <= y2) cancel = TRUE; } } else { // Special nets don't include 1/2 route width // at the ends, so add to the route at the grid if (y < y2) y -= dc; else y += dc; // Routes that extend for more than one track // without a bend do not need a wide stub if (seg->y1 != seg->y2) cancel = TRUE; } } if (cancel == FALSE) { net->flags |= NET_STUB; rt->flags |= RT_STUB; if (Pathon != 1) { pathstart(Cmd, layer, x, y, special, oscale, invscale, horizontal, lnode); lastx = x; lasty = y; } pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale, 0); lastx = x2; lasty = y2; } } } if (Pathon != -1) Pathon = 0; } // if (rt->segments && !(rt->flags & RT_OUTPUT)) } } /*--------------------------------------------------------------*/ /* emit_routes - DEF file output from the list of routes */ /* */ /* Reads the .def file and rewrites file */ /* _route.def, where each net definition has the */ /* physical route appended. */ /* */ /* ARGS: filename to list to */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Mon Aug 11 2003 */ /*--------------------------------------------------------------*/ static void emit_routes(char *filename, double oscale, int iscale) { FILE *Cmd; int i, j, numnets, numvias, stubroutes; char line[MAX_LINE_LEN + 1], *lptr = NULL; char netname[MAX_NAME_LEN]; NET net = NULL; NODE node; ROUTE rt; FILE *fdef; u_char errcond = FALSE; u_char need_cleanup = FALSE; u_char purge_routed = FALSE; u_char skip_net = FALSE; fdef = fopen(DEFfilename, "r"); if ((fdef == NULL) && (DEFfilename != NULL)) { if (strchr(DEFfilename, '.') == NULL) { char *extfilename = malloc(strlen(DEFfilename) + 5); sprintf(extfilename, "%s.def", DEFfilename); fdef = fopen(extfilename, "r"); free(extfilename); } } if (fdef == NULL) { Fprintf(stderr, "emit_routes(): Cannot open DEF file for reading.\n"); return; } if (!strcmp(filename, "stdout")) { Cmd = stdout; } else { char *dotptr; if (filename == DEFfilename) { char *newDEFfile = (char *)malloc(strlen(filename) + 11); strcpy(newDEFfile, filename); dotptr = strrchr(newDEFfile, '.'); if (dotptr) strcpy(dotptr, "_route.def"); else strcat(newDEFfile, "_route.def"); Cmd = fopen(newDEFfile, "w"); free(newDEFfile); } else { dotptr = strrchr(filename, '.'); if (dotptr) Cmd = fopen(filename, "w"); else { char *newDEFfile = (char *)malloc(strlen(filename) + 11); strcpy(newDEFfile, filename); strcat(newDEFfile, ".def"); Cmd = fopen(newDEFfile, "w"); free(newDEFfile); } } } if (!Cmd) { Fprintf(stderr, "emit_routes(): Couldn't open output (routed) DEF file.\n"); return; } // Copy DEF file up to NETS line numnets = 0; numvias = 0; while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { lptr = line; while (isspace(*lptr)) lptr++; if (!strncmp(lptr, "NETS", 4)) { sscanf(lptr + 4, "%d", &numnets); break; } if (!strncmp(lptr, "VIAS", 4)) { sscanf(lptr + 4, "%d", &numvias); LefWriteGeneratedVias(Cmd, (double)(oscale / (double)iscale), numvias); continue; /* VIAS line already written; do not output. */ } if (!strncmp(lptr, "PINS", 4) && (numvias == 0)) { /* Check if there are any generated vias, and write them */ /* prior to the PINS section. */ LefWriteGeneratedVias(Cmd, (double)(oscale / (double)iscale), 0); } fputs(line, Cmd); } fputs(line, Cmd); // Write the NETS line if ((numnets + numSpecial) != Numnets) { Flush(stdout); Fprintf(stderr, "emit_routes(): DEF file has %d nets and %d specialnets.\n", numnets, numSpecial); Fprintf(stderr, "but qrouter wants to write %d nets and specialnets.\n", Numnets); } for (i = 0; i < numnets; i++) { char *instname, *pinname; if (errcond == TRUE) break; net = NULL; while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { if ((lptr = strchr(line, ';')) != NULL) { *lptr = '\n'; *(lptr + 1) = '\0'; #ifdef TCL_QROUTER net = DefFindNet(netname); while ((instname = get_annotate_info(net, &pinname)) != NULL) { /* Output antenna connections that were added to the net */ fprintf(Cmd, " ( %s %s )\n", instname, pinname); } #endif break; } else { lptr = line; while (isspace(*lptr)) lptr++; if (*lptr == '-') { lptr++; while (isspace(*lptr)) lptr++; sscanf(lptr, "%s", netname); fputs(line, Cmd); } else if (*lptr == '+') { #ifdef TCL_QROUTER net = DefFindNet(netname); while ((instname = get_annotate_info(net, &pinname)) != NULL) { /* Output antenna connections that were added to the net */ fprintf(Cmd, " ( %s %s )\n", instname, pinname); } #endif lptr++; while (isspace(*lptr)) lptr++; if (!strncmp(lptr, "ROUTED", 6)) { // This net is being handled by qrouter, so remove // the original routing information while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { if ((lptr = strchr(line, ';')) != NULL) { // *lptr = '\n'; // *(lptr + 1) = '\0'; *line = '\0'; break; } } break; } else fputs(line, Cmd); } else if (!strncmp(lptr, "END", 3)) { // This should not happen fputs(line, Cmd); errcond = TRUE; break; } else fputs(line, Cmd); } } /* Find this net (if not done already) */ if (!net) net = DefFindNet(netname); if (!net || (net->flags & NET_IGNORED)) { if (!net) Fprintf(stderr, "emit_routes(): Net %s cannot be found.\n", netname); /* Dump rest of net and continue */ *(lptr) = ';'; *(lptr + 1) = '\n'; *(lptr + 2) = '\0'; fputs(line, Cmd); continue; } else { /* Add last net terminal, without the semicolon */ fputs(line, Cmd); emit_routed_net(Cmd, net, (u_char)0, oscale, iscale); fprintf(Cmd, ";\n"); } } // Finish copying the rest of the NETS section if (errcond == FALSE) { while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { lptr = line; while (isspace(*lptr)) lptr++; fputs(line, Cmd); if (!strncmp(lptr, "END", 3)) { break; } } } // Determine how many stub routes we will write to SPECIALNETS // Also reset the OUTPUT flag for each route needing a stubroute // to be written. stubroutes = 0; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->flags & NET_IGNORED) continue; if (net->flags & NET_STUB) { stubroutes++; for (rt = net->routes; rt; rt = rt->next) if (rt->flags & RT_STUB) rt->flags &= ~RT_OUTPUT; } } // If there were stub routes, repeat them in SPECIALNETS at the // proper width. if (stubroutes > 0) { fprintf(Cmd, "\nSPECIALNETS %d ", stubroutes + numSpecial); for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->flags & NET_IGNORED) continue; emit_routed_net(Cmd, net, (u_char)1, oscale, iscale); } if (numSpecial == 0) fprintf(Cmd, ";\nEND SPECIALNETS\n"); else fprintf(Cmd, ";\n"); } // Finish copying the rest of the file. Ignore ROUTED specialnets if // the nets are known nets and not power or ground nets. FIXED or // COVER nets are output verbatim. while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { lptr = line; while (isspace(*lptr)) lptr++; if (!strncmp(lptr, "SPECIALNETS", 11)) { if (stubroutes > 0) { purge_routed = TRUE; continue; /* SPECIALNETS line already written; do not output. */ } } if (!purge_routed) fputs(line, Cmd); else { lptr = line; while (isspace(*lptr)) lptr++; if (*lptr == '-') { lptr++; while (isspace(*lptr)) lptr++; sscanf(lptr, "%s", netname); // Find this net net = DefFindNet(netname); if (!net || (net->flags & NET_IGNORED)) skip_net = FALSE; else if (net->netnum == VDD_NET || net->netnum == GND_NET) skip_net = FALSE; else skip_net = TRUE; } if (!skip_net) fputs(line, Cmd); else if ((lptr = strchr(line, ';')) != NULL) { skip_net = FALSE; } } } fclose(fdef); fclose(Cmd); } /* emit_routes() */ /* end of output.c */ qrouter-1.4.88/qrouternullg.c0000644000175000017510000000275513625043307015567 0ustar nileshnilesh/*----------------------------------------------------------------------*/ /* qrouternullg.c */ /*----------------------------------------------------------------------*/ #include #include /*----------------------------------------------------------------------*/ /* Application initiation. This is exactly like the AppInit routine */ /* for "tclsh", minus the cruft, but with "tcl_rcFileName" set to */ /* "qrouter.tcl" instead of "~/.tclshrc". */ /*----------------------------------------------------------------------*/ int qrouter_AppInit(interp) Tcl_Interp *interp; { if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Tcl", Tcl_Init, Tcl_Init); /* This is where we replace the home ".wishrc" file with */ /* qrouter's startup script. */ Tcl_SetVar(interp, "tcl_rcFileName", QROUTER_PATH "/qrouter.tcl", TCL_GLOBAL_ONLY); /* Additional variable can be used to tell if qrouter is in non- */ /* graphics mode. */ Tcl_SetVar(interp, "no_graphics_mode", "true", TCL_GLOBAL_ONLY); return TCL_OK; } /*----------------------------------------------------------------------*/ /* The main procedure; replacement for "tclsh". */ /*----------------------------------------------------------------------*/ int main(argc, argv) int argc; char **argv; { Tcl_Main(argc, argv, qrouter_AppInit); return 0; } /*----------------------------------------------------------------------*/ qrouter-1.4.88/output.h0000644000175000017510000000140513625043307014360 0ustar nileshnilesh/* * output.h -- * * This file includes the DEF file output functions * */ #ifndef _OUTPUTINT_H #define _OUTPUTINT_H extern int Pathon; /* Function prototypes */ static void emit_routes(char *filename, double oscale, int iscale); void cleanup_net(NET net); int write_def(char *filename); int write_failed(char *filename); char *print_node_name(NODE node); void print_nets(char *filename); void print_routes(char *filename); void print_nlgates(char *filename); void print_net(NET net); void print_gate(GATE gate); /* Additional diagnostic routines */ void print_grid_information(int, int, int); void print_instance_information(char *); void print_node_information(char *); void print_net_information(char *); #endif /* _OUTPUTINT_H */ qrouter-1.4.88/Makefile.in0000644000175000017510000001067513625043307014725 0ustar nileshnilesh# # qrouter Makefile # # Main compiler arguments CFLAGS += @CFLAGS@ CPPFLAGS = @CPPFLAGS@ DEFS = @DEFS@ STUB_DEFS = @stub_defs@ LIBS = @LIBS@ LDFLAGS += @LDFLAGS@ LDDL_FLAGS = @LDDL_FLAGS@ LD_RUN_PATH = @LD_RUN_PATH@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ LIB_SPECS_NOSTUB = @LIB_SPECS_NOSTUB@ LIB_SPECS = @LIB_SPECS@ INC_SPECS = @INC_SPECS@ TCL_LIB_DIR = @TCL_LIB_DIR@ TK_LIB_DIR = @TK_LIB_DIR@ EXTRA_LIB_SPECS = @EXTRA_LIB_SPECS@ INSTALL = @INSTALL@ SHDLIB_EXT = @SHDLIB_EXT@ EXEEXT = @EXEEXT@ X_LIBS = @X_LIBS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ QROUTER_LIB_DIR = @QROUTER_LIB_DIR@ WISH_EXE = @WISH_EXE@ VERSION = @VERSION@ REVISION = @REVISION@ prefix = @prefix@ exec_prefix = @exec_prefix@ INSTALL_TARGET := @INSTALL_TARGET@ ALL_TARGET := @ALL_TARGET@ SOURCES = qrouter.c point.c maze.c mask.c node.c output.c qconfig.c lef.c def.c OBJECTS := $(patsubst %.c,%.o,$(SOURCES)) SOURCES2 = graphics.c tclqrouter.c tkSimple.c delays.c antenna.c OBJECTS2 := $(patsubst %.c,%.o,$(SOURCES2)) SOURCES3 = qrouterexec.c OBJECTS3 := $(patsubst %.c,%.o,$(SOURCES3)) SOURCES4 = qrouternullg.c OBJECTS4 := $(patsubst %.c,%.o,$(SOURCES4)) SOURCES5 = main.c OBJECTS5 := $(patsubst %.c,%.o,$(SOURCES5)) BININSTALL = ${prefix}/bin LIBINSTALL = ${prefix}/${QROUTER_LIB_DIR} EXTRA_DEFS = -DQROUTER_PATH=\"${LIBINSTALL}\" INSTALL_BININSTALL = @DIST_DIR@/bin INSTALL_LIBINSTALL = @DIST_DIR@/${QROUTER_LIB_DIR} all: $(ALL_TARGET) install: $(INSTALL_TARGET) nointerp: qrouter$(EXEEXT) tcl: qrouter.sh qrouter.tcl qrouter$(SHDLIB_EXT) qrouterexec$(EXEEXT) \ qrouternullg$(EXEEXT) qrouter.tcl: qrouter.tcl.in sed -e '/LIBDIR/s#LIBDIR#${LIBINSTALL}#' \ -e '/VERSION/s#VERSION#${VERSION}#' \ -e '/REVISION/s#REVISION#${REVISION}#' \ qrouter.tcl.in > $@ qrouter.sh: qrouter.sh.in sed -e '/WISH_EXE/s#WISH_EXE#${WISH_EXE}#' \ -e '/LIBDIR/s#LIBDIR#${LIBINSTALL}#' \ qrouter.sh.in > $@ chmod 0755 $@ qrouter$(EXEEXT): $(OBJECTS) $(OBJECTS5) $(CC) $(LDFLAGS) $(OBJECTS) $(OBJECTS5) -o $@ $(LIBS) -lm qrouter$(SHDLIB_EXT): $(OBJECTS) $(OBJECTS2) $(RM) qrouter$(SHDLIB_EXT) $(CC) ${CFLAGS} ${STUB_DEFS} ${SHLIB_CFLAGS} -o $@ \ ${LDDL_FLAGS} $(OBJECTS) $(OBJECTS2) \ ${LDFLAGS} -lc ${LIBS} ${X_PRE_LIBS} -lX11 ${X_LIBS} \ ${X_EXTRA_LIBS} ${LIB_SPECS} ${EXTRA_LIB_SPECS} -lm qrouterexec$(EXEEXT): $(OBJECTS3) $(RM) qrouterexec$(EXEEXT) $(CC) ${CFLAGS} ${CPPFLAGS} ${DEFS} ${EXTRA_DEFS} \ ${SOURCES3} ${INC_SPECS} -o $@ ${LIB_SPECS_NOSTUB} \ ${LD_RUN_PATH} ${LDFLAGS} ${X_PRE_LIBS} -lX11 ${X_LIBS} \ ${X_EXTRA_LIBS} ${LIBS} ${EXTRA_LIB_SPECS} -lm qrouternullg$(EXEEXT): $(OBJECTS4) $(RM) qrouternullg$(EXEEXT) $(CC) ${CFLAGS} ${CPPFLAGS} ${DEFS} ${EXTRA_DEFS} \ ${SOURCES4} ${INC_SPECS} -o $@ ${LIB_SPECS_NOSTUB} \ ${LD_RUN_PATH} ${LDFLAGS} ${LIBS} ${EXTRA_LIB_SPECS} -lm install-nointerp: @echo "Installing qrouter" $(INSTALL) -d $(DESTDIR)${INSTALL_BININSTALL} $(INSTALL) qrouter $(DESTDIR)${INSTALL_BININSTALL} install-tcl: qrouter.sh qrouter.tcl qrouter$(SHDLIB_EXT) \ qrouterexec$(EXEEXT) qrouternullg$(EXEEXT) @echo "Installing qrouter" $(INSTALL) -d $(DESTDIR)${INSTALL_BININSTALL} $(INSTALL) -d $(DESTDIR)${INSTALL_LIBINSTALL} $(INSTALL) qrouter.sh $(DESTDIR)${INSTALL_BININSTALL}/qrouter $(INSTALL) qrouter$(SHDLIB_EXT) $(DESTDIR)${INSTALL_LIBINSTALL} $(INSTALL) qrouterexec$(EXEEXT) $(DESTDIR)${INSTALL_LIBINSTALL} $(INSTALL) qrouternullg$(EXEEXT) $(DESTDIR)${INSTALL_LIBINSTALL} $(INSTALL) console.tcl $(DESTDIR)${INSTALL_LIBINSTALL} $(INSTALL) tkcon.tcl $(DESTDIR)${INSTALL_LIBINSTALL} $(INSTALL) qrouter.tcl $(DESTDIR)${INSTALL_LIBINSTALL} uninstall: $(RM) $(DESTDIR)${INSTALL_BININSTALL}/qrouter clean: $(RM) $(OBJECTS) $(RM) $(OBJECTS2) $(RM) $(OBJECTS3) $(RM) $(OBJECTS4) $(RM) $(OBJECTS5) $(RM) qrouterexec$(EXEEXT) $(RM) qrouternullg$(EXEEXT) $(RM) qrouter$(EXEEXT) $(RM) qrouter$(SHDLIB_EXT) $(RM) qrouter.tcl $(RM) qrouter.sh veryclean: $(RM) $(OBJECTS) $(RM) $(OBJECTS2) $(RM) $(OBJECTS3) $(RM) $(OBJECTS4) $(RM) $(OBJECTS5) $(RM) qrouterexec$(EXEEXT) $(RM) qrouternullg$(EXEEXT) $(RM) qrouter$(EXEEXT) $(RM) qrouter$(SHDLIB_EXT) $(RM) qrouter.tcl $(RM) qrouter.sh distclean: $(RM) $(OBJECTS) $(RM) $(OBJECTS2) $(RM) $(OBJECTS3) $(RM) $(OBJECTS4) $(RM) $(OBJECTS5) $(RM) qrouterexec$(EXEEXT) $(RM) qrouternullg$(EXEEXT) $(RM) qrouter$(EXEEXT) $(RM) qrouter$(SHDLIB_EXT) $(RM) qrouter.tcl $(RM) qrouter.sh .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) $(SHLIB_CFLAGS) $(DEFS) $(STUB_DEFS) \ $(EXTRA_DEFS) $(INC_SPECS) -c $< -o $@ qrouter-1.4.88/symbol.map0000644000175000017510000000006713625043307014656 0ustar nileshnileshQROUTER_1.2 { global: Qrouter_Init; local: *; }; qrouter-1.4.88/def.h0000644000175000017510000000071313625043307013557 0ustar nileshnilesh/* * def.h -- * * This file includes the DEF I/O functions * */ #ifndef _DEFINT_H #define _DEFINT_H /* Retain information from TRACKS entries in a DEF file */ typedef struct tracks_ { double start; int ntracks; double pitch; } *TRACKS; extern int numSpecial; extern int DefRead(char *inName, float *); extern TRACKS DefGetTracks(int layer); extern GATE DefFindGate(char *name); extern NET DefFindNet(char *name); #endif /* _DEFINT_H */ qrouter-1.4.88/configure.in0000644000175000017510000006253313625043307015171 0ustar nileshnilesh#!/bin/sh AC_INIT(VERSION,, eda-dev@opencircuitdesign.com) AC_PREREQ(2.60) AC_CONFIG_SRCDIR([Makefile.in]) # Determine the host and build type. # =========================================================================== AC_CANONICAL_HOST AC_CANONICAL_TARGET PACKAGE=qrouter VERSION=`cat ./VERSION | cut -d. -f1-2` REVISION=`cat ./VERSION | cut -d. -f3` AC_SUBST(VERSION) AC_SUBST(REVISION) AC_ARG_PROGRAM # Required programs # =========================================================================== AC_PROG_CC AC_PROG_CPP AC_ISC_POSIX if test "x$U" != "x"; then AC_MSG_ERROR(Compiler not ANSI compliant) fi AC_PROG_INSTALL AC_PROG_RANLIB AC_CHECK_PROG(AUTOCONF, autoconf, autoconf, :) AC_CHECK_PROG(CP, cp, cp, :) AC_CHECK_PROG(RM, rm, rm, :) AC_LANG_C AC_HEADER_STDC AC_CHECK_FUNCS(setenv putenv) # Linker # ========================================= #------------------------------------------------------------ # AC_PROG_LD - find the path to the GNU or non-GNU linker # (This stuff ripped from libtool) #------------------------------------------------------------ AC_DEFUN([AC_PROG_LD], [AC_ARG_WITH(gnu-ld, [ --with-gnu-ld assume the C compiler uses GNU ld [[default=no]]], test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl dnl ###not for PostgreSQL### AC_REQUIRE([AC_CANONICAL_BUILD])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case "$ac_prog" in # Accept absolute paths. changequote(,)dnl [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' changequote([,])dnl # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(ac_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ac_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then test "$with_gnu_ld" != no && break else test "$with_gnu_ld" != yes && break fi fi done IFS="$ac_save_ifs" else ac_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$ac_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_PROG_LD_GNU ]) AC_DEFUN([AC_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. if $LD -v 2>&1 &5; then ac_cv_prog_gnu_ld=yes else ac_cv_prog_gnu_ld=no fi]) with_gnu_ld=$ac_cv_prog_gnu_ld ]) AC_PROG_LD dnl Check for va_copy AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy, AC_TRY_LINK( [#include ], [va_list ap1, ap2; va_copy(ap1,ap2); ], [ac_cv_c_va_copy="yes"], [ac_cv_c_va_copy="no"]) ) if test "$ac_cv_c_va_copy" = "yes" then AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy]) fi AC_CACHE_CHECK([for __va_copy], ac_cv_c___va_copy, AC_TRY_LINK( [#include ], [va_list ap1, ap2; __va_copy(ap1,ap2); ], [ac_cv_c___va_copy="yes"], [ac_cv_c___va_copy="no"]) ) if test "$ac_cv_c___va_copy" = "yes" then AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy]) fi # Options # ========================================= QROUTER_LIB_DIR="share/qrouter" AC_ARG_WITH(libdir, [ --with-libdir=DIR path to qrouter default config files], [ QROUTER_LIB_DIR=$withval ], []) # Force warnings to stop compilation. Use # this only for development cleanup. # ========================================= # if test "$GCC" = "yes" ; then # CFLAGS="${CFLAGS} -Wall -Werror" # fi # Interpreter Options # ========================================= qrouter_with_tcl="yes" qrouter_with_tk="yes" qrouter_with_tcl_includes="" qrouter_with_tk_includes="" qrouter_with_tcl_libraries="" qrouter_with_tk_libraries="" usingTcl=1 stub_defs="" # For distributed installs, where the run-time files are installed in a # place that is a temporary staging area, like DESTDIR, but unlike DESTDIR, # the prefix is replaced by the destination directory, rather than appended # to it. DIST_DIR="\${exec_prefix}" AC_ARG_WITH(distdir, [ --with-distdir=DIR install into location DIR for distribution], [ if test "$withval" = "no" -o "$withval" = "NO" ; then DIST_DIR="\${exec_prefix}" else DIST_DIR=${withval} fi ], ) AC_ARG_WITH(tcl, [ --with-tcl=DIR Find tclConfig.sh in DIR], [ qrouter_with_tcl=$withval if test "$withval" = "no" -o "$withval" = "NO"; then usingTcl= fi ], ) #----------------------------------------------------- # SHDLIB_EXT needs to be defined outside of the # Tcl/Tk environment, otherwise the Makefile # target can't differentiate between qrouter and # qrouter.so #----------------------------------------------------- case $target in *-hpux*) SHDLIB_EXT=".sl" SHDLIB_EXT_ALT=".sl" ;; *cygwin*) SHDLIB_EXT=".dll" SHDLIB_EXT_ALT=".dll.a" ;; *darwin*) SHDLIB_EXT=".dylib" SHDLIB_EXT_ALT=".dylib" ;; *) SHDLIB_EXT=".so" SHDLIB_EXT_ALT=".so" ;; esac dnl ---------------------------------------------------------------- dnl Do our best to find Tcl/Tk. If we can't, then flag a warning dnl and don't set the usingTcl variable. dnl dnl This has been broken up into a number of sections, each of which dnl depends independently on the setting of usingTcl. dnl ---------------------------------------------------------------- AC_ARG_WITH(tk, [ --with-tk=DIR Find tkConfig.sh in DIR], qrouter_with_tk=$withval) AC_ARG_WITH(tclincls, [ --with-tclincls=DIR Find tcl.h in DIR], qrouter_with_tcl_includes=$withval) AC_ARG_WITH(tkincls, [ --with-tkincls=DIR Find tk.h in DIR], qrouter_with_tk_includes=$withval) AC_ARG_WITH(tcllibs, [ --with-tcllibs=DIR Find Tcl library in DIR], qrouter_with_tcl_libraries=$withval) AC_ARG_WITH(tklibs, [ --with-tklibs=DIR Find Tk library in DIR], qrouter_with_tk_libraries=$withval) # ----------------------------------------------------------------------- # Find the Tcl build configuration file "tclConfig.sh" # ----------------------------------------------------------------------- if test $usingTcl ; then TCL_INC_DIR="." TK_INC_DIR="." AC_MSG_CHECKING([for tclConfig.sh]) tcl_config_sh="" if test "$qrouter_with_tcl" = "no" ; then qrouter_with_tcl="" elif test "$qrouter_with_tcl" != "yes" ; then # # Verify that a tclConfig.sh file exists in the directory specified # by --with-tcl. # for dir in \ $qrouter_with_tcl do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/unix/tclConfig.sh" ; then tcl_config_sh="$dir/unix/tclConfig.sh" break fi done else # # Otherwise, search for Tcl configuration file. # # 1. Search previously named locations. for dir in \ $ac_default_prefix \ $exec_prefix do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/unix/tclConfig.sh" ; then tcl_config_sh="$dir/unix/tclConfig.sh" break fi done # 2. Search standard locations. if test "x$tcl_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ /usr/local/tcl \ /usr/local/lib \ /usr/local \ `ls -dr /usr/lib/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ `ls -dr /usr/share/tcltk/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ /sw/lib \ /usr/lib \ /usr/lib64 \ /usr do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break fi done fi fi AC_MSG_RESULT([${tcl_config_sh}]) if test "x$tcl_config_sh" = "x" ; then echo "Can't find Tcl configuration script \"tclConfig.sh\"" echo "Reverting to non-Tcl compilation" usingTcl= fi fi # ----------------------------------------------------------------------- # Find the Tk build configuration file "tkConfig.sh" # ----------------------------------------------------------------------- if test $usingTcl ; then AC_MSG_CHECKING([for tkConfig.sh]) tk_config_sh="" if test "$qrouter_with_tk" != "yes"; then # # Verify that a tkConfig.sh file exists in the directory specified # by --with-tcl or --with-tk. # for dir in \ $qrouter_with_tk \ $qrouter_with_tcl do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/unix/tkConfig.sh" ; then tk_config_sh="$dir/unix/tkConfig.sh" break fi done else # # Search for Tk configuration file. # # # 1. Search previously named locations. # for dir in \ $ac_default_prefix \ $exec_prefix do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/unix/tkConfig.sh" ; then tk_config_sh="$dir/unix/tkConfig.sh" break fi done # # 2. Search standard locations. # if test "x$tk_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ `ls -dr /usr/local/tk/tk[[7-9]].[[0-9]]* 2>/dev/null` \ /usr/local/tcl \ /usr/local/lib \ /sw/lib \ /usr/local \ `ls -dr /usr/share/tcltk/tk[[7-9]].[[0-9]]* 2>/dev/null` \ `ls -dr /usr/lib/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ `ls -dr /usr/lib/tk[[7-9]].[[0-9]]* 2>/dev/null` \ ${x_libraries} \ /usr/lib \ /usr/lib64 \ /usr do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break fi done fi fi AC_MSG_RESULT([${tk_config_sh}]) if test "x$tk_config_sh" = "x" ; then echo "can't find Tk configuration script \"tkConfig.sh\"" echo "Reverting to non-Tcl compilation" usingTcl= fi fi # ----------------------------------------------------------------------- # Source in the Tcl/Tk configuration scripts. # ----------------------------------------------------------------------- if test $usingTcl ; then . $tcl_config_sh . $tk_config_sh # Should probably trust the config file contents, but this configure # file checks the Tcl and Tk include and lib directories. Since # the config file doesn't separate out the libraries from the strings # passed to the compiler/linker, do it manually here. # # Extract TCL_LIB_DIR from TCL_LIB_SPEC # Extract TK_LIB_DIR from TK_LIB_SPEC # Extract TCL_INC_DIR from TCL_INCLUDE_SPEC # Extract TK_INC_DIR from TK_INCLUDE_SPEC # # These will be the defaults unless overridden by configure command line tmpstr=${TCL_LIB_SPEC#*-L} TCL_LIB_DIR=${tmpstr% -l*} tmpstr=${TK_LIB_SPEC#*-L} TK_LIB_DIR=${tmpstr% -l*} TCL_INC_DIR=${TCL_INCLUDE_SPEC#*-I} TK_INC_DIR=${TK_INCLUDE_SPEC#*-I} if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then : elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then : elif test "$TCL_VERSION" = "$TK_VERSION" ; then : else echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" echo "Reverting to non-Tcl compile" usingTcl= fi fi if test $usingTcl ; then if test "x${qrouter_with_tcl_includes}" != "x" ; then if test -r "${qrouter_with_tcl_includes}/tcl.h" ; then TCL_INC_DIR=${qrouter_with_tcl_includes} else echo "Can't find tcl.h in \"${qrouter_with_tcl_includes}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for dir in \ ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ ${TCL_PREFIX}/include \ ${TCL_SRC_DIR}/generic \ ${TCL_INC_DIR} do if test -r "$dir/tcl.h" ; then TCL_INC_DIR=$dir break fi done if test "x${TCL_INC_DIR}" = "x" ; then echo "Can't find tcl.h header file" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then if test "x${qrouter_with_tk_includes}" != "x" ; then if test -r "${qrouter_with_tk_includes}/tk.h" ; then TK_INC_DIR=${qrouter_with_tk_includes} else echo "Can't find tk.h in \"${qrouter_with_tk_includes}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for dir in \ ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ ${TK_PREFIX}/include \ ${TK_SRC_DIR}/generic \ ${TK_INC_DIR} \ ${TCL_INC_DIR} do if test -r "$dir/tk.h" ; then TK_INC_DIR=$dir break fi done if test "x${TK_INC_DIR}" = "x" ; then echo "Can't find tk.h header file" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then case $target in *-sunos4*|*-*-netbsd|NetBSD-*|FreeBSD-*|OpenBSD-*) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" ;; *) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" ;; esac loclib=`echo ${TCL_LIB_SPEC} | sed -e 's/.*-L//' -e 's/ .*//'` if test "x${TCL_LIB_SPEC}" = "x" ; then TCL_LIB_SPEC="-l${TCL_LIB_NAME}" fi if test "x${TK_LIB_SPEC}" = "x" ; then TK_LIB_SPEC="-l${TK_LIB_NAME}" fi # Find the version of "wish" that corresponds to TCL_EXEC_PREFIX # We really ought to run "ldd" to confirm that the linked libraries match. AC_MSG_CHECKING([for wish executable]) for dir in \ ${TK_EXEC_PREFIX}/bin \ ${TK_EXEC_PREFIX} do for wishexe in \ wish \ wish${TK_VERSION} \ wish.exe \ wish${TK_VERSION}.exe do if test -r "$dir/$wishexe" ; then WISH_EXE=$dir/$wishexe break fi done if test "x${WISH_EXE}" != "x" ; then break fi done if test "x${WISH_EXE}" = "x" ; then echo "Warning: Can't find executable for \"wish\". You may have to" echo "manually set the value for WISH_EXE in the netgen startup script." AC_MSG_RESULT(no) else AC_MSG_RESULT([${WISH_EXE}]) fi if test "x${qrouter_with_tcl_libraries}" != "x" ; then for libname in \ "${qrouter_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ "${qrouter_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" do if test -r "$libname" ; then TCL_LIB_DIR="${qrouter_with_tcl_libraries}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library in \"${qrouter_with_tcl_libraries}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for libpfix in "lib64" "lib" do libname1="${TCL_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" libname2="${TCL_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" if test -r "$libname1" -o -r "$libname2" ; then TCL_LIB_DIR="${TCL_EXEC_PREFIX}/${libpfix}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then if test "x${qrouter_with_tk_libraries}" != "x" ; then for libname in \ "${qrouter_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ "${qrouter_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" do if test -r "$libname" ; then TK_LIB_DIR="${qrouter_with_tk_libraries}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library in \"${qrouter_with_tk_libraries}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for libpfix in "lib64" "lib" do libname1="${TK_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TK_LIB_NAME}${SHDLIB_EXT}" libname2="${TK_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" if test -r "$libname1" -o -r "$libname2" ; then TK_LIB_DIR="${TK_EXEC_PREFIX}/${libpfix}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi dnl ---------------------------------------------------- dnl End of Tcl/Tk search dnl ---------------------------------------------------- AC_ARG_ENABLE(memdebug, [ --enable-memdebug enable memory debugging], [ if test "x$qrouter_with_tcl" = "x" ; then LIBS="${LIBS} -lefence" else AC_DEFINE(TCL_MEM_DEBUG) fi ],) dnl Check for X enabled/disabled AC_PATH_XTRA if test "x$no_x" = "x"; then usingX11=1 else echo Cannot find X11---will compile anyway. echo Graphics will be disabled if test $usingTcl ; then echo "Cannot compile TCL version without X11, disabling." usingTcl= fi fi AC_CHECK_LIB(Xt, XtToolkitInitialize,,[ AC_CHECK_LIB(Xt, XtDisplayInitialize,,,-lSM -lICE -lXpm -lX11)]) AC_CHECK_HEADERS(sys/mman.h) dnl ---------------------------------------------------------------- dnl Once we're sure what, if any, interpreter is being compiled, dnl set all the appropriate definitions. For Tcl/Tk, override dnl the default install targets: allows compiling tcl version with dnl "make" instead of requiring "make tcl" dnl ---------------------------------------------------------------- if test $usingTcl ; then ALL_TARGET="tcl" INSTALL_TARGET="install-tcl" AC_DEFINE(TCL_QROUTER) stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS" else ALL_TARGET="nointerp" INSTALL_TARGET="install-nointerp" programs="$programs qrouter" fi dnl ---------------------------------------------------------------- dnl Define system-specific settings dnl ---------------------------------------------------------------- case $target in *-linux*) AC_DEFINE(LINUX) AC_DEFINE(SYSV) dnl 64-bit support case $target in *x86_64*) CPPFLAGS="$CPPFLAGS -m64 -fPIC" ;; esac ;; *solaris*) AC_DEFINE(SYSV) ;; *irix*) AC_DEFINE(SYSV) AC_DEFINE(IRIX) AC_DEFINE(_BSD_SIGNALS) ;; *sysv*) AC_DEFINE(SYSV) ;; *cygwin*) AC_DEFINE(CYGWIN) AC_DEFINE(i386) ;; *darwin*) if test "$CPP" = "cc -E" ; then CPPFLAGS="$CPPFLAGS -no-cpp-precomp" fi ;; esac # ----------------------------------------------------------------------- # Tcl/Tk configuration # ----------------------------------------------------------------------- if test $usingTcl ; then LIB_SPECS_NOSTUB="${LIB_SPECS}" # ----------------------------------------------------------------------- # # Tk libraries and header files # # ----------------------------------------------------------------------- if test "${TK_INC_DIR}" != "/usr/include" ; then INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" fi if test "${TK_LIB_DIR}" = "/usr/lib" -o \ "${TK_LIB_DIR}" = "/usr/lib64" ; then LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} ${TK_LIB_SPEC}" LIB_SPECS="${LIB_SPECS} ${TK_STUB_LIB_SPEC}" else LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_STUB_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TK_LIB_DIR}" else loader_run_path="${TK_LIB_DIR}:${loader_run_path}" fi fi # ----------------------------------------------------------------------- # # Tcl libraries and header files # # Add a header file directory specification only if the Tcl headers reside # in a different directory from Tk's. # ## ----------------------------------------------------------------------- if test "${TCL_INC_DIR}" != "/usr/include" -a \ "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" fi if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ "${TCL_LIB_DIR}" = "/usr/lib64" -o \ "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} ${TCL_LIB_SPEC}" LIB_SPECS="${LIB_SPECS} ${TCL_STUB_LIB_SPEC}" else LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_STUB_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TCL_LIB_DIR}" else loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" fi fi #-------------------------------------------------------------------- # # Check if we can generate shared libraries on this system. Set flags # to generate shared libraries for systems that we know about. Start # with the values found in tclConfig.sh, make changes as we know about # the different systems. # #-------------------------------------------------------------------- # Initialize shared library build variables SHLIB_LD="" LDDL_FLAGS="-shared" SHDLIB_EXT=".so" EXTRA_LIB_SPECS="" build_shared="yes" case $target in *-bsdi2*|*-bsdi3*) LD="shlicc" LDDL_FLAGS="-r" EXTRA_LIB_SPECS="-ldl" ;; *darwin*) SHDLIB_EXT=".dylib" LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" LDFLAGS="${LDFLAGS} ${LIB_SPECS}" CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" ;; *cygwin*) SHDLIB_EXT=".dll" AC_DEFINE(USE_DL_IMPORT) LDDL_FLAGS='-shared -Wl,--enable-auto-image-base' if test "x${loader_run_path}" != "x" ; then LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" fi ld_extra_libs=${LIB_SPECS} sub_extra_libs='-L${QROUTERDIR}/qrouter -ltclqrouter' ;; *-bsdi4*) SHLIB_CFLAGS="-export-dynamic -fPIC" LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@' ;; *-linux*) LDDL_FLAGS='-shared -Wl,-soname,$@' if test "x${loader_run_path}" != "x" ; then LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" fi LDFLAGS="" EXTRA_LIB_SPECS="-ldl" ;; *-freebsd*) # Not available on all versions: check for include file. SHLIB_CFLAGS="-fPIC" LDDL_FLAGS="-shared ${LIB_SPECS}" CFLAGS="${CFLAGS} -L/usr/X11R6/include" ;; *-openbsd*) SHLIB_CFLAGS="-fpic" LDDL_FLAGS="-shared ${LIB_SPECS}" CFLAGS="${CFLAGS} -I${X11BASE}/include" ;; *-netbsd*) # Not available on all versions: check for include file. AC_CHECK_HEADER(dlfcn.h, test_ok=yes, test_ok=no) if test "$test_ok" = yes; then SHLIB_CFLAGS="-fpic" LDDL_FLAGS="-Bshareable -x ${LIB_SPEC}" fi ;; esac # If we're running gcc, then set SHLIB_CFLAGS flags for compiling # shared libraries for gcc, instead of those of the vendor's compiler. if test "$GCC" = "yes" ; then case $target in *cygwin*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$with_gnu_ld" = "yes" ; then case $target in *-openbsd*) ;; *) LDDL_FLAGS="${LDDL_FLAGS} -Wl,--version-script=symbol.map" ;; esac fi AC_SUBST(SHDLIB_EXT) AC_SUBST(SHLIB_LD) AC_SUBST(LD) AC_SUBST(LDDL_FLAGS) AC_SUBST(SHLIB_LIB_SPECS) AC_SUBST(stub_defs) AC_SUBST(EXTRA_LIB_SPECS) AC_SUBST(LDFLAGS) AC_SUBST(INC_SPECS) AC_SUBST(LIB_SPECS) AC_SUBST(LIB_SPECS_NOSTUB) AC_SUBST(TCL_LIB_DIR) AC_SUBST(TK_LIB_DIR) AC_SUBST(WISH_EXE) AC_SUBST(X_LIBS) AC_SUBST(X_EXTRA_LIBS) AC_SUBST(X_PRE_LIBS) AC_SUBST(X_CFLAGS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_RUN_PATH) fi dnl Substitute all variables AC_SUBST(CPPFLAGS) AC_SUBST(CFLAGS) AC_SUBST(STDLIBS) AC_SUBST(ALL_TARGET) AC_SUBST(INSTALL_TARGET) AC_SUBST(DIST_DIR) AC_SUBST(QROUTER_LIB_DIR) AC_DEFINE_UNQUOTED(VERSION, "$VERSION") AC_DEFINE_UNQUOTED(REVISION, "$REVISION") AC_OUTPUT(Makefile) qrouter-1.4.88/mask.h0000644000175000017510000000054013625043307013752 0ustar nileshnilesh/* * mask.h -- * * This file includes the route mask functions * */ #ifndef _MASKINT_H #define _MASKINT_H extern u_char *RMask; // mask out best area to route extern void initMask(void); extern void fillMask(u_char value); extern void setBboxCurrent(NET net); extern void create_netorder(u_char method); #endif /* _MASKINT_H */ qrouter-1.4.88/config.sub0000755000175000017510000006700513625043307014642 0ustar nileshnilesh#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. timestamp='2001-08-13' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dsp16xx \ | fr30 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | m32r | m68000 | m68k | m88k | mcore \ | mips16 | mips64 | mips64el | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el | mips64vr4300 \ | mips64vr4300el | mips64vr5000 | mips64vr5000el \ | mipsbe | mipsel | mipsle | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | ns16k | ns32k \ | openrisc \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | s390 | s390x \ | sh | sh[34] | sh[34]eb | shbe | shle \ | sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 \ | we32k \ | x86 | xscale \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alphapca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armv*-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c54x-* \ | clipper-* | cray2-* | cydra-* \ | d10v-* | d30v-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | m32r-* \ | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \ | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipsel-* \ | mipsle-* | mipstx39-* | mipstx39el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | s390-* | s390x-* \ | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \ | sparc-* | sparc64-* | sparc86x-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* \ | t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \ | v850-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xmp-* | xps100-* | xscale-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | ymp) basic_machine=ymp-cray os=-unicos ;; cray2) basic_machine=cray2-cray os=-unicos ;; [cjt]90) basic_machine=${basic_machine}-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mipsel*-linux*) basic_machine=mipsel-unknown os=-linux-gnu ;; mips*-linux*) basic_machine=mips-unknown os=-linux-gnu ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=t3e-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; windows32) basic_machine=i386-pc os=-windows32-msvcrt ;; xmp) basic_machine=xmp-cray os=-unicos ;; xps | xps100) basic_machine=xps100-honeywell ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; mips) if [ x$os = x-linux-gnu ]; then basic_machine=mips-unknown else basic_machine=mips-mips fi ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh3eb | sh4eb) basic_machine=sh-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; c4x*) basic_machine=c4x-none os=-coff ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto*) os=-nto-qnx ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: qrouter-1.4.88/tkSimple.h0000644000175000017510000000035413625043307014612 0ustar nileshnilesh/* * tkSimple.h -- */ #ifndef _TKSIMPLEINT_H #define _TKSIMPLEINT_H #include int Tk_SimpleObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]); #endif /* _TKSIMPLEINT_H */ qrouter-1.4.88/qconfig.c0000644000175000017510000003727413625043307014456 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* 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 #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() */ qrouter-1.4.88/install-sh0000755000175000017510000001273613625043307014664 0ustar nileshnilesh#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 qrouter-1.4.88/qrouter.tcl.in0000644000175000017510000002030214403535743015463 0ustar nileshnilesh#------------------------------------------------------ # Tcl startup script for qrouter #------------------------------------------------------ namespace path {::tcl::mathop ::tcl::mathfunc} set tcllibdir [array get env "QROUTER_LIB_DIR"] if {$tcllibdir == {}} { set QROUTER_LIB_DIR LIBDIR } else { set QROUTER_LIB_DIR [lindex $tcllibdir 1] } unset tcllibdir set libext [info sharedlibextension] if {${tcl_version} >= 8.6} { if {[catch {load ${QROUTER_LIB_DIR}/qrouter$libext}]} { load -lazy ${QROUTER_LIB_DIR}/qrouter$libext } } else { load ${QROUTER_LIB_DIR}/qrouter$libext } package require Qrouter proc pushnamespace { name } { set y [namespace eval ${name} info commands ::${name}::*] set z [info commands] foreach v $y { regsub -all {\*} $v {\\*} i set x [namespace tail $i] if {[lsearch $z $x] < 0} { namespace import $i } else { puts "Warning: ${name} command '$x' use fully-qualified name '$v'" } } } proc popnamespace { name } { set z [info commands] set l [expr [string length ${name}] + 5] while {[set v [lsearch $z ${name}_tcl_*]] >= 0} { set y [lindex $z $v] set w [string range $y $l end] interp alias {} ::$w {} rename ::$y ::$w puts "Info: replacing ::$w with ::$y" } namespace forget ::${name}::* } set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front #--------------------------------------------------------- # Internally-defined procedures (equivalent to commands) #--------------------------------------------------------- #--------------------------------------------------------- # Write the result of the "congested" command out to a # file, with " " per # line of output, one for each instance, ordered. #--------------------------------------------------------- proc qrouter::write_congested {filename} { puts stdout "Writing congestion information into $filename" if {![catch {open $filename w} fcon]} { puts $fcon "Qrouter congestion summary" puts $fcon "--------------------------" set flist [failing summary] set failures [lindex $flist 0] set numnets [lindex $flist 1] puts $fcon "Failures: $failures $numnets" puts $fcon "--------------------------" set clist [congested] foreach cpair $clist { set inst [lindex $cpair 0] set value [lindex $cpair 1] puts $fcon "$inst $value" } close $fcon } else { puts stderr "Error: can't open file $filename for output" } } #------------------------------------------------------ # Standard routing script #------------------------------------------------------ proc qrouter::standard_route {{filename ""} {doquit true} {nocleanup false}} { puts stdout "*** Running stage1 routing with defaults" # Pull root name from filename set rootname [file root $filename] set deffilename ${rootname}.def set rcfilename ${rootname}.rc set result [stage1] if {$result > 0} { set msize 10 while {$msize <= 100} { set lastresult $result puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask $msize, effort 10" set result [stage2 mask $msize effort 10] if {!$result} {break} if {$result > $lastresult} { puts -nonewline stdout "*** Running stage2 routing" set tempmsize [expr $msize + 80] puts stdout " with options mask $tempmsize, effort 20" set result [stage2 mask $tempmsize effort 20] if {!$result} {break} if {$result < 5} { puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask none, effort 50" set result [stage2 mask none effort 50] } if {!$result} {break} } incr msize 10 } } # Attempt a few runs at "mask none" if not solved yet if {$result > 0} { set esize 20 while {$esize <= 100} { puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask none, effort $esize" set result [stage2 mask none effort $esize] if {!$result} {break} incr esize 20 } } # There is no point in running a cleanup stage if there are lots of # unrouted nets. if {$nocleanup == true} { puts stdout "*** Cleanup stage (stage3) bypassed" } elseif {$result < 10} { puts stdout "*** Running stage3 routing with defaults, 1st round" set result [stage3] if {$result > 0} { puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask none" set result [stage2 mask none] } puts stdout "*** Running stage3 routing with defaults, 2nd round" set result [stage3] set i 0 while {$result > 0} { puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask none" set result [stage2 mask none] incr i if {$i == 5} { break } } } cleanup all if {$result == 0} { if {![catch {antenna init}]} { puts stdout "*** Running antenna violation checks" antenna fix } } if {${rootname} != ""} { puts stdout "*** Writing DEF file $deffilename" write_def $deffilename } else { puts stdout "*** Writing DEF file (default)" write_def } if {$result > 0} { write_failed fail.out } if {${rootname} != ""} { puts stdout "*** Writing RC file $rcfilename" write_delays $rcfilename } else { puts stdout "*** Writing RC file (default)" write_delays } if {(!$result) && $doquit} {quit} } #--------------------------------------------------------- # Simple sequence of events (subject to change): # Upon first success, write the DEF file output and quit. # If "stage2 mask none" leaves failing routes, then write # the routes done so far to the DEF file output and remain # in the interpreter. If "stage2 mask none" leaves fewer # than five routes (a very ad hoc number), give it a # second try. #--------------------------------------------------------- proc qrouter::simple_route {} { if {![stage1]} {write_def; quit} if {![stage2]} {write_def; quit} set result [stage2 mask none] if {$result < 5} {set result [stage2 mask none]} write_def if {$result == 0} {quit} } #------------------------------------------------------ # First alternative routing script. Do the quickest # (default) stage1 and stage2 routes. If stage2 # leaves route failures, then write out the list of # instances with congestion information, so that this # information can be fed back to the placement tool # in hopes of producing a routable layout on the next # iteration. Rather than returning to the interpreter # on route failure, it always quits. #------------------------------------------------------ proc qrouter::congestion_route {filename} { if {![stage1]} {write_def; quit} set result [stage2 mask none] if {$result < 5} {set result [stage2 mask none]} if {$result != 0} { qrouter::write_congested $filename } write_def if {$result > 0} { write_failed fail.out } quit } #------------------------------------------------------ pushnamespace qrouter #------------------------------------------------------ # GUI setup #------------------------------------------------------ set appname .qrouter set appframe ${appname}.dframe set drawwindow ${appframe}.drawing if {![catch {toplevel ${appname}}]} { frame ${appframe} pack ${appframe} -side left -expand true -fill both simple ${drawwindow} -width 1000 -height 800 pack ${drawwindow} -expand true -fill both bind ${appframe} redraw bind ${appframe} redraw bind ${appframe} redraw wm withdraw . } proc qrouter::lowerconsole {} { consoledown } puts stdout "Qrouter detail maze router version VERSION.REVISION.T" set autoquit 0 set autoroute 0 set argafter {start} for {set i 0} {$i < $argc} {incr i 1} { set x [lindex $argv $i] switch $x { "-i" - "-h" {set autoquit 1} "-c" {set autoroute 1} } lappend argafter $x } eval $argafter # NOTE: Having a file "route.cfg" in the current directory is # equivalent to specifying "-c ", so autoroute should be set if {$autoroute == 0} { if [file exists route.cfg] { set autoroute 1 } } if {$autoquit} quit if {$autoroute} { qrouter::standard_route } qrouter-1.4.88/main.c0000644000175000017510000000332214473033744013745 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* qrouter entry point for non-Tcl compile version */ /*--------------------------------------------------------------*/ #include #include #include "qrouter.h" #include "output.h" /*--------------------------------------------------------------*/ /* Procedure main() performs the basic route steps without any */ /* interaction or scripting, writes a DEF file as output, and */ /* exits. */ /* */ /* Precedure mimics the "standard_route" script (up to date as */ /* of November 25, 2015) */ /*--------------------------------------------------------------*/ int main(int argc, char *argv[]) { int result; result = runqrouter(argc, argv); if (result != 0) return result; read_def(NULL); maskMode = MASK_AUTO; dofirststage(0, -1); maskMode = MASK_NONE; result = dosecondstage(0, FALSE, FALSE, (u_int)100); if (result < 5) dosecondstage(0, FALSE, FALSE, (u_int)100); write_def(NULL); /* write_delays() cannot work in a non-Tcl build */ // write_delays((delayfilename == NULL) ? "stdout" : delayfilename); return 0; } /*--------------------------------------------------------------*/ /* Define graphics routines as empty subroutines. May want to */ /* provide a simple X11 graphics environment outside of Tcl/Tk */ /*--------------------------------------------------------------*/ void highlight_source(void) { } void highlight_dest(void) { } void highlight_starts(POINT glist) { } void highlight_mask(void) { } void highlight(int x, int y) { } void draw_net(NET net, u_char single, int *lastlayer) { } void draw_layout(void) { } int recalc_spacing(void) { return 0; } qrouter-1.4.88/qrouter.c0000644000175000017510000021102314473033744014521 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* qrouter.c -- general purpose autorouter */ /* Reads LEF libraries and DEF netlists, and generates an */ /* annotated DEF netlist as output. */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June 2011, based on code by Steve */ /* Beccue, 2003 */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include #include #ifdef TCL_QROUTER #include #endif #include "qrouter.h" #include "qconfig.h" #include "point.h" #include "node.h" #include "maze.h" #include "mask.h" #include "output.h" #include "lef.h" #include "def.h" #include "graphics.h" int TotalRoutes = 0; NET *Nlnets; // list of nets in the design NET CurNet; // current net to route, used by 2nd stage STRING DontRoute; // a list of nets not to route (e.g., power) STRING CriticalNet; // list of critical nets to route first GATE GateInfo; // standard cell macro information GATE PinMacro; // macro definition for a pin GATE Nlgates; // gate instance information NETLIST FailedNets; // list of nets that failed to route u_int *Obs[MAX_LAYERS]; // net obstructions in layer PROUTE *Obs2[MAX_LAYERS]; // used for pt->pt routes on layer ObsInfoRec *Obsinfo[MAX_LAYERS]; // temporary array used for detailed obstruction info NODEINFO *Nodeinfo[MAX_LAYERS]; // nodes and stub information is here. . . DSEG UserObs; // user-defined obstruction layers u_int progress[3]; // analysis of behavior u_char needblock[MAX_LAYERS]; char *vddnet = NULL; char *gndnet = NULL; char *antenna_cell = NULL; int Numnets = 0; int Pinlayers = 0; u_int minEffort = 0; // Minimum effort applied from command line. u_char Verbose = 3; // Default verbose level u_char forceRoutable = FALSE; u_char maskMode = MASK_AUTO; u_char mapType = MAP_OBSTRUCT | DRAW_ROUTES; u_char ripLimit = 10; // Fail net rather than rip up more than // this number of other nets. u_char unblockAll = FALSE; char *DEFfilename = NULL; char *delayfilename = NULL; DPOINT testpoint = NULL; // used for debugging route problems ScaleRec Scales; // record of input and output scales /*--------------------------------------------------------------*/ /* Upate the output scale factor. It has to be a valid DEF */ /* scale factor and it has to be a multiple of the given scale */ /* factor. */ /*--------------------------------------------------------------*/ void update_mscale(int mscale) { static int valid_mscales[] = {100, 200, 1000, 2000, 10000, 20000}; int nscales = sizeof(valid_mscales) / sizeof(valid_mscales[0]); int mscale2, i; if (mscale == 0) return; if ((Scales.mscale % mscale) != 0) { // Check valid scale values; if none is appropriate, don't update for (i = 0; i < nscales; i++) { mscale2 = valid_mscales[i]; if (mscale2 <= Scales.mscale) continue; if ((mscale2 % mscale) == 0) { Scales.mscale = mscale2; break; } } } } /*--------------------------------------------------------------*/ /* Check track pitch and set the number of channels (may be */ /* called from DefRead) */ /*--------------------------------------------------------------*/ int set_num_channels(void) { int i, glimitx, glimity; NET net; NODE node; DPOINT ctap, ltap, ntap; if (NumChannelsX != 0) return 0; /* Already been called */ if (PitchX == 0.0) { Fprintf(stderr, "Have a 0 pitch for X direction. Exit.\n"); return (-3); } else if (PitchY == 0.0) { Fprintf(stderr, "Have a 0 pitch for Y direction. Exit.\n"); return (-3); } NumChannelsX = (int)(1.5 + (Xupperbound - Xlowerbound) / PitchX); NumChannelsY = (int)(1.5 + (Yupperbound - Ylowerbound) / PitchY); if ((Verbose > 1) || (NumChannelsX <= 0)) Fprintf(stdout, "Number of x channels is %d\n", NumChannelsX); if ((Verbose > 1) || (NumChannelsY <= 0)) Fprintf(stdout, "Number of y channels is %d\n", NumChannelsY); if (NumChannelsX <= 0) { Fprintf(stderr, "Something wrong with x bounds.\n"); return(-3); } if (NumChannelsY <= 0) { Fprintf(stderr, "Something wrong with y bounds.\n"); return(-3); } Flush(stdout); // 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; glimity = NumChannelsY; 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; glimity = NumChannelsY; 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; } /*--------------------------------------------------------------*/ /* Allocate the Obs[] array (may be called from DefRead) */ /*--------------------------------------------------------------*/ int allocate_obs_array(void) { int i; if (Obs[0] != NULL) return 0; /* Already been called */ for (i = 0; i < Num_layers; i++) { Obs[i] = (u_int *)calloc(NumChannelsX * NumChannelsY, sizeof(u_int)); if (!Obs[i]) { Fprintf(stderr, "Out of memory 4.\n"); return(4); } } return 0; } /*--------------------------------------------------------------*/ /* countlist --- */ /* Count the number of entries in a simple linked list */ /*--------------------------------------------------------------*/ int countlist(NETLIST net) { NETLIST nptr = net; int count = 0; while (nptr != NULL) { count++; nptr = nptr->next; } return count; } /* Forward declaration */ static void helpmessage(void); /*--------------------------------------------------------------*/ /* runqrouter - main program entry point, parse command line */ /* */ /* ARGS: argc (count) argv, command line */ /* RETURNS: to OS */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ int runqrouter(int argc, char *argv[]) { int i; FILE *configFILEptr, *infoFILEptr; static char configdefault[] = CONFIGFILENAME; char *configfile = configdefault; char *infofile = NULL; char *dotptr; char *Filename = NULL; u_char readconfig = FALSE; u_char doscript = FALSE; Scales.iscale = 1; Scales.mscale = 100; /* Parse arguments */ for (i = 0; i < argc; i++) { char optc, argsep = '\0'; char *optarg = NULL; if (*argv[i] == '-') { /* 1st pass---look for which options require an argument */ optc = *(argv[i] + 1); switch (optc) { case 'c': case 'i': case 'e': case 'k': case 'v': case 'd': case 'p': case 'g': case 'r': case 's': argsep = *(argv[i] + 2); if (argsep == '\0') { i++; if (i < argc) { optarg = argv[i]; if (*optarg == '-') { Fprintf(stderr, "Option -%c needs an argument.\n", optc); Fprintf(stderr, "Option not handled.\n"); continue; } } else { Fprintf(stderr, "Option -%c needs an argument.\n", optc); Fprintf(stderr, "Option not handled.\n"); continue; } } else optarg = argv[i] + 2; } /* Now handle each option individually */ switch (optc) { case 'c': configfile = strdup(optarg); break; case 'v': Verbose = atoi(optarg); break; case 'i': infofile = strdup(optarg); break; case 'd': if (delayfilename != NULL) free(delayfilename); delayfilename = strdup(optarg); break; case 'p': vddnet = strdup(optarg); break; case 'g': gndnet = strdup(optarg); break; case 's': // The "-s" argument is not handled here but is used // to avoid generating a warning message. doscript = TRUE; break; case 'r': if (sscanf(optarg, "%d", &Scales.iscale) != 1) { Fprintf(stderr, "Bad resolution scalefactor \"%s\", " "integer expected.\n", optarg); Scales.iscale = 1; } break; case 'h': helpmessage(); return 1; break; case 'f': forceRoutable = TRUE; break; case 'k': Fprintf(stdout, "Option \"k\" deprecated. Use \"effort\"" " in stage2 or stage3 command or -e option\n"); minEffort = 100 * atoi(optarg); break; case 'e': minEffort = atoi(optarg); break; case 'n': /* Ignore '-noc' or '-nog', handled elsewhere */ break; case '\0': /* Ignore '-' */ break; case '-': /* Ignore '--' */ break; default: Fprintf(stderr, "Bad option -%c, ignoring.\n", optc); } } else { /* Not an option or an option argument, so treat as a filename */ Filename = strdup(argv[i]); } } if (infofile != NULL) { infoFILEptr = fopen(infofile, "w" ); free(infofile); } else { infoFILEptr = NULL; #ifndef TCL_QROUTER fprintf(stdout, "Qrouter detail maze router version %s.%s\n", VERSION, REVISION); #endif } if (!doscript) { configFILEptr = fopen(configfile, "r"); if (configFILEptr) { read_config(configFILEptr, (infoFILEptr == NULL) ? FALSE : TRUE); readconfig = TRUE; } else { if (configfile != configdefault) Fprintf(stderr, "Could not open %s\n", configfile ); else Fprintf(stdout, "No .cfg file specified, continuing without.\n"); } if (configfile != configdefault) free(configfile); } if (infoFILEptr != NULL) { /* Print qrouter name and version number at the top */ #ifdef TCL_QROUTER fprintf(infoFILEptr, "qrouter %s.%s.T\n", VERSION, REVISION); #else fprintf(infoFILEptr, "qrouter %s.%s\n", VERSION, REVISION); #endif /* Output database units expected by the technology LEF file */ /* Note that this comes from MANUFACTURINGGRID, not UNITS DATABASE */ fprintf(infoFILEptr, "units scale %d\n", Scales.mscale); /* Resolve base horizontal and vertical pitches. */ post_config(TRUE); /* Print information about route layers, and exit */ for (i = 0; i < Num_layers; i++) { double pitch, width; int vnum, hnum; int o = LefGetRouteOrientation(i); char *layername = LefGetRouteName(i); check_variable_pitch(i, &hnum, &vnum); if (layername != NULL) { pitch = (o == 1) ? PitchY : PitchX, width = LefGetRouteWidth(i); if (pitch == 0.0 || width == 0.0) continue; fprintf(infoFILEptr, "%s %g %g %g %s", layername, pitch, LefGetRouteOffset(i), width, (o == 1) ? "horizontal" : "vertical"); if (o == 1 && vnum > 1) fprintf(infoFILEptr, " %d", vnum); else if (o == 0 && hnum > 1) fprintf(infoFILEptr, " %d", hnum); fprintf(infoFILEptr, "\n"); } } fclose(infoFILEptr); return 1; } 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) { Fprintf(stdout, "No netlist file specified, continuing without.\n"); // Print help message but continue normally. helpmessage(); } Obs[0] = (u_int *)NULL; NumChannelsX = 0; // This is so we can check if NumChannelsX/Y were // set from within DefRead() due to reading in // existing nets. Scales.oscale = 1.0; return 0; } /*--------------------------------------------------------------*/ /* remove_from_failed --- */ /* */ /* Remove one net from the list of failing nets. If "net" was */ /* in the list FailedNets, then return TRUE, otherwise return */ /* FALSE. */ /*--------------------------------------------------------------*/ u_char remove_from_failed(NET net) { NETLIST nl, lastnl; lastnl = (NETLIST)NULL; for (nl = FailedNets; nl; nl = nl->next) { if (nl->net == net) { if (lastnl == NULL) FailedNets = nl->next; else lastnl->next = nl->next; free(nl); return TRUE; } lastnl = nl; } return FALSE; } /*--------------------------------------------------------------*/ /* remove_failed --- */ /* */ /* Free up memory in the list of route failures. */ /*--------------------------------------------------------------*/ void remove_failed() { NETLIST nl; while (FailedNets) { nl = FailedNets; FailedNets = FailedNets->next; free(nl); } } /*--------------------------------------------------------------*/ /* Remove the first (top) route record from a net */ /*--------------------------------------------------------------*/ void remove_top_route(NET net) { ROUTE rt; SEG seg; rt = net->routes; net->routes = net->routes->next; while (rt->segments) { seg = rt->segments; rt->segments = rt->segments->next; free(seg); } free(rt); } /*--------------------------------------------------------------*/ /* reinitialize --- */ /* */ /* Free up memory in preparation for reading another DEF file */ /*--------------------------------------------------------------*/ static void reinitialize() { int i, j; NETLIST nl; NET net; ROUTE rt; SEG seg; DSEG obs, tap; NODE node; GATE gate; DPOINT dpt; // Free up all of the matrices for (i = 0; i < Pinlayers; i++) { for (j = 0; j < NumChannelsX * NumChannelsY; j++) if (Nodeinfo[i][j]) free(Nodeinfo[i][j]); free(Nodeinfo[i]); Nodeinfo[i] = NULL; } for (i = 0; i < Num_layers; i++) { free(Obs2[i]); free(Obs[i]); Obs2[i] = NULL; Obs[i] = NULL; } if (RMask != NULL) { free(RMask); RMask = NULL; } // Free the netlist of failed nets (if there is one) remove_failed(); // Free all net and route information for (i = 0; i < Numnets; i++) { net = Nlnets[i]; while (net->noripup) { nl = net->noripup; net->noripup = net->noripup->next; free(nl); } while (net->routes) remove_top_route(net); while (net->netnodes) { node = net->netnodes; net->netnodes = net->netnodes->next; while (node->taps) { dpt = node->taps; node->taps = node->taps->next; free(dpt); } while (node->extend) { dpt = node->extend; node->extend = node->extend->next; free(dpt); } // Note: node->netname is not allocated // but copied from net record free(node); } free (net->netname); free (net); } free(Nlnets); Nlnets = NULL; Numnets = 0; // Free all gates information while (Nlgates) { gate = Nlgates; Nlgates = Nlgates->next; while (gate->obs) { obs = gate->obs; gate->obs = gate->obs->next; free(obs); } for (i = 0; i < gate->nodes; i++) { while (gate->taps[i]) { tap = gate->taps[i]; gate->taps[i] = gate->taps[i]->next; free(tap); } // Note: gate->node[i] is not allocated // but copied from cell record in GateInfo // Likewise for gate->noderec[i] } free(gate->gatename); } Nlgates = NULL; } /*--------------------------------------------------------------*/ /* apply_drc_blocks() --- */ /* */ /* Use via and route width and spacing information to determine */ /* if blockages are needed in tracks adjacent to routed */ /* segments to avoid causing DRC errors in the output. */ /* */ /* If layer == -1, then determine values normally for all */ /* route layers. If layer >= 0, determine values for specified */ /* layer only. If via_except > 0, then adjust the value for */ /* a DRC violating distance for vias in adjacent tracks by that */ /* amount (in microns). If route_except > 0, then adjust the */ /* value for a DRC violating distance between a via and a route */ /* in adjacent tracks by that amount. */ /*--------------------------------------------------------------*/ void apply_drc_blocks(int layer, double via_except, double route_except) { int i; double sreq1, sreq2, sreq2t; // Fill in needblock bit fields, which are used by commit_proute // when route layers are too large for the grid size, and grid points // around a route need to be marked as blocked whenever something is // routed on those layers. // "ROUTEBLOCK" is set if the spacing is violated between a normal // route and an adjacent via. "VIABLOCK" is set if the spacing is // violated between two adjacent vias. It may be helpful to define // a third category which is route-to-route spacing violation. // There are up to four different via types per base layer with // different geometries based on the permutation of rotations of // the top and bottom layers, so we only register blocking behavior // if all of the via types will generate spacing violations. for (i = 0; i < Num_layers; i++) { if ((layer >= 0) && (i != layer)) continue; needblock[i] = FALSE; sreq1 = LefGetRouteSpacing(i); if (i < Num_layers - 1) { sreq2 = LefGetXYViaWidth(i, i, 0, 0) + sreq1; sreq2t = LefGetXYViaWidth(i, i, 0, 1) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = LefGetXYViaWidth(i, i, 0, 2) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = LefGetXYViaWidth(i, i, 0, 3) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2 -= via_except; if ((sreq2 - EPS) > PitchX) needblock[i] |= VIABLOCKX; } if (i != 0) { sreq2 = LefGetXYViaWidth(i - 1, i, 0, 0) + sreq1; sreq2t = LefGetXYViaWidth(i - 1, i, 0, 1) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = LefGetXYViaWidth(i - 1, i, 0, 2) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = LefGetXYViaWidth(i - 1, i, 0, 3) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2 -= via_except; if ((sreq2 - EPS) > PitchX) needblock[i] |= VIABLOCKX; } if (i < Num_layers - 1) { sreq2 = LefGetXYViaWidth(i, i, 1, 0) + sreq1; sreq2t = LefGetXYViaWidth(i, i, 1, 1) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = LefGetXYViaWidth(i, i, 1, 2) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = LefGetXYViaWidth(i, i, 1, 3) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2 -= via_except; if ((sreq2 - EPS) > PitchY) needblock[i] |= VIABLOCKY; } if (i != 0) { sreq2 = LefGetXYViaWidth(i - 1, i, 1, 0) + sreq1; sreq2t = LefGetXYViaWidth(i - 1, i, 1, 1) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = LefGetXYViaWidth(i - 1, i, 1, 2) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = LefGetXYViaWidth(i - 1, i, 1, 3) + sreq1; if (sreq2t < sreq2) sreq2 = sreq2t; sreq2 -= via_except; if ((sreq2 - EPS) > PitchY) needblock[i] |= VIABLOCKY; } sreq1 += 0.5 * LefGetRouteWidth(i); if (i < Num_layers - 1) { sreq2 = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 0, 0); sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 0, 1); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 0, 2); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 0, 3); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2 -= route_except; if ((sreq2 - EPS) > PitchX) needblock[i] |= ROUTEBLOCKX; } if (i != 0) { sreq2 = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 0, 0); sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 0, 1); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 0, 2); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 0, 3); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2 -= route_except; if ((sreq2 - EPS) > PitchX) needblock[i] |= ROUTEBLOCKX; } if (i < Num_layers - 1) { sreq2 = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 1, 0); sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 1, 1); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 1, 2); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 1, 3); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2 -= route_except; if ((sreq2 - EPS) > PitchY) needblock[i] |= ROUTEBLOCKY; } if (i != 0) { sreq2 = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 1, 0); sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 1, 1); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 1, 2); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 1, 3); if (sreq2t < sreq2) sreq2 = sreq2t; sreq2 -= route_except; if ((sreq2 - EPS) > PitchY) needblock[i] |= ROUTEBLOCKY; } } } /*--------------------------------------------------------------*/ /* remove_tap_blocks */ /* */ /* Qrouter avoids routing directly over a tap point, blocking */ /* it, if there is a Nodeinfo[][]->nodeloc entry present. */ /* Remove this entry to remove the blockage (it can be */ /* replaced if needed by copying back the Nodeinfo[][]->nodesav */ /* pointer) */ /*--------------------------------------------------------------*/ void remove_tap_blocks(int netnum) { int i, j; NODE node; for (i = 0; i < Pinlayers; i++) { for (j = 0; j < NumChannelsX * NumChannelsY; j++) { if (Nodeinfo[i][j]) { node = Nodeinfo[i][j]->nodeloc; if (node != (NODE)NULL) if (node->netnum == netnum) Nodeinfo[i][j]->nodeloc = (NODE)NULL; } } } } /*--------------------------------------------------------------*/ /* post_def_setup --- */ /* */ /* Things to do after a DEF file has been read in, and the size */ /* of the layout, components, and nets are known. */ /*--------------------------------------------------------------*/ static int post_def_setup() { NET net; ROUTE rt; DPOINT tpoint; int i; if (DEFfilename == NULL) { Fprintf(stderr, "No DEF file read, nothing to set up.\n"); return 1; } else { if (Num_layers <= 0) { Fprintf(stderr, "No routing layers defined, nothing to do.\n"); return 1; } } for (i = 0; i < Numnets; i++) { net = Nlnets[i]; find_bounding_box(net); defineRouteTree(net); } create_netorder(0); // Choose ordering method (0 or 1) set_num_channels(); // If not called from DefRead() allocate_obs_array(); // If not called from DefRead() initMask(); for (i = 0; i < Num_layers; i++) { Obsinfo[i] = (ObsInfoRec *)calloc(NumChannelsX * NumChannelsY, sizeof(ObsInfoRec)); if (!Obsinfo[i]) { fprintf(stderr, "Out of memory 5.\n"); exit(5); } Nodeinfo[i] = (NODEINFO *)calloc(NumChannelsX * NumChannelsY, sizeof(NODEINFO)); if (!Nodeinfo[i]) { fprintf( stderr, "Out of memory 6.\n"); exit(6); } } Flush(stdout); if (Verbose > 1) Fprintf(stderr, "Diagnostic: memory block is %d bytes\n", (int)sizeof(u_int) * NumChannelsX * NumChannelsY); /* If any watch points were made, make sure that they have */ /* the correct geometry values, since they were made before */ /* the DEF file was read. */ for (tpoint = testpoint; tpoint; tpoint = tpoint->next) { if (tpoint->gridx < 0) { /* Compute gridx,y from x,y */ tpoint->gridx = (int)(round((tpoint->x - Xlowerbound) / PitchX)); tpoint->gridy = (int)(round((tpoint->y - Xlowerbound) / PitchX)); } else { /* Compute x,y from gridx,y */ tpoint->x = (tpoint->gridx * PitchX) + Xlowerbound; tpoint->y = (tpoint->gridy * PitchY) + Ylowerbound; } } /* Be sure to create obstructions from gates first, since we don't */ /* want improperly defined or positioned obstruction layers to over- */ /* write our node list. */ expand_tap_geometry(); clip_gate_taps(); create_obstructions_from_gates(); create_obstructions_inside_nodes(); create_obstructions_outside_nodes(); tap_to_tap_interactions(); create_obstructions_from_variable_pitch(); adjust_stub_lengths(); find_route_blocks(); count_reachable_taps(unblockAll); count_pinlayers(); // If any nets are pre-routed, calculate route endpoints, and // place those routes. for (i = 0; i < Numnets; i++) { net = Nlnets[i]; for (rt = net->routes; rt; rt = rt->next) route_set_connections(net, rt); writeback_all_routes(net); } // Remove the Obsinfo array, which is no longer needed, and allocate // the Obs2 array for costing information for (i = 0; i < Num_layers; i++) free(Obsinfo[i]); for (i = 0; i < Num_layers; i++) { Obs2[i] = (PROUTE *)calloc(NumChannelsX * NumChannelsY, sizeof(PROUTE)); if (!Obs2[i]) { fprintf( stderr, "Out of memory 9.\n"); exit(9); } } // Remove tap blocks from power, ground, and antenna nets, as these // can take up large areas of the layout and will cause serious issues // with routability if left blocked. remove_tap_blocks(VDD_NET); remove_tap_blocks(GND_NET); remove_tap_blocks(ANTENNA_NET); // Now we have netlist data, and can use it to get a list of nets. FailedNets = (NETLIST)NULL; Flush(stdout); if (Verbose > 0) Fprintf(stdout, "There are %d nets in this design.\n", Numnets); return 0; } /*--------------------------------------------------------------*/ /* read_def --- */ /* */ /* Read in the DEF file in DEFfilename */ /* Return 0 on success, 1 on fatal error in DEF file. */ /*--------------------------------------------------------------*/ int read_def(char *filename) { float oscale; double precis; int result; if ((filename == NULL) && (DEFfilename == NULL)) { Fprintf(stderr, "No DEF file specified, nothing to read.\n"); return 1; } else if (filename != NULL) { if (DEFfilename != NULL) { reinitialize(); free(DEFfilename); } DEFfilename = strdup(filename); } else reinitialize(); oscale = (float)0.0; result = DefRead(DEFfilename, &oscale); precis = Scales.mscale / (double)oscale; // from LEF manufacturing grid if (precis < 1.0) precis = 1.0; precis *= (double)Scales.iscale; // user-defined extra scaling Scales.iscale = (int)(precis + 0.5); Scales.oscale = (double)(Scales.iscale * oscale); if (Verbose > 0) Fprintf(stdout, "Output scale = microns / %g, precision %g\n", Scales.oscale / (double)Scales.iscale, 1.0 / (double)Scales.iscale); post_def_setup(); return result; } /*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/ int dofirststage(u_char graphdebug, int debug_netnum) { int i, failcount, remaining, result; NET net; NETLIST nl; // Clear the lists of failed routes, in case first // stage is being called more than once. if (debug_netnum <= 0) remove_failed(); // Now find and route all the nets remaining = Numnets; for (i = (debug_netnum >= 0) ? debug_netnum : 0; i < Numnets; i++) { net = getnettoroute(i); if ((net != NULL) && (net->netnodes != NULL)) { result = doroute(net, FALSE, graphdebug); if (result == 0) { remaining--; if (Verbose > 0) Fprintf(stdout, "Finished routing net %s\n", net->netname); Fprintf(stdout, "Nets remaining: %d\n", remaining); Flush(stdout); } else { if (Verbose > 0) Fprintf(stdout, "Failed to route net %s\n", net->netname); } } else { if (net && (Verbose > 0)) { Fprintf(stdout, "Nothing to do for net %s\n", net->netname); } remaining--; } if (debug_netnum >= 0) break; } failcount = countlist(FailedNets); if (debug_netnum >= 0) return failcount; if (Verbose > 0) { Flush(stdout); Fprintf(stdout, "\n----------------------------------------------\n"); Fprintf(stdout, "Progress: "); Fprintf(stdout, "Stage 1 total routes completed: %d\n", TotalRoutes); } if (FailedNets == (NETLIST)NULL) Fprintf(stdout, "No failed routes!\n"); else { if (FailedNets != (NETLIST)NULL) Fprintf(stdout, "Failed net routes: %d\n", failcount); } if (Verbose > 0) Fprintf(stdout, "----------------------------------------------\n"); return failcount; } /*--------------------------------------------------------------*/ /* getnettoroute - get a net to route */ /* */ /* ARGS: */ /* RETURNS: */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Fri Aug 8 */ /*--------------------------------------------------------------*/ NET getnettoroute(int order) { NET net; net = Nlnets[order]; if (net == NULL) return NULL; if (net->flags & NET_IGNORED) return NULL; if (net->numnodes >= 2) return net; // Qrouter will route power and ground nets even if the // standard cell power and ground pins are not listed in // the nets section. Because of this, it is okay to have // only one node. if ((net->numnodes == 1) && (net->netnum == VDD_NET || net->netnum == GND_NET || net->netnum == ANTENNA_NET)) return net; if (Verbose > 3) { Flush(stdout); Fprintf(stderr, "getnettoroute(): Fell through\n"); } return NULL; } /* getnettoroute() */ /*--------------------------------------------------------------*/ /* Find all routes that collide with net "net", remove them */ /* from the Obs[] matrix, append them to the FailedNets list, */ /* and then write the net "net" back to the Obs[] matrix. */ /* */ /* Return the number of nets ripped up */ /*--------------------------------------------------------------*/ static int ripup_colliding(NET net, u_char onlybreak) { NETLIST nl, nl2, fn; int ripped; // Analyze route for nets with which it collides nl = find_colliding(net, &ripped); // "ripLimit" limits the number of collisions so that the // router avoids ripping up huge numbers of nets, which can // cause the number of failed nets to keep increasing. if (ripped > ripLimit) { while (nl) { nl2 = nl->next; free(nl); nl = nl2; } return -1; } // Remove the colliding nets from the route grid and append // them to FailedNets. ripped = 0; while(nl) { ripped++; nl2 = nl->next; if (Verbose > 0) Fprintf(stdout, "Ripping up blocking net %s\n", nl->net->netname); if (ripup_net(nl->net, TRUE, onlybreak, FALSE) == TRUE) { for (fn = FailedNets; fn && fn->next != NULL; fn = fn->next); if (fn) fn->next = nl; else FailedNets = nl; // Add nl->net to "noripup" list for this net, so it won't be // routed over again by the net. Avoids infinite looping in // the second stage. fn = (NETLIST)malloc(sizeof(struct netlist_)); fn->next = net->noripup; net->noripup = fn; fn->net = nl->net; } nl->next = (NETLIST)NULL; nl = nl2; } return ripped; } /*--------------------------------------------------------------*/ /* Do a second-stage route (rip-up and re-route) of a single */ /* net "net". */ /*--------------------------------------------------------------*/ int route_net_ripup(NET net, u_char graphdebug, u_char onlybreak) { int result; NETLIST nl, nl2; // Find the net in the Failed list and remove it. if (FailedNets) { if (FailedNets->net == net) { nl2 = FailedNets; FailedNets = FailedNets->next; free(nl2); } else { for (nl = FailedNets; nl->next; nl = nl->next) { if (nl->next->net == net) break; } nl2 = nl->next; nl->next = nl2->next; free(nl2); } } result = doroute(net, TRUE, graphdebug); if (result != 0) { if (net->noripup != NULL) { if ((net->flags & NET_PENDING) == 0) { // Clear this net's "noripup" list and try again. while (net->noripup) { nl = net->noripup->next; free(net->noripup); net->noripup = nl; } result = doroute(net, TRUE, graphdebug); net->flags |= NET_PENDING; // Next time we abandon it. } } } if (result != 0) result = ripup_colliding(net, onlybreak); return result; } /*--------------------------------------------------------------*/ /* dosecondstage() --- */ /* */ /* Second stage: Rip-up and reroute failing nets. */ /* Method: */ /* 1) Route a failing net with stage = 1 (other nets become */ /* costs, not blockages, no copying to Obs) */ /* 2) If net continues to fail, flag it as unroutable and */ /* remove it from the list. */ /* 3) Otherwise, determine the nets with which it collided. */ /* 4) Remove all of the colliding nets, and add them to the */ /* FailedNets list */ /* 5) Route the original failing net. */ /* 6) Continue until all failed nets have been processed. */ /* */ /* Return value: The number of failing nets */ /*--------------------------------------------------------------*/ int dosecondstage(u_char graphdebug, u_char singlestep, u_char onlybreak, u_int effort) { int failcount, result, i; NET net; NETLIST nl, nl2; NETLIST Abandoned; // Abandoned routes---not even trying any more. ROUTE rt, rt2; SEG seg; u_int loceffort = (effort > minEffort) ? effort : minEffort; fillMask((u_char)0); Abandoned = NULL; for (i = 0; i < 3; i++) progress[i] = 0; // Clear the "noripup" field from all of the failed nets, in case // the second stage route is being repeated. for (nl2 = FailedNets; nl2; nl2 = nl2->next) { net = nl2->net; while (net->noripup) { nl = net->noripup->next; free(net->noripup); net->noripup = nl; } net->flags &= ~NET_PENDING; } while (FailedNets != NULL) { // Diagnostic: how are we doing? failcount = countlist(FailedNets); if (Verbose > 1) Fprintf(stdout, "------------------------------\n"); Fprintf(stdout, "Nets remaining: %d\n", failcount); if (Verbose > 1) Fprintf(stdout, "------------------------------\n"); net = FailedNets->net; // Remove this net from the fail list nl2 = FailedNets; FailedNets = FailedNets->next; free(nl2); // Keep track of which routes existed before the call to doroute(). for (rt = net->routes; rt && rt->next; rt = rt->next); if (Verbose > 2) Fprintf(stdout, "Routing net %s with collisions\n", net->netname); Flush(stdout); result = doroute(net, TRUE, graphdebug); if (result != 0) { if (net->noripup != NULL) { if ((net->flags & NET_PENDING) == 0) { // Clear this net's "noripup" list and try again. while (net->noripup) { nl = net->noripup->next; free(net->noripup); net->noripup = nl; } result = doroute(net, TRUE, graphdebug); net->flags |= NET_PENDING; // Next time we abandon it. } } } if (result == 0) { // Find nets that collide with "net" and remove them, adding them // to the end of the FailedNets list. // If the number of nets to be ripped up exceeds "ripLimit", // then treat this as a route failure, and don't rip up any of // the colliding nets. result = ripup_colliding(net, onlybreak); if (result > 0) result = 0; } if (result != 0) { // Complete failure to route, even allowing collisions. // Abandon routing this net. if (Verbose > 0) Fprintf(stdout, "Failure on net %s: Abandoning for now.\n", net->netname); // Add the net to the "abandoned" list nl = (NETLIST)malloc(sizeof(struct netlist_)); nl->net = net; nl->next = Abandoned; Abandoned = nl; while (FailedNets && (FailedNets->net == net)) { nl = FailedNets->next; free(FailedNets); FailedNets = nl; } // Remove routing information for all new routes that have // not been copied back into Obs[]. if (rt == NULL) { rt = net->routes; net->routes = NULL; // remove defunct pointer } else { rt2 = rt->next; rt->next = NULL; rt = rt2; } while (rt != NULL) { rt2 = rt->next; while (rt->segments) { seg = rt->segments->next; free(rt->segments); rt->segments = seg; } free(rt); rt = rt2; } // Remove both routing information and remove the route from // Obs[] for all parts of the net that were previously routed ripup_net(net, TRUE, FALSE, FALSE); // Remove routing information from net continue; } // Write back the original route to the grid array writeback_all_routes(net); // Evaluate progress by counting the total number of remaining // routes in the last (effort) cycles. progress[2]->progress[1] // is a progression from oldest to newest number of remaining // routes. Calculate the slope of this line and declare an end // to this 2nd stage route if the slope falls to zero. progress[1] += failcount; progress[0]++; if (progress[0] > loceffort) { if ((progress[2] > 0) && (progress[2] <= progress[1])) { Fprintf(stderr, "\nNo progress at level of effort %d;" " ending 2nd stage.\n", loceffort); break; } progress[2] = progress[1]; progress[1] = progress[0] = 0; } if (singlestep && (FailedNets != NULL)) return countlist(FailedNets); } // If the list of abandoned nets is non-null, attach it to the // end of the failed nets list. if (Abandoned != NULL) { if (FailedNets == NULL) { FailedNets = Abandoned; Abandoned = NULL; } else { for (nl = FailedNets; nl->next; nl = nl->next); nl->next = Abandoned; Abandoned = NULL; } } if (Verbose > 0) { Flush(stdout); Fprintf(stdout, "\n----------------------------------------------\n"); Fprintf(stdout, "Progress: "); Fprintf(stdout, "Stage 2 total routes completed: %d\n", TotalRoutes); } if (FailedNets == (NETLIST)NULL) { failcount = 0; Fprintf(stdout, "No failed routes!\n"); } else { failcount = countlist(FailedNets); if (FailedNets != (NETLIST)NULL) Fprintf(stdout, "Failed net routes: %d\n", failcount); } if (Verbose > 0) Fprintf(stdout, "----------------------------------------------\n"); return failcount; } /*--------------------------------------------------------------*/ /* 3rd stage routing (cleanup). Rip up each net in turn and */ /* reroute it. With all of the crossover costs gone, routes */ /* should be much better than the 1st stage. Any route that */ /* existed before it got ripped up should by definition be */ /* routable. */ /*--------------------------------------------------------------*/ int dothirdstage(u_char graphdebug, int debug_netnum, u_int effort) { int i, failcount, remaining, result, maskSave; u_char failed; NET net; ROUTE rt; NETLIST nl; u_int loceffort = (effort > minEffort) ? effort : minEffort; // Now find and route all the nets for (i = 0; i < 3; i++) progress[i] = 0; remaining = Numnets; for (i = (debug_netnum >= 0) ? debug_netnum : 0; i < Numnets; i++) { net = getnettoroute(i); failed = remove_from_failed(net); if ((net != NULL) && (net->netnodes != NULL)) { // Simple optimization: If every route has four or fewer // segments, then rerouting is almost certainly a waste of // time. if (!failed) { for (rt = net->routes; rt; rt = rt->next) { int j; SEG seg = rt->segments; for (j = 0; j < 3; j++) { if (seg->next == NULL) break; seg = seg->next; } if (j == 3) break; } if (rt == NULL) { if (Verbose > 0) Fprintf(stdout, "Keeping route for net %s\n", net->netname); remaining--; continue; } } setBboxCurrent(net); ripup_net(net, FALSE, FALSE, TRUE); /* retain = TRUE */ // Set aside routes in case of failure. rt = net->routes; net->routes = NULL; // set mask mode to BBOX, if auto maskSave = maskMode; if (maskMode == MASK_AUTO) maskMode = MASK_BBOX; result = doroute(net, FALSE, graphdebug); maskMode = maskSave; if (result == 0) { if (Verbose > 0) Fprintf(stdout, "Finished routing net %s\n", net->netname); remaining--; Fprintf(stdout, "Nets remaining: %d\n", remaining); Flush(stdout); remove_routes(rt, FALSE); /* original is no longer needed */ } else if (!failed) { if (Verbose > 0) Fprintf(stdout, "Failed to route net %s; restoring original\n", net->netname); ripup_net(net, TRUE, FALSE, TRUE); // Remove routes from Obs array remove_routes(net->routes, FALSE); /* should be NULL already */ net->routes = rt; writeback_all_routes(net); /* restore the original */ remaining--; /* Pull net from FailedNets, since we restored it. */ if (FailedNets && (FailedNets->net == net)) { nl = FailedNets->next; free(FailedNets); FailedNets = nl; } } else { if (Verbose > 0) Fprintf(stdout, "Failed to route net %s.\n", net->netname); } } else { if (net && (Verbose > 0)) { Fprintf(stdout, "Nothing to do for net %s\n", net->netname); } remaining--; } if (debug_netnum >= 0) break; /* Progress analysis (see 2nd stage). Normally, the 3rd */ /* stage is run only after all nets have been successfully */ /* routed. However, there is no guarantee of this, so it */ /* is necessary to anticipate convergence issues. */ progress[1] += failcount; progress[0]++; if (progress[0] > loceffort) { if ((progress[2] > 0) && (progress[2] < progress[1])) { Fprintf(stderr, "\nNo progress at level of effort %d;" " ending 3rd stage.\n", loceffort); break; } progress[2] = progress[1]; progress[1] = progress[0] = 0; } } failcount = countlist(FailedNets); if (debug_netnum >= 0) return failcount; if (Verbose > 0) { Flush(stdout); Fprintf(stdout, "\n----------------------------------------------\n"); Fprintf(stdout, "Progress: "); Fprintf(stdout, "Stage 3 total routes completed: %d\n", TotalRoutes); } if (FailedNets == (NETLIST)NULL) Fprintf(stdout, "No failed routes!\n"); else { if (FailedNets != (NETLIST)NULL) Fprintf(stdout, "Failed net routes: %d\n", failcount); } if (Verbose > 0) Fprintf(stdout, "----------------------------------------------\n"); return failcount; } /*--------------------------------------------------------------*/ /* 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; int i; for (i = 0; i < 6; i++) { while (iroute->glist[i]) { gpoint = iroute->glist[i]; iroute->glist[i] = iroute->glist[i]->next; Pr = &OBS2VAL(gpoint->x1, gpoint->y1, gpoint->layer); Pr->flags &= ~PR_ON_STACK; freePOINT(gpoint); } } } /* Forward declarations */ static int next_route_setup(struct routeinfo_ *iroute, u_char stage); static int route_setup(struct routeinfo_ *iroute, u_char stage); /*--------------------------------------------------------------*/ /* doroute - basic route call */ /* */ /* stage = 0 is normal routing */ /* stage = 1 is the rip-up and reroute stage */ /* */ /* ARGS: two nodes to be connected */ /* RETURNS: 0 on success, -1 on failure */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Fri Aug 8 */ /*--------------------------------------------------------------*/ int doroute(NET net, u_char stage, u_char graphdebug) { ROUTE rt1, lrt; NETLIST nlist; int result, lastlayer, unroutable, i; struct routeinfo_ iroute; if (!net) { Fprintf(stderr, "doroute(): no net to route.\n"); return 0; } CurNet = net; // Global, used by 2nd stage // Fill out route information record iroute.net = net; iroute.rt = NULL; for (i = 0; i < 6; i++) iroute.glist[i] = NULL; iroute.nsrc = NULL; iroute.nsrctap = NULL; iroute.maxcost = MAXRT; iroute.do_pwrbus = FALSE; iroute.pwrbus_src = 0; lastlayer = -1; /* Set up Obs2[] matrix for first route */ result = route_setup(&iroute, stage); unroutable = result - 1; if (graphdebug) highlight_mask(); // Keep going until we are unable to route to a terminal while (net && (result > 0)) { if (graphdebug) highlight_source(); if (graphdebug) highlight_dest(); if (graphdebug) for (i = 0; i < 6; i++) highlight_starts(iroute.glist[i]); rt1 = createemptyroute(); rt1->netnum = net->netnum; iroute.rt = rt1; if (Verbose > 3) { Fprintf(stdout,"doroute(): added net %d path start %d\n", net->netnum, net->netnodes->nodenum); } result = route_segs(&iroute, stage, graphdebug); if (result < 0) { // Route failure. // If we failed this on the last round, then stop // working on this net and move on to the next. if (FailedNets && (FailedNets->net == net)) break; nlist = (NETLIST)malloc(sizeof(struct netlist_)); nlist->net = net; nlist->next = FailedNets; FailedNets = nlist; free(rt1); } else { TotalRoutes++; if (net->routes) { for (lrt = net->routes; lrt->next; lrt = lrt->next); lrt->next = rt1; } else { net->routes = rt1; } draw_net(net, TRUE, &lastlayer); } // For power routing, clear the list of existing pending route // solutions---they will not be relevant. 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) */ free_glist(&iroute); /* Route failure due to no taps or similar error---Log it */ if ((result < 0) || (unroutable > 0)) { if ((FailedNets == NULL) || (FailedNets->net != net)) { nlist = (NETLIST)malloc(sizeof(struct netlist_)); nlist->net = net; nlist->next = FailedNets; FailedNets = nlist; } } return (unroutable > 0) ? -1 : result; } /* doroute() */ /*--------------------------------------------------------------*/ /* Catch-all routine when no tap points are found. This is a */ /* common problem when the technology is not set up correctly */ /* and it's helpful to have all these error conditions pass */ /* to a single subroutine. */ /*--------------------------------------------------------------*/ static void unable_to_route(char *netname, NODE node, unsigned char forced) { if (node) Fprintf(stderr, "Node %s of net %s has no tap points---", print_node_name(node), netname); else Fprintf(stderr, "Node of net %s has no tap points---", netname); if (forced) Fprintf(stderr, "forcing a tap point.\n"); else Fprintf(stderr, "unable to route!\n"); } /*--------------------------------------------------------------*/ /* next_route_setup -- */ /* */ /*--------------------------------------------------------------*/ static int next_route_setup(struct routeinfo_ *iroute, u_char stage) { ROUTE rt; NODE node; int i, j; int rval, result; if (iroute->do_pwrbus == TRUE) { iroute->pwrbus_src++; iroute->nsrc = iroute->nsrc->next; rval = -2; while (rval == -2) { if ((iroute->pwrbus_src > iroute->net->numnodes) || (iroute->nsrc == NULL)) { result = 0; break; } else { result = set_powerbus_to_net(iroute->nsrc->netnum); clear_target_node(iroute->nsrc); rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist[0], &iroute->bbox, stage); if (rval == -2) { if (forceRoutable) { make_routable(iroute->nsrc); } else { iroute->pwrbus_src++; iroute->nsrc = iroute->nsrc->next; } unable_to_route(iroute->net->netname, iroute->nsrc, forceRoutable); } else if (rval < 0) return -1; } } } else { for (rt = iroute->net->routes; (rt && rt->next); rt = rt->next); // Set positions on last route to PR_SOURCE if (rt) { result = set_route_to_net(iroute->net, rt, PR_SOURCE, &iroute->glist[0], &iroute->bbox, stage); if (result == -2) { unable_to_route(iroute->net->netname, NULL, 0); return -1; } } else return -1; result = (count_targets(iroute->net) == 0) ? 0 : 1; } // Check for the possibility that there is already a route to the target if (!result) { // Remove nodes of the net from Nodeinfo.nodeloc so that they will not be // used for crossover costing of future routes. remove_tap_blocks(iroute->net->netnum); free_glist(iroute); return 0; } if (!iroute->do_pwrbus) { // If any target is found during the search, but is not the // target that is chosen for the minimum-cost path, then it // will be left marked "processed" and never visited again. // Make sure this doesn't happen by clearing the "processed" // flag from all such target nodes, and placing the positions // on the stack for processing again. clear_non_source_targets(iroute->net, &iroute->glist[0]); } if (Verbose > 1) { Fprintf(stdout, "netname = %s, route number %d\n", iroute->net->netname, TotalRoutes ); Flush(stdout); } if (iroute->maxcost > 2) iroute->maxcost >>= 1; // Halve the maximum cost from the last run return 1; // Successful setup } /*--------------------------------------------------------------*/ /* route_setup -- */ /* */ /*--------------------------------------------------------------*/ static int route_setup(struct routeinfo_ *iroute, u_char stage) { int i, j; u_int netnum, dir; int result, rval, unroutable; NODE node; NODEINFO lnode; PROUTE *Pr; // Make Obs2[][] a copy of Obs[][]. Convert pin obstructions to // terminal positions for the net being routed. for (i = 0; i < Num_layers; i++) { for (j = 0; j < NumChannelsX * NumChannelsY; j++) { netnum = Obs[i][j] & (~BLOCKED_MASK); Pr = &Obs2[i][j]; if (netnum != 0) { Pr->flags = 0; // Clear all flags if ((netnum & DRC_BLOCKAGE) == DRC_BLOCKAGE) Pr->prdata.net = DRC_BLOCKAGE; else Pr->prdata.net = netnum & NETNUM_MASK; } else { Pr->flags = PR_COST; // This location is routable Pr->prdata.cost = MAXRT; } } } if (iroute->net->netnum == VDD_NET || iroute->net->netnum == GND_NET || iroute->net->netnum == ANTENNA_NET) { // The normal method of selecting source and target is not amenable // to power bus routes. Instead, we use the global standard cell // power rails as the target, and each net in sequence becomes the // sole source node iroute->do_pwrbus = TRUE; iroute->nsrc = find_unrouted_node(iroute->net); result = (iroute->nsrc == NULL) ? 0 : 1; } else { iroute->do_pwrbus = FALSE; if (iroute->net->netnodes != NULL) iroute->nsrc = iroute->net->netnodes; else { Fprintf(stderr, "Net %s has no nodes, unable to route!\n", iroute->net->netname); return -1; } result = 1; } // We start at the node referenced by the route structure, and flag all // of its taps as PR_SOURCE, as well as all connected routes. unroutable = 0; if (result) { iroute->bbox.x2 = iroute->bbox.y2 = 0; iroute->bbox.x1 = NumChannelsX; iroute->bbox.y1 = NumChannelsY; if (iroute->do_pwrbus == FALSE) { // Set node to PR_SOURCE rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist[0], &iroute->bbox, stage); if (rval == -2) { unable_to_route(iroute->net->netname, NULL, 0); return -1; } // Set associated routes to PR_SOURCE (okay to fail) rval = set_routes_to_net(iroute->nsrc, iroute->net, PR_SOURCE, &iroute->glist[0], &iroute->bbox, stage); // Now search for all other nodes on the same net that have not // yet been routed, and flag all of their taps as PR_TARGET result = 0; for (node = iroute->net->netnodes; node; node = node->next) { if (node == iroute->nsrc) continue; rval = set_node_to_net(node, PR_TARGET, NULL, &iroute->bbox, stage); if (rval == 0) { result = 1; } else if (rval == -2) { if (forceRoutable) make_routable(node); unable_to_route(iroute->net->netname, node, forceRoutable); if (result == 0) result = -1; unroutable++; break; } else if (rval == 1) continue; /* This node was part of source */ // And add associated routes rval = set_routes_to_net(node, iroute->net, PR_TARGET, NULL, &iroute->bbox, stage); if (rval == 0) result = 1; /* (okay to fail) */ } /* If there's only one node and it's not routable, then fail. */ if (result == -1) return -1; } else { /* Do this for power bus connections */ while(1) { rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist[0], &iroute->bbox, stage); if (rval == -2) { iroute->nsrc = iroute->nsrc->next; if (iroute->nsrc == NULL) break; } else break; } if (rval == -2) { if (forceRoutable) make_routable(iroute->net->netnodes); unable_to_route(iroute->net->netname, iroute->nsrc, forceRoutable); return -1; } /* Set all nodes that are NOT nsrc to an unused net number */ for (node = iroute->net->netnodes; node; node = node->next) { if (node != iroute->nsrc) { disable_node_nets(node); } } set_powerbus_to_net(iroute->nsrc->netnum); } } if (!result) { // Remove nodes of the net from Nodeinfo.nodeloc so that they will not be // used for crossover costing of future routes. remove_tap_blocks(iroute->net->netnum); free_glist(iroute); return 0; } // Generate a search area mask representing the "likely best route". if ((iroute->do_pwrbus == FALSE) && (maskMode == MASK_AUTO)) { if (stage == 0) createMask(iroute->net, MASK_SMALL, (u_char)Numpasses); else createMask(iroute->net, MASK_LARGE, (u_char)Numpasses); } else if ((iroute->do_pwrbus == TRUE) || (maskMode == MASK_NONE)) fillMask((u_char)0); else if (maskMode == MASK_BBOX) createBboxMask(iroute->net, (u_char)Numpasses); else createMask(iroute->net, maskMode, (u_char)Numpasses); // Heuristic: Set the initial cost beyond which we stop searching. // This value is twice the cost of a direct route across the // maximum extent of the source to target, divided by the square // root of the number of nodes in the net. We purposely set this // value low. It has a severe impact on the total run time of the // algorithm. If the initial max cost is so low that no route can // be found, it will be doubled on each pass. if (iroute->do_pwrbus) iroute->maxcost = 20; // Maybe make this SegCost * row height? else { iroute->maxcost = 1 + 2 * MAX((iroute->bbox.x2 - iroute->bbox.x1), (iroute->bbox.y2 - iroute->bbox.y1)) * SegCost + (int)stage * ConflictCost; iroute->maxcost /= (iroute->nsrc->numnodes - 1); } netnum = iroute->net->netnum; iroute->nsrctap = iroute->nsrc->taps; if (iroute->nsrctap == NULL) iroute->nsrctap = iroute->nsrc->extend; if (iroute->nsrctap == NULL) { unable_to_route(iroute->net->netname, iroute->nsrc, 0); return -1; } if (Verbose > 2) { Fprintf(stdout, "Source node @ %gum %gum layer=%d grid=(%d %d)\n", iroute->nsrctap->x, iroute->nsrctap->y, iroute->nsrctap->layer, iroute->nsrctap->gridx, iroute->nsrctap->gridy); } if (Verbose > 1) { Fprintf(stdout, "netname = %s, route number %d\n", iroute->net->netname, TotalRoutes ); Flush(stdout); } // Successful setup, although if nodes were marked unroutable, // this information is passed back; routing will proceed for // all routable nodes and the net will be then marked as // abandoned. return (unroutable + 1); } /*--------------------------------------------------------------*/ /* route_segs - detailed route from node to node using onestep */ /* method */ /* */ /* ARGS: ROUTE, ready to add segments to do route */ /* RETURNS: NULL if failed, manhattan distance if success */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Fri Aug 8 */ /*--------------------------------------------------------------*/ int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug) { POINT gpoint, gunproc, newpt; int i, o; int pass, maskpass; u_int forbid; GRIDP best, curpt; int rval; u_char first = TRUE; u_char check_order[6]; u_char max_reached; u_char conflict; u_char predecessor; PROUTE *Pr; best.cost = MAXRT; best.x = 0; best.y = 0; best.lay = 0; gunproc = (POINT)NULL; maskpass = 0; for (pass = 0; pass < Numpasses; pass++) { max_reached = FALSE; if (!first && (Verbose > 2)) { Fprintf(stdout, "\n"); first = TRUE; } if (Verbose > 2) { Fprintf(stdout, "Pass %d", pass + 1); Fprintf(stdout, " (maxcost is %d)\n", iroute->maxcost); } while (TRUE) { // Check priority stack and move down if 1st priorty is empty while (iroute->glist[0] == NULL) { for (i = 0; i < 5; i++) iroute->glist[i] = iroute->glist[i + 1]; iroute->glist[5] = NULL; if ((iroute->glist[0] == NULL) && (iroute->glist[1] == NULL) && (iroute->glist[2] == NULL) && (iroute->glist[3] == NULL) && (iroute->glist[4] == NULL)) break; } gpoint = iroute->glist[0]; if (gpoint == NULL) break; iroute->glist[0] = gpoint->next; // Stop-gap: Needs to be investigated. Occasional gpoint has // large (random?) value for y1. Suggests a memory leak. Only // seen occurring during doantennaroute(). Check using valgrind. if ((gpoint->x1 < 0) || (gpoint->y1 < 0) || (gpoint->x1 > NumChannelsX) || (gpoint->y1 > NumChannelsY)) { Fprintf(stderr, "Internal memory error!\n"); freePOINT(gpoint); continue; } curpt.x = gpoint->x1; curpt.y = gpoint->y1; curpt.lay = gpoint->layer; if (graphdebug) highlight(curpt.x, curpt.y); Pr = &OBS2VAL(curpt.x, curpt.y, curpt.lay); // ignore grid positions that have already been processed if (Pr->flags & PR_PROCESSED) { Pr->flags &= ~PR_ON_STACK; freePOINT(gpoint); continue; } if (Pr->flags & PR_COST) curpt.cost = Pr->prdata.cost; // Route points, including target else curpt.cost = 0; // For source tap points // if the grid position is the destination, save the position and // cost if minimum. if (Pr->flags & PR_TARGET) { if (curpt.cost < best.cost) { if (first) { if (Verbose > 2) Fprintf(stdout, "Found a route of cost "); first = FALSE; } else if (Verbose > 2) { Fprintf(stdout, "|"); Fprintf(stdout, "%d", curpt.cost); Flush(stdout); } // This position may be on a route, not at a terminal, so // record it. best.x = curpt.x; best.y = curpt.y; best.lay = curpt.lay; best.cost = curpt.cost; // If a complete route has been found, then there's no point // in searching paths with a greater cost than this one. if (best.cost < iroute->maxcost) iroute->maxcost = best.cost; } // Don't continue processing from the target Pr->flags |= PR_PROCESSED; Pr->flags &= ~PR_ON_STACK; freePOINT(gpoint); continue; } if (curpt.cost < MAXRT) { // Severely limit the search space by not processing anything that // is not under the current route mask, which identifies a narrow // "best route" solution. if (RMASK(curpt.x, curpt.y) > (u_char)maskpass) { gpoint->next = gunproc; gunproc = gpoint; continue; } // Quick check: Limit maximum cost to limit search space // Move the point onto the "unprocessed" stack and we'll pick up // from this point on the next pass, if needed. if (curpt.cost > iroute->maxcost) { max_reached = TRUE; gpoint->next = gunproc; gunproc = gpoint; continue; } } Pr->flags &= ~PR_ON_STACK; freePOINT(gpoint); // check east/west/north/south, and bottom to top // 1st optimization: Direction of route on current layer is preferred. o = LefGetRouteOrientation(curpt.lay); forbid = OBSVAL(curpt.x, curpt.y, curpt.lay) & BLOCKED_MASK; // To reach otherwise unreachable taps, allow searching on blocked // paths but with a high cost. conflict = (forceRoutable) ? PR_CONFLICT : PR_NO_EVAL; if (o == 1) { // horizontal routes---check EAST and WEST first check_order[0] = EAST | ((forbid & BLOCKED_E) ? conflict : 0); check_order[1] = WEST | ((forbid & BLOCKED_W) ? conflict : 0); check_order[2] = UP | ((forbid & BLOCKED_U) ? conflict : 0); check_order[3] = DOWN | ((forbid & BLOCKED_D) ? conflict : 0); check_order[4] = NORTH | ((forbid & BLOCKED_N) ? conflict : 0); check_order[5] = SOUTH | ((forbid & BLOCKED_S) ? conflict : 0); } else { // vertical routes---check NORTH and SOUTH first check_order[0] = NORTH | ((forbid & BLOCKED_N) ? conflict : 0); check_order[1] = SOUTH | ((forbid & BLOCKED_S) ? conflict : 0); check_order[2] = UP | ((forbid & BLOCKED_U) ? conflict : 0); check_order[3] = DOWN | ((forbid & BLOCKED_D) ? conflict : 0); check_order[4] = EAST | ((forbid & BLOCKED_E) ? conflict : 0); check_order[5] = WEST | ((forbid & BLOCKED_W) ? conflict : 0); } // Check order is from 0 (1st priority) to 5 (last priority). However, this // is a stack system, so the last one placed on the stack is the first to be // pulled and processed. Therefore we evaluate and drop positions to check // on the stack in reverse order (5 to 0). for (i = 5; i >= 0; i--) { predecessor = 0; switch (check_order[i]) { case EAST | PR_CONFLICT: predecessor = PR_CONFLICT; case EAST: predecessor |= PR_PRED_W; if ((curpt.x + 1) < NumChannelsX) { if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) { gpoint->next = iroute->glist[i]; iroute->glist[i] = gpoint; } } break; case WEST | PR_CONFLICT: predecessor = PR_CONFLICT; case WEST: predecessor |= PR_PRED_E; if ((curpt.x - 1) >= 0) { if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) { gpoint->next = iroute->glist[i]; iroute->glist[i] = gpoint; } } break; case SOUTH | PR_CONFLICT: predecessor = PR_CONFLICT; case SOUTH: predecessor |= PR_PRED_N; if ((curpt.y - 1) >= 0) { if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) { gpoint->next = iroute->glist[i]; iroute->glist[i] = gpoint; } } break; case NORTH | PR_CONFLICT: predecessor = PR_CONFLICT; case NORTH: predecessor |= PR_PRED_S; if ((curpt.y + 1) < NumChannelsY) { if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) { gpoint->next = iroute->glist[i]; iroute->glist[i] = gpoint; } } break; case DOWN | PR_CONFLICT: predecessor = PR_CONFLICT; case DOWN: predecessor |= PR_PRED_U; if (curpt.lay > 0) { if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) { gpoint->next = iroute->glist[i]; iroute->glist[i] = gpoint; } } break; case UP | PR_CONFLICT: predecessor = PR_CONFLICT; case UP: predecessor |= PR_PRED_D; if (curpt.lay < (Num_layers - 1)) { if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) { gpoint->next = iroute->glist[i]; iroute->glist[i] = gpoint; } } break; } } // Mark this node as processed Pr->flags |= PR_PROCESSED; } // while stack is not empty free_glist(iroute); // If we found a route, save it and return if (best.cost <= iroute->maxcost) { curpt.x = best.x; curpt.y = best.y; curpt.lay = best.lay; if ((rval = commit_proute(iroute->rt, &curpt, stage)) != 1) break; if (Verbose > 2) { Fprintf(stdout, "\nCommit to a route of cost %d\n", best.cost); Fprintf(stdout, "Between positions (%d %d) and (%d %d)\n", best.x, best.y, curpt.x, curpt.y); } route_set_connections(iroute->net, iroute->rt); goto done; /* route success */ } // Continue loop to next pass if any positions were ignored due to // masking or due to exceeding maxcost. // If the cost of the route exceeded maxcost at one or more locations, // then increase maximum cost for next pass. if (max_reached == TRUE) { iroute->maxcost <<= 1; // Cost overflow; we're probably completely hosed long before this. if (iroute->maxcost > MAXRT) break; } else maskpass++; // Increase the mask size if (gunproc == NULL) break; // route failure not due to limiting // search to maxcost or to masking // Regenerate the stack of unprocessed nodes iroute->glist[0] = gunproc; gunproc = NULL; } // pass if (!first && (Verbose > 2)) { Fprintf(stdout, "\n"); Flush(stdout); } if (Verbose > 1) { Fprintf(stderr, "Fell through %d passes\n", pass); } if (!iroute->do_pwrbus && (Verbose > 2)) { Fprintf(stderr, "(%g,%g) net=%s\n", iroute->nsrctap->x, iroute->nsrctap->y, iroute->net->netname); } rval = -1; done: // Regenerate the stack of unprocessed nodes if (gunproc != NULL) iroute->glist[0] = gunproc; return rval; } /* route_segs() */ /*--------------------------------------------------------------*/ /* createemptyroute - begin a ROUTE structure */ /* */ /* ARGS: a nodes */ /* RETURNS: ROUTE calloc'd and ready to begin */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Fri Aug 8 */ /*--------------------------------------------------------------*/ ROUTE createemptyroute(void) { ROUTE rt; rt = (ROUTE)calloc(1, sizeof(struct route_)); rt->netnum = 0; rt->segments = (SEG)NULL; rt->flags = (u_char)0; rt->next = (ROUTE)NULL; rt->start.route = (ROUTE)NULL; rt->end.route = (ROUTE)NULL; return rt; } /* createemptyroute(void) */ /*--------------------------------------------------------------*/ /* helpmessage - tell user how to use the program */ /* */ /* ARGS: none. */ /* RETURNS: nothing. */ /* SIDE EFFECTS: */ /* */ /* NOTES: */ /* 1) "qrouter -v0 -h" prints only the version number and exits */ /* 2) Tcl-Tk based version adds ".T" to the end to alert tools */ /* attempting to query the capabilities of qrouter of the */ /* availability of the scripting. */ /* */ /*--------------------------------------------------------------*/ static void helpmessage(void) { if (Verbose > 0) { Fprintf(stdout, "qrouter - maze router by Tim Edwards\n\n"); Fprintf(stdout, "usage: qrouter [-switches] design_name\n\n"); Fprintf(stdout, "switches:\n"); Fprintf(stdout, "\t-c \t\t\tConfiguration file name if not route.cfg.\n"); Fprintf(stdout, "\t-d \t\t\tGenerate delay information output.\n"); Fprintf(stdout, "\t-v \t\t\tVerbose output level.\n"); Fprintf(stdout, "\t-i \t\t\tPrint route names and pitches and exit.\n"); Fprintf(stdout, "\t-p \t\t\tSpecify global power bus name.\n"); Fprintf(stdout, "\t-g \t\t\tSpecify global ground bus name.\n"); Fprintf(stdout, "\t-r \t\t\tForce output resolution scale.\n"); Fprintf(stdout, "\t-f \t\t\tForce all pins to be routable.\n"); Fprintf(stdout, "\t-e \t\t\tLevel of effort to keep trying.\n"); Fprintf(stdout, "\n"); } #ifdef TCL_QROUTER Fprintf(stdout, "%s.%s.T\n", VERSION, REVISION); #else Fprintf(stdout, "%s.%s\n", VERSION, REVISION); #endif } /* helpmessage() */ /* end of qrouter.c */ qrouter-1.4.88/qrouter.h0000644000175000017510000004160414473033744014534 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* qrouter.h -- general purpose autorouter */ /*--------------------------------------------------------------*/ /* Written by Steve Beccue, 2003 */ /* Modified by Tim Edwards 2011-2013 */ /*--------------------------------------------------------------*/ #ifndef QROUTER_H #define OGRID(x, y) ((int)((x) + ((y) * NumChannelsX))) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define ABSDIFF(x, y) (((x) > (y)) ? ((x) - (y)) : ((y) - (x))) #define EPS 1e-4 // For handling round-off error; value // is in um (so 1e-4 = 0.1nm), should be // smaller than any feature size. // For handling round-off error on signed values. REPS(x) is x + EPS when // x is positive, and x - EPS when x is negative. #define REPS(x) (((x) < 0) ? ((x) - EPS) : ((x) + EPS)) #define TRUE 1 #define FALSE 0 #ifndef _SYS_TYPES_H #ifndef u_char typedef unsigned char u_char; #endif #ifndef u_short typedef unsigned short u_short; #endif #ifndef u_int typedef unsigned int u_int; #endif #ifndef u_long typedef unsigned long u_long; #endif #endif /* _SYS_TYPES_H */ /* Compare functions aren't defined in the Mac's standard library */ #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) typedef int (*__compar_fn_t)(const void*, const void*); #endif /* Maximum number of route layers */ #define MAX_LAYERS 12 /* Maximum number of all defined layers. Since masterslice and */ /* overlap types are ignored, this just includes all the cuts. */ #define MAX_TYPES (MAX_LAYERS * 2 - 1) /* Cell name (and other names) max length */ #define MAX_NAME_LEN 1024 /* Max reasonable line length */ #define MAX_LINE_LEN 2048 /* Default configuration filename */ #define CONFIGFILENAME "route.cfg" // define possible gate orientations #define MNONE 0 #define MX 1 // flipped in X #define MY 2 // flipped in Y #define R90 4 // rotated clockwise 90 degrees // define search directions #define NORTH (u_char)1 #define SOUTH (u_char)2 #define EAST (u_char)3 #define WEST (u_char)4 #define UP (u_char)5 #define DOWN (u_char)6 // define types of via checkerboard patterns #define VIA_PATTERN_NONE -1 #define VIA_PATTERN_NORMAL 0 #define VIA_PATTERN_INVERT 1 // linked list structure for holding a list of char * strings typedef struct linkedstring_ *LinkedStringPtr; typedef struct linkedstring_ { char *name; LinkedStringPtr next; } LinkedString; // structure holding input and output scalefactors typedef struct scalerec_ { int iscale; int mscale; double oscale; } ScaleRec; // structure to hold two offset values, one for x offset, one for y offset typedef struct obsinforec_ { float xoffset; float yoffset; } ObsInfoRec; // define a structure containing x, y, and layer typedef struct gridp_ GRIDP; struct gridp_ { int x; int y; int lay; u_int cost; }; typedef struct proute_ PROUTE; struct proute_ { // partial route u_short flags; // values PR_PROCESSED and PR_CONFLICT, and others union { u_int cost; // cost of route coming from predecessor u_int net; // net number at route point } prdata; }; // Bit values for "flags" in PROUTE #define PR_PRED_DMASK 0x007 // Mask for directional bits #define PR_PRED_NONE 0x000 // This node does not have a predecessor #define PR_PRED_N 0x001 // Predecessor is north #define PR_PRED_S 0x002 // Predecessor is south #define PR_PRED_E 0x003 // Predecessor is east #define PR_PRED_W 0x004 // Predecessor is west #define PR_PRED_U 0x005 // Predecessor is up #define PR_PRED_D 0x006 // Predecessor is down #define PR_PROCESSED 0x008 // Tag to avoid visiting more than once #define PR_NO_EVAL 0x008 // Used only for making calls to eval_pt() #define PR_CONFLICT 0x010 // Two nets collide here during stage 2 #define PR_SOURCE 0x020 // This is a source node #define PR_TARGET 0x040 // This is a target node #define PR_COST 0x080 // if 1, use prdata.cost, not prdata.net #define PR_ON_STACK 0x100 // if 1, position has been recorded for // pending evalutaion // Linked string list typedef struct string_ *STRING; struct string_ { STRING next; char *name; }; /* Path segment information */ #define ST_WIRE 0x01 #define ST_VIA 0x02 #define ST_OFFSET_START 0x04 /* (x1, y1) is offset from grid */ #define ST_OFFSET_END 0x08 /* (x2, y2) is offset from grid */ #define ST_SPECIAL 0x10 /* wide metal (special net) */ #define ST_MINMETAL 0x20 /* segment for min metal area */ typedef struct seg_ *SEG; struct seg_ { SEG next; int layer; int x1, y1, x2, y2; u_char segtype; }; /* DSEG is like a SEG, but coordinates are in microns (therefore type double) */ /* Used for gate node and obstruction positions. */ typedef struct dseg_ *DSEG; struct dseg_ { DSEG next; int layer; double x1, y1, x2, y2; }; /* POINT is an integer point in three dimensions (layer giving the */ /* vertical dimension). */ typedef struct point_ *POINT; struct point_ { POINT next; int layer; int x1, y1; }; /* DPOINT is a point location with coordinates given *both* as an */ /* integer (for the grid-based routing) and as a physical dimension */ /* (microns). */ typedef struct dpoint_ *DPOINT; struct dpoint_ { DPOINT next; int layer; double x, y; int gridx, gridy; }; typedef struct route_ *ROUTE; typedef struct node_ *NODE; struct route_ { ROUTE next; int netnum; SEG segments; union { ROUTE route; NODE node; } start; union { ROUTE route; NODE node; } end; u_char flags; // See below for flags }; /* Definitions for flags in struct route_ */ #define RT_OUTPUT 0x01 // Route has been output #define RT_STUB 0x02 // Route has at least one stub route #define RT_START_NODE 0x04 // Route starts on a node #define RT_END_NODE 0x08 // Route ends on a node #define RT_VISITED 0x10 // Flag for recursive search #define RT_RIP 0x20 // Flag for route rip-up #define RT_CHECK 0x40 // Route from DEF file needs checking /* Structure used to hold nodes, saved nodes, and stub/offset info */ typedef struct nodeinfo_ *NODEINFO; struct nodeinfo_ { NODE nodesav; NODE nodeloc; float stub; // Stub route to node float offset; // Tap offset u_char flags; }; /* Definitions for flags in stuct nodeinfo_ */ #define NI_STUB_NS 0x01 // Stub route north(+)/south(-) #define NI_STUB_EW 0x02 // Stub route east(+)/west(-) #define NI_STUB_MASK 0x03 // Stub route mask (N/S + E/W) #define NI_OFFSET_NS 0x04 // Tap offset north(+)/south(-) #define NI_OFFSET_EW 0x08 // Tap offset east(+)/west(-) #define NI_OFFSET_MASK 0x0c // Tap offset mask (N/S + E/W) #define NI_NO_VIAX 0x10 // Via in ViaX array is prohibited #define NI_NO_VIAY 0x20 // Via in ViaY array is prohibited #define NI_VIA_X 0x40 // Placed via is oriented horizontally #define NI_VIA_Y 0x80 // Placed via is oriented vertically struct node_ { NODE next; int nodenum; // node ordering within its net DPOINT taps; // point position for node taps DPOINT extend; // point position within halo of the tap char *netname; // name of net this node belongs to u_char numtaps; // number of actual reachable taps int netnum; // number of net this node belongs to int numnodes; // number of nodes on this net int branchx; // position of the node branch in x int branchy; // position of the node branch in y }; // these are instances of gates in the netlist. The description of a // given gate (the macro) is held in GateInfo. The same structure is // used for both the macro and the instance records. typedef struct gate_ *GATE; struct gate_ { GATE next; char *gatename; // Name of instance GATE gatetype; // Pointer to macro record int nodes; // number of nodes on this gate char **node; // names of the pins on this gate int *netnum; // net number connected to each pin NODE *noderec; // node record for each pin float *area; // gate area for each pin u_char *direction; // port direction (input, output, etc.) DSEG *taps; // list of gate node locations and layers DSEG obs; // list of obstructions in gate double width, height; double placedX; double placedY; int orient; }; // 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; }; // Structure for a network to be routed typedef struct net_ *NET; typedef struct netlist_ *NETLIST; struct net_ { int netnum; // a unique number for this net char *netname; NODE netnodes; // list of nodes connected to the net int numnodes; // number of nodes connected to the net u_char flags; // flags for this net (see below) int netorder; // to be assigned by route strategy (critical // nets first, then order by number of nodes). int xmin, ymin; // Bounding box lower left corner int xmax, ymax; // Bounding box upper right corner int trunkx; // X position of the net's trunk line (see flags) int trunky; // Y position of the net's trunk line (see flags) NETLIST noripup; // list of nets that have been ripped up to // route this net. This will not be allowed // a second time, to avoid looping. ROUTE routes; // routes for this net }; // Flags used by NET "flags" record #define NET_PENDING 1 // pending being placed on "abandoned" list #define NET_CRITICAL 2 // net is in CriticalNet list #define NET_IGNORED 4 // net is ignored by router #define NET_STUB 8 // Net has at least one stub #define NET_VERTICAL_TRUNK 16 // Trunk line is (preferred) vertical // List of nets, used to maintain a list of failed routes struct netlist_ { NETLIST next; NET net; }; // A structure to hold information about source and target nets for // a route, to be passed between the route setup and execution stages struct routeinfo_ { NET net; ROUTE rt; POINT glist[6]; /* Lists of points by priority 0 to 5 */ NODE nsrc; DPOINT nsrctap; int maxcost; u_char do_pwrbus; int pwrbus_src; struct seg_ bbox; }; #define MAXRT 10000000 // "Infinite" route cost // The following values are added to the Obs[] structure for unobstructed // route positions close to a terminal, but not close enough to connect // directly. They describe which direction to go to reach the terminal. // The Stub[] vector indicates the distance needed to reach the terminal. // The OFFSET_TAP flag marks a position that is inside a terminal but // which needs to be adjusted in one direction to avoid a close obstruction. // The Stub[] vector indicates the distance needed to avoid the obstruction. // // The maximum number of nets must not overrun the area used by flags, so // the maximum number of nets is 0x3fffff, or 4,194,303 nets #define OFFSET_TAP ((u_int)0x80000000) // tap position needs to be offset #define STUBROUTE ((u_int)0x40000000) // route stub to reach terminal #define PINOBSTRUCTMASK ((u_int)0xc0000000) // either offset tap or stub route #define NO_NET ((u_int)0x20000000) // indicates a non-routable obstruction #define ROUTED_NET ((u_int)0x10000000) // indicates position occupied by a routed #define BLOCKED_N ((u_int)0x08000000) // grid point cannot be routed from the N #define BLOCKED_S ((u_int)0x04000000) // grid point cannot be routed from the S #define BLOCKED_E ((u_int)0x02000000) // grid point cannot be routed from the E #define BLOCKED_W ((u_int)0x01000000) // grid point cannot be routed from the W #define BLOCKED_U ((u_int)0x00800000) // grid point cannot be routed from top #define BLOCKED_D ((u_int)0x00400000) // grid point cannot be routed from bottom #define BLOCKED_MASK ((u_int)0x0fc00000) #define OBSTRUCT_MASK ((u_int)0x0000000f) // with NO_NET, directional obstruction #define OBSTRUCT_N ((u_int)0x00000008) // Tells where the obstruction is #define OBSTRUCT_S ((u_int)0x00000004) // relative to the grid point. Nodeinfo #define OBSTRUCT_E ((u_int)0x00000002) // offset contains distance to grid point #define OBSTRUCT_W ((u_int)0x00000001) #define MAX_NETNUMS ((u_int)0x003fffff) // Maximum net number #define NETNUM_MASK ((u_int)0x203fffff) // Mask for the net number field // (includes NO_NET) #define ROUTED_NET_MASK ((u_int)0x303fffff) // Mask for the net number field // (includes NO_NET and ROUTED_NET) #define DRC_BLOCKAGE (NO_NET | ROUTED_NET) // Special case // Map and draw modes #define MAP_NONE 0x0 // No map (blank background) #define MAP_OBSTRUCT 0x1 // Make a map of obstructions and pins #define MAP_CONGEST 0x2 // Make a map of congestion #define MAP_ESTIMATE 0x3 // Make a map of estimated congestion #define MAP_MASK 0x3 #define DRAW_NONE 0x0 // Draw only the background map #define DRAW_ROUTES 0x4 // Draw routes on top of background map #define DRAW_UNROUTED 0x8 // Draw unrouted nets on top of background map #define DRAW_MASK 0xc // Mask types (values other than 255 are interpreted as "slack" value) #define MASK_MINIMUM (u_char)0 // No slack #define MASK_SMALL (u_char)1 // Slack of +/-1 #define MASK_MEDIUM (u_char)2 // Slack of +/-2 #define MASK_LARGE (u_char)4 // Slack of +/-4 #define MASK_AUTO (u_char)253 // Choose best mask type #define MASK_BBOX (u_char)254 // Mask is simple bounding box #define MASK_NONE (u_char)255 // No mask used // Definitions of bits in needblock #define ROUTEBLOCKX (u_char)1 // Block adjacent routes in X #define ROUTEBLOCKY (u_char)2 // Block adjacent routes in Y #define VIABLOCKX (u_char)4 // Block adjacent vias in X #define VIABLOCKY (u_char)8 // Block adjacent vias in Y // Numnets + MIN_NET_NUMBER is guaranteed to be greater than the highest // number assigned to a net. #define MAXNETNUM (Numnets + MIN_NET_NUMBER) /* Global variables */ extern STRING DontRoute; extern STRING CriticalNet; extern NET CurNet; extern NETLIST FailedNets; // nets that have failed the first pass extern char *DEFfilename; extern char *delayfilename; extern ScaleRec Scales; extern DPOINT testpoint; // for debugging routing problems extern GATE GateInfo; // standard cell macro information extern GATE PinMacro; // macro definition for a pin extern GATE Nlgates; extern NET *Nlnets; extern u_char *RMask; extern u_int *Obs[MAX_LAYERS]; // obstructions by layer, y, x extern PROUTE *Obs2[MAX_LAYERS]; // working copy of Obs extern ObsInfoRec *Obsinfo[MAX_LAYERS]; // temporary detailed obstruction info extern NODEINFO *Nodeinfo[MAX_LAYERS]; // stub route distances to pins and // pointers to node structures. #define NODEIPTR(x, y, l) (Nodeinfo[l][OGRID(x, y)]) #define OBSINFO(x, y, l) (Obsinfo[l][OGRID(x, y)]) #define OBSVAL(x, y, l) (Obs[l][OGRID(x, y)]) #define OBS2VAL(x, y, l) (Obs2[l][OGRID(x, y)]) #define RMASK(x, y) (RMask[OGRID(x, y)]) #define CONGEST(x, y) (Congestion[OGRID(x, y)]) extern DSEG UserObs; // user-defined obstruction layers extern u_char needblock[MAX_LAYERS]; extern int Numnets; extern int Pinlayers; // Number of layers containing pin info. extern u_char Verbose; extern u_char forceRoutable; extern u_char maskMode; extern u_char mapType; extern u_char ripLimit; extern u_char unblockAll; extern char *vddnet; extern char *gndnet; extern char *antenna_cell; /* Tcl output to console handling */ #ifdef TCL_QROUTER #define Fprintf tcl_printf #define Flush tcl_stdflush #define Vprintf tcl_vprintf #else #define Fprintf fprintf #define Flush fflush #define Vprintf vfprintf #endif /* Function prototypes */ void update_mscale(int mscale); int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug); ROUTE createemptyroute(void); int set_num_channels(void); int allocate_obs_array(void); int countlist(NETLIST net); int runqrouter(int argc, char *argv[]); void remove_failed(); void apply_drc_blocks(int, double, double); void remove_top_route(NET net); char *get_annotate_info(NET net, char **pinptr); void free_glist(struct routeinfo_ *iroute); #ifdef TCL_QROUTER void find_free_antenna_taps(char *antennacell); #endif void resolve_antenna(char *antennacell, u_char do_fix); void createMask(NET net, u_char slack, u_char halo); void createBboxMask(NET net, u_char halo); int read_def(char *filename); #ifdef TCL_QROUTER int write_delays(char *filename); int write_spef(char *filename); #endif int dofirststage(u_char graphdebug, int debug_netnum); int dosecondstage(u_char graphdebug, u_char singlestep, u_char onlybreak, u_int effort); int dothirdstage(u_char graphdebug, int debug_netnum, u_int effort); int doroute(NET net, u_char stage, u_char graphdebug); NET getnettoroute(int order); int route_net_ripup(NET net, u_char graphdebug, u_char onlybreak); #ifdef TCL_QROUTER void tcl_printf(FILE *, const char *, ...); void tcl_stdflush(FILE *); void tcl_vprintf(FILE *, const char *, va_list); #endif #define QROUTER_H #endif /* end of qrouter.h */ qrouter-1.4.88/VERSION0000644000175000017510000000000714677160544013727 0ustar nileshnilesh1.4.88 qrouter-1.4.88/delays.c0000644000175000017510000007331314677160544014316 0ustar nileshnilesh/*--------------------------------------------------------------*/ /* delays.c -- compute and write path delays from a routed */ /* network. */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, March 2017 */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include #include /* This entire file is dependent on the Tcl/Tk version */ #ifdef TCL_QROUTER #include #include "qrouter.h" #include "qconfig.h" #include "node.h" #include "lef.h" #include "def.h" /*--------------------------------------------------------------*/ /* Find a node in the node list. */ /*--------------------------------------------------------------*/ static GATE FindGateNode(Tcl_HashTable *NodeTable, NODE node, int *ridx) { GATENODE gn; GATE g; Tcl_HashEntry *entry; entry = Tcl_FindHashEntry(NodeTable, (char *)node); if (entry) { gn = (GATENODE)Tcl_GetHashValue(entry); *ridx = gn->idx; return gn->gate; } return NULL; } /*--------------------------------------------------------------*/ /* Structure to hold information about endpoints of a route. */ /*--------------------------------------------------------------*/ typedef struct _endpointinfo { u_char flags; /* flag bits (see below) */ ROUTE route; /* pointer to routed segments */ ROUTE orig; /* original pointer to routed segments */ int startx; /* values at segment start */ int starty; int startl; /* note: layer is exact, not base via layer */ NODE startnode; int endx; /* values at segment end */ int endy; int endl; NODE endnode; double res; /* total resistance of segment */ double cap; /* total capacitance of segment */ int *branching; /* list of downstream segments */ /* (last list item is -1) */ } endpointinfo; /* endpointinfo flag definitions */ #define EPT_VISITED 0x01 /* 1 if endpoint has been visited */ #define EPT_DRIVER 0x02 /* 1 if endpoint is a driver */ /* 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 */ static void walk_route(int, int, endpointinfo *, int, lefrcinfo *); /*--------------------------------------------------------------*/ /* Add route information to the endpoint record showing where */ /* a route continues downstream. */ /*--------------------------------------------------------------*/ static void add_route_to_endpoint(endpointinfo *eptinfo, int eidx, int didx) { int i; for (i = 0; i < 5; i++) { if (eptinfo[eidx].branching[i] == -1) { eptinfo[eidx].branching[i] = didx; if (i < 4) eptinfo[eidx].branching[i + 1] = -1; break; } } } /*--------------------------------------------------------------*/ /* Check for a route segment that is downstream of the current */ /* segment (walkseg), and if found, process it. */ /* "end" is 0 if checking downstream of the driver node. Every */ /* other check is from the end node of a route, and "end" is 1. */ /*--------------------------------------------------------------*/ static void check_downstream(SEG walkseg, endpointinfo *eptinfo, int eidx, int numroutes, lefrcinfo *lefrcvalues, u_char end) { int i; int startcompat, endcompat; NODE nodeptr; /* At given segment "walkseg", find all routes that connect and walk them */ for (i = 0; i < numroutes; i++) { if (eptinfo[i].flags & EPT_VISITED) continue; /* already visited */ /* Check wire/via layer compatibility */ if (walkseg->segtype & ST_WIRE) startcompat = (walkseg->layer == eptinfo[i].startl); else startcompat = (walkseg->layer == eptinfo[i].startl) || (walkseg->layer + 1 == eptinfo[i].startl); if (walkseg->segtype & ST_WIRE) endcompat = (walkseg->layer == eptinfo[i].endl); else endcompat = (walkseg->layer == eptinfo[i].endl) || (walkseg->layer + 1 == eptinfo[i].endl); if ((walkseg->x2 == eptinfo[i].startx) && (walkseg->y2 == eptinfo[i].starty) && startcompat) { /* Watch for short via routes that are compatible */ /* on both start and end---walk from the higher */ /* side. */ int reverse = 0; if ((eptinfo[i].startx == eptinfo[i].endx) && (eptinfo[i].starty == eptinfo[i].endy) && startcompat && endcompat) if (eptinfo[i].endl > eptinfo[i].startl) reverse = 1; /* Diagnostic */ /* Fprintf(stdout, "Connects to %d, %d, %d\n", eptinfo[i].startx, eptinfo[i].starty, eptinfo[i].startl); */ /* Recursive walk */ walk_route(i, reverse, eptinfo, numroutes, lefrcvalues); add_route_to_endpoint(eptinfo, eidx, i); } else if ((walkseg->x2 == eptinfo[i].endx) && (walkseg->y2 == eptinfo[i].endy) && endcompat) { /* Diagnostic */ /* 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 */ walk_route(i, 1, eptinfo, numroutes, lefrcvalues); add_route_to_endpoint(eptinfo, eidx, i); } } /* If there is a node at the segment being checked, 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. */ nodeptr = (end == 0) ? eptinfo[eidx].startnode : eptinfo[eidx].endnode; if (nodeptr != NULL) { for (i = 0; i < numroutes; i++) { if (eptinfo[i].flags & EPT_VISITED) continue; /* already visited */ if (eptinfo[i].startnode == nodeptr) { walk_route(i, 0, eptinfo, numroutes, lefrcvalues); add_route_to_endpoint(eptinfo, eidx, i); } else if (eptinfo[i].endnode == nodeptr) { walk_route(i, 1, eptinfo, numroutes, lefrcvalues); add_route_to_endpoint(eptinfo, eidx, i); } } } } /*--------------------------------------------------------------*/ /* Recursively walk a route to all endpoints, computing the */ /* path R and C values along the way. */ /* */ /* eidx is an index into eptinfo for the current route */ /* 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 */ /*--------------------------------------------------------------*/ static void walk_route(int eidx, int driverend, endpointinfo *eptinfo, int numroutes, lefrcinfo *lefrcvalues) { SEG firstseg, lastseg; SEG walkseg, newseg, testseg; SEG seg, nseg; GATE g; NODE node; int i; ROUTE rt; eptinfo[eidx].flags |= EPT_VISITED; /* Always walk the segment from upstream to downstream. */ /* If the upstream side is the end of the segment linked */ /* list (driverend == 1), then replace the route with a */ /* reversed copy. */ rt = eptinfo[eidx].route; if (driverend == 1) { firstseg = NULL; /* Reverse the route */ 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; } /* Delete the original route and replace it */ for (seg = rt->segments; seg; ) { nseg = seg->next; free(seg); seg = nseg; } rt->segments = firstseg; /* Everything in eptinfo related to start and end needs */ /* to be swapped. */ node = eptinfo[eidx].startnode; eptinfo[eidx].startnode = eptinfo[eidx].endnode; eptinfo[eidx].endnode = node; i = eptinfo[eidx].startx; eptinfo[eidx].startx = eptinfo[eidx].endx; eptinfo[eidx].endx = i; i = eptinfo[eidx].starty; eptinfo[eidx].starty = eptinfo[eidx].endy; eptinfo[eidx].endy = i; i = eptinfo[eidx].startl; eptinfo[eidx].startl = eptinfo[eidx].endl; eptinfo[eidx].endl = i; } else firstseg = rt->segments; /* Check for downstream nodes from the first route point, but only */ /* if it is the driver. */ if (eptinfo[eidx].flags & EPT_DRIVER) check_downstream(firstseg, eptinfo, eidx, numroutes, lefrcvalues, (u_char)0); /* Walk the route segment and accumulate R and C */ eptinfo[eidx].res = 0.0; eptinfo[eidx].cap = 0.0; for (walkseg = firstseg; walkseg; walkseg = walkseg->next) { int rlength; /* Accumulate C and R */ if (walkseg->segtype & ST_VIA) { eptinfo[eidx].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); eptinfo[eidx].res += lefrcvalues[walkseg->layer].resy * rlength; eptinfo[eidx].cap += lefrcvalues[walkseg->layer].capy * rlength; } else { /* Horizontal route */ rlength = (walkseg->x2 > walkseg->x1) ? (walkseg->x2 - walkseg->x1 + 1) : (walkseg->x1 - walkseg->x2 + 1); eptinfo[eidx].res += lefrcvalues[walkseg->layer].resx * rlength; eptinfo[eidx].cap += lefrcvalues[walkseg->layer].capx * rlength; } if (walkseg->next == NULL) lastseg = walkseg; } /* Check for downstream nodes from the last route point */ check_downstream(lastseg, eptinfo, eidx, numroutes, lefrcvalues, (u_char)1); } /*--------------------------------------------------------------*/ /* Walk the sorted, directed routes and generate output. */ /*--------------------------------------------------------------*/ static void walk_route_output(endpointinfo *eptinfo, int eidx, Tcl_HashTable *NodeTable, FILE *delayFile) { int d, i; NODE node; GATE g; /* Output information about self */ fprintf(delayFile, "( %g %g ", eptinfo[eidx].res, eptinfo[eidx].cap); /* Count downstream nodes */ for (d = 0; d < 5; d++) if (eptinfo[eidx].branching[d] == -1) break; /* List of nodes and downstream routes follows */ node = eptinfo[eidx].endnode; if (node != NULL) { /* Look up the gate */ g = FindGateNode(NodeTable, node, &i); if (!strcmp(g->gatetype->node[i], "pin")) fprintf(delayFile, "PIN/%s ", g->gatename); else fprintf(delayFile, "%s/%s ", g->gatename, g->gatetype->node[i]); if (d > 0) fprintf(delayFile, ", "); } else if (d == 0) { /* This should not happen: No node, no route */ fprintf(delayFile, "ERROR "); } /* Output downstream nodes */ for (i = 0; i < d; i++) { walk_route_output(eptinfo, eptinfo[eidx].branching[i], NodeTable, delayFile); if (i < (d - 1)) fprintf(delayFile, ", "); } /* End record */ fprintf(delayFile, ") "); } /*--------------------------------------------------------------*/ /* Free data associated with each entry in the NodeTable hash. */ /*--------------------------------------------------------------*/ void FreeNodeTable(Tcl_HashTable *NodeTable) { Tcl_HashEntry *entry; Tcl_HashSearch hs; GATENODE gn; entry = Tcl_FirstHashEntry(NodeTable, &hs); while (entry != NULL) { gn = Tcl_GetHashValue(entry); if (gn != NULL) free(gn); entry = Tcl_NextHashEntry(&hs); } } /*--------------------------------------------------------------*/ /* 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; SEG seg, newseg, lastseg, nxseg; GATE g, drivergate; int i, j, n, new, driverend, testl; int drivernodeidx, driveridx; int nroute, numroutes; endpointinfo *eptinfo; lefrcinfo *lefrcvalues; 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; entry = Tcl_CreateHashEntry(&NodeTable, (char *)(*(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 / width) * respersq; lefrcvalues[i].resy = (PitchY / width) * respersq; lefrcvalues[i].capx = (PitchX * width) * areacap + (PitchX * edgecap); lefrcvalues[i].capy = (PitchY * width) * areacap + (PitchY * 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) || (net->netnum == ANTENNA_NET)) continue; /* Count number of net routes */ numroutes = 0; for (rt = net->routes; rt; rt = rt->next) numroutes++; if (numroutes == 0) continue; /* Ignore nets with no routes */ /* 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.) */ /* 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].orig = rt; eptinfo[nroute].flags = (u_char)0; eptinfo[nroute].branching = NULL; eptinfo[nroute].startnode = NULL; eptinfo[nroute].endnode = NULL; /* Segment start */ seg = rt->segments; if (seg != NULL) { eptinfo[nroute].startx = seg->x1; eptinfo[nroute].starty = seg->y1; eptinfo[nroute].startl = seg->layer; eptinfo[nroute].res = 0.0; eptinfo[nroute].cap = 0.0; /* If a via, check if direction is up or down */ if (seg->segtype & ST_VIA) { if (seg->next && (seg->next->layer <= seg->layer)) eptinfo[nroute].startl++; } } /* Segment end */ testl = eptinfo[nroute].startl; for (seg = rt->segments; seg && seg->next; seg = seg->next) testl = seg->layer; if (seg != NULL) { eptinfo[nroute].endx = seg->x2; eptinfo[nroute].endy = seg->y2; eptinfo[nroute].endl = seg->layer; /* If a via, check if direction is up or down */ if (seg->segtype & ST_VIA) { if (testl <= seg->layer) eptinfo[nroute].endl++; } } 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->segments = NULL; newroute->start.route = NULL; newroute->end.route = NULL; 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 R, C. */ j = 0; for (rt = droutes; rt; rt = rt->next) { ROUTE testroute; int startx, starty, startl; int endx, endy, endl; int brkx, brky, brkl, brki, startcompat, endcompat; int initial, final; int x1, y1, x2, y2; /* Check all segments (but not the endpoints) */ lastseg = NULL; for (seg = rt->segments; seg; lastseg = 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) && ((lastseg != rt->segments) || (!(rt->segments->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--; /* x1 == x2 here implies that the route is made of */ /* exactly two vias. To continue would be to miss */ /* the center point between the vias. This unique */ /* condition is type == ST_VIA, final == TRUE. */ } else { if (y1 > y2) y2++; else if (y1 < y2) y2--; else continue; /* shouldn't happen */ } } /* Compare against endpoints of all other routes */ brki = -1; for (i = 0; i < numroutes; i++) { if (eptinfo[i].route == rt) continue; testroute = eptinfo[i].orig; if ((!(testroute->flags & RT_START_NODE)) && (testroute->start.route == eptinfo[j].orig)) { /* Nothing */ } else if ((!(testroute->flags & RT_END_NODE)) && (testroute->end.route == eptinfo[j].orig)) { /* Nothing */ } else continue; /* Not a connected route */ /* Check for start/end points connecting on same layer */ startx = eptinfo[i].startx; starty = eptinfo[i].starty; startl = eptinfo[i].startl; endx = eptinfo[i].endx; endy = eptinfo[i].endy; endl = eptinfo[i].endl; /* Check various combinations of wire and via layers */ if (seg->segtype & ST_WIRE) { startcompat = (startl == seg->layer); endcompat = (endl == seg->layer); } else if (final) { /* Unique condition: route is two vias. Look */ /* only at the point between the vias. */ if (lastseg->layer < seg->layer) { startcompat = (startl == seg->layer); endcompat = (endl == seg->layer); } else { startcompat = (startl == seg->layer + 1); endcompat = (endl == seg->layer + 1); } } else { startcompat = (startl == seg->layer) || (startl == seg->layer + 1); endcompat = (endl == seg->layer) || (endl == seg->layer + 1); } if (x1 == x2) { if (startcompat && (startx == x1)) { if (y1 > y2) { if (starty >= y2 && starty <= y1) { brkx = startx; brky = starty; brkl = startl; y2 = brky; brki = i; } } else { if (starty >= y1 && starty <= y2) { brkx = startx; brky = starty; brkl = startl; y2 = brky; brki = i; } } } if (endcompat && (endx == x2)) { if (y1 > y2) { if (endy >= y2 && endy <= y1) { brkx = endx; brky = endy; brkl = endl; y2 = brky; brki = i; } } else { if (endy >= y1 && endy <= y2) { brkx = endx; brky = endy; brkl = endl; y2 = brky; brki = i; } } } } else if (y1 == y2) { if (startcompat && (starty == y1)) { if (x1 > x2) { if (startx >= x2 && startx <= x1) { brkx = startx; brky = starty; brkl = startl; x2 = brkx; brki = i; } } else { if (startx >= x1 && startx <= x2) { brkx = startx; brky = starty; brkl = startl; x2 = brkx; brki = i; } } } if (endcompat && (endy == y2)) { if (x1 > x2) { if (endx >= x2 && endx <= x1) { brkx = endx; brky = endy; brkl = endl; x2 = brkx; brki = i; } } else { if (endx >= x1 && endx <= x2) { brkx = endx; brky = endy; brkl = endl; x2 = brkx; brki = i; } } } } } if (brki >= 0) { /* Disable this endpoint so it is not checked again */ eptinfo[brki].endl = -2; /* Break route at this point */ /* If route type is a wire, then make a copy of the */ /* segment where the break occurs. If a via, then */ /* determine which side of the break the via goes */ /* to. */ newroute = (ROUTE)malloc(sizeof(struct route_)); if (seg->segtype & ST_WIRE) { 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; } else if (lastseg == NULL) { /* Via is the route before the break */ newroute->segments = seg->next; seg->next = NULL; } else if (lastseg->layer <= seg->layer) { if (brkl > seg->layer) { /* Via goes at the end of the route before the break */ newroute->segments = seg->next; seg->next = NULL; } else { /* Via goes at the start of the route after the break */ newroute->segments = seg; lastseg->next = NULL; } } else { /* (lastseg->layer > seg->layer) */ if (brkl > seg->layer) { /* Via goes at the start of the route after the break */ newroute->segments = seg; lastseg->next = NULL; } else { /* Via goes at the end of the route before the break */ newroute->segments = seg->next; seg->next = NULL; } } newroute->netnum = rt->netnum; newroute->flags = (u_char)0; newroute->next = rt->next; rt->next = newroute; newroute->start.route = NULL; newroute->end.route = NULL; /* Update eptinfo[j].route to point to new route */ eptinfo[j].route = newroute; /* Next loop ends list of segs and moves to next route */ /* which is still the same original route, so adjust j */ /* index so that it still refers to the correct */ /* eptinfo entry. */ j--; } } j++; } /* 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; if (seg == NULL) { eptinfo[nroute].route = NULL; eptinfo[nroute].startnode = NULL; eptinfo[nroute].endnode = NULL; eptinfo[nroute].branching = NULL; nroute++; continue; } eptinfo[nroute].startx = seg->x1; eptinfo[nroute].starty = seg->y1; eptinfo[nroute].startl = seg->layer; /* Check for via in down direction rather than the default up */ if ((seg->segtype & ST_VIA) && seg->next && seg->next->layer <= seg->layer) eptinfo[nroute].startl++; nodeptr = (seg->layer < Pinlayers) ? NODEIPTR(seg->x1, seg->y1, seg->layer) : NULL; eptinfo[nroute].startnode = nodeptr ? nodeptr->nodesav : NULL; /* In a 3D grid there can be at most 5 downstream branches */ /* from a single point. */ eptinfo[nroute].branching = (int *)malloc(5 * sizeof(int)); eptinfo[nroute].branching[0] = -1; eptinfo[nroute].res = 0.0; eptinfo[nroute].cap = 0.0; /* Look up node */ if (nodeptr && nodeptr->nodesav) { g = FindGateNode(&NodeTable, nodeptr->nodesav, &i); 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; /* Check for via in down direction rather than default up */ if (seg->segtype & ST_VIA) { if (lastseg && lastseg->layer <= seg->layer) eptinfo[nroute].endl++; else if (!lastseg && eptinfo[nroute].endl <= seg->layer) eptinfo[nroute].endl++; } nodeptr = (eptinfo[nroute].endl < Pinlayers) ? NODEIPTR(seg->x2, seg->y2, eptinfo[nroute].endl) : NULL; eptinfo[nroute].endnode = nodeptr ? nodeptr->nodesav : NULL; /* Look up node */ if (nodeptr && nodeptr->nodesav) { g = FindGateNode(&NodeTable, nodeptr->nodesav, &i); if (g && (g->gatetype->direction[i] == PORT_CLASS_OUTPUT)) { drivernodeidx = i; driveridx = nroute; drivergate = g; driverend = 1; } 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++; } /* Start with net driver node, start generating output */ if ((drivernodeidx != -1) && (driveridx != -1)) { eptinfo[driveridx].flags |= EPT_DRIVER; /* Diagnostic, for debugging */ /* 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]); */ if (!strcmp(drivergate->gatetype->node[drivernodeidx], "pin")) fprintf(delayFile, "%s 1 PIN/%s %d ", net->netname, drivergate->gatename, net->numnodes - 1); else fprintf(delayFile, "%s 1 %s/%s %d ", net->netname, drivergate->gatename, drivergate->gatetype->node[drivernodeidx], net->numnodes - 1); /* Walk the route and organize from driver to terminals and */ /* accumulate resistance and capacitance of each segment */ walk_route(driveridx, driverend, eptinfo, nroute, lefrcvalues); /* Diagnostic: There should be no unhandled segments if */ /* everything went right. */ for (i = 0; i < numroutes; i++) { if ((eptinfo[i].flags & EPT_VISITED) == (u_char)0) { Fprintf(stderr, "Route segment %d was not walked!\n", i); } } walk_route_output(eptinfo, driveridx, &NodeTable, delayFile); fprintf(delayFile, "\n"); /* End of net output */ } 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; } for (i = 0; i < nroute; i++) if (eptinfo[i].branching != NULL) free(eptinfo[i].branching); free(eptinfo); } fclose(delayFile); free(lefrcvalues); FreeNodeTable(&NodeTable); Tcl_DeleteHashTable(&NodeTable); return 0; } #endif /* TCL_QROUTER */ /* end of delays.c */