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