summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.in10
-rw-r--r--VERSION2
-rwxr-xr-xconfigure19
-rw-r--r--configure.in17
-rw-r--r--def.c22
-rw-r--r--delays.c163
-rw-r--r--graphics.c49
-rw-r--r--lef.c344
-rw-r--r--lef.h8
-rw-r--r--main.c4
-rw-r--r--mask.c25
-rw-r--r--maze.c207
-rw-r--r--maze.h8
-rw-r--r--node.c340
-rw-r--r--output.c73
-rw-r--r--qconfig.c11
-rw-r--r--qrouter.c182
-rw-r--r--qrouter.h18
-rw-r--r--qrouter.tcl.in51
-rw-r--r--qrouterexec.c4
-rw-r--r--qrouternullg.c1
-rw-r--r--tclqrouter.c118
-rw-r--r--tkSimple.c40
24 files changed, 1206 insertions, 511 deletions
diff --git a/.gitignore b/.gitignore
index ce60b3b..03f3096 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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 $@
diff --git a/VERSION b/VERSION
index 6421ca1..2c3648c 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.80
+1.3.103
diff --git a/configure b/configure
index 87ed003..473316f 100755
--- a/configure
+++ b/configure
@@ -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)
diff --git a/def.c b/def.c
index 053185e..606df6e 100644
--- a/def.c
+++ b/def.c
@@ -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:
diff --git a/delays.c b/delays.c
index e9ea81d..967a296 100644
--- a/delays.c
+++ b/delays.c
@@ -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);
diff --git a/graphics.c b/graphics.c
index cd7cb4a..2778d61 100644
--- a/graphics.c
+++ b/graphics.c
@@ -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 */
}
diff --git a/lef.c b/lef.c
index 3cd624b..409c693 100644
--- a/lef.c
+++ b/lef.c
@@ -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;
}
diff --git a/lef.h b/lef.h
index 3b94bb8..51da360 100644
--- a/lef.h
+++ b/lef.h
@@ -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. */
diff --git a/main.c b/main.c
index 3bb3d5d..8455684 100644
--- a/main.c
+++ b/main.c
@@ -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;
}
diff --git a/mask.c b/mask.c
index f415bee..3a2fd03 100644
--- a/mask.c
+++ b/mask.c
@@ -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);
diff --git a/maze.c b/maze.c
index dfeea06..ac6833e 100644
--- a/maze.c
+++ b/maze.c
@@ -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;
diff --git a/maze.h b/maze.h
index d29d2f0..7a54b50 100644
--- a/maze.h
+++ b/maze.h
@@ -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);
diff --git a/node.c b/node.c
index 1c9543d..6fb3173 100644
--- a/node.c
+++ b/node.c
@@ -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++;
diff --git a/output.c b/output.c
index 61e9520..723aad4 100644
--- a/output.c
+++ b/output.c
@@ -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;
diff --git a/qconfig.c b/qconfig.c
index de963c8..380315c 100644
--- a/qconfig.c
+++ b/qconfig.c
@@ -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++;
diff --git a/qrouter.c b/qrouter.c
index b0b2164..7b5ae67 100644
--- a/qrouter.c
+++ b/qrouter.c
@@ -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;
diff --git a/qrouter.h b/qrouter.h
index 7278353..3cad5cb 100644
--- a/qrouter.h
+++ b/qrouter.h
@@ -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;
}
}
}
diff --git a/tkSimple.c b/tkSimple.c
index 27ae3ae..c089d9a 100644
--- a/tkSimple.c
+++ b/tkSimple.c
@@ -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);