summaryrefslogtreecommitdiff
path: root/tclqrouter.c
diff options
context:
space:
mode:
Diffstat (limited to 'tclqrouter.c')
-rw-r--r--tclqrouter.c371
1 files changed, 369 insertions, 2 deletions
diff --git a/tclqrouter.c b/tclqrouter.c
index d06dcbb..d37cba3 100644
--- a/tclqrouter.c
+++ b/tclqrouter.c
@@ -11,6 +11,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
+#include <math.h> /* for round() */
#include <tk.h>
@@ -123,6 +124,9 @@ static int qrouter_layers(
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[]);
@@ -141,6 +145,15 @@ static int qrouter_print(
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[] =
{
@@ -161,12 +174,16 @@ static cmdstruct qrouter_commands[] =
{"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},
@@ -314,7 +331,7 @@ void tcl_stdflush(FILE *f)
char *stdptr = stdstr + 11;
Tcl_SaveResult(qrouterinterp, &state);
- strcpy(stdptr, (f == stderr) ? "err" : "out");
+ strncpy(stdptr, (f == stderr) ? "err" : "out", 3);
Tcl_Eval(qrouterinterp, stdstr);
Tcl_RestoreResult(qrouterinterp, &state);
}
@@ -620,6 +637,7 @@ qrouter_start(ClientData clientData, Tcl_Interp *interp,
argv[argc++] = strdup(Tcl_GetString(objv[i]));
}
+ init_config();
result = runqrouter(argc, argv);
if ((result == 0) && (batchmode == 0)) GUI_init(interp);
@@ -1602,7 +1620,7 @@ qrouter_readlef(ClientData clientData, Tcl_Interp *interp,
LEFfile = Tcl_GetString(objv[1]);
mscale = LefRead(LEFfile);
- if (Scales.mscale < mscale) Scales.mscale = mscale;
+ update_mscale(mscale);
for (i = 0; i < Num_layers; i++) {
@@ -2409,6 +2427,231 @@ qrouter_resolution(ClientData clientData, Tcl_Interp *interp,
}
/*------------------------------------------------------*/
+/* 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 <ix> <iy> <layer> [watch] */
+/* query position <dx> <dy> <layer> [watch] */
+/* query instance <instance> */
+/* query node <instance>/<pin> */
+/* query net <name> */
+/* */
+/* <layer> may be either a layer name or integer index. */
+/* <dx> and <dy> should be given in microns. <ix> and */
+/* <iy> 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 <x_microns> <y_microns> <layer> [watch]\n");
+ Fprintf(stderr, " query grid <gridx> <gridy> <layer> [watch]\n");
+ Fprintf(stderr, " query instance <inst_name>\n");
+ Fprintf(stderr, " query node <inst_name>/<pin_name>\n");
+ Fprintf(stderr, " query net <net_name>\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 */
@@ -2988,3 +3231,127 @@ qrouter_print(ClientData clientData, Tcl_Interp *interp,
}
/*------------------------------------------------------*/
+/* 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 [<value>] */
+/*------------------------------------------------------*/
+
+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 [<value>] */
+/*------------------------------------------------------*/
+
+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);
+}
+
+/*------------------------------------------------------*/