[qrouter] 01/02: Imported 1.3.80

Ruben Undheim rubund-guest at moszumanska.debian.org
Thu Jul 13 20:19:36 UTC 2017


This is an automated email from the git hooks/post-receive script.

rubund-guest pushed a commit to branch master
in repository qrouter.

commit d7b158d45004c98cb3b3a57d2f5be004a3e25117
Author: Ruben Undheim <ruben.undheim at gmail.com>
Date:   Thu Jul 13 22:06:10 2017 +0200

    Imported 1.3.80
---
 Makefile.in    |    2 +-
 README         |   11 +-
 VERSION        |    2 +-
 configure      |   48 +-
 configure.in   |    1 +
 def.c          |   66 +-
 def.h          |    5 +-
 delays.c       |    3 +
 main.c         |    4 +-
 mask.c         |  799 +++++++++++++++++
 mask.h         |   17 +
 maze.c         |  638 ++++++++++++--
 maze.h         |    7 +-
 node.c         |  400 +--------
 output.c       | 2039 +++++++++++++++++++++++++++++++++++++++++++
 output.h       |   24 +
 point.c        |  113 +++
 point.h        |   22 +
 qrouter.c      | 2631 ++++----------------------------------------------------
 qrouter.h      |   48 +-
 qrouter.tcl.in |   58 +-
 tclqrouter.c   |   89 +-
 22 files changed, 3986 insertions(+), 3041 deletions(-)

diff --git a/Makefile.in b/Makefile.in
index a1ac67d..cdb4c80 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -31,7 +31,7 @@ prefix = @prefix@
 INSTALL_TARGET := @INSTALL_TARGET@
 ALL_TARGET := @ALL_TARGET@
 
-SOURCES = qrouter.c maze.c node.c qconfig.c lef.c def.c
+SOURCES = qrouter.c point.c maze.c mask.c node.c output.c qconfig.c lef.c def.c
 OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
 
 SOURCES2 = graphics.c tclqrouter.c tkSimple.c delays.c
diff --git a/README b/README
index c088492..f562333 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
 -------------------------------------------------
 Qrouter version 1.3
 Detail netlist router for ASICs
-(c) 2014 by Tim Edwards
+(c) 2017 by Tim Edwards
 Released under Gnu Public License
 ----------------------------------------------
 
@@ -11,10 +11,11 @@ Release notes:
 
 Version 1.3
 ------------
-Branch created September 16, 2014 mainly for
-the purpose of making the existing version 1.2
-the stable branch, particularly as version 1.2
-is required for qflow.
+Branch created September 16, 2014 and slowly
+developed for more robust and DRC-clean output,
+along with numerous bugfixes.  The underlying
+algorithm is essentially unchanged from version
+1.2.
 
 Version 1.2
 ------------
diff --git a/VERSION b/VERSION
index cbbcc34..6421ca1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.69
+1.3.80
diff --git a/configure b/configure
index 9cc1d40..87ed003 100755
--- a/configure
+++ b/configure
@@ -5366,6 +5366,35 @@ fi
 
 fi
 
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/mman.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mman_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_MMAN_H 1
+_ACEOF
+
+fi
+
+done
+
 
 
 if test $usingTcl ; then
@@ -5539,24 +5568,7 @@ if test $usingTcl ; then
 
     *-netbsd*|*-openbsd*)
       # Not available on all versions:  check for include file.
-      # On IRIX 5.3, sys/types and inttypes.h are conflicting.
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
-		  inttypes.h stdint.h unistd.h
-do :
-  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
+      ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
 if test "x$ac_cv_header_dlfcn_h" = xyes; then :
   test_ok=yes
 else
diff --git a/configure.in b/configure.in
index e5dfa44..961bbe4 100644
--- a/configure.in
+++ b/configure.in
@@ -669,6 +669,7 @@ fi
 
 AC_CHECK_LIB(Xt, XtToolkitInitialize,,[
 AC_CHECK_LIB(Xt, XtDisplayInitialize,,,-lSM -lICE -lXpm -lX11)])
+AC_CHECK_HEADERS(sys/mman.h)
 
 dnl ----------------------------------------------------------------
 dnl Once we're sure what, if any, interpreter is being compiled,
diff --git a/def.c b/def.c
index af19881..053185e 100644
--- a/def.c
+++ b/def.c
@@ -13,9 +13,8 @@
  * layer information is already known.  The DEF file should have information
  * primarily on die are, track placement, pins, components, and nets.
  *
- * To-do: Routed nets should have their routes dropped into track obstructions,
- * and the nets should be ignored.  Currently, routed nets are parsed and the
- * routes are ignored.
+ * Routed nets have their routes dropped into track obstructions, and the
+ * nets are ignored.
  */
 
 #include <stdio.h>
@@ -33,6 +32,8 @@
 #include "lef.h"
 #include "def.h"
 
+int numSpecial = 0;		/* Tracks number of specialnets */
+
 #ifndef TCL_QROUTER
 
 /* Find an instance in the instance list.  If qrouter	*/
@@ -146,7 +147,7 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
     char valid = FALSE;		/* is there a valid reference point? */
     char initial = TRUE;
     struct dseg_ locarea;
-    double x, y, lx, ly, w;
+    double x, y, lx, ly, w, hw, s;
     int routeLayer = -1, paintLayer;
     LefList lefl;
     ROUTE routednet = NULL;
@@ -205,6 +206,8 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
 	       routednet->netnum = net->netnum;
 	       routednet->segments = NULL;
 	       routednet->flags = (u_char)0;
+	       routednet->start.route = NULL;
+	       routednet->end.route = NULL;
 	    }
 	}
 	else if (*token != '(')	/* via name */
@@ -234,21 +237,25 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
 			   if (routeLayer < paintLayer) paintLayer = routeLayer;
 			   if ((routeLayer >= 0) && (special == (char)1) &&
 					(valid == TRUE)) {
-			      drect = (DSEG)malloc(sizeof(struct dseg_));
-			      drect->x1 = x + lr->x1;
-			      drect->x2 = x + lr->x2;
-			      drect->y1 = y + lr->y1;
-			      drect->y2 = y + lr->y2;
-			      drect->layer = lr->layer;
-			      drect->next = UserObs;
-			      UserObs = drect;
+				s = LefGetRouteSpacing(routeLayer); 
+				drect = (DSEG)malloc(sizeof(struct dseg_));
+				drect->x1 = x + lr->x1 - s;
+				drect->x2 = x + lr->x2 + s;
+				drect->y1 = y + lr->y1 - s;
+				drect->y2 = y + lr->y2 + s;
+				drect->layer = routeLayer;
+				drect->next = UserObs;
+				UserObs = drect;
 			   }
 			   lr = lr->next;
 			}
 			if (routeLayer == -1) paintLayer = lefl->type;
 		    }
-		    else
+		    else {
 		    	paintLayer = lefl->type;
+			if (special == (char)1)
+			    s = LefGetRouteSpacing(paintLayer); 
+		    }
 		}
 		else
 		{
@@ -273,6 +280,8 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
 			routednet->netnum = net->netnum;
 			routednet->segments = NULL;
 			routednet->flags = (u_char)0;
+			routednet->start.route = NULL;
+			routednet->end.route = NULL;
 		    }
 		    newRoute->next = routednet->segments;
 		    routednet->segments = newRoute;
@@ -359,27 +368,35 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
 	    {
 		locarea.x2 = refp.x1;
 		locarea.y2 = refp.y1;
-		lx = x;
-		ly = y;
 
 		if (special == (char)1) {
 		   if (valid == TRUE) {
+		      s = LefGetRouteSpacing(routeLayer); 
+		      hw = w / 2;
 		      drect = (DSEG)malloc(sizeof(struct dseg_));
 		      if (lx > x) {
-		         drect->x1 = x - w;
-		         drect->x2 = lx + w;
+		         drect->x1 = x - s;
+		         drect->x2 = lx + s;
+		      }
+		      else if (lx < x) {
+		         drect->x1 = lx - s;
+		         drect->x2 = x + s;
 		      }
 		      else {
-		         drect->x1 = x + w;
-		         drect->x2 = lx - w;
+		         drect->x1 = x - hw - s;
+		         drect->x2 = x + hw + s;
 		      }
 		      if (ly > y) {
-		         drect->y1 = y - w;
-		         drect->y2 = ly + w;
+		         drect->y1 = y - s;
+		         drect->y2 = ly + s;
+		      }
+		      else if (ly < y) {
+		         drect->y1 = ly - s;
+		         drect->y2 = y + s;
 		      }
 		      else {
-		         drect->y1 = y + w;
-		         drect->y2 = ly - w;
+		         drect->y1 = y - hw - s;
+		         drect->y2 = y + hw + s;
 		      }
 		      drect->layer = routeLayer;
 		      drect->next = UserObs;
@@ -403,6 +420,8 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
 			routednet->netnum = net->netnum;
 			routednet->segments = NULL;
 			routednet->flags = (u_char)0;
+			routednet->start.route = NULL;
+			routednet->end.route = NULL;
 		   }
 		   newRoute->next = routednet->segments;
 		   routednet->segments = newRoute;
@@ -1983,6 +2002,7 @@ DefRead(char *inName)
 		if (sscanf(token, "%d", &total) != 1) total = 0;
 		LefEndStatement(f);
 		DefReadNets(f, sections[DEF_SPECIALNETS], oscale, TRUE, total);
+		numSpecial = total;
 		break;
 	    case DEF_NETS:
 		token = LefNextToken(f, TRUE);
diff --git a/def.h b/def.h
index ef20aed..9e42f14 100644
--- a/def.h
+++ b/def.h
@@ -1,13 +1,14 @@
 /*
  * def.h --
  *
- * This file include the DEF I/O functions
+ * This file includes the DEF I/O functions
  *
  */
 
 #ifndef _DEFINT_H
 #define _DEFINT_H
 
-float  DefRead(char *inName);
+extern int numSpecial;
+extern float  DefRead(char *inName);
 
 #endif /* _DEFINT_H */
diff --git a/delays.c b/delays.c
index 5a18c1d..e9ea81d 100644
--- a/delays.c
+++ b/delays.c
@@ -793,6 +793,9 @@ int write_delays(char *filename)
 		    newroute->next = rt->next;
 		    rt->next = newroute;
 
+		    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) {
diff --git a/main.c b/main.c
index f6fb6fd..3bb3d5d 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);
+    result = dosecondstage(0, FALSE, (u_int)100);
     if (result < 5)
-	dosecondstage(0, FALSE);
+	dosecondstage(0, FALSE, (u_int)100);
     write_def(NULL);
     return 0;
 }
diff --git a/mask.c b/mask.c
new file mode 100644
index 0000000..f415bee
--- /dev/null
+++ b/mask.c
@@ -0,0 +1,799 @@
+/*--------------------------------------------------------------*/
+/*  mask.c -- qrouter general purpose autorouter                */
+/*  Route mask generation					*/
+/*--------------------------------------------------------------*/
+/* Written by Tim Edwards, June 2011, based on code by Steve	*/
+/* Beccue, 2003							*/
+/*--------------------------------------------------------------*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef TCL_QROUTER
+#include <tk.h>
+#endif
+
+#include "qrouter.h"
+#include "qconfig.h"
+#include "point.h"
+#include "node.h"
+#include "maze.h"
+#include "mask.h"
+#include "output.h"
+#include "lef.h"
+#include "def.h"
+#include "graphics.h"
+
+u_char   *RMask;    	        // mask out best area to route
+
+/*--------------------------------------------------------------*/
+/* Comparison routine used for qsort.  Sort nets by number of	*/
+/* nodes.							*/
+/*--------------------------------------------------------------*/
+
+int compNets(NET *a, NET *b)
+{
+   NET p = *a;
+   NET q = *b;
+
+   // NULL nets get shoved up front
+   if (p == NULL) return ((q == NULL) ? 0 : -1);
+   if (q == NULL) return 1;
+
+   // Sort critical nets at the front by assigned order
+
+   if (p->flags & NET_CRITICAL) {
+      if (q->flags & NET_CRITICAL) {
+	 return (p->netorder < q->netorder) ? -1 : 1;
+      }
+      else return -1;
+   }
+
+   // Otherwise sort by number of nodes
+
+   if (p->numnodes < q->numnodes)
+      return 1;
+   if (p->numnodes > q->numnodes)
+      return -1;
+   return 0;
+}
+
+/*--------------------------------------------------------------*/
+/* Alternative net comparison used for qsort.  Sort nets by	*/
+/* minimum dimension of the bounding box, and if equal, by the	*/
+/* number of nodes in the net.  Bounding box dimensions are	*/
+/* ordered smallest to largest, and number of nodes are ordered	*/
+/* largest to smallest.						*/
+/*--------------------------------------------------------------*/
+
+int altCompNets(NET *a, NET *b)
+{
+   NET p = *a;
+   NET q = *b;
+
+   int pwidth, qwidth, pheight, qheight, pdim, qdim;
+
+   // Any NULL nets get shoved up front
+   if (p == NULL) return ((q == NULL) ? 0 : -1);
+   if (q == NULL) return 1;
+
+   // Sort critical nets at the front by assigned order
+
+   if (p->flags & NET_CRITICAL) {
+      if (q->flags & NET_CRITICAL) {
+	 return (p->netorder < q->netorder) ? -1 : 1;
+      }
+      else return -1;
+   }
+
+   // Otherwise sort as described above.
+
+   pwidth = p->xmax - p->xmin;
+   pheight = p->ymax - p->ymin;
+   pdim = (pwidth > pheight) ? pheight : pwidth;
+
+   qwidth = q->xmax - q->xmin;
+   qheight = q->ymax - q->ymin;
+   qdim = (qwidth > qheight) ? qheight : qwidth;
+
+   if (pdim < qdim)
+      return (-1);
+   else if (pdim > qdim)
+      return (1);
+   else {
+      if (p->numnodes < q->numnodes)
+         return (1);
+      if (p->numnodes > q->numnodes)
+         return (-1);
+      return (0);
+   }
+}
+
+/*--------------------------------------------------------------*/
+/* create_netorder --- assign indexes to net->netorder    	*/
+/* Re-sort Nlnets according to net order.  Since Nlnets is a	*/
+/* global variable, nothing is returned from this routine.	*/
+/*								*/
+/* method = 0							*/
+/* 	Nets are ordered simply from those with the most nodes	*/
+/*	to those with the fewest.  However, any nets marked	*/
+/* 	critical in the configuration or critical net files	*/
+/*	will be given precedence.				*/
+/*								*/
+/* method = 1							*/
+/*	Nets are ordered by minimum bounding box dimension.	*/
+/*	This is based on the principle that small or narrow	*/
+/*	nets have little room to be moved around without	*/
+/*	greatly increasing the net length.  If these are put	*/
+/*	down first, then remaining nets can route around them.	*/
+/*--------------------------------------------------------------*/
+
+void create_netorder(u_char method)
+{
+  int i, j;
+  NET  net;
+  STRING cn;
+
+  i = 1;
+  for (cn = CriticalNet; cn; cn = cn->next) {
+     if (Verbose > 1)
+	Fprintf(stdout, "critical net %s\n", cn->name);
+     for (j = 0; j < Numnets; j++) {
+	net = Nlnets[j];
+	if (!strcmp(net->netname, (char *)cn->name)) {
+           net->netorder = i++;
+	   net->flags |= NET_CRITICAL;
+	}
+     }
+  }
+
+  switch (method) {
+      case 0:
+	 qsort((char *)Nlnets, Numnets, (int)sizeof(NET),
+			(__compar_fn_t)compNets);
+	 break;
+      case 1:
+	 qsort((char *)Nlnets, Numnets, (int)sizeof(NET),
+			(__compar_fn_t)altCompNets);
+	 break;
+  }
+
+  for (i = 0; i < Numnets; i++) {
+     net = Nlnets[i];
+     net->netorder = i++;
+  }
+
+} /* create_netorder() */
+
+/*--------------------------------------------------------------*/
+/* Measure and record the bounding box of a net.		*/
+/* This is preparatory to generating a mask for the net.	*/
+/* Find the bounding box of each node, and record that		*/
+/* information, at the same time computing the whole net's	*/
+/* bounding box as the area bounding all of the nodes.		*/
+/* Determine if the bounding box is more horizontal or		*/
+/* vertical, and specify a direction for the net's trunk line.	*/
+/* Initialize the trunk line as the midpoint between all of the	*/
+/* nodes, extending the width (or height) of the bounding box.	*/
+/* Initialize the node branch position as the line extending	*/
+/* from the middle of the node's bounding box to the trunk	*/
+/* line.  These positions (trunk and branches) will be sorted	*/
+/* and readjusted by "create_nodeorder()".			*/
+/*--------------------------------------------------------------*/
+
+void find_bounding_box(NET net)
+{
+   NODE n1, n2;
+   DPOINT d1tap, d2tap, dtap, mintap;
+   int mindist, dist, dx, dy;
+
+   if (net->numnodes == 2) {
+
+      n1 = (NODE)net->netnodes;
+      n2 = (NODE)net->netnodes->next;
+
+      // Simple 2-pass---pick up first tap on n1, find closest tap on n2,
+      // then find closest tap on n1.
+
+      d1tap = (n1->taps == NULL) ? n1->extend : n1->taps;
+      if (d1tap == NULL) return;
+      d2tap = (n2->taps == NULL) ? n2->extend : n2->taps;
+      if (d2tap == NULL) return;
+      dx = d2tap->gridx - d1tap->gridx;
+      dy = d2tap->gridy - d1tap->gridy;
+      mindist = dx * dx + dy * dy;
+      mintap = d2tap;
+      for (d2tap = d2tap->next; d2tap != NULL; d2tap = d2tap->next) {
+         dx = d2tap->gridx - d1tap->gridx;
+         dy = d2tap->gridy - d1tap->gridy;
+         dist = dx * dx + dy * dy;
+         if (dist < mindist) {
+            mindist = dist;
+            mintap = d2tap;
+         }
+      }
+      d2tap = mintap;
+      d1tap = (n1->taps == NULL) ? n1->extend : n1->taps;
+      dx = d2tap->gridx - d1tap->gridx;
+      dy = d2tap->gridy - d1tap->gridy;
+      mindist = dx * dx + dy * dy;
+      mintap = d1tap;
+      for (d1tap = d1tap->next; d1tap != NULL; d1tap = d1tap->next) {
+         dx = d2tap->gridx - d1tap->gridx;
+         dy = d2tap->gridy - d1tap->gridy;
+         dist = dx * dx + dy * dy;
+         if (dist < mindist) {
+            mindist = dist;
+            mintap = d1tap;
+         }
+      }
+      d1tap = mintap;
+
+      net->xmin = (d1tap->gridx < d2tap->gridx) ? d1tap->gridx : d2tap->gridx;
+      net->xmax = (d1tap->gridx < d2tap->gridx) ? d2tap->gridx : d1tap->gridx;
+      net->ymin = (d1tap->gridy < d2tap->gridy) ? d1tap->gridy : d2tap->gridy;
+      net->ymax = (d1tap->gridy < d2tap->gridy) ? d2tap->gridy : d1tap->gridy;
+   }
+   else {	// Net with more than 2 nodes
+
+      // Use the first tap point for each node to get a rough bounding box and
+      // centroid of all taps
+      net->xmax = net->ymax = -(MAXRT);
+      net->xmin = net->ymin = MAXRT;
+      for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) {
+         dtap = (n1->taps == NULL) ? n1->extend : n1->taps;
+	 if (dtap) {
+            if (dtap->gridx > net->xmax) net->xmax = dtap->gridx;
+            if (dtap->gridx < net->xmin) net->xmin = dtap->gridx;
+            if (dtap->gridy > net->ymax) net->ymax = dtap->gridy;
+            if (dtap->gridy < net->ymin) net->ymin = dtap->gridy;
+	 }
+      }
+   }
+}
+
+/*--------------------------------------------------------------*/
+/* defineRouteTree() ---					*/
+/*								*/
+/* Define a trunk-and-branches potential best route for a net.	*/
+/*								*/
+/* The net is analyzed for aspect ratio, and is determined if	*/
+/* it will have a horizontal or vertical trunk.  Then, each	*/
+/* node will define a branch line extending from the node	*/
+/* position to the trunk.  Trunk position is recorded in the	*/
+/* net record, and branch positions are recorded in the	node	*/
+/* records.							*/
+/*								*/
+/* To do:							*/
+/* Trunk and branch lines will be analyzed for immediate	*/
+/* collisions and sorted to help ensure a free track exists for	*/
+/* each net's trunk line.					*/
+/*--------------------------------------------------------------*/
+
+void defineRouteTree(NET net)
+{
+    NODE n1;
+    DPOINT dtap;
+    int xcent, ycent, xmin, ymin, xmax, ymax;
+
+    // This is called after create_bounding_box(), so bounds have
+    // been calculated.
+
+    xmin = net->xmin;
+    xmax = net->xmax;
+    ymin = net->ymin;
+    ymax = net->ymax;
+
+    if (net->numnodes == 2) {
+
+	// For 2-node nets, record the initial position as
+	// one horizontal trunk + one branch for one "L" of
+	// the bounding box, and one vertical trunk + one
+	// branch for the other "L" of the bounding box.
+
+	net->trunkx = xmin;
+	net->trunky = ymin;
+    }
+    else if (net->numnodes > 0) {
+
+	// Use the first tap point for each node to get a rough
+	// centroid of all taps
+
+	xcent = ycent = 0;
+	for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) {
+	    dtap = (n1->taps == NULL) ? n1->extend : n1->taps;
+	    if (dtap == NULL) continue;
+	    xcent += dtap->gridx;
+	    ycent += dtap->gridy;
+	}
+	xcent /= net->numnodes;
+	ycent /= net->numnodes;
+
+	// Record the trunk line in the net record
+
+	net->trunkx = xcent;
+	net->trunky = ycent;
+    }
+
+    if (xmax - xmin > ymax - ymin) {
+	// Horizontal trunk preferred
+	net->flags &= ~NET_VERTICAL_TRUNK;
+    }
+    else {
+	// Vertical trunk preferred
+	net->flags |= NET_VERTICAL_TRUNK;
+    }
+
+    // Set the branch line positions to the node tap points
+
+    for (n1 = net->netnodes; n1; n1 = n1->next) {
+	dtap = (n1->taps == NULL) ? n1->extend : n1->taps;
+	if (!dtap) continue;
+	n1->branchx = dtap->gridx;
+	n1->branchy = dtap->gridy;
+    }
+}
+
+/*--------------------------------------------------------------*/
+/* initMask() ---						*/
+/*--------------------------------------------------------------*/
+
+void initMask(void)
+{
+   RMask = (u_char *)calloc(NumChannelsX[0] * NumChannelsY[0],
+			sizeof(u_char));
+   if (!RMask) {
+      fprintf(stderr, "Out of memory 3.\n");
+      exit(3);
+   }
+}
+
+/*--------------------------------------------------------------*/
+/* Fill mask around the area of a vertical line			*/
+/*--------------------------------------------------------------*/
+
+void
+create_vbranch_mask(int x, int y1, int y2, u_char slack, u_char halo)
+{
+   int gx1, gx2, gy1, gy2;
+   int i, j, v;
+   u_char m;
+
+   gx1 = x - slack;
+   gx2 = x + slack;
+   if (y1 > y2) {
+      gy1 = y2 - slack;
+      gy2 = y1 + slack;
+   }
+   else {
+      gy1 = y1 - slack;
+      gy2 = y2 + slack;
+   }
+   if (gx1 < 0) gx1 = 0;
+   if (gx2 >= NumChannelsX[0]) gx2 = NumChannelsX[0] - 1;
+   if (gy1 < 0) gy1 = 0;
+   if (gy2 >= NumChannelsY[0]) gy2 = NumChannelsY[0] - 1;
+
+   for (i = gx1; i <= gx2; i++)
+      for (j = gy1; j <= gy2; j++)
+	 RMASK(i, j) = (u_char)0;
+
+   for (v = 1; v < halo; v++) {
+      if (gx1 > 0) gx1--;
+      if (gx2 < NumChannelsX[0] - 1) gx2++;
+      if (y1 > y2) {
+         if (gy1 < NumChannelsY[0] - 1) gy1++;
+         if (gy2 < NumChannelsY[0] - 1) gy2++;
+      }
+      else {
+	 if (gy1 > 0) gy1--;
+	 if (gy2 > 0) gy2--;
+      }
+      for (i = gx1; i <= gx2; i++)
+         for (j = gy1; j <= gy2; j++) {
+	    m = RMASK(i, j);
+	    if (m > v) RMASK(i, j) = (u_char)v;
+	 }
+   }
+}
+
+/*--------------------------------------------------------------*/
+/* Fill mask around the area of a horizontal line		*/
+/*--------------------------------------------------------------*/
+
+void
+create_hbranch_mask(int y, int x1, int x2, u_char slack, u_char halo)
+{
+   int gx1, gx2, gy1, gy2;
+   int i, j, v;
+   u_char m;
+
+   gy1 = y - slack;
+   gy2 = y + slack;
+   if (x1 > x2) {
+      gx1 = x2 - slack;
+      gx2 = x1 + slack;
+   }
+   else {
+      gx1 = x1 - slack;
+      gx2 = x2 + slack;
+   }
+   if (gx1 < 0) gx1 = 0;
+   if (gx2 >= NumChannelsX[0]) gx2 = NumChannelsX[0] - 1;
+   if (gy1 < 0) gy1 = 0;
+   if (gy2 >= NumChannelsY[0]) gy2 = NumChannelsY[0] - 1;
+
+   for (i = gx1; i <= gx2; i++)
+      for (j = gy1; j <= gy2; j++)
+	 RMASK(i, j) = (u_char)0;
+
+   for (v = 1; v < halo; v++) {
+      if (gy1 > 0) gy1--;
+      if (gy2 < NumChannelsY[0] - 1) gy2++;
+      if (x1 > x2) {
+         if (gx1 < NumChannelsX[0] - 1) gx1++;
+         if (gx2 < NumChannelsX[0] - 1) gx2++;
+      }
+      else {
+	 if (gx1 > 0) gx1--;
+	 if (gx2 > 0) gx2--;
+      }
+      for (i = gx1; i <= gx2; i++)
+         for (j = gy1; j <= gy2; j++) {
+	    m = RMASK(i, j);
+	    if (m > v) RMASK(i, j) = (u_char)v;
+	 }
+   }
+}
+
+/*--------------------------------------------------------------*/
+/* setBboxCurrent() ---						*/
+/*								*/
+/* Alter the net's bounding box information to include the	*/
+/* existing bounding box around all net route segments.  This	*/
+/* allows stage 3 routing to minimize the search area.		*/
+/*								*/
+/*--------------------------------------------------------------*/
+
+void setBboxCurrent(NET net)
+{
+    ROUTE rt;
+    SEG seg;
+
+    // If net is routed, increase the bounding box to
+    // include the current route solution.
+
+    for (rt = net->routes; rt; rt = rt->next)
+	for (seg = rt->segments; seg; seg = seg->next)
+	{
+	    if (seg->x1 < net->xmin) net->xmin = seg->x1;
+	    else if (seg->x1 > net->xmax) net->xmax = seg->x1;
+
+	    if (seg->x2 < net->xmin) net->xmin = seg->x2;
+	    else if (seg->x2 > net->xmax) net->xmax = seg->x2;
+
+	    if (seg->y1 < net->ymin) net->ymin = seg->y1;
+	    else if (seg->y1 > net->ymax) net->ymax = seg->y1;
+
+	    if (seg->y2 < net->ymin) net->ymin = seg->y2;
+	    else if (seg->y2 > net->ymax) net->ymax = seg->y2;
+	}
+}
+
+/*--------------------------------------------------------------*/
+/* createBboxMask() ---						*/
+/*								*/
+/* Create mask limiting the area to search for routing		*/
+/*								*/
+/* The bounding box mask generates an area including the	*/
+/* bounding box as defined in the net record, includes all pin	*/
+/* positions in the mask, and increases the mask area by one	*/
+/* route track for each pass, up to "halo".			*/
+/*--------------------------------------------------------------*/
+
+void createBboxMask(NET net, u_char halo)
+{
+    int xmin, ymin, xmax, ymax;
+    int i, j, gx1, gy1, gx2, gy2;
+
+    fillMask((u_char)halo);
+
+    xmin = net->xmin;
+    xmax = net->xmax;
+    ymin = net->ymin;
+    ymax = net->ymax;
+
+    for (gx1 = xmin; gx1 <= xmax; gx1++)
+	for (gy1 = ymin; gy1 <= ymax; gy1++)
+	    RMASK(gx1, gy1) = (u_char)0;
+
+    for (i = 1; i <= halo; i++) {
+	gx1 = xmin - i;
+	if (gx1 >= 0 && gx1 < NumChannelsX[0])
+           for (j = ymin - i; j <= ymax + i; j++)
+	      if (j >= 0 && j < NumChannelsY[0])
+		 RMASK(gx1, j) = (u_char)i;
+
+	gx2 = xmax + i;
+	if (gx2 >= 0 && gx2 < NumChannelsX[0])
+           for (j = ymin - i; j <= ymax + i; j++)
+	      if (j >= 0 && j < NumChannelsY[0])
+		 RMASK(gx2, j) = (u_char)i;
+
+	gy1 = ymin - i;
+	if (gy1 >= 0 && gy1 < NumChannelsY[0])
+           for (j = xmin - i; j <= xmax + i; j++)
+	      if (j >= 0 && j < NumChannelsX[0])
+		 RMASK(j, gy1) = (u_char)i;
+
+	gy2 = ymax + i;
+	if (gy2 >= 0 && gy2 < NumChannelsY[0])
+           for (j = xmin - i; j <= xmax + i; j++)
+	      if (j >= 0 && j < NumChannelsX[0])
+		 RMASK(j, gy2) = (u_char)i;
+     }
+}
+
+/*--------------------------------------------------------------*/
+/* analyzeCongestion() ---					*/
+/*								*/
+/* Given a trunk route at ycent, between ymin and ymax, score	*/
+/* the neighboring positions as a function of congestion and	*/
+/* offset from the ideal location.  Return the position of the	*/
+/* best location for the trunk route.				*/
+/*--------------------------------------------------------------*/
+
+int analyzeCongestion(int ycent, int ymin, int ymax, int xmin, int xmax)
+{
+    int x, y, i, minidx = -1, sidx, n;
+    int *score, minscore;
+
+    score = (int *)malloc((ymax - ymin + 1) * sizeof(int));
+
+    for (y = ymin; y <= ymax; y++) {
+	sidx = y - ymin;
+	score[sidx] = ABSDIFF(ycent, y) * Num_layers;
+	for (x = xmin; x <= xmax; x++) {
+	    for (i = 0; i < Num_layers; i++) {
+		n = OBSVAL(x, y, i);
+		if (n & ROUTED_NET) score[sidx]++;
+		if (n & NO_NET) score[sidx]++;
+		if (n & PINOBSTRUCTMASK) score[sidx]++;
+	    }
+	}
+    }
+    minscore = MAXRT;
+    for (i = 0; i < (ymax - ymin + 1); i++) {
+	if (score[i] < minscore) {
+	    minscore = score[i];
+	    minidx = i + ymin;
+	}
+    }
+
+    free(score);
+    return minidx;
+}
+
+/*--------------------------------------------------------------*/
+/* createMask() ---						*/
+/*								*/
+/* Create mask limiting the area to search for routing		*/
+/*								*/
+/* For 2-node routes, find the two L-shaped routes between the	*/
+/* two closest points of the nodes.				*/
+/* For multi-node (>2) routes, find the best trunk line that	*/
+/* passes close to all nodes, and generate stems to the closest	*/
+/* point on each node.						*/
+/*								*/
+/* Optimizations:  (1) multi-node routes that are in a small	*/
+/* enough area, just mask the bounding box.  (2) Where nodes	*/
+/* at the end of two branches are closer to each other than to	*/
+/* the trunk, mask an additional cross-connection between the	*/
+/* two branches.						*/
+/*								*/
+/* Values are "halo" where there is no mask, 0 on the		*/
+/* closest "slack" routes to the ideal (typically 1), and	*/
+/* values increasing out to a distance of "halo" tracks away	*/
+/* from the ideal.  This allows a greater search area as the	*/
+/* number of passes of the search algorithm increases.		*/
+/*								*/
+/* To do:  Choose the position of trunk line based on		*/
+/* congestion analysis.						*/
+/*--------------------------------------------------------------*/
+
+void createMask(NET net, u_char slack, u_char halo)
+{
+  NODE n1, n2;
+  DPOINT dtap;
+  int i, j, orient;
+  int dx, dy, gx1, gx2, gy1, gy2;
+  int xcent, ycent, xmin, ymin, xmax, ymax;
+
+  fillMask((u_char)halo);
+
+  xmin = net->xmin;
+  xmax = net->xmax;
+  ymin = net->ymin;
+  ymax = net->ymax;
+
+  xcent = net->trunkx;
+  ycent = net->trunky;
+
+  orient = 0;
+
+  // Construct the trunk line mask
+
+  if (!(net->flags & NET_VERTICAL_TRUNK) || (net->numnodes == 2)) {
+     // Horizontal trunk
+     orient |= 1;
+
+     ycent = analyzeCongestion(net->trunky, ymin, ymax, xmin, xmax);
+     ymin = ymax = ycent;
+
+     for (i = xmin - slack; i <= xmax + slack; i++) {
+	if (i < 0 || i >= NumChannelsX[0]) continue;
+	for (j = ycent - slack; j <= ycent + slack; j++) {
+	   if (j < 0 || j >= NumChannelsY[0]) continue;
+	   RMASK(i, j) = (u_char)0;
+	}
+     }
+
+     for (i = 1; i < halo; i++) {
+	gy1 = ycent - slack - i;
+	gy2 = ycent + slack + i;
+        for (j = xmin - slack - i; j <= xmax + slack + i; j++) {
+	   if (j < 0 || j >= NumChannelsX[0]) continue;
+	   if (gy1 >= 0)
+	      RMASK(j, gy1) = (u_char)i;
+	   if (gy2 < NumChannelsY[0])
+	      RMASK(j, gy2) = (u_char)i;
+	}
+	gx1 = xmin - slack - i;
+	gx2 = xmax + slack + i;
+        for (j = ycent - slack - i; j <= ycent + slack + i; j++) {
+	   if (j < 0 || j >= NumChannelsY[0]) continue;
+	   if (gx1 >= 0)
+	      RMASK(gx1, j) = (u_char)i;
+	   if (gx2 < NumChannelsX[0])
+	      RMASK(gx2, j) = (u_char)i;
+	}
+     }
+  }
+  if ((net->flags & NET_VERTICAL_TRUNK) || (net->numnodes == 2)) {
+     // Vertical trunk
+     orient |= 2;
+     xmin = xmax = xcent;
+
+     for (i = xcent - slack; i <= xcent + slack; i++) {
+	if (i < 0 || i >= NumChannelsX[0]) continue;
+	for (j = ymin - slack; j <= ymax + slack; j++) {
+	   if (j < 0 || j >= NumChannelsY[0]) continue;
+	   RMASK(i, j) = (u_char)0;
+	}
+     }
+
+     for (i = 1; i < halo; i++) {
+	gx1 = xcent - slack - i;
+	gx2 = xcent + slack + i;
+        for (j = ymin - slack - i; j <= ymax + slack + i; j++) {
+	   if (j < 0 || j >= NumChannelsY[0]) continue;
+	   if (gx1 >= 0)
+	      RMASK(gx1, j) = (u_char)i;
+	   if (gx2 < NumChannelsX[0])
+	      RMASK(gx2, j) = (u_char)i;
+	}
+	gy1 = ymin - slack - i;
+	gy2 = ymax + slack + i;
+        for (j = xcent - slack - i; j <= xcent + slack + i; j++) {
+	   if (j < 0 || j >= NumChannelsX[0]) continue;
+	   if (gy1 >= 0)
+	      RMASK(j, gy1) = (u_char)i;
+	   if (gy2 < NumChannelsY[0])
+	      RMASK(j, gy2) = (u_char)i;
+	}
+     }
+  }
+     
+  // Construct the branch line masks
+
+  for (n1 = net->netnodes; n1; n1 = n1->next) {
+     dtap = (n1->taps == NULL) ? n1->extend : n1->taps;
+     if (!dtap) continue;
+
+     if (orient | 1) 	// Horizontal trunk, vertical branches
+	create_vbranch_mask(n1->branchx, n1->branchy, ycent, slack, halo);
+     if (orient | 2) 	// Vertical trunk, horizontal branches
+	create_hbranch_mask(n1->branchy, n1->branchx, xcent, slack, halo);
+  }
+
+  // Look for branches that are closer to each other than to the
+  // trunk line.  If any are found, make a cross-connection between
+  // the branch end that is closer to the trunk and the branch that
+  // is its nearest neighbor.
+
+  if (orient | 1) {	// Horizontal trunk, vertical branches
+     for (n1 = net->netnodes; n1; n1 = n1->next) {
+	for (n2 = net->netnodes->next; n2; n2 = n2->next) {
+
+	   // Check if both ends are on the same side of the trunk
+	   if ((n2->branchy > ycent && n1->branchy > ycent) ||
+		  	(n2->branchy < ycent && n1->branchy < ycent)) {
+
+	      // Check if branches are closer to each other than
+	      // the shortest branch is away from the trunk
+	      dx = ABSDIFF(n2->branchx, n1->branchx);
+	      gy1 = ABSDIFF(n1->branchy, ycent);
+	      gy2 = ABSDIFF(n2->branchy, ycent);
+	      if ((dx < gy1) && (dx < gy2)) {
+		 if (gy1 < gy2)
+		    create_hbranch_mask(n1->branchy, n2->branchx,
+				n1->branchx, slack, halo);
+		 else
+		    create_hbranch_mask(n2->branchy, n2->branchx,
+				n1->branchx, slack, halo);
+	      }
+ 	   }
+        }
+     }
+  }
+  if (orient | 2) {		// Vertical trunk, horizontal branches
+     for (n1 = net->netnodes; n1; n1 = n1->next) {
+	for (n2 = net->netnodes->next; n2; n2 = n2->next) {
+
+	   // Check if both ends are on the same side of the trunk
+	   if ((n2->branchx > xcent && n1->branchx > xcent) ||
+		  	(n2->branchx < xcent && n1->branchx < xcent)) {
+
+	      // Check if branches are closer to each other than
+	      // the shortest branch is away from the trunk
+	      dy = ABSDIFF(n2->branchy, n1->branchy);
+	      gx1 = ABSDIFF(n1->branchx, xcent);
+	      gx2 = ABSDIFF(n2->branchx, xcent);
+	      if ((dy < gx1) && (dy < gx2)) {
+		 if (gx1 < gx2)
+		    create_vbranch_mask(n1->branchx, n2->branchy,
+				n1->branchy, slack, halo);
+		 else
+		    create_vbranch_mask(n2->branchx, n2->branchy,
+				n1->branchy, slack, halo);
+	      }
+ 	   }
+        }
+     }
+  }
+
+  // Allow routes at all tap and extension points
+  for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) {
+     for (dtap = n1->taps; dtap != NULL; dtap = dtap->next)
+	RMASK(dtap->gridx, dtap->gridy) = (u_char)0;
+     for (dtap = n1->extend; dtap != NULL; dtap = dtap->next)
+	RMASK(dtap->gridx, dtap->gridy) = (u_char)0;
+  }
+
+  if (Verbose > 2) {
+     if (net->numnodes == 2)
+        Fprintf(stdout, "Two-port mask has bounding box (%d %d) to (%d %d)\n",
+			xmin, ymin, xmax, ymax);
+     else
+        Fprintf(stdout, "multi-port mask has trunk line (%d %d) to (%d %d)\n",
+			xmin, ymin, xmax, ymax);
+  }
+}
+
+/*--------------------------------------------------------------*/
+/* fillMask() fills the Mask[] array with all 1s as a last	*/
+/* resort, ensuring that no valid routes are missed due to a	*/
+/* bad guess about the optimal route positions.			*/
+/*--------------------------------------------------------------*/
+
+void fillMask(u_char value) {
+   memset((void *)RMask, (int)value,
+		(size_t)(NumChannelsX[0] * NumChannelsY[0]
+		* sizeof(u_char)));
+}
+
+/* end of mask.c */
diff --git a/mask.h b/mask.h
new file mode 100644
index 0000000..6540d00
--- /dev/null
+++ b/mask.h
@@ -0,0 +1,17 @@
+/*
+ * mask.h --
+ *
+ * This file includes the route mask functions
+ *
+ */
+
+#ifndef _MASKINT_H
+#define _MASKINT_H
+
+extern u_char *RMask;                // mask out best area to route
+
+extern void initMask(void);
+extern void fillMask(u_char value);
+extern void setBboxCurrent(NET net);
+
+#endif /* _MASKINT_H */
diff --git a/maze.c b/maze.c
index f0b05c9..dfeea06 100644
--- a/maze.c
+++ b/maze.c
@@ -17,6 +17,7 @@
 
 #include "qrouter.h"
 #include "qconfig.h"
+#include "point.h"
 #include "node.h"
 #include "maze.h"
 #include "lef.h"
@@ -194,13 +195,16 @@ void clear_non_source_targets(NET net, POINT *pushlist)
 	 Pr = &OBS2VAL(x, y, lay);
 	 if (Pr->flags & PR_TARGET) {
 	    if (Pr->flags & PR_PROCESSED) {
-		Pr->flags &= ~PR_PROCESSED;
-		gpoint = (POINT)malloc(sizeof(struct point_));
-		gpoint->x1 = x;
-		gpoint->y1 = y;
-		gpoint->layer = lay;
-		gpoint->next = *pushlist;
-		*pushlist = gpoint;
+	       Pr->flags &= ~PR_PROCESSED;
+	       if (~(Pr->flags & PR_ON_STACK)) {
+		  Pr->flags |= PR_ON_STACK;
+		  gpoint = allocPOINT();
+		  gpoint->x1 = x;
+		  gpoint->y1 = y;
+		  gpoint->layer = lay;
+		  gpoint->next = *pushlist;
+		  *pushlist = gpoint;
+	       }
 	    }
 	 }
       }
@@ -213,13 +217,16 @@ void clear_non_source_targets(NET net, POINT *pushlist)
 	    Pr = &OBS2VAL(x, y, lay);
 	    if (Pr->flags & PR_TARGET) {
 		if (Pr->flags & PR_PROCESSED) {
-		    Pr->flags &= ~PR_PROCESSED;
-		    gpoint = (POINT)malloc(sizeof(struct point_));
-		    gpoint->x1 = x;
-		    gpoint->y1 = y;
-		    gpoint->layer = lay;
-		    gpoint->next = *pushlist;
-		    *pushlist = gpoint;
+		   Pr->flags &= ~PR_PROCESSED;
+		   if (~(Pr->flags & PR_ON_STACK)) {
+		      Pr->flags |= PR_ON_STACK;
+		      gpoint = allocPOINT();
+		      gpoint->x1 = x;
+		      gpoint->y1 = y;
+		      gpoint->layer = lay;
+		      gpoint->next = *pushlist;
+		      *pushlist = gpoint;
+		   }
 		}
 	    }
          }
@@ -247,7 +254,7 @@ void clear_target_node(NODE node)
        x = ntap->gridx;
        y = ntap->gridy;
        if ((lay < Pinlayers) && (((lnode = NODEIPTR(x, y, lay)) == NULL)
-		|| (lnode->nodeloc == NULL)))
+		|| (lnode->nodesav == NULL)))
 	  continue;
        Pr = &OBS2VAL(x, y, lay);
        Pr->flags = 0;
@@ -319,14 +326,12 @@ count_targets(NET net)
 /* set_node_to_net() ---					*/
 /*								*/
 /* Change the Obs2[][] flag values to "newflags" for all tap	*/
-/* positions of route terminal "node".  Then follow all routes	*/
-/* connected to "node", updating their positions.  Where those	*/
-/* routes connect to other nodes, repeat recursively.		*/
+/* positions of route terminal "node".				*/
 /*								*/
 /* Return value is 1 if at least one terminal of the node	*/
 /* is already marked as PR_SOURCE, indicating that the node	*/
 /* has already been routed.  Otherwise, the return value is	*/
-/* zero of no error occured, and -1 if any point was found to	*/
+/* zero if no error occured, and -1 if any point was found to	*/
 /* be unoccupied by any net, which should not happen.		*/
 /*								*/
 /* If "bbox" is non-null, record the grid extents of the node	*/
@@ -354,7 +359,7 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s
 {
     int x, y, lay, obsnet = 0;
     int result = 0;
-    u_char found_one = (u_char)0;
+    u_char found_one = FALSE;
     NODEINFO lnode;
     POINT gpoint;
     DPOINT ntap;
@@ -383,7 +388,16 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s
        }
 
        if (Pr->flags & PR_SOURCE) {
-	  result = 1;				// Node is already connected!
+	  if (!found_one)
+	     return 1;			// Node is already connected!
+	  else
+	     continue;			// May be duplicate tap position
+       }
+       else if ((Pr->flags & PR_TARGET) && (newflags & PR_TARGET)) {
+	  if (!found_one)
+	     return 1;
+	  else
+	     continue;
        }
        else if (((Pr->prdata.net == node->netnum) || (stage == (u_char)2))
 			&& !(Pr->flags & newflags)) {
@@ -408,14 +422,17 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s
 	  // push this point on the stack to process
 
 	  if (pushlist != NULL) {
-	     gpoint = (POINT)malloc(sizeof(struct point_));
-	     gpoint->x1 = x;
-	     gpoint->y1 = y;
-	     gpoint->layer = lay;
-	     gpoint->next = *pushlist;
-	     *pushlist = gpoint;
+	     if (~(Pr->flags & PR_ON_STACK)) {
+		Pr->flags |= PR_ON_STACK;
+	        gpoint = allocPOINT();
+	        gpoint->x1 = x;
+	        gpoint->y1 = y;
+	        gpoint->layer = lay;
+	        gpoint->next = *pushlist;
+		*pushlist = gpoint;
+	     }
 	  }
-	  found_one = (u_char)1;
+	  found_one = TRUE;
 
 	  // record extents
 	  if (bbox) {
@@ -447,7 +464,16 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s
 
        Pr = &OBS2VAL(x, y, lay);
        if (Pr->flags & PR_SOURCE) {
-	  result = 1;				// Node is already connected!
+	  if (!found_one)
+	     return 1;			// Node is already connected!
+	  else
+	     continue;			// May be duplicate tap record
+       }
+       else if ((Pr->flags & PR_TARGET) && (newflags & PR_TARGET)) {
+	  if (!found_one)
+	     return 1;
+	  else
+	     continue;
        }
        else if ( !(Pr->flags & newflags) &&
 		((Pr->prdata.net == node->netnum) ||
@@ -461,14 +487,23 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s
 	  // push this point on the stack to process
 
 	  if (pushlist != NULL) {
-	     gpoint = (POINT)malloc(sizeof(struct point_));
-	     gpoint->x1 = x;
-	     gpoint->y1 = y;
-	     gpoint->layer = lay;
-	     gpoint->next = *pushlist;
-	     *pushlist = gpoint;
+	     if (~(Pr->flags & PR_ON_STACK)) {
+		Pr->flags |= PR_ON_STACK;
+	        gpoint = allocPOINT();
+	        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;
+		}
+	     }
 	  }
-	  found_one = (u_char)1;
+	  found_one = TRUE;
 
 	  // record extents
 	  if (bbox) {
@@ -491,7 +526,7 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char s
     // reachable from any grid point, in the first stage, so we don't
     // wait until the rip-up and reroute stage to route them.
 
-    if ((result == 0) && (found_one == (u_char)0)) {
+    if ((result == 0) && (!found_one)) {
        if (stage == (u_char)1)
           return set_node_to_net(node, newflags, pushlist, bbox, (u_char)2);
        else if (stage == (u_char)2)
@@ -581,12 +616,15 @@ int set_route_to_net(NET net, ROUTE rt, int newflags, POINT *pushlist,
 		// push this point on the stack to process
 
 		if (pushlist != NULL) {
-	  	   gpoint = (POINT)malloc(sizeof(struct point_));
-	  	   gpoint->x1 = x;
-	  	   gpoint->y1 = y;
-	  	   gpoint->layer = lay;
-	  	   gpoint->next = *pushlist;
-	 	   *pushlist = gpoint;
+		   if (~(Pr->flags & PR_ON_STACK)) {
+		      Pr->flags |= PR_ON_STACK;
+	  	      gpoint = allocPOINT();
+	  	      gpoint->x1 = x;
+	  	      gpoint->y1 = y;
+	  	      gpoint->layer = lay;
+	  	      gpoint->next = *pushlist;
+	 	      *pushlist = gpoint;
+		   }
 		}
 
 		// record extents
@@ -601,7 +639,7 @@ int set_route_to_net(NET net, ROUTE rt, int newflags, POINT *pushlist,
 		// then process it, too.
 
 		lnode = (lay >= Pinlayers) ? NULL : NODEIPTR(x, y, lay);
-		n2 = (lnode) ? lnode->nodeloc : NULL;
+		n2 = (lnode) ? lnode->nodesav : NULL;
 		if ((n2 != (NODE)NULL) && (n2 != net->netnodes)) {
 		   if (newflags == PR_SOURCE) clear_target_node(n2);
 		   result = set_node_to_net(n2, newflags, pushlist, bbox, stage);
@@ -628,19 +666,90 @@ int set_route_to_net(NET net, ROUTE rt, int newflags, POINT *pushlist,
 }
 
 /*--------------------------------------------------------------*/
-/* Process all routes of a net, and set their routed positions	*/
-/* to SOURCE in Obs2[]						*/
+/* Process a route and all routes that connect to it.  Works	*/
+/* like the routine above, but searches the route endpoints for	*/
+/* connecting nodes and routes, and then recursively calls	*/
+/* itself on the connecting routes, and other routes that	*/
+/* connect do the nodes.					*/
+/*--------------------------------------------------------------*/
+
+int set_route_to_net_recursive(NET net, ROUTE rt, int newflags,
+		POINT *pushlist, SEG bbox, u_char stage)
+{
+    ROUTE route;
+    int result;
+
+    /* If route has been marked, return */
+    if (rt->flags & RT_VISITED) return 0;
+    rt->flags |= RT_VISITED;
+
+    /* First mark this route */
+    result = set_route_to_net(net, rt, newflags, pushlist, bbox, stage);
+    if (result < 0) return result;
+
+    /* Recursively mark the routes connected to the nodes of	*/
+    /* the endpoints or connected directly to the endpoints.	*/
+
+    if (rt->flags & RT_START_NODE) {
+	for (route = net->routes; route; route = route->next) {
+	    if (!(route->flags & RT_START_NODE) && (route->start.route == rt)) {
+		result = set_route_to_net(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);
+		if (result < 0) return result;
+	    }
+	}
+    }
+    else {
+	result = set_route_to_net(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);
+		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);
+		if (result < 0) return result;
+	    }
+	}
+    }
+    else {
+	result = set_route_to_net(net, rt->end.route, newflags, pushlist, bbox, stage);
+	if (result < 0) return result;
+    }
+    return result;
+}
+
+/*--------------------------------------------------------------*/
+/* Process all routes of a net that are connected in some way	*/
+/* node "node", and set their routed positions to the value of	*/
+/* "newflags" (PR_SOURCE or PR_DEST) in Obs2[].			*/
 /*--------------------------------------------------------------*/
 
-int set_routes_to_net(NET net, int newflags, POINT *pushlist, SEG bbox,
-		u_char stage)
+int set_routes_to_net(NODE node, NET net, int newflags, POINT *pushlist,
+		SEG bbox, u_char stage)
 {
     ROUTE rt;
     int result = 0;
 
-    for (rt = net->routes; rt; rt = rt->next)
-	result = set_route_to_net(net, rt, newflags, pushlist, bbox, stage);
+    /* Clear marks on all routes */
+    for (rt = net->routes; rt; rt = rt->next) rt->flags &= ~RT_VISITED;
 
+    /* Find any route that has node as an endpoint */
+    for (rt = net->routes; rt; rt = rt->next) {
+	if ((rt->flags & RT_START_NODE) && (rt->start.node == node))
+	    result = set_route_to_net_recursive(net, rt, newflags,
+				pushlist, bbox, stage);
+	else if ((rt->flags & RT_END_NODE) && (rt->end.node == node))
+	    result = set_route_to_net_recursive(net, rt, newflags,
+				pushlist, bbox, stage);
+	if (result < 0) return result;
+    }
     return result;
 }
 
@@ -648,14 +757,20 @@ int set_routes_to_net(NET net, int newflags, POINT *pushlist, SEG bbox,
 /* Used by find_colliding() (see below).  Save net "netnum"	*/
 /* to the list of colliding nets if it is not already in the	*/
 /* list.  Return 1 if the list got longer, 0 otherwise.		*/
+/* Find the route of the net that includes the point of		*/
+/* collision, and mark it for rip-up.				*/
 /*--------------------------------------------------------------*/
 
 static int
-addcollidingnet(NETLIST *nlptr, int netnum)
+addcollidingnet(NETLIST *nlptr, int netnum, int x, int y, int lay)
 {
+    ROUTE rt;
     NETLIST cnl;
     NET fnet;
+    SEG seg;
     int i;
+    int sx, sy;
+    u_char found;
 
     for (cnl = *nlptr; cnl; cnl = cnl->next)
 	if (cnl->net->netnum == netnum)
@@ -668,6 +783,42 @@ addcollidingnet(NETLIST *nlptr, int netnum)
 	    cnl->net = fnet;
 	    cnl->next = *nlptr;
 	    *nlptr = cnl;
+
+	    /* If there are no routes then we're done. */
+
+	    if (fnet->routes == NULL) return 0;
+
+	    /* If there is only one route then there is no need */
+	    /* to search or shuffle.				*/
+
+	    if (fnet->routes->next == NULL) {
+		fnet->routes->flags |= RT_RIP;
+		return 1;
+	    }
+
+	    for (rt = fnet->routes; rt; rt = rt->next) {
+		found = 0;
+		for (seg = rt->segments; seg; seg = seg->next) {
+		    if ((seg->layer == lay) || ((seg->segtype & ST_VIA) &&
+				((seg->layer + 1) == lay))) {
+			sx = seg->x1;
+			sy = seg->y1;
+			while (1) {
+			    if ((sx == x) && (sy == y)) {
+				found = 1;
+				break;
+			    }
+			    if ((sx == seg->x2) && (sy == seg->y2)) break;
+			    if (sx < seg->x2) sx++;
+			    else if (sx > seg->x2) sx--;
+			    if (sy < seg->y2) sy++;
+			    else if (sy > seg->y2) sy--;
+			}
+			if (found) break;
+		    }
+		}
+		if (found) rt->flags |= RT_RIP;
+	    }
 	    return 1;
 	}
     }
@@ -715,7 +866,7 @@ NETLIST find_colliding(NET net, int *ripnum)
 		        if (!(orignet & NO_NET)) {
 			   orignet &= NETNUM_MASK;
 			   if ((orignet != 0) && (orignet != net->netnum))
-		 	       rnum += addcollidingnet(&nl, orignet);
+		 	       rnum += addcollidingnet(&nl, orignet, x, y, lay);
 		        }
 		     }
 		     if (x > 0) {
@@ -723,7 +874,7 @@ NETLIST find_colliding(NET net, int *ripnum)
 		        if (!(orignet & NO_NET)) {
 			   orignet &= NETNUM_MASK;
 			   if ((orignet != 0) && (orignet != net->netnum))
-		 	       rnum += addcollidingnet(&nl, orignet);
+		 	       rnum += addcollidingnet(&nl, orignet, x, y, lay);
 		        }
 		     }
 		  }
@@ -733,7 +884,7 @@ NETLIST find_colliding(NET net, int *ripnum)
 		        if (!(orignet & NO_NET)) {
 			   orignet &= NETNUM_MASK;
 			   if ((orignet != 0) && (orignet != net->netnum))
-		 	       rnum += addcollidingnet(&nl, orignet);
+		 	       rnum += addcollidingnet(&nl, orignet, x, y, lay);
 			}
 		     }
 		     if (y > 0) {
@@ -741,13 +892,16 @@ NETLIST find_colliding(NET net, int *ripnum)
 		        if (!(orignet & NO_NET)) {
 			   orignet &= NETNUM_MASK;
 			   if ((orignet != 0) && (orignet != net->netnum))
-		 	       rnum += addcollidingnet(&nl, orignet);
+		 	       rnum += addcollidingnet(&nl, orignet, x, y, lay);
 			}
 		     }
 		  }
 	       }
-	       else if ((orignet & NETNUM_MASK) != net->netnum)
-		  rnum += addcollidingnet(&nl, (orignet & NETNUM_MASK));
+	       else {
+		  orignet &= NETNUM_MASK;
+		  if ((orignet != net->netnum) && (orignet != 0))
+		     rnum += addcollidingnet(&nl, orignet, x, y, lay);
+	       }
 
 	       if ((x == seg->x2) && (y == seg->y2)) break;
 
@@ -763,8 +917,8 @@ NETLIST find_colliding(NET net, int *ripnum)
    /* Diagnostic */
 
    if ((nl != NULL) && (Verbose > 0)) {
-      Fprintf(stdout, "Best route of %s collides with nets: ",
-		net->netname);
+      Fprintf(stdout, "Best route of %s collides with net%s: ",
+		net->netname, (rnum > 1) ? "" : "s");
       for (cnl = nl; cnl; cnl = cnl->next) {
          Fprintf(stdout, "%s ", cnl->net->netname);
       }
@@ -776,6 +930,122 @@ NETLIST find_colliding(NET net, int *ripnum)
 }
 
 /*--------------------------------------------------------------*/
+/* ripup_dependent ---						*/
+/*								*/
+/* If a set of routes is being ripped out of a net (marked by	*/
+/* RT_RIP in the flags), check if any routes below them have	*/
+/* endpoints landing on a ripped-out net.  If so, flag those	*/
+/* nets for being ripped out as well.  Repeat recursively.	*/
+/*--------------------------------------------------------------*/
+
+void ripup_dependent(NET net)
+{
+    ROUTE rt, route;
+    u_char rerun = TRUE;
+
+    while (rerun) {
+	rerun = FALSE;
+	for (rt = net->routes; rt; rt = rt->next) {
+	    if (rt->flags & RT_RIP) continue;
+	    if (!(rt->flags & RT_START_NODE)) {
+		route = rt->start.route;
+		// route should not be NULL here. . .
+		if (route && (route->flags & RT_RIP)) {
+		    rt->flags |= RT_RIP;
+		    rerun = TRUE;
+		}
+	    }
+	    if (!(rt->flags & RT_END_NODE)) {
+		route = rt->end.route;
+		// route should not be NULL here. . .
+		if (route && (route->flags & RT_RIP)) {
+		    rt->flags |= RT_RIP;
+		    rerun = TRUE;
+		}
+	    }
+	}
+    }
+}
+
+/*--------------------------------------------------------------*/
+/* Failure analysis (debug procedure)				*/
+/* Occasionally when ripping up a net or net route, the Obs	*/
+/* array shows a different net in the position that is being	*/
+/* ripped, which should not happen.  This routine does a quick	*/
+/* analysis to determine if the position is orphaned.  If so,	*/
+/* it just returns and ripup_net will overwrite the position.	*/
+/* If it appears to be connected to a valid route, it will find	*/
+/* the net and route segment and run rip-up on it.		*/
+/*--------------------------------------------------------------*/
+
+void analyze_route_overwrite(int x, int y, int lay, int netnum)
+{
+    u_char is_valid = FALSE;
+    int i, sx, sy, l;
+    NET fnet;
+    ROUTE rt;
+    SEG seg;
+
+    /* Check on all sides to see if position is orphaned */
+
+    if ((x < NumChannelsX[0] - 1) && (OBSVAL(x + 1, y, lay) & NETNUM_MASK) == netnum)
+	is_valid = TRUE;
+    else if ((x > 0) && (OBSVAL(x - 1, y, lay) & NETNUM_MASK) == netnum)
+	is_valid = TRUE;
+    else if ((y < NumChannelsY[0] - 1) && (OBSVAL(x, y + 1, lay) & NETNUM_MASK) == netnum)
+	is_valid = TRUE;
+    else if ((y > 0) && (OBSVAL(x, y - 1, lay) & NETNUM_MASK) == netnum)
+	is_valid = TRUE;
+    else if ((lay < Num_layers - 1) && (OBSVAL(x, y, lay + 1) & NETNUM_MASK) == netnum)
+	is_valid = TRUE;
+    else if ((lay > 0) && (OBSVAL(x, y, lay - 1) & NETNUM_MASK) == netnum)
+	is_valid = TRUE;
+
+    if (is_valid == FALSE) {
+	Fprintf(stderr, "Net position %d %d %d appears to be orphaned.\n",
+			x, y, lay);
+	return; 	/* No action, just overwrite */
+    }
+
+    for (i = 0; i < Numnets; i++) {
+	fnet = Nlnets[i];
+	if (fnet->netnum == netnum) {
+	    for (rt = fnet->routes; rt; rt = rt->next) {
+		for (seg = rt->segments; seg; seg = seg->next) {
+		    sx = seg->x1;
+		    sy = seg->y1;
+		    l = seg->layer;
+		    while (1) {
+			if ((sx == x) && (sy == y) && (l == lay)) {
+			    Fprintf(stderr, "Net position %d %d %d appears to "
+					"belong to a valid network route.\n",
+					x, y, lay);
+			    /* Found the route containing this position, */
+			    /* so rip up the net now.			 */
+			    Fprintf(stderr, "Taking evasive action against net "
+					"%d\n", netnum);
+			    ripup_net(fnet, TRUE, FALSE);
+			    return;
+			}
+			if ((sx == seg->x2) && (sy == seg->y2)) {
+			    if ((seg->segtype == ST_WIRE) || (l == (lay + 1))) break;
+			    else l++;
+			}
+			else {
+			    if (seg->x2 > seg->x1) sx++;
+			    else if (seg->x2 < seg->x1) sx--;
+			    if (seg->y2 > seg->y1) sy++;
+			    else if (seg->y2 < seg->y1) sy--;
+			}
+		    }
+		}
+	    }
+	    break;
+	}
+    }
+}
+
+/*--------------------------------------------------------------*/
 /* ripup_net ---						*/
 /*								*/
 /* Rip up the entire network located at position x, y, lay.	*/
@@ -783,20 +1053,26 @@ NETLIST find_colliding(NET net, int *ripnum)
 /* If argument "restore" is TRUE, then at each node, restore	*/
 /* the crossover cost by attaching the node back to the		*/
 /* Nodeinfo array.						*/
+/*								*/
+/* If argument "flagged" is TRUE, then only remove routes	*/
+/* that have been flagged with RT_RIP.				*/
 /*--------------------------------------------------------------*/
 
-u_char ripup_net(NET net, u_char restore)
+u_char ripup_net(NET net, u_char restore, u_char flagged)
 {
    int thisnet, oldnet, x, y, lay, dir;
    NODEINFO lnode;
    NODE node;
-   ROUTE rt;
+   ROUTE rt, rsave, rlast;
    SEG seg;
    DPOINT ntap;
 
+   if (flagged) ripup_dependent(net);
+
    thisnet = net->netnum;
 
    for (rt = net->routes; rt; rt = rt->next) {
+      if (flagged && !(rt->flags & RT_RIP)) continue;
       if (rt->segments) {
 	 for (seg = rt->segments; seg; seg = seg->next) {
 	    lay = seg->layer;
@@ -808,7 +1084,12 @@ u_char ripup_net(NET net, u_char restore)
 	          if (oldnet != thisnet) {
 		     Fprintf(stderr, "Error: position %d %d layer %d has net "
 				"%d not %d!\n", x, y, lay, oldnet, thisnet);
-		     return FALSE;	// Something went wrong
+		     // Stop-gap:  Need to analyze the root of this problem.
+		     // However, a reasonable action is to try to find the
+		     // net and route associated with the incorrect net.
+		     analyze_route_overwrite(x, y, lay, oldnet);
+
+		     // return FALSE;	// Something went wrong
 	          }
 
 	          // Reset the net number to zero along this route for
@@ -853,10 +1134,18 @@ u_char ripup_net(NET net, u_char restore)
 		  }
 	       }
 
-	       // This break condition misses via ends, but those are
-	       // terminals and don't get ripped out.
+	       // Check for and handle via end on last route segment.
 
-	       if ((x == seg->x2) && (y == seg->y2)) break;
+	       if ((x == seg->x2) && (y == seg->y2)) {
+		  if (seg->segtype & ST_VIA) {
+		      if (lay == seg->layer)
+			 lay++;
+		      else
+		         break;
+		  }
+		  else
+		     break;
+	       }
 
 	       if (x < seg->x2) x++;
 	       else if (x > seg->x2) x--;
@@ -872,32 +1161,80 @@ u_char ripup_net(NET net, u_char restore)
    // tap.
 
    if (restore != 0) {
-      for (node = net->netnodes; node; node = node->next) {
-	 for (ntap = node->taps; ntap; ntap = ntap->next) {
-	    lay = ntap->layer;
-	    x = ntap->gridx;
-	    y = ntap->gridy;
-	    if (lay < Pinlayers) {
-		lnode = NODEIPTR(x, y, lay);
-		if (lnode) lnode->nodeloc = lnode->nodesav;
+      if (flagged) {
+	 for (rt = net->routes; rt; rt = rt->next) {
+	    if (!(rt->flags & RT_RIP)) continue;
+	    for (seg = rt->segments; seg; seg = seg->next) {
+	       lay = seg->layer;
+	       if (lay >= Pinlayers) continue;
+	       x = seg->x1;
+	       y = seg->y1;
+	       lnode = NODEIPTR(x, y, lay);
+	       if (lnode && lnode->nodesav)
+		   lnode->nodeloc = lnode->nodesav;
+	    }
+	 }
+      }
+      else {
+         for (node = net->netnodes; node; node = node->next) {
+	    for (ntap = node->taps; ntap; ntap = ntap->next) {
+	       lay = ntap->layer;
+	       x = ntap->gridx;
+	       y = ntap->gridy;
+	       if (lay < Pinlayers) {
+		   lnode = NODEIPTR(x, y, lay);
+		   if (lnode) lnode->nodeloc = lnode->nodesav;
+	       }
 	    }
 	 }
       }
    }
 
-   /* Remove all routing information from this net */
-
-   while (net->routes) {
-      rt = net->routes;
-      net->routes = rt->next;
-      while (rt->segments) {
-	 seg = rt->segments->next;
-	 free(rt->segments);
-	 rt->segments = seg;
+   /* Remove all flagged routing information from this net	*/
+   /* if "flagged" is true, otherwise remove all routing	*/
+   /* information.						*/
+
+   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);
       }
-      free(rt);
    }
 
+   // 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.
 
@@ -1145,12 +1482,12 @@ POINT eval_pt(GRIDP *ept, u_char flags, u_char stage)
 		newpt.x, newpt.y, newpt.lay);
        }
        if (~(Pr->flags & PR_ON_STACK)) {
-	  ptret = (POINT)malloc(sizeof(struct point_));
+	  Pr->flags |= PR_ON_STACK;
+	  ptret = allocPOINT();
 	  ptret->x1 = newpt.x;
 	  ptret->y1 = newpt.y;
 	  ptret->layer = newpt.lay;
 	  ptret->next = NULL;
-	  Pr->flags |= PR_ON_STACK;
 	  return ptret;
        }
     }
@@ -1191,7 +1528,7 @@ void writeback_segment(SEG seg, int netnum)
    u_int sobs;
    NODEINFO lnode;
 
-   if (seg->segtype == ST_VIA) {
+   if (seg->segtype & ST_VIA) {
       /* Preserve blocking information */
       dir = OBSVAL(seg->x1, seg->y1, seg->layer + 1) & BLOCKED_MASK;
       OBSVAL(seg->x1, seg->y1, seg->layer + 1) = netnum | dir;
@@ -1336,6 +1673,131 @@ void writeback_segment(SEG seg, int netnum)
 }
 
 /*--------------------------------------------------------------*/
+/* Set the endpoint information for the route.	Look at the	*/
+/* first and last points of the route, determine if they	*/
+/* connect to a node or another route, and set the "start" and	*/
+/* "end" records of the route, and the flags accordingly.	*/
+/*--------------------------------------------------------------*/
+
+void
+route_set_connections(net, route)
+   NET   net;
+   ROUTE route;
+{
+   SEG      seg, s;
+   ROUTE    nr;
+   NODEINFO lnode;
+   u_char   found, match;
+   int	    x, y;
+
+   /* Does first route segment connect to a node? */
+
+   seg = route->segments;
+   found = FALSE;
+   if (seg->layer < Pinlayers) {
+      lnode = NODEIPTR(seg->x1, seg->y1, seg->layer);
+      if (lnode != NULL) {
+	 route->start.node = lnode->nodesav;
+	 route->flags |= RT_START_NODE;
+	 found = TRUE;
+      }
+   }
+
+   /* Does first route segment connect to a route? */
+
+   if (!found) {
+      for (nr = net->routes; nr; nr = nr->next) {
+         if (nr == route) continue;
+         for (s = nr->segments; s; s = s->next) {
+	    match = FALSE;
+	    if (seg->layer == s->layer) match = TRUE;
+	    else if ((seg->segtype & ST_VIA) && ((seg->layer + 1) == s->layer))
+	       match = TRUE;
+	    else if ((s->segtype & ST_VIA) && ((s->layer + 1) == seg->layer))
+	       match = TRUE;
+	    if (!match) continue;
+	    x = s->x1;
+	    y = s->y1;
+	    if (x == seg->x1 && y == seg->y1) {
+	       found = TRUE;
+	       route->start.route = nr;
+	       break;
+	    }
+	    while (TRUE) {
+	       if (s->x2 != s->x1) x += ((s->x2 > s->x1) ? 1 : -1);
+	       if (s->y2 != s->y1) y += ((s->y2 > s->y1) ? 1 : -1);
+	       if (x == seg->x1 && y == seg->y1) {
+		  found = TRUE;
+		  route->start.route = nr;
+		  break;
+	       }
+	       if (x == s->x2 && y == s->y2) break;
+	    }
+	    if (found) break;
+	 }
+	 if (found) break;
+      }
+   }
+
+   if (!found) {
+      Fprintf(stderr, "Error:  Failure to find route start node/route!\n");
+   }
+
+   /* Does last route segment connect to a node? */
+
+   for (; seg->next; seg = seg->next);
+   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;
+      }
+   }
+
+   /* Does last route segment connect to a route? */
+
+   if (!found) {
+      for (nr = net->routes; nr; nr = nr->next) {
+         if (nr == route) continue;
+         for (s = nr->segments; s; s = s->next) {
+	    match = FALSE;
+	    if (seg->layer == s->layer) match = TRUE;
+	    else if ((seg->segtype & ST_VIA) && ((seg->layer + 1) == s->layer))
+	       match = TRUE;
+	    else if ((s->segtype & ST_VIA) && ((s->layer + 1) == seg->layer))
+	       match = TRUE;
+	    if (!match) continue;
+	    x = s->x1;
+	    y = s->y1;
+	    if (x == seg->x2 && y == seg->y2) {
+	       found = TRUE;
+	       route->end.route = nr;
+	       break;
+	    }
+	    while (TRUE) {
+	       if (s->x2 != s->x1) x += ((s->x2 > s->x1) ? 1 : -1);
+	       if (s->y2 != s->y1) y += ((s->y2 > s->y1) ? 1 : -1);
+	       if (x == seg->x2 && y == seg->y2) {
+		  found = TRUE;
+		  route->end.route = nr;
+		  break;
+	       }
+	       if (x == s->x2 && y == s->y2) break;
+	    }
+	    if (found) break;
+	 }
+	 if (found) break;
+      }
+   }
+
+   if (!found) {
+      Fprintf(stderr, "Error:  Failure to find route end node/route!\n");
+   }
+}
+
+/*--------------------------------------------------------------*/
 /* commit_proute - turn the potential route into an actual	*/
 /*		route by generating the route segments		*/
 /*								*/
@@ -1870,7 +2332,7 @@ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage)
       // segments produced.  Vias have to be handled one at a time, as we make
       // no assumptions about stacked vias.
 
-      if (seg->segtype == ST_WIRE) {
+      if (seg->segtype & ST_WIRE) {
 	 while ((lrnext = lrprev->next) != NULL) {
 	    lrnext = lrprev->next;
 	    if (((lrnext->x1 - lrprev->x1) == dx) &&
@@ -1890,7 +2352,7 @@ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage)
          Fprintf(stdout, "commit: index = %d, net = %d\n",
 		Pr->prdata.net, netnum);
 
-	 if (seg->segtype == ST_WIRE) {
+	 if (seg->segtype & ST_WIRE) {
             Fprintf(stdout, "commit: wire layer %d, (%d,%d) to (%d,%d)\n",
 		seg->layer, seg->x1, seg->y1, seg->x2, seg->y2);
 	 }
diff --git a/maze.h b/maze.h
index bf9c52a..d29d2f0 100644
--- a/maze.h
+++ b/maze.h
@@ -10,9 +10,10 @@
 int	set_powerbus_to_net(int netnum);
 int     set_node_to_net(NODE node, int newnet, POINT *pushlist, SEG bbox, u_char stage);
 int	disable_node_nets(NODE node);
-int     set_routes_to_net(NET net, int newnet, POINT *pushlist, SEG bbox, u_char stage);
+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  ripup_net(NET net, u_char restore, u_char topmost);
 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,6 +25,8 @@ void    clear_target_node(NODE node);
 int     count_targets(NET net);
 int	set_route_to_net(NET net, ROUTE rt, int newflags, POINT *pushlist,
                 SEG bbox, u_char stage);
+void    route_set_connections(NET net, ROUTE route);
+
 
 #define MAZE_H
 #endif 
diff --git a/node.c b/node.c
index 17895c8..1c9543d 100644
--- a/node.c
+++ b/node.c
@@ -19,314 +19,6 @@
 #include "lef.h"
 
 /*--------------------------------------------------------------*/
-/* Comparison routine used for qsort.  Sort nets by number of	*/
-/* nodes.							*/
-/*--------------------------------------------------------------*/
-
-int compNets(NET *a, NET *b)
-{
-   NET p = *a;
-   NET q = *b;
-
-   // NULL nets get shoved up front
-   if (p == NULL) return ((q == NULL) ? 0 : -1);
-   if (q == NULL) return 1;
-
-   // Sort critical nets at the front by assigned order
-
-   if (p->flags & NET_CRITICAL) {
-      if (q->flags & NET_CRITICAL) {
-	 return (p->netorder < q->netorder) ? -1 : 1;
-      }
-      else return -1;
-   }
-
-   // Otherwise sort by number of nodes
-
-   if (p->numnodes < q->numnodes)
-      return 1;
-   if (p->numnodes > q->numnodes)
-      return -1;
-   return 0;
-}
-
-/*--------------------------------------------------------------*/
-/* Alternative net comparison used for qsort.  Sort nets by	*/
-/* minimum dimension of the bounding box, and if equal, by the	*/
-/* number of nodes in the net.  Bounding box dimensions are	*/
-/* ordered smallest to largest, and number of nodes are ordered	*/
-/* largest to smallest.						*/
-/*--------------------------------------------------------------*/
-
-int altCompNets(NET *a, NET *b)
-{
-   NET p = *a;
-   NET q = *b;
-
-   int pwidth, qwidth, pheight, qheight, pdim, qdim;
-
-   // Any NULL nets get shoved up front
-   if (p == NULL) return ((q == NULL) ? 0 : -1);
-   if (q == NULL) return 1;
-
-   // Sort critical nets at the front by assigned order
-
-   if (p->flags & NET_CRITICAL) {
-      if (q->flags & NET_CRITICAL) {
-	 return (p->netorder < q->netorder) ? -1 : 1;
-      }
-      else return -1;
-   }
-
-   // Otherwise sort as described above.
-
-   pwidth = p->xmax - p->xmin;
-   pheight = p->ymax - p->ymin;
-   pdim = (pwidth > pheight) ? pheight : pwidth;
-
-   qwidth = q->xmax - q->xmin;
-   qheight = q->ymax - q->ymin;
-   qdim = (qwidth > qheight) ? qheight : qwidth;
-
-   if (pdim < qdim)
-      return (-1);
-   else if (pdim > qdim)
-      return (1);
-   else {
-      if (p->numnodes < q->numnodes)
-         return (1);
-      if (p->numnodes > q->numnodes)
-         return (-1);
-      return (0);
-   }
-}
-
-/*--------------------------------------------------------------*/
-/* create_netorder --- assign indexes to net->netorder    	*/
-/* Re-sort Nlnets according to net order.  Since Nlnets is a	*/
-/* global variable, nothing is returned from this routine.	*/
-/*								*/
-/* method = 0							*/
-/* 	Nets are ordered simply from those with the most nodes	*/
-/*	to those with the fewest.  However, any nets marked	*/
-/* 	critical in the configuration or critical net files	*/
-/*	will be given precedence.				*/
-/*								*/
-/* method = 1							*/
-/*	Nets are ordered by minimum bounding box dimension.	*/
-/*	This is based on the principle that small or narrow	*/
-/*	nets have little room to be moved around without	*/
-/*	greatly increasing the net length.  If these are put	*/
-/*	down first, then remaining nets can route around them.	*/
-/*--------------------------------------------------------------*/
-
-void create_netorder(u_char method)
-{
-  int i, j;
-  NET  net;
-  STRING cn;
-
-  i = 1;
-  for (cn = CriticalNet; cn; cn = cn->next) {
-     if (Verbose > 1)
-	Fprintf(stdout, "critical net %s\n", cn->name);
-     for (j = 0; j < Numnets; j++) {
-	net = Nlnets[j];
-	if (!strcmp(net->netname, (char *)cn->name)) {
-           net->netorder = i++;
-	   net->flags |= NET_CRITICAL;
-	}
-     }
-  }
-
-  switch (method) {
-      case 0:
-	 qsort((char *)Nlnets, Numnets, (int)sizeof(NET),
-			(__compar_fn_t)compNets);
-	 break;
-      case 1:
-	 qsort((char *)Nlnets, Numnets, (int)sizeof(NET),
-			(__compar_fn_t)altCompNets);
-	 break;
-  }
-
-  for (i = 0; i < Numnets; i++) {
-     net = Nlnets[i];
-     net->netorder = i++;
-  }
-
-} /* create_netorder() */
-
-/*--------------------------------------------------------------*/
-/* Measure and record the bounding box of a net.		*/
-/* This is preparatory to generating a mask for the net.	*/
-/* Find the bounding box of each node, and record that		*/
-/* information, at the same time computing the whole net's	*/
-/* bounding box as the area bounding all of the nodes.		*/
-/* Determine if the bounding box is more horizontal or		*/
-/* vertical, and specify a direction for the net's trunk line.	*/
-/* Initialize the trunk line as the midpoint between all of the	*/
-/* nodes, extending the width (or height) of the bounding box.	*/
-/* Initialize the node branch position as the line extending	*/
-/* from the middle of the node's bounding box to the trunk	*/
-/* line.  These positions (trunk and branches) will be sorted	*/
-/* and readjusted by "create_nodeorder()".			*/
-/*--------------------------------------------------------------*/
-
-void find_bounding_box(NET net)
-{
-   NODE n1, n2;
-   DPOINT d1tap, d2tap, dtap, mintap;
-   int mindist, dist, dx, dy;
-
-   if (net->numnodes == 2) {
-
-      n1 = (NODE)net->netnodes;
-      n2 = (NODE)net->netnodes->next;
-
-      // Simple 2-pass---pick up first tap on n1, find closest tap on n2,
-      // then find closest tap on n1.
-
-      d1tap = (n1->taps == NULL) ? n1->extend : n1->taps;
-      if (d1tap == NULL) return;
-      d2tap = (n2->taps == NULL) ? n2->extend : n2->taps;
-      if (d2tap == NULL) return;
-      dx = d2tap->gridx - d1tap->gridx;
-      dy = d2tap->gridy - d1tap->gridy;
-      mindist = dx * dx + dy * dy;
-      mintap = d2tap;
-      for (d2tap = d2tap->next; d2tap != NULL; d2tap = d2tap->next) {
-         dx = d2tap->gridx - d1tap->gridx;
-         dy = d2tap->gridy - d1tap->gridy;
-         dist = dx * dx + dy * dy;
-         if (dist < mindist) {
-            mindist = dist;
-            mintap = d2tap;
-         }
-      }
-      d2tap = mintap;
-      d1tap = (n1->taps == NULL) ? n1->extend : n1->taps;
-      dx = d2tap->gridx - d1tap->gridx;
-      dy = d2tap->gridy - d1tap->gridy;
-      mindist = dx * dx + dy * dy;
-      mintap = d1tap;
-      for (d1tap = d1tap->next; d1tap != NULL; d1tap = d1tap->next) {
-         dx = d2tap->gridx - d1tap->gridx;
-         dy = d2tap->gridy - d1tap->gridy;
-         dist = dx * dx + dy * dy;
-         if (dist < mindist) {
-            mindist = dist;
-            mintap = d1tap;
-         }
-      }
-      d1tap = mintap;
-
-      net->xmin = (d1tap->gridx < d2tap->gridx) ? d1tap->gridx : d2tap->gridx;
-      net->xmax = (d1tap->gridx < d2tap->gridx) ? d2tap->gridx : d1tap->gridx;
-      net->ymin = (d1tap->gridy < d2tap->gridy) ? d1tap->gridy : d2tap->gridy;
-      net->ymax = (d1tap->gridy < d2tap->gridy) ? d2tap->gridy : d1tap->gridy;
-   }
-   else {	// Net with more than 2 nodes
-
-      // Use the first tap point for each node to get a rough bounding box and
-      // centroid of all taps
-      net->xmax = net->ymax = -(MAXRT);
-      net->xmin = net->ymin = MAXRT;
-      for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) {
-         dtap = (n1->taps == NULL) ? n1->extend : n1->taps;
-	 if (dtap) {
-            if (dtap->gridx > net->xmax) net->xmax = dtap->gridx;
-            if (dtap->gridx < net->xmin) net->xmin = dtap->gridx;
-            if (dtap->gridy > net->ymax) net->ymax = dtap->gridy;
-            if (dtap->gridy < net->ymin) net->ymin = dtap->gridy;
-	 }
-      }
-   }
-}
-
-/*--------------------------------------------------------------*/
-/* defineRouteTree() ---					*/
-/*								*/
-/* Define a trunk-and-branches potential best route for a net.	*/
-/*								*/
-/* The net is analyzed for aspect ratio, and is determined if	*/
-/* it will have a horizontal or vertical trunk.  Then, each	*/
-/* node will define a branch line extending from the node	*/
-/* position to the trunk.  Trunk position is recorded in the	*/
-/* net record, and branch positions are recorded in the	node	*/
-/* records.							*/
-/*								*/
-/* To do:							*/
-/* Trunk and branch lines will be analyzed for immediate	*/
-/* collisions and sorted to help ensure a free track exists for	*/
-/* each net's trunk line.					*/
-/*--------------------------------------------------------------*/
-
-void defineRouteTree(NET net)
-{
-    NODE n1;
-    DPOINT dtap;
-    int xcent, ycent, xmin, ymin, xmax, ymax;
-
-    // This is called after create_bounding_box(), so bounds have
-    // been calculated.
-
-    xmin = net->xmin;
-    xmax = net->xmax;
-    ymin = net->ymin;
-    ymax = net->ymax;
-
-    if (net->numnodes == 2) {
-
-	// For 2-node nets, record the initial position as
-	// one horizontal trunk + one branch for one "L" of
-	// the bounding box, and one vertical trunk + one
-	// branch for the other "L" of the bounding box.
-
-	net->trunkx = xmin;
-	net->trunky = ymin;
-    }
-    else if (net->numnodes > 0) {
-
-	// Use the first tap point for each node to get a rough
-	// centroid of all taps
-
-	xcent = ycent = 0;
-	for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) {
-	    dtap = (n1->taps == NULL) ? n1->extend : n1->taps;
-	    if (dtap == NULL) continue;
-	    xcent += dtap->gridx;
-	    ycent += dtap->gridy;
-	}
-	xcent /= net->numnodes;
-	ycent /= net->numnodes;
-
-	// Record the trunk line in the net record
-
-	net->trunkx = xcent;
-	net->trunky = ycent;
-    }
-
-    if (xmax - xmin > ymax - ymin) {
-	// Horizontal trunk preferred
-	net->flags &= ~NET_VERTICAL_TRUNK;
-    }
-    else {
-	// Vertical trunk preferred
-	net->flags |= NET_VERTICAL_TRUNK;
-    }
-
-    // Set the branch line positions to the node tap points
-
-    for (n1 = net->netnodes; n1; n1 = n1->next) {
-	dtap = (n1->taps == NULL) ? n1->extend : n1->taps;
-	if (!dtap) continue;
-	n1->branchx = dtap->gridx;
-	n1->branchy = dtap->gridy;
-    }
-}
-
-/*--------------------------------------------------------------*/
 /* SetNodeinfo --						*/
 /*	Allocate a NODEINFO record and put it in the Nodeinfo	*/
 /*	array at position (gridx, gridy, d->layer).  Return the	*/
@@ -365,94 +57,6 @@ FreeNodeinfo(int gridx, int gridy, int layer)
 }
 
 /*--------------------------------------------------------------*/
-/* print_nodes - show the nodes list				*/
-/*         ARGS: filename to print to
-        RETURNS: nothing
-   SIDE EFFECTS: none
-AUTHOR and DATE: steve beccue      Tue Aug 04  2003
-\*--------------------------------------------------------------*/
-
-void print_nodes(char *filename)
-{
-  FILE *o;
-  int i;
-  NET net;
-  NODE node;
-  DPOINT dp;
-
-    if (!strcmp(filename, "stdout")) {
-	o = stdout;
-    } else {
-	o = fopen(filename, "w");
-    }
-    if (!o) {
-	Fprintf( stderr, "node.c:print_nodes.  Couldn't open output file\n" );
-	return;
-    }
-
-    for (i = 0; i < Numnets; i++) {
-       net = Nlnets[i];
-       for (node = net->netnodes; node; node = node->next) {
-	  dp = (DPOINT)node->taps;
-	  fprintf(o, "%d\t%s\t(%g,%g)(%d,%d) :%d:num=%d netnum=%d\n",
-		node->nodenum, 
-		node->netname,
-		// legacy:  print only the first point
-		dp->x, dp->y, dp->gridx, dp->gridy,
-		node->netnum, node->numnodes, node->netnum );
-		 
-	  /* need to print the routes to this node (deprecated)
-	  for (j = 0 ; j < g->nodes; j++) {
-	      fprintf(o, "%s(%g,%g) ", g->node[j], *(g->x[j]), *(g->y[j]));
-	  }
-	  */
-       }
-    }
-    fclose(o);
-
-} /* void print_nodes() */
-
-/*--------------------------------------------------------------*/
-/*C print_nlnets - show the nets				*/
-/*         ARGS: filename to print to
-        RETURNS: nothing
-   SIDE EFFECTS: none
-AUTHOR and DATE: steve beccue      Tue Aug 04  2003
-\*--------------------------------------------------------------*/
-
-void print_nlnets( char *filename )
-{
-  FILE *o;
-  int i;
-  NODE nd;
-  NET net;
-
-    if (!strcmp(filename, "stdout")) {
-	o = stdout;
-    } else {
-	o = fopen(filename, "w");
-    }
-    if (!o) {
-	Fprintf(stderr, "node.c:print_nlnets.  Couldn't open output file\n");
-	return;
-    }
-
-    for (i = 0; i < Numnets; i++) {
-        net = Nlnets[i];
-	fprintf(o, "%d\t#=%d\t%s   \t\n", net->netnum, 
-		 net->numnodes, net->netname);
-
-	for (nd = net->netnodes; nd; nd = nd->next) {
-	   fprintf(o, "%d ", nd->nodenum);
-	}
-    }
-
-    fprintf(o, "%d nets\n", Numnets);
-    fflush(o);
-
-} /* void print_nlnets() */
-
-/*--------------------------------------------------------------*/
 /* count_reachable_taps()					*/
 /*								*/
 /*  For each grid point in the layout, find if it corresponds	*/
@@ -2204,13 +1808,13 @@ void create_obstructions_outside_nodes(void)
                                 }
 
 				lnode = SetNodeinfo(gridx, gridy, ds->layer);
+				lnode->nodeloc = node;
+				lnode->nodesav = node;
 
 				if ((k < Numnets) && (dir != NI_STUB_MASK)) {
 				   OBSVAL(gridx, gridy, ds->layer)
 				   	= (OBSVAL(gridx, gridy, ds->layer)
 					  & BLOCKED_MASK) | (u_int)g->netnum[i] | mask; 
-				   lnode->nodeloc = node;
-				   lnode->nodesav = node;
 				   lnode->flags |= dir;
 				}
 				else if ((OBSVAL(gridx, gridy, ds->layer)
diff --git a/output.c b/output.c
new file mode 100644
index 0000000..61e9520
--- /dev/null
+++ b/output.c
@@ -0,0 +1,2039 @@
+/*--------------------------------------------------------------*/
+/*  output.c -- qrouter general purpose autorouter              */
+/*  output routines for writing DEF file			*/
+/*--------------------------------------------------------------*/
+/* Written by Tim Edwards, June 2011, based on code by Steve	*/
+/* Beccue, 2003							*/
+/*--------------------------------------------------------------*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef TCL_QROUTER
+#include <tk.h>
+#endif
+
+#include "qrouter.h"
+#include "qconfig.h"
+#include "point.h"
+#include "node.h"
+#include "maze.h"
+#include "mask.h"
+#include "output.h"
+#include "lef.h"
+#include "def.h"
+#include "graphics.h"
+
+int  Pathon = -1;
+
+/*--------------------------------------------------------------*/
+/* Write the output annotated DEF file.				*/
+/*--------------------------------------------------------------*/
+
+int write_def(char *filename)
+{
+   NET net;
+   NETLIST nl;
+
+   emit_routes((filename == NULL) ? DEFfilename : filename,
+		Scales.oscale, Scales.iscale);
+
+   Fprintf(stdout, "----------------------------------------------\n");
+   Fprintf(stdout, "Final: ");
+   if (FailedNets == (NETLIST)NULL)
+      Fprintf(stdout, "No failed routes!\n");
+   else {
+      if (FailedNets != (NETLIST)NULL) {
+         Fprintf(stdout, "Failed net routes: %d\n", countlist(FailedNets));
+	 Fprintf(stdout, "List of failed nets follows:\n");
+
+	 // Make sure FailedNets is cleaned up as we output the failed nets
+
+ 	 while (FailedNets) {
+	    net = FailedNets->net;
+	    Fprintf(stdout, " %s\n", net->netname);
+	    nl = FailedNets->next;
+	    free(FailedNets);
+	    FailedNets = nl;
+	 }
+	 Fprintf(stdout, "\n");
+      }
+   }
+   Fprintf(stdout, "----------------------------------------------\n");
+
+   return 0;
+
+} /* write_def() */
+
+/*--------------------------------------------------------------*/
+/* pathstart - begin a DEF format route path           		*/
+/*								*/
+/* 	If "special" is true, then this path is in a		*/
+/*	SPECIALNETS section, in which each route specifies	*/
+/*	a width.						*/
+/*--------------------------------------------------------------*/
+
+static void
+pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale,
+          double invscale, u_char horizontal)
+{
+   if (Pathon == 1) {
+      Fprintf( stderr, "pathstart():  Major error.  Started a new "
+		"path while one is in progress!\n"
+		"Doing it anyway.\n" );
+   }
+
+   if (layer >= 0) {
+      if (Pathon == -1)
+	 fprintf(cmd, "+ ROUTED ");
+      else
+	 fprintf(cmd, "\n  NEW ");
+      if (special) {
+	 double wvia;
+
+	 wvia = LefGetViaWidth(layer, layer, horizontal);
+	 if (layer > 0) { 
+	    double wvia2;
+	    wvia2 = LefGetViaWidth(layer - 1, layer, horizontal);
+	    if (wvia2 > wvia) wvia = wvia2;
+         }
+
+         fprintf(cmd, "%s %g ( %g %g ) ", CIFLayer[layer],
+			invscale * (int)(oscale * wvia + 0.5),
+			invscale * x, invscale * y);
+      }
+      else
+         fprintf(cmd, "%s ( %g %g ) ", CIFLayer[layer], invscale * x, invscale * y);
+   }
+   Pathon = 1;
+
+} /* pathstart() */
+
+/*--------------------------------------------------------------*/
+/* pathto  - continue a path to the next point        		*/
+/*								*/
+/*   ARGS: coordinate pair					*/
+/*   RETURNS: 							*/
+/*   SIDE EFFECTS: 						*/
+/*--------------------------------------------------------------*/
+
+static void
+pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty,
+       double invscale)
+{
+    if (Pathon <= 0) {
+	Fprintf(stderr, "pathto():  Major error.  Added to a "
+		"non-existent path!\n"
+		"Doing it anyway.\n");
+    }
+
+    /* If the route is not manhattan, then it's because an offset
+     * was added to the last point, and we need to add a small
+     * jog to the route.
+     */
+
+    if ((x != lastx) && (y != lasty)) {
+	if (horizontal)
+	   pathto(cmd, lastx, y, FALSE, lastx, lasty, invscale);
+	else
+	   pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale);
+    }
+
+    fprintf(cmd, "( ");
+    if (horizontal)
+	fprintf(cmd, "%g ", invscale * x);
+    else
+	fprintf(cmd, "* ");
+
+    if (horizontal)
+	fprintf(cmd, "* ");
+    else
+	fprintf(cmd, "%g ", invscale * y);
+
+    fprintf(cmd, ") ");
+
+} /* pathto() */
+
+/*--------------------------------------------------------------*/
+/* pathvia  - add a via to a path               		*/
+/*								*/
+/*   ARGS: coord						*/
+/*   RETURNS: 							*/
+/*   SIDE EFFECTS: 						*/
+/*--------------------------------------------------------------*/
+
+static void
+pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty,
+        int gridx, int gridy, double invscale)
+{
+    char *s;
+    char checkersign = (gridx + gridy + layer) & 0x01;
+
+    if ((ViaPattern == VIA_PATTERN_NONE) || (ViaY[layer] == NULL))
+	s = ViaX[layer];
+    else if (ViaPattern == VIA_PATTERN_NORMAL)
+	s = (checkersign == 0) ?  ViaX[layer] : ViaY[layer];
+    else
+	s = (checkersign == 0) ?  ViaY[layer] : 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);
+    }
+    else {
+       // Normally the path will be manhattan and only one of
+       // these will be true.  But if the via gets an offset to
+       // avoid a DRC spacing violation with an adjacent via,
+       // then we may need to apply both paths to make a dog-leg
+       // route to the via.
+
+       if (x != lastx)
+	  pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale);
+       if (y != lasty)
+	  pathto(cmd, x, y, FALSE, x, lasty, invscale);
+    }
+    fprintf(cmd, "%s ", s);
+    Pathon = 0;
+
+} /* pathvia() */
+
+/*--------------------------------------------------------------*/
+/* Nodes aren't saved in a way that makes it easy to recall	*/
+/* the name of the cell and pin to which they belong.  But	*/
+/* that information doesn't need to be looked up except as a	*/
+/* diagnostic output.  This routine does that lookup.		*/
+/*--------------------------------------------------------------*/
+
+char *print_node_name(NODE node)
+{
+    GATE g;
+    int i;
+    static char *nodestr = NULL;
+
+    for (g = Nlgates; g; g = g->next) {
+	for (i = 0; i < g->nodes; i++) {
+	    if (g->noderec[i] == node) {
+		if (nodestr != NULL)
+		   free(nodestr);
+
+		nodestr = (char *)malloc(strlen(g->gatename)
+			+ strlen(g->node[i]) + 2);
+		if (!strcmp(g->node[i], "pin"))
+		    sprintf(nodestr, "PIN/%s", g->gatename);
+		else
+		    sprintf(nodestr, "%s/%s", g->gatename, g->node[i]);
+		return nodestr;
+	    }
+	}
+    }
+    if (nodestr != NULL) free(nodestr);
+    nodestr = (char *)malloc(22);
+    sprintf(nodestr, "(error: no such node)");
+    return nodestr;
+}
+
+/*--------------------------------------------------------------*/
+/* print_nets - print the nets list - created from Nlgates list */
+/*								*/
+/*   ARGS: filename to list to					*/
+/*   RETURNS: nothing						*/
+/*   SIDE EFFECTS: 						*/
+/*   AUTHOR and DATE: steve beccue      Sat July 26		*/
+/*--------------------------------------------------------------*/
+
+void print_nets(char *filename)
+{
+   FILE *o;
+   GATE g;
+   int i;
+   DSEG drect;
+
+   if (!strcmp(filename, "stdout")) {
+	o = stdout;
+   } else {
+	o = fopen(filename, "w");
+   }
+   if (!o) {
+	Fprintf(stderr, "route:print_nets.  Couldn't open output file\n");
+	return;
+   }
+
+   for (g = Nlgates; g; g = g->next) {
+      fprintf(o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename);
+      for (i = 0; i < g->nodes; i++) {
+	 // This prints the first tap position only.
+	 drect = g->taps[i];
+	 fprintf( o, "%s(%g,%g) ", g->node[i], drect->x1, drect->y1);
+      }
+   }
+   fprintf( o, "\n");
+} /* print_nets() */
+
+/*--------------------------------------------------------------*/
+/* print_routes - print the routes list				*/
+/*								*/
+/*   ARGS: filename to list to					*/
+/*   RETURNS: nothing						*/
+/*   SIDE EFFECTS: 						*/
+/*   AUTHOR and DATE: steve beccue      Sat July 26		*/
+/*--------------------------------------------------------------*/
+
+void print_routes( char *filename )
+{
+    FILE *o;
+    GATE g;
+    int i;
+
+    if( !strcmp( filename, "stdout" ) ) {
+	o = stdout;
+    } else {
+	o = fopen( filename, "w" );
+    }
+    if( !o ) {
+	Fprintf( stderr, "route:print_routes.  Couldn't open output file\n" );
+	return;
+    }
+
+    for (g = Nlgates; g; g = g->next) {
+	fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename );
+	for( i = 0 ; i < g->nodes; i++ ) {
+	    fprintf( o, "%s ", g->node[i] );
+	}
+	fprintf(o, "\n");
+    }
+} /* print_routes() */
+
+/*--------------------------------------------------------------*/
+/* print_nlgates - print the nlgate list			*/
+/*								*/
+/*   ARGS: filename to list to					*/
+/*   RETURNS: nothing						*/
+/*   SIDE EFFECTS: 						*/
+/*   AUTHOR and DATE: steve beccue      Wed July 23		*/
+/*--------------------------------------------------------------*/
+
+void print_nlgates( char *filename )
+{
+    FILE *o;
+    GATE g;
+    int i;
+    DSEG drect;
+
+    if( !strcmp( filename, "stdout" ) ) {
+	o = stdout;
+    } else {
+	o = fopen( filename, "w" );
+    }
+    if( !o ) {
+	Fprintf( stderr, "route:print_nlgates.  Couldn't open output file\n" );
+	return;
+    }
+
+    for (g = Nlgates; g; g = g->next) {
+	fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename );
+	for( i = 0 ; i < g->nodes; i++ ) {
+	    // This prints the first tap position only.
+	    drect = g->taps[i];
+	    fprintf( o, "%s(%g,%g)", g->node[i], drect->x1, drect->y1);
+	}
+        fprintf(o, "\n");
+    }
+} /* print_nlgates() */
+
+
+/*--------------------------------------------------------------*/
+/* print_net - print info about the net to stdout               */
+/*								*/
+/*   ARGS: net to print info about				*/
+/*   RETURNS: nothing						*/
+/*   SIDE EFFECTS: 						*/
+/*--------------------------------------------------------------*/
+
+void print_net(NET net) {
+    NODE node;
+    DPOINT tap;
+    int i, first;
+
+    Fprintf(stdout, "Net %d: %s", net->netnum, net->netname);
+    for (node = net->netnodes; node != NULL; node = node->next) {
+        Fprintf(stdout, "\n  Node %d: \n    Taps: ", node->nodenum);
+        for (tap = node->taps, i = 0, first = TRUE;
+             tap != NULL;
+             tap = tap->next, i = (i + 1) % 4, first = FALSE) {
+            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
+                    (i == 0 ? (first ? "" : "\n        ") : " "),
+                    tap->layer, tap->x, tap->y
+            );
+        }
+        Fprintf(stdout, "\n    Tap extends: ");
+        for (tap = node->extend, i = 0, first = TRUE;
+             tap != NULL;
+             tap = tap->next, i = (i + 1) % 4, first = FALSE) {
+            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
+                    (i == 0 ? (first ? "" : "\n        ") : " "),
+                    tap->layer, tap->x, tap->y
+            );
+        }
+    }
+    Fprintf(stdout, "\n  bbox: (%d,%d)-(%d,%d)\n",
+            net->xmin, net->ymin, net->xmax, net->ymax
+    );
+}
+
+
+/*--------------------------------------------------------------*/
+/* print_gate - print info about the net to stdout              */
+/*								*/
+/*   ARGS: gate to print info about				*/
+/*   RETURNS: nothing						*/
+/*   SIDE EFFECTS: 						*/
+/*--------------------------------------------------------------*/
+
+void print_gate(GATE gate) {
+    int i, j, first;
+    DSEG seg;
+    NODE node;
+    DPOINT tap;
+
+    Fprintf(stdout, "Gate %s\n", gate->gatename);
+    Fprintf(stdout, "  Loc: (%.2lf, %.2lf), WxH: %.2lfx%.2lf\n",
+            gate->placedX, gate->placedY, gate->width, gate->height
+    );
+    Fprintf(stdout, "  Pins");
+    for (i = 0; i < gate->nodes; i++) {
+        Fprintf(stdout, "\n    Pin %s, net %d\n",
+                gate->node[i], gate->netnum[i]
+        );
+        Fprintf(stdout, "      Segs: ");
+        for (seg = gate->taps[i], j = 0, first = TRUE;
+             seg != NULL;
+             seg = seg->next, j = (j + 1) % 3, first = FALSE) {
+            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)-(%.2lf,%.2lf)",
+                    (j == 0 ? (first ? "" : "\n        ") : " "),
+                    seg->layer, seg->x1, seg->y1, seg->x2, seg->y2
+            );
+        }
+        if ((node = gate->noderec[i]) != NULL) {
+            Fprintf(stdout, "\n      Taps: ");
+            for (tap = node->taps, j = 0, first = TRUE;
+                 tap != NULL;
+                 tap = tap->next, j = (j + 1) % 4, first = FALSE) {
+                Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
+                        (j == 0 ? (first ? "" : "\n        ") : " "),
+                        tap->layer, tap->x, tap->y
+                );
+            }
+            Fprintf(stdout, "\n      Tap extends: ");
+            for (tap = node->extend, j = 0, first = TRUE;
+                 tap != NULL;
+                 tap = tap->next, j = (j + 1) % 4, first = FALSE) {
+                Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
+                        (j == 0 ? (first ? "" : "\n        ") : " "),
+                        tap->layer, tap->x, tap->y
+                );
+            }
+        }
+    }
+    Fprintf(stdout, "\n  Obstructions: ");
+    for (seg = gate->obs, j = 0, first = TRUE;
+         seg != NULL;
+         seg = seg->next, j = (j + 1) % 3, first = FALSE) {
+        Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)-(%.2lf,%.2lf)",
+                (j == 0 ? (first ? "" : "\n    ") : " "),
+                seg->layer, seg->x1, seg->y1, seg->x2, seg->y2
+        );
+    }
+    Fprintf(stdout, "\n");
+}
+
+/*--------------------------------------------------------------*/
+/* print_nodes - show the nodes list				*/
+/*								*/
+/*    ARGS: filename to print to				*/
+/*    RETURNS: nothing						*/
+/*    SIDE EFFECTS: none					*/
+/*    AUTHOR and DATE: steve beccue      Tue Aug 04  2003	*/
+/*--------------------------------------------------------------*/
+
+void print_nodes(char *filename)
+{
+  FILE *o;
+  int i;
+  NET net;
+  NODE node;
+  DPOINT dp;
+
+    if (!strcmp(filename, "stdout")) {
+	o = stdout;
+    } else {
+	o = fopen(filename, "w");
+    }
+    if (!o) {
+	Fprintf( stderr, "node.c:print_nodes.  Couldn't open output file\n" );
+	return;
+    }
+
+    for (i = 0; i < Numnets; i++) {
+       net = Nlnets[i];
+       for (node = net->netnodes; node; node = node->next) {
+	  dp = (DPOINT)node->taps;
+	  fprintf(o, "%d\t%s\t(%g,%g)(%d,%d) :%d:num=%d netnum=%d\n",
+		node->nodenum, 
+		node->netname,
+		// legacy:  print only the first point
+		dp->x, dp->y, dp->gridx, dp->gridy,
+		node->netnum, node->numnodes, node->netnum );
+		 
+	  /* need to print the routes to this node (deprecated)
+	  for (j = 0 ; j < g->nodes; j++) {
+	      fprintf(o, "%s(%g,%g) ", g->node[j], *(g->x[j]), *(g->y[j]));
+	  }
+	  */
+       }
+    }
+    fclose(o);
+
+} /* print_nodes() */
+
+/*--------------------------------------------------------------*/
+/* print_nlnets - show the nets					*/
+/*								*/
+/*   ARGS: filename to print to					*/
+/*   RETURNS: nothing						*/
+/*   SIDE EFFECTS: none						*/
+/*   AUTHOR and DATE: steve beccue      Tue Aug 04  2003	*/
+/*--------------------------------------------------------------*/
+
+void print_nlnets( char *filename )
+{
+  FILE *o;
+  int i;
+  NODE nd;
+  NET net;
+
+    if (!strcmp(filename, "stdout")) {
+	o = stdout;
+    } else {
+	o = fopen(filename, "w");
+    }
+    if (!o) {
+	Fprintf(stderr, "node.c:print_nlnets.  Couldn't open output file\n");
+	return;
+    }
+
+    for (i = 0; i < Numnets; i++) {
+        net = Nlnets[i];
+	fprintf(o, "%d\t#=%d\t%s   \t\n", net->netnum, 
+		 net->numnodes, net->netname);
+
+	for (nd = net->netnodes; nd; nd = nd->next) {
+	   fprintf(o, "%d ", nd->nodenum);
+	}
+    }
+
+    fprintf(o, "%d nets\n", Numnets);
+    fflush(o);
+
+} /* print_nlnets() */
+
+/*--------------------------------------------------------------*/
+/* cleanup_net --						*/
+/*								*/
+/* Special handling for layers where needblock[] is non-zero,	*/
+/* and shows that two vias cannot be placed on adjacent routes. */
+/* emit_routed_net() will add specialnets to merge two adjacent	*/
+/* vias on the same route.  However, this cannot be used for	*/
+/* adjacent vias that are each in a different route record.  It	*/
+/* is easier just to find any such instances and remove them by	*/
+/* eliminating one of the vias and adding a segment to connect	*/
+/* the route to the neighboring via.				*/
+/*--------------------------------------------------------------*/
+
+static void cleanup_net(NET net)
+{
+   SEG segf, segl, seg;
+   ROUTE rt, rt2;
+   NODEINFO lnode;
+   int lf, ll, lf2, ll2;
+   u_char fcheck, lcheck;
+   u_char xcheckf, ycheckf, xcheckl, ycheckl; 
+
+   lf = ll = lf2 = ll2 = -1;
+
+   for (rt = net->routes; rt; rt = rt->next) {
+      fcheck = lcheck = FALSE;
+
+      // This problem will only show up on route endpoints.
+      // segf is the first segment of the route.
+      // segl is the last segment of the route.
+      // lf is the layer at the route start (layer first)
+      // lf2 is the layer of the second segment.
+      // ll is the layer at the route end (layer last)
+      // ll2 is the layer of the next-to-last segment
+
+      segf = rt->segments;
+      if (segf == NULL) continue;
+      if ((segf->next != NULL) && (segf->segtype == ST_VIA)) {
+	 if (segf->next->layer > segf->layer) {
+	    lf = segf->layer;
+	    lf2 = segf->layer + 1;
+	 }
+	 else {
+	    lf = segf->layer + 1;
+	    lf2 = segf->layer;
+	 }
+         // Set flag fcheck indicating that segf needs checking
+	 fcheck = TRUE;
+
+	 // We're going to remove the contact so it can't be a tap
+	 if ((lf < Pinlayers) && ((lnode = NODEIPTR(segf->x1, segf->y1, lf)) != NULL)
+			&& (lnode->nodesav != NULL))
+	    fcheck = FALSE;
+      }
+      xcheckf = needblock[lf] & VIABLOCKX;
+      ycheckf = needblock[lf] & VIABLOCKY;
+      if (!xcheckf && !ycheckf) fcheck = FALSE;
+
+      // Move to the next-to-last segment
+      for (segl = segf->next; segl && segl->next && segl->next->next;
+		segl = segl->next);
+
+      if (segl && (segl->next != NULL) && (segl->next->segtype == ST_VIA)) {
+	 if (segl->next->layer < segl->layer) {
+	    ll = segl->next->layer;
+	    ll2 = segl->next->layer + 1;
+	 }
+	 else {
+	    ll = segl->next->layer + 1;
+	    ll2 = segl->next->layer;
+	 }
+	 // Move segl to the last segment
+	 segl = segl->next;
+	 // Set flag lcheck indicating that segl needs checking.
+	 lcheck = TRUE;
+
+	 // We're going to remove the contact so it can't be a tap
+	 if ((ll < Pinlayers) && ((lnode = NODEIPTR(segl->x1, segl->y1, ll)) != NULL)
+			&& (lnode->nodesav != NULL))
+	    lcheck = FALSE;
+      }
+      xcheckl = needblock[ll] & VIABLOCKX;
+      ycheckl = needblock[ll] & VIABLOCKY;
+      if (!xcheckl && !ycheckl) lcheck = FALSE;
+
+      // For each route rt2 that is not rt, look at every via
+      // and see if it is adjacent to segf or segl.
+
+      for (rt2 = net->routes; rt2; rt2 = rt2->next) {
+
+         if ((fcheck == FALSE) && (lcheck == FALSE)) break;
+         if (rt2 == rt) continue;
+
+         for (seg = rt2->segments; seg; seg = seg->next) {
+	    if (seg->segtype & ST_VIA) {
+	       if (fcheck) {
+		  if ((seg->layer == lf) || ((seg->layer + 1) == lf)) {
+		     if (xcheckf && (seg->y1 == segf->y1) &&
+				(ABSDIFF(seg->x1, segf->x1) == 1)) {
+			if (seg->layer != segf->layer) {
+
+			   // Adjacent vias are different types.
+			   // Deal with it by creating a route between
+			   // the vias on their shared layer.  This
+			   // will later be made into a special net to
+			   // avoid notch DRC errors.
+
+			   SEG newseg;
+			   newseg = (SEG)malloc(sizeof(struct seg_));
+			   rt->segments = newseg;
+			   newseg->next = segf;
+			   newseg->layer = lf;
+			   newseg->segtype = ST_WIRE;
+			   newseg->x1 = segf->x1;
+			   newseg->y1 = segf->y1;
+			   newseg->x2 = seg->x1; 
+			   newseg->y2 = seg->y1;
+			}
+			else {
+			   // Change via to wire route, connect it to seg,
+			   // and make sure it has the same layer type as
+			   // the following route.
+			   segf->segtype = ST_WIRE;
+			   segf->x1 = seg->x1;
+			   segf->layer = lf2;
+		        }
+		     }
+		     else if (ycheckf && (seg->x1 == segf->x1) &&
+				(ABSDIFF(seg->y1, segf->y1) == 1)) {
+			if (seg->layer != segf->layer) {
+			   // Adjacent vias are different types.
+			   // Deal with it by creating a route between
+			   // the vias on their shared layer.  This
+			   // will later be made into a special net to
+			   // avoid notch DRC errors.
+
+			   SEG newseg;
+			   newseg = (SEG)malloc(sizeof(struct seg_));
+			   rt->segments = newseg;
+			   newseg->next = segf;
+			   newseg->layer = lf;
+			   newseg->segtype = ST_WIRE;
+			   newseg->x1 = segf->x1;
+			   newseg->y1 = segf->y1;
+			   newseg->x2 = seg->x1; 
+			   newseg->y2 = seg->y1;
+		        }
+		        else {
+			   // Change via to wire route, connect it to seg,
+			   // and make sure it has the same layer type as
+			   // the following route.
+			   segf->segtype = ST_WIRE;
+			   segf->y1 = seg->y1;
+			   segf->layer = lf2;
+			}
+		     }
+		  }
+	       }
+
+               if (lcheck) {
+		  if ((seg->layer == ll) || ((seg->layer + 1) == ll)) {
+		     if (xcheckl && (seg->y1 == segl->y1) &&
+				(ABSDIFF(seg->x1, segl->x1) == 1)) {
+			if (seg->layer != segl->layer) {
+
+			   // Adjacent vias are different types.
+			   // Deal with it by creating a route between
+			   // the vias on their shared layer.  This
+			   // will later be made into a special net to
+			   // avoid notch DRC errors.
+
+			   SEG newseg;
+			   newseg = (SEG)malloc(sizeof(struct seg_));
+			   segl->next = newseg;
+			   newseg->next = NULL;
+			   newseg->layer = ll;
+			   newseg->segtype = ST_WIRE;
+			   newseg->x1 = segl->x1;
+			   newseg->y1 = segl->y1;
+			   newseg->x2 = seg->x1; 
+			   newseg->y2 = seg->y1;
+			}
+			else {
+			   // Change via to wire route, connect it to seg,
+			   // and make sure it has the same layer type as
+			   // the previous route.
+			   segl->segtype = ST_WIRE;
+			   segl->x2 = seg->x2;
+			   segl->layer = ll2;
+			}
+		     }
+		     else if (ycheckl && (seg->x1 == segl->x1) &&
+				(ABSDIFF(seg->y1, segl->y1) == 1)) {
+			if (seg->layer != segl->layer) {
+
+			   // Adjacent vias are different types.
+			   // Deal with it by creating a route between
+			   // the vias on their shared layer.  This
+			   // will later be made into a special net to
+			   // avoid notch DRC errors.
+
+			   SEG newseg;
+			   newseg = (SEG)malloc(sizeof(struct seg_));
+			   segl->next = newseg;
+			   newseg->next = NULL;
+			   newseg->layer = ll;
+			   newseg->segtype = ST_WIRE;
+			   newseg->x1 = segl->x1;
+			   newseg->y1 = segl->y1;
+			   newseg->x2 = seg->x1; 
+			   newseg->y2 = seg->y1;
+			}
+			else {
+			   // Change via to wire route, connect it to seg,
+			   // and make sure it has the same layer type as
+			   // the previous route.
+			   segl->segtype = ST_WIRE;
+			   segl->y2 = seg->y2;
+			   segl->layer = ll2;
+			}
+		     }
+		  }
+	       }
+	    }
+	 }
+      }
+   }
+}
+
+/*--------------------------------------------------------------*/
+/* emit_routed_net --						*/
+/*								*/
+/* Core part of emit_routes().  Dumps the DEF format for a	*/
+/* complete net route to file Cmd.  If "special" is TRUE, then	*/
+/* it looks only for stub routes between a grid point and an	*/
+/* off-grid terminal, and dumps only the stub route geometry as	*/
+/* a SPECIALNET, which takes a width parameter.  This allows	*/
+/* the stub routes to be given the same width as a via, when	*/
+/* the via is larger than a route width, to avoid DRC notch	*/
+/* errors between the via and the terminal.  The SPECIALNETS	*/
+/* are redundant;  all routing information is in the NETS	*/
+/* section.  The SPECIALNETS only specify a wider route for the	*/
+/* stub connection.						*/
+/*--------------------------------------------------------------*/
+
+static void
+emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
+{
+   SEG seg, saveseg, lastseg, prevseg;
+   NODEINFO lnode, lnode1, lnode2;
+   ROUTE rt;
+   u_int dir1, dir2, tdir;
+   int layer;
+   int x = 0, y = 0, x2, y2;
+   double dc;
+   int lastx = -1, lasty = -1, lastlay;
+   int horizontal;
+   float offset1, offset2, stub, offset;
+   u_char cancel, segtype;
+   double invscale = (double)(1.0 / (double)iscale); 
+
+   /* If the STUB flag is set, then we need to write out the net name	*/
+   /* in the SPECIALNETS section.					*/
+
+   if ((special == (u_char)1) && (net->flags & NET_STUB)) {
+      fprintf(Cmd, ";\n- %s\n", net->netname);
+   }
+
+   u_char viaCheckX[MAX_LAYERS];
+   u_char viaCheckY[MAX_LAYERS];
+   double viaOffsetX[MAX_LAYERS][3];
+   double viaOffsetY[MAX_LAYERS][3];
+
+   /* Compute via offsets, if needed for adjacent vias on different nets. */
+
+   /* A well-designed standard cell set should not have DRC errors	*/
+   /* between vias spaced on adjacent tracks.  But not every standard	*/
+   /* cell set is well-designed. . .					*/
+
+   /* Example of offset measurements:					*/
+   /* viaOffsetX[layer][n]:  layer is the base layer of the via, n is	*/
+   /* 0 for the via one layer below, 1 for the same via, and 2 for the	*/
+   /* via one layer above.  Note that the n = 1 has interactions on two	*/
+   /* different metal layers.  The maximum distance is used.		*/
+
+   /* viaCheckX[1] is 0 if all of viaOffsetX[1][0-2] is zero.  This	*/
+   /*	 allows a quick determination if a check for neighboring vias	*/
+   /*    is required.							*/
+   /* viaOffsetX[1][0] is the additional spacing above the grid	width	*/
+   /*	 for via2-to-via1 (on metal2 only).				*/
+   /* viaOffsetX[1][1] is the additional spacing above the grid	width	*/
+   /*	 for via2-to-via2 (maximum for metal2 and metal3)		*/
+   /* viaOffsetX[1][2] is the additional spacing above the grid	width	*/
+   /*	 for via2-to-via3 (on metal3 only).				*/
+
+   viaOffsetX[0][0] = 0;		// nothing below the 1st via
+   viaOffsetY[0][0] = 0;
+   viaOffsetX[Num_layers - 1][2] = 0;	// nothing above the last via
+   viaOffsetY[Num_layers - 1][2] = 0;
+
+   for (layer = 0; layer < Num_layers - 1; layer++) {
+      double s1  = LefGetRouteSpacing(layer);
+      double s2  = LefGetRouteSpacing(layer + 1);
+      double p1x = PitchX[layer];
+      double p2x = PitchX[layer + 1];
+      double p1y = PitchY[layer];
+      double p2y = PitchY[layer + 1];
+      double w1x = LefGetViaWidth(layer, layer, 0);
+      double w1y = LefGetViaWidth(layer, layer, 1);
+      double w2x = LefGetViaWidth(layer, layer + 1, 0);
+      double w2y = LefGetViaWidth(layer, layer + 1, 1);
+    
+      double w0x, w0y, w3x, w3y;
+
+      viaCheckX[layer] = 0;
+      viaCheckY[layer] = 0;
+
+      if (layer > 0) {
+
+	 /* Space from via to (via - 1) */
+
+         w0x = LefGetViaWidth(layer - 1, layer, 0);
+         w0y = LefGetViaWidth(layer - 1, layer, 1);
+
+         dc = s1 + (w1x + w0x) / 2 - p1x;
+         viaOffsetX[layer][0] = (dc > 0.0) ? dc : 0.0;
+
+         dc = s1 + (w1y + w0y) / 2 - p1y;
+         viaOffsetY[layer][0] = (dc > 0.0) ? dc : 0.0;
+      }
+
+      /* Space from via to via (check both lower and upper metal layers) */
+
+      dc = s1 + w1x - p1x;
+      viaOffsetX[layer][1] = (dc > 0.0) ? dc : 0.0;
+
+      dc = s2 + w2x - p2x;
+      if (dc < 0.0) dc = 0.0;
+      if (dc > viaOffsetX[layer][1]) viaOffsetX[layer][1] = dc;
+
+      dc = s1 + w1y - p1y;
+      viaOffsetY[layer][1] = (dc > 0.0) ? dc : 0.0;
+
+      dc = s2 + w2y - p2y;
+      if (dc < 0.0) dc = 0.0;
+      if (dc > viaOffsetY[layer][1]) viaOffsetY[layer][1] = dc;
+
+      if (layer < Num_layers - 1) {
+
+	 /* Space from via to (via + 1) */
+
+         w3x = LefGetViaWidth(layer + 1, layer, 0);
+         w3y = LefGetViaWidth(layer + 1, layer, 1);
+
+         dc = s2 + (w2x + w3x) / 2 - p2x;
+         viaOffsetX[layer][2] = (dc > 0.0) ? dc : 0.0;
+
+         dc = s2 + (w2y + w3y) / 2 - p2y;
+         viaOffsetY[layer][2] = (dc > 0.0) ? dc : 0.0;
+      }
+
+      if (viaOffsetX[layer][0] > 0 || viaOffsetX[layer][1] > 0 ||
+		viaOffsetX[layer][2] > 0)
+	 viaCheckX[layer] = 1;
+      if (viaOffsetY[layer][0] > 0 || viaOffsetY[layer][1] > 0 ||
+		viaOffsetY[layer][2] > 0)
+	 viaCheckY[layer] = 1;
+   }
+
+   Pathon = -1;
+   lastlay = -1;
+
+   /* Insert routed net here */
+   for (rt = net->routes; rt; rt = rt->next) {
+      if (rt->segments && !(rt->flags & RT_OUTPUT)) {
+	 horizontal = FALSE;
+	 cancel = FALSE;
+
+	 // Check first position for terminal offsets
+	 seg = (SEG)rt->segments;
+	 lastseg = saveseg = seg;
+	 layer = seg->layer;
+	 if (seg) {
+
+	    // It is rare but possible to have a stub route off of an
+	    // endpoint via, so check this case, and use the layer type
+	    // of the via top if needed.
+
+	    if ((seg->segtype & ST_VIA) && seg->next && (seg->next->layer <=
+			seg->layer))
+	       layer++;
+
+	    lnode = (layer < Pinlayers) ? NODEIPTR(seg->x1, seg->y1, layer) : NULL;
+	    stub = (lnode) ? lnode->stub : 0.0;
+	    if (OBSVAL(seg->x1, seg->y1, layer) & STUBROUTE) {
+	       if ((special == (u_char)0) && (Verbose > 2))
+		  Fprintf(stdout, "Stub route distance %g to terminal"
+				" at %d %d (%d)\n", stub,
+				seg->x1, seg->y1, layer);
+
+	       dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
+	       x = (int)((REPS(dc)) * oscale);
+	       if (lnode->flags & NI_STUB_EW)
+		  dc += stub;
+	       x2 = (int)((REPS(dc)) * oscale);
+	       dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
+	       y = (int)((REPS(dc)) * oscale);
+	       if (lnode->flags & NI_STUB_NS)
+		  dc += stub;
+	       y2 = (int)((REPS(dc)) * oscale);
+	       if (lnode->flags & NI_STUB_EW) {
+		  horizontal = TRUE;
+
+		  // If the gridpoint ahead of the stub has a route
+		  // on the same net, and the stub is long enough
+		  // to come within a DRC spacing distance of the
+		  // other route, then lengthen it to close up the
+		  // distance and resolve the error.  (NOTE:  This
+		  // unnecessarily stretches routes to cover taps
+		  // that have not been routed to.  At least on the
+		  // test standard cell set, these rules remove a
+		  // handful of DRC errors and don't create any new
+		  // ones.  If necessary, a flag can be added to
+		  // distinguish routes from taps.
+
+		  if ((x < x2) && (seg->x1 < (NumChannelsX[layer] - 1))) {
+		     tdir = OBSVAL(seg->x1 + 1, seg->y1, layer);
+		     if ((tdir & ROUTED_NET_MASK) ==
+					(net->netnum | ROUTED_NET)) {
+			if (stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
+		      	   dc = Xlowerbound + (double)(seg->x1 + 1)
+					* PitchX[layer];
+		      	   x2 = (int)((REPS(dc)) * oscale);
+			}
+		     }
+		  }
+		  else if ((x > x2) && (seg->x1 > 0)) {
+		     tdir = OBSVAL(seg->x1 - 1, seg->y1, layer);
+		     if ((tdir & ROUTED_NET_MASK) ==
+					(net->netnum | ROUTED_NET)) {
+			if (-stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
+		      	   dc = Xlowerbound + (double)(seg->x1 - 1)
+					* PitchX[layer];
+		      	   x2 = (int)((REPS(dc)) * oscale);
+			}
+		     }
+		  }
+
+		  dc = oscale * 0.5 * LefGetRouteWidth(layer);
+		  if (special == (u_char)0) {
+		     // Regular nets include 1/2 route width at
+		     // the ends, so subtract from the stub terminus
+		     if (x < x2) {
+			x2 -= dc;
+			if (x >= x2) cancel = TRUE;
+		     }
+		     else {
+			x2 += dc;
+			if (x <= x2) cancel = TRUE;
+		     }
+		  }
+		  else {
+		     // Special nets don't include 1/2 route width
+		     // at the ends, so add to the route at the grid
+		     if (x < x2)
+			x -= dc;
+		     else
+			x += dc;
+
+		     // Routes that extend for more than one track
+		     // without a bend do not need a wide stub
+		     if (seg->x1 != seg->x2) cancel = TRUE;
+	  	  }
+	       }
+	       else {
+		  horizontal = FALSE;
+
+		  // If the gridpoint ahead of the stub has a route
+		  // on the same net, and the stub is long enough
+		  // to come within a DRC spacing distance of the
+		  // other route, then lengthen it to close up the
+		  // distance and resolve the error.
+
+		  if ((y < y2) && (seg->y1 < (NumChannelsY[layer] - 1))) {
+		     tdir = OBSVAL(seg->x1, seg->y1 + 1, layer);
+		     if ((tdir & ROUTED_NET_MASK) ==
+						(net->netnum | ROUTED_NET)) {
+			if (stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
+		      	   dc = Ylowerbound + (double)(seg->y1 + 1)
+					* PitchY[layer];
+		      	   y2 = (int)((REPS(dc)) * oscale);
+			}
+		     }
+		  }
+		  else if ((y > y2) && (seg->y1 > 0)) {
+		     tdir = OBSVAL(seg->x1, seg->y1 - 1, layer);
+		     if ((tdir & ROUTED_NET_MASK) ==
+						(net->netnum | ROUTED_NET)) {
+			if (-stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
+		      	   dc = Ylowerbound + (double)(seg->y1 - 1)
+					* PitchY[layer];
+		      	   y2 = (int)((REPS(dc)) * oscale);
+			}
+		     }
+		  }
+
+		  dc = oscale * 0.5 * LefGetRouteWidth(layer);
+		  if (special == (u_char)0) {
+		     // Regular nets include 1/2 route width at
+		     // the ends, so subtract from the stub terminus
+		     if (y < y2) {
+			y2 -= dc;
+			if (y >= y2) cancel = TRUE;
+		     }
+		     else {
+			y2 += dc;
+			if (y <= y2) cancel = TRUE;
+		     }
+		  }
+		  else {
+		     // Special nets don't include 1/2 route width
+		     // at the ends, so add to the route at the grid
+		     if (y < y2)
+			y -= dc;
+		     else
+			y += dc;
+
+		     // Routes that extend for more than one track
+		     // without a bend do not need a wide stub
+		     if (seg->y1 != seg->y2) cancel = TRUE;
+		  }
+	       }
+
+	       if (cancel == FALSE) {
+		  net->flags |= NET_STUB;
+		  rt->flags |= RT_STUB;
+		  pathstart(Cmd, layer, x2, y2, special, oscale, invscale, horizontal);
+		  pathto(Cmd, x, y, horizontal, x2, y2, invscale);
+	       }
+	       lastx = x;
+	       lasty = y;
+	       lastlay = layer;
+	    }
+	 }
+
+	 prevseg = NULL;
+	 lastseg = NULL;
+	 for (seg = rt->segments; seg; seg = seg->next) {
+	    layer = seg->layer;
+
+	    // Check for offset terminals at either point
+
+	    offset1 = 0.0;
+	    offset2 = 0.0;
+	    dir1 = 0;
+	    dir2 = 0;
+
+	    if (seg->segtype & ST_OFFSET_START) {
+	       dir1 = OBSVAL(seg->x1, seg->y1, seg->layer) & OFFSET_TAP;
+	       if ((dir1 == 0) && lastseg) {
+		  dir1 = OBSVAL(lastseg->x2, lastseg->y2, lastseg->layer)
+				& OFFSET_TAP;
+		  lnode1 = NODEIPTR(lastseg->x2, lastseg->y2, lastseg->layer);
+		  offset1 = lnode1->offset;
+	       }
+	       else {
+		  lnode1 = NODEIPTR(seg->x1, seg->y1, seg->layer);
+		  offset1 = lnode1->offset;
+	       }
+
+	       // Offset was calculated for vias;  plain metal routes
+	       // typically will need less offset distance, so subtract off
+	       // the difference.
+
+	       if (!(seg->segtype & ST_VIA)) {
+		  if (offset1 < 0) {
+		     offset1 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer, 
+				horizontal) - LefGetRouteWidth(seg->layer));
+		     if (offset1 > 0) offset1 = 0;
+		  }
+		  else if (offset1 > 0) {
+		     offset1 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer,
+				horizontal) - LefGetRouteWidth(seg->layer));
+		     if (offset1 < 0) offset1 = 0;
+		  }
+	       }
+
+	       if (special == (u_char)0) {
+		  if ((seg->segtype & ST_VIA) && (Verbose > 2))
+		     Fprintf(stdout, "Offset terminal distance %g to grid"
+					" at %d %d (%d)\n", offset1,
+					seg->x1, seg->y1, layer);
+	       }
+	    }
+	    if (seg->segtype & ST_OFFSET_END) {
+	       dir2 = OBSVAL(seg->x2, seg->y2, seg->layer) & OFFSET_TAP;
+	       if ((dir2 == 0) && seg->next) {
+		  dir2 = OBSVAL(seg->next->x1, seg->next->y1, seg->next->layer) &
+					OFFSET_TAP;
+		  lnode2 = NODEIPTR(seg->next->x1, seg->next->y1, seg->next->layer);
+		  offset2 = lnode2->offset;
+	       }
+	       else {
+		  lnode2 = NODEIPTR(seg->x2, seg->y2, seg->layer);
+		  offset2 = lnode2->offset;
+	       }
+
+	       // Offset was calculated for vias;  plain metal routes
+	       // typically will need less offset distance, so subtract off
+	       // the difference.
+
+	       if (!(seg->segtype & ST_VIA)) {
+		  if (offset2 < 0) {
+		     offset2 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer,
+				horizontal) - LefGetRouteWidth(seg->layer));
+		     if (offset2 > 0) offset2 = 0;
+		  }
+		  else if (offset2 > 0) {
+		     offset2 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer, 
+				horizontal) - LefGetRouteWidth(seg->layer));
+		     if (offset2 < 0) offset2 = 0;
+		  }
+	       }
+
+	       if (special == (u_char)0) {
+		  if ((seg->segtype & ST_VIA)
+					&& !(seg->segtype & ST_OFFSET_START))
+		     if (Verbose > 2)
+		        Fprintf(stdout, "Offset terminal distance %g to grid"
+					" at %d %d (%d)\n", offset2,
+					seg->x2, seg->y2, layer);
+	       }
+	    }
+
+	    // To do: pick up route layer name from lefInfo.
+	    // At the moment, technology names don't even match,
+	    // and are redundant between CIFLayer[] from the
+	    // config file and lefInfo.
+
+	    dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
+	    if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_EW)) dc += offset1;
+	    x = (int)((REPS(dc)) * oscale);
+	    dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
+	    if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_NS)) dc += offset1;
+	    y = (int)((REPS(dc)) * oscale);
+	    dc = Xlowerbound + (double)seg->x2 * PitchX[layer];
+	    if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_EW)) dc += offset2;
+	    x2 = (int)((REPS(dc)) * oscale);
+	    dc = Ylowerbound + (double)seg->y2 * PitchY[layer];
+	    if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_NS)) dc += offset2;
+	    y2 = (int)((REPS(dc)) * oscale);
+	    segtype = seg->segtype & ~(ST_OFFSET_START | ST_OFFSET_END);
+	    switch (segtype) {
+	       case ST_WIRE:
+
+		  // Normally layers change only at a via.  However, if
+		  // a via has been removed and replaced by a 1-track
+		  // segment to a neighboring via to avoid DRC errors
+		  // (see cleanup_net()), then a layer change may happen
+		  // between two ST_WIRE segments, and a new path should
+		  // be started.
+
+		  if ((Pathon != -1) && (lastlay != -1) && (lastlay != seg->layer))
+		     Pathon = 0;
+
+		  if (Pathon != 1) {	// 1st point of route seg
+		     if (x == x2) {
+			horizontal = FALSE;
+		     }
+		     else if (y == y2) {
+			horizontal = TRUE;
+		     }
+		     else if (Verbose > 3) {
+			// NOTE:  This is a development diagnostic.  The
+			// occasional non-Manhanhattan route is due to a
+			// tap offset and is corrected automatically by
+			// making an L-bend in the wire.
+
+		     	Flush(stdout);
+			Fprintf(stderr, "Warning:  non-Manhattan wire in route"
+				" at (%d %d) to (%d %d)\n", x, y, x2, y2);
+		     }
+		     if (special == (u_char)0) {
+			pathstart(Cmd, seg->layer, x, y, special, oscale, invscale,
+				horizontal);
+			lastx = x;
+			lasty = y;
+			lastlay = seg->layer;
+		     }
+		  }
+		  rt->flags |= RT_OUTPUT;
+		  if (horizontal && x == x2) {
+		     horizontal = FALSE;
+		  }
+		  if ((!horizontal) && y == y2) {
+		     horizontal = TRUE;
+		  }
+		  if (!(x == x2) && !(y == y2)) {
+		     horizontal = FALSE;
+		  }
+		  if (special == (u_char)0) {
+		     pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale);
+		     lastx = x2;
+		     lasty = y2;
+		  }
+
+		  // If a segment is 1 track long, there is a via on either
+		  // end, and the needblock flag is set for the layer, then
+		  // draw a stub route along the length of the track.
+
+		  if (horizontal && needblock[seg->layer] & VIABLOCKX) {
+		     if (ABSDIFF(seg->x2, seg->x1) == 1) {
+			if ((lastseg && lastseg->segtype == ST_VIA) ||
+			    (seg->next && seg->next->segtype == ST_VIA)) {
+			   if (special == (u_char)0) {
+			      net->flags |= NET_STUB;
+			      rt->flags |= RT_STUB;
+			   }
+			   else {
+			      if (Pathon != -1) Pathon = 0;
+			      pathstart(Cmd, layer, x, y, special, oscale,
+						invscale, horizontal);
+			      pathto(Cmd, x2, y2, horizontal, x, y, invscale);
+			      lastlay = layer;
+			   }
+			}
+		     }
+		  }
+		  else if (!horizontal && needblock[seg->layer] & VIABLOCKY) {
+		     if (ABSDIFF(seg->y2, seg->y1) == 1)  {
+			if ((lastseg && lastseg->segtype == ST_VIA) ||
+			    (seg->next && seg->next->segtype == ST_VIA)) {
+			   if (special == (u_char)0) {
+			      net->flags |= NET_STUB;
+			      rt->flags |= RT_STUB;
+			   }
+			   else {
+			      if (Pathon != -1) Pathon = 0;
+			      pathstart(Cmd, layer, x, y, special, oscale,
+						invscale, horizontal);
+			      pathto(Cmd, x2, y2, horizontal, x, y, invscale);
+			      lastlay = layer;
+			   }
+			}
+		     }
+		  }
+		  break;
+	       case ST_VIA:
+		  rt->flags |= RT_OUTPUT;
+		  if (special == (u_char)0) {
+		     double viaoffx, viaoffy;
+		     int vx = 0;
+		     int vy = 0;
+		     u_int tdirpp, tdirp, tdirn;
+		     u_char viaNL, viaNM, viaNU;
+		     u_char viaSL, viaSM, viaSU;
+		     u_char viaEL, viaEM, viaEU;
+		     u_char viaWL, viaWM, viaWU;
+
+		     if (lastseg == NULL) {
+			// Make sure last position is valid
+			lastx = x;
+			lasty = y;
+		     }
+
+		     // Check for vias between adjacent but different nets
+		     // that need position offsets to avoid a DRC spacing error
+
+		     // viaCheckX[layer] indicates whether a check for
+		     // vias is needed.  If so, record what vias are to east
+		     // and west.
+
+		     if (viaCheckX[layer] > 0) {
+
+			viaEL = viaEM = viaEU = 0;
+			viaWL = viaWM = viaWU = 0;
+
+			// Check for via to west
+			if (seg->x1 > 0) {
+			   tdir = OBSVAL(seg->x1 - 1, seg->y1, layer)
+					& ROUTED_NET_MASK;
+
+			   if (((tdir & NO_NET) == 0) && (tdir != 0) &&
+				(tdir != (net->netnum | ROUTED_NET))) {
+
+			      if (layer < Num_layers - 1) {
+			         tdirp = OBSVAL(seg->x1 - 1, seg->y1, layer + 1)
+					& ROUTED_NET_MASK;
+			         if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
+				     	(tdirp != (net->netnum | ROUTED_NET))) {
+
+			            if (layer < Num_layers - 2) {
+			               tdirpp = OBSVAL(seg->x1 - 1, seg->y1, layer + 2)
+						& ROUTED_NET_MASK;
+			               if (tdirp == tdirpp) viaWU = 1;
+				    }
+				 }
+			         if (tdir == tdirp) viaWM = 1;
+			      }
+			
+			      if (layer > 0) {
+			         tdirn = OBSVAL(seg->x1 - 1, seg->y1, layer - 1)
+					& ROUTED_NET_MASK;
+			         if (tdir == tdirn) viaWL = 1;
+			      }
+			   }
+			}
+
+			// Check for via to east
+			if (seg->x1 < NumChannelsX[layer] - 1) {
+			   tdir = OBSVAL(seg->x1 + 1, seg->y1, layer)
+					& ROUTED_NET_MASK;
+
+			   if (((tdir & NO_NET) == 0) && (tdir != 0) &&
+				(tdir != (net->netnum | ROUTED_NET))) {
+
+			      if (layer < Num_layers - 1) {
+			         tdirp = OBSVAL(seg->x1 + 1, seg->y1, layer + 1)
+					& ROUTED_NET_MASK;
+			         if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
+				     	(tdirp != (net->netnum | ROUTED_NET))) {
+
+			            if (layer < Num_layers - 2) {
+			               tdirpp = OBSVAL(seg->x1 + 1, seg->y1, layer + 2)
+						& ROUTED_NET_MASK;
+			               if (tdirp == tdirpp) viaEU = 1;
+				    }
+				 }
+			         if (tdir == tdirp) viaEM = 1;
+			      }
+			
+			      if (layer > 0) {
+			         tdirn = OBSVAL(seg->x1 + 1, seg->y1, layer - 1)
+					& ROUTED_NET_MASK;
+			         if (tdir == tdirn) viaEL = 1;
+			      }
+			   }
+			}
+
+			// Compute X offset
+			viaoffx = 0.0;
+
+			if (viaWL) viaoffx = viaOffsetX[layer][0];
+			else if (viaEL) viaoffx = -viaOffsetX[layer][0];
+
+			if (viaWM && viaOffsetX[layer][1] > viaoffx)
+			   viaoffx = viaOffsetX[layer][1];
+			else if (viaEM && -viaOffsetX[layer][1] < viaoffx)
+			   viaoffx = -viaOffsetX[layer][1];
+
+			if (viaWU && viaOffsetX[layer][2] > viaoffx)
+			   viaoffx = viaOffsetX[layer][2];
+			else if (viaEU && -viaOffsetX[layer][2] < viaoffx)
+			   viaoffx = -viaOffsetX[layer][2];
+
+		        vx = (int)((REPS(viaoffx)) * oscale);
+		     }
+
+		     // viaCheckY[layer] indicates whether a check for
+		     // vias is needed.  If so, record what vias are to north
+		     // and south.
+
+		     if (viaCheckY[layer] > 0) {
+
+			viaNL = viaNM = viaNU = 0;
+			viaSL = viaSM = viaSU = 0;
+
+			// Check for via to south
+			if (seg->y1 > 0) {
+			   tdir = OBSVAL(seg->x1, seg->y1 - 1, layer)
+					& ROUTED_NET_MASK;
+
+			   if (((tdir & NO_NET) == 0) && (tdir != 0) &&
+				(tdir != (net->netnum | ROUTED_NET))) {
+
+			      if (layer < Num_layers - 1) {
+			         tdirp = OBSVAL(seg->x1, seg->y1 - 1, layer + 1)
+					& ROUTED_NET_MASK;
+			         if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
+				     	(tdirp != (net->netnum | ROUTED_NET))) {
+
+			            if (layer < Num_layers - 2) {
+			               tdirpp = OBSVAL(seg->x1, seg->y1 - 1, layer + 2)
+						& ROUTED_NET_MASK;
+			               if (tdirp == tdirpp) viaSU = 1;
+				    }
+				 }
+			         if (tdir == tdirp) viaSM = 1;
+			      }
+			
+			      if (layer > 0) {
+			         tdirn = OBSVAL(seg->x1, seg->y1 - 1, layer - 1)
+					& ROUTED_NET_MASK;
+			         if (tdir == tdirn) viaSL = 1;
+			      }
+			   }
+			}
+
+			// Check for via to north
+			if (seg->y1 < NumChannelsY[layer] - 1) {
+			   tdir = OBSVAL(seg->x1, seg->y1 + 1, layer)
+					& ROUTED_NET_MASK;
+
+			   if (((tdir & NO_NET) == 0) && (tdir != 0) &&
+				(tdir != (net->netnum | ROUTED_NET))) {
+
+			      if (layer < Num_layers - 1) {
+			         tdirp = OBSVAL(seg->x1, seg->y1 + 1, layer + 1)
+					& ROUTED_NET_MASK;
+			         if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
+				     	(tdirp != (net->netnum | ROUTED_NET))) {
+
+			            if (layer < Num_layers - 2) {
+			               tdirpp = OBSVAL(seg->x1, seg->y1 + 1, layer + 2)
+						& ROUTED_NET_MASK;
+			               if (tdirp == tdirpp) viaNU = 1;
+				    }
+				 }
+			         if (tdir == tdirp) viaNM = 1;
+			      }
+			
+			      if (layer > 0) {
+			         tdirn = OBSVAL(seg->x1, seg->y1 + 1, layer - 1)
+					& ROUTED_NET_MASK;
+			         if (tdir == tdirn) viaNL = 1;
+			      }
+			   }
+			}
+
+			// Compute Y offset
+			viaoffy = 0;
+
+			if (viaSL) viaoffy = viaOffsetY[layer][0];
+			else if (viaNL) viaoffy = -viaOffsetY[layer][0];
+
+			if (viaSM && viaOffsetY[layer][1] > viaoffy)
+			   viaoffy = viaOffsetY[layer][1];
+			else if (viaNM && -viaOffsetY[layer][1] < viaoffy)
+			   viaoffy = -viaOffsetY[layer][1];
+
+			if (viaSU && viaOffsetY[layer][2] > viaoffy)
+			   viaoffy = viaOffsetY[layer][2];
+			else if (viaNU && -viaOffsetY[layer][2] < viaoffy)
+			   viaoffy = -viaOffsetY[layer][2];
+
+		        vy = (int)((REPS(viaoffy)) * oscale);
+		     }
+
+		     // via-to-via interactions are symmetric, so move each
+		     // via half the distance (?)
+
+		     pathvia(Cmd, layer, x + vx, y + vy, lastx, lasty,
+					seg->x1, seg->y1, invscale);
+
+		     lastx = x;
+		     lasty = y;
+		     lastlay = -1;
+		  }
+		  break;
+	       default:
+		  break;
+	    }
+
+	    // Break here on last segment so that seg and lastseg are valid
+	    // in the following section of code.
+
+	    if (seg->next == NULL) break;
+	    prevseg = lastseg;
+	    lastseg = seg;
+	 }
+
+	 // For stub routes, reset the path between terminals, since
+	 // the stubs are not connected.
+	 if (special == (u_char)1 && Pathon != -1) Pathon = 0;
+
+	 // Check last position for terminal offsets
+	 if (seg && ((seg != saveseg) || (seg->segtype & ST_WIRE))) {
+	     cancel = FALSE;
+	     layer = seg->layer;
+	     lnode = (layer < Pinlayers) ? NODEIPTR(seg->x2, seg->y2, layer) : NULL;
+
+	     // Look for stub routes and offset taps
+	     dir2 = OBSVAL(seg->x2, seg->y2, layer) & (STUBROUTE | OFFSET_TAP);
+
+	     if ((dir2 & OFFSET_TAP) && (seg->segtype & ST_VIA) && prevseg) {
+
+	        // Additional handling for offset taps.  When a tap position
+	        // is a via and is offset in the direction of the last
+	        // route segment, then a DRC violation can be created if
+	        // (1) the via is wider than the route width, and (2) the
+	        // adjacent track position is another via or a bend in the
+	        // route, and (3) the tap offset is large enough to create
+	        // a spacing violation between the via and the adjacent via
+	        // or perpendicular route.  If these three conditions are
+	        // satisfied, then generate a stub route the width of the
+	        // via and one track pitch in length back toward the last
+	        // track position.
+
+ 	        // Problems only arise when the via width is larger than
+	        // the width of the metal route leaving the via.
+ 
+	        offset = lnode->offset;
+	        if (LefGetViaWidth(seg->layer, lastseg->layer, 1 - horizontal) >
+			LefGetRouteWidth(lastseg->layer)) {
+
+		   // Problems only arise when the last segment is exactly
+		   // one track long.
+
+		   if ((ABSDIFF(lastseg->x2, lastseg->x1) == 1) ||
+			(ABSDIFF(lastseg->y2, lastseg->y1) == 1)) {
+
+		      if (prevseg->segtype & ST_VIA) {
+
+		 	 dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
+			 x = (int)((REPS(dc)) * oscale);
+			 dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
+			 y = (int)((REPS(dc)) * oscale);
+
+			 dc = Xlowerbound + (double)prevseg->x1 * PitchX[layer];
+			 x2 = (int)((REPS(dc)) * oscale);
+			 dc = Ylowerbound + (double)prevseg->y1 * PitchY[layer];
+			 y2 = (int)((REPS(dc)) * oscale);
+
+			 // Setup is (via, 1 track route, via with offset)
+
+			 if (prevseg->x1 != seg->x1) {
+			    if ((PitchX[lastseg->layer] -
+				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) -
+				0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 1) -
+				(prevseg->x1 - seg->x1) * offset)
+				< LefGetRouteSpacing(lastseg->layer)) {
+			       if (special == (u_char)0) {
+				  rt->flags |= RT_STUB;
+				  net->flags |= NET_STUB;
+			       }
+			       else {
+				  pathstart(Cmd, lastseg->layer, x, y,
+					(u_char)1, oscale, invscale, 1);
+				  pathto(Cmd, x2, y2, 1, x, y, invscale);
+		      		  lastx = x2;
+				  lasty = y2;
+			       }
+			    }
+			 }
+			 else if (prevseg->y1 != seg->y1) {
+			    if ((PitchY[lastseg->layer] -
+				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) -
+				0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 0)
+				- (prevseg->y1 - seg->y1) * offset)
+				< LefGetRouteSpacing(lastseg->layer)) {
+			       if (special == (u_char)0) {
+				 rt->flags |= RT_STUB;
+				 net->flags |= NET_STUB;
+			       }
+			       else {
+				  pathstart(Cmd, lastseg->layer, x, y,
+					(u_char)1, oscale, invscale, 0);
+				  pathto(Cmd, x2, y2, 0, x, y, invscale);
+		      		  lastx = x2;
+				  lasty = y2;
+			       }
+			    }
+			 }
+		      }
+		      else {	// Metal route bends at next track
+			 if (prevseg->x1 != seg->x1) {
+			    if ((PitchX[lastseg->layer] -
+				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) -
+				0.5 * LefGetRouteWidth(prevseg->layer) -
+				(prevseg->x1 - seg->x1) * offset)
+				< LefGetRouteSpacing(lastseg->layer)) {
+			       if (special == (u_char)0) {
+				 rt->flags |= RT_STUB;
+				 net->flags |= NET_STUB;
+			       }
+			       else {
+				  pathstart(Cmd, lastseg->layer, x, y,
+					(u_char)1, oscale, invscale, 1);
+				  pathto(Cmd, x2, y2, 1, x, y, invscale);
+		      		  lastx = x2;
+				  lasty = y2;
+			       }
+			    }
+			 }
+			 else if (prevseg->y1 != seg->y1) {
+			    if ((PitchY[lastseg->layer] -
+				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) -
+				0.5 * LefGetRouteWidth(prevseg->layer) -
+				(prevseg->y1 - seg->y1) * offset)
+				< LefGetRouteSpacing(lastseg->layer)) {
+			       if (special == (u_char)0) {
+				  rt->flags |= RT_STUB;
+				  net->flags |= NET_STUB;
+			       }
+			       else {
+				  pathstart(Cmd, lastseg->layer, x, y,
+					(u_char)1, oscale, invscale, 0);
+				  pathto(Cmd, x2, y2, 0, x, y, invscale);
+		      		  lastx = x2;
+				  lasty = y2;
+			       }
+			    }
+			 }
+		      }
+		   }
+	        }
+	     }
+
+	     // For stub routes, reset the path between terminals, since
+	     // the stubs are not connected.
+	     if (special == (u_char)1 && Pathon != -1) Pathon = 0;
+
+	     // Handling of stub routes
+	     if (dir2 & STUBROUTE) {
+	        stub = lnode->stub;
+		if ((special == (u_char)0) && (Verbose > 2))
+		   Fprintf(stdout, "Stub route distance %g to terminal"
+				" at %d %d (%d)\n",
+				stub, seg->x2, seg->y2, layer);
+
+		dc = Xlowerbound + (double)seg->x2 * PitchX[layer];
+		if (lnode->flags & NI_OFFSET_EW)
+		   dc += offset;
+		x = (int)((REPS(dc)) * oscale);
+		if (lnode->flags & NI_STUB_EW)
+		   dc += stub;
+		x2 = (int)((REPS(dc)) * oscale);
+		dc = Ylowerbound + (double)seg->y2 * PitchY[layer];
+		if (lnode->flags & NI_OFFSET_NS)
+		   dc += offset;
+		y = (int)((REPS(dc)) * oscale);
+		if (lnode->flags & NI_STUB_NS)
+		   dc += stub;
+		y2 = (int)((REPS(dc)) * oscale);
+		if (lnode->flags & NI_STUB_EW) {
+		   horizontal = TRUE;
+
+		   // If the gridpoint ahead of the stub has a route
+		   // on the same net, and the stub is long enough
+		   // to come within a DRC spacing distance of the
+		   // other route, then lengthen it to close up the
+		   // distance and resolve the error.
+
+		   if ((x < x2) && (seg->x2 < (NumChannelsX[layer] - 1))) {
+		      tdir = OBSVAL(seg->x2 + 1, seg->y2, layer);
+		      if ((tdir & ROUTED_NET_MASK) ==
+						(net->netnum | ROUTED_NET)) {
+			 if (stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
+		      	    dc = Xlowerbound + (double)(seg->x2 + 1)
+					* PitchX[layer];
+		      	    x2 = (int)((REPS(dc)) * oscale);
+			 }
+		      }
+		   }
+		   else if ((x > x2) && (seg->x2 > 0)) {
+		      tdir = OBSVAL(seg->x2 - 1, seg->y2, layer);
+		      if ((tdir & ROUTED_NET_MASK) ==
+						(net->netnum | ROUTED_NET)) {
+			 if (-stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
+		      	    dc = Xlowerbound + (double)(seg->x2 - 1)
+					* PitchX[layer];
+		      	    x2 = (int)((REPS(dc)) * oscale);
+			 }
+		      }
+		   }
+
+		   dc = oscale * 0.5 * LefGetRouteWidth(layer);
+		   if (special == (u_char)0) {
+		      // Regular nets include 1/2 route width at
+		      // the ends, so subtract from the stub terminus
+		      if (x < x2) {
+			 x2 -= dc;
+			 if (x >= x2) cancel = TRUE;
+		      }
+		      else {
+			 x2 += dc;
+			 if (x <= x2) cancel = TRUE;
+		      }
+		   }
+		   else {
+		      // Special nets don't include 1/2 route width
+		      // at the ends, so add to the route at the grid
+		      if (x < x2)
+			 x -= dc;
+		      else
+			 x += dc;
+
+		      // Routes that extend for more than one track
+		      // without a bend do not need a wide stub
+		      if (seg->x1 != seg->x2) cancel = TRUE;
+		   }
+		}
+		else {  /* lnode->flags & NI_STUB_EW implied */
+		   horizontal = FALSE;
+
+		   // If the gridpoint ahead of the stub has a route
+		   // on the same net, and the stub is long enough
+		   // to come within a DRC spacing distance of the
+		   // other route, then lengthen it to close up the
+		   // distance and resolve the error.
+
+		   if ((y < y2) && (seg->y2 < (NumChannelsY[layer] - 1))) {
+		      tdir = OBSVAL(seg->x2, seg->y2 + 1, layer);
+		      if ((tdir & ROUTED_NET_MASK) ==
+						(net->netnum | ROUTED_NET)) {
+			 if (stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
+		      	    dc = Ylowerbound + (double)(seg->y2 + 1)
+					* PitchY[layer];
+		      	    y2 = (int)((REPS(dc)) * oscale);
+			 }
+		      }
+		   }
+		   else if ((y > y2) && (seg->y2 > 0)) {
+		      tdir = OBSVAL(seg->x2, seg->y2 - 1, layer);
+		      if ((tdir & ROUTED_NET_MASK) ==
+						(net->netnum | ROUTED_NET)) {
+			 if (-stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
+		      	    dc = Ylowerbound + (double)(seg->y2 - 1)
+					* PitchY[layer];
+		      	    y2 = (int)((REPS(dc)) * oscale);
+			 }
+		      }
+		   }
+
+		   dc = oscale * 0.5 * LefGetRouteWidth(layer);
+		   if (special == (u_char)0) {
+		      // Regular nets include 1/2 route width at
+		      // the ends, so subtract from the stub terminus
+		      if (y < y2) {
+			 y2 -= dc;
+			 if (y >= y2) cancel = TRUE;
+		      }
+		      else {
+			 y2 += dc;
+			 if (y <= y2) cancel = TRUE;
+		      }
+		   }
+		   else {
+		      // Special nets don't include 1/2 route width
+		      // at the ends, so add to the route at the grid
+		      if (y < y2)
+			 y -= dc;
+		      else
+			 y += dc;
+
+		      // Routes that extend for more than one track
+		      // without a bend do not need a wide stub
+		      if (seg->y1 != seg->y2) cancel = TRUE;
+		   }
+		}
+		if (cancel == FALSE) {
+	           net->flags |= NET_STUB;
+	           rt->flags |= RT_STUB;
+		   if (Pathon != 1) {
+		      pathstart(Cmd, layer, x, y, special, oscale, invscale,
+				horizontal);
+		      lastx = x;
+		      lasty = y;
+		   }
+		   pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale);
+		   lastx = x2;
+		   lasty = y2;
+		}
+	    }
+	 }
+	 if (Pathon != -1) Pathon = 0;
+
+      } // if (rt->segments && !(rt->flags & RT_OUTPUT))
+   }
+}
+
+/*--------------------------------------------------------------*/
+/* emit_routes - DEF file output from the list of routes	*/
+/*								*/
+/*  Reads the <project>.def file and rewrites file		*/
+/*  <project>_route.def, where each net definition has the	*/
+/*  physical route appended.					*/
+/*								*/
+/*   ARGS: filename to list to					*/
+/*   RETURNS: nothing						*/
+/*   SIDE EFFECTS: 						*/
+/*   AUTHOR and DATE: steve beccue      Mon Aug 11 2003		*/
+/*--------------------------------------------------------------*/
+
+static void emit_routes(char *filename, double oscale, int iscale)
+{
+    FILE *Cmd;
+    int i, j, numnets, stubroutes;
+    char line[MAX_LINE_LEN + 1], *lptr = NULL;
+    char netname[MAX_NAME_LEN];
+    NET net = NULL;
+    ROUTE rt;
+    FILE *fdef;
+    u_char errcond = FALSE;
+    u_char need_cleanup = FALSE;
+
+    fdef = fopen(DEFfilename, "r");
+    if (fdef == NULL) {
+	if (strchr(DEFfilename, '.') == NULL) {
+	    char *extfilename = malloc(strlen(DEFfilename) + 5);
+	    sprintf(extfilename, "%s.def", DEFfilename);
+	    fdef = fopen(extfilename, "r");
+	    free(extfilename);
+	}
+    }
+    if (fdef == NULL) {
+	Fprintf(stderr, "emit_routes(): Cannot open DEF file for reading.\n");
+	return;
+    } 
+
+    if (!strcmp(filename, "stdout")) {
+	Cmd = stdout;
+    }
+    else {
+	char *dotptr;
+
+	if (filename == DEFfilename) {
+	    char *newDEFfile = (char *)malloc(strlen(filename) + 11);
+	    strcpy(newDEFfile, filename);
+	    dotptr = strrchr(newDEFfile, '.');
+	    if (dotptr)
+		strcpy(dotptr, "_route.def");
+	    else
+		strcat(newDEFfile, "_route.def");
+	    
+	    Cmd = fopen(newDEFfile, "w");
+	    free(newDEFfile);
+	}
+	else {
+	    dotptr = strrchr(filename, '.');
+	    if (dotptr)
+	       Cmd = fopen(filename, "w");
+	    else {
+	       char *newDEFfile = (char *)malloc(strlen(filename) + 11);
+	       strcpy(newDEFfile, filename);
+	       strcat(newDEFfile, ".def");
+	       Cmd = fopen(newDEFfile, "w");
+	       free(newDEFfile);
+	    }
+	}
+    }
+    if (!Cmd) {
+	Fprintf(stderr, "emit_routes():  Couldn't open output (routed) DEF file.\n");
+	return;
+    }
+
+    // Copy DEF file up to NETS line
+    numnets = 0;
+    while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
+       lptr = line;
+       while (isspace(*lptr)) lptr++;
+       if (!strncmp(lptr, "NETS", 4)) {
+	  sscanf(lptr + 4, "%d", &numnets);
+	  break;
+       }
+       fputs(line, Cmd);
+    }
+    fputs(line, Cmd);	// Write the NETS line
+
+    if ((numnets + numSpecial) != Numnets) {
+      	Flush(stdout);
+	Fprintf(stderr, "emit_routes():  DEF file has %d nets and %d specialnets.\n",
+			numnets, numSpecial);
+	Fprintf(stderr, "but qrouter wants to write %d nets and specialnets.\n",
+			Numnets);
+    }
+
+    // Quick check to see if cleanup_nets can be avoided
+    for (i = 0; i < Num_layers; i++)
+       if (needblock[i] & (VIABLOCKX | VIABLOCKY))
+	  break;
+
+    if (i != Num_layers) need_cleanup = TRUE;
+
+    for (i = 0; i < numnets; i++) {
+       if (errcond == TRUE) break;
+       while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
+	  if ((lptr = strchr(line, ';')) != NULL) {
+	     *lptr = '\n';
+	     *(lptr + 1) = '\0';
+	     break;
+	  }
+	  else {
+             lptr = line;
+             while (isspace(*lptr)) lptr++;
+	     if (*lptr == '-') {
+		lptr++;
+                while (isspace(*lptr)) lptr++;
+	        sscanf(lptr, "%s", netname);
+		fputs(line, Cmd);
+	     }
+	     else if (*lptr == '+') {
+		lptr++;
+                while (isspace(*lptr)) lptr++;
+		if (!strncmp(lptr, "ROUTED", 6)) {
+		   // This net is being handled by qrouter, so remove
+		   // the original routing information
+		   while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
+		      if ((lptr = strchr(line, ';')) != NULL) {
+			 *lptr = '\n';
+			 *(lptr + 1) = '\0';
+			 break;
+		      }
+		   }
+		   break;
+		}
+		else
+		   fputs(line, Cmd);
+	     }
+	     else if (!strncmp(lptr, "END", 3)) {	// This should not happen
+		fputs(line, Cmd);
+		errcond = TRUE;
+		break;
+	     }
+	     else
+		fputs(line, Cmd);
+	  }
+       }
+
+       /* Find this net */
+
+       for (j = 0; j < Numnets; j++) {
+          net = Nlnets[j];
+	  if (!strcmp(net->netname, netname))
+	     break;
+       }
+       if (!net) {
+	  Fprintf(stderr, "emit_routes():  Net %s cannot be found.\n",
+		netname);
+
+	  /* Dump rest of net and continue---no routing information */
+	  *(lptr) = ';';
+	  fputs(line, Cmd);
+	  continue;
+       }
+       else {
+	  /* Add last net terminal, without the semicolon */
+	  fputs(line, Cmd);
+
+	  if (need_cleanup) cleanup_net(net);
+	  emit_routed_net(Cmd, net, (u_char)0, oscale, iscale);
+	  fprintf(Cmd, ";\n");
+       }
+    }
+
+    // Finish copying the rest of the NETS section
+    if (errcond == FALSE) {
+       while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
+	  lptr = line;
+	  while (isspace(*lptr)) lptr++;
+	  fputs(line, Cmd);
+	  if (!strncmp(lptr, "END", 3)) {
+	     break;
+	  }
+       }
+    }
+
+    // Determine how many stub routes we will write to SPECIALNETS
+    // Also reset the OUTPUT flag for each route needing a stubroute
+    // to be written.
+
+    stubroutes = 0;
+    for (i = 0; i < Numnets; i++) {
+	net = Nlnets[i];
+	if (net->flags & NET_STUB) {
+	    stubroutes++;
+	    for (rt = net->routes; rt; rt = rt->next)
+		if (rt->flags & RT_STUB)
+		    rt->flags &= ~RT_OUTPUT;
+	}
+    }
+
+    // If there were stub routes, repeat them in SPECIALNETS at the
+    // proper width.
+    if (stubroutes > 0) {
+
+        fprintf(Cmd, "\nSPECIALNETS %d ", stubroutes);
+	for (i = 0; i < Numnets; i++) {
+	     net = Nlnets[i];
+	     emit_routed_net(Cmd, net, (u_char)1, oscale, iscale);
+	}
+	fprintf(Cmd, ";\nEND SPECIALNETS\n");
+    }    
+
+    // Finish copying the rest of the file
+    while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
+       fputs(line, Cmd);
+    }
+    fclose(fdef);
+    fclose(Cmd);
+
+} /* emit_routes() */
+
+/* end of output.c */
diff --git a/output.h b/output.h
new file mode 100644
index 0000000..d1b6df8
--- /dev/null
+++ b/output.h
@@ -0,0 +1,24 @@
+/*
+ * output.h --
+ *
+ * This file includes the DEF file output functions
+ *
+ */
+
+#ifndef _OUTPUTINT_H
+#define _OUTPUTINT_H
+
+extern int  Pathon;
+
+/* Function prototypes */
+static void emit_routes(char *filename, double oscale, int iscale);
+
+int    write_def(char *filename);
+char  *print_node_name(NODE node);
+void   print_nets(char *filename);
+void   print_routes(char *filename);
+void   print_nlgates(char *filename);
+void   print_net(NET net);
+void   print_gate(GATE gate);
+
+#endif /* _OUTPUTINT_H */
diff --git a/point.c b/point.c
new file mode 100644
index 0000000..297db74
--- /dev/null
+++ b/point.c
@@ -0,0 +1,113 @@
+/*--------------------------------------------------------------*/
+/* point.c --							*/
+/*								*/
+/* Memory mapped point allocation				*/
+/*--------------------------------------------------------------*/
+/* Written by Tim Edwards, April 2017, based on code from Magic	*/
+/*--------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "qrouter.h"
+#include "point.h"
+
+#ifdef HAVE_SYS_MMAN_H
+
+POINT POINTStoreFreeList = NULL;
+POINT POINTStoreFreeList_end = NULL;
+
+/* The memory mapped POINT Allocation scheme */
+
+static void *_block_begin = NULL;
+static void *_current_ptr = NULL;
+static void *_block_end = NULL;
+
+/* MMAP the point store */
+static signed char
+mmapPOINTStore()
+{
+    int prot = PROT_READ | PROT_WRITE;
+    int flags = MAP_ANON | MAP_PRIVATE;
+    u_long map_len = POINT_STORE_BLOCK_SIZE; 	
+
+    _block_begin = mmap(NULL, map_len, prot, flags, -1, 0);
+    if (_block_begin == MAP_FAILED)
+    {
+	fprintf(stderr, "mmapPOINTStore: Unable to mmap ANON SEGMENT\n");
+	exit(1);
+    }
+    _block_end = (void *) ((unsigned long) _block_begin + map_len);
+    _current_ptr = _block_begin;
+    return 0;
+}
+
+POINT
+allocPOINT()
+{
+    POINT _return_point = NULL;
+
+    if (!_block_begin && !_block_end) mmapPOINTStore();
+
+    /* Check if we can get the point from the 
+     * Free list
+     */
+
+    if (POINTStoreFreeList) {
+	_return_point = POINTStoreFreeList;
+	POINTStoreFreeList = (POINT)POINTStoreFreeList->next;
+	return _return_point;
+    }
+
+    /* Get it from the mmap */
+
+    if (((unsigned long)_current_ptr + sizeof(struct point_)) >
+		(unsigned long)_block_end)
+	 mmapPOINTStore();
+
+    _current_ptr  = (void *)((unsigned long)_current_ptr
+		+ sizeof(struct point_));
+	
+    if ((unsigned long)_current_ptr > (unsigned long) _block_end) {
+	fprintf(stderr,
+		"allocPOINT(): internal assertion failure.");
+	exit(1);
+    }
+    return (POINT)((unsigned long)_current_ptr - sizeof(struct point_));
+}
+
+void
+freePOINT(POINT gp)
+{
+    if (!POINTStoreFreeList_end || !POINTStoreFreeList) {
+	POINTStoreFreeList_end = gp;
+	gp->next = (POINT)NULL;
+	POINTStoreFreeList = POINTStoreFreeList_end;
+    }
+    else {
+	POINTStoreFreeList_end->next = gp;
+	POINTStoreFreeList_end = gp;
+	POINTStoreFreeList_end->next = (POINT)NULL;
+    }
+}
+
+#else
+
+POINT
+allocPOINT()
+{
+    POINT newpoint;
+
+    newpoint = (POINT)malloc((unsigned)(sizeof(struct point_)));
+    return (newpoint);
+}
+
+void
+freePOINT(POINT gp)
+{
+    free((char *)gp);
+}
+
+#endif /* !HAVE_SYS_MMAN_H */
+
diff --git a/point.h b/point.h
new file mode 100644
index 0000000..301cd78
--- /dev/null
+++ b/point.h
@@ -0,0 +1,22 @@
+/*--------------------------------------------------------------*/
+/* point.h --							*/
+/*								*/
+/* Memory mapped point allocation (header file)			*/
+/*--------------------------------------------------------------*/
+/* Written by Tim Edwards, April 2017, based on code from Magic */
+/*--------------------------------------------------------------*/
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#include <unistd.h>
+
+/* Page size is 4KB so we mmap a segment equal to 64 pages */
+#define POINT_STORE_BLOCK_SIZE (4 * 1024 * 64)
+
+extern POINT PointStoreFreeList;
+extern POINT PointStoreFreeList_end;
+
+#endif /* HAVE_SYS_MMAN_H */
+
+extern POINT allocPOINT();
+extern void freePOINT(POINT gp);
diff --git a/qrouter.c b/qrouter.c
index 288af72..b0b2164 100644
--- a/qrouter.c
+++ b/qrouter.c
@@ -20,13 +20,15 @@
 
 #include "qrouter.h"
 #include "qconfig.h"
+#include "point.h"
 #include "node.h"
 #include "maze.h"
+#include "mask.h"
+#include "output.h"
 #include "lef.h"
 #include "def.h"
 #include "graphics.h"
 
-int  Pathon = -1;
 int  TotalRoutes = 0;
 
 NET     *Nlnets;	// list of nets in the design
@@ -38,13 +40,14 @@ GATE	PinMacro;	// macro definition for a pin
 GATE    Nlgates;	// gate instance information
 NETLIST FailedNets;	// list of nets that failed to route
 
-u_char   *RMask;    	        // mask out best area to route
 u_int    *Obs[MAX_LAYERS];      // net obstructions in layer
 PROUTE   *Obs2[MAX_LAYERS];     // used for pt->pt routes on layer
 float    *Obsinfo[MAX_LAYERS];  // temporary array used for detailed obstruction info
 NODEINFO *Nodeinfo[MAX_LAYERS]; // nodes and stub information is here. . .
 DSEG      UserObs;		// user-defined obstruction layers
 
+u_int     progress[3];		// analysis of behavior
+
 u_char needblock[MAX_LAYERS];
 
 char *vddnet = NULL;
@@ -52,8 +55,8 @@ char *gndnet = NULL;
 
 int    Numnets = 0;
 int    Pinlayers = 0;
+u_int  minEffort = 0;	// Minimum effort applied from command line.
 u_char Verbose = 3;	// Default verbose level
-u_char keepTrying = (u_char)0;
 u_char forceRoutable = FALSE;
 u_char maskMode = MASK_AUTO;
 u_char mapType = MAP_OBSTRUCT | DRAW_ROUTES;
@@ -65,17 +68,6 @@ char *delayfilename = NULL;
 
 ScaleRec Scales;	// record of input and output scales
 
-/* Prototypes for some local functions */
-static void initMask(void);
-static void fillMask(u_char value);
-static int next_route_setup(struct routeinfo_ *iroute, u_char stage);
-static int route_setup(struct routeinfo_ *iroute, u_char stage);
-static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug);
-static ROUTE createemptyroute(void);
-static void emit_routes(char *filename, double oscale, int iscale);
-static void helpmessage(void);
-
-
 /*--------------------------------------------------------------*/
 /* Check track pitch and set the number of channels (may be	*/
 /* called from DefRead)						*/
@@ -241,6 +233,7 @@ runqrouter(int argc, char *argv[])
 	 switch (optc) {
 	    case 'c':
 	    case 'i':
+	    case 'e':
 	    case 'k':
 	    case 'v':
 	    case 'd':
@@ -302,10 +295,15 @@ runqrouter(int argc, char *argv[])
 	       return 1;
 	       break;
 	    case 'f':
-	       forceRoutable = 1;
+	       forceRoutable = TRUE;
 	       break;
 	    case 'k':
-	       keepTrying = (u_char)atoi(optarg);
+	       Fprintf(stdout, "Option \"k\" deprecated.  Use \"effort\""
+			" in stage2 or stage3 command or -e option\n");
+	       minEffort = 100 * atoi(optarg);
+	       break;
+	    case 'e':
+	       minEffort = atoi(optarg);
 	       break;
 	    case '\0':
 	       /* Ignore '-' */
@@ -666,7 +664,7 @@ static int post_def_setup()
    // a third category which is route-to-route spacing violation.
 
    for (i = 0; i < Num_layers; i++) {
-      needblock[i] = (u_char)0;
+      needblock[i] = FALSE;
       sreq1 = LefGetRouteSpacing(i);
 
       sreq2 = LefGetViaWidth(i, i, 0) + sreq1;
@@ -777,7 +775,7 @@ int dofirststage(u_char graphdebug, int debug_netnum)
 
       net = getnettoroute(i);
       if ((net != NULL) && (net->netnodes != NULL)) {
-	 result = doroute(net, (u_char)0, graphdebug);
+	 result = doroute(net, FALSE, graphdebug);
 	 if (result == 0) {
 	    remaining--;
 	    if (Verbose > 0)
@@ -819,430 +817,6 @@ int dofirststage(u_char graphdebug, int debug_netnum)
 }
 
 /*--------------------------------------------------------------*/
-/* Write the output annotated DEF file.				*/
-/*--------------------------------------------------------------*/
-
-int write_def(char *filename)
-{
-   NET net;
-   NETLIST nl;
-
-   emit_routes((filename == NULL) ? DEFfilename : filename,
-		Scales.oscale, Scales.iscale);
-
-   Fprintf(stdout, "----------------------------------------------\n");
-   Fprintf(stdout, "Final: ");
-   if (FailedNets == (NETLIST)NULL)
-      Fprintf(stdout, "No failed routes!\n");
-   else {
-      if (FailedNets != (NETLIST)NULL) {
-         Fprintf(stdout, "Failed net routes: %d\n", countlist(FailedNets));
-	 Fprintf(stdout, "List of failed nets follows:\n");
-
-	 // Make sure FailedNets is cleaned up as we output the failed nets
-
- 	 while (FailedNets) {
-	    net = FailedNets->net;
-	    Fprintf(stdout, " %s\n", net->netname);
-	    nl = FailedNets->next;
-	    free(FailedNets);
-	    FailedNets = nl;
-	 }
-	 Fprintf(stdout, "\n");
-      }
-   }
-   Fprintf(stdout, "----------------------------------------------\n");
-
-   return 0;
-
-} /* write_def() */
-
-/*--------------------------------------------------------------*/
-/* pathstart - begin a DEF format route path           		*/
-/*								*/
-/* 	If "special" is true, then this path is in a		*/
-/*	SPECIALNETS section, in which each route specifies	*/
-/*	a width.						*/
-/*--------------------------------------------------------------*/
-
-static void
-pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale,
-          double invscale, u_char horizontal)
-{
-   if (Pathon == 1) {
-      Fprintf( stderr, "pathstart():  Major error.  Started a new "
-		"path while one is in progress!\n"
-		"Doing it anyway.\n" );
-   }
-
-   if (layer >= 0) {
-      if (Pathon == -1)
-	 fprintf(cmd, "+ ROUTED ");
-      else
-	 fprintf(cmd, "\n  NEW ");
-      if (special) {
-	 double wvia;
-
-	 wvia = LefGetViaWidth(layer, layer, horizontal);
-	 if (layer > 0) { 
-	    double wvia2;
-	    wvia2 = LefGetViaWidth(layer - 1, layer, horizontal);
-	    if (wvia2 > wvia) wvia = wvia2;
-         }
-
-         fprintf(cmd, "%s %g ( %g %g ) ", CIFLayer[layer],
-			invscale * (int)(oscale * wvia + 0.5),
-			invscale * x, invscale * y);
-      }
-      else
-         fprintf(cmd, "%s ( %g %g ) ", CIFLayer[layer], invscale * x, invscale * y);
-   }
-   Pathon = 1;
-
-} /* pathstart() */
-
-/*--------------------------------------------------------------*/
-/* pathto  - continue a path to the next point        		*/
-/*								*/
-/*   ARGS: coordinate pair					*/
-/*   RETURNS: 							*/
-/*   SIDE EFFECTS: 						*/
-/*--------------------------------------------------------------*/
-
-static void
-pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty,
-       double invscale)
-{
-    if (Pathon <= 0) {
-	Fprintf(stderr, "pathto():  Major error.  Added to a "
-		"non-existent path!\n"
-		"Doing it anyway.\n");
-    }
-
-    /* If the route is not manhattan, then it's because an offset
-     * was added to the last point, and we need to add a small
-     * jog to the route.
-     */
-
-    if ((x != lastx) && (y != lasty)) {
-	if (horizontal)
-	   pathto(cmd, lastx, y, FALSE, lastx, lasty, invscale);
-	else
-	   pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale);
-    }
-
-    fprintf(cmd, "( ");
-    if (horizontal)
-	fprintf(cmd, "%g ", invscale * x);
-    else
-	fprintf(cmd, "* ");
-
-    if (horizontal)
-	fprintf(cmd, "* ");
-    else
-	fprintf(cmd, "%g ", invscale * y);
-
-    fprintf(cmd, ") ");
-
-} /* pathto() */
-
-/*--------------------------------------------------------------*/
-/* pathvia  - add a via to a path               		*/
-/*								*/
-/*   ARGS: coord						*/
-/*   RETURNS: 							*/
-/*   SIDE EFFECTS: 						*/
-/*--------------------------------------------------------------*/
-
-static void
-pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty,
-        int gridx, int gridy, double invscale)
-{
-    char *s;
-    char checkersign = (gridx + gridy + layer) & 0x01;
-
-    if ((ViaPattern == VIA_PATTERN_NONE) || (ViaY[layer] == NULL))
-	s = ViaX[layer];
-    else if (ViaPattern == VIA_PATTERN_NORMAL)
-	s = (checkersign == 0) ?  ViaX[layer] : ViaY[layer];
-    else
-	s = (checkersign == 0) ?  ViaY[layer] : 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);
-    }
-    else {
-       // Normally the path will be manhattan and only one of
-       // these will be true.  But if the via gets an offset to
-       // avoid a DRC spacing violation with an adjacent via,
-       // then we may need to apply both paths to make a dog-leg
-       // route to the via.
-
-       if (x != lastx)
-	  pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale);
-       if (y != lasty)
-	  pathto(cmd, x, y, FALSE, x, lasty, invscale);
-    }
-    fprintf(cmd, "%s ", s);
-    Pathon = 0;
-
-} /* pathvia() */
-
-/*--------------------------------------------------------------*/
-/* Nodes aren't saved in a way that makes it easy to recall	*/
-/* the name of the cell and pin to which they belong.  But	*/
-/* that information doesn't need to be looked up except as a	*/
-/* diagnostic output.  This routine does that lookup.		*/
-/*--------------------------------------------------------------*/
-
-char *print_node_name(NODE node)
-{
-    GATE g;
-    int i;
-    static char *nodestr = NULL;
-
-    for (g = Nlgates; g; g = g->next) {
-	for (i = 0; i < g->nodes; i++) {
-	    if (g->noderec[i] == node) {
-		if (nodestr != NULL)
-		   free(nodestr);
-
-		nodestr = (char *)malloc(strlen(g->gatename)
-			+ strlen(g->node[i]) + 2);
-		if (!strcmp(g->node[i], "pin"))
-		    sprintf(nodestr, "PIN/%s", g->gatename);
-		else
-		    sprintf(nodestr, "%s/%s", g->gatename, g->node[i]);
-		return nodestr;
-	    }
-	}
-    }
-    if (nodestr != NULL) free(nodestr);
-    nodestr = (char *)malloc(22);
-    sprintf(nodestr, "(error: no such node)");
-    return nodestr;
-}
-
-/*--------------------------------------------------------------*/
-/* print_nets - print the nets list - created from Nlgates list */
-/*								*/
-/*   ARGS: filename to list to					*/
-/*   RETURNS: nothing						*/
-/*   SIDE EFFECTS: 						*/
-/*   AUTHOR and DATE: steve beccue      Sat July 26		*/
-/*--------------------------------------------------------------*/
-
-void print_nets(char *filename)
-{
-   FILE *o;
-   GATE g;
-   int i;
-   DSEG drect;
-
-   if (!strcmp(filename, "stdout")) {
-	o = stdout;
-   } else {
-	o = fopen(filename, "w");
-   }
-   if (!o) {
-	Fprintf(stderr, "route:print_nets.  Couldn't open output file\n");
-	return;
-   }
-
-   for (g = Nlgates; g; g = g->next) {
-      fprintf(o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename);
-      for (i = 0; i < g->nodes; i++) {
-	 // This prints the first tap position only.
-	 drect = g->taps[i];
-	 fprintf( o, "%s(%g,%g) ", g->node[i], drect->x1, drect->y1);
-      }
-   }
-   fprintf( o, "\n");
-} /* print_nets() */
-
-/*--------------------------------------------------------------*/
-/* print_routes - print the routes list				*/
-/*								*/
-/*   ARGS: filename to list to					*/
-/*   RETURNS: nothing						*/
-/*   SIDE EFFECTS: 						*/
-/*   AUTHOR and DATE: steve beccue      Sat July 26		*/
-/*--------------------------------------------------------------*/
-
-void print_routes( char *filename )
-{
-    FILE *o;
-    GATE g;
-    int i;
-
-    if( !strcmp( filename, "stdout" ) ) {
-	o = stdout;
-    } else {
-	o = fopen( filename, "w" );
-    }
-    if( !o ) {
-	Fprintf( stderr, "route:print_routes.  Couldn't open output file\n" );
-	return;
-    }
-
-    for (g = Nlgates; g; g = g->next) {
-	fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename );
-	for( i = 0 ; i < g->nodes; i++ ) {
-	    fprintf( o, "%s ", g->node[i] );
-	}
-	fprintf(o, "\n");
-    }
-} /* print_routes() */
-
-/*--------------------------------------------------------------*/
-/* print_nlgates - print the nlgate list			*/
-/*								*/
-/*   ARGS: filename to list to					*/
-/*   RETURNS: nothing						*/
-/*   SIDE EFFECTS: 						*/
-/*   AUTHOR and DATE: steve beccue      Wed July 23		*/
-/*--------------------------------------------------------------*/
-
-void print_nlgates( char *filename )
-{
-    FILE *o;
-    GATE g;
-    int i;
-    DSEG drect;
-
-    if( !strcmp( filename, "stdout" ) ) {
-	o = stdout;
-    } else {
-	o = fopen( filename, "w" );
-    }
-    if( !o ) {
-	Fprintf( stderr, "route:print_nlgates.  Couldn't open output file\n" );
-	return;
-    }
-
-    for (g = Nlgates; g; g = g->next) {
-	fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename );
-	for( i = 0 ; i < g->nodes; i++ ) {
-	    // This prints the first tap position only.
-	    drect = g->taps[i];
-	    fprintf( o, "%s(%g,%g)", g->node[i], drect->x1, drect->y1);
-	}
-        fprintf(o, "\n");
-    }
-} /* print_nlgates() */
-
-
-/*--------------------------------------------------------------*/
-/* print_net - print info about the net to stdout               */
-/*								*/
-/*   ARGS: net to print info about				*/
-/*   RETURNS: nothing						*/
-/*   SIDE EFFECTS: 						*/
-/*--------------------------------------------------------------*/
-
-void print_net(NET net) {
-    NODE node;
-    DPOINT tap;
-    int i, first;
-
-    Fprintf(stdout, "Net %d: %s", net->netnum, net->netname);
-    for (node = net->netnodes; node != NULL; node = node->next) {
-        Fprintf(stdout, "\n  Node %d: \n    Taps: ", node->nodenum);
-        for (tap = node->taps, i = 0, first = TRUE;
-             tap != NULL;
-             tap = tap->next, i = (i + 1) % 4, first = FALSE) {
-            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
-                    (i == 0 ? (first ? "" : "\n        ") : " "),
-                    tap->layer, tap->x, tap->y
-            );
-        }
-        Fprintf(stdout, "\n    Tap extends: ");
-        for (tap = node->extend, i = 0, first = TRUE;
-             tap != NULL;
-             tap = tap->next, i = (i + 1) % 4, first = FALSE) {
-            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
-                    (i == 0 ? (first ? "" : "\n        ") : " "),
-                    tap->layer, tap->x, tap->y
-            );
-        }
-    }
-    Fprintf(stdout, "\n  bbox: (%d,%d)-(%d,%d)\n",
-            net->xmin, net->ymin, net->xmax, net->ymax
-    );
-}
-
-
-/*--------------------------------------------------------------*/
-/* print_gate - print info about the net to stdout              */
-/*								*/
-/*   ARGS: gate to print info about				*/
-/*   RETURNS: nothing						*/
-/*   SIDE EFFECTS: 						*/
-/*--------------------------------------------------------------*/
-
-void print_gate(GATE gate) {
-    int i, j, first;
-    DSEG seg;
-    NODE node;
-    DPOINT tap;
-
-    Fprintf(stdout, "Gate %s\n", gate->gatename);
-    Fprintf(stdout, "  Loc: (%.2lf, %.2lf), WxH: %.2lfx%.2lf\n",
-            gate->placedX, gate->placedY, gate->width, gate->height
-    );
-    Fprintf(stdout, "  Pins");
-    for (i = 0; i < gate->nodes; i++) {
-        Fprintf(stdout, "\n    Pin %s, net %d\n",
-                gate->node[i], gate->netnum[i]
-        );
-        Fprintf(stdout, "      Segs: ");
-        for (seg = gate->taps[i], j = 0, first = TRUE;
-             seg != NULL;
-             seg = seg->next, j = (j + 1) % 3, first = FALSE) {
-            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)-(%.2lf,%.2lf)",
-                    (j == 0 ? (first ? "" : "\n        ") : " "),
-                    seg->layer, seg->x1, seg->y1, seg->x2, seg->y2
-            );
-        }
-        if ((node = gate->noderec[i]) != NULL) {
-            Fprintf(stdout, "\n      Taps: ");
-            for (tap = node->taps, j = 0, first = TRUE;
-                 tap != NULL;
-                 tap = tap->next, j = (j + 1) % 4, first = FALSE) {
-                Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
-                        (j == 0 ? (first ? "" : "\n        ") : " "),
-                        tap->layer, tap->x, tap->y
-                );
-            }
-            Fprintf(stdout, "\n      Tap extends: ");
-            for (tap = node->extend, j = 0, first = TRUE;
-                 tap != NULL;
-                 tap = tap->next, j = (j + 1) % 4, first = FALSE) {
-                Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
-                        (j == 0 ? (first ? "" : "\n        ") : " "),
-                        tap->layer, tap->x, tap->y
-                );
-            }
-        }
-    }
-    Fprintf(stdout, "\n  Obstructions: ");
-    for (seg = gate->obs, j = 0, first = TRUE;
-         seg != NULL;
-         seg = seg->next, j = (j + 1) % 3, first = FALSE) {
-        Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)-(%.2lf,%.2lf)",
-                (j == 0 ? (first ? "" : "\n    ") : " "),
-                seg->layer, seg->x1, seg->y1, seg->x2, seg->y2
-        );
-    }
-    Fprintf(stdout, "\n");
-}
-
-
-/*--------------------------------------------------------------*/
 /* getnettoroute - get a net to route				*/
 /*								*/
 /*   ARGS: 							*/
@@ -1286,7 +860,7 @@ NET getnettoroute(int order)
 /* Return the number of nets ripped up				*/
 /*--------------------------------------------------------------*/
 
-static int ripup_colliding(NET net)
+static int ripup_colliding(NET net, u_char onlybreak)
 {
     NETLIST nl, nl2, fn;
     int ripped;
@@ -1317,7 +891,7 @@ static int ripup_colliding(NET net)
 	nl2 = nl->next;
 	if (Verbose > 0)
             Fprintf(stdout, "Ripping up blocking net %s\n", nl->net->netname);
-	if (ripup_net(nl->net, (u_char)1) == TRUE) { 
+	if (ripup_net(nl->net, TRUE, onlybreak) == TRUE) { 
 	    for (fn = FailedNets; fn && fn->next != NULL; fn = fn->next);
 	    if (fn)
 		fn->next = nl;
@@ -1345,7 +919,7 @@ static int ripup_colliding(NET net)
 /* net "net".							*/
 /*--------------------------------------------------------------*/
 
-int route_net_ripup(NET net, u_char graphdebug)
+int route_net_ripup(NET net, u_char graphdebug, u_char onlybreak)
 {
     int result;
     NETLIST nl, nl2;
@@ -1368,7 +942,7 @@ int route_net_ripup(NET net, u_char graphdebug)
 	}
     }
 
-    result = doroute(net, (u_char)1, graphdebug);
+    result = doroute(net, TRUE, graphdebug);
     if (result != 0) {
 	if (net->noripup != NULL) {
 	    if ((net->flags & NET_PENDING) == 0) {
@@ -1379,13 +953,13 @@ int route_net_ripup(NET net, u_char graphdebug)
 		    free(net->noripup);
 		    net->noripup = nl;
 		}
-		result = doroute(net, (u_char)1, graphdebug);
+		result = doroute(net, TRUE, graphdebug);
 		net->flags |= NET_PENDING;	// Next time we abandon it.
 	    }
 	}
     }
     if (result != 0)
-	result = ripup_colliding(net);
+	result = ripup_colliding(net, onlybreak);
 
     return result;
 }
@@ -1409,24 +983,20 @@ int route_net_ripup(NET net, u_char graphdebug)
 /*--------------------------------------------------------------*/
 
 int
-dosecondstage(u_char graphdebug, u_char singlestep)
+dosecondstage(u_char graphdebug, u_char singlestep, u_char onlybreak, u_int effort)
 {
-   int failcount, origcount, result, maxtries;
+   int failcount, result, i;
    NET net;
    NETLIST nl, nl2;
    NETLIST Abandoned;	// Abandoned routes---not even trying any more.
    ROUTE rt, rt2;
    SEG seg;
-
-   origcount = countlist(FailedNets);
-   if (FailedNets)
-      maxtries = TotalRoutes + ((origcount < 20) ? 20 : origcount) * 8;
-   else
-      maxtries = 0;
+   u_int loceffort = (effort > minEffort) ? effort : minEffort;
 
    fillMask((u_char)0);
    Abandoned = NULL;
-
+   for (i = 0; i < 3; i++) progress[i] = 0;
+   
    // Clear the "noripup" field from all of the failed nets, in case
    // the second stage route is being repeated.
 
@@ -1462,7 +1032,7 @@ dosecondstage(u_char graphdebug, u_char singlestep)
 	 Fprintf(stdout, "Routing net %s with collisions\n", net->netname);
       Flush(stdout);
 
-      result = doroute(net, (u_char)1, graphdebug);
+      result = doroute(net, TRUE, graphdebug);
 
       if (result != 0) {
 	 if (net->noripup != NULL) {
@@ -1474,7 +1044,7 @@ dosecondstage(u_char graphdebug, u_char singlestep)
 	          free(net->noripup);
 	          net->noripup = nl;
 	       }
-	       result = doroute(net, (u_char)1, graphdebug);
+	       result = doroute(net, TRUE, graphdebug);
 	       net->flags |= NET_PENDING;	// Next time we abandon it.
 	    }
 	 }
@@ -1489,7 +1059,7 @@ dosecondstage(u_char graphdebug, u_char singlestep)
 	 // then treat this as a route failure, and don't rip up any of
 	 // the colliding nets.
 
-	 result = ripup_colliding(net);
+	 result = ripup_colliding(net, onlybreak);
 	 if (result > 0) result = 0;
       }
 
@@ -1498,13 +1068,9 @@ dosecondstage(u_char graphdebug, u_char singlestep)
 	 // Complete failure to route, even allowing collisions.
 	 // Abandon routing this net.
 
-	 if (Verbose > 0) {
-	    Flush(stdout);
-	    Fprintf(stderr, "----------------------------------------------\n");
-	    Fprintf(stderr, "Complete failure on net %s:  Abandoning.\n",
+	 if (Verbose > 0)
+	    Fprintf(stdout, "Failure on net %s:  Abandoning for now.\n",
 			net->netname);
-	    Fprintf(stderr, "----------------------------------------------\n");
-	 }
 
 	 // Add the net to the "abandoned" list
 	 nl = (NETLIST)malloc(sizeof(struct netlist_));
@@ -1543,35 +1109,29 @@ dosecondstage(u_char graphdebug, u_char singlestep)
 	 // Remove both routing information and remove the route from
 	 // Obs[] for all parts of the net that were previously routed
 
-	 ripup_net(net, (u_char)1);	// Remove routing information from net
+	 ripup_net(net, TRUE, FALSE);	// Remove routing information from net
 	 continue;
       }
 
       // Write back the original route to the grid array
       writeback_all_routes(net);
 
-      // Failsafe---if we have been looping enough times to exceed
-      // maxtries (which is set to 8 route attempts per original failed
-      // net), then we check progress.  If we have reduced the number
-      // of failed nets by half or more, then we have an indication of
-      // real progress, and will continue.  If not, we give up.  Qrouter
-      // is almost certainly hopelessly stuck at this point.
-
-      if (TotalRoutes >= maxtries) {
-	 if (failcount <= (origcount / 2)) {
-	    maxtries = TotalRoutes + failcount * 8;
-	    origcount = failcount;
-	 }
-	 else if (keepTrying == 0) {
-	    Fprintf(stderr, "\nQrouter is stuck, abandoning remaining routes.\n");
+      // Evaluate progress by counting the total number of remaining
+      // routes in the last (effort) cycles.  progress[2]->progress[1]
+      // is a progression from oldest to newest number of remaining
+      // routes.  Calculate the slope of this line and declare an end
+      // to this 2nd stage route if the slope falls to zero.
+
+      progress[1] += failcount;
+      progress[0]++;
+      if (progress[0] > loceffort) {
+	 if ((progress[2] > 0) && (progress[2] < progress[1])) {
+	    Fprintf(stderr, "\nNo progress at level of effort %d;"
+			" ending 2nd stage.\n", loceffort);
 	    break;
 	 }
-	 else {
-	    keepTrying--;
-	    Fprintf(stderr, "\nQrouter is stuck, but I was told to keep trying.\n");
-	    maxtries = TotalRoutes + failcount * 8;
-	    origcount = failcount;
-	 }
+	 progress[2] = progress[1];
+	 progress[1] = progress[0] = 0;
       }
       if (singlestep && (FailedNets != NULL)) return countlist(FailedNets);
    }
@@ -1620,14 +1180,14 @@ dosecondstage(u_char graphdebug, u_char singlestep)
 /* routable.							*/
 /*--------------------------------------------------------------*/
 
-int dothirdstage(u_char graphdebug, int debug_netnum)
+int dothirdstage(u_char graphdebug, int debug_netnum, u_int effort)
 {
-   int i, failcount, remaining, result;
+   int i, failcount, remaining, result, maskSave;
    NET net;
    NETLIST nl;
+   u_int loceffort = (effort > minEffort) ? effort : minEffort;
 
-   // Clear the lists of failed routes, in case first
-   // stage is being called more than once.
+   // Clear the lists of failed routes
 
    if (debug_netnum <= 0) {
       while (FailedNets) {
@@ -1639,14 +1199,20 @@ int dothirdstage(u_char graphdebug, int debug_netnum)
 
    // Now find and route all the nets
 
+   for (i = 0; i < 3; i++) progress[i] = 0;
    remaining = Numnets;
  
    for (i = (debug_netnum >= 0) ? debug_netnum : 0; i < Numnets; i++) {
 
       net = getnettoroute(i);
       if ((net != NULL) && (net->netnodes != NULL)) {
-	 ripup_net(net, (u_char)0);
-	 result = doroute(net, (u_char)0, graphdebug);
+	 setBboxCurrent(net);
+	 ripup_net(net, FALSE, FALSE);
+	 // 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)
@@ -1665,6 +1231,23 @@ int dothirdstage(u_char graphdebug, int debug_netnum)
 	 remaining--;
       }
       if (debug_netnum >= 0) break;
+
+      /* Progress analysis (see 2nd stage).  Normally, the 3rd	 */
+      /* stage is run only after all nets have been successfully */	
+      /* routed.  However, there is no guarantee of this, so it	 */
+      /* is necessary to anticipate convergence issues.		 */
+
+      progress[1] += failcount;
+      progress[0]++;
+      if (progress[0] > loceffort) {
+	 if ((progress[2] > 0) && (progress[2] < progress[1])) {
+	    Fprintf(stderr, "\nNo progress at level of effort %d;"
+			" ending 3rd stage.\n", loceffort);
+	    break;
+	 }
+	 progress[2] = progress[1];
+	 progress[1] = progress[0] = 0;
+      }
    }
    failcount = countlist(FailedNets);
    if (debug_netnum >= 0) return failcount;
@@ -1688,430 +1271,6 @@ int dothirdstage(u_char graphdebug, int debug_netnum)
 }
 
 /*--------------------------------------------------------------*/
-/* initMask() ---						*/
-/*--------------------------------------------------------------*/
-
-static void initMask(void)
-{
-   RMask = (u_char *)calloc(NumChannelsX[0] * NumChannelsY[0],
-			sizeof(u_char));
-   if (!RMask) {
-      fprintf(stderr, "Out of memory 3.\n");
-      exit(3);
-   }
-}
-
-/*--------------------------------------------------------------*/
-/* Fill mask around the area of a vertical line			*/
-/*--------------------------------------------------------------*/
-
-static void
-create_vbranch_mask(int x, int y1, int y2, u_char slack, u_char halo)
-{
-   int gx1, gx2, gy1, gy2;
-   int i, j, v;
-   u_char m;
-
-   gx1 = x - slack;
-   gx2 = x + slack;
-   if (y1 > y2) {
-      gy1 = y2 - slack;
-      gy2 = y1 + slack;
-   }
-   else {
-      gy1 = y1 - slack;
-      gy2 = y2 + slack;
-   }
-   if (gx1 < 0) gx1 = 0;
-   if (gx2 >= NumChannelsX[0]) gx2 = NumChannelsX[0] - 1;
-   if (gy1 < 0) gy1 = 0;
-   if (gy2 >= NumChannelsY[0]) gy2 = NumChannelsY[0] - 1;
-
-   for (i = gx1; i <= gx2; i++)
-      for (j = gy1; j <= gy2; j++)
-	 RMASK(i, j) = (u_char)0;
-
-   for (v = 1; v < halo; v++) {
-      if (gx1 > 0) gx1--;
-      if (gx2 < NumChannelsX[0] - 1) gx2++;
-      if (y1 > y2) {
-         if (gy1 < NumChannelsY[0] - 1) gy1++;
-         if (gy2 < NumChannelsY[0] - 1) gy2++;
-      }
-      else {
-	 if (gy1 > 0) gy1--;
-	 if (gy2 > 0) gy2--;
-      }
-      for (i = gx1; i <= gx2; i++)
-         for (j = gy1; j <= gy2; j++) {
-	    m = RMASK(i, j);
-	    if (m > v) RMASK(i, j) = (u_char)v;
-	 }
-   }
-}
-
-/*--------------------------------------------------------------*/
-/* Fill mask around the area of a horizontal line		*/
-/*--------------------------------------------------------------*/
-
-static void
-create_hbranch_mask(int y, int x1, int x2, u_char slack, u_char halo)
-{
-   int gx1, gx2, gy1, gy2;
-   int i, j, v;
-   u_char m;
-
-   gy1 = y - slack;
-   gy2 = y + slack;
-   if (x1 > x2) {
-      gx1 = x2 - slack;
-      gx2 = x1 + slack;
-   }
-   else {
-      gx1 = x1 - slack;
-      gx2 = x2 + slack;
-   }
-   if (gx1 < 0) gx1 = 0;
-   if (gx2 >= NumChannelsX[0]) gx2 = NumChannelsX[0] - 1;
-   if (gy1 < 0) gy1 = 0;
-   if (gy2 >= NumChannelsY[0]) gy2 = NumChannelsY[0] - 1;
-
-   for (i = gx1; i <= gx2; i++)
-      for (j = gy1; j <= gy2; j++)
-	 RMASK(i, j) = (u_char)0;
-
-   for (v = 1; v < halo; v++) {
-      if (gy1 > 0) gy1--;
-      if (gy2 < NumChannelsY[0] - 1) gy2++;
-      if (x1 > x2) {
-         if (gx1 < NumChannelsX[0] - 1) gx1++;
-         if (gx2 < NumChannelsX[0] - 1) gx2++;
-      }
-      else {
-	 if (gx1 > 0) gx1--;
-	 if (gx2 > 0) gx2--;
-      }
-      for (i = gx1; i <= gx2; i++)
-         for (j = gy1; j <= gy2; j++) {
-	    m = RMASK(i, j);
-	    if (m > v) RMASK(i, j) = (u_char)v;
-	 }
-   }
-}
-
-/*--------------------------------------------------------------*/
-/* createBboxMask() ---						*/
-/*								*/
-/* Create mask limiting the area to search for routing		*/
-/*								*/
-/* The bounding box mask generates an area including the	*/
-/* bounding box as defined in the net record, includes all pin	*/
-/* positions in the mask, and increases the mask area by one	*/
-/* route track for each pass, up to "halo".			*/
-/*--------------------------------------------------------------*/
-
-static void createBboxMask(NET net, u_char halo)
-{
-    int xmin, ymin, xmax, ymax;
-    int i, j, gx1, gy1, gx2, gy2;
-
-    fillMask((u_char)halo);
-
-    xmin = net->xmin;
-    xmax = net->xmax;
-    ymin = net->ymin;
-    ymax = net->ymax;
-  
-    for (gx1 = xmin; gx1 <= xmax; gx1++)
-	for (gy1 = ymin; gy1 <= ymax; gy1++)
-	    RMASK(gx1, gy1) = (u_char)0;
-
-    for (i = 1; i <= halo; i++) {
-	gx1 = xmin - i;
-	if (gx1 >= 0 && gx1 < NumChannelsX[0])
-           for (j = ymin - i; j <= ymax + i; j++)
-	      if (j >= 0 && j < NumChannelsY[0])
-		 RMASK(gx1, j) = (u_char)i;
-
-	gx2 = xmax + i;
-	if (gx2 >= 0 && gx2 < NumChannelsX[0])
-           for (j = ymin - i; j <= ymax + i; j++)
-	      if (j >= 0 && j < NumChannelsY[0])
-		 RMASK(gx2, j) = (u_char)i;
-
-	gy1 = ymin - i;
-	if (gy1 >= 0 && gy1 < NumChannelsY[0])
-           for (j = xmin - i; j <= xmax + i; j++)
-	      if (j >= 0 && j < NumChannelsX[0])
-		 RMASK(j, gy1) = (u_char)i;
-
-	gy2 = ymax + i;
-	if (gy2 >= 0 && gy2 < NumChannelsY[0])
-           for (j = xmin - i; j <= xmax + i; j++)
-	      if (j >= 0 && j < NumChannelsX[0])
-		 RMASK(j, gy2) = (u_char)i;
-     }
-}
-
-/*--------------------------------------------------------------*/
-/* analyzeCongestion() ---					*/
-/*								*/
-/* Given a trunk route at ycent, between ymin and ymax, score	*/
-/* the neighboring positions as a function of congestion and	*/
-/* offset from the ideal location.  Return the position of the	*/
-/* best location for the trunk route.				*/
-/*--------------------------------------------------------------*/
-
-static int analyzeCongestion(int ycent, int ymin, int ymax, int xmin, int xmax)
-{
-    int x, y, i, minidx = -1, sidx, n;
-    int *score, minscore;
-
-    score = (int *)malloc((ymax - ymin + 1) * sizeof(int));
-
-    for (y = ymin; y <= ymax; y++) {
-	sidx = y - ymin;
-	score[sidx] = ABSDIFF(ycent, y) * Num_layers;
-	for (x = xmin; x <= xmax; x++) {
-	    for (i = 0; i < Num_layers; i++) {
-		n = OBSVAL(x, y, i);
-		if (n & ROUTED_NET) score[sidx]++;
-		if (n & NO_NET) score[sidx]++;
-		if (n & PINOBSTRUCTMASK) score[sidx]++;
-	    }
-	}
-    }
-    minscore = MAXRT;
-    for (i = 0; i < (ymax - ymin + 1); i++) {
-	if (score[i] < minscore) {
-	    minscore = score[i];
-	    minidx = i + ymin;
-	}
-    }
-
-    free(score);
-    return minidx;
-}
-
-/*--------------------------------------------------------------*/
-/* createMask() ---						*/
-/*								*/
-/* Create mask limiting the area to search for routing		*/
-/*								*/
-/* For 2-node routes, find the two L-shaped routes between the	*/
-/* two closest points of the nodes.				*/
-/* For multi-node (>2) routes, find the best trunk line that	*/
-/* passes close to all nodes, and generate stems to the closest	*/
-/* point on each node.						*/
-/*								*/
-/* Optimizations:  (1) multi-node routes that are in a small	*/
-/* enough area, just mask the bounding box.  (2) Where nodes	*/
-/* at the end of two branches are closer to each other than to	*/
-/* the trunk, mask an additional cross-connection between the	*/
-/* two branches.						*/
-/*								*/
-/* Values are "halo" where there is no mask, 0 on the		*/
-/* closest "slack" routes to the ideal (typically 1), and	*/
-/* values increasing out to a distance of "halo" tracks away	*/
-/* from the ideal.  This allows a greater search area as the	*/
-/* number of passes of the search algorithm increases.		*/
-/*								*/
-/* To do:  Choose the position of trunk line based on		*/
-/* congestion analysis.						*/
-/*--------------------------------------------------------------*/
-
-static void createMask(NET net, u_char slack, u_char halo)
-{
-  NODE n1, n2;
-  DPOINT dtap;
-  int i, j, orient;
-  int dx, dy, gx1, gx2, gy1, gy2;
-  int xcent, ycent, xmin, ymin, xmax, ymax;
-
-  fillMask((u_char)halo);
-
-  xmin = net->xmin;
-  xmax = net->xmax;
-  ymin = net->ymin;
-  ymax = net->ymax;
-
-  xcent = net->trunkx;
-  ycent = net->trunky;
-
-  orient = 0;
-
-  // Construct the trunk line mask
-
-  if (!(net->flags & NET_VERTICAL_TRUNK) || (net->numnodes == 2)) {
-     // Horizontal trunk
-     orient |= 1;
-
-     ycent = analyzeCongestion(net->trunky, ymin, ymax, xmin, xmax);
-     ymin = ymax = ycent;
-
-     for (i = xmin - slack; i <= xmax + slack; i++) {
-	if (i < 0 || i >= NumChannelsX[0]) continue;
-	for (j = ycent - slack; j <= ycent + slack; j++) {
-	   if (j < 0 || j >= NumChannelsY[0]) continue;
-	   RMASK(i, j) = (u_char)0;
-	}
-     }
-
-     for (i = 1; i < halo; i++) {
-	gy1 = ycent - slack - i;
-	gy2 = ycent + slack + i;
-        for (j = xmin - slack - i; j <= xmax + slack + i; j++) {
-	   if (j < 0 || j >= NumChannelsX[0]) continue;
-	   if (gy1 >= 0)
-	      RMASK(j, gy1) = (u_char)i;
-	   if (gy2 < NumChannelsY[0])
-	      RMASK(j, gy2) = (u_char)i;
-	}
-	gx1 = xmin - slack - i;
-	gx2 = xmax + slack + i;
-        for (j = ycent - slack - i; j <= ycent + slack + i; j++) {
-	   if (j < 0 || j >= NumChannelsY[0]) continue;
-	   if (gx1 >= 0)
-	      RMASK(gx1, j) = (u_char)i;
-	   if (gx2 < NumChannelsX[0])
-	      RMASK(gx2, j) = (u_char)i;
-	}
-     }
-  }
-  if ((net->flags & NET_VERTICAL_TRUNK) || (net->numnodes == 2)) {
-     // Vertical trunk
-     orient |= 2;
-     xmin = xmax = xcent;
-
-     for (i = xcent - slack; i <= xcent + slack; i++) {
-	if (i < 0 || i >= NumChannelsX[0]) continue;
-	for (j = ymin - slack; j <= ymax + slack; j++) {
-	   if (j < 0 || j >= NumChannelsY[0]) continue;
-	   RMASK(i, j) = (u_char)0;
-	}
-     }
-
-     for (i = 1; i < halo; i++) {
-	gx1 = xcent - slack - i;
-	gx2 = xcent + slack + i;
-        for (j = ymin - slack - i; j <= ymax + slack + i; j++) {
-	   if (j < 0 || j >= NumChannelsY[0]) continue;
-	   if (gx1 >= 0)
-	      RMASK(gx1, j) = (u_char)i;
-	   if (gx2 < NumChannelsX[0])
-	      RMASK(gx2, j) = (u_char)i;
-	}
-	gy1 = ymin - slack - i;
-	gy2 = ymax + slack + i;
-        for (j = xcent - slack - i; j <= xcent + slack + i; j++) {
-	   if (j < 0 || j >= NumChannelsX[0]) continue;
-	   if (gy1 >= 0)
-	      RMASK(j, gy1) = (u_char)i;
-	   if (gy2 < NumChannelsY[0])
-	      RMASK(j, gy2) = (u_char)i;
-	}
-     }
-  }
-     
-  // Construct the branch line masks
-
-  for (n1 = net->netnodes; n1; n1 = n1->next) {
-     dtap = (n1->taps == NULL) ? n1->extend : n1->taps;
-     if (!dtap) continue;
-
-     if (orient | 1) 	// Horizontal trunk, vertical branches
-	create_vbranch_mask(n1->branchx, n1->branchy, ycent, slack, halo);
-     if (orient | 2) 	// Vertical trunk, horizontal branches
-	create_hbranch_mask(n1->branchy, n1->branchx, xcent, slack, halo);
-  }
-
-  // Look for branches that are closer to each other than to the
-  // trunk line.  If any are found, make a cross-connection between
-  // the branch end that is closer to the trunk and the branch that
-  // is its nearest neighbor.
-
-  if (orient | 1) {	// Horizontal trunk, vertical branches
-     for (n1 = net->netnodes; n1; n1 = n1->next) {
-	for (n2 = net->netnodes->next; n2; n2 = n2->next) {
-
-	   // Check if both ends are on the same side of the trunk
-	   if ((n2->branchy > ycent && n1->branchy > ycent) ||
-		  	(n2->branchy < ycent && n1->branchy < ycent)) {
-
-	      // Check if branches are closer to each other than
-	      // the shortest branch is away from the trunk
-	      dx = ABSDIFF(n2->branchx, n1->branchx);
-	      gy1 = ABSDIFF(n1->branchy, ycent);
-	      gy2 = ABSDIFF(n2->branchy, ycent);
-	      if ((dx < gy1) && (dx < gy2)) {
-		 if (gy1 < gy2)
-		    create_hbranch_mask(n1->branchy, n2->branchx,
-				n1->branchx, slack, halo);
-		 else
-		    create_hbranch_mask(n2->branchy, n2->branchx,
-				n1->branchx, slack, halo);
-	      }
- 	   }
-        }
-     }
-  }
-  if (orient | 2) {		// Vertical trunk, horizontal branches
-     for (n1 = net->netnodes; n1; n1 = n1->next) {
-	for (n2 = net->netnodes->next; n2; n2 = n2->next) {
-
-	   // Check if both ends are on the same side of the trunk
-	   if ((n2->branchx > xcent && n1->branchx > xcent) ||
-		  	(n2->branchx < xcent && n1->branchx < xcent)) {
-
-	      // Check if branches are closer to each other than
-	      // the shortest branch is away from the trunk
-	      dy = ABSDIFF(n2->branchy, n1->branchy);
-	      gx1 = ABSDIFF(n1->branchx, xcent);
-	      gx2 = ABSDIFF(n2->branchx, xcent);
-	      if ((dy < gx1) && (dy < gx2)) {
-		 if (gx1 < gx2)
-		    create_vbranch_mask(n1->branchx, n2->branchy,
-				n1->branchy, slack, halo);
-		 else
-		    create_vbranch_mask(n2->branchx, n2->branchy,
-				n1->branchy, slack, halo);
-	      }
- 	   }
-        }
-     }
-  }
-
-  // Allow routes at all tap and extension points
-  for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) {
-     for (dtap = n1->taps; dtap != NULL; dtap = dtap->next)
-	RMASK(dtap->gridx, dtap->gridy) = (u_char)0;
-     for (dtap = n1->extend; dtap != NULL; dtap = dtap->next)
-	RMASK(dtap->gridx, dtap->gridy) = (u_char)0;
-  }
-
-  if (Verbose > 2) {
-     if (net->numnodes == 2)
-        Fprintf(stdout, "Two-port mask has bounding box (%d %d) to (%d %d)\n",
-			xmin, ymin, xmax, ymax);
-     else
-        Fprintf(stdout, "multi-port mask has trunk line (%d %d) to (%d %d)\n",
-			xmin, ymin, xmax, ymax);
-  }
-}
-
-/*--------------------------------------------------------------*/
-/* fillMask() fills the Mask[] array with all 1s as a last	*/
-/* resort, ensuring that no valid routes are missed due to a	*/
-/* bad guess about the optimal route positions.			*/
-/*--------------------------------------------------------------*/
-
-static void fillMask(u_char value) {
-   memset((void *)RMask, (int)value,
-		(size_t)(NumChannelsX[0] * NumChannelsY[0]
-		* sizeof(u_char)));
-}
-
-/*--------------------------------------------------------------*/
 /* Free memory of an iroute glist and clear the Obs2		*/
 /* PR_ON_STACK flag for each location in the list.		*/
 /*--------------------------------------------------------------*/
@@ -2121,14 +1280,17 @@ free_glist(struct routeinfo_ *iroute)
 {
    POINT gpoint;
    PROUTE *Pr;
-
-   while (iroute->glist) {
-      gpoint = iroute->glist;
-      iroute->glist = iroute->glist->next;
-      Pr = &OBS2VAL(gpoint->x1, gpoint->y1, gpoint->layer);
-      Pr->flags &= ~PR_ON_STACK;
-      free(gpoint);
-  }
+   int i;
+   
+   for (i = 0; i < 6; i++) {
+      while (iroute->glist[i]) {
+         gpoint = iroute->glist[i];
+         iroute->glist[i] = iroute->glist[i]->next;
+         Pr = &OBS2VAL(gpoint->x1, gpoint->y1, gpoint->layer);
+         Pr->flags &= ~PR_ON_STACK;
+         freePOINT(gpoint);
+      }
+   }
 }
 
 /*--------------------------------------------------------------*/
@@ -2145,10 +1307,9 @@ free_glist(struct routeinfo_ *iroute)
 
 int doroute(NET net, u_char stage, u_char graphdebug)
 {
-  POINT gpoint;
   ROUTE rt1, lrt;
   NETLIST nlist;
-  int result, lastlayer, unroutable;
+  int result, lastlayer, unroutable, i;
   struct routeinfo_ iroute;
 
   if (!net) {
@@ -2161,11 +1322,12 @@ int doroute(NET net, u_char stage, u_char graphdebug)
   // Fill out route information record
   iroute.net = net;
   iroute.rt = NULL;
-  iroute.glist = NULL;
+  for (i = 0; i < 6; i++)
+     iroute.glist[i] = NULL;
   iroute.nsrc = NULL;
   iroute.nsrctap = NULL;
   iroute.maxcost = MAXRT;
-  iroute.do_pwrbus = (u_char)0;
+  iroute.do_pwrbus = FALSE;
   iroute.pwrbus_src = 0;
 
   lastlayer = -1;
@@ -2182,7 +1344,9 @@ int doroute(NET net, u_char stage, u_char graphdebug)
 
      if (graphdebug) highlight_source();
      if (graphdebug) highlight_dest();
-     if (graphdebug) highlight_starts(iroute.glist);
+     if (graphdebug)
+	for (i = 0; i < 6; i++)
+	    highlight_starts(iroute.glist[i]);
 
      rt1 = createemptyroute();
      rt1->netnum = net->netnum;
@@ -2277,7 +1441,6 @@ static int next_route_setup(struct routeinfo_ *iroute, u_char stage)
 {
   ROUTE rt;
   NODE node;
-  POINT gpoint;
   int  i, j;
   int  rval, result;
 
@@ -2294,7 +1457,7 @@ 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,
+	    rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist[0],
 			&iroute->bbox, stage);
 	    if (rval == -2) {
 		if (forceRoutable) {
@@ -2316,7 +1479,7 @@ 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,
+	result = set_route_to_net(iroute->net, rt, PR_SOURCE, &iroute->glist[0],
 			&iroute->bbox, stage);
 
         if (result == -2) {
@@ -2360,7 +1523,7 @@ static int next_route_setup(struct routeinfo_ *iroute, u_char stage)
      // flag from all such target nodes, and placing the positions
      // on the stack for processing again.
 
-     clear_non_source_targets(iroute->net, &iroute->glist);
+     clear_non_source_targets(iroute->net, &iroute->glist[0]);
   }
 
   if (Verbose > 1) {
@@ -2382,7 +1545,6 @@ static int next_route_setup(struct routeinfo_ *iroute, u_char stage)
 
 static int route_setup(struct routeinfo_ *iroute, u_char stage)
 {
-  POINT gpoint;
   int  i, j;
   u_int netnum, dir;
   int  result, rval, unroutable;
@@ -2442,25 +1604,10 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
      iroute->bbox.x1 = NumChannelsX[0];
      iroute->bbox.y1 = NumChannelsY[0];
 
-     while(1) {
-        rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist,
-			&iroute->bbox, stage);
-	if (rval == -2) {
-	   iroute->nsrc = iroute->nsrc->next;
-	   if (iroute->nsrc == NULL) break;
-	}
-	else break;
-     }
-     if (rval == -2) {
-        if (forceRoutable) make_routable(iroute->net->netnodes);
-	unable_to_route(iroute->net->netname, iroute->nsrc, forceRoutable);
-        return -1;
-     }
-
      if (iroute->do_pwrbus == FALSE) {
 
-        // Set associated routes to PR_SOURCE
-        rval = set_routes_to_net(iroute->net, PR_SOURCE, &iroute->glist,
+	// Set node to PR_SOURCE
+	rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist[0],
 		&iroute->bbox, stage);
 
         if (rval == -2) {
@@ -2468,6 +1615,10 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
            return -1;
         }
 
+        // Set associated routes to PR_SOURCE (okay to fail)
+        rval = set_routes_to_net(iroute->nsrc, iroute->net, PR_SOURCE,
+		&iroute->glist[0], &iroute->bbox, stage);
+
         // Now search for all other nodes on the same net that have not
         // yet been routed, and flag all of their taps as PR_TARGET
 
@@ -2484,7 +1635,14 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
 	      unable_to_route(iroute->net->netname, node, forceRoutable);
 	      if (result == 0) result = -1;
 	      unroutable++;
+	      break;
            }
+	   else if (rval == 1) continue;	/* This node was part of source */
+
+	   // And add associated routes
+	   rval = set_routes_to_net(node, iroute->net, PR_TARGET, NULL,
+			&iroute->bbox, stage);
+           if (rval == 0) result = 1;	/* (okay to fail) */
         }
 
         /* If there's only one node and it's not routable, then fail. */
@@ -2492,6 +1650,21 @@ 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);
+	   if (rval == -2) {
+	      iroute->nsrc = iroute->nsrc->next;
+	      if (iroute->nsrc == NULL) break;
+	   }
+	   else break;
+        }
+        if (rval == -2) {
+           if (forceRoutable) make_routable(iroute->net->netnodes);
+	   unable_to_route(iroute->net->netname, iroute->nsrc, forceRoutable);
+           return -1;
+        }
+
         /* Set all nodes that are NOT nsrc to an unused net number */
         for (node = iroute->net->netnodes; node; node = node->next) {
 	   if (node != iroute->nsrc) {
@@ -2502,8 +1675,6 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
      }
   }
 
-  // Check for the possibility that there is already a route to the target
-
   if (!result) {
      // Remove nodes of the net from Nodeinfo.nodeloc so that they will not be
      // used for crossover costing of future routes.
@@ -2601,7 +1772,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
   u_int forbid;
   GRIDP best, curpt;
   int rval;
-  u_char first = (u_char)1;
+  u_char first = TRUE;
   u_char check_order[6];
   u_char max_reached;
   u_char conflict;
@@ -2617,19 +1788,32 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
   
   for (pass = 0; pass < Numpasses; pass++) {
 
-    max_reached = (u_char)0;
+    max_reached = FALSE;
     if (!first && (Verbose > 2)) {
        Fprintf(stdout, "\n");
-       first = (u_char)1;
+       first = TRUE;
     }
     if (Verbose > 2) {
        Fprintf(stdout, "Pass %d", pass + 1);
        Fprintf(stdout, " (maxcost is %d)\n", iroute->maxcost);
     }
 
-    while ((gpoint = iroute->glist) != NULL) {
+    while (TRUE) {
 
-      iroute->glist = gpoint->next;
+      // Check priority stack and move down if 1st priorty is empty
+      while (iroute->glist[0] == NULL) {
+	 for (i = 0; i < 5; i++)
+	    iroute->glist[i] = iroute->glist[i + 1];
+	 iroute->glist[5] = NULL;
+	 if ((iroute->glist[0] == NULL) && (iroute->glist[1] == NULL) &&
+		(iroute->glist[2] == NULL) && (iroute->glist[3] == NULL) &&
+		(iroute->glist[4] == NULL))
+	    break;
+      }
+      gpoint = iroute->glist[0];
+      if (gpoint == NULL) break;
+
+      iroute->glist[0] = gpoint->next;
 
       curpt.x = gpoint->x1;
       curpt.y = gpoint->y1;
@@ -2642,7 +1826,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
       // ignore grid positions that have already been processed
       if (Pr->flags & PR_PROCESSED) {
 	 Pr->flags &= ~PR_ON_STACK;
-	 free(gpoint);
+	 freePOINT(gpoint);
 	 continue;
       }
 
@@ -2660,7 +1844,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 	    if (first) {
 	       if (Verbose > 2)
 		  Fprintf(stdout, "Found a route of cost ");
-	       first = (u_char)0;
+	       first = FALSE;
 	    }
 	    else if (Verbose > 2) {
 	       Fprintf(stdout, "|");
@@ -2683,7 +1867,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
          // Don't continue processing from the target
 	 Pr->flags |= PR_PROCESSED;
 	 Pr->flags &= ~PR_ON_STACK;
-	 free(gpoint);
+	 freePOINT(gpoint);
 	 continue;
       }
 
@@ -2704,14 +1888,14 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
          // from this point on the next pass, if needed.
 
          if (curpt.cost > iroute->maxcost) {
-	    max_reached = (u_char)1;
+	    max_reached = TRUE;
 	    gpoint->next = gunproc;
 	    gunproc = gpoint;
 	    continue;
 	 }
       }
       Pr->flags &= ~PR_ON_STACK;
-      free(gpoint);
+      freePOINT(gpoint);
 
       // check east/west/north/south, and bottom to top
 
@@ -2754,8 +1938,8 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 	       predecessor |= PR_PRED_W;
                if ((curpt.x + 1) < NumChannelsX[curpt.lay]) {
          	  if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
-         	     gpoint->next = iroute->glist;
-         	     iroute->glist = gpoint;
+         	     gpoint->next = iroute->glist[i];
+         	     iroute->glist[i] = gpoint;
                   }
                }
 	       break;
@@ -2766,8 +1950,8 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 	       predecessor |= PR_PRED_E;
                if ((curpt.x - 1) >= 0) {
          	  if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
-         	     gpoint->next = iroute->glist;
-         	     iroute->glist = gpoint;
+         	     gpoint->next = iroute->glist[i];
+         	     iroute->glist[i] = gpoint;
                   }
                }
 	       break;
@@ -2778,8 +1962,8 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 	       predecessor |= PR_PRED_N;
                if ((curpt.y - 1) >= 0) {
          	  if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
-         	     gpoint->next = iroute->glist;
-         	     iroute->glist = gpoint;
+         	     gpoint->next = iroute->glist[i];
+         	     iroute->glist[i] = gpoint;
                    }
                }
 	       break;
@@ -2790,8 +1974,8 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 	       predecessor |= PR_PRED_S;
                if ((curpt.y + 1) < NumChannelsY[curpt.lay]) {
          	  if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
-         	     gpoint->next = iroute->glist;
-         	     iroute->glist = gpoint;
+         	     gpoint->next = iroute->glist[i];
+         	     iroute->glist[i] = gpoint;
                   }
                }
 	       break;
@@ -2802,8 +1986,8 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 	       predecessor |= PR_PRED_U;
                if (curpt.lay > 0) {
          	  if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
-         	     gpoint->next = iroute->glist;
-         	     iroute->glist = gpoint;
+         	     gpoint->next = iroute->glist[i];
+         	     iroute->glist[i] = gpoint;
          	  }
                }
 	       break;
@@ -2814,8 +1998,8 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 	       predecessor |= PR_PRED_D;
                if (curpt.lay < (Num_layers - 1)) {
          	  if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
-         	     gpoint->next = iroute->glist;
-         	     iroute->glist = gpoint;
+         	     gpoint->next = iroute->glist[i];
+         	     iroute->glist[i] = gpoint;
          	  }
                }
 	       break;
@@ -2841,6 +2025,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 	   Fprintf(stdout, "Between positions (%d %d) and (%d %d)\n",
 			best.x, best.y, curpt.x, curpt.y);
 	}
+	route_set_connections(iroute->net, iroute->rt);
 	goto done;	/* route success */
     }
 
@@ -2850,7 +2035,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
     // If the cost of the route exceeded maxcost at one or more locations,
     // then increase maximum cost for next pass.
 
-    if (max_reached == (u_char)1) {
+    if (max_reached == TRUE) {
        iroute->maxcost <<= 1;
        // Cost overflow;  we're probably completely hosed long before this.
        if (iroute->maxcost > MAXRT) break;
@@ -2862,7 +2047,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 					// search to maxcost or to masking
 
     // Regenerate the stack of unprocessed nodes
-    iroute->glist = gunproc;
+    iroute->glist[0] = gunproc;
     gunproc = NULL;
     
   } // pass
@@ -2883,7 +2068,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
 done:
 
   // Regenerate the stack of unprocessed nodes
-  if (gunproc != NULL) iroute->glist = gunproc;
+  if (gunproc != NULL) iroute->glist[0] = gunproc;
   return rval;
   
 } /* route_segs() */
@@ -2906,1495 +2091,13 @@ static ROUTE createemptyroute(void)
    rt->segments = (SEG)NULL;
    rt->flags = (u_char)0;
    rt->next = (ROUTE)NULL;
+   rt->start.route = (ROUTE)NULL;
+   rt->end.route = (ROUTE)NULL;
    return rt;
 
 } /* createemptyroute(void) */
 
 /*--------------------------------------------------------------*/
-/* cleanup_net --						*/
-/*								*/
-/* Special handling for layers where needblock[] is non-zero,	*/
-/* and shows that two vias cannot be placed on adjacent routes. */
-/* emit_routed_net() will add specialnets to merge two adjacent	*/
-/* vias on the same route.  However, this cannot be used for	*/
-/* adjacent vias that are each in a different route record.  It	*/
-/* is easier just to find any such instances and remove them by	*/
-/* eliminating one of the vias and adding a segment to connect	*/
-/* the route to the neighboring via.				*/
-/*--------------------------------------------------------------*/
-
-static void cleanup_net(NET net)
-{
-   SEG segf, segl, seg;
-   ROUTE rt, rt2;
-   NODEINFO lnode;
-   int lf, ll, lf2, ll2;
-   u_char fcheck, lcheck;
-   u_char xcheckf, ycheckf, xcheckl, ycheckl; 
-
-   lf = ll = lf2 = ll2 = -1;
-
-   for (rt = net->routes; rt; rt = rt->next) {
-      fcheck = lcheck = FALSE;
-
-      // This problem will only show up on route endpoints.
-      // segf is the first segment of the route.
-      // segl is the last segment of the route.
-      // lf is the layer at the route start (layer first)
-      // lf2 is the layer of the second segment.
-      // ll is the layer at the route end (layer last)
-      // ll2 is the layer of the next-to-last segment
-
-      segf = rt->segments;
-      if (segf == NULL) continue;
-      if ((segf->next != NULL) && (segf->segtype == ST_VIA)) {
-	 if (segf->next->layer > segf->layer) {
-	    lf = segf->layer;
-	    lf2 = segf->layer + 1;
-	 }
-	 else {
-	    lf = segf->layer + 1;
-	    lf2 = segf->layer;
-	 }
-         // Set flag fcheck indicating that segf needs checking
-	 fcheck = TRUE;
-
-	 // We're going to remove the contact so it can't be a tap
-	 if ((lf < Pinlayers) && ((lnode = NODEIPTR(segf->x1, segf->y1, lf)) != NULL)
-			&& (lnode->nodesav != NULL))
-	    fcheck = FALSE;
-      }
-      xcheckf = needblock[lf] & VIABLOCKX;
-      ycheckf = needblock[lf] & VIABLOCKY;
-      if (!xcheckf && !ycheckf) fcheck = FALSE;
-
-      // Move to the next-to-last segment
-      for (segl = segf->next; segl && segl->next && segl->next->next;
-		segl = segl->next);
-
-      if (segl && (segl->next != NULL) && (segl->next->segtype == ST_VIA)) {
-	 if (segl->next->layer < segl->layer) {
-	    ll = segl->next->layer;
-	    ll2 = segl->next->layer + 1;
-	 }
-	 else {
-	    ll = segl->next->layer + 1;
-	    ll2 = segl->next->layer;
-	 }
-	 // Move segl to the last segment
-	 segl = segl->next;
-	 // Set flag lcheck indicating that segl needs checking.
-	 lcheck = TRUE;
-
-	 // We're going to remove the contact so it can't be a tap
-	 if ((ll < Pinlayers) && ((lnode = NODEIPTR(segl->x1, segl->y1, ll)) != NULL)
-			&& (lnode->nodesav != NULL))
-	    lcheck = FALSE;
-      }
-      xcheckl = needblock[ll] & VIABLOCKX;
-      ycheckl = needblock[ll] & VIABLOCKY;
-      if (!xcheckl && !ycheckl) lcheck = FALSE;
-
-      // For each route rt2 that is not rt, look at every via
-      // and see if it is adjacent to segf or segl.
-
-      for (rt2 = net->routes; rt2; rt2 = rt2->next) {
-
-         if ((fcheck == FALSE) && (lcheck == FALSE)) break;
-         if (rt2 == rt) continue;
-
-         for (seg = rt2->segments; seg; seg = seg->next) {
-	    if (seg->segtype & ST_VIA) {
-	       if (fcheck) {
-		  if ((seg->layer == lf) || ((seg->layer + 1) == lf)) {
-		     if (xcheckf && (seg->y1 == segf->y1) &&
-				(ABSDIFF(seg->x1, segf->x1) == 1)) {
-			if (seg->layer != segf->layer) {
-
-			   // Adjacent vias are different types.
-			   // Deal with it by creating a route between
-			   // the vias on their shared layer.  This
-			   // will later be made into a special net to
-			   // avoid notch DRC errors.
-
-			   SEG newseg;
-			   newseg = (SEG)malloc(sizeof(struct seg_));
-			   rt->segments = newseg;
-			   newseg->next = segf;
-			   newseg->layer = lf;
-			   newseg->segtype = ST_WIRE;
-			   newseg->x1 = segf->x1;
-			   newseg->y1 = segf->y1;
-			   newseg->x2 = seg->x1; 
-			   newseg->y2 = seg->y1;
-			}
-			else {
-			   // Change via to wire route, connect it to seg,
-			   // and make sure it has the same layer type as
-			   // the following route.
-			   segf->segtype = ST_WIRE;
-			   segf->x1 = seg->x1;
-			   segf->layer = lf2;
-		        }
-		     }
-		     else if (ycheckf && (seg->x1 == segf->x1) &&
-				(ABSDIFF(seg->y1, segf->y1) == 1)) {
-			if (seg->layer != segf->layer) {
-			   // Adjacent vias are different types.
-			   // Deal with it by creating a route between
-			   // the vias on their shared layer.  This
-			   // will later be made into a special net to
-			   // avoid notch DRC errors.
-
-			   SEG newseg;
-			   newseg = (SEG)malloc(sizeof(struct seg_));
-			   rt->segments = newseg;
-			   newseg->next = segf;
-			   newseg->layer = lf;
-			   newseg->segtype = ST_WIRE;
-			   newseg->x1 = segf->x1;
-			   newseg->y1 = segf->y1;
-			   newseg->x2 = seg->x1; 
-			   newseg->y2 = seg->y1;
-		        }
-		        else {
-			   // Change via to wire route, connect it to seg,
-			   // and make sure it has the same layer type as
-			   // the following route.
-			   segf->segtype = ST_WIRE;
-			   segf->y1 = seg->y1;
-			   segf->layer = lf2;
-			}
-		     }
-		  }
-	       }
-
-               if (lcheck) {
-		  if ((seg->layer == ll) || ((seg->layer + 1) == ll)) {
-		     if (xcheckl && (seg->y1 == segl->y1) &&
-				(ABSDIFF(seg->x1, segl->x1) == 1)) {
-			if (seg->layer != segl->layer) {
-
-			   // Adjacent vias are different types.
-			   // Deal with it by creating a route between
-			   // the vias on their shared layer.  This
-			   // will later be made into a special net to
-			   // avoid notch DRC errors.
-
-			   SEG newseg;
-			   newseg = (SEG)malloc(sizeof(struct seg_));
-			   segl->next = newseg;
-			   newseg->next = NULL;
-			   newseg->layer = ll;
-			   newseg->segtype = ST_WIRE;
-			   newseg->x1 = segl->x1;
-			   newseg->y1 = segl->y1;
-			   newseg->x2 = seg->x1; 
-			   newseg->y2 = seg->y1;
-			}
-			else {
-			   // Change via to wire route, connect it to seg,
-			   // and make sure it has the same layer type as
-			   // the previous route.
-			   segl->segtype = ST_WIRE;
-			   segl->x2 = seg->x2;
-			   segl->layer = ll2;
-			}
-		     }
-		     else if (ycheckl && (seg->x1 == segl->x1) &&
-				(ABSDIFF(seg->y1, segl->y1) == 1)) {
-			if (seg->layer != segl->layer) {
-
-			   // Adjacent vias are different types.
-			   // Deal with it by creating a route between
-			   // the vias on their shared layer.  This
-			   // will later be made into a special net to
-			   // avoid notch DRC errors.
-
-			   SEG newseg;
-			   newseg = (SEG)malloc(sizeof(struct seg_));
-			   segl->next = newseg;
-			   newseg->next = NULL;
-			   newseg->layer = ll;
-			   newseg->segtype = ST_WIRE;
-			   newseg->x1 = segl->x1;
-			   newseg->y1 = segl->y1;
-			   newseg->x2 = seg->x1; 
-			   newseg->y2 = seg->y1;
-			}
-			else {
-			   // Change via to wire route, connect it to seg,
-			   // and make sure it has the same layer type as
-			   // the previous route.
-			   segl->segtype = ST_WIRE;
-			   segl->y2 = seg->y2;
-			   segl->layer = ll2;
-			}
-		     }
-		  }
-	       }
-	    }
-	 }
-      }
-   }
-}
-
-/*--------------------------------------------------------------*/
-/* emit_routed_net --						*/
-/*								*/
-/* Core part of emit_routes().  Dumps the DEF format for a	*/
-/* complete net route to file Cmd.  If "special" is TRUE, then	*/
-/* it looks only for stub routes between a grid point and an	*/
-/* off-grid terminal, and dumps only the stub route geometry as	*/
-/* a SPECIALNET, which takes a width parameter.  This allows	*/
-/* the stub routes to be given the same width as a via, when	*/
-/* the via is larger than a route width, to avoid DRC notch	*/
-/* errors between the via and the terminal.  The SPECIALNETS	*/
-/* are redundant;  all routing information is in the NETS	*/
-/* section.  The SPECIALNETS only specify a wider route for the	*/
-/* stub connection.						*/
-/*--------------------------------------------------------------*/
-
-static void
-emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
-{
-   SEG seg, saveseg, lastseg, prevseg;
-   NODEINFO lnode, lnode1, lnode2;
-   ROUTE rt;
-   u_int dir1, dir2, tdir;
-   int layer;
-   int x = 0, y = 0, x2, y2;
-   double dc;
-   int lastx = -1, lasty = -1, lastlay;
-   int horizontal;
-   float offset1, offset2, stub, offset;
-   u_char cancel, segtype;
-   double invscale = (double)(1.0 / (double)iscale); 
-
-   /* If the STUB flag is set, then we need to write out the net name	*/
-   /* in the SPECIALNETS section.					*/
-
-   if ((special == (u_char)1) && (net->flags & NET_STUB)) {
-      fprintf(Cmd, ";\n- %s\n", net->netname);
-   }
-
-   u_char viaCheckX[MAX_LAYERS];
-   u_char viaCheckY[MAX_LAYERS];
-   double viaOffsetX[MAX_LAYERS][3];
-   double viaOffsetY[MAX_LAYERS][3];
-
-   /* Compute via offsets, if needed for adjacent vias on different nets. */
-
-   /* A well-designed standard cell set should not have DRC errors	*/
-   /* between vias spaced on adjacent tracks.  But not every standard	*/
-   /* cell set is well-designed. . .					*/
-
-   /* Example of offset measurements:					*/
-   /* viaOffsetX[layer][n]:  layer is the base layer of the via, n is	*/
-   /* 0 for the via one layer below, 1 for the same via, and 2 for the	*/
-   /* via one layer above.  Note that the n = 1 has interactions on two	*/
-   /* different metal layers.  The maximum distance is used.		*/
-
-   /* viaCheckX[1] is 0 if all of viaOffsetX[1][0-2] is zero.  This	*/
-   /*	 allows a quick determination if a check for neighboring vias	*/
-   /*    is required.							*/
-   /* viaOffsetX[1][0] is the additional spacing above the grid	width	*/
-   /*	 for via2-to-via1 (on metal2 only).				*/
-   /* viaOffsetX[1][1] is the additional spacing above the grid	width	*/
-   /*	 for via2-to-via2 (maximum for metal2 and metal3)		*/
-   /* viaOffsetX[1][2] is the additional spacing above the grid	width	*/
-   /*	 for via2-to-via3 (on metal3 only).				*/
-
-   viaOffsetX[0][0] = 0;		// nothing below the 1st via
-   viaOffsetY[0][0] = 0;
-   viaOffsetX[Num_layers - 1][2] = 0;	// nothing above the last via
-   viaOffsetY[Num_layers - 1][2] = 0;
-
-   for (layer = 0; layer < Num_layers - 1; layer++) {
-      double s1  = LefGetRouteSpacing(layer);
-      double s2  = LefGetRouteSpacing(layer + 1);
-      double p1x = PitchX[layer];
-      double p2x = PitchX[layer + 1];
-      double p1y = PitchY[layer];
-      double p2y = PitchY[layer + 1];
-      double w1x = LefGetViaWidth(layer, layer, 0);
-      double w1y = LefGetViaWidth(layer, layer, 1);
-      double w2x = LefGetViaWidth(layer, layer + 1, 0);
-      double w2y = LefGetViaWidth(layer, layer + 1, 1);
-    
-      double w0x, w0y, w3x, w3y;
-
-      viaCheckX[layer] = 0;
-      viaCheckY[layer] = 0;
-
-      if (layer > 0) {
-
-	 /* Space from via to (via - 1) */
-
-         w0x = LefGetViaWidth(layer - 1, layer, 0);
-         w0y = LefGetViaWidth(layer - 1, layer, 1);
-
-         dc = s1 + (w1x + w0x) / 2 - p1x;
-         viaOffsetX[layer][0] = (dc > 0.0) ? dc : 0.0;
-
-         dc = s1 + (w1y + w0y) / 2 - p1y;
-         viaOffsetY[layer][0] = (dc > 0.0) ? dc : 0.0;
-      }
-
-      /* Space from via to via (check both lower and upper metal layers) */
-
-      dc = s1 + w1x - p1x;
-      viaOffsetX[layer][1] = (dc > 0.0) ? dc : 0.0;
-
-      dc = s2 + w2x - p2x;
-      if (dc < 0.0) dc = 0.0;
-      if (dc > viaOffsetX[layer][1]) viaOffsetX[layer][1] = dc;
-
-      dc = s1 + w1y - p1y;
-      viaOffsetY[layer][1] = (dc > 0.0) ? dc : 0.0;
-
-      dc = s2 + w2y - p2y;
-      if (dc < 0.0) dc = 0.0;
-      if (dc > viaOffsetY[layer][1]) viaOffsetY[layer][1] = dc;
-
-      if (layer < Num_layers - 1) {
-
-	 /* Space from via to (via + 1) */
-
-         w3x = LefGetViaWidth(layer + 1, layer, 0);
-         w3y = LefGetViaWidth(layer + 1, layer, 1);
-
-         dc = s2 + (w2x + w3x) / 2 - p2x;
-         viaOffsetX[layer][2] = (dc > 0.0) ? dc : 0.0;
-
-         dc = s2 + (w2y + w3y) / 2 - p2y;
-         viaOffsetY[layer][2] = (dc > 0.0) ? dc : 0.0;
-      }
-
-      if (viaOffsetX[layer][0] > 0 || viaOffsetX[layer][1] > 0 ||
-		viaOffsetX[layer][2] > 0)
-	 viaCheckX[layer] = 1;
-      if (viaOffsetY[layer][0] > 0 || viaOffsetY[layer][1] > 0 ||
-		viaOffsetY[layer][2] > 0)
-	 viaCheckY[layer] = 1;
-   }
-
-   Pathon = -1;
-   lastlay = -1;
-
-   /* Insert routed net here */
-   for (rt = net->routes; rt; rt = rt->next) {
-      if (rt->segments && !(rt->flags & RT_OUTPUT)) {
-	 horizontal = FALSE;
-	 cancel = FALSE;
-
-	 // Check first position for terminal offsets
-	 seg = (SEG)rt->segments;
-	 lastseg = saveseg = seg;
-	 layer = seg->layer;
-	 if (seg) {
-
-	    // It is rare but possible to have a stub route off of an
-	    // endpoint via, so check this case, and use the layer type
-	    // of the via top if needed.
-
-	    if ((seg->segtype & ST_VIA) && seg->next && (seg->next->layer <=
-			seg->layer))
-	       layer++;
-
-	    lnode = (layer < Pinlayers) ? NODEIPTR(seg->x1, seg->y1, layer) : NULL;
-	    stub = (lnode) ? lnode->stub : 0.0;
-	    if (OBSVAL(seg->x1, seg->y1, layer) & STUBROUTE) {
-	       if ((special == (u_char)0) && (Verbose > 2))
-		  Fprintf(stdout, "Stub route distance %g to terminal"
-				" at %d %d (%d)\n", stub,
-				seg->x1, seg->y1, layer);
-
-	       dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
-	       x = (int)((REPS(dc)) * oscale);
-	       if (lnode->flags & NI_STUB_EW)
-		  dc += stub;
-	       x2 = (int)((REPS(dc)) * oscale);
-	       dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
-	       y = (int)((REPS(dc)) * oscale);
-	       if (lnode->flags & NI_STUB_NS)
-		  dc += stub;
-	       y2 = (int)((REPS(dc)) * oscale);
-	       if (lnode->flags & NI_STUB_EW) {
-		  horizontal = TRUE;
-
-		  // If the gridpoint ahead of the stub has a route
-		  // on the same net, and the stub is long enough
-		  // to come within a DRC spacing distance of the
-		  // other route, then lengthen it to close up the
-		  // distance and resolve the error.  (NOTE:  This
-		  // unnecessarily stretches routes to cover taps
-		  // that have not been routed to.  At least on the
-		  // test standard cell set, these rules remove a
-		  // handful of DRC errors and don't create any new
-		  // ones.  If necessary, a flag can be added to
-		  // distinguish routes from taps.
-
-		  if ((x < x2) && (seg->x1 < (NumChannelsX[layer] - 1))) {
-		     tdir = OBSVAL(seg->x1 + 1, seg->y1, layer);
-		     if ((tdir & ROUTED_NET_MASK) ==
-					(net->netnum | ROUTED_NET)) {
-			if (stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
-		      	   dc = Xlowerbound + (double)(seg->x1 + 1)
-					* PitchX[layer];
-		      	   x2 = (int)((REPS(dc)) * oscale);
-			}
-		     }
-		  }
-		  else if ((x > x2) && (seg->x1 > 0)) {
-		     tdir = OBSVAL(seg->x1 - 1, seg->y1, layer);
-		     if ((tdir & ROUTED_NET_MASK) ==
-					(net->netnum | ROUTED_NET)) {
-			if (-stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
-		      	   dc = Xlowerbound + (double)(seg->x1 - 1)
-					* PitchX[layer];
-		      	   x2 = (int)((REPS(dc)) * oscale);
-			}
-		     }
-		  }
-
-		  dc = oscale * 0.5 * LefGetRouteWidth(layer);
-		  if (special == (u_char)0) {
-		     // Regular nets include 1/2 route width at
-		     // the ends, so subtract from the stub terminus
-		     if (x < x2) {
-			x2 -= dc;
-			if (x >= x2) cancel = TRUE;
-		     }
-		     else {
-			x2 += dc;
-			if (x <= x2) cancel = TRUE;
-		     }
-		  }
-		  else {
-		     // Special nets don't include 1/2 route width
-		     // at the ends, so add to the route at the grid
-		     if (x < x2)
-			x -= dc;
-		     else
-			x += dc;
-
-		     // Routes that extend for more than one track
-		     // without a bend do not need a wide stub
-		     if (seg->x1 != seg->x2) cancel = TRUE;
-	  	  }
-	       }
-	       else {
-		  horizontal = FALSE;
-
-		  // If the gridpoint ahead of the stub has a route
-		  // on the same net, and the stub is long enough
-		  // to come within a DRC spacing distance of the
-		  // other route, then lengthen it to close up the
-		  // distance and resolve the error.
-
-		  if ((y < y2) && (seg->y1 < (NumChannelsY[layer] - 1))) {
-		     tdir = OBSVAL(seg->x1, seg->y1 + 1, layer);
-		     if ((tdir & ROUTED_NET_MASK) ==
-						(net->netnum | ROUTED_NET)) {
-			if (stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
-		      	   dc = Ylowerbound + (double)(seg->y1 + 1)
-					* PitchY[layer];
-		      	   y2 = (int)((REPS(dc)) * oscale);
-			}
-		     }
-		  }
-		  else if ((y > y2) && (seg->y1 > 0)) {
-		     tdir = OBSVAL(seg->x1, seg->y1 - 1, layer);
-		     if ((tdir & ROUTED_NET_MASK) ==
-						(net->netnum | ROUTED_NET)) {
-			if (-stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
-		      	   dc = Ylowerbound + (double)(seg->y1 - 1)
-					* PitchY[layer];
-		      	   y2 = (int)((REPS(dc)) * oscale);
-			}
-		     }
-		  }
-
-		  dc = oscale * 0.5 * LefGetRouteWidth(layer);
-		  if (special == (u_char)0) {
-		     // Regular nets include 1/2 route width at
-		     // the ends, so subtract from the stub terminus
-		     if (y < y2) {
-			y2 -= dc;
-			if (y >= y2) cancel = TRUE;
-		     }
-		     else {
-			y2 += dc;
-			if (y <= y2) cancel = TRUE;
-		     }
-		  }
-		  else {
-		     // Special nets don't include 1/2 route width
-		     // at the ends, so add to the route at the grid
-		     if (y < y2)
-			y -= dc;
-		     else
-			y += dc;
-
-		     // Routes that extend for more than one track
-		     // without a bend do not need a wide stub
-		     if (seg->y1 != seg->y2) cancel = TRUE;
-		  }
-	       }
-
-	       if (cancel == FALSE) {
-		  net->flags |= NET_STUB;
-		  rt->flags |= RT_STUB;
-		  pathstart(Cmd, layer, x2, y2, special, oscale, invscale, horizontal);
-		  pathto(Cmd, x, y, horizontal, x2, y2, invscale);
-	       }
-	       lastx = x;
-	       lasty = y;
-	       lastlay = layer;
-	    }
-	 }
-
-	 prevseg = NULL;
-	 lastseg = NULL;
-	 for (seg = rt->segments; seg; seg = seg->next) {
-	    layer = seg->layer;
-
-	    // Check for offset terminals at either point
-
-	    offset1 = 0.0;
-	    offset2 = 0.0;
-	    dir1 = 0;
-	    dir2 = 0;
-
-	    if (seg->segtype & ST_OFFSET_START) {
-	       dir1 = OBSVAL(seg->x1, seg->y1, seg->layer) & OFFSET_TAP;
-	       if ((dir1 == 0) && lastseg) {
-		  dir1 = OBSVAL(lastseg->x2, lastseg->y2, lastseg->layer)
-				& OFFSET_TAP;
-		  lnode1 = NODEIPTR(lastseg->x2, lastseg->y2, lastseg->layer);
-		  offset1 = lnode1->offset;
-	       }
-	       else {
-		  lnode1 = NODEIPTR(seg->x1, seg->y1, seg->layer);
-		  offset1 = lnode1->offset;
-	       }
-
-	       // Offset was calculated for vias;  plain metal routes
-	       // typically will need less offset distance, so subtract off
-	       // the difference.
-
-	       if (!(seg->segtype & ST_VIA)) {
-		  if (offset1 < 0) {
-		     offset1 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer, 
-				horizontal) - LefGetRouteWidth(seg->layer));
-		     if (offset1 > 0) offset1 = 0;
-		  }
-		  else if (offset1 > 0) {
-		     offset1 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer,
-				horizontal) - LefGetRouteWidth(seg->layer));
-		     if (offset1 < 0) offset1 = 0;
-		  }
-	       }
-
-	       if (special == (u_char)0) {
-		  if ((seg->segtype & ST_VIA) && (Verbose > 2))
-		     Fprintf(stdout, "Offset terminal distance %g to grid"
-					" at %d %d (%d)\n", offset1,
-					seg->x1, seg->y1, layer);
-	       }
-	    }
-	    if (seg->segtype & ST_OFFSET_END) {
-	       dir2 = OBSVAL(seg->x2, seg->y2, seg->layer) & OFFSET_TAP;
-	       if ((dir2 == 0) && seg->next) {
-		  dir2 = OBSVAL(seg->next->x1, seg->next->y1, seg->next->layer) &
-					OFFSET_TAP;
-		  lnode2 = NODEIPTR(seg->next->x1, seg->next->y1, seg->next->layer);
-		  offset2 = lnode2->offset;
-	       }
-	       else {
-		  lnode2 = NODEIPTR(seg->x2, seg->y2, seg->layer);
-		  offset2 = lnode2->offset;
-	       }
-
-	       // Offset was calculated for vias;  plain metal routes
-	       // typically will need less offset distance, so subtract off
-	       // the difference.
-
-	       if (!(seg->segtype & ST_VIA)) {
-		  if (offset2 < 0) {
-		     offset2 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer,
-				horizontal) - LefGetRouteWidth(seg->layer));
-		     if (offset2 > 0) offset2 = 0;
-		  }
-		  else if (offset2 > 0) {
-		     offset2 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer, 
-				horizontal) - LefGetRouteWidth(seg->layer));
-		     if (offset2 < 0) offset2 = 0;
-		  }
-	       }
-
-	       if (special == (u_char)0) {
-		  if ((seg->segtype & ST_VIA)
-					&& !(seg->segtype & ST_OFFSET_START))
-		     if (Verbose > 2)
-		        Fprintf(stdout, "Offset terminal distance %g to grid"
-					" at %d %d (%d)\n", offset2,
-					seg->x2, seg->y2, layer);
-	       }
-	    }
-
-	    // To do: pick up route layer name from lefInfo.
-	    // At the moment, technology names don't even match,
-	    // and are redundant between CIFLayer[] from the
-	    // config file and lefInfo.
-
-	    dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
-	    if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_EW)) dc += offset1;
-	    x = (int)((REPS(dc)) * oscale);
-	    dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
-	    if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_NS)) dc += offset1;
-	    y = (int)((REPS(dc)) * oscale);
-	    dc = Xlowerbound + (double)seg->x2 * PitchX[layer];
-	    if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_EW)) dc += offset2;
-	    x2 = (int)((REPS(dc)) * oscale);
-	    dc = Ylowerbound + (double)seg->y2 * PitchY[layer];
-	    if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_NS)) dc += offset2;
-	    y2 = (int)((REPS(dc)) * oscale);
-	    segtype = seg->segtype & ~(ST_OFFSET_START | ST_OFFSET_END);
-	    switch (segtype) {
-	       case ST_WIRE:
-
-		  // Normally layers change only at a via.  However, if
-		  // a via has been removed and replaced by a 1-track
-		  // segment to a neighboring via to avoid DRC errors
-		  // (see cleanup_net()), then a layer change may happen
-		  // between two ST_WIRE segments, and a new path should
-		  // be started.
-
-		  if ((Pathon != -1) && (lastlay != -1) && (lastlay != seg->layer))
-		     Pathon = 0;
-
-		  if (Pathon != 1) {	// 1st point of route seg
-		     if (x == x2) {
-			horizontal = FALSE;
-		     }
-		     else if (y == y2) {
-			horizontal = TRUE;
-		     }
-		     else if (Verbose > 3) {
-			// NOTE:  This is a development diagnostic.  The
-			// occasional non-Manhanhattan route is due to a
-			// tap offset and is corrected automatically by
-			// making an L-bend in the wire.
-
-		     	Flush(stdout);
-			Fprintf(stderr, "Warning:  non-Manhattan wire in route"
-				" at (%d %d) to (%d %d)\n", x, y, x2, y2);
-		     }
-		     if (special == (u_char)0) {
-			pathstart(Cmd, seg->layer, x, y, special, oscale, invscale,
-				horizontal);
-			lastx = x;
-			lasty = y;
-			lastlay = seg->layer;
-		     }
-		  }
-		  rt->flags |= RT_OUTPUT;
-		  if (horizontal && x == x2) {
-		     horizontal = FALSE;
-		  }
-		  if ((!horizontal) && y == y2) {
-		     horizontal = TRUE;
-		  }
-		  if (!(x == x2) && !(y == y2)) {
-		     horizontal = FALSE;
-		  }
-		  if (special == (u_char)0) {
-		     pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale);
-		     lastx = x2;
-		     lasty = y2;
-		  }
-
-		  // If a segment is 1 track long, there is a via on either
-		  // end, and the needblock flag is set for the layer, then
-		  // draw a stub route along the length of the track.
-
-		  if (horizontal && needblock[seg->layer] & VIABLOCKX) {
-		     if (ABSDIFF(seg->x2, seg->x1) == 1) {
-			if ((lastseg && lastseg->segtype == ST_VIA) ||
-			    (seg->next && seg->next->segtype == ST_VIA)) {
-			   if (special == (u_char)0) {
-			      net->flags |= NET_STUB;
-			      rt->flags |= RT_STUB;
-			   }
-			   else {
-			      if (Pathon != -1) Pathon = 0;
-			      pathstart(Cmd, layer, x, y, special, oscale,
-						invscale, horizontal);
-			      pathto(Cmd, x2, y2, horizontal, x, y, invscale);
-			      lastlay = layer;
-			   }
-			}
-		     }
-		  }
-		  else if (!horizontal && needblock[seg->layer] & VIABLOCKY) {
-		     if (ABSDIFF(seg->y2, seg->y1) == 1)  {
-			if ((lastseg && lastseg->segtype == ST_VIA) ||
-			    (seg->next && seg->next->segtype == ST_VIA)) {
-			   if (special == (u_char)0) {
-			      net->flags |= NET_STUB;
-			      rt->flags |= RT_STUB;
-			   }
-			   else {
-			      if (Pathon != -1) Pathon = 0;
-			      pathstart(Cmd, layer, x, y, special, oscale,
-						invscale, horizontal);
-			      pathto(Cmd, x2, y2, horizontal, x, y, invscale);
-			      lastlay = layer;
-			   }
-			}
-		     }
-		  }
-		  break;
-	       case ST_VIA:
-		  rt->flags |= RT_OUTPUT;
-		  if (special == (u_char)0) {
-		     double viaoffx, viaoffy;
-		     int vx = 0;
-		     int vy = 0;
-		     u_int tdirpp, tdirp, tdirn;
-		     u_char viaNL, viaNM, viaNU;
-		     u_char viaSL, viaSM, viaSU;
-		     u_char viaEL, viaEM, viaEU;
-		     u_char viaWL, viaWM, viaWU;
-
-		     if (lastseg == NULL) {
-			// Make sure last position is valid
-			lastx = x;
-			lasty = y;
-		     }
-
-		     // Check for vias between adjacent but different nets
-		     // that need position offsets to avoid a DRC spacing error
-
-		     // viaCheckX[layer] indicates whether a check for
-		     // vias is needed.  If so, record what vias are to east
-		     // and west.
-
-		     if (viaCheckX[layer] > 0) {
-
-			viaEL = viaEM = viaEU = 0;
-			viaWL = viaWM = viaWU = 0;
-
-			// Check for via to west
-			if (seg->x1 > 0) {
-			   tdir = OBSVAL(seg->x1 - 1, seg->y1, layer)
-					& ROUTED_NET_MASK;
-
-			   if (((tdir & NO_NET) == 0) && (tdir != 0) &&
-				(tdir != (net->netnum | ROUTED_NET))) {
-
-			      if (layer < Num_layers - 1) {
-			         tdirp = OBSVAL(seg->x1 - 1, seg->y1, layer + 1)
-					& ROUTED_NET_MASK;
-			         if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
-				     	(tdirp != (net->netnum | ROUTED_NET))) {
-
-			            if (layer < Num_layers - 2) {
-			               tdirpp = OBSVAL(seg->x1 - 1, seg->y1, layer + 2)
-						& ROUTED_NET_MASK;
-			               if (tdirp == tdirpp) viaWU = 1;
-				    }
-				 }
-			         if (tdir == tdirp) viaWM = 1;
-			      }
-			
-			      if (layer > 0) {
-			         tdirn = OBSVAL(seg->x1 - 1, seg->y1, layer - 1)
-					& ROUTED_NET_MASK;
-			         if (tdir == tdirn) viaWL = 1;
-			      }
-			   }
-			}
-
-			// Check for via to east
-			if (seg->x1 < NumChannelsX[layer] - 1) {
-			   tdir = OBSVAL(seg->x1 + 1, seg->y1, layer)
-					& ROUTED_NET_MASK;
-
-			   if (((tdir & NO_NET) == 0) && (tdir != 0) &&
-				(tdir != (net->netnum | ROUTED_NET))) {
-
-			      if (layer < Num_layers - 1) {
-			         tdirp = OBSVAL(seg->x1 + 1, seg->y1, layer + 1)
-					& ROUTED_NET_MASK;
-			         if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
-				     	(tdirp != (net->netnum | ROUTED_NET))) {
-
-			            if (layer < Num_layers - 2) {
-			               tdirpp = OBSVAL(seg->x1 + 1, seg->y1, layer + 2)
-						& ROUTED_NET_MASK;
-			               if (tdirp == tdirpp) viaEU = 1;
-				    }
-				 }
-			         if (tdir == tdirp) viaEM = 1;
-			      }
-			
-			      if (layer > 0) {
-			         tdirn = OBSVAL(seg->x1 + 1, seg->y1, layer - 1)
-					& ROUTED_NET_MASK;
-			         if (tdir == tdirn) viaEL = 1;
-			      }
-			   }
-			}
-
-			// Compute X offset
-			viaoffx = 0.0;
-
-			if (viaWL) viaoffx = viaOffsetX[layer][0];
-			else if (viaEL) viaoffx = -viaOffsetX[layer][0];
-
-			if (viaWM && viaOffsetX[layer][1] > viaoffx)
-			   viaoffx = viaOffsetX[layer][1];
-			else if (viaEM && -viaOffsetX[layer][1] < viaoffx)
-			   viaoffx = -viaOffsetX[layer][1];
-
-			if (viaWU && viaOffsetX[layer][2] > viaoffx)
-			   viaoffx = viaOffsetX[layer][2];
-			else if (viaEU && -viaOffsetX[layer][2] < viaoffx)
-			   viaoffx = -viaOffsetX[layer][2];
-
-		        vx = (int)((REPS(viaoffx)) * oscale);
-		     }
-
-		     // viaCheckY[layer] indicates whether a check for
-		     // vias is needed.  If so, record what vias are to north
-		     // and south.
-
-		     if (viaCheckY[layer] > 0) {
-
-			viaNL = viaNM = viaNU = 0;
-			viaSL = viaSM = viaSU = 0;
-
-			// Check for via to south
-			if (seg->y1 > 0) {
-			   tdir = OBSVAL(seg->x1, seg->y1 - 1, layer)
-					& ROUTED_NET_MASK;
-
-			   if (((tdir & NO_NET) == 0) && (tdir != 0) &&
-				(tdir != (net->netnum | ROUTED_NET))) {
-
-			      if (layer < Num_layers - 1) {
-			         tdirp = OBSVAL(seg->x1, seg->y1 - 1, layer + 1)
-					& ROUTED_NET_MASK;
-			         if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
-				     	(tdirp != (net->netnum | ROUTED_NET))) {
-
-			            if (layer < Num_layers - 2) {
-			               tdirpp = OBSVAL(seg->x1, seg->y1 - 1, layer + 2)
-						& ROUTED_NET_MASK;
-			               if (tdirp == tdirpp) viaSU = 1;
-				    }
-				 }
-			         if (tdir == tdirp) viaSM = 1;
-			      }
-			
-			      if (layer > 0) {
-			         tdirn = OBSVAL(seg->x1, seg->y1 - 1, layer - 1)
-					& ROUTED_NET_MASK;
-			         if (tdir == tdirn) viaSL = 1;
-			      }
-			   }
-			}
-
-			// Check for via to north
-			if (seg->y1 < NumChannelsY[layer] - 1) {
-			   tdir = OBSVAL(seg->x1, seg->y1 + 1, layer)
-					& ROUTED_NET_MASK;
-
-			   if (((tdir & NO_NET) == 0) && (tdir != 0) &&
-				(tdir != (net->netnum | ROUTED_NET))) {
-
-			      if (layer < Num_layers - 1) {
-			         tdirp = OBSVAL(seg->x1, seg->y1 + 1, layer + 1)
-					& ROUTED_NET_MASK;
-			         if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
-				     	(tdirp != (net->netnum | ROUTED_NET))) {
-
-			            if (layer < Num_layers - 2) {
-			               tdirpp = OBSVAL(seg->x1, seg->y1 + 1, layer + 2)
-						& ROUTED_NET_MASK;
-			               if (tdirp == tdirpp) viaNU = 1;
-				    }
-				 }
-			         if (tdir == tdirp) viaNM = 1;
-			      }
-			
-			      if (layer > 0) {
-			         tdirn = OBSVAL(seg->x1, seg->y1 + 1, layer - 1)
-					& ROUTED_NET_MASK;
-			         if (tdir == tdirn) viaNL = 1;
-			      }
-			   }
-			}
-
-			// Compute Y offset
-			viaoffy = 0;
-
-			if (viaSL) viaoffy = viaOffsetY[layer][0];
-			else if (viaNL) viaoffy = -viaOffsetY[layer][0];
-
-			if (viaSM && viaOffsetY[layer][1] > viaoffy)
-			   viaoffy = viaOffsetY[layer][1];
-			else if (viaNM && -viaOffsetY[layer][1] < viaoffy)
-			   viaoffy = -viaOffsetY[layer][1];
-
-			if (viaSU && viaOffsetY[layer][2] > viaoffy)
-			   viaoffy = viaOffsetY[layer][2];
-			else if (viaNU && -viaOffsetY[layer][2] < viaoffy)
-			   viaoffy = -viaOffsetY[layer][2];
-
-		        vy = (int)((REPS(viaoffy)) * oscale);
-		     }
-
-		     // via-to-via interactions are symmetric, so move each
-		     // via half the distance (?)
-
-		     pathvia(Cmd, layer, x + vx, y + vy, lastx, lasty,
-					seg->x1, seg->y1, invscale);
-
-		     lastx = x;
-		     lasty = y;
-		     lastlay = -1;
-		  }
-		  break;
-	       default:
-		  break;
-	    }
-
-	    // Break here on last segment so that seg and lastseg are valid
-	    // in the following section of code.
-
-	    if (seg->next == NULL) break;
-	    prevseg = lastseg;
-	    lastseg = seg;
-	 }
-
-	 // For stub routes, reset the path between terminals, since
-	 // the stubs are not connected.
-	 if (special == (u_char)1 && Pathon != -1) Pathon = 0;
-
-	 // Check last position for terminal offsets
-	 if (seg && ((seg != saveseg) || (seg->segtype & ST_WIRE))) {
-	     cancel = FALSE;
-	     layer = seg->layer;
-	     lnode = (layer < Pinlayers) ? NODEIPTR(seg->x2, seg->y2, layer) : NULL;
-
-	     // Look for stub routes and offset taps
-	     dir2 = OBSVAL(seg->x2, seg->y2, layer) & (STUBROUTE | OFFSET_TAP);
-
-	     if ((dir2 & OFFSET_TAP) && (seg->segtype & ST_VIA) && prevseg) {
-
-	        // Additional handling for offset taps.  When a tap position
-	        // is a via and is offset in the direction of the last
-	        // route segment, then a DRC violation can be created if
-	        // (1) the via is wider than the route width, and (2) the
-	        // adjacent track position is another via or a bend in the
-	        // route, and (3) the tap offset is large enough to create
-	        // a spacing violation between the via and the adjacent via
-	        // or perpendicular route.  If these three conditions are
-	        // satisfied, then generate a stub route the width of the
-	        // via and one track pitch in length back toward the last
-	        // track position.
-
- 	        // Problems only arise when the via width is larger than
-	        // the width of the metal route leaving the via.
- 
-	        offset = lnode->offset;
-	        if (LefGetViaWidth(seg->layer, lastseg->layer, 1 - horizontal) >
-			LefGetRouteWidth(lastseg->layer)) {
-
-		   // Problems only arise when the last segment is exactly
-		   // one track long.
-
-		   if ((ABSDIFF(lastseg->x2, lastseg->x1) == 1) ||
-			(ABSDIFF(lastseg->y2, lastseg->y1) == 1)) {
-
-		      if (prevseg->segtype & ST_VIA) {
-
-		 	 dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
-			 x = (int)((REPS(dc)) * oscale);
-			 dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
-			 y = (int)((REPS(dc)) * oscale);
-
-			 dc = Xlowerbound + (double)prevseg->x1 * PitchX[layer];
-			 x2 = (int)((REPS(dc)) * oscale);
-			 dc = Ylowerbound + (double)prevseg->y1 * PitchY[layer];
-			 y2 = (int)((REPS(dc)) * oscale);
-
-			 // Setup is (via, 1 track route, via with offset)
-
-			 if (prevseg->x1 != seg->x1) {
-			    if ((PitchX[lastseg->layer] -
-				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) -
-				0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 1) -
-				(prevseg->x1 - seg->x1) * offset)
-				< LefGetRouteSpacing(lastseg->layer)) {
-			       if (special == (u_char)0) {
-				  rt->flags |= RT_STUB;
-				  net->flags |= NET_STUB;
-			       }
-			       else {
-				  pathstart(Cmd, lastseg->layer, x, y,
-					(u_char)1, oscale, invscale, 1);
-				  pathto(Cmd, x2, y2, 1, x, y, invscale);
-		      		  lastx = x2;
-				  lasty = y2;
-			       }
-			    }
-			 }
-			 else if (prevseg->y1 != seg->y1) {
-			    if ((PitchY[lastseg->layer] -
-				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) -
-				0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 0)
-				- (prevseg->y1 - seg->y1) * offset)
-				< LefGetRouteSpacing(lastseg->layer)) {
-			       if (special == (u_char)0) {
-				 rt->flags |= RT_STUB;
-				 net->flags |= NET_STUB;
-			       }
-			       else {
-				  pathstart(Cmd, lastseg->layer, x, y,
-					(u_char)1, oscale, invscale, 0);
-				  pathto(Cmd, x2, y2, 0, x, y, invscale);
-		      		  lastx = x2;
-				  lasty = y2;
-			       }
-			    }
-			 }
-		      }
-		      else {	// Metal route bends at next track
-			 if (prevseg->x1 != seg->x1) {
-			    if ((PitchX[lastseg->layer] -
-				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) -
-				0.5 * LefGetRouteWidth(prevseg->layer) -
-				(prevseg->x1 - seg->x1) * offset)
-				< LefGetRouteSpacing(lastseg->layer)) {
-			       if (special == (u_char)0) {
-				 rt->flags |= RT_STUB;
-				 net->flags |= NET_STUB;
-			       }
-			       else {
-				  pathstart(Cmd, lastseg->layer, x, y,
-					(u_char)1, oscale, invscale, 1);
-				  pathto(Cmd, x2, y2, 1, x, y, invscale);
-		      		  lastx = x2;
-				  lasty = y2;
-			       }
-			    }
-			 }
-			 else if (prevseg->y1 != seg->y1) {
-			    if ((PitchY[lastseg->layer] -
-				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) -
-				0.5 * LefGetRouteWidth(prevseg->layer) -
-				(prevseg->y1 - seg->y1) * offset)
-				< LefGetRouteSpacing(lastseg->layer)) {
-			       if (special == (u_char)0) {
-				  rt->flags |= RT_STUB;
-				  net->flags |= NET_STUB;
-			       }
-			       else {
-				  pathstart(Cmd, lastseg->layer, x, y,
-					(u_char)1, oscale, invscale, 0);
-				  pathto(Cmd, x2, y2, 0, x, y, invscale);
-		      		  lastx = x2;
-				  lasty = y2;
-			       }
-			    }
-			 }
-		      }
-		   }
-	        }
-	     }
-
-	     // For stub routes, reset the path between terminals, since
-	     // the stubs are not connected.
-	     if (special == (u_char)1 && Pathon != -1) Pathon = 0;
-
-	     // Handling of stub routes
-	     if (dir2 & STUBROUTE) {
-	        stub = lnode->stub;
-		if ((special == (u_char)0) && (Verbose > 2))
-		   Fprintf(stdout, "Stub route distance %g to terminal"
-				" at %d %d (%d)\n",
-				stub, seg->x2, seg->y2, layer);
-
-		dc = Xlowerbound + (double)seg->x2 * PitchX[layer];
-		if (lnode->flags & NI_OFFSET_EW)
-		   dc += offset;
-		x = (int)((REPS(dc)) * oscale);
-		if (lnode->flags & NI_STUB_EW)
-		   dc += stub;
-		x2 = (int)((REPS(dc)) * oscale);
-		dc = Ylowerbound + (double)seg->y2 * PitchY[layer];
-		if (lnode->flags & NI_OFFSET_NS)
-		   dc += offset;
-		y = (int)((REPS(dc)) * oscale);
-		if (lnode->flags & NI_STUB_NS)
-		   dc += stub;
-		y2 = (int)((REPS(dc)) * oscale);
-		if (lnode->flags & NI_STUB_EW) {
-		   horizontal = TRUE;
-
-		   // If the gridpoint ahead of the stub has a route
-		   // on the same net, and the stub is long enough
-		   // to come within a DRC spacing distance of the
-		   // other route, then lengthen it to close up the
-		   // distance and resolve the error.
-
-		   if ((x < x2) && (seg->x2 < (NumChannelsX[layer] - 1))) {
-		      tdir = OBSVAL(seg->x2 + 1, seg->y2, layer);
-		      if ((tdir & ROUTED_NET_MASK) ==
-						(net->netnum | ROUTED_NET)) {
-			 if (stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
-		      	    dc = Xlowerbound + (double)(seg->x2 + 1)
-					* PitchX[layer];
-		      	    x2 = (int)((REPS(dc)) * oscale);
-			 }
-		      }
-		   }
-		   else if ((x > x2) && (seg->x2 > 0)) {
-		      tdir = OBSVAL(seg->x2 - 1, seg->y2, layer);
-		      if ((tdir & ROUTED_NET_MASK) ==
-						(net->netnum | ROUTED_NET)) {
-			 if (-stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
-		      	    dc = Xlowerbound + (double)(seg->x2 - 1)
-					* PitchX[layer];
-		      	    x2 = (int)((REPS(dc)) * oscale);
-			 }
-		      }
-		   }
-
-		   dc = oscale * 0.5 * LefGetRouteWidth(layer);
-		   if (special == (u_char)0) {
-		      // Regular nets include 1/2 route width at
-		      // the ends, so subtract from the stub terminus
-		      if (x < x2) {
-			 x2 -= dc;
-			 if (x >= x2) cancel = TRUE;
-		      }
-		      else {
-			 x2 += dc;
-			 if (x <= x2) cancel = TRUE;
-		      }
-		   }
-		   else {
-		      // Special nets don't include 1/2 route width
-		      // at the ends, so add to the route at the grid
-		      if (x < x2)
-			 x -= dc;
-		      else
-			 x += dc;
-
-		      // Routes that extend for more than one track
-		      // without a bend do not need a wide stub
-		      if (seg->x1 != seg->x2) cancel = TRUE;
-		   }
-		}
-		else {  /* lnode->flags & NI_STUB_EW implied */
-		   horizontal = FALSE;
-
-		   // If the gridpoint ahead of the stub has a route
-		   // on the same net, and the stub is long enough
-		   // to come within a DRC spacing distance of the
-		   // other route, then lengthen it to close up the
-		   // distance and resolve the error.
-
-		   if ((y < y2) && (seg->y2 < (NumChannelsY[layer] - 1))) {
-		      tdir = OBSVAL(seg->x2, seg->y2 + 1, layer);
-		      if ((tdir & ROUTED_NET_MASK) ==
-						(net->netnum | ROUTED_NET)) {
-			 if (stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
-		      	    dc = Ylowerbound + (double)(seg->y2 + 1)
-					* PitchY[layer];
-		      	    y2 = (int)((REPS(dc)) * oscale);
-			 }
-		      }
-		   }
-		   else if ((y > y2) && (seg->y2 > 0)) {
-		      tdir = OBSVAL(seg->x2, seg->y2 - 1, layer);
-		      if ((tdir & ROUTED_NET_MASK) ==
-						(net->netnum | ROUTED_NET)) {
-			 if (-stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
-		      	    dc = Ylowerbound + (double)(seg->y2 - 1)
-					* PitchY[layer];
-		      	    y2 = (int)((REPS(dc)) * oscale);
-			 }
-		      }
-		   }
-
-		   dc = oscale * 0.5 * LefGetRouteWidth(layer);
-		   if (special == (u_char)0) {
-		      // Regular nets include 1/2 route width at
-		      // the ends, so subtract from the stub terminus
-		      if (y < y2) {
-			 y2 -= dc;
-			 if (y >= y2) cancel = TRUE;
-		      }
-		      else {
-			 y2 += dc;
-			 if (y <= y2) cancel = TRUE;
-		      }
-		   }
-		   else {
-		      // Special nets don't include 1/2 route width
-		      // at the ends, so add to the route at the grid
-		      if (y < y2)
-			 y -= dc;
-		      else
-			 y += dc;
-
-		      // Routes that extend for more than one track
-		      // without a bend do not need a wide stub
-		      if (seg->y1 != seg->y2) cancel = TRUE;
-		   }
-		}
-		if (cancel == FALSE) {
-	           net->flags |= NET_STUB;
-	           rt->flags |= RT_STUB;
-		   if (Pathon != 1) {
-		      pathstart(Cmd, layer, x, y, special, oscale, invscale,
-				horizontal);
-		      lastx = x;
-		      lasty = y;
-		   }
-		   pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale);
-		   lastx = x2;
-		   lasty = y2;
-		}
-	    }
-	 }
-	 if (Pathon != -1) Pathon = 0;
-
-      } // if (rt->segments && !(rt->flags & RT_OUTPUT))
-   }
-}
-
-/*--------------------------------------------------------------*/
-/* emit_routes - DEF file output from the list of routes	*/
-/*								*/
-/*  Reads the <project>.def file and rewrites file		*/
-/*  <project>_route.def, where each net definition has the	*/
-/*  physical route appended.					*/
-/*								*/
-/*   ARGS: filename to list to					*/
-/*   RETURNS: nothing						*/
-/*   SIDE EFFECTS: 						*/
-/*   AUTHOR and DATE: steve beccue      Mon Aug 11 2003		*/
-/*--------------------------------------------------------------*/
-
-static void emit_routes(char *filename, double oscale, int iscale)
-{
-    FILE *Cmd;
-    int i, j, numnets, stubroutes;
-    char line[MAX_LINE_LEN + 1], *lptr = NULL;
-    char netname[MAX_NAME_LEN];
-    NET net = NULL;
-    ROUTE rt;
-    FILE *fdef;
-    u_char errcond = FALSE;
-    u_char need_cleanup = FALSE;
-
-    fdef = fopen(filename, "r");
-    if (fdef == NULL) {
-	if (strchr(filename, '.') == NULL) {
-	    char *extfilename = malloc(strlen(filename) + 5);
-	    sprintf(extfilename, "%s.def", filename);
-	    fdef = fopen(extfilename, "r");
-	    free(extfilename);
-	}
-    }
-    if (fdef == NULL) {
-	Fprintf(stderr, "emit_routes(): Cannot open DEF file for reading.\n");
-	return;
-    } 
-
-    if (!strcmp(filename, "stdout")) {
-	Cmd = stdout;
-    }
-    else {
-	char *dotptr;
-
-	if (filename == DEFfilename) {
-	    char *newDEFfile = (char *)malloc(strlen(filename) + 11);
-	    strcpy(newDEFfile, filename);
-	    dotptr = strrchr(newDEFfile, '.');
-	    if (dotptr)
-		strcpy(dotptr, "_route.def");
-	    else
-		strcat(newDEFfile, "_route.def");
-	    
-	    Cmd = fopen(newDEFfile, "w");
-	    free(newDEFfile);
-	}
-	else
-	    Cmd = fopen(filename, "w");
-    }
-    if (!Cmd) {
-	Fprintf(stderr, "emit_routes():  Couldn't open output (routed) DEF file.\n");
-	return;
-    }
-
-    // Copy DEF file up to NETS line
-    numnets = 0;
-    while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
-       lptr = line;
-       while (isspace(*lptr)) lptr++;
-       if (!strncmp(lptr, "NETS", 4)) {
-	  sscanf(lptr + 4, "%d", &numnets);
-	  break;
-       }
-       fputs(line, Cmd);
-    }
-    fputs(line, Cmd);	// Write the NETS line
-
-    // NOTE:  May want to remove this message.  It may merely reflect
-    // that the DEF file defined one or more SPECIALNETS.
-
-    if (numnets != Numnets) {
-      	Flush(stdout);
-	Fprintf(stderr, "emit_routes():  DEF file has %d nets, but we want"
-		" to write %d\n", numnets, Numnets);
-    }
-
-    // Quick check to see if cleanup_nets can be avoided
-    for (i = 0; i < Num_layers; i++)
-       if (needblock[i] & (VIABLOCKX | VIABLOCKY))
-	  break;
-
-    if (i != Num_layers) need_cleanup = TRUE;
-
-    for (i = 0; i < numnets; i++) {
-       if (errcond == TRUE) break;
-       while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
-	  if ((lptr = strchr(line, ';')) != NULL) {
-	     *lptr = '\n';
-	     *(lptr + 1) = '\0';
-	     break;
-	  }
-	  else {
-             lptr = line;
-             while (isspace(*lptr)) lptr++;
-	     if (*lptr == '-') {
-		lptr++;
-                while (isspace(*lptr)) lptr++;
-	        sscanf(lptr, "%s", netname);
-		fputs(line, Cmd);
-	     }
-	     else if (*lptr == '+') {
-		lptr++;
-                while (isspace(*lptr)) lptr++;
-		if (!strncmp(lptr, "ROUTED", 6)) {
-		   // This net is being handled by qrouter, so remove
-		   // the original routing information
-		   while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
-		      if ((lptr = strchr(line, ';')) != NULL) {
-			 *lptr = '\n';
-			 *(lptr + 1) = '\0';
-			 break;
-		      }
-		   }
-		   break;
-		}
-		else
-		   fputs(line, Cmd);
-	     }
-	     else if (!strncmp(lptr, "END", 3)) {	// This should not happen
-		fputs(line, Cmd);
-		errcond = TRUE;
-		break;
-	     }
-	     else
-		fputs(line, Cmd);
-	  }
-       }
-
-       /* Find this net */
-
-       for (j = 0; j < Numnets; j++) {
-          net = Nlnets[j];
-	  if (!strcmp(net->netname, netname))
-	     break;
-       }
-       if (!net) {
-	  Fprintf(stderr, "emit_routes():  Net %s cannot be found.\n",
-		netname);
-
-	  /* Dump rest of net and continue---no routing information */
-	  *(lptr) = ';';
-	  fputs(line, Cmd);
-	  continue;
-       }
-       else {
-	  /* Add last net terminal, without the semicolon */
-	  fputs(line, Cmd);
-
-	  if (need_cleanup) cleanup_net(net);
-	  emit_routed_net(Cmd, net, (u_char)0, oscale, iscale);
-	  fprintf(Cmd, ";\n");
-       }
-    }
-
-    // Finish copying the rest of the NETS section
-    if (errcond == FALSE) {
-       while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
-	  lptr = line;
-	  while (isspace(*lptr)) lptr++;
-	  fputs(line, Cmd);
-	  if (!strncmp(lptr, "END", 3)) {
-	     break;
-	  }
-       }
-    }
-
-    // Determine how many stub routes we will write to SPECIALNETS
-    // Also reset the OUTPUT flag for each route needing a stubroute
-    // to be written.
-
-    stubroutes = 0;
-    for (i = 0; i < Numnets; i++) {
-	net = Nlnets[i];
-	if (net->flags & NET_STUB) {
-	    stubroutes++;
-	    for (rt = net->routes; rt; rt = rt->next)
-		if (rt->flags & RT_STUB)
-		    rt->flags &= ~RT_OUTPUT;
-	}
-    }
-
-    // If there were stub routes, repeat them in SPECIALNETS at the
-    // proper width.
-    if (stubroutes > 0) {
-
-        fprintf(Cmd, "\nSPECIALNETS %d ", stubroutes);
-	for (i = 0; i < Numnets; i++) {
-	     net = Nlnets[i];
-	     emit_routed_net(Cmd, net, (u_char)1, oscale, iscale);
-	}
-	fprintf(Cmd, ";\nEND SPECIALNETS\n");
-    }    
-
-    // Finish copying the rest of the file
-    while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
-       fputs(line, Cmd);
-    }
-    fclose(fdef);
-    fclose(Cmd);
-
-} /* emit_routes() */
-
-/*--------------------------------------------------------------*/
 /* helpmessage - tell user how to use the program		*/
 /*								*/
 /*   ARGS: none.						*/
@@ -4423,7 +2126,7 @@ static void helpmessage(void)
 	Fprintf(stdout, "\t-g <name>\t\t\tSpecify global ground bus name.\n");
 	Fprintf(stdout, "\t-r <value>\t\t\tForce output resolution scale.\n");
 	Fprintf(stdout, "\t-f       \t\t\tForce all pins to be routable.\n");
-	Fprintf(stdout, "\t-k <level>\t\t\tLevel of effort to keep trying.\n");
+	Fprintf(stdout, "\t-e <level>\t\t\tLevel of effort to keep trying.\n");
 	Fprintf(stdout, "\n");
     }
 #ifdef TCL_QROUTER
diff --git a/qrouter.h b/qrouter.h
index f1fa4c6..7278353 100644
--- a/qrouter.h
+++ b/qrouter.h
@@ -192,16 +192,28 @@ typedef struct route_ *ROUTE;
 typedef struct node_ *NODE;
 
 struct route_ {
-  ROUTE  next;
-  int    netnum;
-  SEG    segments;
-  u_char flags;         // See below for flags
+   ROUTE  next;
+   int    netnum;
+   SEG    segments;
+   union {
+      ROUTE route;
+      NODE  node;     
+   } start;
+   union {
+      ROUTE route;
+      NODE  node;     
+   } end;
+   u_char flags;         // See below for flags
 };
 
 /* Definitions for flags in struct route_ */
 
-#define RT_OUTPUT	0x1	// Route has been output
-#define RT_STUB		0x2	// Route has at least one stub route
+#define RT_OUTPUT	0x01	// Route has been output
+#define RT_STUB		0x02	// Route has at least one stub route
+#define RT_START_NODE	0x04	// Route starts on a node
+#define RT_END_NODE	0x08	// Route ends on a node
+#define RT_VISITED	0x10	// Flag for recursive search
+#define RT_RIP		0x20	// Flag for route rip-up
 
 /* Structure used to hold nodes, saved nodes, and stub/offset info */
 
@@ -304,7 +316,7 @@ struct netlist_ {
 struct routeinfo_ {
    NET net;
    ROUTE rt;
-   POINT glist;
+   POINT glist[6];	/* Lists of points by priority 0 to 5 */
    NODE nsrc;
    DPOINT nsrctap;
    int maxcost;
@@ -421,7 +433,6 @@ extern int    Numnets;
 extern int    Pinlayers;		// Number of layers containing pin info.
 
 extern u_char Verbose;
-extern u_char keepTrying;
 extern u_char forceRoutable;
 extern u_char maskMode;
 extern u_char mapType;
@@ -444,32 +455,31 @@ extern char *gndnet;
 
 /* Function prototypes */
 
+static int next_route_setup(struct routeinfo_ *iroute, u_char stage);
+static int route_setup(struct routeinfo_ *iroute, u_char stage);
+static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug);
+static ROUTE createemptyroute(void);
+static void helpmessage(void);
+
 int    set_num_channels(void);
 int    allocate_obs_array(void);
 int    countlist(NETLIST net);
 int    runqrouter(int argc, char *argv[]);
 
 void   read_def(char *filename);
-int    write_def(char *filename);
 
 #ifdef TCL_QROUTER
 int    write_delays(char *filename);
 #endif
 
-char  *print_node_name(NODE node);
-void   print_nets(char *filename);
-void   print_routes(char *filename);
-void   print_nlgates(char *filename);
-void   print_net(NET net);
-void   print_gate(GATE gate);
-
 int    dofirststage(u_char graphdebug, int debug_netnum);
-int    dosecondstage(u_char graphdebug, u_char singlestep);
-int    dothirdstage(u_char graphdebug, int debug_netnum);
+int    dosecondstage(u_char graphdebug, u_char singlestep,
+		u_char onlybreak, u_int effort);
+int    dothirdstage(u_char graphdebug, int debug_netnum, u_int effort);
 
 int    doroute(NET net, u_char stage, u_char graphdebug);
 NET    getnettoroute(int order);
-int    route_net_ripup(NET net, u_char graphdebug);
+int    route_net_ripup(NET net, u_char graphdebug, u_char onlybreak);
 
 #ifdef TCL_QROUTER
 void   tcl_printf(FILE *, const char *, ...);
diff --git a/qrouter.tcl.in b/qrouter.tcl.in
index 61a1509..d13a472 100644
--- a/qrouter.tcl.in
+++ b/qrouter.tcl.in
@@ -84,8 +84,62 @@ proc qrouter::write_congested {filename} {
    }
 }
 
+#------------------------------------------------------
+# Standard routing script
+#------------------------------------------------------
+
+proc qrouter::standard_route {{filename ""} {doquit true}} {
+    puts stdout "*** Running stage1 routing with defaults"
+    set result [stage1]
+    if {$result > 0} {
+	set msize 10
+	while {true} {
+	    set lastresult $result
+	    puts -nonewline stdout "*** Running stage2 routing"
+	    puts stdout " with options mask $msize, effort 10"
+            set result [stage2 mask $msize effort 10]
+	    if {!$result} {break}
+	    if {$result > $lastresult} {
+		puts -nonewline stdout "*** Running stage2 routing"
+		puts stdout " with options mask none, effort 20"
+		set result [stage2 mask none effort 20]
+		if {!$result} {break}
+		if {$result < 5} {
+		    puts -nonewline stdout "*** Running stage2 routing"
+		    puts stdout " with options mask none, effort 50"
+		    set result [stage2 mask none effort 50]
+		}
+		if {!$result} {break}
+	    }
+	    incr msize 10
+	}
+    }
+    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 break, mask none"
+	set result [stage2 break mask none]
+    }
+    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]
+    }
+    if {$filename != ""} {
+        puts stdout "*** Writing DEF file $filename"
+	write_def $filename
+    } else {
+        puts stdout "*** Writing DEF file (default)"
+	write_def
+    }
+    if {(!$result) && $doquit} {quit}
+}
+
 #---------------------------------------------------------
-# Standard sequence of events (subject to change):
+# Simple sequence of events (subject to change):
 # Upon first success, write the DEF file output and quit.
 # If "stage2 mask none" leaves failing routes, then write
 # the routes done so far to the DEF file output and remain
@@ -94,7 +148,7 @@ proc qrouter::write_congested {filename} {
 # second try.
 #---------------------------------------------------------
 
-proc qrouter::standard_route {} {
+proc qrouter::simple_route {} {
    if {![stage1]} {write_def; quit}
    if {![stage2]} {write_def; quit}
    set result [stage2 mask none]
diff --git a/tclqrouter.c b/tclqrouter.c
index aefd9c9..d077a50 100644
--- a/tclqrouter.c
+++ b/tclqrouter.c
@@ -808,6 +808,7 @@ qrouter_stage1(ClientData clientData, Tcl_Interp *interp,
 {
     u_char dodebug;
     u_char dostep;
+    u_char saveForce, saveOverhead;
     int i, idx, idx2, val, result, failcount = 0;
     NET net = NULL;
 
@@ -830,7 +831,9 @@ qrouter_stage1(ClientData clientData, Tcl_Interp *interp,
     dodebug = FALSE;
     dostep = FALSE;
     maskMode = MASK_AUTO;	// Mask mode is auto unless specified
-    forceRoutable = FALSE;	// Don't force unless specified
+
+    // Save these global defaults in case they are locally changed
+    saveForce = forceRoutable;
 
     if (objc >= 2) {
 	for (i = 1; i < objc; i++) {
@@ -852,7 +855,7 @@ qrouter_stage1(ClientData clientData, Tcl_Interp *interp,
 		case ForceIdx:
 		    forceRoutable = TRUE;
 		    break;
-	
+
 		case RouteIdx:
 		    if (i >= objc - 1) {
 			Tcl_WrongNumArgs(interp, 0, objv, "route ?net?");
@@ -935,6 +938,9 @@ qrouter_stage1(ClientData clientData, Tcl_Interp *interp,
 
     if (stepnet >= (Numnets - 1)) stepnet = -1;
 
+    // Restore global defaults in case they were locally changed
+    forceRoutable = saveForce;
+
     return QrouterTagCallback(interp, objc, objv);
 }
 
@@ -966,23 +972,29 @@ qrouter_stage1(ClientData clientData, Tcl_Interp *interp,
 /*  stage2 route <net>	Route net named <net> only.	*/
 /*							*/
 /*  stage2 force	Force a terminal to be routable	*/
-/*  stage2 tries <n>	Keep trying n additional times	*/
+/*  stage2 break	Only rip up colliding segment	*/
+/*  stage2 effort <n>	Level of effort (default 100)	*/
 /*------------------------------------------------------*/
 
 static int
 qrouter_stage2(ClientData clientData, Tcl_Interp *interp,
                int objc, Tcl_Obj *CONST objv[])
 {
+    u_int  effort;
     u_char dodebug;
     u_char dostep;
+    u_char onlybreak;
+    u_char saveForce, saveOverhead;
     int i, idx, idx2, val, result, failcount;
     NET net = NULL;
 
     static char *subCmds[] = {
-	"debug", "mask", "limit", "route", "force", "tries", "step", NULL
+	"debug", "mask", "limit", "route", "force", "tries", "step",
+	"break", "effort", NULL
     };
     enum SubIdx {
-	DebugIdx, MaskIdx, LimitIdx, RouteIdx, ForceIdx, TriesIdx, StepIdx
+	DebugIdx, MaskIdx, LimitIdx, RouteIdx, ForceIdx, TriesIdx, StepIdx,
+	BreakIdx, EffortIdx
     };
    
     static char *maskSubCmds[] = {
@@ -996,9 +1008,12 @@ qrouter_stage2(ClientData clientData, Tcl_Interp *interp,
 
     dodebug = FALSE;
     dostep = FALSE;
+    onlybreak = FALSE;
     maskMode = MASK_AUTO;	// Mask mode is auto unless specified
-    forceRoutable = FALSE;	// Don't force unless specified
+    // Save these global defaults in case they are locally changed
+    saveForce = forceRoutable;
     ripLimit = 10;		// Rip limit is 10 unless specified
+    effort = 100;		// Moderate to high effort
 
     if (objc >= 2) {
 	for (i = 1; i < objc; i++) {
@@ -1016,11 +1031,26 @@ qrouter_stage2(ClientData clientData, Tcl_Interp *interp,
 		case StepIdx:
 		    dostep = TRUE;
 		    break;
+
+		case BreakIdx:
+		    onlybreak = TRUE;
+		    break;
 	
 		case ForceIdx:
 		    forceRoutable = TRUE;
 		    break;
 
+		case EffortIdx:
+		    if (i >= objc - 1) {
+			Tcl_WrongNumArgs(interp, 0, objv, "effort ?num?");
+			return TCL_ERROR;
+		    }
+		    i++;
+		    result = Tcl_GetIntFromObj(interp, objv[i], &val);
+		    if (result != TCL_OK) return result;
+		    effort = (u_int)val;
+		    break;
+
 		case TriesIdx:
 		    if (i >= objc - 1) {
 			Tcl_WrongNumArgs(interp, 0, objv, "tries ?num?");
@@ -1029,7 +1059,9 @@ qrouter_stage2(ClientData clientData, Tcl_Interp *interp,
 		    i++;
 		    result = Tcl_GetIntFromObj(interp, objv[i], &val);
 		    if (result != TCL_OK) return result;
-		    keepTrying = (u_char)val;
+		    Tcl_SetResult(interp, "\"tries\" deprecated, "
+				"use \"effort\" instead.", NULL);
+		    effort = (u_char)val * 100;
 		    break;
 	
 		case RouteIdx:
@@ -1093,12 +1125,16 @@ qrouter_stage2(ClientData clientData, Tcl_Interp *interp,
     }
 
     if (net == NULL)
-	failcount = dosecondstage(dodebug, dostep);
+	failcount = dosecondstage(dodebug, dostep, onlybreak, effort);
     else
-	failcount = route_net_ripup(net, dodebug);
+	failcount = route_net_ripup(net, dodebug, onlybreak);
     Tcl_SetObjResult(interp, Tcl_NewIntObj(failcount));
 
     draw_layout();
+
+    // Restore global defaults in case they were locally changed
+    forceRoutable = saveForce;
+
     return QrouterTagCallback(interp, objc, objv);
 }
 
@@ -1127,22 +1163,25 @@ qrouter_stage2(ClientData clientData, Tcl_Interp *interp,
 /*  stage3 route <net>	Route net named <net> only.	*/
 /*							*/
 /*  stage3 force	Force a terminal to be routable	*/
+/*  stage3 effort	Level of effort (default 100)	*/
 /*------------------------------------------------------*/
 
 static int
 qrouter_stage3(ClientData clientData, Tcl_Interp *interp,
                int objc, Tcl_Obj *CONST objv[])
 {
+    u_int effort;
     u_char dodebug;
     u_char dostep;
+    u_char saveForce, saveOverhead;
     int i, idx, idx2, val, result, failcount = 0;
     NET net = NULL;
 
     static char *subCmds[] = {
-	"debug", "mask", "route", "force", "step", NULL
+	"debug", "mask", "route", "force", "step", "effort", NULL
     };
     enum SubIdx {
-	DebugIdx, MaskIdx, RouteIdx, ForceIdx, StepIdx
+	DebugIdx, MaskIdx, RouteIdx, ForceIdx, StepIdx, EffortIdx
     };
    
     static char *maskSubCmds[] = {
@@ -1157,7 +1196,10 @@ qrouter_stage3(ClientData clientData, Tcl_Interp *interp,
     dodebug = FALSE;
     dostep = FALSE;
     maskMode = MASK_AUTO;	// Mask mode is auto unless specified
-    forceRoutable = FALSE;	// Don't force unless specified
+    effort = 100;		// Moderate to high effort
+
+    // Save these global defaults in case they are locally changed
+    saveForce = forceRoutable;
 
     if (objc >= 2) {
 	for (i = 1; i < objc; i++) {
@@ -1179,7 +1221,18 @@ qrouter_stage3(ClientData clientData, Tcl_Interp *interp,
 		case ForceIdx:
 		    forceRoutable = TRUE;
 		    break;
-	
+
+		case EffortIdx:
+		    if (i >= objc - 1) {
+			Tcl_WrongNumArgs(interp, 0, objv, "effort ?num?");
+			return TCL_ERROR;
+		    }
+		    i++;
+		    result = Tcl_GetIntFromObj(interp, objv[i], &val);
+		    if (result != TCL_OK) return result;
+		    effort = (u_int)val;
+		    break;
+
 		case RouteIdx:
 		    if (i >= objc - 1) {
 			Tcl_WrongNumArgs(interp, 0, objv, "route ?net?");
@@ -1233,7 +1286,7 @@ qrouter_stage3(ClientData clientData, Tcl_Interp *interp,
     else stepnet++;
 
     if (net == NULL)
-	failcount = dothirdstage(dodebug, stepnet);
+	failcount = dothirdstage(dodebug, stepnet, effort);
     else {
 	if ((net != NULL) && (net->netnodes != NULL)) {
 	    result = doroute(net, (u_char)0, dodebug);
@@ -1262,6 +1315,9 @@ qrouter_stage3(ClientData clientData, Tcl_Interp *interp,
 
     if (stepnet >= (Numnets - 1)) stepnet = -1;
 
+    // Restore global defaults in case they were locally changed
+    forceRoutable = saveForce;
+
     return QrouterTagCallback(interp, objc, objv);
 }
 
@@ -1307,7 +1363,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);
+		   ripup_net(net, (u_char)1, (u_char)1);
 		}
 		draw_layout();
 		break;
@@ -1315,7 +1371,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);
+			ripup_net(net, (u_char)1, (u_char)1);
 		}
 		draw_layout();
 		break;
@@ -1335,6 +1391,7 @@ qrouter_remove(ClientData clientData, Tcl_Interp *interp,
 /*			ordered by the standard metric	*/
 /*   failing unordered	Move all nets to FailedNets,	*/
 /*			as originally ordered		*/
+/*   failing summary	List of failed and total nets	*/
 /*------------------------------------------------------*/
 
 static int

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/qrouter.git



More information about the debian-science-commits mailing list