/*--------------------------------------------------------------*/
/*  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;

struct _savepath {
    u_char active;
    int x;
    int y;
    int orient;
} path_delayed;

/*--------------------------------------------------------------*/
/* Output a list of failed nets.				*/
/*--------------------------------------------------------------*/

int write_failed(char *filename)
{
    FILE *ffail;
    NET net;
    NETLIST nl;
    int failcount;

    failcount = countlist(FailedNets);
    if (failcount == 0) {
	Fprintf(stdout, "There are no failing net routes.\n");
	return 0;
    }

    ffail = fopen(filename, "w");
    if (ffail == NULL) {
	Fprintf(stderr, "Could not open file %s for writing.\n", filename);
	return 1;
    }
    fprintf(ffail, "%d nets failed to route:\n", failcount);

    for (nl = FailedNets; nl; nl = nl->next) {
        net = nl->net;
        fprintf(ffail, " %s\n", net->netname);
    }

    fclose(ffail);
    return 0;
}

/*--------------------------------------------------------------*/
/* Write the output annotated DEF file.				*/
/*--------------------------------------------------------------*/

int write_def(char *filename)
{
   NET net;
   NETLIST nl;

   emit_routes((filename == NULL) ? DEFfilename : filename,
		Scales.oscale, Scales.iscale);

   Fprintf(stdout, "----------------------------------------------\n");
   Fprintf(stdout, "Final: ");
   if (FailedNets == (NETLIST)NULL)
      Fprintf(stdout, "No failed routes!\n");
   else {
      if (FailedNets != (NETLIST)NULL) {
         Fprintf(stdout, "Failed net routes: %d\n", countlist(FailedNets));
	 Fprintf(stdout, "List of failed nets follows:\n");

	 // Output a list of the failed nets

	 for (nl = FailedNets; nl; nl = nl->next) {
	    net = nl->net;
	    Fprintf(stdout, " %s\n", net->netname);
	 }
	 Fprintf(stdout, "\n");
      }
   }
   Fprintf(stdout, "----------------------------------------------\n");

   return 0;

} /* write_def() */

/*--------------------------------------------------------------*/
/* pathstart - begin a DEF format route path           		*/
/*								*/
/* 	If "special" is true, then this path is in a		*/
/*	SPECIALNETS section, in which each route specifies	*/
/*	a width.						*/
/*--------------------------------------------------------------*/

static void
pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale,
          double invscale, u_char horizontal, NODEINFO node)
{
   if (Pathon == 1) {
      Fprintf( stderr, "pathstart():  Major error.  Started a new "
		"path while one is in progress!\n"
		"Doing it anyway.\n" );
   }

   if (layer >= 0) {
      if (Pathon == -1)
	 fprintf(cmd, "+ ROUTED ");
      else
	 fprintf(cmd, "\n  NEW ");
      if (special) {
	 double wvia;
	 int vtype = 0;		/* Need to get via type from node record! */

	 if (node != NULL) {
	     if ((node->flags & NI_NO_VIAX) && (!(node->flags & NI_VIA_X)))
		vtype = 2;
	     else if (node->flags & NI_VIA_Y)
		vtype = 2;
	 }
	 else {
	     /* Assume via orientation matches default route direction.	*/
	     /* NOTE:  Need to mark the actual orientation somehow. . . */
	     int ob = LefGetRouteOrientation((layer > 0) ? (layer - 1) : layer);
	     if (ob == 1) vtype = 2;
	 }

	 wvia = LefGetXYViaWidth(layer, layer, horizontal, vtype);
	 if (layer > 0) { 
	    double wvia2;
	    wvia2 = LefGetXYViaWidth(layer - 1, layer, horizontal, vtype);
	    if (wvia2 > wvia) wvia = wvia2;
         }

         fprintf(cmd, "%s %ld ( %ld %ld ) ", CIFLayer[layer],
			(long)(0.5 + invscale * oscale * wvia),
			(long)(0.5 + invscale * x), (long)(0.5 + invscale * y));
      }
      else
         fprintf(cmd, "%s ( %ld %ld ) ", CIFLayer[layer],
			(long)(0.5 + invscale * x), (long)(0.5 + invscale * y));
   }
   Pathon = 1;

} /* pathstart() */

/*--------------------------------------------------------------*/
/* pathto  - continue a path to the next point        		*/
/*								*/
/*   ARGS: coordinate pair					*/
/*   RETURNS: 							*/
/*   SIDE EFFECTS: 						*/
/*--------------------------------------------------------------*/

static void
pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty,
       double invscale, u_char nextvia)
{
    if (Pathon <= 0) {
	Fprintf(stderr, "pathto():  Major error.  Added to a "
		"non-existent path!\n"
		"Doing it anyway.\n");
    }

    /* If the route is not manhattan, then it's because an offset
     * was added to the last point, and we need to add a small
     * jog to the route.
     */

    if ((x != lastx) && (y != lasty)) {
	if (horizontal)
	   pathto(cmd, lastx, y, FALSE, lastx, lasty, invscale, 0);
	else
	   pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale, 0);
    }

    if (nextvia) {
	/* Punt on output until via is output, because via may have an	*/
	/* offset position that needs to be applied to the route.	*/
	path_delayed.active = 1;
	path_delayed.x = x;
	path_delayed.y = y;
	path_delayed.orient = horizontal;
	return;
    }

    fprintf(cmd, "( ");
    if (horizontal)
	fprintf(cmd, "%ld ", (long)(0.5 + invscale * x));
    else
	fprintf(cmd, "* ");

    if (horizontal)
	fprintf(cmd, "* ");
    else
	fprintf(cmd, "%ld ", (long)(0.5 + invscale * y));

    fprintf(cmd, ") ");

} /* pathto() */

/*--------------------------------------------------------------*/
/* pathvia  - add a via to a path               		*/
/*								*/
/*   ARGS: coord						*/
/*   RETURNS: 							*/
/*   SIDE EFFECTS: 						*/
/*--------------------------------------------------------------*/

static void
pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty,
	char *vianame, double invscale)
{
    if (path_delayed.active == 1) {
	/* Output the last path */
	pathto(cmd, path_delayed.x, path_delayed.y, path_delayed.orient,
		path_delayed.x, path_delayed.y, invscale, 0);
	path_delayed.active = 0;
    }

    if (Pathon <= 0) {
       if (Pathon == -1)
	  fprintf(cmd, "+ ROUTED ");
       else 
	  fprintf(cmd, "\n  NEW ");
       fprintf(cmd, "%s ( %ld %ld ) ", CIFLayer[layer],
		(long)(0.5 + invscale * x), (long)(0.5 + invscale * y));
    }
    else {
       // Normally the path will be manhattan and only one of
       // these will be true.  But if the via gets an offset to
       // avoid a DRC spacing violation with an adjacent via,
       // then we may need to apply both paths to make a dog-leg
       // route to the via.

       if (x != lastx)
	  pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale, 0);
       if (y != lasty)
	  pathto(cmd, x, y, FALSE, x, lasty, invscale, 0);
    }
    fprintf(cmd, "%s ", vianame);
    Pathon = 0;

} /* pathvia() */

/*--------------------------------------------------------------*/
/* Nodes aren't saved in a way that makes it easy to recall	*/
/* the name of the cell and pin to which they belong.  But	*/
/* that information doesn't need to be looked up except as a	*/
/* diagnostic output.  This routine does that lookup.		*/
/*--------------------------------------------------------------*/

char *print_node_name(NODE node)
{
    GATE g;
    int i;
    char *nodestr = NULL;

    for (g = Nlgates; g; g = g->next) {
	for (i = 0; i < g->nodes; i++) {
	    if (g->noderec[i] == node) {
		if (nodestr != NULL)
		   free(nodestr);

		if (!strcmp(g->node[i], "pin")) {
		    nodestr = (char *)malloc(strlen(g->gatename) + 5);
		    sprintf(nodestr, "PIN/%s", g->gatename);
		}
		else {
		    nodestr = (char *)malloc(strlen(g->gatename)
				+ strlen(g->node[i]) + 2);
		    sprintf(nodestr, "%s/%s", g->gatename, g->node[i]);
		}
		return nodestr;
	    }
	}
    }
    if (nodestr != NULL) free(nodestr);
    nodestr = (char *)malloc(22);
    sprintf(nodestr, "(error: no such node)");
    return nodestr;
}

/*--------------------------------------------------------------*/
/* print_nets - print the nets list - created from Nlgates list */
/*								*/
/*   ARGS: filename to list to					*/
/*   RETURNS: nothing						*/
/*   SIDE EFFECTS: 						*/
/*   AUTHOR and DATE: steve beccue      Sat July 26		*/
/*--------------------------------------------------------------*/

void print_nets(char *filename)
{
   FILE *o;
   GATE g;
   int i;
   DSEG drect;

   if (!strcmp(filename, "stdout")) {
	o = stdout;
   } else {
	o = fopen(filename, "w");
   }
   if (!o) {
	Fprintf(stderr, "route:print_nets.  Couldn't open output file\n");
	return;
   }

   for (g = Nlgates; g; g = g->next) {
      fprintf(o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename);
      for (i = 0; i < g->nodes; i++) {
	 // This prints the first tap position only.
	 drect = g->taps[i];
	 fprintf( o, "%s(%g,%g) ", g->node[i], drect->x1, drect->y1);
      }
   }
   fprintf( o, "\n");
} /* print_nets() */

/*--------------------------------------------------------------*/
/* print_routes - print the routes list				*/
/*								*/
/*   ARGS: filename to list to					*/
/*   RETURNS: nothing						*/
/*   SIDE EFFECTS: 						*/
/*   AUTHOR and DATE: steve beccue      Sat July 26		*/
/*--------------------------------------------------------------*/

void print_routes( char *filename )
{
    FILE *o;
    GATE g;
    int i;

    if( !strcmp( filename, "stdout" ) ) {
	o = stdout;
    } else {
	o = fopen( filename, "w" );
    }
    if( !o ) {
	Fprintf( stderr, "route:print_routes.  Couldn't open output file\n" );
	return;
    }

    for (g = Nlgates; g; g = g->next) {
	fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename );
	for( i = 0 ; i < g->nodes; i++ ) {
	    fprintf( o, "%s ", g->node[i] );
	}
	fprintf(o, "\n");
    }
} /* print_routes() */

/*--------------------------------------------------------------*/
/* print_nlgates - print the nlgate list			*/
/*								*/
/*   ARGS: filename to list to					*/
/*   RETURNS: nothing						*/
/*   SIDE EFFECTS: 						*/
/*   AUTHOR and DATE: steve beccue      Wed July 23		*/
/*--------------------------------------------------------------*/

void print_nlgates( char *filename )
{
    FILE *o;
    GATE g;
    int i;
    DSEG drect;

    if( !strcmp( filename, "stdout" ) ) {
	o = stdout;
    } else {
	o = fopen( filename, "w" );
    }
    if( !o ) {
	Fprintf( stderr, "route:print_nlgates.  Couldn't open output file\n" );
	return;
    }

    for (g = Nlgates; g; g = g->next) {
	fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename );
	for( i = 0 ; i < g->nodes; i++ ) {
	    // This prints the first tap position only.
	    drect = g->taps[i];
	    fprintf( o, "%s(%g,%g)", g->node[i], drect->x1, drect->y1);
	}
        fprintf(o, "\n");
    }
} /* print_nlgates() */


/*--------------------------------------------------------------*/
/* print_net - print info about the net to stdout               */
/*								*/
/*   ARGS: net to print info about				*/
/*   RETURNS: nothing						*/
/*   SIDE EFFECTS: 						*/
/*--------------------------------------------------------------*/

void print_net(NET net) {
    NODE node;
    DPOINT tap;
    int i, first;

    Fprintf(stdout, "Net %d: %s", net->netnum, net->netname);
    for (node = net->netnodes; node != NULL; node = node->next) {
        Fprintf(stdout, "\n  Node %d (%s): \n    Taps: ",
		node->nodenum, print_node_name(node));
        for (tap = node->taps, i = 0, first = TRUE;
             tap != NULL;
             tap = tap->next, i = (i + 1) % 4, first = FALSE) {
            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
                    (i == 0 ? (first ? "" : "\n        ") : " "),
                    tap->layer, tap->x, tap->y
            );
        }
        Fprintf(stdout, "\n    Tap extends: ");
        for (tap = node->extend, i = 0, first = TRUE;
             tap != NULL;
             tap = tap->next, i = (i + 1) % 4, first = FALSE) {
            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
                    (i == 0 ? (first ? "" : "\n        ") : " "),
                    tap->layer, tap->x, tap->y
            );
        }
    }
    Fprintf(stdout, "\n  bbox: (%d,%d)-(%d,%d)\n",
            net->xmin, net->ymin, net->xmax, net->ymax
    );
}


/*--------------------------------------------------------------*/
/* print_gate - print info about the net to stdout              */
/*								*/
/*   ARGS: gate to print info about				*/
/*   RETURNS: nothing						*/
/*   SIDE EFFECTS: 						*/
/*--------------------------------------------------------------*/

void print_gate(GATE gate) {
    int i, j, first;
    DSEG seg;
    NODE node;
    DPOINT tap;

    Fprintf(stdout, "Gate %s\n", gate->gatename);
    Fprintf(stdout, "  Loc: (%.2lf, %.2lf), WxH: %.2lfx%.2lf\n",
            gate->placedX, gate->placedY, gate->width, gate->height
    );
    Fprintf(stdout, "  Pins");
    for (i = 0; i < gate->nodes; i++) {
        Fprintf(stdout, "\n    Pin %s, net %d\n",
                gate->node[i], gate->netnum[i]
        );
        Fprintf(stdout, "      Segs: ");
        for (seg = gate->taps[i], j = 0, first = TRUE;
             seg != NULL;
             seg = seg->next, j = (j + 1) % 3, first = FALSE) {
            Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)-(%.2lf,%.2lf)",
                    (j == 0 ? (first ? "" : "\n        ") : " "),
                    seg->layer, seg->x1, seg->y1, seg->x2, seg->y2
            );
        }
        if ((node = gate->noderec[i]) != NULL) {
            Fprintf(stdout, "\n      Taps: ");
            for (tap = node->taps, j = 0, first = TRUE;
                 tap != NULL;
                 tap = tap->next, j = (j + 1) % 4, first = FALSE) {
                Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
                        (j == 0 ? (first ? "" : "\n        ") : " "),
                        tap->layer, tap->x, tap->y
                );
            }
            Fprintf(stdout, "\n      Tap extends: ");
            for (tap = node->extend, j = 0, first = TRUE;
                 tap != NULL;
                 tap = tap->next, j = (j + 1) % 4, first = FALSE) {
                Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)",
                        (j == 0 ? (first ? "" : "\n        ") : " "),
                        tap->layer, tap->x, tap->y
                );
            }
        }
    }
    Fprintf(stdout, "\n  Obstructions: ");
    for (seg = gate->obs, j = 0, first = TRUE;
         seg != NULL;
         seg = seg->next, j = (j + 1) % 3, first = FALSE) {
        Fprintf(stdout, "%sL%d:(%.2lf,%.2lf)-(%.2lf,%.2lf)",
                (j == 0 ? (first ? "" : "\n    ") : " "),
                seg->layer, seg->x1, seg->y1, seg->x2, seg->y2
        );
    }
    Fprintf(stdout, "\n");
}

/*--------------------------------------------------------------*/
/* print_nodes - show the nodes list				*/
/*								*/
/*    ARGS: filename to print to				*/
/*    RETURNS: nothing						*/
/*    SIDE EFFECTS: none					*/
/*    AUTHOR and DATE: steve beccue      Tue Aug 04  2003	*/
/*--------------------------------------------------------------*/

void print_nodes(char *filename)
{
  FILE *o;
  int i;
  NET net;
  NODE node;
  DPOINT dp;

    if (!strcmp(filename, "stdout")) {
	o = stdout;
    } else {
	o = fopen(filename, "w");
    }
    if (!o) {
	Fprintf( stderr, "node.c:print_nodes.  Couldn't open output file\n" );
	return;
    }

    for (i = 0; i < Numnets; i++) {
       net = Nlnets[i];
       for (node = net->netnodes; node; node = node->next) {
	  dp = (DPOINT)node->taps;
	  fprintf(o, "%d\t%s\t(%g,%g)(%d,%d) :%d:num=%d netnum=%d\n",
		node->nodenum, 
		node->netname,
		// legacy:  print only the first point
		dp->x, dp->y, dp->gridx, dp->gridy,
		node->netnum, node->numnodes, node->netnum );
		 
	  /* need to print the routes to this node (deprecated)
	  for (j = 0 ; j < g->nodes; j++) {
	      fprintf(o, "%s(%g,%g) ", g->node[j], *(g->x[j]), *(g->y[j]));
	  }
	  */
       }
    }
    fclose(o);

} /* print_nodes() */

/*--------------------------------------------------------------*/
/* print_nlnets - show the nets					*/
/*								*/
/*   ARGS: filename to print to					*/
/*   RETURNS: nothing						*/
/*   SIDE EFFECTS: none						*/
/*   AUTHOR and DATE: steve beccue      Tue Aug 04  2003	*/
/*--------------------------------------------------------------*/

void print_nlnets( char *filename )
{
  FILE *o;
  int i;
  NODE nd;
  NET net;

    if (!strcmp(filename, "stdout")) {
	o = stdout;
    } else {
	o = fopen(filename, "w");
    }
    if (!o) {
	Fprintf(stderr, "node.c:print_nlnets.  Couldn't open output file\n");
	return;
    }

    for (i = 0; i < Numnets; i++) {
        net = Nlnets[i];
	fprintf(o, "%d\t#=%d\t%s   \t\n", net->netnum, 
		 net->numnodes, net->netname);

	for (nd = net->netnodes; nd; nd = nd->next) {
	   fprintf(o, "%d ", nd->nodenum);
	}
    }

    fprintf(o, "%d nets\n", Numnets);
    fflush(o);

} /* print_nlnets() */

/*--------------------------------------------------------------*/
/* print_grid_information()					*/
/*								*/
/*  For help in debugging routing problems, print information	*/
/*  about blockages marked at a specific grid position.		*/
/*--------------------------------------------------------------*/

void
print_grid_information(int gridx, int gridy, int layer)
{
    u_int obsval;
    int i, apos;
    double dx, dy;
    int netidx;
    NET net;
    NODE node;
    NODEINFO lnode;
    DSEG ds;

    apos = OGRID(gridx, gridy);
    obsval = Obs[layer][apos];

    lnode = Nodeinfo[layer][apos];
    if (lnode != NULL) {
	node = lnode->nodesav;
	if (node != NULL) {
	    Fprintf(stdout, "Grid position %d %d is an active node tap.\n",
		    gridx, gridy);

	    if (node->netname)
		Fprintf(stdout, "Node at grid position is %s and belongs "
			"to net \"%s\".\n", print_node_name(node), node->netname);
	    else
		Fprintf(stdout, "Node at grid position is %s and is not routed.\n",
			print_node_name(node));
	    if (lnode->nodeloc == NULL) {
		Fprintf(stdout, "Position temporarily disabled to avoid "
			"blocking the tap.\n");
	    }
	}
	else
	    Fprintf(stdout, "Grid position %d %d is a disabled node tap.\n",
		    gridx, gridy);

	if (lnode->flags & NI_VIA_X)
	    Fprintf(stdout, "Via may be placed horizontally on tap.\n");
	if (lnode->flags & NI_VIA_Y)
	    Fprintf(stdout, "Via may be placed vertically on tap.\n");
	if (lnode->flags & NI_NO_VIAX)
	    Fprintf(stdout, "Horizontal vias are prohibited on tap.\n");
	if (lnode->flags & NI_NO_VIAY)
	    Fprintf(stdout, "Vertical vias are prohibited on tap.\n");
	if (lnode->flags & NI_OFFSET_EW) {
	    if (lnode->offset > 0.0)
		Fprintf(stdout, "Tap connection offset to the east %gum\n",
			    lnode->offset);
	    else
		Fprintf(stdout, "Tap connection offset to the west %gum\n",
			    -lnode->offset);
	}
	if (lnode->flags & NI_OFFSET_NS) {
	    if (lnode->offset > 0.0)
		Fprintf(stdout, "Tap connection offset to the north %gum\n",
			    lnode->offset);
	    else
		Fprintf(stdout, "Tap connection offset to the south %gum\n",
			    -lnode->offset);
	}
	if (lnode->flags & NI_STUB_EW) {
	    if (lnode->stub > 0.0)
		Fprintf(stdout, "Stub connection to the east length %gum\n",
			    lnode->stub);
	    else
		Fprintf(stdout, "Stub connection to the west length %gum\n",
			    -lnode->stub);
	}
	if (lnode->flags & NI_STUB_NS) {
	    if (lnode->stub > 0.0)
		Fprintf(stdout, "Stub connection to the north length %gum\n",
			    lnode->stub);
	    else
		Fprintf(stdout, "Stub connection to the south length %gum\n",
			    -lnode->stub);
	}
	if ((lnode->flags == 0) || (lnode->flags == NI_VIA_X | NI_VIA_Y))
	    Fprintf(stdout, "Node is cleanly routable with no restrictions.\n");
    }
    else
	Fprintf(stdout, "Grid position is not associated with a node tap.\n");

    if (obsval & OFFSET_TAP)
	Fprintf(stdout, "Grid position requires a route position offset.\n");
    if (obsval & STUBROUTE)
	Fprintf(stdout, "Grid position requires a stub route to reach tap.\n");
    if (obsval & ROUTED_NET)
	Fprintf(stdout, "Grid position is assigned to routed net.\n");
    if (obsval & BLOCKED_N)
	Fprintf(stdout, "Grid position cannot be reached from the north.\n");
    if (obsval & BLOCKED_S)
	Fprintf(stdout, "Grid position cannot be reached from the south.\n");
    if (obsval & BLOCKED_E)
	Fprintf(stdout, "Grid position cannot be reached from the east.\n");
    if (obsval & BLOCKED_W)
	Fprintf(stdout, "Grid position cannot be reached from the west.\n");
    if (obsval & BLOCKED_U)
	Fprintf(stdout, "Grid position cannot be reached from above.\n");
    if (obsval & BLOCKED_D)
	Fprintf(stdout, "Grid position cannot be reached from below.\n");
    if ((obsval & (OBSTRUCT_MASK | NO_NET)) == (OBSTRUCT_MASK | NO_NET)) {
	Fprintf(stdout, "Grid position is completely obstructed\n");

	/* Check if grid position is completely obstructed by a UserObs object */
	dx = Xlowerbound + gridx * PitchX;
	dy = Ylowerbound + gridy * PitchY;
	for (ds = UserObs; ds; ds = ds->next) {
	    if (ds->layer == layer) {
		if (ds->x1 < dx && ds->x2 > dx && ds->y1 < dy && ds->y2 > dy) {
		    Fprintf(stdout, "Defined obstruction at (%g, %g) to (%g, %g) "
			    "covers the tap point.\n",
			    ds->x1, ds->y1, ds->x2, ds->y2);
		}
	    }
	}
    }
    else if (obsval & NO_NET) {
	if ((obsval & OBSTRUCT_MASK != 0) && (lnode == NULL)) {
	    Fprintf(stdout, "Error:  Position marked as node obstruction has "
		    "no node assigned!\n");
	}
	else if (lnode != NULL) {
	    if (obsval & OBSTRUCT_N)
		Fprintf(stdout, "Grid position is obstructed to the north at %gum.\n",
			lnode->offset);
	    if (obsval & OBSTRUCT_S)
		Fprintf(stdout, "Grid position is obstructed to the south at %gum.\n",
			lnode->offset);
	    if (obsval & OBSTRUCT_E)
		Fprintf(stdout, "Grid position is obstructed to the east at %gum.\n",
			lnode->offset);
	    if (obsval & OBSTRUCT_W)
		Fprintf(stdout, "Grid position is obstructed to the west at %gum.\n",
			lnode->offset);
	}
    }
    if ((obsval & DRC_BLOCKAGE) == DRC_BLOCKAGE) {
	Fprintf(stdout, "Grid position disabled by neighboring route to prevent"
		" DRC violations.\n");
    }
    if (((obsval & ROUTED_NET_MASK) != 0) && ((obsval & NO_NET) == 0)) {
	netidx = obsval & NETNUM_MASK;
	for (i = 0; i < Numnets; i++) {
	    net = Nlnets[i];
	    if (net->netnum == netidx) break;
	}

	if ((netidx > MAX_NETNUMS) || (i >= Numnets)) {
	    Fprintf(stdout, "Error: Grid position marked with a bad net number.\n");
	}
	else {
	    net = Nlnets[i];
	    Fprintf(stdout, "Grid position assigned to routed net \"%s\".\n",
		    net->netname);
	}
    }
}

/*--------------------------------------------------------------*/
/* print_instance_information()					*/
/*								*/
/*  For help in debugging routing problems, print information	*/
/*  about an instance.						*/
/*--------------------------------------------------------------*/

void
print_instance_information(char *instname)
{
    NET net;
    GATE gate;

    for (gate = Nlgates; gate; gate = gate->next) {
	if (!strcmp(gate->gatename, instname)) {
	    print_gate(gate);
	    break;
	}
    }
}

/*--------------------------------------------------------------*/
/* print_node_information()					*/
/*								*/
/*  For help in debugging routing problems, print information	*/
/*  about a node (instance and pin).				*/
/*--------------------------------------------------------------*/

void
print_node_information(char *nodename)
{
    int i, j, k, l, apos;
    NET net;
    NODE node;
    NODEINFO lnode;
    GATE gate;
    char *pptr, *instname, *pinname;

    pptr = strchr(nodename, '/');
    if (pptr == NULL) {
	Fprintf(stderr, "Node name is not in <instance>/<pin> format!\n");
	return;
    }
    *pptr = '\0';
    instname = nodename;
    pinname = pptr + 1;

    for (gate = Nlgates; gate; gate = gate->next) {
	if (!strcmp(gate->gatename, instname)) {
	    for (i = 0; i < gate->nodes; i++) {
		if (!strcmp(gate->node[i], pinname)) {
		    node = gate->noderec[i];
		    Fprintf(stdout, "Instance name is %s\n", gate->gatename);
		    if (gate->gatetype)
		        Fprintf(stdout, "Gate type is %s\n", gate->gatetype->gatename);
		    else
		        Fprintf(stdout, "Node name is %s\n", print_node_name(node));
		    Fprintf(stdout, "Net connecting to node is %s\n", node->netname);

		    /* Find all grid positions that route to this node */
		    Fprintf(stdout, "Grid positions assigned to node:\n");
		    for (j = 0; j < NumChannelsX; j++) {
			for (k = 0; k < NumChannelsY; k++) {
			    for (l = 0; l < Pinlayers; l++) {
				apos = OGRID(j, k);
				lnode = Nodeinfo[l][apos];
				if (lnode && lnode->nodesav == node) {
				    Fprintf(stdout, "  (%g, %g)um  x=%d y=%d layer=%d\n",
					    Xlowerbound + j * PitchX,
					    Ylowerbound + k * PitchY,
					    j, k, l);
				}
			    }
			}
		    }
		    break;
		}
	    }
	    break;
	}
    }
    *pptr = '/';
}

/*--------------------------------------------------------------*/
/* print_net_information()					*/
/*								*/
/*  For help in debugging routing problems, print information	*/
/*  about a net.						*/
/*--------------------------------------------------------------*/

void
print_net_information(char *netname)
{
    int i;
    NET net;

    for (i = 0; i < Numnets; i++) {
	net = Nlnets[i];
	if (!strcmp(net->netname, netname)) {
	    print_net(net);
	    break;
	}
    }
}

/*--------------------------------------------------------------*/
/* link_up_seg ---						*/
/*								*/
/* As part of cleanup_net (below), when removing unneeded vias,	*/
/* it may be necessary to check if a segment is being used to	*/
/* connect to another route of a net, in which case removing	*/
/* the segment would break the net.  If that is the case, then	*/
/* keep the segment by linking it to the end of the route that	*/
/* was connected to it.						*/
/*								*/
/* Return 1 (true) if the segment was linked to another route,	*/
/* so the caller knows whether or not to free the segment.	*/
/*								*/
/* "rt" is the route that the segment was connected to.  For	*/
/* the sake of efficiency, it does not need to be checked.	*/
/*--------------------------------------------------------------*/

u_char link_up_seg(NET net, SEG seg, int viabase, ROUTE srt)
{
    ROUTE rt;
    SEG segf, segl;
    int x, y;

    for (rt = net->routes; rt; rt = rt->next) {
	if (rt == srt) continue;
	segf = rt->segments;
	if ((segf->x1 == seg->x1) && (segf->y1 == seg->y1) &&
		((segf->layer == viabase) || (segf->layer == viabase + 1))) {
	    /* Reverse seg and prepend it to the route */
	    seg->next = rt->segments;
	    rt->segments = seg;
	    x = seg->x1;
	    y = seg->y1;
	    seg->x1 = seg->x2;
	    seg->y1 = seg->y2;
	    seg->x2 = x;
	    seg->y2 = y;
	    return (u_char)1;
	}

	/* Move to the last segment of the route */
	for (segl = segf; segl && segl->next; segl = segl->next);

	if (segl && (segl->x2 == seg->x1) && (segl->y2 == seg->y1) &&
		((segl->layer == viabase) || (segl->layer == viabase + 1))) {
	    /* Append seg to the route */
	    segl->next = seg;
	    return (u_char)1;
	}
    }
    return (u_char)0;
}

/*--------------------------------------------------------------*/
/* cleanup_net --						*/
/*								*/
/* Special handling for layers where needblock[] is non-zero,	*/
/* and shows that two vias cannot be placed on adjacent routes. */
/* emit_routed_net() will add specialnets to merge two adjacent	*/
/* vias on the same route.  However, this cannot be used for	*/
/* adjacent vias that are each in a different route record.  It	*/
/* is easier just to find any such instances and remove them by	*/
/* eliminating one of the vias and adding a segment to connect	*/
/* the route to the neighboring via.				*/
/*								*/
/* Note that the ensuing change in connectivity can violate	*/
/* the route endpoints and thereby mess up the delay output	*/
/* routine and/or the antenna violation finding routine unless	*/
/* route_set_connections() is re-run on the modified routes.	*/
/*--------------------------------------------------------------*/

void cleanup_net(NET net)
{
   SEG segf, segl, seg, segp;
   ROUTE rt, rt2;
   NODEINFO lnode;
   int lf, ll, lf2, ll2, viabase;
   u_char fcheck, lcheck, needfix;
   u_char xcheckf, ycheckf, xcheckl, ycheckl; 

   lf = ll = lf2 = ll2 = -1;
   needfix = FALSE;

   for (rt = net->routes; rt; rt = rt->next) {
      fcheck = lcheck = FALSE;

      // This problem will only show up on route endpoints.
      // segf is the first segment of the route.
      // segl is the last segment of the route.
      // lf is the layer at the route start (layer first)
      // lf2 is the layer of the second segment.
      // ll is the layer at the route end (layer last)
      // ll2 is the layer of the next-to-last segment

      segf = rt->segments;
      if (segf == NULL) continue;
      if ((segf->next != NULL) && (segf->segtype == ST_VIA)) {
	 if (segf->next->layer > segf->layer) {
	    lf = segf->layer;
	    lf2 = segf->layer + 1;
	 }
	 else {
	    lf = segf->layer + 1;
	    lf2 = segf->layer;
	 }
         // Set flag fcheck indicating that segf needs checking
	 fcheck = TRUE;

	 // We're going to remove the contact so it can't be a tap
	 if ((lf < Pinlayers) && ((lnode = NODEIPTR(segf->x1, segf->y1, lf)) != NULL)
			&& (lnode->nodesav != NULL))
	    fcheck = FALSE;
      }

      /* This could be done if vias are always too close when	*/
      /* placed on adjacent tracks.  However, that ignores the	*/
      /* problem of vias with offsets, and it ignores the fact	*/
      /* that adjacent vias on the same net are always a	*/
      /* redundancy. 						*/

      xcheckf = needblock[lf] & VIABLOCKX;
      ycheckf = needblock[lf] & VIABLOCKY;
      if (!xcheckf && !ycheckf) fcheck = FALSE;

      // Move to the next-to-last segment
      for (segl = segf->next; segl && segl->next && segl->next->next;
		segl = segl->next);

      if (segl && (segl->next != NULL) && (segl->next->segtype == ST_VIA)) {
	 if (segl->next->layer < segl->layer) {
	    ll = segl->next->layer;
	    ll2 = segl->next->layer + 1;
	 }
	 else {
	    ll = segl->next->layer + 1;
	    ll2 = segl->next->layer;
	 }
	 // Move segl to the last segment
	 segl = segl->next;
	 // Set flag lcheck indicating that segl needs checking.
	 lcheck = TRUE;

	 // We're going to remove the contact so it can't be a tap
	 if ((ll < Pinlayers) && ((lnode = NODEIPTR(segl->x1, segl->y1, ll)) != NULL)
			&& (lnode->nodesav != NULL))
	    lcheck = FALSE;
      }

      xcheckl = needblock[ll] & VIABLOCKX;
      ycheckl = needblock[ll] & VIABLOCKY;
      if (!xcheckl && !ycheckl) lcheck = FALSE;

      // For each route rt2 that is not rt, look at every via
      // and see if it is adjacent to segf or segl.

      for (rt2 = net->routes; rt2; rt2 = rt2->next) {

         if ((fcheck == FALSE) && (lcheck == FALSE)) break;
         if (rt2 == rt) continue;

         for (seg = rt2->segments; seg; seg = seg->next) {
	    if (seg->segtype & ST_VIA) {
	       if (fcheck) {
		  if ((seg->layer == lf) || ((seg->layer + 1) == lf)) {
		     if (xcheckf && (seg->y1 == segf->y1) &&
				(ABSDIFF(seg->x1, segf->x1) == 1)) {
			needfix = TRUE;
			if (seg->layer != segf->layer) {

			   // Adjacent vias are different types.
			   // Deal with it by creating a route between
			   // the vias on their shared layer.  This
			   // will later be made into a special net to
			   // avoid notch DRC errors.

			   SEG newseg;
			   newseg = (SEG)malloc(sizeof(struct seg_));
			   rt->segments = newseg;
			   newseg->next = segf;
			   newseg->layer = lf;
			   newseg->segtype = ST_WIRE;
			   newseg->x1 = segf->x1;
			   newseg->y1 = segf->y1;
			   newseg->x2 = seg->x1; 
			   newseg->y2 = seg->y1;
			}
			else {
			   // Change via to wire route, connect it to seg,
			   // and make sure it has the same layer type as
			   // the following route.
			   segf->segtype = ST_WIRE;
			   segf->x1 = seg->x1;
			   segf->layer = lf2;
		        }
		     }
		     else if (ycheckf && (seg->x1 == segf->x1) &&
				(ABSDIFF(seg->y1, segf->y1) == 1)) {
			needfix = TRUE;
			if (seg->layer != segf->layer) {
			   // Adjacent vias are different types.
			   // Deal with it by creating a route between
			   // the vias on their shared layer.  This
			   // will later be made into a special net to
			   // avoid notch DRC errors.

			   SEG newseg;
			   newseg = (SEG)malloc(sizeof(struct seg_));
			   rt->segments = newseg;
			   newseg->next = segf;
			   newseg->layer = lf;
			   newseg->segtype = ST_WIRE;
			   newseg->x1 = segf->x1;
			   newseg->y1 = segf->y1;
			   newseg->x2 = seg->x1; 
			   newseg->y2 = seg->y1;
		        }
		        else {
			   // Change via to wire route, connect it to seg,
			   // and make sure it has the same layer type as
			   // the following route.
			   segf->segtype = ST_WIRE;
			   segf->y1 = seg->y1;
			   segf->layer = lf2;
			}
		     }
		  }
	       }

               if (lcheck) {
		  if ((seg->layer == ll) || ((seg->layer + 1) == ll)) {
		     if (xcheckl && (seg->y1 == segl->y1) &&
				(ABSDIFF(seg->x1, segl->x1) == 1)) {
			needfix = TRUE;
			if (seg->layer != segl->layer) {

			   // Adjacent vias are different types.
			   // Deal with it by creating a route between
			   // the vias on their shared layer.  This
			   // will later be made into a special net to
			   // avoid notch DRC errors.

			   SEG newseg;
			   newseg = (SEG)malloc(sizeof(struct seg_));
			   segl->next = newseg;
			   newseg->next = NULL;
			   newseg->layer = ll;
			   newseg->segtype = ST_WIRE;
			   newseg->x1 = segl->x1;
			   newseg->y1 = segl->y1;
			   newseg->x2 = seg->x1; 
			   newseg->y2 = seg->y1;
			}
			else {
			   // Change via to wire route, connect it to seg,
			   // and make sure it has the same layer type as
			   // the previous route.
			   segl->segtype = ST_WIRE;
			   segl->x2 = seg->x2;
			   segl->layer = ll2;
			}
		     }
		     else if (ycheckl && (seg->x1 == segl->x1) &&
				(ABSDIFF(seg->y1, segl->y1) == 1)) {
			needfix = TRUE;
			if (seg->layer != segl->layer) {

			   // Adjacent vias are different types.
			   // Deal with it by creating a route between
			   // the vias on their shared layer.  This
			   // will later be made into a special net to
			   // avoid notch DRC errors.

			   SEG newseg;
			   newseg = (SEG)malloc(sizeof(struct seg_));
			   segl->next = newseg;
			   newseg->next = NULL;
			   newseg->layer = ll;
			   newseg->segtype = ST_WIRE;
			   newseg->x1 = segl->x1;
			   newseg->y1 = segl->y1;
			   newseg->x2 = seg->x1; 
			   newseg->y2 = seg->y1;
			}
			else {
			   // Change via to wire route, connect it to seg,
			   // and make sure it has the same layer type as
			   // the previous route.
			   segl->segtype = ST_WIRE;
			   segl->y2 = seg->y2;
			   segl->layer = ll2;
			}
		     }
		  }
	       }
	    }
	 }
      }

      /* One case not covered by the checks above:  If the second or	*/
      /* penultimate segment is a via and the final segment is one	*/
      /* track in length and connects to a via, then the same		*/
      /* replacement can be made.  The other routes do not need to be	*/
      /* checked, as it is sufficient to check that the grid is 	*/
      /* occupied at that point on two metal layers with the same net.	*/

      /* NOTE:  Another route could be connecting to the via on the	*/
      /* penultimate segment, and removing it would cause an open net.	*/
      /* Check for this case and resolve if needed.			*/

      if ((fcheck == FALSE) && (lcheck == FALSE)) {
	 int wlen, oval0, oval1, oval2;

	 segf = rt->segments;
	 if ((segf == NULL) || (segf->next == NULL)) continue;
	 seg = segf->next;
	 if ((segf->segtype == ST_WIRE) && (seg->segtype == ST_VIA)) {
	    if ((segf->x1 - segf->x2) == 0) {
		wlen = segf->y1 - segf->y2;
	        if ((wlen == 1) || (wlen == -1)) {
		    oval1 = OBSVAL(segf->x1, segf->y1, seg->layer) & ROUTED_NET_MASK;
		    oval2 = OBSVAL(segf->x1, segf->y1, seg->layer + 1) & ROUTED_NET_MASK;
		    if (oval1 == oval2) {
			/* Check false case in which (layer + 1) is a min area stub */
			segp = seg->next;
			if (segp && (segp->x2 == segf->x1) && (segp->y2 == segf->y1))
			    continue;
			/* Remove via and change wire layer */
			needfix = TRUE;
			segf->next = seg->next;
			viabase = segf->layer;
			segf->layer = (viabase == seg->layer) ? seg->layer + 1 :
				seg->layer;
			if (!link_up_seg(net, seg, viabase, rt)) free(seg);
		    }
		}
	    }
	    else if ((segf->y1 - segf->y2) == 0) {
		wlen = segf->x1 - segf->x2;
	        if ((wlen == 1) || (wlen == -1)) {
		    oval1 = OBSVAL(segf->x1, segf->y1, seg->layer) & ROUTED_NET_MASK;
		    oval2 = OBSVAL(segf->x1, segf->y1, seg->layer + 1) & ROUTED_NET_MASK;
		    if (oval1 == oval2) {
			/* Check false case in which (layer + 1) is a min area stub */
			segp = seg->next;
			if (segp && (segp->x2 == segf->x1) && (segp->y2 == segf->y1))
			    continue;
			/* Remove via and change wire layer */
			needfix = TRUE;
			segf->next = seg->next;
			viabase = segf->layer;
			segf->layer = (viabase == seg->layer) ? seg->layer + 1 :
				seg->layer;
			if (!link_up_seg(net, seg, viabase, rt)) free(seg);
		    }
		}
	    }
	 }
	 segp = NULL;
	 for (seg = rt->segments; seg && seg->next && seg->next->next; seg = seg->next)
	     segp = seg;
	 if ((seg == NULL) || (seg->next == NULL)) continue;
	 segl = seg->next;
	 if ((segl->segtype == ST_WIRE) && (seg->segtype == ST_VIA)) {
	    if ((segl->x1 - segl->x2) == 0) {
		wlen = segl->y1 - segl->y2;
	        if ((wlen == 1) || (wlen == -1)) {
		    oval1 = OBSVAL(segl->x2, segl->y2, seg->layer) & ROUTED_NET_MASK;
		    oval2 = OBSVAL(segl->x2, segl->y2, seg->layer + 1) & ROUTED_NET_MASK;
		    if (oval1 == oval2) {
			/* Check false case in which (layer + 1) is a min area stub */
			if (segp && (segp->x1 == segl->x2) && (segp->y1 == segl->y2))
			    continue;
			/* Remove via and change wire layer */
			needfix = TRUE;
			seg->next = NULL;
			seg->segtype = ST_WIRE;
			viabase = seg->layer;
			seg->layer = (viabase == segl->layer) ? viabase + 1 : viabase;
			seg->x1 = segl->x1;
			seg->y1 = segl->y1;
			seg->x2 = segl->x2;
			seg->y2 = segl->y2;
			if (!link_up_seg(net, segl, viabase, rt)) free(segl);
		    }
		}
	    }
	    else if ((segl->y1 - segl->y2) == 0) {
		wlen = segl->x1 - segl->x2;
	        if ((wlen == 1) || (wlen == -1)) {
		    oval1 = OBSVAL(segl->x2, segl->y2, seg->layer) & ROUTED_NET_MASK;
		    oval2 = OBSVAL(segl->x2, segl->y2, seg->layer + 1) & ROUTED_NET_MASK;
		    if (oval1 == oval2) {
			/* Check false case in which (layer + 1) is a min area stub */
			if (segp && (segp->x1 == segl->x2) && (segp->y1 == segl->y2))
			    continue;
			/* Remove via and change wire layer */
			needfix = TRUE;
			viabase = seg->layer;
			seg->next = NULL;
			seg->segtype = ST_WIRE;
			seg->layer = (viabase == segl->layer) ? viabase + 1 : viabase;
			seg->x1 = segl->x1;
			seg->y1 = segl->y1;
			seg->x2 = segl->x2;
			seg->y2 = segl->y2;
			if (!link_up_seg(net, segl, viabase, rt)) free(segl);
		    }
		}
	    }
	 }
      }
   }
   if (needfix == TRUE)
      for (rt = net->routes; rt; rt = rt->next)
	 route_set_connections(net, rt);
}

/*--------------------------------------------------------------*/
/* emit_routed_net --						*/
/*								*/
/* Core part of emit_routes().  Dumps the DEF format for a	*/
/* complete net route to file Cmd.  If "special" is TRUE, then	*/
/* it looks only for stub routes between a grid point and an	*/
/* off-grid terminal, and dumps only the stub route geometry as	*/
/* a SPECIALNET, which takes a width parameter.  This allows	*/
/* the stub routes to be given the same width as a via, when	*/
/* the via is larger than a route width, to avoid DRC notch	*/
/* errors between the via and the terminal.  The SPECIALNETS	*/
/* are redundant;  all routing information is in the NETS	*/
/* section.  The SPECIALNETS only specify a wider route for the	*/
/* stub connection.						*/
/*--------------------------------------------------------------*/

static void
emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
{
   SEG seg, saveseg, lastseg, prevseg;
   NODEINFO lnode, lnode1, lnode2;
   ROUTE rt;
   u_int dir1, dir2, tdir;
   int layer;
   int x = 0, y = 0, x2, y2;
   double dc;
   int lastx = -1, lasty = -1, lastlay;
   int horizontal;
   float offset1, offset2, stub, offset;
   u_char cancel, segtype, nextvia;
   double invscale = (double)(1.0 / (double)iscale); 

   /* If the STUB flag is set, then we need to write out the net name	*/
   /* in the SPECIALNETS section.					*/

   if ((special == (u_char)1) && (net->flags & NET_STUB)) {
      fprintf(Cmd, ";\n- %s\n", net->netname);
   }

   Pathon = -1;
   lastlay = -1;

   /* Insert routed net here */
   for (rt = net->routes; rt; rt = rt->next) {

      path_delayed.active = 0;

      if (rt->segments && !(rt->flags & RT_OUTPUT)) {
	 horizontal = FALSE;
	 cancel = FALSE;

	 // Check first position for terminal offsets
	 seg = (SEG)rt->segments;
	 lastseg = saveseg = seg;
	 layer = seg->layer;
	 if (seg) {
	    nextvia = (seg->next) ? ((seg->next->segtype == ST_VIA) ? 1 : 0) : 0;

	    // It is rare but possible to have a stub route off of an
	    // endpoint via, so check this case, and use the layer type
	    // of the via top if needed.

	    if ((seg->segtype & ST_VIA) && seg->next && (seg->next->layer <=
			seg->layer))
	       layer++;

	    lnode = (layer < Pinlayers) ? NODEIPTR(seg->x1, seg->y1, layer) : NULL;
	    stub = (lnode) ? lnode->stub : 0.0;
	    if (OBSVAL(seg->x1, seg->y1, layer) & STUBROUTE) {
	       if ((special == (u_char)0) && (Verbose > 2))
		  Fprintf(stdout, "Stub route distance %g to terminal"
				" at %d %d (%d)\n", stub,
				seg->x1, seg->y1, layer);

	       dc = Xlowerbound + (double)seg->x1 * PitchX;
	       x = (int)((REPS(dc)) * oscale);
	       if (lnode->flags & NI_STUB_EW)
		  dc += stub;
	       x2 = (int)((REPS(dc)) * oscale);
	       dc = Ylowerbound + (double)seg->y1 * PitchY;
	       y = (int)((REPS(dc)) * oscale);
	       if (lnode->flags & NI_STUB_NS)
		  dc += stub;
	       y2 = (int)((REPS(dc)) * oscale);
	       if (lnode->flags & NI_STUB_EW) {
		  horizontal = TRUE;

		  // If the gridpoint ahead of the stub has a route
		  // on the same net, and the stub is long enough
		  // to come within a DRC spacing distance of the
		  // other route, then lengthen it to close up the
		  // distance and resolve the error.  (NOTE:  This
		  // unnecessarily stretches routes to cover taps
		  // that have not been routed to.  At least on the
		  // test standard cell set, these rules remove a
		  // handful of DRC errors and don't create any new
		  // ones.  If necessary, a flag can be added to
		  // distinguish routes from taps.

		  if ((x < x2) && (seg->x1 < (NumChannelsX - 1))) {
		     tdir = OBSVAL(seg->x1 + 1, seg->y1, layer);
		     if ((tdir & ROUTED_NET_MASK) ==
					(net->netnum | ROUTED_NET)) {
			if (stub + LefGetRouteKeepout(layer) >= PitchX) {
		      	   dc = Xlowerbound + (double)(seg->x1 + 1) * PitchX;
		      	   x2 = (int)((REPS(dc)) * oscale);
			}
		     }
		  }
		  else if ((x > x2) && (seg->x1 > 0)) {
		     tdir = OBSVAL(seg->x1 - 1, seg->y1, layer);
		     if ((tdir & ROUTED_NET_MASK) ==
					(net->netnum | ROUTED_NET)) {
			if (-stub + LefGetRouteKeepout(layer) >= PitchX) {
		      	   dc = Xlowerbound + (double)(seg->x1 - 1) * PitchX;
		      	   x2 = (int)((REPS(dc)) * oscale);
			}
		     }
		  }

		  dc = oscale * 0.5 * LefGetRouteWidth(layer);
		  if (special == (u_char)0) {
		     // Regular nets include 1/2 route width at
		     // the ends, so subtract from the stub terminus
		     if (x < x2) {
			x2 -= dc;
			if (x >= x2) cancel = TRUE;
		     }
		     else {
			x2 += dc;
			if (x <= x2) cancel = TRUE;
		     }
		  }
		  else {
		     // Special nets don't include 1/2 route width
		     // at the ends, so add to the route at the grid
		     if (x < x2)
			x -= dc;
		     else
			x += dc;

		     // Routes that extend for more than one track
		     // without a bend do not need a wide stub
		     if (seg->x1 != seg->x2) cancel = TRUE;
	  	  }
	       }
	       else {
		  horizontal = FALSE;

		  // If the gridpoint ahead of the stub has a route
		  // on the same net, and the stub is long enough
		  // to come within a DRC spacing distance of the
		  // other route, then lengthen it to close up the
		  // distance and resolve the error.

		  if ((y < y2) && (seg->y1 < (NumChannelsY - 1))) {
		     tdir = OBSVAL(seg->x1, seg->y1 + 1, layer);
		     if ((tdir & ROUTED_NET_MASK) ==
						(net->netnum | ROUTED_NET)) {
			if (stub + LefGetRouteKeepout(layer) >= PitchY) {
		      	   dc = Ylowerbound + (double)(seg->y1 + 1) * PitchY;
		      	   y2 = (int)((REPS(dc)) * oscale);
			}
		     }
		  }
		  else if ((y > y2) && (seg->y1 > 0)) {
		     tdir = OBSVAL(seg->x1, seg->y1 - 1, layer);
		     if ((tdir & ROUTED_NET_MASK) ==
						(net->netnum | ROUTED_NET)) {
			if (-stub + LefGetRouteKeepout(layer) >= PitchY) {
		      	   dc = Ylowerbound + (double)(seg->y1 - 1) * PitchY;
		      	   y2 = (int)((REPS(dc)) * oscale);
			}
		     }
		  }

		  dc = oscale * 0.5 * LefGetRouteWidth(layer);
		  if (special == (u_char)0) {
		     // Regular nets include 1/2 route width at
		     // the ends, so subtract from the stub terminus
		     if (y < y2) {
			y2 -= dc;
			if (y >= y2) cancel = TRUE;
		     }
		     else {
			y2 += dc;
			if (y <= y2) cancel = TRUE;
		     }
		  }
		  else {
		     // Special nets don't include 1/2 route width
		     // at the ends, so add to the route at the grid
		     if (y < y2)
			y -= dc;
		     else
			y += dc;

		     // Routes that extend for more than one track
		     // without a bend do not need a wide stub
		     if (seg->y1 != seg->y2) cancel = TRUE;
		  }
	       }

	       if (cancel == FALSE) {
		  net->flags |= NET_STUB;
		  rt->flags |= RT_STUB;
		  pathstart(Cmd, layer, x2, y2, special, oscale, invscale, horizontal,
			lnode);
		  pathto(Cmd, x, y, horizontal, x2, y2, invscale, nextvia);
	       }
	       lastx = x;
	       lasty = y;
	       lastlay = layer;
	    }
	 }

	 prevseg = NULL;
	 lastseg = NULL;
	 for (seg = rt->segments; seg; seg = seg->next) {
	    nextvia = (seg->next) ? ((seg->next->segtype == ST_VIA) ? 1 : 0) : 0;
	    layer = seg->layer;

	    // Check for offset terminals at either point

	    offset1 = 0.0;
	    offset2 = 0.0;
	    dir1 = 0;
	    dir2 = 0;
	    lnode1 = lnode2 = NULL;

	    if (seg->segtype & ST_OFFSET_START) {
	       dir1 = OBSVAL(seg->x1, seg->y1, seg->layer) & OFFSET_TAP;
	       if ((dir1 == 0) && lastseg) {
		  dir1 = OBSVAL(lastseg->x2, lastseg->y2, lastseg->layer)
				& OFFSET_TAP;
		  lnode1 = NODEIPTR(lastseg->x2, lastseg->y2, lastseg->layer);
		  offset1 = lnode1->offset;
	       }
	       else {
		  lnode1 = NODEIPTR(seg->x1, seg->y1, seg->layer);
		  offset1 = lnode1->offset;
	       }

	       // Offset was calculated for vias;  plain metal routes
	       // typically will need less offset distance, so subtract off
	       // the difference.

	       if (!(seg->segtype & ST_VIA)) {
		  if (offset1 < 0) {
		     offset1 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer, 
				horizontal) - LefGetRouteWidth(seg->layer));
		     if (offset1 > 0) offset1 = 0;
		  }
		  else if (offset1 > 0) {
		     offset1 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer,
				horizontal) - LefGetRouteWidth(seg->layer));
		     if (offset1 < 0) offset1 = 0;
		  }
	       }

	       if (special == (u_char)0) {
		  if ((seg->segtype & ST_VIA) && (Verbose > 2))
		     Fprintf(stdout, "Offset terminal distance %g to grid"
					" at %d %d (%d)\n", offset1,
					seg->x1, seg->y1, layer);
	       }
	    }
	    if (seg->segtype & ST_OFFSET_END) {
	       dir2 = OBSVAL(seg->x2, seg->y2, seg->layer) & OFFSET_TAP;
	       if ((dir2 == 0) && seg->next) {
		  dir2 = OBSVAL(seg->next->x1, seg->next->y1, seg->next->layer) &
					OFFSET_TAP;
		  lnode2 = NODEIPTR(seg->next->x1, seg->next->y1, seg->next->layer);
		  if (lnode2 != NULL)
		      offset2 = lnode2->offset;
	       }
	       else {
		  lnode2 = NODEIPTR(seg->x2, seg->y2, seg->layer);
		  if (lnode2 != NULL)
		      offset2 = lnode2->offset;
	       }

	       // Offset was calculated for vias;  plain metal routes
	       // typically will need less offset distance, so subtract off
	       // the difference.

	       if (!(seg->segtype & ST_VIA)) {
		  if (offset2 < 0) {
		     offset2 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer,
				horizontal) - LefGetRouteWidth(seg->layer));
		     if (offset2 > 0) offset2 = 0;
		  }
		  else if (offset2 > 0) {
		     offset2 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer, 
				horizontal) - LefGetRouteWidth(seg->layer));
		     if (offset2 < 0) offset2 = 0;
		  }
	       }

	       if (special == (u_char)0) {
		  if ((seg->segtype & ST_VIA)
					&& !(seg->segtype & ST_OFFSET_START))
		     if (Verbose > 2)
		        Fprintf(stdout, "Offset terminal distance %g to grid"
					" at %d %d (%d)\n", offset2,
					seg->x2, seg->y2, layer);
	       }
	    }

	    // To do: pick up route layer name from lefInfo.
	    // At the moment, technology names don't even match,
	    // and are redundant between CIFLayer[] from the
	    // config file and lefInfo.

	    dc = Xlowerbound + (double)seg->x1 * PitchX;
	    if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_EW)) dc += offset1;
	    x = (int)((REPS(dc)) * oscale);
	    dc = Ylowerbound + (double)seg->y1 * PitchY;
	    if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_NS)) dc += offset1;
	    y = (int)((REPS(dc)) * oscale);
	    dc = Xlowerbound + (double)seg->x2 * PitchX;
	    if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_EW)) dc += offset2;
	    x2 = (int)((REPS(dc)) * oscale);
	    dc = Ylowerbound + (double)seg->y2 * PitchY;
	    if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_NS)) dc += offset2;
	    y2 = (int)((REPS(dc)) * oscale);
	    segtype = seg->segtype & ~(ST_OFFSET_START | ST_OFFSET_END);
	    switch (segtype) {
	       case ST_WIRE:

		  // Normally layers change only at a via.  However, if
		  // a via has been removed and replaced by a 1-track
		  // segment to a neighboring via to avoid DRC errors
		  // (see cleanup_net()), then a layer change may happen
		  // between two ST_WIRE segments, and a new path should
		  // be started.

		  if ((Pathon != -1) && (lastlay != -1) && (lastlay != seg->layer))
		     Pathon = 0;

		  if (Pathon != 1) {	// 1st point of route seg
		     if (x == x2) {
			horizontal = FALSE;
		     }
		     else if (y == y2) {
			horizontal = TRUE;
		     }
		     else if (Verbose > 3) {
			// NOTE:  This is a development diagnostic.  The
			// occasional non-Manhanhattan route is due to a
			// tap offset and is corrected automatically by
			// making an L-bend in the wire.

		     	Flush(stdout);
			Fprintf(stderr, "Warning:  non-Manhattan wire in route"
				" at (%d, %d) to (%d, %d)\n", x, y, x2, y2);
		     }
		     if (special == (u_char)0) {
			if (lastseg && (lastseg->segtype & ST_OFFSET_START) &&
				((lastx != x) || (lasty != y))) {
			   /* Add bend and connect to offset via */
			   int vertical = (horizontal) ? FALSE : TRUE;
			   pathstart(Cmd, seg->layer, lastx, lasty, special,
				oscale, invscale, vertical, lnode2);
			   pathto(Cmd, x, y, vertical, lastx, lasty, invscale, nextvia);
			}
			else if (lastseg && (lastseg->segtype & ST_VIA) &&
				(lastx != x) && (lasty == y) &&
				(LefGetRouteOrientation(seg->layer) == 1)) {
			   /* Via offset in direction of route (horizontal) */
			   pathstart(Cmd, seg->layer, lastx, y, special, oscale,
				invscale, horizontal, lnode2);
			}
			else if (lastseg && (lastseg->segtype & ST_VIA) &&
				(lastx == x) && (lasty != y) &&
				(LefGetRouteOrientation(seg->layer) == 0)) {
			   /* Via offset in direction of route (vertical) */
			   pathstart(Cmd, seg->layer, x, lasty, special, oscale,
				invscale, horizontal, lnode2);
			}
			else {
			   pathstart(Cmd, seg->layer, x, y, special, oscale,
				invscale, horizontal, lnode2);
			}
			lastx = x;
			lasty = y;
			lastlay = seg->layer;
		     }
		  }
		  rt->flags |= RT_OUTPUT;
		  if (horizontal && x == x2) {
		     horizontal = FALSE;
		  }
		  if ((!horizontal) && y == y2) {
		     horizontal = TRUE;
		  }
		  if (!(x == x2) && !(y == y2)) {
		     horizontal = FALSE;
		  }
		  if (special == (u_char)0) {
		     pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale, nextvia);
		     lastx = x2;
		     lasty = y2;
		  }

		  // Check for path segments that are used for minimum metal
		  // area requirements so that they do not become false
		  // positives for inter-via special nets.

		  if (lastseg && seg->next && (lastseg->x1 == seg->next->x2) &&
				(lastseg->y1 == seg->next->y2)) 
		      seg->segtype |= ST_MINMETAL;

		  // If a segment is 1 track long, there is a via on either
		  // end, and the needblock flag is set for the layer, then
		  // draw a stub route along the length of the track.

		  if (horizontal && needblock[seg->layer] & VIABLOCKX) {
		     if ((ABSDIFF(seg->x2, seg->x1) == 1) &&
				!(seg->segtype & ST_MINMETAL)) {
			if ((lastseg && lastseg->segtype == ST_VIA) ||
			    (seg->next && seg->next->segtype == ST_VIA)) {
			   if (special == (u_char)0) {
			      net->flags |= NET_STUB;
			      rt->flags |= RT_STUB;
			   }
			   else {
			      if (Pathon != -1) Pathon = 0;
			      pathstart(Cmd, layer, x, y, special, oscale,
						invscale, horizontal, lnode2);
			      pathto(Cmd, x2, y2, horizontal, x, y, invscale, 0);
			      lastlay = layer;
			   }
			}
		     }
		  }
		  else if (!horizontal && needblock[seg->layer] & VIABLOCKY) {
		     if ((ABSDIFF(seg->y2, seg->y1) == 1) &&
				!(seg->segtype & ST_MINMETAL)) {
			if ((lastseg && lastseg->segtype == ST_VIA) ||
			    (seg->next && seg->next->segtype == ST_VIA)) {
			   if (special == (u_char)0) {
			      net->flags |= NET_STUB;
			      rt->flags |= RT_STUB;
			   }
			   else {
			      if (Pathon != -1) Pathon = 0;
			      pathstart(Cmd, layer, x, y, special, oscale,
						invscale, horizontal, lnode2);
			      pathto(Cmd, x2, y2, horizontal, x, y, invscale, 0);
			      lastlay = layer;
			   }
			}
		     }
		  }
		  break;

	       case ST_VIA:
		  rt->flags |= RT_OUTPUT;
		  if (special == (u_char)0) {
		     double viaoffx, viaoffy;
		     double w0, w1, dc, altwx, altwy;
		     float offsetx, offsety;
		     int vx = 0;
		     int vy = 0;
		     int flags;
		     u_int tdirpp, tdirp, tdirn;
		     u_char viaNL, viaNM, viaNU;
		     u_char viaSL, viaSM, viaSU;
		     u_char viaEL, viaEM, viaEU;
		     u_char viaWL, viaWM, viaWU;
		     u_char rteNL, rteNU;
		     u_char rteSL, rteSU;
		     u_char rteEL, rteEU;
		     u_char rteWL, rteWU;
		     char *s;
		     char checkersign;
		     int ob, ot;

		     if (lastseg == NULL) {
			// Make sure last position is valid
			lastx = x;
			lasty = y;
		     }

		     // If vias need to be rotated then they do so on a
		     // checkerboard pattern.
		     checkersign = (char)((seg->x1 + seg->y1) & 0x01);

		     // Get the default orientation of the via
		     ob = LefGetRouteOrientation(layer);
		     ot = LefGetRouteOrientation(layer + 1);
		     if (ob == 0 && ot == 1)
			s = ViaYX[layer];
		     else if (ob == 1 && ot == 0)
			s = ViaXY[layer];
		     else if (ob == 0 && ot == 0)
			s = ViaYY[layer];
		     else
			s = ViaXX[layer];

		     // If via is on a pin and rotation is restricted, then
		     // set the rotation accordingly.

		     flags = 0;
		     if (layer < Pinlayers) {
			if ((lnode = NODEIPTR(seg->x1, seg->y1, layer)) != NULL) {
			    if (lnode->flags & NI_NO_VIAX) {
				flags = NI_NO_VIAX;
				if (s == ViaXY[layer])
				    s = ViaYY[layer];
				else if (s == ViaXX[layer])
				    s = ViaYX[layer];
			    }
			    if (lnode->flags & NI_NO_VIAY) {
				flags = NI_NO_VIAY;
				if (s == ViaYX[layer])
				    s = ViaXX[layer];
				else if (s == ViaYY[layer])
				    s = ViaXY[layer];
			    }
			    /* Mark the node with which via direction was used */
			    if ((s == ViaYY[layer]) || (s == ViaYX[layer]))
				lnode->flags |= NI_VIA_Y;
			    else
				lnode->flags |= NI_VIA_X;
			}
		     }

		     // Check for vias between adjacent but different nets
		     // that need rotation and/or position offsets to avoid
		     // a DRC spacing error

		     viaEL = viaEM = viaEU = 0;
		     viaWL = viaWM = viaWU = 0;
		     viaNL = viaNM = viaNU = 0;
		     viaSL = viaSM = viaSU = 0;
		     rteEL = rteEU = rteWL = rteWU = 0;
		     rteNL = rteNU = rteSL = rteSU = 0;

		     // Check for via/route to west
		     if (seg->x1 > 0) {
			tdir = OBSVAL(seg->x1 - 1, seg->y1, layer)
					& ROUTED_NET_MASK;

			if (((tdir & NO_NET) == 0) && (tdir != 0) &&
				(tdir != (net->netnum | ROUTED_NET))) {
			   rteWL = 1;
			   if (layer > 0) {
			      tdirn = OBSVAL(seg->x1 - 1, seg->y1, layer - 1)
					& ROUTED_NET_MASK;
			      if (tdir == tdirn) viaWL = 1;
			   }
			}

			if (layer < Num_layers - 1) {
			   tdirp = OBSVAL(seg->x1 - 1, seg->y1, layer + 1)
					& ROUTED_NET_MASK;
			   if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
				     	(tdirp != (net->netnum | ROUTED_NET))) {
			      rteWU = 1;
			      if (layer < Num_layers - 2) {
			         tdirpp = OBSVAL(seg->x1 - 1, seg->y1, layer + 2)
						& ROUTED_NET_MASK;
			         if (tdirp == tdirpp) viaWU = 1;
			      }
			   }
			   if (rteWL && (tdir == tdirp)) viaWM = 1;
			}
		     }

		     // Check for via/route to east
		     if (seg->x1 < NumChannelsX - 1) {
			tdir = OBSVAL(seg->x1 + 1, seg->y1, layer)
					& ROUTED_NET_MASK;

			if (((tdir & NO_NET) == 0) && (tdir != 0) &&
				(tdir != (net->netnum | ROUTED_NET))) {
			   rteEL = 1;
			   if (layer > 0) {
			      tdirn = OBSVAL(seg->x1 + 1, seg->y1, layer - 1)
					& ROUTED_NET_MASK;
			      if (tdir == tdirn) viaEL = 1;
			   }
			}

			if (layer < Num_layers - 1) {
			   tdirp = OBSVAL(seg->x1 + 1, seg->y1, layer + 1)
					& ROUTED_NET_MASK;
			   if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
				     	(tdirp != (net->netnum | ROUTED_NET))) {
			      rteEU = 1;
			      if (layer < Num_layers - 2) {
			         tdirpp = OBSVAL(seg->x1 + 1, seg->y1, layer + 2)
						& ROUTED_NET_MASK;
			         if (tdirp == tdirpp) viaEU = 1;
			      }
			   }
			   if (rteEL && (tdir == tdirp)) viaEM = 1;
			}
		     }

		     // Check for via/route to south
		     if (seg->y1 > 0) {
			tdir = OBSVAL(seg->x1, seg->y1 - 1, layer)
					& ROUTED_NET_MASK;

			if (((tdir & NO_NET) == 0) && (tdir != 0) &&
				(tdir != (net->netnum | ROUTED_NET))) {
			   rteSL = 1;
			   if (layer > 0) {
			      tdirn = OBSVAL(seg->x1, seg->y1 - 1, layer - 1)
					& ROUTED_NET_MASK;
			      if (tdir == tdirn) viaSL = 1;
			   }
			}

			if (layer < Num_layers - 1) {
			   tdirp = OBSVAL(seg->x1, seg->y1 - 1, layer + 1)
					& ROUTED_NET_MASK;
			   if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
				     	(tdirp != (net->netnum | ROUTED_NET))) {
			      rteSU = 1;
			      if (layer < Num_layers - 2) {
			         tdirpp = OBSVAL(seg->x1, seg->y1 - 1, layer + 2)
						& ROUTED_NET_MASK;
			         if (tdirp == tdirpp) viaSU = 1;
			      }
			   }
			   if (rteSL && (tdir == tdirp)) viaSM = 1;
			}
		     }

		     // Check for via/route to north
		     if (seg->y1 < NumChannelsY - 1) {
			tdir = OBSVAL(seg->x1, seg->y1 + 1, layer)
					& ROUTED_NET_MASK;

			if (((tdir & NO_NET) == 0) && (tdir != 0) &&
				(tdir != (net->netnum | ROUTED_NET))) {
			   rteNL = 1;
			   if (layer > 0) {
			      tdirn = OBSVAL(seg->x1, seg->y1 + 1, layer - 1)
					& ROUTED_NET_MASK;
			      if (tdir == tdirn) viaNL = 1;
			   }
			}

			if (layer < Num_layers - 1) {
			   tdirp = OBSVAL(seg->x1, seg->y1 + 1, layer + 1)
					& ROUTED_NET_MASK;
			   if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
				     	(tdirp != (net->netnum | ROUTED_NET))) {
			      rteNU = 1;
			      if (layer < Num_layers - 2) {
			         tdirpp = OBSVAL(seg->x1, seg->y1 + 1, layer + 2)
						& ROUTED_NET_MASK;
			         if (tdirp == tdirpp) viaNU = 1;
			      }
			   }
			   if (rteNL && (tdir == tdirp)) viaNM = 1;
			}
		     }

		     // Check for any tap offset on the neighboring via,
		     // which needs to be accounted for in the calculations.
		     offsetx = offsety = 0.0;
		     if (viaEL)
			lnode = (layer < Pinlayers && layer > 0) ?
					NODEIPTR(seg->x1 + 1, seg->y1, layer - 1) : NULL;
		     else if (viaWL)
			lnode = (layer < Pinlayers && layer > 0) ?
					NODEIPTR(seg->x1 - 1, seg->y1, layer - 1) : NULL;
		     else if (viaEM)
			lnode = (layer < Pinlayers) ?
					NODEIPTR(seg->x1 + 1, seg->y1, layer) : NULL;
		     else if (viaWM)
			lnode = (layer < Pinlayers) ?
					NODEIPTR(seg->x1 - 1, seg->y1, layer) : NULL;
		     else if (viaEU)
			lnode = (layer < Pinlayers - 1) ?
					NODEIPTR(seg->x1 + 1, seg->y1, layer + 1) : NULL;
		     else if (viaWU)
			lnode = (layer < Pinlayers - 1) ?
					NODEIPTR(seg->x1 - 1, seg->y1, layer + 1) : NULL;

		     if (lnode && (lnode->flags & NI_OFFSET_EW)) {
			offsetx = lnode->offset;
			// offsetx defined as positive in the direction away from
			// the via under consideration.
			if (viaWL || viaWM || viaWU) offsetx = -offsetx;
		     }

		     if (viaNL)
			lnode = (layer < Pinlayers && layer > 0) ?
					NODEIPTR(seg->x1, seg->y1 + 1, layer - 1) : NULL;
		     else if (viaSL)
			lnode = (layer < Pinlayers && layer > 0) ?
					NODEIPTR(seg->x1, seg->y1 - 1, layer - 1) : NULL;
		     else if (viaNM)
			lnode = (layer < Pinlayers) ?
					NODEIPTR(seg->x1, seg->y1 + 1, layer) : NULL;
		     else if (viaSM)
			lnode = (layer < Pinlayers) ?
					NODEIPTR(seg->x1, seg->y1 - 1, layer) : NULL;
		     else if (viaNU)
			lnode = (layer < Pinlayers - 1) ?
					NODEIPTR(seg->x1, seg->y1 + 1, layer + 1) : NULL;
		     else if (viaSU)
			lnode = (layer < Pinlayers - 1) ?
					NODEIPTR(seg->x1, seg->y1 - 1, layer + 1) : NULL;

		     if (lnode && (lnode->flags & NI_OFFSET_NS)) {
			offsety = lnode->offset;
			// offsety defined as positive in the direction away from
			// the via under consideration.
			if (viaSL || viaSM || viaSU) offsety = -offsety;
		     }	

		     // Actions needed only if a via is on the long side and
		     // has a spacing violation.

		     viaoffx = viaoffy = 0.0;
		     altwx = altwy = 0.0;
		     if (ob == 1) {  /* bottom (layer) route is horizontal */
			if (viaEM || viaWM) {
			    /* Assume default rotations and calculate spacing */
			    /* Only take action if there is a spacing violation */

			    w1 = LefGetXYViaWidth(layer, layer, 0, 0);
			    w0 = w1;
		            dc = LefGetRouteSpacing(layer) + w1;
			    if (dc > PitchX + EPS + offsetx) {

				/* via on checkerboard may be rotated */
				if (checkersign && ((flags & NI_NO_VIAY) == 0)) {
				    /* Check spacing violation to routes N and S */
				    /* If via being checked is rotated */
				    if (rteNL || rteSL)
					dc = LefGetRouteSpacing(layer) +
						(LefGetXYViaWidth(layer, layer, 1, 2) +
						LefGetRouteWidth(layer)) / 2;
				    if ((!(rteNL || rteSL))
						|| (dc <= PitchY + EPS)) {
					/* Okay to rotate the via bottom */
					w0 = LefGetXYViaWidth(layer, layer, 0, 2);
					s = (ot == 1) ? ViaYX[layer] : ViaYY[layer];
				    }
				    else if (rteNL || rteSL)
					altwx = w1 -
						LefGetXYViaWidth(layer, layer, 0, 2);

				    /* Measure spacing violation to via */
		        	    dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
				    if (dc > PitchX + EPS + offsetx) {
					/* Calculate offset */
					if (viaEM)
					    viaoffx = PitchX + 2 * offsetx - dc;
					else
					    viaoffx = dc - PitchX - 2 * offsetx;
				    }
				}
				else {
				    /* Measure spacing violation to rotated via */
				    w0 = LefGetXYViaWidth(layer, layer, 0, 2);
		        	    dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
				    if (dc > PitchX + EPS + offsetx) {
					/* Calculate offset */
					if (viaEM)
					    viaoffx = PitchX + 2 * offsetx - dc;
					else
					    viaoffx = dc - PitchX - 2 * offsetx;
				    }
				}
			    }
			}
			else if (viaEL || viaWL) {
			    /* Assume default rotations and calculate spacing */
			    /* Only take action if there is a spacing violation */

			    w0 = LefGetXYViaWidth(layer - 1, layer, 0, 0);
			    w1 = LefGetXYViaWidth(layer, layer, 0, 0);
		            dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
			    if (dc > PitchX + EPS + offsetx) {

				/* via on checkerboard may be rotated */
				if (checkersign && ((flags & NI_NO_VIAY) == 0)) {
				    /* Check spacing violation to routes N and S */
				    /* If via being checked is rotated */
				    if (rteNL || rteSL)
					dc = LefGetRouteSpacing(layer) +
						(LefGetXYViaWidth(layer, layer, 1, 2) +
						LefGetRouteWidth(layer)) / 2;
				    if ((!(rteNL || rteSL))
						|| (dc <= PitchY + EPS)) {
					/* Okay to rotate the via bottom */
					w1 = LefGetXYViaWidth(layer, layer, 0, 2);
					s = (ot == 1) ? ViaYX[layer] : ViaYY[layer];
				    }
				    else if (rteNL || rteSL)
					altwx = w1 -
						LefGetXYViaWidth(layer, layer, 0, 2);

				    /* Measure spacing violation to via */
		        	    dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
				    if (dc > PitchX + EPS + offsetx) {
					/* Calculate offset */
					if (viaEL)
					    viaoffx = PitchX + 2 * offsetx - dc;
					else
					    viaoffx = dc - PitchX - 2 * offsetx;
				    }
				}
				else {
				    /* Measure spacing violation to rotated via */
				    w0 = LefGetXYViaWidth(layer - 1, layer, 0, 1);
		        	    dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
				    if (dc > PitchX + EPS + offsetx) {
					/* Calculate offset */
					if (viaEL)
					    viaoffx = PitchX + 2 * offsetx - dc;
					else
					    viaoffx = dc - PitchX - 2 * offsetx;
				    }
				}
			    }
			}
		     } else {	     /* bottom route vertical */
			if (viaNM || viaSM) {
			    /* Assume default rotations and calculate spacing */
			    /* Only take action if there is a spacing violation */

			    w1 = LefGetXYViaWidth(layer, layer, 1, 3);
			    w0 = w1;
		            dc = LefGetRouteSpacing(layer) + w1;
			    if (dc > PitchY + EPS + offsety) {

				/* via on checkerboard may be rotated */
				if (checkersign && ((flags & NI_NO_VIAX) == 0)) {
				    /* Check spacing violation to routes E and W */
				    /* If via being checked is rotated */
				    if (rteEL || rteWL)
					dc = LefGetRouteSpacing(layer) +
						(LefGetXYViaWidth(layer, layer, 0, 1) +
						LefGetRouteWidth(layer)) / 2;
				    if ((!(rteEL || rteWL))
						|| (dc <= PitchX + EPS)) {
					/* Okay to rotate the via bottom */
					w0 = LefGetXYViaWidth(layer, layer, 1, 1);
					s = (ot == 1) ? ViaXX[layer] : ViaXY[layer];
				    }
				    else if (rteEL || rteWL)
					altwy = w1 -
						LefGetXYViaWidth(layer, layer, 1, 1);

				    /* Measure spacing violation to via */
		        	    dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
				    if (dc > PitchY + EPS + offsety) {
					/* Calculate offset */
					if (viaNM)
					    viaoffy = PitchY + 2 * offsety - dc;
					else
					    viaoffy = dc - PitchY - 2 * offsety;
				    }
				}
				else {
				    /* Measure spacing violation to rotated via */
				    w0 = LefGetXYViaWidth(layer, layer, 1, 1);
		        	    dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
				    if (dc > PitchY + EPS + offsety) {
					/* Calculate offset */
					if (viaNM)
					    viaoffy = PitchY + 2 * offsety - dc;
					else
					    viaoffy = dc - PitchY - 2 * offsety;
				    }
				}
			    }
			}
			else if (viaNL || viaSL) {
			    /* Assume default rotations and calculate spacing */
			    /* Only take action if there is a spacing violation */

			    w0 = LefGetXYViaWidth(layer - 1, layer, 1, 3);
			    w1 = LefGetXYViaWidth(layer, layer, 1, 3);
		            dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
			    if (dc > PitchY + EPS + offsety) {

				/* via on checkerboard may be rotated */
				if (checkersign && ((flags & NI_NO_VIAX) == 0)) {
				    /* Check spacing violation to routes E and W */
				    /* If via being checked is rotated */
				    if (rteEL || rteWL)
					dc = LefGetRouteSpacing(layer) +
						(LefGetXYViaWidth(layer, layer, 0, 1) +
						LefGetRouteWidth(layer)) / 2;
				    if ((!(rteEL || rteWL))
						|| (dc <= PitchX + EPS)) {
					/* Okay to rotate the via bottom */
					w1 = LefGetXYViaWidth(layer, layer, 1, 1);
					s = (ot == 1) ? ViaXX[layer] : ViaXY[layer];
				    }
				    else if (rteEL || rteWL)
					altwy = w1 -
						LefGetXYViaWidth(layer, layer, 1, 1);

				    /* Measure spacing violation to via */
		        	    dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
				    if (dc > PitchY + EPS + offsety) {
					/* Calculate offset */
					if (viaNL)
					    viaoffy = PitchY + 2 * offsety - dc;
					else
					    viaoffy = dc - PitchY - 2 * offsety;
				    }
				}
				else {
				    /* Measure spacing violation to rotated via */
				    w0 = LefGetXYViaWidth(layer - 1, layer, 1, 2);
		        	    dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
				    if (dc > PitchY + EPS + offsety) {
					/* Calculate offset */
					if (viaNL)
					    viaoffy = PitchY + 2 * offsety - dc;
					else
					    viaoffy = dc - PitchY - 2 * offsety;
				    }
				}
			    }
			}
		     }

		     if (ot == 1) {  /* top route horizontal */
			if (viaEU || viaWU) {
			    /* Assume default rotations and calculate spacing */
			    /* Only take action if there is a spacing violation */

			    w0 = LefGetXYViaWidth(layer + 1, layer + 1, 0, 0);
			    w1 = LefGetXYViaWidth(layer, layer + 1, 0, 0);
		            dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
			    if (dc > PitchX + EPS + offsetx) {

				/* via on checkerboard may be rotated */
				if (checkersign) {
				    /* Check spacing violation to routes N and S */
				    /* If via being checked is rotated */
				    if (rteNU || rteSU)
					dc = LefGetRouteSpacing(layer + 1) +
						(LefGetXYViaWidth(layer, layer + 1, 1, 1)
						+ LefGetRouteWidth(layer + 1)) / 2;
				    if ((!(rteNU || rteSU))
						|| (dc <= PitchY + EPS)) {
					/* Okay to rotate the via top */
					w1 = LefGetXYViaWidth(layer, layer + 1, 0, 1);
					s = (s == ViaYX[layer]) ? ViaYY[layer] :
							ViaXY[layer];
				    }
				    else if (rteNU || rteSU)
					altwx = w1 -
						LefGetXYViaWidth(layer, layer + 1, 0, 1);

				    /* Measure spacing violation to via */
		        	    dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
				    if (dc > PitchX + EPS + offsetx) {
					/* Calculate offset */
					if (viaEU)
					    viaoffx = PitchX + 2 * offsetx - dc;
					else
					    viaoffx = dc - PitchX - 2 * offsetx;
				    }
				}
				else {
				    /* Measure spacing violation to rotated via */
				    w0 = LefGetXYViaWidth(layer + 1, layer + 1, 0, 2);
		        	    dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
				    if (dc > PitchX + EPS + offsetx) {
					/* Calculate offset */
					if (viaEU)
					    viaoffx = PitchX + 2 * offsetx - dc;
					else
					    viaoffx = dc - PitchX - 2 * offsetx;
				    }
				}
			    }
			}
			else if (viaEM || viaWM) {
			    /* Assume default rotations and calculate spacing */
			    /* Only take action if there is a spacing violation */

			    w1 = LefGetXYViaWidth(layer, layer + 1, 0, 0);
			    w0 = w1;
		            dc = LefGetRouteSpacing(layer + 1) + w1;
			    if (dc > PitchX + EPS + offsetx) {

				/* via on checkerboard may be rotated */
				if (checkersign) {
				    /* Check spacing violation to routes N and S */
				    /* If via being checked is rotated */
				    if (rteNU || rteSU)
					dc = LefGetRouteSpacing(layer) +
						(LefGetXYViaWidth(layer, layer + 1, 1, 1)
						+ LefGetRouteWidth(layer)) / 2;
				    if ((!(rteNU || rteSU)) || (dc <= PitchY + EPS)) {
					/* Okay to rotate the via top */
					w0 = LefGetXYViaWidth(layer, layer + 1, 0, 1);
					s = (s == ViaYX[layer]) ? ViaYY[layer] :
							ViaXY[layer];
				    }
				    else if (rteNU || rteSU)
					altwx = w1 -
						LefGetXYViaWidth(layer, layer + 1, 0, 1);

				    /* Measure spacing violation to via */
		        	    dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
				    if (dc > PitchX + EPS + offsetx) {
					/* Calculate offset */
					if (viaEM)
					    viaoffx = PitchX + 2 * offsetx - dc;
					else
					    viaoffx = dc - PitchX - 2 * offsetx;
				    }
				}
				else {
				    /* Measure spacing violation to rotated via */
				    w0 = LefGetXYViaWidth(layer, layer + 1, 0, 1);
		        	    dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
				    if (dc > PitchX + EPS + offsetx) {
					/* Calculate offset */
					if (viaEM)
					    viaoffx = PitchX + 2 * offsetx - dc;
					else
					    viaoffx = dc - PitchX - 2 * offsetx;
				    }
				}
			    }
			}
		     } else {	     /* top route vertical */
			if (viaNU || viaSU) {
			    /* Assume default rotations and calculate spacing */
			    /* Only take action if there is a spacing violation */

			    w0 = LefGetXYViaWidth(layer + 1, layer + 1, 1, 3);
			    w1 = LefGetXYViaWidth(layer, layer + 1, 1, 3);
		            dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
			    if (dc > PitchY + EPS + offsety) {

				/* via on checkerboard may be rotated */
				if (checkersign) {
				    /* Check spacing violation to routes E and W */
				    /* If via being checked is rotated */
				    if (rteEU || rteWU)
					dc = LefGetRouteSpacing(layer + 1) +
						(LefGetXYViaWidth(layer, layer + 1, 0, 2)
						+ LefGetRouteWidth(layer + 1)) / 2;
				    if ((!(rteEU || rteWU))
						|| (dc <= PitchX + EPS)) {
					/* Okay to rotate the via top */
					w1 = LefGetXYViaWidth(layer, layer + 1, 1, 2);
					s = (s == ViaYY[layer]) ? ViaYX[layer] :
							ViaXX[layer];
				    }
				    else if (rteEU || rteWU)
					altwy = w1 -
						LefGetXYViaWidth(layer, layer + 1, 1, 2);

				    /* Measure spacing violation to via */
		        	    dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
				    if (dc > PitchY + EPS + offsety) {
					/* Calculate offset */
					if (viaNU)
					    viaoffy = PitchY + 2 * offsety - dc;
					else
					    viaoffy = dc - PitchY - 2 * offsety;
				    }
				}
				else {
				    /* Measure spacing violation to rotated via */
				    w0 = LefGetXYViaWidth(layer + 1, layer + 1, 1, 1);
		        	    dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
				    if (dc > PitchY + EPS + offsety) {
					/* Calculate offset */
					if (viaNU)
					    viaoffy = PitchY + 2 * offsety - dc;
					else
					    viaoffy = dc - PitchY - 2 * offsety;
				    }
				}
			    }
			}
			else if (viaNM || viaSM) {
			    /* Assume default rotations and calculate spacing */
			    /* Only take action if there is a spacing violation */

			    w1 = LefGetXYViaWidth(layer, layer + 1, 1, 3);
			    w0 = w1;
		            dc = LefGetRouteSpacing(layer + 1) + w1;
			    if (dc > PitchY + EPS + offsety) {

				/* via on checkerboard may be rotated */
				if (checkersign) {
				    /* Check spacing violation to routes E and W */
				    /* If via being checked is rotated */
				    if (rteEU || rteWU)
					dc = LefGetRouteSpacing(layer + 1) +
						(LefGetXYViaWidth(layer, layer + 1, 0, 2)
						+ LefGetRouteWidth(layer + 1)) / 2;
				    if ((!(rteEU || rteWU))
						|| (dc <= PitchX + EPS)) {
					/* Okay to rotate the via top */
					w1 = LefGetXYViaWidth(layer, layer + 1, 1, 2);
					s = (s == ViaYY[layer]) ? ViaYX[layer] :
							ViaXX[layer];
				    }
				    else if (rteEU || rteWU)
					altwy = w1 -
						LefGetXYViaWidth(layer, layer + 1, 1, 2);

				    /* Measure spacing violation to via */
		        	    dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
				    if (dc > PitchY + EPS + offsety) {
					/* Calculate offset */
					if (viaNM)
					    viaoffy = PitchY + 2 * offsety - dc;
					else
					    viaoffy = dc - PitchY - 2 * offsety;
				    }
				}
				else {
				    /* Measure spacing violation to rotated via */
				    w0 = LefGetXYViaWidth(layer, layer + 1, 1, 2);
		        	    dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
				    if (dc > PitchY + EPS + offsety) {
					/* Calculate offset */
					if (viaNM)
					    viaoffy = PitchY + 2 * offsety - dc;
					else
					    viaoffy = dc - PitchY - 2 * offsety;
				    }
				}
			    }
			}
		     }

		     /* If a via is constrained by routes on the side	*/
		     /* and cannot be rotated, then the calculations on	*/
		     /* the via in the next track will not take that	*/
		     /* into consideration, and not leave enough space.	*/
		     /* So this via must offset	more to make up the	*/
		     /* difference.					*/

		     if (altwx > 0.0) {
			if (viaoffx < 0) altwx = -altwx;
			viaoffx += altwx;
		     }
		     if (altwy > 0.0) {
			if (viaoffy < 0) altwy = -altwy;
			viaoffy += altwy;
		     }

		     /* When offset, each via moves by half the distance. */
		     viaoffx /= 2;
		     viaoffy /= 2;

		     vx = (int)((REPS(viaoffx)) * oscale);
		     vy = (int)((REPS(viaoffy)) * oscale);

		     /* If via is offset in the direction of the last	*/
		     /* route segment, then move the last route segment	*/
		     /* position to the via center.			*/
		     if ((path_delayed.active == 1) && (vy != 0) &&
				(path_delayed.orient == 0))
			path_delayed.y = y + vy;

		     else if ((path_delayed.active == 1) && (vx != 0) &&
				(path_delayed.orient == 1))
			path_delayed.x = x + vx;

		     pathvia(Cmd, layer, x + vx, y + vy, lastx, lasty, s, invscale);

		     lastx = x + vx;
		     lasty = y + vy;
		     lastlay = -1;
		  }
		  break;
	       default:
		  break;
	    }

	    // Break here on last segment so that seg and lastseg are valid
	    // in the following section of code.

	    if (seg->next == NULL) break;
	    prevseg = lastseg;
	    lastseg = seg;
	 }

	 // For stub routes, reset the path between terminals, since
	 // the stubs are not connected.
	 if (special == (u_char)1 && Pathon != -1) Pathon = 0;

	 // Check last position for terminal offsets
	 if (seg && ((seg != saveseg) || (seg->segtype & ST_WIRE))) {
	     cancel = FALSE;
	     layer = seg->layer;
	     lnode = (layer < Pinlayers) ? NODEIPTR(seg->x2, seg->y2, layer) : NULL;

	     // Look for stub routes and offset taps
	     dir2 = OBSVAL(seg->x2, seg->y2, layer) & (STUBROUTE | OFFSET_TAP);

	     if ((dir2 & OFFSET_TAP) && (seg->segtype & ST_VIA) && prevseg) {

	        // Additional handling for offset taps.  When a tap position
	        // is a via and is offset in the direction of the last
	        // route segment, then a DRC violation can be created if
	        // (1) the via is wider than the route width, and (2) the
	        // adjacent track position is another via or a bend in the
	        // route, and (3) the tap offset is large enough to create
	        // a spacing violation between the via and the adjacent via
	        // or perpendicular route.  If these three conditions are
	        // satisfied, then generate a stub route the width of the
	        // via and one track pitch in length back toward the last
	        // track position.

 	        // Problems only arise when the via width is larger than
	        // the width of the metal route leaving the via.
 
	        offset = lnode->offset;
	        if (LefGetViaWidth(seg->layer, lastseg->layer, 1 - horizontal) >
			LefGetRouteWidth(lastseg->layer)) {

		   // Problems only arise when the last segment is exactly
		   // one track long.

		   if ((ABSDIFF(lastseg->x2, lastseg->x1) == 1) ||
			(ABSDIFF(lastseg->y2, lastseg->y1) == 1)) {

		      if (prevseg->segtype & ST_VIA) {

		 	 dc = Xlowerbound + (double)seg->x1 * PitchX;
			 x = (int)((REPS(dc)) * oscale);
			 dc = Ylowerbound + (double)seg->y1 * PitchY;
			 y = (int)((REPS(dc)) * oscale);

			 dc = Xlowerbound + (double)prevseg->x1 * PitchX;
			 x2 = (int)((REPS(dc)) * oscale);
			 dc = Ylowerbound + (double)prevseg->y1 * PitchY;
			 y2 = (int)((REPS(dc)) * oscale);

			 // Setup is (via, 1 track route, via with offset)

			 if (prevseg->x1 != seg->x1) {
			    if ((PitchX -
				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) -
				0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 1) -
				(prevseg->x1 - seg->x1) * offset)
				< LefGetRouteSpacing(lastseg->layer)) {
			       if (special == (u_char)0) {
				  rt->flags |= RT_STUB;
				  net->flags |= NET_STUB;
			       }
			       else {
				  pathstart(Cmd, lastseg->layer, x, y,
					(u_char)1, oscale, invscale, 1, lnode);
				  pathto(Cmd, x2, y2, 1, x, y, invscale, 0);
		      		  lastx = x2;
				  lasty = y2;
			       }
			    }
			 }
			 else if (prevseg->y1 != seg->y1) {
			    if ((PitchY -
				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) -
				0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 0)
				- (prevseg->y1 - seg->y1) * offset)
				< LefGetRouteSpacing(lastseg->layer)) {
			       if (special == (u_char)0) {
				 rt->flags |= RT_STUB;
				 net->flags |= NET_STUB;
			       }
			       else {
				  pathstart(Cmd, lastseg->layer, x, y,
					(u_char)1, oscale, invscale, 0, lnode);
				  pathto(Cmd, x2, y2, 0, x, y, invscale, 0);
		      		  lastx = x2;
				  lasty = y2;
			       }
			    }
			 }
		      }
		      else {	// Metal route bends at next track
			 if (prevseg->x1 != seg->x1) {
			    if ((PitchX -
				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) -
				0.5 * LefGetRouteWidth(prevseg->layer) -
				(prevseg->x1 - seg->x1) * offset)
				< LefGetRouteSpacing(lastseg->layer)) {
			       if (special == (u_char)0) {
				 rt->flags |= RT_STUB;
				 net->flags |= NET_STUB;
			       }
			       else {
				  pathstart(Cmd, lastseg->layer, x, y,
					(u_char)1, oscale, invscale, 1, lnode);
				  pathto(Cmd, x2, y2, 1, x, y, invscale, 0);
		      		  lastx = x2;
				  lasty = y2;
			       }
			    }
			 }
			 else if (prevseg->y1 != seg->y1) {
			    if ((PitchY -
				0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) -
				0.5 * LefGetRouteWidth(prevseg->layer) -
				(prevseg->y1 - seg->y1) * offset)
				< LefGetRouteSpacing(lastseg->layer)) {
			       if (special == (u_char)0) {
				  rt->flags |= RT_STUB;
				  net->flags |= NET_STUB;
			       }
			       else {
				  pathstart(Cmd, lastseg->layer, x, y,
					(u_char)1, oscale, invscale, 0, lnode);
				  pathto(Cmd, x2, y2, 0, x, y, invscale, 0);
		      		  lastx = x2;
				  lasty = y2;
			       }
			    }
			 }
		      }
		   }
	        }
	     }

	     // For stub routes, reset the path between terminals, since
	     // the stubs are not connected.
	     if (special == (u_char)1 && Pathon != -1) Pathon = 0;

	     // Handling of stub routes
	     if (dir2 & STUBROUTE) {
	        stub = lnode->stub;
		if ((special == (u_char)0) && (Verbose > 2))
		   Fprintf(stdout, "Stub route distance %g to terminal"
				" at %d %d (%d)\n",
				stub, seg->x2, seg->y2, layer);

		dc = Xlowerbound + (double)seg->x2 * PitchX;
		if (lnode->flags & NI_OFFSET_EW)
		   dc += offset;
		x = (int)((REPS(dc)) * oscale);
		if (lnode->flags & NI_STUB_EW)
		   dc += stub;
		x2 = (int)((REPS(dc)) * oscale);
		dc = Ylowerbound + (double)seg->y2 * PitchY;
		if (lnode->flags & NI_OFFSET_NS)
		   dc += offset;
		y = (int)((REPS(dc)) * oscale);
		if (lnode->flags & NI_STUB_NS)
		   dc += stub;
		y2 = (int)((REPS(dc)) * oscale);
		if (lnode->flags & NI_STUB_EW) {
		   horizontal = TRUE;

		   // If the gridpoint ahead of the stub has a route
		   // on the same net, and the stub is long enough
		   // to come within a DRC spacing distance of the
		   // other route, then lengthen it to close up the
		   // distance and resolve the error.

		   if ((x < x2) && (seg->x2 < (NumChannelsX - 1))) {
		      tdir = OBSVAL(seg->x2 + 1, seg->y2, layer);
		      if ((tdir & ROUTED_NET_MASK) ==
						(net->netnum | ROUTED_NET)) {
			 if (stub + LefGetRouteKeepout(layer) >= PitchX) {
		      	    dc = Xlowerbound + (double)(seg->x2 + 1) * PitchX;
		      	    x2 = (int)((REPS(dc)) * oscale);
			 }
		      }
		   }
		   else if ((x > x2) && (seg->x2 > 0)) {
		      tdir = OBSVAL(seg->x2 - 1, seg->y2, layer);
		      if ((tdir & ROUTED_NET_MASK) ==
						(net->netnum | ROUTED_NET)) {
			 if (-stub + LefGetRouteKeepout(layer) >= PitchX) {
		      	    dc = Xlowerbound + (double)(seg->x2 - 1) * PitchX;
		      	    x2 = (int)((REPS(dc)) * oscale);
			 }
		      }
		   }

		   dc = oscale * 0.5 * LefGetRouteWidth(layer);
		   if (special == (u_char)0) {
		      // Regular nets include 1/2 route width at
		      // the ends, so subtract from the stub terminus
		      if (x < x2) {
			 x2 -= dc;
			 if (x >= x2) cancel = TRUE;
		      }
		      else {
			 x2 += dc;
			 if (x <= x2) cancel = TRUE;
		      }
		   }
		   else {
		      // Special nets don't include 1/2 route width
		      // at the ends, so add to the route at the grid
		      if (x < x2)
			 x -= dc;
		      else
			 x += dc;

		      // Routes that extend for more than one track
		      // without a bend do not need a wide stub
		      if (seg->x1 != seg->x2) cancel = TRUE;
		   }
		}
		else {  /* lnode->flags & NI_STUB_EW implied */
		   horizontal = FALSE;

		   // If the gridpoint ahead of the stub has a route
		   // on the same net, and the stub is long enough
		   // to come within a DRC spacing distance of the
		   // other route, then lengthen it to close up the
		   // distance and resolve the error.

		   if ((y < y2) && (seg->y2 < (NumChannelsY - 1))) {
		      tdir = OBSVAL(seg->x2, seg->y2 + 1, layer);
		      if ((tdir & ROUTED_NET_MASK) ==
						(net->netnum | ROUTED_NET)) {
			 if (stub + LefGetRouteKeepout(layer) >= PitchY) {
		      	    dc = Ylowerbound + (double)(seg->y2 + 1) * PitchY;
		      	    y2 = (int)((REPS(dc)) * oscale);
			 }
		      }
		   }
		   else if ((y > y2) && (seg->y2 > 0)) {
		      tdir = OBSVAL(seg->x2, seg->y2 - 1, layer);
		      if ((tdir & ROUTED_NET_MASK) ==
						(net->netnum | ROUTED_NET)) {
			 if (-stub + LefGetRouteKeepout(layer) >= PitchY) {
		      	    dc = Ylowerbound + (double)(seg->y2 - 1) * PitchY;
		      	    y2 = (int)((REPS(dc)) * oscale);
			 }
		      }
		   }

		   dc = oscale * 0.5 * LefGetRouteWidth(layer);
		   if (special == (u_char)0) {
		      // Regular nets include 1/2 route width at
		      // the ends, so subtract from the stub terminus
		      if (y < y2) {
			 y2 -= dc;
			 if (y >= y2) cancel = TRUE;
		      }
		      else {
			 y2 += dc;
			 if (y <= y2) cancel = TRUE;
		      }
		   }
		   else {
		      // Special nets don't include 1/2 route width
		      // at the ends, so add to the route at the grid
		      if (y < y2)
			 y -= dc;
		      else
			 y += dc;

		      // Routes that extend for more than one track
		      // without a bend do not need a wide stub
		      if (seg->y1 != seg->y2) cancel = TRUE;
		   }
		}
		if (cancel == FALSE) {
	           net->flags |= NET_STUB;
	           rt->flags |= RT_STUB;
		   if (Pathon != 1) {
		      pathstart(Cmd, layer, x, y, special, oscale, invscale,
				horizontal, lnode);
		      lastx = x;
		      lasty = y;
		   }
		   pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale, 0);
		   lastx = x2;
		   lasty = y2;
		}
	    }
	 }
	 if (Pathon != -1) Pathon = 0;

      } // if (rt->segments && !(rt->flags & RT_OUTPUT))
   }
}

/*--------------------------------------------------------------*/
/* emit_routes - DEF file output from the list of routes	*/
/*								*/
/*  Reads the <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, numvias, stubroutes;
    char line[MAX_LINE_LEN + 1], *lptr = NULL;
    char netname[MAX_NAME_LEN];
    NET net = NULL;
    NODE node;
    ROUTE rt;
    FILE *fdef;
    u_char errcond = FALSE;
    u_char need_cleanup = FALSE;
    u_char purge_routed = FALSE;
    u_char skip_net = FALSE;

    fdef = fopen(DEFfilename, "r");
    if ((fdef == NULL) && (DEFfilename != NULL)) {
	if (strchr(DEFfilename, '.') == NULL) {
	    char *extfilename = malloc(strlen(DEFfilename) + 5);
	    sprintf(extfilename, "%s.def", DEFfilename);
	    fdef = fopen(extfilename, "r");
	    free(extfilename);
	}
    }
    if (fdef == NULL) {
	Fprintf(stderr, "emit_routes(): Cannot open DEF file for reading.\n");
	return;
    } 

    if (!strcmp(filename, "stdout")) {
	Cmd = stdout;
    }
    else {
	char *dotptr;

	if (filename == DEFfilename) {
	    char *newDEFfile = (char *)malloc(strlen(filename) + 11);
	    strcpy(newDEFfile, filename);
	    dotptr = strrchr(newDEFfile, '.');
	    if (dotptr)
		strcpy(dotptr, "_route.def");
	    else
		strcat(newDEFfile, "_route.def");
	    
	    Cmd = fopen(newDEFfile, "w");
	    free(newDEFfile);
	}
	else {
	    dotptr = strrchr(filename, '.');
	    if (dotptr)
	       Cmd = fopen(filename, "w");
	    else {
	       char *newDEFfile = (char *)malloc(strlen(filename) + 11);
	       strcpy(newDEFfile, filename);
	       strcat(newDEFfile, ".def");
	       Cmd = fopen(newDEFfile, "w");
	       free(newDEFfile);
	    }
	}
    }
    if (!Cmd) {
	Fprintf(stderr, "emit_routes():  Couldn't open output (routed) DEF file.\n");
	return;
    }

    // Copy DEF file up to NETS line
    numnets = 0;
    numvias = 0;
    while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
       lptr = line;
       while (isspace(*lptr)) lptr++;
       if (!strncmp(lptr, "NETS", 4)) {
	   sscanf(lptr + 4, "%d", &numnets);
	   break;
       }
       if (!strncmp(lptr, "VIAS", 4)) {
	   sscanf(lptr + 4, "%d", &numvias);
	   LefWriteGeneratedVias(Cmd, (double)(oscale / (double)iscale), numvias);
	   continue;	/* VIAS line already written;  do not output. */
       }
       if (!strncmp(lptr, "PINS", 4) && (numvias == 0)) {
	   /* Check if there are any generated vias, and write them	*/
	   /* prior to the PINS section.				*/
	   LefWriteGeneratedVias(Cmd, (double)(oscale / (double)iscale), 0);
       }
       fputs(line, Cmd);
    }
    fputs(line, Cmd);	// Write the NETS line

    if ((numnets + numSpecial) != Numnets) {
      	Flush(stdout);
	Fprintf(stderr, "emit_routes():  DEF file has %d nets and %d specialnets.\n",
			numnets, numSpecial);
	Fprintf(stderr, "but qrouter wants to write %d nets and specialnets.\n",
			Numnets);
    }

    for (i = 0; i < numnets; i++) {
       char *instname, *pinname;

       if (errcond == TRUE) break;
       net = NULL;
       while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
	  if ((lptr = strchr(line, ';')) != NULL) {
	     *lptr = '\n';
	     *(lptr + 1) = '\0';
#ifdef TCL_QROUTER
	     net = DefFindNet(netname);
	     while ((instname = get_annotate_info(net, &pinname)) != NULL) {
		 /* Output antenna connections that were added to the net */
		 fprintf(Cmd, "  ( %s %s )\n", instname, pinname);
	     }
#endif
	     break;
	  }
	  else {
             lptr = line;
             while (isspace(*lptr)) lptr++;
	     if (*lptr == '-') {
		lptr++;
                while (isspace(*lptr)) lptr++;
	        sscanf(lptr, "%s", netname);
		fputs(line, Cmd);
	     }
	     else if (*lptr == '+') {
#ifdef TCL_QROUTER
		net = DefFindNet(netname);
		while ((instname = get_annotate_info(net, &pinname)) != NULL) {
		    /* Output antenna connections that were added to the net */
		    fprintf(Cmd, "  ( %s %s )\n", instname, pinname);
		}
#endif
		lptr++;
                while (isspace(*lptr)) lptr++;
		if (!strncmp(lptr, "ROUTED", 6)) {
		   // This net is being handled by qrouter, so remove
		   // the original routing information
		   while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
		      if ((lptr = strchr(line, ';')) != NULL) {
			 // *lptr = '\n';
			 // *(lptr + 1) = '\0';
			 *line = '\0';
			 break;
		      }
		   }
		   break;
		}
		else
		   fputs(line, Cmd);
	     }
	     else if (!strncmp(lptr, "END", 3)) {	// This should not happen
		fputs(line, Cmd);
		errcond = TRUE;
		break;
	     }
	     else
		fputs(line, Cmd);
	  }
       }

       /* Find this net (if not done already) */

       if (!net) net = DefFindNet(netname);
       if (!net || (net->flags & NET_IGNORED)) {
	  if (!net)
	     Fprintf(stderr, "emit_routes():  Net %s cannot be found.\n",
			netname);

	  /* Dump rest of net and continue */
	  *(lptr) = ';';
	  *(lptr + 1) = '\n';
	  *(lptr + 2) = '\0';
	  fputs(line, Cmd);
	  continue;
       }
       else {
	  /* Add last net terminal, without the semicolon */
	  fputs(line, Cmd);

	  emit_routed_net(Cmd, net, (u_char)0, oscale, iscale);
	  fprintf(Cmd, ";\n");
       }
    }

    // Finish copying the rest of the NETS section
    if (errcond == FALSE) {
       while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
	  lptr = line;
	  while (isspace(*lptr)) lptr++;
	  fputs(line, Cmd);
	  if (!strncmp(lptr, "END", 3)) {
	     break;
	  }
       }
    }

    // Determine how many stub routes we will write to SPECIALNETS
    // Also reset the OUTPUT flag for each route needing a stubroute
    // to be written.

    stubroutes = 0;
    for (i = 0; i < Numnets; i++) {
	net = Nlnets[i];
	if (net->flags & NET_IGNORED) continue;
	if (net->flags & NET_STUB) {
	    stubroutes++;
	    for (rt = net->routes; rt; rt = rt->next)
		if (rt->flags & RT_STUB)
		    rt->flags &= ~RT_OUTPUT;
	}
    }

    // If there were stub routes, repeat them in SPECIALNETS at the
    // proper width.
    if (stubroutes > 0) {

        fprintf(Cmd, "\nSPECIALNETS %d ", stubroutes + numSpecial);
	for (i = 0; i < Numnets; i++) {
	     net = Nlnets[i];
	     if (net->flags & NET_IGNORED) continue;
	     emit_routed_net(Cmd, net, (u_char)1, oscale, iscale);
	}
	if (numSpecial == 0)
	    fprintf(Cmd, ";\nEND SPECIALNETS\n");
	else
	    fprintf(Cmd, ";\n");
    }    

    // Finish copying the rest of the file.  Ignore ROUTED specialnets if
    // the nets are known nets and not power or ground nets.  FIXED or
    // COVER nets are output verbatim.

    while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
       lptr = line;
       while (isspace(*lptr)) lptr++;
       if (!strncmp(lptr, "SPECIALNETS", 11)) {
	   if (stubroutes > 0) {
	       purge_routed = TRUE;
	       continue;	/* SPECIALNETS line already written;  do not output. */
	   }
       }
       if (!purge_routed)
	  fputs(line, Cmd);
       else {
          lptr = line;
          while (isspace(*lptr)) lptr++;
	  if (*lptr == '-') {
	     lptr++;
             while (isspace(*lptr)) lptr++;
	     sscanf(lptr, "%s", netname);

	     // Find this net
	     net = DefFindNet(netname);
	     if (!net || (net->flags & NET_IGNORED))
		skip_net = FALSE;
	     else if (net->netnum == VDD_NET || net->netnum == GND_NET)
		skip_net = FALSE;
	     else
		skip_net = TRUE;
	  }
	  if (!skip_net) fputs(line, Cmd);
	  else if ((lptr = strchr(line, ';')) != NULL) {
	      skip_net = FALSE;
	  }
       }
    }
    fclose(fdef);
    fclose(Cmd);

} /* emit_routes() */

/* end of output.c */
