diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile.in | 10 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rwxr-xr-x | configure | 19 | ||||
-rw-r--r-- | configure.in | 17 | ||||
-rw-r--r-- | def.c | 22 | ||||
-rw-r--r-- | delays.c | 163 | ||||
-rw-r--r-- | graphics.c | 49 | ||||
-rw-r--r-- | lef.c | 344 | ||||
-rw-r--r-- | lef.h | 8 | ||||
-rw-r--r-- | main.c | 4 | ||||
-rw-r--r-- | mask.c | 25 | ||||
-rw-r--r-- | maze.c | 207 | ||||
-rw-r--r-- | maze.h | 8 | ||||
-rw-r--r-- | node.c | 340 | ||||
-rw-r--r-- | output.c | 73 | ||||
-rw-r--r-- | qconfig.c | 11 | ||||
-rw-r--r-- | qrouter.c | 182 | ||||
-rw-r--r-- | qrouter.h | 18 | ||||
-rw-r--r-- | qrouter.tcl.in | 51 | ||||
-rw-r--r-- | qrouterexec.c | 4 | ||||
-rw-r--r-- | qrouternullg.c | 1 | ||||
-rw-r--r-- | tclqrouter.c | 118 | ||||
-rw-r--r-- | tkSimple.c | 40 |
24 files changed, 1206 insertions, 511 deletions
@@ -4,6 +4,7 @@ config.status config.log Makefile qrouterexec +qrouternullg qrouter.sh qrouter.tcl *.o diff --git a/Makefile.in b/Makefile.in index cdb4c80..95ed4d4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,11 +6,13 @@ 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@ @@ -76,7 +78,7 @@ qrouter$(EXEEXT): $(OBJECTS) $(OBJECTS5) qrouter$(SHDLIB_EXT): $(OBJECTS) $(OBJECTS2) $(RM) qrouter$(SHDLIB_EXT) - $(CC) ${CFLAGS} ${SHLIB_CFLAGS} -o $@ \ + $(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 @@ -84,14 +86,14 @@ qrouter$(SHDLIB_EXT): $(OBJECTS) $(OBJECTS2) qrouterexec$(EXEEXT): $(OBJECTS3) $(RM) qrouterexec$(EXEEXT) $(CC) ${CFLAGS} ${CPPFLAGS} ${DEFS} ${EXTRA_DEFS} \ - ${SOURCES3} ${INC_SPECS} -o $@ ${LIB_SPECS} \ + ${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} \ + ${SOURCES4} ${INC_SPECS} -o $@ ${LIB_SPECS_NOSTUB} \ ${LD_RUN_PATH} ${LDFLAGS} ${LIBS} ${EXTRA_LIB_SPECS} -lm install-nointerp: @@ -142,5 +144,5 @@ veryclean: $(RM) qrouter.sh .c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) $(SHLIB_CFLAGS) $(DEFS) \ + $(CC) $(CFLAGS) $(CPPFLAGS) $(SHLIB_CFLAGS) $(DEFS) $(STUB_DEFS) \ $(EXTRA_DEFS) $(INC_SPECS) -c $< -o $@ @@ -1 +1 @@ -1.3.80 +1.3.103 @@ -631,9 +631,11 @@ 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 @@ -4088,6 +4090,7 @@ qrouter_with_tcl_libraries="" qrouter_with_tk_libraries="" usingTcl=1 +stub_defs="" # Check whether --with-tcl was given. @@ -5402,6 +5405,7 @@ if test $usingTcl ; then 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" @@ -5454,6 +5458,7 @@ esac # ----------------------------------------------------------------------- if test $usingTcl ; then + LIB_SPECS_NOSTUB="${LIB_SPECS}" # ----------------------------------------------------------------------- # @@ -5465,9 +5470,11 @@ if test $usingTcl ; then fi if test "${TK_LIB_DIR}" = "/usr/lib" -o \ "${TK_LIB_DIR}" = "/usr/lib64" ; then - LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" + LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} ${TK_LIB_SPEC}" + LIB_SPECS="${LIB_SPECS} ${TK_STUB_LIB_SPEC}" else - LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" + 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 @@ -5491,9 +5498,11 @@ if test $usingTcl ; then if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ "${TCL_LIB_DIR}" = "/usr/lib64" -o \ "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then - LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" + LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} ${TCL_LIB_SPEC}" + LIB_SPECS="${LIB_SPECS} ${TCL_STUB_LIB_SPEC}" else - LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" + 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 @@ -5621,6 +5630,8 @@ fi + + fi diff --git a/configure.in b/configure.in index 961bbe4..b9bd50f 100644 --- a/configure.in +++ b/configure.in @@ -187,6 +187,7 @@ qrouter_with_tcl_libraries="" qrouter_with_tk_libraries="" usingTcl=1 +stub_defs="" AC_ARG_WITH(tcl, [ --with-tcl=DIR Find tclConfig.sh in DIR], [ @@ -682,6 +683,7 @@ 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" @@ -729,6 +731,7 @@ esac # ----------------------------------------------------------------------- if test $usingTcl ; then + LIB_SPECS_NOSTUB="${LIB_SPECS}" # ----------------------------------------------------------------------- # @@ -740,9 +743,11 @@ if test $usingTcl ; then fi if test "${TK_LIB_DIR}" = "/usr/lib" -o \ "${TK_LIB_DIR}" = "/usr/lib64" ; then - LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" + LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} ${TK_LIB_SPEC}" + LIB_SPECS="${LIB_SPECS} ${TK_STUB_LIB_SPEC}" else - LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" + 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 @@ -766,9 +771,11 @@ if test $usingTcl ; then if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ "${TCL_LIB_DIR}" = "/usr/lib64" -o \ "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then - LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" + LIB_SPECS_NOSTUB="${LIB_SPECS_NOSTUB} ${TCL_LIB_SPEC}" + LIB_SPECS="${LIB_SPECS} ${TCL_STUB_LIB_SPEC}" else - LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" + 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 @@ -872,11 +879,13 @@ if test $usingTcl ; then 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) @@ -177,6 +177,12 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special) LefError("Unknown layer type \"%s\" for NEW route\n", token); continue; } + else if (routeLayer >= Num_layers) + { + LefError("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) @@ -262,7 +268,8 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special) LefError("Error: Via \"%s\" named but undefined.\n", token); paintLayer = routeLayer; } - if ((special == (char)0) && (paintLayer >= 0)) { + if ((special == (char)0) && (paintLayer >= 0) && + (paintLayer < Num_layers)) { newRoute = (SEG)malloc(sizeof(struct seg_)); newRoute->segtype = ST_VIA; @@ -286,8 +293,12 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special) newRoute->next = routednet->segments; routednet->segments = newRoute; } - else - LefError("Via \"%s\" does not define a metal layer!\n", token); + else { + if (paintLayer >= Num_layers) + LefError("Via \"%s\" exceeds layer limit setting!\n", token); + else + LefError("Via \"%s\" does not define a metal layer!\n", token); + } } else LefError("Via name \"%s\" unknown in route.\n", token); @@ -403,7 +414,7 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special) UserObs = drect; } } - else if (paintLayer >= 0) { + else if ((paintLayer >= 0) && (paintLayer < Num_layers)) { newRoute = (SEG)malloc(sizeof(struct seg_)); newRoute->segtype = ST_WIRE; newRoute->x1 = locarea.x1; @@ -426,6 +437,9 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special) newRoute->next = routednet->segments; routednet->segments = newRoute; } + else if (paintLayer >= Num_layers) { + LefError("Route layer exceeds layer limit setting!\n"); + } } endCoord: @@ -43,7 +43,7 @@ FindGateNode(Tcl_HashTable *NodeTable, NODE node, int *ridx) GATE g; Tcl_HashEntry *entry; - entry = Tcl_FindHashEntry(NodeTable, node); + entry = Tcl_FindHashEntry(NodeTable, (char *)node); if (entry) { gn = (GATENODE)Tcl_GetHashValue(entry); *ridx = gn->idx; @@ -59,6 +59,7 @@ FindGateNode(Tcl_HashTable *NodeTable, NODE node, int *ridx) 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; @@ -123,11 +124,13 @@ add_route_to_endpoint(endpointinfo *eptinfo, int eidx, int didx) /*--------------------------------------------------------------*/ /* 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. */ /*--------------------------------------------------------------*/ void check_downstream(SEG walkseg, endpointinfo *eptinfo, int eidx, - int numroutes, lefrcinfo *lefrcvalues) + int numroutes, lefrcinfo *lefrcvalues, u_char end) { int i; int startcompat, endcompat; @@ -186,16 +189,22 @@ check_downstream(SEG walkseg, endpointinfo *eptinfo, int eidx, 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); @@ -208,8 +217,7 @@ check_downstream(SEG walkseg, endpointinfo *eptinfo, int eidx, /* which a two paths may connect to a node at two different */ /* locations. */ - nodeptr = (walkseg == eptinfo[eidx].route->segments) ? - eptinfo[eidx].startnode : eptinfo[eidx].endnode; + nodeptr = (end == 0) ? eptinfo[eidx].startnode : eptinfo[eidx].endnode; if (nodeptr != NULL) { for (i = 0; i < numroutes; i++) { @@ -316,7 +324,7 @@ walk_route(int eidx, int driverend, endpointinfo *eptinfo, /* if it is the driver. */ if (eptinfo[eidx].flags & EPT_DRIVER) - check_downstream(firstseg, eptinfo, eidx, numroutes, lefrcvalues); + check_downstream(firstseg, eptinfo, eidx, numroutes, lefrcvalues, (u_char)0); /* Walk the route segment and accumulate R and C */ @@ -350,7 +358,7 @@ walk_route(int eidx, int driverend, endpointinfo *eptinfo, } /* Check for downstream nodes from the last route point */ - check_downstream(lastseg, eptinfo, eidx, numroutes, lefrcvalues); + check_downstream(lastseg, eptinfo, eidx, numroutes, lefrcvalues, (u_char)1); } /*--------------------------------------------------------------*/ @@ -423,7 +431,7 @@ int write_delays(char *filename) NODEINFO nodeptr; SEG seg, newseg, lastseg, nxseg; GATE g, drivergate; - int i, n, new, driverend; + int i, j, n, new, driverend; int drivernodeidx, driveridx; int nroute, numroutes; endpointinfo *eptinfo; @@ -455,7 +463,7 @@ int write_delays(char *filename) gn = (GATENODE)malloc(sizeof(struct gatenode_)); gn->idx = i; gn->gate = g; - entry = Tcl_CreateHashEntry(&NodeTable, *(g->noderec + i), &new); + entry = Tcl_CreateHashEntry(&NodeTable, (char *)(*(g->noderec + i)), &new); Tcl_SetHashValue(entry, gn); } } @@ -490,6 +498,11 @@ int write_delays(char *filename) if ((net->netnum == VDD_NET) || (net->netnum == GND_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 */ + /* Marked as one driver node. Not handling more than one driver yet. */ fprintf(delayFile, "%s 1", net->netname); @@ -498,10 +511,6 @@ int write_delays(char *filename) /* (For now, if a net has multiple tristate drivers, just use */ /* the first one and treat the rest as receivers.) */ - /* Count number of net routes */ - numroutes = 0; - for (rt = net->routes; rt; rt = rt->next) numroutes++; - /* Allocate space for endpoint info */ eptinfo = (endpointinfo *)malloc(numroutes * sizeof(endpointinfo)); @@ -509,26 +518,31 @@ int write_delays(char *filename) 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; - eptinfo[nroute].startx = seg->x1; - eptinfo[nroute].starty = seg->y1; - eptinfo[nroute].startl = seg->layer; - eptinfo[nroute].starttype = seg->segtype; - eptinfo[nroute].startnode = NULL; - eptinfo[nroute].branching = NULL; - eptinfo[nroute].res = 0.0; - eptinfo[nroute].cap = 0.0; + if (seg != NULL) { + eptinfo[nroute].startx = seg->x1; + eptinfo[nroute].starty = seg->y1; + eptinfo[nroute].startl = seg->layer; + eptinfo[nroute].starttype = seg->segtype; + eptinfo[nroute].res = 0.0; + eptinfo[nroute].cap = 0.0; + } /* Segment end */ for (seg = rt->segments; seg && seg->next; seg = seg->next); - eptinfo[nroute].endx = seg->x2; - eptinfo[nroute].endy = seg->y2; - eptinfo[nroute].endl = seg->layer; - eptinfo[nroute].endtype = seg->segtype; - eptinfo[nroute].endnode = NULL; - + if (seg != NULL) { + eptinfo[nroute].endx = seg->x2; + eptinfo[nroute].endy = seg->y2; + eptinfo[nroute].endl = seg->layer; + eptinfo[nroute].endtype = seg->segtype; + } nroute++; } @@ -545,6 +559,9 @@ int write_delays(char *filename) 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; @@ -572,11 +589,12 @@ int write_delays(char *filename) /* 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, starttype; int endx, endy, endl, endtype; - int brkx, brky, startcompat, endcompat; + int brkx, brky, brki, startcompat, endcompat; int initial, final; int x1, y1, x2, y2; @@ -631,8 +649,22 @@ int write_delays(char *filename) } /* Compare against endpoints of all other routes */ + brki = -1; for (i = 0; i < numroutes; i++) { if (eptinfo[i].route == rt) continue; + if (eptinfo[i].endl == -2) 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; @@ -683,9 +715,8 @@ int write_delays(char *filename) starty <= y1) { brkx = startx; brky = starty; - /* Disable this endpoint */ - eptinfo[i].startl = -2; - break; + y2 = brky; + brki = i; } } else { @@ -693,9 +724,8 @@ int write_delays(char *filename) starty <= y2) { brkx = startx; brky = starty; - /* Disable this endpoint */ - eptinfo[i].startl = -2; - break; + y2 = brky; + brki = i; } } } @@ -705,9 +735,8 @@ int write_delays(char *filename) endy <= y1) { brkx = endx; brky = endy; - /* Disable this endpoint */ - eptinfo[i].endl = -2; - break; + y2 = brky; + brki = i; } } else { @@ -715,9 +744,8 @@ int write_delays(char *filename) endy <= y2) { brkx = endx; brky = endy; - /* Disable this endpoint */ - eptinfo[i].endl = -2; - break; + y2 = brky; + brki = i; } } } @@ -729,9 +757,8 @@ int write_delays(char *filename) startx <= x1) { brkx = startx; brky = starty; - /* Disable this endpoint */ - eptinfo[i].startl = -2; - break; + x2 = brkx; + brki = i; } } else { @@ -739,9 +766,8 @@ int write_delays(char *filename) startx <= x2) { brkx = startx; brky = starty; - /* Disable this endpoint */ - eptinfo[i].startl = -2; - break; + x2 = brkx; + brki = i; } } } @@ -751,9 +777,8 @@ int write_delays(char *filename) endx <= x1) { brkx = endx; brky = endy; - /* Disable this endpoint */ - eptinfo[i].endl = -2; - break; + x2 = brkx; + brki = i; } } else { @@ -761,16 +786,17 @@ int write_delays(char *filename) endx <= x2) { brkx = endx; brky = endy; - /* Disable this endpoint */ - eptinfo[i].endl = -2; - break; + x2 = brkx; + brki = i; } } } } } + if ((brki >= 0) && (eptinfo[brki].endl != -2)) { + /* Disable this endpoint so it is not checked again */ + eptinfo[brki].endl = -2; - if (i < numroutes) { /* Break route at this point */ /* Make a copy of the segment where the break occurs */ newroute = (ROUTE)malloc(sizeof(struct route_)); @@ -796,15 +822,17 @@ int write_delays(char *filename) newroute->start.route = NULL; newroute->end.route = NULL; - /* Update eptinfo[i].route to point to new split */ - for (i = 0; i < numroutes; i++) { - if (eptinfo[i].route == rt) { - eptinfo[i].route = newroute; - break; - } - } + /* 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 */ @@ -823,6 +851,14 @@ int write_delays(char *filename) 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; @@ -913,13 +949,16 @@ int write_delays(char *filename) 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(g->gatetype->node[i], "pin")) + */ + if (!strcmp(drivergate->gatetype->node[drivernodeidx], "pin")) fprintf(delayFile, " PIN/%s %d ", drivergate->gatename, net->numnodes - 1); else @@ -964,7 +1003,9 @@ int write_delays(char *filename) free(rt); rt = nxroute; } - for (i = 0; i < nroute; i++) free(eptinfo[i].branching); + for (i = 0; i < nroute; i++) + if (eptinfo[i].branching != NULL) + free(eptinfo[i].branching); free(eptinfo); } fclose(delayFile); @@ -32,7 +32,7 @@ static void createGC(Window, GC *, XFontStruct *); XFontStruct *font_info; Pixmap buffer = (Pixmap)0; -Display *dpy; +Display *dpy = NULL; Window win; Colormap cmap; GC gc; @@ -44,6 +44,7 @@ Dimension width, height; 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]; @@ -58,6 +59,8 @@ 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++) { @@ -86,6 +89,8 @@ void highlight_source() { 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 @@ -122,6 +127,8 @@ void highlight_dest() { 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 @@ -157,6 +164,8 @@ 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 @@ -185,6 +194,8 @@ void highlight_mask(void) { // 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 @@ -209,6 +220,8 @@ map_obstruction() int xspc, yspc, hspc; int i, x, y; + if (dpy == NULL) return; + hspc = spacing >> 1; // Draw obstructions as light gray squares @@ -254,6 +267,8 @@ map_congestion() u_char *Congestion; u_char value, maxval; + if (dpy == NULL) return; + hspc = spacing >> 1; Congestion = (u_char *)calloc(NumChannelsX[0] * NumChannelsY[0], @@ -309,6 +324,8 @@ map_estimate() 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[0] * NumChannelsY[0], @@ -395,6 +412,18 @@ void draw_net(NET net, u_char single, int *lastlayer) { 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; @@ -431,6 +460,8 @@ draw_net_nodes(NET net) { 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) { @@ -579,7 +610,7 @@ int GUI_init(Tcl_Interp *interp) { Tk_Window tkwind, tktop; static char *qrouterdrawdefault = ".qrouter"; - char *qrouterdrawwin; + char *qrouterdrawwin, *waitcmd; XColor cvcolor, cvexact; int i; float frac; @@ -638,6 +669,13 @@ int GUI_init(Tcl_Interp *interp) 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)); @@ -666,6 +704,13 @@ int GUI_init(Tcl_Interp *interp) 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 */ } @@ -37,10 +37,13 @@ /* ---------------------------------------------------------------------*/ /* Current line number for reading */ -int lefCurrentLine; +int lefCurrentLine = 0; /* Information about routing layers */ -LefList LefInfo; +LefList LefInfo = NULL; + +/* Information about what vias to use */ +LinkedStringPtr AllowedVias = NULL; /* Gate information is in the linked list GateInfo, imported */ @@ -693,16 +696,51 @@ double LefGetRouteOffset(int layer) { LefList lefl; + u_char o; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { - return lefl->info.route.offset; + o = lefl->info.route.hdirection; + if (o == TRUE) + return lefl->info.route.offsety; + else + return lefl->info.route.offsetx; } } return MIN(PitchX[layer], PitchY[layer]) / 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 PitchX[layer] / 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[layer] / 2.0; +} + /* *------------------------------------------------------------ * Determine and return the width of a via. The first layer @@ -835,20 +873,25 @@ LefGetRouteWideSpacing(int layer, double width) } /* - *------------------------------------------------------------ - * Get the route pitch for a given layer - *------------------------------------------------------------ + *----------------------------------------------------------------- + * 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) { - return lefl->info.route.pitch; + o = lefl->info.route.hdirection; + if (o == TRUE) + return lefl->info.route.pitchy; + else + return lefl->info.route.pitchx; } } return MIN(PitchX[layer], PitchY[layer]); @@ -856,6 +899,46 @@ LefGetRoutePitch(int layer) /* *------------------------------------------------------------ + * 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[layer]; +} + +/* + *------------------------------------------------------------ + * 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[layer]; +} + +/* + *------------------------------------------------------------ * Get the route name for a given layer *------------------------------------------------------------ */ @@ -1010,7 +1093,11 @@ LefReadLayers(f, obstruct, lreturn) } if ((curlayer < 0) && ((!lefl) || (lefl->lefClass != CLASS_IGNORE))) { - LefError("Don't know how to parse layer \"%s\"\n", token); + /* CLASS_VIA in lefl record is a cut, and the layer */ + /* geometry is ignored for the purpose of routing. */ + + if (lefl->lefClass != CLASS_VIA) + LefError("Don't know how to parse layer \"%s\"\n", token); } } return curlayer; @@ -1461,7 +1548,8 @@ LefReadPolygon(FILE *f, int curlayer, float oscale) */ enum lef_geometry_keys {LEF_LAYER = 0, LEF_WIDTH, LEF_PATH, - LEF_RECT, LEF_POLYGON, LEF_VIA, LEF_GEOMETRY_END}; + LEF_RECT, LEF_POLYGON, LEF_VIA, LEF_PORT_CLASS, + LEF_GEOMETRY_END}; DSEG LefReadGeometry(GATE lefMacro, FILE *f, float oscale) @@ -1481,6 +1569,7 @@ LefReadGeometry(GATE lefMacro, FILE *f, float oscale) "RECT", "POLYGON", "VIA", + "CLASS", "END", NULL }; @@ -1525,6 +1614,9 @@ LefReadGeometry(GATE lefMacro, FILE *f, float oscale) case LEF_VIA: LefEndStatement(f); break; + case LEF_PORT_CLASS: + LefEndStatement(f); + break; case LEF_GEOMETRY_END: if (!LefParseEndStatement(f, NULL)) { @@ -1624,7 +1716,9 @@ LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale) */ enum lef_pin_keys {LEF_DIRECTION = 0, LEF_USE, LEF_PORT, LEF_CAPACITANCE, - LEF_PIN_END}; + LEF_ANTENNADIFF, LEF_ANTENNAGATE, LEF_ANTENNAMOD, + LEF_ANTENNAPAR, LEF_ANTENNAPARSIDE, LEF_ANTENNAMAX, LEF_ANTENNAMAXSIDE, + LEF_SHAPE, LEF_NETEXPR, LEF_PIN_END}; void LefReadPin(lefMacro, f, pinname, pinNum, oscale) @@ -1644,6 +1738,15 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale) "USE", "PORT", "CAPACITANCE", + "ANTENNADIFFAREA", + "ANTENNAGATEAREA", + "ANTENNAMODEL", + "ANTENNAPARTIALMETALAREA", + "ANTENNAPARTIALMETALSIDEAREA", + "ANTENNAMAXAREACAR", + "ANTENNAMAXSIDEAREACAR", + "SHAPE", + "NETEXPR", "END", NULL }; @@ -1723,6 +1826,15 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale) LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse, oscale); break; case LEF_CAPACITANCE: + case LEF_ANTENNADIFF: + case LEF_ANTENNAGATE: + 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: @@ -2065,11 +2177,19 @@ LefAddViaGeometry(FILE *f, LefList lefl, int curlayer, float oscale) */ enum lef_layer_keys {LEF_LAYER_TYPE=0, LEF_LAYER_WIDTH, + LEF_LAYER_MAXWIDTH, LEF_LAYER_AREA, LEF_LAYER_SPACING, LEF_LAYER_SPACINGTABLE, LEF_LAYER_PITCH, LEF_LAYER_DIRECTION, LEF_LAYER_OFFSET, + LEF_LAYER_WIREEXT, LEF_LAYER_RES, LEF_LAYER_CAP, LEF_LAYER_EDGECAP, + LEF_LAYER_THICKNESS, LEF_LAYER_HEIGHT, + LEF_LAYER_MINDENSITY, LEF_LAYER_ANTENNADIFF, + LEF_LAYER_ANTENNASIDE, LEF_VIA_DEFAULT, LEF_VIA_LAYER, LEF_VIA_RECT, - LEF_VIARULE_VIA, LEF_LAYER_END}; + 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}; @@ -2099,18 +2219,31 @@ LefReadLayerSection(f, lname, mode, lefl) static char *layer_keys[] = { "TYPE", "WIDTH", + "MAXWIDTH", + "AREA", "SPACING", "SPACINGTABLE", "PITCH", "DIRECTION", "OFFSET", + "WIREEXTENSION", "RESISTANCE", "CAPACITANCE", "EDGECAPACITANCE", + "THICKNESS", + "HEIGHT", + "MINIMUMDENSITY", + "ANTENNADIFFAREARATIO", + "ANTENNASIDEAREARATIO", "DEFAULT", "LAYER", "RECT", + "ENCLOSURE", + "PREFERENCLOSURE", + "OVERHANG", + "METALOVERHANG", "VIA", + "GENERATE", "END", NULL }; @@ -2156,10 +2289,12 @@ LefReadLayerSection(f, lname, mode, lefl) lefl->info.route.width = 0.0; lefl->info.route.spacing = NULL; - lefl->info.route.pitch = 0.0; + 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.offset = -1.0; + lefl->info.route.offsetx = -1.0; + lefl->info.route.offsety = -1.0; lefl->info.route.hdirection = (u_char)0; /* A routing type has been declared. Assume */ @@ -2212,6 +2347,14 @@ LefReadLayerSection(f, lname, mode, lefl) lefl->info.route.width = dvalue / (double)oscale; LefEndStatement(f); break; + case LEF_LAYER_MAXWIDTH: + // Not handled. + LefEndStatement(f); + break; + case LEF_LAYER_AREA: + // Not handled, but needed! + LefEndStatement(f); + break; case LEF_LAYER_SPACING: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); @@ -2302,14 +2445,25 @@ LefReadLayerSection(f, lname, mode, lefl) case LEF_LAYER_PITCH: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); - lefl->info.route.pitch = dvalue / (double)oscale; + 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; + } /* 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.offset < 0.0) - lefl->info.route.offset = lefl->info.route.pitch / 2.0; - LefEndStatement(f); + 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); @@ -2320,8 +2474,17 @@ LefReadLayerSection(f, lname, mode, lefl) case LEF_LAYER_OFFSET: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); - lefl->info.route.offset = dvalue / (double)oscale; - LefEndStatement(f); + 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); @@ -2361,7 +2524,17 @@ LefReadLayerSection(f, lname, mode, lefl) } LefEndStatement(f); break; + case LEF_LAYER_THICKNESS: + case LEF_LAYER_HEIGHT: + case LEF_LAYER_MINDENSITY: + case LEF_LAYER_ANTENNADIFF: + case LEF_LAYER_ANTENNASIDE: + 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: @@ -2369,7 +2542,15 @@ LefReadLayerSection(f, lname, mode, lefl) LefEndStatement(f); break; case LEF_VIA_RECT: - LefAddViaGeometry(f, lefl, curlayer, oscale); + if (curlayer >= 0) + LefAddViaGeometry(f, lefl, curlayer, oscale); + LefEndStatement(f); + break; + case LEF_VIA_ENCLOSURE: + case LEF_VIA_PREFERENCLOSURE: + case LEF_VIARULE_OVERHANG: + case LEF_VIARULE_METALOVERHANG: + /* Ignoring this: Need to handle via generates */ LefEndStatement(f); break; case LEF_VIARULE_VIA: @@ -2387,6 +2568,95 @@ LefReadLayerSection(f, lname, mode, lefl) } } +/*----------------------------------------------------------------*/ +/* This routine runs through all the defined vias, from last to */ +/* first defined. Check the X vs. Y dimension of the base layer. */ +/* If X is longer, save as ViaX. If Y is longer, save as ViaY. */ +/* If there is an AllowedVias list, then only assign vias that */ +/* are in the list. */ +/*----------------------------------------------------------------*/ + +void +LefAssignLayerVias() +{ + LefList lefl; + int layer; + double xydiff; + DSEG grect; + LinkedStringPtr viaName; + char *newViaX[MAX_LAYERS]; + char *newViaY[MAX_LAYERS]; + + for (layer = 0; layer < MAX_LAYERS; layer++) { + newViaX[layer] = newViaY[layer] = NULL; + } + + for (lefl = LefInfo; lefl; lefl = lefl->next) { + if (lefl->lefClass == CLASS_VIA) { + if (lefl->info.via.lr) { + layer = MAX_LAYERS; + if (lefl->info.via.area.layer >= 0) { + layer = lefl->info.via.area.layer; + xydiff = (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 >= 0 && grect->layer < layer) { + layer = grect->layer; + xydiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); + } + } + if (layer < MAX_LAYERS) { + /* 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; + } + if (xydiff > -EPS) { + if (newViaX[layer] != NULL) free(newViaX[layer]); + newViaX[layer] = strdup(lefl->lefName); + } + else { + if (newViaY[layer] != NULL) free(newViaY[layer]); + newViaY[layer] = strdup(lefl->lefName); + } + } + } + } + } + + /* Copy newViaX and newViaY back into viaX and viaY, making */ + /* sure that at least one entry exists for each layer. */ + + /* At this time, only ViaX[] reports values back in */ + /* LefGetViaWidth(), so make sure that if there is only one */ + /* allowed via for a layer, it is copied into the ViaX */ + /* array, regardless of its orientation. */ + + for (layer = 0; layer < MAX_LAYERS; layer++) { + if ((newViaX[layer] == NULL) && (newViaY[layer] == NULL)) + continue; + if (ViaX[layer] != NULL) free(ViaX[layer]); + if (ViaY[layer] != NULL) free(ViaY[layer]); + + if (newViaX[layer] != NULL) + ViaX[layer] = strdup(newViaX[layer]); + else + ViaX[layer] = strdup(newViaY[layer]); + if (newViaY[layer] != NULL) + ViaY[layer] = strdup(newViaY[layer]); + } + + for (layer = 0; layer < MAX_LAYERS; layer++) { + if (newViaX[layer] != NULL) free(newViaX[layer]); + if (newViaY[layer] != NULL) free(newViaY[layer]); + } +} + /* *------------------------------------------------------------ * @@ -2515,6 +2785,7 @@ LefRead(inName) case LEF_SECTION_VIARULE: token = LefNextToken(f, TRUE); sprintf(tsave, "%.127s", token); + lefl = LefFindLayer(token); if (lefl == NULL) { @@ -2677,41 +2948,12 @@ LefRead(inName) /* the strings used for route output, overriding any information */ /* that may have been in the route.cfg file. */ - /* Note that this runs through all the defined vias, from last to */ - /* first defined. Check the X vs. Y dimension of the base layer. */ - /* If X is longer, save as ViaX. If Y is longer, save as ViaY. */ - for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_ROUTE) { strcpy(CIFLayer[lefl->type], lefl->lefName); } - else if (lefl->lefClass == CLASS_VIA) { - if (lefl->info.via.lr) { - layer = MAX_LAYERS; - if (lefl->info.via.area.layer >= 0) { - layer = lefl->info.via.area.layer; - xydiff = (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 >= 0 && grect->layer < layer) { - layer = grect->layer; - xydiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); - } - } - if (layer < MAX_LAYERS) { - if (xydiff > -EPS) { - free(ViaX[layer]); - ViaX[layer] = strdup(lefl->lefName); - } - else { - if (ViaY[layer] != NULL) free(ViaY[layer]); - ViaY[layer] = strdup(lefl->lefName); - } - } - } - } } + LefAssignLayerVias(); + return oprecis; } @@ -57,8 +57,10 @@ typedef struct _lefSpacingRule { typedef struct { lefSpacingRule *spacing; /* spacing rules, ordered by width */ double width; /* nominal route width, in microns */ - double pitch; /* route pitch, in microns */ - double offset; /* route track offset from origin, 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 */ @@ -109,6 +111,7 @@ typedef struct _lefLayer { /* External declaration of global variables */ extern int lefCurrentLine; extern LefList LefInfo; +extern LinkedStringPtr AllowedVias; /* Forward declarations */ @@ -147,6 +150,7 @@ GATE LefFindInstance(char *name); void LefHashCell(GATE gateginfo); int LefRead(char *inName); +void LefAssignLayerVias(); void LefError(char *fmt, ...); /* Variable argument procedure requires */ /* parameter list. */ @@ -27,9 +27,9 @@ main(int argc, char *argv[]) maskMode = MASK_AUTO; dofirststage(0, -1); maskMode = MASK_NONE; - result = dosecondstage(0, FALSE, (u_int)100); + result = dosecondstage(0, FALSE, FALSE, (u_int)100); if (result < 5) - dosecondstage(0, FALSE, (u_int)100); + dosecondstage(0, FALSE, FALSE, (u_int)100); write_def(NULL); return 0; } @@ -612,13 +612,14 @@ void createMask(NET net, u_char slack, u_char halo) 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); - xmin = net->xmin; - xmax = net->xmax; - ymin = net->ymin; - ymax = net->ymax; + oxmin = net->xmin; + oxmax = net->xmax; + oymin = net->ymin; + oymax = net->ymax; xcent = net->trunkx; ycent = net->trunky; @@ -631,8 +632,10 @@ void createMask(NET net, u_char slack, u_char halo) // Horizontal trunk orient |= 1; - ycent = analyzeCongestion(net->trunky, ymin, ymax, xmin, xmax); + ycent = analyzeCongestion(net->trunky, oymin, oymax, oxmin, oxmax); ymin = ymax = ycent; + xmin = oxmin; + xmax = oxmax; for (i = xmin - slack; i <= xmax + slack; i++) { if (i < 0 || i >= NumChannelsX[0]) continue; @@ -667,6 +670,8 @@ void createMask(NET net, u_char slack, u_char halo) // Vertical trunk orient |= 2; xmin = xmax = xcent; + ymin = oymin; + ymax = oymax; for (i = xcent - slack; i <= xcent + slack; i++) { if (i < 0 || i >= NumChannelsX[0]) continue; @@ -704,9 +709,9 @@ void createMask(NET net, u_char slack, u_char halo) dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (!dtap) continue; - if (orient | 1) // Horizontal trunk, vertical branches + if (orient & 1) // Horizontal trunk, vertical branches create_vbranch_mask(n1->branchx, n1->branchy, ycent, slack, halo); - if (orient | 2) // Vertical trunk, horizontal branches + if (orient & 2) // Vertical trunk, horizontal branches create_hbranch_mask(n1->branchy, n1->branchx, xcent, slack, halo); } @@ -715,7 +720,7 @@ void createMask(NET net, u_char slack, u_char halo) // the branch end that is closer to the trunk and the branch that // is its nearest neighbor. - if (orient | 1) { // Horizontal trunk, vertical branches + if (orient & 1) { // Horizontal trunk, vertical branches for (n1 = net->netnodes; n1; n1 = n1->next) { for (n2 = net->netnodes->next; n2; n2 = n2->next) { @@ -740,7 +745,7 @@ void createMask(NET net, u_char slack, u_char halo) } } } - if (orient | 2) { // Vertical trunk, horizontal branches + if (orient & 2) { // Vertical trunk, horizontal branches for (n1 = net->netnodes; n1; n1 = n1->next) { for (n2 = net->netnodes->next; n2; n2 = n2->next) { @@ -777,7 +782,7 @@ void createMask(NET net, u_char slack, u_char halo) if (Verbose > 2) { if (net->numnodes == 2) Fprintf(stdout, "Two-port mask has bounding box (%d %d) to (%d %d)\n", - xmin, ymin, xmax, ymax); + oxmin, oymin, oxmax, oymax); else Fprintf(stdout, "multi-port mask has trunk line (%d %d) to (%d %d)\n", xmin, ymin, xmax, ymax); @@ -224,8 +224,8 @@ void clear_non_source_targets(NET net, POINT *pushlist) gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; - gpoint->next = *pushlist; - *pushlist = gpoint; + gpoint->next = pushlist[1]; + pushlist[1] = gpoint; } } } @@ -355,9 +355,10 @@ count_targets(NET net) /* 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 set_node_to_net(NODE node, int newflags, POINT *pushlist, + SEG bbox, u_char stage) { - int x, y, lay, obsnet = 0; + int x, y, lay, rank, base, obsnet = 0; int result = 0; u_char found_one = FALSE; NODEINFO lnode; @@ -419,6 +420,22 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s 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) { @@ -428,8 +445,8 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; - gpoint->next = *pushlist; - *pushlist = gpoint; + gpoint->next = pushlist[rank]; + pushlist[rank] = gpoint; } } found_one = TRUE; @@ -456,10 +473,15 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s // 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); @@ -493,14 +515,10 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; - if (found_one) { - gpoint->next = pushlist[1]; - pushlist[1] = gpoint; - } - else { - gpoint->next = *pushlist; - *pushlist = gpoint; - } + rank = (found_one == TRUE) ? 2 + base : base; + + gpoint->next = pushlist[rank]; + pushlist[rank] = gpoint; } } found_one = TRUE; @@ -541,8 +559,8 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s } /*--------------------------------------------------------------*/ -/* Set all taps of node "node" to MAXNETNUM, so that it will not */ -/* be routed to. */ +/* Set all taps of node "node" to MAXNETNUM, so that it will */ +/* not be routed to. */ /*--------------------------------------------------------------*/ int disable_node_nets(NODE node) @@ -693,33 +711,39 @@ int set_route_to_net_recursive(NET net, ROUTE rt, int newflags, 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(net, route, newflags, pushlist, bbox, stage); + 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(net, route, newflags, pushlist, bbox, stage); + result = set_route_to_net_recursive(net, route, newflags, + pushlist, bbox, stage); if (result < 0) return result; } } } else { - result = set_route_to_net(net, rt->start.route, newflags, pushlist, bbox, stage); + result = set_route_to_net_recursive(net, rt->start.route, newflags, + pushlist, bbox, stage); if (result < 0) return result; } 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(net, route, newflags, pushlist, bbox, stage); + 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(net, route, newflags, pushlist, bbox, stage); + result = set_route_to_net_recursive(net, route, newflags, + pushlist, bbox, stage); if (result < 0) return result; } } } else { - result = set_route_to_net(net, rt->end.route, newflags, pushlist, bbox, stage); + result = set_route_to_net_recursive(net, rt->end.route, newflags, + pushlist, bbox, stage); if (result < 0) return result; } return result; @@ -918,7 +942,7 @@ NETLIST find_colliding(NET net, int *ripnum) if ((nl != NULL) && (Verbose > 0)) { Fprintf(stdout, "Best route of %s collides with net%s: ", - net->netname, (rnum > 1) ? "" : "s"); + net->netname, (rnum > 1) ? "s" : ""); for (cnl = nl; cnl; cnl = cnl->next) { Fprintf(stdout, "%s ", cnl->net->netname); } @@ -1024,11 +1048,11 @@ void analyze_route_overwrite(int x, int y, int lay, int netnum) /* so rip up the net now. */ Fprintf(stderr, "Taking evasive action against net " "%d\n", netnum); - ripup_net(fnet, TRUE, FALSE); + ripup_net(fnet, TRUE, FALSE, FALSE); return; } if ((sx == seg->x2) && (sy == seg->y2)) { - if ((seg->segtype == ST_WIRE) || (l == (lay + 1))) break; + if ((seg->segtype == ST_WIRE) || (l >= (lay + 1))) break; else l++; } else { @@ -1046,6 +1070,57 @@ void analyze_route_overwrite(int x, int y, int lay, int netnum) } /*--------------------------------------------------------------*/ +/* 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); + } + } +} + +/*--------------------------------------------------------------*/ /* ripup_net --- */ /* */ /* Rip up the entire network located at position x, y, lay. */ @@ -1056,14 +1131,19 @@ void analyze_route_overwrite(int x, int y, int lay, int netnum) /* */ /* 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 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, rsave, rlast; + ROUTE rt; SEG seg; DPOINT ntap; @@ -1190,50 +1270,15 @@ u_char ripup_net(NET net, u_char restore, u_char flagged) } } - /* Remove all flagged routing information from this net */ - /* if "flagged" is true, otherwise remove all routing */ - /* information. */ + if (retain == FALSE) { - if (flagged && (net->routes != NULL)) { - rlast = NULL; - rsave = net->routes; - while (rsave) { - if (rsave->flags & RT_RIP) { - rt = rsave; - if (rlast == NULL) - net->routes = 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 (net->routes) { - rt = net->routes; - net->routes = rt->next; - while (rt->segments) { - seg = rt->segments->next; - free(rt->segments); - rt->segments = seg; - } - free(rt); - } - } + 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 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. @@ -1745,14 +1790,20 @@ route_set_connections(net, route) /* Does last route segment connect to a node? */ - for (; seg->next; seg = seg->next); + /* 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->layer < Pinlayers) { - lnode = NODEIPTR(seg->x2, seg->y2, seg->layer); - if (lnode != NULL) { - route->end.node = lnode->nodesav; - route->flags |= RT_END_NODE; - found = TRUE; + 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) { + route->end.node = lnode->nodesav; + route->flags |= RT_END_NODE; + found = TRUE; + } } } @@ -1771,7 +1822,7 @@ route_set_connections(net, route) if (!match) continue; x = s->x1; y = s->y1; - if (x == seg->x2 && y == seg->y2) { + if (x == seg->x2 && y == seg->y2 && nr != route->start.route) { found = TRUE; route->end.route = nr; break; @@ -1779,7 +1830,7 @@ route_set_connections(net, route) 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) { + if (x == seg->x2 && y == seg->y2 && nr != route->start.route) { found = TRUE; route->end.route = nr; break; @@ -8,12 +8,14 @@ #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 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); -u_char ripup_net(NET net, u_char restore, u_char topmost); +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); @@ -24,7 +26,7 @@ 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); + SEG bbox, u_char stage); void route_set_connections(NET net, ROUTE route); @@ -80,7 +80,7 @@ count_reachable_taps() NODEINFO lnode; GATE g; DSEG ds; - int l, i, j; + int l, i, j, orient; int gridx, gridy; double deltax, deltay; double dx, dy; @@ -108,56 +108,69 @@ count_reachable_taps() 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); - for (ds = g->taps[i]; ds; ds = ds->next) { - deltax = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0); - deltay = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1); + /* Will try more than one via if available */ + for (orient = 0; orient < 2; orient++) { + 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[ds->layer]) - 1; - while (1) { - dx = (gridx * PitchX[ds->layer]) + Xlowerbound; - if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break; + gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1; + while (1) { + dx = (gridx * PitchX[ds->layer]) + Xlowerbound; + if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break; - if (((dx - ds->x1 + EPS) > deltax) && - ((ds->x2 - dx + EPS) > deltax)) { - gridy = (int)((ds->y1 - Ylowerbound) + if (((dx - ds->x1 + EPS) > deltax) && + ((ds->x2 - dx + EPS) > deltax)) { + gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1; - while (1) { - dy = (gridy * PitchY[ds->layer]) + Ylowerbound; - if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) - break; + while (1) { + dy = (gridy * PitchY[ds->layer]) + Ylowerbound; + if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) + break; - if (((dy - ds->y1 + EPS) > deltay) && - ((ds->y2 - dy + EPS) > deltay)) { + if (((dy - ds->y1 + EPS) > deltay) && + ((ds->y2 - dy + EPS) > deltay)) { - if ((ds->layer == Num_layers - 1) || + if ((ds->layer == Num_layers - 1) || !(OBSVAL(gridx, gridy, ds->layer + 1) & NO_NET)) { - // Grid position is clear for placing a via + // Grid position is clear for placing a via - Fprintf(stderr, "Tap position (%g, %g) appears" - " to be technically routable, so it" - " is being forced routable.\n", - dx, dy); + if (orient == 0) + Fprintf(stderr, "Tap position (%g, %g)" + " appears to be technically routable" + " so it is being forced routable.\n", + dx, dy); + else + Fprintf(stderr, "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) = (OBSVAL(gridx, gridy, ds->layer) & BLOCKED_MASK) | (u_int)node->netnum; - lnode = SetNodeinfo(gridx, gridy, ds->layer); - lnode->nodeloc = node; - lnode->nodesav = node; - node->numtaps++; + lnode = SetNodeinfo(gridx, gridy, ds->layer); + lnode->nodeloc = node; + lnode->nodesav = node; + + /* If we got to orient = 1, mark NI_NO_VIAX */ + if (orient == 1) lnode->flags |= NI_NO_VIAX; + + node->numtaps++; + } } + gridy++; } - gridy++; } + gridx++; } - gridx++; } + /* If there's a solution, don't go looking at other vias */ + if (node->numtaps > 0) break; } } if (node->numtaps == 0) { @@ -168,145 +181,169 @@ count_reachable_taps() double dist, mindist; int dir, mask, tapx, tapy, tapl; - /* Initialize mindist to a large value */ - mask = 0; - mindist = PitchX[Num_layers - 1] + PitchY[Num_layers - 1]; - dir = 0; /* Indicates no solution found */ + /* Will try more than one via if available */ + for (orient = 0; orient < 2; orient++) { - for (ds = g->taps[i]; ds; ds = ds->next) { - deltax = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0); - deltay = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1); + /* Initialize mindist to a large value */ + mask = 0; + mindist = PitchX[Num_layers - 1] + PitchY[Num_layers - 1]; + dir = 0; /* Indicates no solution found */ - gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1; - while (1) { - dx = (gridx * PitchX[ds->layer]) + Xlowerbound; - if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break; + 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); - if (((dx - ds->x1 + EPS) > -deltax) && - ((ds->x2 - dx + EPS) > -deltax)) { - gridy = (int)((ds->y1 - Ylowerbound) + gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1; + while (1) { + dx = (gridx * PitchX[ds->layer]) + Xlowerbound; + if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break; + + if (((dx - ds->x1 + EPS) > -deltax) && + ((ds->x2 - dx + EPS) > -deltax)) { + gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1; - while (1) { - dy = (gridy * PitchY[ds->layer]) + Ylowerbound; - if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) - break; - - // Check that the grid position is inside the - // tap rectangle. However, if the point above - // the grid is blocked, then a via cannot be - // placed here, so skip it. - - if (((ds->layer == Num_layers - 1) || - !(OBSVAL(gridx, gridy, ds->layer + 1) - & NO_NET)) && - ((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; + while (1) { + dy = (gridy * PitchY[ds->layer]) + Ylowerbound; + if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) + break; + + // Check that the grid position is inside the + // tap rectangle. However, if the point above + // the grid is blocked, then a via cannot be + // placed here, so skip it. + + if (((ds->layer == Num_layers - 1) || + !(OBSVAL(gridx, gridy, ds->layer + 1) + & NO_NET)) && + ((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 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 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; + // 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++; } - gridy++; } + gridx++; } - gridx++; } - } - /* Was a solution found? */ - if (mask != 0) { - // Grid position is clear for placing a via + /* Was a solution found? */ + if (mask != 0) { + // Grid position is clear for placing a via - Fprintf(stderr, "Tap position (%d, %d) appears to be" + Fprintf(stderr, "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) = (OBSVAL(tapx, tapy, tapl) & BLOCKED_MASK) | mask | (u_int)node->netnum; - lnode = SetNodeinfo(tapx, tapy, tapl); - lnode->nodeloc = node; - lnode->nodesav = node; - lnode->stub = dist; - lnode->flags |= dir; - node->numtaps++; + lnode = SetNodeinfo(tapx, tapy, tapl); + lnode->nodeloc = node; + lnode->nodesav = node; + lnode->stub = dist; + lnode->flags |= dir; + + /* If we got to orient = 1 then mark NI_NO_VIAX */ + if (orient == 1) 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"); } @@ -338,14 +375,13 @@ void check_variable_pitch(int l, int *hptr, int *vptr) // will either have the same width or a larger width. // Note that when "horizontal" (o = 1) is passed to LefGetViaWidth, - // it returns the via width side-to-side; but for horizontal routing - // the dimension of interest is the height of the via. Therefore - // the direction argument passed to LefGetViaWidth is (1 - o). + // it returns the via width top-to-bottom (orient meaning is + // reversed for LefGetViaWidth), which is what we want. . . if (l == 0) - wvia = LefGetViaWidth(l, l, (1 - o)); + wvia = LefGetViaWidth(l, l, o); else - wvia = LefGetViaWidth(l - 1, l, (1 - o)); + wvia = LefGetViaWidth(l - 1, l, o); if (o == 1) { // Horizontal route vpitch = LefGetRoutePitch(l); @@ -734,6 +770,8 @@ void create_obstructions_from_gates(void) // If it clears distance for a route layer but not // vias, then block vias only. + /* (This is restrictive and unnecessary) */ + /* deltaxy = get_route_clear(ds->layer, ds); if (((dx - EPS) <= (ds->x1 - deltaxy)) || ((dx + EPS) >= (ds->x2 + deltaxy)) || @@ -743,7 +781,8 @@ void create_obstructions_from_gates(void) block_route(gridx, gridy, ds->layer, DOWN); } else - check_obstruct(gridx, gridy, ds, dx, dy); + */ + check_obstruct(gridx, gridy, ds, dx, dy); } else { edist = 0; // diagnostic break @@ -818,6 +857,8 @@ void create_obstructions_from_gates(void) // If it clears distance for a route layer but not // vias, then block vias only. + /* (This is restrictive and unnecessary) */ + /* deltaxy = get_route_clear(ds->layer, ds); if (((dx - EPS) < (ds->x1 - deltaxy)) || ((dx + EPS) > (ds->x2 + deltaxy)) || @@ -827,7 +868,8 @@ void create_obstructions_from_gates(void) block_route(gridx, gridy, ds->layer, DOWN); } else - check_obstruct(gridx, gridy, ds, dx, dy); + */ + check_obstruct(gridx, gridy, ds, dx, dy); } } gridy++; @@ -102,12 +102,13 @@ pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale, if (wvia2 > wvia) wvia = wvia2; } - fprintf(cmd, "%s %g ( %g %g ) ", CIFLayer[layer], - invscale * (int)(oscale * wvia + 0.5), - invscale * x, invscale * y); + 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 ( %g %g ) ", CIFLayer[layer], invscale * x, invscale * y); + fprintf(cmd, "%s ( %ld %ld ) ", CIFLayer[layer], + (long)(0.5 + invscale * x), (long)(0.5 + invscale * y)); } Pathon = 1; @@ -145,14 +146,14 @@ pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty, fprintf(cmd, "( "); if (horizontal) - fprintf(cmd, "%g ", invscale * x); + fprintf(cmd, "%ld ", (long)(0.5 + invscale * x)); else fprintf(cmd, "* "); if (horizontal) fprintf(cmd, "* "); else - fprintf(cmd, "%g ", invscale * y); + fprintf(cmd, "%ld ", (long)(0.5 + invscale * y)); fprintf(cmd, ") "); @@ -172,6 +173,7 @@ pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty, { char *s; char checkersign = (gridx + gridy + layer) & 0x01; + NODEINFO lnode; if ((ViaPattern == VIA_PATTERN_NONE) || (ViaY[layer] == NULL)) s = ViaX[layer]; @@ -180,12 +182,26 @@ pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty, else s = (checkersign == 0) ? ViaY[layer] : ViaX[layer]; + /* If the position is a node, then the via type may be switched if */ + /* there is a prohibition declared in the flags. */ + + if (layer < Pinlayers) { + if (((lnode = NODEIPTR(gridx, gridy, layer)) != NULL) + && (lnode->nodesav != NULL)) { + if ((lnode->flags & NI_NO_VIAX) && (s == ViaX[layer])) + s = ViaY[layer]; + if ((lnode->flags & NI_NO_VIAY) && (s == ViaY[layer])) + s = ViaX[layer]; + } + } + if (Pathon <= 0) { if (Pathon == -1) fprintf(cmd, "+ ROUTED "); else fprintf(cmd, "\n NEW "); - fprintf(cmd, "%s ( %g %g ) ", CIFLayer[layer], invscale * x, invscale * y); + 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 @@ -554,6 +570,11 @@ void print_nlnets( char *filename ) /* 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 unless route_set_connections() is re-run on the */ +/* modified routes. */ /*--------------------------------------------------------------*/ static void cleanup_net(NET net) @@ -562,10 +583,11 @@ static void cleanup_net(NET net) ROUTE rt, rt2; NODEINFO lnode; int lf, ll, lf2, ll2; - u_char fcheck, lcheck; + 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; @@ -597,6 +619,13 @@ static void cleanup_net(NET net) && (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; @@ -624,6 +653,7 @@ static void cleanup_net(NET net) && (lnode->nodesav != NULL)) lcheck = FALSE; } + xcheckl = needblock[ll] & VIABLOCKX; ycheckl = needblock[ll] & VIABLOCKY; if (!xcheckl && !ycheckl) lcheck = FALSE; @@ -642,6 +672,7 @@ static void cleanup_net(NET net) 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. @@ -672,6 +703,7 @@ static void cleanup_net(NET net) } 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 @@ -706,6 +738,7 @@ static void cleanup_net(NET net) 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. @@ -736,6 +769,7 @@ static void cleanup_net(NET net) } 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. @@ -770,6 +804,9 @@ static void cleanup_net(NET net) } } } + if (needfix == TRUE) + for (rt = net->routes; rt; rt = rt->next) + route_set_connections(net, rt); } /*--------------------------------------------------------------*/ @@ -1143,11 +1180,13 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale) dir2 = OBSVAL(seg->next->x1, seg->next->y1, seg->next->layer) & OFFSET_TAP; lnode2 = NODEIPTR(seg->next->x1, seg->next->y1, seg->next->layer); - offset2 = lnode2->offset; + if (lnode2 != NULL) + offset2 = lnode2->offset; } else { lnode2 = NODEIPTR(seg->x2, seg->y2, seg->layer); - offset2 = lnode2->offset; + if (lnode2 != NULL) + offset2 = lnode2->offset; } // Offset was calculated for vias; plain metal routes @@ -1226,8 +1265,18 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale) " at (%d %d) to (%d %d)\n", x, y, x2, y2); } if (special == (u_char)0) { - pathstart(Cmd, seg->layer, x, y, special, oscale, invscale, - horizontal); + 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); + pathto(Cmd, x, y, vertical, lastx, lasty, invscale); + } + else { + pathstart(Cmd, seg->layer, x, y, special, oscale, + invscale, horizontal); + } lastx = x; lasty = y; lastlay = seg->layer; @@ -108,7 +108,6 @@ post_config(void) PitchX[i]); PitchX[v] = PitchX[i]; } - PitchX[i] = PitchX[v]; if (PitchY[i] != 0.0 && PitchY[i] != PitchY[h]) { Fprintf(stderr, "Multiple horizontal route layers at different" " pitches. Using smaller pitch %g, will route on" @@ -116,7 +115,13 @@ post_config(void) PitchY[i]); PitchY[h] = PitchY[i]; } - PitchY[i] = PitchY[h]; + } + + // 2nd pass: 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++) { + if (PitchX[i] == 0.0) PitchX[i] = PitchX[v]; + if (PitchY[i] == 0.0) PitchY[i] = PitchY[h]; } } /* post_config() */ @@ -173,7 +178,7 @@ int read_config(FILE *fconfig, int is_info) lines = 0; while (!feof(fconfig)) { - fgets(line, MAX_LINE_LEN, fconfig); + if (fgets(line, MAX_LINE_LEN, fconfig) == NULL) break; lines++; lineptr = line; while (isspace(*lineptr)) lineptr++; @@ -215,6 +215,7 @@ runqrouter(int argc, char *argv[]) char *dotptr; char *Filename = NULL; u_char readconfig = FALSE; + u_char doscript = FALSE; Scales.iscale = 1; Scales.mscale = 100; @@ -240,6 +241,7 @@ runqrouter(int argc, char *argv[]) case 'p': case 'g': case 'r': + case 's': argsep = *(argv[i] + 2); if (argsep == '\0') { i++; @@ -283,6 +285,11 @@ runqrouter(int argc, char *argv[]) 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\", " @@ -305,6 +312,9 @@ runqrouter(int argc, char *argv[]) case 'e': minEffort = atoi(optarg); break; + case 'n': + /* Ignore '-noc' or '-nog', handled elsewhere */ + break; case '\0': /* Ignore '-' */ break; @@ -332,19 +342,21 @@ runqrouter(int argc, char *argv[]) #endif } - configFILEptr = fopen(configfile, "r"); + 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 (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 (configfile != configdefault) free(configfile); if (infoFILEptr != NULL) { @@ -441,6 +453,49 @@ runqrouter(int argc, char *argv[]) } /*--------------------------------------------------------------*/ +/* 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); + } +} + +/*--------------------------------------------------------------*/ /* reinitialize --- */ /* */ /* Free up memory in preparation for reading another DEF file */ @@ -481,11 +536,7 @@ static void reinitialize() // Free the netlist of failed nets (if there is one) - while (FailedNets) { - nl = FailedNets; - FailedNets = FailedNets->next; - free(nl); - } + remove_failed(); // Free all net and route information @@ -759,13 +810,7 @@ int dofirststage(u_char graphdebug, int debug_netnum) // Clear the lists of failed routes, in case first // stage is being called more than once. - if (debug_netnum <= 0) { - while (FailedNets) { - nl = FailedNets->next; - free(FailedNets); - FailedNets = nl; - } - } + if (debug_netnum <= 0) remove_failed(); // Now find and route all the nets @@ -891,7 +936,7 @@ static int ripup_colliding(NET net, u_char onlybreak) nl2 = nl->next; if (Verbose > 0) Fprintf(stdout, "Ripping up blocking net %s\n", nl->net->netname); - if (ripup_net(nl->net, TRUE, onlybreak) == TRUE) { + if (ripup_net(nl->net, TRUE, onlybreak, FALSE) == TRUE) { for (fn = FailedNets; fn && fn->next != NULL; fn = fn->next); if (fn) fn->next = nl; @@ -1109,7 +1154,7 @@ dosecondstage(u_char graphdebug, u_char singlestep, u_char onlybreak, u_int effo // 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); // Remove routing information from net + ripup_net(net, TRUE, FALSE, FALSE); // Remove routing information from net continue; } @@ -1125,7 +1170,7 @@ dosecondstage(u_char graphdebug, u_char singlestep, u_char onlybreak, u_int effo progress[1] += failcount; progress[0]++; if (progress[0] > loceffort) { - if ((progress[2] > 0) && (progress[2] < progress[1])) { + if ((progress[2] > 0) && (progress[2] <= progress[1])) { Fprintf(stderr, "\nNo progress at level of effort %d;" " ending 2nd stage.\n", loceffort); break; @@ -1183,20 +1228,12 @@ dosecondstage(u_char graphdebug, u_char singlestep, u_char onlybreak, u_int effo 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; - // Clear the lists of failed routes - - if (debug_netnum <= 0) { - while (FailedNets) { - nl = FailedNets->next; - free(FailedNets); - FailedNets = nl; - } - } - // Now find and route all the nets for (i = 0; i < 3; i++) progress[i] = 0; @@ -1205,23 +1242,67 @@ int dothirdstage(u_char graphdebug, int debug_netnum, u_int effort) 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); + 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) { - remaining--; if (Verbose > 0) Fprintf(stdout, "Finished routing net %s\n", net->netname); + remaining--; Fprintf(stdout, "Nets remaining: %d\n", remaining); + 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); + 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); + Fprintf(stdout, "Failed to route net %s.\n", net->netname); } } else { @@ -1406,7 +1487,7 @@ int doroute(NET net, u_char stage, u_char graphdebug) FailedNets = nlist; } } - return result; + return (unroutable > 0) ? -1 : result; } /* doroute() */ @@ -1457,8 +1538,8 @@ static int next_route_setup(struct routeinfo_ *iroute, u_char stage) 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); + rval = set_node_to_net(iroute->nsrc, PR_SOURCE, + &iroute->glist[0], &iroute->bbox, stage); if (rval == -2) { if (forceRoutable) { make_routable(iroute->nsrc); @@ -1479,8 +1560,8 @@ static int next_route_setup(struct routeinfo_ *iroute, u_char stage) // 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); + 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); @@ -1519,7 +1600,7 @@ static int next_route_setup(struct routeinfo_ *iroute, u_char stage) // 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 my clearing the "processed" + // 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. @@ -1607,8 +1688,8 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage) 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); + 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); @@ -1625,8 +1706,7 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage) 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); + rval = set_node_to_net(node, PR_TARGET, NULL, &iroute->bbox, stage); if (rval == 0) { result = 1; } @@ -1651,8 +1731,8 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage) else { /* Do this for power bus connections */ while(1) { - rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist[0], - &iroute->bbox, stage); + 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; @@ -58,9 +58,9 @@ typedef int (*__compar_fn_t)(const void*, const void*); // define possible gate orientations -#define MNONE 0 -#define MX 1 -#define MY 2 +#define MNONE 0 +#define MX 1 +#define MY 2 // define search directions @@ -76,6 +76,15 @@ typedef int (*__compar_fn_t)(const void*, const void*); #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_ { @@ -235,6 +244,8 @@ struct nodeinfo_ { #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 struct node_ { NODE next; @@ -470,6 +481,7 @@ void 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); diff --git a/qrouter.tcl.in b/qrouter.tcl.in index d13a472..ce5b874 100644 --- a/qrouter.tcl.in +++ b/qrouter.tcl.in @@ -17,7 +17,13 @@ if {[string compare $tcl_platform(platform) "windows"] == 0} { set libext .so } -load ${QROUTER_LIB_DIR}/qrouter$libext +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 } { @@ -93,7 +99,7 @@ proc qrouter::standard_route {{filename ""} {doquit true}} { set result [stage1] if {$result > 0} { set msize 10 - while {true} { + while {$msize <= 100} { set lastresult $result puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask $msize, effort 10" @@ -114,19 +120,40 @@ proc qrouter::standard_route {{filename ""} {doquit true}} { incr msize 10 } } - puts stdout "*** Running stage3 routing with defaults, 1st round" - set result [stage3] + # Attempt a couple of runs at "mask none" if not solved yet if {$result > 0} { - puts -nonewline stdout "*** Running stage2 routing" - puts stdout " with options break, mask none" - set result [stage2 break mask none] + puts -nonewline stdout "*** Running stage2 routing" + puts stdout " with options mask none, effort 30" + set result [stage2 mask none effort 30] } - puts stdout "*** Running stage3 routing with defaults, 2nd round" - set result [stage3] if {$result > 0} { - puts -nonewline stdout "*** Running stage2 routing" - puts stdout " with options break, mask none" - set result [stage2 break mask none] + puts -nonewline stdout "*** Running stage2 routing" + puts stdout " with options mask none, effort 40" + set result [stage2 mask none effort 40] + } + + # There is no point in running a cleanup stage if there are lots of + # unrouted nets. + if {$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 + } + } } if {$filename != ""} { puts stdout "*** Writing DEF file $filename" diff --git a/qrouterexec.c b/qrouterexec.c index dc1afea..8b7acea 100644 --- a/qrouterexec.c +++ b/qrouterexec.c @@ -24,7 +24,9 @@ qrouter_AppInit(interp) // Ignore Tk_Init return code---maybe can attempt to run in // a non-graphics mode. - Tk_Init(interp); + 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 */ diff --git a/qrouternullg.c b/qrouternullg.c index 4c6313e..71ae78a 100644 --- a/qrouternullg.c +++ b/qrouternullg.c @@ -19,6 +19,7 @@ qrouter_AppInit(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. */ diff --git a/tclqrouter.c b/tclqrouter.c index d077a50..1fe8fd5 100644 --- a/tclqrouter.c +++ b/tclqrouter.c @@ -32,6 +32,7 @@ Tcl_Interp *qrouterinterp; Tcl_Interp *consoleinterp; int stepnet = -1; +int batchmode = 0; /* Command structure */ @@ -511,9 +512,10 @@ int Qrouter_Init(Tcl_Interp *interp) { int cmdidx; - Tk_Window tktop; char command[256]; char version_string[20]; + Tk_Window tktop; + char *nullgvar; /* Interpreter sanity checks */ if (interp == NULL) return TCL_ERROR; @@ -521,13 +523,25 @@ Qrouter_Init(Tcl_Interp *interp) /* Remember the interpreter */ qrouterinterp = interp; - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) return TCL_ERROR; + if (Tcl_InitStubs(interp, "8.5", 0) == NULL) return TCL_ERROR; strcpy(command, "qrouter::"); - /* Create the start command */ - - tktop = Tk_MainWindow(interp); + /* 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") */ @@ -538,11 +552,11 @@ Qrouter_Init(Tcl_Interp *interp) (ClientData)tktop, (Tcl_CmdDeleteProc *) NULL); } - /* Command which creates a "simple" window. */ - - Tcl_CreateObjCommand(interp, "simple", + if (tktop != NULL) { + Tcl_CreateObjCommand(interp, "simple", (Tcl_ObjCmdProc *)Tk_SimpleObjCmd, (ClientData)tktop, (Tcl_CmdDeleteProc *) NULL); + } Tcl_Eval(interp, "lappend auto_path ."); @@ -577,7 +591,7 @@ qrouter_start(ClientData clientData, Tcl_Interp *interp, char **argv; /* For compatibility with the original C code, convert Tcl */ - /* object arguments to strings. Break out "-s <name>", */ + /* object arguments to strings. Handle "-s <name>", */ /* which is not handled by runqrouter(), and source the */ /* script <name> between runqrouter() and read_def(). */ @@ -585,22 +599,45 @@ qrouter_start(ClientData clientData, Tcl_Interp *interp, argc = 0; for (i = 1; i < objc; i++) { if (!strcmp(Tcl_GetString(objv[i]), "-s")) - scriptfile = strdup(Tcl_GetString(objv[++i])); - else - argv[argc++] = strdup(Tcl_GetString(objv[i])); + scriptfile = strdup(Tcl_GetString(objv[i + 1])); + argv[argc++] = strdup(Tcl_GetString(objv[i])); } result = runqrouter(argc, argv); - if (result == 0) GUI_init(interp); + if ((result == 0) && (batchmode == 0)) GUI_init(interp); for (i = 0; i < argc; i++) free(argv[i]); free(argv); if (scriptfile != NULL) { - result = Tcl_EvalFile(interp, scriptfile); + + /* 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); + } free(scriptfile); - if (result != TCL_OK) return result; + + /* 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 (result != TCL_OK) { + /* Make sure Tcl has generated all output */ + while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0); + /* And exit gracefully */ + qrouter_quit(clientData, interp, 1, objv); + } } if ((DEFfilename != NULL) && (Nlgates == NULL)) { @@ -1288,6 +1325,10 @@ qrouter_stage3(ClientData clientData, Tcl_Interp *interp, 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; @@ -1363,7 +1404,7 @@ qrouter_remove(ClientData clientData, Tcl_Interp *interp, case AllIdx: for (i = 0; i < Numnets; i++) { net = Nlnets[i]; - ripup_net(net, (u_char)1, (u_char)1); + ripup_net(net, (u_char)1, (u_char)1, (u_char)0); } draw_layout(); break; @@ -1371,7 +1412,7 @@ qrouter_remove(ClientData clientData, Tcl_Interp *interp, for (i = 2; i < objc; i++) { net = LookupNet(Tcl_GetString(objv[i])); if (net != NULL) - ripup_net(net, (u_char)1, (u_char)1); + ripup_net(net, (u_char)1, (u_char)1, (u_char)0); } draw_layout(); break; @@ -1959,23 +2000,31 @@ qrouter_layerinfo(ClientData clientData, Tcl_Interp *interp, /* the rotation is swapped relative to the grid */ /* positions used in the non-inverted case. */ /* */ +/* 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|<value>] */ /* via pattern [normal|inverted] */ +/* via use <via_name> [<via_name> ...] */ /*------------------------------------------------------*/ static int qrouter_via(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - int idx, idx2, result, value; + int idx, idx2, result, value, i; + char *vname; + Tcl_Obj *lobj; + LinkedStringPtr viaName, newVia; static char *subCmds[] = { - "stack", "pattern", NULL + "stack", "pattern", "use", NULL }; enum SubIdx { - StackIdx, PatternIdx + StackIdx, PatternIdx, UseIdx }; static char *stackSubCmds[] = { @@ -1986,7 +2035,7 @@ qrouter_via(ClientData clientData, Tcl_Interp *interp, }; static char *patternSubCmds[] = { - "none", "normal", "invert", NULL + "none", "normal", "inverted", NULL }; enum patternSubIdx { PatNoneIdx, PatNormalIdx, PatInvertIdx @@ -2008,6 +2057,15 @@ qrouter_via(ClientData clientData, Tcl_Interp *interp, Tcl_NewStringObj( patternSubCmds[ViaPattern + 1], -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 { @@ -2041,6 +2099,24 @@ qrouter_via(ClientData clientData, Tcl_Interp *interp, return result; ViaPattern = idx2 - 1; 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 ViaX and ViaY lists */ + LefAssignLayerVias(); + break; } } } @@ -13,8 +13,6 @@ #include <string.h> #include <tk.h> -/* TODO: include proper include for TkpUseWindow */ -int TkpUseWindow(); #include "graphics.h" @@ -51,10 +49,6 @@ typedef struct { * don't request any size. */ int height; /* Height to request for window. <= 0 means * don't request any size. */ - char *useThis; /* If the window is embedded, this points to - * the name of the window in which it is - * embedded (malloc'ed). For non-embedded - * windows this is NULL. */ char *exitProc; /* Callback procedure upon window deletion. */ char *mydata; /* This space for hire. */ int flags; /* Various flags; see below for @@ -74,8 +68,6 @@ static Tk_ConfigSpec configSpecs[] = { "0", Tk_Offset(Simple, height), 0}, {TK_CONFIG_PIXELS, "-width", "width", "Width", "0", Tk_Offset(Simple, width), 0}, - {TK_CONFIG_STRING, "-use", "use", "Use", - "", Tk_Offset(Simple, useThis), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-exitproc", "exitproc", "ExitProc", "", Tk_Offset(Simple, exitProc), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-data", "data", "Data", @@ -129,7 +121,7 @@ Tk_SimpleObjCmd(clientData, interp, objc, objv) Tk_Window tkwin = (Tk_Window) clientData; Simple *simplePtr; Tk_Window new = NULL; - char *arg, *useOption; + char *arg; int i, c; size_t length; unsigned int mask; @@ -140,26 +132,22 @@ Tk_SimpleObjCmd(clientData, interp, objc, objv) } /* - * Pre-process the argument list. Scan through it to find any - * "-use" option, or the "-main" option. If the "-main" option - * is selected, then the application will exit if this window - * is deleted. + * 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. */ - useOption = NULL; for (i = 2; i < objc; i += 2) { arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } c = arg[1]; - if ((c == 'u') && (strncmp(arg, "-use", length) == 0)) { - useOption = Tcl_GetString(objv[i+1]); - } + /* No arguments parsed */ } /* - * Create the window, and deal with the special option -use. + * Create the window */ if (tkwin != NULL) { @@ -170,14 +158,6 @@ Tk_SimpleObjCmd(clientData, interp, objc, objv) goto error; } Tk_SetClass(new, "Simple"); - if (useOption == NULL) { - useOption = (char *)Tk_GetOption(new, "use", "Use"); - } - if (useOption != NULL) { - if (TkpUseWindow(interp, new, useOption) != TCL_OK) { - goto error; - } - } /* * Create the widget record, process configuration options, and @@ -195,7 +175,6 @@ Tk_SimpleObjCmd(clientData, interp, objc, objv) simplePtr->className = NULL; simplePtr->width = 0; simplePtr->height = 0; - simplePtr->useThis = NULL; simplePtr->exitProc = NULL; simplePtr->flags = 0; simplePtr->mydata = NULL; @@ -293,12 +272,7 @@ SimpleWidgetObjCmd(clientData, interp, objc, objv) continue; } c = arg[1]; - if ((c == 'u') && (strncmp(arg, "-use", length) == 0)) { - Tcl_AppendResult(interp, "can't modify ", arg, - " option after widget is created", (char *) NULL); - result = TCL_ERROR; - goto done; - } + /* No options parsed */ } result = ConfigureSimple(interp, simplePtr, objc-2, objv+2, TK_CONFIG_ARGV_ONLY); |